mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-27 04:52:05 +08:00
b2668f28ee
Use the current target description to include CSRs into the RISC-V baremetal core dumps. Every CSR declared in the current target description will be included in the core dump. It will be critical for users that they have the same target description in use when loading the core file as was in use when writing the core file. This should be fine if the user allows the target description to be written into the core file. In more detail, this commit adds a NT_RISCV_CSR note type. The contents of this section is a series of either 4-byte (on RV32 targets), or 8-byte (on RV64 targets) values. Every CSR that is mentioned in the current target description is written out in the order the registers appear in the target description. As a consequence it is critical that the exact same target description, including the same register order, is in use when the CSRs are loaded from the core file. gdb/ChangeLog: * riscv-none-tdep.c: Add 'user-regs.h' and 'target-description.h' includes. (riscv_csrset): New static global. (riscv_update_csrmap): New function. (riscv_iterate_over_regset_sections): Process CSRs.
174 lines
5.2 KiB
C
174 lines
5.2 KiB
C
/* Copyright (C) 2020-2021 Free Software Foundation, Inc.
|
|
|
|
This file is part of GDB.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
/* This file contain code that is specific for bare-metal RISC-V targets. */
|
|
|
|
#include "defs.h"
|
|
#include "arch-utils.h"
|
|
#include "regcache.h"
|
|
#include "riscv-tdep.h"
|
|
#include "elf-bfd.h"
|
|
#include "regset.h"
|
|
#include "user-regs.h"
|
|
#include "target-descriptions.h"
|
|
|
|
#ifdef HAVE_ELF
|
|
#include "elf-none-tdep.h"
|
|
#endif
|
|
|
|
/* Define the general register mapping. This follows the same format as
|
|
the RISC-V linux corefile. The linux kernel puts the PC at offset 0,
|
|
gdb puts it at offset 32. Register x0 is always 0 and can be ignored.
|
|
Registers x1 to x31 are in the same place. */
|
|
|
|
static const struct regcache_map_entry riscv_gregmap[] =
|
|
{
|
|
{ 1, RISCV_PC_REGNUM, 0 },
|
|
{ 31, RISCV_RA_REGNUM, 0 }, /* x1 to x31 */
|
|
{ 0 }
|
|
};
|
|
|
|
/* Define the FP register mapping. This follows the same format as the
|
|
RISC-V linux corefile. The kernel puts the 32 FP regs first, and then
|
|
FCSR. */
|
|
|
|
static const struct regcache_map_entry riscv_fregmap[] =
|
|
{
|
|
{ 32, RISCV_FIRST_FP_REGNUM, 0 },
|
|
{ 1, RISCV_CSR_FCSR_REGNUM, 4 }, /* Always stored as 4-bytes. */
|
|
{ 0 }
|
|
};
|
|
|
|
/* Define the general register regset. */
|
|
|
|
static const struct regset riscv_gregset =
|
|
{
|
|
riscv_gregmap, riscv_supply_regset, regcache_collect_regset
|
|
};
|
|
|
|
/* Define the FP register regset. */
|
|
|
|
static const struct regset riscv_fregset =
|
|
{
|
|
riscv_fregmap, riscv_supply_regset, regcache_collect_regset
|
|
};
|
|
|
|
/* Define the CSR regset, this is not constant as the regmap field is
|
|
updated dynamically based on the current target description. */
|
|
|
|
static struct regset riscv_csrset =
|
|
{
|
|
nullptr, regcache_supply_regset, regcache_collect_regset
|
|
};
|
|
|
|
/* Update the regmap field of RISCV_CSRSET based on the CSRs available in
|
|
the current target description. */
|
|
|
|
static void
|
|
riscv_update_csrmap (struct gdbarch *gdbarch,
|
|
const struct tdesc_feature *feature_csr)
|
|
{
|
|
int i = 0;
|
|
|
|
/* Release any previously defined map. */
|
|
delete[] ((struct regcache_map_entry *) riscv_csrset.regmap);
|
|
|
|
/* Now create a register map for every csr found in the target
|
|
description. */
|
|
struct regcache_map_entry *riscv_csrmap
|
|
= new struct regcache_map_entry[feature_csr->registers.size() + 1];
|
|
for (auto &csr : feature_csr->registers)
|
|
{
|
|
int regnum = user_reg_map_name_to_regnum (gdbarch, csr->name.c_str(),
|
|
csr->name.length());
|
|
riscv_csrmap[i++] = {1, regnum, 0};
|
|
}
|
|
|
|
/* Mark the end of the array. */
|
|
riscv_csrmap[i] = {0};
|
|
riscv_csrset.regmap = riscv_csrmap;
|
|
}
|
|
|
|
/* Implement the "iterate_over_regset_sections" gdbarch method. */
|
|
|
|
static void
|
|
riscv_iterate_over_regset_sections (struct gdbarch *gdbarch,
|
|
iterate_over_regset_sections_cb *cb,
|
|
void *cb_data,
|
|
const struct regcache *regcache)
|
|
{
|
|
/* Write out the GPRs. */
|
|
int sz = 32 * riscv_isa_xlen (gdbarch);
|
|
cb (".reg", sz, sz, &riscv_gregset, NULL, cb_data);
|
|
|
|
/* Write out the FPRs, but only if present. */
|
|
if (riscv_isa_flen (gdbarch) > 0)
|
|
{
|
|
sz = (32 * riscv_isa_flen (gdbarch)
|
|
+ register_size (gdbarch, RISCV_CSR_FCSR_REGNUM));
|
|
cb (".reg2", sz, sz, &riscv_fregset, NULL, cb_data);
|
|
}
|
|
|
|
/* Read or write the CSRs. The set of CSRs is defined by the current
|
|
target description. The user is responsible for ensuring that the
|
|
same target description is in use when reading the core file as was
|
|
in use when writing the core file. */
|
|
const struct target_desc *tdesc = gdbarch_target_desc (gdbarch);
|
|
|
|
/* Do not dump/load any CSRs if there is no target description or the target
|
|
description does not contain any CSRs. */
|
|
if (tdesc != nullptr)
|
|
{
|
|
const struct tdesc_feature *feature_csr
|
|
= tdesc_find_feature (tdesc, riscv_feature_name_csr);
|
|
if (feature_csr != nullptr && feature_csr->registers.size () > 0)
|
|
{
|
|
riscv_update_csrmap (gdbarch, feature_csr);
|
|
cb (".reg-riscv-csr",
|
|
(feature_csr->registers.size() * riscv_isa_xlen (gdbarch)),
|
|
(feature_csr->registers.size() * riscv_isa_xlen (gdbarch)),
|
|
&riscv_csrset, NULL, cb_data);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Initialize RISC-V bare-metal ABI info. */
|
|
|
|
static void
|
|
riscv_none_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
|
|
{
|
|
#ifdef HAVE_ELF
|
|
elf_none_init_abi (gdbarch);
|
|
#endif
|
|
|
|
/* Iterate over registers for reading and writing bare metal RISC-V core
|
|
files. */
|
|
set_gdbarch_iterate_over_regset_sections
|
|
(gdbarch, riscv_iterate_over_regset_sections);
|
|
|
|
}
|
|
|
|
/* Initialize RISC-V bare-metal target support. */
|
|
|
|
void _initialize_riscv_none_tdep ();
|
|
void
|
|
_initialize_riscv_none_tdep ()
|
|
{
|
|
gdbarch_register_osabi (bfd_arch_riscv, 0, GDB_OSABI_NONE,
|
|
riscv_none_init_abi);
|
|
}
|