Re: [Crash-utility] [PATCH v6] vmware_guestdump: new input format
by lijiang
Hi, Alexey
在 2020年10月10日 05:13, crash-utility-request(a)redhat.com 写道:
> Date: Fri, 9 Oct 2020 14:13:49 -0700
> From: Alexey Makhalov <amakhalov(a)vmware.com>
> To: <crash-utility(a)redhat.com>, <amakhalov(a)vmware.com>,
> <k-hagio-ab(a)nec.com>, <d.hatayama(a)fujitsu.com>
> Subject: [Crash-utility] [PATCH v6] vmware_guestdump: new input format
> Message-ID: <20201009211349.23570-1-amakhalov(a)vmware.com>
> Content-Type: text/plain
>
> 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 /path/to/debug_file.guest vmlinux
> Companion debug_file.vmem must be present in the same folder as
> debug_file.guest. Otherwise crash will shot a message:
> vmw: Open the companion vmem file: /path/to/debug_file.vmem
> crash: vmw: /path/to/debug_file.vmem: No such file or directory
>
> Signed-off-by: Alexey Makhalov <amakhalov(a)vmware.com>
> Acked-by: Kazuhito Hagio <k-hagio-ab(a)nec.com>
> ---
> Makefile | 7 +-
> crash.8 | 12 +-
> defs.h | 8 ++
> filesys.c | 12 +-
> main.c | 14 +++
> memory.c | 8 +-
> vmware_guestdump.c | 315 +++++++++++++++++++++++++++++++++++++++++++++++++++++
Thank you for the patch.
I would recommend splitting it into two patches. For the vmware_vmss.h and and vmware_vmss.c
changes, it may be a separate patch, this changes are different from the new feature.
And the remaining changes(the above seven files) are the second patch, which represents the
new feature changes.
Thanks.
Lianbo
> vmware_vmss.c | 8 +-
> vmware_vmss.h | 8 ++
> 9 files changed, 376 insertions(+), 16 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/crash.8 b/crash.8
> index 136ae78..5020ce1 100644
> --- a/crash.8
> +++ b/crash.8
> @@ -21,8 +21,9 @@ core dump has been created by the
> .I LKCD,
> .I kdump,
> .I xendump
> -or
> .I kvmdump
> +or
> +.I VMware
> facilities. It is loosely based on the SVR4 UNIX crash
> command, but has been significantly enhanced
> by completely merging it with the
> @@ -112,8 +113,9 @@ A kernel core dump file created by the
> .I LKCD
> .I kdump,
> .I xendump
> -or
> .I kvmdump
> +or
> +.I VMware
> facilities.
>
> If a MEMORY-IMAGE argument is not entered, the session will be invoked on
> @@ -144,6 +146,12 @@ in /var/tmp, which will only exist during the crash session. If a raw RAM
> dumpile represents a live memory source, such as that specified by the QEMU
> mem-path argument of a memory-backend-file object, then "live:" must be
> prepended to the MEMORY-IMAGE name.
> +
> +As VMware facility, the
> +.B crash
> +utility is able to process VMware VM memory dump generated by VM suspend
> +or guest core dump. In that case, .vmss or .guest file should be used as
> +a MEMORY-IMAGE and .vmem file must be located in the same folder.
> .TP
> .BI mapfile
> If the NAMELIST file is not the same kernel that is
> diff --git a/defs.h b/defs.h
> index c899fe2..3386709 100644
> --- a/defs.h
> +++ b/defs.h
> @@ -544,6 +544,7 @@ struct program_context {
> #define is_excluded_vmemmap() (pc->flags2 & EXCLUDED_VMEMMAP)
> #define MEMSRC_LOCAL (0x80000ULL)
> #define REDZONE (0x100000ULL)
> +#define VMWARE_VMSS_GUESTDUMP (0x200000ULL)
> char *cleanup;
> char *namelist_orig;
> char *namelist_debug_orig;
> @@ -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..d3fac59
> --- /dev/null
> +++ b/vmware_guestdump.c
> @@ -0,0 +1,315 @@
> +/*
> + * 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 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.
> + *
> + * debug.guest does not have dedicated header magic or signature for
> + * its format. To probe debug.guest we need to perform header fields
> + * and file size validity. In addition, check for the filename
> + * extension, which must be ".guest".
> + */
> +
> +int
> +is_vmware_guestdump(char *filename)
> +{
> + struct guestdumpheader hdr;
> + FILE *fp;
> + uint64_t filesize, holes_sum = 0;
> + int i;
> +
> + if (strcmp(filename + strlen(filename) - 6, ".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);
> +
> + if (hdr.mem_holes > 2)
> + goto unrecognized;
> +
> + 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.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))
> + goto unrecognized;
> +
> + 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;
> +
> +unrecognized:
> + if (CRASHDEBUG(1))
> + error(INFO, LOGPRX"Unrecognized debug.guest file.\n");
> + return FALSE;
> +}
> +
> +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;
> + }
> +
> + vmem_filename = strdup(filename);
> + p = vmem_filename + strlen(vmem_filename) - 5;
> + if (strcmp(p, "guest") != 0) {
> + result = FALSE;
> + goto exit;
> + }
> + strcpy(p, "vmem");
> +
> + fprintf(ofp, LOGPRX"Open the companion vmem file: %s\n", vmem_filename);
> + 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)
> +{
> + 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) {
> + uint64_t holes_sum = 0;
> + unsigned i;
> +
> + 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, 1 month
Re: [Crash-utility] [PATCH v2 1/1] Support member offset uts_namespace.name
by lijiang
在 2020年10月02日 00:00, crash-utility-request(a)redhat.com 写道:
> Message: 2
> Date: Thu, 1 Oct 2020 15:19:59 +0200
> From: Alexander Egorenkov <egorenar(a)linux.ibm.com>
> To: crash-utility(a)redhat.com, k-hagio-ab(a)nec.com
> Subject: [Crash-utility] [PATCH v2 1/1] Support member offset
> uts_namespace.name
> Message-ID: <20201001131959.456735-1-egorenar(a)linux.ibm.com>
> Content-Type: text/plain; charset="US-ASCII"
>
> The offset of the field 'init_uts_ns.name' has changed
> since commit 9a56493f6942 ("uts: Use generic ns_common::count").
>
> Link: https://lore.kernel.org/r/159644978167.604812.1773586504374412107.stgit@l...
>
> Read the offset from VMCOREINFO if present. This requires a linux version
> which exports the requisite offset in VMCOREINFO.
>
> Signed-off-by: Alexander Egorenkov <egorenar(a)linux.ibm.com>
> ---
>
> v1 -> v2:
> * Use offset from VMCOREINFO
> * Initialize corresponding entry in offset_table
> For the v2:
Acked-by: Lianbo Jiang <lijiang(a)redhat.com>
Thanks.
> defs.h | 1 +
> kernel.c | 15 ++++++++++-----
> symbols.c | 3 +++
> 3 files changed, 14 insertions(+), 5 deletions(-)
>
> diff --git a/defs.h b/defs.h
> index c899fe2..9a8030a 100644
> --- a/defs.h
> +++ b/defs.h
> @@ -2104,6 +2104,7 @@ struct offset_table { /* stash of commonly-used offsets */
> long inode_i_sb_list;
> long irq_common_data_affinity;
> long irq_desc_irq_common_data;
> + long uts_namespace_name;
> };
>
> struct size_table { /* stash of commonly-used sizes */
> diff --git a/kernel.c b/kernel.c
> index 5ae8cf1..9871637 100644
> --- a/kernel.c
> +++ b/kernel.c
> @@ -230,16 +230,21 @@ kernel_init()
> fprintf(fp, "%s\n\n", ctime_tz(&kt->date.tv_sec));
> clean_exit(0);
> }
> -
> +
> + MEMBER_OFFSET_INIT(uts_namespace_name, "uts_namespace", "name");
> if (symbol_exists("system_utsname"))
> readmem(symbol_value("system_utsname"), KVADDR, &kt->utsname,
> sizeof(struct new_utsname), "system_utsname",
> RETURN_ON_ERROR);
> - else if (symbol_exists("init_uts_ns"))
> - readmem(symbol_value("init_uts_ns") + sizeof(int),
> - KVADDR, &kt->utsname, sizeof(struct new_utsname),
> + else if (symbol_exists("init_uts_ns")) {
> + long offset = sizeof(int);
> + if (VALID_MEMBER(uts_namespace_name))
> + offset = OFFSET(uts_namespace_name);
> +
> + readmem(symbol_value("init_uts_ns") + offset,
> + KVADDR, &kt->utsname, sizeof(struct new_utsname),
> "init_uts_ns", RETURN_ON_ERROR);
> - else
> + } else
> error(INFO, "cannot access utsname information\n\n");
>
> if (CRASHDEBUG(1)) {
> diff --git a/symbols.c b/symbols.c
> index d22fb1d..3dd5fa1 100644
> --- a/symbols.c
> +++ b/symbols.c
> @@ -10585,6 +10585,9 @@ dump_offset_table(char *spec, ulong makestruct)
> fprintf(fp, " xa_node_shift: %ld\n",
> OFFSET(xa_node_shift));
>
> + fprintf(fp, " uts_namespace_name: %ld\n",
> + OFFSET(uts_namespace_name));
> +
> fprintf(fp, "\n size_table:\n");
> fprintf(fp, " page: %ld\n", SIZE(page));
> fprintf(fp, " page_flags: %ld\n", SIZE(page_flags));
> -- 2.26.2
4 years, 1 month
Re: [Crash-utility] [PATCH 0/2] extensions/trace: Sync up with v5.8 struct renaming
by HAGIO KAZUHITO(萩尾 一仁)
-----Original Message-----
> 在 2020年09月04日 21:53, crash-utility-request(a)redhat.com 写道:
> > Date: Thu, 3 Sep 2020 21:28:45 +0100
> > From: Valentin Schneider <valentin.schneider(a)arm.com>
> > To: crash-utility(a)redhat.com
> > Subject: [Crash-utility] [PATCH 0/2] extensions/trace: Sync up with
> > v5.8 struct renaming
> > Message-ID: <20200903202847.31018-1-valentin.schneider(a)arm.com>
> > Content-Type: text/plain; charset=US-ASCII
> >
> > 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(-)
> >
> Thanks for the fix. This series looks good to me.
>
> Acked-by: Lianbo Jiang <lijiang(a)redhat.com>
Thanks, applied.
BTW, Lianbo, if you cannot find the original email and do reply to a digest,
could you rename its subject to something distinguishable like "Re: <original subject>"?
That would be helpful for us to find which thread you replied:
https://www.redhat.com/archives/crash-utility/2020-October/thread.html
(It was hard for me to track discussion in August..
https://www.redhat.com/archives/crash-utility/2020-August/thread.html )
Thanks,
Kazu
4 years, 1 month
[PATCH v2 1/1] Support cross-compilation
by Alexander Egorenkov
In order to support cross-compilation of crash-utilty,
the configure tool compiled from configure.c must be built
for the host architecture where the cross-compilation will run
instead of the target architecture where the crash-utility shall run.
Therefore, we need to support two C compilers in Maklefile,
one for the host and one for the target. The old CC makefile variable
shall represent the compiler for the target architecture and
the new CONF_CC makefile variable shall represent the host compiler.
Both variables differ only when a cross-compilation is performed.
Furthermore, there must be a way to override the target architecture
which is deduced from the preprocessor macros defined by the compiler
used for the compilation of configure.c, because otherwise the configure
tool will deduce host's architecture instead of the desired target.
With the new preprocessor define CONF_HOST_ARCH, it is possible to
set the desired target architecture for the compiled crash-utility.
When cross-compiling, pass the value of CONF_HOST_ARCH via
the CONF_CFLAGS makefile variable, e.g. like this:
make CONF_CC=gcc CC=s390x-linux-gnu-gcc CONF_FLAGS="-DCONF_HOST_ARCH=S390X"
Signed-off-by: Alexander Egorenkov <egorenar-dev(a)posteo.net>
---
v1 -> v2:
* Improved commit message
* Added a note how to cross-compile crash-utilty to README
* Moved CONF_CC makefile variable to correct place location
Makefile | 3 ++-
README | 4 +++
configure.c | 76 ++++++++++++++++++++++++++++-------------------------
3 files changed, 46 insertions(+), 37 deletions(-)
diff --git a/Makefile b/Makefile
index 7455410..d5985bc 100644
--- a/Makefile
+++ b/Makefile
@@ -25,6 +25,7 @@ PROGRAM=crash
#
TARGET=
GDB_CONF_FLAGS=
+CONF_CC = ${CC}
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
ifeq (${ARCH}, ppc64)
@@ -288,7 +289,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/README b/README
index bfbaef6..707bc63 100644
--- a/README
+++ b/README
@@ -100,6 +100,10 @@
o On an x86_64 host, an x86_64 binary that can be used to analyze
ppc64le dumpfiles may be built by typing "make target=PPC64".
+ To cross-compile the crash utility e.g. for a s390x target:
+
+ $ make CONF_CC=gcc CC=s390x-linux-gnu-gcc CONF_CFLAGS="-DCONF_HOST_ARCH=S390X"
+
Traditionally when vmcores are compressed via the makedumpfile(8) facility
the libz compression library is used, and by default the crash utility
only supports libz. Recently makedumpfile has been enhanced to optionally
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, 1 month
Re: [Crash-utility] [PATCH] sadump: fix help -D lists, uninteresting register entries
by lijiang
在 2020年10月07日 00:00, crash-utility-request(a)redhat.com 写道:
> Date: Tue, 6 Oct 2020 21:05:39 +0900
> From: HATAYAMA Daisuke <d.hatayama(a)fujitsu.com>
> To: crash-utility(a)redhat.com
> Cc: HATAYAMA Daisuke <d.hatayama(a)fujitsu.com>
> Subject: [Crash-utility] [PATCH] sadump: fix help -D lists
> uninteresting register entries
> Message-ID: <1601985939-1431-1-git-send-email-d.hatayama(a)fujitsu.com>
> Content-Type: text/plain; charset="US-ASCII"
>
> Reserved fields in SMRAM CPU states could be non-zero even if the
> corresponding APICs are NOT used. This breaks the assumption that
> SMRAM CPU state is zero cleared if and only if the APIC corresponding
> to the entry is NOT used. As the result, help -D lists uninteresting
> entries as below:
>
> APIC ID: 14
> RIP: 0000000000000000 RSP: 0000000000000000 RBP: 0000000000000000
> RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000
> RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000
> R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000
> R11: 0000000000000000 R12: 0000000000000000 R13: 0000000000000000
> R14: 0000000000000000 R15: 0000000000000000
> SMM REV: 00000000 SMM BASE 00000000
> CS : 00000000 DS: 00000000 SS: 00000000 ES: 00000000 FS: 00000000
> GS : 00000000
> CR0: 0000000000000000 CR3: 0000000000000000 CR4: 00000000
> GDT: 0000000000000000 LDT: 0000000000000000 IDT: 0000000000000000
> GDTlim: 00000000 LDTlim: 00000000 IDTlim: 00000000
> LDTR: 00000000 TR: 00000000 RFLAGS: 0000000000000000
> EPTP: 0000000000000000 EPTP_SETTING: 00000000
> DR6: 0000000000000000 DR7: 0000000000000000
> Ia32Efer: 0000000000000000
> IoMemAddr: 0000000000000000 IoEip: 0000000000000000
> IoMisc: 00000000 LdtInfo: 00000000
> IoInstructionRestart: 0000 AutoHaltRestart: 0000
>
> To fix this issue, mask reserved fields before comparison.
>
Thanks for the fix, HATAYAMA.
Acked-by: Lianbo Jiang <lijiang(a)redhat.com>
> Signed-off-by: HATAYAMA Daisuke <d.hatayama(a)fujitsu.com>
> ---
> sadump.c | 22 ++++++++++++++++++++++
> 1 file changed, 22 insertions(+)
>
> diff --git a/sadump.c b/sadump.c
> index 009e17a..f313528 100644
> --- a/sadump.c
> +++ b/sadump.c
> @@ -51,6 +51,7 @@ static int cpu_to_apicid(int cpu, int *apicid);
> static int get_sadump_smram_cpu_state(int cpu, struct sadump_smram_cpu_state *smram);
> static int block_table_init(void);
> static uint64_t pfn_to_block(uint64_t pfn);
> +static void mask_reserved_fields(struct sadump_smram_cpu_state *smram);
>
> struct sadump_data *
> sadump_get_sadump_data(void)
> @@ -1040,6 +1041,15 @@ int sadump_memory_dump(FILE *fp)
> "cpu_state\n");
> return FALSE;
> }
> + /*
> + * Reserved fields in SMRAM CPU states could
> + * be non-zero even if the corresponding APICs
> + * are NOT used. This breaks the assumption
> + * that SMRAM CPU state is zero cleared if and
> + * only if the APIC corresponding to the entry
> + * is NOT used.
> + */
> + mask_reserved_fields(&scs);
> if (memcmp(&scs, &zero, sizeof(scs)) != 0) {
> fprintf(fp, "\n");
> display_smram_cpu_state(aid, &scs);
> @@ -1707,3 +1717,15 @@ sadump_get_cr3_idtr(ulong *cr3, ulong *idtr)
> return TRUE;
> }
> #endif /* X86_64 */
> +
> +static void
> +mask_reserved_fields(struct sadump_smram_cpu_state *smram)
> +{
> + memset(smram->Reserved1, 0, sizeof(smram->Reserved1));
> + memset(smram->Reserved2, 0, sizeof(smram->Reserved2));
> + memset(smram->Reserved3, 0, sizeof(smram->Reserved3));
> + memset(smram->Reserved4, 0, sizeof(smram->Reserved4));
> + memset(smram->Reserved5, 0, sizeof(smram->Reserved5));
> + memset(smram->Reserved6, 0, sizeof(smram->Reserved6));
> + memset(smram->Reserved7, 0, sizeof(smram->Reserved7));
> +}
> -- 1.8.3.1
4 years, 1 month
Re: [Crash-utility] Crash-utility Digest, Vol 180, Issue 6
by lijiang
在 2020年09月04日 21:53, crash-utility-request(a)redhat.com 写道:
> Date: Thu, 3 Sep 2020 21:28:45 +0100
> From: Valentin Schneider <valentin.schneider(a)arm.com>
> To: crash-utility(a)redhat.com
> Subject: [Crash-utility] [PATCH 0/2] extensions/trace: Sync up with
> v5.8 struct renaming
> Message-ID: <20200903202847.31018-1-valentin.schneider(a)arm.com>
> Content-Type: text/plain; charset=US-ASCII
>
> 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(-)
>
Thanks for the fix. This series looks good to me.
Acked-by: Lianbo Jiang <lijiang(a)redhat.com>
> --
> 2.27.0
4 years, 1 month
[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, 1 month
[PATCH] sadump: fix help -D lists uninteresting register entries
by HATAYAMA Daisuke
Reserved fields in SMRAM CPU states could be non-zero even if the
corresponding APICs are NOT used. This breaks the assumption that
SMRAM CPU state is zero cleared if and only if the APIC corresponding
to the entry is NOT used. As the result, help -D lists uninteresting
entries as below:
APIC ID: 14
RIP: 0000000000000000 RSP: 0000000000000000 RBP: 0000000000000000
RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000
RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000
R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000
R11: 0000000000000000 R12: 0000000000000000 R13: 0000000000000000
R14: 0000000000000000 R15: 0000000000000000
SMM REV: 00000000 SMM BASE 00000000
CS : 00000000 DS: 00000000 SS: 00000000 ES: 00000000 FS: 00000000
GS : 00000000
CR0: 0000000000000000 CR3: 0000000000000000 CR4: 00000000
GDT: 0000000000000000 LDT: 0000000000000000 IDT: 0000000000000000
GDTlim: 00000000 LDTlim: 00000000 IDTlim: 00000000
LDTR: 00000000 TR: 00000000 RFLAGS: 0000000000000000
EPTP: 0000000000000000 EPTP_SETTING: 00000000
DR6: 0000000000000000 DR7: 0000000000000000
Ia32Efer: 0000000000000000
IoMemAddr: 0000000000000000 IoEip: 0000000000000000
IoMisc: 00000000 LdtInfo: 00000000
IoInstructionRestart: 0000 AutoHaltRestart: 0000
To fix this issue, mask reserved fields before comparison.
Signed-off-by: HATAYAMA Daisuke <d.hatayama(a)fujitsu.com>
---
sadump.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/sadump.c b/sadump.c
index 009e17a..f313528 100644
--- a/sadump.c
+++ b/sadump.c
@@ -51,6 +51,7 @@ static int cpu_to_apicid(int cpu, int *apicid);
static int get_sadump_smram_cpu_state(int cpu, struct sadump_smram_cpu_state *smram);
static int block_table_init(void);
static uint64_t pfn_to_block(uint64_t pfn);
+static void mask_reserved_fields(struct sadump_smram_cpu_state *smram);
struct sadump_data *
sadump_get_sadump_data(void)
@@ -1040,6 +1041,15 @@ int sadump_memory_dump(FILE *fp)
"cpu_state\n");
return FALSE;
}
+ /*
+ * Reserved fields in SMRAM CPU states could
+ * be non-zero even if the corresponding APICs
+ * are NOT used. This breaks the assumption
+ * that SMRAM CPU state is zero cleared if and
+ * only if the APIC corresponding to the entry
+ * is NOT used.
+ */
+ mask_reserved_fields(&scs);
if (memcmp(&scs, &zero, sizeof(scs)) != 0) {
fprintf(fp, "\n");
display_smram_cpu_state(aid, &scs);
@@ -1707,3 +1717,15 @@ sadump_get_cr3_idtr(ulong *cr3, ulong *idtr)
return TRUE;
}
#endif /* X86_64 */
+
+static void
+mask_reserved_fields(struct sadump_smram_cpu_state *smram)
+{
+ memset(smram->Reserved1, 0, sizeof(smram->Reserved1));
+ memset(smram->Reserved2, 0, sizeof(smram->Reserved2));
+ memset(smram->Reserved3, 0, sizeof(smram->Reserved3));
+ memset(smram->Reserved4, 0, sizeof(smram->Reserved4));
+ memset(smram->Reserved5, 0, sizeof(smram->Reserved5));
+ memset(smram->Reserved6, 0, sizeof(smram->Reserved6));
+ memset(smram->Reserved7, 0, sizeof(smram->Reserved7));
+}
--
1.8.3.1
4 years, 1 month
[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, 1 month
[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, 1 month