* m68k-tdep.h (struct gdbarch_tdep): Add member

struct_value_regnum.
(m68k_svr4_init_abi): New prototype.
* m68k-tdep.c: Include "floatformat.h".  Add comment about all the
different calling conventions.
(m68k_extract_return_value): Remove code dealing with single-field
structs.
(m68k_store_return_value): Remove code dealing with single-field
structs.  Correctly store return values of 5, 6, 7 or 8 bytes.
(m68k_extract_struct_value_address): Remove function.
(m68k_svr4_extract_return_value,m68k_svr4_store_return_value)
(m68k_reg_struct_return_p, m68k_return_value)
(m68k_svr4_return_value): New functions.
(m68k_use_struct_convention): Remove function.
(m68k_push_dummy_call): Use new struct_value_regnum member of
`struct gdbarch_tdep' instead of hardcoded register number to
store STRUCT_ADDR.
(m68k_svr4_init_abi): New function.
(m68k_gdbarch_init): Don't set extract_return_value,
store_return_values, deprecated_extract_struct_value_address and
use_struct_convention.  Set return_value instead.  Initialize new
struct_value_regnum member of `struct gdbarch_tdep'.
* m68klinux-tdep.c: Update copyright year.
(m68k_linux_extract_return_value, m68k_linux_store_return_value)
(m68k_linux_extract_struct_value_address): Remove function.
(m68k_linux_init_abi): Don't set extract_return_value,
store_return_values, deprecated_extract_struct_value_address and
use_struct_convention.  Call m68k_svr4_init_abi but override the
new struct_value_regnum member of `struct gdbarch_tdep'.
* Makefile.in (m68k-tdep.o): Update dependencies.
This commit is contained in:
Mark Kettenis 2004-05-03 21:56:09 +00:00
parent aaa75496b0
commit f595cb1909
5 changed files with 220 additions and 152 deletions

View File

@ -1,3 +1,36 @@
2004-05-03 Mark Kettenis <kettenis@gnu.org>
* m68k-tdep.h (struct gdbarch_tdep): Add member
struct_value_regnum.
(m68k_svr4_init_abi): New prototype.
* m68k-tdep.c: Include "floatformat.h". Add comment about all the
different calling conventions.
(m68k_extract_return_value): Remove code dealing with single-field
structs.
(m68k_store_return_value): Remove code dealing with single-field
structs. Correctly store return values of 5, 6, 7 or 8 bytes.
(m68k_extract_struct_value_address): Remove function.
(m68k_svr4_extract_return_value,m68k_svr4_store_return_value)
(m68k_reg_struct_return_p, m68k_return_value)
(m68k_svr4_return_value): New functions.
(m68k_use_struct_convention): Remove function.
(m68k_push_dummy_call): Use new struct_value_regnum member of
`struct gdbarch_tdep' instead of hardcoded register number to
store STRUCT_ADDR.
(m68k_svr4_init_abi): New function.
(m68k_gdbarch_init): Don't set extract_return_value,
store_return_values, deprecated_extract_struct_value_address and
use_struct_convention. Set return_value instead. Initialize new
struct_value_regnum member of `struct gdbarch_tdep'.
* m68klinux-tdep.c: Update copyright year.
(m68k_linux_extract_return_value, m68k_linux_store_return_value)
(m68k_linux_extract_struct_value_address): Remove function.
(m68k_linux_init_abi): Don't set extract_return_value,
store_return_values, deprecated_extract_struct_value_address and
use_struct_convention. Call m68k_svr4_init_abi but override the
new struct_value_regnum member of `struct gdbarch_tdep'.
* Makefile.in (m68k-tdep.o): Update dependencies.
2004-05-03 J. Brobecker <brobecker@gnat.com>
* dwarf2read.c (line_header): Add new included_p field in

View File

@ -2032,10 +2032,10 @@ m68knbsd-nat.o: m68knbsd-nat.c $(defs_h) $(inferior_h) $(gdbcore_h) \
m68knbsd-tdep.o: m68knbsd-tdep.c $(defs_h) $(gdbtypes_h) $(regcache_h)
m68k-stub.o: m68k-stub.c
m68k-tdep.o: m68k-tdep.c $(defs_h) $(dwarf2_frame_h) $(frame_h) \
$(frame_base_h) $(frame_unwind_h) $(symtab_h) $(gdbcore_h) \
$(value_h) $(gdb_string_h) $(gdb_assert_h) $(inferior_h) \
$(regcache_h) $(arch_utils_h) $(osabi_h) $(dis_asm_h) $(m68k_tdep_h) \
$(gregset_h)
$(frame_base_h) $(frame_unwind_h) $(floatformat_h) $(symtab_h)\
$(gdbcore_h) $(value_h) $(gdb_string_h) $(gdb_assert_h) \
$(inferior_h) $(regcache_h) $(arch_utils_h) $(osabi_h) $(dis_asm_h) \
$(m68k_tdep_h) $(gregset_h)
macrocmd.o: macrocmd.c $(defs_h) $(macrotab_h) $(macroexp_h) $(macroscope_h) \
$(command_h) $(gdbcmd_h)
macroexp.o: macroexp.c $(defs_h) $(gdb_obstack_h) $(bcache_h) $(macrotab_h) \

View File

@ -25,6 +25,7 @@
#include "frame.h"
#include "frame-base.h"
#include "frame-unwind.h"
#include "floatformat.h"
#include "symtab.h"
#include "gdbcore.h"
#include "value.h"
@ -129,8 +130,36 @@ m68k_register_name (int regnum)
return register_names[regnum];
}
/* Extract from an array REGBUF containing the (raw) register state, a
function return value of TYPE, and copy that, in virtual format,
/* There is a fair number of calling conventions that are in somewhat
wide use. The 68000/08/10 don't support an FPU, not even as a
coprocessor. All function return values are stored in %d0/%d1.
Structures are returned in a static buffer, a pointer to which is
returned in %d0. This means that functions returning a structure
are not re-entrant. To avoid this problem some systems use a
convention where the caller passes a pointer to a buffer in %a1
where the return values is to be stored. This convention is the
default, and is implemented in the function m68k_return_value.
The 68020/030/040/060 do support an FPU, either as a coprocessor
(68881/2) or built-in (68040/68060). That's why System V release 4
(SVR4) instroduces a new calling convention specified by the SVR4
psABI. Integer values are returned in %d0/%d1, pointer return
values in %a0 and floating values in %fp0. When calling functions
returning a structure the caller should pass a pointer to a buffer
for the return value in %a0. This convention is implemented in the
function m68k_svr4_return_value, and by appropriately setting the
struct_value_regnum member of `struct gdbarch_tdep'.
GNU/Linux returns values in the same way as SVR4 does, but uses %a1
for passing the structure return value buffer.
GCC can also generate code where small structures are returned in
%d0/%d1 instead of in memory by using -freg-struct-return. This is
the default on NetBSD a.out, OpenBSD and GNU/Linux and several
embedded systems. This convention is implemented by setting the
struct_return member of `struct gdbarch_tdep' to reg_struct_return. */
/* Read a function return value of TYPE from REGCACHE, and copy that
into VALBUF. */
static void
@ -140,13 +169,6 @@ m68k_extract_return_value (struct type *type, struct regcache *regcache,
int len = TYPE_LENGTH (type);
char buf[M68K_MAX_REGISTER_SIZE];
if (TYPE_CODE (type) == TYPE_CODE_STRUCT
&& TYPE_NFIELDS (type) == 1)
{
m68k_extract_return_value (TYPE_FIELD_TYPE (type, 0), regcache, valbuf);
return;
}
if (len <= 4)
{
regcache_raw_read (regcache, M68K_D0_REGNUM, buf);
@ -164,8 +186,25 @@ m68k_extract_return_value (struct type *type, struct regcache *regcache,
"Cannot extract return value of %d bytes long.", len);
}
/* Write into the appropriate registers a function return value stored
in VALBUF of type TYPE, given in virtual format. */
static void
m68k_svr4_extract_return_value (struct type *type, struct regcache *regcache,
void *valbuf)
{
int len = TYPE_LENGTH (type);
char buf[M68K_MAX_REGISTER_SIZE];
if (TYPE_CODE (type) == TYPE_CODE_FLT)
{
regcache_raw_read (regcache, M68K_FP0_REGNUM, buf);
convert_typed_floating (buf, builtin_type_m68881_ext, valbuf, type);
}
else if (TYPE_CODE (type) == TYPE_CODE_PTR && len == 4)
regcache_raw_read (regcache, M68K_A0_REGNUM, valbuf);
else
m68k_extract_return_value (type, regcache, valbuf);
}
/* Write a function return value of TYPE from VALBUF into REGCACHE. */
static void
m68k_store_return_value (struct type *type, struct regcache *regcache,
@ -173,20 +212,13 @@ m68k_store_return_value (struct type *type, struct regcache *regcache,
{
int len = TYPE_LENGTH (type);
if (TYPE_CODE (type) == TYPE_CODE_STRUCT
&& TYPE_NFIELDS (type) == 1)
{
m68k_store_return_value (TYPE_FIELD_TYPE (type, 0), regcache, valbuf);
return;
}
if (len <= 4)
regcache_raw_write_part (regcache, M68K_D0_REGNUM, 4 - len, len, valbuf);
else if (len <= 8)
{
regcache_raw_write_part (regcache, M68K_D1_REGNUM, 8 - len,
regcache_raw_write_part (regcache, M68K_D0_REGNUM, 8 - len,
len - 4, valbuf);
regcache_raw_write (regcache, M68K_D0_REGNUM,
regcache_raw_write (regcache, M68K_D1_REGNUM,
(char *) valbuf + (len - 4));
}
else
@ -194,29 +226,108 @@ m68k_store_return_value (struct type *type, struct regcache *regcache,
"Cannot store return value of %d bytes long.", len);
}
/* Extract from REGCACHE, which contains the (raw) register state, the
address in which a function should return its structure value, as a
CORE_ADDR. */
static CORE_ADDR
m68k_extract_struct_value_address (struct regcache *regcache)
static void
m68k_svr4_store_return_value (struct type *type, struct regcache *regcache,
const void *valbuf)
{
char buf[4];
int len = TYPE_LENGTH (type);
regcache_cooked_read (regcache, M68K_D0_REGNUM, buf);
return extract_unsigned_integer (buf, 4);
if (TYPE_CODE (type) == TYPE_CODE_FLT)
{
char buf[M68K_MAX_REGISTER_SIZE];
convert_typed_floating (valbuf, type, buf, builtin_type_m68881_ext);
regcache_raw_write (regcache, M68K_FP0_REGNUM, buf);
}
else if (TYPE_CODE (type) == TYPE_CODE_PTR && len == 4)
{
regcache_raw_write (regcache, M68K_A0_REGNUM, valbuf);
regcache_raw_write (regcache, M68K_D0_REGNUM, valbuf);
}
else
m68k_store_return_value (type, regcache, valbuf);
}
/* Return non-zero if TYPE, which is assumed to be a structure or
union type, should be returned in registers for architecture
GDBARCH. */
static int
m68k_use_struct_convention (int gcc_p, struct type *type)
m68k_reg_struct_return_p (struct gdbarch *gdbarch, struct type *type)
{
enum struct_return struct_return;
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
enum type_code code = TYPE_CODE (type);
int len = TYPE_LENGTH (type);
struct_return = gdbarch_tdep (current_gdbarch)->struct_return;
return generic_use_struct_convention (struct_return == reg_struct_return,
type);
gdb_assert (code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION);
if (tdep->struct_return == pcc_struct_return)
return 0;
return (len == 1 || len == 2 || len == 4 || len == 8);
}
/* Determine, for architecture GDBARCH, how a return value of TYPE
should be returned. If it is supposed to be returned in registers,
and READBUF is non-zero, read the appropriate value from REGCACHE,
and copy it into READBUF. If WRITEBUF is non-zero, write the value
from WRITEBUF into REGCACHE. */
static enum return_value_convention
m68k_return_value (struct gdbarch *gdbarch, struct type *type,
struct regcache *regcache, void *readbuf,
const void *writebuf)
{
enum type_code code = TYPE_CODE (type);
if ((code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION)
&& !m68k_reg_struct_return_p (gdbarch, type))
return RETURN_VALUE_STRUCT_CONVENTION;
/* GCC returns a `long double' in memory. */
if (code == TYPE_CODE_FLT && TYPE_LENGTH (type) == 12)
return RETURN_VALUE_STRUCT_CONVENTION;
if (readbuf)
m68k_extract_return_value (type, regcache, readbuf);
if (writebuf)
m68k_store_return_value (type, regcache, writebuf);
return RETURN_VALUE_REGISTER_CONVENTION;
}
static enum return_value_convention
m68k_svr4_return_value (struct gdbarch *gdbarch, struct type *type,
struct regcache *regcache, void *readbuf,
const void *writebuf)
{
enum type_code code = TYPE_CODE (type);
if ((code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION)
&& !m68k_reg_struct_return_p (gdbarch, type))
return RETURN_VALUE_STRUCT_CONVENTION;
/* This special case is for structures consisting of a single
`float' or `double' member. These structures are returned in
%fp0. For these structures, we call ourselves recursively,
changing TYPE into the type of the first member of the structure.
Since that should work for all structures that have only one
member, we don't bother to check the member's type here. */
if (code == TYPE_CODE_STRUCT && TYPE_NFIELDS (type) == 1)
{
type = check_typedef (TYPE_FIELD_TYPE (type, 0));
return m68k_svr4_return_value (gdbarch, type, regcache,
readbuf, writebuf);
}
if (readbuf)
m68k_svr4_extract_return_value (type, regcache, readbuf);
if (writebuf)
m68k_svr4_store_return_value (type, regcache, writebuf);
return RETURN_VALUE_REGISTER_CONVENTION;
}
/* A function that tells us whether the function invocation represented
by fi does not have a frame on the stack associated with it. If it
does not, FRAMELESS is set to 1, else 0. */
@ -293,6 +404,7 @@ m68k_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
struct value **args, CORE_ADDR sp, int struct_return,
CORE_ADDR struct_addr)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
char buf[4];
int i;
@ -321,7 +433,7 @@ m68k_push_dummy_call (struct gdbarch *gdbarch, CORE_ADDR func_addr,
if (struct_return)
{
store_unsigned_integer (buf, 4, struct_addr);
regcache_cooked_write (regcache, M68K_A1_REGNUM, buf);
regcache_cooked_write (regcache, tdep->struct_value_regnum, buf);
}
/* Store return address. */
@ -952,6 +1064,22 @@ m68k_get_longjmp_target (CORE_ADDR *pc)
*pc = extract_unsigned_integer (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT);
return 1;
}
/* System V Release 4 (SVR4). */
void
m68k_svr4_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
/* SVR4 uses a different calling convention. */
set_gdbarch_return_value (gdbarch, m68k_svr4_return_value);
/* SVR4 uses %a0 instead of %a1. */
tdep->struct_value_regnum = M68K_A0_REGNUM;
}
/* Function: m68k_gdbarch_init
Initializer function for the m68k gdbarch vector.
@ -984,11 +1112,6 @@ m68k_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
set_gdbarch_believe_pcc_promotion (gdbarch, 1);
set_gdbarch_decr_pc_after_break (gdbarch, 2);
set_gdbarch_extract_return_value (gdbarch, m68k_extract_return_value);
set_gdbarch_store_return_value (gdbarch, m68k_store_return_value);
set_gdbarch_deprecated_extract_struct_value_address (gdbarch, m68k_extract_struct_value_address);
set_gdbarch_use_struct_convention (gdbarch, m68k_use_struct_convention);
set_gdbarch_deprecated_frameless_function_invocation (gdbarch, m68k_frameless_function_invocation);
set_gdbarch_frame_args_skip (gdbarch, 8);
@ -1002,6 +1125,7 @@ m68k_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
set_gdbarch_fp0_regnum (gdbarch, M68K_FP0_REGNUM);
set_gdbarch_push_dummy_call (gdbarch, m68k_push_dummy_call);
set_gdbarch_return_value (gdbarch, m68k_return_value);
/* Disassembler. */
set_gdbarch_print_insn (gdbarch, print_insn_m68k);
@ -1012,6 +1136,7 @@ m68k_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
#else
tdep->jb_pc = -1;
#endif
tdep->struct_value_regnum = M68K_A1_REGNUM;
tdep->struct_return = pcc_struct_return;
/* Frame unwinder. */

View File

@ -67,10 +67,18 @@ struct gdbarch_tdep
/* The size of each entry in the jump buffer. */
size_t jb_elt_size;
/* Register in which the address to store a structure value is
passed to a function. */
int struct_value_regnum;
/* Convention for returning structures. */
enum struct_return struct_return;
};
/* Initialize a SVR4 architecture variant. */
extern void m68k_svr4_init_abi (struct gdbarch_info, struct gdbarch *);
/* Functions exported from m68kbsd-tdep.c. */
extern int m68kbsd_fpreg_offset (int regnum);

View File

@ -1,7 +1,7 @@
/* Motorola m68k target-dependent support for GNU/Linux.
Copyright 1996, 1998, 2000, 2001, 2002, 2003 Free Software Foundation,
Inc.
Copyright 1996, 1998, 2000, 2001, 2002, 2003, 2004
Free Software Foundation, Inc.
This file is part of GDB.
@ -275,108 +275,6 @@ m68k_linux_sigtramp_frame_sniffer (struct frame_info *next_frame)
return NULL;
}
/* Extract from an array REGBUF containing the (raw) register state, a
function return value of TYPE, and copy that, in virtual format,
into VALBUF. */
static void
m68k_linux_extract_return_value (struct type *type, struct regcache *regcache,
void *valbuf)
{
int len = TYPE_LENGTH (type);
char buf[M68K_MAX_REGISTER_SIZE];
if (TYPE_CODE (type) == TYPE_CODE_STRUCT
&& TYPE_NFIELDS (type) == 1)
{
m68k_linux_extract_return_value (TYPE_FIELD_TYPE (type, 0), regcache,
valbuf);
return;
}
if (TYPE_CODE (type) == TYPE_CODE_FLT)
{
regcache_raw_read (regcache, M68K_FP0_REGNUM, buf);
convert_typed_floating (buf, builtin_type_m68881_ext, valbuf, type);
}
else if (TYPE_CODE (type) == TYPE_CODE_PTR)
regcache_raw_read (regcache, M68K_A0_REGNUM, valbuf);
else
{
if (len <= 4)
{
regcache_raw_read (regcache, M68K_D0_REGNUM, buf);
memcpy (valbuf, buf + (4 - len), len);
}
else if (len <= 8)
{
regcache_raw_read (regcache, M68K_D0_REGNUM, buf);
memcpy (valbuf, buf + (8 - len), len - 4);
regcache_raw_read (regcache, M68K_D1_REGNUM,
(char *) valbuf + (len - 4));
}
else
internal_error (__FILE__, __LINE__,
"Cannot extract return value of %d bytes long.", len);
}
}
/* Write into the appropriate registers a function return value stored
in VALBUF of type TYPE, given in virtual format. */
static void
m68k_linux_store_return_value (struct type *type, struct regcache *regcache,
const void *valbuf)
{
int len = TYPE_LENGTH (type);
if (TYPE_CODE (type) == TYPE_CODE_STRUCT
&& TYPE_NFIELDS (type) == 1)
{
m68k_linux_store_return_value (TYPE_FIELD_TYPE (type, 0), regcache,
valbuf);
return;
}
if (TYPE_CODE (type) == TYPE_CODE_FLT)
{
char buf[M68K_MAX_REGISTER_SIZE];
convert_typed_floating (valbuf, type, buf, builtin_type_m68881_ext);
regcache_raw_write (regcache, M68K_FP0_REGNUM, buf);
}
else if (TYPE_CODE (type) == TYPE_CODE_PTR)
regcache_raw_write (regcache, M68K_A0_REGNUM, valbuf);
else
{
if (len <= 4)
regcache_raw_write_part (regcache, M68K_D0_REGNUM,
4 - len, len, valbuf);
else if (len <= 8)
{
regcache_raw_write_part (regcache, M68K_D1_REGNUM, 8 - len,
len - 4, valbuf);
regcache_raw_write (regcache, M68K_D0_REGNUM,
(char *) valbuf + (len - 4));
}
else
internal_error (__FILE__, __LINE__,
"Cannot store return value of %d bytes long.", len);
}
}
/* Extract from an array REGBUF containing the (raw) register state
the address in which a function should return its structure value,
as a CORE_ADDR. */
static CORE_ADDR
m68k_linux_extract_struct_value_address (struct regcache *regcache)
{
char buf[4];
regcache_cooked_read (regcache, M68K_A0_REGNUM, buf);
return extract_unsigned_integer (buf, 4);
}
static void
m68k_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
{
@ -384,11 +282,15 @@ m68k_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
tdep->jb_pc = M68K_LINUX_JB_PC;
tdep->jb_elt_size = M68K_LINUX_JB_ELEMENT_SIZE;
tdep->struct_return = reg_struct_return;
set_gdbarch_extract_return_value (gdbarch, m68k_linux_extract_return_value);
set_gdbarch_store_return_value (gdbarch, m68k_linux_store_return_value);
set_gdbarch_deprecated_extract_struct_value_address (gdbarch, m68k_linux_extract_struct_value_address);
/* GNU/Linux uses a calling convention that's similar to SVR4. It
returns integer values in %d0/%di, pointer values in %a0 and
floating values in %fp0, just like SVR4, but uses %a1 to pass the
address to store a structure value. It also returns small
structures in registers instead of memory. */
m68k_svr4_init_abi (info, gdbarch);
tdep->struct_value_regnum = M68K_A1_REGNUM;
tdep->struct_return = reg_struct_return;
frame_unwind_append_sniffer (gdbarch, m68k_linux_sigtramp_frame_sniffer);