Re: [patch/rfc] Rewrite "structs" testcase

Andrew Cagney
2003-11-09T01:22:01Z

[-- Attachment #1: Type: text/plain, Size: 2105 bytes --]

> First there are duplicate "${test}" names in the output,
> and some of them PASS and some of them FAIL. Confusion!

Oops, they snuck back in :-(

> The real problem is what to do when the notorious
> "location at which to store the function's return value is unknown"
> happens. If that message happens, perhaps it is a KFAIL because
> gdb cannot do what the user asked. Or perhaps it is okay because
> a message was printed. I'm leaning towards the KFAIL, myself.
>
> But the next bit of code:
>
> # Finally check that the value returned ended up in "L${n}".
> setup_fails ${fails} gdb/1444
> gdb_test "p/c L${n}" " = [foo ${n}]" "${test}"
>
> If "location unknown" has occurred, then it's not even worthwhile
> to execute this at all. Once gdb has informed the user about
> "location unknown" then there should be no expectation on the
> part of the user that the return value will get stored into memory.

Checking my notes. There are two things being tested here:

- that return/finish really did occure
GDB 6.0 was doing something like this:
(gdb) return foo1
Return from fun1? y
Couldn't find location of return type
(gdb) list
No frame
Even though the return was performed, GDB lost the current frame and
forgot to print the new source and line. (I can't tell you exactly what
it did because GDB 6.0 dies a death with this test case on PPC :-/).

- the value was returned
The test is actually pretty robust. For a struct return, the global
won't be modified (still contains zeds).

I've modified the testcase to detect/report this.

> Maybe gdb needs to print an additional message to make it
> more clear to the user:
>
> The location at which to store the function's return value is unknown.
> If you continue, the return value that you specified will be ignored.
> Make fun1 return now? (y or n) y

Like it, yes definitly.

> Then in the test script, if you get "location unknown", issue a KFAIL
> (or do whatever) and skip a test or two.

Attatched is todays version. I think the way the fails are listed is
now "ok". Need to add more comments.

Andrew

[-- Attachment #2: structs.c --]
[-- Type: text/plain, Size: 9987 bytes --]

/* This testcase is part of GDB, the GNU debugger.

Copyright 1996, 1999, 2003 Free Software Foundation, Inc.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

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
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

Please email any bugs, comments, and/or additions to this file to:
bug-gdb@prep.ai.mit.edu */

/* Useful abreviations. */
typedef void t;
typedef char tc;
typedef short ts;
typedef int ti;
typedef long tl;
typedef long long tll;
typedef float tf;
typedef double td;
typedef long double tld;

/* Force the type of each field. */
#ifndef tA
typedef t tA;
#endif
#ifndef tB
typedef tA tB;
#endif
#ifndef tC
typedef tB tC;
#endif
#ifndef tD
typedef tC tD;
#endif
#ifndef tE
typedef tD tE;
#endif
#ifndef tF
typedef tE tF;
#endif
#ifndef tG
typedef tF tG;
#endif
#ifndef tH
typedef tG tH;
#endif
#ifndef tI
typedef tH tI;
#endif
#ifndef tJ
typedef tI tJ;
#endif
#ifndef tK
typedef tJ tK;
#endif
#ifndef tL
typedef tK tL;
#endif
#ifndef tM
typedef tL tM;
#endif
#ifndef tN
typedef tM tN;
#endif
#ifndef tO
typedef tN tO;
#endif
#ifndef tP
typedef tO tP;
#endif
#ifndef tQ
typedef tP tQ;
#endif
#ifndef tR
typedef tQ tR;
#endif

struct struct1 {tA a;};
struct struct2 {tA a; tB b;};
struct struct3 {tA a; tB b; tC c; };
struct struct4 {tA a; tB b; tC c; tD d; };
struct struct5 {tA a; tB b; tC c; tD d; tE e; };
struct struct6 {tA a; tB b; tC c; tD d; tE e; tF f; };
struct struct7 {tA a; tB b; tC c; tD d; tE e; tF f; tG g; };
struct struct8 {tA a; tB b; tC c; tD d; tE e; tF f; tG g; tH h; };
struct struct9 {tA a; tB b; tC c; tD d; tE e; tF f; tG g; tH h; tI i; };
struct struct10 {tA a; tB b; tC c; tD d; tE e; tF f; tG g; tH h; tI i; tJ j; };
struct struct11 {tA a; tB b; tC c; tD d; tE e; tF f; tG g; tH h; tI i; tJ j; tK k; };
struct struct12 {tA a; tB b; tC c; tD d; tE e; tF f; tG g; tH h; tI i; tJ j; tK k; tL l; };
struct struct13 {tA a; tB b; tC c; tD d; tE e; tF f; tG g; tH h; tI i; tJ j; tK k; tL l; tM m; };
struct struct14 {tA a; tB b; tC c; tD d; tE e; tF f; tG g; tH h; tI i; tJ j; tK k; tL l; tM m; tN n; };
struct struct15 {tA a; tB b; tC c; tD d; tE e; tF f; tG g; tH h; tI i; tJ j; tK k; tL l; tM m; tN n; tO o; };
struct struct16 {tA a; tB b; tC c; tD d; tE e; tF f; tG g; tH h; tI i; tJ j; tK k; tL l; tM m; tN n; tO o; tP p; };
struct struct17 {tA a; tB b; tC c; tD d; tE e; tF f; tG g; tH h; tI i; tJ j; tK k; tL l; tM m; tN n; tO o; tP p; tQ q; };
struct struct18 {tA a; tB b; tC c; tD d; tE e; tF f; tG g; tH h; tI i; tJ j; tK k; tL l; tM m; tN n; tO o; tP p; tQ q; tR r; };

struct struct1 foo1 = {'1'}, L1;
struct struct2 foo2 = {'a','2'}, L2;
struct struct3 foo3 = {'1','b','3'}, L3;
struct struct4 foo4 = {'a','2','c','4'}, L4;
struct struct5 foo5 = {'1','b','3','d','5'}, L5;
struct struct6 foo6 = {'a','2','c','4','e','6'}, L6;
struct struct7 foo7 = {'1','b','3','d','5','f','7'}, L7;
struct struct8 foo8 = {'a','2','c','4','e','6','g','8'}, L8;
struct struct9 foo9 = {'1','b','3','d','5','f','7','h','9'}, L9;
struct struct10 foo10 = {'a','2','c','4','e','6','g','8','i','A'}, L10;
struct struct11 foo11 = {'1','b','3','d','5','f','7','h','9','j','B'}, L11;
struct struct12 foo12 = {'a','2','c','4','e','6','g','8','i','A','k','C'}, L12;
struct struct13 foo13 = {'1','b','3','d','5','f','7','h','9','j','B','l','D'}, L13;
struct struct14 foo14 = {'a','2','c','4','e','6','g','8','i','A','k','C','m','E'}, L14;
struct struct15 foo15 = {'1','b','3','d','5','f','7','h','9','j','B','l','D','n','F'}, L15;
struct struct16 foo16 = {'a','2','c','4','e','6','g','8','i','A','k','C','m','E','o','G'}, L16;
struct struct17 foo17 = {'1','b','3','d','5','f','7','h','9','j','B','l','D','n','F','p','H'}, L17;
struct struct18 foo18 = {'a','2','c','4','e','6','g','8','i','A','k','C','m','E','o','G','q','I'}, L18;

struct struct1 fun1()
{
return foo1;
}
struct struct2 fun2()
{
return foo2;
}
struct struct3 fun3()
{
return foo3;
}
struct struct4 fun4()
{
return foo4;
}
struct struct5 fun5()
{
return foo5;
}
struct struct6 fun6()
{
return foo6;
}
struct struct7 fun7()
{
return foo7;
}
struct struct8 fun8()
{
return foo8;
}
struct struct9 fun9()
{
return foo9;
}
struct struct10 fun10()
{
return foo10;
}
struct struct11 fun11()
{
return foo11;
}
struct struct12 fun12()
{
return foo12;
}
struct struct13 fun13()
{
return foo13;
}
struct struct14 fun14()
{
return foo14;
}
struct struct15 fun15()
{
return foo15;
}
struct struct16 fun16()
{
return foo16;
}
struct struct17 fun17()
{
return foo17;
}
struct struct18 fun18()
{
return foo18;
}

#ifdef PROTOTYPES
void Fun1(struct struct1 foo1)
#else
void Fun1(foo1)
struct struct1 foo1;
#endif
{
L1 = foo1;
}
#ifdef PROTOTYPES
void Fun2(struct struct2 foo2)
#else
void Fun2(foo2)
struct struct2 foo2;
#endif
{
L2 = foo2;
}
#ifdef PROTOTYPES
void Fun3(struct struct3 foo3)
#else
void Fun3(foo3)
struct struct3 foo3;
#endif
{
L3 = foo3;
}
#ifdef PROTOTYPES
void Fun4(struct struct4 foo4)
#else
void Fun4(foo4)
struct struct4 foo4;
#endif
{
L4 = foo4;
}
#ifdef PROTOTYPES
void Fun5(struct struct5 foo5)
#else
void Fun5(foo5)
struct struct5 foo5;
#endif
{
L5 = foo5;
}
#ifdef PROTOTYPES
void Fun6(struct struct6 foo6)
#else
void Fun6(foo6)
struct struct6 foo6;
#endif
{
L6 = foo6;
}
#ifdef PROTOTYPES
void Fun7(struct struct7 foo7)
#else
void Fun7(foo7)
struct struct7 foo7;
#endif
{
L7 = foo7;
}
#ifdef PROTOTYPES
void Fun8(struct struct8 foo8)
#else
void Fun8(foo8)
struct struct8 foo8;
#endif
{
L8 = foo8;
}
#ifdef PROTOTYPES
void Fun9(struct struct9 foo9)
#else
void Fun9(foo9)
struct struct9 foo9;
#endif
{
L9 = foo9;
}
#ifdef PROTOTYPES
void Fun10(struct struct10 foo10)
#else
void Fun10(foo10)
struct struct10 foo10;
#endif
{
L10 = foo10;
}
#ifdef PROTOTYPES
void Fun11(struct struct11 foo11)
#else
void Fun11(foo11)
struct struct11 foo11;
#endif
{
L11 = foo11;
}
#ifdef PROTOTYPES
void Fun12(struct struct12 foo12)
#else
void Fun12(foo12)
struct struct12 foo12;
#endif
{
L12 = foo12;
}
#ifdef PROTOTYPES
void Fun13(struct struct13 foo13)
#else
void Fun13(foo13)
struct struct13 foo13;
#endif
{
L13 = foo13;
}
#ifdef PROTOTYPES
void Fun14(struct struct14 foo14)
#else
void Fun14(foo14)
struct struct14 foo14;
#endif
{
L14 = foo14;
}
#ifdef PROTOTYPES
void Fun15(struct struct15 foo15)
#else
void Fun15(foo15)
struct struct15 foo15;
#endif
{
L15 = foo15;
}
#ifdef PROTOTYPES
void Fun16(struct struct16 foo16)
#else
void Fun16(foo16)
struct struct16 foo16;
#endif
{
L16 = foo16;
}
#ifdef PROTOTYPES
void Fun17(struct struct17 foo17)
#else
void Fun17(foo17)
struct struct17 foo17;
#endif
{
L17 = foo17;
}
#ifdef PROTOTYPES
void Fun18(struct struct18 foo18)
#else
void Fun18(foo18)
struct struct18 foo18;
#endif
{
L18 = foo18;
}

zed ()
{

L1.a = L2.a = L3.a = L4.a = L5.a = L6.a = L7.a = L8.a = L9.a = L10.a = L11.a = L12.a = L13.a = L14.a = L15.a = L16.a = L17.a = L18.a = 'Z';

L2.b = L3.b = L4.b = L5.b = L6.b = L7.b = L8.b = L9.b = L10.b = L11.b = L12.b = L13.b = L14.b = L15.b = L16.b = L17.b = L18.b = 'Z';

L3.c = L4.c = L5.c = L6.c = L7.c = L8.c = L9.c = L10.c = L11.c = L12.c = L13.c = L14.c = L15.c = L16.c = L17.c = L18.c = 'Z';

L4.d = L5.d = L6.d = L7.d = L8.d = L9.d = L10.d = L11.d = L12.d = L13.d = L14.d = L15.d = L16.d = L17.d = L18.d = 'Z';

L5.e = L6.e = L7.e = L8.e = L9.e = L10.e = L11.e = L12.e = L13.e = L14.e = L15.e = L16.e = L17.e = L18.e = 'Z';

L6.f = L7.f = L8.f = L9.f = L10.f = L11.f = L12.f = L13.f = L14.f = L15.f = L16.f = L17.f = L18.f = 'Z';

L7.g = L8.g = L9.g = L10.g = L11.g = L12.g = L13.g = L14.g = L15.g = L16.g = L17.g = L18.g = 'Z';

L8.h = L9.h = L10.h = L11.h = L12.h = L13.h = L14.h = L15.h = L16.h = L17.h = L18.h = 'Z';

L9.i = L10.i = L11.i = L12.i = L13.i = L14.i = L15.i = L16.i = L17.i = L18.i = 'Z';

L10.j = L11.j = L12.j = L13.j = L14.j = L15.j = L16.j = L17.j = L18.j = 'Z';

L11.k = L12.k = L13.k = L14.k = L15.k = L16.k = L17.k = L18.k = 'Z';

L12.l = L13.l = L14.l = L15.l = L16.l = L17.l = L18.l = 'Z';

L13.m = L14.m = L15.m = L16.m = L17.m = L18.m = 'Z';

L14.n = L15.n = L16.n = L17.n = L18.n = 'Z';

L15.o = L16.o = L17.o = L18.o = 'Z';

L16.p = L17.p = L18.p = 'Z';

L17.q = L18.q = 'Z';

L18.r = 'Z';
}

int main()
{
#ifdef usestubs
set_debug_traps();
breakpoint();
#endif
int i;

Fun1(foo1);
Fun2(foo2);
Fun3(foo3);
Fun4(foo4);
Fun5(foo5);
Fun6(foo6);
Fun7(foo7);
Fun8(foo8);
Fun9(foo9);
Fun10(foo10);
Fun11(foo11);
Fun12(foo12);
Fun13(foo13);
Fun14(foo14);
Fun15(foo15);
Fun16(foo16);
Fun17(foo17);
Fun18(foo18);

/* An infinite loop that first clears all the variables and then
calls each function. This "hack" is to make testing random
functions easier - "advance funN" is guaranteed to have always
been preceeded by a global variable clearing zed call. */

while (1)
{
zed ();
L1 = fun1();
L2 = fun2();
L3 = fun3();
L4 = fun4();
L5 = fun5();
L6 = fun6();
L7 = fun7();
L8 = fun8();
L9 = fun9();
L10 = fun10();
L11 = fun11();
L12 = fun12();
L13 = fun13();
L14 = fun14();
L15 = fun15();
L16 = fun16();
L17 = fun17();
L18 = fun18();
}

return 0;
}

[-- Attachment #3: structs.exp --]
[-- Type: text/plain, Size: 18972 bytes --]

# This testcase is part of GDB, the GNU debugger.

# Copyright 1996, 1997, 1999, 2003 Free Software Foundation, Inc.

# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# 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
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

# Please email any bugs, comments, and/or additions to this file to:
# bug-gdb@prep.ai.mit.edu

if $tracelevel then {
strace $tracelevel
}

set prms_id 0
set bug_id 0

# Some targets can't call functions, so don't even bother with this
# test.

if [target_info exists gdb,cannot_call_functions] {
setup_xfail "*-*-*" 2416
fail "This target can not call functions"
continue
}

set testfile "structs"
set srcfile ${testfile}.c
set binfile ${objdir}/${subdir}/${testfile}

# Create and source the file that provides information about the
# compiler used to compile the test case.

if [get_compiler_info ${binfile}] {
return -1;
}

# Global variable that contains the list of types for the most recent
# build/start. Types are encoded as two or three letter accronyms
# vis: tc or char, ts for short, tld for long double. The full list
# is found in structs.c.

set struct_types {}

# Compile a variant of structs.c using TYPES to specify the type of
# the first N struct elements (the remaining elements take the type of
# the last TYPES field). Run the compmiled program up to "main".
# Also updates the global "struct_types" to reflect the most recent
# build.

proc start_structs_test { types } {
global testfile
global srcfile
global binfile
global objdir
global subdir
global srcdir
global gdb_prompt

# Set that global to the current set of structs
global struct_types
set struct_types $types

# Create the additional flags
set flags "debug"
set name ""
set n 0
for {set n 0} {$n<[llength ${struct_types}]} {incr n} {
set m [I2A ${n}]
set t [lindex ${struct_types} $n]
lappend flags "additional_flags=-Dt${m}=${t}"
append name "-" "$t"
}

set binfile ${objdir}/${subdir}/${testfile}${name}
if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable "${flags}"] != "" } {
# built the second test case since we can't use prototypes
warning "Prototypes not supported, rebuilding with -DNO_PROTOTYPES"
if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable "${flags} additional_flags=-DNO_PROTOTYPES"] != "" } {
gdb_suppress_entire_file "Testcase compile failed, so all tests in this file will automatically fail."
}
}

# Start with a fresh gdb.
gdb_start
gdb_reinitialize_dir $srcdir/$subdir
gdb_load ${binfile}

# Make certain that the output is consistent
gdb_test "set print sevenbit-strings" "" \
"set print sevenbit-strings; ${struct_types}"
gdb_test "set print address off" "" \
"set print address off; ${struct_types}"
gdb_test "set width 0" "" \
"set width 0; ${struct_types}"

# Advance to main
if { ![runto_main] } then {
gdb_suppress_tests;
}

# check that at the struct containing all the relevant types is correct
set foo_t "type = struct struct[llength ${struct_types}] \{"
for {set n 0} {$n<[llength ${struct_types}]} {incr n} {
append foo_t "\[\r\n \]+[lindex ${struct_types} $n] [i2a $n];"
}
append foo_t "\[\r\n \]+\}"
gdb_test "ptype foo[llength ${struct_types}]" "${foo_t}" \
"ptype foo[llength ${struct_types}]; ${struct_types}"
}

# The expected value for fun${n}, L${n} and foo${n}. First element is
# empty to make indexing easier. "foo" returns the modified value,
# "zed" returns the invalid value.

proc foo { n } {
return [lindex {
"{}"
"{a = 49 '1'}"
"{a = 97 'a', b = 50 '2'}"
"{a = 49 '1', b = 98 'b', c = 51 '3'}"
"{a = 97 'a', b = 50 '2', c = 99 'c', d = 52 '4'}"
"{a = 49 '1', b = 98 'b', c = 51 '3', d = 100 'd', e = 53 '5'}"
"{a = 97 'a', b = 50 '2', c = 99 'c', d = 52 '4', e = 101 'e', f = 54 '6'}"
"{a = 49 '1', b = 98 'b', c = 51 '3', d = 100 'd', e = 53 '5', f = 102 'f', g = 55 '7'}"
"{a = 97 'a', b = 50 '2', c = 99 'c', d = 52 '4', e = 101 'e', f = 54 '6', g = 103 'g', h = 56 '8'}"
"{a = 49 '1', b = 98 'b', c = 51 '3', d = 100 'd', e = 53 '5', f = 102 'f', g = 55 '7', h = 104 'h', i = 57 '9'}"
"{a = 97 'a', b = 50 '2', c = 99 'c', d = 52 '4', e = 101 'e', f = 54 '6', g = 103 'g', h = 56 '8', i = 105 'i', j = 65 'A'}"
"{a = 49 '1', b = 98 'b', c = 51 '3', d = 100 'd', e = 53 '5', f = 102 'f', g = 55 '7', h = 104 'h', i = 57 '9', j = 106 'j', k = 66 'B'}"
"{a = 97 'a', b = 50 '2', c = 99 'c', d = 52 '4', e = 101 'e', f = 54 '6', g = 103 'g', h = 56 '8', i = 105 'i', j = 65 'A', k = 107 'k', l = 67 'C'}"
"{a = 49 '1', b = 98 'b', c = 51 '3', d = 100 'd', e = 53 '5', f = 102 'f', g = 55 '7', h = 104 'h', i = 57 '9', j = 106 'j', k = 66 'B', l = 108 'l', m = 68 'D'}"
"{a = 97 'a', b = 50 '2', c = 99 'c', d = 52 '4', e = 101 'e', f = 54 '6', g = 103 'g', h = 56 '8', i = 105 'i', j = 65 'A', k = 107 'k', l = 67 'C', m = 109 'm', n = 69 'E'}"
"{a = 49 '1', b = 98 'b', c = 51 '3', d = 100 'd', e = 53 '5', f = 102 'f', g = 55 '7', h = 104 'h', i = 57 '9', j = 106 'j', k = 66 'B', l = 108 'l', m = 68 'D', n = 110 'n', o = 70 'F'}"
"{a = 97 'a', b = 50 '2', c = 99 'c', d = 52 '4', e = 101 'e', f = 54 '6', g = 103 'g', h = 56 '8', i = 105 'i', j = 65 'A', k = 107 'k', l = 67 'C', m = 109 'm', n = 69 'E', o = 111 'o', p = 71 'G'}"
"{a = 49 '1', b = 98 'b', c = 51 '3', d = 100 'd', e = 53 '5', f = 102 'f', g = 55 '7', h = 104 'h', i = 57 '9', j = 106 'j', k = 66 'B', l = 108 'l', m = 68 'D', n = 110 'n', o = 70 'F', p = 112 'p', q = 72 'H'}"
} $n]
}

proc zed { n } {
return [lindex {
"{}"
"{a = 90 'Z'}"
"{a = 90 'Z', b = 90 'Z'}"
"{a = 90 'Z', b = 90 'Z', c = 90 'Z'}"
"{a = 90 'Z', b = 90 'Z', c = 90 'Z', d = 90 'Z'}"
"{a = 90 'Z', b = 90 'Z', c = 90 'Z', d = 90 'Z', e = 90 'Z'}"
"{a = 90 'Z', b = 90 'Z', c = 90 'Z', d = 90 'Z', e = 90 'Z', f = 90 'Z'}"
"{a = 90 'Z', b = 90 'Z', c = 90 'Z', d = 90 'Z', e = 90 'Z', f = 90 'Z', g = 90 'Z'}"
"{a = 90 'Z', b = 90 'Z', c = 90 'Z', d = 90 'Z', e = 90 'Z', f = 90 'Z', g = 90 'Z', h = 90 'Z'}"
"{a = 90 'Z', b = 90 'Z', c = 90 'Z', d = 90 'Z', e = 90 'Z', f = 90 'Z', g = 90 'Z', h = 90 'Z', i = 90 'Z'}"
"{a = 90 'Z', b = 90 'Z', c = 90 'Z', d = 90 'Z', e = 90 'Z', f = 90 'Z', g = 90 'Z', h = 90 'Z', i = 90 'Z', j = 90 'Z'}"
"{a = 90 'Z', b = 90 'Z', c = 90 'Z', d = 90 'Z', e = 90 'Z', f = 90 'Z', g = 90 'Z', h = 90 'Z', i = 90 'Z', j = 90 'Z', k = 90 'Z'}"
"{a = 90 'Z', b = 90 'Z', c = 90 'Z', d = 90 'Z', e = 90 'Z', f = 90 'Z', g = 90 'Z', h = 90 'Z', i = 90 'Z', j = 90 'Z', k = 90 'Z', l = 90 'Z'}"
"{a = 90 'Z', b = 90 'Z', c = 90 'Z', d = 90 'Z', e = 90 'Z', f = 90 'Z', g = 90 'Z', h = 90 'Z', i = 90 'Z', j = 90 'Z', k = 90 'Z', l = 90 'Z', m = 90 'Z'}"
"{a = 90 'Z', b = 90 'Z', c = 90 'Z', d = 90 'Z', e = 90 'Z', f = 90 'Z', g = 90 'Z', h = 90 'Z', i = 90 'Z', j = 90 'Z', k = 90 'Z', l = 90 'Z', m = 90 'Z', n = 90 'Z'}"
"{a = 90 'Z', b = 90 'Z', c = 90 'Z', d = 90 'Z', e = 90 'Z', f = 90 'Z', g = 90 'Z', h = 90 'Z', i = 90 'Z', j = 90 'Z', k = 90 'Z', l = 90 'Z', m = 90 'Z', n = 90 'Z', o = 90 'Z'}"
"{a = 90 'Z', b = 90 'Z', c = 90 'Z', d = 90 'Z', e = 90 'Z', f = 90 'Z', g = 90 'Z', h = 90 'Z', i = 90 'Z', j = 90 'Z', k = 90 'Z', l = 90 'Z', m = 90 'Z', n = 90 'Z', o = 90 'Z', p = 90 'Z'}"
"{a = 90 'Z', b = 90 'Z', c = 90 'Z', d = 90 'Z', e = 90 'Z', f = 90 'Z', g = 90 'Z', h = 90 'Z', i = 90 'Z', j = 90 'Z', k = 90 'Z', l = 90 'Z', m = 90 'Z', n = 90 'Z', o = 90 'Z', p = 90 'Z', q = 90 'Z'}"
} $n]
}

# Given N (0..25), return the corresponding alphabetic letter. This
# is i18n proof.

proc i2a { n } {
return [string range "abcdefghijklmnopqrstuvwxyz" $n $n]
}

proc I2A { n } {
return [string toupper [i2a $n]]
}

# Report the test result. Use the tuples in FAILS to mark up any
# expected xfail/kfail based on that result. For instance, if the
# result is a XPASS, any tuple in the FAILS list gets reported as an
# XPASS. Or for a KFAIL, any FAILS become KFAILS.

proc report { expected test fails bug } {
switch $expected {
xpass {
foreach f $fails { setup_xfail $f $bug }
pass $test
}
kpass {
foreach f $fails { setup_kfail $f $bug }
pass $test
}
xfail {
foreach f $fails { setup_xfail $f $bug }
fail $test
}
kfail {
foreach f $fails { setup_kfail $f $bug }
fail $test
}
default {
perror "Bad expected report $expected"
}
}
}

# Check GDB's ability to call inferior functions involving structs.

proc test_struct_calls { n fails } {
global struct_types
global gdb_prompt

# Check that GDB can always extract a struct-return value from an
# inferior function call. Since GDB always knows the location of an
# inferior function call's return value these should never fail

# Implemented by calling the parameterless function "fun$N" and then
# examining the return value printed by GDB.

set tests "call ${struct_types}"

# Call fun${n}, checking the printed return value.
send_gdb "p/c fun${n}()\n"
set test "p/c fun${n}(); ${tests}"
gdb_expect {
-re "[foo ${n}]\[\r\n\]+$gdb_prompt $" {
report kpass "${test}" ${fails} gdb/1443
}
-re "$gdb_prompt $" {
# "Return value of a struct return function lost"
report kfail "${test}" ${fails} gdb/1443
}
timeout {
fail "${test} (timeout)"
}
}

# Check that GDB can always pass a structure to an inferior function.
# This test can never fail.

# Implemented by calling the one parameter function "Fun$N" which
# stores its parameter in the global variable "L$N". GDB then
# examining that global to confirm that the value is as expected.

gdb_test "call Fun${n}(foo${n})" "" "call Fun${n}(foo${n}); ${tests}"
gdb_test "p/c L${n}" [foo ${n}] "p/c L${n}; ${tests}"
}

proc test_struct_returns { n fails } {
global gdb_prompt
global struct_types

set tests "return ${struct_types}"

# Remember if the test involves "struct return convention". If it
# does, the fail is expected - GDB can't handle the edge case.
set struct_return 0

# Check that GDB can correctly force the return of a function that has
# a struct result. Dependant on the ABI, it may, or may not be
# possible to make this work.

# The relevant code looks like "L{n} = fun{n}()". The test forces
# "fun{n}" to "return" with an explicit value. Since that code
# snippet will store the the returned value in "L{n}", its possible to
# confirm that things work by examining "L{n}".

# Get into a call of fun${n}
gdb_test "advance fun${n}" \
"fun${n} .*\[\r\n\]+\[0-9\].*return foo${n}.*" \
"advance to fun${n} for return; ${tests}"

# Check that the program invalidated the relevant global.
gdb_test "p/c L${n}" " = [zed $n]" "zed L${n} for return; ${tests}"

# Now test a forced return. This code is checking that GDB does
# not leave the user dangling and that the final resting place of
# the return is clear (GDB 6.0 sometimes forgot to print the
# "source and line" information leaving the user with "No frame".

send_gdb "return foo${n}\n"
set test "return foo${n}; ${tests}"
gdb_expect {
-re "The location" {
# Ulgh, a struct return, remember this (still need prompt).
set struct_return 1
exp_continue
}
-re "Make fun${n} return now.*y or n. $" {
send_gdb "y\n"
gdb_expect {
-re "L${n} *= fun${n}.*${gdb_prompt} $" {
# Need to step off the function call
gdb_test "next" "L.* *= fun.*" "${test}"
}
-re "L[expr ${n} + 1] *= fun[expr ${n} + 1].*${gdb_prompt} $" {
pass "${test}"
}
timeout {
fail "${test} (timeout 2)"
}
}
}
-re "${gdb_prompt} $" {
fail "${test} (no query)"
}
timeout {
fail "${test} (timeout 1)"
}
}

# Check that the retun value is as expected. As noted below,
# there are two expected outcomes.

send_gdb "p/c L${n}\n"
set test "value foo${n} returned; ${tests}"
gdb_expect {
-re " = [foo ${n}].*${gdb_prompt} $" {
# The value was returned and stored in the global. Can't be
# the struct return case.
if $struct_return {
report kfail "${test}" ${fails} gdb/1444
} else {
report kpass "${test}" ${fails} gdb/1444
}
}
-re " = [zed ${n}].*${gdb_prompt} $" {
# The struct return case. Since any modification would be
# by reference, and that can't happen, the value should
# be unmodified and hence Z is expected. I guess this assumes
# that the compiled code pass a reference to the L variable
# and not something on the stack. Reasonable?
if $struct_return {
# expected
report xfail "${test}" ${fails} gdb/1444
} else {
# unexpected
report kfail "${test}" ${fails} gdb/1444
}
}
-re "${gdb_prompt} $" {
# Garbage returned, garbage printed
report kfail "${test}" ${fails} gdb/1444
}
timeout {
fail "${test} (timeout)"
}
}

# Check that GDB can always finish a struct-return function.
# Dependant on the ABI GDB may or may not be able to find the value
# returned by that function.

# The relevant code snippet is "L{n} = fun{n}()". The program is
# allowed to get into a call to "fun{n}" and that function is then
# finished. The returned value that GDB prints is then checked.

# Get into "fun${n}()".
gdb_test "advance fun${n}" \
"fun${n} .*\[\r\n\]+\[0-9\].*return foo${n}.*" \
"advance to fun${n} for finish; ${tests}"

# Check that the program invalidated the relevant global.
gdb_test "p/c L${n}" " = [zed $n]" "zed L${n} for finish; ${tests}"

# Finish that function, this should put the return value in a
# convenience variable.
gdb_test "finish" "" "finish fun$n; ${tests}"

# Reprint that last value but using a more robust format.
# If the finish didn't display a value, the earlier ZED is displayed.
send_gdb "p/c\n"
set test "value foo${n} finished; ${tests}"
gdb_expect {
-re "[foo ${n}]\[\r\n\]+${gdb_prompt} $" {
report kpass "${test}" ${fails} gdb/1444
}
-re "[zed ${n}]\[\r\n\]+${gdb_prompt} $" {
# Value lost, assume struct return. The return test
# will have checked this. If struct return wasn't expected
# its a bug.
if $struct_return {
report xfail "${test}" ${fails} gdb/1444
} else {
report kfail "${test}" ${fails} gdb/1444
}
}
-re ".*${gdb_prompt} $" {
# Garbage returned
report kfail "${test}" ${fails} gdb/1444
}
timeout {
fail "${test} (timeout)"
}
}
}

# ABIs pass anything >8 or >16 bytes in memory but below that things
# randomly use register and/and structure conventions. Check all
# possible sized char structs in that range. But only a restricted
# range of the other types.

# On NetBSD, "unnatural" sized structs get returned in memory.

start_structs_test { tc }
test_struct_calls 1 { }
test_struct_calls 2 { }
test_struct_calls 3 { }
test_struct_calls 4 { }
test_struct_calls 5 { }
test_struct_calls 6 { }
test_struct_calls 7 { }
test_struct_calls 8 { }
test_struct_calls 9 { }
test_struct_calls 10 { }
test_struct_calls 11 { }
test_struct_calls 12 { }
test_struct_calls 13 { }
test_struct_calls 14 { }
test_struct_calls 15 { }
test_struct_calls 16 { }
test_struct_calls 17 { }
test_struct_returns 1 { }
test_struct_returns 2 { }
test_struct_returns 3 { powerpc-*-netbsd* }
test_struct_returns 4 { }
test_struct_returns 5 { powerpc-*-netbsd* }
test_struct_returns 6 { powerpc-*-netbsd* }
test_struct_returns 7 { powerpc-*-netbsd* }
test_struct_returns 8 { }

start_structs_test { ts}
test_struct_calls 1 { }
test_struct_calls 2 { }
test_struct_calls 3 { }
test_struct_calls 4 { }
test_struct_calls 5 { }
test_struct_returns 1 { }
test_struct_returns 2 { }
test_struct_returns 3 { powerpc-*-netbsd* }
test_struct_returns 4 { }

start_structs_test { ti }
test_struct_calls 1 { }
test_struct_calls 2 { }
test_struct_calls 3 { }
test_struct_returns 1 { }
test_struct_returns 2 { }

start_structs_test { tl }
test_struct_calls 1 { }
test_struct_calls 2 { }
test_struct_calls 3 { }
test_struct_returns 1 { }
test_struct_returns 2 { }

start_structs_test { tll }
test_struct_calls 1 { }
test_struct_calls 2 { }
test_struct_returns 1 { }

start_structs_test { tf }
test_struct_calls 1 { }
test_struct_calls 2 { }
test_struct_calls 3 { }
test_struct_returns 1 { }
test_struct_returns 2 { }

start_structs_test { td }
test_struct_calls 1 { }
test_struct_calls 2 { }
test_struct_returns 1 { }

start_structs_test { tld }
test_struct_calls 1 { }
test_struct_calls 2 { }
test_struct_returns 1 { }

start_structs_test { ts tc }
test_struct_calls 2 { }
test_struct_calls 3 { }
test_struct_calls 4 { }
test_struct_calls 5 { }
test_struct_calls 6 { }
test_struct_calls 7 { }
test_struct_calls 8 { }
test_struct_returns 2 { }

start_structs_test { ti tc }
test_struct_calls 2 { }
test_struct_calls 3 { }
test_struct_calls 4 { }
test_struct_calls 5 { }
test_struct_calls 6 { }
test_struct_returns 2 { }

start_structs_test { tl tc }
test_struct_calls 2 { }
test_struct_calls 3 { }
test_struct_calls 4 { }
test_struct_calls 5 { }
test_struct_calls 6 { }
test_struct_returns 2 { }

start_structs_test { tll tc }
test_struct_calls 2 { }

start_structs_test { tf tc }
test_struct_calls 2 { }
test_struct_calls 3 { }
test_struct_calls 4 { }
test_struct_calls 5 { }
test_struct_calls 6 { }
test_struct_returns 2 { }

start_structs_test { td tc }
test_struct_calls 2 { }

start_structs_test { tld tc }
test_struct_calls 2 { }

start_structs_test { tc ts }
test_struct_calls 2 { }
test_struct_calls 3 { }
test_struct_calls 4 { }
test_struct_calls 5 { }
test_struct_calls 6 { }
test_struct_returns 2 { }

start_structs_test { tc ti }
test_struct_calls 2 { }
test_struct_calls 3 { }
test_struct_calls 4 { }
test_struct_returns 2 { }

start_structs_test { tc tl }
test_struct_calls 2 { }
test_struct_calls 3 { }
test_struct_calls 4 { }
test_struct_returns 2 { }

start_structs_test { tc tll }
test_struct_calls 2 { }

start_structs_test { tc tf }
test_struct_calls 2 { }
test_struct_calls 3 { }
test_struct_calls 4 { }

start_structs_test { tc td }
test_struct_calls 2 { }

start_structs_test { tc tld }
test_struct_calls 2 { }

return 0