From: <cp...@sg...> - 2007-08-02 20:24:49
|
Anyone interested in making lcrash read a kdump dump? It would seem useful to me to do so, especially until the crash tool has a scripting language - such as sial. The below patch enables lcrash to read an x86_64 kdump dump. It may lack a bit in elegance, and is limited to x86_64, but it works. Any interest? -Cliff Diffed against LKCD top of tree 6/28/2007 Signed-off-by: Cliff Wickman <cp...@sg...> --- lcrash/Makefile | 2 lcrash/defs.h | 4392 ++++++++++++++++++++++++++++++++++++ lcrash/netdump.c | 1299 ++++++++++ lcrash/netdump.h | 119 lcrash/util.c | 5 lib/libklib/include/kl_mem_x86_64.h | 4 lib/libklib/kl_dump.c | 8 lib/libklib/kl_dump_x86_64.c | 27 lib/libklib/kl_mem.c | 8 lib/libklib/klib.c | 61 10 files changed, 5894 insertions(+), 31 deletions(-) Index: lkcdutils/lcrash/netdump.c =================================================================== --- /dev/null +++ lkcdutils/lcrash/netdump.c @@ -0,0 +1,1299 @@ +/* netdump.c + * + * Copyright (C) 2002, 2003, 2004, 2005, 2006 David Anderson + * Copyright (C) 2002, 2003, 2004, 2005, 2006 Red Hat, Inc. All rights reserved. + * Borrowed from the crash project for LKCD by Cliff Wickman. 6/2007 + * + * This software may be freely redistributed under the terms of the + * GNU General Public License. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Author: David Anderson + */ + +#include "defs.h" +#include "netdump.h" +#include <lcrash.h> + +static struct vmcore_data vmcore_data = { 0 }; +static struct vmcore_data *nd = &vmcore_data; +static struct xen_kdump_data xen_kdump_data = { 0 }; +static void netdump_print(char *, ...); +static void dump_Elf32_Ehdr(Elf32_Ehdr *); +static void dump_Elf32_Phdr(Elf32_Phdr *, int); +static size_t dump_Elf32_Nhdr(Elf32_Off offset, int); +static void dump_Elf64_Ehdr(Elf64_Ehdr *); +static void dump_Elf64_Phdr(Elf64_Phdr *, int); +static size_t dump_Elf64_Nhdr(Elf64_Off offset, int); +static ulong machdep_machspec_phys_base; +syment_t *kl_lkup_symname(char *name); + +#define ELFSTORE 1 +#define ELFREAD 0 + +#define MIN_PAGE_SIZE (4096) + +struct program_context program_context, *pc; +struct machdep_table machdep_table, *machdep; +struct lkcd_environment lkcd_environment, *lkcd; + +extern void *G_dump_header; /* Pointer to raw dump_header */ + +/* + * make_dump_header() + * G_dump_header should point to a generic dump header. + */ +void +make_dump_header(void) +{ + generic_dump_header_t *gdhp; + + if (!(G_dump_header = malloc(sizeof(generic_dump_header_t)))) { + printf ("malloc failed\n"); + exit(1); + } + /* just 3 fields: */ + gdhp = (generic_dump_header_t *)G_dump_header; + gdhp->magic_number = KL_DUMP_MAGIC_NUMBER; + gdhp->version = KL_DUMP_VERSION_NUMBER; + gdhp->header_size = sizeof(generic_dump_header_t); + + return; +} + +int +symbol_exists(char *name) +{ + if (kl_lkup_symname(name)) { + return 1; + } + return 0; +} + +ulong +symbol_value(char *name) +{ + syment_t *smp; + if ((smp = kl_lkup_symname(name))) { + return smp->s_addr; + } + return 0; +} + +/* return true if the machine type matches "type" */ +int +machine_type(char *type) +{ +#ifdef DUMP_ARCH_X86_64 + return !strcmp("X86_64", type); +#else + return 0; +#endif +} + +/* + * General purpose error reporting routine. Type INFO prints the message + * and returns. Type FATAL aborts the command in progress, and longjmps + * back to the appropriate recovery location. If a FATAL occurs during + * program initialization, exit() is called. + * + * The idea is to get the message out so that it is seen by the user + * regardless of how the command output may be piped or redirected. + * Besides stderr, check whether the output is going to a file or pipe, and + * if so, intermingle the error message there as well. + */ +int +__error(int type, char *fmt, ...) +{ + char buf[BUFSIZE]; + va_list ap; + + va_start(ap, fmt); + (void)vsnprintf(buf, BUFSIZE, fmt, ap); + va_end(ap); + + if (FATAL_ERROR(type)) { + exit(1); + } + return FALSE; +} + +/* called from kl_init_klib() to test for this being a kdump dump */ +/* + * Determine whether a file is a netdump/diskdump/kdump creation, + * and if TRUE, initialize the vmcore_data structure. + */ +int +is_netdump(char *file, ulong source_query) +{ + int i; + int fd; + Elf32_Ehdr *elf32; + Elf32_Phdr *load32; + Elf64_Ehdr *elf64; + Elf64_Phdr *load64; + char header[MIN_NETDUMP_ELF_HEADER_SIZE]; + char buf[BUFSIZE]; + size_t size, len, tot; + Elf32_Off offset32; + Elf64_Off offset64; + ulong tmp_flags; + char *tmp_elf_header; + + pc = &program_context; + pc->flags = 0; + lkcd = &lkcd_environment; /* fix up BITS32 */ +#ifdef DUMP_ARCH_X86_64 + lkcd->bits = 64; +#else + /* Sorry, this lcrash only works on kdump dumps for x86_64 */ + return(0); +#endif + VMALLOC_START = VMALLOC_START_VAL; + VMALLOC_END = VMALLOC_END_VAL; + machdep_machspec_phys_base = 0; /* per crash */ + + /* borrowed from kl_open_dump */ + if (!KLP || !KLP->dump || !KLP->dump->dump) { + printf("KLP not initialized\n"); + exit(1); + } + KLP->dump->core_type = reg_core; + + if ((fd = open(file, O_RDWR)) < 0) { + if ((fd = open(file, O_RDONLY)) < 0) { + sprintf(buf, "%s: open", file); + perror(buf); + return FALSE; + } + } + KLP->dump->core_fd = fd; + + size = MIN_NETDUMP_ELF_HEADER_SIZE; + if (read(fd, header, size) != size) { + sprintf(buf, "%s: read", file); + perror(buf); + goto bailout; + } + + if (lseek(fd, 0, SEEK_SET) != 0) { + sprintf(buf, "%s: lseek", file); + perror(buf); + goto bailout; + } + + tmp_flags = 0; + elf32 = (Elf32_Ehdr *)&header[0]; + elf64 = (Elf64_Ehdr *)&header[0]; + + /* + * Verify the ELF header, and determine the dumpfile format. + * + * For now, kdump vmcores differ from netdump/diskdump like so: + * + * 1. The first kdump PT_LOAD segment is packed just after + * the ELF header, whereas netdump/diskdump page-align + * the first PT_LOAD segment. + * 2. Each kdump PT_LOAD segment has a p_align field of zero, + * whereas netdump/diskdump have their p_align fields set + * to the system page-size. + * + * If either kdump difference is seen, presume kdump -- this + * is obviously subject to change. + */ + if (STRNEQ(elf32->e_ident, ELFMAG) && + (elf32->e_ident[EI_CLASS] == ELFCLASS32) && + (elf32->e_ident[EI_DATA] == ELFDATA2LSB) && + (elf32->e_ident[EI_VERSION] == EV_CURRENT) && + (elf32->e_type == ET_CORE) && + (elf32->e_version == EV_CURRENT) && + (elf32->e_phnum >= 2)) { + switch (elf32->e_machine) + { + case EM_386: + if (machine_type("X86")) + break; + default: + goto bailout; + } + + load32 = (Elf32_Phdr *) + &header[sizeof(Elf32_Ehdr)+sizeof(Elf32_Phdr)]; + size = (size_t)load32->p_offset; + + if ((load32->p_offset & (MIN_PAGE_SIZE-1)) && + (load32->p_align == 0)) + tmp_flags |= KDUMP_ELF32; + else + tmp_flags |= NETDUMP_ELF32; + } else if (STRNEQ(elf64->e_ident, ELFMAG) && + (elf64->e_ident[EI_CLASS] == ELFCLASS64) && + (elf64->e_ident[EI_VERSION] == EV_CURRENT) && + (elf64->e_type == ET_CORE) && + (elf64->e_version == EV_CURRENT) && + (elf64->e_phnum >= 2)) { + switch (elf64->e_machine) + { + case EM_IA_64: + if ((elf64->e_ident[EI_DATA] == ELFDATA2LSB) && + machine_type("IA64")) + break; + else + goto bailout; + + case EM_PPC64: + if ((elf64->e_ident[EI_DATA] == ELFDATA2MSB) && + machine_type("PPC64")) + break; + else + goto bailout; + + case EM_X86_64: + if ((elf64->e_ident[EI_DATA] == ELFDATA2LSB) && + machine_type("X86_64")) + break; + else + goto bailout; + + case EM_386: + if ((elf64->e_ident[EI_DATA] == ELFDATA2LSB) && + machine_type("X86")) + break; + else + goto bailout; + + default: + goto bailout; + } + + load64 = (Elf64_Phdr *) + &header[sizeof(Elf64_Ehdr)+sizeof(Elf64_Phdr)]; + size = (size_t)load64->p_offset; + if ((load64->p_offset & (MIN_PAGE_SIZE-1)) && + (load64->p_align == 0)) + tmp_flags |= KDUMP_ELF64; + else + tmp_flags |= NETDUMP_ELF64; + } else + goto bailout; + + switch (DUMPFILE_FORMAT(tmp_flags)) + { + case NETDUMP_ELF32: + case NETDUMP_ELF64: + if (source_query & (NETDUMP_LOCAL|NETDUMP_REMOTE)) + break; + else + goto bailout; + + case KDUMP_ELF32: + case KDUMP_ELF64: + if (source_query & KDUMP_LOCAL) + break; + else + goto bailout; + } + + if ((tmp_elf_header = (char *)malloc(size)) == NULL) { + fprintf(stderr, "cannot malloc ELF header buffer\n"); + exit(1); + } + + if (read(fd, tmp_elf_header, size) != size) { + sprintf(buf, "%s: read", file); + perror(buf); + free(tmp_elf_header); + goto bailout; + } + + nd->ndfd = fd; + nd->elf_header = tmp_elf_header; + nd->flags = tmp_flags; + nd->flags |= source_query; + + switch (DUMPFILE_FORMAT(nd->flags)) + { + case NETDUMP_ELF32: + case KDUMP_ELF32: + nd->header_size = load32->p_offset; + nd->elf32 = (Elf32_Ehdr *)&nd->elf_header[0]; + nd->num_pt_load_segments = nd->elf32->e_phnum - 1; + if ((nd->pt_load_segments = (struct pt_load_segment *) + malloc(sizeof(struct pt_load_segment) * + nd->num_pt_load_segments)) == NULL) { + fprintf(stderr, "cannot malloc PT_LOAD segment buffers\n"); + exit(1); + } + nd->notes32 = (Elf32_Phdr *) + &nd->elf_header[sizeof(Elf32_Ehdr)]; + nd->load32 = (Elf32_Phdr *) + &nd->elf_header[sizeof(Elf32_Ehdr)+sizeof(Elf32_Phdr)]; + if (DUMPFILE_FORMAT(nd->flags) == NETDUMP_ELF32) + nd->page_size = (uint)nd->load32->p_align; + dump_Elf32_Ehdr(nd->elf32); + dump_Elf32_Phdr(nd->notes32, ELFREAD); + for (i = 0; i < nd->num_pt_load_segments; i++) + dump_Elf32_Phdr(nd->load32 + i, ELFSTORE+i); + offset32 = nd->notes32->p_offset; + for (tot = 0; tot < nd->notes32->p_filesz; tot += len) { + len = dump_Elf32_Nhdr(offset32, ELFSTORE); + offset32 += len; + } + break; + + case NETDUMP_ELF64: + case KDUMP_ELF64: + nd->header_size = load64->p_offset; + nd->elf64 = (Elf64_Ehdr *)&nd->elf_header[0]; + nd->num_pt_load_segments = nd->elf64->e_phnum - 1; + if ((nd->pt_load_segments = (struct pt_load_segment *) + malloc(sizeof(struct pt_load_segment) * + nd->num_pt_load_segments)) == NULL) { + fprintf(stderr, "cannot malloc PT_LOAD segment buffers\n"); + exit(1); + } + nd->notes64 = (Elf64_Phdr *) + &nd->elf_header[sizeof(Elf64_Ehdr)]; + nd->load64 = (Elf64_Phdr *) + &nd->elf_header[sizeof(Elf64_Ehdr)+sizeof(Elf64_Phdr)]; + if (DUMPFILE_FORMAT(nd->flags) == NETDUMP_ELF64) + nd->page_size = (uint)nd->load64->p_align; + dump_Elf64_Ehdr(nd->elf64); + dump_Elf64_Phdr(nd->notes64, ELFREAD); + for (i = 0; i < nd->num_pt_load_segments; i++) + dump_Elf64_Phdr(nd->load64 + i, ELFSTORE+i); + offset64 = nd->notes64->p_offset; + for (tot = 0; tot < nd->notes64->p_filesz; tot += len) { + len = dump_Elf64_Nhdr(offset64, ELFSTORE); + offset64 += len; + } + break; + } + + make_dump_header(); /* make the lkcd-style generic header */ + + return nd->header_size; + +bailout: + close(fd); + return FALSE; +} + +/* + * Read from a netdump-created dumpfile. + */ +int +read_netdump(int fd, void *bufptr, int cnt, ulong paddr) +{ + off_t offset; + struct pt_load_segment *pls; + int i; + + /* + * The Elf32_Phdr has 32-bit fields for p_paddr, p_filesz and + * p_memsz, so for now, multiple PT_LOAD segment support is + * restricted to 64-bit machines for netdump/diskdump vmcores. + * However, kexec/kdump has introduced the optional use of a + * 64-bit ELF header for 32-bit processors. + */ + switch (DUMPFILE_FORMAT(nd->flags)) + { + case NETDUMP_ELF32: + offset = (off_t)paddr + (off_t)nd->header_size; + break; + + case NETDUMP_ELF64: + case KDUMP_ELF32: + case KDUMP_ELF64: + if (nd->num_pt_load_segments == 1) { + offset = (off_t)paddr + (off_t)nd->header_size; + break; + } + + for (i = offset = 0; i < nd->num_pt_load_segments; i++) { + pls = &nd->pt_load_segments[i]; + if ((paddr >= pls->phys_start) && + (paddr < pls->phys_end)) { + offset = (off_t)(paddr - pls->phys_start) + + pls->file_offset; + break; + } + if (pls->zero_fill && (paddr >= pls->phys_end) && + (paddr < pls->zero_fill)) { + memset(bufptr, 0, cnt); + return cnt; + } + } + + if (!offset) { + return READ_ERROR; + } + + break; + } + + if (lseek(nd->ndfd, offset, SEEK_SET) == -1) + return SEEK_ERROR; + + if (read(nd->ndfd, bufptr, cnt) != cnt) + return READ_ERROR; + + return cnt; +} + +/* + * Generic print routine to handle integral and remote daemon output. + */ +static void +netdump_print(char *fmt, ...) +{ + char buf[BUFSIZE]; + va_list ap; + + if (!fmt || !strlen(fmt) || !VMCORE_VALID()) + return; + + va_start(ap, fmt); + (void)vsnprintf(buf, BUFSIZE, fmt, ap); + va_end(ap); + +} + +/* + * Dump an ELF file header. + */ +static void +dump_Elf32_Ehdr(Elf32_Ehdr *elf) +{ + char buf[BUFSIZE]; + + BZERO(buf, BUFSIZE); + BCOPY(elf->e_ident, buf, SELFMAG); + netdump_print("Elf32_Ehdr:\n"); + netdump_print(" e_ident: \\%o%s\n", buf[0], + &buf[1]); + netdump_print(" e_ident[EI_CLASS]: %d ", elf->e_ident[EI_CLASS]); + switch (elf->e_ident[EI_CLASS]) + { + case ELFCLASSNONE: + netdump_print("(ELFCLASSNONE)"); + break; + case ELFCLASS32: + netdump_print("(ELFCLASS32)\n"); + break; + case ELFCLASS64: + netdump_print("(ELFCLASS64)\n"); + break; + case ELFCLASSNUM: + netdump_print("(ELFCLASSNUM)\n"); + break; + default: + netdump_print("(?)\n"); + break; + } + netdump_print(" e_ident[EI_DATA]: %d ", elf->e_ident[EI_DATA]); + switch (elf->e_ident[EI_DATA]) + { + case ELFDATANONE: + netdump_print("(ELFDATANONE)\n"); + break; + case ELFDATA2LSB: + netdump_print("(ELFDATA2LSB)\n"); + break; + case ELFDATA2MSB: + netdump_print("(ELFDATA2MSB)\n"); + break; + case ELFDATANUM: + netdump_print("(ELFDATANUM)\n"); + break; + default: + netdump_print("(?)\n"); + } + netdump_print(" e_ident[EI_VERSION]: %d ", + elf->e_ident[EI_VERSION]); + if (elf->e_ident[EI_VERSION] == EV_CURRENT) + netdump_print("(EV_CURRENT)\n"); + else + netdump_print("(?)\n"); + netdump_print(" e_ident[EI_OSABI]: %d ", elf->e_ident[EI_OSABI]); + switch (elf->e_ident[EI_OSABI]) + { + case ELFOSABI_SYSV: + netdump_print("(ELFOSABI_SYSV)\n"); + break; + case ELFOSABI_HPUX: + netdump_print("(ELFOSABI_HPUX)\n"); + break; + case ELFOSABI_ARM: + netdump_print("(ELFOSABI_ARM)\n"); + break; + case ELFOSABI_STANDALONE: + netdump_print("(ELFOSABI_STANDALONE)\n"); + break; + default: + netdump_print("(?)\n"); + } + netdump_print(" e_ident[EI_ABIVERSION]: %d\n", + elf->e_ident[EI_ABIVERSION]); + + netdump_print(" e_type: %d ", elf->e_type); + switch (elf->e_type) + { + case ET_NONE: + netdump_print("(ET_NONE)\n"); + break; + case ET_REL: + netdump_print("(ET_REL)\n"); + break; + case ET_EXEC: + netdump_print("(ET_EXEC)\n"); + break; + case ET_DYN: + netdump_print("(ET_DYN)\n"); + break; + case ET_CORE: + netdump_print("(ET_CORE)\n"); + break; + case ET_NUM: + netdump_print("(ET_NUM)\n"); + break; + case ET_LOOS: + netdump_print("(ET_LOOS)\n"); + break; + case ET_HIOS: + netdump_print("(ET_HIOS)\n"); + break; + case ET_LOPROC: + netdump_print("(ET_LOPROC)\n"); + break; + case ET_HIPROC: + netdump_print("(ET_HIPROC)\n"); + break; + default: + netdump_print("(?)\n"); + } + + netdump_print(" e_machine: %d ", elf->e_machine); + switch (elf->e_machine) + { + case EM_386: + netdump_print("(EM_386)\n"); + break; + default: + netdump_print("(unsupported)\n"); + break; + } + + netdump_print(" e_version: %ld ", elf->e_version); + netdump_print("%s\n", elf->e_version == EV_CURRENT ? + "(EV_CURRENT)" : ""); + + netdump_print(" e_entry: %lx\n", elf->e_entry); + netdump_print(" e_phoff: %lx\n", elf->e_phoff); + netdump_print(" e_shoff: %lx\n", elf->e_shoff); + netdump_print(" e_flags: %lx\n", elf->e_flags); + netdump_print(" e_ehsize: %x\n", elf->e_ehsize); + netdump_print(" e_phentsize: %x\n", elf->e_phentsize); + netdump_print(" e_phnum: %x\n", elf->e_phnum); + netdump_print(" e_shentsize: %x\n", elf->e_shentsize); + netdump_print(" e_shnum: %x\n", elf->e_shnum); + netdump_print(" e_shstrndx: %x\n", elf->e_shstrndx); +} + +static void +dump_Elf64_Ehdr(Elf64_Ehdr *elf) +{ + char buf[BUFSIZE]; + + BZERO(buf, BUFSIZE); + BCOPY(elf->e_ident, buf, SELFMAG); + netdump_print("Elf64_Ehdr:\n"); + netdump_print(" e_ident: \\%o%s\n", buf[0], + &buf[1]); + netdump_print(" e_ident[EI_CLASS]: %d ", elf->e_ident[EI_CLASS]); + switch (elf->e_ident[EI_CLASS]) + { + case ELFCLASSNONE: + netdump_print("(ELFCLASSNONE)"); + break; + case ELFCLASS32: + netdump_print("(ELFCLASS32)\n"); + break; + case ELFCLASS64: + netdump_print("(ELFCLASS64)\n"); + break; + case ELFCLASSNUM: + netdump_print("(ELFCLASSNUM)\n"); + break; + default: + netdump_print("(?)\n"); + break; + } + netdump_print(" e_ident[EI_DATA]: %d ", elf->e_ident[EI_DATA]); + switch (elf->e_ident[EI_DATA]) + { + case ELFDATANONE: + netdump_print("(ELFDATANONE)\n"); + break; + case ELFDATA2LSB: + netdump_print("(ELFDATA2LSB)\n"); + break; + case ELFDATA2MSB: + netdump_print("(ELFDATA2MSB)\n"); + break; + case ELFDATANUM: + netdump_print("(ELFDATANUM)\n"); + break; + default: + netdump_print("(?)\n"); + } + netdump_print(" e_ident[EI_VERSION]: %d ", + elf->e_ident[EI_VERSION]); + if (elf->e_ident[EI_VERSION] == EV_CURRENT) + netdump_print("(EV_CURRENT)\n"); + else + netdump_print("(?)\n"); + netdump_print(" e_ident[EI_OSABI]: %d ", elf->e_ident[EI_OSABI]); + switch (elf->e_ident[EI_OSABI]) + { + case ELFOSABI_SYSV: + netdump_print("(ELFOSABI_SYSV)\n"); + break; + case ELFOSABI_HPUX: + netdump_print("(ELFOSABI_HPUX)\n"); + break; + case ELFOSABI_ARM: + netdump_print("(ELFOSABI_ARM)\n"); + break; + case ELFOSABI_STANDALONE: + netdump_print("(ELFOSABI_STANDALONE)\n"); + break; + default: + netdump_print("(?)\n"); + } + netdump_print(" e_ident[EI_ABIVERSION]: %d\n", + elf->e_ident[EI_ABIVERSION]); + + netdump_print(" e_type: %d ", elf->e_type); + switch (elf->e_type) + { + case ET_NONE: + netdump_print("(ET_NONE)\n"); + break; + case ET_REL: + netdump_print("(ET_REL)\n"); + break; + case ET_EXEC: + netdump_print("(ET_EXEC)\n"); + break; + case ET_DYN: + netdump_print("(ET_DYN)\n"); + break; + case ET_CORE: + netdump_print("(ET_CORE)\n"); + break; + case ET_NUM: + netdump_print("(ET_NUM)\n"); + break; + case ET_LOOS: + netdump_print("(ET_LOOS)\n"); + break; + case ET_HIOS: + netdump_print("(ET_HIOS)\n"); + break; + case ET_LOPROC: + netdump_print("(ET_LOPROC)\n"); + break; + case ET_HIPROC: + netdump_print("(ET_HIPROC)\n"); + break; + default: + netdump_print("(?)\n"); + } + + netdump_print(" e_machine: %d ", elf->e_machine); + switch (elf->e_machine) + { + case EM_386: + netdump_print("(EM_386)\n"); + break; + case EM_IA_64: + netdump_print("(EM_IA_64)\n"); + break; + case EM_PPC64: + netdump_print("(EM_PPC64)\n"); + break; + case EM_X86_64: + netdump_print("(EM_X86_64)\n"); + break; + default: + netdump_print("(unsupported)\n"); + break; + } + + netdump_print(" e_version: %ld ", elf->e_version); + netdump_print("%s\n", elf->e_version == EV_CURRENT ? + "(EV_CURRENT)" : ""); + + netdump_print(" e_entry: %lx\n", elf->e_entry); + netdump_print(" e_phoff: %lx\n", elf->e_phoff); + netdump_print(" e_shoff: %lx\n", elf->e_shoff); + netdump_print(" e_flags: %lx\n", elf->e_flags); + netdump_print(" e_ehsize: %x\n", elf->e_ehsize); + netdump_print(" e_phentsize: %x\n", elf->e_phentsize); + netdump_print(" e_phnum: %x\n", elf->e_phnum); + netdump_print(" e_shentsize: %x\n", elf->e_shentsize); + netdump_print(" e_shnum: %x\n", elf->e_shnum); + netdump_print(" e_shstrndx: %x\n", elf->e_shstrndx); +} + +/* + * Dump a program segment header + */ +static void +dump_Elf32_Phdr(Elf32_Phdr *prog, int store_pt_load_data) +{ + int others; + struct pt_load_segment *pls; + + if (store_pt_load_data) + pls = &nd->pt_load_segments[store_pt_load_data-1]; + + netdump_print("Elf32_Phdr:\n"); + netdump_print(" p_type: %lx ", prog->p_type); + switch (prog->p_type) + { + case PT_NULL: + netdump_print("(PT_NULL)\n"); + break; + case PT_LOAD: + netdump_print("(PT_LOAD)\n"); + break; + case PT_DYNAMIC: + netdump_print("(PT_DYNAMIC)\n"); + break; + case PT_INTERP: + netdump_print("(PT_INTERP)\n"); + break; + case PT_NOTE: + netdump_print("(PT_NOTE)\n"); + break; + case PT_SHLIB: + netdump_print("(PT_SHLIB)\n"); + break; + case PT_PHDR: + netdump_print("(PT_PHDR)\n"); + break; + case PT_NUM: + netdump_print("(PT_NUM)\n"); + break; + case PT_LOOS: + netdump_print("(PT_LOOS)\n"); + break; + case PT_HIOS: + netdump_print("(PT_HIOS)\n"); + break; + case PT_LOPROC: + netdump_print("(PT_LOPROC)\n"); + break; + case PT_HIPROC: + netdump_print("(PT_HIPROC)\n"); + break; + default: + netdump_print("(?)\n"); + } + + netdump_print(" p_offset: %ld (%lx)\n", prog->p_offset, + prog->p_offset); + if (store_pt_load_data) + pls->file_offset = prog->p_offset; + netdump_print(" p_vaddr: %lx\n", prog->p_vaddr); + netdump_print(" p_paddr: %lx\n", prog->p_paddr); + if (store_pt_load_data) + pls->phys_start = prog->p_paddr; + netdump_print(" p_filesz: %lu (%lx)\n", prog->p_filesz, + prog->p_filesz); + if (store_pt_load_data) { + pls->phys_end = pls->phys_start + prog->p_filesz; + pls->zero_fill = (prog->p_filesz == prog->p_memsz) ? + 0 : pls->phys_start + prog->p_memsz; + } + netdump_print(" p_memsz: %lu (%lx)\n", prog->p_memsz, + prog->p_memsz); + netdump_print(" p_flags: %lx (", prog->p_flags); + others = 0; + if (prog->p_flags & PF_X) + netdump_print("PF_X", others++); + if (prog->p_flags & PF_W) + netdump_print("%sPF_W", others++ ? "|" : ""); + if (prog->p_flags & PF_R) + netdump_print("%sPF_R", others++ ? "|" : ""); + netdump_print(")\n"); + netdump_print(" p_align: %ld\n", prog->p_align); +} + +static void +dump_Elf64_Phdr(Elf64_Phdr *prog, int store_pt_load_data) +{ + int others; + struct pt_load_segment *pls; + + if (store_pt_load_data) + pls = &nd->pt_load_segments[store_pt_load_data-1]; + + netdump_print("Elf64_Phdr:\n"); + netdump_print(" p_type: %lx ", prog->p_type); + switch (prog->p_type) + { + case PT_NULL: + netdump_print("(PT_NULL)\n"); + break; + case PT_LOAD: + netdump_print("(PT_LOAD)\n"); + break; + case PT_DYNAMIC: + netdump_print("(PT_DYNAMIC)\n"); + break; + case PT_INTERP: + netdump_print("(PT_INTERP)\n"); + break; + case PT_NOTE: + netdump_print("(PT_NOTE)\n"); + break; + case PT_SHLIB: + netdump_print("(PT_SHLIB)\n"); + break; + case PT_PHDR: + netdump_print("(PT_PHDR)\n"); + break; + case PT_NUM: + netdump_print("(PT_NUM)\n"); + break; + case PT_LOOS: + netdump_print("(PT_LOOS)\n"); + break; + case PT_HIOS: + netdump_print("(PT_HIOS)\n"); + break; + case PT_LOPROC: + netdump_print("(PT_LOPROC)\n"); + break; + case PT_HIPROC: + netdump_print("(PT_HIPROC)\n"); + break; + default: + netdump_print("(?)\n"); + } + + netdump_print(" p_offset: %ld (%lx)\n", prog->p_offset, + prog->p_offset); + if (store_pt_load_data) + pls->file_offset = prog->p_offset; + netdump_print(" p_vaddr: %lx\n", prog->p_vaddr); + netdump_print(" p_paddr: %lx\n", prog->p_paddr); + if (store_pt_load_data) { + pls->phys_start = prog->p_paddr; + } + netdump_print(" p_filesz: %lu (%lx)\n", prog->p_filesz, + prog->p_filesz); + if (store_pt_load_data) { + pls->phys_end = pls->phys_start + prog->p_filesz; + pls->zero_fill = (prog->p_filesz == prog->p_memsz) ? + 0 : pls->phys_start + prog->p_memsz; + } + netdump_print(" p_memsz: %lu (%lx)\n", prog->p_memsz, + prog->p_memsz); + netdump_print(" p_flags: %lx (", prog->p_flags); + others = 0; + if (prog->p_flags & PF_X) + netdump_print("PF_X", others++); + if (prog->p_flags & PF_W) + netdump_print("%sPF_W", others++ ? "|" : ""); + if (prog->p_flags & PF_R) + netdump_print("%sPF_R", others++ ? "|" : ""); + netdump_print(")\n"); + netdump_print(" p_align: %ld\n", prog->p_align); +} + +/* + * Dump a note section header -- the actual data is defined by netdump + */ + +static size_t +dump_Elf32_Nhdr(Elf32_Off offset, int store) +{ + int i, lf, words; + Elf32_Nhdr *note; + size_t len; + char buf[BUFSIZE]; + char *ptr; + ulong *uptr; + int xen_core; + + note = (Elf32_Nhdr *)((char *)nd->elf32 + offset); + + netdump_print("Elf32_Nhdr:\n"); + netdump_print(" n_namesz: %ld ", note->n_namesz); + BZERO(buf, BUFSIZE); + xen_core = FALSE; + ptr = (char *)note + sizeof(Elf32_Nhdr); + BCOPY(ptr, buf, note->n_namesz); + netdump_print("(\"%s\")\n", buf); + + netdump_print(" n_descsz: %ld\n", note->n_descsz); + netdump_print(" n_type: %lx ", note->n_type); + switch (note->n_type) + { + case NT_PRSTATUS: + netdump_print("(NT_PRSTATUS)\n"); + if (store) { + if (!nd->nt_prstatus) + nd->nt_prstatus = (void *)note; + for (i = 0; i < NR_CPUS; i++) { + if (!nd->nt_prstatus_percpu[i]) { + nd->nt_prstatus_percpu[i] = (void *)note; + nd->num_prstatus_notes++; + break; + } + } + } + break; + case NT_PRPSINFO: + netdump_print("(NT_PRPSINFO)\n"); + if (store) + nd->nt_prpsinfo = (void *)note; + break; + case NT_TASKSTRUCT: + netdump_print("(NT_TASKSTRUCT)\n"); + if (store) { + nd->nt_taskstruct = (void *)note; + nd->task_struct = *((ulong *)(ptr + note->n_namesz)); + nd->switch_stack = *((ulong *) + (ptr + note->n_namesz + sizeof(ulong))); + } + break; + case NT_DISKDUMP: + netdump_print("(NT_DISKDUMP)\n"); + uptr = (ulong *)(ptr + note->n_namesz); + if (*uptr && store) + nd->flags |= PARTIAL_DUMP; + break; +#ifdef NOTDEF + /* + * Note: Based upon the original, abandoned, proposal for + * its contents -- keep around for potential future use. + */ + case NT_KDUMPINFO: + netdump_print("(NT_KDUMPINFO)\n"); + if (store) { + uptr = (note->n_namesz == 5) ? + (ulong *)(ptr + ((note->n_namesz + 3) & ~3)) : + (ulong *)(ptr + note->n_namesz); + nd->page_size = (uint)(1 << *uptr); + uptr++; + nd->task_struct = *uptr; + } + break; +#endif + default: + xen_core = STRNEQ(buf, "XEN CORE") || STRNEQ(buf, "Xen"); + if (xen_core) { + netdump_print("(unknown Xen n_type)\n"); + if (store) + error(WARNING, "unknown Xen n_type: %lx\n\n", + note->n_type); + } else + netdump_print("(?)\n"); + break; + + case NT_XEN_KDUMP_CR3: + netdump_print("(NT_XEN_KDUMP_CR3) [obsolete]\n"); + if (store) + error(WARNING, + "obsolete Xen n_type: %lx (NT_XEN_KDUMP_CR3)\n\n", + note->n_type); + /* FALL THROUGH */ + + case XEN_ELFNOTE_CRASH_INFO: + /* + * x86 and x86_64: p2m mfn appended to crash_xen_info_t structure + */ + if (note->n_type == XEN_ELFNOTE_CRASH_INFO) + netdump_print("(XEN_ELFNOTE_CRASH_INFO)\n"); + xen_core = TRUE; + if (store) { + pc->flags |= XEN_CORE; + nd->xen_kdump_data = &xen_kdump_data; + nd->xen_kdump_data->last_mfn_read = UNINITIALIZED; + nd->xen_kdump_data->last_pmd_read = UNINITIALIZED; + + if ((note->n_type == NT_XEN_KDUMP_CR3) && + ((note->n_descsz/sizeof(ulong)) == 1)) { + nd->xen_kdump_data->flags |= KDUMP_CR3; + /* + * Use the first cr3 found. + */ + if (!nd->xen_kdump_data->cr3) { + uptr = (ulong *)(ptr + note->n_namesz); + uptr = (ulong *)roundup((ulong)uptr, 4); + nd->xen_kdump_data->cr3 = *uptr; + } + } else { + nd->xen_kdump_data->flags |= KDUMP_MFN_LIST; + uptr = (ulong *)(ptr + note->n_namesz); + uptr = (ulong *)roundup((ulong)uptr, 4); + words = note->n_descsz/sizeof(ulong); + /* + * If already set, overridden with --pfm_mfn + */ + if (!nd->xen_kdump_data->p2m_mfn) + nd->xen_kdump_data->p2m_mfn = *(uptr+(words-1)); + } + } + break; + + case XEN_ELFNOTE_CRASH_REGS: + /* + * x86 and x86_64: cr0, cr2, cr3, cr4 + */ + xen_core = TRUE; + netdump_print("(XEN_ELFNOTE_CRASH_REGS)\n"); + break; + } + + uptr = (ulong *)(ptr + note->n_namesz); + + /* + * kdumps are off-by-1, because their n_namesz is 5 for "CORE". + */ + if ((nd->flags & KDUMP_ELF32) && (note->n_namesz == 5)) + uptr = (ulong *)(ptr + ((note->n_namesz + 3) & ~3)); + + if (xen_core) + uptr = (ulong *)roundup((ulong)uptr, 4); + + for (i = lf = 0; i < note->n_descsz/sizeof(ulong); i++) { + if (((i%4)==0)) { + netdump_print("%s ", + i ? "\n" : ""); + lf++; + } else + lf = 0; + netdump_print("%08lx ", *uptr++); + } + if (!lf || (note->n_type == NT_TASKSTRUCT) || + (note->n_type == NT_DISKDUMP) || xen_core) + netdump_print("\n"); + + len = sizeof(Elf32_Nhdr); + len = roundup(len + note->n_namesz, 4); + len = roundup(len + note->n_descsz, 4); + + return len; +} + + +static size_t +dump_Elf64_Nhdr(Elf64_Off offset, int store) +{ + int i, lf, words; + Elf64_Nhdr *note; + size_t len; + char buf[BUFSIZE]; + char *ptr; + ulonglong *uptr; + int *iptr; + ulong *up; + int xen_core; + + note = (Elf64_Nhdr *)((char *)nd->elf64 + offset); + + netdump_print("Elf64_Nhdr:\n"); + netdump_print(" n_namesz: %ld ", note->n_namesz); + BZERO(buf, BUFSIZE); + ptr = (char *)note + sizeof(Elf64_Nhdr); + xen_core = FALSE; + BCOPY(ptr, buf, note->n_namesz); + netdump_print("(\"%s\")\n", buf); + + netdump_print(" n_descsz: %ld\n", note->n_descsz); + netdump_print(" n_type: %lx ", note->n_type); + switch (note->n_type) + { + case NT_PRSTATUS: + netdump_print("(NT_PRSTATUS)\n"); + if (store) { + if (!nd->nt_prstatus) + nd->nt_prstatus = (void *)note; + for (i = 0; i < NR_CPUS; i++) { + if (!nd->nt_prstatus_percpu[i]) { + nd->nt_prstatus_percpu[i] = (void *)note; + nd->num_prstatus_notes++; + break; + } + } + } + break; + case NT_PRPSINFO: + netdump_print("(NT_PRPSINFO)\n"); + if (store) + nd->nt_prpsinfo = (void *)note; + break; + case NT_TASKSTRUCT: + netdump_print("(NT_TASKSTRUCT)\n"); + if (store) { + nd->nt_taskstruct = (void *)note; + nd->task_struct = *((ulong *)(ptr + note->n_namesz)); + nd->switch_stack = *((ulong *) + (ptr + note->n_namesz + sizeof(ulong))); + } + break; + case NT_DISKDUMP: + netdump_print("(NT_DISKDUMP)\n"); + iptr = (int *)(ptr + note->n_namesz); + if (*iptr && store) + nd->flags |= PARTIAL_DUMP; + if (note->n_descsz < sizeof(ulonglong)) + netdump_print(" %08x", *iptr); + break; +#ifdef NOTDEF + /* + * Note: Based upon the original, abandoned, proposal for + * its contents -- keep around for potential future use. + */ + case NT_KDUMPINFO: + netdump_print("(NT_KDUMPINFO)\n"); + if (store) { + uint32_t *u32ptr; + + if (nd->elf64->e_machine == EM_386) { + u32ptr = (note->n_namesz == 5) ? + (uint *)(ptr + ((note->n_namesz + 3) & ~3)) : + (uint *)(ptr + note->n_namesz); + nd->page_size = 1 << *u32ptr; + u32ptr++; + nd->task_struct = *u32ptr; + } else { + uptr = (note->n_namesz == 5) ? + (ulonglong *)(ptr + ((note->n_namesz + 3) & ~3)) : + (ulonglong *)(ptr + note->n_namesz); + nd->page_size = (uint)(1 << *uptr); + uptr++; + nd->task_struct = *uptr; + } + } + break; +#endif + default: + xen_core = STRNEQ(buf, "XEN CORE") || STRNEQ(buf, "Xen"); + if (xen_core) { + netdump_print("(unknown Xen n_type)\n"); + if (store) + error(WARNING, + "unknown Xen n_type: %lx\n\n", note->n_type); + } else + netdump_print("(?)\n"); + break; + + case NT_XEN_KDUMP_CR3: + netdump_print("(NT_XEN_KDUMP_CR3) [obsolete]\n"); + if (store) + error(WARNING, + "obsolete Xen n_type: %lx (NT_XEN_KDUMP_CR3)\n\n", + note->n_type); + /* FALL THROUGH */ + + case XEN_ELFNOTE_CRASH_INFO: + /* + * x86 and x86_64: p2m mfn appended to crash_xen_info_t structure + */ + if (note->n_type == XEN_ELFNOTE_CRASH_INFO) + netdump_print("(XEN_ELFNOTE_CRASH_INFO)\n"); + xen_core = TRUE; + if (store) { + pc->flags |= XEN_CORE; + nd->xen_kdump_data = &xen_kdump_data; + nd->xen_kdump_data->last_mfn_read = UNINITIALIZED; + nd->xen_kdump_data->last_pmd_read = UNINITIALIZED; + + if ((note->n_type == NT_XEN_KDUMP_CR3) && + ((note->n_descsz/sizeof(ulong)) == 1)) { + nd->xen_kdump_data->flags |= KDUMP_CR3; + /* + * Use the first cr3 found. + */ + if (!nd->xen_kdump_data->cr3) { + up = (ulong *)(ptr + note->n_namesz); + up = (ulong *)roundup((ulong)up, 4); + nd->xen_kdump_data->cr3 = *up; + } + } else { + nd->xen_kdump_data->flags |= KDUMP_MFN_LIST; + up = (ulong *)(ptr + note->n_namesz); + up = (ulong *)roundup((ulong)up, 4); + words = note->n_descsz/sizeof(ulong); + /* + * If already set, overridden with --p2m_mfn + */ + if (!nd->xen_kdump_data->p2m_mfn) + nd->xen_kdump_data->p2m_mfn = *(up+(words-1)); + } + } + break; + + case XEN_ELFNOTE_CRASH_REGS: + /* + * x86 and x86_64: cr0, cr2, cr3, cr4 + */ + xen_core = TRUE; + netdump_print("(XEN_ELFNOTE_CRASH_REGS)\n"); + break; + } + + uptr = (ulonglong *)(ptr + note->n_namesz); + + /* + * kdumps are off-by-1, because their n_namesz is 5 for "CORE". + */ + if ((nd->flags & KDUMP_ELF64) && (note->n_namesz == 5)) + uptr = (ulonglong *)(ptr + ((note->n_namesz + 3) & ~3)); + + if (xen_core) + uptr = (ulonglong *)roundup((ulong)uptr, 4); + + if (BITS32() && (xen_core || (note->n_type == NT_PRSTATUS))) { + iptr = (int *)uptr; + for (i = lf = 0; i < note->n_descsz/sizeof(ulong); i++) { + if (((i%4)==0)) { + netdump_print("%s ", + i ? "\n" : ""); + lf++; + } else + lf = 0; + netdump_print("%08lx ", *iptr++); + } + } else { + for (i = lf = 0; i < note->n_descsz/sizeof(ulonglong); i++) { + if (((i%2)==0)) { + netdump_print("%s ", + i ? "\n" : ""); + lf++; + } else + lf = 0; + netdump_print("%016llx ", *uptr++); + } + } + if (!lf) + netdump_print("\n"); + else if (i && (i&1)) + netdump_print("\n"); + + len = sizeof(Elf64_Nhdr); + len = roundup(len + note->n_namesz, 4); + len = roundup(len + note->n_descsz, 4); + + return len; +} Index: lkcdutils/lcrash/Makefile =================================================================== --- lkcdutils.orig/lcrash/Makefile +++ lkcdutils/lcrash/Makefile @@ -23,7 +23,7 @@ EXTRA_LFLAGS += $(LFLAGS) -L. -L$(LKCDLI # common lcrash code COMMON = main.c util.c eval.c stabs.c struct.c dump.c sial.c \ - module.c dis.c arch.c trace.c report.c pci.c + module.c dis.c arch.c trace.c report.c pci.c netdump.c # dump architecture specific lcrash code DUMP_ALPHA = arch_alpha.c dis_alpha.c trace_alpha.c Index: lkcdutils/lcrash/netdump.h =================================================================== --- /dev/null +++ lkcdutils/lcrash/netdump.h @@ -0,0 +1,119 @@ +/* netdump.h + * + * Copyright (C) 2002, 2003, 2004, 2005 David Anderson + * Copyright (C) 2002, 2003, 2004, 2005 Red Hat, Inc. All rights reserved. + * Borrowed from the crash project for LKCD by Cliff Wickman. 6/2007 + * + * This software may be freely redistributed under the terms of the + * GNU General Public License. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Author: David Anderson + */ + +#include <elf.h> + +#define MIN_NETDUMP_ELF32_HEADER_SIZE \ + sizeof(Elf32_Ehdr)+sizeof(Elf32_Phdr)+sizeof(Elf32_Phdr) +#define MIN_NETDUMP_ELF64_HEADER_SIZE \ + sizeof(Elf64_Ehdr)+sizeof(Elf64_Phdr)+sizeof(Elf64_Phdr) +#define MIN_NETDUMP_ELF_HEADER_SIZE \ + MAX(MIN_NETDUMP_ELF32_HEADER_SIZE, MIN_NETDUMP_ELF64_HEADER_SIZE) + +#define NT_TASKSTRUCT 4 +#define NT_DISKDUMP 0x70000001 + +#ifdef NOTDEF +/* + * Note: Based upon the original, abandoned, proposal for + * its contents -- keep around for potential future use. + */ +#ifndef NT_KDUMPINFO +#define NT_KDUMPINFO 7 +#endif + +#endif /* NOTDEF */ + +struct pt_load_segment { + off_t file_offset; + physaddr_t phys_start; + physaddr_t phys_end; + physaddr_t zero_fill; +}; + +struct vmcore_data { + ulong flags; + int ndfd; + FILE *ofp; + uint header_size; + char *elf_header; + uint num_pt_load_segments; + struct pt_load_segment *pt_load_segments; + Elf32_Ehdr *elf32; + Elf32_Phdr *notes32; + Elf32_Phdr *load32; + Elf64_Ehdr *elf64; + Elf64_Phdr *notes64; + Elf64_Phdr *load64; + void *nt_prstatus; + void *nt_prpsinfo; + void *nt_taskstruct; + ulong task_struct; + uint page_size; + ulong switch_stack; + uint num_prstatus_notes; + void *nt_prstatus_percpu[NR_CPUS]; + struct xen_kdump_data *xen_kdump_data; +}; + +/* + * ELF note types for Xen dom0/hypervisor kdumps. + * The comments below are from xen/include/public/elfnote.h. + */ + +/* + * System information exported through crash notes. + * + * The kexec / kdump code will create one XEN_ELFNOTE_CRASH_INFO + * note in case of a system crash. This note will contain various + * information about the system, see xen/include/xen/elfcore.h. + */ +#define XEN_ELFNOTE_CRASH_INFO 0x1000001 + +/* + * System registers exported through crash notes. + * + * The kexec / kdump code will create one XEN_ELFNOTE_CRASH_REGS + * note per cpu in case of a system crash. This note is architecture + * specific and will contain registers not saved in the "CORE" note. + * See xen/include/xen/elfcore.h for more information. + */ +#define XEN_ELFNOTE_CRASH_REGS 0x1000002 + + +/* + * For (temporary) backwards compatibility. + */ +#define NT_XEN_KDUMP_CR3 0x10000001 + +struct xen_kdump_data { + ulong flags; + ulong cr3; + ulong p2m_mfn; + char *page; + ulong last_mfn_read; + ulong last_pmd_read; + ulong cache_hits; + ulong accesses; + int p2m_frames; + ulong *p2m_mfn_frame_list; +}; + +#define KDUMP_P2M_INIT (0x1) +#define KDUMP_CR3 (0x2) +#define KDUMP_MFN_LIST (0x4) + +#define P2M_FAILURE ((physaddr_t)(0xffffffffffffffffLL)) Index: lkcdutils/lcrash/defs.h =================================================================== --- /dev/null +++ lkcdutils/lcrash/defs.h @@ -0,0 +1,4392 @@ +/* defs.h - core analysis suite + * + * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. + * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 David Anderson + * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Red Hat, Inc. All rights reserved. + * Copyright (C) 2002 Silicon Graphics, Inc. + * Borrowed from the crash project for LKCD by Cliff Wickman. 6/2007 + * + * 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. + */ + +#ifndef GDB_COMMON + +#include <stdio.h> +#include <stdarg.h> +#include <stdint.h> +#include <termios.h> +#include <unistd.h> +#include <sys/mman.h> +#include <setjmp.h> +#undef basename +#if !defined(__USE_GNU) +#define __USE_GNU +#include <string.h> +#undef __USE_GNU +#else +#include <string.h> +#endif +#include <fcntl.h> +#include <stdlib.h> +#include <signal.h> +#include <assert.h> +#include <errno.h> +#include <dirent.h> +#include <time.h> +#include <zlib.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/param.h> +#include <sys/wait.h> +#include <sys/time.h> + +#define BASELEVEL_REVISION "4.0" + +#undef TRUE +#undef FALSE + +#define TRUE (1) +#define FALSE (0) + +#ifdef X86 +#define NR_CPUS (256) +#endif +#ifdef DUMP_ARCH_X86_64 +#define NR_CPUS (256) +#endif +#ifdef ALPHA +#define NR_CPUS (64) +#endif +#ifdef PPC +#define NR_CPUS (32) +#endif +#ifdef IA64 +#define NR_CPUS (1024) +#endif +#ifdef PPC64 +#define NR_CPUS (128) +#endif +#ifdef S390 +#define NR_CPUS (64) +#endif +#ifdef S390X +#define NR_CPUS (64) +#endif + +#define BUFSIZE (1500) +#define NULLCHAR ('\0') + +#define MAXARGS (100) /* max number of arguments to one function */ +#define MAXARGLEN (40) /* max length of argument */ + +#define HIST_BLKSIZE (4096) + +#define STREQ(A, B) (A && B && (strcmp((char *)(A), (char *)(B)) == 0)) +#define STRNEQ(A, B) (A && B && \ + (strncmp((char *)(A), (char *)(B), strlen((char *)(B))) == 0)) +#define BZERO(S, N) (memset(S, NULLCHAR, N)) +#define BCOPY(S, D, C) (memcpy(D, S, C)) +#define BNEG(S, N) (memset(S, 0xff, N)) +#define BEEP() fprintf(stderr, "%c", 0x7) +#define LASTCHAR(s) (s[strlen(s)-1]) +#define FIRSTCHAR(s) (s[0]) +#define QUOTED_STRING(s) ((FIRSTCHAR(s) == '"') && (LASTCHAR(s) == '"')) +#define PATHEQ(A, B) ((A) && (B) && (pathcmp((char *)(A), (char *)(B)) == 0)) + +#ifdef roundup +#undef roundup +#endif +#define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) + +typedef uint64_t physaddr_t; + +#define PADDR_NOT_AVAILABLE (0x1ULL) + +typedef unsigned long long int ulonglong; +struct number_option { + ulong num; + ulonglong ll_num; + ulong retflags; +}; + +/* + * program_context flags + */ +#define LIVE_SYSTEM (0x1ULL) +#define TTY (0x2ULL) +#define RUNTIME (0x4ULL) +#define IN_FOREACH (0x8ULL) +#define MCLXCD (0x10ULL) +#define CMDLINE_IFILE (0x20ULL) +#define MFD_RDWR (0x40ULL) +#define DFD_RDWR (0x80ULL) +#define SILENT (0x100ULL) +#define REMOTE_DAEMON (0x200ULL) +#define HASH (0x400ULL) +#define SCROLL (0x800ULL) +#define NO_CONSOLE (0x1000ULL) +#define RUNTIME_IFILE (0x2000ULL) +#define DROP_CORE (0x4000ULL) +#define LKCD (0x8000ULL) +#define GDB_INIT (0x10000ULL) +#define IN_GDB (0x20000ULL) +#define RCLOCAL_IFILE (0x40000ULL) +#define RCHOME_IFILE (0x80000ULL) +#define GET_TIMESTAMP (0x100000ULL) +#define READLINE (0x200000ULL) +#define _SIGINT_ (0x400000ULL) +#define IN_RESTART (0x800000ULL) +#define KERNEL_DEBUG_QUERY (0x1000000ULL) +#define DEVMEM (0x2000000ULL) +#define REM_LIVE_SYSTEM (0x4000000ULL) +#define NAMELIST_LOCAL (0x8000000ULL) +#define MEMSRC_LOCAL (0x10000000ULL) +#define NAMELIST_SAVED (0x20000000ULL) +#define DUMPFILE_SAVED (0x40000000ULL) +#define UNLINK_NAMELIST (0x80000000ULL) +#define NAMELIST_UNLINKED (0x100000000ULL) +#define REM_MCLXCD (0x200000000ULL) +#define REM_LKCD (0x400000000ULL) +#define NAMELIST_NO_GZIP (0x800000000ULL) +#define UNLINK_MODULES (0x1000000000ULL) +#define S390D (0x2000000000ULL) +#define REM_S390D (0x4000000000ULL) +#define SYSRQ (0x8000000000ULL) +#define KDUMP (0x10000000000ULL) +#define NETDUMP (0x20000000000ULL) +#define REM_NETDUMP (0x40000000000ULL) +#define SYSMAP (0x80000000000ULL) +#define SYSMAP_ARG (0x100000000000ULL) +#define MEMMOD (0x200000000000ULL) +#define MODPRELOAD (0x400000000000ULL) +#define DISKDUMP (0x800000000000ULL) +#define DATADEBUG (0x1000000000000ULL) +#define FINDKERNEL (0x2000000000000ULL) +#define VERSION_QUERY (0x4000000000000ULL) +#define READNOW (0x8000000000000ULL) +#define NOCRASHRC (0x10000000000000ULL) +#define INIT_IFILE (0x20000000000000ULL) +#define XENDUMP (0x40000000000000ULL) +#define XEN_HYPER (0x80000000000000ULL) +#define XEN_CORE (0x100000000000000ULL) +#define PLEASE_WAIT (0x200000000000000ULL) + +#define ACTIVE() (pc->flags & LIVE_SYSTEM) +#define DUMPFILE() (!(pc->flags & LIVE_SYSTEM)) +#define MEMORY_SOURCES (NETDUMP|KDUMP|MCLXCD|LKCD|DEVMEM|S390D|MEMMOD|DISKDUMP|XENDUMP) +#define DUMPFILE_TYPES (DISKDUMP|NETDUMP|KDUMP|MCLXCD|LKCD|S390D|XENDUMP) +#define REMOTE() (pc->flags & REMOTE_DAEMON) +#define REMOTE_ACTIVE() (pc->flags & REM_LIVE_SYSTEM) +#define REMOTE_DUMPFILE() \ + (pc->flags & (REM_NETDUMP|REM_MCLXCD|REM_LKCD|REM_S390D)) +#define REMOTE_MEMSRC() (REMOTE_ACTIVE() || REMOTE_DUMPFILE()) +#define LKCD_DUMPFILE() (pc->flags & (LKCD|REM_LKCD)) +#define NETDUMP_DUMPFILE() (pc->flags & (NETDUMP|REM_NETDUMP)) +#define DISKDUMP_DUMPFILE() (pc->flags & DISKDUMP) +#define KDUMP_DUMPFILE() (pc->flags & KDUMP) +#define XENDUMP_DUMPFILE() (pc->flags & XENDUMP) +#define XEN_HYPER_MODE() (pc->flags & XEN_HYPER) +#define SYSRQ_TASK(X) ((pc->flags & SYSRQ) && is_task_active(X)) +#define XEN_CORE_DUMPFILE() (pc->flags & XEN_CORE) + +#define NETDUMP_LOCAL (0x1) /* netdump_data flags */ +#define NETDUMP_REMOTE (0x2) +#define VMCORE_VALID() (nd->flags & (NETDUMP_LOCAL|NETDUMP_REMOTE|KDUMP_LOCAL)) +#define NETDUMP_ELF32 (0x4) +#define NETDUMP_ELF64 (0x8) +#define PARTIAL_DUMP (0x10) /* netdump or diskdump */ +#define KDUMP_ELF32 (0x20) +#define KDUMP_ELF64 (0x40) +#define KDUMP_LOCAL (0x80) + +#define DUMPFILE_FORMAT(flags) ((flags) & \ + (NETDUMP_ELF32|NETDUMP_ELF64|KDUMP_ELF32|KDUMP_ELF64)) + +#define DISKDUMP_LOCAL (0x1) +#define KDUMP_CMPRS_LOCAL (0x2) +#define ERROR_EXCLUDED (0x4) +#define ZERO_EXCLUDED (0x8) +#define DISKDUMP_VALID() (dd->flags & DISKDUMP_LOCAL) +#define KDUMP_CMPRS_VALID() (dd->flags & KDUMP_CMPRS_LOCAL) + +#define XENDUMP_LOCAL (0x1) +#define XENDUMP_VALID() (xd->flags & XENDUMP_LOCAL) + +#define CRASHDEBUG(x) (pc->debug >= (x)) + +#define CRASHDEBUG_SUSPEND(X) { pc->debug_save = pc->debug; pc->debug = X; } +#define CRASHDEBUG_RESTORE() { pc->debug = pc->debug_save; } + +#define VERBOSE (0x1) +#define ADDRESS_SPECIFIED (0x2) + +#define FAULT_ON_ERROR (0x1) +#define RETURN_ON_ERROR (0x2) +#define QUIET (0x4) +#define HEX_BIAS (0x8) +#define LONG_LONG (0x10) + +#define SEEK_ERROR (-1) +#define READ_ERROR (-2) +#define WRITE_ERROR (-3) +#define PAGE_EXCLUDED (-4) + +#define RESTART() (longjmp(pc->main_loop_env, 1)) +#define RESUME_FOREACH() (longjmp(pc->foreach_loop_env, 1)) + +#define INFO (1) +#define FATAL (2) +#define FATAL_RESTART (3) +#define WARNING (4) +#define NOTE (5) +#define FATAL_ERROR(x) (((x) == FATAL) || ((x) == FATAL_RESTART)) + +#define CONSOLE_OFF(x) ((x) = console_off()) +#define CONSOLE_ON(x) (console_on(x)) + +#define RADIX(X) (X) + +#define NUM_HEX (0x1) +#define NUM_DEC (0x2) +#define NUM_EXPR (0x4) +#define NUM_ANY (NUM_HEX|NUM_DEC|NUM_EXPR) + +/* + * program context redirect flags + */ +#define FROM_COMMAND_LINE (0x1) +#define FROM_INPUT_FILE (0x2) +#define REDIRECT_NOT_DONE (0x4) +#define REDIRECT_TO_PIPE (0x8) +#define REDIRECT_TO_STDPIPE (0x10) +#define REDIRECT_TO_FILE (0x20) +#define REDIRECT_FAILURE (0x40) +#define REDIRECT_SHELL_ESCAPE (0x80) +#define REDIRECT_SHELL_COMMAND (0x100) +#define REDIRECT_PID_KNOWN (0x200) +#define REDIRECT_MULTI_PIPE (0x400) + +#define PIPE_OPTIONS (FROM_COMMAND_LINE | FROM_INPUT_FILE | REDIRECT_TO_PIPE | \ + REDIRECT_TO_STDPIPE | REDIRECT_TO_FILE) + +#define DEFAULT_REDHAT_DEBUG_LOCATION "/usr/lib/debug/lib/modules" + +#define MEMORY_DRIVER_MODULE "crash" +#define MEMORY_DRIVER_DEVICE "/dev/crash" +#define MEMORY_DRIVER_DEVICE_MODE (S_IFCHR|S_IRUSR) + +/* + * structure definitions + */ +struct program_context { + char *program_name; /* this program's name */ + char *program_path; /* unadulterated argv[0] */ + char *program_version; /* this program's version */ + char *gdb_version; /* embedded gdb version */ + char *prompt; /* this program's prompt */ + unsigned long long flags; /* flags from above */ + char *namelist; /* linux namelist */ + char *dumpfile; /* dumpfile or /dev/kmem */ + char *live_memsrc; /* live memory driver */ + char *system_map; /* get symbol values from System.map */ + char *namelist_debug; /* namelist containing debug data */ + char *debuginfo_file; /* separate debuginfo file */ + char *memory_module; /* alternative to mem.c driver */ + char *memory_device; /* alternative to /dev/[k]mem device */ + char *machine_type; /* machine's processor type */ + char *editing_mode; /* readline vi or emacs */ + char *server; /* network daemon */ + char *server_memsrc; /* memory source on server */ + char *server_namelist; /* kernel namelist on server */ + int nfd; /* linux namelist fd */ + int mfd; /* /dev/mem fd */ + int kfd; /* /dev/kmem fd */ + int dfd; /* dumpfile fd */ + int confd; /* console fd */ + int sockfd; /* network daemon socket */ + ushort port; /* network daemon port */ + int rmfd; /* remote server memory source fd */ + int rkfd; /* remote server /dev/kmem fd */ + ulong program_pid; /* program pid */ + ulong server_pid; /* server pid */ + ulong rcvbufsize; /* client-side receive buffer size */ + char *home; /* user's home directory */ + char command_line[BUFSIZE]; /* possibly parsed input command line */ + char orig_line[BUFSIZE]; /* original input line */ + char *readline; /* pointer to last readline() return */ + char my_tty[10]; /* real tty name (shown by ps -ef) */ + ulong debug; /* level of debug */ + ulong debug_save; /* saved level for debug-suspend */ + char *console; /* current debug console device */ + char *redhat_debug_loc; /* location of matching debug objects */ + int pipefd[2]; /* output pipe file descriptors */ + FILE *nullfp; /* bitbucket */ + FILE *stdpipe; /* standard pipe for output */ + FILE *pipe; /* command line specified pipe */ + FILE *ofile; /* command line specified output file */ + FILE *ifile; /* command line specified input file */ + FILE *ifile_pipe; /* output pipe specified from file */ + FILE *ifile_ofile; /* output file specified from file */ + FILE *symfile; /* symbol table data file */ + FILE *symfile2; /* alternate access to above */ + FILE *tmpfile; /* tmpfile for selective data output */ + FILE *saved_fp; /* for printing while parsing tmpfile */ + FILE *tmp_fp; /* stored tmpfile pointer */ + char *input_file; /* input file specified at invocation */ + FILE *tmpfile2; /* tmpfile2 does not use save_fp! */ + int eoc_index; /* end of redirected command index */ + int scroll_command; /* default scroll command for output */ +#define SCROLL_NONE 0 +#define SCROLL_LESS 1 +#define SCROLL_MORE 2 + ulong redirect; /* per-cmd origin and output flags */ + pid_t stdpipe_pid; /* per-cmd standard output pipe's pid */ + pid_t pipe_pid; /* per-cmd output pipe's pid */ + pid_t pipe_shell_pid; /* per-cmd output pipe's shell pid */ + char pipe_command[BUFSIZE]; /* pipe command line */ + struct command_table_entry *cmd_table; /* linux/xen command table */ + char *curcmd; /* currently-executing command */ + char *lastcmd; /* previously-executed command */ + ulong cmdgencur; /* current command generation number */ + ulong curcmd_flags; /* general purpose per-command flag */ +#define XEN_MACHINE_ADDR (0x1) +#define REPEAT (0x2) +#define IDLE_TASK_SHOWN (0x4) +#define TASK_SPECIFIED (0x8) +#define MEMTYPE_UVADDR (0x10) +#define MEMTYPE_FILEADDR (0x20) +#define HEADER_PRINTED (0x40) +#define BAD_INSTRUCTION (0x80) +#define UD2A_INSTRUCTION (0x100) + ulonglong curcmd_private; /* general purpose per-command info */ + int cur_gdb_cmd; /* current gdb command */ + int last_gdb_cmd; /* previously-executed gdb command */ + int sigint_cnt; /* number of ignored SIGINTs */ + struct gnu_request *cur_req; /* current gdb gnu_request */ + struct sigaction sigaction; /* general usage sigaction. */ + struct sigaction gdb_sigaction; /* gdb's SIGINT sigaction. */ + jmp_buf main_loop_env; /* longjmp target default */ + jmp_buf foreach_loop_env; /* longjmp target within foreach */ + jmp_buf gdb_interface_env; /* longjmp target for gdb error catch */ + struct termios termios_orig; /* non-raw settings */ + struct termios termios_raw; /* while gathering command input */ + int ncmds; /* number of commands in menu */ + char **cmdlist; /* current list of available commands */ + int cmdlistsz; /* space available in cmdlist */ + unsigned output_radix; /* current gdb output_radix */ + void *sbrk; /* current sbrk value */ + struct extension_table *curext; /* extension being loaded */ + int (*readmem)(int, void *, int, ulong, physaddr_t); /* memory access */ + int (*writemem)(int, void *, int, ulong, physaddr_t);/* memory access */ +}; + +#define READMEM pc->readmem + +typedef void (*cmd_func_t)(void); + +struct command_table_entry { /* one for each command in menu */ + char *name; + cmd_func_t func; + char **help_data; + ulong flags; +}; + +#define REFRESH_TASK_TABLE (0x1) /* command_table_entry flags */ +#define HIDDEN_COMMAND (0x2) +#define CLEANUP (0x4) /* for extensions only */ + +/* + * A linked list of extension table structures keeps track of the current + * set of shared library extensions. + */ +struct extension_table { + void *handle; /* handle from dlopen() */ + char *filename; /* name of shared library */ + struct command_table_entry *command_table; /* list of commands */ + ulong flags; /* registration flags */ + struct extension_table *next, *prev; /* bookkeeping */ +}; + +#define REGISTERED (0x1) /* extension_table flags */ +#define DUPLICATE_COMMAND_NAME (0x2) + +struct new_utsname { + char sysname[65]; + char nodename[65]; + char release[65]; + char version[65]; + char machine[65]; + char domainname[65]; +}; + +#define NO_MODULE_ACCESS (0x1) +#define TVEC_BASES_V1 (0x2) +#define GCC_3_2 (0x4) +#define GCC_3_2_3 (0x8) +#define GCC_2_96 (0x10) +#define RA_SEEK (0x20) +#define NO_RA_SEEK (0x40) +#define KALLSYMS_V1 (0x80) +#define NO_KALLSYMS (0x100) +#define PER_CPU_OFF (0x200) +#define SMP (0x400) +#define GCC_3_3_2 (0x800) +#define KMOD_V1 (0x1000) +#define KMOD_V2 (0x2000) +#define KALLSYMS_V2 (0x2000) +#define TVEC_BASES_V2 (0x4000) +#define GCC_3_3_3 (0x8000) +#define USE_OLD_BT (0x10000) +#define ARCH_XEN (0x20000) +#define NO_IKCONFIG (0x40000) +#define DWARF_UNWIND (0x80000) +#define NO_DWARF_UNWIND (0x100000) +#define DWARF_UNWIND_MEMORY (0x200000) +#define DWARF_UNWIND_EH_FRAME (0x400000) +#define DWARF_UNWIND_CAPABLE (DWARF_UNWIND_MEMORY|DWARF_UNWIND_EH_FRAME) +#define DWARF_UNWIND_MODULES (0x800000) +#define BUGVERBOSE_OFF (0x1000000) + +#define GCC_VERSION_DEPRECATED (GCC_3_2|GCC_3_2_3|GCC_2_96|GCC_3_3_2|GCC_3_3_3) + +#define XEN() (kt->flags & ARCH_XEN) + +#define XEN_MACHINE_TO_MFN(m) ((ulonglong)(m) >> PAGESHIFT()) +#define XEN_PFN_TO_PSEUDO(p) ((ulonglong)(p) << PAGESHIFT()) + +#define XEN_MFN_NOT_FOUND (~0UL) +#define XEN_PFNS_PER_PAGE (PAGESIZE()/sizeof(ulong)) +#define XEN_FOREIGN_FRAME (1UL << (BITS()-1)) + +#define XEN_MACHADDR_NOT_FOUND (~0ULL) + +struct kernel_table { /* kernel data */ + ulong flags; + ulong stext; + ulong etext; + ulong stext_init; + ulong etext_init; + ulong init_begin; + ulong init_end; + ulong end; + int cpus; + char *cpus_override; + void (*display_bh)(void); + ulong module_list; + ulong kernel_module; + int mods_installed; + struct timespec date; + char proc_version[BUFSIZE]; + struct new_utsname utsname; + uint kernel_version[3]; + uint gcc_version[3]; + int runq_siblings; + int kernel_NR_CPUS; + long __rq_idx[NR_CPUS]; + long __cpu_idx[NR_CPUS]; + long __per_cpu_offset[NR_CPUS]; + ulong cpu_flags[NR_CPUS]; + int BUG_bytes; +#define NMI 0x1 + ulong xen_flags; +#define WRITABLE_PAGE_TABLES (0x1) +#define SHADOW_PAGE_TABLES (0x2) +#define CANONICAL_PAGE_TABLES (0x4) +#define XEN_SUSPEND (0x8) + char *m2p_page; + ulong phys_to_machine_mapping; + ulong p2m_table_size; +#define P2M_MAPPING_CACHE (512) + struct p2m_mapping_cache { + ulong mapping; + ulong start; + ulong end; + } p2m_m... [truncated message content] |