Reimplement ravenscar registers using tables
Currently, the ravenscar-thread implementation for each architecture is written by hand. However, these are actually written by copy-paste. It seems better to switch to a table-driven approach. The previous code also fetched all registers whenever any register was requested. This is corrected in the new implementation.
This commit is contained in:
parent
2808125fbb
commit
e73434e38f
7 changed files with 208 additions and 582 deletions
|
@ -61,127 +61,10 @@ static const int aarch64_context_offsets[] =
|
||||||
112, 116,
|
112, 116,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The register layout info. */
|
|
||||||
|
|
||||||
struct ravenscar_reg_info
|
|
||||||
{
|
|
||||||
/* A table providing the offset relative to the context structure
|
|
||||||
where each register is saved. */
|
|
||||||
const int *context_offsets;
|
|
||||||
|
|
||||||
/* The number of elements in the context_offsets table above. */
|
|
||||||
int context_offsets_size;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* supply register REGNUM, which has been saved on REGISTER_ADDR, to the
|
|
||||||
regcache. */
|
|
||||||
|
|
||||||
static void
|
|
||||||
supply_register_at_address (struct regcache *regcache, int regnum,
|
|
||||||
CORE_ADDR register_addr)
|
|
||||||
{
|
|
||||||
struct gdbarch *gdbarch = regcache->arch ();
|
|
||||||
int buf_size = register_size (gdbarch, regnum);
|
|
||||||
gdb_byte *buf;
|
|
||||||
|
|
||||||
buf = (gdb_byte *) alloca (buf_size);
|
|
||||||
read_memory (register_addr, buf, buf_size);
|
|
||||||
regcache->raw_supply (regnum, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return true if, for a non-running thread, REGNUM has been saved on the
|
|
||||||
Thread_Descriptor. */
|
|
||||||
|
|
||||||
static int
|
|
||||||
register_in_thread_descriptor_p (const struct ravenscar_reg_info *reg_info,
|
|
||||||
int regnum)
|
|
||||||
{
|
|
||||||
/* Check FPU registers */
|
|
||||||
return (regnum < reg_info->context_offsets_size
|
|
||||||
&& reg_info->context_offsets[regnum] != NO_OFFSET);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* to_fetch_registers when inferior_ptid is different from the running
|
|
||||||
thread. */
|
|
||||||
|
|
||||||
static void
|
|
||||||
aarch64_ravenscar_generic_fetch_registers
|
|
||||||
(const struct ravenscar_reg_info *reg_info,
|
|
||||||
struct regcache *regcache, int regnum)
|
|
||||||
{
|
|
||||||
struct gdbarch *gdbarch = regcache->arch ();
|
|
||||||
const int num_regs = gdbarch_num_regs (gdbarch);
|
|
||||||
int current_regnum;
|
|
||||||
CORE_ADDR current_address;
|
|
||||||
CORE_ADDR thread_descriptor_address;
|
|
||||||
|
|
||||||
/* The tid is the thread_id field, which is a pointer to the thread. */
|
|
||||||
thread_descriptor_address = (CORE_ADDR) inferior_ptid.tid ();
|
|
||||||
|
|
||||||
/* Read registers. */
|
|
||||||
for (current_regnum = 0; current_regnum < num_regs; current_regnum++)
|
|
||||||
{
|
|
||||||
if (register_in_thread_descriptor_p (reg_info, current_regnum))
|
|
||||||
{
|
|
||||||
current_address = thread_descriptor_address
|
|
||||||
+ reg_info->context_offsets[current_regnum];
|
|
||||||
supply_register_at_address (regcache, current_regnum,
|
|
||||||
current_address);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* to_store_registers when inferior_ptid is different from the running
|
|
||||||
thread. */
|
|
||||||
|
|
||||||
static void
|
|
||||||
aarch64_ravenscar_generic_store_registers
|
|
||||||
(const struct ravenscar_reg_info *reg_info,
|
|
||||||
struct regcache *regcache, int regnum)
|
|
||||||
{
|
|
||||||
struct gdbarch *gdbarch = regcache->arch ();
|
|
||||||
int buf_size = register_size (gdbarch, regnum);
|
|
||||||
gdb_byte buf[buf_size];
|
|
||||||
ULONGEST register_address;
|
|
||||||
|
|
||||||
if (register_in_thread_descriptor_p (reg_info, regnum))
|
|
||||||
register_address
|
|
||||||
= inferior_ptid.tid () + reg_info->context_offsets [regnum];
|
|
||||||
else
|
|
||||||
return;
|
|
||||||
|
|
||||||
regcache->raw_collect (regnum, buf);
|
|
||||||
write_memory (register_address,
|
|
||||||
buf,
|
|
||||||
buf_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The ravenscar_reg_info for most Aarch64 targets. */
|
|
||||||
|
|
||||||
static const struct ravenscar_reg_info aarch64_reg_info =
|
|
||||||
{
|
|
||||||
aarch64_context_offsets,
|
|
||||||
ARRAY_SIZE (aarch64_context_offsets),
|
|
||||||
};
|
|
||||||
|
|
||||||
struct aarch64_ravenscar_ops : public ravenscar_arch_ops
|
|
||||||
{
|
|
||||||
void fetch_registers (struct regcache *regcache, int regnum) override
|
|
||||||
{
|
|
||||||
aarch64_ravenscar_generic_fetch_registers
|
|
||||||
(&aarch64_reg_info, regcache, regnum);
|
|
||||||
}
|
|
||||||
|
|
||||||
void store_registers (struct regcache *regcache, int regnum) override
|
|
||||||
{
|
|
||||||
aarch64_ravenscar_generic_store_registers
|
|
||||||
(&aarch64_reg_info, regcache, regnum);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* The ravenscar_arch_ops vector for most Aarch64 targets. */
|
/* The ravenscar_arch_ops vector for most Aarch64 targets. */
|
||||||
|
|
||||||
static struct aarch64_ravenscar_ops aarch64_ravenscar_ops;
|
static struct ravenscar_arch_ops aarch64_ravenscar_ops
|
||||||
|
(aarch64_context_offsets);
|
||||||
|
|
||||||
/* Register aarch64_ravenscar_ops in GDBARCH. */
|
/* Register aarch64_ravenscar_ops in GDBARCH. */
|
||||||
|
|
||||||
|
|
|
@ -26,17 +26,6 @@
|
||||||
#include "ravenscar-thread.h"
|
#include "ravenscar-thread.h"
|
||||||
#include "amd64-ravenscar-thread.h"
|
#include "amd64-ravenscar-thread.h"
|
||||||
|
|
||||||
struct amd64_ravenscar_ops : public ravenscar_arch_ops
|
|
||||||
{
|
|
||||||
void fetch_registers (struct regcache *regcache, int regnum) override;
|
|
||||||
void store_registers (struct regcache *regcache, int regnum) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
/* Return the offset of the register in the context buffer. */
|
|
||||||
int register_offset (struct gdbarch *arch, int regnum);
|
|
||||||
};
|
|
||||||
|
|
||||||
/* x86-64 Ravenscar stores registers as:
|
/* x86-64 Ravenscar stores registers as:
|
||||||
|
|
||||||
type Context_Buffer is record
|
type Context_Buffer is record
|
||||||
|
@ -54,92 +43,29 @@ private:
|
||||||
*/
|
*/
|
||||||
static const int register_layout[] =
|
static const int register_layout[] =
|
||||||
{
|
{
|
||||||
AMD64_RIP_REGNUM,
|
/* RAX */ -1,
|
||||||
AMD64_EFLAGS_REGNUM,
|
/* RBX */ 3 * 8,
|
||||||
AMD64_RSP_REGNUM,
|
/* RCX */ -1,
|
||||||
AMD64_RBX_REGNUM,
|
/* RDX */ -1,
|
||||||
AMD64_RBP_REGNUM,
|
/* RSI */ -1,
|
||||||
AMD64_R12_REGNUM,
|
/* RDI */ -1,
|
||||||
AMD64_R13_REGNUM,
|
/* RBP */ 4 * 8,
|
||||||
AMD64_R14_REGNUM,
|
/* RSP */ 2 * 8,
|
||||||
AMD64_R15_REGNUM,
|
/* R8 */ -1,
|
||||||
|
/* R9 */ -1,
|
||||||
|
/* R10 */ -1,
|
||||||
|
/* R11 */ -1,
|
||||||
|
/* R12 */ 5 * 8,
|
||||||
|
/* R13 */ 6 * 8,
|
||||||
|
/* R14 */ 7 * 8,
|
||||||
|
/* R15 */ 8 * 8,
|
||||||
|
/* RIP */ 0 * 8,
|
||||||
|
/* EFLAGS */ 1 * 8,
|
||||||
};
|
};
|
||||||
|
|
||||||
int
|
|
||||||
amd64_ravenscar_ops::register_offset (struct gdbarch *arch, int regnum)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < ARRAY_SIZE (register_layout); ++i)
|
|
||||||
if (register_layout[i] == regnum)
|
|
||||||
return i * 8;
|
|
||||||
/* Not saved. */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Supply register REGNUM, which has been saved at REGISTER_ADDR, to
|
|
||||||
the regcache. */
|
|
||||||
|
|
||||||
static void
|
|
||||||
supply_register_at_address (struct regcache *regcache, int regnum,
|
|
||||||
CORE_ADDR register_addr)
|
|
||||||
{
|
|
||||||
struct gdbarch *gdbarch = regcache->arch ();
|
|
||||||
int buf_size = register_size (gdbarch, regnum);
|
|
||||||
gdb_byte *buf;
|
|
||||||
|
|
||||||
buf = (gdb_byte *) alloca (buf_size);
|
|
||||||
read_memory (register_addr, buf, buf_size);
|
|
||||||
regcache->raw_supply (regnum, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
amd64_ravenscar_ops::fetch_registers (struct regcache *regcache, int regnum)
|
|
||||||
{
|
|
||||||
struct gdbarch *gdbarch = regcache->arch ();
|
|
||||||
const int num_regs = gdbarch_num_regs (gdbarch);
|
|
||||||
int current_regnum;
|
|
||||||
CORE_ADDR current_address;
|
|
||||||
CORE_ADDR thread_descriptor_address;
|
|
||||||
|
|
||||||
/* The tid is the thread_id field, which is a pointer to the thread. */
|
|
||||||
thread_descriptor_address = (CORE_ADDR) inferior_ptid.tid ();
|
|
||||||
|
|
||||||
/* Read registers. */
|
|
||||||
for (current_regnum = 0; current_regnum < num_regs; current_regnum++)
|
|
||||||
{
|
|
||||||
int offset = register_offset (gdbarch, current_regnum);
|
|
||||||
|
|
||||||
if (offset != -1)
|
|
||||||
{
|
|
||||||
current_address = thread_descriptor_address + offset;
|
|
||||||
supply_register_at_address (regcache, current_regnum,
|
|
||||||
current_address);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
amd64_ravenscar_ops::store_registers (struct regcache *regcache, int regnum)
|
|
||||||
{
|
|
||||||
struct gdbarch *gdbarch = regcache->arch ();
|
|
||||||
int buf_size = register_size (gdbarch, regnum);
|
|
||||||
gdb_byte buf[buf_size];
|
|
||||||
CORE_ADDR register_address;
|
|
||||||
|
|
||||||
int offset = register_offset (gdbarch, regnum);
|
|
||||||
if (offset != -1)
|
|
||||||
{
|
|
||||||
register_address = inferior_ptid.tid () + offset;
|
|
||||||
|
|
||||||
regcache->raw_collect (regnum, buf);
|
|
||||||
write_memory (register_address,
|
|
||||||
buf,
|
|
||||||
buf_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The ravenscar_arch_ops vector for AMD64 targets. */
|
/* The ravenscar_arch_ops vector for AMD64 targets. */
|
||||||
|
|
||||||
static struct amd64_ravenscar_ops amd64_ravenscar_ops;
|
static struct ravenscar_arch_ops amd64_ravenscar_ops (register_layout);
|
||||||
|
|
||||||
/* Register amd64_ravenscar_ops in GDBARCH. */
|
/* Register amd64_ravenscar_ops in GDBARCH. */
|
||||||
|
|
||||||
|
|
|
@ -100,129 +100,10 @@ static const int e500_context_offsets[] =
|
||||||
NO_OFFSET, 176
|
NO_OFFSET, 176
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The register layout info. */
|
|
||||||
|
|
||||||
struct ravenscar_reg_info
|
|
||||||
{
|
|
||||||
/* A table providing the offset relative to the context structure
|
|
||||||
where each register is saved. */
|
|
||||||
const int *context_offsets;
|
|
||||||
|
|
||||||
/* The number of elements in the context_offsets table above. */
|
|
||||||
int context_offsets_size;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* supply register REGNUM, which has been saved on REGISTER_ADDR, to the
|
|
||||||
regcache. */
|
|
||||||
|
|
||||||
static void
|
|
||||||
supply_register_at_address (struct regcache *regcache, int regnum,
|
|
||||||
CORE_ADDR register_addr)
|
|
||||||
{
|
|
||||||
struct gdbarch *gdbarch = regcache->arch ();
|
|
||||||
int buf_size = register_size (gdbarch, regnum);
|
|
||||||
gdb_byte *buf;
|
|
||||||
|
|
||||||
buf = (gdb_byte *) alloca (buf_size);
|
|
||||||
read_memory (register_addr, buf, buf_size);
|
|
||||||
regcache->raw_supply (regnum, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return true if, for a non-running thread, REGNUM has been saved on the
|
|
||||||
Thread_Descriptor. */
|
|
||||||
|
|
||||||
static int
|
|
||||||
register_in_thread_descriptor_p (const struct ravenscar_reg_info *reg_info,
|
|
||||||
int regnum)
|
|
||||||
{
|
|
||||||
return (regnum < reg_info->context_offsets_size
|
|
||||||
&& reg_info->context_offsets[regnum] != NO_OFFSET);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* to_fetch_registers when inferior_ptid is different from the running
|
|
||||||
thread. */
|
|
||||||
|
|
||||||
static void
|
|
||||||
ppc_ravenscar_generic_fetch_registers
|
|
||||||
(const struct ravenscar_reg_info *reg_info,
|
|
||||||
struct regcache *regcache, int regnum)
|
|
||||||
{
|
|
||||||
struct gdbarch *gdbarch = regcache->arch ();
|
|
||||||
const int num_regs = gdbarch_num_regs (gdbarch);
|
|
||||||
int current_regnum;
|
|
||||||
CORE_ADDR current_address;
|
|
||||||
CORE_ADDR thread_descriptor_address;
|
|
||||||
|
|
||||||
/* The tid is the thread_id field, which is a pointer to the thread. */
|
|
||||||
thread_descriptor_address = (CORE_ADDR) inferior_ptid.tid ();
|
|
||||||
|
|
||||||
/* Read registers. */
|
|
||||||
for (current_regnum = 0; current_regnum < num_regs; current_regnum++)
|
|
||||||
{
|
|
||||||
if (register_in_thread_descriptor_p (reg_info, current_regnum))
|
|
||||||
{
|
|
||||||
current_address = thread_descriptor_address
|
|
||||||
+ reg_info->context_offsets[current_regnum];
|
|
||||||
supply_register_at_address (regcache, current_regnum,
|
|
||||||
current_address);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* to_store_registers when inferior_ptid is different from the running
|
|
||||||
thread. */
|
|
||||||
|
|
||||||
static void
|
|
||||||
ppc_ravenscar_generic_store_registers
|
|
||||||
(const struct ravenscar_reg_info *reg_info,
|
|
||||||
struct regcache *regcache, int regnum)
|
|
||||||
{
|
|
||||||
struct gdbarch *gdbarch = regcache->arch ();
|
|
||||||
int buf_size = register_size (gdbarch, regnum);
|
|
||||||
gdb_byte buf[buf_size];
|
|
||||||
ULONGEST register_address;
|
|
||||||
|
|
||||||
if (register_in_thread_descriptor_p (reg_info, regnum))
|
|
||||||
register_address
|
|
||||||
= inferior_ptid.tid () + reg_info->context_offsets [regnum];
|
|
||||||
else
|
|
||||||
return;
|
|
||||||
|
|
||||||
regcache->raw_collect (regnum, buf);
|
|
||||||
write_memory (register_address,
|
|
||||||
buf,
|
|
||||||
buf_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The ravenscar_reg_info for most PowerPC targets. */
|
|
||||||
|
|
||||||
static const struct ravenscar_reg_info ppc_reg_info =
|
|
||||||
{
|
|
||||||
powerpc_context_offsets,
|
|
||||||
ARRAY_SIZE (powerpc_context_offsets),
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ppc_ravenscar_powerpc_ops : public ravenscar_arch_ops
|
|
||||||
{
|
|
||||||
void fetch_registers (struct regcache *, int) override;
|
|
||||||
void store_registers (struct regcache *, int) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
|
||||||
ppc_ravenscar_powerpc_ops::fetch_registers (struct regcache *regcache, int regnum)
|
|
||||||
{
|
|
||||||
ppc_ravenscar_generic_fetch_registers (&ppc_reg_info, regcache, regnum);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ppc_ravenscar_powerpc_ops::store_registers (struct regcache *regcache, int regnum)
|
|
||||||
{
|
|
||||||
ppc_ravenscar_generic_store_registers (&ppc_reg_info, regcache, regnum);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The ravenscar_arch_ops vector for most PowerPC targets. */
|
/* The ravenscar_arch_ops vector for most PowerPC targets. */
|
||||||
|
|
||||||
static struct ppc_ravenscar_powerpc_ops ppc_ravenscar_powerpc_ops;
|
static struct ravenscar_arch_ops ppc_ravenscar_powerpc_ops
|
||||||
|
(powerpc_context_offsets);
|
||||||
|
|
||||||
/* Register ppc_ravenscar_powerpc_ops in GDBARCH. */
|
/* Register ppc_ravenscar_powerpc_ops in GDBARCH. */
|
||||||
|
|
||||||
|
@ -232,38 +113,9 @@ register_ppc_ravenscar_ops (struct gdbarch *gdbarch)
|
||||||
set_gdbarch_ravenscar_ops (gdbarch, &ppc_ravenscar_powerpc_ops);
|
set_gdbarch_ravenscar_ops (gdbarch, &ppc_ravenscar_powerpc_ops);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The ravenscar_reg_info for E500 targets. */
|
|
||||||
|
|
||||||
static const struct ravenscar_reg_info e500_reg_info =
|
|
||||||
{
|
|
||||||
e500_context_offsets,
|
|
||||||
ARRAY_SIZE (e500_context_offsets),
|
|
||||||
};
|
|
||||||
|
|
||||||
struct ppc_ravenscar_e500_ops : public ravenscar_arch_ops
|
|
||||||
{
|
|
||||||
void fetch_registers (struct regcache *, int) override;
|
|
||||||
void store_registers (struct regcache *, int) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
|
||||||
ppc_ravenscar_e500_ops::fetch_registers (struct regcache *regcache, int regnum)
|
|
||||||
{
|
|
||||||
ppc_ravenscar_generic_fetch_registers (&e500_reg_info, regcache, regnum);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Implement the to_store_registers ravenscar_arch_ops method
|
|
||||||
for E500 targets. */
|
|
||||||
|
|
||||||
void
|
|
||||||
ppc_ravenscar_e500_ops::store_registers (struct regcache *regcache, int regnum)
|
|
||||||
{
|
|
||||||
ppc_ravenscar_generic_store_registers (&e500_reg_info, regcache, regnum);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The ravenscar_arch_ops vector for E500 targets. */
|
/* The ravenscar_arch_ops vector for E500 targets. */
|
||||||
|
|
||||||
static struct ppc_ravenscar_e500_ops ppc_ravenscar_e500_ops;
|
static struct ravenscar_arch_ops ppc_ravenscar_e500_ops (e500_context_offsets);
|
||||||
|
|
||||||
/* Register ppc_ravenscar_e500_ops in GDBARCH. */
|
/* Register ppc_ravenscar_e500_ops in GDBARCH. */
|
||||||
|
|
||||||
|
|
|
@ -477,6 +477,116 @@ ravenscar_thread_target::pid_to_str (ptid_t ptid)
|
||||||
phex_nz (ptid.tid (), sizeof (ULONGEST)));
|
phex_nz (ptid.tid (), sizeof (ULONGEST)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CORE_ADDR
|
||||||
|
ravenscar_arch_ops::get_stack_base (struct regcache *regcache) const
|
||||||
|
{
|
||||||
|
struct gdbarch *gdbarch = regcache->arch ();
|
||||||
|
const int sp_regnum = gdbarch_sp_regnum (gdbarch);
|
||||||
|
ULONGEST stack_address;
|
||||||
|
regcache_cooked_read_unsigned (regcache, sp_regnum, &stack_address);
|
||||||
|
return (CORE_ADDR) stack_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ravenscar_arch_ops::supply_one_register (struct regcache *regcache,
|
||||||
|
int regnum,
|
||||||
|
CORE_ADDR descriptor,
|
||||||
|
CORE_ADDR stack_base) const
|
||||||
|
{
|
||||||
|
CORE_ADDR addr;
|
||||||
|
if (regnum >= first_stack_register && regnum <= last_stack_register)
|
||||||
|
addr = stack_base;
|
||||||
|
else
|
||||||
|
addr = descriptor;
|
||||||
|
addr += offsets[regnum];
|
||||||
|
|
||||||
|
struct gdbarch *gdbarch = regcache->arch ();
|
||||||
|
int size = register_size (gdbarch, regnum);
|
||||||
|
gdb_byte *buf = (gdb_byte *) alloca (size);
|
||||||
|
read_memory (addr, buf, size);
|
||||||
|
regcache->raw_supply (regnum, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ravenscar_arch_ops::fetch_registers (struct regcache *regcache,
|
||||||
|
int regnum) const
|
||||||
|
{
|
||||||
|
struct gdbarch *gdbarch = regcache->arch ();
|
||||||
|
/* The tid is the thread_id field, which is a pointer to the thread. */
|
||||||
|
CORE_ADDR thread_descriptor_address
|
||||||
|
= (CORE_ADDR) regcache->ptid ().tid ();
|
||||||
|
|
||||||
|
int sp_regno = -1;
|
||||||
|
CORE_ADDR stack_address = 0;
|
||||||
|
if (regnum == -1
|
||||||
|
|| (regnum >= first_stack_register && regnum <= last_stack_register))
|
||||||
|
{
|
||||||
|
/* We must supply SP for get_stack_base, so recurse. */
|
||||||
|
sp_regno = gdbarch_sp_regnum (gdbarch);
|
||||||
|
gdb_assert (!(sp_regno >= first_stack_register
|
||||||
|
&& sp_regno <= last_stack_register));
|
||||||
|
fetch_registers (regcache, sp_regno);
|
||||||
|
stack_address = get_stack_base (regcache);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (regnum == -1)
|
||||||
|
{
|
||||||
|
/* Fetch all registers. */
|
||||||
|
for (int reg = 0; reg < offsets.size (); ++reg)
|
||||||
|
if (reg != sp_regno && offsets[reg] != -1)
|
||||||
|
supply_one_register (regcache, reg, thread_descriptor_address,
|
||||||
|
stack_address);
|
||||||
|
}
|
||||||
|
else if (regnum < offsets.size () && offsets[regnum] != -1)
|
||||||
|
supply_one_register (regcache, regnum, thread_descriptor_address,
|
||||||
|
stack_address);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ravenscar_arch_ops::store_one_register (struct regcache *regcache, int regnum,
|
||||||
|
CORE_ADDR descriptor,
|
||||||
|
CORE_ADDR stack_base) const
|
||||||
|
{
|
||||||
|
CORE_ADDR addr;
|
||||||
|
if (regnum >= first_stack_register && regnum <= last_stack_register)
|
||||||
|
addr = stack_base;
|
||||||
|
else
|
||||||
|
addr = descriptor;
|
||||||
|
addr += offsets[regnum];
|
||||||
|
|
||||||
|
struct gdbarch *gdbarch = regcache->arch ();
|
||||||
|
int size = register_size (gdbarch, regnum);
|
||||||
|
gdb_byte *buf = (gdb_byte *) alloca (size);
|
||||||
|
regcache->raw_collect (regnum, buf);
|
||||||
|
write_memory (addr, buf, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ravenscar_arch_ops::store_registers (struct regcache *regcache,
|
||||||
|
int regnum) const
|
||||||
|
{
|
||||||
|
/* The tid is the thread_id field, which is a pointer to the thread. */
|
||||||
|
CORE_ADDR thread_descriptor_address
|
||||||
|
= (CORE_ADDR) regcache->ptid ().tid ();
|
||||||
|
|
||||||
|
CORE_ADDR stack_address = 0;
|
||||||
|
if (regnum == -1
|
||||||
|
|| (regnum >= first_stack_register && regnum <= last_stack_register))
|
||||||
|
stack_address = get_stack_base (regcache);
|
||||||
|
|
||||||
|
if (regnum == -1)
|
||||||
|
{
|
||||||
|
/* Store all registers. */
|
||||||
|
for (int reg = 0; reg < offsets.size (); ++reg)
|
||||||
|
if (offsets[reg] != -1)
|
||||||
|
store_one_register (regcache, reg, thread_descriptor_address,
|
||||||
|
stack_address);
|
||||||
|
}
|
||||||
|
else if (regnum < offsets.size () && offsets[regnum] != -1)
|
||||||
|
store_one_register (regcache, regnum, thread_descriptor_address,
|
||||||
|
stack_address);
|
||||||
|
}
|
||||||
|
|
||||||
/* Temporarily set the ptid of a regcache to some other value. When
|
/* Temporarily set the ptid of a regcache to some other value. When
|
||||||
this object is destroyed, the regcache's original ptid is
|
this object is destroyed, the regcache's original ptid is
|
||||||
restored. */
|
restored. */
|
||||||
|
@ -506,7 +616,8 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
ravenscar_thread_target::fetch_registers (struct regcache *regcache, int regnum)
|
ravenscar_thread_target::fetch_registers (struct regcache *regcache,
|
||||||
|
int regnum)
|
||||||
{
|
{
|
||||||
ptid_t ptid = regcache->ptid ();
|
ptid_t ptid = regcache->ptid ();
|
||||||
|
|
||||||
|
|
|
@ -24,12 +24,48 @@
|
||||||
|
|
||||||
struct ravenscar_arch_ops
|
struct ravenscar_arch_ops
|
||||||
{
|
{
|
||||||
virtual ~ravenscar_arch_ops ()
|
ravenscar_arch_ops (gdb::array_view<const int> offsets_,
|
||||||
|
int first_stack = -1,
|
||||||
|
int last_stack = -1)
|
||||||
|
: offsets (offsets_),
|
||||||
|
first_stack_register (first_stack),
|
||||||
|
last_stack_register (last_stack)
|
||||||
{
|
{
|
||||||
|
/* These must either both be -1 or both be valid. */
|
||||||
|
gdb_assert ((first_stack_register == -1) == (last_stack_register == -1));
|
||||||
|
/* They must also be ordered. */
|
||||||
|
gdb_assert (last_stack_register >= first_stack_register);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void fetch_registers (struct regcache *, int) = 0;
|
void fetch_registers (struct regcache *, int) const;
|
||||||
virtual void store_registers (struct regcache *, int) = 0;
|
void store_registers (struct regcache *, int) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/* An array where the indices are register numbers and the contents
|
||||||
|
are offsets. The offsets are either in the thread descriptor or
|
||||||
|
the stack, depending on the other fields. An offset of -1 means
|
||||||
|
that the corresponding register is not stored. */
|
||||||
|
const gdb::array_view<const int> offsets;
|
||||||
|
|
||||||
|
/* If these are -1, then all registers for this architecture are
|
||||||
|
stored in the thread descriptor. Otherwise, these mark a range
|
||||||
|
of registers that are stored on the stack. */
|
||||||
|
const int first_stack_register;
|
||||||
|
const int last_stack_register;
|
||||||
|
|
||||||
|
/* Helper function to supply one register. */
|
||||||
|
void supply_one_register (struct regcache *regcache, int regnum,
|
||||||
|
CORE_ADDR descriptor,
|
||||||
|
CORE_ADDR stack_base) const;
|
||||||
|
/* Helper function to store one register. */
|
||||||
|
void store_one_register (struct regcache *regcache, int regnum,
|
||||||
|
CORE_ADDR descriptor,
|
||||||
|
CORE_ADDR stack_base) const;
|
||||||
|
/* Helper function to find stack address where registers are stored.
|
||||||
|
This must be called with the stack pointer already supplied in
|
||||||
|
the register cache. */
|
||||||
|
CORE_ADDR get_stack_base (struct regcache *) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* !defined (RAVENSCAR_THREAD_H) */
|
#endif /* !defined (RAVENSCAR_THREAD_H) */
|
||||||
|
|
|
@ -26,20 +26,22 @@
|
||||||
#include "ravenscar-thread.h"
|
#include "ravenscar-thread.h"
|
||||||
#include "riscv-ravenscar-thread.h"
|
#include "riscv-ravenscar-thread.h"
|
||||||
|
|
||||||
|
#define LAST_REGISTER (RISCV_FIRST_FP_REGNUM + 14)
|
||||||
|
|
||||||
struct riscv_ravenscar_ops : public ravenscar_arch_ops
|
struct riscv_ravenscar_ops : public ravenscar_arch_ops
|
||||||
{
|
{
|
||||||
void fetch_registers (struct regcache *regcache, int regnum) override;
|
int reg_offsets[LAST_REGISTER + 1];
|
||||||
void store_registers (struct regcache *regcache, int regnum) override;
|
|
||||||
|
|
||||||
private:
|
riscv_ravenscar_ops (struct gdbarch *arch);
|
||||||
|
|
||||||
/* Return the offset of the register in the context buffer. */
|
|
||||||
int register_offset (struct gdbarch *arch, int regnum);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
int
|
riscv_ravenscar_ops::riscv_ravenscar_ops (struct gdbarch *arch)
|
||||||
riscv_ravenscar_ops::register_offset (struct gdbarch *arch, int regnum)
|
: ravenscar_arch_ops (gdb::make_array_view (reg_offsets, LAST_REGISTER + 1))
|
||||||
{
|
{
|
||||||
|
int reg_size = riscv_isa_xlen (arch);
|
||||||
|
|
||||||
|
for (int regnum = 0; regnum <= LAST_REGISTER; ++regnum)
|
||||||
|
{
|
||||||
int offset;
|
int offset;
|
||||||
if (regnum == RISCV_RA_REGNUM || regnum == RISCV_PC_REGNUM)
|
if (regnum == RISCV_RA_REGNUM || regnum == RISCV_PC_REGNUM)
|
||||||
offset = 0;
|
offset = 0;
|
||||||
|
@ -56,85 +58,19 @@ riscv_ravenscar_ops::register_offset (struct gdbarch *arch, int regnum)
|
||||||
&& regnum <= RISCV_FIRST_FP_REGNUM + 11)
|
&& regnum <= RISCV_FIRST_FP_REGNUM + 11)
|
||||||
offset = regnum - RISCV_FIRST_FP_REGNUM + 14; /* FS0..FS11 */
|
offset = regnum - RISCV_FIRST_FP_REGNUM + 14; /* FS0..FS11 */
|
||||||
else
|
else
|
||||||
{
|
offset = -1;
|
||||||
/* Not saved. */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int size = register_size (arch, regnum);
|
|
||||||
return offset * size;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Supply register REGNUM, which has been saved on REGISTER_ADDR, to the
|
|
||||||
regcache. */
|
|
||||||
|
|
||||||
static void
|
|
||||||
supply_register_at_address (struct regcache *regcache, int regnum,
|
|
||||||
CORE_ADDR register_addr)
|
|
||||||
{
|
|
||||||
struct gdbarch *gdbarch = regcache->arch ();
|
|
||||||
int buf_size = register_size (gdbarch, regnum);
|
|
||||||
gdb_byte *buf;
|
|
||||||
|
|
||||||
buf = (gdb_byte *) alloca (buf_size);
|
|
||||||
read_memory (register_addr, buf, buf_size);
|
|
||||||
regcache->raw_supply (regnum, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
riscv_ravenscar_ops::fetch_registers (struct regcache *regcache, int regnum)
|
|
||||||
{
|
|
||||||
struct gdbarch *gdbarch = regcache->arch ();
|
|
||||||
const int num_regs = gdbarch_num_regs (gdbarch);
|
|
||||||
int current_regnum;
|
|
||||||
CORE_ADDR current_address;
|
|
||||||
CORE_ADDR thread_descriptor_address;
|
|
||||||
|
|
||||||
/* The tid is the thread_id field, which is a pointer to the thread. */
|
|
||||||
thread_descriptor_address = (CORE_ADDR) inferior_ptid.tid ();
|
|
||||||
|
|
||||||
/* Read registers. */
|
|
||||||
for (current_regnum = 0; current_regnum < num_regs; current_regnum++)
|
|
||||||
{
|
|
||||||
int offset = register_offset (gdbarch, current_regnum);
|
|
||||||
|
|
||||||
if (offset != -1)
|
if (offset != -1)
|
||||||
{
|
offset *= reg_size;
|
||||||
current_address = thread_descriptor_address + offset;
|
|
||||||
supply_register_at_address (regcache, current_regnum,
|
reg_offsets[regnum] = offset;
|
||||||
current_address);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
riscv_ravenscar_ops::store_registers (struct regcache *regcache, int regnum)
|
|
||||||
{
|
|
||||||
struct gdbarch *gdbarch = regcache->arch ();
|
|
||||||
int buf_size = register_size (gdbarch, regnum);
|
|
||||||
gdb_byte buf[buf_size];
|
|
||||||
CORE_ADDR register_address;
|
|
||||||
|
|
||||||
int offset = register_offset (gdbarch, regnum);
|
|
||||||
if (offset != -1)
|
|
||||||
{
|
|
||||||
register_address = inferior_ptid.tid () + offset;
|
|
||||||
|
|
||||||
regcache->raw_collect (regnum, buf);
|
|
||||||
write_memory (register_address,
|
|
||||||
buf,
|
|
||||||
buf_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The ravenscar_arch_ops vector for most RISC-V targets. */
|
|
||||||
|
|
||||||
static struct riscv_ravenscar_ops riscv_ravenscar_ops;
|
|
||||||
|
|
||||||
/* Register riscv_ravenscar_ops in GDBARCH. */
|
/* Register riscv_ravenscar_ops in GDBARCH. */
|
||||||
|
|
||||||
void
|
void
|
||||||
register_riscv_ravenscar_ops (struct gdbarch *gdbarch)
|
register_riscv_ravenscar_ops (struct gdbarch *gdbarch)
|
||||||
{
|
{
|
||||||
set_gdbarch_ravenscar_ops (gdbarch, &riscv_ravenscar_ops);
|
set_gdbarch_ravenscar_ops (gdbarch, new riscv_ravenscar_ops (gdbarch));
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,12 +26,6 @@
|
||||||
#include "sparc-ravenscar-thread.h"
|
#include "sparc-ravenscar-thread.h"
|
||||||
#include "gdbarch.h"
|
#include "gdbarch.h"
|
||||||
|
|
||||||
struct sparc_ravenscar_ops : public ravenscar_arch_ops
|
|
||||||
{
|
|
||||||
void fetch_registers (struct regcache *, int) override;
|
|
||||||
void store_registers (struct regcache *, int) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Register offsets from a referenced address (exempli gratia the
|
/* Register offsets from a referenced address (exempli gratia the
|
||||||
Thread_Descriptor). The referenced address depends on the register
|
Thread_Descriptor). The referenced address depends on the register
|
||||||
number. The Thread_Descriptor layout and the stack layout are documented
|
number. The Thread_Descriptor layout and the stack layout are documented
|
||||||
|
@ -56,121 +50,9 @@ static const int sparc_register_offsets[] =
|
||||||
0x40, 0x20, 0x44, -1, 0x1C, -1, 0x4C, -1
|
0x40, 0x20, 0x44, -1, 0x1C, -1, 0x4C, -1
|
||||||
};
|
};
|
||||||
|
|
||||||
/* supply register REGNUM, which has been saved on REGISTER_ADDR, to the
|
static struct ravenscar_arch_ops sparc_ravenscar_ops (sparc_register_offsets,
|
||||||
regcache. */
|
SPARC_L0_REGNUM,
|
||||||
|
SPARC_I7_REGNUM);
|
||||||
static void
|
|
||||||
supply_register_at_address (struct regcache *regcache, int regnum,
|
|
||||||
CORE_ADDR register_addr)
|
|
||||||
{
|
|
||||||
struct gdbarch *gdbarch = regcache->arch ();
|
|
||||||
int buf_size = register_size (gdbarch, regnum);
|
|
||||||
gdb_byte *buf;
|
|
||||||
|
|
||||||
buf = (gdb_byte *) alloca (buf_size);
|
|
||||||
read_memory (register_addr, buf, buf_size);
|
|
||||||
regcache->raw_supply (regnum, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return true if, for a non-running thread, REGNUM has been saved on the
|
|
||||||
stack. */
|
|
||||||
|
|
||||||
static int
|
|
||||||
register_on_stack_p (int regnum)
|
|
||||||
{
|
|
||||||
return (regnum >= SPARC_L0_REGNUM && regnum <= SPARC_L7_REGNUM)
|
|
||||||
|| (regnum >= SPARC_I0_REGNUM && regnum <= SPARC_I7_REGNUM);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return true if, for a non-running thread, REGNUM has been saved on the
|
|
||||||
Thread_Descriptor. */
|
|
||||||
|
|
||||||
static int
|
|
||||||
register_in_thread_descriptor_p (int regnum)
|
|
||||||
{
|
|
||||||
return (regnum >= SPARC_O0_REGNUM && regnum <= SPARC_O7_REGNUM)
|
|
||||||
|| (regnum == SPARC32_PSR_REGNUM)
|
|
||||||
|| (regnum >= SPARC_G1_REGNUM && regnum <= SPARC_G7_REGNUM)
|
|
||||||
|| (regnum == SPARC32_Y_REGNUM)
|
|
||||||
|| (regnum == SPARC32_WIM_REGNUM)
|
|
||||||
|| (regnum == SPARC32_FSR_REGNUM)
|
|
||||||
|| (regnum >= SPARC_F0_REGNUM && regnum <= SPARC_F0_REGNUM + 31)
|
|
||||||
|| (regnum == SPARC32_PC_REGNUM);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* to_fetch_registers when inferior_ptid is different from the running
|
|
||||||
thread. */
|
|
||||||
|
|
||||||
void
|
|
||||||
sparc_ravenscar_ops::fetch_registers (struct regcache *regcache, int regnum)
|
|
||||||
{
|
|
||||||
struct gdbarch *gdbarch = regcache->arch ();
|
|
||||||
const int sp_regnum = gdbarch_sp_regnum (gdbarch);
|
|
||||||
const int num_regs = gdbarch_num_regs (gdbarch);
|
|
||||||
int current_regnum;
|
|
||||||
CORE_ADDR current_address;
|
|
||||||
CORE_ADDR thread_descriptor_address;
|
|
||||||
ULONGEST stack_address;
|
|
||||||
|
|
||||||
/* The tid is the thread_id field, which is a pointer to the thread. */
|
|
||||||
thread_descriptor_address = (CORE_ADDR) inferior_ptid.tid ();
|
|
||||||
|
|
||||||
/* Read the saved SP in the context buffer. */
|
|
||||||
current_address = thread_descriptor_address
|
|
||||||
+ sparc_register_offsets [sp_regnum];
|
|
||||||
supply_register_at_address (regcache, sp_regnum, current_address);
|
|
||||||
regcache_cooked_read_unsigned (regcache, sp_regnum, &stack_address);
|
|
||||||
|
|
||||||
/* Read registers. */
|
|
||||||
for (current_regnum = 0; current_regnum < num_regs; current_regnum ++)
|
|
||||||
{
|
|
||||||
if (register_in_thread_descriptor_p (current_regnum))
|
|
||||||
{
|
|
||||||
current_address = thread_descriptor_address
|
|
||||||
+ sparc_register_offsets [current_regnum];
|
|
||||||
supply_register_at_address (regcache, current_regnum,
|
|
||||||
current_address);
|
|
||||||
}
|
|
||||||
else if (register_on_stack_p (current_regnum))
|
|
||||||
{
|
|
||||||
current_address = stack_address
|
|
||||||
+ sparc_register_offsets [current_regnum];
|
|
||||||
supply_register_at_address (regcache, current_regnum,
|
|
||||||
current_address);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* to_store_registers when inferior_ptid is different from the running
|
|
||||||
thread. */
|
|
||||||
|
|
||||||
void
|
|
||||||
sparc_ravenscar_ops::store_registers (struct regcache *regcache, int regnum)
|
|
||||||
{
|
|
||||||
struct gdbarch *gdbarch = regcache->arch ();
|
|
||||||
int buf_size = register_size (gdbarch, regnum);
|
|
||||||
gdb_byte buf[buf_size];
|
|
||||||
ULONGEST register_address;
|
|
||||||
|
|
||||||
if (register_in_thread_descriptor_p (regnum))
|
|
||||||
register_address =
|
|
||||||
inferior_ptid.tid () + sparc_register_offsets [regnum];
|
|
||||||
else if (register_on_stack_p (regnum))
|
|
||||||
{
|
|
||||||
regcache_cooked_read_unsigned (regcache, SPARC_SP_REGNUM,
|
|
||||||
®ister_address);
|
|
||||||
register_address += sparc_register_offsets [regnum];
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return;
|
|
||||||
|
|
||||||
regcache->raw_collect (regnum, buf);
|
|
||||||
write_memory (register_address,
|
|
||||||
buf,
|
|
||||||
buf_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct sparc_ravenscar_ops sparc_ravenscar_ops;
|
|
||||||
|
|
||||||
/* Register ravenscar_arch_ops in GDBARCH. */
|
/* Register ravenscar_arch_ops in GDBARCH. */
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue