/* Target-dependent code for the RISC-V architecture, for GDB.
- Copyright (C) 2018-2019 Free Software Foundation, Inc.
+ Copyright (C) 2018-2020 Free Software Foundation, Inc.
This file is part of GDB.
#include "dwarf2-frame.h"
#include "user-regs.h"
#include "valprint.h"
-#include "common/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
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);
}
{
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;
LUI,
SD,
SW,
- /* These are needed for software breakopint support. */
+ /* These are needed for software breakpoint support. */
JAL,
JALR,
BEQ,
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
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;
}
else if (e_flags & EF_RISCV_FLOAT_ABI_SINGLE)
features.flen = 4;
}
- 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);
- }
return features;
}
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.
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)
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;
}