X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Friscv-tdep.c;h=9b06f7c08d3552da40f6b626aaaf0e19cd14055f;hb=389fe8647555af73fca362bb066786b8cfe52761;hp=704e8512b3daac2eb80748a289b0e779ecf9f36d;hpb=ecc82c059059cfa21a8a099779253686f9637f9f;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/riscv-tdep.c b/gdb/riscv-tdep.c index 704e8512b3..9b06f7c08d 100644 --- a/gdb/riscv-tdep.c +++ b/gdb/riscv-tdep.c @@ -1,6 +1,6 @@ /* Target-dependent code for the RISC-V architecture, for GDB. - Copyright (C) 2018 Free Software Foundation, Inc. + Copyright (C) 2018-2020 Free Software Foundation, Inc. This file is part of GDB. @@ -50,12 +50,13 @@ #include "dwarf2-frame.h" #include "user-regs.h" #include "valprint.h" -#include "common-defs.h" +#include "gdbsupport/common-defs.h" #include "opcode/riscv-opc.h" #include "cli/cli-decode.h" #include "observable.h" #include "prologue-value.h" #include "arch/riscv.h" +#include "riscv-ravenscar-thread.h" /* The stack must be 16-byte aligned. */ #define SP_ALIGNMENT 16 @@ -185,7 +186,7 @@ static const struct riscv_register_feature riscv_freg_feature = { RISCV_FIRST_FP_REGNUM + 5, { "ft5", "f5" }, true }, { RISCV_FIRST_FP_REGNUM + 6, { "ft6", "f6" }, true }, { RISCV_FIRST_FP_REGNUM + 7, { "ft7", "f7" }, true }, - { RISCV_FIRST_FP_REGNUM + 8, { "fs0", "f8", "s0" }, true }, + { RISCV_FIRST_FP_REGNUM + 8, { "fs0", "f8" }, true }, { RISCV_FIRST_FP_REGNUM + 9, { "fs1", "f9" }, true }, { RISCV_FIRST_FP_REGNUM + 10, { "fa0", "f10" }, true }, { RISCV_FIRST_FP_REGNUM + 11, { "fa1", "f11" }, true }, @@ -361,7 +362,15 @@ static unsigned int riscv_debug_gdbarch = 0; int riscv_isa_xlen (struct gdbarch *gdbarch) { - return gdbarch_tdep (gdbarch)->features.xlen; + return gdbarch_tdep (gdbarch)->isa_features.xlen; +} + +/* See riscv-tdep.h. */ + +int +riscv_abi_xlen (struct gdbarch *gdbarch) +{ + return gdbarch_tdep (gdbarch)->abi_features.xlen; } /* See riscv-tdep.h. */ @@ -369,7 +378,15 @@ riscv_isa_xlen (struct gdbarch *gdbarch) int riscv_isa_flen (struct gdbarch *gdbarch) { - return gdbarch_tdep (gdbarch)->features.flen; + return gdbarch_tdep (gdbarch)->isa_features.flen; +} + +/* See riscv-tdep.h. */ + +int +riscv_abi_flen (struct gdbarch *gdbarch) +{ + return gdbarch_tdep (gdbarch)->abi_features.flen; } /* Return true if the target for GDBARCH has floating point hardware. */ @@ -385,7 +402,7 @@ riscv_has_fp_regs (struct gdbarch *gdbarch) static bool riscv_has_fp_abi (struct gdbarch *gdbarch) { - return gdbarch_tdep (gdbarch)->features.hw_float_abi; + return gdbarch_tdep (gdbarch)->abi_features.flen > 0; } /* Return true if REGNO is a floating pointer register. */ @@ -414,7 +431,15 @@ riscv_breakpoint_kind_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr) unaligned_p = true; else { - /* Read the opcode byte to determine the instruction length. */ + /* Read the opcode byte to determine the instruction length. If + the read fails this may be because we tried to set the + breakpoint at an invalid address, in this case we provide a + fake result which will give a breakpoint length of 4. + Hopefully when we try to actually insert the breakpoint we + will see a failure then too which will be reported to the + user. */ + if (target_read_code (*pcptr, buf, 1) == -1) + buf[0] = 0; read_code (*pcptr, buf, 1); } @@ -635,19 +660,18 @@ riscv_print_one_register_info (struct gdbarch *gdbarch, fputs_filtered (name, file); print_spaces_filtered (value_column_1 - strlen (name), file); - TRY + try { val = value_of_register (regnum, frame); regtype = value_type (val); } - CATCH (ex, RETURN_MASK_ERROR) + catch (const gdb_exception_error &ex) { /* Handle failure to read a register without interrupting the entire 'info registers' flow. */ - fprintf_filtered (file, "%s\n", ex.message); + fprintf_filtered (file, "%s\n", ex.what ()); return; } - END_CATCH print_raw_format = (value_entirely_available (val) && !value_optimized_out (val)); @@ -665,7 +689,7 @@ riscv_print_one_register_info (struct gdbarch *gdbarch, { struct value_print_options opts; const gdb_byte *valaddr = value_contents_for_printing (val); - enum bfd_endian byte_order = gdbarch_byte_order (get_type_arch (regtype)); + enum bfd_endian byte_order = type_byte_order (regtype); get_user_print_options (&opts); opts.deref_ref = 1; @@ -987,7 +1011,7 @@ public: LUI, SD, SW, - /* These are needed for software breakopint support. */ + /* These are needed for software breakpoint support. */ JAL, JALR, BEQ, @@ -1362,10 +1386,12 @@ riscv_insn::decode (struct gdbarch *gdbarch, CORE_ADDR pc) m_opcode = OTHER; } else - internal_error (__FILE__, __LINE__, - _("unable to decode %d byte instructions in " - "prologue at %s"), m_length, - core_addr_to_string (pc)); + { + /* This must be a 6 or 8 byte instruction, we don't currently decode + any of these, so just ignore it. */ + gdb_assert (m_length == 6 || m_length == 8); + m_opcode = OTHER; + } } /* The prologue scanner. This is currently only used for skipping the @@ -1596,62 +1622,59 @@ riscv_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp, struct type *value_type, CORE_ADDR *real_pc, CORE_ADDR *bp_addr, struct regcache *regcache) { + /* A nop instruction is 'add x0, x0, 0'. */ + static const gdb_byte nop_insn[] = { 0x13, 0x00, 0x00, 0x00 }; + /* Allocate space for a breakpoint, and keep the stack correctly - aligned. */ + aligned. The space allocated here must be at least big enough to + accommodate the NOP_INSN defined above. */ sp -= 16; *bp_addr = sp; *real_pc = funaddr; + + /* When we insert a breakpoint we select whether to use a compressed + breakpoint or not based on the existing contents of the memory. + + If the breakpoint is being placed onto the stack as part of setting up + for an inferior call from GDB, then the existing stack contents may + randomly appear to be a compressed instruction, causing GDB to insert + a compressed breakpoint. If this happens on a target that does not + support compressed instructions then this could cause problems. + + To prevent this issue we write an uncompressed nop onto the stack at + the location where the breakpoint will be inserted. In this way we + ensure that we always use an uncompressed breakpoint, which should + work on all targets. + + We call TARGET_WRITE_MEMORY here so that if the write fails we don't + throw an exception. Instead we ignore the error and move on. The + assumption is that either GDB will error later when actually trying to + insert a software breakpoint, or GDB will use hardware breakpoints and + there will be no need to write to memory later. */ + int status = target_write_memory (*bp_addr, nop_insn, sizeof (nop_insn)); + + if (riscv_debug_breakpoints || riscv_debug_infcall) + fprintf_unfiltered (gdb_stdlog, + "Writing %s-byte nop instruction to %s: %s\n", + plongest (sizeof (nop_insn)), + paddress (gdbarch, *bp_addr), + (status == 0 ? "success" : "failed")); + return sp; } -/* Compute the alignment of the type T. Used while setting up the - arguments for a dummy call. */ +/* Implement the gdbarch type alignment method, overrides the generic + alignment algorithm for anything that is RISC-V specific. */ -static int -riscv_type_alignment (struct type *t) +static ULONGEST +riscv_type_align (gdbarch *gdbarch, type *type) { - t = check_typedef (t); - switch (TYPE_CODE (t)) - { - default: - error (_("Could not compute alignment of type")); - - case TYPE_CODE_RVALUE_REF: - case TYPE_CODE_PTR: - case TYPE_CODE_ENUM: - case TYPE_CODE_INT: - case TYPE_CODE_FLT: - case TYPE_CODE_REF: - case TYPE_CODE_CHAR: - case TYPE_CODE_BOOL: - return TYPE_LENGTH (t); - - case TYPE_CODE_ARRAY: - if (TYPE_VECTOR (t)) - return std::min (TYPE_LENGTH (t), (unsigned) BIGGEST_ALIGNMENT); - /* FALLTHROUGH */ - - case TYPE_CODE_COMPLEX: - return riscv_type_alignment (TYPE_TARGET_TYPE (t)); - - case TYPE_CODE_STRUCT: - case TYPE_CODE_UNION: - { - int i; - int align = 1; + type = check_typedef (type); + if (TYPE_CODE (type) == TYPE_CODE_ARRAY && TYPE_VECTOR (type)) + return std::min (TYPE_LENGTH (type), (ULONGEST) BIGGEST_ALIGNMENT); - for (i = 0; i < TYPE_NFIELDS (t); ++i) - { - if (TYPE_FIELD_LOC_KIND (t, i) == FIELD_LOC_KIND_BITPOS) - { - int a = riscv_type_alignment (TYPE_FIELD_TYPE (t, i)); - if (a > align) - align = a; - } - } - return align; - } - } + /* Anything else will be aligned by the generic code. */ + return 0; } /* Holds information about a single argument either being passed to an @@ -1786,8 +1809,8 @@ struct riscv_call_info : int_regs (RISCV_A0_REGNUM, RISCV_A0_REGNUM + 7), float_regs (RISCV_FA0_REGNUM, RISCV_FA0_REGNUM + 7) { - xlen = riscv_isa_xlen (gdbarch); - flen = riscv_isa_flen (gdbarch); + xlen = riscv_abi_xlen (gdbarch); + flen = riscv_abi_flen (gdbarch); /* Disable use of floating point registers if needed. */ if (!riscv_has_fp_abi (gdbarch)) @@ -1807,7 +1830,7 @@ struct riscv_call_info struct riscv_arg_reg float_regs; /* The XLEN and FLEN are copied in to this structure for convenience, and - are just the results of calling RISCV_ISA_XLEN and RISCV_ISA_FLEN. */ + are just the results of calling RISCV_ABI_XLEN and RISCV_ABI_FLEN. */ int xlen; int flen; }; @@ -1977,7 +2000,7 @@ riscv_call_arg_complex_float (struct riscv_arg_info *ainfo, int len = ainfo->length / 2; result = riscv_assign_reg_location (&ainfo->argloc[0], - &cinfo->float_regs, len, len); + &cinfo->float_regs, len, 0); gdb_assert (result); result = riscv_assign_reg_location (&ainfo->argloc[1], @@ -1998,14 +2021,18 @@ class riscv_struct_info public: riscv_struct_info () : m_number_of_fields (0), - m_types { nullptr, nullptr } + m_types { nullptr, nullptr }, + m_offsets { 0, 0 } { /* Nothing. */ } /* Analyse TYPE descending into nested structures, count the number of scalar fields and record the types of the first two fields found. */ - void analyse (struct type *type); + void analyse (struct type *type) + { + analyse_inner (type, 0); + } /* The number of scalar fields found in the analysed type. This is currently only accurate if the value returned is 0, 1, or 2 as the @@ -2025,6 +2052,16 @@ public: return m_types[index]; } + /* Return the offset of scalar field INDEX within the analysed type. Will + return 0 if there is no field at that index. Only INDEX values 0 and + 1 can be requested as the RiscV ABI only has special cases for + structures with 1 or 2 fields. */ + int field_offset (int index) const + { + gdb_assert (index < (sizeof (m_offsets) / sizeof (m_offsets[0]))); + return m_offsets[index]; + } + private: /* The number of scalar fields found within the structure after recursing into nested structures. */ @@ -2033,13 +2070,20 @@ private: /* The types of the first two scalar fields found within the structure after recursing into nested structures. */ struct type *m_types[2]; + + /* The offsets of the first two scalar fields found within the structure + after recursing into nested structures. */ + int m_offsets[2]; + + /* Recursive core for ANALYSE, the OFFSET parameter tracks the byte + offset from the start of the top level structure being analysed. */ + void analyse_inner (struct type *type, int offset); }; -/* Analyse TYPE descending into nested structures, count the number of - scalar fields and record the types of the first two fields found. */ +/* See description in class declaration. */ void -riscv_struct_info::analyse (struct type *type) +riscv_struct_info::analyse_inner (struct type *type, int offset) { unsigned int count = TYPE_NFIELDS (type); unsigned int i; @@ -2051,11 +2095,13 @@ riscv_struct_info::analyse (struct type *type) struct type *field_type = TYPE_FIELD_TYPE (type, i); field_type = check_typedef (field_type); + int field_offset + = offset + TYPE_FIELD_BITPOS (type, i) / TARGET_CHAR_BIT; switch (TYPE_CODE (field_type)) { case TYPE_CODE_STRUCT: - analyse (field_type); + analyse_inner (field_type, field_offset); break; default: @@ -2065,7 +2111,10 @@ riscv_struct_info::analyse (struct type *type) structure we can special case, and pass the structure in memory. */ if (m_number_of_fields < 2) - m_types[m_number_of_fields] = field_type; + { + m_types[m_number_of_fields] = field_type; + m_offsets[m_number_of_fields] = field_offset; + } m_number_of_fields++; break; } @@ -2098,17 +2147,54 @@ riscv_call_arg_struct (struct riscv_arg_info *ainfo, if (sinfo.number_of_fields () == 1 && TYPE_CODE (sinfo.field_type (0)) == TYPE_CODE_COMPLEX) { - gdb_assert (TYPE_LENGTH (ainfo->type) - == TYPE_LENGTH (sinfo.field_type (0))); - return riscv_call_arg_complex_float (ainfo, cinfo); + /* The following is similar to RISCV_CALL_ARG_COMPLEX_FLOAT, + except we use the type of the complex field instead of the + type from AINFO, and the first location might be at a non-zero + offset. */ + if (TYPE_LENGTH (sinfo.field_type (0)) <= (2 * cinfo->flen) + && riscv_arg_regs_available (&cinfo->float_regs) >= 2 + && !ainfo->is_unnamed) + { + bool result; + int len = TYPE_LENGTH (sinfo.field_type (0)) / 2; + int offset = sinfo.field_offset (0); + + result = riscv_assign_reg_location (&ainfo->argloc[0], + &cinfo->float_regs, len, + offset); + gdb_assert (result); + + result = riscv_assign_reg_location (&ainfo->argloc[1], + &cinfo->float_regs, len, + (offset + len)); + gdb_assert (result); + } + else + riscv_call_arg_scalar_int (ainfo, cinfo); + return; } if (sinfo.number_of_fields () == 1 && TYPE_CODE (sinfo.field_type (0)) == TYPE_CODE_FLT) { - gdb_assert (TYPE_LENGTH (ainfo->type) - == TYPE_LENGTH (sinfo.field_type (0))); - return riscv_call_arg_scalar_float (ainfo, cinfo); + /* The following is similar to RISCV_CALL_ARG_SCALAR_FLOAT, + except we use the type of the first scalar field instead of + the type from AINFO. Also the location might be at a non-zero + offset. */ + if (TYPE_LENGTH (sinfo.field_type (0)) > cinfo->flen + || ainfo->is_unnamed) + riscv_call_arg_scalar_int (ainfo, cinfo); + else + { + int offset = sinfo.field_offset (0); + int len = TYPE_LENGTH (sinfo.field_type (0)); + + if (!riscv_assign_reg_location (&ainfo->argloc[0], + &cinfo->float_regs, + len, offset)) + riscv_call_arg_scalar_int (ainfo, cinfo); + } + return; } if (sinfo.number_of_fields () == 2 @@ -2118,17 +2204,14 @@ riscv_call_arg_struct (struct riscv_arg_info *ainfo, && TYPE_LENGTH (sinfo.field_type (1)) <= cinfo->flen && riscv_arg_regs_available (&cinfo->float_regs) >= 2) { - int len0, len1, offset; - - gdb_assert (TYPE_LENGTH (ainfo->type) <= (2 * cinfo->flen)); - - len0 = TYPE_LENGTH (sinfo.field_type (0)); + int len0 = TYPE_LENGTH (sinfo.field_type (0)); + int offset = sinfo.field_offset (0); if (!riscv_assign_reg_location (&ainfo->argloc[0], - &cinfo->float_regs, len0, 0)) + &cinfo->float_regs, len0, offset)) error (_("failed during argument setup")); - len1 = TYPE_LENGTH (sinfo.field_type (1)); - offset = align_up (len0, riscv_type_alignment (sinfo.field_type (1))); + int len1 = TYPE_LENGTH (sinfo.field_type (1)); + offset = sinfo.field_offset (1); gdb_assert (len1 <= (TYPE_LENGTH (ainfo->type) - TYPE_LENGTH (sinfo.field_type (0)))); @@ -2146,18 +2229,14 @@ riscv_call_arg_struct (struct riscv_arg_info *ainfo, && is_integral_type (sinfo.field_type (1)) && TYPE_LENGTH (sinfo.field_type (1)) <= cinfo->xlen)) { - int len0, len1, offset; - - gdb_assert (TYPE_LENGTH (ainfo->type) - <= (cinfo->flen + cinfo->xlen)); - - len0 = TYPE_LENGTH (sinfo.field_type (0)); + int len0 = TYPE_LENGTH (sinfo.field_type (0)); + int offset = sinfo.field_offset (0); if (!riscv_assign_reg_location (&ainfo->argloc[0], - &cinfo->float_regs, len0, 0)) + &cinfo->float_regs, len0, offset)) error (_("failed during argument setup")); - len1 = TYPE_LENGTH (sinfo.field_type (1)); - offset = align_up (len0, riscv_type_alignment (sinfo.field_type (1))); + int len1 = TYPE_LENGTH (sinfo.field_type (1)); + offset = sinfo.field_offset (1); gdb_assert (len1 <= cinfo->xlen); if (!riscv_assign_reg_location (&ainfo->argloc[1], &cinfo->int_regs, len1, offset)) @@ -2172,22 +2251,18 @@ riscv_call_arg_struct (struct riscv_arg_info *ainfo, && TYPE_CODE (sinfo.field_type (1)) == TYPE_CODE_FLT && TYPE_LENGTH (sinfo.field_type (1)) <= cinfo->flen)) { - int len0, len1, offset; - - gdb_assert (TYPE_LENGTH (ainfo->type) - <= (cinfo->flen + cinfo->xlen)); - - len0 = TYPE_LENGTH (sinfo.field_type (0)); - len1 = TYPE_LENGTH (sinfo.field_type (1)); - offset = align_up (len0, riscv_type_alignment (sinfo.field_type (1))); + int len0 = TYPE_LENGTH (sinfo.field_type (0)); + int len1 = TYPE_LENGTH (sinfo.field_type (1)); gdb_assert (len0 <= cinfo->xlen); gdb_assert (len1 <= cinfo->flen); + int offset = sinfo.field_offset (0); if (!riscv_assign_reg_location (&ainfo->argloc[0], - &cinfo->int_regs, len0, 0)) + &cinfo->int_regs, len0, offset)) error (_("failed during argument setup")); + offset = sinfo.field_offset (1); if (!riscv_assign_reg_location (&ainfo->argloc[1], &cinfo->float_regs, len1, offset)) @@ -2199,7 +2274,6 @@ riscv_call_arg_struct (struct riscv_arg_info *ainfo, /* Non of the structure flattening cases apply, so we just pass using the integer ABI. */ - ainfo->length = align_up (ainfo->length, cinfo->xlen); riscv_call_arg_scalar_int (ainfo, cinfo); } @@ -2221,9 +2295,11 @@ riscv_arg_location (struct gdbarch *gdbarch, { ainfo->type = type; ainfo->length = TYPE_LENGTH (ainfo->type); - ainfo->align = riscv_type_alignment (ainfo->type); + ainfo->align = type_align (ainfo->type); ainfo->is_unnamed = is_unnamed; ainfo->contents = nullptr; + ainfo->argloc[0].c_length = 0; + ainfo->argloc[1].c_length = 0; switch (TYPE_CODE (ainfo->type)) { @@ -2245,7 +2321,7 @@ riscv_arg_location (struct gdbarch *gdbarch, } /* Recalculate the alignment requirement. */ - ainfo->align = riscv_type_alignment (ainfo->type); + ainfo->align = type_align (ainfo->type); riscv_call_arg_scalar_int (ainfo, cinfo); break; @@ -2465,10 +2541,11 @@ riscv_push_dummy_call (struct gdbarch *gdbarch, memset (tmp, -1, sizeof (tmp)); else memset (tmp, 0, sizeof (tmp)); - memcpy (tmp, info->contents, info->argloc[0].c_length); + memcpy (tmp, (info->contents + info->argloc[0].c_offset), + info->argloc[0].c_length); regcache->cooked_write (info->argloc[0].loc_data.regno, tmp); second_arg_length = - ((info->argloc[0].c_length < info->length) + (((info->argloc[0].c_length + info->argloc[0].c_offset) < info->length) ? info->argloc[1].c_length : 0); second_arg_data = info->contents + info->argloc[1].c_offset; } @@ -2579,7 +2656,35 @@ riscv_return_value (struct gdbarch *gdbarch, if (readbuf != nullptr || writebuf != nullptr) { - int regnum; + unsigned int arg_len; + struct value *abi_val; + gdb_byte *old_readbuf = nullptr; + int regnum; + + /* We only do one thing at a time. */ + gdb_assert (readbuf == nullptr || writebuf == nullptr); + + /* In some cases the argument is not returned as the declared type, + and we need to cast to or from the ABI type in order to + correctly access the argument. When writing to the machine we + do the cast here, when reading from the machine the cast occurs + later, after extracting the value. As the ABI type can be + larger than the declared type, then the read or write buffers + passed in might be too small. Here we ensure that we are using + buffers of sufficient size. */ + if (writebuf != nullptr) + { + struct value *arg_val = value_from_contents (arg_type, writebuf); + abi_val = value_cast (info.type, arg_val); + writebuf = value_contents_raw (abi_val); + } + else + { + abi_val = allocate_value (info.type); + old_readbuf = readbuf; + readbuf = value_contents_raw (abi_val); + } + arg_len = TYPE_LENGTH (info.type); switch (info.argloc[0].loc_type) { @@ -2587,32 +2692,54 @@ riscv_return_value (struct gdbarch *gdbarch, case riscv_arg_info::location::in_reg: { regnum = info.argloc[0].loc_data.regno; + gdb_assert (info.argloc[0].c_length <= arg_len); + gdb_assert (info.argloc[0].c_length + <= register_size (gdbarch, regnum)); if (readbuf) - regcache->cooked_read (regnum, readbuf); + { + gdb_byte *ptr = readbuf + info.argloc[0].c_offset; + regcache->cooked_read_part (regnum, 0, + info.argloc[0].c_length, + ptr); + } if (writebuf) - regcache->cooked_write (regnum, writebuf); + { + const gdb_byte *ptr = writebuf + info.argloc[0].c_offset; + regcache->cooked_write_part (regnum, 0, + info.argloc[0].c_length, + ptr); + } /* A return value in register can have a second part in a second register. */ - if (info.argloc[0].c_length < info.length) + if (info.argloc[1].c_length > 0) { switch (info.argloc[1].loc_type) { case riscv_arg_info::location::in_reg: regnum = info.argloc[1].loc_data.regno; + gdb_assert ((info.argloc[0].c_length + + info.argloc[1].c_length) <= arg_len); + gdb_assert (info.argloc[1].c_length + <= register_size (gdbarch, regnum)); + if (readbuf) { readbuf += info.argloc[1].c_offset; - regcache->cooked_read (regnum, readbuf); + regcache->cooked_read_part (regnum, 0, + info.argloc[1].c_length, + readbuf); } if (writebuf) { writebuf += info.argloc[1].c_offset; - regcache->cooked_write (regnum, writebuf); + regcache->cooked_write_part (regnum, 0, + info.argloc[1].c_length, + writebuf); } break; @@ -2645,6 +2772,16 @@ riscv_return_value (struct gdbarch *gdbarch, error (_("invalid argument location")); break; } + + /* This completes the cast from abi type back to the declared type + in the case that we are reading from the machine. See the + comment at the head of this block for more details. */ + if (readbuf != nullptr) + { + struct value *arg_val = value_cast (arg_type, abi_val); + memcpy (old_readbuf, value_contents_raw (arg_val), + TYPE_LENGTH (arg_type)); + } } switch (info.argloc[0].loc_type) @@ -2667,31 +2804,6 @@ riscv_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr) return align_down (addr, 16); } -/* Implement the unwind_pc gdbarch method. */ - -static CORE_ADDR -riscv_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame) -{ - return frame_unwind_register_unsigned (next_frame, RISCV_PC_REGNUM); -} - -/* Implement the unwind_sp gdbarch method. */ - -static CORE_ADDR -riscv_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame) -{ - return frame_unwind_register_unsigned (next_frame, RISCV_SP_REGNUM); -} - -/* Implement the dummy_id gdbarch method. */ - -static struct frame_id -riscv_dummy_id (struct gdbarch *gdbarch, struct frame_info *this_frame) -{ - return frame_id_build (get_frame_register_signed (this_frame, RISCV_SP_REGNUM), - get_frame_pc (this_frame)); -} - /* Generate, or return the cached frame cache for the RiscV frame unwinder. */ @@ -2763,17 +2875,16 @@ riscv_frame_this_id (struct frame_info *this_frame, { struct riscv_unwind_cache *cache; - TRY + try { cache = riscv_frame_cache (this_frame, prologue_cache); *this_id = cache->this_id; } - CATCH (ex, RETURN_MASK_ERROR) + catch (const gdb_exception_error &ex) { /* Ignore errors, this leaves the frame id as the predefined outer frame id which terminates the backtrace at this point. */ } - END_CATCH } /* Implement the prev_register callback for RiscV frame unwinder. */ @@ -2836,27 +2947,9 @@ riscv_features_from_gdbarch_info (const struct gdbarch_info info) _("unknown ELF header class %d"), eclass); if (e_flags & EF_RISCV_FLOAT_ABI_DOUBLE) - { - features.flen = 8; - features.hw_float_abi = true; - } + features.flen = 8; else if (e_flags & EF_RISCV_FLOAT_ABI_SINGLE) - { - features.flen = 4; - features.hw_float_abi = true; - } - } - else - { - const struct bfd_arch_info *binfo = info.bfd_arch_info; - - if (binfo->bits_per_word == 32) - features.xlen = 4; - else if (binfo->bits_per_word == 64) - features.xlen = 8; - else - internal_error (__FILE__, __LINE__, _("unknown bits_per_word %d"), - binfo->bits_per_word); + features.flen = 4; } return features; @@ -2963,6 +3056,58 @@ riscv_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int reg) return -1; } +/* Implement the gcc_target_options method. We have to select the arch and abi + from the feature info. We have enough feature info to select the abi, but + not enough info for the arch given all of the possible architecture + extensions. So choose reasonable defaults for now. */ + +static std::string +riscv_gcc_target_options (struct gdbarch *gdbarch) +{ + int isa_xlen = riscv_isa_xlen (gdbarch); + int isa_flen = riscv_isa_flen (gdbarch); + int abi_xlen = riscv_abi_xlen (gdbarch); + int abi_flen = riscv_abi_flen (gdbarch); + std::string target_options; + + target_options = "-march=rv"; + if (isa_xlen == 8) + target_options += "64"; + else + target_options += "32"; + if (isa_flen == 8) + target_options += "gc"; + else if (isa_flen == 4) + target_options += "imafc"; + else + target_options += "imac"; + + target_options += " -mabi="; + if (abi_xlen == 8) + target_options += "lp64"; + else + target_options += "ilp32"; + if (abi_flen == 8) + target_options += "d"; + else if (abi_flen == 4) + target_options += "f"; + + /* The gdb loader doesn't handle link-time relaxation relocations. */ + target_options += " -mno-relax"; + + return target_options; +} + +/* Implement the gnu_triplet_regexp method. A single compiler supports both + 32-bit and 64-bit code, and may be named riscv32 or riscv64 or (not + recommended) riscv. */ + +static const char * +riscv_gnu_triplet_regexp (struct gdbarch *gdbarch) +{ + return "riscv(32|64)?"; +} + /* Initialize the current architecture based on INFO. If possible, re-use an architecture from ARCHES, which is a list of architectures already created during this debugging session. @@ -3025,7 +3170,21 @@ riscv_gdbarch_init (struct gdbarch_info info, valid_p &= riscv_check_tdesc_feature (tdesc_data, feature_fpu, &riscv_freg_feature); - int bitsize = tdesc_register_bitsize (feature_fpu, "ft0"); + /* Search for the first floating point register (by any alias), to + determine the bitsize. */ + int bitsize = -1; + const auto &fp0 = riscv_freg_feature.registers[0]; + + for (const char *name : fp0.names) + { + if (tdesc_unnumbered_register (feature_fpu, name)) + { + bitsize = tdesc_register_bitsize (feature_fpu, name); + break; + } + } + + gdb_assert (bitsize != -1); features.flen = (bitsize / 8); if (riscv_debug_gdbarch) @@ -3062,25 +3221,26 @@ riscv_gdbarch_init (struct gdbarch_info info, /* Have a look at what the supplied (if any) bfd object requires of the target, then check that this matches with what the target is providing. */ - struct riscv_gdbarch_features info_features + struct riscv_gdbarch_features abi_features = riscv_features_from_gdbarch_info (info); - if (info_features.xlen != 0 && info_features.xlen != features.xlen) + /* In theory a binary compiled for RV32 could run on an RV64 target, + however, this has not been tested in GDB yet, so for now we require + that the requested xlen match the targets xlen. */ + if (abi_features.xlen != 0 && abi_features.xlen != features.xlen) error (_("bfd requires xlen %d, but target has xlen %d"), - info_features.xlen, features.xlen); - if (info_features.flen != 0 && info_features.flen != features.flen) + abi_features.xlen, features.xlen); + /* We do support running binaries compiled for 32-bit float on targets + with 64-bit float, so we only complain if the binary requires more + than the target has available. */ + if (abi_features.flen > features.flen) error (_("bfd requires flen %d, but target has flen %d"), - info_features.flen, features.flen); + abi_features.flen, features.flen); - /* If the xlen from INFO_FEATURES is 0 then this indicates either there - is no bfd object, or nothing useful could be extracted from it, in - this case we enable hardware float abi if the target has floating - point registers. - - If the xlen from INFO_FEATURES is not 0, and the flen in - INFO_FEATURES is also not 0, then this indicates that the supplied - bfd does require hardware floating point abi. */ - if (info_features.xlen == 0 || info_features.flen != 0) - features.hw_float_abi = (features.flen > 0); + /* If the ABI_FEATURES xlen is 0 then this indicates we got no useful abi + features from the INFO object. In this case we assume that the xlen + abi matches the hardware. */ + if (abi_features.xlen == 0) + abi_features.xlen = features.xlen; /* Find a candidate among the list of pre-declared architectures. */ for (arches = gdbarch_list_lookup_by_info (arches, &info); @@ -3092,7 +3252,8 @@ riscv_gdbarch_init (struct gdbarch_info info, gdbarch. */ struct gdbarch_tdep *other_tdep = gdbarch_tdep (arches->gdbarch); - if (other_tdep->features != features) + if (other_tdep->isa_features != features + || other_tdep->abi_features != abi_features) continue; break; @@ -3107,7 +3268,8 @@ riscv_gdbarch_init (struct gdbarch_info info, /* None found, so create a new architecture from the information provided. */ tdep = new (struct gdbarch_tdep); gdbarch = gdbarch_alloc (&info, tdep); - tdep->features = features; + tdep->isa_features = features; + tdep->abi_features = abi_features; /* Target data types. */ set_gdbarch_short_bit (gdbarch, 16); @@ -3120,6 +3282,7 @@ riscv_gdbarch_init (struct gdbarch_info info, set_gdbarch_long_double_format (gdbarch, floatformats_ia64_quad); set_gdbarch_ptr_bit (gdbarch, riscv_isa_xlen (gdbarch) * 8); set_gdbarch_char_signed (gdbarch, 0); + set_gdbarch_type_align (gdbarch, riscv_type_align); /* Information about the target architecture. */ set_gdbarch_return_value (gdbarch, riscv_return_value); @@ -3132,15 +3295,10 @@ riscv_gdbarch_init (struct gdbarch_info info, set_gdbarch_inner_than (gdbarch, core_addr_lessthan); set_gdbarch_frame_align (gdbarch, riscv_frame_align); - /* Functions to access frame data. */ - set_gdbarch_unwind_pc (gdbarch, riscv_unwind_pc); - set_gdbarch_unwind_sp (gdbarch, riscv_unwind_sp); - /* Functions handling dummy frames. */ set_gdbarch_call_dummy_location (gdbarch, ON_STACK); set_gdbarch_push_dummy_code (gdbarch, riscv_push_dummy_code); set_gdbarch_push_dummy_call (gdbarch, riscv_push_dummy_call); - set_gdbarch_dummy_id (gdbarch, riscv_dummy_id); /* Frame unwinders. Use DWARF debug info if available, otherwise use our own unwinder. */ @@ -3194,9 +3352,15 @@ riscv_gdbarch_init (struct gdbarch_info info, riscv_setup_register_aliases (gdbarch, &riscv_freg_feature); riscv_setup_register_aliases (gdbarch, &riscv_csr_feature); + /* Compile command hooks. */ + set_gdbarch_gcc_target_options (gdbarch, riscv_gcc_target_options); + set_gdbarch_gnu_triplet_regexp (gdbarch, riscv_gnu_triplet_regexp); + /* Hook in OS ABI-specific overrides, if they have been registered. */ gdbarch_init_osabi (info, gdbarch); + register_riscv_ravenscar_ops (gdbarch); + return gdbarch; }