diff options
Diffstat (limited to 'gdb/v850-tdep.c')
-rw-r--r-- | gdb/v850-tdep.c | 157 |
1 files changed, 134 insertions, 23 deletions
diff --git a/gdb/v850-tdep.c b/gdb/v850-tdep.c index e1869d0..3752dce 100644 --- a/gdb/v850-tdep.c +++ b/gdb/v850-tdep.c @@ -21,7 +21,6 @@ #include "defs.h" #include "frame.h" #include "inferior.h" -#include "obstack.h" #include "target.h" #include "value.h" #include "bfd.h" @@ -123,6 +122,12 @@ enum E_ALL_REGS_SIZE = (E_NUM_REGS) * v850_reg_size }; +/* Size of return datatype which fits into all return registers. */ +enum +{ + E_MAX_RETTYPE_SIZE_IN_REGS = 2 * v850_reg_size +}; + static LONGEST call_dummy_nil[] = {0}; static char *v850_generic_reg_names[] = @@ -199,7 +204,7 @@ static CORE_ADDR v850_scan_prologue (CORE_ADDR pc, struct prologue_info *fs); /* Function: v850_register_name Returns the name of the v850/v850e register N. */ -static char * +static const char * v850_register_name (int regnum) { if (regnum < 0 || regnum >= E_NUM_REGS) @@ -266,11 +271,90 @@ v850_reg_virtual_type (int regnum) return builtin_type_int32; } +static int +v850_type_is_scalar (struct type *t) +{ + return (TYPE_CODE (t) != TYPE_CODE_STRUCT + && TYPE_CODE (t) != TYPE_CODE_UNION + && TYPE_CODE (t) != TYPE_CODE_ARRAY); +} + /* Should call_function allocate stack space for a struct return? */ -int +static int v850_use_struct_convention (int gcc_p, struct type *type) { - return (TYPE_NFIELDS (type) > 1 || TYPE_LENGTH (type) > 4); + /* According to ABI: + * return TYPE_LENGTH (type) > 8); + */ + + /* Current implementation in gcc: */ + + int i; + struct type *fld_type, *tgt_type; + + /* 1. The value is greater than 8 bytes -> returned by copying */ + if (TYPE_LENGTH (type) > 8) + return 1; + + /* 2. The value is a single basic type -> returned in register */ + if (v850_type_is_scalar (type)) + return 0; + + /* The value is a structure or union with a single element + * and that element is either a single basic type or an array of + * a single basic type whoes size is greater than or equal to 4 + * -> returned in register */ + if ((TYPE_CODE (type) == TYPE_CODE_STRUCT + || TYPE_CODE (type) == TYPE_CODE_UNION) + && TYPE_NFIELDS (type) == 1) + { + fld_type = TYPE_FIELD_TYPE (type, 0); + if (v850_type_is_scalar (fld_type) && TYPE_LENGTH (fld_type) >= 4) + return 0; + + if (TYPE_CODE (fld_type) == TYPE_CODE_ARRAY) + { + tgt_type = TYPE_TARGET_TYPE (fld_type); + if (v850_type_is_scalar (tgt_type) && TYPE_LENGTH (tgt_type) >= 4) + return 0; + } + } + + /* The value is a structure whose first element is an integer or + * a float, and which contains no arrays of more than two elements + * -> returned in register */ + if (TYPE_CODE (type) == TYPE_CODE_STRUCT + && v850_type_is_scalar (TYPE_FIELD_TYPE (type, 0)) + && TYPE_LENGTH (TYPE_FIELD_TYPE (type, 0)) == 4) + { + for (i = 1; i < TYPE_NFIELDS (type); ++i) + { + fld_type = TYPE_FIELD_TYPE (type, 0); + if (TYPE_CODE (fld_type) == TYPE_CODE_ARRAY) + { + tgt_type = TYPE_TARGET_TYPE (fld_type); + if (TYPE_LENGTH (fld_type) >= 0 && TYPE_LENGTH (tgt_type) >= 0 + && TYPE_LENGTH (fld_type) / TYPE_LENGTH (tgt_type) > 2) + return 1; + } + } + return 0; + } + + /* The value is a union which contains at least one field which + * would be returned in registers according to these rules + * -> returned in register */ + if (TYPE_CODE (type) == TYPE_CODE_UNION) + { + for (i = 0; i < TYPE_NFIELDS (type); ++i) + { + fld_type = TYPE_FIELD_TYPE (type, 0); + if (!v850_use_struct_convention (0, fld_type)) + return 0; + } + } + + return 1; } @@ -844,22 +928,22 @@ v850_push_arguments (int nargs, struct value **args, CORE_ADDR sp, /* First, just for safety, make sure stack is aligned */ sp &= ~3; + /* The offset onto the stack at which we will start copying parameters + (after the registers are used up) begins at 16 rather than at zero. + I don't really know why, that's just the way it seems to work. */ + stack_offset = 16; + /* Now make space on the stack for the args. */ for (argnum = 0; argnum < nargs; argnum++) len += ((TYPE_LENGTH (VALUE_TYPE (args[argnum])) + 3) & ~3); - sp -= len; /* possibly over-allocating, but it works... */ + sp -= len + stack_offset; /* possibly over-allocating, but it works... */ /* (you might think we could allocate 16 bytes */ /* less, but the ABI seems to use it all! ) */ - argreg = E_ARG0_REGNUM; + argreg = E_ARG0_REGNUM; /* the struct_return pointer occupies the first parameter-passing reg */ if (struct_return) - write_register (argreg++, struct_addr); - - stack_offset = 16; - /* The offset onto the stack at which we will start copying parameters - (after the registers are used up) begins at 16 rather than at zero. - I don't really know why, that's just the way it seems to work. */ + argreg++; /* Now load as many as possible of the first arguments into registers, and push the rest onto the stack. There are 16 bytes @@ -870,8 +954,8 @@ v850_push_arguments (int nargs, struct value **args, CORE_ADDR sp, char *val; char valbuf[v850_register_raw_size (E_ARG0_REGNUM)]; - if (TYPE_CODE (VALUE_TYPE (*args)) == TYPE_CODE_STRUCT - && TYPE_LENGTH (VALUE_TYPE (*args)) > 8) + if (!v850_type_is_scalar (VALUE_TYPE (*args)) + && TYPE_LENGTH (VALUE_TYPE (*args)) > E_MAX_RETTYPE_SIZE_IN_REGS) { store_address (valbuf, 4, VALUE_ADDRESS (*args)); len = 4; @@ -966,8 +1050,26 @@ v850_saved_pc_after_call (struct frame_info *ignore) static void v850_extract_return_value (struct type *type, char *regbuf, char *valbuf) { - memcpy (valbuf, regbuf + v850_register_byte (E_V0_REGNUM), - TYPE_LENGTH (type)); + CORE_ADDR return_buffer; + + if (!v850_use_struct_convention (0, type)) + { + /* Scalar return values of <= 8 bytes are returned in + E_V0_REGNUM to E_V1_REGNUM. */ + memcpy (valbuf, + ®buf[REGISTER_BYTE (E_V0_REGNUM)], + TYPE_LENGTH (type)); + } + else + { + /* Aggregates and return values > 8 bytes are returned in memory, + pointed to by R6. */ + return_buffer = + extract_address (regbuf + REGISTER_BYTE (E_V0_REGNUM), + REGISTER_RAW_SIZE (E_V0_REGNUM)); + + read_memory (return_buffer, valbuf, TYPE_LENGTH (type)); + } } const static unsigned char * @@ -988,8 +1090,16 @@ v850_extract_struct_value_address (char *regbuf) static void v850_store_return_value (struct type *type, char *valbuf) { - write_register_bytes(v850_register_byte (E_V0_REGNUM), valbuf, - TYPE_LENGTH (type)); + CORE_ADDR return_buffer; + + if (!v850_use_struct_convention (0, type)) + write_register_bytes (REGISTER_BYTE (E_V0_REGNUM), valbuf, + TYPE_LENGTH (type)); + else + { + return_buffer = read_register (E_V0_REGNUM); + write_memory (return_buffer, valbuf, TYPE_LENGTH (type)); + } } static void @@ -1057,8 +1167,9 @@ v850_init_extra_frame_info (int fromleaf, struct frame_info *fi) } static void -v850_store_struct_return (CORE_ADDR a, CORE_ADDR b) +v850_store_struct_return (CORE_ADDR addr, CORE_ADDR sp) { + write_register (E_ARG0_REGNUM, addr); } static CORE_ADDR @@ -1126,7 +1237,7 @@ v850_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_init_extra_frame_info (gdbarch, v850_init_extra_frame_info); set_gdbarch_frame_init_saved_regs (gdbarch, v850_frame_init_saved_regs); set_gdbarch_frame_chain (gdbarch, v850_frame_chain); - set_gdbarch_get_saved_register (gdbarch, generic_get_saved_register); + set_gdbarch_get_saved_register (gdbarch, generic_unwind_get_saved_register); set_gdbarch_saved_pc_after_call (gdbarch, v850_saved_pc_after_call); set_gdbarch_frame_saved_pc (gdbarch, v850_frame_saved_pc); set_gdbarch_skip_prologue (gdbarch, v850_skip_prologue); @@ -1158,12 +1269,12 @@ v850_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_use_generic_dummy_frames (gdbarch, 1); set_gdbarch_push_dummy_frame (gdbarch, generic_push_dummy_frame); set_gdbarch_push_return_address (gdbarch, v850_push_return_address); - set_gdbarch_extract_return_value (gdbarch, v850_extract_return_value); + set_gdbarch_deprecated_extract_return_value (gdbarch, v850_extract_return_value); set_gdbarch_push_arguments (gdbarch, v850_push_arguments); set_gdbarch_pop_frame (gdbarch, v850_pop_frame); set_gdbarch_store_struct_return (gdbarch, v850_store_struct_return); - set_gdbarch_store_return_value (gdbarch, v850_store_return_value); - set_gdbarch_extract_struct_value_address (gdbarch, v850_extract_struct_value_address); + set_gdbarch_deprecated_store_return_value (gdbarch, v850_store_return_value); + set_gdbarch_deprecated_extract_struct_value_address (gdbarch, v850_extract_struct_value_address); set_gdbarch_use_struct_convention (gdbarch, v850_use_struct_convention); set_gdbarch_call_dummy_location (gdbarch, AT_ENTRY_POINT); set_gdbarch_call_dummy_address (gdbarch, entry_point_address); |