--- crash-4.0-8.9/main.c 2009-05-29 16:41:10.000000000 -0400 +++ crash-4.0-8.10/main.c 2009-05-12 13:54:10.000000000 -0400 @@ -1,8 +1,8 @@ /* main.c - core analysis suite * * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc. - * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 David Anderson - * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 Red Hat, Inc. All rights reserved. + * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 David Anderson + * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Red Hat, Inc. All rights reserved. * * 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 @@ -59,6 +59,7 @@ {"reloc", required_argument, 0, 0}, {"active", 0, 0, 0}, {"minimal", 0, 0, 0}, + {"mod", required_argument, 0, 0}, {0, 0, 0, 0} }; @@ -203,6 +204,9 @@ else if (STREQ(long_options[option_index].name, "active")) tt->flags |= ACTIVE_ONLY; + else if (STREQ(long_options[option_index].name, "mod")) + kt->module_tree = optarg; + else if (STREQ(long_options[option_index].name, "reloc")) { if (!calculate(optarg, &kt->relocate, NULL, 0)) { error(INFO, "invalid --reloc argument: %s\n", @@ -1309,6 +1313,8 @@ fprintf(fp, "%sUD2A_INSTRUCTION", others ? "|" : ""); if (pc->curcmd_flags & IRQ_IN_USE) fprintf(fp, "%sIRQ_IN_USE", others ? "|" : ""); + if (pc->curcmd_flags & MODULE_TREE) + fprintf(fp, "%sMODULE_TREE", others ? "|" : ""); fprintf(fp, ")\n"); fprintf(fp, " curcmd_private: %llx\n", pc->curcmd_private); fprintf(fp, " sigint_cnt: %d\n", pc->sigint_cnt); --- crash-4.0-8.9/filesys.c 2009-05-29 16:41:11.000000000 -0400 +++ crash-4.0-8.10/filesys.c 2009-05-08 16:23:32.000000000 -0400 @@ -933,7 +933,7 @@ * When time permits, rewrite this doing the search by hand. */ char * -search_directory_tree(char *directory, char *file) +search_directory_tree(char *directory, char *file, int follow_links) { char command[BUFSIZE]; char buf[BUFSIZE]; @@ -949,8 +949,8 @@ return NULL; sprintf(command, - "/usr/bin/find %s -name %s -print; /bin/echo search done", - directory, file); + "/usr/bin/find %s %s -name %s -print; /bin/echo search done", + follow_links ? "-L" : "", directory, file); if ((pipe = popen(command, "r")) == NULL) { error(INFO, "%s: %s\n", command, strerror(errno)); --- crash-4.0-8.9/task.c 2009-05-29 16:41:11.000000000 -0400 +++ crash-4.0-8.10/task.c 2009-05-29 10:06:50.000000000 -0400 @@ -1873,6 +1873,8 @@ */ cnt = 0; for (i = 0; i < kt->cpus; i++) { + if (!tt->idle_threads[i]) + continue; if (hq_enter(tt->idle_threads[i])) cnt++; else --- crash-4.0-8.9/kernel.c 2009-05-29 16:41:11.000000000 -0400 +++ crash-4.0-8.10/kernel.c 2009-04-30 14:22:56.000000000 -0400 @@ -533,6 +533,62 @@ } /* + * Get cpu map address. Types are: possible, online, present and active. + * They exist as either: + * + * (1) cpu__map symbols, or + * (2) what is pointed to by cpu__mask + */ +ulong +cpu_map_addr(const char *type) +{ + char map_symbol[32]; + ulong addr; + + sprintf(map_symbol, "cpu_%s_map", type); + if (kernel_symbol_exists(map_symbol)) + return symbol_value(map_symbol); + + sprintf(map_symbol, "cpu_%s_mask", type); + if (kernel_symbol_exists(map_symbol)) { + get_symbol_data(map_symbol, sizeof(ulong), &addr); + return addr; + } + + return 0; +} + +/* + * Get cpu map (possible, online, etc.) size + */ +static int +cpu_map_size(const char *type) +{ + int len; + char map_symbol[32]; + struct gnu_request req; + + if (LKCD_KERNTYPES()) { + if ((len = STRUCT_SIZE("cpumask_t")) < 0) + error(FATAL, "cannot determine type cpumask_t\n"); + return len; + } + + sprintf(map_symbol, "cpu_%s_map", type); + if (kernel_symbol_exists(map_symbol)) { + len = get_symbol_type(map_symbol, NULL, &req) == + TYPE_CODE_UNDEF ? sizeof(ulong) : req.length; + return len; + } + + len = STRUCT_SIZE("cpumask_t"); + if (len < 0) + return sizeof(ulong); + else + return len; +} + +/* * If the cpu_present_map, cpu_online_map and cpu_possible_maps exist, * set up the kt->cpu_flags[NR_CPUS] with their settings. */ @@ -541,14 +597,14 @@ { int i, c, m, cpu, len; char *buf; - ulong *maskptr; + ulong *maskptr, addr; struct mapinfo { ulong cpu_flag; char *name; } mapinfo[] = { - { POSSIBLE, "cpu_possible_map" }, - { PRESENT, "cpu_present_map" }, - { ONLINE, "cpu_online_map" }, + { POSSIBLE, "possible" }, + { PRESENT, "present" }, + { ONLINE, "online" }, }; if ((len = STRUCT_SIZE("cpumask_t")) < 0) @@ -557,12 +613,13 @@ buf = GETBUF(len); for (m = 0; m < sizeof(mapinfo)/sizeof(struct mapinfo); m++) { - if (!kernel_symbol_exists(mapinfo[m].name)) + if (!(addr = cpu_map_addr(mapinfo[m].name))) continue; - if (!readmem(symbol_value(mapinfo[m].name), KVADDR, buf, len, + if (!readmem(addr, KVADDR, buf, len, mapinfo[m].name, RETURN_ON_ERROR)) { - error(WARNING, "cannot read %s\n", mapinfo[m].name); + error(WARNING, "cannot read cpu_%s_map\n", + mapinfo[m].name); continue; } @@ -578,7 +635,7 @@ } if (CRASHDEBUG(1)) { - fprintf(fp, "%s: ", mapinfo[m].name); + fprintf(fp, "cpu_%s_map: ", mapinfo[m].name); for (i = 0; i < NR_CPUS; i++) { if (kt->cpu_flags[i] & mapinfo[m].cpu_flag) fprintf(fp, "%d ", i); @@ -605,21 +662,21 @@ switch (map) { case POSSIBLE: - if (!kernel_symbol_exists("cpu_possible_map")) { + if (!cpu_map_addr("possible")) { error(INFO, "cpu_possible_map does not exist\n"); return FALSE; } return (kt->cpu_flags[cpu] & POSSIBLE); case PRESENT: - if (!kernel_symbol_exists("cpu_present_map")) { + if (!cpu_map_addr("present")) { error(INFO, "cpu_present_map does not exist\n"); return FALSE; } return (kt->cpu_flags[cpu] & PRESENT); case ONLINE: - if (!kernel_symbol_exists("cpu_online_map")) { + if (!cpu_map_addr("online")) { error(INFO, "cpu_online_map does not exist\n"); return FALSE; } @@ -2799,7 +2856,7 @@ cmd_mod(void) { int c; - char *objfile, *modref, *tree; + char *objfile, *modref, *tree, *symlink; ulong flag, address; char buf[BUFSIZE]; @@ -2817,11 +2874,11 @@ return; } - modref = objfile = tree = NULL; + modref = objfile = tree = symlink = NULL; address = 0; flag = LIST_MODULE_HDR; - while ((c = getopt(argcnt, args, "rd:Ds:St:o")) != EOF) { + while ((c = getopt(argcnt, args, "rd:Ds:So")) != EOF) { switch(c) { case 'r': @@ -2867,15 +2924,6 @@ st->flags |= USE_OLD_ADD_SYM; return; - case 't': - if (is_directory(optarg)) - tree = optarg; - else { - error(INFO, "%s is not a directory\n", args[2]); - cmd_usage(pc->curcmd, SYNOPSIS); - } - break; - case 'S': if (flag) cmd_usage(pc->curcmd, SYNOPSIS); @@ -2979,8 +3027,50 @@ break; } + if ((flag == LOAD_ALL_MODULE_SYMBOLS) && + (tree || kt->module_tree)) { + if (!tree) + tree = kt->module_tree; + + pc->curcmd_flags |= MODULE_TREE; + } + do_module_cmd(flag, modref, address, objfile, tree); + if (symlink) + FREEBUF(symlink); +} + +int +check_specified_module_tree(char *module, char *gdb_buffer) +{ + char *p1, *treebuf; + int retval; + + retval = FALSE; + + if (!(pc->curcmd_flags & MODULE_TREE)) + return retval; + /* + * Search for "/lib/modules" in the module name string + * and insert "/usr/lib/debug" there. + */ + if (strstr(module, "/lib/modules")) { + treebuf = GETBUF(strlen(module) + strlen("/usr/lib/debug") + + strlen(".debug") + 1); + strcpy(treebuf, module); + p1 = strstr(treebuf, "/lib/modules"); + shift_string_right(p1, strlen("/usr/lib/debug")); + BCOPY("/usr/lib/debug", p1, strlen("/usr/lib/debug")); + strcat(treebuf, ".debug"); + if (file_exists(treebuf, NULL)) { + strcpy(gdb_buffer, treebuf); + retval = TRUE; + } + FREEBUF(treebuf); + } + + return retval; } @@ -3290,12 +3380,12 @@ } if (tree) { - if (!(retbuf = search_directory_tree(tree, file))) { + if (!(retbuf = search_directory_tree(tree, file, 1))) { switch (kt->flags & (KMOD_V1|KMOD_V2)) { case KMOD_V2: sprintf(file, "%s.ko", modref); - retbuf = search_directory_tree(tree, file); + retbuf = search_directory_tree(tree, file, 1); } } return retbuf; @@ -3303,28 +3393,28 @@ sprintf(dir, "%s/%s", DEFAULT_REDHAT_DEBUG_LOCATION, kt->utsname.release); - retbuf = search_directory_tree(dir, file); + retbuf = search_directory_tree(dir, file, 0); if (!retbuf) { sprintf(dir, "/lib/modules/%s/updates", kt->utsname.release); - if (!(retbuf = search_directory_tree(dir, file))) { + if (!(retbuf = search_directory_tree(dir, file, 0))) { switch (kt->flags & (KMOD_V1|KMOD_V2)) { case KMOD_V2: sprintf(file, "%s.ko", modref); - retbuf = search_directory_tree(dir, file); + retbuf = search_directory_tree(dir, file, 0); } } } if (!retbuf) { sprintf(dir, "/lib/modules/%s", kt->utsname.release); - if (!(retbuf = search_directory_tree(dir, file))) { + if (!(retbuf = search_directory_tree(dir, file, 0))) { switch (kt->flags & (KMOD_V1|KMOD_V2)) { case KMOD_V2: sprintf(file, "%s.ko", modref); - retbuf = search_directory_tree(dir, file); + retbuf = search_directory_tree(dir, file, 0); } } } @@ -4101,6 +4191,8 @@ fprintf(fp, " module_list: %lx\n", kt->module_list); fprintf(fp, " kernel_module: %lx\n", kt->kernel_module); fprintf(fp, "mods_installed: %d\n", kt->mods_installed); + fprintf(fp, " module_tree: %s\n", kt->module_tree ? + kt->module_tree : "(not used)"); if (!(pc->flags & KERNEL_DEBUG_QUERY) && ACTIVE()) get_symbol_data("xtime", sizeof(struct timespec), &kt->date); fprintf(fp, " date: %s\n", @@ -4187,7 +4279,7 @@ } fprintf(fp, "\n"); fprintf(fp, " cpu_possible_map: "); - if (kernel_symbol_exists("cpu_possible_map")) { + if (cpu_map_addr("possible")) { for (i = 0; i < nr_cpus; i++) { if (kt->cpu_flags[i] & POSSIBLE) fprintf(fp, "%d ", i); @@ -4196,7 +4288,7 @@ } else fprintf(fp, "(does not exist)\n"); fprintf(fp, " cpu_present_map: "); - if (kernel_symbol_exists("cpu_present_map")) { + if (cpu_map_addr("present")) { for (i = 0; i < nr_cpus; i++) { if (kt->cpu_flags[i] & PRESENT) fprintf(fp, "%d ", i); @@ -4205,7 +4297,7 @@ } else fprintf(fp, "(does not exist)\n"); fprintf(fp, " cpu_online_map: "); - if (kernel_symbol_exists("cpu_online_map")) { + if (cpu_map_addr("online")) { for (i = 0; i < nr_cpus; i++) { if (kt->cpu_flags[i] & ONLINE) fprintf(fp, "%d ", i); @@ -5923,35 +6015,30 @@ get_cpus_online() { int i, len, online; - struct gnu_request req; char *buf; - ulong *maskptr; + ulong *maskptr, addr; - if (!symbol_exists("cpu_online_map")) + if (!(addr = cpu_map_addr("online"))) return 0; - if (LKCD_KERNTYPES()) { - if ((len = STRUCT_SIZE("cpumask_t")) < 0) - error(FATAL, "cannot determine type cpumask_t\n"); - } else - len = get_symbol_type("cpu_online_map", NULL, &req) == - TYPE_CODE_UNDEF ? sizeof(ulong) : req.length; + len = cpu_map_size("online"); buf = GETBUF(len); online = 0; - if (readmem(symbol_value("cpu_online_map"), KVADDR, buf, len, - "cpu_online_map", RETURN_ON_ERROR)) { + if (readmem(addr, KVADDR, buf, len, + "cpu_online_map", RETURN_ON_ERROR)) { maskptr = (ulong *)buf; for (i = 0; i < (len/sizeof(ulong)); i++, maskptr++) online += count_bits_long(*maskptr); - FREEBUF(buf); if (CRASHDEBUG(1)) error(INFO, "get_cpus_online: online: %d\n", online); } + FREEBUF(buf); + return online; } @@ -5962,35 +6049,30 @@ get_cpus_present() { int i, len, present; - struct gnu_request req; char *buf; - ulong *maskptr; + ulong *maskptr, addr; - if (!symbol_exists("cpu_present_map")) + if (!(addr = cpu_map_addr("present"))) return 0; - if (LKCD_KERNTYPES()) { - if ((len = STRUCT_SIZE("cpumask_t")) < 0) - error(FATAL, "cannot determine type cpumask_t\n"); - } else - len = get_symbol_type("cpu_present_map", NULL, &req) == - TYPE_CODE_UNDEF ? sizeof(ulong) : req.length; + len = cpu_map_size("present"); buf = GETBUF(len); present = 0; - if (readmem(symbol_value("cpu_present_map"), KVADDR, buf, len, - "cpu_present_map", RETURN_ON_ERROR)) { + if (readmem(addr, KVADDR, buf, len, + "cpu_present_map", RETURN_ON_ERROR)) { maskptr = (ulong *)buf; for (i = 0; i < (len/sizeof(ulong)); i++, maskptr++) present += count_bits_long(*maskptr); - FREEBUF(buf); if (CRASHDEBUG(1)) error(INFO, "get_cpus_present: present: %d\n", present); } + FREEBUF(buf); + return present; } @@ -6001,36 +6083,31 @@ get_cpus_possible() { int i, len, possible; - struct gnu_request req; char *buf; - ulong *maskptr; + ulong *maskptr, addr; - if (!symbol_exists("cpu_possible_map")) + if (!(addr = cpu_map_addr("possible"))) return 0; - if (LKCD_KERNTYPES()) { - if ((len = STRUCT_SIZE("cpumask_t")) < 0) - error(FATAL, "cannot determine type cpumask_t\n"); - } else - len = get_symbol_type("cpu_possible_map", NULL, &req) == - TYPE_CODE_UNDEF ? sizeof(ulong) : req.length; + len = cpu_map_size("possible"); buf = GETBUF(len); possible = 0; - if (readmem(symbol_value("cpu_possible_map"), KVADDR, buf, len, + if (readmem(addr, KVADDR, buf, len, "cpu_possible_map", RETURN_ON_ERROR)) { maskptr = (ulong *)buf; for (i = 0; i < (len/sizeof(ulong)); i++, maskptr++) possible += count_bits_long(*maskptr); - FREEBUF(buf); if (CRASHDEBUG(1)) error(INFO, "get_cpus_possible: possible: %d\n", possible); } + FREEBUF(buf); + return possible; } --- crash-4.0-8.9/configure.c 2009-05-29 16:41:11.000000000 -0400 +++ crash-4.0-8.10/configure.c 2009-05-21 16:55:48.000000000 -0400 @@ -1198,6 +1198,7 @@ printf("The following extensions are provided:\n"); printf("* sial: Provides C-like language for writing dump analysis scripts\n"); printf("* dminfo: Device-mapper target analyzer\n"); + printf("* snap: Takes a snapshot of live memory and creates a kdump dumpfile\n"); printf("\n"); printf("%%prep\n"); printf("%%setup -n %%{name}-%%{version}-%%{release}\n"); @@ -1219,6 +1220,7 @@ printf("mkdir -p %%{buildroot}%%{_libdir}/crash/extensions\n"); printf("cp extensions/sial.so %%{buildroot}%%{_libdir}/crash/extensions\n"); printf("cp extensions/dminfo.so %%{buildroot}%%{_libdir}/crash/extensions\n"); + printf("cp extensions/snap.so %%{buildroot}%%{_libdir}/crash/extensions\n"); printf("\n"); printf("%%clean\n"); printf("rm -rf %%{buildroot}\n"); --- crash-4.0-8.9/s390.c 2009-05-29 16:41:11.000000000 -0400 +++ crash-4.0-8.10/s390.c 2009-04-30 14:16:29.000000000 -0400 @@ -999,16 +999,7 @@ int s390_get_smp_cpus(void) { - unsigned long map = 0, addr; - int i, cpu_num = 0; - addr=symbol_value("cpu_online_map"); - readmem(addr, KVADDR, &map,sizeof(long), "cpu_online_map",FAULT_ON_ERROR); - for(i = 0; i < sizeof(map)*8;i++){ - if(map & 0x1UL) - cpu_num += 1; - map >>= 1; - } - return cpu_num; + return get_cpus_online(); } /* --- crash-4.0-8.9/s390x.c 2009-05-29 16:41:11.000000000 -0400 +++ crash-4.0-8.10/s390x.c 2009-04-30 14:16:53.000000000 -0400 @@ -1029,16 +1029,7 @@ int s390x_get_smp_cpus(void) { - unsigned long map = 0, addr; - int i, cpu_num = 0; - addr=symbol_value("cpu_online_map"); - readmem(addr, KVADDR, &map,sizeof(long), "cpu_online_map",FAULT_ON_ERROR); - for(i = 0; i < sizeof(map)*8;i++){ - if(map & 0x1UL) - cpu_num += 1; - map >>= 1; - } - return cpu_num; + return get_cpus_online(); } /* --- crash-4.0-8.9/ppc64.c 2009-05-29 16:41:11.000000000 -0400 +++ crash-4.0-8.10/ppc64.c 2009-05-18 16:09:09.000000000 -0400 @@ -1578,7 +1578,7 @@ unsigned long unip; pt_regs = (struct ppc64_pt_regs *)bt_in->machdep; - if (!pt_regs->gpr[1]) { + if (!pt_regs || !pt_regs->gpr[1]) { /* * Not collected regs. May be the corresponding CPU not * responded to an IPI. @@ -2407,9 +2407,9 @@ if (!symbol_exists("paca")) error(FATAL, "PPC64: Could not find 'paca' symbol\n"); - if (symbol_exists("cpu_present_map")) + if (cpu_map_addr("present")) map = PRESENT; - else if (symbol_exists("cpu_online_map")) + else if (cpu_map_addr("online")) map = ONLINE; else error(FATAL, --- crash-4.0-8.9/x86_64.c 2009-05-29 16:41:10.000000000 -0400 +++ crash-4.0-8.10/x86_64.c 2009-05-29 16:09:19.000000000 -0400 @@ -71,6 +71,7 @@ void x86_64_compiler_warning_stub(void); static void x86_64_init_kernel_pgd(void); static void x86_64_cpu_pda_init(void); +static void x86_64_per_cpu_init(void); static void x86_64_ist_init(void); static void x86_64_post_init(void); static void parse_cmdline_args(void); @@ -292,7 +293,10 @@ MEMBER_OFFSET_INIT(user_regs_struct_ss, "user_regs_struct", "ss"); STRUCT_SIZE_INIT(user_regs_struct, "user_regs_struct"); - x86_64_cpu_pda_init(); + if (STRUCT_EXISTS("x8664_pda")) + x86_64_cpu_pda_init(); + else + x86_64_per_cpu_init(); x86_64_ist_init(); if ((machdep->machspec->irqstack = (char *) malloc(machdep->machspec->stkinfo.isize)) == NULL) @@ -700,6 +704,52 @@ FREEBUF(cpu_pda_buf); } +static void +x86_64_per_cpu_init(void) +{ + int i, cpus, cpunumber; + + if (!(kt->flags & PER_CPU_OFF)) + return; + + if (!symbol_exists("per_cpu__cpu_number") || + !symbol_exists("per_cpu__irq_stack_union")) + return; + + for (i = cpus = 0; i < NR_CPUS; i++) { + readmem(symbol_value("per_cpu__cpu_number") + + kt->__per_cpu_offset[i], + KVADDR, &cpunumber, sizeof(int), + "cpu number (per_cpu)", FAULT_ON_ERROR); + + if (cpunumber != cpus) + break; + cpus++; + + machdep->machspec->stkinfo.ibase[i] = + symbol_value("per_cpu__irq_stack_union") + + kt->__per_cpu_offset[i]; + } + + if ((machdep->machspec->stkinfo.isize = + MEMBER_SIZE("irq_stack_union", "irq_stack")) <= 0) + machdep->machspec->stkinfo.isize = 16384; + + if (CRASHDEBUG(2)) + fprintf(fp, "x86_64_per_cpu_init: " + "setup_percpu areas: %d\n", cpus); + + if (cpus > 1) + kt->flags |= SMP; + + if ((i = get_cpus_online()) && (i < cpus)) + kt->cpus = i; + else + kt->cpus = cpus; + + verify_spinlock(); +} + /* * Gather the ist addresses for each CPU. */ @@ -777,7 +827,7 @@ */ sp = value_search(ms->stkinfo.ebase[0][0], &offset); if (!sp || offset || !STREQ(sp->name, "boot_exception_stacks")) { - if (symbol_value("boot_exception_stacks")) { + if (symbol_exists("boot_exception_stacks")) { error(WARNING, "cpu 0 first exception stack: %lx\n boot_exception_stacks: %lx\n\n", ms->stkinfo.ebase[0][0], @@ -785,7 +835,7 @@ if (!ms->stkinfo.ebase[0][0]) ms->stkinfo.ebase[0][0] = symbol_value("boot_exception_stacks"); - } else + } else if (STRUCT_EXISTS("x8664_pda")) error(WARNING, "boot_exception_stacks: symbol does not exist in this kernel!\n"); } @@ -1727,11 +1777,27 @@ static int x86_64_verify_symbol(const char *name, ulong value, char type) { - if (STREQ(name, "_text") || STREQ(name, "_stext")) - machdep->flags |= KSYMS_START; + if (!name || !strlen(name)) + return FALSE; + + if (!(machdep->flags & KSYMS_START)) { + if (STREQ(name, "_text") || STREQ(name, "_stext")) { + machdep->flags |= KSYMS_START; + if (!st->first_ksymbol) + st->first_ksymbol = value; + return TRUE; + } else if (STREQ(name, "__per_cpu_start")) { + st->flags |= PERCPU_SYMS; + return TRUE; + } else if (st->flags & PERCPU_SYMS) { + if (STRNEQ(name, "per_cpu") || + STREQ(name, "__per_cpu_end")) + return TRUE; + } + + return FALSE; + } - if (!name || !strlen(name) || !(machdep->flags & KSYMS_START)) - return FALSE; return TRUE; } @@ -3972,8 +4038,26 @@ char *cpu_pda_buf; ulong level4_pgt, cpu_pda_addr; - if (!VALID_STRUCT(x8664_pda)) - return 1; + if (!VALID_STRUCT(x8664_pda)) { + if (!(kt->flags & PER_CPU_OFF) || + !symbol_exists("per_cpu__cpu_number")) + return 1; + + for (i = cpus = 0; i < NR_CPUS; i++) { + readmem(symbol_value("per_cpu__cpu_number") + + kt->__per_cpu_offset[i], KVADDR, + &cpunumber, sizeof(int), + "cpu number (per_cpu)", FAULT_ON_ERROR); + if (cpunumber != cpus) + break; + cpus++; + } + + if ((i = get_cpus_online()) && (i < cpus)) + cpus = i; + + return cpus; + } cpu_pda_buf = GETBUF(SIZE(x8664_pda)); --- crash-4.0-8.9/extensions.c 2009-05-29 16:41:11.000000000 -0400 +++ crash-4.0-8.10/extensions.c 2009-05-19 15:02:23.000000000 -0400 @@ -316,6 +316,10 @@ if (file_exists(buf, NULL)) return TRUE; + sprintf(buf, "./extensions/%s", lib); + if (file_exists(buf, NULL)) + return TRUE; + return FALSE; } --- crash-4.0-8.9/symbols.c 2009-05-29 16:41:10.000000000 -0400 +++ crash-4.0-8.10/symbols.c 2009-05-29 15:09:23.000000000 -0400 @@ -428,11 +428,14 @@ } /* - * Callback for gdb to use a specified debug file. + * Callback for gdb to use a specified vmlinux.debug file. */ char * -check_specified_debug_file() +check_specified_kernel_debug_file() { + if (pc->flags & GDB_INIT) + return NULL; + return (pc->namelist_debug ? pc->namelist_debug : NULL); } @@ -2295,6 +2298,8 @@ fprintf(fp, "%sADD_SYMBOL_FILE", others++ ? "|" : ""); if (st->flags & USE_OLD_ADD_SYM) fprintf(fp, "%sUSE_OLD_ADD_SYM", others++ ? "|" : ""); + if (st->flags & PERCPU_SYMS) + fprintf(fp, "%sPERCPU_SYMS", others++ ? "|" : ""); fprintf(fp, ")\n"); fprintf(fp, " bfd: %lx\n", (ulong)st->bfd); @@ -2302,6 +2307,14 @@ fprintf(fp, " symend: %lx\n", (ulong)st->symend); fprintf(fp, " symcnt: %ld\n", st->symcnt); fprintf(fp, " syment_size: %ld\n", st->syment_size); + fprintf(fp, " first_ksymbol: "); + if (st->first_ksymbol) { + fprintf(fp, "%lx (%s)\n", + st->first_ksymbol, + st->flags & KERNEL_SYMS ? + value_symbol(st->first_ksymbol) : ""); + } else + fprintf(fp, "(unused)\n"); fprintf(fp, " symval_hash[%d]: %lx\n", SYMVAL_HASH, (ulong)&st->symval_hash[0]); @@ -3277,8 +3290,12 @@ in_ksymbol_range(ulong value) { if ((value >= st->symtable[0].value) && - (value <= st->symtable[st->symcnt-1].value)) - return TRUE; + (value <= st->symtable[st->symcnt-1].value)) { + if ((st->flags & PERCPU_SYMS) && (value < st->first_ksymbol)) + return FALSE; + else + return TRUE; + } if (module_symbol(value, NULL, NULL, NULL, output_radix)) return TRUE; --- crash-4.0-8.9/netdump.c 2009-05-29 16:41:11.000000000 -0400 +++ crash-4.0-8.10/netdump.c 2009-05-29 14:12:38.000000000 -0400 @@ -616,14 +616,15 @@ case KDUMP_ELF32: case KDUMP_ELF64: crashing_cpu = -1; - if (symbol_exists("crashing_cpu")) { + if (kernel_symbol_exists("crashing_cpu")) { get_symbol_data("crashing_cpu", sizeof(int), &i); if ((i >= 0) && (i < nd->num_prstatus_notes)) { crashing_cpu = i; if (CRASHDEBUG(1)) error(INFO, - "get_netdump_panic_task: crashing_cpu: %d\n", - crashing_cpu); + "get_netdump_panic_task: active_set[crashing_cpu: %d]: %lx\n", + crashing_cpu, + tt->active_set[crashing_cpu]); } } @@ -716,6 +717,11 @@ } } } + + if (nd->elf64->e_machine == EM_X86_64) { + if ((crashing_cpu != -1) && (crashing_cpu <= kt->cpus)) + return (tt->active_set[crashing_cpu]); + } } panic_task_undetermined: @@ -2488,3 +2494,151 @@ { return nd->xen_kdump_data->xen_minor_version; } + + +/* + * The following set of functions are not used by the crash + * source code, but are available to extension modules for + * gathering register sets from ELF NT_PRSTATUS note sections. + * + * Contributed by: Sharyathi Nagesh (sharyath@in.ibm.com) + */ + +static void *get_ppc64_regs_from_elf_notes(struct task_context *); +static void *get_x86_regs_from_elf_notes(struct task_context *); +static void *get_x86_64_regs_from_elf_notes(struct task_context *); + +int get_netdump_arch(void) +{ + int e_machine; + + if (nd->elf32) + e_machine = nd->elf32->e_machine; + else if (nd->elf64) + e_machine = nd->elf64->e_machine; + else + e_machine = EM_NONE; + + return e_machine; +} + +void * +get_regs_from_elf_notes(struct task_context *tc) +{ + switch(get_netdump_arch()) + { + case EM_386: + return get_x86_regs_from_elf_notes(tc); + case EM_PPC64: + return get_ppc64_regs_from_elf_notes(tc); + case EM_X86_64: + return get_x86_64_regs_from_elf_notes(tc); + default: + error(FATAL, + "support for ELF machine type %d not available\n", + get_netdump_arch()); + } + + return NULL; +} + +static void * +get_x86_regs_from_elf_notes(struct task_context *tc) +{ + Elf32_Nhdr *note_32; + Elf64_Nhdr *note_64; + void *note; + size_t len; + void *pt_regs; + + if ((tc->task == tt->panic_task) || + (is_task_active(tc->task) && (nd->num_prstatus_notes > 1))) { + if (nd->num_prstatus_notes > 1) + note = (void *) + nd->nt_prstatus_percpu[tc->processor]; + else + note = (void *)nd->nt_prstatus; + if (nd->elf32) { + note_32 = (Elf32_Nhdr *)note; + len = sizeof(Elf32_Nhdr); + len = roundup(len + note_32->n_namesz, 4); + } else if (nd->elf64) { + note_64 = (Elf64_Nhdr *)note; + len = sizeof(Elf64_Nhdr); + len = roundup(len + note_64->n_namesz, 4); + } + + pt_regs = (void *)((char *)note + len + + MEMBER_OFFSET("elf_prstatus", "pr_reg")); + /* NEED TO BE FIXED: Hack to get the proper alignment */ + pt_regs +=4; + } else + error(FATAL, + "cannot determine register set for task \"%s\"\n", + tc->comm); + return pt_regs; + +} + +static void * +get_x86_64_regs_from_elf_notes(struct task_context *tc) +{ + Elf64_Nhdr *note; + size_t len; + void *pt_regs; + + if ((tc->task == tt->panic_task) || + (is_task_active(tc->task) && (nd->num_prstatus_notes > 1))) { + if (nd->num_prstatus_notes > 1) + note = (Elf64_Nhdr *) + nd->nt_prstatus_percpu[tc->processor]; + else + note = (Elf64_Nhdr *)nd->nt_prstatus; + + len = sizeof(Elf64_Nhdr); + len = roundup(len + note->n_namesz, 4); + pt_regs = (void *)((char *)note + len + + MEMBER_OFFSET("elf_prstatus", "pr_reg")); + } else + error(FATAL, + "cannot determine register set for task \"%s\"\n", + tc->comm); + return pt_regs; +} + +static void * +get_ppc64_regs_from_elf_notes(struct task_context *tc) +{ + Elf64_Nhdr *note; + size_t len; + void *pt_regs; + extern struct vmcore_data *nd; + + if ((tc->task == tt->panic_task) || + (is_task_active(tc->task) && (nd->num_prstatus_notes > 1))) { + /* + * Registers are always saved during the dump process for the + * panic task. Kdump also captures registers for all CPUs if + * they responded to an IPI. + */ + if (nd->num_prstatus_notes > 1) { + if (tc->processor >= nd->num_prstatus_notes) + error(FATAL, "cannot determine NT_PRSTATUS ELF note " + "for %s task: %lx\n", (tc->task == tt->panic_task) ? + "panic" : "active", tc->task); + note = (Elf64_Nhdr *) + nd->nt_prstatus_percpu[tc->processor]; + } else + note = (Elf64_Nhdr *)nd->nt_prstatus; + + len = sizeof(Elf64_Nhdr); + len = roundup(len + note->n_namesz, 4); + pt_regs = (void *)((char *)note + len + + MEMBER_OFFSET("elf_prstatus", "pr_reg")); + } else + error(FATAL, + "cannot determine register set for task \"%s\"\n", + tc->comm); + + return pt_regs; +} --- crash-4.0-8.9/defs.h 2009-05-29 16:41:11.000000000 -0400 +++ crash-4.0-8.10/defs.h 2009-05-29 15:09:29.000000000 -0400 @@ -381,6 +381,7 @@ #define BAD_INSTRUCTION (0x80) #define UD2A_INSTRUCTION (0x100) #define IRQ_IN_USE (0x200) +#define MODULE_TREE (0x400) ulonglong curcmd_private; /* general purpose per-command info */ int cur_gdb_cmd; /* current gdb command */ int last_gdb_cmd; /* previously-executed gdb command */ @@ -547,6 +548,7 @@ ulong p2m_mfn_cache_hits; ulong p2m_page_cache_hits; ulong relocate; + char *module_tree; }; /* @@ -1894,6 +1896,7 @@ struct load_module *load_modules; off_t dwarf_eh_frame_file_offset; ulong dwarf_eh_frame_size; + ulong first_ksymbol; }; /* flags for st */ @@ -1909,6 +1912,7 @@ #define CRC_MATCHES (0x100) #define ADD_SYMBOL_FILE (0x200) #define USE_OLD_ADD_SYM (0x400) +#define PERCPU_SYMS (0x800) #endif /* !GDB_COMMON */ @@ -3281,7 +3285,7 @@ * symbols.c */ void symtab_init(void); -char *check_specified_debug_file(void); +char *check_specified_kernel_debug_file(void); void no_debugging_data(int); void get_text_init_space(void); int is_kernel_text(ulong); @@ -3427,7 +3431,7 @@ int file_exists(char *, struct stat *); int file_readable(char *); int is_directory(char *); -char *search_directory_tree(char *, char *); +char *search_directory_tree(char *, char *, int); void open_tmpfile(void); void close_tmpfile(void); void open_tmpfile2(void); @@ -3627,6 +3631,7 @@ void non_matching_kernel(void); struct load_module *modref_to_load_module(char *); void unlink_module(struct load_module *); +int check_specified_module_tree(char *, char *); int is_system_call(char *, ulong); void generic_dump_irq(int); int generic_dis_filter(ulong, char *); @@ -3647,6 +3652,7 @@ void paravirt_init(void); void print_stack_text_syms(struct bt_info *, ulong, ulong); void back_trace(struct bt_info *); +ulong cpu_map_addr(const char *type); #define BT_RAW (0x1ULL) #define BT_SYMBOLIC_ARGS (0x2ULL) #define BT_FULL (0x4ULL) @@ -4133,6 +4139,8 @@ ulong xen_phys_start(void); int xen_major_version(void); int xen_minor_version(void); +int get_netdump_arch(void); +void *get_regs_from_elf_notes(struct task_context *); /* * diskdump.c --- crash-4.0-8.9/Makefile 2009-05-29 16:41:43.000000000 -0400 +++ crash-4.0-8.10/Makefile 2009-05-29 16:41:43.000000000 -0400 @@ -106,6 +106,7 @@ EXTENSIONS=extensions EXTENSION_SOURCE_FILES=${EXTENSIONS}/Makefile ${EXTENSIONS}/echo.c ${EXTENSIONS}/dminfo.c \ + ${EXTENSIONS}/snap.c ${EXTENSIONS}/snap.mk \ ${EXTENSIONS}/libsial/Makefile \ ${EXTENSIONS}/libsial/mkbaseop.c \ ${EXTENSIONS}/libsial/README \ --- crash-4.0-8.9/gdb-6.1/gdb/symtab.c 2009-05-29 16:41:11.000000000 -0400 +++ crash-4.0-8.10/gdb-6.1/gdb/symtab.c 2009-04-28 13:09:59.000000000 -0400 @@ -4,7 +4,7 @@ 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. Portions Copyright (C) 2001, 2002 Mission Critical Linux, Inc. - Copyright (c) 2002, 2003, 2004, 2005, 2007 Red Hat, Inc. All rights reserved. + Copyright (c) 2002, 2003, 2004, 2005, 2007, 2009 Red Hat, Inc. All rights reserved. This file is part of GDB. @@ -4696,7 +4696,8 @@ register struct objfile *objfile; ALL_OBJFILES(objfile) { - if (STREQ(objfile->name, req->name)) { + if (STREQ(objfile->name, req->name) || + same_file(objfile->name, req->name)) { free_objfile(objfile); break; } --- crash-4.0-8.9/gdb-6.1/gdb/symfile.c 2009-05-29 16:41:11.000000000 -0400 +++ crash-4.0-8.10/gdb-6.1/gdb/symfile.c 2009-04-28 13:10:32.000000000 -0400 @@ -3,7 +3,7 @@ Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. Portions Copyright (C) 2001, 2002 Mission Critical Linux, Inc. - Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 Red Hat, Inc. All rights reserved. + Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007, 2009 Red Hat, Inc. All rights reserved. Contributed by Cygnus Support, using pieces from other GDB modules. @@ -1051,7 +1051,11 @@ char *basename; char *dir; char *debugfile; +#ifdef CRASH_MERGE char *name_copy; + extern int check_specified_module_tree(char *, char *); + extern char *check_specified_kernel_debug_file(); +#endif bfd_size_type debuglink_size; unsigned long crc32; int i; @@ -1105,6 +1109,17 @@ xfree (dir); return xstrdup (debugfile); } + +#ifdef CRASH_MERGE +{ + if (check_specified_module_tree(objfile->name, debugfile) && + separate_debug_file_exists(debugfile, crc32)) { + xfree(basename); + xfree(dir); + return xstrdup(debugfile); + } +} +#endif /* Then try in the global debugfile directory. */ strcpy (debugfile, debug_file_directory); @@ -1123,8 +1138,7 @@ xfree (dir); #ifdef CRASH_MERGE { - extern char *check_specified_debug_file(); - name_copy = check_specified_debug_file(); + name_copy = check_specified_kernel_debug_file(); return (name_copy ? xstrdup (name_copy) : NULL); } #else --- crash-4.0-8.9/extensions/Makefile 2009-05-29 16:41:11.000000000 -0400 +++ crash-4.0-8.10/extensions/Makefile 2009-05-21 16:08:33.000000000 -0400 @@ -1,8 +1,8 @@ # # Makefile for building crash shared object extensions # -# Copyright (C) 2005, 2007 David Anderson -# Copyright (C) 2005, 2007 Red Hat, Inc. All rights reserved. +# Copyright (C) 2005, 2007, 2009 David Anderson +# Copyright (C) 2005, 2007, 2009 Red Hat, Inc. All rights reserved. # # 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 @@ -29,10 +29,10 @@ all: link_defs $(CONTRIB_SO) link_defs: - @if [ ! -f defs.h ]; then \ - ln -s ../defs.h; fi + @rm -f defs.h + @ln ../defs.h -$(CONTRIB_SO): %.so: %.c +$(CONTRIB_SO): %.so: %.c defs.h @if [ -f $*.mk ]; then \ make -f $*.mk; \ else \ --- crash-4.0-8.9/extensions/snap.c 2009-05-29 16:41:42.000000000 -0400 +++ crash-4.0-8.10/extensions/snap.c 2009-05-26 10:40:42.000000000 -0400 @@ -0,0 +1,736 @@ +/* snap.c - capture live memory into a kdump or netdump dumpfile + * + * Copyright (C) 2009 David Anderson + * Copyright (C) 2009 Red Hat, Inc. All rights reserved. + * + * 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. + */ + +#include "defs.h" +#include +#include +#include + +int _init(void); +int _fini(void); + +void cmd_snap(void); +char *help_snap[]; + +static struct command_table_entry command_table[] = { + { "snap", cmd_snap, help_snap, 0 }, + { NULL } +}; + +static size_t generate_elf_header(int, int, char *); +static int verify_paddr(physaddr_t); +static void init_ram_segments(void); +static int print_progress(const char *, ulong); + +#if defined(X86) || defined(X86_64) || defined(IA64) || defined(PPC64) +int supported = TRUE; +#else +int supported = FALSE; +#endif + +int +_init(void) /* Register the command set. */ +{ + register_extension(command_table); + return 1; +} + +int +_fini(void) +{ + return 1; +} + + +/* + * Just pass in an unused filename. + */ +void +cmd_snap(void) +{ + int c, fd, n; + physaddr_t paddr; + size_t offset; + char *buf; + char *filename; + struct node_table *nt; + int type; + + if (!supported) + error(FATAL, "command not supported on the %s architecture\n", + pc->machine_type); + + filename = NULL; + buf = GETBUF(PAGESIZE()); + type = KDUMP_ELF64; + + while ((c = getopt(argcnt, args, "n")) != EOF) { + switch(c) + { + case 'n': + if (machine_type("X86_64")) + option_not_supported('n'); + else + type = NETDUMP_ELF64; + break; + default: + argerrs++; + break; + } + } + + if (argerrs || !args[optind]) + cmd_usage(pc->curcmd, SYNOPSIS); + + while (args[optind]) { + if (filename) + cmd_usage(pc->curcmd, SYNOPSIS); + + if (file_exists(args[optind], NULL)) + error(FATAL, "%s: file already exists\n", args[optind]); + else if ((fd = open(args[optind], O_RDWR|O_CREAT, 0644)) < 0) + error(FATAL, args[optind]); + + filename = args[optind]; + optind++; + } + + if (!filename) + cmd_usage(pc->curcmd, SYNOPSIS); + + init_ram_segments(); + + if (!(offset = generate_elf_header(type, fd, filename))) + error(FATAL, "cannot generate ELF header\n"); + + for (n = 0; n < vt->numnodes; n++) { + nt = &vt->node_table[n]; + paddr = nt->start_paddr; + for (c = 0; c < nt->size; c++, paddr += PAGESIZE()) { + if (!verify_paddr(paddr)) + continue; + if (!readmem(paddr, PHYSADDR, &buf[0], PAGESIZE(), + "memory page", QUIET|RETURN_ON_ERROR)) + continue; + + lseek(fd, (off_t)(paddr + offset), SEEK_SET); + if (write(fd, &buf[0], PAGESIZE()) != PAGESIZE()) + error(FATAL, "write to dumpfile failed\n"); + + if (!print_progress(filename, BTOP(paddr))) + return; + } + } + + fprintf(stderr, "\r%s: [100%%] ", filename); + fprintf(fp, "\n"); + sprintf(buf, "/bin/ls -l %s\n", filename); + system(buf); + + FREEBUF(buf); +} + + +char *help_snap[] = { + "snap", /* command name */ + "take a memory snapshot", /* short description */ + "[-n] dumpfile", /* filename */ + + " This command takes a snapshot of physical memory and creates an ELF vmcore.", + " The default vmcore is a kdump-style dumpfile. Supported on x86, x86_64,", + " ia64 and ppc64 architectures only.", + " ", + " -n create a netdump-style vmcore (n/a on x86_64).", + NULL +}; + +/* + * Architecture-specific and -generic ELF header data borrowed from the + * netdump.h file in the netdump package, modified slightly to also create + * a kdump-style vmcore. + */ + +/****************************************************************************** + * Elf core dumping * + ******************************************************************************/ + +/* + * Host-platform independent data + */ +#define ELF_PRARGSZ (80) /* Number of chars for args */ +struct elf_prpsinfo_64 +{ + char pr_state; /* numeric process state */ + char pr_sname; /* char for pr_state */ + char pr_zomb; /* zombie */ + char pr_nice; /* nice val */ + __u64 pr_flag; /* flags */ + __u32 pr_uid; + __u32 pr_gid; + __u32 pr_pid, pr_ppid, pr_pgrp, pr_sid; + /* Lots missing */ + char pr_fname[16]; /* filename of executable */ + char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */ +}; + +/* + * i386 specific + */ +struct user_regs_struct_i386 { + __u32 ebx, ecx, edx, esi, edi, ebp, eax; + __u16 ds, __ds, es, __es; + __u16 fs, __fs, gs, __gs; + __u32 orig_eax, eip; + __u16 cs, __cs; + __u32 eflags, esp; + __u16 ss, __ss; +}; + +#define ELF_NGREG_I386 (sizeof (struct user_regs_struct_i386) / sizeof(__u32)) +typedef __u32 elf_gregset_i386_t[ELF_NGREG_I386]; + +struct elf_prstatus_i386 { + char pad[72]; + elf_gregset_i386_t pr_reg; /* GP registers */ + __u32 pr_fpvalid; /* True if math co-processor being used. */ +}; + +/* + * x86_64 specific + */ +struct user_regs_struct_x86_64 { + __u64 r15,r14,r13,r12,rbp,rbx,r11,r10; + __u64 r9,r8,rax,rcx,rdx,rsi,rdi,orig_rax; + __u64 rip,cs,eflags; + __u64 rsp,ss; + __u64 fs_base, gs_base; + __u64 ds,es,fs,gs; +}; + +#define ELF_NGREG_X86_64 (sizeof (struct user_regs_struct_x86_64) / sizeof(__u64)) +typedef __u64 elf_gregset_x86_64_t[ELF_NGREG_X86_64]; + +struct elf_prstatus_x86_64 { + char pad[112]; + elf_gregset_x86_64_t pr_reg; /* GP registers */ + __u32 pr_fpvalid; /* True if math co-processor being used. */ +}; + +/* + * ppc64 specific + */ +struct user_regs_struct_ppc64 { + __u64 gpr[32]; + __u64 nip; + __u64 msr; + __u64 orig_gpr3; + __u64 ctr; + __u64 link; + __u64 xer; + __u64 ccr; + __u64 softe; + __u64 trap; + __u64 dar; + __u64 dsisr; + __u64 result; +}; + +#define ELF_NGREG_PPC64 (sizeof (struct user_regs_struct_ppc64) / sizeof(__u64)) +typedef __u64 elf_gregset_ppc64_t[ELF_NGREG_PPC64]; + +struct elf_prstatus_ppc64 { + char pad[112]; + elf_gregset_ppc64_t pr_reg; /* GP registers */ + __u32 pr_fpvalid; /* True if math co-processor being used. */ +}; + +/* + * ia64 specific + */ +struct _ia64_fpreg { + union { + __u64 bits[2]; + } u; +} __attribute__ ((aligned (16))); + +struct user_regs_struct_ia64 { + /* The following registers are saved by SAVE_MIN: */ + __u64 b6; /* scratch */ + __u64 b7; /* scratch */ + + __u64 ar_csd; /* used by cmp8xchg16 (scratch) */ + __u64 ar_ssd; /* reserved for future use (scratch) */ + + __u64 r8; /* scratch (return value register 0) */ + __u64 r9; /* scratch (return value register 1) */ + __u64 r10; /* scratch (return value register 2) */ + __u64 r11; /* scratch (return value register 3) */ + + __u64 cr_ipsr; /* interrupted task's psr */ + __u64 cr_iip; /* interrupted task's instruction pointer */ + __u64 cr_ifs; /* interrupted task's function state */ + + __u64 ar_unat; /* interrupted task's NaT register (preserved) */ + __u64 ar_pfs; /* prev function state */ + __u64 ar_rsc; /* RSE configuration */ + /* The following two are valid only if cr_ipsr.cpl > 0: */ + __u64 ar_rnat; /* RSE NaT */ + __u64 ar_bspstore; /* RSE bspstore */ + + __u64 pr; /* 64 predicate registers (1 bit each) */ + __u64 b0; /* return pointer (bp) */ + __u64 loadrs; /* size of dirty partition << 16 */ + + __u64 r1; /* the gp pointer */ + __u64 r12; /* interrupted task's memory stack pointer */ + __u64 r13; /* thread pointer */ + + __u64 ar_fpsr; /* floating point status (preserved) */ + __u64 r15; /* scratch */ + + /* The remaining registers are NOT saved for system calls. */ + + __u64 r14; /* scratch */ + __u64 r2; /* scratch */ + __u64 r3; /* scratch */ + + /* The following registers are saved by SAVE_REST: */ + __u64 r16; /* scratch */ + __u64 r17; /* scratch */ + __u64 r18; /* scratch */ + __u64 r19; /* scratch */ + __u64 r20; /* scratch */ + __u64 r21; /* scratch */ + __u64 r22; /* scratch */ + __u64 r23; /* scratch */ + __u64 r24; /* scratch */ + __u64 r25; /* scratch */ + __u64 r26; /* scratch */ + __u64 r27; /* scratch */ + __u64 r28; /* scratch */ + __u64 r29; /* scratch */ + __u64 r30; /* scratch */ + __u64 r31; /* scratch */ + + __u64 ar_ccv; /* compare/exchange value (scratch) */ + + /* + * Floating point registers that the kernel considers scratch: + */ + struct _ia64_fpreg f6; /* scratch */ + struct _ia64_fpreg f7; /* scratch */ + struct _ia64_fpreg f8; /* scratch */ + struct _ia64_fpreg f9; /* scratch */ + struct _ia64_fpreg f10; /* scratch */ + struct _ia64_fpreg f11; /* scratch */ +}; + +#define ELF_NGREG_IA64 (sizeof (struct user_regs_struct_ia64) / sizeof(__u64)) +typedef __u64 elf_gregset_ia64_t[ELF_NGREG_IA64]; + +struct elf_prstatus_ia64 { + char pad[112]; + elf_gregset_ia64_t pr_reg; /* GP registers */ + __u32 pr_fpvalid; /* True if math co-processor being used. */ +}; + +union prstatus { + struct elf_prstatus_i386 x86; + struct elf_prstatus_x86_64 x86_64; + struct elf_prstatus_ppc64 ppc64; + struct elf_prstatus_ia64 ia64; +}; + +static size_t +dump_elf_note(char *buf, Elf64_Word type, char *name, char *desc, int d_len) +{ + Elf64_Nhdr *note; + size_t len; + + note = (Elf64_Nhdr *)buf; + note->n_namesz = strlen(name); + note->n_descsz = d_len; + note->n_type = type; + len = sizeof(Elf64_Nhdr); + + memcpy(buf + len, name, note->n_namesz); + len = roundup(len + note->n_namesz, 4); + + memcpy(buf + len, desc, note->n_descsz); + len = roundup(len + note->n_descsz, 4); + + return len; +} + +static size_t +generate_elf_header(int type, int fd, char *filename) +{ + int i, n; + char *buffer, *ptr; + Elf64_Ehdr *elf; + Elf64_Phdr *notes; + Elf64_Phdr *load; + size_t offset, len, l_offset; + size_t data_offset; + struct elf_prpsinfo_64 prpsinfo; + union prstatus prstatus; + int prstatus_len; + ushort e_machine; + int num_segments; + struct node_table *nt; + ulonglong task_struct; + + num_segments = vt->numnodes; + + if (machine_type("X86_64")) { + e_machine = EM_X86_64; + prstatus_len = sizeof(prstatus.x86_64); + num_segments += 1; /* mapped kernel section for phys_base */ + } else if (machine_type("X86")) { + e_machine = EM_386; + prstatus_len = sizeof(prstatus.x86); + } else if (machine_type("IA64")) { + e_machine = EM_IA_64; + prstatus_len = sizeof(prstatus.ia64); + num_segments += 1; /* mapped kernel section for phys_start */ + } else if (machine_type("PPC64")) { + e_machine = EM_PPC64; + prstatus_len = sizeof(prstatus.ppc64); + } + + /* should be enought for the notes + roundup + two blocks */ + buffer = (char *)GETBUF(sizeof(Elf64_Ehdr) + + num_segments * sizeof(Elf64_Phdr) + PAGESIZE() * 2); + offset = 0; + ptr = buffer; + + /* Elf header */ + elf = (Elf64_Ehdr *)ptr; + memcpy(elf->e_ident, ELFMAG, SELFMAG); + elf->e_ident[EI_CLASS] = ELFCLASS64; +#if __BYTE_ORDER == __BIG_ENDIAN + elf->e_ident[EI_DATA] = ELFDATA2MSB; +#else + elf->e_ident[EI_DATA] = ELFDATA2LSB; +#endif + elf->e_ident[EI_VERSION] = EV_CURRENT; + elf->e_ident[EI_OSABI] = ELFOSABI_SYSV; + elf->e_ident[EI_ABIVERSION] = 0; + memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD); + + elf->e_type = ET_CORE; + elf->e_machine = e_machine; + elf->e_version = EV_CURRENT; + elf->e_entry = 0; + elf->e_phoff = sizeof(Elf64_Ehdr); + elf->e_shoff = 0; + elf->e_flags = 0; + elf->e_ehsize = sizeof(Elf64_Ehdr); + elf->e_phentsize = sizeof(Elf64_Phdr); + elf->e_phnum = 1 + num_segments; + elf->e_shentsize = 0; + elf->e_shnum = 0; + elf->e_shstrndx = 0; + + offset += sizeof(Elf64_Ehdr); + ptr += sizeof(Elf64_Ehdr); + + /* PT_NOTE */ + notes = (Elf64_Phdr *)ptr; + notes->p_type = PT_NOTE; + notes->p_offset = 0; /* TO BE FILLED IN */ + notes->p_vaddr = 0; + notes->p_paddr = 0; + notes->p_filesz = 0; /* TO BE FILLED IN */ + notes->p_memsz = 0; + notes->p_flags = 0; + notes->p_align = 0; + + offset += sizeof(Elf64_Phdr); + ptr += sizeof(Elf64_Phdr); + + /* PT_LOAD */ + load = (Elf64_Phdr *)ptr; + for (i = n = 0; i < num_segments; i++) { + load[i].p_type = PT_LOAD; + load[i].p_offset = 0; /* TO BE FILLED IN */ + + switch (e_machine) + { + case EM_X86_64: + nt = &vt->node_table[n]; + if (i == 0) { +#ifdef X86_64 + load[i].p_vaddr = __START_KERNEL_map; + load[i].p_paddr = machdep->machspec->phys_base; +#endif + load[i].p_filesz = 0; + load[i].p_memsz = load[i].p_filesz; + } else { + load[i].p_vaddr = PTOV(nt->start_paddr); + load[i].p_paddr = nt->start_paddr; + load[i].p_filesz = nt->size * PAGESIZE(); + load[i].p_memsz = load[i].p_filesz; + n++; + } + load[i].p_flags = PF_R | PF_W | PF_X; + load[i].p_align = 0; + break; + + case EM_386: + nt = &vt->node_table[n++]; + load[i].p_vaddr = 0; + load[i].p_paddr = nt->start_paddr; + load[i].p_filesz = nt->size * PAGESIZE(); + load[i].p_memsz = load[i].p_filesz; + load[i].p_flags = PF_R | PF_W | PF_X; + load[i].p_align = (type == NETDUMP_ELF64) ? PAGESIZE() : 0; + break; + + case EM_IA_64: + nt = &vt->node_table[n]; + if (i == 0) { +#ifdef IA64 + load[i].p_vaddr = machdep->machspec->kernel_start; + load[i].p_paddr = machdep->machspec->phys_start; +#endif + load[i].p_filesz = 0; + load[i].p_memsz = load[i].p_filesz; + } else { + load[i].p_vaddr = PTOV(nt->start_paddr); + load[i].p_paddr = nt->start_paddr; + load[i].p_filesz = nt->size * PAGESIZE(); + load[i].p_memsz = load[i].p_filesz; + n++; + } + load[i].p_flags = PF_R | PF_W | PF_X; + load[i].p_align = (type == NETDUMP_ELF64) ? PAGESIZE() : 0; + break; + + case EM_PPC64: + nt = &vt->node_table[n++]; + load[i].p_vaddr = PTOV(nt->start_paddr); + load[i].p_paddr = nt->start_paddr; + load[i].p_filesz = nt->size * PAGESIZE(); + load[i].p_memsz = load[i].p_filesz; + load[i].p_flags = PF_R | PF_W | PF_X; + load[i].p_align = (type == NETDUMP_ELF64) ? PAGESIZE() : 0; + break; + } + + l_offset += load[i].p_filesz; + offset += sizeof(Elf64_Phdr); + ptr += sizeof(Elf64_Phdr); + } + notes->p_offset = offset; + + /* NT_PRSTATUS note */ + memset(&prstatus, 0, sizeof(prstatus)); + len = dump_elf_note(ptr, NT_PRSTATUS, "CORE", + (char *)&prstatus, prstatus_len); + offset += len; + ptr += len; + notes->p_filesz += len; + + /* NT_PRPSINFO note */ + memset(&prpsinfo, 0, sizeof(struct elf_prpsinfo_64)); + prpsinfo.pr_state = 0; + prpsinfo.pr_sname = 'R'; + prpsinfo.pr_zomb = 0; + strcpy(prpsinfo.pr_fname, "vmlinux"); + + len = dump_elf_note(ptr, NT_PRPSINFO, "CORE", + (char *)&prpsinfo, sizeof(prpsinfo)); + + offset += len; + ptr += len; + notes->p_filesz += len; + + /* NT_TASKSTRUCT note */ + task_struct = CURRENT_TASK(); + len = dump_elf_note (ptr, NT_TASKSTRUCT, "CORE", + (char *)&task_struct, sizeof(ulonglong)); + offset += len; + ptr += len; + notes->p_filesz += len; + + if (type == NETDUMP_ELF64) + offset = roundup (offset, PAGESIZE()); + + l_offset = offset; + for (i = 0; i < num_segments; i++) { + load[i].p_offset = l_offset; + l_offset += load[i].p_filesz; + } + data_offset = offset; + + while (offset > 0) { + len = write(fd, buffer + (data_offset - offset), offset); + if (len < 0) { + perror(filename); + data_offset = 0; + break; + } + + offset -= len; + } + FREEBUF(buffer); + + return data_offset; +} + +struct ram_segments { + physaddr_t start; + physaddr_t end; +}; + +static struct ram_segments *ram_segments = NULL; +static int nr_segments = 0; + +static void +init_ram_segments(void) +{ + int i, errflag; + FILE *iomem; + char buf[BUFSIZE], *p1, *p2; + physaddr_t start, end; + + if ((iomem = fopen("/proc/iomem", "r")) == NULL) + goto fail_iomem; + + while (fgets(buf, BUFSIZE, iomem)) { + if (strstr(buf, "System RAM")) { + console(buf); + nr_segments++; + } + } + if (!nr_segments) + goto fail_iomem; + + ram_segments = (struct ram_segments *) + GETBUF(sizeof(struct ram_segments) * nr_segments); + + rewind(iomem); + i = 0; + while (fgets(buf, BUFSIZE, iomem)) { + if (strstr(buf, "System RAM")) { + if (!(p1 = strstr(buf, ":"))) + goto fail_iomem; + *p1 = NULLCHAR; + clean_line(buf); + if (strstr(buf, " ")) + goto fail_iomem; + p1 = buf; + if (!(p2 = strstr(buf, "-"))) + goto fail_iomem; + *p2 = NULLCHAR; + p2++; + errflag = 0; + start = htoll(p1, RETURN_ON_ERROR|QUIET, &errflag); + end = htoll(p2, RETURN_ON_ERROR|QUIET, &errflag); + if (errflag) + goto fail_iomem; + ram_segments[i].start = PHYSPAGEBASE(start); + if (PAGEOFFSET(start)) + ram_segments[i].start += PAGESIZE(); + ram_segments[i].end = PHYSPAGEBASE(end); + if (PAGEOFFSET(end) == (PAGESIZE()-1)) + ram_segments[i].end += PAGESIZE(); + console("ram_segments[%d]: %016llx %016llx [%s-%s]\n", i, + (ulonglong)ram_segments[i].start, + (ulonglong)ram_segments[i].end, p1, p2); + i++; + } + } + + fclose(iomem); + return; + +fail_iomem: + fclose(iomem); + nr_segments = 0; + if (ram_segments) + FREEBUF(ram_segments); + + return; +} + +static int +verify_paddr(physaddr_t paddr) +{ + int i, ok; + + if (!machdep->verify_paddr(paddr)) + return FALSE; + + if (!nr_segments) + return TRUE; + + for (i = ok = 0; i < nr_segments; i++) { + if ((paddr >= ram_segments[i].start) && + (paddr < ram_segments[i].end)) { + ok++; + break; + } + } + + if (!ok) { + if (CRASHDEBUG(1)) + console("reject: %llx\n", (ulonglong)paddr); + return FALSE; + } + + return TRUE; +} + +/* + * Borrowed from makedumpfile, prints a percentage-done value + * once per second. + */ +static int +print_progress(const char *filename, ulong current) +{ + int n, progress; + time_t tm; + struct node_table *nt; + static time_t last_time = 0; + static ulong total_pages = 0; + + if (!total_pages) { + for (n = 0; n < vt->numnodes; n++) { + nt = &vt->node_table[n]; + total_pages += nt->size; + } + } + + if (received_SIGINT()) { + fprintf(stderr, "\n\n"); + return FALSE; + } + + if (current < total_pages) { + tm = time(NULL); + if (tm - last_time < 1) + return TRUE; + last_time = tm; + progress = current * 100 / total_pages; + } else + progress = 100; + + fprintf(stderr, "\r%s: [%2d%%] ", filename, progress); + + return TRUE; +} --- crash-4.0-8.9/extensions/snap.mk 2009-05-29 16:41:42.000000000 -0400 +++ crash-4.0-8.10/extensions/snap.mk 2009-05-21 16:38:41.000000000 -0400 @@ -0,0 +1,26 @@ +ifeq ($(shell arch), i686) + TARGET=X86 + TARGET_CFLAGS=-D_FILE_OFFSET_BITS=64 +else ifeq ($(shell arch), ppc64) + TARGET=PPC64 + TARGET_CFLAGS=-m64 +else ifeq ($(shell arch), ia64) + TARGET=IA64 + TARGET_CFLAGS= +else ifeq ($(shell arch), x86_64) + TARGET=X86_64 + TARGET_CFLAGS= +endif + +ifeq ($(shell /bin/ls ./defs.h 2> /dev/null), ./defs.h) + INCDIR=. +else ifeq ($(shell /bin/ls ../defs.h 2> /dev/null), ../defs.h) + INCDIR=.. +else ifeq ($(shell /bin/ls /usr/include/crash/defs.h 2>/dev/null), /usr/include/crash/defs.h) + INCDIR=/usr/include/crash +endif + +all: snap.so + +snap.so: $(INCDIR)/defs.h snap.c + gcc -Wall -I$(INCDIR) -nostartfiles -shared -rdynamic -o snap.so snap.c -fPIC -D$(TARGET) $(TARGET_CFLAGS) --- crash-4.0-8.9/extensions/sial.c 2009-05-29 16:41:11.000000000 -0400 +++ crash-4.0-8.10/extensions/sial.c 2009-05-20 10:42:37.000000000 -0400 @@ -1,5 +1,5 @@ /* - * $Id: sial.c,v 1.7 2008/10/28 18:53:10 anderson Exp $ + * $Id: sial.c,v 1.8 2009/04/30 20:04:02 anderson Exp $ * * This file is part of lcrash, an analysis tool for Linux memory dumps. * @@ -84,6 +84,14 @@ extern FILE *fp; extern char *crash_global_cmd(); +typedef unsigned long long int ulonglong; +extern int readmem(ulonglong, int, void *, long, char *, ulong); +extern int symbol_exists(char *); +extern ulong symbol_value(char *); +extern void cmd_usage(char *, int); +extern void register_extension(struct command_table_entry *); + + // ///////////////////////////////////////////////////////////////////////// /*