ABI Compliance Checker 1.96.8
diff --git a/abi-compliance-checker.pl b/abi-compliance-checker.pl
new file mode 100755
index 0000000..a6716f8
--- /dev/null
+++ b/abi-compliance-checker.pl
@@ -0,0 +1,16771 @@
+#!/usr/bin/perl
+###########################################################################
+# ABI Compliance Checker (ACC) 1.96.8
+# A tool for checking backward binary compatibility of a C/C++ library API
+#
+# Copyright (C) 2009-2010 The Linux Foundation.
+# Copyright (C) 2009-2011 Institute for System Programming, RAS.
+# Copyright (C) 2011-2012 Nokia Corporation and/or its subsidiary(-ies).
+# Copyright (C) 2011-2012 ROSA Laboratory.
+#
+# Written by Andrey Ponomarenko
+#
+# PLATFORMS
+# =========
+#  Linux, FreeBSD, Mac OS X, Haiku, MS Windows, Symbian
+#
+# REQUIREMENTS
+# ============
+#  Linux
+#    - G++ (3.0-4.6.2, recommended >= 4.5)
+#    - GNU Binutils (readelf, c++filt, objdump)
+#    - Perl 5 (5.8-5.14)
+#
+#  Mac OS X
+#    - Xcode (gcc, otool, c++filt)
+#
+#  MS Windows
+#    - MinGW (3.0-4.6.2, recommended >= 4.5)
+#    - MS Visual C++ (dumpbin, undname, cl)
+#    - Active Perl 5 (5.8-5.14)
+#    - Sigcheck v1.71 or newer
+#    - Info-ZIP 3.0 (zip, unzip)
+#    - Add gcc.exe path (C:\MinGW\bin\) to your system PATH variable
+#    - Run vsvars32.bat (C:\Microsoft Visual Studio 9.0\Common7\Tools\)
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License or the GNU Lesser
+# General Public License as published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# and the GNU Lesser General Public License along with this program.
+# If not, see <http://www.gnu.org/licenses/>.
+###########################################################################
+use Getopt::Long;
+Getopt::Long::Configure ("posix_default", "no_ignore_case");
+use File::Path qw(mkpath rmtree);
+use File::Temp qw(tempdir);
+use File::Copy qw(copy move);
+use Cwd qw(abs_path cwd);
+use Data::Dumper;
+use Config;
+
+my $TOOL_VERSION = "1.96.8";
+my $ABI_DUMP_VERSION = "2.10.1";
+my $OLDEST_SUPPORTED_VERSION = "1.18";
+my $XML_REPORT_VERSION = "1.0";
+my $OSgroup = get_OSgroup();
+my $ORIG_DIR = cwd();
+my $TMP_DIR = tempdir(CLEANUP=>1);
+
+# Internal modules
+my $MODULES_DIR = get_Modules();
+push(@INC, get_dirname($MODULES_DIR));
+# Rules DB
+my %RULES_PATH = (
+    "Binary" => $MODULES_DIR."/RulesBin.xml",
+    "Source" => $MODULES_DIR."/RulesSrc.xml");
+
+my ($Help, $ShowVersion, %Descriptor, $TargetLibraryName, $GenerateTemplate,
+$TestTool, $DumpAPI, $SymbolsListPath, $CheckHeadersOnly_Opt, $UseDumps,
+$CheckObjectsOnly_Opt, $AppPath, $StrictCompat, $DumpVersion, $ParamNamesPath,
+%RelativeDirectory, $TargetLibraryFName, $TestDump, $CheckImpl, $LoggingPath,
+%TargetVersion, $InfoMsg, $UseOldDumps, %UsedDump, $CrossGcc, %OutputLogPath,
+$OutputReportPath, $OutputDumpPath, $ShowRetVal, $SystemRoot_Opt, $DumpSystem,
+$CmpSystems, $TargetLibsPath, $Debug, $CrossPrefix, $UseStaticLibs, $NoStdInc,
+$TargetComponent_Opt, $TargetSysInfo, $TargetHeader, $ExtendedCheck, $Quiet,
+$SkipHeadersPath, $Cpp2003, $LogMode, $StdOut, $ListAffected, $ReportFormat,
+$UserLang, $TargetHeadersPath);
+
+my $CmdName = get_filename($0);
+my %OS_LibExt = (
+    "dynamic" => {
+        "default"=>"so",
+        "macos"=>"dylib",
+        "windows"=>"dll",
+        "symbian"=>"dso"
+    },
+    "static" => {
+        "default"=>"a",
+        "windows"=>"lib",
+        "symbian"=>"lib"
+    }
+);
+
+my %OS_Archive = (
+    "windows"=>"zip",
+    "default"=>"tar.gz"
+);
+
+my %ERROR_CODE = (
+    # Compatible verdict
+    "Compatible"=>0,
+    "Success"=>0,
+    # Incompatible verdict
+    "Incompatible"=>1,
+    # Undifferentiated error code
+    "Error"=>2,
+    # System command is not found
+    "Not_Found"=>3,
+    # Cannot access input files
+    "Access_Error"=>4,
+    # Cannot compile header files
+    "Cannot_Compile"=>5,
+    # Header compiled with errors
+    "Compile_Error"=>6,
+    # Invalid input ABI dump
+    "Invalid_Dump"=>7,
+    # Incompatible version of ABI dump
+    "Dump_Version"=>8,
+    # Cannot find a module
+    "Module_Error"=>9,
+    # Empty intersection between
+    # headers and shared objects
+    "Empty_Intersection"=>10,
+    # Empty set of symbols in headers
+    "Empty_Set"=>11
+);
+
+my %HomePage = (
+    "Wiki"=>"http://ispras.linux-foundation.org/index.php/ABI_compliance_checker",
+    "Dev"=>"http://forge.ispras.ru/projects/abi-compliance-checker"
+);
+
+my $ShortUsage = "ABI Compliance Checker (ACC) $TOOL_VERSION
+A tool for checking backward binary compatibility of a C/C++ library API
+Copyright (C) 2012 ROSA Laboratory
+License: GNU LGPL or GNU GPL
+
+Usage: $CmdName [options]
+Example: $CmdName -lib NAME -d1 OLD.xml -d2 NEW.xml
+
+OLD.xml and NEW.xml are XML-descriptors:
+
+    <version>
+        1.0
+    </version>
+
+    <headers>
+        /path/to/headers/
+    </headers>
+
+    <libs>
+        /path/to/libraries/
+    </libs>
+
+More info: $CmdName --help\n";
+
+if($#ARGV==-1) {
+    printMsg("INFO", $ShortUsage);
+    exit(0);
+}
+
+foreach (2 .. $#ARGV)
+{# correct comma separated options
+    if($ARGV[$_-1] eq ",") {
+        $ARGV[$_-2].=",".$ARGV[$_];
+        splice(@ARGV, $_-1, 2);
+    }
+    elsif($ARGV[$_-1]=~/,\Z/) {
+        $ARGV[$_-1].=$ARGV[$_];
+        splice(@ARGV, $_, 1);
+    }
+    elsif($ARGV[$_]=~/\A,/
+    and $ARGV[$_] ne ",") {
+        $ARGV[$_-1].=$ARGV[$_];
+        splice(@ARGV, $_, 1);
+    }
+}
+
+GetOptions("h|help!" => \$Help,
+  "i|info!" => \$InfoMsg,
+  "v|version!" => \$ShowVersion,
+  "dumpversion!" => \$DumpVersion,
+# general options
+  "l|lib|library=s" => \$TargetLibraryName,
+  "d1|old|o=s" => \$Descriptor{1}{"Path"},
+  "d2|new|n=s" => \$Descriptor{2}{"Path"},
+  "dump|dump-abi|dump_abi=s" => \$DumpAPI,
+  "old-dumps!" => \$UseOldDumps,
+# extra options
+  "d|descriptor-template!" => \$GenerateTemplate,
+  "app|application=s" => \$AppPath,
+  "static-libs!" => \$UseStaticLibs,
+  "cross-gcc=s" => \$CrossGcc,
+  "cross-prefix=s" => \$CrossPrefix,
+  "sysroot=s" => \$SystemRoot_Opt,
+  "v1|version1|vnum=s" => \$TargetVersion{1},
+  "v2|version2=s" => \$TargetVersion{2},
+  "s|strict!" => \$StrictCompat,
+  "symbols-list=s" => \$SymbolsListPath,
+  "skip-headers=s" => \$SkipHeadersPath,
+  "headers-only|headers_only!" => \$CheckHeadersOnly_Opt,
+  "objects-only!" => \$CheckObjectsOnly_Opt,
+  "check-impl|check-implementation!" => \$CheckImpl,
+  "show-retval!" => \$ShowRetVal,
+  "use-dumps!" => \$UseDumps,
+  "nostdinc!" => \$NoStdInc,
+  "dump-system=s" => \$DumpSystem,
+  "sysinfo=s" => \$TargetSysInfo,
+  "cmp-systems!" => \$CmpSystems,
+  "libs-list=s" => \$TargetLibsPath,
+  "headers-list=s" => \$TargetHeadersPath,
+  "header=s" => \$TargetHeader,
+  "ext|extended!" => \$ExtendedCheck,
+  "q|quiet!" => \$Quiet,
+  "stdout!" => \$StdOut,
+  "report-format=s" => \$ReportFormat,
+  "lang=s" => \$UserLang,
+# other options
+  "test!" => \$TestTool,
+  "test-dump!" => \$TestDump,
+  "debug!" => \$Debug,
+  "cpp-compatible!" => \$Cpp2003,
+  "p|params=s" => \$ParamNamesPath,
+  "relpath1|relpath=s" => \$RelativeDirectory{1},
+  "relpath2=s" => \$RelativeDirectory{2},
+  "dump-path=s" => \$OutputDumpPath,
+  "report-path=s" => \$OutputReportPath,
+  "log-path=s" => \$LoggingPath,
+  "log1-path=s" => \$OutputLogPath{1},
+  "log2-path=s" => \$OutputLogPath{2},
+  "logging-mode=s" => \$LogMode,
+  "list-affected!" => \$ListAffected,
+  "l-full|lib-full=s" => \$TargetLibraryFName,
+  "component=s" => \$TargetComponent_Opt
+) or ERR_MESSAGE();
+
+sub ERR_MESSAGE()
+{
+    printMsg("INFO", "\n".$ShortUsage);
+    exit($ERROR_CODE{"Error"});
+}
+
+my $LIB_TYPE = $UseStaticLibs?"static":"dynamic";
+my $SLIB_TYPE = $LIB_TYPE;
+if($OSgroup!~/macos|windows/ and $SLIB_TYPE eq "dynamic")
+{ # show as "shared" library
+    $SLIB_TYPE = "shared";
+}
+my $LIB_EXT = getLIB_EXT($OSgroup);
+my $AR_EXT = getAR_EXT($OSgroup);
+my $BYTE_SIZE = 8;
+my $COMMON_LOG_PATH = "logs/run.log";
+
+my $HelpMessage="
+NAME:
+  ABI Compliance Checker ($CmdName)
+  Check backward binary compatibility of a $SLIB_TYPE C/C++ library API
+
+DESCRIPTION:
+  ABI Compliance Checker (ACC) is a tool for checking backward binary
+  compatibility of a $SLIB_TYPE C/C++ library API. The tool checks header
+  files and $SLIB_TYPE libraries (*.$LIB_EXT) of old and new versions and
+  analyzes changes in Application Binary Interface (ABI=API+compiler ABI)
+  that may break binary compatibility: changes in calling stack, v-table
+  changes, removed symbols, etc. Binary incompatibility may result in
+  crashing or incorrect behavior of applications built with an old version
+  of a library if they run on a new one.
+
+  The tool is intended for library developers and OS maintainers who are
+  interested in ensuring binary compatibility, i.e. allow old applications
+  to run with new library versions without the need to recompile. Also it
+  can be used by ISVs for checking applications portability to new library
+  versions. Found issues can be taken into account when adapting the
+  application to a new library version.
+
+  This tool is free software: you can redistribute it and/or modify it
+  under the terms of the GNU LGPL or GNU GPL.
+
+USAGE:
+  $CmdName [options]
+
+EXAMPLE:
+  $CmdName -lib NAME -d1 OLD.xml -d2 NEW.xml
+
+  OLD.xml and NEW.xml are XML-descriptors:
+
+    <version>
+        1.0
+    </version>
+
+    <headers>
+        /path1/to/header(s)/
+        /path2/to/header(s)/
+         ...
+    </headers>
+
+    <libs>
+        /path1/to/library(ies)/
+        /path2/to/library(ies)/
+         ...
+    </libs>
+
+INFORMATION OPTIONS:
+  -h|-help
+      Print this help.
+
+  -i|-info
+      Print complete info.
+
+  -v|-version
+      Print version information.
+
+  -dumpversion
+      Print the tool version ($TOOL_VERSION) and don't do anything else.
+
+GENERAL OPTIONS:
+  -l|-lib|-library <name>
+      Library name (without version).
+      It affects only on the path and the title of the report.
+
+  -d1|-old|-o <path>
+      Descriptor of 1st (old) library version.
+      It may be one of the following:
+      
+         1. XML-descriptor (VERSION.xml file):
+
+              <version>
+                  1.0
+              </version>
+
+              <headers>
+                  /path1/to/header(s)/
+                  /path2/to/header(s)/
+                   ...
+              </headers>
+
+              <libs>
+                  /path1/to/library(ies)/
+                  /path2/to/library(ies)/
+                   ...
+              </libs>
+
+                 ... (XML-descriptor template
+                         can be generated by -d option)
+             
+         2. ABI dump generated by -dump option
+         3. Directory with headers and/or $SLIB_TYPE libraries
+         4. Single header file
+         5. Single $SLIB_TYPE library
+         6. Comma separated list of headers and/or libraries
+
+      If you are using an 2-6 descriptor types then you should
+      specify version numbers with -v1 <num> and -v2 <num> options too.
+
+      For more information, please see:
+        http://ispras.linux-foundation.org/index.php/Library_Descriptor
+
+  -d2|-new|-n <path>
+      Descriptor of 2nd (new) library version.
+
+  -dump|-dump-abi <descriptor path(s)>
+      Dump library ABI to gzipped TXT format file. You can transfer it
+      anywhere and pass instead of the descriptor. Also it can be used
+      for debugging the tool. Compatible dump versions: ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION
+
+  -old-dumps
+      Enable support for old-version ABI dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0).\n";
+
+sub HELP_MESSAGE() {
+    printMsg("INFO", $HelpMessage."
+MORE INFO:
+     $CmdName --info\n");
+}
+
+sub INFO_MESSAGE()
+{
+    printMsg("INFO", "$HelpMessage
+EXTRA OPTIONS:
+  -d|-descriptor-template
+      Create XML-descriptor template ./VERSION.xml
+
+  -app|-application <path>
+      This option allows to specify the application that should be checked
+      for portability to the new library version.
+
+  -static-libs
+      Check static libraries instead of the shared ones. The <libs> section
+      of the XML-descriptor should point to static libraries location.
+
+  -cross-gcc <path>
+      Path to the cross GCC compiler to use instead of the usual (host) GCC.
+
+  -cross-prefix <prefix>
+      GCC toolchain prefix.
+
+  -sysroot <dirpath>
+      Specify the alternative root directory. The tool will search for include
+      paths in the <dirpath>/usr/include and <dirpath>/usr/lib directories.
+
+  -v1|-version1 <num>
+      Specify 1st library version outside the descriptor. This option is needed
+      if you have prefered an alternative descriptor type (see -d1 option).
+
+      In general case you should specify it in the XML-descriptor:
+          <version>
+              VERSION
+          </version>
+
+  -v2|-version2 <num>
+      Specify 2nd library version outside the descriptor.
+
+  -s|-strict
+      Treat all compatibility warnings as problems. Add a number of \"Low\"
+      severity problems to the return value of the tool.
+
+  -headers-only
+      Check header files without $SLIB_TYPE libraries. It is easy to run, but may
+      provide a low quality compatibility report with false positives and
+      without detecting of added/removed symbols.
+      
+      Alternatively you can write \"none\" word to the <libs> section
+      in the XML-descriptor:
+          <libs>
+              none
+          </libs>
+
+  -objects-only
+      Check $SLIB_TYPE libraries without header files. It is easy to run, but may
+      provide a low quality compatibility report with false positives and
+      without analysis of changes in parameters and data types.
+
+      Alternatively you can write \"none\" word to the <headers> section
+      in the XML-descriptor:
+          <headers>
+              none
+          </headers>
+
+  -check-impl|-check-implementation
+      Compare canonified disassembled binary code of $SLIB_TYPE libraries to
+      detect changes in the implementation. Add \'Problems with Implementation\'
+      section to the report.
+
+  -show-retval
+      Show the symbol's return type in the report.
+
+  -symbols-list <path>
+      This option allows to specify a file with a list of symbols (mangled
+      names in C++) that should be checked, other symbols will not be checked.
+
+  -skip-headers <path>
+      The file with the list of header files, that should not be checked.
+
+  -use-dumps
+      Make dumps for two versions of a library and compare dumps. This should
+      increase the performance of the tool and decrease the system memory usage.
+
+  -nostdinc
+      Do not search the GCC standard system directories for header files.
+
+  -dump-system <name> -sysroot <dirpath>
+      Find all the shared libraries and header files in <dirpath> directory,
+      create XML descriptors and make ABI dumps for each library. The result
+      set of ABI dumps can be compared (--cmp-systems) with the other one
+      created for other version of operating system in order to check them for
+      compatibility. Do not forget to specify -cross-gcc option if your target
+      system requires some specific version of GCC compiler (different from
+      the host GCC). The system ABI dump will be generated to:
+          sys_dumps/<name>/<arch>
+          
+  -dump-system <descriptor.xml>
+      The same as the previous option but takes an XML descriptor of the target
+      system as input, where you should describe it:
+          
+          /* Primary sections */
+          
+          <name>
+              /* Name of the system */
+          </name>
+          
+          <headers>
+              /* The list of paths to header files and/or
+                 directories with header files, one per line */
+          </headers>
+          
+          <libs>
+              /* The list of paths to shared libraries and/or
+                 directories with shared libraries, one per line */
+          </libs>
+          
+          /* Optional sections */
+          
+          <search_headers>
+              /* List of directories to be searched
+                 for header files to automatically
+                 generate include paths, one per line */
+          </search_headers>
+          
+          <search_libs>
+              /* List of directories to be searched
+                 for shared libraries to resolve
+                 dependencies, one per line */
+          </search_libs>
+          
+          <tools>
+              /* List of directories with tools used
+                 for analysis (GCC toolchain), one per line */
+          </tools>
+          
+          <cross_prefix>
+              /* GCC toolchain prefix.
+                 Examples:
+                     arm-linux-gnueabi
+                     arm-none-symbianelf */
+          </cross_prefix>
+          
+          <gcc_options>
+              /* Additional GCC options, one per line */
+          </gcc_options>
+
+  -sysinfo <dir>
+      This option may be used with -dump-system to dump ABI of operating
+      systems and configure the dumping process.
+      Default:
+          modules/Targets/{unix, symbian, windows}
+
+  -cmp-systems -d1 sys_dumps/<name1>/<arch> -d2 sys_dumps/<name2>/<arch>
+      Compare two system ABI dumps. Create compatibility reports for each
+      library and the common HTML report including the summary of test
+      results for all checked libraries. Report will be generated to:
+          sys_compat_reports/<name1>_to_<name2>/<arch>
+
+  -libs-list <path>
+      The file with a list of libraries, that should be dumped by
+      the -dump-system option or should be checked by the -cmp-systems option.
+
+  -header <name>
+      Check/Dump ABI of this header only.
+
+  -headers-list <path>
+      The file with a list of headers, that should be checked/dumped.
+
+  -ext|-extended
+      If your library A is supposed to be used by other library B and you
+      want to control the ABI of B, then you should enable this option. The
+      tool will check for changes in all data types, even if they are not
+      used by any function in the library A. Such data types are not part
+      of the A library ABI, but may be a part of the ABI of the B library.
+      
+      The short scheme is:
+        app C (broken) -> lib B (broken ABI) -> lib A (stable ABI)
+
+  -q|-quiet
+      Print all messages to the file instead of stdout and stderr.
+      Default path (can be changed by -log-path option):
+          $COMMON_LOG_PATH
+
+  -stdout
+      Print analysis results (compatibility reports and ABI dumps) to stdout
+      instead of creating a file. This would allow piping data to other programs.
+
+  -report-format <fmt>
+      Change format of compatibility report.
+      Formats:
+        htm - HTML format (default)
+        xml - XML format
+
+  -lang <lang>
+      Set library language (C or C++). You can use this option if the tool
+      cannot auto-detect a language. This option may be useful for checking
+      C-library headers (--lang=C) in --headers-only or --extended modes.
+
+OTHER OPTIONS:
+  -test
+      Run internal tests. Create two binary incompatible versions of a sample
+      library and run the tool to check them for compatibility. This option
+      allows to check if the tool works correctly in the current environment.
+
+  -test-dump
+      Test ability to create, read and compare ABI dumps.
+      
+  -debug
+      Debugging mode. Print debug info on the screen. Save intermediate
+      analysis stages in the debug directory:
+          debug/<library>/<version>/
+
+  -cpp-compatible
+      If your header file is written in C language and can be compiled by
+      the C++ compiler (i.e. doesn't contain C++-keywords and other bad
+      things), then you can tell ACC about this and speedup the analysis.
+
+  -p|-params <path>
+      Path to file with the function parameter names. It can be used
+      for improving report view if the library header files have no
+      parameter names. File format:
+      
+            func1;param1;param2;param3 ...
+            func2;param1;param2;param3 ...
+             ...
+
+  -relpath <path>
+      Replace {RELPATH} macros to <path> in the XML-descriptor used
+      for dumping the library ABI (see -dump option).
+  
+  -relpath1 <path>
+      Replace {RELPATH} macros to <path> in the 1st XML-descriptor (-d1).
+
+  -relpath2 <path>
+      Replace {RELPATH} macros to <path> in the 2nd XML-descriptor (-d2).
+
+  -dump-path <path>
+      Specify a file path (*.abi.$AR_EXT) where to generate an ABI dump.
+      Default: 
+          abi_dumps/<library>/<library>_<version>.abi.$AR_EXT
+
+  -report-path <path>
+      Compatibility report path.
+      Default: 
+          compat_reports/<library name>/<v1>_to_<v2>/abi_compat_report.html
+
+  -log-path <path>
+      Log path for all messages.
+      Default:
+          logs/<library>/<version>/log.txt
+
+  -log1-path <path>
+      Log path for 1st version of a library.
+      Default:
+          logs/<library name>/<v1>/log.txt
+
+  -log2-path <path>
+      Log path for 2nd version of a library.
+      Default:
+          logs/<library name>/<v2>/log.txt
+
+  -logging-mode <mode>
+      Change logging mode.
+      Modes:
+        w - overwrite old logs (default)
+        a - append old logs
+        n - do not write any logs
+
+  -list-affected
+      Generate file with the list of incompatible
+      symbols beside the HTML compatibility report.
+      Use 'c++filt \@file' command from GNU binutils
+      to unmangle C++ symbols in the generated file.
+      Default name:
+          abi_affected.txt
+
+  -component <name>
+      The component name in the title and summary of the HTML report.
+      Default:
+          library
+      
+  -l-full|-lib-full <name>
+      Change library name in the report title to <name>. By default
+      will be displayed a name specified by -l option.
+
+REPORT:
+    Compatibility report will be generated to:
+        compat_reports/<library name>/<v1>_to_<v2>/abi_compat_report.html
+
+    Log will be generated to:
+        logs/<library name>/<v1>/log.txt
+        logs/<library name>/<v2>/log.txt
+
+EXIT CODES:
+    0 - Compatible. The tool has run without any errors.
+    non-zero - Incompatible or the tool has run with errors.
+
+REPORT BUGS TO:
+    abi-compliance-checker\@linuxtesting.org
+    Andrey Ponomarenko <aponomarenko\@mandriva.org>
+
+MORE INFORMATION:
+    ".$HomePage{"Wiki"}."
+    ".$HomePage{"Dev"}."\n");
+}
+
+my $DescriptorTemplate = "
+<?xml version=\"1.0\" encoding=\"utf-8\"?>
+<descriptor>
+
+/* Primary sections */
+
+<version>
+    /* Version of the library */
+</version>
+
+<headers>
+    /* The list of paths to header files and/or
+       directories with header files, one per line */
+</headers>
+
+<libs>
+    /* The list of paths to shared libraries (*.$LIB_EXT) and/or
+       directories with shared libraries, one per line */
+</libs>
+
+/* Optional sections */
+
+<include_paths>
+    /* The list of include paths that will be provided
+       to GCC to compile library headers, one per line.
+       NOTE: If you define this section then the tool
+       will not automatically generate include paths */
+</include_paths>
+
+<add_include_paths>
+    /* The list of include paths that will be added
+       to the automatically generated include paths, one per line */
+</add_include_paths>
+
+<skip_include_paths>
+    /* The list of include paths that will be removed from the
+       list of automatically generated include paths, one per line */
+</skip_include_paths>
+
+<gcc_options>
+    /* Additional GCC options, one per line */
+</gcc_options>
+
+<include_preamble>
+    /* The list of header files that will be
+       included before other headers, one per line.
+       Examples:
+           1) tree.h for libxml2
+           2) ft2build.h for freetype2 */
+</include_preamble>
+
+<defines>
+    /* The list of defines that will be added at the
+       headers compiling stage, one per line:
+          #define A B
+          #define C D */
+</defines>
+
+<skip_types>
+    /* The list of data types, that
+       should not be checked, one per line */
+</skip_types>
+
+<skip_symbols>
+    /* The list of functions (mangled/symbol names in C++),
+       that should not be checked, one per line */
+</skip_symbols>
+
+<skip_namespaces>
+    /* The list of C++ namespaces, that
+       should not be checked, one per line */
+</skip_namespaces>
+
+<skip_constants>
+    /* The list of constants that should
+       not be checked, one name per line */
+</skip_constants>
+
+<skip_headers>
+    /* The list of header files and/or directories
+       with header files that should not be checked, one per line */
+</skip_headers>
+
+<skip_libs>
+    /* The list of shared libraries and/or directories
+       with shared libraries that should not be checked, one per line */
+</skip_libs>
+
+<skip_including>
+    /* The list of header files, that cannot be included
+       directly (or non-self compiled ones), one per line */
+</skip_including>
+
+<search_headers>
+    /* List of directories to be searched
+       for header files to automatically
+       generate include paths, one per line. */
+</search_headers>
+
+<search_libs>
+    /* List of directories to be searched
+       for shared librariess to resolve
+       dependencies, one per line */
+</search_libs>
+
+<tools>
+    /* List of directories with tools used
+       for analysis (GCC toolchain), one per line */
+</tools>
+
+<cross_prefix>
+    /* GCC toolchain prefix.
+       Examples:
+           arm-linux-gnueabi
+           arm-none-symbianelf */
+</cross_prefix>
+
+</descriptor>";
+
+my %Operator_Indication = (
+    "not" => "~",
+    "assign" => "=",
+    "andassign" => "&=",
+    "orassign" => "|=",
+    "xorassign" => "^=",
+    "or" => "|",
+    "xor" => "^",
+    "addr" => "&",
+    "and" => "&",
+    "lnot" => "!",
+    "eq" => "==",
+    "ne" => "!=",
+    "lt" => "<",
+    "lshift" => "<<",
+    "lshiftassign" => "<<=",
+    "rshiftassign" => ">>=",
+    "call" => "()",
+    "mod" => "%",
+    "modassign" => "%=",
+    "subs" => "[]",
+    "land" => "&&",
+    "lor" => "||",
+    "rshift" => ">>",
+    "ref" => "->",
+    "le" => "<=",
+    "deref" => "*",
+    "mult" => "*",
+    "preinc" => "++",
+    "delete" => " delete",
+    "vecnew" => " new[]",
+    "vecdelete" => " delete[]",
+    "predec" => "--",
+    "postinc" => "++",
+    "postdec" => "--",
+    "plusassign" => "+=",
+    "plus" => "+",
+    "minus" => "-",
+    "minusassign" => "-=",
+    "gt" => ">",
+    "ge" => ">=",
+    "new" => " new",
+    "multassign" => "*=",
+    "divassign" => "/=",
+    "div" => "/",
+    "neg" => "-",
+    "pos" => "+",
+    "memref" => "->*",
+    "compound" => "," );
+
+my %CppKeywords_C = map {$_=>1} (
+    # C++ 2003 keywords
+    "public",
+    "protected",
+    "private",
+    "default",
+    "template",
+    "new",
+    #"asm",
+    "dynamic_cast",
+    "auto",
+    "try",
+    "namespace",
+    "typename",
+    "using",
+    "reinterpret_cast",
+    "friend",
+    "class",
+    "virtual",
+    "const_cast",
+    "mutable",
+    "static_cast",
+    "export",
+    # C++0x keywords
+    "noexcept",
+    "nullptr",
+    "constexpr",
+    "static_assert",
+    "explicit",
+    # cannot be used as a macro name
+    # as it is an operator in C++
+    "and",
+    #"and_eq",
+    "not",
+    #"not_eq",
+    "or"
+    #"or_eq",
+    #"bitand",
+    #"bitor",
+    #"xor",
+    #"xor_eq",
+    #"compl"
+);
+
+my %CppKeywords_F = map {$_=>1} (
+    "delete",
+    "catch",
+    "alignof",
+    "thread_local",
+    "decltype",
+    "typeid"
+);
+
+my %CppKeywords_O = map {$_=>1} (
+    "bool",
+    "register",
+    "inline",
+    "operator"
+);
+
+my %CppKeywords_A = map {$_=>1} (
+    "this",
+    "throw"
+);
+
+foreach (keys(%CppKeywords_C),
+keys(%CppKeywords_F),
+keys(%CppKeywords_O)) {
+    $CppKeywords_A{$_}=1;
+}
+
+# Header file extensions as described by gcc
+my $HEADER_EXT = "h|hh|hp|hxx|hpp|h\\+\\+";
+
+my %IntrinsicMangling = (
+    "void" => "v",
+    "bool" => "b",
+    "wchar_t" => "w",
+    "char" => "c",
+    "signed char" => "a",
+    "unsigned char" => "h",
+    "short" => "s",
+    "unsigned short" => "t",
+    "int" => "i",
+    "unsigned int" => "j",
+    "long" => "l",
+    "unsigned long" => "m",
+    "long long" => "x",
+    "__int64" => "x",
+    "unsigned long long" => "y",
+    "__int128" => "n",
+    "unsigned __int128" => "o",
+    "float" => "f",
+    "double" => "d",
+    "long double" => "e",
+    "__float80" => "e",
+    "__float128" => "g",
+    "..." => "z"
+);
+
+my %StdcxxMangling = (
+    "3std"=>"St",
+    "3std9allocator"=>"Sa",
+    "3std12basic_string"=>"Sb",
+    "3std12basic_stringIcE"=>"Ss",
+    "3std13basic_istreamIcE"=>"Si",
+    "3std13basic_ostreamIcE"=>"So",
+    "3std14basic_iostreamIcE"=>"Sd"
+);
+
+my %ConstantSuffix = (
+    "unsigned int"=>"u",
+    "long"=>"l",
+    "unsigned long"=>"ul",
+    "long long"=>"ll",
+    "unsigned long long"=>"ull"
+);
+
+my %ConstantSuffixR =
+reverse(%ConstantSuffix);
+
+my %OperatorMangling = (
+    "~" => "co",
+    "=" => "aS",
+    "|" => "or",
+    "^" => "eo",
+    "&" => "an",#ad (addr)
+    "==" => "eq",
+    "!" => "nt",
+    "!=" => "ne",
+    "<" => "lt",
+    "<=" => "le",
+    "<<" => "ls",
+    "<<=" => "lS",
+    ">" => "gt",
+    ">=" => "ge",
+    ">>" => "rs",
+    ">>=" => "rS",
+    "()" => "cl",
+    "%" => "rm",
+    "[]" => "ix",
+    "&&" => "aa",
+    "||" => "oo",
+    "*" => "ml",#de (deref)
+    "++" => "pp",#
+    "--" => "mm",#
+    "new" => "nw",
+    "delete" => "dl",
+    "new[]" => "na",
+    "delete[]" => "da",
+    "+=" => "pL",
+    "+" => "pl",#ps (pos)
+    "-" => "mi",#ng (neg)
+    "-=" => "mI",
+    "*=" => "mL",
+    "/=" => "dV",
+    "&=" => "aN",
+    "|=" => "oR",
+    "%=" => "rM",
+    "^=" => "eO",
+    "/" => "dv",
+    "->*" => "pm",
+    "->" => "pt",#rf (ref)
+    "," => "cm",
+    "?" => "qu",
+    "." => "dt",
+    "sizeof"=> "sz"#st
+);
+
+my %GlibcHeader = map {$_=>1} (
+    "aliases.h",
+    "argp.h",
+    "argz.h",
+    "assert.h",
+    "cpio.h",
+    "ctype.h",
+    "dirent.h",
+    "envz.h",
+    "errno.h",
+    "error.h",
+    "execinfo.h",
+    "fcntl.h",
+    "fstab.h",
+    "ftw.h",
+    "glob.h",
+    "grp.h",
+    "iconv.h",
+    "ifaddrs.h",
+    "inttypes.h",
+    "langinfo.h",
+    "limits.h",
+    "link.h",
+    "locale.h",
+    "malloc.h",
+    "math.h",
+    "mntent.h",
+    "monetary.h",
+    "nl_types.h",
+    "obstack.h",
+    "printf.h",
+    "pwd.h",
+    "regex.h",
+    "sched.h",
+    "search.h",
+    "setjmp.h",
+    "shadow.h",
+    "signal.h",
+    "spawn.h",
+    "stdarg.h",
+    "stdint.h",
+    "stdio.h",
+    "stdlib.h",
+    "string.h",
+    "tar.h",
+    "termios.h",
+    "time.h",
+    "ulimit.h",
+    "unistd.h",
+    "utime.h",
+    "wchar.h",
+    "wctype.h",
+    "wordexp.h" );
+
+my %GlibcDir = map {$_=>1} (
+    "arpa",
+    "bits",
+    "gnu",
+    "netinet",
+    "net",
+    "nfs",
+    "rpc",
+    "sys",
+    "linux" );
+
+my %LocalIncludes = map {$_=>1} (
+    "/usr/local/include",
+    "/usr/local" );
+
+my %OS_AddPath=(
+# These paths are needed if the tool cannot detect them automatically
+    "macos"=>{
+        "include"=>{
+            "/Library"=>1,
+            "/Developer/usr/include"=>1
+        },
+        "lib"=>{
+            "/Library"=>1,
+            "/Developer/usr/lib"=>1
+        },
+        "bin"=>{
+            "/Developer/usr/bin"=>1
+        }
+    },
+    "beos"=>{
+    # Haiku has GCC 2.95.3 by default
+    # try to find GCC>=3.0 in /boot/develop/abi
+        "include"=>{
+            "/boot/common"=>1,
+            "/boot/develop"=>1},
+        "lib"=>{
+            "/boot/common/lib"=>1,
+            "/boot/system/lib"=>1,
+            "/boot/apps"=>1},
+        "bin"=>{
+            "/boot/common/bin"=>1,
+            "/boot/system/bin"=>1,
+            "/boot/develop/abi"=>1
+    }
+}
+);
+
+my %Slash_Type=(
+    "default"=>"/",
+    "windows"=>"\\"
+);
+
+my $SLASH = $Slash_Type{$OSgroup}?$Slash_Type{$OSgroup}:$Slash_Type{"default"};
+
+# Global Variables
+my %COMMON_LANGUAGE=(
+  1 => "C",
+  2 => "C" );
+
+my $MAX_COMMAND_LINE_ARGUMENTS = 4096;
+my (%WORD_SIZE, %CPU_ARCH, %GCC_VERSION);
+
+my %LIB_ARCH;
+
+my $STDCXX_TESTING = 0;
+my $GLIBC_TESTING = 0;
+
+my $CheckHeadersOnly = $CheckHeadersOnly_Opt;
+my $CheckObjectsOnly = $CheckObjectsOnly_Opt;
+my $TargetComponent = lc($TargetComponent_Opt);
+if(not $TargetComponent)
+{ # default: library
+  # other components: header, system, ...
+    $TargetComponent = "library";
+}
+
+my $SystemRoot;
+
+my $MAIN_CPP_DIR;
+my %RESULT=(
+    "Problems"=>0,
+    "Warnings"=>0,
+    "Affected"=>0
+);
+my %LOG_PATH;
+my %DEBUG_PATH;
+my %Cache;
+my %LibInfo;
+my $COMPILE_ERRORS = 0;
+my %CompilerOptions;
+my %CheckedDyLib;
+my $TargetLibraryShortName = parse_libname($TargetLibraryName, "shortest", $OSgroup);
+
+# Constants (#defines)
+my %Constants;
+my %SkipConstants;
+
+# Types
+my %TypeInfo;
+my %TemplateInstance_Func;
+my %TemplateInstance;
+my %SkipTypes = (
+  "1"=>{},
+  "2"=>{} );
+my %Tid_TDid = (
+  "1"=>{},
+  "2"=>{} );
+my %CheckedTypes;
+my %TName_Tid;
+my %EnumMembName_Id;
+my %NestedNameSpaces = (
+  "1"=>{},
+  "2"=>{} );
+my %UsedType;
+my %VirtualTable;
+my %VirtualTable_Full;
+my %ClassVTable;
+my %ClassVTable_Content;
+my %VTableClass;
+my %AllocableClass;
+my %ClassMethods;
+my %ClassToId;
+my %Class_SubClasses;
+my %OverriddenMethods;
+my $MAX_TID;
+
+# Typedefs
+my %Typedef_BaseName;
+my %Typedef_Tr;
+my %Typedef_Eq;
+my %StdCxxTypedef;
+my %MissedTypedef;
+
+# Symbols
+my %SymbolInfo;
+my %tr_name;
+my %mangled_name_gcc;
+my %mangled_name;
+my %SkipSymbols = (
+  "1"=>{},
+  "2"=>{} );
+my %SkipNameSpaces = (
+  "1"=>{},
+  "2"=>{} );
+my %SymbolsList;
+my %SymbolsList_App;
+my %CheckedSymbols;
+my %GeneratedSymbols;
+my %DepSymbols = (
+  "1"=>{},
+  "2"=>{} );
+my %MangledNames;
+my %AddIntParams;
+my %Interface_Impl;
+
+# Headers
+my %Include_Preamble;
+my %Registered_Headers;
+my %HeaderName_Paths;
+my %Header_Dependency;
+my %Include_Neighbors;
+my %Include_Paths;
+my %INC_PATH_AUTODETECT = (
+  "1"=>1,
+  "2"=>1 );
+my %Add_Include_Paths;
+my %Skip_Include_Paths;
+my %RegisteredDirs;
+my %RegisteredDeps;
+my %Header_ErrorRedirect;
+my %Header_Includes;
+my %Header_ShouldNotBeUsed;
+my %RecursiveIncludes;
+my %Header_Include_Prefix;
+my %SkipHeaders;
+my %SkipHeadersList=(
+  "1"=>{},
+  "2"=>{} );
+my %SkipLibs;
+my %Include_Order;
+my %TUnit_NameSpaces;
+
+my %C99Mode = (
+  "1"=>0,
+  "2"=>0 );
+my %AutoPreambleMode = (
+  "1"=>0,
+  "2"=>0 );
+my %MinGWMode = (
+  "1"=>0,
+  "2"=>0 );
+
+# Shared Objects
+my %DyLib_DefaultPath;
+my %InputObject_Paths;
+my %RegisteredObjDirs;
+
+# System Objects
+my %SystemObjects;
+my %DefaultLibPaths;
+
+# System Headers
+my %SystemHeaders;
+my %DefaultCppPaths;
+my %DefaultGccPaths;
+my %DefaultIncPaths;
+my %DefaultCppHeader;
+my %DefaultGccHeader;
+my %UserIncPath;
+
+# Merging
+my %CompleteSignature;
+my %Symbol_Library;
+my %Library_Symbol = (
+  "1"=>{},
+  "2"=>{} );
+my $Version;
+my %AddedInt;
+my %RemovedInt;
+my %AddedInt_Virt;
+my %RemovedInt_Virt;
+my %VirtualReplacement;
+my %ChangedTypedef;
+my %CompatRules;
+my %IncompleteRules;
+my %UnknownRules;
+my %VTableChanged;
+my %ExtendedFuncs;
+my %ReturnedClass;
+my %ParamClass;
+
+# OS Compliance
+my %TargetLibs;
+my %TargetHeaders;
+
+# OS Specifics
+my $OStarget = $OSgroup;
+my %TargetTools;
+
+# Compliance Report
+my %Type_MaxPriority;
+
+# Recursion locks
+my @RecurLib;
+my @RecurSymlink;
+my @RecurTypes;
+my @RecurInclude;
+my @RecurConstant;
+
+# System
+my %SystemPaths;
+my %DefaultBinPaths;
+my $GCC_PATH;
+
+# Symbols versioning
+my %SymVer = (
+  "1"=>{},
+  "2"=>{} );
+
+# Problem descriptions
+my %CompatProblems;
+my %ProblemsWithConstants;
+my %ImplProblems;
+my %TotalAffected;
+
+# Rerorts
+my $ContentID = 1;
+my $ContentSpanStart = "<span class=\"section\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
+my $ContentSpanStart_Affected = "<span class=\"section_affected\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
+my $ContentSpanStart_Info = "<span class=\"section_info\" onclick=\"javascript:showContent(this, 'CONTENT_ID')\">\n";
+my $ContentSpanEnd = "</span>\n";
+my $ContentDivStart = "<div id=\"CONTENT_ID\" style=\"display:none;\">\n";
+my $ContentDivEnd = "</div>\n";
+my $Content_Counter = 0;
+
+my $JScripts = "
+<script type=\"text/javascript\" language=\"JavaScript\">
+<!--
+function showContent(header, id)   {
+    e = document.getElementById(id);
+    if(e.style.display == 'none')
+    {
+        e.style.display = 'block';
+        e.style.visibility = 'visible';
+        header.innerHTML = header.innerHTML.replace(/\\\[[^0-9 ]\\\]/gi,\"[&minus;]\");
+    }
+    else
+    {
+        e.style.display = 'none';
+        e.style.visibility = 'hidden';
+        header.innerHTML = header.innerHTML.replace(/\\\[[^0-9 ]\\\]/gi,\"[+]\");
+    }
+}
+-->
+</script>";
+
+sub get_Modules()
+{
+    my $TOOL_DIR = get_dirname($0);
+    if(not $TOOL_DIR)
+    { # patch for MS Windows
+        $TOOL_DIR = ".";
+    }
+    my @SEARCH_DIRS = (
+        # tool's directory
+        abs_path($TOOL_DIR),
+        # relative path to modules
+        abs_path($TOOL_DIR)."/../share/abi-compliance-checker",
+        # system directory
+        "ACC_MODULES_INSTALL_PATH"
+    );
+    foreach my $DIR (@SEARCH_DIRS)
+    {
+        if(not is_abs($DIR))
+        { # relative path
+            $DIR = abs_path($TOOL_DIR)."/".$DIR;
+        }
+        if(-d $DIR."/modules") {
+            return $DIR."/modules";
+        }
+    }
+    exitStatus("Module_Error", "can't find modules");
+}
+
+sub loadModule($)
+{
+    my $Name = $_[0];
+    my $Path = $MODULES_DIR."/Internals/$Name.pm";
+    if(not -f $Path) {
+        exitStatus("Module_Error", "can't access \'$Path\'");
+    }
+    require $Path;
+}
+
+sub numToStr($)
+{
+    my $Number = int($_[0]);
+    if($Number>3) {
+        return $Number."th";
+    }
+    elsif($Number==1) {
+        return "1st";
+    }
+    elsif($Number==2) {
+        return "2nd";
+    }
+    elsif($Number==3) {
+        return "3rd";
+    }
+    else {
+        return $Number;
+    }
+}
+
+sub search_Tools($)
+{
+    my $Name = $_[0];
+    return "" if(not $Name);
+    if(my @Paths = keys(%TargetTools))
+    {
+        foreach my $Path (@Paths)
+        {
+            if(-f joinPath($Path, $Name)) {
+                return joinPath($Path, $Name);
+            }
+            if($CrossPrefix)
+            { # user-defined prefix (arm-none-symbianelf, ...)
+                my $Candidate = joinPath($Path, $CrossPrefix."-".$Name);
+                if(-f $Candidate) {
+                    return $Candidate;
+                }
+            }
+        }
+    }
+    else {
+        return "";
+    }
+}
+
+sub synch_Cmd($)
+{
+    my $Name = $_[0];
+    if(not $GCC_PATH)
+    { # GCC was not found yet
+        return "";
+    }
+    my $Candidate = $GCC_PATH;
+    if($Candidate=~s/(\W|\A)gcc(|\.\w+)\Z/$1$Name$2/) {
+        return $Candidate;
+    }
+    return "";
+}
+
+sub get_CmdPath($)
+{
+    my $Name = $_[0];
+    return "" if(not $Name);
+    if(defined $Cache{"get_CmdPath"}{$Name}) {
+        return $Cache{"get_CmdPath"}{$Name};
+    }
+    my %BinUtils = map {$_=>1} (
+        "c++filt",
+        "objdump",
+        "readelf"
+    );
+    if($BinUtils{$Name}) {
+        if(my $Dir = get_dirname($GCC_PATH)) {
+            $TargetTools{$Dir}=1;
+        }
+    }
+    my $Path = search_Tools($Name);
+    if(not $Path and $OSgroup eq "windows") {
+        $Path = search_Tools($Name.".exe");
+    }
+    if(not $Path and $BinUtils{$Name})
+    {
+        if($CrossPrefix)
+        { # user-defined prefix
+            $Path = search_Cmd($CrossPrefix."-".$Name);
+        }
+    }
+    if(not $Path and $BinUtils{$Name})
+    {
+        if(my $Candidate = synch_Cmd($Name))
+        { # synch with GCC
+            if($Candidate=~/[\/\\]/)
+            {# command path
+                if(-f $Candidate) {
+                    $Path = $Candidate;
+                }
+            }
+            elsif($Candidate = search_Cmd($Candidate))
+            {# command name
+                $Path = $Candidate;
+            }
+        }
+    }
+    if(not $Path) {
+        $Path = search_Cmd($Name);
+    }
+    if(not $Path and $OSgroup eq "windows")
+    {# search for *.exe file
+        $Path=search_Cmd($Name.".exe");
+    }
+    if($Path=~/\s/) {
+        $Path = "\"".$Path."\"";
+    }
+    return ($Cache{"get_CmdPath"}{$Name}=$Path);
+}
+
+sub search_Cmd($)
+{
+    my $Name = $_[0];
+    return "" if(not $Name);
+    if(defined $Cache{"search_Cmd"}{$Name}) {
+        return $Cache{"search_Cmd"}{$Name};
+    }
+    if(my $DefaultPath = get_CmdPath_Default($Name)) {
+        return ($Cache{"search_Cmd"}{$Name} = $DefaultPath);
+    }
+    foreach my $Path (sort {length($a)<=>length($b)} keys(%{$SystemPaths{"bin"}}))
+    {
+        my $CmdPath = joinPath($Path,$Name);
+        if(-f $CmdPath)
+        {
+            if($Name=~/gcc/) {
+                next if(not check_gcc_version($CmdPath, "3"));
+            }
+            return ($Cache{"search_Cmd"}{$Name} = $CmdPath);
+        }
+    }
+    return ($Cache{"search_Cmd"}{$Name} = "");
+}
+
+sub get_CmdPath_Default($)
+{ # search in PATH
+    my $Name = $_[0];
+    return "" if(not $Name);
+    if(defined $Cache{"get_CmdPath_Default"}{$Name}) {
+        return $Cache{"get_CmdPath_Default"}{$Name};
+    }
+    if($Name=~/find/)
+    { # special case: search for "find" utility
+        if(`find . -maxdepth 0 2>$TMP_DIR/null`) {
+            return ($Cache{"get_CmdPath_Default"}{$Name} = "find");
+        }
+    }
+    elsif($Name=~/gcc/) {
+        return check_gcc_version($Name, "3");
+    }
+    if(check_command($Name)) {
+        return ($Cache{"get_CmdPath_Default"}{$Name} = $Name);
+    }
+    if($OSgroup eq "windows"
+    and `$Name /? 2>$TMP_DIR/null`) {
+        return ($Cache{"get_CmdPath_Default"}{$Name} = $Name);
+    }
+    if($Name!~/which/)
+    {
+        my $WhichCmd = get_CmdPath("which");
+        if($WhichCmd and `$WhichCmd $Name 2>$TMP_DIR/null`) {
+            return ($Cache{"get_CmdPath_Default"}{$Name} = $Name);
+        }
+    }
+    foreach my $Path (sort {length($a)<=>length($b)} keys(%DefaultBinPaths))
+    {
+        if(-f $Path."/".$Name) {
+            return ($Cache{"get_CmdPath_Default"}{$Name} = joinPath($Path,$Name));
+        }
+    }
+    return ($Cache{"get_CmdPath_Default"}{$Name} = "");
+}
+
+sub clean_path($)
+{
+    my $Path = $_[0];
+    $Path=~s/[\/\\]+\Z//g;
+    return $Path;
+}
+
+sub classifyPath($)
+{
+    my $Path = $_[0];
+    if($Path=~/[\*\[]/)
+    { # wildcard
+        $Path=~s/\*/.*/g;
+        $Path=~s/\\/\\\\/g;
+        return ($Path, "Pattern");
+    }
+    elsif($Path=~/[\/\\]/)
+    { # directory or relative path
+        return (path_format($Path, $OSgroup), "Path");
+    }
+    else {
+        return ($Path, "Name");
+    }
+}
+
+sub readDescriptor($$)
+{
+    my ($LibVersion, $Content) = @_;
+    return if(not $LibVersion);
+    my $DName = $DumpAPI?"descriptor":"descriptor \"d$LibVersion\"";
+    if(not $Content) {
+        exitStatus("Error", "$DName is empty");
+    }
+    if($Content!~/\</) {
+        exitStatus("Error", "$DName is not a descriptor (see -d1 option)");
+    }
+    $Content=~s/\/\*(.|\n)+?\*\///g;
+    $Content=~s/<\!--(.|\n)+?-->//g;
+    $Descriptor{$LibVersion}{"Version"} = parseTag(\$Content, "version");
+    if($TargetVersion{$LibVersion}) {
+        $Descriptor{$LibVersion}{"Version"} = $TargetVersion{$LibVersion};
+    }
+    if(not $Descriptor{$LibVersion}{"Version"}) {
+        exitStatus("Error", "version in the $DName is not specified (<version> section)");
+    }
+    if($Content=~/{RELPATH}/)
+    {
+        if(my $RelDir = $RelativeDirectory{$LibVersion}) {
+            $Content =~ s/{RELPATH}/$RelDir/g;
+        }
+        else
+        {
+            my $NeedRelpath = $DumpAPI?"-relpath":"-relpath$LibVersion";
+            exitStatus("Error", "you have not specified $NeedRelpath option, but the $DName contains {RELPATH} macro");
+        }
+    }
+    
+    if(not $CheckObjectsOnly_Opt)
+    {
+        my $DHeaders = parseTag(\$Content, "headers");
+        if(not $DHeaders) {
+            exitStatus("Error", "header files in the $DName are not specified (<headers> section)");
+        }
+        elsif(lc($DHeaders) ne "none")
+        { # append the descriptor headers list
+            if($Descriptor{$LibVersion}{"Headers"})
+            { # multiple descriptors
+                $Descriptor{$LibVersion}{"Headers"} .= "\n".$DHeaders;
+            }
+            else {
+                $Descriptor{$LibVersion}{"Headers"} = $DHeaders;
+            }
+            foreach my $Path (split(/\s*\n\s*/, $DHeaders))
+            {
+                if(not -e $Path) {
+                    exitStatus("Access_Error", "can't access \'$Path\'");
+                }
+            }
+        }
+    }
+    if(not $CheckHeadersOnly_Opt)
+    {
+        my $DObjects = parseTag(\$Content, "libs");
+        if(not $DObjects) {
+            exitStatus("Error", "$SLIB_TYPE libraries in the $DName are not specified (<libs> section)");
+        }
+        elsif(lc($DObjects) ne "none")
+        { # append the descriptor libraries list
+            if($Descriptor{$LibVersion}{"Libs"})
+            { # multiple descriptors
+                $Descriptor{$LibVersion}{"Libs"} .= "\n".$DObjects;
+            }
+            else {
+                $Descriptor{$LibVersion}{"Libs"} .= $DObjects;
+            }
+            foreach my $Path (split(/\s*\n\s*/, $DObjects))
+            {
+                if(not -e $Path) {
+                    exitStatus("Access_Error", "can't access \'$Path\'");
+                }
+            }
+        }
+    }
+    foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_headers")))
+    {
+        $Path = clean_path($Path);
+        if(not -d $Path) {
+            exitStatus("Access_Error", "can't access directory \'$Path\'");
+        }
+        $Path = path_format($Path, $OSgroup);
+        $SystemPaths{"include"}{$Path}=1;
+    }
+    foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "search_libs")))
+    {
+        $Path = clean_path($Path);
+        if(not -d $Path) {
+            exitStatus("Access_Error", "can't access directory \'$Path\'");
+        }
+        $Path = path_format($Path, $OSgroup);
+        $SystemPaths{"lib"}{$Path}=1;
+    }
+    foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "tools")))
+    {
+        $Path=clean_path($Path);
+        if(not -d $Path) {
+            exitStatus("Access_Error", "can't access directory \'$Path\'");
+        }
+        $Path = path_format($Path, $OSgroup);
+        $SystemPaths{"bin"}{$Path}=1;
+        $TargetTools{$Path}=1;
+    }
+    if(my $Prefix = parseTag(\$Content, "cross_prefix")) {
+        $CrossPrefix = $Prefix;
+    }
+    foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "include_paths")))
+    {
+        $Path=clean_path($Path);
+        if(not -d $Path) {
+            exitStatus("Access_Error", "can't access directory \'$Path\'");
+        }
+        $Path = path_format($Path, $OSgroup);
+        $Descriptor{$LibVersion}{"IncludePaths"}{$Path} = 1;
+    }
+    foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "add_include_paths")))
+    {
+        $Path=clean_path($Path);
+        if(not -d $Path) {
+            exitStatus("Access_Error", "can't access directory \'$Path\'");
+        }
+        $Path = path_format($Path, $OSgroup);
+        $Descriptor{$LibVersion}{"AddIncludePaths"}{$Path} = 1;
+    }
+    foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_include_paths")))
+    {
+        # skip some auto-generated include paths
+        $Skip_Include_Paths{$LibVersion}{path_format($Path)}=1;
+    }
+    foreach my $Path (split(/\s*\n\s*/, parseTag(\$Content, "skip_including")))
+    {
+        # skip direct including of some headers
+        my ($CPath, $Type) = classifyPath($Path);
+        $SkipHeaders{$LibVersion}{$Type}{$CPath} = 2;
+        $SkipHeadersList{$LibVersion}{$Path} = 2;
+    }
+    $Descriptor{$LibVersion}{"GccOptions"} = parseTag(\$Content, "gcc_options");
+    foreach my $Option (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"GccOptions"})) {
+        $CompilerOptions{$LibVersion} .= " ".$Option;
+    }
+    $Descriptor{$LibVersion}{"SkipHeaders"} = parseTag(\$Content, "skip_headers");
+    foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipHeaders"}))
+    {
+        my ($CPath, $Type) = classifyPath($Path);
+        $SkipHeaders{$LibVersion}{$Type}{$CPath} = 1;
+        $SkipHeadersList{$LibVersion}{$Path} = 1;
+    }
+    $Descriptor{$LibVersion}{"SkipLibs"} = parseTag(\$Content, "skip_libs");
+    foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"SkipLibs"}))
+    {
+        my ($CPath, $Type) = classifyPath($Path);
+        $SkipLibs{$LibVersion}{$Type}{$CPath} = 1;
+    }
+    if(my $DDefines = parseTag(\$Content, "defines"))
+    {
+        if($Descriptor{$LibVersion}{"Defines"})
+        { # multiple descriptors
+            $Descriptor{$LibVersion}{"Defines"} .= "\n".$DDefines;
+        }
+        else {
+            $Descriptor{$LibVersion}{"Defines"} = $DDefines;
+        }
+    }
+    foreach my $Order (split(/\s*\n\s*/, parseTag(\$Content, "include_order")))
+    {
+        if($Order=~/\A(.+):(.+)\Z/) {
+            $Include_Order{$LibVersion}{$1} = $2;
+        }
+    }
+    foreach my $Type_Name (split(/\s*\n\s*/, parseTag(\$Content, "opaque_types")),
+    split(/\s*\n\s*/, parseTag(\$Content, "skip_types")))
+    {# opaque_types renamed to skip_types (1.23.4)
+        $SkipTypes{$LibVersion}{$Type_Name} = 1;
+    }
+    foreach my $Symbol (split(/\s*\n\s*/, parseTag(\$Content, "skip_interfaces")),
+    split(/\s*\n\s*/, parseTag(\$Content, "skip_symbols")))
+    {# skip_interfaces renamed to skip_symbols (1.22.1)
+        $SkipSymbols{$LibVersion}{$Symbol} = 1;
+    }
+    foreach my $NameSpace (split(/\s*\n\s*/, parseTag(\$Content, "skip_namespaces"))) {
+        $SkipNameSpaces{$LibVersion}{$NameSpace} = 1;
+    }
+    foreach my $Constant (split(/\s*\n\s*/, parseTag(\$Content, "skip_constants"))) {
+        $SkipConstants{$LibVersion}{$Constant} = 1;
+    }
+    if(my $DIncPreamble = parseTag(\$Content, "include_preamble"))
+    {
+        if($Descriptor{$LibVersion}{"IncludePreamble"})
+        {# multiple descriptors
+            $Descriptor{$LibVersion}{"IncludePreamble"} .= "\n".$DIncPreamble;
+        }
+        else {
+            $Descriptor{$LibVersion}{"IncludePreamble"} = $DIncPreamble;
+        }
+    }
+}
+
+sub parseTag($$)
+{
+    my ($CodeRef, $Tag) = @_;
+    return "" if(not $CodeRef or not ${$CodeRef} or not $Tag);
+    if(${$CodeRef}=~s/\<\Q$Tag\E\>((.|\n)+?)\<\/\Q$Tag\E\>//)
+    {
+        my $Content = $1;
+        $Content=~s/(\A\s+|\s+\Z)//g;
+        return $Content;
+    }
+    else {
+        return "";
+    }
+}
+
+my %check_node= map {$_=>1} (
+  "array_type",
+  "binfo",
+  "boolean_type",
+  "complex_type",
+  "const_decl",
+  "enumeral_type",
+  "field_decl",
+  "function_decl",
+  "function_type",
+  "identifier_node",
+  "integer_cst",
+  "integer_type",
+  "method_type",
+  "namespace_decl",
+  "parm_decl",
+  "pointer_type",
+  "real_cst",
+  "real_type",
+  "record_type",
+  "reference_type",
+  "string_cst",
+  "template_decl",
+  "template_type_parm",
+  "tree_list",
+  "tree_vec",
+  "type_decl",
+  "union_type",
+  "var_decl",
+  "void_type",
+  "offset_type" );
+
+sub getInfo($)
+{
+    my $InfoPath = $_[0];
+    return if(not $InfoPath or not -f $InfoPath);
+    my $Content = readFile($InfoPath);
+    unlink($InfoPath);
+    $Content=~s/\n[ ]+/ /g;
+    my @Lines = split("\n", $Content);
+    $Content="";# clear
+    foreach (@Lines)
+    {
+        if(/\A\@(\d+)\s+([a-z_]+)\s+(.+)\Z/oi)
+        { # get a number and attributes of a node
+            next if(not $check_node{$2});
+            $LibInfo{$Version}{"info_type"}{$1}=$2;
+            $LibInfo{$Version}{"info"}{$1}=$3;
+        }
+    }
+    $MAX_TID = $#Lines+1;
+    @Lines=();# clear
+    # processing info
+    setTemplateParams_All();
+    getTypeInfo_All();
+    simplifyNames();
+    getSymbolInfo_All();
+    getVarInfo_All();
+    
+    # cleaning memory
+    %LibInfo = ();
+    %TemplateInstance = ();
+    %TemplateInstance_Func = ();
+    %MangledNames = ();
+
+    if($Debug) {
+        # debugMangling($Version);
+    }
+}
+
+sub simplifyNames()
+{
+    foreach my $Base (keys(%{$Typedef_Tr{$Version}}))
+    {
+        my @Translations = keys(%{$Typedef_Tr{$Version}{$Base}});
+        if($#Translations==0 and length($Translations[0])<=length($Base)) {
+            $Typedef_Eq{$Version}{$Base} = $Translations[0];
+        }
+    }
+    foreach my $TDid (keys(%{$TypeInfo{$Version}}))
+    {
+        foreach my $Tid (keys(%{$TypeInfo{$Version}{$TDid}}))
+        {
+            my $TypeName = $TypeInfo{$Version}{$TDid}{$Tid}{"Name"};
+            if(not $TypeName) {
+                next;
+            }
+            next if(index($TypeName,"<")==-1);# template instances only
+            if($TypeName=~/>(::\w+)+\Z/)
+            { # skip unused types
+                next;
+            };
+            foreach my $Base (sort {length($b)<=>length($a)}
+            sort {$b cmp $a} keys(%{$Typedef_Eq{$Version}}))
+            {
+                next if(not $Base);
+                next if(index($TypeName,$Base)==-1);
+                next if(length($TypeName) - length($Base) <= 3);
+                my $Typedef = $Typedef_Eq{$Version}{$Base};
+                $TypeName=~s/(\<|\,)\Q$Base\E(\W|\Z)/$1$Typedef$2/g;
+                $TypeName=~s/(\<|\,)\Q$Base\E(\w|\Z)/$1$Typedef $2/g;
+            }
+            if($TypeName ne $TypeInfo{$Version}{$TDid}{$Tid}{"Name"})
+            {
+                $TypeInfo{$Version}{$TDid}{$Tid}{"Name"} = formatName($TypeName);
+                $TName_Tid{$Version}{$TypeName} = $Tid;
+            }
+        }
+    }
+}
+
+sub setTemplateParams_All()
+{
+    foreach (keys(%{$LibInfo{$Version}{"info"}}))
+    {
+        if($LibInfo{$Version}{"info_type"}{$_} eq "template_decl") {
+            setTemplateParams($_);
+        }
+    }
+}
+
+sub setTemplateParams($)
+{
+    my $TypeInfoId = $_[0];
+    if($LibInfo{$Version}{"info"}{$TypeInfoId}=~/(inst|spcs)[ ]*:[ ]*@(\d+) /)
+    {
+        my $TmplInst_InfoId = $2;
+        setTemplateInstParams($TmplInst_InfoId);
+        my $TmplInst_Info = $LibInfo{$Version}{"info"}{$TmplInst_InfoId};
+        while($TmplInst_Info=~/(chan|chain)[ ]*:[ ]*@(\d+) /)
+        {
+            $TmplInst_InfoId = $2;
+            $TmplInst_Info = $LibInfo{$Version}{"info"}{$TmplInst_InfoId};
+            setTemplateInstParams($TmplInst_InfoId);
+        }
+    }
+}
+
+sub setTemplateInstParams($)
+{
+    my $TmplInst_Id = $_[0];
+    my $Info = $LibInfo{$Version}{"info"}{$TmplInst_Id};
+    my ($Params_InfoId, $ElemId) = ();
+    if($Info=~/purp[ ]*:[ ]*@(\d+) /) {
+        $Params_InfoId = $1;
+    }
+    if($Info=~/valu[ ]*:[ ]*@(\d+) /) {
+        $ElemId = $1;
+    }
+    if($Params_InfoId and $ElemId)
+    {
+        my $Params_Info = $LibInfo{$Version}{"info"}{$Params_InfoId};
+        while($Params_Info=~s/ (\d+)[ ]*:[ ]*\@(\d+) / /)
+        {
+            my ($Param_Pos, $Param_TypeId) = ($1, $2);
+            return if($LibInfo{$Version}{"info_type"}{$Param_TypeId} eq "template_type_parm");
+            if($LibInfo{$Version}{"info_type"}{$ElemId} eq "function_decl") {
+                $TemplateInstance_Func{$Version}{$ElemId}{$Param_Pos} = $Param_TypeId;
+            }
+            else {
+                $TemplateInstance{$Version}{getTypeDeclId($ElemId)}{$ElemId}{$Param_Pos} = $Param_TypeId;
+            }
+        }
+    }
+}
+
+sub getTypeDeclId($)
+{
+    if($LibInfo{$Version}{"info"}{$_[0]}=~/name[ ]*:[ ]*@(\d+)/) {
+        return $1;
+    }
+    else {
+        return "";
+    }
+}
+
+sub isFuncPtr($)
+{
+    my $Ptd = pointTo($_[0]);
+    return 0 if(not $Ptd);
+    if($LibInfo{$Version}{"info"}{$_[0]}=~/unql[ ]*:/
+    and $LibInfo{$Version}{"info"}{$_[0]}!~/qual[ ]*:/) {
+        return 0;
+    }
+    elsif($LibInfo{$Version}{"info_type"}{$_[0]} eq "pointer_type"
+    and $LibInfo{$Version}{"info_type"}{$Ptd} eq "function_type") {
+        return 1;
+    }
+    return 0;
+}
+
+sub isMethodPtr($)
+{
+    my $Ptd = pointTo($_[0]);
+    return 0 if(not $Ptd);
+    if($LibInfo{$Version}{"info_type"}{$_[0]} eq "record_type"
+    and $LibInfo{$Version}{"info_type"}{$Ptd} eq "method_type"
+    and $LibInfo{$Version}{"info"}{$_[0]}=~/ ptrmem /) {
+        return 1;
+    }
+    return 0;
+}
+
+sub isFieldPtr($)
+{
+    if($LibInfo{$Version}{"info_type"}{$_[0]} eq "offset_type"
+    and $LibInfo{$Version}{"info"}{$_[0]}=~/ ptrmem /) {
+        return 1;
+    }
+    return 0;
+}
+
+sub pointTo($)
+{
+    if($LibInfo{$Version}{"info"}{$_[0]}=~/ptd[ ]*:[ ]*@(\d+)/) {
+        return $1;
+    }
+    else {
+        return "";
+    }
+}
+
+sub getTypeInfo_All()
+{
+    if(not check_gcc_version($GCC_PATH, "4.5"))
+    { # support for GCC < 4.5
+      # missed typedefs: QStyle::State is typedef to QFlags<QStyle::StateFlag>
+      # but QStyleOption.state is of type QFlags<QStyle::StateFlag> in the TU dump
+      # FIXME: check GCC versions
+        addMissedTypes_Pre();
+    }
+    foreach (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
+    {
+        my $IType = $LibInfo{$Version}{"info_type"}{$_};
+        if($IType=~/_type\Z/ and $IType ne "function_type"
+        and $IType ne "method_type") {
+            getTypeInfo(getTypeDeclId("$_"), "$_");
+        }
+    }
+    $TypeInfo{$Version}{""}{-1}{"Name"} = "...";
+    $TypeInfo{$Version}{""}{-1}{"Type"} = "Intrinsic";
+    $TypeInfo{$Version}{""}{-1}{"Tid"} = -1;
+    if(not check_gcc_version($GCC_PATH, "4.5"))
+    { # support for GCC < 4.5
+        addMissedTypes_Post();
+    }
+}
+
+sub addMissedTypes_Pre()
+{
+    foreach my $MissedTDid (sort {int($a)<=>int($b)} keys(%{$LibInfo{$Version}{"info"}}))
+    { # detecting missed typedefs
+        if($LibInfo{$Version}{"info_type"}{$MissedTDid} eq "type_decl")
+        {
+            my $TypeId = getTreeAttr($MissedTDid, "type");
+            next if(not $TypeId);
+            my $TypeType = getTypeType($MissedTDid, $TypeId);
+            if($TypeType eq "Unknown")
+            { # template_type_parm
+                next;
+            }
+            my $TypeDeclId = getTypeDeclId($TypeId);
+            next if($TypeDeclId eq $MissedTDid);#or not $TypeDeclId
+            my $TypedefName = getNameByInfo($MissedTDid);
+            next if(not $TypedefName);
+            next if($TypedefName eq "__float80");
+            next if(isAnon($TypedefName));
+            if(not $TypeDeclId
+            or getNameByInfo($TypeDeclId) ne $TypedefName) {
+                $MissedTypedef{$Version}{$TypeId}{"$MissedTDid"} = 1;
+            }
+        }
+    }
+    foreach my $Tid (keys(%{$MissedTypedef{$Version}}))
+    { # add missed typedefs
+        my @Missed = keys(%{$MissedTypedef{$Version}{$Tid}});
+        if(not @Missed or $#Missed>=1) {
+            delete($MissedTypedef{$Version}{$Tid});
+            next;
+        }
+        my $MissedTDid = $Missed[0];
+        my $TDid = getTypeDeclId($Tid);
+        my ($TypedefName, $TypedefNS) = getTrivialName($MissedTDid, $Tid);
+        my %MissedInfo = ( # typedef info
+            "Name" => $TypedefName,
+            "NameSpace" => $TypedefNS,
+            "BaseType" => {
+                            "TDid" => $TDid,
+                            "Tid" => $Tid
+                          },
+            "Type" => "Typedef",
+            "Tid" => ++$MAX_TID,
+            "TDid" => $MissedTDid );
+        my ($H, $L) = getLocation($MissedTDid);
+        $MissedInfo{"Header"} = $H;
+        $MissedInfo{"Line"} = $L;
+        # $MissedInfo{"Size"} = getSize($Tid)/$BYTE_SIZE;
+        my $MName = $MissedInfo{"Name"};
+        next if(not $MName);
+        if($MName=~/\*|\&|\s/)
+        { # other types
+            next;
+        }
+        if($MName=~/>(::\w+)+\Z/)
+        { # QFlags<Qt::DropAction>::enum_type
+            delete($MissedTypedef{$Version}{$Tid});
+            next;
+        }
+        if(getTypeType($TDid, $Tid)=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
+        { # double-check for the name of typedef
+            my ($TName, $TNS) = getTrivialName($TDid, $Tid); # base type info
+            next if(not $TName);
+            if(length($MName)>=length($TName))
+            { # too long typedef
+                delete($MissedTypedef{$Version}{$Tid});
+                next;
+            }
+            if($TName=~/\A\Q$MName\E</) {
+                next;
+            }
+            if($MName=~/\A\Q$TName\E/)
+            { # QDateTimeEdit::Section and QDateTimeEdit::Sections::enum_type
+                delete($MissedTypedef{$Version}{$Tid});
+                next;
+            }
+            if(get_depth($MName)==0 and get_depth($TName)!=0)
+            { # std::_Vector_base and std::vector::_Base
+                delete($MissedTypedef{$Version}{$Tid});
+                next;
+            }
+        }
+        %{$TypeInfo{$Version}{$MissedTDid}{$MissedInfo{"Tid"}}} = %MissedInfo;
+        $Tid_TDid{$Version}{$MissedInfo{"Tid"}} = $MissedTDid;
+        delete($TypeInfo{$Version}{$MissedTDid}{$Tid});
+        # register typedef
+        $MissedTypedef{$Version}{$Tid}{"TDid"} = $MissedTDid;
+        $MissedTypedef{$Version}{$Tid}{"Tid"} = $MissedInfo{"Tid"};
+    }
+}
+
+sub addMissedTypes_Post()
+{
+    foreach my $BaseId (keys(%{$MissedTypedef{$Version}}))
+    {
+        my $Tid = $MissedTypedef{$Version}{$BaseId}{"Tid"};
+        my $TDid = $MissedTypedef{$Version}{$BaseId}{"TDid"};
+        $TypeInfo{$Version}{$TDid}{$Tid}{"Size"} = get_TypeAttr($BaseId, $Version, "Size");
+    }
+}
+
+sub getTypeInfo($$)
+{
+    my ($TDId, $TId) = @_;
+    %{$TypeInfo{$Version}{$TDId}{$TId}} = getTypeAttr($TDId, $TId);
+    my $TName = $TypeInfo{$Version}{$TDId}{$TId}{"Name"};
+    if(not $TName) {
+        delete($TypeInfo{$Version}{$TDId}{$TId});
+        return;
+    }
+    if($TDId) {
+        $Tid_TDid{$Version}{$TId} = $TDId;
+    }
+    if(not $TName_Tid{$Version}{$TName}) {
+        $TName_Tid{$Version}{$TName} = $TId;
+    }
+}
+
+sub getArraySize($$)
+{
+    my ($TypeId, $BaseName) = @_;
+    my $SizeBytes = getSize($TypeId)/$BYTE_SIZE;
+    while($BaseName=~s/\s*\[(\d+)\]//) {
+        $SizeBytes/=$1;
+    }
+    my $BasicId = $TName_Tid{$Version}{$BaseName};
+    if(my $BasicSize = $TypeInfo{$Version}{getTypeDeclId($BasicId)}{$BasicId}{"Size"}) {
+        $SizeBytes/=$BasicSize;
+    }
+    return $SizeBytes;
+}
+
+sub getTParams_Func($)
+{
+    my $FuncInfoId = $_[0];
+    my @TmplParams = ();
+    foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$TemplateInstance_Func{$Version}{$FuncInfoId}}))
+    {
+        my $Param = get_TemplateParam($Pos, $TemplateInstance_Func{$Version}{$FuncInfoId}{$Pos});
+        if($Param eq "") {
+            return ();
+        }
+        elsif($Param ne "\@skip\@") {
+            push(@TmplParams, $Param);
+        }
+    }
+    return @TmplParams;
+}
+
+sub getTParams($$)
+{
+    my ($TypeDeclId, $TypeId) = @_;
+    my @Template_Params = ();
+    foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$TemplateInstance{$Version}{$TypeDeclId}{$TypeId}}))
+    {
+        my $Param_TypeId = $TemplateInstance{$Version}{$TypeDeclId}{$TypeId}{$Pos};
+        my $Param = get_TemplateParam($Pos, $Param_TypeId);
+        if($Param eq "") {
+            return ();
+        }
+        elsif($Param ne "\@skip\@") {
+            @Template_Params = (@Template_Params, $Param);
+        }
+    }
+    return @Template_Params;
+}
+
+sub getTypeAttr($$)
+{
+    my ($TypeDeclId, $TypeId) = @_;
+    my ($BaseTypeSpec, %TypeAttr) = ();
+    if(defined $TypeInfo{$Version}{$TypeDeclId}{$TypeId}
+    and $TypeInfo{$Version}{$TypeDeclId}{$TypeId}{"Name"}) {
+        return %{$TypeInfo{$Version}{$TypeDeclId}{$TypeId}};
+    }
+    $TypeAttr{"Tid"} = $TypeId;
+    $TypeAttr{"TDid"} = $TypeDeclId;
+    $TypeAttr{"Type"} = getTypeType($TypeDeclId, $TypeId);
+    if($TypeAttr{"Type"} eq "Unknown") {
+        return ();
+    }
+    elsif($TypeAttr{"Type"}=~/(Func|Method|Field)Ptr/)
+    {
+        %{$TypeInfo{$Version}{$TypeDeclId}{$TypeId}} = getMemPtrAttr(pointTo($TypeId), $TypeDeclId, $TypeId, $TypeAttr{"Type"});
+        $TName_Tid{$Version}{$TypeInfo{$Version}{$TypeDeclId}{$TypeId}{"Name"}} = $TypeId;
+        return %{$TypeInfo{$Version}{$TypeDeclId}{$TypeId}};
+    }
+    elsif($TypeAttr{"Type"} eq "Array")
+    {
+        ($TypeAttr{"BaseType"}{"Tid"}, $TypeAttr{"BaseType"}{"TDid"}, $BaseTypeSpec) = selectBaseType($TypeDeclId, $TypeId);
+        my %BaseTypeAttr = getTypeAttr($TypeAttr{"BaseType"}{"TDid"}, $TypeAttr{"BaseType"}{"Tid"});
+        if(my $NElems = getArraySize($TypeId, $BaseTypeAttr{"Name"}))
+        {
+            $TypeAttr{"Size"} = getSize($TypeId)/$BYTE_SIZE;
+            if($BaseTypeAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
+                $TypeAttr{"Name"} = $1."[$NElems]".$2;
+            }
+            else {
+                $TypeAttr{"Name"} = $BaseTypeAttr{"Name"}."[$NElems]";
+            }
+        }
+        else
+        {
+            $TypeAttr{"Size"} = $WORD_SIZE{$Version}; # pointer
+            if($BaseTypeAttr{"Name"}=~/\A([^\[\]]+)(\[(\d+|)\].*)\Z/) {
+                $TypeAttr{"Name"} = $1."[]".$2;
+            }
+            else {
+                $TypeAttr{"Name"} = $BaseTypeAttr{"Name"}."[]";
+            }
+        }
+        $TypeAttr{"Name"} = formatName($TypeAttr{"Name"});
+        if($BaseTypeAttr{"Header"})  {
+            $TypeAttr{"Header"} = $BaseTypeAttr{"Header"};
+        }
+        %{$TypeInfo{$Version}{$TypeDeclId}{$TypeId}} = %TypeAttr;
+        $TName_Tid{$Version}{$TypeInfo{$Version}{$TypeDeclId}{$TypeId}{"Name"}} = $TypeId;
+        return %TypeAttr;
+    }
+    elsif($TypeAttr{"Type"}=~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/)
+    {
+        %{$TypeInfo{$Version}{$TypeDeclId}{$TypeId}} = getTrivialTypeAttr($TypeDeclId, $TypeId);
+        return %{$TypeInfo{$Version}{$TypeDeclId}{$TypeId}};
+    }
+    else
+    {
+        ($TypeAttr{"BaseType"}{"Tid"}, $TypeAttr{"BaseType"}{"TDid"}, $BaseTypeSpec) = selectBaseType($TypeDeclId, $TypeId);
+        if(my $MissedTDid = $MissedTypedef{$Version}{$TypeAttr{"BaseType"}{"Tid"}}{"TDid"})
+        {
+            if($MissedTDid ne $TypeDeclId)
+            {
+                $TypeAttr{"BaseType"}{"TDid"} = $MissedTDid;
+                $TypeAttr{"BaseType"}{"Tid"} = $MissedTypedef{$Version}{$TypeAttr{"BaseType"}{"Tid"}}{"Tid"};
+            }
+        }
+        my %BaseTypeAttr = getTypeAttr($TypeAttr{"BaseType"}{"TDid"}, $TypeAttr{"BaseType"}{"Tid"});
+        if(not $BaseTypeAttr{"Name"})
+        { # const "template_type_parm"
+            return ();
+        }
+        if($BaseTypeAttr{"Type"} eq "Typedef")
+        { # relinking typedefs
+            my %BaseBase = get_Type($BaseTypeAttr{"BaseType"}{"TDid"},$BaseTypeAttr{"BaseType"}{"Tid"}, $Version);
+            if($BaseTypeAttr{"Name"} eq $BaseBase{"Name"}) {
+                ($TypeAttr{"BaseType"}{"Tid"}, $TypeAttr{"BaseType"}{"TDid"}) = ($BaseBase{"Tid"}, $BaseBase{"TDid"});
+            }
+        }
+        if($BaseTypeSpec)
+        {
+            if($TypeAttr{"Type"} eq "Pointer"
+            and $BaseTypeAttr{"Name"}=~/\([\*]+\)/) {
+                $TypeAttr{"Name"} = $BaseTypeAttr{"Name"};
+                $TypeAttr{"Name"}=~s/\(([*]+)\)/($1*)/g;
+            }
+            else {
+                $TypeAttr{"Name"} = $BaseTypeAttr{"Name"}." ".$BaseTypeSpec;
+            }
+        }
+        else {
+            $TypeAttr{"Name"} = $BaseTypeAttr{"Name"};
+        }
+        if($TypeAttr{"Type"} eq "Typedef")
+        {
+            $TypeAttr{"Name"} = getNameByInfo($TypeDeclId);
+            if(my $NS = getNameSpace($TypeDeclId))
+            {
+                my $TypeName = $TypeAttr{"Name"};
+                if($NS=~/\A(struct |union |class |)((.+)::|)\Q$TypeName\E\Z/)
+                { # "some_type" is the typedef to "struct some_type" in C++
+                    if($3) {
+                        $TypeAttr{"Name"} = $3."::".$TypeName;
+                    }
+                }
+                else
+                {
+                    $TypeAttr{"NameSpace"} = $NS;
+                    $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
+                    if($TypeAttr{"NameSpace"}=~/\Astd(::|\Z)/ and $BaseTypeAttr{"NameSpace"}=~/\Astd(::|\Z)/
+                    and $BaseTypeAttr{"Name"}=~/</ and $TypeAttr{"Name"}!~/>(::\w+)+\Z/)
+                    { # types like "std::fpos<__mbstate_t>" are
+                      # not covered by typedefs in the ABI dump
+                      # so trying to add such typedefs manually
+                        $StdCxxTypedef{$Version}{$BaseTypeAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
+                        if(length($TypeAttr{"Name"})<=length($BaseTypeAttr{"Name"}))
+                        {
+                            if(($BaseTypeAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/))
+                            { # skip "other" in "std" and "type" in "boost"
+                                $Typedef_Eq{$Version}{$BaseTypeAttr{"Name"}} = $TypeAttr{"Name"};
+                            }
+                        }
+                    }
+                }
+            }
+            if($TypeAttr{"Name"} ne $BaseTypeAttr{"Name"}
+            and $TypeAttr{"Name"}!~/>(::\w+)+\Z/ and $BaseTypeAttr{"Name"}!~/>(::\w+)+\Z/)
+            {
+                $Typedef_BaseName{$Version}{$TypeAttr{"Name"}} = $BaseTypeAttr{"Name"};
+                if($BaseTypeAttr{"Name"}=~/</)
+                {
+                    if(($BaseTypeAttr{"Name"}!~/\A(std|boost)::/ or $TypeAttr{"Name"}!~/\A[a-z]+\Z/)) {
+                        $Typedef_Tr{$Version}{$BaseTypeAttr{"Name"}}{$TypeAttr{"Name"}} = 1;
+                    }
+                }
+            }
+            ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeDeclId);
+        }
+        if(not $TypeAttr{"Size"})
+        {
+            if($TypeAttr{"Type"} eq "Pointer") {
+                $TypeAttr{"Size"} = $WORD_SIZE{$Version};
+            }
+            elsif($BaseTypeAttr{"Size"}) {
+                $TypeAttr{"Size"} = $BaseTypeAttr{"Size"};
+            }
+        }
+        $TypeAttr{"Name"} = formatName($TypeAttr{"Name"});
+        if(not $TypeAttr{"Header"} and $BaseTypeAttr{"Header"})  {
+            $TypeAttr{"Header"} = $BaseTypeAttr{"Header"};
+        }
+        %{$TypeInfo{$Version}{$TypeDeclId}{$TypeId}} = %TypeAttr;
+        if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
+            $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
+        }
+        return %TypeAttr;
+    }
+}
+
+sub get_TemplateParam($$)
+{
+    my ($Pos, $Type_Id) = @_;
+    return "" if(not $Type_Id);
+    if($Cache{"get_TemplateParam"}{$Type_Id}) {
+        return $Cache{"get_TemplateParam"}{$Type_Id};
+    }
+    if(getNodeType($Type_Id) eq "integer_cst")
+    { # int (1), unsigned (2u), char ('c' as 99), ...
+        my $CstTid = getTreeAttr($Type_Id, "type");
+        my %CstType = getTypeAttr(getTypeDeclId($CstTid), $CstTid);
+        my $Num = getNodeIntCst($Type_Id);
+        if(my $CstSuffix = $ConstantSuffix{$CstType{"Name"}}) {
+            return $Num.$CstSuffix;
+        }
+        else {
+            return "(".$CstType{"Name"}.")".$Num;
+        }
+    }
+    elsif(getNodeType($Type_Id) eq "string_cst") {
+        return getNodeStrCst($Type_Id);
+    }
+    elsif(getNodeType($Type_Id) eq "tree_vec") {
+        return "\@skip\@";
+    }
+    else
+    {
+        my $Type_DId = getTypeDeclId($Type_Id);
+        my %ParamAttr = getTypeAttr($Type_DId, $Type_Id);
+        if(not $ParamAttr{"Name"}) {
+            return "";
+        }
+        my $PName = $ParamAttr{"Name"};
+        if($ParamAttr{"Name"}=~/\>/) {
+            if(my $Cover = cover_stdcxx_typedef($ParamAttr{"Name"})) {
+                $PName = $Cover;
+            }
+        }
+        if($Pos>=1 and
+        $PName=~/\Astd::(allocator|less|((char|regex)_traits)|((i|o)streambuf_iterator))\</)
+        { # template<typename _Tp, typename _Alloc = std::allocator<_Tp> >
+          # template<typename _Key, typename _Compare = std::less<_Key>
+          # template<typename _CharT, typename _Traits = std::char_traits<_CharT> >
+          # template<typename _Ch_type, typename _Rx_traits = regex_traits<_Ch_type> >
+          # template<typename _CharT, typename _InIter = istreambuf_iterator<_CharT> >
+          # template<typename _CharT, typename _OutIter = ostreambuf_iterator<_CharT> >
+            return "\@skip\@";
+        }
+        return $PName;
+    }
+}
+
+sub cover_stdcxx_typedef($)
+{
+    my $TypeName = $_[0];
+    if(my @Covers = sort {length($a)<=>length($b)}
+    sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
+    { # take the shortest typedef
+      # FIXME: there may be more than
+      # one typedefs to the same type
+        return $Covers[0];
+    }
+    my $TypeName_Covered = $TypeName;
+    while($TypeName=~s/(>)[ ]*(const|volatile|restrict| |\*|\&)\Z/$1/g){};
+    if(my @Covers = sort {length($a)<=>length($b)} sort keys(%{$StdCxxTypedef{$Version}{$TypeName}}))
+    {
+        my $Cover = $Covers[0];
+        $TypeName_Covered=~s/(\W|\A)\Q$TypeName\E(\W|\Z)/$1$Cover$2/g;
+        $TypeName_Covered=~s/(\W|\A)\Q$TypeName\E(\w|\Z)/$1$Cover $2/g;
+    }
+    return formatName($TypeName_Covered);
+}
+
+sub getNodeType($)
+{
+    return $LibInfo{$Version}{"info_type"}{$_[0]};
+}
+
+sub getNodeIntCst($)
+{
+    my $CstId = $_[0];
+    my $CstTypeId = getTreeAttr($CstId, "type");
+    if($EnumMembName_Id{$Version}{$CstId}) {
+        return $EnumMembName_Id{$Version}{$CstId};
+    }
+    elsif((my $Value = getTreeValue($CstId)) ne "")
+    {
+        if($Value eq "0") {
+            if(getNodeType($CstTypeId) eq "boolean_type") {
+                return "false";
+            }
+            else {
+                return "0";
+            }
+        }
+        elsif($Value eq "1") {
+            if(getNodeType($CstTypeId) eq "boolean_type") {
+                return "true";
+            }
+            else {
+                return "1";
+            }
+        }
+        else {
+            return $Value;
+        }
+    }
+    else {
+        return "";
+    }
+}
+
+sub getNodeStrCst($)
+{
+    if($LibInfo{$Version}{"info"}{$_[0]}=~/strg[ ]*: (.+) lngt:[ ]*(\d+)/)
+    { # string length is N-1 because of the null terminator
+        return substr($1, 0, $2-1);
+    }
+    else {
+        return "";
+    }
+}
+
+sub getMemPtrAttr($$$$)
+{ # function, method and field pointers
+    my ($PtrId, $TypeDeclId, $TypeId, $Type) = @_;
+    my $MemInfo = $LibInfo{$Version}{"info"}{$PtrId};
+    if($Type eq "FieldPtr") {
+        $MemInfo = $LibInfo{$Version}{"info"}{$TypeId};
+    }
+    my $MemInfo_Type = $LibInfo{$Version}{"info_type"}{$PtrId};
+    my $MemPtrName = "";
+    my %TypeAttr = ("Size"=>$WORD_SIZE{$Version}, "Type"=>$Type, "TDid"=>$TypeDeclId, "Tid"=>$TypeId);
+    if($Type eq "MethodPtr")
+    { # size of "method pointer" may be greater than WORD size
+        $TypeAttr{"Size"} = getSize($TypeId)/$BYTE_SIZE;
+    }
+    # Return
+    if($Type eq "FieldPtr")
+    {
+        my %ReturnAttr = getTypeAttr(getTypeDeclId($PtrId), $PtrId);
+        $MemPtrName .= $ReturnAttr{"Name"};
+        $TypeAttr{"Return"} = $PtrId;
+    }
+    else
+    {
+        if($MemInfo=~/retn[ ]*:[ ]*\@(\d+) /)
+        {
+            my $ReturnTypeId = $1;
+            my %ReturnAttr = getTypeAttr(getTypeDeclId($ReturnTypeId), $ReturnTypeId);
+            $MemPtrName .= $ReturnAttr{"Name"};
+            $TypeAttr{"Return"} = $ReturnTypeId;
+        }
+    }
+    # Class
+    if($MemInfo=~/(clas|cls)[ ]*:[ ]*@(\d+) /)
+    {
+        $TypeAttr{"Class"} = $2;
+        my %Class = getTypeAttr(getTypeDeclId($TypeAttr{"Class"}), $TypeAttr{"Class"});
+        if($Class{"Name"}) {
+            $MemPtrName .= " (".$Class{"Name"}."\:\:*)";
+        }
+        else {
+            $MemPtrName .= " (*)";
+        }
+    }
+    else {
+        $MemPtrName .= " (*)";
+    }
+    # Parameters
+    if($Type eq "FuncPtr"
+    or $Type eq "MethodPtr")
+    {
+        my @ParamTypeName = ();
+        if($MemInfo=~/prms[ ]*:[ ]*@(\d+) /)
+        {
+            my $ParamTypeInfoId = $1;
+            my $Position = 0;
+            while($ParamTypeInfoId)
+            {
+                my $ParamTypeInfo = $LibInfo{$Version}{"info"}{$ParamTypeInfoId};
+                last if($ParamTypeInfo!~/valu[ ]*:[ ]*@(\d+) /);
+                my $ParamTypeId = $1;
+                my %ParamAttr = getTypeAttr(getTypeDeclId($ParamTypeId), $ParamTypeId);
+                last if($ParamAttr{"Name"} eq "void");
+                if($Position!=0 or $Type ne "MethodPtr")
+                {
+                    $TypeAttr{"Param"}{$Position}{"type"} = $ParamTypeId;
+                    push(@ParamTypeName, $ParamAttr{"Name"});
+                }
+                last if($ParamTypeInfo!~/(chan|chain)[ ]*:[ ]*@(\d+) /);
+                $ParamTypeInfoId = $2;
+                $Position+=1;
+            }
+        }
+        $MemPtrName .= " (".join(", ", @ParamTypeName).")";
+    }
+    $TypeAttr{"Name"} = formatName($MemPtrName);
+    return %TypeAttr;
+}
+
+sub getTreeTypeName($)
+{
+    my $Info = $LibInfo{$Version}{"info"}{$_[0]};
+    if($Info=~/name[ ]*:[ ]*@(\d+) /) {
+        return getNameByInfo($1);
+    }
+    else
+    {
+        if($LibInfo{$Version}{"info_type"}{$_[0]} eq "integer_type")
+        {
+            if($LibInfo{$Version}{"info"}{$_[0]}=~/unsigned/) {
+                return "unsigned int";
+            }
+            else {
+                return "int";
+            }
+        }
+        else {
+            return "";
+        }
+    }
+}
+
+sub getTypeType($$)
+{
+    my ($TypeDeclId, $TypeId) = @_;
+    if($MissedTypedef{$Version}{$TypeId}{"TDid"}
+    and $MissedTypedef{$Version}{$TypeId}{"TDid"} eq $TypeDeclId)
+    { # support for old GCC versions
+        return "Typedef";
+    }
+    my $Info = $LibInfo{$Version}{"info"}{$TypeId};
+    if($Info=~/unql[ ]*:/ and $Info!~/qual[ ]*:/
+    and getNameByInfo($TypeDeclId)) {
+        return "Typedef";
+    }
+    elsif(my ($Qual, $To) = getQual($TypeId))
+    {
+        if($Qual eq "const volatile") {
+            return "ConstVolatile";
+        }
+        else {
+            return ucfirst($Qual);
+        }
+    }
+    my $TypeType = getTypeTypeByTypeId($TypeId);
+    if($TypeType eq "Struct")
+    {
+        if($TypeDeclId
+        and $LibInfo{$Version}{"info_type"}{$TypeDeclId} eq "template_decl") {
+            return "Template";
+        }
+        else {
+            return "Struct";
+        }
+    }
+    else {
+        return $TypeType;
+    }
+}
+
+sub getQual($)
+{
+    my $TypeId = $_[0];
+    my $Info = $LibInfo{$Version}{"info"}{$TypeId};
+    my ($Qual, $To) = ();
+    my %UnQual = (
+        "r"=>"restrict",
+        "v"=>"volatile",
+        "c"=>"const",
+        "cv"=>"const volatile"
+    );
+    if($Info=~/qual[ ]*:[ ]*(r|c|v|cv) /) {
+        $Qual = $UnQual{$1};
+    }
+    if($Info=~/unql[ ]*:[ ]*\@(\d+)/) {
+        $To = $1;
+    }
+    if($Qual and $To) {
+        return ($Qual, $To);
+    }
+    return ();
+}
+
+sub selectBaseType($$)
+{
+    my ($TypeDeclId, $TypeId) = @_;
+    if($MissedTypedef{$Version}{$TypeId}{"TDid"}
+    and $MissedTypedef{$Version}{$TypeId}{"TDid"} eq $TypeDeclId) {
+        return ($TypeId, getTypeDeclId($TypeId), "");
+    }
+    my $TInfo = $LibInfo{$Version}{"info"}{$TypeId};
+    if(my ($Qual, $To) = getQual($TypeId)
+    and $TInfo=~/name[ ]*:[ ]*\@(\d+) /
+    and (getTypeId($1) ne $TypeId)) {
+        return (getTypeId($1), $1, $Qual);
+    }
+    elsif($TInfo!~/qual[ ]*:/
+    and $TInfo=~/unql[ ]*:[ ]*\@(\d+) /
+    and getNameByInfo($TypeDeclId))
+    { # typedefs
+        return ($1, getTypeDeclId($1), "");
+    }
+    elsif(my ($Qual, $To) = getQual($TypeId)) {
+        return ($To, getTypeDeclId($To), $Qual);
+    }
+    elsif($LibInfo{$Version}{"info_type"}{$TypeId} eq "reference_type")
+    {
+        if($TInfo=~/refd[ ]*:[ ]*@(\d+) /) {
+            return ($1, getTypeDeclId($1), "&");
+        }
+        else {
+            return (0, 0, "");
+        }
+    }
+    elsif($LibInfo{$Version}{"info_type"}{$TypeId} eq "array_type")
+    {
+        if($TInfo=~/elts[ ]*:[ ]*@(\d+) /) {
+            return ($1, getTypeDeclId($1), "");
+        }
+        else {
+            return (0, 0, "");
+        }
+    }
+    elsif($LibInfo{$Version}{"info_type"}{$TypeId} eq "pointer_type")
+    {
+        if($TInfo=~/ptd[ ]*:[ ]*@(\d+) /) {
+            return ($1, getTypeDeclId($1), "*");
+        }
+        else {
+            return (0, 0, "");
+        }
+    }
+    else {
+        return (0, 0, "");
+    }
+}
+
+sub getSymbolInfo_All()
+{
+    foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
+    { # reverse order
+        if($LibInfo{$Version}{"info_type"}{$_} eq "function_decl") {
+            getSymbolInfo("$_");
+        }
+    }
+}
+
+sub getVarInfo_All()
+{
+    foreach (sort {int($b)<=>int($a)} keys(%{$LibInfo{$Version}{"info"}}))
+    { # reverse order
+        if($LibInfo{$Version}{"info_type"}{$_} eq "var_decl") {
+            getVarInfo("$_");
+        }
+    }
+}
+
+sub isBuiltIn($) {
+    return ($_[0]=~/\<built\-in\>|\<internal\>|\A\./);
+}
+
+sub getVarInfo($)
+{
+    my $InfoId = $_[0];
+    if($LibInfo{$Version}{"info_type"}{getNameSpaceId($InfoId)} eq "function_decl") {
+        return;
+    }
+    ($SymbolInfo{$Version}{$InfoId}{"Header"}, $SymbolInfo{$Version}{$InfoId}{"Line"}) = getLocation($InfoId);
+    if(not $SymbolInfo{$Version}{$InfoId}{"Header"}
+    or isBuiltIn($SymbolInfo{$Version}{$InfoId}{"Header"})) {
+        delete($SymbolInfo{$Version}{$InfoId});
+        return;
+    }
+    my $ShortName = $SymbolInfo{$Version}{$InfoId}{"ShortName"} = getVarShortName($InfoId);
+    if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\Atmp_add_class_\d+\Z/) {
+        delete($SymbolInfo{$Version}{$InfoId});
+        return;
+    }
+    $SymbolInfo{$Version}{$InfoId}{"MnglName"} = getFuncMnglName($InfoId);
+    if($SymbolInfo{$Version}{$InfoId}{"MnglName"}
+    and $SymbolInfo{$Version}{$InfoId}{"MnglName"}!~/\A_Z/)
+    { # validate mangled name
+        delete($SymbolInfo{$Version}{$InfoId});
+        return;
+    }
+    $SymbolInfo{$Version}{$InfoId}{"Data"} = 1;
+    $SymbolInfo{$Version}{$InfoId}{"Return"} = getTypeId($InfoId);
+    if(not $SymbolInfo{$Version}{$InfoId}{"Return"}) {
+        delete($SymbolInfo{$Version}{$InfoId}{"Return"});
+    }
+    set_Class_And_Namespace($InfoId);
+    if($LibInfo{$Version}{"info"}{$InfoId}=~/ lang:[ ]*C /i) {
+        $SymbolInfo{$Version}{$InfoId}{"Lang"} = "C";
+    }
+    if($UserLang eq "C")
+    { # --lang=C option
+        $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
+    }
+    if($COMMON_LANGUAGE{$Version} eq "C++")
+    {
+        if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
+        { # for some symbols (_ZTI) the short name is the mangled name
+            if($ShortName=~/\A_Z/) {
+                $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
+            }
+        }
+        if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"})
+        { # try to mangle symbol (link with libraries)
+            $SymbolInfo{$Version}{$InfoId}{"MnglName"} = linkSymbol($InfoId);
+        }
+        if($OStarget eq "windows")
+        {
+            if(my $Mangled = $mangled_name{$Version}{modelUnmangled($InfoId, "MSVC")})
+            { # link MS C++ symbols from library with GCC symbols from headers
+                $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $Mangled;
+            }
+        }
+    }
+    if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) {
+        $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
+    }
+    if(not link_symbol($SymbolInfo{$Version}{$InfoId}{"MnglName"}, $Version, "-Deps")
+    and not $CheckHeadersOnly)
+    {
+        if(link_symbol($ShortName, $Version, "-Deps")
+        and $SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/_ZL\d+$ShortName\Z/)
+        { # const int global_data is mangled as _ZL11global_data in the tree
+            $SymbolInfo{$Version}{$InfoId}{"MnglName"} = $ShortName;
+        }
+        else {
+            delete($SymbolInfo{$Version}{$InfoId});
+            return;
+        }
+    }
+    if(not $SymbolInfo{$Version}{$InfoId}{"MnglName"}) {
+        delete($SymbolInfo{$Version}{$InfoId});
+        return;
+    }
+    if(my $AddedTid = $MissedTypedef{$Version}{$SymbolInfo{$Version}{$InfoId}{"Return"}}{"Tid"}) {
+        $SymbolInfo{$Version}{$InfoId}{"Return"} = $AddedTid;
+    }
+    setFuncAccess($InfoId);
+    if($SymbolInfo{$Version}{$InfoId}{"MnglName"}=~/\A_ZTV/) {
+        delete($SymbolInfo{$Version}{$InfoId}{"Return"});
+    }
+    if($ShortName=~/\A(_Z|\?)/) {
+        delete($SymbolInfo{$Version}{$InfoId}{"ShortName"});
+    }
+}
+
+sub getTrivialName($$)
+{
+    my ($TypeInfoId, $TypeId) = @_;
+    my %TypeAttr = ();
+    $TypeAttr{"Name"} = getNameByInfo($TypeInfoId);
+    if(not $TypeAttr{"Name"}) {
+        $TypeAttr{"Name"} = getTreeTypeName($TypeId);
+    }
+    $TypeAttr{"Name"}=~s/<(.+)\Z//g; # GCC 3.4.4 add template params to the name
+    if(my $NameSpaceId = getNameSpaceId($TypeInfoId)) {
+        if($NameSpaceId ne $TypeId) {
+            $TypeAttr{"NameSpace"} = getNameSpace($TypeInfoId);
+        }
+    }
+    if($TypeAttr{"NameSpace"} and isNotAnon($TypeAttr{"Name"})) {
+        $TypeAttr{"Name"} = $TypeAttr{"NameSpace"}."::".$TypeAttr{"Name"};
+    }
+    $TypeAttr{"Name"} = formatName($TypeAttr{"Name"});
+    if(isAnon($TypeAttr{"Name"}))
+    {# anon-struct-header.h-line
+        $TypeAttr{"Name"} = "anon-".lc(getTypeType($TypeInfoId, $TypeId))."-";
+        $TypeAttr{"Name"} .= $TypeAttr{"Header"}."-".$TypeAttr{"Line"};
+    }
+    if(defined $TemplateInstance{$Version}{$TypeInfoId}{$TypeId})
+    {
+        my @TParams = getTParams($TypeInfoId, $TypeId);
+        if(not @TParams)
+        { # template declarations with abstract params
+            # vector (tree_vec) of template_type_parm nodes in the TU dump
+            return ("", "");
+        }
+        $TypeAttr{"Name"} = formatName($TypeAttr{"Name"}."< ".join(", ", @TParams)." >");
+    }
+    return ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"});
+}
+
+sub getTrivialTypeAttr($$)
+{
+    my ($TypeInfoId, $TypeId) = @_;
+    my %TypeAttr = ();
+    if(getTypeTypeByTypeId($TypeId)!~/\A(Intrinsic|Union|Struct|Enum|Class)\Z/) {
+        return ();
+    }
+    setTypeAccess($TypeId, \%TypeAttr);
+    ($TypeAttr{"Header"}, $TypeAttr{"Line"}) = getLocation($TypeInfoId);
+    if(isBuiltIn($TypeAttr{"Header"}))
+    {
+        delete($TypeAttr{"Header"});
+        delete($TypeAttr{"Line"});
+    }
+    $TypeAttr{"Type"} = getTypeType($TypeInfoId, $TypeId);
+    ($TypeAttr{"Name"}, $TypeAttr{"NameSpace"}) = getTrivialName($TypeInfoId, $TypeId);
+    if(not $TypeAttr{"Name"}) {
+        return ();
+    }
+    if(not $TypeAttr{"NameSpace"}) {
+        delete($TypeAttr{"NameSpace"});
+    }
+    if(isAnon($TypeAttr{"Name"}))
+    {
+        $TypeAttr{"Name"} = "anon-".lc($TypeAttr{"Type"})."-";
+        $TypeAttr{"Name"} .= $TypeAttr{"Header"}."-".$TypeAttr{"Line"};
+    }
+    if(my $Size = getSize($TypeId)) {
+        $TypeAttr{"Size"} = $Size/$BYTE_SIZE;
+    }
+    if($TypeAttr{"Type"} eq "Struct"
+    and detect_lang($TypeId))
+    {
+        $TypeAttr{"Type"} = "Class";
+        $TypeAttr{"Copied"} = 1;# default, will be changed in getSymbolInfo()
+    }
+    if($TypeAttr{"Type"} eq "Struct"
+    or $TypeAttr{"Type"} eq "Class") {
+        setBaseClasses($TypeInfoId, $TypeId, \%TypeAttr);
+    }
+    setSpec($TypeId, \%TypeAttr);
+    setTypeMemb($TypeId, \%TypeAttr);
+    $TypeAttr{"Tid"} = $TypeId;
+    $TypeAttr{"TDid"} = $TypeInfoId;
+    if($TypeInfoId) {
+        $Tid_TDid{$Version}{$TypeId} = $TypeInfoId;
+    }
+    if(not $TName_Tid{$Version}{$TypeAttr{"Name"}}) {
+        $TName_Tid{$Version}{$TypeAttr{"Name"}} = $TypeId;
+    }
+    if(my $VTable = $ClassVTable_Content{$Version}{$TypeAttr{"Name"}})
+    {
+        my @Entries = split(/\n/, $VTable);
+        foreach (1 .. $#Entries)
+        {
+            my $Entry = $Entries[$_];
+            if($Entry=~/\A(\d+)\s+(.+)\Z/) {
+                $TypeAttr{"VTable"}{$1} = $2;
+            }
+        }
+    }
+    return %TypeAttr;
+}
+
+sub detect_lang($)
+{
+    my $TypeId = $_[0];
+    my $Info = $LibInfo{$Version}{"info"}{$TypeId};
+    if(check_gcc_version($GCC_PATH, "4"))
+    {# GCC 4 fncs-node points to only non-artificial methods
+        return ($Info=~/(fncs)[ ]*:[ ]*@(\d+) /);
+    }
+    else
+    {# GCC 3
+        my $Fncs = getTreeAttr($TypeId, "fncs");
+        while($Fncs)
+        {
+            my $Info = $LibInfo{$Version}{"info"}{$Fncs};
+            if($Info!~/artificial/) {
+                return 1;
+            }
+            $Fncs = getTreeAttr($Fncs, "chan");
+        }
+    }
+    return 0;
+}
+
+sub setSpec($$)
+{
+    my ($TypeId, $TypeAttr) = @_;
+    my $Info = $LibInfo{$Version}{"info"}{$TypeId};
+    if($Info=~/\s+spec\s+/) {
+        $TypeAttr->{"Spec"} = 1;
+    }
+}
+
+sub setBaseClasses($$$)
+{
+    my ($TypeInfoId, $TypeId, $TypeAttr) = @_;
+    my $Info = $LibInfo{$Version}{"info"}{$TypeId};
+    if($Info=~/binf[ ]*:[ ]*@(\d+) /)
+    {
+        $Info = $LibInfo{$Version}{"info"}{$1};
+        my $Pos = 0;
+        while($Info=~s/(pub|public|prot|protected|priv|private|)[ ]+binf[ ]*:[ ]*@(\d+) //)
+        {
+            my ($Access, $BInfoId) = ($1, $2);
+            my $ClassId = getBinfClassId($BInfoId);
+            my $BaseInfo = $LibInfo{$Version}{"info"}{$BInfoId};
+            if($Access=~/prot/)
+            {
+                $TypeAttr->{"Base"}{$ClassId}{"access"} = "protected";
+            }
+            elsif($Access=~/priv/)
+            {
+                $TypeAttr->{"Base"}{$ClassId}{"access"} = "private";
+            }
+            $TypeAttr->{"Base"}{$ClassId}{"pos"} = $Pos++;
+            if($BaseInfo=~/virt/)
+            {# virtual base
+                $TypeAttr->{"Base"}{$ClassId}{"virtual"} = 1;
+            }
+            $Class_SubClasses{$Version}{$ClassId}{$TypeId}=1;
+        }
+    }
+}
+
+sub getBinfClassId($)
+{
+    my $Info = $LibInfo{$Version}{"info"}{$_[0]};
+    $Info=~/type[ ]*:[ ]*@(\d+) /;
+    return $1;
+}
+
+sub unmangledFormat($$)
+{
+    my ($Name, $LibVersion) = @_;
+    $Name = uncover_typedefs($Name, $LibVersion);
+    while($Name=~s/([^\w>*])(const|volatile)(,|>|\Z)/$1$3/g){};
+    $Name=~s/\(\w+\)(\d)/$1/;
+    return $Name;
+}
+
+sub modelUnmangled($$)
+{
+    my ($InfoId, $Compiler) = @_;
+    if($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId}) {
+        return $Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId};
+    }
+    my $PureSignature = $SymbolInfo{$Version}{$InfoId}{"ShortName"};
+    if($SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
+        $PureSignature = "~".$PureSignature;
+    }
+    if(not $SymbolInfo{$Version}{$InfoId}{"Data"})
+    {
+        my (@Params, @ParamTypes) = ();
+        if(defined $SymbolInfo{$Version}{$InfoId}{"Param"}
+        and not $SymbolInfo{$Version}{$InfoId}{"Destructor"}) {
+            @Params = keys(%{$SymbolInfo{$Version}{$InfoId}{"Param"}});
+        }
+        foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
+        { # checking parameters
+            my $PId = $SymbolInfo{$Version}{$InfoId}{"Param"}{$ParamPos}{"type"};
+            my %PType = get_PureType($Tid_TDid{$Version}{$PId}, $PId, $Version);
+            my $PTName = unmangledFormat($PType{"Name"}, $Version);
+            $PTName=~s/(\A|\W)(restrict|register)(\W|\Z)/$1$3/g;
+            if($Compiler eq "MSVC") {
+                $PTName=~s/(\W|\A)long long(\W|\Z)/$1__int64$2/;
+            }
+            @ParamTypes = (@ParamTypes, $PTName);
+        }
+        if(@ParamTypes) {
+            $PureSignature .= "(".join(", ", @ParamTypes).")";
+        }
+        else
+        {
+            if($Compiler eq "MSVC")
+            {
+                $PureSignature .= "(void)";
+            }
+            else
+            { # GCC
+                $PureSignature .= "()";
+            }
+        }
+        $PureSignature = delete_keywords($PureSignature);
+    }
+    if(my $ClassId = $SymbolInfo{$Version}{$InfoId}{"Class"})
+    {
+        my $ClassName = unmangledFormat(get_TypeName($ClassId, $Version), $Version);
+        $PureSignature = $ClassName."::".$PureSignature;
+    }
+    elsif(my $NS = $SymbolInfo{$Version}{$InfoId}{"NameSpace"}) {
+        $PureSignature = $NS."::".$PureSignature;
+    }
+    if($SymbolInfo{$Version}{$InfoId}{"Const"}) {
+        $PureSignature .= " const";
+    }
+    if($SymbolInfo{$Version}{$InfoId}{"Volatile"}) {
+        $PureSignature .= " volatile";
+    }
+    my $ShowReturn = 0;
+    if($Compiler eq "MSVC"
+    and $SymbolInfo{$Version}{$InfoId}{"Data"})
+    {
+        $ShowReturn=1;
+    }
+    elsif(defined $TemplateInstance_Func{$Version}{$InfoId}
+    and keys(%{$TemplateInstance_Func{$Version}{$InfoId}}))
+    {
+        $ShowReturn=1;
+    }
+    if($ShowReturn)
+    { # mangled names for template function specializations include return value
+        if(my $ReturnId = $SymbolInfo{$Version}{$InfoId}{"Return"})
+        {
+            my %RType = get_PureType($Tid_TDid{$Version}{$ReturnId}, $ReturnId, $Version);
+            my $ReturnName = unmangledFormat($RType{"Name"}, $Version);
+            $PureSignature = $ReturnName." ".$PureSignature;
+        }
+    }
+    return ($Cache{"modelUnmangled"}{$Version}{$Compiler}{$InfoId} = formatName($PureSignature));
+}
+
+sub mangle_symbol($$$)
+{ # mangling for simple methods
+  # see gcc-4.6.0/gcc/cp/mangle.c
+    my ($InfoId, $LibVersion, $Compiler) = @_;
+    if($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler}) {
+        return $Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler};
+    }
+    my $Mangled = "";
+    if($Compiler eq "GCC") {
+        $Mangled = mangle_symbol_gcc($InfoId, $LibVersion);
+    }
+    elsif($Compiler eq "MSVC") {
+        $Mangled = mangle_symbol_msvc($InfoId, $LibVersion);
+    }
+    return ($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler} = $Mangled);
+}
+
+sub mangle_symbol_msvc($$)
+{
+    my ($InfoId, $LibVersion) = @_;
+    return "";
+}
+
+sub mangle_symbol_gcc($$)
+{ # see gcc-4.6.0/gcc/cp/mangle.c
+    my ($InfoId, $LibVersion) = @_;
+    my ($Mangled, $ClassId, $NameSpace) = ("_Z", 0, "");
+    my %Repl = ();# SN_ replacements
+    if($ClassId = $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
+    {
+        my $MangledClass = mangle_param($ClassId, $LibVersion, \%Repl);
+        if($MangledClass!~/\AN/) {
+            $MangledClass = "N".$MangledClass;
+        }
+        else {
+            $MangledClass=~s/E\Z//;
+        }
+        if($SymbolInfo{$LibVersion}{$InfoId}{"Volatile"}) {
+            $MangledClass=~s/\AN/NV/;
+        }
+        if($SymbolInfo{$LibVersion}{$InfoId}{"Const"}) {
+            $MangledClass=~s/\AN/NK/;
+        }
+        $Mangled .= $MangledClass;
+    }
+    elsif($NameSpace = $SymbolInfo{$LibVersion}{$InfoId}{"NameSpace"})
+    { # mangled by name due to the absence of structured info
+        my $MangledNS = mangle_ns($NameSpace, $LibVersion, \%Repl);
+        if($MangledNS!~/\AN/) {
+            $MangledNS = "N".$MangledNS;
+        }
+        else {
+            $MangledNS=~s/E\Z//;
+        }
+        $Mangled .= $MangledNS;
+    }
+    my ($ShortName, $TmplParams) = template_base($SymbolInfo{$LibVersion}{$InfoId}{"ShortName"});
+    my @TParams = getTParams_Func($InfoId);
+    if(not @TParams and $TmplParams)
+    { # support for old ABI dumps
+        @TParams = separate_params($TmplParams, 0);
+    }
+    if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"}) {
+        $Mangled .= "C1";
+    }
+    elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
+        $Mangled .= "D0";
+    }
+    elsif($ShortName)
+    {
+        if(($NameSpace eq "__gnu_cxx"
+        or $ShortName=~/\A__(gthrw|gthread)_/)
+        and not $ClassId)
+        { # _ZN9__gnu_cxxL25__exchange_and_add_singleEPii
+          # _ZN9__gnu_cxxL19__atomic_add_singleEPii
+          # _ZL19__gthrw_sched_yieldv
+          # _ZL21__gthread_setspecificjPKv
+            $Mangled .= "L";
+        }
+        if($ShortName=~/\Aoperator(\W.*)\Z/)
+        {
+            my $Op = $1;
+            $Op=~s/\A[ ]+//g;
+            if(my $OpMngl = $OperatorMangling{$Op}) {
+                $Mangled .= $OpMngl;
+            }
+            else { # conversion operator
+                $Mangled .= "cv".mangle_param(getTypeIdByName($Op, $LibVersion), $LibVersion, \%Repl);
+            }
+        }
+        else {
+            $Mangled .= length($ShortName).$ShortName;
+        }
+        if(@TParams)
+        { # templates
+            $Mangled .= "I";
+            foreach my $TParam (@TParams) {
+                $Mangled .= mangle_template_param($TParam, $LibVersion, \%Repl);
+            }
+            $Mangled .= "E";
+        }
+        if(not $ClassId and @TParams) {
+            add_substitution($ShortName, \%Repl, 0);
+        }
+    }
+    if($ClassId or $NameSpace) {
+        $Mangled .= "E";
+    }
+    if(@TParams) {
+        if(my $Return = $SymbolInfo{$LibVersion}{$InfoId}{"Return"}) {
+            $Mangled .= mangle_param($Return, $LibVersion, \%Repl);
+        }
+    }
+    if(not $SymbolInfo{$LibVersion}{$InfoId}{"Data"})
+    {
+        my @Params = ();
+        if(defined $SymbolInfo{$LibVersion}{$InfoId}{"Param"}
+        and not $SymbolInfo{$LibVersion}{$InfoId}{"Destructor"}) {
+            @Params = keys(%{$SymbolInfo{$LibVersion}{$InfoId}{"Param"}});
+        }
+        foreach my $ParamPos (sort {int($a) <=> int($b)} @Params)
+        { # checking parameters
+            my $ParamType_Id = $SymbolInfo{$LibVersion}{$InfoId}{"Param"}{$ParamPos}{"type"};
+            $Mangled .= mangle_param($ParamType_Id, $LibVersion, \%Repl);
+        }
+        if(not @Params) {
+            $Mangled .= "v";
+        }
+    }
+    $Mangled = correct_incharge($InfoId, $LibVersion, $Mangled);
+    $Mangled = write_stdcxx_substitution($Mangled);
+    if($Mangled eq "_Z") {
+        return "";
+    }
+    return $Mangled;
+}
+
+sub correct_incharge($$$)
+{
+    my ($InfoId, $LibVersion, $Mangled) = @_;
+    if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"})
+    {
+        if($MangledNames{$LibVersion}{$Mangled}) {
+            $Mangled=~s/C1E/C2E/;
+        }
+    }
+    elsif($SymbolInfo{$LibVersion}{$InfoId}{"Destructor"})
+    {
+        if($MangledNames{$LibVersion}{$Mangled}) {
+            $Mangled=~s/D0E/D1E/;
+        }
+        if($MangledNames{$LibVersion}{$Mangled}) {
+            $Mangled=~s/D1E/D2E/;
+        }
+    }
+    return $Mangled;
+}
+
+sub template_base($)
+{ # NOTE: std::_Vector_base<mysqlpp::mysql_type_info>::_Vector_impl
+  # NOTE: operator<<
+    my $Name = $_[0];
+    if($Name!~/>\Z/) {
+        return $Name;
+    }
+    my $TParams = $Name;
+    while(my $CPos = detect_center($TParams, "<")) {
+        $TParams = substr($TParams, $CPos);
+    }
+    $Name=~s/\Q$TParams\E\Z//;
+    $TParams=~s/\A<(.+)>\Z/$1/;
+    return ($Name, $TParams);
+}
+
+sub get_sub_ns($)
+{
+    my $Name = $_[0];
+    my @NS = ();
+    while(my $CPos = detect_center($Name, ":"))
+    {
+        push(@NS, substr($Name, 0, $CPos));
+        $Name = substr($Name, $CPos);
+        $Name=~s/\A:://;
+    }
+    return (join("::", @NS), $Name);
+}
+
+sub mangle_ns($$$)
+{
+    my ($Name, $LibVersion, $Repl) = @_;
+    if(my $Tid = $TName_Tid{$LibVersion}{$Name})
+    {
+        my $Mangled = mangle_param($Tid, $LibVersion, $Repl);
+        $Mangled=~s/\AN(.+)E\Z/$1/;
+        return $Mangled;
+        
+    }
+    else
+    {
+        my ($MangledNS, $SubNS) = ("", "");
+        ($SubNS, $Name) = get_sub_ns($Name);
+        if($SubNS) {
+            $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
+        }
+        $MangledNS .= length($Name).$Name;
+        add_substitution($MangledNS, $Repl, 0);
+        return $MangledNS;
+    }
+}
+
+sub mangle_param($$$)
+{
+    my ($PTid, $LibVersion, $Repl) = @_;
+    my ($MPrefix, $Mangled) = ("", "");
+    my %ReplCopy = %{$Repl};
+    my %BaseType = get_BaseType($Tid_TDid{$LibVersion}{$PTid}, $PTid, $LibVersion);
+    my $BaseType_Name = $BaseType{"Name"};
+    if(not $BaseType_Name) {
+        return "";
+    }
+    my ($ShortName, $TmplParams) = template_base($BaseType_Name);
+    my $Suffix = get_BaseTypeQual($Tid_TDid{$LibVersion}{$PTid}, $PTid, $LibVersion);
+    while($Suffix=~s/\s*(const|volatile|restrict)\Z//g){};
+    while($Suffix=~/(&|\*|const)\Z/)
+    {
+        if($Suffix=~s/[ ]*&\Z//) {
+            $MPrefix .= "R";
+        }
+        if($Suffix=~s/[ ]*\*\Z//) {
+            $MPrefix .= "P";
+        }
+        if($Suffix=~s/[ ]*const\Z//)
+        {
+            if($MPrefix=~/R|P/
+            or $Suffix=~/&|\*/) {
+                $MPrefix .= "K";
+            }
+        }
+        if($Suffix=~s/[ ]*volatile\Z//) {
+            $MPrefix .= "V";
+        }
+        #if($Suffix=~s/[ ]*restrict\Z//) {
+            #$MPrefix .= "r";
+        #}
+    }
+    if(my $Token = $IntrinsicMangling{$BaseType_Name}) {
+        $Mangled .= $Token;
+    }
+    elsif($BaseType{"Type"}=~/(Class|Struct|Union|Enum)/)
+    {
+        my @TParams = getTParams($BaseType{"TDid"}, $BaseType{"Tid"});
+        if(not @TParams and $TmplParams)
+        { # support for old ABI dumps
+            @TParams = separate_params($TmplParams, 0);
+        }
+        my $MangledNS = "";
+        my ($SubNS, $SName) = get_sub_ns($ShortName);
+        if($SubNS) {
+            $MangledNS .= mangle_ns($SubNS, $LibVersion, $Repl);
+        }
+        $MangledNS .= length($SName).$SName;
+        if(@TParams) {
+            add_substitution($MangledNS, $Repl, 0);
+        }
+        $Mangled .= "N".$MangledNS;
+        if(@TParams)
+        { # templates
+            $Mangled .= "I";
+            foreach my $TParam (@TParams) {
+                $Mangled .= mangle_template_param($TParam, $LibVersion, $Repl);
+            }
+            $Mangled .= "E";
+        }
+        $Mangled .= "E";
+    }
+    elsif($BaseType{"Type"}=~/(FuncPtr|MethodPtr)/)
+    {
+        if($BaseType{"Type"} eq "MethodPtr") {
+            $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl)."F";
+        }
+        else {
+            $Mangled .= "PF";
+        }
+        $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
+        my @Params = keys(%{$BaseType{"Param"}});
+        foreach my $Num (sort {int($a)<=>int($b)} @Params) {
+            $Mangled .= mangle_param($BaseType{"Param"}{$Num}{"type"}, $LibVersion, $Repl);
+        }
+        if(not @Params) {
+            $Mangled .= "v";
+        }
+        $Mangled .= "E";
+    }
+    elsif($BaseType{"Type"} eq "FieldPtr")
+    {
+        $Mangled .= "M".mangle_param($BaseType{"Class"}, $LibVersion, $Repl);
+        $Mangled .= mangle_param($BaseType{"Return"}, $LibVersion, $Repl);
+    }
+    $Mangled = $MPrefix.$Mangled;# add prefix (RPK)
+    if(my $Optimized = write_substitution($Mangled, \%ReplCopy))
+    {
+        if($Mangled eq $Optimized)
+        {
+            if($ShortName!~/::/)
+            { # remove "N ... E"
+                if($MPrefix) {
+                    $Mangled=~s/\A($MPrefix)N(.+)E\Z/$1$2/g;
+                }
+                else {
+                    $Mangled=~s/\AN(.+)E\Z/$1/g;
+                }
+            }
+        }
+        else {
+            $Mangled = $Optimized;
+        }
+    }
+    add_substitution($Mangled, $Repl, 1);
+    return $Mangled;
+}
+
+sub mangle_template_param($$$)
+{ # types + literals
+    my ($TParam, $LibVersion, $Repl) = @_;
+    if(my $TPTid = $TName_Tid{$LibVersion}{$TParam}) {
+        return mangle_param($TPTid, $LibVersion, $Repl);
+    }
+    elsif($TParam=~/\A(\d+)(\w+)\Z/)
+    { # class_name<1u>::method(...)
+        return "L".$IntrinsicMangling{$ConstantSuffixR{$2}}.$1."E";
+    }
+    elsif($TParam=~/\A\(([\w ]+)\)(\d+)\Z/)
+    { # class_name<(signed char)1>::method(...)
+        return "L".$IntrinsicMangling{$1}.$2."E";
+    }
+    elsif($TParam eq "true")
+    { # class_name<true>::method(...)
+        return "Lb1E";
+    }
+    elsif($TParam eq "false")
+    { # class_name<true>::method(...)
+        return "Lb0E";
+    }
+    else { # internal error
+        return length($TParam).$TParam;
+    }
+}
+
+sub add_substitution($$$)
+{
+    my ($Value, $Repl, $Rec) = @_;
+    if($Rec)
+    { # subtypes
+        my @Subs = ($Value);
+        while($Value=~s/\A(R|P|K)//) {
+            push(@Subs, $Value);
+        }
+        foreach (reverse(@Subs)) {
+            add_substitution($_, $Repl, 0);
+        }
+        return;
+    }
+    return if($Value=~/\AS(\d*)_\Z/);
+    $Value=~s/\AN(.+)E\Z/$1/g;
+    return if(defined $Repl->{$Value});
+    return if(length($Value)<=1);
+    return if($StdcxxMangling{$Value});
+    # check for duplicates
+    my $Base = $Value;
+    foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
+    {
+        my $Num = $Repl->{$Type};
+        my $Replace = macro_mangle($Num);
+        $Base=~s/\Q$Replace\E/$Type/;
+    }
+    if(my $OldNum = $Repl->{$Base})
+    {
+        $Repl->{$Value} = $OldNum;
+        return;
+    }
+    my @Repls = sort {$b<=>$a} values(%{$Repl});
+    if(@Repls) {
+        $Repl->{$Value} = $Repls[0]+1;
+    }
+    else {
+        $Repl->{$Value} = -1;
+    }
+    # register duplicates
+    # upward
+    my $Base = $Value;
+    foreach my $Type (sort {$Repl->{$a}<=>$Repl->{$b}} sort keys(%{$Repl}))
+    {
+        next if($Base eq $Type);
+        my $Num = $Repl->{$Type};
+        my $Replace = macro_mangle($Num);
+        $Base=~s/\Q$Type\E/$Replace/;
+        $Repl->{$Base} = $Repl->{$Value};
+    }
+}
+
+sub macro_mangle($)
+{
+    my $Num = $_[0];
+    if($Num==-1) {
+        return "S_";
+    }
+    else
+    {
+        my $Code = "";
+        if($Num<10)
+        { # S0_, S1_, S2_, ...
+            $Code = $Num;
+        }
+        elsif($Num>=10 and $Num<=35)
+        { # SA_, SB_, SC_, ...
+            $Code = chr(55+$Num);
+        }
+        else
+        { # S10_, S11_, S12_
+            $Code = $Num-26; # 26 is length of english alphabet
+        }
+        return "S".$Code."_";
+    }
+}
+
+sub write_stdcxx_substitution($)
+{
+    my $Mangled = $_[0];
+    if($StdcxxMangling{$Mangled}) {
+        return $StdcxxMangling{$Mangled};
+    }
+    else
+    {
+        my @Repls = keys(%StdcxxMangling);
+        @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
+        foreach my $MangledType (@Repls)
+        {
+            my $Replace = $StdcxxMangling{$MangledType};
+            #if($Mangled!~/$Replace/) {
+                $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
+                $Mangled=~s/\Q$MangledType\E/$Replace/g;
+            #}
+        }
+    }
+    return $Mangled;
+}
+
+sub write_substitution($$)
+{
+    my ($Mangled, $Repl) = @_;
+    if(defined $Repl->{$Mangled}
+    and my $MnglNum = $Repl->{$Mangled}) {
+        $Mangled = macro_mangle($MnglNum);
+    }
+    else
+    {
+        my @Repls = keys(%{$Repl});
+        #@Repls = sort {$Repl->{$a}<=>$Repl->{$b}} @Repls;
+        # FIXME: how to apply replacements? by num or by pos
+        @Repls = sort {length($b)<=>length($a)} sort {$b cmp $a} @Repls;
+        foreach my $MangledType (@Repls)
+        {
+            my $Replace = macro_mangle($Repl->{$MangledType});
+            if($Mangled!~/$Replace/) {
+                $Mangled=~s/N\Q$MangledType\EE/$Replace/g;
+                $Mangled=~s/\Q$MangledType\E/$Replace/g;
+            }
+        }
+    }
+    return $Mangled;
+}
+
+sub delete_keywords($)
+{
+    my $TypeName = $_[0];
+    $TypeName=~s/(\W|\A)(enum |struct |union |class )/$1/g;
+    return $TypeName;
+}
+
+my %Intrinsic_Keywords = map {$_=>1} (
+    "true",
+    "false",
+    "_Bool",
+    "_Complex",
+    "const",
+    "int",
+    "long",
+    "void",
+    "short",
+    "float",
+    "volatile",
+    "restrict",
+    "unsigned",
+    "signed",
+    "char",
+    "double",
+    "class",
+    "struct",
+    "union",
+    "enum"
+);
+
+sub uncover_typedefs($$)
+{
+    my ($TypeName, $LibVersion) = @_;
+    return "" if(not $TypeName);
+    if(defined $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName}) {
+        return $Cache{"uncover_typedefs"}{$LibVersion}{$TypeName};
+    }
+    my ($TypeName_New, $TypeName_Pre) = (formatName($TypeName), "");
+    while($TypeName_New ne $TypeName_Pre)
+    {
+        $TypeName_Pre = $TypeName_New;
+        my $TypeName_Copy = $TypeName_New;
+        my %Words = ();
+        while($TypeName_Copy=~s/(\W|\A)([a-z_][\w:]*)(\W|\Z)//io)
+        {
+            my $Word = $2;
+            next if(not $Word or $Intrinsic_Keywords{$Word});
+            $Words{$Word} = 1;
+        }
+        foreach my $Word (keys(%Words))
+        {
+            my $BaseType_Name = $Typedef_BaseName{$LibVersion}{$Word};
+            next if(not $BaseType_Name);
+            next if($TypeName_New=~/(\A|\W)(struct|union|enum)\s\Q$Word\E(\W|\Z)/);
+            if($BaseType_Name=~/\([\*]+\)/)
+            { # FuncPtr
+                if($TypeName_New=~/\Q$Word\E(.*)\Z/)
+                {
+                    my $Type_Suffix = $1;
+                    $TypeName_New = $BaseType_Name;
+                    if($TypeName_New=~s/\(([\*]+)\)/($1 $Type_Suffix)/) {
+                        $TypeName_New = formatName($TypeName_New);
+                    }
+                }
+            }
+            else
+            {
+                if($TypeName_New=~s/(\W|\A)\Q$Word\E(\W|\Z)/$1$BaseType_Name$2/g) {
+                    $TypeName_New = formatName($TypeName_New);
+                }
+            }
+        }
+    }
+    return ($Cache{"uncover_typedefs"}{$LibVersion}{$TypeName} = $TypeName_New);
+}
+
+sub isInternal($)
+{
+    my $FuncInfoId = $_[0];
+    my $FuncInfo = $LibInfo{$Version}{"info"}{$_[0]};
+    return 0 if($FuncInfo!~/mngl[ ]*:[ ]*@(\d+) /);
+    my $FuncMnglNameInfoId = $1;
+    return ($LibInfo{$Version}{"info"}{$FuncMnglNameInfoId}=~/\*[ ]*INTERNAL[ ]*\*/);
+}
+
+sub set_Class_And_Namespace($)
+{
+    my $InfoId = $_[0];
+    my $FuncInfo = $LibInfo{$Version}{"info"}{$InfoId};
+    if($FuncInfo=~/scpe[ ]*:[ ]*@(\d+) /)
+    {
+        my $NameSpaceInfoId = $1;
+        if($LibInfo{$Version}{"info_type"}{$NameSpaceInfoId} eq "namespace_decl") {
+            $SymbolInfo{$Version}{$InfoId}{"NameSpace"} = getNameSpace($InfoId);
+        }
+        elsif($LibInfo{$Version}{"info_type"}{$NameSpaceInfoId} eq "record_type") {
+            $SymbolInfo{$Version}{$InfoId}{"Class"} = $NameSpaceInfoId;
+        }
+    }
+    if($SymbolInfo{$Version}{$InfoId}{"Class"}
+    or $SymbolInfo{$Version}{$InfoId}{"NameSpace"})
+    { # identify language
+        setLanguage($Version, "C++");
+    }
+}
+
+sub debugType($$)
+{
+    my ($Tid, $LibVersion) = @_;
+    my %Type = get_Type($Tid_TDid{$LibVersion}{$Tid}, $Tid, $LibVersion);
+    printMsg("INFO", Dumper(\%Type));
+}
+
+sub debugMangling($)
+{
+    my $LibVersion = $_[0];
+    my %Mangled = ();
+    foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
+    {
+        if(my $Mngl = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"})
+        {
+            if($Mngl=~/\A(_Z|\?)/) {
+                $Mangled{$Mngl}=$InfoId;
+            }
+        }
+    }
+    translateSymbols(keys(%Mangled), $LibVersion);
+    foreach my $Mngl (keys(%Mangled))
+    {
+        my $Unmngl1 = modelUnmangled($Mangled{$Mngl}, "GCC");
+        my $Unmngl2 = $tr_name{$Mngl};
+        if($Unmngl1 ne $Unmngl2) {
+            printMsg("INFO", "INCORRECT MANGLING:\n  $Mngl\n  $Unmngl1\n  $Unmngl2\n");
+        }
+    }
+}
+
+sub linkSymbol($)
+{ # link symbols from shared libraries
+  # with the symbols from header files
+    my $InfoId = $_[0];
+    if($SymbolInfo{$Version}{$InfoId}{"Lang"} eq "C")
+    { # extern "C"
+        return $SymbolInfo{$Version}{$InfoId}{"ShortName"};
+    }
+    # try to mangle symbol
+    if((not check_gcc_version($GCC_PATH, "4") and $SymbolInfo{$Version}{$InfoId}{"Class"})
+    or (check_gcc_version($GCC_PATH, "4") and not $SymbolInfo{$Version}{$InfoId}{"Class"}))
+    { # 1. GCC 3.x doesn't mangle class methods names in the TU dump (only functions and global data)
+      # 2. GCC 4.x doesn't mangle C++ functions in the TU dump (only class methods) except extern "C" functions
+        if($CheckHeadersOnly)
+        {
+            if(my $Mangled = mangle_symbol($InfoId, $Version, "GCC")) {
+                return $Mangled;
+            }
+        }
+        else
+        {
+            if(my $Mangled = $mangled_name_gcc{modelUnmangled($InfoId, "GCC")}) {
+                return correct_incharge($InfoId, $Version, $Mangled);
+            }
+        }
+    }
+    return "";
+}
+
+sub setLanguage($$)
+{
+    my ($LibVersion, $Lang) = @_;
+    if(not $UserLang) {
+        $COMMON_LANGUAGE{$LibVersion} = $Lang;
+    }
+}
+
+sub getSymbolInfo($)
+{
+    my $FuncInfoId = $_[0];
+    return if(isInternal($FuncInfoId));
+    ($SymbolInfo{$Version}{$FuncInfoId}{"Header"}, $SymbolInfo{$Version}{$FuncInfoId}{"Line"}) = getLocation($FuncInfoId);
+    if(not $SymbolInfo{$Version}{$FuncInfoId}{"Header"}
+    or isBuiltIn($SymbolInfo{$Version}{$FuncInfoId}{"Header"})) {
+        delete($SymbolInfo{$Version}{$FuncInfoId});
+        return;
+    }
+    setFuncAccess($FuncInfoId);
+    setFuncKind($FuncInfoId);
+    if($SymbolInfo{$Version}{$FuncInfoId}{"PseudoTemplate"}) {
+        delete($SymbolInfo{$Version}{$FuncInfoId});
+        return;
+    }
+    $SymbolInfo{$Version}{$FuncInfoId}{"Type"} = getFuncType($FuncInfoId);
+    $SymbolInfo{$Version}{$FuncInfoId}{"Return"} = getFuncReturn($FuncInfoId);
+    if(my $AddedTid = $MissedTypedef{$Version}{$SymbolInfo{$Version}{$FuncInfoId}{"Return"}}{"Tid"}) {
+        $SymbolInfo{$Version}{$FuncInfoId}{"Return"} = $AddedTid;
+    }
+    if(not $SymbolInfo{$Version}{$FuncInfoId}{"Return"}) {
+        delete($SymbolInfo{$Version}{$FuncInfoId}{"Return"});
+    }
+    $SymbolInfo{$Version}{$FuncInfoId}{"ShortName"} = getFuncShortName(getFuncOrig($FuncInfoId));
+    if($SymbolInfo{$Version}{$FuncInfoId}{"ShortName"}=~/\._/) {
+        delete($SymbolInfo{$Version}{$FuncInfoId});
+        return;
+    }
+    if(defined $TemplateInstance_Func{$Version}{$FuncInfoId})
+    {
+        my @TParams = getTParams_Func($FuncInfoId);
+        if(not @TParams) {
+            delete($SymbolInfo{$Version}{$FuncInfoId});
+            return;
+        }
+        my $PrmsInLine = join(", ", @TParams);
+        $SymbolInfo{$Version}{$FuncInfoId}{"ShortName"} .= "<".$PrmsInLine.">";
+        $SymbolInfo{$Version}{$FuncInfoId}{"ShortName"} = formatName($SymbolInfo{$Version}{$FuncInfoId}{"ShortName"});
+    }
+    else
+    { # support for GCC 3.4
+        $SymbolInfo{$Version}{$FuncInfoId}{"ShortName"}=~s/<.+>\Z//;
+    }
+    $SymbolInfo{$Version}{$FuncInfoId}{"MnglName"} = getFuncMnglName($FuncInfoId);
+    if($SymbolInfo{$Version}{$FuncInfoId}{"MnglName"}
+    and $SymbolInfo{$Version}{$FuncInfoId}{"MnglName"}!~/\A_Z/)
+    {
+        delete($SymbolInfo{$Version}{$FuncInfoId});
+        return;
+    }
+    if($SymbolInfo{$FuncInfoId}{"MnglName"} and not $STDCXX_TESTING)
+    { # stdc++ interfaces
+        if($SymbolInfo{$Version}{$FuncInfoId}{"MnglName"}=~/\A(_ZS|_ZNS|_ZNKS)/) {
+            delete($SymbolInfo{$Version}{$FuncInfoId});
+            return;
+        }
+    }
+    if(not $SymbolInfo{$Version}{$FuncInfoId}{"Destructor"})
+    { # destructors have an empty parameter list
+        my $Skip = setFuncParams($FuncInfoId);
+        if($CheckHeadersOnly and $Skip)
+        { # skip template symbols that cannot be
+          # filtered without access to the library
+            delete($SymbolInfo{$Version}{$FuncInfoId});
+            return;
+        }
+    }
+    set_Class_And_Namespace($FuncInfoId);
+    if(not $CheckHeadersOnly and $SymbolInfo{$Version}{$FuncInfoId}{"Type"} eq "Function"
+    and not $SymbolInfo{$Version}{$FuncInfoId}{"Class"}
+    and link_symbol($SymbolInfo{$Version}{$FuncInfoId}{"ShortName"}, $Version, "-Deps"))
+    { # functions (C++): not mangled in library, but are mangled in TU dump
+        if(not $SymbolInfo{$Version}{$FuncInfoId}{"MnglName"}
+        or not link_symbol($SymbolInfo{$Version}{$FuncInfoId}{"MnglName"}, $Version, "-Deps")) {
+            $SymbolInfo{$Version}{$FuncInfoId}{"MnglName"} = $SymbolInfo{$Version}{$FuncInfoId}{"ShortName"};
+        }
+    }
+    if($LibInfo{$Version}{"info"}{$FuncInfoId}=~/ lang:[ ]*C /i) {
+        $SymbolInfo{$Version}{$FuncInfoId}{"Lang"} = "C";
+    }
+    if($UserLang eq "C")
+    { # --lang=C option
+        $SymbolInfo{$Version}{$FuncInfoId}{"MnglName"} = $SymbolInfo{$Version}{$FuncInfoId}{"ShortName"};
+    }
+    if($COMMON_LANGUAGE{$Version} eq "C++")
+    { # correct mangled & short names
+        if($SymbolInfo{$Version}{$FuncInfoId}{"ShortName"}=~/\A__(comp|base|deleting)_(c|d)tor\Z/)
+        { # support for old GCC versions: reconstruct real names for constructors and destructors
+            $SymbolInfo{$Version}{$FuncInfoId}{"ShortName"}=getNameByInfo(getTypeDeclId($SymbolInfo{$Version}{$FuncInfoId}{"Class"}));
+            $SymbolInfo{$Version}{$FuncInfoId}{"ShortName"}=~s/<.+>\Z//;
+        }
+        if(not $SymbolInfo{$Version}{$FuncInfoId}{"MnglName"})
+        { # try to mangle symbol (link with libraries)
+            if(my $Mangled = linkSymbol($FuncInfoId)) {
+                $SymbolInfo{$Version}{$FuncInfoId}{"MnglName"} = $Mangled;
+            }
+        }
+        if($OStarget eq "windows")
+        { # link MS C++ symbols from library with GCC symbols from headers
+            if(my $Mangled = $mangled_name{$Version}{modelUnmangled($FuncInfoId, "MSVC")})
+            { # exported symbols
+                $SymbolInfo{$Version}{$FuncInfoId}{"MnglName"} = $Mangled;
+            }
+            elsif(my $Mangled = mangle_symbol($FuncInfoId, $Version, "MSVC"))
+            { # pure virtual symbols
+                $SymbolInfo{$Version}{$FuncInfoId}{"MnglName"} = $Mangled;
+            }
+        }
+    }
+    if(not $SymbolInfo{$Version}{$FuncInfoId}{"MnglName"})
+    { # can't detect symbol name
+        delete($SymbolInfo{$Version}{$FuncInfoId});
+        return;
+    }
+    if(getFuncSpec($FuncInfoId) eq "Virt")
+    { # virtual methods
+        $SymbolInfo{$Version}{$FuncInfoId}{"Virt"} = 1;
+    }
+    if(getFuncSpec($FuncInfoId) eq "PureVirt")
+    { # pure virtual methods
+        $SymbolInfo{$Version}{$FuncInfoId}{"PureVirt"} = 1;
+    }
+    if(isInline($FuncInfoId)) {
+        $SymbolInfo{$Version}{$FuncInfoId}{"InLine"} = 1;
+    }
+    if($SymbolInfo{$Version}{$FuncInfoId}{"Constructor"}
+    and my $ClassId = $SymbolInfo{$Version}{$FuncInfoId}{"Class"})
+    {
+        if(not $SymbolInfo{$Version}{$FuncInfoId}{"InLine"}
+        and $LibInfo{$Version}{"info"}{$FuncInfoId}!~/ artificial /i)
+        { # inline or auto-generated constructor
+            delete($TypeInfo{$Version}{$Tid_TDid{$Version}{$ClassId}}{$ClassId}{"Copied"});
+        }
+    }
+    if(not link_symbol($SymbolInfo{$Version}{$FuncInfoId}{"MnglName"}, $Version, "-Deps")
+    and not $SymbolInfo{$Version}{$FuncInfoId}{"Virt"}
+    and not $SymbolInfo{$Version}{$FuncInfoId}{"PureVirt"})
+    { # removing src only and external non-virtual functions
+      # non-virtual template instances going here
+        if(not $CheckHeadersOnly) {
+            delete($SymbolInfo{$Version}{$FuncInfoId});
+            return;
+        }
+    }
+    if($SymbolInfo{$Version}{$FuncInfoId}{"Type"} eq "Method"
+    or $SymbolInfo{$Version}{$FuncInfoId}{"Constructor"}
+    or $SymbolInfo{$Version}{$FuncInfoId}{"Destructor"}
+    or $SymbolInfo{$Version}{$FuncInfoId}{"Class"})
+    {
+        if($SymbolInfo{$Version}{$FuncInfoId}{"MnglName"}!~/\A(_Z|\?)/) {
+            delete($SymbolInfo{$Version}{$FuncInfoId});
+            return;
+        }
+    }
+    if($SymbolInfo{$Version}{$FuncInfoId}{"MnglName"})
+    {
+        if($MangledNames{$Version}{$SymbolInfo{$Version}{$FuncInfoId}{"MnglName"}})
+        { # one instance for one mangled name only
+            delete($SymbolInfo{$Version}{$FuncInfoId});
+            return;
+        }
+        else {
+            $MangledNames{$Version}{$SymbolInfo{$Version}{$FuncInfoId}{"MnglName"}} = 1;
+        }
+    }
+    if($SymbolInfo{$Version}{$FuncInfoId}{"Constructor"}
+    or $SymbolInfo{$Version}{$FuncInfoId}{"Destructor"}) {
+        delete($SymbolInfo{$Version}{$FuncInfoId}{"Return"});
+    }
+    if($SymbolInfo{$Version}{$FuncInfoId}{"MnglName"}=~/\A(_Z|\?)/
+    and $SymbolInfo{$Version}{$FuncInfoId}{"Class"})
+    {
+        if($SymbolInfo{$Version}{$FuncInfoId}{"Type"} eq "Function")
+        { # static methods
+            $SymbolInfo{$Version}{$FuncInfoId}{"Static"} = 1;
+        }
+    }
+    if(getFuncLink($FuncInfoId) eq "Static") {
+        $SymbolInfo{$Version}{$FuncInfoId}{"Static"} = 1;
+    }
+    if($SymbolInfo{$Version}{$FuncInfoId}{"MnglName"}=~/\A(_Z|\?)/
+    and $tr_name{$SymbolInfo{$Version}{$FuncInfoId}{"MnglName"}}=~/\.\_\d/) {
+        delete($SymbolInfo{$Version}{$FuncInfoId});
+        return;
+    }
+    delete($SymbolInfo{$Version}{$FuncInfoId}{"Type"});
+    if($SymbolInfo{$Version}{$FuncInfoId}{"MnglName"}=~/\A_ZN(V|)K/) {
+        $SymbolInfo{$Version}{$FuncInfoId}{"Const"} = 1;
+    }
+    if($SymbolInfo{$Version}{$FuncInfoId}{"MnglName"}=~/\A_ZN(K|)V/) {
+        $SymbolInfo{$Version}{$FuncInfoId}{"Volatile"} = 1;
+    }
+}
+
+sub isInline($)
+{ # "body: undefined" in the tree
+  # -fkeep-inline-functions GCC option should be specified
+    my $FuncInfo = $LibInfo{$Version}{"info"}{$_[0]};
+    if($FuncInfo=~/ undefined /i) {
+        return 0;
+    }
+    return 1;
+}
+
+sub getTypeId($)
+{
+    if($LibInfo{$Version}{"info"}{$_[0]}=~/type[ ]*:[ ]*@(\d+) /) {
+        return $1;
+    }
+    else {
+        return "";
+    }
+}
+
+sub setTypeMemb($$)
+{
+    my ($TypeId, $TypeAttr) = @_;
+    my $TypeType = $TypeAttr->{"Type"};
+    my ($Position, $UnnamedPos) = (0, 0);
+    if($TypeType eq "Enum")
+    {
+        my $TypeMembInfoId = getEnumMembInfoId($TypeId);
+        while($TypeMembInfoId)
+        {
+            $TypeAttr->{"Memb"}{$Position}{"value"} = getEnumMembVal($TypeMembInfoId);
+            my $MembName = getEnumMembName($TypeMembInfoId);
+            $TypeAttr->{"Memb"}{$Position}{"name"} = getEnumMembName($TypeMembInfoId);
+            $EnumMembName_Id{$Version}{getTreeAttr($TypeMembInfoId, "valu")} = ($TypeAttr->{"NameSpace"})?$TypeAttr->{"NameSpace"}."::".$MembName:$MembName;
+            $TypeMembInfoId = getNextMembInfoId($TypeMembInfoId);
+            $Position += 1;
+        }
+    }
+    elsif($TypeType=~/\A(Struct|Class|Union)\Z/)
+    {
+        my $TypeMembInfoId = getStructMembInfoId($TypeId);
+        while($TypeMembInfoId)
+        {
+            if($LibInfo{$Version}{"info_type"}{$TypeMembInfoId} ne "field_decl") {
+                $TypeMembInfoId = getNextStructMembInfoId($TypeMembInfoId);
+                next;
+            }
+            my $StructMembName = getStructMembName($TypeMembInfoId);
+            if($StructMembName=~/_vptr\./)
+            {# virtual tables
+                $TypeMembInfoId = getNextStructMembInfoId($TypeMembInfoId);
+                next;
+            }
+            if(not $StructMembName)
+            { # unnamed fields
+                if($TypeAttr->{"Name"}!~/_type_info_pseudo/)
+                {
+                    my $UnnamedTid = getTreeAttr($TypeMembInfoId, "type");
+                    my $UnnamedTName = getNameByInfo(getTypeDeclId($UnnamedTid));
+                    if(isAnon($UnnamedTName))
+                    { # rename unnamed fields to unnamed0, unnamed1, ...
+                        $StructMembName = "unnamed".($UnnamedPos++);
+                    }
+                }
+            }
+            if(not $StructMembName)
+            { # unnamed fields and base classes
+                $TypeMembInfoId = getNextStructMembInfoId($TypeMembInfoId);
+                next;
+            }
+            my $MembTypeId = getTreeAttr($TypeMembInfoId, "type");
+            if(my $AddedTid = $MissedTypedef{$Version}{$MembTypeId}{"Tid"}) {
+                $MembTypeId = $AddedTid;
+            }
+            $TypeAttr->{"Memb"}{$Position}{"type"} = $MembTypeId;
+            $TypeAttr->{"Memb"}{$Position}{"name"} = $StructMembName;
+            if((my $Access = getTreeAccess($TypeMembInfoId)) ne "public")
+            {# marked only protected and private, public by default
+                $TypeAttr->{"Memb"}{$Position}{"access"} = $Access;
+            }
+            if(my $BFSize = getStructMembBitFieldSize($TypeMembInfoId)) {
+                $TypeAttr->{"Memb"}{$Position}{"bitfield"} = $BFSize;
+            }
+            else
+            { # set alignment for non-bit fields
+              # alignment for bitfields is always equal to 1 bit
+                $TypeAttr->{"Memb"}{$Position}{"algn"} = getAlgn($TypeMembInfoId)/$BYTE_SIZE;
+            }
+            $TypeMembInfoId = getNextStructMembInfoId($TypeMembInfoId);
+            $Position += 1;
+        }
+    }
+}
+
+sub setFuncParams($)
+{
+    my $FuncInfoId = $_[0];
+    my $ParamInfoId = getFuncParamInfoId($FuncInfoId);
+    my $FunctionType = getFuncType($FuncInfoId);
+    if($FunctionType eq "Method")
+    { # check type of "this" pointer
+        my $ObjectTypeId = getFuncParamType($ParamInfoId);
+        if(get_TypeName($ObjectTypeId, $Version)=~/(\A|\W)const(| volatile)\*const(\W|\Z)/) {
+            $SymbolInfo{$Version}{$FuncInfoId}{"Const"} = 1;
+        }
+        if(get_TypeName($ObjectTypeId, $Version)=~/(\A|\W)volatile(\W|\Z)/) {
+            $SymbolInfo{$Version}{$FuncInfoId}{"Volatile"} = 1;
+        }
+        $ParamInfoId = getNextElem($ParamInfoId);
+    }
+    my ($Position, $Vtt_Pos) = (0, -1);
+    while($ParamInfoId)
+    {
+        my $ParamTypeId = getFuncParamType($ParamInfoId);
+        my $ParamName = getFuncParamName($ParamInfoId);
+        if($TypeInfo{$Version}{getTypeDeclId($ParamTypeId)}{$ParamTypeId}{"Name"} eq "void") {
+            last;
+        }
+        if(my $AddedTid = $MissedTypedef{$Version}{$ParamTypeId}{"Tid"}) {
+            $ParamTypeId = $AddedTid;
+        }
+        my $PType = get_TypeAttr($ParamTypeId, $Version, "Type");
+        if(not $PType or $PType eq "Unknown") {
+            return 1;
+        }
+        if($ParamName eq "__vtt_parm"
+        and get_TypeName($ParamTypeId, $Version) eq "void const**")
+        {
+            $Vtt_Pos = $Position;
+            $ParamInfoId = getNextElem($ParamInfoId);
+            next;
+        }
+        $SymbolInfo{$Version}{$FuncInfoId}{"Param"}{$Position}{"type"} = $ParamTypeId;
+        $SymbolInfo{$Version}{$FuncInfoId}{"Param"}{$Position}{"name"} = $ParamName;
+        $SymbolInfo{$Version}{$FuncInfoId}{"Param"}{$Position}{"algn"} = getAlgn($ParamInfoId)/$BYTE_SIZE;
+        if(not $SymbolInfo{$Version}{$FuncInfoId}{"Param"}{$Position}{"name"}) {
+            $SymbolInfo{$Version}{$FuncInfoId}{"Param"}{$Position}{"name"} = "p".($Position+1);
+        }
+        if($LibInfo{$Version}{"info"}{$ParamInfoId}=~/spec:\s*register /)
+        { # foo(register type arg)
+            $SymbolInfo{$Version}{$FuncInfoId}{"Param"}{$Position}{"reg"} = 1;
+        }
+        $ParamInfoId = getNextElem($ParamInfoId);
+        $Position += 1;
+    }
+    if(detect_nolimit_args($FuncInfoId, $Vtt_Pos)) {
+        $SymbolInfo{$Version}{$FuncInfoId}{"Param"}{$Position}{"type"} = -1;
+    }
+    return 0;
+}
+
+sub detect_nolimit_args($$)
+{
+    my ($FuncInfoId, $Vtt_Pos) = @_;
+    my $FuncTypeId = getFuncTypeId($FuncInfoId);
+    my $ParamListElemId = getTreeAttr($FuncTypeId, "prms");
+    if(getFuncType($FuncInfoId) eq "Method") {
+        $ParamListElemId = getNextElem($ParamListElemId);
+    }
+    return 1 if(not $ParamListElemId);# foo(...)
+    my $HaveVoid = 0;
+    my $Position = 0;
+    while($ParamListElemId)
+    {
+        if($Vtt_Pos!=-1 and $Position==$Vtt_Pos)
+        {
+            $Vtt_Pos=-1;
+            $ParamListElemId = getNextElem($ParamListElemId);
+            next;
+        }
+        my $ParamTypeId = getTreeAttr($ParamListElemId, "valu");
+        if(my $PurpId = getTreeAttr($ParamListElemId, "purp"))
+        {
+            if($LibInfo{$Version}{"info_type"}{$PurpId} eq "integer_cst") {
+                $SymbolInfo{$Version}{$FuncInfoId}{"Param"}{$Position}{"default"} = getTreeValue($PurpId);
+            }
+            elsif($LibInfo{$Version}{"info_type"}{$PurpId} eq "string_cst") {
+                $SymbolInfo{$Version}{$FuncInfoId}{"Param"}{$Position}{"default"} = getNodeStrCst($PurpId);
+            }
+        }
+        if($TypeInfo{$Version}{getTypeDeclId($ParamTypeId)}{$ParamTypeId}{"Name"} eq "void") {
+            $HaveVoid = 1;
+            last;
+        }
+        elsif(not defined $SymbolInfo{$Version}{$FuncInfoId}{"Param"}{$Position}{"type"})
+        {
+            $SymbolInfo{$Version}{$FuncInfoId}{"Param"}{$Position}{"type"} = $ParamTypeId;
+            if(not $SymbolInfo{$Version}{$FuncInfoId}{"Param"}{$Position}{"name"}) {
+                $SymbolInfo{$Version}{$FuncInfoId}{"Param"}{$Position}{"name"} = "p".($Position+1);
+            }
+        }
+        $ParamListElemId = getNextElem($ParamListElemId);
+        $Position += 1;
+    }
+    return ($Position>=1 and not $HaveVoid);
+}
+
+sub getTreeAttr($$)
+{
+    my $Attr = $_[1];
+    if($LibInfo{$Version}{"info"}{$_[0]}=~/\Q$Attr\E\s*:\s*\@(\d+) /) {
+        return $1;
+    }
+    return "";
+}
+
+sub getTreeValue($)
+{
+    if($LibInfo{$Version}{"info"}{$_[0]}=~/low[ ]*:[ ]*([^ ]+) /) {
+        return $1;
+    }
+    return "";
+}
+
+sub getTreeAccess($)
+{
+    my $InfoId = $_[0];
+    if($LibInfo{$Version}{"info"}{$InfoId}=~/accs[ ]*:[ ]*([a-zA-Z]+) /)
+    {
+        my $Access = $1;
+        if($Access eq "prot") {
+            return "protected";
+        }
+        elsif($Access eq "priv") {
+            return "private";
+        }
+    }
+    elsif($LibInfo{$Version}{"info"}{$InfoId}=~/ protected /)
+    {# support for old GCC versions
+        return "protected";
+    }
+    elsif($LibInfo{$Version}{"info"}{$InfoId}=~/ private /)
+    {# support for old GCC versions
+        return "private";
+    }
+    return "public";
+}
+
+sub setFuncAccess($)
+{
+    my $FuncInfoId = $_[0];
+    my $Access = getTreeAccess($FuncInfoId);
+    if($Access eq "protected") {
+        $SymbolInfo{$Version}{$FuncInfoId}{"Protected"} = 1;
+    }
+    elsif($Access eq "private") {
+        $SymbolInfo{$Version}{$FuncInfoId}{"Private"} = 1;
+    }
+}
+
+sub setTypeAccess($$)
+{
+    my ($TypeId, $TypeAttr) = @_;
+    my $Access = getTreeAccess($TypeId);
+    if($Access eq "protected") {
+        $TypeAttr->{"Protected"} = 1;
+    }
+    elsif($Access eq "private") {
+        $TypeAttr->{"Private"} = 1;
+    }
+}
+
+sub setFuncKind($)
+{
+    my $FuncInfoId = $_[0];
+    if($LibInfo{$Version}{"info"}{$FuncInfoId}=~/pseudo tmpl/) {
+        $SymbolInfo{$Version}{$FuncInfoId}{"PseudoTemplate"} = 1;
+    }
+    elsif($LibInfo{$Version}{"info"}{$FuncInfoId}=~/ constructor /) {
+        $SymbolInfo{$Version}{$FuncInfoId}{"Constructor"} = 1;
+    }
+    elsif($LibInfo{$Version}{"info"}{$FuncInfoId}=~/ destructor /) {
+        $SymbolInfo{$Version}{$FuncInfoId}{"Destructor"} = 1;
+    }
+}
+
+sub getFuncSpec($)
+{
+    my $FuncInfoId = $_[0];
+    my $FuncInfo = $LibInfo{$Version}{"info"}{$FuncInfoId};
+    if($FuncInfo=~/spec[ ]*:[ ]*pure /) {
+        return "PureVirt";
+    }
+    elsif($FuncInfo=~/spec[ ]*:[ ]*virt /) {
+        return "Virt";
+    }
+    elsif($FuncInfo=~/ pure\s+virtual /)
+    {# support for old GCC versions
+        return "PureVirt";
+    }
+    elsif($FuncInfo=~/ virtual /)
+    {# support for old GCC versions
+        return "Virt";
+    }
+    return "";
+}
+
+sub getFuncClass($)
+{
+    my $FuncInfoId = $_[0];
+    my $FuncInfo = $LibInfo{$Version}{"info"}{$FuncInfoId};
+    if($FuncInfo=~/scpe[ ]*:[ ]*@(\d+) /) {
+        return $1;
+    }
+    else {
+        return "";
+    }
+}
+
+sub getFuncLink($)
+{
+    my $FuncInfoId = $_[0];
+    my $FuncInfo = $LibInfo{$Version}{"info"}{$FuncInfoId};
+    if($FuncInfo=~/link[ ]*:[ ]*static /) {
+        return "Static";
+    }
+    else {
+        if($FuncInfo=~/link[ ]*:[ ]*([a-zA-Z]+) /) {
+            return $1;
+        }
+        else {
+            return "";
+        }
+    }
+}
+
+sub getNextElem($)
+{
+    my $FuncInfoId = $_[0];
+    my $FuncInfo = $LibInfo{$Version}{"info"}{$FuncInfoId};
+    if($FuncInfo=~/(chan|chain)[ ]*:[ ]*@(\d+) /) {
+        return $2;
+    }
+    else {
+        return "";
+    }
+}
+
+sub getFuncParamInfoId($)
+{
+    my $FuncInfoId = $_[0];
+    my $FuncInfo = $LibInfo{$Version}{"info"}{$FuncInfoId};
+    if($FuncInfo=~/args[ ]*:[ ]*@(\d+) /) {
+        return $1;
+    }
+    else {
+        return "";
+    }
+}
+
+sub getFuncParamType($)
+{
+    my $ParamInfoId = $_[0];
+    my $ParamInfo = $LibInfo{$Version}{"info"}{$ParamInfoId};
+    if($ParamInfo=~/type[ ]*:[ ]*@(\d+) /) {
+        return $1;
+    }
+    else {
+        return "";
+    }
+}
+
+sub getFuncParamName($)
+{
+    my $ParamInfoId = $_[0];
+    my $ParamInfo = $LibInfo{$Version}{"info"}{$ParamInfoId};
+    if($ParamInfo=~/name[ ]*:[ ]*@(\d+) /) {
+        return getTreeStr($1);
+    }
+    return "";
+}
+
+sub getEnumMembInfoId($)
+{
+    if($LibInfo{$Version}{"info"}{$_[0]}=~/csts[ ]*:[ ]*@(\d+) /) {
+        return $1;
+    }
+    else {
+        return "";
+    }
+}
+
+sub getStructMembInfoId($)
+{
+    if($LibInfo{$Version}{"info"}{$_[0]}=~/flds[ ]*:[ ]*@(\d+) /) {
+        return $1;
+    }
+    else {
+        return "";
+    }
+}
+
+sub get_IntNameSpace($$)
+{
+    my ($Interface, $LibVersion) = @_;
+    return "" if(not $Interface or not $LibVersion);
+    if(defined $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion}) {
+        return $Cache{"get_IntNameSpace"}{$Interface}{$LibVersion};
+    }
+    my $Signature = get_Signature($Interface, $LibVersion);
+    if($Signature=~/\:\:/)
+    {
+        my $FounNameSpace = 0;
+        foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
+        {
+            if($Signature=~/(\A|\s+for\s+)\Q$NameSpace\E\:\:/) {
+                return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = $NameSpace);
+            }
+        }
+    }
+    else {
+        return ($Cache{"get_IntNameSpace"}{$Interface}{$LibVersion} = "");
+    }
+}
+
+sub parse_TypeNameSpace($$)
+{
+    my ($TypeName, $LibVersion) = @_;
+    return "" if(not $TypeName or not $LibVersion);
+    if(defined $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion}) {
+        return $Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion};
+    }
+    if($TypeName=~/\:\:/)
+    {
+        my $FounNameSpace = 0;
+        foreach my $NameSpace (sort {get_depth($b)<=>get_depth($a)} keys(%{$NestedNameSpaces{$LibVersion}}))
+        {
+            if($TypeName=~/\A\Q$NameSpace\E\:\:/) {
+                return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = $NameSpace);
+            }
+        }
+    }
+    else {
+        return ($Cache{"parse_TypeNameSpace"}{$TypeName}{$LibVersion} = "");
+    }
+}
+
+sub getNameSpace($)
+{
+    my $TypeInfoId = $_[0];
+    my $NameSpaceInfoId = getTreeAttr($TypeInfoId, "scpe");
+    return "" if(not $NameSpaceInfoId);
+    if($LibInfo{$Version}{"info_type"}{$NameSpaceInfoId} eq "namespace_decl")
+    {
+        my $NameSpaceInfo = $LibInfo{$Version}{"info"}{$NameSpaceInfoId};
+        if($NameSpaceInfo=~/name[ ]*:[ ]*@(\d+) /)
+        {
+            my $NameSpace = getTreeStr($1);
+            return "" if($NameSpace eq "::");
+            if(my $BaseNameSpace = getNameSpace($NameSpaceInfoId)) {
+                $NameSpace = $BaseNameSpace."::".$NameSpace;
+            }
+            $NestedNameSpaces{$Version}{$NameSpace} = 1;
+            return $NameSpace;
+        }
+        else {
+            return "";
+        }
+    }
+    elsif($LibInfo{$Version}{"info_type"}{$NameSpaceInfoId} eq "record_type")
+    {# inside data type
+        my ($Name, $NameNS) = getTrivialName(getTypeDeclId($NameSpaceInfoId), $NameSpaceInfoId);
+        return $Name;
+    }
+    else {
+        return "";
+    }
+}
+
+sub getNameSpaceId($)
+{
+    if($LibInfo{$Version}{"info"}{$_[0]}=~/scpe[ ]*:[ ]*\@(\d+)/) {
+        return $1;
+    }
+    else {
+        return "";
+    }
+}
+
+sub getEnumMembName($)
+{
+    if($LibInfo{$Version}{"info"}{$_[0]}=~/purp[ ]*:[ ]*\@(\d+)/) {
+        return getTreeStr($1);
+    }
+    else {
+        return "";
+    }
+}
+
+sub getStructMembName($)
+{
+    if($LibInfo{$Version}{"info"}{$_[0]}=~/name[ ]*:[ ]*\@(\d+)/) {
+        return getTreeStr($1);
+    }
+    else {
+        return "";
+    }
+}
+
+sub getEnumMembVal($)
+{
+    if($LibInfo{$Version}{"info"}{$_[0]}=~/valu[ ]*:[ ]*\@(\d+)/)
+    {
+        if($LibInfo{$Version}{"info"}{$1}=~/cnst[ ]*:[ ]*\@(\d+)/)
+        {# in newer versions of GCC the value is in the "const_decl->cnst" node
+            return getTreeValue($1);
+        }
+        else
+        {# some old versions of GCC (3.3) have the value in the "integer_cst" node
+            return getTreeValue($1);
+        }
+    }
+    return "";
+}
+
+sub getSize($)
+{
+    if($LibInfo{$Version}{"info"}{$_[0]}=~/size[ ]*:[ ]*\@(\d+)/) {
+        return getTreeValue($1);
+    }
+    else {
+        return 0;
+    }
+}
+
+sub getAlgn($)
+{
+    if($LibInfo{$Version}{"info"}{$_[0]}=~/algn[ ]*:[ ]*(\d+) /) {
+        return $1;
+    }
+    else {
+        return "";
+    }
+}
+
+sub getStructMembBitFieldSize($)
+{
+    if($LibInfo{$Version}{"info"}{$_[0]}=~/ bitfield /) {
+        return getSize($_[0]);
+    }
+    else {
+        return 0;
+    }
+}
+
+sub getNextMembInfoId($)
+{
+    if($LibInfo{$Version}{"info"}{$_[0]}=~/(chan|chain)[ ]*:[ ]*@(\d+) /) {
+        return $2;
+    }
+    else {
+        return "";
+    }
+}
+
+sub getNextStructMembInfoId($)
+{
+    if($LibInfo{$Version}{"info"}{$_[0]}=~/(chan|chain)[ ]*:[ ]*@(\d+) /) {
+        return $2;
+    }
+    else {
+        return "";
+    }
+}
+
+sub fieldHasName($)
+{
+    my $TypeMembInfoId = $_[0];
+    if($LibInfo{$Version}{"info_type"}{$TypeMembInfoId} eq "field_decl")
+    {
+        if($LibInfo{$Version}{"info"}{$TypeMembInfoId}=~/name[ ]*:[ ]*@(\d+) /) {
+            return $1;
+        }
+        else {
+            return "";
+        }
+    }
+    else {
+        return 0;
+    }
+}
+
+sub register_header($$)
+{ # input: header absolute path, relative path or name
+    my ($Header, $LibVersion) = @_;
+    return "" if(not $Header);
+    if(is_abs($Header) and not -f $Header) {
+        exitStatus("Access_Error", "can't access \'$Header\'");
+    }
+    return "" if(skip_header($Header, $LibVersion));
+    my $Header_Path = identify_header($Header, $LibVersion);
+    return "" if(not $Header_Path);
+    detect_header_includes($Header_Path, $LibVersion);
+    if(my $RHeader_Path = $Header_ErrorRedirect{$LibVersion}{$Header_Path})
+    {
+        return "" if(skip_header($RHeader_Path, $LibVersion));
+        $Header_Path = $RHeader_Path;
+        return "" if($Registered_Headers{$LibVersion}{$Header_Path}{"Identity"});
+    }
+    elsif($Header_ShouldNotBeUsed{$LibVersion}{$Header_Path}) {
+        return "";
+    }
+    $Registered_Headers{$LibVersion}{$Header_Path}{"Identity"} = get_filename($Header_Path);
+    $HeaderName_Paths{$LibVersion}{get_filename($Header_Path)}{$Header_Path} = 1;
+    if(($Header=~/\.(\w+)\Z/ and $1 ne "h")
+    or $Header!~/\.(\w+)\Z/)
+    { # hpp, hh
+        setLanguage($LibVersion, "C++");
+    }
+    if($CheckHeadersOnly
+    and $Header=~/(\A|\/)c\+\+(\/|\Z)/)
+    { # /usr/include/c++/4.6.1/...
+        $STDCXX_TESTING = 1;
+    }
+    return $Header_Path;
+}
+
+sub register_directory($$$)
+{
+    my ($Dir, $WithDeps, $LibVersion) = @_;
+    $Dir=~s/[\/\\]+\Z//g;
+    return if(not $LibVersion or not $Dir or not -d $Dir);
+    return if(skip_header($Dir, $LibVersion));
+    $Dir = get_abs_path($Dir);
+    my $Mode = "All";
+    if($WithDeps) {
+        if($RegisteredDirs{$LibVersion}{$Dir}{1}) {
+            return;
+        }
+        elsif($RegisteredDirs{$LibVersion}{$Dir}{0}) {
+            $Mode = "DepsOnly";
+        }
+    }
+    else {
+        if($RegisteredDirs{$LibVersion}{$Dir}{1}
+        or $RegisteredDirs{$LibVersion}{$Dir}{0}) {
+            return;
+        }
+    }
+    $Header_Dependency{$LibVersion}{$Dir} = 1;
+    $RegisteredDirs{$LibVersion}{$Dir}{$WithDeps} = 1;
+    if($Mode eq "DepsOnly")
+    {
+        foreach my $Path (cmd_find($Dir,"d","","")) {
+            $Header_Dependency{$LibVersion}{$Path} = 1;
+        }
+        return;
+    }
+    foreach my $Path (sort {length($b)<=>length($a)} cmd_find($Dir,"f","",""))
+    {
+        if($WithDeps)
+        { 
+            my $SubDir = $Path;
+            while(($SubDir = get_dirname($SubDir)) ne $Dir)
+            { # register all sub directories
+                $Header_Dependency{$LibVersion}{$SubDir} = 1;
+            }
+        }
+        next if(is_not_header($Path));
+        next if(ignore_path($Path));
+        next if(skip_header($Path, $LibVersion));
+        # Neighbors
+        foreach my $Part (get_path_prefixes($Path)) {
+            $Include_Neighbors{$LibVersion}{$Part} = $Path;
+        }
+    }
+    if(get_filename($Dir) eq "include")
+    { # search for "lib/include/" directory
+        my $LibDir = $Dir;
+        if($LibDir=~s/([\/\\])include\Z/$1lib/g and -d $LibDir) {
+            register_directory($LibDir, $WithDeps, $LibVersion);
+        }
+    }
+}
+
+sub parse_redirect($$$)
+{
+    my ($Content, $Path, $LibVersion) = @_;
+    if(defined $Cache{"parse_redirect"}{$LibVersion}{$Path}) {
+        return $Cache{"parse_redirect"}{$LibVersion}{$Path};
+    }
+    return "" if(not $Content);
+    my @Errors = ();
+    while($Content=~s/#\s*error\s+([^\n]+?)\s*(\n|\Z)//) {
+        push(@Errors, $1);
+    }
+    my $Redirect = "";
+    foreach (@Errors)
+    {
+        s/\s{2,}/ /g;
+        if(/(only|must\ include
+        |update\ to\ include
+        |replaced\ with
+        |replaced\ by|renamed\ to
+        |is\ in|use)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))/ix)
+        {
+            $Redirect = $2;
+            last;
+        }
+        elsif(/(include|use|is\ in)\ (<[^<>]+>|[\w\-\/\\]+\.($HEADER_EXT))\ instead/i)
+        {
+            $Redirect = $2;
+            last;
+        }
+        elsif(/this\ header\ should\ not\ be\ used
+         |programs\ should\ not\ directly\ include
+         |you\ should\ not\ (include|be\ (including|using)\ this\ (file|header))
+         |is\ not\ supported\ API\ for\ general\ use
+         |do\ not\ use
+         |should\ not\ be\ used
+         |cannot\ be\ included\ directly/ix and not /\ from\ /i) {
+            $Header_ShouldNotBeUsed{$LibVersion}{$Path} = 1;
+        }
+    }
+    $Redirect=~s/\A<//g;
+    $Redirect=~s/>\Z//g;
+    return ($Cache{"parse_redirect"}{$LibVersion}{$Path} = $Redirect);
+}
+
+sub parse_includes($$)
+{
+    my ($Content, $Path) = @_;
+    my %Includes = ();
+    while($Content=~s/#([ \t]*)(include|include_next|import)([ \t]*)(<|")([^<>"]+)(>|")//)
+    {# C/C++: include, Objective C/C++: import directive
+        my ($Header, $Method) = ($5, $4);
+        $Header = path_format($Header, $OSgroup);
+        if(($Method eq "\"" and -e joinPath(get_dirname($Path), $Header))
+        or is_abs($Header)) {
+        # include "path/header.h" that doesn't exist is equal to include <path/header.h>
+            $Includes{$Header} = -1;
+        }
+        else {
+            $Includes{$Header} = 1;
+        }
+    }
+    return \%Includes;
+}
+
+sub ignore_path($)
+{
+    my $Path = $_[0];
+    if($Path=~/\~\Z/)
+    {# skipping system backup files
+        return 1;
+    }
+    if($Path=~/(\A|[\/\\]+)(\.(svn|git|bzr|hg)|CVS)([\/\\]+|\Z)/)
+    {# skipping hidden .svn, .git, .bzr, .hg and CVS directories
+        return 1;
+    }
+    return 0;
+}
+
+sub sort_by_word($$)
+{
+    my ($ArrRef, $W) = @_;
+    return if(length($W)<2);
+    @{$ArrRef} = sort {get_filename($b)=~/\Q$W\E/i<=>get_filename($a)=~/\Q$W\E/i} @{$ArrRef};
+}
+
+sub natural_sorting($$)
+{
+    my ($H1, $H2) = @_;
+    $H1=~s/\.[a-z]+\Z//ig;
+    $H2=~s/\.[a-z]+\Z//ig;
+    my ($HDir1, $Hname1) = separate_path($H1);
+    my ($HDir2, $Hname2) = separate_path($H2);
+    my $Dirname1 = get_filename($HDir1);
+    my $Dirname2 = get_filename($HDir2);
+    if($H1 eq $H2) {
+        return 0;
+    }
+    elsif($H1=~/\A\Q$H2\E/) {
+        return 1;
+    }
+    elsif($H2=~/\A\Q$H1\E/) {
+        return -1;
+    }
+    elsif($HDir1=~/\Q$Hname1\E/i
+    and $HDir2!~/\Q$Hname2\E/i)
+    {# include/glib-2.0/glib.h
+        return -1;
+    }
+    elsif($HDir2=~/\Q$Hname2\E/i
+    and $HDir1!~/\Q$Hname1\E/i)
+    {# include/glib-2.0/glib.h
+        return 1;
+    }
+    elsif($Hname1=~/\Q$Dirname1\E/i
+    and $Hname2!~/\Q$Dirname2\E/i)
+    {# include/hildon-thumbnail/hildon-thumbnail-factory.h
+        return -1;
+    }
+    elsif($Hname2=~/\Q$Dirname2\E/i
+    and $Hname1!~/\Q$Dirname1\E/i)
+    {# include/hildon-thumbnail/hildon-thumbnail-factory.h
+        return 1;
+    }
+    elsif($Hname1=~/(config|lib)/i
+    and $Hname2!~/(config|lib)/i)
+    {# include/alsa/asoundlib.h
+        return -1;
+    }
+    elsif($Hname2=~/(config|lib)/i
+    and $Hname1!~/(config|lib)/i)
+    {# include/alsa/asoundlib.h
+        return 1;
+    }
+    elsif(checkRelevance($H1)
+    and not checkRelevance($H2))
+    {# libebook/e-book.h
+        return -1;
+    }
+    elsif(checkRelevance($H2)
+    and not checkRelevance($H1))
+    {# libebook/e-book.h
+        return 1;
+    }
+    else {
+        return (lc($H1) cmp lc($H2));
+    }
+}
+
+sub searchForHeaders($)
+{
+    my $LibVersion = $_[0];
+    # gcc standard include paths
+    find_gcc_cxx_headers($LibVersion);
+    # processing header paths
+    foreach my $Path (keys(%{$Descriptor{$LibVersion}{"IncludePaths"}}),
+    keys(%{$Descriptor{$LibVersion}{"AddIncludePaths"}}))
+    {
+        my $IPath = $Path;
+        if(not -e $Path) {
+            exitStatus("Access_Error", "can't access \'$Path\'");
+        }
+        elsif(-f $Path) {
+            exitStatus("Access_Error", "\'$Path\' - not a directory");
+        }
+        elsif(-d $Path)
+        {
+            $Path = get_abs_path($Path);
+            register_directory($Path, 0, $LibVersion);
+            if($Descriptor{$LibVersion}{"AddIncludePaths"}{$IPath}) {
+                $Add_Include_Paths{$LibVersion}{$Path} = 1;
+            }
+            else {
+                $Include_Paths{$LibVersion}{$Path} = 1;
+            }
+        }
+    }
+    if(keys(%{$Include_Paths{$LibVersion}})) {
+        $INC_PATH_AUTODETECT{$LibVersion} = 0;
+    }
+    # registering directories
+    foreach my $Path (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
+    {
+        next if(not -e $Path);
+        $Path = get_abs_path($Path);
+        $Path = path_format($Path, $OSgroup);
+        if(-d $Path) {
+            register_directory($Path, 1, $LibVersion);
+        }
+        elsif(-f $Path)
+        {
+            my $Dir = get_dirname($Path);
+            if(not $SystemPaths{"include"}{$Dir}
+            and not $LocalIncludes{$Dir})
+            {
+                register_directory($Dir, 1, $LibVersion);
+                if(my $OutDir = get_dirname($Dir))
+                { # registering the outer directory
+                    if(not $SystemPaths{"include"}{$OutDir}
+                    and not $LocalIncludes{$OutDir}) {
+                        register_directory($OutDir, 0, $LibVersion);
+                    }
+                }
+            }
+        }
+    }
+    # registering headers
+    my $Position = 0;
+    foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Headers"}))
+    {
+        if(is_abs($Dest) and not -e $Dest) {
+            exitStatus("Access_Error", "can't access \'$Dest\'");
+        }
+        $Dest = path_format($Dest, $OSgroup);
+        if(is_header($Dest, 1, $LibVersion))
+        {
+            if(my $HPath = register_header($Dest, $LibVersion)) {
+                $Registered_Headers{$LibVersion}{$HPath}{"Pos"} = $Position++;
+            }
+        }
+        elsif(-d $Dest)
+        {
+            my @Registered = ();
+            foreach my $Path (cmd_find($Dest,"f","",""))
+            {
+                next if(ignore_path($Path));
+                next if(not is_header($Path, 0, $LibVersion));
+                if(my $HPath = register_header($Path, $LibVersion)) {
+                    push(@Registered, $HPath);
+                }
+            }
+            @Registered = sort {natural_sorting($a, $b)} @Registered;
+            sort_by_word(\@Registered, $TargetLibraryShortName);
+            foreach my $Path (@Registered) {
+                $Registered_Headers{$LibVersion}{$Path}{"Pos"} = $Position++;
+            }
+        }
+        else {
+            exitStatus("Access_Error", "can't identify \'$Dest\' as a header file");
+        }
+    }
+    # preparing preamble headers
+    my $Preamble_Position=0;
+    foreach my $Header (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"IncludePreamble"}))
+    {
+        if(is_abs($Header) and not -f $Header) {
+            exitStatus("Access_Error", "can't access file \'$Header\'");
+        }
+        $Header = path_format($Header, $OSgroup);
+        if(my $Header_Path = is_header($Header, 1, $LibVersion))
+        {
+            next if(skip_header($Header_Path, $LibVersion));
+            $Include_Preamble{$LibVersion}{$Header_Path}{"Position"} = $Preamble_Position++;
+        }
+        else {
+            exitStatus("Access_Error", "can't identify \'$Header\' as a header file");
+        }
+    }
+    foreach my $Header_Name (keys(%{$HeaderName_Paths{$LibVersion}}))
+    { # set relative paths (for duplicates)
+        if(keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})>=2)
+        { # search for duplicates
+            my $FirstPath = (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))[0];
+            my $Prefix = get_dirname($FirstPath);
+            while($Prefix=~/\A(.+)[\/\\]+[^\/\\]+\Z/)
+            { # detect a shortest distinguishing prefix
+                my $NewPrefix = $1;
+                my %Identity = ();
+                foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
+                {
+                    if($Path=~/\A\Q$Prefix\E[\/\\]+(.*)\Z/) {
+                        $Identity{$Path} = $1;
+                    }
+                }
+                if(keys(%Identity)==keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}}))
+                { # all names are differend with current prefix
+                    foreach my $Path (keys(%{$HeaderName_Paths{$LibVersion}{$Header_Name}})) {
+                        $Registered_Headers{$LibVersion}{$Path}{"Identity"} = $Identity{$Path};
+                    }
+                    last;
+                }
+                $Prefix = $NewPrefix; # increase prefix
+            }
+        }
+    }
+    foreach my $HeaderName (keys(%{$Include_Order{$LibVersion}}))
+    { # ordering headers according to descriptor
+        my $PairName=$Include_Order{$LibVersion}{$HeaderName};
+        my ($Pos, $PairPos) = (-1, -1);
+        my ($Path, $PairPath) = ();
+        my @Paths = keys(%{$Registered_Headers{$LibVersion}});
+        @Paths = sort {int($Registered_Headers{$LibVersion}{$a}{"Pos"})<=>int($Registered_Headers{$LibVersion}{$b}{"Pos"})} @Paths;
+        foreach my $Header_Path (@Paths) 
+        {
+            if(get_filename($Header_Path) eq $PairName)
+            {
+                $PairPos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
+                $PairPath = $Header_Path;
+            }
+            if(get_filename($Header_Path) eq $HeaderName)
+            {
+                $Pos = $Registered_Headers{$LibVersion}{$Header_Path}{"Pos"};
+                $Path = $Header_Path;
+            }
+        }
+        if($PairPos!=-1 and $Pos!=-1
+        and int($PairPos)<int($Pos))
+        {
+            my %Tmp = %{$Registered_Headers{$LibVersion}{$Path}};
+            %{$Registered_Headers{$LibVersion}{$Path}} = %{$Registered_Headers{$LibVersion}{$PairPath}};
+            %{$Registered_Headers{$LibVersion}{$PairPath}} = %Tmp;
+        }
+    }
+    if(not keys(%{$Registered_Headers{$LibVersion}})) {
+        exitStatus("Error", "header files are not found in the ".$Descriptor{$LibVersion}{"Version"});
+    }
+}
+
+sub detect_real_includes($$)
+{
+    my ($AbsPath, $LibVersion) = @_;
+    return () if(not $LibVersion or not $AbsPath or not -e $AbsPath);
+    if($Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}
+    or keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
+        return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
+    }
+    my $Path = callPreprocessor($AbsPath, "", $LibVersion);
+    return () if(not $Path);
+    open(PREPROC, $Path);
+    while(<PREPROC>)
+    {
+        if(/#\s+\d+\s+"([^"]+)"[\s\d]*\n/)
+        {
+            my $Include = path_format($1, $OSgroup);
+            if($Include=~/\<(built\-in|internal|command(\-|\s)line)\>|\A\./) {
+                next;
+            }
+            if($Include eq $AbsPath) {
+                next;
+            }
+            $RecursiveIncludes{$LibVersion}{$AbsPath}{$Include} = 1;
+        }
+    }
+    close(PREPROC);
+    $Cache{"detect_real_includes"}{$LibVersion}{$AbsPath}=1;
+    return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
+}
+
+sub detect_header_includes($$)
+{
+    my ($Path, $LibVersion) = @_;
+    return if(not $LibVersion or not $Path or not -e $Path);
+    return if($Cache{"detect_header_includes"}{$LibVersion}{$Path});
+    my $Content = readFile($Path);
+    if($Content=~/#[ \t]*error[ \t]+/ and (my $Redirect = parse_redirect($Content, $Path, $LibVersion)))
+    {# detecting error directive in the headers
+        if(my $RedirectPath = identify_header($Redirect, $LibVersion))
+        {
+            if($RedirectPath=~/\/usr\/include\// and $Path!~/\/usr\/include\//) {
+                $RedirectPath = identify_header(get_filename($Redirect), $LibVersion);
+            }
+            if($RedirectPath ne $Path) {
+                $Header_ErrorRedirect{$LibVersion}{$Path} = $RedirectPath;
+            }
+        }
+    }
+    my $Inc = parse_includes($Content, $Path);
+    foreach my $Include (keys(%{$Inc}))
+    {# detecting includes
+        #if(is_not_header($Include))
+        #{ #include<*.c> and others
+            # next;
+        #}
+        $Header_Includes{$LibVersion}{$Path}{$Include} = $Inc->{$Include};
+    }
+    $Cache{"detect_header_includes"}{$LibVersion}{$Path} = 1;
+}
+
+sub simplify_path($)
+{
+    my $Path = $_[0];
+    while($Path=~s&([\/\\])[^\/\\]+[\/\\]\.\.[\/\\]&$1&){};
+    return $Path;
+}
+
+sub fromLibc($)
+{ # GLIBC header
+    my $Path = $_[0];
+    my ($Dir, $Name) = separate_path($Path);
+    if(get_filename($Dir)=~/\A(include|libc)\Z/ and $GlibcHeader{$Name})
+    { # /usr/include/{stdio.h, ...}
+      # epoc32/include/libc/{stdio.h, ...}
+        return 1;
+    }
+    if(isLibcDir($Dir)) {
+        return 1;
+    }
+    return 0;
+}
+
+sub isLibcDir($)
+{ # GLIBC directory
+    my $Dir = $_[0];
+    my ($OutDir, $Name) = separate_path($Dir);
+    if(get_filename($OutDir)=~/\A(include|libc)\Z/
+    and ($Name=~/\Aasm(|-.+)\Z/ or $GlibcDir{$Name}))
+    { # /usr/include/{sys,bits,asm,asm-*}/*.h
+        return 1;
+    }
+    return 0;
+}
+
+sub detect_recursive_includes($$)
+{
+    my ($AbsPath, $LibVersion) = @_;
+    return () if(not $AbsPath);
+    if(isCyclical(\@RecurInclude, $AbsPath)) {
+        return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
+    }
+    my ($AbsDir, $Name) = separate_path($AbsPath);
+    if(isLibcDir($AbsDir))
+    { # GLIBC internals
+        return ();
+    }
+    if(keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}})) {
+        return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
+    }
+    return () if($OSgroup ne "windows" and $Name=~/windows|win32|win64/i);
+    return () if($MAIN_CPP_DIR and $AbsPath=~/\A\Q$MAIN_CPP_DIR\E/ and not $STDCXX_TESTING);
+    push(@RecurInclude, $AbsPath);
+    if($DefaultGccPaths{$AbsDir}
+    or fromLibc($AbsPath))
+    { # check "real" (non-"model") include paths
+        my @Paths = detect_real_includes($AbsPath, $LibVersion);
+        pop(@RecurInclude);
+        return @Paths;
+    }
+    if(not keys(%{$Header_Includes{$LibVersion}{$AbsPath}})) {
+        detect_header_includes($AbsPath, $LibVersion);
+    }
+    foreach my $Include (keys(%{$Header_Includes{$LibVersion}{$AbsPath}}))
+    {
+        my $HPath = "";
+        if($Header_Includes{$LibVersion}{$AbsPath}{$Include}==-1)
+        { # for #include "..."
+            my $Candidate = joinPath($AbsDir, $Include);
+            if(-f $Candidate) {
+                $HPath = simplify_path($Candidate);
+            }
+        }
+        elsif($Header_Includes{$LibVersion}{$AbsPath}{$Include}==1
+        and $Include=~/[\/\\]/ and not find_in_defaults($Include))
+        { # search for the nearest header
+          # QtCore/qabstractanimation.h includes <QtCore/qobject.h>
+            my $Candidate = joinPath(get_dirname($AbsDir), $Include);
+            if(-f $Candidate) {
+                $HPath = $Candidate;
+            }
+        }
+        if(not $HPath) {
+            $HPath = identify_header($Include, $LibVersion);
+        }
+        next if(not $HPath);
+        if($HPath eq $AbsPath) {
+            next;
+        }
+        $RecursiveIncludes{$LibVersion}{$AbsPath}{$HPath} = 1;
+        if($Header_Includes{$LibVersion}{$AbsPath}{$Include}==1)
+        { # only include <...>, skip include "..." prefixes
+            $Header_Include_Prefix{$LibVersion}{$AbsPath}{$HPath}{get_dirname($Include)} = 1;
+        }
+        foreach my $IncPath (detect_recursive_includes($HPath, $LibVersion))
+        {
+            if($IncPath eq $AbsPath) {
+                next;
+            }
+            $RecursiveIncludes{$LibVersion}{$AbsPath}{$IncPath} = 1;
+            foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$HPath}{$IncPath}})) {
+                $Header_Include_Prefix{$LibVersion}{$AbsPath}{$IncPath}{$Prefix} = 1;
+            }
+        }
+        foreach my $Dep (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}}))
+        {
+            if($GlibcHeader{get_filename($Dep)} and keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}})>=2
+            and defined $Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""})
+            { # distinguish math.h from glibc and math.h from the tested library
+                delete($Header_Include_Prefix{$LibVersion}{$AbsPath}{$Dep}{""});
+                last;
+            }
+        }
+    }
+    pop(@RecurInclude);
+    return keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}});
+}
+
+sub find_in_framework($$$)
+{
+    my ($Header, $Framework, $LibVersion) = @_;
+    return "" if(not $Header or not $Framework or not $LibVersion);
+    if(defined $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header}) {
+        return $Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header};
+    }
+    foreach my $Dependency (sort {get_depth($a)<=>get_depth($b)} keys(%{$Header_Dependency{$LibVersion}}))
+    {
+        if(get_filename($Dependency) eq $Framework
+        and -f get_dirname($Dependency)."/".$Header) {
+            return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = get_dirname($Dependency));
+        }
+    }
+    return ($Cache{"find_in_framework"}{$LibVersion}{$Framework}{$Header} = "");
+}
+
+sub find_in_defaults($)
+{
+    my $Header = $_[0];
+    return "" if(not $Header);
+    if(defined $Cache{"find_in_defaults"}{$Header}) {
+        return $Cache{"find_in_defaults"}{$Header};
+    }
+    foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
+    (keys(%DefaultIncPaths), keys(%DefaultGccPaths), keys(%DefaultCppPaths), keys(%UserIncPath)))
+    {
+        next if(not $Dir);
+        if(-f $Dir."/".$Header) {
+            return ($Cache{"find_in_defaults"}{$Header}=$Dir);
+        }
+    }
+    return ($Cache{"find_in_defaults"}{$Header}="");
+}
+
+sub cmp_paths($$)
+{
+    my ($Path1, $Path2) = @_;
+    my @Parts1 = split(/[\/\\]/, $Path1);
+    my @Parts2 = split(/[\/\\]/, $Path2);
+    foreach my $Num (0 .. $#Parts1)
+    {
+        my $Part1 = $Parts1[$Num];
+        my $Part2 = $Parts2[$Num];
+        if($GlibcDir{$Part1}
+        and not $GlibcDir{$Part2}) {
+            return 1;
+        }
+        elsif($GlibcDir{$Part2}
+        and not $GlibcDir{$Part1}) {
+            return -1;
+        }
+        elsif($Part1=~/glib/
+        and $Part2!~/glib/) {
+            return 1;
+        }
+        elsif($Part1!~/glib/
+        and $Part2=~/glib/) {
+            return -1;
+        }
+        elsif(my $CmpRes = ($Part1 cmp $Part2)) {
+            return $CmpRes;
+        }
+    }
+    return 0;
+}
+
+sub checkRelevance($)
+{
+    my ($Path) = @_;
+    return 0 if(not $Path);
+    if($SystemRoot) {
+        $Path=~s/\A\Q$SystemRoot\E//g;
+    }
+    my ($Dir, $Name) = separate_path($Path);
+    $Name=~s/\.\w+\Z//g;# remove extension (.h)
+    my @Tokens = split(/[_\d\W]+/, $Name);
+    foreach (@Tokens)
+    {
+        next if(not $_);
+        if($Dir=~/(\A|lib|[_\d\W])\Q$_\E([_\d\W]|lib|\Z)/i
+        or length($_)>=4 and $Dir=~/\Q$_\E/i)
+        { # include/gupnp-1.0/libgupnp/gupnp-context.h
+          # include/evolution-data-server-1.4/libebook/e-book.h
+            return 1;
+        }
+    }
+    return 0;
+}
+
+sub checkFamily(@)
+{
+    my @Paths = @_;
+    return 1 if($#Paths<=0);
+    my %Prefix = ();
+    foreach my $Path (@Paths)
+    {
+        if($SystemRoot) {
+            $Path = cut_path_prefix($Path, $SystemRoot);
+        }
+        if(my $Dir = get_dirname($Path))
+        {
+            $Dir=~s/(\/[^\/]+?)[\d\.\-\_]+\Z/$1/g; # remove version suffix
+            $Prefix{$Dir} += 1;
+            $Prefix{get_dirname($Dir)} += 1;
+        }
+    }
+    foreach (sort keys(%Prefix))
+    {
+        if(get_depth($_)>=3
+        and $Prefix{$_}==$#Paths+1) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+sub isAcceptable($$$)
+{
+    my ($Header, $Candidate, $LibVersion) = @_;
+    my $HName = get_filename($Header);
+    if(get_dirname($Header))
+    { # with prefix
+        return 1;
+    }
+    if($HName=~/config|setup/i and $Candidate=~/[\/\\]lib\d*[\/\\]/)
+    { # allow to search for glibconfig.h in /usr/lib/glib-2.0/include/
+        return 1;
+    }
+    if(checkRelevance($Candidate))
+    { # allow to search for atk.h in /usr/include/atk-1.0/atk/
+        return 1;
+    }
+    if(checkFamily(getSystemHeaders($HName, $LibVersion)))
+    { # /usr/include/qt4/QtNetwork/qsslconfiguration.h
+      # /usr/include/qt4/Qt/qsslconfiguration.h
+        return 1;
+    }
+    if($OStarget eq "symbian")
+    {
+        if($Candidate=~/[\/\\]stdapis[\/\\]/) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+sub isRelevant($$$)
+{ # disallow to search for "abstract" headers in too deep directories
+    my ($Header, $Candidate, $LibVersion) = @_;
+    my $HName = get_filename($Header);
+    if($OStarget eq "symbian")
+    {
+        if($Candidate=~/[\/\\](tools|stlportv5)[\/\\]/) {
+            return 0;
+        }
+    }
+    if($OStarget ne "bsd") {
+        if($Candidate=~/[\/\\]include[\/\\]bsd[\/\\]/)
+        { # openssh: skip /usr/lib/bcc/include/bsd/signal.h
+            return 0;
+        }
+    }
+    if(not get_dirname($Header)
+    and $Candidate=~/[\/\\]wx[\/\\]/)
+    { # do NOT search in system /wx/ directory
+      # for headers without a prefix: sstream.h
+        return 0;
+    }
+    if($Candidate=~/c\+\+[\/\\]\d+/ and $MAIN_CPP_DIR
+    and $Candidate!~/\A\Q$MAIN_CPP_DIR\E/)
+    { # skip ../c++/3.3.3/ if using ../c++/4.5/
+        return 0;
+    }
+    if($Candidate=~/[\/\\]asm-/
+    and (my $Arch = getArch($LibVersion)) ne "unknown")
+    { # arch-specific header files
+        if($Candidate!~/[\/\\]asm-\Q$Arch\E/)
+        {# skip ../asm-arm/ if using x86 architecture
+            return 0;
+        }
+    }
+    my @Candidates = getSystemHeaders($HName, $LibVersion);
+    if($#Candidates==1)
+    { # unique header
+        return 1;
+    }
+    my @SCandidates = getSystemHeaders($Header, $LibVersion);
+    if($#SCandidates==1)
+    { # unique name
+        return 1;
+    }
+    my $SystemDepth = $SystemRoot?get_depth($SystemRoot):0;
+    if(get_depth($Candidate)-$SystemDepth>=5)
+    { # abstract headers in too deep directories
+      # sstream.h or typeinfo.h in /usr/include/wx-2.9/wx/
+        if(not isAcceptable($Header, $Candidate, $LibVersion)) {
+            return 0;
+        }
+    }
+    if($Header eq "parser.h"
+    and $Candidate!~/\/libxml2\//)
+    { # select parser.h from xml2 library
+        return 0;
+    }
+    if(not get_dirname($Header)
+    and keys(%{$SystemHeaders{$HName}})>=3)
+    { # many headers with the same name
+      # like thread.h included without a prefix
+        if(not checkFamily(@Candidates)) {
+            return 0;
+        }
+    }
+    return 1;
+}
+
+sub selectSystemHeader($$)
+{
+    my ($Header, $LibVersion) = @_;
+    return $Header if(-f $Header);
+    return "" if(is_abs($Header) and not -f $Header);
+    return "" if($Header=~/\A(atomic|config|configure|build|conf|setup)\.h\Z/i);
+    if($OSgroup ne "windows")
+    {
+        if(get_filename($Header)=~/windows|win32|win64|\A(dos|process|winsock|config-win)\.h\Z/i) {
+            return "";
+        }
+        elsif($Header=~/\A(mem)\.h\Z/)
+        { # pngconf.h include mem.h for __MSDOS__
+            return "";
+        }
+    }
+    if($OSgroup ne "solaris")
+    {
+        if($Header=~/\A(thread)\.h\Z/)
+        { # thread.h in Solaris
+            return "";
+        }
+    }
+    if(defined $Cache{"selectSystemHeader"}{$LibVersion}{$Header}) {
+        return $Cache{"selectSystemHeader"}{$LibVersion}{$Header};
+    }
+    foreach my $Path (keys(%{$SystemPaths{"include"}}))
+    { # search in default paths
+        if(-f $Path."/".$Header) {
+            return ($Cache{"selectSystemHeader"}{$LibVersion}{$Header} = joinPath($Path,$Header));
+        }
+    }
+    if(not keys(%SystemHeaders)) {
+        detectSystemHeaders();
+    }
+    foreach my $Candidate (sort {get_depth($a)<=>get_depth($b)}
+    sort {cmp_paths($b, $a)} getSystemHeaders($Header, $LibVersion))
+    {
+        if(isRelevant($Header, $Candidate, $LibVersion)) {
+            return ($Cache{"selectSystemHeader"}{$LibVersion}{$Header} = $Candidate);
+        }
+    }
+    return ($Cache{"selectSystemHeader"}{$LibVersion}{$Header} = ""); # error
+}
+
+sub getSystemHeaders($$)
+{
+    my ($Header, $LibVersion) = @_;
+    my @Candidates = ();
+    foreach my $Candidate (sort keys(%{$SystemHeaders{$Header}}))
+    {
+        if(skip_header($Candidate, $LibVersion)) {
+            next;
+        }
+        push(@Candidates, $Candidate);
+    }
+    return @Candidates;
+}
+
+sub cut_path_prefix($$)
+{
+    my ($Path, $Prefix) = @_;
+    return $Path if(not $Prefix);
+    $Prefix=~s/[\/\\]+\Z//;
+    $Path=~s/\A\Q$Prefix\E([\/\\]+|\Z)//;
+    return $Path;
+}
+
+sub is_default_include_dir($)
+{
+    my $Dir = $_[0];
+    $Dir=~s/[\/\\]+\Z//;
+    return ($DefaultGccPaths{$Dir} or $DefaultCppPaths{$Dir} or $DefaultIncPaths{$Dir});
+}
+
+sub identify_header($$)
+{
+    my ($Header, $LibVersion) = @_;
+    $Header=~s/\A(\.\.[\\\/])+//g;
+    if(defined $Cache{"identify_header"}{$Header}{$LibVersion}) {
+        return $Cache{"identify_header"}{$Header}{$LibVersion};
+    }
+    my $Path = identify_header_internal($Header, $LibVersion);
+    if(not $Path and $OSgroup eq "macos" and my $Dir = get_dirname($Header))
+    { # search in frameworks: "OpenGL/gl.h" is "OpenGL.framework/Headers/gl.h"
+        my $RelPath = "Headers\/".get_filename($Header);
+        if(my $HeaderDir = find_in_framework($RelPath, $Dir.".framework", $LibVersion)) {
+            $Path = joinPath($HeaderDir, $RelPath);
+        }
+    }
+    return ($Cache{"identify_header"}{$Header}{$LibVersion} = $Path);
+}
+
+sub identify_header_internal($$)
+{ # search for header by absolute path, relative path or name
+    my ($Header, $LibVersion) = @_;
+    return "" if(not $Header);
+    if(-f $Header)
+    { # it's relative or absolute path
+        return get_abs_path($Header);
+    }
+    elsif($GlibcHeader{$Header} and not $GLIBC_TESTING
+    and my $HeaderDir = find_in_defaults($Header))
+    { # search for libc headers in the /usr/include
+      # for non-libc target library before searching
+      # in the library paths
+        return joinPath($HeaderDir,$Header);
+    }
+    elsif(my $Path = $Include_Neighbors{$LibVersion}{$Header})
+    { # search in the target library paths
+        return $Path;
+    }
+    elsif($DefaultGccHeader{$Header})
+    { # search in the internal GCC include paths
+        return $DefaultGccHeader{$Header};
+    }
+    elsif(my $HeaderDir = find_in_defaults($Header))
+    { # search in the default GCC include paths
+        return joinPath($HeaderDir,$Header);
+    }
+    elsif($DefaultCppHeader{$Header})
+    { # search in the default G++ include paths
+        return $DefaultCppHeader{$Header};
+    }
+    elsif(my $AnyPath = selectSystemHeader($Header, $LibVersion))
+    { # search everywhere in the system
+        return $AnyPath;
+    }
+    else
+    { # cannot find anything
+        return "";
+    }
+}
+
+sub getLocation($)
+{
+    if($LibInfo{$Version}{"info"}{$_[0]}=~/srcp[ ]*:[ ]*([\w\-\<\>\.\+\/\\]+):(\d+) /) {
+        return ($1, $2);
+    }
+    else {
+        return ();
+    }
+}
+
+sub getTypeTypeByTypeId($)
+{
+    my $TypeId = $_[0];
+    my $TypeType = $LibInfo{$Version}{"info_type"}{$TypeId};
+    if($TypeType=~/integer_type|real_type|boolean_type|void_type|complex_type/)
+    {
+        return "Intrinsic";
+    }
+    elsif(isFuncPtr($TypeId)) {
+        return "FuncPtr";
+    }
+    elsif(isMethodPtr($TypeId)) {
+        return "MethodPtr";
+    }
+    elsif(isFieldPtr($TypeId)) {
+        return "FieldPtr";
+    }
+    elsif($TypeType eq "pointer_type") {
+        return "Pointer";
+    }
+    elsif($TypeType eq "reference_type") {
+        return "Ref";
+    }
+    elsif($TypeType eq "union_type") {
+        return "Union";
+    }
+    elsif($TypeType eq "enumeral_type") {
+        return "Enum";
+    }
+    elsif($TypeType eq "record_type") {
+        return "Struct";
+    }
+    elsif($TypeType eq "array_type") {
+        return "Array";
+    }
+    elsif($TypeType eq "complex_type") {
+        return "Intrinsic";
+    }
+    elsif($TypeType eq "function_type") {
+        return "FunctionType";
+    }
+    elsif($TypeType eq "method_type") {
+        return "MethodType";
+    }
+    else {
+        return "Unknown";
+    }
+}
+
+sub getNameByInfo($)
+{
+    return "" if($LibInfo{$Version}{"info"}{$_[0]}!~/name[ ]*:[ ]*@(\d+) /);
+    if($LibInfo{$Version}{"info"}{$1}=~/strg[ ]*:[ ]*(.*?)[ ]+lngt/)
+    {# short unsigned int (may include spaces)
+        return $1;
+    }
+    else {
+        return "";
+    }
+}
+
+sub getTreeStr($)
+{
+    my $Info = $LibInfo{$Version}{"info"}{$_[0]};
+    if($Info=~/strg[ ]*:[ ]*([^ ]*)/)
+    {
+        my $Str = $1;
+        if($C99Mode{$Version}
+        and $Str=~/\Ac99_(.+)\Z/) {
+            if($CppKeywords_A{$1}) {
+                $Str=$1;
+            }
+        }
+        return $Str;
+    }
+    else {
+        return "";
+    }
+}
+
+sub getVarShortName($)
+{
+    my $VarInfo = $LibInfo{$Version}{"info"}{$_[0]};
+    return "" if($VarInfo!~/name[ ]*:[ ]*@(\d+) /);
+    return getTreeStr($1);
+}
+
+sub getFuncShortName($)
+{
+    my $FuncInfo = $LibInfo{$Version}{"info"}{$_[0]};
+    if($FuncInfo=~/ operator /)
+    {
+        if($FuncInfo=~/ conversion /) {
+            return "operator ".get_TypeName($SymbolInfo{$Version}{$_[0]}{"Return"}, $Version);
+        }
+        else
+        {
+            return "" if($FuncInfo!~/ operator[ ]+([a-zA-Z]+) /);
+            return "operator".$Operator_Indication{$1};
+        }
+    }
+    else
+    {
+        return "" if($FuncInfo!~/name[ ]*:[ ]*@(\d+) /);
+        return getTreeStr($1);
+    }
+}
+
+sub getFuncMnglName($)
+{
+    my $FuncInfo = $LibInfo{$Version}{"info"}{$_[0]};
+    return "" if($FuncInfo!~/mngl[ ]*:[ ]*@(\d+) /);
+    return getTreeStr($1);
+}
+
+sub getFuncReturn($)
+{
+    my $FuncInfo = $LibInfo{$Version}{"info"}{$_[0]};
+    if($FuncInfo=~/type[ ]*:[ ]*@(\d+) /) {
+        if($LibInfo{$Version}{"info"}{$1}=~/retn[ ]*:[ ]*@(\d+) /) {
+            return $1;
+        }
+    }
+    return "";
+}
+
+sub getFuncOrig($)
+{
+    my $FuncInfo = $LibInfo{$Version}{"info"}{$_[0]};
+    if($FuncInfo=~/orig[ ]*:[ ]*@(\d+) /) {
+        return $1;
+    }
+    else {
+        return $_[0];
+    }
+}
+
+sub unmangleSymbol($)
+{
+    my $Symbol = $_[0];
+    my @Unmngl = unmangleArray($Symbol);
+    return $Unmngl[0];
+}
+
+sub unmangleArray(@)
+{
+    if(@_[0]=~/\A\?/)
+    { # MSVC mangling
+        my $UndNameCmd = get_CmdPath("undname");
+        if(not $UndNameCmd) {
+            exitStatus("Not_Found", "can't find \"undname\"");
+        }
+        writeFile("$TMP_DIR/unmangle", join("\n", @_));
+        return split(/\n/, `$UndNameCmd 0x8386 $TMP_DIR/unmangle`);
+    }
+    else
+    { # GCC mangling
+        my $CppFiltCmd = get_CmdPath("c++filt");
+        if(not $CppFiltCmd) {
+            exitStatus("Not_Found", "can't find c++filt in PATH");
+        }
+        my $Info = `$CppFiltCmd -h 2>&1`;
+        if($Info=~/\@<file>/)
+        {# new version of c++filt can take a file
+            my $NoStrip = "";
+            if($OSgroup eq "macos"
+            or $OSgroup eq "windows") {
+                $NoStrip = "-n";
+            }
+            writeFile("$TMP_DIR/unmangle", join("\n", @_));
+            return split(/\n/, `$CppFiltCmd $NoStrip \@\"$TMP_DIR/unmangle\"`);
+        }
+        else
+        { # old-style unmangling
+            if($#_>$MAX_COMMAND_LINE_ARGUMENTS) {
+                my @Half = splice(@_, 0, ($#_+1)/2);
+                return (unmangleArray(@Half), unmangleArray(@_))
+            }
+            else
+            {
+                my $NoStrip = "";
+                if($OSgroup eq "macos"
+                or $OSgroup eq "windows") {
+                    $NoStrip = "-n";
+                }
+                my $Strings = join(" ", @_);
+                return split(/\n/, `$CppFiltCmd $NoStrip $Strings`);
+            }
+        }
+    }
+}
+
+sub get_SignatureNoInfo($$)
+{
+    my ($Interface, $LibVersion) = @_;
+    if($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Interface}) {
+        return $Cache{"get_SignatureNoInfo"}{$LibVersion}{$Interface};
+    }
+    my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Interface);
+    my $Signature = $tr_name{$MnglName}?$tr_name{$MnglName}:$MnglName;
+    if($Interface=~/\A(_Z|\?)/)
+    { # C++
+        $Signature=~s/\Qstd::basic_string<char, std::char_traits<char>, std::allocator<char> >\E/std::string/g;
+        $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;
+    }
+    if(not $CheckObjectsOnly or $OSgroup=~/linux|bsd|beos/)
+    { # ELF format marks data as OBJECT
+        if($CompleteSignature{$LibVersion}{$Interface}{"Object"}) {
+            $Signature .= " [data]";
+        }
+        elsif($Interface!~/\A(_Z|\?)/) {
+            $Signature .= " (...)";
+        }
+    }
+    if(my $ChargeLevel = get_ChargeLevel($Interface, $LibVersion))
+    {
+        my $ShortName = substr($Signature, 0, detect_center($Signature, "("));
+        $Signature=~s/\A\Q$ShortName\E/$ShortName $ChargeLevel/g;
+    }
+    if($SymbolVersion) {
+        $Signature .= $VersionSpec.$SymbolVersion;
+    }
+    return ($Cache{"get_SignatureNoInfo"}{$LibVersion}{$Interface} = $Signature);
+}
+
+sub get_ChargeLevel($$)
+{
+    my ($Interface, $LibVersion) = @_;
+    return "" if($Interface!~/\A(_Z|\?)/);
+    if(defined $CompleteSignature{$LibVersion}{$Interface}
+    and $CompleteSignature{$LibVersion}{$Interface}{"Header"})
+    {
+        if($CompleteSignature{$LibVersion}{$Interface}{"Constructor"})
+        {
+            if($Interface=~/C1E/) {
+                return "[in-charge]";
+            }
+            elsif($Interface=~/C2E/) {
+                return "[not-in-charge]";
+            }
+        }
+        elsif($CompleteSignature{$LibVersion}{$Interface}{"Destructor"})
+        {
+            if($Interface=~/D1E/) {
+                return "[in-charge]";
+            }
+            elsif($Interface=~/D2E/) {
+                return "[not-in-charge]";
+            }
+            elsif($Interface=~/D0E/) {
+                return "[in-charge-deleting]";
+            }
+        }
+    }
+    else
+    {
+        if($Interface=~/C1E/) {
+            return "[in-charge]";
+        }
+        elsif($Interface=~/C2E/) {
+            return "[not-in-charge]";
+        }
+        elsif($Interface=~/D1E/) {
+            return "[in-charge]";
+        }
+        elsif($Interface=~/D2E/) {
+            return "[not-in-charge]";
+        }
+        elsif($Interface=~/D0E/) {
+            return "[in-charge-deleting]";
+        }
+    }
+    return "";
+}
+
+sub get_Signature($$)
+{
+    my ($Interface, $LibVersion) = @_;
+    if($Cache{"get_Signature"}{$LibVersion}{$Interface}) {
+        return $Cache{"get_Signature"}{$LibVersion}{$Interface};
+    }
+    my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Interface);
+    if(skipGlobalData($MnglName) or not $CompleteSignature{$LibVersion}{$Interface}{"Header"}) {
+        return get_SignatureNoInfo($Interface, $LibVersion);
+    }
+    my ($Func_Signature, @Param_Types_FromUnmangledName) = ();
+    my $ShortName = $CompleteSignature{$LibVersion}{$Interface}{"ShortName"};
+    if($Interface=~/\A(_Z|\?)/)
+    {
+        if(my $ClassId = $CompleteSignature{$LibVersion}{$Interface}{"Class"}) {
+            $Func_Signature = get_TypeName($ClassId, $LibVersion)."::".(($CompleteSignature{$LibVersion}{$Interface}{"Destructor"})?"~":"").$ShortName;
+        }
+        elsif(my $NameSpace = $CompleteSignature{$LibVersion}{$Interface}{"NameSpace"}) {
+            $Func_Signature = $NameSpace."::".$ShortName;
+        }
+        else {
+            $Func_Signature = $ShortName;
+        }
+        @Param_Types_FromUnmangledName = get_s_params($tr_name{$MnglName}, 0);
+    }
+    else {
+        $Func_Signature = $MnglName;
+    }
+    my @ParamArray = ();
+    foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{$LibVersion}{$Interface}{"Param"}}))
+    {
+        next if($Pos eq "");
+        my $ParamTypeId = $CompleteSignature{$LibVersion}{$Interface}{"Param"}{$Pos}{"type"};
+        next if(not $ParamTypeId);
+        my $ParamTypeName = get_TypeName($ParamTypeId, $LibVersion);
+        if(not $ParamTypeName) {
+            $ParamTypeName = $Param_Types_FromUnmangledName[$Pos];
+        }
+        foreach my $Typedef (keys(%ChangedTypedef))
+        {
+            my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
+            $ParamTypeName=~s/(\A|\W)\Q$Typedef\E(\W|\Z)/$1$Base$2/g;
+        }
+        if(my $ParamName = $CompleteSignature{$LibVersion}{$Interface}{"Param"}{$Pos}{"name"}) {
+            push(@ParamArray, create_member_decl($ParamTypeName, $ParamName));
+        }
+        else {
+            push(@ParamArray, $ParamTypeName);
+        }
+    }
+    if($CompleteSignature{$LibVersion}{$Interface}{"Data"}
+    or $CompleteSignature{$LibVersion}{$Interface}{"Object"}) {
+        $Func_Signature .= " [data]";
+    }
+    else
+    {
+        if(my $ChargeLevel = get_ChargeLevel($Interface, $LibVersion))
+        { # add [in-charge]
+            $Func_Signature .= " ".$ChargeLevel;
+        }
+        $Func_Signature .= " (".join(", ", @ParamArray).")";
+        if($CompleteSignature{$LibVersion}{$Interface}{"Const"}
+        or $Interface=~/\A_ZN(V|)K/) {
+            $Func_Signature .= " const";
+        }
+        if($CompleteSignature{$LibVersion}{$Interface}{"Volatile"}
+        or $Interface=~/\A_ZN(K|)V/) {
+            $Func_Signature .= " volatile";
+        }
+        if($CompleteSignature{$LibVersion}{$Interface}{"Static"}
+        and $Interface=~/\A(_Z|\?)/)
+        {# for static methods
+            $Func_Signature .= " [static]";
+        }
+    }
+    if(defined $ShowRetVal
+    and my $ReturnTId = $CompleteSignature{$LibVersion}{$Interface}{"Return"}) {
+        $Func_Signature .= ":".get_TypeName($ReturnTId, $LibVersion);
+    }
+    if($SymbolVersion) {
+        $Func_Signature .= $VersionSpec.$SymbolVersion;
+    }
+    return ($Cache{"get_Signature"}{$LibVersion}{$Interface} = $Func_Signature);
+}
+
+sub create_member_decl($$)
+{
+    my ($TName, $Member) = @_;
+    if($TName=~/\([\*]+\)/) {
+        $TName=~s/\(([\*]+)\)/\($1$Member\)/;
+        return $TName;
+    }
+    else
+    {
+        my @ArraySizes = ();
+        while($TName=~s/(\[[^\[\]]*\])\Z//) {
+            push(@ArraySizes, $1);
+        }
+        return $TName." ".$Member.join("", @ArraySizes);
+    }
+}
+
+sub getFuncType($)
+{
+    my $FuncInfo = $LibInfo{$Version}{"info"}{$_[0]};
+    return "" if($FuncInfo!~/type[ ]*:[ ]*@(\d+) /);
+    my $FuncTypeInfoId = $1;
+    my $FunctionType = $LibInfo{$Version}{"info_type"}{$FuncTypeInfoId};
+    if($FunctionType eq "method_type") {
+        return "Method";
+    }
+    elsif($FunctionType eq "function_type") {
+        return "Function";
+    }
+    else {
+        return $FunctionType;
+    }
+}
+
+sub getFuncTypeId($)
+{
+    my $FuncInfo = $LibInfo{$Version}{"info"}{$_[0]};
+    if($FuncInfo=~/type[ ]*:[ ]*@(\d+)( |\Z)/) {
+        return $1;
+    }
+    else {
+        return 0;
+    }
+}
+
+sub isNotAnon($) {
+    return (not isAnon($_[0]));
+}
+
+sub isAnon($)
+{# "._N" or "$_N" in older GCC versions
+    return ($_[0]=~/(\.|\$)\_\d+|anon\-/);
+}
+
+sub unmangled_Compact($)
+{ # Removes all non-essential (for C++ language) whitespace from a string.  If 
+  # the whitespace is essential it will be replaced with exactly one ' ' 
+  # character. Works correctly only for unmangled names.
+    my $Name = $_[0];
+    if(defined $Cache{"unmangled_Compact"}{$Name}) {
+        return $Cache{"unmangled_Compact"}{$Name};
+    }
+    # First, we reduce all spaces that we can
+    my $coms='[-()<>:*&~!|+=%@~"?.,/[^'."']";
+    my $coms_nobr='[-()<:*&~!|+=%@~"?.,'."']";
+    my $clos='[),;:\]]';
+    $_ = $Name;
+    s/^\s+//gm;
+    s/\s+$//gm;
+    s/((?!\n)\s)+/ /g;
+    s/(\w+)\s+($coms+)/$1$2/gm;
+    s/($coms+)\s+(\w+)/$1$2/gm;
+    s/(\w)\s+($clos)/$1$2/gm;
+    s/($coms+)\s+($coms+)/$1 $2/gm;
+    s/($coms_nobr+)\s+($coms+)/$1$2/gm;
+    s/($coms+)\s+($coms_nobr+)/$1$2/gm;
+    # don't forget about >> and <:.  In unmangled names global-scope modifier 
+    # is not used, so <: will always be a digraph and requires no special treatment.
+    # We also try to remove other parts that are better to be removed here than in other places
+    # double-cv
+    s/\bconst\s+const\b/const/gm;
+    s/\bvolatile\s+volatile\b/volatile/gm;
+    s/\bconst\s+volatile\b\s+const\b/const volatile/gm;
+    s/\bvolatile\s+const\b\s+volatile\b/const volatile/gm;
+    # Place cv in proper order
+    s/\bvolatile\s+const\b/const volatile/gm;
+    return ($Cache{"unmangled_Compact"}{$Name} = $_);
+}
+
+sub unmangled_PostProcess($)
+{
+    my $Name = $_[0];
+    $_ = $Name;
+    #s/\bunsigned int\b/unsigned/g;
+    s/\bshort unsigned int\b/unsigned short/g;
+    s/\bshort int\b/short/g;
+    s/\blong long unsigned int\b/unsigned long long/g;
+    s/\blong unsigned int\b/unsigned long/g;
+    s/\blong long int\b/long long/g;
+    s/\blong int\b/long/g;
+    s/\)const\b/\) const/g;
+    s/\blong long unsigned\b/unsigned long long/g;
+    s/\blong unsigned\b/unsigned long/g;
+    return $_;
+}
+
+sub formatName($)
+{# type name correction
+    my $Name = $_[0];
+    $Name=unmangled_Compact($Name);
+    $Name=unmangled_PostProcess($Name);
+    $Name=~s/>>/> >/g; # double templates
+    $Name=~s/(operator\s*)> >/$1>>/;
+    return $Name;
+}
+
+sub get_HeaderDeps($$)
+{
+    my ($AbsPath, $LibVersion) = @_;
+    return () if(not $AbsPath or not $LibVersion);
+    if(defined $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}) {
+        return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
+    }
+    my %IncDir = ();
+    detect_recursive_includes($AbsPath, $LibVersion);
+    foreach my $HeaderPath (keys(%{$RecursiveIncludes{$LibVersion}{$AbsPath}}))
+    {
+        next if(not $HeaderPath);
+        next if($MAIN_CPP_DIR and $HeaderPath=~/\A\Q$MAIN_CPP_DIR\E([\/\\]|\Z)/);
+        my $Dir = get_dirname($HeaderPath);
+        foreach my $Prefix (keys(%{$Header_Include_Prefix{$LibVersion}{$AbsPath}{$HeaderPath}}))
+        {
+            my $Dep = $Dir;
+            if($Prefix)
+            {
+                if($OSgroup eq "windows")
+                { # case insensitive seach on windows
+                    if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//ig) {
+                        next;
+                    }
+                }
+                elsif($OSgroup eq "macos")
+                { # seach in frameworks
+                    if(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
+                    {
+                        if($HeaderPath=~/(.+\.framework)\/Headers\/([^\/]+)/)
+                        {# frameworks
+                            my ($HFramework, $HName) = ($1, $2);
+                            $Dep = $HFramework;
+                        }
+                        else
+                        {# mismatch
+                            next;
+                        }
+                    }
+                }
+                elsif(not $Dep=~s/[\/\\]+\Q$Prefix\E\Z//g)
+                { # Linux, FreeBSD
+                    next;
+                }
+            }
+            if(not $Dep)
+            { # nothing to include
+                next;
+            }
+            if(is_default_include_dir($Dep))
+            { # included by the compiler
+                next;
+            }
+            if(get_depth($Dep)==1)
+            { # too short
+                next;
+            }
+            if(isLibcDir($Dep))
+            { # do NOT include /usr/include/{sys,bits}
+                next;
+            }
+            $IncDir{$Dep}=1;
+        }
+    }
+    $Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath} = sortIncPaths([keys(%IncDir)], $LibVersion);
+    return @{$Cache{"get_HeaderDeps"}{$LibVersion}{$AbsPath}};
+}
+
+sub sortIncPaths($$)
+{
+    my ($ArrRef, $LibVersion) = @_;
+    @{$ArrRef} = sort {$b cmp $a} @{$ArrRef};
+    @{$ArrRef} = sort {get_depth($a)<=>get_depth($b)} @{$ArrRef};
+    @{$ArrRef} = sort {$Header_Dependency{$LibVersion}{$b}<=>$Header_Dependency{$LibVersion}{$a}} @{$ArrRef};
+    return $ArrRef;
+}
+
+sub joinPath($$) {
+    return join($SLASH, @_);
+}
+
+sub get_namespace_additions($)
+{
+    my $NameSpaces = $_[0];
+    my ($Additions, $AddNameSpaceId) = ("", 1);
+    foreach my $NS (sort {$a=~/_/ <=> $b=~/_/} sort {lc($a) cmp lc($b)} keys(%{$NameSpaces}))
+    {
+        next if($SkipNameSpaces{$Version}{$NS});
+        next if(not $NS or $NameSpaces->{$NS}==-1);
+        next if($NS=~/(\A|::)iterator(::|\Z)/i);
+        next if($NS=~/\A__/i);
+        next if(($NS=~/\Astd::/ or $NS=~/\A(std|tr1|rel_ops|fcntl)\Z/) and not $STDCXX_TESTING);
+        $NestedNameSpaces{$Version}{$NS} = 1;# for future use in reports
+        my ($TypeDecl_Prefix, $TypeDecl_Suffix) = ();
+        my @NS_Parts = split(/::/, $NS);
+        next if($#NS_Parts==-1);
+        next if($NS_Parts[0]=~/\A(random|or)\Z/);
+        foreach my $NS_Part (@NS_Parts)
+        {
+            $TypeDecl_Prefix .= "namespace $NS_Part\{";
+            $TypeDecl_Suffix .= "}";
+        }
+        my $TypeDecl = $TypeDecl_Prefix."typedef int tmp_add_type_$AddNameSpaceId;".$TypeDecl_Suffix;
+        my $FuncDecl = "$NS\:\:tmp_add_type_$AddNameSpaceId tmp_add_func_$AddNameSpaceId(){return 0;};";
+        $Additions.="  $TypeDecl\n  $FuncDecl\n";
+        $AddNameSpaceId+=1;
+    }
+    return $Additions;
+}
+
+sub path_format($$)
+{# forward slash to pass into MinGW GCC
+    my ($Path, $Fmt) = @_;
+    if($Fmt eq "windows") {
+        $Path=~s/\//\\/g;
+        $Path=lc($Path);
+    }
+    else {
+        $Path=~s/\\/\//g;
+    }
+    return $Path;
+}
+
+sub inc_opt($$)
+{
+    my ($Path, $Style) = @_;
+    if($Style eq "GCC")
+    {# GCC options
+        if($OSgroup eq "windows")
+        {# to MinGW GCC
+            return "-I\"".path_format($Path, "unix")."\"";
+        }
+        elsif($OSgroup eq "macos"
+        and $Path=~/\.framework\Z/)
+        {# to Apple's GCC
+            return "-F".esc(get_dirname($Path));
+        }
+        else {
+            return "-I".esc($Path);
+        }
+    }
+    elsif($Style eq "CL") {
+        return "/I \"$Path\"";
+    }
+    return "";
+}
+
+sub platformSpecs($)
+{
+    my $LibVersion = $_[0];
+    my $Arch = getArch($LibVersion);
+    if($OStarget eq "symbian")
+    { # options for GCCE compiler
+        my %Symbian_Opts = map {$_=>1} (
+            "-D__GCCE__",
+            "-DUNICODE",
+            "-fexceptions",
+            "-D__SYMBIAN32__",
+            "-D__MARM_INTERWORK__",
+            "-D_UNICODE",
+            "-D__S60_50__",
+            "-D__S60_3X__",
+            "-D__SERIES60_3X__",
+            "-D__EPOC32__",
+            "-D__MARM__",
+            "-D__EABI__",
+            "-D__MARM_ARMV5__",
+            "-D__SUPPORT_CPP_EXCEPTIONS__",
+            "-march=armv5t",
+            "-mapcs",
+            "-mthumb-interwork",
+            "-DEKA2",
+            "-DSYMBIAN_ENABLE_SPLIT_HEADERS"
+        );
+        return join(" ", keys(%Symbian_Opts));
+    }
+    elsif($OSgroup eq "windows"
+    and get_dumpmachine($GCC_PATH)=~/mingw/i)
+    { # add options to MinGW compiler
+      # to simulate the MSVC compiler
+        my %MinGW_Opts = map {$_=>1} (
+            "-D_WIN32",
+            "-D_STDCALL_SUPPORTED",
+            "-D__int64=\"long long\"",
+            "-D__int32=int",
+            "-D__int16=short",
+            "-D__int8=char",
+            "-D__possibly_notnullterminated=\" \"",
+            "-D__nullterminated=\" \"",
+            "-D__nullnullterminated=\" \"",
+            "-D__w64=\" \"",
+            "-D__ptr32=\" \"",
+            "-D__ptr64=\" \"",
+            "-D__forceinline=inline",
+            "-D__inline=inline",
+            "-D__uuidof(x)=IID()",
+            "-D__try=",
+            "-D__except(x)=",
+            "-D__declspec(x)=__attribute__((x))",
+            "-D__pragma(x)=",
+            "-D_inline=inline",
+            "-D__forceinline=__inline",
+            "-D__stdcall=__attribute__((__stdcall__))",
+            "-D__cdecl=__attribute__((__cdecl__))",
+            "-D__fastcall=__attribute__((__fastcall__))",
+            "-D__thiscall=__attribute__((__thiscall__))",
+            "-D_stdcall=__attribute__((__stdcall__))",
+            "-D_cdecl=__attribute__((__cdecl__))",
+            "-D_fastcall=__attribute__((__fastcall__))",
+            "-D_thiscall=__attribute__((__thiscall__))",
+            "-DSHSTDAPI_(x)=x",
+            "-D_MSC_EXTENSIONS",
+            "-DSECURITY_WIN32",
+            "-D_MSC_VER=1500",
+            "-D_USE_DECLSPECS_FOR_SAL",
+            "-D__noop=\" \"",
+            "-DDECLSPEC_DEPRECATED=\" \"",
+            "-D__builtin_alignof(x)=__alignof__(x)",
+            "-DSORTPP_PASS");
+        if($Arch eq "x86") {
+            $MinGW_Opts{"-D_M_IX86=300"}=1;
+        }
+        elsif($Arch eq "x86_64") {
+            $MinGW_Opts{"-D_M_AMD64=300"}=1;
+        }
+        elsif($Arch eq "ia64") {
+            $MinGW_Opts{"-D_M_IA64=300"}=1;
+        }
+        return join(" ", keys(%MinGW_Opts));
+    }
+    return "";
+}
+
+my %C_Structure = map {$_=>1} (
+# FIXME: Can't separate union and struct data types before dumping,
+# so it sometimes cause compilation errors for unknown reason
+# when trying to declare TYPE* tmp_add_class_N
+# This is a list of such structures + list of other C structures
+    "sigval",
+    "sigevent",
+    "sigaction",
+    "sigvec",
+    "sigstack",
+    "timeval",
+    "timezone",
+    "rusage",
+    "rlimit",
+    "wait",
+    "flock",
+    "stat",
+    "_stat",
+    "stat32",
+    "_stat32",
+    "stat64",
+    "_stat64",
+    "_stati64",
+    "if_nameindex",
+    "usb_device",
+    "sigaltstack",
+    "sysinfo",
+    "timeLocale",
+    "tcp_debug",
+    "rpc_createerr",
+# Other C structures appearing in every dump
+    "timespec",
+    "random_data",
+    "drand48_data",
+    "_IO_marker",
+    "_IO_FILE",
+    "lconv",
+    "sched_param",
+    "tm",
+    "itimerspec",
+    "_pthread_cleanup_buffer",
+    "fd_set",
+    "siginfo"
+);
+
+sub getCompileCmd($$$)
+{
+    my ($Path, $Opt, $Inc) = @_;
+    my $GccCall = $GCC_PATH;
+    if($Opt) {
+        $GccCall .= " ".$Opt;
+    }
+    $GccCall .= " -x ";
+    if($OSgroup eq "macos") {
+        $GccCall .= "objective-";
+    }
+    if(check_gcc_version($GCC_PATH, "4"))
+    { # compile as "C++" header
+      # to obtain complete dump using GCC 4.0
+        $GccCall .= "c++-header";
+    }
+    else
+    { # compile as "C++" source
+      # GCC 3.3 cannot compile headers
+        $GccCall .= "c++";
+    }
+    if(my $Opts = platformSpecs($Version))
+    {# platform-specific options
+        $GccCall .= " ".$Opts;
+    }
+    # allow extra qualifications
+    # and other nonconformant code
+    $GccCall .= " -fpermissive -w";
+    if($NoStdInc)
+    {
+        $GccCall .= " -nostdinc";
+        $GccCall .= " -nostdinc++";
+    }
+    if($CompilerOptions{$Version})
+    { # user-defined options
+        $GccCall .= " ".$CompilerOptions{$Version};
+    }
+    $GccCall .= " \"$Path\"";
+    if($Inc)
+    { # include paths
+        $GccCall .= " ".$Inc;
+    }
+    return $GccCall;
+}
+
+sub getDump()
+{
+    if(not $GCC_PATH) {
+        exitStatus("Error", "internal error - GCC path is not set");
+    }
+    my %HeaderElems = (
+        # Types
+        "stdio.h" => ["FILE", "va_list"],
+        "stddef.h" => ["NULL"],
+        "stdint.h" => ["uint32_t", "int32_t", "uint64_t"],
+        "time.h" => ["time_t"],
+        "sys/types.h" => ["ssize_t", "u_int32_t", "u_short", "u_char",
+             "u_int", "off_t", "u_quad_t", "u_long", "size_t", "mode_t"],
+        "unistd.h" => ["gid_t", "uid_t"],
+        "stdbool.h" => ["_Bool"],
+        "rpc/xdr.h" => ["bool_t"],
+        "in_systm.h" => ["n_long", "n_short"],
+        # Fields
+        "arpa/inet.h" => ["fw_src", "ip_src"]
+    );
+    my %AutoPreamble = ();
+    foreach (keys(%HeaderElems)) {
+        foreach my $Elem (@{$HeaderElems{$_}}) {
+            $AutoPreamble{$Elem}=$_;
+        }
+    }
+    my $TmpHeaderPath = "$TMP_DIR/dump$Version.h";
+    my $MHeaderPath = $TmpHeaderPath;
+    open(LIB_HEADER, ">$TmpHeaderPath") || die ("can't open file \'$TmpHeaderPath\': $!\n");
+    if(my $AddDefines = $Descriptor{$Version}{"Defines"})
+    {
+        $AddDefines=~s/\n\s+/\n  /g;
+        print LIB_HEADER "\n  // add defines\n  ".$AddDefines."\n";
+    }
+    print LIB_HEADER "\n  // add includes\n";
+    my @PreambleHeaders = keys(%{$Include_Preamble{$Version}});
+    @PreambleHeaders = sort {int($Include_Preamble{$Version}{$a}{"Position"})<=>int($Include_Preamble{$Version}{$b}{"Position"})} @PreambleHeaders;
+    foreach my $Header_Path (@PreambleHeaders) {
+        print LIB_HEADER "  #include \"".path_format($Header_Path, "unix")."\"\n";
+    }
+    my @Headers = keys(%{$Registered_Headers{$Version}});
+    @Headers = sort {int($Registered_Headers{$Version}{$a}{"Pos"})<=>int($Registered_Headers{$Version}{$b}{"Pos"})} @Headers;
+    foreach my $Header_Path (@Headers)
+    {
+        next if($Include_Preamble{$Version}{$Header_Path});
+        print LIB_HEADER "  #include \"".path_format($Header_Path, "unix")."\"\n";
+    }
+    close(LIB_HEADER);
+    my $IncludeString = getIncString(getIncPaths(@PreambleHeaders, @Headers), "GCC");
+    if($Debug)
+    { # debug mode
+        writeFile($DEBUG_PATH{$Version}."/recursive-includes.txt", Dumper(\%RecursiveIncludes));
+        writeFile($DEBUG_PATH{$Version}."/include-paths.txt", Dumper($Cache{"get_HeaderDeps"}));
+        writeFile($DEBUG_PATH{$Version}."/includes.txt", Dumper(\%Header_Includes));
+        writeFile($DEBUG_PATH{$Version}."/default-includes.txt", Dumper(\%DefaultIncPaths));
+    }
+    # preprocessing stage
+    checkPreprocessedUnit(callPreprocessor($TmpHeaderPath, $IncludeString, $Version));
+    my $MContent = "";
+    my $PreprocessCmd = getCompileCmd($TmpHeaderPath, "-E", $IncludeString);
+    if($OStarget eq "windows"
+    and get_dumpmachine($GCC_PATH)=~/mingw/i
+    and $MinGWMode{$Version}!=-1)
+    { # modify headers to compile by MinGW
+        if(not $MContent)
+        { # preprocessing
+            $MContent = `$PreprocessCmd 2>$TMP_DIR/null`;
+        }
+        if($MContent=~s/__asm\s*(\{[^{}]*?\}|[^{};]*)//g)
+        { # __asm { ... }
+            $MinGWMode{$Version}=1;
+        }
+        if($MContent=~s/\s+(\/ \/.*?)\n/\n/g)
+        { # comments after preprocessing
+            $MinGWMode{$Version}=1;
+        }
+        if($MContent=~s/(\W)(0x[a-f]+|\d+)(i|ui)(8|16|32|64)(\W)/$1$2$5/g)
+        { # 0xffui8
+            $MinGWMode{$Version}=1;
+        }
+        if($MinGWMode{$Version}) {
+            printMsg("INFO", "Using MinGW compatibility mode");
+            $MHeaderPath = "$TMP_DIR/dump$Version.i";
+        }
+    }
+    if(($COMMON_LANGUAGE{$Version} eq "C" or $CheckHeadersOnly)
+    and $C99Mode{$Version}!=-1 and not $Cpp2003)
+    { # rename "C++" keywords in "C" code
+        if(not $MContent)
+        { # preprocessing
+            $MContent = `$PreprocessCmd 2>$TMP_DIR/null`;
+        }
+        my $RegExp_C = join("|", keys(%CppKeywords_C));
+        my $RegExp_F = join("|", keys(%CppKeywords_F));
+        my $RegExp_O = join("|", keys(%CppKeywords_O));
+        while($MContent=~s/(\A|\n[^\#\/\n][^\n]*?|\n)(\*\s*|\s+|\@|\,|\()($RegExp_C|$RegExp_F)(\s*(\,|\)|\;|\-\>|\.|\:\s*\d))/$1$2c99_$3$4/g)
+        { # MATCH:
+          # int foo(int new, int class, int (*new)(int));
+          # unsigned private: 8;
+          # DO NOT MATCH:
+          # #pragma GCC visibility push(default)
+            $C99Mode{$Version} = 1;
+        }
+        if($MContent=~s/([^\w\s]|\w\s+)(?<!operator )(delete)(\s*(\())/$1c99_$2$3/g)
+        { # MATCH:
+          # int delete(...);
+          # int explicit(...);
+          # DO NOT MATCH:
+          # void operator delete(...)
+            $C99Mode{$Version} = 1;
+        }
+        if($MContent=~s/(\s+)($RegExp_O)(\s*(\;|\:))/$1c99_$2$3/g)
+        { # MATCH:
+          # int bool;
+          # DO NOT MATCH:
+          # bool X;
+          # return *this;
+          # throw;
+            $C99Mode{$Version} = 1;
+        }
+        if($MContent=~s/(\s+)(operator)(\s*(\(\s*\)\s*[^\(\s]|\(\s*[^\)\s]))/$1c99_$2$3/g)
+        { # MATCH:
+          # int operator(...);
+          # DO NOT MATCH:
+          # int operator()(...);
+            $C99Mode{$Version} = 1;
+        }
+        if($MContent=~s/([^\w\(\,\s]\s*|\s+)(operator)(\s*(\,\s*[^\(\s]|\)))/$1c99_$2$3/g)
+        { # MATCH:
+          # int foo(int operator);
+          # int foo(int operator, int other);
+          # DO NOT MATCH:
+          # int operator,(...);
+            $C99Mode{$Version} = 1;
+        }
+        if($MContent=~s/(\*\s*|\w\s+)(bool)(\s*(\,|\)))/$1c99_$2$3/g)
+        { # MATCH:
+          # int foo(gboolean *bool);
+          # DO NOT MATCH:
+          # void setTabEnabled(int index, bool);
+            $C99Mode{$Version} = 1;
+        }
+        if($MContent=~s/(\w)([^\w\(\,\s]\s*|\s+)(this)(\s*(\,|\)))/$1$2c99_$3$4/g)
+        { # MATCH:
+          # int foo(int* this);
+          # int bar(int this);
+          # DO NOT MATCH:
+          # baz(X, this);
+            $C99Mode{$Version} = 1;
+        }
+        if($C99Mode{$Version}==1)
+        { # try to change C++ "keyword" to "c99_keyword"
+            printMsg("INFO", "Using C99 compatibility mode");
+            $MHeaderPath = "$TMP_DIR/dump$Version.i";
+        }
+    }
+    if($C99Mode{$Version}==1
+    or $MinGWMode{$Version}==1)
+    { # compile the corrected preprocessor output
+        writeFile($MHeaderPath, $MContent);
+    }
+    if($COMMON_LANGUAGE{$Version} eq "C++")
+    { # add classes and namespaces to the dump
+        my $CHdump = "-fdump-class-hierarchy -c";
+        if($C99Mode{$Version}==1
+        or $MinGWMode{$Version}==1) {
+            $CHdump .= " -fpreprocessed";
+        }
+        my $ClassHierarchyCmd = getCompileCmd($MHeaderPath, $CHdump, $IncludeString);
+        chdir($TMP_DIR);
+        system("$ClassHierarchyCmd >null 2>&1");
+        chdir($ORIG_DIR);
+        if(my $ClassDump = (cmd_find($TMP_DIR,"f","*.class",1))[0])
+        {
+            my %AddClasses = ();
+            my $Content = readFile($ClassDump);
+            foreach my $ClassInfo (split(/\n\n/, $Content))
+            {
+                if($ClassInfo=~/\AClass\s+(.+)\s*/i)
+                {
+                    my $CName = $1;
+                    next if($CName=~/\A(__|_objc_|_opaque_)/);
+                    $TUnit_NameSpaces{$Version}{$CName} = -1;
+                    if($CName=~/\A[\w:]+\Z/)
+                    { # classes
+                        $AddClasses{$CName} = 1;
+                    }
+                    if($CName=~/(\w[\w:]*)::/)
+                    { # namespaces
+                        my $NS = $1;
+                        if(not defined $TUnit_NameSpaces{$Version}{$NS}) {
+                            $TUnit_NameSpaces{$Version}{$NS} = 1;
+                        }
+                    }
+                }
+                elsif($ClassInfo=~/\AVtable\s+for\s+(.+)\n((.|\n)+)\Z/i)
+                { # read v-tables (advanced approach)
+                    my ($CName, $VTable) = ($1, $2);
+                    $ClassVTable_Content{$Version}{$CName} = $VTable;
+                }
+            }
+            if($Debug)
+            { # debug mode
+                mkpath($DEBUG_PATH{$Version});
+                copy($ClassDump, $DEBUG_PATH{$Version}."/class-hierarchy.txt");
+            }
+            unlink($ClassDump);
+            if(my $NS_Add = get_namespace_additions($TUnit_NameSpaces{$Version}))
+            { # GCC on all supported platforms does not include namespaces to the dump by default
+                appendFile($MHeaderPath, "\n  // add namespaces\n".$NS_Add);
+            }
+            # some GCC versions don't include class methods to the TU dump by default
+            my ($AddClass, $ClassNum) = ("", 0);
+            foreach my $CName (sort keys(%AddClasses))
+            {
+                next if($C_Structure{$CName});
+                next if(not $STDCXX_TESTING and $CName=~/\Astd::/);
+                next if(($CName=~tr![:]!!)>2);
+                next if($SkipTypes{$Version}{$CName});
+                if($CName=~/\A(.+)::[^:]+\Z/
+                and $AddClasses{$1}) {
+                    next;
+                }
+                $AddClass .= "  $CName* tmp_add_class_".($ClassNum++).";\n";
+            }
+            appendFile($MHeaderPath, "\n  // add classes\n".$AddClass);
+        }
+    }
+    writeLog($Version, "Temporary header file \'$TmpHeaderPath\' with the following content will be compiled to create GCC translation unit dump:\n".readFile($TmpHeaderPath)."\n");
+    # create TU dump
+    my $TUdump = "-fdump-translation-unit -fkeep-inline-functions -c";
+    if($C99Mode{$Version}==1
+    or $MinGWMode{$Version}==1) {
+        $TUdump .= " -fpreprocessed";
+    }
+    my $SyntaxTreeCmd = getCompileCmd($MHeaderPath, $TUdump, $IncludeString);
+    writeLog($Version, "The GCC parameters:\n  $SyntaxTreeCmd\n\n");
+    chdir($TMP_DIR);
+    system($SyntaxTreeCmd." >$TMP_DIR/tu_errors 2>&1");
+    if($?)
+    { # failed to compile, but the TU dump still can be created
+        my $Errors = readFile("$TMP_DIR/tu_errors");
+        if($Errors=~/c99_/)
+        { # disable c99 mode
+            $C99Mode{$Version}=-1;
+            printMsg("INFO", "Disabling C99 compatibility mode");
+            resetLogging($Version);
+            $TMP_DIR = tempdir(CLEANUP=>1);
+            return getDump();
+        }
+        elsif($AutoPreambleMode{$Version}!=-1
+        and my $TErrors = $Errors)
+        {
+            my %Types = ();
+            while($TErrors=~s/error\:\s*(field\s*|)\W+(.+?)\W+//)
+            { # error: 'FILE' has not been declared
+                $Types{$2}=1;
+            }
+            my %AddHeaders = ();
+            foreach my $Type (keys(%Types))
+            {
+                if(my $Header = $AutoPreamble{$Type}) {
+                    $AddHeaders{path_format($Header, $OSgroup)}=$Type;
+                }
+            }
+            if(my @Headers = sort {$b cmp $a} keys(%AddHeaders))
+            { # sys/types.h should be the first
+                foreach my $Num (0 .. $#Headers)
+                {
+                    my $Name = $Headers[$Num];
+                    if(my $Path = identify_header($Name, $Version))
+                    { # add automatic preamble headers
+                        if(defined $Include_Preamble{$Version}{$Path})
+                        { # already added
+                            next;
+                        }
+                        $Include_Preamble{$Version}{$Path}{"Position"} = keys(%{$Include_Preamble{$Version}});
+                        my $Type = $AddHeaders{$Name};
+                        printMsg("INFO", "Add \'$Name\' preamble header for \'$Type\'");
+                    }
+                }
+                $AutoPreambleMode{$Version}=-1;
+                resetLogging($Version);
+                $TMP_DIR = tempdir(CLEANUP=>1);
+                return getDump();
+            }
+        }
+        elsif($MinGWMode{$Version}!=-1)
+        {
+            $MinGWMode{$Version}=-1;
+            resetLogging($Version);
+            $TMP_DIR = tempdir(CLEANUP=>1);
+            return getDump();
+        }
+        # FIXME: handle other errors and try to recompile
+        writeLog($Version, $Errors);
+        printMsg("ERROR", "some errors occurred when compiling headers");
+        printErrorLog($Version);
+        $COMPILE_ERRORS = $ERROR_CODE{"Compile_Error"};
+        writeLog($Version, "\n");# new line
+    }
+    chdir($ORIG_DIR);
+    unlink($TmpHeaderPath, $MHeaderPath);
+    return (cmd_find($TMP_DIR,"f","*.tu",1))[0];
+}
+
+sub cmd_file($)
+{
+    my $Path = $_[0];
+    return "" if(not $Path or not -e $Path);
+    if(my $CmdPath = get_CmdPath("file")) {
+        return `$CmdPath -b \"$Path\"`;
+    }
+    return "";
+}
+
+sub getIncString($$)
+{
+    my ($ArrRef, $Style) = @_;
+    return if(not $ArrRef or $#{$ArrRef}<0);
+    my $String = "";
+    foreach (@{$ArrRef}) {
+        $String .= " ".inc_opt($_, $Style);
+    }
+    return $String;
+}
+
+sub getIncPaths(@)
+{
+    my @HeaderPaths = @_;
+    my @IncPaths = ();
+    if($INC_PATH_AUTODETECT{$Version})
+    { # auto-detecting dependencies
+        my %Includes = ();
+        foreach my $HPath (@HeaderPaths)
+        {
+            foreach my $Dir (get_HeaderDeps($HPath, $Version))
+            {
+                if($Skip_Include_Paths{$Version}{$Dir}) {
+                    next;
+                }
+                $Includes{$Dir}=1;
+            }
+        }
+        foreach my $Dir (keys(%{$Add_Include_Paths{$Version}}))
+        { # added by user
+            next if($Includes{$Dir});
+            push(@IncPaths, $Dir);
+        }
+        foreach my $Dir (@{sortIncPaths([keys(%Includes)], $Version)}) {
+            push(@IncPaths, $Dir);
+        }
+    }
+    else
+    { # user-defined paths
+        foreach my $Dir (sort {get_depth($a)<=>get_depth($b)}
+        sort {$b cmp $a} keys(%{$Include_Paths{$Version}})) {
+            push(@IncPaths, $Dir);
+        }
+    }
+    return \@IncPaths;
+}
+
+sub callPreprocessor($$$)
+{
+    my ($Path, $Inc, $LibVersion) = @_;
+    return "" if(not $Path or not -f $Path);
+    my $IncludeString=$Inc;
+    if(not $Inc) {
+        $IncludeString = getIncString(getIncPaths($Path), "GCC");
+    }
+    my $Cmd = getCompileCmd($Path, "-dD -E", $IncludeString);
+    my $Path = "$TMP_DIR/preprocessed";
+    system("$Cmd >$Path 2>$TMP_DIR/null");
+    return $Path;
+}
+
+sub cmd_find($$$$)
+{ # native "find" is much faster than File::Find (~6x)
+  # also the File::Find doesn't support --maxdepth N option
+  # so using the cross-platform wrapper for the native one
+    my ($Path, $Type, $Name, $MaxDepth) = @_;
+    return () if(not $Path or not -e $Path);
+    if($OSgroup eq "windows")
+    {
+        my $DirCmd = get_CmdPath("dir");
+        if(not $DirCmd) {
+            exitStatus("Not_Found", "can't find \"dir\" command");
+        }
+        $Path=~s/[\\]+\Z//;
+        $Path = get_abs_path($Path);
+        $Path = path_format($Path, $OSgroup);
+        my $Cmd = $DirCmd." \"$Path\" /B /O";
+        if($MaxDepth!=1) {
+            $Cmd .= " /S";
+        }
+        if($Type eq "d") {
+            $Cmd .= " /AD";
+        }
+        my @Files = ();
+        if($Name)
+        { # FIXME: how to search file names in MS shell?
+            $Name=~s/\*/.*/g if($Name!~/\]/);
+            foreach my $File (split(/\n/, `$Cmd`))
+            {
+                if($File=~/$Name\Z/i) {
+                    push(@Files, $File);
+                }
+            }
+        }
+        else {
+            @Files = split(/\n/, `$Cmd 2>$TMP_DIR/null`);
+        }
+        my @AbsPaths = ();
+        foreach my $File (@Files)
+        {
+            if(not is_abs($File)) {
+                $File = joinPath($Path, $File);
+            }
+            if($Type eq "f" and not -f $File)
+            { # skip dirs
+                next;
+            }
+            push(@AbsPaths, path_format($File, $OSgroup));
+        }
+        if($Type eq "d") {
+            push(@AbsPaths, $Path);
+        }
+        return @AbsPaths;
+    }
+    else
+    {
+        my $FindCmd = get_CmdPath("find");
+        if(not $FindCmd) {
+            exitStatus("Not_Found", "can't find a \"find\" command");
+        }
+        $Path = get_abs_path($Path);
+        if(-d $Path and -l $Path
+        and $Path!~/\/\Z/)
+        { # for directories that are symlinks
+            $Path.="/";
+        }
+        my $Cmd = $FindCmd." \"$Path\"";
+        if($MaxDepth) {
+            $Cmd .= " -maxdepth $MaxDepth";
+        }
+        if($Type) {
+            $Cmd .= " -type $Type";
+        }
+        if($Name)
+        { # file name
+            if($Name=~/\]/) {
+                $Cmd .= " -regex \"$Name\"";
+            }
+            else {
+                $Cmd .= " -name \"$Name\"";
+            }
+        }
+        return split(/\n/, `$Cmd 2>$TMP_DIR/null`);
+    }
+}
+
+sub unpackDump($)
+{
+    my $Path = $_[0];
+    return "" if(not $Path or not -e $Path);
+    $Path = get_abs_path($Path);
+    $Path = path_format($Path, $OSgroup);
+    my ($Dir, $FileName) = separate_path($Path);
+    my $UnpackDir = $TMP_DIR."/unpack";
+    rmtree($UnpackDir);
+    mkpath($UnpackDir);
+    if($FileName=~s/\Q.zip\E\Z//g)
+    { # *.zip
+        my $UnzipCmd = get_CmdPath("unzip");
+        if(not $UnzipCmd) {
+            exitStatus("Not_Found", "can't find \"unzip\" command");
+        }
+        chdir($UnpackDir);
+        system("$UnzipCmd \"$Path\" >$UnpackDir/contents.txt");
+        if($?) {
+            exitStatus("Error", "can't extract \'$Path\'");
+        }
+        chdir($ORIG_DIR);
+        my @Contents = ();
+        foreach (split("\n", readFile("$UnpackDir/contents.txt")))
+        {
+            if(/inflating:\s*([^\s]+)/) {
+                push(@Contents, $1);
+            }
+        }
+        if(not @Contents) {
+            exitStatus("Error", "can't extract \'$Path\'");
+        }
+        return joinPath($UnpackDir, $Contents[0]);
+    }
+    elsif($FileName=~s/\Q.tar.gz\E\Z//g)
+    { # *.tar.gz
+        if($OSgroup eq "windows")
+        { # -xvzf option is not implemented in tar.exe (2003)
+          # use "gzip.exe -k -d -f" + "tar.exe -xvf" instead
+            my $TarCmd = get_CmdPath("tar");
+            if(not $TarCmd) {
+                exitStatus("Not_Found", "can't find \"tar\" command");
+            }
+            my $GzipCmd = get_CmdPath("gzip");
+            if(not $GzipCmd) {
+                exitStatus("Not_Found", "can't find \"gzip\" command");
+            }
+            chdir($UnpackDir);
+            system("$GzipCmd -k -d -f \"$Path\"");# keep input files (-k)
+            if($?) {
+                exitStatus("Error", "can't extract \'$Path\'");
+            }
+            system("$TarCmd -xvf \"$Dir\\$FileName.tar\" >$UnpackDir/contents.txt");
+            if($?) {
+                exitStatus("Error", "can't extract \'$Path\'");
+            }
+            chdir($ORIG_DIR);
+            unlink($Dir."/".$FileName.".tar");
+            my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
+            if(not @Contents) {
+                exitStatus("Error", "can't extract \'$Path\'");
+            }
+            return joinPath($UnpackDir, $Contents[0]);
+        }
+        else
+        { # Unix
+            my $TarCmd = get_CmdPath("tar");
+            if(not $TarCmd) {
+                exitStatus("Not_Found", "can't find \"tar\" command");
+            }
+            chdir($UnpackDir);
+            system("$TarCmd -xvzf \"$Path\" >$UnpackDir/contents.txt");
+            if($?) {
+                exitStatus("Error", "can't extract \'$Path\'");
+            }
+            chdir($ORIG_DIR);
+            # The content file name may be different
+            # from the package file name
+            my @Contents = split("\n", readFile("$UnpackDir/contents.txt"));
+            if(not @Contents) {
+                exitStatus("Error", "can't extract \'$Path\'");
+            }
+            return joinPath($UnpackDir, $Contents[0]);
+        }
+    }
+}
+
+sub createArchive($$)
+{
+    my ($Path, $To) = @_;
+    if(not $Path or not -e $Path
+    or not -d $To) {
+        return "";
+    }
+    my ($From, $Name) = separate_path($Path);
+    if($OSgroup eq "windows")
+    { # *.zip
+        my $ZipCmd = get_CmdPath("zip");
+        if(not $ZipCmd) {
+            exitStatus("Not_Found", "can't find \"zip\"");
+        }
+        my $Pkg = $To."/".$Name.".zip";
+        unlink($Pkg);
+        chdir($To);
+        system("$ZipCmd -j \"$Name.zip\" \"$Path\" >$TMP_DIR/null");
+        if($?)
+        { # cannot allocate memory (or other problems with "zip")
+            unlink($Path);
+            exitStatus("Error", "can't pack the ABI dump: ".$!);
+        }
+        chdir($ORIG_DIR);
+        unlink($Path);
+        return $Pkg;
+    }
+    else
+    { # *.tar.gz
+        my $TarCmd = get_CmdPath("tar");
+        if(not $TarCmd) {
+            exitStatus("Not_Found", "can't find \"tar\"");
+        }
+        my $GzipCmd = get_CmdPath("gzip");
+        if(not $GzipCmd) {
+            exitStatus("Not_Found", "can't find \"gzip\"");
+        }
+        my $Pkg = abs_path($To)."/".$Name.".tar.gz";
+        unlink($Pkg);
+        chdir($From);
+        system($TarCmd, "-czf", $Pkg, $Name);
+        if($?)
+        { # cannot allocate memory (or other problems with "tar")
+            unlink($Path);
+            exitStatus("Error", "can't pack the ABI dump: ".$!);
+        }
+        chdir($ORIG_DIR);
+        unlink($Path);
+        return $To."/".$Name.".tar.gz";
+    }
+}
+
+sub is_header_file($)
+{
+    if($_[0]=~/\.($HEADER_EXT)\Z/i) {
+        return $_[0];
+    }
+    return 0;
+}
+
+sub is_not_header($)
+{
+    if($_[0]=~/\.\w+\Z/
+    and $_[0]!~/\.($HEADER_EXT)\Z/i) {
+        return 1;
+    }
+    return 0;
+}
+
+sub is_header($$$)
+{
+    my ($Header, $UserDefined, $LibVersion) = @_;
+    return 0 if(-d $Header);
+    if(-f $Header) {
+        $Header = get_abs_path($Header);
+    }
+    else
+    {
+        if(is_abs($Header))
+        { # incorrect absolute path
+            return 0;
+        }
+        if(my $HPath = identify_header($Header, $LibVersion)) {
+            $Header = $HPath;
+        }
+        else
+        { # can't find header
+            return 0;
+        }
+    }
+    if($Header=~/\.\w+\Z/)
+    { # have an extension
+        return is_header_file($Header);
+    }
+    else
+    {
+        if($UserDefined==2)
+        { # specified on the command line
+            if(cmd_file($Header)!~/HTML|XML/i) {
+                return $Header;
+            }
+        }
+        elsif($UserDefined)
+        { # specified in the XML-descriptor
+          # header file without an extension
+            return $Header;
+        }
+        else
+        {
+            if(cmd_file($Header)=~/C[\+]*\s+program/i)
+            { # !~/HTML|XML|shared|dynamic/i
+                return $Header;
+            }
+        }
+    }
+    return 0;
+}
+
+sub detectTargetHeaders($)
+{
+    my $LibVersion = $_[0];
+    foreach my $RegHeader (keys(%{$Registered_Headers{$LibVersion}}))
+    {
+        my $RegDir = get_dirname($RegHeader);
+        $TargetHeaders{$LibVersion}{get_filename($RegHeader)}=1;
+        foreach my $RecInc (keys(%{$RecursiveIncludes{$LibVersion}{$RegHeader}}))
+        {
+            my $Dir = get_dirname($RecInc);
+            if($Dir=~/\A$RegDir([\/\\]|\Z)/)
+            { # in the same directory
+                $TargetHeaders{$LibVersion}{get_filename($RecInc)}=1;
+            }
+        }
+    }
+}
+
+sub readHeaders($)
+{
+    $Version = $_[0];
+    printMsg("INFO", "checking header(s) ".$Descriptor{$Version}{"Version"}." ...");
+    my $DumpPath = getDump();
+    if(not $DumpPath) {
+        exitStatus("Cannot_Compile", "can't compile header(s)");
+    }
+    if($Debug)
+    { # debug mode
+        mkpath($DEBUG_PATH{$Version});
+        copy($DumpPath, $DEBUG_PATH{$Version}."/translation-unit.txt");
+    }
+    getInfo($DumpPath);
+    if($CheckHeadersOnly)
+    { # --headers-only mode
+        detectTargetHeaders($Version);
+    }
+}
+
+sub prepareTypes($)
+{
+    my $LibVersion = $_[0];
+    if(cmpVersions($UsedDump{$LibVersion}{"V"}, "2.0")<0)
+    { # support for old ABI dumps
+      # type names have been corrected in ACC 1.22 (dump 2.0 format)
+        foreach my $TypeDeclId (keys(%{$TypeInfo{$LibVersion}}))
+        {
+            foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}}))
+            {
+                my $TName = $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Name"};
+                if($TName=~/\A(\w+)::(\w+)/) {
+                    my ($P1, $P2) = ($1, $2);
+                    if($P1 eq $P2) {
+                        $TName=~s/\A$P1:\:$P1(\W)/$P1$1/;
+                    }
+                    else {
+                        $TName=~s/\A(\w+:\:)$P2:\:$P2(\W)/$1$P2$2/;
+                    }
+                }
+                $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Name"} = $TName;
+            }
+        }
+    }
+    if(cmpVersions($UsedDump{$LibVersion}{"V"}, "2.5")<0)
+    { # support for old ABI dumps
+      # V < 2.5: array size == "number of elements"
+      # V >= 2.5: array size in bytes
+        foreach my $TypeDeclId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
+        {
+            foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}}))
+            {
+                my %Type = get_PureType($TypeDeclId, $TypeId, $LibVersion);
+                if($Type{"Type"} eq "Array")
+                {
+                    if($Type{"Size"})
+                    { # array[N]
+                        my %Base = get_OneStep_BaseType($Type{"TDid"}, $Type{"Tid"}, $LibVersion);
+                        $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Size"} = $Type{"Size"}*$Base{"Size"};
+                    }
+                    else
+                    { # array[] is a pointer
+                        $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Size"} = $WORD_SIZE{$LibVersion};
+                    }
+                }
+            }
+        }
+    }
+    my $V2 = ($LibVersion==1)?2:1;
+    if(cmpVersions($UsedDump{1}{"V"}, "2.7")<0)
+    { # support for old ABI dumps
+      # size of "method ptr" corrected in 2.7
+        foreach my $TypeDeclId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
+        {
+            foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}}))
+            {
+                my %PureType = get_PureType($TypeDeclId, $TypeId, $LibVersion);
+                if($PureType{"Type"} eq "MethodPtr")
+                {
+                    my %Type = get_Type($TypeDeclId, $TypeId, $LibVersion);
+                    my $TypeId_2 = getTypeIdByName($PureType{"Name"}, $V2);
+                    my %Type2 = get_Type($Tid_TDid{$V2}{$TypeId_2}, $TypeId_2, $V2);
+                    if($Type{"Size"} ne $Type2{"Size"}) {
+                        $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Size"} = $Type2{"Size"};
+                    }
+                }
+            }
+        }
+    }
+}
+
+sub prepareInterfaces($)
+{
+    my $LibVersion = $_[0];
+    my $Remangle = 0;
+    if(($UsedDump{1}{"V"} and cmpVersions($UsedDump{1}{"V"}, "2.10")<0)
+    or ($UsedDump{2}{"V"} and cmpVersions($UsedDump{2}{"V"}, "2.10")<0))
+    { # different formats
+        $Remangle = 1;
+    }
+    if($CheckHeadersOnly)
+    { # different languages
+        if($UserLang)
+        { # --lang=LANG for both versions
+            if(($UsedDump{1}{"V"} and $UserLang ne $UsedDump{1}{"L"})
+            or ($UsedDump{2}{"V"} and $UserLang ne $UsedDump{2}{"L"}))
+            {
+                if($UserLang eq "C++")
+                { # remangle symbols
+                    $Remangle = 1;
+                }
+                elsif($UserLang eq "C")
+                { # remove mangling
+                    $Remangle = -1;
+                }
+            }
+        }
+    }
+    foreach my $FuncInfoId (sort {int($b)<=>int($a)} keys(%{$SymbolInfo{$LibVersion}}))
+    { # reverse order: D0, D1, D2, D0 (artificial, GCC < 4.5), C1, C2
+        if($SymbolInfo{$LibVersion}{$FuncInfoId}{"Destructor"})
+        {
+            if(defined $SymbolInfo{$LibVersion}{$FuncInfoId}{"Param"}
+            and keys(%{$SymbolInfo{$LibVersion}{$FuncInfoId}{"Param"}})
+            and $SymbolInfo{$LibVersion}{$FuncInfoId}{"Param"}{"0"}{"name"})
+            { # support for old GCC < 4.5: skip artificial ~dtor(int __in_chrg)
+              # + support for old ABI dumps
+                next;
+            }
+        }
+        my $MnglName = $SymbolInfo{$LibVersion}{$FuncInfoId}{"MnglName"};
+        if($Remangle==1)
+        { # support for old ABI dumps: some symbols are not mangled in old dumps
+          # mangle both sets of symbols (old and new)
+          # NOTE: remangling all symbols by the same mangler
+            if($MnglName=~/\A_ZN(V|)K/)
+            { # mangling may be incorrect on old ABI dumps
+              # because of absent "Const" attribute
+                $SymbolInfo{$LibVersion}{$FuncInfoId}{"Const"} = 1;
+            }
+            if($MnglName=~/\A_ZN(K|)V/)
+            { # mangling may be incorrect on old ABI dumps
+              # because of absent "Volatile" attribute
+                $SymbolInfo{$LibVersion}{$FuncInfoId}{"Volatile"} = 1;
+            }
+            if(($SymbolInfo{$LibVersion}{$FuncInfoId}{"Class"} and ($MnglName!~/\A_Z/ or not link_symbol($MnglName, $LibVersion, "-Deps")))
+            or (not $SymbolInfo{$LibVersion}{$FuncInfoId}{"Class"} and $CheckHeadersOnly))
+            { # GCC >= 4.0
+              # remangling C++-functions (not mangled in the TU dump)
+              # remangling broken C++-methods (without a mangled name)
+              # remangling all inline virtual C++-methods
+                if($MnglName = mangle_symbol($FuncInfoId, $LibVersion, "GCC"))
+                {
+                    $SymbolInfo{$LibVersion}{$FuncInfoId}{"MnglName"} = $MnglName;
+                    $MangledNames{$LibVersion}{$MnglName} = 1;
+                }
+            }
+        }
+        elsif($Remangle==-1)
+        { # remove mangling
+            $MnglName = "";
+            $SymbolInfo{$LibVersion}{$FuncInfoId}{"MnglName"} = "";
+        }
+        if(not $MnglName)
+        { # ABI dumps don't contain mangled names for C-functions
+            $MnglName = $SymbolInfo{$LibVersion}{$FuncInfoId}{"ShortName"};
+            $SymbolInfo{$LibVersion}{$FuncInfoId}{"MnglName"} = $MnglName;
+        }
+        if(not $MnglName) {
+            next;
+        }
+        if(not $CompleteSignature{$LibVersion}{$MnglName}{"MnglName"})
+        { # NOTE: global data may enter here twice
+            %{$CompleteSignature{$LibVersion}{$MnglName}} = %{$SymbolInfo{$LibVersion}{$FuncInfoId}};
+        }
+        if($UsedDump{$LibVersion}{"V"}
+        and cmpVersions($UsedDump{$LibVersion}{"V"}, "2.6")<0)
+        { # support for old dumps
+          # add "Volatile" attribute
+            if($MnglName=~/_Z(K|)V/) {
+                $CompleteSignature{$LibVersion}{$MnglName}{"Volatile"}=1;
+            }
+        }
+        # symbol and its symlink have same signatures
+        if($SymVer{$LibVersion}{$MnglName}) {
+            %{$CompleteSignature{$LibVersion}{$SymVer{$LibVersion}{$MnglName}}} = %{$SymbolInfo{$LibVersion}{$FuncInfoId}};
+        }
+        delete($SymbolInfo{$LibVersion}{$FuncInfoId});
+    }
+    if($COMMON_LANGUAGE{$LibVersion} eq "C++" or $OSgroup eq "windows") {
+        translateSymbols(keys(%{$CompleteSignature{$LibVersion}}), $LibVersion);
+    }
+    if($ExtendedCheck)
+    { # --ext option
+        addExtension($LibVersion);
+    }
+    if(not keys(%{$CompleteSignature{$LibVersion}}))
+    { # check if input is valid
+        if(not $ExtendedCheck and not $CheckObjectsOnly)
+        {
+            if($CheckHeadersOnly) {
+                exitStatus("Empty_Set", "the set of public symbols is empty (".$Descriptor{$LibVersion}{"Version"}.")");
+            }
+            else {
+                exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection (".$Descriptor{$LibVersion}{"Version"}.")");
+            }
+        }
+    }
+    foreach my $MnglName (keys(%{$CompleteSignature{$LibVersion}}))
+    { # detect allocable classes with public exported constructors
+      # or classes with auto-generated or inline-only constructors
+        if(my $ClassId = $CompleteSignature{$LibVersion}{$MnglName}{"Class"})
+        {
+            my $ClassName = get_TypeName($ClassId, $LibVersion);
+            if($CompleteSignature{$LibVersion}{$MnglName}{"Constructor"}
+            and not $CompleteSignature{$LibVersion}{$MnglName}{"InLine"})
+            { # Class() { ... } will not be exported
+                if(not $CompleteSignature{$LibVersion}{$MnglName}{"Private"})
+                {
+                    if(link_symbol($MnglName, $LibVersion, "-Deps")) {
+                        $AllocableClass{$LibVersion}{$ClassName} = 1;
+                    }
+                }
+            }
+            if(not $CompleteSignature{$LibVersion}{$MnglName}{"Private"})
+            { # all imported class methods
+                if($CheckHeadersOnly)
+                {
+                    if(not $CompleteSignature{$LibVersion}{$MnglName}{"InLine"}
+                    or $CompleteSignature{$LibVersion}{$MnglName}{"Virt"})
+                    {# all symbols except non-virtual inline
+                        $ClassMethods{$LibVersion}{$ClassName}{$MnglName} = 1;
+                    }
+                }
+                elsif(link_symbol($MnglName, $LibVersion, "-Deps"))
+                { # all symbols
+                    $ClassMethods{$LibVersion}{$ClassName}{$MnglName} = 1;
+                }
+            }
+            $ClassToId{$LibVersion}{$ClassName} = $ClassId;
+        }
+        if(my $RetId = $CompleteSignature{$LibVersion}{$MnglName}{"Return"})
+        {
+            my %Base = get_BaseType($Tid_TDid{$LibVersion}{$RetId}, $RetId, $LibVersion);
+            if($Base{"Type"}=~/Struct|Class/)
+            {
+                my $Name = get_TypeName($Base{"Tid"}, $LibVersion);
+                if($Name=~/<([^<>\s]+)>/)
+                {
+                    if(my $Tid = getTypeIdByName($1, $LibVersion)) {
+                        $ReturnedClass{$LibVersion}{$Tid} = 1;
+                    }
+                }
+                else {
+                    $ReturnedClass{$LibVersion}{$Base{"Tid"}} = 1;
+                }
+            }
+        }
+        foreach my $Num (keys(%{$CompleteSignature{$LibVersion}{$MnglName}{"Param"}}))
+        {
+            my $PId = $CompleteSignature{$LibVersion}{$MnglName}{"Param"}{$Num}{"type"};
+            if(get_PointerLevel($Tid_TDid{1}{$PId}, $PId, $LibVersion)>=1)
+            {
+                my %Base = get_BaseType($Tid_TDid{$LibVersion}{$PId}, $PId, $LibVersion);
+                if($Base{"Type"}=~/Struct|Class/)
+                {
+                    $ParamClass{$LibVersion}{$Base{"Tid"}}{$MnglName} = 1;
+                    foreach my $SubId (get_sub_classes($Base{"Tid"}, $LibVersion, 1))
+                    { # mark all derived classes
+                        $ParamClass{$LibVersion}{$SubId}{$MnglName} = 1;
+                    }
+                }
+            }
+        }
+    }
+    foreach my $MnglName (keys(%{$VTableClass{$LibVersion}}))
+    { # reconstruct header name for v-tables
+        if($MnglName=~/\A_ZTV/)
+        {
+            if(my $ClassName = $VTableClass{$LibVersion}{$MnglName})
+            {
+                if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName}) {
+                    $CompleteSignature{$LibVersion}{$MnglName}{"Header"} = get_TypeAttr($ClassId, $LibVersion, "Header");
+                }
+            }
+        }
+    }
+}
+
+sub addExtension($)
+{
+    my $LibVersion = $_[0];
+    foreach my $TDid (keys(%{$TypeInfo{$LibVersion}}))
+    {
+        foreach my $Tid (keys(%{$TypeInfo{$LibVersion}{$TDid}}))
+        {
+            my $TType = $TypeInfo{$LibVersion}{$TDid}{$Tid}{"Type"};
+            if($TType=~/Struct|Union|Enum|Class/)
+            {
+                my $HName = $TypeInfo{$LibVersion}{$TDid}{$Tid}{"Header"};
+                if(not $HName or isBuiltIn($HName)) {
+                    next;
+                }
+                my $TName = $TypeInfo{$LibVersion}{$TDid}{$Tid}{"Name"};
+                if(isAnon($TName))
+                { # anon-struct-header.h-265
+                    next;
+                }
+                my $FuncName = "external_func_".$TName;
+                $ExtendedFuncs{$FuncName}=1;
+                my %Attrs = (
+                    "Header" => "extended.h",
+                    "ShortName" => $FuncName,
+                    "MnglName" => $FuncName,
+                    "Param" => { "0" => { "type"=>$Tid, "name"=>"p1" } }
+                );
+                %{$CompleteSignature{$LibVersion}{$FuncName}} = %Attrs;
+                register_TypeUsing($TDid, $Tid, $LibVersion);
+                $GeneratedSymbols{$FuncName}=1;
+                $CheckedSymbols{$FuncName}=1;
+            }
+        }
+    }
+    my $ConstFunc = "external_func_0";
+    $GeneratedSymbols{$ConstFunc}=1;
+    $CheckedSymbols{$ConstFunc}=1;
+}
+
+sub formatDump($)
+{ # remove unnecessary data from the ABI dump
+    my $LibVersion = $_[0];
+    foreach my $FuncInfoId (keys(%{$SymbolInfo{$LibVersion}}))
+    {
+        my $MnglName = $SymbolInfo{$LibVersion}{$FuncInfoId}{"MnglName"};
+        if(not $MnglName) {
+            delete($SymbolInfo{$LibVersion}{$FuncInfoId});
+            next;
+        }
+        if($MnglName eq $SymbolInfo{$LibVersion}{$FuncInfoId}{"ShortName"}) {
+            delete($SymbolInfo{$LibVersion}{$FuncInfoId}{"MnglName"});
+        }
+        if(not is_target_header($SymbolInfo{$LibVersion}{$FuncInfoId}{"Header"}))
+        { # user-defined header
+            delete($SymbolInfo{$LibVersion}{$FuncInfoId});
+            next;
+        }
+        if(not link_symbol($MnglName, $LibVersion, "-Deps")
+        and not $SymbolInfo{$LibVersion}{$FuncInfoId}{"Virt"}
+        and not $SymbolInfo{$LibVersion}{$FuncInfoId}{"PureVirt"})
+        { # removing src only and all external functions
+            if(not $CheckHeadersOnly) {
+                delete($SymbolInfo{$LibVersion}{$FuncInfoId});
+                next;
+            }
+        }
+        if(not symbolFilter($MnglName, $LibVersion, "Public")) {
+            delete($SymbolInfo{$LibVersion}{$FuncInfoId});
+            next;
+        }
+        my %FuncInfo = %{$SymbolInfo{$LibVersion}{$FuncInfoId}};
+        register_TypeUsing($Tid_TDid{$LibVersion}{$FuncInfo{"Return"}}, $FuncInfo{"Return"}, $LibVersion);
+        register_TypeUsing($Tid_TDid{$LibVersion}{$FuncInfo{"Class"}}, $FuncInfo{"Class"}, $LibVersion);
+        foreach my $Param_Pos (keys(%{$FuncInfo{"Param"}}))
+        {
+            my $Param_TypeId = $FuncInfo{"Param"}{$Param_Pos}{"type"};
+            register_TypeUsing($Tid_TDid{$LibVersion}{$Param_TypeId}, $Param_TypeId, $LibVersion);
+        }
+        if(not keys(%{$SymbolInfo{$LibVersion}{$FuncInfoId}{"Param"}})) {
+            delete($SymbolInfo{$LibVersion}{$FuncInfoId}{"Param"});
+        }
+    }
+    foreach my $TDid (keys(%{$TypeInfo{$LibVersion}}))
+    {
+        if(not keys(%{$TypeInfo{$LibVersion}{$TDid}})) {
+            delete($TypeInfo{$LibVersion}{$TDid});
+        }
+        else
+        {
+            foreach my $Tid (keys(%{$TypeInfo{$LibVersion}{$TDid}}))
+            {
+                if(not $UsedType{$LibVersion}{$TDid}{$Tid})
+                {
+                    delete($TypeInfo{$LibVersion}{$TDid}{$Tid});
+                    if(not keys(%{$TypeInfo{$LibVersion}{$TDid}})) {
+                        delete($TypeInfo{$LibVersion}{$TDid});
+                    }
+                    if($Tid_TDid{$LibVersion}{$Tid} eq $TDid) {
+                        delete($Tid_TDid{$LibVersion}{$Tid});
+                    }
+                }
+                else
+                { # clean attributes
+                    if(not $TypeInfo{$LibVersion}{$TDid}{$Tid}{"TDid"}) {
+                        delete($TypeInfo{$LibVersion}{$TDid}{$Tid}{"TDid"});
+                    }
+                    if(not $TypeInfo{$LibVersion}{$TDid}{$Tid}{"NameSpace"}) {
+                        delete($TypeInfo{$LibVersion}{$TDid}{$Tid}{"NameSpace"});
+                    }
+                    if(defined $TypeInfo{$LibVersion}{$TDid}{$Tid}{"BaseType"}
+                    and not $TypeInfo{$LibVersion}{$TDid}{$Tid}{"BaseType"}{"TDid"}) {
+                        delete($TypeInfo{$LibVersion}{$TDid}{$Tid}{"BaseType"}{"TDid"});
+                    }
+                    if(not $TypeInfo{$LibVersion}{$TDid}{$Tid}{"Header"}) {
+                        delete($TypeInfo{$LibVersion}{$TDid}{$Tid}{"Header"});
+                    }
+                    if(not $TypeInfo{$LibVersion}{$TDid}{$Tid}{"Line"}) {
+                        delete($TypeInfo{$LibVersion}{$TDid}{$Tid}{"Line"});
+                    }
+                    if(not $TypeInfo{$LibVersion}{$TDid}{$Tid}{"Size"}) {
+                        delete($TypeInfo{$LibVersion}{$TDid}{$Tid}{"Size"});
+                    }
+                }
+            }
+        }
+    }
+}
+
+sub register_TypeUsing($$$)
+{
+    my ($TypeDeclId, $TypeId, $LibVersion) = @_;
+    return if($UsedType{$LibVersion}{$TypeDeclId}{$TypeId});
+    my %Type = get_Type($TypeDeclId, $TypeId, $LibVersion);
+    if($Type{"Type"}=~/\A(Struct|Union|Class|FuncPtr|MethodPtr|FieldPtr|Enum)\Z/)
+    {
+        $UsedType{$LibVersion}{$TypeDeclId}{$TypeId} = 1;
+        if($Type{"Type"}=~/\A(Struct|Class)\Z/)
+        {
+            if(my $ThisPtrId = getTypeIdByName(get_TypeName($TypeId, $LibVersion)."*const", $LibVersion))
+            {# register "this" pointer
+                my $ThisPtrDId = $Tid_TDid{$LibVersion}{$ThisPtrId};
+                my %ThisPtrType = get_Type($ThisPtrDId, $ThisPtrId, $LibVersion);
+                $UsedType{$LibVersion}{$ThisPtrDId}{$ThisPtrId} = 1;
+                register_TypeUsing($ThisPtrType{"BaseType"}{"TDid"}, $ThisPtrType{"BaseType"}{"Tid"}, $LibVersion);
+            }
+            foreach my $BaseId (keys(%{$Type{"Base"}}))
+            {# register base classes
+                register_TypeUsing($Tid_TDid{$LibVersion}{$BaseId}, $BaseId, $LibVersion);
+            }
+        }
+        foreach my $Memb_Pos (keys(%{$Type{"Memb"}}))
+        {
+            my $Member_TypeId = $Type{"Memb"}{$Memb_Pos}{"type"};
+            register_TypeUsing($Tid_TDid{$LibVersion}{$Member_TypeId}, $Member_TypeId, $LibVersion);
+        }
+        if($Type{"Type"} eq "FuncPtr"
+        or $Type{"Type"} eq "MethodPtr") {
+            my $ReturnType = $Type{"Return"};
+            register_TypeUsing($Tid_TDid{$LibVersion}{$ReturnType}, $ReturnType, $LibVersion);
+            foreach my $Memb_Pos (keys(%{$Type{"Param"}}))
+            {
+                my $Member_TypeId = $Type{"Param"}{$Memb_Pos}{"type"};
+                register_TypeUsing($Tid_TDid{$LibVersion}{$Member_TypeId}, $Member_TypeId, $LibVersion);
+            }
+        }
+    }
+    elsif($Type{"Type"}=~/\A(Const|Pointer|Ref|Volatile|Restrict|Array|Typedef)\Z/)
+    {
+        $UsedType{$LibVersion}{$TypeDeclId}{$TypeId} = 1;
+        register_TypeUsing($Type{"BaseType"}{"TDid"}, $Type{"BaseType"}{"Tid"}, $LibVersion);
+    }
+    elsif($Type{"Type"} eq "Intrinsic") {
+        $UsedType{$LibVersion}{$TypeDeclId}{$TypeId} = 1;
+    }
+    else
+    {
+        delete($TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId});
+        if(not keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}})) {
+            delete($TypeInfo{$LibVersion}{$TypeDeclId});
+        }
+        if($Tid_TDid{$LibVersion}{$TypeId} eq $TypeDeclId) {
+            delete($Tid_TDid{$LibVersion}{$TypeId});
+        }
+    }
+}
+
+sub findMethod($$$)
+{
+    my ($VirtFunc, $ClassId, $LibVersion) = @_;
+    foreach my $BaseClass_Id (keys(%{$TypeInfo{$LibVersion}{$Tid_TDid{$LibVersion}{$ClassId}}{$ClassId}{"Base"}}))
+    {
+        if(my $VirtMethodInClass = findMethod_Class($VirtFunc, $BaseClass_Id, $LibVersion)) {
+            return $VirtMethodInClass;
+        }
+        elsif(my $VirtMethodInBaseClasses = findMethod($VirtFunc, $BaseClass_Id, $LibVersion)) {
+            return $VirtMethodInBaseClasses;
+        }
+    }
+    return "";
+}
+
+sub findMethod_Class($$$)
+{
+    my ($VirtFunc, $ClassId, $LibVersion) = @_;
+    my $ClassName = get_TypeName($ClassId, $LibVersion);
+    return "" if(not defined $VirtualTable{$LibVersion}{$ClassName});
+    my $TargetSuffix = get_symbol_suffix($VirtFunc, 1);
+    my $TargetShortName = $CompleteSignature{$LibVersion}{$VirtFunc}{"ShortName"};
+    foreach my $Candidate (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
+    { # search for interface with the same parameters suffix (overridden)
+        if($TargetSuffix eq get_symbol_suffix($Candidate, 1))
+        {
+            if($CompleteSignature{$LibVersion}{$VirtFunc}{"Destructor"}) {
+                if($CompleteSignature{$LibVersion}{$Candidate}{"Destructor"}) {
+                    if(($VirtFunc=~/D0E/ and $Candidate=~/D0E/)
+                    or ($VirtFunc=~/D1E/ and $Candidate=~/D1E/)
+                    or ($VirtFunc=~/D2E/ and $Candidate=~/D2E/)) {
+                        return $Candidate;
+                    }
+                }
+            }
+            else {
+                if($TargetShortName eq $CompleteSignature{$LibVersion}{$Candidate}{"ShortName"}) {
+                    return $Candidate;
+                }
+            }
+        }
+    }
+    return "";
+}
+
+sub registerVirtualTable($)
+{
+    my $LibVersion = $_[0];
+    foreach my $Interface (keys(%{$CompleteSignature{$LibVersion}}))
+    {
+        if($CompleteSignature{$LibVersion}{$Interface}{"Virt"}
+        or $CompleteSignature{$LibVersion}{$Interface}{"PureVirt"})
+        {
+            my $ClassName = get_TypeName($CompleteSignature{$LibVersion}{$Interface}{"Class"}, $LibVersion);
+            next if(not $STDCXX_TESTING and $ClassName=~/\A(std::|__cxxabi)/);
+            if($CompleteSignature{$LibVersion}{$Interface}{"Destructor"}
+            and $Interface=~/D2E/)
+            { # pure virtual D2-destructors are marked as "virt" in the dump
+              # virtual D2-destructors are NOT marked as "virt" in the dump
+              # both destructors are not presented in the v-table
+                next;
+            }
+            my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Interface);
+            $VirtualTable{$LibVersion}{$ClassName}{$MnglName} = 1;
+        }
+        if($CheckHeadersOnly
+        and $CompleteSignature{$LibVersion}{$Interface}{"Virt"})
+        { # Register added and removed virtual symbols
+          # This is necessary for --headers-only mode
+          # Virtual function cannot be inline, so:
+          # presence in headers <=> presence in shared libs
+            if($LibVersion==2 and not $CompleteSignature{1}{$Interface}{"Header"})
+            { # not presented in old-version headers
+                $AddedInt{$Interface} = 1;
+            }
+            if($LibVersion==1 and not $CompleteSignature{2}{$Interface}{"Header"})
+            { # not presented in new-version headers
+                $RemovedInt{$Interface} = 1;
+            }
+        }
+    }
+}
+
+sub registerOverriding($)
+{
+    my $LibVersion = $_[0];
+    my @Classes = keys(%{$VirtualTable{$LibVersion}});
+    @Classes = sort {int($ClassToId{$LibVersion}{$a})<=>int($ClassToId{$LibVersion}{$b})} @Classes;
+    foreach my $ClassName (@Classes)
+    {
+        foreach my $VirtFunc (keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
+        {
+            next if($CompleteSignature{$LibVersion}{$VirtFunc}{"PureVirt"});
+            if(my $OverriddenMethod = findMethod($VirtFunc, $TName_Tid{$LibVersion}{$ClassName}, $LibVersion))
+            { # both overridden virtual and implemented pure virtual functions
+                $CompleteSignature{$LibVersion}{$VirtFunc}{"Override"} = $OverriddenMethod;
+                $OverriddenMethods{$LibVersion}{$OverriddenMethod}{$VirtFunc} = 1;
+                delete($VirtualTable{$LibVersion}{$ClassName}{$VirtFunc});
+            }
+        }
+        if(not keys(%{$VirtualTable{$LibVersion}{$ClassName}})) {
+            delete($VirtualTable{$LibVersion}{$ClassName});
+        }
+    }
+}
+
+sub setVirtFuncPositions($)
+{
+    my $LibVersion = $_[0];
+    foreach my $ClassName (keys(%{$VirtualTable{$LibVersion}}))
+    {
+        my ($Num, $RelPos, $AbsNum) = (1, 0, 1);
+        foreach my $VirtFunc (sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})}
+        sort keys(%{$VirtualTable{$LibVersion}{$ClassName}}))
+        {
+            if(not $CompleteSignature{1}{$VirtFunc}{"Override"}
+            and not $CompleteSignature{2}{$VirtFunc}{"Override"})
+            {
+                if(defined $VirtualTable{1}{$ClassName} and defined $VirtualTable{1}{$ClassName}{$VirtFunc}
+                and defined $VirtualTable{2}{$ClassName} and defined $VirtualTable{2}{$ClassName}{$VirtFunc})
+                { # relative position excluding added and removed virtual functions
+                    $CompleteSignature{$LibVersion}{$VirtFunc}{"RelPos"} = $RelPos++;
+                }
+                $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}=$Num++;
+            }
+            
+        }
+    }
+    foreach my $ClassName (keys(%{$ClassToId{$LibVersion}}))
+    {
+        my $AbsNum = 1;
+        foreach my $VirtFunc (getVTable($ClassToId{$LibVersion}{$ClassName}, $LibVersion)) {
+            $VirtualTable_Full{$LibVersion}{$ClassName}{$VirtFunc}=$AbsNum++;
+        }
+    }
+}
+
+sub get_sub_classes($$$)
+{
+    my ($ClassId, $LibVersion, $Recursive) = @_;
+    return () if(not defined $Class_SubClasses{$LibVersion}{$ClassId});
+    my @Subs = ();
+    foreach my $SubId (keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
+    {
+        if($Recursive) {
+            foreach my $SubSubId (get_sub_classes($SubId, $LibVersion, $Recursive)) {
+                push(@Subs, $SubSubId);
+            }
+        }
+        push(@Subs, $SubId);
+    }
+    return @Subs;
+}
+
+sub get_base_classes($$$)
+{
+    my ($ClassId, $LibVersion, $Recursive) = @_;
+    my %ClassType = get_Type($Tid_TDid{$LibVersion}{$ClassId}, $ClassId, $LibVersion);
+    return () if(not defined $ClassType{"Base"});
+    my @Bases = ();
+    foreach my $BaseId (sort {int($ClassType{"Base"}{$a}{"pos"})<=>int($ClassType{"Base"}{$b}{"pos"})}
+    keys(%{$ClassType{"Base"}}))
+    {
+        if($Recursive) {
+            foreach my $SubBaseId (get_base_classes($BaseId, $LibVersion, $Recursive)) {
+                push(@Bases, $SubBaseId);
+            }
+        }
+        push(@Bases, $BaseId);
+    }
+    return @Bases;
+}
+
+sub getVTable($$)
+{# return list of v-table elements
+    my ($ClassId, $LibVersion) = @_;
+    my @Bases = get_base_classes($ClassId, $LibVersion, 1);
+    my @Elements = ();
+    foreach my $BaseId (@Bases, $ClassId)
+    {
+        my $BName = get_TypeName($BaseId, $LibVersion);
+        my @VFunctions = keys(%{$VirtualTable{$LibVersion}{$BName}});
+        @VFunctions = sort {int($CompleteSignature{$LibVersion}{$a}{"Line"}) <=> int($CompleteSignature{$LibVersion}{$b}{"Line"})} @VFunctions;
+        foreach my $VFunc (@VFunctions)
+        {
+            push(@Elements, $VFunc);
+        }
+    }
+    return @Elements;
+}
+
+sub getVShift($$)
+{
+    my ($ClassId, $LibVersion) = @_;
+    my @Bases = get_base_classes($ClassId, $LibVersion, 1);
+    my $VShift = 0;
+    foreach my $BaseId (@Bases)
+    {
+        my $BName = get_TypeName($BaseId, $LibVersion);
+        if(defined $VirtualTable{$LibVersion}{$BName}) {
+            $VShift+=keys(%{$VirtualTable{$LibVersion}{$BName}});
+        }
+    }
+    return $VShift;
+}
+
+sub getShift($$)
+{
+    my ($ClassId, $LibVersion) = @_;
+    my @Bases = get_base_classes($ClassId, $LibVersion, 0);
+    my $Shift = 0;
+    foreach my $BaseId (@Bases)
+    {
+        my $Size = get_TypeSize($BaseId, $LibVersion);
+        if($Size!=1) {
+            # empty base class
+            $Shift+=get_TypeSize($BaseId, $LibVersion);
+        }
+    }
+    return $Shift;
+}
+
+sub getVSize($$)
+{
+    my ($ClassName, $LibVersion) = @_;
+    if(defined $VirtualTable{$LibVersion}{$ClassName})  {
+        return keys(%{$VirtualTable{$LibVersion}{$ClassName}});
+    }
+    else {
+        return 0;
+    }
+}
+
+sub isCopyingClass($$)
+{
+    my ($TypeId, $LibVersion) = @_;
+    return $TypeInfo{$LibVersion}{$Tid_TDid{$LibVersion}{$TypeId}}{$TypeId}{"Copied"};
+}
+
+sub isLeafClass($$)
+{
+    my ($ClassId, $LibVersion) = @_;
+    return (not keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}));
+}
+
+sub havePubFields($)
+{# check structured type for public fields
+    return isAccessible($_[0], (), 0, -1);
+}
+
+sub isAccessible($$$$)
+{# check interval in structured type for public fields
+    my ($TypePtr, $Skip, $Start, $End) = @_;
+    return 0 if(not $TypePtr);
+    if($End==-1) {
+        $End = keys(%{$TypePtr->{"Memb"}})-1;
+    }
+    foreach my $MemPos (keys(%{$TypePtr->{"Memb"}}))
+    {
+        if($Skip and $Skip->{$MemPos})
+        { # skip removed/added fields
+            next;
+        }
+        if(int($MemPos)>=$Start and int($MemPos)<=$End)
+        {
+            if(isPublic($TypePtr, $MemPos)) {
+                return ($MemPos+1);
+            }
+        }
+    }
+    return 0;
+}
+
+sub getAlignment($$$)
+{
+    my ($Pos, $TypePtr, $LibVersion) = @_;
+    my $Tid = $TypePtr->{"Memb"}{$Pos}{"type"};
+    my %Type = get_PureType($Tid_TDid{$LibVersion}{$Tid}, $Tid, $LibVersion);
+    my $TSize = $Type{"Size"}*$BYTE_SIZE;
+    my $MSize = $Type{"Size"}*$BYTE_SIZE;
+    if(my $BSize = $TypePtr->{"Memb"}{$Pos}{"bitfield"})
+    { # bitfields
+        ($TSize, $MSize) = ($WORD_SIZE{$LibVersion}*$BYTE_SIZE, $BSize);
+    }
+    elsif($Type{"Type"} eq "Array")
+    { # in the context of function parameter
+      # it's passed through the pointer
+    }
+    # alignment
+    my $Alignment = $WORD_SIZE{$LibVersion}*$BYTE_SIZE; # default
+    if(my $Computed = $TypePtr->{"Memb"}{$Pos}{"algn"})
+    { # computed by GCC
+        $Alignment = $Computed*$BYTE_SIZE;
+    }
+    elsif($TypePtr->{"Memb"}{$Pos}{"bitfield"})
+    { # bitfields are 1 bit aligned
+        $Alignment = 1;
+    }
+    elsif($TSize and $TSize<$WORD_SIZE{$LibVersion}*$BYTE_SIZE)
+    { # model
+        $Alignment = $TSize;
+    }
+    return ($Alignment, $MSize);
+}
+
+sub getOffset($$$)
+{ # offset of the field including padding
+    my ($FieldPos, $TypePtr, $LibVersion) = @_;
+    my $Offset = 0;
+    foreach my $Pos (0 .. keys(%{$TypePtr->{"Memb"}})-1)
+    {
+        my ($Alignment, $MSize) = getAlignment($Pos, $TypePtr, $LibVersion);
+        # padding
+        my $Padding = 0;
+        if($Offset % $Alignment!=0)
+        { # not aligned, add padding
+            $Padding = $Alignment - $Offset % $Alignment;
+        }
+        $Offset += $Padding;
+        if($Pos==$FieldPos)
+        { # after the padding
+          # before the field
+            return $Offset;
+        }
+        $Offset += $MSize;
+    }
+    return $FieldPos;# if something is going wrong
+}
+
+sub isMemPadded($$$$$)
+{ # check if the target field can be added/removed/changed
+  # without shifting other fields because of padding bits
+    my ($FieldPos, $Size, $TypePtr, $Skip, $LibVersion) = @_;
+    return 0 if($FieldPos==0);
+    if(defined $TypePtr->{"Memb"}{""})
+    {
+        delete($TypePtr->{"Memb"}{""});
+        if($Debug) {
+            printMsg("WARNING", "internal error detected");
+        }
+    }
+    my $Offset = 0;
+    my (%Alignment, %MSize) = ();
+    my $MaxAlgn = 0;
+    my $End = keys(%{$TypePtr->{"Memb"}})-1;
+    my $NextField = $FieldPos+1;
+    foreach my $Pos (0 .. $End)
+    {
+        if($Skip and $Skip->{$Pos})
+        { # skip removed/added fields
+            if($Pos > $FieldPos)
+            { # after the target
+                $NextField += 1;
+                next;
+            }
+        }
+        ($Alignment{$Pos}, $MSize{$Pos}) = getAlignment($Pos, $TypePtr, $LibVersion);
+        if($Alignment{$Pos}>$MaxAlgn) {
+            $MaxAlgn = $Alignment{$Pos};
+        }
+        if($Pos==$FieldPos)
+        {
+            if($Size==-1)
+            { # added/removed fields
+                if($Pos!=$End)
+                { # skip target field and see
+                  # if enough padding will be
+                  # created on the next step
+                  # to include this field
+                    next;
+                }
+            }
+        }
+        # padding
+        my $Padding = 0;
+        if($Offset % $Alignment{$Pos}!=0)
+        { # not aligned, add padding
+            $Padding = $Alignment{$Pos} - $Offset % $Alignment{$Pos};
+        }
+        if($Pos==$NextField)
+        { # try to place target field in the padding
+            if($Size==-1)
+            { # added/removed fields
+                my $TPadding = 0;
+                if($Offset % $Alignment{$FieldPos}!=0)
+                {# padding of the target field
+                    $TPadding = $Alignment{$FieldPos} - $Offset % $Alignment{$FieldPos};
+                }
+                if($TPadding+$MSize{$FieldPos}<=$Padding)
+                { # enough padding to place target field
+                    return 1;
+                }
+                else {
+                    return 0;
+                }
+            }
+            else
+            { # changed fields
+                my $Delta = $Size-$MSize{$FieldPos};
+                if($Delta>=0)
+                { # increased
+                    if($Size-$MSize{$FieldPos}<=$Padding)
+                    { # enough padding to change target field
+                        return 1;
+                    }
+                    else {
+                        return 0;
+                    }
+                }
+                else
+                { # decreased
+                    $Delta = abs($Delta);
+                    if($Delta+$Padding>=$MSize{$Pos})
+                    { # try to place the next field
+                        if(($Offset-$Delta) % $Alignment{$Pos} != 0)
+                        { # padding of the next field in new place
+                            my $NPadding = $Alignment{$Pos} - ($Offset-$Delta) % $Alignment{$Pos};
+                            if($NPadding+$MSize{$Pos}<=$Delta+$Padding)
+                            { # enough delta+padding to store next field
+                                return 0;
+                            }
+                        }
+                        else
+                        {
+                            return 0;
+                        }
+                    }
+                    return 1;
+                }
+            }
+        }
+        elsif($Pos==$End)
+        { # target field is the last field
+            if($Size==-1)
+            { # added/removed fields
+                if($Offset % $MaxAlgn!=0)
+                { # tail padding
+                    my $TailPadding = $MaxAlgn - $Offset % $MaxAlgn;
+                    if($Padding+$MSize{$Pos}<=$TailPadding)
+                    { # enough tail padding to place the last field
+                        return 1;
+                    }
+                }
+                return 0;
+            }
+            else
+            { # changed fields
+                # scenario #1
+                my $Offset1 = $Offset+$Padding+$MSize{$Pos};
+                if($Offset1 % $MaxAlgn != 0)
+                { # tail padding
+                    $Offset1 += $MaxAlgn - $Offset1 % $MaxAlgn;
+                }
+                # scenario #2
+                my $Offset2 = $Offset+$Padding+$Size;
+                if($Offset2 % $MaxAlgn != 0)
+                { # tail padding
+                    $Offset2 += $MaxAlgn - $Offset2 % $MaxAlgn;
+                }
+                if($Offset1!=$Offset2)
+                { # different sizes of structure
+                    return 0;
+                }
+                return 1;
+            }
+        }
+        $Offset += $Padding+$MSize{$Pos};
+    }
+    return 0;
+}
+
+sub isReserved($)
+{ # reserved fields == private
+    my $MName = $_[0];
+    if($MName=~/reserved|padding|f_spare/i) {
+        return 1;
+    }
+    if($MName=~/\A[_]*(spare|pad|unused)[_]*\Z/i) {
+        return 1;
+    }
+    if($MName=~/(pad\d+)/i) {
+        return 1;
+    }
+    return 0;
+}
+
+sub isPublic($$)
+{
+    my ($TypePtr, $FieldPos) = @_;
+    return 0 if(not $TypePtr);
+    return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos});
+    return 0 if(not defined $TypePtr->{"Memb"}{$FieldPos}{"name"});
+    if(not $TypePtr->{"Memb"}{$FieldPos}{"access"})
+    { # by name in C language
+      # FIXME: add other methods to detect private members
+        my $MName = $TypePtr->{"Memb"}{$FieldPos}{"name"};
+        if($MName=~/priv|abidata|parent_object/i)
+        { # C-styled private data
+            return 0;
+        }
+        if(lc($MName) eq "abi")
+        { # ABI information/reserved field
+            return 0;
+        }
+        if(isReserved($MName))
+        { # reserved fields
+            return 0;
+        }
+        return 1;
+    }
+    elsif($TypePtr->{"Memb"}{$FieldPos}{"access"} ne "private")
+    { # by access in C++ language
+        return 1;
+    }
+    return 0;
+}
+
+sub cmpVTables_Model($)
+{
+    my $ClassName = $_[0];
+    foreach my $Symbol (keys(%{$VirtualTable_Full{1}{$ClassName}}))
+    {
+        if(not defined $VirtualTable_Full{2}{$ClassName}{$Symbol}) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+sub cmpVTables($$)
+{
+    my ($ClassName, $Strong) = @_;
+    my $ClassId1 = $ClassToId{1}{$ClassName};
+    my $ClassId2 = $ClassToId{2}{$ClassName};
+    my %Type1 = get_Type($Tid_TDid{1}{$ClassId1}, $ClassId1, 1);
+    my %Type2 = get_Type($Tid_TDid{2}{$ClassId2}, $ClassId2, 2);
+    if(not defined $Type1{"VTable"}
+    or not defined $Type2{"VTable"})
+    { # old ABI dumps
+        return 0;
+    }
+    my %Indexes = map {$_=>1} (keys(%{$Type1{"VTable"}}), keys(%{$Type2{"VTable"}}));
+    foreach my $Offset (sort {int($a)<=>int($b)} keys(%Indexes))
+    {
+        if(not defined $Type1{"VTable"}{$Offset})
+        { # v-table v.1 < v-table v.2
+            return $Strong;
+        }
+        my $Entry1 = $Type1{"VTable"}{$Offset};
+        if(not defined $Type2{"VTable"}{$Offset})
+        { # v-table v.1 > v-table v.2
+            return $Strong;
+        }
+        my $Entry2 = $Type2{"VTable"}{$Offset};
+        $Entry1 = simpleVEntry($Entry1);
+        $Entry2 = simpleVEntry($Entry2);
+        if($Entry1 ne $Entry2)
+        { # register as changed
+            if($Entry1=~/::([^:]+)\Z/)
+            {
+                my $M1 = $1;
+                if($Entry2=~/::([^:]+)\Z/)
+                {
+                    my $M2 = $1;
+                    if($M1 eq $M2)
+                    { # overridden
+                        next;
+                    }
+                }
+            }
+            return 1;
+        }
+    }
+    return 0;
+}
+
+sub mergeVTables()
+{ # merging v-tables without diagnostics
+    foreach my $ClassName (keys(%{$VirtualTable{1}}))
+    {
+        if($VTableChanged{$ClassName})
+        { # already registered
+            next;
+        }
+        if(cmpVTables($ClassName, 0))
+        {
+            my @Affected = (keys(%{$ClassMethods{1}{$ClassName}}));
+            foreach my $Symbol (@Affected)
+            {
+                %{$CompatProblems{$Symbol}{"Virtual_Table_Changed_Unknown"}{$ClassName}}=(
+                    "Type_Name"=>$ClassName,
+                    "Type_Type"=>"Class",
+                    "Target"=>$ClassName);
+            }
+        }
+    }
+}
+
+sub mergeBases()
+{
+    foreach my $ClassName (keys(%{$ClassToId{1}}))
+    { # detect added and removed virtual functions
+        my $ClassId = $ClassToId{1}{$ClassName};
+        next if(not $ClassId);
+        foreach my $VirtFunc (keys(%{$VirtualTable{2}{$ClassName}}))
+        {
+            if($ClassToId{1}{$ClassName}
+            and not defined $VirtualTable{1}{$ClassName}{$VirtFunc})
+            { # added to v-table
+                if(not $CompleteSignature{2}{$VirtFunc}{"Override"}) {
+                    $AddedInt_Virt{$ClassName}{$VirtFunc} = 1;
+                }
+            }
+        }
+        foreach my $VirtFunc (keys(%{$VirtualTable{1}{$ClassName}}))
+        {
+            if($ClassToId{2}{$ClassName}
+            and not defined $VirtualTable{2}{$ClassName}{$VirtFunc})
+            { # removed from v-table
+                if(not $CompleteSignature{1}{$VirtFunc}{"Override"}) {
+                    $RemovedInt_Virt{$ClassName}{$VirtFunc} = 1;
+                }
+            }
+        }
+        my %Class_Type = get_Type($Tid_TDid{1}{$ClassId}, $ClassId, 1);
+        foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$ClassName}}))
+        { # check replacements, including pure virtual methods
+            my $AddedPos = $VirtualTable{2}{$ClassName}{$AddedVFunc};
+            foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$ClassName}}))
+            {
+                my $RemovedPos = $VirtualTable{1}{$ClassName}{$RemovedVFunc};
+                if($AddedPos==$RemovedPos)
+                {
+                    $VirtualReplacement{$AddedVFunc} = $RemovedVFunc;
+                    $VirtualReplacement{$RemovedVFunc} = $AddedVFunc;
+                    last;# other methods will be reported as "added" or "removed"
+                }
+            }
+            if(my $RemovedVFunc = $VirtualReplacement{$AddedVFunc})
+            {
+                if(lc($AddedVFunc) eq lc($RemovedVFunc))
+                { # skip: DomUi => DomUI parameter (qt 4.2.3 to 4.3.0)
+                    next;
+                }
+                my $ProblemType = "Virtual_Replacement";
+                my @Affected = ($RemovedVFunc);
+                if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
+                { # pure methods
+                    if(not isUsedClass($ClassId, 1))
+                    { # not a parameter of some exported method
+                        next;
+                    }
+                    $ProblemType = "Pure_Virtual_Replacement";
+                    @Affected = (keys(%{$ClassMethods{1}{$ClassName}}))
+                }
+                foreach my $AffectedInt (@Affected)
+                {
+                    if($CompleteSignature{1}{$AffectedInt}{"PureVirt"})
+                    { # affected exported methods only
+                        next;
+                    }
+                    %{$CompatProblems{$AffectedInt}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
+                        "Type_Name"=>$Class_Type{"Name"},
+                        "Type_Type"=>"Class",
+                        "Target"=>get_Signature($AddedVFunc, 2),
+                        "Old_Value"=>get_Signature($RemovedVFunc, 1));
+                }
+            }
+        }
+    }
+    if($UsedDump{1}{"V"}
+    and cmpVersions($UsedDump{1}{"V"}, "2.0")<0)
+    { # support for old dumps
+      # "Base" attribute introduced in ACC 1.22 (dump 2.0 format)
+        return;
+    }
+    if($UsedDump{2}{"V"}
+    and cmpVersions($UsedDump{2}{"V"}, "2.0")<0)
+    { # support for old dumps
+      # "Base" attribute introduced in ACC 1.22 (dump 2.0 format)
+        return;
+    }
+    foreach my $ClassName (sort keys(%{$ClassToId{1}}))
+    {
+        my $ClassId_Old = $ClassToId{1}{$ClassName};
+        next if(not $ClassId_Old);
+        if(not isCreatable($ClassId_Old, 1))
+        { # skip classes without public constructors (including auto-generated)
+          # example: class has only a private exported or private inline constructor
+            next;
+        }
+        if($ClassName=~/>/)
+        { # skip affected template instances
+            next;
+        }
+        my %Class_Old = get_Type($Tid_TDid{1}{$ClassId_Old}, $ClassId_Old, 1);
+        my $ClassId_New = $ClassToId{2}{$ClassName};
+        next if(not $ClassId_New);
+        my %Class_New = get_Type($Tid_TDid{2}{$ClassId_New}, $ClassId_New, 2);
+        my @Bases_Old = sort {$Class_Old{"Base"}{$a}{"pos"}<=>$Class_Old{"Base"}{$b}{"pos"}} keys(%{$Class_Old{"Base"}});
+        my @Bases_New = sort {$Class_New{"Base"}{$a}{"pos"}<=>$Class_New{"Base"}{$b}{"pos"}} keys(%{$Class_New{"Base"}});
+        my ($BNum1, $BNum2) = (1, 1);
+        my %BasePos_Old = map {get_TypeName($_, 1) => $BNum1++} @Bases_Old;
+        my %BasePos_New = map {get_TypeName($_, 2) => $BNum2++} @Bases_New;
+        my %ShortBase_Old = map {get_TypeShort($_, 1) => 1} @Bases_Old;
+        my %ShortBase_New = map {get_TypeShort($_, 2) => 1} @Bases_New;
+        my $Shift_Old = getShift($ClassId_Old, 1);
+        my $Shift_New = getShift($ClassId_New, 2);
+        my %BaseId_New = map {get_TypeName($_, 2) => $_} @Bases_New;
+        my ($Added, $Removed) = (0, 0);
+        my @StableBases_Old = ();
+        foreach my $BaseId (@Bases_Old)
+        {
+            my $BaseName = get_TypeName($BaseId, 1);
+            if($BasePos_New{$BaseName}) {
+                push(@StableBases_Old, $BaseId);
+            }
+            elsif(not $ShortBase_New{$BaseName}
+            and not $ShortBase_New{get_TypeShort($BaseId, 1)})
+            { # removed base
+              # excluding namespace::SomeClass to SomeClass renaming
+                my $ProblemKind = "Removed_Base_Class";
+                if($Shift_Old ne $Shift_New)
+                { # affected fields
+                    if(havePubFields(\%Class_Old)) {
+                        $ProblemKind .= "_And_Shift";
+                    }
+                    elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
+                        $ProblemKind .= "_And_Size";
+                    }
+                }
+                if(keys(%{$VirtualTable_Full{1}{$BaseName}})
+                and (cmpVTables($ClassName, 1) or cmpVTables_Model($ClassName)))
+                { # affected v-table
+                    $ProblemKind .= "_And_VTable";
+                    $VTableChanged{$ClassName}=1;
+                }
+                my @Affected = keys(%{$ClassMethods{1}{$ClassName}});
+                foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
+                {
+                    my $SubName = get_TypeName($SubId, 1);
+                    push(@Affected, keys(%{$ClassMethods{1}{$SubName}}));
+                    if($ProblemKind=~/VTable/) {
+                        $VTableChanged{$SubName}=1;
+                    }
+                }
+                foreach my $Interface (@Affected)
+                {
+                    %{$CompatProblems{$Interface}{$ProblemKind}{"this"}}=(
+                        "Type_Name"=>$ClassName,
+                        "Type_Type"=>"Class",
+                        "Target"=>$BaseName,
+                        "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
+                        "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
+                        "Shift"=>abs($Shift_New-$Shift_Old)  );
+                }
+                $Removed+=1;
+            }
+        }
+        my @StableBases_New = ();
+        foreach my $BaseId (@Bases_New)
+        {
+            my $BaseName = get_TypeName($BaseId, 2);
+            if($BasePos_Old{$BaseName}) {
+                push(@StableBases_New, $BaseId);
+            }
+            elsif(not $ShortBase_Old{$BaseName}
+            and not $ShortBase_Old{get_TypeShort($BaseId, 2)})
+            { # added base
+              # excluding namespace::SomeClass to SomeClass renaming
+                my $ProblemKind = "Added_Base_Class";
+                if($Shift_Old ne $Shift_New)
+                { # affected fields
+                    if(havePubFields(\%Class_Old)) {
+                        $ProblemKind .= "_And_Shift";
+                    }
+                    elsif($Class_Old{"Size"} ne $Class_New{"Size"}) {
+                        $ProblemKind .= "_And_Size";
+                    }
+                }
+                if(keys(%{$VirtualTable_Full{2}{$BaseName}})
+                and (cmpVTables($ClassName, 1) or cmpVTables_Model($ClassName)))
+                { # affected v-table
+                    $ProblemKind .= "_And_VTable";
+                    $VTableChanged{$ClassName}=1;
+                }
+                my @Affected = keys(%{$ClassMethods{1}{$ClassName}});
+                foreach my $SubId (get_sub_classes($ClassId_Old, 1, 1))
+                {
+                    my $SubName = get_TypeName($SubId, 1);
+                    push(@Affected, keys(%{$ClassMethods{1}{$SubName}}));
+                    if($ProblemKind=~/VTable/) {
+                        $VTableChanged{$SubName}=1;
+                    }
+                }
+                foreach my $Interface (@Affected)
+                {
+                    %{$CompatProblems{$Interface}{$ProblemKind}{"this"}}=(
+                        "Type_Name"=>$ClassName,
+                        "Type_Type"=>"Class",
+                        "Target"=>$BaseName,
+                        "Old_Size"=>$Class_Old{"Size"}*$BYTE_SIZE,
+                        "New_Size"=>$Class_New{"Size"}*$BYTE_SIZE,
+                        "Shift"=>abs($Shift_New-$Shift_Old)  );
+                }
+                $Added+=1;
+            }
+        }
+        ($BNum1, $BNum2) = (1, 1);
+        my %BaseRelPos_Old = map {get_TypeName($_, 1) => $BNum1++} @StableBases_Old;
+        my %BaseRelPos_New = map {get_TypeName($_, 2) => $BNum2++} @StableBases_New;
+        foreach my $BaseId (@Bases_Old)
+        {
+            my $BaseName = get_TypeName($BaseId, 1);
+            if(my $NewPos = $BaseRelPos_New{$BaseName})
+            {
+                my $BaseNewId = $BaseId_New{$BaseName};
+                my $OldPos = $BaseRelPos_Old{$BaseName};
+                if($NewPos!=$OldPos)
+                { # changed position of the base class
+                    foreach my $Interface (keys(%{$ClassMethods{1}{$ClassName}}))
+                    {
+                        %{$CompatProblems{$Interface}{"Base_Class_Position"}{"this"}}=(
+                            "Type_Name"=>$ClassName,
+                            "Type_Type"=>"Class",
+                            "Target"=>$BaseName,
+                            "Old_Value"=>$OldPos-1,
+                            "New_Value"=>$NewPos-1  );
+                    }
+                }
+                if($Class_Old{"Base"}{$BaseId}{"virtual"}
+                and not $Class_New{"Base"}{$BaseNewId}{"virtual"})
+                { # became non-virtual base
+                    foreach my $Interface (keys(%{$ClassMethods{1}{$ClassName}}))
+                    {
+                        %{$CompatProblems{$Interface}{"Base_Class_Became_Non_Virtually_Inherited"}{"this->".$BaseName}}=(
+                            "Type_Name"=>$ClassName,
+                            "Type_Type"=>"Class",
+                            "Target"=>$BaseName  );
+                    }
+                }
+                elsif(not $Class_Old{"Base"}{$BaseId}{"virtual"}
+                and $Class_New{"Base"}{$BaseNewId}{"virtual"})
+                { # became virtual base
+                    foreach my $Interface (keys(%{$ClassMethods{1}{$ClassName}}))
+                    {
+                        %{$CompatProblems{$Interface}{"Base_Class_Became_Virtually_Inherited"}{"this->".$BaseName}}=(
+                            "Type_Name"=>$ClassName,
+                            "Type_Type"=>"Class",
+                            "Target"=>$BaseName  );
+                    }
+                }
+            }
+        }
+        # detect size changes in base classes
+        if($Shift_Old!=$Shift_New)
+        { # size of allocable class
+            foreach my $BaseId (@StableBases_Old)
+            { # search for changed base
+                my %BaseType = get_Type($Tid_TDid{1}{$BaseId}, $BaseId, 1);
+                my $Size_Old = get_TypeSize($BaseId, 1);
+                my $Size_New = get_TypeSize($BaseId_New{$BaseType{"Name"}}, 2);
+                if($Size_Old ne $Size_New
+                and $Size_Old and $Size_New)
+                {
+                    my $ProblemType = "";
+                    if(isCopyingClass($BaseId, 1)) {
+                        $ProblemType = "Size_Of_Copying_Class";
+                    }
+                    elsif($AllocableClass{1}{$BaseType{"Name"}})
+                    {
+                        if($Size_New>$Size_Old)
+                        { # increased size
+                            $ProblemType = "Size_Of_Allocable_Class_Increased";
+                        }
+                        else
+                        { # decreased size
+                            $ProblemType = "Size_Of_Allocable_Class_Decreased";
+                            if(not havePubFields(\%Class_Old))
+                            { # affected class has no public members
+                                next;
+                            }
+                        }
+                    }
+                    next if(not $ProblemType);
+                    foreach my $Interface (keys(%{$ClassMethods{1}{$ClassName}}))
+                    { # base class size changes affecting current class
+                        %{$CompatProblems{$Interface}{$ProblemType}{"this->".$BaseType{"Name"}}}=(
+                            "Type_Name"=>$BaseType{"Name"},
+                            "Type_Type"=>"Class",
+                            "Target"=>$BaseType{"Name"},
+                            "Old_Size"=>$Size_Old*$BYTE_SIZE,
+                            "New_Size"=>$Size_New*$BYTE_SIZE  );
+                    }
+                }
+            }
+        }
+        if(my @VFunctions = keys(%{$VirtualTable{1}{$ClassName}}))
+        { # compare virtual tables size in base classes
+            my $VShift_Old = getVShift($ClassId_Old, 1);
+            my $VShift_New = getVShift($ClassId_New, 2);
+            if($VShift_Old ne $VShift_New)
+            { # changes in the base class or changes in the list of base classes
+                my @AllBases_Old = get_base_classes($ClassId_Old, 1, 1);
+                my @AllBases_New = get_base_classes($ClassId_New, 2, 1);
+                ($BNum1, $BNum2) = (1, 1);
+                my %StableBase = map {get_TypeName($_, 2) => $_} @AllBases_New;
+                foreach my $BaseId (@AllBases_Old)
+                {
+                    my %BaseType = get_Type($Tid_TDid{1}{$BaseId}, $BaseId, 1);
+                    if(not $StableBase{$BaseType{"Name"}})
+                    { # lost base
+                        next;
+                    }
+                    my $VSize_Old = getVSize($BaseType{"Name"}, 1);
+                    my $VSize_New = getVSize($BaseType{"Name"}, 2);
+                    if($VSize_Old!=$VSize_New)
+                    {
+                        my $VRealSize_Old = get_VTableSymbolSize($BaseType{"Name"}, 1);
+                        my $VRealSize_New = get_VTableSymbolSize($BaseType{"Name"}, 2);
+                        if(not $VRealSize_Old or not $VRealSize_New)
+                        { # try to compute a model v-table size
+                            $VRealSize_Old = ($VSize_Old+2+getVShift($BaseId, 1))*$WORD_SIZE{1};
+                            $VRealSize_New = ($VSize_New+2+getVShift($StableBase{$BaseType{"Name"}}, 2))*$WORD_SIZE{2};
+                        }
+                        foreach my $Interface (@VFunctions)
+                        {
+                            if(not defined $VirtualTable{2}{$ClassName}{$Interface})
+                            { # Removed_Virtual_Method, will be registered in mergeVirtualTables()
+                                next;
+                            }
+                            if($VirtualTable{2}{$ClassName}{$Interface}-$VirtualTable{1}{$ClassName}{$Interface}+$VSize_New-$VSize_Old==0)
+                            { # skip interfaces that have not changed the absolute virtual position
+                                next;
+                            }
+                            if(not link_symbol($Interface, 1, "-Deps")
+                            and not $CheckHeadersOnly)
+                            { # affected symbols in shared library
+                                next;
+                            }
+                            if($LIB_ARCH{1} eq $LIB_ARCH{2}
+                            or not $LIB_ARCH{1} or not $LIB_ARCH{2})
+                            {
+                                %{$CompatProblems{$Interface}{"Virtual_Table_Size"}{$BaseType{"Name"}}}=(
+                                    "Type_Name"=>$BaseType{"Name"},
+                                    "Type_Type"=>"Class",
+                                    "Target"=>get_Signature($Interface, 1),
+                                    "Old_Size"=>$VRealSize_Old*$BYTE_SIZE,
+                                    "New_Size"=>$VRealSize_New*$BYTE_SIZE  );
+                            }
+                            $VTableChanged{$BaseType{"Name"}} = 1;
+                            $VTableChanged{$ClassName} = 1;
+                            foreach my $VirtFunc (keys(%{$AddedInt_Virt{$BaseType{"Name"}}}))
+                            { # the reason of the layout change: added virtual functions
+                                next if($VirtualReplacement{$VirtFunc});
+                                my $ProblemType = "Added_Virtual_Method";
+                                if($CompleteSignature{2}{$VirtFunc}{"PureVirt"}) {
+                                    $ProblemType = "Added_Pure_Virtual_Method";
+                                }
+                                %{$CompatProblems{$Interface}{$ProblemType}{get_Signature($VirtFunc, 2)}}=(
+                                    "Type_Name"=>$BaseType{"Name"},
+                                    "Type_Type"=>"Class",
+                                    "Target"=>get_Signature($VirtFunc, 2)  );
+                            }
+                            foreach my $VirtFunc (keys(%{$RemovedInt_Virt{$BaseType{"Name"}}}))
+                            { # the reason of the layout change: removed virtual functions
+                                next if($VirtualReplacement{$VirtFunc});
+                                my $ProblemType = "Removed_Virtual_Method";
+                                if($CompleteSignature{1}{$VirtFunc}{"PureVirt"}) {
+                                    $ProblemType = "Removed_Pure_Virtual_Method";
+                                }
+                                %{$CompatProblems{$Interface}{$ProblemType}{get_Signature($VirtFunc, 1)}}=(
+                                    "Type_Name"=>$BaseType{"Name"},
+                                    "Type_Type"=>"Class",
+                                    "Target"=>get_Signature($VirtFunc, 1)  );
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+sub isCreatable($$)
+{
+    my ($ClassId, $LibVersion) = @_;
+    if($AllocableClass{$LibVersion}{get_TypeName($ClassId, $LibVersion)}
+    or isCopyingClass($ClassId, $LibVersion)) {
+        return 1;
+    }
+    if(keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
+    { # Fix for incomplete data: if this class has
+      # a base class then it should also has a constructor 
+        return 1;
+    }
+    if($ReturnedClass{$LibVersion}{$ClassId})
+    { # returned by some method of this class
+      # or any other class
+        return 1;
+    }
+    return 0;
+}
+
+sub isUsedClass($$)
+{
+    my ($ClassId, $LibVersion) = @_;
+    if(keys(%{$ParamClass{$LibVersion}{$ClassId}}))
+    { # parameter of some exported method
+        return 1;
+    }
+    my $CName = get_TypeName($ClassId, 1);
+    if(keys(%{$ClassMethods{1}{$CName}}))
+    { # method from target class
+        return 1;
+    }
+    return 0;
+}
+
+sub mergeVirtualTables($)
+{ # check for changes in the virtual table
+    my $Interface = $_[0];
+    # affected method:
+    #  - virtual
+    #  - pure-virtual
+    #  - non-virtual
+    if($CompleteSignature{1}{$Interface}{"Data"})
+    { # global data is not affected
+        return;
+    }
+    my $Class_Id = $CompleteSignature{1}{$Interface}{"Class"};
+    my $CName = get_TypeName($Class_Id, 1);
+    if($CompleteSignature{1}{$Interface}{"PureVirt"}
+    and not isUsedClass($Class_Id, 1))
+    { # pure virtuals should not be affected
+      # if there are no exported methods using this class
+        return;
+    }
+    $CheckedTypes{$CName} = 1;
+    # check virtual table structure
+    foreach my $AddedVFunc (keys(%{$AddedInt_Virt{$CName}}))
+    {
+        next if($Interface eq $AddedVFunc);
+        next if($VirtualReplacement{$AddedVFunc});
+        my $VPos_Added = $VirtualTable{2}{$CName}{$AddedVFunc};
+        if($CompleteSignature{2}{$AddedVFunc}{"PureVirt"})
+        { # pure virtual methods affect all others (virtual and non-virtual)
+            %{$CompatProblems{$Interface}{"Added_Pure_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
+                "Type_Name"=>$CName,
+                "Type_Type"=>"Class",
+                "Target"=>get_Signature($AddedVFunc, 2)  );
+            $VTableChanged{$CName} = 1;
+        }
+        elsif($VPos_Added>keys(%{$VirtualTable{1}{$CName}}))
+        { # added virtual function at the end of v-table
+            if(not keys(%{$VirtualTable_Full{1}{$CName}}))
+            { # became polymorphous class, added v-table pointer
+                %{$CompatProblems{$Interface}{"Added_First_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
+                    "Type_Name"=>$CName,
+                    "Type_Type"=>"Class",
+                    "Target"=>get_Signature($AddedVFunc, 2)  );
+                $VTableChanged{$CName} = 1;
+            }
+            else
+            {
+                my $VSize_Old = getVSize($CName, 1);
+                my $VSize_New = getVSize($CName, 2);
+                next if($VSize_Old==$VSize_New);# exception: register as removed and added virtual method
+                if(isCopyingClass($Class_Id, 1))
+                { # class has no constructors and v-table will be copied by applications, this may affect all methods
+                    my $ProblemType = "Added_Virtual_Method";
+                    if(isLeafClass($Class_Id, 1)) {
+                        $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Copying_Class";
+                    }
+                    %{$CompatProblems{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
+                        "Type_Name"=>$CName,
+                        "Type_Type"=>"Class",
+                        "Target"=>get_Signature($AddedVFunc, 2)  );
+                    $VTableChanged{$CName} = 1;
+                }
+                else
+                {
+                    my $ProblemType = "Added_Virtual_Method";
+                    if(isLeafClass($Class_Id, 1)) {
+                        $ProblemType = "Added_Virtual_Method_At_End_Of_Leaf_Allocable_Class";
+                    }
+                    %{$CompatProblems{$Interface}{$ProblemType}{$tr_name{$AddedVFunc}}}=(
+                        "Type_Name"=>$CName,
+                        "Type_Type"=>"Class",
+                        "Target"=>get_Signature($AddedVFunc, 2)  );
+                    $VTableChanged{$CName} = 1;
+                }
+            }
+        }
+        elsif($CompleteSignature{1}{$Interface}{"Virt"}
+        or $CompleteSignature{1}{$Interface}{"PureVirt"})
+        {
+            my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
+            my $VPos_New = $VirtualTable{2}{$CName}{$Interface};
+            if($VPos_Added<=$VPos_Old and $VPos_Old!=$VPos_New)
+            {
+                my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
+                foreach my $ASymbol (@Affected)
+                {
+                    if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"}
+                    and not link_symbol($ASymbol, 1, "-Deps")) {
+                        next;
+                    }
+                    $CheckedSymbols{$ASymbol} = 1;
+                    %{$CompatProblems{$ASymbol}{"Added_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
+                        "Type_Name"=>$CName,
+                        "Type_Type"=>"Class",
+                        "Target"=>get_Signature($AddedVFunc, 2)  );
+                    $VTableChanged{get_TypeName($CompleteSignature{1}{$ASymbol}{"Class"}, 1)} = 1;
+                }
+            }
+        }
+        else {
+            # safe
+        }
+    }
+    foreach my $RemovedVFunc (keys(%{$RemovedInt_Virt{$CName}}))
+    {
+        next if($VirtualReplacement{$RemovedVFunc});
+        if($RemovedVFunc eq $Interface
+        and $CompleteSignature{1}{$RemovedVFunc}{"PureVirt"})
+        { # This case is for removed virtual methods
+          # implemented in both versions of a library
+            next;
+        }
+        if(not keys(%{$VirtualTable_Full{2}{$CName}}))
+        { # became non-polymorphous class, removed v-table pointer
+            %{$CompatProblems{$Interface}{"Removed_Last_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
+                "Type_Name"=>$CName,
+                "Type_Type"=>"Class",
+                "Target"=>get_Signature($RemovedVFunc, 1)  );
+            $VTableChanged{$CName} = 1;
+        }
+        elsif($CompleteSignature{1}{$Interface}{"Virt"}
+        or $CompleteSignature{1}{$Interface}{"PureVirt"})
+        {
+            my $VPos_Removed = $VirtualTable{1}{$CName}{$RemovedVFunc};
+            my $VPos_Old = $VirtualTable{1}{$CName}{$Interface};
+            my $VPos_New = $VirtualTable{2}{$CName}{$Interface};
+            if($VPos_Removed<=$VPos_Old and $VPos_Old!=$VPos_New)
+            {
+                my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
+                foreach my $ASymbol (@Affected)
+                {
+                    if(not $CompleteSignature{1}{$ASymbol}{"PureVirt"}
+                    and not link_symbol($ASymbol, 1, "-Deps")) {
+                        next;
+                    }
+                    my $ProblemType = "Removed_Virtual_Method";
+                    if($CompleteSignature{1}{$RemovedVFunc}{"PureVirt"}) {
+                        $ProblemType = "Removed_Pure_Virtual_Method";
+                    }
+                    $CheckedSymbols{$ASymbol} = 1;
+                    %{$CompatProblems{$ASymbol}{$ProblemType}{$tr_name{$RemovedVFunc}}}=(
+                        "Type_Name"=>$CName,
+                        "Type_Type"=>"Class",
+                        "Target"=>get_Signature($RemovedVFunc, 1)  );
+                    $VTableChanged{get_TypeName($CompleteSignature{1}{$ASymbol}{"Class"}, 1)} = 1;
+                }
+            }
+        }
+    }
+}
+
+sub find_MemberPair_Pos_byName($$)
+{
+    my ($Member_Name, $Pair_Type) = @_;
+    $Member_Name=~s/\A[_]+|[_]+\Z//g;
+    foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
+    {
+        if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos})
+        {
+            my $Name = $Pair_Type->{"Memb"}{$MemberPair_Pos}{"name"};
+            $Name=~s/\A[_]+|[_]+\Z//g;
+            if($Name eq $Member_Name) {
+                return $MemberPair_Pos;
+            }
+        }
+    }
+    return "lost";
+}
+
+sub find_MemberPair_Pos_byVal($$)
+{
+    my ($Member_Value, $Pair_Type) = @_;
+    foreach my $MemberPair_Pos (sort {int($a)<=>int($b)} keys(%{$Pair_Type->{"Memb"}}))
+    {
+        if(defined $Pair_Type->{"Memb"}{$MemberPair_Pos}
+        and $Pair_Type->{"Memb"}{$MemberPair_Pos}{"value"} eq $Member_Value) {
+            return $MemberPair_Pos;
+        }
+    }
+    return "lost";
+}
+
+my %Priority_Value=(
+    "High"=>3,
+    "Medium"=>2,
+    "Low"=>1);
+
+sub max_priority($$)
+{
+    my ($Pr1, $Pr2) = @_;
+    if(cmp_priority($Pr1, $Pr2)) {
+        return $Pr1;
+    }
+    else {
+        return $Pr2;
+    }
+}
+
+sub cmp_priority($$)
+{
+    my ($Pr1, $Pr2) = @_;
+    return ($Priority_Value{$Pr1}>$Priority_Value{$Pr2});
+}
+
+sub getProblemSeverity($$)
+{
+    my ($Level, $Kind) = @_;
+    return $CompatRules{$Level}{$Kind}{"Severity"};
+}
+
+sub isRecurType($$$$)
+{
+    foreach (@RecurTypes)
+    {
+        if($_->{"Tid1"} eq $_[0]
+        and $_->{"TDid1"} eq $_[1]
+        and $_->{"Tid2"} eq $_[2]
+        and $_->{"TDid2"} eq $_[3])
+        {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+sub pushType($$$$)
+{
+    my %TypeIDs=(
+        "Tid1"  => $_[0],
+        "TDid1" => $_[1],
+        "Tid2"  => $_[2],
+        "TDid2" => $_[3]  );
+    push(@RecurTypes, \%TypeIDs);
+}
+
+sub isRenamed($$$$$)
+{
+    my ($MemPos, $Type1, $LVersion1, $Type2, $LVersion2) = @_;
+    my $Member_Name = $Type1->{"Memb"}{$MemPos}{"name"};
+    my $MemberType_Id = $Type1->{"Memb"}{$MemPos}{"type"};
+    my %MemberType_Pure = get_PureType($Tid_TDid{$LVersion1}{$MemberType_Id}, $MemberType_Id, $LVersion1);
+    if(not defined $Type2->{"Memb"}{$MemPos}) {
+        return "";
+    }
+    my $StraightPairType_Id = $Type2->{"Memb"}{$MemPos}{"type"};
+    my %StraightPairType_Pure = get_PureType($Tid_TDid{$LVersion2}{$StraightPairType_Id}, $StraightPairType_Id, $LVersion2);
+    
+    my $StraightPair_Name = $Type2->{"Memb"}{$MemPos}{"name"};
+    my $MemberPair_Pos_Rev = ($Member_Name eq $StraightPair_Name)?$MemPos:find_MemberPair_Pos_byName($StraightPair_Name, $Type1);
+    if($MemberPair_Pos_Rev eq "lost")
+    {
+        if($MemberType_Pure{"Name"} eq $StraightPairType_Pure{"Name"})
+        {# base type match
+            return $StraightPair_Name;
+        }
+        if(get_TypeName($MemberType_Id, $LVersion1) eq get_TypeName($StraightPairType_Id, $LVersion2))
+        {# exact type match
+            return $StraightPair_Name;
+        }
+        if($MemberType_Pure{"Size"} eq $StraightPairType_Pure{"Size"})
+        {# size match
+            return $StraightPair_Name;
+        }
+        if(isReserved($StraightPair_Name))
+        {# reserved fields
+            return $StraightPair_Name;
+        }
+    }
+    return "";
+}
+
+sub isLastElem($$)
+{
+    my ($Pos, $TypeRef) = @_;
+    my $Name = $TypeRef->{"Memb"}{$Pos}{"name"};
+    if($Name=~/last|count|max|total/i)
+    { # GST_LEVEL_COUNT, GST_RTSP_ELAST
+        return 1;
+    }
+    elsif($Name=~/END|NLIMITS\Z/)
+    { # __RLIMIT_NLIMITS
+        return 1;
+    }
+    elsif($Name=~/\AN[A-Z](.+)[a-z]+s\Z/
+    and $Pos+1==keys(%{$TypeRef->{"Memb"}}))
+    { # NImageFormats, NColorRoles
+        return 1;
+    }
+    return 0;
+}
+
+sub nonComparable($$)
+{
+    my ($T1, $T2) = @_;
+    if($T1->{"Name"} ne $T2->{"Name"}
+    and not isAnon($T1->{"Name"})
+    and not isAnon($T2->{"Name"}))
+    { # different names
+        if($T1->{"Type"} ne "Pointer"
+        or $T2->{"Type"} ne "Pointer")
+        { # compare base types
+            return 1;
+        }
+        if($T1->{"Name"}!~/\Avoid\s*\*/
+        and $T2->{"Name"}=~/\Avoid\s*\*/)
+        {
+            return 1;
+        }
+    }
+    elsif($T1->{"Type"} ne $T2->{"Type"})
+    { # different types
+        if($T1->{"Type"} eq "Class"
+        and $T2->{"Type"} eq "Struct")
+        { # "class" to "struct"
+            return 0;
+        }
+        elsif($T2->{"Type"} eq "Class"
+        and $T1->{"Type"} eq "Struct")
+        { # "struct" to "class"
+            return 0;
+        }
+        else
+        { # "class" to "enum"
+          # "union" to "class"
+          #  ...
+            return 1;
+        }
+    }
+    return 0;
+}
+
+sub mergeTypes($$$$)
+{
+    my ($Type1_Id, $Type1_DId, $Type2_Id, $Type2_DId) = @_;
+    return () if((not $Type1_Id and not $Type1_DId) or (not $Type2_Id and not $Type2_DId));
+    my (%Sub_SubProblems, %SubProblems) = ();
+    if($Cache{"mergeTypes"}{$Type1_Id}{$Type1_DId}{$Type2_Id}{$Type2_DId})
+    { # already merged
+        return %{$Cache{"mergeTypes"}{$Type1_Id}{$Type1_DId}{$Type2_Id}{$Type2_DId}};
+    }
+    my %Type1 = get_Type($Type1_DId, $Type1_Id, 1);
+    my %Type2 = get_Type($Type2_DId, $Type2_Id, 2);
+    my %Type1_Pure = get_PureType($Type1_DId, $Type1_Id, 1);
+    my %Type2_Pure = get_PureType($Type2_DId, $Type2_Id, 2);
+    $CheckedTypes{$Type1{"Name"}}=1;
+    $CheckedTypes{$Type1_Pure{"Name"}}=1;
+    return () if(not $Type1_Pure{"Size"} or not $Type2_Pure{"Size"});
+    if(isRecurType($Type1_Pure{"Tid"}, $Type1_Pure{"TDid"}, $Type2_Pure{"Tid"}, $Type2_Pure{"TDid"}))
+    { # skip recursive declarations
+        return ();
+    }
+    return () if(not $Type1_Pure{"Name"} or not $Type2_Pure{"Name"});
+    return () if($SkipTypes{1}{$Type1_Pure{"Name"}});
+    return () if($SkipTypes{1}{$Type1{"Name"}});
+    
+    my %Typedef_1 = goToFirst($Type1{"TDid"}, $Type1{"Tid"}, 1, "Typedef");
+    my %Typedef_2 = goToFirst($Type2{"TDid"}, $Type2{"Tid"}, 2, "Typedef");
+    if($Typedef_1{"Type"} eq "Typedef" and $Typedef_2{"Type"} eq "Typedef"
+    and $Typedef_1{"Name"} eq $Typedef_2{"Name"} and not $UseOldDumps)
+    {
+        my %Base_1 = get_OneStep_BaseType($Typedef_1{"TDid"}, $Typedef_1{"Tid"}, 1);
+        my %Base_2 = get_OneStep_BaseType($Typedef_2{"TDid"}, $Typedef_2{"Tid"}, 2);
+        if(differentFmts())
+        { # different GCC versions or different dumps
+            $Base_1{"Name"} = uncover_typedefs($Base_1{"Name"}, 1);
+            $Base_2{"Name"} = uncover_typedefs($Base_2{"Name"}, 2);
+            # std::__va_list and __va_list
+            $Base_1{"Name"}=~s/\A(\w+::)+//;
+            $Base_2{"Name"}=~s/\A(\w+::)+//;
+            $Base_1{"Name"} = formatName($Base_1{"Name"});
+            $Base_2{"Name"} = formatName($Base_2{"Name"});
+        }
+        if($Base_1{"Name"}!~/anon\-/ and $Base_2{"Name"}!~/anon\-/
+        and $Base_1{"Name"} ne $Base_2{"Name"})
+        {
+            if($Type1{"Size"} ne $Type2{"Size"})
+            {
+                %{$SubProblems{"DataType_Size"}{$Typedef_1{"Name"}}}=(
+                    "Target"=>$Typedef_1{"Name"},
+                    "Type_Name"=>$Typedef_1{"Name"},
+                    "Type_Type"=>"Typedef",
+                    "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
+                    "New_Size"=>$Type2{"Size"}*$BYTE_SIZE  );
+            }
+            %{$SubProblems{"Typedef_BaseType"}{$Typedef_1{"Name"}}}=(
+                "Target"=>$Typedef_1{"Name"},
+                "Type_Name"=>$Typedef_1{"Name"},
+                "Type_Type"=>"Typedef",
+                "Old_Value"=>$Base_1{"Name"},
+                "New_Value"=>$Base_2{"Name"}  );
+        }
+    }
+    if(nonComparable(\%Type1_Pure, \%Type2_Pure))
+    { # different types (reported in detectTypeChange(...))
+        if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
+        and $Type1_Pure{"Type"} ne $Type2_Pure{"Type"}
+        and $Type1_Pure{"Type"}!~/Intrinsic|Pointer|Ref|Typedef/)
+        { # different type of the type
+            %{$SubProblems{"DataType_Type"}{$Type1_Pure{"Name"}}}=(
+                "Target"=>$Type1_Pure{"Name"},
+                "Type_Name"=>$Type1_Pure{"Name"},
+                "Type_Type"=>$Type1_Pure{"Type"},
+                "Old_Value"=>lc($Type1_Pure{"Type"}),
+                "New_Value"=>lc($Type2_Pure{"Type"})  );
+        }
+        %{$Cache{"mergeTypes"}{$Type1_Id}{$Type1_DId}{$Type2_Id}{$Type2_DId}} = %SubProblems;
+        return %SubProblems;
+    }
+    pushType($Type1_Pure{"Tid"}, $Type1_Pure{"TDid"},
+             $Type2_Pure{"Tid"}, $Type2_Pure{"TDid"});
+    if(($Type1_Pure{"Name"} eq $Type2_Pure{"Name"}
+    or (isAnon($Type1_Pure{"Name"}) and isAnon($Type2_Pure{"Name"})))
+    and $Type1_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
+    { # checking size
+        if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
+        {
+            my $ProblemKind = "DataType_Size";
+            if($Type1_Pure{"Type"} eq "Class"
+            and keys(%{$ClassMethods{1}{$Type1_Pure{"Name"}}}))
+            {
+                if(isCopyingClass($Type1_Pure{"Tid"}, 1)) {
+                    $ProblemKind = "Size_Of_Copying_Class";
+                }
+                elsif($AllocableClass{1}{$Type1_Pure{"Name"}})
+                {
+                    if(int($Type2_Pure{"Size"})>int($Type1_Pure{"Size"})) {
+                        $ProblemKind = "Size_Of_Allocable_Class_Increased";
+                    }
+                    else {
+                        # descreased size of allocable class
+                        # it has no special effects
+                    }
+                }
+            }
+            %{$SubProblems{$ProblemKind}{$Type1_Pure{"Name"}}}=(
+                "Target"=>$Type1_Pure{"Name"},
+                "Type_Name"=>$Type1_Pure{"Name"},
+                "Type_Type"=>$Type1_Pure{"Type"},
+                "Old_Size"=>$Type1_Pure{"Size"}*$BYTE_SIZE,
+                "New_Size"=>$Type2_Pure{"Size"}*$BYTE_SIZE,
+                "InitialType_Type"=>$Type1_Pure{"Type"}  );
+        }
+    }
+    if($Type1_Pure{"BaseType"}{"Tid"} and $Type2_Pure{"BaseType"}{"Tid"})
+    {# checking base types
+        %Sub_SubProblems = mergeTypes($Type1_Pure{"BaseType"}{"Tid"}, $Type1_Pure{"BaseType"}{"TDid"},
+                                       $Type2_Pure{"BaseType"}{"Tid"}, $Type2_Pure{"BaseType"}{"TDid"});
+        foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
+        {
+            foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
+            {
+                foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
+                    $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
+                }
+                $SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{"InitialType_Type"} = $Type1_Pure{"Type"};
+            }
+        }
+    }
+    my (%AddedField, %RemovedField, %RenamedField, %RenamedField_Rev, %RelatedField, %RelatedField_Rev) = ();
+    my %NameToPosA = map {$Type1_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type1_Pure{"Memb"}});
+    my %NameToPosB = map {$Type2_Pure{"Memb"}{$_}{"name"}=>$_} keys(%{$Type2_Pure{"Memb"}});
+    foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
+    { # detect removed and renamed fields
+        my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
+        next if(not $Member_Name);
+        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);
+        if($MemberPair_Pos eq "lost")
+        {
+            if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
+            {
+                if(isUnnamed($Member_Name))
+                { # support for old-version dumps
+                  # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
+                    if($UsedDump{2}{"V"}
+                    and cmpVersions($UsedDump{2}{"V"}, "2.1")<0) {
+                        next;
+                    }
+                }
+                if(my $RenamedTo = isRenamed($Member_Pos, \%Type1_Pure, 1, \%Type2_Pure, 2))
+                { # renamed
+                    $RenamedField{$Member_Pos}=$RenamedTo;
+                    $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
+                }
+                else
+                { # removed
+                    $RemovedField{$Member_Pos}=1;
+                }
+            }
+            elsif($Type1_Pure{"Type"} eq "Enum")
+            {
+                my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
+                next if($Member_Value1 eq "");
+                $MemberPair_Pos = find_MemberPair_Pos_byVal($Member_Value1, \%Type2_Pure);
+                if($MemberPair_Pos ne "lost")
+                { # renamed
+                    my $RenamedTo = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"name"};
+                    my $MemberPair_Pos_Rev = find_MemberPair_Pos_byName($RenamedTo, \%Type1_Pure);
+                    if($MemberPair_Pos_Rev eq "lost")
+                    {
+                        $RenamedField{$Member_Pos}=$RenamedTo;
+                        $RenamedField_Rev{$NameToPosB{$RenamedTo}}=$Member_Name;
+                    }
+                    else {
+                        $RemovedField{$Member_Pos}=1;
+                    }
+                }
+                else
+                { # removed
+                    $RemovedField{$Member_Pos}=1;
+                }
+            }
+        }
+        else
+        { # related
+            $RelatedField{$Member_Pos} = $MemberPair_Pos;
+            $RelatedField_Rev{$MemberPair_Pos} = $Member_Pos;
+        }
+    }
+    foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
+    { # detect added fields
+        my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
+        next if(not $Member_Name);
+        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);
+        if($MemberPair_Pos eq "lost")
+        {
+            if(isUnnamed($Member_Name))
+            { # support for old-version dumps
+              # unnamed fields have been introduced in the ACC 1.23 (dump 2.1 format)
+                if($UsedDump{1}{"V"}
+                and cmpVersions($UsedDump{1}{"V"}, "2.1")<0) {
+                    next;
+                }
+            }
+            if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union|Enum)\Z/)
+            {
+                if(not $RenamedField_Rev{$Member_Pos})
+                { # added
+                    $AddedField{$Member_Pos}=1;
+                }
+            }
+        }
+    }
+    if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
+    { # detect moved fields
+        my (%RelPos, %RelPosName, %AbsPos) = ();
+        my $Pos = 0;
+        foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
+        { # relative positions in 1st version
+            my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
+            next if(not $Member_Name);
+            if(not $RemovedField{$Member_Pos})
+            { # old type without removed fields
+                $RelPos{1}{$Member_Name}=$Pos;
+                $RelPosName{1}{$Pos} = $Member_Name;
+                $AbsPos{1}{$Pos++} = $Member_Pos;
+            }
+        }
+        $Pos = 0;
+        foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
+        { # relative positions in 2nd version
+            my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
+            next if(not $Member_Name);
+            if(not $AddedField{$Member_Pos})
+            { # new type without added fields
+                $RelPos{2}{$Member_Name}=$Pos;
+                $RelPosName{2}{$Pos} = $Member_Name;
+                $AbsPos{2}{$Pos++} = $Member_Pos;
+            }
+        }
+        foreach my $Member_Name (keys(%{$RelPos{1}}))
+        {
+            my $RPos1 = $RelPos{1}{$Member_Name};
+            my $AbsPos1 = $NameToPosA{$Member_Name};
+            my $Member_Name2 = $Member_Name;
+            if(my $RenamedTo = $RenamedField{$AbsPos1})
+            { # renamed
+                $Member_Name2 = $RenamedTo;
+            }
+            my $RPos2 = $RelPos{2}{$Member_Name2};
+            if($RPos2 ne "" and $RPos1 ne $RPos2)
+            { # different relative positions
+                my $AbsPos2 = $NameToPosB{$Member_Name2};
+                if($AbsPos1 ne $AbsPos2)
+                { # different absolute positions
+                    my $ProblemType = "Moved_Field";
+                    if(not isPublic(\%Type1_Pure, $AbsPos1))
+                    { # may change layout and size of type
+                        $ProblemType = "Moved_Private_Field";
+                    }
+                    if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
+                    { # affected size
+                        my $MemSize1 = get_TypeSize($Type1_Pure{"Memb"}{$AbsPos1}{"type"}, 1);
+                        my $MovedAbsPos = $AbsPos{1}{$RPos2};
+                        my $MemSize2 = get_TypeSize($Type1_Pure{"Memb"}{$MovedAbsPos}{"type"}, 1);
+                        if($MemSize1 ne $MemSize2) {
+                            $ProblemType .= "_And_Size";
+                        }
+                    }
+                    if($ProblemType eq "Moved_Private_Field") {
+                        next;
+                    }
+                    %{$SubProblems{$ProblemType}{$Member_Name}}=(
+                        "Target"=>$Member_Name,
+                        "Type_Name"=>$Type1_Pure{"Name"},
+                        "Type_Type"=>$Type1_Pure{"Type"},
+                        "Old_Value"=>$RPos1,
+                        "New_Value"=>$RPos2 );
+                }
+            }
+        }
+    }
+    foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type1_Pure{"Memb"}}))
+    {# check older fields, public and private
+        my $Member_Name = $Type1_Pure{"Memb"}{$Member_Pos}{"name"};
+        next if(not $Member_Name);
+        if(my $RenamedTo = $RenamedField{$Member_Pos})
+        { # renamed
+            if($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
+            {
+                if(isPublic(\%Type1_Pure, $Member_Pos))
+                {
+                    %{$SubProblems{"Renamed_Field"}{$Member_Name}}=(
+                        "Target"=>$Member_Name,
+                        "Type_Name"=>$Type1_Pure{"Name"},
+                        "Type_Type"=>$Type1_Pure{"Type"},
+                        "Old_Value"=>$Member_Name,
+                        "New_Value"=>$RenamedTo  );
+                }
+            }
+            elsif($Type1_Pure{"Type"} eq "Enum")
+            {
+                %{$SubProblems{"Enum_Member_Name"}{$Type1_Pure{"Memb"}{$Member_Pos}{"value"}}}=(
+                    "Target"=>$Type1_Pure{"Memb"}{$Member_Pos}{"value"},
+                    "Type_Name"=>$Type1_Pure{"Name"},
+                    "Type_Type"=>$Type1_Pure{"Type"},
+                    "Old_Value"=>$Member_Name,
+                    "New_Value"=>$RenamedTo  );
+            }
+        }
+        elsif($RemovedField{$Member_Pos})
+        { # removed
+            if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
+            {
+                my $ProblemType = "Removed_Field";
+                if(not isPublic(\%Type1_Pure, $Member_Pos)
+                or isUnnamed($Member_Name)) {
+                    $ProblemType = "Removed_Private_Field";
+                }
+                if(not isMemPadded($Member_Pos, -1, \%Type1_Pure, \%RemovedField, 1))
+                {
+                    if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
+                    { # affected fields
+                        if(getOffset($MNum-1, \%Type1_Pure, 1)!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, 2))
+                        { # changed offset
+                            $ProblemType .= "_And_Layout";
+                        }
+                    }
+                    if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
+                    { # affected size
+                        $ProblemType .= "_And_Size";
+                    }
+                }
+                if($ProblemType eq "Removed_Private_Field") {
+                    next;
+                }
+                %{$SubProblems{$ProblemType}{$Member_Name}}=(
+                    "Target"=>$Member_Name,
+                    "Type_Name"=>$Type1_Pure{"Name"},
+                    "Type_Type"=>$Type1_Pure{"Type"}  );
+            }
+            elsif($Type2_Pure{"Type"} eq "Union")
+            {
+                if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
+                {
+                    %{$SubProblems{"Removed_Union_Field_And_Size"}{$Member_Name}}=(
+                        "Target"=>$Member_Name,
+                        "Type_Name"=>$Type1_Pure{"Name"},
+                        "Type_Type"=>$Type1_Pure{"Type"}  );
+                }
+                else
+                {
+                    %{$SubProblems{"Removed_Union_Field"}{$Member_Name}}=(
+                        "Target"=>$Member_Name,
+                        "Type_Name"=>$Type1_Pure{"Name"},
+                        "Type_Type"=>$Type1_Pure{"Type"}  );
+                }
+            }
+            elsif($Type1_Pure{"Type"} eq "Enum")
+            {
+                %{$SubProblems{"Enum_Member_Removed"}{$Member_Name}}=(
+                    "Target"=>$Member_Name,
+                    "Type_Name"=>$Type1_Pure{"Name"},
+                    "Type_Type"=>$Type1_Pure{"Type"},
+                    "Old_Value"=>$Member_Name  );
+            }
+        }
+        else
+        { # changed
+            my $MemberPair_Pos = $RelatedField{$Member_Pos};
+            if($Type1_Pure{"Type"} eq "Enum")
+            {
+                my $Member_Value1 = $Type1_Pure{"Memb"}{$Member_Pos}{"value"};
+                next if($Member_Value1 eq "");
+                my $Member_Value2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"value"};
+                next if($Member_Value2 eq "");
+                if($Member_Value1 ne $Member_Value2)
+                {
+                    my $ProblemType = "Enum_Member_Value";
+                    if(isLastElem($Member_Pos, \%Type1_Pure)) {
+                        $ProblemType = "Enum_Last_Member_Value";
+                    }
+                    %{$SubProblems{$ProblemType}{$Member_Name}}=(
+                        "Target"=>$Member_Name,
+                        "Type_Name"=>$Type1_Pure{"Name"},
+                        "Type_Type"=>$Type1_Pure{"Type"},
+                        "Old_Value"=>$Member_Value1,
+                        "New_Value"=>$Member_Value2  );
+                }
+            }
+            elsif($Type2_Pure{"Type"}=~/\A(Struct|Class|Union)\Z/)
+            {
+                my $MemberType1_Id = $Type1_Pure{"Memb"}{$Member_Pos}{"type"};
+                my $MemberType2_Id = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"type"};
+                my $SizeV1 = get_TypeSize($MemberType1_Id, 1)*$BYTE_SIZE;
+                if(my $BSize1 = $Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}) {
+                    $SizeV1 = $BSize1;
+                }
+                my $SizeV2 = get_TypeSize($MemberType2_Id, 2)*$BYTE_SIZE;
+                if(my $BSize2 = $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}) {
+                    $SizeV2 = $BSize2;
+                }
+                my $MemberType1_Name = get_TypeName($MemberType1_Id, 1);
+                my $MemberType2_Name = get_TypeName($MemberType2_Id, 2);
+                if($SizeV1 ne $SizeV2)
+                {
+                    if($MemberType1_Name eq $MemberType2_Name or (isAnon($MemberType1_Name) and isAnon($MemberType2_Name))
+                    or ($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"} and $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"}))
+                    { # field size change (including anon-structures and unions)
+                      # - same types
+                      # - unnamed types
+                      # - bitfields
+                        my $ProblemType = "Field_Size";
+                        if(not isPublic(\%Type1_Pure, $Member_Pos)
+                        or isUnnamed($Member_Name))
+                        { # should not be accessed by applications, goes to "Low Severity"
+                          # example: "abidata" members in GStreamer types
+                            $ProblemType = "Private_".$ProblemType;
+                        }
+                        if(not isMemPadded($Member_Pos, get_TypeSize($MemberType2_Id, 2)*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, 1))
+                        { # check an effect
+                            if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
+                            { # public fields after the current
+                                if(getOffset($MNum-1, \%Type1_Pure, 1)!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, 2))
+                                { # changed offset
+                                    $ProblemType .= "_And_Layout";
+                                }
+                            }
+                            if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
+                                $ProblemType .= "_And_Type_Size";
+                            }
+                        }
+                        if($ProblemType eq "Private_Field_Size")
+                        { # private field size with no effect
+                            $ProblemType = "";
+                        }
+                        if($ProblemType)
+                        { # register a problem
+                            %{$SubProblems{$ProblemType}{$Member_Name}}=(
+                                "Target"=>$Member_Name,
+                                "Type_Name"=>$Type1_Pure{"Name"},
+                                "Type_Type"=>$Type1_Pure{"Type"},
+                                "Old_Size"=>$SizeV1,
+                                "New_Size"=>$SizeV2);
+                        }
+                    }
+                }
+                if($Type1_Pure{"Memb"}{$Member_Pos}{"bitfield"}
+                or $Type2_Pure{"Memb"}{$MemberPair_Pos}{"bitfield"})
+                { # do NOT check bitfield type changes
+                    next;
+                }
+                %Sub_SubProblems = detectTypeChange($MemberType1_Id, $MemberType2_Id, "Field");
+                foreach my $ProblemType (keys(%Sub_SubProblems))
+                {
+                    my $Old_Value = $Sub_SubProblems{$ProblemType}{"Old_Value"};
+                    my $New_Value = $Sub_SubProblems{$ProblemType}{"New_Value"};
+                    if($ProblemType eq "Field_Type"
+                    or $ProblemType eq "Field_Type_And_Size")
+                    {
+                        if((not $UsedDump{1}{"V"} or cmpVersions($UsedDump{1}{"V"}, "2.6")>=0)
+                        and (not $UsedDump{2}{"V"} or cmpVersions($UsedDump{2}{"V"}, "2.6")>=0))
+                        {
+                            if($Old_Value!~/(\A|\W)volatile(\W|\Z)/
+                            and $New_Value=~/(\A|\W)volatile(\W|\Z)/)
+                            { # non-"volatile" to "volatile"
+                                %{$Sub_SubProblems{"Field_Became_Volatile"}} = %{$Sub_SubProblems{$ProblemType}};
+                            }
+                        }
+                    }
+                }
+                foreach my $ProblemType (keys(%Sub_SubProblems))
+                {
+                    my $ProblemType_Init = $ProblemType;
+                    if($ProblemType eq "Field_Type_And_Size")
+                    {
+                        if(not isPublic(\%Type1_Pure, $Member_Pos)
+                        or isUnnamed($Member_Name)) {
+                            $ProblemType = "Private_".$ProblemType;
+                        }
+                        if(not isMemPadded($Member_Pos, get_TypeSize($MemberType2_Id, 2)*$BYTE_SIZE, \%Type1_Pure, \%RemovedField, 1))
+                        { # check an effect
+                            if(my $MNum = isAccessible(\%Type1_Pure, \%RemovedField, $Member_Pos+1, -1))
+                            { # public fields after the current
+                                if(getOffset($MNum-1, \%Type1_Pure, 1)!=getOffset($RelatedField{$MNum-1}, \%Type2_Pure, 2))
+                                { # changed offset
+                                    $ProblemType .= "_And_Layout";
+                                }
+                            }
+                            if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
+                                $ProblemType .= "_And_Type_Size";
+                            }
+                        }
+                    }
+                    else
+                    {
+                        if(not isPublic(\%Type1_Pure, $Member_Pos)
+                        or isUnnamed($Member_Name)) {
+                            next;
+                        }
+                    }
+                    if($ProblemType eq "Private_Field_Type_And_Size")
+                    { # private field change with no effect
+                        next;
+                    }
+                    %{$SubProblems{$ProblemType}{$Member_Name}}=(
+                        "Target"=>$Member_Name,
+                        "Type_Name"=>$Type1_Pure{"Name"},
+                        "Type_Type"=>$Type1_Pure{"Type"}  );
+                    foreach my $Attr (keys(%{$Sub_SubProblems{$ProblemType_Init}}))
+                    { # other properties
+                        $SubProblems{$ProblemType}{$Member_Name}{$Attr} = $Sub_SubProblems{$ProblemType_Init}{$Attr};
+                    }
+                }
+                if(not isPublic(\%Type1_Pure, $Member_Pos))
+                { # do NOT check internal type changes
+                    next;
+                }
+                if($MemberType1_Id and $MemberType2_Id)
+                {# checking member type changes (replace)
+                    %Sub_SubProblems = mergeTypes($MemberType1_Id, $Tid_TDid{1}{$MemberType1_Id},
+                                                  $MemberType2_Id, $Tid_TDid{2}{$MemberType2_Id});
+                    foreach my $Sub_SubProblemType (keys(%Sub_SubProblems))
+                    {
+                        foreach my $Sub_SubLocation (keys(%{$Sub_SubProblems{$Sub_SubProblemType}}))
+                        {
+                            my $NewLocation = ($Sub_SubLocation)?$Member_Name."->".$Sub_SubLocation:$Member_Name;
+                            $SubProblems{$Sub_SubProblemType}{$NewLocation}{"IsInTypeInternals"}=1;
+                            foreach my $Attr (keys(%{$Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}})) {
+                                $SubProblems{$Sub_SubProblemType}{$NewLocation}{$Attr} = $Sub_SubProblems{$Sub_SubProblemType}{$Sub_SubLocation}{$Attr};
+                            }
+                            if($Sub_SubLocation!~/\-\>/) {
+                                $SubProblems{$Sub_SubProblemType}{$NewLocation}{"Start_Type_Name"} = $MemberType1_Name;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    foreach my $Member_Pos (sort {int($a) <=> int($b)} keys(%{$Type2_Pure{"Memb"}}))
+    { # checking added members, public and private
+        my $Member_Name = $Type2_Pure{"Memb"}{$Member_Pos}{"name"};
+        next if(not $Member_Name);
+        if($AddedField{$Member_Pos})
+        { # added
+            if($Type2_Pure{"Type"}=~/\A(Struct|Class)\Z/)
+            {
+                my $ProblemType = "Added_Field";
+                if(not isPublic(\%Type2_Pure, $Member_Pos)
+                or isUnnamed($Member_Name)) {
+                    $ProblemType = "Added_Private_Field";
+                }
+                if(not isMemPadded($Member_Pos, -1, \%Type2_Pure, \%AddedField, 2))
+                {
+                    if(my $MNum = isAccessible(\%Type2_Pure, \%AddedField, $Member_Pos, -1))
+                    { # public fields after the current
+                        if(getOffset($MNum-1, \%Type2_Pure, 2)!=getOffset($RelatedField_Rev{$MNum-1}, \%Type1_Pure, 1))
+                        { # changed offset
+                            $ProblemType .= "_And_Layout";
+                        }
+                    }
+                    if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"}) {
+                        $ProblemType .= "_And_Size";
+                    }
+                }
+                if($ProblemType eq "Added_Private_Field")
+                { # skip added private fields
+                    next;
+                }
+                %{$SubProblems{$ProblemType}{$Member_Name}}=(
+                    "Target"=>$Member_Name,
+                    "Type_Name"=>$Type1_Pure{"Name"},
+                    "Type_Type"=>$Type1_Pure{"Type"}  );
+            }
+            elsif($Type2_Pure{"Type"} eq "Union")
+            {
+                if($Type1_Pure{"Size"} ne $Type2_Pure{"Size"})
+                {
+                    %{$SubProblems{"Added_Union_Field_And_Size"}{$Member_Name}}=(
+                        "Target"=>$Member_Name,
+                        "Type_Name"=>$Type1_Pure{"Name"},
+                        "Type_Type"=>$Type1_Pure{"Type"}  );
+                }
+                else
+                {
+                    %{$SubProblems{"Added_Union_Field"}{$Member_Name}}=(
+                        "Target"=>$Member_Name,
+                        "Type_Name"=>$Type1_Pure{"Name"},
+                        "Type_Type"=>$Type1_Pure{"Type"}  );
+                }
+            }
+            elsif($Type2_Pure{"Type"} eq "Enum")
+            {
+                my $Member_Value = $Type2_Pure{"Memb"}{$Member_Pos}{"value"};
+                next if($Member_Value eq "");
+                %{$SubProblems{"Added_Enum_Member"}{$Member_Name}}=(
+                    "Target"=>$Member_Name,
+                    "Type_Name"=>$Type2_Pure{"Name"},
+                    "Type_Type"=>$Type2_Pure{"Type"},
+                    "New_Value"=>$Member_Value  );
+            }
+        }
+    }
+    %{$Cache{"mergeTypes"}{$Type1_Id}{$Type1_DId}{$Type2_Id}{$Type2_DId}} = %SubProblems;
+    pop(@RecurTypes);
+    return %SubProblems;
+}
+
+sub isUnnamed($) {
+    return $_[0]=~/\Aunnamed\d+\Z/;
+}
+
+sub get_TypeName($$)
+{
+    my ($TypeId, $LibVersion) = @_;
+    return $TypeInfo{$LibVersion}{$Tid_TDid{$LibVersion}{$TypeId}}{$TypeId}{"Name"};
+}
+
+sub get_TypeShort($$)
+{
+    my ($TypeId, $LibVersion) = @_;
+    my $TypeName = $TypeInfo{$LibVersion}{$Tid_TDid{$LibVersion}{$TypeId}}{$TypeId}{"Name"};
+    my $NameSpace = $TypeInfo{$LibVersion}{$Tid_TDid{$LibVersion}{$TypeId}}{$TypeId}{"NameSpace"};
+    $TypeName=~s/\A$NameSpace\:\://g;
+    return $TypeName;
+}
+
+sub get_TypeSize($$)
+{
+    my ($TypeId, $LibVersion) = @_;
+    return $TypeInfo{$LibVersion}{$Tid_TDid{$LibVersion}{$TypeId}}{$TypeId}{"Size"};
+}
+
+sub get_TypeAttr($$$)
+{
+    my ($TypeId, $LibVersion, $Attr) = @_;
+    return $TypeInfo{$LibVersion}{$Tid_TDid{$LibVersion}{$TypeId}}{$TypeId}{$Attr};
+}
+
+sub goToFirst($$$$)
+{
+    my ($TypeDId, $TypeId, $LibVersion, $Type_Type) = @_;
+    if(defined $Cache{"goToFirst"}{$TypeDId}{$TypeId}{$LibVersion}{$Type_Type}) {
+        return %{$Cache{"goToFirst"}{$TypeDId}{$TypeId}{$LibVersion}{$Type_Type}};
+    }
+    return () if(not $TypeInfo{$LibVersion}{$TypeDId}{$TypeId});
+    my %Type = %{$TypeInfo{$LibVersion}{$TypeDId}{$TypeId}};
+    return () if(not $Type{"Type"});
+    if($Type{"Type"} ne $Type_Type)
+    {
+        return () if(not $Type{"BaseType"}{"TDid"} and not $Type{"BaseType"}{"Tid"});
+        %Type = goToFirst($Type{"BaseType"}{"TDid"}, $Type{"BaseType"}{"Tid"}, $LibVersion, $Type_Type);
+    }
+    $Cache{"goToFirst"}{$TypeDId}{$TypeId}{$LibVersion}{$Type_Type} = \%Type;
+    return %Type;
+}
+
+my %TypeSpecAttributes = (
+    "Const" => 1,
+    "Volatile" => 1,
+    "ConstVolatile" => 1,
+    "Restrict" => 1,
+    "Typedef" => 1
+);
+
+sub get_PureType($$$)
+{
+    my ($TypeDId, $TypeId, $LibVersion) = @_;
+    return "" if(not $TypeId);
+    if(defined $Cache{"get_PureType"}{$TypeDId}{$TypeId}{$LibVersion}) {
+        return %{$Cache{"get_PureType"}{$TypeDId}{$TypeId}{$LibVersion}};
+    }
+    return "" if(not $TypeInfo{$LibVersion}{$TypeDId}{$TypeId});
+    my %Type = %{$TypeInfo{$LibVersion}{$TypeDId}{$TypeId}};
+    return %Type if(not $Type{"BaseType"}{"TDid"} and not $Type{"BaseType"}{"Tid"});
+    if($TypeSpecAttributes{$Type{"Type"}}) {
+        %Type = get_PureType($Type{"BaseType"}{"TDid"}, $Type{"BaseType"}{"Tid"}, $LibVersion);
+    }
+    $Cache{"get_PureType"}{$TypeDId}{$TypeId}{$LibVersion} = \%Type;
+    return %Type;
+}
+
+sub get_PointerLevel($$$)
+{
+    my ($TypeDId, $TypeId, $LibVersion) = @_;
+    return 0 if(not $TypeId);
+    if(defined $Cache{"get_PointerLevel"}{$TypeDId}{$TypeId}{$LibVersion}) {
+        return $Cache{"get_PointerLevel"}{$TypeDId}{$TypeId}{$LibVersion};
+    }
+    return "" if(not $TypeInfo{$LibVersion}{$TypeDId}{$TypeId});
+    my %Type = %{$TypeInfo{$LibVersion}{$TypeDId}{$TypeId}};
+    return 1 if($Type{"Type"}=~/FuncPtr|MethodPtr|FieldPtr/);
+    return 0 if(not $Type{"BaseType"}{"TDid"} and not $Type{"BaseType"}{"Tid"});
+    my $PointerLevel = 0;
+    if($Type{"Type"} =~/Pointer|Ref|FuncPtr|MethodPtr|FieldPtr/) {
+        $PointerLevel += 1;
+    }
+    $PointerLevel += get_PointerLevel($Type{"BaseType"}{"TDid"}, $Type{"BaseType"}{"Tid"}, $LibVersion);
+    $Cache{"get_PointerLevel"}{$TypeDId}{$TypeId}{$LibVersion} = $PointerLevel;
+    return $PointerLevel;
+}
+
+sub get_BaseType($$$)
+{
+    my ($TypeDId, $TypeId, $LibVersion) = @_;
+    return () if(not $TypeId);
+    if(defined $Cache{"get_BaseType"}{$TypeDId}{$TypeId}{$LibVersion}) {
+        return %{$Cache{"get_BaseType"}{$TypeDId}{$TypeId}{$LibVersion}};
+    }
+    return () if(not $TypeInfo{$LibVersion}{$TypeDId}{$TypeId});
+    my %Type = %{$TypeInfo{$LibVersion}{$TypeDId}{$TypeId}};
+    return %Type if(not $Type{"BaseType"}{"TDid"} and not $Type{"BaseType"}{"Tid"});
+    %Type = get_BaseType($Type{"BaseType"}{"TDid"}, $Type{"BaseType"}{"Tid"}, $LibVersion);
+    $Cache{"get_BaseType"}{$TypeDId}{$TypeId}{$LibVersion} = \%Type;
+    return %Type;
+}
+
+sub get_BaseTypeQual($$$)
+{
+    my ($TypeDId, $TypeId, $LibVersion) = @_;
+    return "" if(not $TypeId);
+    return "" if(not $TypeInfo{$LibVersion}{$TypeDId}{$TypeId});
+    my %Type = %{$TypeInfo{$LibVersion}{$TypeDId}{$TypeId}};
+    return "" if(not $Type{"BaseType"}{"TDid"} and not $Type{"BaseType"}{"Tid"});
+    my $Qual = "";
+    if($Type{"Type"} eq "Pointer") {
+        $Qual .= "*";
+    }
+    elsif($Type{"Type"} eq "Ref") {
+        $Qual .= "&";
+    }
+    elsif($Type{"Type"} eq "ConstVolatile") {
+        $Qual .= "const volatile";
+    }
+    elsif($Type{"Type"} eq "Const"
+    or $Type{"Type"} eq "Volatile"
+    or $Type{"Type"} eq "Restrict") {
+        $Qual .= lc($Type{"Type"});
+    }
+    my $BQual = get_BaseTypeQual($Type{"BaseType"}{"TDid"}, $Type{"BaseType"}{"Tid"}, $LibVersion);
+    return $BQual.$Qual;
+}
+
+sub get_OneStep_BaseType($$$)
+{
+    my ($TypeDId, $TypeId, $LibVersion) = @_;
+    return () if(not $TypeId);
+    return () if(not $TypeInfo{$LibVersion}{$TypeDId}{$TypeId});
+    my %Type = %{$TypeInfo{$LibVersion}{$TypeDId}{$TypeId}};
+    if(not $Type{"BaseType"}{"TDid"}
+    and not $Type{"BaseType"}{"Tid"}) {
+        return %Type;
+    }
+    return get_Type($Type{"BaseType"}{"TDid"}, $Type{"BaseType"}{"Tid"}, $LibVersion);
+}
+
+sub get_Type($$$)
+{
+    my ($TypeDId, $TypeId, $LibVersion) = @_;
+    return "" if(not $TypeId);
+    return "" if(not $TypeInfo{$LibVersion}{$TypeDId}{$TypeId});
+    return %{$TypeInfo{$LibVersion}{$TypeDId}{$TypeId}};
+}
+
+sub skipGlobalData($)
+{
+    my $Symbol = $_[0];
+    return ($Symbol=~/\A(_ZGV|_ZTI|_ZTS|_ZTT|_ZTV|_ZTC|_ZThn|_ZTv0_n)/);
+}
+
+sub isTemplateInstance($)
+{
+    my $Symbol = $_[0];
+    return 0 if($Symbol!~/\A(_Z|\?)/);
+    my $Signature = $tr_name{$Symbol};
+    return 0 if($Signature!~/>/);
+    my $ShortName = substr($Signature, 0, detect_center($Signature, "("));
+    $ShortName=~s/::operator .*//;# class::operator template<instance>
+    return ($ShortName=~/<.+>/);
+}
+
+sub isTemplateSpec($$)
+{
+    my ($Symbol, $LibVersion) = @_;
+    if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
+    {
+        if(get_TypeAttr($ClassId, $LibVersion, "Spec"))
+        { # class specialization
+            return 1;
+        }
+        elsif($CompleteSignature{$LibVersion}{$Symbol}{"Spec"})
+        { # method specialization
+            return 1;
+        }
+    }
+    return 0;
+}
+
+sub symbolFilter($$$)
+{ # some special cases when the symbol cannot be imported
+    my ($Symbol, $LibVersion, $Type) = @_;
+    if(skipGlobalData($Symbol))
+    { # non-public global data
+        return 0;
+    }
+    if($CheckObjectsOnly) {
+        return 0 if($Symbol=~/\A(_init|_fini)\Z/);
+    }
+    if($CheckHeadersOnly and $UsedDump{$LibVersion}{"V"}
+    and cmpVersions($UsedDump{$LibVersion}{"V"}, "2.7")<0)
+    { # support for old ABI dumps in --headers-only mode
+        foreach my $Pos (keys(%{$CompleteSignature{$LibVersion}{$Symbol}{"Param"}}))
+        {
+            if(my $Pid = $CompleteSignature{$LibVersion}{$Symbol}{"Param"}{$Pos}{"type"})
+            {
+                my $PType = get_TypeAttr($Pid, $LibVersion, "Type");
+                if(not $PType or $PType eq "Unknown") {
+                    return 0;
+                }
+            }
+        }
+    }
+    if($Type=~/Imported/)
+    {
+        my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"};
+        if(not $STDCXX_TESTING and $Symbol=~/\A(_ZS|_ZNS|_ZNKS)/)
+        { # stdc++ interfaces
+            return 0;
+        }
+        if($SkipSymbols{$LibVersion}{$Symbol})
+        { # user defined symbols to ignore
+            return 0;
+        }
+        my $NameSpace = $CompleteSignature{$LibVersion}{$Symbol}{"NameSpace"};
+        if(not $NameSpace and $ClassId)
+        { # class methods have no "NameSpace" attribute
+            $NameSpace = get_TypeAttr($ClassId, $LibVersion, "NameSpace");
+        }
+        if($NameSpace)
+        { # user defined namespaces to ignore
+            if($SkipNameSpaces{$LibVersion}{$NameSpace}) {
+                return 0;
+            }
+            foreach my $NS (keys(%{$SkipNameSpaces{$LibVersion}}))
+            { # nested namespaces
+                if($NameSpace=~/\A\Q$NS\E(\:\:|\Z)/) { 
+                    return 0;
+                }
+            }
+        }
+        if(my $Header = $CompleteSignature{$LibVersion}{$Symbol}{"Header"})
+        {
+            if(my $Skip = skip_header($Header, $LibVersion))
+            { # --skip-headers or <skip_headers> (not <skip_including>)
+                if($Skip==1) {
+                    return 0;
+                }
+            }
+            if(not is_target_header($Header))
+            { # --header, --headers-list
+                return 0;
+            }
+        }
+        if($SymbolsListPath and not $SymbolsList{$Symbol})
+        { # user defined symbols
+            return 0;
+        }
+        if($AppPath and not $SymbolsList_App{$Symbol})
+        { # user defined symbols (in application)
+            return 0;
+        }
+        if($CompleteSignature{$LibVersion}{$Symbol}{"InLine"}
+        or (isTemplateInstance($Symbol) and not isTemplateSpec($Symbol, $LibVersion)))
+        {
+            if($ClassId and $CompleteSignature{$LibVersion}{$Symbol}{"Virt"})
+            { # inline virtual methods
+                if($Type=~/InlineVirtual/) {
+                    return 1;
+                }
+                my $Allocable = (not isCopyingClass($ClassId, $LibVersion));
+                if(not $Allocable)
+                { # check bases
+                    foreach my $DCId (get_sub_classes($ClassId, $LibVersion, 1))
+                    {
+                        if(not isCopyingClass($DCId, $LibVersion))
+                        { # exists a derived class without default c-tor
+                            $Allocable=1;
+                            last;
+                        }
+                    }
+                }
+                if(not $Allocable) {
+                    return 0;
+                }
+            }
+            else
+            { # inline non-virtual methods
+                return 0;
+            }
+        }
+    }
+    return 1;
+}
+
+sub mergeImpl()
+{
+    my $DiffCmd = get_CmdPath("diff");
+    if(not $DiffCmd) {
+        exitStatus("Not_Found", "can't find \"diff\"");
+    }
+    foreach my $Interface (sort keys(%{$Symbol_Library{1}}))
+    { # implementation changes
+        next if($CompleteSignature{1}{$Interface}{"Private"});
+        next if(not $CompleteSignature{1}{$Interface}{"Header"} and not $CheckObjectsOnly);
+        next if(not $Symbol_Library{2}{$Interface} and not $Symbol_Library{2}{$SymVer{2}{$Interface}});
+        next if(not symbolFilter($Interface, 1, "Imported"));
+        my $Impl1 = canonify_implementation($Interface_Impl{1}{$Interface});
+        next if(not $Impl1);
+        my $Impl2 = canonify_implementation($Interface_Impl{2}{$Interface});
+        next if(not $Impl2);
+        if($Impl1 ne $Impl2)
+        {
+            writeFile("$TMP_DIR/impl1", $Impl1);
+            writeFile("$TMP_DIR/impl2", $Impl2);
+            my $Diff = `$DiffCmd -rNau $TMP_DIR/impl1 $TMP_DIR/impl2`;
+            $Diff=~s/(---|\+\+\+).+\n//g;
+            $Diff=~s/[ ]{3,}/ /g;
+            $Diff=~s/\n\@\@/\n \n\@\@/g;
+            unlink("$TMP_DIR/impl1", "$TMP_DIR/impl2");
+            %{$ImplProblems{$Interface}}=(
+                "Diff" => get_CodeView($Diff)  );
+        }
+    }
+}
+
+sub canonify_implementation($)
+{
+    my $FuncBody=  $_[0];
+    return "" if(not $FuncBody);
+    $FuncBody=~s/0x[a-f\d]+/0x?/g;# addr
+    $FuncBody=~s/((\A|\n)[a-z]+[\t ]+)[a-f\d]+([^x]|\Z)/$1?$3/g;# call, jump
+    $FuncBody=~s/# [a-f\d]+ /# ? /g;# call, jump
+    $FuncBody=~s/%([a-z]+[a-f\d]*)/\%reg/g;# registers
+    while($FuncBody=~s/\nnop[ \t]*(\n|\Z)/$1/g){};# empty op
+    $FuncBody=~s/<.+?\.cpp.+?>/<name.cpp>/g;
+    $FuncBody=~s/(\A|\n)[a-f\d]+ </$1? </g;# 5e74 <_ZN...
+    $FuncBody=~s/\.L\d+/.L/g;
+    $FuncBody=~s/#(-?)\d+/#$1?/g;# r3, [r3, #120]
+    $FuncBody=~s/[\n]{2,}/\n/g;
+    return $FuncBody;
+}
+
+sub get_CodeView($)
+{
+    my $Code = $_[0];
+    my $View = "";
+    foreach my $Line (split(/\n/, $Code))
+    {
+        if($Line=~s/\A(\+|-)/$1 /g)
+        {# bold line
+            $View .= "<tr><td><b>".htmlSpecChars($Line)."</b></td></tr>\n";
+        }
+        else {
+            $View .= "<tr><td>".htmlSpecChars($Line)."</td></tr>\n";
+        }
+    }
+    return "<table class='code_view'>$View</table>\n";
+}
+
+sub getImplementations($$)
+{
+    my ($LibVersion, $Path) = @_;
+    return if(not $LibVersion or not -e $Path);
+    if($OSgroup eq "macos")
+    {
+        my $OtoolCmd = get_CmdPath("otool");
+        if(not $OtoolCmd) {
+            exitStatus("Not_Found", "can't find \"otool\"");
+        }
+        my $CurInterface = "";
+        foreach my $Line (split(/\n/, `$OtoolCmd -tv $Path 2>$TMP_DIR/null`))
+        {
+            if($Line=~/\A\s*_(\w+)\s*:/i) {
+                $CurInterface = $1;
+            }
+            elsif($Line=~/\A\s*[\da-z]+\s+(.+?)\Z/i) {
+                $Interface_Impl{$LibVersion}{$CurInterface} .= "$1\n";
+            }
+        }
+    }
+    else
+    {
+        my $ObjdumpCmd = get_CmdPath("objdump");
+        if(not $ObjdumpCmd) {
+            exitStatus("Not_Found", "can't find \"objdump\"");
+        }
+        my $CurInterface = "";
+        foreach my $Line (split(/\n/, `$ObjdumpCmd -d $Path 2>$TMP_DIR/null`))
+        {
+            if($Line=~/\A[\da-z]+\s+<(\w+)>/i) {
+                $CurInterface = $1;
+            }
+            else
+            { # x86:    51fa:(\t)89 e5               (\t)mov    %esp,%ebp
+              # arm:    5020:(\t)e24cb004(\t)sub(\t)fp, ip, #4(\t); 0x4
+                if($Line=~/\A\s*[a-f\d]+:\s+([a-f\d]+\s+)+([a-z]+\s+.*?)\s*(;.*|)\Z/i) {
+                    $Interface_Impl{$LibVersion}{$CurInterface} .= "$2\n";
+                }
+            }
+        }
+    }
+}
+
+sub detectAdded()
+{
+    foreach my $Symbol (keys(%{$Symbol_Library{2}}))
+    {
+        if(link_symbol($Symbol, 1, "+Deps"))
+        { # linker can find a new symbol
+          # in the old-version library
+          # So, it's not a new symbol
+            next;
+        }
+        if(my $VSym = $SymVer{2}{$Symbol}
+        and $Symbol!~/\@/) {
+            next;
+        }
+        $AddedInt{$Symbol} = 1;
+    }
+}
+
+sub detectRemoved()
+{
+    foreach my $Symbol (keys(%{$Symbol_Library{1}}))
+    {
+        if($CheckObjectsOnly) {
+            $CheckedSymbols{$Symbol} = 1;
+        }
+        if(link_symbol($Symbol, 2, "+Deps"))
+        { # linker can find an old symbol
+          # in the new-version library
+            next;
+        }
+        if(my $VSym = $SymVer{1}{$Symbol}
+        and $Symbol!~/\@/) {
+            next;
+        }
+        $RemovedInt{$Symbol} = 1;
+    }
+}
+
+sub mergeLibs()
+{
+    foreach my $Symbol (sort keys(%AddedInt))
+    { # checking added symbols
+        next if($CompleteSignature{2}{$Symbol}{"Private"});
+        next if(not $CompleteSignature{2}{$Symbol}{"Header"} and not $CheckObjectsOnly);
+        next if(not symbolFilter($Symbol, 2, "Imported"));
+        %{$CompatProblems{$Symbol}{"Added_Interface"}{""}}=();
+    }
+    foreach my $Symbol (sort keys(%RemovedInt))
+    { # checking removed symbols
+        next if($CompleteSignature{1}{$Symbol}{"Private"});
+        next if(not $CompleteSignature{1}{$Symbol}{"Header"} and not $CheckObjectsOnly);
+        if($Symbol=~/\A_ZTV/)
+        { # skip v-tables for templates, that should not be imported by applications
+            next if($tr_name{$Symbol}=~/</);
+            if(not keys(%{$ClassMethods{1}{$VTableClass{1}{$Symbol}}}))
+            { # vtables for "private" classes
+              # use case: vtable for QDragManager (Qt 4.5.3 to 4.6.0) became HIDDEN symbol
+                next;
+            }
+        }
+        else {
+            next if(not symbolFilter($Symbol, 1, "Imported"));
+        }
+        if($CompleteSignature{1}{$Symbol}{"PureVirt"})
+        { # symbols for pure virtual methods cannot be called by clients
+            next;
+        }
+        %{$CompatProblems{$Symbol}{"Removed_Interface"}{""}}=();
+    }
+}
+
+sub detectAdded_H()
+{
+    foreach my $Symbol (sort keys(%{$CompleteSignature{2}}))
+    {
+        if($GeneratedSymbols{$Symbol}) {
+            next;
+        }
+        if(not $CompleteSignature{1}{$Symbol}) {
+            $AddedInt{$Symbol} = 1;
+        }
+    }
+}
+
+sub detectRemoved_H()
+{
+    foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
+    {
+        if($GeneratedSymbols{$Symbol}) {
+            next;
+        }
+        if(not $CompleteSignature{2}{$Symbol}) {
+            $RemovedInt{$Symbol} = 1;
+        }
+    }
+}
+
+sub mergeHeaders()
+{
+    foreach my $Symbol (sort keys(%AddedInt))
+    { # checking added symbols
+        next if($CompleteSignature{2}{$Symbol}{"PureVirt"});
+        next if($CompleteSignature{2}{$Symbol}{"InLine"});
+        next if($CompleteSignature{2}{$Symbol}{"Private"});
+        next if(not symbolFilter($Symbol, 2, "Imported"));
+        %{$CompatProblems{$Symbol}{"Added_Interface"}{""}}=();
+    }
+    foreach my $Symbol (sort keys(%RemovedInt))
+    { # checking removed symbols
+        next if($CompleteSignature{1}{$Symbol}{"PureVirt"});
+        next if($CompleteSignature{1}{$Symbol}{"InLine"});
+        next if($CompleteSignature{1}{$Symbol}{"Private"});
+        next if(not symbolFilter($Symbol, 1, "Imported"));
+        %{$CompatProblems{$Symbol}{"Removed_Interface"}{""}}=();
+    }
+}
+
+sub addParamNames($)
+{
+    my $LibraryVersion = $_[0];
+    return if(not keys(%AddIntParams));
+    my $SecondVersion = $LibraryVersion==1?2:1;
+    foreach my $Interface (sort keys(%{$CompleteSignature{$LibraryVersion}}))
+    {
+        next if(not keys(%{$AddIntParams{$Interface}}));
+        foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibraryVersion}{$Interface}{"Param"}}))
+        {# add absent parameter names
+            my $ParamName = $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"};
+            if($ParamName=~/\Ap\d+\Z/ and my $NewParamName = $AddIntParams{$Interface}{$ParamPos})
+            {# names from the external file
+                if(defined $CompleteSignature{$SecondVersion}{$Interface}
+                and defined $CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos})
+                {
+                    if($CompleteSignature{$SecondVersion}{$Interface}{"Param"}{$ParamPos}{"name"}=~/\Ap\d+\Z/) {
+                        $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
+                    }
+                }
+                else {
+                    $CompleteSignature{$LibraryVersion}{$Interface}{"Param"}{$ParamPos}{"name"} = $NewParamName;
+                }
+            }
+        }
+    }
+}
+
+sub detectChangedTypedefs()
+{ # detect changed typedefs to create correct function signatures
+    foreach my $Typedef (keys(%{$Typedef_BaseName{1}}))
+    {
+        next if(not $Typedef);
+        next if(isAnon($Typedef_BaseName{1}{$Typedef}));
+        next if(isAnon($Typedef_BaseName{2}{$Typedef}));
+        next if(not $Typedef_BaseName{1}{$Typedef});
+        next if(not $Typedef_BaseName{2}{$Typedef});# exclude added/removed
+        if($Typedef_BaseName{1}{$Typedef} ne $Typedef_BaseName{2}{$Typedef}) {
+            $ChangedTypedef{$Typedef} = 1;
+        }
+    }
+}
+
+sub get_symbol_suffix($$)
+{
+    my ($Interface, $Full) = @_;
+    $Interface=~s/\A([^\@\$\?]+)[\@\$]+/$1/g;# remove version
+    my $Signature = $tr_name{$Interface};
+    my $Suffix = substr($Signature, detect_center($Signature, "("));
+    if(not $Full) {
+        $Suffix=~s/(\))\s*(const volatile|volatile const|const|volatile)\Z/$1/g;
+    }
+    return $Suffix;
+}
+
+sub get_symbol_prefix($$)
+{
+    my ($Symbol, $LibVersion) = @_;
+    my $ShortName = $CompleteSignature{$LibVersion}{$Symbol}{"ShortName"};
+    if(my $ClassId = $CompleteSignature{$LibVersion}{$Symbol}{"Class"})
+    { # methods
+        $ShortName = get_TypeName($ClassId, $LibVersion)."::".$ShortName;
+    }
+    return $ShortName;
+}
+
+sub mergeSignatures()
+{
+    my %SubProblems = ();
+    
+    registerVirtualTable(1);
+    registerVirtualTable(2);
+
+    if($UsedDump{1}{"V"} and cmpVersions($UsedDump{1}{"V"}, "1.22")<0
+    and (not $UsedDump{2}{"V"} or cmpVersions($UsedDump{2}{"V"}, "1.22")>=0))
+    { # support for old ABI dumps
+        foreach my $ClassName (keys(%{$VirtualTable{2}}))
+        {
+            if($ClassName=~/</)
+            { # templates
+                if(not defined $VirtualTable{1}{$ClassName})
+                { # synchronize
+                    delete($VirtualTable{2}{$ClassName});
+                }
+            }
+        }
+    }
+    
+    registerOverriding(1);
+    registerOverriding(2);
+    
+    setVirtFuncPositions(1);
+    setVirtFuncPositions(2);
+    
+    addParamNames(1);
+    addParamNames(2);
+    
+    detectChangedTypedefs();
+    mergeBases();
+    my %AddedOverloads = ();
+    foreach my $Interface (sort keys(%AddedInt))
+    { # check all added exported symbols
+        next if(not $CompleteSignature{2}{$Interface}{"Header"});
+        if(defined $CompleteSignature{1}{$Interface}
+        and $CompleteSignature{1}{$Interface}{"Header"})
+        { # double-check added symbol
+            next;
+        }
+        next if(not symbolFilter($Interface, 2, "Imported"));
+        if($Interface=~/\A(_Z|\?)/)
+        { # C++
+            $AddedOverloads{get_symbol_prefix($Interface, 2)}{get_symbol_suffix($Interface, 1)} = $Interface;
+        }
+        if(my $OverriddenMethod = $CompleteSignature{2}{$Interface}{"Override"})
+        { # register virtual redefinition
+            my $AffectedClass_Name = get_TypeName($CompleteSignature{2}{$Interface}{"Class"}, 2);
+            if(defined $CompleteSignature{1}{$OverriddenMethod}
+            and $CompleteSignature{1}{$OverriddenMethod}{"Virt"} and $ClassToId{1}{$AffectedClass_Name}
+            and not $CompleteSignature{1}{$OverriddenMethod}{"Private"})
+            { # public virtual methods, virtual destructors: class should exist in previous version
+                if(isCopyingClass($ClassToId{1}{$AffectedClass_Name}, 1))
+                { # old v-table (copied) will be used by applications
+                    next;
+                }
+                if(defined $CompleteSignature{1}{$Interface}
+                and $CompleteSignature{1}{$Interface}{"InLine"})
+                { # auto-generated virtual destructors stay in the header (and v-table), added to library
+                  # use case: Ice 3.3.1 -> 3.4.0
+                    next;
+                }
+                %{$CompatProblems{$OverriddenMethod}{"Overridden_Virtual_Method"}{$tr_name{$Interface}}}=(
+                    "Type_Name"=>$AffectedClass_Name,
+                    "Type_Type"=>"Class",
+                    "Target"=>get_Signature($Interface, 2),
+                    "Old_Value"=>get_Signature($OverriddenMethod, 2),
+                    "New_Value"=>get_Signature($Interface, 2)  );
+            }
+        }
+    }
+    foreach my $Interface (sort keys(%RemovedInt))
+    {
+        next if(not $CompleteSignature{1}{$Interface}{"Header"});
+        if(defined $CompleteSignature{2}{$Interface}
+        and $CompleteSignature{2}{$Interface}{"Header"})
+        { # double-check removed symbol
+            next;
+        }
+        next if($CompleteSignature{1}{$Interface}{"Private"}); # skip private methods
+        next if(not symbolFilter($Interface, 1, "Imported"));
+        $CheckedSymbols{$Interface} = 1;
+        if(my $OverriddenMethod = $CompleteSignature{1}{$Interface}{"Override"})
+        { # register virtual redefinition
+            my $AffectedClass_Name = get_TypeName($CompleteSignature{1}{$Interface}{"Class"}, 1);
+            if(defined $CompleteSignature{2}{$OverriddenMethod}
+            and $CompleteSignature{2}{$OverriddenMethod}{"Virt"} and $ClassToId{2}{$AffectedClass_Name})
+            { # virtual methods, virtual destructors: class should exist in newer version
+                if(isCopyingClass($CompleteSignature{1}{$Interface}{"Class"}, 1))
+                { # old v-table (copied) will be used by applications
+                    next;
+                }
+                if(defined $CompleteSignature{2}{$Interface}
+                and $CompleteSignature{2}{$Interface}{"InLine"})
+                { # auto-generated virtual destructors stay in the header (and v-table), removed from library
+                  # use case: Ice 3.3.1 -> 3.4.0
+                    next;
+                }
+                %{$CompatProblems{$Interface}{"Overridden_Virtual_Method_B"}{$tr_name{$OverriddenMethod}}}=(
+                    "Type_Name"=>$AffectedClass_Name,
+                    "Type_Type"=>"Class",
+                    "Target"=>get_Signature($OverriddenMethod, 1),
+                    "Old_Value"=>get_Signature($Interface, 1),
+                    "New_Value"=>get_Signature($OverriddenMethod, 1)  );
+            }
+        }
+        if($OSgroup eq "windows")
+        { # register the reason of symbol name change
+            if(my $NewSymbol = $mangled_name{2}{$tr_name{$Interface}})
+            {
+                if($AddedInt{$NewSymbol})
+                {
+                    if($CompleteSignature{1}{$Interface}{"Static"} ne $CompleteSignature{2}{$NewSymbol}{"Static"})
+                    {
+                        if($CompleteSignature{2}{$NewSymbol}{"Static"}) {
+                            %{$CompatProblems{$Interface}{"Symbol_Changed_Static"}{$tr_name{$Interface}}}=(
+                                "Target"=>$tr_name{$Interface},
+                                "Old_Value"=>$Interface,
+                                "New_Value"=>$NewSymbol  );
+                        }
+                        else {
+                            %{$CompatProblems{$Interface}{"Symbol_Changed_NonStatic"}{$tr_name{$Interface}}}=(
+                                "Target"=>$tr_name{$Interface},
+                                "Old_Value"=>$Interface,
+                                "New_Value"=>$NewSymbol  );
+                        }
+                    }
+                    if($CompleteSignature{1}{$Interface}{"Virt"} ne $CompleteSignature{2}{$NewSymbol}{"Virt"})
+                    {
+                        if($CompleteSignature{2}{$NewSymbol}{"Virt"}) {
+                            %{$CompatProblems{$Interface}{"Symbol_Changed_Virtual"}{$tr_name{$Interface}}}=(
+                                "Target"=>$tr_name{$Interface},
+                                "Old_Value"=>$Interface,
+                                "New_Value"=>$NewSymbol  );
+                        }
+                        else {
+                            %{$CompatProblems{$Interface}{"Symbol_Changed_NonVirtual"}{$tr_name{$Interface}}}=(
+                                "Target"=>$tr_name{$Interface},
+                                "Old_Value"=>$Interface,
+                                "New_Value"=>$NewSymbol  );
+                        }
+                    }
+                    my $ReturnTypeName1 = get_TypeName($CompleteSignature{1}{$Interface}{"Return"}, 1);
+                    my $ReturnTypeName2 = get_TypeName($CompleteSignature{2}{$NewSymbol}{"Return"}, 2);
+                    if($ReturnTypeName1 ne $ReturnTypeName2)
+                    {
+                        my $ProblemType = "Symbol_Changed_Return";
+                        if($CompleteSignature{1}{$Interface}{"Data"}) {
+                            $ProblemType = "Global_Data_Symbol_Changed_Type";
+                        }
+                        %{$CompatProblems{$Interface}{$ProblemType}{$tr_name{$Interface}}}=(
+                            "Target"=>$tr_name{$Interface},
+                            "Old_Type"=>$ReturnTypeName1,
+                            "New_Type"=>$ReturnTypeName2,
+                            "Old_Value"=>$Interface,
+                            "New_Value"=>$NewSymbol  );
+                    }
+                }
+            }
+        }
+        if($Interface=~/\A(_Z|\?)/)
+        { # C++
+            my $Prefix = get_symbol_prefix($Interface, 1);
+            if(my @Overloads = sort keys(%{$AddedOverloads{$Prefix}})
+            and not $AddedOverloads{$Prefix}{get_symbol_suffix($Interface, 1)})
+            { # changed signature: params, "const"-qualifier
+                my $NewSymbol = $AddedOverloads{$Prefix}{$Overloads[0]};
+                if($CompleteSignature{1}{$Interface}{"Constructor"}) {
+                    if($Interface=~/(C1E|C2E)/) {
+                        my $CtorType = $1;
+                        $NewSymbol=~s/(C1E|C2E)/$CtorType/g;
+                    }
+                }
+                elsif($CompleteSignature{1}{$Interface}{"Destructor"}) {
+                    if($Interface=~/(D0E|D1E|D2E)/) {
+                        my $DtorType = $1;
+                        $NewSymbol=~s/(D0E|D1E|D2E)/$DtorType/g;
+                    }
+                }
+                if($CompleteSignature{1}{$Interface}{"NameSpace"} eq $CompleteSignature{2}{$NewSymbol}{"NameSpace"})
+                { # from the same class and namespace
+                    if($CompleteSignature{1}{$Interface}{"Const"}
+                    and not $CompleteSignature{2}{$NewSymbol}{"Const"})
+                    { # "const" to non-"const"
+                        %{$CompatProblems{$Interface}{"Symbol_Changed_Became_NonConst"}{$tr_name{$Interface}}}=(
+                            "Target"=>$tr_name{$Interface},
+                            "New_Signature"=>get_Signature($NewSymbol, 2),
+                            "Old_Value"=>$Interface,
+                            "New_Value"=>$NewSymbol  );
+                    }
+                    elsif(not $CompleteSignature{1}{$Interface}{"Const"}
+                    and $CompleteSignature{2}{$NewSymbol}{"Const"})
+                    { # non-"const" to "const"
+                        %{$CompatProblems{$Interface}{"Symbol_Changed_Became_Const"}{$tr_name{$Interface}}}=(
+                            "Target"=>$tr_name{$Interface},
+                            "New_Signature"=>get_Signature($NewSymbol, 2),
+                            "Old_Value"=>$Interface,
+                            "New_Value"=>$NewSymbol  );
+                    }
+                    if($CompleteSignature{1}{$Interface}{"Volatile"}
+                    and not $CompleteSignature{2}{$NewSymbol}{"Volatile"})
+                    { # "volatile" to non-"volatile"
+                        
+                        %{$CompatProblems{$Interface}{"Symbol_Changed_Became_NonVolatile"}{$tr_name{$Interface}}}=(
+                            "Target"=>$tr_name{$Interface},
+                            "New_Signature"=>get_Signature($NewSymbol, 2),
+                            "Old_Value"=>$Interface,
+                            "New_Value"=>$NewSymbol  );
+                    }
+                    elsif(not $CompleteSignature{1}{$Interface}{"Volatile"}
+                    and $CompleteSignature{2}{$NewSymbol}{"Volatile"})
+                    { # non-"volatile" to "volatile"
+                        %{$CompatProblems{$Interface}{"Symbol_Changed_Became_Volatile"}{$tr_name{$Interface}}}=(
+                            "Target"=>$tr_name{$Interface},
+                            "New_Signature"=>get_Signature($NewSymbol, 2),
+                            "Old_Value"=>$Interface,
+                            "New_Value"=>$NewSymbol  );
+                    }
+                    if(get_symbol_suffix($Interface, 0) ne get_symbol_suffix($NewSymbol, 0))
+                    { # params list
+                        %{$CompatProblems{$Interface}{"Symbol_Changed_Parameters"}{$tr_name{$Interface}}}=(
+                            "Target"=>$tr_name{$Interface},
+                            "New_Signature"=>get_Signature($NewSymbol, 2),
+                            "Old_Value"=>$Interface,
+                            "New_Value"=>$NewSymbol  );
+                    }
+                }
+            }
+        }
+    }
+    foreach my $Interface (sort keys(%{$CompleteSignature{1}}))
+    { # checking interfaces
+        if($Interface!~/[\@\$\?]/)
+        { # symbol without version
+            if(my $VSym = $SymVer{1}{$Interface})
+            { # the symbol is linked with versioned symbol
+                if($CompleteSignature{2}{$VSym}{"MnglName"})
+                { # show report for symbol@ver only
+                    next;
+                }
+                elsif(not link_symbol($VSym, 2, "-Deps"))
+                { # changed version: sym@v1 to sym@v2
+                  # do NOT show report for symbol
+                    next;
+                }
+            }
+        }
+        if($CompleteSignature{1}{$Interface}{"Private"})
+        { # private symbols
+            next;
+        }
+        if(not $CompleteSignature{1}{$Interface}{"MnglName"}
+        or not $CompleteSignature{2}{$Interface}{"MnglName"})
+        { # absent mangled name
+            next;
+        }
+        if(not $CompleteSignature{1}{$Interface}{"Header"}
+        or not $CompleteSignature{2}{$Interface}{"Header"})
+        { # without a header
+            next;
+        }
+        if($CheckHeadersOnly)
+        { # skip added and removed pure virtual methods
+            next if(not $CompleteSignature{1}{$Interface}{"PureVirt"} and $CompleteSignature{2}{$Interface}{"PureVirt"});
+            next if($CompleteSignature{1}{$Interface}{"PureVirt"} and not $CompleteSignature{2}{$Interface}{"PureVirt"});
+        }
+        else
+        { # skip external, added and removed functions except pure virtual methods
+            if(not link_symbol($Interface, 1, "-Deps")
+            or not link_symbol($Interface, 2, "-Deps"))
+            { # symbols from target library(ies) only
+              # excluding dependent libraries
+                if(not $CompleteSignature{1}{$Interface}{"PureVirt"}
+                or not $CompleteSignature{2}{$Interface}{"PureVirt"}) {
+                    next;
+                }
+            }
+        }
+        if(not symbolFilter($Interface, 1, "Imported|InlineVirtual"))
+        { # symbols that cannot be imported
+            next;
+        }
+        # checking virtual table
+        if($CompleteSignature{1}{$Interface}{"Class"}) {
+            mergeVirtualTables($Interface);
+        }
+        if($COMPILE_ERRORS)
+        { # if some errors occurred at the compiling stage
+          # then some false positives can be skipped here
+            if(not $CompleteSignature{1}{$Interface}{"Data"} and $CompleteSignature{2}{$Interface}{"Data"}
+            and not $CompleteSignature{2}{$Interface}{"Object"})
+            { # missed information about parameters in newer version
+                next;
+            }
+            if($CompleteSignature{1}{$Interface}{"Data"} and not $CompleteSignature{1}{$Interface}{"Object"}
+            and not $CompleteSignature{2}{$Interface}{"Data"})
+            {# missed information about parameters in older version
+                next;
+            }
+        }
+        my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Interface);
+        # checking attributes
+        if($CompleteSignature{2}{$Interface}{"Static"}
+        and not $CompleteSignature{1}{$Interface}{"Static"} and $Interface=~/\A(_Z|\?)/) {
+            %{$CompatProblems{$Interface}{"Method_Became_Static"}{""}}=();
+        }
+        elsif(not $CompleteSignature{2}{$Interface}{"Static"}
+        and $CompleteSignature{1}{$Interface}{"Static"} and $Interface=~/\A(_Z|\?)/) {
+            %{$CompatProblems{$Interface}{"Method_Became_NonStatic"}{""}}=();
+        }
+        if(($CompleteSignature{1}{$Interface}{"Virt"} and $CompleteSignature{2}{$Interface}{"Virt"})
+        or ($CompleteSignature{1}{$Interface}{"PureVirt"} and $CompleteSignature{2}{$Interface}{"PureVirt"}))
+        { # relative position of virtual and pure virtual methods
+            if($CompleteSignature{1}{$Interface}{"RelPos"}!=$CompleteSignature{2}{$Interface}{"RelPos"})
+            {
+                my $Class_Id = $CompleteSignature{1}{$Interface}{"Class"};
+                if($VirtualTable{1}{get_TypeName($Class_Id, 1)}{$Interface}!=$VirtualTable{2}{get_TypeName($Class_Id, 1)}{$Interface})
+                { # check the absolute position of virtual method (including added and removed methods)
+                    my %Class_Type = get_Type($Tid_TDid{1}{$Class_Id}, $Class_Id, 1);
+                    my $ProblemType = "Virtual_Method_Position";
+                    if($CompleteSignature{1}{$Interface}{"PureVirt"}) {
+                        $ProblemType = "Pure_Virtual_Method_Position";
+                    }
+                    if(isUsedClass($Class_Id, 1))
+                    {
+                        my @Affected = ($Interface, keys(%{$OverriddenMethods{1}{$Interface}}));
+                        foreach my $AffectedInterface (@Affected)
+                        {
+                            %{$CompatProblems{$AffectedInterface}{$ProblemType}{$tr_name{$MnglName}}}=(
+                                "Type_Name"=>$Class_Type{"Name"},
+                                "Type_Type"=>"Class",
+                                "Old_Value"=>$CompleteSignature{1}{$Interface}{"RelPos"},
+                                "New_Value"=>$CompleteSignature{2}{$Interface}{"RelPos"},
+                                "Target"=>get_Signature($Interface, 1)  );
+                        }
+                        $VTableChanged{$Class_Type{"Name"}} = 1;
+                    }
+                }
+            }
+        }
+        if($CompleteSignature{1}{$Interface}{"PureVirt"}
+        or $CompleteSignature{2}{$Interface}{"PureVirt"})
+        { # do NOT check type changes in pure virtuals
+            next;
+        }
+        $CheckedSymbols{$Interface}=1;
+        if($Interface=~/\A(_Z|\?)/
+        or keys(%{$CompleteSignature{1}{$Interface}{"Param"}})==keys(%{$CompleteSignature{2}{$Interface}{"Param"}}))
+        { # C/C++: changes in parameters
+            foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Interface}{"Param"}}))
+            { # checking parameters
+                mergeParameters($Interface, $ParamPos, $ParamPos);
+            }
+        }
+        else
+        { # C: added/removed parameters
+            foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{2}{$Interface}{"Param"}}))
+            { # checking added parameters
+                my $ParamType2_Id = $CompleteSignature{2}{$Interface}{"Param"}{$ParamPos}{"type"};
+                last if(get_TypeName($ParamType2_Id, 2) eq "...");
+                my $Parameter_Name = $CompleteSignature{2}{$Interface}{"Param"}{$ParamPos}{"name"};
+                my $Parameter_OldName = (defined $CompleteSignature{1}{$Interface}{"Param"}{$ParamPos})?$CompleteSignature{1}{$Interface}{"Param"}{$ParamPos}{"name"}:"";
+                my $ParamPos_Prev = "-1";
+                if($Parameter_Name=~/\Ap\d+\Z/i)
+                { # added unnamed parameter ( pN )
+                    my @Positions1 = find_ParamPair_Pos_byTypeAndPos(get_TypeName($ParamType2_Id, 2), $ParamPos, "backward", $Interface, 1);
+                    my @Positions2 = find_ParamPair_Pos_byTypeAndPos(get_TypeName($ParamType2_Id, 2), $ParamPos, "backward", $Interface, 2);
+                    if($#Positions1==-1 or $#Positions2>$#Positions1) {
+                        $ParamPos_Prev = "lost";
+                    }
+                }
+                else {
+                    $ParamPos_Prev = find_ParamPair_Pos_byName($Parameter_Name, $Interface, 1);
+                }
+                if($ParamPos_Prev eq "lost")
+                {
+                    if($ParamPos>keys(%{$CompleteSignature{1}{$Interface}{"Param"}})-1)
+                    {
+                        my $ProblemType = "Added_Parameter";
+                        if($Parameter_Name=~/\Ap\d+\Z/) {
+                            $ProblemType = "Added_Unnamed_Parameter";
+                        }
+                        %{$CompatProblems{$Interface}{$ProblemType}{numToStr($ParamPos+1)." Parameter"}}=(
+                            "Target"=>$Parameter_Name,
+                            "Param_Pos"=>$ParamPos,
+                            "Param_Type"=>get_TypeName($ParamType2_Id, 2),
+                            "New_Signature"=>get_Signature($Interface, 2)  );
+                    }
+                    else
+                    {
+                        my %ParamType_Pure = get_PureType($Tid_TDid{2}{$ParamType2_Id}, $ParamType2_Id, 2);
+                        my $ParamStraightPairType_Id = $CompleteSignature{1}{$Interface}{"Param"}{$ParamPos}{"type"};
+                        my %ParamStraightPairType_Pure = get_PureType($Tid_TDid{1}{$ParamStraightPairType_Id}, $ParamStraightPairType_Id, 1);
+                        if(($ParamType_Pure{"Name"} eq $ParamStraightPairType_Pure{"Name"} or get_TypeName($ParamType2_Id, 2) eq get_TypeName($ParamStraightPairType_Id, 1))
+                        and find_ParamPair_Pos_byName($Parameter_OldName, $Interface, 2) eq "lost")
+                        {
+                            if($Parameter_OldName!~/\Ap\d+\Z/ and $Parameter_Name!~/\Ap\d+\Z/)
+                            {
+                                %{$CompatProblems{$Interface}{"Renamed_Parameter"}{numToStr($ParamPos+1)." Parameter"}}=(
+                                    "Target"=>$Parameter_OldName,
+                                    "Param_Pos"=>$ParamPos,
+                                    "Param_Type"=>get_TypeName($ParamType2_Id, 2),
+                                    "Old_Value"=>$Parameter_OldName,
+                                    "New_Value"=>$Parameter_Name,
+                                    "New_Signature"=>get_Signature($Interface, 2)  );
+                            }
+                        }
+                        else
+                        {
+                            my $ProblemType = "Added_Middle_Parameter";
+                            if($Parameter_Name=~/\Ap\d+\Z/) {
+                                $ProblemType = "Added_Middle_Unnamed_Parameter";
+                            }
+                            %{$CompatProblems{$Interface}{$ProblemType}{numToStr($ParamPos+1)." Parameter"}}=(
+                                "Target"=>$Parameter_Name,
+                                "Param_Pos"=>$ParamPos,
+                                "Param_Type"=>get_TypeName($ParamType2_Id, 2),
+                                "New_Signature"=>get_Signature($Interface, 2)  );
+                        }
+                    }
+                }
+            }
+            foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Interface}{"Param"}}))
+            { # check relevant parameters
+                my $ParamType1_Id = $CompleteSignature{1}{$Interface}{"Param"}{$ParamPos}{"type"};
+                my $ParamName1 = $CompleteSignature{1}{$Interface}{"Param"}{$ParamPos}{"name"};
+                # FIXME: find relevant parameter by name
+                if(defined $CompleteSignature{2}{$Interface}{"Param"}{$ParamPos})
+                {
+                    my $ParamType2_Id = $CompleteSignature{2}{$Interface}{"Param"}{$ParamPos}{"type"};
+                    my $ParamName2 = $CompleteSignature{2}{$Interface}{"Param"}{$ParamPos}{"name"};
+                    if(($ParamName1!~/\Ap\d+\Z/i and $ParamName1 eq $ParamName2)
+                    or get_TypeName($ParamType1_Id, 1) eq get_TypeName($ParamType2_Id, 2)) {
+                        mergeParameters($Interface, $ParamPos, $ParamPos);
+                    }
+                }
+            }
+            foreach my $ParamPos (sort {int($a) <=> int($b)} keys(%{$CompleteSignature{1}{$Interface}{"Param"}}))
+            { # checking removed parameters
+                my $ParamType1_Id = $CompleteSignature{1}{$Interface}{"Param"}{$ParamPos}{"type"};
+                last if(get_TypeName($ParamType1_Id, 1) eq "...");
+                my $Parameter_Name = $CompleteSignature{1}{$Interface}{"Param"}{$ParamPos}{"name"};
+                my $Parameter_NewName = (defined $CompleteSignature{2}{$Interface}{"Param"}{$ParamPos})?$CompleteSignature{2}{$Interface}{"Param"}{$ParamPos}{"name"}:"";
+                my $ParamPos_New = "-1";
+                if($Parameter_Name=~/\Ap\d+\Z/i)
+                { # removed unnamed parameter ( pN )
+                    my @Positions1 = find_ParamPair_Pos_byTypeAndPos(get_TypeName($ParamType1_Id, 1), $ParamPos, "forward", $Interface, 1);
+                    my @Positions2 = find_ParamPair_Pos_byTypeAndPos(get_TypeName($ParamType1_Id, 1), $ParamPos, "forward", $Interface, 2);
+                    if($#Positions2==-1 or $#Positions2<$#Positions1) {
+                        $ParamPos_New = "lost";
+                    }
+                }
+                else {
+                    $ParamPos_New = find_ParamPair_Pos_byName($Parameter_Name, $Interface, 2);
+                }
+                if($ParamPos_New eq "lost")
+                {
+                    if($ParamPos>keys(%{$CompleteSignature{2}{$Interface}{"Param"}})-1)
+                    {
+                        my $ProblemType = "Removed_Parameter";
+                        if($Parameter_Name=~/\Ap\d+\Z/) {
+                            $ProblemType = "Removed_Unnamed_Parameter";
+                        }
+                        %{$CompatProblems{$Interface}{$ProblemType}{numToStr($ParamPos+1)." Parameter"}}=(
+                            "Target"=>$Parameter_Name,
+                            "Param_Pos"=>$ParamPos,
+                            "Param_Type"=>get_TypeName($ParamType1_Id, 1),
+                            "New_Signature"=>get_Signature($Interface, 2)  );
+                    }
+                    elsif($ParamPos<keys(%{$CompleteSignature{1}{$Interface}{"Param"}})-1)
+                    {
+                        my %ParamType_Pure = get_PureType($Tid_TDid{1}{$ParamType1_Id}, $ParamType1_Id, 1);
+                        my $ParamStraightPairType_Id = $CompleteSignature{2}{$Interface}{"Param"}{$ParamPos}{"type"};
+                        my %ParamStraightPairType_Pure = get_PureType($Tid_TDid{2}{$ParamStraightPairType_Id}, $ParamStraightPairType_Id, 2);
+                        if(($ParamType_Pure{"Name"} eq $ParamStraightPairType_Pure{"Name"} or get_TypeName($ParamType1_Id, 1) eq get_TypeName($ParamStraightPairType_Id, 2))
+                        and find_ParamPair_Pos_byName($Parameter_NewName, $Interface, 1) eq "lost")
+                        {
+                            if($Parameter_NewName!~/\Ap\d+\Z/ and $Parameter_Name!~/\Ap\d+\Z/)
+                            {
+                                %{$CompatProblems{$Interface}{"Renamed_Parameter"}{numToStr($ParamPos+1)." Parameter"}}=(
+                                    "Target"=>$Parameter_Name,
+                                    "Param_Pos"=>$ParamPos,
+                                    "Param_Type"=>get_TypeName($ParamType1_Id, 1),
+                                    "Old_Value"=>$Parameter_Name,
+                                    "New_Value"=>$Parameter_NewName,
+                                    "New_Signature"=>get_Signature($Interface, 2)  );
+                            }
+                        }
+                        else
+                        {
+                            my $ProblemType = "Removed_Middle_Parameter";
+                            if($Parameter_Name=~/\Ap\d+\Z/) {
+                                $ProblemType = "Removed_Middle_Unnamed_Parameter";
+                            }
+                            %{$CompatProblems{$Interface}{$ProblemType}{numToStr($ParamPos+1)." Parameter"}}=(
+                                "Target"=>$Parameter_Name,
+                                "Param_Pos"=>$ParamPos,
+                                "Param_Type"=>get_TypeName($ParamType1_Id, 1),
+                                "New_Signature"=>get_Signature($Interface, 2)  );
+                        }
+                    }
+                }
+            }
+        }
+        # checking return type
+        my $ReturnType1_Id = $CompleteSignature{1}{$Interface}{"Return"};
+        my $ReturnType2_Id = $CompleteSignature{2}{$Interface}{"Return"};
+        %SubProblems = detectTypeChange($ReturnType1_Id, $ReturnType2_Id, "Return");
+        foreach my $SubProblemType (keys(%SubProblems))
+        {
+            my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
+            my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
+            my $NewProblemType = $SubProblemType;
+            if($SubProblemType eq "Return_Type_Became_Void"
+            and keys(%{$CompleteSignature{1}{$Interface}{"Param"}}))
+            { # parameters stack has been affected
+                $NewProblemType = "Return_Type_Became_Void_And_Stack_Layout";
+            }
+            elsif($SubProblemType eq "Return_Type_From_Void")
+            { # parameters stack has been affected
+                if(keys(%{$CompleteSignature{1}{$Interface}{"Param"}})) {
+                    $NewProblemType = "Return_Type_From_Void_And_Stack_Layout";
+                }
+                else
+                { # safe
+                    delete($SubProblems{$SubProblemType});
+                    next;
+                }
+            }
+            elsif($SubProblemType eq "Return_Type_And_Size"
+            and $CompleteSignature{1}{$Interface}{"Data"}) {
+                $NewProblemType = "Global_Data_Type_And_Size";
+            }
+            elsif($SubProblemType eq "Return_Type")
+            {
+                if($CompleteSignature{1}{$Interface}{"Data"})
+                {
+                    if(removedConstness($Old_Value, $New_Value))
+                    { # const -> non-const global data
+                        $NewProblemType = "Global_Data_Became_Non_Const";
+                    }
+                    elsif(removedConstness($New_Value, $Old_Value))
+                    { # non-const -> const global data
+                        $NewProblemType = "Global_Data_Became_Const";
+                    }
+                    else {
+                        $NewProblemType = "Global_Data_Type";
+                    }
+                }
+                else
+                {
+                    if(removedConstness($New_Value, $Old_Value)) {
+                        $NewProblemType = "Return_Type_Became_Const";
+                    }
+                }
+            }
+            @{$CompatProblems{$Interface}{$NewProblemType}{"retval"}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
+        }
+        if($ReturnType1_Id and $ReturnType2_Id)
+        {
+            @RecurTypes = ();
+            %SubProblems = mergeTypes($ReturnType1_Id, $Tid_TDid{1}{$ReturnType1_Id},
+                                      $ReturnType2_Id, $Tid_TDid{2}{$ReturnType2_Id});
+            foreach my $SubProblemType (keys(%SubProblems))
+            { # add "Global_Data_Size" problem
+                my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
+                my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
+                if($SubProblemType eq "DataType_Size"
+                and $CompleteSignature{1}{$Interface}{"Data"}
+                and get_PointerLevel($Tid_TDid{1}{$ReturnType1_Id}, $ReturnType1_Id, 1)==0)
+                { # add a new problem
+                    %{$SubProblems{"Global_Data_Size"}} = %{$SubProblems{$SubProblemType}};
+                }
+            }
+            foreach my $SubProblemType (keys(%SubProblems))
+            {
+                foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
+                {
+                    my $NewLocation = ($SubLocation)?"retval->".$SubLocation:"retval";
+                    %{$CompatProblems{$Interface}{$SubProblemType}{$NewLocation}}=(
+                        "Return_Type_Name"=>get_TypeName($ReturnType1_Id, 1) );
+                    @{$CompatProblems{$Interface}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
+                    if($SubLocation!~/\-\>/) {
+                        $CompatProblems{$Interface}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = get_TypeName($ReturnType1_Id, 1);
+                    }
+                }
+            }
+        }
+        
+        # checking object type
+        my $ObjectType1_Id = $CompleteSignature{1}{$Interface}{"Class"};
+        my $ObjectType2_Id = $CompleteSignature{2}{$Interface}{"Class"};
+        if($ObjectType1_Id and $ObjectType2_Id
+        and not $CompleteSignature{1}{$Interface}{"Static"})
+        {
+            my $ThisPtr1_Id = getTypeIdByName(get_TypeName($ObjectType1_Id, 1)."*const", 1);
+            my $ThisPtr2_Id = getTypeIdByName(get_TypeName($ObjectType2_Id, 2)."*const", 2);
+            if($ThisPtr1_Id and $ThisPtr2_Id)
+            {
+                @RecurTypes = ();
+                %SubProblems = mergeTypes($ThisPtr1_Id, $Tid_TDid{1}{$ThisPtr1_Id},
+                                          $ThisPtr2_Id, $Tid_TDid{2}{$ThisPtr2_Id});
+                foreach my $SubProblemType (keys(%SubProblems))
+                {
+                    foreach my $SubLocation (keys(%{$SubProblems{$SubProblemType}}))
+                    {
+                        my $NewLocation = ($SubLocation)?"this->".$SubLocation:"this";
+                        %{$CompatProblems{$Interface}{$SubProblemType}{$NewLocation}}=(
+                            "Object_Type_Name"=>get_TypeName($ObjectType1_Id, 1) );
+                        @{$CompatProblems{$Interface}{$SubProblemType}{$NewLocation}}{keys(%{$SubProblems{$SubProblemType}{$SubLocation}})} = values %{$SubProblems{$SubProblemType}{$SubLocation}};
+                        if($SubLocation!~/\-\>/) {
+                            $CompatProblems{$Interface}{$SubProblemType}{$NewLocation}{"Start_Type_Name"} = get_TypeName($ObjectType1_Id, 1);
+                        }
+                    }
+                }
+            }
+        }
+    }
+    mergeVTables();
+}
+
+sub removedConstness($$)
+{
+    my ($Old_Value, $New_Value) = @_;
+    if($Old_Value eq $New_Value) {
+        return 0;
+    }
+    while($Old_Value=~s/(\A|\W)const(\W|\Z)/$1$2/)
+    { # remove all "const" qualifiers
+      # one-by-one, left-to-right
+        $Old_Value=~s/\s+\Z//g;
+        $Old_Value=~s/\A\s+//g;
+        $Old_Value = formatName($Old_Value);
+        if($Old_Value eq $New_Value)
+        { # compare with a new type
+            return 1;
+        }
+    }
+    return 0;
+}
+
+sub mergeParameters($$$)
+{
+    my ($Interface, $ParamPos1, $ParamPos2) = @_;
+    return if(not $Interface);
+    return if(not defined $CompleteSignature{1}{$Interface}{"Param"});
+    return if(not defined $CompleteSignature{2}{$Interface}{"Param"});
+    my $ParamType1_Id = $CompleteSignature{1}{$Interface}{"Param"}{$ParamPos1}{"type"};
+    my $ParamName1 = $CompleteSignature{1}{$Interface}{"Param"}{$ParamPos1}{"name"};
+    my $ParamType2_Id = $CompleteSignature{2}{$Interface}{"Param"}{$ParamPos2}{"type"};
+    my $ParamName2 = $CompleteSignature{2}{$Interface}{"Param"}{$ParamPos2}{"name"};
+    return if(not $ParamType1_Id or not $ParamType2_Id);
+    my %Type1 = get_Type($Tid_TDid{1}{$ParamType1_Id}, $ParamType1_Id, 1);
+    my %Type2 = get_Type($Tid_TDid{2}{$ParamType2_Id}, $ParamType2_Id, 2);
+    my %BaseType1 = get_BaseType($Tid_TDid{1}{$ParamType1_Id}, $ParamType1_Id, 1);
+    my %BaseType2 = get_BaseType($Tid_TDid{2}{$ParamType2_Id}, $ParamType2_Id, 2);
+    my $Parameter_Location = ($ParamName1)?$ParamName1:numToStr($ParamPos1+1)." Parameter";
+    if((not $UsedDump{1}{"V"} or cmpVersions($UsedDump{1}{"V"}, "2.6.1")>=0)
+    and (not $UsedDump{2}{"V"} or cmpVersions($UsedDump{2}{"V"}, "2.6.1")>=0))
+    { # "reg" attribute added in ACC 1.95.1 (dump 2.6.1 format)
+        if($CompleteSignature{1}{$Interface}{"Param"}{$ParamPos1}{"reg"}
+        and not $CompleteSignature{2}{$Interface}{"Param"}{$ParamPos2}{"reg"})
+        {
+            %{$CompatProblems{$Interface}{"Parameter_Became_Non_Register"}{$Parameter_Location}}=(
+                "Target"=>$ParamName1,
+                "Param_Pos"=>$ParamPos1  );
+        }
+        elsif(not $CompleteSignature{1}{$Interface}{"Param"}{$ParamPos1}{"reg"}
+        and $CompleteSignature{2}{$Interface}{"Param"}{$ParamPos2}{"reg"})
+        {
+            %{$CompatProblems{$Interface}{"Parameter_Became_Register"}{$Parameter_Location}}=(
+                "Target"=>$ParamName1,
+                "Param_Pos"=>$ParamPos1  );
+        }
+    }
+    if((not $UsedDump{1}{"V"} or cmpVersions($UsedDump{1}{"V"}, "2.0")>=0)
+    and (not $UsedDump{2}{"V"} or cmpVersions($UsedDump{2}{"V"}, "2.0")>=0))
+    { # "default" attribute added in ACC 1.22 (dump 2.0 format)
+        my $DefaultValue_Old = $CompleteSignature{1}{$Interface}{"Param"}{$ParamPos1}{"default"};
+        my $DefaultValue_New = $CompleteSignature{2}{$Interface}{"Param"}{$ParamPos2}{"default"};
+        my %PureType1 = get_PureType($Tid_TDid{1}{$ParamType1_Id}, $ParamType1_Id, 1);
+        if($PureType1{"Name"}=~/\A(char\*|char const\*)\Z/)
+        {
+            if($DefaultValue_Old)
+            { # FIXME: how to distinguish "0" and 0 (NULL)
+                $DefaultValue_Old = "\"$DefaultValue_Old\"";
+            }
+            if($DefaultValue_New) {
+                $DefaultValue_New = "\"$DefaultValue_New\"";
+            }
+        }
+        elsif($PureType1{"Name"}=~/\A(char)\Z/)
+        {
+            if($DefaultValue_Old) {
+                $DefaultValue_Old = "\'$DefaultValue_Old\'";
+            }
+            if($DefaultValue_New) {
+                $DefaultValue_New = "\'$DefaultValue_New\'";
+            }
+        }
+        if($DefaultValue_Old ne "")
+        {
+            if($DefaultValue_New ne "")
+            {
+                if($DefaultValue_Old ne $DefaultValue_New)
+                {
+                    %{$CompatProblems{$Interface}{"Parameter_Default_Value_Changed"}{$Parameter_Location}}=(
+                        "Target"=>$ParamName1,
+                        "Param_Pos"=>$ParamPos1,
+                        "Old_Value"=>$DefaultValue_Old,
+                        "New_Value"=>$DefaultValue_New  );
+                }
+            }
+            else
+            {
+                %{$CompatProblems{$Interface}{"Parameter_Default_Value_Removed"}{$Parameter_Location}}=(
+                        "Target"=>$ParamName1,
+                        "Param_Pos"=>$ParamPos1,
+                        "Old_Value"=>$DefaultValue_Old  );
+            }
+        }
+    }
+    if($ParamName1 ne $ParamName2
+    and $ParamType1_Id!=-1 and $ParamType2_Id!=-1
+    and $ParamName1!~/\Ap\d+\Z/ and $ParamName2!~/\Ap\d+\Z/)
+    { # except unnamed "..." value list (Id=-1)
+        %{$CompatProblems{$Interface}{"Renamed_Parameter"}{numToStr($ParamPos1+1)." Parameter"}}=(
+            "Target"=>$ParamName1,
+            "Param_Pos"=>$ParamPos1,
+            "Param_Type"=>get_TypeName($ParamType1_Id, 1),
+            "Old_Value"=>$ParamName1,
+            "New_Value"=>$ParamName2,
+            "New_Signature"=>get_Signature($Interface, 2)  );
+    }
+    # checking type change (replace)
+    my %SubProblems = detectTypeChange($ParamType1_Id, $ParamType2_Id, "Parameter");
+    foreach my $SubProblemType (keys(%SubProblems))
+    { # add new problems, remove false alarms
+        my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
+        my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
+        if($SubProblemType eq "Parameter_Type")
+        {
+            if((not $UsedDump{1}{"V"} or cmpVersions($UsedDump{1}{"V"}, "2.6")>=0)
+            and (not $UsedDump{2}{"V"} or cmpVersions($UsedDump{2}{"V"}, "2.6")>=0))
+            {
+                if($Old_Value!~/(\A|\W)restrict(\W|\Z)/
+                and $New_Value=~/(\A|\W)restrict(\W|\Z)/)
+                { # change to be "restrict"
+                    %{$SubProblems{"Parameter_Became_Restrict"}} = %{$SubProblems{$SubProblemType}};
+                }
+            }
+            if($Type2{"Type"} eq "Const" and $BaseType2{"Name"} eq $Type1{"Name"}
+            and $Type1{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
+            { # int to "int const"
+                delete($SubProblems{$SubProblemType});
+            }
+            if($Type1{"Type"} eq "Const" and $BaseType1{"Name"} eq $Type2{"Name"}
+            and $Type2{"Type"}=~/Intrinsic|Class|Struct|Union|Enum/)
+            { # "int const" to int
+                delete($SubProblems{$SubProblemType});
+            }
+        }
+    }
+    foreach my $SubProblemType (keys(%SubProblems))
+    { # modify/register problems
+        my $New_Value = $SubProblems{$SubProblemType}{"New_Value"};
+        my $Old_Value = $SubProblems{$SubProblemType}{"Old_Value"};
+        my $NewProblemType = $SubProblemType;
+        if($Old_Value eq "..." and $New_Value ne "...")
+        { # change from "..." to "int"
+            if($ParamPos1==0)
+            { # ISO C requires a named argument before "..."
+                next;
+            }
+            $NewProblemType = "Parameter_Became_NonVaList";
+        }
+        elsif($New_Value eq "..." and $Old_Value ne "...")
+        { # change from "int" to "..."
+            if($ParamPos2==0)
+            { # ISO C requires a named argument before "..."
+                next;
+            }
+            $NewProblemType = "Parameter_Became_VaList";
+        }
+        elsif($SubProblemType eq "Parameter_Type"
+        and removedConstness($Old_Value, $New_Value))
+        { # parameter: "const" to non-"const"
+            $NewProblemType = "Parameter_Became_Non_Const";
+        }
+        elsif($SubProblemType eq "Parameter_Type_And_Size"
+        or $SubProblemType eq "Parameter_Type")
+        {
+            my ($Arch1, $Arch2) = (getArch(1), getArch(2));
+            if($Arch1 eq "unknown" or $Arch2 eq "unknown")
+            { # if one of the architectures is unknown
+                # then set other arhitecture to unknown too
+                ($Arch1, $Arch2) = ("unknown", "unknown");
+            }
+            my ($Method1, $Passed1, $SizeOnStack1, $RegName1) = callingConvention($Interface, $ParamPos1, 1, $Arch1);
+            my ($Method2, $Passed2, $SizeOnStack2, $RegName2) = callingConvention($Interface, $ParamPos2, 2, $Arch2);
+            if($Method1 eq $Method2)
+            {
+                if($Method1 eq "stack" and $SizeOnStack1 ne $SizeOnStack2) {
+                    $NewProblemType = "Parameter_Type_And_Stack";
+                }
+                elsif($Method1 eq "register" and $RegName1 ne $RegName2) {
+                    $NewProblemType = "Parameter_Type_And_Register";
+                }
+            }
+            else
+            {
+                if($Method1 eq "stack") {
+                    $NewProblemType = "Parameter_Type_And_Pass_Through_Register";
+                }
+                elsif($Method1 eq "register") {
+                    $NewProblemType = "Parameter_Type_And_Pass_Through_Stack";
+                }
+            }
+            $SubProblems{$SubProblemType}{"Old_Reg"} = $RegName1;
+            $SubProblems{$SubProblemType}{"New_Reg"} = $RegName2;
+        }
+        %{$CompatProblems{$Interface}{$NewProblemType}{$Parameter_Location}}=(
+            "Target"=>$ParamName1,
+            "Param_Pos"=>$ParamPos1,
+            "New_Signature"=>get_Signature($Interface, 2) );
+        @{$CompatProblems{$Interface}{$NewProblemType}{$Parameter_Location}}{keys(%{$SubProblems{$SubProblemType}})} = values %{$SubProblems{$SubProblemType}};
+    }
+    @RecurTypes = ();
+    # checking type definition changes
+    my %SubProblems_Merge = mergeTypes($ParamType1_Id, $Tid_TDid{1}{$ParamType1_Id}, $ParamType2_Id, $Tid_TDid{2}{$ParamType2_Id});
+    foreach my $SubProblemType (keys(%SubProblems_Merge))
+    {
+        foreach my $SubLocation (keys(%{$SubProblems_Merge{$SubProblemType}}))
+        {
+            my $NewProblemType = $SubProblemType;
+            if($SubProblemType eq "DataType_Size")
+            {
+                my $InitialType_Type = $SubProblems_Merge{$SubProblemType}{$SubLocation}{"InitialType_Type"};
+                if($InitialType_Type!~/\A(Pointer|Ref)\Z/ and $SubLocation!~/\-\>/)
+                { # stack has been affected
+                    $NewProblemType = "DataType_Size_And_Stack";
+                }
+            }
+            my $NewLocation = ($SubLocation)?$Parameter_Location."->".$SubLocation:$Parameter_Location;
+            %{$CompatProblems{$Interface}{$NewProblemType}{$NewLocation}}=(
+                "Param_Type"=>get_TypeName($ParamType1_Id, 1),
+                "Param_Pos"=>$ParamPos1,
+                "Param_Name"=>$ParamName1  );
+            @{$CompatProblems{$Interface}{$NewProblemType}{$NewLocation}}{keys(%{$SubProblems_Merge{$SubProblemType}{$SubLocation}})} = values %{$SubProblems_Merge{$SubProblemType}{$SubLocation}};
+            if($SubLocation!~/\-\>/) {
+                $CompatProblems{$Interface}{$NewProblemType}{$NewLocation}{"Start_Type_Name"} = get_TypeName($ParamType1_Id, 1);
+            }
+        }
+    }
+}
+
+sub callingConvention($$$$)
+{ # calling conventions for different compilers and operating systems
+    my ($Interface, $ParamPos, $LibVersion, $Arch) = @_;
+    my $ParamTypeId = $CompleteSignature{$LibVersion}{$Interface}{"Param"}{$ParamPos}{"type"};
+    my %Type = get_PureType($Tid_TDid{$LibVersion}{$ParamTypeId}, $ParamTypeId, $LibVersion);
+    my ($Method, $Alignment, $Passed, $Register) = ("", 0, "", "");
+    if($OSgroup=~/\A(linux|macos|freebsd)\Z/)
+    {# GCC
+        if($Arch eq "x86")
+        { # System V ABI Intel386 ("Function Calling Sequence")
+          # The stack is word aligned. Although the architecture does not require any
+          # alignment of the stack, software convention and the operating system
+          # requires that the stack be aligned on a word boundary.
+
+          # Argument words are pushed onto the stack in reverse order (that is, the
+          # rightmost argument in C call syntax has the highest address), preserving the
+          # stack’s word alignment. All incoming arguments appear on the stack, residing
+          # in the stack frame of the caller.
+
+          # An argument’s size is increased, if necessary, to make it a multiple of words.
+          # This may require tail padding, depending on the size of the argument.
+
+          # Other areas depend on the compiler and the code being compiled. The stan-
+          # dard calling sequence does not define a maximum stack frame size, nor does
+          # it restrict how a language system uses the ‘‘unspecified’’ area of the stan-
+          # dard stack frame.
+            ($Method, $Alignment) = ("stack", 4);
+        }
+        elsif($Arch eq "x86_64")
+        { # System V AMD64 ABI ("Function Calling Sequence")
+            ($Method, $Alignment) = ("stack", 8);# eightbyte aligned
+        }
+        elsif($Arch eq "arm")
+        { # Procedure Call Standard for the ARM Architecture
+          # The stack must be double-word aligned
+            ($Method, $Alignment) = ("stack", 8);# double-word
+        }
+    }
+    elsif($OSgroup eq "windows")
+    {# MS C++ Compiler
+        if($Arch eq "x86")
+        {
+            if($ParamPos==0) {
+                ($Method, $Register, $Passed) = ("register", "ecx", "value");
+            }
+            elsif($ParamPos==1) {
+                ($Method, $Register, $Passed) = ("register", "edx", "value");
+            }
+            else {
+                ($Method, $Alignment) = ("stack", 4);
+            }
+        }
+        elsif($Arch eq "x86_64")
+        {
+            if($ParamPos<=3)
+            {
+                if($Type{"Name"}=~/\A(float|double|long double)\Z/) {
+                    ($Method, $Passed) = ("xmm".$ParamPos, "value");
+                }
+                elsif($Type{"Name"}=~/\A(unsigned |)(short|int|long|long long)\Z/
+                or $Type{"Type"}=~/\A(Struct|Union|Enum|Array)\Z/
+                or $Type{"Name"}=~/\A(__m64|__m128)\Z/)
+                {
+                    if($ParamPos==0) {
+                        ($Method, $Register, $Passed) = ("register", "rcx", "value");
+                    }
+                    elsif($ParamPos==1) {
+                        ($Method, $Register, $Passed) = ("register", "rdx", "value");
+                    }
+                    elsif($ParamPos==2) {
+                        ($Method, $Register, $Passed) = ("register", "r8", "value");
+                    }
+                    elsif($ParamPos==3) {
+                        ($Method, $Register, $Passed) = ("register", "r9", "value");
+                    }
+                    if($Type{"Size"}>64
+                    or $Type{"Type"} eq "Array") {
+                        $Passed = "pointer";
+                    }
+                }
+            }
+            else {
+                ($Method, $Alignment) = ("stack", 8);# word alignment
+            }
+        }
+    }
+    if($Method eq "register") {
+        return ("register", $Passed, "", $Register);
+    }
+    else
+    {# on the stack
+        if(not $Alignment)
+        {# default convention
+            $Alignment = $WORD_SIZE{$LibVersion};
+        }
+        if(not $Passed)
+        {# default convention
+            $Passed = "value";
+        }
+        my $SizeOnStack = $Type{"Size"};
+        # FIXME: improve stack alignment
+        if($SizeOnStack!=$Alignment) {
+            $SizeOnStack = int(($Type{"Size"}+$Alignment)/$Alignment)*$Alignment;
+        }
+        return ("stack", $Passed, $SizeOnStack, "");
+    }
+}
+
+sub find_ParamPair_Pos_byName($$$)
+{
+    my ($Name, $Interface, $LibVersion) = @_;
+    foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Interface}{"Param"}}))
+    {
+        next if(not defined $CompleteSignature{$LibVersion}{$Interface}{"Param"}{$ParamPos});
+        if($CompleteSignature{$LibVersion}{$Interface}{"Param"}{$ParamPos}{"name"} eq $Name)
+        {
+            return $ParamPos;
+        }
+    }
+    return "lost";
+}
+
+sub find_ParamPair_Pos_byTypeAndPos($$$$$)
+{
+    my ($TypeName, $MediumPos, $Order, $Interface, $LibVersion) = @_;
+    my @Positions = ();
+    foreach my $ParamPos (sort {int($a)<=>int($b)} keys(%{$CompleteSignature{$LibVersion}{$Interface}{"Param"}}))
+    {
+        next if($Order eq "backward" and $ParamPos>$MediumPos);
+        next if($Order eq "forward" and $ParamPos<$MediumPos);
+        next if(not defined $CompleteSignature{$LibVersion}{$Interface}{"Param"}{$ParamPos});
+        my $PTypeId = $CompleteSignature{$LibVersion}{$Interface}{"Param"}{$ParamPos}{"type"};
+        if(get_TypeName($PTypeId, $LibVersion) eq $TypeName) {
+            push(@Positions, $ParamPos);
+        }
+    }
+    return @Positions;
+}
+
+sub getTypeIdByName($$)
+{
+    my ($TypeName, $Version) = @_;
+    return $TName_Tid{$Version}{formatName($TypeName)};
+}
+
+sub checkFormatChange($$)
+{
+    my ($Type1_Id, $Type2_Id) = @_;
+    my $Type1_DId = $Tid_TDid{1}{$Type1_Id};
+    my $Type2_DId = $Tid_TDid{2}{$Type2_Id};
+    my %Type1_Pure = get_PureType($Type1_DId, $Type1_Id, 1);
+    my %Type2_Pure = get_PureType($Type2_DId, $Type2_Id, 2);
+    if($Type1_Pure{"Name"} eq $Type2_Pure{"Name"})
+    { # equal types
+        return 0;
+    }
+    if($Type1_Pure{"Name"}=~/\*/
+    or $Type2_Pure{"Name"}=~/\*/)
+    { # compared in detectTypeChange()
+        return 0;
+    }
+    my %FloatType = map {$_=>1} (
+        "float",
+        "double",
+        "long double"
+    );
+    if($Type1_Pure{"Type"} ne $Type2_Pure{"Type"})
+    { # different types
+        if($Type1_Pure{"Type"} eq "Intrinsic"
+        and $Type2_Pure{"Type"} eq "Enum")
+        { # "int" to "enum"
+            return 0;
+        }
+        elsif($Type2_Pure{"Type"} eq "Intrinsic"
+        and $Type1_Pure{"Type"} eq "Enum")
+        { # "enum" to "int"
+            return 0;
+        }
+        else
+        { # "union" to "struct"
+          #  ...
+            return 1;
+        }
+    }
+    else
+    {
+        if($Type1_Pure{"Type"} eq "Intrinsic")
+        {
+            if($FloatType{$Type1_Pure{"Name"}}
+            or $FloatType{$Type2_Pure{"Name"}})
+            { # "float" to "double"
+              # "float" to "int"
+                return 1;
+            }
+        }
+        elsif($Type1_Pure{"Type"}=~/Class|Struct|Union|Enum/)
+        {
+            my @Membs1 = keys(%{$Type1_Pure{"Memb"}});
+            my @Membs2 = keys(%{$Type2_Pure{"Memb"}});
+            if($#Membs1!=$#Membs2)
+            { # different number of elements
+                return 1;
+            }
+            if($Type1_Pure{"Type"} eq "Enum")
+            {
+                foreach my $Pos (@Membs1)
+                { # compare elements by name and value
+                    if($Type1_Pure{"Memb"}{$Pos}{"name"} ne $Type2_Pure{"Memb"}{$Pos}{"name"}
+                    or $Type1_Pure{"Memb"}{$Pos}{"value"} ne $Type2_Pure{"Memb"}{$Pos}{"value"})
+                    { # different names
+                        return 1;
+                    }
+                }
+            }
+            else
+            {
+                foreach my $Pos (@Membs1)
+                { # compare elements by type name
+                    my $MT1 = get_TypeName($Type1_Pure{"Memb"}{$Pos}{"type"}, 1);
+                    my $MT2 = get_TypeName($Type2_Pure{"Memb"}{$Pos}{"type"}, 2);
+                    if($MT1 ne $MT2)
+                    { # different types
+                        return 1;
+                    }
+                }
+            }
+        }
+    }
+    return 0;
+}
+
+sub isScalar($) {
+    return ($_[0]=~/\A(unsigned |)(short|int|long|long long)\Z/);
+}
+
+sub isFloat($) {
+    return ($_[0]=~/\A(float|double|long double)\Z/);
+}
+
+sub detectTypeChange($$$)
+{
+    my ($Type1_Id, $Type2_Id, $Prefix) = @_;
+    my %LocalProblems = ();
+    my $Type1_DId = $Tid_TDid{1}{$Type1_Id};
+    my $Type2_DId = $Tid_TDid{2}{$Type2_Id};
+    my %Type1 = get_Type($Type1_DId, $Type1_Id, 1);
+    my %Type2 = get_Type($Type2_DId, $Type2_Id, 2);
+    my %Type1_Pure = get_PureType($Type1_DId, $Type1_Id, 1);
+    my %Type2_Pure = get_PureType($Type2_DId, $Type2_Id, 2);
+    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);
+    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);
+    my $Type1_PLevel = get_PointerLevel($Type1_DId, $Type1_Id, 1);
+    my $Type2_PLevel = get_PointerLevel($Type2_DId, $Type2_Id, 2);
+    return () if(not $Type1{"Name"} or not $Type2{"Name"});
+    return () if(not $Type1_Base{"Name"} or not $Type2_Base{"Name"});
+    return () if($Type1_PLevel eq "" or $Type2_PLevel eq "");
+    if($Type1_Base{"Name"} ne $Type2_Base{"Name"}
+    and ($Type1{"Name"} eq $Type2{"Name"} or ($Type1_PLevel>=1 and $Type1_PLevel==$Type2_PLevel
+    and $Type1_Base{"Name"} ne "void" and $Type2_Base{"Name"} ne "void")))
+    { # base type change
+        if($Type1{"Type"} eq "Typedef" and $Type2{"Type"} eq "Typedef"
+        and $Type1{"Name"} eq $Type2{"Name"})
+        { # will be reported in mergeTypes() as typedef problem
+            return ();
+        }
+        if($Type1_Base{"Name"}!~/anon\-/ and $Type2_Base{"Name"}!~/anon\-/)
+        {
+            if($Type1_Base{"Size"} ne $Type2_Base{"Size"}
+            and $Type1_Base{"Size"} and $Type2_Base{"Size"})
+            {
+                %{$LocalProblems{$Prefix."_BaseType_And_Size"}}=(
+                    "Old_Value"=>$Type1_Base{"Name"},
+                    "New_Value"=>$Type2_Base{"Name"},
+                    "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
+                    "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
+                    "InitialType_Type"=>$Type1_Pure{"Type"});
+            }
+            else
+            {
+                if(checkFormatChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}))
+                { # format change
+                    %{$LocalProblems{$Prefix."_BaseType_Format"}}=(
+                        "Old_Value"=>$Type1_Base{"Name"},
+                        "New_Value"=>$Type2_Base{"Name"},
+                        "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
+                        "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
+                        "InitialType_Type"=>$Type1_Pure{"Type"});
+                }
+                elsif(tNameLock($Type1_Base{"Tid"}, $Type2_Base{"Tid"}))
+                {
+                    %{$LocalProblems{$Prefix."_BaseType"}}=(
+                        "Old_Value"=>$Type1_Base{"Name"},
+                        "New_Value"=>$Type2_Base{"Name"},
+                        "Old_Size"=>$Type1_Base{"Size"}*$BYTE_SIZE,
+                        "New_Size"=>$Type2_Base{"Size"}*$BYTE_SIZE,
+                        "InitialType_Type"=>$Type1_Pure{"Type"});
+                }
+            }
+        }
+    }
+    elsif($Type1{"Name"} ne $Type2{"Name"})
+    { # type change
+        if($Type1{"Name"}!~/anon\-/ and $Type2{"Name"}!~/anon\-/)
+        {
+            if($Prefix eq "Return" and $Type1{"Name"} eq "void"
+            and $Type2_Pure{"Type"}=~/Intrinsic|Enum/) {
+                # safe change
+            }
+            elsif($Prefix eq "Return"
+            and $Type1_Pure{"Name"} eq "void")
+            {
+                %{$LocalProblems{"Return_Type_From_Void"}}=(
+                    "New_Value"=>$Type2{"Name"},
+                    "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
+                    "InitialType_Type"=>$Type1_Pure{"Type"});
+            }
+            elsif($Prefix eq "Return" and $Type1_Pure{"Type"}=~/Intrinsic|Enum/
+            and $Type2_Pure{"Type"}=~/Struct|Class|Union/)
+            { # returns into hidden first parameter instead of a register
+                
+                # System V ABI Intel386 ("Function Calling Sequence")
+                # A function that returns an integral or pointer value places its result in register %eax.
+
+                # A floating-point return value appears on the top of the Intel387 register stack. The
+                # caller then must remove the value from the Intel387 stack, even if it doesn’t use the
+                # value.
+
+                # If a function returns a structure or union, then the caller provides space for the
+                # return value and places its address on the stack as argument word zero. In effect,
+                # this address becomes a ‘‘hidden’’ first argument.
+                
+                %{$LocalProblems{"Return_Type_From_Register_To_Stack"}}=(
+                    "Old_Value"=>$Type1{"Name"},
+                    "New_Value"=>$Type2{"Name"},
+                    "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
+                    "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
+                    "InitialType_Type"=>$Type1_Pure{"Type"});
+            }
+            elsif($Prefix eq "Return"
+            and $Type2_Pure{"Name"} eq "void")
+            {
+                %{$LocalProblems{"Return_Type_Became_Void"}}=(
+                    "Old_Value"=>$Type1{"Name"},
+                    "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
+                    "InitialType_Type"=>$Type1_Pure{"Type"});
+            }
+            elsif($Prefix eq "Return"
+            and ((isScalar($Type1_Pure{"Name"}) and isFloat($Type2_Pure{"Name"}))
+            or (isScalar($Type2_Pure{"Name"}) and isFloat($Type1_Pure{"Name"}))))
+            { # The scalar and floating-point values are passed in different registers
+                %{$LocalProblems{"Return_Type_And_Register"}}=(
+                    "Old_Value"=>$Type1{"Name"},
+                    "New_Value"=>$Type2{"Name"},
+                    "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
+                    "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
+                    "InitialType_Type"=>$Type1_Pure{"Type"});
+            }
+            elsif($Prefix eq "Return" and $Type2_Pure{"Type"}=~/Intrinsic|Enum/
+            and $Type1_Pure{"Type"}=~/Struct|Class|Union/)
+            { # returns in a register instead of a hidden first parameter
+                %{$LocalProblems{"Return_Type_From_Stack_To_Register"}}=(
+                    "Old_Value"=>$Type1{"Name"},
+                    "New_Value"=>$Type2{"Name"},
+                    "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
+                    "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
+                    "InitialType_Type"=>$Type1_Pure{"Type"});
+            }
+            else
+            {
+                if($Type1{"Size"} ne $Type2{"Size"}
+                and $Type1{"Size"} and $Type2{"Size"})
+                {
+                    %{$LocalProblems{$Prefix."_Type_And_Size"}}=(
+                        "Old_Value"=>$Type1{"Name"},
+                        "New_Value"=>$Type2{"Name"},
+                        "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
+                        "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
+                        "InitialType_Type"=>$Type1_Pure{"Type"});
+                }
+                else
+                {
+                    if(checkFormatChange($Type1_Id, $Type2_Id))
+                    { # format change
+                        %{$LocalProblems{$Prefix."_Type_Format"}}=(
+                            "Old_Value"=>$Type1{"Name"},
+                            "New_Value"=>$Type2{"Name"},
+                            "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
+                            "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
+                            "InitialType_Type"=>$Type1_Pure{"Type"});
+                    }
+                    elsif(tNameLock($Type1_Id, $Type2_Id))
+                    { # FIXME: correct this condition
+                        %{$LocalProblems{$Prefix."_Type"}}=(
+                            "Old_Value"=>$Type1{"Name"},
+                            "New_Value"=>$Type2{"Name"},
+                            "Old_Size"=>$Type1{"Size"}*$BYTE_SIZE,
+                            "New_Size"=>$Type2{"Size"}*$BYTE_SIZE,
+                            "InitialType_Type"=>$Type1_Pure{"Type"});
+                    }
+                }
+            }
+        }
+    }
+    if($Type1_PLevel!=$Type2_PLevel)
+    {
+        if($Type1{"Name"} ne "void" and $Type1{"Name"} ne "..."
+        and $Type2{"Name"} ne "void" and $Type2{"Name"} ne "...")
+        {
+            if($Type2_PLevel>$Type1_PLevel) {
+                %{$LocalProblems{$Prefix."_PointerLevel_Increased"}}=(
+                    "Old_Value"=>$Type1_PLevel,
+                    "New_Value"=>$Type2_PLevel);
+            }
+            else {
+                %{$LocalProblems{$Prefix."_PointerLevel_Decreased"}}=(
+                    "Old_Value"=>$Type1_PLevel,
+                    "New_Value"=>$Type2_PLevel);
+            }
+        }
+    }
+    if($Type1_Pure{"Type"} eq "Array")
+    { # base_type[N] -> base_type[N]
+      # base_type: older_structure -> typedef to newer_structure
+        my %SubProblems = detectTypeChange($Type1_Base{"Tid"}, $Type2_Base{"Tid"}, $Prefix);
+        foreach my $SubProblemType (keys(%SubProblems))
+        {
+            $SubProblemType=~s/_Type/_BaseType/g;
+            next if(defined $LocalProblems{$SubProblemType});
+            foreach my $Attr (keys(%{$SubProblems{$SubProblemType}})) {
+                $LocalProblems{$SubProblemType}{$Attr} = $SubProblems{$SubProblemType}{$Attr};
+            }
+        }
+    }
+    return %LocalProblems;
+}
+
+sub tNameLock($$)
+{
+    my ($Tid1, $Tid2) = @_;
+    if(differentFmts())
+    { # different formats
+        if($UseOldDumps)
+        { # old dumps
+            return 0;
+        }
+        my $TN1 = get_TypeName($Tid1, 1);
+        my $TN2 = get_TypeName($Tid2, 2);
+        my %Base1 = get_Type($Tid_TDid{1}{$Tid1}, $Tid1, 1);
+        while($Base1{"Type"} eq "Typedef") {
+            %Base1 = get_OneStep_BaseType($Base1{"TDid"}, $Base1{"Tid"}, 1);
+        }
+        my %Base2 = get_Type($Tid_TDid{2}{$Tid2}, $Tid2, 2);
+        while($Base2{"Type"} eq "Typedef") {
+            %Base2 = get_OneStep_BaseType($Base2{"TDid"}, $Base2{"Tid"}, 2);
+        }
+        my $Base1 = uncover_typedefs($Base1{"Name"}, 1);
+        my $Base2 = uncover_typedefs($Base2{"Name"}, 2);
+        if($TN1 ne $TN2
+        and $Base1 eq $Base2)
+        { # equal base types
+            return 0;
+        }
+        if(($UsedDump{1}{"V"} and cmpVersions($UsedDump{1}{"V"}, "2.6")<0)
+        or ($UsedDump{2}{"V"} and cmpVersions($UsedDump{2}{"V"}, "2.6")<0))
+        {
+            if($TN1!~/(\A|\W)restrict(\W|\Z)/
+            and $TN2=~/(\A|\W)restrict(\W|\Z)/) {
+                return 0;
+            }
+        }
+        
+    }
+    return 1;
+}
+
+sub differentFmts()
+{
+    if(getGccVersion(1) ne getGccVersion(2))
+    { # different GCC versions
+        return 1;
+    }
+    if(cmpVersions(formatVersion($UsedDump{1}{"V"}, 2),
+    formatVersion($UsedDump{2}{"V"}, 2))!=0)
+    { # different dump versions (skip micro version)
+        return 1;
+    }
+    return 0;
+}
+
+sub formatVersion($$)
+{ # cut off version digits
+    my ($Version, $Digits) = @_;
+    my @Elems = split(/\./, $Version);
+    return join(".", splice(@Elems, 0, $Digits));
+} 
+
+sub htmlSpecChars($)
+{
+    my $Str = $_[0];
+    $Str=~s/\&([^#]|\Z)/&amp;$1/g;
+    $Str=~s/</&lt;/g;
+    $Str=~s/\-\>/&#45;&gt;/g; # &minus;
+    $Str=~s/>/&gt;/g;
+    $Str=~s/([^ ])( )([^ ])/$1\@ALONE_SP\@$3/g;
+    $Str=~s/ /&#160;/g; # &nbsp;
+    $Str=~s/\@ALONE_SP\@/ /g;
+    $Str=~s/\n/<br\/>/g;
+    $Str=~s/\"/&quot;/g;
+    $Str=~s/\'/&#39;/g;
+    return $Str;
+}
+
+sub black_name($)
+{
+    my $Name = $_[0];
+    return "<span class='iname_b'>".highLight_Signature($Name)."</span>";
+}
+
+sub highLight_Signature($)
+{
+    my $Signature = $_[0];
+    return highLight_Signature_PPos_Italic($Signature, "", 0, 0, 0);
+}
+
+sub highLight_Signature_Italic_Color($)
+{
+    my $Signature = $_[0];
+    return highLight_Signature_PPos_Italic($Signature, "", 1, 1, 1);
+}
+
+sub separate_symbol($)
+{
+    my $Symbol = $_[0];
+    my ($Name, $Spec, $Ver) = ($Symbol, "", "");
+    if($Symbol=~/\A([^\@\$\?]+)([\@\$]+)([^\@\$]+)\Z/) {
+        ($Name, $Spec, $Ver) = ($1, $2, $3);
+    }
+    return ($Name, $Spec, $Ver);
+}
+
+sub cut_f_attrs($)
+{
+    if($_[0]=~s/(\))((| (const volatile|const|volatile))(| \[static\]))\Z/$1/) {
+        return $2;
+    }
+    return "";
+}
+
+sub highLight_Signature_PPos_Italic($$$$$)
+{
+    my ($FullSignature, $Parameter_Position, $ItalicParams, $ColorParams, $ShowReturn) = @_;
+    if($CheckObjectsOnly) {
+        $ItalicParams=$ColorParams=0;
+    }
+    my ($Signature, $VersionSpec, $SymbolVersion) = separate_symbol($FullSignature);
+    my $Return = "";
+    if($ShowRetVal and $Signature=~s/([^:]):([^:].+?)\Z/$1/g) {
+        $Return = $2;
+    }
+    my $SCenter = detect_center($Signature, "(");
+    if(not $SCenter)
+    {# global data
+        $Signature = htmlSpecChars($Signature);
+        $Signature=~s!(\[data\])!<span style='color:Black;font-weight:normal;'>$1</span>!g;
+        $Signature .= (($SymbolVersion)?"<span class='symver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
+        if($Return and $ShowReturn) {
+            $Signature .= "<span class='int_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
+        }
+        return $Signature;
+    }
+    my ($Begin, $End) = (substr($Signature, 0, $SCenter), "");
+    $Begin.=" " if($Begin!~/ \Z/);
+    $End = cut_f_attrs($Signature);
+    my @Parts = ();
+    my @SParts = get_s_params($Signature, 1);
+    foreach my $Num (0 .. $#SParts)
+    {
+        my $Part = $SParts[$Num];
+        $Part=~s/\A\s+|\s+\Z//g;
+        my ($Part_Styled, $ParamName) = (htmlSpecChars($Part), "");
+        if($Part=~/\([\*]+(\w+)\)/i) {
+            $ParamName = $1;#func-ptr
+        }
+        elsif($Part=~/(\w+)[\,\)]*\Z/i) {
+            $ParamName = $1;
+        }
+        if(not $ParamName) {
+            push(@Parts, $Part_Styled);
+            next;
+        }
+        if($ItalicParams and not $TName_Tid{1}{$Part}
+        and not $TName_Tid{2}{$Part})
+        {
+            if($Parameter_Position ne ""
+            and $Num==$Parameter_Position) {
+                $Part_Styled =~ s!(\W)$ParamName([\,\)]|\Z)!$1<span class='focus_p'>$ParamName</span>$2!ig;
+            }
+            elsif($ColorParams) {
+                $Part_Styled =~ s!(\W)$ParamName([\,\)]|\Z)!$1<span class='color_p'>$ParamName</span>$2!ig;
+            }
+            else {
+                $Part_Styled =~ s!(\W)$ParamName([\,\)]|\Z)!$1<span style='font-style:italic;'>$ParamName</span>$2!ig;
+            }
+        }
+        $Part_Styled=~s/,(\w)/, $1/g;
+        push(@Parts, $Part_Styled);
+    }
+    if(@Parts)
+    {
+        foreach my $Num (0 .. $#Parts)
+        {
+            if($Num==$#Parts)
+            { # add ")" to the last parameter
+                $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]." )</span>";
+            }
+            elsif(length($Parts[$Num])<=45) {
+                $Parts[$Num] = "<span class='nowrap'>".$Parts[$Num]."</span>";
+            }
+        }
+        $Signature = htmlSpecChars($Begin)."<span class='int_p'>(&#160;".join(" ", @Parts)."</span>".$End;
+    }
+    else {
+        $Signature = htmlSpecChars($Begin)."<span class='int_p'>(&#160;)</span>".$End;
+    }
+    if($Return and $ShowReturn) {
+        $Signature .= "<span class='int_p nowrap'> &#160;<b>:</b>&#160;&#160;".htmlSpecChars($Return)."</span>";
+    }
+    $Signature=~s!\[\]![<span style='padding-left:2px;'>]</span>!g;
+    $Signature=~s!operator=!operator<span style='padding-left:2px'>=</span>!g;
+    $Signature=~s!(\[in-charge\]|\[not-in-charge\]|\[in-charge-deleting\]|\[static\])!<span style='color:Black;font-weight:normal;'>$1</span>!g;
+    return $Signature.(($SymbolVersion)?"<span class='symver'>&#160;$VersionSpec&#160;$SymbolVersion</span>":"");
+}
+
+sub get_s_params($$)
+{
+    my ($Signature, $Comma) = @_;
+    my @Parts = ();
+    my $Signature = $Signature;
+    my $ShortName = substr($Signature, 0, detect_center($Signature, "("));
+    $Signature=~s/\A\Q$ShortName\E\(//g;
+    cut_f_attrs($Signature);
+    $Signature=~s/\)\Z//;
+    return separate_params($Signature, $Comma);
+}
+
+sub separate_params($$)
+{
+    my ($Params, $Comma) = @_;
+    my @Parts = ();
+    my ($Bracket_Num, $Bracket2_Num, $Part_Num) = (0, 0, 0);
+    foreach my $Pos (0 .. length($Params) - 1)
+    {
+        my $Symbol = substr($Params, $Pos, 1);
+        $Bracket_Num += 1 if($Symbol eq "(");
+        $Bracket_Num -= 1 if($Symbol eq ")");
+        $Bracket2_Num += 1 if($Symbol eq "<");
+        $Bracket2_Num -= 1 if($Symbol eq ">");
+        if($Symbol eq "," and $Bracket_Num==0 and $Bracket2_Num==0)
+        {
+            if($Comma) {# include comma
+                $Parts[$Part_Num] .= $Symbol;
+            }
+            $Part_Num += 1;
+        }
+        else {
+            $Parts[$Part_Num] .= $Symbol;
+        }
+    }
+    return @Parts;
+}
+
+sub detect_center($$)
+{
+    my ($Sign, $Target) = @_;
+    my %B = (
+        "("=>0,
+        "<"=>0,
+        ")"=>0,
+        ">"=>0 );
+    my $Center = 0;
+    if($Sign=~s/(operator([<>\-\=\*]+|\(\)))//g)
+    { # operators: (),->,->*,<,<=,<<,<<=,>,>=,>>,>>=
+        $Center+=length($1);
+    }
+    foreach my $Pos (0 .. length($Sign)-1)
+    {
+        my $S = substr($Sign, $Pos, 1);
+        if($S eq $Target)
+        {
+            if($B{"("}==$B{")"}
+            and $B{"<"}==$B{">"}) {
+                return $Center;
+            }
+        }
+        if(defined $B{$S}) {
+            $B{$S}+=1;
+        }
+        $Center+=1;
+    }
+    return 0;
+}
+
+sub appendFile($$)
+{
+    my ($Path, $Content) = @_;
+    return if(not $Path);
+    if(my $Dir = get_dirname($Path)) {
+        mkpath($Dir);
+    }
+    open(FILE, ">>".$Path) || die ("can't open file \'$Path\': $!\n");
+    print FILE $Content;
+    close(FILE);
+}
+
+sub writeFile($$)
+{
+    my ($Path, $Content) = @_;
+    return if(not $Path);
+    if(my $Dir = get_dirname($Path)) {
+        mkpath($Dir);
+    }
+    open (FILE, ">".$Path) || die ("can't open file \'$Path\': $!\n");
+    print FILE $Content;
+    close(FILE);
+}
+
+sub readFile($)
+{
+    my $Path = $_[0];
+    return "" if(not $Path or not -f $Path);
+    open (FILE, $Path);
+    local $/ = undef;
+    my $Content = <FILE>;
+    close(FILE);
+    if($Path!~/\.(tu|class)\Z/) {
+        $Content=~s/\r/\n/g;
+    }
+    return $Content;
+}
+
+sub get_filename($)
+{ # much faster than basename() from File::Basename module
+    if($_[0]=~/([^\/\\]+)[\/\\]*\Z/) {
+        return $1;
+    }
+    return "";
+}
+
+sub get_dirname($)
+{ # much faster than dirname() from File::Basename module
+    if($_[0]=~/\A(.*?)[\/\\]+[^\/\\]*[\/\\]*\Z/) {
+        return $1;
+    }
+    return "";
+}
+
+sub separate_path($) {
+    return (get_dirname($_[0]), get_filename($_[0]));
+}
+
+sub esc($)
+{
+    my $Str = $_[0];
+    $Str=~s/([()\[\]{}$ &'"`;,<>\+])/\\$1/g;
+    return $Str;
+}
+
+sub readLineNum($$)
+{
+    my ($Path, $Num) = @_;
+    return "" if(not $Path or not -f $Path);
+    open (FILE, $Path);
+    foreach (1 ... $Num) {
+        <FILE>;
+    }
+    my $Line = <FILE>;
+    close(FILE);
+    return $Line;
+}
+
+sub readAttributes($)
+{
+    my $Path = $_[0];
+    return () if(not $Path or not -f $Path);
+    my %Attributes = ();
+    if(readLineNum($Path, 0)=~/<!--\s+(.+)\s+-->/) {
+        foreach my $AttrVal (split(/;/, $1)) {
+            if($AttrVal=~/(.+):(.+)/)
+            {
+                my ($Name, $Value) = ($1, $2);
+                $Attributes{$Name} = $Value;
+            }
+        }
+    }
+    return \%Attributes;
+}
+
+sub is_abs($) {
+    return ($_[0]=~/\A(\/|\w+:[\/\\])/);
+}
+
+sub get_abs_path($)
+{ # abs_path() should NOT be called for absolute inputs
+  # because it can change them
+    my $Path = $_[0];
+    if(not is_abs($Path)) {
+        $Path = abs_path($Path);
+    }
+    return $Path;
+}
+
+sub get_OSgroup()
+{
+    $_ = $Config{"osname"};
+    if(/macos|darwin|rhapsody/i) {
+        return "macos";
+    }
+    elsif(/freebsd|openbsd|netbsd/i) {
+        return "bsd";
+    }
+    elsif(/haiku|beos/i) {
+        return "beos";
+    }
+    elsif(/symbian|epoc/i) {
+        return "symbian";
+    }
+    elsif(/win/i) {
+        return "windows";
+    }
+    else {
+        return $_;
+    }
+}
+
+sub getGccVersion($)
+{
+    my $LibVersion = $_[0];
+    if($GCC_VERSION{$LibVersion})
+    { # dump version
+        return $GCC_VERSION{$LibVersion};
+    }
+    elsif($UsedDump{$LibVersion}{"V"})
+    { # old-version dumps
+        return "unknown";
+    }
+    my $GccVersion = get_dumpversion($GCC_PATH); # host version
+    if(not $GccVersion) {
+        return "unknown";
+    }
+    return $GccVersion;
+}
+
+sub showArch($)
+{
+    my $Arch = $_[0];
+    if($Arch eq "arm"
+    or $Arch eq "mips") {
+        return uc($Arch);
+    }
+    return $Arch;
+}
+
+sub getArch($)
+{
+    my $LibVersion = $_[0];
+    if($CPU_ARCH{$LibVersion})
+    { # dump version
+        return $CPU_ARCH{$LibVersion};
+    }
+    elsif($UsedDump{$LibVersion}{"V"})
+    { # old-version dumps
+        return "unknown";
+    }
+    if(defined $Cache{"getArch"}{$LibVersion}) {
+        return $Cache{"getArch"}{$LibVersion};
+    }
+    my $Arch = get_dumpmachine($GCC_PATH); # host version
+    if(not $Arch) {
+        return "unknown";
+    }
+    if($Arch=~/\A([\w]{3,})(-|\Z)/) {
+        $Arch = $1;
+    }
+    $Arch = "x86" if($Arch=~/\Ai[3-7]86\Z/);
+    if($OSgroup eq "windows") {
+        $Arch = "x86" if($Arch=~/win32|mingw32/i);
+        $Arch = "x86_64" if($Arch=~/win64|mingw64/i);
+    }
+    $Cache{"getArch"}{$LibVersion} = $Arch;
+    return $Arch;
+}
+
+sub get_Report_Header()
+{
+    my $ArchInfo = " on <span style='color:Blue;'>".showArch(getArch(1))."</span>";
+    if(getArch(1) ne getArch(2) or getArch(1) eq "unknown")
+    { # don't show architecture in the header
+        $ArchInfo="";
+    }
+    my $Report_Header = "<h1><span class='nowrap'>Binary compatibility report for the <span style='color:Blue;'>$TargetLibraryFName</span> $TargetComponent</span>";
+    $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>";
+    if($AppPath) {
+        $Report_Header .= " <span class='nowrap'>&#160;(relating to the portability of application <span style='color:Blue;'>".get_filename($AppPath)."</span>)</span>";
+    }
+    $Report_Header .= "</h1>\n";
+    return $Report_Header;
+}
+
+sub get_SourceInfo()
+{
+    my $CheckedHeaders = "<a name='Headers'></a><h2>Header Files (".keys(%{$Registered_Headers{1}}).")</h2><hr/>\n";
+    $CheckedHeaders .= "<div class='h_list'>\n";
+    foreach my $Header_Path (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
+    {
+        my $Identity = $Registered_Headers{1}{$Header_Path}{"Identity"};
+        my $Header_Name = get_filename($Identity);
+        my $Dest_Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
+        $CheckedHeaders .= "$Header_Name$Dest_Comment<br/>\n";
+    }
+    $CheckedHeaders .= "</div>\n";
+    $CheckedHeaders .= "<br/><a style='font-size:11px;' href='#Top'>to the top</a><br/>\n";
+    my $CheckedLibs = "<a name='Libs'></a><h2>".ucfirst($SLIB_TYPE)." Libraries (".keys(%{$Library_Symbol{1}}).")</h2><hr/>\n";
+    $CheckedLibs .= "<div class='lib_list'>\n";
+    foreach my $Library (sort {lc($a) cmp lc($b)}  keys(%{$Library_Symbol{1}}))
+    {
+        $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
+        $CheckedLibs .= "$Library<br/>\n";
+    }
+    $CheckedLibs .= "</div>\n";
+    $CheckedLibs .= "<br/><a style='font-size:11px;' href='#Top'>to the top</a><br/>\n";
+    if($CheckObjectsOnly) {
+        $CheckedHeaders = "";
+    }
+    if($CheckHeadersOnly) {
+        $CheckedLibs = "";
+    }
+    return $CheckedHeaders.$CheckedLibs;
+}
+
+sub get_TypeProblems_Count($$$)
+{
+    my ($TypeChanges, $TargetPriority, $Level) = @_;
+    my $Type_Problems_Count = 0;
+    foreach my $Type_Name (sort keys(%{$TypeChanges}))
+    {
+        my %Kinds_Target = ();
+        foreach my $Kind (keys(%{$TypeChanges->{$Type_Name}}))
+        {
+            foreach my $Location (keys(%{$TypeChanges->{$Type_Name}{$Kind}}))
+            {
+                my $Target = $TypeChanges->{$Type_Name}{$Kind}{$Location}{"Target"};
+                my $Priority = getProblemSeverity($Level, $Kind);
+                next if($Priority ne $TargetPriority);
+                if($Kinds_Target{$Kind}{$Target}) {
+                    next;
+                }
+                if(cmp_priority($Type_MaxPriority{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
+                { # select a problem with the highest priority
+                    next;
+                }
+                $Kinds_Target{$Kind}{$Target} = 1;
+                $Type_Problems_Count += 1;
+            }
+        }
+    }
+    return $Type_Problems_Count;
+}
+
+sub get_Summary($)
+{
+    my $Level = $_[0]; # API or ABI
+    my ($Added, $Removed, $I_Problems_High, $I_Problems_Medium, $I_Problems_Low,
+    $T_Problems_High, $T_Problems_Medium, $T_Problems_Low, $I_Other, $T_Other) = (0,0,0,0,0,0,0,0,0,0);
+    # check rules
+    foreach my $Interface (sort keys(%CompatProblems))
+    {
+        foreach my $Kind (keys(%{$CompatProblems{$Interface}}))
+        {
+            if(not defined $CompatRules{$Level}{$Kind})
+            { # unknown rule
+                if(not $UnknownRules{$Level}{$Kind})
+                { # only one warning
+                    printMsg("WARNING", "unknown rule \"$Kind\" (\"$Level\")");
+                    $UnknownRules{$Level}{$Kind}=1;
+                }
+                delete($CompatProblems{$Interface}{$Kind});
+            }
+        }
+    }
+    foreach my $Interface (sort keys(%CompatProblems))
+    {
+        foreach my $Kind (sort keys(%{$CompatProblems{$Interface}}))
+        {
+            if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols")
+            {
+                foreach my $Location (sort keys(%{$CompatProblems{$Interface}{$Kind}}))
+                {
+                    my $Priority = getProblemSeverity($Level, $Kind);
+                    if($Kind eq "Added_Interface") {
+                        $Added += 1;
+                    }
+                    elsif($Kind eq "Removed_Interface")
+                    {
+                        $Removed += 1;
+                        $TotalAffected{$Level}{$Interface} = $Priority;
+                    }
+                    else
+                    {
+                        if($Priority eq "Safe") {
+                            $I_Other += 1;
+                        }
+                        elsif($Priority eq "High") {
+                            $I_Problems_High += 1;
+                        }
+                        elsif($Priority eq "Medium") {
+                            $I_Problems_Medium += 1;
+                        }
+                        elsif($Priority eq "Low") {
+                            $I_Problems_Low += 1;
+                        }
+                        if(($Priority ne "Low" or $StrictCompat)
+                        and $Priority ne "Safe") {
+                            $TotalAffected{$Level}{$Interface} = $Priority;
+                        }
+                    }
+                }
+            }
+        }
+    }
+    my %TypeChanges = ();
+    foreach my $Interface (sort keys(%CompatProblems))
+    {
+        foreach my $Kind (keys(%{$CompatProblems{$Interface}}))
+        {
+            if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
+            {
+                foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Interface}{$Kind}}))
+                {
+                    my $Type_Name = $CompatProblems{$Interface}{$Kind}{$Location}{"Type_Name"};
+                    my $Target = $CompatProblems{$Interface}{$Kind}{$Location}{"Target"};
+                    my $Priority = getProblemSeverity($Level, $Kind);
+                    if(cmp_priority($Type_MaxPriority{$Level}{$Type_Name}{$Kind}{$Target}, $Priority))
+                    { # select a problem with the highest priority
+                        next;
+                    }
+                    if(($Priority ne "Low" or $StrictCompat)
+                    and $Priority ne "Safe") {
+                        $TotalAffected{$Level}{$Interface} = max_priority($TotalAffected{$Level}{$Interface}, $Priority);
+                    }
+                    %{$TypeChanges{$Type_Name}{$Kind}{$Location}} = %{$CompatProblems{$Interface}{$Kind}{$Location}};
+                    $Type_MaxPriority{$Level}{$Type_Name}{$Kind}{$Target} = max_priority($Type_MaxPriority{$Level}{$Type_Name}{$Kind}{$Target}, $Priority);
+                }
+            }
+        }
+    }
+    $T_Problems_High = get_TypeProblems_Count(\%TypeChanges, "High", $Level);
+    $T_Problems_Medium = get_TypeProblems_Count(\%TypeChanges, "Medium", $Level);
+    $T_Problems_Low = get_TypeProblems_Count(\%TypeChanges, "Low", $Level);
+    $T_Other = get_TypeProblems_Count(\%TypeChanges, "Safe", $Level);
+    if($CheckObjectsOnly)
+    { # only removed exported symbols
+        $RESULT{"Affected"} = $Removed*100/keys(%{$Symbol_Library{1}});
+    }
+    else
+    { # changed and removed public symbols
+        my $SCount = keys(%CheckedSymbols);
+        if($ExtendedCheck)
+        { # don't count external_func_0 for constants
+            $SCount-=1;
+        }
+        if($SCount)
+        {
+            my %Weight = (
+                "High" => 100,
+                "Medium" => 50,
+                "Low" => 25
+            );
+            foreach (keys(%{$TotalAffected{$Level}})) {
+                $RESULT{"Affected"}+=$Weight{$TotalAffected{$Level}{$_}};
+            }
+            $RESULT{"Affected"} = $RESULT{"Affected"}/$SCount;
+        }
+        else {
+            $RESULT{"Affected"} = 0;
+        }
+    }
+    $RESULT{"Affected"} = show_number($RESULT{"Affected"});
+    if($RESULT{"Affected"}>=100) {
+        $RESULT{"Affected"} = 100;
+    }
+    
+    $RESULT{"Problems"} = $Removed + $T_Problems_High + $I_Problems_High;
+    $RESULT{"Problems"} += $T_Problems_Medium + $I_Problems_Medium;
+    $RESULT{$StrictCompat?"Problems":"Warnings"} += $T_Problems_Low + $I_Problems_Low;
+    $RESULT{$StrictCompat?"Problems":"Warnings"} += keys(%ProblemsWithConstants);
+    if($CheckImpl) {
+        $RESULT{$StrictCompat?"Problems":"Warnings"} += keys(%ImplProblems);
+    }
+    $RESULT{"Verdict"} = $RESULT{"Problems"}?"incompatible":"compatible";
+    
+    my $TotalTypes = keys(%CheckedTypes);
+    if(not $TotalTypes) {# list all the types
+        $TotalTypes = keys(%{$TName_Tid{1}});
+    }
+    
+    my ($Arch1, $Arch2) = (getArch(1), getArch(2));
+    my ($GccV1, $GccV2) = (getGccVersion(1), getGccVersion(2));
+    
+    my ($TestInfo, $TestResults, $Problem_Summary) = ();
+    
+    if($ReportFormat eq "xml")
+    { # XML
+        # test info
+        $TestInfo .= "  <library>$TargetLibraryName</library>\n";
+        $TestInfo .= "  <version1>\n";
+        $TestInfo .= "    <number>".$Descriptor{1}{"Version"}."</number>\n";
+        $TestInfo .= "    <architecture>$Arch1</architecture>\n";
+        $TestInfo .= "    <gcc>$GccV1</gcc>\n";
+        $TestInfo .= "  </version1>\n";
+        
+        $TestInfo .= "  <version2>\n";
+        $TestInfo .= "    <number>".$Descriptor{2}{"Version"}."</number>\n";
+        $TestInfo .= "    <architecture>$Arch2</architecture>\n";
+        $TestInfo .= "    <gcc>$GccV2</gcc>\n";
+        $TestInfo .= "  </version2>\n";
+        $TestInfo = "<test_info>\n".$TestInfo."</test_info>\n\n";
+        
+        # test results
+        $TestResults .= "  <headers>\n";
+        foreach my $Name (sort {lc($Registered_Headers{1}{$a}{"Identity"}) cmp lc($Registered_Headers{1}{$b}{"Identity"})} keys(%{$Registered_Headers{1}}))
+        {
+            my $Identity = $Registered_Headers{1}{$_}{"Identity"};
+            my $Comment = ($Identity=~/[\/\\]/)?" ($Identity)":"";
+            $TestResults .= "    <name>".get_filename($Name).$Comment."</name>\n";
+        }
+        $TestResults .= "  </headers>\n";
+        
+        $TestResults .= "  <libs>\n";
+        foreach my $Library (sort {lc($a) cmp lc($b)}  keys(%{$Library_Symbol{1}}))
+        {
+            $Library.=" (.$LIB_EXT)" if($Library!~/\.\w+\Z/);
+            $TestResults .= "    <name>$Library</name>\n";
+        }
+        $TestResults .= "  </libs>\n";
+        
+        $TestResults .= "  <symbols>".(keys(%CheckedSymbols) - keys(%GeneratedSymbols))."</symbols>\n";
+        $TestResults .= "  <types>".$TotalTypes."</types>\n";
+        
+        $TestResults .= "  <verdict>".$RESULT{"Verdict"}."</verdict>\n";
+        $TestResults .= "  <affected>".$RESULT{"Affected"}."</affected>\n";
+        $TestResults = "<test_results>\n".$TestResults."</test_results>\n\n";
+        
+        # problem summary
+        $Problem_Summary .= "  <added_symbols>".$Added."</added_symbols>\n";
+        $Problem_Summary .= "  <removed_symbols>".$Removed."</removed_symbols>\n";
+        
+        $Problem_Summary .= "  <problems_with_types>\n";
+        $Problem_Summary .= "    <high>$T_Problems_High</high>\n";
+        $Problem_Summary .= "    <medium>$T_Problems_Medium</medium>\n";
+        $Problem_Summary .= "    <low>$T_Problems_Low</low>\n";
+        $Problem_Summary .= "    <safe>$T_Other</safe>\n";
+        $Problem_Summary .= "  </problems_with_types>\n";
+        
+        $Problem_Summary .= "  <problems_with_symbols>\n";
+        $Problem_Summary .= "    <high>$I_Problems_High</high>\n";
+        $Problem_Summary .= "    <medium>$I_Problems_Medium</medium>\n";
+        $Problem_Summary .= "    <low>$I_Problems_Low</low>\n";
+        $Problem_Summary .= "  </problems_with_symbols>\n";
+        
+        $Problem_Summary .= "  <problems_with_constants>\n";
+        $Problem_Summary .= "    <low>".keys(%ProblemsWithConstants)."</low>\n";
+        $Problem_Summary .= "  </problems_with_constants>\n";
+        if($CheckImpl)
+        {
+            $Problem_Summary .= "  <impl>\n";
+            $Problem_Summary .= "    <low>".keys(%ImplProblems)."</low>\n";
+            $Problem_Summary .= "  </impl>\n";
+        }
+        $Problem_Summary = "<problem_summary>\n".$Problem_Summary."</problem_summary>\n\n";
+        
+        return ($TestInfo.$TestResults.$Problem_Summary, "");
+    }
+    else
+    { # HTML
+        # test info
+        $TestInfo = "<h2>Test Info</h2><hr/>\n";
+        $TestInfo .= "<table cellpadding='3' cellspacing='0' class='summary'>\n";
+        $TestInfo .= "<tr><th>".ucfirst($TargetComponent)." Name</th><td>$TargetLibraryFName</td></tr>\n";
+        
+        my (@VInf1, @VInf2, $AddTestInfo) = ();
+        if($Arch1 ne "unknown"
+        and $Arch2 ne "unknown")
+        { # CPU arch
+            if($Arch1 eq $Arch2)
+            { # go to the separate section
+                $AddTestInfo .= "<tr><th>CPU Architecture</th><td>".showArch($Arch1)."</td></tr>\n";
+            }
+            else
+            { # go to the version number
+                push(@VInf1, showArch($Arch1));
+                push(@VInf2, showArch($Arch2));
+            }
+        }
+        if($GccV1 ne "unknown"
+        and $GccV2 ne "unknown"
+        and $OStarget ne "windows")
+        { # GCC version
+            if($GccV1 eq $GccV2)
+            { # go to the separate section
+                $AddTestInfo .= "<tr><th>GCC Version</th><td>$GccV1</td></tr>\n";
+            }
+            else
+            { # go to the version number
+                push(@VInf1, "gcc ".$GccV1);
+                push(@VInf2, "gcc ".$GccV2);
+            }
+        }
+        # show long version names with GCC version and CPU architecture name (if different)
+        $TestInfo .= "<tr><th>Version #1</th><td>".$Descriptor{1}{"Version"}.(@VInf1?" (".join(", ", reverse(@VInf1)).")":"")."</td></tr>\n";
+        $TestInfo .= "<tr><th>Version #2</th><td>".$Descriptor{2}{"Version"}.(@VInf2?" (".join(", ", reverse(@VInf2)).")":"")."</td></tr>\n";
+        $TestInfo .= $AddTestInfo;
+        #if($COMMON_LANGUAGE{1}) {
+        #    $TestInfo .= "<tr><th>Language</th><td>".$COMMON_LANGUAGE{1}."</td></tr>\n";
+        #}
+        if($ExtendedCheck) {
+            $TestInfo .= "<tr><th>Mode</th><td>Extended</td></tr>\n";
+        }
+        $TestInfo .= "</table>\n";
+        
+        # test results
+        $TestResults = "<h2>Test Results</h2><hr/>\n";
+        $TestResults .= "<table cellpadding='3' cellspacing='0' class='summary'>";
+        
+        my $Headers_Link = "0";
+        $Headers_Link = "<a href='#Headers' style='color:Blue;'>".keys(%{$Registered_Headers{1}})."</a>" if(keys(%{$Registered_Headers{1}})>0);
+        $TestResults .= "<tr><th>Total Header Files</th><td>".($CheckObjectsOnly?"0&#160;(not&#160;analyzed)":$Headers_Link)."</td></tr>\n";
+        
+        if(not $ExtendedCheck)
+        {
+            my $Libs_Link = "0";
+            $Libs_Link = "<a href='#Libs' style='color:Blue;'>".keys(%{$Library_Symbol{1}})."</a>" if(keys(%{$Library_Symbol{1}})>0);
+            $TestResults .= "<tr><th>Total ".ucfirst($SLIB_TYPE)." Libraries</th><td>".($CheckHeadersOnly?"0&#160;(not&#160;analyzed)":$Libs_Link)."</td></tr>\n";
+        }
+        
+        $TestResults .= "<tr><th>Total Symbols / Types</th><td>".(keys(%CheckedSymbols) - keys(%GeneratedSymbols))." / ".$TotalTypes."</td></tr>\n";
+        
+        my $Verdict = "";
+        if($RESULT{"Problems"}) {
+            $Verdict = "<span style='color:Red;'><b>Incompatible<br/>(".$RESULT{"Affected"}."%)</b></span>";
+        }
+        else {
+            $Verdict = "<span style='color:Green;'><b>Compatible</b></span>";
+        }
+        my $META_DATA = $RESULT{"Problems"}?"verdict:incompatible;":"verdict:compatible;";
+        
+        $TestResults .= "<tr><th>Verdict</th><td>$Verdict</td></tr>";
+        $TestResults .= "</table>\n";
+        
+        $META_DATA .= "affected:".$RESULT{"Affected"}.";";# in percents
+        # problem summary
+        $Problem_Summary = "<h2>Problem Summary</h2><hr/>\n";
+        $Problem_Summary .= "<table cellpadding='3' cellspacing='0' class='summary'>";
+        $Problem_Summary .= "<tr><th></th><th style='text-align:center;'>Severity</th><th style='text-align:center;'>Count</th></tr>";
+        
+        my $Added_Link = "0";
+        $Added_Link = "<a href='#Added' style='color:Blue;'>$Added</a>" if($Added>0);
+        #$Added_Link = "n/a" if($CheckHeadersOnly);
+        $META_DATA .= "added:$Added;";
+        $Problem_Summary .= "<tr><th>Added Symbols</th><td>-</td><td>$Added_Link</td></tr>\n";
+        
+        my $Removed_Link = "0";
+        $Removed_Link = "<a href='#Removed' style='color:Blue;'>$Removed</a>" if($Removed>0);
+        #$Removed_Link = "n/a" if($CheckHeadersOnly);
+        $META_DATA .= "removed:$Removed;";
+        $Problem_Summary .= "<tr><th>Removed Symbols</th><td style='color:Red;'>High</td><td>$Removed_Link</td></tr>\n";
+        
+        my $TH_Link = "0";
+        $TH_Link = "<a href='#Type_Problems_High' style='color:Blue;'>$T_Problems_High</a>" if($T_Problems_High>0);
+        $TH_Link = "n/a" if($CheckObjectsOnly);
+        $META_DATA .= "type_problems_high:$T_Problems_High;";
+        $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Data Types</th><td style='color:Red;'>High</td><td>$TH_Link</td></tr>\n";
+        
+        my $TM_Link = "0";
+        $TM_Link = "<a href='#Type_Problems_Medium' style='color:Blue;'>$T_Problems_Medium</a>" if($T_Problems_Medium>0);
+        $TM_Link = "n/a" if($CheckObjectsOnly);
+        $META_DATA .= "type_problems_medium:$T_Problems_Medium;";
+        $Problem_Summary .= "<tr><td>Medium</td><td>$TM_Link</td></tr>\n";
+        
+        my $TL_Link = "0";
+        $TL_Link = "<a href='#Type_Problems_Low' style='color:Blue;'>$T_Problems_Low</a>" if($T_Problems_Low>0);
+        $TL_Link = "n/a" if($CheckObjectsOnly);
+        $META_DATA .= "type_problems_low:$T_Problems_Low;";
+        $Problem_Summary .= "<tr><td>Low</td><td>$TL_Link</td></tr>\n";
+        
+        my $IH_Link = "0";
+        $IH_Link = "<a href='#Interface_Problems_High' style='color:Blue;'>$I_Problems_High</a>" if($I_Problems_High>0);
+        $IH_Link = "n/a" if($CheckObjectsOnly);
+        $META_DATA .= "interface_problems_high:$I_Problems_High;";
+        $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Symbols</th><td style='color:Red;'>High</td><td>$IH_Link</td></tr>\n";
+        
+        my $IM_Link = "0";
+        $IM_Link = "<a href='#Interface_Problems_Medium' style='color:Blue;'>$I_Problems_Medium</a>" if($I_Problems_Medium>0);
+        $IM_Link = "n/a" if($CheckObjectsOnly);
+        $META_DATA .= "interface_problems_medium:$I_Problems_Medium;";
+        $Problem_Summary .= "<tr><td>Medium</td><td>$IM_Link</td></tr>\n";
+        
+        my $IL_Link = "0";
+        $IL_Link = "<a href='#Interface_Problems_Low' style='color:Blue;'>$I_Problems_Low</a>" if($I_Problems_Low>0);
+        $IL_Link = "n/a" if($CheckObjectsOnly);
+        $META_DATA .= "interface_problems_low:$I_Problems_Low;";
+        $Problem_Summary .= "<tr><td>Low</td><td>$IL_Link</td></tr>\n";
+        
+        my $ChangedConstants_Link = "0";
+        if(keys(%CheckedSymbols) and keys(%ProblemsWithConstants)>0) {
+            $ChangedConstants_Link = "<a href='#Changed_Constants' style='color:Blue;'>".keys(%ProblemsWithConstants)."</a>";
+        }
+        $ChangedConstants_Link = "n/a" if($CheckObjectsOnly);
+        $META_DATA .= "changed_constants:".keys(%ProblemsWithConstants).";";
+        $Problem_Summary .= "<tr><th>Problems with<br/>Constants</th><td>Low</td><td>$ChangedConstants_Link</td></tr>\n";
+        
+        if($CheckImpl)
+        {
+            my $ChangedImpl_Link = "0";
+            $ChangedImpl_Link = "<a href='#Changed_Implementation' style='color:Blue;'>".keys(%ImplProblems)."</a>" if(keys(%ImplProblems)>0);
+            $ChangedImpl_Link = "n/a" if($CheckHeadersOnly);
+            $META_DATA .= "changed_implementation:".keys(%ImplProblems).";";
+            $Problem_Summary .= "<tr><th>Problems with<br/>Implementation</th><td>Low</td><td>$ChangedImpl_Link</td></tr>\n";
+        }
+        # Safe Changes
+        my $TS_Link = "0";
+        if($T_Other) {
+            $TS_Link = "<a href='#Other_Changes_In_Types' style='color:Blue;'>$T_Other</a>";
+        }
+        $TS_Link = "n/a" if($CheckObjectsOnly);
+        $Problem_Summary .= "<tr><th>Other Changes</th><td>-</td><td>$TS_Link</td></tr>\n";
+        
+        $META_DATA .= "tool_version:$TOOL_VERSION";
+        $Problem_Summary .= "</table>\n";
+        return ($TestInfo.$TestResults.$Problem_Summary, $META_DATA);
+    }
+}
+
+sub show_number($)
+{
+    if($_[0]
+    and my $Num = cut_off_number($_[0], 3))
+    {
+        if($Num eq "0") {
+            $Num = cut_off_number($_[0], 7);
+        }
+        if($Num eq "0") {
+            $Num = $_[0];
+        }
+        return $Num;
+    }
+    return $_[0];
+}
+
+sub cut_off_number($$)
+{
+    my ($num, $digs_to_cut) = @_;
+    if($num!~/\./)
+    {
+        $num .= ".";
+        foreach (1 .. $digs_to_cut-1) {
+            $num .= "0";
+        }
+    }
+    elsif($num=~/\.(.+)\Z/ and length($1)<$digs_to_cut-1)
+    {
+        foreach (1 .. $digs_to_cut - 1 - length($1)) {
+            $num .= "0";
+        }
+    }
+    elsif($num=~/\d+\.(\d){$digs_to_cut,}/) {
+      $num=sprintf("%.".($digs_to_cut-1)."f", $num);
+    }
+    $num=~s/\.[0]+\Z//g;
+    return $num;
+}
+
+sub get_Report_ChangedConstants()
+{
+    my ($CHANGED_CONSTANTS, %HeaderConstant) = ();
+    foreach my $Constant (keys(%ProblemsWithConstants)) {
+        $HeaderConstant{$Constants{1}{$Constant}{"Header"}}{$Constant} = 1;
+    }
+    my $Kind = "Changed_Constant";
+    if($ReportFormat eq "xml")
+    { # XML
+        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%HeaderConstant))
+        {
+            $CHANGED_CONSTANTS .= "  <header name=\"$HeaderName\">\n";
+            foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$HeaderConstant{$HeaderName}}))
+            {
+                $CHANGED_CONSTANTS .= "    <constant name=\"$Constant\">\n";
+                my $Change = $CompatRules{"Binary"}{$Kind}{"Change"};
+                my $Effect = $CompatRules{"Binary"}{$Kind}{"Effect"};
+                my $Overcome = $CompatRules{"Binary"}{$Kind}{"Overcome"};
+                $CHANGED_CONSTANTS .= "      <problem id=\"$Kind\">\n";
+                $CHANGED_CONSTANTS .= "        <change".getXmlParams($Change, $ProblemsWithConstants{$Constant}).">$Change</change>\n";
+                $CHANGED_CONSTANTS .= "        <effect".getXmlParams($Effect, $ProblemsWithConstants{$Constant}).">$Effect</effect>\n";
+                $CHANGED_CONSTANTS .= "        <overcome".getXmlParams($Overcome, $ProblemsWithConstants{$Constant}).">$Overcome</overcome>\n";
+                $CHANGED_CONSTANTS .= "      </problem>\n";
+                $CHANGED_CONSTANTS .= "    </constant>\n";
+            }
+            $CHANGED_CONSTANTS .= "    </header>\n";
+        }
+        $CHANGED_CONSTANTS = "<problems_with_constants severity=\"Low\">\n".$CHANGED_CONSTANTS."</problems_with_constants>\n\n";
+    }
+    else
+    { # HTML
+        my $Number = 0;
+        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%HeaderConstant))
+        {
+            $CHANGED_CONSTANTS .= "<span class='h_name'>$HeaderName</span><br/>\n";
+            foreach my $Name (sort {lc($a) cmp lc($b)} keys(%{$HeaderConstant{$HeaderName}}))
+            {
+                $Number += 1;
+                my $Change = applyMacroses("Binary", $Kind, $CompatRules{"Binary"}{$Kind}{"Change"}, $ProblemsWithConstants{$Name});
+                my $Effect = $CompatRules{"Binary"}{$Kind}{"Effect"};
+                my $Report = "<tr><th>1</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>$Effect</td></tr>\n";
+                $Report = $ContentDivStart."<table cellpadding='3' cellspacing='0' class='problems_table'><tr><th width='2%'></th><th width='47%'>Change</th><th>Effect</th></tr>".$Report."</table><br/>$ContentDivEnd\n";
+                $Report = $ContentSpanStart."<span class='extendable'>[+]</span> ".$Name.$ContentSpanEnd."<br/>\n".$Report;
+                $CHANGED_CONSTANTS .= insertIDs($Report);
+            }
+            $CHANGED_CONSTANTS .= "<br/>\n";
+        }
+        if($CHANGED_CONSTANTS) {
+            $CHANGED_CONSTANTS = "<a name='Changed_Constants'></a><h2>Problems with Constants ($Number)</h2><hr/>\n".$CHANGED_CONSTANTS."<a style='font-size:11px;' href='#Top'>to the top</a><br/>\n";
+        }
+    }
+    return $CHANGED_CONSTANTS;
+}
+
+sub get_Report_Impl()
+{
+    my ($CHANGED_IMPLEMENTATION, %HeaderLibFunc);
+    foreach my $Interface (sort keys(%ImplProblems))
+    {
+        my $HeaderName = $CompleteSignature{1}{$Interface}{"Header"};
+        my $DyLib = $Symbol_Library{1}{$Interface};
+        $HeaderLibFunc{$HeaderName}{$DyLib}{$Interface} = 1;
+    }
+    my $Changed_Number = 0;
+    foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%HeaderLibFunc))
+    {
+        foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$HeaderLibFunc{$HeaderName}}))
+        {
+            my $FDyLib=$DyLib.($DyLib!~/\.\w+\Z/?" (.$LIB_EXT)":"");
+            if($HeaderName) {
+                $CHANGED_IMPLEMENTATION .= "<span class='h_name'>$HeaderName</span>, <span class='lib_name'>$FDyLib</span><br/>\n";
+            }
+            else {
+                $CHANGED_IMPLEMENTATION .= "<span class='lib_name'>$DyLib</span><br/>\n";
+            }
+            my %NameSpace_Interface = ();
+            foreach my $Interface (keys(%{$HeaderLibFunc{$HeaderName}{$DyLib}})) {
+                $NameSpace_Interface{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
+            }
+            foreach my $NameSpace (sort keys(%NameSpace_Interface))
+            {
+                $CHANGED_IMPLEMENTATION .= ($NameSpace)?"<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span>"."<br/>\n":"";
+                my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpace_Interface{$NameSpace}});
+                foreach my $Interface (@SortedInterfaces)
+                {
+                    $Changed_Number += 1;
+                    my $Signature = get_Signature($Interface, 1);
+                    if($NameSpace) {
+                        $Signature=~s/(\W|\A)\Q$NameSpace\E\:\:(\w)/$1$2/g;
+                    }
+                    $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");
+                }
+            }
+            $CHANGED_IMPLEMENTATION .= "<br/>\n";
+        }
+    }
+    if($CHANGED_IMPLEMENTATION) {
+        $CHANGED_IMPLEMENTATION = "<a name='Changed_Implementation'></a><h2>Problems with Implementation ($Changed_Number)</h2><hr/>\n".$CHANGED_IMPLEMENTATION."<a style='font-size:11px;' href='#Top'>to the top</a><br/>\n";
+    }
+    return $CHANGED_IMPLEMENTATION;
+}
+
+sub get_Report_Added($)
+{
+    my $Level = $_[0]; # API or ABI
+    
+    my ($ADDED_INTERFACES, %FuncAddedInHeaderLib);
+    foreach my $Interface (sort keys(%CompatProblems))
+    {
+        foreach my $Kind (sort keys(%{$CompatProblems{$Interface}}))
+        {
+            if($Kind eq "Added_Interface")
+            {
+                my $HeaderName = $CompleteSignature{2}{$Interface}{"Header"};
+                my $DyLib = $Symbol_Library{2}{$Interface};
+                $FuncAddedInHeaderLib{$HeaderName}{$DyLib}{$Interface} = 1;
+            }
+        }
+    }
+    if($ReportFormat eq "xml")
+    { # XML
+        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%FuncAddedInHeaderLib))
+        {
+            $ADDED_INTERFACES .= "  <header name=\"$HeaderName\">\n";
+            foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$FuncAddedInHeaderLib{$HeaderName}}))
+            {
+                $ADDED_INTERFACES .= "    <library name=\"$DyLib\">\n";
+                foreach my $Interface (keys(%{$FuncAddedInHeaderLib{$HeaderName}{$DyLib}})) {
+                    $ADDED_INTERFACES .= "      <name>$Interface</name>\n";
+                }
+                $ADDED_INTERFACES .= "    </library>\n";
+            }
+            $ADDED_INTERFACES .= "  </header>\n";
+        }
+        $ADDED_INTERFACES = "<added_symbols>\n".$ADDED_INTERFACES."</added_symbols>\n\n";
+    }
+    else
+    { # HTML
+        my $Added_Number = 0;
+        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%FuncAddedInHeaderLib))
+        {
+            foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$FuncAddedInHeaderLib{$HeaderName}}))
+            {
+                my $FDyLib=$DyLib.($DyLib!~/\.\w+\Z/?" (.$LIB_EXT)":"");
+                if($HeaderName and $DyLib) {
+                    $ADDED_INTERFACES .= "<span class='h_name'>$HeaderName</span>, <span class='lib_name'>$FDyLib</span><br/>\n";
+                }
+                elsif($DyLib) {
+                    $ADDED_INTERFACES .= "<span class='lib_name'>$FDyLib</span><br/>\n";
+                }
+                elsif($HeaderName) {
+                    $ADDED_INTERFACES .= "<span class='h_name'>$HeaderName</span><br/>\n";
+                }
+                my %NameSpace_Interface = ();
+                foreach my $Interface (keys(%{$FuncAddedInHeaderLib{$HeaderName}{$DyLib}})) {
+                    $NameSpace_Interface{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
+                }
+                foreach my $NameSpace (sort keys(%NameSpace_Interface))
+                {
+                    $ADDED_INTERFACES .= ($NameSpace)?"<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span>"."<br/>\n":"";
+                    my @SortedInterfaces = sort {lc(get_Signature($a, 2)) cmp lc(get_Signature($b, 2))} keys(%{$NameSpace_Interface{$NameSpace}});
+                    foreach my $Interface (@SortedInterfaces)
+                    {
+                        $Added_Number += 1;
+                        my $SubReport = "";
+                        my $Signature = get_Signature($Interface, 2);
+                        if($NameSpace) {
+                            $Signature=~s/(\W|\A)\Q$NameSpace\E\:\:(\w)/$1$2/g;
+                        }
+                        if($Interface=~/\A(_Z|\?)/) {
+                            if($Signature) {
+                                $SubReport = insertIDs($ContentSpanStart.highLight_Signature_Italic_Color($Signature).$ContentSpanEnd."<br/>\n".$ContentDivStart."<span class='mangled'>[ symbol: <b>$Interface</b> ]</span><br/><br/>".$ContentDivEnd."\n");
+                            }
+                            else {
+                                $SubReport = "<span class=\"iname\">".$Interface."</span><br/>\n";
+                            }
+                        }
+                        else {
+                            if($Signature) {
+                                $SubReport = "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
+                            }
+                            else {
+                                $SubReport = "<span class=\"iname\">".$Interface."</span><br/>\n";
+                            }
+                        }
+                        $ADDED_INTERFACES .= $SubReport;
+                    }
+                }
+                $ADDED_INTERFACES .= "<br/>\n";
+            }
+        }
+        if($ADDED_INTERFACES) {
+            $ADDED_INTERFACES = "<a name='Added'></a><h2>Added Symbols ($Added_Number)</h2><hr/>\n".$ADDED_INTERFACES."<a style='font-size:11px;' href='#Top'>to the top</a><br/>\n";
+        }
+    }
+    return $ADDED_INTERFACES;
+}
+
+sub get_Report_Removed($)
+{
+    my $Level = $_[0];# API or ABI
+    my (%FuncRemovedFromHeaderLib, $REMOVED_INTERFACES) = ();
+    foreach my $Interface (sort keys(%CompatProblems))
+    {
+        foreach my $Kind (sort keys(%{$CompatProblems{$Interface}}))
+        {
+            if($Kind eq "Removed_Interface")
+            {
+                my $HeaderName = $CompleteSignature{1}{$Interface}{"Header"};
+                my $DyLib = $Symbol_Library{1}{$Interface};
+                $FuncRemovedFromHeaderLib{$HeaderName}{$DyLib}{$Interface} = 1;
+            }
+        }
+    }
+    if($ReportFormat eq "xml")
+    { # XML
+        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%FuncRemovedFromHeaderLib))
+        {
+            $REMOVED_INTERFACES .= "  <header name=\"$HeaderName\">\n";
+            foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$FuncRemovedFromHeaderLib{$HeaderName}}))
+            {
+                $REMOVED_INTERFACES .= "    <library name=\"$DyLib\">\n";
+                foreach my $Interface (keys(%{$FuncRemovedFromHeaderLib{$HeaderName}{$DyLib}})) {
+                    $REMOVED_INTERFACES .= "      <name>$Interface</name>\n";
+                }
+                $REMOVED_INTERFACES .= "    </library>\n";
+            }
+            $REMOVED_INTERFACES .= "  </header>\n";
+        }
+        $REMOVED_INTERFACES = "<removed_symbols>\n".$REMOVED_INTERFACES."</removed_symbols>\n\n";
+    }
+    else
+    { # HTML
+        my $Removed_Number = 0;
+        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%FuncRemovedFromHeaderLib))
+        {
+            foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$FuncRemovedFromHeaderLib{$HeaderName}}))
+            {
+                my $FDyLib=$DyLib.($DyLib!~/\.\w+\Z/?" (.$LIB_EXT)":"");
+                if($HeaderName and $DyLib) {
+                    $REMOVED_INTERFACES .= "<span class='h_name'>$HeaderName</span>, <span class='lib_name'>$FDyLib</span><br/>\n";
+                }
+                elsif($DyLib) {
+                    $REMOVED_INTERFACES .= "<span class='lib_name'>$FDyLib</span><br/>\n";
+                }
+                elsif($HeaderName) {
+                    $REMOVED_INTERFACES .= "<span class='h_name'>$HeaderName</span><br/>\n";
+                }
+                my %NameSpace_Interface = ();
+                foreach my $Interface (keys(%{$FuncRemovedFromHeaderLib{$HeaderName}{$DyLib}}))
+                {
+                    $NameSpace_Interface{get_IntNameSpace($Interface, 1)}{$Interface} = 1;
+                }
+                foreach my $NameSpace (sort keys(%NameSpace_Interface))
+                {
+                    $REMOVED_INTERFACES .= ($NameSpace)?"<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span>"."<br/>\n":"";
+                    my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NameSpace_Interface{$NameSpace}});
+                    foreach my $Interface (@SortedInterfaces)
+                    {
+                        $Removed_Number += 1;
+                        my $SubReport = "";
+                        my $Signature = get_Signature($Interface, 1);
+                        if($NameSpace) {
+                            $Signature=~s/(\W|\A)\Q$NameSpace\E\:\:(\w)/$1$2/g;
+                        }
+                        if($Interface=~/\A(_Z|\?)/) {
+                            if($Signature) {
+                                $SubReport = insertIDs($ContentSpanStart.highLight_Signature_Italic_Color($Signature).$ContentSpanEnd."<br/>\n".$ContentDivStart."<span class='mangled'>[ symbol: <b>$Interface</b> ]</span><br/><br/>".$ContentDivEnd."\n");
+                            }
+                            else {
+                                $SubReport = "<span class=\"iname\">".$Interface."</span><br/>\n";
+                            }
+                        }
+                        else {
+                            if($Signature) {
+                                $SubReport = "<span class=\"iname\">".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
+                            }
+                            else {
+                                $SubReport = "<span class=\"iname\">".$Interface."</span><br/>\n";
+                            }
+                        }
+                        $REMOVED_INTERFACES .= $SubReport;
+                    }
+                }
+                $REMOVED_INTERFACES .= "<br/>\n";
+            }
+        }
+        if($REMOVED_INTERFACES) {
+            $REMOVED_INTERFACES = "<a name='Removed'></a><a name='Withdrawn'></a><h2>Removed Symbols ($Removed_Number)</h2><hr/>\n".$REMOVED_INTERFACES."<a style='font-size:11px;' href='#Top'>to the top</a><br/>\n";
+        }
+    }
+    return $REMOVED_INTERFACES;
+}
+
+sub getXmlParams($$)
+{
+    my ($Content, $Problem) = @_;
+    return "" if(not $Content or not $Problem);
+    my %XMLparams = ();
+    foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
+    {
+        my $Macro = "\@".lc($Attr);
+        if($Content=~/\Q$Macro\E/) {
+            $XMLparams{lc($Attr)} = $Problem->{$Attr};
+        }
+    }
+    my @PString = ();
+    foreach my $P (sort {$b cmp $a} keys(%XMLparams)) {
+        push(@PString, $P."=\"".htmlSpecChars($XMLparams{$P})."\"");
+    }
+    if(@PString) {
+        return " ".join(" ", @PString);
+    }
+    else {
+        return "";
+    }
+}
+
+sub addMarkup($)
+{
+    my $Content = $_[0];
+    # auto-markup
+    $Content=~s/\n[ ]*//; # spaces
+    $Content=~s!(\@\w+\s*\(\@\w+\))!<nowrap>$1</nowrap>!g; # @old_type (@old_size)
+    $Content=~s!(... \(\w+\))!<nowrap><b>$1</b></nowrap>!g; # ... (va_list)
+    $Content=~s!([2-9]\))!<br/>$1!g; # 1), 2), ...
+    if($Content=~/\ANOTE:/)
+    { # notes
+        $Content=~s!(NOTE):!<b>$1</b>:!g;
+    }
+    else {
+        $Content=~s!(NOTE):!<br/><b>$1</b>:!g;
+    }
+    $Content=~s! (out)-! <b>$1</b>-!g; # out-parameters
+    my @Keywords = (
+        "void",
+        "const",
+        "static",
+        "restrict",
+        "volatile",
+        "register",
+        "virtual",
+        "virtually"
+    );
+    my $MKeys = join("|", @Keywords);
+    foreach (@Keywords) {
+        $MKeys .= "|non-".$_;
+    }
+    $Content=~s!(added\s*|to\s*|from\s*|became\s*)($MKeys)([^\w-]|\Z)!$1<b>$2</b>$3!ig; # intrinsic types, modifiers
+    return $Content;
+}
+
+sub applyMacroses($$$$)
+{
+    my ($Level, $Kind, $Content, $Problem) = @_;
+    return "" if(not $Content or not $Problem);
+    $Problem->{"Word_Size"} = $WORD_SIZE{2};
+    $Content = addMarkup($Content);
+    # macros
+    foreach my $Attr (sort {$b cmp $a} keys(%{$Problem}))
+    {
+        my $Macro = "\@".lc($Attr);
+        my $Value = $Problem->{$Attr};
+        if($Value=~/\s\(/)
+        { # functions
+            $Value = black_name($Value);
+        }
+        elsif($Value=~/\s/) {
+            $Value = "<span class='value'>".htmlSpecChars($Value)."</span>";
+        }
+        elsif($Value=~/\A\d+\Z/
+        and ($Attr eq "Old_Size" or $Attr eq "New_Size"))
+        { # bits to bytes
+            if($Value % $BYTE_SIZE)
+            { # bits
+                if($Value==1) {
+                    $Value = "<b>".$Value."</b> bit";
+                }
+                else {
+                    $Value = "<b>".$Value."</b> bits";
+                }
+            }
+            else
+            { # bytes
+                $Value /= $BYTE_SIZE;
+                if($Value==1) {
+                    $Value = "<b>".$Value."</b> byte";
+                }
+                else {
+                    $Value = "<b>".$Value."</b> bytes";
+                }
+            }
+        }
+        else {
+            $Value = "<b>".htmlSpecChars($Value)."</b>";
+        }
+        $Content=~s/\Q$Macro\E/$Value/g;
+    }
+    
+    if($Content=~/(\A|[^\@\w])\@\w/)
+    {
+        if(not $IncompleteRules{$Level}{$Kind})
+        { # only one warning
+            printMsg("WARNING", "incomplete rule \"$Kind\" (\"$Level\")");
+            $IncompleteRules{$Level}{$Kind} = 1;
+        }
+    }
+    $Content=~s!<nowrap>(.+?)</nowrap>!<span class='nowrap'>$1</span>!g;
+    return $Content;
+}
+
+sub get_Report_InterfaceProblems($$)
+{
+    my ($TargetPriority, $Level) = @_;
+    my ($INTERFACE_PROBLEMS, %FuncHeaderLib, %SymbolChanges);
+    foreach my $Interface (sort keys(%CompatProblems))
+    {
+        next if($Interface=~/\A([^\@\$\?]+)[\@\$]+/ and defined $CompatProblems{$1});
+        foreach my $Kind (sort keys(%{$CompatProblems{$Interface}}))
+        {
+            if($CompatRules{$Level}{$Kind}{"Kind"} eq "Symbols"
+            and $Kind ne "Added_Interface" and $Kind ne "Removed_Interface")
+            {
+                my $HeaderName = $CompleteSignature{1}{$Interface}{"Header"};
+                my $DyLib = $Symbol_Library{1}{$Interface};
+                if(not $DyLib and my $VSym = $SymVer{1}{$Interface})
+                { # Symbol with Version
+                    $DyLib = $Symbol_Library{1}{$VSym};
+                }
+                $FuncHeaderLib{$HeaderName}{$DyLib}{$Interface} = 1;
+                %{$SymbolChanges{$Interface}{$Kind}} = %{$CompatProblems{$Interface}{$Kind}};
+                foreach my $Location (sort keys(%{$SymbolChanges{$Interface}{$Kind}}))
+                {
+                    my $Priority = getProblemSeverity($Level, $Kind);
+                    if($Priority ne $TargetPriority) {
+                        delete($SymbolChanges{$Interface}{$Kind}{$Location});
+                    }
+                }
+                if(not keys(%{$SymbolChanges{$Interface}{$Kind}})) {
+                    delete($SymbolChanges{$Interface}{$Kind});
+                }
+                if(not keys(%{$SymbolChanges{$Interface}})) {
+                    delete($SymbolChanges{$Interface});
+                }
+            }
+        }
+    }
+    if($ReportFormat eq "xml")
+    { # XML
+        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%FuncHeaderLib))
+        {
+            $INTERFACE_PROBLEMS .= "  <header name=\"$HeaderName\">\n";
+            foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$FuncHeaderLib{$HeaderName}}))
+            {
+                $INTERFACE_PROBLEMS .= "    <library name=\"$DyLib\">\n";
+                foreach my $Symbol (sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%SymbolChanges))
+                {
+                    $INTERFACE_PROBLEMS .= "      <symbol name=\"$Symbol\">\n";
+                    foreach my $Kind (keys(%{$SymbolChanges{$Symbol}}))
+                    {
+                        foreach my $Location (sort keys(%{$SymbolChanges{$Symbol}{$Kind}}))
+                        {
+                            my %Problem = %{$SymbolChanges{$Symbol}{$Kind}{$Location}};
+                            $Problem{"Param_Pos"} = numToStr($Problem{"Param_Pos"} + 1);
+                            $INTERFACE_PROBLEMS .= "        <problem id=\"$Kind\">\n";
+                            my $Change = $CompatRules{$Level}{$Kind}{"Change"};
+                            $INTERFACE_PROBLEMS .= "          <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
+                            my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
+                            $INTERFACE_PROBLEMS .= "          <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
+                            my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
+                            $INTERFACE_PROBLEMS .= "          <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
+                            $INTERFACE_PROBLEMS .= "        </problem>\n";
+                        }
+                    }
+                    $INTERFACE_PROBLEMS .= "      </symbol>\n";
+                }
+                $INTERFACE_PROBLEMS .= "    </library>\n";
+            }
+            $INTERFACE_PROBLEMS .= "  </header>\n";
+        }
+        $INTERFACE_PROBLEMS = "<problems_with_symbols severity=\"$TargetPriority\">\n".$INTERFACE_PROBLEMS."</problems_with_symbols>\n\n";
+    }
+    else
+    { # HTML
+        my $ProblemsNum = 0;
+        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%FuncHeaderLib))
+        {
+            foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$FuncHeaderLib{$HeaderName}}))
+            {
+                my ($HEADER_LIB_REPORT, %NameSpace_Interface, %NewSignature) = ();
+                foreach my $Interface (keys(%{$FuncHeaderLib{$HeaderName}{$DyLib}})) {
+                    $NameSpace_Interface{get_IntNameSpace($Interface, 1)}{$Interface} = 1;
+                }
+                foreach my $NameSpace (sort keys(%NameSpace_Interface))
+                {
+                    my $NS_REPORT = "";
+                    my @SortedInterfaces = sort {lc($tr_name{$a}) cmp lc($tr_name{$b})} keys(%{$NameSpace_Interface{$NameSpace}});
+                    foreach my $Interface (@SortedInterfaces)
+                    {
+                        my $Signature = get_Signature($Interface, 1);
+                        my $InterfaceProblemsReport = "";
+                        my $ProblemNum = 1;
+                        foreach my $Kind (keys(%{$SymbolChanges{$Interface}}))
+                        {
+                            foreach my $Location (sort keys(%{$SymbolChanges{$Interface}{$Kind}}))
+                            {
+                                my %Problem = %{$SymbolChanges{$Interface}{$Kind}{$Location}};
+                                $Problem{"Param_Pos"} = numToStr($Problem{"Param_Pos"} + 1);
+                                if($Problem{"New_Signature"}) {
+                                    $NewSignature{$Interface} = $Problem{"New_Signature"};
+                                }
+                                if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
+                                {
+                                    my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
+                                    $InterfaceProblemsReport .= "<tr><th>$ProblemNum</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>".$Effect."</td></tr>\n";
+                                    $ProblemNum += 1;
+                                    $ProblemsNum += 1;
+                                }
+                            }
+                        }
+                        $ProblemNum -= 1;
+                        if($InterfaceProblemsReport)
+                        {
+                            if($Signature) {
+                                $NS_REPORT .= $ContentSpanStart."<span class='extendable'>[+]</span> ".highLight_Signature_Italic_Color($Signature)." ($ProblemNum)".$ContentSpanEnd."<br/>\n$ContentDivStart\n";
+                                if($Interface=~/\A(_Z|\?)/
+                                and not $NewSignature{$Interface}) {
+                                    $NS_REPORT .= "<span class='mangled'>&#160;&#160;[ symbol: <b>$Interface</b> ]</span><br/>\n";
+                                }
+                            }
+                            else {
+                                $NS_REPORT .= $ContentSpanStart."<span class='extendable'>[+]</span> ".$Interface." ($ProblemNum)".$ContentSpanEnd."<br/>\n$ContentDivStart\n";
+                            }
+                            if($NewSignature{$Interface}) {# argument list changed to
+                                $NS_REPORT .= "\n<span class='new_signature_label'>changed to:</span><br/><span class='new_signature'>".highLight_Signature_Italic_Color($NewSignature{$Interface})."</span>\n";
+                            }
+                            $NS_REPORT .= "<table cellpadding='3' cellspacing='0' class='problems_table'><tr><th width='2%'></th><th width='47%'>Change</th><th>Effect</th></tr>$InterfaceProblemsReport</table><br/>$ContentDivEnd\n";
+                            $NS_REPORT = insertIDs($NS_REPORT);
+                            if($NameSpace) {
+                                $NS_REPORT=~s/(\W|\A)\Q$NameSpace\E\:\:(\w)/$1$2/g;
+                            }
+                        }
+                    }
+                    if($NS_REPORT) {
+                        $HEADER_LIB_REPORT .= (($NameSpace)?"<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span>"."<br/>\n":"").$NS_REPORT;
+                    }
+                }
+                if($HEADER_LIB_REPORT)
+                {
+                    my $FDyLib=$DyLib.($DyLib!~/\.\w+\Z/?" (.$LIB_EXT)":"");
+                    if($HeaderName and $DyLib) {
+                        $INTERFACE_PROBLEMS .= "<span class='h_name'>$HeaderName</span>, <span class='lib_name'>$FDyLib</span><br/>\n".$HEADER_LIB_REPORT."<br/>";
+                    }
+                    elsif($HeaderName) {
+                        $INTERFACE_PROBLEMS .= "<span class='h_name'>$HeaderName</span><br/>\n".$HEADER_LIB_REPORT."<br/>";
+                    }
+                    elsif($DyLib) {
+                        $INTERFACE_PROBLEMS .= "<span class='lib_name'>$FDyLib</span><br/>\n".$HEADER_LIB_REPORT."<br/>";
+                    }
+                    else {
+                        $INTERFACE_PROBLEMS .= $HEADER_LIB_REPORT."<br/>";
+                    }
+                }
+            }
+        }
+        if($INTERFACE_PROBLEMS)
+        {
+            my $Title = "Problems with Symbols, $TargetPriority Severity";
+            my $Anchor = "Interface_Problems_$TargetPriority";
+            if($TargetPriority eq "Safe")
+            { # Safe Changes
+                $Title = "Other Changes in Symbols";
+                $Anchor = "Other_Changes_In_Symbols";
+            }
+            $INTERFACE_PROBLEMS = "<a name=\'$Anchor\'></a>\n<h2>$Title ($ProblemsNum)</h2><hr/>\n".$INTERFACE_PROBLEMS."<a style='font-size:11px;' href='#Top'>to the top</a><br/>\n";
+        }
+    }
+    return $INTERFACE_PROBLEMS;
+}
+
+sub get_Report_TypeProblems($$)
+{
+    my ($TargetPriority, $Level) = @_;
+    my ($TYPE_PROBLEMS, %TypeHeader, %TypeChanges, %TypeType) = ();
+    foreach my $Interface (sort keys(%CompatProblems))
+    {
+        foreach my $Kind (keys(%{$CompatProblems{$Interface}}))
+        {
+            if($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
+            {
+                foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$CompatProblems{$Interface}{$Kind}}))
+                {
+                    my $TypeName = $CompatProblems{$Interface}{$Kind}{$Location}{"Type_Name"};
+                    my $Target = $CompatProblems{$Interface}{$Kind}{$Location}{"Target"};
+                    my $Priority = getProblemSeverity($Level, $Kind);
+                    if($Priority eq "Safe"
+                    and $TargetPriority ne "Safe") {
+                        next;
+                    }
+                    if(not $TypeType{$TypeName}
+                    or $TypeType{$TypeName} eq "Struct")
+                    { # register type of the type, select "class" if type has "class"- and "struct"-type changes
+                        $TypeType{$TypeName} = $CompatProblems{$Interface}{$Kind}{$Location}{"Type_Type"};
+                    }
+                    if(cmp_priority($Type_MaxPriority{$Level}{$TypeName}{$Kind}{$Target}, $Priority))
+                    { # select a problem with the highest priority
+                        next;
+                    }
+                    %{$TypeChanges{$TypeName}{$Kind}{$Location}} = %{$CompatProblems{$Interface}{$Kind}{$Location}};
+                }
+            }
+        }
+    }
+    my %Kinds_Locations = ();
+    foreach my $TypeName (keys(%TypeChanges))
+    {
+        my %Kinds_Target = ();
+        foreach my $Kind (sort keys(%{$TypeChanges{$TypeName}}))
+        {
+            foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
+            {
+                my $Priority = getProblemSeverity($Level, $Kind);
+                if($Priority ne $TargetPriority)
+                { # other priority
+                    delete($TypeChanges{$TypeName}{$Kind}{$Location});
+                    next;
+                }
+                $Kinds_Locations{$TypeName}{$Kind}{$Location} = 1;
+                my $Target = $TypeChanges{$TypeName}{$Kind}{$Location}{"Target"};
+                if($Kinds_Target{$Kind}{$Target})
+                { # duplicate target
+                    delete($TypeChanges{$TypeName}{$Kind}{$Location});
+                    next;
+                }
+                $Kinds_Target{$Kind}{$Target} = 1;
+                my $HeaderName = get_TypeAttr($TName_Tid{1}{$TypeName}, 1, "Header");
+                $TypeHeader{$HeaderName}{$TypeName} = 1;
+            }
+            if(not keys(%{$TypeChanges{$TypeName}{$Kind}})) {
+                delete($TypeChanges{$TypeName}{$Kind});
+            }
+        }
+    }
+    if($ReportFormat eq "xml")
+    { # XML
+        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%TypeHeader))
+        {
+            $TYPE_PROBLEMS .= "  <header name=\"$HeaderName\">\n";
+            foreach my $TypeName (keys(%{$TypeHeader{$HeaderName}}))
+            {
+                $TYPE_PROBLEMS .= "    <type name=\"".htmlSpecChars($TypeName)."\">\n";
+                foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
+                {
+                    foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
+                    {
+                        my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
+                        $TYPE_PROBLEMS .= "      <problem id=\"$Kind\">\n";
+                        my $Change = $CompatRules{$Level}{$Kind}{"Change"};
+                        $TYPE_PROBLEMS .= "        <change".getXmlParams($Change, \%Problem).">$Change</change>\n";
+                        my $Effect = $CompatRules{$Level}{$Kind}{"Effect"};
+                        $TYPE_PROBLEMS .= "        <effect".getXmlParams($Effect, \%Problem).">$Effect</effect>\n";
+                        my $Overcome = $CompatRules{$Level}{$Kind}{"Overcome"};
+                        $TYPE_PROBLEMS .= "        <overcome".getXmlParams($Overcome, \%Problem).">$Overcome</overcome>\n";
+                        $TYPE_PROBLEMS .= "      </problem>\n";
+                    }
+                }
+                $TYPE_PROBLEMS .= getAffectedInterfaces($Level, $TypeName, $Kinds_Locations{$TypeName});
+                if(grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
+                    $TYPE_PROBLEMS .= showVTables($TypeName);
+                }
+                $TYPE_PROBLEMS .= "    </type>\n";
+            }
+            $TYPE_PROBLEMS .= "  </header>\n";
+        }
+        $TYPE_PROBLEMS = "<problems_with_types severity=\"$TargetPriority\">\n".$TYPE_PROBLEMS."</problems_with_types>\n\n";
+    }
+    else
+    { # HTML
+        my $ProblemsNum = 0;
+        foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%TypeHeader))
+        {
+            my ($HEADER_REPORT, %NameSpace_Type) = ();
+            foreach my $TypeName (keys(%{$TypeHeader{$HeaderName}})) {
+                $NameSpace_Type{parse_TypeNameSpace($TypeName, 1)}{$TypeName} = 1;
+            }
+            foreach my $NameSpace (sort keys(%NameSpace_Type))
+            {
+                my $NS_REPORT = "";
+                my @SortedTypes = sort {lc($TypeType{$a}." ".$a) cmp lc($TypeType{$b}." ".$b)} keys(%{$NameSpace_Type{$NameSpace}});
+                foreach my $TypeName (@SortedTypes)
+                {
+                    my $ProblemNum = 1;
+                    my $TYPE_REPORT = "";
+                    foreach my $Kind (sort {$b=~/Size/ <=> $a=~/Size/} sort keys(%{$TypeChanges{$TypeName}}))
+                    {
+                        foreach my $Location (sort {cmp_locations($b, $a)} sort keys(%{$TypeChanges{$TypeName}{$Kind}}))
+                        {
+                            my %Problem = %{$TypeChanges{$TypeName}{$Kind}{$Location}};
+                            if(my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, \%Problem))
+                            {
+                                my $Effect = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Effect"}, \%Problem);
+                                $TYPE_REPORT .= "<tr><th>$ProblemNum</th><td align='left' valign='top'>".$Change."</td><td align='left' valign='top'>$Effect</td></tr>\n";
+                                $ProblemNum += 1;
+                                $ProblemsNum += 1;
+                            }
+                        }
+                    }
+                    $ProblemNum -= 1;
+                    if($TYPE_REPORT)
+                    {
+                        my $Affected = getAffectedInterfaces($Level, $TypeName, $Kinds_Locations{$TypeName});
+                        my $ShowVTables = "";
+                        if(grep {$_=~/Virtual|Base_Class/} keys(%{$Kinds_Locations{$TypeName}})) {
+                            $ShowVTables = showVTables($TypeName);
+                        }
+                        $NS_REPORT .= $ContentSpanStart."<span class='extendable'>[+]</span> <span class='ttype'>".lc($TypeType{$TypeName})."</span> ".htmlSpecChars($TypeName)." ($ProblemNum)".$ContentSpanEnd;
+                        $NS_REPORT .= "<br/>\n".$ContentDivStart."<table cellpadding='3' cellspacing='0' class='problems_table'><tr>\n";
+                        $NS_REPORT .= "<th width='2%'></th><th width='47%'>Change</th>\n";
+                        $NS_REPORT .= "<th>Effect</th></tr>".$TYPE_REPORT."</table>\n";
+                        $NS_REPORT .= $ShowVTables.$Affected."<br/><br/>".$ContentDivEnd."\n";
+                        $NS_REPORT = insertIDs($NS_REPORT);
+                        if($NameSpace) {
+                            $NS_REPORT=~s/(\W|\A)\Q$NameSpace\E\:\:(\w|\~)/$1$2/g;
+                        }
+                    }
+                }
+                if($NS_REPORT) {
+                    $HEADER_REPORT .= (($NameSpace)?"<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span>"."<br/>\n":"").$NS_REPORT;
+                }
+            }
+            if($HEADER_REPORT) {
+                $TYPE_PROBLEMS .= "<span class='h_name'>$HeaderName</span><br/>\n".$HEADER_REPORT."<br/>";
+            }
+        }
+        if($TYPE_PROBLEMS)
+        {
+            my $Title = "Problems with Data Types, $TargetPriority Severity";
+            my $Anchor = "Type_Problems_$TargetPriority";
+            if($TargetPriority eq "Safe")
+            { # Safe Changes
+                $Title = "Other Changes in Data Types";
+                $Anchor = "Other_Changes_In_Types";
+            }
+            $TYPE_PROBLEMS = "<a name=\'$Anchor\'></a>\n<h2>$Title ($ProblemsNum)</h2><hr/>\n".$TYPE_PROBLEMS."<a style='font-size:11px;' href='#Top'>to the top</a><br/>\n";
+        }
+    }
+    return $TYPE_PROBLEMS;
+}
+
+sub showVTables($)
+{
+    my $TypeName = $_[0];
+    my $TypeId1 = $TName_Tid{1}{$TypeName};
+    my %Type1 = get_Type($Tid_TDid{1}{$TypeId1}, $TypeId1, 1);
+    if(defined $Type1{"VTable"}
+    and keys(%{$Type1{"VTable"}}))
+    {
+        my $TypeId2 = $TName_Tid{2}{$TypeName};
+        my %Type2 = get_Type($Tid_TDid{2}{$TypeId2}, $TypeId2, 2);
+        if(defined $Type2{"VTable"}
+        and keys(%{$Type2{"VTable"}}))
+        {
+            my %Indexes = map {$_=>1} (keys(%{$Type1{"VTable"}}), keys(%{$Type2{"VTable"}}));
+            my %Entries = ();
+            foreach (sort {int($a)<=>int($b)} (keys(%Indexes)))
+            {
+                $Entries{$_}{"E1"} = simpleVEntry($Type1{"VTable"}{$_});
+                $Entries{$_}{"E2"} = simpleVEntry($Type2{"VTable"}{$_});
+            }
+            my $VTABLES = "";
+            if($ReportFormat eq "xml")
+            { # XML
+                $VTABLES .= "      <vtable>\n";
+                foreach (sort {int($a)<=>int($b)} (keys(%Entries)))
+                {
+                    $VTABLES .= "        <entry offset=\"$_\">\n";
+                    $VTABLES .= "          <old>".htmlSpecChars($Entries{$_}{"E1"})."</old>\n";
+                    $VTABLES .= "          <new>".htmlSpecChars($Entries{$_}{"E2"})."</new>\n";
+                    $VTABLES .= "        </entry>\n";
+                }
+                $VTABLES .= "      </vtable>\n\n";
+            }
+            else
+            { # HTML
+                $VTABLES .= "<table cellpadding='3' cellspacing='0' class='virtual_table'>";
+                $VTABLES .= "<tr><th width='2%'>Offset</th>";
+                $VTABLES .= "<th width='45%'>Virtual Table (Old) - ".(keys(%{$Type1{"VTable"}}))." entries</th>";
+                $VTABLES .= "<th>Virtual Table (New) - ".(keys(%{$Type2{"VTable"}}))." entries</th></tr>";
+                foreach (sort {int($a)<=>int($b)} (keys(%Entries)))
+                {
+                    my ($Color1, $Color2) = ("", "");
+                    if($Entries{$_}{"E1"} ne $Entries{$_}{"E2"})
+                    {
+                        if($Entries{$_}{"E1"})
+                        {
+                            $Color1 = " class='vtable_red'";
+                            $Color2 = " class='vtable_red'";
+                        }
+                        else {
+                            $Color2 = " class='vtable_yellow'";
+                        }
+                    }
+                    $VTABLES .= "<tr><th>$_</th>\n";
+                    $VTABLES .= "<td$Color1>".htmlSpecChars($Entries{$_}{"E1"})."</td>\n";
+                    $VTABLES .= "<td$Color2>".htmlSpecChars($Entries{$_}{"E2"})."</td></tr>\n";
+                }
+                $VTABLES .= "</table><br/>\n";
+                $VTABLES = $ContentDivStart.$VTABLES.$ContentDivEnd;
+                $VTABLES = "<span style='padding-left:15px;'>".$ContentSpanStart_Info."[+] show v-table (old and new)".$ContentSpanEnd."</span><br/>\n".$VTABLES;
+            }
+            return $VTABLES;
+        }
+    }
+    return "";
+}
+
+sub simpleVEntry($)
+{
+    my $VEntry = $_[0];
+    $VEntry=~s/\A(.+)::(_ZThn.+)\Z/$2/; # thunks
+    $VEntry=~s/_ZTI\w+/typeinfo/g; # typeinfo
+    if($VEntry=~/\A_ZThn.+\Z/) {
+        $VEntry = "non-virtual thunk";
+    }
+    $VEntry=~s/\A\(int \(\*\)\(...\)\)([^\(\d])/$1/i;
+    # support for old GCC versions
+    $VEntry=~s/\A0u\Z/(int (*)(...))0/;
+    $VEntry=~s/\A4294967268u\Z/(int (*)(...))-0x000000004/;
+    $VEntry=~s/\A&_Z\Z/& _Z/;
+    # templates
+    if($VEntry=~s/ \[with (\w+) = (.+?)(, [^=]+ = .+|])\Z//g)
+    { # std::basic_streambuf<_CharT, _Traits>::imbue [with _CharT = char, _Traits = std::char_traits<char>]
+      # become std::basic_streambuf<char, ...>::imbue
+        my ($Pname, $Pval) = ($1, $2);
+        if($Pname eq "_CharT" and $VEntry=~/\Astd::/)
+        { # stdc++ typedefs
+            $VEntry=~s/<$Pname(, [^<>]+|)>/<$Pval>/g;
+            # FIXME: simplify names using stdcxx typedefs (StdCxxTypedef)
+            # The typedef info should be added to ABI dumps
+        }
+        else
+        {
+            $VEntry=~s/<$Pname>/<$Pval>/g;
+            $VEntry=~s/<$Pname, [^<>]+>/<$Pval, ...>/g;
+        }
+    }
+    $VEntry=~s/([^:]+)::\~([^:]+)\Z/~$1/; # destructors
+    return $VEntry;
+}
+
+sub getAffectedInterfaces($$$)
+{
+    my ($Level, $Target_TypeName, $Kinds_Locations) = @_;
+    my (%INumber, %IProblems) = ();
+    my $LIMIT = 1000;
+    foreach my $Interface (sort {lc($tr_name{$a}?$tr_name{$a}:$a) cmp lc($tr_name{$b}?$tr_name{$b}:$b)} keys(%CompatProblems))
+    {
+        last if(keys(%INumber)>$LIMIT);
+        if(($Interface=~/C2E|D2E|D0E/))
+        { # duplicated problems for C2 constructors, D2 and D0 destructors
+            next;
+        }
+        my ($MinPath_Length, $ProblemLocation_Last) = ();
+        my $MaxPriority = 0;
+        my $Signature = get_Signature($Interface, 1);
+        foreach my $Kind (keys(%{$CompatProblems{$Interface}}))
+        {
+            foreach my $Location (keys(%{$CompatProblems{$Interface}{$Kind}}))
+            {
+                if(not defined $Kinds_Locations->{$Kind}
+                or not $Kinds_Locations->{$Kind}{$Location}) {
+                    next;
+                }
+                if($Interface=~/\A([^\@\$\?]+)[\@\$]+/ and defined $CompatProblems{$1}
+                and defined $CompatProblems{$1}{$Kind}{$Location})
+                { # duplicated problems for versioned symbols
+                    next;
+                }
+                my $Type_Name = $CompatProblems{$Interface}{$Kind}{$Location}{"Type_Name"};
+                next if($Type_Name ne $Target_TypeName);
+                
+                my $Position = $CompatProblems{$Interface}{$Kind}{$Location}{"Param_Pos"};
+                my $Param_Name = $CompatProblems{$Interface}{$Kind}{$Location}{"Param_Name"};
+                my $Priority = $CompatProblems{$Interface}{$Kind}{$Location}{"Priority"};
+                $INumber{$Interface} = 1;
+                my $Path_Length = 0;
+                my $ProblemLocation = $Location;
+                if($Type_Name) {
+                    $ProblemLocation=~s/->\Q$Type_Name\E\Z//g;
+                }
+                while($ProblemLocation=~/\-\>/g){$Path_Length += 1;}
+                if($MinPath_Length eq "" or ($Path_Length<=$MinPath_Length and $Priority_Value{$Priority}>$MaxPriority)
+                or (cmp_locations($ProblemLocation, $ProblemLocation_Last) and $Priority_Value{$Priority}==$MaxPriority))
+                {
+                    $MinPath_Length = $Path_Length;
+                    $MaxPriority = $Priority_Value{$Priority};
+                    $ProblemLocation_Last = $ProblemLocation;
+                    %{$IProblems{$Interface}} = (
+                        "Description"=>getAffectDescription($Level, $Interface, $Kind, $Location),
+                        "Priority"=>$MaxPriority,
+                        "Signature"=>$Signature,
+                        "Position"=>$Position,
+                        "Param_Name"=>$Param_Name,
+                        "Location"=>$Location
+                    );
+                }
+            }
+        }
+    }
+    my @Interfaces = keys(%IProblems);
+    @Interfaces = sort {lc($tr_name{$a}?$tr_name{$a}:$a) cmp lc($tr_name{$b}?$tr_name{$b}:$b)} @Interfaces;
+    @Interfaces = sort {$IProblems{$b}{"Priority"}<=>$IProblems{$a}{"Priority"}} @Interfaces;
+    my $Affected = "";
+    if($ReportFormat eq "xml")
+    { # XML
+        $Affected .= "      <affected>\n";
+        foreach my $Interface (@Interfaces)
+        {
+            my $Param_Name = $IProblems{$Interface}{"Param_Name"};
+            my $Description = $IProblems{$Interface}{"Description"};
+            my $Location = $IProblems{$Interface}{"Location"};
+            my $Target = "";
+            if($Param_Name) {
+                $Target = " affected=\"param\" param_name=\"$Param_Name\"";
+            }
+            elsif($Location=~/\Aretval(\-|\Z)/i) {
+                $Target = " affected=\"retval\"";
+            }
+            elsif($Location=~/\Athis(\-|\Z)/i) {
+                $Target = " affected=\"this\"";
+            }
+            $Affected .= "        <symbol$Target name=\"$Interface\">\n";
+            $Affected .= "          <comment>".htmlSpecChars($Description)."</comment>\n";
+            $Affected .= "        </symbol>\n";
+        }
+        $Affected .= "      </affected>\n";
+    }
+    else
+    { # HTML
+        foreach my $Interface (@Interfaces)
+        {
+            my $Description = $IProblems{$Interface}{"Description"};
+            my $Signature = $IProblems{$Interface}{"Signature"};
+            my $Pos = $IProblems{$Interface}{"Position"};
+            $Affected .= "<span class='iname_b'>".highLight_Signature_PPos_Italic($Signature, $Pos, 1, 0, 0)."</span><br/>"."<div class='affect'>".htmlSpecChars($Description)."</div>\n";
+        }
+        $Affected = "<div class='affected'>".$Affected."</div>";
+        if(keys(%INumber)>$LIMIT) {
+            $Affected .= "and others ...<br/>";
+        }
+        if($Affected)
+        {
+            $Affected = $ContentDivStart.$Affected.$ContentDivEnd;
+            my $AHeader = $ContentSpanStart_Affected."[+] affected symbols (".(keys(%INumber)>$LIMIT?"more than $LIMIT":keys(%INumber)).")".$ContentSpanEnd;
+            $AHeader = "<span style='padding-left:15px'>".$AHeader."</span>";
+            $Affected = $AHeader.$Affected;
+        }
+    }
+    return $Affected;
+}
+
+sub cmp_locations($$)
+{
+    my ($Location1, $Location2) = @_;
+    if($Location2=~/(\A|\W)(retval|this)(\W|\Z)/
+    and $Location1!~/(\A|\W)(retval|this)(\W|\Z)/ and $Location1!~/\-\>/) {
+        return 1;
+    }
+    if($Location2=~/(\A|\W)(retval|this)(\W|\Z)/ and $Location2=~/\-\>/
+    and $Location1!~/(\A|\W)(retval|this)(\W|\Z)/ and $Location1=~/\-\>/) {
+        return 1;
+    }
+    return 0;
+}
+
+sub getAffectDescription($$$$)
+{
+    my ($Level, $Interface, $Kind, $Location) = @_;
+    my %Problem = %{$CompatProblems{$Interface}{$Kind}{$Location}};
+    my $PPos = numToStr($Problem{"Param_Pos"} + 1);
+    my @Sentence = ();
+    $Location=~s/\A(.*)\-\>.+?\Z/$1/;
+    if($Kind eq "Overridden_Virtual_Method"
+    or $Kind eq "Overridden_Virtual_Method_B") {
+        push(@Sentence, "The method '".$Problem{"New_Value"}."' will be called instead of this method.");
+    }
+    elsif($CompatRules{$Level}{$Kind}{"Kind"} eq "Types")
+    {
+        if($Location eq "this" or $Kind=~/(\A|_)Virtual(_|\Z)/)
+        {
+            my $METHOD_TYPE = $CompleteSignature{1}{$Interface}{"Constructor"}?"constructor":"method";
+            my $ClassName = get_TypeName($CompleteSignature{1}{$Interface}{"Class"}, 1);
+            if($ClassName eq $Problem{"Type_Name"}) {
+                push(@Sentence, "This $METHOD_TYPE is from \'".$Problem{"Type_Name"}."\' class.");
+            }
+            else {
+                push(@Sentence, "This $METHOD_TYPE is from derived class \'".$ClassName."\'.");
+            }
+        }
+        else
+        {
+            if($Location=~/retval/)
+            { # return value
+                if($Location=~/\-\>/) {
+                    push(@Sentence, "Field \'".$Location."\' in return value");
+                }
+                else {
+                    push(@Sentence, "Return value");
+                }
+                if($Problem{"InitialType_Type"} eq "Pointer") {
+                    push(@Sentence, "(pointer)");
+                }
+                elsif($Problem{"InitialType_Type"} eq "Ref") {
+                    push(@Sentence, "(reference)");
+                }
+            }
+            elsif($Location=~/this/)
+            { # "this" pointer
+                if($Location=~/\-\>/) {
+                    push(@Sentence, "Field \'".$Location."\' in the object of this method");
+                }
+                else {
+                    push(@Sentence, "\'this\' pointer");
+                }
+            }
+            else
+            { # parameters
+                if($Location=~/\-\>/) {
+                    push(@Sentence, "Field \'".$Location."\' in $PPos parameter");
+                }
+                else {
+                    push(@Sentence, "$PPos parameter");
+                }
+                if($Problem{"Param_Name"}) {
+                    push(@Sentence, "\'".$Problem{"Param_Name"}."\'");
+                }
+                if($Problem{"InitialType_Type"} eq "Pointer") {
+                    push(@Sentence, "(pointer)");
+                }
+                elsif($Problem{"InitialType_Type"} eq "Ref") {
+                    push(@Sentence, "(reference)");
+                }
+            }
+            if($Location eq "this") {
+                push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
+            }
+            elsif($Problem{"Start_Type_Name"} eq $Problem{"Type_Name"}) {
+                push(@Sentence, "has type \'".$Problem{"Type_Name"}."\'.");
+            }
+            else {
+                push(@Sentence, "has base type \'".$Problem{"Type_Name"}."\'.");
+            }
+        }
+    }
+    if($ExtendedFuncs{$Interface}) {
+        push(@Sentence, " This is a symbol from an artificial external library that may use the \'$TargetLibraryName\' library and change its ABI after recompiling.");
+    }
+    return join(" ", @Sentence);
+}
+
+sub get_XmlSign($$)
+{
+    my ($Symbol, $LibVersion) = @_;
+    my $Info = $CompleteSignature{$LibVersion}{$Symbol};
+    my $Report = "";
+    foreach my $Pos (sort {int($a)<=>int($b)} keys(%{$Info->{"Param"}}))
+    {
+        my $Name = $Info->{"Param"}{$Pos}{"name"};
+        my $TypeName = get_TypeName($Info->{"Param"}{$Pos}{"type"}, $LibVersion);
+        foreach my $Typedef (keys(%ChangedTypedef))
+        {
+            my $Base = $Typedef_BaseName{$LibVersion}{$Typedef};
+            $TypeName=~s/(\A|\W)\Q$Typedef\E(\W|\Z)/$1$Base$2/g;
+        }
+        $Report .= "    <param pos=\"$Pos\">\n";
+        $Report .= "      <name>".$Name."</name>\n";
+        $Report .= "      <type>".htmlSpecChars($TypeName)."</type>\n";
+        $Report .= "    </param>\n";
+    }
+    if(my $Return = $Info->{"Return"})
+    {
+        my $RTName = get_TypeName($Return, $LibVersion);
+        $Report .= "    <retval>\n";
+        $Report .= "      <type>".htmlSpecChars($RTName)."</type>\n";
+        $Report .= "    </retval>\n";
+    }
+    return $Report;
+}
+
+sub get_Report_SymbolsInfo()
+{
+    my $Report = "<symbols_info>\n";
+    foreach my $Symbol (sort keys(%CompatProblems))
+    {
+        if($Symbol=~/\A([^\@\$\?]+)[\@\$]+/
+        and defined $CompatProblems{$1}) {
+            next;
+        }
+        $Report .= "  <symbol name=\"$Symbol\">\n";
+        my ($S1, $P1, $S2, $P2) = ();
+        if(not $AddedInt{$Symbol})
+        {
+            if(defined $CompleteSignature{1}{$Symbol}
+            and defined $CompleteSignature{1}{$Symbol}{"Header"})
+            {
+                $P1 = get_XmlSign($Symbol, 1);
+                $S1 = get_Signature($Symbol, 1);
+            }
+            elsif($Symbol=~/\A(_Z|\?)/) {
+                $S1 = $tr_name{$Symbol};
+            }
+        }
+        if(not $RemovedInt{$Symbol})
+        {
+            if(defined $CompleteSignature{2}{$Symbol}
+            and defined $CompleteSignature{2}{$Symbol}{"Header"})
+            {
+                $P2 = get_XmlSign($Symbol, 2);
+                $S2 = get_Signature($Symbol, 2);
+            }
+            elsif($Symbol=~/\A(_Z|\?)/) {
+                $S2 = $tr_name{$Symbol};
+            }
+        }
+        if($S1)
+        {
+            $Report .= "    <old signature=\"".htmlSpecChars($S1)."\">\n";
+            $Report .= $P1;
+            $Report .= "    </old>\n";
+        }
+        if($S2 and $S2 ne $S1)
+        {
+            $Report .= "    <new signature=\"".htmlSpecChars($S2)."\">\n";
+            $Report .= $P2;
+            $Report .= "    </new>\n";
+        }
+        $Report .= "  </symbol>\n";
+    }
+    $Report .= "</symbols_info>\n";
+    return $Report;
+}
+
+sub createHtmlReport($)
+{
+    my $Path = $_[0];
+    my $Report = "";
+    if($ReportFormat eq "xml")
+    { # XML
+        $Report .= "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
+        $Report .= "<report version=\"$XML_REPORT_VERSION\">\n\n";
+        my ($Summary, $MetaData) = get_Summary("Binary");
+        $Report .= $Summary."\n";
+        $Report .= get_Report_Added("Binary").get_Report_Removed("Binary");
+        $Report .= get_Report_Problems("High", "Binary").get_Report_Problems("Medium", "Binary").get_Report_Problems("Low", "Binary").get_Report_Problems("Safe", "Binary");
+        $Report .= get_Report_SymbolsInfo();
+        $Report .= "</report>\n";
+    }
+    else
+    { # HTML
+        my $CssStyles = readStyles("CompatReport.css");
+        my ($Summary, $MetaData) = get_Summary("Binary");
+        my $Title = "$TargetLibraryFName: ".$Descriptor{1}{"Version"}." to ".$Descriptor{2}{"Version"}." binary compatibility report";
+        my $Keywords = "$TargetLibraryFName, binary compatibility, API, report";
+        my $Description = "Binary compatibility report for the $TargetLibraryFName $TargetComponent between ".$Descriptor{1}{"Version"}." and ".$Descriptor{2}{"Version"}." versions";
+        if(getArch(1) eq getArch(2)
+        and getArch(1) ne "unknown") {
+            $Description .= " on ".showArch(getArch(1));
+        }
+        $Report .= "<!-\- $MetaData -\->\n".composeHTML_Head($Title, $Keywords, $Description, $CssStyles."\n".$JScripts)."\n<body>\n<div><a name='Top'></a>\n";
+        $Report .= get_Report_Header()."\n".$Summary."\n";
+        $Report .= get_Report_Added("Binary").get_Report_Removed("Binary");
+        $Report .= get_Report_Problems("High", "Binary").get_Report_Problems("Medium", "Binary").get_Report_Problems("Low", "Binary").get_Report_Problems("Safe", "Binary");
+        $Report .= get_SourceInfo();
+        $Report .= "</div>\n<br/><br/><br/><hr/>\n";
+        $Report .= getReportFooter($TargetLibraryFName);
+        $Report .= "\n<div style='height:999px;'></div>\n</body></html>";
+    }
+    if($StdOut)
+    { # --stdout option
+        print STDOUT $Report;
+    }
+    else {
+        writeFile($Path, $Report);
+    }
+}
+
+sub getReportFooter($)
+{
+    my $LibName = $_[0];
+    my $Footer = "<div style='width:100%;font-size:11px;' align='right'><i>Generated on ".(localtime time); # report date
+    $Footer .= " for <span style='font-weight:bold'>$LibName</span>"; # tested library/system name
+    $Footer .= " by <a href='".$HomePage{"Dev"}."'>ABI Compliance Checker</a>"; # tool name
+    my $ToolSummary = "<br/>A tool for checking backward binary compatibility of a shared C/C++ library API&#160;&#160;";
+    $Footer .= " $TOOL_VERSION &#160;$ToolSummary</i></div>"; # tool version
+    return $Footer;
+}
+
+sub get_Report_Problems($$)
+{
+    my ($Priority, $Level) = @_;
+    my $Report = get_Report_TypeProblems($Priority, $Level).get_Report_InterfaceProblems($Priority, $Level);
+    if($Priority eq "Low")
+    {
+        $Report .= get_Report_ChangedConstants();
+        if($ReportFormat eq "html") {
+            if($CheckImpl and $Level eq "Binary") {
+                $Report .= get_Report_Impl();
+            }
+        }
+    }
+    if($ReportFormat eq "html")
+    {
+        if($Report)
+        { # add anchor
+            if($Priority eq "Safe") {
+                $Report = "<a name=\'Other_Changes\'></a>".$Report;
+            }
+            else {
+                $Report = "<a name=\'".$Priority."_Risk_Problems\'></a>".$Report;
+            }
+        }
+    }
+    return $Report;
+}
+
+sub composeHTML_Head($$$$)
+{
+    my ($Title, $Keywords, $Description, $OtherInHead) = @_;
+    return "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n<head>
+    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />
+    <meta name=\"keywords\" content=\"$Keywords\" />
+    <meta name=\"description\" content=\"$Description\" />
+    <title>\n        $Title\n    </title>\n$OtherInHead\n</head>";
+}
+
+sub insertIDs($)
+{
+    my $Text = $_[0];
+    while($Text=~/CONTENT_ID/)
+    {
+        if(int($Content_Counter)%2) {
+            $ContentID -= 1;
+        }
+        $Text=~s/CONTENT_ID/c_$ContentID/;
+        $ContentID += 1;
+        $Content_Counter += 1;
+    }
+    return $Text;
+}
+
+sub checkPreprocessedUnit($)
+{
+    my $Path = $_[0];
+    my $CurHeader = "";
+    open(PREPROC, "$Path") || die ("can't open file \'$Path\': $!\n");
+    while(<PREPROC>)
+    {# detecting public and private constants
+        next if(not /\A#/);
+        chomp($_);
+        if(/#[ \t]+\d+[ \t]+\"(.+)\"/) {
+            $CurHeader=path_format($1, $OSgroup);
+        }
+        if(not $Include_Neighbors{$Version}{get_filename($CurHeader)}
+        and not $Registered_Headers{$Version}{$CurHeader})
+        { # not a target
+            next;
+        }
+        if(not is_target_header(get_filename($CurHeader)))
+        { # user-defined header
+            next;
+        }
+        if(/\#[ \t]*define[ \t]+([_A-Z0-9]+)[ \t]+(.+)[ \t]*\Z/)
+        {
+            my ($Name, $Value) = ($1, $2);
+            if(not $Constants{$Version}{$Name}{"Access"})
+            {
+                $Constants{$Version}{$Name}{"Access"} = "public";
+                $Constants{$Version}{$Name}{"Value"} = $Value;
+                $Constants{$Version}{$Name}{"Header"} = get_filename($CurHeader);
+            }
+        }
+        elsif(/\#[ \t]*undef[ \t]+([_A-Z]+)[ \t]*/) {
+            $Constants{$Version}{$1}{"Access"} = "private";
+        }
+    }
+    close(PREPROC);
+    foreach my $Constant (keys(%{$Constants{$Version}}))
+    {
+        if($Constants{$Version}{$Constant}{"Access"} eq "private" or $Constant=~/_h\Z/i
+        or isBuiltIn($Constants{$Version}{$Constant}{"Header"}))
+        { # skip private constants
+            delete($Constants{$Version}{$Constant});
+        }
+        else {
+            delete($Constants{$Version}{$Constant}{"Access"});
+        }
+    }
+}
+
+my %IgnoreConstant=(
+    "VERSION"=>1,
+    "VERSIONCODE"=>1,
+    "VERNUM"=>1,
+    "VERS_INFO"=>1,
+    "PATCHLEVEL"=>1,
+    "INSTALLPREFIX"=>1,
+    "VBUILD"=>1,
+    "VPATCH"=>1,
+    "VMINOR"=>1,
+    "BUILD_STRING"=>1,
+    "BUILD_TIME"=>1,
+    "PACKAGE_STRING"=>1,
+    "PRODUCTION"=>1,
+    "CONFIGURE_COMMAND"=>1,
+    "INSTALLDIR"=>1,
+    "BINDIR"=>1,
+    "CONFIG_FILE_PATH"=>1,
+    "DATADIR"=>1,
+    "EXTENSION_DIR"=>1,
+    "INCLUDE_PATH"=>1,
+    "LIBDIR"=>1,
+    "LOCALSTATEDIR"=>1,
+    "SBINDIR"=>1,
+    "SYSCONFDIR"=>1,
+    "RELEASE"=>1,
+    "SOURCE_ID"=>1,
+    "SUBMINOR"=>1,
+    "MINOR"=>1,
+    "MINNOR"=>1,
+    "MINORVERSION"=>1,
+    "MAJOR"=>1,
+    "MAJORVERSION"=>1,
+    "MICRO"=>1,
+    "MICROVERSION"=>1,
+    "BINARY_AGE"=>1,
+    "INTERFACE_AGE"=>1,
+    "CORE_ABI"=>1,
+    "PATCH"=>1,
+    "COPYRIGHT"=>1,
+    "TIMESTAMP"=>1,
+    "REVISION"=>1,
+    "PACKAGE_TAG"=>1,
+    "PACKAGEDATE"=>1,
+    "NUMVERSION"=>1
+);
+
+sub mergeConstants()
+{
+    foreach my $Constant (keys(%{$Constants{1}}))
+    {
+        if($SkipConstants{1}{$Constant})
+        { # skipped by the user
+            next;
+        }
+        if($Constants{2}{$Constant}{"Value"} eq "")
+        { # empty value
+            next;
+        }
+        if(not is_target_header($Constants{1}{$Constant}{"Header"}))
+        { # user-defined header
+            next;
+        }
+        my ($Old_Value, $New_Value, $Old_Value_Pure, $New_Value_Pure);
+        $Old_Value = $Old_Value_Pure = uncover_constant(1, $Constant);
+        $New_Value = $New_Value_Pure = uncover_constant(2, $Constant);
+        $Old_Value_Pure=~s/(\W)\s+/$1/g;
+        $Old_Value_Pure=~s/\s+(\W)/$1/g;
+        $New_Value_Pure=~s/(\W)\s+/$1/g;
+        $New_Value_Pure=~s/\s+(\W)/$1/g;
+        next if($New_Value_Pure eq "" or $Old_Value_Pure eq "");
+        if($New_Value_Pure ne $Old_Value_Pure)
+        { # different values
+            if(grep {$Constant=~/(\A|_)$_(_|\Z)/} keys(%IgnoreConstant))
+            { # ignore library version
+                next;
+            }
+            if($Constant=~/(\A|_)(lib|open|)$TargetLibraryShortName(_|)(VERSION|VER|DATE|API|PREFIX)(_|\Z)/i)
+            { # ignore library version
+                next;
+            }
+            if($Old_Value=~/\A('|"|)[\/\\]\w+([\/\\]|:|('|"|)\Z)/ or $Old_Value=~/[\/\\]\w+[\/\\]\w+/)
+            { # ignoring path defines:
+              #  /lib64:/usr/lib64:/lib:/usr/lib:/usr/X11R6/lib/Xaw3d ...
+                next;
+            }
+            if($Old_Value=~/\A\(*[a-z_]+(\s+|\|)/i)
+            { # ignore source defines:
+              #  static int gcry_pth_init ( void) { return ...
+              #  (RE_BACKSLASH_ESCAPE_IN_LISTS | RE...
+                next;
+            }
+            if(convert_integer($Old_Value) eq convert_integer($New_Value))
+            { # 0x0001 and 0x1, 0x1 and 1 equal constants
+                next;
+            }
+            if($Old_Value eq "0" and $New_Value eq "NULL")
+            { # 0 => NULL
+                next;
+            }
+            if($Old_Value eq "NULL" and $New_Value eq "0")
+            { # NULL => 0
+                next;
+            }
+            %{$ProblemsWithConstants{$Constant}} = (
+                "Target"=>$Constant,
+                "Old_Value"=>$Old_Value,
+                "New_Value"=>$New_Value  );
+        }
+    }
+}
+
+sub convert_integer($)
+{
+    my $Value = $_[0];
+    if($Value=~/\A0x[a-f0-9]+\Z/)
+    {# hexadecimal
+        return hex($Value);
+    }
+    elsif($Value=~/\A0[0-7]+\Z/)
+    {# octal
+        return oct($Value);
+    }
+    elsif($Value=~/\A0b[0-1]+\Z/)
+    {# binary
+        return oct($Value);
+    }
+    else {
+        return $Value;
+    }
+}
+
+sub uncover_constant($$)
+{
+    my ($LibVersion, $Constant) = @_;
+    return "" if(not $LibVersion or not $Constant);
+    return $Constant if(isCyclical(\@RecurConstant, $Constant));
+    if($Cache{"uncover_constant"}{$LibVersion}{$Constant} ne "") {
+        return $Cache{"uncover_constant"}{$LibVersion}{$Constant};
+    }
+    my $Value = $Constants{$LibVersion}{$Constant}{"Value"};
+    if($Value=~/\A[A-Z0-9_]+\Z/ and $Value=~/[A-Z]/)
+    {
+        push(@RecurConstant, $Constant);
+        if((my $Uncovered = uncover_constant($LibVersion, $Value)) ne "") {
+            $Value = $Uncovered;
+        }
+        pop(@RecurConstant);
+    }
+    # FIXME: uncover $Value using all the enum constants
+    # USECASE: change of define NC_LONG from NC_INT (enum value) to NC_INT (define)
+    $Cache{"uncover_constant"}{$LibVersion}{$Constant} = $Value;
+    return $Value;
+}
+
+sub getSymbols($)
+{
+    my $LibVersion = $_[0];
+    my @DyLibPaths = getSoPaths($LibVersion);
+    if($#DyLibPaths==-1 and not $CheckHeadersOnly)
+    {
+        if($LibVersion==1)
+        {
+            printMsg("WARNING", "checking headers only");
+            $CheckHeadersOnly = 1;
+        }
+        else {
+            exitStatus("Error", "$SLIB_TYPE libraries are not found in ".$Descriptor{$LibVersion}{"Version"});
+        }
+    }
+    my %GroupNames = map {parse_libname(get_filename($_), "name+ext", $OStarget)=>1} @DyLibPaths;
+    foreach my $DyLibPath (sort {length($a)<=>length($b)} @DyLibPaths) {
+        getSymbols_Lib($LibVersion, $DyLibPath, 0, \%GroupNames, "+Weak");
+    }
+}
+
+sub get_VTableSymbolSize($$)
+{
+    my ($ClassName, $LibVersion) = @_;
+    return 0 if(not $ClassName);
+    my $Symbol = $ClassVTable{$LibVersion}{$ClassName};
+    if(defined $Symbol_Library{$LibVersion}{$Symbol}
+    and my $DyLib = $Symbol_Library{$LibVersion}{$Symbol})
+    { # bind class name and v-table size
+        if(defined $Library_Symbol{$LibVersion}{$DyLib}{$Symbol}
+        and my $Size = -$Library_Symbol{$LibVersion}{$DyLib}{$Symbol})
+        { # size from the shared library
+            if($Size>=12) {
+#               0     (int (*)(...))0
+#               4     (int (*)(...))(& _ZTIN7mysqlpp8DateTimeE)
+#               8     mysqlpp::DateTime::~DateTime
+                return $Size;
+            }
+            else {
+                return 0;
+            }
+        }
+    }
+}
+
+sub canonifyName($)
+{ # make TIFFStreamOpen(char const*, std::basic_ostream<char, std::char_traits<char> >*)
+  # to be TIFFStreamOpen(char const*, std::basic_ostream<char>*)
+    my $Name = $_[0];
+    my $Rem = "std::(allocator|less|char_traits|regex_traits)";
+    if($Name=~/([^<>,]+),\s*$Rem<([^<>,]+)>\s*/)
+    {
+        if($1 eq $3)
+        {
+            my $P = $1;
+            while($Name=~s/\Q$P\E,\s*$Rem<\Q$P\E>\s*/$P/g){};
+        }
+    }
+    return $Name;
+}
+
+sub translateSymbols(@_$)
+{
+    my $LibVersion = pop(@_);
+    my (@MnglNames1, @MnglNames2, @UnMnglNames) = ();
+    foreach my $Interface (sort @_)
+    {
+        if($Interface=~/\A_Z/)
+        {
+            next if($tr_name{$Interface});
+            $Interface=~s/[\@\$]+(.*)\Z//;
+            push(@MnglNames1, $Interface);
+        }
+        elsif($Interface=~/\A\?/) {
+            push(@MnglNames2, $Interface);
+        }
+        else
+        { # not mangled
+            $tr_name{$Interface} = $Interface;
+            $mangled_name_gcc{$Interface} = $Interface;
+            $mangled_name{$LibVersion}{$Interface} = $Interface;
+        }
+    }
+    if($#MnglNames1 > -1)
+    { # GCC names
+        @UnMnglNames = reverse(unmangleArray(@MnglNames1));
+        foreach my $MnglName (@MnglNames1)
+        {
+            my $Unmangled = $tr_name{$MnglName} = formatName(canonifyName(pop(@UnMnglNames)));
+            if(not $mangled_name_gcc{$Unmangled}) {
+                $mangled_name_gcc{$Unmangled} = $MnglName;
+            }
+            if($MnglName=~/\A_ZTV/ and $Unmangled=~/vtable for (.+)/)
+            { # bind class name and v-table symbol
+                $ClassVTable{$LibVersion}{$1} = $MnglName;
+                $VTableClass{$LibVersion}{$MnglName} = $1;
+            }
+        }
+    }
+    if($#MnglNames2 > -1)
+    { # MSVC names
+        @UnMnglNames = reverse(unmangleArray(@MnglNames2));
+        foreach my $MnglName (@MnglNames2)
+        {
+            $tr_name{$MnglName} = formatName(pop(@UnMnglNames));
+            $mangled_name{$LibVersion}{$tr_name{$MnglName}} = $MnglName;
+        }
+    }
+    return \%tr_name;
+}
+
+sub link_symbol($$$)
+{
+    my ($Symbol, $RunWith, $Deps) = @_;
+    if(link_symbol_internal($Symbol, $RunWith, \%Symbol_Library)) {
+        return 1;
+    }
+    if($Deps eq "+Deps")
+    { # check the dependencies
+        if(link_symbol_internal($Symbol, $RunWith, \%DepSymbols)) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+sub link_symbol_internal($$$)
+{
+    my ($Symbol, $RunWith, $Where) = @_;
+    return 0 if(not $Where or not $Symbol);
+    if($Where->{$RunWith}{$Symbol})
+    { # the exact match by symbol name
+        return 1;
+    }
+    if(my $VSym = $SymVer{$RunWith}{$Symbol})
+    { # indirect symbol version, i.e.
+      # foo_old and its symlink foo@v (or foo@@v)
+      # foo_old may be in .symtab table
+        if($Where->{$RunWith}{$VSym}) {
+            return 1;
+        }
+    }
+    my ($Sym, $Del, $Ver) = separate_symbol($Symbol);
+    if($Sym and $Ver)
+    { # search for the symbol with the same version
+      # or without version
+        if($Where->{$RunWith}{$Sym})
+        { # old: foo@v|foo@@v
+          # new: foo
+            return 1;
+        }
+        if($Where->{$RunWith}{$Sym."\@".$Ver})
+        { # old: foo|foo@@v
+          # new: foo@v
+            return 1;
+        }
+        if($Where->{$RunWith}{$Sym."\@\@".$Ver})
+        { # old: foo|foo@v
+          # new: foo@@v
+            return 1;
+        }
+    }
+    return 0;
+}
+
+sub getSymbols_App($)
+{
+    my $Path = $_[0];
+    return () if(not $Path or not -f $Path);
+    my @Imported = ();
+    if($OSgroup eq "macos")
+    {
+        my $OtoolCmd = get_CmdPath("otool");
+        if(not $OtoolCmd) {
+            exitStatus("Not_Found", "can't find \"otool\"");
+        }
+        open(APP, "$OtoolCmd -IV $Path 2>$TMP_DIR/null |");
+        while(<APP>) {
+            if(/[^_]+\s+_?([\w\$]+)\s*\Z/) {
+                push(@Imported, $1);
+            }
+        }
+        close(APP);
+    }
+    elsif($OSgroup eq "windows")
+    {
+        my $DumpBinCmd = get_CmdPath("dumpbin");
+        if(not $DumpBinCmd) {
+            exitStatus("Not_Found", "can't find \"dumpbin.exe\"");
+        }
+        open(APP, "$DumpBinCmd /IMPORTS $Path 2>$TMP_DIR/null |");
+        while(<APP>) {
+            if(/\s*\w+\s+\w+\s+\w+\s+([\w\?\@]+)\s*/) {
+                push(@Imported, $1);
+            }
+        }
+        close(APP);
+    }
+    else
+    {
+        my $ReadelfCmd = get_CmdPath("readelf");
+        if(not $ReadelfCmd) {
+            exitStatus("Not_Found", "can't find \"readelf\"");
+        }
+        open(APP, "$ReadelfCmd -WhlSsdA $Path 2>$TMP_DIR/null |");
+        my $symtab=0; # indicates that we are processing 'symtab' section of 'readelf' output
+        while(<APP>)
+        {
+            if( /'.dynsym'/ ) {
+                $symtab=0;
+            }
+            elsif($symtab == 1) {
+                # do nothing with symtab (but there are some plans for the future)
+                next;
+            }
+            elsif( /'.symtab'/ ) {
+                $symtab=1;
+            }
+            elsif(my ($fullname, $idx, $Ndx, $type, $size, $bind) = readline_ELF($_))
+            {
+                if( $Ndx eq "UND" ) {
+                    #only imported symbols
+                    push(@Imported, $fullname);
+                }
+            }
+        }
+        close(APP);
+    }
+    return @Imported;
+}
+
+sub readline_ELF($)
+{
+    if($_[0]=~/\s*\d+:\s+(\w*)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s+(\w+)\s([^\s]+)/)
+    { # the line of 'readelf' output corresponding to the interface
+      # symbian-style: _ZN12CCTTokenType4NewLE4TUid3RFs@@ctfinder{000a0000}[102020e5].dll
+        my ($value, $size, $type, $bind,
+        $vis, $Ndx, $fullname)=($1, $2, $3, $4, $5, $6, $7);
+        if($bind!~/\A(WEAK|GLOBAL)\Z/) {
+            return ();
+        }
+        if($type!~/\A(FUNC|IFUNC|OBJECT|COMMON)\Z/) {
+            return ();
+        }
+        if($vis!~/\A(DEFAULT|PROTECTED)\Z/) {
+            return ();
+        }
+        if($Ndx eq "ABS" and $value!~/\D|1|2|3|4|5|6|7|8|9/) {
+            return ();
+        }
+        if($OStarget eq "symbian")
+        {
+            if($fullname=~/_\._\.absent_export_\d+/)
+            {# "_._.absent_export_111"@@libstdcpp{00010001}[10282872].dll
+                return ();
+            }
+            my @Elems = separate_symbol($fullname);
+            $fullname = $Elems[0];# remove internal version, {00020001}[10011235].dll
+        }
+        return ($fullname, $value, $Ndx, $type, $size, $bind);
+    }
+    else {
+        return ();
+    }
+}
+
+sub getSymbols_Lib($$$$$)
+{
+    my ($LibVersion, $Lib_Path, $IsNeededLib, $GroupNames, $Weak) = @_;
+    return if(not $Lib_Path or not -f $Lib_Path);
+    my ($Lib_Dir, $Lib_Name) = separate_path(resolve_symlink($Lib_Path));
+    return if($CheckedDyLib{$LibVersion}{$Lib_Name} and $IsNeededLib);
+    return if(isCyclical(\@RecurLib, $Lib_Name) or $#RecurLib>=1);
+    $CheckedDyLib{$LibVersion}{$Lib_Name} = 1;
+    getImplementations($LibVersion, $Lib_Path) if($CheckImpl and not $IsNeededLib);
+    push(@RecurLib, $Lib_Name);
+    my (%Value_Interface, %Interface_Value, %NeededLib) = ();
+    if(not $IsNeededLib)
+    { # libstdc++ and libc are always used by other libs
+      # if you test one of these libs then you not need
+      # to find them in the system for reusing
+        if(parse_libname($Lib_Name, "short", $OStarget) eq "libstdc++")
+        { # libstdc++.so.6
+            $STDCXX_TESTING = 1;
+        }
+        if(parse_libname($Lib_Name, "short", $OStarget) eq "libc")
+        { # libc-2.11.3.so
+            $GLIBC_TESTING = 1;
+        }
+    }
+    if($OStarget eq "macos")
+    { # Mac OS X: *.dylib, *.a
+        my $OtoolCmd = get_CmdPath("otool");
+        if(not $OtoolCmd) {
+            exitStatus("Not_Found", "can't find \"otool\"");
+        }
+        open(LIB, "$OtoolCmd -TV $Lib_Path 2>$TMP_DIR/null |");
+        while(<LIB>)
+        {
+            if(/[^_]+\s+_([\w\$]+)\s*\Z/)
+            {
+                my $realname = $1;
+                if($IsNeededLib and $GroupNames
+                and not $GroupNames->{parse_libname($Lib_Name, "name+ext", $OStarget)}) {
+                    $DepSymbols{$LibVersion}{$realname} = 1;
+                }
+                if(not $IsNeededLib)
+                {
+                    $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
+                    $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
+                    if($COMMON_LANGUAGE{$LibVersion} ne "C++"
+                    and $realname=~/\A(_Z|\?)/) {
+                        setLanguage($LibVersion, "C++");
+                    }
+                    if($CheckObjectsOnly
+                    and $LibVersion==1) {
+                        $CheckedSymbols{$realname} = 1;
+                    }
+                }
+            }
+        }
+        close(LIB);
+        if($LIB_TYPE eq "dynamic")
+        { # dependencies
+            open(LIB, "$OtoolCmd -L $Lib_Path 2>$TMP_DIR/null |");
+            while(<LIB>) {
+                if(/\s*([\/\\].+\.$LIB_EXT)\s*/
+                and $1 ne $Lib_Path) {
+                    $NeededLib{$1} = 1;
+                }
+            }
+            close(LIB);
+        }
+    }
+    elsif($OStarget eq "windows")
+    { # Windows *.dll, *.lib
+        my $DumpBinCmd = get_CmdPath("dumpbin");
+        if(not $DumpBinCmd) {
+            exitStatus("Not_Found", "can't find \"dumpbin\"");
+        }
+        open(LIB, "$DumpBinCmd /EXPORTS \"$Lib_Path\" 2>$TMP_DIR/null |");
+        while(<LIB>)
+        { # 1197 4AC 0000A620 SetThreadStackGuarantee
+          # 1198 4AD          SetThreadToken (forwarded to ...)
+          # 3368 _o2i_ECPublicKey
+            if(/\A\s*\d+\s+[a-f\d]+\s+[a-f\d]+\s+([\w\?\@]+)\s*\Z/i
+            or /\A\s*\d+\s+[a-f\d]+\s+([\w\?\@]+)\s*\(\s*forwarded\s+/
+            or /\A\s*\d+\s+_([\w\?\@]+)\s*\Z/)
+            { # dynamic, static and forwarded symbols
+                my $realname = $1;
+                if($IsNeededLib and not $GroupNames->{parse_libname($Lib_Name, "name+ext", $OStarget)}) {
+                    $DepSymbols{$LibVersion}{$realname} = 1;
+                }
+                if(not $IsNeededLib)
+                {
+                    $Symbol_Library{$LibVersion}{$realname} = $Lib_Name;
+                    $Library_Symbol{$LibVersion}{$Lib_Name}{$realname} = 1;
+                    if($COMMON_LANGUAGE{$LibVersion} ne "C++"
+                    and $realname=~/\A(_Z|\?)/) {
+                        setLanguage($LibVersion, "C++");
+                    }
+                    if($CheckObjectsOnly
+                    and $LibVersion==1) {
+                        $CheckedSymbols{$realname} = 1;
+                    }
+                }
+            }
+        }
+        close(LIB);
+        if($LIB_TYPE eq "dynamic")
+        { # dependencies
+            open(LIB, "$DumpBinCmd /DEPENDENTS $Lib_Path 2>$TMP_DIR/null |");
+            while(<LIB>) {
+                if(/\s*([^\s]+?\.$LIB_EXT)\s*/i
+                and $1 ne $Lib_Path) {
+                    $NeededLib{path_format($1, $OSgroup)} = 1;
+                }
+            }
+            close(LIB);
+        }
+    }
+    else
+    { # Unix; *.so, *.a
+      # Symbian: *.dso, *.lib
+        my $ReadelfCmd = get_CmdPath("readelf");
+        if(not $ReadelfCmd) {
+            exitStatus("Not_Found", "can't find \"readelf\"");
+        }
+        open(LIB, "$ReadelfCmd -WhlSsdA $Lib_Path 2>$TMP_DIR/null |");
+        my $symtab=0; # indicates that we are processing 'symtab' section of 'readelf' output
+        while(<LIB>)
+        {
+            if($LIB_TYPE eq "dynamic")
+            { # dynamic library specifics
+                if(/NEEDED.+\[([^\[\]]+)\]/)
+                { # dependencies:
+                  # 0x00000001 (NEEDED) Shared library: [libc.so.6]
+                    $NeededLib{$1} = 1;
+                    next;
+                }
+                if(/'\.dynsym'/)
+                { # dynamic table
+                    $symtab=0;
+                    next;
+                }
+                if($symtab == 1)
+                { # do nothing with symtab
+                    next;
+                }
+                if(/'\.symtab'/)
+                { # symbol table
+                    $symtab=1;
+                    next;
+                }
+            }
+            if(not $LIB_ARCH{$LibVersion})
+            {
+                if(/Machine:.*?([\w\-]+)\s*\Z/)
+                { # architecture
+                    $LIB_ARCH{$LibVersion}=$1;
+                    next;
+                }
+            }
+            if(my ($fullname, $idx, $Ndx, $type, $size, $bind) = readline_ELF($_))
+            { # read ELF entry
+                if( $Ndx eq "UND" )
+                { # ignore interfaces that are imported from somewhere else
+                    next;
+                }
+                if($bind eq "WEAK"
+                and $Weak eq "-Weak")
+                { # skip WEAK symbols
+                    next;
+                }
+                my ($realname, $version_spec, $version) = separate_symbol($fullname);
+                if($type eq "OBJECT")
+                { # global data
+                    $CompleteSignature{$LibVersion}{$fullname}{"Object"} = 1;
+                    $CompleteSignature{$LibVersion}{$realname}{"Object"} = 1;
+                }
+                if($IsNeededLib and not $GroupNames->{parse_libname($Lib_Name, "name+ext", $OStarget)}) {
+                    $DepSymbols{$LibVersion}{$fullname} = 1;
+                }
+                if(not $IsNeededLib)
+                {
+                    $Symbol_Library{$LibVersion}{$fullname} = $Lib_Name;
+                    $Library_Symbol{$LibVersion}{$Lib_Name}{$fullname} = ($type eq "OBJECT")?-$size:1;
+                    if($LIB_EXT eq "so")
+                    { # value
+                        $Interface_Value{$LibVersion}{$fullname} = $idx;
+                        $Value_Interface{$LibVersion}{$idx}{$fullname} = 1;
+                    }
+                    if($COMMON_LANGUAGE{$LibVersion} ne "C++"
+                    and $realname=~/\A(_Z|\?)/) {
+                        setLanguage($LibVersion, "C++");
+                    }
+                    if($CheckObjectsOnly
+                    and $LibVersion==1) {
+                        $CheckedSymbols{$fullname} = 1;
+                    }
+                }
+            }
+        }
+        close(LIB);
+    }
+    if(not $IsNeededLib and $LIB_EXT eq "so")
+    { # get symbol versions
+        foreach my $Symbol (keys(%{$Symbol_Library{$LibVersion}}))
+        {
+            next if($Symbol!~/\@/);
+            my $Interface_SymName = "";
+            foreach my $Symbol_SameValue (keys(%{$Value_Interface{$LibVersion}{$Interface_Value{$LibVersion}{$Symbol}}}))
+            {
+                if($Symbol_SameValue ne $Symbol
+                and $Symbol_SameValue!~/\@/)
+                {
+                    $SymVer{$LibVersion}{$Symbol_SameValue} = $Symbol;
+                    $Interface_SymName = $Symbol_SameValue;
+                    last;
+                }
+            }
+            if(not $Interface_SymName)
+            {
+                if($Symbol=~/\A([^\@\$\?]*)[\@\$]+([^\@\$]*)\Z/
+                and not $SymVer{$LibVersion}{$1}) {
+                    $SymVer{$LibVersion}{$1} = $Symbol;
+                }
+            }
+        }
+    }
+    foreach my $DyLib (sort keys(%NeededLib))
+    {
+        my $DepPath = find_lib_path($LibVersion, $DyLib);
+        if($DepPath and -f $DepPath) {
+            getSymbols_Lib($LibVersion, $DepPath, 1, $GroupNames, "+Weak");
+        }
+    }
+    pop(@RecurLib);
+    return $Library_Symbol{$LibVersion};
+}
+
+sub get_path_prefixes($)
+{
+    my $Path = $_[0];
+    my ($Dir, $Name) = separate_path($Path);
+    my %Prefixes = ();
+    foreach my $Prefix (reverse(split(/[\/\\]+/, $Dir)))
+    {
+        $Prefixes{$Name} = 1;
+        $Name = joinPath($Prefix, $Name);
+        last if(keys(%Prefixes)>5 or $Prefix eq "include");
+    }
+    return keys(%Prefixes);
+}
+
+sub detectSystemHeaders()
+{
+    my @SysHeaders = ();
+    foreach my $DevelPath (keys(%{$SystemPaths{"include"}}))
+    {
+        next if(not -d $DevelPath);
+        # search for all header files in the /usr/include
+        # with or without extension (ncurses.h, QtCore, ...)
+        @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f","",""));
+        foreach my $Link (cmd_find($DevelPath,"l","",""))
+        { # add symbolic links
+            if(-f $Link) {
+                push(@SysHeaders, $Link);
+            }
+        }
+    }
+    foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
+    {
+        next if(not -d $DevelPath);
+        # search for config headers in the /usr/lib
+        @SysHeaders = (@SysHeaders, cmd_find($DevelPath,"f","*.h",""));
+        foreach my $Dir (cmd_find($DevelPath,"d","include",""))
+        { # search for all include directories
+          # this is for headers that are installed to /usr/lib
+          # Example: Qt4 headers in Mandriva (/usr/lib/qt4/include/)
+            if($Dir=~/\/(gcc|jvm|syslinux|kdb)\//) {
+                next;
+            }
+            @SysHeaders = (@SysHeaders, cmd_find($Dir,"f","",""));
+        }
+    }
+    foreach my $Path (@SysHeaders)
+    {
+        foreach my $Part (get_path_prefixes($Path)) {
+            $SystemHeaders{$Part}{$Path}=1;
+        }
+    }
+}
+
+sub detectSystemObjects()
+{
+    foreach my $DevelPath (keys(%{$SystemPaths{"lib"}}))
+    {
+        next if(not -d $DevelPath);
+        foreach my $Path (find_libs($DevelPath,"",""))
+        { # search for shared libraries in the /usr/lib (including symbolic links)
+            $SystemObjects{parse_libname(get_filename($Path), "name+ext", $OStarget)}{$Path}=1;
+        }
+    }
+}
+
+sub find_lib_path($$)
+{
+    my ($LibVersion, $DyLib) = @_;
+    return "" if(not $DyLib or not $LibVersion);
+    return $DyLib if(is_abs($DyLib));
+    if(defined $Cache{"find_lib_path"}{$LibVersion}{$DyLib}) {
+        return $Cache{"find_lib_path"}{$LibVersion}{$DyLib};
+    }
+    if(my @Paths = sort keys(%{$InputObject_Paths{$LibVersion}{$DyLib}})) {
+        return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $Paths[0]);
+    }
+    elsif(my $DefaultPath = $DyLib_DefaultPath{$DyLib}) {
+        return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $DefaultPath);
+    }
+    else
+    {
+        foreach my $Dir (sort keys(%DefaultLibPaths), sort keys(%{$SystemPaths{"lib"}}))
+        { # search in default linker paths and then in all system paths
+            if(-f $Dir."/".$DyLib) {
+                return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = joinPath($Dir,$DyLib));
+            }
+        }
+        detectSystemObjects() if(not keys(%SystemObjects));
+        if(my @AllObjects = keys(%{$SystemObjects{$DyLib}})) {
+            return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $AllObjects[0]);
+        }
+        my $ShortName = parse_libname($DyLib, "name+ext", $OStarget);
+        if($ShortName ne $DyLib
+        and my $Path = find_lib_path($ShortName))
+        { # FIXME: check this case
+            return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = $Path);
+        }
+        return ($Cache{"find_lib_path"}{$LibVersion}{$DyLib} = "");
+    }
+}
+
+sub getSoPaths($)
+{
+    my $LibVersion = $_[0];
+    my @SoPaths = ();
+    foreach my $Dest (split(/\s*\n\s*/, $Descriptor{$LibVersion}{"Libs"}))
+    {
+        if(not -e $Dest) {
+            exitStatus("Access_Error", "can't access \'$Dest\'");
+        }
+        my @SoPaths_Dest = getSOPaths_Dest($Dest, $LibVersion);
+        foreach (@SoPaths_Dest) {
+            push(@SoPaths, $_);
+        }
+    }
+    return @SoPaths;
+}
+
+sub skip_lib($$)
+{
+    my ($Path, $LibVersion) = @_;
+    return 1 if(not $Path or not $LibVersion);
+    my $LibName = get_filename($Path);
+    if($SkipLibs{$LibVersion}{"Name"}{$LibName}) {
+        return 1;
+    }
+    my $ShortName = parse_libname($LibName, "name+ext", $OStarget);
+    if($SkipLibs{$LibVersion}{"Name"}{$ShortName}) {
+        return 1;
+    }
+    foreach my $Dir (keys(%{$SkipLibs{$LibVersion}{"Path"}}))
+    {
+        if($Path=~/\Q$Dir\E([\/\\]|\Z)/) {
+            return 1;
+        }
+    }
+    foreach my $Pattern (keys(%{$SkipLibs{$LibVersion}{"Pattern"}}))
+    {
+        if($LibName=~/$Pattern/) {
+            return 1;
+        }
+        if($Pattern=~/[\/\\]/ and $Path=~/$Pattern/) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+sub skip_header($$)
+{ # returns:
+  #  1 - if header should NOT be included and checked
+  #  2 - if header should NOT be included, but should be checked
+    my ($Path, $LibVersion) = @_;
+    return 1 if(not $Path or not $LibVersion);
+    my $HeaderName = get_filename($Path);
+    if(my $Kind = $SkipHeaders{$LibVersion}{"Name"}{$HeaderName}) {
+        return $Kind;
+    }
+    foreach my $Dir (keys(%{$SkipHeaders{$LibVersion}{"Path"}}))
+    {
+        if($Path=~/\Q$Dir\E([\/\\]|\Z)/) {
+            return $SkipHeaders{$LibVersion}{"Path"}{$Dir};
+        }
+    }
+    foreach my $Pattern (keys(%{$SkipHeaders{$LibVersion}{"Pattern"}}))
+    {
+        if($HeaderName=~/$Pattern/) {
+            return $SkipHeaders{$LibVersion}{"Pattern"}{$Pattern};
+        }
+        if($Pattern=~/[\/\\]/ and $Path=~/$Pattern/) {
+            return $SkipHeaders{$LibVersion}{"Pattern"}{$Pattern};
+        }
+    }
+    return 0;
+}
+
+sub register_objects($$)
+{
+    my ($Dir, $LibVersion) = @_;
+    if($SystemPaths{"lib"}{$Dir})
+    { # system directory
+        return;
+    }
+    if($RegisteredObjDirs{$LibVersion}{$Dir})
+    { # already registered
+        return;
+    }
+    foreach my $Path (find_libs($Dir,"",1))
+    {
+        next if(ignore_path($Path));
+        next if(skip_lib($Path, $LibVersion));
+        $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
+    }
+    $RegisteredObjDirs{$LibVersion}{$Dir} = 1;
+}
+
+sub getSOPaths_Dest($$)
+{
+    my ($Dest, $LibVersion) = @_;
+    if(skip_lib($Dest, $LibVersion)) {
+        return ();
+    }
+    if(-f $Dest)
+    {
+        if(not parse_libname($Dest, "name", $OStarget)) {
+            exitStatus("Error", "incorrect format of library (should be *.$LIB_EXT): \'$Dest\'");
+        }
+        $InputObject_Paths{$LibVersion}{get_filename($Dest)}{$Dest} = 1;
+        register_objects(get_dirname($Dest), $LibVersion);
+        return ($Dest);
+    }
+    elsif(-d $Dest)
+    {
+        $Dest=~s/[\/\\]+\Z//g;
+        my @AllObjects = ();
+        if($SystemPaths{"lib"}{$Dest})
+        { # you have specified /usr/lib as the search directory (<libs>) in the XML descriptor
+          # and the real name of the library by -l option (bz2, stdc++, Xaw, ...)
+            foreach my $Path (cmd_find($Dest,"","*".esc($TargetLibraryName)."*\.$LIB_EXT*",2))
+            { # all files and symlinks that match the name of a library
+                if(get_filename($Path)=~/\A(|lib)\Q$TargetLibraryName\E[\d\-]*\.$LIB_EXT[\d\.]*\Z/i)
+                {
+                    $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
+                    push(@AllObjects, resolve_symlink($Path));
+                }
+            }
+        }
+        else
+        { # search for all files and symlinks
+            foreach my $Path (find_libs($Dest,"",""))
+            {
+                next if(ignore_path($Path));
+                next if(skip_lib($Path, $LibVersion));
+                $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
+                push(@AllObjects, resolve_symlink($Path));
+            }
+            if($OSgroup eq "macos")
+            { # shared libraries on MacOS X may have no extension
+                foreach my $Path (cmd_find($Dest,"f","",""))
+                {
+                    next if(ignore_path($Path));
+                    next if(skip_lib($Path, $LibVersion));
+                    if(get_filename($Path)!~/\./
+                    and cmd_file($Path)=~/(shared|dynamic)\s+library/i) {
+                        $InputObject_Paths{$LibVersion}{get_filename($Path)}{$Path} = 1;
+                        push(@AllObjects, resolve_symlink($Path));
+                    }
+                }
+            }
+        }
+        return @AllObjects;
+    }
+    else {
+        return ();
+    }
+}
+
+sub isCyclical($$) {
+    return (grep {$_ eq $_[1]} @{$_[0]});
+}
+
+sub read_symlink($)
+{
+    my $Path = $_[0];
+    return "" if(not $Path);
+    return "" if(not -f $Path and not -l $Path);
+    if(defined $Cache{"read_symlink"}{$Path}) {
+        return $Cache{"read_symlink"}{$Path};
+    }
+    if(my $Res = readlink($Path)) {
+        return ($Cache{"read_symlink"}{$Path} = $Res);
+    }
+    elsif(my $ReadlinkCmd = get_CmdPath("readlink")) {
+        return ($Cache{"read_symlink"}{$Path} = `$ReadlinkCmd -n $Path`);
+    }
+    elsif(my $FileCmd = get_CmdPath("file"))
+    {
+        my $Info = `$FileCmd $Path`;
+        if($Info=~/symbolic\s+link\s+to\s+['`"]*([\w\d\.\-\/\\]+)['`"]*/i) {
+            return ($Cache{"read_symlink"}{$Path} = $1);
+        }
+    }
+    return ($Cache{"read_symlink"}{$Path} = "");
+}
+
+sub resolve_symlink($)
+{
+    my $Path = $_[0];
+    return "" if(not $Path);
+    return "" if(not -f $Path and not -l $Path);
+    if(defined $Cache{"resolve_symlink"}{$Path}) {
+        return $Cache{"resolve_symlink"}{$Path};
+    }
+    return $Path if(isCyclical(\@RecurSymlink, $Path));
+    push(@RecurSymlink, $Path);
+    if(-l $Path and my $Redirect=read_symlink($Path))
+    {
+        if(is_abs($Redirect))
+        { # absolute path
+            if($SystemRoot and $SystemRoot ne "/"
+            and $Path=~/\A\Q$SystemRoot\E\//
+            and (-f $SystemRoot.$Redirect or -l $SystemRoot.$Redirect))
+            { # symbolic links from the sysroot
+              # should be corrected to point to
+              # the files inside sysroot
+                $Redirect = $SystemRoot.$Redirect;
+            }
+            my $Res = resolve_symlink($Redirect);
+            pop(@RecurSymlink);
+            return ($Cache{"resolve_symlink"}{$Path} = $Res);
+        }
+        elsif($Redirect=~/\.\.[\/\\]/)
+        { # relative path
+            $Redirect = joinPath(get_dirname($Path),$Redirect);
+            while($Redirect=~s&(/|\\)[^\/\\]+(\/|\\)\.\.(\/|\\)&$1&){};
+            my $Res = resolve_symlink($Redirect);
+            pop(@RecurSymlink);
+            return ($Cache{"resolve_symlink"}{$Path} = $Res);
+        }
+        elsif(-f get_dirname($Path)."/".$Redirect)
+        { # file name in the same directory
+            my $Res = resolve_symlink(joinPath(get_dirname($Path),$Redirect));
+            pop(@RecurSymlink);
+            return ($Cache{"resolve_symlink"}{$Path} = $Res);
+        }
+        else
+        { # broken link
+            pop(@RecurSymlink);
+            return ($Cache{"resolve_symlink"}{$Path} = "");
+        }
+    }
+    pop(@RecurSymlink);
+    return ($Cache{"resolve_symlink"}{$Path} = $Path);
+}
+
+sub generateTemplate()
+{
+    writeFile("VERSION.xml", $DescriptorTemplate."\n");
+    printMsg("INFO", "XML-descriptor template ./VERSION.xml has been generated");
+}
+
+sub detectWordSize()
+{
+    return "" if(not $GCC_PATH);
+    if($Cache{"detectWordSize"}) {
+        return $Cache{"detectWordSize"};
+    }
+    writeFile("$TMP_DIR/empty.h", "");
+    my $Defines = `$GCC_PATH -E -dD $TMP_DIR/empty.h`;
+    unlink("$TMP_DIR/empty.h");
+    my $WSize = 0;
+    if($Defines=~/ __SIZEOF_POINTER__\s+(\d+)/)
+    {# GCC 4
+        $WSize = $1;
+    }
+    elsif($Defines=~/ __PTRDIFF_TYPE__\s+(\w+)/)
+    {# GCC 3
+        my $PTRDIFF = $1;
+        if($PTRDIFF=~/long/) {
+            $WSize = 8;
+        }
+        else {
+            $WSize = 4;
+        }
+    }
+    if(not int($WSize)) {
+        exitStatus("Error", "can't check WORD size");
+    }
+    return ($Cache{"detectWordSize"} = $WSize);
+}
+
+sub majorVersion($)
+{
+    my $V = $_[0];
+    return 0 if(not $V);
+    my @VParts = split(/\./, $V);
+    return $VParts[0];
+}
+
+sub cmpVersions($$)
+{# compare two versions in dotted-numeric format
+    my ($V1, $V2) = @_;
+    return 0 if($V1 eq $V2);
+    return undef if($V1!~/\A\d+[\.\d+]*\Z/);
+    return undef if($V2!~/\A\d+[\.\d+]*\Z/);
+    my @V1Parts = split(/\./, $V1);
+    my @V2Parts = split(/\./, $V2);
+    for (my $i = 0; $i <= $#V1Parts && $i <= $#V2Parts; $i++) {
+        return -1 if(int($V1Parts[$i]) < int($V2Parts[$i]));
+        return 1 if(int($V1Parts[$i]) > int($V2Parts[$i]));
+    }
+    return -1 if($#V1Parts < $#V2Parts);
+    return 1 if($#V1Parts > $#V2Parts);
+    return 0;
+}
+
+sub read_ABI_Dump($$)
+{
+    my ($LibVersion, $Path) = @_;
+    return if(not $LibVersion or not -e $Path);
+    my $FilePath = "";
+    if($Path=~/\.abi\Z/)
+    { # input *.abi
+        $FilePath = $Path;
+    }
+    else
+    { # input *.abi.tar.gz
+        $FilePath = unpackDump($Path);
+    }
+    if($FilePath!~/\.abi\Z/) {
+        exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
+    }
+    my $Content = readFile($FilePath);
+    if($Path!~/\.abi\Z/)
+    { # remove temp file
+        unlink($FilePath);
+    }
+    if($Content!~/};\s*\Z/) {
+        exitStatus("Invalid_Dump", "specified ABI dump \'$Path\' is not valid, try to recreate it");
+    }
+    my $LibraryABI = eval($Content);
+    if(not $LibraryABI) {
+        exitStatus("Error", "internal error - eval() procedure seem to not working correctly, try to remove 'use strict' and try again");
+    }
+    # new dumps (>=1.22) have a personal versioning
+    my $DumpVersion = $LibraryABI->{"ABI_DUMP_VERSION"};
+    my $ToolVersion = $LibraryABI->{"ABI_COMPLIANCE_CHECKER_VERSION"};
+    if(not $DumpVersion)
+    { # old dumps (<=1.21.6) have been marked by the tool version
+        $DumpVersion = $ToolVersion;
+    }
+    $UsedDump{$LibVersion}{"V"} = $DumpVersion;
+    if(majorVersion($DumpVersion) ne majorVersion($ABI_DUMP_VERSION))
+    { # should be compatible with dumps of the same major version
+        if(cmpVersions($DumpVersion, $ABI_DUMP_VERSION)>0)
+        { # Don't know how to parse future dump formats
+            exitStatus("Dump_Version", "incompatible version $DumpVersion of specified ABI dump (newer than $ABI_DUMP_VERSION)");
+        }
+        elsif(cmpVersions($DumpVersion, $TOOL_VERSION)>0 and not $LibraryABI->{"ABI_DUMP_VERSION"})
+        { # Don't know how to parse future dump formats
+            exitStatus("Dump_Version", "incompatible version $DumpVersion of specified ABI dump (newer than $TOOL_VERSION)");
+        }
+        if($UseOldDumps)
+        {
+            if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)<0) {
+                exitStatus("Dump_Version", "incompatible version $DumpVersion of specified ABI dump (older than $OLDEST_SUPPORTED_VERSION)");
+            }
+        }
+        else
+        {
+            my $Msg = "incompatible version $DumpVersion of specified ABI dump (allowed only ".majorVersion($ABI_DUMP_VERSION).".0<=V<=$ABI_DUMP_VERSION)";
+            if(cmpVersions($DumpVersion, $OLDEST_SUPPORTED_VERSION)>=0) {
+                $Msg .= "\nUse -old-dumps option to use old-version dumps ($OLDEST_SUPPORTED_VERSION<=V<".majorVersion($ABI_DUMP_VERSION).".0)";
+            }
+            exitStatus("Dump_Version", $Msg);
+        }
+    }
+    if($LibraryABI->{"Mode"} eq "Extended")
+    { # --ext option
+        $ExtendedCheck = 1;
+    }
+    if(my $Lang = $LibraryABI->{"Language"})
+    {
+        $UsedDump{$LibVersion}{"L"} = $Lang;
+        setLanguage($LibVersion, $Lang);
+    }
+    $TypeInfo{$LibVersion} = $LibraryABI->{"TypeInfo"};
+    if(not $TypeInfo{$LibVersion})
+    { # support for old ABI dumps
+        $TypeInfo{$LibVersion} = $LibraryABI->{"TypeDescr"};
+    }
+    read_Machine_DumpInfo($LibraryABI, $LibVersion);
+    $SymbolInfo{$LibVersion} = $LibraryABI->{"SymbolInfo"};
+    if(not $SymbolInfo{$LibVersion})
+    { # support for old dumps
+        $SymbolInfo{$LibVersion} = $LibraryABI->{"FuncDescr"};
+    }
+    if(not keys(%{$SymbolInfo{$LibVersion}}))
+    { # validation of old-version dumps
+        if(not $ExtendedCheck) {
+            exitStatus("Invalid_Dump", "the input dump d$LibVersion is invalid");
+        }
+    }
+    $Library_Symbol{$LibVersion} = $LibraryABI->{"Symbols"};
+    if(not $Library_Symbol{$LibVersion})
+    { # support for old dumps
+        $Library_Symbol{$LibVersion} = $LibraryABI->{"Interfaces"};
+    }
+    $DepSymbols{$LibVersion} = $LibraryABI->{"DepSymbols"};
+    if(not $DepSymbols{$LibVersion})
+    { # support for old dumps
+        $DepSymbols{$LibVersion} = $LibraryABI->{"DepInterfaces"};
+    }
+    if(not $DepSymbols{$LibVersion})
+    { # support for old dumps
+      # Cannot reconstruct DepSymbols. This may result in false
+      # positives if the old dump is for library 2. Not a problem if
+      # old dumps are only from old libraries.
+        $DepSymbols{$LibVersion} = {};
+    }
+    $SymVer{$LibVersion} = $LibraryABI->{"SymbolVersion"};
+    $Tid_TDid{$LibVersion} = $LibraryABI->{"Tid_TDid"};
+    $Descriptor{$LibVersion}{"Version"} = $LibraryABI->{"LibraryVersion"};
+    $SkipTypes{$LibVersion} = $LibraryABI->{"SkipTypes"};
+    if(not $SkipTypes{$LibVersion})
+    { # support for old dumps
+        $SkipTypes{$LibVersion} = $LibraryABI->{"OpaqueTypes"};
+    }
+    $SkipSymbols{$LibVersion} = $LibraryABI->{"SkipSymbols"};
+    if(not $SkipSymbols{$LibVersion})
+    { # support for old dumps
+        $SkipSymbols{$LibVersion} = $LibraryABI->{"SkipInterfaces"};
+    }
+    if(not $SkipSymbols{$LibVersion})
+    { # support for old dumps
+        $SkipSymbols{$LibVersion} = $LibraryABI->{"InternalInterfaces"};
+    }
+    $SkipNameSpaces{$LibVersion} = $LibraryABI->{"SkipNameSpaces"};
+    $TargetHeaders{$LibVersion} = $LibraryABI->{"TargetHeaders"};
+    foreach my $Path (keys(%{$LibraryABI->{"SkipHeaders"}}))
+    {
+        my ($CPath, $Type) = classifyPath($Path);
+        $SkipHeaders{$LibVersion}{$Type}{$CPath} = $LibraryABI->{"SkipHeaders"}{$Path};
+        $SkipHeadersList{$LibVersion}{$Path} = $LibraryABI->{"SkipHeaders"}{$Path};
+    }
+    read_Headers_DumpInfo($LibraryABI, $LibVersion);
+    read_Libs_DumpInfo($LibraryABI, $LibVersion);
+    if(not $Descriptor{$LibVersion}{"Libs"})
+    { # support for old ABI dumps
+        if(cmpVersions($DumpVersion, "2.10.1")<0)
+        {
+            if(not $TargetHeaders{$LibVersion})
+            {
+                foreach (keys(%{$Registered_Headers{$LibVersion}})) {
+                    $TargetHeaders{$LibVersion}{get_filename($_)}=1;
+                }
+            }
+        }
+    }
+    $Constants{$LibVersion} = $LibraryABI->{"Constants"};
+    $NestedNameSpaces{$LibVersion} = $LibraryABI->{"NameSpaces"};
+    if(not $NestedNameSpaces{$LibVersion})
+    { # support for old dumps
+      # Cannot reconstruct NameSpaces. This may affect design
+      # of the compatibility report.
+        $NestedNameSpaces{$LibVersion} = {};
+    }
+    # target system type
+    # needed to adopt HTML report
+    if(not $DumpSystem)
+    { # to use in createSymbolsList(...)
+        $OStarget = $LibraryABI->{"Target"};
+    }
+    # recreate environment
+    foreach my $Lib_Name (keys(%{$Library_Symbol{$LibVersion}}))
+    {
+        foreach my $Interface (keys(%{$Library_Symbol{$LibVersion}{$Lib_Name}}))
+        {
+            $Symbol_Library{$LibVersion}{$Interface} = $Lib_Name;
+            if($Library_Symbol{$LibVersion}{$Lib_Name}{$Interface}<=-1)
+            { # data marked as -size in the dump
+                $CompleteSignature{$LibVersion}{$Interface}{"Object"} = 1;
+            }
+            if($COMMON_LANGUAGE{$LibVersion} ne "C++"
+            and $Interface=~/\A(_Z|\?)/) {
+                setLanguage($LibVersion, "C++");
+            }
+        }
+    }
+    my @VFunc = ();
+    foreach my $FuncInfoId (keys(%{$SymbolInfo{$LibVersion}}))
+    {
+        my $MnglName = $SymbolInfo{$LibVersion}{$FuncInfoId}{"MnglName"};
+        if(not $MnglName)
+        { # C-functions
+            next;
+        }
+        if(not $Symbol_Library{$LibVersion}{$MnglName}
+        and not $DepSymbols{$LibVersion}{$MnglName}) {
+            push(@VFunc, $MnglName);
+        }
+    }
+    translateSymbols(@VFunc, $LibVersion);
+    translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
+    translateSymbols(keys(%{$DepSymbols{$LibVersion}}), $LibVersion);
+
+    foreach my $TypeDeclId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
+    {
+        foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}}))
+        {
+            if(defined $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"BaseClass"})
+            { # support for old ABI dumps < 2.0 (ACC 1.22)
+                foreach my $BId (keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"BaseClass"}}))
+                {
+                    if(my $Access = $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"BaseClass"}{$BId})
+                    {
+                        if($Access ne "public") {
+                            $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Base"}{$BId}{"access"} = $Access;
+                        }
+                    }
+                    $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Base"}{$BId} = {};
+                }
+                delete($TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"BaseClass"});
+            }
+            my %TInfo = %{$TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}};
+            if(defined $TInfo{"Base"})
+            {
+                foreach (keys(%{$TInfo{"Base"}})) {
+                    $Class_SubClasses{$LibVersion}{$_}{$TypeId}=1;
+                }
+            }
+            if($TInfo{"Type"} eq "Typedef")
+            {
+                my ($BTDid, $BTid) = ($TInfo{"BaseType"}{"TDid"}, $TInfo{"BaseType"}{"Tid"});
+                $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}} = $TypeInfo{$LibVersion}{$BTDid}{$BTid}{"Name"};
+            }
+            if(not $TName_Tid{$LibVersion}{$TInfo{"Name"}})
+            { # classes: class (id1), typedef (artificial, id2 > id1)
+                $TName_Tid{$LibVersion}{$TInfo{"Name"}} = $TypeId;
+            }
+        }
+    }
+    
+    $Descriptor{$LibVersion}{"Dump"} = 1;
+}
+
+sub read_Machine_DumpInfo($$)
+{
+    my ($LibraryABI, $LibVersion) = @_;
+    if($LibraryABI->{"Arch"}) {
+        $CPU_ARCH{$LibVersion} = $LibraryABI->{"Arch"};
+    }
+    if($LibraryABI->{"WordSize"}) {
+        $WORD_SIZE{$LibVersion} = $LibraryABI->{"WordSize"};
+    }
+    else
+    { # support for old dumps
+        $WORD_SIZE{$LibVersion} = $LibraryABI->{"SizeOfPointer"};
+    }
+    if(not $WORD_SIZE{$LibVersion})
+    { # support for old dumps (<1.23)
+        if(my $Tid = getTypeIdByName("char*", $LibVersion))
+        { # size of char*
+            $WORD_SIZE{$LibVersion} = get_TypeSize($Tid, $LibVersion);
+        }
+        else
+        {
+            my $PSize = 0;
+            foreach my $TDid (keys(%{$TypeInfo{$LibVersion}}))
+            {
+                foreach my $Tid (keys(%{$TypeInfo{$LibVersion}{$TDid}}))
+                {
+                    if(get_TypeAttr($Tid, $LibVersion, "Type") eq "Pointer")
+                    { # any "pointer"-type
+                        $PSize = get_TypeSize($Tid, $LibVersion);
+                        last;
+                    }
+                }
+                if($PSize) {
+                    last;
+                }
+            }
+            if($PSize)
+            { # a pointer type size
+                $WORD_SIZE{$LibVersion} = $PSize;
+            }
+            else {
+                printMsg("WARNING", "cannot identify a WORD size in the ABI dump (too old format)");
+            }
+        }
+    }
+    if($LibraryABI->{"GccVersion"}) {
+        $GCC_VERSION{$LibVersion} = $LibraryABI->{"GccVersion"};
+    }
+}
+
+sub read_Libs_DumpInfo($$)
+{
+    my ($LibraryABI, $LibVersion) = @_;
+    if(keys(%{$Library_Symbol{$LibVersion}})
+    and not $DumpAPI) {
+        $Descriptor{$LibVersion}{"Libs"} = "OK";
+    }
+}
+
+sub read_Headers_DumpInfo($$)
+{
+    my ($LibraryABI, $LibVersion) = @_;
+    if(keys(%{$LibraryABI->{"Headers"}})
+    and not $DumpAPI) {
+        $Descriptor{$LibVersion}{"Headers"} = "OK";
+    }
+    foreach my $Identity (keys(%{$LibraryABI->{"Headers"}}))
+    { # headers info is stored in the old dumps in the different way
+        if($UseOldDumps
+        and my $Name = $LibraryABI->{"Headers"}{$Identity}{"Name"})
+        { # support for old dumps: headers info corrected in 1.22
+            $Identity = $Name;
+        }
+        $Registered_Headers{$LibVersion}{$Identity}{"Identity"} = $Identity;
+    }
+}
+
+sub find_libs($$$)
+{
+    my ($Path, $Type, $MaxDepth) = @_;
+    # FIXME: correct the search pattern
+    return cmd_find($Path, $Type, ".*\\.$LIB_EXT\[0-9.]*", $MaxDepth);
+}
+
+sub createDescriptor($$)
+{
+    my ($LibVersion, $Path) = @_;
+    if(not $LibVersion or not $Path
+    or not -e $Path) {
+        return "";
+    }
+    if(-d $Path)
+    { # directory with headers files and shared objects
+        return "
+            <version>
+                ".$TargetVersion{$LibVersion}."
+            </version>
+
+            <headers>
+                $Path
+            </headers>
+
+            <libs>
+                $Path
+            </libs>";
+    }
+    else
+    { # files
+        if($Path=~/\.xml\Z/i)
+        { # standard XML-descriptor
+            return readFile($Path);
+        }
+        elsif(is_header($Path, 2, $LibVersion))
+        { # header file
+            return "
+                <version>
+                    ".$TargetVersion{$LibVersion}."
+                </version>
+
+                <headers>
+                    $Path
+                </headers>
+
+                <libs>
+                    none
+                </libs>";
+        }
+        elsif(parse_libname($Path, "name", $OStarget))
+        { # shared object
+            return "
+                <version>
+                    ".$TargetVersion{$LibVersion}."
+                </version>
+
+                <headers>
+                    none
+                </headers>
+
+                <libs>
+                    $Path
+                </libs>";
+        }
+        else
+        { # standard XML-descriptor
+            return readFile($Path);
+        }
+    }
+}
+
+sub detect_lib_default_paths()
+{
+    my %LPaths = ();
+    if($OSgroup eq "bsd")
+    {
+        if(my $LdConfig = get_CmdPath("ldconfig")) {
+            foreach my $Line (split(/\n/, `$LdConfig -r 2>$TMP_DIR/null`)) {
+                if($Line=~/\A[ \t]*\d+:\-l(.+) \=\> (.+)\Z/) {
+                    $LPaths{"lib".$1} = $2;
+                }
+            }
+        }
+        else {
+            printMsg("WARNING", "can't find ldconfig");
+        }
+    }
+    else
+    {
+        if(my $LdConfig = get_CmdPath("ldconfig"))
+        {
+            if($SystemRoot and $OSgroup eq "linux")
+            { # use host (x86) ldconfig with the target (arm) ld.so.conf
+                if(-e $SystemRoot."/etc/ld.so.conf") {
+                    $LdConfig .= " -f ".$SystemRoot."/etc/ld.so.conf";
+                }
+            }
+            foreach my $Line (split(/\n/, `$LdConfig -p 2>$TMP_DIR/null`)) {
+                if($Line=~/\A[ \t]*([^ \t]+) .* \=\> (.+)\Z/)
+                {
+                    my ($Name, $Path) = ($1, $2);
+                    $Path=~s/[\/]{2,}/\//;
+                    $LPaths{$Name} = $Path;
+                }
+            }
+        }
+        elsif($OSgroup=~/linux/i) {
+            printMsg("WARNING", "can't find ldconfig");
+        }
+    }
+    return \%LPaths;
+}
+
+sub detect_bin_default_paths()
+{
+    my $EnvPaths = $ENV{"PATH"};
+    if($OSgroup eq "beos") {
+        $EnvPaths.=":".$ENV{"BETOOLS"};
+    }
+    my $Sep = ($OSgroup eq "windows")?";":":|;";
+    foreach my $Path (sort {length($a)<=>length($b)} split(/$Sep/, $EnvPaths))
+    {
+        $Path = path_format($Path, $OSgroup);
+        $Path=~s/[\/\\]+\Z//g;
+        next if(not $Path);
+        if($SystemRoot
+        and $Path=~/\A\Q$SystemRoot\E\//)
+        { # do NOT use binaries from target system
+            next;
+        }
+        $DefaultBinPaths{$Path} = 1;
+    }
+}
+
+sub detect_inc_default_paths()
+{
+    return () if(not $GCC_PATH);
+    my %DPaths = ("Cpp"=>{},"Gcc"=>{},"Inc"=>{});
+    writeFile("$TMP_DIR/empty.h", "");
+    foreach my $Line (split(/\n/, `$GCC_PATH -v -x c++ -E "$TMP_DIR/empty.h" 2>&1`))
+    {# detecting gcc default include paths
+        if($Line=~/\A[ \t]*((\/|\w+:\\).+)[ \t]*\Z/)
+        {
+            my $Path = simplify_path($1);
+            $Path=~s/[\/\\]+\Z//g;
+            $Path = path_format($Path, $OSgroup);
+            if($Path=~/c\+\+|\/g\+\+\//)
+            {
+                $DPaths{"Cpp"}{$Path}=1;
+                if(not defined $MAIN_CPP_DIR
+                or get_depth($MAIN_CPP_DIR)>get_depth($Path)) {
+                    $MAIN_CPP_DIR = $Path;
+                }
+            }
+            elsif($Path=~/gcc/) {
+                $DPaths{"Gcc"}{$Path}=1;
+            }
+            else
+            {
+                next if($Path=~/local[\/\\]+include/);
+                if($SystemRoot
+                and $Path!~/\A\Q$SystemRoot\E(\/|\Z)/)
+                { # The GCC include path for user headers is not a part of the system root
+                  # The reason: you are not specified the --cross-gcc option or selected a wrong compiler
+                  # or it is the internal cross-GCC path like arm-linux-gnueabi/include
+                    next;
+                }
+                $DPaths{"Inc"}{$Path}=1;
+            }
+        }
+    }
+    unlink("$TMP_DIR/empty.h");
+    return %DPaths;
+}
+
+sub detect_default_paths($)
+{
+    my ($HSearch, $LSearch, $BSearch, $GSearch) = (1, 1, 1, 1);
+    my $Search = $_[0];
+    if($Search!~/inc/) {
+        $HSearch = 0;
+    }
+    if($Search!~/lib/) {
+        $LSearch = 0;
+    }
+    if($Search!~/bin/) {
+        $BSearch = 0;
+    }
+    if($Search!~/gcc/) {
+        $GSearch = 0;
+    }
+    if(keys(%{$SystemPaths{"include"}}))
+    { # <search_headers> section of the XML descriptor
+      # do NOT search for systems headers
+        $HSearch = 0;
+    }
+    if(keys(%{$SystemPaths{"lib"}}))
+    { # <search_headers> section of the XML descriptor
+      # do NOT search for systems headers
+        $LSearch = 0;
+    }
+    foreach my $Type (keys(%{$OS_AddPath{$OSgroup}}))
+    { # additional search paths
+        next if($Type eq "include" and not $HSearch);
+        next if($Type eq "lib" and not $LSearch);
+        next if($Type eq "bin" and not $BSearch);
+        foreach my $Path (keys(%{$OS_AddPath{$OSgroup}{$Type}}))
+        {
+            next if(not -d $Path);
+            $SystemPaths{$Type}{$Path} = $OS_AddPath{$OSgroup}{$Type}{$Path};
+        }
+    }
+    if($OSgroup ne "windows")
+    { # unix-like
+        foreach my $Type ("include", "lib", "bin")
+        { # automatic detection of system "devel" directories
+            next if($Type eq "include" and not $HSearch);
+            next if($Type eq "lib" and not $LSearch);
+            next if($Type eq "bin" and not $BSearch);
+            my ($UsrDir, $RootDir) = ("/usr", "/");
+            if($SystemRoot and $Type ne "bin")
+            { # 1. search for target headers and libraries
+              # 2. use host commands: ldconfig, readelf, etc.
+                ($UsrDir, $RootDir) = ("$SystemRoot/usr", $SystemRoot);
+            }
+            foreach my $Path (cmd_find($RootDir,"d","*$Type*",1)) {
+                $SystemPaths{$Type}{$Path} = 1;
+            }
+            if(-d $RootDir."/".$Type)
+            { # if "/lib" is symbolic link
+                if($RootDir eq "/") {
+                    $SystemPaths{$Type}{"/".$Type} = 1;
+                }
+                else {
+                    $SystemPaths{$Type}{$RootDir."/".$Type} = 1;
+                }
+            }
+            if(-d $UsrDir) {
+                foreach my $Path (cmd_find($UsrDir,"d","*$Type*",1)) {
+                    $SystemPaths{$Type}{$Path} = 1;
+                }
+                if(-d $UsrDir."/".$Type)
+                { # if "/usr/lib" is symbolic link
+                    $SystemPaths{$Type}{$UsrDir."/".$Type} = 1;
+                }
+            }
+        }
+    }
+    if($BSearch)
+    {
+        detect_bin_default_paths();
+        foreach my $Path (keys(%DefaultBinPaths)) {
+            $SystemPaths{"bin"}{$Path} = $DefaultBinPaths{$Path};
+        }
+    }
+    # check environment variables
+    if($OSgroup eq "beos")
+    {
+        foreach (keys(%{$SystemPaths{"bin"}}))
+        {
+            if($_ eq ".") {
+                next;
+            }
+            foreach my $Path (cmd_find($_, "d", "bin", ""))
+            { # search for /boot/develop/abi/x86/gcc4/tools/gcc-4.4.4-haiku-101111/bin/
+                $SystemPaths{"bin"}{$Path} = 1;
+            }
+        }
+        if($HSearch)
+        {
+            foreach my $Path (split(/:|;/, $ENV{"BEINCLUDES"}))
+            {
+                if(is_abs($Path)) {
+                    $DefaultIncPaths{$Path} = 1;
+                }
+            }
+        }
+        if($LSearch)
+        {
+            foreach my $Path (split(/:|;/, $ENV{"BELIBRARIES"}), split(/:|;/, $ENV{"LIBRARY_PATH"}))
+            {
+                if(is_abs($Path)) {
+                    $DefaultLibPaths{$Path} = 1;
+                }
+            }
+        }
+    }
+    if($LSearch)
+    { # using linker to get system paths
+        if(my $LPaths = detect_lib_default_paths())
+        { # unix-like
+            foreach my $Name (keys(%{$LPaths}))
+            {
+                if($SystemRoot
+                and $LPaths->{$Name}!~/\A\Q$SystemRoot\E\//)
+                { # wrong ldconfig configuration
+                  # check your <sysroot>/etc/ld.so.conf
+                    next;
+                }
+                $DyLib_DefaultPath{$Name} = $LPaths->{$Name};
+                $DefaultLibPaths{get_dirname($LPaths->{$Name})} = 1;
+            }
+        }
+        foreach my $Path (keys(%DefaultLibPaths)) {
+            $SystemPaths{"lib"}{$Path} = $DefaultLibPaths{$Path};
+        }
+    }
+    if($BSearch)
+    {
+        if($CrossGcc)
+        { # --cross-gcc=arm-linux-gcc
+            if(-e $CrossGcc)
+            { # absolute or relative path
+                $GCC_PATH = get_abs_path($CrossGcc);
+            }
+            elsif($CrossGcc!~/\// and get_CmdPath($CrossGcc))
+            { # command name
+                $GCC_PATH = $CrossGcc;
+            }
+            else {
+                exitStatus("Access_Error", "can't access \'$CrossGcc\'");
+            }
+            if($GCC_PATH=~/\s/) {
+                $GCC_PATH = "\"".$GCC_PATH."\"";
+            }
+        }
+    }
+    if($GSearch)
+    { # GCC path and default include dirs
+        if(not $CrossGcc) {
+            $GCC_PATH = get_CmdPath("gcc");
+        }
+        if(not $GCC_PATH) {
+            exitStatus("Not_Found", "can't find GCC>=3.0 in PATH");
+        }
+        if(not $CheckObjectsOnly_Opt)
+        {
+            if(my $GCC_Ver = get_dumpversion($GCC_PATH))
+            {
+                my $GccTarget = get_dumpmachine($GCC_PATH);
+                printMsg("INFO", "Using GCC $GCC_Ver ($GccTarget)");
+                if($GccTarget=~/symbian/)
+                {
+                    $OStarget = "symbian";
+                    $LIB_EXT = $OS_LibExt{$LIB_TYPE}{$OStarget};
+                }
+            }
+            else {
+                exitStatus("Error", "something is going wrong with the GCC compiler");
+            }
+        }
+        if(not $NoStdInc)
+        { # do NOT search in GCC standard paths
+            my %DPaths = detect_inc_default_paths();
+            %DefaultCppPaths = %{$DPaths{"Cpp"}};
+            %DefaultGccPaths = %{$DPaths{"Gcc"}};
+            %DefaultIncPaths = %{$DPaths{"Inc"}};
+            foreach my $Path (keys(%DefaultIncPaths)) {
+                $SystemPaths{"include"}{$Path} = $DefaultIncPaths{$Path};
+            }
+        }
+    }
+    if($HSearch)
+    { # user include paths
+        if(-d $SystemRoot."/usr/include") {
+            $UserIncPath{$SystemRoot."/usr/include"}=1;
+        }
+    }
+}
+
+sub getLIB_EXT($)
+{
+    my $Target = $_[0];
+    if(my $Ext = $OS_LibExt{$LIB_TYPE}{$Target}) {
+        return $Ext;
+    }
+    return $OS_LibExt{$LIB_TYPE}{"default"};
+}
+
+sub getAR_EXT($)
+{
+    my $Target = $_[0];
+    if(my $Ext = $OS_Archive{$Target}) {
+        return $Ext;
+    }
+    return $OS_Archive{"default"};
+}
+
+sub get_dumpversion($)
+{
+    my $Cmd = $_[0];
+    return "" if(not $Cmd);
+    if($Cache{"get_dumpversion"}{$Cmd}) {
+        return $Cache{"get_dumpversion"}{$Cmd};
+    }
+    my $V = `$Cmd -dumpversion 2>$TMP_DIR/null`;
+    chomp($V);
+    return ($Cache{"get_dumpversion"}{$Cmd} = $V);
+}
+
+sub get_dumpmachine($)
+{
+    my $Cmd = $_[0];
+    return "" if(not $Cmd);
+    if($Cache{"get_dumpmachine"}{$Cmd}) {
+        return $Cache{"get_dumpmachine"}{$Cmd};
+    }
+    my $Machine = `$Cmd -dumpmachine 2>$TMP_DIR/null`;
+    chomp($Machine);
+    return ($Cache{"get_dumpmachine"}{$Cmd} = $Machine);
+}
+
+sub check_command($)
+{
+    my $Cmd = $_[0];
+    return "" if(not $Cmd);
+    my @Options = (
+        "--version",
+        "-help"
+    );
+    foreach my $Opt (@Options)
+    {
+        my $Info = `$Cmd $Opt 2>$TMP_DIR/null`;
+        if($Info) {
+            return 1;
+        }
+    }
+    return 0;
+}
+
+sub check_gcc_version($$)
+{
+    my ($Cmd, $Req_V) = @_;
+    return 0 if(not $Cmd or not $Req_V);
+    my $Gcc_V = get_dumpversion($Cmd);
+    $Gcc_V=~s/(-|_)[a-z_]+.*\Z//; # remove suffix (like "-haiku-100818")
+    if(cmpVersions($Gcc_V, $Req_V)>=0) {
+        return $Cmd;
+    }
+    return "";
+}
+
+sub get_depth($)
+{
+    if(defined $Cache{"get_depth"}{$_[0]}) {
+        return $Cache{"get_depth"}{$_[0]}
+    }
+    return ($Cache{"get_depth"}{$_[0]} = ($_[0]=~tr![\/\\]|\:\:!!));
+}
+
+sub find_gcc_cxx_headers($)
+{
+    my $LibVersion = $_[0];
+    return if($Cache{"find_gcc_cxx_headers"});# this function should be called once
+    # detecting system header paths
+    foreach my $Path (sort {get_depth($b) <=> get_depth($a)} keys(%DefaultGccPaths))
+    {
+        foreach my $HeaderPath (sort {get_depth($a) <=> get_depth($b)} cmd_find($Path,"f","",""))
+        {
+            my $FileName = get_filename($HeaderPath);
+            next if($DefaultGccHeader{$FileName});
+            $DefaultGccHeader{$FileName} = $HeaderPath;
+        }
+    }
+    if($COMMON_LANGUAGE{$LibVersion} eq "C++" and not $STDCXX_TESTING)
+    {
+        foreach my $CppDir (sort {get_depth($b)<=>get_depth($a)} keys(%DefaultCppPaths))
+        {
+            my @AllCppHeaders = cmd_find($CppDir,"f","","");
+            foreach my $Path (sort {get_depth($a)<=>get_depth($b)} @AllCppHeaders)
+            {
+                my $FileName = get_filename($Path);
+                next if($DefaultCppHeader{$FileName});
+                $DefaultCppHeader{$FileName} = $Path;
+            }
+        }
+    }
+    $Cache{"find_gcc_cxx_headers"} = 1;
+}
+
+sub parse_libname($$$)
+{
+    my ($Name, $Type, $Target) = @_;
+    if($Target eq "symbian") {
+        return parse_libname_symbian($Name, $Type);
+    }
+    elsif($Target eq "windows") {
+        return parse_libname_windows($Name, $Type);
+    }
+    my $Ext = getLIB_EXT($Target);
+    if($Name=~/((((lib|).+?)([\-\_][\d\-\.\_]+|))\.$Ext)(\.(.+)|)\Z/)
+    { # libSDL-1.2.so.0.7.1
+      # libwbxml2.so.0.0.18
+        if($Type eq "name")
+        { # libSDL-1.2
+          # libwbxml2
+            return $2;
+        }
+        elsif($Type eq "name+ext")
+        { # libSDL-1.2.so
+          # libwbxml2.so
+            return $1;
+        }
+        elsif($Type eq "version")
+        {
+            if($7 ne "")
+            { # 0.7.1
+                return $7;
+            }
+            else
+            { # libc-2.5.so (=>2.5 version)
+                my $MV = $5;
+                $MV=~s/\A[\-\_]+//g;
+                return $MV;
+            }
+        }
+        elsif($Type eq "short")
+        { # libSDL
+          # libwbxml2
+            return $3;
+        }
+        elsif($Type eq "shortest")
+        { # SDL
+          # wbxml
+            return shortest_name($3);
+        }
+    }
+    return "";# error
+}
+
+sub parse_libname_symbian($$)
+{
+    my ($Name, $Type) = @_;
+    my $Ext = getLIB_EXT("symbian");
+    if($Name=~/(((.+?)(\{.+\}|))\.$Ext)\Z/)
+    { # libpthread{00010001}.dso
+        if($Type eq "name")
+        { # libpthread{00010001}
+            return $2;
+        }
+        elsif($Type eq "name+ext")
+        { # libpthread{00010001}.dso
+            return $1;
+        }
+        elsif($Type eq "version")
+        { # 00010001
+            my $V = $4;
+            $V=~s/\{(.+)\}/$1/;
+            return $V;
+        }
+        elsif($Type eq "short")
+        { # libpthread
+            return $3;
+        }
+        elsif($Type eq "shortest")
+        { # pthread
+            return shortest_name($3);
+        }
+    }
+    return "";# error
+}
+
+sub parse_libname_windows($$)
+{
+    my ($Name, $Type) = @_;
+    my $Ext = getLIB_EXT("windows");
+    if($Name=~/((.+?)\.$Ext)\Z/)
+    { # netapi32.dll
+        if($Type eq "name")
+        { # netapi32
+            return $2;
+        }
+        elsif($Type eq "name+ext")
+        { # netapi32.dll
+            return $1;
+        }
+        elsif($Type eq "version")
+        { # DLL version embedded
+          # at binary-level
+            return "";
+        }
+        elsif($Type eq "short")
+        { # netapi32
+            return $2;
+        }
+        elsif($Type eq "shortest")
+        { # netapi
+            return shortest_name($2);
+        }
+    }
+    return "";# error
+}
+
+sub shortest_name($)
+{
+    my $Name = $_[0];
+    # remove prefix
+    $Name=~s/\A(lib|open)//;
+    # remove suffix
+    $Name=~s/[\W\d_]+\Z//i;
+    $Name=~s/([a-z]{2,})(lib)\Z/$1/i;
+    return $Name;
+}
+
+sub getPrefix($)
+{
+    my $Str = $_[0];
+    if($Str=~/\A(Get|get|Set|set)([A-Z]|_)/)
+    {# GetError
+        return "";
+    }
+    if($Str=~/\A([_]*[A-Z][a-z]{1,5})[A-Z]/)
+    {# XmuValidArea: Xmu
+        return $1;
+    }
+    elsif($Str=~/\A([_]*[a-z]+)[A-Z]/)
+    {# snfReadFont: snf
+        return $1;
+    }
+    elsif($Str=~/\A([_]*[A-Z]{2,})[A-Z][a-z]+([A-Z][a-z]+|\Z)/)
+    {# XRRTimes: XRR
+        return $1;
+    }
+    elsif($Str=~/\A([_]*[a-z0-9]{2,}_)[a-z]+/i)
+    {# alarm_event_add: alarm_
+        return $1;
+    }
+    elsif($Str=~/\A(([a-z])\2{1,})/i)
+    {# ffopen
+        return $1;
+    }
+    else {
+        return "";
+    }
+}
+
+sub problem_title($)
+{
+    if($_[0]==1)  {
+        return "1 problem";
+    }
+    else  {
+        return $_[0]." problems";
+    }
+}
+
+sub warning_title($)
+{
+    if($_[0]==1)  {
+        return "1 warning";
+    }
+    else  {
+        return $_[0]." warnings";
+    }
+}
+
+sub createSymbolsList($$$$$)
+{
+    my ($DPath, $SaveTo, $LName, $LVersion, $ArchName) = @_;
+    read_ABI_Dump(1, $DPath);
+    if(not $CheckObjectsOnly) {
+        prepareInterfaces(1);
+    }
+    my %SymbolHeaderLib = ();
+    my $Total = 0;
+    # Get List
+    foreach my $Symbol (sort keys(%{$CompleteSignature{1}}))
+    {
+        if(not link_symbol($Symbol, 1, "-Deps"))
+        {# skip src only and all external functions
+            next;
+        }
+        if(not symbolFilter($Symbol, 1, "Public"))
+        { # skip other symbols
+            next;
+        }
+        my $HeaderName = $CompleteSignature{1}{$Symbol}{"Header"};
+        if(not $HeaderName)
+        {# skip src only and all external functions
+            next;
+        }
+        my $DyLib = $Symbol_Library{1}{$Symbol};
+        if(not $DyLib)
+        {# skip src only and all external functions
+            next;
+        }
+        $SymbolHeaderLib{$HeaderName}{$DyLib}{$Symbol} = 1;
+        $Total+=1;
+    }
+    # Draw List
+    my $SYMBOLS_LIST = "<h1>Public symbols in <span style='color:Blue;'>$LName</span> (<span style='color:Red;'>$LVersion</span>)";
+    $SYMBOLS_LIST .= " on <span style='color:Blue;'>".showArch($ArchName)."</span><br/>Total: $Total</h1><br/>";
+    foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%SymbolHeaderLib))
+    {
+        foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$SymbolHeaderLib{$HeaderName}}))
+        {
+            if($HeaderName and $DyLib) {
+                $SYMBOLS_LIST .= "<span class='h_name'>$HeaderName</span>, <span class='lib_name'>$DyLib</span><br/>\n";
+            }
+            elsif($DyLib) {
+                $SYMBOLS_LIST .= "<span class='lib_name'>$DyLib</span><br/>\n";
+            }
+            elsif($HeaderName) {
+                $SYMBOLS_LIST .= "<span class='h_name'>$HeaderName</span><br/>\n";
+            }
+            my %NS_Symbol = ();
+            foreach my $Symbol (keys(%{$SymbolHeaderLib{$HeaderName}{$DyLib}})) {
+                $NS_Symbol{get_IntNameSpace($Symbol, 1)}{$Symbol} = 1;
+            }
+            foreach my $NameSpace (sort keys(%NS_Symbol))
+            {
+                $SYMBOLS_LIST .= ($NameSpace)?"<span class='ns_title'>namespace</span> <span class='ns'>$NameSpace</span>"."<br/>\n":"";
+                my @SortedInterfaces = sort {lc(get_Signature($a, 1)) cmp lc(get_Signature($b, 1))} keys(%{$NS_Symbol{$NameSpace}});
+                foreach my $Symbol (@SortedInterfaces)
+                {
+                    my $SubReport = "";
+                    my $Signature = get_Signature($Symbol, 1);
+                    if($NameSpace) {
+                        $Signature=~s/(\W|\A)\Q$NameSpace\E\:\:(\w)/$1$2/g;
+                    }
+                    if($Symbol=~/\A(_Z|\?)/)
+                    {
+                        if($Signature) {
+                            $SubReport = insertIDs($ContentSpanStart.highLight_Signature_Italic_Color($Signature).$ContentSpanEnd."<br/>\n".$ContentDivStart."<span class='mangled'>[ symbol: <b>$Symbol</b> ]</span><br/><br/>".$ContentDivEnd."\n");
+                        }# report_added
+                        else {
+                            $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
+                        }
+                    }
+                    else
+                    {
+                        if($Signature) {
+                            $SubReport = "<span class='iname'>".highLight_Signature_Italic_Color($Signature)."</span><br/>\n";
+                        }
+                        else {
+                            $SubReport = "<span class='iname'>".$Symbol."</span><br/>\n";
+                        }
+                    }
+                    $SYMBOLS_LIST .= $SubReport;
+                }
+            }
+            $SYMBOLS_LIST .= "<br/>\n";
+        }
+    }
+    # Clear Info
+    (%TypeInfo, %SymbolInfo, %Library_Symbol,
+    %DepSymbols, %SymVer, %Tid_TDid, %SkipTypes,
+    %SkipSymbols, %NestedNameSpaces, %ClassMethods,
+    %AllocableClass, %ClassToId, %CompleteSignature,
+    %SkipNameSpaces, %Symbol_Library) = ();
+    ($Content_Counter, $ContentID) = (0, 0);
+    # Print Report
+    my $CssStyles = readStyles("SymbolsList.css");
+    $SYMBOLS_LIST = "<a name='Top'></a>".$SYMBOLS_LIST."<a style='font-size:11px;' href='#Top'>to the top</a><br/>\n";
+    my $Title = "$LName: public symbols";
+    my $Keywords = "$LName, API, symbols";
+    my $Description = "List of symbols in $LName ($LVersion) on ".showArch($ArchName);
+    $SYMBOLS_LIST = composeHTML_Head($Title, $Keywords, $Description, $CssStyles."\n".$JScripts)."
+    <body><div>\n$SYMBOLS_LIST</div>
+    <br/><br/><hr/>\n".getReportFooter($LName)."
+    <div style='height:999px;'></div></body></html>";
+    writeFile($SaveTo, $SYMBOLS_LIST);
+}
+
+sub readStyles($)
+{
+    my $Name = $_[0];
+    my $Path = $MODULES_DIR."/Internals/Styles/".$Name;
+    if(not -f $Path) {
+        exitStatus("Module_Error", "can't access \'$Path\'");
+    }
+    my $Styles = readFile($Path);
+    return "<style type=\"text/css\">\n".$Styles."\n</style>";
+}
+
+sub is_target_lib($)
+{
+    my $LName = $_[0];
+    if($TargetLibraryName
+    and $LName!~/\Q$TargetLibraryName\E/) {
+        return 0;
+    }
+    if(keys(%TargetLibs)
+    and not $TargetLibs{$LName}
+    and not $TargetLibs{parse_libname($LName, "name+ext", $OStarget)}) {
+        return 0;
+    }
+    return 1;
+}
+
+sub is_target_header($)
+{ # --header, --headers-list
+    if(keys(%{$TargetHeaders{1}})
+    or keys(%{$TargetHeaders{2}}))
+    {
+        if(not $TargetHeaders{1}{$_[0]}
+        and not $TargetHeaders{2}{$_[0]})
+        {
+            return 0;
+        }
+    }
+    return 1;
+}
+
+sub checkVersionNum($$)
+{
+    my ($LibVersion, $Path) = @_;
+    if(my $VerNum = $TargetVersion{$LibVersion}) {
+        return $VerNum;
+    }
+    my $UsedAltDescr = 0;
+    foreach my $Part (split(/\s*,\s*/, $Path))
+    {# try to get version string from file path
+        next if($Part=~/\.xml\Z/i);
+        next if(isDump($Part));
+        if(parse_libname($Part, "version", $OStarget)
+        or is_header($Part, 2, $LibVersion) or -d $Part)
+        {
+            $UsedAltDescr = 1;
+            if(my $VerNum = readStringVersion($Part))
+            {
+                $TargetVersion{$LibVersion} = $VerNum;
+                if($DumpAPI) {
+                    printMsg("WARNING", "setting version number to $VerNum (use -vnum <num> option to change it)");
+                }
+                else {
+                    printMsg("WARNING", "setting ".($LibVersion==1?"1st":"2nd")." version number to \"$VerNum\" (use -v$LibVersion <num> option to change it)");
+                }
+                return $TargetVersion{$LibVersion};
+            }
+        }
+    }
+    if($UsedAltDescr)
+    {
+        if($DumpAPI) {
+            exitStatus("Error", "version number is not set (use -vnum <num> option)");
+        }
+        else {
+            exitStatus("Error", ($LibVersion==1?"1st":"2nd")." version number is not set (use -v$LibVersion <num> option)");
+        }
+    }
+}
+
+sub readStringVersion($)
+{
+    my $Str = $_[0];
+    return "" if(not $Str);
+    $Str=~s/\Q$TargetLibraryName\E//g;
+    if($Str=~/(\/|\\|\w|\A)[\-\_]*(\d+[\d\.\-]+\d+|\d+)/)
+    {# .../libssh-0.4.0/...
+        return $2;
+    }
+    elsif(my $V = parse_libname($Str, "version", $OStarget)) {
+        return $V;
+    }
+    return "";
+}
+
+sub readLibs($)
+{
+    my $LibVersion = $_[0];
+    if($OStarget eq "windows")
+    { # dumpbin.exe will crash
+        # without VS Environment
+        check_win32_env();
+    }
+    getSymbols($LibVersion);
+    translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
+    translateSymbols(keys(%{$DepSymbols{$LibVersion}}), $LibVersion);
+}
+
+sub dump_sorting($)
+{
+    my $hash = $_[0];
+    return [] if(not $hash or not keys(%{$hash}));
+    if((keys(%{$hash}))[0]=~/\A\d+\Z/) {
+        return [sort {int($a) <=> int($b)} keys(%{$hash})];
+    }
+    else {
+        return [sort {$a cmp $b} keys(%{$hash})];
+    }
+}
+
+sub printMsg($$)
+{
+    my ($Type, $Msg) = @_;
+    if($Type!~/\AINFO/) {
+        $Msg = $Type.": ".$Msg;
+    }
+    if($Type!~/_C\Z/) {
+        $Msg .= "\n";
+    }
+    if($Quiet)
+    { # --quiet option
+        appendFile($COMMON_LOG_PATH, $Msg);
+    }
+    else
+    {
+        if($Type eq "ERROR") {
+            print STDERR $Msg;
+        }
+        else {
+            print $Msg;
+        }
+    }
+}
+
+sub exitStatus($$)
+{
+    my ($Code, $Msg) = @_;
+    printMsg("ERROR", $Msg);
+    exit($ERROR_CODE{$Code});
+}
+
+sub exitReport()
+{ # the tool has run without any errors
+    printReport();
+    if($COMPILE_ERRORS)
+    { # errors in headers may add false positives/negatives
+        exit($ERROR_CODE{"Compile_Error"});
+    }
+    if($RESULT{"Problems"}) {
+        exit($ERROR_CODE{"Incompatible"});
+    }
+    else {
+        exit($ERROR_CODE{"Compatible"});
+    }
+}
+
+sub readRules($)
+{
+    my $Kind = $_[0];
+    if(not -f $RULES_PATH{$Kind}) {
+        exitStatus("Module_Error", "can't access \'".$RULES_PATH{$Kind}."\'");
+    }
+    my $Content = readFile($RULES_PATH{$Kind});
+    while(my $Rule = parseTag(\$Content, "rule"))
+    {
+        my $RId = parseTag(\$Rule, "id");
+        my @Properties = ("Severity", "Change", "Effect", "Overcome", "Kind");
+        foreach my $Prop (@Properties) {
+            if(my $Value = parseTag(\$Rule, lc($Prop)))
+            {
+                $Value=~s/\n[ ]*//;
+                $CompatRules{$Kind}{$RId}{$Prop} = $Value;
+            }
+        }
+        if($CompatRules{$Kind}{$RId}{"Kind"}=~/\A(Symbols|Parameters)\Z/) {
+            $CompatRules{$Kind}{$RId}{"Kind"} = "Symbols";
+        }
+        else {
+            $CompatRules{$Kind}{$RId}{"Kind"} = "Types";
+        }
+    }
+}
+
+sub printReport()
+{
+    printMsg("INFO", "creating compatibility report ...");
+    my $ReportPath = $OutputReportPath;
+    if(not $ReportPath) {
+        $ReportPath = "compat_reports/$TargetLibraryName/".$Descriptor{1}{"Version"}."_to_".$Descriptor{2}{"Version"}."/abi_compat_report.$ReportFormat";
+    }
+    createHtmlReport($ReportPath);
+    if($ListAffected)
+    { # --list-affected
+        my $List = "";
+        foreach (keys(%{$TotalAffected{"Binary"}}))
+        {
+            if($StrictCompat and $TotalAffected{"Binary"}{$_} eq "Low")
+            { # skip "Low"-severity problems
+                next;
+            }
+            $List .= "$_\n";
+        }
+        writeFile(get_dirname($ReportPath)."/abi_affected.txt", $List);
+    }
+    if($RESULT{"Problems"}) {
+        printMsg("INFO", "result: INCOMPATIBLE ".$RESULT{"Affected"}."\% (total problems: ".$RESULT{"Problems"}.", warnings: ".$RESULT{"Warnings"}.")");
+    }
+    else {
+        printMsg("INFO", "result: COMPATIBLE (total problems: ".$RESULT{"Problems"}.", warnings: ".$RESULT{"Warnings"}.")");
+    }
+    if($StdOut) {
+        printMsg("INFO", "compatibility report has been generated to stdout");
+    }
+    else {
+        printMsg("INFO", "see detailed report:\n  $ReportPath");
+    }
+}
+
+sub check_win32_env()
+{
+    if(not $ENV{"DevEnvDir"}
+    or not $ENV{"LIB"}) {
+        exitStatus("Error", "can't start without VS environment (vsvars32.bat)");
+    }
+}
+
+sub create_ABI_Dump()
+{
+    if(not -e $DumpAPI) {
+        exitStatus("Access_Error", "can't access \'$DumpAPI\'");
+    }
+    # check the archive utilities
+    if($OSgroup eq "windows")
+    { # using zip
+        my $ZipCmd = get_CmdPath("zip");
+        if(not $ZipCmd) {
+            exitStatus("Not_Found", "can't find \"zip\"");
+        }
+    }
+    else
+    { # using tar and gzip
+        my $TarCmd = get_CmdPath("tar");
+        if(not $TarCmd) {
+            exitStatus("Not_Found", "can't find \"tar\"");
+        }
+        my $GzipCmd = get_CmdPath("gzip");
+        if(not $GzipCmd) {
+            exitStatus("Not_Found", "can't find \"gzip\"");
+        }
+    }
+    my @DParts = split(/\s*,\s*/, $DumpAPI);
+    foreach my $Part (@DParts)
+    {
+        if(not -e $Part) {
+            exitStatus("Access_Error", "can't access \'$Part\'");
+        }
+    }
+    checkVersionNum(1, $DumpAPI);
+    foreach my $Part (@DParts)
+    {
+        if(isDump($Part)) {
+            read_ABI_Dump(1, $Part);
+        }
+        else {
+            readDescriptor(1, createDescriptor(1, $Part));
+        }
+    }
+    initLogging(1);
+    detect_default_paths("inc|lib|bin|gcc"); # complete analysis
+    if(not $CheckHeadersOnly) {
+        readLibs(1);
+    }
+    if($CheckHeadersOnly) {
+        setLanguage(1, "C++");
+    }
+    if(not $CheckObjectsOnly) {
+        searchForHeaders(1);
+    }
+    $WORD_SIZE{1} = detectWordSize();
+    if($Descriptor{1}{"Headers"}
+    and not $Descriptor{1}{"Dump"}) {
+        readHeaders(1);
+    }
+    if($ExtendedCheck)
+    { # --ext option
+        addExtension(1);
+    }
+    formatDump(1);
+    if(not keys(%{$SymbolInfo{1}}))
+    { # check if created dump is valid
+        if(not $ExtendedCheck and not $CheckObjectsOnly)
+        {
+            if($CheckHeadersOnly) {
+                exitStatus("Empty_Set", "the set of public symbols is empty");
+            }
+            else {
+                exitStatus("Empty_Intersection", "the sets of public symbols in headers and libraries have empty intersection");
+            }
+        }
+    }
+    my %HeadersInfo = ();
+    foreach my $HPath (keys(%{$Registered_Headers{1}}))
+    { # headers info stored without paths in the dump
+        $HeadersInfo{$Registered_Headers{1}{$HPath}{"Identity"}} = $Registered_Headers{1}{$HPath}{"Pos"};
+    }
+    printMsg("INFO", "creating library ABI dump ...");
+    my %LibraryABI = (
+        "TypeInfo" => $TypeInfo{1},
+        "SymbolInfo" => $SymbolInfo{1},
+        "Symbols" => $Library_Symbol{1},
+        "DepSymbols" => $DepSymbols{1},
+        "SymbolVersion" => $SymVer{1},
+        "LibraryVersion" => $Descriptor{1}{"Version"},
+        "LibraryName" => $TargetLibraryName,
+        "Language" => $COMMON_LANGUAGE{1},
+        "Tid_TDid" => $Tid_TDid{1},
+        "SkipTypes" => $SkipTypes{1},
+        "SkipSymbols" => $SkipSymbols{1},
+        "SkipNameSpaces" => $SkipNameSpaces{1},
+        "SkipHeaders" => $SkipHeadersList{1},
+        "TargetHeaders" => $TargetHeaders{1},
+        "Headers" => \%HeadersInfo,
+        "Constants" => $Constants{1},
+        "NameSpaces" => $NestedNameSpaces{1},
+        "Target" => $OStarget,
+        "Arch" => getArch(1),
+        "WordSize" => $WORD_SIZE{1},
+        "GccVersion" => get_dumpversion($GCC_PATH),
+        "ABI_DUMP_VERSION" => $ABI_DUMP_VERSION,
+        "ABI_COMPLIANCE_CHECKER_VERSION" => $TOOL_VERSION
+    );
+    if($ExtendedCheck)
+    { # --ext option
+        $LibraryABI{"Mode"} = "Extended";
+    }
+    if($StdOut)
+    { # --stdout option
+        print STDOUT Dumper(\%LibraryABI);
+        printMsg("INFO", "ABI dump has been generated to stdout");
+        return;
+    }
+    else
+    { # write to gzipped file
+        my $DumpPath = "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi.".$AR_EXT;
+        if($OutputDumpPath)
+        { # user defined path
+            $DumpPath = $OutputDumpPath;
+        }
+        if(not $DumpPath=~s/\Q.$AR_EXT\E\Z//g) {
+            exitStatus("Error", "the dump path (-dump-path option) should be the path to a *.$AR_EXT file");
+        }
+        my ($DDir, $DName) = separate_path($DumpPath);
+        my $DPath = $TMP_DIR."/".$DName;
+        mkpath($DDir);
+        writeFile($DPath, Dumper(\%LibraryABI));
+        if(not -s $DPath) {
+            exitStatus("Error", "can't create ABI dump because something is going wrong with the Data::Dumper module");
+        }
+        my $Pkg = createArchive($DPath, $DDir);
+        printMsg("INFO", "library ABI has been dumped to:\n  $Pkg");
+        printMsg("INFO", "you can transfer this dump everywhere and use instead of the ".$Descriptor{1}{"Version"}." version descriptor");
+    }
+}
+
+sub quickEmptyReports()
+{ # Quick "empty" reports
+  # 4 times faster than merging equal dumps
+  # NOTE: the dump contains the "LibraryVersion" attribute
+  # if you change the version, then your dump will be different
+  # OVERCOME: use -v1 and v2 options for comparing dumps
+  # and don't change version in the XML descriptor (and dumps)
+  # OVERCOME 2: separate meta info from the dumps in ACC 2.0
+    if(-s $Descriptor{1}{"Path"} == -s $Descriptor{2}{"Path"})
+    {
+        my $FilePath1 = unpackDump($Descriptor{1}{"Path"});
+        my $FilePath2 = unpackDump($Descriptor{2}{"Path"});
+        if($FilePath1 and $FilePath2)
+        {
+            my $Content = readFile($FilePath1);
+            if($Content eq readFile($FilePath2))
+            {
+                # read a number of headers, libs, symbols and types
+                my $ABIdump = eval($Content);
+                if(not $ABIdump) {
+                    exitStatus("Error", "internal error");
+                }
+                if(not $ABIdump->{"TypeInfo"})
+                {# support for old dumps
+                    $ABIdump->{"TypeInfo"} = $ABIdump->{"TypeDescr"};
+                }
+                if(not $ABIdump->{"SymbolInfo"})
+                {# support for old dumps
+                    $ABIdump->{"SymbolInfo"} = $ABIdump->{"FuncDescr"};
+                }
+                read_Headers_DumpInfo($ABIdump, 1);
+                read_Libs_DumpInfo($ABIdump, 1);
+                read_Machine_DumpInfo($ABIdump, 1);
+                read_Machine_DumpInfo($ABIdump, 2);
+                %CheckedTypes = %{$ABIdump->{"TypeInfo"}};
+                %CheckedSymbols = %{$ABIdump->{"SymbolInfo"}};
+                $Descriptor{1}{"Version"} = $TargetVersion{1}?$TargetVersion{1}:$ABIdump->{"LibraryVersion"};
+                $Descriptor{2}{"Version"} = $TargetVersion{2}?$TargetVersion{2}:$ABIdump->{"LibraryVersion"};
+                exitReport();
+            }
+        }
+    }
+}
+
+sub initLogging($)
+{
+    my $LibVersion = $_[0];
+    # create log directory
+    my ($LOG_DIR, $LOG_FILE) = ("logs/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"}, "log.txt");
+    if($OutputLogPath{$LibVersion})
+    { # user-defined by -log-path option
+        ($LOG_DIR, $LOG_FILE) = separate_path($OutputLogPath{$LibVersion});
+    }
+    if($LogMode ne "n") {
+        mkpath($LOG_DIR);
+    }
+    $LOG_PATH{$LibVersion} = get_abs_path($LOG_DIR)."/".$LOG_FILE;
+    resetLogging($LibVersion);
+    if($Debug)
+    { # debug directory
+        $DEBUG_PATH{$LibVersion} = "debug/$TargetLibraryName/".$Descriptor{$LibVersion}{"Version"};
+        rmtree($DEBUG_PATH{$LibVersion});
+    }
+}
+
+sub writeLog($$)
+{
+    my ($LibVersion, $Msg) = @_;
+    if($LogMode ne "n") {
+        appendFile($LOG_PATH{$LibVersion}, $Msg);
+    }
+}
+
+sub resetLogging($)
+{
+    my $LibVersion = $_[0];
+    if($LogMode!~/a|n/)
+    { # remove old log
+        unlink($LOG_PATH{$LibVersion});
+    }
+}
+
+sub printErrorLog($)
+{
+    my $LibVersion = $_[0];
+    if($LogMode ne "n") {
+        printMsg("ERROR", "see log for details:\n  ".$LOG_PATH{$LibVersion}."\n");
+    }
+}
+
+sub isDump($)
+{
+    if(get_filename($_[0])=~/\A(.+)\.abi(\Q.tar.gz\E|\Q.zip\E|)\Z/)
+    { # returns a name of package
+        return $1;
+    }
+    return 0;
+}
+
+sub compareAPIs()
+{
+    # read input XML descriptors or ABI dumps
+    if(not $Descriptor{1}{"Path"}) {
+        exitStatus("Error", "-d1 option is not specified");
+    }
+    my @DParts1 = split(/\s*,\s*/, $Descriptor{1}{"Path"});
+    foreach my $Part (@DParts1)
+    {
+        if(not -e $Part) {
+            exitStatus("Access_Error", "can't access \'$Part\'");
+        }
+    }
+    if(not $Descriptor{2}{"Path"}) {
+        exitStatus("Error", "-d2 option is not specified");
+    }
+    my @DParts2 = split(/\s*,\s*/, $Descriptor{2}{"Path"});
+    foreach my $Part (@DParts2)
+    {
+        if(not -e $Part) {
+            exitStatus("Access_Error", "can't access \'$Part\'");
+        }
+    }
+    detect_default_paths("bin"); # to extract dumps
+    if($#DParts1==0 and $#DParts2==0
+    and isDump($Descriptor{1}{"Path"})
+    and isDump($Descriptor{2}{"Path"}))
+    { # optimization: equal ABI dumps
+        quickEmptyReports();
+    }
+    checkVersionNum(1, $Descriptor{1}{"Path"});
+    checkVersionNum(2, $Descriptor{2}{"Path"});
+    printMsg("INFO", "preparation, please wait ...");
+    foreach my $Part (@DParts1)
+    {
+        if(isDump($Part)) {
+            read_ABI_Dump(1, $Part);
+        }
+        else {
+            readDescriptor(1, createDescriptor(1, $Part));
+        }
+    }
+    foreach my $Part (@DParts2)
+    {
+        if(isDump($Part)) {
+            read_ABI_Dump(2, $Part);
+        }
+        else {
+            readDescriptor(2, createDescriptor(2, $Part));
+        }
+    }
+    initLogging(1);
+    initLogging(2);
+    # check consistency
+    if(not $Descriptor{1}{"Headers"}
+    and not $Descriptor{1}{"Libs"}) {
+        exitStatus("Error", "descriptor d1 does not contain both header files and libraries info");
+    }
+    if(not $Descriptor{2}{"Headers"}
+    and not $Descriptor{2}{"Libs"}) {
+        exitStatus("Error", "descriptor d2 does not contain both header files and libraries info");
+    }
+    if($Descriptor{1}{"Headers"} and not $Descriptor{1}{"Libs"}
+    and not $Descriptor{2}{"Headers"} and $Descriptor{2}{"Libs"}) {
+        exitStatus("Error", "can't compare headers with $SLIB_TYPE libraries");
+    }
+    elsif(not $Descriptor{1}{"Headers"} and $Descriptor{1}{"Libs"}
+    and $Descriptor{2}{"Headers"} and not $Descriptor{2}{"Libs"}) {
+        exitStatus("Error", "can't compare $SLIB_TYPE libraries with headers");
+    }
+    if(not $Descriptor{1}{"Headers"}) {
+        if($CheckHeadersOnly_Opt) {
+            exitStatus("Error", "can't find header files info in descriptor d1");
+        }
+    }
+    if(not $Descriptor{2}{"Headers"}) {
+        if($CheckHeadersOnly_Opt) {
+            exitStatus("Error", "can't find header files info in descriptor d2");
+        }
+    }
+    if(not $Descriptor{1}{"Headers"}
+    or not $Descriptor{2}{"Headers"}) {
+        if(not $CheckObjectsOnly_Opt) {
+            printMsg("WARNING", "comparing $SLIB_TYPE libraries only");
+            $CheckObjectsOnly = 1;
+        }
+    }
+    if(not $Descriptor{1}{"Libs"}) {
+        if($CheckObjectsOnly_Opt) {
+            exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d1");
+        }
+    }
+    if(not $Descriptor{2}{"Libs"}) {
+        if($CheckObjectsOnly_Opt) {
+            exitStatus("Error", "can't find $SLIB_TYPE libraries info in descriptor d2");
+        }
+    }
+    if(not $Descriptor{1}{"Libs"}
+    or not $Descriptor{2}{"Libs"})
+    { # comparing standalone header files
+      # comparing ABI dumps created with --headers-only
+        if(not $CheckHeadersOnly_Opt)
+        {
+            printMsg("WARNING", "checking headers only");
+            $CheckHeadersOnly = 1;
+        }
+    }
+    if($UseDumps)
+    { # --use-dumps
+      # parallel processing
+        my $pid = fork();
+        if($pid)
+        { # dump on two CPU cores
+            my @PARAMS = ("-dump", $Descriptor{1}{"Path"}, "-l", $TargetLibraryName);
+            if($RelativeDirectory{1}) {
+                @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{1});
+            }
+            if($OutputLogPath{1}) {
+                @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{1});
+            }
+            if($CrossGcc) {
+                @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
+            }
+            if($Debug) {
+                @PARAMS = (@PARAMS, "-debug");
+            }
+            if($Quiet) {
+                @PARAMS = (@PARAMS, "-quiet");
+            }
+            if($ExtendedCheck) {
+                @PARAMS = (@PARAMS, "-extended");
+            }
+            if($UserLang) {
+                @PARAMS = (@PARAMS, "-lang", $UserLang);
+            }
+            if($TargetVersion{1}) {
+                @PARAMS = (@PARAMS, "-vnum", $TargetVersion{1});
+            }
+            if($LogMode eq "n") {
+                @PARAMS = (@PARAMS, "-logging-mode", "n");
+            }
+            elsif($Quiet) {
+                @PARAMS = (@PARAMS, "-logging-mode", "a");
+            }
+            system("perl", $0, @PARAMS);
+            if($?) {
+                exit(1);
+            }
+        }
+        else
+        { # child
+            my @PARAMS = ("-dump", $Descriptor{2}{"Path"}, "-l", $TargetLibraryName);
+            if($RelativeDirectory{2}) {
+                @PARAMS = (@PARAMS, "-relpath", $RelativeDirectory{2});
+            }
+            if($OutputLogPath{2}) {
+                @PARAMS = (@PARAMS, "-log-path", $OutputLogPath{2});
+            }
+            if($CrossGcc) {
+                @PARAMS = (@PARAMS, "-cross-gcc", $CrossGcc);
+            }
+            if($Debug) {
+                @PARAMS = (@PARAMS, "-debug");
+            }
+            if($Quiet) {
+                @PARAMS = (@PARAMS, "-quiet");
+            }
+            if($ExtendedCheck) {
+                @PARAMS = (@PARAMS, "-extended");
+            }
+            if($UserLang) {
+                @PARAMS = (@PARAMS, "-lang", $UserLang);
+            }
+            if($TargetVersion{2}) {
+                @PARAMS = (@PARAMS, "-vnum", $TargetVersion{2});
+            }
+            if($LogMode eq "n") {
+                @PARAMS = (@PARAMS, "-logging-mode", "n");
+            }
+            elsif($Quiet) {
+                @PARAMS = (@PARAMS, "-logging-mode", "a");
+            }
+            system("perl", $0, @PARAMS);
+            if($?) {
+                exit(1);
+            }
+            else {
+                exit(0);
+            }
+        }
+        waitpid($pid, 0);
+        my @CMP_PARAMS = ("-l", $TargetLibraryName);
+        @CMP_PARAMS = (@CMP_PARAMS, "-d1", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{1}{"Version"}.".abi.$AR_EXT");
+        @CMP_PARAMS = (@CMP_PARAMS, "-d2", "abi_dumps/$TargetLibraryName/".$TargetLibraryName."_".$Descriptor{2}{"Version"}.".abi.$AR_EXT");
+        if($TargetLibraryFName ne $TargetLibraryName) {
+            @CMP_PARAMS = (@CMP_PARAMS, "-l-full", $TargetLibraryFName);
+        }
+        if($ShowRetVal) {
+            @CMP_PARAMS = (@CMP_PARAMS, "-show-retval");
+        }
+        if($CrossGcc) {
+            @CMP_PARAMS = (@CMP_PARAMS, "-cross-gcc", $CrossGcc);
+        }
+        if($Quiet) {
+            @CMP_PARAMS = (@CMP_PARAMS, "-quiet");
+        }
+        if($LogMode eq "n") {
+            @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", "n");
+        }
+        elsif($Quiet) {
+            @CMP_PARAMS = (@CMP_PARAMS, "-logging-mode", "a");
+        }
+        if($ReportFormat) {
+            @CMP_PARAMS = (@CMP_PARAMS, "-report-format", $ReportFormat);
+        }
+        system("perl", $0, @CMP_PARAMS);
+        exit($?>>8);
+    }
+    if(not $Descriptor{1}{"Dump"}
+    or not $Descriptor{2}{"Dump"})
+    { # need GCC toolchain to analyze
+      # header files and libraries
+        detect_default_paths("inc|lib|gcc");
+    }
+    if(not $Descriptor{1}{"Dump"})
+    {
+        if(not $CheckHeadersOnly) {
+            readLibs(1);
+        }
+        if($CheckHeadersOnly) {
+            setLanguage(1, "C++");
+        }
+        if(not $CheckObjectsOnly) {
+            searchForHeaders(1);
+        }
+        $WORD_SIZE{1} = detectWordSize();
+    }
+    if(not $Descriptor{2}{"Dump"})
+    {
+        if(not $CheckHeadersOnly) {
+            readLibs(2);
+        }
+        if($CheckHeadersOnly) {
+            setLanguage(2, "C++");
+        }
+        if(not $CheckObjectsOnly) {
+            searchForHeaders(2);
+        }
+        $WORD_SIZE{2} = detectWordSize();
+    }
+    if($WORD_SIZE{1} ne $WORD_SIZE{2})
+    { # support for old ABI dumps
+      # try to synch different WORD sizes
+        if($UsedDump{1}{"V"}
+        and cmpVersions($UsedDump{1}{"V"}, "2.1")<0)
+        {
+            $WORD_SIZE{1} = $WORD_SIZE{2};
+            printMsg("WARNING", "set WORD size to ".$WORD_SIZE{2}." bytes");
+        }
+        elsif($UsedDump{2}{"V"}
+        and cmpVersions($UsedDump{2}{"V"}, "2.1")<0)
+        {
+            $WORD_SIZE{2} = $WORD_SIZE{1};
+            printMsg("WARNING", "set WORD size to ".$WORD_SIZE{1}." bytes");
+        }
+    }
+    elsif(not $WORD_SIZE{1}
+    and not $WORD_SIZE{2})
+    { # support for old ABI dumps
+        $WORD_SIZE{1} = 4;
+        $WORD_SIZE{2} = 4;
+    }
+    if($Descriptor{1}{"Dump"})
+    { # support for old ABI dumps
+        prepareTypes(1);
+    }
+    if($Descriptor{2}{"Dump"})
+    { # support for old ABI dumps
+        prepareTypes(2);
+    }
+    if($AppPath and not keys(%{$Symbol_Library{1}})) {
+        printMsg("WARNING", "the application ".get_filename($AppPath)." has no symbols imported from the $SLIB_TYPE libraries");
+    }
+    # started to process input data
+    readRules("Binary");
+    readRules("Source");
+    if(not $CheckHeadersOnly)
+    {# added/removed in libs
+        detectAdded();
+        detectRemoved();
+    }
+    if(not $CheckObjectsOnly)
+    {
+        if($Descriptor{1}{"Headers"}
+        and not $Descriptor{1}{"Dump"}) {
+            readHeaders(1);
+        }
+        if($Descriptor{2}{"Headers"}
+        and not $Descriptor{2}{"Dump"}) {
+            readHeaders(2);
+        }
+        printMsg("INFO", "comparing headers ...");
+        prepareInterfaces(1);
+        prepareInterfaces(2);
+        %SymbolInfo=();
+        if($CheckHeadersOnly)
+        { # added/removed in headers
+            detectAdded_H();
+            detectRemoved_H();
+        }
+        mergeSignatures();
+        if(keys(%CheckedSymbols)) {
+            mergeConstants();
+        }
+    }
+    if($CheckHeadersOnly)
+    { # added/removed in headers
+        mergeHeaders();
+    }
+    else
+    {
+        printMsg("INFO", "comparing libraries ...");
+        mergeLibs();
+        if($CheckImpl) {
+            mergeImpl();
+        }
+    }
+}
+
+sub optimize_set(@)
+{
+    my %Included = ();
+    foreach my $Path (@_)
+    {
+        detect_header_includes($Path, 1);
+        foreach my $Include (keys(%{$Header_Includes{1}{$Path}})) {
+            $Included{get_filename($Include)}{$Include}=1;
+        }
+    }
+    my @Res = ();
+    foreach my $Path (@_)
+    {
+        my $Add = 1;
+        foreach my $Inc (keys(%{$Included{get_filename($Path)}}))
+        {
+            if($Path=~/\/\Q$Inc\E\Z/)
+            {
+                $Add = 0;
+                last;
+            }
+        }
+        if($Add) {
+            push(@Res, $Path);
+        }
+    }
+    return @Res;
+}
+
+sub writeOpts()
+{
+    my %Opts = (
+    "OStarget"=>$OStarget,
+    "Debug"=>$Debug,
+    "Quiet"=>$Quiet,
+    "LogMode"=>$LogMode,
+    "CheckHeadersOnly"=>$CheckHeadersOnly,
+    
+    "SystemRoot"=>$SystemRoot,
+    "MODULES_DIR"=>$MODULES_DIR,
+    "GCC_PATH"=>$GCC_PATH,
+    "TargetSysInfo"=>$TargetSysInfo,
+    "CrossPrefix"=>$CrossPrefix,
+    "TargetLibraryName"=>$TargetLibraryName,
+    "CrossGcc"=>$CrossGcc,
+    "UseStaticLibs"=>$UseStaticLibs,
+    "NoStdInc"=>$NoStdInc
+    );
+    return \%Opts;
+}
+
+sub get_CoreError($)
+{
+    my %CODE_ERROR = reverse(%ERROR_CODE);
+    return $CODE_ERROR{$_[0]};
+}
+
+sub scenario()
+{
+    if($StdOut)
+    { # enable quiet mode
+        $Quiet = 1;
+    }
+    if($UserLang)
+    { # --lang=C++
+        $UserLang = uc($UserLang);
+        $COMMON_LANGUAGE{1}=$UserLang;
+        $COMMON_LANGUAGE{2}=$UserLang;
+    }
+    if($LoggingPath)
+    {
+        $OutputLogPath{1} = $LoggingPath;
+        $OutputLogPath{2} = $LoggingPath;
+        if($Quiet) {
+            $COMMON_LOG_PATH = $LoggingPath;
+        }
+    }
+    if($ReportFormat)
+    { # validate
+        if($ReportFormat!~/\A(xml|html)\Z/) {
+            exitStatus("Error", "unknown format \'$ReportFormat\'");
+        }
+    }
+    else
+    { # default: HTML
+        $ReportFormat = "html";
+    }
+    if($Quiet and $LogMode!~/a|n/)
+    { # --quiet log
+        if(-f $COMMON_LOG_PATH) {
+            unlink($COMMON_LOG_PATH);
+        }
+    }
+    if($TestTool and $UseDumps)
+    { # --test && --use-dumps == --test-dump
+        $TestDump = 1;
+    }
+    if($Help) {
+        HELP_MESSAGE();
+        exit(0);
+    }
+    if($InfoMsg) {
+        INFO_MESSAGE();
+        exit(0);
+    }
+    if($ShowVersion) {
+        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.");
+        exit(0);
+    }
+    if($DumpVersion) {
+        printMsg("INFO", $TOOL_VERSION);
+        exit(0);
+    }
+    if($ExtendedCheck) {
+        $CheckHeadersOnly = 1;
+    }
+    if($SystemRoot_Opt)
+    { # user defined root
+        if(not -e $SystemRoot_Opt) {
+            exitStatus("Access_Error", "can't access \'$SystemRoot\'");
+        }
+        $SystemRoot = $SystemRoot_Opt;
+        $SystemRoot=~s/[\/]+\Z//g;
+        if($SystemRoot) {
+            $SystemRoot = get_abs_path($SystemRoot);
+        }
+    }
+    $Data::Dumper::Sortkeys = 1;
+    # FIXME: can't pass \&dump_sorting - cause a segfault sometimes
+    # $Data::Dumper::Sortkeys = \&dump_sorting;
+    if($TargetLibsPath)
+    {
+        if(not -f $TargetLibsPath) {
+            exitStatus("Access_Error", "can't access file \'$TargetLibsPath\'");
+        }
+        foreach my $Lib (split(/\s*\n\s*/, readFile($TargetLibsPath))) {
+            $TargetLibs{$Lib} = 1;
+        }
+    }
+    if($TargetHeadersPath)
+    { # --headers-list
+        if(not -f $TargetHeadersPath) {
+            exitStatus("Access_Error", "can't access file \'$TargetHeadersPath\'");
+        }
+        foreach my $Header (split(/\s*\n\s*/, readFile($TargetHeadersPath)))
+        {
+            $TargetHeaders{1}{$Header} = 1;
+            $TargetHeaders{2}{$Header} = 1;
+        }
+    }
+    if($TargetHeader)
+    { # --header
+        $TargetHeaders{1}{$TargetHeader} = 1;
+        $TargetHeaders{2}{$TargetHeader} = 1;
+    }
+    if($TestTool
+    or $TestDump)
+    { # --test, --test-dump
+        detect_default_paths("bin|gcc"); # to compile libs
+        loadModule("RegTests");
+        testTool($TestDump, $Debug, $Quiet, $ExtendedCheck, $LogMode, $ReportFormat, $LIB_EXT, $GCC_PATH);
+        exit(0);
+    }
+    if($DumpSystem)
+    { # --dump-system
+        loadModule("SysCheck");
+        if($DumpSystem=~/\.xml\Z/)
+        { # system XML descriptor
+            if(not -f $DumpSystem) {
+                exitStatus("Access_Error", "can't access file \'$DumpSystem\'");
+            }
+            my $Ret = readSystemDescriptor(readFile($DumpSystem));
+            foreach (@{$Ret->{"Tools"}}) {
+                $SystemPaths{"bin"}{$_} = 1;
+                $TargetTools{$_}=1;
+            }
+            if($Ret->{"CrossPrefix"}) {
+                $CrossPrefix = $Ret->{"CrossPrefix"};
+            }
+        }
+        elsif($SystemRoot_Opt)
+        { # -sysroot "/" option
+          # default target: /usr/lib, /usr/include
+          # search libs: /usr/lib and /lib
+            if(not -e $SystemRoot."/usr/lib") {
+                exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/lib'");
+            }
+            if(not -e $SystemRoot."/lib") {
+                exitStatus("Access_Error", "can't access '".$SystemRoot."/lib'");
+            }
+            if(not -e $SystemRoot."/usr/include") {
+                exitStatus("Access_Error", "can't access '".$SystemRoot."/usr/include'");
+            }
+            readSystemDescriptor("
+                <name>
+                    $DumpSystem
+                </name>
+                <headers>
+                    $SystemRoot/usr/include
+                </headers>
+                <libs>
+                    $SystemRoot/usr/lib
+                </libs>
+                <search_libs>
+                    $SystemRoot/lib
+                </search_libs>");
+        }
+        else {
+            exitStatus("Error", "-sysroot <dirpath> option should be specified, usually it's \"/\"");
+        }
+        detect_default_paths("bin|gcc"); # to check symbols
+        if($OStarget eq "windows")
+        { # to run dumpbin.exe
+          # and undname.exe
+            check_win32_env();
+        }
+        dumpSystem(writeOpts());
+        exit(0);
+    }
+    if($CmpSystems)
+    { # --cmp-systems
+        detect_default_paths("bin"); # to extract dumps
+        loadModule("SysCheck");
+        cmpSystems($Descriptor{1}{"Path"}, $Descriptor{2}{"Path"}, writeOpts());
+        exit(0);
+    }
+    if($GenerateTemplate) {
+        generateTemplate();
+        exit(0);
+    }
+    if(not $TargetLibraryName) {
+        exitStatus("Error", "library name is not selected (option -l <name>)");
+    }
+    else
+    { # validate library name
+        if($TargetLibraryName=~/[\*\/\\]/) {
+            exitStatus("Error", "\"\\\", \"\/\" and \"*\" symbols are not allowed in the library name");
+        }
+    }
+    if(not $TargetLibraryFName) {
+        $TargetLibraryFName = $TargetLibraryName;
+    }
+    if($CheckHeadersOnly_Opt and $CheckObjectsOnly_Opt) {
+        exitStatus("Error", "you can't specify both -headers-only and -objects-only options at the same time");
+    }
+    if($SymbolsListPath)
+    {
+        if(not -f $SymbolsListPath) {
+            exitStatus("Access_Error", "can't access file \'$SymbolsListPath\'");
+        }
+        foreach my $Interface (split(/\s*\n\s*/, readFile($SymbolsListPath))) {
+            $SymbolsList{$Interface} = 1;
+        }
+    }
+    if($SkipHeadersPath)
+    {
+        if(not -f $SkipHeadersPath) {
+            exitStatus("Access_Error", "can't access file \'$SkipHeadersPath\'");
+        }
+        foreach my $Path (split(/\s*\n\s*/, readFile($SkipHeadersPath)))
+        {
+            my ($CPath, $Type) = classifyPath($Path);
+            $SkipHeaders{1}{$Type}{$CPath} = 1;
+            $SkipHeadersList{1}{$Path} = 1;
+            # register for both versions
+            $SkipHeaders{2}{$Type}{$CPath} = 1;
+            $SkipHeadersList{2}{$Path} = 1;
+        }
+    }
+    if($ParamNamesPath)
+    {
+        if(not -f $ParamNamesPath) {
+            exitStatus("Access_Error", "can't access file \'$ParamNamesPath\'");
+        }
+        foreach my $Line (split(/\n/, readFile($ParamNamesPath)))
+        {
+            if($Line=~s/\A(\w+)\;//)
+            {
+                my $Interface = $1;
+                if($Line=~/;(\d+);/) {
+                    while($Line=~s/(\d+);(\w+)//) {
+                        $AddIntParams{$Interface}{$1}=$2;
+                    }
+                }
+                else {
+                    my $Num = 0;
+                    foreach my $Name (split(/;/, $Line)) {
+                        $AddIntParams{$Interface}{$Num++}=$Name;
+                    }
+                }
+            }
+        }
+    }
+    if($AppPath)
+    {
+        if(not -f $AppPath) {
+            exitStatus("Access_Error", "can't access file \'$AppPath\'");
+        }
+        foreach my $Interface (getSymbols_App($AppPath)) {
+            $SymbolsList_App{$Interface} = 1;
+        }
+    }
+    if($DumpAPI)
+    { # --dump-abi
+      # make an API dump
+        create_ABI_Dump();
+        exit($COMPILE_ERRORS);
+    }
+    # default: compare APIs
+    #  -d1 <path>
+    #  -d2 <path>
+    compareAPIs();
+    exitReport();
+}
+
+scenario();