[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