X-Git-Url: https://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fm68k-tdep.c;h=baad8039e2ba6156c77d68d956d4f96dafa96582;hb=refs%2Fheads%2Fgdb-11-branch-vfork-fixes-2022-01-17;hp=274ba61ea587e8952fb284d0617b18119ed0616d;hpb=ac7936dfd0c85e5de2dfec45ca0dbf72baeffa51;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/m68k-tdep.c b/gdb/m68k-tdep.c index 274ba61ea5..baad8039e2 100644 --- a/gdb/m68k-tdep.c +++ b/gdb/m68k-tdep.c @@ -1,6 +1,6 @@ /* Target-dependent code for the Motorola 68000 series. - Copyright (C) 1990-2017 Free Software Foundation, Inc. + Copyright (C) 1990-2022 Free Software Foundation, Inc. This file is part of GDB. @@ -18,7 +18,7 @@ along with this program. If not, see . */ #include "defs.h" -#include "dwarf2-frame.h" +#include "dwarf2/frame.h" #include "frame.h" #include "frame-base.h" #include "frame-unwind.h" @@ -33,6 +33,9 @@ #include "dis-asm.h" #include "target-descriptions.h" #include "floatformat.h" +#include "target-float.h" +#include "elf-bfd.h" +#include "elf/m68k.h" #include "m68k-tdep.h" @@ -154,7 +157,7 @@ m68k_register_type (struct gdbarch *gdbarch, int regnum) return builtin_type (gdbarch)->builtin_int32; } -static const char *m68k_register_names[] = { +static const char * const m68k_register_names[] = { "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "a0", "a1", "a2", "a3", "a4", "a5", "fp", "sp", "ps", "pc", @@ -190,7 +193,7 @@ m68k_convert_register_p (struct gdbarch *gdbarch, return 0; return (regnum >= M68K_FP0_REGNUM && regnum <= M68K_FP0_REGNUM + 7 /* We only support floating-point values. */ - && TYPE_CODE (type) == TYPE_CODE_FLT + && type->code () == TYPE_CODE_FLT && type != register_type (gdbarch, M68K_FP0_REGNUM)); } @@ -206,15 +209,17 @@ m68k_register_to_value (struct frame_info *frame, int regnum, gdb_byte from[M68K_MAX_REGISTER_SIZE]; struct type *fpreg_type = register_type (gdbarch, M68K_FP0_REGNUM); - gdb_assert (TYPE_CODE (type) == TYPE_CODE_FLT); + gdb_assert (type->code () == TYPE_CODE_FLT); /* Convert to TYPE. */ if (!get_frame_register_bytes (frame, regnum, 0, - register_size (gdbarch, regnum), - from, optimizedp, unavailablep)) + gdb::make_array_view (from, + register_size (gdbarch, + regnum)), + optimizedp, unavailablep)) return 0; - convert_typed_floating (from, fpreg_type, to, type); + target_float_convert (from, fpreg_type, to, type); *optimizedp = *unavailablep = 0; return 1; } @@ -231,7 +236,7 @@ m68k_value_to_register (struct frame_info *frame, int regnum, M68K_FP0_REGNUM); /* We only support floating-point values. */ - if (TYPE_CODE (type) != TYPE_CODE_FLT) + if (type->code () != TYPE_CODE_FLT) { warning (_("Cannot convert non-floating-point type " "to floating-point register value.")); @@ -239,7 +244,7 @@ m68k_value_to_register (struct frame_info *frame, int regnum, } /* Convert from TYPE. */ - convert_typed_floating (from, type, to, fpreg_type); + target_float_convert (from, type, to, fpreg_type); put_frame_register (frame, regnum, to); } @@ -256,7 +261,7 @@ m68k_value_to_register (struct frame_info *frame, int regnum, 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 + (SVR4) introduces 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 @@ -271,7 +276,12 @@ m68k_value_to_register (struct frame_info *frame, int regnum, %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. */ + struct_return member of `struct gdbarch_tdep' to reg_struct_return. + + GCC also has an "embedded" ABI. This works like the SVR4 ABI, + except that pointers are returned in %D0. This is implemented by + setting the pointer_result_regnum member of `struct gdbarch_tdep' + as appropriate. */ /* Read a function return value of TYPE from REGCACHE, and copy that into VALBUF. */ @@ -283,16 +293,22 @@ m68k_extract_return_value (struct type *type, struct regcache *regcache, int len = TYPE_LENGTH (type); gdb_byte buf[M68K_MAX_REGISTER_SIZE]; - if (len <= 4) + if (type->code () == TYPE_CODE_PTR && len == 4) + { + struct gdbarch *gdbarch = regcache->arch (); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + regcache->raw_read (tdep->pointer_result_regnum, valbuf); + } + else if (len <= 4) { - regcache_raw_read (regcache, M68K_D0_REGNUM, buf); + regcache->raw_read (M68K_D0_REGNUM, buf); memcpy (valbuf, buf + (4 - len), len); } else if (len <= 8) { - regcache_raw_read (regcache, M68K_D0_REGNUM, buf); + regcache->raw_read (M68K_D0_REGNUM, buf); memcpy (valbuf, buf + (8 - len), len - 4); - regcache_raw_read (regcache, M68K_D1_REGNUM, valbuf + (len - 4)); + regcache->raw_read (M68K_D1_REGNUM, valbuf + (len - 4)); } else internal_error (__FILE__, __LINE__, @@ -307,14 +323,12 @@ m68k_svr4_extract_return_value (struct type *type, struct regcache *regcache, struct gdbarch *gdbarch = regcache->arch (); struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - if (tdep->float_return && TYPE_CODE (type) == TYPE_CODE_FLT) + if (tdep->float_return && type->code () == TYPE_CODE_FLT) { struct type *fpreg_type = register_type (gdbarch, M68K_FP0_REGNUM); - regcache_raw_read (regcache, M68K_FP0_REGNUM, buf); - convert_typed_floating (buf, fpreg_type, valbuf, type); + regcache->raw_read (M68K_FP0_REGNUM, buf); + target_float_convert (buf, fpreg_type, valbuf, type); } - else if (TYPE_CODE (type) == TYPE_CODE_PTR && TYPE_LENGTH (type) == 4) - regcache_raw_read (regcache, M68K_A0_REGNUM, valbuf); else m68k_extract_return_value (type, regcache, valbuf); } @@ -327,13 +341,21 @@ m68k_store_return_value (struct type *type, struct regcache *regcache, { int len = TYPE_LENGTH (type); - if (len <= 4) - regcache_raw_write_part (regcache, M68K_D0_REGNUM, 4 - len, len, valbuf); + if (type->code () == TYPE_CODE_PTR && len == 4) + { + struct gdbarch *gdbarch = regcache->arch (); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + regcache->raw_write (tdep->pointer_result_regnum, valbuf); + /* gdb historically also set D0 in the SVR4 case. */ + if (tdep->pointer_result_regnum != M68K_D0_REGNUM) + regcache->raw_write (M68K_D0_REGNUM, valbuf); + } + else if (len <= 4) + regcache->raw_write_part (M68K_D0_REGNUM, 4 - len, len, valbuf); else if (len <= 8) { - regcache_raw_write_part (regcache, M68K_D0_REGNUM, 8 - len, - len - 4, valbuf); - regcache_raw_write (regcache, M68K_D1_REGNUM, valbuf + (len - 4)); + regcache->raw_write_part (M68K_D0_REGNUM, 8 - len, len - 4, valbuf); + regcache->raw_write (M68K_D1_REGNUM, valbuf + (len - 4)); } else internal_error (__FILE__, __LINE__, @@ -347,17 +369,12 @@ m68k_svr4_store_return_value (struct type *type, struct regcache *regcache, struct gdbarch *gdbarch = regcache->arch (); struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - if (tdep->float_return && TYPE_CODE (type) == TYPE_CODE_FLT) + if (tdep->float_return && type->code () == TYPE_CODE_FLT) { struct type *fpreg_type = register_type (gdbarch, M68K_FP0_REGNUM); gdb_byte buf[M68K_MAX_REGISTER_SIZE]; - convert_typed_floating (valbuf, type, buf, fpreg_type); - regcache_raw_write (regcache, M68K_FP0_REGNUM, buf); - } - else if (TYPE_CODE (type) == TYPE_CODE_PTR && TYPE_LENGTH (type) == 4) - { - regcache_raw_write (regcache, M68K_A0_REGNUM, valbuf); - regcache_raw_write (regcache, M68K_D0_REGNUM, valbuf); + target_float_convert (valbuf, type, buf, fpreg_type); + regcache->raw_write (M68K_FP0_REGNUM, buf); } else m68k_store_return_value (type, regcache, valbuf); @@ -371,15 +388,32 @@ static int m68k_reg_struct_return_p (struct gdbarch *gdbarch, struct type *type) { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - enum type_code code = TYPE_CODE (type); + enum type_code code = type->code (); int len = TYPE_LENGTH (type); gdb_assert (code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION - || code == TYPE_CODE_COMPLEX); + || code == TYPE_CODE_COMPLEX || code == TYPE_CODE_ARRAY); if (tdep->struct_return == pcc_struct_return) return 0; + const bool is_vector = code == TYPE_CODE_ARRAY && type->is_vector (); + + if (is_vector + && check_typedef (TYPE_TARGET_TYPE (type))->code () == TYPE_CODE_FLT) + return 0; + + /* According to m68k_return_in_memory in the m68k GCC back-end, + strange things happen for small aggregate types. Aggregate types + with only one component are always returned like the type of the + component. Aggregate types whose size is 2, 4, or 8 are returned + in registers if their natural alignment is at least 16 bits. + + We reject vectors here, as experimentally this gives the correct + answer. */ + if (!is_vector && (len == 2 || len == 4 || len == 8)) + return type_align (type) >= 2; + return (len == 1 || len == 2 || len == 4 || len == 8); } @@ -394,17 +428,17 @@ m68k_return_value (struct gdbarch *gdbarch, struct value *function, struct type *type, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf) { - enum type_code code = TYPE_CODE (type); + enum type_code code = type->code (); /* GCC returns a `long double' in memory too. */ if (((code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION - || code == TYPE_CODE_COMPLEX) + || code == TYPE_CODE_COMPLEX || code == TYPE_CODE_ARRAY) && !m68k_reg_struct_return_p (gdbarch, type)) || (code == TYPE_CODE_FLT && TYPE_LENGTH (type) == 12)) { /* The default on m68k is to return structures in static memory. - Consequently a function must return the address where we can - find the return value. */ + Consequently a function must return the address where we can + find the return value. */ if (readbuf) { @@ -430,11 +464,25 @@ m68k_svr4_return_value (struct gdbarch *gdbarch, struct value *function, struct type *type, struct regcache *regcache, gdb_byte *readbuf, const gdb_byte *writebuf) { - enum type_code code = TYPE_CODE (type); + enum type_code code = type->code (); + + /* Aggregates with a single member are always returned like their + sole element. */ + if ((code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION) + && type->num_fields () == 1) + { + type = check_typedef (type->field (0).type ()); + return m68k_svr4_return_value (gdbarch, function, type, regcache, + readbuf, writebuf); + } - if ((code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION - || code == TYPE_CODE_COMPLEX) - && !m68k_reg_struct_return_p (gdbarch, type)) + if (((code == TYPE_CODE_STRUCT || code == TYPE_CODE_UNION + || code == TYPE_CODE_COMPLEX || code == TYPE_CODE_ARRAY) + && !m68k_reg_struct_return_p (gdbarch, type)) + /* GCC may return a `long double' in memory too. */ + || (!gdbarch_tdep (gdbarch)->float_return + && code == TYPE_CODE_FLT + && TYPE_LENGTH (type) == 12)) { /* The System V ABI says that: @@ -444,32 +492,25 @@ m68k_svr4_return_value (struct gdbarch *gdbarch, struct value *function, register %a0." So the ABI guarantees that we can always find the return - value just after the function has returned. */ + value just after the function has returned. + + However, GCC also implements the "embedded" ABI. That ABI + does not preserve %a0 across calls, but does write the value + back to %d0. */ if (readbuf) { + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); ULONGEST addr; - regcache_raw_read_unsigned (regcache, M68K_A0_REGNUM, &addr); + regcache_raw_read_unsigned (regcache, tdep->pointer_result_regnum, + &addr); read_memory (addr, readbuf, TYPE_LENGTH (type)); } return RETURN_VALUE_ABI_RETURNS_ADDRESS; } - /* 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, function, type, regcache, - readbuf, writebuf); - } - if (readbuf) m68k_svr4_extract_return_value (type, regcache, readbuf); if (writebuf) @@ -492,7 +533,8 @@ m68k_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp) static CORE_ADDR m68k_push_dummy_call (struct gdbarch *gdbarch, struct value *function, struct regcache *regcache, CORE_ADDR bp_addr, int nargs, - struct value **args, CORE_ADDR sp, int struct_return, + struct value **args, CORE_ADDR sp, + function_call_return_method return_method, CORE_ADDR struct_addr) { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); @@ -510,9 +552,9 @@ m68k_push_dummy_call (struct gdbarch *gdbarch, struct value *function, /* Non-scalars bigger than 4 bytes are left aligned, others are right aligned. */ - if ((TYPE_CODE (value_type) == TYPE_CODE_STRUCT - || TYPE_CODE (value_type) == TYPE_CODE_UNION - || TYPE_CODE (value_type) == TYPE_CODE_ARRAY) + if ((value_type->code () == TYPE_CODE_STRUCT + || value_type->code () == TYPE_CODE_UNION + || value_type->code () == TYPE_CODE_ARRAY) && len > 4) offset = 0; else @@ -522,10 +564,10 @@ m68k_push_dummy_call (struct gdbarch *gdbarch, struct value *function, } /* Store struct value address. */ - if (struct_return) + if (return_method == return_method_struct) { store_unsigned_integer (buf, 4, byte_order, struct_addr); - regcache_cooked_write (regcache, tdep->struct_value_regnum, buf); + regcache->cooked_write (tdep->struct_value_regnum, buf); } /* Store return address. */ @@ -535,10 +577,10 @@ m68k_push_dummy_call (struct gdbarch *gdbarch, struct value *function, /* Finally, update the stack pointer... */ store_unsigned_integer (buf, 4, byte_order, sp); - regcache_cooked_write (regcache, M68K_SP_REGNUM, buf); + regcache->cooked_write (M68K_SP_REGNUM, buf); /* ...and fake a frame pointer. */ - regcache_cooked_write (regcache, M68K_FP_REGNUM, buf); + regcache->cooked_write (M68K_FP_REGNUM, buf); /* DWARF2/GCC uses the stack address *before* the function call as a frame's CFA. */ @@ -961,6 +1003,7 @@ m68k_frame_prev_register (struct frame_info *this_frame, void **this_cache, static const struct frame_unwind m68k_frame_unwind = { + "m68k prologue", NORMAL_FRAME, default_frame_unwind_stop_reason, m68k_frame_this_id, @@ -1061,7 +1104,23 @@ m68k_svr4_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) /* SVR4 uses %a0 instead of %a1. */ tdep->struct_value_regnum = M68K_A0_REGNUM; + + /* SVR4 returns pointers in %a0. */ + tdep->pointer_result_regnum = M68K_A0_REGNUM; } + +/* GCC's m68k "embedded" ABI. This is like the SVR4 ABI, but pointer + values are returned in %d0, not %a0. */ + +static void +m68k_embedded_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + m68k_svr4_init_abi (info, gdbarch); + tdep->pointer_result_regnum = M68K_D0_REGNUM; +} + /* Function: m68k_gdbarch_init @@ -1074,7 +1133,7 @@ m68k_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) struct gdbarch_tdep *tdep = NULL; struct gdbarch *gdbarch; struct gdbarch_list *best_arch; - struct tdesc_arch_data *tdesc_data = NULL; + tdesc_arch_data_up tdesc_data; int i; enum m68k_flavour flavour = m68k_no_flavour; int has_fp = 1; @@ -1112,14 +1171,11 @@ m68k_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) valid_p = 1; for (i = 0; i <= M68K_PC_REGNUM; i++) - valid_p &= tdesc_numbered_register (feature, tdesc_data, i, + valid_p &= tdesc_numbered_register (feature, tdesc_data.get (), i, m68k_register_names[i]); if (!valid_p) - { - tdesc_data_cleanup (tdesc_data); - return NULL; - } + return NULL; feature = tdesc_find_feature (info.target_desc, "org.gnu.gdb.coldfire.fp"); @@ -1127,13 +1183,10 @@ m68k_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) { valid_p = 1; for (i = M68K_FP0_REGNUM; i <= M68K_FPI_REGNUM; i++) - valid_p &= tdesc_numbered_register (feature, tdesc_data, i, + valid_p &= tdesc_numbered_register (feature, tdesc_data.get (), i, m68k_register_names[i]); if (!valid_p) - { - tdesc_data_cleanup (tdesc_data); - return NULL; - } + return NULL; } else has_fp = 0; @@ -1154,6 +1207,24 @@ m68k_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) flavour = m68k_coldfire_flavour; } + /* Try to figure out if the arch uses floating registers to return + floating point values from functions. On ColdFire, floating + point values are returned in D0. */ + int float_return = 0; + if (has_fp && flavour != m68k_coldfire_flavour) + float_return = 1; +#ifdef HAVE_ELF + if (info.abfd && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour) + { + int fp_abi = bfd_elf_get_obj_attr_int (info.abfd, OBJ_ATTR_GNU, + Tag_GNU_M68K_ABI_FP); + if (fp_abi == 1) + float_return = 1; + else if (fp_abi == 2) + float_return = 0; + } +#endif /* HAVE_ELF */ + /* If there is already a candidate, use it. */ for (best_arch = gdbarch_list_lookup_by_info (arches, &info); best_arch != NULL; @@ -1165,19 +1236,19 @@ m68k_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) if (has_fp != gdbarch_tdep (best_arch->gdbarch)->fpregs_present) continue; + if (float_return != gdbarch_tdep (best_arch->gdbarch)->float_return) + continue; + break; } if (best_arch != NULL) - { - if (tdesc_data != NULL) - tdesc_data_cleanup (tdesc_data); - return best_arch->gdbarch; - } + return best_arch->gdbarch; tdep = XCNEW (struct gdbarch_tdep); gdbarch = gdbarch_alloc (&info, tdep); tdep->fpregs_present = has_fp; + tdep->float_return = float_return; tdep->flavour = flavour; if (flavour == m68k_coldfire_flavour || flavour == m68k_fido_flavour) @@ -1213,22 +1284,6 @@ m68k_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) if (has_fp) set_gdbarch_fp0_regnum (gdbarch, M68K_FP0_REGNUM); - /* Try to figure out if the arch uses floating registers to return - floating point values from functions. */ - if (has_fp) - { - /* On ColdFire, floating point values are returned in D0. */ - if (flavour == m68k_coldfire_flavour) - tdep->float_return = 0; - else - tdep->float_return = 1; - } - else - { - /* No floating registers, so can't use them for returning values. */ - tdep->float_return = 0; - } - /* Function call & return. */ set_gdbarch_push_dummy_call (gdbarch, m68k_push_dummy_call); set_gdbarch_return_value (gdbarch, m68k_return_value); @@ -1241,6 +1296,7 @@ m68k_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) #else tdep->jb_pc = -1; #endif + tdep->pointer_result_regnum = M68K_D0_REGNUM; tdep->struct_value_regnum = M68K_A1_REGNUM; tdep->struct_return = reg_struct_return; @@ -1264,8 +1320,8 @@ m68k_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) frame_unwind_append_unwinder (gdbarch, &m68k_frame_unwind); - if (tdesc_data) - tdesc_use_registers (gdbarch, info.target_desc, tdesc_data); + if (tdesc_data != nullptr) + tdesc_use_registers (gdbarch, info.target_desc, std::move (tdesc_data)); return gdbarch; } @@ -1280,8 +1336,27 @@ m68k_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file) return; } +/* OSABI sniffer for m68k. */ + +static enum gdb_osabi +m68k_osabi_sniffer (bfd *abfd) +{ + unsigned int elfosabi = elf_elfheader (abfd)->e_ident[EI_OSABI]; + + if (elfosabi == ELFOSABI_NONE) + return GDB_OSABI_SVR4; + + return GDB_OSABI_UNKNOWN; +} + +void _initialize_m68k_tdep (); void -_initialize_m68k_tdep (void) +_initialize_m68k_tdep () { gdbarch_register (bfd_arch_m68k, m68k_gdbarch_init, m68k_dump_tdep); + + gdbarch_register_osabi_sniffer (bfd_arch_m68k, bfd_target_elf_flavour, + m68k_osabi_sniffer); + gdbarch_register_osabi (bfd_arch_m68k, 0, GDB_OSABI_SVR4, + m68k_embedded_init_abi); }