Copyright (C) 2018 Free Software Foundation, Inc.
- Contributed by Alessandro Forin(af@cs.cmu.edu) at CMU
- and by Per Bothner(bothner@cs.wisc.edu) at U.Wisconsin
- and by Todd Snyder <todd@bluespec.com>
- and by Mike Frysinger <vapier@gentoo.org>.
-
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
#include "common-defs.h"
#include "opcode/riscv-opc.h"
#include "cli/cli-decode.h"
-#include "observer.h"
+#include "observable.h"
/* The stack must be 16-byte aligned. */
#define SP_ALIGNMENT 16
{ "t0", 5 },
{ "t1", 6 },
{ "t2", 7 },
- { "fp", 8 },
{ "s0", 8 },
+ { "fp", 8 },
{ "s1", 9 },
{ "a0", 10 },
{ "a1", 11 },
gdb_assert (feature >= 'A' && feature <= 'Z');
- /* It would be nice to always check with the real target where possible,
- however, for compressed instructions this is a bad idea.
-
- The call to `set_gdbarch_decr_pc_after_break' is made just once per
- GDBARCH and we decide at that point if we should decrement by 2 or 4
- bytes based on whether the BFD has compressed instruction support or
- not.
-
- If the BFD was not compiled with compressed instruction support, but we
- are running on a target with compressed instructions then we might
- place a 4-byte breakpoint, then decrement the $pc by 2 bytes leading to
- confusion.
-
- It's safer if we just make decisions about compressed instruction
- support based on the BFD. */
- if (feature != 'C')
- misa = riscv_read_misa_reg (&have_read_misa);
+ misa = riscv_read_misa_reg (&have_read_misa);
if (!have_read_misa || misa == 0)
misa = gdbarch_tdep (gdbarch)->core_features;
{
default:
warning (_("unknown xlen size, assuming 4 bytes"));
+ /* Fall through. */
case 1:
return 4;
case 2:
return (gdbarch_tdep (gdbarch)->abi.fields.float_abi != 0);
}
+/* Return true if REGNO is a floating pointer register. */
+
+static bool
+riscv_is_fp_regno_p (int regno)
+{
+ return (regno >= RISCV_FIRST_FP_REGNUM
+ && regno <= RISCV_LAST_FP_REGNUM);
+}
+
/* Implement the breakpoint_kind_from_pc gdbarch method. */
static int
case 4:
return ebreak;
default:
- gdb_assert_not_reached ("unhandled breakpoint kind");
+ gdb_assert_not_reached (_("unhandled breakpoint kind"));
}
}
static const char *
riscv_register_name (struct gdbarch *gdbarch, int regnum)
{
- if (tdesc_has_registers (gdbarch_target_desc (gdbarch)))
- return tdesc_register_name (gdbarch, regnum);
-
/* Prefer to use the alias. */
if (regnum >= RISCV_ZERO_REGNUM && regnum <= RISCV_LAST_REGNUM)
{
{
static char buf[20];
- sprintf (buf, "csr%d", regnum - RISCV_FIRST_CSR_REGNUM);
+ xsnprintf (buf, sizeof (buf), "csr%d",
+ regnum - RISCV_FIRST_CSR_REGNUM);
return buf;
}
return NULL;
}
-/* Implement the pseudo_register_read gdbarch method. */
-
-static enum register_status
-riscv_pseudo_register_read (struct gdbarch *gdbarch,
- readable_regcache *regcache,
- int regnum,
- gdb_byte *buf)
-{
- return regcache->raw_read (regnum, buf);
-}
-
-/* Implement the pseudo_register_write gdbarch method. */
-
-static void
-riscv_pseudo_register_write (struct gdbarch *gdbarch,
- struct regcache *regcache,
- int cookednum,
- const gdb_byte *buf)
-{
- regcache_raw_write (regcache, cookednum, buf);
-}
-
/* Implement the register_type gdbarch method. */
static struct type *
return 0;
}
else if (reggroup == float_reggroup)
- return ((regnum >= RISCV_FIRST_FP_REGNUM && regnum <= RISCV_LAST_FP_REGNUM)
- || (regnum == RISCV_CSR_FCSR_REGNUM
- || regnum == RISCV_CSR_FFLAGS_REGNUM
- || regnum == RISCV_CSR_FRM_REGNUM));
+ return (riscv_is_fp_regno_p (regnum)
+ || regnum == RISCV_CSR_FCSR_REGNUM
+ || regnum == RISCV_CSR_FFLAGS_REGNUM
+ || regnum == RISCV_CSR_FRM_REGNUM);
else if (reggroup == general_reggroup)
return regnum < RISCV_FIRST_FP_REGNUM;
else if (reggroup == restore_reggroup || reggroup == save_reggroup)
/* If we need more, grab it now. */
instlen = riscv_insn_length (buf[0]);
+ gdb_assert (instlen <= sizeof (buf));
*len = instlen;
- if (instlen > sizeof (buf))
- internal_error (__FILE__, __LINE__,
- _("%s: riscv_insn_length returned %i"),
- __func__, instlen);
- else if (instlen > 2)
+
+ if (instlen > 2)
{
status = target_read_memory (addr + 2, buf + 2, instlen - 2);
if (status)
struct riscv_arg_info *info,
CORE_ADDR sp_refs, CORE_ADDR sp_args)
{
- const char* type_name = TYPE_NAME (info->type);
- if (type_name == nullptr)
- type_name = "???";
-
fprintf_unfiltered (stream, "type: '%s', length: 0x%x, alignment: 0x%x",
- type_name, info->length, info->align);
+ TYPE_SAFE_NAME (info->type), info->length, info->align);
switch (info->argloc[0].loc_type)
{
case riscv_arg_info::location::in_reg:
break;
default:
- error ("unknown argument location type");
+ gdb_assert_not_reached (_("unknown argument location type"));
}
}
gdb_byte buf[sizeof (LONGEST)];
store_unsigned_integer (buf, call_info.xlen, byte_order, struct_addr);
- regcache_cooked_write (regcache, RISCV_A0_REGNUM, buf);
+ regcache->cooked_write (RISCV_A0_REGNUM, buf);
}
for (i = 0; i < nargs; ++i)
gdb_assert (info->argloc[0].c_length <= info->length);
memset (tmp, 0, sizeof (tmp));
memcpy (tmp, info->contents, info->argloc[0].c_length);
- regcache_cooked_write (regcache,
- info->argloc[0].loc_data.regno,
- tmp);
+ regcache->cooked_write (info->argloc[0].loc_data.regno, tmp);
second_arg_length =
((info->argloc[0].c_length < info->length)
? info->argloc[1].c_length : 0);
break;
default:
- error ("unknown argument location type");
+ gdb_assert_not_reached (_("unknown argument location type"));
}
if (second_arg_length > 0)
{
gdb_byte tmp [sizeof (ULONGEST)];
- gdb_assert (second_arg_length <= call_info.xlen);
+ gdb_assert ((riscv_is_fp_regno_p (info->argloc[1].loc_data.regno)
+ && second_arg_length <= call_info.flen)
+ || second_arg_length <= call_info.xlen);
memset (tmp, 0, sizeof (tmp));
memcpy (tmp, second_arg_data, second_arg_length);
- regcache_cooked_write (regcache,
- info->argloc[1].loc_data.regno,
- tmp);
+ regcache->cooked_write (info->argloc[1].loc_data.regno, tmp);
}
break;
regnum = info.argloc[0].loc_data.regno;
if (readbuf)
- regcache_cooked_read (regcache, regnum, readbuf);
+ regcache->cooked_read (regnum, readbuf);
if (writebuf)
- regcache_cooked_write (regcache, regnum, writebuf);
+ regcache->cooked_write (regnum, writebuf);
/* A return value in register can have a second part in a
second register. */
if (readbuf)
{
readbuf += info.argloc[1].c_offset;
- regcache_cooked_read (regcache, regnum, readbuf);
+ regcache->cooked_read (regnum, readbuf);
}
if (writebuf)
{
writebuf += info.argloc[1].c_offset;
- regcache_cooked_write (regcache, regnum, writebuf);
+ regcache->cooked_write (regnum, writebuf);
}
break;
struct gdbarch *gdbarch;
struct gdbarch_tdep *tdep;
struct gdbarch_tdep tmp_tdep;
- bool has_compressed_isa = false;
int i;
/* Ideally, we'd like to get as much information from the target for
_("unknown ELF header class %d"), eclass);
if (e_flags & EF_RISCV_RVC)
- {
- has_compressed_isa = true;
- tmp_tdep.core_features |= (1 << ('C' - 'A'));
- }
+ tmp_tdep.core_features |= (1 << ('C' - 'A'));
if (e_flags & EF_RISCV_FLOAT_ABI_DOUBLE)
{
set_gdbarch_sw_breakpoint_from_kind (gdbarch, riscv_sw_breakpoint_from_kind);
/* Register architecture. */
- set_gdbarch_pseudo_register_read (gdbarch, riscv_pseudo_register_read);
- set_gdbarch_pseudo_register_write (gdbarch, riscv_pseudo_register_write);
set_gdbarch_num_regs (gdbarch, RISCV_LAST_REGNUM + 1);
- set_gdbarch_num_pseudo_regs (gdbarch, RISCV_LAST_REGNUM + 1);
set_gdbarch_sp_regnum (gdbarch, RISCV_SP_REGNUM);
set_gdbarch_pc_regnum (gdbarch, RISCV_PC_REGNUM);
set_gdbarch_ps_regnum (gdbarch, RISCV_FP_REGNUM);
set_gdbarch_register_reggroup_p (gdbarch, riscv_register_reggroup_p);
/* Functions to analyze frames. */
- set_gdbarch_decr_pc_after_break (gdbarch, (has_compressed_isa ? 2 : 4));
set_gdbarch_skip_prologue (gdbarch, riscv_skip_prologue);
set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
set_gdbarch_frame_align (gdbarch, riscv_frame_align);
dwarf2_append_unwinders (gdbarch);
frame_unwind_append_unwinder (gdbarch, &riscv_frame_unwind);
- /* Check any target description for validity. */
- if (tdesc_has_registers (info.target_desc))
- {
- const struct tdesc_feature *feature;
- struct tdesc_arch_data *tdesc_data;
- int valid_p;
-
- feature = tdesc_find_feature (info.target_desc, "org.gnu.gdb.riscv.cpu");
- if (feature == NULL)
- goto no_tdata;
-
- tdesc_data = tdesc_data_alloc ();
-
- valid_p = 1;
- for (i = RISCV_ZERO_REGNUM; i <= RISCV_LAST_FP_REGNUM; ++i)
- valid_p &= tdesc_numbered_register (feature, tdesc_data, i,
- riscv_gdb_reg_names[i]);
- for (i = RISCV_FIRST_CSR_REGNUM; i <= RISCV_LAST_CSR_REGNUM; ++i)
- {
- char buf[20];
-
- sprintf (buf, "csr%d", i - RISCV_FIRST_CSR_REGNUM);
- valid_p &= tdesc_numbered_register (feature, tdesc_data, i, buf);
- }
-
- valid_p &= tdesc_numbered_register (feature, tdesc_data, i++, "priv");
-
- if (!valid_p)
- tdesc_data_cleanup (tdesc_data);
- else
- tdesc_use_registers (gdbarch, info.target_desc, tdesc_data);
- }
- no_tdata:
-
for (i = 0; i < ARRAY_SIZE (riscv_register_aliases); ++i)
user_reg_add (gdbarch, riscv_register_aliases[i].name,
value_of_riscv_user_reg, &riscv_register_aliases[i].regnum);
+ /* Hook in OS ABI-specific overrides, if they have been registered. */
+ gdbarch_init_osabi (info, gdbarch);
+
return gdbarch;
}
= register_inferior_data_with_cleanup (NULL, riscv_inferior_data_cleanup);
/* Observers used to invalidate the inferior data when needed. */
- observer_attach_inferior_exit (riscv_invalidate_inferior_data);
- observer_attach_inferior_appeared (riscv_invalidate_inferior_data);
+ gdb::observers::inferior_exit.attach (riscv_invalidate_inferior_data);
+ gdb::observers::inferior_appeared.attach (riscv_invalidate_inferior_data);
/* Add root prefix command for all "set debug riscv" and "show debug
riscv" commands. */