mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-11-27 03:51:15 +08:00
gdb: LoongArch: Add LBT extension support
Loongson Binary Translation (LBT) is used to accelerate binary translation, which contains 4 scratch registers (scr0 to scr3), x86/ARM eflags (eflags) and x87 fpu stack pointer (ftop). This patch support gdb to fetch/store these registers. Signed-off-by: Feiyang Chen <chenfeiyang@loongson.cn> # Framework Signed-off-by: Binbin Zhou <zhoubinbin@loongson.cn> # Detail Optimizes Signed-off-by: Hui Li <lihui@loongson.cn> # Error Fixes Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
This commit is contained in:
parent
1e9569f383
commit
e4d74c01e7
@ -27,6 +27,7 @@
|
||||
#include "../features/loongarch/fpu.c"
|
||||
#include "../features/loongarch/lsx.c"
|
||||
#include "../features/loongarch/lasx.c"
|
||||
#include "../features/loongarch/lbt.c"
|
||||
|
||||
#ifndef GDBSERVER
|
||||
#define STATIC_IN_GDB static
|
||||
@ -69,6 +70,9 @@ loongarch_create_target_description (const struct loongarch_gdbarch_features fea
|
||||
regnum = create_feature_loongarch_lsx (tdesc.get (), regnum);
|
||||
regnum = create_feature_loongarch_lasx (tdesc.get (), regnum);
|
||||
|
||||
/* For now we only support creating scr registers, eflags and ftop. */
|
||||
regnum = create_feature_loongarch_lbt (tdesc.get (), regnum);
|
||||
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
|
@ -45,6 +45,12 @@ enum loongarch_regnum
|
||||
LOONGARCH_LINUX_NUM_LSXREGSET = 32,
|
||||
LOONGARCH_FIRST_LASX_REGNUM = LOONGARCH_FIRST_LSX_REGNUM + LOONGARCH_LINUX_NUM_LSXREGSET,
|
||||
LOONGARCH_LINUX_NUM_LASXREGSET = 32,
|
||||
|
||||
LOONGARCH_FIRST_SCR_REGNUM = LOONGARCH_FIRST_LASX_REGNUM + LOONGARCH_LINUX_NUM_LASXREGSET,
|
||||
LOONGARCH_LINUX_NUM_SCR = 4,
|
||||
LOONGARCH_LAST_SCR_REGNUM = LOONGARCH_FIRST_SCR_REGNUM + LOONGARCH_LINUX_NUM_SCR - 1,
|
||||
LOONGARCH_EFLAGS_REGNUM = LOONGARCH_LAST_SCR_REGNUM + 1,
|
||||
LOONGARCH_FTOP_REGNUM = LOONGARCH_EFLAGS_REGNUM + 1,
|
||||
};
|
||||
|
||||
enum loongarch_fputype
|
||||
@ -53,6 +59,8 @@ enum loongarch_fputype
|
||||
DOUBLE_FLOAT = 2,
|
||||
};
|
||||
|
||||
#define LOONGARCH_LBT_REGS_SIZE (8 * LOONGARCH_LINUX_NUM_SCR + 4 + 4)
|
||||
|
||||
/* The set of LoongArch architectural features that we track that impact how
|
||||
we configure the actual gdbarch instance. We hold one of these in the
|
||||
gdbarch_tdep structure, and use it to distinguish between different
|
||||
|
@ -239,6 +239,7 @@ FEATURE_XMLFILES = aarch64-core.xml \
|
||||
loongarch/fpu.xml \
|
||||
loongarch/lsx.xml \
|
||||
loongarch/lasx.xml \
|
||||
loongarch/lbt.xml \
|
||||
riscv/rv32e-xregs.xml \
|
||||
riscv/32bit-cpu.xml \
|
||||
riscv/32bit-fpu.xml \
|
||||
|
19
gdb/features/loongarch/lbt.c
Normal file
19
gdb/features/loongarch/lbt.c
Normal file
@ -0,0 +1,19 @@
|
||||
/* THIS FILE IS GENERATED. -*- buffer-read-only: t -*- vi:set ro:
|
||||
Original: lbt.xml */
|
||||
|
||||
#include "gdbsupport/tdesc.h"
|
||||
|
||||
static int
|
||||
create_feature_loongarch_lbt (struct target_desc *result, long regnum)
|
||||
{
|
||||
struct tdesc_feature *feature;
|
||||
|
||||
feature = tdesc_create_feature (result, "org.gnu.gdb.loongarch.lbt");
|
||||
tdesc_create_reg (feature, "scr0", regnum++, 1, "lbt", 64, "uint64");
|
||||
tdesc_create_reg (feature, "scr1", regnum++, 1, "lbt", 64, "uint64");
|
||||
tdesc_create_reg (feature, "scr2", regnum++, 1, "lbt", 64, "uint64");
|
||||
tdesc_create_reg (feature, "scr3", regnum++, 1, "lbt", 64, "uint64");
|
||||
tdesc_create_reg (feature, "eflags", regnum++, 1, "lbt", 32, "uint32");
|
||||
tdesc_create_reg (feature, "ftop", regnum++, 1, "lbt", 32, "uint32");
|
||||
return regnum;
|
||||
}
|
16
gdb/features/loongarch/lbt.xml
Normal file
16
gdb/features/loongarch/lbt.xml
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- Copyright (C) 2022-2024 Free Software Foundation, Inc.
|
||||
|
||||
Copying and distribution of this file, with or without modification,
|
||||
are permitted in any medium without royalty provided the copyright
|
||||
notice and this notice are preserved. -->
|
||||
|
||||
<!DOCTYPE feature SYSTEM "gdb-target.dtd">
|
||||
<feature name="org.gnu.gdb.loongarch.lbt">
|
||||
<reg name="scr0" bitsize="64" type="uint64" group="lbt"/>
|
||||
<reg name="scr1" bitsize="64" type="uint64" group="lbt"/>
|
||||
<reg name="scr2" bitsize="64" type="uint64" group="lbt"/>
|
||||
<reg name="scr3" bitsize="64" type="uint64" group="lbt"/>
|
||||
<reg name="eflags" bitsize="32" type="uint32" group="lbt"/>
|
||||
<reg name="ftop" bitsize="32" type="uint32" group="lbt"/>
|
||||
</feature>
|
@ -265,6 +265,70 @@ store_lasxregs_to_thread (struct regcache *regcache, int regnum, pid_t tid)
|
||||
}
|
||||
|
||||
|
||||
/* Fill GDB's register array with the lbt register values
|
||||
from the current thread. */
|
||||
|
||||
static void
|
||||
fetch_lbt_from_thread (struct regcache *regcache, int regnum, pid_t tid)
|
||||
{
|
||||
gdb_byte regset[LOONGARCH_LBT_REGS_SIZE];
|
||||
|
||||
if (regnum == -1
|
||||
|| (regnum >= LOONGARCH_FIRST_SCR_REGNUM
|
||||
&& regnum <= LOONGARCH_FTOP_REGNUM))
|
||||
{
|
||||
struct iovec iov;
|
||||
|
||||
iov.iov_base = regset;
|
||||
iov.iov_len = LOONGARCH_LBT_REGS_SIZE;
|
||||
|
||||
if (ptrace (PTRACE_GETREGSET, tid, NT_LARCH_LBT, (long) &iov) < 0)
|
||||
{
|
||||
/* If kernel dose not support lbt, just return. */
|
||||
if (errno == EINVAL)
|
||||
return;
|
||||
perror_with_name (_("Couldn't get NT_LARCH_LBT registers"));
|
||||
}
|
||||
else
|
||||
loongarch_lbtregset.supply_regset (nullptr, regcache, -1,
|
||||
regset, LOONGARCH_LBT_REGS_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Store to the current thread the valid lbt register values
|
||||
in the GDB's register array. */
|
||||
|
||||
static void
|
||||
store_lbt_to_thread (struct regcache *regcache, int regnum, pid_t tid)
|
||||
{
|
||||
gdb_byte regset[LOONGARCH_LBT_REGS_SIZE];
|
||||
|
||||
if (regnum == -1
|
||||
|| (regnum >= LOONGARCH_FIRST_SCR_REGNUM
|
||||
&& regnum <= LOONGARCH_FTOP_REGNUM))
|
||||
{
|
||||
struct iovec iov;
|
||||
|
||||
iov.iov_base = regset;
|
||||
iov.iov_len = LOONGARCH_LBT_REGS_SIZE;
|
||||
|
||||
if (ptrace (PTRACE_GETREGSET, tid, NT_LARCH_LBT, (long) &iov) < 0)
|
||||
{
|
||||
/* If kernel dose not support lbt, just return. */
|
||||
if (errno == EINVAL)
|
||||
return;
|
||||
perror_with_name (_("Couldn't get NT_LARCH_LBT registers"));
|
||||
}
|
||||
else
|
||||
{
|
||||
loongarch_lbtregset.collect_regset (nullptr, regcache, regnum,
|
||||
regset, LOONGARCH_LBT_REGS_SIZE);
|
||||
if (ptrace (PTRACE_SETREGSET, tid, NT_LARCH_LBT, (long) &iov) < 0)
|
||||
perror_with_name (_("Couldn't set NT_LARCH_LBT registers"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Implement the "fetch_registers" target_ops method. */
|
||||
|
||||
void
|
||||
@ -277,6 +341,7 @@ loongarch_linux_nat_target::fetch_registers (struct regcache *regcache,
|
||||
fetch_fpregs_from_thread(regcache, regnum, tid);
|
||||
fetch_lsxregs_from_thread(regcache, regnum, tid);
|
||||
fetch_lasxregs_from_thread(regcache, regnum, tid);
|
||||
fetch_lbt_from_thread (regcache, regnum, tid);
|
||||
}
|
||||
|
||||
/* Implement the "store_registers" target_ops method. */
|
||||
@ -291,6 +356,7 @@ loongarch_linux_nat_target::store_registers (struct regcache *regcache,
|
||||
store_fpregs_to_thread(regcache, regnum, tid);
|
||||
store_lsxregs_to_thread(regcache, regnum, tid);
|
||||
store_lasxregs_to_thread(regcache, regnum, tid);
|
||||
store_lbt_to_thread (regcache, regnum, tid);
|
||||
}
|
||||
|
||||
/* Return the address in the core dump or inferior of register REGNO. */
|
||||
|
@ -338,6 +338,107 @@ const struct regset loongarch_lasxregset =
|
||||
loongarch_fill_lasxregset,
|
||||
};
|
||||
|
||||
/* Unpack an lbt regset into GDB's register cache. */
|
||||
|
||||
static void
|
||||
loongarch_supply_lbtregset (const struct regset *regset,
|
||||
struct regcache *regcache, int regnum,
|
||||
const void *regs, size_t len)
|
||||
{
|
||||
int scrsize = register_size (regcache->arch (), LOONGARCH_FIRST_SCR_REGNUM);
|
||||
int eflagssize = register_size (regcache->arch (), LOONGARCH_EFLAGS_REGNUM);
|
||||
const gdb_byte *buf = nullptr;
|
||||
|
||||
if (regnum == -1)
|
||||
{
|
||||
for (int i = 0; i < LOONGARCH_LINUX_NUM_SCR; i++)
|
||||
{
|
||||
buf = (const gdb_byte *) regs + scrsize * i;
|
||||
regcache->raw_supply (LOONGARCH_FIRST_SCR_REGNUM + i,
|
||||
(const void *) buf);
|
||||
}
|
||||
|
||||
buf = (const gdb_byte*) regs + scrsize * LOONGARCH_LINUX_NUM_SCR;
|
||||
regcache->raw_supply (LOONGARCH_EFLAGS_REGNUM, (const void *) buf);
|
||||
|
||||
buf = (const gdb_byte*) regs
|
||||
+ scrsize * LOONGARCH_LINUX_NUM_SCR
|
||||
+ eflagssize;
|
||||
regcache->raw_supply (LOONGARCH_FTOP_REGNUM, (const void *) buf);
|
||||
}
|
||||
else if (regnum >= LOONGARCH_FIRST_SCR_REGNUM
|
||||
&& regnum <= LOONGARCH_LAST_SCR_REGNUM)
|
||||
{
|
||||
buf = (const gdb_byte*) regs
|
||||
+ scrsize * (regnum - LOONGARCH_FIRST_SCR_REGNUM);
|
||||
regcache->raw_supply (regnum, (const void *) buf);
|
||||
}
|
||||
else if (regnum == LOONGARCH_EFLAGS_REGNUM)
|
||||
{
|
||||
buf = (const gdb_byte*) regs + scrsize * LOONGARCH_LINUX_NUM_SCR;
|
||||
regcache->raw_supply (regnum, (const void *) buf);
|
||||
}
|
||||
else if (regnum == LOONGARCH_FTOP_REGNUM)
|
||||
{
|
||||
buf = (const gdb_byte*) regs
|
||||
+ scrsize * LOONGARCH_LINUX_NUM_SCR
|
||||
+ eflagssize;
|
||||
regcache->raw_supply (regnum, (const void *) buf);
|
||||
}
|
||||
}
|
||||
|
||||
/* Pack the GDB's register cache value into an lbt regset. */
|
||||
|
||||
static void
|
||||
loongarch_fill_lbtregset (const struct regset *regset,
|
||||
const struct regcache *regcache, int regnum,
|
||||
void *regs, size_t len)
|
||||
{
|
||||
int scrsize = register_size (regcache->arch (), LOONGARCH_FIRST_SCR_REGNUM);
|
||||
int eflagssize = register_size (regcache->arch (), LOONGARCH_EFLAGS_REGNUM);
|
||||
gdb_byte *buf = nullptr;
|
||||
|
||||
if (regnum == -1)
|
||||
{
|
||||
for (int i = 0; i < LOONGARCH_LINUX_NUM_SCR; i++)
|
||||
{
|
||||
buf = (gdb_byte *) regs + scrsize * i;
|
||||
regcache->raw_collect (LOONGARCH_FIRST_SCR_REGNUM + i, (void *) buf);
|
||||
}
|
||||
|
||||
buf = (gdb_byte *) regs + scrsize * LOONGARCH_LINUX_NUM_SCR;
|
||||
regcache->raw_collect (LOONGARCH_EFLAGS_REGNUM, (void *) buf);
|
||||
|
||||
buf = (gdb_byte *) regs + scrsize * LOONGARCH_LINUX_NUM_SCR + eflagssize;
|
||||
regcache->raw_collect (LOONGARCH_FTOP_REGNUM, (void *) buf);
|
||||
}
|
||||
else if (regnum >= LOONGARCH_FIRST_SCR_REGNUM
|
||||
&& regnum <= LOONGARCH_LAST_SCR_REGNUM)
|
||||
{
|
||||
buf = (gdb_byte *) regs + scrsize * (regnum - LOONGARCH_FIRST_SCR_REGNUM);
|
||||
regcache->raw_collect (regnum, (void *) buf);
|
||||
}
|
||||
else if (regnum == LOONGARCH_EFLAGS_REGNUM)
|
||||
{
|
||||
buf = (gdb_byte *) regs + scrsize * LOONGARCH_LINUX_NUM_SCR;
|
||||
regcache->raw_collect (regnum, (void *) buf);
|
||||
}
|
||||
else if (regnum == LOONGARCH_FTOP_REGNUM)
|
||||
{
|
||||
buf = (gdb_byte *) regs + scrsize * LOONGARCH_LINUX_NUM_SCR + eflagssize;
|
||||
regcache->raw_collect (regnum, (void *) buf);
|
||||
}
|
||||
}
|
||||
|
||||
/* Define the lbt register regset. */
|
||||
|
||||
const struct regset loongarch_lbtregset =
|
||||
{
|
||||
nullptr,
|
||||
loongarch_supply_lbtregset,
|
||||
loongarch_fill_lbtregset,
|
||||
};
|
||||
|
||||
/* Implement the "init" method of struct tramp_frame. */
|
||||
|
||||
#define LOONGARCH_RT_SIGFRAME_UCONTEXT_OFFSET 128
|
||||
@ -394,6 +495,10 @@ loongarch_iterate_over_regset_sections (struct gdbarch *gdbarch,
|
||||
fccsize * LOONGARCH_LINUX_NUM_FCC + fcsrsize;
|
||||
int lsxrsize = register_size (gdbarch, LOONGARCH_FIRST_LSX_REGNUM);
|
||||
int lasxrsize = register_size (gdbarch, LOONGARCH_FIRST_LASX_REGNUM);
|
||||
int scrsize = register_size (gdbarch, LOONGARCH_FIRST_SCR_REGNUM);
|
||||
int eflagssize = register_size (gdbarch, LOONGARCH_EFLAGS_REGNUM);
|
||||
int ftopsize = register_size (gdbarch, LOONGARCH_FTOP_REGNUM);
|
||||
int lbtsize = scrsize * LOONGARCH_LINUX_NUM_SCR + eflagssize + ftopsize;
|
||||
|
||||
cb (".reg", LOONGARCH_LINUX_NUM_GREGSET * gprsize,
|
||||
LOONGARCH_LINUX_NUM_GREGSET * gprsize, &loongarch_gregset, nullptr, cb_data);
|
||||
@ -402,6 +507,8 @@ loongarch_iterate_over_regset_sections (struct gdbarch *gdbarch,
|
||||
&loongarch_lsxregset, nullptr, cb_data);
|
||||
cb (".reg-loongarch-lasx", lasxrsize, lasxrsize,
|
||||
&loongarch_lasxregset, nullptr, cb_data);
|
||||
cb (".reg-loongarch-lbt", lbtsize, lbtsize,
|
||||
&loongarch_lbtregset, nullptr, cb_data);
|
||||
|
||||
}
|
||||
|
||||
|
@ -1743,6 +1743,24 @@ loongarch_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
|
||||
if (!valid_p)
|
||||
return nullptr;
|
||||
|
||||
const struct tdesc_feature *feature_lbt
|
||||
= tdesc_find_feature (tdesc, "org.gnu.gdb.loongarch.lbt");
|
||||
if (feature_lbt == nullptr)
|
||||
return nullptr;
|
||||
|
||||
/* Validate the description provides the lbt registers and
|
||||
allocate their numbers. */
|
||||
regnum = LOONGARCH_FIRST_SCR_REGNUM;
|
||||
for (int i = 0; i < LOONGARCH_LINUX_NUM_SCR; i++)
|
||||
valid_p &= tdesc_numbered_register (feature_lbt, tdesc_data.get (), regnum++,
|
||||
loongarch_cr_normal_name[i] + 1);
|
||||
valid_p &= tdesc_numbered_register (feature_lbt, tdesc_data.get (), regnum++,
|
||||
"eflags");
|
||||
valid_p &= tdesc_numbered_register (feature_lbt, tdesc_data.get (), regnum++,
|
||||
"ftop");
|
||||
if (!valid_p)
|
||||
return nullptr;
|
||||
|
||||
/* LoongArch code is always little-endian. */
|
||||
info.byte_order_for_code = BFD_ENDIAN_LITTLE;
|
||||
|
||||
|
@ -32,6 +32,7 @@ extern const struct regset loongarch_gregset;
|
||||
extern const struct regset loongarch_fpregset;
|
||||
extern const struct regset loongarch_lsxregset;
|
||||
extern const struct regset loongarch_lasxregset;
|
||||
extern const struct regset loongarch_lbtregset;
|
||||
|
||||
/* Target-dependent structure in gdbarch. */
|
||||
struct loongarch_gdbarch_tdep : gdbarch_tdep_base
|
||||
|
@ -225,6 +225,47 @@ loongarch_store_lasxregset (struct regcache *regcache, const void *buf)
|
||||
supply_register (regcache, LOONGARCH_FIRST_LASX_REGNUM + i, *regset + i);
|
||||
}
|
||||
|
||||
/* Collect lbt regs from REGCACHE into BUF. */
|
||||
|
||||
static void
|
||||
loongarch_fill_lbtregset (struct regcache *regcache, void *buf)
|
||||
{
|
||||
gdb_byte *regbuf = (gdb_byte*)buf;
|
||||
int scrsize = register_size (regcache->tdesc, LOONGARCH_FIRST_SCR_REGNUM);
|
||||
int eflagssize = register_size (regcache->tdesc, LOONGARCH_EFLAGS_REGNUM);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < LOONGARCH_LINUX_NUM_SCR; i++)
|
||||
collect_register (regcache, LOONGARCH_FIRST_SCR_REGNUM + i, regbuf + scrsize * i);
|
||||
|
||||
collect_register (regcache, LOONGARCH_EFLAGS_REGNUM,
|
||||
regbuf + LOONGARCH_LINUX_NUM_SCR * scrsize);
|
||||
collect_register (regcache, LOONGARCH_FTOP_REGNUM,
|
||||
regbuf + LOONGARCH_LINUX_NUM_SCR * scrsize + eflagssize);
|
||||
|
||||
}
|
||||
|
||||
/* Supply lbt regs from BUF into REGCACHE. */
|
||||
|
||||
static void
|
||||
loongarch_store_lbtregset (struct regcache *regcache, const void *buf)
|
||||
{
|
||||
|
||||
gdb_byte *regbuf = (gdb_byte*)buf;
|
||||
int scrsize = register_size (regcache->tdesc, LOONGARCH_FIRST_SCR_REGNUM);
|
||||
int eflagssize = register_size (regcache->tdesc, LOONGARCH_EFLAGS_REGNUM);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < LOONGARCH_LINUX_NUM_SCR; i++)
|
||||
supply_register (regcache, LOONGARCH_FIRST_SCR_REGNUM + i, regbuf + scrsize * i);
|
||||
|
||||
supply_register (regcache, LOONGARCH_EFLAGS_REGNUM,
|
||||
regbuf + LOONGARCH_LINUX_NUM_SCR * scrsize);
|
||||
supply_register (regcache, LOONGARCH_FTOP_REGNUM,
|
||||
regbuf + LOONGARCH_LINUX_NUM_SCR * scrsize + eflagssize);
|
||||
|
||||
}
|
||||
|
||||
/* LoongArch/Linux regsets. */
|
||||
static struct regset_info loongarch_regsets[] = {
|
||||
{ PTRACE_GETREGSET, PTRACE_SETREGSET, NT_PRSTATUS, sizeof (elf_gregset_t),
|
||||
@ -235,6 +276,8 @@ static struct regset_info loongarch_regsets[] = {
|
||||
OPTIONAL_REGS, loongarch_fill_lsxregset, loongarch_store_lsxregset },
|
||||
{ PTRACE_GETREGSET, PTRACE_SETREGSET, NT_LARCH_LASX, sizeof (elf_lasxregset_t),
|
||||
OPTIONAL_REGS, loongarch_fill_lasxregset, loongarch_store_lasxregset },
|
||||
{ PTRACE_GETREGSET, PTRACE_SETREGSET, NT_LARCH_LBT, LOONGARCH_LBT_REGS_SIZE,
|
||||
OPTIONAL_REGS, loongarch_fill_lbtregset, loongarch_store_lbtregset },
|
||||
NULL_REGSET
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user