amd64: Integer parameters in function calls on Windows.

gdb/ChangeLog:

        * i386-tdep.h (enum amd64_reg_class): New, moved here from
        amd64-tdep.c.
        (struct gdbarch_tdep): Add fields call_dummy_num_integer_regs,
        call_dummy_integer_regs, and classify.
        * amd64-tdep.h (amd64_classify): Add declaration.
        * amd64-tdep.c (amd64_dummy_call_integer_regs): New static constant.
        (amd64_reg_class): Delete, moved to i386-tdep.h.
        (amd64_classify): Make non-static.  Move declaration to amd64-tdep.h.
        Replace call to amd64_classify by call to tdep->classify.
        (amd64_push_arguments): Get the list of registers to use for
        passing integer parameters from the gdbarch tdep structure,
        rather than using a hardcoded one.  Replace calls to amd64_classify
        by calls to tdep->classify.
        (amd64_push_dummy_call): Get the register number used for
        the "hidden" argument from tdep->call_dummy_integer_regs.
        (amd64_init_abi): Initialize tdep->call_dummy_num_integer_regs
        and tdep->call_dummy_integer_regs.  Set tdep->classify.
        * amd64-windows-tdep.c: Add include of gdbtypes.h.
        (amd64_windows_dummy_call_integer_regs): New static global.
        (amd64_windows_classify): New function.
        (amd64_windows_init_abi): Initialize tdep->call_dummy_num_integer_regs
        tdep->call_dummy_integer_regs and tdep->classify.

gdb/testsuite/ChangeLog:

        * gdb.ada/call_pn: New testcase.
This commit is contained in:
Joel Brobecker
2010-01-29 05:19:23 +00:00
parent a1504221ad
commit ba581dc13b
10 changed files with 269 additions and 31 deletions

View File

@ -1,3 +1,28 @@
2010-01-29 Joel Brobecker <brobecker@adacore.com>
* i386-tdep.h (enum amd64_reg_class): New, moved here from
amd64-tdep.c.
(struct gdbarch_tdep): Add fields call_dummy_num_integer_regs,
call_dummy_integer_regs, and classify.
* amd64-tdep.h (amd64_classify): Add declaration.
* amd64-tdep.c (amd64_dummy_call_integer_regs): New static constant.
(amd64_reg_class): Delete, moved to i386-tdep.h.
(amd64_classify): Make non-static. Move declaration to amd64-tdep.h.
Replace call to amd64_classify by call to tdep->classify.
(amd64_push_arguments): Get the list of registers to use for
passing integer parameters from the gdbarch tdep structure,
rather than using a hardcoded one. Replace calls to amd64_classify
by calls to tdep->classify.
(amd64_push_dummy_call): Get the register number used for
the "hidden" argument from tdep->call_dummy_integer_regs.
(amd64_init_abi): Initialize tdep->call_dummy_num_integer_regs
and tdep->call_dummy_integer_regs. Set tdep->classify.
* amd64-windows-tdep.c: Add include of gdbtypes.h.
(amd64_windows_dummy_call_integer_regs): New static global.
(amd64_windows_classify): New function.
(amd64_windows_init_abi): Initialize tdep->call_dummy_num_integer_regs
tdep->call_dummy_integer_regs and tdep->classify.
2010-01-28 Daniel Jacobowitz <dan@codesourcery.com> 2010-01-28 Daniel Jacobowitz <dan@codesourcery.com>
* regcache.c (regcache_xmalloc): Add aspace argument. Use it * regcache.c (regcache_xmalloc): Add aspace argument. Use it

View File

@ -72,6 +72,17 @@ static const char *amd64_register_names[] =
/* Total number of registers. */ /* Total number of registers. */
#define AMD64_NUM_REGS ARRAY_SIZE (amd64_register_names) #define AMD64_NUM_REGS ARRAY_SIZE (amd64_register_names)
/* The registers used to pass integer arguments during a function call. */
static int amd64_dummy_call_integer_regs[] =
{
AMD64_RDI_REGNUM, /* %rdi */
AMD64_RSI_REGNUM, /* %rsi */
AMD64_RDX_REGNUM, /* %rdx */
AMD64_RCX_REGNUM, /* %rcx */
8, /* %r8 */
9 /* %r9 */
};
/* Return the name of register REGNUM. */ /* Return the name of register REGNUM. */
const char * const char *
@ -240,20 +251,6 @@ amd64_arch_reg_to_regnum (int reg)
/* Register classes as defined in the psABI. */
enum amd64_reg_class
{
AMD64_INTEGER,
AMD64_SSE,
AMD64_SSEUP,
AMD64_X87,
AMD64_X87UP,
AMD64_COMPLEX_X87,
AMD64_NO_CLASS,
AMD64_MEMORY
};
/* Return the union class of CLASS1 and CLASS2. See the psABI for /* Return the union class of CLASS1 and CLASS2. See the psABI for
details. */ details. */
@ -290,8 +287,6 @@ amd64_merge_classes (enum amd64_reg_class class1, enum amd64_reg_class class2)
return AMD64_SSE; return AMD64_SSE;
} }
static void amd64_classify (struct type *type, enum amd64_reg_class class[2]);
/* Return non-zero if TYPE is a non-POD structure or union type. */ /* Return non-zero if TYPE is a non-POD structure or union type. */
static int static int
@ -383,7 +378,7 @@ amd64_classify_aggregate (struct type *type, enum amd64_reg_class class[2])
/* Classify TYPE, and store the result in CLASS. */ /* Classify TYPE, and store the result in CLASS. */
static void void
amd64_classify (struct type *type, enum amd64_reg_class class[2]) amd64_classify (struct type *type, enum amd64_reg_class class[2])
{ {
enum type_code code = TYPE_CODE (type); enum type_code code = TYPE_CODE (type);
@ -434,6 +429,7 @@ amd64_return_value (struct gdbarch *gdbarch, struct type *func_type,
struct type *type, struct regcache *regcache, struct type *type, struct regcache *regcache,
gdb_byte *readbuf, const gdb_byte *writebuf) gdb_byte *readbuf, const gdb_byte *writebuf)
{ {
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
enum amd64_reg_class class[2]; enum amd64_reg_class class[2];
int len = TYPE_LENGTH (type); int len = TYPE_LENGTH (type);
static int integer_regnum[] = { AMD64_RAX_REGNUM, AMD64_RDX_REGNUM }; static int integer_regnum[] = { AMD64_RAX_REGNUM, AMD64_RDX_REGNUM };
@ -443,9 +439,10 @@ amd64_return_value (struct gdbarch *gdbarch, struct type *func_type,
int i; int i;
gdb_assert (!(readbuf && writebuf)); gdb_assert (!(readbuf && writebuf));
gdb_assert (tdep->classify);
/* 1. Classify the return type with the classification algorithm. */ /* 1. Classify the return type with the classification algorithm. */
amd64_classify (type, class); tdep->classify (type, class);
/* 2. If the type has class MEMORY, then the caller provides space /* 2. If the type has class MEMORY, then the caller provides space
for the return value and passes the address of this storage in for the return value and passes the address of this storage in
@ -543,15 +540,10 @@ static CORE_ADDR
amd64_push_arguments (struct regcache *regcache, int nargs, amd64_push_arguments (struct regcache *regcache, int nargs,
struct value **args, CORE_ADDR sp, int struct_return) struct value **args, CORE_ADDR sp, int struct_return)
{ {
static int integer_regnum[] = struct gdbarch_tdep *tdep = gdbarch_tdep (get_regcache_arch (regcache));
{ int *integer_regs = tdep->call_dummy_integer_regs;
AMD64_RDI_REGNUM, /* %rdi */ int num_integer_regs = tdep->call_dummy_num_integer_regs;
AMD64_RSI_REGNUM, /* %rsi */
AMD64_RDX_REGNUM, /* %rdx */
AMD64_RCX_REGNUM, /* %rcx */
8, /* %r8 */
9 /* %r9 */
};
static int sse_regnum[] = static int sse_regnum[] =
{ {
/* %xmm0 ... %xmm7 */ /* %xmm0 ... %xmm7 */
@ -568,6 +560,8 @@ amd64_push_arguments (struct regcache *regcache, int nargs,
int sse_reg = 0; int sse_reg = 0;
int i; int i;
gdb_assert (tdep->classify);
/* Reserve a register for the "hidden" argument. */ /* Reserve a register for the "hidden" argument. */
if (struct_return) if (struct_return)
integer_reg++; integer_reg++;
@ -582,7 +576,7 @@ amd64_push_arguments (struct regcache *regcache, int nargs,
int j; int j;
/* Classify argument. */ /* Classify argument. */
amd64_classify (type, class); tdep->classify (type, class);
/* Calculate the number of integer and SSE registers needed for /* Calculate the number of integer and SSE registers needed for
this argument. */ this argument. */
@ -596,7 +590,7 @@ amd64_push_arguments (struct regcache *regcache, int nargs,
/* Check whether enough registers are available, and if the /* Check whether enough registers are available, and if the
argument should be passed in registers at all. */ argument should be passed in registers at all. */
if (integer_reg + needed_integer_regs > ARRAY_SIZE (integer_regnum) if (integer_reg + needed_integer_regs > num_integer_regs
|| sse_reg + needed_sse_regs > ARRAY_SIZE (sse_regnum) || sse_reg + needed_sse_regs > ARRAY_SIZE (sse_regnum)
|| (needed_integer_regs == 0 && needed_sse_regs == 0)) || (needed_integer_regs == 0 && needed_sse_regs == 0))
{ {
@ -620,7 +614,7 @@ amd64_push_arguments (struct regcache *regcache, int nargs,
switch (class[j]) switch (class[j])
{ {
case AMD64_INTEGER: case AMD64_INTEGER:
regnum = integer_regnum[integer_reg++]; regnum = integer_regs[integer_reg++];
break; break;
case AMD64_SSE: case AMD64_SSE:
@ -686,8 +680,13 @@ amd64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
/* Pass "hidden" argument". */ /* Pass "hidden" argument". */
if (struct_return) if (struct_return)
{ {
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
/* The "hidden" argument is passed throught the first argument
register. */
const int arg_regnum = tdep->call_dummy_integer_regs[0];
store_unsigned_integer (buf, 8, byte_order, struct_addr); store_unsigned_integer (buf, 8, byte_order, struct_addr);
regcache_cooked_write (regcache, AMD64_RDI_REGNUM, buf); regcache_cooked_write (regcache, arg_regnum, buf);
} }
/* Store return address. */ /* Store return address. */
@ -2134,6 +2133,10 @@ amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
set_gdbarch_push_dummy_call (gdbarch, amd64_push_dummy_call); set_gdbarch_push_dummy_call (gdbarch, amd64_push_dummy_call);
set_gdbarch_frame_align (gdbarch, amd64_frame_align); set_gdbarch_frame_align (gdbarch, amd64_frame_align);
set_gdbarch_frame_red_zone_size (gdbarch, 128); set_gdbarch_frame_red_zone_size (gdbarch, 128);
tdep->call_dummy_num_integer_regs =
ARRAY_SIZE (amd64_dummy_call_integer_regs);
tdep->call_dummy_integer_regs = amd64_dummy_call_integer_regs;
tdep->classify = amd64_classify;
set_gdbarch_convert_register_p (gdbarch, i387_convert_register_p); set_gdbarch_convert_register_p (gdbarch, i387_convert_register_p);
set_gdbarch_register_to_value (gdbarch, i387_register_to_value); set_gdbarch_register_to_value (gdbarch, i387_register_to_value);

View File

@ -98,6 +98,9 @@ extern void amd64_supply_fxsave (struct regcache *regcache, int regnum,
extern void amd64_collect_fxsave (const struct regcache *regcache, int regnum, extern void amd64_collect_fxsave (const struct regcache *regcache, int regnum,
void *fxsave); void *fxsave);
void amd64_classify (struct type *type, enum amd64_reg_class class[2]);
/* Variables exported from amd64nbsd-tdep.c. */ /* Variables exported from amd64nbsd-tdep.c. */

View File

@ -20,15 +20,70 @@
#include "amd64-tdep.h" #include "amd64-tdep.h"
#include "solib.h" #include "solib.h"
#include "solib-target.h" #include "solib-target.h"
#include "gdbtypes.h"
/* The registers used to pass integer arguments during a function call. */
static int amd64_windows_dummy_call_integer_regs[] =
{
AMD64_RCX_REGNUM, /* %rcx */
AMD64_RDX_REGNUM, /* %rdx */
8, /* %r8 */
9 /* %r9 */
};
/* Implement the "classify" method in the gdbarch_tdep structure
for amd64-windows. */
static void
amd64_windows_classify (struct type *type, enum amd64_reg_class class[2])
{
switch (TYPE_CODE (type))
{
case TYPE_CODE_ARRAY:
/* Arrays are always passed by memory. */
class[0] = class[1] = AMD64_MEMORY;
break;
case TYPE_CODE_STRUCT:
case TYPE_CODE_UNION:
/* Struct/Union types whose size is 1, 2, 4, or 8 bytes
are passed as if they were integers of the same size.
Types of different sizes are passed by memory. */
if (TYPE_LENGTH (type) == 1
|| TYPE_LENGTH (type) == 2
|| TYPE_LENGTH (type) == 4
|| TYPE_LENGTH (type) == 8)
{
class[0] = AMD64_INTEGER;
class[1] = AMD64_NO_CLASS;
}
else
class[0] = class[1] = AMD64_MEMORY;
break;
default:
/* For all the other types, the conventions are the same as
with the System V ABI. */
amd64_classify (type, class);
}
}
static void static void
amd64_windows_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) amd64_windows_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{ {
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
amd64_init_abi (info, gdbarch); amd64_init_abi (info, gdbarch);
/* On Windows, "long"s are only 32bit. */ /* On Windows, "long"s are only 32bit. */
set_gdbarch_long_bit (gdbarch, 32); set_gdbarch_long_bit (gdbarch, 32);
/* Function calls. */
tdep->call_dummy_num_integer_regs =
ARRAY_SIZE (amd64_windows_dummy_call_integer_regs);
tdep->call_dummy_integer_regs = amd64_windows_dummy_call_integer_regs;
tdep->classify = amd64_windows_classify;
set_solib_ops (gdbarch, &solib_target_so_ops); set_solib_ops (gdbarch, &solib_target_so_ops);
} }

View File

@ -53,6 +53,20 @@ enum struct_return
reg_struct_return /* Return "short" structures in registers. */ reg_struct_return /* Return "short" structures in registers. */
}; };
/* Register classes as defined in the AMD x86-64 psABI. */
enum amd64_reg_class
{
AMD64_INTEGER,
AMD64_SSE,
AMD64_SSEUP,
AMD64_X87,
AMD64_X87UP,
AMD64_COMPLEX_X87,
AMD64_NO_CLASS,
AMD64_MEMORY
};
/* i386 architecture specific information. */ /* i386 architecture specific information. */
struct gdbarch_tdep struct gdbarch_tdep
{ {
@ -62,6 +76,16 @@ struct gdbarch_tdep
int gregset_num_regs; int gregset_num_regs;
size_t sizeof_gregset; size_t sizeof_gregset;
/* The general-purpose registers used to pass integers when making
function calls. This only applies to amd64, as all parameters
are passed through the stack on x86. */
int call_dummy_num_integer_regs;
int *call_dummy_integer_regs;
/* Classify TYPE according to calling conventions, and store
the result in CLASS. Used on amd64 only. */
void (*classify) (struct type *type, enum amd64_reg_class class[2]);
/* Floating-point registers. */ /* Floating-point registers. */
struct regset *fpregset; struct regset *fpregset;
size_t sizeof_fpregset; size_t sizeof_fpregset;

View File

@ -1,3 +1,7 @@
2010-01-29 Joel Brobecker <brobecker@adacore.com>
* gdb.ada/call_pn: New testcase.
2010-01-28 Daniel Jacobowitz <dan@codesourcery.com> 2010-01-28 Daniel Jacobowitz <dan@codesourcery.com>
* gdb.mi/mi-nonstop.exp (mi_nonstop_resume): New function. * gdb.mi/mi-nonstop.exp (mi_nonstop_resume): New function.

View File

@ -0,0 +1,53 @@
# Copyright 2010 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 3 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, see <http://www.gnu.org/licenses/>.
if $tracelevel then {
strace $tracelevel
}
load_lib "ada.exp"
set testdir "call_pn"
set testfile "${testdir}/foo"
set srcfile ${srcdir}/${subdir}/${testfile}.adb
set binfile ${objdir}/${subdir}/${testfile}
file mkdir ${objdir}/${subdir}/${testdir}
if {[gdb_compile_ada "${srcfile}" "${binfile}" executable [list debug ]] != "" } {
return -1
}
gdb_exit
gdb_start
gdb_reinitialize_dir $srcdir/$subdir
gdb_load ${binfile}
set bp_location [gdb_get_line_number "STOP" ${testdir}/foo.adb]
if ![runto "foo.adb:$bp_location" ] then {
perror "Couldn't run ${testfile}"
return
}
# Make sure that last_node_id is set to zero...
gdb_test "print last_node_id" "= 0" "print last_node_id before calling pn"
# Now, call procedure Pn, which should set Last_Node_Id to the value
# of the parameter used in the function call. Verify that we can print
# the returned value correctly, while we're at it.
gdb_test "print pn (4321)" "= 4321" "print pn (4321)"
# Make sure that last_node_id now has the correct value...
gdb_test "print last_node_id" "= 4321" "print last_node_id after calling pn"

View File

@ -0,0 +1,23 @@
-- Copyright 2010 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 3 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, see <http://www.gnu.org/licenses/>.
with Pck; use Pck;
procedure Foo is
New_Node : Node_Id;
begin
New_Node := Pn (1234); -- STOP
end Foo;

View File

@ -0,0 +1,25 @@
-- Copyright 2010 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 3 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, see <http://www.gnu.org/licenses/>.
package body Pck is
Last_Node_Id : Node_Id := Node_Id'First;
function Pn (N : Node_Id) return Node_Id is
begin
Last_Node_Id := N;
return N;
end Pn;
end Pck;

View File

@ -0,0 +1,23 @@
-- Copyright 2010 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 3 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, see <http://www.gnu.org/licenses/>.
package Pck is
Node_Low_Bound : constant := 0;
Node_High_Bound : constant := 099_999_999;
type Node_Id is range Node_Low_Bound .. Node_High_Bound;
function Pn (N : Node_Id) return Node_Id;
end Pck;