[PATCHv4 2/2] gdb: Initial baremetal riscv support

Yao Qi qiyaoltc@gmail.com
Tue Mar 6 11:06:00 GMT 2018


Andrew Burgess <andrew.burgess@embecosm.com> writes:

Hi Andrew,
Did you see the GDB internal error in gdb selftests.  I build my gdb
with all targets enabled (--enable-targets=all --enable-64-bit-bfd), and
type command "maintenance selftest"

../../binutils-gdb/gdb/regcache.c:371: internal-error: void reg_buffer::assert_regnum(int) const: Assertion `regnum < gdbarch_num_regs (arch ())' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
Quit this debugging session? (y or n) n

(gdb) bt 10
#0  internal_error (file=file@entry=0xeb4630 "../../binutils-gdb/gdb/regcache.c", line=line@entry=371, fmt=0xd91f23 "%s: Assertion `%s' failed.")
    at ../../binutils-gdb/gdb/common/errors.c:51
#1  0x0000000000768691 in reg_buffer::assert_regnum (this=<optimized out>, regnum=4162) at ../../binutils-gdb/gdb/regcache.c:371
#2  0x0000000000768802 in regcache::raw_update (this=0x7fffffffd0f0, regnum=4162) at ../../binutils-gdb/gdb/regcache.c:521
#3  0x000000000076903a in readable_regcache::raw_read (this=0x7fffffffd0f0, regnum=4162, buf=0x34adc30 "\230k)\366\377\177") at ../../binutils-gdb/gdb/regcache.c:550
#4  0x00000000007695af in selftests::cooked_read_test (gdbarch=0x29e4a00) at ../../binutils-gdb/gdb/regcache.c:1659
#5  0x00000000005d6403 in selftests::gdbarch_selftest::operator() (this=0x2840aa0) at ../../binutils-gdb/gdb/selftest-arch.c:73
#6  0x00000000005d57c2 in selftests::run_tests (filter=0x0) at
../../binutils-gdb/gdb/common/selftest.c:88
(gdb) p gdbarch->bfd_arch_info
$3 = (const bfd_arch_info *) 0x1969d80 <bfd_riscv_arch>

Looks it is from riscv port.  Some other comments on this patch below,

> +   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>.
> +

Please don't use "Contributed by" see
https://sourceware.org/gdb/wiki/ContributionChecklist#Attribution

> +
> +/* 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);
> +}
> +

unwind_pc has some duplication across all gdb ports.  Can we define a
default implementation of this method like this,

static CORE_ADDR
default_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
{
  return frame_unwind_register_unsigned (next_frame,
					 gdbarch_pc_regnum (gdbarch));
} 

so many ports, including riscv, don't need to define its own unwind_pc
at all.

> +/* 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);
> +}
> +

> +/* 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.
> +
> +   Called e.g. at program startup, when reading a core file, and when
> +   reading a binary file.  */
> +
> +static struct gdbarch *
> +riscv_gdbarch_init (struct gdbarch_info info,
> +		    struct gdbarch_list *arches)
> +{
> +  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
> +     things like register size, and whether the target has floating point
> +     hardware.  However, there are some things that the target can't tell
> +     us, like, what ABI is being used.
> +
> +     So, for now, we take as much information as possible from the ELF,
> +     including things like register size, and FP hardware support, along
> +     with information about the ABI.
> +
> +     Information about this target is built up in TMP_TDEP, and then we
> +     look for an existing gdbarch in ARCHES that matches TMP_TDEP.  If no
> +     match is found we'll create a new gdbarch and copy TMP_TDEP over.  */
> +  memset (&tmp_tdep, 0, sizeof (tmp_tdep));
> +
> +  if (info.abfd != NULL
> +      && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
> +    {
> +      unsigned char eclass = elf_elfheader (info.abfd)->e_ident[EI_CLASS];
> +      int e_flags = elf_elfheader (info.abfd)->e_flags;
> +
> +      if (eclass == ELFCLASS32)
> +	tmp_tdep.abi.fields.base_len = 1;
> +      else if (eclass == ELFCLASS64)
> +	tmp_tdep.abi.fields.base_len = 2;
> +      else
> +        internal_error (__FILE__, __LINE__,
> +			_("unknown ELF header class %d"), eclass);
> +
> +      if (e_flags & EF_RISCV_RVC)
> +	{
> +	  has_compressed_isa = true;
> +	  tmp_tdep.core_features |= (1 << ('C' - 'A'));
> +	}
> +
> +      if (e_flags & EF_RISCV_FLOAT_ABI_DOUBLE)
> +	{
> +	  tmp_tdep.abi.fields.float_abi = 2;
> +	  tmp_tdep.core_features |= (1 << ('D' - 'A'));
> +	  tmp_tdep.core_features |= (1 << ('F' - 'A'));
> +	}
> +      else if (e_flags & EF_RISCV_FLOAT_ABI_SINGLE)
> +	{
> +	  tmp_tdep.abi.fields.float_abi = 1;
> +	  tmp_tdep.core_features |= (1 << ('F' - 'A'));
> +	}
> +    }
> +  else
> +    {
> +      const struct bfd_arch_info *binfo = info.bfd_arch_info;
> +
> +      if (binfo->bits_per_word == 32)
> +	tmp_tdep.abi.fields.base_len = 1;
> +      else if (binfo->bits_per_word == 64)
> +	tmp_tdep.abi.fields.base_len = 2;
> +      else
> +        internal_error (__FILE__, __LINE__, _("unknown bits_per_word %d"),
> +			binfo->bits_per_word);
> +    }
> +
> +  /* Find a candidate among the list of pre-declared architectures.  */
> +  for (arches = gdbarch_list_lookup_by_info (arches, &info);
> +       arches != NULL;
> +       arches = gdbarch_list_lookup_by_info (arches->next, &info))
> +    if (gdbarch_tdep (arches->gdbarch)->abi.value == tmp_tdep.abi.value)
> +      return arches->gdbarch;
> +
> +  /* None found, so create a new architecture from the information provided.  */
> +  tdep = (struct gdbarch_tdep *) xmalloc (sizeof *tdep);
> +  gdbarch = gdbarch_alloc (&info, tdep);
> +  memcpy (tdep, &tmp_tdep, sizeof (tmp_tdep));
> +
> +  /* Target data types.  */
> +  set_gdbarch_short_bit (gdbarch, 16);
> +  set_gdbarch_int_bit (gdbarch, 32);
> +  set_gdbarch_long_bit (gdbarch, riscv_isa_xlen (gdbarch) * 8);
> +  set_gdbarch_long_long_bit (gdbarch, 64);
> +  set_gdbarch_float_bit (gdbarch, 32);
> +  set_gdbarch_double_bit (gdbarch, 64);
> +  set_gdbarch_long_double_bit (gdbarch, 128);
> +  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);
> +
> +  /* Information about the target architecture.  */
> +  set_gdbarch_return_value (gdbarch, riscv_return_value);
> +  set_gdbarch_breakpoint_kind_from_pc (gdbarch, riscv_breakpoint_kind_from_pc);
> +  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_deprecated_fp_regnum (gdbarch, RISCV_FP_REGNUM);
> +
> +  /* Functions to supply register information.  */
> +  set_gdbarch_register_name (gdbarch, riscv_register_name);
> +  set_gdbarch_register_type (gdbarch, riscv_register_type);
> +  set_gdbarch_print_registers_info (gdbarch, riscv_print_registers_info);
> +  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);
> +
> +  /* 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.  */
> +  dwarf2_append_unwinders (gdbarch);
> +  frame_unwind_append_unwinder (gdbarch, &riscv_frame_unwind);
> +
> +  /* Check any target description for validity.  */

Target description is not added yet.  Can we remove it?

> +  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);
> +
> +  return gdbarch;
> +}
> +
> +

-- 
Yao (齐尧)



More information about the Gdb-patches mailing list