[Crash-utility] [PATCH v3 2/2] crash_taget: fetch_registers support

Alexey Makhalov amakhalov at vmware.com
Tue Dec 29 10:06:09 UTC 2020


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 at vmware.com>
---
 crash_target.c  | 33 ++++++++++++++++++++++++++++++++-
 defs.h          | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb_interface.c | 18 +++++++++++++-----
 vmware_vmss.c   | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 x86_64.c        | 16 ++++++++++++++++
 5 files changed, 164 insertions(+), 7 deletions(-)

diff --git a/crash_target.c b/crash_target.c
index 5f1c08e..b8796ec 100644
--- a/crash_target.c
+++ b/crash_target.c
@@ -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,7 +57,7 @@ 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 ()); }
@@ -62,6 +65,28 @@ public:
 };
 
 
+/* 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,
 			   gdb_byte *readbuf, const gdb_byte *writebuf,
@@ -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 ();
 }
diff --git a/defs.h b/defs.h
index 169d4dc..704c14a 100644
--- a/defs.h
+++ b/defs.h
@@ -1000,6 +1000,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 *);
@@ -6706,6 +6707,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
@@ -7130,4 +7132,55 @@ extern int have_full_symbols(void);
 #define XEN_HYPERVISOR_ARCH 
 #endif
 
+#if defined(X86_64)
+/*
+ * 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
+
 #endif /* !GDB_COMMON */
diff --git a/gdb_interface.c b/gdb_interface.c
index c1ba5e0..6115db3 100644
--- a/gdb_interface.c
+++ b/gdb_interface.c
@@ -698,10 +698,9 @@ is_gdb_command(int merge_orig_args, ulong flags)
 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",
+	"finish", "handle", "interrupt", "jump", "kill", "next", "nexti", "signal",
+	"step", "s", "stepi", "target", "until", "delete", "clear", "disable",
+	"enable", "condition", "ignore", "catch", "tcatch", "return",
 	"file", "exec-file", "core-file", "symbol-file", "load", "si", "ni", 
 	"shell", 
 	NULL  /* must be last */
@@ -1056,7 +1055,6 @@ get_frame_offset(ulong pc)
 }
 #endif /* !ALPHA */ 
 
-
 unsigned long crash_get_kaslr_offset(void);
 unsigned long crash_get_kaslr_offset(void)
 {
@@ -1065,6 +1063,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)
 {
@@ -1081,3 +1081,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);
+}
+
diff --git a/vmware_vmss.c b/vmware_vmss.c
index 52d58e8..fbd94bd 100644
--- a/vmware_vmss.c
+++ b/vmware_vmss.c
@@ -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 at vmware.com>
  *          Sergio Lopez <slp at redhat.com>
+ *          Alexey Makhalov <amakhalov at vmware.com>
  */
 
 #include "defs.h"
@@ -892,6 +893,54 @@ vmware_vmss_get_cr3_cr4_idtr(int cpu, ulong *cr3, ulong *cr4, ulong *idtr)
 }
 
 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)
 {
 	*phys_base = vmss.phys_base;
diff --git a/x86_64.c b/x86_64.c
index 62a8563..8b5d2c2 100644
--- a/x86_64.c
+++ b/x86_64.c
@@ -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);
@@ -191,6 +192,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"))) {
@@ -875,6 +877,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() ?
@@ -8883,6 +8886,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.
  */
-- 
2.11.0




More information about the Crash-utility mailing list