blob: 61b3bf8172e1941f8333330d3b640ef236d4f6cc [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;
56use Config;
57
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
6421 "arpa/inet.h" => ["fw_src", "ip_src"]
6422 );
6423 my %AutoPreamble = ();
6424 foreach (keys(%HeaderElems)) {
6425 foreach my $Elem (@{$HeaderElems{$_}}) {
6426 $AutoPreamble{$Elem}=$_;
6427 }
6428 }
6429 my $TmpHeaderPath = "$TMP_DIR/dump$Version.h";
6430 my $MHeaderPath = $TmpHeaderPath;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04006431 open(LIB_HEADER, ">", $TmpHeaderPath) || die ("can't open file \'$TmpHeaderPath\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006432 if(my $AddDefines = $Descriptor{$Version}{"Defines"})
6433 {
6434 $AddDefines=~s/\n\s+/\n /g;
6435 print LIB_HEADER "\n // add defines\n ".$AddDefines."\n";
6436 }
6437 print LIB_HEADER "\n // add includes\n";
6438 my @PreambleHeaders = keys(%{$Include_Preamble{$Version}});
6439 @PreambleHeaders = sort {int($Include_Preamble{$Version}{$a}{"Position"})<=>int($Include_Preamble{$Version}{$b}{"Position"})} @PreambleHeaders;
6440 foreach my $Header_Path (@PreambleHeaders) {
6441 print LIB_HEADER " #include \"".path_format($Header_Path, "unix")."\"\n";
6442 }
6443 my @Headers = keys(%{$Registered_Headers{$Version}});
6444 @Headers = sort {int($Registered_Headers{$Version}{$a}{"Pos"})<=>int($Registered_Headers{$Version}{$b}{"Pos"})} @Headers;
6445 foreach my $Header_Path (@Headers)
6446 {
6447 next if($Include_Preamble{$Version}{$Header_Path});
6448 print LIB_HEADER " #include \"".path_format($Header_Path, "unix")."\"\n";
6449 }
6450 close(LIB_HEADER);
6451 my $IncludeString = getIncString(getIncPaths(@PreambleHeaders, @Headers), "GCC");
6452 if($Debug)
6453 { # debug mode
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006454 writeFile($DEBUG_PATH{$Version}."/headers/direct-includes.txt", Dumper(\%Header_Includes));
6455 writeFile($DEBUG_PATH{$Version}."/headers/recursive-includes.txt", Dumper(\%RecursiveIncludes));
6456 writeFile($DEBUG_PATH{$Version}."/headers/include-paths.txt", Dumper($Cache{"get_HeaderDeps"}));
6457 writeFile($DEBUG_PATH{$Version}."/headers/default-paths.txt", Dumper(\%DefaultIncPaths));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006458 }
6459 # preprocessing stage
6460 checkPreprocessedUnit(callPreprocessor($TmpHeaderPath, $IncludeString, $Version));
6461 my $MContent = "";
6462 my $PreprocessCmd = getCompileCmd($TmpHeaderPath, "-E", $IncludeString);
6463 if($OStarget eq "windows"
6464 and get_dumpmachine($GCC_PATH)=~/mingw/i
6465 and $MinGWMode{$Version}!=-1)
6466 { # modify headers to compile by MinGW
6467 if(not $MContent)
6468 { # preprocessing
6469 $MContent = `$PreprocessCmd 2>$TMP_DIR/null`;
6470 }
6471 if($MContent=~s/__asm\s*(\{[^{}]*?\}|[^{};]*)//g)
6472 { # __asm { ... }
6473 $MinGWMode{$Version}=1;
6474 }
6475 if($MContent=~s/\s+(\/ \/.*?)\n/\n/g)
6476 { # comments after preprocessing
6477 $MinGWMode{$Version}=1;
6478 }
6479 if($MContent=~s/(\W)(0x[a-f]+|\d+)(i|ui)(8|16|32|64)(\W)/$1$2$5/g)
6480 { # 0xffui8
6481 $MinGWMode{$Version}=1;
6482 }
6483 if($MinGWMode{$Version}) {
6484 printMsg("INFO", "Using MinGW compatibility mode");
6485 $MHeaderPath = "$TMP_DIR/dump$Version.i";
6486 }
6487 }
6488 if(($COMMON_LANGUAGE{$Version} eq "C" or $CheckHeadersOnly)
6489 and $C99Mode{$Version}!=-1 and not $Cpp2003)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006490 { # rename C++ keywords in C code
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006491 if(not $MContent)
6492 { # preprocessing
6493 $MContent = `$PreprocessCmd 2>$TMP_DIR/null`;
6494 }
6495 my $RegExp_C = join("|", keys(%CppKeywords_C));
6496 my $RegExp_F = join("|", keys(%CppKeywords_F));
6497 my $RegExp_O = join("|", keys(%CppKeywords_O));
6498 while($MContent=~s/(\A|\n[^\#\/\n][^\n]*?|\n)(\*\s*|\s+|\@|\,|\()($RegExp_C|$RegExp_F)(\s*(\,|\)|\;|\-\>|\.|\:\s*\d))/$1$2c99_$3$4/g)
6499 { # MATCH:
6500 # int foo(int new, int class, int (*new)(int));
6501 # unsigned private: 8;
6502 # DO NOT MATCH:
6503 # #pragma GCC visibility push(default)
6504 $C99Mode{$Version} = 1;
6505 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006506 if($MContent=~s/([^\w\s]|\w\s+)(?<!operator )(delete)(\s*\()/$1c99_$2$3/g)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006507 { # MATCH:
6508 # int delete(...);
6509 # int explicit(...);
6510 # DO NOT MATCH:
6511 # void operator delete(...)
6512 $C99Mode{$Version} = 1;
6513 }
6514 if($MContent=~s/(\s+)($RegExp_O)(\s*(\;|\:))/$1c99_$2$3/g)
6515 { # MATCH:
6516 # int bool;
6517 # DO NOT MATCH:
6518 # bool X;
6519 # return *this;
6520 # throw;
6521 $C99Mode{$Version} = 1;
6522 }
6523 if($MContent=~s/(\s+)(operator)(\s*(\(\s*\)\s*[^\(\s]|\(\s*[^\)\s]))/$1c99_$2$3/g)
6524 { # MATCH:
6525 # int operator(...);
6526 # DO NOT MATCH:
6527 # int operator()(...);
6528 $C99Mode{$Version} = 1;
6529 }
6530 if($MContent=~s/([^\w\(\,\s]\s*|\s+)(operator)(\s*(\,\s*[^\(\s]|\)))/$1c99_$2$3/g)
6531 { # MATCH:
6532 # int foo(int operator);
6533 # int foo(int operator, int other);
6534 # DO NOT MATCH:
6535 # int operator,(...);
6536 $C99Mode{$Version} = 1;
6537 }
6538 if($MContent=~s/(\*\s*|\w\s+)(bool)(\s*(\,|\)))/$1c99_$2$3/g)
6539 { # MATCH:
6540 # int foo(gboolean *bool);
6541 # DO NOT MATCH:
6542 # void setTabEnabled(int index, bool);
6543 $C99Mode{$Version} = 1;
6544 }
6545 if($MContent=~s/(\w)([^\w\(\,\s]\s*|\s+)(this)(\s*(\,|\)))/$1$2c99_$3$4/g)
6546 { # MATCH:
6547 # int foo(int* this);
6548 # int bar(int this);
6549 # DO NOT MATCH:
6550 # baz(X, this);
6551 $C99Mode{$Version} = 1;
6552 }
6553 if($C99Mode{$Version}==1)
6554 { # try to change C++ "keyword" to "c99_keyword"
6555 printMsg("INFO", "Using C99 compatibility mode");
6556 $MHeaderPath = "$TMP_DIR/dump$Version.i";
6557 }
6558 }
6559 if($C99Mode{$Version}==1
6560 or $MinGWMode{$Version}==1)
6561 { # compile the corrected preprocessor output
6562 writeFile($MHeaderPath, $MContent);
6563 }
6564 if($COMMON_LANGUAGE{$Version} eq "C++")
6565 { # add classes and namespaces to the dump
6566 my $CHdump = "-fdump-class-hierarchy -c";
6567 if($C99Mode{$Version}==1
6568 or $MinGWMode{$Version}==1) {
6569 $CHdump .= " -fpreprocessed";
6570 }
6571 my $ClassHierarchyCmd = getCompileCmd($MHeaderPath, $CHdump, $IncludeString);
6572 chdir($TMP_DIR);
6573 system("$ClassHierarchyCmd >null 2>&1");
6574 chdir($ORIG_DIR);
6575 if(my $ClassDump = (cmd_find($TMP_DIR,"f","*.class",1))[0])
6576 {
6577 my %AddClasses = ();
6578 my $Content = readFile($ClassDump);
6579 foreach my $ClassInfo (split(/\n\n/, $Content))
6580 {
6581 if($ClassInfo=~/\AClass\s+(.+)\s*/i)
6582 {
6583 my $CName = $1;
6584 next if($CName=~/\A(__|_objc_|_opaque_)/);
6585 $TUnit_NameSpaces{$Version}{$CName} = -1;
6586 if($CName=~/\A[\w:]+\Z/)
6587 { # classes
6588 $AddClasses{$CName} = 1;
6589 }
6590 if($CName=~/(\w[\w:]*)::/)
6591 { # namespaces
6592 my $NS = $1;
6593 if(not defined $TUnit_NameSpaces{$Version}{$NS}) {
6594 $TUnit_NameSpaces{$Version}{$NS} = 1;
6595 }
6596 }
6597 }
6598 elsif($ClassInfo=~/\AVtable\s+for\s+(.+)\n((.|\n)+)\Z/i)
6599 { # read v-tables (advanced approach)
6600 my ($CName, $VTable) = ($1, $2);
6601 $ClassVTable_Content{$Version}{$CName} = $VTable;
6602 }
6603 }
6604 if($Debug)
6605 { # debug mode
6606 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04006607 copy($ClassDump, $DEBUG_PATH{$Version}."/class-hierarchy-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006608 }
6609 unlink($ClassDump);
6610 if(my $NS_Add = get_namespace_additions($TUnit_NameSpaces{$Version}))
6611 { # GCC on all supported platforms does not include namespaces to the dump by default
6612 appendFile($MHeaderPath, "\n // add namespaces\n".$NS_Add);
6613 }
6614 # some GCC versions don't include class methods to the TU dump by default
6615 my ($AddClass, $ClassNum) = ("", 0);
6616 foreach my $CName (sort keys(%AddClasses))
6617 {
6618 next if($C_Structure{$CName});
6619 next if(not $STDCXX_TESTING and $CName=~/\Astd::/);
6620 next if(($CName=~tr![:]!!)>2);
6621 next if($SkipTypes{$Version}{$CName});
6622 if($CName=~/\A(.+)::[^:]+\Z/
6623 and $AddClasses{$1}) {
6624 next;
6625 }
6626 $AddClass .= " $CName* tmp_add_class_".($ClassNum++).";\n";
6627 }
6628 appendFile($MHeaderPath, "\n // add classes\n".$AddClass);
6629 }
6630 }
6631 writeLog($Version, "Temporary header file \'$TmpHeaderPath\' with the following content will be compiled to create GCC translation unit dump:\n".readFile($TmpHeaderPath)."\n");
6632 # create TU dump
6633 my $TUdump = "-fdump-translation-unit -fkeep-inline-functions -c";
6634 if($C99Mode{$Version}==1
6635 or $MinGWMode{$Version}==1) {
6636 $TUdump .= " -fpreprocessed";
6637 }
6638 my $SyntaxTreeCmd = getCompileCmd($MHeaderPath, $TUdump, $IncludeString);
6639 writeLog($Version, "The GCC parameters:\n $SyntaxTreeCmd\n\n");
6640 chdir($TMP_DIR);
6641 system($SyntaxTreeCmd." >$TMP_DIR/tu_errors 2>&1");
6642 if($?)
6643 { # failed to compile, but the TU dump still can be created
6644 my $Errors = readFile("$TMP_DIR/tu_errors");
6645 if($Errors=~/c99_/)
6646 { # disable c99 mode
6647 $C99Mode{$Version}=-1;
6648 printMsg("INFO", "Disabling C99 compatibility mode");
6649 resetLogging($Version);
6650 $TMP_DIR = tempdir(CLEANUP=>1);
6651 return getDump();
6652 }
6653 elsif($AutoPreambleMode{$Version}!=-1
6654 and my $TErrors = $Errors)
6655 {
6656 my %Types = ();
6657 while($TErrors=~s/error\:\s*(field\s*|)\W+(.+?)\W+//)
6658 { # error: 'FILE' has not been declared
6659 $Types{$2}=1;
6660 }
6661 my %AddHeaders = ();
6662 foreach my $Type (keys(%Types))
6663 {
6664 if(my $Header = $AutoPreamble{$Type}) {
6665 $AddHeaders{path_format($Header, $OSgroup)}=$Type;
6666 }
6667 }
6668 if(my @Headers = sort {$b cmp $a} keys(%AddHeaders))
6669 { # sys/types.h should be the first
6670 foreach my $Num (0 .. $#Headers)
6671 {
6672 my $Name = $Headers[$Num];
6673 if(my $Path = identify_header($Name, $Version))
6674 { # add automatic preamble headers
6675 if(defined $Include_Preamble{$Version}{$Path})
6676 { # already added
6677 next;
6678 }
6679 $Include_Preamble{$Version}{$Path}{"Position"} = keys(%{$Include_Preamble{$Version}});
6680 my $Type = $AddHeaders{$Name};
6681 printMsg("INFO", "Add \'$Name\' preamble header for \'$Type\'");
6682 }
6683 }
6684 $AutoPreambleMode{$Version}=-1;
6685 resetLogging($Version);
6686 $TMP_DIR = tempdir(CLEANUP=>1);
6687 return getDump();
6688 }
6689 }
6690 elsif($MinGWMode{$Version}!=-1)
6691 {
6692 $MinGWMode{$Version}=-1;
6693 resetLogging($Version);
6694 $TMP_DIR = tempdir(CLEANUP=>1);
6695 return getDump();
6696 }
6697 # FIXME: handle other errors and try to recompile
6698 writeLog($Version, $Errors);
6699 printMsg("ERROR", "some errors occurred when compiling headers");
6700 printErrorLog($Version);
6701 $COMPILE_ERRORS = $ERROR_CODE{"Compile_Error"};
6702 writeLog($Version, "\n");# new line
6703 }
6704 chdir($ORIG_DIR);
6705 unlink($TmpHeaderPath, $MHeaderPath);
6706 return (cmd_find($TMP_DIR,"f","*.tu",1))[0];
6707}
6708
6709sub cmd_file($)
6710{
6711 my $Path = $_[0];
6712 return "" if(not $Path or not -e $Path);
6713 if(my $CmdPath = get_CmdPath("file")) {
6714 return `$CmdPath -b \"$Path\"`;
6715 }
6716 return "";
6717}
6718
6719sub getIncString($$)
6720{
6721 my ($ArrRef, $Style) = @_;
6722 return if(not $ArrRef or $#{$ArrRef}<0);
6723 my $String = "";
6724 foreach (@{$ArrRef}) {
6725 $String .= " ".inc_opt($_, $Style);
6726 }
6727 return $String;
6728}
6729
6730sub getIncPaths(@)
6731{
6732 my @HeaderPaths = @_;
6733 my @IncPaths = ();
6734 if($INC_PATH_AUTODETECT{$Version})
6735 { # auto-detecting dependencies
6736 my %Includes = ();
6737 foreach my $HPath (@HeaderPaths)
6738 {
6739 foreach my $Dir (get_HeaderDeps($HPath, $Version))
6740 {
6741 if($Skip_Include_Paths{$Version}{$Dir}) {
6742 next;
6743 }
6744 $Includes{$Dir}=1;
6745 }
6746 }
6747 foreach my $Dir (keys(%{$Add_Include_Paths{$Version}}))
6748 { # added by user
6749 next if($Includes{$Dir});
6750 push(@IncPaths, $Dir);
6751 }
6752 foreach my $Dir (@{sortIncPaths([keys(%Includes)], $Version)}) {
6753 push(@IncPaths, $Dir);
6754 }
6755 }
6756 else
6757 { # user-defined paths
6758 foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
6759 sort {$b cmp $a} keys(%{$Include_Paths{$Version}})) {
6760 push(@IncPaths, $Dir);
6761 }
6762 }
6763 return \@IncPaths;
6764}
6765
6766sub callPreprocessor($$$)
6767{
6768 my ($Path, $Inc, $LibVersion) = @_;
6769 return "" if(not $Path or not -f $Path);
6770 my $IncludeString=$Inc;
6771 if(not $Inc) {
6772 $IncludeString = getIncString(getIncPaths($Path), "GCC");
6773 }
6774 my $Cmd = getCompileCmd($Path, "-dD -E", $IncludeString);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04006775 my $Out = "$TMP_DIR/preprocessed";
6776 system("$Cmd >$Out 2>$TMP_DIR/null");
6777 return $Out;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04006778}
6779
6780sub cmd_find($$$$)
6781{ # native "find" is much faster than File::Find (~6x)
6782 # also the File::Find doesn't support --maxdepth N option
6783 # so using the cross-platform wrapper for the native one
6784 my ($Path, $Type, $Name, $MaxDepth) = @_;
6785 return () if(not $Path or not -e $Path);
6786 if($OSgroup eq "windows")
6787 {
6788 my $DirCmd = get_CmdPath("dir");
6789 if(not $DirCmd) {
6790 exitStatus("Not_Found", "can't find \"dir\" command");
6791 }
6792 $Path=~s/[\\]+\Z//;
6793 $Path = get_abs_path($Path);
6794 $Path = path_format($Path, $OSgroup);
6795 my $Cmd = $DirCmd." \"$Path\" /B /O";
6796 if($MaxDepth!=1) {
6797 $Cmd .= " /S";
6798 }
6799 if($Type eq "d") {
6800 $Cmd .= " /AD";
6801 }
6802 my @Files = ();
6803 if($Name)
6804 { # FIXME: how to search file names in MS shell?
6805 $Name=~s/\*/.*/g if($Name!~/\]/);
6806 foreach my $File (split(/\n/, `$Cmd`))
6807 {
6808 if($File=~/$Name\Z/i) {
6809 push(@Files, $File);
6810 }
6811 }
6812 }
6813 else {
6814 @Files = split(/\n/, `$Cmd 2>$TMP_DIR/null`);
6815 }
6816 my @AbsPaths = ();
6817 foreach my $File (@Files)
6818 {
6819 if(not is_abs($File)) {
6820 $File = joinPath($Path, $File);
6821 }
6822 if($Type eq "f" and not -f $File)
6823 { # skip dirs
6824 next;
6825 }
6826 push(@AbsPaths, path_format($File, $OSgroup));
6827 }
6828 if($Type eq "d") {
6829 push(@AbsPaths, $Path);
6830 }
6831 return @AbsPaths;
6832 }
6833 else
6834 {
6835 my $FindCmd = get_CmdPath("find");
6836 if(not $FindCmd) {
6837 exitStatus("Not_Found", "can't find a \"find\" command");
6838 }
6839 $Path = get_abs_path($Path);
6840 if(-d $Path and -l $Path
6841 and $Path!~/\/\Z/)
6842 { # for directories that are symlinks
6843 $Path.="/";
6844 }
6845 my $Cmd = $FindCmd." \"$Path\"";
6846 if($MaxDepth) {
6847 $Cmd .= " -maxdepth $MaxDepth";
6848 }
6849 if($Type) {
6850 $Cmd .= " -type $Type";
6851 }
6852 if($Name)
6853 { # file name
6854 if($Name=~/\]/) {
6855 $Cmd .= " -regex \"$Name\"";
6856 }
6857 else {
6858 $Cmd .= " -name \"$Name\"";
6859 }
6860 }
6861 return split(/\n/, `$Cmd 2>$TMP_DIR/null`);
6862 }
6863}
6864
6865sub unpackDump($)
6866{
6867 my $Path = $_[0];
6868 return "" if(not $Path or not -e $Path);
6869 $Path = get_abs_path($Path);
6870 $Path = path_format($Path, $OSgroup);
6871 my ($Dir, $FileName) = separate_path($Path);
6872 my $UnpackDir = $TMP_DIR."/unpack";
6873 rmtree($UnpackDir);
6874 mkpath($UnpackDir);
6875 if($FileName=~s/\Q.zip\E\Z//g)
6876 { # *.zip
6877 my $UnzipCmd = get_CmdPath("unzip");
6878 if(not $UnzipCmd) {
6879 exitStatus("Not_Found", "can't find \"unzip\" command");
6880 }
6881 chdir($UnpackDir);
6882 system("$UnzipCmd \"$Path\" >$UnpackDir/contents.txt");
6883 if($?) {
6884 exitStatus("Error", "can't extract \'$Path\'");
6885 }
6886 chdir($ORIG_DIR);
6887 my @Contents = ();
6888 foreach (split("\n", readFile("$UnpackDir/contents.txt")))
6889 {
6890 if(/inflating:\s*([^\s]+)/) {
6891 push(@Contents, $1);
6892 }
6893 }
6894 if(not @Contents) {
6895 exitStatus("Error", "can't extract \'$Path\'");
6896 }
6897 return joinPath($UnpackDir, $Contents[0]);
6898 }
6899 elsif($FileName=~s/\Q.tar.gz\E\Z//g)
6900 { # *.tar.gz
6901 if($OSgroup eq "windows")
6902 { # -xvzf option is not implemented in tar.exe (2003)
6903 # use "gzip.exe -k -d -f" + "tar.exe -xvf" instead
6904 my $TarCmd = get_CmdPath("tar");
6905 if(not $TarCmd) {
6906 exitStatus("Not_Found", "can't find \"tar\" command");
6907 }
6908 my $GzipCmd = get_CmdPath("gzip");
6909 if(not $GzipCmd) {
6910 exitStatus("Not_Found", "can't find \"gzip\" command");
6911 }
6912 chdir($UnpackDir);
6913 system("$GzipCmd -k -d -f \"$Path\"");# keep input files (-k)
6914 if($?) {
6915 exitStatus("Error", "can't extract \'$Path\'");
6916 }
6917 system("$TarCmd -xvf \"$Dir\\$FileName.tar\" >$UnpackDir/contents.txt");
6918 if($?) {
6919 exitStatus("Error", "can't extract \'$Path\'");
6920 }
6921 chdir($ORIG_DIR);
6922 unlink($Dir."/".$FileName.".tar");
6923 my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
6924 if(not @Contents) {
6925 exitStatus("Error", "can't extract \'$Path\'");
6926 }
6927 return joinPath($UnpackDir, $Contents[0]);
6928 }
6929 else
6930 { # Unix
6931 my $TarCmd = get_CmdPath("tar");
6932 if(not $TarCmd) {
6933 exitStatus("Not_Found", "can't find \"tar\" command");
6934 }
6935 chdir($UnpackDir);
6936 system("$TarCmd -xvzf \"$Path\" >$UnpackDir/contents.txt");
6937 if($?) {
6938 exitStatus("Error", "can't extract \'$Path\'");
6939 }
6940 chdir($ORIG_DIR);
6941 # The content file name may be different
6942 # from the package file name
6943 my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
6944 if(not @Contents) {
6945 exitStatus("Error", "can't extract \'$Path\'");
6946 }
6947 return joinPath($UnpackDir, $Contents[0]);
6948 }
6949 }
6950}
6951
6952sub createArchive($$)
6953{
6954 my ($Path, $To) = @_;
6955 if(not $Path or not -e $Path
6956 or not -d $To) {
6957 return "";
6958 }
6959 my ($From, $Name) = separate_path($Path);
6960 if($OSgroup eq "windows")
6961 { # *.zip
6962 my $ZipCmd = get_CmdPath("zip");
6963 if(not $ZipCmd) {
6964 exitStatus("Not_Found", "can't find \"zip\"");
6965 }
6966 my $Pkg = $To."/".$Name.".zip";
6967 unlink($Pkg);
6968 chdir($To);
6969 system("$ZipCmd -j \"$Name.zip\" \"$Path\" >$TMP_DIR/null");
6970 if($?)
6971 { # cannot allocate memory (or other problems with "zip")
6972 unlink($Path);
6973 exitStatus("Error", "can't pack the ABI dump: ".$!);
6974 }
6975 chdir($ORIG_DIR);
6976 unlink($Path);
6977 return $Pkg;
6978 }
6979 else
6980 { # *.tar.gz
6981 my $TarCmd = get_CmdPath("tar");
6982 if(not $TarCmd) {
6983 exitStatus("Not_Found", "can't find \"tar\"");
6984 }
6985 my $GzipCmd = get_CmdPath("gzip");
6986 if(not $GzipCmd) {
6987 exitStatus("Not_Found", "can't find \"gzip\"");
6988 }
6989 my $Pkg = abs_path($To)."/".$Name.".tar.gz";
6990 unlink($Pkg);
6991 chdir($From);
6992 system($TarCmd, "-czf", $Pkg, $Name);
6993 if($?)
6994 { # cannot allocate memory (or other problems with "tar")
6995 unlink($Path);
6996 exitStatus("Error", "can't pack the ABI dump: ".$!);
6997 }
6998 chdir($ORIG_DIR);
6999 unlink($Path);
7000 return $To."/".$Name.".tar.gz";
7001 }
7002}
7003
7004sub is_header_file($)
7005{
7006 if($_[0]=~/\.($HEADER_EXT)\Z/i) {
7007 return $_[0];
7008 }
7009 return 0;
7010}
7011
7012sub is_not_header($)
7013{
7014 if($_[0]=~/\.\w+\Z/
7015 and $_[0]!~/\.($HEADER_EXT)\Z/i) {
7016 return 1;
7017 }
7018 return 0;
7019}
7020
7021sub is_header($$$)
7022{
7023 my ($Header, $UserDefined, $LibVersion) = @_;
7024 return 0 if(-d $Header);
7025 if(-f $Header) {
7026 $Header = get_abs_path($Header);
7027 }
7028 else
7029 {
7030 if(is_abs($Header))
7031 { # incorrect absolute path
7032 return 0;
7033 }
7034 if(my $HPath = identify_header($Header, $LibVersion)) {
7035 $Header = $HPath;
7036 }
7037 else
7038 { # can't find header
7039 return 0;
7040 }
7041 }
7042 if($Header=~/\.\w+\Z/)
7043 { # have an extension
7044 return is_header_file($Header);
7045 }
7046 else
7047 {
7048 if($UserDefined==2)
7049 { # specified on the command line
7050 if(cmd_file($Header)!~/HTML|XML/i) {
7051 return $Header;
7052 }
7053 }
7054 elsif($UserDefined)
7055 { # specified in the XML-descriptor
7056 # header file without an extension
7057 return $Header;
7058 }
7059 else
7060 {
7061 if(cmd_file($Header)=~/C[\+]*\s+program/i)
7062 { # !~/HTML|XML|shared|dynamic/i
7063 return $Header;
7064 }
7065 }
7066 }
7067 return 0;
7068}
7069
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007070sub addTargetHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007071{
7072 my $LibVersion = $_[0];
7073 foreach my $RegHeader (keys(%{$Registered_Headers{$LibVersion}}))
7074 {
7075 my $RegDir = get_dirname($RegHeader);
7076 $TargetHeaders{$LibVersion}{get_filename($RegHeader)}=1;
7077 foreach my $RecInc (keys(%{$RecursiveIncludes{$LibVersion}{$RegHeader}}))
7078 {
7079 my $Dir = get_dirname($RecInc);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007080 if($Dir=~/\A\Q$RegDir\E([\/\\]|\Z)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007081 { # in the same directory
7082 $TargetHeaders{$LibVersion}{get_filename($RecInc)}=1;
7083 }
7084 }
7085 }
7086}
7087
7088sub readHeaders($)
7089{
7090 $Version = $_[0];
7091 printMsg("INFO", "checking header(s) ".$Descriptor{$Version}{"Version"}." ...");
7092 my $DumpPath = getDump();
7093 if(not $DumpPath) {
7094 exitStatus("Cannot_Compile", "can't compile header(s)");
7095 }
7096 if($Debug)
7097 { # debug mode
7098 mkpath($DEBUG_PATH{$Version});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007099 copy($DumpPath, $DEBUG_PATH{$Version}."/translation-unit-dump.txt");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007100 }
7101 getInfo($DumpPath);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007102 addTargetHeaders($Version);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007103}
7104
7105sub prepareTypes($)
7106{
7107 my $LibVersion = $_[0];
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007108 if(not checkDumpVersion($LibVersion, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007109 { # support for old ABI dumps
7110 # type names have been corrected in ACC 1.22 (dump 2.0 format)
7111 foreach my $TypeDeclId (keys(%{$TypeInfo{$LibVersion}}))
7112 {
7113 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}}))
7114 {
7115 my $TName = $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Name"};
7116 if($TName=~/\A(\w+)::(\w+)/) {
7117 my ($P1, $P2) = ($1, $2);
7118 if($P1 eq $P2) {
7119 $TName=~s/\A$P1:\:$P1(\W)/$P1$1/;
7120 }
7121 else {
7122 $TName=~s/\A(\w+:\:)$P2:\:$P2(\W)/$1$P2$2/;
7123 }
7124 }
7125 $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Name"} = $TName;
7126 }
7127 }
7128 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007129 if(not checkDumpVersion($LibVersion, "2.5"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007130 { # support for old ABI dumps
7131 # V < 2.5: array size == "number of elements"
7132 # V >= 2.5: array size in bytes
7133 foreach my $TypeDeclId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
7134 {
7135 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}}))
7136 {
7137 my %Type = get_PureType($TypeDeclId, $TypeId, $LibVersion);
7138 if($Type{"Type"} eq "Array")
7139 {
7140 if($Type{"Size"})
7141 { # array[N]
7142 my %Base = get_OneStep_BaseType($Type{"TDid"}, $Type{"Tid"}, $LibVersion);
7143 $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Size"} = $Type{"Size"}*$Base{"Size"};
7144 }
7145 else
7146 { # array[] is a pointer
7147 $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Size"} = $WORD_SIZE{$LibVersion};
7148 }
7149 }
7150 }
7151 }
7152 }
7153 my $V2 = ($LibVersion==1)?2:1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007154 if(not checkDumpVersion($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007155 { # support for old ABI dumps
7156 # size of "method ptr" corrected in 2.7
7157 foreach my $TypeDeclId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
7158 {
7159 foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}}))
7160 {
7161 my %PureType = get_PureType($TypeDeclId, $TypeId, $LibVersion);
7162 if($PureType{"Type"} eq "MethodPtr")
7163 {
7164 my %Type = get_Type($TypeDeclId, $TypeId, $LibVersion);
7165 my $TypeId_2 = getTypeIdByName($PureType{"Name"}, $V2);
7166 my %Type2 = get_Type($Tid_TDid{$V2}{$TypeId_2}, $TypeId_2, $V2);
7167 if($Type{"Size"} ne $Type2{"Size"}) {
7168 $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Size"} = $Type2{"Size"};
7169 }
7170 }
7171 }
7172 }
7173 }
7174}
7175
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007176sub prepareSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007177{
7178 my $LibVersion = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007179
7180 if(not keys(%{$SymbolInfo{$LibVersion}}))
7181 { # check if input is valid
7182 if(not $ExtendedCheck and not $CheckObjectsOnly)
7183 {
7184 if($CheckHeadersOnly) {
7185 exitStatus("Empty_Set", "the set of public symbols is empty (".$Descriptor{$LibVersion}{"Version"}.")");
7186 }
7187 else {
7188 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection (".$Descriptor{$LibVersion}{"Version"}.")");
7189 }
7190 }
7191 }
7192
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007193 my $Remangle = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007194 if(not checkDumpVersion(1, "2.10")
7195 or not checkDumpVersion(2, "2.10"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007196 { # different formats
7197 $Remangle = 1;
7198 }
7199 if($CheckHeadersOnly)
7200 { # different languages
7201 if($UserLang)
7202 { # --lang=LANG for both versions
7203 if(($UsedDump{1}{"V"} and $UserLang ne $UsedDump{1}{"L"})
7204 or ($UsedDump{2}{"V"} and $UserLang ne $UsedDump{2}{"L"}))
7205 {
7206 if($UserLang eq "C++")
7207 { # remangle symbols
7208 $Remangle = 1;
7209 }
7210 elsif($UserLang eq "C")
7211 { # remove mangling
7212 $Remangle = -1;
7213 }
7214 }
7215 }
7216 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007217 foreach my $InfoId (sort {int($b)<=>int($a)} keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007218 { # reverse order: D0, D1, D2, D0 (artificial, GCC < 4.5), C1, C2
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007219 if($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007220 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007221 if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
7222 and keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})
7223 and $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{"0"}{"name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007224 { # support for old GCC < 4.5: skip artificial ~dtor(int __in_chrg)
7225 # + support for old ABI dumps
7226 next;
7227 }
7228 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007229 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007230 my $ClassID = $SymbolInfo{$LibVersion}{$InfoId}{"Class"};
7231 my $SRemangle = 0;
7232 if(not checkDumpVersion($LibVersion, "2.12"))
7233 { # support for old ABI dumps
7234 if($SymbolInfo{$LibVersion}{$InfoId}{"ShortName"} eq "operator>>")
7235 { # corrected mangling of operator>>
7236 $SRemangle = 1;
7237 }
7238 if($SymbolInfo{$LibVersion}{$InfoId}{"Data"}
7239 and not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
7240 { # corrected mangling of const global data
7241 $SRemangle = 1;
7242 }
7243 }
7244 if($Remangle==1 or $SRemangle==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007245 { # support for old ABI dumps: some symbols are not mangled in old dumps
7246 # mangle both sets of symbols (old and new)
7247 # NOTE: remangling all symbols by the same mangler
7248 if($MnglName=~/\A_ZN(V|)K/)
7249 { # mangling may be incorrect on old ABI dumps
7250 # because of absent "Const" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007251 $SymbolInfo{$LibVersion}{$InfoId}{"Const"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007252 }
7253 if($MnglName=~/\A_ZN(K|)V/)
7254 { # mangling may be incorrect on old ABI dumps
7255 # because of absent "Volatile" attribute
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007256 $SymbolInfo{$LibVersion}{$InfoId}{"Volatile"} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007257 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007258 if(($ClassID and $MnglName!~/\A(_Z|\?)/)
7259 or (not $ClassID and $CheckHeadersOnly)
7260 or (not $ClassID and not link_symbol($MnglName, $LibVersion, "-Deps")))
7261 { # support for old ABI dumps, GCC >= 4.0
7262 # remangling all manually mangled symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007263 if($MnglName = mangle_symbol($InfoId, $LibVersion, "GCC"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007264 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007265 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007266 $MangledNames{$LibVersion}{$MnglName} = 1;
7267 }
7268 }
7269 }
7270 elsif($Remangle==-1)
7271 { # remove mangling
7272 $MnglName = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007273 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007274 }
7275 if(not $MnglName)
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007276 { # ABI dumps have no mangled names for C-functions
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007277 $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
7278 $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007279 }
7280 if(not $MnglName) {
7281 next;
7282 }
7283 if(not $CompleteSignature{$LibVersion}{$MnglName}{"MnglName"})
7284 { # NOTE: global data may enter here twice
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007285 %{$CompleteSignature{$LibVersion}{$MnglName}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
7286
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007287 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007288 if(not checkDumpVersion($LibVersion, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007289 { # support for old dumps
7290 # add "Volatile" attribute
7291 if($MnglName=~/_Z(K|)V/) {
7292 $CompleteSignature{$LibVersion}{$MnglName}{"Volatile"}=1;
7293 }
7294 }
7295 # symbol and its symlink have same signatures
7296 if($SymVer{$LibVersion}{$MnglName}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007297 %{$CompleteSignature{$LibVersion}{$SymVer{$LibVersion}{$MnglName}}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007298 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007299 delete($SymbolInfo{$LibVersion}{$InfoId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007300 }
7301 if($COMMON_LANGUAGE{$LibVersion} eq "C++" or $OSgroup eq "windows") {
7302 translateSymbols(keys(%{$CompleteSignature{$LibVersion}}), $LibVersion);
7303 }
7304 if($ExtendedCheck)
7305 { # --ext option
7306 addExtension($LibVersion);
7307 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007308 $SymbolInfo{$LibVersion} = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007309 foreach my $MnglName (keys(%{$CompleteSignature{$LibVersion}}))
7310 { # detect allocable classes with public exported constructors
7311 # or classes with auto-generated or inline-only constructors
7312 if(my $ClassId = $CompleteSignature{$LibVersion}{$MnglName}{"Class"})
7313 {
7314 my $ClassName = get_TypeName($ClassId, $LibVersion);
7315 if($CompleteSignature{$LibVersion}{$MnglName}{"Constructor"}
7316 and not $CompleteSignature{$LibVersion}{$MnglName}{"InLine"})
7317 { # Class() { ... } will not be exported
7318 if(not $CompleteSignature{$LibVersion}{$MnglName}{"Private"})
7319 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007320 if($CheckHeadersOnly or link_symbol($MnglName, $LibVersion, "-Deps")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007321 $AllocableClass{$LibVersion}{$ClassName} = 1;
7322 }
7323 }
7324 }
7325 if(not $CompleteSignature{$LibVersion}{$MnglName}{"Private"})
7326 { # all imported class methods
7327 if($CheckHeadersOnly)
7328 {
7329 if(not $CompleteSignature{$LibVersion}{$MnglName}{"InLine"}
7330 or $CompleteSignature{$LibVersion}{$MnglName}{"Virt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007331 { # all symbols except non-virtual inline
7332 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$MnglName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007333 }
7334 }
7335 elsif(link_symbol($MnglName, $LibVersion, "-Deps"))
7336 { # all symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007337 $ClassMethods{"Binary"}{$LibVersion}{$ClassName}{$MnglName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007338 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007339 $ClassMethods{"Source"}{$LibVersion}{$ClassName}{$MnglName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007340 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007341 $ClassNames{$LibVersion}{$ClassName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007342 }
7343 if(my $RetId = $CompleteSignature{$LibVersion}{$MnglName}{"Return"})
7344 {
7345 my %Base = get_BaseType($Tid_TDid{$LibVersion}{$RetId}, $RetId, $LibVersion);
7346 if($Base{"Type"}=~/Struct|Class/)
7347 {
7348 my $Name = get_TypeName($Base{"Tid"}, $LibVersion);
7349 if($Name=~/<([^<>\s]+)>/)
7350 {
7351 if(my $Tid = getTypeIdByName($1, $LibVersion)) {
7352 $ReturnedClass{$LibVersion}{$Tid} = 1;
7353 }
7354 }
7355 else {
7356 $ReturnedClass{$LibVersion}{$Base{"Tid"}} = 1;
7357 }
7358 }
7359 }
7360 foreach my $Num (keys(%{$CompleteSignature{$LibVersion}{$MnglName}{"Param"}}))
7361 {
7362 my $PId = $CompleteSignature{$LibVersion}{$MnglName}{"Param"}{$Num}{"type"};
7363 if(get_PointerLevel($Tid_TDid{1}{$PId}, $PId, $LibVersion)>=1)
7364 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007365 if(my %Base = get_BaseType($Tid_TDid{$LibVersion}{$PId}, $PId, $LibVersion))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007366 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007367 if($Base{"Type"}=~/Struct|Class/)
7368 {
7369 $ParamClass{$LibVersion}{$Base{"Tid"}}{$MnglName} = 1;
7370 foreach my $SubId (get_sub_classes($Base{"Tid"}, $LibVersion, 1))
7371 { # mark all derived classes
7372 $ParamClass{$LibVersion}{$SubId}{$MnglName} = 1;
7373 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007374 }
7375 }
7376 }
7377 }
7378 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04007379 foreach my $MnglName (keys(%VTableClass))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007380 { # reconstruct header name for v-tables
7381 if($MnglName=~/\A_ZTV/)
7382 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04007383 if(my $ClassName = $VTableClass{$MnglName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007384 {
7385 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName}) {
7386 $CompleteSignature{$LibVersion}{$MnglName}{"Header"} = get_TypeAttr($ClassId, $LibVersion, "Header");
7387 }
7388 }
7389 }
7390 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007391
7392 # types
7393 foreach my $TypeDeclId (keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007394 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007395 foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007396 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007397 if(not defined $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"TDid"})
7398 { # to avoid Perl warnings about uninitialized values
7399 $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"TDid"} = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007400 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007401 if(my $TName = $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007402 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007403 if(defined $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"VTable"}) {
7404 $ClassNames{$LibVersion}{$TName} = 1;
7405 }
7406 if(defined $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Base"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007407 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007408 $ClassNames{$LibVersion}{$TName} = 1;
7409 foreach (keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Base"}})) {
7410 $ClassNames{$LibVersion}{get_TypeName($_, $LibVersion)} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007411 }
7412 }
7413 }
7414 }
7415 }
7416}
7417
7418sub register_TypeUsing($$$)
7419{
7420 my ($TypeDeclId, $TypeId, $LibVersion) = @_;
7421 return if($UsedType{$LibVersion}{$TypeDeclId}{$TypeId});
7422 my %Type = get_Type($TypeDeclId, $TypeId, $LibVersion);
7423 if($Type{"Type"}=~/\A(Struct|Union|Class|FuncPtr|MethodPtr|FieldPtr|Enum)\Z/)
7424 {
7425 $UsedType{$LibVersion}{$TypeDeclId}{$TypeId} = 1;
7426 if($Type{"Type"}=~/\A(Struct|Class)\Z/)
7427 {
7428 if(my $ThisPtrId = getTypeIdByName(get_TypeName($TypeId, $LibVersion)."*const", $LibVersion))
7429 {# register "this" pointer
7430 my $ThisPtrDId = $Tid_TDid{$LibVersion}{$ThisPtrId};
7431 my %ThisPtrType = get_Type($ThisPtrDId, $ThisPtrId, $LibVersion);
7432 $UsedType{$LibVersion}{$ThisPtrDId}{$ThisPtrId} = 1;
7433 register_TypeUsing($ThisPtrType{"BaseType"}{"TDid"}, $ThisPtrType{"BaseType"}{"Tid"}, $LibVersion);
7434 }
7435 foreach my $BaseId (keys(%{$Type{"Base"}}))
7436 {# register base classes
7437 register_TypeUsing($Tid_TDid{$LibVersion}{$BaseId}, $BaseId, $LibVersion);
7438 }
7439 }
7440 foreach my $Memb_Pos (keys(%{$Type{"Memb"}}))
7441 {
7442 my $Member_TypeId = $Type{"Memb"}{$Memb_Pos}{"type"};
7443 register_TypeUsing($Tid_TDid{$LibVersion}{$Member_TypeId}, $Member_TypeId, $LibVersion);
7444 }
7445 if($Type{"Type"} eq "FuncPtr"
7446 or $Type{"Type"} eq "MethodPtr") {
7447 my $ReturnType = $Type{"Return"};
7448 register_TypeUsing($Tid_TDid{$LibVersion}{$ReturnType}, $ReturnType, $LibVersion);
7449 foreach my $Memb_Pos (keys(%{$Type{"Param"}}))
7450 {
7451 my $Member_TypeId = $Type{"Param"}{$Memb_Pos}{"type"};
7452 register_TypeUsing($Tid_TDid{$LibVersion}{$Member_TypeId}, $Member_TypeId, $LibVersion);
7453 }
7454 }
7455 }
7456 elsif($Type{"Type"}=~/\A(Const|Pointer|Ref|Volatile|Restrict|Array|Typedef)\Z/)
7457 {
7458 $UsedType{$LibVersion}{$TypeDeclId}{$TypeId} = 1;
7459 register_TypeUsing($Type{"BaseType"}{"TDid"}, $Type{"BaseType"}{"Tid"}, $LibVersion);
7460 }
7461 elsif($Type{"Type"} eq "Intrinsic") {
7462 $UsedType{$LibVersion}{$TypeDeclId}{$TypeId} = 1;
7463 }
7464 else
7465 {
7466 delete($TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId});
7467 if(not keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}})) {
7468 delete($TypeInfo{$LibVersion}{$TypeDeclId});
7469 }
7470 if($Tid_TDid{$LibVersion}{$TypeId} eq $TypeDeclId) {
7471 delete($Tid_TDid{$LibVersion}{$TypeId});
7472 }
7473 }
7474}
7475
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007476sub isVirt($$) {
7477 return ($SymbolInfo{$_[0]}{$_[1]}{"Virt"} or $SymbolInfo{$_[0]}{$_[1]}{"PureVirt"});
7478}
7479
7480sub formatDump($)
7481{ # remove unnecessary data from the ABI dump
7482 my $LibVersion = $_[0];
7483 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
7484 {
7485 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
7486 if(not $MnglName) {
7487 delete($SymbolInfo{$LibVersion}{$InfoId});
7488 next;
7489 }
7490 if($MnglName eq $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"}) {
7491 delete($SymbolInfo{$LibVersion}{$InfoId}{"MnglName"});
7492 }
7493 if(not isVirt($LibVersion, $InfoId))
7494 { # non-virtual only
7495 if(not is_target_header($SymbolInfo{$LibVersion}{$InfoId}{"Header"}))
7496 { # user-defined header
7497 delete($SymbolInfo{$LibVersion}{$InfoId});
7498 next;
7499 }
7500 if(not $CheckHeadersOnly)
7501 {
7502 if($BinaryOnly)
7503 { # --dump --binary
7504 if(not link_symbol($MnglName, $LibVersion, "-Deps"))
7505 { # removing src only (inline)
7506 # and all non-exported functions
7507 delete($SymbolInfo{$LibVersion}{$InfoId});
7508 next;
7509 }
7510 }
7511 }
7512 if(not symbolFilter($MnglName, $LibVersion, "Public", "Source")) {
7513 delete($SymbolInfo{$LibVersion}{$InfoId});
7514 next;
7515 }
7516 }
7517 my %FuncInfo = %{$SymbolInfo{$LibVersion}{$InfoId}};
7518 register_TypeUsing($Tid_TDid{$LibVersion}{$FuncInfo{"Return"}}, $FuncInfo{"Return"}, $LibVersion);
7519 register_TypeUsing($Tid_TDid{$LibVersion}{$FuncInfo{"Class"}}, $FuncInfo{"Class"}, $LibVersion);
7520 foreach my $Param_Pos (keys(%{$FuncInfo{"Param"}}))
7521 {
7522 my $Param_TypeId = $FuncInfo{"Param"}{$Param_Pos}{"type"};
7523 register_TypeUsing($Tid_TDid{$LibVersion}{$Param_TypeId}, $Param_TypeId, $LibVersion);
7524 }
7525 if(not keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}})) {
7526 delete($SymbolInfo{$LibVersion}{$InfoId}{"Param"});
7527 }
7528 }
7529 foreach my $TDid (keys(%{$TypeInfo{$LibVersion}}))
7530 { # remove unused types
7531 if(not keys(%{$TypeInfo{$LibVersion}{$TDid}})) {
7532 delete($TypeInfo{$LibVersion}{$TDid});
7533 }
7534 else
7535 {
7536 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}{$TDid}}))
7537 {
7538 if(not $UsedType{$LibVersion}{$TDid}{$Tid})
7539 {
7540 delete($TypeInfo{$LibVersion}{$TDid}{$Tid});
7541 if(not keys(%{$TypeInfo{$LibVersion}{$TDid}})) {
7542 delete($TypeInfo{$LibVersion}{$TDid});
7543 }
7544 if($Tid_TDid{$LibVersion}{$Tid} eq $TDid) {
7545 delete($Tid_TDid{$LibVersion}{$Tid});
7546 }
7547 }
7548 else
7549 { # clean attributes
7550 if(not $TypeInfo{$LibVersion}{$TDid}{$Tid}{"TDid"}) {
7551 delete($TypeInfo{$LibVersion}{$TDid}{$Tid}{"TDid"});
7552 }
7553 if(not $TypeInfo{$LibVersion}{$TDid}{$Tid}{"NameSpace"}) {
7554 delete($TypeInfo{$LibVersion}{$TDid}{$Tid}{"NameSpace"});
7555 }
7556 if(defined $TypeInfo{$LibVersion}{$TDid}{$Tid}{"BaseType"}
7557 and not $TypeInfo{$LibVersion}{$TDid}{$Tid}{"BaseType"}{"TDid"}) {
7558 delete($TypeInfo{$LibVersion}{$TDid}{$Tid}{"BaseType"}{"TDid"});
7559 }
7560 if(not $TypeInfo{$LibVersion}{$TDid}{$Tid}{"Header"}) {
7561 delete($TypeInfo{$LibVersion}{$TDid}{$Tid}{"Header"});
7562 }
7563 if(not $TypeInfo{$LibVersion}{$TDid}{$Tid}{"Line"}) {
7564 delete($TypeInfo{$LibVersion}{$TDid}{$Tid}{"Line"});
7565 }
7566 if(not $TypeInfo{$LibVersion}{$TDid}{$Tid}{"Size"}) {
7567 delete($TypeInfo{$LibVersion}{$TDid}{$Tid}{"Size"});
7568 }
7569 }
7570 }
7571 }
7572 }
7573 foreach my $Tid (keys(%{$Tid_TDid{$LibVersion}}))
7574 {
7575 if(not $Tid_TDid{$LibVersion}{$Tid}) {
7576 delete($Tid_TDid{$LibVersion}{$Tid});
7577 }
7578 }
7579}
7580
7581sub addExtension($)
7582{
7583 my $LibVersion = $_[0];
7584 foreach my $TDid (keys(%{$TypeInfo{$LibVersion}}))
7585 {
7586 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}{$TDid}}))
7587 {
7588 my $TType = $TypeInfo{$LibVersion}{$TDid}{$Tid}{"Type"};
7589 if($TType=~/Struct|Union|Enum|Class/)
7590 {
7591 my $HName = $TypeInfo{$LibVersion}{$TDid}{$Tid}{"Header"};
7592 if(not $HName or isBuiltIn($HName)) {
7593 next;
7594 }
7595 my $TName = $TypeInfo{$LibVersion}{$TDid}{$Tid}{"Name"};
7596 if(isAnon($TName))
7597 { # anon-struct-header.h-265
7598 next;
7599 }
7600 my $FuncName = "external_func_".$TName;
7601 $ExtendedFuncs{$FuncName}=1;
7602 my %Attrs = (
7603 "Header" => "extended.h",
7604 "ShortName" => $FuncName,
7605 "MnglName" => $FuncName,
7606 "Param" => { "0" => { "type"=>$Tid, "name"=>"p1" } }
7607 );
7608 %{$CompleteSignature{$LibVersion}{$FuncName}} = %Attrs;
7609 register_TypeUsing($TDid, $Tid, $LibVersion);
7610 $GeneratedSymbols{$FuncName}=1;
7611 $CheckedSymbols{"Binary"}{$FuncName}=1;
7612 $CheckedSymbols{"Source"}{$FuncName}=1;
7613 }
7614 }
7615 }
7616 my $ConstFunc = "external_func_0";
7617 $GeneratedSymbols{$ConstFunc}=1;
7618 $CheckedSymbols{"Binary"}{$ConstFunc}=1;
7619 $CheckedSymbols{"Source"}{$ConstFunc}=1;
7620}
7621
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007622sub findMethod($$$)
7623{
7624 my ($VirtFunc, $ClassId, $LibVersion) = @_;
7625 foreach my $BaseClass_Id (keys(%{$TypeInfo{$LibVersion}{$Tid_TDid{$LibVersion}{$ClassId}}{$ClassId}{"Base"}}))
7626 {
7627 if(my $VirtMethodInClass = findMethod_Class($VirtFunc, $BaseClass_Id, $LibVersion)) {
7628 return $VirtMethodInClass;
7629 }
7630 elsif(my $VirtMethodInBaseClasses = findMethod($VirtFunc, $BaseClass_Id, $LibVersion)) {
7631 return $VirtMethodInBaseClasses;
7632 }
7633 }
7634 return "";
7635}
7636
7637sub findMethod_Class($$$)
7638{
7639 my ($VirtFunc, $ClassId, $LibVersion) = @_;
7640 my $ClassName = get_TypeName($ClassId, $LibVersion);
7641 return "" if(not defined $VirtualTable{$LibVersion}{$ClassName});
7642 my $TargetSuffix = get_symbol_suffix($VirtFunc, 1);
7643 my $TargetShortName = $CompleteSignature{$LibVersion}{$VirtFunc}{"ShortName"};
7644 foreach my $Candidate (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
7645 { # search for interface with the same parameters suffix (overridden)
7646 if($TargetSuffix eq get_symbol_suffix($Candidate, 1))
7647 {
7648 if($CompleteSignature{$LibVersion}{$VirtFunc}{"Destructor"}) {
7649 if($CompleteSignature{$LibVersion}{$Candidate}{"Destructor"}) {
7650 if(($VirtFunc=~/D0E/ and $Candidate=~/D0E/)
7651 or ($VirtFunc=~/D1E/ and $Candidate=~/D1E/)
7652 or ($VirtFunc=~/D2E/ and $Candidate=~/D2E/)) {
7653 return $Candidate;
7654 }
7655 }
7656 }
7657 else {
7658 if($TargetShortName eq $CompleteSignature{$LibVersion}{$Candidate}{"ShortName"}) {
7659 return $Candidate;
7660 }
7661 }
7662 }
7663 }
7664 return "";
7665}
7666
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007667sub registerVTable($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007668{
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007669 my $LibVersion = $_[0];
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007670 foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007671 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007672 if($CompleteSignature{$LibVersion}{$Symbol}{"Virt"}
7673 or $CompleteSignature{$LibVersion}{$Symbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007674 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007675 my $ClassName = get_TypeName($CompleteSignature{$LibVersion}{$Symbol}{"Class"}, $LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007676 next if(not $STDCXX_TESTING and $ClassName=~/\A(std::|__cxxabi)/);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007677 if($CompleteSignature{$LibVersion}{$Symbol}{"Destructor"}
7678 and $Symbol=~/D2E/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007679 { # pure virtual D2-destructors are marked as "virt" in the dump
7680 # virtual D2-destructors are NOT marked as "virt" in the dump
7681 # both destructors are not presented in the v-table
7682 next;
7683 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04007684 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007685 $VirtualTable{$LibVersion}{$ClassName}{$MnglName} = 1;
7686 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007687 }
7688}
7689
7690sub registerOverriding($)
7691{
7692 my $LibVersion = $_[0];
7693 my @Classes = keys(%{$VirtualTable{$LibVersion}});
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007694 @Classes = sort {int($ClassNames{$LibVersion}{$a})<=>int($ClassNames{$LibVersion}{$b})} @Classes;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007695 foreach my $ClassName (@Classes)
7696 {
7697 foreach my $VirtFunc (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
7698 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007699 if($CompleteSignature{$LibVersion}{$VirtFunc}{"PureVirt"})
7700 { # pure virtuals
7701 next;
7702 }
7703 my $ClassId = $TName_Tid{$LibVersion}{$ClassName};
7704 if(my $Overridden = findMethod($VirtFunc, $ClassId, $LibVersion))
7705 { # both overridden virtual methods
7706 # and implemented pure virtual methods
7707 $CompleteSignature{$LibVersion}{$VirtFunc}{"Override"} = $Overridden;
7708 $OverriddenMethods{$LibVersion}{$Overridden}{$VirtFunc} = 1;
7709 delete($VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}); # remove from v-table model
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007710 }
7711 }
7712 if(not keys(%{$VirtualTable{$LibVersion}{$ClassName}})) {
7713 delete($VirtualTable{$LibVersion}{$ClassName});
7714 }
7715 }
7716}
7717
7718sub setVirtFuncPositions($)
7719{
7720 my $LibVersion = $_[0];
7721 foreach my $ClassName (keys(%{$VirtualTable{$LibVersion}}))
7722 {
7723 my ($Num, $RelPos, $AbsNum) = (1, 0, 1);
7724 foreach my $VirtFunc (sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})}
7725 sort keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
7726 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007727 $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}=$Num++;
7728
7729 # set relative positions
7730 if(defined $VirtualTable{1}{$ClassName} and defined $VirtualTable{1}{$ClassName}{$VirtFunc}
7731 and defined $VirtualTable{2}{$ClassName} and defined $VirtualTable{2}{$ClassName}{$VirtFunc})
7732 { # relative position excluding added and removed virtual functions
7733 if(not $CompleteSignature{1}{$VirtFunc}{"Override"}
7734 and not $CompleteSignature{2}{$VirtFunc}{"Override"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007735 $CompleteSignature{$LibVersion}{$VirtFunc}{"RelPos"} = $RelPos++;
7736 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007737 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007738 }
7739 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007740 foreach my $ClassName (keys(%{$ClassNames{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007741 {
7742 my $AbsNum = 1;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007743 foreach my $VirtFunc (getVTable_Model($TName_Tid{$LibVersion}{$ClassName}, $LibVersion)) {
7744 $VirtualTable_Model{$LibVersion}{$ClassName}{$VirtFunc}=$AbsNum++;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007745 }
7746 }
7747}
7748
7749sub get_sub_classes($$$)
7750{
7751 my ($ClassId, $LibVersion, $Recursive) = @_;
7752 return () if(not defined $Class_SubClasses{$LibVersion}{$ClassId});
7753 my @Subs = ();
7754 foreach my $SubId (keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
7755 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007756 if($Recursive)
7757 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007758 foreach my $SubSubId (get_sub_classes($SubId, $LibVersion, $Recursive)) {
7759 push(@Subs, $SubSubId);
7760 }
7761 }
7762 push(@Subs, $SubId);
7763 }
7764 return @Subs;
7765}
7766
7767sub get_base_classes($$$)
7768{
7769 my ($ClassId, $LibVersion, $Recursive) = @_;
7770 my %ClassType = get_Type($Tid_TDid{$LibVersion}{$ClassId}, $ClassId, $LibVersion);
7771 return () if(not defined $ClassType{"Base"});
7772 my @Bases = ();
7773 foreach my $BaseId (sort {int($ClassType{"Base"}{$a}{"pos"})<=>int($ClassType{"Base"}{$b}{"pos"})}
7774 keys(%{$ClassType{"Base"}}))
7775 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007776 if($Recursive)
7777 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007778 foreach my $SubBaseId (get_base_classes($BaseId, $LibVersion, $Recursive)) {
7779 push(@Bases, $SubBaseId);
7780 }
7781 }
7782 push(@Bases, $BaseId);
7783 }
7784 return @Bases;
7785}
7786
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007787sub getVTable_Model($$)
7788{ # return an ordered list of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007789 my ($ClassId, $LibVersion) = @_;
7790 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
7791 my @Elements = ();
7792 foreach my $BaseId (@Bases, $ClassId)
7793 {
7794 my $BName = get_TypeName($BaseId, $LibVersion);
7795 my @VFunctions = keys(%{$VirtualTable{$LibVersion}{$BName}});
7796 @VFunctions = sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})} @VFunctions;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007797 foreach my $VFunc (@VFunctions) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007798 push(@Elements, $VFunc);
7799 }
7800 }
7801 return @Elements;
7802}
7803
7804sub getVShift($$)
7805{
7806 my ($ClassId, $LibVersion) = @_;
7807 my @Bases = get_base_classes($ClassId, $LibVersion, 1);
7808 my $VShift = 0;
7809 foreach my $BaseId (@Bases)
7810 {
7811 my $BName = get_TypeName($BaseId, $LibVersion);
7812 if(defined $VirtualTable{$LibVersion}{$BName}) {
7813 $VShift+=keys(%{$VirtualTable{$LibVersion}{$BName}});
7814 }
7815 }
7816 return $VShift;
7817}
7818
7819sub getShift($$)
7820{
7821 my ($ClassId, $LibVersion) = @_;
7822 my @Bases = get_base_classes($ClassId, $LibVersion, 0);
7823 my $Shift = 0;
7824 foreach my $BaseId (@Bases)
7825 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04007826 if(my $Size = get_TypeSize($BaseId, $LibVersion))
7827 {
7828 if($Size!=1)
7829 { # not empty base class
7830 $Shift+=$Size;
7831 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007832 }
7833 }
7834 return $Shift;
7835}
7836
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007837sub getVTable_Size($$)
7838{ # number of v-table elements
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007839 my ($ClassName, $LibVersion) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007840 my $Size = 0;
7841 # three approaches
7842 if(not $Size)
7843 { # real size
7844 if(my %VTable = getVTable_Real($ClassName, $LibVersion)) {
7845 $Size = keys(%VTable);
7846 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007847 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007848 if(not $Size)
7849 { # shared library symbol size
7850 if($Size = getSymbolSize($ClassVTable{$ClassName}, $LibVersion)) {
7851 $Size /= $WORD_SIZE{$LibVersion};
7852 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007853 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04007854 if(not $Size)
7855 { # model size
7856 if(defined $VirtualTable_Model{$LibVersion}{$ClassName}) {
7857 $Size = keys(%{$VirtualTable_Model{$LibVersion}{$ClassName}}) + 2;
7858 }
7859 }
7860 return $Size;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007861}
7862
7863sub isCopyingClass($$)
7864{
7865 my ($TypeId, $LibVersion) = @_;
7866 return $TypeInfo{$LibVersion}{$Tid_TDid{$LibVersion}{$TypeId}}{$TypeId}{"Copied"};
7867}
7868
7869sub isLeafClass($$)
7870{
7871 my ($ClassId, $LibVersion) = @_;
7872 return (not keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}));
7873}
7874
7875sub havePubFields($)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04007876{ # check structured type for public fields
7877 return isAccessible($_[0], {}, 0, -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007878}
7879
7880sub isAccessible($$$$)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04007881{ # check interval in structured type for public fields
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04007882 my ($TypePtr, $Skip, $Start, $End) = @_;
7883 return 0 if(not $TypePtr);
7884 if($End==-1) {
7885 $End = keys(%{$TypePtr->{"Memb"}})-1;
7886 }
7887 foreach my $MemPos (keys(%{$TypePtr->{"Memb"}}))
7888 {
7889 if($Skip and $Skip->{$MemPos})
7890 { # skip removed/added fields
7891 next;
7892 }
7893 if(int($MemPos)>=$Start and int($MemPos)<=$End)
7894 {
7895 if(isPublic($TypePtr, $MemPos)) {
7896 return ($MemPos+1);
7897 }
7898 }
7899 }
7900 return 0;
7901}
7902
7903sub getAlignment($$$)
7904{
7905 my ($Pos, $TypePtr, $LibVersion) = @_;
7906 my $Tid = $TypePtr->{"Memb"}{$Pos}{"type"};
7907 my %Type = get_PureType($Tid_TDid{$LibVersion}{$Tid}, $Tid, $LibVersion);
7908 my $TSize = $Type{"Size"}*$BYTE_SIZE;
7909 my $MSize = $Type{"Size"}*$BYTE_SIZE;
7910 if(my $BSize = $TypePtr->{"Memb"}{$Pos}{"bitfield"})
7911 { # bitfields
7912 ($TSize, $MSize) = ($WORD_SIZE{$LibVersion}*$BYTE_SIZE, $BSize);
7913 }
7914 elsif($Type{"Type"} eq "Array")
7915 { # in the context of function parameter
7916 # it's passed through the pointer
7917 }
7918 # alignment
7919 my $Alignment = $WORD_SIZE{$LibVersion}*$BYTE_SIZE; # default
7920 if(my $Computed = $TypePtr->{"Memb"}{$Pos}{"algn"})
7921 { # computed by GCC
7922 $Alignment = $Computed*$BYTE_SIZE;
7923 }
7924 elsif($TypePtr->{"Memb"}{$Pos}{"bitfield"})
7925 { # bitfields are 1 bit aligned
7926 $Alignment = 1;
7927 }
7928 elsif($TSize and $TSize<$WORD_SIZE{$LibVersion}*$BYTE_SIZE)
7929 { # model
7930 $Alignment = $TSize;
7931 }
7932 return ($Alignment, $MSize);
7933}
7934
7935sub getOffset($$$)
7936{ # offset of the field including padding
7937 my ($FieldPos, $TypePtr, $LibVersion) = @_;
7938 my $Offset = 0;
7939 foreach my $Pos (0 .. keys(%{$TypePtr->{"Memb"}})-1)
7940 {
7941 my ($Alignment, $MSize) = getAlignment($Pos, $TypePtr, $LibVersion);
7942 # padding
7943 my $Padding = 0;
7944 if($Offset % $Alignment!=0)
7945 { # not aligned, add padding
7946 $Padding = $Alignment - $Offset % $Alignment;
7947 }
7948 $Offset += $Padding;
7949 if($Pos==$FieldPos)
7950 { # after the padding
7951 # before the field
7952 return $Offset;
7953 }
7954 $Offset += $MSize;
7955 }
7956 return $FieldPos;# if something is going wrong
7957}
7958
7959sub isMemPadded($$$$$)
7960{ # check if the target field can be added/removed/changed
7961 # without shifting other fields because of padding bits
7962 my ($FieldPos, $Size, $TypePtr, $Skip, $LibVersion) = @_;
7963 return 0 if($FieldPos==0);
7964 if(defined $TypePtr->{"Memb"}{""})
7965 {
7966 delete($TypePtr->{"Memb"}{""});
7967 if($Debug) {
7968 printMsg("WARNING", "internal error detected");
7969 }
7970 }
7971 my $Offset = 0;
7972 my (%Alignment, %MSize) = ();
7973 my $MaxAlgn = 0;
7974 my $End = keys(%{$TypePtr->{"Memb"}})-1;
7975 my $NextField = $FieldPos+1;
7976 foreach my $Pos (0 .. $End)
7977 {
7978 if($Skip and $Skip->{$Pos})
7979 { # skip removed/added fields
7980 if($Pos > $FieldPos)
7981 { # after the target
7982 $NextField += 1;
7983 next;
7984 }
7985 }
7986 ($Alignment{$Pos}, $MSize{$Pos}) = getAlignment($Pos, $TypePtr, $LibVersion);
7987 if($Alignment{$Pos}>$MaxAlgn) {
7988 $MaxAlgn = $Alignment{$Pos};
7989 }
7990 if($Pos==$FieldPos)
7991 {
7992 if($Size==-1)
7993 { # added/removed fields
7994 if($Pos!=$End)
7995 { # skip target field and see
7996 # if enough padding will be
7997 # created on the next step
7998 # to include this field
7999 next;
8000 }
8001 }
8002 }
8003 # padding
8004 my $Padding = 0;
8005 if($Offset % $Alignment{$Pos}!=0)
8006 { # not aligned, add padding
8007 $Padding = $Alignment{$Pos} - $Offset % $Alignment{$Pos};
8008 }
8009 if($Pos==$NextField)
8010 { # try to place target field in the padding
8011 if($Size==-1)
8012 { # added/removed fields
8013 my $TPadding = 0;
8014 if($Offset % $Alignment{$FieldPos}!=0)
8015 {# padding of the target field
8016 $TPadding = $Alignment{$FieldPos} - $Offset % $Alignment{$FieldPos};
8017 }
8018 if($TPadding+$MSize{$FieldPos}<=$Padding)
8019 { # enough padding to place target field
8020 return 1;
8021 }
8022 else {
8023 return 0;
8024 }
8025 }
8026 else
8027 { # changed fields
8028 my $Delta = $Size-$MSize{$FieldPos};
8029 if($Delta>=0)
8030 { # increased
8031 if($Size-$MSize{$FieldPos}<=$Padding)
8032 { # enough padding to change target field
8033 return 1;
8034 }
8035 else {
8036 return 0;
8037 }
8038 }
8039 else
8040 { # decreased
8041 $Delta = abs($Delta);
8042 if($Delta+$Padding>=$MSize{$Pos})
8043 { # try to place the next field
8044 if(($Offset-$Delta) % $Alignment{$Pos} != 0)
8045 { # padding of the next field in new place
8046 my $NPadding = $Alignment{$Pos} - ($Offset-$Delta) % $Alignment{$Pos};
8047 if($NPadding+$MSize{$Pos}<=$Delta+$Padding)
8048 { # enough delta+padding to store next field
8049 return 0;
8050 }
8051 }
8052 else
8053 {
8054 return 0;
8055 }
8056 }
8057 return 1;
8058 }
8059 }
8060 }
8061 elsif($Pos==$End)
8062 { # target field is the last field
8063 if($Size==-1)
8064 { # added/removed fields
8065 if($Offset % $MaxAlgn!=0)
8066 { # tail padding
8067 my $TailPadding = $MaxAlgn - $Offset % $MaxAlgn;
8068 if($Padding+$MSize{$Pos}<=$TailPadding)
8069 { # enough tail padding to place the last field
8070 return 1;
8071 }
8072 }
8073 return 0;
8074 }
8075 else
8076 { # changed fields
8077 # scenario #1
8078 my $Offset1 = $Offset+$Padding+$MSize{$Pos};
8079 if($Offset1 % $MaxAlgn != 0)
8080 { # tail padding
8081 $Offset1 += $MaxAlgn - $Offset1 % $MaxAlgn;
8082 }
8083 # scenario #2
8084 my $Offset2 = $Offset+$Padding+$Size;
8085 if($Offset2 % $MaxAlgn != 0)
8086 { # tail padding
8087 $Offset2 += $MaxAlgn - $Offset2 % $MaxAlgn;
8088 }
8089 if($Offset1!=$Offset2)
8090 { # different sizes of structure
8091 return 0;
8092 }
8093 return 1;
8094 }
8095 }
8096 $Offset += $Padding+$MSize{$Pos};
8097 }
8098 return 0;
8099}
8100
8101sub isReserved($)
8102{ # reserved fields == private
8103 my $MName = $_[0];
8104 if($MName=~/reserved|padding|f_spare/i) {
8105 return 1;
8106 }
8107 if($MName=~/\A[_]*(spare|pad|unused)[_]*\Z/i) {
8108 return 1;
8109 }
8110 if($MName=~/(pad\d+)/i) {
8111 return 1;
8112 }
8113 return 0;
8114}
8115
8116sub isPublic($$)
8117{
8118 my ($TypePtr, $FieldPos) = @_;
8119 return 0 if(not $TypePtr);
8120 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos});
8121 return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos}{"name"});
8122 if(not $TypePtr->{"Memb"}{$FieldPos}{"access"})
8123 { # by name in C language
8124 # FIXME: add other methods to detect private members
8125 my $MName = $TypePtr->{"Memb"}{$FieldPos}{"name"};
8126 if($MName=~/priv|abidata|parent_object/i)
8127 { # C-styled private data
8128 return 0;
8129 }
8130 if(lc($MName) eq "abi")
8131 { # ABI information/reserved field
8132 return 0;
8133 }
8134 if(isReserved($MName))
8135 { # reserved fields
8136 return 0;
8137 }
8138 return 1;
8139 }
8140 elsif($TypePtr->{"Memb"}{$FieldPos}{"access"} ne "private")
8141 { # by access in C++ language
8142 return 1;
8143 }
8144 return 0;
8145}
8146
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008147sub getVTable_Real($$)
8148{
8149 my ($ClassName, $LibVersion) = @_;
8150 if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName})
8151 {
8152 my %Type = get_Type($Tid_TDid{$LibVersion}{$ClassId}, $ClassId, $LibVersion);
8153 if(defined $Type{"VTable"}) {
8154 return %{$Type{"VTable"}};
8155 }
8156 }
8157 return ();
8158}
8159
8160sub cmpVTables($)
8161{
8162 my $ClassName = $_[0];
8163 my $Res = cmpVTables_Real($ClassName, 1);
8164 if($Res==-1) {
8165 $Res = cmpVTables_Model($ClassName);
8166 }
8167 return $Res;
8168}
8169
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008170sub cmpVTables_Model($)
8171{
8172 my $ClassName = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008173 foreach my $Symbol (keys(%{$VirtualTable_Model{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008174 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008175 if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008176 return 1;
8177 }
8178 }
8179 return 0;
8180}
8181
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008182sub cmpVTables_Real($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008183{
8184 my ($ClassName, $Strong) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008185 if(defined $Cache{"cmpVTables_Real"}{$Strong}{$ClassName}) {
8186 return $Cache{"cmpVTables_Real"}{$Strong}{$ClassName};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008187 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008188 my %VTable_Old = getVTable_Real($ClassName, 1);
8189 my %VTable_New = getVTable_Real($ClassName, 2);
8190 if(not %VTable_Old or not %VTable_New)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008191 { # old ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008192 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = -1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008193 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008194 my %Indexes = map {$_=>1} (keys(%VTable_Old), keys(%VTable_New));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008195 foreach my $Offset (sort {int($a)<=>int($b)} keys(%Indexes))
8196 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008197 if(not defined $VTable_Old{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008198 { # v-table v.1 < v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008199 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = $Strong);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008200 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008201 my $Entry1 = $VTable_Old{$Offset};
8202 if(not defined $VTable_New{$Offset})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008203 { # v-table v.1 > v-table v.2
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008204 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = ($Strong or $Entry1!~/__cxa_pure_virtual/));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008205 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008206 my $Entry2 = $VTable_New{$Offset};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008207 $Entry1 = simpleVEntry($Entry1);
8208 $Entry2 = simpleVEntry($Entry2);
8209 if($Entry1 ne $Entry2)
8210 { # register as changed
8211 if($Entry1=~/::([^:]+)\Z/)
8212 {
8213 my $M1 = $1;
8214 if($Entry2=~/::([^:]+)\Z/)
8215 {
8216 my $M2 = $1;
8217 if($M1 eq $M2)
8218 { # overridden
8219 next;
8220 }
8221 }
8222 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008223 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008224 }
8225 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008226 return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 0);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008227}
8228
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008229sub mergeVTables($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008230{ # merging v-tables without diagnostics
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008231 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008232 foreach my $ClassName (keys(%{$VirtualTable{1}}))
8233 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008234 if($VTableChanged_M{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008235 { # already registered
8236 next;
8237 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008238 if(cmpVTables_Real($ClassName, 0)==1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008239 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008240 my @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008241 foreach my $Symbol (@Affected)
8242 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008243 %{$CompatProblems{$Level}{$Symbol}{"Virtual_Table_Changed_Unknown"}{$ClassName}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008244 "Type_Name"=>$ClassName,
8245 "Type_Type"=>"Class",
8246 "Target"=>$ClassName);
8247 }
8248 }
8249 }
8250}
8251
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008252sub mergeBases($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008253{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008254 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008255 foreach my $ClassName (keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008256 { # detect added and removed virtual functions
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008257 my $ClassId = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008258 next if(not $ClassId);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008259 if(defined $VirtualTable{2}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008260 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008261 foreach my $Symbol (keys(%{$VirtualTable{2}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008262 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008263 if($TName_Tid{1}{$ClassName}
8264 and not defined $VirtualTable{1}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008265 { # added to v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008266 if(defined $CompleteSignature{1}{$Symbol}
8267 and $CompleteSignature{1}{$Symbol}{"Virt"})
8268 { # override some method in v.1
8269 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008270 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008271 $AddedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008272 }
8273 }
8274 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008275 if(defined $VirtualTable{1}{$ClassName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008276 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008277 foreach my $Symbol (keys(%{$VirtualTable{1}{$ClassName}}))
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008278 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008279 if($TName_Tid{2}{$ClassName}
8280 and not defined $VirtualTable{2}{$ClassName}{$Symbol})
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008281 { # removed from v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008282 if(defined $CompleteSignature{2}{$Symbol}
8283 and $CompleteSignature{2}{$Symbol}{"Virt"})
8284 { # override some method in v.2
8285 next;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008286 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008287 $RemovedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008288 }
8289 }
8290 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008291 if($Level eq "Binary")
8292 { # Binary-level
8293 my %Class_Type = get_Type($Tid_TDid{1}{$ClassId}, $ClassId, 1);
8294 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$ClassName}}))
8295 { # check replacements, including pure virtual methods
8296 my $AddedPos = $VirtualTable{2}{$ClassName}{$AddedVFunc};
8297 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008298 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008299 my $RemovedPos = $VirtualTable{1}{$ClassName}{$RemovedVFunc};
8300 if($AddedPos==$RemovedPos)
8301 {
8302 $VirtualReplacement{$AddedVFunc} = $RemovedVFunc;
8303 $VirtualReplacement{$RemovedVFunc} = $AddedVFunc;
8304 last; # other methods will be reported as "added" or "removed"
8305 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008306 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008307 if(my $RemovedVFunc = $VirtualReplacement{$AddedVFunc})
8308 {
8309 if(lc($AddedVFunc) eq lc($RemovedVFunc))
8310 { # skip: DomUi => DomUI parameter (Qt 4.2.3 to 4.3.0)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008311 next;
8312 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008313 my $ProblemType = "Virtual_Replacement";
8314 my @Affected = ($RemovedVFunc);
8315 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
8316 { # pure methods
8317 if(not isUsedClass($ClassId, 1, $Level))
8318 { # not a parameter of some exported method
8319 next;
8320 }
8321 $ProblemType = "Pure_Virtual_Replacement";
8322 @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008323 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008324 foreach my $AffectedInt (@Affected)
8325 {
8326 if($CompleteSignature{1}{$AffectedInt}{"PureVirt"})
8327 { # affected exported methods only
8328 next;
8329 }
8330 %{$CompatProblems{$Level}{$AffectedInt}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
8331 "Type_Name"=>$Class_Type{"Name"},
8332 "Type_Type"=>"Class",
8333 "Target"=>get_Signature($AddedVFunc, 2),
8334 "Old_Value"=>get_Signature($RemovedVFunc, 1));
8335 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008336 }
8337 }
8338 }
8339 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008340 if(not checkDumpVersion(1, "2.0")
8341 or not checkDumpVersion(2, "2.0"))
8342 { # support for old ABI dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008343 # "Base" attribute introduced in ACC 1.22 (dump 2.0 format)
8344 return;
8345 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008346 foreach my $ClassName (sort keys(%{$ClassNames{1}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008347 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008348 my $ClassId_Old = $TName_Tid{1}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008349 next if(not $ClassId_Old);
8350 if(not isCreatable($ClassId_Old, 1))
8351 { # skip classes without public constructors (including auto-generated)
8352 # example: class has only a private exported or private inline constructor
8353 next;
8354 }
8355 if($ClassName=~/>/)
8356 { # skip affected template instances
8357 next;
8358 }
8359 my %Class_Old = get_Type($Tid_TDid{1}{$ClassId_Old}, $ClassId_Old, 1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008360 my $ClassId_New = $TName_Tid{2}{$ClassName};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008361 next if(not $ClassId_New);
8362 my %Class_New = get_Type($Tid_TDid{2}{$ClassId_New}, $ClassId_New, 2);
8363 my @Bases_Old = sort {$Class_Old{"Base"}{$a}{"pos"}<=>$Class_Old{"Base"}{$b}{"pos"}} keys(%{$Class_Old{"Base"}});
8364 my @Bases_New = sort {$Class_New{"Base"}{$a}{"pos"}<=>$Class_New{"Base"}{$b}{"pos"}} keys(%{$Class_New{"Base"}});
8365 my ($BNum1, $BNum2) = (1, 1);
8366 my %BasePos_Old = map {get_TypeName($_, 1) => $BNum1++} @Bases_Old;
8367 my %BasePos_New = map {get_TypeName($_, 2) => $BNum2++} @Bases_New;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008368 my %ShortBase_Old = map {get_ShortType($_, 1) => 1} @Bases_Old;
8369 my %ShortBase_New = map {get_ShortType($_, 2) => 1} @Bases_New;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008370 my $Shift_Old = getShift($ClassId_Old, 1);
8371 my $Shift_New = getShift($ClassId_New, 2);
8372 my %BaseId_New = map {get_TypeName($_, 2) => $_} @Bases_New;
8373 my ($Added, $Removed) = (0, 0);
8374 my @StableBases_Old = ();
8375 foreach my $BaseId (@Bases_Old)
8376 {
8377 my $BaseName = get_TypeName($BaseId, 1);
8378 if($BasePos_New{$BaseName}) {
8379 push(@StableBases_Old, $BaseId);
8380 }
8381 elsif(not $ShortBase_New{$BaseName}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008382 and not $ShortBase_New{get_ShortType($BaseId, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008383 { # removed base
8384 # excluding namespace::SomeClass to SomeClass renaming
8385 my $ProblemKind = "Removed_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008386 if($Level eq "Binary")
8387 { # Binary-level
8388 if($Shift_Old ne $Shift_New)
8389 { # affected fields
8390 if(havePubFields(\%Class_Old)) {
8391 $ProblemKind .= "_And_Shift";
8392 }
8393 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
8394 $ProblemKind .= "_And_Size";
8395 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008396 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008397 if(keys(%{$VirtualTable_Model{1}{$BaseName}})
8398 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008399 { # affected v-table
8400 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008401 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008402 }
8403 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008404 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008405 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
8406 {
8407 my $SubName = get_TypeName($SubId, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008408 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008409 if($ProblemKind=~/VTable/) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008410 $VTableChanged_M{$SubName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008411 }
8412 }
8413 foreach my $Interface (@Affected)
8414 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008415 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008416 "Type_Name"=>$ClassName,
8417 "Type_Type"=>"Class",
8418 "Target"=>$BaseName,
8419 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
8420 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
8421 "Shift"=>abs($Shift_New-$Shift_Old) );
8422 }
8423 $Removed+=1;
8424 }
8425 }
8426 my @StableBases_New = ();
8427 foreach my $BaseId (@Bases_New)
8428 {
8429 my $BaseName = get_TypeName($BaseId, 2);
8430 if($BasePos_Old{$BaseName}) {
8431 push(@StableBases_New, $BaseId);
8432 }
8433 elsif(not $ShortBase_Old{$BaseName}
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008434 and not $ShortBase_Old{get_ShortType($BaseId, 2)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008435 { # added base
8436 # excluding namespace::SomeClass to SomeClass renaming
8437 my $ProblemKind = "Added_Base_Class";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008438 if($Level eq "Binary")
8439 { # Binary-level
8440 if($Shift_Old ne $Shift_New)
8441 { # affected fields
8442 if(havePubFields(\%Class_Old)) {
8443 $ProblemKind .= "_And_Shift";
8444 }
8445 elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
8446 $ProblemKind .= "_And_Size";
8447 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008448 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008449 if(keys(%{$VirtualTable_Model{2}{$BaseName}})
8450 and cmpVTables($ClassName)==1)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008451 { # affected v-table
8452 $ProblemKind .= "_And_VTable";
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008453 $VTableChanged_M{$ClassName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008454 }
8455 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008456 my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008457 foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
8458 {
8459 my $SubName = get_TypeName($SubId, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008460 push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008461 if($ProblemKind=~/VTable/) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008462 $VTableChanged_M{$SubName}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008463 }
8464 }
8465 foreach my $Interface (@Affected)
8466 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008467 %{$CompatProblems{$Level}{$Interface}{$ProblemKind}{"this"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008468 "Type_Name"=>$ClassName,
8469 "Type_Type"=>"Class",
8470 "Target"=>$BaseName,
8471 "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
8472 "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
8473 "Shift"=>abs($Shift_New-$Shift_Old) );
8474 }
8475 $Added+=1;
8476 }
8477 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008478 if($Level eq "Binary")
8479 { # Binary-level
8480 ($BNum1, $BNum2) = (1, 1);
8481 my %BaseRelPos_Old = map {get_TypeName($_, 1) => $BNum1++} @StableBases_Old;
8482 my %BaseRelPos_New = map {get_TypeName($_, 2) => $BNum2++} @StableBases_New;
8483 foreach my $BaseId (@Bases_Old)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008484 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008485 my $BaseName = get_TypeName($BaseId, 1);
8486 if(my $NewPos = $BaseRelPos_New{$BaseName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008487 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008488 my $BaseNewId = $BaseId_New{$BaseName};
8489 my $OldPos = $BaseRelPos_Old{$BaseName};
8490 if($NewPos!=$OldPos)
8491 { # changed position of the base class
8492 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008493 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008494 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Position"}{"this"}}=(
8495 "Type_Name"=>$ClassName,
8496 "Type_Type"=>"Class",
8497 "Target"=>$BaseName,
8498 "Old_Value"=>$OldPos-1,
8499 "New_Value"=>$NewPos-1 );
8500 }
8501 }
8502 if($Class_Old{"Base"}{$BaseId}{"virtual"}
8503 and not $Class_New{"Base"}{$BaseNewId}{"virtual"})
8504 { # became non-virtual base
8505 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
8506 {
8507 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Non_Virtually_Inherited"}{"this->".$BaseName}}=(
8508 "Type_Name"=>$ClassName,
8509 "Type_Type"=>"Class",
8510 "Target"=>$BaseName );
8511 }
8512 }
8513 elsif(not $Class_Old{"Base"}{$BaseId}{"virtual"}
8514 and $Class_New{"Base"}{$BaseNewId}{"virtual"})
8515 { # became virtual base
8516 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
8517 {
8518 %{$CompatProblems{$Level}{$Interface}{"Base_Class_Became_Virtually_Inherited"}{"this->".$BaseName}}=(
8519 "Type_Name"=>$ClassName,
8520 "Type_Type"=>"Class",
8521 "Target"=>$BaseName );
8522 }
8523 }
8524 }
8525 }
8526 # detect size changes in base classes
8527 if($Shift_Old!=$Shift_New)
8528 { # size of allocable class
8529 foreach my $BaseId (@StableBases_Old)
8530 { # search for changed base
8531 my %BaseType = get_Type($Tid_TDid{1}{$BaseId}, $BaseId, 1);
8532 my $Size_Old = get_TypeSize($BaseId, 1);
8533 my $Size_New = get_TypeSize($BaseId_New{$BaseType{"Name"}}, 2);
8534 if($Size_Old ne $Size_New
8535 and $Size_Old and $Size_New)
8536 {
8537 my $ProblemType = "";
8538 if(isCopyingClass($BaseId, 1)) {
8539 $ProblemType = "Size_Of_Copying_Class";
8540 }
8541 elsif($AllocableClass{1}{$BaseType{"Name"}})
8542 {
8543 if($Size_New>$Size_Old)
8544 { # increased size
8545 $ProblemType = "Size_Of_Allocable_Class_Increased";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008546 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008547 else
8548 { # decreased size
8549 $ProblemType = "Size_Of_Allocable_Class_Decreased";
8550 if(not havePubFields(\%Class_Old))
8551 { # affected class has no public members
8552 next;
8553 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008554 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008555 }
8556 next if(not $ProblemType);
8557 foreach my $Interface (keys(%{$ClassMethods{$Level}{1}{$ClassName}}))
8558 { # base class size changes affecting current class
8559 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{"this->".$BaseType{"Name"}}}=(
8560 "Type_Name"=>$BaseType{"Name"},
8561 "Type_Type"=>"Class",
8562 "Target"=>$BaseType{"Name"},
8563 "Old_Size"=>$Size_Old*$BYTE_SIZE,
8564 "New_Size"=>$Size_New*$BYTE_SIZE );
8565 }
8566 }
8567 }
8568 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008569 if(defined $VirtualTable{1}{$ClassName}
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008570 and cmpVTables_Real($ClassName, 1)==1
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008571 and my @VFunctions = keys(%{$VirtualTable{1}{$ClassName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008572 { # compare virtual tables size in base classes
8573 my $VShift_Old = getVShift($ClassId_Old, 1);
8574 my $VShift_New = getVShift($ClassId_New, 2);
8575 if($VShift_Old ne $VShift_New)
8576 { # changes in the base class or changes in the list of base classes
8577 my @AllBases_Old = get_base_classes($ClassId_Old, 1, 1);
8578 my @AllBases_New = get_base_classes($ClassId_New, 2, 1);
8579 ($BNum1, $BNum2) = (1, 1);
8580 my %StableBase = map {get_TypeName($_, 2) => $_} @AllBases_New;
8581 foreach my $BaseId (@AllBases_Old)
8582 {
8583 my %BaseType = get_Type($Tid_TDid{1}{$BaseId}, $BaseId, 1);
8584 if(not $StableBase{$BaseType{"Name"}})
8585 { # lost base
8586 next;
8587 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008588 my $VSize_Old = getVTable_Size($BaseType{"Name"}, 1);
8589 my $VSize_New = getVTable_Size($BaseType{"Name"}, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008590 if($VSize_Old!=$VSize_New)
8591 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008592 foreach my $Interface (@VFunctions)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008593 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008594 if(not defined $VirtualTable{2}{$ClassName}{$Interface})
8595 { # Removed_Virtual_Method, will be registered in mergeVirtualTables()
8596 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008597 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008598 if($VirtualTable_Model{2}{$ClassName}{$Interface}-$VirtualTable_Model{1}{$ClassName}{$Interface}==0)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008599 { # skip interfaces that have not changed the absolute virtual position
8600 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008601 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008602 if(not $CheckHeadersOnly)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008603 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008604 if(not link_symbol($Interface, 1, "-Deps"))
8605 { # affected symbols in shared library
8606 next;
8607 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008608 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008609 $VTableChanged_M{$BaseType{"Name"}} = 1;
8610 $VTableChanged_M{$ClassName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008611 foreach my $VirtFunc (keys(%{$AddedInt_Virt{$Level}{$BaseType{"Name"}}}))
8612 { # the reason of the layout change: added virtual functions
8613 next if($VirtualReplacement{$VirtFunc});
8614 my $ProblemType = "Added_Virtual_Method";
8615 if($CompleteSignature{2}{$VirtFunc}{"PureVirt"}) {
8616 $ProblemType = "Added_Pure_Virtual_Method";
8617 }
8618 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{get_Signature($VirtFunc, 2)}}=(
8619 "Type_Name"=>$BaseType{"Name"},
8620 "Type_Type"=>"Class",
8621 "Target"=>get_Signature($VirtFunc, 2) );
8622 }
8623 foreach my $VirtFunc (keys(%{$RemovedInt_Virt{$Level}{$BaseType{"Name"}}}))
8624 { # the reason of the layout change: removed virtual functions
8625 next if($VirtualReplacement{$VirtFunc});
8626 my $ProblemType = "Removed_Virtual_Method";
8627 if($CompleteSignature{1}{$VirtFunc}{"PureVirt"}) {
8628 $ProblemType = "Removed_Pure_Virtual_Method";
8629 }
8630 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{get_Signature($VirtFunc, 1)}}=(
8631 "Type_Name"=>$BaseType{"Name"},
8632 "Type_Type"=>"Class",
8633 "Target"=>get_Signature($VirtFunc, 1) );
8634 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008635 }
8636 }
8637 }
8638 }
8639 }
8640 }
8641 }
8642}
8643
8644sub isCreatable($$)
8645{
8646 my ($ClassId, $LibVersion) = @_;
8647 if($AllocableClass{$LibVersion}{get_TypeName($ClassId, $LibVersion)}
8648 or isCopyingClass($ClassId, $LibVersion)) {
8649 return 1;
8650 }
8651 if(keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
8652 { # Fix for incomplete data: if this class has
8653 # a base class then it should also has a constructor
8654 return 1;
8655 }
8656 if($ReturnedClass{$LibVersion}{$ClassId})
8657 { # returned by some method of this class
8658 # or any other class
8659 return 1;
8660 }
8661 return 0;
8662}
8663
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008664sub isUsedClass($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008665{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008666 my ($ClassId, $LibVersion, $Level) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008667 if(keys(%{$ParamClass{$LibVersion}{$ClassId}}))
8668 { # parameter of some exported method
8669 return 1;
8670 }
8671 my $CName = get_TypeName($ClassId, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008672 if(keys(%{$ClassMethods{$Level}{1}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008673 { # method from target class
8674 return 1;
8675 }
8676 return 0;
8677}
8678
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008679sub mergeVirtualTables($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008680{ # check for changes in the virtual table
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008681 my ($Interface, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008682 # affected methods:
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008683 # - virtual
8684 # - pure-virtual
8685 # - non-virtual
8686 if($CompleteSignature{1}{$Interface}{"Data"})
8687 { # global data is not affected
8688 return;
8689 }
8690 my $Class_Id = $CompleteSignature{1}{$Interface}{"Class"};
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008691 if(not $Class_Id) {
8692 return;
8693 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008694 my $CName = get_TypeName($Class_Id, 1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008695 if(cmpVTables_Real($CName, 1)==0)
8696 { # no changes
8697 return;
8698 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008699 $CheckedTypes{$Level}{$CName} = 1;
8700 if($Level eq "Binary")
8701 { # Binary-level
8702 if($CompleteSignature{1}{$Interface}{"PureVirt"}
8703 and not isUsedClass($Class_Id, 1, $Level))
8704 { # pure virtuals should not be affected
8705 # if there are no exported methods using this class
8706 return;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008707 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008708 # check virtual table structure
8709 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
8710 {
8711 next if($Interface eq $AddedVFunc);
8712 next if($VirtualReplacement{$AddedVFunc});
8713 my $VPos_Added = $VirtualTable{2}{$CName}{$AddedVFunc};
8714 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
8715 { # pure virtual methods affect all others (virtual and non-virtual)
8716 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008717 "Type_Name"=>$CName,
8718 "Type_Type"=>"Class",
8719 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008720 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008721 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008722 elsif(not defined $VirtualTable{1}{$CName}
8723 or $VPos_Added>keys(%{$VirtualTable{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008724 { # added virtual function at the end of v-table
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008725 if(not keys(%{$VirtualTable_Model{1}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008726 { # became polymorphous class, added v-table pointer
8727 %{$CompatProblems{$Level}{$Interface}{"Added_First_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008728 "Type_Name"=>$CName,
8729 "Type_Type"=>"Class",
8730 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008731 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008732 }
8733 else
8734 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008735 my $VSize_Old = getVTable_Size($CName, 1);
8736 my $VSize_New = getVTable_Size($CName, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008737 next if($VSize_Old==$VSize_New);# exception: register as removed and added virtual method
8738 if(isCopyingClass($Class_Id, 1))
8739 { # class has no constructors and v-table will be copied by applications, this may affect all methods
8740 my $ProblemType = "Added_Virtual_Method";
8741 if(isLeafClass($Class_Id, 1)) {
8742 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Copying_Class";
8743 }
8744 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
8745 "Type_Name"=>$CName,
8746 "Type_Type"=>"Class",
8747 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008748 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008749 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008750 else
8751 {
8752 my $ProblemType = "Added_Virtual_Method";
8753 if(isLeafClass($Class_Id, 1)) {
8754 $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Allocable_Class";
8755 }
8756 %{$CompatProblems{$Level}{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
8757 "Type_Name"=>$CName,
8758 "Type_Type"=>"Class",
8759 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008760 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008761 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008762 }
8763 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008764 elsif($CompleteSignature{1}{$Interface}{"Virt"}
8765 or $CompleteSignature{1}{$Interface}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008766 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008767 if(defined $VirtualTable{1}{$CName}
8768 and defined $VirtualTable{2}{$CName})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008769 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008770 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
8771 my $VPos_New = $VirtualTable{2}{$CName}{$Interface};
8772 if($VPos_Added<=$VPos_Old and $VPos_Old!=$VPos_New)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008773 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008774 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
8775 foreach my $ASymbol (@Affected)
8776 {
8777 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"}
8778 and not link_symbol($ASymbol, 1, "-Deps")) {
8779 next;
8780 }
8781 $CheckedSymbols{$Level}{$ASymbol} = 1;
8782 %{$CompatProblems{$Level}{$ASymbol}{"Added_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
8783 "Type_Name"=>$CName,
8784 "Type_Type"=>"Class",
8785 "Target"=>get_Signature($AddedVFunc, 2) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008786 $VTableChanged_M{get_TypeName($CompleteSignature{1}{$ASymbol}{"Class"}, 1)} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008787 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008788 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008789 }
8790 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008791 else {
8792 # safe
8793 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008794 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008795 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
8796 {
8797 next if($VirtualReplacement{$RemovedVFunc});
8798 if($RemovedVFunc eq $Interface
8799 and $CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
8800 { # This case is for removed virtual methods
8801 # implemented in both versions of a library
8802 next;
8803 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008804 if(not keys(%{$VirtualTable_Model{2}{$CName}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008805 { # became non-polymorphous class, removed v-table pointer
8806 %{$CompatProblems{$Level}{$Interface}{"Removed_Last_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
8807 "Type_Name"=>$CName,
8808 "Type_Type"=>"Class",
8809 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008810 $VTableChanged_M{$CName} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008811 }
8812 elsif($CompleteSignature{1}{$Interface}{"Virt"}
8813 or $CompleteSignature{1}{$Interface}{"PureVirt"})
8814 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008815 if(defined $VirtualTable{1}{$CName} and defined $VirtualTable{2}{$CName})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008816 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008817 if(not defined $VirtualTable{1}{$CName}{$Interface}) {
8818 next;
8819 }
8820 my $VPos_New = -1;
8821 if(defined $VirtualTable{2}{$CName}{$Interface})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008822 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008823 $VPos_New = $VirtualTable{2}{$CName}{$Interface};
8824 }
8825 else
8826 {
8827 if($Interface ne $RemovedVFunc) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008828 next;
8829 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008830 }
8831 my $VPos_Removed = $VirtualTable{1}{$CName}{$RemovedVFunc};
8832 my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
8833 if($VPos_Removed<=$VPos_Old and $VPos_Old!=$VPos_New)
8834 {
8835 my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
8836 foreach my $ASymbol (@Affected)
8837 {
8838 if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"}
8839 and not link_symbol($ASymbol, 1, "-Deps")) {
8840 next;
8841 }
8842 my $ProblemType = "Removed_Virtual_Method";
8843 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) {
8844 $ProblemType = "Removed_Pure_Virtual_Method";
8845 }
8846 $CheckedSymbols{$Level}{$ASymbol} = 1;
8847 %{$CompatProblems{$Level}{$ASymbol}{$ProblemType}{$tr_name{$RemovedVFunc}}}=(
8848 "Type_Name"=>$CName,
8849 "Type_Type"=>"Class",
8850 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008851 $VTableChanged_M{get_TypeName($CompleteSignature{1}{$ASymbol}{"Class"}, 1)} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008852 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008853 }
8854 }
8855 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008856 }
8857 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008858 else
8859 { # Source-level
8860 foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$Level}{$CName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008861 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008862 next if($Interface eq $AddedVFunc);
8863 if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008864 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04008865 %{$CompatProblems{$Level}{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
8866 "Type_Name"=>$CName,
8867 "Type_Type"=>"Class",
8868 "Target"=>get_Signature($AddedVFunc, 2) );
8869 }
8870 }
8871 foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$Level}{$CName}}))
8872 {
8873 if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
8874 {
8875 %{$CompatProblems{$Level}{$Interface}{"Removed_Pure_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
8876 "Type_Name"=>$CName,
8877 "Type_Type"=>"Class",
8878 "Target"=>get_Signature($RemovedVFunc, 1) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008879 }
8880 }
8881 }
8882}
8883
8884sub find_MemberPair_Pos_byName($$)
8885{
8886 my ($Member_Name, $Pair_Type) = @_;
8887 $Member_Name=~s/\A[_]+|[_]+\Z//g;
8888 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
8889 {
8890 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos})
8891 {
8892 my $Name = $Pair_Type->{"Memb"}{$MemberPair_Pos}{"name"};
8893 $Name=~s/\A[_]+|[_]+\Z//g;
8894 if($Name eq $Member_Name) {
8895 return $MemberPair_Pos;
8896 }
8897 }
8898 }
8899 return "lost";
8900}
8901
8902sub find_MemberPair_Pos_byVal($$)
8903{
8904 my ($Member_Value, $Pair_Type) = @_;
8905 foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
8906 {
8907 if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos}
8908 and $Pair_Type->{"Memb"}{$MemberPair_Pos}{"value"} eq $Member_Value) {
8909 return $MemberPair_Pos;
8910 }
8911 }
8912 return "lost";
8913}
8914
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008915my %Severity_Val=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008916 "High"=>3,
8917 "Medium"=>2,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008918 "Low"=>1,
8919 "Safe"=>-1
8920);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008921
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008922sub maxSeverity($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008923{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008924 my ($S1, $S2) = @_;
8925 if(cmpSeverities($S1, $S2)) {
8926 return $S1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008927 }
8928 else {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008929 return $S2;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008930 }
8931}
8932
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008933sub cmpSeverities($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008934{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04008935 my ($S1, $S2) = @_;
8936 if(not $S1) {
8937 return 0;
8938 }
8939 elsif(not $S2) {
8940 return 1;
8941 }
8942 return ($Severity_Val{$S1}>$Severity_Val{$S2});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008943}
8944
8945sub getProblemSeverity($$)
8946{
8947 my ($Level, $Kind) = @_;
8948 return $CompatRules{$Level}{$Kind}{"Severity"};
8949}
8950
8951sub isRecurType($$$$)
8952{
8953 foreach (@RecurTypes)
8954 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008955 if( $_->{"1"} eq $_[0]
8956 and $_->{"2"} eq $_[1]
8957 and $_->{"3"} eq $_[2]
8958 and $_->{"4"} eq $_[3] )
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008959 {
8960 return 1;
8961 }
8962 }
8963 return 0;
8964}
8965
8966sub pushType($$$$)
8967{
8968 my %TypeIDs=(
Andrey Ponomarenko16934472012-03-29 15:37:04 +04008969 "1" => $_[0], #Tid1
8970 "2" => $_[1], #TDid1
8971 "3" => $_[2], #Tid2
8972 "4" => $_[3] #TDid2
8973 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04008974 push(@RecurTypes, \%TypeIDs);
8975}
8976
8977sub isRenamed($$$$$)
8978{
8979 my ($MemPos, $Type1, $LVersion1, $Type2, $LVersion2) = @_;
8980 my $Member_Name = $Type1->{"Memb"}{$MemPos}{"name"};
8981 my $MemberType_Id = $Type1->{"Memb"}{$MemPos}{"type"};
8982 my %MemberType_Pure = get_PureType($Tid_TDid{$LVersion1}{$MemberType_Id}, $MemberType_Id, $LVersion1);
8983 if(not defined $Type2->{"Memb"}{$MemPos}) {
8984 return "";
8985 }
8986 my $StraightPairType_Id = $Type2->{"Memb"}{$MemPos}{"type"};
8987 my %StraightPairType_Pure = get_PureType($Tid_TDid{$LVersion2}{$StraightPairType_Id}, $StraightPairType_Id, $LVersion2);
8988
8989 my $StraightPair_Name = $Type2->{"Memb"}{$MemPos}{"name"};
8990 my $MemberPair_Pos_Rev = ($Member_Name eq $StraightPair_Name)?$MemPos:find_MemberPair_Pos_byName($StraightPair_Name, $Type1);
8991 if($MemberPair_Pos_Rev eq "lost")
8992 {
8993 if($MemberType_Pure{"Name"} eq $StraightPairType_Pure{"Name"})
8994 {# base type match
8995 return $StraightPair_Name;
8996 }
8997 if(get_TypeName($MemberType_Id, $LVersion1) eq get_TypeName($StraightPairType_Id, $LVersion2))
8998 {# exact type match
8999 return $StraightPair_Name;
9000 }
9001 if($MemberType_Pure{"Size"} eq $StraightPairType_Pure{"Size"})
9002 {# size match
9003 return $StraightPair_Name;
9004 }
9005 if(isReserved($StraightPair_Name))
9006 {# reserved fields
9007 return $StraightPair_Name;
9008 }
9009 }
9010 return "";
9011}
9012
9013sub isLastElem($$)
9014{
9015 my ($Pos, $TypeRef) = @_;
9016 my $Name = $TypeRef->{"Memb"}{$Pos}{"name"};
9017 if($Name=~/last|count|max|total/i)
9018 { # GST_LEVEL_COUNT, GST_RTSP_ELAST
9019 return 1;
9020 }
9021 elsif($Name=~/END|NLIMITS\Z/)
9022 { # __RLIMIT_NLIMITS
9023 return 1;
9024 }
9025 elsif($Name=~/\AN[A-Z](.+)[a-z]+s\Z/
9026 and $Pos+1==keys(%{$TypeRef->{"Memb"}}))
9027 { # NImageFormats, NColorRoles
9028 return 1;
9029 }
9030 return 0;
9031}
9032
9033sub nonComparable($$)
9034{
9035 my ($T1, $T2) = @_;
9036 if($T1->{"Name"} ne $T2->{"Name"}
9037 and not isAnon($T1->{"Name"})
9038 and not isAnon($T2->{"Name"}))
9039 { # different names
9040 if($T1->{"Type"} ne "Pointer"
9041 or $T2->{"Type"} ne "Pointer")
9042 { # compare base types
9043 return 1;
9044 }
9045 if($T1->{"Name"}!~/\Avoid\s*\*/
9046 and $T2->{"Name"}=~/\Avoid\s*\*/)
9047 {
9048 return 1;
9049 }
9050 }
9051 elsif($T1->{"Type"} ne $T2->{"Type"})
9052 { # different types
9053 if($T1->{"Type"} eq "Class"
9054 and $T2->{"Type"} eq "Struct")
9055 { # "class" to "struct"
9056 return 0;
9057 }
9058 elsif($T2->{"Type"} eq "Class"
9059 and $T1->{"Type"} eq "Struct")
9060 { # "struct" to "class"
9061 return 0;
9062 }
9063 else
9064 { # "class" to "enum"
9065 # "union" to "class"
9066 # ...
9067 return 1;
9068 }
9069 }
9070 return 0;
9071}
9072
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009073sub mergeTypes($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009074{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009075 my ($Type1_Id, $Type1_DId, $Type2_Id, $Type2_DId, $Level) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009076 return () if((not $Type1_Id and not $Type1_DId) or (not $Type2_Id and not $Type2_DId));
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009077 $Type1_DId = "" if(not defined $Type1_DId);
9078 $Type2_DId = "" if(not defined $Type2_DId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009079 my (%Sub_SubProblems, %SubProblems) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009080 if($Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type1_DId}{$Type2_Id}{$Type2_DId})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009081 { # already merged
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009082 return %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type1_DId}{$Type2_Id}{$Type2_DId}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009083 }
9084 my %Type1 = get_Type($Type1_DId, $Type1_Id, 1);
9085 my %Type2 = get_Type($Type2_DId, $Type2_Id, 2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009086 if(not $Type1{"Name"} or not $Type2{"Name"}) {
9087 return ();
9088 }
9089 $CheckedTypes{$Level}{$Type1{"Name"}}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009090 my %Type1_Pure = get_PureType($Type1_DId, $Type1_Id, 1);
9091 my %Type2_Pure = get_PureType($Type2_DId, $Type2_Id, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009092 $CheckedTypes{$Level}{$Type1_Pure{"Name"}}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009093 return () if(not $Type1_Pure{"Size"} or not $Type2_Pure{"Size"});
9094 if(isRecurType($Type1_Pure{"Tid"}, $Type1_Pure{"TDid"}, $Type2_Pure{"Tid"}, $Type2_Pure{"TDid"}))
9095 { # skip recursive declarations
9096 return ();
9097 }
9098 return () if(not $Type1_Pure{"Name"} or not $Type2_Pure{"Name"});
9099 return () if($SkipTypes{1}{$Type1_Pure{"Name"}});
9100 return () if($SkipTypes{1}{$Type1{"Name"}});
9101
9102 my %Typedef_1 = goToFirst($Type1{"TDid"}, $Type1{"Tid"}, 1, "Typedef");
9103 my %Typedef_2 = goToFirst($Type2{"TDid"}, $Type2{"Tid"}, 2, "Typedef");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009104 if(not $UseOldDumps and %Typedef_1 and %Typedef_2
9105 and $Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef"
9106 and $Typedef_1{"Name"} eq $Typedef_2{"Name"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009107 {
9108 my %Base_1 = get_OneStep_BaseType($Typedef_1{"TDid"}, $Typedef_1{"Tid"}, 1);
9109 my %Base_2 = get_OneStep_BaseType($Typedef_2{"TDid"}, $Typedef_2{"Tid"}, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009110 if(differentDumps("G")
9111 or differentDumps("V"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009112 { # different GCC versions or different dumps
9113 $Base_1{"Name"} = uncover_typedefs($Base_1{"Name"}, 1);
9114 $Base_2{"Name"} = uncover_typedefs($Base_2{"Name"}, 2);
9115 # std::__va_list and __va_list
9116 $Base_1{"Name"}=~s/\A(\w+::)+//;
9117 $Base_2{"Name"}=~s/\A(\w+::)+//;
9118 $Base_1{"Name"} = formatName($Base_1{"Name"});
9119 $Base_2{"Name"} = formatName($Base_2{"Name"});
9120 }
9121 if($Base_1{"Name"}!~/anon\-/ and $Base_2{"Name"}!~/anon\-/
9122 and $Base_1{"Name"} ne $Base_2{"Name"})
9123 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009124 if($Level eq "Binary"
9125 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009126 {
9127 %{$SubProblems{"DataType_Size"}{$Typedef_1{"Name"}}}=(
9128 "Target"=>$Typedef_1{"Name"},
9129 "Type_Name"=>$Typedef_1{"Name"},
9130 "Type_Type"=>"Typedef",
9131 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
9132 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE );
9133 }
9134 %{$SubProblems{"Typedef_BaseType"}{$Typedef_1{"Name"}}}=(
9135 "Target"=>$Typedef_1{"Name"},
9136 "Type_Name"=>$Typedef_1{"Name"},
9137 "Type_Type"=>"Typedef",
9138 "Old_Value"=>$Base_1{"Name"},
9139 "New_Value"=>$Base_2{"Name"} );
9140 }
9141 }
9142 if(nonComparable(\%Type1_Pure, \%Type2_Pure))
9143 { # different types (reported in detectTypeChange(...))
9144 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
9145 and $Type1_Pure{"Type"} ne $Type2_Pure{"Type"}
9146 and $Type1_Pure{"Type"}!~/Intrinsic|Pointer|Ref|Typedef/)
9147 { # different type of the type
9148 %{$SubProblems{"DataType_Type"}{$Type1_Pure{"Name"}}}=(
9149 "Target"=>$Type1_Pure{"Name"},
9150 "Type_Name"=>$Type1_Pure{"Name"},
9151 "Type_Type"=>$Type1_Pure{"Type"},
9152 "Old_Value"=>lc($Type1_Pure{"Type"}),
9153 "New_Value"=>lc($Type2_Pure{"Type"}) );
9154 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009155 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type1_DId}{$Type2_Id}{$Type2_DId}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009156 return %SubProblems;
9157 }
9158 pushType($Type1_Pure{"Tid"}, $Type1_Pure{"TDid"},
9159 $Type2_Pure{"Tid"}, $Type2_Pure{"TDid"});
9160 if(($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
9161 or (isAnon($Type1_Pure{"Name"}) and isAnon($Type2_Pure{"Name"})))
9162 and $Type1_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
9163 { # checking size
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009164 if($Level eq "Binary"
9165 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009166 {
9167 my $ProblemKind = "DataType_Size";
9168 if($Type1_Pure{"Type"} eq "Class"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009169 and keys(%{$ClassMethods{$Level}{1}{$Type1_Pure{"Name"}}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009170 {
9171 if(isCopyingClass($Type1_Pure{"Tid"}, 1)) {
9172 $ProblemKind = "Size_Of_Copying_Class";
9173 }
9174 elsif($AllocableClass{1}{$Type1_Pure{"Name"}})
9175 {
9176 if(int($Type2_Pure{"Size"})>int($Type1_Pure{"Size"})) {
9177 $ProblemKind = "Size_Of_Allocable_Class_Increased";
9178 }
9179 else {
9180 # descreased size of allocable class
9181 # it has no special effects
9182 }
9183 }
9184 }
9185 %{$SubProblems{$ProblemKind}{$Type1_Pure{"Name"}}}=(
9186 "Target"=>$Type1_Pure{"Name"},
9187 "Type_Name"=>$Type1_Pure{"Name"},
9188 "Type_Type"=>$Type1_Pure{"Type"},
9189 "Old_Size"=>$Type1_Pure{"Size"}*$BYTE_SIZE,
9190 "New_Size"=>$Type2_Pure{"Size"}*$BYTE_SIZE,
9191 "InitialType_Type"=>$Type1_Pure{"Type"} );
9192 }
9193 }
9194 if($Type1_Pure{"BaseType"}{"Tid"} and $Type2_Pure{"BaseType"}{"Tid"})
9195 {# checking base types
9196 %Sub_SubProblems = mergeTypes($Type1_Pure{"BaseType"}{"Tid"}, $Type1_Pure{"BaseType"}{"TDid"},
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009197 $Type2_Pure{"BaseType"}{"Tid"}, $Type2_Pure{"BaseType"}{"TDid"}, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009198 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
9199 {
9200 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
9201 {
9202 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
9203 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
9204 }
9205 $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{"InitialType_Type"} = $Type1_Pure{"Type"};
9206 }
9207 }
9208 }
9209 my (%AddedField, %RemovedField, %RenamedField, %RenamedField_Rev, %RelatedField, %RelatedField_Rev) = ();
9210 my %NameToPosA = map {$Type1_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type1_Pure{"Memb"}});
9211 my %NameToPosB = map {$Type2_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type2_Pure{"Memb"}});
9212 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
9213 { # detect removed and renamed fields
9214 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
9215 next if(not $Member_Name);
9216 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);
9217 if($MemberPair_Pos eq "lost")
9218 {
9219 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
9220 {
9221 if(isUnnamed($Member_Name))
9222 { # support for old-version dumps
9223 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009224 if(not checkDumpVersion(2, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009225 next;
9226 }
9227 }
9228 if(my $RenamedTo = isRenamed($Member_Pos, \%Type1_Pure, 1, \%Type2_Pure, 2))
9229 { # renamed
9230 $RenamedField{$Member_Pos}=$RenamedTo;
9231 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
9232 }
9233 else
9234 { # removed
9235 $RemovedField{$Member_Pos}=1;
9236 }
9237 }
9238 elsif($Type1_Pure{"Type"} eq "Enum")
9239 {
9240 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
9241 next if($Member_Value1 eq "");
9242 $MemberPair_Pos = find_MemberPair_Pos_byVal($Member_Value1, \%Type2_Pure);
9243 if($MemberPair_Pos ne "lost")
9244 { # renamed
9245 my $RenamedTo = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"name"};
9246 my $MemberPair_Pos_Rev = find_MemberPair_Pos_byName($RenamedTo, \%Type1_Pure);
9247 if($MemberPair_Pos_Rev eq "lost")
9248 {
9249 $RenamedField{$Member_Pos}=$RenamedTo;
9250 $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
9251 }
9252 else {
9253 $RemovedField{$Member_Pos}=1;
9254 }
9255 }
9256 else
9257 { # removed
9258 $RemovedField{$Member_Pos}=1;
9259 }
9260 }
9261 }
9262 else
9263 { # related
9264 $RelatedField{$Member_Pos} = $MemberPair_Pos;
9265 $RelatedField_Rev{$MemberPair_Pos} = $Member_Pos;
9266 }
9267 }
9268 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
9269 { # detect added fields
9270 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
9271 next if(not $Member_Name);
9272 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);
9273 if($MemberPair_Pos eq "lost")
9274 {
9275 if(isUnnamed($Member_Name))
9276 { # support for old-version dumps
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009277 # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
9278 if(not checkDumpVersion(1, "2.1")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009279 next;
9280 }
9281 }
9282 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union|Enum)\Z/)
9283 {
9284 if(not $RenamedField_Rev{$Member_Pos})
9285 { # added
9286 $AddedField{$Member_Pos}=1;
9287 }
9288 }
9289 }
9290 }
9291 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
9292 { # detect moved fields
9293 my (%RelPos, %RelPosName, %AbsPos) = ();
9294 my $Pos = 0;
9295 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
9296 { # relative positions in 1st version
9297 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
9298 next if(not $Member_Name);
9299 if(not $RemovedField{$Member_Pos})
9300 { # old type without removed fields
9301 $RelPos{1}{$Member_Name}=$Pos;
9302 $RelPosName{1}{$Pos} = $Member_Name;
9303 $AbsPos{1}{$Pos++} = $Member_Pos;
9304 }
9305 }
9306 $Pos = 0;
9307 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
9308 { # relative positions in 2nd version
9309 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
9310 next if(not $Member_Name);
9311 if(not $AddedField{$Member_Pos})
9312 { # new type without added fields
9313 $RelPos{2}{$Member_Name}=$Pos;
9314 $RelPosName{2}{$Pos} = $Member_Name;
9315 $AbsPos{2}{$Pos++} = $Member_Pos;
9316 }
9317 }
9318 foreach my $Member_Name (keys(%{$RelPos{1}}))
9319 {
9320 my $RPos1 = $RelPos{1}{$Member_Name};
9321 my $AbsPos1 = $NameToPosA{$Member_Name};
9322 my $Member_Name2 = $Member_Name;
9323 if(my $RenamedTo = $RenamedField{$AbsPos1})
9324 { # renamed
9325 $Member_Name2 = $RenamedTo;
9326 }
9327 my $RPos2 = $RelPos{2}{$Member_Name2};
9328 if($RPos2 ne "" and $RPos1 ne $RPos2)
9329 { # different relative positions
9330 my $AbsPos2 = $NameToPosB{$Member_Name2};
9331 if($AbsPos1 ne $AbsPos2)
9332 { # different absolute positions
9333 my $ProblemType = "Moved_Field";
9334 if(not isPublic(\%Type1_Pure, $AbsPos1))
9335 { # may change layout and size of type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009336 if($Level eq "Source") {
9337 next;
9338 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009339 $ProblemType = "Moved_Private_Field";
9340 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009341 if($Level eq "Binary"
9342 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009343 { # affected size
9344 my $MemSize1 = get_TypeSize($Type1_Pure{"Memb"}{$AbsPos1}{"type"}, 1);
9345 my $MovedAbsPos = $AbsPos{1}{$RPos2};
9346 my $MemSize2 = get_TypeSize($Type1_Pure{"Memb"}{$MovedAbsPos}{"type"}, 1);
9347 if($MemSize1 ne $MemSize2) {
9348 $ProblemType .= "_And_Size";
9349 }
9350 }
9351 if($ProblemType eq "Moved_Private_Field") {
9352 next;
9353 }
9354 %{$SubProblems{$ProblemType}{$Member_Name}}=(
9355 "Target"=>$Member_Name,
9356 "Type_Name"=>$Type1_Pure{"Name"},
9357 "Type_Type"=>$Type1_Pure{"Type"},
9358 "Old_Value"=>$RPos1,
9359 "New_Value"=>$RPos2 );
9360 }
9361 }
9362 }
9363 }
9364 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009365 { # check older fields, public and private
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009366 my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
9367 next if(not $Member_Name);
9368 if(my $RenamedTo = $RenamedField{$Member_Pos})
9369 { # renamed
9370 if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
9371 {
9372 if(isPublic(\%Type1_Pure, $Member_Pos))
9373 {
9374 %{$SubProblems{"Renamed_Field"}{$Member_Name}}=(
9375 "Target"=>$Member_Name,
9376 "Type_Name"=>$Type1_Pure{"Name"},
9377 "Type_Type"=>$Type1_Pure{"Type"},
9378 "Old_Value"=>$Member_Name,
9379 "New_Value"=>$RenamedTo );
9380 }
9381 }
9382 elsif($Type1_Pure{"Type"} eq "Enum")
9383 {
9384 %{$SubProblems{"Enum_Member_Name"}{$Type1_Pure{"Memb"}{$Member_Pos}{"value"}}}=(
9385 "Target"=>$Type1_Pure{"Memb"}{$Member_Pos}{"value"},
9386 "Type_Name"=>$Type1_Pure{"Name"},
9387 "Type_Type"=>$Type1_Pure{"Type"},
9388 "Old_Value"=>$Member_Name,
9389 "New_Value"=>$RenamedTo );
9390 }
9391 }
9392 elsif($RemovedField{$Member_Pos})
9393 { # removed
9394 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
9395 {
9396 my $ProblemType = "Removed_Field";
9397 if(not isPublic(\%Type1_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009398 or isUnnamed($Member_Name))
9399 {
9400 if($Level eq "Source") {
9401 next;
9402 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009403 $ProblemType = "Removed_Private_Field";
9404 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009405 if($Level eq "Binary"
9406 and not isMemPadded($Member_Pos, -1, \%Type1_Pure, \%RemovedField, 1))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009407 {
9408 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
9409 { # affected fields
9410 if(getOffset($MNum-1, \%Type1_Pure, 1)!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, 2))
9411 { # changed offset
9412 $ProblemType .= "_And_Layout";
9413 }
9414 }
9415 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
9416 { # affected size
9417 $ProblemType .= "_And_Size";
9418 }
9419 }
9420 if($ProblemType eq "Removed_Private_Field") {
9421 next;
9422 }
9423 %{$SubProblems{$ProblemType}{$Member_Name}}=(
9424 "Target"=>$Member_Name,
9425 "Type_Name"=>$Type1_Pure{"Name"},
9426 "Type_Type"=>$Type1_Pure{"Type"} );
9427 }
9428 elsif($Type2_Pure{"Type"} eq "Union")
9429 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009430 if($Level eq "Binary"
9431 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009432 {
9433 %{$SubProblems{"Removed_Union_Field_And_Size"}{$Member_Name}}=(
9434 "Target"=>$Member_Name,
9435 "Type_Name"=>$Type1_Pure{"Name"},
9436 "Type_Type"=>$Type1_Pure{"Type"} );
9437 }
9438 else
9439 {
9440 %{$SubProblems{"Removed_Union_Field"}{$Member_Name}}=(
9441 "Target"=>$Member_Name,
9442 "Type_Name"=>$Type1_Pure{"Name"},
9443 "Type_Type"=>$Type1_Pure{"Type"} );
9444 }
9445 }
9446 elsif($Type1_Pure{"Type"} eq "Enum")
9447 {
9448 %{$SubProblems{"Enum_Member_Removed"}{$Member_Name}}=(
9449 "Target"=>$Member_Name,
9450 "Type_Name"=>$Type1_Pure{"Name"},
9451 "Type_Type"=>$Type1_Pure{"Type"},
9452 "Old_Value"=>$Member_Name );
9453 }
9454 }
9455 else
9456 { # changed
9457 my $MemberPair_Pos = $RelatedField{$Member_Pos};
9458 if($Type1_Pure{"Type"} eq "Enum")
9459 {
9460 my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
9461 next if($Member_Value1 eq "");
9462 my $Member_Value2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"value"};
9463 next if($Member_Value2 eq "");
9464 if($Member_Value1 ne $Member_Value2)
9465 {
9466 my $ProblemType = "Enum_Member_Value";
9467 if(isLastElem($Member_Pos, \%Type1_Pure)) {
9468 $ProblemType = "Enum_Last_Member_Value";
9469 }
9470 %{$SubProblems{$ProblemType}{$Member_Name}}=(
9471 "Target"=>$Member_Name,
9472 "Type_Name"=>$Type1_Pure{"Name"},
9473 "Type_Type"=>$Type1_Pure{"Type"},
9474 "Old_Value"=>$Member_Value1,
9475 "New_Value"=>$Member_Value2 );
9476 }
9477 }
9478 elsif($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
9479 {
9480 my $MemberType1_Id = $Type1_Pure{"Memb"}{$Member_Pos}{"type"};
9481 my $MemberType2_Id = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"type"};
9482 my $SizeV1 = get_TypeSize($MemberType1_Id, 1)*$BYTE_SIZE;
9483 if(my $BSize1 = $Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}) {
9484 $SizeV1 = $BSize1;
9485 }
9486 my $SizeV2 = get_TypeSize($MemberType2_Id, 2)*$BYTE_SIZE;
9487 if(my $BSize2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}) {
9488 $SizeV2 = $BSize2;
9489 }
9490 my $MemberType1_Name = get_TypeName($MemberType1_Id, 1);
9491 my $MemberType2_Name = get_TypeName($MemberType2_Id, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009492 if($Level eq "Binary"
9493 and $SizeV1 ne $SizeV2)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009494 {
9495 if($MemberType1_Name eq $MemberType2_Name or (isAnon($MemberType1_Name) and isAnon($MemberType2_Name))
9496 or ($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"} and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}))
9497 { # field size change (including anon-structures and unions)
9498 # - same types
9499 # - unnamed types
9500 # - bitfields
9501 my $ProblemType = "Field_Size";
9502 if(not isPublic(\%Type1_Pure, $Member_Pos)
9503 or isUnnamed($Member_Name))
9504 { # should not be accessed by applications, goes to "Low Severity"
9505 # example: "abidata" members in GStreamer types
9506 $ProblemType = "Private_".$ProblemType;
9507 }
9508 if(not isMemPadded($Member_Pos, get_TypeSize($MemberType2_Id, 2)*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, 1))
9509 { # check an effect
9510 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
9511 { # public fields after the current
9512 if(getOffset($MNum-1, \%Type1_Pure, 1)!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, 2))
9513 { # changed offset
9514 $ProblemType .= "_And_Layout";
9515 }
9516 }
9517 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
9518 $ProblemType .= "_And_Type_Size";
9519 }
9520 }
9521 if($ProblemType eq "Private_Field_Size")
9522 { # private field size with no effect
9523 $ProblemType = "";
9524 }
9525 if($ProblemType)
9526 { # register a problem
9527 %{$SubProblems{$ProblemType}{$Member_Name}}=(
9528 "Target"=>$Member_Name,
9529 "Type_Name"=>$Type1_Pure{"Name"},
9530 "Type_Type"=>$Type1_Pure{"Type"},
9531 "Old_Size"=>$SizeV1,
9532 "New_Size"=>$SizeV2);
9533 }
9534 }
9535 }
9536 if($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}
9537 or $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"})
9538 { # do NOT check bitfield type changes
9539 next;
9540 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009541 %Sub_SubProblems = detectTypeChange($MemberType1_Id, $MemberType2_Id, "Field", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009542 foreach my $ProblemType (keys(%Sub_SubProblems))
9543 {
9544 my $Old_Value = $Sub_SubProblems{$ProblemType}{"Old_Value"};
9545 my $New_Value = $Sub_SubProblems{$ProblemType}{"New_Value"};
9546 if($ProblemType eq "Field_Type"
9547 or $ProblemType eq "Field_Type_And_Size")
9548 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009549 if(checkDumpVersion(1, "2.6") and checkDumpVersion(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009550 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009551 if($Level eq "Binary")
9552 {
9553 if($Old_Value!~/(\A|\W)volatile(\W|\Z)/
9554 and $New_Value=~/(\A|\W)volatile(\W|\Z)/)
9555 { # non-"volatile" to "volatile"
9556 %{$Sub_SubProblems{"Field_Became_Volatile"}} = %{$Sub_SubProblems{$ProblemType}};
9557 }
9558 elsif($Old_Value=~/(\A|\W)volatile(\W|\Z)/
9559 and $New_Value!~/(\A|\W)volatile(\W|\Z)/)
9560 { # non-"volatile" to "volatile"
9561 %{$Sub_SubProblems{"Field_Became_NonVolatile"}} = %{$Sub_SubProblems{$ProblemType}};
9562 }
9563 }
9564 else
9565 { # Source
9566 if(removedQual($New_Value, $Old_Value, "volatile"))
9567 { # non-"volatile" to "volatile"
9568 %{$Sub_SubProblems{"Field_Became_Volatile"}} = %{$Sub_SubProblems{$ProblemType}};
9569 delete($Sub_SubProblems{$ProblemType});
9570 }
9571 elsif(removedQual($Old_Value, $New_Value, "volatile"))
9572 { # non-"volatile" to "volatile"
9573 %{$Sub_SubProblems{"Field_Became_NonVolatile"}} = %{$Sub_SubProblems{$ProblemType}};
9574 delete($Sub_SubProblems{$ProblemType});
9575 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009576 }
9577 }
9578 }
9579 }
9580 foreach my $ProblemType (keys(%Sub_SubProblems))
9581 {
9582 my $ProblemType_Init = $ProblemType;
9583 if($ProblemType eq "Field_Type_And_Size")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009584 { # Binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009585 if(not isPublic(\%Type1_Pure, $Member_Pos)
9586 or isUnnamed($Member_Name)) {
9587 $ProblemType = "Private_".$ProblemType;
9588 }
9589 if(not isMemPadded($Member_Pos, get_TypeSize($MemberType2_Id, 2)*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, 1))
9590 { # check an effect
9591 if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
9592 { # public fields after the current
9593 if(getOffset($MNum-1, \%Type1_Pure, 1)!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, 2))
9594 { # changed offset
9595 $ProblemType .= "_And_Layout";
9596 }
9597 }
9598 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
9599 $ProblemType .= "_And_Type_Size";
9600 }
9601 }
9602 }
9603 else
9604 {
9605 if(not isPublic(\%Type1_Pure, $Member_Pos)
9606 or isUnnamed($Member_Name)) {
9607 next;
9608 }
9609 }
9610 if($ProblemType eq "Private_Field_Type_And_Size")
9611 { # private field change with no effect
9612 next;
9613 }
9614 %{$SubProblems{$ProblemType}{$Member_Name}}=(
9615 "Target"=>$Member_Name,
9616 "Type_Name"=>$Type1_Pure{"Name"},
9617 "Type_Type"=>$Type1_Pure{"Type"} );
9618 foreach my $Attr (keys(%{$Sub_SubProblems{$ProblemType_Init}}))
9619 { # other properties
9620 $SubProblems{$ProblemType}{$Member_Name}{$Attr} = $Sub_SubProblems{$ProblemType_Init}{$Attr};
9621 }
9622 }
9623 if(not isPublic(\%Type1_Pure, $Member_Pos))
9624 { # do NOT check internal type changes
9625 next;
9626 }
9627 if($MemberType1_Id and $MemberType2_Id)
9628 {# checking member type changes (replace)
9629 %Sub_SubProblems = mergeTypes($MemberType1_Id, $Tid_TDid{1}{$MemberType1_Id},
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009630 $MemberType2_Id, $Tid_TDid{2}{$MemberType2_Id}, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009631 foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
9632 {
9633 foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
9634 {
9635 my $NewLocation = ($Sub_SubLocation)?$Member_Name."->".$Sub_SubLocation:$Member_Name;
9636 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"IsInTypeInternals"}=1;
9637 foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
9638 $SubProblems{$Sub_SubProblemType}{$NewLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
9639 }
9640 if($Sub_SubLocation!~/\-\>/) {
9641 $SubProblems{$Sub_SubProblemType}{$NewLocation}{"Start_Type_Name"} = $MemberType1_Name;
9642 }
9643 }
9644 }
9645 }
9646 }
9647 }
9648 }
9649 foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
9650 { # checking added members, public and private
9651 my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
9652 next if(not $Member_Name);
9653 if($AddedField{$Member_Pos})
9654 { # added
9655 if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
9656 {
9657 my $ProblemType = "Added_Field";
9658 if(not isPublic(\%Type2_Pure, $Member_Pos)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009659 or isUnnamed($Member_Name))
9660 {
9661 if($Level eq "Source") {
9662 next;
9663 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009664 $ProblemType = "Added_Private_Field";
9665 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009666 if($Level eq "Binary"
9667 and not isMemPadded($Member_Pos, -1, \%Type2_Pure, \%AddedField, 2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009668 {
9669 if(my $MNum = isAccessible(\%Type2_Pure, \%AddedField, $Member_Pos, -1))
9670 { # public fields after the current
9671 if(getOffset($MNum-1, \%Type2_Pure, 2)!=getOffset($RelatedField_Rev{$MNum-1}, \%Type1_Pure, 1))
9672 { # changed offset
9673 $ProblemType .= "_And_Layout";
9674 }
9675 }
9676 if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
9677 $ProblemType .= "_And_Size";
9678 }
9679 }
9680 if($ProblemType eq "Added_Private_Field")
9681 { # skip added private fields
9682 next;
9683 }
9684 %{$SubProblems{$ProblemType}{$Member_Name}}=(
9685 "Target"=>$Member_Name,
9686 "Type_Name"=>$Type1_Pure{"Name"},
9687 "Type_Type"=>$Type1_Pure{"Type"} );
9688 }
9689 elsif($Type2_Pure{"Type"} eq "Union")
9690 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009691 if($Level eq "Binary"
9692 and $Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009693 {
9694 %{$SubProblems{"Added_Union_Field_And_Size"}{$Member_Name}}=(
9695 "Target"=>$Member_Name,
9696 "Type_Name"=>$Type1_Pure{"Name"},
9697 "Type_Type"=>$Type1_Pure{"Type"} );
9698 }
9699 else
9700 {
9701 %{$SubProblems{"Added_Union_Field"}{$Member_Name}}=(
9702 "Target"=>$Member_Name,
9703 "Type_Name"=>$Type1_Pure{"Name"},
9704 "Type_Type"=>$Type1_Pure{"Type"} );
9705 }
9706 }
9707 elsif($Type2_Pure{"Type"} eq "Enum")
9708 {
9709 my $Member_Value = $Type2_Pure{"Memb"}{$Member_Pos}{"value"};
9710 next if($Member_Value eq "");
9711 %{$SubProblems{"Added_Enum_Member"}{$Member_Name}}=(
9712 "Target"=>$Member_Name,
9713 "Type_Name"=>$Type2_Pure{"Name"},
9714 "Type_Type"=>$Type2_Pure{"Type"},
9715 "New_Value"=>$Member_Value );
9716 }
9717 }
9718 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009719 %{$Cache{"mergeTypes"}{$Level}{$Type1_Id}{$Type1_DId}{$Type2_Id}{$Type2_DId}} = %SubProblems;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009720 pop(@RecurTypes);
9721 return %SubProblems;
9722}
9723
9724sub isUnnamed($) {
9725 return $_[0]=~/\Aunnamed\d+\Z/;
9726}
9727
9728sub get_TypeName($$)
9729{
9730 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009731 return get_TypeAttr($TypeId, $LibVersion, "Name");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009732}
9733
9734sub get_TypeSize($$)
9735{
9736 my ($TypeId, $LibVersion) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009737 return get_TypeAttr($TypeId, $LibVersion, "Size");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009738}
9739
9740sub get_TypeAttr($$$)
9741{
9742 my ($TypeId, $LibVersion, $Attr) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009743 return "" if(not defined $TypeId);
9744 if(not defined $Tid_TDid{$LibVersion}{$TypeId})
9745 { # correcting data
9746 $Tid_TDid{$LibVersion}{$TypeId} = "";
9747 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009748 return $TypeInfo{$LibVersion}{$Tid_TDid{$LibVersion}{$TypeId}}{$TypeId}{$Attr};
9749}
9750
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009751sub get_ShortType($$)
9752{
9753 my ($TypeId, $LibVersion) = @_;
9754 my $TypeName = get_TypeAttr($TypeId, $LibVersion, "Name");
9755 if(my $NameSpace = get_TypeAttr($TypeId, $LibVersion, "NameSpace")) {
9756 $TypeName=~s/\A$NameSpace\:\://g;
9757 }
9758 return $TypeName;
9759}
9760
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009761sub goToFirst($$$$)
9762{
9763 my ($TypeDId, $TypeId, $LibVersion, $Type_Type) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009764 return () if(not $TypeId);
9765 $TypeDId = "" if(not defined $TypeDId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009766 if(defined $Cache{"goToFirst"}{$TypeDId}{$TypeId}{$LibVersion}{$Type_Type}) {
9767 return %{$Cache{"goToFirst"}{$TypeDId}{$TypeId}{$LibVersion}{$Type_Type}};
9768 }
9769 return () if(not $TypeInfo{$LibVersion}{$TypeDId}{$TypeId});
9770 my %Type = %{$TypeInfo{$LibVersion}{$TypeDId}{$TypeId}};
9771 return () if(not $Type{"Type"});
9772 if($Type{"Type"} ne $Type_Type)
9773 {
9774 return () if(not $Type{"BaseType"}{"TDid"} and not $Type{"BaseType"}{"Tid"});
9775 %Type = goToFirst($Type{"BaseType"}{"TDid"}, $Type{"BaseType"}{"Tid"}, $LibVersion, $Type_Type);
9776 }
9777 $Cache{"goToFirst"}{$TypeDId}{$TypeId}{$LibVersion}{$Type_Type} = \%Type;
9778 return %Type;
9779}
9780
9781my %TypeSpecAttributes = (
9782 "Const" => 1,
9783 "Volatile" => 1,
9784 "ConstVolatile" => 1,
9785 "Restrict" => 1,
9786 "Typedef" => 1
9787);
9788
9789sub get_PureType($$$)
9790{
9791 my ($TypeDId, $TypeId, $LibVersion) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009792 return () if(not $TypeId);
9793 $TypeDId = "" if(not defined $TypeDId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009794 if(defined $Cache{"get_PureType"}{$TypeDId}{$TypeId}{$LibVersion}) {
9795 return %{$Cache{"get_PureType"}{$TypeDId}{$TypeId}{$LibVersion}};
9796 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009797 return () if(not $TypeInfo{$LibVersion}{$TypeDId}{$TypeId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009798 my %Type = %{$TypeInfo{$LibVersion}{$TypeDId}{$TypeId}};
9799 return %Type if(not $Type{"BaseType"}{"TDid"} and not $Type{"BaseType"}{"Tid"});
9800 if($TypeSpecAttributes{$Type{"Type"}}) {
9801 %Type = get_PureType($Type{"BaseType"}{"TDid"}, $Type{"BaseType"}{"Tid"}, $LibVersion);
9802 }
9803 $Cache{"get_PureType"}{$TypeDId}{$TypeId}{$LibVersion} = \%Type;
9804 return %Type;
9805}
9806
9807sub get_PointerLevel($$$)
9808{
9809 my ($TypeDId, $TypeId, $LibVersion) = @_;
9810 return 0 if(not $TypeId);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009811 $TypeDId = "" if(not defined $TypeDId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009812 if(defined $Cache{"get_PointerLevel"}{$TypeDId}{$TypeId}{$LibVersion}) {
9813 return $Cache{"get_PointerLevel"}{$TypeDId}{$TypeId}{$LibVersion};
9814 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009815 return 0 if(not $TypeInfo{$LibVersion}{$TypeDId}{$TypeId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009816 my %Type = %{$TypeInfo{$LibVersion}{$TypeDId}{$TypeId}};
9817 return 1 if($Type{"Type"}=~/FuncPtr|MethodPtr|FieldPtr/);
9818 return 0 if(not $Type{"BaseType"}{"TDid"} and not $Type{"BaseType"}{"Tid"});
9819 my $PointerLevel = 0;
9820 if($Type{"Type"} =~/Pointer|Ref|FuncPtr|MethodPtr|FieldPtr/) {
9821 $PointerLevel += 1;
9822 }
9823 $PointerLevel += get_PointerLevel($Type{"BaseType"}{"TDid"}, $Type{"BaseType"}{"Tid"}, $LibVersion);
9824 $Cache{"get_PointerLevel"}{$TypeDId}{$TypeId}{$LibVersion} = $PointerLevel;
9825 return $PointerLevel;
9826}
9827
9828sub get_BaseType($$$)
9829{
9830 my ($TypeDId, $TypeId, $LibVersion) = @_;
9831 return () if(not $TypeId);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009832 $TypeDId = "" if(not defined $TypeDId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009833 if(defined $Cache{"get_BaseType"}{$TypeDId}{$TypeId}{$LibVersion}) {
9834 return %{$Cache{"get_BaseType"}{$TypeDId}{$TypeId}{$LibVersion}};
9835 }
9836 return () if(not $TypeInfo{$LibVersion}{$TypeDId}{$TypeId});
9837 my %Type = %{$TypeInfo{$LibVersion}{$TypeDId}{$TypeId}};
9838 return %Type if(not $Type{"BaseType"}{"TDid"} and not $Type{"BaseType"}{"Tid"});
9839 %Type = get_BaseType($Type{"BaseType"}{"TDid"}, $Type{"BaseType"}{"Tid"}, $LibVersion);
9840 $Cache{"get_BaseType"}{$TypeDId}{$TypeId}{$LibVersion} = \%Type;
9841 return %Type;
9842}
9843
9844sub get_BaseTypeQual($$$)
9845{
9846 my ($TypeDId, $TypeId, $LibVersion) = @_;
9847 return "" if(not $TypeId);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009848 $TypeDId = "" if(not defined $TypeDId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009849 return "" if(not $TypeInfo{$LibVersion}{$TypeDId}{$TypeId});
9850 my %Type = %{$TypeInfo{$LibVersion}{$TypeDId}{$TypeId}};
9851 return "" if(not $Type{"BaseType"}{"TDid"} and not $Type{"BaseType"}{"Tid"});
9852 my $Qual = "";
9853 if($Type{"Type"} eq "Pointer") {
9854 $Qual .= "*";
9855 }
9856 elsif($Type{"Type"} eq "Ref") {
9857 $Qual .= "&";
9858 }
9859 elsif($Type{"Type"} eq "ConstVolatile") {
9860 $Qual .= "const volatile";
9861 }
9862 elsif($Type{"Type"} eq "Const"
9863 or $Type{"Type"} eq "Volatile"
9864 or $Type{"Type"} eq "Restrict") {
9865 $Qual .= lc($Type{"Type"});
9866 }
9867 my $BQual = get_BaseTypeQual($Type{"BaseType"}{"TDid"}, $Type{"BaseType"}{"Tid"}, $LibVersion);
9868 return $BQual.$Qual;
9869}
9870
9871sub get_OneStep_BaseType($$$)
9872{
9873 my ($TypeDId, $TypeId, $LibVersion) = @_;
9874 return () if(not $TypeId);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009875 $TypeDId = "" if(not defined $TypeDId);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009876 return () if(not $TypeInfo{$LibVersion}{$TypeDId}{$TypeId});
9877 my %Type = %{$TypeInfo{$LibVersion}{$TypeDId}{$TypeId}};
9878 if(not $Type{"BaseType"}{"TDid"}
9879 and not $Type{"BaseType"}{"Tid"}) {
9880 return %Type;
9881 }
9882 return get_Type($Type{"BaseType"}{"TDid"}, $Type{"BaseType"}{"Tid"}, $LibVersion);
9883}
9884
9885sub get_Type($$$)
9886{
9887 my ($TypeDId, $TypeId, $LibVersion) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +04009888 return () if(not $TypeId);
9889 $TypeDId = "" if(not defined $TypeDId);
9890 return () if(not $TypeInfo{$LibVersion}{$TypeDId}{$TypeId});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009891 return %{$TypeInfo{$LibVersion}{$TypeDId}{$TypeId}};
9892}
9893
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009894sub skipPrivateData($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009895{
9896 my $Symbol = $_[0];
9897 return ($Symbol=~/\A(_ZGV|_ZTI|_ZTS|_ZTT|_ZTV|_ZTC|_ZThn|_ZTv0_n)/);
9898}
9899
9900sub isTemplateInstance($)
9901{
9902 my $Symbol = $_[0];
9903 return 0 if($Symbol!~/\A(_Z|\?)/);
9904 my $Signature = $tr_name{$Symbol};
9905 return 0 if($Signature!~/>/);
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009906 my $ShortName = substr($Signature, 0, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009907 $ShortName=~s/::operator .*//;# class::operator template<instance>
9908 return ($ShortName=~/<.+>/);
9909}
9910
9911sub isTemplateSpec($$)
9912{
9913 my ($Symbol, $LibVersion) = @_;
9914 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
9915 {
9916 if(get_TypeAttr($ClassId, $LibVersion, "Spec"))
9917 { # class specialization
9918 return 1;
9919 }
9920 elsif($CompleteSignature{$LibVersion}{$Symbol}{"Spec"})
9921 { # method specialization
9922 return 1;
9923 }
9924 }
9925 return 0;
9926}
9927
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009928sub symbolFilter($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009929{ # some special cases when the symbol cannot be imported
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009930 my ($Symbol, $LibVersion, $Type, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +04009931 if(skipPrivateData($Symbol))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009932 { # non-public global data
9933 return 0;
9934 }
9935 if($CheckObjectsOnly) {
9936 return 0 if($Symbol=~/\A(_init|_fini)\Z/);
9937 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +04009938 if($CheckHeadersOnly and not checkDumpVersion($LibVersion, "2.7"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +04009939 { # support for old ABI dumps in --headers-only mode
9940 foreach my $Pos (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
9941 {
9942 if(my $Pid = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"})
9943 {
9944 my $PType = get_TypeAttr($Pid, $LibVersion, "Type");
9945 if(not $PType or $PType eq "Unknown") {
9946 return 0;
9947 }
9948 }
9949 }
9950 }
9951 if($Type=~/Imported/)
9952 {
9953 my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"};
9954 if(not $STDCXX_TESTING and $Symbol=~/\A(_ZS|_ZNS|_ZNKS)/)
9955 { # stdc++ interfaces
9956 return 0;
9957 }
9958 if($SkipSymbols{$LibVersion}{$Symbol})
9959 { # user defined symbols to ignore
9960 return 0;
9961 }
9962 my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"};
9963 if(not $NameSpace and $ClassId)
9964 { # class methods have no "NameSpace" attribute
9965 $NameSpace = get_TypeAttr($ClassId, $LibVersion, "NameSpace");
9966 }
9967 if($NameSpace)
9968 { # user defined namespaces to ignore
9969 if($SkipNameSpaces{$LibVersion}{$NameSpace}) {
9970 return 0;
9971 }
9972 foreach my $NS (keys(%{$SkipNameSpaces{$LibVersion}}))
9973 { # nested namespaces
9974 if($NameSpace=~/\A\Q$NS\E(\:\:|\Z)/) {
9975 return 0;
9976 }
9977 }
9978 }
9979 if(my $Header = $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
9980 {
9981 if(my $Skip = skip_header($Header, $LibVersion))
9982 { # --skip-headers or <skip_headers> (not <skip_including>)
9983 if($Skip==1) {
9984 return 0;
9985 }
9986 }
9987 if(not is_target_header($Header))
9988 { # --header, --headers-list
9989 return 0;
9990 }
9991 }
9992 if($SymbolsListPath and not $SymbolsList{$Symbol})
9993 { # user defined symbols
9994 return 0;
9995 }
9996 if($AppPath and not $SymbolsList_App{$Symbol})
9997 { # user defined symbols (in application)
9998 return 0;
9999 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010000 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010001 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010002 if($CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
10003 or (isTemplateInstance($Symbol) and not isTemplateSpec($Symbol, $LibVersion)))
10004 {
10005 if($ClassId and $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
10006 { # inline virtual methods
10007 if($Type=~/InlineVirtual/) {
10008 return 1;
10009 }
10010 my $Allocable = (not isCopyingClass($ClassId, $LibVersion));
10011 if(not $Allocable)
10012 { # check bases
10013 foreach my $DCId (get_sub_classes($ClassId, $LibVersion, 1))
10014 {
10015 if(not isCopyingClass($DCId, $LibVersion))
10016 { # exists a derived class without default c-tor
10017 $Allocable=1;
10018 last;
10019 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010020 }
10021 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010022 if(not $Allocable) {
10023 return 0;
10024 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010025 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010026 else
10027 { # inline non-virtual methods
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010028 return 0;
10029 }
10030 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010031 }
10032 }
10033 return 1;
10034}
10035
10036sub mergeImpl()
10037{
10038 my $DiffCmd = get_CmdPath("diff");
10039 if(not $DiffCmd) {
10040 exitStatus("Not_Found", "can't find \"diff\"");
10041 }
10042 foreach my $Interface (sort keys(%{$Symbol_Library{1}}))
10043 { # implementation changes
10044 next if($CompleteSignature{1}{$Interface}{"Private"});
10045 next if(not $CompleteSignature{1}{$Interface}{"Header"} and not $CheckObjectsOnly);
10046 next if(not $Symbol_Library{2}{$Interface} and not $Symbol_Library{2}{$SymVer{2}{$Interface}});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010047 next if(not symbolFilter($Interface, 1, "Imported", "Binary"));
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010048 my $Impl1 = canonifyImpl($Interface_Impl{1}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010049 next if(not $Impl1);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010050 my $Impl2 = canonifyImpl($Interface_Impl{2}{$Interface});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010051 next if(not $Impl2);
10052 if($Impl1 ne $Impl2)
10053 {
10054 writeFile("$TMP_DIR/impl1", $Impl1);
10055 writeFile("$TMP_DIR/impl2", $Impl2);
10056 my $Diff = `$DiffCmd -rNau $TMP_DIR/impl1 $TMP_DIR/impl2`;
10057 $Diff=~s/(---|\+\+\+).+\n//g;
10058 $Diff=~s/[ ]{3,}/ /g;
10059 $Diff=~s/\n\@\@/\n \n\@\@/g;
10060 unlink("$TMP_DIR/impl1", "$TMP_DIR/impl2");
10061 %{$ImplProblems{$Interface}}=(
10062 "Diff" => get_CodeView($Diff) );
10063 }
10064 }
10065}
10066
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010067sub canonifyImpl($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010068{
10069 my $FuncBody= $_[0];
10070 return "" if(not $FuncBody);
10071 $FuncBody=~s/0x[a-f\d]+/0x?/g;# addr
10072 $FuncBody=~s/((\A|\n)[a-z]+[\t ]+)[a-f\d]+([^x]|\Z)/$1?$3/g;# call, jump
10073 $FuncBody=~s/# [a-f\d]+ /# ? /g;# call, jump
10074 $FuncBody=~s/%([a-z]+[a-f\d]*)/\%reg/g;# registers
10075 while($FuncBody=~s/\nnop[ \t]*(\n|\Z)/$1/g){};# empty op
10076 $FuncBody=~s/<.+?\.cpp.+?>/<name.cpp>/g;
10077 $FuncBody=~s/(\A|\n)[a-f\d]+ </$1? </g;# 5e74 <_ZN...
10078 $FuncBody=~s/\.L\d+/.L/g;
10079 $FuncBody=~s/#(-?)\d+/#$1?/g;# r3, [r3, #120]
10080 $FuncBody=~s/[\n]{2,}/\n/g;
10081 return $FuncBody;
10082}
10083
10084sub get_CodeView($)
10085{
10086 my $Code = $_[0];
10087 my $View = "";
10088 foreach my $Line (split(/\n/, $Code))
10089 {
10090 if($Line=~s/\A(\+|-)/$1 /g)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010091 { # bold line
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010092 $View .= "<tr><td><b>".htmlSpecChars($Line)."</b></td></tr>\n";
10093 }
10094 else {
10095 $View .= "<tr><td>".htmlSpecChars($Line)."</td></tr>\n";
10096 }
10097 }
10098 return "<table class='code_view'>$View</table>\n";
10099}
10100
10101sub getImplementations($$)
10102{
10103 my ($LibVersion, $Path) = @_;
10104 return if(not $LibVersion or not -e $Path);
10105 if($OSgroup eq "macos")
10106 {
10107 my $OtoolCmd = get_CmdPath("otool");
10108 if(not $OtoolCmd) {
10109 exitStatus("Not_Found", "can't find \"otool\"");
10110 }
10111 my $CurInterface = "";
10112 foreach my $Line (split(/\n/, `$OtoolCmd -tv $Path 2>$TMP_DIR/null`))
10113 {
10114 if($Line=~/\A\s*_(\w+)\s*:/i) {
10115 $CurInterface = $1;
10116 }
10117 elsif($Line=~/\A\s*[\da-z]+\s+(.+?)\Z/i) {
10118 $Interface_Impl{$LibVersion}{$CurInterface} .= "$1\n";
10119 }
10120 }
10121 }
10122 else
10123 {
10124 my $ObjdumpCmd = get_CmdPath("objdump");
10125 if(not $ObjdumpCmd) {
10126 exitStatus("Not_Found", "can't find \"objdump\"");
10127 }
10128 my $CurInterface = "";
10129 foreach my $Line (split(/\n/, `$ObjdumpCmd -d $Path 2>$TMP_DIR/null`))
10130 {
10131 if($Line=~/\A[\da-z]+\s+<(\w+)>/i) {
10132 $CurInterface = $1;
10133 }
10134 else
10135 { # x86: 51fa:(\t)89 e5 (\t)mov %esp,%ebp
10136 # arm: 5020:(\t)e24cb004(\t)sub(\t)fp, ip, #4(\t); 0x4
10137 if($Line=~/\A\s*[a-f\d]+:\s+([a-f\d]+\s+)+([a-z]+\s+.*?)\s*(;.*|)\Z/i) {
10138 $Interface_Impl{$LibVersion}{$CurInterface} .= "$2\n";
10139 }
10140 }
10141 }
10142 }
10143}
10144
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010145sub detectAdded($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010146{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010147 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010148 foreach my $Symbol (keys(%{$Symbol_Library{2}}))
10149 {
10150 if(link_symbol($Symbol, 1, "+Deps"))
10151 { # linker can find a new symbol
10152 # in the old-version library
10153 # So, it's not a new symbol
10154 next;
10155 }
10156 if(my $VSym = $SymVer{2}{$Symbol}
10157 and $Symbol!~/\@/) {
10158 next;
10159 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010160 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010161 }
10162}
10163
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010164sub detectRemoved($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010165{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010166 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010167 foreach my $Symbol (keys(%{$Symbol_Library{1}}))
10168 {
10169 if($CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010170 $CheckedSymbols{"Binary"}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010171 }
10172 if(link_symbol($Symbol, 2, "+Deps"))
10173 { # linker can find an old symbol
10174 # in the new-version library
10175 next;
10176 }
10177 if(my $VSym = $SymVer{1}{$Symbol}
10178 and $Symbol!~/\@/) {
10179 next;
10180 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010181 $RemovedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010182 }
10183}
10184
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010185sub mergeLibs($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010186{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010187 my $Level = $_[0];
10188 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010189 { # checking added symbols
10190 next if($CompleteSignature{2}{$Symbol}{"Private"});
10191 next if(not $CompleteSignature{2}{$Symbol}{"Header"} and not $CheckObjectsOnly);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010192 next if(not symbolFilter($Symbol, 2, "Imported", $Level));
10193 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010194 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010195 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010196 { # checking removed symbols
10197 next if($CompleteSignature{1}{$Symbol}{"Private"});
10198 next if(not $CompleteSignature{1}{$Symbol}{"Header"} and not $CheckObjectsOnly);
10199 if($Symbol=~/\A_ZTV/)
10200 { # skip v-tables for templates, that should not be imported by applications
10201 next if($tr_name{$Symbol}=~/</);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010202 if(my $CName = $VTableClass{$Symbol})
10203 {
10204 if(not keys(%{$ClassMethods{$Level}{1}{$CName}}))
10205 { # vtables for "private" classes
10206 # use case: vtable for QDragManager (Qt 4.5.3 to 4.6.0) became HIDDEN symbol
10207 next;
10208 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010209 }
10210 }
10211 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010212 next if(not symbolFilter($Symbol, 1, "Imported", $Level));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010213 }
10214 if($CompleteSignature{1}{$Symbol}{"PureVirt"})
10215 { # symbols for pure virtual methods cannot be called by clients
10216 next;
10217 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010218 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010219 }
10220}
10221
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010222sub checkDumpVersion($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010223{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010224 my ($LibVersion, $DumpVersion) = @_;
10225 return (not $UsedDump{$LibVersion}{"V"} or cmpVersions($UsedDump{$LibVersion}{"V"}, $DumpVersion)>=0);
10226}
10227
10228sub detectAdded_H($)
10229{
10230 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010231 foreach my $Symbol (sort keys(%{$CompleteSignature{2}}))
10232 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010233 if($Level eq "Source")
10234 { # remove symbol version
10235 my ($SN, $SS, $SV) = separate_symbol($Symbol);
10236 $Symbol=$SN;
10237 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010238 if(not $CompleteSignature{2}{$Symbol}{"Header"}
10239 or not $CompleteSignature{2}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010240 next;
10241 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010242 if($GeneratedSymbols{$Symbol}) {
10243 next;
10244 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010245 if(not defined $CompleteSignature{1}{$Symbol}
10246 or not $CompleteSignature{1}{$Symbol}{"MnglName"})
10247 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010248 if($UsedDump{2}{"SrcBin"})
10249 {
10250 if($UsedDump{1}{"BinOnly"} or not checkDumpVersion(1, "2.11"))
10251 { # support for old and different (!) ABI dumps
10252 if(not $CompleteSignature{2}{$Symbol}{"Virt"}
10253 and not $CompleteSignature{2}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010254 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010255 if($CheckHeadersOnly)
10256 { # skip all added symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010257 next;
10258 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010259 else
10260 {
10261 if(not link_symbol($Symbol, 2, "-Deps"))
10262 { # skip added inline symbols
10263 next;
10264 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010265 }
10266 }
10267 }
10268 }
10269 $AddedInt{$Level}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010270 }
10271 }
10272}
10273
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010274sub detectRemoved_H($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010275{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010276 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010277 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
10278 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010279 if($Level eq "Source")
10280 { # remove symbol version
10281 my ($SN, $SS, $SV) = separate_symbol($Symbol);
10282 $Symbol=$SN;
10283 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010284 if(not $CompleteSignature{1}{$Symbol}{"Header"}
10285 or not $CompleteSignature{1}{$Symbol}{"MnglName"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010286 next;
10287 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010288 if($GeneratedSymbols{$Symbol}) {
10289 next;
10290 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010291 if(not defined $CompleteSignature{2}{$Symbol}
10292 or not $CompleteSignature{2}{$Symbol}{"MnglName"})
10293 { # support for old and different (!) ABI dumps
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010294 if($UsedDump{1}{"SrcBin"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010295 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010296 if($UsedDump{2}{"BinOnly"} or not checkDumpVersion(2, "2.11"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010297 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010298 if(not $CompleteSignature{1}{$Symbol}{"Virt"}
10299 and not $CompleteSignature{1}{$Symbol}{"PureVirt"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010300 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010301 if($CheckHeadersOnly)
10302 { # skip all removed symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010303 next;
10304 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010305 else
10306 {
10307 if(not link_symbol($Symbol, 1, "-Deps"))
10308 { # skip removed inline symbols
10309 next;
10310 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010311 }
10312 }
10313 }
10314 }
10315 $RemovedInt{$Level}{$Symbol} = 1;
10316 if($Level eq "Source")
10317 { # search for a source-compatible equivalent
10318 setAlternative($Symbol, $Level);
10319 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010320 }
10321 }
10322}
10323
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010324sub mergeHeaders($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010325{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010326 my $Level = $_[0];
10327 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010328 { # checking added symbols
10329 next if($CompleteSignature{2}{$Symbol}{"PureVirt"});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010330 if($Level eq "Binary") {
10331 next if($CompleteSignature{2}{$Symbol}{"InLine"});
10332 }
10333 else
10334 { # Source
10335 if($SourceAlternative_B{$Symbol}) {
10336 next;
10337 }
10338 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010339 next if($CompleteSignature{2}{$Symbol}{"Private"});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010340 next if(not symbolFilter($Symbol, 2, "Imported", $Level));
10341 %{$CompatProblems{$Level}{$Symbol}{"Added_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010342 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010343 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010344 { # checking removed symbols
10345 next if($CompleteSignature{1}{$Symbol}{"PureVirt"});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010346 if($Level eq "Binary") {
10347 next if($CompleteSignature{1}{$Symbol}{"InLine"});
10348 }
10349 else
10350 { # Source
10351 if($SourceAlternative{$Symbol}) {
10352 next;
10353 }
10354 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010355 next if($CompleteSignature{1}{$Symbol}{"Private"});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010356 next if(not symbolFilter($Symbol, 1, "Imported", $Level));
10357 %{$CompatProblems{$Level}{$Symbol}{"Removed_Symbol"}{""}}=();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010358 }
10359}
10360
10361sub addParamNames($)
10362{
10363 my $LibraryVersion = $_[0];
10364 return if(not keys(%AddIntParams));
10365 my $SecondVersion = $LibraryVersion==1?2:1;
10366 foreach my $Interface (sort keys(%{$CompleteSignature{$LibraryVersion}}))
10367 {
10368 next if(not keys(%{$AddIntParams{$Interface}}));
10369 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibraryVersion}{$Interface}{"Param"}}))
10370 {# add absent parameter names
10371 my $ParamName = $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"};
10372 if($ParamName=~/\Ap\d+\Z/ and my $NewParamName = $AddIntParams{$Interface}{$ParamPos})
10373 {# names from the external file
10374 if(defined $CompleteSignature{$SecondVersion}{$Interface}
10375 and defined $CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos})
10376 {
10377 if($CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos}{"name"}=~/\Ap\d+\Z/) {
10378 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
10379 }
10380 }
10381 else {
10382 $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
10383 }
10384 }
10385 }
10386 }
10387}
10388
10389sub detectChangedTypedefs()
10390{ # detect changed typedefs to create correct function signatures
10391 foreach my $Typedef (keys(%{$Typedef_BaseName{1}}))
10392 {
10393 next if(not $Typedef);
10394 next if(isAnon($Typedef_BaseName{1}{$Typedef}));
10395 next if(isAnon($Typedef_BaseName{2}{$Typedef}));
10396 next if(not $Typedef_BaseName{1}{$Typedef});
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010397 next if(not $Typedef_BaseName{2}{$Typedef}); # exclude added/removed
10398 if($Typedef_BaseName{1}{$Typedef} ne $Typedef_BaseName{2}{$Typedef})
10399 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010400 $ChangedTypedef{$Typedef} = 1;
10401 }
10402 }
10403}
10404
10405sub get_symbol_suffix($$)
10406{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010407 my ($Symbol, $Full) = @_;
10408 my ($SN, $SO, $SV) = separate_symbol($Symbol);
10409 $Symbol=$SN;# remove version
10410 my $Signature = $tr_name{$Symbol};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010411 my $Suffix = substr($Signature, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010412 if(not $Full) {
10413 $Suffix=~s/(\))\s*(const volatile|volatile const|const|volatile)\Z/$1/g;
10414 }
10415 return $Suffix;
10416}
10417
10418sub get_symbol_prefix($$)
10419{
10420 my ($Symbol, $LibVersion) = @_;
10421 my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
10422 if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
10423 { # methods
10424 $ShortName = get_TypeName($ClassId, $LibVersion)."::".$ShortName;
10425 }
10426 return $ShortName;
10427}
10428
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010429sub setAlternative($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010430{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010431 my $Symbol = $_[0];
10432 my $PSymbol = $Symbol;
10433 if(not defined $CompleteSignature{2}{$PSymbol}
10434 or (not $CompleteSignature{2}{$PSymbol}{"MnglName"}
10435 and not $CompleteSignature{2}{$PSymbol}{"ShortName"}))
10436 { # search for a pair
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010437 if(my $ShortName = $CompleteSignature{1}{$PSymbol}{"ShortName"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010438 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010439 if($CompleteSignature{1}{$PSymbol}{"Data"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010440 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010441 if($PSymbol=~s/L(\d+$ShortName(E)\Z)/$1/
10442 or $PSymbol=~s/(\d+$ShortName(E)\Z)/L$1/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010443 {
10444 if(defined $CompleteSignature{2}{$PSymbol}
10445 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
10446 {
10447 $SourceAlternative{$Symbol} = $PSymbol;
10448 $SourceAlternative_B{$PSymbol} = $Symbol;
10449 if(not defined $CompleteSignature{1}{$PSymbol}
10450 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
10451 $SourceReplacement{$Symbol} = $PSymbol;
10452 }
10453 }
10454 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010455 }
10456 else
10457 {
10458 foreach my $Sp ("KV", "VK", "K", "V")
10459 {
10460 if($PSymbol=~s/\A_ZN$Sp/_ZN/
10461 or $PSymbol=~s/\A_ZN/_ZN$Sp/)
10462 {
10463 if(defined $CompleteSignature{2}{$PSymbol}
10464 and $CompleteSignature{2}{$PSymbol}{"MnglName"})
10465 {
10466 $SourceAlternative{$Symbol} = $PSymbol;
10467 $SourceAlternative_B{$PSymbol} = $Symbol;
10468 if(not defined $CompleteSignature{1}{$PSymbol}
10469 or not $CompleteSignature{1}{$PSymbol}{"MnglName"}) {
10470 $SourceReplacement{$Symbol} = $PSymbol;
10471 }
10472 }
10473 }
10474 $PSymbol = $Symbol;
10475 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010476 }
10477 }
10478 }
10479 return "";
10480}
10481
10482sub mergeSignatures($)
10483{
10484 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010485 my %SubProblems = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010486
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010487 mergeBases($Level);
10488
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010489 my %AddedOverloads = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010490 foreach my $Symbol (sort keys(%{$AddedInt{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010491 { # check all added exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010492 if(not $CompleteSignature{2}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010493 next;
10494 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010495 if($CheckHeadersOnly or $Level eq "Source")
10496 {
10497 if(defined $CompleteSignature{1}{$Symbol}
10498 and $CompleteSignature{1}{$Symbol}{"Header"})
10499 { # double-check added symbol
10500 next;
10501 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010502 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010503 if(not symbolFilter($Symbol, 2, "Imported", $Level)) {
10504 next;
10505 }
10506 if($Symbol=~/\A(_Z|\?)/)
10507 { # C++
10508 $AddedOverloads{get_symbol_prefix($Symbol, 2)}{get_symbol_suffix($Symbol, 1)} = $Symbol;
10509 }
10510 if(my $OverriddenMethod = $CompleteSignature{2}{$Symbol}{"Override"})
10511 { # register virtual overridings
10512 my $AffectedClass_Name = get_TypeName($CompleteSignature{2}{$Symbol}{"Class"}, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010513 if(defined $CompleteSignature{1}{$OverriddenMethod}
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010514 and $CompleteSignature{1}{$OverriddenMethod}{"Virt"} and $TName_Tid{1}{$AffectedClass_Name}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010515 and not $CompleteSignature{1}{$OverriddenMethod}{"Private"})
10516 { # public virtual methods, virtual destructors: class should exist in previous version
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010517 if(isCopyingClass($TName_Tid{1}{$AffectedClass_Name}, 1))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010518 { # old v-table (copied) will be used by applications
10519 next;
10520 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010521 if(defined $CompleteSignature{1}{$Symbol}
10522 and $CompleteSignature{1}{$Symbol}{"InLine"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010523 { # auto-generated virtual destructors stay in the header (and v-table), added to library
10524 # use case: Ice 3.3.1 -> 3.4.0
10525 next;
10526 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010527 %{$CompatProblems{$Level}{$OverriddenMethod}{"Overridden_Virtual_Method"}{$tr_name{$Symbol}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010528 "Type_Name"=>$AffectedClass_Name,
10529 "Type_Type"=>"Class",
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010530 "Target"=>get_Signature($Symbol, 2),
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010531 "Old_Value"=>get_Signature($OverriddenMethod, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010532 "New_Value"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010533 }
10534 }
10535 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010536 foreach my $Symbol (sort keys(%{$RemovedInt{$Level}}))
10537 { # check all removed exported symbols
10538 if(not $CompleteSignature{1}{$Symbol}{"Header"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010539 next;
10540 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010541 if($CheckHeadersOnly or $Level eq "Source")
10542 {
10543 if(defined $CompleteSignature{2}{$Symbol}
10544 and $CompleteSignature{2}{$Symbol}{"Header"})
10545 { # double-check removed symbol
10546 next;
10547 }
10548 }
10549 if($CompleteSignature{1}{$Symbol}{"Private"})
10550 { # skip private methods
10551 next;
10552 }
10553 if(not symbolFilter($Symbol, 1, "Imported", $Level)) {
10554 next;
10555 }
10556 $CheckedSymbols{$Level}{$Symbol} = 1;
10557 if(my $OverriddenMethod = $CompleteSignature{1}{$Symbol}{"Override"})
10558 { # register virtual overridings
10559 my $AffectedClass_Name = get_TypeName($CompleteSignature{1}{$Symbol}{"Class"}, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010560 if(defined $CompleteSignature{2}{$OverriddenMethod}
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010561 and $CompleteSignature{2}{$OverriddenMethod}{"Virt"} and $TName_Tid{2}{$AffectedClass_Name})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010562 { # virtual methods, virtual destructors: class should exist in newer version
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010563 if(isCopyingClass($CompleteSignature{1}{$Symbol}{"Class"}, 1))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010564 { # old v-table (copied) will be used by applications
10565 next;
10566 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010567 if(defined $CompleteSignature{2}{$Symbol}
10568 and $CompleteSignature{2}{$Symbol}{"InLine"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010569 { # auto-generated virtual destructors stay in the header (and v-table), removed from library
10570 # use case: Ice 3.3.1 -> 3.4.0
10571 next;
10572 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010573 %{$CompatProblems{$Level}{$Symbol}{"Overridden_Virtual_Method_B"}{$tr_name{$OverriddenMethod}}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010574 "Type_Name"=>$AffectedClass_Name,
10575 "Type_Type"=>"Class",
10576 "Target"=>get_Signature($OverriddenMethod, 1),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010577 "Old_Value"=>get_Signature($Symbol, 1),
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010578 "New_Value"=>get_Signature($OverriddenMethod, 1) );
10579 }
10580 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010581 if($Level eq "Binary"
10582 and $OSgroup eq "windows")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010583 { # register the reason of symbol name change
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010584 if(my $NewSymbol = $mangled_name{2}{$tr_name{$Symbol}})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010585 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010586 if($AddedInt{$Level}{$NewSymbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010587 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010588 if($CompleteSignature{1}{$Symbol}{"Static"} ne $CompleteSignature{2}{$NewSymbol}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010589 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010590 if($CompleteSignature{2}{$NewSymbol}{"Static"})
10591 {
10592 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Static"}{$tr_name{$Symbol}}}=(
10593 "Target"=>$tr_name{$Symbol},
10594 "Old_Value"=>$Symbol,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010595 "New_Value"=>$NewSymbol );
10596 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010597 else
10598 {
10599 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonStatic"}{$tr_name{$Symbol}}}=(
10600 "Target"=>$tr_name{$Symbol},
10601 "Old_Value"=>$Symbol,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010602 "New_Value"=>$NewSymbol );
10603 }
10604 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010605 if($CompleteSignature{1}{$Symbol}{"Virt"} ne $CompleteSignature{2}{$NewSymbol}{"Virt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010606 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010607 if($CompleteSignature{2}{$NewSymbol}{"Virt"})
10608 {
10609 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Virtual"}{$tr_name{$Symbol}}}=(
10610 "Target"=>$tr_name{$Symbol},
10611 "Old_Value"=>$Symbol,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010612 "New_Value"=>$NewSymbol );
10613 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010614 else
10615 {
10616 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonVirtual"}{$tr_name{$Symbol}}}=(
10617 "Target"=>$tr_name{$Symbol},
10618 "Old_Value"=>$Symbol,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010619 "New_Value"=>$NewSymbol );
10620 }
10621 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010622 my $ReturnTypeName1 = get_TypeName($CompleteSignature{1}{$Symbol}{"Return"}, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010623 my $ReturnTypeName2 = get_TypeName($CompleteSignature{2}{$NewSymbol}{"Return"}, 2);
10624 if($ReturnTypeName1 ne $ReturnTypeName2)
10625 {
10626 my $ProblemType = "Symbol_Changed_Return";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010627 if($CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010628 $ProblemType = "Global_Data_Symbol_Changed_Type";
10629 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010630 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{$tr_name{$Symbol}}}=(
10631 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010632 "Old_Type"=>$ReturnTypeName1,
10633 "New_Type"=>$ReturnTypeName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010634 "Old_Value"=>$Symbol,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010635 "New_Value"=>$NewSymbol );
10636 }
10637 }
10638 }
10639 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010640 if($Symbol=~/\A(_Z|\?)/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010641 { # C++
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010642 my $Prefix = get_symbol_prefix($Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010643 if(my @Overloads = sort keys(%{$AddedOverloads{$Prefix}})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010644 and not $AddedOverloads{$Prefix}{get_symbol_suffix($Symbol, 1)})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010645 { # changed signature: params, "const"-qualifier
10646 my $NewSymbol = $AddedOverloads{$Prefix}{$Overloads[0]};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010647 if($CompleteSignature{1}{$Symbol}{"Constructor"})
10648 {
10649 if($Symbol=~/(C1E|C2E)/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010650 my $CtorType = $1;
10651 $NewSymbol=~s/(C1E|C2E)/$CtorType/g;
10652 }
10653 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010654 elsif($CompleteSignature{1}{$Symbol}{"Destructor"})
10655 {
10656 if($Symbol=~/(D0E|D1E|D2E)/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010657 my $DtorType = $1;
10658 $NewSymbol=~s/(D0E|D1E|D2E)/$DtorType/g;
10659 }
10660 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010661 my $NS1 = $CompleteSignature{1}{$Symbol}{"NameSpace"};
10662 my $NS2 = $CompleteSignature{2}{$NewSymbol}{"NameSpace"};
10663 if((not $NS1 and not $NS2) or ($NS1 and $NS2 and $NS1 eq $NS2))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010664 { # from the same class and namespace
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010665 if($CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010666 and not $CompleteSignature{2}{$NewSymbol}{"Const"})
10667 { # "const" to non-"const"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010668 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonConst"}{$tr_name{$Symbol}}}=(
10669 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010670 "New_Signature"=>get_Signature($NewSymbol, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010671 "Old_Value"=>$Symbol,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010672 "New_Value"=>$NewSymbol );
10673 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010674 elsif(not $CompleteSignature{1}{$Symbol}{"Const"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010675 and $CompleteSignature{2}{$NewSymbol}{"Const"})
10676 { # non-"const" to "const"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010677 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Const"}{$tr_name{$Symbol}}}=(
10678 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010679 "New_Signature"=>get_Signature($NewSymbol, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010680 "Old_Value"=>$Symbol,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010681 "New_Value"=>$NewSymbol );
10682 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010683 if($CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010684 and not $CompleteSignature{2}{$NewSymbol}{"Volatile"})
10685 { # "volatile" to non-"volatile"
10686
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010687 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_NonVolatile"}{$tr_name{$Symbol}}}=(
10688 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010689 "New_Signature"=>get_Signature($NewSymbol, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010690 "Old_Value"=>$Symbol,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010691 "New_Value"=>$NewSymbol );
10692 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010693 elsif(not $CompleteSignature{1}{$Symbol}{"Volatile"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010694 and $CompleteSignature{2}{$NewSymbol}{"Volatile"})
10695 { # non-"volatile" to "volatile"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010696 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Became_Volatile"}{$tr_name{$Symbol}}}=(
10697 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010698 "New_Signature"=>get_Signature($NewSymbol, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010699 "Old_Value"=>$Symbol,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010700 "New_Value"=>$NewSymbol );
10701 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010702 if(get_symbol_suffix($Symbol, 0) ne get_symbol_suffix($NewSymbol, 0))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010703 { # params list
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010704 %{$CompatProblems{$Level}{$Symbol}{"Symbol_Changed_Parameters"}{$tr_name{$Symbol}}}=(
10705 "Target"=>$tr_name{$Symbol},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010706 "New_Signature"=>get_Signature($NewSymbol, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010707 "Old_Value"=>$Symbol,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010708 "New_Value"=>$NewSymbol );
10709 }
10710 }
10711 }
10712 }
10713 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010714 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
10715 { # checking symbols
10716 my ($SN, $SS, $SV) = separate_symbol($Symbol);
10717 if($Level eq "Source")
10718 { # remove symbol version
10719 $Symbol=$SN;
10720 }
10721 else
10722 { # Binary
10723 if(not $SV)
10724 { # symbol without version
10725 if(my $VSym = $SymVer{1}{$Symbol})
10726 { # the symbol is linked with versioned symbol
10727 if($CompleteSignature{2}{$VSym}{"MnglName"})
10728 { # show report for symbol@ver only
10729 next;
10730 }
10731 elsif(not link_symbol($VSym, 2, "-Deps"))
10732 { # changed version: sym@v1 to sym@v2
10733 # do NOT show report for symbol
10734 next;
10735 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010736 }
10737 }
10738 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010739 my $PSymbol = $Symbol;
10740 if($Level eq "Source"
10741 and my $S = $SourceReplacement{$Symbol})
10742 { # take a source-compatible replacement function
10743 $PSymbol = $S;
10744 }
10745 if($CompleteSignature{1}{$Symbol}{"Private"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010746 { # private symbols
10747 next;
10748 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010749 if(not defined $CompleteSignature{1}{$Symbol}
10750 or not defined $CompleteSignature{2}{$PSymbol})
10751 { # no info
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010752 next;
10753 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010754 if(not $CompleteSignature{1}{$Symbol}{"MnglName"}
10755 or not $CompleteSignature{2}{$PSymbol}{"MnglName"})
10756 { # no mangled name
10757 next;
10758 }
10759 if(not $CompleteSignature{1}{$Symbol}{"Header"}
10760 or not $CompleteSignature{2}{$PSymbol}{"Header"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010761 { # without a header
10762 next;
10763 }
10764 if($CheckHeadersOnly)
10765 { # skip added and removed pure virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010766 next if(not $CompleteSignature{1}{$Symbol}{"PureVirt"} and $CompleteSignature{2}{$PSymbol}{"PureVirt"});
10767 next if($CompleteSignature{1}{$Symbol}{"PureVirt"} and not $CompleteSignature{2}{$PSymbol}{"PureVirt"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010768 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010769 elsif($Level eq "Binary")
10770 { # skip non-exported, added and removed functions except pure virtual methods
10771 if(not link_symbol($Symbol, 1, "-Deps")
10772 or not link_symbol($PSymbol, 2, "-Deps"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010773 { # symbols from target library(ies) only
10774 # excluding dependent libraries
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010775 if(not $CompleteSignature{1}{$Symbol}{"PureVirt"}
10776 or not $CompleteSignature{2}{$PSymbol}{"PureVirt"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010777 next;
10778 }
10779 }
10780 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010781 if(not symbolFilter($Symbol, 1, "Imported|InlineVirtual", $Level))
10782 { # symbols that cannot be imported at binary-level
10783 # or used at source-level
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010784 next;
10785 }
10786 # checking virtual table
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010787 mergeVirtualTables($Symbol, $Level);
10788
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010789 if($COMPILE_ERRORS)
10790 { # if some errors occurred at the compiling stage
10791 # then some false positives can be skipped here
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010792 if(not $CompleteSignature{1}{$Symbol}{"Data"} and $CompleteSignature{2}{$PSymbol}{"Data"}
10793 and not $CompleteSignature{2}{$Symbol}{"Object"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010794 { # missed information about parameters in newer version
10795 next;
10796 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010797 if($CompleteSignature{1}{$Symbol}{"Data"} and not $CompleteSignature{1}{$Symbol}{"Object"}
10798 and not $CompleteSignature{2}{$PSymbol}{"Data"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010799 {# missed information about parameters in older version
10800 next;
10801 }
10802 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010803 my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010804 # checking attributes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010805 if($CompleteSignature{2}{$PSymbol}{"Static"}
10806 and not $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/) {
10807 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_Static"}{""}}=(
10808 "Target"=>get_Signature($Symbol, 1)
10809 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010810 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010811 elsif(not $CompleteSignature{2}{$PSymbol}{"Static"}
10812 and $CompleteSignature{1}{$Symbol}{"Static"} and $Symbol=~/\A(_Z|\?)/) {
10813 %{$CompatProblems{$Level}{$Symbol}{"Method_Became_NonStatic"}{""}}=(
10814 "Target"=>get_Signature($Symbol, 1)
10815 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010816 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010817 if(($CompleteSignature{1}{$Symbol}{"Virt"} and $CompleteSignature{2}{$PSymbol}{"Virt"})
10818 or ($CompleteSignature{1}{$Symbol}{"PureVirt"} and $CompleteSignature{2}{$PSymbol}{"PureVirt"}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010819 { # relative position of virtual and pure virtual methods
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010820 if($Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010821 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010822 if(defined $CompleteSignature{1}{$Symbol}{"RelPos"} and defined $CompleteSignature{2}{$PSymbol}{"RelPos"}
10823 and $CompleteSignature{1}{$Symbol}{"RelPos"}!=$CompleteSignature{2}{$PSymbol}{"RelPos"})
10824 { # top-level virtual methods only
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010825 my $Class_Id = $CompleteSignature{1}{$Symbol}{"Class"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010826 my $Class_Name = get_TypeName($Class_Id, 1);
10827 if(defined $VirtualTable{1}{$Class_Name} and defined $VirtualTable{2}{$Class_Name}
10828 and $VirtualTable{1}{$Class_Name}{$Symbol}!=$VirtualTable{2}{$Class_Name}{$Symbol})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010829 { # check the absolute position of virtual method (including added and removed methods)
10830 my %Class_Type = get_Type($Tid_TDid{1}{$Class_Id}, $Class_Id, 1);
10831 my $ProblemType = "Virtual_Method_Position";
10832 if($CompleteSignature{1}{$Symbol}{"PureVirt"}) {
10833 $ProblemType = "Pure_Virtual_Method_Position";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010834 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010835 if(isUsedClass($Class_Id, 1, $Level))
10836 {
10837 my @Affected = ($Symbol, keys(%{$OverriddenMethods{1}{$Symbol}}));
10838 foreach my $AffectedInterface (@Affected)
10839 {
10840 %{$CompatProblems{$Level}{$AffectedInterface}{$ProblemType}{$tr_name{$MnglName}}}=(
10841 "Type_Name"=>$Class_Type{"Name"},
10842 "Type_Type"=>"Class",
10843 "Old_Value"=>$CompleteSignature{1}{$Symbol}{"RelPos"},
10844 "New_Value"=>$CompleteSignature{2}{$PSymbol}{"RelPos"},
10845 "Target"=>get_Signature($Symbol, 1) );
10846 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040010847 $VTableChanged_M{$Class_Type{"Name"}} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010848 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010849 }
10850 }
10851 }
10852 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010853 if($CompleteSignature{1}{$Symbol}{"PureVirt"}
10854 or $CompleteSignature{2}{$PSymbol}{"PureVirt"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010855 { # do NOT check type changes in pure virtuals
10856 next;
10857 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010858 $CheckedSymbols{$Level}{$Symbol}=1;
10859 if($Symbol=~/\A(_Z|\?)/
10860 or keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})==keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010861 { # C/C++: changes in parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010862 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010863 { # checking parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010864 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010865 }
10866 }
10867 else
10868 { # C: added/removed parameters
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010869 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010870 { # checking added parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010871 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
10872 last if(get_TypeName($PType2_Id, 2) eq "...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010873 my $Parameter_Name = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
10874 my $Parameter_OldName = (defined $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos})?$CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010875 my $ParamPos_Prev = "-1";
10876 if($Parameter_Name=~/\Ap\d+\Z/i)
10877 { # added unnamed parameter ( pN )
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010878 my @Positions1 = find_ParamPair_Pos_byTypeAndPos(get_TypeName($PType2_Id, 2), $ParamPos, "backward", $Symbol, 1);
10879 my @Positions2 = find_ParamPair_Pos_byTypeAndPos(get_TypeName($PType2_Id, 2), $ParamPos, "backward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010880 if($#Positions1==-1 or $#Positions2>$#Positions1) {
10881 $ParamPos_Prev = "lost";
10882 }
10883 }
10884 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010885 $ParamPos_Prev = find_ParamPair_Pos_byName($Parameter_Name, $Symbol, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010886 }
10887 if($ParamPos_Prev eq "lost")
10888 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010889 if($ParamPos>keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010890 {
10891 my $ProblemType = "Added_Parameter";
10892 if($Parameter_Name=~/\Ap\d+\Z/) {
10893 $ProblemType = "Added_Unnamed_Parameter";
10894 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010895 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showNum($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010896 "Target"=>$Parameter_Name,
10897 "Param_Pos"=>$ParamPos,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010898 "Param_Type"=>get_TypeName($PType2_Id, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010899 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010900 }
10901 else
10902 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010903 my %ParamType_Pure = get_PureType($Tid_TDid{2}{$PType2_Id}, $PType2_Id, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010904 my $ParamStraightPairType_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010905 my %ParamStraightPairType_Pure = get_PureType($Tid_TDid{1}{$ParamStraightPairType_Id}, $ParamStraightPairType_Id, 1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010906 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 +040010907 and find_ParamPair_Pos_byName($Parameter_OldName, $Symbol, 2) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010908 {
10909 if($Parameter_OldName!~/\Ap\d+\Z/ and $Parameter_Name!~/\Ap\d+\Z/)
10910 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010911 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showNum($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010912 "Target"=>$Parameter_OldName,
10913 "Param_Pos"=>$ParamPos,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010914 "Param_Type"=>get_TypeName($PType2_Id, 2),
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010915 "Old_Value"=>$Parameter_OldName,
10916 "New_Value"=>$Parameter_Name,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010917 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010918 }
10919 }
10920 else
10921 {
10922 my $ProblemType = "Added_Middle_Parameter";
10923 if($Parameter_Name=~/\Ap\d+\Z/) {
10924 $ProblemType = "Added_Middle_Unnamed_Parameter";
10925 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010926 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showNum($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010927 "Target"=>$Parameter_Name,
10928 "Param_Pos"=>$ParamPos,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010929 "Param_Type"=>get_TypeName($PType2_Id, 2),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010930 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010931 }
10932 }
10933 }
10934 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010935 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010936 { # check relevant parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010937 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010938 my $ParamName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010939 # FIXME: find relevant parameter by name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010940 if(defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010941 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010942 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010943 my $ParamName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010944 if(($ParamName1!~/\Ap\d+\Z/i and $ParamName1 eq $ParamName2)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010945 or get_TypeName($PType1_Id, 1) eq get_TypeName($PType2_Id, 2)) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010946 mergeParameters($Symbol, $PSymbol, $ParamPos, $ParamPos, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010947 }
10948 }
10949 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010950 foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010951 { # checking removed parameters
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010952 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"type"};
10953 last if(get_TypeName($PType1_Id, 1) eq "...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010954 my $Parameter_Name = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos}{"name"};
10955 my $Parameter_NewName = (defined $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos})?$CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"name"}:"";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010956 my $ParamPos_New = "-1";
10957 if($Parameter_Name=~/\Ap\d+\Z/i)
10958 { # removed unnamed parameter ( pN )
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010959 my @Positions1 = find_ParamPair_Pos_byTypeAndPos(get_TypeName($PType1_Id, 1), $ParamPos, "forward", $Symbol, 1);
10960 my @Positions2 = find_ParamPair_Pos_byTypeAndPos(get_TypeName($PType1_Id, 1), $ParamPos, "forward", $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010961 if($#Positions2==-1 or $#Positions2<$#Positions1) {
10962 $ParamPos_New = "lost";
10963 }
10964 }
10965 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010966 $ParamPos_New = find_ParamPair_Pos_byName($Parameter_Name, $Symbol, 2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010967 }
10968 if($ParamPos_New eq "lost")
10969 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010970 if($ParamPos>keys(%{$CompleteSignature{2}{$PSymbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010971 {
10972 my $ProblemType = "Removed_Parameter";
10973 if($Parameter_Name=~/\Ap\d+\Z/) {
10974 $ProblemType = "Removed_Unnamed_Parameter";
10975 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010976 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showNum($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010977 "Target"=>$Parameter_Name,
10978 "Param_Pos"=>$ParamPos,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010979 "Param_Type"=>get_TypeName($PType1_Id, 1),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010980 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010981 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010982 elsif($ParamPos<keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})-1)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010983 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010984 my %ParamType_Pure = get_PureType($Tid_TDid{1}{$PType1_Id}, $PType1_Id, 1);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010985 my $ParamStraightPairType_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010986 my %ParamStraightPairType_Pure = get_PureType($Tid_TDid{2}{$ParamStraightPairType_Id}, $ParamStraightPairType_Id, 2);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010987 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 +040010988 and find_ParamPair_Pos_byName($Parameter_NewName, $Symbol, 1) eq "lost")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010989 {
10990 if($Parameter_NewName!~/\Ap\d+\Z/ and $Parameter_Name!~/\Ap\d+\Z/)
10991 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010992 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showNum($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010993 "Target"=>$Parameter_Name,
10994 "Param_Pos"=>$ParamPos,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040010995 "Param_Type"=>get_TypeName($PType1_Id, 1),
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010996 "Old_Value"=>$Parameter_Name,
10997 "New_Value"=>$Parameter_NewName,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040010998 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040010999 }
11000 }
11001 else
11002 {
11003 my $ProblemType = "Removed_Middle_Parameter";
11004 if($Parameter_Name=~/\Ap\d+\Z/) {
11005 $ProblemType = "Removed_Middle_Unnamed_Parameter";
11006 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011007 %{$CompatProblems{$Level}{$Symbol}{$ProblemType}{showNum($ParamPos)." Parameter"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011008 "Target"=>$Parameter_Name,
11009 "Param_Pos"=>$ParamPos,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011010 "Param_Type"=>get_TypeName($PType1_Id, 1),
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011011 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011012 }
11013 }
11014 }
11015 }
11016 }
11017 # checking return type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011018 my $ReturnType1_Id = $CompleteSignature{1}{$Symbol}{"Return"};
11019 my $ReturnType2_Id = $CompleteSignature{2}{$PSymbol}{"Return"};
11020 %SubProblems = detectTypeChange($ReturnType1_Id, $ReturnType2_Id, "Return", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011021 foreach my $SubProblemType (keys(%SubProblems))
11022 {
11023 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
11024 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
11025 my $NewProblemType = $SubProblemType;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011026 if($Level eq "Binary" and $SubProblemType eq "Return_Type_Became_Void"
11027 and keys(%{$CompleteSignature{1}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011028 { # parameters stack has been affected
11029 $NewProblemType = "Return_Type_Became_Void_And_Stack_Layout";
11030 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011031 elsif($Level eq "Binary"
11032 and $SubProblemType eq "Return_Type_From_Void")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011033 { # parameters stack has been affected
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011034 if(keys(%{$CompleteSignature{1}{$Symbol}{"Param"}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011035 $NewProblemType = "Return_Type_From_Void_And_Stack_Layout";
11036 }
11037 else
11038 { # safe
11039 delete($SubProblems{$SubProblemType});
11040 next;
11041 }
11042 }
11043 elsif($SubProblemType eq "Return_Type_And_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011044 and $CompleteSignature{1}{$Symbol}{"Data"}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011045 $NewProblemType = "Global_Data_Type_And_Size";
11046 }
11047 elsif($SubProblemType eq "Return_Type")
11048 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011049 if($CompleteSignature{1}{$Symbol}{"Data"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011050 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011051 if(removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011052 { # const -> non-const global data
11053 $NewProblemType = "Global_Data_Became_Non_Const";
11054 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011055 elsif(removedQual($New_Value, $Old_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011056 { # non-const -> const global data
11057 $NewProblemType = "Global_Data_Became_Const";
11058 }
11059 else {
11060 $NewProblemType = "Global_Data_Type";
11061 }
11062 }
11063 else
11064 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011065 if(removedQual($New_Value, $Old_Value, "const")) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011066 $NewProblemType = "Return_Type_Became_Const";
11067 }
11068 }
11069 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011070 elsif($SubProblemType eq "Return_Type_Format")
11071 {
11072 if($CompleteSignature{1}{$Symbol}{"Data"}) {
11073 $NewProblemType = "Global_Data_Type_Format";
11074 }
11075 }
11076 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011077 }
11078 if($ReturnType1_Id and $ReturnType2_Id)
11079 {
11080 @RecurTypes = ();
11081 %SubProblems = mergeTypes($ReturnType1_Id, $Tid_TDid{1}{$ReturnType1_Id},
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011082 $ReturnType2_Id, $Tid_TDid{2}{$ReturnType2_Id}, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011083 foreach my $SubProblemType (keys(%SubProblems))
11084 { # add "Global_Data_Size" problem
11085 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
11086 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
11087 if($SubProblemType eq "DataType_Size"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011088 and $CompleteSignature{1}{$Symbol}{"Data"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011089 and get_PointerLevel($Tid_TDid{1}{$ReturnType1_Id}, $ReturnType1_Id, 1)==0)
11090 { # add a new problem
11091 %{$SubProblems{"Global_Data_Size"}} = %{$SubProblems{$SubProblemType}};
11092 }
11093 }
11094 foreach my $SubProblemType (keys(%SubProblems))
11095 {
11096 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
11097 {
11098 my $NewLocation = ($SubLocation)?"retval->".$SubLocation:"retval";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011099 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011100 "Return_Type_Name"=>get_TypeName($ReturnType1_Id, 1) );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011101 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011102 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011103 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = get_TypeName($ReturnType1_Id, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011104 }
11105 }
11106 }
11107 }
11108
11109 # checking object type
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011110 my $ObjectType1_Id = $CompleteSignature{1}{$Symbol}{"Class"};
11111 my $ObjectType2_Id = $CompleteSignature{2}{$PSymbol}{"Class"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011112 if($ObjectType1_Id and $ObjectType2_Id
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011113 and not $CompleteSignature{1}{$Symbol}{"Static"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011114 {
11115 my $ThisPtr1_Id = getTypeIdByName(get_TypeName($ObjectType1_Id, 1)."*const", 1);
11116 my $ThisPtr2_Id = getTypeIdByName(get_TypeName($ObjectType2_Id, 2)."*const", 2);
11117 if($ThisPtr1_Id and $ThisPtr2_Id)
11118 {
11119 @RecurTypes = ();
11120 %SubProblems = mergeTypes($ThisPtr1_Id, $Tid_TDid{1}{$ThisPtr1_Id},
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011121 $ThisPtr2_Id, $Tid_TDid{2}{$ThisPtr2_Id}, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011122 foreach my $SubProblemType (keys(%SubProblems))
11123 {
11124 foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
11125 {
11126 my $NewLocation = ($SubLocation)?"this->".$SubLocation:"this";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011127 %{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011128 "Object_Type_Name"=>get_TypeName($ObjectType1_Id, 1) );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011129 @{$CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011130 if($SubLocation!~/\-\>/) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011131 $CompatProblems{$Level}{$Symbol}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = get_TypeName($ObjectType1_Id, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011132 }
11133 }
11134 }
11135 }
11136 }
11137 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011138 if($Level eq "Binary") {
11139 mergeVTables($Level);
11140 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011141}
11142
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011143sub removedQual($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011144{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011145 my ($Old_Value, $New_Value, $Qual) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011146 if($Old_Value eq $New_Value) {
11147 return 0;
11148 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011149 while($Old_Value=~s/(\A|\W)$Qual(\W|\Z)/$1$2/)
11150 { # remove all qualifiers
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011151 # one-by-one, left-to-right
11152 $Old_Value=~s/\s+\Z//g;
11153 $Old_Value=~s/\A\s+//g;
11154 $Old_Value = formatName($Old_Value);
11155 if($Old_Value eq $New_Value)
11156 { # compare with a new type
11157 return 1;
11158 }
11159 }
11160 return 0;
11161}
11162
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011163sub mergeParameters($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011164{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011165 my ($Symbol, $PSymbol, $ParamPos1, $ParamPos2, $Level) = @_;
11166 return if(not $Symbol);
11167 return if(not defined $CompleteSignature{1}{$Symbol}{"Param"});
11168 return if(not defined $CompleteSignature{2}{$PSymbol}{"Param"});
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011169 my $PType1_Id = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"type"};
11170 my $PName1 = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"name"};
11171 my $PType2_Id = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"type"};
11172 my $PName2 = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"name"};
11173 return if(not $PType1_Id or not $PType2_Id);
11174 my %Type1 = get_Type($Tid_TDid{1}{$PType1_Id}, $PType1_Id, 1);
11175 my %Type2 = get_Type($Tid_TDid{2}{$PType2_Id}, $PType2_Id, 2);
11176 my %BaseType1 = get_BaseType($Tid_TDid{1}{$PType1_Id}, $PType1_Id, 1);
11177 my %BaseType2 = get_BaseType($Tid_TDid{2}{$PType2_Id}, $PType2_Id, 2);
11178 my $Parameter_Location = ($PName1)?$PName1:showNum($ParamPos1)." Parameter";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011179 if($Level eq "Binary")
11180 {
11181 if(checkDumpVersion(1, "2.6.1") and checkDumpVersion(2, "2.6.1"))
11182 { # "reg" attribute added in ACC 1.95.1 (dump 2.6.1 format)
11183 if($CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
11184 and not $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
11185 {
11186 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Non_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011187 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011188 "Param_Pos"=>$ParamPos1 );
11189 }
11190 elsif(not $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"reg"}
11191 and $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"reg"})
11192 {
11193 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Became_Register"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011194 "Target"=>$PName1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011195 "Param_Pos"=>$ParamPos1 );
11196 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011197 }
11198 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011199 if(checkDumpVersion(1, "2.0") and checkDumpVersion(2, "2.0"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011200 { # "default" attribute added in ACC 1.22 (dump 2.0 format)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011201 my $DefaultValue_Old = $CompleteSignature{1}{$Symbol}{"Param"}{$ParamPos1}{"default"};
11202 my $DefaultValue_New = $CompleteSignature{2}{$PSymbol}{"Param"}{$ParamPos2}{"default"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011203 my %PureType1 = get_PureType($Tid_TDid{1}{$PType1_Id}, $PType1_Id, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011204 if($PureType1{"Name"}=~/\A(char\*|char const\*)\Z/)
11205 {
11206 if($DefaultValue_Old)
11207 { # FIXME: how to distinguish "0" and 0 (NULL)
11208 $DefaultValue_Old = "\"$DefaultValue_Old\"";
11209 }
11210 if($DefaultValue_New) {
11211 $DefaultValue_New = "\"$DefaultValue_New\"";
11212 }
11213 }
11214 elsif($PureType1{"Name"}=~/\A(char)\Z/)
11215 {
11216 if($DefaultValue_Old) {
11217 $DefaultValue_Old = "\'$DefaultValue_Old\'";
11218 }
11219 if($DefaultValue_New) {
11220 $DefaultValue_New = "\'$DefaultValue_New\'";
11221 }
11222 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011223 if(defined $DefaultValue_Old
11224 and $DefaultValue_Old ne "")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011225 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011226 if(defined $DefaultValue_New
11227 and $DefaultValue_New ne "")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011228 {
11229 if($DefaultValue_Old ne $DefaultValue_New)
11230 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011231 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Changed"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011232 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011233 "Param_Pos"=>$ParamPos1,
11234 "Old_Value"=>$DefaultValue_Old,
11235 "New_Value"=>$DefaultValue_New );
11236 }
11237 }
11238 else
11239 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011240 %{$CompatProblems{$Level}{$Symbol}{"Parameter_Default_Value_Removed"}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011241 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011242 "Param_Pos"=>$ParamPos1,
11243 "Old_Value"=>$DefaultValue_Old );
11244 }
11245 }
11246 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011247 if($PName1 and $PName2 and $PName1 ne $PName2
11248 and $PType1_Id!=-1 and $PType2_Id!=-1
11249 and $PName1!~/\Ap\d+\Z/ and $PName2!~/\Ap\d+\Z/)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011250 { # except unnamed "..." value list (Id=-1)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011251 %{$CompatProblems{$Level}{$Symbol}{"Renamed_Parameter"}{showNum($ParamPos1)." Parameter"}}=(
11252 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011253 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011254 "Param_Type"=>get_TypeName($PType1_Id, 1),
11255 "Old_Value"=>$PName1,
11256 "New_Value"=>$PName2,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011257 "New_Signature"=>get_Signature($Symbol, 2) );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011258 }
11259 # checking type change (replace)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011260 my %SubProblems = detectTypeChange($PType1_Id, $PType2_Id, "Parameter", $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011261 foreach my $SubProblemType (keys(%SubProblems))
11262 { # add new problems, remove false alarms
11263 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
11264 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
11265 if($SubProblemType eq "Parameter_Type")
11266 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011267 if(checkDumpVersion(1, "2.6") and checkDumpVersion(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011268 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011269 if($Level eq "Binary")
11270 {
11271 if($Old_Value!~/(\A|\W)restrict(\W|\Z)/
11272 and $New_Value=~/(\A|\W)restrict(\W|\Z)/)
11273 { # change to be "restrict"
11274 %{$SubProblems{"Parameter_Became_Restrict"}} = %{$SubProblems{$SubProblemType}};
11275 }
11276 elsif($Old_Value=~/(\A|\W)restrict(\W|\Z)/
11277 and $New_Value!~/(\A|\W)restrict(\W|\Z)/)
11278 { # change to be "restrict"
11279 %{$SubProblems{"Parameter_Became_NonRestrict"}} = %{$SubProblems{$SubProblemType}};
11280 }
11281 }
11282 else
11283 {
11284 if(removedQual($New_Value, $Old_Value, "restrict"))
11285 { # change to be "restrict"
11286 %{$SubProblems{"Parameter_Became_Restrict"}} = %{$SubProblems{$SubProblemType}};
11287 delete($SubProblems{$SubProblemType});
11288 }
11289 elsif(removedQual($Old_Value, $New_Value, "restrict"))
11290 { # change to be "restrict"
11291 %{$SubProblems{"Parameter_Became_NonRestrict"}} = %{$SubProblems{$SubProblemType}};
11292 delete($SubProblems{$SubProblemType});
11293 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011294 }
11295 }
11296 if($Type2{"Type"} eq "Const" and $BaseType2{"Name"} eq $Type1{"Name"}
11297 and $Type1{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
11298 { # int to "int const"
11299 delete($SubProblems{$SubProblemType});
11300 }
11301 if($Type1{"Type"} eq "Const" and $BaseType1{"Name"} eq $Type2{"Name"}
11302 and $Type2{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
11303 { # "int const" to int
11304 delete($SubProblems{$SubProblemType});
11305 }
11306 }
11307 }
11308 foreach my $SubProblemType (keys(%SubProblems))
11309 { # modify/register problems
11310 my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
11311 my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
11312 my $NewProblemType = $SubProblemType;
11313 if($Old_Value eq "..." and $New_Value ne "...")
11314 { # change from "..." to "int"
11315 if($ParamPos1==0)
11316 { # ISO C requires a named argument before "..."
11317 next;
11318 }
11319 $NewProblemType = "Parameter_Became_NonVaList";
11320 }
11321 elsif($New_Value eq "..." and $Old_Value ne "...")
11322 { # change from "int" to "..."
11323 if($ParamPos2==0)
11324 { # ISO C requires a named argument before "..."
11325 next;
11326 }
11327 $NewProblemType = "Parameter_Became_VaList";
11328 }
11329 elsif($SubProblemType eq "Parameter_Type"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011330 and removedQual($Old_Value, $New_Value, "const"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011331 { # parameter: "const" to non-"const"
11332 $NewProblemType = "Parameter_Became_Non_Const";
11333 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011334 elsif($Level eq "Binary" and ($SubProblemType eq "Parameter_Type_And_Size"
11335 or $SubProblemType eq "Parameter_Type"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011336 {
11337 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
11338 if($Arch1 eq "unknown" or $Arch2 eq "unknown")
11339 { # if one of the architectures is unknown
11340 # then set other arhitecture to unknown too
11341 ($Arch1, $Arch2) = ("unknown", "unknown");
11342 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011343 my ($Method1, $Passed1, $SizeOnStack1, $RegName1) = callingConvention($Symbol, $ParamPos1, 1, $Arch1);
11344 my ($Method2, $Passed2, $SizeOnStack2, $RegName2) = callingConvention($Symbol, $ParamPos2, 2, $Arch2);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011345 if($Method1 eq $Method2)
11346 {
11347 if($Method1 eq "stack" and $SizeOnStack1 ne $SizeOnStack2) {
11348 $NewProblemType = "Parameter_Type_And_Stack";
11349 }
11350 elsif($Method1 eq "register" and $RegName1 ne $RegName2) {
11351 $NewProblemType = "Parameter_Type_And_Register";
11352 }
11353 }
11354 else
11355 {
11356 if($Method1 eq "stack") {
11357 $NewProblemType = "Parameter_Type_And_Pass_Through_Register";
11358 }
11359 elsif($Method1 eq "register") {
11360 $NewProblemType = "Parameter_Type_And_Pass_Through_Stack";
11361 }
11362 }
11363 $SubProblems{$SubProblemType}{"Old_Reg"} = $RegName1;
11364 $SubProblems{$SubProblemType}{"New_Reg"} = $RegName2;
11365 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011366 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011367 "Target"=>$PName1,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011368 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011369 "New_Signature"=>get_Signature($Symbol, 2) );
11370 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$Parameter_Location}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011371 }
11372 @RecurTypes = ();
11373 # checking type definition changes
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011374 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 +040011375 foreach my $SubProblemType (keys(%SubProblems_Merge))
11376 {
11377 foreach my $SubLocation (keys(%{$SubProblems_Merge{$SubProblemType}}))
11378 {
11379 my $NewProblemType = $SubProblemType;
11380 if($SubProblemType eq "DataType_Size")
11381 {
11382 my $InitialType_Type = $SubProblems_Merge{$SubProblemType}{$SubLocation}{"InitialType_Type"};
11383 if($InitialType_Type!~/\A(Pointer|Ref)\Z/ and $SubLocation!~/\-\>/)
11384 { # stack has been affected
11385 $NewProblemType = "DataType_Size_And_Stack";
11386 }
11387 }
11388 my $NewLocation = ($SubLocation)?$Parameter_Location."->".$SubLocation:$Parameter_Location;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011389 %{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}=(
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011390 "Param_Type"=>get_TypeName($PType1_Id, 1),
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011391 "Param_Pos"=>$ParamPos1,
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011392 "Param_Name"=>$PName1 );
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011393 @{$CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}}{keys(%{$SubProblems_Merge{$SubProblemType}{$SubLocation}})} = values %{$SubProblems_Merge{$SubProblemType}{$SubLocation}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011394 if($SubLocation!~/\-\>/) {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011395 $CompatProblems{$Level}{$Symbol}{$NewProblemType}{$NewLocation}{"Start_Type_Name"} = get_TypeName($PType1_Id, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011396 }
11397 }
11398 }
11399}
11400
11401sub callingConvention($$$$)
11402{ # calling conventions for different compilers and operating systems
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011403 my ($Symbol, $ParamPos, $LibVersion, $Arch) = @_;
11404 my $ParamTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011405 my %Type = get_PureType($Tid_TDid{$LibVersion}{$ParamTypeId}, $ParamTypeId, $LibVersion);
11406 my ($Method, $Alignment, $Passed, $Register) = ("", 0, "", "");
11407 if($OSgroup=~/\A(linux|macos|freebsd)\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011408 { # GCC
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011409 if($Arch eq "x86")
11410 { # System V ABI Intel386 ("Function Calling Sequence")
11411 # The stack is word aligned. Although the architecture does not require any
11412 # alignment of the stack, software convention and the operating system
11413 # requires that the stack be aligned on a word boundary.
11414
11415 # Argument words are pushed onto the stack in reverse order (that is, the
11416 # rightmost argument in C call syntax has the highest address), preserving the
11417 # stack’s word alignment. All incoming arguments appear on the stack, residing
11418 # in the stack frame of the caller.
11419
11420 # An argument’s size is increased, if necessary, to make it a multiple of words.
11421 # This may require tail padding, depending on the size of the argument.
11422
11423 # Other areas depend on the compiler and the code being compiled. The stan-
11424 # dard calling sequence does not define a maximum stack frame size, nor does
11425 # it restrict how a language system uses the ‘‘unspecified’’ area of the stan-
11426 # dard stack frame.
11427 ($Method, $Alignment) = ("stack", 4);
11428 }
11429 elsif($Arch eq "x86_64")
11430 { # System V AMD64 ABI ("Function Calling Sequence")
11431 ($Method, $Alignment) = ("stack", 8);# eightbyte aligned
11432 }
11433 elsif($Arch eq "arm")
11434 { # Procedure Call Standard for the ARM Architecture
11435 # The stack must be double-word aligned
11436 ($Method, $Alignment) = ("stack", 8);# double-word
11437 }
11438 }
11439 elsif($OSgroup eq "windows")
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011440 { # MS C++ Compiler
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011441 if($Arch eq "x86")
11442 {
11443 if($ParamPos==0) {
11444 ($Method, $Register, $Passed) = ("register", "ecx", "value");
11445 }
11446 elsif($ParamPos==1) {
11447 ($Method, $Register, $Passed) = ("register", "edx", "value");
11448 }
11449 else {
11450 ($Method, $Alignment) = ("stack", 4);
11451 }
11452 }
11453 elsif($Arch eq "x86_64")
11454 {
11455 if($ParamPos<=3)
11456 {
11457 if($Type{"Name"}=~/\A(float|double|long double)\Z/) {
11458 ($Method, $Passed) = ("xmm".$ParamPos, "value");
11459 }
11460 elsif($Type{"Name"}=~/\A(unsigned |)(short|int|long|long long)\Z/
11461 or $Type{"Type"}=~/\A(Struct|Union|Enum|Array)\Z/
11462 or $Type{"Name"}=~/\A(__m64|__m128)\Z/)
11463 {
11464 if($ParamPos==0) {
11465 ($Method, $Register, $Passed) = ("register", "rcx", "value");
11466 }
11467 elsif($ParamPos==1) {
11468 ($Method, $Register, $Passed) = ("register", "rdx", "value");
11469 }
11470 elsif($ParamPos==2) {
11471 ($Method, $Register, $Passed) = ("register", "r8", "value");
11472 }
11473 elsif($ParamPos==3) {
11474 ($Method, $Register, $Passed) = ("register", "r9", "value");
11475 }
11476 if($Type{"Size"}>64
11477 or $Type{"Type"} eq "Array") {
11478 $Passed = "pointer";
11479 }
11480 }
11481 }
11482 else {
11483 ($Method, $Alignment) = ("stack", 8);# word alignment
11484 }
11485 }
11486 }
11487 if($Method eq "register") {
11488 return ("register", $Passed, "", $Register);
11489 }
11490 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011491 { # on the stack
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011492 if(not $Alignment)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011493 { # default convention
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011494 $Alignment = $WORD_SIZE{$LibVersion};
11495 }
11496 if(not $Passed)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011497 { # default convention
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011498 $Passed = "value";
11499 }
11500 my $SizeOnStack = $Type{"Size"};
11501 # FIXME: improve stack alignment
11502 if($SizeOnStack!=$Alignment) {
11503 $SizeOnStack = int(($Type{"Size"}+$Alignment)/$Alignment)*$Alignment;
11504 }
11505 return ("stack", $Passed, $SizeOnStack, "");
11506 }
11507}
11508
11509sub find_ParamPair_Pos_byName($$$)
11510{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011511 my ($Name, $Symbol, $LibVersion) = @_;
11512 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011513 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011514 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
11515 if($CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"name"} eq $Name)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011516 {
11517 return $ParamPos;
11518 }
11519 }
11520 return "lost";
11521}
11522
11523sub find_ParamPair_Pos_byTypeAndPos($$$$$)
11524{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011525 my ($TypeName, $MediumPos, $Order, $Symbol, $LibVersion) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011526 my @Positions = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011527 foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011528 {
11529 next if($Order eq "backward" and $ParamPos>$MediumPos);
11530 next if($Order eq "forward" and $ParamPos<$MediumPos);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011531 next if(not defined $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos});
11532 my $PTypeId = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$ParamPos}{"type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011533 if(get_TypeName($PTypeId, $LibVersion) eq $TypeName) {
11534 push(@Positions, $ParamPos);
11535 }
11536 }
11537 return @Positions;
11538}
11539
11540sub getTypeIdByName($$)
11541{
11542 my ($TypeName, $Version) = @_;
11543 return $TName_Tid{$Version}{formatName($TypeName)};
11544}
11545
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011546sub checkFormatChange($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011547{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011548 my ($Type1_Id, $Type2_Id, $Level) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011549 my $Type1_DId = $Tid_TDid{1}{$Type1_Id};
11550 my $Type2_DId = $Tid_TDid{2}{$Type2_Id};
11551 my %Type1_Pure = get_PureType($Type1_DId, $Type1_Id, 1);
11552 my %Type2_Pure = get_PureType($Type2_DId, $Type2_Id, 2);
11553 if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"})
11554 { # equal types
11555 return 0;
11556 }
11557 if($Type1_Pure{"Name"}=~/\*/
11558 or $Type2_Pure{"Name"}=~/\*/)
11559 { # compared in detectTypeChange()
11560 return 0;
11561 }
11562 my %FloatType = map {$_=>1} (
11563 "float",
11564 "double",
11565 "long double"
11566 );
11567 if($Type1_Pure{"Type"} ne $Type2_Pure{"Type"})
11568 { # different types
11569 if($Type1_Pure{"Type"} eq "Intrinsic"
11570 and $Type2_Pure{"Type"} eq "Enum")
11571 { # "int" to "enum"
11572 return 0;
11573 }
11574 elsif($Type2_Pure{"Type"} eq "Intrinsic"
11575 and $Type1_Pure{"Type"} eq "Enum")
11576 { # "enum" to "int"
11577 return 0;
11578 }
11579 else
11580 { # "union" to "struct"
11581 # ...
11582 return 1;
11583 }
11584 }
11585 else
11586 {
11587 if($Type1_Pure{"Type"} eq "Intrinsic")
11588 {
11589 if($FloatType{$Type1_Pure{"Name"}}
11590 or $FloatType{$Type2_Pure{"Name"}})
11591 { # "float" to "double"
11592 # "float" to "int"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011593 if($Level eq "Source")
11594 { # Safe
11595 return 0;
11596 }
11597 else {
11598 return 1;
11599 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011600 }
11601 }
11602 elsif($Type1_Pure{"Type"}=~/Class|Struct|Union|Enum/)
11603 {
11604 my @Membs1 = keys(%{$Type1_Pure{"Memb"}});
11605 my @Membs2 = keys(%{$Type2_Pure{"Memb"}});
11606 if($#Membs1!=$#Membs2)
11607 { # different number of elements
11608 return 1;
11609 }
11610 if($Type1_Pure{"Type"} eq "Enum")
11611 {
11612 foreach my $Pos (@Membs1)
11613 { # compare elements by name and value
11614 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"}
11615 or $Type1_Pure{"Memb"}{$Pos}{"value"} ne $Type2_Pure{"Memb"}{$Pos}{"value"})
11616 { # different names
11617 return 1;
11618 }
11619 }
11620 }
11621 else
11622 {
11623 foreach my $Pos (@Membs1)
11624 { # compare elements by type name
11625 my $MT1 = get_TypeName($Type1_Pure{"Memb"}{$Pos}{"type"}, 1);
11626 my $MT2 = get_TypeName($Type2_Pure{"Memb"}{$Pos}{"type"}, 2);
11627 if($MT1 ne $MT2)
11628 { # different types
11629 return 1;
11630 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011631 if($Level eq "Source")
11632 {
11633 if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"})
11634 { # different names
11635 return 1;
11636 }
11637 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011638 }
11639 }
11640 }
11641 }
11642 return 0;
11643}
11644
11645sub isScalar($) {
11646 return ($_[0]=~/\A(unsigned |)(short|int|long|long long)\Z/);
11647}
11648
11649sub isFloat($) {
11650 return ($_[0]=~/\A(float|double|long double)\Z/);
11651}
11652
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011653sub detectTypeChange($$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011654{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011655 my ($Type1_Id, $Type2_Id, $Prefix, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011656 if(not $Type1_Id or not $Type2_Id) {
11657 return ();
11658 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011659 my %LocalProblems = ();
11660 my $Type1_DId = $Tid_TDid{1}{$Type1_Id};
11661 my $Type2_DId = $Tid_TDid{2}{$Type2_Id};
11662 my %Type1 = get_Type($Type1_DId, $Type1_Id, 1);
11663 my %Type2 = get_Type($Type2_DId, $Type2_Id, 2);
11664 my %Type1_Pure = get_PureType($Type1_DId, $Type1_Id, 1);
11665 my %Type2_Pure = get_PureType($Type2_DId, $Type2_Id, 2);
11666 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);
11667 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);
11668 my $Type1_PLevel = get_PointerLevel($Type1_DId, $Type1_Id, 1);
11669 my $Type2_PLevel = get_PointerLevel($Type2_DId, $Type2_Id, 2);
11670 return () if(not $Type1{"Name"} or not $Type2{"Name"});
11671 return () if(not $Type1_Base{"Name"} or not $Type2_Base{"Name"});
11672 return () if($Type1_PLevel eq "" or $Type2_PLevel eq "");
11673 if($Type1_Base{"Name"} ne $Type2_Base{"Name"}
11674 and ($Type1{"Name"} eq $Type2{"Name"} or ($Type1_PLevel>=1 and $Type1_PLevel==$Type2_PLevel
11675 and $Type1_Base{"Name"} ne "void" and $Type2_Base{"Name"} ne "void")))
11676 { # base type change
11677 if($Type1{"Type"} eq "Typedef" and $Type2{"Type"} eq "Typedef"
11678 and $Type1{"Name"} eq $Type2{"Name"})
11679 { # will be reported in mergeTypes() as typedef problem
11680 return ();
11681 }
11682 if($Type1_Base{"Name"}!~/anon\-/ and $Type2_Base{"Name"}!~/anon\-/)
11683 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011684 if($Level eq "Binary"
11685 and $Type1_Base{"Size"} ne $Type2_Base{"Size"}
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011686 and $Type1_Base{"Size"} and $Type2_Base{"Size"})
11687 {
11688 %{$LocalProblems{$Prefix."_BaseType_And_Size"}}=(
11689 "Old_Value"=>$Type1_Base{"Name"},
11690 "New_Value"=>$Type2_Base{"Name"},
11691 "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
11692 "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
11693 "InitialType_Type"=>$Type1_Pure{"Type"});
11694 }
11695 else
11696 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011697 if(checkFormatChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011698 { # format change
11699 %{$LocalProblems{$Prefix."_BaseType_Format"}}=(
11700 "Old_Value"=>$Type1_Base{"Name"},
11701 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011702 "InitialType_Type"=>$Type1_Pure{"Type"});
11703 }
11704 elsif(tNameLock($Type1_Base{"Tid"}, $Type2_Base{"Tid"}))
11705 {
11706 %{$LocalProblems{$Prefix."_BaseType"}}=(
11707 "Old_Value"=>$Type1_Base{"Name"},
11708 "New_Value"=>$Type2_Base{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011709 "InitialType_Type"=>$Type1_Pure{"Type"});
11710 }
11711 }
11712 }
11713 }
11714 elsif($Type1{"Name"} ne $Type2{"Name"})
11715 { # type change
11716 if($Type1{"Name"}!~/anon\-/ and $Type2{"Name"}!~/anon\-/)
11717 {
11718 if($Prefix eq "Return" and $Type1{"Name"} eq "void"
11719 and $Type2_Pure{"Type"}=~/Intrinsic|Enum/) {
11720 # safe change
11721 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011722 elsif($Level eq "Binary"
11723 and $Prefix eq "Return"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011724 and $Type1_Pure{"Name"} eq "void")
11725 {
11726 %{$LocalProblems{"Return_Type_From_Void"}}=(
11727 "New_Value"=>$Type2{"Name"},
11728 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
11729 "InitialType_Type"=>$Type1_Pure{"Type"});
11730 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011731 elsif($Level eq "Binary"
11732 and $Prefix eq "Return" and $Type1_Pure{"Type"}=~/Intrinsic|Enum/
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011733 and $Type2_Pure{"Type"}=~/Struct|Class|Union/)
11734 { # returns into hidden first parameter instead of a register
11735
11736 # System V ABI Intel386 ("Function Calling Sequence")
11737 # A function that returns an integral or pointer value places its result in register %eax.
11738
11739 # A floating-point return value appears on the top of the Intel387 register stack. The
11740 # caller then must remove the value from the Intel387 stack, even if it doesn’t use the
11741 # value.
11742
11743 # If a function returns a structure or union, then the caller provides space for the
11744 # return value and places its address on the stack as argument word zero. In effect,
11745 # this address becomes a ‘‘hidden’’ first argument.
11746
11747 %{$LocalProblems{"Return_Type_From_Register_To_Stack"}}=(
11748 "Old_Value"=>$Type1{"Name"},
11749 "New_Value"=>$Type2{"Name"},
11750 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
11751 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
11752 "InitialType_Type"=>$Type1_Pure{"Type"});
11753 }
11754 elsif($Prefix eq "Return"
11755 and $Type2_Pure{"Name"} eq "void")
11756 {
11757 %{$LocalProblems{"Return_Type_Became_Void"}}=(
11758 "Old_Value"=>$Type1{"Name"},
11759 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
11760 "InitialType_Type"=>$Type1_Pure{"Type"});
11761 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011762 elsif($Level eq "Binary" and $Prefix eq "Return"
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011763 and ((isScalar($Type1_Pure{"Name"}) and isFloat($Type2_Pure{"Name"}))
11764 or (isScalar($Type2_Pure{"Name"}) and isFloat($Type1_Pure{"Name"}))))
11765 { # The scalar and floating-point values are passed in different registers
11766 %{$LocalProblems{"Return_Type_And_Register"}}=(
11767 "Old_Value"=>$Type1{"Name"},
11768 "New_Value"=>$Type2{"Name"},
11769 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
11770 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
11771 "InitialType_Type"=>$Type1_Pure{"Type"});
11772 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011773 elsif($Level eq "Binary"
11774 and $Prefix eq "Return" and $Type2_Pure{"Type"}=~/Intrinsic|Enum/
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011775 and $Type1_Pure{"Type"}=~/Struct|Class|Union/)
11776 { # returns in a register instead of a hidden first parameter
11777 %{$LocalProblems{"Return_Type_From_Stack_To_Register"}}=(
11778 "Old_Value"=>$Type1{"Name"},
11779 "New_Value"=>$Type2{"Name"},
11780 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
11781 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
11782 "InitialType_Type"=>$Type1_Pure{"Type"});
11783 }
11784 else
11785 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011786 if($Level eq "Binary"
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011787 and $Type1{"Size"} and $Type2{"Size"}
11788 and $Type1{"Size"} ne $Type2{"Size"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011789 {
11790 %{$LocalProblems{$Prefix."_Type_And_Size"}}=(
11791 "Old_Value"=>$Type1{"Name"},
11792 "New_Value"=>$Type2{"Name"},
11793 "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
11794 "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
11795 "InitialType_Type"=>$Type1_Pure{"Type"});
11796 }
11797 else
11798 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011799 if(checkFormatChange($Type1_Id, $Type2_Id, $Level))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011800 { # format change
11801 %{$LocalProblems{$Prefix."_Type_Format"}}=(
11802 "Old_Value"=>$Type1{"Name"},
11803 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011804 "InitialType_Type"=>$Type1_Pure{"Type"});
11805 }
11806 elsif(tNameLock($Type1_Id, $Type2_Id))
11807 { # FIXME: correct this condition
11808 %{$LocalProblems{$Prefix."_Type"}}=(
11809 "Old_Value"=>$Type1{"Name"},
11810 "New_Value"=>$Type2{"Name"},
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011811 "InitialType_Type"=>$Type1_Pure{"Type"});
11812 }
11813 }
11814 }
11815 }
11816 }
11817 if($Type1_PLevel!=$Type2_PLevel)
11818 {
11819 if($Type1{"Name"} ne "void" and $Type1{"Name"} ne "..."
11820 and $Type2{"Name"} ne "void" and $Type2{"Name"} ne "...")
11821 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011822 if($Level eq "Source")
11823 {
11824 %{$LocalProblems{$Prefix."_PointerLevel"}}=(
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011825 "Old_Value"=>$Type1_PLevel,
11826 "New_Value"=>$Type2_PLevel);
11827 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011828 else
11829 {
11830 if($Type2_PLevel>$Type1_PLevel) {
11831 %{$LocalProblems{$Prefix."_PointerLevel_Increased"}}=(
11832 "Old_Value"=>$Type1_PLevel,
11833 "New_Value"=>$Type2_PLevel);
11834 }
11835 else {
11836 %{$LocalProblems{$Prefix."_PointerLevel_Decreased"}}=(
11837 "Old_Value"=>$Type1_PLevel,
11838 "New_Value"=>$Type2_PLevel);
11839 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011840 }
11841 }
11842 }
11843 if($Type1_Pure{"Type"} eq "Array")
11844 { # base_type[N] -> base_type[N]
11845 # base_type: older_structure -> typedef to newer_structure
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011846 my %SubProblems = detectTypeChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Prefix, $Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011847 foreach my $SubProblemType (keys(%SubProblems))
11848 {
11849 $SubProblemType=~s/_Type/_BaseType/g;
11850 next if(defined $LocalProblems{$SubProblemType});
11851 foreach my $Attr (keys(%{$SubProblems{$SubProblemType}})) {
11852 $LocalProblems{$SubProblemType}{$Attr} = $SubProblems{$SubProblemType}{$Attr};
11853 }
11854 }
11855 }
11856 return %LocalProblems;
11857}
11858
11859sub tNameLock($$)
11860{
11861 my ($Tid1, $Tid2) = @_;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011862 if(differentDumps("G")
11863 or differentDumps("V"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011864 { # different formats
11865 if($UseOldDumps)
11866 { # old dumps
11867 return 0;
11868 }
11869 my $TN1 = get_TypeName($Tid1, 1);
11870 my $TN2 = get_TypeName($Tid2, 2);
11871 my %Base1 = get_Type($Tid_TDid{1}{$Tid1}, $Tid1, 1);
11872 while($Base1{"Type"} eq "Typedef") {
11873 %Base1 = get_OneStep_BaseType($Base1{"TDid"}, $Base1{"Tid"}, 1);
11874 }
11875 my %Base2 = get_Type($Tid_TDid{2}{$Tid2}, $Tid2, 2);
11876 while($Base2{"Type"} eq "Typedef") {
11877 %Base2 = get_OneStep_BaseType($Base2{"TDid"}, $Base2{"Tid"}, 2);
11878 }
11879 my $Base1 = uncover_typedefs($Base1{"Name"}, 1);
11880 my $Base2 = uncover_typedefs($Base2{"Name"}, 2);
11881 if($TN1 ne $TN2
11882 and $Base1 eq $Base2)
11883 { # equal base types
11884 return 0;
11885 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011886 if(not checkDumpVersion(1, "2.6")
11887 or not checkDumpVersion(2, "2.6"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011888 {
11889 if($TN1!~/(\A|\W)restrict(\W|\Z)/
11890 and $TN2=~/(\A|\W)restrict(\W|\Z)/) {
11891 return 0;
11892 }
11893 }
11894
11895 }
11896 return 1;
11897}
11898
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011899sub differentDumps($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011900{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011901 my $Check = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011902 if($UsedDump{1}{"V"} and $UsedDump{2}{"V"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011903 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011904 if($Check eq "G")
11905 {
11906 if(getGccVersion(1) ne getGccVersion(2))
11907 { # different GCC versions
11908 return 1;
11909 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011910 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011911 if($Check eq "V")
11912 {
11913 if(cmpVersions(formatVersion($UsedDump{1}{"V"}, 2),
11914 formatVersion($UsedDump{2}{"V"}, 2))!=0)
11915 { # different dump versions (skip micro version)
11916 return 1;
11917 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011918 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011919 }
11920 return 0;
11921}
11922
11923sub formatVersion($$)
11924{ # cut off version digits
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011925 my ($V, $Digits) = @_;
11926 my @Elems = split(/\./, $V);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011927 return join(".", splice(@Elems, 0, $Digits));
11928}
11929
11930sub htmlSpecChars($)
11931{
11932 my $Str = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011933 if($Str eq "") {
11934 return "";
11935 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011936 $Str=~s/\&([^#]|\Z)/&amp;$1/g;
11937 $Str=~s/</&lt;/g;
11938 $Str=~s/\-\>/&#45;&gt;/g; # &minus;
11939 $Str=~s/>/&gt;/g;
11940 $Str=~s/([^ ])( )([^ ])/$1\@ALONE_SP\@$3/g;
11941 $Str=~s/ /&#160;/g; # &nbsp;
11942 $Str=~s/\@ALONE_SP\@/ /g;
11943 $Str=~s/\n/<br\/>/g;
11944 $Str=~s/\"/&quot;/g;
11945 $Str=~s/\'/&#39;/g;
11946 return $Str;
11947}
11948
11949sub black_name($)
11950{
11951 my $Name = $_[0];
11952 return "<span class='iname_b'>".highLight_Signature($Name)."</span>";
11953}
11954
11955sub highLight_Signature($)
11956{
11957 my $Signature = $_[0];
11958 return highLight_Signature_PPos_Italic($Signature, "", 0, 0, 0);
11959}
11960
11961sub highLight_Signature_Italic_Color($)
11962{
11963 my $Signature = $_[0];
11964 return highLight_Signature_PPos_Italic($Signature, "", 1, 1, 1);
11965}
11966
11967sub separate_symbol($)
11968{
11969 my $Symbol = $_[0];
11970 my ($Name, $Spec, $Ver) = ($Symbol, "", "");
11971 if($Symbol=~/\A([^\@\$\?]+)([\@\$]+)([^\@\$]+)\Z/) {
11972 ($Name, $Spec, $Ver) = ($1, $2, $3);
11973 }
11974 return ($Name, $Spec, $Ver);
11975}
11976
11977sub cut_f_attrs($)
11978{
11979 if($_[0]=~s/(\))((| (const volatile|const|volatile))(| \[static\]))\Z/$1/) {
11980 return $2;
11981 }
11982 return "";
11983}
11984
11985sub highLight_Signature_PPos_Italic($$$$$)
11986{
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040011987 my ($FullSignature, $Param_Pos, $ItalicParams, $ColorParams, $ShowReturn) = @_;
11988 $Param_Pos = "" if(not defined $Param_Pos);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011989 if($CheckObjectsOnly) {
11990 $ItalicParams=$ColorParams=0;
11991 }
11992 my ($Signature, $VersionSpec, $SymbolVersion) = separate_symbol($FullSignature);
11993 my $Return = "";
11994 if($ShowRetVal and $Signature=~s/([^:]):([^:].+?)\Z/$1/g) {
11995 $Return = $2;
11996 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040011997 my $SCenter = find_center($Signature, "(");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040011998 if(not $SCenter)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040011999 { # global data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012000 $Signature = htmlSpecChars($Signature);
12001 $Signature=~s!(\[data\])!<span style='color:Black;font-weight:normal;'>$1</span>!g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012002 $Signature .= (($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012003 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012004 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012005 }
12006 return $Signature;
12007 }
12008 my ($Begin, $End) = (substr($Signature, 0, $SCenter), "");
12009 $Begin.=" " if($Begin!~/ \Z/);
12010 $End = cut_f_attrs($Signature);
12011 my @Parts = ();
12012 my @SParts = get_s_params($Signature, 1);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012013 foreach my $Pos (0 .. $#SParts)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012014 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012015 my $Part = $SParts[$Pos];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012016 $Part=~s/\A\s+|\s+\Z//g;
12017 my ($Part_Styled, $ParamName) = (htmlSpecChars($Part), "");
12018 if($Part=~/\([\*]+(\w+)\)/i) {
12019 $ParamName = $1;#func-ptr
12020 }
12021 elsif($Part=~/(\w+)[\,\)]*\Z/i) {
12022 $ParamName = $1;
12023 }
12024 if(not $ParamName) {
12025 push(@Parts, $Part_Styled);
12026 next;
12027 }
12028 if($ItalicParams and not $TName_Tid{1}{$Part}
12029 and not $TName_Tid{2}{$Part})
12030 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012031 if($Param_Pos ne ""
12032 and $Pos==$Param_Pos) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012033 $Part_Styled =~ s!(\W)$ParamName([\,\)]|\Z)!$1<span class='focus_p'>$ParamName</span>$2!ig;
12034 }
12035 elsif($ColorParams) {
12036 $Part_Styled =~ s!(\W)$ParamName([\,\)]|\Z)!$1<span class='color_p'>$ParamName</span>$2!ig;
12037 }
12038 else {
12039 $Part_Styled =~ s!(\W)$ParamName([\,\)]|\Z)!$1<span style='font-style:italic;'>$ParamName</span>$2!ig;
12040 }
12041 }
12042 $Part_Styled=~s/,(\w)/, $1/g;
12043 push(@Parts, $Part_Styled);
12044 }
12045 if(@Parts)
12046 {
12047 foreach my $Num (0 .. $#Parts)
12048 {
12049 if($Num==$#Parts)
12050 { # add ")" to the last parameter
12051 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]." )</span>";
12052 }
12053 elsif(length($Parts[$Num])<=45) {
12054 $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]."</span>";
12055 }
12056 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012057 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;".join(" ", @Parts)."</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012058 }
12059 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012060 $Signature = htmlSpecChars($Begin)."<span class='sym_p'>(&#160;)</span>".$End;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012061 }
12062 if($Return and $ShowReturn) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012063 $Signature .= "<span class='sym_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012064 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012065 $Signature=~s!\[\]![&#160;]!g;
12066 $Signature=~s!operator=!operator&#160;=!g;
12067 $Signature=~s!(\[in-charge\]|\[not-in-charge\]|\[in-charge-deleting\]|\[static\])!<span class='sym_kind'>$1</span>!g;
12068 return $Signature.(($SymbolVersion)?"<span class='sym_ver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012069}
12070
12071sub get_s_params($$)
12072{
12073 my ($Signature, $Comma) = @_;
12074 my @Parts = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012075 my $ShortName = substr($Signature, 0, find_center($Signature, "("));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012076 $Signature=~s/\A\Q$ShortName\E\(//g;
12077 cut_f_attrs($Signature);
12078 $Signature=~s/\)\Z//;
12079 return separate_params($Signature, $Comma);
12080}
12081
12082sub separate_params($$)
12083{
12084 my ($Params, $Comma) = @_;
12085 my @Parts = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012086 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
12087 my $Part = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012088 foreach my $Pos (0 .. length($Params) - 1)
12089 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012090 my $S = substr($Params, $Pos, 1);
12091 if(defined $B{$S}) {
12092 $B{$S}+=1;
12093 }
12094 if($S eq "," and
12095 $B{"("}==$B{")"} and $B{"<"}==$B{">"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012096 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012097 if($Comma)
12098 { # include comma
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012099 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012100 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012101 $Part += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012102 }
12103 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012104 $Parts[$Part] .= $S;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012105 }
12106 }
12107 return @Parts;
12108}
12109
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012110sub find_center($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012111{
12112 my ($Sign, $Target) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012113 my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012114 my $Center = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012115 if($Sign=~s/(operator([^\w\s\(\)]+|\(\)))//g)
12116 { # operators
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012117 $Center+=length($1);
12118 }
12119 foreach my $Pos (0 .. length($Sign)-1)
12120 {
12121 my $S = substr($Sign, $Pos, 1);
12122 if($S eq $Target)
12123 {
12124 if($B{"("}==$B{")"}
12125 and $B{"<"}==$B{">"}) {
12126 return $Center;
12127 }
12128 }
12129 if(defined $B{$S}) {
12130 $B{$S}+=1;
12131 }
12132 $Center+=1;
12133 }
12134 return 0;
12135}
12136
12137sub appendFile($$)
12138{
12139 my ($Path, $Content) = @_;
12140 return if(not $Path);
12141 if(my $Dir = get_dirname($Path)) {
12142 mkpath($Dir);
12143 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012144 open(FILE, ">>", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012145 print FILE $Content;
12146 close(FILE);
12147}
12148
12149sub writeFile($$)
12150{
12151 my ($Path, $Content) = @_;
12152 return if(not $Path);
12153 if(my $Dir = get_dirname($Path)) {
12154 mkpath($Dir);
12155 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012156 open(FILE, ">", $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012157 print FILE $Content;
12158 close(FILE);
12159}
12160
12161sub readFile($)
12162{
12163 my $Path = $_[0];
12164 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012165 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012166 local $/ = undef;
12167 my $Content = <FILE>;
12168 close(FILE);
12169 if($Path!~/\.(tu|class)\Z/) {
12170 $Content=~s/\r/\n/g;
12171 }
12172 return $Content;
12173}
12174
12175sub get_filename($)
12176{ # much faster than basename() from File::Basename module
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012177 if($_[0] and $_[0]=~/([^\/\\]+)[\/\\]*\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012178 return $1;
12179 }
12180 return "";
12181}
12182
12183sub get_dirname($)
12184{ # much faster than dirname() from File::Basename module
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012185 if($_[0] and $_[0]=~/\A(.*?)[\/\\]+[^\/\\]*[\/\\]*\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012186 return $1;
12187 }
12188 return "";
12189}
12190
12191sub separate_path($) {
12192 return (get_dirname($_[0]), get_filename($_[0]));
12193}
12194
12195sub esc($)
12196{
12197 my $Str = $_[0];
12198 $Str=~s/([()\[\]{}$ &'"`;,<>\+])/\\$1/g;
12199 return $Str;
12200}
12201
12202sub readLineNum($$)
12203{
12204 my ($Path, $Num) = @_;
12205 return "" if(not $Path or not -f $Path);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012206 open(FILE, $Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012207 foreach (1 ... $Num) {
12208 <FILE>;
12209 }
12210 my $Line = <FILE>;
12211 close(FILE);
12212 return $Line;
12213}
12214
12215sub readAttributes($)
12216{
12217 my $Path = $_[0];
12218 return () if(not $Path or not -f $Path);
12219 my %Attributes = ();
12220 if(readLineNum($Path, 0)=~/<!--\s+(.+)\s+-->/) {
12221 foreach my $AttrVal (split(/;/, $1)) {
12222 if($AttrVal=~/(.+):(.+)/)
12223 {
12224 my ($Name, $Value) = ($1, $2);
12225 $Attributes{$Name} = $Value;
12226 }
12227 }
12228 }
12229 return \%Attributes;
12230}
12231
12232sub is_abs($) {
12233 return ($_[0]=~/\A(\/|\w+:[\/\\])/);
12234}
12235
12236sub get_abs_path($)
12237{ # abs_path() should NOT be called for absolute inputs
12238 # because it can change them
12239 my $Path = $_[0];
12240 if(not is_abs($Path)) {
12241 $Path = abs_path($Path);
12242 }
12243 return $Path;
12244}
12245
12246sub get_OSgroup()
12247{
12248 $_ = $Config{"osname"};
12249 if(/macos|darwin|rhapsody/i) {
12250 return "macos";
12251 }
12252 elsif(/freebsd|openbsd|netbsd/i) {
12253 return "bsd";
12254 }
12255 elsif(/haiku|beos/i) {
12256 return "beos";
12257 }
12258 elsif(/symbian|epoc/i) {
12259 return "symbian";
12260 }
12261 elsif(/win/i) {
12262 return "windows";
12263 }
12264 else {
12265 return $_;
12266 }
12267}
12268
12269sub getGccVersion($)
12270{
12271 my $LibVersion = $_[0];
12272 if($GCC_VERSION{$LibVersion})
12273 { # dump version
12274 return $GCC_VERSION{$LibVersion};
12275 }
12276 elsif($UsedDump{$LibVersion}{"V"})
12277 { # old-version dumps
12278 return "unknown";
12279 }
12280 my $GccVersion = get_dumpversion($GCC_PATH); # host version
12281 if(not $GccVersion) {
12282 return "unknown";
12283 }
12284 return $GccVersion;
12285}
12286
12287sub showArch($)
12288{
12289 my $Arch = $_[0];
12290 if($Arch eq "arm"
12291 or $Arch eq "mips") {
12292 return uc($Arch);
12293 }
12294 return $Arch;
12295}
12296
12297sub getArch($)
12298{
12299 my $LibVersion = $_[0];
12300 if($CPU_ARCH{$LibVersion})
12301 { # dump version
12302 return $CPU_ARCH{$LibVersion};
12303 }
12304 elsif($UsedDump{$LibVersion}{"V"})
12305 { # old-version dumps
12306 return "unknown";
12307 }
12308 if(defined $Cache{"getArch"}{$LibVersion}) {
12309 return $Cache{"getArch"}{$LibVersion};
12310 }
12311 my $Arch = get_dumpmachine($GCC_PATH); # host version
12312 if(not $Arch) {
12313 return "unknown";
12314 }
12315 if($Arch=~/\A([\w]{3,})(-|\Z)/) {
12316 $Arch = $1;
12317 }
12318 $Arch = "x86" if($Arch=~/\Ai[3-7]86\Z/);
12319 if($OSgroup eq "windows") {
12320 $Arch = "x86" if($Arch=~/win32|mingw32/i);
12321 $Arch = "x86_64" if($Arch=~/win64|mingw64/i);
12322 }
12323 $Cache{"getArch"}{$LibVersion} = $Arch;
12324 return $Arch;
12325}
12326
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012327sub get_Report_Header($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012328{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012329 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012330 my $ArchInfo = " on <span style='color:Blue;'>".showArch(getArch(1))."</span>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012331 if(getArch(1) ne getArch(2)
12332 or getArch(1) eq "unknown"
12333 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012334 { # don't show architecture in the header
12335 $ArchInfo="";
12336 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012337 my $Report_Header = "<h1><span class='nowrap'>";
12338 if($Level eq "Source") {
12339 $Report_Header .= "Source compatibility";
12340 }
12341 elsif($Level eq "Binary") {
12342 $Report_Header .= "Binary compatibility";
12343 }
12344 else {
12345 $Report_Header .= "API compatibility";
12346 }
12347 $Report_Header .= " report for the <span style='color:Blue;'>$TargetLibraryFName</span> $TargetComponent</span>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012348 $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>";
12349 if($AppPath) {
12350 $Report_Header .= " <span class='nowrap'>&#160;(relating to the portability of application <span style='color:Blue;'>".get_filename($AppPath)."</span>)</span>";
12351 }
12352 $Report_Header .= "</h1>\n";
12353 return $Report_Header;
12354}
12355
12356sub get_SourceInfo()
12357{
12358 my $CheckedHeaders = "<a name='Headers'></a><h2>Header Files (".keys(%{$Registered_Headers{1}}).")</h2><hr/>\n";
12359 $CheckedHeaders .= "<div class='h_list'>\n";
12360 foreach my $Header_Path (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
12361 {
12362 my $Identity = $Registered_Headers{1}{$Header_Path}{"Identity"};
12363 my $Header_Name = get_filename($Identity);
12364 my $Dest_Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
12365 $CheckedHeaders .= "$Header_Name$Dest_Comment<br/>\n";
12366 }
12367 $CheckedHeaders .= "</div>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012368 $CheckedHeaders .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012369 my $CheckedLibs = "<a name='Libs'></a><h2>".ucfirst($SLIB_TYPE)." Libraries (".keys(%{$Library_Symbol{1}}).")</h2><hr/>\n";
12370 $CheckedLibs .= "<div class='lib_list'>\n";
12371 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
12372 {
12373 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
12374 $CheckedLibs .= "$Library<br/>\n";
12375 }
12376 $CheckedLibs .= "</div>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012377 $CheckedLibs .= "<br/>$TOP_REF<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012378 if($CheckObjectsOnly) {
12379 $CheckedHeaders = "";
12380 }
12381 if($CheckHeadersOnly) {
12382 $CheckedLibs = "";
12383 }
12384 return $CheckedHeaders.$CheckedLibs;
12385}
12386
12387sub get_TypeProblems_Count($$$)
12388{
12389 my ($TypeChanges, $TargetPriority, $Level) = @_;
12390 my $Type_Problems_Count = 0;
12391 foreach my $Type_Name (sort keys(%{$TypeChanges}))
12392 {
12393 my %Kinds_Target = ();
12394 foreach my $Kind (keys(%{$TypeChanges->{$Type_Name}}))
12395 {
12396 foreach my $Location (keys(%{$TypeChanges->{$Type_Name}{$Kind}}))
12397 {
12398 my $Target = $TypeChanges->{$Type_Name}{$Kind}{$Location}{"Target"};
12399 my $Priority = getProblemSeverity($Level, $Kind);
12400 next if($Priority ne $TargetPriority);
12401 if($Kinds_Target{$Kind}{$Target}) {
12402 next;
12403 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012404 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012405 { # select a problem with the highest priority
12406 next;
12407 }
12408 $Kinds_Target{$Kind}{$Target} = 1;
12409 $Type_Problems_Count += 1;
12410 }
12411 }
12412 }
12413 return $Type_Problems_Count;
12414}
12415
12416sub get_Summary($)
12417{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012418 my $Level = $_[0];
12419 my ($Added, $Removed, $I_Problems_High, $I_Problems_Medium, $I_Problems_Low, $T_Problems_High,
12420 $C_Problems_Low, $T_Problems_Medium, $T_Problems_Low, $I_Other, $T_Other) = (0,0,0,0,0,0,0,0,0,0,0);
12421 %{$RESULT{$Level}} = (
12422 "Problems"=>0,
12423 "Warnings"=>0,
12424 "Affected"=>0 );
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012425 # check rules
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012426 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012427 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012428 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012429 {
12430 if(not defined $CompatRules{$Level}{$Kind})
12431 { # unknown rule
12432 if(not $UnknownRules{$Level}{$Kind})
12433 { # only one warning
12434 printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")");
12435 $UnknownRules{$Level}{$Kind}=1;
12436 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012437 delete($CompatProblems{$Level}{$Interface}{$Kind});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012438 }
12439 }
12440 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012441 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012442 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012443 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012444 {
12445 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols")
12446 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012447 foreach my $Location (sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012448 {
12449 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012450 if($Kind eq "Added_Symbol") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012451 $Added += 1;
12452 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012453 elsif($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012454 {
12455 $Removed += 1;
12456 $TotalAffected{$Level}{$Interface} = $Priority;
12457 }
12458 else
12459 {
12460 if($Priority eq "Safe") {
12461 $I_Other += 1;
12462 }
12463 elsif($Priority eq "High") {
12464 $I_Problems_High += 1;
12465 }
12466 elsif($Priority eq "Medium") {
12467 $I_Problems_Medium += 1;
12468 }
12469 elsif($Priority eq "Low") {
12470 $I_Problems_Low += 1;
12471 }
12472 if(($Priority ne "Low" or $StrictCompat)
12473 and $Priority ne "Safe") {
12474 $TotalAffected{$Level}{$Interface} = $Priority;
12475 }
12476 }
12477 }
12478 }
12479 }
12480 }
12481 my %TypeChanges = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012482 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012483 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012484 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012485 {
12486 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
12487 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012488 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012489 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012490 my $Type_Name = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
12491 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012492 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012493 if(cmpSeverities($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012494 { # select a problem with the highest priority
12495 next;
12496 }
12497 if(($Priority ne "Low" or $StrictCompat)
12498 and $Priority ne "Safe") {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012499 $TotalAffected{$Level}{$Interface} = maxSeverity($TotalAffected{$Level}{$Interface}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012500 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012501 %{$TypeChanges{$Type_Name}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040012502 $Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target} = maxSeverity($Type_MaxSeverity{$Level}{$Type_Name}{$Kind}{$Target}, $Priority);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012503 }
12504 }
12505 }
12506 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012507
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012508 $T_Problems_High = get_TypeProblems_Count(\%TypeChanges, "High", $Level);
12509 $T_Problems_Medium = get_TypeProblems_Count(\%TypeChanges, "Medium", $Level);
12510 $T_Problems_Low = get_TypeProblems_Count(\%TypeChanges, "Low", $Level);
12511 $T_Other = get_TypeProblems_Count(\%TypeChanges, "Safe", $Level);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012512
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012513 if($CheckObjectsOnly)
12514 { # only removed exported symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012515 $RESULT{$Level}{"Affected"} = $Removed*100/keys(%{$Symbol_Library{1}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012516 }
12517 else
12518 { # changed and removed public symbols
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012519 my $SCount = keys(%{$CheckedSymbols{$Level}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012520 if($ExtendedCheck)
12521 { # don't count external_func_0 for constants
12522 $SCount-=1;
12523 }
12524 if($SCount)
12525 {
12526 my %Weight = (
12527 "High" => 100,
12528 "Medium" => 50,
12529 "Low" => 25
12530 );
12531 foreach (keys(%{$TotalAffected{$Level}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012532 $RESULT{$Level}{"Affected"}+=$Weight{$TotalAffected{$Level}{$_}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012533 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012534 $RESULT{$Level}{"Affected"} = $RESULT{$Level}{"Affected"}/$SCount;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012535 }
12536 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012537 $RESULT{$Level}{"Affected"} = 0;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012538 }
12539 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012540 $RESULT{$Level}{"Affected"} = show_number($RESULT{$Level}{"Affected"});
12541 if($RESULT{$Level}{"Affected"}>=100) {
12542 $RESULT{$Level}{"Affected"} = 100;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012543 }
12544
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012545 $RESULT{$Level}{"Problems"} = $Removed + $T_Problems_High + $I_Problems_High;
12546 $RESULT{$Level}{"Problems"} += $T_Problems_Medium + $I_Problems_Medium;
12547 $RESULT{$Level}{$StrictCompat?"Problems":"Warnings"} += $T_Problems_Low + $I_Problems_Low;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012548
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012549 if($C_Problems_Low = keys(%{$ProblemsWithConstants{$Level}}))
12550 {
12551 if(defined $CompatRules{$Level}{"Changed_Constant"}) {
12552 $RESULT{$Level}{$StrictCompat?"Problems":"Warnings"} += $C_Problems_Low;
12553 }
12554 else
12555 {
12556 printMsg("WARNING", "unknown rule \"Changed_Constant\" (\"$Level\")");
12557 $C_Problems_Low = 0;
12558 }
12559 }
12560 if($CheckImpl and $Level eq "Binary") {
12561 $RESULT{$Level}{$StrictCompat?"Problems":"Warnings"} += keys(%ImplProblems);
12562 }
12563 $RESULT{$Level}{"Verdict"} = $RESULT{$Level}{"Problems"}?"incompatible":"compatible";
12564
12565 my $TotalTypes = keys(%{$CheckedTypes{$Level}});
12566 if(not $TotalTypes)
12567 { # list all the types
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012568 $TotalTypes = keys(%{$TName_Tid{1}});
12569 }
12570
12571 my ($Arch1, $Arch2) = (getArch(1), getArch(2));
12572 my ($GccV1, $GccV2) = (getGccVersion(1), getGccVersion(2));
12573
12574 my ($TestInfo, $TestResults, $Problem_Summary) = ();
12575
12576 if($ReportFormat eq "xml")
12577 { # XML
12578 # test info
12579 $TestInfo .= " <library>$TargetLibraryName</library>\n";
12580 $TestInfo .= " <version1>\n";
12581 $TestInfo .= " <number>".$Descriptor{1}{"Version"}."</number>\n";
12582 $TestInfo .= " <architecture>$Arch1</architecture>\n";
12583 $TestInfo .= " <gcc>$GccV1</gcc>\n";
12584 $TestInfo .= " </version1>\n";
12585
12586 $TestInfo .= " <version2>\n";
12587 $TestInfo .= " <number>".$Descriptor{2}{"Version"}."</number>\n";
12588 $TestInfo .= " <architecture>$Arch2</architecture>\n";
12589 $TestInfo .= " <gcc>$GccV2</gcc>\n";
12590 $TestInfo .= " </version2>\n";
12591 $TestInfo = "<test_info>\n".$TestInfo."</test_info>\n\n";
12592
12593 # test results
12594 $TestResults .= " <headers>\n";
12595 foreach my $Name (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
12596 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012597 my $Identity = $Registered_Headers{1}{$Name}{"Identity"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012598 my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
12599 $TestResults .= " <name>".get_filename($Name).$Comment."</name>\n";
12600 }
12601 $TestResults .= " </headers>\n";
12602
12603 $TestResults .= " <libs>\n";
12604 foreach my $Library (sort {lc($a) cmp lc($b)} keys(%{$Library_Symbol{1}}))
12605 {
12606 $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
12607 $TestResults .= " <name>$Library</name>\n";
12608 }
12609 $TestResults .= " </libs>\n";
12610
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012611 $TestResults .= " <symbols>".(keys(%{$CheckedSymbols{$Level}}) - keys(%GeneratedSymbols))."</symbols>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012612 $TestResults .= " <types>".$TotalTypes."</types>\n";
12613
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012614 $TestResults .= " <verdict>".$RESULT{$Level}{"Verdict"}."</verdict>\n";
12615 $TestResults .= " <affected>".$RESULT{$Level}{"Affected"}."</affected>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012616 $TestResults = "<test_results>\n".$TestResults."</test_results>\n\n";
12617
12618 # problem summary
12619 $Problem_Summary .= " <added_symbols>".$Added."</added_symbols>\n";
12620 $Problem_Summary .= " <removed_symbols>".$Removed."</removed_symbols>\n";
12621
12622 $Problem_Summary .= " <problems_with_types>\n";
12623 $Problem_Summary .= " <high>$T_Problems_High</high>\n";
12624 $Problem_Summary .= " <medium>$T_Problems_Medium</medium>\n";
12625 $Problem_Summary .= " <low>$T_Problems_Low</low>\n";
12626 $Problem_Summary .= " <safe>$T_Other</safe>\n";
12627 $Problem_Summary .= " </problems_with_types>\n";
12628
12629 $Problem_Summary .= " <problems_with_symbols>\n";
12630 $Problem_Summary .= " <high>$I_Problems_High</high>\n";
12631 $Problem_Summary .= " <medium>$I_Problems_Medium</medium>\n";
12632 $Problem_Summary .= " <low>$I_Problems_Low</low>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012633 $Problem_Summary .= " <safe>$I_Other</safe>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012634 $Problem_Summary .= " </problems_with_symbols>\n";
12635
12636 $Problem_Summary .= " <problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012637 $Problem_Summary .= " <low>$C_Problems_Low</low>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012638 $Problem_Summary .= " </problems_with_constants>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012639 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012640 {
12641 $Problem_Summary .= " <impl>\n";
12642 $Problem_Summary .= " <low>".keys(%ImplProblems)."</low>\n";
12643 $Problem_Summary .= " </impl>\n";
12644 }
12645 $Problem_Summary = "<problem_summary>\n".$Problem_Summary."</problem_summary>\n\n";
12646
12647 return ($TestInfo.$TestResults.$Problem_Summary, "");
12648 }
12649 else
12650 { # HTML
12651 # test info
12652 $TestInfo = "<h2>Test Info</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012653 $TestInfo .= "<table class='summary'>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012654 $TestInfo .= "<tr><th>".ucfirst($TargetComponent)." Name</th><td>$TargetLibraryFName</td></tr>\n";
12655
12656 my (@VInf1, @VInf2, $AddTestInfo) = ();
12657 if($Arch1 ne "unknown"
12658 and $Arch2 ne "unknown")
12659 { # CPU arch
12660 if($Arch1 eq $Arch2)
12661 { # go to the separate section
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012662 $AddTestInfo .= "<tr><th>CPU Type</th><td>".showArch($Arch1)."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012663 }
12664 else
12665 { # go to the version number
12666 push(@VInf1, showArch($Arch1));
12667 push(@VInf2, showArch($Arch2));
12668 }
12669 }
12670 if($GccV1 ne "unknown"
12671 and $GccV2 ne "unknown"
12672 and $OStarget ne "windows")
12673 { # GCC version
12674 if($GccV1 eq $GccV2)
12675 { # go to the separate section
12676 $AddTestInfo .= "<tr><th>GCC Version</th><td>$GccV1</td></tr>\n";
12677 }
12678 else
12679 { # go to the version number
12680 push(@VInf1, "gcc ".$GccV1);
12681 push(@VInf2, "gcc ".$GccV2);
12682 }
12683 }
12684 # show long version names with GCC version and CPU architecture name (if different)
12685 $TestInfo .= "<tr><th>Version #1</th><td>".$Descriptor{1}{"Version"}.(@VInf1?" (".join(", ", reverse(@VInf1)).")":"")."</td></tr>\n";
12686 $TestInfo .= "<tr><th>Version #2</th><td>".$Descriptor{2}{"Version"}.(@VInf2?" (".join(", ", reverse(@VInf2)).")":"")."</td></tr>\n";
12687 $TestInfo .= $AddTestInfo;
12688 #if($COMMON_LANGUAGE{1}) {
12689 # $TestInfo .= "<tr><th>Language</th><td>".$COMMON_LANGUAGE{1}."</td></tr>\n";
12690 #}
12691 if($ExtendedCheck) {
12692 $TestInfo .= "<tr><th>Mode</th><td>Extended</td></tr>\n";
12693 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012694 if($JoinReport)
12695 {
12696 if($Level eq "Binary") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012697 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Binary Compatibility</td></tr>\n"; # Run-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012698 }
12699 if($Level eq "Source") {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012700 $TestInfo .= "<tr><th>Subject</th><td width='150px'>Source Compatibility</td></tr>\n"; # Build-time
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012701 }
12702 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012703 $TestInfo .= "</table>\n";
12704
12705 # test results
12706 $TestResults = "<h2>Test Results</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012707 $TestResults .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012708
12709 my $Headers_Link = "0";
12710 $Headers_Link = "<a href='#Headers' style='color:Blue;'>".keys(%{$Registered_Headers{1}})."</a>" if(keys(%{$Registered_Headers{1}})>0);
12711 $TestResults .= "<tr><th>Total Header Files</th><td>".($CheckObjectsOnly?"0&#160;(not&#160;analyzed)":$Headers_Link)."</td></tr>\n";
12712
12713 if(not $ExtendedCheck)
12714 {
12715 my $Libs_Link = "0";
12716 $Libs_Link = "<a href='#Libs' style='color:Blue;'>".keys(%{$Library_Symbol{1}})."</a>" if(keys(%{$Library_Symbol{1}})>0);
12717 $TestResults .= "<tr><th>Total ".ucfirst($SLIB_TYPE)." Libraries</th><td>".($CheckHeadersOnly?"0&#160;(not&#160;analyzed)":$Libs_Link)."</td></tr>\n";
12718 }
12719
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012720 $TestResults .= "<tr><th>Total Symbols / Types</th><td>".(keys(%{$CheckedSymbols{$Level}}) - keys(%GeneratedSymbols))." / ".$TotalTypes."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012721
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012722 my $META_DATA = $RESULT{$Level}{"Problems"}?"verdict:incompatible;":"verdict:compatible;";
12723 if($JoinReport) {
12724 $META_DATA = "kind:".lc($Level).";".$META_DATA;
12725 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012726 $TestResults .= "<tr><th>Verdict</th>";
12727 if($RESULT{$Level}{"Problems"}) {
12728 $TestResults .= "<td><span style='color:Red;'><b>Incompatible<br/>(".$RESULT{$Level}{"Affected"}."%)</b></span></td>";
12729 }
12730 else {
12731 $TestResults .= "<td><span style='color:Green;'><b>Compatible</b></span></td>";
12732 }
12733 $TestResults .= "</tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012734 $TestResults .= "</table>\n";
12735
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012736 $META_DATA .= "affected:".$RESULT{$Level}{"Affected"}.";";# in percents
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012737 # problem summary
12738 $Problem_Summary = "<h2>Problem Summary</h2><hr/>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012739 $Problem_Summary .= "<table class='summary'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012740 $Problem_Summary .= "<tr><th></th><th style='text-align:center;'>Severity</th><th style='text-align:center;'>Count</th></tr>";
12741
12742 my $Added_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012743 if($Added>0)
12744 {
12745 if($JoinReport) {
12746 $Added_Link = "<a href='#".$Level."_Added' style='color:Blue;'>$Added</a>";
12747 }
12748 else {
12749 $Added_Link = "<a href='#Added' style='color:Blue;'>$Added</a>";
12750 }
12751 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012752 #$Added_Link = "n/a" if($CheckHeadersOnly);
12753 $META_DATA .= "added:$Added;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012754 $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 +040012755
12756 my $Removed_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012757 if($Removed>0)
12758 {
12759 if($JoinReport) {
12760 $Removed_Link = "<a href='#".$Level."_Removed' style='color:Blue;'>$Removed</a>"
12761 }
12762 else {
12763 $Removed_Link = "<a href='#Removed' style='color:Blue;'>$Removed</a>"
12764 }
12765 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012766 #$Removed_Link = "n/a" if($CheckHeadersOnly);
12767 $META_DATA .= "removed:$Removed;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012768 $Problem_Summary .= "<tr><th>Removed Symbols</th>";
12769 $Problem_Summary .= "<td>High</td><td".getStyle("I", "R", $Removed).">$Removed_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012770
12771 my $TH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012772 $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 +040012773 $TH_Link = "n/a" if($CheckObjectsOnly);
12774 $META_DATA .= "type_problems_high:$T_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012775 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Data Types</th>";
12776 $Problem_Summary .= "<td>High</td><td".getStyle("T", "H", $T_Problems_High).">$TH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012777
12778 my $TM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012779 $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 +040012780 $TM_Link = "n/a" if($CheckObjectsOnly);
12781 $META_DATA .= "type_problems_medium:$T_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012782 $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 +040012783
12784 my $TL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012785 $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 +040012786 $TL_Link = "n/a" if($CheckObjectsOnly);
12787 $META_DATA .= "type_problems_low:$T_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012788 $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 +040012789
12790 my $IH_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012791 $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 +040012792 $IH_Link = "n/a" if($CheckObjectsOnly);
12793 $META_DATA .= "interface_problems_high:$I_Problems_High;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012794 $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Symbols</th>";
12795 $Problem_Summary .= "<td>High</td><td".getStyle("I", "H", $I_Problems_High).">$IH_Link</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012796
12797 my $IM_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012798 $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 +040012799 $IM_Link = "n/a" if($CheckObjectsOnly);
12800 $META_DATA .= "interface_problems_medium:$I_Problems_Medium;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012801 $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 +040012802
12803 my $IL_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012804 $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 +040012805 $IL_Link = "n/a" if($CheckObjectsOnly);
12806 $META_DATA .= "interface_problems_low:$I_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012807 $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 +040012808
12809 my $ChangedConstants_Link = "0";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012810 if(keys(%{$CheckedSymbols{$Level}}) and $C_Problems_Low)
12811 {
12812 if($JoinReport) {
12813 $ChangedConstants_Link = "<a href='#".$Level."_Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
12814 }
12815 else {
12816 $ChangedConstants_Link = "<a href='#Changed_Constants' style='color:Blue;'>$C_Problems_Low</a>";
12817 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012818 }
12819 $ChangedConstants_Link = "n/a" if($CheckObjectsOnly);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012820 $META_DATA .= "changed_constants:$C_Problems_Low;";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012821 $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 +040012822
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012823 if($CheckImpl and $Level eq "Binary")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012824 {
12825 my $ChangedImpl_Link = "0";
12826 $ChangedImpl_Link = "<a href='#Changed_Implementation' style='color:Blue;'>".keys(%ImplProblems)."</a>" if(keys(%ImplProblems)>0);
12827 $ChangedImpl_Link = "n/a" if($CheckHeadersOnly);
12828 $META_DATA .= "changed_implementation:".keys(%ImplProblems).";";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012829 $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 +040012830 }
12831 # Safe Changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012832 if($T_Other and not $CheckObjectsOnly)
12833 {
12834 my $TS_Link = "<a href='#".get_Anchor("Type", $Level, "Safe")."' style='color:Blue;'>$T_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012835 $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 +040012836 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012837
12838 if($I_Other and not $CheckObjectsOnly)
12839 {
12840 my $IS_Link = "<a href='#".get_Anchor("Symbol", $Level, "Safe")."' style='color:Blue;'>$I_Other</a>";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012841 $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 +040012842 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012843
12844 $META_DATA .= "tool_version:$TOOL_VERSION";
12845 $Problem_Summary .= "</table>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012846 # $TestInfo = getLegend().$TestInfo;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012847 return ($TestInfo.$TestResults.$Problem_Summary, $META_DATA);
12848 }
12849}
12850
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012851sub getStyle($$$)
12852{
12853 my ($Subj, $Act, $Num) = @_;
12854 my %Style = (
12855 "A"=>"new",
12856 "R"=>"failed",
12857 "S"=>"passed",
12858 "L"=>"warning",
12859 "M"=>"failed",
12860 "H"=>"failed"
12861 );
12862 if($Num>0) {
12863 return " class='".$Style{$Act}."'";
12864 }
12865 return "";
12866}
12867
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012868sub show_number($)
12869{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012870 if($_[0])
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012871 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012872 my $Num = cut_off_number($_[0], 2, 0);
12873 if($Num eq "0")
12874 {
12875 foreach my $P (3 .. 7)
12876 {
12877 $Num = cut_off_number($_[0], $P, 1);
12878 if($Num ne "0") {
12879 last;
12880 }
12881 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012882 }
12883 if($Num eq "0") {
12884 $Num = $_[0];
12885 }
12886 return $Num;
12887 }
12888 return $_[0];
12889}
12890
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012891sub cut_off_number($$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012892{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012893 my ($num, $digs_to_cut, $z) = @_;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012894 if($num!~/\./)
12895 {
12896 $num .= ".";
12897 foreach (1 .. $digs_to_cut-1) {
12898 $num .= "0";
12899 }
12900 }
12901 elsif($num=~/\.(.+)\Z/ and length($1)<$digs_to_cut-1)
12902 {
12903 foreach (1 .. $digs_to_cut - 1 - length($1)) {
12904 $num .= "0";
12905 }
12906 }
12907 elsif($num=~/\d+\.(\d){$digs_to_cut,}/) {
12908 $num=sprintf("%.".($digs_to_cut-1)."f", $num);
12909 }
12910 $num=~s/\.[0]+\Z//g;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012911 if($z) {
12912 $num=~s/(\.[1-9]+)[0]+\Z/$1/g;
12913 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012914 return $num;
12915}
12916
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012917sub get_Report_ChangedConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012918{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012919 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012920 my $CHANGED_CONSTANTS = "";
12921 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012922 foreach my $Constant (keys(%{$ProblemsWithConstants{$Level}})) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012923 $ReportMap{$Constants{1}{$Constant}{"Header"}}{$Constant} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012924 }
12925 my $Kind = "Changed_Constant";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012926 if(not defined $CompatRules{$Level}{$Kind}) {
12927 return "";
12928 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012929 if($ReportFormat eq "xml")
12930 { # XML
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012931 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012932 {
12933 $CHANGED_CONSTANTS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012934 foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012935 {
12936 $CHANGED_CONSTANTS .= " <constant name=\"$Constant\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012937 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
12938 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
12939 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012940 $CHANGED_CONSTANTS .= " <problem id=\"$Kind\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012941 $CHANGED_CONSTANTS .= " <change".getXmlParams($Change, $ProblemsWithConstants{$Level}{$Constant}).">$Change</change>\n";
12942 $CHANGED_CONSTANTS .= " <effect".getXmlParams($Effect, $ProblemsWithConstants{$Level}{$Constant}).">$Effect</effect>\n";
12943 $CHANGED_CONSTANTS .= " <overcome".getXmlParams($Overcome, $ProblemsWithConstants{$Level}{$Constant}).">$Overcome</overcome>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012944 $CHANGED_CONSTANTS .= " </problem>\n";
12945 $CHANGED_CONSTANTS .= " </constant>\n";
12946 }
12947 $CHANGED_CONSTANTS .= " </header>\n";
12948 }
12949 $CHANGED_CONSTANTS = "<problems_with_constants severity=\"Low\">\n".$CHANGED_CONSTANTS."</problems_with_constants>\n\n";
12950 }
12951 else
12952 { # HTML
12953 my $Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012954 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012955 {
12956 $CHANGED_CONSTANTS .= "<span class='h_name'>$HeaderName</span><br/>\n";
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012957 foreach my $Name (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012958 {
12959 $Number += 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012960 my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $ProblemsWithConstants{$Level}{$Name});
12961 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012962 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 +040012963 $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 +040012964 $Report = $ContentSpanStart."<span class='extendable'>[+]</span> ".$Name.$ContentSpanEnd."<br/>\n".$Report;
12965 $CHANGED_CONSTANTS .= insertIDs($Report);
12966 }
12967 $CHANGED_CONSTANTS .= "<br/>\n";
12968 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040012969 if($CHANGED_CONSTANTS)
12970 {
12971 my $Anchor = "<a name='Changed_Constants'></a>";
12972 if($JoinReport) {
12973 $Anchor = "<a name='".$Level."_Changed_Constants'></a>";
12974 }
12975 $CHANGED_CONSTANTS = $Anchor."<h2>Problems with Constants ($Number)</h2><hr/>\n".$CHANGED_CONSTANTS.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012976 }
12977 }
12978 return $CHANGED_CONSTANTS;
12979}
12980
12981sub get_Report_Impl()
12982{
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012983 my $CHANGED_IMPLEMENTATION = "";
12984 my %ReportMap = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012985 foreach my $Interface (sort keys(%ImplProblems))
12986 {
12987 my $HeaderName = $CompleteSignature{1}{$Interface}{"Header"};
12988 my $DyLib = $Symbol_Library{1}{$Interface};
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012989 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012990 }
12991 my $Changed_Number = 0;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012992 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012993 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040012994 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040012995 {
12996 my $FDyLib=$DyLib.($DyLib!~/\.\w+\Z/?" (.$LIB_EXT)":"");
12997 if($HeaderName) {
12998 $CHANGED_IMPLEMENTATION .= "<span class='h_name'>$HeaderName</span>, <span class='lib_name'>$FDyLib</span><br/>\n";
12999 }
13000 else {
13001 $CHANGED_IMPLEMENTATION .= "<span class='lib_name'>$DyLib</span><br/>\n";
13002 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013003 my %NameSpaceSymbols = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013004 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013005 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013006 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013007 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013008 {
13009 $CHANGED_IMPLEMENTATION .= ($NameSpace)?"<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span>"."<br/>\n":"";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013010 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013011 foreach my $Interface (@SortedInterfaces)
13012 {
13013 $Changed_Number += 1;
13014 my $Signature = get_Signature($Interface, 1);
13015 if($NameSpace) {
13016 $Signature=~s/(\W|\A)\Q$NameSpace\E\:\:(\w)/$1$2/g;
13017 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013018 $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 +040013019 }
13020 }
13021 $CHANGED_IMPLEMENTATION .= "<br/>\n";
13022 }
13023 }
13024 if($CHANGED_IMPLEMENTATION) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013025 $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 +040013026 }
13027 return $CHANGED_IMPLEMENTATION;
13028}
13029
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013030sub getTitle($$$)
13031{
13032 my ($Header, $Library, $NameSpace) = @_;
13033 my $Title = "";
13034 if($Library and $Library!~/\.\w+\Z/) {
13035 $Library .= " (.$LIB_EXT)";
13036 }
13037 if($Header and $Library)
13038 {
13039 $Title .= "<span class='h_name'>$Header</span>";
13040 $Title .= ", <span class='lib_name'>$Library</span><br/>\n";
13041 }
13042 elsif($Library) {
13043 $Title .= "<span class='lib_name'>$Library</span><br/>\n";
13044 }
13045 elsif($Header) {
13046 $Title .= "<span class='h_name'>$Header</span><br/>\n";
13047 }
13048 if($NameSpace) {
13049 $Title .= "<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span><br/>\n";
13050 }
13051 return $Title;
13052}
13053
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013054sub get_Report_Added($)
13055{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013056 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013057 my $ADDED_INTERFACES = "";
13058 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013059 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013060 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013061 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013062 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013063 if($Kind eq "Added_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013064 {
13065 my $HeaderName = $CompleteSignature{2}{$Interface}{"Header"};
13066 my $DyLib = $Symbol_Library{2}{$Interface};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013067 if($Level eq "Source" and $ReportFormat eq "html")
13068 { # do not show library name in HTML report
13069 $DyLib = "";
13070 }
13071 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013072 }
13073 }
13074 }
13075 if($ReportFormat eq "xml")
13076 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013077 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013078 {
13079 $ADDED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013080 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013081 {
13082 $ADDED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013083 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013084 $ADDED_INTERFACES .= " <name>$Interface</name>\n";
13085 }
13086 $ADDED_INTERFACES .= " </library>\n";
13087 }
13088 $ADDED_INTERFACES .= " </header>\n";
13089 }
13090 $ADDED_INTERFACES = "<added_symbols>\n".$ADDED_INTERFACES."</added_symbols>\n\n";
13091 }
13092 else
13093 { # HTML
13094 my $Added_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013095 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013096 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013097 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013098 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013099 my %NameSpaceSymbols = ();
13100 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
13101 $NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013102 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013103 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013104 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013105 $ADDED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
13106 my @SortedInterfaces = sort {lc(get_Signature($a, 2)) cmp lc(get_Signature($b, 2))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013107 foreach my $Interface (@SortedInterfaces)
13108 {
13109 $Added_Number += 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013110 my $Signature = get_Signature($Interface, 2);
13111 if($NameSpace) {
13112 $Signature=~s/(\W|\A)\Q$NameSpace\E\:\:(\w)/$1$2/g;
13113 }
13114 if($Interface=~/\A(_Z|\?)/) {
13115 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013116 $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 +040013117 }
13118 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013119 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013120 }
13121 }
13122 else {
13123 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013124 $ADDED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013125 }
13126 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013127 $ADDED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013128 }
13129 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013130 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013131 $ADDED_INTERFACES .= "<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013132 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013133 }
13134 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013135 if($ADDED_INTERFACES)
13136 {
13137 my $Anchor = "<a name='Added'></a>";
13138 if($JoinReport) {
13139 $Anchor = "<a name='".$Level."_Added'></a>";
13140 }
13141 $ADDED_INTERFACES = $Anchor."<h2>Added Symbols ($Added_Number)</h2><hr/>\n".$ADDED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013142 }
13143 }
13144 return $ADDED_INTERFACES;
13145}
13146
13147sub get_Report_Removed($)
13148{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013149 my $Level = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013150 my $REMOVED_INTERFACES = "";
13151 my %ReportMap = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013152 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013153 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013154 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013155 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013156 if($Kind eq "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013157 {
13158 my $HeaderName = $CompleteSignature{1}{$Interface}{"Header"};
13159 my $DyLib = $Symbol_Library{1}{$Interface};
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013160 if($Level eq "Source" and $ReportFormat eq "html")
13161 { # do not show library name in HTML report
13162 $DyLib = "";
13163 }
13164 $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013165 }
13166 }
13167 }
13168 if($ReportFormat eq "xml")
13169 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013170 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013171 {
13172 $REMOVED_INTERFACES .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013173 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013174 {
13175 $REMOVED_INTERFACES .= " <library name=\"$DyLib\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013176 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013177 $REMOVED_INTERFACES .= " <name>$Interface</name>\n";
13178 }
13179 $REMOVED_INTERFACES .= " </library>\n";
13180 }
13181 $REMOVED_INTERFACES .= " </header>\n";
13182 }
13183 $REMOVED_INTERFACES = "<removed_symbols>\n".$REMOVED_INTERFACES."</removed_symbols>\n\n";
13184 }
13185 else
13186 { # HTML
13187 my $Removed_Number = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013188 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013189 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013190 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013191 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013192 my %NameSpaceSymbols = ();
13193 foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
13194 $NameSpaceSymbols{get_IntNameSpace($Interface, 1)}{$Interface} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013195 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013196 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013197 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013198 $REMOVED_INTERFACES .= getTitle($HeaderName, $DyLib, $NameSpace);
13199 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpaceSymbols{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013200 foreach my $Interface (@SortedInterfaces)
13201 {
13202 $Removed_Number += 1;
13203 my $SubReport = "";
13204 my $Signature = get_Signature($Interface, 1);
13205 if($NameSpace) {
13206 $Signature=~s/(\W|\A)\Q$NameSpace\E\:\:(\w)/$1$2/g;
13207 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013208 if($Interface=~/\A(_Z|\?)/)
13209 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013210 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013211 $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 +040013212 }
13213 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013214 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013215 }
13216 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013217 else
13218 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013219 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013220 $REMOVED_INTERFACES .= "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013221 }
13222 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013223 $REMOVED_INTERFACES .= "<span class=\"iname\">".$Interface."</span><br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013224 }
13225 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013226 }
13227 }
13228 $REMOVED_INTERFACES .= "<br/>\n";
13229 }
13230 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013231 if($REMOVED_INTERFACES)
13232 {
13233 my $Anchor = "<a name='Removed'></a><a name='Withdrawn'></a>";
13234 if($JoinReport) {
13235 $Anchor = "<a name='".$Level."_Removed'></a><a name='".$Level."_Withdrawn'></a>";
13236 }
13237 $REMOVED_INTERFACES = $Anchor."<h2>Removed Symbols ($Removed_Number)</h2><hr/>\n".$REMOVED_INTERFACES.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013238 }
13239 }
13240 return $REMOVED_INTERFACES;
13241}
13242
13243sub getXmlParams($$)
13244{
13245 my ($Content, $Problem) = @_;
13246 return "" if(not $Content or not $Problem);
13247 my %XMLparams = ();
13248 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
13249 {
13250 my $Macro = "\@".lc($Attr);
13251 if($Content=~/\Q$Macro\E/) {
13252 $XMLparams{lc($Attr)} = $Problem->{$Attr};
13253 }
13254 }
13255 my @PString = ();
13256 foreach my $P (sort {$b cmp $a} keys(%XMLparams)) {
13257 push(@PString, $P."=\"".htmlSpecChars($XMLparams{$P})."\"");
13258 }
13259 if(@PString) {
13260 return " ".join(" ", @PString);
13261 }
13262 else {
13263 return "";
13264 }
13265}
13266
13267sub addMarkup($)
13268{
13269 my $Content = $_[0];
13270 # auto-markup
13271 $Content=~s/\n[ ]*//; # spaces
13272 $Content=~s!(\@\w+\s*\(\@\w+\))!<nowrap>$1</nowrap>!g; # @old_type (@old_size)
13273 $Content=~s!(... \(\w+\))!<nowrap><b>$1</b></nowrap>!g; # ... (va_list)
13274 $Content=~s!([2-9]\))!<br/>$1!g; # 1), 2), ...
13275 if($Content=~/\ANOTE:/)
13276 { # notes
13277 $Content=~s!(NOTE):!<b>$1</b>:!g;
13278 }
13279 else {
13280 $Content=~s!(NOTE):!<br/><b>$1</b>:!g;
13281 }
13282 $Content=~s! (out)-! <b>$1</b>-!g; # out-parameters
13283 my @Keywords = (
13284 "void",
13285 "const",
13286 "static",
13287 "restrict",
13288 "volatile",
13289 "register",
13290 "virtual",
13291 "virtually"
13292 );
13293 my $MKeys = join("|", @Keywords);
13294 foreach (@Keywords) {
13295 $MKeys .= "|non-".$_;
13296 }
13297 $Content=~s!(added\s*|to\s*|from\s*|became\s*)($MKeys)([^\w-]|\Z)!$1<b>$2</b>$3!ig; # intrinsic types, modifiers
13298 return $Content;
13299}
13300
13301sub applyMacroses($$$$)
13302{
13303 my ($Level, $Kind, $Content, $Problem) = @_;
13304 return "" if(not $Content or not $Problem);
13305 $Problem->{"Word_Size"} = $WORD_SIZE{2};
13306 $Content = addMarkup($Content);
13307 # macros
13308 foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
13309 {
13310 my $Macro = "\@".lc($Attr);
13311 my $Value = $Problem->{$Attr};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013312 if(not defined $Value
13313 or $Value eq "") {
13314 next;
13315 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013316 if($Value=~/\s\(/)
13317 { # functions
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013318 $Value=~s/\s*\[[\w\-]+\]//g; # remove quals
13319 $Value=~s/\s\w+(\)|,)/$1/g; # remove parameter names
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013320 $Value = black_name($Value);
13321 }
13322 elsif($Value=~/\s/) {
13323 $Value = "<span class='value'>".htmlSpecChars($Value)."</span>";
13324 }
13325 elsif($Value=~/\A\d+\Z/
13326 and ($Attr eq "Old_Size" or $Attr eq "New_Size"))
13327 { # bits to bytes
13328 if($Value % $BYTE_SIZE)
13329 { # bits
13330 if($Value==1) {
13331 $Value = "<b>".$Value."</b> bit";
13332 }
13333 else {
13334 $Value = "<b>".$Value."</b> bits";
13335 }
13336 }
13337 else
13338 { # bytes
13339 $Value /= $BYTE_SIZE;
13340 if($Value==1) {
13341 $Value = "<b>".$Value."</b> byte";
13342 }
13343 else {
13344 $Value = "<b>".$Value."</b> bytes";
13345 }
13346 }
13347 }
13348 else {
13349 $Value = "<b>".htmlSpecChars($Value)."</b>";
13350 }
13351 $Content=~s/\Q$Macro\E/$Value/g;
13352 }
13353
13354 if($Content=~/(\A|[^\@\w])\@\w/)
13355 {
13356 if(not $IncompleteRules{$Level}{$Kind})
13357 { # only one warning
13358 printMsg("WARNING", "incomplete rule \"$Kind\" (\"$Level\")");
13359 $IncompleteRules{$Level}{$Kind} = 1;
13360 }
13361 }
13362 $Content=~s!<nowrap>(.+?)</nowrap>!<span class='nowrap'>$1</span>!g;
13363 return $Content;
13364}
13365
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013366sub get_Report_SymbolProblems($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013367{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013368 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013369 my $INTERFACE_PROBLEMS = "";
13370 my (%ReportMap, %SymbolChanges) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013371 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013372 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013373 my ($SN, $SS, $SV) = separate_symbol($Symbol);
13374 if($SV and defined $CompatProblems{$Level}{$SN}) {
13375 next;
13376 }
13377 foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013378 {
13379 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols"
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013380 and $Kind ne "Added_Symbol" and $Kind ne "Removed_Symbol")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013381 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013382 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
13383 my $DyLib = $Symbol_Library{1}{$Symbol};
13384 if(not $DyLib and my $VSym = $SymVer{1}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013385 { # Symbol with Version
13386 $DyLib = $Symbol_Library{1}{$VSym};
13387 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013388 if($Level eq "Source" and $ReportFormat eq "html")
13389 { # do not show library name in HTML report
13390 $DyLib = "";
13391 }
13392 %{$SymbolChanges{$Symbol}{$Kind}} = %{$CompatProblems{$Level}{$Symbol}{$Kind}};
13393 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013394 {
13395 my $Priority = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013396 if($Priority ne $TargetSeverity) {
13397 delete($SymbolChanges{$Symbol}{$Kind}{$Location});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013398 }
13399 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013400 if(not keys(%{$SymbolChanges{$Symbol}{$Kind}}))
13401 {
13402 delete($SymbolChanges{$Symbol}{$Kind});
13403 next;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013404 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013405 $ReportMap{$HeaderName}{$DyLib}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013406 }
13407 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013408 if(not keys(%{$SymbolChanges{$Symbol}})) {
13409 delete($SymbolChanges{$Symbol});
13410 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013411 }
13412 if($ReportFormat eq "xml")
13413 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013414 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013415 {
13416 $INTERFACE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013417 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013418 {
13419 $INTERFACE_PROBLEMS .= " <library name=\"$DyLib\">\n";
13420 foreach my $Symbol (sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%SymbolChanges))
13421 {
13422 $INTERFACE_PROBLEMS .= " <symbol name=\"$Symbol\">\n";
13423 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
13424 {
13425 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
13426 {
13427 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013428 $Problem{"Param_Pos"} = showNum($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013429 $INTERFACE_PROBLEMS .= " <problem id=\"$Kind\">\n";
13430 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
13431 $INTERFACE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
13432 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
13433 $INTERFACE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
13434 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
13435 $INTERFACE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
13436 $INTERFACE_PROBLEMS .= " </problem>\n";
13437 }
13438 }
13439 $INTERFACE_PROBLEMS .= " </symbol>\n";
13440 }
13441 $INTERFACE_PROBLEMS .= " </library>\n";
13442 }
13443 $INTERFACE_PROBLEMS .= " </header>\n";
13444 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013445 $INTERFACE_PROBLEMS = "<problems_with_symbols severity=\"$TargetSeverity\">\n".$INTERFACE_PROBLEMS."</problems_with_symbols>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013446 }
13447 else
13448 { # HTML
13449 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013450 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013451 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013452 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013453 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013454 my (%NameSpaceSymbols, %NewSignature) = ();
13455 foreach my $Symbol (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
13456 $NameSpaceSymbols{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013457 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013458 foreach my $NameSpace (sort keys(%NameSpaceSymbols))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013459 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013460 $INTERFACE_PROBLEMS .= getTitle($HeaderName, $DyLib, $NameSpace);
13461 my @SortedInterfaces = sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%{$NameSpaceSymbols{$NameSpace}});
13462 foreach my $Symbol (@SortedInterfaces)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013463 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013464 my $Signature = get_Signature($Symbol, 1);
13465 my $SYMBOL_REPORT = "";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013466 my $ProblemNum = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013467 foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013468 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013469 foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013470 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013471 my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013472 $Problem{"Param_Pos"} = showNum($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013473 if($Problem{"New_Signature"}) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013474 $NewSignature{$Symbol} = $Problem{"New_Signature"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013475 }
13476 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
13477 {
13478 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013479 $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 +040013480 $ProblemNum += 1;
13481 $ProblemsNum += 1;
13482 }
13483 }
13484 }
13485 $ProblemNum -= 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013486 if($SYMBOL_REPORT)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013487 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013488 $INTERFACE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> ";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013489 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013490 $INTERFACE_PROBLEMS .= highLight_Signature_Italic_Color($Signature);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013491 }
13492 else {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013493 $INTERFACE_PROBLEMS .= $Symbol;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013494 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013495 $INTERFACE_PROBLEMS .= " ($ProblemNum)".$ContentSpanEnd."<br/>\n";
13496 $INTERFACE_PROBLEMS .= $ContentDivStart."\n";
13497 if($NewSignature{$Symbol})
13498 { # argument list changed to
13499 $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 +040013500 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013501 if($Symbol=~/\A(_Z|\?)/) {
13502 $INTERFACE_PROBLEMS .= "<span class='mangled'>&#160;&#160;&#160;&#160;[symbol: <b>$Symbol</b>]</span><br/>\n";
13503 }
13504 $INTERFACE_PROBLEMS .= "<table class='ptable'><tr><th width='2%'></th><th width='47%'>Change</th><th>Effect</th></tr>$SYMBOL_REPORT</table><br/>\n";
13505 $INTERFACE_PROBLEMS .= $ContentDivEnd;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013506 if($NameSpace) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013507 $INTERFACE_PROBLEMS=~s/(\W|\A)\Q$NameSpace\E\:\:(\w)/$1$2/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013508 }
13509 }
13510 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013511 $INTERFACE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013512 }
13513 }
13514 }
13515 if($INTERFACE_PROBLEMS)
13516 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013517 $INTERFACE_PROBLEMS = insertIDs($INTERFACE_PROBLEMS);
13518 my $Title = "Problems with Symbols, $TargetSeverity Severity";
13519 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013520 { # Safe Changes
13521 $Title = "Other Changes in Symbols";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013522 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013523 $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 +040013524 }
13525 }
13526 return $INTERFACE_PROBLEMS;
13527}
13528
13529sub get_Report_TypeProblems($$)
13530{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013531 my ($TargetSeverity, $Level) = @_;
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013532 my $TYPE_PROBLEMS = "";
13533 my (%ReportMap, %TypeChanges, %TypeType) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013534 foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013535 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013536 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013537 {
13538 if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
13539 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013540 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Level}{$Interface}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013541 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013542 my $TypeName = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Name"};
13543 my $TypeType = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
13544 my $Target = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Target"};
13545 $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"} = lc($TypeType);
13546 my $Severity = getProblemSeverity($Level, $Kind);
13547 if($Severity eq "Safe"
13548 and $TargetSeverity ne "Safe") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013549 next;
13550 }
13551 if(not $TypeType{$TypeName}
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013552 or $TypeType{$TypeName} eq "struct")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013553 { # register type of the type, select "class" if type has "class"- and "struct"-type changes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013554 $TypeType{$TypeName} = $CompatProblems{$Level}{$Interface}{$Kind}{$Location}{"Type_Type"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013555 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013556
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013557 if(cmpSeverities($Type_MaxSeverity{$Level}{$TypeName}{$Kind}{$Target}, $Severity))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013558 { # select a problem with the highest priority
13559 next;
13560 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013561 %{$TypeChanges{$TypeName}{$Kind}{$Location}} = %{$CompatProblems{$Level}{$Interface}{$Kind}{$Location}};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013562 }
13563 }
13564 }
13565 }
13566 my %Kinds_Locations = ();
13567 foreach my $TypeName (keys(%TypeChanges))
13568 {
13569 my %Kinds_Target = ();
13570 foreach my $Kind (sort keys(%{$TypeChanges{$TypeName}}))
13571 {
13572 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
13573 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013574 my $Severity = getProblemSeverity($Level, $Kind);
13575 if($Severity ne $TargetSeverity)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013576 { # other priority
13577 delete($TypeChanges{$TypeName}{$Kind}{$Location});
13578 next;
13579 }
13580 $Kinds_Locations{$TypeName}{$Kind}{$Location} = 1;
13581 my $Target = $TypeChanges{$TypeName}{$Kind}{$Location}{"Target"};
13582 if($Kinds_Target{$Kind}{$Target})
13583 { # duplicate target
13584 delete($TypeChanges{$TypeName}{$Kind}{$Location});
13585 next;
13586 }
13587 $Kinds_Target{$Kind}{$Target} = 1;
13588 my $HeaderName = get_TypeAttr($TName_Tid{1}{$TypeName}, 1, "Header");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013589 $ReportMap{$HeaderName}{$TypeName} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013590 }
13591 if(not keys(%{$TypeChanges{$TypeName}{$Kind}})) {
13592 delete($TypeChanges{$TypeName}{$Kind});
13593 }
13594 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013595 if(not keys(%{$TypeChanges{$TypeName}})) {
13596 delete($TypeChanges{$TypeName});
13597 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013598 }
13599 if($ReportFormat eq "xml")
13600 { # XML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013601 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013602 {
13603 $TYPE_PROBLEMS .= " <header name=\"$HeaderName\">\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013604 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013605 {
13606 $TYPE_PROBLEMS .= " <type name=\"".htmlSpecChars($TypeName)."\">\n";
13607 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
13608 {
13609 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
13610 {
13611 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
13612 $TYPE_PROBLEMS .= " <problem id=\"$Kind\">\n";
13613 my $Change = $CompatRules{$Level}{$Kind}{"Change"};
13614 $TYPE_PROBLEMS .= " <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
13615 my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
13616 $TYPE_PROBLEMS .= " <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
13617 my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
13618 $TYPE_PROBLEMS .= " <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
13619 $TYPE_PROBLEMS .= " </problem>\n";
13620 }
13621 }
13622 $TYPE_PROBLEMS .= getAffectedInterfaces($Level, $TypeName, $Kinds_Locations{$TypeName});
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013623 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013624 $TYPE_PROBLEMS .= showVTables($TypeName);
13625 }
13626 $TYPE_PROBLEMS .= " </type>\n";
13627 }
13628 $TYPE_PROBLEMS .= " </header>\n";
13629 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013630 $TYPE_PROBLEMS = "<problems_with_types severity=\"$TargetSeverity\">\n".$TYPE_PROBLEMS."</problems_with_types>\n\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013631 }
13632 else
13633 { # HTML
13634 my $ProblemsNum = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013635 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013636 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013637 my (%NameSpace_Type) = ();
13638 foreach my $TypeName (keys(%{$ReportMap{$HeaderName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013639 $NameSpace_Type{parse_TypeNameSpace($TypeName, 1)}{$TypeName} = 1;
13640 }
13641 foreach my $NameSpace (sort keys(%NameSpace_Type))
13642 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013643 $TYPE_PROBLEMS .= getTitle($HeaderName, "", $NameSpace);
13644 my @SortedTypes = sort {$TypeType{$a}." ".lc($a) cmp $TypeType{$b}." ".lc($b)} keys(%{$NameSpace_Type{$NameSpace}});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013645 foreach my $TypeName (@SortedTypes)
13646 {
13647 my $ProblemNum = 1;
13648 my $TYPE_REPORT = "";
13649 foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
13650 {
13651 foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
13652 {
13653 my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
13654 if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
13655 {
13656 my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
13657 $TYPE_REPORT .= "<tr><th>$ProblemNum</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>$Effect</td></tr>\n";
13658 $ProblemNum += 1;
13659 $ProblemsNum += 1;
13660 }
13661 }
13662 }
13663 $ProblemNum -= 1;
13664 if($TYPE_REPORT)
13665 {
13666 my $Affected = getAffectedInterfaces($Level, $TypeName, $Kinds_Locations{$TypeName});
13667 my $ShowVTables = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013668 if($Level eq "Binary" and grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013669 $ShowVTables = showVTables($TypeName);
13670 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013671 $TYPE_PROBLEMS .= $ContentSpanStart."<span class='extendable'>[+]</span> <span class='ttype'>".$TypeType{$TypeName}."</span> ".htmlSpecChars($TypeName)." ($ProblemNum)".$ContentSpanEnd;
13672 $TYPE_PROBLEMS .= "<br/>\n".$ContentDivStart."<table class='ptable'><tr>\n";
13673 $TYPE_PROBLEMS .= "<th width='2%'></th><th width='47%'>Change</th>\n";
13674 $TYPE_PROBLEMS .= "<th>Effect</th></tr>".$TYPE_REPORT."</table>\n";
13675 $TYPE_PROBLEMS .= $ShowVTables.$Affected."<br/><br/>".$ContentDivEnd."\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013676 if($NameSpace) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013677 $TYPE_PROBLEMS=~s/(\W|\A)\Q$NameSpace\E\:\:(\w|\~)/$1$2/g;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013678 }
13679 }
13680 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013681 $TYPE_PROBLEMS .= "<br/>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013682 }
13683 }
13684 if($TYPE_PROBLEMS)
13685 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013686 $TYPE_PROBLEMS = insertIDs($TYPE_PROBLEMS);
13687 my $Title = "Problems with Data Types, $TargetSeverity Severity";
13688 my $Anchor = "Type_Problems_$TargetSeverity";
13689 if($TargetSeverity eq "Safe")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013690 { # Safe Changes
13691 $Title = "Other Changes in Data Types";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013692 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013693 $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 +040013694 }
13695 }
13696 return $TYPE_PROBLEMS;
13697}
13698
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013699sub get_Anchor($$$)
13700{
13701 my ($Kind, $Level, $Severity) = @_;
13702 if($JoinReport)
13703 {
13704 if($Severity eq "Safe") {
13705 return "Other_".$Level."_Changes_In_".$Kind."s";
13706 }
13707 else {
13708 return $Kind."_".$Level."_Problems_".$Severity;
13709 }
13710 }
13711 else
13712 {
13713 if($Severity eq "Safe") {
13714 return "Other_Changes_In_".$Kind."s";
13715 }
13716 else {
13717 return $Kind."_Problems_".$Severity;
13718 }
13719 }
13720}
13721
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013722sub showVTables($)
13723{
13724 my $TypeName = $_[0];
13725 my $TypeId1 = $TName_Tid{1}{$TypeName};
13726 my %Type1 = get_Type($Tid_TDid{1}{$TypeId1}, $TypeId1, 1);
13727 if(defined $Type1{"VTable"}
13728 and keys(%{$Type1{"VTable"}}))
13729 {
13730 my $TypeId2 = $TName_Tid{2}{$TypeName};
13731 my %Type2 = get_Type($Tid_TDid{2}{$TypeId2}, $TypeId2, 2);
13732 if(defined $Type2{"VTable"}
13733 and keys(%{$Type2{"VTable"}}))
13734 {
13735 my %Indexes = map {$_=>1} (keys(%{$Type1{"VTable"}}), keys(%{$Type2{"VTable"}}));
13736 my %Entries = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013737 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Indexes)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013738 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013739 $Entries{$Index}{"E1"} = simpleVEntry($Type1{"VTable"}{$Index});
13740 $Entries{$Index}{"E2"} = simpleVEntry($Type2{"VTable"}{$Index});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013741 }
13742 my $VTABLES = "";
13743 if($ReportFormat eq "xml")
13744 { # XML
13745 $VTABLES .= " <vtable>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013746 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013747 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013748 $VTABLES .= " <entry offset=\"".$Index."\">\n";
13749 $VTABLES .= " <old>".htmlSpecChars($Entries{$Index}{"E1"})."</old>\n";
13750 $VTABLES .= " <new>".htmlSpecChars($Entries{$Index}{"E2"})."</new>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013751 $VTABLES .= " </entry>\n";
13752 }
13753 $VTABLES .= " </vtable>\n\n";
13754 }
13755 else
13756 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013757 $VTABLES .= "<table class='vtable'>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013758 $VTABLES .= "<tr><th width='2%'>Offset</th>";
13759 $VTABLES .= "<th width='45%'>Virtual Table (Old) - ".(keys(%{$Type1{"VTable"}}))." entries</th>";
13760 $VTABLES .= "<th>Virtual Table (New) - ".(keys(%{$Type2{"VTable"}}))." entries</th></tr>";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013761 foreach my $Index (sort {int($a)<=>int($b)} (keys(%Entries)))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013762 {
13763 my ($Color1, $Color2) = ("", "");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013764 if($Entries{$Index}{"E1"} ne $Entries{$Index}{"E2"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013765 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013766 if($Entries{$Index}{"E1"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013767 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013768 $Color1 = " class='failed'";
13769 $Color2 = " class='failed'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013770 }
13771 else {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040013772 $Color2 = " class='warning'";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013773 }
13774 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013775 $VTABLES .= "<tr><th>".$Index."</th>\n";
13776 $VTABLES .= "<td$Color1>".htmlSpecChars($Entries{$Index}{"E1"})."</td>\n";
13777 $VTABLES .= "<td$Color2>".htmlSpecChars($Entries{$Index}{"E2"})."</td></tr>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013778 }
13779 $VTABLES .= "</table><br/>\n";
13780 $VTABLES = $ContentDivStart.$VTABLES.$ContentDivEnd;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013781 $VTABLES = $ContentSpanStart_Info."[+] show v-table (old and new)".$ContentSpanEnd."<br/>\n".$VTABLES;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013782 }
13783 return $VTABLES;
13784 }
13785 }
13786 return "";
13787}
13788
13789sub simpleVEntry($)
13790{
13791 my $VEntry = $_[0];
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013792 if(not defined $VEntry
13793 or $VEntry eq "") {
13794 return "";
13795 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013796 $VEntry=~s/\A(.+)::(_ZThn.+)\Z/$2/; # thunks
13797 $VEntry=~s/_ZTI\w+/typeinfo/g; # typeinfo
13798 if($VEntry=~/\A_ZThn.+\Z/) {
13799 $VEntry = "non-virtual thunk";
13800 }
13801 $VEntry=~s/\A\(int \(\*\)\(...\)\)([^\(\d])/$1/i;
13802 # support for old GCC versions
13803 $VEntry=~s/\A0u\Z/(int (*)(...))0/;
13804 $VEntry=~s/\A4294967268u\Z/(int (*)(...))-0x000000004/;
13805 $VEntry=~s/\A&_Z\Z/& _Z/;
13806 # templates
13807 if($VEntry=~s/ \[with (\w+) = (.+?)(, [^=]+ = .+|])\Z//g)
13808 { # std::basic_streambuf<_CharT, _Traits>::imbue [with _CharT = char, _Traits = std::char_traits<char>]
13809 # become std::basic_streambuf<char, ...>::imbue
13810 my ($Pname, $Pval) = ($1, $2);
13811 if($Pname eq "_CharT" and $VEntry=~/\Astd::/)
13812 { # stdc++ typedefs
13813 $VEntry=~s/<$Pname(, [^<>]+|)>/<$Pval>/g;
13814 # FIXME: simplify names using stdcxx typedefs (StdCxxTypedef)
13815 # The typedef info should be added to ABI dumps
13816 }
13817 else
13818 {
13819 $VEntry=~s/<$Pname>/<$Pval>/g;
13820 $VEntry=~s/<$Pname, [^<>]+>/<$Pval, ...>/g;
13821 }
13822 }
13823 $VEntry=~s/([^:]+)::\~([^:]+)\Z/~$1/; # destructors
13824 return $VEntry;
13825}
13826
13827sub getAffectedInterfaces($$$)
13828{
13829 my ($Level, $Target_TypeName, $Kinds_Locations) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013830 my (%INumber, %SymProblems) = ();
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013831 my $LIMIT = 1000;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013832 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 +040013833 {
13834 last if(keys(%INumber)>$LIMIT);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013835 if(($Symbol=~/C2E|D2E|D0E/))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013836 { # duplicated problems for C2 constructors, D2 and D0 destructors
13837 next;
13838 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013839 my ($SN, $SS, $SV) = separate_symbol($Symbol);
13840 if($Level eq "Source")
13841 { # remove symbol version
13842 $Symbol=$SN;
13843 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013844 my ($MinPath_Length, $ProblemLocation_Last) = (-1, "");
13845 my $Severity_Max = 0;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013846 my $Signature = get_Signature($Symbol, 1);
13847 foreach my $Kind (keys(%{$CompatProblems{$Level}{$Symbol}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013848 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013849 foreach my $Location (keys(%{$CompatProblems{$Level}{$Symbol}{$Kind}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013850 {
13851 if(not defined $Kinds_Locations->{$Kind}
13852 or not $Kinds_Locations->{$Kind}{$Location}) {
13853 next;
13854 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013855 if($SV and defined $CompatProblems{$Level}{$SN}
13856 and defined $CompatProblems{$Level}{$SN}{$Kind}{$Location})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013857 { # duplicated problems for versioned symbols
13858 next;
13859 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013860 my $Type_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Type_Name"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013861 next if($Type_Name ne $Target_TypeName);
13862
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013863 my $Position = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Pos"};
13864 my $Param_Name = $CompatProblems{$Level}{$Symbol}{$Kind}{$Location}{"Param_Name"};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013865 my $Severity = getProblemSeverity($Level, $Kind);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013866 $INumber{$Symbol} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013867 my $Path_Length = 0;
13868 my $ProblemLocation = $Location;
13869 if($Type_Name) {
13870 $ProblemLocation=~s/->\Q$Type_Name\E\Z//g;
13871 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013872 while($ProblemLocation=~/\-\>/g) {
13873 $Path_Length += 1;
13874 }
13875 if($MinPath_Length==-1 or ($Path_Length<=$MinPath_Length and $Severity_Val{$Severity}>$Severity_Max)
13876 or (cmp_locations($ProblemLocation, $ProblemLocation_Last) and $Severity_Val{$Severity}==$Severity_Max))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013877 {
13878 $MinPath_Length = $Path_Length;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013879 $Severity_Max = $Severity_Val{$Severity};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013880 $ProblemLocation_Last = $ProblemLocation;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013881 %{$SymProblems{$Symbol}} = (
13882 "Descr"=>getAffectDescription($Level, $Symbol, $Kind, $Location),
13883 "Severity_Max"=>$Severity_Max,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013884 "Signature"=>$Signature,
13885 "Position"=>$Position,
13886 "Param_Name"=>$Param_Name,
13887 "Location"=>$Location
13888 );
13889 }
13890 }
13891 }
13892 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013893 my @Symbols = keys(%SymProblems);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013894 @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 +040013895 @Symbols = sort {$SymProblems{$b}{"Severity_Max"}<=>$SymProblems{$a}{"Severity_Max"}} @Symbols;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013896 my $Affected = "";
13897 if($ReportFormat eq "xml")
13898 { # XML
13899 $Affected .= " <affected>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013900 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013901 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013902 my $Param_Name = $SymProblems{$Symbol}{"Param_Name"};
13903 my $Description = $SymProblems{$Symbol}{"Descr"};
13904 my $Location = $SymProblems{$Symbol}{"Location"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013905 my $Target = "";
13906 if($Param_Name) {
13907 $Target = " affected=\"param\" param_name=\"$Param_Name\"";
13908 }
13909 elsif($Location=~/\Aretval(\-|\Z)/i) {
13910 $Target = " affected=\"retval\"";
13911 }
13912 elsif($Location=~/\Athis(\-|\Z)/i) {
13913 $Target = " affected=\"this\"";
13914 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013915 $Affected .= " <symbol$Target name=\"$Symbol\">\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013916 $Affected .= " <comment>".htmlSpecChars($Description)."</comment>\n";
13917 $Affected .= " </symbol>\n";
13918 }
13919 $Affected .= " </affected>\n";
13920 }
13921 else
13922 { # HTML
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013923 foreach my $Symbol (@Symbols)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013924 {
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013925 my $Description = $SymProblems{$Symbol}{"Descr"};
13926 my $Signature = $SymProblems{$Symbol}{"Signature"};
13927 my $Pos = $SymProblems{$Symbol}{"Position"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013928 $Affected .= "<span class='iname_b'>".highLight_Signature_PPos_Italic($Signature, $Pos, 1, 0, 0)."</span><br/>"."<div class='affect'>".htmlSpecChars($Description)."</div>\n";
13929 }
13930 $Affected = "<div class='affected'>".$Affected."</div>";
13931 if(keys(%INumber)>$LIMIT) {
13932 $Affected .= "and others ...<br/>";
13933 }
13934 if($Affected)
13935 {
13936 $Affected = $ContentDivStart.$Affected.$ContentDivEnd;
13937 my $AHeader = $ContentSpanStart_Affected."[+] affected symbols (".(keys(%INumber)>$LIMIT?"more than $LIMIT":keys(%INumber)).")".$ContentSpanEnd;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013938 $Affected = $AHeader.$Affected;
13939 }
13940 }
13941 return $Affected;
13942}
13943
13944sub cmp_locations($$)
13945{
13946 my ($Location1, $Location2) = @_;
13947 if($Location2=~/(\A|\W)(retval|this)(\W|\Z)/
13948 and $Location1!~/(\A|\W)(retval|this)(\W|\Z)/ and $Location1!~/\-\>/) {
13949 return 1;
13950 }
13951 if($Location2=~/(\A|\W)(retval|this)(\W|\Z)/ and $Location2=~/\-\>/
13952 and $Location1!~/(\A|\W)(retval|this)(\W|\Z)/ and $Location1=~/\-\>/) {
13953 return 1;
13954 }
13955 return 0;
13956}
13957
13958sub getAffectDescription($$$$)
13959{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013960 my ($Level, $Symbol, $Kind, $Location) = @_;
13961 my %Problem = %{$CompatProblems{$Level}{$Symbol}{$Kind}{$Location}};
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013962 my $PPos = showNum($Problem{"Param_Pos"});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013963 my @Sentence = ();
13964 $Location=~s/\A(.*)\-\>.+?\Z/$1/;
13965 if($Kind eq "Overridden_Virtual_Method"
13966 or $Kind eq "Overridden_Virtual_Method_B") {
13967 push(@Sentence, "The method '".$Problem{"New_Value"}."' will be called instead of this method.");
13968 }
13969 elsif($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
13970 {
13971 if($Location eq "this" or $Kind=~/(\A|_)Virtual(_|\Z)/)
13972 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040013973 my $METHOD_TYPE = $CompleteSignature{1}{$Symbol}{"Constructor"}?"constructor":"method";
13974 my $ClassName = get_TypeName($CompleteSignature{1}{$Symbol}{"Class"}, 1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040013975 if($ClassName eq $Problem{"Type_Name"}) {
13976 push(@Sentence, "This $METHOD_TYPE is from \'".$Problem{"Type_Name"}."\' class.");
13977 }
13978 else {
13979 push(@Sentence, "This $METHOD_TYPE is from derived class \'".$ClassName."\'.");
13980 }
13981 }
13982 else
13983 {
13984 if($Location=~/retval/)
13985 { # return value
13986 if($Location=~/\-\>/) {
13987 push(@Sentence, "Field \'".$Location."\' in return value");
13988 }
13989 else {
13990 push(@Sentence, "Return value");
13991 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040013992 if(my $Init = $Problem{"InitialType_Type"})
13993 {
13994 if($Init eq "Pointer") {
13995 push(@Sentence, "(pointer)");
13996 }
13997 elsif($Init eq "Ref") {
13998 push(@Sentence, "(reference)");
13999 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014000 }
14001 }
14002 elsif($Location=~/this/)
14003 { # "this" pointer
14004 if($Location=~/\-\>/) {
14005 push(@Sentence, "Field \'".$Location."\' in the object of this method");
14006 }
14007 else {
14008 push(@Sentence, "\'this\' pointer");
14009 }
14010 }
14011 else
14012 { # parameters
14013 if($Location=~/\-\>/) {
14014 push(@Sentence, "Field \'".$Location."\' in $PPos parameter");
14015 }
14016 else {
14017 push(@Sentence, "$PPos parameter");
14018 }
14019 if($Problem{"Param_Name"}) {
14020 push(@Sentence, "\'".$Problem{"Param_Name"}."\'");
14021 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014022 if(my $Init = $Problem{"InitialType_Type"})
14023 {
14024 if($Init eq "Pointer") {
14025 push(@Sentence, "(pointer)");
14026 }
14027 elsif($Init eq "Ref") {
14028 push(@Sentence, "(reference)");
14029 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014030 }
14031 }
14032 if($Location eq "this") {
14033 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
14034 }
14035 elsif($Problem{"Start_Type_Name"} eq $Problem{"Type_Name"}) {
14036 push(@Sentence, "has type \'".$Problem{"Type_Name"}."\'.");
14037 }
14038 else {
14039 push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
14040 }
14041 }
14042 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014043 if($ExtendedFuncs{$Symbol}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014044 push(@Sentence, " This is a symbol from an artificial external library that may use the \'$TargetLibraryName\' library and change its ABI after recompiling.");
14045 }
14046 return join(" ", @Sentence);
14047}
14048
14049sub get_XmlSign($$)
14050{
14051 my ($Symbol, $LibVersion) = @_;
14052 my $Info = $CompleteSignature{$LibVersion}{$Symbol};
14053 my $Report = "";
14054 foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$Info->{"Param"}}))
14055 {
14056 my $Name = $Info->{"Param"}{$Pos}{"name"};
14057 my $TypeName = get_TypeName($Info->{"Param"}{$Pos}{"type"}, $LibVersion);
14058 foreach my $Typedef (keys(%ChangedTypedef))
14059 {
14060 my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
14061 $TypeName=~s/(\A|\W)\Q$Typedef\E(\W|\Z)/$1$Base$2/g;
14062 }
14063 $Report .= " <param pos=\"$Pos\">\n";
14064 $Report .= " <name>".$Name."</name>\n";
14065 $Report .= " <type>".htmlSpecChars($TypeName)."</type>\n";
14066 $Report .= " </param>\n";
14067 }
14068 if(my $Return = $Info->{"Return"})
14069 {
14070 my $RTName = get_TypeName($Return, $LibVersion);
14071 $Report .= " <retval>\n";
14072 $Report .= " <type>".htmlSpecChars($RTName)."</type>\n";
14073 $Report .= " </retval>\n";
14074 }
14075 return $Report;
14076}
14077
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014078sub get_Report_SymbolsInfo($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014079{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014080 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014081 my $Report = "<symbols_info>\n";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014082 foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014083 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014084 my ($SN, $SS, $SV) = separate_symbol($Symbol);
14085 if($SV and defined $CompatProblems{$Level}{$SN}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014086 next;
14087 }
14088 $Report .= " <symbol name=\"$Symbol\">\n";
14089 my ($S1, $P1, $S2, $P2) = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014090 if(not $AddedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014091 {
14092 if(defined $CompleteSignature{1}{$Symbol}
14093 and defined $CompleteSignature{1}{$Symbol}{"Header"})
14094 {
14095 $P1 = get_XmlSign($Symbol, 1);
14096 $S1 = get_Signature($Symbol, 1);
14097 }
14098 elsif($Symbol=~/\A(_Z|\?)/) {
14099 $S1 = $tr_name{$Symbol};
14100 }
14101 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014102 if(not $RemovedInt{$Level}{$Symbol})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014103 {
14104 if(defined $CompleteSignature{2}{$Symbol}
14105 and defined $CompleteSignature{2}{$Symbol}{"Header"})
14106 {
14107 $P2 = get_XmlSign($Symbol, 2);
14108 $S2 = get_Signature($Symbol, 2);
14109 }
14110 elsif($Symbol=~/\A(_Z|\?)/) {
14111 $S2 = $tr_name{$Symbol};
14112 }
14113 }
14114 if($S1)
14115 {
14116 $Report .= " <old signature=\"".htmlSpecChars($S1)."\">\n";
14117 $Report .= $P1;
14118 $Report .= " </old>\n";
14119 }
14120 if($S2 and $S2 ne $S1)
14121 {
14122 $Report .= " <new signature=\"".htmlSpecChars($S2)."\">\n";
14123 $Report .= $P2;
14124 $Report .= " </new>\n";
14125 }
14126 $Report .= " </symbol>\n";
14127 }
14128 $Report .= "</symbols_info>\n";
14129 return $Report;
14130}
14131
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014132sub writeReport($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014133{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014134 my ($Level, $Report) = @_;
14135 if($ReportFormat eq "xml") {
14136 $Report = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n".$Report;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014137 }
14138 if($StdOut)
14139 { # --stdout option
14140 print STDOUT $Report;
14141 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014142 else
14143 {
14144 my $RPath = getReportPath($Level);
14145 writeFile($RPath, $Report);
14146 if($Browse)
14147 {
14148 system($Browse." $RPath >/dev/null 2>&1 &");
14149 if($JoinReport or $DoubleReport)
14150 {
14151 if($Level eq "Binary")
14152 { # wait to open a browser
14153 sleep(1);
14154 }
14155 }
14156 }
14157 }
14158}
14159
14160sub getReport($)
14161{
14162 my $Level = $_[0];
14163 if($ReportFormat eq "xml")
14164 { # XML
14165
14166 if($Level eq "Join")
14167 {
14168 my $Report = "<reports>\n";
14169 $Report .= getReport("Binary");
14170 $Report .= getReport("Source");
14171 $Report .= "</reports>\n";
14172 return $Report;
14173 }
14174 else
14175 {
14176 my $Report = "<report kind=\"".lc($Level)."\" version=\"$XML_REPORT_VERSION\">\n\n";
14177 my ($Summary, $MetaData) = get_Summary($Level);
14178 $Report .= $Summary."\n";
14179 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
14180 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
14181 $Report .= get_Report_SymbolsInfo($Level);
14182 $Report .= "</report>\n";
14183 return $Report;
14184 }
14185 }
14186 else
14187 { # HTML
14188 my $CssStyles = readModule("Styles", "Report.css");
14189 my $JScripts = readModule("Scripts", "Sections.js");
14190 if($Level eq "Join")
14191 {
14192 $CssStyles .= "\n".readModule("Styles", "Tabs.css");
14193 $JScripts .= "\n".readModule("Scripts", "Tabs.js");
14194 my $Title = "$TargetLibraryFName: ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." compatibility report";
14195 my $Keywords = "$TargetLibraryFName, compatibility, API, report";
14196 my $Description = "Compatibility report for the $TargetLibraryFName $TargetComponent between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions";
14197 my ($BSummary, $BMetaData) = get_Summary("Binary");
14198 my ($SSummary, $SMetaData) = get_Summary("Source");
14199 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>";
14200 $Report .= get_Report_Header("Join")."
14201 <br/><div class='tabset'>
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014202 <a id='BinaryID' href='#BinaryTab' class='tab active'>Binary<br/>Compatibility</a>
14203 <a id='SourceID' href='#SourceTab' style='margin-left:3px' class='tab disabled'>Source<br/>Compatibility</a>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014204 </div>";
14205 $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>";
14206 $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>";
14207 $Report .= getReportFooter($TargetLibraryFName);
14208 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
14209 return $Report;
14210 }
14211 else
14212 {
14213 my ($Summary, $MetaData) = get_Summary($Level);
14214 my $Title = "$TargetLibraryFName: ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." ".lc($Level)." compatibility report";
14215 my $Keywords = "$TargetLibraryFName, ".lc($Level)." compatibility, API, report";
14216 my $Description = "$Level compatibility report for the $TargetLibraryFName $TargetComponent between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions";
14217 if($Level eq "Binary")
14218 {
14219 if(getArch(1) eq getArch(2)
14220 and getArch(1) ne "unknown") {
14221 $Description .= " on ".showArch(getArch(1));
14222 }
14223 }
14224 my $Report = "<!-\- $MetaData -\->\n".composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."\n<body>\n<div><a name='Top'></a>\n";
14225 $Report .= get_Report_Header($Level)."\n".$Summary."\n";
14226 $Report .= get_Report_Added($Level).get_Report_Removed($Level);
14227 $Report .= get_Report_Problems("High", $Level).get_Report_Problems("Medium", $Level).get_Report_Problems("Low", $Level).get_Report_Problems("Safe", $Level);
14228 $Report .= get_SourceInfo();
14229 $Report .= "</div>\n<br/><br/><br/><hr/>\n";
14230 $Report .= getReportFooter($TargetLibraryFName);
14231 $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
14232 return $Report;
14233 }
14234 }
14235}
14236
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014237sub getLegend()
14238{
14239 return "<br/>
14240<table class='summary'>
14241<tr>
14242 <td class='new'>added</td>
14243 <td class='passed'>compatible</td>
14244</tr>
14245<tr>
14246 <td class='warning'>warning</td>
14247 <td class='failed'>incompatible</td>
14248</tr></table>\n";
14249}
14250
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014251sub createReport()
14252{
14253 if($JoinReport)
14254 { # --join-report, --stdout
14255 writeReport("Join", getReport("Join"));
14256 }
14257 elsif($DoubleReport)
14258 { # default
14259 writeReport("Binary", getReport("Binary"));
14260 writeReport("Source", getReport("Source"));
14261 }
14262 elsif($BinaryOnly)
14263 { # --binary
14264 writeReport("Binary", getReport("Binary"));
14265 }
14266 elsif($SourceOnly)
14267 { # --source
14268 writeReport("Source", getReport("Source"));
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014269 }
14270}
14271
14272sub getReportFooter($)
14273{
14274 my $LibName = $_[0];
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014275 my $FooterStyle = (not $JoinReport)?"width:99%":"width:97%;padding-top:3px";
14276 my $Footer = "<div style='$FooterStyle;font-size:11px;' align='right'><i>Generated on ".(localtime time); # report date
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014277 $Footer .= " for <span style='font-weight:bold'>$LibName</span>"; # tested library/system name
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014278 $Footer .= " by <a href='".$HomePage{"Wiki"}."'>ABI Compliance Checker</a>"; # tool name
14279 my $ToolSummary = "<br/>A tool for checking backward compatibility of a C/C++ library API&#160;&#160;";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014280 $Footer .= " $TOOL_VERSION &#160;$ToolSummary</i></div>"; # tool version
14281 return $Footer;
14282}
14283
14284sub get_Report_Problems($$)
14285{
14286 my ($Priority, $Level) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014287 my $Report = get_Report_TypeProblems($Priority, $Level);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014288 if(my $SProblems = get_Report_SymbolProblems($Priority, $Level)) {
14289 $Report .= $SProblems;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014290 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014291 if($Priority eq "Low")
14292 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014293 $Report .= get_Report_ChangedConstants($Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014294 if($ReportFormat eq "html") {
14295 if($CheckImpl and $Level eq "Binary") {
14296 $Report .= get_Report_Impl();
14297 }
14298 }
14299 }
14300 if($ReportFormat eq "html")
14301 {
14302 if($Report)
14303 { # add anchor
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014304 if($JoinReport)
14305 {
14306 if($Priority eq "Safe") {
14307 $Report = "<a name=\'Other_".$Level."_Changes\'></a>".$Report;
14308 }
14309 else {
14310 $Report = "<a name=\'".$Priority."_Risk_".$Level."_Problems\'></a>".$Report;
14311 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014312 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014313 else
14314 {
14315 if($Priority eq "Safe") {
14316 $Report = "<a name=\'Other_Changes\'></a>".$Report;
14317 }
14318 else {
14319 $Report = "<a name=\'".$Priority."_Risk_Problems\'></a>".$Report;
14320 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014321 }
14322 }
14323 }
14324 return $Report;
14325}
14326
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014327sub composeHTML_Head($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014328{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014329 my ($Title, $Keywords, $Description, $Styles, $Scripts) = @_;
14330 return "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
14331 <html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">
14332 <head>
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014333 <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />
14334 <meta name=\"keywords\" content=\"$Keywords\" />
14335 <meta name=\"description\" content=\"$Description\" />
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014336 <title>
14337 $Title
14338 </title>
14339 <style type=\"text/css\">
14340 $Styles
14341 </style>
14342 <script type=\"text/javascript\" language=\"JavaScript\">
14343 <!--
14344 $Scripts
14345 -->
14346 </script>
14347 </head>";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014348}
14349
14350sub insertIDs($)
14351{
14352 my $Text = $_[0];
14353 while($Text=~/CONTENT_ID/)
14354 {
14355 if(int($Content_Counter)%2) {
14356 $ContentID -= 1;
14357 }
14358 $Text=~s/CONTENT_ID/c_$ContentID/;
14359 $ContentID += 1;
14360 $Content_Counter += 1;
14361 }
14362 return $Text;
14363}
14364
14365sub checkPreprocessedUnit($)
14366{
14367 my $Path = $_[0];
14368 my $CurHeader = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014369 open(PREPROC, $Path) || die ("can't open file \'$Path\': $!\n");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014370 while(<PREPROC>)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014371 { # detecting public and private constants
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014372 next if(not /\A#/);
14373 chomp($_);
14374 if(/#[ \t]+\d+[ \t]+\"(.+)\"/) {
14375 $CurHeader=path_format($1, $OSgroup);
14376 }
14377 if(not $Include_Neighbors{$Version}{get_filename($CurHeader)}
14378 and not $Registered_Headers{$Version}{$CurHeader})
14379 { # not a target
14380 next;
14381 }
14382 if(not is_target_header(get_filename($CurHeader)))
14383 { # user-defined header
14384 next;
14385 }
14386 if(/\#[ \t]*define[ \t]+([_A-Z0-9]+)[ \t]+(.+)[ \t]*\Z/)
14387 {
14388 my ($Name, $Value) = ($1, $2);
14389 if(not $Constants{$Version}{$Name}{"Access"})
14390 {
14391 $Constants{$Version}{$Name}{"Access"} = "public";
14392 $Constants{$Version}{$Name}{"Value"} = $Value;
14393 $Constants{$Version}{$Name}{"Header"} = get_filename($CurHeader);
14394 }
14395 }
14396 elsif(/\#[ \t]*undef[ \t]+([_A-Z]+)[ \t]*/) {
14397 $Constants{$Version}{$1}{"Access"} = "private";
14398 }
14399 }
14400 close(PREPROC);
14401 foreach my $Constant (keys(%{$Constants{$Version}}))
14402 {
14403 if($Constants{$Version}{$Constant}{"Access"} eq "private" or $Constant=~/_h\Z/i
14404 or isBuiltIn($Constants{$Version}{$Constant}{"Header"}))
14405 { # skip private constants
14406 delete($Constants{$Version}{$Constant});
14407 }
14408 else {
14409 delete($Constants{$Version}{$Constant}{"Access"});
14410 }
14411 }
14412}
14413
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014414sub uncoverConstant($$)
14415{
14416 my ($LibVersion, $Constant) = @_;
14417 return "" if(not $LibVersion or not $Constant);
14418 return $Constant if(isCyclical(\@RecurConstant, $Constant));
14419 if(defined $Cache{"uncoverConstant"}{$LibVersion}{$Constant}) {
14420 return $Cache{"uncoverConstant"}{$LibVersion}{$Constant};
14421 }
14422 my $Value = $Constants{$LibVersion}{$Constant}{"Value"};
14423 if(defined $Value)
14424 {
14425 if($Value=~/\A[A-Z0-9_]+\Z/ and $Value=~/[A-Z]/)
14426 {
14427 push(@RecurConstant, $Constant);
14428 my $Uncovered = uncoverConstant($LibVersion, $Value);
14429 if($Uncovered ne "") {
14430 $Value = $Uncovered;
14431 }
14432 pop(@RecurConstant);
14433 }
14434 # FIXME: uncover $Value using all the enum constants
14435 # USECASE: change of define NC_LONG from NC_INT (enum value) to NC_INT (define)
14436 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = $Value);
14437 }
14438 return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = "");
14439}
14440
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014441my %IgnoreConstant=(
14442 "VERSION"=>1,
14443 "VERSIONCODE"=>1,
14444 "VERNUM"=>1,
14445 "VERS_INFO"=>1,
14446 "PATCHLEVEL"=>1,
14447 "INSTALLPREFIX"=>1,
14448 "VBUILD"=>1,
14449 "VPATCH"=>1,
14450 "VMINOR"=>1,
14451 "BUILD_STRING"=>1,
14452 "BUILD_TIME"=>1,
14453 "PACKAGE_STRING"=>1,
14454 "PRODUCTION"=>1,
14455 "CONFIGURE_COMMAND"=>1,
14456 "INSTALLDIR"=>1,
14457 "BINDIR"=>1,
14458 "CONFIG_FILE_PATH"=>1,
14459 "DATADIR"=>1,
14460 "EXTENSION_DIR"=>1,
14461 "INCLUDE_PATH"=>1,
14462 "LIBDIR"=>1,
14463 "LOCALSTATEDIR"=>1,
14464 "SBINDIR"=>1,
14465 "SYSCONFDIR"=>1,
14466 "RELEASE"=>1,
14467 "SOURCE_ID"=>1,
14468 "SUBMINOR"=>1,
14469 "MINOR"=>1,
14470 "MINNOR"=>1,
14471 "MINORVERSION"=>1,
14472 "MAJOR"=>1,
14473 "MAJORVERSION"=>1,
14474 "MICRO"=>1,
14475 "MICROVERSION"=>1,
14476 "BINARY_AGE"=>1,
14477 "INTERFACE_AGE"=>1,
14478 "CORE_ABI"=>1,
14479 "PATCH"=>1,
14480 "COPYRIGHT"=>1,
14481 "TIMESTAMP"=>1,
14482 "REVISION"=>1,
14483 "PACKAGE_TAG"=>1,
14484 "PACKAGEDATE"=>1,
14485 "NUMVERSION"=>1
14486);
14487
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014488sub mergeConstants($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014489{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014490 my $Level = $_[0];
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014491 foreach my $Constant (keys(%{$Constants{1}}))
14492 {
14493 if($SkipConstants{1}{$Constant})
14494 { # skipped by the user
14495 next;
14496 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014497 if(not defined $Constants{2}{$Constant}{"Value"}
14498 or $Constants{2}{$Constant}{"Value"} eq "")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014499 { # empty value
14500 next;
14501 }
14502 if(not is_target_header($Constants{1}{$Constant}{"Header"}))
14503 { # user-defined header
14504 next;
14505 }
14506 my ($Old_Value, $New_Value, $Old_Value_Pure, $New_Value_Pure);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014507 $Old_Value = $Old_Value_Pure = uncoverConstant(1, $Constant);
14508 $New_Value = $New_Value_Pure = uncoverConstant(2, $Constant);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014509 $Old_Value_Pure=~s/(\W)\s+/$1/g;
14510 $Old_Value_Pure=~s/\s+(\W)/$1/g;
14511 $New_Value_Pure=~s/(\W)\s+/$1/g;
14512 $New_Value_Pure=~s/\s+(\W)/$1/g;
14513 next if($New_Value_Pure eq "" or $Old_Value_Pure eq "");
14514 if($New_Value_Pure ne $Old_Value_Pure)
14515 { # different values
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014516 if($Level eq "Binary")
14517 {
14518 if(grep {$Constant=~/(\A|_)$_(_|\Z)/} keys(%IgnoreConstant))
14519 { # ignore library version
14520 next;
14521 }
14522 if($Constant=~/(\A|_)(lib|open|)$TargetLibraryShortName(_|)(VERSION|VER|DATE|API|PREFIX)(_|\Z)/i)
14523 { # ignore library version
14524 next;
14525 }
14526 if($Old_Value=~/\A('|"|)[\/\\]\w+([\/\\]|:|('|"|)\Z)/ or $Old_Value=~/[\/\\]\w+[\/\\]\w+/)
14527 { # ignoring path defines:
14528 # /lib64:/usr/lib64:/lib:/usr/lib:/usr/X11R6/lib/Xaw3d ...
14529 next;
14530 }
14531 if($Old_Value=~/\A\(*[a-z_]+(\s+|\|)/i)
14532 { # ignore source defines:
14533 # static int gcry_pth_init ( void) { return ...
14534 # (RE_BACKSLASH_ESCAPE_IN_LISTS | RE...
14535 next;
14536 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014537 }
14538 if(convert_integer($Old_Value) eq convert_integer($New_Value))
14539 { # 0x0001 and 0x1, 0x1 and 1 equal constants
14540 next;
14541 }
14542 if($Old_Value eq "0" and $New_Value eq "NULL")
14543 { # 0 => NULL
14544 next;
14545 }
14546 if($Old_Value eq "NULL" and $New_Value eq "0")
14547 { # NULL => 0
14548 next;
14549 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014550 %{$ProblemsWithConstants{$Level}{$Constant}} = (
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014551 "Target"=>$Constant,
14552 "Old_Value"=>$Old_Value,
14553 "New_Value"=>$New_Value );
14554 }
14555 }
14556}
14557
14558sub convert_integer($)
14559{
14560 my $Value = $_[0];
14561 if($Value=~/\A0x[a-f0-9]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014562 { # hexadecimal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014563 return hex($Value);
14564 }
14565 elsif($Value=~/\A0[0-7]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014566 { # octal
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014567 return oct($Value);
14568 }
14569 elsif($Value=~/\A0b[0-1]+\Z/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014570 { # binary
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014571 return oct($Value);
14572 }
14573 else {
14574 return $Value;
14575 }
14576}
14577
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014578sub readSymbols($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014579{
14580 my $LibVersion = $_[0];
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014581 my @LibPaths = getSoPaths($LibVersion);
14582 if($#LibPaths==-1 and not $CheckHeadersOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014583 {
14584 if($LibVersion==1)
14585 {
14586 printMsg("WARNING", "checking headers only");
14587 $CheckHeadersOnly = 1;
14588 }
14589 else {
14590 exitStatus("Error", "$SLIB_TYPE libraries are not found in ".$Descriptor{$LibVersion}{"Version"});
14591 }
14592 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014593 my %GroupNames = map {parse_libname(get_filename($_), "name+ext", $OStarget)=>1} @LibPaths;
14594 foreach my $LibPath (sort {length($a)<=>length($b)} @LibPaths) {
14595 readSymbols_Lib($LibVersion, $LibPath, 0, \%GroupNames, "+Weak");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014596 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014597 if(not $CheckHeadersOnly)
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014598 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014599 if($#LibPaths!=-1)
14600 {
14601 if(not keys(%{$Symbol_Library{$LibVersion}}))
14602 {
14603 printMsg("WARNING", "the set of public symbols in library(ies) is empty");
14604 printMsg("WARNING", "checking headers only");
14605 $CheckHeadersOnly = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014606 }
14607 }
14608 }
14609}
14610
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014611sub getSymbolSize($$)
14612{ # size from the shared library
14613 my ($Symbol, $LibVersion) = @_;
14614 return 0 if(not $Symbol);
14615 if(defined $Symbol_Library{$LibVersion}{$Symbol}
14616 and my $LibName = $Symbol_Library{$LibVersion}{$Symbol})
14617 {
14618 if(defined $Library_Symbol{$LibVersion}{$LibName}{$Symbol}
14619 and my $Size = $Library_Symbol{$LibVersion}{$LibName}{$Symbol})
14620 {
14621 if($Size<0) {
14622 return -$Size;
14623 }
14624 }
14625 }
14626 return 0;
14627}
14628
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014629sub canonifyName($)
14630{ # make TIFFStreamOpen(char const*, std::basic_ostream<char, std::char_traits<char> >*)
14631 # to be TIFFStreamOpen(char const*, std::basic_ostream<char>*)
14632 my $Name = $_[0];
14633 my $Rem = "std::(allocator|less|char_traits|regex_traits)";
14634 if($Name=~/([^<>,]+),\s*$Rem<([^<>,]+)>\s*/)
14635 {
14636 if($1 eq $3)
14637 {
14638 my $P = $1;
14639 while($Name=~s/\Q$P\E,\s*$Rem<\Q$P\E>\s*/$P/g){};
14640 }
14641 }
14642 return $Name;
14643}
14644
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014645sub translateSymbols(@)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014646{
14647 my $LibVersion = pop(@_);
14648 my (@MnglNames1, @MnglNames2, @UnMnglNames) = ();
14649 foreach my $Interface (sort @_)
14650 {
14651 if($Interface=~/\A_Z/)
14652 {
14653 next if($tr_name{$Interface});
14654 $Interface=~s/[\@\$]+(.*)\Z//;
14655 push(@MnglNames1, $Interface);
14656 }
14657 elsif($Interface=~/\A\?/) {
14658 push(@MnglNames2, $Interface);
14659 }
14660 else
14661 { # not mangled
14662 $tr_name{$Interface} = $Interface;
14663 $mangled_name_gcc{$Interface} = $Interface;
14664 $mangled_name{$LibVersion}{$Interface} = $Interface;
14665 }
14666 }
14667 if($#MnglNames1 > -1)
14668 { # GCC names
14669 @UnMnglNames = reverse(unmangleArray(@MnglNames1));
14670 foreach my $MnglName (@MnglNames1)
14671 {
14672 my $Unmangled = $tr_name{$MnglName} = formatName(canonifyName(pop(@UnMnglNames)));
14673 if(not $mangled_name_gcc{$Unmangled}) {
14674 $mangled_name_gcc{$Unmangled} = $MnglName;
14675 }
14676 if($MnglName=~/\A_ZTV/ and $Unmangled=~/vtable for (.+)/)
14677 { # bind class name and v-table symbol
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014678 my $ClassName = $1;
14679 $ClassVTable{$ClassName} = $MnglName;
14680 $VTableClass{$MnglName} = $ClassName;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014681 }
14682 }
14683 }
14684 if($#MnglNames2 > -1)
14685 { # MSVC names
14686 @UnMnglNames = reverse(unmangleArray(@MnglNames2));
14687 foreach my $MnglName (@MnglNames2)
14688 {
14689 $tr_name{$MnglName} = formatName(pop(@UnMnglNames));
14690 $mangled_name{$LibVersion}{$tr_name{$MnglName}} = $MnglName;
14691 }
14692 }
14693 return \%tr_name;
14694}
14695
14696sub link_symbol($$$)
14697{
14698 my ($Symbol, $RunWith, $Deps) = @_;
14699 if(link_symbol_internal($Symbol, $RunWith, \%Symbol_Library)) {
14700 return 1;
14701 }
14702 if($Deps eq "+Deps")
14703 { # check the dependencies
14704 if(link_symbol_internal($Symbol, $RunWith, \%DepSymbols)) {
14705 return 1;
14706 }
14707 }
14708 return 0;
14709}
14710
14711sub link_symbol_internal($$$)
14712{
14713 my ($Symbol, $RunWith, $Where) = @_;
14714 return 0 if(not $Where or not $Symbol);
14715 if($Where->{$RunWith}{$Symbol})
14716 { # the exact match by symbol name
14717 return 1;
14718 }
14719 if(my $VSym = $SymVer{$RunWith}{$Symbol})
14720 { # indirect symbol version, i.e.
14721 # foo_old and its symlink foo@v (or foo@@v)
14722 # foo_old may be in .symtab table
14723 if($Where->{$RunWith}{$VSym}) {
14724 return 1;
14725 }
14726 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014727 my ($Sym, $Spec, $Ver) = separate_symbol($Symbol);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014728 if($Sym and $Ver)
14729 { # search for the symbol with the same version
14730 # or without version
14731 if($Where->{$RunWith}{$Sym})
14732 { # old: foo@v|foo@@v
14733 # new: foo
14734 return 1;
14735 }
14736 if($Where->{$RunWith}{$Sym."\@".$Ver})
14737 { # old: foo|foo@@v
14738 # new: foo@v
14739 return 1;
14740 }
14741 if($Where->{$RunWith}{$Sym."\@\@".$Ver})
14742 { # old: foo|foo@v
14743 # new: foo@@v
14744 return 1;
14745 }
14746 }
14747 return 0;
14748}
14749
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014750sub readSymbols_App($)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014751{
14752 my $Path = $_[0];
14753 return () if(not $Path or not -f $Path);
14754 my @Imported = ();
14755 if($OSgroup eq "macos")
14756 {
14757 my $OtoolCmd = get_CmdPath("otool");
14758 if(not $OtoolCmd) {
14759 exitStatus("Not_Found", "can't find \"otool\"");
14760 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014761 open(APP, "$OtoolCmd -IV \"".$Path."\" 2>$TMP_DIR/null |");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014762 while(<APP>) {
14763 if(/[^_]+\s+_?([\w\$]+)\s*\Z/) {
14764 push(@Imported, $1);
14765 }
14766 }
14767 close(APP);
14768 }
14769 elsif($OSgroup eq "windows")
14770 {
14771 my $DumpBinCmd = get_CmdPath("dumpbin");
14772 if(not $DumpBinCmd) {
14773 exitStatus("Not_Found", "can't find \"dumpbin.exe\"");
14774 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014775 open(APP, "$DumpBinCmd /IMPORTS \"".$Path."\" 2>$TMP_DIR/null |");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014776 while(<APP>) {
14777 if(/\s*\w+\s+\w+\s+\w+\s+([\w\?\@]+)\s*/) {
14778 push(@Imported, $1);
14779 }
14780 }
14781 close(APP);
14782 }
14783 else
14784 {
14785 my $ReadelfCmd = get_CmdPath("readelf");
14786 if(not $ReadelfCmd) {
14787 exitStatus("Not_Found", "can't find \"readelf\"");
14788 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014789 open(APP, "$ReadelfCmd -WhlSsdA \"".$Path."\" 2>$TMP_DIR/null |");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014790 my $symtab=0; # indicates that we are processing 'symtab' section of 'readelf' output
14791 while(<APP>)
14792 {
14793 if( /'.dynsym'/ ) {
14794 $symtab=0;
14795 }
14796 elsif($symtab == 1) {
14797 # do nothing with symtab (but there are some plans for the future)
14798 next;
14799 }
14800 elsif( /'.symtab'/ ) {
14801 $symtab=1;
14802 }
14803 elsif(my ($fullname, $idx, $Ndx, $type, $size, $bind) = readline_ELF($_))
14804 {
14805 if( $Ndx eq "UND" ) {
14806 #only imported symbols
14807 push(@Imported, $fullname);
14808 }
14809 }
14810 }
14811 close(APP);
14812 }
14813 return @Imported;
14814}
14815
14816sub readline_ELF($)
14817{
14818 if($_[0]=~/\s*\d+:\s+(\w*)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s([^\s]+)/)
14819 { # the line of 'readelf' output corresponding to the interface
14820 # symbian-style: _ZN12CCTTokenType4NewLE4TUid3RFs@@ctfinder{000a0000}[102020e5].dll
14821 my ($value, $size, $type, $bind,
14822 $vis, $Ndx, $fullname)=($1, $2, $3, $4, $5, $6, $7);
14823 if($bind!~/\A(WEAK|GLOBAL)\Z/) {
14824 return ();
14825 }
14826 if($type!~/\A(FUNC|IFUNC|OBJECT|COMMON)\Z/) {
14827 return ();
14828 }
14829 if($vis!~/\A(DEFAULT|PROTECTED)\Z/) {
14830 return ();
14831 }
14832 if($Ndx eq "ABS" and $value!~/\D|1|2|3|4|5|6|7|8|9/) {
14833 return ();
14834 }
14835 if($OStarget eq "symbian")
14836 {
14837 if($fullname=~/_\._\.absent_export_\d+/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014838 { # "_._.absent_export_111"@@libstdcpp{00010001}[10282872].dll
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014839 return ();
14840 }
14841 my @Elems = separate_symbol($fullname);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014842 $fullname = $Elems[0]; # remove internal version, {00020001}[10011235].dll
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014843 }
14844 return ($fullname, $value, $Ndx, $type, $size, $bind);
14845 }
14846 else {
14847 return ();
14848 }
14849}
14850
Andrey Ponomarenko16934472012-03-29 15:37:04 +040014851sub read_symlink($)
14852{
14853 my $Path = $_[0];
14854 return "" if(not $Path);
14855 return "" if(not -f $Path and not -l $Path);
14856 if(defined $Cache{"read_symlink"}{$Path}) {
14857 return $Cache{"read_symlink"}{$Path};
14858 }
14859 if(my $Res = readlink($Path)) {
14860 return ($Cache{"read_symlink"}{$Path} = $Res);
14861 }
14862 elsif(my $ReadlinkCmd = get_CmdPath("readlink")) {
14863 return ($Cache{"read_symlink"}{$Path} = `$ReadlinkCmd -n $Path`);
14864 }
14865 elsif(my $FileCmd = get_CmdPath("file"))
14866 {
14867 my $Info = `$FileCmd $Path`;
14868 if($Info=~/symbolic\s+link\s+to\s+['`"]*([\w\d\.\-\/\\]+)['`"]*/i) {
14869 return ($Cache{"read_symlink"}{$Path} = $1);
14870 }
14871 }
14872 return ($Cache{"read_symlink"}{$Path} = "");
14873}
14874
14875sub resolve_symlink($)
14876{
14877 my $Path = $_[0];
14878 return "" if(not $Path);
14879 return "" if(not -f $Path and not -l $Path);
14880 if(defined $Cache{"resolve_symlink"}{$Path}) {
14881 return $Cache{"resolve_symlink"}{$Path};
14882 }
14883 return $Path if(isCyclical(\@RecurSymlink, $Path));
14884 push(@RecurSymlink, $Path);
14885 if(-l $Path and my $Redirect=read_symlink($Path))
14886 {
14887 if(is_abs($Redirect))
14888 { # absolute path
14889 if($SystemRoot and $SystemRoot ne "/"
14890 and $Path=~/\A\Q$SystemRoot\E\//
14891 and (-f $SystemRoot.$Redirect or -l $SystemRoot.$Redirect))
14892 { # symbolic links from the sysroot
14893 # should be corrected to point to
14894 # the files inside sysroot
14895 $Redirect = $SystemRoot.$Redirect;
14896 }
14897 my $Res = resolve_symlink($Redirect);
14898 pop(@RecurSymlink);
14899 return ($Cache{"resolve_symlink"}{$Path} = $Res);
14900 }
14901 elsif($Redirect=~/\.\.[\/\\]/)
14902 { # relative path
14903 $Redirect = joinPath(get_dirname($Path),$Redirect);
14904 while($Redirect=~s&(/|\\)[^\/\\]+(\/|\\)\.\.(\/|\\)&$1&){};
14905 my $Res = resolve_symlink($Redirect);
14906 pop(@RecurSymlink);
14907 return ($Cache{"resolve_symlink"}{$Path} = $Res);
14908 }
14909 elsif(-f get_dirname($Path)."/".$Redirect)
14910 { # file name in the same directory
14911 my $Res = resolve_symlink(joinPath(get_dirname($Path),$Redirect));
14912 pop(@RecurSymlink);
14913 return ($Cache{"resolve_symlink"}{$Path} = $Res);
14914 }
14915 else
14916 { # broken link
14917 pop(@RecurSymlink);
14918 return ($Cache{"resolve_symlink"}{$Path} = "");
14919 }
14920 }
14921 pop(@RecurSymlink);
14922 return ($Cache{"resolve_symlink"}{$Path} = $Path);
14923}
14924
14925sub find_lib_path($$)
14926{
14927 my ($LibVersion, $DyLib) = @_;
14928 return "" if(not $DyLib or not $LibVersion);
14929 return $DyLib if(is_abs($DyLib));
14930 if(defined $Cache{"find_lib_path"}{$LibVersion}{$DyLib}) {
14931 return $Cache{"find_lib_path"}{$LibVersion}{$DyLib};
14932 }
14933 if(my @Paths = sort keys(%{$InputObject_Paths{$LibVersion}{$DyLib}})) {
14934 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $Paths[0]);
14935 }
14936 elsif(my $DefaultPath = $DyLib_DefaultPath{$DyLib}) {
14937 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $DefaultPath);
14938 }
14939 else
14940 {
14941 foreach my $Dir (sort keys(%DefaultLibPaths), sort keys(%{$SystemPaths{"lib"}}))
14942 { # search in default linker paths and then in all system paths
14943 if(-f $Dir."/".$DyLib) {
14944 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = joinPath($Dir,$DyLib));
14945 }
14946 }
14947 detectSystemObjects() if(not keys(%SystemObjects));
14948 if(my @AllObjects = keys(%{$SystemObjects{$DyLib}})) {
14949 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $AllObjects[0]);
14950 }
14951 my $ShortName = parse_libname($DyLib, "name+ext", $OStarget);
14952 if($ShortName ne $DyLib
14953 and my $Path = find_lib_path($ShortName))
14954 { # FIXME: check this case
14955 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $Path);
14956 }
14957 return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = "");
14958 }
14959}
14960
14961sub readSymbols_Lib($$$$$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014962{
14963 my ($LibVersion, $Lib_Path, $IsNeededLib, $GroupNames, $Weak) = @_;
14964 return if(not $Lib_Path or not -f $Lib_Path);
14965 my ($Lib_Dir, $Lib_Name) = separate_path(resolve_symlink($Lib_Path));
14966 return if($CheckedDyLib{$LibVersion}{$Lib_Name} and $IsNeededLib);
14967 return if(isCyclical(\@RecurLib, $Lib_Name) or $#RecurLib>=1);
14968 $CheckedDyLib{$LibVersion}{$Lib_Name} = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014969 if($CheckImpl and not $IsNeededLib) {
14970 getImplementations($LibVersion, $Lib_Path);
14971 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014972 push(@RecurLib, $Lib_Name);
14973 my (%Value_Interface, %Interface_Value, %NeededLib) = ();
14974 if(not $IsNeededLib)
14975 { # libstdc++ and libc are always used by other libs
14976 # if you test one of these libs then you not need
14977 # to find them in the system for reusing
14978 if(parse_libname($Lib_Name, "short", $OStarget) eq "libstdc++")
14979 { # libstdc++.so.6
14980 $STDCXX_TESTING = 1;
14981 }
14982 if(parse_libname($Lib_Name, "short", $OStarget) eq "libc")
14983 { # libc-2.11.3.so
14984 $GLIBC_TESTING = 1;
14985 }
14986 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014987 my $DebugPath = "";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014988 if($Debug)
14989 { # debug mode
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040014990 $DebugPath = $DEBUG_PATH{$LibVersion}."/libs/".get_filename($Lib_Path).".txt";
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014991 mkpath(get_dirname($DebugPath));
14992 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040014993 if($OStarget eq "macos")
14994 { # Mac OS X: *.dylib, *.a
14995 my $OtoolCmd = get_CmdPath("otool");
14996 if(not $OtoolCmd) {
14997 exitStatus("Not_Found", "can't find \"otool\"");
14998 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040014999 $OtoolCmd .= " -TV \"".$Lib_Path."\" 2>$TMP_DIR/null";
15000 if($Debug)
15001 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015002 # write to file
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015003 system($OtoolCmd." >".$DebugPath);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015004 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015005 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015006 else
15007 { # write to pipe
15008 open(LIB, $OtoolCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015009 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015010 while(<LIB>)
15011 {
15012 if(/[^_]+\s+_([\w\$]+)\s*\Z/)
15013 {
15014 my $realname = $1;
15015 if($IsNeededLib and $GroupNames
15016 and not $GroupNames->{parse_libname($Lib_Name, "name+ext", $OStarget)}) {
15017 $DepSymbols{$LibVersion}{$realname} = 1;
15018 }
15019 if(not $IsNeededLib)
15020 {
15021 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
15022 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
15023 if($COMMON_LANGUAGE{$LibVersion} ne "C++"
15024 and $realname=~/\A(_Z|\?)/) {
15025 setLanguage($LibVersion, "C++");
15026 }
15027 if($CheckObjectsOnly
15028 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015029 $CheckedSymbols{"Binary"}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015030 }
15031 }
15032 }
15033 }
15034 close(LIB);
15035 if($LIB_TYPE eq "dynamic")
15036 { # dependencies
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015037 open(LIB, "$OtoolCmd -L \"".$Lib_Path."\" 2>$TMP_DIR/null |");
15038 while(<LIB>)
15039 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015040 if(/\s*([\/\\].+\.$LIB_EXT)\s*/
15041 and $1 ne $Lib_Path) {
15042 $NeededLib{$1} = 1;
15043 }
15044 }
15045 close(LIB);
15046 }
15047 }
15048 elsif($OStarget eq "windows")
15049 { # Windows *.dll, *.lib
15050 my $DumpBinCmd = get_CmdPath("dumpbin");
15051 if(not $DumpBinCmd) {
15052 exitStatus("Not_Found", "can't find \"dumpbin\"");
15053 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015054 $DumpBinCmd .= " /EXPORTS \"".$Lib_Path."\" 2>$TMP_DIR/null";
15055 if($Debug)
15056 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015057 # write to file
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015058 system($DumpBinCmd." >".$DebugPath);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015059 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015060 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015061 else
15062 { # write to pipe
15063 open(LIB, $DumpBinCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015064 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015065 while(<LIB>)
15066 { # 1197 4AC 0000A620 SetThreadStackGuarantee
15067 # 1198 4AD SetThreadToken (forwarded to ...)
15068 # 3368 _o2i_ECPublicKey
15069 if(/\A\s*\d+\s+[a-f\d]+\s+[a-f\d]+\s+([\w\?\@]+)\s*\Z/i
15070 or /\A\s*\d+\s+[a-f\d]+\s+([\w\?\@]+)\s*\(\s*forwarded\s+/
15071 or /\A\s*\d+\s+_([\w\?\@]+)\s*\Z/)
15072 { # dynamic, static and forwarded symbols
15073 my $realname = $1;
15074 if($IsNeededLib and not $GroupNames->{parse_libname($Lib_Name, "name+ext", $OStarget)}) {
15075 $DepSymbols{$LibVersion}{$realname} = 1;
15076 }
15077 if(not $IsNeededLib)
15078 {
15079 $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
15080 $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
15081 if($COMMON_LANGUAGE{$LibVersion} ne "C++"
15082 and $realname=~/\A(_Z|\?)/) {
15083 setLanguage($LibVersion, "C++");
15084 }
15085 if($CheckObjectsOnly
15086 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015087 $CheckedSymbols{"Binary"}{$realname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015088 }
15089 }
15090 }
15091 }
15092 close(LIB);
15093 if($LIB_TYPE eq "dynamic")
15094 { # dependencies
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015095 open(LIB, "$DumpBinCmd /DEPENDENTS \"".$Lib_Path."\" 2>$TMP_DIR/null |");
15096 while(<LIB>)
15097 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015098 if(/\s*([^\s]+?\.$LIB_EXT)\s*/i
15099 and $1 ne $Lib_Path) {
15100 $NeededLib{path_format($1, $OSgroup)} = 1;
15101 }
15102 }
15103 close(LIB);
15104 }
15105 }
15106 else
15107 { # Unix; *.so, *.a
15108 # Symbian: *.dso, *.lib
15109 my $ReadelfCmd = get_CmdPath("readelf");
15110 if(not $ReadelfCmd) {
15111 exitStatus("Not_Found", "can't find \"readelf\"");
15112 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015113 $ReadelfCmd .= " -WhlSsdA \"".$Lib_Path."\" 2>$TMP_DIR/null";
15114 if($Debug)
15115 { # debug mode
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015116 # write to file
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015117 system($ReadelfCmd." >".$DebugPath);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015118 open(LIB, $DebugPath);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015119 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015120 else
15121 { # write to pipe
15122 open(LIB, $ReadelfCmd." |");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015123 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015124 my $symtab=0; # indicates that we are processing 'symtab' section of 'readelf' output
15125 while(<LIB>)
15126 {
15127 if($LIB_TYPE eq "dynamic")
15128 { # dynamic library specifics
15129 if(/NEEDED.+\[([^\[\]]+)\]/)
15130 { # dependencies:
15131 # 0x00000001 (NEEDED) Shared library: [libc.so.6]
15132 $NeededLib{$1} = 1;
15133 next;
15134 }
15135 if(/'\.dynsym'/)
15136 { # dynamic table
15137 $symtab=0;
15138 next;
15139 }
15140 if($symtab == 1)
15141 { # do nothing with symtab
15142 next;
15143 }
15144 if(/'\.symtab'/)
15145 { # symbol table
15146 $symtab=1;
15147 next;
15148 }
15149 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015150 if(my ($fullname, $idx, $Ndx, $type, $size, $bind) = readline_ELF($_))
15151 { # read ELF entry
15152 if( $Ndx eq "UND" )
15153 { # ignore interfaces that are imported from somewhere else
15154 next;
15155 }
15156 if($bind eq "WEAK"
15157 and $Weak eq "-Weak")
15158 { # skip WEAK symbols
15159 next;
15160 }
15161 my ($realname, $version_spec, $version) = separate_symbol($fullname);
15162 if($type eq "OBJECT")
15163 { # global data
15164 $CompleteSignature{$LibVersion}{$fullname}{"Object"} = 1;
15165 $CompleteSignature{$LibVersion}{$realname}{"Object"} = 1;
15166 }
15167 if($IsNeededLib and not $GroupNames->{parse_libname($Lib_Name, "name+ext", $OStarget)}) {
15168 $DepSymbols{$LibVersion}{$fullname} = 1;
15169 }
15170 if(not $IsNeededLib)
15171 {
15172 $Symbol_Library{$LibVersion}{$fullname} = $Lib_Name;
15173 $Library_Symbol{$LibVersion}{$Lib_Name}{$fullname} = ($type eq "OBJECT")?-$size:1;
15174 if($LIB_EXT eq "so")
15175 { # value
15176 $Interface_Value{$LibVersion}{$fullname} = $idx;
15177 $Value_Interface{$LibVersion}{$idx}{$fullname} = 1;
15178 }
15179 if($COMMON_LANGUAGE{$LibVersion} ne "C++"
15180 and $realname=~/\A(_Z|\?)/) {
15181 setLanguage($LibVersion, "C++");
15182 }
15183 if($CheckObjectsOnly
15184 and $LibVersion==1) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015185 $CheckedSymbols{"Binary"}{$fullname} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015186 }
15187 }
15188 }
15189 }
15190 close(LIB);
15191 }
15192 if(not $IsNeededLib and $LIB_EXT eq "so")
15193 { # get symbol versions
15194 foreach my $Symbol (keys(%{$Symbol_Library{$LibVersion}}))
15195 {
15196 next if($Symbol!~/\@/);
15197 my $Interface_SymName = "";
15198 foreach my $Symbol_SameValue (keys(%{$Value_Interface{$LibVersion}{$Interface_Value{$LibVersion}{$Symbol}}}))
15199 {
15200 if($Symbol_SameValue ne $Symbol
15201 and $Symbol_SameValue!~/\@/)
15202 {
15203 $SymVer{$LibVersion}{$Symbol_SameValue} = $Symbol;
15204 $Interface_SymName = $Symbol_SameValue;
15205 last;
15206 }
15207 }
15208 if(not $Interface_SymName)
15209 {
15210 if($Symbol=~/\A([^\@\$\?]*)[\@\$]+([^\@\$]*)\Z/
15211 and not $SymVer{$LibVersion}{$1}) {
15212 $SymVer{$LibVersion}{$1} = $Symbol;
15213 }
15214 }
15215 }
15216 }
15217 foreach my $DyLib (sort keys(%NeededLib))
15218 {
15219 my $DepPath = find_lib_path($LibVersion, $DyLib);
15220 if($DepPath and -f $DepPath) {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015221 readSymbols_Lib($LibVersion, $DepPath, 1, $GroupNames, "+Weak");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015222 }
15223 }
15224 pop(@RecurLib);
15225 return $Library_Symbol{$LibVersion};
15226}
15227
15228sub get_path_prefixes($)
15229{
15230 my $Path = $_[0];
15231 my ($Dir, $Name) = separate_path($Path);
15232 my %Prefixes = ();
15233 foreach my $Prefix (reverse(split(/[\/\\]+/, $Dir)))
15234 {
15235 $Prefixes{$Name} = 1;
15236 $Name = joinPath($Prefix, $Name);
15237 last if(keys(%Prefixes)>5 or $Prefix eq "include");
15238 }
15239 return keys(%Prefixes);
15240}
15241
15242sub detectSystemHeaders()
15243{
15244 my @SysHeaders = ();
15245 foreach my $DevelPath (keys(%{$SystemPaths{"include"}}))
15246 {
15247 next if(not -d $DevelPath);
15248 # search for all header files in the /usr/include
15249 # with or without extension (ncurses.h, QtCore, ...)
15250 @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f","",""));
15251 foreach my $Link (cmd_find($DevelPath,"l","",""))
15252 { # add symbolic links
15253 if(-f $Link) {
15254 push(@SysHeaders, $Link);
15255 }
15256 }
15257 }
15258 foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
15259 {
15260 next if(not -d $DevelPath);
15261 # search for config headers in the /usr/lib
15262 @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f","*.h",""));
15263 foreach my $Dir (cmd_find($DevelPath,"d","include",""))
15264 { # search for all include directories
15265 # this is for headers that are installed to /usr/lib
15266 # Example: Qt4 headers in Mandriva (/usr/lib/qt4/include/)
15267 if($Dir=~/\/(gcc|jvm|syslinux|kdb)\//) {
15268 next;
15269 }
15270 @SysHeaders = (@SysHeaders, cmd_find($Dir,"f","",""));
15271 }
15272 }
15273 foreach my $Path (@SysHeaders)
15274 {
15275 foreach my $Part (get_path_prefixes($Path)) {
15276 $SystemHeaders{$Part}{$Path}=1;
15277 }
15278 }
15279}
15280
15281sub detectSystemObjects()
15282{
15283 foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
15284 {
15285 next if(not -d $DevelPath);
15286 foreach my $Path (find_libs($DevelPath,"",""))
15287 { # search for shared libraries in the /usr/lib (including symbolic links)
15288 $SystemObjects{parse_libname(get_filename($Path), "name+ext", $OStarget)}{$Path}=1;
15289 }
15290 }
15291}
15292
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015293sub getSoPaths($)
15294{
15295 my $LibVersion = $_[0];
15296 my @SoPaths = ();
15297 foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Libs"}))
15298 {
15299 if(not -e $Dest) {
15300 exitStatus("Access_Error", "can't access \'$Dest\'");
15301 }
15302 my @SoPaths_Dest = getSOPaths_Dest($Dest, $LibVersion);
15303 foreach (@SoPaths_Dest) {
15304 push(@SoPaths, $_);
15305 }
15306 }
15307 return @SoPaths;
15308}
15309
15310sub skip_lib($$)
15311{
15312 my ($Path, $LibVersion) = @_;
15313 return 1 if(not $Path or not $LibVersion);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015314 my $Name = get_filename($Path);
15315 if($SkipLibs{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015316 return 1;
15317 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015318 my $ShortName = parse_libname($Name, "name+ext", $OStarget);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015319 if($SkipLibs{$LibVersion}{"Name"}{$ShortName}) {
15320 return 1;
15321 }
15322 foreach my $Dir (keys(%{$SkipLibs{$LibVersion}{"Path"}}))
15323 {
15324 if($Path=~/\Q$Dir\E([\/\\]|\Z)/) {
15325 return 1;
15326 }
15327 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015328 foreach my $P (keys(%{$SkipLibs{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015329 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015330 if($Name=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015331 return 1;
15332 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015333 if($P=~/[\/\\]/ and $Path=~/$P/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015334 return 1;
15335 }
15336 }
15337 return 0;
15338}
15339
15340sub skip_header($$)
15341{ # returns:
15342 # 1 - if header should NOT be included and checked
15343 # 2 - if header should NOT be included, but should be checked
15344 my ($Path, $LibVersion) = @_;
15345 return 1 if(not $Path or not $LibVersion);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015346 my $Name = get_filename($Path);
15347 if(my $Kind = $SkipHeaders{$LibVersion}{"Name"}{$Name}) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015348 return $Kind;
15349 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015350 foreach my $D (keys(%{$SkipHeaders{$LibVersion}{"Path"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015351 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015352 if($Path=~/\Q$D\E([\/\\]|\Z)/) {
15353 return $SkipHeaders{$LibVersion}{"Path"}{$D};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015354 }
15355 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015356 foreach my $P (keys(%{$SkipHeaders{$LibVersion}{"Pattern"}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015357 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015358 if($Name=~/$P/) {
15359 return $SkipHeaders{$LibVersion}{"Pattern"}{$P};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015360 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015361 if($P=~/[\/\\]/ and $Path=~/$P/) {
15362 return $SkipHeaders{$LibVersion}{"Pattern"}{$P};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015363 }
15364 }
15365 return 0;
15366}
15367
15368sub register_objects($$)
15369{
15370 my ($Dir, $LibVersion) = @_;
15371 if($SystemPaths{"lib"}{$Dir})
15372 { # system directory
15373 return;
15374 }
15375 if($RegisteredObjDirs{$LibVersion}{$Dir})
15376 { # already registered
15377 return;
15378 }
15379 foreach my $Path (find_libs($Dir,"",1))
15380 {
15381 next if(ignore_path($Path));
15382 next if(skip_lib($Path, $LibVersion));
15383 $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
15384 }
15385 $RegisteredObjDirs{$LibVersion}{$Dir} = 1;
15386}
15387
15388sub getSOPaths_Dest($$)
15389{
15390 my ($Dest, $LibVersion) = @_;
15391 if(skip_lib($Dest, $LibVersion)) {
15392 return ();
15393 }
15394 if(-f $Dest)
15395 {
15396 if(not parse_libname($Dest, "name", $OStarget)) {
15397 exitStatus("Error", "incorrect format of library (should be *.$LIB_EXT): \'$Dest\'");
15398 }
15399 $InputObject_Paths{$LibVersion}{get_filename($Dest)}{$Dest} = 1;
15400 register_objects(get_dirname($Dest), $LibVersion);
15401 return ($Dest);
15402 }
15403 elsif(-d $Dest)
15404 {
15405 $Dest=~s/[\/\\]+\Z//g;
15406 my @AllObjects = ();
15407 if($SystemPaths{"lib"}{$Dest})
15408 { # you have specified /usr/lib as the search directory (<libs>) in the XML descriptor
15409 # and the real name of the library by -l option (bz2, stdc++, Xaw, ...)
15410 foreach my $Path (cmd_find($Dest,"","*".esc($TargetLibraryName)."*\.$LIB_EXT*",2))
15411 { # all files and symlinks that match the name of a library
15412 if(get_filename($Path)=~/\A(|lib)\Q$TargetLibraryName\E[\d\-]*\.$LIB_EXT[\d\.]*\Z/i)
15413 {
15414 $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
15415 push(@AllObjects, resolve_symlink($Path));
15416 }
15417 }
15418 }
15419 else
15420 { # search for all files and symlinks
15421 foreach my $Path (find_libs($Dest,"",""))
15422 {
15423 next if(ignore_path($Path));
15424 next if(skip_lib($Path, $LibVersion));
15425 $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
15426 push(@AllObjects, resolve_symlink($Path));
15427 }
15428 if($OSgroup eq "macos")
15429 { # shared libraries on MacOS X may have no extension
15430 foreach my $Path (cmd_find($Dest,"f","",""))
15431 {
15432 next if(ignore_path($Path));
15433 next if(skip_lib($Path, $LibVersion));
15434 if(get_filename($Path)!~/\./
15435 and cmd_file($Path)=~/(shared|dynamic)\s+library/i) {
15436 $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
15437 push(@AllObjects, resolve_symlink($Path));
15438 }
15439 }
15440 }
15441 }
15442 return @AllObjects;
15443 }
15444 else {
15445 return ();
15446 }
15447}
15448
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015449sub isCyclical($$)
15450{
15451 my ($Stack, $Value) = @_;
15452 return (grep {$_ eq $Value} @{$Stack});
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015453}
15454
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015455sub generateTemplate()
15456{
15457 writeFile("VERSION.xml", $DescriptorTemplate."\n");
15458 printMsg("INFO", "XML-descriptor template ./VERSION.xml has been generated");
15459}
15460
15461sub detectWordSize()
15462{
15463 return "" if(not $GCC_PATH);
15464 if($Cache{"detectWordSize"}) {
15465 return $Cache{"detectWordSize"};
15466 }
15467 writeFile("$TMP_DIR/empty.h", "");
15468 my $Defines = `$GCC_PATH -E -dD $TMP_DIR/empty.h`;
15469 unlink("$TMP_DIR/empty.h");
15470 my $WSize = 0;
15471 if($Defines=~/ __SIZEOF_POINTER__\s+(\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015472 { # GCC 4
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015473 $WSize = $1;
15474 }
15475 elsif($Defines=~/ __PTRDIFF_TYPE__\s+(\w+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015476 { # GCC 3
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015477 my $PTRDIFF = $1;
15478 if($PTRDIFF=~/long/) {
15479 $WSize = 8;
15480 }
15481 else {
15482 $WSize = 4;
15483 }
15484 }
15485 if(not int($WSize)) {
15486 exitStatus("Error", "can't check WORD size");
15487 }
15488 return ($Cache{"detectWordSize"} = $WSize);
15489}
15490
15491sub majorVersion($)
15492{
15493 my $V = $_[0];
15494 return 0 if(not $V);
15495 my @VParts = split(/\./, $V);
15496 return $VParts[0];
15497}
15498
15499sub cmpVersions($$)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015500{ # compare two versions in dotted-numeric format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015501 my ($V1, $V2) = @_;
15502 return 0 if($V1 eq $V2);
15503 return undef if($V1!~/\A\d+[\.\d+]*\Z/);
15504 return undef if($V2!~/\A\d+[\.\d+]*\Z/);
15505 my @V1Parts = split(/\./, $V1);
15506 my @V2Parts = split(/\./, $V2);
15507 for (my $i = 0; $i <= $#V1Parts && $i <= $#V2Parts; $i++) {
15508 return -1 if(int($V1Parts[$i]) < int($V2Parts[$i]));
15509 return 1 if(int($V1Parts[$i]) > int($V2Parts[$i]));
15510 }
15511 return -1 if($#V1Parts < $#V2Parts);
15512 return 1 if($#V1Parts > $#V2Parts);
15513 return 0;
15514}
15515
15516sub read_ABI_Dump($$)
15517{
15518 my ($LibVersion, $Path) = @_;
15519 return if(not $LibVersion or not -e $Path);
15520 my $FilePath = "";
15521 if($Path=~/\.abi\Z/)
15522 { # input *.abi
15523 $FilePath = $Path;
15524 }
15525 else
15526 { # input *.abi.tar.gz
15527 $FilePath = unpackDump($Path);
15528 }
15529 if($FilePath!~/\.abi\Z/) {
15530 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
15531 }
15532 my $Content = readFile($FilePath);
15533 if($Path!~/\.abi\Z/)
15534 { # remove temp file
15535 unlink($FilePath);
15536 }
15537 if($Content!~/};\s*\Z/) {
15538 exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
15539 }
15540 my $LibraryABI = eval($Content);
15541 if(not $LibraryABI) {
15542 exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again");
15543 }
15544 # new dumps (>=1.22) have a personal versioning
15545 my $DumpVersion = $LibraryABI->{"ABI_DUMP_VERSION"};
15546 my $ToolVersion = $LibraryABI->{"ABI_COMPLIANCE_CHECKER_VERSION"};
15547 if(not $DumpVersion)
15548 { # old dumps (<=1.21.6) have been marked by the tool version
15549 $DumpVersion = $ToolVersion;
15550 }
15551 $UsedDump{$LibVersion}{"V"} = $DumpVersion;
15552 if(majorVersion($DumpVersion) ne majorVersion($ABI_DUMP_VERSION))
15553 { # should be compatible with dumps of the same major version
15554 if(cmpVersions($DumpVersion, $ABI_DUMP_VERSION)>0)
15555 { # Don't know how to parse future dump formats
15556 exitStatus("Dump_Version", "incompatible version $DumpVersion of specified ABI dump (newer than $ABI_DUMP_VERSION)");
15557 }
15558 elsif(cmpVersions($DumpVersion, $TOOL_VERSION)>0 and not $LibraryABI->{"ABI_DUMP_VERSION"})
15559 { # Don't know how to parse future dump formats
15560 exitStatus("Dump_Version", "incompatible version $DumpVersion of specified ABI dump (newer than $TOOL_VERSION)");
15561 }
15562 if($UseOldDumps)
15563 {
15564 if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)<0) {
15565 exitStatus("Dump_Version", "incompatible version $DumpVersion of specified ABI dump (older than $OLDEST_SUPPORTED_VERSION)");
15566 }
15567 }
15568 else
15569 {
15570 my $Msg = "incompatible version $DumpVersion of specified ABI dump (allowed only ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION)";
15571 if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)>=0) {
15572 $Msg .= "\nUse -old-dumps option to use old-version dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0)";
15573 }
15574 exitStatus("Dump_Version", $Msg);
15575 }
15576 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015577 if($LibraryABI->{"SrcBin"})
15578 { # default
15579 $UsedDump{$LibVersion}{"SrcBin"} = 1;
15580 }
15581 elsif($LibraryABI->{"BinOnly"})
15582 { # ABI dump created with --binary option
15583 $UsedDump{$LibVersion}{"BinOnly"} = 1;
15584 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015585 if(defined $LibraryABI->{"Mode"}
15586 and $LibraryABI->{"Mode"} eq "Extended")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015587 { # --ext option
15588 $ExtendedCheck = 1;
15589 }
15590 if(my $Lang = $LibraryABI->{"Language"})
15591 {
15592 $UsedDump{$LibVersion}{"L"} = $Lang;
15593 setLanguage($LibVersion, $Lang);
15594 }
15595 $TypeInfo{$LibVersion} = $LibraryABI->{"TypeInfo"};
15596 if(not $TypeInfo{$LibVersion})
15597 { # support for old ABI dumps
15598 $TypeInfo{$LibVersion} = $LibraryABI->{"TypeDescr"};
15599 }
15600 read_Machine_DumpInfo($LibraryABI, $LibVersion);
15601 $SymbolInfo{$LibVersion} = $LibraryABI->{"SymbolInfo"};
15602 if(not $SymbolInfo{$LibVersion})
15603 { # support for old dumps
15604 $SymbolInfo{$LibVersion} = $LibraryABI->{"FuncDescr"};
15605 }
15606 if(not keys(%{$SymbolInfo{$LibVersion}}))
15607 { # validation of old-version dumps
15608 if(not $ExtendedCheck) {
15609 exitStatus("Invalid_Dump", "the input dump d$LibVersion is invalid");
15610 }
15611 }
15612 $Library_Symbol{$LibVersion} = $LibraryABI->{"Symbols"};
15613 if(not $Library_Symbol{$LibVersion})
15614 { # support for old dumps
15615 $Library_Symbol{$LibVersion} = $LibraryABI->{"Interfaces"};
15616 }
15617 $DepSymbols{$LibVersion} = $LibraryABI->{"DepSymbols"};
15618 if(not $DepSymbols{$LibVersion})
15619 { # support for old dumps
15620 $DepSymbols{$LibVersion} = $LibraryABI->{"DepInterfaces"};
15621 }
15622 if(not $DepSymbols{$LibVersion})
15623 { # support for old dumps
15624 # Cannot reconstruct DepSymbols. This may result in false
15625 # positives if the old dump is for library 2. Not a problem if
15626 # old dumps are only from old libraries.
15627 $DepSymbols{$LibVersion} = {};
15628 }
15629 $SymVer{$LibVersion} = $LibraryABI->{"SymbolVersion"};
15630 $Tid_TDid{$LibVersion} = $LibraryABI->{"Tid_TDid"};
15631 $Descriptor{$LibVersion}{"Version"} = $LibraryABI->{"LibraryVersion"};
15632 $SkipTypes{$LibVersion} = $LibraryABI->{"SkipTypes"};
15633 if(not $SkipTypes{$LibVersion})
15634 { # support for old dumps
15635 $SkipTypes{$LibVersion} = $LibraryABI->{"OpaqueTypes"};
15636 }
15637 $SkipSymbols{$LibVersion} = $LibraryABI->{"SkipSymbols"};
15638 if(not $SkipSymbols{$LibVersion})
15639 { # support for old dumps
15640 $SkipSymbols{$LibVersion} = $LibraryABI->{"SkipInterfaces"};
15641 }
15642 if(not $SkipSymbols{$LibVersion})
15643 { # support for old dumps
15644 $SkipSymbols{$LibVersion} = $LibraryABI->{"InternalInterfaces"};
15645 }
15646 $SkipNameSpaces{$LibVersion} = $LibraryABI->{"SkipNameSpaces"};
15647 $TargetHeaders{$LibVersion} = $LibraryABI->{"TargetHeaders"};
15648 foreach my $Path (keys(%{$LibraryABI->{"SkipHeaders"}}))
15649 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015650 $SkipHeadersList{$LibVersion}{$Path} = $LibraryABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015651 my ($CPath, $Type) = classifyPath($Path);
15652 $SkipHeaders{$LibVersion}{$Type}{$CPath} = $LibraryABI->{"SkipHeaders"}{$Path};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015653 }
15654 read_Headers_DumpInfo($LibraryABI, $LibVersion);
15655 read_Libs_DumpInfo($LibraryABI, $LibVersion);
15656 if(not $Descriptor{$LibVersion}{"Libs"})
15657 { # support for old ABI dumps
15658 if(cmpVersions($DumpVersion, "2.10.1")<0)
15659 {
15660 if(not $TargetHeaders{$LibVersion})
15661 {
15662 foreach (keys(%{$Registered_Headers{$LibVersion}})) {
15663 $TargetHeaders{$LibVersion}{get_filename($_)}=1;
15664 }
15665 }
15666 }
15667 }
15668 $Constants{$LibVersion} = $LibraryABI->{"Constants"};
15669 $NestedNameSpaces{$LibVersion} = $LibraryABI->{"NameSpaces"};
15670 if(not $NestedNameSpaces{$LibVersion})
15671 { # support for old dumps
15672 # Cannot reconstruct NameSpaces. This may affect design
15673 # of the compatibility report.
15674 $NestedNameSpaces{$LibVersion} = {};
15675 }
15676 # target system type
15677 # needed to adopt HTML report
15678 if(not $DumpSystem)
15679 { # to use in createSymbolsList(...)
15680 $OStarget = $LibraryABI->{"Target"};
15681 }
15682 # recreate environment
15683 foreach my $Lib_Name (keys(%{$Library_Symbol{$LibVersion}}))
15684 {
15685 foreach my $Interface (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}}))
15686 {
15687 $Symbol_Library{$LibVersion}{$Interface} = $Lib_Name;
15688 if($Library_Symbol{$LibVersion}{$Lib_Name}{$Interface}<=-1)
15689 { # data marked as -size in the dump
15690 $CompleteSignature{$LibVersion}{$Interface}{"Object"} = 1;
15691 }
15692 if($COMMON_LANGUAGE{$LibVersion} ne "C++"
15693 and $Interface=~/\A(_Z|\?)/) {
15694 setLanguage($LibVersion, "C++");
15695 }
15696 }
15697 }
15698 my @VFunc = ();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015699 foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015700 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015701 my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015702 if(not $MnglName)
15703 { # C-functions
15704 next;
15705 }
15706 if(not $Symbol_Library{$LibVersion}{$MnglName}
15707 and not $DepSymbols{$LibVersion}{$MnglName}) {
15708 push(@VFunc, $MnglName);
15709 }
15710 }
15711 translateSymbols(@VFunc, $LibVersion);
15712 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
15713 translateSymbols(keys(%{$DepSymbols{$LibVersion}}), $LibVersion);
15714
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015715 foreach my $TypeDeclId (sort keys(%{$TypeInfo{$LibVersion}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015716 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015717 foreach my $TypeId (sort keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}}))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015718 {
15719 if(defined $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"BaseClass"})
15720 { # support for old ABI dumps < 2.0 (ACC 1.22)
15721 foreach my $BId (keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"BaseClass"}}))
15722 {
15723 if(my $Access = $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"BaseClass"}{$BId})
15724 {
15725 if($Access ne "public") {
15726 $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Base"}{$BId}{"access"} = $Access;
15727 }
15728 }
15729 $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Base"}{$BId} = {};
15730 }
15731 delete($TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"BaseClass"});
15732 }
15733 my %TInfo = %{$TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}};
15734 if(defined $TInfo{"Base"})
15735 {
15736 foreach (keys(%{$TInfo{"Base"}})) {
15737 $Class_SubClasses{$LibVersion}{$_}{$TypeId}=1;
15738 }
15739 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015740 if($TInfo{"Type"} eq "Typedef" and defined $TInfo{"BaseType"})
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015741 {
Andrey Ponomarenko16934472012-03-29 15:37:04 +040015742 if(my ($BTDid, $BTid) = ($TInfo{"BaseType"}{"TDid"}, $TInfo{"BaseType"}{"Tid"}))
15743 {
15744 $BTDid = "" if(not defined $BTDid);
15745 $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}} = $TypeInfo{$LibVersion}{$BTDid}{$BTid}{"Name"};
15746 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015747 }
15748 if(not $TName_Tid{$LibVersion}{$TInfo{"Name"}})
15749 { # classes: class (id1), typedef (artificial, id2 > id1)
15750 $TName_Tid{$LibVersion}{$TInfo{"Name"}} = $TypeId;
15751 }
15752 }
15753 }
15754
15755 $Descriptor{$LibVersion}{"Dump"} = 1;
15756}
15757
15758sub read_Machine_DumpInfo($$)
15759{
15760 my ($LibraryABI, $LibVersion) = @_;
15761 if($LibraryABI->{"Arch"}) {
15762 $CPU_ARCH{$LibVersion} = $LibraryABI->{"Arch"};
15763 }
15764 if($LibraryABI->{"WordSize"}) {
15765 $WORD_SIZE{$LibVersion} = $LibraryABI->{"WordSize"};
15766 }
15767 else
15768 { # support for old dumps
15769 $WORD_SIZE{$LibVersion} = $LibraryABI->{"SizeOfPointer"};
15770 }
15771 if(not $WORD_SIZE{$LibVersion})
15772 { # support for old dumps (<1.23)
15773 if(my $Tid = getTypeIdByName("char*", $LibVersion))
15774 { # size of char*
15775 $WORD_SIZE{$LibVersion} = get_TypeSize($Tid, $LibVersion);
15776 }
15777 else
15778 {
15779 my $PSize = 0;
15780 foreach my $TDid (keys(%{$TypeInfo{$LibVersion}}))
15781 {
15782 foreach my $Tid (keys(%{$TypeInfo{$LibVersion}{$TDid}}))
15783 {
15784 if(get_TypeAttr($Tid, $LibVersion, "Type") eq "Pointer")
15785 { # any "pointer"-type
15786 $PSize = get_TypeSize($Tid, $LibVersion);
15787 last;
15788 }
15789 }
15790 if($PSize) {
15791 last;
15792 }
15793 }
15794 if($PSize)
15795 { # a pointer type size
15796 $WORD_SIZE{$LibVersion} = $PSize;
15797 }
15798 else {
15799 printMsg("WARNING", "cannot identify a WORD size in the ABI dump (too old format)");
15800 }
15801 }
15802 }
15803 if($LibraryABI->{"GccVersion"}) {
15804 $GCC_VERSION{$LibVersion} = $LibraryABI->{"GccVersion"};
15805 }
15806}
15807
15808sub read_Libs_DumpInfo($$)
15809{
15810 my ($LibraryABI, $LibVersion) = @_;
15811 if(keys(%{$Library_Symbol{$LibVersion}})
15812 and not $DumpAPI) {
15813 $Descriptor{$LibVersion}{"Libs"} = "OK";
15814 }
15815}
15816
15817sub read_Headers_DumpInfo($$)
15818{
15819 my ($LibraryABI, $LibVersion) = @_;
15820 if(keys(%{$LibraryABI->{"Headers"}})
15821 and not $DumpAPI) {
15822 $Descriptor{$LibVersion}{"Headers"} = "OK";
15823 }
15824 foreach my $Identity (keys(%{$LibraryABI->{"Headers"}}))
15825 { # headers info is stored in the old dumps in the different way
15826 if($UseOldDumps
15827 and my $Name = $LibraryABI->{"Headers"}{$Identity}{"Name"})
15828 { # support for old dumps: headers info corrected in 1.22
15829 $Identity = $Name;
15830 }
15831 $Registered_Headers{$LibVersion}{$Identity}{"Identity"} = $Identity;
15832 }
15833}
15834
15835sub find_libs($$$)
15836{
15837 my ($Path, $Type, $MaxDepth) = @_;
15838 # FIXME: correct the search pattern
15839 return cmd_find($Path, $Type, ".*\\.$LIB_EXT\[0-9.]*", $MaxDepth);
15840}
15841
15842sub createDescriptor($$)
15843{
15844 my ($LibVersion, $Path) = @_;
15845 if(not $LibVersion or not $Path
15846 or not -e $Path) {
15847 return "";
15848 }
15849 if(-d $Path)
15850 { # directory with headers files and shared objects
15851 return "
15852 <version>
15853 ".$TargetVersion{$LibVersion}."
15854 </version>
15855
15856 <headers>
15857 $Path
15858 </headers>
15859
15860 <libs>
15861 $Path
15862 </libs>";
15863 }
15864 else
15865 { # files
15866 if($Path=~/\.xml\Z/i)
15867 { # standard XML-descriptor
15868 return readFile($Path);
15869 }
15870 elsif(is_header($Path, 2, $LibVersion))
15871 { # header file
15872 return "
15873 <version>
15874 ".$TargetVersion{$LibVersion}."
15875 </version>
15876
15877 <headers>
15878 $Path
15879 </headers>
15880
15881 <libs>
15882 none
15883 </libs>";
15884 }
15885 elsif(parse_libname($Path, "name", $OStarget))
15886 { # shared object
15887 return "
15888 <version>
15889 ".$TargetVersion{$LibVersion}."
15890 </version>
15891
15892 <headers>
15893 none
15894 </headers>
15895
15896 <libs>
15897 $Path
15898 </libs>";
15899 }
15900 else
15901 { # standard XML-descriptor
15902 return readFile($Path);
15903 }
15904 }
15905}
15906
15907sub detect_lib_default_paths()
15908{
15909 my %LPaths = ();
15910 if($OSgroup eq "bsd")
15911 {
15912 if(my $LdConfig = get_CmdPath("ldconfig")) {
15913 foreach my $Line (split(/\n/, `$LdConfig -r 2>$TMP_DIR/null`)) {
15914 if($Line=~/\A[ \t]*\d+:\-l(.+) \=\> (.+)\Z/) {
15915 $LPaths{"lib".$1} = $2;
15916 }
15917 }
15918 }
15919 else {
15920 printMsg("WARNING", "can't find ldconfig");
15921 }
15922 }
15923 else
15924 {
15925 if(my $LdConfig = get_CmdPath("ldconfig"))
15926 {
15927 if($SystemRoot and $OSgroup eq "linux")
15928 { # use host (x86) ldconfig with the target (arm) ld.so.conf
15929 if(-e $SystemRoot."/etc/ld.so.conf") {
15930 $LdConfig .= " -f ".$SystemRoot."/etc/ld.so.conf";
15931 }
15932 }
15933 foreach my $Line (split(/\n/, `$LdConfig -p 2>$TMP_DIR/null`)) {
15934 if($Line=~/\A[ \t]*([^ \t]+) .* \=\> (.+)\Z/)
15935 {
15936 my ($Name, $Path) = ($1, $2);
15937 $Path=~s/[\/]{2,}/\//;
15938 $LPaths{$Name} = $Path;
15939 }
15940 }
15941 }
15942 elsif($OSgroup=~/linux/i) {
15943 printMsg("WARNING", "can't find ldconfig");
15944 }
15945 }
15946 return \%LPaths;
15947}
15948
15949sub detect_bin_default_paths()
15950{
15951 my $EnvPaths = $ENV{"PATH"};
15952 if($OSgroup eq "beos") {
15953 $EnvPaths.=":".$ENV{"BETOOLS"};
15954 }
15955 my $Sep = ($OSgroup eq "windows")?";":":|;";
15956 foreach my $Path (sort {length($a)<=>length($b)} split(/$Sep/, $EnvPaths))
15957 {
15958 $Path = path_format($Path, $OSgroup);
15959 $Path=~s/[\/\\]+\Z//g;
15960 next if(not $Path);
15961 if($SystemRoot
15962 and $Path=~/\A\Q$SystemRoot\E\//)
15963 { # do NOT use binaries from target system
15964 next;
15965 }
15966 $DefaultBinPaths{$Path} = 1;
15967 }
15968}
15969
15970sub detect_inc_default_paths()
15971{
15972 return () if(not $GCC_PATH);
15973 my %DPaths = ("Cpp"=>{},"Gcc"=>{},"Inc"=>{});
15974 writeFile("$TMP_DIR/empty.h", "");
15975 foreach my $Line (split(/\n/, `$GCC_PATH -v -x c++ -E "$TMP_DIR/empty.h" 2>&1`))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040015976 { # detecting GCC default include paths
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040015977 if($Line=~/\A[ \t]*((\/|\w+:\\).+)[ \t]*\Z/)
15978 {
15979 my $Path = simplify_path($1);
15980 $Path=~s/[\/\\]+\Z//g;
15981 $Path = path_format($Path, $OSgroup);
15982 if($Path=~/c\+\+|\/g\+\+\//)
15983 {
15984 $DPaths{"Cpp"}{$Path}=1;
15985 if(not defined $MAIN_CPP_DIR
15986 or get_depth($MAIN_CPP_DIR)>get_depth($Path)) {
15987 $MAIN_CPP_DIR = $Path;
15988 }
15989 }
15990 elsif($Path=~/gcc/) {
15991 $DPaths{"Gcc"}{$Path}=1;
15992 }
15993 else
15994 {
15995 next if($Path=~/local[\/\\]+include/);
15996 if($SystemRoot
15997 and $Path!~/\A\Q$SystemRoot\E(\/|\Z)/)
15998 { # The GCC include path for user headers is not a part of the system root
15999 # The reason: you are not specified the --cross-gcc option or selected a wrong compiler
16000 # or it is the internal cross-GCC path like arm-linux-gnueabi/include
16001 next;
16002 }
16003 $DPaths{"Inc"}{$Path}=1;
16004 }
16005 }
16006 }
16007 unlink("$TMP_DIR/empty.h");
16008 return %DPaths;
16009}
16010
16011sub detect_default_paths($)
16012{
16013 my ($HSearch, $LSearch, $BSearch, $GSearch) = (1, 1, 1, 1);
16014 my $Search = $_[0];
16015 if($Search!~/inc/) {
16016 $HSearch = 0;
16017 }
16018 if($Search!~/lib/) {
16019 $LSearch = 0;
16020 }
16021 if($Search!~/bin/) {
16022 $BSearch = 0;
16023 }
16024 if($Search!~/gcc/) {
16025 $GSearch = 0;
16026 }
16027 if(keys(%{$SystemPaths{"include"}}))
16028 { # <search_headers> section of the XML descriptor
16029 # do NOT search for systems headers
16030 $HSearch = 0;
16031 }
16032 if(keys(%{$SystemPaths{"lib"}}))
16033 { # <search_headers> section of the XML descriptor
16034 # do NOT search for systems headers
16035 $LSearch = 0;
16036 }
16037 foreach my $Type (keys(%{$OS_AddPath{$OSgroup}}))
16038 { # additional search paths
16039 next if($Type eq "include" and not $HSearch);
16040 next if($Type eq "lib" and not $LSearch);
16041 next if($Type eq "bin" and not $BSearch);
16042 foreach my $Path (keys(%{$OS_AddPath{$OSgroup}{$Type}}))
16043 {
16044 next if(not -d $Path);
16045 $SystemPaths{$Type}{$Path} = $OS_AddPath{$OSgroup}{$Type}{$Path};
16046 }
16047 }
16048 if($OSgroup ne "windows")
16049 { # unix-like
16050 foreach my $Type ("include", "lib", "bin")
16051 { # automatic detection of system "devel" directories
16052 next if($Type eq "include" and not $HSearch);
16053 next if($Type eq "lib" and not $LSearch);
16054 next if($Type eq "bin" and not $BSearch);
16055 my ($UsrDir, $RootDir) = ("/usr", "/");
16056 if($SystemRoot and $Type ne "bin")
16057 { # 1. search for target headers and libraries
16058 # 2. use host commands: ldconfig, readelf, etc.
16059 ($UsrDir, $RootDir) = ("$SystemRoot/usr", $SystemRoot);
16060 }
16061 foreach my $Path (cmd_find($RootDir,"d","*$Type*",1)) {
16062 $SystemPaths{$Type}{$Path} = 1;
16063 }
16064 if(-d $RootDir."/".$Type)
16065 { # if "/lib" is symbolic link
16066 if($RootDir eq "/") {
16067 $SystemPaths{$Type}{"/".$Type} = 1;
16068 }
16069 else {
16070 $SystemPaths{$Type}{$RootDir."/".$Type} = 1;
16071 }
16072 }
16073 if(-d $UsrDir) {
16074 foreach my $Path (cmd_find($UsrDir,"d","*$Type*",1)) {
16075 $SystemPaths{$Type}{$Path} = 1;
16076 }
16077 if(-d $UsrDir."/".$Type)
16078 { # if "/usr/lib" is symbolic link
16079 $SystemPaths{$Type}{$UsrDir."/".$Type} = 1;
16080 }
16081 }
16082 }
16083 }
16084 if($BSearch)
16085 {
16086 detect_bin_default_paths();
16087 foreach my $Path (keys(%DefaultBinPaths)) {
16088 $SystemPaths{"bin"}{$Path} = $DefaultBinPaths{$Path};
16089 }
16090 }
16091 # check environment variables
16092 if($OSgroup eq "beos")
16093 {
16094 foreach (keys(%{$SystemPaths{"bin"}}))
16095 {
16096 if($_ eq ".") {
16097 next;
16098 }
16099 foreach my $Path (cmd_find($_, "d", "bin", ""))
16100 { # search for /boot/develop/abi/x86/gcc4/tools/gcc-4.4.4-haiku-101111/bin/
16101 $SystemPaths{"bin"}{$Path} = 1;
16102 }
16103 }
16104 if($HSearch)
16105 {
16106 foreach my $Path (split(/:|;/, $ENV{"BEINCLUDES"}))
16107 {
16108 if(is_abs($Path)) {
16109 $DefaultIncPaths{$Path} = 1;
16110 }
16111 }
16112 }
16113 if($LSearch)
16114 {
16115 foreach my $Path (split(/:|;/, $ENV{"BELIBRARIES"}), split(/:|;/, $ENV{"LIBRARY_PATH"}))
16116 {
16117 if(is_abs($Path)) {
16118 $DefaultLibPaths{$Path} = 1;
16119 }
16120 }
16121 }
16122 }
16123 if($LSearch)
16124 { # using linker to get system paths
16125 if(my $LPaths = detect_lib_default_paths())
16126 { # unix-like
16127 foreach my $Name (keys(%{$LPaths}))
16128 {
16129 if($SystemRoot
16130 and $LPaths->{$Name}!~/\A\Q$SystemRoot\E\//)
16131 { # wrong ldconfig configuration
16132 # check your <sysroot>/etc/ld.so.conf
16133 next;
16134 }
16135 $DyLib_DefaultPath{$Name} = $LPaths->{$Name};
16136 $DefaultLibPaths{get_dirname($LPaths->{$Name})} = 1;
16137 }
16138 }
16139 foreach my $Path (keys(%DefaultLibPaths)) {
16140 $SystemPaths{"lib"}{$Path} = $DefaultLibPaths{$Path};
16141 }
16142 }
16143 if($BSearch)
16144 {
16145 if($CrossGcc)
16146 { # --cross-gcc=arm-linux-gcc
16147 if(-e $CrossGcc)
16148 { # absolute or relative path
16149 $GCC_PATH = get_abs_path($CrossGcc);
16150 }
16151 elsif($CrossGcc!~/\// and get_CmdPath($CrossGcc))
16152 { # command name
16153 $GCC_PATH = $CrossGcc;
16154 }
16155 else {
16156 exitStatus("Access_Error", "can't access \'$CrossGcc\'");
16157 }
16158 if($GCC_PATH=~/\s/) {
16159 $GCC_PATH = "\"".$GCC_PATH."\"";
16160 }
16161 }
16162 }
16163 if($GSearch)
16164 { # GCC path and default include dirs
16165 if(not $CrossGcc) {
16166 $GCC_PATH = get_CmdPath("gcc");
16167 }
16168 if(not $GCC_PATH) {
16169 exitStatus("Not_Found", "can't find GCC>=3.0 in PATH");
16170 }
16171 if(not $CheckObjectsOnly_Opt)
16172 {
16173 if(my $GCC_Ver = get_dumpversion($GCC_PATH))
16174 {
16175 my $GccTarget = get_dumpmachine($GCC_PATH);
16176 printMsg("INFO", "Using GCC $GCC_Ver ($GccTarget)");
16177 if($GccTarget=~/symbian/)
16178 {
16179 $OStarget = "symbian";
16180 $LIB_EXT = $OS_LibExt{$LIB_TYPE}{$OStarget};
16181 }
16182 }
16183 else {
16184 exitStatus("Error", "something is going wrong with the GCC compiler");
16185 }
16186 }
16187 if(not $NoStdInc)
16188 { # do NOT search in GCC standard paths
16189 my %DPaths = detect_inc_default_paths();
16190 %DefaultCppPaths = %{$DPaths{"Cpp"}};
16191 %DefaultGccPaths = %{$DPaths{"Gcc"}};
16192 %DefaultIncPaths = %{$DPaths{"Inc"}};
16193 foreach my $Path (keys(%DefaultIncPaths)) {
16194 $SystemPaths{"include"}{$Path} = $DefaultIncPaths{$Path};
16195 }
16196 }
16197 }
16198 if($HSearch)
16199 { # user include paths
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016200 my $IncPath = "/usr/include";
16201 if($SystemRoot) {
16202 $IncPath = $SystemRoot.$IncPath;
16203 }
16204 if(-d $IncPath) {
16205 $UserIncPath{$IncPath}=1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016206 }
16207 }
16208}
16209
16210sub getLIB_EXT($)
16211{
16212 my $Target = $_[0];
16213 if(my $Ext = $OS_LibExt{$LIB_TYPE}{$Target}) {
16214 return $Ext;
16215 }
16216 return $OS_LibExt{$LIB_TYPE}{"default"};
16217}
16218
16219sub getAR_EXT($)
16220{
16221 my $Target = $_[0];
16222 if(my $Ext = $OS_Archive{$Target}) {
16223 return $Ext;
16224 }
16225 return $OS_Archive{"default"};
16226}
16227
16228sub get_dumpversion($)
16229{
16230 my $Cmd = $_[0];
16231 return "" if(not $Cmd);
16232 if($Cache{"get_dumpversion"}{$Cmd}) {
16233 return $Cache{"get_dumpversion"}{$Cmd};
16234 }
16235 my $V = `$Cmd -dumpversion 2>$TMP_DIR/null`;
16236 chomp($V);
16237 return ($Cache{"get_dumpversion"}{$Cmd} = $V);
16238}
16239
16240sub get_dumpmachine($)
16241{
16242 my $Cmd = $_[0];
16243 return "" if(not $Cmd);
16244 if($Cache{"get_dumpmachine"}{$Cmd}) {
16245 return $Cache{"get_dumpmachine"}{$Cmd};
16246 }
16247 my $Machine = `$Cmd -dumpmachine 2>$TMP_DIR/null`;
16248 chomp($Machine);
16249 return ($Cache{"get_dumpmachine"}{$Cmd} = $Machine);
16250}
16251
16252sub check_command($)
16253{
16254 my $Cmd = $_[0];
16255 return "" if(not $Cmd);
16256 my @Options = (
16257 "--version",
16258 "-help"
16259 );
16260 foreach my $Opt (@Options)
16261 {
16262 my $Info = `$Cmd $Opt 2>$TMP_DIR/null`;
16263 if($Info) {
16264 return 1;
16265 }
16266 }
16267 return 0;
16268}
16269
16270sub check_gcc_version($$)
16271{
16272 my ($Cmd, $Req_V) = @_;
16273 return 0 if(not $Cmd or not $Req_V);
16274 my $Gcc_V = get_dumpversion($Cmd);
16275 $Gcc_V=~s/(-|_)[a-z_]+.*\Z//; # remove suffix (like "-haiku-100818")
16276 if(cmpVersions($Gcc_V, $Req_V)>=0) {
16277 return $Cmd;
16278 }
16279 return "";
16280}
16281
16282sub get_depth($)
16283{
16284 if(defined $Cache{"get_depth"}{$_[0]}) {
16285 return $Cache{"get_depth"}{$_[0]}
16286 }
16287 return ($Cache{"get_depth"}{$_[0]} = ($_[0]=~tr![\/\\]|\:\:!!));
16288}
16289
16290sub find_gcc_cxx_headers($)
16291{
16292 my $LibVersion = $_[0];
16293 return if($Cache{"find_gcc_cxx_headers"});# this function should be called once
16294 # detecting system header paths
16295 foreach my $Path (sort {get_depth($b) <=> get_depth($a)} keys(%DefaultGccPaths))
16296 {
16297 foreach my $HeaderPath (sort {get_depth($a) <=> get_depth($b)} cmd_find($Path,"f","",""))
16298 {
16299 my $FileName = get_filename($HeaderPath);
16300 next if($DefaultGccHeader{$FileName});
16301 $DefaultGccHeader{$FileName} = $HeaderPath;
16302 }
16303 }
16304 if($COMMON_LANGUAGE{$LibVersion} eq "C++" and not $STDCXX_TESTING)
16305 {
16306 foreach my $CppDir (sort {get_depth($b)<=>get_depth($a)} keys(%DefaultCppPaths))
16307 {
16308 my @AllCppHeaders = cmd_find($CppDir,"f","","");
16309 foreach my $Path (sort {get_depth($a)<=>get_depth($b)} @AllCppHeaders)
16310 {
16311 my $FileName = get_filename($Path);
16312 next if($DefaultCppHeader{$FileName});
16313 $DefaultCppHeader{$FileName} = $Path;
16314 }
16315 }
16316 }
16317 $Cache{"find_gcc_cxx_headers"} = 1;
16318}
16319
16320sub parse_libname($$$)
16321{
16322 my ($Name, $Type, $Target) = @_;
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040016323 if(not $Name) {
16324 return "";
16325 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016326 if($Target eq "symbian") {
16327 return parse_libname_symbian($Name, $Type);
16328 }
16329 elsif($Target eq "windows") {
16330 return parse_libname_windows($Name, $Type);
16331 }
16332 my $Ext = getLIB_EXT($Target);
16333 if($Name=~/((((lib|).+?)([\-\_][\d\-\.\_]+|))\.$Ext)(\.(.+)|)\Z/)
16334 { # libSDL-1.2.so.0.7.1
16335 # libwbxml2.so.0.0.18
16336 if($Type eq "name")
16337 { # libSDL-1.2
16338 # libwbxml2
16339 return $2;
16340 }
16341 elsif($Type eq "name+ext")
16342 { # libSDL-1.2.so
16343 # libwbxml2.so
16344 return $1;
16345 }
16346 elsif($Type eq "version")
16347 {
16348 if($7 ne "")
16349 { # 0.7.1
16350 return $7;
16351 }
16352 else
16353 { # libc-2.5.so (=>2.5 version)
16354 my $MV = $5;
16355 $MV=~s/\A[\-\_]+//g;
16356 return $MV;
16357 }
16358 }
16359 elsif($Type eq "short")
16360 { # libSDL
16361 # libwbxml2
16362 return $3;
16363 }
16364 elsif($Type eq "shortest")
16365 { # SDL
16366 # wbxml
16367 return shortest_name($3);
16368 }
16369 }
16370 return "";# error
16371}
16372
16373sub parse_libname_symbian($$)
16374{
16375 my ($Name, $Type) = @_;
16376 my $Ext = getLIB_EXT("symbian");
16377 if($Name=~/(((.+?)(\{.+\}|))\.$Ext)\Z/)
16378 { # libpthread{00010001}.dso
16379 if($Type eq "name")
16380 { # libpthread{00010001}
16381 return $2;
16382 }
16383 elsif($Type eq "name+ext")
16384 { # libpthread{00010001}.dso
16385 return $1;
16386 }
16387 elsif($Type eq "version")
16388 { # 00010001
16389 my $V = $4;
16390 $V=~s/\{(.+)\}/$1/;
16391 return $V;
16392 }
16393 elsif($Type eq "short")
16394 { # libpthread
16395 return $3;
16396 }
16397 elsif($Type eq "shortest")
16398 { # pthread
16399 return shortest_name($3);
16400 }
16401 }
16402 return "";# error
16403}
16404
16405sub parse_libname_windows($$)
16406{
16407 my ($Name, $Type) = @_;
16408 my $Ext = getLIB_EXT("windows");
16409 if($Name=~/((.+?)\.$Ext)\Z/)
16410 { # netapi32.dll
16411 if($Type eq "name")
16412 { # netapi32
16413 return $2;
16414 }
16415 elsif($Type eq "name+ext")
16416 { # netapi32.dll
16417 return $1;
16418 }
16419 elsif($Type eq "version")
16420 { # DLL version embedded
16421 # at binary-level
16422 return "";
16423 }
16424 elsif($Type eq "short")
16425 { # netapi32
16426 return $2;
16427 }
16428 elsif($Type eq "shortest")
16429 { # netapi
16430 return shortest_name($2);
16431 }
16432 }
16433 return "";# error
16434}
16435
16436sub shortest_name($)
16437{
16438 my $Name = $_[0];
16439 # remove prefix
16440 $Name=~s/\A(lib|open)//;
16441 # remove suffix
16442 $Name=~s/[\W\d_]+\Z//i;
16443 $Name=~s/([a-z]{2,})(lib)\Z/$1/i;
16444 return $Name;
16445}
16446
16447sub getPrefix($)
16448{
16449 my $Str = $_[0];
16450 if($Str=~/\A(Get|get|Set|set)([A-Z]|_)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016451 { # GetError
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016452 return "";
16453 }
16454 if($Str=~/\A([_]*[A-Z][a-z]{1,5})[A-Z]/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016455 { # XmuValidArea: Xmu
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016456 return $1;
16457 }
16458 elsif($Str=~/\A([_]*[a-z]+)[A-Z]/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016459 { # snfReadFont: snf
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016460 return $1;
16461 }
16462 elsif($Str=~/\A([_]*[A-Z]{2,})[A-Z][a-z]+([A-Z][a-z]+|\Z)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016463 { # XRRTimes: XRR
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016464 return $1;
16465 }
16466 elsif($Str=~/\A([_]*[a-z0-9]{2,}_)[a-z]+/i)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016467 { # alarm_event_add: alarm_
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016468 return $1;
16469 }
16470 elsif($Str=~/\A(([a-z])\2{1,})/i)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016471 { # ffopen
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016472 return $1;
16473 }
16474 else {
16475 return "";
16476 }
16477}
16478
16479sub problem_title($)
16480{
16481 if($_[0]==1) {
16482 return "1 problem";
16483 }
16484 else {
16485 return $_[0]." problems";
16486 }
16487}
16488
16489sub warning_title($)
16490{
16491 if($_[0]==1) {
16492 return "1 warning";
16493 }
16494 else {
16495 return $_[0]." warnings";
16496 }
16497}
16498
16499sub createSymbolsList($$$$$)
16500{
16501 my ($DPath, $SaveTo, $LName, $LVersion, $ArchName) = @_;
16502 read_ABI_Dump(1, $DPath);
16503 if(not $CheckObjectsOnly) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016504 prepareSymbols(1);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016505 }
16506 my %SymbolHeaderLib = ();
16507 my $Total = 0;
16508 # Get List
16509 foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
16510 {
16511 if(not link_symbol($Symbol, 1, "-Deps"))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016512 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016513 next;
16514 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016515 if(not symbolFilter($Symbol, 1, "Public", "Binary"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016516 { # skip other symbols
16517 next;
16518 }
16519 my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
16520 if(not $HeaderName)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016521 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016522 next;
16523 }
16524 my $DyLib = $Symbol_Library{1}{$Symbol};
16525 if(not $DyLib)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016526 { # skip src only and all external functions
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016527 next;
16528 }
16529 $SymbolHeaderLib{$HeaderName}{$DyLib}{$Symbol} = 1;
16530 $Total+=1;
16531 }
16532 # Draw List
16533 my $SYMBOLS_LIST = "<h1>Public symbols in <span style='color:Blue;'>$LName</span> (<span style='color:Red;'>$LVersion</span>)";
16534 $SYMBOLS_LIST .= " on <span style='color:Blue;'>".showArch($ArchName)."</span><br/>Total: $Total</h1><br/>";
16535 foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%SymbolHeaderLib))
16536 {
16537 foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$SymbolHeaderLib{$HeaderName}}))
16538 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016539 my %NS_Symbol = ();
16540 foreach my $Symbol (keys(%{$SymbolHeaderLib{$HeaderName}{$DyLib}})) {
16541 $NS_Symbol{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
16542 }
16543 foreach my $NameSpace (sort keys(%NS_Symbol))
16544 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016545 $SYMBOLS_LIST .= getTitle($HeaderName, $DyLib, $NameSpace);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016546 my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NS_Symbol{$NameSpace}});
16547 foreach my $Symbol (@SortedInterfaces)
16548 {
16549 my $SubReport = "";
16550 my $Signature = get_Signature($Symbol, 1);
16551 if($NameSpace) {
16552 $Signature=~s/(\W|\A)\Q$NameSpace\E\:\:(\w)/$1$2/g;
16553 }
16554 if($Symbol=~/\A(_Z|\?)/)
16555 {
16556 if($Signature) {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016557 $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 +040016558 }# report_added
16559 else {
16560 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
16561 }
16562 }
16563 else
16564 {
16565 if($Signature) {
16566 $SubReport = "<span class='iname'>".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
16567 }
16568 else {
16569 $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
16570 }
16571 }
16572 $SYMBOLS_LIST .= $SubReport;
16573 }
16574 }
16575 $SYMBOLS_LIST .= "<br/>\n";
16576 }
16577 }
16578 # Clear Info
16579 (%TypeInfo, %SymbolInfo, %Library_Symbol,
16580 %DepSymbols, %SymVer, %Tid_TDid, %SkipTypes,
16581 %SkipSymbols, %NestedNameSpaces, %ClassMethods,
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016582 %AllocableClass, %ClassNames, %CompleteSignature,
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016583 %SkipNameSpaces, %Symbol_Library) = ();
16584 ($Content_Counter, $ContentID) = (0, 0);
16585 # Print Report
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016586 my $CssStyles = readModule("Styles", "SymbolsList.css");
16587 my $JScripts = readModule("Scripts", "Sections.js");
16588 $SYMBOLS_LIST = "<a name='Top'></a>".$SYMBOLS_LIST.$TOP_REF."<br/>\n";
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016589 my $Title = "$LName: public symbols";
16590 my $Keywords = "$LName, API, symbols";
16591 my $Description = "List of symbols in $LName ($LVersion) on ".showArch($ArchName);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016592 $SYMBOLS_LIST = composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016593 <body><div>\n$SYMBOLS_LIST</div>
16594 <br/><br/><hr/>\n".getReportFooter($LName)."
16595 <div style='height:999px;'></div></body></html>";
16596 writeFile($SaveTo, $SYMBOLS_LIST);
16597}
16598
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016599sub readModule($$)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016600{
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016601 my ($Module, $Name) = @_;
16602 my $Path = $MODULES_DIR."/Internals/$Module/".$Name;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016603 if(not -f $Path) {
16604 exitStatus("Module_Error", "can't access \'$Path\'");
16605 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016606 return readFile($Path);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016607}
16608
16609sub is_target_lib($)
16610{
16611 my $LName = $_[0];
16612 if($TargetLibraryName
16613 and $LName!~/\Q$TargetLibraryName\E/) {
16614 return 0;
16615 }
16616 if(keys(%TargetLibs)
16617 and not $TargetLibs{$LName}
16618 and not $TargetLibs{parse_libname($LName, "name+ext", $OStarget)}) {
16619 return 0;
16620 }
16621 return 1;
16622}
16623
16624sub is_target_header($)
16625{ # --header, --headers-list
16626 if(keys(%{$TargetHeaders{1}})
16627 or keys(%{$TargetHeaders{2}}))
16628 {
16629 if(not $TargetHeaders{1}{$_[0]}
16630 and not $TargetHeaders{2}{$_[0]})
16631 {
16632 return 0;
16633 }
16634 }
16635 return 1;
16636}
16637
16638sub checkVersionNum($$)
16639{
16640 my ($LibVersion, $Path) = @_;
16641 if(my $VerNum = $TargetVersion{$LibVersion}) {
16642 return $VerNum;
16643 }
16644 my $UsedAltDescr = 0;
16645 foreach my $Part (split(/\s*,\s*/, $Path))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016646 { # try to get version string from file path
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016647 next if($Part=~/\.xml\Z/i);
16648 next if(isDump($Part));
16649 if(parse_libname($Part, "version", $OStarget)
16650 or is_header($Part, 2, $LibVersion) or -d $Part)
16651 {
16652 $UsedAltDescr = 1;
16653 if(my $VerNum = readStringVersion($Part))
16654 {
16655 $TargetVersion{$LibVersion} = $VerNum;
16656 if($DumpAPI) {
16657 printMsg("WARNING", "setting version number to $VerNum (use -vnum <num> option to change it)");
16658 }
16659 else {
16660 printMsg("WARNING", "setting ".($LibVersion==1?"1st":"2nd")." version number to \"$VerNum\" (use -v$LibVersion <num> option to change it)");
16661 }
16662 return $TargetVersion{$LibVersion};
16663 }
16664 }
16665 }
16666 if($UsedAltDescr)
16667 {
16668 if($DumpAPI) {
16669 exitStatus("Error", "version number is not set (use -vnum <num> option)");
16670 }
16671 else {
16672 exitStatus("Error", ($LibVersion==1?"1st":"2nd")." version number is not set (use -v$LibVersion <num> option)");
16673 }
16674 }
16675}
16676
16677sub readStringVersion($)
16678{
16679 my $Str = $_[0];
16680 return "" if(not $Str);
16681 $Str=~s/\Q$TargetLibraryName\E//g;
16682 if($Str=~/(\/|\\|\w|\A)[\-\_]*(\d+[\d\.\-]+\d+|\d+)/)
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016683 { # .../libssh-0.4.0/...
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016684 return $2;
16685 }
16686 elsif(my $V = parse_libname($Str, "version", $OStarget)) {
16687 return $V;
16688 }
16689 return "";
16690}
16691
16692sub readLibs($)
16693{
16694 my $LibVersion = $_[0];
16695 if($OStarget eq "windows")
16696 { # dumpbin.exe will crash
16697 # without VS Environment
16698 check_win32_env();
16699 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040016700 readSymbols($LibVersion);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016701 translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
16702 translateSymbols(keys(%{$DepSymbols{$LibVersion}}), $LibVersion);
16703}
16704
16705sub dump_sorting($)
16706{
16707 my $hash = $_[0];
16708 return [] if(not $hash or not keys(%{$hash}));
16709 if((keys(%{$hash}))[0]=~/\A\d+\Z/) {
16710 return [sort {int($a) <=> int($b)} keys(%{$hash})];
16711 }
16712 else {
16713 return [sort {$a cmp $b} keys(%{$hash})];
16714 }
16715}
16716
16717sub printMsg($$)
16718{
16719 my ($Type, $Msg) = @_;
16720 if($Type!~/\AINFO/) {
16721 $Msg = $Type.": ".$Msg;
16722 }
16723 if($Type!~/_C\Z/) {
16724 $Msg .= "\n";
16725 }
16726 if($Quiet)
16727 { # --quiet option
16728 appendFile($COMMON_LOG_PATH, $Msg);
16729 }
16730 else
16731 {
16732 if($Type eq "ERROR") {
16733 print STDERR $Msg;
16734 }
16735 else {
16736 print $Msg;
16737 }
16738 }
16739}
16740
16741sub exitStatus($$)
16742{
16743 my ($Code, $Msg) = @_;
16744 printMsg("ERROR", $Msg);
16745 exit($ERROR_CODE{$Code});
16746}
16747
16748sub exitReport()
16749{ # the tool has run without any errors
16750 printReport();
16751 if($COMPILE_ERRORS)
16752 { # errors in headers may add false positives/negatives
16753 exit($ERROR_CODE{"Compile_Error"});
16754 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016755 if($BinaryOnly and $RESULT{"Binary"}{"Problems"})
16756 { # --binary
16757 exit($ERROR_CODE{"Incompatible"});
16758 }
16759 elsif($SourceOnly and $RESULT{"Source"}{"Problems"})
16760 { # --source
16761 exit($ERROR_CODE{"Incompatible"});
16762 }
16763 elsif($RESULT{"Source"}{"Problems"}
16764 or $RESULT{"Binary"}{"Problems"})
16765 { # default
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016766 exit($ERROR_CODE{"Incompatible"});
16767 }
16768 else {
16769 exit($ERROR_CODE{"Compatible"});
16770 }
16771}
16772
16773sub readRules($)
16774{
16775 my $Kind = $_[0];
16776 if(not -f $RULES_PATH{$Kind}) {
16777 exitStatus("Module_Error", "can't access \'".$RULES_PATH{$Kind}."\'");
16778 }
16779 my $Content = readFile($RULES_PATH{$Kind});
16780 while(my $Rule = parseTag(\$Content, "rule"))
16781 {
16782 my $RId = parseTag(\$Rule, "id");
16783 my @Properties = ("Severity", "Change", "Effect", "Overcome", "Kind");
16784 foreach my $Prop (@Properties) {
16785 if(my $Value = parseTag(\$Rule, lc($Prop)))
16786 {
16787 $Value=~s/\n[ ]*//;
16788 $CompatRules{$Kind}{$RId}{$Prop} = $Value;
16789 }
16790 }
16791 if($CompatRules{$Kind}{$RId}{"Kind"}=~/\A(Symbols|Parameters)\Z/) {
16792 $CompatRules{$Kind}{$RId}{"Kind"} = "Symbols";
16793 }
16794 else {
16795 $CompatRules{$Kind}{$RId}{"Kind"} = "Types";
16796 }
16797 }
16798}
16799
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016800sub getReportPath($)
16801{
16802 my $Level = $_[0];
16803 my $Dir = "compat_reports/$TargetLibraryName/".$Descriptor{1}{"Version"}."_to_".$Descriptor{2}{"Version"};
16804 if($Level eq "Binary")
16805 {
16806 if($BinaryReportPath)
16807 { # --bin-report-path
16808 return $BinaryReportPath;
16809 }
16810 elsif($OutputReportPath)
16811 { # --report-path
16812 return $OutputReportPath;
16813 }
16814 else
16815 { # default
16816 return $Dir."/abi_compat_report.$ReportFormat";
16817 }
16818 }
16819 elsif($Level eq "Source")
16820 {
16821 if($SourceReportPath)
16822 { # --src-report-path
16823 return $SourceReportPath;
16824 }
16825 elsif($OutputReportPath)
16826 { # --report-path
16827 return $OutputReportPath;
16828 }
16829 else
16830 { # default
16831 return $Dir."/src_compat_report.$ReportFormat";
16832 }
16833 }
16834 else
16835 {
16836 if($OutputReportPath)
16837 { # --report-path
16838 return $OutputReportPath;
16839 }
16840 else
16841 { # default
16842 return $Dir."/compat_report.$ReportFormat";
16843 }
16844 }
16845}
16846
16847sub printStatMsg($)
16848{
16849 my $Level = $_[0];
16850 printMsg("INFO", "total \"$Level\" compatibility problems: ".$RESULT{$Level}{"Problems"}.", warnings: ".$RESULT{$Level}{"Warnings"});
16851}
16852
16853sub listAffected($)
16854{
16855 my $Level = $_[0];
16856 my $List = "";
16857 foreach (keys(%{$TotalAffected{$Level}}))
16858 {
16859 if($StrictCompat and $TotalAffected{$Level}{$_} eq "Low")
16860 { # skip "Low"-severity problems
16861 next;
16862 }
16863 $List .= "$_\n";
16864 }
16865 my $Dir = get_dirname(getReportPath($Level));
16866 if($Level eq "Binary") {
16867 writeFile($Dir."/abi_affected.txt", $List);
16868 }
16869 elsif($Level eq "Source") {
16870 writeFile($Dir."/src_affected.txt", $List);
16871 }
16872}
16873
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016874sub printReport()
16875{
16876 printMsg("INFO", "creating compatibility report ...");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016877 createReport();
16878 if($JoinReport or $DoubleReport)
16879 {
16880 if($RESULT{"Binary"}{"Problems"}
16881 or $RESULT{"Source"}{"Problems"}) {
16882 printMsg("INFO", "result: INCOMPATIBLE (Binary: ".$RESULT{"Binary"}{"Affected"}."\%, Source: ".$RESULT{"Source"}{"Affected"}."\%)");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016883 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016884 else {
16885 printMsg("INFO", "result: COMPATIBLE");
16886 }
16887 printStatMsg("Binary");
16888 printStatMsg("Source");
16889 if($ListAffected)
16890 { # --list-affected
16891 listAffected("Binary");
16892 listAffected("Source");
16893 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016894 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016895 elsif($BinaryOnly)
16896 {
16897 if($RESULT{"Binary"}{"Problems"}) {
16898 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Binary"}{"Affected"}."\%)");
16899 }
16900 else {
16901 printMsg("INFO", "result: COMPATIBLE");
16902 }
16903 printStatMsg("Binary");
16904 if($ListAffected)
16905 { # --list-affected
16906 listAffected("Binary");
16907 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016908 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016909 elsif($SourceOnly)
16910 {
16911 if($RESULT{"Source"}{"Problems"}) {
16912 printMsg("INFO", "result: INCOMPATIBLE (".$RESULT{"Source"}{"Affected"}."\%)");
16913 }
16914 else {
16915 printMsg("INFO", "result: COMPATIBLE");
16916 }
16917 printStatMsg("Source");
16918 if($ListAffected)
16919 { # --list-affected
16920 listAffected("Source");
16921 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016922 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016923 if($StdOut)
16924 {
16925 if($JoinReport or not $DoubleReport)
16926 { # --join-report, --binary or --source
16927 printMsg("INFO", "compatibility report has been generated to stdout");
16928 }
16929 else
16930 { # default
16931 printMsg("INFO", "compatibility reports have been generated to stdout");
16932 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016933 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040016934 else
16935 {
16936 if($JoinReport)
16937 { # --join-report
16938 printMsg("INFO", "see detailed report:\n ".getReportPath("Join"));
16939 }
16940 elsif($DoubleReport)
16941 { # default
16942 printMsg("INFO", "see detailed reports:\n ".getReportPath("Binary")."\n ".getReportPath("Source"));
16943 }
16944 elsif($BinaryOnly)
16945 { # --binary
16946 printMsg("INFO", "see detailed report:\n ".getReportPath("Binary"));
16947 }
16948 elsif($SourceOnly)
16949 { # --source
16950 printMsg("INFO", "see detailed report:\n ".getReportPath("Source"));
16951 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040016952 }
16953}
16954
16955sub check_win32_env()
16956{
16957 if(not $ENV{"DevEnvDir"}
16958 or not $ENV{"LIB"}) {
16959 exitStatus("Error", "can't start without VS environment (vsvars32.bat)");
16960 }
16961}
16962
16963sub create_ABI_Dump()
16964{
16965 if(not -e $DumpAPI) {
16966 exitStatus("Access_Error", "can't access \'$DumpAPI\'");
16967 }
16968 # check the archive utilities
16969 if($OSgroup eq "windows")
16970 { # using zip
16971 my $ZipCmd = get_CmdPath("zip");
16972 if(not $ZipCmd) {
16973 exitStatus("Not_Found", "can't find \"zip\"");
16974 }
16975 }
16976 else
16977 { # using tar and gzip
16978 my $TarCmd = get_CmdPath("tar");
16979 if(not $TarCmd) {
16980 exitStatus("Not_Found", "can't find \"tar\"");
16981 }
16982 my $GzipCmd = get_CmdPath("gzip");
16983 if(not $GzipCmd) {
16984 exitStatus("Not_Found", "can't find \"gzip\"");
16985 }
16986 }
16987 my @DParts = split(/\s*,\s*/, $DumpAPI);
16988 foreach my $Part (@DParts)
16989 {
16990 if(not -e $Part) {
16991 exitStatus("Access_Error", "can't access \'$Part\'");
16992 }
16993 }
16994 checkVersionNum(1, $DumpAPI);
16995 foreach my $Part (@DParts)
16996 {
16997 if(isDump($Part)) {
16998 read_ABI_Dump(1, $Part);
16999 }
17000 else {
17001 readDescriptor(1, createDescriptor(1, $Part));
17002 }
17003 }
17004 initLogging(1);
17005 detect_default_paths("inc|lib|bin|gcc"); # complete analysis
17006 if(not $CheckHeadersOnly) {
17007 readLibs(1);
17008 }
17009 if($CheckHeadersOnly) {
17010 setLanguage(1, "C++");
17011 }
17012 if(not $CheckObjectsOnly) {
17013 searchForHeaders(1);
17014 }
17015 $WORD_SIZE{1} = detectWordSize();
17016 if($Descriptor{1}{"Headers"}
17017 and not $Descriptor{1}{"Dump"}) {
17018 readHeaders(1);
17019 }
17020 if($ExtendedCheck)
17021 { # --ext option
17022 addExtension(1);
17023 }
17024 formatDump(1);
17025 if(not keys(%{$SymbolInfo{1}}))
17026 { # check if created dump is valid
17027 if(not $ExtendedCheck and not $CheckObjectsOnly)
17028 {
17029 if($CheckHeadersOnly) {
17030 exitStatus("Empty_Set", "the set of public symbols is empty");
17031 }
17032 else {
17033 exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection");
17034 }
17035 }
17036 }
17037 my %HeadersInfo = ();
17038 foreach my $HPath (keys(%{$Registered_Headers{1}}))
17039 { # headers info stored without paths in the dump
17040 $HeadersInfo{$Registered_Headers{1}{$HPath}{"Identity"}} = $Registered_Headers{1}{$HPath}{"Pos"};
17041 }
17042 printMsg("INFO", "creating library ABI dump ...");
17043 my %LibraryABI = (
17044 "TypeInfo" => $TypeInfo{1},
17045 "SymbolInfo" => $SymbolInfo{1},
17046 "Symbols" => $Library_Symbol{1},
17047 "DepSymbols" => $DepSymbols{1},
17048 "SymbolVersion" => $SymVer{1},
17049 "LibraryVersion" => $Descriptor{1}{"Version"},
17050 "LibraryName" => $TargetLibraryName,
17051 "Language" => $COMMON_LANGUAGE{1},
17052 "Tid_TDid" => $Tid_TDid{1},
17053 "SkipTypes" => $SkipTypes{1},
17054 "SkipSymbols" => $SkipSymbols{1},
17055 "SkipNameSpaces" => $SkipNameSpaces{1},
17056 "SkipHeaders" => $SkipHeadersList{1},
17057 "TargetHeaders" => $TargetHeaders{1},
17058 "Headers" => \%HeadersInfo,
17059 "Constants" => $Constants{1},
17060 "NameSpaces" => $NestedNameSpaces{1},
17061 "Target" => $OStarget,
17062 "Arch" => getArch(1),
17063 "WordSize" => $WORD_SIZE{1},
17064 "GccVersion" => get_dumpversion($GCC_PATH),
17065 "ABI_DUMP_VERSION" => $ABI_DUMP_VERSION,
17066 "ABI_COMPLIANCE_CHECKER_VERSION" => $TOOL_VERSION
17067 );
17068 if($ExtendedCheck)
17069 { # --ext option
17070 $LibraryABI{"Mode"} = "Extended";
17071 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017072 if($BinaryOnly)
17073 { # --binary
17074 $LibraryABI{"BinOnly"} = 1;
17075 }
17076 else
17077 { # default
17078 $LibraryABI{"SrcBin"} = 1;
17079 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017080 if($StdOut)
17081 { # --stdout option
17082 print STDOUT Dumper(\%LibraryABI);
17083 printMsg("INFO", "ABI dump has been generated to stdout");
17084 return;
17085 }
17086 else
17087 { # write to gzipped file
17088 my $DumpPath = "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi.".$AR_EXT;
17089 if($OutputDumpPath)
17090 { # user defined path
17091 $DumpPath = $OutputDumpPath;
17092 }
17093 if(not $DumpPath=~s/\Q.$AR_EXT\E\Z//g) {
17094 exitStatus("Error", "the dump path (-dump-path option) should be the path to a *.$AR_EXT file");
17095 }
17096 my ($DDir, $DName) = separate_path($DumpPath);
17097 my $DPath = $TMP_DIR."/".$DName;
17098 mkpath($DDir);
17099 writeFile($DPath, Dumper(\%LibraryABI));
17100 if(not -s $DPath) {
17101 exitStatus("Error", "can't create ABI dump because something is going wrong with the Data::Dumper module");
17102 }
17103 my $Pkg = createArchive($DPath, $DDir);
17104 printMsg("INFO", "library ABI has been dumped to:\n $Pkg");
17105 printMsg("INFO", "you can transfer this dump everywhere and use instead of the ".$Descriptor{1}{"Version"}." version descriptor");
17106 }
17107}
17108
17109sub quickEmptyReports()
17110{ # Quick "empty" reports
17111 # 4 times faster than merging equal dumps
17112 # NOTE: the dump contains the "LibraryVersion" attribute
17113 # if you change the version, then your dump will be different
17114 # OVERCOME: use -v1 and v2 options for comparing dumps
17115 # and don't change version in the XML descriptor (and dumps)
17116 # OVERCOME 2: separate meta info from the dumps in ACC 2.0
17117 if(-s $Descriptor{1}{"Path"} == -s $Descriptor{2}{"Path"})
17118 {
17119 my $FilePath1 = unpackDump($Descriptor{1}{"Path"});
17120 my $FilePath2 = unpackDump($Descriptor{2}{"Path"});
17121 if($FilePath1 and $FilePath2)
17122 {
17123 my $Content = readFile($FilePath1);
17124 if($Content eq readFile($FilePath2))
17125 {
17126 # read a number of headers, libs, symbols and types
17127 my $ABIdump = eval($Content);
17128 if(not $ABIdump) {
17129 exitStatus("Error", "internal error");
17130 }
17131 if(not $ABIdump->{"TypeInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017132 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017133 $ABIdump->{"TypeInfo"} = $ABIdump->{"TypeDescr"};
17134 }
17135 if(not $ABIdump->{"SymbolInfo"})
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017136 { # support for old dumps
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017137 $ABIdump->{"SymbolInfo"} = $ABIdump->{"FuncDescr"};
17138 }
17139 read_Headers_DumpInfo($ABIdump, 1);
17140 read_Libs_DumpInfo($ABIdump, 1);
17141 read_Machine_DumpInfo($ABIdump, 1);
17142 read_Machine_DumpInfo($ABIdump, 2);
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017143
17144 %{$CheckedTypes{"Binary"}} = %{$ABIdump->{"TypeInfo"}};
17145 %{$CheckedTypes{"Source"}} = %{$ABIdump->{"TypeInfo"}};
17146
17147 %{$CheckedSymbols{"Binary"}} = %{$ABIdump->{"SymbolInfo"}};
17148 %{$CheckedSymbols{"Source"}} = %{$ABIdump->{"SymbolInfo"}};
17149
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017150 $Descriptor{1}{"Version"} = $TargetVersion{1}?$TargetVersion{1}:$ABIdump->{"LibraryVersion"};
17151 $Descriptor{2}{"Version"} = $TargetVersion{2}?$TargetVersion{2}:$ABIdump->{"LibraryVersion"};
17152 exitReport();
17153 }
17154 }
17155 }
17156}
17157
17158sub initLogging($)
17159{
17160 my $LibVersion = $_[0];
17161 # create log directory
17162 my ($LOG_DIR, $LOG_FILE) = ("logs/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"}, "log.txt");
17163 if($OutputLogPath{$LibVersion})
17164 { # user-defined by -log-path option
17165 ($LOG_DIR, $LOG_FILE) = separate_path($OutputLogPath{$LibVersion});
17166 }
17167 if($LogMode ne "n") {
17168 mkpath($LOG_DIR);
17169 }
17170 $LOG_PATH{$LibVersion} = get_abs_path($LOG_DIR)."/".$LOG_FILE;
17171 resetLogging($LibVersion);
17172 if($Debug)
17173 { # debug directory
17174 $DEBUG_PATH{$LibVersion} = "debug/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"};
17175 rmtree($DEBUG_PATH{$LibVersion});
17176 }
17177}
17178
17179sub writeLog($$)
17180{
17181 my ($LibVersion, $Msg) = @_;
17182 if($LogMode ne "n") {
17183 appendFile($LOG_PATH{$LibVersion}, $Msg);
17184 }
17185}
17186
17187sub resetLogging($)
17188{
17189 my $LibVersion = $_[0];
17190 if($LogMode!~/a|n/)
17191 { # remove old log
17192 unlink($LOG_PATH{$LibVersion});
17193 }
17194}
17195
17196sub printErrorLog($)
17197{
17198 my $LibVersion = $_[0];
17199 if($LogMode ne "n") {
17200 printMsg("ERROR", "see log for details:\n ".$LOG_PATH{$LibVersion}."\n");
17201 }
17202}
17203
17204sub isDump($)
17205{
17206 if(get_filename($_[0])=~/\A(.+)\.abi(\Q.tar.gz\E|\Q.zip\E|)\Z/)
17207 { # returns a name of package
17208 return $1;
17209 }
17210 return 0;
17211}
17212
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017213sub compareInit()
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017214{
17215 # read input XML descriptors or ABI dumps
17216 if(not $Descriptor{1}{"Path"}) {
17217 exitStatus("Error", "-d1 option is not specified");
17218 }
17219 my @DParts1 = split(/\s*,\s*/, $Descriptor{1}{"Path"});
17220 foreach my $Part (@DParts1)
17221 {
17222 if(not -e $Part) {
17223 exitStatus("Access_Error", "can't access \'$Part\'");
17224 }
17225 }
17226 if(not $Descriptor{2}{"Path"}) {
17227 exitStatus("Error", "-d2 option is not specified");
17228 }
17229 my @DParts2 = split(/\s*,\s*/, $Descriptor{2}{"Path"});
17230 foreach my $Part (@DParts2)
17231 {
17232 if(not -e $Part) {
17233 exitStatus("Access_Error", "can't access \'$Part\'");
17234 }
17235 }
17236 detect_default_paths("bin"); # to extract dumps
17237 if($#DParts1==0 and $#DParts2==0
17238 and isDump($Descriptor{1}{"Path"})
17239 and isDump($Descriptor{2}{"Path"}))
17240 { # optimization: equal ABI dumps
17241 quickEmptyReports();
17242 }
17243 checkVersionNum(1, $Descriptor{1}{"Path"});
17244 checkVersionNum(2, $Descriptor{2}{"Path"});
17245 printMsg("INFO", "preparation, please wait ...");
17246 foreach my $Part (@DParts1)
17247 {
17248 if(isDump($Part)) {
17249 read_ABI_Dump(1, $Part);
17250 }
17251 else {
17252 readDescriptor(1, createDescriptor(1, $Part));
17253 }
17254 }
17255 foreach my $Part (@DParts2)
17256 {
17257 if(isDump($Part)) {
17258 read_ABI_Dump(2, $Part);
17259 }
17260 else {
17261 readDescriptor(2, createDescriptor(2, $Part));
17262 }
17263 }
17264 initLogging(1);
17265 initLogging(2);
17266 # check consistency
17267 if(not $Descriptor{1}{"Headers"}
17268 and not $Descriptor{1}{"Libs"}) {
17269 exitStatus("Error", "descriptor d1 does not contain both header files and libraries info");
17270 }
17271 if(not $Descriptor{2}{"Headers"}
17272 and not $Descriptor{2}{"Libs"}) {
17273 exitStatus("Error", "descriptor d2 does not contain both header files and libraries info");
17274 }
17275 if($Descriptor{1}{"Headers"} and not $Descriptor{1}{"Libs"}
17276 and not $Descriptor{2}{"Headers"} and $Descriptor{2}{"Libs"}) {
17277 exitStatus("Error", "can't compare headers with $SLIB_TYPE libraries");
17278 }
17279 elsif(not $Descriptor{1}{"Headers"} and $Descriptor{1}{"Libs"}
17280 and $Descriptor{2}{"Headers"} and not $Descriptor{2}{"Libs"}) {
17281 exitStatus("Error", "can't compare $SLIB_TYPE libraries with headers");
17282 }
17283 if(not $Descriptor{1}{"Headers"}) {
17284 if($CheckHeadersOnly_Opt) {
17285 exitStatus("Error", "can't find header files info in descriptor d1");
17286 }
17287 }
17288 if(not $Descriptor{2}{"Headers"}) {
17289 if($CheckHeadersOnly_Opt) {
17290 exitStatus("Error", "can't find header files info in descriptor d2");
17291 }
17292 }
17293 if(not $Descriptor{1}{"Headers"}
17294 or not $Descriptor{2}{"Headers"}) {
17295 if(not $CheckObjectsOnly_Opt) {
17296 printMsg("WARNING", "comparing $SLIB_TYPE libraries only");
17297 $CheckObjectsOnly = 1;
17298 }
17299 }
17300 if(not $Descriptor{1}{"Libs"}) {
17301 if($CheckObjectsOnly_Opt) {
17302 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d1");
17303 }
17304 }
17305 if(not $Descriptor{2}{"Libs"}) {
17306 if($CheckObjectsOnly_Opt) {
17307 exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d2");
17308 }
17309 }
17310 if(not $Descriptor{1}{"Libs"}
17311 or not $Descriptor{2}{"Libs"})
17312 { # comparing standalone header files
17313 # comparing ABI dumps created with --headers-only
17314 if(not $CheckHeadersOnly_Opt)
17315 {
17316 printMsg("WARNING", "checking headers only");
17317 $CheckHeadersOnly = 1;
17318 }
17319 }
17320 if($UseDumps)
17321 { # --use-dumps
17322 # parallel processing
17323 my $pid = fork();
17324 if($pid)
17325 { # dump on two CPU cores
17326 my @PARAMS = ("-dump", $Descriptor{1}{"Path"}, "-l", $TargetLibraryName);
17327 if($RelativeDirectory{1}) {
17328 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{1});
17329 }
17330 if($OutputLogPath{1}) {
17331 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{1});
17332 }
17333 if($CrossGcc) {
17334 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
17335 }
17336 if($Debug) {
17337 @PARAMS = (@PARAMS, "-debug");
17338 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040017339 if($Quiet)
17340 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017341 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040017342 @PARAMS = (@PARAMS, "-logging-mode", "a");
17343 }
17344 elsif($LogMode and $LogMode ne "w")
17345 { # "w" is default
17346 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017347 }
17348 if($ExtendedCheck) {
17349 @PARAMS = (@PARAMS, "-extended");
17350 }
17351 if($UserLang) {
17352 @PARAMS = (@PARAMS, "-lang", $UserLang);
17353 }
17354 if($TargetVersion{1}) {
17355 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{1});
17356 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017357 system("perl", $0, @PARAMS);
17358 if($?) {
17359 exit(1);
17360 }
17361 }
17362 else
17363 { # child
17364 my @PARAMS = ("-dump", $Descriptor{2}{"Path"}, "-l", $TargetLibraryName);
17365 if($RelativeDirectory{2}) {
17366 @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{2});
17367 }
17368 if($OutputLogPath{2}) {
17369 @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{2});
17370 }
17371 if($CrossGcc) {
17372 @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
17373 }
17374 if($Debug) {
17375 @PARAMS = (@PARAMS, "-debug");
17376 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040017377 if($Quiet)
17378 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017379 @PARAMS = (@PARAMS, "-quiet");
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040017380 @PARAMS = (@PARAMS, "-logging-mode", "a");
17381 }
17382 elsif($LogMode and $LogMode ne "w")
17383 { # "w" is default
17384 @PARAMS = (@PARAMS, "-logging-mode", $LogMode);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017385 }
17386 if($ExtendedCheck) {
17387 @PARAMS = (@PARAMS, "-extended");
17388 }
17389 if($UserLang) {
17390 @PARAMS = (@PARAMS, "-lang", $UserLang);
17391 }
17392 if($TargetVersion{2}) {
17393 @PARAMS = (@PARAMS, "-vnum", $TargetVersion{2});
17394 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017395 system("perl", $0, @PARAMS);
17396 if($?) {
17397 exit(1);
17398 }
17399 else {
17400 exit(0);
17401 }
17402 }
17403 waitpid($pid, 0);
17404 my @CMP_PARAMS = ("-l", $TargetLibraryName);
17405 @CMP_PARAMS = (@CMP_PARAMS, "-d1", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi.$AR_EXT");
17406 @CMP_PARAMS = (@CMP_PARAMS, "-d2", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{2}{"Version"}.".abi.$AR_EXT");
17407 if($TargetLibraryFName ne $TargetLibraryName) {
17408 @CMP_PARAMS = (@CMP_PARAMS, "-l-full", $TargetLibraryFName);
17409 }
17410 if($ShowRetVal) {
17411 @CMP_PARAMS = (@CMP_PARAMS, "-show-retval");
17412 }
17413 if($CrossGcc) {
17414 @CMP_PARAMS = (@CMP_PARAMS, "-cross-gcc", $CrossGcc);
17415 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040017416 if($Quiet)
17417 {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017418 @CMP_PARAMS = (@CMP_PARAMS, "-quiet");
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017419 @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", "a");
17420 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040017421 elsif($LogMode and $LogMode ne "w")
17422 { # "w" is default
17423 @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", $LogMode);
17424 }
17425 if($ReportFormat and $ReportFormat ne "html")
17426 { # HTML is default format
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017427 @CMP_PARAMS = (@CMP_PARAMS, "-report-format", $ReportFormat);
17428 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017429 if($OutputReportPath) {
17430 @CMP_PARAMS = (@CMP_PARAMS, "-report-path", $OutputReportPath);
17431 }
17432 if($BinaryReportPath) {
17433 @CMP_PARAMS = (@CMP_PARAMS, "-bin-report-path", $BinaryReportPath);
17434 }
17435 if($SourceReportPath) {
17436 @CMP_PARAMS = (@CMP_PARAMS, "-src-report-path", $SourceReportPath);
17437 }
17438 if($LoggingPath) {
17439 @CMP_PARAMS = (@CMP_PARAMS, "-log-path", $LoggingPath);
17440 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017441 system("perl", $0, @CMP_PARAMS);
17442 exit($?>>8);
17443 }
17444 if(not $Descriptor{1}{"Dump"}
17445 or not $Descriptor{2}{"Dump"})
17446 { # need GCC toolchain to analyze
17447 # header files and libraries
17448 detect_default_paths("inc|lib|gcc");
17449 }
17450 if(not $Descriptor{1}{"Dump"})
17451 {
17452 if(not $CheckHeadersOnly) {
17453 readLibs(1);
17454 }
17455 if($CheckHeadersOnly) {
17456 setLanguage(1, "C++");
17457 }
17458 if(not $CheckObjectsOnly) {
17459 searchForHeaders(1);
17460 }
17461 $WORD_SIZE{1} = detectWordSize();
17462 }
17463 if(not $Descriptor{2}{"Dump"})
17464 {
17465 if(not $CheckHeadersOnly) {
17466 readLibs(2);
17467 }
17468 if($CheckHeadersOnly) {
17469 setLanguage(2, "C++");
17470 }
17471 if(not $CheckObjectsOnly) {
17472 searchForHeaders(2);
17473 }
17474 $WORD_SIZE{2} = detectWordSize();
17475 }
17476 if($WORD_SIZE{1} ne $WORD_SIZE{2})
17477 { # support for old ABI dumps
17478 # try to synch different WORD sizes
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017479 if(not checkDumpVersion(1, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017480 {
17481 $WORD_SIZE{1} = $WORD_SIZE{2};
17482 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{2}." bytes");
17483 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017484 elsif(not checkDumpVersion(2, "2.1"))
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017485 {
17486 $WORD_SIZE{2} = $WORD_SIZE{1};
17487 printMsg("WARNING", "set WORD size to ".$WORD_SIZE{1}." bytes");
17488 }
17489 }
17490 elsif(not $WORD_SIZE{1}
17491 and not $WORD_SIZE{2})
17492 { # support for old ABI dumps
17493 $WORD_SIZE{1} = 4;
17494 $WORD_SIZE{2} = 4;
17495 }
17496 if($Descriptor{1}{"Dump"})
17497 { # support for old ABI dumps
17498 prepareTypes(1);
17499 }
17500 if($Descriptor{2}{"Dump"})
17501 { # support for old ABI dumps
17502 prepareTypes(2);
17503 }
17504 if($AppPath and not keys(%{$Symbol_Library{1}})) {
17505 printMsg("WARNING", "the application ".get_filename($AppPath)." has no symbols imported from the $SLIB_TYPE libraries");
17506 }
17507 # started to process input data
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017508 if(not $CheckObjectsOnly)
17509 {
17510 if($Descriptor{1}{"Headers"}
17511 and not $Descriptor{1}{"Dump"}) {
17512 readHeaders(1);
17513 }
17514 if($Descriptor{2}{"Headers"}
17515 and not $Descriptor{2}{"Dump"}) {
17516 readHeaders(2);
17517 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017518 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017519 prepareSymbols(1);
17520 prepareSymbols(2);
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017521
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017522 %SymbolInfo = ();
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017523
17524 # Virtual Tables
17525 registerVTable(1);
17526 registerVTable(2);
17527
17528 if(not checkDumpVersion(1, "1.22")
17529 and checkDumpVersion(2, "1.22"))
17530 { # support for old ABI dumps
17531 foreach my $ClassName (keys(%{$VirtualTable{2}}))
17532 {
17533 if($ClassName=~/</)
17534 { # templates
17535 if(not defined $VirtualTable{1}{$ClassName})
17536 { # synchronize
17537 delete($VirtualTable{2}{$ClassName});
17538 }
17539 }
17540 }
17541 }
17542
17543 registerOverriding(1);
17544 registerOverriding(2);
17545
17546 setVirtFuncPositions(1);
17547 setVirtFuncPositions(2);
17548
17549 # Other
17550 addParamNames(1);
17551 addParamNames(2);
17552
17553 detectChangedTypedefs();
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017554}
17555
17556sub compareAPIs($)
17557{
17558 my $Level = $_[0];
17559 readRules($Level);
17560 if($Level eq "Binary") {
17561 printMsg("INFO", "comparing ABIs ...");
17562 }
17563 else {
17564 printMsg("INFO", "comparing APIs ...");
17565 }
17566 if($CheckHeadersOnly
17567 or $Level eq "Source")
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017568 { # added/removed in headers
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017569 detectAdded_H($Level);
17570 detectRemoved_H($Level);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017571 }
17572 else
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017573 { # added/removed in libs
17574 detectAdded($Level);
17575 detectRemoved($Level);
17576 }
17577 if(not $CheckObjectsOnly)
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017578 {
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017579 mergeSignatures($Level);
17580 if(keys(%{$CheckedSymbols{$Level}})) {
17581 mergeConstants($Level);
17582 }
17583 }
17584 if($CheckHeadersOnly
17585 or $Level eq "Source")
17586 { # added/removed in headers
17587 mergeHeaders($Level);
17588 }
17589 else
17590 { # added/removed in libs
17591 mergeLibs($Level);
17592 if($CheckImpl
17593 and $Level eq "Binary") {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017594 mergeImpl();
17595 }
17596 }
17597}
17598
17599sub optimize_set(@)
17600{
17601 my %Included = ();
17602 foreach my $Path (@_)
17603 {
17604 detect_header_includes($Path, 1);
17605 foreach my $Include (keys(%{$Header_Includes{1}{$Path}})) {
17606 $Included{get_filename($Include)}{$Include}=1;
17607 }
17608 }
17609 my @Res = ();
17610 foreach my $Path (@_)
17611 {
17612 my $Add = 1;
17613 foreach my $Inc (keys(%{$Included{get_filename($Path)}}))
17614 {
17615 if($Path=~/\/\Q$Inc\E\Z/)
17616 {
17617 $Add = 0;
17618 last;
17619 }
17620 }
17621 if($Add) {
17622 push(@Res, $Path);
17623 }
17624 }
17625 return @Res;
17626}
17627
17628sub writeOpts()
17629{
17630 my %Opts = (
17631 "OStarget"=>$OStarget,
17632 "Debug"=>$Debug,
17633 "Quiet"=>$Quiet,
17634 "LogMode"=>$LogMode,
17635 "CheckHeadersOnly"=>$CheckHeadersOnly,
17636
17637 "SystemRoot"=>$SystemRoot,
17638 "MODULES_DIR"=>$MODULES_DIR,
17639 "GCC_PATH"=>$GCC_PATH,
17640 "TargetSysInfo"=>$TargetSysInfo,
17641 "CrossPrefix"=>$CrossPrefix,
17642 "TargetLibraryName"=>$TargetLibraryName,
17643 "CrossGcc"=>$CrossGcc,
17644 "UseStaticLibs"=>$UseStaticLibs,
17645 "NoStdInc"=>$NoStdInc
17646 );
17647 return \%Opts;
17648}
17649
17650sub get_CoreError($)
17651{
17652 my %CODE_ERROR = reverse(%ERROR_CODE);
17653 return $CODE_ERROR{$_[0]};
17654}
17655
17656sub scenario()
17657{
17658 if($StdOut)
17659 { # enable quiet mode
17660 $Quiet = 1;
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017661 $JoinReport = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017662 }
Andrey Ponomarenkodde2dad2012-03-26 19:06:14 +040017663 if(not $LogMode)
17664 { # default
17665 $LogMode = "w";
17666 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017667 if($UserLang)
17668 { # --lang=C++
17669 $UserLang = uc($UserLang);
17670 $COMMON_LANGUAGE{1}=$UserLang;
17671 $COMMON_LANGUAGE{2}=$UserLang;
17672 }
17673 if($LoggingPath)
17674 {
17675 $OutputLogPath{1} = $LoggingPath;
17676 $OutputLogPath{2} = $LoggingPath;
17677 if($Quiet) {
17678 $COMMON_LOG_PATH = $LoggingPath;
17679 }
17680 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017681 if($BinaryOnly and $SourceOnly)
17682 { # both --binary and --source
17683 # is the default mode
17684 $DoubleReport = 1;
17685 $JoinReport = 0;
17686 $BinaryOnly = 0;
17687 $SourceOnly = 0;
17688 if($OutputReportPath)
17689 { # --report-path
17690 $DoubleReport = 0;
17691 $JoinReport = 1;
17692 }
17693 }
17694 elsif($BinaryOnly or $SourceOnly)
17695 { # --binary or --source
17696 $DoubleReport = 0;
17697 $JoinReport = 0;
17698 }
17699 if($UseXML)
17700 { # --xml option
17701 $ReportFormat = "xml";
17702 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017703 if($ReportFormat)
17704 { # validate
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017705 $ReportFormat = lc($ReportFormat);
17706 if($ReportFormat!~/\A(xml|html|htm)\Z/) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017707 exitStatus("Error", "unknown format \'$ReportFormat\'");
17708 }
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017709 if($ReportFormat eq "htm")
17710 { # HTM == HTML
17711 $ReportFormat = "html";
17712 }
17713 elsif($ReportFormat eq "xml")
17714 { # --report-format=XML equal to --xml
17715 $UseXML = 1;
17716 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017717 }
17718 else
17719 { # default: HTML
17720 $ReportFormat = "html";
17721 }
17722 if($Quiet and $LogMode!~/a|n/)
17723 { # --quiet log
17724 if(-f $COMMON_LOG_PATH) {
17725 unlink($COMMON_LOG_PATH);
17726 }
17727 }
17728 if($TestTool and $UseDumps)
17729 { # --test && --use-dumps == --test-dump
17730 $TestDump = 1;
17731 }
17732 if($Help) {
17733 HELP_MESSAGE();
17734 exit(0);
17735 }
17736 if($InfoMsg) {
17737 INFO_MESSAGE();
17738 exit(0);
17739 }
17740 if($ShowVersion) {
17741 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.");
17742 exit(0);
17743 }
17744 if($DumpVersion) {
17745 printMsg("INFO", $TOOL_VERSION);
17746 exit(0);
17747 }
17748 if($ExtendedCheck) {
17749 $CheckHeadersOnly = 1;
17750 }
17751 if($SystemRoot_Opt)
17752 { # user defined root
17753 if(not -e $SystemRoot_Opt) {
17754 exitStatus("Access_Error", "can't access \'$SystemRoot\'");
17755 }
17756 $SystemRoot = $SystemRoot_Opt;
17757 $SystemRoot=~s/[\/]+\Z//g;
17758 if($SystemRoot) {
17759 $SystemRoot = get_abs_path($SystemRoot);
17760 }
17761 }
17762 $Data::Dumper::Sortkeys = 1;
17763 # FIXME: can't pass \&dump_sorting - cause a segfault sometimes
17764 # $Data::Dumper::Sortkeys = \&dump_sorting;
17765 if($TargetLibsPath)
17766 {
17767 if(not -f $TargetLibsPath) {
17768 exitStatus("Access_Error", "can't access file \'$TargetLibsPath\'");
17769 }
17770 foreach my $Lib (split(/\s*\n\s*/, readFile($TargetLibsPath))) {
17771 $TargetLibs{$Lib} = 1;
17772 }
17773 }
17774 if($TargetHeadersPath)
17775 { # --headers-list
17776 if(not -f $TargetHeadersPath) {
17777 exitStatus("Access_Error", "can't access file \'$TargetHeadersPath\'");
17778 }
17779 foreach my $Header (split(/\s*\n\s*/, readFile($TargetHeadersPath)))
17780 {
17781 $TargetHeaders{1}{$Header} = 1;
17782 $TargetHeaders{2}{$Header} = 1;
17783 }
17784 }
17785 if($TargetHeader)
17786 { # --header
17787 $TargetHeaders{1}{$TargetHeader} = 1;
17788 $TargetHeaders{2}{$TargetHeader} = 1;
17789 }
17790 if($TestTool
17791 or $TestDump)
17792 { # --test, --test-dump
17793 detect_default_paths("bin|gcc"); # to compile libs
17794 loadModule("RegTests");
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017795 testTool($TestDump, $Debug, $Quiet, $ExtendedCheck,
17796 $LogMode, $ReportFormat, $LIB_EXT, $GCC_PATH, $Browse);
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017797 exit(0);
17798 }
17799 if($DumpSystem)
17800 { # --dump-system
17801 loadModule("SysCheck");
17802 if($DumpSystem=~/\.xml\Z/)
17803 { # system XML descriptor
17804 if(not -f $DumpSystem) {
17805 exitStatus("Access_Error", "can't access file \'$DumpSystem\'");
17806 }
17807 my $Ret = readSystemDescriptor(readFile($DumpSystem));
17808 foreach (@{$Ret->{"Tools"}}) {
17809 $SystemPaths{"bin"}{$_} = 1;
17810 $TargetTools{$_}=1;
17811 }
17812 if($Ret->{"CrossPrefix"}) {
17813 $CrossPrefix = $Ret->{"CrossPrefix"};
17814 }
17815 }
17816 elsif($SystemRoot_Opt)
17817 { # -sysroot "/" option
17818 # default target: /usr/lib, /usr/include
17819 # search libs: /usr/lib and /lib
17820 if(not -e $SystemRoot."/usr/lib") {
17821 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/lib'");
17822 }
17823 if(not -e $SystemRoot."/lib") {
17824 exitStatus("Access_Error", "can't access '".$SystemRoot."/lib'");
17825 }
17826 if(not -e $SystemRoot."/usr/include") {
17827 exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/include'");
17828 }
17829 readSystemDescriptor("
17830 <name>
17831 $DumpSystem
17832 </name>
17833 <headers>
17834 $SystemRoot/usr/include
17835 </headers>
17836 <libs>
17837 $SystemRoot/usr/lib
17838 </libs>
17839 <search_libs>
17840 $SystemRoot/lib
17841 </search_libs>");
17842 }
17843 else {
17844 exitStatus("Error", "-sysroot <dirpath> option should be specified, usually it's \"/\"");
17845 }
17846 detect_default_paths("bin|gcc"); # to check symbols
17847 if($OStarget eq "windows")
17848 { # to run dumpbin.exe
17849 # and undname.exe
17850 check_win32_env();
17851 }
17852 dumpSystem(writeOpts());
17853 exit(0);
17854 }
17855 if($CmpSystems)
17856 { # --cmp-systems
17857 detect_default_paths("bin"); # to extract dumps
17858 loadModule("SysCheck");
17859 cmpSystems($Descriptor{1}{"Path"}, $Descriptor{2}{"Path"}, writeOpts());
17860 exit(0);
17861 }
17862 if($GenerateTemplate) {
17863 generateTemplate();
17864 exit(0);
17865 }
17866 if(not $TargetLibraryName) {
17867 exitStatus("Error", "library name is not selected (option -l <name>)");
17868 }
17869 else
17870 { # validate library name
17871 if($TargetLibraryName=~/[\*\/\\]/) {
17872 exitStatus("Error", "\"\\\", \"\/\" and \"*\" symbols are not allowed in the library name");
17873 }
17874 }
17875 if(not $TargetLibraryFName) {
17876 $TargetLibraryFName = $TargetLibraryName;
17877 }
17878 if($CheckHeadersOnly_Opt and $CheckObjectsOnly_Opt) {
17879 exitStatus("Error", "you can't specify both -headers-only and -objects-only options at the same time");
17880 }
17881 if($SymbolsListPath)
17882 {
17883 if(not -f $SymbolsListPath) {
17884 exitStatus("Access_Error", "can't access file \'$SymbolsListPath\'");
17885 }
17886 foreach my $Interface (split(/\s*\n\s*/, readFile($SymbolsListPath))) {
17887 $SymbolsList{$Interface} = 1;
17888 }
17889 }
17890 if($SkipHeadersPath)
17891 {
17892 if(not -f $SkipHeadersPath) {
17893 exitStatus("Access_Error", "can't access file \'$SkipHeadersPath\'");
17894 }
17895 foreach my $Path (split(/\s*\n\s*/, readFile($SkipHeadersPath)))
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017896 { # register for both versions
17897 $SkipHeadersList{1}{$Path} = 1;
17898 $SkipHeadersList{2}{$Path} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017899 my ($CPath, $Type) = classifyPath($Path);
17900 $SkipHeaders{1}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017901 $SkipHeaders{2}{$Type}{$CPath} = 1;
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017902 }
17903 }
17904 if($ParamNamesPath)
17905 {
17906 if(not -f $ParamNamesPath) {
17907 exitStatus("Access_Error", "can't access file \'$ParamNamesPath\'");
17908 }
17909 foreach my $Line (split(/\n/, readFile($ParamNamesPath)))
17910 {
17911 if($Line=~s/\A(\w+)\;//)
17912 {
17913 my $Interface = $1;
17914 if($Line=~/;(\d+);/) {
17915 while($Line=~s/(\d+);(\w+)//) {
17916 $AddIntParams{$Interface}{$1}=$2;
17917 }
17918 }
17919 else {
17920 my $Num = 0;
17921 foreach my $Name (split(/;/, $Line)) {
17922 $AddIntParams{$Interface}{$Num++}=$Name;
17923 }
17924 }
17925 }
17926 }
17927 }
17928 if($AppPath)
17929 {
17930 if(not -f $AppPath) {
17931 exitStatus("Access_Error", "can't access file \'$AppPath\'");
17932 }
Andrey Ponomarenko16934472012-03-29 15:37:04 +040017933 foreach my $Interface (readSymbols_App($AppPath)) {
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017934 $SymbolsList_App{$Interface} = 1;
17935 }
17936 }
17937 if($DumpAPI)
17938 { # --dump-abi
17939 # make an API dump
17940 create_ABI_Dump();
17941 exit($COMPILE_ERRORS);
17942 }
17943 # default: compare APIs
17944 # -d1 <path>
17945 # -d2 <path>
Andrey Ponomarenko1bdef342012-03-19 17:23:47 +040017946 compareInit();
17947 if($JoinReport or $DoubleReport)
17948 {
17949 compareAPIs("Binary");
17950 compareAPIs("Source");
17951 }
17952 elsif($BinaryOnly) {
17953 compareAPIs("Binary");
17954 }
17955 elsif($SourceOnly) {
17956 compareAPIs("Source");
17957 }
Andrey Ponomarenkoab282102012-03-11 11:57:02 +040017958 exitReport();
17959}
17960
17961scenario();