[PATCH] vmware_guestdump: new input format
by Alexey Makhalov
vmware_guestdump is extension to vmware_vmss with ability to debug
debug.guest and debug.vmem files.
debug.guest.gz and debug.vmem.gz can be obtained using following
.vmx options from VM running in debug mode:
monitor.mini-suspend_on_panic = TRUE
monitor.suspend_on_triplefault = TRUE
guestdump (debug.guest) is simplified version of *.vmss which does
not contain full VM state, but minimal guest state, such as memory
layout and CPUs state, needed for debugger. is_vmware_guestdump()
and vmware_guestdump_init() functions parse guestdump header and
populate vmss data structure (from vmware_vmss.c). As result, all
handlers (except mempry_dump) from vmware_vmss.c can be reused.
How to use: $ crash debug.guest vmlinux
debug.vmem must be present in the same folder as debug.guest.
Signed-off-by: Alexey Makhalov <amakhalov(a)vmware.com>
---
Makefile | 7 +-
defs.h | 8 ++
filesys.c | 12 ++-
main.c | 14 +++
memory.c | 8 +-
vmware_guestdump.c | 308 +++++++++++++++++++++++++++++++++++++++++++++++++++++
vmware_vmss.c | 8 +-
vmware_vmss.h | 8 ++
8 files changed, 359 insertions(+), 14 deletions(-)
create mode 100644 vmware_guestdump.c
diff --git a/Makefile b/Makefile
index 7455410..d185719 100644
--- a/Makefile
+++ b/Makefile
@@ -70,7 +70,7 @@ CFILES=main.c tools.c global_data.c memory.c filesys.c help.c task.c \
unwind_x86_32_64.c unwind_arm.c \
xen_hyper.c xen_hyper_command.c xen_hyper_global_data.c \
xen_hyper_dump_tables.c kvmdump.c qemu.c qemu-load.c sadump.c ipcs.c \
- ramdump.c vmware_vmss.c \
+ ramdump.c vmware_vmss.c vmware_guestdump.c \
xen_dom0.c kaslr_helper.c
SOURCE_FILES=${CFILES} ${GENERIC_HFILES} ${MCORE_HFILES} \
@@ -89,7 +89,7 @@ OBJECT_FILES=main.o tools.o global_data.o memory.o filesys.o help.o task.o \
unwind_x86_32_64.o unwind_arm.o \
xen_hyper.o xen_hyper_command.o xen_hyper_global_data.o \
xen_hyper_dump_tables.o kvmdump.o qemu.o qemu-load.o sadump.o ipcs.o \
- ramdump.o vmware_vmss.o \
+ ramdump.o vmware_vmss.o vmware_guestdump.o \
xen_dom0.o kaslr_helper.o
MEMORY_DRIVER_FILES=memory_driver/Makefile memory_driver/crash.c memory_driver/README
@@ -518,6 +518,9 @@ ramdump.o: ${GENERIC_HFILES} ${REDHAT_HFILES} ramdump.c
vmware_vmss.o: ${GENERIC_HFILES} ${VMWARE_HFILES} vmware_vmss.c
${CC} -c ${CRASH_CFLAGS} vmware_vmss.c ${WARNING_OPTIONS} ${WARNING_ERROR}
+vmware_guestdump.o: ${GENERIC_HFILES} ${VMWARE_HFILES} vmware_guestdump.c
+ ${CC} -c ${CRASH_CFLAGS} vmware_guestdump.c ${WARNING_OPTIONS} ${WARNING_ERROR}
+
kaslr_helper.o: ${GENERIC_HFILES} kaslr_helper.c
${CC} -c ${CRASH_CFLAGS} kaslr_helper.c ${WARNING_OPTIONS} ${WARNING_ERROR}
diff --git a/defs.h b/defs.h
index c899fe2..f61f864 100644
--- a/defs.h
+++ b/defs.h
@@ -655,6 +655,7 @@ struct new_utsname {
#define IRQ_DESC_TREE_RADIX (0x40ULL)
#define IRQ_DESC_TREE_XARRAY (0x80ULL)
#define KMOD_PAX (0x100ULL)
+#define VMWARE_VMSS_GUESTDUMP (0x200ULL)
#define XEN() (kt->flags & ARCH_XEN)
#define OPENVZ() (kt->flags & ARCH_OPENVZ)
@@ -6679,6 +6680,13 @@ int vmware_vmss_phys_base(ulong *phys_base);
int vmware_vmss_set_phys_base(ulong);
/*
+ * vmware_guestdump.c
+ */
+int is_vmware_guestdump(char *filename);
+int vmware_guestdump_init(char *filename, FILE *ofp);
+int vmware_guestdump_memory_dump(FILE *);
+
+/*
* kaslr_helper.c
*/
int calc_kaslr_offset(ulong *, ulong *);
diff --git a/filesys.c b/filesys.c
index 2ec2b31..3361b6c 100644
--- a/filesys.c
+++ b/filesys.c
@@ -253,9 +253,15 @@ memory_source_init(void)
error(FATAL, "%s: initialization failed\n",
pc->dumpfile);
} else if (pc->flags & VMWARE_VMSS) {
- if (!vmware_vmss_init(pc->dumpfile, fp))
- error(FATAL, "%s: initialization failed\n",
- pc->dumpfile);
+ if (pc->flags2 & VMWARE_VMSS_GUESTDUMP) {
+ if (!vmware_guestdump_init(pc->dumpfile, fp))
+ error(FATAL, "%s: initialization failed\n",
+ pc->dumpfile);
+ } else {
+ if (!vmware_vmss_init(pc->dumpfile, fp))
+ error(FATAL, "%s: initialization failed\n",
+ pc->dumpfile);
+ }
}
}
}
diff --git a/main.c b/main.c
index 7f562e6..388ac46 100644
--- a/main.c
+++ b/main.c
@@ -671,6 +671,18 @@ main(int argc, char **argv)
pc->readmem = read_vmware_vmss;
pc->writemem = write_vmware_vmss;
+ } else if (is_vmware_guestdump(argv[optind])) {
+ if (pc->flags & MEMORY_SOURCES) {
+ error(INFO,
+ "too many dumpfile arguments\n");
+ program_usage(SHORT_FORM);
+ }
+ pc->flags |= VMWARE_VMSS;
+ pc->flags2 |= VMWARE_VMSS_GUESTDUMP;
+ pc->dumpfile = argv[optind];
+ pc->readmem = read_vmware_vmss;
+ pc->writemem = write_vmware_vmss;
+
} else {
error(INFO,
"%s: not a supported file format\n",
@@ -1486,6 +1498,8 @@ dump_program_context(void)
fprintf(fp, "%sMEMSRC_LOCAL", others++ ? "|" : "");
if (pc->flags2 & REDZONE)
fprintf(fp, "%sREDZONE", others++ ? "|" : "");
+ if (pc->flags2 & VMWARE_VMSS_GUESTDUMP)
+ fprintf(fp, "%sVMWARE_VMSS_GUESTDUMP", others++ ? "|" : "");
fprintf(fp, ")\n");
fprintf(fp, " namelist: %s\n", pc->namelist);
diff --git a/memory.c b/memory.c
index c951827..0848097 100644
--- a/memory.c
+++ b/memory.c
@@ -17115,8 +17115,12 @@ dumpfile_memory(int cmd)
retval = kcore_memory_dump(fp);
else if (pc->flags & SADUMP)
retval = sadump_memory_dump(fp);
- else if (pc->flags & VMWARE_VMSS)
- retval = vmware_vmss_memory_dump(fp);
+ else if (pc->flags & VMWARE_VMSS) {
+ if (pc->flags2 & VMWARE_VMSS_GUESTDUMP)
+ retval = vmware_guestdump_memory_dump(fp);
+ else
+ retval = vmware_vmss_memory_dump(fp);
+ }
break;
case DUMPFILE_ENVIRONMENT:
diff --git a/vmware_guestdump.c b/vmware_guestdump.c
new file mode 100644
index 0000000..45acb7a
--- /dev/null
+++ b/vmware_guestdump.c
@@ -0,0 +1,308 @@
+/*
+ * vmware_guestdump.c
+ *
+ * Copyright (c) 2020 VMware, Inc.
+ *
+ * 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 2 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.
+ *
+ * Author: Alexey Makhalov <amakhalov(a)vmware.com>
+ */
+
+#include "defs.h"
+#include "vmware_vmss.h"
+
+#define LOGPRX "vmw: "
+
+#define GUESTDUMP_VERSION 4
+#define GUESTDUMP_MAGIC1 1
+#define GUESTDUMP_MAGIC2 0
+
+struct guestdumpheader {
+ uint32_t version;
+ uint32_t num_vcpus;
+ uint8_t magic1;
+ uint8_t reserved1;
+ uint32_t cpu_vendor;
+ uint64_t magic2;
+ uint64_t last_addr;
+ uint64_t memsize_in_pages;
+ uint32_t reserved2;
+ uint32_t mem_holes;
+ struct memhole {
+ uint64_t ppn;
+ uint64_t pages;
+ } holes[2];
+} __attribute__((packed));
+
+struct vcpu_state {
+ uint32_t cr0;
+ uint64_t cr2;
+ uint64_t cr3;
+ uint64_t cr4;
+ uint64_t reserved1[10];
+ uint64_t idt_base;
+ uint16_t reserved2[21];
+ struct x86_64_pt_regs {
+ uint64_t r15;
+ uint64_t r14;
+ uint64_t r13;
+ uint64_t r12;
+ uint64_t rbp;
+ uint64_t rbx;
+ uint64_t r11;
+ uint64_t r10;
+ uint64_t r9;
+ uint64_t r8;
+ uint64_t rax;
+ uint64_t rcx;
+ uint64_t rdx;
+ uint64_t rsi;
+ uint64_t rdi;
+ uint64_t orig_rax;
+ uint64_t rip;
+ uint64_t cs;
+ uint64_t eflags;
+ uint64_t rsp;
+ uint64_t ss;
+ } regs64;
+ uint8_t reserved3[65];
+} __attribute__((packed));
+
+
+/*
+ * vmware_guestdump is an extension to vmware_vmss with ability to debug
+ * debug.guest and debug.vmem files.
+ *
+ * debug.guest.gz and debug.vmem.gz can be obtained using following
+ * .vmx options from VM running in debug mode:
+ * monitor.mini-suspend_on_panic = TRUE
+ * monitor.suspend_on_triplefault = TRUE
+ *
+ * guestdump (debug.guest) is simplified version of *.vmss which does
+ * not contain full VM state, but minimal guest state, such as memory
+ * layout and CPUs state, needed for debugger. is_vmware_guestdump()
+ * and vmware_guestdump_init() functions parse guestdump header and
+ * populate vmss data structure (from vmware_vmss.c). As result, all
+ * handlers (except mempry_dump) from vmware_vmss.c can be reused.
+ *
+ */
+
+int
+is_vmware_guestdump(char *filename)
+{
+ struct guestdumpheader hdr;
+ FILE *fp;
+ uint64_t filesize, holes_sum = 0;
+ int i;
+
+ if (strcmp(basename(filename), "debug.guest"))
+ return FALSE;
+
+ if ((fp = fopen(filename, "r")) == NULL) {
+ error(INFO, LOGPRX"Failed to open '%s': [Error %d] %s\n",
+ filename, errno, strerror(errno));
+ return FALSE;
+ }
+
+ if (fread(&hdr, sizeof(struct guestdumpheader), 1, fp) != 1) {
+ error(INFO, LOGPRX"Failed to read '%s': [Error %d] %s\n",
+ filename, errno, strerror(errno));
+ fclose(fp);
+ return FALSE;
+ }
+
+ if (fseek(fp, 0L, SEEK_END) == -1) {
+ error(INFO, LOGPRX"Failed to fseek '%s': [Error %d] %s\n",
+ filename, errno, strerror(errno));
+ fclose(fp);
+ return FALSE;
+ }
+ filesize = ftell(fp);
+ fclose(fp);
+
+ for (i = 0; i < hdr.mem_holes; i++) {
+ /* hole start page */
+ vmss.regions[i].startpagenum = hdr.holes[i].ppn;
+ /* hole end page */
+ vmss.regions[i].startppn = hdr.holes[i].ppn + hdr.holes[i].pages;
+ holes_sum += hdr.holes[i].pages;
+ }
+
+ if (hdr.version != GUESTDUMP_VERSION ||
+ hdr.magic1 != GUESTDUMP_MAGIC1 ||
+ hdr.magic2 != GUESTDUMP_MAGIC2 ||
+ hdr.mem_holes > 2 ||
+ (hdr.last_addr + 1) != ((hdr.memsize_in_pages + holes_sum) << VMW_PAGE_SHIFT) ||
+ filesize != sizeof(struct guestdumpheader) +
+ hdr.num_vcpus * (sizeof (struct vcpu_state) + VMW_PAGE_SIZE)) {
+ if (CRASHDEBUG(1))
+ error(INFO, LOGPRX"Unrecognized debug.guest file.\n");
+ return FALSE;
+ }
+
+ vmss.memsize = hdr.memsize_in_pages << VMW_PAGE_SHIFT;
+ vmss.regionscount = hdr.mem_holes + 1;
+ vmss.memoffset = 0;
+ vmss.num_vcpus = hdr.num_vcpus;
+ return TRUE;
+}
+
+int
+vmware_guestdump_init(char *filename, FILE *ofp)
+{
+ FILE *fp = NULL;
+ int i, result = TRUE;
+ char *vmem_filename = NULL;
+ struct vcpu_state vs;
+ char *p;
+
+ if (!machine_type("X86") && !machine_type("X86_64")) {
+ error(INFO,
+ LOGPRX"Invalid or unsupported host architecture for .vmss file: %s\n",
+ MACHINE_TYPE);
+ result = FALSE;
+ goto exit;
+ }
+
+ if ((fp = fopen(filename, "r")) == NULL) {
+ error(INFO, LOGPRX"Failed to open '%s': [Error %d] %s\n",
+ filename, errno, strerror(errno));
+ result = FALSE;
+ goto exit;
+ }
+
+ if (fseek(fp, sizeof(struct guestdumpheader), SEEK_SET) == -1) {
+ error(INFO, LOGPRX"Failed to fseek '%s': [Error %d] %s\n",
+ filename, errno, strerror(errno));
+ result = FALSE;
+ goto exit;
+ }
+
+ vmss.vcpu_regs = malloc(vmss.num_vcpus * sizeof(uint32_t));
+ vmss.regs64 = calloc(vmss.num_vcpus, sizeof(void *));
+ if (!vmss.vcpu_regs || !vmss.regs64) {
+ error(INFO, LOGPRX"Failed to allocate memory\n");
+ result = FALSE;
+ goto exit;
+ }
+
+ for (i = 0; i < vmss.num_vcpus; i++) {
+ if (fread(&vs, sizeof(struct vcpu_state), 1, fp) != 1) {
+ error(INFO, LOGPRX"Failed to read '%s': [Error %d] %s\n",
+ filename, errno, strerror(errno));
+ result = FALSE;
+ goto exit;
+ }
+ vmss.regs64[i] = calloc(1, sizeof(vmssregs64));
+ if (!vmss.regs64[i]) {
+ error(INFO, LOGPRX"Failed to allocate memory\n");
+ result = FALSE;
+ goto exit;
+ }
+ vmss.vcpu_regs[i] = 0;
+
+ vmss.regs64[i]->rax = vs.regs64.rax;
+ vmss.regs64[i]->rcx = vs.regs64.rcx;
+ vmss.regs64[i]->rdx = vs.regs64.rdx;
+ vmss.regs64[i]->rbx = vs.regs64.rbx;
+ vmss.regs64[i]->rbp = vs.regs64.rbp;
+ vmss.regs64[i]->rsp = vs.regs64.rsp;
+ vmss.regs64[i]->rsi = vs.regs64.rsi;
+ vmss.regs64[i]->rdi = vs.regs64.rdi;
+ vmss.regs64[i]->r8 = vs.regs64.r8;
+ vmss.regs64[i]->r9 = vs.regs64.r9;
+ vmss.regs64[i]->r10 = vs.regs64.r10;
+ vmss.regs64[i]->r11 = vs.regs64.r11;
+ vmss.regs64[i]->r12 = vs.regs64.r12;
+ vmss.regs64[i]->r13 = vs.regs64.r13;
+ vmss.regs64[i]->r14 = vs.regs64.r14;
+ vmss.regs64[i]->r15 = vs.regs64.r15;
+ vmss.regs64[i]->idtr = vs.idt_base;
+ vmss.regs64[i]->cr[0] = vs.cr0;
+ vmss.regs64[i]->cr[2] = vs.cr2;
+ vmss.regs64[i]->cr[3] = vs.cr3;
+ vmss.regs64[i]->cr[4] = vs.cr4;
+ vmss.regs64[i]->rip = vs.regs64.rip;
+ vmss.regs64[i]->rflags = vs.regs64.eflags;
+
+ vmss.vcpu_regs[i] = REGS_PRESENT_ALL;
+ }
+
+
+ fprintf(ofp, LOGPRX"Try to locate the companion vmem file ...\n");
+ vmem_filename = strdup(filename);
+ p = vmem_filename + strlen(vmem_filename) - 5;
+ if (strcmp(p, "guest") != 0) {
+ result = FALSE;
+ goto exit;
+ }
+ strcpy(p, "vmem");
+ if ((vmss.dfp = fopen(vmem_filename, "r")) == NULL) {
+ error(INFO, LOGPRX"%s: %s\n", vmem_filename, strerror(errno));
+ result = FALSE;
+ goto exit;
+ }
+ fseek(vmss.dfp, 0L, SEEK_END);
+ if (vmss.memsize != ftell(vmss.dfp)) {
+ error(INFO, LOGPRX"%s: unexpected size\n", vmem_filename);
+ result = FALSE;
+ goto exit;
+ }
+ fseek(vmss.dfp, 0L, SEEK_SET);
+ fprintf(ofp, LOGPRX"vmem file: %s\n\n", vmem_filename);
+
+exit:
+ if (fp)
+ fclose(fp);
+ if (vmem_filename)
+ free(vmem_filename);
+ if (result == FALSE) {
+ if (vmss.dfp)
+ fclose(vmss.dfp);
+ if (vmss.regs64) {
+ for (i = 0; i < vmss.num_vcpus; i++) {
+ if (vmss.regs64[i])
+ free(vmss.regs64[i]);
+ }
+ free(vmss.regs64);
+ }
+ if (vmss.vcpu_regs)
+ free(vmss.vcpu_regs);
+ }
+ return result;
+}
+
+int
+vmware_guestdump_memory_dump(FILE *ofp)
+{
+ int result = TRUE;
+ uint64_t holes_sum = 0;
+ unsigned i;
+
+ fprintf(ofp, "vmware_guestdump:\n");
+ fprintf(ofp, " Header: version=%d num_vcpus=%ld\n",
+ GUESTDUMP_VERSION, vmss.num_vcpus);
+ fprintf(ofp, "Total memory: %ld\n", vmss.memsize);
+
+ if (vmss.regionscount > 1) {
+ fprintf(ofp, "Memory regions[%d]:\n", vmss.regionscount);
+ fprintf(ofp, " [0x%016x-", 0);
+ for (i = 0; i < vmss.regionscount - 1; i++) {
+ fprintf(ofp, "0x%016lx]\n", (uint64_t)vmss.regions[i].startpagenum << VMW_PAGE_SHIFT);
+ fprintf(ofp, " [0x%016lx-", (uint64_t)vmss.regions[i].startppn << VMW_PAGE_SHIFT);
+ holes_sum += vmss.regions[i].startppn - vmss.regions[i].startpagenum;
+ }
+ fprintf(ofp, "0x%016lx]\n", vmss.memsize + (holes_sum << VMW_PAGE_SHIFT));
+ }
+
+ return TRUE;
+}
+
diff --git a/vmware_vmss.c b/vmware_vmss.c
index 252bfa2..b168f29 100644
--- a/vmware_vmss.c
+++ b/vmware_vmss.c
@@ -23,13 +23,7 @@
#define LOGPRX "vmw: "
-/* VMware only supports X86/X86_64 virtual machines. */
-#define VMW_PAGE_SIZE (4096)
-#define VMW_PAGE_SHIFT (12)
-
-#define MAX_BLOCK_DUMP (128)
-
-static vmssdata vmss = { 0 };
+vmssdata vmss = { 0 };
int
is_vmware_vmss(char *filename)
diff --git a/vmware_vmss.h b/vmware_vmss.h
index a5828a0..01d9446 100644
--- a/vmware_vmss.h
+++ b/vmware_vmss.h
@@ -165,6 +165,14 @@ struct vmssdata {
};
typedef struct vmssdata vmssdata;
+/* VMware only supports X86/X86_64 virtual machines. */
+#define VMW_PAGE_SIZE (4096)
+#define VMW_PAGE_SHIFT (12)
+
+#define MAX_BLOCK_DUMP (128)
+
+extern vmssdata vmss;
+
#define DEBUG_PARSE_PRINT(x) \
do { \
if (CRASHDEBUG(1)) { \
--
2.11.0
4 years, 2 months
[PATCH 1/1] Support cross-compilation
by Alexander Egorenkov
- Introduce CONF_CC variable to compile configure.c
- Introduce CONF_HOST_ARCH to configure.c to enable overriding target
at compile time
Signed-off-by: Alexander Egorenkov <egorenar-dev(a)posteo.net>
---
Makefile | 4 ++-
configure.c | 76 ++++++++++++++++++++++++++++-------------------------
2 files changed, 43 insertions(+), 37 deletions(-)
diff --git a/Makefile b/Makefile
index 7455410..402be6e 100644
--- a/Makefile
+++ b/Makefile
@@ -17,6 +17,8 @@
# GNU General Public License for more details.
#
+CONF_CC = ${CC}
+
PROGRAM=crash
#
@@ -288,7 +290,7 @@ force:
make_configure: force
@rm -f configure
- @${CC} ${CONF_FLAGS} -o configure configure.c ${WARNING_ERROR} ${WARNING_OPTIONS}
+ @${CONF_CC} ${CONF_FLAGS} -o configure configure.c ${WARNING_ERROR} ${WARNING_OPTIONS}
clean: make_configure
@./configure ${CONF_TARGET_FLAG} -q -b
diff --git a/configure.c b/configure.c
index 7f6d19e..d736c56 100644
--- a/configure.c
+++ b/configure.c
@@ -120,6 +120,45 @@ void add_extra_lib(char *);
#define MIPS 11
#define SPARC64 12
+#ifndef CONF_HOST_ARCH
+#ifdef __alpha__
+#define CONF_HOST_ARCH ALPHA
+#endif
+#ifdef __i386__
+#define CONF_HOST_ARCH X86
+#endif
+#ifdef __powerpc__
+#define CONF_HOST_ARCH PPC
+#endif
+#ifdef __ia64__
+#define CONF_HOST_ARCH IA64
+#endif
+#ifdef __s390__
+#define CONF_HOST_ARCH S390
+#endif
+#ifdef __s390x__
+#define CONF_HOST_ARCH S390X
+#endif
+#ifdef __powerpc64__
+#define CONF_HOST_ARCH PPC64
+#endif
+#ifdef __x86_64__
+#define CONF_HOST_ARCH X86_64
+#endif
+#ifdef __arm__
+#define CONF_HOST_ARCH ARM
+#endif
+#ifdef __aarch64__
+#define CONF_HOST_ARCH ARM64
+#endif
+#ifdef __mips__
+#define CONF_HOST_ARCH MIPS
+#endif
+#ifdef __sparc_v9__
+#define CONF_HOST_ARCH SPARC64
+#endif
+#endif // #ifndef CONF_HOST_ARCH
+
#define TARGET_X86 "TARGET=X86"
#define TARGET_ALPHA "TARGET=ALPHA"
#define TARGET_PPC "TARGET=PPC"
@@ -349,42 +388,7 @@ get_current_configuration(struct supported_gdb_version *sp)
static char buf[512];
char *p;
-#ifdef __alpha__
- target_data.target = ALPHA;
-#endif
-#ifdef __i386__
- target_data.target = X86;
-#endif
-#ifdef __powerpc__
- target_data.target = PPC;
-#endif
-#ifdef __ia64__
- target_data.target = IA64;
-#endif
-#ifdef __s390__
- target_data.target = S390;
-#endif
-#ifdef __s390x__
- target_data.target = S390X;
-#endif
-#ifdef __powerpc64__
- target_data.target = PPC64;
-#endif
-#ifdef __x86_64__
- target_data.target = X86_64;
-#endif
-#ifdef __arm__
- target_data.target = ARM;
-#endif
-#ifdef __aarch64__
- target_data.target = ARM64;
-#endif
-#ifdef __mips__
- target_data.target = MIPS;
-#endif
-#ifdef __sparc_v9__
- target_data.target = SPARC64;
-#endif
+ target_data.target = CONF_HOST_ARCH;
set_initial_target(sp);
--
2.28.0
4 years, 2 months
[PATCH 1/1] Calculate offset to field 'init_uts_ns.name'
by Alexander Egorenkov
The offset has changed in linux-next (v5.9.0) from 4 to 0 because
there is no more 'kref' member variable at the beginning of 'init_uts_ns'.
The change was introduced with commit 9a56493f6942c0e2df1579986128721da96e00d8.
To handle both cases correctly, calculate the offset at run time instead.
Signed-off-by: Alexander Egorenkov <egorenar(a)linux.ibm.com>
---
kernel.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/kernel.c b/kernel.c
index 21bd1eb..13942b9 100644
--- a/kernel.c
+++ b/kernel.c
@@ -237,7 +237,7 @@ kernel_init()
sizeof(struct new_utsname), "system_utsname",
RETURN_ON_ERROR);
else if (symbol_exists("init_uts_ns"))
- readmem(symbol_value("init_uts_ns") + sizeof(int),
+ readmem(symbol_value("init_uts_ns") + ANON_MEMBER_OFFSET("uts_namespace","name"),
KVADDR, &kt->utsname, sizeof(struct new_utsname),
"init_uts_ns", RETURN_ON_ERROR);
else
--
2.26.2
4 years, 2 months
[PATCH] Fix for failure when using extensions on PPC64 target x86_64 binary
by HAGIO KAZUHITO(萩尾 一仁)
Without the patch, the "extend" command on an x86_64 binary that can
be used to analyze ppc64le dumpfiles fails with the error meesage
"extend: <path to extension>: not an ELF format object".
Suggested-by: Arun Easi <aeasi.linux(a)gmail.com>
Signed-off-by: Kazuhito Hagio <k-hagio-ab(a)nec.com>
---
I'm not sure which tag I should use in this case, so if you want
me to use another one e.g. Signed-off-by, please let me know.
symbols.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/symbols.c b/symbols.c
index d22fb1d9bdd1..603946db4f34 100644
--- a/symbols.c
+++ b/symbols.c
@@ -3868,7 +3868,8 @@ is_shared_object(char *file)
break;
case EM_X86_64:
- if (machine_type("X86_64") || machine_type("ARM64"))
+ if (machine_type("X86_64") || machine_type("ARM64") ||
+ machine_type("PPC64"))
return TRUE;
break;
--
1.8.3.1
4 years, 3 months
[PATCH 0/2] extensions/trace: Sync up with v5.8 struct renaming
by Valentin Schneider
Hi,
Trying to use the trace extension on a mainline kernel doesn't work, and it
stems from some struct renaming that has happened upstream.
These two patches update the internal naming to match the upstream one, and
includes some backwards-compatibility checks to figure out which naming version
to use depending on what symbols are available.
This was briefly tested on on both v5.4 and 5.9-rc1 kernels using QEMU's
dump-guest-memory. The kernel starts tracing some sched & initicall stuff from
boot, and "trace show" behaves just fine on both of these.
Cheers,
Valentin
Valentin Schneider (2):
extensions/trace: Rename trace_buffer to array_buffer
extensions/trace: Rename ring_buffer to trace_buffer
extensions/trace.c | 101 ++++++++++++++++++++++++++++-----------------
1 file changed, 63 insertions(+), 38 deletions(-)
--
2.27.0
4 years, 3 months
[PATCH] xendump: fix failure to match arm/aarch64 elf format of xendump file
by HAGIO KAZUHITO(萩尾 一仁)
From: Goodbach <goodbach(a)gmail.com>
Date: Wed, 12 Aug 2020 11:22:29 +0800
Resolves: https://github.com/crash-utility/crash/pull/61
Signed-off-by: Goodbach <goodbach(a)gmail.com>
---
xendump.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/xendump.c b/xendump.c
index 70cf261..a81817d 100644
--- a/xendump.c
+++ b/xendump.c
@@ -2055,6 +2055,16 @@ xc_core_elf_verify(char *file, char *buf)
goto bailout;
break;
+ case EM_ARM:
+ if (machine_type_mismatch(file, "ARM", NULL, 0))
+ goto bailout;
+ break;
+
+ case EM_AARCH64:
+ if (machine_type_mismatch(file, "ARM64", NULL, 0))
+ goto bailout;
+ break;
+
default:
if (machine_type_mismatch(file, "(unknown)", NULL, 0))
goto bailout;
4 years, 3 months
[PATCH] crash-extension/gcore: fix the failure of invalid structure member offset
by Lianbo Jiang
With kernel commit: <577d5cd7e585> ("x86/ioperm: Move iobitmap data into
a struct"), the io_bitmap_max and io_bitmap_ptr have been changed. And
move the iobitmap data into a struct io_bitmap.
So, the crash-gcore-command needs to be updated accordingly, otherwise,
the gcore will fail as below:
crash> bt -t|grep -i task
PID: 3968 TASK: ffff9e512e97af80 CPU: 86 COMMAND: "bash"
crash> gcore 3968
gcore: invalid structure member offset: thread_struct_io_bitmap_max
FILE: libgcore/gcore_x86.c LINE: 846 FUNCTION: ioperm_active()
[./crash] error trace: 7f31fca56108 => 7f31fca593b7 => 53a4e1 => 53a463
53a463: OFFSET_verify.part.27+51
53a4e1: OFFSET_verify+49
gcore: invalid structure member offset: thread_struct_io_bitmap_max
FILE: libgcore/gcore_x86.c LINE: 846 FUNCTION: ioperm_active()
Failed.
Signed-off-by: Lianbo Jiang <lijiang(a)redhat.com>
---
gcore.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/gcore.c b/gcore.c
index 27a11938026a..e3e41ecb435b 100644
--- a/gcore.c
+++ b/gcore.c
@@ -487,6 +487,10 @@ static void gcore_offset_table_init(void)
GCORE_MEMBER_OFFSET_INIT(thread_struct_xstate, "thread_struct", "i387");
GCORE_MEMBER_OFFSET_INIT(thread_struct_io_bitmap_max, "thread_struct", "io_bitmap_max");
GCORE_MEMBER_OFFSET_INIT(thread_struct_io_bitmap_ptr, "thread_struct", "io_bitmap_ptr");
+ if (GCORE_INVALID_MEMBER(thread_struct_io_bitmap_max)) {
+ GCORE_MEMBER_OFFSET_INIT(thread_struct_io_bitmap_max, "io_bitmap", "max");
+ GCORE_MEMBER_OFFSET_INIT(thread_struct_io_bitmap_ptr, "io_bitmap", "bitmap");
+ }
GCORE_MEMBER_OFFSET_INIT(user_regset_n, "user_regset", "n");
GCORE_MEMBER_OFFSET_INIT(vm_area_struct_anon_vma, "vm_area_struct", "anon_vma");
GCORE_MEMBER_OFFSET_INIT(vm_area_struct_vm_ops, "vm_area_struct", "vm_ops");
--
2.17.1
4 years, 3 months
[PATCH v2] Append time zone to output of date and time
by HAGIO KAZUHITO(萩尾 一仁)
Currently it's not easy to distinguish which time zone the output of
DATE uses:
crash> sys | grep DATE
DATE: Thu Nov 29 06:44:02 2018
Let's introduce ctime_tz() function like ctime() but explicitly appends
the time zone to its result string.
DATE: Thu Nov 29 06:44:02 JST 2018
Resolves: https://github.com/crash-utility/crash/issues/62
Suggested-by: Jacob Wen <jian.w.wen(a)oracle.com>
Signed-off-by: Kazuhito Hagio <k-hagio-ab(a)nec.com>
---
v1 -> v2
- Add comment about the fallbacks in ctime_tz()
- Add NULL check on timep
defs.h | 1 +
help.c | 3 +--
kernel.c | 16 ++++++----------
tools.c | 32 ++++++++++++++++++++++++++++++++
4 files changed, 40 insertions(+), 12 deletions(-)
diff --git a/defs.h b/defs.h
index 17e98763362b..e7dec7c672a6 100644
--- a/defs.h
+++ b/defs.h
@@ -5096,6 +5096,7 @@ char *strdupbuf(char *);
void sigsetup(int, void *, struct sigaction *, struct sigaction *);
#define SIGACTION(s, h, a, o) sigsetup(s, h, a, o)
char *convert_time(ulonglong, char *);
+char *ctime_tz(time_t *);
void stall(ulong);
char *pages_to_size(ulong, char *);
int clean_arg(void);
diff --git a/help.c b/help.c
index b707cfa58826..d3427a36829f 100644
--- a/help.c
+++ b/help.c
@@ -9299,8 +9299,7 @@ display_README(void)
fprintf(fp, " GNU gdb %s\n", pc->gdb_version);
} else if (STREQ(README[i], README_DATE)) {
time(&time_now);
- fprintf(fp, " DATE: %s\n",
- strip_linefeeds(ctime(&time_now)));
+ fprintf(fp, " DATE: %s\n", ctime_tz(&time_now));
} else if (STREQ(README[i], README_HELP_MENU)) {
display_help_screen(" ");
} else if (STREQ(README[i], README_GPL_INFO)) {
diff --git a/kernel.c b/kernel.c
index f179375f2d3d..92bfe6329900 100644
--- a/kernel.c
+++ b/kernel.c
@@ -225,10 +225,9 @@ kernel_init()
get_xtime(&kt->date);
if (CRASHDEBUG(1))
fprintf(fp, "xtime timespec.tv_sec: %lx: %s\n",
- kt->date.tv_sec, strip_linefeeds(ctime(&kt->date.tv_sec)));
+ kt->date.tv_sec, ctime_tz(&kt->date.tv_sec));
if (kt->flags2 & GET_TIMESTAMP) {
- fprintf(fp, "%s\n\n",
- strip_linefeeds(ctime(&kt->date.tv_sec)));
+ fprintf(fp, "%s\n\n", ctime_tz(&kt->date.tv_sec));
clean_exit(0);
}
@@ -5178,7 +5177,7 @@ dump_log_entry(char *logptr, int msg_flags)
rem = (ulonglong)ts_nsec % (ulonglong)1000000000;
if (msg_flags & SHOW_LOG_CTIME) {
time_t t = kt->boot_date.tv_sec + nanos;
- sprintf(buf, "[%s] ", strip_linefeeds(ctime(&t)));
+ sprintf(buf, "[%s] ", ctime_tz(&t));
}
else
sprintf(buf, "[%5lld.%06ld] ", nanos, rem/1000);
@@ -5553,8 +5552,7 @@ display_sys_stats(void)
if (ACTIVE())
get_xtime(&kt->date);
- fprintf(fp, " DATE: %s\n",
- strip_linefeeds(ctime(&kt->date.tv_sec)));
+ fprintf(fp, " DATE: %s\n", ctime_tz(&kt->date.tv_sec));
fprintf(fp, " UPTIME: %s\n", get_uptime(buf, NULL));
fprintf(fp, "LOAD AVERAGE: %s\n", get_loadavg(buf));
fprintf(fp, " TASKS: %ld\n", RUNNING_TASKS());
@@ -6043,10 +6041,8 @@ dump_kernel_table(int verbose)
kt->source_tree : "(not used)");
if (!(pc->flags & KERNEL_DEBUG_QUERY) && ACTIVE())
get_xtime(&kt->date);
- fprintf(fp, " date: %s\n",
- strip_linefeeds(ctime(&kt->date.tv_sec)));
- fprintf(fp, " boot_ date: %s\n",
- strip_linefeeds(ctime(&kt->boot_date.tv_sec)));
+ fprintf(fp, " date: %s\n", ctime_tz(&kt->date.tv_sec));
+ fprintf(fp, " boot_date: %s\n", ctime_tz(&kt->boot_date.tv_sec));
fprintf(fp, " proc_version: %s\n", strip_linefeeds(kt->proc_version));
fprintf(fp, " new_utsname: \n");
fprintf(fp, " .sysname: %s\n", uts->sysname);
diff --git a/tools.c b/tools.c
index 85c81668e40e..89352b1dc5f5 100644
--- a/tools.c
+++ b/tools.c
@@ -6318,6 +6318,38 @@ convert_time(ulonglong count, char *buf)
}
/*
+ * Convert a calendar time into a null-terminated string like ctime(), but
+ * the result string contains the time zone string and does not ends with a
+ * linefeed ('\n'). If localtime() or strftime() fails, fail back to return
+ * POSIX time (seconds since the Epoch) or ctime() string respectively.
+ *
+ * NOTE: The return value points to a statically allocated string which is
+ * overwritten by subsequent calls.
+ */
+char *
+ctime_tz(time_t *timep)
+{
+ static char buf[64];
+ struct tm *tm;
+ size_t size;
+
+ if (!timep)
+ return NULL;
+
+ tm = localtime(timep);
+ if (!tm) {
+ snprintf(buf, sizeof(buf), "%ld", *timep);
+ return buf;
+ }
+
+ size = strftime(buf, sizeof(buf), "%a %b %e %T %Z %Y", tm);
+ if (!size)
+ return strip_linefeeds(ctime(timep));
+
+ return buf;
+}
+
+/*
* Stall for a number of microseconds.
*/
void
--
1.8.3.1
4 years, 3 months
7.2.8: Failure when using PPC64 extensions on a PPC64 build from X86_64
by Arun Easi
Hi,
I was trying to debug a PPC64 crash from a X86_64 machine. I got crash
(7.2.8) to work with a "make target=PPC64", but when I tried to load an
extension I got this error:
crash> extend
/root/misc/builds/mpykdump-v3.2.1-g4308a70/Extension/mpykdump.so
extend: /root/misc/builds/mpykdump-v3.2.1-g4308a70/Extension/mpykdump.so:
not an ELF format object file
I tried other sample extensions (like dminfo) with the same result.
A little debugging shows that "is_shared_object()" is returning FALSE
leading to this. Just commenting the call makes the extension work as
expected.
gdb of is_shared_object():
3852 } else if ((elf64->e_ident[EI_CLASS] == ELFCLASS64) &&
(gdb)
3854 switch (swap16(elf64->e_machine, swap))
(gdb) p elf64
$6 = (Elf64_Ehdr *) 0x7fffffffca40
(gdb) p *elf64
$7 = {e_ident = "\177ELF\002\001\001\000\000\000\000\000\000\000\000",
e_type = 3, e_machine = 62,
e_version = 1, e_entry = 511360, e_phoff = 64, e_shoff = 20379704,
e_flags = 0, e_ehsize = 64,
e_phentsize = 56, e_phnum = 7, e_shentsize = 64, e_shnum = 31, e_shstrndx
= 28}
(gdb) p/x *elf64
$8 = {e_ident = {0x7f, 0x45, 0x4c, 0x46, 0x2, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0,
0x0, 0x0, 0x0, 0x0, 0x0},
e_type = 0x3, e_machine = 0x3e, e_version = 0x1, e_entry = 0x7cd80,
e_phoff = 0x40, e_shoff = 0x136f838,
e_flags = 0x0, e_ehsize = 0x40, e_phentsize = 0x38, e_phnum = 0x7,
e_shentsize = 0x40, e_shnum = 0x1f,
e_shstrndx = 0x1c}
(gdb) n
3867 if (machine_type("X86_64") ||
machine_type("ARM64"))
(gdb)
3877 if (machine_type("ARM64"))
(gdb)
3887 if (CRASHDEBUG(1))
(gdb) p swap
$9 = 0
(gdb) p machine_type("X86_64")
$10 = 0
(gdb) p machine_type("PPC64")
$11 = 1
(gdb) n
3793 return FALSE;
It appears like the fix should be something like this (which does fix the
issue), but I'd leave it to experts how to fix this correctly:
# diff -up symbols.c.org symbols.c
--- symbols.c.org 2020-09-02 11:28:33.855265712 -0700
+++ symbols.c 2020-09-02 11:28:36.964274966 -0700
@@ -3864,7 +3864,8 @@ is_shared_object(char *file)
break;
case EM_X86_64:
- if (machine_type("X86_64") ||
machine_type("ARM64"))
+ if (machine_type("X86_64") || machine_type("ARM64")
||
+ machine_type("PPC64"))
return TRUE;
break;
Regards,
-Arun
4 years, 3 months