aboutsummaryrefslogtreecommitdiff
path: root/modules/Internals
diff options
context:
space:
mode:
authorAndrey Ponomarenko <aponomarenko@rosalab.ru>2012-07-19 18:57:20 +0400
committerAndrey Ponomarenko <aponomarenko@rosalab.ru>2012-07-19 18:57:20 +0400
commitf48ec93de57523ec5eef23a60d3b50c71c106983 (patch)
tree52d123e31e0d37fe479f8819cb0cd7e72d272732 /modules/Internals
parent01117f17f0064f91d93bfd2dafe8fcd36e636f33 (diff)
downloadabi-compliance-checker-f48ec93de57523ec5eef23a60d3b50c71c106983.tar.gz
ABI Compliance Checker 1.98.3
Diffstat (limited to 'modules/Internals')
-rw-r--r--modules/Internals/CallConv.pm1219
-rw-r--r--modules/Internals/RegTests.pm168
-rw-r--r--modules/Internals/XmlDump.pm6
3 files changed, 1369 insertions, 24 deletions
diff --git a/modules/Internals/CallConv.pm b/modules/Internals/CallConv.pm
new file mode 100644
index 0000000..6a65d1b
--- /dev/null
+++ b/modules/Internals/CallConv.pm
@@ -0,0 +1,1219 @@
+###########################################################################
+# Module for ACC tool to create a model of calling conventions
+#
+# 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 and Mac OS X
+# x86 - System V ABI Intel386 Architecture Processor Supplement
+# x86_64 - System V ABI AMD64 Architecture Processor Supplement
+#
+# MS Windows
+# x86 - MSDN Argument Passing and Naming Conventions
+# x86_64 - MSDN x64 Software Conventions
+#
+# 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 strict;
+
+my $BYTE = 8;
+
+my %UsedReg = ();
+my %UsedStack = ();
+
+sub classifyType($$$$$)
+{
+ my ($Tid, $TInfo, $Arch, $System, $Word) = @_;
+ my %Type = get_PureType($Tid, $TInfo);
+ my %Classes = ();
+ if($Type{"Name"} eq "void")
+ {
+ $Classes{0}{"Class"} = "VOID";
+ return %Classes;
+ }
+ if($System=~/\A(linux|macos|freebsd)\Z/)
+ { # GCC
+ if($Arch eq "x86")
+ {
+ if(isFloat($Type{"Name"})) {
+ $Classes{0}{"Class"} = "FLOAT";
+ }
+ elsif($Type{"Type"}=~/Intrinsic|Enum|Pointer|Ptr/) {
+ $Classes{0}{"Class"} = "INTEGRAL";
+ }
+ else { # Struct, Class, Union
+ $Classes{0}{"Class"} = "MEMORY";
+ }
+ }
+ elsif($Arch eq "x86_64")
+ {
+ if($Type{"Type"}=~/Enum|Pointer|Ptr/
+ or isScalar($Type{"Name"})
+ or $Type{"Name"}=~/\A(_Bool|bool)\Z/) {
+ $Classes{0}{"Class"} = "INTEGER";
+ }
+ elsif($Type{"Name"} eq "__int128"
+ or $Type{"Name"} eq "unsigned __int128")
+ {
+ $Classes{0}{"Class"} = "INTEGER";
+ $Classes{1}{"Class"} = "INTEGER";
+ }
+ elsif($Type{"Name"}=~/\A(float|double|_Decimal32|_Decimal64|__m64)\Z/) {
+ $Classes{0}{"Class"} = "SSE";
+ }
+ elsif($Type{"Name"}=~/\A(__float128|_Decimal128|__m128)\Z/)
+ {
+ $Classes{0}{"Class"} = "SSE";
+ $Classes{8}{"Class"} = "SSEUP";
+ }
+ elsif($Type{"Name"} eq "__m256")
+ {
+ $Classes{0}{"Class"} = "SSE";
+ $Classes{24}{"Class"} = "SSEUP";
+ }
+ elsif($Type{"Name"} eq "long double")
+ {
+ $Classes{0}{"Class"} = "X87";
+ $Classes{8}{"Class"} = "X87UP";
+ }
+ elsif($Type{"Name"}=~/\Acomplex (float|double)\Z/) {
+ $Classes{0}{"Class"} = "MEMORY";
+ }
+ elsif($Type{"Name"} eq "complex long double") {
+ $Classes{0}{"Class"} = "COMPLEX_X87";
+ }
+ elsif($Type{"Type"}=~/Struct|Class|Union|Array/)
+ {
+ if($Type{"Size"}>4*8) {
+ $Classes{0}{"Class"} = "MEMORY";
+ }
+ else {
+ %Classes = classifyAggregate($Tid, $TInfo, $Arch, $System, $Word);
+ }
+ }
+ else {
+ $Classes{0}{"Class"} = "MEMORY";
+ }
+ }
+ elsif($Arch eq "arm")
+ {
+ }
+ }
+ elsif($System eq "windows")
+ { # MS C++ Compiler
+ if($Arch eq "x86")
+ {
+ if(isFloat($Type{"Name"})) {
+ $Classes{0}{"Class"} = "FLOAT";
+ }
+ elsif($Type{"Type"}=~/Intrinsic|Enum|Pointer|Ptr/) {
+ $Classes{0}{"Class"} = "INTEGRAL";
+ }
+ elsif($Type{"Type"}=~/\A(Struct|Union)\Z/ and $Type{"Size"}<=8) {
+ $Classes{0}{"Class"} = "POD";
+ }
+ else { # Struct, Class, Union
+ $Classes{0}{"Class"} = "MEMORY";
+ }
+ }
+ elsif($Arch eq "x86_64")
+ {
+ if($Type{"Name"}=~/\A(float|double|long double)\Z/) {
+ $Classes{0}{"Class"} = "FLOAT";
+ }
+ elsif($Type{"Name"}=~/\A__m128(|i|d)\Z/) {
+ $Classes{0}{"Class"} = "M128";
+ }
+ elsif(isScalar($Type{"Name"})
+ or $Type{"Type"}=~/Enum|Pointer|Ptr/
+ or $Type{"Name"}=~/\A(_Bool|bool)\Z/
+ or ($Type{"Type"}=~/\A(Struct|Union)\Z/ and $Type{"Size"}<=8)
+ or $Type{"Name"} eq "__m64") {
+ $Classes{0}{"Class"} = "INTEGRAL";
+ }
+ else {
+ $Classes{0}{"Class"} = "MEMORY";
+ }
+ }
+ }
+ return %Classes;
+}
+
+sub classifyAggregate($$$$$)
+{
+ my ($Tid, $TInfo, $Arch, $System, $Word) = @_;
+ my %Type = get_PureType($Tid, $TInfo);
+ my %Group = ();
+ my $GroupID = 0;
+ my %Classes = ();
+ my %Offsets = ();
+ if($Type{"Type"} eq "Array")
+ {
+ my %Base = get_OneStep_BaseType($Tid, $TInfo);
+ my %BaseType = get_PureType($Base{"Tid"}, $TInfo);
+ my $Pos = 0;
+ my $Max = 0;
+ if(my $BSize = $BaseType{"Size"}) {
+ $Max = ($Type{"Size"}/$BSize) - 1;
+ }
+ foreach my $Pos (0 .. $Max)
+ {
+ $Type{"Memb"}{$Pos}{"algn"} = getTypeAlgn($BaseType{"Tid"}, $TInfo);
+ $Type{"Memb"}{$Pos}{"type"} = $BaseType{"Tid"};
+ $Type{"Memb"}{$Pos}{"name"} = "[$Pos]";
+ }
+ }
+ if($Type{"Type"} eq "Union")
+ {
+ foreach my $Pos (keys(%{$Type{"Memb"}}))
+ {
+ $Offsets{$Pos} = $Pos;
+ $Group{0}{$Pos} = 1;
+ }
+ }
+ else
+ { # Struct, Class
+ foreach my $Pos (keys(%{$Type{"Memb"}}))
+ {
+ my $Offset = getOffset($Pos, \%Type, $TInfo, $Word)/$BYTE;
+ $Offsets{$Pos} = $Offset;
+ my $GroupOffset = int($Offset/$Word)*$Word;
+ $Group{$GroupOffset}{$Pos} = 1;
+ }
+ }
+ foreach my $GroupOffset (sort {int($a)<=>int($b)} (keys(%Group)))
+ {
+ my %GroupClasses = ();
+ foreach my $Pos (sort {int($a)<=>int($b)} (keys(%{$Group{$GroupOffset}})))
+ { # split the field into the classes
+ my $MTid = $Type{"Memb"}{$Pos}{"type"};
+ my $MName = $Type{"Memb"}{$Pos}{"name"};
+ my %SubClasses = classifyType($MTid, $TInfo, $Arch, $System, $Word);
+ foreach my $Offset (sort {int($a)<=>int($b)} keys(%SubClasses))
+ {
+ if(defined $SubClasses{$Offset}{"Elems"})
+ {
+ foreach (keys(%{$SubClasses{$Offset}{"Elems"}})) {
+ $SubClasses{$Offset}{"Elems"}{$_} = joinFields($MName, $SubClasses{$Offset}{"Elems"}{$_});
+ }
+ }
+ else {
+ $SubClasses{$Offset}{"Elems"}{0} = $MName;
+ }
+ }
+
+ # add to the group
+ foreach my $Offset (sort {int($a)<=>int($b)} keys(%SubClasses)) {
+ $GroupClasses{$Offsets{$Pos}+$Offset} = $SubClasses{$Offset};
+ }
+ }
+
+ # merge classes in the group
+ my %MergeGroup = ();
+
+ foreach my $Offset (sort {int($a)<=>int($b)} keys(%GroupClasses)) {
+ $MergeGroup{int($Offset/$Word)}{$Offset} = $GroupClasses{$Offset};
+ }
+
+ foreach my $Offset (sort {int($a)<=>int($b)} keys(%MergeGroup)) {
+ while(postMerger($Arch, $System, $MergeGroup{$Offset})) { };
+ }
+
+ %GroupClasses = ();
+ foreach my $M_Offset (sort {int($a)<=>int($b)} keys(%MergeGroup))
+ {
+ foreach my $Offset (sort {int($a)<=>int($b)} keys(%{$MergeGroup{$M_Offset}}))
+ {
+ $GroupClasses{$Offset} = $MergeGroup{$M_Offset}{$Offset};
+ }
+ }
+
+ # add to the result list of classes
+ foreach my $Offset (sort {int($a)<=>int($b)} keys(%GroupClasses))
+ {
+ if($Type{"Type"} eq "Union")
+ {
+ foreach my $P (keys(%{$GroupClasses{$Offset}{"Elems"}}))
+ {
+ if($P!=0) {
+ delete($GroupClasses{$Offset}{"Elems"}{$P});
+ }
+ }
+ }
+ $Classes{$Offset} = $GroupClasses{$Offset};
+ }
+ }
+
+ return %Classes;
+}
+
+sub postMerger($$$)
+{
+ my ($Arch, $System, $PreClasses) = @_;
+ my @Offsets = sort {int($a)<=>int($b)} keys(%{$PreClasses});
+ if($#Offsets==0) {
+ return 0;
+ }
+ my %PostClasses = ();
+ my $Num = 0;
+ my $Merged = 0;
+ while($Num<=$#Offsets-1)
+ {
+ my $Offset1 = $Offsets[$Num];
+ my $Offset2 = $Offsets[$Num+1];
+ my $Class1 = $PreClasses->{$Offset1}{"Class"};
+ my $Class2 = $PreClasses->{$Offset2}{"Class"};
+ my $ResClass = "";
+ if($System=~/\A(linux|macos|freebsd)\Z/)
+ { # GCC
+ if($Arch eq "x86_64")
+ {
+ if($Class1 eq $Class2) {
+ $ResClass = $Class1;
+ }
+ elsif($Class1 eq "MEMORY"
+ or $Class2 eq "MEMORY") {
+ $ResClass = "MEMORY";
+ }
+ elsif($Class1 eq "INTEGER"
+ or $Class2 eq "INTEGER") {
+ $ResClass = "INTEGER";
+ }
+ elsif($Class1=~/X87/
+ or $Class2=~/X87/) {
+ $ResClass = "MEMORY";
+ }
+ else {
+ $ResClass = "SSE";
+ }
+ }
+ }
+ if($ResClass)
+ { # combine
+ $PostClasses{$Offset1}{"Class"} = $ResClass;
+ foreach (keys(%{$PreClasses->{$Offset1}{"Elems"}})) {
+ $PostClasses{$Offset1}{"Elems"}{$Offset1+$_} = $PreClasses->{$Offset1}{"Elems"}{$_};
+ }
+ foreach (keys(%{$PreClasses->{$Offset2}{"Elems"}})) {
+ $PostClasses{$Offset1}{"Elems"}{$Offset2+$_} = $PreClasses->{$Offset2}{"Elems"}{$_};
+ }
+ $Merged = 1;
+ }
+ else
+ { # save unchanged
+ $PostClasses{$Offset1} = $PreClasses->{$Offset1};
+ $PostClasses{$Offset2} = $PreClasses->{$Offset2};
+ }
+ $Num += 2;
+ }
+ if($Num==$#Offsets) {
+ $PostClasses{$Offsets[$Num]} = $PreClasses->{$Offsets[$Num]};
+ }
+ %{$PreClasses} = %PostClasses;
+ return $Merged;
+}
+
+sub callingConvention_R_Model($$$$$$) {
+ return callingConvention_R_I_Model(@_, 1);
+}
+
+sub joinFields($$)
+{
+ my ($F1, $F2) = @_;
+ if(substr($F2, 0, 1) eq "[")
+ { # array elements
+ return $F1.$F2;
+ }
+ else { # fields
+ return $F1.".".$F2;
+ }
+}
+
+sub callingConvention_R_I_Model($$$$$$)
+{
+ my ($SInfo, $TInfo, $Arch, $System, $Word, $Target) = @_;
+ my %Conv = ();
+ my $RTid = $SInfo->{"Return"};
+ my %Type = get_PureType($RTid, $TInfo);
+
+ if($Target) {
+ %UsedReg = ();
+ }
+
+ my %UsedReg_Copy = %UsedReg;
+
+ my %Classes = classifyType($RTid, $TInfo, $Arch, $System, $Word);
+
+ foreach my $Offset (sort {int($a)<=>int($b)} keys(%Classes))
+ {
+ my $Elems = undef;
+ if(defined $Classes{$Offset}{"Elems"})
+ {
+ foreach (keys(%{$Classes{$Offset}{"Elems"}})) {
+ $Classes{$Offset}{"Elems"}{$_} = joinFields(".result", $Classes{$Offset}{"Elems"}{$_});
+ }
+ $Elems = $Classes{$Offset}{"Elems"};
+ }
+ else {
+ $Elems = { 0 => ".result" };
+ }
+
+ my $CName = $Classes{$Offset}{"Class"};
+
+ if($CName eq "VOID") {
+ next;
+ }
+
+ if($System=~/\A(linux|macos|freebsd)\Z/)
+ { # GCC
+ if($Arch eq "x86")
+ {
+ if($CName eq "FLOAT")
+ { # x87 register
+ useRegister("st0", "f", $Elems, $SInfo);
+ }
+ elsif($CName eq "INTEGRAL")
+ {
+ useRegister("eax", "f", $Elems, $SInfo);
+ }
+ elsif($CName eq "MEMORY") {
+ pushStack_R($SInfo, $Word);
+ }
+ }
+ elsif($Arch eq "x86_64")
+ {
+ my @INT = ("rax", "rdx");
+ my @SSE = ("xmm0", "xmm1");
+ if($CName eq "INTEGER")
+ {
+ if(my $R = getLastAvailable($SInfo, "f", @INT))
+ {
+ useRegister($R, "f", $Elems, $SInfo);
+ }
+ else
+ { # revert registers
+ # pass as MEMORY
+ %UsedReg = %UsedReg_Copy;
+ useHidden($SInfo, $Arch, $System, $Word);
+ $Conv{"Hidden"} = 1;
+ last;
+ }
+ }
+ elsif($CName eq "SSE")
+ {
+ if(my $R = getLastAvailable($SInfo, "8l", @SSE))
+ {
+ useRegister($R, "8l", $Elems, $SInfo);
+ }
+ else
+ {
+ %UsedReg = %UsedReg_Copy;
+ useHidden($SInfo, $Arch, $System, $Word);
+ $Conv{"Hidden"} = 1;
+ last;
+ }
+ }
+ elsif($CName eq "SSEUP")
+ {
+ if(my $R = getLastUsed($SInfo, "xmm0", "xmm1"))
+ {
+ useRegister($R, "8h", $Elems, $SInfo);
+ }
+ else
+ {
+ %UsedReg = %UsedReg_Copy;
+ useHidden($SInfo, $Arch, $System, $Word);
+ $Conv{"Hidden"} = 1;
+ last;
+ }
+ }
+ elsif($CName eq "X87")
+ {
+ useRegister("st0", "8l", $Elems, $SInfo);
+ }
+ elsif($CName eq "X87UP")
+ {
+ useRegister("st0", "8h", $Elems, $SInfo);
+ }
+ elsif($CName eq "COMPLEX_X87")
+ {
+ useRegister("st0", "f", $Elems, $SInfo);
+ useRegister("st1", "f", $Elems, $SInfo);
+ }
+ elsif($CName eq "MEMORY")
+ {
+ useHidden($SInfo, $Arch, $System, $Word);
+ $Conv{"Hidden"} = 1;
+ last;
+ }
+ }
+ elsif($Arch eq "arm")
+ { # TODO
+ }
+ }
+ elsif($System eq "windows")
+ { # MS C++ Compiler
+ if($Arch eq "x86")
+ {
+ if($CName eq "FLOAT")
+ {
+ useRegister("fp0", "f", $Elems, $SInfo);
+ }
+ elsif($CName eq "INTEGRAL")
+ {
+ useRegister("eax", "f", $Elems, $SInfo);
+ }
+ elsif($CName eq "POD")
+ {
+ useRegister("eax", "f", $Elems, $SInfo);
+ useRegister("edx", "f", $Elems, $SInfo);
+ }
+ elsif($CName eq "MEMORY" or $CName eq "M128")
+ {
+ useHidden($SInfo, $Arch, $System, $Word);
+ $Conv{"Hidden"} = 1;
+ }
+ }
+ elsif($Arch eq "x86_64")
+ {
+ if($CName eq "FLOAT" or $CName eq "M128")
+ {
+ useRegister("xmm0", "f", $Elems, $SInfo);
+ }
+ elsif($CName eq "INTEGRAL")
+ {
+ useRegister("eax", "f", $Elems, $SInfo);
+ }
+ elsif($CName eq "MEMORY")
+ {
+ useHidden($SInfo, $Arch, $System, $Word);
+ $Conv{"Hidden"} = 1;
+ }
+ }
+ }
+ }
+
+
+ if(my %Regs = usedBy(".result", $SInfo))
+ {
+ $Conv{"Method"} = "reg";
+ $Conv{"Registers"} = join(", ", sort(keys(%Regs)));
+ }
+ elsif(my %Regs = usedBy(".result_ptr", $SInfo))
+ {
+ $Conv{"Method"} = "reg";
+ $Conv{"Registers"} = join(", ", sort(keys(%Regs)));
+ }
+
+ if(not $Conv{"Method"})
+ { # unknown
+ if($Type{"Name"} ne "void")
+ {
+ $Conv{"Method"} = "stack";
+ $Conv{"Hidden"} = 1;
+ }
+ }
+
+ return %Conv;
+}
+
+sub usedBy($$)
+{
+ my ($Name, $SInfo) = @_;
+ my %Regs = ();
+ foreach my $Reg (sort keys(%{$UsedReg{$SInfo}}))
+ {
+ foreach my $Size (sort keys(%{$UsedReg{$SInfo}{$Reg}}))
+ {
+ foreach my $Offset (sort keys(%{$UsedReg{$SInfo}{$Reg}{$Size}}))
+ {
+ if($UsedReg{$SInfo}{$Reg}{$Size}{$Offset}=~/\A\Q$Name\E(\.|\Z)/) {
+ $Regs{$Reg} = 1;
+ }
+ }
+ }
+ }
+ return %Regs;
+}
+
+sub useHidden($$$$)
+{
+ my ($SInfo, $Arch, $System, $Word) = @_;
+ if($System=~/\A(linux|macos|freebsd)\Z/)
+ { # GCC
+ if($Arch eq "x86") {
+ pushStack_R($SInfo, $Word);
+ }
+ elsif($Arch eq "x86_64")
+ {
+ my $Elems = { 0 => ".result_ptr" };
+ useRegister("rdi", "f", $Elems, $SInfo);
+ }
+ }
+ elsif($System eq "windows")
+ { # MS C++ Compiler
+ if($Arch eq "x86") {
+ pushStack_R($SInfo, $Word);
+ }
+ elsif($Arch eq "x86_64")
+ {
+ my $Elems = { 0 => ".result_ptr" };
+ useRegister("rcx", "f", $Elems, $SInfo);
+ }
+ }
+}
+
+sub pushStack_P($$$$)
+{
+ my ($SInfo, $Pos, $TInfo, $StackAlgn) = @_;
+ my $PTid = $SInfo->{"Param"}{$Pos}{"type"};
+ my $PName = $SInfo->{"Param"}{$Pos}{"name"};
+ my $Alignment = $SInfo->{"Param"}{$Pos}{"algn"};
+ if($Alignment<$StackAlgn) {
+ $Alignment = $StackAlgn;
+ }
+ return pushStack($SInfo, $Alignment, $TInfo->{$PTid}{"Size"}, { 0 => $PName });
+}
+
+sub pushStack_R($$)
+{
+ my ($SInfo, $Word) = @_;
+ return pushStack($SInfo, $Word, $Word, { 0 => ".result_ptr" });
+}
+
+sub pushStack_C($$$)
+{
+ my ($SInfo, $Class, $TInfo) = @_;
+ return pushStack($SInfo, $Class->{"Algn"}, $Class->{"Size"}, $Class->{"Elems"});
+}
+
+sub pushStack($$$$)
+{
+ my ($SInfo, $Algn, $Size, $Elem) = @_;
+ my $Offset = 0;
+ if(my @Offsets = sort {int($a)<=>int($b)} keys(%{$UsedStack{$SInfo}}))
+ {
+ $Offset = $Offsets[$#Offsets];
+ $Offset += $UsedStack{$SInfo}{$Offset}{"Size"};
+ $Offset += getPadding($Offset, $Algn);
+ }
+ my %Info = (
+ "Size" => $Size,
+ "Elem" => $Elem
+ );
+ $UsedStack{$SInfo}{$Offset} = \%Info;
+ return $Offset;
+}
+
+sub useRegister($$$$)
+{
+ my ($R, $Offset, $Elems, $SInfo) = @_;
+ if(defined $UsedReg{$SInfo}{$R})
+ {
+ if(defined $UsedReg{$SInfo}{$R}{$Offset})
+ { # busy
+ return 0;
+ }
+ }
+ $UsedReg{$SInfo}{$R}{$Offset}=$Elems;
+ return $R;
+}
+
+sub getLastAvailable(@)
+{
+ my $SInfo = shift(@_);
+ my $Offset = shift(@_);
+ my $Pos = 0;
+ foreach (@_)
+ {
+ if(not defined $UsedReg{$SInfo}{$_}) {
+ return $_;
+ }
+ elsif(not defined $UsedReg{$SInfo}{$_}{$Offset}) {
+ return $_;
+ }
+ }
+ return undef;
+}
+
+sub getLastUsed(@)
+{
+ my $SInfo = shift(@_);
+ my $Pos = 0;
+ foreach (@_)
+ {
+ if(not defined $UsedReg{$SInfo}{$_})
+ {
+ if($Pos>0) {
+ return @_[$Pos-1];
+ }
+ else {
+ return @_[0];
+ }
+ }
+ $Pos+=1;
+ }
+ return undef;
+}
+
+sub callingConvention_P_Model($$$$$$) {
+ return callingConvention_P_I_Model(@_, 1);
+}
+
+sub callingConvention_P_I_Model($$$$$$$)
+{ # calling conventions for different compilers and operating systems
+ my ($SInfo, $Pos, $TInfo, $Arch, $System, $Word, $Target) = @_;
+ my %Conv = ();
+ my $ParamTypeId = $SInfo->{"Param"}{$Pos}{"type"};
+ my $PName = $SInfo->{"Param"}{$Pos}{"name"};
+ my %Type = get_PureType($ParamTypeId, $TInfo);
+
+ if($Target)
+ {
+ %UsedReg = ();
+
+ # distribute return value
+ if(my $RTid = $SInfo->{"Return"}) {
+ callingConvention_R_I_Model($SInfo, $TInfo, $Arch, $System, $Word, 0);
+ }
+ # distribute other parameters
+ if($Pos>0)
+ {
+ my %PConv = ();
+ my $PPos = 0;
+ while($PConv{"Next"} ne $Pos)
+ {
+ %PConv = callingConvention_P_I_Model($SInfo, $PPos++, $TInfo, $Arch, $System, $Word, 0);
+ if(not $PConv{"Next"}) {
+ last;
+ }
+ }
+ }
+ }
+
+ my %UsedReg_Copy = %UsedReg;
+
+ my %Classes = classifyType($ParamTypeId, $TInfo, $Arch, $System, $Word);
+
+ my $Error = 0;
+ foreach my $Offset (sort {int($a)<=>int($b)} keys(%Classes))
+ {
+ my $Elems = undef;
+ if(defined $Classes{$Offset}{"Elems"})
+ {
+ foreach (keys(%{$Classes{$Offset}{"Elems"}})) {
+ $Classes{$Offset}{"Elems"}{$_} = joinFields($PName, $Classes{$Offset}{"Elems"}{$_});
+ }
+ $Elems = $Classes{$Offset}{"Elems"};
+ }
+ else {
+ $Elems = { 0 => $PName };
+ }
+
+ my $CName = $Classes{$Offset}{"Class"};
+
+ if($CName eq "VOID") {
+ next;
+ }
+
+ if($System=~/\A(linux|macos|freebsd)\Z/)
+ { # GCC
+ if($Arch eq "x86")
+ {
+ pushStack_P($SInfo, $Pos, $TInfo, $Word);
+ last;
+ }
+ elsif($Arch eq "x86_64")
+ {
+ my @INT = ("rdi", "rsi", "rdx", "rcx", "r8", "r9");
+ my @SSE = ("xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7");
+
+ if($CName eq "INTEGER")
+ {
+ if(my $R = getLastAvailable($SInfo, "f", @INT)) {
+ useRegister($R, "f", $Elems, $SInfo);
+ }
+ else
+ { # revert registers and
+ # push the argument on the stack
+ %UsedReg = %UsedReg_Copy;
+ pushStack_P($SInfo, $Pos, $TInfo, $Word);
+ last;
+ }
+ }
+ elsif($CName eq "SSE")
+ {
+ if(my $R = getLastAvailable($SInfo, "8l", @SSE)) {
+ useRegister($R, "8l", $Elems, $SInfo);
+ }
+ else
+ {
+ %UsedReg = %UsedReg_Copy;
+ pushStack_P($SInfo, $Pos, $TInfo, $Word);
+ last;
+ }
+ }
+ elsif($CName eq "SSEUP")
+ {
+ if(my $R = getLastUsed($SInfo, @SSE)) {
+ useRegister($R, "8h", $Elems, $SInfo);
+ }
+ else
+ {
+ %UsedReg = %UsedReg_Copy;
+ pushStack_P($SInfo, $Pos, $TInfo, $Word);
+ last;
+ }
+ }
+ elsif($CName=~/X87|MEMORY/)
+ { # MEMORY, X87, X87UP, COMPLEX_X87
+ pushStack_P($SInfo, $Pos, $TInfo, $Word);
+ last;
+ }
+ else
+ {
+ pushStack_P($SInfo, $Pos, $TInfo, $Word);
+ last;
+ }
+ }
+ elsif($Arch eq "arm")
+ { # Procedure Call Standard for the ARM Architecture
+ # TODO
+ pushStack_P($SInfo, $Pos, $TInfo, $Word);
+ last;
+ }
+ else
+ { # TODO
+ pushStack_P($SInfo, $Pos, $TInfo, $Word);
+ last;
+ }
+ }
+ elsif($System eq "windows")
+ { # MS C++ Compiler
+ if($Arch eq "x86")
+ {
+ pushStack_P($SInfo, $Pos, $TInfo, $Word);
+ last;
+ }
+ elsif($Arch eq "x86_64")
+ {
+ if($Pos<=3)
+ {
+ if($CName eq "FLOAT")
+ {
+ useRegister("xmm".$Pos, "8l", $Elems, $SInfo);
+ }
+ elsif($CName eq "INTEGRAL")
+ {
+ if($Pos==0) {
+ useRegister("rcx", "f", $Elems, $SInfo);
+ }
+ elsif($Pos==1) {
+ useRegister("rdx", "f", $Elems, $SInfo);
+ }
+ elsif($Pos==2) {
+ useRegister("r8", "f", $Elems, $SInfo);
+ }
+ elsif($Pos==3) {
+ useRegister("r9", "f", $Elems, $SInfo);
+ }
+ else
+ {
+ pushStack_P($SInfo, $Pos, $TInfo, $Word);
+ last;
+ }
+ }
+ else
+ {
+ pushStack_P($SInfo, $Pos, $TInfo, $Word);
+ last;
+ }
+ }
+ else
+ {
+ pushStack_P($SInfo, $Pos, $TInfo, $Word);
+ last;
+ }
+ }
+ }
+ else
+ { # TODO
+ pushStack_P($SInfo, $Pos, $TInfo, $Word);
+ last;
+ }
+ }
+
+ if(my %Regs = usedBy($PName, $SInfo))
+ {
+ $Conv{"Method"} = "reg";
+ $Conv{"Registers"} = join(", ", sort(keys(%Regs)));
+ }
+ else
+ {
+ if($Type{"Name"} ne "void") {
+ $Conv{"Method"} = "stack";
+ }
+ }
+
+ if(defined $SInfo->{"Param"}{$Pos+1})
+ { # TODO
+ $Conv{"Next"} = $Pos+1;
+ }
+
+ return %Conv;
+}
+
+sub getTypeAlgn($$)
+{
+ my ($Tid, $TInfo) = @_;
+ if(defined $TInfo->{$Tid}{"Algn"}) {
+ return $TInfo->{$Tid}{"Algn"};
+ }
+ else
+ { # support for old ABI dumps
+ if($TInfo->{$Tid}{"Type"}=~/Struct|Class|Union/)
+ {
+ if(defined $TInfo->{$Tid}{"Memb"})
+ {
+ my $Max = 0;
+ foreach my $Pos (keys(%{$TInfo->{$Tid}{"Memb"}}))
+ {
+ my $Algn = $TInfo->{$Tid}{"Memb"}{$Pos}{"algn"};
+ if($Algn>$Algn) {
+ $Max = $Algn;
+ }
+ }
+ return $Max;
+ }
+ return 0;
+ }
+ elsif($TInfo->{$Tid}{"Type"} eq "Array")
+ {
+ my %Base = get_OneStep_BaseType($Tid, $TInfo);
+ return getTypeAlgn($Base{"Tid"}, $TInfo);
+ }
+ elsif($TInfo->{$Tid}{"Type"}=~/Intrinsic|Enum|Pointer|Ptr/)
+ { # model
+ return $TInfo->{$Tid}{"Size"};
+ }
+ else
+ {
+ my %PureType = get_PureType($Tid, $TInfo);
+ return getTypeAlgn($PureType{"Tid"}, $TInfo);
+ }
+ }
+}
+
+sub getAlignment($$$$)
+{
+ my ($Pos, $TypePtr, $TInfo, $Word) = @_;
+ my $Tid = $TypePtr->{"Memb"}{$Pos}{"type"};
+ my %Type = get_PureType($Tid, $TInfo);
+ my $Computed = $TypePtr->{"Memb"}{$Pos}{"algn"};
+ my $Alignment = 0;
+
+ if(my $BSize = $TypePtr->{"Memb"}{$Pos}{"bitfield"})
+ { # bitfields
+ if($Computed)
+ { # real in bits
+ $Alignment = $Computed;
+ }
+ return ($Alignment, $BSize);
+ }
+ else
+ { # other fields
+ if($Computed)
+ { # real in bytes
+ $Alignment = $Computed*$BYTE;
+ }
+ else
+ { # model
+ $Alignment = $Type{"Size"}*$BYTE;
+ }
+ return ($Alignment, $Type{"Size"}*$BYTE);
+ }
+}
+
+sub getOffset($$$$)
+{ # offset of the field including padding
+ my ($FieldPos, $TypePtr, $TInfo, $Word) = @_;
+ my $Offset = 0;
+
+ my $Buffer=0;
+
+ foreach my $Pos (0 .. keys(%{$TypePtr->{"Memb"}})-1)
+ {
+ my ($Alignment, $MSize) = getAlignment($Pos, $TypePtr, $TInfo, $Word);
+
+ if(not $Alignment)
+ { # support for old ABI dumps
+ if($MSize=~/\A(8|16|32|64)\Z/)
+ {
+ if($Buffer+$MSize<$Word*$BYTE)
+ {
+ $Alignment = 1;
+ $Buffer += $MSize;
+ }
+ else
+ {
+ $Alignment = $MSize;
+ $Buffer = 0;
+ }
+ }
+ else
+ {
+ $Alignment = 1;
+ $Buffer += $MSize;
+ }
+ }
+
+ # padding
+ $Offset += getPadding($Offset, $Alignment);
+ if($Pos==$FieldPos)
+ { # after the padding
+ # before the field
+ return $Offset;
+ }
+ $Offset += $MSize;
+ }
+ return $FieldPos;# if something is going wrong
+}
+
+sub getPadding($$)
+{
+ my ($Offset, $Alignment) = @_;
+ my $Padding = 0;
+ if($Offset % $Alignment!=0)
+ { # not aligned, add padding
+ $Padding = $Alignment - $Offset % $Alignment;
+ }
+ return $Padding;
+}
+
+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, $TInfo, $Word) = @_;
+ return 0 if($FieldPos==0);
+ delete($TypePtr->{"Memb"}{""});
+ 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, $TInfo, $Word);
+ 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 isScalar($) {
+ return ($_[0]=~/\A(unsigned |)(char|short|int|long|long long)\Z/);
+}
+
+sub isFloat($) {
+ return ($_[0]=~/\A(float|double|long double)\Z/);
+}
+
+sub callingConvention_R_Real($)
+{
+ my $SInfo = $_[0];
+ my %Conv = ();
+ my %Regs = ();
+ my $Hidden = 0;
+ foreach my $Reg (keys(%{$SInfo->{"Reg"}}))
+ {
+
+ foreach my $Elem (keys(%{$SInfo->{"Reg"}{$Reg}}))
+ {
+ if($Elem eq ".result_ptr")
+ {
+ $Hidden = 1;
+ $Regs{$Reg}=1;
+ }
+ elsif(index($Elem, ".result")==0) {
+ $Regs{$Reg}=1;
+ }
+ }
+ }
+ if(my @R = sort keys(%Regs))
+ {
+ $Conv{"Method"} = "reg";
+ $Conv{"Registers"} = join(", ", @R);
+ if($Hidden) {
+ $Conv{"Hidden"} = 1;
+ }
+ }
+ else
+ {
+ $Conv{"Method"} = "stack";
+ $Conv{"Hidden"} = 1;
+ }
+ return %Conv;
+}
+
+sub callingConvention_P_Real($$)
+{
+ my ($SInfo, $Pos) = @_;
+ my $PName = $SInfo->{"Param"}{$Pos}{"name"};
+ my %Conv = ();
+ my %Regs = ();
+ my $Hidden = 0;
+ foreach my $Reg (keys(%{$SInfo->{"Reg"}}))
+ {
+
+ foreach my $Elem (keys(%{$SInfo->{"Reg"}{$Reg}}))
+ {
+ if($Elem=~/\A$PName(\.|\Z)/) {
+ $Regs{$Reg}=1;
+ }
+ }
+ }
+ if(my @R = sort keys(%Regs))
+ {
+ $Conv{"Method"} = "reg";
+ $Conv{"Registers"} = join(", ", @R);
+ }
+ else {
+ $Conv{"Method"} = "stack";
+ }
+ return %Conv;
+}
+
+return 1; \ No newline at end of file
diff --git a/modules/Internals/RegTests.pm b/modules/Internals/RegTests.pm
index 48ef2e0..628b4c0 100644
--- a/modules/Internals/RegTests.pm
+++ b/modules/Internals/RegTests.pm
@@ -1,5 +1,5 @@
###########################################################################
-# Internal Regression Tests for ABI Compliance Checker
+# Module for ABI Compliance Checker with regression test suite
#
# Copyright (C) 2009-2010 The Linux Foundation
# Copyright (C) 2009-2011 Institute for System Programming, RAS
@@ -24,13 +24,15 @@
use strict;
my ($TestDump, $Debug, $Quiet, $ExtendedCheck, $LogMode, $ReportFormat,
-$DumpFormat, $LIB_EXT, $GCC_PATH, $Browse, $OpenReport, $SortDump);
+$DumpFormat, $LIB_EXT, $GCC_PATH, $Browse, $OpenReport, $SortDump,
+$CheckHeadersOnly, $CheckObjectsOnly);
my $OSgroup = get_OSgroup();
sub testTool($$$$$$$$$$$)
{
($TestDump, $Debug, $Quiet, $ExtendedCheck, $LogMode, $ReportFormat,
- $DumpFormat, $LIB_EXT, $GCC_PATH, $Browse, $OpenReport, $SortDump) = @_;
+ $DumpFormat, $LIB_EXT, $GCC_PATH, $Browse, $OpenReport, $SortDump,
+ $CheckHeadersOnly, $CheckObjectsOnly) = @_;
testC();
testCpp();
@@ -41,7 +43,7 @@ sub testCpp()
printMsg("INFO", "verifying detectable C++ library changes");
my ($HEADER1, $SOURCE1, $HEADER2, $SOURCE2) = ();
my $DECL_SPEC = ($OSgroup eq "windows")?"__declspec( dllexport )":"";
- my $EXTERN = ($OSgroup eq "windows")?"extern ":"";# add "extern" for CL compiler
+ my $EXTERN = ($OSgroup eq "windows")?"extern ":""; # add "extern" for CL compiler
# Begin namespace
$HEADER1 .= "namespace TestNS {\n";
@@ -247,7 +249,7 @@ sub testCpp()
int globalDataBecameConst = 10;";
$HEADER2 .= "
- $DECL_SPEC const int globalDataBecameConst = 15;";
+ $EXTERN $DECL_SPEC const int globalDataBecameConst = 15;";
# Global_Data_Became_Const
# Class Member
@@ -283,18 +285,18 @@ sub testCpp()
# Global_Data_Value_Changed
# Integer
$HEADER1 .= "
- $DECL_SPEC const int globalDataValue_Integer = 10;";
+ $EXTERN $DECL_SPEC const int globalDataValue_Integer = 10;";
$HEADER2 .= "
- $DECL_SPEC const int globalDataValue_Integer = 15;";
+ $EXTERN $DECL_SPEC const int globalDataValue_Integer = 15;";
# Global_Data_Value_Changed
# Character
$HEADER1 .= "
- $DECL_SPEC const char globalDataValue_Char = \'o\';";
+ $EXTERN $DECL_SPEC const char globalDataValue_Char = \'o\';";
$HEADER2 .= "
- $DECL_SPEC const char globalDataValue_Char = \'N\';";
+ $EXTERN $DECL_SPEC const char globalDataValue_Char = \'N\';";
# Parameter_Became_Restrict
$HEADER1 .= "
@@ -2659,7 +2661,108 @@ sub testC()
printMsg("INFO", "\nverifying detectable C library changes");
my ($HEADER1, $SOURCE1, $HEADER2, $SOURCE2) = ();
my $DECL_SPEC = ($OSgroup eq "windows")?"__declspec( dllexport )":"";
- my $EXTERN = ($OSgroup eq "windows")?"extern ":"";
+ my $EXTERN = ($OSgroup eq "windows")?"extern ":""; # add "extern" for CL compiler
+
+ # Parameter_Type_And_Register
+ $HEADER1 .= "
+ typedef struct {
+ int a[4];
+ } ARRAY;
+ $DECL_SPEC void callConv5 (ARRAY i, int j);";
+ $SOURCE1 .= "
+ void callConv5 (ARRAY i, int j) { }";
+
+ $HEADER2 .= "
+ typedef struct {
+ int a[4];
+ } ARRAY;
+ $DECL_SPEC void callConv5 (ARRAY i, double j);";
+ $SOURCE2 .= "
+ void callConv5 (ARRAY i, double j) { }";
+
+ # Parameter_Type_And_Register
+ $HEADER1 .= "
+ typedef union {
+ int a;
+ double b;
+ } UNION;
+ $DECL_SPEC void callConv4 (UNION i, int j);";
+ $SOURCE1 .= "
+ void callConv4 (UNION i, int j) { }";
+
+ $HEADER2 .= "
+ typedef union {
+ int a;
+ double b;
+ } UNION;
+ $DECL_SPEC void callConv4 (UNION i, double j);";
+ $SOURCE2 .= "
+ void callConv4 (UNION i, double j) { }";
+
+ # Parameter_Type_And_Register
+ $HEADER1 .= "
+ typedef struct {
+ long a:4;
+ long b:16;
+ } POD2;
+ $DECL_SPEC void callConv3 (POD2 i, int j);";
+ $SOURCE1 .= "
+ void callConv3 (POD2 i, int j) { }";
+
+ $HEADER2 .= "
+ typedef struct {
+ long a:4;
+ long b:16;
+ } POD2;
+ $DECL_SPEC void callConv3 (POD2 i, double j);";
+ $SOURCE2 .= "
+ void callConv3 (POD2 i, double j) { }";
+
+ # Parameter_Type_And_Register
+ $HEADER1 .= "
+ typedef struct {
+ short s:9;
+ int j:9;
+ char c;
+ short t:9;
+ short u:9;
+ char d;
+ } POD;
+ $DECL_SPEC void callConv2 (POD i, int j);";
+ $SOURCE1 .= "
+ void callConv2 (POD i, int j) { }";
+
+ $HEADER2 .= "
+ typedef struct {
+ short s:9;
+ int j:9;
+ char c;
+ short t:9;
+ short u:9;
+ char d;
+ } POD;
+ $DECL_SPEC void callConv2 (POD i, double j);";
+ $SOURCE2 .= "
+ void callConv2 (POD i, double j) { }";
+
+ # Parameter_Type_And_Register
+ $HEADER1 .= "
+ typedef struct {
+ int a, b;
+ double d;
+ } POD1;
+ $DECL_SPEC void callConv (int e, int f, POD1 s, int g, int h, long double ld, double m, double n, int i, int j, int k);";
+ $SOURCE1 .= "
+ void callConv(int e, int f, POD1 s, int g, int h, long double ld, double m, double n, int i, int j, int k) { }";
+
+ $HEADER2 .= "
+ typedef struct {
+ int a, b;
+ double d;
+ } POD1;
+ $DECL_SPEC void callConv (int e, int f, POD1 s, int g, int h, long double ld, double m, double n, int i, int j, double k);";
+ $SOURCE2 .= "
+ void callConv(int e, int f, POD1 s, int g, int h, long double ld, double m, double n, int i, int j, double k) { }";
# Parameter_Type (int to "int const")
$HEADER1 .= "
@@ -2914,22 +3017,22 @@ sub testC()
# Global_Data_Value_Changed
# Integer
$HEADER1 .= "
- $DECL_SPEC const int globalDataValue_Integer = 10;";
+ $EXTERN $DECL_SPEC const int globalDataValue_Integer = 10;";
$HEADER2 .= "
- $DECL_SPEC const int globalDataValue_Integer = 15;";
+ $EXTERN $DECL_SPEC const int globalDataValue_Integer = 15;";
# Global_Data_Value_Changed
# Character
$HEADER1 .= "
- $DECL_SPEC const char globalDataValue_Char = \'o\';";
+ $EXTERN $DECL_SPEC const char globalDataValue_Char = \'o\';";
$HEADER2 .= "
- $DECL_SPEC const char globalDataValue_Char = \'N\';";
+ $EXTERN $DECL_SPEC const char globalDataValue_Char = \'N\';";
# Global_Data_Became_Non_Const
$HEADER1 .= "
- $DECL_SPEC const int globalDataBecameNonConst = 10;";
+ $EXTERN $DECL_SPEC const int globalDataBecameNonConst = 10;";
$HEADER2 .= "
extern $DECL_SPEC int globalDataBecameNonConst;";
@@ -2940,7 +3043,7 @@ sub testC()
# Typedef
$HEADER1 .= "
typedef const int CONST_INT;
- $DECL_SPEC CONST_INT globalDataBecameNonConst_Typedef = 10;";
+ $EXTERN $DECL_SPEC CONST_INT globalDataBecameNonConst_Typedef = 10;";
$HEADER2 .= "
extern $DECL_SPEC int globalDataBecameNonConst_Typedef;";
@@ -2954,7 +3057,7 @@ sub testC()
int globalDataBecameConst = 10;";
$HEADER2 .= "
- $DECL_SPEC const int globalDataBecameConst = 15;";
+ $EXTERN $DECL_SPEC const int globalDataBecameConst = 15;";
# Global_Data_Became_Non_Const
$HEADER1 .= "
@@ -3438,12 +3541,12 @@ sub testC()
int parameterTypeAndSize(long long param, int other_param) { return other_param; }";
# Parameter_Type_And_Size (test calling conventions)
- $HEADER1 .= "\n
+ $HEADER1 .= "
$DECL_SPEC int parameterCallingConvention(int p1, int p2, int p3);";
$SOURCE1 .= "
int parameterCallingConvention(int p1, int p2, int p3) { return 0; }";
- $HEADER2 .= "\n
+ $HEADER2 .= "
$DECL_SPEC float parameterCallingConvention(char p1, int p2, int p3);";
$SOURCE2 .= "
float parameterCallingConvention(char p1, int p2, int p3) { return 7.0f; }";
@@ -3554,13 +3657,19 @@ sub testC()
# Return_Type ("struct" to "void*")
$HEADER1 .= "
- struct SomeStruct {int A;long B;};
+ struct SomeStruct {
+ int a;
+ double b, c, d;
+ };
$DECL_SPEC struct SomeStruct* returnTypeChangeToVoidPtr(int param);";
$SOURCE1 .= "
struct SomeStruct* returnTypeChangeToVoidPtr(int param) { return (struct SomeStruct*)0; }";
$HEADER2 .= "
- struct SomeStruct {int A;int B;};
+ struct SomeStruct {
+ int a;
+ double b, c, d;
+ };
$DECL_SPEC void* returnTypeChangeToVoidPtr(int param);";
$SOURCE2 .= "
void* returnTypeChangeToVoidPtr(int param) { return (void*)0; }";
@@ -3603,6 +3712,17 @@ sub testC()
$DECL_SPEC long returnTypeChangeFromVoidToLong(int param);";
$SOURCE2 .= "
long returnTypeChangeFromVoidToLong(int param) { return 0; }";
+
+ # Return_Type_From_Void_And_Stack_Layout (safe, "void" to "void*")
+ $HEADER1 .= "
+ $DECL_SPEC void returnTypeChangeFromVoidToVoidPtr(int param);";
+ $SOURCE1 .= "
+ void returnTypeChangeFromVoidToVoidPtr(int param) { return; }";
+
+ $HEADER2 .= "
+ $DECL_SPEC void* returnTypeChangeFromVoidToVoidPtr(int param);";
+ $SOURCE2 .= "
+ void* returnTypeChangeFromVoidToVoidPtr(int param) { return 0; }";
# Return_Type_From_Register_To_Stack ("int" to "struct")
$HEADER1 .= "
@@ -4269,6 +4389,12 @@ sub runTests($$$$$$$$)
{ # HTML is default format
@Cmd = (@Cmd, "-report-format", $ReportFormat);
}
+ if($CheckHeadersOnly) {
+ @Cmd = (@Cmd, "-headers-only");
+ }
+ if($CheckObjectsOnly) {
+ @Cmd = (@Cmd, "-objects-only");
+ }
if($Browse) {
@Cmd = (@Cmd, "-browse", $Browse);
}
diff --git a/modules/Internals/XmlDump.pm b/modules/Internals/XmlDump.pm
index 4fa84af..76b8247 100644
--- a/modules/Internals/XmlDump.pm
+++ b/modules/Internals/XmlDump.pm
@@ -79,7 +79,7 @@ sub createXmlDump($)
$ABI_DUMP .= openTag("data_type");
$ABI_DUMP .= addTag("id", $ID);
foreach my $Attr ("Name", "Type", "Size",
- "Header", "Line", "NameSpace", "Class", "Return")
+ "Header", "Line", "NameSpace", "Class", "Return", "Algn")
{
if(defined $TInfo{$Attr}) {
$ABI_DUMP .= addTag(lc($Attr), $TInfo{$Attr});
@@ -546,8 +546,8 @@ sub readXmlDump($)
$TInfo{"Spec"} = 1;
}
}
- foreach my $Attr ("Name", "Type", "Class",
- "Header", "Line", "NameSpace", "Return", "Size")
+ foreach my $Attr ("Name", "Type", "Size",
+ "Header", "Line", "NameSpace", "Class", "Return", "Algn")
{
my $Val = parseTag(\$DataType, lc($Attr));
if(defined $Val) {