ACC 1.97.2: corrected ABI dumps, improved HTML reports.
diff --git a/abi-compliance-checker.pl b/abi-compliance-checker.pl
index 201ab16..61b3bf8 100644
--- a/abi-compliance-checker.pl
+++ b/abi-compliance-checker.pl
@@ -1,6 +1,6 @@
#!/usr/bin/perl
###########################################################################
-# ABI Compliance Checker (ACC) 1.97.1
+# ABI Compliance Checker (ACC) 1.97.2
# A tool for checking backward compatibility of a C/C++ library API
#
# Copyright (C) 2009-2010 The Linux Foundation.
@@ -55,8 +55,8 @@
use Data::Dumper;
use Config;
-my $TOOL_VERSION = "1.97.1";
-my $ABI_DUMP_VERSION = "2.11";
+my $TOOL_VERSION = "1.97.2";
+my $ABI_DUMP_VERSION = "2.12";
my $OLDEST_SUPPORTED_VERSION = "1.18";
my $XML_REPORT_VERSION = "1.0";
my $OSgroup = get_OSgroup();
@@ -1177,8 +1177,6 @@
my $MAX_COMMAND_LINE_ARGUMENTS = 4096;
my (%WORD_SIZE, %CPU_ARCH, %GCC_VERSION);
-my %LIB_ARCH;
-
my $STDCXX_TESTING = 0;
my $GLIBC_TESTING = 0;
@@ -1233,16 +1231,16 @@
"2"=>{} );
my %UsedType;
my %VirtualTable;
-my %VirtualTable_Full;
+my %VirtualTable_Model;
my %ClassVTable;
my %ClassVTable_Content;
my %VTableClass;
my %AllocableClass;
my %ClassMethods;
-my %ClassToId;
+my %ClassNames;
my %Class_SubClasses;
my %OverriddenMethods;
-my $MAX_TID;
+my $MAX_ID;
# Typedefs
my %Typedef_BaseName;
@@ -1344,7 +1342,7 @@
my %CompatRules;
my %IncompleteRules;
my %UnknownRules;
-my %VTableChanged;
+my %VTableChanged_M;
my %ExtendedFuncs;
my %ReturnedClass;
my %ParamClass;
@@ -1914,7 +1912,7 @@
$LibInfo{$Version}{"info"}{$1}=$3;
}
}
- $MAX_TID = $#Lines+1;
+ $MAX_ID = $#Lines+1;
@Lines=();# clear
# processing info
setTemplateParams_All();
@@ -2169,7 +2167,7 @@
"Tid" => $Tid
},
"Type" => "Typedef",
- "Tid" => ++$MAX_TID,
+ "Tid" => ++$MAX_ID,
"TDid" => $MissedTDid );
my ($H, $L) = getLocation($MissedTDid);
$MissedInfo{"Header"} = $H;
@@ -2261,10 +2259,11 @@
sub getTParams_Func($)
{
+ my $InfoId = $_[0];
my @TmplParams = ();
- foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$TemplateInstance_Func{$Version}{$_[0]}}))
+ foreach my $Pos (sort {int($a) <=> int($b)} keys(%{$TemplateInstance_Func{$Version}{$InfoId}}))
{
- my $Param = get_TemplateParam($Pos, $TemplateInstance_Func{$Version}{$_[0]}{$Pos});
+ my $Param = get_TemplateParam($Pos, $TemplateInstance_Func{$Version}{$InfoId}{$Pos});
if($Param eq "") {
return ();
}
@@ -2457,9 +2456,6 @@
{
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");
@@ -2997,6 +2993,15 @@
if(not $TypeAttr{"NameSpace"}) {
delete($TypeAttr{"NameSpace"});
}
+ if(defined $TemplateInstance{$Version}{$TypeInfoId}{$TypeId})
+ {
+ if(my @TParams = getTParams($TypeInfoId, $TypeId))
+ {
+ foreach my $Pos (0 .. $#TParams) {
+ $TypeAttr{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
+ }
+ }
+ }
if(my $Size = getSize($TypeId)) {
$TypeAttr{"Size"} = $Size/$BYTE_SIZE;
}
@@ -3203,21 +3208,21 @@
}
my $Mangled = "";
if($Compiler eq "GCC") {
- $Mangled = mangle_symbol_gcc($InfoId, $LibVersion);
+ $Mangled = mangle_symbol_GCC($InfoId, $LibVersion);
}
elsif($Compiler eq "MSVC") {
- $Mangled = mangle_symbol_msvc($InfoId, $LibVersion);
+ $Mangled = mangle_symbol_MSVC($InfoId, $LibVersion);
}
return ($Cache{"mangle_symbol"}{$LibVersion}{$InfoId}{$Compiler} = $Mangled);
}
-sub mangle_symbol_msvc($$)
+sub mangle_symbol_MSVC($$)
{
my ($InfoId, $LibVersion) = @_;
return "";
}
-sub mangle_symbol_gcc($$)
+sub mangle_symbol_GCC($$)
{ # see gcc-4.6.0/gcc/cp/mangle.c
my ($InfoId, $LibVersion) = @_;
my ($Mangled, $ClassId, $NameSpace) = ("_Z", 0, "");
@@ -3252,9 +3257,14 @@
$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
+ my @TParams = ();
+ if($Version)
+ { # parsing mode
+ @TParams = getTParams_Func($InfoId);
+ }
+ elsif($TmplParams)
+ { # remangling mode
+ # support for old ABI dumps
@TParams = separate_params($TmplParams, 0);
}
if($SymbolInfo{$LibVersion}{$InfoId}{"Constructor"}) {
@@ -3267,20 +3277,12 @@
{
if($SymbolInfo{$LibVersion}{$InfoId}{"Data"})
{
- if(get_TypeAttr($Return, $LibVersion, "Type") eq "Const")
+ if(not $SymbolInfo{$LibVersion}{$InfoId}{"Class"}
+ and get_TypeAttr($Return, $LibVersion, "Type") eq "Const")
{ # "const" global data is mangled as _ZL...
$Mangled .= "L";
}
}
- elsif(($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;
@@ -3362,17 +3364,23 @@
sub template_base($)
{ # NOTE: std::_Vector_base<mysqlpp::mysql_type_info>::_Vector_impl
- # NOTE: operator<<
+ # NOTE: operators: >>, <<
my $Name = $_[0];
- if($Name!~/>\Z/) {
+ if($Name!~/>\Z/ or $Name!~/</) {
return $Name;
}
my $TParams = $Name;
- while(my $CPos = detect_center($TParams, "<")) {
+ while(my $CPos = find_center($TParams, "<"))
+ { # search for the last <T>
$TParams = substr($TParams, $CPos);
}
- $Name=~s/\Q$TParams\E\Z//;
- $TParams=~s/\A<(.+)>\Z/$1/;
+ if($TParams=~s/\A<(.+)>\Z/$1/) {
+ $Name=~s/<\Q$TParams\E>\Z//;
+ }
+ else
+ { # error
+ $TParams = "";
+ }
return ($Name, $TParams);
}
@@ -3380,7 +3388,7 @@
{
my $Name = $_[0];
my @NS = ();
- while(my $CPos = detect_center($Name, ":"))
+ while(my $CPos = find_center($Name, ":"))
{
push(@NS, substr($Name, 0, $CPos));
$Name = substr($Name, $CPos);
@@ -3452,9 +3460,14 @@
}
elsif($BaseType{"Type"}=~/(Class|Struct|Union|Enum)/)
{
- my @TParams = getTParams($BaseType{"TDid"}, $BaseType{"Tid"});
- if(not @TParams and $TmplParams)
- { # support for old ABI dumps
+ my @TParams = ();
+ if($Version)
+ { # parsing mode
+ @TParams = getTParams($BaseType{"TDid"}, $BaseType{"Tid"});
+ }
+ elsif($TmplParams)
+ { # remangling mode
+ # support for old ABI dumps
@TParams = separate_params($TmplParams, 0);
}
my $MangledNS = "";
@@ -3828,18 +3841,20 @@
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(not $CheckHeadersOnly)
{
if(my $Mangled = $mangled_name_gcc{modelUnmangled($InfoId, "GCC")}) {
return correct_incharge($InfoId, $Version, $Mangled);
}
}
+ if($CheckHeadersOnly
+ or not $BinaryOnly)
+ { # 1. --headers-only mode
+ # 2. not mangled src-only symbols
+ if(my $Mangled = mangle_symbol($InfoId, $Version, "GCC")) {
+ return $Mangled;
+ }
+ }
}
return "";
}
@@ -3888,7 +3903,14 @@
delete($SymbolInfo{$Version}{$InfoId});
return;
}
+ foreach my $Pos (0 .. $#TParams) {
+ $SymbolInfo{$Version}{$InfoId}{"TParam"}{$Pos}{"name"}=$TParams[$Pos];
+ }
my $PrmsInLine = join(", ", @TParams);
+ if($SymbolInfo{$Version}{$InfoId}{"ShortName"}=~/\Aoperator\W+\Z/)
+ { # operator<< <T>, operator>> <T>
+ $SymbolInfo{$Version}{$InfoId}{"ShortName"} .= " ";
+ }
$SymbolInfo{$Version}{$InfoId}{"ShortName"} .= "<".$PrmsInLine.">";
$SymbolInfo{$Version}{$InfoId}{"ShortName"} = formatName($SymbolInfo{$Version}{$InfoId}{"ShortName"});
}
@@ -5794,7 +5816,7 @@
}
if(my $ChargeLevel = get_ChargeLevel($Interface, $LibVersion))
{
- my $ShortName = substr($Signature, 0, detect_center($Signature, "("));
+ my $ShortName = substr($Signature, 0, find_center($Signature, "("));
$Signature=~s/\A\Q$ShortName\E/$ShortName $ChargeLevel/g;
}
if($SymbolVersion) {
@@ -5860,7 +5882,7 @@
return $Cache{"get_Signature"}{$LibVersion}{$Interface};
}
my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Interface);
- if(skipGlobalData($MnglName) or not $CompleteSignature{$LibVersion}{$Interface}{"Header"}) {
+ if(skipPrivateData($MnglName) or not $CompleteSignature{$LibVersion}{$Interface}{"Header"}) {
return get_SignatureNoInfo($Interface, $LibVersion);
}
my ($Func_Signature, @Param_Types_FromUnmangledName) = ();
@@ -6406,7 +6428,7 @@
}
my $TmpHeaderPath = "$TMP_DIR/dump$Version.h";
my $MHeaderPath = $TmpHeaderPath;
- open(LIB_HEADER, ">".$TmpHeaderPath) || die ("can't open file \'$TmpHeaderPath\': $!\n");
+ open(LIB_HEADER, ">", $TmpHeaderPath) || die ("can't open file \'$TmpHeaderPath\': $!\n");
if(my $AddDefines = $Descriptor{$Version}{"Defines"})
{
$AddDefines=~s/\n\s+/\n /g;
@@ -7045,7 +7067,7 @@
return 0;
}
-sub detectTargetHeaders($)
+sub addTargetHeaders($)
{
my $LibVersion = $_[0];
foreach my $RegHeader (keys(%{$Registered_Headers{$LibVersion}}))
@@ -7055,7 +7077,7 @@
foreach my $RecInc (keys(%{$RecursiveIncludes{$LibVersion}{$RegHeader}}))
{
my $Dir = get_dirname($RecInc);
- if($Dir=~/\A$RegDir([\/\\]|\Z)/)
+ if($Dir=~/\A\Q$RegDir\E([\/\\]|\Z)/)
{ # in the same directory
$TargetHeaders{$LibVersion}{get_filename($RecInc)}=1;
}
@@ -7077,11 +7099,7 @@
copy($DumpPath, $DEBUG_PATH{$Version}."/translation-unit-dump.txt");
}
getInfo($DumpPath);
- if($CheckHeadersOnly
- or not $BinaryOnly)
- { # --headers-only mode
- detectTargetHeaders($Version);
- }
+ addTargetHeaders($Version);
}
sub prepareTypes($)
@@ -7158,6 +7176,20 @@
sub prepareSymbols($)
{
my $LibVersion = $_[0];
+
+ if(not keys(%{$SymbolInfo{$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"}.")");
+ }
+ }
+ }
+
my $Remangle = 0;
if(not checkDumpVersion(1, "2.10")
or not checkDumpVersion(2, "2.10"))
@@ -7195,7 +7227,21 @@
}
}
my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
- if($Remangle==1)
+ my $ClassID = $SymbolInfo{$LibVersion}{$InfoId}{"Class"};
+ my $SRemangle = 0;
+ if(not checkDumpVersion($LibVersion, "2.12"))
+ { # support for old ABI dumps
+ if($SymbolInfo{$LibVersion}{$InfoId}{"ShortName"} eq "operator>>")
+ { # corrected mangling of operator>>
+ $SRemangle = 1;
+ }
+ if($SymbolInfo{$LibVersion}{$InfoId}{"Data"}
+ and not $SymbolInfo{$LibVersion}{$InfoId}{"Class"})
+ { # corrected mangling of const global data
+ $SRemangle = 1;
+ }
+ }
+ if($Remangle==1 or $SRemangle==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
@@ -7209,12 +7255,11 @@
# because of absent "Volatile" attribute
$SymbolInfo{$LibVersion}{$InfoId}{"Volatile"} = 1;
}
- if(($SymbolInfo{$LibVersion}{$InfoId}{"Class"} and ($MnglName!~/\A_Z/ or not link_symbol($MnglName, $LibVersion, "-Deps")))
- or (not $SymbolInfo{$LibVersion}{$InfoId}{"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(($ClassID and $MnglName!~/\A(_Z|\?)/)
+ or (not $ClassID and $CheckHeadersOnly)
+ or (not $ClassID and not link_symbol($MnglName, $LibVersion, "-Deps")))
+ { # support for old ABI dumps, GCC >= 4.0
+ # remangling all manually mangled symbols
if($MnglName = mangle_symbol($InfoId, $LibVersion, "GCC"))
{
$SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
@@ -7228,7 +7273,7 @@
$SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = "";
}
if(not $MnglName)
- { # ABI dumps don't contain mangled names for C-functions
+ { # ABI dumps have no mangled names for C-functions
$MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"};
$SymbolInfo{$LibVersion}{$InfoId}{"MnglName"} = $MnglName;
}
@@ -7251,6 +7296,7 @@
if($SymVer{$LibVersion}{$MnglName}) {
%{$CompleteSignature{$LibVersion}{$SymVer{$LibVersion}{$MnglName}}} = %{$SymbolInfo{$LibVersion}{$InfoId}};
}
+ delete($SymbolInfo{$LibVersion}{$InfoId});
}
if($COMMON_LANGUAGE{$LibVersion} eq "C++" or $OSgroup eq "windows") {
translateSymbols(keys(%{$CompleteSignature{$LibVersion}}), $LibVersion);
@@ -7259,18 +7305,6 @@
{ # --ext option
addExtension($LibVersion);
}
- if(not keys(%{$SymbolInfo{$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"}.")");
- }
- }
- }
$SymbolInfo{$LibVersion} = ();
foreach my $MnglName (keys(%{$CompleteSignature{$LibVersion}}))
{ # detect allocable classes with public exported constructors
@@ -7283,7 +7317,7 @@
{ # Class() { ... } will not be exported
if(not $CompleteSignature{$LibVersion}{$MnglName}{"Private"})
{
- if(link_symbol($MnglName, $LibVersion, "-Deps")) {
+ if($CheckHeadersOnly or link_symbol($MnglName, $LibVersion, "-Deps")) {
$AllocableClass{$LibVersion}{$ClassName} = 1;
}
}
@@ -7304,7 +7338,7 @@
}
$ClassMethods{"Source"}{$LibVersion}{$ClassName}{$MnglName} = 1;
}
- $ClassToId{$LibVersion}{$ClassName} = $ClassId;
+ $ClassNames{$LibVersion}{$ClassName} = 1;
}
if(my $RetId = $CompleteSignature{$LibVersion}{$MnglName}{"Return"})
{
@@ -7328,13 +7362,15 @@
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/)
+ if(my %Base = get_BaseType($Tid_TDid{$LibVersion}{$PId}, $PId, $LibVersion))
{
- $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;
+ 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;
+ }
}
}
}
@@ -7352,146 +7388,31 @@
}
}
}
-}
-
-sub addExtension($)
-{
- my $LibVersion = $_[0];
- foreach my $TDid (keys(%{$TypeInfo{$LibVersion}}))
+
+ # types
+ foreach my $TypeDeclId (keys(%{$TypeInfo{$LibVersion}}))
{
- foreach my $Tid (keys(%{$TypeInfo{$LibVersion}{$TDid}}))
+ foreach my $TypeId (keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}}))
{
- 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{"Binary"}{$FuncName}=1;
- $CheckedSymbols{"Source"}{$FuncName}=1;
+ if(not defined $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"TDid"})
+ { # to avoid Perl warnings about uninitialized values
+ $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"TDid"} = "";
}
- }
- }
- my $ConstFunc = "external_func_0";
- $GeneratedSymbols{$ConstFunc}=1;
- $CheckedSymbols{"Binary"}{$ConstFunc}=1;
- $CheckedSymbols{"Source"}{$ConstFunc}=1;
-}
-
-sub formatDump($)
-{ # remove unnecessary data from the ABI dump
- my $LibVersion = $_[0];
- foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
- {
- my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
- if(not $MnglName) {
- delete($SymbolInfo{$LibVersion}{$InfoId});
- next;
- }
- if($MnglName eq $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"}) {
- delete($SymbolInfo{$LibVersion}{$InfoId}{"MnglName"});
- }
- if(not is_target_header($SymbolInfo{$LibVersion}{$InfoId}{"Header"}))
- { # user-defined header
- delete($SymbolInfo{$LibVersion}{$InfoId});
- next;
- }
- if($BinaryOnly and not $SourceOnly)
- { # --dump --binary
- if(not link_symbol($MnglName, $LibVersion, "-Deps")
- and not $SymbolInfo{$LibVersion}{$InfoId}{"Virt"}
- and not $SymbolInfo{$LibVersion}{$InfoId}{"PureVirt"})
- { # removing src only (inline)
- # and all non-exported functions
- if(not $CheckHeadersOnly) {
- delete($SymbolInfo{$LibVersion}{$InfoId});
- next;
- }
- }
- }
- if(not symbolFilter($MnglName, $LibVersion, "Public", "Source")) {
- delete($SymbolInfo{$LibVersion}{$InfoId});
- next;
- }
- my %FuncInfo = %{$SymbolInfo{$LibVersion}{$InfoId}};
- 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}{$InfoId}{"Param"}})) {
- delete($SymbolInfo{$LibVersion}{$InfoId}{"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(my $TName = $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Name"})
{
- if(not $UsedType{$LibVersion}{$TDid}{$Tid})
+ if(defined $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"VTable"}) {
+ $ClassNames{$LibVersion}{$TName} = 1;
+ }
+ if(defined $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Base"})
{
- 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"});
+ $ClassNames{$LibVersion}{$TName} = 1;
+ foreach (keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"Base"}})) {
+ $ClassNames{$LibVersion}{get_TypeName($_, $LibVersion)} = 1;
}
}
}
}
}
- foreach my $Tid (keys(%{$Tid_TDid{$LibVersion}}))
- {
- if(not $Tid_TDid{$LibVersion}{$Tid}) {
- delete($Tid_TDid{$LibVersion}{$Tid});
- }
- }
}
sub register_TypeUsing($$$)
@@ -7552,6 +7473,152 @@
}
}
+sub isVirt($$) {
+ return ($SymbolInfo{$_[0]}{$_[1]}{"Virt"} or $SymbolInfo{$_[0]}{$_[1]}{"PureVirt"});
+}
+
+sub formatDump($)
+{ # remove unnecessary data from the ABI dump
+ my $LibVersion = $_[0];
+ foreach my $InfoId (keys(%{$SymbolInfo{$LibVersion}}))
+ {
+ my $MnglName = $SymbolInfo{$LibVersion}{$InfoId}{"MnglName"};
+ if(not $MnglName) {
+ delete($SymbolInfo{$LibVersion}{$InfoId});
+ next;
+ }
+ if($MnglName eq $SymbolInfo{$LibVersion}{$InfoId}{"ShortName"}) {
+ delete($SymbolInfo{$LibVersion}{$InfoId}{"MnglName"});
+ }
+ if(not isVirt($LibVersion, $InfoId))
+ { # non-virtual only
+ if(not is_target_header($SymbolInfo{$LibVersion}{$InfoId}{"Header"}))
+ { # user-defined header
+ delete($SymbolInfo{$LibVersion}{$InfoId});
+ next;
+ }
+ if(not $CheckHeadersOnly)
+ {
+ if($BinaryOnly)
+ { # --dump --binary
+ if(not link_symbol($MnglName, $LibVersion, "-Deps"))
+ { # removing src only (inline)
+ # and all non-exported functions
+ delete($SymbolInfo{$LibVersion}{$InfoId});
+ next;
+ }
+ }
+ }
+ if(not symbolFilter($MnglName, $LibVersion, "Public", "Source")) {
+ delete($SymbolInfo{$LibVersion}{$InfoId});
+ next;
+ }
+ }
+ my %FuncInfo = %{$SymbolInfo{$LibVersion}{$InfoId}};
+ 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}{$InfoId}{"Param"}})) {
+ delete($SymbolInfo{$LibVersion}{$InfoId}{"Param"});
+ }
+ }
+ foreach my $TDid (keys(%{$TypeInfo{$LibVersion}}))
+ { # remove unused types
+ 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"});
+ }
+ }
+ }
+ }
+ }
+ foreach my $Tid (keys(%{$Tid_TDid{$LibVersion}}))
+ {
+ if(not $Tid_TDid{$LibVersion}{$Tid}) {
+ delete($Tid_TDid{$LibVersion}{$Tid});
+ }
+ }
+}
+
+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{"Binary"}{$FuncName}=1;
+ $CheckedSymbols{"Source"}{$FuncName}=1;
+ }
+ }
+ }
+ my $ConstFunc = "external_func_0";
+ $GeneratedSymbols{$ConstFunc}=1;
+ $CheckedSymbols{"Binary"}{$ConstFunc}=1;
+ $CheckedSymbols{"Source"}{$ConstFunc}=1;
+}
+
sub findMethod($$$)
{
my ($VirtFunc, $ClassId, $LibVersion) = @_;
@@ -7597,9 +7664,9 @@
return "";
}
-sub registerVTable($$)
+sub registerVTable($)
{
- my ($LibVersion, $Level) = @_;
+ my $LibVersion = $_[0];
foreach my $Symbol (keys(%{$CompleteSignature{$LibVersion}}))
{
if($CompleteSignature{$LibVersion}{$Symbol}{"Virt"}
@@ -7617,21 +7684,6 @@
my ($MnglName, $VersionSpec, $SymbolVersion) = separate_symbol($Symbol);
$VirtualTable{$LibVersion}{$ClassName}{$MnglName} = 1;
}
- if($CheckHeadersOnly
- and $CompleteSignature{$LibVersion}{$Symbol}{"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}{$Symbol}{"Header"})
- { # not presented in old-version headers
- $AddedInt{$Level}{$Symbol} = 1;
- }
- if($LibVersion==1 and not $CompleteSignature{2}{$Symbol}{"Header"})
- { # not presented in new-version headers
- $RemovedInt{$Level}{$Symbol} = 1;
- }
- }
}
}
@@ -7639,17 +7691,22 @@
{
my $LibVersion = $_[0];
my @Classes = keys(%{$VirtualTable{$LibVersion}});
- @Classes = sort {int($ClassToId{$LibVersion}{$a})<=>int($ClassToId{$LibVersion}{$b})} @Classes;
+ @Classes = sort {int($ClassNames{$LibVersion}{$a})<=>int($ClassNames{$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($CompleteSignature{$LibVersion}{$VirtFunc}{"PureVirt"})
+ { # pure virtuals
+ next;
+ }
+ my $ClassId = $TName_Tid{$LibVersion}{$ClassName};
+ if(my $Overridden = findMethod($VirtFunc, $ClassId, $LibVersion))
+ { # both overridden virtual methods
+ # and implemented pure virtual methods
+ $CompleteSignature{$LibVersion}{$VirtFunc}{"Override"} = $Overridden;
+ $OverriddenMethods{$LibVersion}{$Overridden}{$VirtFunc} = 1;
+ delete($VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}); # remove from v-table model
}
}
if(not keys(%{$VirtualTable{$LibVersion}{$ClassName}})) {
@@ -7667,24 +7724,24 @@
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
+ $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}=$Num++;
+
+ # set relative positions
+ 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
+ if(not $CompleteSignature{1}{$VirtFunc}{"Override"}
+ and not $CompleteSignature{2}{$VirtFunc}{"Override"}) {
$CompleteSignature{$LibVersion}{$VirtFunc}{"RelPos"} = $RelPos++;
}
- $VirtualTable{$LibVersion}{$ClassName}{$VirtFunc}=$Num++;
}
-
}
}
- foreach my $ClassName (keys(%{$ClassToId{$LibVersion}}))
+ foreach my $ClassName (keys(%{$ClassNames{$LibVersion}}))
{
my $AbsNum = 1;
- foreach my $VirtFunc (getVTable($ClassToId{$LibVersion}{$ClassName}, $LibVersion)) {
- $VirtualTable_Full{$LibVersion}{$ClassName}{$VirtFunc}=$AbsNum++;
+ foreach my $VirtFunc (getVTable_Model($TName_Tid{$LibVersion}{$ClassName}, $LibVersion)) {
+ $VirtualTable_Model{$LibVersion}{$ClassName}{$VirtFunc}=$AbsNum++;
}
}
}
@@ -7696,7 +7753,8 @@
my @Subs = ();
foreach my $SubId (keys(%{$Class_SubClasses{$LibVersion}{$ClassId}}))
{
- if($Recursive) {
+ if($Recursive)
+ {
foreach my $SubSubId (get_sub_classes($SubId, $LibVersion, $Recursive)) {
push(@Subs, $SubSubId);
}
@@ -7715,7 +7773,8 @@
foreach my $BaseId (sort {int($ClassType{"Base"}{$a}{"pos"})<=>int($ClassType{"Base"}{$b}{"pos"})}
keys(%{$ClassType{"Base"}}))
{
- if($Recursive) {
+ if($Recursive)
+ {
foreach my $SubBaseId (get_base_classes($BaseId, $LibVersion, $Recursive)) {
push(@Bases, $SubBaseId);
}
@@ -7725,8 +7784,8 @@
return @Bases;
}
-sub getVTable($$)
-{# return list of v-table elements
+sub getVTable_Model($$)
+{ # return an ordered list of v-table elements
my ($ClassId, $LibVersion) = @_;
my @Bases = get_base_classes($ClassId, $LibVersion, 1);
my @Elements = ();
@@ -7735,8 +7794,7 @@
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)
- {
+ foreach my $VFunc (@VFunctions) {
push(@Elements, $VFunc);
}
}
@@ -7776,15 +7834,30 @@
return $Shift;
}
-sub getVSize($$)
-{
+sub getVTable_Size($$)
+{ # number of v-table elements
my ($ClassName, $LibVersion) = @_;
- if(defined $VirtualTable{$LibVersion}{$ClassName}) {
- return keys(%{$VirtualTable{$LibVersion}{$ClassName}});
+ my $Size = 0;
+ # three approaches
+ if(not $Size)
+ { # real size
+ if(my %VTable = getVTable_Real($ClassName, $LibVersion)) {
+ $Size = keys(%VTable);
+ }
}
- else {
- return 0;
+ if(not $Size)
+ { # shared library symbol size
+ if($Size = getSymbolSize($ClassVTable{$ClassName}, $LibVersion)) {
+ $Size /= $WORD_SIZE{$LibVersion};
+ }
}
+ if(not $Size)
+ { # model size
+ if(defined $VirtualTable_Model{$LibVersion}{$ClassName}) {
+ $Size = keys(%{$VirtualTable_Model{$LibVersion}{$ClassName}}) + 2;
+ }
+ }
+ return $Size;
}
sub isCopyingClass($$)
@@ -8071,46 +8144,66 @@
return 0;
}
+sub getVTable_Real($$)
+{
+ my ($ClassName, $LibVersion) = @_;
+ if(my $ClassId = $TName_Tid{$LibVersion}{$ClassName})
+ {
+ my %Type = get_Type($Tid_TDid{$LibVersion}{$ClassId}, $ClassId, $LibVersion);
+ if(defined $Type{"VTable"}) {
+ return %{$Type{"VTable"}};
+ }
+ }
+ return ();
+}
+
+sub cmpVTables($)
+{
+ my $ClassName = $_[0];
+ my $Res = cmpVTables_Real($ClassName, 1);
+ if($Res==-1) {
+ $Res = cmpVTables_Model($ClassName);
+ }
+ return $Res;
+}
+
sub cmpVTables_Model($)
{
my $ClassName = $_[0];
- foreach my $Symbol (keys(%{$VirtualTable_Full{1}{$ClassName}}))
+ foreach my $Symbol (keys(%{$VirtualTable_Model{1}{$ClassName}}))
{
- if(not defined $VirtualTable_Full{2}{$ClassName}{$Symbol}) {
+ if(not defined $VirtualTable_Model{2}{$ClassName}{$Symbol}) {
return 1;
}
}
return 0;
}
-sub cmpVTables($$)
+sub cmpVTables_Real($$)
{
my ($ClassName, $Strong) = @_;
- my $ClassId1 = $ClassToId{1}{$ClassName};
- my $ClassId2 = $ClassToId{2}{$ClassName};
- if(not $ClassId1 or not $ClassId2) {
- return 0;
+ if(defined $Cache{"cmpVTables_Real"}{$Strong}{$ClassName}) {
+ return $Cache{"cmpVTables_Real"}{$Strong}{$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"})
+ my %VTable_Old = getVTable_Real($ClassName, 1);
+ my %VTable_New = getVTable_Real($ClassName, 2);
+ if(not %VTable_Old or not %VTable_New)
{ # old ABI dumps
- return 0;
+ return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = -1);
}
- my %Indexes = map {$_=>1} (keys(%{$Type1{"VTable"}}), keys(%{$Type2{"VTable"}}));
+ my %Indexes = map {$_=>1} (keys(%VTable_Old), keys(%VTable_New));
foreach my $Offset (sort {int($a)<=>int($b)} keys(%Indexes))
{
- if(not defined $Type1{"VTable"}{$Offset})
+ if(not defined $VTable_Old{$Offset})
{ # v-table v.1 < v-table v.2
- return $Strong;
+ return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = $Strong);
}
- my $Entry1 = $Type1{"VTable"}{$Offset};
- if(not defined $Type2{"VTable"}{$Offset})
+ my $Entry1 = $VTable_Old{$Offset};
+ if(not defined $VTable_New{$Offset})
{ # v-table v.1 > v-table v.2
- return $Strong;
+ return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = ($Strong or $Entry1!~/__cxa_pure_virtual/));
}
- my $Entry2 = $Type2{"VTable"}{$Offset};
+ my $Entry2 = $VTable_New{$Offset};
$Entry1 = simpleVEntry($Entry1);
$Entry2 = simpleVEntry($Entry2);
if($Entry1 ne $Entry2)
@@ -8127,10 +8220,10 @@
}
}
}
- return 1;
+ return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 1);
}
}
- return 0;
+ return ($Cache{"cmpVTables_Real"}{$Strong}{$ClassName} = 0);
}
sub mergeVTables($)
@@ -8138,11 +8231,11 @@
my $Level = $_[0];
foreach my $ClassName (keys(%{$VirtualTable{1}}))
{
- if($VTableChanged{$ClassName})
+ if($VTableChanged_M{$ClassName})
{ # already registered
next;
}
- if(cmpVTables($ClassName, 0))
+ if(cmpVTables_Real($ClassName, 0)==1)
{
my @Affected = (keys(%{$ClassMethods{$Level}{1}{$ClassName}}));
foreach my $Symbol (@Affected)
@@ -8159,33 +8252,39 @@
sub mergeBases($)
{
my $Level = $_[0];
- foreach my $ClassName (keys(%{$ClassToId{1}}))
+ foreach my $ClassName (keys(%{$ClassNames{1}}))
{ # detect added and removed virtual functions
- my $ClassId = $ClassToId{1}{$ClassName};
+ my $ClassId = $TName_Tid{1}{$ClassName};
next if(not $ClassId);
if(defined $VirtualTable{2}{$ClassName})
{
- foreach my $VirtFunc (keys(%{$VirtualTable{2}{$ClassName}}))
+ foreach my $Symbol (keys(%{$VirtualTable{2}{$ClassName}}))
{
- if($ClassToId{1}{$ClassName}
- and not defined $VirtualTable{1}{$ClassName}{$VirtFunc})
+ if($TName_Tid{1}{$ClassName}
+ and not defined $VirtualTable{1}{$ClassName}{$Symbol})
{ # added to v-table
- if(not $CompleteSignature{2}{$VirtFunc}{"Override"}) {
- $AddedInt_Virt{$Level}{$ClassName}{$VirtFunc} = 1;
+ if(defined $CompleteSignature{1}{$Symbol}
+ and $CompleteSignature{1}{$Symbol}{"Virt"})
+ { # override some method in v.1
+ next;
}
+ $AddedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
}
}
}
if(defined $VirtualTable{1}{$ClassName})
{
- foreach my $VirtFunc (keys(%{$VirtualTable{1}{$ClassName}}))
+ foreach my $Symbol (keys(%{$VirtualTable{1}{$ClassName}}))
{
- if($ClassToId{2}{$ClassName}
- and not defined $VirtualTable{2}{$ClassName}{$VirtFunc})
+ if($TName_Tid{2}{$ClassName}
+ and not defined $VirtualTable{2}{$ClassName}{$Symbol})
{ # removed from v-table
- if(not $CompleteSignature{1}{$VirtFunc}{"Override"}) {
- $RemovedInt_Virt{$Level}{$ClassName}{$VirtFunc} = 1;
+ if(defined $CompleteSignature{2}{$Symbol}
+ and $CompleteSignature{2}{$Symbol}{"Virt"})
+ { # override some method in v.2
+ next;
}
+ $RemovedInt_Virt{$Level}{$ClassName}{$Symbol} = 1;
}
}
}
@@ -8244,9 +8343,9 @@
# "Base" attribute introduced in ACC 1.22 (dump 2.0 format)
return;
}
- foreach my $ClassName (sort keys(%{$ClassToId{1}}))
+ foreach my $ClassName (sort keys(%{$ClassNames{1}}))
{
- my $ClassId_Old = $ClassToId{1}{$ClassName};
+ my $ClassId_Old = $TName_Tid{1}{$ClassName};
next if(not $ClassId_Old);
if(not isCreatable($ClassId_Old, 1))
{ # skip classes without public constructors (including auto-generated)
@@ -8258,7 +8357,7 @@
next;
}
my %Class_Old = get_Type($Tid_TDid{1}{$ClassId_Old}, $ClassId_Old, 1);
- my $ClassId_New = $ClassToId{2}{$ClassName};
+ my $ClassId_New = $TName_Tid{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"}});
@@ -8295,11 +8394,11 @@
$ProblemKind .= "_And_Size";
}
}
- if(keys(%{$VirtualTable_Full{1}{$BaseName}})
- and (cmpVTables($ClassName, 1) or cmpVTables_Model($ClassName)))
+ if(keys(%{$VirtualTable_Model{1}{$BaseName}})
+ and cmpVTables($ClassName)==1)
{ # affected v-table
$ProblemKind .= "_And_VTable";
- $VTableChanged{$ClassName}=1;
+ $VTableChanged_M{$ClassName}=1;
}
}
my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
@@ -8308,7 +8407,7 @@
my $SubName = get_TypeName($SubId, 1);
push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
if($ProblemKind=~/VTable/) {
- $VTableChanged{$SubName}=1;
+ $VTableChanged_M{$SubName}=1;
}
}
foreach my $Interface (@Affected)
@@ -8347,11 +8446,11 @@
$ProblemKind .= "_And_Size";
}
}
- if(keys(%{$VirtualTable_Full{2}{$BaseName}})
- and (cmpVTables($ClassName, 1) or cmpVTables_Model($ClassName)))
+ if(keys(%{$VirtualTable_Model{2}{$BaseName}})
+ and cmpVTables($ClassName)==1)
{ # affected v-table
$ProblemKind .= "_And_VTable";
- $VTableChanged{$ClassName}=1;
+ $VTableChanged_M{$ClassName}=1;
}
}
my @Affected = keys(%{$ClassMethods{$Level}{1}{$ClassName}});
@@ -8360,7 +8459,7 @@
my $SubName = get_TypeName($SubId, 1);
push(@Affected, keys(%{$ClassMethods{$Level}{1}{$SubName}}));
if($ProblemKind=~/VTable/) {
- $VTableChanged{$SubName}=1;
+ $VTableChanged_M{$SubName}=1;
}
}
foreach my $Interface (@Affected)
@@ -8468,6 +8567,7 @@
}
}
if(defined $VirtualTable{1}{$ClassName}
+ and cmpVTables_Real($ClassName, 1)==1
and my @VFunctions = keys(%{$VirtualTable{1}{$ClassName}}))
{ # compare virtual tables size in base classes
my $VShift_Old = getVShift($ClassId_Old, 1);
@@ -8485,44 +8585,29 @@
{ # lost base
next;
}
- my $VSize_Old = getVSize($BaseType{"Name"}, 1);
- my $VSize_New = getVSize($BaseType{"Name"}, 2);
+ my $VSize_Old = getVTable_Size($BaseType{"Name"}, 1);
+ my $VSize_New = getVTable_Size($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)
+ if($VirtualTable_Model{2}{$ClassName}{$Interface}-$VirtualTable_Model{1}{$ClassName}{$Interface}==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})
+ if(not $CheckHeadersOnly)
{
- %{$CompatProblems{$Level}{$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 );
+ if(not link_symbol($Interface, 1, "-Deps"))
+ { # affected symbols in shared library
+ next;
+ }
}
- $VTableChanged{$BaseType{"Name"}} = 1;
- $VTableChanged{$ClassName} = 1;
+ $VTableChanged_M{$BaseType{"Name"}} = 1;
+ $VTableChanged_M{$ClassName} = 1;
foreach my $VirtFunc (keys(%{$AddedInt_Virt{$Level}{$BaseType{"Name"}}}))
{ # the reason of the layout change: added virtual functions
next if($VirtualReplacement{$VirtFunc});
@@ -8594,17 +8679,23 @@
sub mergeVirtualTables($$)
{ # check for changes in the virtual table
my ($Interface, $Level) = @_;
- # affected method:
+ # affected methods:
# - virtual
# - pure-virtual
# - non-virtual
-
if($CompleteSignature{1}{$Interface}{"Data"})
{ # global data is not affected
return;
}
my $Class_Id = $CompleteSignature{1}{$Interface}{"Class"};
+ if(not $Class_Id) {
+ return;
+ }
my $CName = get_TypeName($Class_Id, 1);
+ if(cmpVTables_Real($CName, 1)==0)
+ { # no changes
+ return;
+ }
$CheckedTypes{$Level}{$CName} = 1;
if($Level eq "Binary")
{ # Binary-level
@@ -8626,23 +8717,23 @@
"Type_Name"=>$CName,
"Type_Type"=>"Class",
"Target"=>get_Signature($AddedVFunc, 2) );
- $VTableChanged{$CName} = 1;
+ $VTableChanged_M{$CName} = 1;
}
elsif(not defined $VirtualTable{1}{$CName}
or $VPos_Added>keys(%{$VirtualTable{1}{$CName}}))
{ # added virtual function at the end of v-table
- if(not keys(%{$VirtualTable_Full{1}{$CName}}))
+ if(not keys(%{$VirtualTable_Model{1}{$CName}}))
{ # became polymorphous class, added v-table pointer
%{$CompatProblems{$Level}{$Interface}{"Added_First_Virtual_Method"}{$tr_name{$AddedVFunc}}}=(
"Type_Name"=>$CName,
"Type_Type"=>"Class",
"Target"=>get_Signature($AddedVFunc, 2) );
- $VTableChanged{$CName} = 1;
+ $VTableChanged_M{$CName} = 1;
}
else
{
- my $VSize_Old = getVSize($CName, 1);
- my $VSize_New = getVSize($CName, 2);
+ my $VSize_Old = getVTable_Size($CName, 1);
+ my $VSize_New = getVTable_Size($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
@@ -8654,7 +8745,7 @@
"Type_Name"=>$CName,
"Type_Type"=>"Class",
"Target"=>get_Signature($AddedVFunc, 2) );
- $VTableChanged{$CName} = 1;
+ $VTableChanged_M{$CName} = 1;
}
else
{
@@ -8666,7 +8757,7 @@
"Type_Name"=>$CName,
"Type_Type"=>"Class",
"Target"=>get_Signature($AddedVFunc, 2) );
- $VTableChanged{$CName} = 1;
+ $VTableChanged_M{$CName} = 1;
}
}
}
@@ -8692,7 +8783,7 @@
"Type_Name"=>$CName,
"Type_Type"=>"Class",
"Target"=>get_Signature($AddedVFunc, 2) );
- $VTableChanged{get_TypeName($CompleteSignature{1}{$ASymbol}{"Class"}, 1)} = 1;
+ $VTableChanged_M{get_TypeName($CompleteSignature{1}{$ASymbol}{"Class"}, 1)} = 1;
}
}
}
@@ -8710,13 +8801,13 @@
# implemented in both versions of a library
next;
}
- if(not keys(%{$VirtualTable_Full{2}{$CName}}))
+ if(not keys(%{$VirtualTable_Model{2}{$CName}}))
{ # became non-polymorphous class, removed v-table pointer
%{$CompatProblems{$Level}{$Interface}{"Removed_Last_Virtual_Method"}{$tr_name{$RemovedVFunc}}}=(
"Type_Name"=>$CName,
"Type_Type"=>"Class",
"Target"=>get_Signature($RemovedVFunc, 1) );
- $VTableChanged{$CName} = 1;
+ $VTableChanged_M{$CName} = 1;
}
elsif($CompleteSignature{1}{$Interface}{"Virt"}
or $CompleteSignature{1}{$Interface}{"PureVirt"})
@@ -8757,7 +8848,7 @@
"Type_Name"=>$CName,
"Type_Type"=>"Class",
"Target"=>get_Signature($RemovedVFunc, 1) );
- $VTableChanged{get_TypeName($CompleteSignature{1}{$ASymbol}{"Class"}, 1)} = 1;
+ $VTableChanged_M{get_TypeName($CompleteSignature{1}{$ASymbol}{"Class"}, 1)} = 1;
}
}
}
@@ -8861,10 +8952,10 @@
{
foreach (@RecurTypes)
{
- if($_->{"Tid1"} eq $_[0]
- and $_->{"TDid1"} eq $_[1]
- and $_->{"Tid2"} eq $_[2]
- and $_->{"TDid2"} eq $_[3])
+ if( $_->{"1"} eq $_[0]
+ and $_->{"2"} eq $_[1]
+ and $_->{"3"} eq $_[2]
+ and $_->{"4"} eq $_[3] )
{
return 1;
}
@@ -8875,10 +8966,11 @@
sub pushType($$$$)
{
my %TypeIDs=(
- "Tid1" => $_[0],
- "TDid1" => $_[1],
- "Tid2" => $_[2],
- "TDid2" => $_[3] );
+ "1" => $_[0], #Tid1
+ "2" => $_[1], #TDid1
+ "3" => $_[2], #Tid2
+ "4" => $_[3] #TDid2
+ );
push(@RecurTypes, \%TypeIDs);
}
@@ -8991,9 +9083,12 @@
}
my %Type1 = get_Type($Type1_DId, $Type1_Id, 1);
my %Type2 = get_Type($Type2_DId, $Type2_Id, 2);
+ if(not $Type1{"Name"} or not $Type2{"Name"}) {
+ return ();
+ }
+ $CheckedTypes{$Level}{$Type1{"Name"}}=1;
my %Type1_Pure = get_PureType($Type1_DId, $Type1_Id, 1);
my %Type2_Pure = get_PureType($Type2_DId, $Type2_Id, 2);
- $CheckedTypes{$Level}{$Type1{"Name"}}=1;
$CheckedTypes{$Level}{$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"}))
@@ -9666,6 +9761,8 @@
sub goToFirst($$$$)
{
my ($TypeDId, $TypeId, $LibVersion, $Type_Type) = @_;
+ return () if(not $TypeId);
+ $TypeDId = "" if(not defined $TypeDId);
if(defined $Cache{"goToFirst"}{$TypeDId}{$TypeId}{$LibVersion}{$Type_Type}) {
return %{$Cache{"goToFirst"}{$TypeDId}{$TypeId}{$LibVersion}{$Type_Type}};
}
@@ -9748,6 +9845,7 @@
{
my ($TypeDId, $TypeId, $LibVersion) = @_;
return "" if(not $TypeId);
+ $TypeDId = "" if(not defined $TypeDId);
return "" if(not $TypeInfo{$LibVersion}{$TypeDId}{$TypeId});
my %Type = %{$TypeInfo{$LibVersion}{$TypeDId}{$TypeId}};
return "" if(not $Type{"BaseType"}{"TDid"} and not $Type{"BaseType"}{"Tid"});
@@ -9774,6 +9872,7 @@
{
my ($TypeDId, $TypeId, $LibVersion) = @_;
return () if(not $TypeId);
+ $TypeDId = "" if(not defined $TypeDId);
return () if(not $TypeInfo{$LibVersion}{$TypeDId}{$TypeId});
my %Type = %{$TypeInfo{$LibVersion}{$TypeDId}{$TypeId}};
if(not $Type{"BaseType"}{"TDid"}
@@ -9792,7 +9891,7 @@
return %{$TypeInfo{$LibVersion}{$TypeDId}{$TypeId}};
}
-sub skipGlobalData($)
+sub skipPrivateData($)
{
my $Symbol = $_[0];
return ($Symbol=~/\A(_ZGV|_ZTI|_ZTS|_ZTT|_ZTV|_ZTC|_ZThn|_ZTv0_n)/);
@@ -9804,7 +9903,7 @@
return 0 if($Symbol!~/\A(_Z|\?)/);
my $Signature = $tr_name{$Symbol};
return 0 if($Signature!~/>/);
- my $ShortName = substr($Signature, 0, detect_center($Signature, "("));
+ my $ShortName = substr($Signature, 0, find_center($Signature, "("));
$ShortName=~s/::operator .*//;# class::operator template<instance>
return ($ShortName=~/<.+>/);
}
@@ -9829,7 +9928,7 @@
sub symbolFilter($$$$)
{ # some special cases when the symbol cannot be imported
my ($Symbol, $LibVersion, $Type, $Level) = @_;
- if(skipGlobalData($Symbol))
+ if(skipPrivateData($Symbol))
{ # non-public global data
return 0;
}
@@ -9946,9 +10045,9 @@
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", "Binary"));
- my $Impl1 = canonify_implementation($Interface_Impl{1}{$Interface});
+ my $Impl1 = canonifyImpl($Interface_Impl{1}{$Interface});
next if(not $Impl1);
- my $Impl2 = canonify_implementation($Interface_Impl{2}{$Interface});
+ my $Impl2 = canonifyImpl($Interface_Impl{2}{$Interface});
next if(not $Impl2);
if($Impl1 ne $Impl2)
{
@@ -9965,7 +10064,7 @@
}
}
-sub canonify_implementation($)
+sub canonifyImpl($)
{
my $FuncBody= $_[0];
return "" if(not $FuncBody);
@@ -10136,7 +10235,8 @@
my ($SN, $SS, $SV) = separate_symbol($Symbol);
$Symbol=$SN;
}
- if(not $CompleteSignature{2}{$Symbol}{"Header"}) {
+ if(not $CompleteSignature{2}{$Symbol}{"Header"}
+ or not $CompleteSignature{2}{$Symbol}{"MnglName"}) {
next;
}
if($GeneratedSymbols{$Symbol}) {
@@ -10145,24 +10245,23 @@
if(not defined $CompleteSignature{1}{$Symbol}
or not $CompleteSignature{1}{$Symbol}{"MnglName"})
{
- if(($UsedDump{1}{"BinOnly"} and $UsedDump{2}{"SrcBin"})
- or (not checkDumpVersion(1, "2.11") and checkDumpVersion(2, "2.11")))
- { # support for old and different (!) ABI dumps
- if(not $CompleteSignature{2}{$Symbol}{"Virt"}
- and not $CompleteSignature{2}{$Symbol}{"PureVirt"})
- {
- if($CheckHeadersOnly)
+ if($UsedDump{2}{"SrcBin"})
+ {
+ if($UsedDump{1}{"BinOnly"} or not checkDumpVersion(1, "2.11"))
+ { # support for old and different (!) ABI dumps
+ if(not $CompleteSignature{2}{$Symbol}{"Virt"}
+ and not $CompleteSignature{2}{$Symbol}{"PureVirt"})
{
- if($CompleteSignature{2}{$Symbol}{"InLine"})
- { # skip added inline symbols
+ if($CheckHeadersOnly)
+ { # skip all added symbols
next;
}
- }
- else
- {
- if(not link_symbol($Symbol, 2, "-Deps"))
- { # skip added inline symbols
- next;
+ else
+ {
+ if(not link_symbol($Symbol, 2, "-Deps"))
+ { # skip added inline symbols
+ next;
+ }
}
}
}
@@ -10182,7 +10281,8 @@
my ($SN, $SS, $SV) = separate_symbol($Symbol);
$Symbol=$SN;
}
- if(not $CompleteSignature{1}{$Symbol}{"Header"}) {
+ if(not $CompleteSignature{1}{$Symbol}{"Header"}
+ or not $CompleteSignature{1}{$Symbol}{"MnglName"}) {
next;
}
if($GeneratedSymbols{$Symbol}) {
@@ -10191,24 +10291,23 @@
if(not defined $CompleteSignature{2}{$Symbol}
or not $CompleteSignature{2}{$Symbol}{"MnglName"})
{ # support for old and different (!) ABI dumps
- if(($UsedDump{1}{"SrcBin"} and $UsedDump{2}{"BinOnly"})
- or (checkDumpVersion(1, "2.11") and not checkDumpVersion(2, "2.11")))
+ if($UsedDump{1}{"SrcBin"})
{
- if(not $CompleteSignature{1}{$Symbol}{"Virt"}
- and not $CompleteSignature{1}{$Symbol}{"PureVirt"})
+ if($UsedDump{2}{"BinOnly"} or not checkDumpVersion(2, "2.11"))
{
- if($CheckHeadersOnly)
+ if(not $CompleteSignature{1}{$Symbol}{"Virt"}
+ and not $CompleteSignature{1}{$Symbol}{"PureVirt"})
{
- if($CompleteSignature{1}{$Symbol}{"InLine"})
- { # skip added inline symbols
+ if($CheckHeadersOnly)
+ { # skip all removed symbols
next;
}
- }
- else
- {
- if(not link_symbol($Symbol, 1, "-Deps"))
- { # skip removed inline symbols
- next;
+ else
+ {
+ if(not link_symbol($Symbol, 1, "-Deps"))
+ { # skip removed inline symbols
+ next;
+ }
}
}
}
@@ -10295,8 +10394,9 @@
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}) {
+ next if(not $Typedef_BaseName{2}{$Typedef}); # exclude added/removed
+ if($Typedef_BaseName{1}{$Typedef} ne $Typedef_BaseName{2}{$Typedef})
+ {
$ChangedTypedef{$Typedef} = 1;
}
}
@@ -10308,7 +10408,7 @@
my ($SN, $SO, $SV) = separate_symbol($Symbol);
$Symbol=$SN;# remove version
my $Signature = $tr_name{$Symbol};
- my $Suffix = substr($Signature, detect_center($Signature, "("));
+ my $Suffix = substr($Signature, find_center($Signature, "("));
if(not $Full) {
$Suffix=~s/(\))\s*(const volatile|volatile const|const|volatile)\Z/$1/g;
}
@@ -10383,35 +10483,7 @@
{
my $Level = $_[0];
my %SubProblems = ();
-
- registerVTable(1, $Level);
- registerVTable(2, $Level);
- if(not checkDumpVersion(1, "1.22")
- and checkDumpVersion(2, "1.22"))
- { # 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($Level);
my %AddedOverloads = ();
@@ -10439,10 +10511,10 @@
{ # register virtual overridings
my $AffectedClass_Name = get_TypeName($CompleteSignature{2}{$Symbol}{"Class"}, 2);
if(defined $CompleteSignature{1}{$OverriddenMethod}
- and $CompleteSignature{1}{$OverriddenMethod}{"Virt"} and $ClassToId{1}{$AffectedClass_Name}
+ and $CompleteSignature{1}{$OverriddenMethod}{"Virt"} and $TName_Tid{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))
+ if(isCopyingClass($TName_Tid{1}{$AffectedClass_Name}, 1))
{ # old v-table (copied) will be used by applications
next;
}
@@ -10486,7 +10558,7 @@
{ # register virtual overridings
my $AffectedClass_Name = get_TypeName($CompleteSignature{1}{$Symbol}{"Class"}, 1);
if(defined $CompleteSignature{2}{$OverriddenMethod}
- and $CompleteSignature{2}{$OverriddenMethod}{"Virt"} and $ClassToId{2}{$AffectedClass_Name})
+ and $CompleteSignature{2}{$OverriddenMethod}{"Virt"} and $TName_Tid{2}{$AffectedClass_Name})
{ # virtual methods, virtual destructors: class should exist in newer version
if(isCopyingClass($CompleteSignature{1}{$Symbol}{"Class"}, 1))
{ # old v-table (copied) will be used by applications
@@ -10712,9 +10784,8 @@
next;
}
# checking virtual table
- if($CompleteSignature{1}{$Symbol}{"Class"}) {
- mergeVirtualTables($Symbol, $Level);
- }
+ mergeVirtualTables($Symbol, $Level);
+
if($COMPILE_ERRORS)
{ # if some errors occurred at the compiling stage
# then some false positives can be skipped here
@@ -10773,7 +10844,7 @@
"New_Value"=>$CompleteSignature{2}{$PSymbol}{"RelPos"},
"Target"=>get_Signature($Symbol, 1) );
}
- $VTableChanged{$Class_Type{"Name"}} = 1;
+ $VTableChanged_M{$Class_Type{"Name"}} = 1;
}
}
}
@@ -11923,7 +11994,7 @@
if($ShowRetVal and $Signature=~s/([^:]):([^:].+?)\Z/$1/g) {
$Return = $2;
}
- my $SCenter = detect_center($Signature, "(");
+ my $SCenter = find_center($Signature, "(");
if(not $SCenter)
{ # global data
$Signature = htmlSpecChars($Signature);
@@ -12001,7 +12072,7 @@
{
my ($Signature, $Comma) = @_;
my @Parts = ();
- my $ShortName = substr($Signature, 0, detect_center($Signature, "("));
+ my $ShortName = substr($Signature, 0, find_center($Signature, "("));
$Signature=~s/\A\Q$ShortName\E\(//g;
cut_f_attrs($Signature);
$Signature=~s/\)\Z//;
@@ -12012,40 +12083,37 @@
{
my ($Params, $Comma) = @_;
my @Parts = ();
- my ($Bracket_Num, $Bracket2_Num, $Part_Num) = (0, 0, 0);
+ my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
+ my $Part = 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)
+ my $S = substr($Params, $Pos, 1);
+ if(defined $B{$S}) {
+ $B{$S}+=1;
+ }
+ if($S eq "," and
+ $B{"("}==$B{")"} and $B{"<"}==$B{">"})
{
if($Comma)
{ # include comma
- $Parts[$Part_Num] .= $Symbol;
+ $Parts[$Part] .= $S;
}
- $Part_Num += 1;
+ $Part += 1;
}
else {
- $Parts[$Part_Num] .= $Symbol;
+ $Parts[$Part] .= $S;
}
}
return @Parts;
}
-sub detect_center($$)
+sub find_center($$)
{
my ($Sign, $Target) = @_;
- my %B = (
- "("=>0,
- "<"=>0,
- ")"=>0,
- ">"=>0 );
+ my %B = ( "("=>0, "<"=>0, ")"=>0, ">"=>0 );
my $Center = 0;
- if($Sign=~s/(operator([<>\-\=\*]+|\(\)))//g)
- { # operators: (),->,->*,<,<=,<<,<<=,>,>=,>>,>>=
+ if($Sign=~s/(operator([^\w\s\(\)]+|\(\)))//g)
+ { # operators
$Center+=length($1);
}
foreach my $Pos (0 .. length($Sign)-1)
@@ -12073,7 +12141,7 @@
if(my $Dir = get_dirname($Path)) {
mkpath($Dir);
}
- open(FILE, ">>".$Path) || die ("can't open file \'$Path\': $!\n");
+ open(FILE, ">>", $Path) || die ("can't open file \'$Path\': $!\n");
print FILE $Content;
close(FILE);
}
@@ -12085,7 +12153,7 @@
if(my $Dir = get_dirname($Path)) {
mkpath($Dir);
}
- open (FILE, ">".$Path) || die ("can't open file \'$Path\': $!\n");
+ open(FILE, ">", $Path) || die ("can't open file \'$Path\': $!\n");
print FILE $Content;
close(FILE);
}
@@ -12094,7 +12162,7 @@
{
my $Path = $_[0];
return "" if(not $Path or not -f $Path);
- open (FILE, $Path);
+ open(FILE, $Path);
local $/ = undef;
my $Content = <FILE>;
close(FILE);
@@ -12106,7 +12174,7 @@
sub get_filename($)
{ # much faster than basename() from File::Basename module
- if($_[0]=~/([^\/\\]+)[\/\\]*\Z/) {
+ if($_[0] and $_[0]=~/([^\/\\]+)[\/\\]*\Z/) {
return $1;
}
return "";
@@ -12114,7 +12182,7 @@
sub get_dirname($)
{ # much faster than dirname() from File::Basename module
- if($_[0]=~/\A(.*?)[\/\\]+[^\/\\]*[\/\\]*\Z/) {
+ if($_[0] and $_[0]=~/\A(.*?)[\/\\]+[^\/\\]*[\/\\]*\Z/) {
return $1;
}
return "";
@@ -12135,7 +12203,7 @@
{
my ($Path, $Num) = @_;
return "" if(not $Path or not -f $Path);
- open (FILE, $Path);
+ open(FILE, $Path);
foreach (1 ... $Num) {
<FILE>;
}
@@ -12626,10 +12694,10 @@
if($JoinReport)
{
if($Level eq "Binary") {
- $TestInfo .= "<tr><th>Subject</th><td>Binary Compatibility</td></tr>\n"; # Run-time
+ $TestInfo .= "<tr><th>Subject</th><td width='150px'>Binary Compatibility</td></tr>\n"; # Run-time
}
if($Level eq "Source") {
- $TestInfo .= "<tr><th>Subject</th><td>Source Compatibility</td></tr>\n"; # Build-time
+ $TestInfo .= "<tr><th>Subject</th><td width='150px'>Source Compatibility</td></tr>\n"; # Build-time
}
}
$TestInfo .= "</table>\n";
@@ -12651,18 +12719,18 @@
$TestResults .= "<tr><th>Total Symbols / Types</th><td>".(keys(%{$CheckedSymbols{$Level}}) - keys(%GeneratedSymbols))." / ".$TotalTypes."</td></tr>\n";
- my $Verdict = "";
- if($RESULT{$Level}{"Problems"}) {
- $Verdict = "<span style='color:Red;'><b>Incompatible<br/>(".$RESULT{$Level}{"Affected"}."%)</b></span>";
- }
- else {
- $Verdict = "<span style='color:Green;'><b>Compatible</b></span>";
- }
my $META_DATA = $RESULT{$Level}{"Problems"}?"verdict:incompatible;":"verdict:compatible;";
if($JoinReport) {
$META_DATA = "kind:".lc($Level).";".$META_DATA;
}
- $TestResults .= "<tr><th>Verdict</th><td>$Verdict</td></tr>";
+ $TestResults .= "<tr><th>Verdict</th>";
+ if($RESULT{$Level}{"Problems"}) {
+ $TestResults .= "<td><span style='color:Red;'><b>Incompatible<br/>(".$RESULT{$Level}{"Affected"}."%)</b></span></td>";
+ }
+ else {
+ $TestResults .= "<td><span style='color:Green;'><b>Compatible</b></span></td>";
+ }
+ $TestResults .= "</tr>\n";
$TestResults .= "</table>\n";
$META_DATA .= "affected:".$RESULT{$Level}{"Affected"}.";";# in percents
@@ -12683,7 +12751,7 @@
}
#$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";
+ $Problem_Summary .= "<tr><th>Added Symbols</th><td>-</td><td".getStyle("I", "A", $Added).">$Added_Link</td></tr>\n";
my $Removed_Link = "0";
if($Removed>0)
@@ -12697,43 +12765,46 @@
}
#$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";
+ $Problem_Summary .= "<tr><th>Removed Symbols</th>";
+ $Problem_Summary .= "<td>High</td><td".getStyle("I", "R", $Removed).">$Removed_Link</td></tr>\n";
my $TH_Link = "0";
$TH_Link = "<a href='#".get_Anchor("Type", $Level, "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";
+ $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Data Types</th>";
+ $Problem_Summary .= "<td>High</td><td".getStyle("T", "H", $T_Problems_High).">$TH_Link</td></tr>\n";
my $TM_Link = "0";
$TM_Link = "<a href='#".get_Anchor("Type", $Level, "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";
+ $Problem_Summary .= "<tr><td>Medium</td><td".getStyle("T", "M", $T_Problems_Medium).">$TM_Link</td></tr>\n";
my $TL_Link = "0";
$TL_Link = "<a href='#".get_Anchor("Type", $Level, "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";
+ $Problem_Summary .= "<tr><td>Low</td><td".getStyle("T", "L", $T_Problems_Low).">$TL_Link</td></tr>\n";
my $IH_Link = "0";
$IH_Link = "<a href='#".get_Anchor("Symbol", $Level, "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";
+ $Problem_Summary .= "<tr><th rowspan='3'>Problems with<br/>Symbols</th>";
+ $Problem_Summary .= "<td>High</td><td".getStyle("I", "H", $I_Problems_High).">$IH_Link</td></tr>\n";
my $IM_Link = "0";
$IM_Link = "<a href='#".get_Anchor("Symbol", $Level, "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";
+ $Problem_Summary .= "<tr><td>Medium</td><td".getStyle("I", "M", $I_Problems_Medium).">$IM_Link</td></tr>\n";
my $IL_Link = "0";
$IL_Link = "<a href='#".get_Anchor("Symbol", $Level, "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";
+ $Problem_Summary .= "<tr><td>Low</td><td".getStyle("I", "L", $I_Problems_Low).">$IL_Link</td></tr>\n";
my $ChangedConstants_Link = "0";
if(keys(%{$CheckedSymbols{$Level}}) and $C_Problems_Low)
@@ -12747,7 +12818,7 @@
}
$ChangedConstants_Link = "n/a" if($CheckObjectsOnly);
$META_DATA .= "changed_constants:$C_Problems_Low;";
- $Problem_Summary .= "<tr><th>Problems with<br/>Constants</th><td>Low</td><td>$ChangedConstants_Link</td></tr>\n";
+ $Problem_Summary .= "<tr><th>Problems with<br/>Constants</th><td>Low</td><td".getStyle("C", "L", $C_Problems_Low).">$ChangedConstants_Link</td></tr>\n";
if($CheckImpl and $Level eq "Binary")
{
@@ -12755,34 +12826,59 @@
$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";
+ $Problem_Summary .= "<tr><th>Problems with<br/>Implementation</th><td>Low</td><td".getStyle("Imp", "L", keys(%ImplProblems)).">$ChangedImpl_Link</td></tr>\n";
}
# Safe Changes
if($T_Other and not $CheckObjectsOnly)
{
my $TS_Link = "<a href='#".get_Anchor("Type", $Level, "Safe")."' style='color:Blue;'>$T_Other</a>";
- $Problem_Summary .= "<tr><th>Other Changes<br/>in Data Types</th><td>-</td><td>$TS_Link</td></tr>\n";
+ $Problem_Summary .= "<tr><th>Other Changes<br/>in Data Types</th><td>-</td><td".getStyle("T", "S", $T_Other).">$TS_Link</td></tr>\n";
}
if($I_Other and not $CheckObjectsOnly)
{
my $IS_Link = "<a href='#".get_Anchor("Symbol", $Level, "Safe")."' style='color:Blue;'>$I_Other</a>";
- $Problem_Summary .= "<tr><th>Other Changes<br/>in Symbols</th><td>-</td><td>$IS_Link</td></tr>\n";
+ $Problem_Summary .= "<tr><th>Other Changes<br/>in Symbols</th><td>-</td><td".getStyle("I", "S", $I_Other).">$IS_Link</td></tr>\n";
}
$META_DATA .= "tool_version:$TOOL_VERSION";
$Problem_Summary .= "</table>\n";
+ # $TestInfo = getLegend().$TestInfo;
return ($TestInfo.$TestResults.$Problem_Summary, $META_DATA);
}
}
+sub getStyle($$$)
+{
+ my ($Subj, $Act, $Num) = @_;
+ my %Style = (
+ "A"=>"new",
+ "R"=>"failed",
+ "S"=>"passed",
+ "L"=>"warning",
+ "M"=>"failed",
+ "H"=>"failed"
+ );
+ if($Num>0) {
+ return " class='".$Style{$Act}."'";
+ }
+ return "";
+}
+
sub show_number($)
{
if($_[0])
{
- my $Num = cut_off_number($_[0], 3, 0);
- if($Num eq "0") {
- $Num = cut_off_number($_[0], 7, 1);
+ my $Num = cut_off_number($_[0], 2, 0);
+ if($Num eq "0")
+ {
+ foreach my $P (3 .. 7)
+ {
+ $Num = cut_off_number($_[0], $P, 1);
+ if($Num ne "0") {
+ last;
+ }
+ }
}
if($Num eq "0") {
$Num = $_[0];
@@ -12821,9 +12917,10 @@
sub get_Report_ChangedConstants($)
{
my $Level = $_[0];
- my ($CHANGED_CONSTANTS, %HeaderConstant) = ();
+ my $CHANGED_CONSTANTS = "";
+ my %ReportMap = ();
foreach my $Constant (keys(%{$ProblemsWithConstants{$Level}})) {
- $HeaderConstant{$Constants{1}{$Constant}{"Header"}}{$Constant} = 1;
+ $ReportMap{$Constants{1}{$Constant}{"Header"}}{$Constant} = 1;
}
my $Kind = "Changed_Constant";
if(not defined $CompatRules{$Level}{$Kind}) {
@@ -12831,10 +12928,10 @@
}
if($ReportFormat eq "xml")
{ # XML
- foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%HeaderConstant))
+ foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
{
$CHANGED_CONSTANTS .= " <header name=\"$HeaderName\">\n";
- foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$HeaderConstant{$HeaderName}}))
+ foreach my $Constant (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
{
$CHANGED_CONSTANTS .= " <constant name=\"$Constant\">\n";
my $Change = $CompatRules{$Level}{$Kind}{"Change"};
@@ -12854,10 +12951,10 @@
else
{ # HTML
my $Number = 0;
- foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%HeaderConstant))
+ foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
{
$CHANGED_CONSTANTS .= "<span class='h_name'>$HeaderName</span><br/>\n";
- foreach my $Name (sort {lc($a) cmp lc($b)} keys(%{$HeaderConstant{$HeaderName}}))
+ foreach my $Name (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
{
$Number += 1;
my $Change = applyMacroses($Level, $Kind, $CompatRules{$Level}{$Kind}{"Change"}, $ProblemsWithConstants{$Level}{$Name});
@@ -12883,17 +12980,18 @@
sub get_Report_Impl()
{
- my ($CHANGED_IMPLEMENTATION, %HeaderLibFunc);
+ my $CHANGED_IMPLEMENTATION = "";
+ my %ReportMap = ();
foreach my $Interface (sort keys(%ImplProblems))
{
my $HeaderName = $CompleteSignature{1}{$Interface}{"Header"};
my $DyLib = $Symbol_Library{1}{$Interface};
- $HeaderLibFunc{$HeaderName}{$DyLib}{$Interface} = 1;
+ $ReportMap{$HeaderName}{$DyLib}{$Interface} = 1;
}
my $Changed_Number = 0;
- foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%HeaderLibFunc))
+ foreach my $HeaderName (sort {lc($a) cmp lc($b)} keys(%ReportMap))
{
- foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$HeaderLibFunc{$HeaderName}}))
+ foreach my $DyLib (sort {lc($a) cmp lc($b)} keys(%{$ReportMap{$HeaderName}}))
{
my $FDyLib=$DyLib.($DyLib!~/\.\w+\Z/?" (.$LIB_EXT)":"");
if($HeaderName) {
@@ -12903,7 +13001,7 @@
$CHANGED_IMPLEMENTATION .= "<span class='lib_name'>$DyLib</span><br/>\n";
}
my %NameSpaceSymbols = ();
- foreach my $Interface (keys(%{$HeaderLibFunc{$HeaderName}{$DyLib}})) {
+ foreach my $Interface (keys(%{$ReportMap{$HeaderName}{$DyLib}})) {
$NameSpaceSymbols{get_IntNameSpace($Interface, 2)}{$Interface} = 1;
}
foreach my $NameSpace (sort keys(%NameSpaceSymbols))
@@ -12956,7 +13054,8 @@
sub get_Report_Added($)
{
my $Level = $_[0];
- my ($ADDED_INTERFACES, %ReportMap);
+ my $ADDED_INTERFACES = "";
+ my %ReportMap = ();
foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
{
foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
@@ -13048,7 +13147,8 @@
sub get_Report_Removed($)
{
my $Level = $_[0];
- my (%ReportMap, $REMOVED_INTERFACES) = ();
+ my $REMOVED_INTERFACES = "";
+ my %ReportMap = ();
foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
{
foreach my $Kind (sort keys(%{$CompatProblems{$Level}{$Interface}}))
@@ -13266,7 +13366,8 @@
sub get_Report_SymbolProblems($$)
{
my ($TargetSeverity, $Level) = @_;
- my ($INTERFACE_PROBLEMS, %ReportMap, %SymbolChanges);
+ my $INTERFACE_PROBLEMS = "";
+ my (%ReportMap, %SymbolChanges) = ();
foreach my $Symbol (sort keys(%{$CompatProblems{$Level}}))
{
my ($SN, $SS, $SV) = separate_symbol($Symbol);
@@ -13428,7 +13529,8 @@
sub get_Report_TypeProblems($$)
{
my ($TargetSeverity, $Level) = @_;
- my ($TYPE_PROBLEMS, %ReportMap, %TypeChanges, %TypeType) = ();
+ my $TYPE_PROBLEMS = "";
+ my (%ReportMap, %TypeChanges, %TypeType) = ();
foreach my $Interface (sort keys(%{$CompatProblems{$Level}}))
{
foreach my $Kind (keys(%{$CompatProblems{$Level}{$Interface}}))
@@ -13663,11 +13765,11 @@
{
if($Entries{$Index}{"E1"})
{
- $Color1 = " class='vtable_red'";
- $Color2 = " class='vtable_red'";
+ $Color1 = " class='failed'";
+ $Color2 = " class='failed'";
}
else {
- $Color2 = " class='vtable_yellow'";
+ $Color2 = " class='warning'";
}
}
$VTABLES .= "<tr><th>".$Index."</th>\n";
@@ -14097,8 +14199,8 @@
my $Report = "<!-\- $BMetaData -\->\n<!-\- $SMetaData -\->\n".composeHTML_Head($Title, $Keywords, $Description, $CssStyles, $JScripts)."<body><a name='Source'></a><a name='Binary'></a><a name='Top'></a>";
$Report .= get_Report_Header("Join")."
<br/><div class='tabset'>
- <a id='BinaryID' href='#BinaryTab' class='tab active'>Binary-level</a>
- <a id='SourceID' href='#SourceTab' style='margin-left:3px' class='tab disabled'>Source-level</a>
+ <a id='BinaryID' href='#BinaryTab' class='tab active'>Binary<br/>Compatibility</a>
+ <a id='SourceID' href='#SourceTab' style='margin-left:3px' class='tab disabled'>Source<br/>Compatibility</a>
</div>";
$Report .= "<div id='BinaryTab' class='tab'>\n$BSummary\n".get_Report_Added("Binary").get_Report_Removed("Binary").get_Report_Problems("High", "Binary").get_Report_Problems("Medium", "Binary").get_Report_Problems("Low", "Binary").get_Report_Problems("Safe", "Binary").get_SourceInfo()."<br/><br/><br/></div>";
$Report .= "<div id='SourceTab' class='tab'>\n$SSummary\n".get_Report_Added("Source").get_Report_Removed("Source").get_Report_Problems("High", "Source").get_Report_Problems("Medium", "Source").get_Report_Problems("Low", "Source").get_Report_Problems("Safe", "Source").get_SourceInfo()."<br/><br/><br/></div>";
@@ -14132,6 +14234,20 @@
}
}
+sub getLegend()
+{
+ return "<br/>
+<table class='summary'>
+<tr>
+ <td class='new'>added</td>
+ <td class='passed'>compatible</td>
+</tr>
+<tr>
+ <td class='warning'>warning</td>
+ <td class='failed'>incompatible</td>
+</tr></table>\n";
+}
+
sub createReport()
{
if($JoinReport)
@@ -14169,8 +14285,8 @@
{
my ($Priority, $Level) = @_;
my $Report = get_Report_TypeProblems($Priority, $Level);
- if(my $SymProblems = get_Report_SymbolProblems($Priority, $Level)) {
- $Report .= $SymProblems;
+ if(my $SProblems = get_Report_SymbolProblems($Priority, $Level)) {
+ $Report .= $SProblems;
}
if($Priority eq "Low")
{
@@ -14295,6 +14411,33 @@
}
}
+sub uncoverConstant($$)
+{
+ my ($LibVersion, $Constant) = @_;
+ return "" if(not $LibVersion or not $Constant);
+ return $Constant if(isCyclical(\@RecurConstant, $Constant));
+ if(defined $Cache{"uncoverConstant"}{$LibVersion}{$Constant}) {
+ return $Cache{"uncoverConstant"}{$LibVersion}{$Constant};
+ }
+ my $Value = $Constants{$LibVersion}{$Constant}{"Value"};
+ if(defined $Value)
+ {
+ if($Value=~/\A[A-Z0-9_]+\Z/ and $Value=~/[A-Z]/)
+ {
+ push(@RecurConstant, $Constant);
+ my $Uncovered = uncoverConstant($LibVersion, $Value);
+ if($Uncovered 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)
+ return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = $Value);
+ }
+ return ($Cache{"uncoverConstant"}{$LibVersion}{$Constant} = "");
+}
+
my %IgnoreConstant=(
"VERSION"=>1,
"VERSIONCODE"=>1,
@@ -14351,7 +14494,8 @@
{ # skipped by the user
next;
}
- if($Constants{2}{$Constant}{"Value"} eq "")
+ if(not defined $Constants{2}{$Constant}{"Value"}
+ or $Constants{2}{$Constant}{"Value"} eq "")
{ # empty value
next;
}
@@ -14360,8 +14504,8 @@
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 = $Old_Value_Pure = uncoverConstant(1, $Constant);
+ $New_Value = $New_Value_Pure = uncoverConstant(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;
@@ -14431,34 +14575,11 @@
}
}
-sub uncover_constant($$)
-{
- my ($LibVersion, $Constant) = @_;
- return "" if(not $LibVersion or not $Constant);
- return $Constant if(isCyclical(\@RecurConstant, $Constant));
- if(defined $Cache{"uncover_constant"}{$LibVersion}{$Constant}) {
- 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($)
+sub readSymbols($)
{
my $LibVersion = $_[0];
- my @DyLibPaths = getSoPaths($LibVersion);
- if($#DyLibPaths==-1 and not $CheckHeadersOnly)
+ my @LibPaths = getSoPaths($LibVersion);
+ if($#LibPaths==-1 and not $CheckHeadersOnly)
{
if($LibVersion==1)
{
@@ -14469,38 +14590,42 @@
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");
+ my %GroupNames = map {parse_libname(get_filename($_), "name+ext", $OStarget)=>1} @LibPaths;
+ foreach my $LibPath (sort {length($a)<=>length($b)} @LibPaths) {
+ readSymbols_Lib($LibVersion, $LibPath, 0, \%GroupNames, "+Weak");
}
-}
-
-sub get_VTableSymbolSize($$)
-{
- my ($ClassName, $LibVersion) = @_;
- return 0 if(not $ClassName);
- if(my $Symbol = $ClassVTable{$ClassName})
+ if(not $CheckHeadersOnly)
{
- 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;
- }
+ if($#LibPaths!=-1)
+ {
+ if(not keys(%{$Symbol_Library{$LibVersion}}))
+ {
+ printMsg("WARNING", "the set of public symbols in library(ies) is empty");
+ printMsg("WARNING", "checking headers only");
+ $CheckHeadersOnly = 1;
}
}
}
}
+sub getSymbolSize($$)
+{ # size from the shared library
+ my ($Symbol, $LibVersion) = @_;
+ return 0 if(not $Symbol);
+ if(defined $Symbol_Library{$LibVersion}{$Symbol}
+ and my $LibName = $Symbol_Library{$LibVersion}{$Symbol})
+ {
+ if(defined $Library_Symbol{$LibVersion}{$LibName}{$Symbol}
+ and my $Size = $Library_Symbol{$LibVersion}{$LibName}{$Symbol})
+ {
+ if($Size<0) {
+ return -$Size;
+ }
+ }
+ }
+ 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>*)
@@ -14622,7 +14747,7 @@
return 0;
}
-sub getSymbols_App($)
+sub readSymbols_App($)
{
my $Path = $_[0];
return () if(not $Path or not -f $Path);
@@ -14723,7 +14848,117 @@
}
}
-sub getSymbols_Lib($$$$$)
+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 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 readSymbols_Lib($$$$$)
{
my ($LibVersion, $Lib_Path, $IsNeededLib, $GroupNames, $Weak) = @_;
return if(not $Lib_Path or not -f $Lib_Path);
@@ -14764,11 +14999,13 @@
$OtoolCmd .= " -TV \"".$Lib_Path."\" 2>$TMP_DIR/null";
if($Debug)
{ # debug mode
+ # write to file
system($OtoolCmd." >".$DebugPath);
- open(LIB, $DebugPath); # write to file
+ open(LIB, $DebugPath);
}
- else {
- open(LIB, $OtoolCmd." |"); # write to pipe
+ else
+ { # write to pipe
+ open(LIB, $OtoolCmd." |");
}
while(<LIB>)
{
@@ -14817,11 +15054,13 @@
$DumpBinCmd .= " /EXPORTS \"".$Lib_Path."\" 2>$TMP_DIR/null";
if($Debug)
{ # debug mode
+ # write to file
system($DumpBinCmd." >".$DebugPath);
- open(LIB, $DebugPath); # write to file
+ open(LIB, $DebugPath);
}
- else {
- open(LIB, $DumpBinCmd." |"); # write to pipe
+ else
+ { # write to pipe
+ open(LIB, $DumpBinCmd." |");
}
while(<LIB>)
{ # 1197 4AC 0000A620 SetThreadStackGuarantee
@@ -14874,11 +15113,13 @@
$ReadelfCmd .= " -WhlSsdA \"".$Lib_Path."\" 2>$TMP_DIR/null";
if($Debug)
{ # debug mode
+ # write to file
system($ReadelfCmd." >".$DebugPath);
- open(LIB, $DebugPath); # write to file
+ open(LIB, $DebugPath);
}
- else {
- open(LIB, $ReadelfCmd." |"); # write to pipe
+ else
+ { # write to pipe
+ open(LIB, $ReadelfCmd." |");
}
my $symtab=0; # indicates that we are processing 'symtab' section of 'readelf' output
while(<LIB>)
@@ -14906,14 +15147,6 @@
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" )
@@ -14985,7 +15218,7 @@
{
my $DepPath = find_lib_path($LibVersion, $DyLib);
if($DepPath and -f $DepPath) {
- getSymbols_Lib($LibVersion, $DepPath, 1, $GroupNames, "+Weak");
+ readSymbols_Lib($LibVersion, $DepPath, 1, $GroupNames, "+Weak");
}
}
pop(@RecurLib);
@@ -15057,42 +15290,6 @@
}
}
-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];
@@ -15255,80 +15452,6 @@
return (grep {$_ eq $Value} @{$Stack});
}
-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");
@@ -15459,7 +15582,8 @@
{ # ABI dump created with --binary option
$UsedDump{$LibVersion}{"BinOnly"} = 1;
}
- if($LibraryABI->{"Mode"} eq "Extended")
+ if(defined $LibraryABI->{"Mode"}
+ and $LibraryABI->{"Mode"} eq "Extended")
{ # --ext option
$ExtendedCheck = 1;
}
@@ -15588,9 +15712,9 @@
translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
translateSymbols(keys(%{$DepSymbols{$LibVersion}}), $LibVersion);
- foreach my $TypeDeclId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}}))
+ foreach my $TypeDeclId (sort keys(%{$TypeInfo{$LibVersion}}))
{
- foreach my $TypeId (sort {int($a)<=>int($b)} keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}}))
+ foreach my $TypeId (sort keys(%{$TypeInfo{$LibVersion}{$TypeDeclId}}))
{
if(defined $TypeInfo{$LibVersion}{$TypeDeclId}{$TypeId}{"BaseClass"})
{ # support for old ABI dumps < 2.0 (ACC 1.22)
@@ -15613,10 +15737,13 @@
$Class_SubClasses{$LibVersion}{$_}{$TypeId}=1;
}
}
- if($TInfo{"Type"} eq "Typedef")
+ if($TInfo{"Type"} eq "Typedef" and defined $TInfo{"BaseType"})
{
- my ($BTDid, $BTid) = ($TInfo{"BaseType"}{"TDid"}, $TInfo{"BaseType"}{"Tid"});
- $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}} = $TypeInfo{$LibVersion}{$BTDid}{$BTid}{"Name"};
+ if(my ($BTDid, $BTid) = ($TInfo{"BaseType"}{"TDid"}, $TInfo{"BaseType"}{"Tid"}))
+ {
+ $BTDid = "" if(not defined $BTDid);
+ $Typedef_BaseName{$LibVersion}{$TInfo{"Name"}} = $TypeInfo{$LibVersion}{$BTDid}{$BTid}{"Name"};
+ }
}
if(not $TName_Tid{$LibVersion}{$TInfo{"Name"}})
{ # classes: class (id1), typedef (artificial, id2 > id1)
@@ -16452,7 +16579,7 @@
(%TypeInfo, %SymbolInfo, %Library_Symbol,
%DepSymbols, %SymVer, %Tid_TDid, %SkipTypes,
%SkipSymbols, %NestedNameSpaces, %ClassMethods,
- %AllocableClass, %ClassToId, %CompleteSignature,
+ %AllocableClass, %ClassNames, %CompleteSignature,
%SkipNameSpaces, %Symbol_Library) = ();
($Content_Counter, $ContentID) = (0, 0);
# Print Report
@@ -16570,7 +16697,7 @@
# without VS Environment
check_win32_env();
}
- getSymbols($LibVersion);
+ readSymbols($LibVersion);
translateSymbols(keys(%{$Symbol_Library{$LibVersion}}), $LibVersion);
translateSymbols(keys(%{$DepSymbols{$LibVersion}}), $LibVersion);
}
@@ -17391,7 +17518,39 @@
}
prepareSymbols(1);
prepareSymbols(2);
+
%SymbolInfo = ();
+
+ # Virtual Tables
+ registerVTable(1);
+ registerVTable(2);
+
+ if(not checkDumpVersion(1, "1.22")
+ and checkDumpVersion(2, "1.22"))
+ { # 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);
+
+ # Other
+ addParamNames(1);
+ addParamNames(2);
+
+ detectChangedTypedefs();
}
sub compareAPIs($)
@@ -17771,7 +17930,7 @@
if(not -f $AppPath) {
exitStatus("Access_Error", "can't access file \'$AppPath\'");
}
- foreach my $Interface (getSymbols_App($AppPath)) {
+ foreach my $Interface (readSymbols_App($AppPath)) {
$SymbolsList_App{$Interface} = 1;
}
}