crash_taget: fetch_registers support

Provides API for crash_target to fetch registers of given
CPU. It will allow gdb to perform such commands as "bt",
"frame", "info locals".

Highlevel API is crash_get_cpu_reg (). It calls machine
(architecture) specific function: machdep->get_cpu_reg().
Input arguments such as register number and register size
come from gdb arch information. So, get_cpu_regs()
implementations in crash must understand it.

Signed-off-by: Alexey Makhalov <amakhalov@vmware.com>
This commit is contained in:
Alexey Makhalov 2021-03-19 21:07:33 -07:00 committed by Lianbo Jiang
parent 0b85218983
commit 2f967fb5eb
5 changed files with 163 additions and 7 deletions

View File

@ -27,6 +27,8 @@ void crash_target_init (void);
extern "C" int gdb_readmem_callback(unsigned long, void *, int, int);
extern "C" int crash_get_nr_cpus(void);
extern "C" int crash_get_cpu_reg (int cpu, int regno, const char *regname,
int regsize, void *val);
/* The crash target. */
@ -44,6 +46,7 @@ public:
const target_info &info () const override
{ return crash_target_info; }
void fetch_registers (struct regcache *, int) override;
enum target_xfer_status xfer_partial (enum target_object object,
const char *annex,
gdb_byte *readbuf,
@ -54,13 +57,35 @@ public:
bool has_all_memory () override { return true; }
bool has_memory () override { return true; }
bool has_stack () override { return true; }
bool has_registers () override { return false; }
bool has_registers () override { return true; }
bool thread_alive (ptid_t ptid) override { return true; }
std::string pid_to_str (ptid_t ptid) override
{ return string_printf ("CPU %ld", ptid.tid ()); }
};
/* We just get all the registers, so we don't use regno. */
void
crash_target::fetch_registers (struct regcache *regcache, int regno)
{
gdb_byte regval[16];
int cpu = inferior_ptid.tid();
struct gdbarch *arch = regcache->arch ();
for (int r = 0; r < gdbarch_num_regs (arch); r++)
{
const char *regname = gdbarch_register_name(arch, r);
int regsize = register_size (arch, r);
if (regsize > sizeof (regval))
error (_("fatal error: buffer size is not enough to fit register value"));
if (crash_get_cpu_reg (cpu, r, regname, regsize, (void *)&regval))
regcache->raw_supply (r, regval);
else
regcache->raw_supply (r, NULL);
}
}
enum target_xfer_status
crash_target::xfer_partial (enum target_object object, const char *annex,
@ -101,4 +126,10 @@ crash_target_init (void)
if (!i)
switch_to_thread (thread);
}
/* Fetch all registers from core file. */
target_fetch_registers (get_current_regcache (), -1);
/* Now, set up the frame cache. */
reinit_frame_cache ();
}

51
defs.h
View File

@ -1013,6 +1013,7 @@ struct machdep_table {
ulong (*processor_speed)(void);
int (*uvtop)(struct task_context *, ulong, physaddr_t *, int);
int (*kvtop)(struct task_context *, ulong, physaddr_t *, int);
int (*get_cpu_reg)(int, int, const char *, int, void *);
ulong (*get_task_pgd)(ulong);
void (*dump_irq)(int);
void (*get_stack_frame)(struct bt_info *, ulong *, ulong *);
@ -6858,6 +6859,7 @@ int vmware_vmss_get_nr_cpus(void);
int vmware_vmss_get_cr3_cr4_idtr(int, ulong *, ulong *, ulong *);
int vmware_vmss_phys_base(ulong *phys_base);
int vmware_vmss_set_phys_base(ulong);
int vmware_vmss_get_cpu_reg(int, int, const char *, int, void *);
/*
* vmware_guestdump.c
@ -7282,4 +7284,53 @@ extern int have_full_symbols(void);
#define XEN_HYPERVISOR_ARCH
#endif
/*
* Register numbers must be in sync with gdb/features/i386/64bit-core.c
* to make crash_target->fetch_registers() ---> machdep->get_cpu_reg()
* working properly.
*/
enum x86_64_regnum {
RAX_REGNUM,
RBX_REGNUM,
RCX_REGNUM,
RDX_REGNUM,
RSI_REGNUM,
RDI_REGNUM,
RBP_REGNUM,
RSP_REGNUM,
R8_REGNUM,
R9_REGNUM,
R10_REGNUM,
R11_REGNUM,
R12_REGNUM,
R13_REGNUM,
R14_REGNUM,
R15_REGNUM,
RIP_REGNUM,
EFLAGS_REGNUM,
CS_REGNUM,
SS_REGNUM,
DS_REGNUM,
ES_REGNUM,
FS_REGNUM,
GS_REGNUM,
ST0_REGNUM,
ST1_REGNUM,
ST2_REGNUM,
ST3_REGNUM,
ST4_REGNUM,
ST5_REGNUM,
ST6_REGNUM,
ST7_REGNUM,
FCTRL_REGNUM,
FSTAT_REGNUM,
FTAG_REGNUM,
FISEG_REGNUM,
FIOFF_REGNUM,
FOSEG_REGNUM,
FOOFF_REGNUM,
FOP_REGNUM,
LAST_REGNUM
};
#endif /* !GDB_COMMON */

View File

@ -698,11 +698,10 @@ static char *prohibited_list[] = {
"run", "r", "break", "b", "tbreak", "hbreak", "thbreak", "rbreak",
"watch", "rwatch", "awatch", "attach", "continue", "c", "fg", "detach",
"finish", "handle", "interrupt", "jump", "kill", "next", "nexti",
"signal", "step", "s", "stepi", "target", "thread", "until", "delete",
"clear", "disable", "enable", "condition", "ignore", "frame",
"select-frame", "f", "up", "down", "catch", "tcatch", "return",
"file", "exec-file", "core-file", "symbol-file", "load", "si", "ni",
"shell", "sy",
"signal", "step", "s", "stepi", "target", "until", "delete",
"clear", "disable", "enable", "condition", "ignore", "frame", "catch",
"tcatch", "return", "file", "exec-file", "core-file", "symbol-file",
"load", "si", "ni", "shell", "sy",
NULL /* must be last */
};
@ -1067,6 +1066,8 @@ unsigned long crash_get_kaslr_offset(void)
/* Callbacks for crash_target */
int crash_get_nr_cpus(void);
int crash_get_cpu_reg (int cpu, int regno, const char *regname,
int regsize, void *val);
int crash_get_nr_cpus(void)
{
@ -1083,3 +1084,11 @@ int crash_get_nr_cpus(void)
return 1;
}
int crash_get_cpu_reg (int cpu, int regno, const char *regname,
int regsize, void *value)
{
if (!machdep->get_cpu_reg)
return FALSE;
return machdep->get_cpu_reg(cpu, regno, regname, regsize, value);
}

View File

@ -1,7 +1,7 @@
/*
* vmware_vmss.c
*
* Copyright (c) 2015 VMware, Inc.
* Copyright (c) 2015, 2020 VMware, Inc.
* Copyright (c) 2018 Red Hat Inc.
*
* This program is free software; you can redistribute it and/or modify
@ -16,6 +16,7 @@
*
* Authors: Dyno Hongjun Fu <hfu@vmware.com>
* Sergio Lopez <slp@redhat.com>
* Alexey Makhalov <amakhalov@vmware.com>
*/
#include "defs.h"
@ -891,6 +892,54 @@ vmware_vmss_get_cr3_cr4_idtr(int cpu, ulong *cr3, ulong *cr4, ulong *idtr)
return TRUE;
}
int
vmware_vmss_get_cpu_reg(int cpu, int regno, const char *name, int size,
void *value)
{
if (cpu >= vmss.num_vcpus)
return FALSE;
/* All supported registers are 8 bytes long. */
if (size != 8)
return FALSE;
#define CASE(R,r) \
case R##_REGNUM: \
if (!(vmss.vcpu_regs[cpu] & REGS_PRESENT_##R)) \
return FALSE; \
memcpy(value, &vmss.regs64[cpu]->r, size); \
break
switch (regno) {
CASE (RAX, rax);
CASE (RBX, rbx);
CASE (RCX, rcx);
CASE (RDX, rdx);
CASE (RSI, rsi);
CASE (RDI, rdi);
CASE (RBP, rbp);
CASE (RSP, rsp);
CASE (R8, r8);
CASE (R9, r9);
CASE (R10, r10);
CASE (R11, r11);
CASE (R12, r12);
CASE (R13, r13);
CASE (R14, r14);
CASE (R15, r15);
CASE (RIP, rip);
case EFLAGS_REGNUM:
if (!(vmss.vcpu_regs[cpu] & REGS_PRESENT_RFLAGS))
return FALSE;
memcpy(value, &vmss.regs64[cpu]->rflags, size);
break;
default:
return FALSE;
}
return TRUE;
}
int
vmware_vmss_phys_base(ulong *phys_base)
{

View File

@ -126,6 +126,7 @@ static int x86_64_get_framesize(struct bt_info *, ulong, ulong);
static void x86_64_framesize_debug(struct bt_info *);
static void x86_64_get_active_set(void);
static int x86_64_get_kvaddr_ranges(struct vaddr_range *);
static int x86_64_get_cpu_reg(int, int, const char *, int, void *);
static int x86_64_verify_paddr(uint64_t);
static void GART_init(void);
static void x86_64_exception_stacks_init(void);
@ -194,6 +195,7 @@ x86_64_init(int when)
machdep->machspec->irq_eframe_link = UNINITIALIZED;
machdep->machspec->irq_stack_gap = UNINITIALIZED;
machdep->get_kvaddr_ranges = x86_64_get_kvaddr_ranges;
machdep->get_cpu_reg = x86_64_get_cpu_reg;
if (machdep->cmdline_args[0])
parse_cmdline_args();
if ((string = pc->read_vmcoreinfo("relocate"))) {
@ -884,6 +886,7 @@ x86_64_dump_machdep_table(ulong arg)
fprintf(fp, " is_page_ptr: x86_64_is_page_ptr()\n");
fprintf(fp, " verify_paddr: x86_64_verify_paddr()\n");
fprintf(fp, " get_kvaddr_ranges: x86_64_get_kvaddr_ranges()\n");
fprintf(fp, " get_cpu_reg: x86_64_get_cpu_reg()\n");
fprintf(fp, " init_kernel_pgd: x86_64_init_kernel_pgd()\n");
fprintf(fp, "clear_machdep_cache: x86_64_clear_machdep_cache()\n");
fprintf(fp, " xendump_p2m_create: %s\n", PVOPS_XEN() ?
@ -8934,6 +8937,19 @@ x86_64_get_kvaddr_ranges(struct vaddr_range *vrp)
return cnt;
}
static int
x86_64_get_cpu_reg(int cpu, int regno, const char *name,
int size, void *value)
{
if (regno >= LAST_REGNUM)
return FALSE;
if (VMSS_DUMPFILE())
return vmware_vmss_get_cpu_reg(cpu, regno, name, size, value);
return FALSE;
}
/*
* Determine the physical memory range reserved for GART.
*/