blob: 14df3a0f81b69a005399e87daf9fa0e1d34a2697 [file] [log] [blame]
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001#!/usr/bin/perl
2###########################################################################
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003# ABI Compliance Checker (ACC) 1.97.2
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#
6# 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.
10#
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
20# - G++ (3.0-4.6.2, recommended >= 4.5)
21# - GNU Binutils (readelf, c++filt, objdump)
22# - Perl 5 (5.8-5.14)
23#
24# Mac OS X
25# - Xcode (gcc, otool, c++filt)
26#
27# MS Windows
28# - MinGW (3.0-4.6.2, recommended >= 4.5)
29# - MS Visual C++ (dumpbin, undname, cl)
30# - Active Perl 5 (5.8-5.14)
31# - 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 Ponomarenko16934472012-03-29 15:37:04 +040058my $TOOL_VERSION = "1.97.2";
59my $ABI_DUMP_VERSION = "2.12";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040060my $OLDEST_SUPPORTED_VERSION = "1.18";
61my $XML_REPORT_VERSION = "1.0";
62my $OSgroup = get_OSgroup();
63my $ORIG_DIR = cwd();
64my $TMP_DIR = tempdir(CLEANUP=>1);
65
66# Internal modules
67my $MODULES_DIR = get_Modules();
68push(@INC, get_dirname($MODULES_DIR));
69# Rules DB
70my %RULES_PATH = (
71 "Binary" => $MODULES_DIR."/RulesBin.xml",
72 "Source" => $MODULES_DIR."/RulesSrc.xml");
73
74my ($Help, $ShowVersion, %Descriptor, $TargetLibraryName, $GenerateTemplate,
75$TestTool, $DumpAPI, $SymbolsListPath, $CheckHeadersOnly_Opt, $UseDumps,
76$CheckObjectsOnly_Opt, $AppPath, $StrictCompat, $DumpVersion, $ParamNamesPath,
77%RelativeDirectory, $TargetLibraryFName, $TestDump, $CheckImpl, $LoggingPath,
78%TargetVersion, $InfoMsg, $UseOldDumps, %UsedDump, $CrossGcc, %OutputLogPath,
79$OutputReportPath, $OutputDumpPath, $ShowRetVal, $SystemRoot_Opt, $DumpSystem,
80$CmpSystems, $TargetLibsPath, $Debug, $CrossPrefix, $UseStaticLibs, $NoStdInc,
81$TargetComponent_Opt, $TargetSysInfo, $TargetHeader, $ExtendedCheck, $Quiet,
82$SkipHeadersPath, $Cpp2003, $LogMode, $StdOut, $ListAffected, $ReportFormat,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040083$UserLang, $TargetHeadersPath, $BinaryOnly, $SourceOnly, $BinaryReportPath,
84$SourceReportPath, $UseXML, $Browse);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040085
86my $CmdName = get_filename($0);
87my %OS_LibExt = (
88 "dynamic" => {
89 "default"=>"so",
90 "macos"=>"dylib",
91 "windows"=>"dll",
92 "symbian"=>"dso"
93 },
94 "static" => {
95 "default"=>"a",
96 "windows"=>"lib",
97 "symbian"=>"lib"
98 }
99);
100
101my %OS_Archive = (
102 "windows"=>"zip",
103 "default"=>"tar.gz"
104);
105
106my %ERROR_CODE = (
107 # Compatible verdict
108 "Compatible"=>0,
109 "Success"=>0,
110 # Incompatible verdict
111 "Incompatible"=>1,
112 # Undifferentiated error code
113 "Error"=>2,
114 # System command is not found
115 "Not_Found"=>3,
116 # Cannot access input files
117 "Access_Error"=>4,
118 # Cannot compile header files
119 "Cannot_Compile"=>5,
120 # Header compiled with errors
121 "Compile_Error"=>6,
122 # Invalid input ABI dump
123 "Invalid_Dump"=>7,
124 # Incompatible version of ABI dump
125 "Dump_Version"=>8,
126 # Cannot find a module
127 "Module_Error"=>9,
128 # Empty intersection between
129 # headers and shared objects
130 "Empty_Intersection"=>10,
131 # Empty set of symbols in headers
132 "Empty_Set"=>11
133);
134
135my %HomePage = (
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400136 "Wiki"=>"http://ispras.linuxbase.org/index.php/ABI_compliance_checker",
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +0400137 "Dev1"=>"https://github.com/lvc/abi-compliance-checker",
138 "Dev2"=>"http://forge.ispras.ru/projects/abi-compliance-checker"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400139);
140
141my $ShortUsage = "ABI Compliance Checker (ACC) $TOOL_VERSION
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400142A tool for checking backward compatibility of a C/C++ library API
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400143Copyright (C) 2012 ROSA Laboratory
144License: GNU LGPL or GNU GPL
145
146Usage: $CmdName [options]
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +0400147Example: $CmdName -lib NAME -old OLD.xml -new NEW.xml
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400148
149OLD.xml and NEW.xml are XML-descriptors:
150
151 <version>
152 1.0
153 </version>
154
155 <headers>
156 /path/to/headers/
157 </headers>
158
159 <libs>
160 /path/to/libraries/
161 </libs>
162
163More info: $CmdName --help\n";
164
165if($#ARGV==-1) {
166 printMsg("INFO", $ShortUsage);
167 exit(0);
168}
169
170foreach (2 .. $#ARGV)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400171{ # correct comma separated options
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400172 if($ARGV[$_-1] eq ",") {
173 $ARGV[$_-2].=",".$ARGV[$_];
174 splice(@ARGV, $_-1, 2);
175 }
176 elsif($ARGV[$_-1]=~/,\Z/) {
177 $ARGV[$_-1].=$ARGV[$_];
178 splice(@ARGV, $_, 1);
179 }
180 elsif($ARGV[$_]=~/\A,/
181 and $ARGV[$_] ne ",") {
182 $ARGV[$_-1].=$ARGV[$_];
183 splice(@ARGV, $_, 1);
184 }
185}
186
187GetOptions("h|help!" => \$Help,
188 "i|info!" => \$InfoMsg,
189 "v|version!" => \$ShowVersion,
190 "dumpversion!" => \$DumpVersion,
191# general options
192 "l|lib|library=s" => \$TargetLibraryName,
193 "d1|old|o=s" => \$Descriptor{1}{"Path"},
194 "d2|new|n=s" => \$Descriptor{2}{"Path"},
195 "dump|dump-abi|dump_abi=s" => \$DumpAPI,
196 "old-dumps!" => \$UseOldDumps,
197# extra options
198 "d|descriptor-template!" => \$GenerateTemplate,
199 "app|application=s" => \$AppPath,
200 "static-libs!" => \$UseStaticLibs,
201 "cross-gcc=s" => \$CrossGcc,
202 "cross-prefix=s" => \$CrossPrefix,
203 "sysroot=s" => \$SystemRoot_Opt,
204 "v1|version1|vnum=s" => \$TargetVersion{1},
205 "v2|version2=s" => \$TargetVersion{2},
206 "s|strict!" => \$StrictCompat,
207 "symbols-list=s" => \$SymbolsListPath,
208 "skip-headers=s" => \$SkipHeadersPath,
209 "headers-only|headers_only!" => \$CheckHeadersOnly_Opt,
210 "objects-only!" => \$CheckObjectsOnly_Opt,
211 "check-impl|check-implementation!" => \$CheckImpl,
212 "show-retval!" => \$ShowRetVal,
213 "use-dumps!" => \$UseDumps,
214 "nostdinc!" => \$NoStdInc,
215 "dump-system=s" => \$DumpSystem,
216 "sysinfo=s" => \$TargetSysInfo,
217 "cmp-systems!" => \$CmpSystems,
218 "libs-list=s" => \$TargetLibsPath,
219 "headers-list=s" => \$TargetHeadersPath,
220 "header=s" => \$TargetHeader,
221 "ext|extended!" => \$ExtendedCheck,
222 "q|quiet!" => \$Quiet,
223 "stdout!" => \$StdOut,
224 "report-format=s" => \$ReportFormat,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400225 "xml!" => \$UseXML,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400226 "lang=s" => \$UserLang,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400227 "binary|bin|abi!" => \$BinaryOnly,
228 "source|src|api!" => \$SourceOnly,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400229# other options
230 "test!" => \$TestTool,
231 "test-dump!" => \$TestDump,
232 "debug!" => \$Debug,
233 "cpp-compatible!" => \$Cpp2003,
234 "p|params=s" => \$ParamNamesPath,
235 "relpath1|relpath=s" => \$RelativeDirectory{1},
236 "relpath2=s" => \$RelativeDirectory{2},
237 "dump-path=s" => \$OutputDumpPath,
238 "report-path=s" => \$OutputReportPath,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400239 "bin-report-path=s" => \$BinaryReportPath,
240 "src-report-path=s" => \$SourceReportPath,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400241 "log-path=s" => \$LoggingPath,
242 "log1-path=s" => \$OutputLogPath{1},
243 "log2-path=s" => \$OutputLogPath{2},
244 "logging-mode=s" => \$LogMode,
245 "list-affected!" => \$ListAffected,
246 "l-full|lib-full=s" => \$TargetLibraryFName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400247 "component=s" => \$TargetComponent_Opt,
248 "b|browse=s" => \$Browse
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400249) or ERR_MESSAGE();
250
251sub ERR_MESSAGE()
252{
253 printMsg("INFO", "\n".$ShortUsage);
254 exit($ERROR_CODE{"Error"});
255}
256
257my $LIB_TYPE = $UseStaticLibs?"static":"dynamic";
258my $SLIB_TYPE = $LIB_TYPE;
259if($OSgroup!~/macos|windows/ and $SLIB_TYPE eq "dynamic")
260{ # show as "shared" library
261 $SLIB_TYPE = "shared";
262}
263my $LIB_EXT = getLIB_EXT($OSgroup);
264my $AR_EXT = getAR_EXT($OSgroup);
265my $BYTE_SIZE = 8;
266my $COMMON_LOG_PATH = "logs/run.log";
267
268my $HelpMessage="
269NAME:
270 ABI Compliance Checker ($CmdName)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400271 Check backward binary and source-level compatibility of a C/C++ library API
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400272
273DESCRIPTION:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400274 ABI Compliance Checker (ACC) is a tool for checking backward binary and
275 source-level compatibility of a $SLIB_TYPE C/C++ library. The tool checks
276 header files and $SLIB_TYPE libraries (*.$LIB_EXT) of old and new versions and
277 analyzes changes in API and ABI (ABI=API+compiler ABI) that may break binary
278 and/or source-level compatibility: changes in calling stack, v-table changes,
279 removed symbols, renamed fields, etc. Binary incompatibility may result in
280 crashing or incorrect behavior of applications built with an old version of
281 a library if they run on a new one. Source incompatibility may result in
282 recompilation errors with a new library version.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400283
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +0400284 The tool is intended for developers of software libraries and maintainers
285 of operating systems who are interested in ensuring backward compatibility,
286 i.e. allow old applications to run or to be recompiled with newer library
287 versions.
288
289 Also the tool can be used by ISVs for checking applications portability to
290 new library versions. Found issues can be taken into account when adapting
291 the application to a new library version.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400292
293 This tool is free software: you can redistribute it and/or modify it
294 under the terms of the GNU LGPL or GNU GPL.
295
296USAGE:
297 $CmdName [options]
298
299EXAMPLE:
300 $CmdName -lib NAME -d1 OLD.xml -d2 NEW.xml
301
302 OLD.xml and NEW.xml are XML-descriptors:
303
304 <version>
305 1.0
306 </version>
307
308 <headers>
309 /path1/to/header(s)/
310 /path2/to/header(s)/
311 ...
312 </headers>
313
314 <libs>
315 /path1/to/library(ies)/
316 /path2/to/library(ies)/
317 ...
318 </libs>
319
320INFORMATION OPTIONS:
321 -h|-help
322 Print this help.
323
324 -i|-info
325 Print complete info.
326
327 -v|-version
328 Print version information.
329
330 -dumpversion
331 Print the tool version ($TOOL_VERSION) and don't do anything else.
332
333GENERAL OPTIONS:
334 -l|-lib|-library <name>
335 Library name (without version).
336 It affects only on the path and the title of the report.
337
338 -d1|-old|-o <path>
339 Descriptor of 1st (old) library version.
340 It may be one of the following:
341
342 1. XML-descriptor (VERSION.xml file):
343
344 <version>
345 1.0
346 </version>
347
348 <headers>
349 /path1/to/header(s)/
350 /path2/to/header(s)/
351 ...
352 </headers>
353
354 <libs>
355 /path1/to/library(ies)/
356 /path2/to/library(ies)/
357 ...
358 </libs>
359
360 ... (XML-descriptor template
361 can be generated by -d option)
362
363 2. ABI dump generated by -dump option
364 3. Directory with headers and/or $SLIB_TYPE libraries
365 4. Single header file
366 5. Single $SLIB_TYPE library
367 6. Comma separated list of headers and/or libraries
368
369 If you are using an 2-6 descriptor types then you should
370 specify version numbers with -v1 <num> and -v2 <num> options too.
371
372 For more information, please see:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400373 http://ispras.linuxbase.org/index.php/Library_Descriptor
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400374
375 -d2|-new|-n <path>
376 Descriptor of 2nd (new) library version.
377
378 -dump|-dump-abi <descriptor path(s)>
379 Dump library ABI to gzipped TXT format file. You can transfer it
380 anywhere and pass instead of the descriptor. Also it can be used
381 for debugging the tool. Compatible dump versions: ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION
382
383 -old-dumps
384 Enable support for old-version ABI dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0).\n";
385
386sub HELP_MESSAGE() {
387 printMsg("INFO", $HelpMessage."
388MORE INFO:
389 $CmdName --info\n");
390}
391
392sub INFO_MESSAGE()
393{
394 printMsg("INFO", "$HelpMessage
395EXTRA OPTIONS:
396 -d|-descriptor-template
397 Create XML-descriptor template ./VERSION.xml
398
399 -app|-application <path>
400 This option allows to specify the application that should be checked
401 for portability to the new library version.
402
403 -static-libs
404 Check static libraries instead of the shared ones. The <libs> section
405 of the XML-descriptor should point to static libraries location.
406
407 -cross-gcc <path>
408 Path to the cross GCC compiler to use instead of the usual (host) GCC.
409
410 -cross-prefix <prefix>
411 GCC toolchain prefix.
412
413 -sysroot <dirpath>
414 Specify the alternative root directory. The tool will search for include
415 paths in the <dirpath>/usr/include and <dirpath>/usr/lib directories.
416
417 -v1|-version1 <num>
418 Specify 1st library version outside the descriptor. This option is needed
419 if you have prefered an alternative descriptor type (see -d1 option).
420
421 In general case you should specify it in the XML-descriptor:
422 <version>
423 VERSION
424 </version>
425
426 -v2|-version2 <num>
427 Specify 2nd library version outside the descriptor.
428
429 -s|-strict
430 Treat all compatibility warnings as problems. Add a number of \"Low\"
431 severity problems to the return value of the tool.
432
433 -headers-only
434 Check header files without $SLIB_TYPE libraries. It is easy to run, but may
435 provide a low quality compatibility report with false positives and
436 without detecting of added/removed symbols.
437
438 Alternatively you can write \"none\" word to the <libs> section
439 in the XML-descriptor:
440 <libs>
441 none
442 </libs>
443
444 -objects-only
445 Check $SLIB_TYPE libraries without header files. It is easy to run, but may
446 provide a low quality compatibility report with false positives and
447 without analysis of changes in parameters and data types.
448
449 Alternatively you can write \"none\" word to the <headers> section
450 in the XML-descriptor:
451 <headers>
452 none
453 </headers>
454
455 -check-impl|-check-implementation
456 Compare canonified disassembled binary code of $SLIB_TYPE libraries to
457 detect changes in the implementation. Add \'Problems with Implementation\'
458 section to the report.
459
460 -show-retval
461 Show the symbol's return type in the report.
462
463 -symbols-list <path>
464 This option allows to specify a file with a list of symbols (mangled
465 names in C++) that should be checked, other symbols will not be checked.
466
467 -skip-headers <path>
468 The file with the list of header files, that should not be checked.
469
470 -use-dumps
471 Make dumps for two versions of a library and compare dumps. This should
472 increase the performance of the tool and decrease the system memory usage.
473
474 -nostdinc
475 Do not search the GCC standard system directories for header files.
476
477 -dump-system <name> -sysroot <dirpath>
478 Find all the shared libraries and header files in <dirpath> directory,
479 create XML descriptors and make ABI dumps for each library. The result
480 set of ABI dumps can be compared (--cmp-systems) with the other one
481 created for other version of operating system in order to check them for
482 compatibility. Do not forget to specify -cross-gcc option if your target
483 system requires some specific version of GCC compiler (different from
484 the host GCC). The system ABI dump will be generated to:
485 sys_dumps/<name>/<arch>
486
487 -dump-system <descriptor.xml>
488 The same as the previous option but takes an XML descriptor of the target
489 system as input, where you should describe it:
490
491 /* Primary sections */
492
493 <name>
494 /* Name of the system */
495 </name>
496
497 <headers>
498 /* The list of paths to header files and/or
499 directories with header files, one per line */
500 </headers>
501
502 <libs>
503 /* The list of paths to shared libraries and/or
504 directories with shared libraries, one per line */
505 </libs>
506
507 /* Optional sections */
508
509 <search_headers>
510 /* List of directories to be searched
511 for header files to automatically
512 generate include paths, one per line */
513 </search_headers>
514
515 <search_libs>
516 /* List of directories to be searched
517 for shared libraries to resolve
518 dependencies, one per line */
519 </search_libs>
520
521 <tools>
522 /* List of directories with tools used
523 for analysis (GCC toolchain), one per line */
524 </tools>
525
526 <cross_prefix>
527 /* GCC toolchain prefix.
528 Examples:
529 arm-linux-gnueabi
530 arm-none-symbianelf */
531 </cross_prefix>
532
533 <gcc_options>
534 /* Additional GCC options, one per line */
535 </gcc_options>
536
537 -sysinfo <dir>
538 This option may be used with -dump-system to dump ABI of operating
539 systems and configure the dumping process.
540 Default:
541 modules/Targets/{unix, symbian, windows}
542
543 -cmp-systems -d1 sys_dumps/<name1>/<arch> -d2 sys_dumps/<name2>/<arch>
544 Compare two system ABI dumps. Create compatibility reports for each
545 library and the common HTML report including the summary of test
546 results for all checked libraries. Report will be generated to:
547 sys_compat_reports/<name1>_to_<name2>/<arch>
548
549 -libs-list <path>
550 The file with a list of libraries, that should be dumped by
551 the -dump-system option or should be checked by the -cmp-systems option.
552
553 -header <name>
554 Check/Dump ABI of this header only.
555
556 -headers-list <path>
557 The file with a list of headers, that should be checked/dumped.
558
559 -ext|-extended
560 If your library A is supposed to be used by other library B and you
561 want to control the ABI of B, then you should enable this option. The
562 tool will check for changes in all data types, even if they are not
563 used by any function in the library A. Such data types are not part
564 of the A library ABI, but may be a part of the ABI of the B library.
565
566 The short scheme is:
567 app C (broken) -> lib B (broken ABI) -> lib A (stable ABI)
568
569 -q|-quiet
570 Print all messages to the file instead of stdout and stderr.
571 Default path (can be changed by -log-path option):
572 $COMMON_LOG_PATH
573
574 -stdout
575 Print analysis results (compatibility reports and ABI dumps) to stdout
576 instead of creating a file. This would allow piping data to other programs.
577
578 -report-format <fmt>
579 Change format of compatibility report.
580 Formats:
581 htm - HTML format (default)
582 xml - XML format
583
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400584 -xml
585 Alias for: --report-format=xml
586
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400587 -lang <lang>
588 Set library language (C or C++). You can use this option if the tool
589 cannot auto-detect a language. This option may be useful for checking
590 C-library headers (--lang=C) in --headers-only or --extended modes.
591
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400592 -binary|-bin|-abi
593 Show \"Binary\" compatibility problems only.
594 Generate report to:
595 compat_reports/<library name>/<v1>_to_<v2>/abi_compat_report.html
596
597 -source|-src|-api
598 Show \"Source\" compatibility problems only.
599 Generate report to:
600 compat_reports/<library name>/<v1>_to_<v2>/src_compat_report.html
601
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400602OTHER OPTIONS:
603 -test
604 Run internal tests. Create two binary incompatible versions of a sample
605 library and run the tool to check them for compatibility. This option
606 allows to check if the tool works correctly in the current environment.
607
608 -test-dump
609 Test ability to create, read and compare ABI dumps.
610
611 -debug
612 Debugging mode. Print debug info on the screen. Save intermediate
613 analysis stages in the debug directory:
614 debug/<library>/<version>/
615
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400616 Also consider using --dump option for debugging the tool.
617
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400618 -cpp-compatible
619 If your header file is written in C language and can be compiled by
620 the C++ compiler (i.e. doesn't contain C++-keywords and other bad
621 things), then you can tell ACC about this and speedup the analysis.
622
623 -p|-params <path>
624 Path to file with the function parameter names. It can be used
625 for improving report view if the library header files have no
626 parameter names. File format:
627
628 func1;param1;param2;param3 ...
629 func2;param1;param2;param3 ...
630 ...
631
632 -relpath <path>
633 Replace {RELPATH} macros to <path> in the XML-descriptor used
634 for dumping the library ABI (see -dump option).
635
636 -relpath1 <path>
637 Replace {RELPATH} macros to <path> in the 1st XML-descriptor (-d1).
638
639 -relpath2 <path>
640 Replace {RELPATH} macros to <path> in the 2nd XML-descriptor (-d2).
641
642 -dump-path <path>
643 Specify a file path (*.abi.$AR_EXT) where to generate an ABI dump.
644 Default:
645 abi_dumps/<library>/<library>_<version>.abi.$AR_EXT
646
647 -report-path <path>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400648 Path to joined compatibility report (see -join-report option).
649 Default:
650 compat_reports/<library name>/<v1>_to_<v2>/compat_report.html
651
652 -bin-report-path <path>
653 Path to \"Binary\" compatibility report.
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400654 Default:
655 compat_reports/<library name>/<v1>_to_<v2>/abi_compat_report.html
656
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400657 -src-report-path <path>
658 Path to \"Source\" compatibility report.
659 Default:
660 compat_reports/<library name>/<v1>_to_<v2>/src_compat_report.html
661
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400662 -log-path <path>
663 Log path for all messages.
664 Default:
665 logs/<library>/<version>/log.txt
666
667 -log1-path <path>
668 Log path for 1st version of a library.
669 Default:
670 logs/<library name>/<v1>/log.txt
671
672 -log2-path <path>
673 Log path for 2nd version of a library.
674 Default:
675 logs/<library name>/<v2>/log.txt
676
677 -logging-mode <mode>
678 Change logging mode.
679 Modes:
680 w - overwrite old logs (default)
681 a - append old logs
682 n - do not write any logs
683
684 -list-affected
685 Generate file with the list of incompatible
686 symbols beside the HTML compatibility report.
687 Use 'c++filt \@file' command from GNU binutils
688 to unmangle C++ symbols in the generated file.
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400689 Default names:
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400690 abi_affected.txt
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400691 src_affected.txt
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400692
693 -component <name>
694 The component name in the title and summary of the HTML report.
695 Default:
696 library
697
698 -l-full|-lib-full <name>
699 Change library name in the report title to <name>. By default
700 will be displayed a name specified by -l option.
701
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400702 -b|-browse <program>
703 Open report(s) in the browser (firefox, opera, etc.).
704
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400705REPORT:
706 Compatibility report will be generated to:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400707 compat_reports/<library name>/<v1>_to_<v2>/compat_report.html
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400708
709 Log will be generated to:
710 logs/<library name>/<v1>/log.txt
711 logs/<library name>/<v2>/log.txt
712
713EXIT CODES:
714 0 - Compatible. The tool has run without any errors.
715 non-zero - Incompatible or the tool has run with errors.
716
717REPORT BUGS TO:
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400718 Andrey Ponomarenko <aponomarenko\@rosalab.ru>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400719
720MORE INFORMATION:
721 ".$HomePage{"Wiki"}."
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +0400722 ".$HomePage{"Dev1"}."\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +0400723}
724
725my $DescriptorTemplate = "
726<?xml version=\"1.0\" encoding=\"utf-8\"?>
727<descriptor>
728
729/* Primary sections */
730
731<version>
732 /* Version of the library */
733</version>
734
735<headers>
736 /* The list of paths to header files and/or
737 directories with header files, one per line */
738</headers>
739
740<libs>
741 /* The list of paths to shared libraries (*.$LIB_EXT) and/or
742 directories with shared libraries, one per line */
743</libs>
744
745/* Optional sections */
746
747<include_paths>
748 /* The list of include paths that will be provided
749 to GCC to compile library headers, one per line.
750 NOTE: If you define this section then the tool
751 will not automatically generate include paths */
752</include_paths>
753
754<add_include_paths>
755 /* The list of include paths that will be added
756 to the automatically generated include paths, one per line */
757</add_include_paths>
758
759<skip_include_paths>
760 /* The list of include paths that will be removed from the
761 list of automatically generated include paths, one per line */
762</skip_include_paths>
763
764<gcc_options>
765 /* Additional GCC options, one per line */
766</gcc_options>
767
768<include_preamble>
769 /* The list of header files that will be
770 included before other headers, one per line.
771 Examples:
772 1) tree.h for libxml2
773 2) ft2build.h for freetype2 */
774</include_preamble>
775
776<defines>
777 /* The list of defines that will be added at the
778 headers compiling stage, one per line:
779 #define A B
780 #define C D */
781</defines>
782
783<skip_types>
784 /* The list of data types, that
785 should not be checked, one per line */
786</skip_types>
787
788<skip_symbols>
789 /* The list of functions (mangled/symbol names in C++),
790 that should not be checked, one per line */
791</skip_symbols>
792
793<skip_namespaces>
794 /* The list of C++ namespaces, that
795 should not be checked, one per line */
796</skip_namespaces>
797
798<skip_constants>
799 /* The list of constants that should
800 not be checked, one name per line */
801</skip_constants>
802
803<skip_headers>
804 /* The list of header files and/or directories
805 with header files that should not be checked, one per line */
806</skip_headers>
807
808<skip_libs>
809 /* The list of shared libraries and/or directories
810 with shared libraries that should not be checked, one per line */
811</skip_libs>
812
813<skip_including>
814 /* The list of header files, that cannot be included
815 directly (or non-self compiled ones), one per line */
816</skip_including>
817
818<search_headers>
819 /* List of directories to be searched
820 for header files to automatically
821 generate include paths, one per line. */
822</search_headers>
823
824<search_libs>
825 /* List of directories to be searched
826 for shared librariess to resolve
827 dependencies, one per line */
828</search_libs>
829
830<tools>
831 /* List of directories with tools used
832 for analysis (GCC toolchain), one per line */
833</tools>
834
835<cross_prefix>
836 /* GCC toolchain prefix.
837 Examples:
838 arm-linux-gnueabi
839 arm-none-symbianelf */
840</cross_prefix>
841
842</descriptor>";
843
844my %Operator_Indication = (
845 "not" => "~",
846 "assign" => "=",
847 "andassign" => "&=",
848 "orassign" => "|=",
849 "xorassign" => "^=",
850 "or" => "|",
851 "xor" => "^",
852 "addr" => "&",
853 "and" => "&",
854 "lnot" => "!",
855 "eq" => "==",
856 "ne" => "!=",
857 "lt" => "<",
858 "lshift" => "<<",
859 "lshiftassign" => "<<=",
860 "rshiftassign" => ">>=",
861 "call" => "()",
862 "mod" => "%",
863 "modassign" => "%=",
864 "subs" => "[]",
865 "land" => "&&",
866 "lor" => "||",
867 "rshift" => ">>",
868 "ref" => "->",
869 "le" => "<=",
870 "deref" => "*",
871 "mult" => "*",
872 "preinc" => "++",
873 "delete" => " delete",
874 "vecnew" => " new[]",
875 "vecdelete" => " delete[]",
876 "predec" => "--",
877 "postinc" => "++",
878 "postdec" => "--",
879 "plusassign" => "+=",
880 "plus" => "+",
881 "minus" => "-",
882 "minusassign" => "-=",
883 "gt" => ">",
884 "ge" => ">=",
885 "new" => " new",
886 "multassign" => "*=",
887 "divassign" => "/=",
888 "div" => "/",
889 "neg" => "-",
890 "pos" => "+",
891 "memref" => "->*",
892 "compound" => "," );
893
894my %CppKeywords_C = map {$_=>1} (
895 # C++ 2003 keywords
896 "public",
897 "protected",
898 "private",
899 "default",
900 "template",
901 "new",
902 #"asm",
903 "dynamic_cast",
904 "auto",
905 "try",
906 "namespace",
907 "typename",
908 "using",
909 "reinterpret_cast",
910 "friend",
911 "class",
912 "virtual",
913 "const_cast",
914 "mutable",
915 "static_cast",
916 "export",
917 # C++0x keywords
918 "noexcept",
919 "nullptr",
920 "constexpr",
921 "static_assert",
922 "explicit",
923 # cannot be used as a macro name
924 # as it is an operator in C++
925 "and",
926 #"and_eq",
927 "not",
928 #"not_eq",
929 "or"
930 #"or_eq",
931 #"bitand",
932 #"bitor",
933 #"xor",
934 #"xor_eq",
935 #"compl"
936);
937
938my %CppKeywords_F = map {$_=>1} (
939 "delete",
940 "catch",
941 "alignof",
942 "thread_local",
943 "decltype",
944 "typeid"
945);
946
947my %CppKeywords_O = map {$_=>1} (
948 "bool",
949 "register",
950 "inline",
951 "operator"
952);
953
954my %CppKeywords_A = map {$_=>1} (
955 "this",
956 "throw"
957);
958
959foreach (keys(%CppKeywords_C),
960keys(%CppKeywords_F),
961keys(%CppKeywords_O)) {
962 $CppKeywords_A{$_}=1;
963}
964
965# Header file extensions as described by gcc
966my $HEADER_EXT = "h|hh|hp|hxx|hpp|h\\+\\+";
967
968my %IntrinsicMangling = (
969 "void" => "v",
970 "bool" => "b",
971 "wchar_t" => "w",
972 "char" => "c",
973 "signed char" => "a",
974 "unsigned char" => "h",
975 "short" => "s",
976 "unsigned short" => "t",
977 "int" => "i",
978 "unsigned int" => "j",
979 "long" => "l",
980 "unsigned long" => "m",
981 "long long" => "x",
982 "__int64" => "x",
983 "unsigned long long" => "y",
984 "__int128" => "n",
985 "unsigned __int128" => "o",
986 "float" => "f",
987 "double" => "d",
988 "long double" => "e",
989 "__float80" => "e",
990 "__float128" => "g",
991 "..." => "z"
992);
993
994my %StdcxxMangling = (
995 "3std"=>"St",
996 "3std9allocator"=>"Sa",
997 "3std12basic_string"=>"Sb",
998 "3std12basic_stringIcE"=>"Ss",
999 "3std13basic_istreamIcE"=>"Si",
1000 "3std13basic_ostreamIcE"=>"So",
1001 "3std14basic_iostreamIcE"=>"Sd"
1002);
1003
1004my %ConstantSuffix = (
1005 "unsigned int"=>"u",
1006 "long"=>"l",
1007 "unsigned long"=>"ul",
1008 "long long"=>"ll",
1009 "unsigned long long"=>"ull"
1010);
1011
1012my %ConstantSuffixR =
1013reverse(%ConstantSuffix);
1014
1015my %OperatorMangling = (
1016 "~" => "co",
1017 "=" => "aS",
1018 "|" => "or",
1019 "^" => "eo",
1020 "&" => "an",#ad (addr)
1021 "==" => "eq",
1022 "!" => "nt",
1023 "!=" => "ne",
1024 "<" => "lt",
1025 "<=" => "le",
1026 "<<" => "ls",
1027 "<<=" => "lS",
1028 ">" => "gt",
1029 ">=" => "ge",
1030 ">>" => "rs",
1031 ">>=" => "rS",
1032 "()" => "cl",
1033 "%" => "rm",
1034 "[]" => "ix",
1035 "&&" => "aa",
1036 "||" => "oo",
1037 "*" => "ml",#de (deref)
1038 "++" => "pp",#
1039 "--" => "mm",#
1040 "new" => "nw",
1041 "delete" => "dl",
1042 "new[]" => "na",
1043 "delete[]" => "da",
1044 "+=" => "pL",
1045 "+" => "pl",#ps (pos)
1046 "-" => "mi",#ng (neg)
1047 "-=" => "mI",
1048 "*=" => "mL",
1049 "/=" => "dV",
1050 "&=" => "aN",
1051 "|=" => "oR",
1052 "%=" => "rM",
1053 "^=" => "eO",
1054 "/" => "dv",
1055 "->*" => "pm",
1056 "->" => "pt",#rf (ref)
1057 "," => "cm",
1058 "?" => "qu",
1059 "." => "dt",
1060 "sizeof"=> "sz"#st
1061);
1062
1063my %GlibcHeader = map {$_=>1} (
1064 "aliases.h",
1065 "argp.h",
1066 "argz.h",
1067 "assert.h",
1068 "cpio.h",
1069 "ctype.h",
1070 "dirent.h",
1071 "envz.h",
1072 "errno.h",
1073 "error.h",
1074 "execinfo.h",
1075 "fcntl.h",
1076 "fstab.h",
1077 "ftw.h",
1078 "glob.h",
1079 "grp.h",
1080 "iconv.h",
1081 "ifaddrs.h",
1082 "inttypes.h",
1083 "langinfo.h",
1084 "limits.h",
1085 "link.h",
1086 "locale.h",
1087 "malloc.h",
1088 "math.h",
1089 "mntent.h",
1090 "monetary.h",
1091 "nl_types.h",
1092 "obstack.h",
1093 "printf.h",
1094 "pwd.h",
1095 "regex.h",
1096 "sched.h",
1097 "search.h",
1098 "setjmp.h",
1099 "shadow.h",
1100 "signal.h",
1101 "spawn.h",
1102 "stdarg.h",
1103 "stdint.h",
1104 "stdio.h",
1105 "stdlib.h",
1106 "string.h",
1107 "tar.h",
1108 "termios.h",
1109 "time.h",
1110 "ulimit.h",
1111 "unistd.h",
1112 "utime.h",
1113 "wchar.h",
1114 "wctype.h",
1115 "wordexp.h" );
1116
1117my %GlibcDir = map {$_=>1} (
1118 "arpa",
1119 "bits",
1120 "gnu",
1121 "netinet",
1122 "net",
1123 "nfs",
1124 "rpc",
1125 "sys",
1126 "linux" );
1127
1128my %LocalIncludes = map {$_=>1} (
1129 "/usr/local/include",
1130 "/usr/local" );
1131
1132my %OS_AddPath=(
1133# These paths are needed if the tool cannot detect them automatically
1134 "macos"=>{
1135 "include"=>{
1136 "/Library"=>1,
1137 "/Developer/usr/include"=>1
1138 },
1139 "lib"=>{
1140 "/Library"=>1,
1141 "/Developer/usr/lib"=>1
1142 },
1143 "bin"=>{
1144 "/Developer/usr/bin"=>1
1145 }
1146 },
1147 "beos"=>{
1148 # Haiku has GCC 2.95.3 by default
1149 # try to find GCC>=3.0 in /boot/develop/abi
1150 "include"=>{
1151 "/boot/common"=>1,
1152 "/boot/develop"=>1},
1153 "lib"=>{
1154 "/boot/common/lib"=>1,
1155 "/boot/system/lib"=>1,
1156 "/boot/apps"=>1},
1157 "bin"=>{
1158 "/boot/common/bin"=>1,
1159 "/boot/system/bin"=>1,
1160 "/boot/develop/abi"=>1
1161 }
1162}
1163);
1164
1165my %Slash_Type=(
1166 "default"=>"/",
1167 "windows"=>"\\"
1168);
1169
1170my $SLASH = $Slash_Type{$OSgroup}?$Slash_Type{$OSgroup}:$Slash_Type{"default"};
1171
1172# Global Variables
1173my %COMMON_LANGUAGE=(
1174 1 => "C",
1175 2 => "C" );
1176
1177my $MAX_COMMAND_LINE_ARGUMENTS = 4096;
1178my (%WORD_SIZE, %CPU_ARCH, %GCC_VERSION);
1179
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001180my $STDCXX_TESTING = 0;
1181my $GLIBC_TESTING = 0;
1182
1183my $CheckHeadersOnly = $CheckHeadersOnly_Opt;
1184my $CheckObjectsOnly = $CheckObjectsOnly_Opt;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001185my $TargetComponent;
1186
1187# Set Target Component Name
1188if($TargetComponent_Opt) {
1189 $TargetComponent = lc($TargetComponent_Opt);
1190}
1191else
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001192{ # default: library
1193 # other components: header, system, ...
1194 $TargetComponent = "library";
1195}
1196
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001197my $TOP_REF = "<a style='font-size:11px;' href='#Top'>to the top</a>";
1198
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001199my $SystemRoot;
1200
1201my $MAIN_CPP_DIR;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001202my %RESULT;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001203my %LOG_PATH;
1204my %DEBUG_PATH;
1205my %Cache;
1206my %LibInfo;
1207my $COMPILE_ERRORS = 0;
1208my %CompilerOptions;
1209my %CheckedDyLib;
1210my $TargetLibraryShortName = parse_libname($TargetLibraryName, "shortest", $OSgroup);
1211
1212# Constants (#defines)
1213my %Constants;
1214my %SkipConstants;
1215
1216# Types
1217my %TypeInfo;
1218my %TemplateInstance_Func;
1219my %TemplateInstance;
1220my %SkipTypes = (
1221 "1"=>{},
1222 "2"=>{} );
1223my %Tid_TDid = (
1224 "1"=>{},
1225 "2"=>{} );
1226my %CheckedTypes;
1227my %TName_Tid;
1228my %EnumMembName_Id;
1229my %NestedNameSpaces = (
1230 "1"=>{},
1231 "2"=>{} );
1232my %UsedType;
1233my %VirtualTable;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001234my %VirtualTable_Model;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001235my %ClassVTable;
1236my %ClassVTable_Content;
1237my %VTableClass;
1238my %AllocableClass;
1239my %ClassMethods;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001240my %ClassNames;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001241my %Class_SubClasses;
1242my %OverriddenMethods;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001243my $MAX_ID;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001244
1245# Typedefs
1246my %Typedef_BaseName;
1247my %Typedef_Tr;
1248my %Typedef_Eq;
1249my %StdCxxTypedef;
1250my %MissedTypedef;
1251
1252# Symbols
1253my %SymbolInfo;
1254my %tr_name;
1255my %mangled_name_gcc;
1256my %mangled_name;
1257my %SkipSymbols = (
1258 "1"=>{},
1259 "2"=>{} );
1260my %SkipNameSpaces = (
1261 "1"=>{},
1262 "2"=>{} );
1263my %SymbolsList;
1264my %SymbolsList_App;
1265my %CheckedSymbols;
1266my %GeneratedSymbols;
1267my %DepSymbols = (
1268 "1"=>{},
1269 "2"=>{} );
1270my %MangledNames;
1271my %AddIntParams;
1272my %Interface_Impl;
1273
1274# Headers
1275my %Include_Preamble;
1276my %Registered_Headers;
1277my %HeaderName_Paths;
1278my %Header_Dependency;
1279my %Include_Neighbors;
1280my %Include_Paths;
1281my %INC_PATH_AUTODETECT = (
1282 "1"=>1,
1283 "2"=>1 );
1284my %Add_Include_Paths;
1285my %Skip_Include_Paths;
1286my %RegisteredDirs;
1287my %RegisteredDeps;
1288my %Header_ErrorRedirect;
1289my %Header_Includes;
1290my %Header_ShouldNotBeUsed;
1291my %RecursiveIncludes;
1292my %Header_Include_Prefix;
1293my %SkipHeaders;
1294my %SkipHeadersList=(
1295 "1"=>{},
1296 "2"=>{} );
1297my %SkipLibs;
1298my %Include_Order;
1299my %TUnit_NameSpaces;
1300
1301my %C99Mode = (
1302 "1"=>0,
1303 "2"=>0 );
1304my %AutoPreambleMode = (
1305 "1"=>0,
1306 "2"=>0 );
1307my %MinGWMode = (
1308 "1"=>0,
1309 "2"=>0 );
1310
1311# Shared Objects
1312my %DyLib_DefaultPath;
1313my %InputObject_Paths;
1314my %RegisteredObjDirs;
1315
1316# System Objects
1317my %SystemObjects;
1318my %DefaultLibPaths;
1319
1320# System Headers
1321my %SystemHeaders;
1322my %DefaultCppPaths;
1323my %DefaultGccPaths;
1324my %DefaultIncPaths;
1325my %DefaultCppHeader;
1326my %DefaultGccHeader;
1327my %UserIncPath;
1328
1329# Merging
1330my %CompleteSignature;
1331my %Symbol_Library;
1332my %Library_Symbol = (
1333 "1"=>{},
1334 "2"=>{} );
1335my $Version;
1336my %AddedInt;
1337my %RemovedInt;
1338my %AddedInt_Virt;
1339my %RemovedInt_Virt;
1340my %VirtualReplacement;
1341my %ChangedTypedef;
1342my %CompatRules;
1343my %IncompleteRules;
1344my %UnknownRules;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001345my %VTableChanged_M;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001346my %ExtendedFuncs;
1347my %ReturnedClass;
1348my %ParamClass;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001349my %SourceAlternative;
1350my %SourceAlternative_B;
1351my %SourceReplacement;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001352
1353# OS Compliance
1354my %TargetLibs;
1355my %TargetHeaders;
1356
1357# OS Specifics
1358my $OStarget = $OSgroup;
1359my %TargetTools;
1360
1361# Compliance Report
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001362my %Type_MaxSeverity;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001363
1364# Recursion locks
1365my @RecurLib;
1366my @RecurSymlink;
1367my @RecurTypes;
1368my @RecurInclude;
1369my @RecurConstant;
1370
1371# System
1372my %SystemPaths;
1373my %DefaultBinPaths;
1374my $GCC_PATH;
1375
1376# Symbols versioning
1377my %SymVer = (
1378 "1"=>{},
1379 "2"=>{} );
1380
1381# Problem descriptions
1382my %CompatProblems;
1383my %ProblemsWithConstants;
1384my %ImplProblems;
1385my %TotalAffected;
1386
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001387# Reports
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001388my $ContentID = 1;
1389my $ContentSpanStart = "<span class=\"section\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1390my $ContentSpanStart_Affected = "<span class=\"section_affected\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1391my $ContentSpanStart_Info = "<span class=\"section_info\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
1392my $ContentSpanEnd = "</span>\n";
1393my $ContentDivStart = "<div id=\"CONTENT_ID\" style=\"display:none;\">\n";
1394my $ContentDivEnd = "</div>\n";
1395my $Content_Counter = 0;
1396
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001397# Modes
1398my $JoinReport = 1;
1399my $DoubleReport = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001400
1401sub get_Modules()
1402{
1403 my $TOOL_DIR = get_dirname($0);
1404 if(not $TOOL_DIR)
1405 { # patch for MS Windows
1406 $TOOL_DIR = ".";
1407 }
1408 my @SEARCH_DIRS = (
1409 # tool's directory
1410 abs_path($TOOL_DIR),
1411 # relative path to modules
1412 abs_path($TOOL_DIR)."/../share/abi-compliance-checker",
1413 # system directory
1414 "ACC_MODULES_INSTALL_PATH"
1415 );
1416 foreach my $DIR (@SEARCH_DIRS)
1417 {
1418 if(not is_abs($DIR))
1419 { # relative path
1420 $DIR = abs_path($TOOL_DIR)."/".$DIR;
1421 }
1422 if(-d $DIR."/modules") {
1423 return $DIR."/modules";
1424 }
1425 }
1426 exitStatus("Module_Error", "can't find modules");
1427}
1428
1429sub loadModule($)
1430{
1431 my $Name = $_[0];
1432 my $Path = $MODULES_DIR."/Internals/$Name.pm";
1433 if(not -f $Path) {
1434 exitStatus("Module_Error", "can't access \'$Path\'");
1435 }
1436 require $Path;
1437}
1438
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001439sub showNum($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001440{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001441 my $Number = $_[0];
1442 if(not $Number) {
1443 $Number = 1;
1444 }
1445 else {
1446 $Number = int($Number)+1;
1447 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001448 if($Number>3) {
1449 return $Number."th";
1450 }
1451 elsif($Number==1) {
1452 return "1st";
1453 }
1454 elsif($Number==2) {
1455 return "2nd";
1456 }
1457 elsif($Number==3) {
1458 return "3rd";
1459 }
1460 else {
1461 return $Number;
1462 }
1463}
1464
1465sub search_Tools($)
1466{
1467 my $Name = $_[0];
1468 return "" if(not $Name);
1469 if(my @Paths = keys(%TargetTools))
1470 {
1471 foreach my $Path (@Paths)
1472 {
1473 if(-f joinPath($Path, $Name)) {
1474 return joinPath($Path, $Name);
1475 }
1476 if($CrossPrefix)
1477 { # user-defined prefix (arm-none-symbianelf, ...)
1478 my $Candidate = joinPath($Path, $CrossPrefix."-".$Name);
1479 if(-f $Candidate) {
1480 return $Candidate;
1481 }
1482 }
1483 }
1484 }
1485 else {
1486 return "";
1487 }
1488}
1489
1490sub synch_Cmd($)
1491{
1492 my $Name = $_[0];
1493 if(not $GCC_PATH)
1494 { # GCC was not found yet
1495 return "";
1496 }
1497 my $Candidate = $GCC_PATH;
1498 if($Candidate=~s/(\W|\A)gcc(|\.\w+)\Z/$1$Name$2/) {
1499 return $Candidate;
1500 }
1501 return "";
1502}
1503
1504sub get_CmdPath($)
1505{
1506 my $Name = $_[0];
1507 return "" if(not $Name);
1508 if(defined $Cache{"get_CmdPath"}{$Name}) {
1509 return $Cache{"get_CmdPath"}{$Name};
1510 }
1511 my %BinUtils = map {$_=>1} (
1512 "c++filt",
1513 "objdump",
1514 "readelf"
1515 );
1516 if($BinUtils{$Name}) {
1517 if(my $Dir = get_dirname($GCC_PATH)) {
1518 $TargetTools{$Dir}=1;
1519 }
1520 }
1521 my $Path = search_Tools($Name);
1522 if(not $Path and $OSgroup eq "windows") {
1523 $Path = search_Tools($Name.".exe");
1524 }
1525 if(not $Path and $BinUtils{$Name})
1526 {
1527 if($CrossPrefix)
1528 { # user-defined prefix
1529 $Path = search_Cmd($CrossPrefix."-".$Name);
1530 }
1531 }
1532 if(not $Path and $BinUtils{$Name})
1533 {
1534 if(my $Candidate = synch_Cmd($Name))
1535 { # synch with GCC
1536 if($Candidate=~/[\/\\]/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001537 { # command path
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001538 if(-f $Candidate) {
1539 $Path = $Candidate;
1540 }
1541 }
1542 elsif($Candidate = search_Cmd($Candidate))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001543 { # command name
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001544 $Path = $Candidate;
1545 }
1546 }
1547 }
1548 if(not $Path) {
1549 $Path = search_Cmd($Name);
1550 }
1551 if(not $Path and $OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001552 { # search for *.exe file
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001553 $Path=search_Cmd($Name.".exe");
1554 }
1555 if($Path=~/\s/) {
1556 $Path = "\"".$Path."\"";
1557 }
1558 return ($Cache{"get_CmdPath"}{$Name}=$Path);
1559}
1560
1561sub search_Cmd($)
1562{
1563 my $Name = $_[0];
1564 return "" if(not $Name);
1565 if(defined $Cache{"search_Cmd"}{$Name}) {
1566 return $Cache{"search_Cmd"}{$Name};
1567 }
1568 if(my $DefaultPath = get_CmdPath_Default($Name)) {
1569 return ($Cache{"search_Cmd"}{$Name} = $DefaultPath);
1570 }
1571 foreach my $Path (sort {length($a)<=>length($b)} keys(%{$SystemPaths{"bin"}}))
1572 {
1573 my $CmdPath = joinPath($Path,$Name);
1574 if(-f $CmdPath)
1575 {
1576 if($Name=~/gcc/) {
1577 next if(not check_gcc_version($CmdPath, "3"));
1578 }
1579 return ($Cache{"search_Cmd"}{$Name} = $CmdPath);
1580 }
1581 }
1582 return ($Cache{"search_Cmd"}{$Name} = "");
1583}
1584
1585sub get_CmdPath_Default($)
1586{ # search in PATH
1587 my $Name = $_[0];
1588 return "" if(not $Name);
1589 if(defined $Cache{"get_CmdPath_Default"}{$Name}) {
1590 return $Cache{"get_CmdPath_Default"}{$Name};
1591 }
1592 if($Name=~/find/)
1593 { # special case: search for "find" utility
1594 if(`find . -maxdepth 0 2>$TMP_DIR/null`) {
1595 return ($Cache{"get_CmdPath_Default"}{$Name} = "find");
1596 }
1597 }
1598 elsif($Name=~/gcc/) {
1599 return check_gcc_version($Name, "3");
1600 }
1601 if(check_command($Name)) {
1602 return ($Cache{"get_CmdPath_Default"}{$Name} = $Name);
1603 }
1604 if($OSgroup eq "windows"
1605 and `$Name /? 2>$TMP_DIR/null`) {
1606 return ($Cache{"get_CmdPath_Default"}{$Name} = $Name);
1607 }
1608 if($Name!~/which/)
1609 {
1610 my $WhichCmd = get_CmdPath("which");
1611 if($WhichCmd and `$WhichCmd $Name 2>$TMP_DIR/null`) {
1612 return ($Cache{"get_CmdPath_Default"}{$Name} = $Name);
1613 }
1614 }
1615 foreach my $Path (sort {length($a)<=>length($b)} keys(%DefaultBinPaths))
1616 {
1617 if(-f $Path."/".$Name) {
1618 return ($Cache{"get_CmdPath_Default"}{$Name} = joinPath($Path,$Name));
1619 }
1620 }
1621 return ($Cache{"get_CmdPath_Default"}{$Name} = "");
1622}
1623
1624sub clean_path($)
1625{
1626 my $Path = $_[0];
1627 $Path=~s/[\/\\]+\Z//g;
1628 return $Path;
1629}
1630
1631sub classifyPath($)
1632{
1633 my $Path = $_[0];
1634 if($Path=~/[\*\[]/)
1635 { # wildcard
1636 $Path=~s/\*/.*/g;
1637 $Path=~s/\\/\\\\/g;
1638 return ($Path, "Pattern");
1639 }
1640 elsif($Path=~/[\/\\]/)
1641 { # directory or relative path
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001642 $Path=~s/[\/\\]+\Z//g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001643 return (path_format($Path, $OSgroup), "Path");
1644 }
1645 else {
1646 return ($Path, "Name");
1647 }
1648}
1649
1650sub readDescriptor($$)
1651{
1652 my ($LibVersion, $Content) = @_;
1653 return if(not $LibVersion);
1654 my $DName = $DumpAPI?"descriptor":"descriptor \"d$LibVersion\"";
1655 if(not $Content) {
1656 exitStatus("Error", "$DName is empty");
1657 }
1658 if($Content!~/\</) {
1659 exitStatus("Error", "$DName is not a descriptor (see -d1 option)");
1660 }
1661 $Content=~s/\/\*(.|\n)+?\*\///g;
1662 $Content=~s/<\!--(.|\n)+?-->//g;
1663 $Descriptor{$LibVersion}{"Version"} = parseTag(\$Content, "version");
1664 if($TargetVersion{$LibVersion}) {
1665 $Descriptor{$LibVersion}{"Version"} = $TargetVersion{$LibVersion};
1666 }
1667 if(not $Descriptor{$LibVersion}{"Version"}) {
1668 exitStatus("Error", "version in the $DName is not specified (<version> section)");
1669 }
1670 if($Content=~/{RELPATH}/)
1671 {
1672 if(my $RelDir = $RelativeDirectory{$LibVersion}) {
1673 $Content =~ s/{RELPATH}/$RelDir/g;
1674 }
1675 else
1676 {
1677 my $NeedRelpath = $DumpAPI?"-relpath":"-relpath$LibVersion";
1678 exitStatus("Error", "you have not specified $NeedRelpath option, but the $DName contains {RELPATH} macro");
1679 }
1680 }
1681
1682 if(not $CheckObjectsOnly_Opt)
1683 {
1684 my $DHeaders = parseTag(\$Content, "headers");
1685 if(not $DHeaders) {
1686 exitStatus("Error", "header files in the $DName are not specified (<headers> section)");
1687 }
1688 elsif(lc($DHeaders) ne "none")
1689 { # append the descriptor headers list
1690 if($Descriptor{$LibVersion}{"Headers"})
1691 { # multiple descriptors
1692 $Descriptor{$LibVersion}{"Headers"} .= "\n".$DHeaders;
1693 }
1694 else {
1695 $Descriptor{$LibVersion}{"Headers"} = $DHeaders;
1696 }
1697 foreach my $Path (split(/\s*\n\s*/, $DHeaders))
1698 {
1699 if(not -e $Path) {
1700 exitStatus("Access_Error", "can't access \'$Path\'");
1701 }
1702 }
1703 }
1704 }
1705 if(not $CheckHeadersOnly_Opt)
1706 {
1707 my $DObjects = parseTag(\$Content, "libs");
1708 if(not $DObjects) {
1709 exitStatus("Error", "$SLIB_TYPE libraries in the $DName are not specified (<libs> section)");
1710 }
1711 elsif(lc($DObjects) ne "none")
1712 { # append the descriptor libraries list
1713 if($Descriptor{$LibVersion}{"Libs"})
1714 { # multiple descriptors
1715 $Descriptor{$LibVersion}{"Libs"} .= "\n".$DObjects;
1716 }
1717 else {
1718 $Descriptor{$LibVersion}{"Libs"} .= $DObjects;
1719 }
1720 foreach my $Path (split(/\s*\n\s*/, $DObjects))
1721 {
1722 if(not -e $Path) {
1723 exitStatus("Access_Error", "can't access \'$Path\'");
1724 }
1725 }
1726 }
1727 }
1728 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_headers")))
1729 {
1730 $Path = clean_path($Path);
1731 if(not -d $Path) {
1732 exitStatus("Access_Error", "can't access directory \'$Path\'");
1733 }
1734 $Path = path_format($Path, $OSgroup);
1735 $SystemPaths{"include"}{$Path}=1;
1736 }
1737 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_libs")))
1738 {
1739 $Path = clean_path($Path);
1740 if(not -d $Path) {
1741 exitStatus("Access_Error", "can't access directory \'$Path\'");
1742 }
1743 $Path = path_format($Path, $OSgroup);
1744 $SystemPaths{"lib"}{$Path}=1;
1745 }
1746 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "tools")))
1747 {
1748 $Path=clean_path($Path);
1749 if(not -d $Path) {
1750 exitStatus("Access_Error", "can't access directory \'$Path\'");
1751 }
1752 $Path = path_format($Path, $OSgroup);
1753 $SystemPaths{"bin"}{$Path}=1;
1754 $TargetTools{$Path}=1;
1755 }
1756 if(my $Prefix = parseTag(\$Content, "cross_prefix")) {
1757 $CrossPrefix = $Prefix;
1758 }
1759 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "include_paths")))
1760 {
1761 $Path=clean_path($Path);
1762 if(not -d $Path) {
1763 exitStatus("Access_Error", "can't access directory \'$Path\'");
1764 }
1765 $Path = path_format($Path, $OSgroup);
1766 $Descriptor{$LibVersion}{"IncludePaths"}{$Path} = 1;
1767 }
1768 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "add_include_paths")))
1769 {
1770 $Path=clean_path($Path);
1771 if(not -d $Path) {
1772 exitStatus("Access_Error", "can't access directory \'$Path\'");
1773 }
1774 $Path = path_format($Path, $OSgroup);
1775 $Descriptor{$LibVersion}{"AddIncludePaths"}{$Path} = 1;
1776 }
1777 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_include_paths")))
1778 {
1779 # skip some auto-generated include paths
1780 $Skip_Include_Paths{$LibVersion}{path_format($Path)}=1;
1781 }
1782 foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_including")))
1783 {
1784 # skip direct including of some headers
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001785 $SkipHeadersList{$LibVersion}{$Path} = 2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001786 my ($CPath, $Type) = classifyPath($Path);
1787 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001788 }
1789 $Descriptor{$LibVersion}{"GccOptions"} = parseTag(\$Content, "gcc_options");
1790 foreach my $Option (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"GccOptions"})) {
1791 $CompilerOptions{$LibVersion} .= " ".$Option;
1792 }
1793 $Descriptor{$LibVersion}{"SkipHeaders"} = parseTag(\$Content, "skip_headers");
1794 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipHeaders"}))
1795 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001796 $SkipHeadersList{$LibVersion}{$Path} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001797 my ($CPath, $Type) = classifyPath($Path);
1798 $SkipHeaders{$LibVersion}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001799 }
1800 $Descriptor{$LibVersion}{"SkipLibs"} = parseTag(\$Content, "skip_libs");
1801 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipLibs"}))
1802 {
1803 my ($CPath, $Type) = classifyPath($Path);
1804 $SkipLibs{$LibVersion}{$Type}{$CPath} = 1;
1805 }
1806 if(my $DDefines = parseTag(\$Content, "defines"))
1807 {
1808 if($Descriptor{$LibVersion}{"Defines"})
1809 { # multiple descriptors
1810 $Descriptor{$LibVersion}{"Defines"} .= "\n".$DDefines;
1811 }
1812 else {
1813 $Descriptor{$LibVersion}{"Defines"} = $DDefines;
1814 }
1815 }
1816 foreach my $Order (split(/\s*\n\s*/, parseTag(\$Content, "include_order")))
1817 {
1818 if($Order=~/\A(.+):(.+)\Z/) {
1819 $Include_Order{$LibVersion}{$1} = $2;
1820 }
1821 }
1822 foreach my $Type_Name (split(/\s*\n\s*/, parseTag(\$Content, "opaque_types")),
1823 split(/\s*\n\s*/, parseTag(\$Content, "skip_types")))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001824 { # opaque_types renamed to skip_types (1.23.4)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001825 $SkipTypes{$LibVersion}{$Type_Name} = 1;
1826 }
1827 foreach my $Symbol (split(/\s*\n\s*/, parseTag(\$Content, "skip_interfaces")),
1828 split(/\s*\n\s*/, parseTag(\$Content, "skip_symbols")))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001829 { # skip_interfaces renamed to skip_symbols (1.22.1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001830 $SkipSymbols{$LibVersion}{$Symbol} = 1;
1831 }
1832 foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "skip_namespaces"))) {
1833 $SkipNameSpaces{$LibVersion}{$NameSpace} = 1;
1834 }
1835 foreach my $Constant (split(/\s*\n\s*/, parseTag(\$Content, "skip_constants"))) {
1836 $SkipConstants{$LibVersion}{$Constant} = 1;
1837 }
1838 if(my $DIncPreamble = parseTag(\$Content, "include_preamble"))
1839 {
1840 if($Descriptor{$LibVersion}{"IncludePreamble"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04001841 { # multiple descriptors
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001842 $Descriptor{$LibVersion}{"IncludePreamble"} .= "\n".$DIncPreamble;
1843 }
1844 else {
1845 $Descriptor{$LibVersion}{"IncludePreamble"} = $DIncPreamble;
1846 }
1847 }
1848}
1849
1850sub parseTag($$)
1851{
1852 my ($CodeRef, $Tag) = @_;
1853 return "" if(not $CodeRef or not ${$CodeRef} or not $Tag);
1854 if(${$CodeRef}=~s/\<\Q$Tag\E\>((.|\n)+?)\<\/\Q$Tag\E\>//)
1855 {
1856 my $Content = $1;
1857 $Content=~s/(\A\s+|\s+\Z)//g;
1858 return $Content;
1859 }
1860 else {
1861 return "";
1862 }
1863}
1864
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001865my %NodeType= (
1866 "array_type" => "Array",
1867 "binfo" => "Other",
1868 "boolean_type" => "Intrinsic",
1869 "complex_type" => "Intrinsic",
1870 "const_decl" => "Other",
1871 "enumeral_type" => "Enum",
1872 "field_decl" => "Other",
1873 "function_decl" => "Other",
1874 "function_type" => "FunctionType",
1875 "identifier_node" => "Other",
1876 "integer_cst" => "Other",
1877 "integer_type" => "Intrinsic",
1878 "method_type" => "MethodType",
1879 "namespace_decl" => "Other",
1880 "parm_decl" => "Other",
1881 "pointer_type" => "Pointer",
1882 "real_cst" => "Other",
1883 "real_type" => "Intrinsic",
1884 "record_type" => "Struct",
1885 "reference_type" => "Ref",
1886 "string_cst" => "Other",
1887 "template_decl" => "Other",
1888 "template_type_parm" => "Other",
1889 "tree_list" => "Other",
1890 "tree_vec" => "Other",
1891 "type_decl" => "Other",
1892 "union_type" => "Union",
1893 "var_decl" => "Other",
1894 "void_type" => "Intrinsic",
1895 "offset_type" => "Other" );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001896
1897sub getInfo($)
1898{
1899 my $InfoPath = $_[0];
1900 return if(not $InfoPath or not -f $InfoPath);
1901 my $Content = readFile($InfoPath);
1902 unlink($InfoPath);
1903 $Content=~s/\n[ ]+/ /g;
1904 my @Lines = split("\n", $Content);
1905 $Content="";# clear
1906 foreach (@Lines)
1907 {
1908 if(/\A\@(\d+)\s+([a-z_]+)\s+(.+)\Z/oi)
1909 { # get a number and attributes of a node
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04001910 next if(not $NodeType{$2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001911 $LibInfo{$Version}{"info_type"}{$1}=$2;
1912 $LibInfo{$Version}{"info"}{$1}=$3;
1913 }
1914 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04001915 $MAX_ID = $#Lines+1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04001916 @Lines=();# clear
1917 # processing info
1918 setTemplateParams_All();
1919 getTypeInfo_All();
1920 simplifyNames();
1921 getSymbolInfo_All();
1922 getVarInfo_All();
1923
1924 # cleaning memory
1925 %LibInfo = ();
1926 %TemplateInstance = ();
1927 %TemplateInstance_Func = ();
1928 %MangledNames = ();
1929
1930 if($Debug) {
1931 # debugMangling($Version);
1932 }
1933}
1934
1935sub simplifyNames()
1936{
1937 foreach my $Base (keys(%{$Typedef_Tr{$Version}}))
1938 {
1939 my @Translations = keys(%{$Typedef_Tr{$Version}{$Base}});
1940 if($#Translations==0 and length($Translations[0])<=length($Base)) {
1941 $Typedef_Eq{$Version}{$Base} = $Translations[0];
1942 }
1943 }
1944 foreach my $TDid (keys(%{$TypeInfo{$Version}}))
1945 {
1946 foreach my $Tid (keys(%{$TypeInfo{$Version}{$TDid}}))
1947 {
1948 my $TypeName = $TypeInfo{$Version}{$TDid}{$Tid}{"Name"};
1949 if(not $TypeName) {
1950 next;
1951 }
1952 next if(index($TypeName,"<")==-1);# template instances only
1953 if($TypeName=~/>(::\w+)+\Z/)
1954 { # skip unused types
1955 next;
1956 };
1957 foreach my $Base (sort {length($b)<=>length($a)}
1958 sort {$b cmp $a} keys(%{$Typedef_Eq{$Version}}))
1959 {
1960 next if(not $Base);
1961 next if(index($TypeName,$Base)==-1);
1962 next if(length($TypeName) - length($Base) <= 3);
1963 my $Typedef = $Typedef_Eq{$Version}{$Base};
1964 $TypeName=~s/(\<|\,)\Q$Base\E(\W|\Z)/$1$Typedef$2/g;
1965 $TypeName=~s/(\<|\,)\Q$Base\E(\w|\Z)/$1$Typedef $2/g;
1966 }
1967 if($TypeName ne $TypeInfo{$Version}{$TDid}{$Tid}{"Name"})
1968 {
1969 $TypeInfo{$Version}{$TDid}{$Tid}{"Name"} = formatName($TypeName);
1970 $TName_Tid{$Version}{$TypeName} = $Tid;
1971 }
1972 }
1973 }
1974}
1975
1976sub setTemplateParams_All()
1977{
1978 foreach (keys(%{$LibInfo{$Version}{"info"}}))
1979 {
1980 if($LibInfo{$Version}{"info_type"}{$_} eq "template_decl") {
1981 setTemplateParams($_);
1982 }
1983 }
1984}
1985
1986sub setTemplateParams($)
1987{
1988 my $TypeInfoId = $_[0];
1989 if($LibInfo{$Version}{"info"}{$TypeInfoId}=~/(inst|spcs)[ ]*:[ ]*@(\d+) /)
1990 {
1991 my $TmplInst_InfoId = $2;
1992 setTemplateInstParams($TmplInst_InfoId);
1993 my $TmplInst_Info = $LibInfo{$Version}{"info"}{$TmplInst_InfoId};
1994 while($TmplInst_Info=~/(chan|chain)[ ]*:[ ]*@(\d+) /)
1995 {
1996 $TmplInst_InfoId = $2;
1997 $TmplInst_Info = $LibInfo{$Version}{"info"}{$TmplInst_InfoId};
1998 setTemplateInstParams($TmplInst_InfoId);
1999 }
2000 }
2001}
2002
2003sub setTemplateInstParams($)
2004{
2005 my $TmplInst_Id = $_[0];
2006 my $Info = $LibInfo{$Version}{"info"}{$TmplInst_Id};
2007 my ($Params_InfoId, $ElemId) = ();
2008 if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
2009 $Params_InfoId = $1;
2010 }
2011 if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
2012 $ElemId = $1;
2013 }
2014 if($Params_InfoId and $ElemId)
2015 {
2016 my $Params_Info = $LibInfo{$Version}{"info"}{$Params_InfoId};
2017 while($Params_Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
2018 {
2019 my ($Param_Pos, $Param_TypeId) = ($1, $2);
2020 return if($LibInfo{$Version}{"info_type"}{$Param_TypeId} eq "template_type_parm");
2021 if($LibInfo{$Version}{"info_type"}{$ElemId} eq "function_decl") {
2022 $TemplateInstance_Func{$Version}{$ElemId}{$Param_Pos} = $Param_TypeId;
2023 }
2024 else {
2025 $TemplateInstance{$Version}{getTypeDeclId($ElemId)}{$ElemId}{$Param_Pos} = $Param_TypeId;
2026 }
2027 }
2028 }
2029}
2030
2031sub getTypeDeclId($)
2032{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002033 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2034 {
2035 if($Info=~/name[ ]*:[ ]*@(\d+)/) {
2036 return $1;
2037 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002038 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002039 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002040}
2041
2042sub isFuncPtr($)
2043{
2044 my $Ptd = pointTo($_[0]);
2045 return 0 if(not $Ptd);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002046 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2047 {
2048 if($Info=~/unql[ ]*:/ and $Info!~/qual[ ]*:/) {
2049 return 0;
2050 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002051 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002052 if(my $InfoT1 = $LibInfo{$Version}{"info_type"}{$_[0]}
2053 and my $InfoT2 = $LibInfo{$Version}{"info_type"}{$Ptd})
2054 {
2055 if($InfoT1 eq "pointer_type"
2056 and $InfoT2 eq "function_type") {
2057 return 1;
2058 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002059 }
2060 return 0;
2061}
2062
2063sub isMethodPtr($)
2064{
2065 my $Ptd = pointTo($_[0]);
2066 return 0 if(not $Ptd);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002067 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2068 {
2069 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "record_type"
2070 and $LibInfo{$Version}{"info_type"}{$Ptd} eq "method_type"
2071 and $Info=~/ ptrmem /) {
2072 return 1;
2073 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002074 }
2075 return 0;
2076}
2077
2078sub isFieldPtr($)
2079{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002080 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2081 {
2082 if($LibInfo{$Version}{"info_type"}{$_[0]} eq "offset_type"
2083 and $Info=~/ ptrmem /) {
2084 return 1;
2085 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002086 }
2087 return 0;
2088}
2089
2090sub pointTo($)
2091{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002092 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2093 {
2094 if($Info=~/ptd[ ]*:[ ]*@(\d+)/) {
2095 return $1;
2096 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002097 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002098 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002099}
2100
2101sub getTypeInfo_All()
2102{
2103 if(not check_gcc_version($GCC_PATH, "4.5"))
2104 { # support for GCC < 4.5
2105 # missed typedefs: QStyle::State is typedef to QFlags<QStyle::StateFlag>
2106 # but QStyleOption.state is of type QFlags<QStyle::StateFlag> in the TU dump
2107 # FIXME: check GCC versions
2108 addMissedTypes_Pre();
2109 }
2110 foreach (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
2111 {
2112 my $IType = $LibInfo{$Version}{"info_type"}{$_};
2113 if($IType=~/_type\Z/ and $IType ne "function_type"
2114 and $IType ne "method_type") {
2115 getTypeInfo(getTypeDeclId("$_"), "$_");
2116 }
2117 }
2118 $TypeInfo{$Version}{""}{-1}{"Name"} = "...";
2119 $TypeInfo{$Version}{""}{-1}{"Type"} = "Intrinsic";
2120 $TypeInfo{$Version}{""}{-1}{"Tid"} = -1;
2121 if(not check_gcc_version($GCC_PATH, "4.5"))
2122 { # support for GCC < 4.5
2123 addMissedTypes_Post();
2124 }
2125}
2126
2127sub addMissedTypes_Pre()
2128{
2129 foreach my $MissedTDid (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
2130 { # detecting missed typedefs
2131 if($LibInfo{$Version}{"info_type"}{$MissedTDid} eq "type_decl")
2132 {
2133 my $TypeId = getTreeAttr($MissedTDid, "type");
2134 next if(not $TypeId);
2135 my $TypeType = getTypeType($MissedTDid, $TypeId);
2136 if($TypeType eq "Unknown")
2137 { # template_type_parm
2138 next;
2139 }
2140 my $TypeDeclId = getTypeDeclId($TypeId);
2141 next if($TypeDeclId eq $MissedTDid);#or not $TypeDeclId
2142 my $TypedefName = getNameByInfo($MissedTDid);
2143 next if(not $TypedefName);
2144 next if($TypedefName eq "__float80");
2145 next if(isAnon($TypedefName));
2146 if(not $TypeDeclId
2147 or getNameByInfo($TypeDeclId) ne $TypedefName) {
2148 $MissedTypedef{$Version}{$TypeId}{"$MissedTDid"} = 1;
2149 }
2150 }
2151 }
2152 foreach my $Tid (keys(%{$MissedTypedef{$Version}}))
2153 { # add missed typedefs
2154 my @Missed = keys(%{$MissedTypedef{$Version}{$Tid}});
2155 if(not @Missed or $#Missed>=1) {
2156 delete($MissedTypedef{$Version}{$Tid});
2157 next;
2158 }
2159 my $MissedTDid = $Missed[0];
2160 my $TDid = getTypeDeclId($Tid);
2161 my ($TypedefName, $TypedefNS) = getTrivialName($MissedTDid, $Tid);
2162 my %MissedInfo = ( # typedef info
2163 "Name" => $TypedefName,
2164 "NameSpace" => $TypedefNS,
2165 "BaseType" => {
2166 "TDid" => $TDid,
2167 "Tid" => $Tid
2168 },
2169 "Type" => "Typedef",
Andrey Ponomarenko16934472012-03-29 15:37:04 +04002170 "Tid" => ++$MAX_ID,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002171 "TDid" => $MissedTDid );
2172 my ($H, $L) = getLocation($MissedTDid);
2173 $MissedInfo{"Header"} = $H;
2174 $MissedInfo{"Line"} = $L;
2175 # $MissedInfo{"Size"} = getSize($Tid)/$BYTE_SIZE;
2176 my $MName = $MissedInfo{"Name"};
2177 next if(not $MName);
2178 if($MName=~/\*|\&|\s/)
2179 { # other types
2180 next;
2181 }
2182 if($MName=~/>(::\w+)+\Z/)
2183 { # QFlags<Qt::DropAction>::enum_type
2184 delete($MissedTypedef{$Version}{$Tid});
2185 next;
2186 }
2187 if(getTypeType($TDid, $Tid)=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
2188 { # double-check for the name of typedef
2189 my ($TName, $TNS) = getTrivialName($TDid, $Tid); # base type info
2190 next if(not $TName);
2191 if(length($MName)>=length($TName))
2192 { # too long typedef
2193 delete($MissedTypedef{$Version}{$Tid});
2194 next;
2195 }
2196 if($TName=~/\A\Q$MName\E</) {
2197 next;
2198 }
2199 if($MName=~/\A\Q$TName\E/)
2200 { # QDateTimeEdit::Section and QDateTimeEdit::Sections::enum_type
2201 delete($MissedTypedef{$Version}{$Tid});
2202 next;
2203 }
2204 if(get_depth($MName)==0 and get_depth($TName)!=0)
2205 { # std::_Vector_base and std::vector::_Base
2206 delete($MissedTypedef{$Version}{$Tid});
2207 next;
2208 }
2209 }
2210 %{$TypeInfo{$Version}{$MissedTDid}{$MissedInfo{"Tid"}}} = %MissedInfo;
2211 $Tid_TDid{$Version}{$MissedInfo{"Tid"}} = $MissedTDid;
2212 delete($TypeInfo{$Version}{$MissedTDid}{$Tid});
2213 # register typedef
2214 $MissedTypedef{$Version}{$Tid}{"TDid"} = $MissedTDid;
2215 $MissedTypedef{$Version}{$Tid}{"Tid"} = $MissedInfo{"Tid"};
2216 }
2217}
2218
2219sub addMissedTypes_Post()
2220{
2221 foreach my $BaseId (keys(%{$MissedTypedef{$Version}}))
2222 {
2223 my $Tid = $MissedTypedef{$Version}{$BaseId}{"Tid"};
2224 my $TDid = $MissedTypedef{$Version}{$BaseId}{"TDid"};
2225 $TypeInfo{$Version}{$TDid}{$Tid}{"Size"} = get_TypeAttr($BaseId, $Version, "Size");
2226 }
2227}
2228
2229sub getTypeInfo($$)
2230{
2231 my ($TDId, $TId) = @_;
2232 %{$TypeInfo{$Version}{$TDId}{$TId}} = getTypeAttr($TDId, $TId);
2233 my $TName = $TypeInfo{$Version}{$TDId}{$TId}{"Name"};
2234 if(not $TName) {
2235 delete($TypeInfo{$Version}{$TDId}{$TId});
2236 return;
2237 }
2238 if($TDId) {
2239 $Tid_TDid{$Version}{$TId} = $TDId;
2240 }
2241 if(not $TName_Tid{$Version}{$TName}) {
2242 $TName_Tid{$Version}{$TName} = $TId;
2243 }
2244}
2245
2246sub getArraySize($$)
2247{
2248 my ($TypeId, $BaseName) = @_;
2249 my $SizeBytes = getSize($TypeId)/$BYTE_SIZE;
2250 while($BaseName=~s/\s*\[(\d+)\]//) {
2251 $SizeBytes/=$1;
2252 }
2253 my $BasicId = $TName_Tid{$Version}{$BaseName};
2254 if(my $BasicSize = $TypeInfo{$Version}{getTypeDeclId($BasicId)}{$BasicId}{"Size"}) {
2255 $SizeBytes/=$BasicSize;
2256 }
2257 return $SizeBytes;
2258}
2259
2260sub getTParams_Func($)
2261{
Andrey Ponomarenko16934472012-03-29 15:37:04 +04002262 my $InfoId = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002263 my @TmplParams = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +04002264 foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$TemplateInstance_Func{$Version}{$InfoId}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002265 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04002266 my $Param = get_TemplateParam($Pos, $TemplateInstance_Func{$Version}{$InfoId}{$Pos});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002267 if($Param eq "") {
2268 return ();
2269 }
2270 elsif($Param ne "\@skip\@") {
2271 push(@TmplParams, $Param);
2272 }
2273 }
2274 return @TmplParams;
2275}
2276
2277sub getTParams($$)
2278{
2279 my ($TypeDeclId, $TypeId) = @_;
2280 my @Template_Params = ();
2281 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$TemplateInstance{$Version}{$TypeDeclId}{$TypeId}}))
2282 {
2283 my $Param_TypeId = $TemplateInstance{$Version}{$TypeDeclId}{$TypeId}{$Pos};
2284 my $Param = get_TemplateParam($Pos, $Param_TypeId);
2285 if($Param eq "") {
2286 return ();
2287 }
2288 elsif($Param ne "\@skip\@") {
2289 @Template_Params = (@Template_Params, $Param);
2290 }
2291 }
2292 return @Template_Params;
2293}
2294
2295sub getTypeAttr($$)
2296{
2297 my ($TypeDeclId, $TypeId) = @_;
2298 my ($BaseTypeSpec, %TypeAttr) = ();
2299 if(defined $TypeInfo{$Version}{$TypeDeclId}{$TypeId}
2300 and $TypeInfo{$Version}{$TypeDeclId}{$TypeId}{"Name"}) {
2301 return %{$TypeInfo{$Version}{$TypeDeclId}{$TypeId}};
2302 }
2303 $TypeAttr{"Tid"} = $TypeId;
2304 $TypeAttr{"TDid"} = $TypeDeclId;
2305 $TypeAttr{"Type"} = getTypeType($TypeDeclId, $TypeId);
2306 if($TypeAttr{"Type"} eq "Unknown") {
2307 return ();
2308 }
2309 elsif($TypeAttr{"Type"}=~/(Func|Method|Field)Ptr/)
2310 {
2311 %{$TypeInfo{$Version}{$TypeDeclId}{$TypeId}} = getMemPtrAttr(pointTo($TypeId), $TypeDeclId, $TypeId, $TypeAttr{"Type"});
2312 $TName_Tid{$Version}{$TypeInfo{$Version}{$TypeDeclId}{$TypeId}{"Name"}} = $TypeId;
2313 return %{$TypeInfo{$Version}{$TypeDeclId}{$TypeId}};
2314 }
2315 elsif($TypeAttr{"Type"} eq "Array")
2316 {
2317 ($TypeAttr{"BaseType"}{"Tid"}, $TypeAttr{"BaseType"}{"TDid"}, $BaseTypeSpec) = selectBaseType($TypeDeclId, $TypeId);
2318 my %BaseTypeAttr = getTypeAttr($TypeAttr{"BaseType"}{"TDid"}, $TypeAttr{"BaseType"}{"Tid"});
2319 if(my $NElems = getArraySize($TypeId, $BaseTypeAttr{"Name"}))
2320 {
2321 $TypeAttr{"Size"} = getSize($TypeId)/$BYTE_SIZE;
2322 if($BaseTypeAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
2323 $TypeAttr{"Name"} = $1."[$NElems]".$2;
2324 }
2325 else {
2326 $TypeAttr{"Name"} = $BaseTypeAttr{"Name"}."[$NElems]";
2327 }
2328 }
2329 else
2330 {
2331 $TypeAttr{"Size"} = $WORD_SIZE{$Version}; # pointer
2332 if($BaseTypeAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
2333 $TypeAttr{"Name"} = $1."[]".$2;
2334 }
2335 else {
2336 $TypeAttr{"Name"} = $BaseTypeAttr{"Name"}."[]";
2337 }
2338 }
2339 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"});
2340 if($BaseTypeAttr{"Header"}) {
2341 $TypeAttr{"Header"} = $BaseTypeAttr{"Header"};
2342 }
2343 %{$TypeInfo{$Version}{$TypeDeclId}{$TypeId}} = %TypeAttr;
2344 $TName_Tid{$Version}{$TypeInfo{$Version}{$TypeDeclId}{$TypeId}{"Name"}} = $TypeId;
2345 return %TypeAttr;
2346 }
2347 elsif($TypeAttr{"Type"}=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
2348 {
2349 %{$TypeInfo{$Version}{$TypeDeclId}{$TypeId}} = getTrivialTypeAttr($TypeDeclId, $TypeId);
2350 return %{$TypeInfo{$Version}{$TypeDeclId}{$TypeId}};
2351 }
2352 else
2353 {
2354 ($TypeAttr{"BaseType"}{"Tid"}, $TypeAttr{"BaseType"}{"TDid"}, $BaseTypeSpec) = selectBaseType($TypeDeclId, $TypeId);
2355 if(my $MissedTDid = $MissedTypedef{$Version}{$TypeAttr{"BaseType"}{"Tid"}}{"TDid"})
2356 {
2357 if($MissedTDid ne $TypeDeclId)
2358 {
2359 $TypeAttr{"BaseType"}{"TDid"} = $MissedTDid;
2360 $TypeAttr{"BaseType"}{"Tid"} = $MissedTypedef{$Version}{$TypeAttr{"BaseType"}{"Tid"}}{"Tid"};
2361 }
2362 }
2363 my %BaseTypeAttr = getTypeAttr($TypeAttr{"BaseType"}{"TDid"}, $TypeAttr{"BaseType"}{"Tid"});
2364 if(not $BaseTypeAttr{"Name"})
2365 { # const "template_type_parm"
2366 return ();
2367 }
2368 if($BaseTypeAttr{"Type"} eq "Typedef")
2369 { # relinking typedefs
2370 my %BaseBase = get_Type($BaseTypeAttr{"BaseType"}{"TDid"},$BaseTypeAttr{"BaseType"}{"Tid"}, $Version);
2371 if($BaseTypeAttr{"Name"} eq $BaseBase{"Name"}) {
2372 ($TypeAttr{"BaseType"}{"Tid"}, $TypeAttr{"BaseType"}{"TDid"}) = ($BaseBase{"Tid"}, $BaseBase{"TDid"});
2373 }
2374 }
2375 if($BaseTypeSpec)
2376 {
2377 if($TypeAttr{"Type"} eq "Pointer"
2378 and $BaseTypeAttr{"Name"}=~/\([\*]+\)/) {
2379 $TypeAttr{"Name"} = $BaseTypeAttr{"Name"};
2380 $TypeAttr{"Name"}=~s/\(([*]+)\)/($1*)/g;
2381 }
2382 else {
2383 $TypeAttr{"Name"} = $BaseTypeAttr{"Name"}." ".$BaseTypeSpec;
2384 }
2385 }
2386 else {
2387 $TypeAttr{"Name"} = $BaseTypeAttr{"Name"};
2388 }
2389 if($TypeAttr{"Type"} eq "Typedef")
2390 {
2391 $TypeAttr{"Name"} = getNameByInfo($TypeDeclId);
2392 if(my $NS = getNameSpace($TypeDeclId))
2393 {
2394 my $TypeName = $TypeAttr{"Name"};
2395 if($NS=~/\A(struct |union |class |)((.+)::|)\Q$TypeName\E\Z/)
2396 { # "some_type" is the typedef to "struct some_type" in C++
2397 if($3) {
2398 $TypeAttr{"Name"} = $3."::".$TypeName;
2399 }
2400 }
2401 else
2402 {
2403 $TypeAttr{"NameSpace"} = $NS;
2404 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
2405 if($TypeAttr{"NameSpace"}=~/\Astd(::|\Z)/ and $BaseTypeAttr{"NameSpace"}=~/\Astd(::|\Z)/
2406 and $BaseTypeAttr{"Name"}=~/</ and $TypeAttr{"Name"}!~/>(::\w+)+\Z/)
2407 { # types like "std::fpos<__mbstate_t>" are
2408 # not covered by typedefs in the ABI dump
2409 # so trying to add such typedefs manually
2410 $StdCxxTypedef{$Version}{$BaseTypeAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
2411 if(length($TypeAttr{"Name"})<=length($BaseTypeAttr{"Name"}))
2412 {
2413 if(($BaseTypeAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/))
2414 { # skip "other" in "std" and "type" in "boost"
2415 $Typedef_Eq{$Version}{$BaseTypeAttr{"Name"}} = $TypeAttr{"Name"};
2416 }
2417 }
2418 }
2419 }
2420 }
2421 if($TypeAttr{"Name"} ne $BaseTypeAttr{"Name"}
2422 and $TypeAttr{"Name"}!~/>(::\w+)+\Z/ and $BaseTypeAttr{"Name"}!~/>(::\w+)+\Z/)
2423 {
2424 $Typedef_BaseName{$Version}{$TypeAttr{"Name"}} = $BaseTypeAttr{"Name"};
2425 if($BaseTypeAttr{"Name"}=~/</)
2426 {
2427 if(($BaseTypeAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/)) {
2428 $Typedef_Tr{$Version}{$BaseTypeAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
2429 }
2430 }
2431 }
2432 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeDeclId);
2433 }
2434 if(not $TypeAttr{"Size"})
2435 {
2436 if($TypeAttr{"Type"} eq "Pointer") {
2437 $TypeAttr{"Size"} = $WORD_SIZE{$Version};
2438 }
2439 elsif($BaseTypeAttr{"Size"}) {
2440 $TypeAttr{"Size"} = $BaseTypeAttr{"Size"};
2441 }
2442 }
2443 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"});
2444 if(not $TypeAttr{"Header"} and $BaseTypeAttr{"Header"}) {
2445 $TypeAttr{"Header"} = $BaseTypeAttr{"Header"};
2446 }
2447 %{$TypeInfo{$Version}{$TypeDeclId}{$TypeId}} = %TypeAttr;
2448 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
2449 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
2450 }
2451 return %TypeAttr;
2452 }
2453}
2454
2455sub get_TemplateParam($$)
2456{
2457 my ($Pos, $Type_Id) = @_;
2458 return "" if(not $Type_Id);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002459 if(getNodeType($Type_Id) eq "integer_cst")
2460 { # int (1), unsigned (2u), char ('c' as 99), ...
2461 my $CstTid = getTreeAttr($Type_Id, "type");
2462 my %CstType = getTypeAttr(getTypeDeclId($CstTid), $CstTid);
2463 my $Num = getNodeIntCst($Type_Id);
2464 if(my $CstSuffix = $ConstantSuffix{$CstType{"Name"}}) {
2465 return $Num.$CstSuffix;
2466 }
2467 else {
2468 return "(".$CstType{"Name"}.")".$Num;
2469 }
2470 }
2471 elsif(getNodeType($Type_Id) eq "string_cst") {
2472 return getNodeStrCst($Type_Id);
2473 }
2474 elsif(getNodeType($Type_Id) eq "tree_vec") {
2475 return "\@skip\@";
2476 }
2477 else
2478 {
2479 my $Type_DId = getTypeDeclId($Type_Id);
2480 my %ParamAttr = getTypeAttr($Type_DId, $Type_Id);
2481 if(not $ParamAttr{"Name"}) {
2482 return "";
2483 }
2484 my $PName = $ParamAttr{"Name"};
2485 if($ParamAttr{"Name"}=~/\>/) {
2486 if(my $Cover = cover_stdcxx_typedef($ParamAttr{"Name"})) {
2487 $PName = $Cover;
2488 }
2489 }
2490 if($Pos>=1 and
2491 $PName=~/\Astd::(allocator|less|((char|regex)_traits)|((i|o)streambuf_iterator))\</)
2492 { # template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
2493 # template<typename _Key, typename _Compare = std::less<_Key>
2494 # template<typename _CharT, typename _Traits = std::char_traits<_CharT> >
2495 # template<typename _Ch_type, typename _Rx_traits = regex_traits<_Ch_type> >
2496 # template<typename _CharT, typename _InIter = istreambuf_iterator<_CharT> >
2497 # template<typename _CharT, typename _OutIter = ostreambuf_iterator<_CharT> >
2498 return "\@skip\@";
2499 }
2500 return $PName;
2501 }
2502}
2503
2504sub cover_stdcxx_typedef($)
2505{
2506 my $TypeName = $_[0];
2507 if(my @Covers = sort {length($a)<=>length($b)}
2508 sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
2509 { # take the shortest typedef
2510 # FIXME: there may be more than
2511 # one typedefs to the same type
2512 return $Covers[0];
2513 }
2514 my $TypeName_Covered = $TypeName;
2515 while($TypeName=~s/(>)[ ]*(const|volatile|restrict| |\*|\&)\Z/$1/g){};
2516 if(my @Covers = sort {length($a)<=>length($b)} sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
2517 {
2518 my $Cover = $Covers[0];
2519 $TypeName_Covered=~s/(\W|\A)\Q$TypeName\E(\W|\Z)/$1$Cover$2/g;
2520 $TypeName_Covered=~s/(\W|\A)\Q$TypeName\E(\w|\Z)/$1$Cover $2/g;
2521 }
2522 return formatName($TypeName_Covered);
2523}
2524
2525sub getNodeType($)
2526{
2527 return $LibInfo{$Version}{"info_type"}{$_[0]};
2528}
2529
2530sub getNodeIntCst($)
2531{
2532 my $CstId = $_[0];
2533 my $CstTypeId = getTreeAttr($CstId, "type");
2534 if($EnumMembName_Id{$Version}{$CstId}) {
2535 return $EnumMembName_Id{$Version}{$CstId};
2536 }
2537 elsif((my $Value = getTreeValue($CstId)) ne "")
2538 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002539 if($Value eq "0")
2540 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002541 if(getNodeType($CstTypeId) eq "boolean_type") {
2542 return "false";
2543 }
2544 else {
2545 return "0";
2546 }
2547 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002548 elsif($Value eq "1")
2549 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002550 if(getNodeType($CstTypeId) eq "boolean_type") {
2551 return "true";
2552 }
2553 else {
2554 return "1";
2555 }
2556 }
2557 else {
2558 return $Value;
2559 }
2560 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002561 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002562}
2563
2564sub getNodeStrCst($)
2565{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002566 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
2567 {
2568 if($Info=~/strg[ ]*: (.+) lngt:[ ]*(\d+)/)
2569 { # string length is N-1 because of the null terminator
2570 return substr($1, 0, $2-1);
2571 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002572 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002573 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002574}
2575
2576sub getMemPtrAttr($$$$)
2577{ # function, method and field pointers
2578 my ($PtrId, $TypeDeclId, $TypeId, $Type) = @_;
2579 my $MemInfo = $LibInfo{$Version}{"info"}{$PtrId};
2580 if($Type eq "FieldPtr") {
2581 $MemInfo = $LibInfo{$Version}{"info"}{$TypeId};
2582 }
2583 my $MemInfo_Type = $LibInfo{$Version}{"info_type"}{$PtrId};
2584 my $MemPtrName = "";
2585 my %TypeAttr = ("Size"=>$WORD_SIZE{$Version}, "Type"=>$Type, "TDid"=>$TypeDeclId, "Tid"=>$TypeId);
2586 if($Type eq "MethodPtr")
2587 { # size of "method pointer" may be greater than WORD size
2588 $TypeAttr{"Size"} = getSize($TypeId)/$BYTE_SIZE;
2589 }
2590 # Return
2591 if($Type eq "FieldPtr")
2592 {
2593 my %ReturnAttr = getTypeAttr(getTypeDeclId($PtrId), $PtrId);
2594 $MemPtrName .= $ReturnAttr{"Name"};
2595 $TypeAttr{"Return"} = $PtrId;
2596 }
2597 else
2598 {
2599 if($MemInfo=~/retn[ ]*:[ ]*\@(\d+) /)
2600 {
2601 my $ReturnTypeId = $1;
2602 my %ReturnAttr = getTypeAttr(getTypeDeclId($ReturnTypeId), $ReturnTypeId);
2603 $MemPtrName .= $ReturnAttr{"Name"};
2604 $TypeAttr{"Return"} = $ReturnTypeId;
2605 }
2606 }
2607 # Class
2608 if($MemInfo=~/(clas|cls)[ ]*:[ ]*@(\d+) /)
2609 {
2610 $TypeAttr{"Class"} = $2;
2611 my %Class = getTypeAttr(getTypeDeclId($TypeAttr{"Class"}), $TypeAttr{"Class"});
2612 if($Class{"Name"}) {
2613 $MemPtrName .= " (".$Class{"Name"}."\:\:*)";
2614 }
2615 else {
2616 $MemPtrName .= " (*)";
2617 }
2618 }
2619 else {
2620 $MemPtrName .= " (*)";
2621 }
2622 # Parameters
2623 if($Type eq "FuncPtr"
2624 or $Type eq "MethodPtr")
2625 {
2626 my @ParamTypeName = ();
2627 if($MemInfo=~/prms[ ]*:[ ]*@(\d+) /)
2628 {
2629 my $ParamTypeInfoId = $1;
2630 my $Position = 0;
2631 while($ParamTypeInfoId)
2632 {
2633 my $ParamTypeInfo = $LibInfo{$Version}{"info"}{$ParamTypeInfoId};
2634 last if($ParamTypeInfo!~/valu[ ]*:[ ]*@(\d+) /);
2635 my $ParamTypeId = $1;
2636 my %ParamAttr = getTypeAttr(getTypeDeclId($ParamTypeId), $ParamTypeId);
2637 last if($ParamAttr{"Name"} eq "void");
2638 if($Position!=0 or $Type ne "MethodPtr")
2639 {
2640 $TypeAttr{"Param"}{$Position}{"type"} = $ParamTypeId;
2641 push(@ParamTypeName, $ParamAttr{"Name"});
2642 }
2643 last if($ParamTypeInfo!~/(chan|chain)[ ]*:[ ]*@(\d+) /);
2644 $ParamTypeInfoId = $2;
2645 $Position+=1;
2646 }
2647 }
2648 $MemPtrName .= " (".join(", ", @ParamTypeName).")";
2649 }
2650 $TypeAttr{"Name"} = formatName($MemPtrName);
2651 return %TypeAttr;
2652}
2653
2654sub getTreeTypeName($)
2655{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002656 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002657 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002658 if($Info=~/name[ ]*:[ ]*@(\d+) /) {
2659 return getNameByInfo($1);
2660 }
2661 elsif($LibInfo{$Version}{"info_type"}{$_[0]} eq "integer_type")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002662 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002663 if($Info=~/unsigned/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002664 return "unsigned int";
2665 }
2666 else {
2667 return "int";
2668 }
2669 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002670 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002671 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002672}
2673
2674sub getTypeType($$)
2675{
2676 my ($TypeDeclId, $TypeId) = @_;
2677 if($MissedTypedef{$Version}{$TypeId}{"TDid"}
2678 and $MissedTypedef{$Version}{$TypeId}{"TDid"} eq $TypeDeclId)
2679 { # support for old GCC versions
2680 return "Typedef";
2681 }
2682 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002683 if($Info and $Info=~/unql[ ]*:/ and $Info!~/qual[ ]*:/
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002684 and getNameByInfo($TypeDeclId)) {
2685 return "Typedef";
2686 }
2687 elsif(my ($Qual, $To) = getQual($TypeId))
2688 {
2689 if($Qual eq "const volatile") {
2690 return "ConstVolatile";
2691 }
2692 else {
2693 return ucfirst($Qual);
2694 }
2695 }
2696 my $TypeType = getTypeTypeByTypeId($TypeId);
2697 if($TypeType eq "Struct")
2698 {
2699 if($TypeDeclId
2700 and $LibInfo{$Version}{"info_type"}{$TypeDeclId} eq "template_decl") {
2701 return "Template";
2702 }
2703 else {
2704 return "Struct";
2705 }
2706 }
2707 else {
2708 return $TypeType;
2709 }
2710}
2711
2712sub getQual($)
2713{
2714 my $TypeId = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002715 my %UnQual = (
2716 "r"=>"restrict",
2717 "v"=>"volatile",
2718 "c"=>"const",
2719 "cv"=>"const volatile"
2720 );
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002721 if(my $Info = $LibInfo{$Version}{"info"}{$TypeId})
2722 {
2723 my ($Qual, $To) = ();
2724 if($Info=~/qual[ ]*:[ ]*(r|c|v|cv) /) {
2725 $Qual = $UnQual{$1};
2726 }
2727 if($Info=~/unql[ ]*:[ ]*\@(\d+)/) {
2728 $To = $1;
2729 }
2730 if($Qual and $To) {
2731 return ($Qual, $To);
2732 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002733 }
2734 return ();
2735}
2736
2737sub selectBaseType($$)
2738{
2739 my ($TypeDeclId, $TypeId) = @_;
2740 if($MissedTypedef{$Version}{$TypeId}{"TDid"}
2741 and $MissedTypedef{$Version}{$TypeId}{"TDid"} eq $TypeDeclId) {
2742 return ($TypeId, getTypeDeclId($TypeId), "");
2743 }
2744 my $TInfo = $LibInfo{$Version}{"info"}{$TypeId};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002745 my ($Qual, $To) = getQual($TypeId);
2746 if(($Qual or $To) and $TInfo=~/name[ ]*:[ ]*\@(\d+) /
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002747 and (getTypeId($1) ne $TypeId)) {
2748 return (getTypeId($1), $1, $Qual);
2749 }
2750 elsif($TInfo!~/qual[ ]*:/
2751 and $TInfo=~/unql[ ]*:[ ]*\@(\d+) /
2752 and getNameByInfo($TypeDeclId))
2753 { # typedefs
2754 return ($1, getTypeDeclId($1), "");
2755 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002756 elsif($Qual or $To) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002757 return ($To, getTypeDeclId($To), $Qual);
2758 }
2759 elsif($LibInfo{$Version}{"info_type"}{$TypeId} eq "reference_type")
2760 {
2761 if($TInfo=~/refd[ ]*:[ ]*@(\d+) /) {
2762 return ($1, getTypeDeclId($1), "&");
2763 }
2764 else {
2765 return (0, 0, "");
2766 }
2767 }
2768 elsif($LibInfo{$Version}{"info_type"}{$TypeId} eq "array_type")
2769 {
2770 if($TInfo=~/elts[ ]*:[ ]*@(\d+) /) {
2771 return ($1, getTypeDeclId($1), "");
2772 }
2773 else {
2774 return (0, 0, "");
2775 }
2776 }
2777 elsif($LibInfo{$Version}{"info_type"}{$TypeId} eq "pointer_type")
2778 {
2779 if($TInfo=~/ptd[ ]*:[ ]*@(\d+) /) {
2780 return ($1, getTypeDeclId($1), "*");
2781 }
2782 else {
2783 return (0, 0, "");
2784 }
2785 }
2786 else {
2787 return (0, 0, "");
2788 }
2789}
2790
2791sub getSymbolInfo_All()
2792{
2793 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
2794 { # reverse order
2795 if($LibInfo{$Version}{"info_type"}{$_} eq "function_decl") {
2796 getSymbolInfo("$_");
2797 }
2798 }
2799}
2800
2801sub getVarInfo_All()
2802{
2803 foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
2804 { # reverse order
2805 if($LibInfo{$Version}{"info_type"}{$_} eq "var_decl") {
2806 getVarInfo("$_");
2807 }
2808 }
2809}
2810
2811sub isBuiltIn($) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002812 return ($_[0] and $_[0]=~/\<built\-in\>|\<internal\>|\A\./);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002813}
2814
2815sub getVarInfo($)
2816{
2817 my $InfoId = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002818 if(my $NSid = getNameSpaceId($InfoId))
2819 {
2820 my $NSInfoType = $LibInfo{$Version}{"info_type"}{$NSid};
2821 if($NSInfoType and $NSInfoType eq "function_decl") {
2822 return;
2823 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002824 }
2825 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
2826 if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
2827 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) {
2828 delete($SymbolInfo{$Version}{$InfoId});
2829 return;
2830 }
2831 my $ShortName = $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getVarShortName($InfoId);
2832 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\Atmp_add_class_\d+\Z/) {
2833 delete($SymbolInfo{$Version}{$InfoId});
2834 return;
2835 }
2836 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = getFuncMnglName($InfoId);
2837 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
2838 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A_Z/)
2839 { # validate mangled name
2840 delete($SymbolInfo{$Version}{$InfoId});
2841 return;
2842 }
2843 $SymbolInfo{$Version}{$InfoId}{"Data"} = 1;
2844 $SymbolInfo{$Version}{$InfoId}{"Return"} = getTypeId($InfoId);
2845 if(not $SymbolInfo{$Version}{$InfoId}{"Return"}) {
2846 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
2847 }
2848 set_Class_And_Namespace($InfoId);
2849 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i) {
2850 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
2851 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002852 if($UserLang and $UserLang eq "C")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002853 { # --lang=C option
2854 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
2855 }
2856 if($COMMON_LANGUAGE{$Version} eq "C++")
2857 {
2858 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
2859 { # for some symbols (_ZTI) the short name is the mangled name
2860 if($ShortName=~/\A_Z/) {
2861 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
2862 }
2863 }
2864 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
2865 { # try to mangle symbol (link with libraries)
2866 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = linkSymbol($InfoId);
2867 }
2868 if($OStarget eq "windows")
2869 {
2870 if(my $Mangled = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
2871 { # link MS C++ symbols from library with GCC symbols from headers
2872 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
2873 }
2874 }
2875 }
2876 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) {
2877 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
2878 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04002879 if(not $CheckHeadersOnly
2880 and not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002881 {
2882 if(link_symbol($ShortName, $Version, "-Deps")
2883 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/_ZL\d+$ShortName\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04002884 { # "const" global data is mangled as _ZL... in the TU dump
2885 # but not mangled when compiling a C shared library
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002886 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
2887 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04002888 elsif($BinaryOnly)
2889 { # --binary: remove src-only symbols
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002890 delete($SymbolInfo{$Version}{$InfoId});
2891 return;
2892 }
2893 }
2894 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) {
2895 delete($SymbolInfo{$Version}{$InfoId});
2896 return;
2897 }
2898 if(my $AddedTid = $MissedTypedef{$Version}{$SymbolInfo{$Version}{$InfoId}{"Return"}}{"Tid"}) {
2899 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
2900 }
2901 setFuncAccess($InfoId);
2902 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZTV/) {
2903 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
2904 }
2905 if($ShortName=~/\A(_Z|\?)/) {
2906 delete($SymbolInfo{$Version}{$InfoId}{"ShortName"});
2907 }
2908}
2909
2910sub getTrivialName($$)
2911{
2912 my ($TypeInfoId, $TypeId) = @_;
2913 my %TypeAttr = ();
2914 $TypeAttr{"Name"} = getNameByInfo($TypeInfoId);
2915 if(not $TypeAttr{"Name"}) {
2916 $TypeAttr{"Name"} = getTreeTypeName($TypeId);
2917 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002918 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
2919 $TypeAttr{"Type"} = getTypeType($TypeInfoId, $TypeId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002920 $TypeAttr{"Name"}=~s/<(.+)\Z//g; # GCC 3.4.4 add template params to the name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04002921 if(isAnon($TypeAttr{"Name"}))
2922 {
2923 my $NameSpaceId = $TypeId;
2924 while(my $NSId = getNameSpaceId(getTypeDeclId($NameSpaceId)))
2925 { # searching for a first not anon scope
2926 if($NSId eq $NameSpaceId) {
2927 last;
2928 }
2929 else
2930 {
2931 $TypeAttr{"NameSpace"} = getNameSpace(getTypeDeclId($TypeId));
2932 if(not $TypeAttr{"NameSpace"}
2933 or isNotAnon($TypeAttr{"NameSpace"})) {
2934 last;
2935 }
2936 }
2937 $NameSpaceId=$NSId;
2938 }
2939 }
2940 else
2941 {
2942 if(my $NameSpaceId = getNameSpaceId($TypeInfoId))
2943 {
2944 if($NameSpaceId ne $TypeId) {
2945 $TypeAttr{"NameSpace"} = getNameSpace($TypeInfoId);
2946 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002947 }
2948 }
2949 if($TypeAttr{"NameSpace"} and isNotAnon($TypeAttr{"Name"})) {
2950 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
2951 }
2952 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"});
2953 if(isAnon($TypeAttr{"Name"}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04002954 { # anon-struct-header.h-line
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002955 $TypeAttr{"Name"} = "anon-".lc($TypeAttr{"Type"})."-";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002956 $TypeAttr{"Name"} .= $TypeAttr{"Header"}."-".$TypeAttr{"Line"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04002957 if($TypeAttr{"NameSpace"}) {
2958 $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
2959 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04002960 }
2961 if(defined $TemplateInstance{$Version}{$TypeInfoId}{$TypeId})
2962 {
2963 my @TParams = getTParams($TypeInfoId, $TypeId);
2964 if(not @TParams)
2965 { # template declarations with abstract params
2966 # vector (tree_vec) of template_type_parm nodes in the TU dump
2967 return ("", "");
2968 }
2969 $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."< ".join(", ", @TParams)." >");
2970 }
2971 return ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"});
2972}
2973
2974sub getTrivialTypeAttr($$)
2975{
2976 my ($TypeInfoId, $TypeId) = @_;
2977 my %TypeAttr = ();
2978 if(getTypeTypeByTypeId($TypeId)!~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/) {
2979 return ();
2980 }
2981 setTypeAccess($TypeId, \%TypeAttr);
2982 ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
2983 if(isBuiltIn($TypeAttr{"Header"}))
2984 {
2985 delete($TypeAttr{"Header"});
2986 delete($TypeAttr{"Line"});
2987 }
2988 $TypeAttr{"Type"} = getTypeType($TypeInfoId, $TypeId);
2989 ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"}) = getTrivialName($TypeInfoId, $TypeId);
2990 if(not $TypeAttr{"Name"}) {
2991 return ();
2992 }
2993 if(not $TypeAttr{"NameSpace"}) {
2994 delete($TypeAttr{"NameSpace"});
2995 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04002996 if(defined $TemplateInstance{$Version}{$TypeInfoId}{$TypeId})
2997 {
2998 if(my @TParams = getTParams($TypeInfoId, $TypeId))
2999 {
3000 foreach my $Pos (0 .. $#TParams) {
3001 $TypeAttr{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
3002 }
3003 }
3004 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003005 if(my $Size = getSize($TypeId)) {
3006 $TypeAttr{"Size"} = $Size/$BYTE_SIZE;
3007 }
3008 if($TypeAttr{"Type"} eq "Struct"
3009 and detect_lang($TypeId))
3010 {
3011 $TypeAttr{"Type"} = "Class";
3012 $TypeAttr{"Copied"} = 1;# default, will be changed in getSymbolInfo()
3013 }
3014 if($TypeAttr{"Type"} eq "Struct"
3015 or $TypeAttr{"Type"} eq "Class") {
3016 setBaseClasses($TypeInfoId, $TypeId, \%TypeAttr);
3017 }
3018 setSpec($TypeId, \%TypeAttr);
3019 setTypeMemb($TypeId, \%TypeAttr);
3020 $TypeAttr{"Tid"} = $TypeId;
3021 $TypeAttr{"TDid"} = $TypeInfoId;
3022 if($TypeInfoId) {
3023 $Tid_TDid{$Version}{$TypeId} = $TypeInfoId;
3024 }
3025 if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
3026 $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
3027 }
3028 if(my $VTable = $ClassVTable_Content{$Version}{$TypeAttr{"Name"}})
3029 {
3030 my @Entries = split(/\n/, $VTable);
3031 foreach (1 .. $#Entries)
3032 {
3033 my $Entry = $Entries[$_];
3034 if($Entry=~/\A(\d+)\s+(.+)\Z/) {
3035 $TypeAttr{"VTable"}{$1} = $2;
3036 }
3037 }
3038 }
3039 return %TypeAttr;
3040}
3041
3042sub detect_lang($)
3043{
3044 my $TypeId = $_[0];
3045 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3046 if(check_gcc_version($GCC_PATH, "4"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003047 { # GCC 4 fncs-node points to only non-artificial methods
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003048 return ($Info=~/(fncs)[ ]*:[ ]*@(\d+) /);
3049 }
3050 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003051 { # GCC 3
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003052 my $Fncs = getTreeAttr($TypeId, "fncs");
3053 while($Fncs)
3054 {
3055 my $Info = $LibInfo{$Version}{"info"}{$Fncs};
3056 if($Info!~/artificial/) {
3057 return 1;
3058 }
3059 $Fncs = getTreeAttr($Fncs, "chan");
3060 }
3061 }
3062 return 0;
3063}
3064
3065sub setSpec($$)
3066{
3067 my ($TypeId, $TypeAttr) = @_;
3068 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3069 if($Info=~/\s+spec\s+/) {
3070 $TypeAttr->{"Spec"} = 1;
3071 }
3072}
3073
3074sub setBaseClasses($$$)
3075{
3076 my ($TypeInfoId, $TypeId, $TypeAttr) = @_;
3077 my $Info = $LibInfo{$Version}{"info"}{$TypeId};
3078 if($Info=~/binf[ ]*:[ ]*@(\d+) /)
3079 {
3080 $Info = $LibInfo{$Version}{"info"}{$1};
3081 my $Pos = 0;
3082 while($Info=~s/(pub|public|prot|protected|priv|private|)[ ]+binf[ ]*:[ ]*@(\d+) //)
3083 {
3084 my ($Access, $BInfoId) = ($1, $2);
3085 my $ClassId = getBinfClassId($BInfoId);
3086 my $BaseInfo = $LibInfo{$Version}{"info"}{$BInfoId};
3087 if($Access=~/prot/)
3088 {
3089 $TypeAttr->{"Base"}{$ClassId}{"access"} = "protected";
3090 }
3091 elsif($Access=~/priv/)
3092 {
3093 $TypeAttr->{"Base"}{$ClassId}{"access"} = "private";
3094 }
3095 $TypeAttr->{"Base"}{$ClassId}{"pos"} = $Pos++;
3096 if($BaseInfo=~/virt/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003097 { # virtual base
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003098 $TypeAttr->{"Base"}{$ClassId}{"virtual"} = 1;
3099 }
3100 $Class_SubClasses{$Version}{$ClassId}{$TypeId}=1;
3101 }
3102 }
3103}
3104
3105sub getBinfClassId($)
3106{
3107 my $Info = $LibInfo{$Version}{"info"}{$_[0]};
3108 $Info=~/type[ ]*:[ ]*@(\d+) /;
3109 return $1;
3110}
3111
3112sub unmangledFormat($$)
3113{
3114 my ($Name, $LibVersion) = @_;
3115 $Name = uncover_typedefs($Name, $LibVersion);
3116 while($Name=~s/([^\w>*])(const|volatile)(,|>|\Z)/$1$3/g){};
3117 $Name=~s/\(\w+\)(\d)/$1/;
3118 return $Name;
3119}
3120
3121sub modelUnmangled($$)
3122{
3123 my ($InfoId, $Compiler) = @_;
3124 if($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId}) {
3125 return $Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId};
3126 }
3127 my $PureSignature = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
3128 if($SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3129 $PureSignature = "~".$PureSignature;
3130 }
3131 if(not $SymbolInfo{$Version}{$InfoId}{"Data"})
3132 {
3133 my (@Params, @ParamTypes) = ();
3134 if(defined $SymbolInfo{$Version}{$InfoId}{"Param"}
3135 and not $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
3136 @Params = keys(%{$SymbolInfo{$Version}{$InfoId}{"Param"}});
3137 }
3138 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
3139 { # checking parameters
3140 my $PId = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"type"};
3141 my %PType = get_PureType($Tid_TDid{$Version}{$PId}, $PId, $Version);
3142 my $PTName = unmangledFormat($PType{"Name"}, $Version);
3143 $PTName=~s/(\A|\W)(restrict|register)(\W|\Z)/$1$3/g;
3144 if($Compiler eq "MSVC") {
3145 $PTName=~s/(\W|\A)long long(\W|\Z)/$1__int64$2/;
3146 }
3147 @ParamTypes = (@ParamTypes, $PTName);
3148 }
3149 if(@ParamTypes) {
3150 $PureSignature .= "(".join(", ", @ParamTypes).")";
3151 }
3152 else
3153 {
3154 if($Compiler eq "MSVC")
3155 {
3156 $PureSignature .= "(void)";
3157 }
3158 else
3159 { # GCC
3160 $PureSignature .= "()";
3161 }
3162 }
3163 $PureSignature = delete_keywords($PureSignature);
3164 }
3165 if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
3166 {
3167 my $ClassName = unmangledFormat(get_TypeName($ClassId, $Version), $Version);
3168 $PureSignature = $ClassName."::".$PureSignature;
3169 }
3170 elsif(my $NS = $SymbolInfo{$Version}{$InfoId}{"NameSpace"}) {
3171 $PureSignature = $NS."::".$PureSignature;
3172 }
3173 if($SymbolInfo{$Version}{$InfoId}{"Const"}) {
3174 $PureSignature .= " const";
3175 }
3176 if($SymbolInfo{$Version}{$InfoId}{"Volatile"}) {
3177 $PureSignature .= " volatile";
3178 }
3179 my $ShowReturn = 0;
3180 if($Compiler eq "MSVC"
3181 and $SymbolInfo{$Version}{$InfoId}{"Data"})
3182 {
3183 $ShowReturn=1;
3184 }
3185 elsif(defined $TemplateInstance_Func{$Version}{$InfoId}
3186 and keys(%{$TemplateInstance_Func{$Version}{$InfoId}}))
3187 {
3188 $ShowReturn=1;
3189 }
3190 if($ShowReturn)
3191 { # mangled names for template function specializations include return value
3192 if(my $ReturnId = $SymbolInfo{$Version}{$InfoId}{"Return"})
3193 {
3194 my %RType = get_PureType($Tid_TDid{$Version}{$ReturnId}, $ReturnId, $Version);
3195 my $ReturnName = unmangledFormat($RType{"Name"}, $Version);
3196 $PureSignature = $ReturnName." ".$PureSignature;
3197 }
3198 }
3199 return ($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId} = formatName($PureSignature));
3200}
3201
3202sub mangle_symbol($$$)
3203{ # mangling for simple methods
3204 # see gcc-4.6.0/gcc/cp/mangle.c
3205 my ($InfoId, $LibVersion, $Compiler) = @_;
3206 if($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler}) {
3207 return $Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler};
3208 }
3209 my $Mangled = "";
3210 if($Compiler eq "GCC") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003211 $Mangled = mangle_symbol_GCC($InfoId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003212 }
3213 elsif($Compiler eq "MSVC") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003214 $Mangled = mangle_symbol_MSVC($InfoId, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003215 }
3216 return ($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler} = $Mangled);
3217}
3218
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003219sub mangle_symbol_MSVC($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003220{
3221 my ($InfoId, $LibVersion) = @_;
3222 return "";
3223}
3224
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003225sub mangle_symbol_GCC($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003226{ # see gcc-4.6.0/gcc/cp/mangle.c
3227 my ($InfoId, $LibVersion) = @_;
3228 my ($Mangled, $ClassId, $NameSpace) = ("_Z", 0, "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003229 my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003230 my %Repl = ();# SN_ replacements
3231 if($ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
3232 {
3233 my $MangledClass = mangle_param($ClassId, $LibVersion, \%Repl);
3234 if($MangledClass!~/\AN/) {
3235 $MangledClass = "N".$MangledClass;
3236 }
3237 else {
3238 $MangledClass=~s/E\Z//;
3239 }
3240 if($SymbolInfo{$LibVersion}{$InfoId}{"Volatile"}) {
3241 $MangledClass=~s/\AN/NV/;
3242 }
3243 if($SymbolInfo{$LibVersion}{$InfoId}{"Const"}) {
3244 $MangledClass=~s/\AN/NK/;
3245 }
3246 $Mangled .= $MangledClass;
3247 }
3248 elsif($NameSpace = $SymbolInfo{$LibVersion}{$InfoId}{"NameSpace"})
3249 { # mangled by name due to the absence of structured info
3250 my $MangledNS = mangle_ns($NameSpace, $LibVersion, \%Repl);
3251 if($MangledNS!~/\AN/) {
3252 $MangledNS = "N".$MangledNS;
3253 }
3254 else {
3255 $MangledNS=~s/E\Z//;
3256 }
3257 $Mangled .= $MangledNS;
3258 }
3259 my ($ShortName, $TmplParams) = template_base($SymbolInfo{$LibVersion}{$InfoId}{"ShortName"});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003260 my @TParams = ();
3261 if($Version)
3262 { # parsing mode
3263 @TParams = getTParams_Func($InfoId);
3264 }
3265 elsif($TmplParams)
3266 { # remangling mode
3267 # support for old ABI dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003268 @TParams = separate_params($TmplParams, 0);
3269 }
3270 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"}) {
3271 $Mangled .= "C1";
3272 }
3273 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
3274 $Mangled .= "D0";
3275 }
3276 elsif($ShortName)
3277 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003278 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
3279 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003280 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
3281 and get_TypeAttr($Return, $LibVersion, "Type") eq "Const")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003282 { # "const" global data is mangled as _ZL...
3283 $Mangled .= "L";
3284 }
3285 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003286 if($ShortName=~/\Aoperator(\W.*)\Z/)
3287 {
3288 my $Op = $1;
3289 $Op=~s/\A[ ]+//g;
3290 if(my $OpMngl = $OperatorMangling{$Op}) {
3291 $Mangled .= $OpMngl;
3292 }
3293 else { # conversion operator
3294 $Mangled .= "cv".mangle_param(getTypeIdByName($Op, $LibVersion), $LibVersion, \%Repl);
3295 }
3296 }
3297 else {
3298 $Mangled .= length($ShortName).$ShortName;
3299 }
3300 if(@TParams)
3301 { # templates
3302 $Mangled .= "I";
3303 foreach my $TParam (@TParams) {
3304 $Mangled .= mangle_template_param($TParam, $LibVersion, \%Repl);
3305 }
3306 $Mangled .= "E";
3307 }
3308 if(not $ClassId and @TParams) {
3309 add_substitution($ShortName, \%Repl, 0);
3310 }
3311 }
3312 if($ClassId or $NameSpace) {
3313 $Mangled .= "E";
3314 }
3315 if(@TParams) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003316 if($Return) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003317 $Mangled .= mangle_param($Return, $LibVersion, \%Repl);
3318 }
3319 }
3320 if(not $SymbolInfo{$LibVersion}{$InfoId}{"Data"})
3321 {
3322 my @Params = ();
3323 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
3324 and not $SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
3325 @Params = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}});
3326 }
3327 foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
3328 { # checking parameters
3329 my $ParamType_Id = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$ParamPos}{"type"};
3330 $Mangled .= mangle_param($ParamType_Id, $LibVersion, \%Repl);
3331 }
3332 if(not @Params) {
3333 $Mangled .= "v";
3334 }
3335 }
3336 $Mangled = correct_incharge($InfoId, $LibVersion, $Mangled);
3337 $Mangled = write_stdcxx_substitution($Mangled);
3338 if($Mangled eq "_Z") {
3339 return "";
3340 }
3341 return $Mangled;
3342}
3343
3344sub correct_incharge($$$)
3345{
3346 my ($InfoId, $LibVersion, $Mangled) = @_;
3347 if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"})
3348 {
3349 if($MangledNames{$LibVersion}{$Mangled}) {
3350 $Mangled=~s/C1E/C2E/;
3351 }
3352 }
3353 elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
3354 {
3355 if($MangledNames{$LibVersion}{$Mangled}) {
3356 $Mangled=~s/D0E/D1E/;
3357 }
3358 if($MangledNames{$LibVersion}{$Mangled}) {
3359 $Mangled=~s/D1E/D2E/;
3360 }
3361 }
3362 return $Mangled;
3363}
3364
3365sub template_base($)
3366{ # NOTE: std::_Vector_base<mysqlpp::mysql_type_info>::_Vector_impl
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003367 # NOTE: operators: >>, <<
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003368 my $Name = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003369 if($Name!~/>\Z/ or $Name!~/</) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003370 return $Name;
3371 }
3372 my $TParams = $Name;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003373 while(my $CPos = find_center($TParams, "<"))
3374 { # search for the last <T>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003375 $TParams = substr($TParams, $CPos);
3376 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003377 if($TParams=~s/\A<(.+)>\Z/$1/) {
3378 $Name=~s/<\Q$TParams\E>\Z//;
3379 }
3380 else
3381 { # error
3382 $TParams = "";
3383 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003384 return ($Name, $TParams);
3385}
3386
3387sub get_sub_ns($)
3388{
3389 my $Name = $_[0];
3390 my @NS = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003391 while(my $CPos = find_center($Name, ":"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003392 {
3393 push(@NS, substr($Name, 0, $CPos));
3394 $Name = substr($Name, $CPos);
3395 $Name=~s/\A:://;
3396 }
3397 return (join("::", @NS), $Name);
3398}
3399
3400sub mangle_ns($$$)
3401{
3402 my ($Name, $LibVersion, $Repl) = @_;
3403 if(my $Tid = $TName_Tid{$LibVersion}{$Name})
3404 {
3405 my $Mangled = mangle_param($Tid, $LibVersion, $Repl);
3406 $Mangled=~s/\AN(.+)E\Z/$1/;
3407 return $Mangled;
3408
3409 }
3410 else
3411 {
3412 my ($MangledNS, $SubNS) = ("", "");
3413 ($SubNS, $Name) = get_sub_ns($Name);
3414 if($SubNS) {
3415 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
3416 }
3417 $MangledNS .= length($Name).$Name;
3418 add_substitution($MangledNS, $Repl, 0);
3419 return $MangledNS;
3420 }
3421}
3422
3423sub mangle_param($$$)
3424{
3425 my ($PTid, $LibVersion, $Repl) = @_;
3426 my ($MPrefix, $Mangled) = ("", "");
3427 my %ReplCopy = %{$Repl};
3428 my %BaseType = get_BaseType($Tid_TDid{$LibVersion}{$PTid}, $PTid, $LibVersion);
3429 my $BaseType_Name = $BaseType{"Name"};
3430 if(not $BaseType_Name) {
3431 return "";
3432 }
3433 my ($ShortName, $TmplParams) = template_base($BaseType_Name);
3434 my $Suffix = get_BaseTypeQual($Tid_TDid{$LibVersion}{$PTid}, $PTid, $LibVersion);
3435 while($Suffix=~s/\s*(const|volatile|restrict)\Z//g){};
3436 while($Suffix=~/(&|\*|const)\Z/)
3437 {
3438 if($Suffix=~s/[ ]*&\Z//) {
3439 $MPrefix .= "R";
3440 }
3441 if($Suffix=~s/[ ]*\*\Z//) {
3442 $MPrefix .= "P";
3443 }
3444 if($Suffix=~s/[ ]*const\Z//)
3445 {
3446 if($MPrefix=~/R|P/
3447 or $Suffix=~/&|\*/) {
3448 $MPrefix .= "K";
3449 }
3450 }
3451 if($Suffix=~s/[ ]*volatile\Z//) {
3452 $MPrefix .= "V";
3453 }
3454 #if($Suffix=~s/[ ]*restrict\Z//) {
3455 #$MPrefix .= "r";
3456 #}
3457 }
3458 if(my $Token = $IntrinsicMangling{$BaseType_Name}) {
3459 $Mangled .= $Token;
3460 }
3461 elsif($BaseType{"Type"}=~/(Class|Struct|Union|Enum)/)
3462 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003463 my @TParams = ();
3464 if($Version)
3465 { # parsing mode
3466 @TParams = getTParams($BaseType{"TDid"}, $BaseType{"Tid"});
3467 }
3468 elsif($TmplParams)
3469 { # remangling mode
3470 # support for old ABI dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003471 @TParams = separate_params($TmplParams, 0);
3472 }
3473 my $MangledNS = "";
3474 my ($SubNS, $SName) = get_sub_ns($ShortName);
3475 if($SubNS) {
3476 $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
3477 }
3478 $MangledNS .= length($SName).$SName;
3479 if(@TParams) {
3480 add_substitution($MangledNS, $Repl, 0);
3481 }
3482 $Mangled .= "N".$MangledNS;
3483 if(@TParams)
3484 { # templates
3485 $Mangled .= "I";
3486 foreach my $TParam (@TParams) {
3487 $Mangled .= mangle_template_param($TParam, $LibVersion, $Repl);
3488 }
3489 $Mangled .= "E";
3490 }
3491 $Mangled .= "E";
3492 }
3493 elsif($BaseType{"Type"}=~/(FuncPtr|MethodPtr)/)
3494 {
3495 if($BaseType{"Type"} eq "MethodPtr") {
3496 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl)."F";
3497 }
3498 else {
3499 $Mangled .= "PF";
3500 }
3501 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
3502 my @Params = keys(%{$BaseType{"Param"}});
3503 foreach my $Num (sort {int($a)<=>int($b)} @Params) {
3504 $Mangled .= mangle_param($BaseType{"Param"}{$Num}{"type"}, $LibVersion, $Repl);
3505 }
3506 if(not @Params) {
3507 $Mangled .= "v";
3508 }
3509 $Mangled .= "E";
3510 }
3511 elsif($BaseType{"Type"} eq "FieldPtr")
3512 {
3513 $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl);
3514 $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
3515 }
3516 $Mangled = $MPrefix.$Mangled;# add prefix (RPK)
3517 if(my $Optimized = write_substitution($Mangled, \%ReplCopy))
3518 {
3519 if($Mangled eq $Optimized)
3520 {
3521 if($ShortName!~/::/)
3522 { # remove "N ... E"
3523 if($MPrefix) {
3524 $Mangled=~s/\A($MPrefix)N(.+)E\Z/$1$2/g;
3525 }
3526 else {
3527 $Mangled=~s/\AN(.+)E\Z/$1/g;
3528 }
3529 }
3530 }
3531 else {
3532 $Mangled = $Optimized;
3533 }
3534 }
3535 add_substitution($Mangled, $Repl, 1);
3536 return $Mangled;
3537}
3538
3539sub mangle_template_param($$$)
3540{ # types + literals
3541 my ($TParam, $LibVersion, $Repl) = @_;
3542 if(my $TPTid = $TName_Tid{$LibVersion}{$TParam}) {
3543 return mangle_param($TPTid, $LibVersion, $Repl);
3544 }
3545 elsif($TParam=~/\A(\d+)(\w+)\Z/)
3546 { # class_name<1u>::method(...)
3547 return "L".$IntrinsicMangling{$ConstantSuffixR{$2}}.$1."E";
3548 }
3549 elsif($TParam=~/\A\(([\w ]+)\)(\d+)\Z/)
3550 { # class_name<(signed char)1>::method(...)
3551 return "L".$IntrinsicMangling{$1}.$2."E";
3552 }
3553 elsif($TParam eq "true")
3554 { # class_name<true>::method(...)
3555 return "Lb1E";
3556 }
3557 elsif($TParam eq "false")
3558 { # class_name<true>::method(...)
3559 return "Lb0E";
3560 }
3561 else { # internal error
3562 return length($TParam).$TParam;
3563 }
3564}
3565
3566sub add_substitution($$$)
3567{
3568 my ($Value, $Repl, $Rec) = @_;
3569 if($Rec)
3570 { # subtypes
3571 my @Subs = ($Value);
3572 while($Value=~s/\A(R|P|K)//) {
3573 push(@Subs, $Value);
3574 }
3575 foreach (reverse(@Subs)) {
3576 add_substitution($_, $Repl, 0);
3577 }
3578 return;
3579 }
3580 return if($Value=~/\AS(\d*)_\Z/);
3581 $Value=~s/\AN(.+)E\Z/$1/g;
3582 return if(defined $Repl->{$Value});
3583 return if(length($Value)<=1);
3584 return if($StdcxxMangling{$Value});
3585 # check for duplicates
3586 my $Base = $Value;
3587 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
3588 {
3589 my $Num = $Repl->{$Type};
3590 my $Replace = macro_mangle($Num);
3591 $Base=~s/\Q$Replace\E/$Type/;
3592 }
3593 if(my $OldNum = $Repl->{$Base})
3594 {
3595 $Repl->{$Value} = $OldNum;
3596 return;
3597 }
3598 my @Repls = sort {$b<=>$a} values(%{$Repl});
3599 if(@Repls) {
3600 $Repl->{$Value} = $Repls[0]+1;
3601 }
3602 else {
3603 $Repl->{$Value} = -1;
3604 }
3605 # register duplicates
3606 # upward
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003607 $Base = $Value;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003608 foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
3609 {
3610 next if($Base eq $Type);
3611 my $Num = $Repl->{$Type};
3612 my $Replace = macro_mangle($Num);
3613 $Base=~s/\Q$Type\E/$Replace/;
3614 $Repl->{$Base} = $Repl->{$Value};
3615 }
3616}
3617
3618sub macro_mangle($)
3619{
3620 my $Num = $_[0];
3621 if($Num==-1) {
3622 return "S_";
3623 }
3624 else
3625 {
3626 my $Code = "";
3627 if($Num<10)
3628 { # S0_, S1_, S2_, ...
3629 $Code = $Num;
3630 }
3631 elsif($Num>=10 and $Num<=35)
3632 { # SA_, SB_, SC_, ...
3633 $Code = chr(55+$Num);
3634 }
3635 else
3636 { # S10_, S11_, S12_
3637 $Code = $Num-26; # 26 is length of english alphabet
3638 }
3639 return "S".$Code."_";
3640 }
3641}
3642
3643sub write_stdcxx_substitution($)
3644{
3645 my $Mangled = $_[0];
3646 if($StdcxxMangling{$Mangled}) {
3647 return $StdcxxMangling{$Mangled};
3648 }
3649 else
3650 {
3651 my @Repls = keys(%StdcxxMangling);
3652 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
3653 foreach my $MangledType (@Repls)
3654 {
3655 my $Replace = $StdcxxMangling{$MangledType};
3656 #if($Mangled!~/$Replace/) {
3657 $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
3658 $Mangled=~s/\Q$MangledType\E/$Replace/g;
3659 #}
3660 }
3661 }
3662 return $Mangled;
3663}
3664
3665sub write_substitution($$)
3666{
3667 my ($Mangled, $Repl) = @_;
3668 if(defined $Repl->{$Mangled}
3669 and my $MnglNum = $Repl->{$Mangled}) {
3670 $Mangled = macro_mangle($MnglNum);
3671 }
3672 else
3673 {
3674 my @Repls = keys(%{$Repl});
3675 #@Repls = sort {$Repl->{$a}<=>$Repl->{$b}} @Repls;
3676 # FIXME: how to apply replacements? by num or by pos
3677 @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
3678 foreach my $MangledType (@Repls)
3679 {
3680 my $Replace = macro_mangle($Repl->{$MangledType});
3681 if($Mangled!~/$Replace/) {
3682 $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
3683 $Mangled=~s/\Q$MangledType\E/$Replace/g;
3684 }
3685 }
3686 }
3687 return $Mangled;
3688}
3689
3690sub delete_keywords($)
3691{
3692 my $TypeName = $_[0];
3693 $TypeName=~s/(\W|\A)(enum |struct |union |class )/$1/g;
3694 return $TypeName;
3695}
3696
3697my %Intrinsic_Keywords = map {$_=>1} (
3698 "true",
3699 "false",
3700 "_Bool",
3701 "_Complex",
3702 "const",
3703 "int",
3704 "long",
3705 "void",
3706 "short",
3707 "float",
3708 "volatile",
3709 "restrict",
3710 "unsigned",
3711 "signed",
3712 "char",
3713 "double",
3714 "class",
3715 "struct",
3716 "union",
3717 "enum"
3718);
3719
3720sub uncover_typedefs($$)
3721{
3722 my ($TypeName, $LibVersion) = @_;
3723 return "" if(not $TypeName);
3724 if(defined $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName}) {
3725 return $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName};
3726 }
3727 my ($TypeName_New, $TypeName_Pre) = (formatName($TypeName), "");
3728 while($TypeName_New ne $TypeName_Pre)
3729 {
3730 $TypeName_Pre = $TypeName_New;
3731 my $TypeName_Copy = $TypeName_New;
3732 my %Words = ();
3733 while($TypeName_Copy=~s/(\W|\A)([a-z_][\w:]*)(\W|\Z)//io)
3734 {
3735 my $Word = $2;
3736 next if(not $Word or $Intrinsic_Keywords{$Word});
3737 $Words{$Word} = 1;
3738 }
3739 foreach my $Word (keys(%Words))
3740 {
3741 my $BaseType_Name = $Typedef_BaseName{$LibVersion}{$Word};
3742 next if(not $BaseType_Name);
3743 next if($TypeName_New=~/(\A|\W)(struct|union|enum)\s\Q$Word\E(\W|\Z)/);
3744 if($BaseType_Name=~/\([\*]+\)/)
3745 { # FuncPtr
3746 if($TypeName_New=~/\Q$Word\E(.*)\Z/)
3747 {
3748 my $Type_Suffix = $1;
3749 $TypeName_New = $BaseType_Name;
3750 if($TypeName_New=~s/\(([\*]+)\)/($1 $Type_Suffix)/) {
3751 $TypeName_New = formatName($TypeName_New);
3752 }
3753 }
3754 }
3755 else
3756 {
3757 if($TypeName_New=~s/(\W|\A)\Q$Word\E(\W|\Z)/$1$BaseType_Name$2/g) {
3758 $TypeName_New = formatName($TypeName_New);
3759 }
3760 }
3761 }
3762 }
3763 return ($Cache{"uncover_typedefs"}{$LibVersion}{$TypeName} = $TypeName_New);
3764}
3765
3766sub isInternal($)
3767{
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003768 my $FuncInfo = $LibInfo{$Version}{"info"}{$_[0]};
3769 return 0 if($FuncInfo!~/mngl[ ]*:[ ]*@(\d+) /);
3770 my $FuncMnglNameInfoId = $1;
3771 return ($LibInfo{$Version}{"info"}{$FuncMnglNameInfoId}=~/\*[ ]*INTERNAL[ ]*\*/);
3772}
3773
3774sub set_Class_And_Namespace($)
3775{
3776 my $InfoId = $_[0];
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003777 if($LibInfo{$Version}{"info"}{$InfoId}=~/scpe[ ]*:[ ]*@(\d+) /)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003778 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003779 my $NSInfoId = $1;
3780 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
3781 {
3782 if($InfoType eq "namespace_decl") {
3783 $SymbolInfo{$Version}{$InfoId}{"NameSpace"} = getNameSpace($InfoId);
3784 }
3785 elsif($InfoType eq "record_type") {
3786 $SymbolInfo{$Version}{$InfoId}{"Class"} = $NSInfoId;
3787 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003788 }
3789 }
3790 if($SymbolInfo{$Version}{$InfoId}{"Class"}
3791 or $SymbolInfo{$Version}{$InfoId}{"NameSpace"})
3792 { # identify language
3793 setLanguage($Version, "C++");
3794 }
3795}
3796
3797sub debugType($$)
3798{
3799 my ($Tid, $LibVersion) = @_;
3800 my %Type = get_Type($Tid_TDid{$LibVersion}{$Tid}, $Tid, $LibVersion);
3801 printMsg("INFO", Dumper(\%Type));
3802}
3803
3804sub debugMangling($)
3805{
3806 my $LibVersion = $_[0];
3807 my %Mangled = ();
3808 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
3809 {
3810 if(my $Mngl = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
3811 {
3812 if($Mngl=~/\A(_Z|\?)/) {
3813 $Mangled{$Mngl}=$InfoId;
3814 }
3815 }
3816 }
3817 translateSymbols(keys(%Mangled), $LibVersion);
3818 foreach my $Mngl (keys(%Mangled))
3819 {
3820 my $Unmngl1 = modelUnmangled($Mangled{$Mngl}, "GCC");
3821 my $Unmngl2 = $tr_name{$Mngl};
3822 if($Unmngl1 ne $Unmngl2) {
3823 printMsg("INFO", "INCORRECT MANGLING:\n $Mngl\n $Unmngl1\n $Unmngl2\n");
3824 }
3825 }
3826}
3827
3828sub linkSymbol($)
3829{ # link symbols from shared libraries
3830 # with the symbols from header files
3831 my $InfoId = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003832 if(my $Lang = $SymbolInfo{$Version}{$InfoId}{"Lang"})
3833 {
3834 if($Lang eq "C")
3835 { # extern "C"
3836 return $SymbolInfo{$Version}{$InfoId}{"ShortName"};
3837 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003838 }
3839 # try to mangle symbol
3840 if((not check_gcc_version($GCC_PATH, "4") and $SymbolInfo{$Version}{$InfoId}{"Class"})
3841 or (check_gcc_version($GCC_PATH, "4") and not $SymbolInfo{$Version}{$InfoId}{"Class"}))
3842 { # 1. GCC 3.x doesn't mangle class methods names in the TU dump (only functions and global data)
3843 # 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 +04003844 if(not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003845 {
3846 if(my $Mangled = $mangled_name_gcc{modelUnmangled($InfoId, "GCC")}) {
3847 return correct_incharge($InfoId, $Version, $Mangled);
3848 }
3849 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003850 if($CheckHeadersOnly
3851 or not $BinaryOnly)
3852 { # 1. --headers-only mode
3853 # 2. not mangled src-only symbols
3854 if(my $Mangled = mangle_symbol($InfoId, $Version, "GCC")) {
3855 return $Mangled;
3856 }
3857 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003858 }
3859 return "";
3860}
3861
3862sub setLanguage($$)
3863{
3864 my ($LibVersion, $Lang) = @_;
3865 if(not $UserLang) {
3866 $COMMON_LANGUAGE{$LibVersion} = $Lang;
3867 }
3868}
3869
3870sub getSymbolInfo($)
3871{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003872 my $InfoId = $_[0];
3873 return if(isInternal($InfoId));
3874 ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
3875 if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
3876 or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) {
3877 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003878 return;
3879 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003880 setFuncAccess($InfoId);
3881 setFuncKind($InfoId);
3882 if($SymbolInfo{$Version}{$InfoId}{"PseudoTemplate"}) {
3883 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003884 return;
3885 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003886 $SymbolInfo{$Version}{$InfoId}{"Type"} = getFuncType($InfoId);
3887 $SymbolInfo{$Version}{$InfoId}{"Return"} = getFuncReturn($InfoId);
3888 if(my $AddedTid = $MissedTypedef{$Version}{$SymbolInfo{$Version}{$InfoId}{"Return"}}{"Tid"}) {
3889 $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003890 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003891 if(not $SymbolInfo{$Version}{$InfoId}{"Return"}) {
3892 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003893 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003894 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getFuncShortName(getFuncOrig($InfoId));
3895 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\._/) {
3896 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003897 return;
3898 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003899 if(defined $TemplateInstance_Func{$Version}{$InfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003900 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003901 my @TParams = getTParams_Func($InfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003902 if(not @TParams) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003903 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003904 return;
3905 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003906 foreach my $Pos (0 .. $#TParams) {
3907 $SymbolInfo{$Version}{$InfoId}{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
3908 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003909 my $PrmsInLine = join(", ", @TParams);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04003910 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\Aoperator\W+\Z/)
3911 { # operator<< <T>, operator>> <T>
3912 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= " ";
3913 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003914 $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= "<".$PrmsInLine.">";
3915 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = formatName($SymbolInfo{$Version}{$InfoId}{"ShortName"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003916 }
3917 else
3918 { # support for GCC 3.4
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003919 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003920 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003921 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = getFuncMnglName($InfoId);
3922 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
3923 and $SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A_Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003924 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003925 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003926 return;
3927 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003928 if($SymbolInfo{$InfoId}{"MnglName"} and not $STDCXX_TESTING)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003929 { # stdc++ interfaces
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003930 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_ZS|_ZNS|_ZNKS)/) {
3931 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003932 return;
3933 }
3934 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003935 if(not $SymbolInfo{$Version}{$InfoId}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003936 { # destructors have an empty parameter list
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003937 my $Skip = setFuncParams($InfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003938 if($CheckHeadersOnly and $Skip)
3939 { # skip template symbols that cannot be
3940 # filtered without access to the library
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003941 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003942 return;
3943 }
3944 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003945 set_Class_And_Namespace($InfoId);
3946 if(not $CheckHeadersOnly and $SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function"
3947 and not $SymbolInfo{$Version}{$InfoId}{"Class"}
3948 and link_symbol($SymbolInfo{$Version}{$InfoId}{"ShortName"}, $Version, "-Deps"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003949 { # functions (C++): not mangled in library, but are mangled in TU dump
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003950 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}
3951 or not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps")) {
3952 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003953 }
3954 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003955 if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i) {
3956 $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003957 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003958 if($UserLang and $UserLang eq "C")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003959 { # --lang=C option
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003960 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003961 }
3962 if($COMMON_LANGUAGE{$Version} eq "C++")
3963 { # correct mangled & short names
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003964 # C++ or --headers-only mode
3965 if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\A__(comp|base|deleting)_(c|d)tor\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003966 { # support for old GCC versions: reconstruct real names for constructors and destructors
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003967 $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getNameByInfo(getTypeDeclId($SymbolInfo{$Version}{$InfoId}{"Class"}));
3968 $SymbolInfo{$Version}{$InfoId}{"ShortName"}=~s/<.+>\Z//;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003969 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003970 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003971 { # try to mangle symbol (link with libraries)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003972 if(my $Mangled = linkSymbol($InfoId)) {
3973 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003974 }
3975 }
3976 if($OStarget eq "windows")
3977 { # link MS C++ symbols from library with GCC symbols from headers
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003978 if(my $Mangled1 = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003979 { # exported symbols
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003980 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003981 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003982 elsif(my $Mangled2 = mangle_symbol($InfoId, $Version, "MSVC"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003983 { # pure virtual symbols
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04003984 $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003985 }
3986 }
3987 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003988 if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003989 { # can't detect symbol name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003990 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003991 return;
3992 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003993 if(getFuncSpec($InfoId) eq "Virt")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003994 { # virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003995 $SymbolInfo{$Version}{$InfoId}{"Virt"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003996 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003997 if(getFuncSpec($InfoId) eq "PureVirt")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04003998 { # pure virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04003999 $SymbolInfo{$Version}{$InfoId}{"PureVirt"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004000 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004001 if(isInline($InfoId)) {
4002 $SymbolInfo{$Version}{$InfoId}{"InLine"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004003 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004004 if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4005 and my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004006 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004007 if(not $SymbolInfo{$Version}{$InfoId}{"InLine"}
4008 and $LibInfo{$Version}{"info"}{$InfoId}!~/ artificial /i)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004009 { # inline or auto-generated constructor
4010 delete($TypeInfo{$Version}{$Tid_TDid{$Version}{$ClassId}}{$ClassId}{"Copied"});
4011 }
4012 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004013 if(not $CheckHeadersOnly and $BinaryOnly
4014 and not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps"))
4015 {
4016 if(not $SymbolInfo{$Version}{$InfoId}{"Virt"}
4017 and not $SymbolInfo{$Version}{$InfoId}{"PureVirt"})
4018 { # removing src only and external non-virtual functions
4019 # non-virtual template instances going here
4020 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004021 return;
4022 }
4023 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004024 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Method"
4025 or $SymbolInfo{$Version}{$InfoId}{"Constructor"}
4026 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}
4027 or $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004028 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004029 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A(_Z|\?)/) {
4030 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004031 return;
4032 }
4033 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004034 if($SymbolInfo{$Version}{$InfoId}{"MnglName"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004035 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004036 if($MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004037 { # one instance for one mangled name only
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004038 delete($SymbolInfo{$Version}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004039 return;
4040 }
4041 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004042 $MangledNames{$Version}{$SymbolInfo{$Version}{$InfoId}{"MnglName"}} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004043 }
4044 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004045 if($SymbolInfo{$Version}{$InfoId}{"Constructor"}
4046 or $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
4047 delete($SymbolInfo{$Version}{$InfoId}{"Return"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004048 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004049 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/
4050 and $SymbolInfo{$Version}{$InfoId}{"Class"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004051 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004052 if($SymbolInfo{$Version}{$InfoId}{"Type"} eq "Function")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004053 { # static methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004054 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004055 }
4056 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004057 if(getFuncLink($InfoId) eq "Static") {
4058 $SymbolInfo{$Version}{$InfoId}{"Static"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004059 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004060 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A(_Z|\?)/)
4061 {
4062 if(my $Unmangled = $tr_name{$SymbolInfo{$Version}{$InfoId}{"MnglName"}})
4063 {
4064 if($Unmangled=~/\.\_\d/) {
4065 delete($SymbolInfo{$Version}{$InfoId});
4066 return;
4067 }
4068 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004069 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004070 delete($SymbolInfo{$Version}{$InfoId}{"Type"});
4071 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(V|)K/) {
4072 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004073 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004074 if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZN(K|)V/) {
4075 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004076 }
4077}
4078
4079sub isInline($)
4080{ # "body: undefined" in the tree
4081 # -fkeep-inline-functions GCC option should be specified
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004082 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4083 {
4084 if($Info=~/ undefined /i) {
4085 return 0;
4086 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004087 }
4088 return 1;
4089}
4090
4091sub getTypeId($)
4092{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004093 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4094 {
4095 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
4096 return $1;
4097 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004098 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004099 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004100}
4101
4102sub setTypeMemb($$)
4103{
4104 my ($TypeId, $TypeAttr) = @_;
4105 my $TypeType = $TypeAttr->{"Type"};
4106 my ($Position, $UnnamedPos) = (0, 0);
4107 if($TypeType eq "Enum")
4108 {
4109 my $TypeMembInfoId = getEnumMembInfoId($TypeId);
4110 while($TypeMembInfoId)
4111 {
4112 $TypeAttr->{"Memb"}{$Position}{"value"} = getEnumMembVal($TypeMembInfoId);
4113 my $MembName = getEnumMembName($TypeMembInfoId);
4114 $TypeAttr->{"Memb"}{$Position}{"name"} = getEnumMembName($TypeMembInfoId);
4115 $EnumMembName_Id{$Version}{getTreeAttr($TypeMembInfoId, "valu")} = ($TypeAttr->{"NameSpace"})?$TypeAttr->{"NameSpace"}."::".$MembName:$MembName;
4116 $TypeMembInfoId = getNextMembInfoId($TypeMembInfoId);
4117 $Position += 1;
4118 }
4119 }
4120 elsif($TypeType=~/\A(Struct|Class|Union)\Z/)
4121 {
4122 my $TypeMembInfoId = getStructMembInfoId($TypeId);
4123 while($TypeMembInfoId)
4124 {
4125 if($LibInfo{$Version}{"info_type"}{$TypeMembInfoId} ne "field_decl") {
4126 $TypeMembInfoId = getNextStructMembInfoId($TypeMembInfoId);
4127 next;
4128 }
4129 my $StructMembName = getStructMembName($TypeMembInfoId);
4130 if($StructMembName=~/_vptr\./)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004131 { # virtual tables
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004132 $TypeMembInfoId = getNextStructMembInfoId($TypeMembInfoId);
4133 next;
4134 }
4135 if(not $StructMembName)
4136 { # unnamed fields
4137 if($TypeAttr->{"Name"}!~/_type_info_pseudo/)
4138 {
4139 my $UnnamedTid = getTreeAttr($TypeMembInfoId, "type");
4140 my $UnnamedTName = getNameByInfo(getTypeDeclId($UnnamedTid));
4141 if(isAnon($UnnamedTName))
4142 { # rename unnamed fields to unnamed0, unnamed1, ...
4143 $StructMembName = "unnamed".($UnnamedPos++);
4144 }
4145 }
4146 }
4147 if(not $StructMembName)
4148 { # unnamed fields and base classes
4149 $TypeMembInfoId = getNextStructMembInfoId($TypeMembInfoId);
4150 next;
4151 }
4152 my $MembTypeId = getTreeAttr($TypeMembInfoId, "type");
4153 if(my $AddedTid = $MissedTypedef{$Version}{$MembTypeId}{"Tid"}) {
4154 $MembTypeId = $AddedTid;
4155 }
4156 $TypeAttr->{"Memb"}{$Position}{"type"} = $MembTypeId;
4157 $TypeAttr->{"Memb"}{$Position}{"name"} = $StructMembName;
4158 if((my $Access = getTreeAccess($TypeMembInfoId)) ne "public")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004159 { # marked only protected and private, public by default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004160 $TypeAttr->{"Memb"}{$Position}{"access"} = $Access;
4161 }
4162 if(my $BFSize = getStructMembBitFieldSize($TypeMembInfoId)) {
4163 $TypeAttr->{"Memb"}{$Position}{"bitfield"} = $BFSize;
4164 }
4165 else
4166 { # set alignment for non-bit fields
4167 # alignment for bitfields is always equal to 1 bit
4168 $TypeAttr->{"Memb"}{$Position}{"algn"} = getAlgn($TypeMembInfoId)/$BYTE_SIZE;
4169 }
4170 $TypeMembInfoId = getNextStructMembInfoId($TypeMembInfoId);
4171 $Position += 1;
4172 }
4173 }
4174}
4175
4176sub setFuncParams($)
4177{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004178 my $InfoId = $_[0];
4179 my $ParamInfoId = getFuncParamInfoId($InfoId);
4180 my $FunctionType = getFuncType($InfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004181 if($FunctionType eq "Method")
4182 { # check type of "this" pointer
4183 my $ObjectTypeId = getFuncParamType($ParamInfoId);
4184 if(get_TypeName($ObjectTypeId, $Version)=~/(\A|\W)const(| volatile)\*const(\W|\Z)/) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004185 $SymbolInfo{$Version}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004186 }
4187 if(get_TypeName($ObjectTypeId, $Version)=~/(\A|\W)volatile(\W|\Z)/) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004188 $SymbolInfo{$Version}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004189 }
4190 $ParamInfoId = getNextElem($ParamInfoId);
4191 }
4192 my ($Position, $Vtt_Pos) = (0, -1);
4193 while($ParamInfoId)
4194 {
4195 my $ParamTypeId = getFuncParamType($ParamInfoId);
4196 my $ParamName = getFuncParamName($ParamInfoId);
4197 if($TypeInfo{$Version}{getTypeDeclId($ParamTypeId)}{$ParamTypeId}{"Name"} eq "void") {
4198 last;
4199 }
4200 if(my $AddedTid = $MissedTypedef{$Version}{$ParamTypeId}{"Tid"}) {
4201 $ParamTypeId = $AddedTid;
4202 }
4203 my $PType = get_TypeAttr($ParamTypeId, $Version, "Type");
4204 if(not $PType or $PType eq "Unknown") {
4205 return 1;
4206 }
4207 if($ParamName eq "__vtt_parm"
4208 and get_TypeName($ParamTypeId, $Version) eq "void const**")
4209 {
4210 $Vtt_Pos = $Position;
4211 $ParamInfoId = getNextElem($ParamInfoId);
4212 next;
4213 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004214 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Position}{"type"} = $ParamTypeId;
4215 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Position}{"name"} = $ParamName;
4216 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Position}{"algn"} = getAlgn($ParamInfoId)/$BYTE_SIZE;
4217 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Position}{"name"}) {
4218 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Position}{"name"} = "p".($Position+1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004219 }
4220 if($LibInfo{$Version}{"info"}{$ParamInfoId}=~/spec:\s*register /)
4221 { # foo(register type arg)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004222 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Position}{"reg"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004223 }
4224 $ParamInfoId = getNextElem($ParamInfoId);
4225 $Position += 1;
4226 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004227 if(detect_nolimit_args($InfoId, $Vtt_Pos)) {
4228 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Position}{"type"} = -1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004229 }
4230 return 0;
4231}
4232
4233sub detect_nolimit_args($$)
4234{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004235 my ($InfoId, $Vtt_Pos) = @_;
4236 my $FuncTypeId = getFuncTypeId($InfoId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004237 my $ParamListElemId = getTreeAttr($FuncTypeId, "prms");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004238 if(getFuncType($InfoId) eq "Method") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004239 $ParamListElemId = getNextElem($ParamListElemId);
4240 }
4241 return 1 if(not $ParamListElemId);# foo(...)
4242 my $HaveVoid = 0;
4243 my $Position = 0;
4244 while($ParamListElemId)
4245 {
4246 if($Vtt_Pos!=-1 and $Position==$Vtt_Pos)
4247 {
4248 $Vtt_Pos=-1;
4249 $ParamListElemId = getNextElem($ParamListElemId);
4250 next;
4251 }
4252 my $ParamTypeId = getTreeAttr($ParamListElemId, "valu");
4253 if(my $PurpId = getTreeAttr($ParamListElemId, "purp"))
4254 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004255 if(my $PurpType = $LibInfo{$Version}{"info_type"}{$PurpId})
4256 {
4257 if($PurpType eq "integer_cst") {
4258 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Position}{"default"} = getTreeValue($PurpId);
4259 }
4260 elsif($PurpType eq "string_cst") {
4261 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Position}{"default"} = getNodeStrCst($PurpId);
4262 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004263 }
4264 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004265 if($TypeInfo{$Version}{getTypeDeclId($ParamTypeId)}{$ParamTypeId}{"Name"} eq "void")
4266 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004267 $HaveVoid = 1;
4268 last;
4269 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004270 elsif(not defined $SymbolInfo{$Version}{$InfoId}{"Param"}{$Position}{"type"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004271 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004272 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Position}{"type"} = $ParamTypeId;
4273 if(not $SymbolInfo{$Version}{$InfoId}{"Param"}{$Position}{"name"}) {
4274 $SymbolInfo{$Version}{$InfoId}{"Param"}{$Position}{"name"} = "p".($Position+1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004275 }
4276 }
4277 $ParamListElemId = getNextElem($ParamListElemId);
4278 $Position += 1;
4279 }
4280 return ($Position>=1 and not $HaveVoid);
4281}
4282
4283sub getTreeAttr($$)
4284{
4285 my $Attr = $_[1];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004286 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4287 {
4288 if($Info=~/\Q$Attr\E\s*:\s*\@(\d+) /) {
4289 return $1;
4290 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004291 }
4292 return "";
4293}
4294
4295sub getTreeValue($)
4296{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004297 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4298 {
4299 if($Info=~/low[ ]*:[ ]*([^ ]+) /) {
4300 return $1;
4301 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004302 }
4303 return "";
4304}
4305
4306sub getTreeAccess($)
4307{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004308 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004309 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004310 if($Info=~/accs[ ]*:[ ]*([a-zA-Z]+) /)
4311 {
4312 my $Access = $1;
4313 if($Access eq "prot") {
4314 return "protected";
4315 }
4316 elsif($Access eq "priv") {
4317 return "private";
4318 }
4319 }
4320 elsif($Info=~/ protected /)
4321 { # support for old GCC versions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004322 return "protected";
4323 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004324 elsif($Info=~/ private /)
4325 { # support for old GCC versions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004326 return "private";
4327 }
4328 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004329 return "public";
4330}
4331
4332sub setFuncAccess($)
4333{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004334 my $Access = getTreeAccess($_[0]);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004335 if($Access eq "protected") {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004336 $SymbolInfo{$Version}{$_[0]}{"Protected"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004337 }
4338 elsif($Access eq "private") {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04004339 $SymbolInfo{$Version}{$_[0]}{"Private"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004340 }
4341}
4342
4343sub setTypeAccess($$)
4344{
4345 my ($TypeId, $TypeAttr) = @_;
4346 my $Access = getTreeAccess($TypeId);
4347 if($Access eq "protected") {
4348 $TypeAttr->{"Protected"} = 1;
4349 }
4350 elsif($Access eq "private") {
4351 $TypeAttr->{"Private"} = 1;
4352 }
4353}
4354
4355sub setFuncKind($)
4356{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004357 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4358 {
4359 if($Info=~/pseudo tmpl/) {
4360 $SymbolInfo{$Version}{$_[0]}{"PseudoTemplate"} = 1;
4361 }
4362 elsif($Info=~/ constructor /) {
4363 $SymbolInfo{$Version}{$_[0]}{"Constructor"} = 1;
4364 }
4365 elsif($Info=~/ destructor /) {
4366 $SymbolInfo{$Version}{$_[0]}{"Destructor"} = 1;
4367 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004368 }
4369}
4370
4371sub getFuncSpec($)
4372{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004373 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4374 {
4375 if($Info=~/spec[ ]*:[ ]*pure /) {
4376 return "PureVirt";
4377 }
4378 elsif($Info=~/spec[ ]*:[ ]*virt /) {
4379 return "Virt";
4380 }
4381 elsif($Info=~/ pure\s+virtual /)
4382 { # support for old GCC versions
4383 return "PureVirt";
4384 }
4385 elsif($Info=~/ virtual /)
4386 { # support for old GCC versions
4387 return "Virt";
4388 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004389 }
4390 return "";
4391}
4392
4393sub getFuncClass($)
4394{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004395 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4396 {
4397 if($Info=~/scpe[ ]*:[ ]*@(\d+) /) {
4398 return $1;
4399 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004400 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004401 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004402}
4403
4404sub getFuncLink($)
4405{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004406 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4407 {
4408 if($Info=~/link[ ]*:[ ]*static /) {
4409 return "Static";
4410 }
4411 elsif($Info=~/link[ ]*:[ ]*([a-zA-Z]+) /) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004412 return $1;
4413 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004414 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004415 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004416}
4417
4418sub getNextElem($)
4419{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004420 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4421 {
4422 if($Info=~/(chan|chain)[ ]*:[ ]*@(\d+) /) {
4423 return $2;
4424 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004425 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004426 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004427}
4428
4429sub getFuncParamInfoId($)
4430{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004431 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4432 {
4433 if($Info=~/args[ ]*:[ ]*@(\d+) /) {
4434 return $1;
4435 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004436 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004437 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004438}
4439
4440sub getFuncParamType($)
4441{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004442 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4443 {
4444 if($Info=~/type[ ]*:[ ]*@(\d+) /) {
4445 return $1;
4446 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004447 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004448 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004449}
4450
4451sub getFuncParamName($)
4452{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004453 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4454 {
4455 if($Info=~/name[ ]*:[ ]*@(\d+) /) {
4456 return getTreeStr($1);
4457 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004458 }
4459 return "";
4460}
4461
4462sub getEnumMembInfoId($)
4463{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004464 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4465 {
4466 if($Info=~/csts[ ]*:[ ]*@(\d+) /) {
4467 return $1;
4468 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004469 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004470 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004471}
4472
4473sub getStructMembInfoId($)
4474{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004475 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4476 {
4477 if($Info=~/flds[ ]*:[ ]*@(\d+) /) {
4478 return $1;
4479 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004480 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004481 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004482}
4483
4484sub get_IntNameSpace($$)
4485{
4486 my ($Interface, $LibVersion) = @_;
4487 return "" if(not $Interface or not $LibVersion);
4488 if(defined $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion}) {
4489 return $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion};
4490 }
4491 my $Signature = get_Signature($Interface, $LibVersion);
4492 if($Signature=~/\:\:/)
4493 {
4494 my $FounNameSpace = 0;
4495 foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
4496 {
4497 if($Signature=~/(\A|\s+for\s+)\Q$NameSpace\E\:\:/) {
4498 return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = $NameSpace);
4499 }
4500 }
4501 }
4502 else {
4503 return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = "");
4504 }
4505}
4506
4507sub parse_TypeNameSpace($$)
4508{
4509 my ($TypeName, $LibVersion) = @_;
4510 return "" if(not $TypeName or not $LibVersion);
4511 if(defined $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion}) {
4512 return $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion};
4513 }
4514 if($TypeName=~/\:\:/)
4515 {
4516 my $FounNameSpace = 0;
4517 foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
4518 {
4519 if($TypeName=~/\A\Q$NameSpace\E\:\:/) {
4520 return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = $NameSpace);
4521 }
4522 }
4523 }
4524 else {
4525 return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = "");
4526 }
4527}
4528
4529sub getNameSpace($)
4530{
4531 my $TypeInfoId = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004532 my $NSInfoId = getTreeAttr($TypeInfoId, "scpe");
4533 return "" if(not $NSInfoId);
4534 if(my $InfoType = $LibInfo{$Version}{"info_type"}{$NSInfoId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004535 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004536 if($InfoType eq "namespace_decl")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004537 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004538 if($LibInfo{$Version}{"info"}{$NSInfoId}=~/name[ ]*:[ ]*@(\d+) /)
4539 {
4540 my $NameSpace = getTreeStr($1);
4541 return "" if($NameSpace eq "::");
4542 if(my $BaseNameSpace = getNameSpace($NSInfoId)) {
4543 $NameSpace = $BaseNameSpace."::".$NameSpace;
4544 }
4545 $NestedNameSpaces{$Version}{$NameSpace} = 1;
4546 return $NameSpace;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004547 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004548 else {
4549 return "";
4550 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004551 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004552 elsif($InfoType eq "record_type")
4553 { # inside data type
4554 my ($Name, $NameNS) = getTrivialName(getTypeDeclId($NSInfoId), $NSInfoId);
4555 return $Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004556 }
4557 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004558 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004559}
4560
4561sub getNameSpaceId($)
4562{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004563 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4564 {
4565 if($Info=~/scpe[ ]*:[ ]*\@(\d+)/) {
4566 return $1;
4567 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004568 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004569 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004570}
4571
4572sub getEnumMembName($)
4573{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004574 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4575 {
4576 if($Info=~/purp[ ]*:[ ]*\@(\d+)/) {
4577 return getTreeStr($1);
4578 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004579 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004580 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004581}
4582
4583sub getStructMembName($)
4584{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004585 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4586 {
4587 if($Info=~/name[ ]*:[ ]*\@(\d+)/) {
4588 return getTreeStr($1);
4589 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004590 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004591 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004592}
4593
4594sub getEnumMembVal($)
4595{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004596 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004597 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004598 if($Info=~/valu[ ]*:[ ]*\@(\d+)/)
4599 {
4600 if(my $VInfo = $LibInfo{$Version}{"info"}{$1})
4601 {
4602 if($VInfo=~/cnst[ ]*:[ ]*\@(\d+)/)
4603 { # in newer versions of GCC the value is in the "const_decl->cnst" node
4604 return getTreeValue($1);
4605 }
4606 else
4607 { # some old versions of GCC (3.3) have the value in the "integer_cst" node
4608 return getTreeValue($1);
4609 }
4610 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004611 }
4612 }
4613 return "";
4614}
4615
4616sub getSize($)
4617{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004618 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4619 {
4620 if($Info=~/size[ ]*:[ ]*\@(\d+)/) {
4621 return getTreeValue($1);
4622 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004623 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004624 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004625}
4626
4627sub getAlgn($)
4628{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004629 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4630 {
4631 if($Info=~/algn[ ]*:[ ]*(\d+) /) {
4632 return $1;
4633 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004634 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004635 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004636}
4637
4638sub getStructMembBitFieldSize($)
4639{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004640 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4641 {
4642 if($Info=~/ bitfield /) {
4643 return getSize($_[0]);
4644 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004645 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004646 return 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004647}
4648
4649sub getNextMembInfoId($)
4650{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004651 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
4652 {
4653 if($Info=~/(chan|chain)[ ]*:[ ]*@(\d+) /) {
4654 return $2;
4655 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004656 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004657 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004658}
4659
4660sub getNextStructMembInfoId($)
4661{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004662 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004663 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004664 if($Info=~/(chan|chain)[ ]*:[ ]*@(\d+) /) {
4665 return $2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004666 }
4667 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04004668 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04004669}
4670
4671sub register_header($$)
4672{ # input: header absolute path, relative path or name
4673 my ($Header, $LibVersion) = @_;
4674 return "" if(not $Header);
4675 if(is_abs($Header) and not -f $Header) {
4676 exitStatus("Access_Error", "can't access \'$Header\'");
4677 }
4678 return "" if(skip_header($Header, $LibVersion));
4679 my $Header_Path = identify_header($Header, $LibVersion);
4680 return "" if(not $Header_Path);
4681 detect_header_includes($Header_Path, $LibVersion);
4682 if(my $RHeader_Path = $Header_ErrorRedirect{$LibVersion}{$Header_Path})
4683 {
4684 return "" if(skip_header($RHeader_Path, $LibVersion));
4685 $Header_Path = $RHeader_Path;
4686 return "" if($Registered_Headers{$LibVersion}{$Header_Path}{"Identity"});
4687 }
4688 elsif($Header_ShouldNotBeUsed{$LibVersion}{$Header_Path}) {
4689 return "";
4690 }
4691 $Registered_Headers{$LibVersion}{$Header_Path}{"Identity"} = get_filename($Header_Path);
4692 $HeaderName_Paths{$LibVersion}{get_filename($Header_Path)}{$Header_Path} = 1;
4693 if(($Header=~/\.(\w+)\Z/ and $1 ne "h")
4694 or $Header!~/\.(\w+)\Z/)
4695 { # hpp, hh
4696 setLanguage($LibVersion, "C++");
4697 }
4698 if($CheckHeadersOnly
4699 and $Header=~/(\A|\/)c\+\+(\/|\Z)/)
4700 { # /usr/include/c++/4.6.1/...
4701 $STDCXX_TESTING = 1;
4702 }
4703 return $Header_Path;
4704}
4705
4706sub register_directory($$$)
4707{
4708 my ($Dir, $WithDeps, $LibVersion) = @_;
4709 $Dir=~s/[\/\\]+\Z//g;
4710 return if(not $LibVersion or not $Dir or not -d $Dir);
4711 return if(skip_header($Dir, $LibVersion));
4712 $Dir = get_abs_path($Dir);
4713 my $Mode = "All";
4714 if($WithDeps) {
4715 if($RegisteredDirs{$LibVersion}{$Dir}{1}) {
4716 return;
4717 }
4718 elsif($RegisteredDirs{$LibVersion}{$Dir}{0}) {
4719 $Mode = "DepsOnly";
4720 }
4721 }
4722 else {
4723 if($RegisteredDirs{$LibVersion}{$Dir}{1}
4724 or $RegisteredDirs{$LibVersion}{$Dir}{0}) {
4725 return;
4726 }
4727 }
4728 $Header_Dependency{$LibVersion}{$Dir} = 1;
4729 $RegisteredDirs{$LibVersion}{$Dir}{$WithDeps} = 1;
4730 if($Mode eq "DepsOnly")
4731 {
4732 foreach my $Path (cmd_find($Dir,"d","","")) {
4733 $Header_Dependency{$LibVersion}{$Path} = 1;
4734 }
4735 return;
4736 }
4737 foreach my $Path (sort {length($b)<=>length($a)} cmd_find($Dir,"f","",""))
4738 {
4739 if($WithDeps)
4740 {
4741 my $SubDir = $Path;
4742 while(($SubDir = get_dirname($SubDir)) ne $Dir)
4743 { # register all sub directories
4744 $Header_Dependency{$LibVersion}{$SubDir} = 1;
4745 }
4746 }
4747 next if(is_not_header($Path));
4748 next if(ignore_path($Path));
4749 next if(skip_header($Path, $LibVersion));
4750 # Neighbors
4751 foreach my $Part (get_path_prefixes($Path)) {
4752 $Include_Neighbors{$LibVersion}{$Part} = $Path;
4753 }
4754 }
4755 if(get_filename($Dir) eq "include")
4756 { # search for "lib/include/" directory
4757 my $LibDir = $Dir;
4758 if($LibDir=~s/([\/\\])include\Z/$1lib/g and -d $LibDir) {
4759 register_directory($LibDir, $WithDeps, $LibVersion);
4760 }
4761 }
4762}
4763
4764sub parse_redirect($$$)
4765{
4766 my ($Content, $Path, $LibVersion) = @_;
4767 if(defined $Cache{"parse_redirect"}{$LibVersion}{$Path}) {
4768 return $Cache{"parse_redirect"}{$LibVersion}{$Path};
4769 }
4770 return "" if(not $Content);
4771 my @Errors = ();
4772 while($Content=~s/#\s*error\s+([^\n]+?)\s*(\n|\Z)//) {
4773 push(@Errors, $1);
4774 }
4775 my $Redirect = "";
4776 foreach (@Errors)
4777 {
4778 s/\s{2,}/ /g;
4779 if(/(only|must\ include
4780 |update\ to\ include
4781 |replaced\ with
4782 |replaced\ by|renamed\ to
4783 |is\ in|use)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))/ix)
4784 {
4785 $Redirect = $2;
4786 last;
4787 }
4788 elsif(/(include|use|is\ in)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))\ instead/i)
4789 {
4790 $Redirect = $2;
4791 last;
4792 }
4793 elsif(/this\ header\ should\ not\ be\ used
4794 |programs\ should\ not\ directly\ include
4795 |you\ should\ not\ (include|be\ (including|using)\ this\ (file|header))
4796 |is\ not\ supported\ API\ for\ general\ use
4797 |do\ not\ use
4798 |should\ not\ be\ used
4799 |cannot\ be\ included\ directly/ix and not /\ from\ /i) {
4800 $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
4801 }
4802 }
4803 $Redirect=~s/\A<//g;
4804 $Redirect=~s/>\Z//g;
4805 return ($Cache{"parse_redirect"}{$LibVersion}{$Path} = $Redirect);
4806}
4807
4808sub parse_includes($$)
4809{
4810 my ($Content, $Path) = @_;
4811 my %Includes = ();
4812 while($Content=~s/#([ \t]*)(include|include_next|import)([ \t]*)(<|")([^<>"]+)(>|")//)
4813 {# C/C++: include, Objective C/C++: import directive
4814 my ($Header, $Method) = ($5, $4);
4815 $Header = path_format($Header, $OSgroup);
4816 if(($Method eq "\"" and -e joinPath(get_dirname($Path), $Header))
4817 or is_abs($Header)) {
4818 # include "path/header.h" that doesn't exist is equal to include <path/header.h>
4819 $Includes{$Header} = -1;
4820 }
4821 else {
4822 $Includes{$Header} = 1;
4823 }
4824 }
4825 return \%Includes;
4826}
4827
4828sub ignore_path($)
4829{
4830 my $Path = $_[0];
4831 if($Path=~/\~\Z/)
4832 {# skipping system backup files
4833 return 1;
4834 }
4835 if($Path=~/(\A|[\/\\]+)(\.(svn|git|bzr|hg)|CVS)([\/\\]+|\Z)/)
4836 {# skipping hidden .svn, .git, .bzr, .hg and CVS directories
4837 return 1;
4838 }
4839 return 0;
4840}
4841
4842sub sort_by_word($$)
4843{
4844 my ($ArrRef, $W) = @_;
4845 return if(length($W)<2);
4846 @{$ArrRef} = sort {get_filename($b)=~/\Q$W\E/i<=>get_filename($a)=~/\Q$W\E/i} @{$ArrRef};
4847}
4848
4849sub natural_sorting($$)
4850{
4851 my ($H1, $H2) = @_;
4852 $H1=~s/\.[a-z]+\Z//ig;
4853 $H2=~s/\.[a-z]+\Z//ig;
4854 my ($HDir1, $Hname1) = separate_path($H1);
4855 my ($HDir2, $Hname2) = separate_path($H2);
4856 my $Dirname1 = get_filename($HDir1);
4857 my $Dirname2 = get_filename($HDir2);
4858 if($H1 eq $H2) {
4859 return 0;
4860 }
4861 elsif($H1=~/\A\Q$H2\E/) {
4862 return 1;
4863 }
4864 elsif($H2=~/\A\Q$H1\E/) {
4865 return -1;
4866 }
4867 elsif($HDir1=~/\Q$Hname1\E/i
4868 and $HDir2!~/\Q$Hname2\E/i)
4869 {# include/glib-2.0/glib.h
4870 return -1;
4871 }
4872 elsif($HDir2=~/\Q$Hname2\E/i
4873 and $HDir1!~/\Q$Hname1\E/i)
4874 {# include/glib-2.0/glib.h
4875 return 1;
4876 }
4877 elsif($Hname1=~/\Q$Dirname1\E/i
4878 and $Hname2!~/\Q$Dirname2\E/i)
4879 {# include/hildon-thumbnail/hildon-thumbnail-factory.h
4880 return -1;
4881 }
4882 elsif($Hname2=~/\Q$Dirname2\E/i
4883 and $Hname1!~/\Q$Dirname1\E/i)
4884 {# include/hildon-thumbnail/hildon-thumbnail-factory.h
4885 return 1;
4886 }
4887 elsif($Hname1=~/(config|lib)/i
4888 and $Hname2!~/(config|lib)/i)
4889 {# include/alsa/asoundlib.h
4890 return -1;
4891 }
4892 elsif($Hname2=~/(config|lib)/i
4893 and $Hname1!~/(config|lib)/i)
4894 {# include/alsa/asoundlib.h
4895 return 1;
4896 }
4897 elsif(checkRelevance($H1)
4898 and not checkRelevance($H2))
4899 {# libebook/e-book.h
4900 return -1;
4901 }
4902 elsif(checkRelevance($H2)
4903 and not checkRelevance($H1))
4904 {# libebook/e-book.h
4905 return 1;
4906 }
4907 else {
4908 return (lc($H1) cmp lc($H2));
4909 }
4910}
4911
4912sub searchForHeaders($)
4913{
4914 my $LibVersion = $_[0];
4915 # gcc standard include paths
4916 find_gcc_cxx_headers($LibVersion);
4917 # processing header paths
4918 foreach my $Path (keys(%{$Descriptor{$LibVersion}{"IncludePaths"}}),
4919 keys(%{$Descriptor{$LibVersion}{"AddIncludePaths"}}))
4920 {
4921 my $IPath = $Path;
4922 if(not -e $Path) {
4923 exitStatus("Access_Error", "can't access \'$Path\'");
4924 }
4925 elsif(-f $Path) {
4926 exitStatus("Access_Error", "\'$Path\' - not a directory");
4927 }
4928 elsif(-d $Path)
4929 {
4930 $Path = get_abs_path($Path);
4931 register_directory($Path, 0, $LibVersion);
4932 if($Descriptor{$LibVersion}{"AddIncludePaths"}{$IPath}) {
4933 $Add_Include_Paths{$LibVersion}{$Path} = 1;
4934 }
4935 else {
4936 $Include_Paths{$LibVersion}{$Path} = 1;
4937 }
4938 }
4939 }
4940 if(keys(%{$Include_Paths{$LibVersion}})) {
4941 $INC_PATH_AUTODETECT{$LibVersion} = 0;
4942 }
4943 # registering directories
4944 foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
4945 {
4946 next if(not -e $Path);
4947 $Path = get_abs_path($Path);
4948 $Path = path_format($Path, $OSgroup);
4949 if(-d $Path) {
4950 register_directory($Path, 1, $LibVersion);
4951 }
4952 elsif(-f $Path)
4953 {
4954 my $Dir = get_dirname($Path);
4955 if(not $SystemPaths{"include"}{$Dir}
4956 and not $LocalIncludes{$Dir})
4957 {
4958 register_directory($Dir, 1, $LibVersion);
4959 if(my $OutDir = get_dirname($Dir))
4960 { # registering the outer directory
4961 if(not $SystemPaths{"include"}{$OutDir}
4962 and not $LocalIncludes{$OutDir}) {
4963 register_directory($OutDir, 0, $LibVersion);
4964 }
4965 }
4966 }
4967 }
4968 }
4969 # registering headers
4970 my $Position = 0;
4971 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
4972 {
4973 if(is_abs($Dest) and not -e $Dest) {
4974 exitStatus("Access_Error", "can't access \'$Dest\'");
4975 }
4976 $Dest = path_format($Dest, $OSgroup);
4977 if(is_header($Dest, 1, $LibVersion))
4978 {
4979 if(my $HPath = register_header($Dest, $LibVersion)) {
4980 $Registered_Headers{$LibVersion}{$HPath}{"Pos"} = $Position++;
4981 }
4982 }
4983 elsif(-d $Dest)
4984 {
4985 my @Registered = ();
4986 foreach my $Path (cmd_find($Dest,"f","",""))
4987 {
4988 next if(ignore_path($Path));
4989 next if(not is_header($Path, 0, $LibVersion));
4990 if(my $HPath = register_header($Path, $LibVersion)) {
4991 push(@Registered, $HPath);
4992 }
4993 }
4994 @Registered = sort {natural_sorting($a, $b)} @Registered;
4995 sort_by_word(\@Registered, $TargetLibraryShortName);
4996 foreach my $Path (@Registered) {
4997 $Registered_Headers{$LibVersion}{$Path}{"Pos"} = $Position++;
4998 }
4999 }
5000 else {
5001 exitStatus("Access_Error", "can't identify \'$Dest\' as a header file");
5002 }
5003 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005004 if(my $HList = $Descriptor{$LibVersion}{"IncludePreamble"})
5005 { # preparing preamble headers
5006 my $PPos=0;
5007 foreach my $Header (split(/\s*\n\s*/, $HList))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005008 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005009 if(is_abs($Header) and not -f $Header) {
5010 exitStatus("Access_Error", "can't access file \'$Header\'");
5011 }
5012 $Header = path_format($Header, $OSgroup);
5013 if(my $Header_Path = is_header($Header, 1, $LibVersion))
5014 {
5015 next if(skip_header($Header_Path, $LibVersion));
5016 $Include_Preamble{$LibVersion}{$Header_Path}{"Position"} = $PPos++;
5017 }
5018 else {
5019 exitStatus("Access_Error", "can't identify \'$Header\' as a header file");
5020 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005021 }
5022 }
5023 foreach my $Header_Name (keys(%{$HeaderName_Paths{$LibVersion}}))
5024 { # set relative paths (for duplicates)
5025 if(keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})>=2)
5026 { # search for duplicates
5027 my $FirstPath = (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))[0];
5028 my $Prefix = get_dirname($FirstPath);
5029 while($Prefix=~/\A(.+)[\/\\]+[^\/\\]+\Z/)
5030 { # detect a shortest distinguishing prefix
5031 my $NewPrefix = $1;
5032 my %Identity = ();
5033 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
5034 {
5035 if($Path=~/\A\Q$Prefix\E[\/\\]+(.*)\Z/) {
5036 $Identity{$Path} = $1;
5037 }
5038 }
5039 if(keys(%Identity)==keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
5040 { # all names are differend with current prefix
5041 foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})) {
5042 $Registered_Headers{$LibVersion}{$Path}{"Identity"} = $Identity{$Path};
5043 }
5044 last;
5045 }
5046 $Prefix = $NewPrefix; # increase prefix
5047 }
5048 }
5049 }
5050 foreach my $HeaderName (keys(%{$Include_Order{$LibVersion}}))
5051 { # ordering headers according to descriptor
5052 my $PairName=$Include_Order{$LibVersion}{$HeaderName};
5053 my ($Pos, $PairPos) = (-1, -1);
5054 my ($Path, $PairPath) = ();
5055 my @Paths = keys(%{$Registered_Headers{$LibVersion}});
5056 @Paths = sort {int($Registered_Headers{$LibVersion}{$a}{"Pos"})<=>int($Registered_Headers{$LibVersion}{$b}{"Pos"})} @Paths;
5057 foreach my $Header_Path (@Paths)
5058 {
5059 if(get_filename($Header_Path) eq $PairName)
5060 {
5061 $PairPos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
5062 $PairPath = $Header_Path;
5063 }
5064 if(get_filename($Header_Path) eq $HeaderName)
5065 {
5066 $Pos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
5067 $Path = $Header_Path;
5068 }
5069 }
5070 if($PairPos!=-1 and $Pos!=-1
5071 and int($PairPos)<int($Pos))
5072 {
5073 my %Tmp = %{$Registered_Headers{$LibVersion}{$Path}};
5074 %{$Registered_Headers{$LibVersion}{$Path}} = %{$Registered_Headers{$LibVersion}{$PairPath}};
5075 %{$Registered_Headers{$LibVersion}{$PairPath}} = %Tmp;
5076 }
5077 }
5078 if(not keys(%{$Registered_Headers{$LibVersion}})) {
5079 exitStatus("Error", "header files are not found in the ".$Descriptor{$LibVersion}{"Version"});
5080 }
5081}
5082
5083sub detect_real_includes($$)
5084{
5085 my ($AbsPath, $LibVersion) = @_;
5086 return () if(not $LibVersion or not $AbsPath or not -e $AbsPath);
5087 if($Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}
5088 or keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
5089 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5090 }
5091 my $Path = callPreprocessor($AbsPath, "", $LibVersion);
5092 return () if(not $Path);
5093 open(PREPROC, $Path);
5094 while(<PREPROC>)
5095 {
5096 if(/#\s+\d+\s+"([^"]+)"[\s\d]*\n/)
5097 {
5098 my $Include = path_format($1, $OSgroup);
5099 if($Include=~/\<(built\-in|internal|command(\-|\s)line)\>|\A\./) {
5100 next;
5101 }
5102 if($Include eq $AbsPath) {
5103 next;
5104 }
5105 $RecursiveIncludes{$LibVersion}{$AbsPath}{$Include} = 1;
5106 }
5107 }
5108 close(PREPROC);
5109 $Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}=1;
5110 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5111}
5112
5113sub detect_header_includes($$)
5114{
5115 my ($Path, $LibVersion) = @_;
5116 return if(not $LibVersion or not $Path or not -e $Path);
5117 return if($Cache{"detect_header_includes"}{$LibVersion}{$Path});
5118 my $Content = readFile($Path);
5119 if($Content=~/#[ \t]*error[ \t]+/ and (my $Redirect = parse_redirect($Content, $Path, $LibVersion)))
5120 {# detecting error directive in the headers
5121 if(my $RedirectPath = identify_header($Redirect, $LibVersion))
5122 {
5123 if($RedirectPath=~/\/usr\/include\// and $Path!~/\/usr\/include\//) {
5124 $RedirectPath = identify_header(get_filename($Redirect), $LibVersion);
5125 }
5126 if($RedirectPath ne $Path) {
5127 $Header_ErrorRedirect{$LibVersion}{$Path} = $RedirectPath;
5128 }
5129 }
5130 }
5131 my $Inc = parse_includes($Content, $Path);
5132 foreach my $Include (keys(%{$Inc}))
5133 {# detecting includes
5134 #if(is_not_header($Include))
5135 #{ #include<*.c> and others
5136 # next;
5137 #}
5138 $Header_Includes{$LibVersion}{$Path}{$Include} = $Inc->{$Include};
5139 }
5140 $Cache{"detect_header_includes"}{$LibVersion}{$Path} = 1;
5141}
5142
5143sub simplify_path($)
5144{
5145 my $Path = $_[0];
5146 while($Path=~s&([\/\\])[^\/\\]+[\/\\]\.\.[\/\\]&$1&){};
5147 return $Path;
5148}
5149
5150sub fromLibc($)
5151{ # GLIBC header
5152 my $Path = $_[0];
5153 my ($Dir, $Name) = separate_path($Path);
5154 if(get_filename($Dir)=~/\A(include|libc)\Z/ and $GlibcHeader{$Name})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005155 { # /usr/include/{stdio, ...}.h
5156 # epoc32/include/libc/{stdio, ...}.h
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005157 return 1;
5158 }
5159 if(isLibcDir($Dir)) {
5160 return 1;
5161 }
5162 return 0;
5163}
5164
5165sub isLibcDir($)
5166{ # GLIBC directory
5167 my $Dir = $_[0];
5168 my ($OutDir, $Name) = separate_path($Dir);
5169 if(get_filename($OutDir)=~/\A(include|libc)\Z/
5170 and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name}))
5171 { # /usr/include/{sys,bits,asm,asm-*}/*.h
5172 return 1;
5173 }
5174 return 0;
5175}
5176
5177sub detect_recursive_includes($$)
5178{
5179 my ($AbsPath, $LibVersion) = @_;
5180 return () if(not $AbsPath);
5181 if(isCyclical(\@RecurInclude, $AbsPath)) {
5182 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5183 }
5184 my ($AbsDir, $Name) = separate_path($AbsPath);
5185 if(isLibcDir($AbsDir))
5186 { # GLIBC internals
5187 return ();
5188 }
5189 if(keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
5190 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5191 }
5192 return () if($OSgroup ne "windows" and $Name=~/windows|win32|win64/i);
5193 return () if($MAIN_CPP_DIR and $AbsPath=~/\A\Q$MAIN_CPP_DIR\E/ and not $STDCXX_TESTING);
5194 push(@RecurInclude, $AbsPath);
5195 if($DefaultGccPaths{$AbsDir}
5196 or fromLibc($AbsPath))
5197 { # check "real" (non-"model") include paths
5198 my @Paths = detect_real_includes($AbsPath, $LibVersion);
5199 pop(@RecurInclude);
5200 return @Paths;
5201 }
5202 if(not keys(%{$Header_Includes{$LibVersion}{$AbsPath}})) {
5203 detect_header_includes($AbsPath, $LibVersion);
5204 }
5205 foreach my $Include (keys(%{$Header_Includes{$LibVersion}{$AbsPath}}))
5206 {
5207 my $HPath = "";
5208 if($Header_Includes{$LibVersion}{$AbsPath}{$Include}==-1)
5209 { # for #include "..."
5210 my $Candidate = joinPath($AbsDir, $Include);
5211 if(-f $Candidate) {
5212 $HPath = simplify_path($Candidate);
5213 }
5214 }
5215 elsif($Header_Includes{$LibVersion}{$AbsPath}{$Include}==1
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04005216 and $Include=~/[\/\\]/) # and not find_in_defaults($Include)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005217 { # search for the nearest header
5218 # QtCore/qabstractanimation.h includes <QtCore/qobject.h>
5219 my $Candidate = joinPath(get_dirname($AbsDir), $Include);
5220 if(-f $Candidate) {
5221 $HPath = $Candidate;
5222 }
5223 }
5224 if(not $HPath) {
5225 $HPath = identify_header($Include, $LibVersion);
5226 }
5227 next if(not $HPath);
5228 if($HPath eq $AbsPath) {
5229 next;
5230 }
5231 $RecursiveIncludes{$LibVersion}{$AbsPath}{$HPath} = 1;
5232 if($Header_Includes{$LibVersion}{$AbsPath}{$Include}==1)
5233 { # only include <...>, skip include "..." prefixes
5234 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$HPath}{get_dirname($Include)} = 1;
5235 }
5236 foreach my $IncPath (detect_recursive_includes($HPath, $LibVersion))
5237 {
5238 if($IncPath eq $AbsPath) {
5239 next;
5240 }
5241 $RecursiveIncludes{$LibVersion}{$AbsPath}{$IncPath} = 1;
5242 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$HPath}{$IncPath}})) {
5243 $Header_Include_Prefix{$LibVersion}{$AbsPath}{$IncPath}{$Prefix} = 1;
5244 }
5245 }
5246 foreach my $Dep (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}}))
5247 {
5248 if($GlibcHeader{get_filename($Dep)} and keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}})>=2
5249 and defined $Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""})
5250 { # distinguish math.h from glibc and math.h from the tested library
5251 delete($Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""});
5252 last;
5253 }
5254 }
5255 }
5256 pop(@RecurInclude);
5257 return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
5258}
5259
5260sub find_in_framework($$$)
5261{
5262 my ($Header, $Framework, $LibVersion) = @_;
5263 return "" if(not $Header or not $Framework or not $LibVersion);
5264 if(defined $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header}) {
5265 return $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header};
5266 }
5267 foreach my $Dependency (sort {get_depth($a)<=>get_depth($b)} keys(%{$Header_Dependency{$LibVersion}}))
5268 {
5269 if(get_filename($Dependency) eq $Framework
5270 and -f get_dirname($Dependency)."/".$Header) {
5271 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = get_dirname($Dependency));
5272 }
5273 }
5274 return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = "");
5275}
5276
5277sub find_in_defaults($)
5278{
5279 my $Header = $_[0];
5280 return "" if(not $Header);
5281 if(defined $Cache{"find_in_defaults"}{$Header}) {
5282 return $Cache{"find_in_defaults"}{$Header};
5283 }
5284 foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
5285 (keys(%DefaultIncPaths), keys(%DefaultGccPaths), keys(%DefaultCppPaths), keys(%UserIncPath)))
5286 {
5287 next if(not $Dir);
5288 if(-f $Dir."/".$Header) {
5289 return ($Cache{"find_in_defaults"}{$Header}=$Dir);
5290 }
5291 }
5292 return ($Cache{"find_in_defaults"}{$Header}="");
5293}
5294
5295sub cmp_paths($$)
5296{
5297 my ($Path1, $Path2) = @_;
5298 my @Parts1 = split(/[\/\\]/, $Path1);
5299 my @Parts2 = split(/[\/\\]/, $Path2);
5300 foreach my $Num (0 .. $#Parts1)
5301 {
5302 my $Part1 = $Parts1[$Num];
5303 my $Part2 = $Parts2[$Num];
5304 if($GlibcDir{$Part1}
5305 and not $GlibcDir{$Part2}) {
5306 return 1;
5307 }
5308 elsif($GlibcDir{$Part2}
5309 and not $GlibcDir{$Part1}) {
5310 return -1;
5311 }
5312 elsif($Part1=~/glib/
5313 and $Part2!~/glib/) {
5314 return 1;
5315 }
5316 elsif($Part1!~/glib/
5317 and $Part2=~/glib/) {
5318 return -1;
5319 }
5320 elsif(my $CmpRes = ($Part1 cmp $Part2)) {
5321 return $CmpRes;
5322 }
5323 }
5324 return 0;
5325}
5326
5327sub checkRelevance($)
5328{
5329 my ($Path) = @_;
5330 return 0 if(not $Path);
5331 if($SystemRoot) {
5332 $Path=~s/\A\Q$SystemRoot\E//g;
5333 }
5334 my ($Dir, $Name) = separate_path($Path);
5335 $Name=~s/\.\w+\Z//g;# remove extension (.h)
5336 my @Tokens = split(/[_\d\W]+/, $Name);
5337 foreach (@Tokens)
5338 {
5339 next if(not $_);
5340 if($Dir=~/(\A|lib|[_\d\W])\Q$_\E([_\d\W]|lib|\Z)/i
5341 or length($_)>=4 and $Dir=~/\Q$_\E/i)
5342 { # include/gupnp-1.0/libgupnp/gupnp-context.h
5343 # include/evolution-data-server-1.4/libebook/e-book.h
5344 return 1;
5345 }
5346 }
5347 return 0;
5348}
5349
5350sub checkFamily(@)
5351{
5352 my @Paths = @_;
5353 return 1 if($#Paths<=0);
5354 my %Prefix = ();
5355 foreach my $Path (@Paths)
5356 {
5357 if($SystemRoot) {
5358 $Path = cut_path_prefix($Path, $SystemRoot);
5359 }
5360 if(my $Dir = get_dirname($Path))
5361 {
5362 $Dir=~s/(\/[^\/]+?)[\d\.\-\_]+\Z/$1/g; # remove version suffix
5363 $Prefix{$Dir} += 1;
5364 $Prefix{get_dirname($Dir)} += 1;
5365 }
5366 }
5367 foreach (sort keys(%Prefix))
5368 {
5369 if(get_depth($_)>=3
5370 and $Prefix{$_}==$#Paths+1) {
5371 return 1;
5372 }
5373 }
5374 return 0;
5375}
5376
5377sub isAcceptable($$$)
5378{
5379 my ($Header, $Candidate, $LibVersion) = @_;
5380 my $HName = get_filename($Header);
5381 if(get_dirname($Header))
5382 { # with prefix
5383 return 1;
5384 }
5385 if($HName=~/config|setup/i and $Candidate=~/[\/\\]lib\d*[\/\\]/)
5386 { # allow to search for glibconfig.h in /usr/lib/glib-2.0/include/
5387 return 1;
5388 }
5389 if(checkRelevance($Candidate))
5390 { # allow to search for atk.h in /usr/include/atk-1.0/atk/
5391 return 1;
5392 }
5393 if(checkFamily(getSystemHeaders($HName, $LibVersion)))
5394 { # /usr/include/qt4/QtNetwork/qsslconfiguration.h
5395 # /usr/include/qt4/Qt/qsslconfiguration.h
5396 return 1;
5397 }
5398 if($OStarget eq "symbian")
5399 {
5400 if($Candidate=~/[\/\\]stdapis[\/\\]/) {
5401 return 1;
5402 }
5403 }
5404 return 0;
5405}
5406
5407sub isRelevant($$$)
5408{ # disallow to search for "abstract" headers in too deep directories
5409 my ($Header, $Candidate, $LibVersion) = @_;
5410 my $HName = get_filename($Header);
5411 if($OStarget eq "symbian")
5412 {
5413 if($Candidate=~/[\/\\](tools|stlportv5)[\/\\]/) {
5414 return 0;
5415 }
5416 }
5417 if($OStarget ne "bsd") {
5418 if($Candidate=~/[\/\\]include[\/\\]bsd[\/\\]/)
5419 { # openssh: skip /usr/lib/bcc/include/bsd/signal.h
5420 return 0;
5421 }
5422 }
5423 if(not get_dirname($Header)
5424 and $Candidate=~/[\/\\]wx[\/\\]/)
5425 { # do NOT search in system /wx/ directory
5426 # for headers without a prefix: sstream.h
5427 return 0;
5428 }
5429 if($Candidate=~/c\+\+[\/\\]\d+/ and $MAIN_CPP_DIR
5430 and $Candidate!~/\A\Q$MAIN_CPP_DIR\E/)
5431 { # skip ../c++/3.3.3/ if using ../c++/4.5/
5432 return 0;
5433 }
5434 if($Candidate=~/[\/\\]asm-/
5435 and (my $Arch = getArch($LibVersion)) ne "unknown")
5436 { # arch-specific header files
5437 if($Candidate!~/[\/\\]asm-\Q$Arch\E/)
5438 {# skip ../asm-arm/ if using x86 architecture
5439 return 0;
5440 }
5441 }
5442 my @Candidates = getSystemHeaders($HName, $LibVersion);
5443 if($#Candidates==1)
5444 { # unique header
5445 return 1;
5446 }
5447 my @SCandidates = getSystemHeaders($Header, $LibVersion);
5448 if($#SCandidates==1)
5449 { # unique name
5450 return 1;
5451 }
5452 my $SystemDepth = $SystemRoot?get_depth($SystemRoot):0;
5453 if(get_depth($Candidate)-$SystemDepth>=5)
5454 { # abstract headers in too deep directories
5455 # sstream.h or typeinfo.h in /usr/include/wx-2.9/wx/
5456 if(not isAcceptable($Header, $Candidate, $LibVersion)) {
5457 return 0;
5458 }
5459 }
5460 if($Header eq "parser.h"
5461 and $Candidate!~/\/libxml2\//)
5462 { # select parser.h from xml2 library
5463 return 0;
5464 }
5465 if(not get_dirname($Header)
5466 and keys(%{$SystemHeaders{$HName}})>=3)
5467 { # many headers with the same name
5468 # like thread.h included without a prefix
5469 if(not checkFamily(@Candidates)) {
5470 return 0;
5471 }
5472 }
5473 return 1;
5474}
5475
5476sub selectSystemHeader($$)
5477{
5478 my ($Header, $LibVersion) = @_;
5479 return $Header if(-f $Header);
5480 return "" if(is_abs($Header) and not -f $Header);
5481 return "" if($Header=~/\A(atomic|config|configure|build|conf|setup)\.h\Z/i);
5482 if($OSgroup ne "windows")
5483 {
5484 if(get_filename($Header)=~/windows|win32|win64|\A(dos|process|winsock|config-win)\.h\Z/i) {
5485 return "";
5486 }
5487 elsif($Header=~/\A(mem)\.h\Z/)
5488 { # pngconf.h include mem.h for __MSDOS__
5489 return "";
5490 }
5491 }
5492 if($OSgroup ne "solaris")
5493 {
5494 if($Header=~/\A(thread)\.h\Z/)
5495 { # thread.h in Solaris
5496 return "";
5497 }
5498 }
5499 if(defined $Cache{"selectSystemHeader"}{$LibVersion}{$Header}) {
5500 return $Cache{"selectSystemHeader"}{$LibVersion}{$Header};
5501 }
5502 foreach my $Path (keys(%{$SystemPaths{"include"}}))
5503 { # search in default paths
5504 if(-f $Path."/".$Header) {
5505 return ($Cache{"selectSystemHeader"}{$LibVersion}{$Header} = joinPath($Path,$Header));
5506 }
5507 }
5508 if(not keys(%SystemHeaders)) {
5509 detectSystemHeaders();
5510 }
5511 foreach my $Candidate (sort {get_depth($a)<=>get_depth($b)}
5512 sort {cmp_paths($b, $a)} getSystemHeaders($Header, $LibVersion))
5513 {
5514 if(isRelevant($Header, $Candidate, $LibVersion)) {
5515 return ($Cache{"selectSystemHeader"}{$LibVersion}{$Header} = $Candidate);
5516 }
5517 }
5518 return ($Cache{"selectSystemHeader"}{$LibVersion}{$Header} = ""); # error
5519}
5520
5521sub getSystemHeaders($$)
5522{
5523 my ($Header, $LibVersion) = @_;
5524 my @Candidates = ();
5525 foreach my $Candidate (sort keys(%{$SystemHeaders{$Header}}))
5526 {
5527 if(skip_header($Candidate, $LibVersion)) {
5528 next;
5529 }
5530 push(@Candidates, $Candidate);
5531 }
5532 return @Candidates;
5533}
5534
5535sub cut_path_prefix($$)
5536{
5537 my ($Path, $Prefix) = @_;
5538 return $Path if(not $Prefix);
5539 $Prefix=~s/[\/\\]+\Z//;
5540 $Path=~s/\A\Q$Prefix\E([\/\\]+|\Z)//;
5541 return $Path;
5542}
5543
5544sub is_default_include_dir($)
5545{
5546 my $Dir = $_[0];
5547 $Dir=~s/[\/\\]+\Z//;
5548 return ($DefaultGccPaths{$Dir} or $DefaultCppPaths{$Dir} or $DefaultIncPaths{$Dir});
5549}
5550
5551sub identify_header($$)
5552{
5553 my ($Header, $LibVersion) = @_;
5554 $Header=~s/\A(\.\.[\\\/])+//g;
5555 if(defined $Cache{"identify_header"}{$Header}{$LibVersion}) {
5556 return $Cache{"identify_header"}{$Header}{$LibVersion};
5557 }
5558 my $Path = identify_header_internal($Header, $LibVersion);
5559 if(not $Path and $OSgroup eq "macos" and my $Dir = get_dirname($Header))
5560 { # search in frameworks: "OpenGL/gl.h" is "OpenGL.framework/Headers/gl.h"
5561 my $RelPath = "Headers\/".get_filename($Header);
5562 if(my $HeaderDir = find_in_framework($RelPath, $Dir.".framework", $LibVersion)) {
5563 $Path = joinPath($HeaderDir, $RelPath);
5564 }
5565 }
5566 return ($Cache{"identify_header"}{$Header}{$LibVersion} = $Path);
5567}
5568
5569sub identify_header_internal($$)
5570{ # search for header by absolute path, relative path or name
5571 my ($Header, $LibVersion) = @_;
5572 return "" if(not $Header);
5573 if(-f $Header)
5574 { # it's relative or absolute path
5575 return get_abs_path($Header);
5576 }
5577 elsif($GlibcHeader{$Header} and not $GLIBC_TESTING
5578 and my $HeaderDir = find_in_defaults($Header))
5579 { # search for libc headers in the /usr/include
5580 # for non-libc target library before searching
5581 # in the library paths
5582 return joinPath($HeaderDir,$Header);
5583 }
5584 elsif(my $Path = $Include_Neighbors{$LibVersion}{$Header})
5585 { # search in the target library paths
5586 return $Path;
5587 }
5588 elsif($DefaultGccHeader{$Header})
5589 { # search in the internal GCC include paths
5590 return $DefaultGccHeader{$Header};
5591 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005592 elsif(my $DefaultDir = find_in_defaults($Header))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005593 { # search in the default GCC include paths
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005594 return joinPath($DefaultDir,$Header);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005595 }
5596 elsif($DefaultCppHeader{$Header})
5597 { # search in the default G++ include paths
5598 return $DefaultCppHeader{$Header};
5599 }
5600 elsif(my $AnyPath = selectSystemHeader($Header, $LibVersion))
5601 { # search everywhere in the system
5602 return $AnyPath;
5603 }
5604 else
5605 { # cannot find anything
5606 return "";
5607 }
5608}
5609
5610sub getLocation($)
5611{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005612 if($_[0] and my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5613 {
5614 if($Info=~/srcp[ ]*:[ ]*([\w\-\<\>\.\+\/\\]+):(\d+) /) {
5615 return ($1, $2);
5616 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005617 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005618 return ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005619}
5620
5621sub getTypeTypeByTypeId($)
5622{
5623 my $TypeId = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005624 if(my $TType = $LibInfo{$Version}{"info_type"}{$TypeId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005625 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005626 my $NType = $NodeType{$TType};
5627 if($NType eq "Intrinsic") {
5628 return $NType;
5629 }
5630 elsif(isFuncPtr($TypeId)) {
5631 return "FuncPtr";
5632 }
5633 elsif(isMethodPtr($TypeId)) {
5634 return "MethodPtr";
5635 }
5636 elsif(isFieldPtr($TypeId)) {
5637 return "FieldPtr";
5638 }
5639 elsif($NType ne "Other") {
5640 return $NType;
5641 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005642 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005643 return "Unknown";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005644}
5645
5646sub getNameByInfo($)
5647{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005648 if(my $Info = $LibInfo{$Version}{"info"}{$_[0]})
5649 {
5650 if($Info=~/name[ ]*:[ ]*@(\d+) /)
5651 {
5652 if(my $NInfo = $LibInfo{$Version}{"info"}{$1})
5653 {
5654 if($NInfo=~/strg[ ]*:[ ]*(.*?)[ ]+lngt/)
5655 { # short unsigned int (may include spaces)
5656 return $1;
5657 }
5658 }
5659 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005660 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005661 return "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005662}
5663
5664sub getTreeStr($)
5665{
5666 my $Info = $LibInfo{$Version}{"info"}{$_[0]};
5667 if($Info=~/strg[ ]*:[ ]*([^ ]*)/)
5668 {
5669 my $Str = $1;
5670 if($C99Mode{$Version}
5671 and $Str=~/\Ac99_(.+)\Z/) {
5672 if($CppKeywords_A{$1}) {
5673 $Str=$1;
5674 }
5675 }
5676 return $Str;
5677 }
5678 else {
5679 return "";
5680 }
5681}
5682
5683sub getVarShortName($)
5684{
5685 my $VarInfo = $LibInfo{$Version}{"info"}{$_[0]};
5686 return "" if($VarInfo!~/name[ ]*:[ ]*@(\d+) /);
5687 return getTreeStr($1);
5688}
5689
5690sub getFuncShortName($)
5691{
5692 my $FuncInfo = $LibInfo{$Version}{"info"}{$_[0]};
5693 if($FuncInfo=~/ operator /)
5694 {
5695 if($FuncInfo=~/ conversion /) {
5696 return "operator ".get_TypeName($SymbolInfo{$Version}{$_[0]}{"Return"}, $Version);
5697 }
5698 else
5699 {
5700 return "" if($FuncInfo!~/ operator[ ]+([a-zA-Z]+) /);
5701 return "operator".$Operator_Indication{$1};
5702 }
5703 }
5704 else
5705 {
5706 return "" if($FuncInfo!~/name[ ]*:[ ]*@(\d+) /);
5707 return getTreeStr($1);
5708 }
5709}
5710
5711sub getFuncMnglName($)
5712{
5713 my $FuncInfo = $LibInfo{$Version}{"info"}{$_[0]};
5714 return "" if($FuncInfo!~/mngl[ ]*:[ ]*@(\d+) /);
5715 return getTreeStr($1);
5716}
5717
5718sub getFuncReturn($)
5719{
5720 my $FuncInfo = $LibInfo{$Version}{"info"}{$_[0]};
5721 if($FuncInfo=~/type[ ]*:[ ]*@(\d+) /) {
5722 if($LibInfo{$Version}{"info"}{$1}=~/retn[ ]*:[ ]*@(\d+) /) {
5723 return $1;
5724 }
5725 }
5726 return "";
5727}
5728
5729sub getFuncOrig($)
5730{
5731 my $FuncInfo = $LibInfo{$Version}{"info"}{$_[0]};
5732 if($FuncInfo=~/orig[ ]*:[ ]*@(\d+) /) {
5733 return $1;
5734 }
5735 else {
5736 return $_[0];
5737 }
5738}
5739
5740sub unmangleSymbol($)
5741{
5742 my $Symbol = $_[0];
5743 my @Unmngl = unmangleArray($Symbol);
5744 return $Unmngl[0];
5745}
5746
5747sub unmangleArray(@)
5748{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04005749 if($_[0]=~/\A\?/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005750 { # MSVC mangling
5751 my $UndNameCmd = get_CmdPath("undname");
5752 if(not $UndNameCmd) {
5753 exitStatus("Not_Found", "can't find \"undname\"");
5754 }
5755 writeFile("$TMP_DIR/unmangle", join("\n", @_));
5756 return split(/\n/, `$UndNameCmd 0x8386 $TMP_DIR/unmangle`);
5757 }
5758 else
5759 { # GCC mangling
5760 my $CppFiltCmd = get_CmdPath("c++filt");
5761 if(not $CppFiltCmd) {
5762 exitStatus("Not_Found", "can't find c++filt in PATH");
5763 }
5764 my $Info = `$CppFiltCmd -h 2>&1`;
5765 if($Info=~/\@<file>/)
5766 {# new version of c++filt can take a file
5767 my $NoStrip = "";
5768 if($OSgroup eq "macos"
5769 or $OSgroup eq "windows") {
5770 $NoStrip = "-n";
5771 }
5772 writeFile("$TMP_DIR/unmangle", join("\n", @_));
5773 return split(/\n/, `$CppFiltCmd $NoStrip \@\"$TMP_DIR/unmangle\"`);
5774 }
5775 else
5776 { # old-style unmangling
5777 if($#_>$MAX_COMMAND_LINE_ARGUMENTS) {
5778 my @Half = splice(@_, 0, ($#_+1)/2);
5779 return (unmangleArray(@Half), unmangleArray(@_))
5780 }
5781 else
5782 {
5783 my $NoStrip = "";
5784 if($OSgroup eq "macos"
5785 or $OSgroup eq "windows") {
5786 $NoStrip = "-n";
5787 }
5788 my $Strings = join(" ", @_);
5789 return split(/\n/, `$CppFiltCmd $NoStrip $Strings`);
5790 }
5791 }
5792 }
5793}
5794
5795sub get_SignatureNoInfo($$)
5796{
5797 my ($Interface, $LibVersion) = @_;
5798 if($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Interface}) {
5799 return $Cache{"get_SignatureNoInfo"}{$LibVersion}{$Interface};
5800 }
5801 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Interface);
5802 my $Signature = $tr_name{$MnglName}?$tr_name{$MnglName}:$MnglName;
5803 if($Interface=~/\A(_Z|\?)/)
5804 { # C++
5805 $Signature=~s/\Qstd::basic_string<char, std::char_traits<char>, std::allocator<char> >\E/std::string/g;
5806 $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;
5807 }
5808 if(not $CheckObjectsOnly or $OSgroup=~/linux|bsd|beos/)
5809 { # ELF format marks data as OBJECT
5810 if($CompleteSignature{$LibVersion}{$Interface}{"Object"}) {
5811 $Signature .= " [data]";
5812 }
5813 elsif($Interface!~/\A(_Z|\?)/) {
5814 $Signature .= " (...)";
5815 }
5816 }
5817 if(my $ChargeLevel = get_ChargeLevel($Interface, $LibVersion))
5818 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04005819 my $ShortName = substr($Signature, 0, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005820 $Signature=~s/\A\Q$ShortName\E/$ShortName $ChargeLevel/g;
5821 }
5822 if($SymbolVersion) {
5823 $Signature .= $VersionSpec.$SymbolVersion;
5824 }
5825 return ($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Interface} = $Signature);
5826}
5827
5828sub get_ChargeLevel($$)
5829{
5830 my ($Interface, $LibVersion) = @_;
5831 return "" if($Interface!~/\A(_Z|\?)/);
5832 if(defined $CompleteSignature{$LibVersion}{$Interface}
5833 and $CompleteSignature{$LibVersion}{$Interface}{"Header"})
5834 {
5835 if($CompleteSignature{$LibVersion}{$Interface}{"Constructor"})
5836 {
5837 if($Interface=~/C1E/) {
5838 return "[in-charge]";
5839 }
5840 elsif($Interface=~/C2E/) {
5841 return "[not-in-charge]";
5842 }
5843 }
5844 elsif($CompleteSignature{$LibVersion}{$Interface}{"Destructor"})
5845 {
5846 if($Interface=~/D1E/) {
5847 return "[in-charge]";
5848 }
5849 elsif($Interface=~/D2E/) {
5850 return "[not-in-charge]";
5851 }
5852 elsif($Interface=~/D0E/) {
5853 return "[in-charge-deleting]";
5854 }
5855 }
5856 }
5857 else
5858 {
5859 if($Interface=~/C1E/) {
5860 return "[in-charge]";
5861 }
5862 elsif($Interface=~/C2E/) {
5863 return "[not-in-charge]";
5864 }
5865 elsif($Interface=~/D1E/) {
5866 return "[in-charge]";
5867 }
5868 elsif($Interface=~/D2E/) {
5869 return "[not-in-charge]";
5870 }
5871 elsif($Interface=~/D0E/) {
5872 return "[in-charge-deleting]";
5873 }
5874 }
5875 return "";
5876}
5877
5878sub get_Signature($$)
5879{
5880 my ($Interface, $LibVersion) = @_;
5881 if($Cache{"get_Signature"}{$LibVersion}{$Interface}) {
5882 return $Cache{"get_Signature"}{$LibVersion}{$Interface};
5883 }
5884 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Interface);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04005885 if(skipPrivateData($MnglName) or not $CompleteSignature{$LibVersion}{$Interface}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04005886 return get_SignatureNoInfo($Interface, $LibVersion);
5887 }
5888 my ($Func_Signature, @Param_Types_FromUnmangledName) = ();
5889 my $ShortName = $CompleteSignature{$LibVersion}{$Interface}{"ShortName"};
5890 if($Interface=~/\A(_Z|\?)/)
5891 {
5892 if(my $ClassId = $CompleteSignature{$LibVersion}{$Interface}{"Class"}) {
5893 $Func_Signature = get_TypeName($ClassId, $LibVersion)."::".(($CompleteSignature{$LibVersion}{$Interface}{"Destructor"})?"~":"").$ShortName;
5894 }
5895 elsif(my $NameSpace = $CompleteSignature{$LibVersion}{$Interface}{"NameSpace"}) {
5896 $Func_Signature = $NameSpace."::".$ShortName;
5897 }
5898 else {
5899 $Func_Signature = $ShortName;
5900 }
5901 @Param_Types_FromUnmangledName = get_s_params($tr_name{$MnglName}, 0);
5902 }
5903 else {
5904 $Func_Signature = $MnglName;
5905 }
5906 my @ParamArray = ();
5907 foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{$LibVersion}{$Interface}{"Param"}}))
5908 {
5909 next if($Pos eq "");
5910 my $ParamTypeId = $CompleteSignature{$LibVersion}{$Interface}{"Param"}{$Pos}{"type"};
5911 next if(not $ParamTypeId);
5912 my $ParamTypeName = get_TypeName($ParamTypeId, $LibVersion);
5913 if(not $ParamTypeName) {
5914 $ParamTypeName = $Param_Types_FromUnmangledName[$Pos];
5915 }
5916 foreach my $Typedef (keys(%ChangedTypedef))
5917 {
5918 my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
5919 $ParamTypeName=~s/(\A|\W)\Q$Typedef\E(\W|\Z)/$1$Base$2/g;
5920 }
5921 if(my $ParamName = $CompleteSignature{$LibVersion}{$Interface}{"Param"}{$Pos}{"name"}) {
5922 push(@ParamArray, create_member_decl($ParamTypeName, $ParamName));
5923 }
5924 else {
5925 push(@ParamArray, $ParamTypeName);
5926 }
5927 }
5928 if($CompleteSignature{$LibVersion}{$Interface}{"Data"}
5929 or $CompleteSignature{$LibVersion}{$Interface}{"Object"}) {
5930 $Func_Signature .= " [data]";
5931 }
5932 else
5933 {
5934 if(my $ChargeLevel = get_ChargeLevel($Interface, $LibVersion))
5935 { # add [in-charge]
5936 $Func_Signature .= " ".$ChargeLevel;
5937 }
5938 $Func_Signature .= " (".join(", ", @ParamArray).")";
5939 if($CompleteSignature{$LibVersion}{$Interface}{"Const"}
5940 or $Interface=~/\A_ZN(V|)K/) {
5941 $Func_Signature .= " const";
5942 }
5943 if($CompleteSignature{$LibVersion}{$Interface}{"Volatile"}
5944 or $Interface=~/\A_ZN(K|)V/) {
5945 $Func_Signature .= " volatile";
5946 }
5947 if($CompleteSignature{$LibVersion}{$Interface}{"Static"}
5948 and $Interface=~/\A(_Z|\?)/)
5949 {# for static methods
5950 $Func_Signature .= " [static]";
5951 }
5952 }
5953 if(defined $ShowRetVal
5954 and my $ReturnTId = $CompleteSignature{$LibVersion}{$Interface}{"Return"}) {
5955 $Func_Signature .= ":".get_TypeName($ReturnTId, $LibVersion);
5956 }
5957 if($SymbolVersion) {
5958 $Func_Signature .= $VersionSpec.$SymbolVersion;
5959 }
5960 return ($Cache{"get_Signature"}{$LibVersion}{$Interface} = $Func_Signature);
5961}
5962
5963sub create_member_decl($$)
5964{
5965 my ($TName, $Member) = @_;
5966 if($TName=~/\([\*]+\)/) {
5967 $TName=~s/\(([\*]+)\)/\($1$Member\)/;
5968 return $TName;
5969 }
5970 else
5971 {
5972 my @ArraySizes = ();
5973 while($TName=~s/(\[[^\[\]]*\])\Z//) {
5974 push(@ArraySizes, $1);
5975 }
5976 return $TName." ".$Member.join("", @ArraySizes);
5977 }
5978}
5979
5980sub getFuncType($)
5981{
5982 my $FuncInfo = $LibInfo{$Version}{"info"}{$_[0]};
5983 return "" if($FuncInfo!~/type[ ]*:[ ]*@(\d+) /);
5984 my $FuncTypeInfoId = $1;
5985 my $FunctionType = $LibInfo{$Version}{"info_type"}{$FuncTypeInfoId};
5986 if($FunctionType eq "method_type") {
5987 return "Method";
5988 }
5989 elsif($FunctionType eq "function_type") {
5990 return "Function";
5991 }
5992 else {
5993 return $FunctionType;
5994 }
5995}
5996
5997sub getFuncTypeId($)
5998{
5999 my $FuncInfo = $LibInfo{$Version}{"info"}{$_[0]};
6000 if($FuncInfo=~/type[ ]*:[ ]*@(\d+)( |\Z)/) {
6001 return $1;
6002 }
6003 else {
6004 return 0;
6005 }
6006}
6007
6008sub isNotAnon($) {
6009 return (not isAnon($_[0]));
6010}
6011
6012sub isAnon($)
6013{# "._N" or "$_N" in older GCC versions
6014 return ($_[0]=~/(\.|\$)\_\d+|anon\-/);
6015}
6016
6017sub unmangled_Compact($)
6018{ # Removes all non-essential (for C++ language) whitespace from a string. If
6019 # the whitespace is essential it will be replaced with exactly one ' '
6020 # character. Works correctly only for unmangled names.
6021 my $Name = $_[0];
6022 if(defined $Cache{"unmangled_Compact"}{$Name}) {
6023 return $Cache{"unmangled_Compact"}{$Name};
6024 }
6025 # First, we reduce all spaces that we can
6026 my $coms='[-()<>:*&~!|+=%@~"?.,/[^'."']";
6027 my $coms_nobr='[-()<:*&~!|+=%@~"?.,'."']";
6028 my $clos='[),;:\]]';
6029 $_ = $Name;
6030 s/^\s+//gm;
6031 s/\s+$//gm;
6032 s/((?!\n)\s)+/ /g;
6033 s/(\w+)\s+($coms+)/$1$2/gm;
6034 s/($coms+)\s+(\w+)/$1$2/gm;
6035 s/(\w)\s+($clos)/$1$2/gm;
6036 s/($coms+)\s+($coms+)/$1 $2/gm;
6037 s/($coms_nobr+)\s+($coms+)/$1$2/gm;
6038 s/($coms+)\s+($coms_nobr+)/$1$2/gm;
6039 # don't forget about >> and <:. In unmangled names global-scope modifier
6040 # is not used, so <: will always be a digraph and requires no special treatment.
6041 # We also try to remove other parts that are better to be removed here than in other places
6042 # double-cv
6043 s/\bconst\s+const\b/const/gm;
6044 s/\bvolatile\s+volatile\b/volatile/gm;
6045 s/\bconst\s+volatile\b\s+const\b/const volatile/gm;
6046 s/\bvolatile\s+const\b\s+volatile\b/const volatile/gm;
6047 # Place cv in proper order
6048 s/\bvolatile\s+const\b/const volatile/gm;
6049 return ($Cache{"unmangled_Compact"}{$Name} = $_);
6050}
6051
6052sub unmangled_PostProcess($)
6053{
6054 my $Name = $_[0];
6055 $_ = $Name;
6056 #s/\bunsigned int\b/unsigned/g;
6057 s/\bshort unsigned int\b/unsigned short/g;
6058 s/\bshort int\b/short/g;
6059 s/\blong long unsigned int\b/unsigned long long/g;
6060 s/\blong unsigned int\b/unsigned long/g;
6061 s/\blong long int\b/long long/g;
6062 s/\blong int\b/long/g;
6063 s/\)const\b/\) const/g;
6064 s/\blong long unsigned\b/unsigned long long/g;
6065 s/\blong unsigned\b/unsigned long/g;
6066 return $_;
6067}
6068
6069sub formatName($)
6070{# type name correction
6071 my $Name = $_[0];
6072 $Name=unmangled_Compact($Name);
6073 $Name=unmangled_PostProcess($Name);
6074 $Name=~s/>>/> >/g; # double templates
6075 $Name=~s/(operator\s*)> >/$1>>/;
6076 return $Name;
6077}
6078
6079sub get_HeaderDeps($$)
6080{
6081 my ($AbsPath, $LibVersion) = @_;
6082 return () if(not $AbsPath or not $LibVersion);
6083 if(defined $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}) {
6084 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
6085 }
6086 my %IncDir = ();
6087 detect_recursive_includes($AbsPath, $LibVersion);
6088 foreach my $HeaderPath (keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}))
6089 {
6090 next if(not $HeaderPath);
6091 next if($MAIN_CPP_DIR and $HeaderPath=~/\A\Q$MAIN_CPP_DIR\E([\/\\]|\Z)/);
6092 my $Dir = get_dirname($HeaderPath);
6093 foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$HeaderPath}}))
6094 {
6095 my $Dep = $Dir;
6096 if($Prefix)
6097 {
6098 if($OSgroup eq "windows")
6099 { # case insensitive seach on windows
6100 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//ig) {
6101 next;
6102 }
6103 }
6104 elsif($OSgroup eq "macos")
6105 { # seach in frameworks
6106 if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
6107 {
6108 if($HeaderPath=~/(.+\.framework)\/Headers\/([^\/]+)/)
6109 {# frameworks
6110 my ($HFramework, $HName) = ($1, $2);
6111 $Dep = $HFramework;
6112 }
6113 else
6114 {# mismatch
6115 next;
6116 }
6117 }
6118 }
6119 elsif(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
6120 { # Linux, FreeBSD
6121 next;
6122 }
6123 }
6124 if(not $Dep)
6125 { # nothing to include
6126 next;
6127 }
6128 if(is_default_include_dir($Dep))
6129 { # included by the compiler
6130 next;
6131 }
6132 if(get_depth($Dep)==1)
6133 { # too short
6134 next;
6135 }
6136 if(isLibcDir($Dep))
6137 { # do NOT include /usr/include/{sys,bits}
6138 next;
6139 }
6140 $IncDir{$Dep}=1;
6141 }
6142 }
6143 $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath} = sortIncPaths([keys(%IncDir)], $LibVersion);
6144 return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
6145}
6146
6147sub sortIncPaths($$)
6148{
6149 my ($ArrRef, $LibVersion) = @_;
6150 @{$ArrRef} = sort {$b cmp $a} @{$ArrRef};
6151 @{$ArrRef} = sort {get_depth($a)<=>get_depth($b)} @{$ArrRef};
6152 @{$ArrRef} = sort {$Header_Dependency{$LibVersion}{$b}<=>$Header_Dependency{$LibVersion}{$a}} @{$ArrRef};
6153 return $ArrRef;
6154}
6155
6156sub joinPath($$) {
6157 return join($SLASH, @_);
6158}
6159
6160sub get_namespace_additions($)
6161{
6162 my $NameSpaces = $_[0];
6163 my ($Additions, $AddNameSpaceId) = ("", 1);
6164 foreach my $NS (sort {$a=~/_/ <=> $b=~/_/} sort {lc($a) cmp lc($b)} keys(%{$NameSpaces}))
6165 {
6166 next if($SkipNameSpaces{$Version}{$NS});
6167 next if(not $NS or $NameSpaces->{$NS}==-1);
6168 next if($NS=~/(\A|::)iterator(::|\Z)/i);
6169 next if($NS=~/\A__/i);
6170 next if(($NS=~/\Astd::/ or $NS=~/\A(std|tr1|rel_ops|fcntl)\Z/) and not $STDCXX_TESTING);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006171 $NestedNameSpaces{$Version}{$NS} = 1; # for future use in reports
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006172 my ($TypeDecl_Prefix, $TypeDecl_Suffix) = ();
6173 my @NS_Parts = split(/::/, $NS);
6174 next if($#NS_Parts==-1);
6175 next if($NS_Parts[0]=~/\A(random|or)\Z/);
6176 foreach my $NS_Part (@NS_Parts)
6177 {
6178 $TypeDecl_Prefix .= "namespace $NS_Part\{";
6179 $TypeDecl_Suffix .= "}";
6180 }
6181 my $TypeDecl = $TypeDecl_Prefix."typedef int tmp_add_type_$AddNameSpaceId;".$TypeDecl_Suffix;
6182 my $FuncDecl = "$NS\:\:tmp_add_type_$AddNameSpaceId tmp_add_func_$AddNameSpaceId(){return 0;};";
6183 $Additions.=" $TypeDecl\n $FuncDecl\n";
6184 $AddNameSpaceId+=1;
6185 }
6186 return $Additions;
6187}
6188
6189sub path_format($$)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006190{ # forward slash to pass into MinGW GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006191 my ($Path, $Fmt) = @_;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006192 if($Fmt eq "windows")
6193 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006194 $Path=~s/\//\\/g;
6195 $Path=lc($Path);
6196 }
6197 else {
6198 $Path=~s/\\/\//g;
6199 }
6200 return $Path;
6201}
6202
6203sub inc_opt($$)
6204{
6205 my ($Path, $Style) = @_;
6206 if($Style eq "GCC")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006207 { # GCC options
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006208 if($OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006209 { # to MinGW GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006210 return "-I\"".path_format($Path, "unix")."\"";
6211 }
6212 elsif($OSgroup eq "macos"
6213 and $Path=~/\.framework\Z/)
6214 {# to Apple's GCC
6215 return "-F".esc(get_dirname($Path));
6216 }
6217 else {
6218 return "-I".esc($Path);
6219 }
6220 }
6221 elsif($Style eq "CL") {
6222 return "/I \"$Path\"";
6223 }
6224 return "";
6225}
6226
6227sub platformSpecs($)
6228{
6229 my $LibVersion = $_[0];
6230 my $Arch = getArch($LibVersion);
6231 if($OStarget eq "symbian")
6232 { # options for GCCE compiler
6233 my %Symbian_Opts = map {$_=>1} (
6234 "-D__GCCE__",
6235 "-DUNICODE",
6236 "-fexceptions",
6237 "-D__SYMBIAN32__",
6238 "-D__MARM_INTERWORK__",
6239 "-D_UNICODE",
6240 "-D__S60_50__",
6241 "-D__S60_3X__",
6242 "-D__SERIES60_3X__",
6243 "-D__EPOC32__",
6244 "-D__MARM__",
6245 "-D__EABI__",
6246 "-D__MARM_ARMV5__",
6247 "-D__SUPPORT_CPP_EXCEPTIONS__",
6248 "-march=armv5t",
6249 "-mapcs",
6250 "-mthumb-interwork",
6251 "-DEKA2",
6252 "-DSYMBIAN_ENABLE_SPLIT_HEADERS"
6253 );
6254 return join(" ", keys(%Symbian_Opts));
6255 }
6256 elsif($OSgroup eq "windows"
6257 and get_dumpmachine($GCC_PATH)=~/mingw/i)
6258 { # add options to MinGW compiler
6259 # to simulate the MSVC compiler
6260 my %MinGW_Opts = map {$_=>1} (
6261 "-D_WIN32",
6262 "-D_STDCALL_SUPPORTED",
6263 "-D__int64=\"long long\"",
6264 "-D__int32=int",
6265 "-D__int16=short",
6266 "-D__int8=char",
6267 "-D__possibly_notnullterminated=\" \"",
6268 "-D__nullterminated=\" \"",
6269 "-D__nullnullterminated=\" \"",
6270 "-D__w64=\" \"",
6271 "-D__ptr32=\" \"",
6272 "-D__ptr64=\" \"",
6273 "-D__forceinline=inline",
6274 "-D__inline=inline",
6275 "-D__uuidof(x)=IID()",
6276 "-D__try=",
6277 "-D__except(x)=",
6278 "-D__declspec(x)=__attribute__((x))",
6279 "-D__pragma(x)=",
6280 "-D_inline=inline",
6281 "-D__forceinline=__inline",
6282 "-D__stdcall=__attribute__((__stdcall__))",
6283 "-D__cdecl=__attribute__((__cdecl__))",
6284 "-D__fastcall=__attribute__((__fastcall__))",
6285 "-D__thiscall=__attribute__((__thiscall__))",
6286 "-D_stdcall=__attribute__((__stdcall__))",
6287 "-D_cdecl=__attribute__((__cdecl__))",
6288 "-D_fastcall=__attribute__((__fastcall__))",
6289 "-D_thiscall=__attribute__((__thiscall__))",
6290 "-DSHSTDAPI_(x)=x",
6291 "-D_MSC_EXTENSIONS",
6292 "-DSECURITY_WIN32",
6293 "-D_MSC_VER=1500",
6294 "-D_USE_DECLSPECS_FOR_SAL",
6295 "-D__noop=\" \"",
6296 "-DDECLSPEC_DEPRECATED=\" \"",
6297 "-D__builtin_alignof(x)=__alignof__(x)",
6298 "-DSORTPP_PASS");
6299 if($Arch eq "x86") {
6300 $MinGW_Opts{"-D_M_IX86=300"}=1;
6301 }
6302 elsif($Arch eq "x86_64") {
6303 $MinGW_Opts{"-D_M_AMD64=300"}=1;
6304 }
6305 elsif($Arch eq "ia64") {
6306 $MinGW_Opts{"-D_M_IA64=300"}=1;
6307 }
6308 return join(" ", keys(%MinGW_Opts));
6309 }
6310 return "";
6311}
6312
6313my %C_Structure = map {$_=>1} (
6314# FIXME: Can't separate union and struct data types before dumping,
6315# so it sometimes cause compilation errors for unknown reason
6316# when trying to declare TYPE* tmp_add_class_N
6317# This is a list of such structures + list of other C structures
6318 "sigval",
6319 "sigevent",
6320 "sigaction",
6321 "sigvec",
6322 "sigstack",
6323 "timeval",
6324 "timezone",
6325 "rusage",
6326 "rlimit",
6327 "wait",
6328 "flock",
6329 "stat",
6330 "_stat",
6331 "stat32",
6332 "_stat32",
6333 "stat64",
6334 "_stat64",
6335 "_stati64",
6336 "if_nameindex",
6337 "usb_device",
6338 "sigaltstack",
6339 "sysinfo",
6340 "timeLocale",
6341 "tcp_debug",
6342 "rpc_createerr",
6343# Other C structures appearing in every dump
6344 "timespec",
6345 "random_data",
6346 "drand48_data",
6347 "_IO_marker",
6348 "_IO_FILE",
6349 "lconv",
6350 "sched_param",
6351 "tm",
6352 "itimerspec",
6353 "_pthread_cleanup_buffer",
6354 "fd_set",
6355 "siginfo"
6356);
6357
6358sub getCompileCmd($$$)
6359{
6360 my ($Path, $Opt, $Inc) = @_;
6361 my $GccCall = $GCC_PATH;
6362 if($Opt) {
6363 $GccCall .= " ".$Opt;
6364 }
6365 $GccCall .= " -x ";
6366 if($OSgroup eq "macos") {
6367 $GccCall .= "objective-";
6368 }
6369 if(check_gcc_version($GCC_PATH, "4"))
6370 { # compile as "C++" header
6371 # to obtain complete dump using GCC 4.0
6372 $GccCall .= "c++-header";
6373 }
6374 else
6375 { # compile as "C++" source
6376 # GCC 3.3 cannot compile headers
6377 $GccCall .= "c++";
6378 }
6379 if(my $Opts = platformSpecs($Version))
6380 {# platform-specific options
6381 $GccCall .= " ".$Opts;
6382 }
6383 # allow extra qualifications
6384 # and other nonconformant code
6385 $GccCall .= " -fpermissive -w";
6386 if($NoStdInc)
6387 {
6388 $GccCall .= " -nostdinc";
6389 $GccCall .= " -nostdinc++";
6390 }
6391 if($CompilerOptions{$Version})
6392 { # user-defined options
6393 $GccCall .= " ".$CompilerOptions{$Version};
6394 }
6395 $GccCall .= " \"$Path\"";
6396 if($Inc)
6397 { # include paths
6398 $GccCall .= " ".$Inc;
6399 }
6400 return $GccCall;
6401}
6402
6403sub getDump()
6404{
6405 if(not $GCC_PATH) {
6406 exitStatus("Error", "internal error - GCC path is not set");
6407 }
6408 my %HeaderElems = (
6409 # Types
6410 "stdio.h" => ["FILE", "va_list"],
6411 "stddef.h" => ["NULL"],
6412 "stdint.h" => ["uint32_t", "int32_t", "uint64_t"],
6413 "time.h" => ["time_t"],
6414 "sys/types.h" => ["ssize_t", "u_int32_t", "u_short", "u_char",
6415 "u_int", "off_t", "u_quad_t", "u_long", "size_t", "mode_t"],
6416 "unistd.h" => ["gid_t", "uid_t"],
6417 "stdbool.h" => ["_Bool"],
6418 "rpc/xdr.h" => ["bool_t"],
6419 "in_systm.h" => ["n_long", "n_short"],
6420 # Fields
Andrey Ponomarenkobede8372012-03-29 17:43:21 +04006421 "arpa/inet.h" => ["fw_src", "ip_src"],
6422 # Functions
6423 "stdlib.h" => ["free", "malloc"],
6424 "string.h" => ["memmove"]
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006425 );
6426 my %AutoPreamble = ();
6427 foreach (keys(%HeaderElems)) {
6428 foreach my $Elem (@{$HeaderElems{$_}}) {
6429 $AutoPreamble{$Elem}=$_;
6430 }
6431 }
6432 my $TmpHeaderPath = "$TMP_DIR/dump$Version.h";
6433 my $MHeaderPath = $TmpHeaderPath;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04006434 open(LIB_HEADER, ">", $TmpHeaderPath) || die ("can't open file \'$TmpHeaderPath\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006435 if(my $AddDefines = $Descriptor{$Version}{"Defines"})
6436 {
6437 $AddDefines=~s/\n\s+/\n /g;
6438 print LIB_HEADER "\n // add defines\n ".$AddDefines."\n";
6439 }
6440 print LIB_HEADER "\n // add includes\n";
6441 my @PreambleHeaders = keys(%{$Include_Preamble{$Version}});
6442 @PreambleHeaders = sort {int($Include_Preamble{$Version}{$a}{"Position"})<=>int($Include_Preamble{$Version}{$b}{"Position"})} @PreambleHeaders;
6443 foreach my $Header_Path (@PreambleHeaders) {
6444 print LIB_HEADER " #include \"".path_format($Header_Path, "unix")."\"\n";
6445 }
6446 my @Headers = keys(%{$Registered_Headers{$Version}});
6447 @Headers = sort {int($Registered_Headers{$Version}{$a}{"Pos"})<=>int($Registered_Headers{$Version}{$b}{"Pos"})} @Headers;
6448 foreach my $Header_Path (@Headers)
6449 {
6450 next if($Include_Preamble{$Version}{$Header_Path});
6451 print LIB_HEADER " #include \"".path_format($Header_Path, "unix")."\"\n";
6452 }
6453 close(LIB_HEADER);
6454 my $IncludeString = getIncString(getIncPaths(@PreambleHeaders, @Headers), "GCC");
6455 if($Debug)
6456 { # debug mode
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006457 writeFile($DEBUG_PATH{$Version}."/headers/direct-includes.txt", Dumper(\%Header_Includes));
6458 writeFile($DEBUG_PATH{$Version}."/headers/recursive-includes.txt", Dumper(\%RecursiveIncludes));
6459 writeFile($DEBUG_PATH{$Version}."/headers/include-paths.txt", Dumper($Cache{"get_HeaderDeps"}));
6460 writeFile($DEBUG_PATH{$Version}."/headers/default-paths.txt", Dumper(\%DefaultIncPaths));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006461 }
6462 # preprocessing stage
6463 checkPreprocessedUnit(callPreprocessor($TmpHeaderPath, $IncludeString, $Version));
6464 my $MContent = "";
6465 my $PreprocessCmd = getCompileCmd($TmpHeaderPath, "-E", $IncludeString);
6466 if($OStarget eq "windows"
6467 and get_dumpmachine($GCC_PATH)=~/mingw/i
6468 and $MinGWMode{$Version}!=-1)
6469 { # modify headers to compile by MinGW
6470 if(not $MContent)
6471 { # preprocessing
6472 $MContent = `$PreprocessCmd 2>$TMP_DIR/null`;
6473 }
6474 if($MContent=~s/__asm\s*(\{[^{}]*?\}|[^{};]*)//g)
6475 { # __asm { ... }
6476 $MinGWMode{$Version}=1;
6477 }
6478 if($MContent=~s/\s+(\/ \/.*?)\n/\n/g)
6479 { # comments after preprocessing
6480 $MinGWMode{$Version}=1;
6481 }
6482 if($MContent=~s/(\W)(0x[a-f]+|\d+)(i|ui)(8|16|32|64)(\W)/$1$2$5/g)
6483 { # 0xffui8
6484 $MinGWMode{$Version}=1;
6485 }
6486 if($MinGWMode{$Version}) {
6487 printMsg("INFO", "Using MinGW compatibility mode");
6488 $MHeaderPath = "$TMP_DIR/dump$Version.i";
6489 }
6490 }
6491 if(($COMMON_LANGUAGE{$Version} eq "C" or $CheckHeadersOnly)
6492 and $C99Mode{$Version}!=-1 and not $Cpp2003)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006493 { # rename C++ keywords in C code
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006494 if(not $MContent)
6495 { # preprocessing
6496 $MContent = `$PreprocessCmd 2>$TMP_DIR/null`;
6497 }
6498 my $RegExp_C = join("|", keys(%CppKeywords_C));
6499 my $RegExp_F = join("|", keys(%CppKeywords_F));
6500 my $RegExp_O = join("|", keys(%CppKeywords_O));
6501 while($MContent=~s/(\A|\n[^\#\/\n][^\n]*?|\n)(\*\s*|\s+|\@|\,|\()($RegExp_C|$RegExp_F)(\s*(\,|\)|\;|\-\>|\.|\:\s*\d))/$1$2c99_$3$4/g)
6502 { # MATCH:
6503 # int foo(int new, int class, int (*new)(int));
6504 # unsigned private: 8;
6505 # DO NOT MATCH:
6506 # #pragma GCC visibility push(default)
6507 $C99Mode{$Version} = 1;
6508 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006509 if($MContent=~s/([^\w\s]|\w\s+)(?<!operator )(delete)(\s*\()/$1c99_$2$3/g)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006510 { # MATCH:
6511 # int delete(...);
6512 # int explicit(...);
6513 # DO NOT MATCH:
6514 # void operator delete(...)
6515 $C99Mode{$Version} = 1;
6516 }
6517 if($MContent=~s/(\s+)($RegExp_O)(\s*(\;|\:))/$1c99_$2$3/g)
6518 { # MATCH:
6519 # int bool;
6520 # DO NOT MATCH:
6521 # bool X;
6522 # return *this;
6523 # throw;
6524 $C99Mode{$Version} = 1;
6525 }
6526 if($MContent=~s/(\s+)(operator)(\s*(\(\s*\)\s*[^\(\s]|\(\s*[^\)\s]))/$1c99_$2$3/g)
6527 { # MATCH:
6528 # int operator(...);
6529 # DO NOT MATCH:
6530 # int operator()(...);
6531 $C99Mode{$Version} = 1;
6532 }
6533 if($MContent=~s/([^\w\(\,\s]\s*|\s+)(operator)(\s*(\,\s*[^\(\s]|\)))/$1c99_$2$3/g)
6534 { # MATCH:
6535 # int foo(int operator);
6536 # int foo(int operator, int other);
6537 # DO NOT MATCH:
6538 # int operator,(...);
6539 $C99Mode{$Version} = 1;
6540 }
6541 if($MContent=~s/(\*\s*|\w\s+)(bool)(\s*(\,|\)))/$1c99_$2$3/g)
6542 { # MATCH:
6543 # int foo(gboolean *bool);
6544 # DO NOT MATCH:
6545 # void setTabEnabled(int index, bool);
6546 $C99Mode{$Version} = 1;
6547 }
6548 if($MContent=~s/(\w)([^\w\(\,\s]\s*|\s+)(this)(\s*(\,|\)))/$1$2c99_$3$4/g)
6549 { # MATCH:
6550 # int foo(int* this);
6551 # int bar(int this);
6552 # DO NOT MATCH:
6553 # baz(X, this);
6554 $C99Mode{$Version} = 1;
6555 }
6556 if($C99Mode{$Version}==1)
6557 { # try to change C++ "keyword" to "c99_keyword"
6558 printMsg("INFO", "Using C99 compatibility mode");
6559 $MHeaderPath = "$TMP_DIR/dump$Version.i";
6560 }
6561 }
6562 if($C99Mode{$Version}==1
6563 or $MinGWMode{$Version}==1)
6564 { # compile the corrected preprocessor output
6565 writeFile($MHeaderPath, $MContent);
6566 }
6567 if($COMMON_LANGUAGE{$Version} eq "C++")
6568 { # add classes and namespaces to the dump
6569 my $CHdump = "-fdump-class-hierarchy -c";
6570 if($C99Mode{$Version}==1
6571 or $MinGWMode{$Version}==1) {
6572 $CHdump .= " -fpreprocessed";
6573 }
6574 my $ClassHierarchyCmd = getCompileCmd($MHeaderPath, $CHdump, $IncludeString);
6575 chdir($TMP_DIR);
6576 system("$ClassHierarchyCmd >null 2>&1");
6577 chdir($ORIG_DIR);
6578 if(my $ClassDump = (cmd_find($TMP_DIR,"f","*.class",1))[0])
6579 {
6580 my %AddClasses = ();
6581 my $Content = readFile($ClassDump);
6582 foreach my $ClassInfo (split(/\n\n/, $Content))
6583 {
6584 if($ClassInfo=~/\AClass\s+(.+)\s*/i)
6585 {
6586 my $CName = $1;
6587 next if($CName=~/\A(__|_objc_|_opaque_)/);
6588 $TUnit_NameSpaces{$Version}{$CName} = -1;
6589 if($CName=~/\A[\w:]+\Z/)
6590 { # classes
6591 $AddClasses{$CName} = 1;
6592 }
6593 if($CName=~/(\w[\w:]*)::/)
6594 { # namespaces
6595 my $NS = $1;
6596 if(not defined $TUnit_NameSpaces{$Version}{$NS}) {
6597 $TUnit_NameSpaces{$Version}{$NS} = 1;
6598 }
6599 }
6600 }
6601 elsif($ClassInfo=~/\AVtable\s+for\s+(.+)\n((.|\n)+)\Z/i)
6602 { # read v-tables (advanced approach)
6603 my ($CName, $VTable) = ($1, $2);
6604 $ClassVTable_Content{$Version}{$CName} = $VTable;
6605 }
6606 }
6607 if($Debug)
6608 { # debug mode
6609 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006610 copy($ClassDump, $DEBUG_PATH{$Version}."/class-hierarchy-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006611 }
6612 unlink($ClassDump);
6613 if(my $NS_Add = get_namespace_additions($TUnit_NameSpaces{$Version}))
6614 { # GCC on all supported platforms does not include namespaces to the dump by default
6615 appendFile($MHeaderPath, "\n // add namespaces\n".$NS_Add);
6616 }
6617 # some GCC versions don't include class methods to the TU dump by default
6618 my ($AddClass, $ClassNum) = ("", 0);
6619 foreach my $CName (sort keys(%AddClasses))
6620 {
6621 next if($C_Structure{$CName});
6622 next if(not $STDCXX_TESTING and $CName=~/\Astd::/);
6623 next if(($CName=~tr![:]!!)>2);
6624 next if($SkipTypes{$Version}{$CName});
6625 if($CName=~/\A(.+)::[^:]+\Z/
6626 and $AddClasses{$1}) {
6627 next;
6628 }
6629 $AddClass .= " $CName* tmp_add_class_".($ClassNum++).";\n";
6630 }
6631 appendFile($MHeaderPath, "\n // add classes\n".$AddClass);
6632 }
6633 }
6634 writeLog($Version, "Temporary header file \'$TmpHeaderPath\' with the following content will be compiled to create GCC translation unit dump:\n".readFile($TmpHeaderPath)."\n");
6635 # create TU dump
6636 my $TUdump = "-fdump-translation-unit -fkeep-inline-functions -c";
6637 if($C99Mode{$Version}==1
6638 or $MinGWMode{$Version}==1) {
6639 $TUdump .= " -fpreprocessed";
6640 }
6641 my $SyntaxTreeCmd = getCompileCmd($MHeaderPath, $TUdump, $IncludeString);
6642 writeLog($Version, "The GCC parameters:\n $SyntaxTreeCmd\n\n");
6643 chdir($TMP_DIR);
6644 system($SyntaxTreeCmd." >$TMP_DIR/tu_errors 2>&1");
6645 if($?)
6646 { # failed to compile, but the TU dump still can be created
6647 my $Errors = readFile("$TMP_DIR/tu_errors");
6648 if($Errors=~/c99_/)
6649 { # disable c99 mode
6650 $C99Mode{$Version}=-1;
6651 printMsg("INFO", "Disabling C99 compatibility mode");
6652 resetLogging($Version);
6653 $TMP_DIR = tempdir(CLEANUP=>1);
6654 return getDump();
6655 }
6656 elsif($AutoPreambleMode{$Version}!=-1
6657 and my $TErrors = $Errors)
6658 {
6659 my %Types = ();
6660 while($TErrors=~s/error\:\s*(field\s*|)\W+(.+?)\W+//)
6661 { # error: 'FILE' has not been declared
6662 $Types{$2}=1;
6663 }
6664 my %AddHeaders = ();
6665 foreach my $Type (keys(%Types))
6666 {
6667 if(my $Header = $AutoPreamble{$Type}) {
6668 $AddHeaders{path_format($Header, $OSgroup)}=$Type;
6669 }
6670 }
6671 if(my @Headers = sort {$b cmp $a} keys(%AddHeaders))
6672 { # sys/types.h should be the first
6673 foreach my $Num (0 .. $#Headers)
6674 {
6675 my $Name = $Headers[$Num];
6676 if(my $Path = identify_header($Name, $Version))
6677 { # add automatic preamble headers
6678 if(defined $Include_Preamble{$Version}{$Path})
6679 { # already added
6680 next;
6681 }
6682 $Include_Preamble{$Version}{$Path}{"Position"} = keys(%{$Include_Preamble{$Version}});
6683 my $Type = $AddHeaders{$Name};
6684 printMsg("INFO", "Add \'$Name\' preamble header for \'$Type\'");
6685 }
6686 }
6687 $AutoPreambleMode{$Version}=-1;
6688 resetLogging($Version);
6689 $TMP_DIR = tempdir(CLEANUP=>1);
6690 return getDump();
6691 }
6692 }
6693 elsif($MinGWMode{$Version}!=-1)
6694 {
6695 $MinGWMode{$Version}=-1;
6696 resetLogging($Version);
6697 $TMP_DIR = tempdir(CLEANUP=>1);
6698 return getDump();
6699 }
6700 # FIXME: handle other errors and try to recompile
6701 writeLog($Version, $Errors);
6702 printMsg("ERROR", "some errors occurred when compiling headers");
6703 printErrorLog($Version);
6704 $COMPILE_ERRORS = $ERROR_CODE{"Compile_Error"};
6705 writeLog($Version, "\n");# new line
6706 }
6707 chdir($ORIG_DIR);
6708 unlink($TmpHeaderPath, $MHeaderPath);
6709 return (cmd_find($TMP_DIR,"f","*.tu",1))[0];
6710}
6711
6712sub cmd_file($)
6713{
6714 my $Path = $_[0];
6715 return "" if(not $Path or not -e $Path);
6716 if(my $CmdPath = get_CmdPath("file")) {
6717 return `$CmdPath -b \"$Path\"`;
6718 }
6719 return "";
6720}
6721
6722sub getIncString($$)
6723{
6724 my ($ArrRef, $Style) = @_;
6725 return if(not $ArrRef or $#{$ArrRef}<0);
6726 my $String = "";
6727 foreach (@{$ArrRef}) {
6728 $String .= " ".inc_opt($_, $Style);
6729 }
6730 return $String;
6731}
6732
6733sub getIncPaths(@)
6734{
6735 my @HeaderPaths = @_;
6736 my @IncPaths = ();
6737 if($INC_PATH_AUTODETECT{$Version})
6738 { # auto-detecting dependencies
6739 my %Includes = ();
6740 foreach my $HPath (@HeaderPaths)
6741 {
6742 foreach my $Dir (get_HeaderDeps($HPath, $Version))
6743 {
6744 if($Skip_Include_Paths{$Version}{$Dir}) {
6745 next;
6746 }
6747 $Includes{$Dir}=1;
6748 }
6749 }
6750 foreach my $Dir (keys(%{$Add_Include_Paths{$Version}}))
6751 { # added by user
6752 next if($Includes{$Dir});
6753 push(@IncPaths, $Dir);
6754 }
6755 foreach my $Dir (@{sortIncPaths([keys(%Includes)], $Version)}) {
6756 push(@IncPaths, $Dir);
6757 }
6758 }
6759 else
6760 { # user-defined paths
6761 foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
6762 sort {$b cmp $a} keys(%{$Include_Paths{$Version}})) {
6763 push(@IncPaths, $Dir);
6764 }
6765 }
6766 return \@IncPaths;
6767}
6768
6769sub callPreprocessor($$$)
6770{
6771 my ($Path, $Inc, $LibVersion) = @_;
6772 return "" if(not $Path or not -f $Path);
6773 my $IncludeString=$Inc;
6774 if(not $Inc) {
6775 $IncludeString = getIncString(getIncPaths($Path), "GCC");
6776 }
6777 my $Cmd = getCompileCmd($Path, "-dD -E", $IncludeString);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006778 my $Out = "$TMP_DIR/preprocessed";
6779 system("$Cmd >$Out 2>$TMP_DIR/null");
6780 return $Out;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006781}
6782
6783sub cmd_find($$$$)
6784{ # native "find" is much faster than File::Find (~6x)
6785 # also the File::Find doesn't support --maxdepth N option
6786 # so using the cross-platform wrapper for the native one
6787 my ($Path, $Type, $Name, $MaxDepth) = @_;
6788 return () if(not $Path or not -e $Path);
6789 if($OSgroup eq "windows")
6790 {
6791 my $DirCmd = get_CmdPath("dir");
6792 if(not $DirCmd) {
6793 exitStatus("Not_Found", "can't find \"dir\" command");
6794 }
6795 $Path=~s/[\\]+\Z//;
6796 $Path = get_abs_path($Path);
6797 $Path = path_format($Path, $OSgroup);
6798 my $Cmd = $DirCmd." \"$Path\" /B /O";
6799 if($MaxDepth!=1) {
6800 $Cmd .= " /S";
6801 }
6802 if($Type eq "d") {
6803 $Cmd .= " /AD";
6804 }
6805 my @Files = ();
6806 if($Name)
6807 { # FIXME: how to search file names in MS shell?
6808 $Name=~s/\*/.*/g if($Name!~/\]/);
6809 foreach my $File (split(/\n/, `$Cmd`))
6810 {
6811 if($File=~/$Name\Z/i) {
6812 push(@Files, $File);
6813 }
6814 }
6815 }
6816 else {
6817 @Files = split(/\n/, `$Cmd 2>$TMP_DIR/null`);
6818 }
6819 my @AbsPaths = ();
6820 foreach my $File (@Files)
6821 {
6822 if(not is_abs($File)) {
6823 $File = joinPath($Path, $File);
6824 }
6825 if($Type eq "f" and not -f $File)
6826 { # skip dirs
6827 next;
6828 }
6829 push(@AbsPaths, path_format($File, $OSgroup));
6830 }
6831 if($Type eq "d") {
6832 push(@AbsPaths, $Path);
6833 }
6834 return @AbsPaths;
6835 }
6836 else
6837 {
6838 my $FindCmd = get_CmdPath("find");
6839 if(not $FindCmd) {
6840 exitStatus("Not_Found", "can't find a \"find\" command");
6841 }
6842 $Path = get_abs_path($Path);
6843 if(-d $Path and -l $Path
6844 and $Path!~/\/\Z/)
6845 { # for directories that are symlinks
6846 $Path.="/";
6847 }
6848 my $Cmd = $FindCmd." \"$Path\"";
6849 if($MaxDepth) {
6850 $Cmd .= " -maxdepth $MaxDepth";
6851 }
6852 if($Type) {
6853 $Cmd .= " -type $Type";
6854 }
6855 if($Name)
6856 { # file name
6857 if($Name=~/\]/) {
6858 $Cmd .= " -regex \"$Name\"";
6859 }
6860 else {
6861 $Cmd .= " -name \"$Name\"";
6862 }
6863 }
6864 return split(/\n/, `$Cmd 2>$TMP_DIR/null`);
6865 }
6866}
6867
6868sub unpackDump($)
6869{
6870 my $Path = $_[0];
6871 return "" if(not $Path or not -e $Path);
6872 $Path = get_abs_path($Path);
6873 $Path = path_format($Path, $OSgroup);
6874 my ($Dir, $FileName) = separate_path($Path);
6875 my $UnpackDir = $TMP_DIR."/unpack";
6876 rmtree($UnpackDir);
6877 mkpath($UnpackDir);
6878 if($FileName=~s/\Q.zip\E\Z//g)
6879 { # *.zip
6880 my $UnzipCmd = get_CmdPath("unzip");
6881 if(not $UnzipCmd) {
6882 exitStatus("Not_Found", "can't find \"unzip\" command");
6883 }
6884 chdir($UnpackDir);
6885 system("$UnzipCmd \"$Path\" >$UnpackDir/contents.txt");
6886 if($?) {
6887 exitStatus("Error", "can't extract \'$Path\'");
6888 }
6889 chdir($ORIG_DIR);
6890 my @Contents = ();
6891 foreach (split("\n", readFile("$UnpackDir/contents.txt")))
6892 {
6893 if(/inflating:\s*([^\s]+)/) {
6894 push(@Contents, $1);
6895 }
6896 }
6897 if(not @Contents) {
6898 exitStatus("Error", "can't extract \'$Path\'");
6899 }
6900 return joinPath($UnpackDir, $Contents[0]);
6901 }
6902 elsif($FileName=~s/\Q.tar.gz\E\Z//g)
6903 { # *.tar.gz
6904 if($OSgroup eq "windows")
6905 { # -xvzf option is not implemented in tar.exe (2003)
6906 # use "gzip.exe -k -d -f" + "tar.exe -xvf" instead
6907 my $TarCmd = get_CmdPath("tar");
6908 if(not $TarCmd) {
6909 exitStatus("Not_Found", "can't find \"tar\" command");
6910 }
6911 my $GzipCmd = get_CmdPath("gzip");
6912 if(not $GzipCmd) {
6913 exitStatus("Not_Found", "can't find \"gzip\" command");
6914 }
6915 chdir($UnpackDir);
6916 system("$GzipCmd -k -d -f \"$Path\"");# keep input files (-k)
6917 if($?) {
6918 exitStatus("Error", "can't extract \'$Path\'");
6919 }
6920 system("$TarCmd -xvf \"$Dir\\$FileName.tar\" >$UnpackDir/contents.txt");
6921 if($?) {
6922 exitStatus("Error", "can't extract \'$Path\'");
6923 }
6924 chdir($ORIG_DIR);
6925 unlink($Dir."/".$FileName.".tar");
6926 my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
6927 if(not @Contents) {
6928 exitStatus("Error", "can't extract \'$Path\'");
6929 }
6930 return joinPath($UnpackDir, $Contents[0]);
6931 }
6932 else
6933 { # Unix
6934 my $TarCmd = get_CmdPath("tar");
6935 if(not $TarCmd) {
6936 exitStatus("Not_Found", "can't find \"tar\" command");
6937 }
6938 chdir($UnpackDir);
6939 system("$TarCmd -xvzf \"$Path\" >$UnpackDir/contents.txt");
6940 if($?) {
6941 exitStatus("Error", "can't extract \'$Path\'");
6942 }
6943 chdir($ORIG_DIR);
6944 # The content file name may be different
6945 # from the package file name
6946 my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
6947 if(not @Contents) {
6948 exitStatus("Error", "can't extract \'$Path\'");
6949 }
6950 return joinPath($UnpackDir, $Contents[0]);
6951 }
6952 }
6953}
6954
6955sub createArchive($$)
6956{
6957 my ($Path, $To) = @_;
6958 if(not $Path or not -e $Path
6959 or not -d $To) {
6960 return "";
6961 }
6962 my ($From, $Name) = separate_path($Path);
6963 if($OSgroup eq "windows")
6964 { # *.zip
6965 my $ZipCmd = get_CmdPath("zip");
6966 if(not $ZipCmd) {
6967 exitStatus("Not_Found", "can't find \"zip\"");
6968 }
6969 my $Pkg = $To."/".$Name.".zip";
6970 unlink($Pkg);
6971 chdir($To);
6972 system("$ZipCmd -j \"$Name.zip\" \"$Path\" >$TMP_DIR/null");
6973 if($?)
6974 { # cannot allocate memory (or other problems with "zip")
6975 unlink($Path);
6976 exitStatus("Error", "can't pack the ABI dump: ".$!);
6977 }
6978 chdir($ORIG_DIR);
6979 unlink($Path);
6980 return $Pkg;
6981 }
6982 else
6983 { # *.tar.gz
6984 my $TarCmd = get_CmdPath("tar");
6985 if(not $TarCmd) {
6986 exitStatus("Not_Found", "can't find \"tar\"");
6987 }
6988 my $GzipCmd = get_CmdPath("gzip");
6989 if(not $GzipCmd) {
6990 exitStatus("Not_Found", "can't find \"gzip\"");
6991 }
6992 my $Pkg = abs_path($To)."/".$Name.".tar.gz";
6993 unlink($Pkg);
6994 chdir($From);
6995 system($TarCmd, "-czf", $Pkg, $Name);
6996 if($?)
6997 { # cannot allocate memory (or other problems with "tar")
6998 unlink($Path);
6999 exitStatus("Error", "can't pack the ABI dump: ".$!);
7000 }
7001 chdir($ORIG_DIR);
7002 unlink($Path);
7003 return $To."/".$Name.".tar.gz";
7004 }
7005}
7006
7007sub is_header_file($)
7008{
7009 if($_[0]=~/\.($HEADER_EXT)\Z/i) {
7010 return $_[0];
7011 }
7012 return 0;
7013}
7014
7015sub is_not_header($)
7016{
7017 if($_[0]=~/\.\w+\Z/
7018 and $_[0]!~/\.($HEADER_EXT)\Z/i) {
7019 return 1;
7020 }
7021 return 0;
7022}
7023
7024sub is_header($$$)
7025{
7026 my ($Header, $UserDefined, $LibVersion) = @_;
7027 return 0 if(-d $Header);
7028 if(-f $Header) {
7029 $Header = get_abs_path($Header);
7030 }
7031 else
7032 {
7033 if(is_abs($Header))
7034 { # incorrect absolute path
7035 return 0;
7036 }
7037 if(my $HPath = identify_header($Header, $LibVersion)) {
7038 $Header = $HPath;
7039 }
7040 else
7041 { # can't find header
7042 return 0;
7043 }
7044 }
7045 if($Header=~/\.\w+\Z/)
7046 { # have an extension
7047 return is_header_file($Header);
7048 }
7049 else
7050 {
7051 if($UserDefined==2)
7052 { # specified on the command line
7053 if(cmd_file($Header)!~/HTML|XML/i) {
7054 return $Header;
7055 }
7056 }
7057 elsif($UserDefined)
7058 { # specified in the XML-descriptor
7059 # header file without an extension
7060 return $Header;
7061 }
7062 else
7063 {
7064 if(cmd_file($Header)=~/C[\+]*\s+program/i)
7065 { # !~/HTML|XML|shared|dynamic/i
7066 return $Header;
7067 }
7068 }
7069 }
7070 return 0;
7071}
7072
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007073sub addTargetHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007074{
7075 my $LibVersion = $_[0];
7076 foreach my $RegHeader (keys(%{$Registered_Headers{$LibVersion}}))
7077 {
7078 my $RegDir = get_dirname($RegHeader);
7079 $TargetHeaders{$LibVersion}{get_filename($RegHeader)}=1;
7080 foreach my $RecInc (keys(%{$RecursiveIncludes{$LibVersion}{$RegHeader}}))
7081 {
7082 my $Dir = get_dirname($RecInc);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007083 if($Dir=~/\A\Q$RegDir\E([\/\\]|\Z)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007084 { # in the same directory
7085 $TargetHeaders{$LibVersion}{get_filename($RecInc)}=1;
7086 }
7087 }
7088 }
7089}
7090
7091sub readHeaders($)
7092{
7093 $Version = $_[0];
7094 printMsg("INFO", "checking header(s) ".$Descriptor{$Version}{"Version"}." ...");
7095 my $DumpPath = getDump();
7096 if(not $DumpPath) {
7097 exitStatus("Cannot_Compile", "can't compile header(s)");
7098 }
7099 if($Debug)
7100 { # debug mode
7101 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007102 copy($DumpPath, $DEBUG_PATH{$Version}."/translation-unit-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007103 }
7104 getInfo($DumpPath);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007105 addTargetHeaders($Version);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007106}
7107
7108sub prepareTypes($)
7109{
7110 my $LibVersion = $_[0];
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007111 if(not checkDumpVersion($LibVersion, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007112 { # support for old ABI dumps
7113 # type names have been corrected in ACC 1.22 (dump 2.0 format)
7114 foreach my $TypeDeclId (keys(%{$TypeInfo{$LibVersion}}))
7115 {
7116 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}}))
7117 {
7118 my $TName = $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Name"};
7119 if($TName=~/\A(\w+)::(\w+)/) {
7120 my ($P1, $P2) = ($1, $2);
7121 if($P1 eq $P2) {
7122 $TName=~s/\A$P1:\:$P1(\W)/$P1$1/;
7123 }
7124 else {
7125 $TName=~s/\A(\w+:\:)$P2:\:$P2(\W)/$1$P2$2/;
7126 }
7127 }
7128 $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Name"} = $TName;
7129 }
7130 }
7131 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007132 if(not checkDumpVersion($LibVersion, "2.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007133 { # support for old ABI dumps
7134 # V < 2.5: array size == "number of elements"
7135 # V >= 2.5: array size in bytes
7136 foreach my $TypeDeclId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
7137 {
7138 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}}))
7139 {
7140 my %Type = get_PureType($TypeDeclId, $TypeId, $LibVersion);
7141 if($Type{"Type"} eq "Array")
7142 {
7143 if($Type{"Size"})
7144 { # array[N]
7145 my %Base = get_OneStep_BaseType($Type{"TDid"}, $Type{"Tid"}, $LibVersion);
7146 $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Size"} = $Type{"Size"}*$Base{"Size"};
7147 }
7148 else
7149 { # array[] is a pointer
7150 $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Size"} = $WORD_SIZE{$LibVersion};
7151 }
7152 }
7153 }
7154 }
7155 }
7156 my $V2 = ($LibVersion==1)?2:1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007157 if(not checkDumpVersion($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007158 { # support for old ABI dumps
7159 # size of "method ptr" corrected in 2.7
7160 foreach my $TypeDeclId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
7161 {
7162 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}}))
7163 {
7164 my %PureType = get_PureType($TypeDeclId, $TypeId, $LibVersion);
7165 if($PureType{"Type"} eq "MethodPtr")
7166 {
7167 my %Type = get_Type($TypeDeclId, $TypeId, $LibVersion);
7168 my $TypeId_2 = getTypeIdByName($PureType{"Name"}, $V2);
7169 my %Type2 = get_Type($Tid_TDid{$V2}{$TypeId_2}, $TypeId_2, $V2);
7170 if($Type{"Size"} ne $Type2{"Size"}) {
7171 $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Size"} = $Type2{"Size"};
7172 }
7173 }
7174 }
7175 }
7176 }
7177}
7178
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007179sub prepareSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007180{
7181 my $LibVersion = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007182
7183 if(not keys(%{$SymbolInfo{$LibVersion}}))
7184 { # check if input is valid
7185 if(not $ExtendedCheck and not $CheckObjectsOnly)
7186 {
7187 if($CheckHeadersOnly) {
7188 exitStatus("Empty_Set", "the set of public symbols is empty (".$Descriptor{$LibVersion}{"Version"}.")");
7189 }
7190 else {
7191 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection (".$Descriptor{$LibVersion}{"Version"}.")");
7192 }
7193 }
7194 }
7195
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007196 my $Remangle = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007197 if(not checkDumpVersion(1, "2.10")
7198 or not checkDumpVersion(2, "2.10"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007199 { # different formats
7200 $Remangle = 1;
7201 }
7202 if($CheckHeadersOnly)
7203 { # different languages
7204 if($UserLang)
7205 { # --lang=LANG for both versions
7206 if(($UsedDump{1}{"V"} and $UserLang ne $UsedDump{1}{"L"})
7207 or ($UsedDump{2}{"V"} and $UserLang ne $UsedDump{2}{"L"}))
7208 {
7209 if($UserLang eq "C++")
7210 { # remangle symbols
7211 $Remangle = 1;
7212 }
7213 elsif($UserLang eq "C")
7214 { # remove mangling
7215 $Remangle = -1;
7216 }
7217 }
7218 }
7219 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007220 foreach my $InfoId (sort {int($b)<=>int($a)} keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007221 { # reverse order: D0, D1, D2, D0 (artificial, GCC < 4.5), C1, C2
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007222 if($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007223 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007224 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
7225 and keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})
7226 and $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{"0"}{"name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007227 { # support for old GCC < 4.5: skip artificial ~dtor(int __in_chrg)
7228 # + support for old ABI dumps
7229 next;
7230 }
7231 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007232 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007233 my $ClassID = $SymbolInfo{$LibVersion}{$InfoId}{"Class"};
7234 my $SRemangle = 0;
7235 if(not checkDumpVersion($LibVersion, "2.12"))
7236 { # support for old ABI dumps
7237 if($SymbolInfo{$LibVersion}{$InfoId}{"ShortName"} eq "operator>>")
7238 { # corrected mangling of operator>>
7239 $SRemangle = 1;
7240 }
7241 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"}
7242 and not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
7243 { # corrected mangling of const global data
7244 $SRemangle = 1;
7245 }
7246 }
7247 if($Remangle==1 or $SRemangle==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007248 { # support for old ABI dumps: some symbols are not mangled in old dumps
7249 # mangle both sets of symbols (old and new)
7250 # NOTE: remangling all symbols by the same mangler
7251 if($MnglName=~/\A_ZN(V|)K/)
7252 { # mangling may be incorrect on old ABI dumps
7253 # because of absent "Const" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007254 $SymbolInfo{$LibVersion}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007255 }
7256 if($MnglName=~/\A_ZN(K|)V/)
7257 { # mangling may be incorrect on old ABI dumps
7258 # because of absent "Volatile" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007259 $SymbolInfo{$LibVersion}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007260 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007261 if(($ClassID and $MnglName!~/\A(_Z|\?)/)
7262 or (not $ClassID and $CheckHeadersOnly)
7263 or (not $ClassID and not link_symbol($MnglName, $LibVersion, "-Deps")))
7264 { # support for old ABI dumps, GCC >= 4.0
7265 # remangling all manually mangled symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007266 if($MnglName = mangle_symbol($InfoId, $LibVersion, "GCC"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007267 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007268 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007269 $MangledNames{$LibVersion}{$MnglName} = 1;
7270 }
7271 }
7272 }
7273 elsif($Remangle==-1)
7274 { # remove mangling
7275 $MnglName = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007276 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007277 }
7278 if(not $MnglName)
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007279 { # ABI dumps have no mangled names for C-functions
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007280 $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
7281 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007282 }
7283 if(not $MnglName) {
7284 next;
7285 }
7286 if(not $CompleteSignature{$LibVersion}{$MnglName}{"MnglName"})
7287 { # NOTE: global data may enter here twice
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007288 %{$CompleteSignature{$LibVersion}{$MnglName}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
7289
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007290 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007291 if(not checkDumpVersion($LibVersion, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007292 { # support for old dumps
7293 # add "Volatile" attribute
7294 if($MnglName=~/_Z(K|)V/) {
7295 $CompleteSignature{$LibVersion}{$MnglName}{"Volatile"}=1;
7296 }
7297 }
7298 # symbol and its symlink have same signatures
7299 if($SymVer{$LibVersion}{$MnglName}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007300 %{$CompleteSignature{$LibVersion}{$SymVer{$LibVersion}{$MnglName}}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007301 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007302 delete($SymbolInfo{$LibVersion}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007303 }
7304 if($COMMON_LANGUAGE{$LibVersion} eq "C++" or $OSgroup eq "windows") {
7305 translateSymbols(keys(%{$CompleteSignature{$LibVersion}}), $LibVersion);
7306 }
7307 if($ExtendedCheck)
7308 { # --ext option
7309 addExtension($LibVersion);
7310 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007311 $SymbolInfo{$LibVersion} = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007312 foreach my $MnglName (keys(%{$CompleteSignature{$LibVersion}}))
7313 { # detect allocable classes with public exported constructors
7314 # or classes with auto-generated or inline-only constructors
7315 if(my $ClassId = $CompleteSignature{$LibVersion}{$MnglName}{"Class"})
7316 {
7317 my $ClassName = get_TypeName($ClassId, $LibVersion);
7318 if($CompleteSignature{$LibVersion}{$MnglName}{"Constructor"}
7319 and not $CompleteSignature{$LibVersion}{$MnglName}{"InLine"})
7320 { # Class() { ... } will not be exported
7321 if(not $CompleteSignature{$LibVersion}{$MnglName}{"Private"})
7322 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007323 if($CheckHeadersOnly or link_symbol($MnglName, $LibVersion, "-Deps")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007324 $AllocableClass{$LibVersion}{$ClassName} = 1;
7325 }
7326 }
7327 }
7328 if(not $CompleteSignature{$LibVersion}{$MnglName}{"Private"})
7329 { # all imported class methods
7330 if($CheckHeadersOnly)
7331 {
7332 if(not $CompleteSignature{$LibVersion}{$MnglName}{"InLine"}
7333 or $CompleteSignature{$LibVersion}{$MnglName}{"Virt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007334 { # all symbols except non-virtual inline
7335 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$MnglName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007336 }
7337 }
7338 elsif(link_symbol($MnglName, $LibVersion, "-Deps"))
7339 { # all symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007340 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$MnglName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007341 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007342 $ClassMethods{"Source"}{$LibVersion}{$ClassName}{$MnglName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007343 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007344 $ClassNames{$LibVersion}{$ClassName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007345 }
7346 if(my $RetId = $CompleteSignature{$LibVersion}{$MnglName}{"Return"})
7347 {
7348 my %Base = get_BaseType($Tid_TDid{$LibVersion}{$RetId}, $RetId, $LibVersion);
7349 if($Base{"Type"}=~/Struct|Class/)
7350 {
7351 my $Name = get_TypeName($Base{"Tid"}, $LibVersion);
7352 if($Name=~/<([^<>\s]+)>/)
7353 {
7354 if(my $Tid = getTypeIdByName($1, $LibVersion)) {
7355 $ReturnedClass{$LibVersion}{$Tid} = 1;
7356 }
7357 }
7358 else {
7359 $ReturnedClass{$LibVersion}{$Base{"Tid"}} = 1;
7360 }
7361 }
7362 }
7363 foreach my $Num (keys(%{$CompleteSignature{$LibVersion}{$MnglName}{"Param"}}))
7364 {
7365 my $PId = $CompleteSignature{$LibVersion}{$MnglName}{"Param"}{$Num}{"type"};
7366 if(get_PointerLevel($Tid_TDid{1}{$PId}, $PId, $LibVersion)>=1)
7367 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007368 if(my %Base = get_BaseType($Tid_TDid{$LibVersion}{$PId}, $PId, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007369 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007370 if($Base{"Type"}=~/Struct|Class/)
7371 {
7372 $ParamClass{$LibVersion}{$Base{"Tid"}}{$MnglName} = 1;
7373 foreach my $SubId (get_sub_classes($Base{"Tid"}, $LibVersion, 1))
7374 { # mark all derived classes
7375 $ParamClass{$LibVersion}{$SubId}{$MnglName} = 1;
7376 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007377 }
7378 }
7379 }
7380 }
7381 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04007382 foreach my $MnglName (keys(%VTableClass))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007383 { # reconstruct header name for v-tables
7384 if($MnglName=~/\A_ZTV/)
7385 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04007386 if(my $ClassName = $VTableClass{$MnglName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007387 {
7388 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName}) {
7389 $CompleteSignature{$LibVersion}{$MnglName}{"Header"} = get_TypeAttr($ClassId, $LibVersion, "Header");
7390 }
7391 }
7392 }
7393 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007394
7395 # types
7396 foreach my $TypeDeclId (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007397 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007398 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007399 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007400 if(not defined $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"TDid"})
7401 { # to avoid Perl warnings about uninitialized values
7402 $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"TDid"} = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007403 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007404 if(my $TName = $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007405 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007406 if(defined $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"VTable"}) {
7407 $ClassNames{$LibVersion}{$TName} = 1;
7408 }
7409 if(defined $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Base"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007410 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007411 $ClassNames{$LibVersion}{$TName} = 1;
7412 foreach (keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Base"}})) {
7413 $ClassNames{$LibVersion}{get_TypeName($_, $LibVersion)} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007414 }
7415 }
7416 }
7417 }
7418 }
7419}
7420
7421sub register_TypeUsing($$$)
7422{
7423 my ($TypeDeclId, $TypeId, $LibVersion) = @_;
7424 return if($UsedType{$LibVersion}{$TypeDeclId}{$TypeId});
7425 my %Type = get_Type($TypeDeclId, $TypeId, $LibVersion);
7426 if($Type{"Type"}=~/\A(Struct|Union|Class|FuncPtr|MethodPtr|FieldPtr|Enum)\Z/)
7427 {
7428 $UsedType{$LibVersion}{$TypeDeclId}{$TypeId} = 1;
7429 if($Type{"Type"}=~/\A(Struct|Class)\Z/)
7430 {
7431 if(my $ThisPtrId = getTypeIdByName(get_TypeName($TypeId, $LibVersion)."*const", $LibVersion))
7432 {# register "this" pointer
7433 my $ThisPtrDId = $Tid_TDid{$LibVersion}{$ThisPtrId};
7434 my %ThisPtrType = get_Type($ThisPtrDId, $ThisPtrId, $LibVersion);
7435 $UsedType{$LibVersion}{$ThisPtrDId}{$ThisPtrId} = 1;
7436 register_TypeUsing($ThisPtrType{"BaseType"}{"TDid"}, $ThisPtrType{"BaseType"}{"Tid"}, $LibVersion);
7437 }
7438 foreach my $BaseId (keys(%{$Type{"Base"}}))
7439 {# register base classes
7440 register_TypeUsing($Tid_TDid{$LibVersion}{$BaseId}, $BaseId, $LibVersion);
7441 }
7442 }
7443 foreach my $Memb_Pos (keys(%{$Type{"Memb"}}))
7444 {
7445 my $Member_TypeId = $Type{"Memb"}{$Memb_Pos}{"type"};
7446 register_TypeUsing($Tid_TDid{$LibVersion}{$Member_TypeId}, $Member_TypeId, $LibVersion);
7447 }
7448 if($Type{"Type"} eq "FuncPtr"
7449 or $Type{"Type"} eq "MethodPtr") {
7450 my $ReturnType = $Type{"Return"};
7451 register_TypeUsing($Tid_TDid{$LibVersion}{$ReturnType}, $ReturnType, $LibVersion);
7452 foreach my $Memb_Pos (keys(%{$Type{"Param"}}))
7453 {
7454 my $Member_TypeId = $Type{"Param"}{$Memb_Pos}{"type"};
7455 register_TypeUsing($Tid_TDid{$LibVersion}{$Member_TypeId}, $Member_TypeId, $LibVersion);
7456 }
7457 }
7458 }
7459 elsif($Type{"Type"}=~/\A(Const|Pointer|Ref|Volatile|Restrict|Array|Typedef)\Z/)
7460 {
7461 $UsedType{$LibVersion}{$TypeDeclId}{$TypeId} = 1;
7462 register_TypeUsing($Type{"BaseType"}{"TDid"}, $Type{"BaseType"}{"Tid"}, $LibVersion);
7463 }
7464 elsif($Type{"Type"} eq "Intrinsic") {
7465 $UsedType{$LibVersion}{$TypeDeclId}{$TypeId} = 1;
7466 }
7467 else
7468 {
7469 delete($TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId});
7470 if(not keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}})) {
7471 delete($TypeInfo{$LibVersion}{$TypeDeclId});
7472 }
7473 if($Tid_TDid{$LibVersion}{$TypeId} eq $TypeDeclId) {
7474 delete($Tid_TDid{$LibVersion}{$TypeId});
7475 }
7476 }
7477}
7478
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007479sub isVirt($$) {
7480 return ($SymbolInfo{$_[0]}{$_[1]}{"Virt"} or $SymbolInfo{$_[0]}{$_[1]}{"PureVirt"});
7481}
7482
7483sub formatDump($)
7484{ # remove unnecessary data from the ABI dump
7485 my $LibVersion = $_[0];
7486 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
7487 {
7488 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
7489 if(not $MnglName) {
7490 delete($SymbolInfo{$LibVersion}{$InfoId});
7491 next;
7492 }
7493 if($MnglName eq $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"}) {
7494 delete($SymbolInfo{$LibVersion}{$InfoId}{"MnglName"});
7495 }
7496 if(not isVirt($LibVersion, $InfoId))
7497 { # non-virtual only
7498 if(not is_target_header($SymbolInfo{$LibVersion}{$InfoId}{"Header"}))
7499 { # user-defined header
7500 delete($SymbolInfo{$LibVersion}{$InfoId});
7501 next;
7502 }
7503 if(not $CheckHeadersOnly)
7504 {
7505 if($BinaryOnly)
7506 { # --dump --binary
7507 if(not link_symbol($MnglName, $LibVersion, "-Deps"))
7508 { # removing src only (inline)
7509 # and all non-exported functions
7510 delete($SymbolInfo{$LibVersion}{$InfoId});
7511 next;
7512 }
7513 }
7514 }
7515 if(not symbolFilter($MnglName, $LibVersion, "Public", "Source")) {
7516 delete($SymbolInfo{$LibVersion}{$InfoId});
7517 next;
7518 }
7519 }
7520 my %FuncInfo = %{$SymbolInfo{$LibVersion}{$InfoId}};
7521 register_TypeUsing($Tid_TDid{$LibVersion}{$FuncInfo{"Return"}}, $FuncInfo{"Return"}, $LibVersion);
7522 register_TypeUsing($Tid_TDid{$LibVersion}{$FuncInfo{"Class"}}, $FuncInfo{"Class"}, $LibVersion);
7523 foreach my $Param_Pos (keys(%{$FuncInfo{"Param"}}))
7524 {
7525 my $Param_TypeId = $FuncInfo{"Param"}{$Param_Pos}{"type"};
7526 register_TypeUsing($Tid_TDid{$LibVersion}{$Param_TypeId}, $Param_TypeId, $LibVersion);
7527 }
7528 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})) {
7529 delete($SymbolInfo{$LibVersion}{$InfoId}{"Param"});
7530 }
7531 }
7532 foreach my $TDid (keys(%{$TypeInfo{$LibVersion}}))
7533 { # remove unused types
7534 if(not keys(%{$TypeInfo{$LibVersion}{$TDid}})) {
7535 delete($TypeInfo{$LibVersion}{$TDid});
7536 }
7537 else
7538 {
7539 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}{$TDid}}))
7540 {
7541 if(not $UsedType{$LibVersion}{$TDid}{$Tid})
7542 {
7543 delete($TypeInfo{$LibVersion}{$TDid}{$Tid});
7544 if(not keys(%{$TypeInfo{$LibVersion}{$TDid}})) {
7545 delete($TypeInfo{$LibVersion}{$TDid});
7546 }
7547 if($Tid_TDid{$LibVersion}{$Tid} eq $TDid) {
7548 delete($Tid_TDid{$LibVersion}{$Tid});
7549 }
7550 }
7551 else
7552 { # clean attributes
7553 if(not $TypeInfo{$LibVersion}{$TDid}{$Tid}{"TDid"}) {
7554 delete($TypeInfo{$LibVersion}{$TDid}{$Tid}{"TDid"});
7555 }
7556 if(not $TypeInfo{$LibVersion}{$TDid}{$Tid}{"NameSpace"}) {
7557 delete($TypeInfo{$LibVersion}{$TDid}{$Tid}{"NameSpace"});
7558 }
7559 if(defined $TypeInfo{$LibVersion}{$TDid}{$Tid}{"BaseType"}
7560 and not $TypeInfo{$LibVersion}{$TDid}{$Tid}{"BaseType"}{"TDid"}) {
7561 delete($TypeInfo{$LibVersion}{$TDid}{$Tid}{"BaseType"}{"TDid"});
7562 }
7563 if(not $TypeInfo{$LibVersion}{$TDid}{$Tid}{"Header"}) {
7564 delete($TypeInfo{$LibVersion}{$TDid}{$Tid}{"Header"});
7565 }
7566 if(not $TypeInfo{$LibVersion}{$TDid}{$Tid}{"Line"}) {
7567 delete($TypeInfo{$LibVersion}{$TDid}{$Tid}{"Line"});
7568 }
7569 if(not $TypeInfo{$LibVersion}{$TDid}{$Tid}{"Size"}) {
7570 delete($TypeInfo{$LibVersion}{$TDid}{$Tid}{"Size"});
7571 }
7572 }
7573 }
7574 }
7575 }
7576 foreach my $Tid (keys(%{$Tid_TDid{$LibVersion}}))
7577 {
7578 if(not $Tid_TDid{$LibVersion}{$Tid}) {
7579 delete($Tid_TDid{$LibVersion}{$Tid});
7580 }
7581 }
7582}
7583
7584sub addExtension($)
7585{
7586 my $LibVersion = $_[0];
7587 foreach my $TDid (keys(%{$TypeInfo{$LibVersion}}))
7588 {
7589 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}{$TDid}}))
7590 {
7591 my $TType = $TypeInfo{$LibVersion}{$TDid}{$Tid}{"Type"};
7592 if($TType=~/Struct|Union|Enum|Class/)
7593 {
7594 my $HName = $TypeInfo{$LibVersion}{$TDid}{$Tid}{"Header"};
7595 if(not $HName or isBuiltIn($HName)) {
7596 next;
7597 }
7598 my $TName = $TypeInfo{$LibVersion}{$TDid}{$Tid}{"Name"};
7599 if(isAnon($TName))
7600 { # anon-struct-header.h-265
7601 next;
7602 }
7603 my $FuncName = "external_func_".$TName;
7604 $ExtendedFuncs{$FuncName}=1;
7605 my %Attrs = (
7606 "Header" => "extended.h",
7607 "ShortName" => $FuncName,
7608 "MnglName" => $FuncName,
7609 "Param" => { "0" => { "type"=>$Tid, "name"=>"p1" } }
7610 );
7611 %{$CompleteSignature{$LibVersion}{$FuncName}} = %Attrs;
7612 register_TypeUsing($TDid, $Tid, $LibVersion);
7613 $GeneratedSymbols{$FuncName}=1;
7614 $CheckedSymbols{"Binary"}{$FuncName}=1;
7615 $CheckedSymbols{"Source"}{$FuncName}=1;
7616 }
7617 }
7618 }
7619 my $ConstFunc = "external_func_0";
7620 $GeneratedSymbols{$ConstFunc}=1;
7621 $CheckedSymbols{"Binary"}{$ConstFunc}=1;
7622 $CheckedSymbols{"Source"}{$ConstFunc}=1;
7623}
7624
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007625sub findMethod($$$)
7626{
7627 my ($VirtFunc, $ClassId, $LibVersion) = @_;
7628 foreach my $BaseClass_Id (keys(%{$TypeInfo{$LibVersion}{$Tid_TDid{$LibVersion}{$ClassId}}{$ClassId}{"Base"}}))
7629 {
7630 if(my $VirtMethodInClass = findMethod_Class($VirtFunc, $BaseClass_Id, $LibVersion)) {
7631 return $VirtMethodInClass;
7632 }
7633 elsif(my $VirtMethodInBaseClasses = findMethod($VirtFunc, $BaseClass_Id, $LibVersion)) {
7634 return $VirtMethodInBaseClasses;
7635 }
7636 }
7637 return "";
7638}
7639
7640sub findMethod_Class($$$)
7641{
7642 my ($VirtFunc, $ClassId, $LibVersion) = @_;
7643 my $ClassName = get_TypeName($ClassId, $LibVersion);
7644 return "" if(not defined $VirtualTable{$LibVersion}{$ClassName});
7645 my $TargetSuffix = get_symbol_suffix($VirtFunc, 1);
7646 my $TargetShortName = $CompleteSignature{$LibVersion}{$VirtFunc}{"ShortName"};
7647 foreach my $Candidate (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
7648 { # search for interface with the same parameters suffix (overridden)
7649 if($TargetSuffix eq get_symbol_suffix($Candidate, 1))
7650 {
7651 if($CompleteSignature{$LibVersion}{$VirtFunc}{"Destructor"}) {
7652 if($CompleteSignature{$LibVersion}{$Candidate}{"Destructor"}) {
7653 if(($VirtFunc=~/D0E/ and $Candidate=~/D0E/)
7654 or ($VirtFunc=~/D1E/ and $Candidate=~/D1E/)
7655 or ($VirtFunc=~/D2E/ and $Candidate=~/D2E/)) {
7656 return $Candidate;
7657 }
7658 }
7659 }
7660 else {
7661 if($TargetShortName eq $CompleteSignature{$LibVersion}{$Candidate}{"ShortName"}) {
7662 return $Candidate;
7663 }
7664 }
7665 }
7666 }
7667 return "";
7668}
7669
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007670sub registerVTable($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007671{
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007672 my $LibVersion = $_[0];
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007673 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007674 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007675 if($CompleteSignature{$LibVersion}{$Symbol}{"Virt"}
7676 or $CompleteSignature{$LibVersion}{$Symbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007677 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007678 my $ClassName = get_TypeName($CompleteSignature{$LibVersion}{$Symbol}{"Class"}, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007679 next if(not $STDCXX_TESTING and $ClassName=~/\A(std::|__cxxabi)/);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007680 if($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"}
7681 and $Symbol=~/D2E/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007682 { # pure virtual D2-destructors are marked as "virt" in the dump
7683 # virtual D2-destructors are NOT marked as "virt" in the dump
7684 # both destructors are not presented in the v-table
7685 next;
7686 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007687 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007688 $VirtualTable{$LibVersion}{$ClassName}{$MnglName} = 1;
7689 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007690 }
7691}
7692
7693sub registerOverriding($)
7694{
7695 my $LibVersion = $_[0];
7696 my @Classes = keys(%{$VirtualTable{$LibVersion}});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007697 @Classes = sort {int($ClassNames{$LibVersion}{$a})<=>int($ClassNames{$LibVersion}{$b})} @Classes;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007698 foreach my $ClassName (@Classes)
7699 {
7700 foreach my $VirtFunc (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
7701 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007702 if($CompleteSignature{$LibVersion}{$VirtFunc}{"PureVirt"})
7703 { # pure virtuals
7704 next;
7705 }
7706 my $ClassId = $TName_Tid{$LibVersion}{$ClassName};
7707 if(my $Overridden = findMethod($VirtFunc, $ClassId, $LibVersion))
7708 { # both overridden virtual methods
7709 # and implemented pure virtual methods
7710 $CompleteSignature{$LibVersion}{$VirtFunc}{"Override"} = $Overridden;
7711 $OverriddenMethods{$LibVersion}{$Overridden}{$VirtFunc} = 1;
7712 delete($VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}); # remove from v-table model
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007713 }
7714 }
7715 if(not keys(%{$VirtualTable{$LibVersion}{$ClassName}})) {
7716 delete($VirtualTable{$LibVersion}{$ClassName});
7717 }
7718 }
7719}
7720
7721sub setVirtFuncPositions($)
7722{
7723 my $LibVersion = $_[0];
7724 foreach my $ClassName (keys(%{$VirtualTable{$LibVersion}}))
7725 {
7726 my ($Num, $RelPos, $AbsNum) = (1, 0, 1);
7727 foreach my $VirtFunc (sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})}
7728 sort keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
7729 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007730 $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}=$Num++;
7731
7732 # set relative positions
7733 if(defined $VirtualTable{1}{$ClassName} and defined $VirtualTable{1}{$ClassName}{$VirtFunc}
7734 and defined $VirtualTable{2}{$ClassName} and defined $VirtualTable{2}{$ClassName}{$VirtFunc})
7735 { # relative position excluding added and removed virtual functions
7736 if(not $CompleteSignature{1}{$VirtFunc}{"Override"}
7737 and not $CompleteSignature{2}{$VirtFunc}{"Override"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007738 $CompleteSignature{$LibVersion}{$VirtFunc}{"RelPos"} = $RelPos++;
7739 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007740 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007741 }
7742 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007743 foreach my $ClassName (keys(%{$ClassNames{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007744 {
7745 my $AbsNum = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007746 foreach my $VirtFunc (getVTable_Model($TName_Tid{$LibVersion}{$ClassName}, $LibVersion)) {
7747 $VirtualTable_Model{$LibVersion}{$ClassName}{$VirtFunc}=$AbsNum++;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007748 }
7749 }
7750}
7751
7752sub get_sub_classes($$$)
7753{
7754 my ($ClassId, $LibVersion, $Recursive) = @_;
7755 return () if(not defined $Class_SubClasses{$LibVersion}{$ClassId});
7756 my @Subs = ();
7757 foreach my $SubId (keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
7758 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007759 if($Recursive)
7760 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007761 foreach my $SubSubId (get_sub_classes($SubId, $LibVersion, $Recursive)) {
7762 push(@Subs, $SubSubId);
7763 }
7764 }
7765 push(@Subs, $SubId);
7766 }
7767 return @Subs;
7768}
7769
7770sub get_base_classes($$$)
7771{
7772 my ($ClassId, $LibVersion, $Recursive) = @_;
7773 my %ClassType = get_Type($Tid_TDid{$LibVersion}{$ClassId}, $ClassId, $LibVersion);
7774 return () if(not defined $ClassType{"Base"});
7775 my @Bases = ();
7776 foreach my $BaseId (sort {int($ClassType{"Base"}{$a}{"pos"})<=>int($ClassType{"Base"}{$b}{"pos"})}
7777 keys(%{$ClassType{"Base"}}))
7778 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007779 if($Recursive)
7780 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007781 foreach my $SubBaseId (get_base_classes($BaseId, $LibVersion, $Recursive)) {
7782 push(@Bases, $SubBaseId);
7783 }
7784 }
7785 push(@Bases, $BaseId);
7786 }
7787 return @Bases;
7788}
7789
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007790sub getVTable_Model($$)
7791{ # return an ordered list of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007792 my ($ClassId, $LibVersion) = @_;
7793 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
7794 my @Elements = ();
7795 foreach my $BaseId (@Bases, $ClassId)
7796 {
7797 my $BName = get_TypeName($BaseId, $LibVersion);
7798 my @VFunctions = keys(%{$VirtualTable{$LibVersion}{$BName}});
7799 @VFunctions = sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})} @VFunctions;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007800 foreach my $VFunc (@VFunctions) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007801 push(@Elements, $VFunc);
7802 }
7803 }
7804 return @Elements;
7805}
7806
7807sub getVShift($$)
7808{
7809 my ($ClassId, $LibVersion) = @_;
7810 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
7811 my $VShift = 0;
7812 foreach my $BaseId (@Bases)
7813 {
7814 my $BName = get_TypeName($BaseId, $LibVersion);
7815 if(defined $VirtualTable{$LibVersion}{$BName}) {
7816 $VShift+=keys(%{$VirtualTable{$LibVersion}{$BName}});
7817 }
7818 }
7819 return $VShift;
7820}
7821
7822sub getShift($$)
7823{
7824 my ($ClassId, $LibVersion) = @_;
7825 my @Bases = get_base_classes($ClassId, $LibVersion, 0);
7826 my $Shift = 0;
7827 foreach my $BaseId (@Bases)
7828 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04007829 if(my $Size = get_TypeSize($BaseId, $LibVersion))
7830 {
7831 if($Size!=1)
7832 { # not empty base class
7833 $Shift+=$Size;
7834 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007835 }
7836 }
7837 return $Shift;
7838}
7839
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007840sub getVTable_Size($$)
7841{ # number of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007842 my ($ClassName, $LibVersion) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007843 my $Size = 0;
7844 # three approaches
7845 if(not $Size)
7846 { # real size
7847 if(my %VTable = getVTable_Real($ClassName, $LibVersion)) {
7848 $Size = keys(%VTable);
7849 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007850 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007851 if(not $Size)
7852 { # shared library symbol size
7853 if($Size = getSymbolSize($ClassVTable{$ClassName}, $LibVersion)) {
7854 $Size /= $WORD_SIZE{$LibVersion};
7855 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007856 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007857 if(not $Size)
7858 { # model size
7859 if(defined $VirtualTable_Model{$LibVersion}{$ClassName}) {
7860 $Size = keys(%{$VirtualTable_Model{$LibVersion}{$ClassName}}) + 2;
7861 }
7862 }
7863 return $Size;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007864}
7865
7866sub isCopyingClass($$)
7867{
7868 my ($TypeId, $LibVersion) = @_;
7869 return $TypeInfo{$LibVersion}{$Tid_TDid{$LibVersion}{$TypeId}}{$TypeId}{"Copied"};
7870}
7871
7872sub isLeafClass($$)
7873{
7874 my ($ClassId, $LibVersion) = @_;
7875 return (not keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}));
7876}
7877
7878sub havePubFields($)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04007879{ # check structured type for public fields
7880 return isAccessible($_[0], {}, 0, -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007881}
7882
7883sub isAccessible($$$$)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04007884{ # check interval in structured type for public fields
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007885 my ($TypePtr, $Skip, $Start, $End) = @_;
7886 return 0 if(not $TypePtr);
7887 if($End==-1) {
7888 $End = keys(%{$TypePtr->{"Memb"}})-1;
7889 }
7890 foreach my $MemPos (keys(%{$TypePtr->{"Memb"}}))
7891 {
7892 if($Skip and $Skip->{$MemPos})
7893 { # skip removed/added fields
7894 next;
7895 }
7896 if(int($MemPos)>=$Start and int($MemPos)<=$End)
7897 {
7898 if(isPublic($TypePtr, $MemPos)) {
7899 return ($MemPos+1);
7900 }
7901 }
7902 }
7903 return 0;
7904}
7905
7906sub getAlignment($$$)
7907{
7908 my ($Pos, $TypePtr, $LibVersion) = @_;
7909 my $Tid = $TypePtr->{"Memb"}{$Pos}{"type"};
7910 my %Type = get_PureType($Tid_TDid{$LibVersion}{$Tid}, $Tid, $LibVersion);
7911 my $TSize = $Type{"Size"}*$BYTE_SIZE;
7912 my $MSize = $Type{"Size"}*$BYTE_SIZE;
7913 if(my $BSize = $TypePtr->{"Memb"}{$Pos}{"bitfield"})
7914 { # bitfields
7915 ($TSize, $MSize) = ($WORD_SIZE{$LibVersion}*$BYTE_SIZE, $BSize);
7916 }
7917 elsif($Type{"Type"} eq "Array")
7918 { # in the context of function parameter
7919 # it's passed through the pointer
7920 }
7921 # alignment
7922 my $Alignment = $WORD_SIZE{$LibVersion}*$BYTE_SIZE; # default
7923 if(my $Computed = $TypePtr->{"Memb"}{$Pos}{"algn"})
7924 { # computed by GCC
7925 $Alignment = $Computed*$BYTE_SIZE;
7926 }
7927 elsif($TypePtr->{"Memb"}{$Pos}{"bitfield"})
7928 { # bitfields are 1 bit aligned
7929 $Alignment = 1;
7930 }
7931 elsif($TSize and $TSize<$WORD_SIZE{$LibVersion}*$BYTE_SIZE)
7932 { # model
7933 $Alignment = $TSize;
7934 }
7935 return ($Alignment, $MSize);
7936}
7937
7938sub getOffset($$$)
7939{ # offset of the field including padding
7940 my ($FieldPos, $TypePtr, $LibVersion) = @_;
7941 my $Offset = 0;
7942 foreach my $Pos (0 .. keys(%{$TypePtr->{"Memb"}})-1)
7943 {
7944 my ($Alignment, $MSize) = getAlignment($Pos, $TypePtr, $LibVersion);
7945 # padding
7946 my $Padding = 0;
7947 if($Offset % $Alignment!=0)
7948 { # not aligned, add padding
7949 $Padding = $Alignment - $Offset % $Alignment;
7950 }
7951 $Offset += $Padding;
7952 if($Pos==$FieldPos)
7953 { # after the padding
7954 # before the field
7955 return $Offset;
7956 }
7957 $Offset += $MSize;
7958 }
7959 return $FieldPos;# if something is going wrong
7960}
7961
7962sub isMemPadded($$$$$)
7963{ # check if the target field can be added/removed/changed
7964 # without shifting other fields because of padding bits
7965 my ($FieldPos, $Size, $TypePtr, $Skip, $LibVersion) = @_;
7966 return 0 if($FieldPos==0);
7967 if(defined $TypePtr->{"Memb"}{""})
7968 {
7969 delete($TypePtr->{"Memb"}{""});
7970 if($Debug) {
7971 printMsg("WARNING", "internal error detected");
7972 }
7973 }
7974 my $Offset = 0;
7975 my (%Alignment, %MSize) = ();
7976 my $MaxAlgn = 0;
7977 my $End = keys(%{$TypePtr->{"Memb"}})-1;
7978 my $NextField = $FieldPos+1;
7979 foreach my $Pos (0 .. $End)
7980 {
7981 if($Skip and $Skip->{$Pos})
7982 { # skip removed/added fields
7983 if($Pos > $FieldPos)
7984 { # after the target
7985 $NextField += 1;
7986 next;
7987 }
7988 }
7989 ($Alignment{$Pos}, $MSize{$Pos}) = getAlignment($Pos, $TypePtr, $LibVersion);
7990 if($Alignment{$Pos}>$MaxAlgn) {
7991 $MaxAlgn = $Alignment{$Pos};
7992 }
7993 if($Pos==$FieldPos)
7994 {
7995 if($Size==-1)
7996 { # added/removed fields
7997 if($Pos!=$End)
7998 { # skip target field and see
7999 # if enough padding will be
8000 # created on the next step
8001 # to include this field
8002 next;
8003 }
8004 }
8005 }
8006 # padding
8007 my $Padding = 0;
8008 if($Offset % $Alignment{$Pos}!=0)
8009 { # not aligned, add padding
8010 $Padding = $Alignment{$Pos} - $Offset % $Alignment{$Pos};
8011 }
8012 if($Pos==$NextField)
8013 { # try to place target field in the padding
8014 if($Size==-1)
8015 { # added/removed fields
8016 my $TPadding = 0;
8017 if($Offset % $Alignment{$FieldPos}!=0)
8018 {# padding of the target field
8019 $TPadding = $Alignment{$FieldPos} - $Offset % $Alignment{$FieldPos};
8020 }
8021 if($TPadding+$MSize{$FieldPos}<=$Padding)
8022 { # enough padding to place target field
8023 return 1;
8024 }
8025 else {
8026 return 0;
8027 }
8028 }
8029 else
8030 { # changed fields
8031 my $Delta = $Size-$MSize{$FieldPos};
8032 if($Delta>=0)
8033 { # increased
8034 if($Size-$MSize{$FieldPos}<=$Padding)
8035 { # enough padding to change target field
8036 return 1;
8037 }
8038 else {
8039 return 0;
8040 }
8041 }
8042 else
8043 { # decreased
8044 $Delta = abs($Delta);
8045 if($Delta+$Padding>=$MSize{$Pos})
8046 { # try to place the next field
8047 if(($Offset-$Delta) % $Alignment{$Pos} != 0)
8048 { # padding of the next field in new place
8049 my $NPadding = $Alignment{$Pos} - ($Offset-$Delta) % $Alignment{$Pos};
8050 if($NPadding+$MSize{$Pos}<=$Delta+$Padding)
8051 { # enough delta+padding to store next field
8052 return 0;
8053 }
8054 }
8055 else
8056 {
8057 return 0;
8058 }
8059 }
8060 return 1;
8061 }
8062 }
8063 }
8064 elsif($Pos==$End)
8065 { # target field is the last field
8066 if($Size==-1)
8067 { # added/removed fields
8068 if($Offset % $MaxAlgn!=0)
8069 { # tail padding
8070 my $TailPadding = $MaxAlgn - $Offset % $MaxAlgn;
8071 if($Padding+$MSize{$Pos}<=$TailPadding)
8072 { # enough tail padding to place the last field
8073 return 1;
8074 }
8075 }
8076 return 0;
8077 }
8078 else
8079 { # changed fields
8080 # scenario #1
8081 my $Offset1 = $Offset+$Padding+$MSize{$Pos};
8082 if($Offset1 % $MaxAlgn != 0)
8083 { # tail padding
8084 $Offset1 += $MaxAlgn - $Offset1 % $MaxAlgn;
8085 }
8086 # scenario #2
8087 my $Offset2 = $Offset+$Padding+$Size;
8088 if($Offset2 % $MaxAlgn != 0)
8089 { # tail padding
8090 $Offset2 += $MaxAlgn - $Offset2 % $MaxAlgn;
8091 }
8092 if($Offset1!=$Offset2)
8093 { # different sizes of structure
8094 return 0;
8095 }
8096 return 1;
8097 }
8098 }
8099 $Offset += $Padding+$MSize{$Pos};
8100 }
8101 return 0;
8102}
8103
8104sub isReserved($)
8105{ # reserved fields == private
8106 my $MName = $_[0];
8107 if($MName=~/reserved|padding|f_spare/i) {
8108 return 1;
8109 }
8110 if($MName=~/\A[_]*(spare|pad|unused)[_]*\Z/i) {
8111 return 1;
8112 }
8113 if($MName=~/(pad\d+)/i) {
8114 return 1;
8115 }
8116 return 0;
8117}
8118
8119sub isPublic($$)
8120{
8121 my ($TypePtr, $FieldPos) = @_;
8122 return 0 if(not $TypePtr);
8123 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos});
8124 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos}{"name"});
8125 if(not $TypePtr->{"Memb"}{$FieldPos}{"access"})
8126 { # by name in C language
8127 # FIXME: add other methods to detect private members
8128 my $MName = $TypePtr->{"Memb"}{$FieldPos}{"name"};
8129 if($MName=~/priv|abidata|parent_object/i)
8130 { # C-styled private data
8131 return 0;
8132 }
8133 if(lc($MName) eq "abi")
8134 { # ABI information/reserved field
8135 return 0;
8136 }
8137 if(isReserved($MName))
8138 { # reserved fields
8139 return 0;
8140 }
8141 return 1;
8142 }
8143 elsif($TypePtr->{"Memb"}{$FieldPos}{"access"} ne "private")
8144 { # by access in C++ language
8145 return 1;
8146 }
8147 return 0;
8148}
8149
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008150sub getVTable_Real($$)
8151{
8152 my ($ClassName, $LibVersion) = @_;
8153 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName})
8154 {
8155 my %Type = get_Type($Tid_TDid{$LibVersion}{$ClassId}, $ClassId, $LibVersion);
8156 if(defined $Type{"VTable"}) {
8157 return %{$Type{"VTable"}};
8158 }
8159 }
8160 return ();
8161}
8162
8163sub cmpVTables($)
8164{
8165 my $ClassName = $_[0];
8166 my $Res = cmpVTables_Real($ClassName, 1);
8167 if($Res==-1) {
8168 $Res = cmpVTables_Model($ClassName);
8169 }
8170 return $Res;
8171}
8172
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008173sub cmpVTables_Model($)
8174{
8175 my $ClassName = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008176 foreach my $Symbol (keys(%{$VirtualTable_Model{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008177 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008178 if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008179 return 1;
8180 }
8181 }
8182 return 0;
8183}
8184
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008185sub cmpVTables_Real($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008186{
8187 my ($ClassName, $Strong) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008188 if(defined $Cache{"cmpVTables_Real"}{$Strong}{$ClassName}) {
8189 return $Cache{"cmpVTables_Real"}{$Strong}{$ClassName};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008190 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008191 my %VTable_Old = getVTable_Real($ClassName, 1);
8192 my %VTable_New = getVTable_Real($ClassName, 2);
8193 if(not %VTable_Old or not %VTable_New)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008194 { # old ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008195 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008196 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008197 my %Indexes = map {$_=>1} (keys(%VTable_Old), keys(%VTable_New));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008198 foreach my $Offset (sort {int($a)<=>int($b)} keys(%Indexes))
8199 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008200 if(not defined $VTable_Old{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008201 { # v-table v.1 < v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008202 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = $Strong);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008203 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008204 my $Entry1 = $VTable_Old{$Offset};
8205 if(not defined $VTable_New{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008206 { # v-table v.1 > v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008207 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = ($Strong or $Entry1!~/__cxa_pure_virtual/));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008208 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008209 my $Entry2 = $VTable_New{$Offset};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008210 $Entry1 = simpleVEntry($Entry1);
8211 $Entry2 = simpleVEntry($Entry2);
8212 if($Entry1 ne $Entry2)
8213 { # register as changed
8214 if($Entry1=~/::([^:]+)\Z/)
8215 {
8216 my $M1 = $1;
8217 if($Entry2=~/::([^:]+)\Z/)
8218 {
8219 my $M2 = $1;
8220 if($M1 eq $M2)
8221 { # overridden
8222 next;
8223 }
8224 }
8225 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008226 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008227 }
8228 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008229 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008230}
8231
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008232sub mergeVTables($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008233{ # merging v-tables without diagnostics
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008234 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008235 foreach my $ClassName (keys(%{$VirtualTable{1}}))
8236 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008237 if($VTableChanged_M{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008238 { # already registered
8239 next;
8240 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008241 if(cmpVTables_Real($ClassName, 0)==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008242 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008243 my @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008244 foreach my $Symbol (@Affected)
8245 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008246 %{$CompatProblems{$Level}{$Symbol}{"Virtual_Table_Changed_Unknown"}{$ClassName}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008247 "Type_Name"=>$ClassName,
8248 "Type_Type"=>"Class",
8249 "Target"=>$ClassName);
8250 }
8251 }
8252 }
8253}
8254
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008255sub mergeBases($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008256{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008257 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008258 foreach my $ClassName (keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008259 { # detect added and removed virtual functions
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008260 my $ClassId = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008261 next if(not $ClassId);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008262 if(defined $VirtualTable{2}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008263 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008264 foreach my $Symbol (keys(%{$VirtualTable{2}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008265 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008266 if($TName_Tid{1}{$ClassName}
8267 and not defined $VirtualTable{1}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008268 { # added to v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008269 if(defined $CompleteSignature{1}{$Symbol}
8270 and $CompleteSignature{1}{$Symbol}{"Virt"})
8271 { # override some method in v.1
8272 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008273 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008274 $AddedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008275 }
8276 }
8277 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008278 if(defined $VirtualTable{1}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008279 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008280 foreach my $Symbol (keys(%{$VirtualTable{1}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008281 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008282 if($TName_Tid{2}{$ClassName}
8283 and not defined $VirtualTable{2}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008284 { # removed from v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008285 if(defined $CompleteSignature{2}{$Symbol}
8286 and $CompleteSignature{2}{$Symbol}{"Virt"})
8287 { # override some method in v.2
8288 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008289 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008290 $RemovedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008291 }
8292 }
8293 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008294 if($Level eq "Binary")
8295 { # Binary-level
8296 my %Class_Type = get_Type($Tid_TDid{1}{$ClassId}, $ClassId, 1);
8297 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$ClassName}}))
8298 { # check replacements, including pure virtual methods
8299 my $AddedPos = $VirtualTable{2}{$ClassName}{$AddedVFunc};
8300 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008301 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008302 my $RemovedPos = $VirtualTable{1}{$ClassName}{$RemovedVFunc};
8303 if($AddedPos==$RemovedPos)
8304 {
8305 $VirtualReplacement{$AddedVFunc} = $RemovedVFunc;
8306 $VirtualReplacement{$RemovedVFunc} = $AddedVFunc;
8307 last; # other methods will be reported as "added" or "removed"
8308 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008309 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008310 if(my $RemovedVFunc = $VirtualReplacement{$AddedVFunc})
8311 {
8312 if(lc($AddedVFunc) eq lc($RemovedVFunc))
8313 { # skip: DomUi => DomUI parameter (Qt 4.2.3 to 4.3.0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008314 next;
8315 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008316 my $ProblemType = "Virtual_Replacement";
8317 my @Affected = ($RemovedVFunc);
8318 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
8319 { # pure methods
8320 if(not isUsedClass($ClassId, 1, $Level))
8321 { # not a parameter of some exported method
8322 next;
8323 }
8324 $ProblemType = "Pure_Virtual_Replacement";
8325 @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008326 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008327 foreach my $AffectedInt (@Affected)
8328 {
8329 if($CompleteSignature{1}{$AffectedInt}{"PureVirt"})
8330 { # affected exported methods only
8331 next;
8332 }
8333 %{$CompatProblems{$Level}{$AffectedInt}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
8334 "Type_Name"=>$Class_Type{"Name"},
8335 "Type_Type"=>"Class",
8336 "Target"=>get_Signature($AddedVFunc, 2),
8337 "Old_Value"=>get_Signature($RemovedVFunc, 1));
8338 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008339 }
8340 }
8341 }
8342 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008343 if(not checkDumpVersion(1, "2.0")
8344 or not checkDumpVersion(2, "2.0"))
8345 { # support for old ABI dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008346 # "Base" attribute introduced in ACC 1.22 (dump 2.0 format)
8347 return;
8348 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008349 foreach my $ClassName (sort keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008350 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008351 my $ClassId_Old = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008352 next if(not $ClassId_Old);
8353 if(not isCreatable($ClassId_Old, 1))
8354 { # skip classes without public constructors (including auto-generated)
8355 # example: class has only a private exported or private inline constructor
8356 next;
8357 }
8358 if($ClassName=~/>/)
8359 { # skip affected template instances
8360 next;
8361 }
8362 my %Class_Old = get_Type($Tid_TDid{1}{$ClassId_Old}, $ClassId_Old, 1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008363 my $ClassId_New = $TName_Tid{2}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008364 next if(not $ClassId_New);
8365 my %Class_New = get_Type($Tid_TDid{2}{$ClassId_New}, $ClassId_New, 2);
8366 my @Bases_Old = sort {$Class_Old{"Base"}{$a}{"pos"}<=>$Class_Old{"Base"}{$b}{"pos"}} keys(%{$Class_Old{"Base"}});
8367 my @Bases_New = sort {$Class_New{"Base"}{$a}{"pos"}<=>$Class_New{"Base"}{$b}{"pos"}} keys(%{$Class_New{"Base"}});
8368 my ($BNum1, $BNum2) = (1, 1);
8369 my %BasePos_Old = map {get_TypeName($_, 1) => $BNum1++} @Bases_Old;
8370 my %BasePos_New = map {get_TypeName($_, 2) => $BNum2++} @Bases_New;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008371 my %ShortBase_Old = map {get_ShortType($_, 1) => 1} @Bases_Old;
8372 my %ShortBase_New = map {get_ShortType($_, 2) => 1} @Bases_New;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008373 my $Shift_Old = getShift($ClassId_Old, 1);
8374 my $Shift_New = getShift($ClassId_New, 2);
8375 my %BaseId_New = map {get_TypeName($_, 2) => $_} @Bases_New;
8376 my ($Added, $Removed) = (0, 0);
8377 my @StableBases_Old = ();
8378 foreach my $BaseId (@Bases_Old)
8379 {
8380 my $BaseName = get_TypeName($BaseId, 1);
8381 if($BasePos_New{$BaseName}) {
8382 push(@StableBases_Old, $BaseId);
8383 }
8384 elsif(not $ShortBase_New{$BaseName}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008385 and not $ShortBase_New{get_ShortType($BaseId, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008386 { # removed base
8387 # excluding namespace::SomeClass to SomeClass renaming
8388 my $ProblemKind = "Removed_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008389 if($Level eq "Binary")
8390 { # Binary-level
8391 if($Shift_Old ne $Shift_New)
8392 { # affected fields
8393 if(havePubFields(\%Class_Old)) {
8394 $ProblemKind .= "_And_Shift";
8395 }
8396 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
8397 $ProblemKind .= "_And_Size";
8398 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008399 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008400 if(keys(%{$VirtualTable_Model{1}{$BaseName}})
8401 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008402 { # affected v-table
8403 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008404 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008405 }
8406 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008407 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008408 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
8409 {
8410 my $SubName = get_TypeName($SubId, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008411 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008412 if($ProblemKind=~/VTable/) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008413 $VTableChanged_M{$SubName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008414 }
8415 }
8416 foreach my $Interface (@Affected)
8417 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008418 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008419 "Type_Name"=>$ClassName,
8420 "Type_Type"=>"Class",
8421 "Target"=>$BaseName,
8422 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
8423 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
8424 "Shift"=>abs($Shift_New-$Shift_Old) );
8425 }
8426 $Removed+=1;
8427 }
8428 }
8429 my @StableBases_New = ();
8430 foreach my $BaseId (@Bases_New)
8431 {
8432 my $BaseName = get_TypeName($BaseId, 2);
8433 if($BasePos_Old{$BaseName}) {
8434 push(@StableBases_New, $BaseId);
8435 }
8436 elsif(not $ShortBase_Old{$BaseName}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008437 and not $ShortBase_Old{get_ShortType($BaseId, 2)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008438 { # added base
8439 # excluding namespace::SomeClass to SomeClass renaming
8440 my $ProblemKind = "Added_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008441 if($Level eq "Binary")
8442 { # Binary-level
8443 if($Shift_Old ne $Shift_New)
8444 { # affected fields
8445 if(havePubFields(\%Class_Old)) {
8446 $ProblemKind .= "_And_Shift";
8447 }
8448 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
8449 $ProblemKind .= "_And_Size";
8450 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008451 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008452 if(keys(%{$VirtualTable_Model{2}{$BaseName}})
8453 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008454 { # affected v-table
8455 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008456 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008457 }
8458 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008459 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008460 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
8461 {
8462 my $SubName = get_TypeName($SubId, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008463 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008464 if($ProblemKind=~/VTable/) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008465 $VTableChanged_M{$SubName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008466 }
8467 }
8468 foreach my $Interface (@Affected)
8469 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008470 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008471 "Type_Name"=>$ClassName,
8472 "Type_Type"=>"Class",
8473 "Target"=>$BaseName,
8474 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
8475 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
8476 "Shift"=>abs($Shift_New-$Shift_Old) );
8477 }
8478 $Added+=1;
8479 }
8480 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008481 if($Level eq "Binary")
8482 { # Binary-level
8483 ($BNum1, $BNum2) = (1, 1);
8484 my %BaseRelPos_Old = map {get_TypeName($_, 1) => $BNum1++} @StableBases_Old;
8485 my %BaseRelPos_New = map {get_TypeName($_, 2) => $BNum2++} @StableBases_New;
8486 foreach my $BaseId (@Bases_Old)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008487 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008488 my $BaseName = get_TypeName($BaseId, 1);
8489 if(my $NewPos = $BaseRelPos_New{$BaseName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008490 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008491 my $BaseNewId = $BaseId_New{$BaseName};
8492 my $OldPos = $BaseRelPos_Old{$BaseName};
8493 if($NewPos!=$OldPos)
8494 { # changed position of the base class
8495 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008496 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008497 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Position"}{"this"}}=(
8498 "Type_Name"=>$ClassName,
8499 "Type_Type"=>"Class",
8500 "Target"=>$BaseName,
8501 "Old_Value"=>$OldPos-1,
8502 "New_Value"=>$NewPos-1 );
8503 }
8504 }
8505 if($Class_Old{"Base"}{$BaseId}{"virtual"}
8506 and not $Class_New{"Base"}{$BaseNewId}{"virtual"})
8507 { # became non-virtual base
8508 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
8509 {
8510 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Non_Virtually_Inherited"}{"this->".$BaseName}}=(
8511 "Type_Name"=>$ClassName,
8512 "Type_Type"=>"Class",
8513 "Target"=>$BaseName );
8514 }
8515 }
8516 elsif(not $Class_Old{"Base"}{$BaseId}{"virtual"}
8517 and $Class_New{"Base"}{$BaseNewId}{"virtual"})
8518 { # became virtual base
8519 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
8520 {
8521 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Virtually_Inherited"}{"this->".$BaseName}}=(
8522 "Type_Name"=>$ClassName,
8523 "Type_Type"=>"Class",
8524 "Target"=>$BaseName );
8525 }
8526 }
8527 }
8528 }
8529 # detect size changes in base classes
8530 if($Shift_Old!=$Shift_New)
8531 { # size of allocable class
8532 foreach my $BaseId (@StableBases_Old)
8533 { # search for changed base
8534 my %BaseType = get_Type($Tid_TDid{1}{$BaseId}, $BaseId, 1);
8535 my $Size_Old = get_TypeSize($BaseId, 1);
8536 my $Size_New = get_TypeSize($BaseId_New{$BaseType{"Name"}}, 2);
8537 if($Size_Old ne $Size_New
8538 and $Size_Old and $Size_New)
8539 {
8540 my $ProblemType = "";
8541 if(isCopyingClass($BaseId, 1)) {
8542 $ProblemType = "Size_Of_Copying_Class";
8543 }
8544 elsif($AllocableClass{1}{$BaseType{"Name"}})
8545 {
8546 if($Size_New>$Size_Old)
8547 { # increased size
8548 $ProblemType = "Size_Of_Allocable_Class_Increased";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008549 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008550 else
8551 { # decreased size
8552 $ProblemType = "Size_Of_Allocable_Class_Decreased";
8553 if(not havePubFields(\%Class_Old))
8554 { # affected class has no public members
8555 next;
8556 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008557 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008558 }
8559 next if(not $ProblemType);
8560 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
8561 { # base class size changes affecting current class
8562 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{"this->".$BaseType{"Name"}}}=(
8563 "Type_Name"=>$BaseType{"Name"},
8564 "Type_Type"=>"Class",
8565 "Target"=>$BaseType{"Name"},
8566 "Old_Size"=>$Size_Old*$BYTE_SIZE,
8567 "New_Size"=>$Size_New*$BYTE_SIZE );
8568 }
8569 }
8570 }
8571 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008572 if(defined $VirtualTable{1}{$ClassName}
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008573 and cmpVTables_Real($ClassName, 1)==1
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008574 and my @VFunctions = keys(%{$VirtualTable{1}{$ClassName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008575 { # compare virtual tables size in base classes
8576 my $VShift_Old = getVShift($ClassId_Old, 1);
8577 my $VShift_New = getVShift($ClassId_New, 2);
8578 if($VShift_Old ne $VShift_New)
8579 { # changes in the base class or changes in the list of base classes
8580 my @AllBases_Old = get_base_classes($ClassId_Old, 1, 1);
8581 my @AllBases_New = get_base_classes($ClassId_New, 2, 1);
8582 ($BNum1, $BNum2) = (1, 1);
8583 my %StableBase = map {get_TypeName($_, 2) => $_} @AllBases_New;
8584 foreach my $BaseId (@AllBases_Old)
8585 {
8586 my %BaseType = get_Type($Tid_TDid{1}{$BaseId}, $BaseId, 1);
8587 if(not $StableBase{$BaseType{"Name"}})
8588 { # lost base
8589 next;
8590 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008591 my $VSize_Old = getVTable_Size($BaseType{"Name"}, 1);
8592 my $VSize_New = getVTable_Size($BaseType{"Name"}, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008593 if($VSize_Old!=$VSize_New)
8594 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008595 foreach my $Interface (@VFunctions)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008596 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008597 if(not defined $VirtualTable{2}{$ClassName}{$Interface})
8598 { # Removed_Virtual_Method, will be registered in mergeVirtualTables()
8599 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008600 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008601 if($VirtualTable_Model{2}{$ClassName}{$Interface}-$VirtualTable_Model{1}{$ClassName}{$Interface}==0)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008602 { # skip interfaces that have not changed the absolute virtual position
8603 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008604 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008605 if(not $CheckHeadersOnly)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008606 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008607 if(not link_symbol($Interface, 1, "-Deps"))
8608 { # affected symbols in shared library
8609 next;
8610 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008611 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008612 $VTableChanged_M{$BaseType{"Name"}} = 1;
8613 $VTableChanged_M{$ClassName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008614 foreach my $VirtFunc (keys(%{$AddedInt_Virt{$Level}{$BaseType{"Name"}}}))
8615 { # the reason of the layout change: added virtual functions
8616 next if($VirtualReplacement{$VirtFunc});
8617 my $ProblemType = "Added_Virtual_Method";
8618 if($CompleteSignature{2}{$VirtFunc}{"PureVirt"}) {
8619 $ProblemType = "Added_Pure_Virtual_Method";
8620 }
8621 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{get_Signature($VirtFunc, 2)}}=(
8622 "Type_Name"=>$BaseType{"Name"},
8623 "Type_Type"=>"Class",
8624 "Target"=>get_Signature($VirtFunc, 2) );
8625 }
8626 foreach my $VirtFunc (keys(%{$RemovedInt_Virt{$Level}{$BaseType{"Name"}}}))
8627 { # the reason of the layout change: removed virtual functions
8628 next if($VirtualReplacement{$VirtFunc});
8629 my $ProblemType = "Removed_Virtual_Method";
8630 if($CompleteSignature{1}{$VirtFunc}{"PureVirt"}) {
8631 $ProblemType = "Removed_Pure_Virtual_Method";
8632 }
8633 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{get_Signature($VirtFunc, 1)}}=(
8634 "Type_Name"=>$BaseType{"Name"},
8635 "Type_Type"=>"Class",
8636 "Target"=>get_Signature($VirtFunc, 1) );
8637 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008638 }
8639 }
8640 }
8641 }
8642 }
8643 }
8644 }
8645}
8646
8647sub isCreatable($$)
8648{
8649 my ($ClassId, $LibVersion) = @_;
8650 if($AllocableClass{$LibVersion}{get_TypeName($ClassId, $LibVersion)}
8651 or isCopyingClass($ClassId, $LibVersion)) {
8652 return 1;
8653 }
8654 if(keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
8655 { # Fix for incomplete data: if this class has
8656 # a base class then it should also has a constructor
8657 return 1;
8658 }
8659 if($ReturnedClass{$LibVersion}{$ClassId})
8660 { # returned by some method of this class
8661 # or any other class
8662 return 1;
8663 }
8664 return 0;
8665}
8666
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008667sub isUsedClass($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008668{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008669 my ($ClassId, $LibVersion, $Level) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008670 if(keys(%{$ParamClass{$LibVersion}{$ClassId}}))
8671 { # parameter of some exported method
8672 return 1;
8673 }
8674 my $CName = get_TypeName($ClassId, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008675 if(keys(%{$ClassMethods{$Level}{1}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008676 { # method from target class
8677 return 1;
8678 }
8679 return 0;
8680}
8681
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008682sub mergeVirtualTables($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008683{ # check for changes in the virtual table
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008684 my ($Interface, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008685 # affected methods:
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008686 # - virtual
8687 # - pure-virtual
8688 # - non-virtual
8689 if($CompleteSignature{1}{$Interface}{"Data"})
8690 { # global data is not affected
8691 return;
8692 }
8693 my $Class_Id = $CompleteSignature{1}{$Interface}{"Class"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008694 if(not $Class_Id) {
8695 return;
8696 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008697 my $CName = get_TypeName($Class_Id, 1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008698 if(cmpVTables_Real($CName, 1)==0)
8699 { # no changes
8700 return;
8701 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008702 $CheckedTypes{$Level}{$CName} = 1;
8703 if($Level eq "Binary")
8704 { # Binary-level
8705 if($CompleteSignature{1}{$Interface}{"PureVirt"}
8706 and not isUsedClass($Class_Id, 1, $Level))
8707 { # pure virtuals should not be affected
8708 # if there are no exported methods using this class
8709 return;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008710 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008711 # check virtual table structure
8712 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
8713 {
8714 next if($Interface eq $AddedVFunc);
8715 next if($VirtualReplacement{$AddedVFunc});
8716 my $VPos_Added = $VirtualTable{2}{$CName}{$AddedVFunc};
8717 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
8718 { # pure virtual methods affect all others (virtual and non-virtual)
8719 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008720 "Type_Name"=>$CName,
8721 "Type_Type"=>"Class",
8722 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008723 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008724 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008725 elsif(not defined $VirtualTable{1}{$CName}
8726 or $VPos_Added>keys(%{$VirtualTable{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008727 { # added virtual function at the end of v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008728 if(not keys(%{$VirtualTable_Model{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008729 { # became polymorphous class, added v-table pointer
8730 %{$CompatProblems{$Level}{$Interface}{"Added_First_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008731 "Type_Name"=>$CName,
8732 "Type_Type"=>"Class",
8733 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008734 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008735 }
8736 else
8737 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008738 my $VSize_Old = getVTable_Size($CName, 1);
8739 my $VSize_New = getVTable_Size($CName, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008740 next if($VSize_Old==$VSize_New);# exception: register as removed and added virtual method
8741 if(isCopyingClass($Class_Id, 1))
8742 { # class has no constructors and v-table will be copied by applications, this may affect all methods
8743 my $ProblemType = "Added_Virtual_Method";
8744 if(isLeafClass($Class_Id, 1)) {
8745 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Copying_Class";
8746 }
8747 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
8748 "Type_Name"=>$CName,
8749 "Type_Type"=>"Class",
8750 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008751 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008752 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008753 else
8754 {
8755 my $ProblemType = "Added_Virtual_Method";
8756 if(isLeafClass($Class_Id, 1)) {
8757 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Allocable_Class";
8758 }
8759 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
8760 "Type_Name"=>$CName,
8761 "Type_Type"=>"Class",
8762 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008763 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008764 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008765 }
8766 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008767 elsif($CompleteSignature{1}{$Interface}{"Virt"}
8768 or $CompleteSignature{1}{$Interface}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008769 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008770 if(defined $VirtualTable{1}{$CName}
8771 and defined $VirtualTable{2}{$CName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008772 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008773 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
8774 my $VPos_New = $VirtualTable{2}{$CName}{$Interface};
8775 if($VPos_Added<=$VPos_Old and $VPos_Old!=$VPos_New)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008776 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008777 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
8778 foreach my $ASymbol (@Affected)
8779 {
8780 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"}
8781 and not link_symbol($ASymbol, 1, "-Deps")) {
8782 next;
8783 }
8784 $CheckedSymbols{$Level}{$ASymbol} = 1;
8785 %{$CompatProblems{$Level}{$ASymbol}{"Added_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
8786 "Type_Name"=>$CName,
8787 "Type_Type"=>"Class",
8788 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008789 $VTableChanged_M{get_TypeName($CompleteSignature{1}{$ASymbol}{"Class"}, 1)} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008790 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008791 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008792 }
8793 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008794 else {
8795 # safe
8796 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008797 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008798 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
8799 {
8800 next if($VirtualReplacement{$RemovedVFunc});
8801 if($RemovedVFunc eq $Interface
8802 and $CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
8803 { # This case is for removed virtual methods
8804 # implemented in both versions of a library
8805 next;
8806 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008807 if(not keys(%{$VirtualTable_Model{2}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008808 { # became non-polymorphous class, removed v-table pointer
8809 %{$CompatProblems{$Level}{$Interface}{"Removed_Last_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
8810 "Type_Name"=>$CName,
8811 "Type_Type"=>"Class",
8812 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008813 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008814 }
8815 elsif($CompleteSignature{1}{$Interface}{"Virt"}
8816 or $CompleteSignature{1}{$Interface}{"PureVirt"})
8817 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008818 if(defined $VirtualTable{1}{$CName} and defined $VirtualTable{2}{$CName})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008819 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008820 if(not defined $VirtualTable{1}{$CName}{$Interface}) {
8821 next;
8822 }
8823 my $VPos_New = -1;
8824 if(defined $VirtualTable{2}{$CName}{$Interface})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008825 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008826 $VPos_New = $VirtualTable{2}{$CName}{$Interface};
8827 }
8828 else
8829 {
8830 if($Interface ne $RemovedVFunc) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008831 next;
8832 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008833 }
8834 my $VPos_Removed = $VirtualTable{1}{$CName}{$RemovedVFunc};
8835 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
8836 if($VPos_Removed<=$VPos_Old and $VPos_Old!=$VPos_New)
8837 {
8838 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
8839 foreach my $ASymbol (@Affected)
8840 {
8841 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"}
8842 and not link_symbol($ASymbol, 1, "-Deps")) {
8843 next;
8844 }
8845 my $ProblemType = "Removed_Virtual_Method";
8846 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) {
8847 $ProblemType = "Removed_Pure_Virtual_Method";
8848 }
8849 $CheckedSymbols{$Level}{$ASymbol} = 1;
8850 %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$RemovedVFunc}}}=(
8851 "Type_Name"=>$CName,
8852 "Type_Type"=>"Class",
8853 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008854 $VTableChanged_M{get_TypeName($CompleteSignature{1}{$ASymbol}{"Class"}, 1)} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008855 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008856 }
8857 }
8858 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008859 }
8860 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008861 else
8862 { # Source-level
8863 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008864 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008865 next if($Interface eq $AddedVFunc);
8866 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008867 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008868 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
8869 "Type_Name"=>$CName,
8870 "Type_Type"=>"Class",
8871 "Target"=>get_Signature($AddedVFunc, 2) );
8872 }
8873 }
8874 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
8875 {
8876 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
8877 {
8878 %{$CompatProblems{$Level}{$Interface}{"Removed_Pure_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
8879 "Type_Name"=>$CName,
8880 "Type_Type"=>"Class",
8881 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008882 }
8883 }
8884 }
8885}
8886
8887sub find_MemberPair_Pos_byName($$)
8888{
8889 my ($Member_Name, $Pair_Type) = @_;
8890 $Member_Name=~s/\A[_]+|[_]+\Z//g;
8891 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
8892 {
8893 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos})
8894 {
8895 my $Name = $Pair_Type->{"Memb"}{$MemberPair_Pos}{"name"};
8896 $Name=~s/\A[_]+|[_]+\Z//g;
8897 if($Name eq $Member_Name) {
8898 return $MemberPair_Pos;
8899 }
8900 }
8901 }
8902 return "lost";
8903}
8904
8905sub find_MemberPair_Pos_byVal($$)
8906{
8907 my ($Member_Value, $Pair_Type) = @_;
8908 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
8909 {
8910 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos}
8911 and $Pair_Type->{"Memb"}{$MemberPair_Pos}{"value"} eq $Member_Value) {
8912 return $MemberPair_Pos;
8913 }
8914 }
8915 return "lost";
8916}
8917
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008918my %Severity_Val=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008919 "High"=>3,
8920 "Medium"=>2,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008921 "Low"=>1,
8922 "Safe"=>-1
8923);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008924
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008925sub maxSeverity($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008926{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008927 my ($S1, $S2) = @_;
8928 if(cmpSeverities($S1, $S2)) {
8929 return $S1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008930 }
8931 else {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008932 return $S2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008933 }
8934}
8935
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008936sub cmpSeverities($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008937{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008938 my ($S1, $S2) = @_;
8939 if(not $S1) {
8940 return 0;
8941 }
8942 elsif(not $S2) {
8943 return 1;
8944 }
8945 return ($Severity_Val{$S1}>$Severity_Val{$S2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008946}
8947
8948sub getProblemSeverity($$)
8949{
8950 my ($Level, $Kind) = @_;
8951 return $CompatRules{$Level}{$Kind}{"Severity"};
8952}
8953
8954sub isRecurType($$$$)
8955{
8956 foreach (@RecurTypes)
8957 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008958 if( $_->{"1"} eq $_[0]
8959 and $_->{"2"} eq $_[1]
8960 and $_->{"3"} eq $_[2]
8961 and $_->{"4"} eq $_[3] )
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008962 {
8963 return 1;
8964 }
8965 }
8966 return 0;
8967}
8968
8969sub pushType($$$$)
8970{
8971 my %TypeIDs=(
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008972 "1" => $_[0], #Tid1
8973 "2" => $_[1], #TDid1
8974 "3" => $_[2], #Tid2
8975 "4" => $_[3] #TDid2
8976 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008977 push(@RecurTypes, \%TypeIDs);
8978}
8979
8980sub isRenamed($$$$$)
8981{
8982 my ($MemPos, $Type1, $LVersion1, $Type2, $LVersion2) = @_;
8983 my $Member_Name = $Type1->{"Memb"}{$MemPos}{"name"};
8984 my $MemberType_Id = $Type1->{"Memb"}{$MemPos}{"type"};
8985 my %MemberType_Pure = get_PureType($Tid_TDid{$LVersion1}{$MemberType_Id}, $MemberType_Id, $LVersion1);
8986 if(not defined $Type2->{"Memb"}{$MemPos}) {
8987 return "";
8988 }
8989 my $StraightPairType_Id = $Type2->{"Memb"}{$MemPos}{"type"};
8990 my %StraightPairType_Pure = get_PureType($Tid_TDid{$LVersion2}{$StraightPairType_Id}, $StraightPairType_Id, $LVersion2);
8991
8992 my $StraightPair_Name = $Type2->{"Memb"}{$MemPos}{"name"};
8993 my $MemberPair_Pos_Rev = ($Member_Name eq $StraightPair_Name)?$MemPos:find_MemberPair_Pos_byName($StraightPair_Name, $Type1);
8994 if($MemberPair_Pos_Rev eq "lost")
8995 {
8996 if($MemberType_Pure{"Name"} eq $StraightPairType_Pure{"Name"})
8997 {# base type match
8998 return $StraightPair_Name;
8999 }
9000 if(get_TypeName($MemberType_Id, $LVersion1) eq get_TypeName($StraightPairType_Id, $LVersion2))
9001 {# exact type match
9002 return $StraightPair_Name;
9003 }
9004 if($MemberType_Pure{"Size"} eq $StraightPairType_Pure{"Size"})
9005 {# size match
9006 return $StraightPair_Name;
9007 }
9008 if(isReserved($StraightPair_Name))
9009 {# reserved fields
9010 return $StraightPair_Name;
9011 }
9012 }
9013 return "";
9014}
9015
9016sub isLastElem($$)
9017{
9018 my ($Pos, $TypeRef) = @_;
9019 my $Name = $TypeRef->{"Memb"}{$Pos}{"name"};
9020 if($Name=~/last|count|max|total/i)
9021 { # GST_LEVEL_COUNT, GST_RTSP_ELAST
9022 return 1;
9023 }
9024 elsif($Name=~/END|NLIMITS\Z/)
9025 { # __RLIMIT_NLIMITS
9026 return 1;
9027 }
9028 elsif($Name=~/\AN[A-Z](.+)[a-z]+s\Z/
9029 and $Pos+1==keys(%{$TypeRef->{"Memb"}}))
9030 { # NImageFormats, NColorRoles
9031 return 1;
9032 }
9033 return 0;
9034}
9035
9036sub nonComparable($$)
9037{
9038 my ($T1, $T2) = @_;
9039 if($T1->{"Name"} ne $T2->{"Name"}
9040 and not isAnon($T1->{"Name"})
9041 and not isAnon($T2->{"Name"}))
9042 { # different names
9043 if($T1->{"Type"} ne "Pointer"
9044 or $T2->{"Type"} ne "Pointer")
9045 { # compare base types
9046 return 1;
9047 }
9048 if($T1->{"Name"}!~/\Avoid\s*\*/
9049 and $T2->{"Name"}=~/\Avoid\s*\*/)
9050 {
9051 return 1;
9052 }
9053 }
9054 elsif($T1->{"Type"} ne $T2->{"Type"})
9055 { # different types
9056 if($T1->{"Type"} eq "Class"
9057 and $T2->{"Type"} eq "Struct")
9058 { # "class" to "struct"
9059 return 0;
9060 }
9061 elsif($T2->{"Type"} eq "Class"
9062 and $T1->{"Type"} eq "Struct")
9063 { # "struct" to "class"
9064 return 0;
9065 }
9066 else
9067 { # "class" to "enum"
9068 # "union" to "class"
9069 # ...
9070 return 1;
9071 }
9072 }
9073 return 0;
9074}
9075
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009076sub mergeTypes($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009077{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009078 my ($Type1_Id, $Type1_DId, $Type2_Id, $Type2_DId, $Level) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009079 return () if((not $Type1_Id and not $Type1_DId) or (not $Type2_Id and not $Type2_DId));
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009080 $Type1_DId = "" if(not defined $Type1_DId);
9081 $Type2_DId = "" if(not defined $Type2_DId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009082 my (%Sub_SubProblems, %SubProblems) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009083 if($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type1_DId}{$Type2_Id}{$Type2_DId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009084 { # already merged
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009085 return %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type1_DId}{$Type2_Id}{$Type2_DId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009086 }
9087 my %Type1 = get_Type($Type1_DId, $Type1_Id, 1);
9088 my %Type2 = get_Type($Type2_DId, $Type2_Id, 2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009089 if(not $Type1{"Name"} or not $Type2{"Name"}) {
9090 return ();
9091 }
9092 $CheckedTypes{$Level}{$Type1{"Name"}}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009093 my %Type1_Pure = get_PureType($Type1_DId, $Type1_Id, 1);
9094 my %Type2_Pure = get_PureType($Type2_DId, $Type2_Id, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009095 $CheckedTypes{$Level}{$Type1_Pure{"Name"}}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009096 return () if(not $Type1_Pure{"Size"} or not $Type2_Pure{"Size"});
9097 if(isRecurType($Type1_Pure{"Tid"}, $Type1_Pure{"TDid"}, $Type2_Pure{"Tid"}, $Type2_Pure{"TDid"}))
9098 { # skip recursive declarations
9099 return ();
9100 }
9101 return () if(not $Type1_Pure{"Name"} or not $Type2_Pure{"Name"});
9102 return () if($SkipTypes{1}{$Type1_Pure{"Name"}});
9103 return () if($SkipTypes{1}{$Type1{"Name"}});
9104
9105 my %Typedef_1 = goToFirst($Type1{"TDid"}, $Type1{"Tid"}, 1, "Typedef");
9106 my %Typedef_2 = goToFirst($Type2{"TDid"}, $Type2{"Tid"}, 2, "Typedef");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009107 if(not $UseOldDumps and %Typedef_1 and %Typedef_2
9108 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef"
9109 and $Typedef_1{"Name"} eq $Typedef_2{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009110 {
9111 my %Base_1 = get_OneStep_BaseType($Typedef_1{"TDid"}, $Typedef_1{"Tid"}, 1);
9112 my %Base_2 = get_OneStep_BaseType($Typedef_2{"TDid"}, $Typedef_2{"Tid"}, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009113 if(differentDumps("G")
9114 or differentDumps("V"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009115 { # different GCC versions or different dumps
9116 $Base_1{"Name"} = uncover_typedefs($Base_1{"Name"}, 1);
9117 $Base_2{"Name"} = uncover_typedefs($Base_2{"Name"}, 2);
9118 # std::__va_list and __va_list
9119 $Base_1{"Name"}=~s/\A(\w+::)+//;
9120 $Base_2{"Name"}=~s/\A(\w+::)+//;
9121 $Base_1{"Name"} = formatName($Base_1{"Name"});
9122 $Base_2{"Name"} = formatName($Base_2{"Name"});
9123 }
9124 if($Base_1{"Name"}!~/anon\-/ and $Base_2{"Name"}!~/anon\-/
9125 and $Base_1{"Name"} ne $Base_2{"Name"})
9126 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009127 if($Level eq "Binary"
9128 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009129 {
9130 %{$SubProblems{"DataType_Size"}{$Typedef_1{"Name"}}}=(
9131 "Target"=>$Typedef_1{"Name"},
9132 "Type_Name"=>$Typedef_1{"Name"},
9133 "Type_Type"=>"Typedef",
9134 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
9135 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE );
9136 }
9137 %{$SubProblems{"Typedef_BaseType"}{$Typedef_1{"Name"}}}=(
9138 "Target"=>$Typedef_1{"Name"},
9139 "Type_Name"=>$Typedef_1{"Name"},
9140 "Type_Type"=>"Typedef",
9141 "Old_Value"=>$Base_1{"Name"},
9142 "New_Value"=>$Base_2{"Name"} );
9143 }
9144 }
9145 if(nonComparable(\%Type1_Pure, \%Type2_Pure))
9146 { # different types (reported in detectTypeChange(...))
9147 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
9148 and $Type1_Pure{"Type"} ne $Type2_Pure{"Type"}
9149 and $Type1_Pure{"Type"}!~/Intrinsic|Pointer|Ref|Typedef/)
9150 { # different type of the type
9151 %{$SubProblems{"DataType_Type"}{$Type1_Pure{"Name"}}}=(
9152 "Target"=>$Type1_Pure{"Name"},
9153 "Type_Name"=>$Type1_Pure{"Name"},
9154 "Type_Type"=>$Type1_Pure{"Type"},
9155 "Old_Value"=>lc($Type1_Pure{"Type"}),
9156 "New_Value"=>lc($Type2_Pure{"Type"}) );
9157 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009158 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type1_DId}{$Type2_Id}{$Type2_DId}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009159 return %SubProblems;
9160 }
9161 pushType($Type1_Pure{"Tid"}, $Type1_Pure{"TDid"},
9162 $Type2_Pure{"Tid"}, $Type2_Pure{"TDid"});
9163 if(($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
9164 or (isAnon($Type1_Pure{"Name"}) and isAnon($Type2_Pure{"Name"})))
9165 and $Type1_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
9166 { # checking size
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009167 if($Level eq "Binary"
9168 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009169 {
9170 my $ProblemKind = "DataType_Size";
9171 if($Type1_Pure{"Type"} eq "Class"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009172 and keys(%{$ClassMethods{$Level}{1}{$Type1_Pure{"Name"}}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009173 {
9174 if(isCopyingClass($Type1_Pure{"Tid"}, 1)) {
9175 $ProblemKind = "Size_Of_Copying_Class";
9176 }
9177 elsif($AllocableClass{1}{$Type1_Pure{"Name"}})
9178 {
9179 if(int($Type2_Pure{"Size"})>int($Type1_Pure{"Size"})) {
9180 $ProblemKind = "Size_Of_Allocable_Class_Increased";
9181 }
9182 else {
9183 # descreased size of allocable class
9184 # it has no special effects
9185 }
9186 }
9187 }
9188 %{$SubProblems{$ProblemKind}{$Type1_Pure{"Name"}}}=(
9189 "Target"=>$Type1_Pure{"Name"},
9190 "Type_Name"=>$Type1_Pure{"Name"},
9191 "Type_Type"=>$Type1_Pure{"Type"},
9192 "Old_Size"=>$Type1_Pure{"Size"}*$BYTE_SIZE,
9193 "New_Size"=>$Type2_Pure{"Size"}*$BYTE_SIZE,
9194 "InitialType_Type"=>$Type1_Pure{"Type"} );
9195 }
9196 }
9197 if($Type1_Pure{"BaseType"}{"Tid"} and $Type2_Pure{"BaseType"}{"Tid"})
9198 {# checking base types
9199 %Sub_SubProblems = mergeTypes($Type1_Pure{"BaseType"}{"Tid"}, $Type1_Pure{"BaseType"}{"TDid"},
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009200 $Type2_Pure{"BaseType"}{"Tid"}, $Type2_Pure{"BaseType"}{"TDid"}, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009201 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
9202 {
9203 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
9204 {
9205 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
9206 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
9207 }
9208 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{"InitialType_Type"} = $Type1_Pure{"Type"};
9209 }
9210 }
9211 }
9212 my (%AddedField, %RemovedField, %RenamedField, %RenamedField_Rev, %RelatedField, %RelatedField_Rev) = ();
9213 my %NameToPosA = map {$Type1_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type1_Pure{"Memb"}});
9214 my %NameToPosB = map {$Type2_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type2_Pure{"Memb"}});
9215 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
9216 { # detect removed and renamed fields
9217 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
9218 next if(not $Member_Name);
9219 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);
9220 if($MemberPair_Pos eq "lost")
9221 {
9222 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
9223 {
9224 if(isUnnamed($Member_Name))
9225 { # support for old-version dumps
9226 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009227 if(not checkDumpVersion(2, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009228 next;
9229 }
9230 }
9231 if(my $RenamedTo = isRenamed($Member_Pos, \%Type1_Pure, 1, \%Type2_Pure, 2))
9232 { # renamed
9233 $RenamedField{$Member_Pos}=$RenamedTo;
9234 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
9235 }
9236 else
9237 { # removed
9238 $RemovedField{$Member_Pos}=1;
9239 }
9240 }
9241 elsif($Type1_Pure{"Type"} eq "Enum")
9242 {
9243 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
9244 next if($Member_Value1 eq "");
9245 $MemberPair_Pos = find_MemberPair_Pos_byVal($Member_Value1, \%Type2_Pure);
9246 if($MemberPair_Pos ne "lost")
9247 { # renamed
9248 my $RenamedTo = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"name"};
9249 my $MemberPair_Pos_Rev = find_MemberPair_Pos_byName($RenamedTo, \%Type1_Pure);
9250 if($MemberPair_Pos_Rev eq "lost")
9251 {
9252 $RenamedField{$Member_Pos}=$RenamedTo;
9253 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
9254 }
9255 else {
9256 $RemovedField{$Member_Pos}=1;
9257 }
9258 }
9259 else
9260 { # removed
9261 $RemovedField{$Member_Pos}=1;
9262 }
9263 }
9264 }
9265 else
9266 { # related
9267 $RelatedField{$Member_Pos} = $MemberPair_Pos;
9268 $RelatedField_Rev{$MemberPair_Pos} = $Member_Pos;
9269 }
9270 }
9271 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
9272 { # detect added fields
9273 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
9274 next if(not $Member_Name);
9275 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);
9276 if($MemberPair_Pos eq "lost")
9277 {
9278 if(isUnnamed($Member_Name))
9279 { # support for old-version dumps
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009280 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
9281 if(not checkDumpVersion(1, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009282 next;
9283 }
9284 }
9285 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union|Enum)\Z/)
9286 {
9287 if(not $RenamedField_Rev{$Member_Pos})
9288 { # added
9289 $AddedField{$Member_Pos}=1;
9290 }
9291 }
9292 }
9293 }
9294 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
9295 { # detect moved fields
9296 my (%RelPos, %RelPosName, %AbsPos) = ();
9297 my $Pos = 0;
9298 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
9299 { # relative positions in 1st version
9300 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
9301 next if(not $Member_Name);
9302 if(not $RemovedField{$Member_Pos})
9303 { # old type without removed fields
9304 $RelPos{1}{$Member_Name}=$Pos;
9305 $RelPosName{1}{$Pos} = $Member_Name;
9306 $AbsPos{1}{$Pos++} = $Member_Pos;
9307 }
9308 }
9309 $Pos = 0;
9310 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
9311 { # relative positions in 2nd version
9312 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
9313 next if(not $Member_Name);
9314 if(not $AddedField{$Member_Pos})
9315 { # new type without added fields
9316 $RelPos{2}{$Member_Name}=$Pos;
9317 $RelPosName{2}{$Pos} = $Member_Name;
9318 $AbsPos{2}{$Pos++} = $Member_Pos;
9319 }
9320 }
9321 foreach my $Member_Name (keys(%{$RelPos{1}}))
9322 {
9323 my $RPos1 = $RelPos{1}{$Member_Name};
9324 my $AbsPos1 = $NameToPosA{$Member_Name};
9325 my $Member_Name2 = $Member_Name;
9326 if(my $RenamedTo = $RenamedField{$AbsPos1})
9327 { # renamed
9328 $Member_Name2 = $RenamedTo;
9329 }
9330 my $RPos2 = $RelPos{2}{$Member_Name2};
9331 if($RPos2 ne "" and $RPos1 ne $RPos2)
9332 { # different relative positions
9333 my $AbsPos2 = $NameToPosB{$Member_Name2};
9334 if($AbsPos1 ne $AbsPos2)
9335 { # different absolute positions
9336 my $ProblemType = "Moved_Field";
9337 if(not isPublic(\%Type1_Pure, $AbsPos1))
9338 { # may change layout and size of type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009339 if($Level eq "Source") {
9340 next;
9341 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009342 $ProblemType = "Moved_Private_Field";
9343 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009344 if($Level eq "Binary"
9345 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009346 { # affected size
9347 my $MemSize1 = get_TypeSize($Type1_Pure{"Memb"}{$AbsPos1}{"type"}, 1);
9348 my $MovedAbsPos = $AbsPos{1}{$RPos2};
9349 my $MemSize2 = get_TypeSize($Type1_Pure{"Memb"}{$MovedAbsPos}{"type"}, 1);
9350 if($MemSize1 ne $MemSize2) {
9351 $ProblemType .= "_And_Size";
9352 }
9353 }
9354 if($ProblemType eq "Moved_Private_Field") {
9355 next;
9356 }
9357 %{$SubProblems{$ProblemType}{$Member_Name}}=(
9358 "Target"=>$Member_Name,
9359 "Type_Name"=>$Type1_Pure{"Name"},
9360 "Type_Type"=>$Type1_Pure{"Type"},
9361 "Old_Value"=>$RPos1,
9362 "New_Value"=>$RPos2 );
9363 }
9364 }
9365 }
9366 }
9367 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009368 { # check older fields, public and private
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009369 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
9370 next if(not $Member_Name);
9371 if(my $RenamedTo = $RenamedField{$Member_Pos})
9372 { # renamed
9373 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
9374 {
9375 if(isPublic(\%Type1_Pure, $Member_Pos))
9376 {
9377 %{$SubProblems{"Renamed_Field"}{$Member_Name}}=(
9378 "Target"=>$Member_Name,
9379 "Type_Name"=>$Type1_Pure{"Name"},
9380 "Type_Type"=>$Type1_Pure{"Type"},
9381 "Old_Value"=>$Member_Name,
9382 "New_Value"=>$RenamedTo );
9383 }
9384 }
9385 elsif($Type1_Pure{"Type"} eq "Enum")
9386 {
9387 %{$SubProblems{"Enum_Member_Name"}{$Type1_Pure{"Memb"}{$Member_Pos}{"value"}}}=(
9388 "Target"=>$Type1_Pure{"Memb"}{$Member_Pos}{"value"},
9389 "Type_Name"=>$Type1_Pure{"Name"},
9390 "Type_Type"=>$Type1_Pure{"Type"},
9391 "Old_Value"=>$Member_Name,
9392 "New_Value"=>$RenamedTo );
9393 }
9394 }
9395 elsif($RemovedField{$Member_Pos})
9396 { # removed
9397 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
9398 {
9399 my $ProblemType = "Removed_Field";
9400 if(not isPublic(\%Type1_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009401 or isUnnamed($Member_Name))
9402 {
9403 if($Level eq "Source") {
9404 next;
9405 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009406 $ProblemType = "Removed_Private_Field";
9407 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009408 if($Level eq "Binary"
9409 and not isMemPadded($Member_Pos, -1, \%Type1_Pure, \%RemovedField, 1))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009410 {
9411 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
9412 { # affected fields
9413 if(getOffset($MNum-1, \%Type1_Pure, 1)!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, 2))
9414 { # changed offset
9415 $ProblemType .= "_And_Layout";
9416 }
9417 }
9418 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
9419 { # affected size
9420 $ProblemType .= "_And_Size";
9421 }
9422 }
9423 if($ProblemType eq "Removed_Private_Field") {
9424 next;
9425 }
9426 %{$SubProblems{$ProblemType}{$Member_Name}}=(
9427 "Target"=>$Member_Name,
9428 "Type_Name"=>$Type1_Pure{"Name"},
9429 "Type_Type"=>$Type1_Pure{"Type"} );
9430 }
9431 elsif($Type2_Pure{"Type"} eq "Union")
9432 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009433 if($Level eq "Binary"
9434 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009435 {
9436 %{$SubProblems{"Removed_Union_Field_And_Size"}{$Member_Name}}=(
9437 "Target"=>$Member_Name,
9438 "Type_Name"=>$Type1_Pure{"Name"},
9439 "Type_Type"=>$Type1_Pure{"Type"} );
9440 }
9441 else
9442 {
9443 %{$SubProblems{"Removed_Union_Field"}{$Member_Name}}=(
9444 "Target"=>$Member_Name,
9445 "Type_Name"=>$Type1_Pure{"Name"},
9446 "Type_Type"=>$Type1_Pure{"Type"} );
9447 }
9448 }
9449 elsif($Type1_Pure{"Type"} eq "Enum")
9450 {
9451 %{$SubProblems{"Enum_Member_Removed"}{$Member_Name}}=(
9452 "Target"=>$Member_Name,
9453 "Type_Name"=>$Type1_Pure{"Name"},
9454 "Type_Type"=>$Type1_Pure{"Type"},
9455 "Old_Value"=>$Member_Name );
9456 }
9457 }
9458 else
9459 { # changed
9460 my $MemberPair_Pos = $RelatedField{$Member_Pos};
9461 if($Type1_Pure{"Type"} eq "Enum")
9462 {
9463 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
9464 next if($Member_Value1 eq "");
9465 my $Member_Value2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"value"};
9466 next if($Member_Value2 eq "");
9467 if($Member_Value1 ne $Member_Value2)
9468 {
9469 my $ProblemType = "Enum_Member_Value";
9470 if(isLastElem($Member_Pos, \%Type1_Pure)) {
9471 $ProblemType = "Enum_Last_Member_Value";
9472 }
9473 %{$SubProblems{$ProblemType}{$Member_Name}}=(
9474 "Target"=>$Member_Name,
9475 "Type_Name"=>$Type1_Pure{"Name"},
9476 "Type_Type"=>$Type1_Pure{"Type"},
9477 "Old_Value"=>$Member_Value1,
9478 "New_Value"=>$Member_Value2 );
9479 }
9480 }
9481 elsif($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
9482 {
9483 my $MemberType1_Id = $Type1_Pure{"Memb"}{$Member_Pos}{"type"};
9484 my $MemberType2_Id = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"type"};
9485 my $SizeV1 = get_TypeSize($MemberType1_Id, 1)*$BYTE_SIZE;
9486 if(my $BSize1 = $Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}) {
9487 $SizeV1 = $BSize1;
9488 }
9489 my $SizeV2 = get_TypeSize($MemberType2_Id, 2)*$BYTE_SIZE;
9490 if(my $BSize2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}) {
9491 $SizeV2 = $BSize2;
9492 }
9493 my $MemberType1_Name = get_TypeName($MemberType1_Id, 1);
9494 my $MemberType2_Name = get_TypeName($MemberType2_Id, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009495 if($Level eq "Binary"
9496 and $SizeV1 ne $SizeV2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009497 {
9498 if($MemberType1_Name eq $MemberType2_Name or (isAnon($MemberType1_Name) and isAnon($MemberType2_Name))
9499 or ($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"} and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}))
9500 { # field size change (including anon-structures and unions)
9501 # - same types
9502 # - unnamed types
9503 # - bitfields
9504 my $ProblemType = "Field_Size";
9505 if(not isPublic(\%Type1_Pure, $Member_Pos)
9506 or isUnnamed($Member_Name))
9507 { # should not be accessed by applications, goes to "Low Severity"
9508 # example: "abidata" members in GStreamer types
9509 $ProblemType = "Private_".$ProblemType;
9510 }
9511 if(not isMemPadded($Member_Pos, get_TypeSize($MemberType2_Id, 2)*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, 1))
9512 { # check an effect
9513 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
9514 { # public fields after the current
9515 if(getOffset($MNum-1, \%Type1_Pure, 1)!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, 2))
9516 { # changed offset
9517 $ProblemType .= "_And_Layout";
9518 }
9519 }
9520 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
9521 $ProblemType .= "_And_Type_Size";
9522 }
9523 }
9524 if($ProblemType eq "Private_Field_Size")
9525 { # private field size with no effect
9526 $ProblemType = "";
9527 }
9528 if($ProblemType)
9529 { # register a problem
9530 %{$SubProblems{$ProblemType}{$Member_Name}}=(
9531 "Target"=>$Member_Name,
9532 "Type_Name"=>$Type1_Pure{"Name"},
9533 "Type_Type"=>$Type1_Pure{"Type"},
9534 "Old_Size"=>$SizeV1,
9535 "New_Size"=>$SizeV2);
9536 }
9537 }
9538 }
9539 if($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}
9540 or $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"})
9541 { # do NOT check bitfield type changes
9542 next;
9543 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009544 %Sub_SubProblems = detectTypeChange($MemberType1_Id, $MemberType2_Id, "Field", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009545 foreach my $ProblemType (keys(%Sub_SubProblems))
9546 {
9547 my $Old_Value = $Sub_SubProblems{$ProblemType}{"Old_Value"};
9548 my $New_Value = $Sub_SubProblems{$ProblemType}{"New_Value"};
9549 if($ProblemType eq "Field_Type"
9550 or $ProblemType eq "Field_Type_And_Size")
9551 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009552 if(checkDumpVersion(1, "2.6") and checkDumpVersion(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009553 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009554 if($Level eq "Binary")
9555 {
9556 if($Old_Value!~/(\A|\W)volatile(\W|\Z)/
9557 and $New_Value=~/(\A|\W)volatile(\W|\Z)/)
9558 { # non-"volatile" to "volatile"
9559 %{$Sub_SubProblems{"Field_Became_Volatile"}} = %{$Sub_SubProblems{$ProblemType}};
9560 }
9561 elsif($Old_Value=~/(\A|\W)volatile(\W|\Z)/
9562 and $New_Value!~/(\A|\W)volatile(\W|\Z)/)
9563 { # non-"volatile" to "volatile"
9564 %{$Sub_SubProblems{"Field_Became_NonVolatile"}} = %{$Sub_SubProblems{$ProblemType}};
9565 }
9566 }
9567 else
9568 { # Source
9569 if(removedQual($New_Value, $Old_Value, "volatile"))
9570 { # non-"volatile" to "volatile"
9571 %{$Sub_SubProblems{"Field_Became_Volatile"}} = %{$Sub_SubProblems{$ProblemType}};
9572 delete($Sub_SubProblems{$ProblemType});
9573 }
9574 elsif(removedQual($Old_Value, $New_Value, "volatile"))
9575 { # non-"volatile" to "volatile"
9576 %{$Sub_SubProblems{"Field_Became_NonVolatile"}} = %{$Sub_SubProblems{$ProblemType}};
9577 delete($Sub_SubProblems{$ProblemType});
9578 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009579 }
9580 }
9581 }
9582 }
9583 foreach my $ProblemType (keys(%Sub_SubProblems))
9584 {
9585 my $ProblemType_Init = $ProblemType;
9586 if($ProblemType eq "Field_Type_And_Size")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009587 { # Binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009588 if(not isPublic(\%Type1_Pure, $Member_Pos)
9589 or isUnnamed($Member_Name)) {
9590 $ProblemType = "Private_".$ProblemType;
9591 }
9592 if(not isMemPadded($Member_Pos, get_TypeSize($MemberType2_Id, 2)*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, 1))
9593 { # check an effect
9594 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
9595 { # public fields after the current
9596 if(getOffset($MNum-1, \%Type1_Pure, 1)!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, 2))
9597 { # changed offset
9598 $ProblemType .= "_And_Layout";
9599 }
9600 }
9601 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
9602 $ProblemType .= "_And_Type_Size";
9603 }
9604 }
9605 }
9606 else
9607 {
9608 if(not isPublic(\%Type1_Pure, $Member_Pos)
9609 or isUnnamed($Member_Name)) {
9610 next;
9611 }
9612 }
9613 if($ProblemType eq "Private_Field_Type_And_Size")
9614 { # private field change with no effect
9615 next;
9616 }
9617 %{$SubProblems{$ProblemType}{$Member_Name}}=(
9618 "Target"=>$Member_Name,
9619 "Type_Name"=>$Type1_Pure{"Name"},
9620 "Type_Type"=>$Type1_Pure{"Type"} );
9621 foreach my $Attr (keys(%{$Sub_SubProblems{$ProblemType_Init}}))
9622 { # other properties
9623 $SubProblems{$ProblemType}{$Member_Name}{$Attr} = $Sub_SubProblems{$ProblemType_Init}{$Attr};
9624 }
9625 }
9626 if(not isPublic(\%Type1_Pure, $Member_Pos))
9627 { # do NOT check internal type changes
9628 next;
9629 }
9630 if($MemberType1_Id and $MemberType2_Id)
9631 {# checking member type changes (replace)
9632 %Sub_SubProblems = mergeTypes($MemberType1_Id, $Tid_TDid{1}{$MemberType1_Id},
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009633 $MemberType2_Id, $Tid_TDid{2}{$MemberType2_Id}, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009634 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
9635 {
9636 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
9637 {
9638 my $NewLocation = ($Sub_SubLocation)?$Member_Name."->".$Sub_SubLocation:$Member_Name;
9639 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"IsInTypeInternals"}=1;
9640 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
9641 $SubProblems{$Sub_SubProblemType}{$NewLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
9642 }
9643 if($Sub_SubLocation!~/\-\>/) {
9644 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"Start_Type_Name"} = $MemberType1_Name;
9645 }
9646 }
9647 }
9648 }
9649 }
9650 }
9651 }
9652 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
9653 { # checking added members, public and private
9654 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
9655 next if(not $Member_Name);
9656 if($AddedField{$Member_Pos})
9657 { # added
9658 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
9659 {
9660 my $ProblemType = "Added_Field";
9661 if(not isPublic(\%Type2_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009662 or isUnnamed($Member_Name))
9663 {
9664 if($Level eq "Source") {
9665 next;
9666 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009667 $ProblemType = "Added_Private_Field";
9668 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009669 if($Level eq "Binary"
9670 and not isMemPadded($Member_Pos, -1, \%Type2_Pure, \%AddedField, 2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009671 {
9672 if(my $MNum = isAccessible(\%Type2_Pure, \%AddedField, $Member_Pos, -1))
9673 { # public fields after the current
9674 if(getOffset($MNum-1, \%Type2_Pure, 2)!=getOffset($RelatedField_Rev{$MNum-1}, \%Type1_Pure, 1))
9675 { # changed offset
9676 $ProblemType .= "_And_Layout";
9677 }
9678 }
9679 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
9680 $ProblemType .= "_And_Size";
9681 }
9682 }
9683 if($ProblemType eq "Added_Private_Field")
9684 { # skip added private fields
9685 next;
9686 }
9687 %{$SubProblems{$ProblemType}{$Member_Name}}=(
9688 "Target"=>$Member_Name,
9689 "Type_Name"=>$Type1_Pure{"Name"},
9690 "Type_Type"=>$Type1_Pure{"Type"} );
9691 }
9692 elsif($Type2_Pure{"Type"} eq "Union")
9693 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009694 if($Level eq "Binary"
9695 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009696 {
9697 %{$SubProblems{"Added_Union_Field_And_Size"}{$Member_Name}}=(
9698 "Target"=>$Member_Name,
9699 "Type_Name"=>$Type1_Pure{"Name"},
9700 "Type_Type"=>$Type1_Pure{"Type"} );
9701 }
9702 else
9703 {
9704 %{$SubProblems{"Added_Union_Field"}{$Member_Name}}=(
9705 "Target"=>$Member_Name,
9706 "Type_Name"=>$Type1_Pure{"Name"},
9707 "Type_Type"=>$Type1_Pure{"Type"} );
9708 }
9709 }
9710 elsif($Type2_Pure{"Type"} eq "Enum")
9711 {
9712 my $Member_Value = $Type2_Pure{"Memb"}{$Member_Pos}{"value"};
9713 next if($Member_Value eq "");
9714 %{$SubProblems{"Added_Enum_Member"}{$Member_Name}}=(
9715 "Target"=>$Member_Name,
9716 "Type_Name"=>$Type2_Pure{"Name"},
9717 "Type_Type"=>$Type2_Pure{"Type"},
9718 "New_Value"=>$Member_Value );
9719 }
9720 }
9721 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009722 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type1_DId}{$Type2_Id}{$Type2_DId}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009723 pop(@RecurTypes);
9724 return %SubProblems;
9725}
9726
9727sub isUnnamed($) {
9728 return $_[0]=~/\Aunnamed\d+\Z/;
9729}
9730
9731sub get_TypeName($$)
9732{
9733 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009734 return get_TypeAttr($TypeId, $LibVersion, "Name");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009735}
9736
9737sub get_TypeSize($$)
9738{
9739 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009740 return get_TypeAttr($TypeId, $LibVersion, "Size");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009741}
9742
9743sub get_TypeAttr($$$)
9744{
9745 my ($TypeId, $LibVersion, $Attr) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009746 return "" if(not defined $TypeId);
9747 if(not defined $Tid_TDid{$LibVersion}{$TypeId})
9748 { # correcting data
9749 $Tid_TDid{$LibVersion}{$TypeId} = "";
9750 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009751 return $TypeInfo{$LibVersion}{$Tid_TDid{$LibVersion}{$TypeId}}{$TypeId}{$Attr};
9752}
9753
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009754sub get_ShortType($$)
9755{
9756 my ($TypeId, $LibVersion) = @_;
9757 my $TypeName = get_TypeAttr($TypeId, $LibVersion, "Name");
9758 if(my $NameSpace = get_TypeAttr($TypeId, $LibVersion, "NameSpace")) {
9759 $TypeName=~s/\A$NameSpace\:\://g;
9760 }
9761 return $TypeName;
9762}
9763
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009764sub goToFirst($$$$)
9765{
9766 my ($TypeDId, $TypeId, $LibVersion, $Type_Type) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009767 return () if(not $TypeId);
9768 $TypeDId = "" if(not defined $TypeDId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009769 if(defined $Cache{"goToFirst"}{$TypeDId}{$TypeId}{$LibVersion}{$Type_Type}) {
9770 return %{$Cache{"goToFirst"}{$TypeDId}{$TypeId}{$LibVersion}{$Type_Type}};
9771 }
9772 return () if(not $TypeInfo{$LibVersion}{$TypeDId}{$TypeId});
9773 my %Type = %{$TypeInfo{$LibVersion}{$TypeDId}{$TypeId}};
9774 return () if(not $Type{"Type"});
9775 if($Type{"Type"} ne $Type_Type)
9776 {
9777 return () if(not $Type{"BaseType"}{"TDid"} and not $Type{"BaseType"}{"Tid"});
9778 %Type = goToFirst($Type{"BaseType"}{"TDid"}, $Type{"BaseType"}{"Tid"}, $LibVersion, $Type_Type);
9779 }
9780 $Cache{"goToFirst"}{$TypeDId}{$TypeId}{$LibVersion}{$Type_Type} = \%Type;
9781 return %Type;
9782}
9783
9784my %TypeSpecAttributes = (
9785 "Const" => 1,
9786 "Volatile" => 1,
9787 "ConstVolatile" => 1,
9788 "Restrict" => 1,
9789 "Typedef" => 1
9790);
9791
9792sub get_PureType($$$)
9793{
9794 my ($TypeDId, $TypeId, $LibVersion) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009795 return () if(not $TypeId);
9796 $TypeDId = "" if(not defined $TypeDId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009797 if(defined $Cache{"get_PureType"}{$TypeDId}{$TypeId}{$LibVersion}) {
9798 return %{$Cache{"get_PureType"}{$TypeDId}{$TypeId}{$LibVersion}};
9799 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009800 return () if(not $TypeInfo{$LibVersion}{$TypeDId}{$TypeId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009801 my %Type = %{$TypeInfo{$LibVersion}{$TypeDId}{$TypeId}};
9802 return %Type if(not $Type{"BaseType"}{"TDid"} and not $Type{"BaseType"}{"Tid"});
9803 if($TypeSpecAttributes{$Type{"Type"}}) {
9804 %Type = get_PureType($Type{"BaseType"}{"TDid"}, $Type{"BaseType"}{"Tid"}, $LibVersion);
9805 }
9806 $Cache{"get_PureType"}{$TypeDId}{$TypeId}{$LibVersion} = \%Type;
9807 return %Type;
9808}
9809
9810sub get_PointerLevel($$$)
9811{
9812 my ($TypeDId, $TypeId, $LibVersion) = @_;
9813 return 0 if(not $TypeId);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009814 $TypeDId = "" if(not defined $TypeDId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009815 if(defined $Cache{"get_PointerLevel"}{$TypeDId}{$TypeId}{$LibVersion}) {
9816 return $Cache{"get_PointerLevel"}{$TypeDId}{$TypeId}{$LibVersion};
9817 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009818 return 0 if(not $TypeInfo{$LibVersion}{$TypeDId}{$TypeId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009819 my %Type = %{$TypeInfo{$LibVersion}{$TypeDId}{$TypeId}};
9820 return 1 if($Type{"Type"}=~/FuncPtr|MethodPtr|FieldPtr/);
9821 return 0 if(not $Type{"BaseType"}{"TDid"} and not $Type{"BaseType"}{"Tid"});
9822 my $PointerLevel = 0;
9823 if($Type{"Type"} =~/Pointer|Ref|FuncPtr|MethodPtr|FieldPtr/) {
9824 $PointerLevel += 1;
9825 }
9826 $PointerLevel += get_PointerLevel($Type{"BaseType"}{"TDid"}, $Type{"BaseType"}{"Tid"}, $LibVersion);
9827 $Cache{"get_PointerLevel"}{$TypeDId}{$TypeId}{$LibVersion} = $PointerLevel;
9828 return $PointerLevel;
9829}
9830
9831sub get_BaseType($$$)
9832{
9833 my ($TypeDId, $TypeId, $LibVersion) = @_;
9834 return () if(not $TypeId);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009835 $TypeDId = "" if(not defined $TypeDId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009836 if(defined $Cache{"get_BaseType"}{$TypeDId}{$TypeId}{$LibVersion}) {
9837 return %{$Cache{"get_BaseType"}{$TypeDId}{$TypeId}{$LibVersion}};
9838 }
9839 return () if(not $TypeInfo{$LibVersion}{$TypeDId}{$TypeId});
9840 my %Type = %{$TypeInfo{$LibVersion}{$TypeDId}{$TypeId}};
9841 return %Type if(not $Type{"BaseType"}{"TDid"} and not $Type{"BaseType"}{"Tid"});
9842 %Type = get_BaseType($Type{"BaseType"}{"TDid"}, $Type{"BaseType"}{"Tid"}, $LibVersion);
9843 $Cache{"get_BaseType"}{$TypeDId}{$TypeId}{$LibVersion} = \%Type;
9844 return %Type;
9845}
9846
9847sub get_BaseTypeQual($$$)
9848{
9849 my ($TypeDId, $TypeId, $LibVersion) = @_;
9850 return "" if(not $TypeId);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009851 $TypeDId = "" if(not defined $TypeDId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009852 return "" if(not $TypeInfo{$LibVersion}{$TypeDId}{$TypeId});
9853 my %Type = %{$TypeInfo{$LibVersion}{$TypeDId}{$TypeId}};
9854 return "" if(not $Type{"BaseType"}{"TDid"} and not $Type{"BaseType"}{"Tid"});
9855 my $Qual = "";
9856 if($Type{"Type"} eq "Pointer") {
9857 $Qual .= "*";
9858 }
9859 elsif($Type{"Type"} eq "Ref") {
9860 $Qual .= "&";
9861 }
9862 elsif($Type{"Type"} eq "ConstVolatile") {
9863 $Qual .= "const volatile";
9864 }
9865 elsif($Type{"Type"} eq "Const"
9866 or $Type{"Type"} eq "Volatile"
9867 or $Type{"Type"} eq "Restrict") {
9868 $Qual .= lc($Type{"Type"});
9869 }
9870 my $BQual = get_BaseTypeQual($Type{"BaseType"}{"TDid"}, $Type{"BaseType"}{"Tid"}, $LibVersion);
9871 return $BQual.$Qual;
9872}
9873
9874sub get_OneStep_BaseType($$$)
9875{
9876 my ($TypeDId, $TypeId, $LibVersion) = @_;
9877 return () if(not $TypeId);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009878 $TypeDId = "" if(not defined $TypeDId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009879 return () if(not $TypeInfo{$LibVersion}{$TypeDId}{$TypeId});
9880 my %Type = %{$TypeInfo{$LibVersion}{$TypeDId}{$TypeId}};
9881 if(not $Type{"BaseType"}{"TDid"}
9882 and not $Type{"BaseType"}{"Tid"}) {
9883 return %Type;
9884 }
9885 return get_Type($Type{"BaseType"}{"TDid"}, $Type{"BaseType"}{"Tid"}, $LibVersion);
9886}
9887
9888sub get_Type($$$)
9889{
9890 my ($TypeDId, $TypeId, $LibVersion) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009891 return () if(not $TypeId);
9892 $TypeDId = "" if(not defined $TypeDId);
9893 return () if(not $TypeInfo{$LibVersion}{$TypeDId}{$TypeId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009894 return %{$TypeInfo{$LibVersion}{$TypeDId}{$TypeId}};
9895}
9896
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009897sub skipPrivateData($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009898{
9899 my $Symbol = $_[0];
9900 return ($Symbol=~/\A(_ZGV|_ZTI|_ZTS|_ZTT|_ZTV|_ZTC|_ZThn|_ZTv0_n)/);
9901}
9902
9903sub isTemplateInstance($)
9904{
9905 my $Symbol = $_[0];
9906 return 0 if($Symbol!~/\A(_Z|\?)/);
9907 my $Signature = $tr_name{$Symbol};
9908 return 0 if($Signature!~/>/);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009909 my $ShortName = substr($Signature, 0, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009910 $ShortName=~s/::operator .*//;# class::operator template<instance>
9911 return ($ShortName=~/<.+>/);
9912}
9913
9914sub isTemplateSpec($$)
9915{
9916 my ($Symbol, $LibVersion) = @_;
9917 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
9918 {
9919 if(get_TypeAttr($ClassId, $LibVersion, "Spec"))
9920 { # class specialization
9921 return 1;
9922 }
9923 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Spec"})
9924 { # method specialization
9925 return 1;
9926 }
9927 }
9928 return 0;
9929}
9930
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009931sub symbolFilter($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009932{ # some special cases when the symbol cannot be imported
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009933 my ($Symbol, $LibVersion, $Type, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009934 if(skipPrivateData($Symbol))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009935 { # non-public global data
9936 return 0;
9937 }
9938 if($CheckObjectsOnly) {
9939 return 0 if($Symbol=~/\A(_init|_fini)\Z/);
9940 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009941 if($CheckHeadersOnly and not checkDumpVersion($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009942 { # support for old ABI dumps in --headers-only mode
9943 foreach my $Pos (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
9944 {
9945 if(my $Pid = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"})
9946 {
9947 my $PType = get_TypeAttr($Pid, $LibVersion, "Type");
9948 if(not $PType or $PType eq "Unknown") {
9949 return 0;
9950 }
9951 }
9952 }
9953 }
9954 if($Type=~/Imported/)
9955 {
9956 my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"};
9957 if(not $STDCXX_TESTING and $Symbol=~/\A(_ZS|_ZNS|_ZNKS)/)
9958 { # stdc++ interfaces
9959 return 0;
9960 }
9961 if($SkipSymbols{$LibVersion}{$Symbol})
9962 { # user defined symbols to ignore
9963 return 0;
9964 }
9965 my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"};
9966 if(not $NameSpace and $ClassId)
9967 { # class methods have no "NameSpace" attribute
9968 $NameSpace = get_TypeAttr($ClassId, $LibVersion, "NameSpace");
9969 }
9970 if($NameSpace)
9971 { # user defined namespaces to ignore
9972 if($SkipNameSpaces{$LibVersion}{$NameSpace}) {
9973 return 0;
9974 }
9975 foreach my $NS (keys(%{$SkipNameSpaces{$LibVersion}}))
9976 { # nested namespaces
9977 if($NameSpace=~/\A\Q$NS\E(\:\:|\Z)/) {
9978 return 0;
9979 }
9980 }
9981 }
9982 if(my $Header = $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
9983 {
9984 if(my $Skip = skip_header($Header, $LibVersion))
9985 { # --skip-headers or <skip_headers> (not <skip_including>)
9986 if($Skip==1) {
9987 return 0;
9988 }
9989 }
9990 if(not is_target_header($Header))
9991 { # --header, --headers-list
9992 return 0;
9993 }
9994 }
9995 if($SymbolsListPath and not $SymbolsList{$Symbol})
9996 { # user defined symbols
9997 return 0;
9998 }
9999 if($AppPath and not $SymbolsList_App{$Symbol})
10000 { # user defined symbols (in application)
10001 return 0;
10002 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010003 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010004 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010005 if($CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
10006 or (isTemplateInstance($Symbol) and not isTemplateSpec($Symbol, $LibVersion)))
10007 {
10008 if($ClassId and $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
10009 { # inline virtual methods
10010 if($Type=~/InlineVirtual/) {
10011 return 1;
10012 }
10013 my $Allocable = (not isCopyingClass($ClassId, $LibVersion));
10014 if(not $Allocable)
10015 { # check bases
10016 foreach my $DCId (get_sub_classes($ClassId, $LibVersion, 1))
10017 {
10018 if(not isCopyingClass($DCId, $LibVersion))
10019 { # exists a derived class without default c-tor
10020 $Allocable=1;
10021 last;
10022 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010023 }
10024 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010025 if(not $Allocable) {
10026 return 0;
10027 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010028 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010029 else
10030 { # inline non-virtual methods
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010031 return 0;
10032 }
10033 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010034 }
10035 }
10036 return 1;
10037}
10038
10039sub mergeImpl()
10040{
10041 my $DiffCmd = get_CmdPath("diff");
10042 if(not $DiffCmd) {
10043 exitStatus("Not_Found", "can't find \"diff\"");
10044 }
10045 foreach my $Interface (sort keys(%{$Symbol_Library{1}}))
10046 { # implementation changes
10047 next if($CompleteSignature{1}{$Interface}{"Private"});
10048 next if(not $CompleteSignature{1}{$Interface}{"Header"} and not $CheckObjectsOnly);
10049 next if(not $Symbol_Library{2}{$Interface} and not $Symbol_Library{2}{$SymVer{2}{$Interface}});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010050 next if(not symbolFilter($Interface, 1, "Imported", "Binary"));
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010051 my $Impl1 = canonifyImpl($Interface_Impl{1}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010052 next if(not $Impl1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010053 my $Impl2 = canonifyImpl($Interface_Impl{2}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010054 next if(not $Impl2);
10055 if($Impl1 ne $Impl2)
10056 {
10057 writeFile("$TMP_DIR/impl1", $Impl1);
10058 writeFile("$TMP_DIR/impl2", $Impl2);
10059 my $Diff = `$DiffCmd -rNau $TMP_DIR/impl1 $TMP_DIR/impl2`;
10060 $Diff=~s/(---|\+\+\+).+\n//g;
10061 $Diff=~s/[ ]{3,}/ /g;
10062 $Diff=~s/\n\@\@/\n \n\@\@/g;
10063 unlink("$TMP_DIR/impl1", "$TMP_DIR/impl2");
10064 %{$ImplProblems{$Interface}}=(
10065 "Diff" => get_CodeView($Diff) );
10066 }
10067 }
10068}
10069
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010070sub canonifyImpl($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010071{
10072 my $FuncBody= $_[0];
10073 return "" if(not $FuncBody);
10074 $FuncBody=~s/0x[a-f\d]+/0x?/g;# addr
10075 $FuncBody=~s/((\A|\n)[a-z]+[\t ]+)[a-f\d]+([^x]|\Z)/$1?$3/g;# call, jump
10076 $FuncBody=~s/# [a-f\d]+ /# ? /g;# call, jump
10077 $FuncBody=~s/%([a-z]+[a-f\d]*)/\%reg/g;# registers
10078 while($FuncBody=~s/\nnop[ \t]*(\n|\Z)/$1/g){};# empty op
10079 $FuncBody=~s/<.+?\.cpp.+?>/<name.cpp>/g;
10080 $FuncBody=~s/(\A|\n)[a-f\d]+ </$1? </g;# 5e74 <_ZN...
10081 $FuncBody=~s/\.L\d+/.L/g;
10082 $FuncBody=~s/#(-?)\d+/#$1?/g;# r3, [r3, #120]
10083 $FuncBody=~s/[\n]{2,}/\n/g;
10084 return $FuncBody;
10085}
10086
10087sub get_CodeView($)
10088{
10089 my $Code = $_[0];
10090 my $View = "";
10091 foreach my $Line (split(/\n/, $Code))
10092 {
10093 if($Line=~s/\A(\+|-)/$1 /g)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010094 { # bold line
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010095 $View .= "<tr><td><b>".htmlSpecChars($Line)."</b></td></tr>\n";
10096 }
10097 else {
10098 $View .= "<tr><td>".htmlSpecChars($Line)."</td></tr>\n";
10099 }
10100 }
10101 return "<table class='code_view'>$View</table>\n";
10102}
10103
10104sub getImplementations($$)
10105{
10106 my ($LibVersion, $Path) = @_;
10107 return if(not $LibVersion or not -e $Path);
10108 if($OSgroup eq "macos")
10109 {
10110 my $OtoolCmd = get_CmdPath("otool");
10111 if(not $OtoolCmd) {
10112 exitStatus("Not_Found", "can't find \"otool\"");
10113 }
10114 my $CurInterface = "";
10115 foreach my $Line (split(/\n/, `$OtoolCmd -tv $Path 2>$TMP_DIR/null`))
10116 {
10117 if($Line=~/\A\s*_(\w+)\s*:/i) {
10118 $CurInterface = $1;
10119 }
10120 elsif($Line=~/\A\s*[\da-z]+\s+(.+?)\Z/i) {
10121 $Interface_Impl{$LibVersion}{$CurInterface} .= "$1\n";
10122 }
10123 }
10124 }
10125 else
10126 {
10127 my $ObjdumpCmd = get_CmdPath("objdump");
10128 if(not $ObjdumpCmd) {
10129 exitStatus("Not_Found", "can't find \"objdump\"");
10130 }
10131 my $CurInterface = "";
10132 foreach my $Line (split(/\n/, `$ObjdumpCmd -d $Path 2>$TMP_DIR/null`))
10133 {
10134 if($Line=~/\A[\da-z]+\s+<(\w+)>/i) {
10135 $CurInterface = $1;
10136 }
10137 else
10138 { # x86: 51fa:(\t)89 e5 (\t)mov %esp,%ebp
10139 # arm: 5020:(\t)e24cb004(\t)sub(\t)fp, ip, #4(\t); 0x4
10140 if($Line=~/\A\s*[a-f\d]+:\s+([a-f\d]+\s+)+([a-z]+\s+.*?)\s*(;.*|)\Z/i) {
10141 $Interface_Impl{$LibVersion}{$CurInterface} .= "$2\n";
10142 }
10143 }
10144 }
10145 }
10146}
10147
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010148sub detectAdded($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010149{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010150 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010151 foreach my $Symbol (keys(%{$Symbol_Library{2}}))
10152 {
10153 if(link_symbol($Symbol, 1, "+Deps"))
10154 { # linker can find a new symbol
10155 # in the old-version library
10156 # So, it's not a new symbol
10157 next;
10158 }
10159 if(my $VSym = $SymVer{2}{$Symbol}
10160 and $Symbol!~/\@/) {
10161 next;
10162 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010163 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010164 }
10165}
10166
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010167sub detectRemoved($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010168{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010169 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010170 foreach my $Symbol (keys(%{$Symbol_Library{1}}))
10171 {
10172 if($CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010173 $CheckedSymbols{"Binary"}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010174 }
10175 if(link_symbol($Symbol, 2, "+Deps"))
10176 { # linker can find an old symbol
10177 # in the new-version library
10178 next;
10179 }
10180 if(my $VSym = $SymVer{1}{$Symbol}
10181 and $Symbol!~/\@/) {
10182 next;
10183 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010184 $RemovedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010185 }
10186}
10187
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010188sub mergeLibs($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010189{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010190 my $Level = $_[0];
10191 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010192 { # checking added symbols
10193 next if($CompleteSignature{2}{$Symbol}{"Private"});
10194 next if(not $CompleteSignature{2}{$Symbol}{"Header"} and not $CheckObjectsOnly);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010195 next if(not symbolFilter($Symbol, 2, "Imported", $Level));
10196 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010197 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010198 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010199 { # checking removed symbols
10200 next if($CompleteSignature{1}{$Symbol}{"Private"});
10201 next if(not $CompleteSignature{1}{$Symbol}{"Header"} and not $CheckObjectsOnly);
10202 if($Symbol=~/\A_ZTV/)
10203 { # skip v-tables for templates, that should not be imported by applications
10204 next if($tr_name{$Symbol}=~/</);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010205 if(my $CName = $VTableClass{$Symbol})
10206 {
10207 if(not keys(%{$ClassMethods{$Level}{1}{$CName}}))
10208 { # vtables for "private" classes
10209 # use case: vtable for QDragManager (Qt 4.5.3 to 4.6.0) became HIDDEN symbol
10210 next;
10211 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010212 }
10213 }
10214 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010215 next if(not symbolFilter($Symbol, 1, "Imported", $Level));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010216 }
10217 if($CompleteSignature{1}{$Symbol}{"PureVirt"})
10218 { # symbols for pure virtual methods cannot be called by clients
10219 next;
10220 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010221 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010222 }
10223}
10224
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010225sub checkDumpVersion($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010226{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010227 my ($LibVersion, $DumpVersion) = @_;
10228 return (not $UsedDump{$LibVersion}{"V"} or cmpVersions($UsedDump{$LibVersion}{"V"}, $DumpVersion)>=0);
10229}
10230
10231sub detectAdded_H($)
10232{
10233 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010234 foreach my $Symbol (sort keys(%{$CompleteSignature{2}}))
10235 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010236 if($Level eq "Source")
10237 { # remove symbol version
10238 my ($SN, $SS, $SV) = separate_symbol($Symbol);
10239 $Symbol=$SN;
10240 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010241 if(not $CompleteSignature{2}{$Symbol}{"Header"}
10242 or not $CompleteSignature{2}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010243 next;
10244 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010245 if($GeneratedSymbols{$Symbol}) {
10246 next;
10247 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010248 if(not defined $CompleteSignature{1}{$Symbol}
10249 or not $CompleteSignature{1}{$Symbol}{"MnglName"})
10250 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010251 if($UsedDump{2}{"SrcBin"})
10252 {
10253 if($UsedDump{1}{"BinOnly"} or not checkDumpVersion(1, "2.11"))
10254 { # support for old and different (!) ABI dumps
10255 if(not $CompleteSignature{2}{$Symbol}{"Virt"}
10256 and not $CompleteSignature{2}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010257 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010258 if($CheckHeadersOnly)
10259 { # skip all added symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010260 next;
10261 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010262 else
10263 {
10264 if(not link_symbol($Symbol, 2, "-Deps"))
10265 { # skip added inline symbols
10266 next;
10267 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010268 }
10269 }
10270 }
10271 }
10272 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010273 }
10274 }
10275}
10276
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010277sub detectRemoved_H($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010278{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010279 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010280 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
10281 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010282 if($Level eq "Source")
10283 { # remove symbol version
10284 my ($SN, $SS, $SV) = separate_symbol($Symbol);
10285 $Symbol=$SN;
10286 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010287 if(not $CompleteSignature{1}{$Symbol}{"Header"}
10288 or not $CompleteSignature{1}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010289 next;
10290 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010291 if($GeneratedSymbols{$Symbol}) {
10292 next;
10293 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010294 if(not defined $CompleteSignature{2}{$Symbol}
10295 or not $CompleteSignature{2}{$Symbol}{"MnglName"})
10296 { # support for old and different (!) ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010297 if($UsedDump{1}{"SrcBin"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010298 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010299 if($UsedDump{2}{"BinOnly"} or not checkDumpVersion(2, "2.11"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010300 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010301 if(not $CompleteSignature{1}{$Symbol}{"Virt"}
10302 and not $CompleteSignature{1}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010303 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010304 if($CheckHeadersOnly)
10305 { # skip all removed symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010306 next;
10307 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010308 else
10309 {
10310 if(not link_symbol($Symbol, 1, "-Deps"))
10311 { # skip removed inline symbols
10312 next;
10313 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010314 }
10315 }
10316 }
10317 }
10318 $RemovedInt{$Level}{$Symbol} = 1;
10319 if($Level eq "Source")
10320 { # search for a source-compatible equivalent
10321 setAlternative($Symbol, $Level);
10322 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010323 }
10324 }
10325}
10326
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010327sub mergeHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010328{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010329 my $Level = $_[0];
10330 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010331 { # checking added symbols
10332 next if($CompleteSignature{2}{$Symbol}{"PureVirt"});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010333 if($Level eq "Binary") {
10334 next if($CompleteSignature{2}{$Symbol}{"InLine"});
10335 }
10336 else
10337 { # Source
10338 if($SourceAlternative_B{$Symbol}) {
10339 next;
10340 }
10341 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010342 next if($CompleteSignature{2}{$Symbol}{"Private"});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010343 next if(not symbolFilter($Symbol, 2, "Imported", $Level));
10344 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010345 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010346 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010347 { # checking removed symbols
10348 next if($CompleteSignature{1}{$Symbol}{"PureVirt"});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010349 if($Level eq "Binary") {
10350 next if($CompleteSignature{1}{$Symbol}{"InLine"});
10351 }
10352 else
10353 { # Source
10354 if($SourceAlternative{$Symbol}) {
10355 next;
10356 }
10357 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010358 next if($CompleteSignature{1}{$Symbol}{"Private"});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010359 next if(not symbolFilter($Symbol, 1, "Imported", $Level));
10360 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010361 }
10362}
10363
10364sub addParamNames($)
10365{
10366 my $LibraryVersion = $_[0];
10367 return if(not keys(%AddIntParams));
10368 my $SecondVersion = $LibraryVersion==1?2:1;
10369 foreach my $Interface (sort keys(%{$CompleteSignature{$LibraryVersion}}))
10370 {
10371 next if(not keys(%{$AddIntParams{$Interface}}));
10372 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibraryVersion}{$Interface}{"Param"}}))
10373 {# add absent parameter names
10374 my $ParamName = $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"};
10375 if($ParamName=~/\Ap\d+\Z/ and my $NewParamName = $AddIntParams{$Interface}{$ParamPos})
10376 {# names from the external file
10377 if(defined $CompleteSignature{$SecondVersion}{$Interface}
10378 and defined $CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos})
10379 {
10380 if($CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos}{"name"}=~/\Ap\d+\Z/) {
10381 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
10382 }
10383 }
10384 else {
10385 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
10386 }
10387 }
10388 }
10389 }
10390}
10391
10392sub detectChangedTypedefs()
10393{ # detect changed typedefs to create correct function signatures
10394 foreach my $Typedef (keys(%{$Typedef_BaseName{1}}))
10395 {
10396 next if(not $Typedef);
10397 next if(isAnon($Typedef_BaseName{1}{$Typedef}));
10398 next if(isAnon($Typedef_BaseName{2}{$Typedef}));
10399 next if(not $Typedef_BaseName{1}{$Typedef});
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010400 next if(not $Typedef_BaseName{2}{$Typedef}); # exclude added/removed
10401 if($Typedef_BaseName{1}{$Typedef} ne $Typedef_BaseName{2}{$Typedef})
10402 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010403 $ChangedTypedef{$Typedef} = 1;
10404 }
10405 }
10406}
10407
10408sub get_symbol_suffix($$)
10409{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010410 my ($Symbol, $Full) = @_;
10411 my ($SN, $SO, $SV) = separate_symbol($Symbol);
10412 $Symbol=$SN;# remove version
10413 my $Signature = $tr_name{$Symbol};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010414 my $Suffix = substr($Signature, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010415 if(not $Full) {
10416 $Suffix=~s/(\))\s*(const volatile|volatile const|const|volatile)\Z/$1/g;
10417 }
10418 return $Suffix;
10419}
10420
10421sub get_symbol_prefix($$)
10422{
10423 my ($Symbol, $LibVersion) = @_;
10424 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
10425 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
10426 { # methods
10427 $ShortName = get_TypeName($ClassId, $LibVersion)."::".$ShortName;
10428 }
10429 return $ShortName;
10430}
10431
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010432sub setAlternative($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010433{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010434 my $Symbol = $_[0];
10435 my $PSymbol = $Symbol;
10436 if(not defined $CompleteSignature{2}{$PSymbol}
10437 or (not $CompleteSignature{2}{$PSymbol}{"MnglName"}
10438 and not $CompleteSignature{2}{$PSymbol}{"ShortName"}))
10439 { # search for a pair
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010440 if(my $ShortName = $CompleteSignature{1}{$PSymbol}{"ShortName"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010441 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010442 if($CompleteSignature{1}{$PSymbol}{"Data"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010443 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010444 if($PSymbol=~s/L(\d+$ShortName(E)\Z)/$1/
10445 or $PSymbol=~s/(\d+$ShortName(E)\Z)/L$1/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010446 {
10447 if(defined $CompleteSignature{2}{$PSymbol}
10448 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
10449 {
10450 $SourceAlternative{$Symbol} = $PSymbol;
10451 $SourceAlternative_B{$PSymbol} = $Symbol;
10452 if(not defined $CompleteSignature{1}{$PSymbol}
10453 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
10454 $SourceReplacement{$Symbol} = $PSymbol;
10455 }
10456 }
10457 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010458 }
10459 else
10460 {
10461 foreach my $Sp ("KV", "VK", "K", "V")
10462 {
10463 if($PSymbol=~s/\A_ZN$Sp/_ZN/
10464 or $PSymbol=~s/\A_ZN/_ZN$Sp/)
10465 {
10466 if(defined $CompleteSignature{2}{$PSymbol}
10467 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
10468 {
10469 $SourceAlternative{$Symbol} = $PSymbol;
10470 $SourceAlternative_B{$PSymbol} = $Symbol;
10471 if(not defined $CompleteSignature{1}{$PSymbol}
10472 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
10473 $SourceReplacement{$Symbol} = $PSymbol;
10474 }
10475 }
10476 }
10477 $PSymbol = $Symbol;
10478 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010479 }
10480 }
10481 }
10482 return "";
10483}
10484
10485sub mergeSignatures($)
10486{
10487 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010488 my %SubProblems = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010489
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010490 mergeBases($Level);
10491
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010492 my %AddedOverloads = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010493 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010494 { # check all added exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010495 if(not $CompleteSignature{2}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010496 next;
10497 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010498 if($CheckHeadersOnly or $Level eq "Source")
10499 {
10500 if(defined $CompleteSignature{1}{$Symbol}
10501 and $CompleteSignature{1}{$Symbol}{"Header"})
10502 { # double-check added symbol
10503 next;
10504 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010505 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010506 if(not symbolFilter($Symbol, 2, "Imported", $Level)) {
10507 next;
10508 }
10509 if($Symbol=~/\A(_Z|\?)/)
10510 { # C++
10511 $AddedOverloads{get_symbol_prefix($Symbol, 2)}{get_symbol_suffix($Symbol, 1)} = $Symbol;
10512 }
10513 if(my $OverriddenMethod = $CompleteSignature{2}{$Symbol}{"Override"})
10514 { # register virtual overridings
10515 my $AffectedClass_Name = get_TypeName($CompleteSignature{2}{$Symbol}{"Class"}, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010516 if(defined $CompleteSignature{1}{$OverriddenMethod}
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010517 and $CompleteSignature{1}{$OverriddenMethod}{"Virt"} and $TName_Tid{1}{$AffectedClass_Name}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010518 and not $CompleteSignature{1}{$OverriddenMethod}{"Private"})
10519 { # public virtual methods, virtual destructors: class should exist in previous version
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010520 if(isCopyingClass($TName_Tid{1}{$AffectedClass_Name}, 1))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010521 { # old v-table (copied) will be used by applications
10522 next;
10523 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010524 if(defined $CompleteSignature{1}{$Symbol}
10525 and $CompleteSignature{1}{$Symbol}{"InLine"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010526 { # auto-generated virtual destructors stay in the header (and v-table), added to library
10527 # use case: Ice 3.3.1 -> 3.4.0
10528 next;
10529 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010530 %{$CompatProblems{$Level}{$OverriddenMethod}{"Overridden_Virtual_Method"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010531 "Type_Name"=>$AffectedClass_Name,
10532 "Type_Type"=>"Class",
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010533 "Target"=>get_Signature($Symbol, 2),
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010534 "Old_Value"=>get_Signature($OverriddenMethod, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010535 "New_Value"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010536 }
10537 }
10538 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010539 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
10540 { # check all removed exported symbols
10541 if(not $CompleteSignature{1}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010542 next;
10543 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010544 if($CheckHeadersOnly or $Level eq "Source")
10545 {
10546 if(defined $CompleteSignature{2}{$Symbol}
10547 and $CompleteSignature{2}{$Symbol}{"Header"})
10548 { # double-check removed symbol
10549 next;
10550 }
10551 }
10552 if($CompleteSignature{1}{$Symbol}{"Private"})
10553 { # skip private methods
10554 next;
10555 }
10556 if(not symbolFilter($Symbol, 1, "Imported", $Level)) {
10557 next;
10558 }
10559 $CheckedSymbols{$Level}{$Symbol} = 1;
10560 if(my $OverriddenMethod = $CompleteSignature{1}{$Symbol}{"Override"})
10561 { # register virtual overridings
10562 my $AffectedClass_Name = get_TypeName($CompleteSignature{1}{$Symbol}{"Class"}, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010563 if(defined $CompleteSignature{2}{$OverriddenMethod}
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010564 and $CompleteSignature{2}{$OverriddenMethod}{"Virt"} and $TName_Tid{2}{$AffectedClass_Name})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010565 { # virtual methods, virtual destructors: class should exist in newer version
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010566 if(isCopyingClass($CompleteSignature{1}{$Symbol}{"Class"}, 1))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010567 { # old v-table (copied) will be used by applications
10568 next;
10569 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010570 if(defined $CompleteSignature{2}{$Symbol}
10571 and $CompleteSignature{2}{$Symbol}{"InLine"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010572 { # auto-generated virtual destructors stay in the header (and v-table), removed from library
10573 # use case: Ice 3.3.1 -> 3.4.0
10574 next;
10575 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010576 %{$CompatProblems{$Level}{$Symbol}{"Overridden_Virtual_Method_B"}{$tr_name{$OverriddenMethod}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010577 "Type_Name"=>$AffectedClass_Name,
10578 "Type_Type"=>"Class",
10579 "Target"=>get_Signature($OverriddenMethod, 1),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010580 "Old_Value"=>get_Signature($Symbol, 1),
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010581 "New_Value"=>get_Signature($OverriddenMethod, 1) );
10582 }
10583 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010584 if($Level eq "Binary"
10585 and $OSgroup eq "windows")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010586 { # register the reason of symbol name change
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010587 if(my $NewSymbol = $mangled_name{2}{$tr_name{$Symbol}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010588 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010589 if($AddedInt{$Level}{$NewSymbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010590 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010591 if($CompleteSignature{1}{$Symbol}{"Static"} ne $CompleteSignature{2}{$NewSymbol}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010592 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010593 if($CompleteSignature{2}{$NewSymbol}{"Static"})
10594 {
10595 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Static"}{$tr_name{$Symbol}}}=(
10596 "Target"=>$tr_name{$Symbol},
10597 "Old_Value"=>$Symbol,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010598 "New_Value"=>$NewSymbol );
10599 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010600 else
10601 {
10602 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonStatic"}{$tr_name{$Symbol}}}=(
10603 "Target"=>$tr_name{$Symbol},
10604 "Old_Value"=>$Symbol,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010605 "New_Value"=>$NewSymbol );
10606 }
10607 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010608 if($CompleteSignature{1}{$Symbol}{"Virt"} ne $CompleteSignature{2}{$NewSymbol}{"Virt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010609 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010610 if($CompleteSignature{2}{$NewSymbol}{"Virt"})
10611 {
10612 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Virtual"}{$tr_name{$Symbol}}}=(
10613 "Target"=>$tr_name{$Symbol},
10614 "Old_Value"=>$Symbol,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010615 "New_Value"=>$NewSymbol );
10616 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010617 else
10618 {
10619 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonVirtual"}{$tr_name{$Symbol}}}=(
10620 "Target"=>$tr_name{$Symbol},
10621 "Old_Value"=>$Symbol,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010622 "New_Value"=>$NewSymbol );
10623 }
10624 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010625 my $ReturnTypeName1 = get_TypeName($CompleteSignature{1}{$Symbol}{"Return"}, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010626 my $ReturnTypeName2 = get_TypeName($CompleteSignature{2}{$NewSymbol}{"Return"}, 2);
10627 if($ReturnTypeName1 ne $ReturnTypeName2)
10628 {
10629 my $ProblemType = "Symbol_Changed_Return";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010630 if($CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010631 $ProblemType = "Global_Data_Symbol_Changed_Type";
10632 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010633 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{$tr_name{$Symbol}}}=(
10634 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010635 "Old_Type"=>$ReturnTypeName1,
10636 "New_Type"=>$ReturnTypeName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010637 "Old_Value"=>$Symbol,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010638 "New_Value"=>$NewSymbol );
10639 }
10640 }
10641 }
10642 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010643 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010644 { # C++
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010645 my $Prefix = get_symbol_prefix($Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010646 if(my @Overloads = sort keys(%{$AddedOverloads{$Prefix}})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010647 and not $AddedOverloads{$Prefix}{get_symbol_suffix($Symbol, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010648 { # changed signature: params, "const"-qualifier
10649 my $NewSymbol = $AddedOverloads{$Prefix}{$Overloads[0]};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010650 if($CompleteSignature{1}{$Symbol}{"Constructor"})
10651 {
10652 if($Symbol=~/(C1E|C2E)/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010653 my $CtorType = $1;
10654 $NewSymbol=~s/(C1E|C2E)/$CtorType/g;
10655 }
10656 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010657 elsif($CompleteSignature{1}{$Symbol}{"Destructor"})
10658 {
10659 if($Symbol=~/(D0E|D1E|D2E)/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010660 my $DtorType = $1;
10661 $NewSymbol=~s/(D0E|D1E|D2E)/$DtorType/g;
10662 }
10663 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010664 my $NS1 = $CompleteSignature{1}{$Symbol}{"NameSpace"};
10665 my $NS2 = $CompleteSignature{2}{$NewSymbol}{"NameSpace"};
10666 if((not $NS1 and not $NS2) or ($NS1 and $NS2 and $NS1 eq $NS2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010667 { # from the same class and namespace
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010668 if($CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010669 and not $CompleteSignature{2}{$NewSymbol}{"Const"})
10670 { # "const" to non-"const"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010671 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonConst"}{$tr_name{$Symbol}}}=(
10672 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010673 "New_Signature"=>get_Signature($NewSymbol, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010674 "Old_Value"=>$Symbol,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010675 "New_Value"=>$NewSymbol );
10676 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010677 elsif(not $CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010678 and $CompleteSignature{2}{$NewSymbol}{"Const"})
10679 { # non-"const" to "const"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010680 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Const"}{$tr_name{$Symbol}}}=(
10681 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010682 "New_Signature"=>get_Signature($NewSymbol, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010683 "Old_Value"=>$Symbol,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010684 "New_Value"=>$NewSymbol );
10685 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010686 if($CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010687 and not $CompleteSignature{2}{$NewSymbol}{"Volatile"})
10688 { # "volatile" to non-"volatile"
10689
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010690 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonVolatile"}{$tr_name{$Symbol}}}=(
10691 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010692 "New_Signature"=>get_Signature($NewSymbol, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010693 "Old_Value"=>$Symbol,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010694 "New_Value"=>$NewSymbol );
10695 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010696 elsif(not $CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010697 and $CompleteSignature{2}{$NewSymbol}{"Volatile"})
10698 { # non-"volatile" to "volatile"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010699 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Volatile"}{$tr_name{$Symbol}}}=(
10700 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010701 "New_Signature"=>get_Signature($NewSymbol, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010702 "Old_Value"=>$Symbol,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010703 "New_Value"=>$NewSymbol );
10704 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010705 if(get_symbol_suffix($Symbol, 0) ne get_symbol_suffix($NewSymbol, 0))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010706 { # params list
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010707 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Changed_Parameters"}{$tr_name{$Symbol}}}=(
10708 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010709 "New_Signature"=>get_Signature($NewSymbol, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010710 "Old_Value"=>$Symbol,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010711 "New_Value"=>$NewSymbol );
10712 }
10713 }
10714 }
10715 }
10716 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010717 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
10718 { # checking symbols
10719 my ($SN, $SS, $SV) = separate_symbol($Symbol);
10720 if($Level eq "Source")
10721 { # remove symbol version
10722 $Symbol=$SN;
10723 }
10724 else
10725 { # Binary
10726 if(not $SV)
10727 { # symbol without version
10728 if(my $VSym = $SymVer{1}{$Symbol})
10729 { # the symbol is linked with versioned symbol
10730 if($CompleteSignature{2}{$VSym}{"MnglName"})
10731 { # show report for symbol@ver only
10732 next;
10733 }
10734 elsif(not link_symbol($VSym, 2, "-Deps"))
10735 { # changed version: sym@v1 to sym@v2
10736 # do NOT show report for symbol
10737 next;
10738 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010739 }
10740 }
10741 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010742 my $PSymbol = $Symbol;
10743 if($Level eq "Source"
10744 and my $S = $SourceReplacement{$Symbol})
10745 { # take a source-compatible replacement function
10746 $PSymbol = $S;
10747 }
10748 if($CompleteSignature{1}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010749 { # private symbols
10750 next;
10751 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010752 if(not defined $CompleteSignature{1}{$Symbol}
10753 or not defined $CompleteSignature{2}{$PSymbol})
10754 { # no info
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010755 next;
10756 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010757 if(not $CompleteSignature{1}{$Symbol}{"MnglName"}
10758 or not $CompleteSignature{2}{$PSymbol}{"MnglName"})
10759 { # no mangled name
10760 next;
10761 }
10762 if(not $CompleteSignature{1}{$Symbol}{"Header"}
10763 or not $CompleteSignature{2}{$PSymbol}{"Header"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010764 { # without a header
10765 next;
10766 }
10767 if($CheckHeadersOnly)
10768 { # skip added and removed pure virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010769 next if(not $CompleteSignature{1}{$Symbol}{"PureVirt"} and $CompleteSignature{2}{$PSymbol}{"PureVirt"});
10770 next if($CompleteSignature{1}{$Symbol}{"PureVirt"} and not $CompleteSignature{2}{$PSymbol}{"PureVirt"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010771 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010772 elsif($Level eq "Binary")
10773 { # skip non-exported, added and removed functions except pure virtual methods
10774 if(not link_symbol($Symbol, 1, "-Deps")
10775 or not link_symbol($PSymbol, 2, "-Deps"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010776 { # symbols from target library(ies) only
10777 # excluding dependent libraries
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010778 if(not $CompleteSignature{1}{$Symbol}{"PureVirt"}
10779 or not $CompleteSignature{2}{$PSymbol}{"PureVirt"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010780 next;
10781 }
10782 }
10783 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010784 if(not symbolFilter($Symbol, 1, "Imported|InlineVirtual", $Level))
10785 { # symbols that cannot be imported at binary-level
10786 # or used at source-level
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010787 next;
10788 }
10789 # checking virtual table
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010790 mergeVirtualTables($Symbol, $Level);
10791
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010792 if($COMPILE_ERRORS)
10793 { # if some errors occurred at the compiling stage
10794 # then some false positives can be skipped here
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010795 if(not $CompleteSignature{1}{$Symbol}{"Data"} and $CompleteSignature{2}{$PSymbol}{"Data"}
10796 and not $CompleteSignature{2}{$Symbol}{"Object"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010797 { # missed information about parameters in newer version
10798 next;
10799 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010800 if($CompleteSignature{1}{$Symbol}{"Data"} and not $CompleteSignature{1}{$Symbol}{"Object"}
10801 and not $CompleteSignature{2}{$PSymbol}{"Data"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010802 {# missed information about parameters in older version
10803 next;
10804 }
10805 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010806 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010807 # checking attributes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010808 if($CompleteSignature{2}{$PSymbol}{"Static"}
10809 and not $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/) {
10810 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Static"}{""}}=(
10811 "Target"=>get_Signature($Symbol, 1)
10812 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010813 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010814 elsif(not $CompleteSignature{2}{$PSymbol}{"Static"}
10815 and $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/) {
10816 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonStatic"}{""}}=(
10817 "Target"=>get_Signature($Symbol, 1)
10818 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010819 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010820 if(($CompleteSignature{1}{$Symbol}{"Virt"} and $CompleteSignature{2}{$PSymbol}{"Virt"})
10821 or ($CompleteSignature{1}{$Symbol}{"PureVirt"} and $CompleteSignature{2}{$PSymbol}{"PureVirt"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010822 { # relative position of virtual and pure virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010823 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010824 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010825 if(defined $CompleteSignature{1}{$Symbol}{"RelPos"} and defined $CompleteSignature{2}{$PSymbol}{"RelPos"}
10826 and $CompleteSignature{1}{$Symbol}{"RelPos"}!=$CompleteSignature{2}{$PSymbol}{"RelPos"})
10827 { # top-level virtual methods only
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010828 my $Class_Id = $CompleteSignature{1}{$Symbol}{"Class"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010829 my $Class_Name = get_TypeName($Class_Id, 1);
10830 if(defined $VirtualTable{1}{$Class_Name} and defined $VirtualTable{2}{$Class_Name}
10831 and $VirtualTable{1}{$Class_Name}{$Symbol}!=$VirtualTable{2}{$Class_Name}{$Symbol})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010832 { # check the absolute position of virtual method (including added and removed methods)
10833 my %Class_Type = get_Type($Tid_TDid{1}{$Class_Id}, $Class_Id, 1);
10834 my $ProblemType = "Virtual_Method_Position";
10835 if($CompleteSignature{1}{$Symbol}{"PureVirt"}) {
10836 $ProblemType = "Pure_Virtual_Method_Position";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010837 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010838 if(isUsedClass($Class_Id, 1, $Level))
10839 {
10840 my @Affected = ($Symbol, keys(%{$OverriddenMethods{1}{$Symbol}}));
10841 foreach my $AffectedInterface (@Affected)
10842 {
10843 %{$CompatProblems{$Level}{$AffectedInterface}{$ProblemType}{$tr_name{$MnglName}}}=(
10844 "Type_Name"=>$Class_Type{"Name"},
10845 "Type_Type"=>"Class",
10846 "Old_Value"=>$CompleteSignature{1}{$Symbol}{"RelPos"},
10847 "New_Value"=>$CompleteSignature{2}{$PSymbol}{"RelPos"},
10848 "Target"=>get_Signature($Symbol, 1) );
10849 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010850 $VTableChanged_M{$Class_Type{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010851 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010852 }
10853 }
10854 }
10855 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010856 if($CompleteSignature{1}{$Symbol}{"PureVirt"}
10857 or $CompleteSignature{2}{$PSymbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010858 { # do NOT check type changes in pure virtuals
10859 next;
10860 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010861 $CheckedSymbols{$Level}{$Symbol}=1;
10862 if($Symbol=~/\A(_Z|\?)/
10863 or keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})==keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010864 { # C/C++: changes in parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010865 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010866 { # checking parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010867 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010868 }
10869 }
10870 else
10871 { # C: added/removed parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010872 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010873 { # checking added parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010874 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
10875 last if(get_TypeName($PType2_Id, 2) eq "...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010876 my $Parameter_Name = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
10877 my $Parameter_OldName = (defined $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos})?$CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010878 my $ParamPos_Prev = "-1";
10879 if($Parameter_Name=~/\Ap\d+\Z/i)
10880 { # added unnamed parameter ( pN )
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010881 my @Positions1 = find_ParamPair_Pos_byTypeAndPos(get_TypeName($PType2_Id, 2), $ParamPos, "backward", $Symbol, 1);
10882 my @Positions2 = find_ParamPair_Pos_byTypeAndPos(get_TypeName($PType2_Id, 2), $ParamPos, "backward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010883 if($#Positions1==-1 or $#Positions2>$#Positions1) {
10884 $ParamPos_Prev = "lost";
10885 }
10886 }
10887 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010888 $ParamPos_Prev = find_ParamPair_Pos_byName($Parameter_Name, $Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010889 }
10890 if($ParamPos_Prev eq "lost")
10891 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010892 if($ParamPos>keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010893 {
10894 my $ProblemType = "Added_Parameter";
10895 if($Parameter_Name=~/\Ap\d+\Z/) {
10896 $ProblemType = "Added_Unnamed_Parameter";
10897 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010898 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showNum($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010899 "Target"=>$Parameter_Name,
10900 "Param_Pos"=>$ParamPos,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010901 "Param_Type"=>get_TypeName($PType2_Id, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010902 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010903 }
10904 else
10905 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010906 my %ParamType_Pure = get_PureType($Tid_TDid{2}{$PType2_Id}, $PType2_Id, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010907 my $ParamStraightPairType_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010908 my %ParamStraightPairType_Pure = get_PureType($Tid_TDid{1}{$ParamStraightPairType_Id}, $ParamStraightPairType_Id, 1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010909 if(($ParamType_Pure{"Name"} eq $ParamStraightPairType_Pure{"Name"} or get_TypeName($PType2_Id, 2) eq get_TypeName($ParamStraightPairType_Id, 1))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010910 and find_ParamPair_Pos_byName($Parameter_OldName, $Symbol, 2) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010911 {
10912 if($Parameter_OldName!~/\Ap\d+\Z/ and $Parameter_Name!~/\Ap\d+\Z/)
10913 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010914 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showNum($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010915 "Target"=>$Parameter_OldName,
10916 "Param_Pos"=>$ParamPos,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010917 "Param_Type"=>get_TypeName($PType2_Id, 2),
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010918 "Old_Value"=>$Parameter_OldName,
10919 "New_Value"=>$Parameter_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010920 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010921 }
10922 }
10923 else
10924 {
10925 my $ProblemType = "Added_Middle_Parameter";
10926 if($Parameter_Name=~/\Ap\d+\Z/) {
10927 $ProblemType = "Added_Middle_Unnamed_Parameter";
10928 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010929 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showNum($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010930 "Target"=>$Parameter_Name,
10931 "Param_Pos"=>$ParamPos,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010932 "Param_Type"=>get_TypeName($PType2_Id, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010933 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010934 }
10935 }
10936 }
10937 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010938 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010939 { # check relevant parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010940 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010941 my $ParamName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010942 # FIXME: find relevant parameter by name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010943 if(defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010944 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010945 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010946 my $ParamName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010947 if(($ParamName1!~/\Ap\d+\Z/i and $ParamName1 eq $ParamName2)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010948 or get_TypeName($PType1_Id, 1) eq get_TypeName($PType2_Id, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010949 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010950 }
10951 }
10952 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010953 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010954 { # checking removed parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010955 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
10956 last if(get_TypeName($PType1_Id, 1) eq "...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010957 my $Parameter_Name = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
10958 my $Parameter_NewName = (defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})?$CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010959 my $ParamPos_New = "-1";
10960 if($Parameter_Name=~/\Ap\d+\Z/i)
10961 { # removed unnamed parameter ( pN )
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010962 my @Positions1 = find_ParamPair_Pos_byTypeAndPos(get_TypeName($PType1_Id, 1), $ParamPos, "forward", $Symbol, 1);
10963 my @Positions2 = find_ParamPair_Pos_byTypeAndPos(get_TypeName($PType1_Id, 1), $ParamPos, "forward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010964 if($#Positions2==-1 or $#Positions2<$#Positions1) {
10965 $ParamPos_New = "lost";
10966 }
10967 }
10968 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010969 $ParamPos_New = find_ParamPair_Pos_byName($Parameter_Name, $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010970 }
10971 if($ParamPos_New eq "lost")
10972 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010973 if($ParamPos>keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010974 {
10975 my $ProblemType = "Removed_Parameter";
10976 if($Parameter_Name=~/\Ap\d+\Z/) {
10977 $ProblemType = "Removed_Unnamed_Parameter";
10978 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010979 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showNum($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010980 "Target"=>$Parameter_Name,
10981 "Param_Pos"=>$ParamPos,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010982 "Param_Type"=>get_TypeName($PType1_Id, 1),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010983 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010984 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010985 elsif($ParamPos<keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010986 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010987 my %ParamType_Pure = get_PureType($Tid_TDid{1}{$PType1_Id}, $PType1_Id, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010988 my $ParamStraightPairType_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010989 my %ParamStraightPairType_Pure = get_PureType($Tid_TDid{2}{$ParamStraightPairType_Id}, $ParamStraightPairType_Id, 2);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010990 if(($ParamType_Pure{"Name"} eq $ParamStraightPairType_Pure{"Name"} or get_TypeName($PType1_Id, 1) eq get_TypeName($ParamStraightPairType_Id, 2))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010991 and find_ParamPair_Pos_byName($Parameter_NewName, $Symbol, 1) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010992 {
10993 if($Parameter_NewName!~/\Ap\d+\Z/ and $Parameter_Name!~/\Ap\d+\Z/)
10994 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010995 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showNum($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010996 "Target"=>$Parameter_Name,
10997 "Param_Pos"=>$ParamPos,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010998 "Param_Type"=>get_TypeName($PType1_Id, 1),
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010999 "Old_Value"=>$Parameter_Name,
11000 "New_Value"=>$Parameter_NewName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011001 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011002 }
11003 }
11004 else
11005 {
11006 my $ProblemType = "Removed_Middle_Parameter";
11007 if($Parameter_Name=~/\Ap\d+\Z/) {
11008 $ProblemType = "Removed_Middle_Unnamed_Parameter";
11009 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011010 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showNum($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011011 "Target"=>$Parameter_Name,
11012 "Param_Pos"=>$ParamPos,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011013 "Param_Type"=>get_TypeName($PType1_Id, 1),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011014 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011015 }
11016 }
11017 }
11018 }
11019 }
11020 # checking return type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011021 my $ReturnType1_Id = $CompleteSignature{1}{$Symbol}{"Return"};
11022 my $ReturnType2_Id = $CompleteSignature{2}{$PSymbol}{"Return"};
11023 %SubProblems = detectTypeChange($ReturnType1_Id, $ReturnType2_Id, "Return", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011024 foreach my $SubProblemType (keys(%SubProblems))
11025 {
11026 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
11027 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
11028 my $NewProblemType = $SubProblemType;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011029 if($Level eq "Binary" and $SubProblemType eq "Return_Type_Became_Void"
11030 and keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011031 { # parameters stack has been affected
11032 $NewProblemType = "Return_Type_Became_Void_And_Stack_Layout";
11033 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011034 elsif($Level eq "Binary"
11035 and $SubProblemType eq "Return_Type_From_Void")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011036 { # parameters stack has been affected
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011037 if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011038 $NewProblemType = "Return_Type_From_Void_And_Stack_Layout";
11039 }
11040 else
11041 { # safe
11042 delete($SubProblems{$SubProblemType});
11043 next;
11044 }
11045 }
11046 elsif($SubProblemType eq "Return_Type_And_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011047 and $CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011048 $NewProblemType = "Global_Data_Type_And_Size";
11049 }
11050 elsif($SubProblemType eq "Return_Type")
11051 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011052 if($CompleteSignature{1}{$Symbol}{"Data"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011053 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011054 if(removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011055 { # const -> non-const global data
11056 $NewProblemType = "Global_Data_Became_Non_Const";
11057 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011058 elsif(removedQual($New_Value, $Old_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011059 { # non-const -> const global data
11060 $NewProblemType = "Global_Data_Became_Const";
11061 }
11062 else {
11063 $NewProblemType = "Global_Data_Type";
11064 }
11065 }
11066 else
11067 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011068 if(removedQual($New_Value, $Old_Value, "const")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011069 $NewProblemType = "Return_Type_Became_Const";
11070 }
11071 }
11072 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011073 elsif($SubProblemType eq "Return_Type_Format")
11074 {
11075 if($CompleteSignature{1}{$Symbol}{"Data"}) {
11076 $NewProblemType = "Global_Data_Type_Format";
11077 }
11078 }
11079 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011080 }
11081 if($ReturnType1_Id and $ReturnType2_Id)
11082 {
11083 @RecurTypes = ();
11084 %SubProblems = mergeTypes($ReturnType1_Id, $Tid_TDid{1}{$ReturnType1_Id},
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011085 $ReturnType2_Id, $Tid_TDid{2}{$ReturnType2_Id}, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011086 foreach my $SubProblemType (keys(%SubProblems))
11087 { # add "Global_Data_Size" problem
11088 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
11089 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
11090 if($SubProblemType eq "DataType_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011091 and $CompleteSignature{1}{$Symbol}{"Data"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011092 and get_PointerLevel($Tid_TDid{1}{$ReturnType1_Id}, $ReturnType1_Id, 1)==0)
11093 { # add a new problem
11094 %{$SubProblems{"Global_Data_Size"}} = %{$SubProblems{$SubProblemType}};
11095 }
11096 }
11097 foreach my $SubProblemType (keys(%SubProblems))
11098 {
11099 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
11100 {
11101 my $NewLocation = ($SubLocation)?"retval->".$SubLocation:"retval";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011102 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011103 "Return_Type_Name"=>get_TypeName($ReturnType1_Id, 1) );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011104 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011105 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011106 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = get_TypeName($ReturnType1_Id, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011107 }
11108 }
11109 }
11110 }
11111
11112 # checking object type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011113 my $ObjectType1_Id = $CompleteSignature{1}{$Symbol}{"Class"};
11114 my $ObjectType2_Id = $CompleteSignature{2}{$PSymbol}{"Class"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011115 if($ObjectType1_Id and $ObjectType2_Id
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011116 and not $CompleteSignature{1}{$Symbol}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011117 {
11118 my $ThisPtr1_Id = getTypeIdByName(get_TypeName($ObjectType1_Id, 1)."*const", 1);
11119 my $ThisPtr2_Id = getTypeIdByName(get_TypeName($ObjectType2_Id, 2)."*const", 2);
11120 if($ThisPtr1_Id and $ThisPtr2_Id)
11121 {
11122 @RecurTypes = ();
11123 %SubProblems = mergeTypes($ThisPtr1_Id, $Tid_TDid{1}{$ThisPtr1_Id},
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011124 $ThisPtr2_Id, $Tid_TDid{2}{$ThisPtr2_Id}, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011125 foreach my $SubProblemType (keys(%SubProblems))
11126 {
11127 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
11128 {
11129 my $NewLocation = ($SubLocation)?"this->".$SubLocation:"this";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011130 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011131 "Object_Type_Name"=>get_TypeName($ObjectType1_Id, 1) );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011132 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011133 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011134 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = get_TypeName($ObjectType1_Id, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011135 }
11136 }
11137 }
11138 }
11139 }
11140 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011141 if($Level eq "Binary") {
11142 mergeVTables($Level);
11143 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011144}
11145
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011146sub removedQual($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011147{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011148 my ($Old_Value, $New_Value, $Qual) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011149 if($Old_Value eq $New_Value) {
11150 return 0;
11151 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011152 while($Old_Value=~s/(\A|\W)$Qual(\W|\Z)/$1$2/)
11153 { # remove all qualifiers
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011154 # one-by-one, left-to-right
11155 $Old_Value=~s/\s+\Z//g;
11156 $Old_Value=~s/\A\s+//g;
11157 $Old_Value = formatName($Old_Value);
11158 if($Old_Value eq $New_Value)
11159 { # compare with a new type
11160 return 1;
11161 }
11162 }
11163 return 0;
11164}
11165
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011166sub mergeParameters($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011167{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011168 my ($Symbol, $PSymbol, $ParamPos1, $ParamPos2, $Level) = @_;
11169 return if(not $Symbol);
11170 return if(not defined $CompleteSignature{1}{$Symbol}{"Param"});
11171 return if(not defined $CompleteSignature{2}{$PSymbol}{"Param"});
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011172 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"type"};
11173 my $PName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"name"};
11174 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"type"};
11175 my $PName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"name"};
11176 return if(not $PType1_Id or not $PType2_Id);
11177 my %Type1 = get_Type($Tid_TDid{1}{$PType1_Id}, $PType1_Id, 1);
11178 my %Type2 = get_Type($Tid_TDid{2}{$PType2_Id}, $PType2_Id, 2);
11179 my %BaseType1 = get_BaseType($Tid_TDid{1}{$PType1_Id}, $PType1_Id, 1);
11180 my %BaseType2 = get_BaseType($Tid_TDid{2}{$PType2_Id}, $PType2_Id, 2);
11181 my $Parameter_Location = ($PName1)?$PName1:showNum($ParamPos1)." Parameter";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011182 if($Level eq "Binary")
11183 {
11184 if(checkDumpVersion(1, "2.6.1") and checkDumpVersion(2, "2.6.1"))
11185 { # "reg" attribute added in ACC 1.95.1 (dump 2.6.1 format)
11186 if($CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
11187 and not $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
11188 {
11189 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Non_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011190 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011191 "Param_Pos"=>$ParamPos1 );
11192 }
11193 elsif(not $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
11194 and $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
11195 {
11196 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011197 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011198 "Param_Pos"=>$ParamPos1 );
11199 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011200 }
11201 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011202 if(checkDumpVersion(1, "2.0") and checkDumpVersion(2, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011203 { # "default" attribute added in ACC 1.22 (dump 2.0 format)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011204 my $DefaultValue_Old = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"default"};
11205 my $DefaultValue_New = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"default"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011206 my %PureType1 = get_PureType($Tid_TDid{1}{$PType1_Id}, $PType1_Id, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011207 if($PureType1{"Name"}=~/\A(char\*|char const\*)\Z/)
11208 {
11209 if($DefaultValue_Old)
11210 { # FIXME: how to distinguish "0" and 0 (NULL)
11211 $DefaultValue_Old = "\"$DefaultValue_Old\"";
11212 }
11213 if($DefaultValue_New) {
11214 $DefaultValue_New = "\"$DefaultValue_New\"";
11215 }
11216 }
11217 elsif($PureType1{"Name"}=~/\A(char)\Z/)
11218 {
11219 if($DefaultValue_Old) {
11220 $DefaultValue_Old = "\'$DefaultValue_Old\'";
11221 }
11222 if($DefaultValue_New) {
11223 $DefaultValue_New = "\'$DefaultValue_New\'";
11224 }
11225 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011226 if(defined $DefaultValue_Old
11227 and $DefaultValue_Old ne "")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011228 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011229 if(defined $DefaultValue_New
11230 and $DefaultValue_New ne "")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011231 {
11232 if($DefaultValue_Old ne $DefaultValue_New)
11233 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011234 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Changed"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011235 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011236 "Param_Pos"=>$ParamPos1,
11237 "Old_Value"=>$DefaultValue_Old,
11238 "New_Value"=>$DefaultValue_New );
11239 }
11240 }
11241 else
11242 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011243 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Removed"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011244 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011245 "Param_Pos"=>$ParamPos1,
11246 "Old_Value"=>$DefaultValue_Old );
11247 }
11248 }
11249 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011250 if($PName1 and $PName2 and $PName1 ne $PName2
11251 and $PType1_Id!=-1 and $PType2_Id!=-1
11252 and $PName1!~/\Ap\d+\Z/ and $PName2!~/\Ap\d+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011253 { # except unnamed "..." value list (Id=-1)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011254 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showNum($ParamPos1)." Parameter"}}=(
11255 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011256 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011257 "Param_Type"=>get_TypeName($PType1_Id, 1),
11258 "Old_Value"=>$PName1,
11259 "New_Value"=>$PName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011260 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011261 }
11262 # checking type change (replace)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011263 my %SubProblems = detectTypeChange($PType1_Id, $PType2_Id, "Parameter", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011264 foreach my $SubProblemType (keys(%SubProblems))
11265 { # add new problems, remove false alarms
11266 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
11267 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
11268 if($SubProblemType eq "Parameter_Type")
11269 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011270 if(checkDumpVersion(1, "2.6") and checkDumpVersion(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011271 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011272 if($Level eq "Binary")
11273 {
11274 if($Old_Value!~/(\A|\W)restrict(\W|\Z)/
11275 and $New_Value=~/(\A|\W)restrict(\W|\Z)/)
11276 { # change to be "restrict"
11277 %{$SubProblems{"Parameter_Became_Restrict"}} = %{$SubProblems{$SubProblemType}};
11278 }
11279 elsif($Old_Value=~/(\A|\W)restrict(\W|\Z)/
11280 and $New_Value!~/(\A|\W)restrict(\W|\Z)/)
11281 { # change to be "restrict"
11282 %{$SubProblems{"Parameter_Became_NonRestrict"}} = %{$SubProblems{$SubProblemType}};
11283 }
11284 }
11285 else
11286 {
11287 if(removedQual($New_Value, $Old_Value, "restrict"))
11288 { # change to be "restrict"
11289 %{$SubProblems{"Parameter_Became_Restrict"}} = %{$SubProblems{$SubProblemType}};
11290 delete($SubProblems{$SubProblemType});
11291 }
11292 elsif(removedQual($Old_Value, $New_Value, "restrict"))
11293 { # change to be "restrict"
11294 %{$SubProblems{"Parameter_Became_NonRestrict"}} = %{$SubProblems{$SubProblemType}};
11295 delete($SubProblems{$SubProblemType});
11296 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011297 }
11298 }
11299 if($Type2{"Type"} eq "Const" and $BaseType2{"Name"} eq $Type1{"Name"}
11300 and $Type1{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
11301 { # int to "int const"
11302 delete($SubProblems{$SubProblemType});
11303 }
11304 if($Type1{"Type"} eq "Const" and $BaseType1{"Name"} eq $Type2{"Name"}
11305 and $Type2{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
11306 { # "int const" to int
11307 delete($SubProblems{$SubProblemType});
11308 }
11309 }
11310 }
11311 foreach my $SubProblemType (keys(%SubProblems))
11312 { # modify/register problems
11313 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
11314 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
11315 my $NewProblemType = $SubProblemType;
11316 if($Old_Value eq "..." and $New_Value ne "...")
11317 { # change from "..." to "int"
11318 if($ParamPos1==0)
11319 { # ISO C requires a named argument before "..."
11320 next;
11321 }
11322 $NewProblemType = "Parameter_Became_NonVaList";
11323 }
11324 elsif($New_Value eq "..." and $Old_Value ne "...")
11325 { # change from "int" to "..."
11326 if($ParamPos2==0)
11327 { # ISO C requires a named argument before "..."
11328 next;
11329 }
11330 $NewProblemType = "Parameter_Became_VaList";
11331 }
11332 elsif($SubProblemType eq "Parameter_Type"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011333 and removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011334 { # parameter: "const" to non-"const"
11335 $NewProblemType = "Parameter_Became_Non_Const";
11336 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011337 elsif($Level eq "Binary" and ($SubProblemType eq "Parameter_Type_And_Size"
11338 or $SubProblemType eq "Parameter_Type"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011339 {
11340 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
11341 if($Arch1 eq "unknown" or $Arch2 eq "unknown")
11342 { # if one of the architectures is unknown
11343 # then set other arhitecture to unknown too
11344 ($Arch1, $Arch2) = ("unknown", "unknown");
11345 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011346 my ($Method1, $Passed1, $SizeOnStack1, $RegName1) = callingConvention($Symbol, $ParamPos1, 1, $Arch1);
11347 my ($Method2, $Passed2, $SizeOnStack2, $RegName2) = callingConvention($Symbol, $ParamPos2, 2, $Arch2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011348 if($Method1 eq $Method2)
11349 {
11350 if($Method1 eq "stack" and $SizeOnStack1 ne $SizeOnStack2) {
11351 $NewProblemType = "Parameter_Type_And_Stack";
11352 }
11353 elsif($Method1 eq "register" and $RegName1 ne $RegName2) {
11354 $NewProblemType = "Parameter_Type_And_Register";
11355 }
11356 }
11357 else
11358 {
11359 if($Method1 eq "stack") {
11360 $NewProblemType = "Parameter_Type_And_Pass_Through_Register";
11361 }
11362 elsif($Method1 eq "register") {
11363 $NewProblemType = "Parameter_Type_And_Pass_Through_Stack";
11364 }
11365 }
11366 $SubProblems{$SubProblemType}{"Old_Reg"} = $RegName1;
11367 $SubProblems{$SubProblemType}{"New_Reg"} = $RegName2;
11368 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011369 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011370 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011371 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011372 "New_Signature"=>get_Signature($Symbol, 2) );
11373 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011374 }
11375 @RecurTypes = ();
11376 # checking type definition changes
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011377 my %SubProblems_Merge = mergeTypes($PType1_Id, $Tid_TDid{1}{$PType1_Id}, $PType2_Id, $Tid_TDid{2}{$PType2_Id}, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011378 foreach my $SubProblemType (keys(%SubProblems_Merge))
11379 {
11380 foreach my $SubLocation (keys(%{$SubProblems_Merge{$SubProblemType}}))
11381 {
11382 my $NewProblemType = $SubProblemType;
11383 if($SubProblemType eq "DataType_Size")
11384 {
11385 my $InitialType_Type = $SubProblems_Merge{$SubProblemType}{$SubLocation}{"InitialType_Type"};
11386 if($InitialType_Type!~/\A(Pointer|Ref)\Z/ and $SubLocation!~/\-\>/)
11387 { # stack has been affected
11388 $NewProblemType = "DataType_Size_And_Stack";
11389 }
11390 }
11391 my $NewLocation = ($SubLocation)?$Parameter_Location."->".$SubLocation:$Parameter_Location;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011392 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011393 "Param_Type"=>get_TypeName($PType1_Id, 1),
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011394 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011395 "Param_Name"=>$PName1 );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011396 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}{keys(%{$SubProblems_Merge{$SubProblemType}{$SubLocation}})} = values %{$SubProblems_Merge{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011397 if($SubLocation!~/\-\>/) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011398 $CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}{"Start_Type_Name"} = get_TypeName($PType1_Id, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011399 }
11400 }
11401 }
11402}
11403
11404sub callingConvention($$$$)
11405{ # calling conventions for different compilers and operating systems
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011406 my ($Symbol, $ParamPos, $LibVersion, $Arch) = @_;
11407 my $ParamTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011408 my %Type = get_PureType($Tid_TDid{$LibVersion}{$ParamTypeId}, $ParamTypeId, $LibVersion);
11409 my ($Method, $Alignment, $Passed, $Register) = ("", 0, "", "");
11410 if($OSgroup=~/\A(linux|macos|freebsd)\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011411 { # GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011412 if($Arch eq "x86")
11413 { # System V ABI Intel386 ("Function Calling Sequence")
11414 # The stack is word aligned. Although the architecture does not require any
11415 # alignment of the stack, software convention and the operating system
11416 # requires that the stack be aligned on a word boundary.
11417
11418 # Argument words are pushed onto the stack in reverse order (that is, the
11419 # rightmost argument in C call syntax has the highest address), preserving the
11420 # stack’s word alignment. All incoming arguments appear on the stack, residing
11421 # in the stack frame of the caller.
11422
11423 # An argument’s size is increased, if necessary, to make it a multiple of words.
11424 # This may require tail padding, depending on the size of the argument.
11425
11426 # Other areas depend on the compiler and the code being compiled. The stan-
11427 # dard calling sequence does not define a maximum stack frame size, nor does
11428 # it restrict how a language system uses the ‘‘unspecified’’ area of the stan-
11429 # dard stack frame.
11430 ($Method, $Alignment) = ("stack", 4);
11431 }
11432 elsif($Arch eq "x86_64")
11433 { # System V AMD64 ABI ("Function Calling Sequence")
11434 ($Method, $Alignment) = ("stack", 8);# eightbyte aligned
11435 }
11436 elsif($Arch eq "arm")
11437 { # Procedure Call Standard for the ARM Architecture
11438 # The stack must be double-word aligned
11439 ($Method, $Alignment) = ("stack", 8);# double-word
11440 }
11441 }
11442 elsif($OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011443 { # MS C++ Compiler
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011444 if($Arch eq "x86")
11445 {
11446 if($ParamPos==0) {
11447 ($Method, $Register, $Passed) = ("register", "ecx", "value");
11448 }
11449 elsif($ParamPos==1) {
11450 ($Method, $Register, $Passed) = ("register", "edx", "value");
11451 }
11452 else {
11453 ($Method, $Alignment) = ("stack", 4);
11454 }
11455 }
11456 elsif($Arch eq "x86_64")
11457 {
11458 if($ParamPos<=3)
11459 {
11460 if($Type{"Name"}=~/\A(float|double|long double)\Z/) {
11461 ($Method, $Passed) = ("xmm".$ParamPos, "value");
11462 }
11463 elsif($Type{"Name"}=~/\A(unsigned |)(short|int|long|long long)\Z/
11464 or $Type{"Type"}=~/\A(Struct|Union|Enum|Array)\Z/
11465 or $Type{"Name"}=~/\A(__m64|__m128)\Z/)
11466 {
11467 if($ParamPos==0) {
11468 ($Method, $Register, $Passed) = ("register", "rcx", "value");
11469 }
11470 elsif($ParamPos==1) {
11471 ($Method, $Register, $Passed) = ("register", "rdx", "value");
11472 }
11473 elsif($ParamPos==2) {
11474 ($Method, $Register, $Passed) = ("register", "r8", "value");
11475 }
11476 elsif($ParamPos==3) {
11477 ($Method, $Register, $Passed) = ("register", "r9", "value");
11478 }
11479 if($Type{"Size"}>64
11480 or $Type{"Type"} eq "Array") {
11481 $Passed = "pointer";
11482 }
11483 }
11484 }
11485 else {
11486 ($Method, $Alignment) = ("stack", 8);# word alignment
11487 }
11488 }
11489 }
11490 if($Method eq "register") {
11491 return ("register", $Passed, "", $Register);
11492 }
11493 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011494 { # on the stack
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011495 if(not $Alignment)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011496 { # default convention
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011497 $Alignment = $WORD_SIZE{$LibVersion};
11498 }
11499 if(not $Passed)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011500 { # default convention
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011501 $Passed = "value";
11502 }
11503 my $SizeOnStack = $Type{"Size"};
11504 # FIXME: improve stack alignment
11505 if($SizeOnStack!=$Alignment) {
11506 $SizeOnStack = int(($Type{"Size"}+$Alignment)/$Alignment)*$Alignment;
11507 }
11508 return ("stack", $Passed, $SizeOnStack, "");
11509 }
11510}
11511
11512sub find_ParamPair_Pos_byName($$$)
11513{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011514 my ($Name, $Symbol, $LibVersion) = @_;
11515 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011516 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011517 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
11518 if($CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"name"} eq $Name)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011519 {
11520 return $ParamPos;
11521 }
11522 }
11523 return "lost";
11524}
11525
11526sub find_ParamPair_Pos_byTypeAndPos($$$$$)
11527{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011528 my ($TypeName, $MediumPos, $Order, $Symbol, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011529 my @Positions = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011530 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011531 {
11532 next if($Order eq "backward" and $ParamPos>$MediumPos);
11533 next if($Order eq "forward" and $ParamPos<$MediumPos);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011534 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
11535 my $PTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011536 if(get_TypeName($PTypeId, $LibVersion) eq $TypeName) {
11537 push(@Positions, $ParamPos);
11538 }
11539 }
11540 return @Positions;
11541}
11542
11543sub getTypeIdByName($$)
11544{
11545 my ($TypeName, $Version) = @_;
11546 return $TName_Tid{$Version}{formatName($TypeName)};
11547}
11548
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011549sub checkFormatChange($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011550{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011551 my ($Type1_Id, $Type2_Id, $Level) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011552 my $Type1_DId = $Tid_TDid{1}{$Type1_Id};
11553 my $Type2_DId = $Tid_TDid{2}{$Type2_Id};
11554 my %Type1_Pure = get_PureType($Type1_DId, $Type1_Id, 1);
11555 my %Type2_Pure = get_PureType($Type2_DId, $Type2_Id, 2);
11556 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"})
11557 { # equal types
11558 return 0;
11559 }
11560 if($Type1_Pure{"Name"}=~/\*/
11561 or $Type2_Pure{"Name"}=~/\*/)
11562 { # compared in detectTypeChange()
11563 return 0;
11564 }
11565 my %FloatType = map {$_=>1} (
11566 "float",
11567 "double",
11568 "long double"
11569 );
11570 if($Type1_Pure{"Type"} ne $Type2_Pure{"Type"})
11571 { # different types
11572 if($Type1_Pure{"Type"} eq "Intrinsic"
11573 and $Type2_Pure{"Type"} eq "Enum")
11574 { # "int" to "enum"
11575 return 0;
11576 }
11577 elsif($Type2_Pure{"Type"} eq "Intrinsic"
11578 and $Type1_Pure{"Type"} eq "Enum")
11579 { # "enum" to "int"
11580 return 0;
11581 }
11582 else
11583 { # "union" to "struct"
11584 # ...
11585 return 1;
11586 }
11587 }
11588 else
11589 {
11590 if($Type1_Pure{"Type"} eq "Intrinsic")
11591 {
11592 if($FloatType{$Type1_Pure{"Name"}}
11593 or $FloatType{$Type2_Pure{"Name"}})
11594 { # "float" to "double"
11595 # "float" to "int"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011596 if($Level eq "Source")
11597 { # Safe
11598 return 0;
11599 }
11600 else {
11601 return 1;
11602 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011603 }
11604 }
11605 elsif($Type1_Pure{"Type"}=~/Class|Struct|Union|Enum/)
11606 {
11607 my @Membs1 = keys(%{$Type1_Pure{"Memb"}});
11608 my @Membs2 = keys(%{$Type2_Pure{"Memb"}});
11609 if($#Membs1!=$#Membs2)
11610 { # different number of elements
11611 return 1;
11612 }
11613 if($Type1_Pure{"Type"} eq "Enum")
11614 {
11615 foreach my $Pos (@Membs1)
11616 { # compare elements by name and value
11617 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"}
11618 or $Type1_Pure{"Memb"}{$Pos}{"value"} ne $Type2_Pure{"Memb"}{$Pos}{"value"})
11619 { # different names
11620 return 1;
11621 }
11622 }
11623 }
11624 else
11625 {
11626 foreach my $Pos (@Membs1)
11627 { # compare elements by type name
11628 my $MT1 = get_TypeName($Type1_Pure{"Memb"}{$Pos}{"type"}, 1);
11629 my $MT2 = get_TypeName($Type2_Pure{"Memb"}{$Pos}{"type"}, 2);
11630 if($MT1 ne $MT2)
11631 { # different types
11632 return 1;
11633 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011634 if($Level eq "Source")
11635 {
11636 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"})
11637 { # different names
11638 return 1;
11639 }
11640 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011641 }
11642 }
11643 }
11644 }
11645 return 0;
11646}
11647
11648sub isScalar($) {
11649 return ($_[0]=~/\A(unsigned |)(short|int|long|long long)\Z/);
11650}
11651
11652sub isFloat($) {
11653 return ($_[0]=~/\A(float|double|long double)\Z/);
11654}
11655
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011656sub detectTypeChange($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011657{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011658 my ($Type1_Id, $Type2_Id, $Prefix, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011659 if(not $Type1_Id or not $Type2_Id) {
11660 return ();
11661 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011662 my %LocalProblems = ();
11663 my $Type1_DId = $Tid_TDid{1}{$Type1_Id};
11664 my $Type2_DId = $Tid_TDid{2}{$Type2_Id};
11665 my %Type1 = get_Type($Type1_DId, $Type1_Id, 1);
11666 my %Type2 = get_Type($Type2_DId, $Type2_Id, 2);
11667 my %Type1_Pure = get_PureType($Type1_DId, $Type1_Id, 1);
11668 my %Type2_Pure = get_PureType($Type2_DId, $Type2_Id, 2);
11669 my %Type1_Base = ($Type1_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type1_Pure{"TDid"}, $Type1_Pure{"Tid"}, 1):get_BaseType($Type1_DId, $Type1_Id, 1);
11670 my %Type2_Base = ($Type2_Pure{"Type"} eq "Array")?get_OneStep_BaseType($Type2_Pure{"TDid"}, $Type2_Pure{"Tid"}, 2):get_BaseType($Type2_DId, $Type2_Id, 2);
11671 my $Type1_PLevel = get_PointerLevel($Type1_DId, $Type1_Id, 1);
11672 my $Type2_PLevel = get_PointerLevel($Type2_DId, $Type2_Id, 2);
11673 return () if(not $Type1{"Name"} or not $Type2{"Name"});
11674 return () if(not $Type1_Base{"Name"} or not $Type2_Base{"Name"});
11675 return () if($Type1_PLevel eq "" or $Type2_PLevel eq "");
11676 if($Type1_Base{"Name"} ne $Type2_Base{"Name"}
11677 and ($Type1{"Name"} eq $Type2{"Name"} or ($Type1_PLevel>=1 and $Type1_PLevel==$Type2_PLevel
11678 and $Type1_Base{"Name"} ne "void" and $Type2_Base{"Name"} ne "void")))
11679 { # base type change
11680 if($Type1{"Type"} eq "Typedef" and $Type2{"Type"} eq "Typedef"
11681 and $Type1{"Name"} eq $Type2{"Name"})
11682 { # will be reported in mergeTypes() as typedef problem
11683 return ();
11684 }
11685 if($Type1_Base{"Name"}!~/anon\-/ and $Type2_Base{"Name"}!~/anon\-/)
11686 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011687 if($Level eq "Binary"
11688 and $Type1_Base{"Size"} ne $Type2_Base{"Size"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011689 and $Type1_Base{"Size"} and $Type2_Base{"Size"})
11690 {
11691 %{$LocalProblems{$Prefix."_BaseType_And_Size"}}=(
11692 "Old_Value"=>$Type1_Base{"Name"},
11693 "New_Value"=>$Type2_Base{"Name"},
11694 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
11695 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
11696 "InitialType_Type"=>$Type1_Pure{"Type"});
11697 }
11698 else
11699 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011700 if(checkFormatChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011701 { # format change
11702 %{$LocalProblems{$Prefix."_BaseType_Format"}}=(
11703 "Old_Value"=>$Type1_Base{"Name"},
11704 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011705 "InitialType_Type"=>$Type1_Pure{"Type"});
11706 }
11707 elsif(tNameLock($Type1_Base{"Tid"}, $Type2_Base{"Tid"}))
11708 {
11709 %{$LocalProblems{$Prefix."_BaseType"}}=(
11710 "Old_Value"=>$Type1_Base{"Name"},
11711 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011712 "InitialType_Type"=>$Type1_Pure{"Type"});
11713 }
11714 }
11715 }
11716 }
11717 elsif($Type1{"Name"} ne $Type2{"Name"})
11718 { # type change
11719 if($Type1{"Name"}!~/anon\-/ and $Type2{"Name"}!~/anon\-/)
11720 {
11721 if($Prefix eq "Return" and $Type1{"Name"} eq "void"
11722 and $Type2_Pure{"Type"}=~/Intrinsic|Enum/) {
11723 # safe change
11724 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011725 elsif($Level eq "Binary"
11726 and $Prefix eq "Return"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011727 and $Type1_Pure{"Name"} eq "void")
11728 {
11729 %{$LocalProblems{"Return_Type_From_Void"}}=(
11730 "New_Value"=>$Type2{"Name"},
11731 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
11732 "InitialType_Type"=>$Type1_Pure{"Type"});
11733 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011734 elsif($Level eq "Binary"
11735 and $Prefix eq "Return" and $Type1_Pure{"Type"}=~/Intrinsic|Enum/
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011736 and $Type2_Pure{"Type"}=~/Struct|Class|Union/)
11737 { # returns into hidden first parameter instead of a register
11738
11739 # System V ABI Intel386 ("Function Calling Sequence")
11740 # A function that returns an integral or pointer value places its result in register %eax.
11741
11742 # A floating-point return value appears on the top of the Intel387 register stack. The
11743 # caller then must remove the value from the Intel387 stack, even if it doesn’t use the
11744 # value.
11745
11746 # If a function returns a structure or union, then the caller provides space for the
11747 # return value and places its address on the stack as argument word zero. In effect,
11748 # this address becomes a ‘‘hidden’’ first argument.
11749
11750 %{$LocalProblems{"Return_Type_From_Register_To_Stack"}}=(
11751 "Old_Value"=>$Type1{"Name"},
11752 "New_Value"=>$Type2{"Name"},
11753 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
11754 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
11755 "InitialType_Type"=>$Type1_Pure{"Type"});
11756 }
11757 elsif($Prefix eq "Return"
11758 and $Type2_Pure{"Name"} eq "void")
11759 {
11760 %{$LocalProblems{"Return_Type_Became_Void"}}=(
11761 "Old_Value"=>$Type1{"Name"},
11762 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
11763 "InitialType_Type"=>$Type1_Pure{"Type"});
11764 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011765 elsif($Level eq "Binary" and $Prefix eq "Return"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011766 and ((isScalar($Type1_Pure{"Name"}) and isFloat($Type2_Pure{"Name"}))
11767 or (isScalar($Type2_Pure{"Name"}) and isFloat($Type1_Pure{"Name"}))))
11768 { # The scalar and floating-point values are passed in different registers
11769 %{$LocalProblems{"Return_Type_And_Register"}}=(
11770 "Old_Value"=>$Type1{"Name"},
11771 "New_Value"=>$Type2{"Name"},
11772 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
11773 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
11774 "InitialType_Type"=>$Type1_Pure{"Type"});
11775 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011776 elsif($Level eq "Binary"
11777 and $Prefix eq "Return" and $Type2_Pure{"Type"}=~/Intrinsic|Enum/
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011778 and $Type1_Pure{"Type"}=~/Struct|Class|Union/)
11779 { # returns in a register instead of a hidden first parameter
11780 %{$LocalProblems{"Return_Type_From_Stack_To_Register"}}=(
11781 "Old_Value"=>$Type1{"Name"},
11782 "New_Value"=>$Type2{"Name"},
11783 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
11784 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
11785 "InitialType_Type"=>$Type1_Pure{"Type"});
11786 }
11787 else
11788 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011789 if($Level eq "Binary"
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011790 and $Type1{"Size"} and $Type2{"Size"}
11791 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011792 {
11793 %{$LocalProblems{$Prefix."_Type_And_Size"}}=(
11794 "Old_Value"=>$Type1{"Name"},
11795 "New_Value"=>$Type2{"Name"},
11796 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
11797 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
11798 "InitialType_Type"=>$Type1_Pure{"Type"});
11799 }
11800 else
11801 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011802 if(checkFormatChange($Type1_Id, $Type2_Id, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011803 { # format change
11804 %{$LocalProblems{$Prefix."_Type_Format"}}=(
11805 "Old_Value"=>$Type1{"Name"},
11806 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011807 "InitialType_Type"=>$Type1_Pure{"Type"});
11808 }
11809 elsif(tNameLock($Type1_Id, $Type2_Id))
11810 { # FIXME: correct this condition
11811 %{$LocalProblems{$Prefix."_Type"}}=(
11812 "Old_Value"=>$Type1{"Name"},
11813 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011814 "InitialType_Type"=>$Type1_Pure{"Type"});
11815 }
11816 }
11817 }
11818 }
11819 }
11820 if($Type1_PLevel!=$Type2_PLevel)
11821 {
11822 if($Type1{"Name"} ne "void" and $Type1{"Name"} ne "..."
11823 and $Type2{"Name"} ne "void" and $Type2{"Name"} ne "...")
11824 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011825 if($Level eq "Source")
11826 {
11827 %{$LocalProblems{$Prefix."_PointerLevel"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011828 "Old_Value"=>$Type1_PLevel,
11829 "New_Value"=>$Type2_PLevel);
11830 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011831 else
11832 {
11833 if($Type2_PLevel>$Type1_PLevel) {
11834 %{$LocalProblems{$Prefix."_PointerLevel_Increased"}}=(
11835 "Old_Value"=>$Type1_PLevel,
11836 "New_Value"=>$Type2_PLevel);
11837 }
11838 else {
11839 %{$LocalProblems{$Prefix."_PointerLevel_Decreased"}}=(
11840 "Old_Value"=>$Type1_PLevel,
11841 "New_Value"=>$Type2_PLevel);
11842 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011843 }
11844 }
11845 }
11846 if($Type1_Pure{"Type"} eq "Array")
11847 { # base_type[N] -> base_type[N]
11848 # base_type: older_structure -> typedef to newer_structure
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011849 my %SubProblems = detectTypeChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Prefix, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011850 foreach my $SubProblemType (keys(%SubProblems))
11851 {
11852 $SubProblemType=~s/_Type/_BaseType/g;
11853 next if(defined $LocalProblems{$SubProblemType});
11854 foreach my $Attr (keys(%{$SubProblems{$SubProblemType}})) {
11855 $LocalProblems{$SubProblemType}{$Attr} = $SubProblems{$SubProblemType}{$Attr};
11856 }
11857 }
11858 }
11859 return %LocalProblems;
11860}
11861
11862sub tNameLock($$)
11863{
11864 my ($Tid1, $Tid2) = @_;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011865 if(differentDumps("G")
11866 or differentDumps("V"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011867 { # different formats
11868 if($UseOldDumps)
11869 { # old dumps
11870 return 0;
11871 }
11872 my $TN1 = get_TypeName($Tid1, 1);
11873 my $TN2 = get_TypeName($Tid2, 2);
11874 my %Base1 = get_Type($Tid_TDid{1}{$Tid1}, $Tid1, 1);
11875 while($Base1{"Type"} eq "Typedef") {
11876 %Base1 = get_OneStep_BaseType($Base1{"TDid"}, $Base1{"Tid"}, 1);
11877 }
11878 my %Base2 = get_Type($Tid_TDid{2}{$Tid2}, $Tid2, 2);
11879 while($Base2{"Type"} eq "Typedef") {
11880 %Base2 = get_OneStep_BaseType($Base2{"TDid"}, $Base2{"Tid"}, 2);
11881 }
11882 my $Base1 = uncover_typedefs($Base1{"Name"}, 1);
11883 my $Base2 = uncover_typedefs($Base2{"Name"}, 2);
11884 if($TN1 ne $TN2
11885 and $Base1 eq $Base2)
11886 { # equal base types
11887 return 0;
11888 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011889 if(not checkDumpVersion(1, "2.6")
11890 or not checkDumpVersion(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011891 {
11892 if($TN1!~/(\A|\W)restrict(\W|\Z)/
11893 and $TN2=~/(\A|\W)restrict(\W|\Z)/) {
11894 return 0;
11895 }
11896 }
11897
11898 }
11899 return 1;
11900}
11901
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011902sub differentDumps($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011903{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011904 my $Check = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011905 if($UsedDump{1}{"V"} and $UsedDump{2}{"V"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011906 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011907 if($Check eq "G")
11908 {
11909 if(getGccVersion(1) ne getGccVersion(2))
11910 { # different GCC versions
11911 return 1;
11912 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011913 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011914 if($Check eq "V")
11915 {
11916 if(cmpVersions(formatVersion($UsedDump{1}{"V"}, 2),
11917 formatVersion($UsedDump{2}{"V"}, 2))!=0)
11918 { # different dump versions (skip micro version)
11919 return 1;
11920 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011921 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011922 }
11923 return 0;
11924}
11925
11926sub formatVersion($$)
11927{ # cut off version digits
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011928 my ($V, $Digits) = @_;
11929 my @Elems = split(/\./, $V);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011930 return join(".", splice(@Elems, 0, $Digits));
11931}
11932
11933sub htmlSpecChars($)
11934{
11935 my $Str = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011936 if($Str eq "") {
11937 return "";
11938 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011939 $Str=~s/\&([^#]|\Z)/&amp;$1/g;
11940 $Str=~s/</&lt;/g;
11941 $Str=~s/\-\>/&#45;&gt;/g; # &minus;
11942 $Str=~s/>/&gt;/g;
11943 $Str=~s/([^ ])( )([^ ])/$1\@ALONE_SP\@$3/g;
11944 $Str=~s/ /&#160;/g; # &nbsp;
11945 $Str=~s/\@ALONE_SP\@/ /g;
11946 $Str=~s/\n/<br\/>/g;
11947 $Str=~s/\"/&quot;/g;
11948 $Str=~s/\'/&#39;/g;
11949 return $Str;
11950}
11951
11952sub black_name($)
11953{
11954 my $Name = $_[0];
11955 return "<span class='iname_b'>".highLight_Signature($Name)."</span>";
11956}
11957
11958sub highLight_Signature($)
11959{
11960 my $Signature = $_[0];
11961 return highLight_Signature_PPos_Italic($Signature, "", 0, 0, 0);
11962}
11963
11964sub highLight_Signature_Italic_Color($)
11965{
11966 my $Signature = $_[0];
11967 return highLight_Signature_PPos_Italic($Signature, "", 1, 1, 1);
11968}
11969
11970sub separate_symbol($)
11971{
11972 my $Symbol = $_[0];
11973 my ($Name, $Spec, $Ver) = ($Symbol, "", "");
11974 if($Symbol=~/\A([^\@\$\?]+)([\@\$]+)([^\@\$]+)\Z/) {
11975 ($Name, $Spec, $Ver) = ($1, $2, $3);
11976 }
11977 return ($Name, $Spec, $Ver);
11978}
11979
11980sub cut_f_attrs($)
11981{
11982 if($_[0]=~s/(\))((| (const volatile|const|volatile))(| \[static\]))\Z/$1/) {
11983 return $2;
11984 }
11985 return "";
11986}
11987
11988sub highLight_Signature_PPos_Italic($$$$$)
11989{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011990 my ($FullSignature, $Param_Pos, $ItalicParams, $ColorParams, $ShowReturn) = @_;
11991 $Param_Pos = "" if(not defined $Param_Pos);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011992 if($CheckObjectsOnly) {
11993 $ItalicParams=$ColorParams=0;
11994 }
11995 my ($Signature, $VersionSpec, $SymbolVersion) = separate_symbol($FullSignature);
11996 my $Return = "";
11997 if($ShowRetVal and $Signature=~s/([^:]):([^:].+?)\Z/$1/g) {
11998 $Return = $2;
11999 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012000 my $SCenter = find_center($Signature, "(");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012001 if(not $SCenter)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012002 { # global data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012003 $Signature = htmlSpecChars($Signature);
12004 $Signature=~s!(\[data\])!<span style='color:Black;font-weight:normal;'>$1</span>!g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012005 $Signature .= (($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012006 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012007 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012008 }
12009 return $Signature;
12010 }
12011 my ($Begin, $End) = (substr($Signature, 0, $SCenter), "");
12012 $Begin.=" " if($Begin!~/ \Z/);
12013 $End = cut_f_attrs($Signature);
12014 my @Parts = ();
12015 my @SParts = get_s_params($Signature, 1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012016 foreach my $Pos (0 .. $#SParts)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012017 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012018 my $Part = $SParts[$Pos];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012019 $Part=~s/\A\s+|\s+\Z//g;
12020 my ($Part_Styled, $ParamName) = (htmlSpecChars($Part), "");
12021 if($Part=~/\([\*]+(\w+)\)/i) {
12022 $ParamName = $1;#func-ptr
12023 }
12024 elsif($Part=~/(\w+)[\,\)]*\Z/i) {
12025 $ParamName = $1;
12026 }
12027 if(not $ParamName) {
12028 push(@Parts, $Part_Styled);
12029 next;
12030 }
12031 if($ItalicParams and not $TName_Tid{1}{$Part}
12032 and not $TName_Tid{2}{$Part})
12033 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012034 if($Param_Pos ne ""
12035 and $Pos==$Param_Pos) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012036 $Part_Styled =~ s!(\W)$ParamName([\,\)]|\Z)!$1<span class='focus_p'>$ParamName</span>$2!ig;
12037 }
12038 elsif($ColorParams) {
12039 $Part_Styled =~ s!(\W)$ParamName([\,\)]|\Z)!$1<span class='color_p'>$ParamName</span>$2!ig;
12040 }
12041 else {
12042 $Part_Styled =~ s!(\W)$ParamName([\,\)]|\Z)!$1<span style='font-style:italic;'>$ParamName</span>$2!ig;
12043 }
12044 }
12045 $Part_Styled=~s/,(\w)/, $1/g;
12046 push(@Parts, $Part_Styled);
12047 }
12048 if(@Parts)
12049 {
12050 foreach my $Num (0 .. $#Parts)
12051 {
12052 if($Num==$#Parts)
12053 { # add ")" to the last parameter
12054 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]." )</span>";
12055 }
12056 elsif(length($Parts[$Num])<=45) {
12057 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]."</span>";
12058 }
12059 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012060 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;".join(" ", @Parts)."</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012061 }
12062 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012063 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;)</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012064 }
12065 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012066 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012067 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012068 $Signature=~s!\[\]![&#160;]!g;
12069 $Signature=~s!operator=!operator&#160;=!g;
12070 $Signature=~s!(\[in-charge\]|\[not-in-charge\]|\[in-charge-deleting\]|\[static\])!<span class='sym_kind'>$1</span>!g;
12071 return $Signature.(($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012072}
12073
12074sub get_s_params($$)
12075{
12076 my ($Signature, $Comma) = @_;
12077 my @Parts = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012078 my $ShortName = substr($Signature, 0, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012079 $Signature=~s/\A\Q$ShortName\E\(//g;
12080 cut_f_attrs($Signature);
12081 $Signature=~s/\)\Z//;
12082 return separate_params($Signature, $Comma);
12083}
12084
12085sub separate_params($$)
12086{
12087 my ($Params, $Comma) = @_;
12088 my @Parts = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012089 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
12090 my $Part = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012091 foreach my $Pos (0 .. length($Params) - 1)
12092 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012093 my $S = substr($Params, $Pos, 1);
12094 if(defined $B{$S}) {
12095 $B{$S}+=1;
12096 }
12097 if($S eq "," and
12098 $B{"("}==$B{")"} and $B{"<"}==$B{">"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012099 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012100 if($Comma)
12101 { # include comma
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012102 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012103 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012104 $Part += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012105 }
12106 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012107 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012108 }
12109 }
12110 return @Parts;
12111}
12112
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012113sub find_center($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012114{
12115 my ($Sign, $Target) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012116 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012117 my $Center = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012118 if($Sign=~s/(operator([^\w\s\(\)]+|\(\)))//g)
12119 { # operators
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012120 $Center+=length($1);
12121 }
12122 foreach my $Pos (0 .. length($Sign)-1)
12123 {
12124 my $S = substr($Sign, $Pos, 1);
12125 if($S eq $Target)
12126 {
12127 if($B{"("}==$B{")"}
12128 and $B{"<"}==$B{">"}) {
12129 return $Center;
12130 }
12131 }
12132 if(defined $B{$S}) {
12133 $B{$S}+=1;
12134 }
12135 $Center+=1;
12136 }
12137 return 0;
12138}
12139
12140sub appendFile($$)
12141{
12142 my ($Path, $Content) = @_;
12143 return if(not $Path);
12144 if(my $Dir = get_dirname($Path)) {
12145 mkpath($Dir);
12146 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012147 open(FILE, ">>", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012148 print FILE $Content;
12149 close(FILE);
12150}
12151
12152sub writeFile($$)
12153{
12154 my ($Path, $Content) = @_;
12155 return if(not $Path);
12156 if(my $Dir = get_dirname($Path)) {
12157 mkpath($Dir);
12158 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012159 open(FILE, ">", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012160 print FILE $Content;
12161 close(FILE);
12162}
12163
12164sub readFile($)
12165{
12166 my $Path = $_[0];
12167 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012168 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012169 local $/ = undef;
12170 my $Content = <FILE>;
12171 close(FILE);
12172 if($Path!~/\.(tu|class)\Z/) {
12173 $Content=~s/\r/\n/g;
12174 }
12175 return $Content;
12176}
12177
12178sub get_filename($)
12179{ # much faster than basename() from File::Basename module
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012180 if($_[0] and $_[0]=~/([^\/\\]+)[\/\\]*\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012181 return $1;
12182 }
12183 return "";
12184}
12185
12186sub get_dirname($)
12187{ # much faster than dirname() from File::Basename module
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012188 if($_[0] and $_[0]=~/\A(.*?)[\/\\]+[^\/\\]*[\/\\]*\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012189 return $1;
12190 }
12191 return "";
12192}
12193
12194sub separate_path($) {
12195 return (get_dirname($_[0]), get_filename($_[0]));
12196}
12197
12198sub esc($)
12199{
12200 my $Str = $_[0];
12201 $Str=~s/([()\[\]{}$ &'"`;,<>\+])/\\$1/g;
12202 return $Str;
12203}
12204
12205sub readLineNum($$)
12206{
12207 my ($Path, $Num) = @_;
12208 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012209 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012210 foreach (1 ... $Num) {
12211 <FILE>;
12212 }
12213 my $Line = <FILE>;
12214 close(FILE);
12215 return $Line;
12216}
12217
12218sub readAttributes($)
12219{
12220 my $Path = $_[0];
12221 return () if(not $Path or not -f $Path);
12222 my %Attributes = ();
12223 if(readLineNum($Path, 0)=~/<!--\s+(.+)\s+-->/) {
12224 foreach my $AttrVal (split(/;/, $1)) {
12225 if($AttrVal=~/(.+):(.+)/)
12226 {
12227 my ($Name, $Value) = ($1, $2);
12228 $Attributes{$Name} = $Value;
12229 }
12230 }
12231 }
12232 return \%Attributes;
12233}
12234
12235sub is_abs($) {
12236 return ($_[0]=~/\A(\/|\w+:[\/\\])/);
12237}
12238
12239sub get_abs_path($)
12240{ # abs_path() should NOT be called for absolute inputs
12241 # because it can change them
12242 my $Path = $_[0];
12243 if(not is_abs($Path)) {
12244 $Path = abs_path($Path);
12245 }
12246 return $Path;
12247}
12248
12249sub get_OSgroup()
12250{
12251 $_ = $Config{"osname"};
12252 if(/macos|darwin|rhapsody/i) {
12253 return "macos";
12254 }
12255 elsif(/freebsd|openbsd|netbsd/i) {
12256 return "bsd";
12257 }
12258 elsif(/haiku|beos/i) {
12259 return "beos";
12260 }
12261 elsif(/symbian|epoc/i) {
12262 return "symbian";
12263 }
12264 elsif(/win/i) {
12265 return "windows";
12266 }
12267 else {
12268 return $_;
12269 }
12270}
12271
12272sub getGccVersion($)
12273{
12274 my $LibVersion = $_[0];
12275 if($GCC_VERSION{$LibVersion})
12276 { # dump version
12277 return $GCC_VERSION{$LibVersion};
12278 }
12279 elsif($UsedDump{$LibVersion}{"V"})
12280 { # old-version dumps
12281 return "unknown";
12282 }
12283 my $GccVersion = get_dumpversion($GCC_PATH); # host version
12284 if(not $GccVersion) {
12285 return "unknown";
12286 }
12287 return $GccVersion;
12288}
12289
12290sub showArch($)
12291{
12292 my $Arch = $_[0];
12293 if($Arch eq "arm"
12294 or $Arch eq "mips") {
12295 return uc($Arch);
12296 }
12297 return $Arch;
12298}
12299
12300sub getArch($)
12301{
12302 my $LibVersion = $_[0];
12303 if($CPU_ARCH{$LibVersion})
12304 { # dump version
12305 return $CPU_ARCH{$LibVersion};
12306 }
12307 elsif($UsedDump{$LibVersion}{"V"})
12308 { # old-version dumps
12309 return "unknown";
12310 }
12311 if(defined $Cache{"getArch"}{$LibVersion}) {
12312 return $Cache{"getArch"}{$LibVersion};
12313 }
12314 my $Arch = get_dumpmachine($GCC_PATH); # host version
12315 if(not $Arch) {
12316 return "unknown";
12317 }
12318 if($Arch=~/\A([\w]{3,})(-|\Z)/) {
12319 $Arch = $1;
12320 }
12321 $Arch = "x86" if($Arch=~/\Ai[3-7]86\Z/);
12322 if($OSgroup eq "windows") {
12323 $Arch = "x86" if($Arch=~/win32|mingw32/i);
12324 $Arch = "x86_64" if($Arch=~/win64|mingw64/i);
12325 }
12326 $Cache{"getArch"}{$LibVersion} = $Arch;
12327 return $Arch;
12328}
12329
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012330sub get_Report_Header($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012331{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012332 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012333 my $ArchInfo = " on <span style='color:Blue;'>".showArch(getArch(1))."</span>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012334 if(getArch(1) ne getArch(2)
12335 or getArch(1) eq "unknown"
12336 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012337 { # don't show architecture in the header
12338 $ArchInfo="";
12339 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012340 my $Report_Header = "<h1><span class='nowrap'>";
12341 if($Level eq "Source") {
12342 $Report_Header .= "Source compatibility";
12343 }
12344 elsif($Level eq "Binary") {
12345 $Report_Header .= "Binary compatibility";
12346 }
12347 else {
12348 $Report_Header .= "API compatibility";
12349 }
12350 $Report_Header .= " report for the <span style='color:Blue;'>$TargetLibraryFName</span> $TargetComponent</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012351 $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>";
12352 if($AppPath) {
12353 $Report_Header .= " <span class='nowrap'>&#160;(relating to the portability of application <span style='color:Blue;'>".get_filename($AppPath)."</span>)</span>";
12354 }
12355 $Report_Header .= "</h1>\n";
12356 return $Report_Header;
12357}
12358
12359sub get_SourceInfo()
12360{
12361 my $CheckedHeaders = "<a name='Headers'></a><h2>Header Files (".keys(%{$Registered_Headers{1}}).")</h2><hr/>\n";
12362 $CheckedHeaders .= "<div class='h_list'>\n";
12363 foreach my $Header_Path (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
12364 {
12365 my $Identity = $Registered_Headers{1}{$Header_Path}{"Identity"};
12366 my $Header_Name = get_filename($Identity);
12367 my $Dest_Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
12368 $CheckedHeaders .= "$Header_Name$Dest_Comment<br/>\n";
12369 }
12370 $CheckedHeaders .= "</div>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012371 $CheckedHeaders .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012372 my $CheckedLibs = "<a name='Libs'></a><h2>".ucfirst($SLIB_TYPE)." Libraries (".keys(%{$Library_Symbol{1}}).")</h2><hr/>\n";
12373 $CheckedLibs .= "<div class='lib_list'>\n";
12374 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
12375 {
12376 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
12377 $CheckedLibs .= "$Library<br/>\n";
12378 }
12379 $CheckedLibs .= "</div>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012380 $CheckedLibs .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012381 if($CheckObjectsOnly) {
12382 $CheckedHeaders = "";
12383 }
12384 if($CheckHeadersOnly) {
12385 $CheckedLibs = "";
12386 }
12387 return $CheckedHeaders.$CheckedLibs;
12388}
12389
12390sub get_TypeProblems_Count($$$)
12391{
12392 my ($TypeChanges, $TargetPriority, $Level) = @_;
12393 my $Type_Problems_Count = 0;
12394 foreach my $Type_Name (sort keys(%{$TypeChanges}))
12395 {
12396 my %Kinds_Target = ();
12397 foreach my $Kind (keys(%{$TypeChanges->{$Type_Name}}))
12398 {
12399 foreach my $Location (keys(%{$TypeChanges->{$Type_Name}{$Kind}}))
12400 {
12401 my $Target = $TypeChanges->{$Type_Name}{$Kind}{$Location}{"Target"};
12402 my $Priority = getProblemSeverity($Level, $Kind);
12403 next if($Priority ne $TargetPriority);
12404 if($Kinds_Target{$Kind}{$Target}) {
12405 next;
12406 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012407 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012408 { # select a problem with the highest priority
12409 next;
12410 }
12411 $Kinds_Target{$Kind}{$Target} = 1;
12412 $Type_Problems_Count += 1;
12413 }
12414 }
12415 }
12416 return $Type_Problems_Count;
12417}
12418
12419sub get_Summary($)
12420{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012421 my $Level = $_[0];
12422 my ($Added, $Removed, $I_Problems_High, $I_Problems_Medium, $I_Problems_Low, $T_Problems_High,
12423 $C_Problems_Low, $T_Problems_Medium, $T_Problems_Low, $I_Other, $T_Other) = (0,0,0,0,0,0,0,0,0,0,0);
12424 %{$RESULT{$Level}} = (
12425 "Problems"=>0,
12426 "Warnings"=>0,
12427 "Affected"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012428 # check rules
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012429 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012430 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012431 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012432 {
12433 if(not defined $CompatRules{$Level}{$Kind})
12434 { # unknown rule
12435 if(not $UnknownRules{$Level}{$Kind})
12436 { # only one warning
12437 printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")");
12438 $UnknownRules{$Level}{$Kind}=1;
12439 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012440 delete($CompatProblems{$Level}{$Interface}{$Kind});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012441 }
12442 }
12443 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012444 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012445 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012446 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012447 {
12448 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols")
12449 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012450 foreach my $Location (sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012451 {
12452 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012453 if($Kind eq "Added_Symbol") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012454 $Added += 1;
12455 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012456 elsif($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012457 {
12458 $Removed += 1;
12459 $TotalAffected{$Level}{$Interface} = $Priority;
12460 }
12461 else
12462 {
12463 if($Priority eq "Safe") {
12464 $I_Other += 1;
12465 }
12466 elsif($Priority eq "High") {
12467 $I_Problems_High += 1;
12468 }
12469 elsif($Priority eq "Medium") {
12470 $I_Problems_Medium += 1;
12471 }
12472 elsif($Priority eq "Low") {
12473 $I_Problems_Low += 1;
12474 }
12475 if(($Priority ne "Low" or $StrictCompat)
12476 and $Priority ne "Safe") {
12477 $TotalAffected{$Level}{$Interface} = $Priority;
12478 }
12479 }
12480 }
12481 }
12482 }
12483 }
12484 my %TypeChanges = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012485 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012486 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012487 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012488 {
12489 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
12490 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012491 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012492 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012493 my $Type_Name = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
12494 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012495 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012496 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012497 { # select a problem with the highest priority
12498 next;
12499 }
12500 if(($Priority ne "Low" or $StrictCompat)
12501 and $Priority ne "Safe") {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012502 $TotalAffected{$Level}{$Interface} = maxSeverity($TotalAffected{$Level}{$Interface}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012503 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012504 %{$TypeChanges{$Type_Name}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012505 $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target} = maxSeverity($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012506 }
12507 }
12508 }
12509 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012510
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012511 $T_Problems_High = get_TypeProblems_Count(\%TypeChanges, "High", $Level);
12512 $T_Problems_Medium = get_TypeProblems_Count(\%TypeChanges, "Medium", $Level);
12513 $T_Problems_Low = get_TypeProblems_Count(\%TypeChanges, "Low", $Level);
12514 $T_Other = get_TypeProblems_Count(\%TypeChanges, "Safe", $Level);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012515
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012516 if($CheckObjectsOnly)
12517 { # only removed exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012518 $RESULT{$Level}{"Affected"} = $Removed*100/keys(%{$Symbol_Library{1}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012519 }
12520 else
12521 { # changed and removed public symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012522 my $SCount = keys(%{$CheckedSymbols{$Level}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012523 if($ExtendedCheck)
12524 { # don't count external_func_0 for constants
12525 $SCount-=1;
12526 }
12527 if($SCount)
12528 {
12529 my %Weight = (
12530 "High" => 100,
12531 "Medium" => 50,
12532 "Low" => 25
12533 );
12534 foreach (keys(%{$TotalAffected{$Level}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012535 $RESULT{$Level}{"Affected"}+=$Weight{$TotalAffected{$Level}{$_}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012536 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012537 $RESULT{$Level}{"Affected"} = $RESULT{$Level}{"Affected"}/$SCount;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012538 }
12539 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012540 $RESULT{$Level}{"Affected"} = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012541 }
12542 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012543 $RESULT{$Level}{"Affected"} = show_number($RESULT{$Level}{"Affected"});
12544 if($RESULT{$Level}{"Affected"}>=100) {
12545 $RESULT{$Level}{"Affected"} = 100;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012546 }
12547
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012548 $RESULT{$Level}{"Problems"} = $Removed + $T_Problems_High + $I_Problems_High;
12549 $RESULT{$Level}{"Problems"} += $T_Problems_Medium + $I_Problems_Medium;
12550 $RESULT{$Level}{$StrictCompat?"Problems":"Warnings"} += $T_Problems_Low + $I_Problems_Low;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012551
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012552 if($C_Problems_Low = keys(%{$ProblemsWithConstants{$Level}}))
12553 {
12554 if(defined $CompatRules{$Level}{"Changed_Constant"}) {
12555 $RESULT{$Level}{$StrictCompat?"Problems":"Warnings"} += $C_Problems_Low;
12556 }
12557 else
12558 {
12559 printMsg("WARNING", "unknown rule \"Changed_Constant\" (\"$Level\")");
12560 $C_Problems_Low = 0;
12561 }
12562 }
12563 if($CheckImpl and $Level eq "Binary") {
12564 $RESULT{$Level}{$StrictCompat?"Problems":"Warnings"} += keys(%ImplProblems);
12565 }
12566 $RESULT{$Level}{"Verdict"} = $RESULT{$Level}{"Problems"}?"incompatible":"compatible";
12567
12568 my $TotalTypes = keys(%{$CheckedTypes{$Level}});
12569 if(not $TotalTypes)
12570 { # list all the types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012571 $TotalTypes = keys(%{$TName_Tid{1}});
12572 }
12573
12574 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
12575 my ($GccV1, $GccV2) = (getGccVersion(1), getGccVersion(2));
12576
12577 my ($TestInfo, $TestResults, $Problem_Summary) = ();
12578
12579 if($ReportFormat eq "xml")
12580 { # XML
12581 # test info
12582 $TestInfo .= " <library>$TargetLibraryName</library>\n";
12583 $TestInfo .= " <version1>\n";
12584 $TestInfo .= " <number>".$Descriptor{1}{"Version"}."</number>\n";
12585 $TestInfo .= " <architecture>$Arch1</architecture>\n";
12586 $TestInfo .= " <gcc>$GccV1</gcc>\n";
12587 $TestInfo .= " </version1>\n";
12588
12589 $TestInfo .= " <version2>\n";
12590 $TestInfo .= " <number>".$Descriptor{2}{"Version"}."</number>\n";
12591 $TestInfo .= " <architecture>$Arch2</architecture>\n";
12592 $TestInfo .= " <gcc>$GccV2</gcc>\n";
12593 $TestInfo .= " </version2>\n";
12594 $TestInfo = "<test_info>\n".$TestInfo."</test_info>\n\n";
12595
12596 # test results
12597 $TestResults .= " <headers>\n";
12598 foreach my $Name (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
12599 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012600 my $Identity = $Registered_Headers{1}{$Name}{"Identity"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012601 my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
12602 $TestResults .= " <name>".get_filename($Name).$Comment."</name>\n";
12603 }
12604 $TestResults .= " </headers>\n";
12605
12606 $TestResults .= " <libs>\n";
12607 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
12608 {
12609 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
12610 $TestResults .= " <name>$Library</name>\n";
12611 }
12612 $TestResults .= " </libs>\n";
12613
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012614 $TestResults .= " <symbols>".(keys(%{$CheckedSymbols{$Level}}) - keys(%GeneratedSymbols))."</symbols>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012615 $TestResults .= " <types>".$TotalTypes."</types>\n";
12616
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012617 $TestResults .= " <verdict>".$RESULT{$Level}{"Verdict"}."</verdict>\n";
12618 $TestResults .= " <affected>".$RESULT{$Level}{"Affected"}."</affected>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012619 $TestResults = "<test_results>\n".$TestResults."</test_results>\n\n";
12620
12621 # problem summary
12622 $Problem_Summary .= " <added_symbols>".$Added."</added_symbols>\n";
12623 $Problem_Summary .= " <removed_symbols>".$Removed."</removed_symbols>\n";
12624
12625 $Problem_Summary .= " <problems_with_types>\n";
12626 $Problem_Summary .= " <high>$T_Problems_High</high>\n";
12627 $Problem_Summary .= " <medium>$T_Problems_Medium</medium>\n";
12628 $Problem_Summary .= " <low>$T_Problems_Low</low>\n";
12629 $Problem_Summary .= " <safe>$T_Other</safe>\n";
12630 $Problem_Summary .= " </problems_with_types>\n";
12631
12632 $Problem_Summary .= " <problems_with_symbols>\n";
12633 $Problem_Summary .= " <high>$I_Problems_High</high>\n";
12634 $Problem_Summary .= " <medium>$I_Problems_Medium</medium>\n";
12635 $Problem_Summary .= " <low>$I_Problems_Low</low>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012636 $Problem_Summary .= " <safe>$I_Other</safe>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012637 $Problem_Summary .= " </problems_with_symbols>\n";
12638
12639 $Problem_Summary .= " <problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012640 $Problem_Summary .= " <low>$C_Problems_Low</low>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012641 $Problem_Summary .= " </problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012642 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012643 {
12644 $Problem_Summary .= " <impl>\n";
12645 $Problem_Summary .= " <low>".keys(%ImplProblems)."</low>\n";
12646 $Problem_Summary .= " </impl>\n";
12647 }
12648 $Problem_Summary = "<problem_summary>\n".$Problem_Summary."</problem_summary>\n\n";
12649
12650 return ($TestInfo.$TestResults.$Problem_Summary, "");
12651 }
12652 else
12653 { # HTML
12654 # test info
12655 $TestInfo = "<h2>Test Info</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012656 $TestInfo .= "<table class='summary'>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012657 $TestInfo .= "<tr><th>".ucfirst($TargetComponent)." Name</th><td>$TargetLibraryFName</td></tr>\n";
12658
12659 my (@VInf1, @VInf2, $AddTestInfo) = ();
12660 if($Arch1 ne "unknown"
12661 and $Arch2 ne "unknown")
12662 { # CPU arch
12663 if($Arch1 eq $Arch2)
12664 { # go to the separate section
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012665 $AddTestInfo .= "<tr><th>CPU Type</th><td>".showArch($Arch1)."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012666 }
12667 else
12668 { # go to the version number
12669 push(@VInf1, showArch($Arch1));
12670 push(@VInf2, showArch($Arch2));
12671 }
12672 }
12673 if($GccV1 ne "unknown"
12674 and $GccV2 ne "unknown"
12675 and $OStarget ne "windows")
12676 { # GCC version
12677 if($GccV1 eq $GccV2)
12678 { # go to the separate section
12679 $AddTestInfo .= "<tr><th>GCC Version</th><td>$GccV1</td></tr>\n";
12680 }
12681 else
12682 { # go to the version number
12683 push(@VInf1, "gcc ".$GccV1);
12684 push(@VInf2, "gcc ".$GccV2);
12685 }
12686 }
12687 # show long version names with GCC version and CPU architecture name (if different)
12688 $TestInfo .= "<tr><th>Version #1</th><td>".$Descriptor{1}{"Version"}.(@VInf1?" (".join(", ", reverse(@VInf1)).")":"")."</td></tr>\n";
12689 $TestInfo .= "<tr><th>Version #2</th><td>".$Descriptor{2}{"Version"}.(@VInf2?" (".join(", ", reverse(@VInf2)).")":"")."</td></tr>\n";
12690 $TestInfo .= $AddTestInfo;
12691 #if($COMMON_LANGUAGE{1}) {
12692 # $TestInfo .= "<tr><th>Language</th><td>".$COMMON_LANGUAGE{1}."</td></tr>\n";
12693 #}
12694 if($ExtendedCheck) {
12695 $TestInfo .= "<tr><th>Mode</th><td>Extended</td></tr>\n";
12696 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012697 if($JoinReport)
12698 {
12699 if($Level eq "Binary") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012700 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Binary Compatibility</td></tr>\n"; # Run-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012701 }
12702 if($Level eq "Source") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012703 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Source Compatibility</td></tr>\n"; # Build-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012704 }
12705 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012706 $TestInfo .= "</table>\n";
12707
12708 # test results
12709 $TestResults = "<h2>Test Results</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012710 $TestResults .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012711
12712 my $Headers_Link = "0";
12713 $Headers_Link = "<a href='#Headers' style='color:Blue;'>".keys(%{$Registered_Headers{1}})."</a>" if(keys(%{$Registered_Headers{1}})>0);
12714 $TestResults .= "<tr><th>Total Header Files</th><td>".($CheckObjectsOnly?"0&#160;(not&#160;analyzed)":$Headers_Link)."</td></tr>\n";
12715
12716 if(not $ExtendedCheck)
12717 {
12718 my $Libs_Link = "0";
12719 $Libs_Link = "<a href='#Libs' style='color:Blue;'>".keys(%{$Library_Symbol{1}})."</a>" if(keys(%{$Library_Symbol{1}})>0);
12720 $TestResults .= "<tr><th>Total ".ucfirst($SLIB_TYPE)." Libraries</th><td>".($CheckHeadersOnly?"0&#160;(not&#160;analyzed)":$Libs_Link)."</td></tr>\n";
12721 }
12722
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012723 $TestResults .= "<tr><th>Total Symbols / Types</th><td>".(keys(%{$CheckedSymbols{$Level}}) - keys(%GeneratedSymbols))." / ".$TotalTypes."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012724
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012725 my $META_DATA = $RESULT{$Level}{"Problems"}?"verdict:incompatible;":"verdict:compatible;";
12726 if($JoinReport) {
12727 $META_DATA = "kind:".lc($Level).";".$META_DATA;
12728 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012729 $TestResults .= "<tr><th>Verdict</th>";
12730 if($RESULT{$Level}{"Problems"}) {
12731 $TestResults .= "<td><span style='color:Red;'><b>Incompatible<br/>(".$RESULT{$Level}{"Affected"}."%)</b></span></td>";
12732 }
12733 else {
12734 $TestResults .= "<td><span style='color:Green;'><b>Compatible</b></span></td>";
12735 }
12736 $TestResults .= "</tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012737 $TestResults .= "</table>\n";
12738
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012739 $META_DATA .= "affected:".$RESULT{$Level}{"Affected"}.";";# in percents
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012740 # problem summary
12741 $Problem_Summary = "<h2>Problem Summary</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012742 $Problem_Summary .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012743 $Problem_Summary .= "<tr><th></th><th style='text-align:center;'>Severity</th><th style='text-align:center;'>Count</th></tr>";
12744
12745 my $Added_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012746 if($Added>0)
12747 {
12748 if($JoinReport) {
12749 $Added_Link = "<a href='#".$Level."_Added' style='color:Blue;'>$Added</a>";
12750 }
12751 else {
12752 $Added_Link = "<a href='#Added' style='color:Blue;'>$Added</a>";
12753 }
12754 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012755 #$Added_Link = "n/a" if($CheckHeadersOnly);
12756 $META_DATA .= "added:$Added;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012757 $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 +040012758
12759 my $Removed_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012760 if($Removed>0)
12761 {
12762 if($JoinReport) {
12763 $Removed_Link = "<a href='#".$Level."_Removed' style='color:Blue;'>$Removed</a>"
12764 }
12765 else {
12766 $Removed_Link = "<a href='#Removed' style='color:Blue;'>$Removed</a>"
12767 }
12768 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012769 #$Removed_Link = "n/a" if($CheckHeadersOnly);
12770 $META_DATA .= "removed:$Removed;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012771 $Problem_Summary .= "<tr><th>Removed Symbols</th>";
12772 $Problem_Summary .= "<td>High</td><td".getStyle("I", "R", $Removed).">$Removed_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012773
12774 my $TH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012775 $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 +040012776 $TH_Link = "n/a" if($CheckObjectsOnly);
12777 $META_DATA .= "type_problems_high:$T_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012778 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Data Types</th>";
12779 $Problem_Summary .= "<td>High</td><td".getStyle("T", "H", $T_Problems_High).">$TH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012780
12781 my $TM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012782 $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 +040012783 $TM_Link = "n/a" if($CheckObjectsOnly);
12784 $META_DATA .= "type_problems_medium:$T_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012785 $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 +040012786
12787 my $TL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012788 $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 +040012789 $TL_Link = "n/a" if($CheckObjectsOnly);
12790 $META_DATA .= "type_problems_low:$T_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012791 $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 +040012792
12793 my $IH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012794 $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 +040012795 $IH_Link = "n/a" if($CheckObjectsOnly);
12796 $META_DATA .= "interface_problems_high:$I_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012797 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Symbols</th>";
12798 $Problem_Summary .= "<td>High</td><td".getStyle("I", "H", $I_Problems_High).">$IH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012799
12800 my $IM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012801 $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 +040012802 $IM_Link = "n/a" if($CheckObjectsOnly);
12803 $META_DATA .= "interface_problems_medium:$I_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012804 $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 +040012805
12806 my $IL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012807 $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 +040012808 $IL_Link = "n/a" if($CheckObjectsOnly);
12809 $META_DATA .= "interface_problems_low:$I_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012810 $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 +040012811
12812 my $ChangedConstants_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012813 if(keys(%{$CheckedSymbols{$Level}}) and $C_Problems_Low)
12814 {
12815 if($JoinReport) {
12816 $ChangedConstants_Link = "<a href='#".$Level."_Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
12817 }
12818 else {
12819 $ChangedConstants_Link = "<a href='#Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
12820 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012821 }
12822 $ChangedConstants_Link = "n/a" if($CheckObjectsOnly);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012823 $META_DATA .= "changed_constants:$C_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012824 $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 +040012825
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012826 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012827 {
12828 my $ChangedImpl_Link = "0";
12829 $ChangedImpl_Link = "<a href='#Changed_Implementation' style='color:Blue;'>".keys(%ImplProblems)."</a>" if(keys(%ImplProblems)>0);
12830 $ChangedImpl_Link = "n/a" if($CheckHeadersOnly);
12831 $META_DATA .= "changed_implementation:".keys(%ImplProblems).";";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012832 $Problem_Summary .= "<tr><th>Problems with<br/>Implementation</th><td>Low</td><td".getStyle("Imp", "L", keys(%ImplProblems)).">$ChangedImpl_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012833 }
12834 # Safe Changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012835 if($T_Other and not $CheckObjectsOnly)
12836 {
12837 my $TS_Link = "<a href='#".get_Anchor("Type", $Level, "Safe")."' style='color:Blue;'>$T_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012838 $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 +040012839 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012840
12841 if($I_Other and not $CheckObjectsOnly)
12842 {
12843 my $IS_Link = "<a href='#".get_Anchor("Symbol", $Level, "Safe")."' style='color:Blue;'>$I_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012844 $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 +040012845 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012846
12847 $META_DATA .= "tool_version:$TOOL_VERSION";
12848 $Problem_Summary .= "</table>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012849 # $TestInfo = getLegend().$TestInfo;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012850 return ($TestInfo.$TestResults.$Problem_Summary, $META_DATA);
12851 }
12852}
12853
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012854sub getStyle($$$)
12855{
12856 my ($Subj, $Act, $Num) = @_;
12857 my %Style = (
12858 "A"=>"new",
12859 "R"=>"failed",
12860 "S"=>"passed",
12861 "L"=>"warning",
12862 "M"=>"failed",
12863 "H"=>"failed"
12864 );
12865 if($Num>0) {
12866 return " class='".$Style{$Act}."'";
12867 }
12868 return "";
12869}
12870
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012871sub show_number($)
12872{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012873 if($_[0])
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012874 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012875 my $Num = cut_off_number($_[0], 2, 0);
12876 if($Num eq "0")
12877 {
12878 foreach my $P (3 .. 7)
12879 {
12880 $Num = cut_off_number($_[0], $P, 1);
12881 if($Num ne "0") {
12882 last;
12883 }
12884 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012885 }
12886 if($Num eq "0") {
12887 $Num = $_[0];
12888 }
12889 return $Num;
12890 }
12891 return $_[0];
12892}
12893
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012894sub cut_off_number($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012895{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012896 my ($num, $digs_to_cut, $z) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012897 if($num!~/\./)
12898 {
12899 $num .= ".";
12900 foreach (1 .. $digs_to_cut-1) {
12901 $num .= "0";
12902 }
12903 }
12904 elsif($num=~/\.(.+)\Z/ and length($1)<$digs_to_cut-1)
12905 {
12906 foreach (1 .. $digs_to_cut - 1 - length($1)) {
12907 $num .= "0";
12908 }
12909 }
12910 elsif($num=~/\d+\.(\d){$digs_to_cut,}/) {
12911 $num=sprintf("%.".($digs_to_cut-1)."f", $num);
12912 }
12913 $num=~s/\.[0]+\Z//g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012914 if($z) {
12915 $num=~s/(\.[1-9]+)[0]+\Z/$1/g;
12916 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012917 return $num;
12918}
12919
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012920sub get_Report_ChangedConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012921{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012922 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012923 my $CHANGED_CONSTANTS = "";
12924 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012925 foreach my $Constant (keys(%{$ProblemsWithConstants{$Level}})) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012926 $ReportMap{$Constants{1}{$Constant}{"Header"}}{$Constant} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012927 }
12928 my $Kind = "Changed_Constant";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012929 if(not defined $CompatRules{$Level}{$Kind}) {
12930 return "";
12931 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012932 if($ReportFormat eq "xml")
12933 { # XML
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012934 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012935 {
12936 $CHANGED_CONSTANTS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012937 foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012938 {
12939 $CHANGED_CONSTANTS .= " <constant name=\"$Constant\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012940 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
12941 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
12942 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012943 $CHANGED_CONSTANTS .= " <problem id=\"$Kind\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012944 $CHANGED_CONSTANTS .= " <change".getXmlParams($Change, $ProblemsWithConstants{$Level}{$Constant}).">$Change</change>\n";
12945 $CHANGED_CONSTANTS .= " <effect".getXmlParams($Effect, $ProblemsWithConstants{$Level}{$Constant}).">$Effect</effect>\n";
12946 $CHANGED_CONSTANTS .= " <overcome".getXmlParams($Overcome, $ProblemsWithConstants{$Level}{$Constant}).">$Overcome</overcome>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012947 $CHANGED_CONSTANTS .= " </problem>\n";
12948 $CHANGED_CONSTANTS .= " </constant>\n";
12949 }
12950 $CHANGED_CONSTANTS .= " </header>\n";
12951 }
12952 $CHANGED_CONSTANTS = "<problems_with_constants severity=\"Low\">\n".$CHANGED_CONSTANTS."</problems_with_constants>\n\n";
12953 }
12954 else
12955 { # HTML
12956 my $Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012957 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012958 {
12959 $CHANGED_CONSTANTS .= "<span class='h_name'>$HeaderName</span><br/>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012960 foreach my $Name (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012961 {
12962 $Number += 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012963 my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $ProblemsWithConstants{$Level}{$Name});
12964 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012965 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 +040012966 $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 +040012967 $Report = $ContentSpanStart."<span class='extendable'>[+]</span> ".$Name.$ContentSpanEnd."<br/>\n".$Report;
12968 $CHANGED_CONSTANTS .= insertIDs($Report);
12969 }
12970 $CHANGED_CONSTANTS .= "<br/>\n";
12971 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012972 if($CHANGED_CONSTANTS)
12973 {
12974 my $Anchor = "<a name='Changed_Constants'></a>";
12975 if($JoinReport) {
12976 $Anchor = "<a name='".$Level."_Changed_Constants'></a>";
12977 }
12978 $CHANGED_CONSTANTS = $Anchor."<h2>Problems with Constants ($Number)</h2><hr/>\n".$CHANGED_CONSTANTS.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012979 }
12980 }
12981 return $CHANGED_CONSTANTS;
12982}
12983
12984sub get_Report_Impl()
12985{
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012986 my $CHANGED_IMPLEMENTATION = "";
12987 my %ReportMap = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012988 foreach my $Interface (sort keys(%ImplProblems))
12989 {
12990 my $HeaderName = $CompleteSignature{1}{$Interface}{"Header"};
12991 my $DyLib = $Symbol_Library{1}{$Interface};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012992 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012993 }
12994 my $Changed_Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012995 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012996 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012997 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012998 {
12999 my $FDyLib=$DyLib.($DyLib!~/\.\w+\Z/?" (.$LIB_EXT)":"");
13000 if($HeaderName) {
13001 $CHANGED_IMPLEMENTATION .= "<span class='h_name'>$HeaderName</span>, <span class='lib_name'>$FDyLib</span><br/>\n";
13002 }
13003 else {
13004 $CHANGED_IMPLEMENTATION .= "<span class='lib_name'>$DyLib</span><br/>\n";
13005 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013006 my %NameSpaceSymbols = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013007 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013008 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013009 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013010 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013011 {
13012 $CHANGED_IMPLEMENTATION .= ($NameSpace)?"<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span>"."<br/>\n":"";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013013 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013014 foreach my $Interface (@SortedInterfaces)
13015 {
13016 $Changed_Number += 1;
13017 my $Signature = get_Signature($Interface, 1);
13018 if($NameSpace) {
13019 $Signature=~s/(\W|\A)\Q$NameSpace\E\:\:(\w)/$1$2/g;
13020 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013021 $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 +040013022 }
13023 }
13024 $CHANGED_IMPLEMENTATION .= "<br/>\n";
13025 }
13026 }
13027 if($CHANGED_IMPLEMENTATION) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013028 $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 +040013029 }
13030 return $CHANGED_IMPLEMENTATION;
13031}
13032
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013033sub getTitle($$$)
13034{
13035 my ($Header, $Library, $NameSpace) = @_;
13036 my $Title = "";
13037 if($Library and $Library!~/\.\w+\Z/) {
13038 $Library .= " (.$LIB_EXT)";
13039 }
13040 if($Header and $Library)
13041 {
13042 $Title .= "<span class='h_name'>$Header</span>";
13043 $Title .= ", <span class='lib_name'>$Library</span><br/>\n";
13044 }
13045 elsif($Library) {
13046 $Title .= "<span class='lib_name'>$Library</span><br/>\n";
13047 }
13048 elsif($Header) {
13049 $Title .= "<span class='h_name'>$Header</span><br/>\n";
13050 }
13051 if($NameSpace) {
13052 $Title .= "<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n";
13053 }
13054 return $Title;
13055}
13056
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013057sub get_Report_Added($)
13058{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013059 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013060 my $ADDED_INTERFACES = "";
13061 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013062 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013063 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013064 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013065 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013066 if($Kind eq "Added_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013067 {
13068 my $HeaderName = $CompleteSignature{2}{$Interface}{"Header"};
13069 my $DyLib = $Symbol_Library{2}{$Interface};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013070 if($Level eq "Source" and $ReportFormat eq "html")
13071 { # do not show library name in HTML report
13072 $DyLib = "";
13073 }
13074 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013075 }
13076 }
13077 }
13078 if($ReportFormat eq "xml")
13079 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013080 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013081 {
13082 $ADDED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013083 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013084 {
13085 $ADDED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013086 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013087 $ADDED_INTERFACES .= " <name>$Interface</name>\n";
13088 }
13089 $ADDED_INTERFACES .= " </library>\n";
13090 }
13091 $ADDED_INTERFACES .= " </header>\n";
13092 }
13093 $ADDED_INTERFACES = "<added_symbols>\n".$ADDED_INTERFACES."</added_symbols>\n\n";
13094 }
13095 else
13096 { # HTML
13097 my $Added_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013098 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013099 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013100 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013101 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013102 my %NameSpaceSymbols = ();
13103 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
13104 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013105 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013106 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013107 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013108 $ADDED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
13109 my @SortedInterfaces = sort {lc(get_Signature($a, 2)) cmp lc(get_Signature($b, 2))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013110 foreach my $Interface (@SortedInterfaces)
13111 {
13112 $Added_Number += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013113 my $Signature = get_Signature($Interface, 2);
13114 if($NameSpace) {
13115 $Signature=~s/(\W|\A)\Q$NameSpace\E\:\:(\w)/$1$2/g;
13116 }
13117 if($Interface=~/\A(_Z|\?)/) {
13118 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013119 $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 +040013120 }
13121 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013122 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013123 }
13124 }
13125 else {
13126 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013127 $ADDED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013128 }
13129 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013130 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013131 }
13132 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013133 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013134 $ADDED_INTERFACES .= "<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013135 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013136 }
13137 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013138 if($ADDED_INTERFACES)
13139 {
13140 my $Anchor = "<a name='Added'></a>";
13141 if($JoinReport) {
13142 $Anchor = "<a name='".$Level."_Added'></a>";
13143 }
13144 $ADDED_INTERFACES = $Anchor."<h2>Added Symbols ($Added_Number)</h2><hr/>\n".$ADDED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013145 }
13146 }
13147 return $ADDED_INTERFACES;
13148}
13149
13150sub get_Report_Removed($)
13151{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013152 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013153 my $REMOVED_INTERFACES = "";
13154 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013155 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013156 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013157 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013158 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013159 if($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013160 {
13161 my $HeaderName = $CompleteSignature{1}{$Interface}{"Header"};
13162 my $DyLib = $Symbol_Library{1}{$Interface};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013163 if($Level eq "Source" and $ReportFormat eq "html")
13164 { # do not show library name in HTML report
13165 $DyLib = "";
13166 }
13167 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013168 }
13169 }
13170 }
13171 if($ReportFormat eq "xml")
13172 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013173 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013174 {
13175 $REMOVED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013176 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013177 {
13178 $REMOVED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013179 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013180 $REMOVED_INTERFACES .= " <name>$Interface</name>\n";
13181 }
13182 $REMOVED_INTERFACES .= " </library>\n";
13183 }
13184 $REMOVED_INTERFACES .= " </header>\n";
13185 }
13186 $REMOVED_INTERFACES = "<removed_symbols>\n".$REMOVED_INTERFACES."</removed_symbols>\n\n";
13187 }
13188 else
13189 { # HTML
13190 my $Removed_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013191 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013192 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013193 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013194 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013195 my %NameSpaceSymbols = ();
13196 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
13197 $NameSpaceSymbols{get_IntNameSpace($Interface, 1)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013198 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013199 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013200 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013201 $REMOVED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
13202 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013203 foreach my $Interface (@SortedInterfaces)
13204 {
13205 $Removed_Number += 1;
13206 my $SubReport = "";
13207 my $Signature = get_Signature($Interface, 1);
13208 if($NameSpace) {
13209 $Signature=~s/(\W|\A)\Q$NameSpace\E\:\:(\w)/$1$2/g;
13210 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013211 if($Interface=~/\A(_Z|\?)/)
13212 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013213 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013214 $REMOVED_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 +040013215 }
13216 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013217 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013218 }
13219 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013220 else
13221 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013222 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013223 $REMOVED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013224 }
13225 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013226 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013227 }
13228 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013229 }
13230 }
13231 $REMOVED_INTERFACES .= "<br/>\n";
13232 }
13233 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013234 if($REMOVED_INTERFACES)
13235 {
13236 my $Anchor = "<a name='Removed'></a><a name='Withdrawn'></a>";
13237 if($JoinReport) {
13238 $Anchor = "<a name='".$Level."_Removed'></a><a name='".$Level."_Withdrawn'></a>";
13239 }
13240 $REMOVED_INTERFACES = $Anchor."<h2>Removed Symbols ($Removed_Number)</h2><hr/>\n".$REMOVED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013241 }
13242 }
13243 return $REMOVED_INTERFACES;
13244}
13245
13246sub getXmlParams($$)
13247{
13248 my ($Content, $Problem) = @_;
13249 return "" if(not $Content or not $Problem);
13250 my %XMLparams = ();
13251 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
13252 {
13253 my $Macro = "\@".lc($Attr);
13254 if($Content=~/\Q$Macro\E/) {
13255 $XMLparams{lc($Attr)} = $Problem->{$Attr};
13256 }
13257 }
13258 my @PString = ();
13259 foreach my $P (sort {$b cmp $a} keys(%XMLparams)) {
13260 push(@PString, $P."=\"".htmlSpecChars($XMLparams{$P})."\"");
13261 }
13262 if(@PString) {
13263 return " ".join(" ", @PString);
13264 }
13265 else {
13266 return "";
13267 }
13268}
13269
13270sub addMarkup($)
13271{
13272 my $Content = $_[0];
13273 # auto-markup
13274 $Content=~s/\n[ ]*//; # spaces
13275 $Content=~s!(\@\w+\s*\(\@\w+\))!<nowrap>$1</nowrap>!g; # @old_type (@old_size)
13276 $Content=~s!(... \(\w+\))!<nowrap><b>$1</b></nowrap>!g; # ... (va_list)
13277 $Content=~s!([2-9]\))!<br/>$1!g; # 1), 2), ...
13278 if($Content=~/\ANOTE:/)
13279 { # notes
13280 $Content=~s!(NOTE):!<b>$1</b>:!g;
13281 }
13282 else {
13283 $Content=~s!(NOTE):!<br/><b>$1</b>:!g;
13284 }
13285 $Content=~s! (out)-! <b>$1</b>-!g; # out-parameters
13286 my @Keywords = (
13287 "void",
13288 "const",
13289 "static",
13290 "restrict",
13291 "volatile",
13292 "register",
13293 "virtual",
13294 "virtually"
13295 );
13296 my $MKeys = join("|", @Keywords);
13297 foreach (@Keywords) {
13298 $MKeys .= "|non-".$_;
13299 }
13300 $Content=~s!(added\s*|to\s*|from\s*|became\s*)($MKeys)([^\w-]|\Z)!$1<b>$2</b>$3!ig; # intrinsic types, modifiers
13301 return $Content;
13302}
13303
13304sub applyMacroses($$$$)
13305{
13306 my ($Level, $Kind, $Content, $Problem) = @_;
13307 return "" if(not $Content or not $Problem);
13308 $Problem->{"Word_Size"} = $WORD_SIZE{2};
13309 $Content = addMarkup($Content);
13310 # macros
13311 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
13312 {
13313 my $Macro = "\@".lc($Attr);
13314 my $Value = $Problem->{$Attr};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013315 if(not defined $Value
13316 or $Value eq "") {
13317 next;
13318 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013319 if($Value=~/\s\(/)
13320 { # functions
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013321 $Value=~s/\s*\[[\w\-]+\]//g; # remove quals
13322 $Value=~s/\s\w+(\)|,)/$1/g; # remove parameter names
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013323 $Value = black_name($Value);
13324 }
13325 elsif($Value=~/\s/) {
13326 $Value = "<span class='value'>".htmlSpecChars($Value)."</span>";
13327 }
13328 elsif($Value=~/\A\d+\Z/
13329 and ($Attr eq "Old_Size" or $Attr eq "New_Size"))
13330 { # bits to bytes
13331 if($Value % $BYTE_SIZE)
13332 { # bits
13333 if($Value==1) {
13334 $Value = "<b>".$Value."</b> bit";
13335 }
13336 else {
13337 $Value = "<b>".$Value."</b> bits";
13338 }
13339 }
13340 else
13341 { # bytes
13342 $Value /= $BYTE_SIZE;
13343 if($Value==1) {
13344 $Value = "<b>".$Value."</b> byte";
13345 }
13346 else {
13347 $Value = "<b>".$Value."</b> bytes";
13348 }
13349 }
13350 }
13351 else {
13352 $Value = "<b>".htmlSpecChars($Value)."</b>";
13353 }
13354 $Content=~s/\Q$Macro\E/$Value/g;
13355 }
13356
13357 if($Content=~/(\A|[^\@\w])\@\w/)
13358 {
13359 if(not $IncompleteRules{$Level}{$Kind})
13360 { # only one warning
13361 printMsg("WARNING", "incomplete rule \"$Kind\" (\"$Level\")");
13362 $IncompleteRules{$Level}{$Kind} = 1;
13363 }
13364 }
13365 $Content=~s!<nowrap>(.+?)</nowrap>!<span class='nowrap'>$1</span>!g;
13366 return $Content;
13367}
13368
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013369sub get_Report_SymbolProblems($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013370{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013371 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013372 my $INTERFACE_PROBLEMS = "";
13373 my (%ReportMap, %SymbolChanges) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013374 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013375 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013376 my ($SN, $SS, $SV) = separate_symbol($Symbol);
13377 if($SV and defined $CompatProblems{$Level}{$SN}) {
13378 next;
13379 }
13380 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013381 {
13382 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013383 and $Kind ne "Added_Symbol" and $Kind ne "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013384 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013385 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
13386 my $DyLib = $Symbol_Library{1}{$Symbol};
13387 if(not $DyLib and my $VSym = $SymVer{1}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013388 { # Symbol with Version
13389 $DyLib = $Symbol_Library{1}{$VSym};
13390 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013391 if($Level eq "Source" and $ReportFormat eq "html")
13392 { # do not show library name in HTML report
13393 $DyLib = "";
13394 }
13395 %{$SymbolChanges{$Symbol}{$Kind}} = %{$CompatProblems{$Level}{$Symbol}{$Kind}};
13396 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013397 {
13398 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013399 if($Priority ne $TargetSeverity) {
13400 delete($SymbolChanges{$Symbol}{$Kind}{$Location});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013401 }
13402 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013403 if(not keys(%{$SymbolChanges{$Symbol}{$Kind}}))
13404 {
13405 delete($SymbolChanges{$Symbol}{$Kind});
13406 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013407 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013408 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013409 }
13410 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013411 if(not keys(%{$SymbolChanges{$Symbol}})) {
13412 delete($SymbolChanges{$Symbol});
13413 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013414 }
13415 if($ReportFormat eq "xml")
13416 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013417 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013418 {
13419 $INTERFACE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013420 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013421 {
13422 $INTERFACE_PROBLEMS .= " <library name=\"$DyLib\">\n";
13423 foreach my $Symbol (sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%SymbolChanges))
13424 {
13425 $INTERFACE_PROBLEMS .= " <symbol name=\"$Symbol\">\n";
13426 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
13427 {
13428 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
13429 {
13430 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013431 $Problem{"Param_Pos"} = showNum($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013432 $INTERFACE_PROBLEMS .= " <problem id=\"$Kind\">\n";
13433 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
13434 $INTERFACE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
13435 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
13436 $INTERFACE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
13437 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
13438 $INTERFACE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
13439 $INTERFACE_PROBLEMS .= " </problem>\n";
13440 }
13441 }
13442 $INTERFACE_PROBLEMS .= " </symbol>\n";
13443 }
13444 $INTERFACE_PROBLEMS .= " </library>\n";
13445 }
13446 $INTERFACE_PROBLEMS .= " </header>\n";
13447 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013448 $INTERFACE_PROBLEMS = "<problems_with_symbols severity=\"$TargetSeverity\">\n".$INTERFACE_PROBLEMS."</problems_with_symbols>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013449 }
13450 else
13451 { # HTML
13452 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013453 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013454 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013455 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013456 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013457 my (%NameSpaceSymbols, %NewSignature) = ();
13458 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
13459 $NameSpaceSymbols{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013460 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013461 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013462 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013463 $INTERFACE_PROBLEMS .= getTitle($HeaderName, $DyLib, $NameSpace);
13464 my @SortedInterfaces = sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%{$NameSpaceSymbols{$NameSpace}});
13465 foreach my $Symbol (@SortedInterfaces)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013466 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013467 my $Signature = get_Signature($Symbol, 1);
13468 my $SYMBOL_REPORT = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013469 my $ProblemNum = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013470 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013471 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013472 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013473 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013474 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013475 $Problem{"Param_Pos"} = showNum($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013476 if($Problem{"New_Signature"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013477 $NewSignature{$Symbol} = $Problem{"New_Signature"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013478 }
13479 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
13480 {
13481 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013482 $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 +040013483 $ProblemNum += 1;
13484 $ProblemsNum += 1;
13485 }
13486 }
13487 }
13488 $ProblemNum -= 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013489 if($SYMBOL_REPORT)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013490 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013491 $INTERFACE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> ";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013492 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013493 $INTERFACE_PROBLEMS .= highLight_Signature_Italic_Color($Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013494 }
13495 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013496 $INTERFACE_PROBLEMS .= $Symbol;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013497 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013498 $INTERFACE_PROBLEMS .= " ($ProblemNum)".$ContentSpanEnd."<br/>\n";
13499 $INTERFACE_PROBLEMS .= $ContentDivStart."\n";
13500 if($NewSignature{$Symbol})
13501 { # argument list changed to
13502 $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 +040013503 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013504 if($Symbol=~/\A(_Z|\?)/) {
13505 $INTERFACE_PROBLEMS .= "<span class='mangled'>&#160;&#160;&#160;&#160;[symbol: <b>$Symbol</b>]</span><br/>\n";
13506 }
13507 $INTERFACE_PROBLEMS .= "<table class='ptable'><tr><th width='2%'></th><th width='47%'>Change</th><th>Effect</th></tr>$SYMBOL_REPORT</table><br/>\n";
13508 $INTERFACE_PROBLEMS .= $ContentDivEnd;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013509 if($NameSpace) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013510 $INTERFACE_PROBLEMS=~s/(\W|\A)\Q$NameSpace\E\:\:(\w)/$1$2/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013511 }
13512 }
13513 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013514 $INTERFACE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013515 }
13516 }
13517 }
13518 if($INTERFACE_PROBLEMS)
13519 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013520 $INTERFACE_PROBLEMS = insertIDs($INTERFACE_PROBLEMS);
13521 my $Title = "Problems with Symbols, $TargetSeverity Severity";
13522 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013523 { # Safe Changes
13524 $Title = "Other Changes in Symbols";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013525 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013526 $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 +040013527 }
13528 }
13529 return $INTERFACE_PROBLEMS;
13530}
13531
13532sub get_Report_TypeProblems($$)
13533{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013534 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013535 my $TYPE_PROBLEMS = "";
13536 my (%ReportMap, %TypeChanges, %TypeType) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013537 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013538 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013539 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013540 {
13541 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
13542 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013543 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013544 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013545 my $TypeName = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
13546 my $TypeType = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
13547 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
13548 $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"} = lc($TypeType);
13549 my $Severity = getProblemSeverity($Level, $Kind);
13550 if($Severity eq "Safe"
13551 and $TargetSeverity ne "Safe") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013552 next;
13553 }
13554 if(not $TypeType{$TypeName}
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013555 or $TypeType{$TypeName} eq "struct")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013556 { # register type of the type, select "class" if type has "class"- and "struct"-type changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013557 $TypeType{$TypeName} = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013558 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013559
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013560 if(cmpSeverities($Type_MaxSeverity{$Level}{$TypeName}{$Kind}{$Target}, $Severity))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013561 { # select a problem with the highest priority
13562 next;
13563 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013564 %{$TypeChanges{$TypeName}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013565 }
13566 }
13567 }
13568 }
13569 my %Kinds_Locations = ();
13570 foreach my $TypeName (keys(%TypeChanges))
13571 {
13572 my %Kinds_Target = ();
13573 foreach my $Kind (sort keys(%{$TypeChanges{$TypeName}}))
13574 {
13575 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
13576 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013577 my $Severity = getProblemSeverity($Level, $Kind);
13578 if($Severity ne $TargetSeverity)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013579 { # other priority
13580 delete($TypeChanges{$TypeName}{$Kind}{$Location});
13581 next;
13582 }
13583 $Kinds_Locations{$TypeName}{$Kind}{$Location} = 1;
13584 my $Target = $TypeChanges{$TypeName}{$Kind}{$Location}{"Target"};
13585 if($Kinds_Target{$Kind}{$Target})
13586 { # duplicate target
13587 delete($TypeChanges{$TypeName}{$Kind}{$Location});
13588 next;
13589 }
13590 $Kinds_Target{$Kind}{$Target} = 1;
13591 my $HeaderName = get_TypeAttr($TName_Tid{1}{$TypeName}, 1, "Header");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013592 $ReportMap{$HeaderName}{$TypeName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013593 }
13594 if(not keys(%{$TypeChanges{$TypeName}{$Kind}})) {
13595 delete($TypeChanges{$TypeName}{$Kind});
13596 }
13597 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013598 if(not keys(%{$TypeChanges{$TypeName}})) {
13599 delete($TypeChanges{$TypeName});
13600 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013601 }
13602 if($ReportFormat eq "xml")
13603 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013604 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013605 {
13606 $TYPE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013607 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013608 {
13609 $TYPE_PROBLEMS .= " <type name=\"".htmlSpecChars($TypeName)."\">\n";
13610 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
13611 {
13612 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
13613 {
13614 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
13615 $TYPE_PROBLEMS .= " <problem id=\"$Kind\">\n";
13616 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
13617 $TYPE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
13618 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
13619 $TYPE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
13620 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
13621 $TYPE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
13622 $TYPE_PROBLEMS .= " </problem>\n";
13623 }
13624 }
13625 $TYPE_PROBLEMS .= getAffectedInterfaces($Level, $TypeName, $Kinds_Locations{$TypeName});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013626 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013627 $TYPE_PROBLEMS .= showVTables($TypeName);
13628 }
13629 $TYPE_PROBLEMS .= " </type>\n";
13630 }
13631 $TYPE_PROBLEMS .= " </header>\n";
13632 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013633 $TYPE_PROBLEMS = "<problems_with_types severity=\"$TargetSeverity\">\n".$TYPE_PROBLEMS."</problems_with_types>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013634 }
13635 else
13636 { # HTML
13637 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013638 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013639 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013640 my (%NameSpace_Type) = ();
13641 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013642 $NameSpace_Type{parse_TypeNameSpace($TypeName, 1)}{$TypeName} = 1;
13643 }
13644 foreach my $NameSpace (sort keys(%NameSpace_Type))
13645 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013646 $TYPE_PROBLEMS .= getTitle($HeaderName, "", $NameSpace);
13647 my @SortedTypes = sort {$TypeType{$a}." ".lc($a) cmp $TypeType{$b}." ".lc($b)} keys(%{$NameSpace_Type{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013648 foreach my $TypeName (@SortedTypes)
13649 {
13650 my $ProblemNum = 1;
13651 my $TYPE_REPORT = "";
13652 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
13653 {
13654 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
13655 {
13656 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
13657 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
13658 {
13659 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
13660 $TYPE_REPORT .= "<tr><th>$ProblemNum</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>$Effect</td></tr>\n";
13661 $ProblemNum += 1;
13662 $ProblemsNum += 1;
13663 }
13664 }
13665 }
13666 $ProblemNum -= 1;
13667 if($TYPE_REPORT)
13668 {
13669 my $Affected = getAffectedInterfaces($Level, $TypeName, $Kinds_Locations{$TypeName});
13670 my $ShowVTables = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013671 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013672 $ShowVTables = showVTables($TypeName);
13673 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013674 $TYPE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> <span class='ttype'>".$TypeType{$TypeName}."</span> ".htmlSpecChars($TypeName)." ($ProblemNum)".$ContentSpanEnd;
13675 $TYPE_PROBLEMS .= "<br/>\n".$ContentDivStart."<table class='ptable'><tr>\n";
13676 $TYPE_PROBLEMS .= "<th width='2%'></th><th width='47%'>Change</th>\n";
13677 $TYPE_PROBLEMS .= "<th>Effect</th></tr>".$TYPE_REPORT."</table>\n";
13678 $TYPE_PROBLEMS .= $ShowVTables.$Affected."<br/><br/>".$ContentDivEnd."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013679 if($NameSpace) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013680 $TYPE_PROBLEMS=~s/(\W|\A)\Q$NameSpace\E\:\:(\w|\~)/$1$2/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013681 }
13682 }
13683 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013684 $TYPE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013685 }
13686 }
13687 if($TYPE_PROBLEMS)
13688 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013689 $TYPE_PROBLEMS = insertIDs($TYPE_PROBLEMS);
13690 my $Title = "Problems with Data Types, $TargetSeverity Severity";
13691 my $Anchor = "Type_Problems_$TargetSeverity";
13692 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013693 { # Safe Changes
13694 $Title = "Other Changes in Data Types";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013695 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013696 $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 +040013697 }
13698 }
13699 return $TYPE_PROBLEMS;
13700}
13701
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013702sub get_Anchor($$$)
13703{
13704 my ($Kind, $Level, $Severity) = @_;
13705 if($JoinReport)
13706 {
13707 if($Severity eq "Safe") {
13708 return "Other_".$Level."_Changes_In_".$Kind."s";
13709 }
13710 else {
13711 return $Kind."_".$Level."_Problems_".$Severity;
13712 }
13713 }
13714 else
13715 {
13716 if($Severity eq "Safe") {
13717 return "Other_Changes_In_".$Kind."s";
13718 }
13719 else {
13720 return $Kind."_Problems_".$Severity;
13721 }
13722 }
13723}
13724
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013725sub showVTables($)
13726{
13727 my $TypeName = $_[0];
13728 my $TypeId1 = $TName_Tid{1}{$TypeName};
13729 my %Type1 = get_Type($Tid_TDid{1}{$TypeId1}, $TypeId1, 1);
13730 if(defined $Type1{"VTable"}
13731 and keys(%{$Type1{"VTable"}}))
13732 {
13733 my $TypeId2 = $TName_Tid{2}{$TypeName};
13734 my %Type2 = get_Type($Tid_TDid{2}{$TypeId2}, $TypeId2, 2);
13735 if(defined $Type2{"VTable"}
13736 and keys(%{$Type2{"VTable"}}))
13737 {
13738 my %Indexes = map {$_=>1} (keys(%{$Type1{"VTable"}}), keys(%{$Type2{"VTable"}}));
13739 my %Entries = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013740 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Indexes)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013741 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013742 $Entries{$Index}{"E1"} = simpleVEntry($Type1{"VTable"}{$Index});
13743 $Entries{$Index}{"E2"} = simpleVEntry($Type2{"VTable"}{$Index});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013744 }
13745 my $VTABLES = "";
13746 if($ReportFormat eq "xml")
13747 { # XML
13748 $VTABLES .= " <vtable>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013749 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013750 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013751 $VTABLES .= " <entry offset=\"".$Index."\">\n";
13752 $VTABLES .= " <old>".htmlSpecChars($Entries{$Index}{"E1"})."</old>\n";
13753 $VTABLES .= " <new>".htmlSpecChars($Entries{$Index}{"E2"})."</new>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013754 $VTABLES .= " </entry>\n";
13755 }
13756 $VTABLES .= " </vtable>\n\n";
13757 }
13758 else
13759 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013760 $VTABLES .= "<table class='vtable'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013761 $VTABLES .= "<tr><th width='2%'>Offset</th>";
13762 $VTABLES .= "<th width='45%'>Virtual Table (Old) - ".(keys(%{$Type1{"VTable"}}))." entries</th>";
13763 $VTABLES .= "<th>Virtual Table (New) - ".(keys(%{$Type2{"VTable"}}))." entries</th></tr>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013764 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013765 {
13766 my ($Color1, $Color2) = ("", "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013767 if($Entries{$Index}{"E1"} ne $Entries{$Index}{"E2"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013768 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013769 if($Entries{$Index}{"E1"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013770 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013771 $Color1 = " class='failed'";
13772 $Color2 = " class='failed'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013773 }
13774 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013775 $Color2 = " class='warning'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013776 }
13777 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013778 $VTABLES .= "<tr><th>".$Index."</th>\n";
13779 $VTABLES .= "<td$Color1>".htmlSpecChars($Entries{$Index}{"E1"})."</td>\n";
13780 $VTABLES .= "<td$Color2>".htmlSpecChars($Entries{$Index}{"E2"})."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013781 }
13782 $VTABLES .= "</table><br/>\n";
13783 $VTABLES = $ContentDivStart.$VTABLES.$ContentDivEnd;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013784 $VTABLES = $ContentSpanStart_Info."[+] show v-table (old and new)".$ContentSpanEnd."<br/>\n".$VTABLES;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013785 }
13786 return $VTABLES;
13787 }
13788 }
13789 return "";
13790}
13791
13792sub simpleVEntry($)
13793{
13794 my $VEntry = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013795 if(not defined $VEntry
13796 or $VEntry eq "") {
13797 return "";
13798 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013799 $VEntry=~s/\A(.+)::(_ZThn.+)\Z/$2/; # thunks
13800 $VEntry=~s/_ZTI\w+/typeinfo/g; # typeinfo
13801 if($VEntry=~/\A_ZThn.+\Z/) {
13802 $VEntry = "non-virtual thunk";
13803 }
13804 $VEntry=~s/\A\(int \(\*\)\(...\)\)([^\(\d])/$1/i;
13805 # support for old GCC versions
13806 $VEntry=~s/\A0u\Z/(int (*)(...))0/;
13807 $VEntry=~s/\A4294967268u\Z/(int (*)(...))-0x000000004/;
13808 $VEntry=~s/\A&_Z\Z/& _Z/;
13809 # templates
13810 if($VEntry=~s/ \[with (\w+) = (.+?)(, [^=]+ = .+|])\Z//g)
13811 { # std::basic_streambuf<_CharT, _Traits>::imbue [with _CharT = char, _Traits = std::char_traits<char>]
13812 # become std::basic_streambuf<char, ...>::imbue
13813 my ($Pname, $Pval) = ($1, $2);
13814 if($Pname eq "_CharT" and $VEntry=~/\Astd::/)
13815 { # stdc++ typedefs
13816 $VEntry=~s/<$Pname(, [^<>]+|)>/<$Pval>/g;
13817 # FIXME: simplify names using stdcxx typedefs (StdCxxTypedef)
13818 # The typedef info should be added to ABI dumps
13819 }
13820 else
13821 {
13822 $VEntry=~s/<$Pname>/<$Pval>/g;
13823 $VEntry=~s/<$Pname, [^<>]+>/<$Pval, ...>/g;
13824 }
13825 }
13826 $VEntry=~s/([^:]+)::\~([^:]+)\Z/~$1/; # destructors
13827 return $VEntry;
13828}
13829
13830sub getAffectedInterfaces($$$)
13831{
13832 my ($Level, $Target_TypeName, $Kinds_Locations) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013833 my (%INumber, %SymProblems) = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013834 my $LIMIT = 1000;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013835 foreach my $Symbol (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 +040013836 {
13837 last if(keys(%INumber)>$LIMIT);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013838 if(($Symbol=~/C2E|D2E|D0E/))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013839 { # duplicated problems for C2 constructors, D2 and D0 destructors
13840 next;
13841 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013842 my ($SN, $SS, $SV) = separate_symbol($Symbol);
13843 if($Level eq "Source")
13844 { # remove symbol version
13845 $Symbol=$SN;
13846 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013847 my ($MinPath_Length, $ProblemLocation_Last) = (-1, "");
13848 my $Severity_Max = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013849 my $Signature = get_Signature($Symbol, 1);
13850 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013851 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013852 foreach my $Location (keys(%{$CompatProblems{$Level}{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013853 {
13854 if(not defined $Kinds_Locations->{$Kind}
13855 or not $Kinds_Locations->{$Kind}{$Location}) {
13856 next;
13857 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013858 if($SV and defined $CompatProblems{$Level}{$SN}
13859 and defined $CompatProblems{$Level}{$SN}{$Kind}{$Location})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013860 { # duplicated problems for versioned symbols
13861 next;
13862 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013863 my $Type_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Type_Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013864 next if($Type_Name ne $Target_TypeName);
13865
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013866 my $Position = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Pos"};
13867 my $Param_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Name"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013868 my $Severity = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013869 $INumber{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013870 my $Path_Length = 0;
13871 my $ProblemLocation = $Location;
13872 if($Type_Name) {
13873 $ProblemLocation=~s/->\Q$Type_Name\E\Z//g;
13874 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013875 while($ProblemLocation=~/\-\>/g) {
13876 $Path_Length += 1;
13877 }
13878 if($MinPath_Length==-1 or ($Path_Length<=$MinPath_Length and $Severity_Val{$Severity}>$Severity_Max)
13879 or (cmp_locations($ProblemLocation, $ProblemLocation_Last) and $Severity_Val{$Severity}==$Severity_Max))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013880 {
13881 $MinPath_Length = $Path_Length;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013882 $Severity_Max = $Severity_Val{$Severity};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013883 $ProblemLocation_Last = $ProblemLocation;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013884 %{$SymProblems{$Symbol}} = (
13885 "Descr"=>getAffectDescription($Level, $Symbol, $Kind, $Location),
13886 "Severity_Max"=>$Severity_Max,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013887 "Signature"=>$Signature,
13888 "Position"=>$Position,
13889 "Param_Name"=>$Param_Name,
13890 "Location"=>$Location
13891 );
13892 }
13893 }
13894 }
13895 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013896 my @Symbols = keys(%SymProblems);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013897 @Symbols = sort {lc($tr_name{$a}?$tr_name{$a}:$a) cmp lc($tr_name{$b}?$tr_name{$b}:$b)} @Symbols;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013898 @Symbols = sort {$SymProblems{$b}{"Severity_Max"}<=>$SymProblems{$a}{"Severity_Max"}} @Symbols;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013899 my $Affected = "";
13900 if($ReportFormat eq "xml")
13901 { # XML
13902 $Affected .= " <affected>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013903 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013904 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013905 my $Param_Name = $SymProblems{$Symbol}{"Param_Name"};
13906 my $Description = $SymProblems{$Symbol}{"Descr"};
13907 my $Location = $SymProblems{$Symbol}{"Location"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013908 my $Target = "";
13909 if($Param_Name) {
13910 $Target = " affected=\"param\" param_name=\"$Param_Name\"";
13911 }
13912 elsif($Location=~/\Aretval(\-|\Z)/i) {
13913 $Target = " affected=\"retval\"";
13914 }
13915 elsif($Location=~/\Athis(\-|\Z)/i) {
13916 $Target = " affected=\"this\"";
13917 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013918 $Affected .= " <symbol$Target name=\"$Symbol\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013919 $Affected .= " <comment>".htmlSpecChars($Description)."</comment>\n";
13920 $Affected .= " </symbol>\n";
13921 }
13922 $Affected .= " </affected>\n";
13923 }
13924 else
13925 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013926 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013927 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013928 my $Description = $SymProblems{$Symbol}{"Descr"};
13929 my $Signature = $SymProblems{$Symbol}{"Signature"};
13930 my $Pos = $SymProblems{$Symbol}{"Position"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013931 $Affected .= "<span class='iname_b'>".highLight_Signature_PPos_Italic($Signature, $Pos, 1, 0, 0)."</span><br/>"."<div class='affect'>".htmlSpecChars($Description)."</div>\n";
13932 }
13933 $Affected = "<div class='affected'>".$Affected."</div>";
13934 if(keys(%INumber)>$LIMIT) {
13935 $Affected .= "and others ...<br/>";
13936 }
13937 if($Affected)
13938 {
13939 $Affected = $ContentDivStart.$Affected.$ContentDivEnd;
13940 my $AHeader = $ContentSpanStart_Affected."[+] affected symbols (".(keys(%INumber)>$LIMIT?"more than $LIMIT":keys(%INumber)).")".$ContentSpanEnd;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013941 $Affected = $AHeader.$Affected;
13942 }
13943 }
13944 return $Affected;
13945}
13946
13947sub cmp_locations($$)
13948{
13949 my ($Location1, $Location2) = @_;
13950 if($Location2=~/(\A|\W)(retval|this)(\W|\Z)/
13951 and $Location1!~/(\A|\W)(retval|this)(\W|\Z)/ and $Location1!~/\-\>/) {
13952 return 1;
13953 }
13954 if($Location2=~/(\A|\W)(retval|this)(\W|\Z)/ and $Location2=~/\-\>/
13955 and $Location1!~/(\A|\W)(retval|this)(\W|\Z)/ and $Location1=~/\-\>/) {
13956 return 1;
13957 }
13958 return 0;
13959}
13960
13961sub getAffectDescription($$$$)
13962{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013963 my ($Level, $Symbol, $Kind, $Location) = @_;
13964 my %Problem = %{$CompatProblems{$Level}{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013965 my $PPos = showNum($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013966 my @Sentence = ();
13967 $Location=~s/\A(.*)\-\>.+?\Z/$1/;
13968 if($Kind eq "Overridden_Virtual_Method"
13969 or $Kind eq "Overridden_Virtual_Method_B") {
13970 push(@Sentence, "The method '".$Problem{"New_Value"}."' will be called instead of this method.");
13971 }
13972 elsif($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
13973 {
13974 if($Location eq "this" or $Kind=~/(\A|_)Virtual(_|\Z)/)
13975 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013976 my $METHOD_TYPE = $CompleteSignature{1}{$Symbol}{"Constructor"}?"constructor":"method";
13977 my $ClassName = get_TypeName($CompleteSignature{1}{$Symbol}{"Class"}, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013978 if($ClassName eq $Problem{"Type_Name"}) {
13979 push(@Sentence, "This $METHOD_TYPE is from \'".$Problem{"Type_Name"}."\' class.");
13980 }
13981 else {
13982 push(@Sentence, "This $METHOD_TYPE is from derived class \'".$ClassName."\'.");
13983 }
13984 }
13985 else
13986 {
13987 if($Location=~/retval/)
13988 { # return value
13989 if($Location=~/\-\>/) {
13990 push(@Sentence, "Field \'".$Location."\' in return value");
13991 }
13992 else {
13993 push(@Sentence, "Return value");
13994 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013995 if(my $Init = $Problem{"InitialType_Type"})
13996 {
13997 if($Init eq "Pointer") {
13998 push(@Sentence, "(pointer)");
13999 }
14000 elsif($Init eq "Ref") {
14001 push(@Sentence, "(reference)");
14002 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014003 }
14004 }
14005 elsif($Location=~/this/)
14006 { # "this" pointer
14007 if($Location=~/\-\>/) {
14008 push(@Sentence, "Field \'".$Location."\' in the object of this method");
14009 }
14010 else {
14011 push(@Sentence, "\'this\' pointer");
14012 }
14013 }
14014 else
14015 { # parameters
14016 if($Location=~/\-\>/) {
14017 push(@Sentence, "Field \'".$Location."\' in $PPos parameter");
14018 }
14019 else {
14020 push(@Sentence, "$PPos parameter");
14021 }
14022 if($Problem{"Param_Name"}) {
14023 push(@Sentence, "\'".$Problem{"Param_Name"}."\'");
14024 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014025 if(my $Init = $Problem{"InitialType_Type"})
14026 {
14027 if($Init eq "Pointer") {
14028 push(@Sentence, "(pointer)");
14029 }
14030 elsif($Init eq "Ref") {
14031 push(@Sentence, "(reference)");
14032 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014033 }
14034 }
14035 if($Location eq "this") {
14036 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
14037 }
14038 elsif($Problem{"Start_Type_Name"} eq $Problem{"Type_Name"}) {
14039 push(@Sentence, "has type \'".$Problem{"Type_Name"}."\'.");
14040 }
14041 else {
14042 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
14043 }
14044 }
14045 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014046 if($ExtendedFuncs{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014047 push(@Sentence, " This is a symbol from an artificial external library that may use the \'$TargetLibraryName\' library and change its ABI after recompiling.");
14048 }
14049 return join(" ", @Sentence);
14050}
14051
14052sub get_XmlSign($$)
14053{
14054 my ($Symbol, $LibVersion) = @_;
14055 my $Info = $CompleteSignature{$LibVersion}{$Symbol};
14056 my $Report = "";
14057 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$Info->{"Param"}}))
14058 {
14059 my $Name = $Info->{"Param"}{$Pos}{"name"};
14060 my $TypeName = get_TypeName($Info->{"Param"}{$Pos}{"type"}, $LibVersion);
14061 foreach my $Typedef (keys(%ChangedTypedef))
14062 {
14063 my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
14064 $TypeName=~s/(\A|\W)\Q$Typedef\E(\W|\Z)/$1$Base$2/g;
14065 }
14066 $Report .= " <param pos=\"$Pos\">\n";
14067 $Report .= " <name>".$Name."</name>\n";
14068 $Report .= " <type>".htmlSpecChars($TypeName)."</type>\n";
14069 $Report .= " </param>\n";
14070 }
14071 if(my $Return = $Info->{"Return"})
14072 {
14073 my $RTName = get_TypeName($Return, $LibVersion);
14074 $Report .= " <retval>\n";
14075 $Report .= " <type>".htmlSpecChars($RTName)."</type>\n";
14076 $Report .= " </retval>\n";
14077 }
14078 return $Report;
14079}
14080
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014081sub get_Report_SymbolsInfo($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014082{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014083 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014084 my $Report = "<symbols_info>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014085 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014086 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014087 my ($SN, $SS, $SV) = separate_symbol($Symbol);
14088 if($SV and defined $CompatProblems{$Level}{$SN}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014089 next;
14090 }
14091 $Report .= " <symbol name=\"$Symbol\">\n";
14092 my ($S1, $P1, $S2, $P2) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014093 if(not $AddedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014094 {
14095 if(defined $CompleteSignature{1}{$Symbol}
14096 and defined $CompleteSignature{1}{$Symbol}{"Header"})
14097 {
14098 $P1 = get_XmlSign($Symbol, 1);
14099 $S1 = get_Signature($Symbol, 1);
14100 }
14101 elsif($Symbol=~/\A(_Z|\?)/) {
14102 $S1 = $tr_name{$Symbol};
14103 }
14104 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014105 if(not $RemovedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014106 {
14107 if(defined $CompleteSignature{2}{$Symbol}
14108 and defined $CompleteSignature{2}{$Symbol}{"Header"})
14109 {
14110 $P2 = get_XmlSign($Symbol, 2);
14111 $S2 = get_Signature($Symbol, 2);
14112 }
14113 elsif($Symbol=~/\A(_Z|\?)/) {
14114 $S2 = $tr_name{$Symbol};
14115 }
14116 }
14117 if($S1)
14118 {
14119 $Report .= " <old signature=\"".htmlSpecChars($S1)."\">\n";
14120 $Report .= $P1;
14121 $Report .= " </old>\n";
14122 }
14123 if($S2 and $S2 ne $S1)
14124 {
14125 $Report .= " <new signature=\"".htmlSpecChars($S2)."\">\n";
14126 $Report .= $P2;
14127 $Report .= " </new>\n";
14128 }
14129 $Report .= " </symbol>\n";
14130 }
14131 $Report .= "</symbols_info>\n";
14132 return $Report;
14133}
14134
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014135sub writeReport($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014136{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014137 my ($Level, $Report) = @_;
14138 if($ReportFormat eq "xml") {
14139 $Report = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".$Report;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014140 }
14141 if($StdOut)
14142 { # --stdout option
14143 print STDOUT $Report;
14144 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014145 else
14146 {
14147 my $RPath = getReportPath($Level);
14148 writeFile($RPath, $Report);
14149 if($Browse)
14150 {
14151 system($Browse." $RPath >/dev/null 2>&1 &");
14152 if($JoinReport or $DoubleReport)
14153 {
14154 if($Level eq "Binary")
14155 { # wait to open a browser
14156 sleep(1);
14157 }
14158 }
14159 }
14160 }
14161}
14162
14163sub getReport($)
14164{
14165 my $Level = $_[0];
14166 if($ReportFormat eq "xml")
14167 { # XML
14168
14169 if($Level eq "Join")
14170 {
14171 my $Report = "<reports>\n";
14172 $Report .= getReport("Binary");
14173 $Report .= getReport("Source");
14174 $Report .= "</reports>\n";
14175 return $Report;
14176 }
14177 else
14178 {
14179 my $Report = "<report kind=\"".lc($Level)."\" version=\"$XML_REPORT_VERSION\">\n\n";
14180 my ($Summary, $MetaData) = get_Summary($Level);
14181 $Report .= $Summary."\n";
14182 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
14183 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
14184 $Report .= get_Report_SymbolsInfo($Level);
14185 $Report .= "</report>\n";
14186 return $Report;
14187 }
14188 }
14189 else
14190 { # HTML
14191 my $CssStyles = readModule("Styles", "Report.css");
14192 my $JScripts = readModule("Scripts", "Sections.js");
14193 if($Level eq "Join")
14194 {
14195 $CssStyles .= "\n".readModule("Styles", "Tabs.css");
14196 $JScripts .= "\n".readModule("Scripts", "Tabs.js");
14197 my $Title = "$TargetLibraryFName: ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." compatibility report";
14198 my $Keywords = "$TargetLibraryFName, compatibility, API, report";
14199 my $Description = "Compatibility report for the $TargetLibraryFName $TargetComponent between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions";
14200 my ($BSummary, $BMetaData) = get_Summary("Binary");
14201 my ($SSummary, $SMetaData) = get_Summary("Source");
14202 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>";
14203 $Report .= get_Report_Header("Join")."
14204 <br/><div class='tabset'>
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014205 <a id='BinaryID' href='#BinaryTab' class='tab active'>Binary<br/>Compatibility</a>
14206 <a id='SourceID' href='#SourceTab' style='margin-left:3px' class='tab disabled'>Source<br/>Compatibility</a>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014207 </div>";
14208 $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>";
14209 $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>";
14210 $Report .= getReportFooter($TargetLibraryFName);
14211 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
14212 return $Report;
14213 }
14214 else
14215 {
14216 my ($Summary, $MetaData) = get_Summary($Level);
14217 my $Title = "$TargetLibraryFName: ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." ".lc($Level)." compatibility report";
14218 my $Keywords = "$TargetLibraryFName, ".lc($Level)." compatibility, API, report";
14219 my $Description = "$Level compatibility report for the $TargetLibraryFName $TargetComponent between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions";
14220 if($Level eq "Binary")
14221 {
14222 if(getArch(1) eq getArch(2)
14223 and getArch(1) ne "unknown") {
14224 $Description .= " on ".showArch(getArch(1));
14225 }
14226 }
14227 my $Report = "<!-\- $MetaData -\->\n".composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."\n<body>\n<div><a name='Top'></a>\n";
14228 $Report .= get_Report_Header($Level)."\n".$Summary."\n";
14229 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
14230 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
14231 $Report .= get_SourceInfo();
14232 $Report .= "</div>\n<br/><br/><br/><hr/>\n";
14233 $Report .= getReportFooter($TargetLibraryFName);
14234 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
14235 return $Report;
14236 }
14237 }
14238}
14239
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014240sub getLegend()
14241{
14242 return "<br/>
14243<table class='summary'>
14244<tr>
14245 <td class='new'>added</td>
14246 <td class='passed'>compatible</td>
14247</tr>
14248<tr>
14249 <td class='warning'>warning</td>
14250 <td class='failed'>incompatible</td>
14251</tr></table>\n";
14252}
14253
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014254sub createReport()
14255{
14256 if($JoinReport)
14257 { # --join-report, --stdout
14258 writeReport("Join", getReport("Join"));
14259 }
14260 elsif($DoubleReport)
14261 { # default
14262 writeReport("Binary", getReport("Binary"));
14263 writeReport("Source", getReport("Source"));
14264 }
14265 elsif($BinaryOnly)
14266 { # --binary
14267 writeReport("Binary", getReport("Binary"));
14268 }
14269 elsif($SourceOnly)
14270 { # --source
14271 writeReport("Source", getReport("Source"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014272 }
14273}
14274
14275sub getReportFooter($)
14276{
14277 my $LibName = $_[0];
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014278 my $FooterStyle = (not $JoinReport)?"width:99%":"width:97%;padding-top:3px";
14279 my $Footer = "<div style='$FooterStyle;font-size:11px;' align='right'><i>Generated on ".(localtime time); # report date
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014280 $Footer .= " for <span style='font-weight:bold'>$LibName</span>"; # tested library/system name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014281 $Footer .= " by <a href='".$HomePage{"Wiki"}."'>ABI Compliance Checker</a>"; # tool name
14282 my $ToolSummary = "<br/>A tool for checking backward compatibility of a C/C++ library API&#160;&#160;";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014283 $Footer .= " $TOOL_VERSION &#160;$ToolSummary</i></div>"; # tool version
14284 return $Footer;
14285}
14286
14287sub get_Report_Problems($$)
14288{
14289 my ($Priority, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014290 my $Report = get_Report_TypeProblems($Priority, $Level);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014291 if(my $SProblems = get_Report_SymbolProblems($Priority, $Level)) {
14292 $Report .= $SProblems;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014293 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014294 if($Priority eq "Low")
14295 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014296 $Report .= get_Report_ChangedConstants($Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014297 if($ReportFormat eq "html") {
14298 if($CheckImpl and $Level eq "Binary") {
14299 $Report .= get_Report_Impl();
14300 }
14301 }
14302 }
14303 if($ReportFormat eq "html")
14304 {
14305 if($Report)
14306 { # add anchor
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014307 if($JoinReport)
14308 {
14309 if($Priority eq "Safe") {
14310 $Report = "<a name=\'Other_".$Level."_Changes\'></a>".$Report;
14311 }
14312 else {
14313 $Report = "<a name=\'".$Priority."_Risk_".$Level."_Problems\'></a>".$Report;
14314 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014315 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014316 else
14317 {
14318 if($Priority eq "Safe") {
14319 $Report = "<a name=\'Other_Changes\'></a>".$Report;
14320 }
14321 else {
14322 $Report = "<a name=\'".$Priority."_Risk_Problems\'></a>".$Report;
14323 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014324 }
14325 }
14326 }
14327 return $Report;
14328}
14329
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014330sub composeHTML_Head($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014331{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014332 my ($Title, $Keywords, $Description, $Styles, $Scripts) = @_;
14333 return "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
14334 <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">
14335 <head>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014336 <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />
14337 <meta name=\"keywords\" content=\"$Keywords\" />
14338 <meta name=\"description\" content=\"$Description\" />
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014339 <title>
14340 $Title
14341 </title>
14342 <style type=\"text/css\">
14343 $Styles
14344 </style>
14345 <script type=\"text/javascript\" language=\"JavaScript\">
14346 <!--
14347 $Scripts
14348 -->
14349 </script>
14350 </head>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014351}
14352
14353sub insertIDs($)
14354{
14355 my $Text = $_[0];
14356 while($Text=~/CONTENT_ID/)
14357 {
14358 if(int($Content_Counter)%2) {
14359 $ContentID -= 1;
14360 }
14361 $Text=~s/CONTENT_ID/c_$ContentID/;
14362 $ContentID += 1;
14363 $Content_Counter += 1;
14364 }
14365 return $Text;
14366}
14367
14368sub checkPreprocessedUnit($)
14369{
14370 my $Path = $_[0];
14371 my $CurHeader = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014372 open(PREPROC, $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014373 while(<PREPROC>)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014374 { # detecting public and private constants
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014375 next if(not /\A#/);
14376 chomp($_);
14377 if(/#[ \t]+\d+[ \t]+\"(.+)\"/) {
14378 $CurHeader=path_format($1, $OSgroup);
14379 }
14380 if(not $Include_Neighbors{$Version}{get_filename($CurHeader)}
14381 and not $Registered_Headers{$Version}{$CurHeader})
14382 { # not a target
14383 next;
14384 }
14385 if(not is_target_header(get_filename($CurHeader)))
14386 { # user-defined header
14387 next;
14388 }
14389 if(/\#[ \t]*define[ \t]+([_A-Z0-9]+)[ \t]+(.+)[ \t]*\Z/)
14390 {
14391 my ($Name, $Value) = ($1, $2);
14392 if(not $Constants{$Version}{$Name}{"Access"})
14393 {
14394 $Constants{$Version}{$Name}{"Access"} = "public";
14395 $Constants{$Version}{$Name}{"Value"} = $Value;
14396 $Constants{$Version}{$Name}{"Header"} = get_filename($CurHeader);
14397 }
14398 }
14399 elsif(/\#[ \t]*undef[ \t]+([_A-Z]+)[ \t]*/) {
14400 $Constants{$Version}{$1}{"Access"} = "private";
14401 }
14402 }
14403 close(PREPROC);
14404 foreach my $Constant (keys(%{$Constants{$Version}}))
14405 {
14406 if($Constants{$Version}{$Constant}{"Access"} eq "private" or $Constant=~/_h\Z/i
14407 or isBuiltIn($Constants{$Version}{$Constant}{"Header"}))
14408 { # skip private constants
14409 delete($Constants{$Version}{$Constant});
14410 }
14411 else {
14412 delete($Constants{$Version}{$Constant}{"Access"});
14413 }
14414 }
14415}
14416
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014417sub uncoverConstant($$)
14418{
14419 my ($LibVersion, $Constant) = @_;
14420 return "" if(not $LibVersion or not $Constant);
14421 return $Constant if(isCyclical(\@RecurConstant, $Constant));
14422 if(defined $Cache{"uncoverConstant"}{$LibVersion}{$Constant}) {
14423 return $Cache{"uncoverConstant"}{$LibVersion}{$Constant};
14424 }
14425 my $Value = $Constants{$LibVersion}{$Constant}{"Value"};
14426 if(defined $Value)
14427 {
14428 if($Value=~/\A[A-Z0-9_]+\Z/ and $Value=~/[A-Z]/)
14429 {
14430 push(@RecurConstant, $Constant);
14431 my $Uncovered = uncoverConstant($LibVersion, $Value);
14432 if($Uncovered ne "") {
14433 $Value = $Uncovered;
14434 }
14435 pop(@RecurConstant);
14436 }
14437 # FIXME: uncover $Value using all the enum constants
14438 # USECASE: change of define NC_LONG from NC_INT (enum value) to NC_INT (define)
14439 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = $Value);
14440 }
14441 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = "");
14442}
14443
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014444my %IgnoreConstant=(
14445 "VERSION"=>1,
14446 "VERSIONCODE"=>1,
14447 "VERNUM"=>1,
14448 "VERS_INFO"=>1,
14449 "PATCHLEVEL"=>1,
14450 "INSTALLPREFIX"=>1,
14451 "VBUILD"=>1,
14452 "VPATCH"=>1,
14453 "VMINOR"=>1,
14454 "BUILD_STRING"=>1,
14455 "BUILD_TIME"=>1,
14456 "PACKAGE_STRING"=>1,
14457 "PRODUCTION"=>1,
14458 "CONFIGURE_COMMAND"=>1,
14459 "INSTALLDIR"=>1,
14460 "BINDIR"=>1,
14461 "CONFIG_FILE_PATH"=>1,
14462 "DATADIR"=>1,
14463 "EXTENSION_DIR"=>1,
14464 "INCLUDE_PATH"=>1,
14465 "LIBDIR"=>1,
14466 "LOCALSTATEDIR"=>1,
14467 "SBINDIR"=>1,
14468 "SYSCONFDIR"=>1,
14469 "RELEASE"=>1,
14470 "SOURCE_ID"=>1,
14471 "SUBMINOR"=>1,
14472 "MINOR"=>1,
14473 "MINNOR"=>1,
14474 "MINORVERSION"=>1,
14475 "MAJOR"=>1,
14476 "MAJORVERSION"=>1,
14477 "MICRO"=>1,
14478 "MICROVERSION"=>1,
14479 "BINARY_AGE"=>1,
14480 "INTERFACE_AGE"=>1,
14481 "CORE_ABI"=>1,
14482 "PATCH"=>1,
14483 "COPYRIGHT"=>1,
14484 "TIMESTAMP"=>1,
14485 "REVISION"=>1,
14486 "PACKAGE_TAG"=>1,
14487 "PACKAGEDATE"=>1,
14488 "NUMVERSION"=>1
14489);
14490
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014491sub mergeConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014492{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014493 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014494 foreach my $Constant (keys(%{$Constants{1}}))
14495 {
14496 if($SkipConstants{1}{$Constant})
14497 { # skipped by the user
14498 next;
14499 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014500 if(not defined $Constants{2}{$Constant}{"Value"}
14501 or $Constants{2}{$Constant}{"Value"} eq "")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014502 { # empty value
14503 next;
14504 }
14505 if(not is_target_header($Constants{1}{$Constant}{"Header"}))
14506 { # user-defined header
14507 next;
14508 }
14509 my ($Old_Value, $New_Value, $Old_Value_Pure, $New_Value_Pure);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014510 $Old_Value = $Old_Value_Pure = uncoverConstant(1, $Constant);
14511 $New_Value = $New_Value_Pure = uncoverConstant(2, $Constant);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014512 $Old_Value_Pure=~s/(\W)\s+/$1/g;
14513 $Old_Value_Pure=~s/\s+(\W)/$1/g;
14514 $New_Value_Pure=~s/(\W)\s+/$1/g;
14515 $New_Value_Pure=~s/\s+(\W)/$1/g;
14516 next if($New_Value_Pure eq "" or $Old_Value_Pure eq "");
14517 if($New_Value_Pure ne $Old_Value_Pure)
14518 { # different values
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014519 if($Level eq "Binary")
14520 {
14521 if(grep {$Constant=~/(\A|_)$_(_|\Z)/} keys(%IgnoreConstant))
14522 { # ignore library version
14523 next;
14524 }
14525 if($Constant=~/(\A|_)(lib|open|)$TargetLibraryShortName(_|)(VERSION|VER|DATE|API|PREFIX)(_|\Z)/i)
14526 { # ignore library version
14527 next;
14528 }
14529 if($Old_Value=~/\A('|"|)[\/\\]\w+([\/\\]|:|('|"|)\Z)/ or $Old_Value=~/[\/\\]\w+[\/\\]\w+/)
14530 { # ignoring path defines:
14531 # /lib64:/usr/lib64:/lib:/usr/lib:/usr/X11R6/lib/Xaw3d ...
14532 next;
14533 }
14534 if($Old_Value=~/\A\(*[a-z_]+(\s+|\|)/i)
14535 { # ignore source defines:
14536 # static int gcry_pth_init ( void) { return ...
14537 # (RE_BACKSLASH_ESCAPE_IN_LISTS | RE...
14538 next;
14539 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014540 }
14541 if(convert_integer($Old_Value) eq convert_integer($New_Value))
14542 { # 0x0001 and 0x1, 0x1 and 1 equal constants
14543 next;
14544 }
14545 if($Old_Value eq "0" and $New_Value eq "NULL")
14546 { # 0 => NULL
14547 next;
14548 }
14549 if($Old_Value eq "NULL" and $New_Value eq "0")
14550 { # NULL => 0
14551 next;
14552 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014553 %{$ProblemsWithConstants{$Level}{$Constant}} = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014554 "Target"=>$Constant,
14555 "Old_Value"=>$Old_Value,
14556 "New_Value"=>$New_Value );
14557 }
14558 }
14559}
14560
14561sub convert_integer($)
14562{
14563 my $Value = $_[0];
14564 if($Value=~/\A0x[a-f0-9]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014565 { # hexadecimal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014566 return hex($Value);
14567 }
14568 elsif($Value=~/\A0[0-7]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014569 { # octal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014570 return oct($Value);
14571 }
14572 elsif($Value=~/\A0b[0-1]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014573 { # binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014574 return oct($Value);
14575 }
14576 else {
14577 return $Value;
14578 }
14579}
14580
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014581sub readSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014582{
14583 my $LibVersion = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014584 my @LibPaths = getSoPaths($LibVersion);
14585 if($#LibPaths==-1 and not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014586 {
14587 if($LibVersion==1)
14588 {
14589 printMsg("WARNING", "checking headers only");
14590 $CheckHeadersOnly = 1;
14591 }
14592 else {
14593 exitStatus("Error", "$SLIB_TYPE libraries are not found in ".$Descriptor{$LibVersion}{"Version"});
14594 }
14595 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014596 my %GroupNames = map {parse_libname(get_filename($_), "name+ext", $OStarget)=>1} @LibPaths;
14597 foreach my $LibPath (sort {length($a)<=>length($b)} @LibPaths) {
14598 readSymbols_Lib($LibVersion, $LibPath, 0, \%GroupNames, "+Weak");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014599 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014600 if(not $CheckHeadersOnly)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014601 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014602 if($#LibPaths!=-1)
14603 {
14604 if(not keys(%{$Symbol_Library{$LibVersion}}))
14605 {
14606 printMsg("WARNING", "the set of public symbols in library(ies) is empty");
14607 printMsg("WARNING", "checking headers only");
14608 $CheckHeadersOnly = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014609 }
14610 }
14611 }
14612}
14613
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014614sub getSymbolSize($$)
14615{ # size from the shared library
14616 my ($Symbol, $LibVersion) = @_;
14617 return 0 if(not $Symbol);
14618 if(defined $Symbol_Library{$LibVersion}{$Symbol}
14619 and my $LibName = $Symbol_Library{$LibVersion}{$Symbol})
14620 {
14621 if(defined $Library_Symbol{$LibVersion}{$LibName}{$Symbol}
14622 and my $Size = $Library_Symbol{$LibVersion}{$LibName}{$Symbol})
14623 {
14624 if($Size<0) {
14625 return -$Size;
14626 }
14627 }
14628 }
14629 return 0;
14630}
14631
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014632sub canonifyName($)
14633{ # make TIFFStreamOpen(char const*, std::basic_ostream<char, std::char_traits<char> >*)
14634 # to be TIFFStreamOpen(char const*, std::basic_ostream<char>*)
14635 my $Name = $_[0];
14636 my $Rem = "std::(allocator|less|char_traits|regex_traits)";
14637 if($Name=~/([^<>,]+),\s*$Rem<([^<>,]+)>\s*/)
14638 {
14639 if($1 eq $3)
14640 {
14641 my $P = $1;
14642 while($Name=~s/\Q$P\E,\s*$Rem<\Q$P\E>\s*/$P/g){};
14643 }
14644 }
14645 return $Name;
14646}
14647
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014648sub translateSymbols(@)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014649{
14650 my $LibVersion = pop(@_);
14651 my (@MnglNames1, @MnglNames2, @UnMnglNames) = ();
14652 foreach my $Interface (sort @_)
14653 {
14654 if($Interface=~/\A_Z/)
14655 {
14656 next if($tr_name{$Interface});
14657 $Interface=~s/[\@\$]+(.*)\Z//;
14658 push(@MnglNames1, $Interface);
14659 }
14660 elsif($Interface=~/\A\?/) {
14661 push(@MnglNames2, $Interface);
14662 }
14663 else
14664 { # not mangled
14665 $tr_name{$Interface} = $Interface;
14666 $mangled_name_gcc{$Interface} = $Interface;
14667 $mangled_name{$LibVersion}{$Interface} = $Interface;
14668 }
14669 }
14670 if($#MnglNames1 > -1)
14671 { # GCC names
14672 @UnMnglNames = reverse(unmangleArray(@MnglNames1));
14673 foreach my $MnglName (@MnglNames1)
14674 {
14675 my $Unmangled = $tr_name{$MnglName} = formatName(canonifyName(pop(@UnMnglNames)));
14676 if(not $mangled_name_gcc{$Unmangled}) {
14677 $mangled_name_gcc{$Unmangled} = $MnglName;
14678 }
14679 if($MnglName=~/\A_ZTV/ and $Unmangled=~/vtable for (.+)/)
14680 { # bind class name and v-table symbol
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014681 my $ClassName = $1;
14682 $ClassVTable{$ClassName} = $MnglName;
14683 $VTableClass{$MnglName} = $ClassName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014684 }
14685 }
14686 }
14687 if($#MnglNames2 > -1)
14688 { # MSVC names
14689 @UnMnglNames = reverse(unmangleArray(@MnglNames2));
14690 foreach my $MnglName (@MnglNames2)
14691 {
14692 $tr_name{$MnglName} = formatName(pop(@UnMnglNames));
14693 $mangled_name{$LibVersion}{$tr_name{$MnglName}} = $MnglName;
14694 }
14695 }
14696 return \%tr_name;
14697}
14698
14699sub link_symbol($$$)
14700{
14701 my ($Symbol, $RunWith, $Deps) = @_;
14702 if(link_symbol_internal($Symbol, $RunWith, \%Symbol_Library)) {
14703 return 1;
14704 }
14705 if($Deps eq "+Deps")
14706 { # check the dependencies
14707 if(link_symbol_internal($Symbol, $RunWith, \%DepSymbols)) {
14708 return 1;
14709 }
14710 }
14711 return 0;
14712}
14713
14714sub link_symbol_internal($$$)
14715{
14716 my ($Symbol, $RunWith, $Where) = @_;
14717 return 0 if(not $Where or not $Symbol);
14718 if($Where->{$RunWith}{$Symbol})
14719 { # the exact match by symbol name
14720 return 1;
14721 }
14722 if(my $VSym = $SymVer{$RunWith}{$Symbol})
14723 { # indirect symbol version, i.e.
14724 # foo_old and its symlink foo@v (or foo@@v)
14725 # foo_old may be in .symtab table
14726 if($Where->{$RunWith}{$VSym}) {
14727 return 1;
14728 }
14729 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014730 my ($Sym, $Spec, $Ver) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014731 if($Sym and $Ver)
14732 { # search for the symbol with the same version
14733 # or without version
14734 if($Where->{$RunWith}{$Sym})
14735 { # old: foo@v|foo@@v
14736 # new: foo
14737 return 1;
14738 }
14739 if($Where->{$RunWith}{$Sym."\@".$Ver})
14740 { # old: foo|foo@@v
14741 # new: foo@v
14742 return 1;
14743 }
14744 if($Where->{$RunWith}{$Sym."\@\@".$Ver})
14745 { # old: foo|foo@v
14746 # new: foo@@v
14747 return 1;
14748 }
14749 }
14750 return 0;
14751}
14752
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014753sub readSymbols_App($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014754{
14755 my $Path = $_[0];
14756 return () if(not $Path or not -f $Path);
14757 my @Imported = ();
14758 if($OSgroup eq "macos")
14759 {
14760 my $OtoolCmd = get_CmdPath("otool");
14761 if(not $OtoolCmd) {
14762 exitStatus("Not_Found", "can't find \"otool\"");
14763 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014764 open(APP, "$OtoolCmd -IV \"".$Path."\" 2>$TMP_DIR/null |");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014765 while(<APP>) {
14766 if(/[^_]+\s+_?([\w\$]+)\s*\Z/) {
14767 push(@Imported, $1);
14768 }
14769 }
14770 close(APP);
14771 }
14772 elsif($OSgroup eq "windows")
14773 {
14774 my $DumpBinCmd = get_CmdPath("dumpbin");
14775 if(not $DumpBinCmd) {
14776 exitStatus("Not_Found", "can't find \"dumpbin.exe\"");
14777 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014778 open(APP, "$DumpBinCmd /IMPORTS \"".$Path."\" 2>$TMP_DIR/null |");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014779 while(<APP>) {
14780 if(/\s*\w+\s+\w+\s+\w+\s+([\w\?\@]+)\s*/) {
14781 push(@Imported, $1);
14782 }
14783 }
14784 close(APP);
14785 }
14786 else
14787 {
14788 my $ReadelfCmd = get_CmdPath("readelf");
14789 if(not $ReadelfCmd) {
14790 exitStatus("Not_Found", "can't find \"readelf\"");
14791 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014792 open(APP, "$ReadelfCmd -WhlSsdA \"".$Path."\" 2>$TMP_DIR/null |");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014793 my $symtab=0; # indicates that we are processing 'symtab' section of 'readelf' output
14794 while(<APP>)
14795 {
14796 if( /'.dynsym'/ ) {
14797 $symtab=0;
14798 }
14799 elsif($symtab == 1) {
14800 # do nothing with symtab (but there are some plans for the future)
14801 next;
14802 }
14803 elsif( /'.symtab'/ ) {
14804 $symtab=1;
14805 }
14806 elsif(my ($fullname, $idx, $Ndx, $type, $size, $bind) = readline_ELF($_))
14807 {
14808 if( $Ndx eq "UND" ) {
14809 #only imported symbols
14810 push(@Imported, $fullname);
14811 }
14812 }
14813 }
14814 close(APP);
14815 }
14816 return @Imported;
14817}
14818
14819sub readline_ELF($)
14820{
14821 if($_[0]=~/\s*\d+:\s+(\w*)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s([^\s]+)/)
14822 { # the line of 'readelf' output corresponding to the interface
14823 # symbian-style: _ZN12CCTTokenType4NewLE4TUid3RFs@@ctfinder{000a0000}[102020e5].dll
14824 my ($value, $size, $type, $bind,
14825 $vis, $Ndx, $fullname)=($1, $2, $3, $4, $5, $6, $7);
14826 if($bind!~/\A(WEAK|GLOBAL)\Z/) {
14827 return ();
14828 }
14829 if($type!~/\A(FUNC|IFUNC|OBJECT|COMMON)\Z/) {
14830 return ();
14831 }
14832 if($vis!~/\A(DEFAULT|PROTECTED)\Z/) {
14833 return ();
14834 }
14835 if($Ndx eq "ABS" and $value!~/\D|1|2|3|4|5|6|7|8|9/) {
14836 return ();
14837 }
14838 if($OStarget eq "symbian")
14839 {
14840 if($fullname=~/_\._\.absent_export_\d+/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014841 { # "_._.absent_export_111"@@libstdcpp{00010001}[10282872].dll
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014842 return ();
14843 }
14844 my @Elems = separate_symbol($fullname);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014845 $fullname = $Elems[0]; # remove internal version, {00020001}[10011235].dll
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014846 }
14847 return ($fullname, $value, $Ndx, $type, $size, $bind);
14848 }
14849 else {
14850 return ();
14851 }
14852}
14853
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014854sub read_symlink($)
14855{
14856 my $Path = $_[0];
14857 return "" if(not $Path);
14858 return "" if(not -f $Path and not -l $Path);
14859 if(defined $Cache{"read_symlink"}{$Path}) {
14860 return $Cache{"read_symlink"}{$Path};
14861 }
14862 if(my $Res = readlink($Path)) {
14863 return ($Cache{"read_symlink"}{$Path} = $Res);
14864 }
14865 elsif(my $ReadlinkCmd = get_CmdPath("readlink")) {
14866 return ($Cache{"read_symlink"}{$Path} = `$ReadlinkCmd -n $Path`);
14867 }
14868 elsif(my $FileCmd = get_CmdPath("file"))
14869 {
14870 my $Info = `$FileCmd $Path`;
14871 if($Info=~/symbolic\s+link\s+to\s+['`"]*([\w\d\.\-\/\\]+)['`"]*/i) {
14872 return ($Cache{"read_symlink"}{$Path} = $1);
14873 }
14874 }
14875 return ($Cache{"read_symlink"}{$Path} = "");
14876}
14877
14878sub resolve_symlink($)
14879{
14880 my $Path = $_[0];
14881 return "" if(not $Path);
14882 return "" if(not -f $Path and not -l $Path);
14883 if(defined $Cache{"resolve_symlink"}{$Path}) {
14884 return $Cache{"resolve_symlink"}{$Path};
14885 }
14886 return $Path if(isCyclical(\@RecurSymlink, $Path));
14887 push(@RecurSymlink, $Path);
14888 if(-l $Path and my $Redirect=read_symlink($Path))
14889 {
14890 if(is_abs($Redirect))
14891 { # absolute path
14892 if($SystemRoot and $SystemRoot ne "/"
14893 and $Path=~/\A\Q$SystemRoot\E\//
14894 and (-f $SystemRoot.$Redirect or -l $SystemRoot.$Redirect))
14895 { # symbolic links from the sysroot
14896 # should be corrected to point to
14897 # the files inside sysroot
14898 $Redirect = $SystemRoot.$Redirect;
14899 }
14900 my $Res = resolve_symlink($Redirect);
14901 pop(@RecurSymlink);
14902 return ($Cache{"resolve_symlink"}{$Path} = $Res);
14903 }
14904 elsif($Redirect=~/\.\.[\/\\]/)
14905 { # relative path
14906 $Redirect = joinPath(get_dirname($Path),$Redirect);
14907 while($Redirect=~s&(/|\\)[^\/\\]+(\/|\\)\.\.(\/|\\)&$1&){};
14908 my $Res = resolve_symlink($Redirect);
14909 pop(@RecurSymlink);
14910 return ($Cache{"resolve_symlink"}{$Path} = $Res);
14911 }
14912 elsif(-f get_dirname($Path)."/".$Redirect)
14913 { # file name in the same directory
14914 my $Res = resolve_symlink(joinPath(get_dirname($Path),$Redirect));
14915 pop(@RecurSymlink);
14916 return ($Cache{"resolve_symlink"}{$Path} = $Res);
14917 }
14918 else
14919 { # broken link
14920 pop(@RecurSymlink);
14921 return ($Cache{"resolve_symlink"}{$Path} = "");
14922 }
14923 }
14924 pop(@RecurSymlink);
14925 return ($Cache{"resolve_symlink"}{$Path} = $Path);
14926}
14927
14928sub find_lib_path($$)
14929{
14930 my ($LibVersion, $DyLib) = @_;
14931 return "" if(not $DyLib or not $LibVersion);
14932 return $DyLib if(is_abs($DyLib));
14933 if(defined $Cache{"find_lib_path"}{$LibVersion}{$DyLib}) {
14934 return $Cache{"find_lib_path"}{$LibVersion}{$DyLib};
14935 }
14936 if(my @Paths = sort keys(%{$InputObject_Paths{$LibVersion}{$DyLib}})) {
14937 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $Paths[0]);
14938 }
14939 elsif(my $DefaultPath = $DyLib_DefaultPath{$DyLib}) {
14940 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $DefaultPath);
14941 }
14942 else
14943 {
14944 foreach my $Dir (sort keys(%DefaultLibPaths), sort keys(%{$SystemPaths{"lib"}}))
14945 { # search in default linker paths and then in all system paths
14946 if(-f $Dir."/".$DyLib) {
14947 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = joinPath($Dir,$DyLib));
14948 }
14949 }
14950 detectSystemObjects() if(not keys(%SystemObjects));
14951 if(my @AllObjects = keys(%{$SystemObjects{$DyLib}})) {
14952 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $AllObjects[0]);
14953 }
14954 my $ShortName = parse_libname($DyLib, "name+ext", $OStarget);
14955 if($ShortName ne $DyLib
14956 and my $Path = find_lib_path($ShortName))
14957 { # FIXME: check this case
14958 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $Path);
14959 }
14960 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = "");
14961 }
14962}
14963
14964sub readSymbols_Lib($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014965{
14966 my ($LibVersion, $Lib_Path, $IsNeededLib, $GroupNames, $Weak) = @_;
14967 return if(not $Lib_Path or not -f $Lib_Path);
14968 my ($Lib_Dir, $Lib_Name) = separate_path(resolve_symlink($Lib_Path));
14969 return if($CheckedDyLib{$LibVersion}{$Lib_Name} and $IsNeededLib);
14970 return if(isCyclical(\@RecurLib, $Lib_Name) or $#RecurLib>=1);
14971 $CheckedDyLib{$LibVersion}{$Lib_Name} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014972 if($CheckImpl and not $IsNeededLib) {
14973 getImplementations($LibVersion, $Lib_Path);
14974 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014975 push(@RecurLib, $Lib_Name);
14976 my (%Value_Interface, %Interface_Value, %NeededLib) = ();
14977 if(not $IsNeededLib)
14978 { # libstdc++ and libc are always used by other libs
14979 # if you test one of these libs then you not need
14980 # to find them in the system for reusing
14981 if(parse_libname($Lib_Name, "short", $OStarget) eq "libstdc++")
14982 { # libstdc++.so.6
14983 $STDCXX_TESTING = 1;
14984 }
14985 if(parse_libname($Lib_Name, "short", $OStarget) eq "libc")
14986 { # libc-2.11.3.so
14987 $GLIBC_TESTING = 1;
14988 }
14989 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014990 my $DebugPath = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014991 if($Debug)
14992 { # debug mode
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014993 $DebugPath = $DEBUG_PATH{$LibVersion}."/libs/".get_filename($Lib_Path).".txt";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014994 mkpath(get_dirname($DebugPath));
14995 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014996 if($OStarget eq "macos")
14997 { # Mac OS X: *.dylib, *.a
14998 my $OtoolCmd = get_CmdPath("otool");
14999 if(not $OtoolCmd) {
15000 exitStatus("Not_Found", "can't find \"otool\"");
15001 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015002 $OtoolCmd .= " -TV \"".$Lib_Path."\" 2>$TMP_DIR/null";
15003 if($Debug)
15004 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015005 # write to file
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015006 system($OtoolCmd." >".$DebugPath);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015007 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015008 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015009 else
15010 { # write to pipe
15011 open(LIB, $OtoolCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015012 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015013 while(<LIB>)
15014 {
15015 if(/[^_]+\s+_([\w\$]+)\s*\Z/)
15016 {
15017 my $realname = $1;
15018 if($IsNeededLib and $GroupNames
15019 and not $GroupNames->{parse_libname($Lib_Name, "name+ext", $OStarget)}) {
15020 $DepSymbols{$LibVersion}{$realname} = 1;
15021 }
15022 if(not $IsNeededLib)
15023 {
15024 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
15025 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
15026 if($COMMON_LANGUAGE{$LibVersion} ne "C++"
15027 and $realname=~/\A(_Z|\?)/) {
15028 setLanguage($LibVersion, "C++");
15029 }
15030 if($CheckObjectsOnly
15031 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015032 $CheckedSymbols{"Binary"}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015033 }
15034 }
15035 }
15036 }
15037 close(LIB);
15038 if($LIB_TYPE eq "dynamic")
15039 { # dependencies
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015040 open(LIB, "$OtoolCmd -L \"".$Lib_Path."\" 2>$TMP_DIR/null |");
15041 while(<LIB>)
15042 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015043 if(/\s*([\/\\].+\.$LIB_EXT)\s*/
15044 and $1 ne $Lib_Path) {
15045 $NeededLib{$1} = 1;
15046 }
15047 }
15048 close(LIB);
15049 }
15050 }
15051 elsif($OStarget eq "windows")
15052 { # Windows *.dll, *.lib
15053 my $DumpBinCmd = get_CmdPath("dumpbin");
15054 if(not $DumpBinCmd) {
15055 exitStatus("Not_Found", "can't find \"dumpbin\"");
15056 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015057 $DumpBinCmd .= " /EXPORTS \"".$Lib_Path."\" 2>$TMP_DIR/null";
15058 if($Debug)
15059 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015060 # write to file
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015061 system($DumpBinCmd." >".$DebugPath);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015062 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015063 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015064 else
15065 { # write to pipe
15066 open(LIB, $DumpBinCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015067 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015068 while(<LIB>)
15069 { # 1197 4AC 0000A620 SetThreadStackGuarantee
15070 # 1198 4AD SetThreadToken (forwarded to ...)
15071 # 3368 _o2i_ECPublicKey
15072 if(/\A\s*\d+\s+[a-f\d]+\s+[a-f\d]+\s+([\w\?\@]+)\s*\Z/i
15073 or /\A\s*\d+\s+[a-f\d]+\s+([\w\?\@]+)\s*\(\s*forwarded\s+/
15074 or /\A\s*\d+\s+_([\w\?\@]+)\s*\Z/)
15075 { # dynamic, static and forwarded symbols
15076 my $realname = $1;
15077 if($IsNeededLib and not $GroupNames->{parse_libname($Lib_Name, "name+ext", $OStarget)}) {
15078 $DepSymbols{$LibVersion}{$realname} = 1;
15079 }
15080 if(not $IsNeededLib)
15081 {
15082 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
15083 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
15084 if($COMMON_LANGUAGE{$LibVersion} ne "C++"
15085 and $realname=~/\A(_Z|\?)/) {
15086 setLanguage($LibVersion, "C++");
15087 }
15088 if($CheckObjectsOnly
15089 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015090 $CheckedSymbols{"Binary"}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015091 }
15092 }
15093 }
15094 }
15095 close(LIB);
15096 if($LIB_TYPE eq "dynamic")
15097 { # dependencies
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015098 open(LIB, "$DumpBinCmd /DEPENDENTS \"".$Lib_Path."\" 2>$TMP_DIR/null |");
15099 while(<LIB>)
15100 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015101 if(/\s*([^\s]+?\.$LIB_EXT)\s*/i
15102 and $1 ne $Lib_Path) {
15103 $NeededLib{path_format($1, $OSgroup)} = 1;
15104 }
15105 }
15106 close(LIB);
15107 }
15108 }
15109 else
15110 { # Unix; *.so, *.a
15111 # Symbian: *.dso, *.lib
15112 my $ReadelfCmd = get_CmdPath("readelf");
15113 if(not $ReadelfCmd) {
15114 exitStatus("Not_Found", "can't find \"readelf\"");
15115 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015116 $ReadelfCmd .= " -WhlSsdA \"".$Lib_Path."\" 2>$TMP_DIR/null";
15117 if($Debug)
15118 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015119 # write to file
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015120 system($ReadelfCmd." >".$DebugPath);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015121 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015122 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015123 else
15124 { # write to pipe
15125 open(LIB, $ReadelfCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015126 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015127 my $symtab=0; # indicates that we are processing 'symtab' section of 'readelf' output
15128 while(<LIB>)
15129 {
15130 if($LIB_TYPE eq "dynamic")
15131 { # dynamic library specifics
15132 if(/NEEDED.+\[([^\[\]]+)\]/)
15133 { # dependencies:
15134 # 0x00000001 (NEEDED) Shared library: [libc.so.6]
15135 $NeededLib{$1} = 1;
15136 next;
15137 }
15138 if(/'\.dynsym'/)
15139 { # dynamic table
15140 $symtab=0;
15141 next;
15142 }
15143 if($symtab == 1)
15144 { # do nothing with symtab
15145 next;
15146 }
15147 if(/'\.symtab'/)
15148 { # symbol table
15149 $symtab=1;
15150 next;
15151 }
15152 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015153 if(my ($fullname, $idx, $Ndx, $type, $size, $bind) = readline_ELF($_))
15154 { # read ELF entry
15155 if( $Ndx eq "UND" )
15156 { # ignore interfaces that are imported from somewhere else
15157 next;
15158 }
15159 if($bind eq "WEAK"
15160 and $Weak eq "-Weak")
15161 { # skip WEAK symbols
15162 next;
15163 }
15164 my ($realname, $version_spec, $version) = separate_symbol($fullname);
15165 if($type eq "OBJECT")
15166 { # global data
15167 $CompleteSignature{$LibVersion}{$fullname}{"Object"} = 1;
15168 $CompleteSignature{$LibVersion}{$realname}{"Object"} = 1;
15169 }
15170 if($IsNeededLib and not $GroupNames->{parse_libname($Lib_Name, "name+ext", $OStarget)}) {
15171 $DepSymbols{$LibVersion}{$fullname} = 1;
15172 }
15173 if(not $IsNeededLib)
15174 {
15175 $Symbol_Library{$LibVersion}{$fullname} = $Lib_Name;
15176 $Library_Symbol{$LibVersion}{$Lib_Name}{$fullname} = ($type eq "OBJECT")?-$size:1;
15177 if($LIB_EXT eq "so")
15178 { # value
15179 $Interface_Value{$LibVersion}{$fullname} = $idx;
15180 $Value_Interface{$LibVersion}{$idx}{$fullname} = 1;
15181 }
15182 if($COMMON_LANGUAGE{$LibVersion} ne "C++"
15183 and $realname=~/\A(_Z|\?)/) {
15184 setLanguage($LibVersion, "C++");
15185 }
15186 if($CheckObjectsOnly
15187 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015188 $CheckedSymbols{"Binary"}{$fullname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015189 }
15190 }
15191 }
15192 }
15193 close(LIB);
15194 }
15195 if(not $IsNeededLib and $LIB_EXT eq "so")
15196 { # get symbol versions
15197 foreach my $Symbol (keys(%{$Symbol_Library{$LibVersion}}))
15198 {
15199 next if($Symbol!~/\@/);
15200 my $Interface_SymName = "";
15201 foreach my $Symbol_SameValue (keys(%{$Value_Interface{$LibVersion}{$Interface_Value{$LibVersion}{$Symbol}}}))
15202 {
15203 if($Symbol_SameValue ne $Symbol
15204 and $Symbol_SameValue!~/\@/)
15205 {
15206 $SymVer{$LibVersion}{$Symbol_SameValue} = $Symbol;
15207 $Interface_SymName = $Symbol_SameValue;
15208 last;
15209 }
15210 }
15211 if(not $Interface_SymName)
15212 {
15213 if($Symbol=~/\A([^\@\$\?]*)[\@\$]+([^\@\$]*)\Z/
15214 and not $SymVer{$LibVersion}{$1}) {
15215 $SymVer{$LibVersion}{$1} = $Symbol;
15216 }
15217 }
15218 }
15219 }
15220 foreach my $DyLib (sort keys(%NeededLib))
15221 {
15222 my $DepPath = find_lib_path($LibVersion, $DyLib);
15223 if($DepPath and -f $DepPath) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015224 readSymbols_Lib($LibVersion, $DepPath, 1, $GroupNames, "+Weak");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015225 }
15226 }
15227 pop(@RecurLib);
15228 return $Library_Symbol{$LibVersion};
15229}
15230
15231sub get_path_prefixes($)
15232{
15233 my $Path = $_[0];
15234 my ($Dir, $Name) = separate_path($Path);
15235 my %Prefixes = ();
15236 foreach my $Prefix (reverse(split(/[\/\\]+/, $Dir)))
15237 {
15238 $Prefixes{$Name} = 1;
15239 $Name = joinPath($Prefix, $Name);
15240 last if(keys(%Prefixes)>5 or $Prefix eq "include");
15241 }
15242 return keys(%Prefixes);
15243}
15244
15245sub detectSystemHeaders()
15246{
15247 my @SysHeaders = ();
15248 foreach my $DevelPath (keys(%{$SystemPaths{"include"}}))
15249 {
15250 next if(not -d $DevelPath);
15251 # search for all header files in the /usr/include
15252 # with or without extension (ncurses.h, QtCore, ...)
15253 @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f","",""));
15254 foreach my $Link (cmd_find($DevelPath,"l","",""))
15255 { # add symbolic links
15256 if(-f $Link) {
15257 push(@SysHeaders, $Link);
15258 }
15259 }
15260 }
15261 foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
15262 {
15263 next if(not -d $DevelPath);
15264 # search for config headers in the /usr/lib
15265 @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f","*.h",""));
15266 foreach my $Dir (cmd_find($DevelPath,"d","include",""))
15267 { # search for all include directories
15268 # this is for headers that are installed to /usr/lib
15269 # Example: Qt4 headers in Mandriva (/usr/lib/qt4/include/)
15270 if($Dir=~/\/(gcc|jvm|syslinux|kdb)\//) {
15271 next;
15272 }
15273 @SysHeaders = (@SysHeaders, cmd_find($Dir,"f","",""));
15274 }
15275 }
15276 foreach my $Path (@SysHeaders)
15277 {
15278 foreach my $Part (get_path_prefixes($Path)) {
15279 $SystemHeaders{$Part}{$Path}=1;
15280 }
15281 }
15282}
15283
15284sub detectSystemObjects()
15285{
15286 foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
15287 {
15288 next if(not -d $DevelPath);
15289 foreach my $Path (find_libs($DevelPath,"",""))
15290 { # search for shared libraries in the /usr/lib (including symbolic links)
15291 $SystemObjects{parse_libname(get_filename($Path), "name+ext", $OStarget)}{$Path}=1;
15292 }
15293 }
15294}
15295
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015296sub getSoPaths($)
15297{
15298 my $LibVersion = $_[0];
15299 my @SoPaths = ();
15300 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Libs"}))
15301 {
15302 if(not -e $Dest) {
15303 exitStatus("Access_Error", "can't access \'$Dest\'");
15304 }
15305 my @SoPaths_Dest = getSOPaths_Dest($Dest, $LibVersion);
15306 foreach (@SoPaths_Dest) {
15307 push(@SoPaths, $_);
15308 }
15309 }
15310 return @SoPaths;
15311}
15312
15313sub skip_lib($$)
15314{
15315 my ($Path, $LibVersion) = @_;
15316 return 1 if(not $Path or not $LibVersion);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015317 my $Name = get_filename($Path);
15318 if($SkipLibs{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015319 return 1;
15320 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015321 my $ShortName = parse_libname($Name, "name+ext", $OStarget);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015322 if($SkipLibs{$LibVersion}{"Name"}{$ShortName}) {
15323 return 1;
15324 }
15325 foreach my $Dir (keys(%{$SkipLibs{$LibVersion}{"Path"}}))
15326 {
15327 if($Path=~/\Q$Dir\E([\/\\]|\Z)/) {
15328 return 1;
15329 }
15330 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015331 foreach my $P (keys(%{$SkipLibs{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015332 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015333 if($Name=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015334 return 1;
15335 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015336 if($P=~/[\/\\]/ and $Path=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015337 return 1;
15338 }
15339 }
15340 return 0;
15341}
15342
15343sub skip_header($$)
15344{ # returns:
15345 # 1 - if header should NOT be included and checked
15346 # 2 - if header should NOT be included, but should be checked
15347 my ($Path, $LibVersion) = @_;
15348 return 1 if(not $Path or not $LibVersion);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015349 my $Name = get_filename($Path);
15350 if(my $Kind = $SkipHeaders{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015351 return $Kind;
15352 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015353 foreach my $D (keys(%{$SkipHeaders{$LibVersion}{"Path"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015354 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015355 if($Path=~/\Q$D\E([\/\\]|\Z)/) {
15356 return $SkipHeaders{$LibVersion}{"Path"}{$D};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015357 }
15358 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015359 foreach my $P (keys(%{$SkipHeaders{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015360 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015361 if($Name=~/$P/) {
15362 return $SkipHeaders{$LibVersion}{"Pattern"}{$P};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015363 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015364 if($P=~/[\/\\]/ and $Path=~/$P/) {
15365 return $SkipHeaders{$LibVersion}{"Pattern"}{$P};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015366 }
15367 }
15368 return 0;
15369}
15370
15371sub register_objects($$)
15372{
15373 my ($Dir, $LibVersion) = @_;
15374 if($SystemPaths{"lib"}{$Dir})
15375 { # system directory
15376 return;
15377 }
15378 if($RegisteredObjDirs{$LibVersion}{$Dir})
15379 { # already registered
15380 return;
15381 }
15382 foreach my $Path (find_libs($Dir,"",1))
15383 {
15384 next if(ignore_path($Path));
15385 next if(skip_lib($Path, $LibVersion));
15386 $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
15387 }
15388 $RegisteredObjDirs{$LibVersion}{$Dir} = 1;
15389}
15390
15391sub getSOPaths_Dest($$)
15392{
15393 my ($Dest, $LibVersion) = @_;
15394 if(skip_lib($Dest, $LibVersion)) {
15395 return ();
15396 }
15397 if(-f $Dest)
15398 {
15399 if(not parse_libname($Dest, "name", $OStarget)) {
15400 exitStatus("Error", "incorrect format of library (should be *.$LIB_EXT): \'$Dest\'");
15401 }
15402 $InputObject_Paths{$LibVersion}{get_filename($Dest)}{$Dest} = 1;
15403 register_objects(get_dirname($Dest), $LibVersion);
15404 return ($Dest);
15405 }
15406 elsif(-d $Dest)
15407 {
15408 $Dest=~s/[\/\\]+\Z//g;
15409 my @AllObjects = ();
15410 if($SystemPaths{"lib"}{$Dest})
15411 { # you have specified /usr/lib as the search directory (<libs>) in the XML descriptor
15412 # and the real name of the library by -l option (bz2, stdc++, Xaw, ...)
15413 foreach my $Path (cmd_find($Dest,"","*".esc($TargetLibraryName)."*\.$LIB_EXT*",2))
15414 { # all files and symlinks that match the name of a library
15415 if(get_filename($Path)=~/\A(|lib)\Q$TargetLibraryName\E[\d\-]*\.$LIB_EXT[\d\.]*\Z/i)
15416 {
15417 $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
15418 push(@AllObjects, resolve_symlink($Path));
15419 }
15420 }
15421 }
15422 else
15423 { # search for all files and symlinks
15424 foreach my $Path (find_libs($Dest,"",""))
15425 {
15426 next if(ignore_path($Path));
15427 next if(skip_lib($Path, $LibVersion));
15428 $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
15429 push(@AllObjects, resolve_symlink($Path));
15430 }
15431 if($OSgroup eq "macos")
15432 { # shared libraries on MacOS X may have no extension
15433 foreach my $Path (cmd_find($Dest,"f","",""))
15434 {
15435 next if(ignore_path($Path));
15436 next if(skip_lib($Path, $LibVersion));
15437 if(get_filename($Path)!~/\./
15438 and cmd_file($Path)=~/(shared|dynamic)\s+library/i) {
15439 $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
15440 push(@AllObjects, resolve_symlink($Path));
15441 }
15442 }
15443 }
15444 }
15445 return @AllObjects;
15446 }
15447 else {
15448 return ();
15449 }
15450}
15451
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015452sub isCyclical($$)
15453{
15454 my ($Stack, $Value) = @_;
15455 return (grep {$_ eq $Value} @{$Stack});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015456}
15457
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015458sub generateTemplate()
15459{
15460 writeFile("VERSION.xml", $DescriptorTemplate."\n");
15461 printMsg("INFO", "XML-descriptor template ./VERSION.xml has been generated");
15462}
15463
15464sub detectWordSize()
15465{
15466 return "" if(not $GCC_PATH);
15467 if($Cache{"detectWordSize"}) {
15468 return $Cache{"detectWordSize"};
15469 }
15470 writeFile("$TMP_DIR/empty.h", "");
15471 my $Defines = `$GCC_PATH -E -dD $TMP_DIR/empty.h`;
15472 unlink("$TMP_DIR/empty.h");
15473 my $WSize = 0;
15474 if($Defines=~/ __SIZEOF_POINTER__\s+(\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015475 { # GCC 4
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015476 $WSize = $1;
15477 }
15478 elsif($Defines=~/ __PTRDIFF_TYPE__\s+(\w+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015479 { # GCC 3
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015480 my $PTRDIFF = $1;
15481 if($PTRDIFF=~/long/) {
15482 $WSize = 8;
15483 }
15484 else {
15485 $WSize = 4;
15486 }
15487 }
15488 if(not int($WSize)) {
15489 exitStatus("Error", "can't check WORD size");
15490 }
15491 return ($Cache{"detectWordSize"} = $WSize);
15492}
15493
15494sub majorVersion($)
15495{
15496 my $V = $_[0];
15497 return 0 if(not $V);
15498 my @VParts = split(/\./, $V);
15499 return $VParts[0];
15500}
15501
15502sub cmpVersions($$)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015503{ # compare two versions in dotted-numeric format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015504 my ($V1, $V2) = @_;
15505 return 0 if($V1 eq $V2);
15506 return undef if($V1!~/\A\d+[\.\d+]*\Z/);
15507 return undef if($V2!~/\A\d+[\.\d+]*\Z/);
15508 my @V1Parts = split(/\./, $V1);
15509 my @V2Parts = split(/\./, $V2);
15510 for (my $i = 0; $i <= $#V1Parts && $i <= $#V2Parts; $i++) {
15511 return -1 if(int($V1Parts[$i]) < int($V2Parts[$i]));
15512 return 1 if(int($V1Parts[$i]) > int($V2Parts[$i]));
15513 }
15514 return -1 if($#V1Parts < $#V2Parts);
15515 return 1 if($#V1Parts > $#V2Parts);
15516 return 0;
15517}
15518
15519sub read_ABI_Dump($$)
15520{
15521 my ($LibVersion, $Path) = @_;
15522 return if(not $LibVersion or not -e $Path);
15523 my $FilePath = "";
15524 if($Path=~/\.abi\Z/)
15525 { # input *.abi
15526 $FilePath = $Path;
15527 }
15528 else
15529 { # input *.abi.tar.gz
15530 $FilePath = unpackDump($Path);
15531 }
15532 if($FilePath!~/\.abi\Z/) {
15533 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
15534 }
15535 my $Content = readFile($FilePath);
15536 if($Path!~/\.abi\Z/)
15537 { # remove temp file
15538 unlink($FilePath);
15539 }
15540 if($Content!~/};\s*\Z/) {
15541 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
15542 }
15543 my $LibraryABI = eval($Content);
15544 if(not $LibraryABI) {
15545 exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again");
15546 }
15547 # new dumps (>=1.22) have a personal versioning
15548 my $DumpVersion = $LibraryABI->{"ABI_DUMP_VERSION"};
15549 my $ToolVersion = $LibraryABI->{"ABI_COMPLIANCE_CHECKER_VERSION"};
15550 if(not $DumpVersion)
15551 { # old dumps (<=1.21.6) have been marked by the tool version
15552 $DumpVersion = $ToolVersion;
15553 }
15554 $UsedDump{$LibVersion}{"V"} = $DumpVersion;
15555 if(majorVersion($DumpVersion) ne majorVersion($ABI_DUMP_VERSION))
15556 { # should be compatible with dumps of the same major version
15557 if(cmpVersions($DumpVersion, $ABI_DUMP_VERSION)>0)
15558 { # Don't know how to parse future dump formats
15559 exitStatus("Dump_Version", "incompatible version $DumpVersion of specified ABI dump (newer than $ABI_DUMP_VERSION)");
15560 }
15561 elsif(cmpVersions($DumpVersion, $TOOL_VERSION)>0 and not $LibraryABI->{"ABI_DUMP_VERSION"})
15562 { # Don't know how to parse future dump formats
15563 exitStatus("Dump_Version", "incompatible version $DumpVersion of specified ABI dump (newer than $TOOL_VERSION)");
15564 }
15565 if($UseOldDumps)
15566 {
15567 if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)<0) {
15568 exitStatus("Dump_Version", "incompatible version $DumpVersion of specified ABI dump (older than $OLDEST_SUPPORTED_VERSION)");
15569 }
15570 }
15571 else
15572 {
15573 my $Msg = "incompatible version $DumpVersion of specified ABI dump (allowed only ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION)";
15574 if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)>=0) {
15575 $Msg .= "\nUse -old-dumps option to use old-version dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0)";
15576 }
15577 exitStatus("Dump_Version", $Msg);
15578 }
15579 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015580 if($LibraryABI->{"SrcBin"})
15581 { # default
15582 $UsedDump{$LibVersion}{"SrcBin"} = 1;
15583 }
15584 elsif($LibraryABI->{"BinOnly"})
15585 { # ABI dump created with --binary option
15586 $UsedDump{$LibVersion}{"BinOnly"} = 1;
15587 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015588 if(defined $LibraryABI->{"Mode"}
15589 and $LibraryABI->{"Mode"} eq "Extended")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015590 { # --ext option
15591 $ExtendedCheck = 1;
15592 }
15593 if(my $Lang = $LibraryABI->{"Language"})
15594 {
15595 $UsedDump{$LibVersion}{"L"} = $Lang;
15596 setLanguage($LibVersion, $Lang);
15597 }
15598 $TypeInfo{$LibVersion} = $LibraryABI->{"TypeInfo"};
15599 if(not $TypeInfo{$LibVersion})
15600 { # support for old ABI dumps
15601 $TypeInfo{$LibVersion} = $LibraryABI->{"TypeDescr"};
15602 }
15603 read_Machine_DumpInfo($LibraryABI, $LibVersion);
15604 $SymbolInfo{$LibVersion} = $LibraryABI->{"SymbolInfo"};
15605 if(not $SymbolInfo{$LibVersion})
15606 { # support for old dumps
15607 $SymbolInfo{$LibVersion} = $LibraryABI->{"FuncDescr"};
15608 }
15609 if(not keys(%{$SymbolInfo{$LibVersion}}))
15610 { # validation of old-version dumps
15611 if(not $ExtendedCheck) {
15612 exitStatus("Invalid_Dump", "the input dump d$LibVersion is invalid");
15613 }
15614 }
15615 $Library_Symbol{$LibVersion} = $LibraryABI->{"Symbols"};
15616 if(not $Library_Symbol{$LibVersion})
15617 { # support for old dumps
15618 $Library_Symbol{$LibVersion} = $LibraryABI->{"Interfaces"};
15619 }
15620 $DepSymbols{$LibVersion} = $LibraryABI->{"DepSymbols"};
15621 if(not $DepSymbols{$LibVersion})
15622 { # support for old dumps
15623 $DepSymbols{$LibVersion} = $LibraryABI->{"DepInterfaces"};
15624 }
15625 if(not $DepSymbols{$LibVersion})
15626 { # support for old dumps
15627 # Cannot reconstruct DepSymbols. This may result in false
15628 # positives if the old dump is for library 2. Not a problem if
15629 # old dumps are only from old libraries.
15630 $DepSymbols{$LibVersion} = {};
15631 }
15632 $SymVer{$LibVersion} = $LibraryABI->{"SymbolVersion"};
15633 $Tid_TDid{$LibVersion} = $LibraryABI->{"Tid_TDid"};
15634 $Descriptor{$LibVersion}{"Version"} = $LibraryABI->{"LibraryVersion"};
15635 $SkipTypes{$LibVersion} = $LibraryABI->{"SkipTypes"};
15636 if(not $SkipTypes{$LibVersion})
15637 { # support for old dumps
15638 $SkipTypes{$LibVersion} = $LibraryABI->{"OpaqueTypes"};
15639 }
15640 $SkipSymbols{$LibVersion} = $LibraryABI->{"SkipSymbols"};
15641 if(not $SkipSymbols{$LibVersion})
15642 { # support for old dumps
15643 $SkipSymbols{$LibVersion} = $LibraryABI->{"SkipInterfaces"};
15644 }
15645 if(not $SkipSymbols{$LibVersion})
15646 { # support for old dumps
15647 $SkipSymbols{$LibVersion} = $LibraryABI->{"InternalInterfaces"};
15648 }
15649 $SkipNameSpaces{$LibVersion} = $LibraryABI->{"SkipNameSpaces"};
15650 $TargetHeaders{$LibVersion} = $LibraryABI->{"TargetHeaders"};
15651 foreach my $Path (keys(%{$LibraryABI->{"SkipHeaders"}}))
15652 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015653 $SkipHeadersList{$LibVersion}{$Path} = $LibraryABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015654 my ($CPath, $Type) = classifyPath($Path);
15655 $SkipHeaders{$LibVersion}{$Type}{$CPath} = $LibraryABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015656 }
15657 read_Headers_DumpInfo($LibraryABI, $LibVersion);
15658 read_Libs_DumpInfo($LibraryABI, $LibVersion);
15659 if(not $Descriptor{$LibVersion}{"Libs"})
15660 { # support for old ABI dumps
15661 if(cmpVersions($DumpVersion, "2.10.1")<0)
15662 {
15663 if(not $TargetHeaders{$LibVersion})
15664 {
15665 foreach (keys(%{$Registered_Headers{$LibVersion}})) {
15666 $TargetHeaders{$LibVersion}{get_filename($_)}=1;
15667 }
15668 }
15669 }
15670 }
15671 $Constants{$LibVersion} = $LibraryABI->{"Constants"};
15672 $NestedNameSpaces{$LibVersion} = $LibraryABI->{"NameSpaces"};
15673 if(not $NestedNameSpaces{$LibVersion})
15674 { # support for old dumps
15675 # Cannot reconstruct NameSpaces. This may affect design
15676 # of the compatibility report.
15677 $NestedNameSpaces{$LibVersion} = {};
15678 }
15679 # target system type
15680 # needed to adopt HTML report
15681 if(not $DumpSystem)
15682 { # to use in createSymbolsList(...)
15683 $OStarget = $LibraryABI->{"Target"};
15684 }
15685 # recreate environment
15686 foreach my $Lib_Name (keys(%{$Library_Symbol{$LibVersion}}))
15687 {
15688 foreach my $Interface (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}}))
15689 {
15690 $Symbol_Library{$LibVersion}{$Interface} = $Lib_Name;
15691 if($Library_Symbol{$LibVersion}{$Lib_Name}{$Interface}<=-1)
15692 { # data marked as -size in the dump
15693 $CompleteSignature{$LibVersion}{$Interface}{"Object"} = 1;
15694 }
15695 if($COMMON_LANGUAGE{$LibVersion} ne "C++"
15696 and $Interface=~/\A(_Z|\?)/) {
15697 setLanguage($LibVersion, "C++");
15698 }
15699 }
15700 }
15701 my @VFunc = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015702 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015703 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015704 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015705 if(not $MnglName)
15706 { # C-functions
15707 next;
15708 }
15709 if(not $Symbol_Library{$LibVersion}{$MnglName}
15710 and not $DepSymbols{$LibVersion}{$MnglName}) {
15711 push(@VFunc, $MnglName);
15712 }
15713 }
15714 translateSymbols(@VFunc, $LibVersion);
15715 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
15716 translateSymbols(keys(%{$DepSymbols{$LibVersion}}), $LibVersion);
15717
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015718 foreach my $TypeDeclId (sort keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015719 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015720 foreach my $TypeId (sort keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015721 {
15722 if(defined $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"BaseClass"})
15723 { # support for old ABI dumps < 2.0 (ACC 1.22)
15724 foreach my $BId (keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"BaseClass"}}))
15725 {
15726 if(my $Access = $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"BaseClass"}{$BId})
15727 {
15728 if($Access ne "public") {
15729 $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Base"}{$BId}{"access"} = $Access;
15730 }
15731 }
15732 $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Base"}{$BId} = {};
15733 }
15734 delete($TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"BaseClass"});
15735 }
15736 my %TInfo = %{$TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}};
15737 if(defined $TInfo{"Base"})
15738 {
15739 foreach (keys(%{$TInfo{"Base"}})) {
15740 $Class_SubClasses{$LibVersion}{$_}{$TypeId}=1;
15741 }
15742 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015743 if($TInfo{"Type"} eq "Typedef" and defined $TInfo{"BaseType"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015744 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015745 if(my ($BTDid, $BTid) = ($TInfo{"BaseType"}{"TDid"}, $TInfo{"BaseType"}{"Tid"}))
15746 {
15747 $BTDid = "" if(not defined $BTDid);
15748 $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}} = $TypeInfo{$LibVersion}{$BTDid}{$BTid}{"Name"};
15749 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015750 }
15751 if(not $TName_Tid{$LibVersion}{$TInfo{"Name"}})
15752 { # classes: class (id1), typedef (artificial, id2 > id1)
15753 $TName_Tid{$LibVersion}{$TInfo{"Name"}} = $TypeId;
15754 }
15755 }
15756 }
15757
15758 $Descriptor{$LibVersion}{"Dump"} = 1;
15759}
15760
15761sub read_Machine_DumpInfo($$)
15762{
15763 my ($LibraryABI, $LibVersion) = @_;
15764 if($LibraryABI->{"Arch"}) {
15765 $CPU_ARCH{$LibVersion} = $LibraryABI->{"Arch"};
15766 }
15767 if($LibraryABI->{"WordSize"}) {
15768 $WORD_SIZE{$LibVersion} = $LibraryABI->{"WordSize"};
15769 }
15770 else
15771 { # support for old dumps
15772 $WORD_SIZE{$LibVersion} = $LibraryABI->{"SizeOfPointer"};
15773 }
15774 if(not $WORD_SIZE{$LibVersion})
15775 { # support for old dumps (<1.23)
15776 if(my $Tid = getTypeIdByName("char*", $LibVersion))
15777 { # size of char*
15778 $WORD_SIZE{$LibVersion} = get_TypeSize($Tid, $LibVersion);
15779 }
15780 else
15781 {
15782 my $PSize = 0;
15783 foreach my $TDid (keys(%{$TypeInfo{$LibVersion}}))
15784 {
15785 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}{$TDid}}))
15786 {
15787 if(get_TypeAttr($Tid, $LibVersion, "Type") eq "Pointer")
15788 { # any "pointer"-type
15789 $PSize = get_TypeSize($Tid, $LibVersion);
15790 last;
15791 }
15792 }
15793 if($PSize) {
15794 last;
15795 }
15796 }
15797 if($PSize)
15798 { # a pointer type size
15799 $WORD_SIZE{$LibVersion} = $PSize;
15800 }
15801 else {
15802 printMsg("WARNING", "cannot identify a WORD size in the ABI dump (too old format)");
15803 }
15804 }
15805 }
15806 if($LibraryABI->{"GccVersion"}) {
15807 $GCC_VERSION{$LibVersion} = $LibraryABI->{"GccVersion"};
15808 }
15809}
15810
15811sub read_Libs_DumpInfo($$)
15812{
15813 my ($LibraryABI, $LibVersion) = @_;
15814 if(keys(%{$Library_Symbol{$LibVersion}})
15815 and not $DumpAPI) {
15816 $Descriptor{$LibVersion}{"Libs"} = "OK";
15817 }
15818}
15819
15820sub read_Headers_DumpInfo($$)
15821{
15822 my ($LibraryABI, $LibVersion) = @_;
15823 if(keys(%{$LibraryABI->{"Headers"}})
15824 and not $DumpAPI) {
15825 $Descriptor{$LibVersion}{"Headers"} = "OK";
15826 }
15827 foreach my $Identity (keys(%{$LibraryABI->{"Headers"}}))
15828 { # headers info is stored in the old dumps in the different way
15829 if($UseOldDumps
15830 and my $Name = $LibraryABI->{"Headers"}{$Identity}{"Name"})
15831 { # support for old dumps: headers info corrected in 1.22
15832 $Identity = $Name;
15833 }
15834 $Registered_Headers{$LibVersion}{$Identity}{"Identity"} = $Identity;
15835 }
15836}
15837
15838sub find_libs($$$)
15839{
15840 my ($Path, $Type, $MaxDepth) = @_;
15841 # FIXME: correct the search pattern
15842 return cmd_find($Path, $Type, ".*\\.$LIB_EXT\[0-9.]*", $MaxDepth);
15843}
15844
15845sub createDescriptor($$)
15846{
15847 my ($LibVersion, $Path) = @_;
15848 if(not $LibVersion or not $Path
15849 or not -e $Path) {
15850 return "";
15851 }
15852 if(-d $Path)
15853 { # directory with headers files and shared objects
15854 return "
15855 <version>
15856 ".$TargetVersion{$LibVersion}."
15857 </version>
15858
15859 <headers>
15860 $Path
15861 </headers>
15862
15863 <libs>
15864 $Path
15865 </libs>";
15866 }
15867 else
15868 { # files
15869 if($Path=~/\.xml\Z/i)
15870 { # standard XML-descriptor
15871 return readFile($Path);
15872 }
15873 elsif(is_header($Path, 2, $LibVersion))
15874 { # header file
15875 return "
15876 <version>
15877 ".$TargetVersion{$LibVersion}."
15878 </version>
15879
15880 <headers>
15881 $Path
15882 </headers>
15883
15884 <libs>
15885 none
15886 </libs>";
15887 }
15888 elsif(parse_libname($Path, "name", $OStarget))
15889 { # shared object
15890 return "
15891 <version>
15892 ".$TargetVersion{$LibVersion}."
15893 </version>
15894
15895 <headers>
15896 none
15897 </headers>
15898
15899 <libs>
15900 $Path
15901 </libs>";
15902 }
15903 else
15904 { # standard XML-descriptor
15905 return readFile($Path);
15906 }
15907 }
15908}
15909
15910sub detect_lib_default_paths()
15911{
15912 my %LPaths = ();
15913 if($OSgroup eq "bsd")
15914 {
15915 if(my $LdConfig = get_CmdPath("ldconfig")) {
15916 foreach my $Line (split(/\n/, `$LdConfig -r 2>$TMP_DIR/null`)) {
15917 if($Line=~/\A[ \t]*\d+:\-l(.+) \=\> (.+)\Z/) {
15918 $LPaths{"lib".$1} = $2;
15919 }
15920 }
15921 }
15922 else {
15923 printMsg("WARNING", "can't find ldconfig");
15924 }
15925 }
15926 else
15927 {
15928 if(my $LdConfig = get_CmdPath("ldconfig"))
15929 {
15930 if($SystemRoot and $OSgroup eq "linux")
15931 { # use host (x86) ldconfig with the target (arm) ld.so.conf
15932 if(-e $SystemRoot."/etc/ld.so.conf") {
15933 $LdConfig .= " -f ".$SystemRoot."/etc/ld.so.conf";
15934 }
15935 }
15936 foreach my $Line (split(/\n/, `$LdConfig -p 2>$TMP_DIR/null`)) {
15937 if($Line=~/\A[ \t]*([^ \t]+) .* \=\> (.+)\Z/)
15938 {
15939 my ($Name, $Path) = ($1, $2);
15940 $Path=~s/[\/]{2,}/\//;
15941 $LPaths{$Name} = $Path;
15942 }
15943 }
15944 }
15945 elsif($OSgroup=~/linux/i) {
15946 printMsg("WARNING", "can't find ldconfig");
15947 }
15948 }
15949 return \%LPaths;
15950}
15951
15952sub detect_bin_default_paths()
15953{
15954 my $EnvPaths = $ENV{"PATH"};
15955 if($OSgroup eq "beos") {
15956 $EnvPaths.=":".$ENV{"BETOOLS"};
15957 }
15958 my $Sep = ($OSgroup eq "windows")?";":":|;";
15959 foreach my $Path (sort {length($a)<=>length($b)} split(/$Sep/, $EnvPaths))
15960 {
15961 $Path = path_format($Path, $OSgroup);
15962 $Path=~s/[\/\\]+\Z//g;
15963 next if(not $Path);
15964 if($SystemRoot
15965 and $Path=~/\A\Q$SystemRoot\E\//)
15966 { # do NOT use binaries from target system
15967 next;
15968 }
15969 $DefaultBinPaths{$Path} = 1;
15970 }
15971}
15972
15973sub detect_inc_default_paths()
15974{
15975 return () if(not $GCC_PATH);
15976 my %DPaths = ("Cpp"=>{},"Gcc"=>{},"Inc"=>{});
15977 writeFile("$TMP_DIR/empty.h", "");
15978 foreach my $Line (split(/\n/, `$GCC_PATH -v -x c++ -E "$TMP_DIR/empty.h" 2>&1`))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015979 { # detecting GCC default include paths
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015980 if($Line=~/\A[ \t]*((\/|\w+:\\).+)[ \t]*\Z/)
15981 {
15982 my $Path = simplify_path($1);
15983 $Path=~s/[\/\\]+\Z//g;
15984 $Path = path_format($Path, $OSgroup);
15985 if($Path=~/c\+\+|\/g\+\+\//)
15986 {
15987 $DPaths{"Cpp"}{$Path}=1;
15988 if(not defined $MAIN_CPP_DIR
15989 or get_depth($MAIN_CPP_DIR)>get_depth($Path)) {
15990 $MAIN_CPP_DIR = $Path;
15991 }
15992 }
15993 elsif($Path=~/gcc/) {
15994 $DPaths{"Gcc"}{$Path}=1;
15995 }
15996 else
15997 {
15998 next if($Path=~/local[\/\\]+include/);
15999 if($SystemRoot
16000 and $Path!~/\A\Q$SystemRoot\E(\/|\Z)/)
16001 { # The GCC include path for user headers is not a part of the system root
16002 # The reason: you are not specified the --cross-gcc option or selected a wrong compiler
16003 # or it is the internal cross-GCC path like arm-linux-gnueabi/include
16004 next;
16005 }
16006 $DPaths{"Inc"}{$Path}=1;
16007 }
16008 }
16009 }
16010 unlink("$TMP_DIR/empty.h");
16011 return %DPaths;
16012}
16013
16014sub detect_default_paths($)
16015{
16016 my ($HSearch, $LSearch, $BSearch, $GSearch) = (1, 1, 1, 1);
16017 my $Search = $_[0];
16018 if($Search!~/inc/) {
16019 $HSearch = 0;
16020 }
16021 if($Search!~/lib/) {
16022 $LSearch = 0;
16023 }
16024 if($Search!~/bin/) {
16025 $BSearch = 0;
16026 }
16027 if($Search!~/gcc/) {
16028 $GSearch = 0;
16029 }
16030 if(keys(%{$SystemPaths{"include"}}))
16031 { # <search_headers> section of the XML descriptor
16032 # do NOT search for systems headers
16033 $HSearch = 0;
16034 }
16035 if(keys(%{$SystemPaths{"lib"}}))
16036 { # <search_headers> section of the XML descriptor
16037 # do NOT search for systems headers
16038 $LSearch = 0;
16039 }
16040 foreach my $Type (keys(%{$OS_AddPath{$OSgroup}}))
16041 { # additional search paths
16042 next if($Type eq "include" and not $HSearch);
16043 next if($Type eq "lib" and not $LSearch);
16044 next if($Type eq "bin" and not $BSearch);
16045 foreach my $Path (keys(%{$OS_AddPath{$OSgroup}{$Type}}))
16046 {
16047 next if(not -d $Path);
16048 $SystemPaths{$Type}{$Path} = $OS_AddPath{$OSgroup}{$Type}{$Path};
16049 }
16050 }
16051 if($OSgroup ne "windows")
16052 { # unix-like
16053 foreach my $Type ("include", "lib", "bin")
16054 { # automatic detection of system "devel" directories
16055 next if($Type eq "include" and not $HSearch);
16056 next if($Type eq "lib" and not $LSearch);
16057 next if($Type eq "bin" and not $BSearch);
16058 my ($UsrDir, $RootDir) = ("/usr", "/");
16059 if($SystemRoot and $Type ne "bin")
16060 { # 1. search for target headers and libraries
16061 # 2. use host commands: ldconfig, readelf, etc.
16062 ($UsrDir, $RootDir) = ("$SystemRoot/usr", $SystemRoot);
16063 }
16064 foreach my $Path (cmd_find($RootDir,"d","*$Type*",1)) {
16065 $SystemPaths{$Type}{$Path} = 1;
16066 }
16067 if(-d $RootDir."/".$Type)
16068 { # if "/lib" is symbolic link
16069 if($RootDir eq "/") {
16070 $SystemPaths{$Type}{"/".$Type} = 1;
16071 }
16072 else {
16073 $SystemPaths{$Type}{$RootDir."/".$Type} = 1;
16074 }
16075 }
16076 if(-d $UsrDir) {
16077 foreach my $Path (cmd_find($UsrDir,"d","*$Type*",1)) {
16078 $SystemPaths{$Type}{$Path} = 1;
16079 }
16080 if(-d $UsrDir."/".$Type)
16081 { # if "/usr/lib" is symbolic link
16082 $SystemPaths{$Type}{$UsrDir."/".$Type} = 1;
16083 }
16084 }
16085 }
16086 }
16087 if($BSearch)
16088 {
16089 detect_bin_default_paths();
16090 foreach my $Path (keys(%DefaultBinPaths)) {
16091 $SystemPaths{"bin"}{$Path} = $DefaultBinPaths{$Path};
16092 }
16093 }
16094 # check environment variables
16095 if($OSgroup eq "beos")
16096 {
16097 foreach (keys(%{$SystemPaths{"bin"}}))
16098 {
16099 if($_ eq ".") {
16100 next;
16101 }
16102 foreach my $Path (cmd_find($_, "d", "bin", ""))
16103 { # search for /boot/develop/abi/x86/gcc4/tools/gcc-4.4.4-haiku-101111/bin/
16104 $SystemPaths{"bin"}{$Path} = 1;
16105 }
16106 }
16107 if($HSearch)
16108 {
16109 foreach my $Path (split(/:|;/, $ENV{"BEINCLUDES"}))
16110 {
16111 if(is_abs($Path)) {
16112 $DefaultIncPaths{$Path} = 1;
16113 }
16114 }
16115 }
16116 if($LSearch)
16117 {
16118 foreach my $Path (split(/:|;/, $ENV{"BELIBRARIES"}), split(/:|;/, $ENV{"LIBRARY_PATH"}))
16119 {
16120 if(is_abs($Path)) {
16121 $DefaultLibPaths{$Path} = 1;
16122 }
16123 }
16124 }
16125 }
16126 if($LSearch)
16127 { # using linker to get system paths
16128 if(my $LPaths = detect_lib_default_paths())
16129 { # unix-like
16130 foreach my $Name (keys(%{$LPaths}))
16131 {
16132 if($SystemRoot
16133 and $LPaths->{$Name}!~/\A\Q$SystemRoot\E\//)
16134 { # wrong ldconfig configuration
16135 # check your <sysroot>/etc/ld.so.conf
16136 next;
16137 }
16138 $DyLib_DefaultPath{$Name} = $LPaths->{$Name};
16139 $DefaultLibPaths{get_dirname($LPaths->{$Name})} = 1;
16140 }
16141 }
16142 foreach my $Path (keys(%DefaultLibPaths)) {
16143 $SystemPaths{"lib"}{$Path} = $DefaultLibPaths{$Path};
16144 }
16145 }
16146 if($BSearch)
16147 {
16148 if($CrossGcc)
16149 { # --cross-gcc=arm-linux-gcc
16150 if(-e $CrossGcc)
16151 { # absolute or relative path
16152 $GCC_PATH = get_abs_path($CrossGcc);
16153 }
16154 elsif($CrossGcc!~/\// and get_CmdPath($CrossGcc))
16155 { # command name
16156 $GCC_PATH = $CrossGcc;
16157 }
16158 else {
16159 exitStatus("Access_Error", "can't access \'$CrossGcc\'");
16160 }
16161 if($GCC_PATH=~/\s/) {
16162 $GCC_PATH = "\"".$GCC_PATH."\"";
16163 }
16164 }
16165 }
16166 if($GSearch)
16167 { # GCC path and default include dirs
16168 if(not $CrossGcc) {
16169 $GCC_PATH = get_CmdPath("gcc");
16170 }
16171 if(not $GCC_PATH) {
16172 exitStatus("Not_Found", "can't find GCC>=3.0 in PATH");
16173 }
16174 if(not $CheckObjectsOnly_Opt)
16175 {
16176 if(my $GCC_Ver = get_dumpversion($GCC_PATH))
16177 {
16178 my $GccTarget = get_dumpmachine($GCC_PATH);
16179 printMsg("INFO", "Using GCC $GCC_Ver ($GccTarget)");
16180 if($GccTarget=~/symbian/)
16181 {
16182 $OStarget = "symbian";
16183 $LIB_EXT = $OS_LibExt{$LIB_TYPE}{$OStarget};
16184 }
16185 }
16186 else {
16187 exitStatus("Error", "something is going wrong with the GCC compiler");
16188 }
16189 }
16190 if(not $NoStdInc)
16191 { # do NOT search in GCC standard paths
16192 my %DPaths = detect_inc_default_paths();
16193 %DefaultCppPaths = %{$DPaths{"Cpp"}};
16194 %DefaultGccPaths = %{$DPaths{"Gcc"}};
16195 %DefaultIncPaths = %{$DPaths{"Inc"}};
16196 foreach my $Path (keys(%DefaultIncPaths)) {
16197 $SystemPaths{"include"}{$Path} = $DefaultIncPaths{$Path};
16198 }
16199 }
16200 }
16201 if($HSearch)
16202 { # user include paths
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016203 my $IncPath = "/usr/include";
16204 if($SystemRoot) {
16205 $IncPath = $SystemRoot.$IncPath;
16206 }
16207 if(-d $IncPath) {
16208 $UserIncPath{$IncPath}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016209 }
16210 }
16211}
16212
16213sub getLIB_EXT($)
16214{
16215 my $Target = $_[0];
16216 if(my $Ext = $OS_LibExt{$LIB_TYPE}{$Target}) {
16217 return $Ext;
16218 }
16219 return $OS_LibExt{$LIB_TYPE}{"default"};
16220}
16221
16222sub getAR_EXT($)
16223{
16224 my $Target = $_[0];
16225 if(my $Ext = $OS_Archive{$Target}) {
16226 return $Ext;
16227 }
16228 return $OS_Archive{"default"};
16229}
16230
16231sub get_dumpversion($)
16232{
16233 my $Cmd = $_[0];
16234 return "" if(not $Cmd);
16235 if($Cache{"get_dumpversion"}{$Cmd}) {
16236 return $Cache{"get_dumpversion"}{$Cmd};
16237 }
16238 my $V = `$Cmd -dumpversion 2>$TMP_DIR/null`;
16239 chomp($V);
16240 return ($Cache{"get_dumpversion"}{$Cmd} = $V);
16241}
16242
16243sub get_dumpmachine($)
16244{
16245 my $Cmd = $_[0];
16246 return "" if(not $Cmd);
16247 if($Cache{"get_dumpmachine"}{$Cmd}) {
16248 return $Cache{"get_dumpmachine"}{$Cmd};
16249 }
16250 my $Machine = `$Cmd -dumpmachine 2>$TMP_DIR/null`;
16251 chomp($Machine);
16252 return ($Cache{"get_dumpmachine"}{$Cmd} = $Machine);
16253}
16254
16255sub check_command($)
16256{
16257 my $Cmd = $_[0];
16258 return "" if(not $Cmd);
16259 my @Options = (
16260 "--version",
16261 "-help"
16262 );
16263 foreach my $Opt (@Options)
16264 {
16265 my $Info = `$Cmd $Opt 2>$TMP_DIR/null`;
16266 if($Info) {
16267 return 1;
16268 }
16269 }
16270 return 0;
16271}
16272
16273sub check_gcc_version($$)
16274{
16275 my ($Cmd, $Req_V) = @_;
16276 return 0 if(not $Cmd or not $Req_V);
16277 my $Gcc_V = get_dumpversion($Cmd);
16278 $Gcc_V=~s/(-|_)[a-z_]+.*\Z//; # remove suffix (like "-haiku-100818")
16279 if(cmpVersions($Gcc_V, $Req_V)>=0) {
16280 return $Cmd;
16281 }
16282 return "";
16283}
16284
16285sub get_depth($)
16286{
16287 if(defined $Cache{"get_depth"}{$_[0]}) {
16288 return $Cache{"get_depth"}{$_[0]}
16289 }
16290 return ($Cache{"get_depth"}{$_[0]} = ($_[0]=~tr![\/\\]|\:\:!!));
16291}
16292
16293sub find_gcc_cxx_headers($)
16294{
16295 my $LibVersion = $_[0];
16296 return if($Cache{"find_gcc_cxx_headers"});# this function should be called once
16297 # detecting system header paths
16298 foreach my $Path (sort {get_depth($b) <=> get_depth($a)} keys(%DefaultGccPaths))
16299 {
16300 foreach my $HeaderPath (sort {get_depth($a) <=> get_depth($b)} cmd_find($Path,"f","",""))
16301 {
16302 my $FileName = get_filename($HeaderPath);
16303 next if($DefaultGccHeader{$FileName});
16304 $DefaultGccHeader{$FileName} = $HeaderPath;
16305 }
16306 }
16307 if($COMMON_LANGUAGE{$LibVersion} eq "C++" and not $STDCXX_TESTING)
16308 {
16309 foreach my $CppDir (sort {get_depth($b)<=>get_depth($a)} keys(%DefaultCppPaths))
16310 {
16311 my @AllCppHeaders = cmd_find($CppDir,"f","","");
16312 foreach my $Path (sort {get_depth($a)<=>get_depth($b)} @AllCppHeaders)
16313 {
16314 my $FileName = get_filename($Path);
16315 next if($DefaultCppHeader{$FileName});
16316 $DefaultCppHeader{$FileName} = $Path;
16317 }
16318 }
16319 }
16320 $Cache{"find_gcc_cxx_headers"} = 1;
16321}
16322
16323sub parse_libname($$$)
16324{
16325 my ($Name, $Type, $Target) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016326 if(not $Name) {
16327 return "";
16328 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016329 if($Target eq "symbian") {
16330 return parse_libname_symbian($Name, $Type);
16331 }
16332 elsif($Target eq "windows") {
16333 return parse_libname_windows($Name, $Type);
16334 }
16335 my $Ext = getLIB_EXT($Target);
16336 if($Name=~/((((lib|).+?)([\-\_][\d\-\.\_]+|))\.$Ext)(\.(.+)|)\Z/)
16337 { # libSDL-1.2.so.0.7.1
16338 # libwbxml2.so.0.0.18
16339 if($Type eq "name")
16340 { # libSDL-1.2
16341 # libwbxml2
16342 return $2;
16343 }
16344 elsif($Type eq "name+ext")
16345 { # libSDL-1.2.so
16346 # libwbxml2.so
16347 return $1;
16348 }
16349 elsif($Type eq "version")
16350 {
16351 if($7 ne "")
16352 { # 0.7.1
16353 return $7;
16354 }
16355 else
16356 { # libc-2.5.so (=>2.5 version)
16357 my $MV = $5;
16358 $MV=~s/\A[\-\_]+//g;
16359 return $MV;
16360 }
16361 }
16362 elsif($Type eq "short")
16363 { # libSDL
16364 # libwbxml2
16365 return $3;
16366 }
16367 elsif($Type eq "shortest")
16368 { # SDL
16369 # wbxml
16370 return shortest_name($3);
16371 }
16372 }
16373 return "";# error
16374}
16375
16376sub parse_libname_symbian($$)
16377{
16378 my ($Name, $Type) = @_;
16379 my $Ext = getLIB_EXT("symbian");
16380 if($Name=~/(((.+?)(\{.+\}|))\.$Ext)\Z/)
16381 { # libpthread{00010001}.dso
16382 if($Type eq "name")
16383 { # libpthread{00010001}
16384 return $2;
16385 }
16386 elsif($Type eq "name+ext")
16387 { # libpthread{00010001}.dso
16388 return $1;
16389 }
16390 elsif($Type eq "version")
16391 { # 00010001
16392 my $V = $4;
16393 $V=~s/\{(.+)\}/$1/;
16394 return $V;
16395 }
16396 elsif($Type eq "short")
16397 { # libpthread
16398 return $3;
16399 }
16400 elsif($Type eq "shortest")
16401 { # pthread
16402 return shortest_name($3);
16403 }
16404 }
16405 return "";# error
16406}
16407
16408sub parse_libname_windows($$)
16409{
16410 my ($Name, $Type) = @_;
16411 my $Ext = getLIB_EXT("windows");
16412 if($Name=~/((.+?)\.$Ext)\Z/)
16413 { # netapi32.dll
16414 if($Type eq "name")
16415 { # netapi32
16416 return $2;
16417 }
16418 elsif($Type eq "name+ext")
16419 { # netapi32.dll
16420 return $1;
16421 }
16422 elsif($Type eq "version")
16423 { # DLL version embedded
16424 # at binary-level
16425 return "";
16426 }
16427 elsif($Type eq "short")
16428 { # netapi32
16429 return $2;
16430 }
16431 elsif($Type eq "shortest")
16432 { # netapi
16433 return shortest_name($2);
16434 }
16435 }
16436 return "";# error
16437}
16438
16439sub shortest_name($)
16440{
16441 my $Name = $_[0];
16442 # remove prefix
16443 $Name=~s/\A(lib|open)//;
16444 # remove suffix
16445 $Name=~s/[\W\d_]+\Z//i;
16446 $Name=~s/([a-z]{2,})(lib)\Z/$1/i;
16447 return $Name;
16448}
16449
16450sub getPrefix($)
16451{
16452 my $Str = $_[0];
16453 if($Str=~/\A(Get|get|Set|set)([A-Z]|_)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016454 { # GetError
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016455 return "";
16456 }
16457 if($Str=~/\A([_]*[A-Z][a-z]{1,5})[A-Z]/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016458 { # XmuValidArea: Xmu
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016459 return $1;
16460 }
16461 elsif($Str=~/\A([_]*[a-z]+)[A-Z]/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016462 { # snfReadFont: snf
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016463 return $1;
16464 }
16465 elsif($Str=~/\A([_]*[A-Z]{2,})[A-Z][a-z]+([A-Z][a-z]+|\Z)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016466 { # XRRTimes: XRR
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016467 return $1;
16468 }
16469 elsif($Str=~/\A([_]*[a-z0-9]{2,}_)[a-z]+/i)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016470 { # alarm_event_add: alarm_
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016471 return $1;
16472 }
16473 elsif($Str=~/\A(([a-z])\2{1,})/i)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016474 { # ffopen
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016475 return $1;
16476 }
16477 else {
16478 return "";
16479 }
16480}
16481
16482sub problem_title($)
16483{
16484 if($_[0]==1) {
16485 return "1 problem";
16486 }
16487 else {
16488 return $_[0]." problems";
16489 }
16490}
16491
16492sub warning_title($)
16493{
16494 if($_[0]==1) {
16495 return "1 warning";
16496 }
16497 else {
16498 return $_[0]." warnings";
16499 }
16500}
16501
16502sub createSymbolsList($$$$$)
16503{
16504 my ($DPath, $SaveTo, $LName, $LVersion, $ArchName) = @_;
16505 read_ABI_Dump(1, $DPath);
16506 if(not $CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016507 prepareSymbols(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016508 }
16509 my %SymbolHeaderLib = ();
16510 my $Total = 0;
16511 # Get List
16512 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
16513 {
16514 if(not link_symbol($Symbol, 1, "-Deps"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016515 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016516 next;
16517 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016518 if(not symbolFilter($Symbol, 1, "Public", "Binary"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016519 { # skip other symbols
16520 next;
16521 }
16522 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
16523 if(not $HeaderName)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016524 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016525 next;
16526 }
16527 my $DyLib = $Symbol_Library{1}{$Symbol};
16528 if(not $DyLib)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016529 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016530 next;
16531 }
16532 $SymbolHeaderLib{$HeaderName}{$DyLib}{$Symbol} = 1;
16533 $Total+=1;
16534 }
16535 # Draw List
16536 my $SYMBOLS_LIST = "<h1>Public symbols in <span style='color:Blue;'>$LName</span> (<span style='color:Red;'>$LVersion</span>)";
16537 $SYMBOLS_LIST .= " on <span style='color:Blue;'>".showArch($ArchName)."</span><br/>Total: $Total</h1><br/>";
16538 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%SymbolHeaderLib))
16539 {
16540 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$SymbolHeaderLib{$HeaderName}}))
16541 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016542 my %NS_Symbol = ();
16543 foreach my $Symbol (keys(%{$SymbolHeaderLib{$HeaderName}{$DyLib}})) {
16544 $NS_Symbol{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
16545 }
16546 foreach my $NameSpace (sort keys(%NS_Symbol))
16547 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016548 $SYMBOLS_LIST .= getTitle($HeaderName, $DyLib, $NameSpace);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016549 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NS_Symbol{$NameSpace}});
16550 foreach my $Symbol (@SortedInterfaces)
16551 {
16552 my $SubReport = "";
16553 my $Signature = get_Signature($Symbol, 1);
16554 if($NameSpace) {
16555 $Signature=~s/(\W|\A)\Q$NameSpace\E\:\:(\w)/$1$2/g;
16556 }
16557 if($Symbol=~/\A(_Z|\?)/)
16558 {
16559 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016560 $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 +040016561 }# report_added
16562 else {
16563 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
16564 }
16565 }
16566 else
16567 {
16568 if($Signature) {
16569 $SubReport = "<span class='iname'>".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
16570 }
16571 else {
16572 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
16573 }
16574 }
16575 $SYMBOLS_LIST .= $SubReport;
16576 }
16577 }
16578 $SYMBOLS_LIST .= "<br/>\n";
16579 }
16580 }
16581 # Clear Info
16582 (%TypeInfo, %SymbolInfo, %Library_Symbol,
16583 %DepSymbols, %SymVer, %Tid_TDid, %SkipTypes,
16584 %SkipSymbols, %NestedNameSpaces, %ClassMethods,
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016585 %AllocableClass, %ClassNames, %CompleteSignature,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016586 %SkipNameSpaces, %Symbol_Library) = ();
16587 ($Content_Counter, $ContentID) = (0, 0);
16588 # Print Report
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016589 my $CssStyles = readModule("Styles", "SymbolsList.css");
16590 my $JScripts = readModule("Scripts", "Sections.js");
16591 $SYMBOLS_LIST = "<a name='Top'></a>".$SYMBOLS_LIST.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016592 my $Title = "$LName: public symbols";
16593 my $Keywords = "$LName, API, symbols";
16594 my $Description = "List of symbols in $LName ($LVersion) on ".showArch($ArchName);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016595 $SYMBOLS_LIST = composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016596 <body><div>\n$SYMBOLS_LIST</div>
16597 <br/><br/><hr/>\n".getReportFooter($LName)."
16598 <div style='height:999px;'></div></body></html>";
16599 writeFile($SaveTo, $SYMBOLS_LIST);
16600}
16601
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016602sub readModule($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016603{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016604 my ($Module, $Name) = @_;
16605 my $Path = $MODULES_DIR."/Internals/$Module/".$Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016606 if(not -f $Path) {
16607 exitStatus("Module_Error", "can't access \'$Path\'");
16608 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016609 return readFile($Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016610}
16611
16612sub is_target_lib($)
16613{
16614 my $LName = $_[0];
16615 if($TargetLibraryName
16616 and $LName!~/\Q$TargetLibraryName\E/) {
16617 return 0;
16618 }
16619 if(keys(%TargetLibs)
16620 and not $TargetLibs{$LName}
16621 and not $TargetLibs{parse_libname($LName, "name+ext", $OStarget)}) {
16622 return 0;
16623 }
16624 return 1;
16625}
16626
16627sub is_target_header($)
16628{ # --header, --headers-list
16629 if(keys(%{$TargetHeaders{1}})
16630 or keys(%{$TargetHeaders{2}}))
16631 {
16632 if(not $TargetHeaders{1}{$_[0]}
16633 and not $TargetHeaders{2}{$_[0]})
16634 {
16635 return 0;
16636 }
16637 }
16638 return 1;
16639}
16640
16641sub checkVersionNum($$)
16642{
16643 my ($LibVersion, $Path) = @_;
16644 if(my $VerNum = $TargetVersion{$LibVersion}) {
16645 return $VerNum;
16646 }
16647 my $UsedAltDescr = 0;
16648 foreach my $Part (split(/\s*,\s*/, $Path))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016649 { # try to get version string from file path
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016650 next if($Part=~/\.xml\Z/i);
16651 next if(isDump($Part));
16652 if(parse_libname($Part, "version", $OStarget)
16653 or is_header($Part, 2, $LibVersion) or -d $Part)
16654 {
16655 $UsedAltDescr = 1;
16656 if(my $VerNum = readStringVersion($Part))
16657 {
16658 $TargetVersion{$LibVersion} = $VerNum;
16659 if($DumpAPI) {
16660 printMsg("WARNING", "setting version number to $VerNum (use -vnum <num> option to change it)");
16661 }
16662 else {
16663 printMsg("WARNING", "setting ".($LibVersion==1?"1st":"2nd")." version number to \"$VerNum\" (use -v$LibVersion <num> option to change it)");
16664 }
16665 return $TargetVersion{$LibVersion};
16666 }
16667 }
16668 }
16669 if($UsedAltDescr)
16670 {
16671 if($DumpAPI) {
16672 exitStatus("Error", "version number is not set (use -vnum <num> option)");
16673 }
16674 else {
16675 exitStatus("Error", ($LibVersion==1?"1st":"2nd")." version number is not set (use -v$LibVersion <num> option)");
16676 }
16677 }
16678}
16679
16680sub readStringVersion($)
16681{
16682 my $Str = $_[0];
16683 return "" if(not $Str);
16684 $Str=~s/\Q$TargetLibraryName\E//g;
16685 if($Str=~/(\/|\\|\w|\A)[\-\_]*(\d+[\d\.\-]+\d+|\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016686 { # .../libssh-0.4.0/...
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016687 return $2;
16688 }
16689 elsif(my $V = parse_libname($Str, "version", $OStarget)) {
16690 return $V;
16691 }
16692 return "";
16693}
16694
16695sub readLibs($)
16696{
16697 my $LibVersion = $_[0];
16698 if($OStarget eq "windows")
16699 { # dumpbin.exe will crash
16700 # without VS Environment
16701 check_win32_env();
16702 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016703 readSymbols($LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016704 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
16705 translateSymbols(keys(%{$DepSymbols{$LibVersion}}), $LibVersion);
16706}
16707
16708sub dump_sorting($)
16709{
16710 my $hash = $_[0];
16711 return [] if(not $hash or not keys(%{$hash}));
16712 if((keys(%{$hash}))[0]=~/\A\d+\Z/) {
16713 return [sort {int($a) <=> int($b)} keys(%{$hash})];
16714 }
16715 else {
16716 return [sort {$a cmp $b} keys(%{$hash})];
16717 }
16718}
16719
16720sub printMsg($$)
16721{
16722 my ($Type, $Msg) = @_;
16723 if($Type!~/\AINFO/) {
16724 $Msg = $Type.": ".$Msg;
16725 }
16726 if($Type!~/_C\Z/) {
16727 $Msg .= "\n";
16728 }
16729 if($Quiet)
16730 { # --quiet option
16731 appendFile($COMMON_LOG_PATH, $Msg);
16732 }
16733 else
16734 {
16735 if($Type eq "ERROR") {
16736 print STDERR $Msg;
16737 }
16738 else {
16739 print $Msg;
16740 }
16741 }
16742}
16743
16744sub exitStatus($$)
16745{
16746 my ($Code, $Msg) = @_;
16747 printMsg("ERROR", $Msg);
16748 exit($ERROR_CODE{$Code});
16749}
16750
16751sub exitReport()
16752{ # the tool has run without any errors
16753 printReport();
16754 if($COMPILE_ERRORS)
16755 { # errors in headers may add false positives/negatives
16756 exit($ERROR_CODE{"Compile_Error"});
16757 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016758 if($BinaryOnly and $RESULT{"Binary"}{"Problems"})
16759 { # --binary
16760 exit($ERROR_CODE{"Incompatible"});
16761 }
16762 elsif($SourceOnly and $RESULT{"Source"}{"Problems"})
16763 { # --source
16764 exit($ERROR_CODE{"Incompatible"});
16765 }
16766 elsif($RESULT{"Source"}{"Problems"}
16767 or $RESULT{"Binary"}{"Problems"})
16768 { # default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016769 exit($ERROR_CODE{"Incompatible"});
16770 }
16771 else {
16772 exit($ERROR_CODE{"Compatible"});
16773 }
16774}
16775
16776sub readRules($)
16777{
16778 my $Kind = $_[0];
16779 if(not -f $RULES_PATH{$Kind}) {
16780 exitStatus("Module_Error", "can't access \'".$RULES_PATH{$Kind}."\'");
16781 }
16782 my $Content = readFile($RULES_PATH{$Kind});
16783 while(my $Rule = parseTag(\$Content, "rule"))
16784 {
16785 my $RId = parseTag(\$Rule, "id");
16786 my @Properties = ("Severity", "Change", "Effect", "Overcome", "Kind");
16787 foreach my $Prop (@Properties) {
16788 if(my $Value = parseTag(\$Rule, lc($Prop)))
16789 {
16790 $Value=~s/\n[ ]*//;
16791 $CompatRules{$Kind}{$RId}{$Prop} = $Value;
16792 }
16793 }
16794 if($CompatRules{$Kind}{$RId}{"Kind"}=~/\A(Symbols|Parameters)\Z/) {
16795 $CompatRules{$Kind}{$RId}{"Kind"} = "Symbols";
16796 }
16797 else {
16798 $CompatRules{$Kind}{$RId}{"Kind"} = "Types";
16799 }
16800 }
16801}
16802
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016803sub getReportPath($)
16804{
16805 my $Level = $_[0];
16806 my $Dir = "compat_reports/$TargetLibraryName/".$Descriptor{1}{"Version"}."_to_".$Descriptor{2}{"Version"};
16807 if($Level eq "Binary")
16808 {
16809 if($BinaryReportPath)
16810 { # --bin-report-path
16811 return $BinaryReportPath;
16812 }
16813 elsif($OutputReportPath)
16814 { # --report-path
16815 return $OutputReportPath;
16816 }
16817 else
16818 { # default
16819 return $Dir."/abi_compat_report.$ReportFormat";
16820 }
16821 }
16822 elsif($Level eq "Source")
16823 {
16824 if($SourceReportPath)
16825 { # --src-report-path
16826 return $SourceReportPath;
16827 }
16828 elsif($OutputReportPath)
16829 { # --report-path
16830 return $OutputReportPath;
16831 }
16832 else
16833 { # default
16834 return $Dir."/src_compat_report.$ReportFormat";
16835 }
16836 }
16837 else
16838 {
16839 if($OutputReportPath)
16840 { # --report-path
16841 return $OutputReportPath;
16842 }
16843 else
16844 { # default
16845 return $Dir."/compat_report.$ReportFormat";
16846 }
16847 }
16848}
16849
16850sub printStatMsg($)
16851{
16852 my $Level = $_[0];
16853 printMsg("INFO", "total \"$Level\" compatibility problems: ".$RESULT{$Level}{"Problems"}.", warnings: ".$RESULT{$Level}{"Warnings"});
16854}
16855
16856sub listAffected($)
16857{
16858 my $Level = $_[0];
16859 my $List = "";
16860 foreach (keys(%{$TotalAffected{$Level}}))
16861 {
16862 if($StrictCompat and $TotalAffected{$Level}{$_} eq "Low")
16863 { # skip "Low"-severity problems
16864 next;
16865 }
16866 $List .= "$_\n";
16867 }
16868 my $Dir = get_dirname(getReportPath($Level));
16869 if($Level eq "Binary") {
16870 writeFile($Dir."/abi_affected.txt", $List);
16871 }
16872 elsif($Level eq "Source") {
16873 writeFile($Dir."/src_affected.txt", $List);
16874 }
16875}
16876
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016877sub printReport()
16878{
16879 printMsg("INFO", "creating compatibility report ...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016880 createReport();
16881 if($JoinReport or $DoubleReport)
16882 {
16883 if($RESULT{"Binary"}{"Problems"}
16884 or $RESULT{"Source"}{"Problems"}) {
16885 printMsg("INFO", "result: INCOMPATIBLE (Binary: ".$RESULT{"Binary"}{"Affected"}."\%, Source: ".$RESULT{"Source"}{"Affected"}."\%)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016886 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016887 else {
16888 printMsg("INFO", "result: COMPATIBLE");
16889 }
16890 printStatMsg("Binary");
16891 printStatMsg("Source");
16892 if($ListAffected)
16893 { # --list-affected
16894 listAffected("Binary");
16895 listAffected("Source");
16896 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016897 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016898 elsif($BinaryOnly)
16899 {
16900 if($RESULT{"Binary"}{"Problems"}) {
16901 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Binary"}{"Affected"}."\%)");
16902 }
16903 else {
16904 printMsg("INFO", "result: COMPATIBLE");
16905 }
16906 printStatMsg("Binary");
16907 if($ListAffected)
16908 { # --list-affected
16909 listAffected("Binary");
16910 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016911 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016912 elsif($SourceOnly)
16913 {
16914 if($RESULT{"Source"}{"Problems"}) {
16915 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Source"}{"Affected"}."\%)");
16916 }
16917 else {
16918 printMsg("INFO", "result: COMPATIBLE");
16919 }
16920 printStatMsg("Source");
16921 if($ListAffected)
16922 { # --list-affected
16923 listAffected("Source");
16924 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016925 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016926 if($StdOut)
16927 {
16928 if($JoinReport or not $DoubleReport)
16929 { # --join-report, --binary or --source
16930 printMsg("INFO", "compatibility report has been generated to stdout");
16931 }
16932 else
16933 { # default
16934 printMsg("INFO", "compatibility reports have been generated to stdout");
16935 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016936 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016937 else
16938 {
16939 if($JoinReport)
16940 { # --join-report
16941 printMsg("INFO", "see detailed report:\n ".getReportPath("Join"));
16942 }
16943 elsif($DoubleReport)
16944 { # default
16945 printMsg("INFO", "see detailed reports:\n ".getReportPath("Binary")."\n ".getReportPath("Source"));
16946 }
16947 elsif($BinaryOnly)
16948 { # --binary
16949 printMsg("INFO", "see detailed report:\n ".getReportPath("Binary"));
16950 }
16951 elsif($SourceOnly)
16952 { # --source
16953 printMsg("INFO", "see detailed report:\n ".getReportPath("Source"));
16954 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016955 }
16956}
16957
16958sub check_win32_env()
16959{
16960 if(not $ENV{"DevEnvDir"}
16961 or not $ENV{"LIB"}) {
16962 exitStatus("Error", "can't start without VS environment (vsvars32.bat)");
16963 }
16964}
16965
16966sub create_ABI_Dump()
16967{
16968 if(not -e $DumpAPI) {
16969 exitStatus("Access_Error", "can't access \'$DumpAPI\'");
16970 }
16971 # check the archive utilities
16972 if($OSgroup eq "windows")
16973 { # using zip
16974 my $ZipCmd = get_CmdPath("zip");
16975 if(not $ZipCmd) {
16976 exitStatus("Not_Found", "can't find \"zip\"");
16977 }
16978 }
16979 else
16980 { # using tar and gzip
16981 my $TarCmd = get_CmdPath("tar");
16982 if(not $TarCmd) {
16983 exitStatus("Not_Found", "can't find \"tar\"");
16984 }
16985 my $GzipCmd = get_CmdPath("gzip");
16986 if(not $GzipCmd) {
16987 exitStatus("Not_Found", "can't find \"gzip\"");
16988 }
16989 }
16990 my @DParts = split(/\s*,\s*/, $DumpAPI);
16991 foreach my $Part (@DParts)
16992 {
16993 if(not -e $Part) {
16994 exitStatus("Access_Error", "can't access \'$Part\'");
16995 }
16996 }
16997 checkVersionNum(1, $DumpAPI);
16998 foreach my $Part (@DParts)
16999 {
17000 if(isDump($Part)) {
17001 read_ABI_Dump(1, $Part);
17002 }
17003 else {
17004 readDescriptor(1, createDescriptor(1, $Part));
17005 }
17006 }
17007 initLogging(1);
17008 detect_default_paths("inc|lib|bin|gcc"); # complete analysis
17009 if(not $CheckHeadersOnly) {
17010 readLibs(1);
17011 }
17012 if($CheckHeadersOnly) {
17013 setLanguage(1, "C++");
17014 }
17015 if(not $CheckObjectsOnly) {
17016 searchForHeaders(1);
17017 }
17018 $WORD_SIZE{1} = detectWordSize();
17019 if($Descriptor{1}{"Headers"}
17020 and not $Descriptor{1}{"Dump"}) {
17021 readHeaders(1);
17022 }
17023 if($ExtendedCheck)
17024 { # --ext option
17025 addExtension(1);
17026 }
17027 formatDump(1);
17028 if(not keys(%{$SymbolInfo{1}}))
17029 { # check if created dump is valid
17030 if(not $ExtendedCheck and not $CheckObjectsOnly)
17031 {
17032 if($CheckHeadersOnly) {
17033 exitStatus("Empty_Set", "the set of public symbols is empty");
17034 }
17035 else {
17036 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection");
17037 }
17038 }
17039 }
17040 my %HeadersInfo = ();
17041 foreach my $HPath (keys(%{$Registered_Headers{1}}))
17042 { # headers info stored without paths in the dump
17043 $HeadersInfo{$Registered_Headers{1}{$HPath}{"Identity"}} = $Registered_Headers{1}{$HPath}{"Pos"};
17044 }
17045 printMsg("INFO", "creating library ABI dump ...");
17046 my %LibraryABI = (
17047 "TypeInfo" => $TypeInfo{1},
17048 "SymbolInfo" => $SymbolInfo{1},
17049 "Symbols" => $Library_Symbol{1},
17050 "DepSymbols" => $DepSymbols{1},
17051 "SymbolVersion" => $SymVer{1},
17052 "LibraryVersion" => $Descriptor{1}{"Version"},
17053 "LibraryName" => $TargetLibraryName,
17054 "Language" => $COMMON_LANGUAGE{1},
17055 "Tid_TDid" => $Tid_TDid{1},
17056 "SkipTypes" => $SkipTypes{1},
17057 "SkipSymbols" => $SkipSymbols{1},
17058 "SkipNameSpaces" => $SkipNameSpaces{1},
17059 "SkipHeaders" => $SkipHeadersList{1},
17060 "TargetHeaders" => $TargetHeaders{1},
17061 "Headers" => \%HeadersInfo,
17062 "Constants" => $Constants{1},
17063 "NameSpaces" => $NestedNameSpaces{1},
17064 "Target" => $OStarget,
17065 "Arch" => getArch(1),
17066 "WordSize" => $WORD_SIZE{1},
17067 "GccVersion" => get_dumpversion($GCC_PATH),
17068 "ABI_DUMP_VERSION" => $ABI_DUMP_VERSION,
17069 "ABI_COMPLIANCE_CHECKER_VERSION" => $TOOL_VERSION
17070 );
17071 if($ExtendedCheck)
17072 { # --ext option
17073 $LibraryABI{"Mode"} = "Extended";
17074 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017075 if($BinaryOnly)
17076 { # --binary
17077 $LibraryABI{"BinOnly"} = 1;
17078 }
17079 else
17080 { # default
17081 $LibraryABI{"SrcBin"} = 1;
17082 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017083 if($StdOut)
17084 { # --stdout option
17085 print STDOUT Dumper(\%LibraryABI);
17086 printMsg("INFO", "ABI dump has been generated to stdout");
17087 return;
17088 }
17089 else
17090 { # write to gzipped file
17091 my $DumpPath = "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi.".$AR_EXT;
17092 if($OutputDumpPath)
17093 { # user defined path
17094 $DumpPath = $OutputDumpPath;
17095 }
17096 if(not $DumpPath=~s/\Q.$AR_EXT\E\Z//g) {
17097 exitStatus("Error", "the dump path (-dump-path option) should be the path to a *.$AR_EXT file");
17098 }
17099 my ($DDir, $DName) = separate_path($DumpPath);
17100 my $DPath = $TMP_DIR."/".$DName;
17101 mkpath($DDir);
17102 writeFile($DPath, Dumper(\%LibraryABI));
17103 if(not -s $DPath) {
17104 exitStatus("Error", "can't create ABI dump because something is going wrong with the Data::Dumper module");
17105 }
17106 my $Pkg = createArchive($DPath, $DDir);
17107 printMsg("INFO", "library ABI has been dumped to:\n $Pkg");
17108 printMsg("INFO", "you can transfer this dump everywhere and use instead of the ".$Descriptor{1}{"Version"}." version descriptor");
17109 }
17110}
17111
17112sub quickEmptyReports()
17113{ # Quick "empty" reports
17114 # 4 times faster than merging equal dumps
17115 # NOTE: the dump contains the "LibraryVersion" attribute
17116 # if you change the version, then your dump will be different
17117 # OVERCOME: use -v1 and v2 options for comparing dumps
17118 # and don't change version in the XML descriptor (and dumps)
17119 # OVERCOME 2: separate meta info from the dumps in ACC 2.0
17120 if(-s $Descriptor{1}{"Path"} == -s $Descriptor{2}{"Path"})
17121 {
17122 my $FilePath1 = unpackDump($Descriptor{1}{"Path"});
17123 my $FilePath2 = unpackDump($Descriptor{2}{"Path"});
17124 if($FilePath1 and $FilePath2)
17125 {
17126 my $Content = readFile($FilePath1);
17127 if($Content eq readFile($FilePath2))
17128 {
17129 # read a number of headers, libs, symbols and types
17130 my $ABIdump = eval($Content);
17131 if(not $ABIdump) {
17132 exitStatus("Error", "internal error");
17133 }
17134 if(not $ABIdump->{"TypeInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017135 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017136 $ABIdump->{"TypeInfo"} = $ABIdump->{"TypeDescr"};
17137 }
17138 if(not $ABIdump->{"SymbolInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017139 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017140 $ABIdump->{"SymbolInfo"} = $ABIdump->{"FuncDescr"};
17141 }
17142 read_Headers_DumpInfo($ABIdump, 1);
17143 read_Libs_DumpInfo($ABIdump, 1);
17144 read_Machine_DumpInfo($ABIdump, 1);
17145 read_Machine_DumpInfo($ABIdump, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017146
17147 %{$CheckedTypes{"Binary"}} = %{$ABIdump->{"TypeInfo"}};
17148 %{$CheckedTypes{"Source"}} = %{$ABIdump->{"TypeInfo"}};
17149
17150 %{$CheckedSymbols{"Binary"}} = %{$ABIdump->{"SymbolInfo"}};
17151 %{$CheckedSymbols{"Source"}} = %{$ABIdump->{"SymbolInfo"}};
17152
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017153 $Descriptor{1}{"Version"} = $TargetVersion{1}?$TargetVersion{1}:$ABIdump->{"LibraryVersion"};
17154 $Descriptor{2}{"Version"} = $TargetVersion{2}?$TargetVersion{2}:$ABIdump->{"LibraryVersion"};
17155 exitReport();
17156 }
17157 }
17158 }
17159}
17160
17161sub initLogging($)
17162{
17163 my $LibVersion = $_[0];
17164 # create log directory
17165 my ($LOG_DIR, $LOG_FILE) = ("logs/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"}, "log.txt");
17166 if($OutputLogPath{$LibVersion})
17167 { # user-defined by -log-path option
17168 ($LOG_DIR, $LOG_FILE) = separate_path($OutputLogPath{$LibVersion});
17169 }
17170 if($LogMode ne "n") {
17171 mkpath($LOG_DIR);
17172 }
17173 $LOG_PATH{$LibVersion} = get_abs_path($LOG_DIR)."/".$LOG_FILE;
17174 resetLogging($LibVersion);
17175 if($Debug)
17176 { # debug directory
17177 $DEBUG_PATH{$LibVersion} = "debug/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"};
17178 rmtree($DEBUG_PATH{$LibVersion});
17179 }
17180}
17181
17182sub writeLog($$)
17183{
17184 my ($LibVersion, $Msg) = @_;
17185 if($LogMode ne "n") {
17186 appendFile($LOG_PATH{$LibVersion}, $Msg);
17187 }
17188}
17189
17190sub resetLogging($)
17191{
17192 my $LibVersion = $_[0];
17193 if($LogMode!~/a|n/)
17194 { # remove old log
17195 unlink($LOG_PATH{$LibVersion});
17196 }
17197}
17198
17199sub printErrorLog($)
17200{
17201 my $LibVersion = $_[0];
17202 if($LogMode ne "n") {
17203 printMsg("ERROR", "see log for details:\n ".$LOG_PATH{$LibVersion}."\n");
17204 }
17205}
17206
17207sub isDump($)
17208{
17209 if(get_filename($_[0])=~/\A(.+)\.abi(\Q.tar.gz\E|\Q.zip\E|)\Z/)
17210 { # returns a name of package
17211 return $1;
17212 }
17213 return 0;
17214}
17215
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017216sub compareInit()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017217{
17218 # read input XML descriptors or ABI dumps
17219 if(not $Descriptor{1}{"Path"}) {
17220 exitStatus("Error", "-d1 option is not specified");
17221 }
17222 my @DParts1 = split(/\s*,\s*/, $Descriptor{1}{"Path"});
17223 foreach my $Part (@DParts1)
17224 {
17225 if(not -e $Part) {
17226 exitStatus("Access_Error", "can't access \'$Part\'");
17227 }
17228 }
17229 if(not $Descriptor{2}{"Path"}) {
17230 exitStatus("Error", "-d2 option is not specified");
17231 }
17232 my @DParts2 = split(/\s*,\s*/, $Descriptor{2}{"Path"});
17233 foreach my $Part (@DParts2)
17234 {
17235 if(not -e $Part) {
17236 exitStatus("Access_Error", "can't access \'$Part\'");
17237 }
17238 }
17239 detect_default_paths("bin"); # to extract dumps
17240 if($#DParts1==0 and $#DParts2==0
17241 and isDump($Descriptor{1}{"Path"})
17242 and isDump($Descriptor{2}{"Path"}))
17243 { # optimization: equal ABI dumps
17244 quickEmptyReports();
17245 }
17246 checkVersionNum(1, $Descriptor{1}{"Path"});
17247 checkVersionNum(2, $Descriptor{2}{"Path"});
17248 printMsg("INFO", "preparation, please wait ...");
17249 foreach my $Part (@DParts1)
17250 {
17251 if(isDump($Part)) {
17252 read_ABI_Dump(1, $Part);
17253 }
17254 else {
17255 readDescriptor(1, createDescriptor(1, $Part));
17256 }
17257 }
17258 foreach my $Part (@DParts2)
17259 {
17260 if(isDump($Part)) {
17261 read_ABI_Dump(2, $Part);
17262 }
17263 else {
17264 readDescriptor(2, createDescriptor(2, $Part));
17265 }
17266 }
17267 initLogging(1);
17268 initLogging(2);
17269 # check consistency
17270 if(not $Descriptor{1}{"Headers"}
17271 and not $Descriptor{1}{"Libs"}) {
17272 exitStatus("Error", "descriptor d1 does not contain both header files and libraries info");
17273 }
17274 if(not $Descriptor{2}{"Headers"}
17275 and not $Descriptor{2}{"Libs"}) {
17276 exitStatus("Error", "descriptor d2 does not contain both header files and libraries info");
17277 }
17278 if($Descriptor{1}{"Headers"} and not $Descriptor{1}{"Libs"}
17279 and not $Descriptor{2}{"Headers"} and $Descriptor{2}{"Libs"}) {
17280 exitStatus("Error", "can't compare headers with $SLIB_TYPE libraries");
17281 }
17282 elsif(not $Descriptor{1}{"Headers"} and $Descriptor{1}{"Libs"}
17283 and $Descriptor{2}{"Headers"} and not $Descriptor{2}{"Libs"}) {
17284 exitStatus("Error", "can't compare $SLIB_TYPE libraries with headers");
17285 }
17286 if(not $Descriptor{1}{"Headers"}) {
17287 if($CheckHeadersOnly_Opt) {
17288 exitStatus("Error", "can't find header files info in descriptor d1");
17289 }
17290 }
17291 if(not $Descriptor{2}{"Headers"}) {
17292 if($CheckHeadersOnly_Opt) {
17293 exitStatus("Error", "can't find header files info in descriptor d2");
17294 }
17295 }
17296 if(not $Descriptor{1}{"Headers"}
17297 or not $Descriptor{2}{"Headers"}) {
17298 if(not $CheckObjectsOnly_Opt) {
17299 printMsg("WARNING", "comparing $SLIB_TYPE libraries only");
17300 $CheckObjectsOnly = 1;
17301 }
17302 }
17303 if(not $Descriptor{1}{"Libs"}) {
17304 if($CheckObjectsOnly_Opt) {
17305 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d1");
17306 }
17307 }
17308 if(not $Descriptor{2}{"Libs"}) {
17309 if($CheckObjectsOnly_Opt) {
17310 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d2");
17311 }
17312 }
17313 if(not $Descriptor{1}{"Libs"}
17314 or not $Descriptor{2}{"Libs"})
17315 { # comparing standalone header files
17316 # comparing ABI dumps created with --headers-only
17317 if(not $CheckHeadersOnly_Opt)
17318 {
17319 printMsg("WARNING", "checking headers only");
17320 $CheckHeadersOnly = 1;
17321 }
17322 }
17323 if($UseDumps)
17324 { # --use-dumps
17325 # parallel processing
17326 my $pid = fork();
17327 if($pid)
17328 { # dump on two CPU cores
17329 my @PARAMS = ("-dump", $Descriptor{1}{"Path"}, "-l", $TargetLibraryName);
17330 if($RelativeDirectory{1}) {
17331 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{1});
17332 }
17333 if($OutputLogPath{1}) {
17334 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{1});
17335 }
17336 if($CrossGcc) {
17337 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
17338 }
17339 if($Debug) {
17340 @PARAMS = (@PARAMS, "-debug");
17341 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040017342 if($Quiet)
17343 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017344 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040017345 @PARAMS = (@PARAMS, "-logging-mode", "a");
17346 }
17347 elsif($LogMode and $LogMode ne "w")
17348 { # "w" is default
17349 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017350 }
17351 if($ExtendedCheck) {
17352 @PARAMS = (@PARAMS, "-extended");
17353 }
17354 if($UserLang) {
17355 @PARAMS = (@PARAMS, "-lang", $UserLang);
17356 }
17357 if($TargetVersion{1}) {
17358 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{1});
17359 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017360 system("perl", $0, @PARAMS);
17361 if($?) {
17362 exit(1);
17363 }
17364 }
17365 else
17366 { # child
17367 my @PARAMS = ("-dump", $Descriptor{2}{"Path"}, "-l", $TargetLibraryName);
17368 if($RelativeDirectory{2}) {
17369 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{2});
17370 }
17371 if($OutputLogPath{2}) {
17372 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{2});
17373 }
17374 if($CrossGcc) {
17375 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
17376 }
17377 if($Debug) {
17378 @PARAMS = (@PARAMS, "-debug");
17379 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040017380 if($Quiet)
17381 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017382 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040017383 @PARAMS = (@PARAMS, "-logging-mode", "a");
17384 }
17385 elsif($LogMode and $LogMode ne "w")
17386 { # "w" is default
17387 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017388 }
17389 if($ExtendedCheck) {
17390 @PARAMS = (@PARAMS, "-extended");
17391 }
17392 if($UserLang) {
17393 @PARAMS = (@PARAMS, "-lang", $UserLang);
17394 }
17395 if($TargetVersion{2}) {
17396 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{2});
17397 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017398 system("perl", $0, @PARAMS);
17399 if($?) {
17400 exit(1);
17401 }
17402 else {
17403 exit(0);
17404 }
17405 }
17406 waitpid($pid, 0);
17407 my @CMP_PARAMS = ("-l", $TargetLibraryName);
17408 @CMP_PARAMS = (@CMP_PARAMS, "-d1", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi.$AR_EXT");
17409 @CMP_PARAMS = (@CMP_PARAMS, "-d2", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{2}{"Version"}.".abi.$AR_EXT");
17410 if($TargetLibraryFName ne $TargetLibraryName) {
17411 @CMP_PARAMS = (@CMP_PARAMS, "-l-full", $TargetLibraryFName);
17412 }
17413 if($ShowRetVal) {
17414 @CMP_PARAMS = (@CMP_PARAMS, "-show-retval");
17415 }
17416 if($CrossGcc) {
17417 @CMP_PARAMS = (@CMP_PARAMS, "-cross-gcc", $CrossGcc);
17418 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040017419 if($Quiet)
17420 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017421 @CMP_PARAMS = (@CMP_PARAMS, "-quiet");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017422 @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", "a");
17423 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040017424 elsif($LogMode and $LogMode ne "w")
17425 { # "w" is default
17426 @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", $LogMode);
17427 }
17428 if($ReportFormat and $ReportFormat ne "html")
17429 { # HTML is default format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017430 @CMP_PARAMS = (@CMP_PARAMS, "-report-format", $ReportFormat);
17431 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017432 if($OutputReportPath) {
17433 @CMP_PARAMS = (@CMP_PARAMS, "-report-path", $OutputReportPath);
17434 }
17435 if($BinaryReportPath) {
17436 @CMP_PARAMS = (@CMP_PARAMS, "-bin-report-path", $BinaryReportPath);
17437 }
17438 if($SourceReportPath) {
17439 @CMP_PARAMS = (@CMP_PARAMS, "-src-report-path", $SourceReportPath);
17440 }
17441 if($LoggingPath) {
17442 @CMP_PARAMS = (@CMP_PARAMS, "-log-path", $LoggingPath);
17443 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017444 system("perl", $0, @CMP_PARAMS);
17445 exit($?>>8);
17446 }
17447 if(not $Descriptor{1}{"Dump"}
17448 or not $Descriptor{2}{"Dump"})
17449 { # need GCC toolchain to analyze
17450 # header files and libraries
17451 detect_default_paths("inc|lib|gcc");
17452 }
17453 if(not $Descriptor{1}{"Dump"})
17454 {
17455 if(not $CheckHeadersOnly) {
17456 readLibs(1);
17457 }
17458 if($CheckHeadersOnly) {
17459 setLanguage(1, "C++");
17460 }
17461 if(not $CheckObjectsOnly) {
17462 searchForHeaders(1);
17463 }
17464 $WORD_SIZE{1} = detectWordSize();
17465 }
17466 if(not $Descriptor{2}{"Dump"})
17467 {
17468 if(not $CheckHeadersOnly) {
17469 readLibs(2);
17470 }
17471 if($CheckHeadersOnly) {
17472 setLanguage(2, "C++");
17473 }
17474 if(not $CheckObjectsOnly) {
17475 searchForHeaders(2);
17476 }
17477 $WORD_SIZE{2} = detectWordSize();
17478 }
17479 if($WORD_SIZE{1} ne $WORD_SIZE{2})
17480 { # support for old ABI dumps
17481 # try to synch different WORD sizes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017482 if(not checkDumpVersion(1, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017483 {
17484 $WORD_SIZE{1} = $WORD_SIZE{2};
17485 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{2}." bytes");
17486 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017487 elsif(not checkDumpVersion(2, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017488 {
17489 $WORD_SIZE{2} = $WORD_SIZE{1};
17490 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{1}." bytes");
17491 }
17492 }
17493 elsif(not $WORD_SIZE{1}
17494 and not $WORD_SIZE{2})
17495 { # support for old ABI dumps
17496 $WORD_SIZE{1} = 4;
17497 $WORD_SIZE{2} = 4;
17498 }
17499 if($Descriptor{1}{"Dump"})
17500 { # support for old ABI dumps
17501 prepareTypes(1);
17502 }
17503 if($Descriptor{2}{"Dump"})
17504 { # support for old ABI dumps
17505 prepareTypes(2);
17506 }
17507 if($AppPath and not keys(%{$Symbol_Library{1}})) {
17508 printMsg("WARNING", "the application ".get_filename($AppPath)." has no symbols imported from the $SLIB_TYPE libraries");
17509 }
17510 # started to process input data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017511 if(not $CheckObjectsOnly)
17512 {
17513 if($Descriptor{1}{"Headers"}
17514 and not $Descriptor{1}{"Dump"}) {
17515 readHeaders(1);
17516 }
17517 if($Descriptor{2}{"Headers"}
17518 and not $Descriptor{2}{"Dump"}) {
17519 readHeaders(2);
17520 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017521 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017522 prepareSymbols(1);
17523 prepareSymbols(2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017524
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017525 %SymbolInfo = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017526
17527 # Virtual Tables
17528 registerVTable(1);
17529 registerVTable(2);
17530
17531 if(not checkDumpVersion(1, "1.22")
17532 and checkDumpVersion(2, "1.22"))
17533 { # support for old ABI dumps
17534 foreach my $ClassName (keys(%{$VirtualTable{2}}))
17535 {
17536 if($ClassName=~/</)
17537 { # templates
17538 if(not defined $VirtualTable{1}{$ClassName})
17539 { # synchronize
17540 delete($VirtualTable{2}{$ClassName});
17541 }
17542 }
17543 }
17544 }
17545
17546 registerOverriding(1);
17547 registerOverriding(2);
17548
17549 setVirtFuncPositions(1);
17550 setVirtFuncPositions(2);
17551
17552 # Other
17553 addParamNames(1);
17554 addParamNames(2);
17555
17556 detectChangedTypedefs();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017557}
17558
17559sub compareAPIs($)
17560{
17561 my $Level = $_[0];
17562 readRules($Level);
17563 if($Level eq "Binary") {
17564 printMsg("INFO", "comparing ABIs ...");
17565 }
17566 else {
17567 printMsg("INFO", "comparing APIs ...");
17568 }
17569 if($CheckHeadersOnly
17570 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017571 { # added/removed in headers
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017572 detectAdded_H($Level);
17573 detectRemoved_H($Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017574 }
17575 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017576 { # added/removed in libs
17577 detectAdded($Level);
17578 detectRemoved($Level);
17579 }
17580 if(not $CheckObjectsOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017581 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017582 mergeSignatures($Level);
17583 if(keys(%{$CheckedSymbols{$Level}})) {
17584 mergeConstants($Level);
17585 }
17586 }
17587 if($CheckHeadersOnly
17588 or $Level eq "Source")
17589 { # added/removed in headers
17590 mergeHeaders($Level);
17591 }
17592 else
17593 { # added/removed in libs
17594 mergeLibs($Level);
17595 if($CheckImpl
17596 and $Level eq "Binary") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017597 mergeImpl();
17598 }
17599 }
17600}
17601
17602sub optimize_set(@)
17603{
17604 my %Included = ();
17605 foreach my $Path (@_)
17606 {
17607 detect_header_includes($Path, 1);
17608 foreach my $Include (keys(%{$Header_Includes{1}{$Path}})) {
17609 $Included{get_filename($Include)}{$Include}=1;
17610 }
17611 }
17612 my @Res = ();
17613 foreach my $Path (@_)
17614 {
17615 my $Add = 1;
17616 foreach my $Inc (keys(%{$Included{get_filename($Path)}}))
17617 {
17618 if($Path=~/\/\Q$Inc\E\Z/)
17619 {
17620 $Add = 0;
17621 last;
17622 }
17623 }
17624 if($Add) {
17625 push(@Res, $Path);
17626 }
17627 }
17628 return @Res;
17629}
17630
17631sub writeOpts()
17632{
17633 my %Opts = (
17634 "OStarget"=>$OStarget,
17635 "Debug"=>$Debug,
17636 "Quiet"=>$Quiet,
17637 "LogMode"=>$LogMode,
17638 "CheckHeadersOnly"=>$CheckHeadersOnly,
17639
17640 "SystemRoot"=>$SystemRoot,
17641 "MODULES_DIR"=>$MODULES_DIR,
17642 "GCC_PATH"=>$GCC_PATH,
17643 "TargetSysInfo"=>$TargetSysInfo,
17644 "CrossPrefix"=>$CrossPrefix,
17645 "TargetLibraryName"=>$TargetLibraryName,
17646 "CrossGcc"=>$CrossGcc,
17647 "UseStaticLibs"=>$UseStaticLibs,
17648 "NoStdInc"=>$NoStdInc
17649 );
17650 return \%Opts;
17651}
17652
17653sub get_CoreError($)
17654{
17655 my %CODE_ERROR = reverse(%ERROR_CODE);
17656 return $CODE_ERROR{$_[0]};
17657}
17658
17659sub scenario()
17660{
17661 if($StdOut)
17662 { # enable quiet mode
17663 $Quiet = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017664 $JoinReport = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017665 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040017666 if(not $LogMode)
17667 { # default
17668 $LogMode = "w";
17669 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017670 if($UserLang)
17671 { # --lang=C++
17672 $UserLang = uc($UserLang);
17673 $COMMON_LANGUAGE{1}=$UserLang;
17674 $COMMON_LANGUAGE{2}=$UserLang;
17675 }
17676 if($LoggingPath)
17677 {
17678 $OutputLogPath{1} = $LoggingPath;
17679 $OutputLogPath{2} = $LoggingPath;
17680 if($Quiet) {
17681 $COMMON_LOG_PATH = $LoggingPath;
17682 }
17683 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017684 if($BinaryOnly and $SourceOnly)
17685 { # both --binary and --source
17686 # is the default mode
17687 $DoubleReport = 1;
17688 $JoinReport = 0;
17689 $BinaryOnly = 0;
17690 $SourceOnly = 0;
17691 if($OutputReportPath)
17692 { # --report-path
17693 $DoubleReport = 0;
17694 $JoinReport = 1;
17695 }
17696 }
17697 elsif($BinaryOnly or $SourceOnly)
17698 { # --binary or --source
17699 $DoubleReport = 0;
17700 $JoinReport = 0;
17701 }
17702 if($UseXML)
17703 { # --xml option
17704 $ReportFormat = "xml";
17705 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017706 if($ReportFormat)
17707 { # validate
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017708 $ReportFormat = lc($ReportFormat);
17709 if($ReportFormat!~/\A(xml|html|htm)\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017710 exitStatus("Error", "unknown format \'$ReportFormat\'");
17711 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017712 if($ReportFormat eq "htm")
17713 { # HTM == HTML
17714 $ReportFormat = "html";
17715 }
17716 elsif($ReportFormat eq "xml")
17717 { # --report-format=XML equal to --xml
17718 $UseXML = 1;
17719 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017720 }
17721 else
17722 { # default: HTML
17723 $ReportFormat = "html";
17724 }
17725 if($Quiet and $LogMode!~/a|n/)
17726 { # --quiet log
17727 if(-f $COMMON_LOG_PATH) {
17728 unlink($COMMON_LOG_PATH);
17729 }
17730 }
17731 if($TestTool and $UseDumps)
17732 { # --test && --use-dumps == --test-dump
17733 $TestDump = 1;
17734 }
17735 if($Help) {
17736 HELP_MESSAGE();
17737 exit(0);
17738 }
17739 if($InfoMsg) {
17740 INFO_MESSAGE();
17741 exit(0);
17742 }
17743 if($ShowVersion) {
17744 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.");
17745 exit(0);
17746 }
17747 if($DumpVersion) {
17748 printMsg("INFO", $TOOL_VERSION);
17749 exit(0);
17750 }
17751 if($ExtendedCheck) {
17752 $CheckHeadersOnly = 1;
17753 }
17754 if($SystemRoot_Opt)
17755 { # user defined root
17756 if(not -e $SystemRoot_Opt) {
17757 exitStatus("Access_Error", "can't access \'$SystemRoot\'");
17758 }
17759 $SystemRoot = $SystemRoot_Opt;
17760 $SystemRoot=~s/[\/]+\Z//g;
17761 if($SystemRoot) {
17762 $SystemRoot = get_abs_path($SystemRoot);
17763 }
17764 }
17765 $Data::Dumper::Sortkeys = 1;
17766 # FIXME: can't pass \&dump_sorting - cause a segfault sometimes
17767 # $Data::Dumper::Sortkeys = \&dump_sorting;
17768 if($TargetLibsPath)
17769 {
17770 if(not -f $TargetLibsPath) {
17771 exitStatus("Access_Error", "can't access file \'$TargetLibsPath\'");
17772 }
17773 foreach my $Lib (split(/\s*\n\s*/, readFile($TargetLibsPath))) {
17774 $TargetLibs{$Lib} = 1;
17775 }
17776 }
17777 if($TargetHeadersPath)
17778 { # --headers-list
17779 if(not -f $TargetHeadersPath) {
17780 exitStatus("Access_Error", "can't access file \'$TargetHeadersPath\'");
17781 }
17782 foreach my $Header (split(/\s*\n\s*/, readFile($TargetHeadersPath)))
17783 {
17784 $TargetHeaders{1}{$Header} = 1;
17785 $TargetHeaders{2}{$Header} = 1;
17786 }
17787 }
17788 if($TargetHeader)
17789 { # --header
17790 $TargetHeaders{1}{$TargetHeader} = 1;
17791 $TargetHeaders{2}{$TargetHeader} = 1;
17792 }
17793 if($TestTool
17794 or $TestDump)
17795 { # --test, --test-dump
17796 detect_default_paths("bin|gcc"); # to compile libs
17797 loadModule("RegTests");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017798 testTool($TestDump, $Debug, $Quiet, $ExtendedCheck,
17799 $LogMode, $ReportFormat, $LIB_EXT, $GCC_PATH, $Browse);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017800 exit(0);
17801 }
17802 if($DumpSystem)
17803 { # --dump-system
17804 loadModule("SysCheck");
17805 if($DumpSystem=~/\.xml\Z/)
17806 { # system XML descriptor
17807 if(not -f $DumpSystem) {
17808 exitStatus("Access_Error", "can't access file \'$DumpSystem\'");
17809 }
17810 my $Ret = readSystemDescriptor(readFile($DumpSystem));
17811 foreach (@{$Ret->{"Tools"}}) {
17812 $SystemPaths{"bin"}{$_} = 1;
17813 $TargetTools{$_}=1;
17814 }
17815 if($Ret->{"CrossPrefix"}) {
17816 $CrossPrefix = $Ret->{"CrossPrefix"};
17817 }
17818 }
17819 elsif($SystemRoot_Opt)
17820 { # -sysroot "/" option
17821 # default target: /usr/lib, /usr/include
17822 # search libs: /usr/lib and /lib
17823 if(not -e $SystemRoot."/usr/lib") {
17824 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/lib'");
17825 }
17826 if(not -e $SystemRoot."/lib") {
17827 exitStatus("Access_Error", "can't access '".$SystemRoot."/lib'");
17828 }
17829 if(not -e $SystemRoot."/usr/include") {
17830 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/include'");
17831 }
17832 readSystemDescriptor("
17833 <name>
17834 $DumpSystem
17835 </name>
17836 <headers>
17837 $SystemRoot/usr/include
17838 </headers>
17839 <libs>
17840 $SystemRoot/usr/lib
17841 </libs>
17842 <search_libs>
17843 $SystemRoot/lib
17844 </search_libs>");
17845 }
17846 else {
17847 exitStatus("Error", "-sysroot <dirpath> option should be specified, usually it's \"/\"");
17848 }
17849 detect_default_paths("bin|gcc"); # to check symbols
17850 if($OStarget eq "windows")
17851 { # to run dumpbin.exe
17852 # and undname.exe
17853 check_win32_env();
17854 }
17855 dumpSystem(writeOpts());
17856 exit(0);
17857 }
17858 if($CmpSystems)
17859 { # --cmp-systems
17860 detect_default_paths("bin"); # to extract dumps
17861 loadModule("SysCheck");
17862 cmpSystems($Descriptor{1}{"Path"}, $Descriptor{2}{"Path"}, writeOpts());
17863 exit(0);
17864 }
17865 if($GenerateTemplate) {
17866 generateTemplate();
17867 exit(0);
17868 }
17869 if(not $TargetLibraryName) {
17870 exitStatus("Error", "library name is not selected (option -l <name>)");
17871 }
17872 else
17873 { # validate library name
17874 if($TargetLibraryName=~/[\*\/\\]/) {
17875 exitStatus("Error", "\"\\\", \"\/\" and \"*\" symbols are not allowed in the library name");
17876 }
17877 }
17878 if(not $TargetLibraryFName) {
17879 $TargetLibraryFName = $TargetLibraryName;
17880 }
17881 if($CheckHeadersOnly_Opt and $CheckObjectsOnly_Opt) {
17882 exitStatus("Error", "you can't specify both -headers-only and -objects-only options at the same time");
17883 }
17884 if($SymbolsListPath)
17885 {
17886 if(not -f $SymbolsListPath) {
17887 exitStatus("Access_Error", "can't access file \'$SymbolsListPath\'");
17888 }
17889 foreach my $Interface (split(/\s*\n\s*/, readFile($SymbolsListPath))) {
17890 $SymbolsList{$Interface} = 1;
17891 }
17892 }
17893 if($SkipHeadersPath)
17894 {
17895 if(not -f $SkipHeadersPath) {
17896 exitStatus("Access_Error", "can't access file \'$SkipHeadersPath\'");
17897 }
17898 foreach my $Path (split(/\s*\n\s*/, readFile($SkipHeadersPath)))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017899 { # register for both versions
17900 $SkipHeadersList{1}{$Path} = 1;
17901 $SkipHeadersList{2}{$Path} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017902 my ($CPath, $Type) = classifyPath($Path);
17903 $SkipHeaders{1}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017904 $SkipHeaders{2}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017905 }
17906 }
17907 if($ParamNamesPath)
17908 {
17909 if(not -f $ParamNamesPath) {
17910 exitStatus("Access_Error", "can't access file \'$ParamNamesPath\'");
17911 }
17912 foreach my $Line (split(/\n/, readFile($ParamNamesPath)))
17913 {
17914 if($Line=~s/\A(\w+)\;//)
17915 {
17916 my $Interface = $1;
17917 if($Line=~/;(\d+);/) {
17918 while($Line=~s/(\d+);(\w+)//) {
17919 $AddIntParams{$Interface}{$1}=$2;
17920 }
17921 }
17922 else {
17923 my $Num = 0;
17924 foreach my $Name (split(/;/, $Line)) {
17925 $AddIntParams{$Interface}{$Num++}=$Name;
17926 }
17927 }
17928 }
17929 }
17930 }
17931 if($AppPath)
17932 {
17933 if(not -f $AppPath) {
17934 exitStatus("Access_Error", "can't access file \'$AppPath\'");
17935 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017936 foreach my $Interface (readSymbols_App($AppPath)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017937 $SymbolsList_App{$Interface} = 1;
17938 }
17939 }
17940 if($DumpAPI)
17941 { # --dump-abi
17942 # make an API dump
17943 create_ABI_Dump();
17944 exit($COMPILE_ERRORS);
17945 }
17946 # default: compare APIs
17947 # -d1 <path>
17948 # -d2 <path>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017949 compareInit();
17950 if($JoinReport or $DoubleReport)
17951 {
17952 compareAPIs("Binary");
17953 compareAPIs("Source");
17954 }
17955 elsif($BinaryOnly) {
17956 compareAPIs("Binary");
17957 }
17958 elsif($SourceOnly) {
17959 compareAPIs("Source");
17960 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017961 exitReport();
17962}
17963
17964scenario();