--- crash-4.0-8.8/main.c 2009-04-16 13:18:20.000000000 -0400 +++ crash-4.0-8.9/main.c 2009-04-09 14:10:02.000000000 -0400 @@ -65,7 +65,7 @@ int main(int argc, char **argv) { - int c, option_index; + int i, c, option_index; setup_environment(argc, argv); @@ -128,8 +128,17 @@ kt->flags |= SMP; else if (STREQ(long_options[option_index].name, - "machdep")) - machdep->cmdline_arg = optarg; + "machdep")) { + for (i = 0; i < MAX_MACHDEP_ARGS; i++) { + if (machdep->cmdline_args[i]) + continue; + machdep->cmdline_args[i] = optarg; + break; + } + if (i == MAX_MACHDEP_ARGS) + error(INFO, "option ignored: %s\n", + optarg); + } else if (STREQ(long_options[option_index].name, "version")) { @@ -297,7 +306,15 @@ break; case 'm': - machdep->cmdline_arg = optarg; + for (i = 0; i < MAX_MACHDEP_ARGS; i++) { + if (machdep->cmdline_args[i]) + continue; + machdep->cmdline_args[i] = optarg; + break; + } + if (i == MAX_MACHDEP_ARGS) + error(INFO, "option ignored: %s\n", + optarg); break; default: @@ -396,7 +413,8 @@ pc->writemem = write_xendump; } else if (is_diskdump(argv[optind])) { - if (pc->flags & MEMORY_SOURCES) { + if ((pc->flags & MEMORY_SOURCES) && + (!dumpfile_is_split())) { error(INFO, "too many dumpfile arguments\n"); program_usage(SHORT_FORM); --- crash-4.0-8.8/help.c 2009-04-16 13:18:20.000000000 -0400 +++ crash-4.0-8.9/help.c 2009-04-02 14:28:56.000000000 -0400 @@ -1251,7 +1251,7 @@ "bt", "backtrace", #if defined(GDB_6_0) || defined(GDB_6_1) -"[-a|-r|-t|-T|-l|-e|-E|-f|-o|-O] [-R ref] [ -I ip ] [-S sp] [pid | taskp]", +"[-a|-g|-r|-t|-T|-l|-e|-E|-f|-o|-O] [-R ref] [ -I ip ] [-S sp] [pid | taskp]", #else "[-a|-r|-t|-l|-e|-f|-g] [-R ref] [ -I ip ] [-S sp] [pid | taskp]", #endif @@ -1259,6 +1259,8 @@ " trace of the current context will be displayed.\n", " -a displays the stack traces of the active task on each CPU.", " (only applicable to crash dumps)", +" -g displays the stack traces of all threads in the thread group of", +" the target task; the thread group leader will be displayed first.", " -r display raw stack data, consisting of a memory dump of the two", " pages of memory containing the task_union structure.", " -t display all text symbols found from the last known stack location", --- crash-4.0-8.8/task.c 2009-04-16 13:18:20.000000000 -0400 +++ crash-4.0-8.9/task.c 2009-04-02 14:25:00.000000000 -0400 @@ -5064,6 +5064,11 @@ error(INFO, "line numbers are not available\n"); fd->flags &= ~FOREACH_l_FLAG; } +#if defined(GDB_6_0) || defined(GDB_6_1) + if ((fd->flags & FOREACH_g_FLAG)) + error(FATAL, + "bt -g option is not supported when issued from foreach\n"); +#endif bt = &bt_info; break; --- crash-4.0-8.8/kernel.c 2009-04-16 13:18:20.000000000 -0400 +++ crash-4.0-8.9/kernel.c 2009-04-03 09:21:37.000000000 -0400 @@ -828,19 +828,26 @@ fprintf(fp, "DEBUG KERNEL: %s %s\n", pc->namelist_debug, debug_kernel_version(pc->namelist_debug)); - fprintf(fp, " DUMPFILE: "); + if (dumpfile_is_split()) + fprintf(fp, " DUMPFILES: "); + else + fprintf(fp, " DUMPFILE: "); if (ACTIVE()) { if (REMOTE_ACTIVE()) fprintf(fp, "%s@%s (remote live system)\n", pc->server_memsrc, pc->server); - else + else fprintf(fp, "%s\n", pc->live_memsrc); } else { if (REMOTE_DUMPFILE()) fprintf(fp, "%s@%s (remote dumpfile)\n", pc->server_memsrc, pc->server); - else - fprintf(fp, "%s\n", pc->dumpfile); + else { + if (dumpfile_is_split()) + show_split_dumpfiles(); + else + fprintf(fp, "%s", pc->dumpfile); + } } fprintf(fp, "\n"); @@ -1600,11 +1607,54 @@ bt->ref = &reference; \ bt->ref->str = refptr; \ } + +#define DO_TASK_BACKTRACE() \ + { \ + BT_SETUP(tc); \ + if (!BT_REFERENCE_CHECK(bt)) \ + print_task_header(fp, tc, subsequent++); \ + back_trace(bt); \ + } +#define DO_THREAD_GROUP_BACKTRACE() \ + { \ + tc = pid_to_context(tgid); \ + BT_SETUP(tc); \ + if (!BT_REFERENCE_CHECK(bt)) \ + print_task_header(fp, tc, subsequent++); \ + if (setjmp(pc->foreach_loop_env)) { \ + pc->flags &= ~IN_FOREACH; \ + free_all_bufs(); \ + } else { \ + pc->flags |= IN_FOREACH; \ + back_trace(bt); \ + pc->flags &= ~IN_FOREACH; \ + } \ + tc = FIRST_CONTEXT(); \ + for (i = 0; i < RUNNING_TASKS(); i++, tc++) { \ + if (tc->pid == tgid) \ + continue; \ + if (task_tgid(tc->task) != tgid) \ + continue; \ + BT_SETUP(tc); \ + if (!BT_REFERENCE_CHECK(bt)) \ + print_task_header(fp, tc, subsequent++);\ + if (setjmp(pc->foreach_loop_env)) { \ + pc->flags &= ~IN_FOREACH; \ + free_all_bufs(); \ + } else { \ + pc->flags |= IN_FOREACH; \ + back_trace(bt); \ + pc->flags &= ~IN_FOREACH; \ + } \ + } \ + pc->flags &= ~IN_FOREACH; \ + } + void cmd_bt(void) { - int c; + int i, c; ulong value; struct task_context *tc; int count, subsequent, active; @@ -1612,6 +1662,7 @@ struct bt_info bt_info, bt_setup, *bt; struct reference reference; char *refptr; + ulong tgid; tc = NULL; subsequent = active = count = 0; @@ -1688,8 +1739,7 @@ case 'g': #if defined(GDB_6_0) || defined(GDB_6_1) - error(FATAL, - "-g option is not supported with this version of gdb\n"); + bt->flags |= BT_THREAD_GROUP; #else bt->flags |= BT_USE_GDB; #endif @@ -1838,33 +1888,36 @@ if (active) { if (ACTIVE()) error(FATAL, - "-a option not supported on a live system\n"); + "-a option not supported on a live system\n"); + + if (bt->flags & BT_THREAD_GROUP) + error(FATAL, + "-a option cannot be used with the -g option\n"); for (c = 0; c < NR_CPUS; c++) { if (setjmp(pc->foreach_loop_env)) { + pc->flags &= ~IN_FOREACH; free_all_bufs(); continue; } - pc->flags |= IN_FOREACH; - if ((tc = task_to_context(tt->panic_threads[c]))) { - BT_SETUP(tc); - if (!BT_REFERENCE_CHECK(bt)) - print_task_header(fp, tc, subsequent++); - back_trace(bt); + pc->flags |= IN_FOREACH; + DO_TASK_BACKTRACE(); + pc->flags &= ~IN_FOREACH; } } - pc->flags &= ~IN_FOREACH; return; } if (!args[optind]) { - tc = CURRENT_CONTEXT(); - BT_SETUP(tc); - if (!BT_REFERENCE_CHECK(bt)) - print_task_header(fp, tc, 0); - back_trace(bt); + if (CURRENT_PID() && (bt->flags & BT_THREAD_GROUP)) { + tgid = task_tgid(CURRENT_TASK()); + DO_THREAD_GROUP_BACKTRACE(); + } else { + tc = CURRENT_CONTEXT(); + DO_TASK_BACKTRACE(); + } return; } @@ -1873,19 +1926,31 @@ { case STR_PID: for (tc = pid_to_context(value); tc; tc = tc->tc_next) { - BT_SETUP(tc); - if (!BT_REFERENCE_CHECK(bt)) - print_task_header(fp, tc, subsequent++); - back_trace(bt); - } - break; + if (tc->pid && (bt->flags & BT_THREAD_GROUP)) { + tgid = task_tgid(tc->task); + DO_THREAD_GROUP_BACKTRACE(); + break; + } else if (tc->tc_next) { + if (setjmp(pc->foreach_loop_env)) { + pc->flags &= ~IN_FOREACH; + free_all_bufs(); + continue; + } + pc->flags |= IN_FOREACH; + DO_TASK_BACKTRACE(); + pc->flags &= ~IN_FOREACH; + } else + DO_TASK_BACKTRACE(); + } + break; case STR_TASK: - BT_SETUP(tc); - if (!BT_REFERENCE_CHECK(bt)) - print_task_header(fp, tc, subsequent++); - back_trace(bt); - break; + if (tc->pid && (bt->flags & BT_THREAD_GROUP)) { + tgid = task_tgid(value); + DO_THREAD_GROUP_BACKTRACE(); + } else + DO_TASK_BACKTRACE(); + break; case STR_INVALID: error(INFO, "%sinvalid task or pid value: %s\n", @@ -3571,7 +3636,10 @@ fprintf(fp, "DEBUG KERNEL: %s %s\n", pc->namelist_debug, debug_kernel_version(pc->namelist_debug)); - fprintf(fp, " DUMPFILE: "); + if (dumpfile_is_split()) + fprintf(fp, " DUMPFILES: "); + else + fprintf(fp, " DUMPFILE: "); if (ACTIVE()) { if (REMOTE_ACTIVE()) fprintf(fp, "%s@%s (remote live system)\n", @@ -3582,13 +3650,18 @@ if (REMOTE_DUMPFILE()) fprintf(fp, "%s@%s (remote dumpfile)", pc->server_memsrc, pc->server); - else - fprintf(fp, "%s", pc->dumpfile); + else { + if (dumpfile_is_split()) + show_split_dumpfiles(); + else + fprintf(fp, "%s", pc->dumpfile); + } if (NETDUMP_DUMPFILE() && is_partial_netdump()) fprintf(fp, " [PARTIAL DUMP]"); - if (DISKDUMP_DUMPFILE() && is_partial_diskdump()) + if (DISKDUMP_DUMPFILE() && !dumpfile_is_split() && + is_partial_diskdump()) fprintf(fp, " [PARTIAL DUMP]"); fprintf(fp, "\n"); --- crash-4.0-8.8/ia64.c 2009-04-16 13:18:20.000000000 -0400 +++ crash-4.0-8.9/ia64.c 2009-04-09 15:25:33.000000000 -0400 @@ -55,7 +55,7 @@ static struct line_number_hook ia64_line_number_hooks[]; static ulong ia64_get_stackbase(ulong); static ulong ia64_get_stacktop(ulong); -static void parse_cmdline_arg(void); +static void parse_cmdline_args(void); static void ia64_calc_phys_start(void); struct unw_frame_info; @@ -145,8 +145,8 @@ machdep->verify_paddr = ia64_verify_paddr; machdep->ptrs_per_pgd = PTRS_PER_PGD; machdep->machspec->phys_start = UNKNOWN_PHYS_START; - if (machdep->cmdline_arg) - parse_cmdline_arg(); + if (machdep->cmdline_args[0]) + parse_cmdline_args(); if (ACTIVE()) machdep->flags |= DEVMEMRD; break; @@ -267,9 +267,9 @@ */ void -parse_cmdline_arg(void) +parse_cmdline_args(void) { - int i, c, errflag; + int index, i, c, errflag; char *p; char buf[BUFSIZE]; char *arglist[MAXARGS]; @@ -280,92 +280,98 @@ ms = &ia64_machine_specific; vm_flag = 0; - if (!strstr(machdep->cmdline_arg, "=")) { - errflag = 0; - value = htol(machdep->cmdline_arg, - RETURN_ON_ERROR|QUIET, &errflag); - if (!errflag) { - ms->phys_start = value; - error(NOTE, "setting phys_start to: 0x%lx\n", - ms->phys_start); - } else - error(WARNING, "ignoring --machdep option: %s\n\n", - machdep->cmdline_arg); - return; - } - - strcpy(buf, machdep->cmdline_arg); + for (index = 0; index < MAX_MACHDEP_ARGS; index++) { - for (p = buf; *p; p++) { - if (*p == ',') - *p = ' '; - } - - c = parse_line(buf, arglist); - - for (i = 0; i < c; i++) { - errflag = 0; + if (!machdep->cmdline_args[index]) + break; - if (STRNEQ(arglist[i], "phys_start=")) { - p = arglist[i] + strlen("phys_start="); - if (strlen(p)) { - value = htol(p, RETURN_ON_ERROR|QUIET, - &errflag); - if (!errflag) { - ms->phys_start = value; - error(NOTE, - "setting phys_start to: 0x%lx\n", - ms->phys_start); - continue; + if (!strstr(machdep->cmdline_args[index], "=")) { + errflag = 0; + value = htol(machdep->cmdline_args[index], + RETURN_ON_ERROR|QUIET, &errflag); + if (!errflag) { + ms->phys_start = value; + error(NOTE, "setting phys_start to: 0x%lx\n", + ms->phys_start); + } else + error(WARNING, "ignoring --machdep option: %s\n\n", + machdep->cmdline_args[index]); + continue; + } + + strcpy(buf, machdep->cmdline_args[index]); + + for (p = buf; *p; p++) { + if (*p == ',') + *p = ' '; + } + + c = parse_line(buf, arglist); + + for (i = 0; i < c; i++) { + errflag = 0; + + if (STRNEQ(arglist[i], "phys_start=")) { + p = arglist[i] + strlen("phys_start="); + if (strlen(p)) { + value = htol(p, RETURN_ON_ERROR|QUIET, + &errflag); + if (!errflag) { + ms->phys_start = value; + error(NOTE, + "setting phys_start to: 0x%lx\n", + ms->phys_start); + continue; + } } - } - } else if (STRNEQ(arglist[i], "init_stack_size=")) { - p = arglist[i] + strlen("init_stack_size="); - if (strlen(p)) { - value = stol(p, RETURN_ON_ERROR|QUIET, - &errflag); - if (!errflag) { - ms->ia64_init_stack_size = (int)value; - error(NOTE, - "setting init_stack_size to: 0x%x (%d)\n", - ms->ia64_init_stack_size, - ms->ia64_init_stack_size); - continue; + } else if (STRNEQ(arglist[i], "init_stack_size=")) { + p = arglist[i] + strlen("init_stack_size="); + if (strlen(p)) { + value = stol(p, RETURN_ON_ERROR|QUIET, + &errflag); + if (!errflag) { + ms->ia64_init_stack_size = (int)value; + error(NOTE, + "setting init_stack_size to: 0x%x (%d)\n", + ms->ia64_init_stack_size, + ms->ia64_init_stack_size); + continue; + } } - } - } else if (STRNEQ(arglist[i], "vm=")) { - vm_flag++; - p = arglist[i] + strlen("vm="); - if (strlen(p)) { - if (STREQ(p, "4l")) { - machdep->flags |= VM_4_LEVEL; - continue; + } else if (STRNEQ(arglist[i], "vm=")) { + vm_flag++; + p = arglist[i] + strlen("vm="); + if (strlen(p)) { + if (STREQ(p, "4l")) { + machdep->flags |= VM_4_LEVEL; + continue; + } } } - } - - error(WARNING, "ignoring --machdep option: %s\n", arglist[i]); - } - - if (vm_flag) { - switch (machdep->flags & (VM_4_LEVEL)) - { - case VM_4_LEVEL: - error(NOTE, "using 4-level pagetable\n"); - c++; - break; - - default: - error(WARNING, "invalid vm= option\n"); - c++; - machdep->flags &= ~(VM_4_LEVEL); - break; + + error(WARNING, "ignoring --machdep option: %s\n", arglist[i]); } + + if (vm_flag) { + switch (machdep->flags & (VM_4_LEVEL)) + { + case VM_4_LEVEL: + error(NOTE, "using 4-level pagetable\n"); + c++; + break; + + default: + error(WARNING, "invalid vm= option\n"); + c++; + machdep->flags &= ~(VM_4_LEVEL); + break; + } + } + + + if (c) + fprintf(fp, "\n"); } - - - if (c) - fprintf(fp, "\n"); } @@ -444,7 +450,7 @@ void ia64_dump_machdep_table(ulong arg) { - int others, verbose; + int i, others, verbose; struct machine_specific *ms; verbose = FALSE; @@ -589,7 +595,11 @@ fprintf(fp, " pmd: %lx\n", (ulong)machdep->pmd); fprintf(fp, " ptbl: %lx\n", (ulong)machdep->ptbl); fprintf(fp, " ptrs_per_pgd: %d\n", machdep->ptrs_per_pgd); - fprintf(fp, " cmdline_arg: %s\n", machdep->cmdline_arg); + for (i = 0; i < MAX_MACHDEP_ARGS; i++) { + fprintf(fp, " cmdline_args[%d]: %s\n", + i, machdep->cmdline_args[i] ? + machdep->cmdline_args[i] : "(unused)"); + } fprintf(fp, " section_size_bits: %ld\n", machdep->section_size_bits); fprintf(fp, " max_physmem_bits: %ld\n", machdep->max_physmem_bits); fprintf(fp, " sections_per_root: %ld\n", machdep->sections_per_root); @@ -4255,8 +4265,8 @@ machdep->ptrs_per_pgd = PTRS_PER_PGD; machdep->machspec->phys_start = UNKNOWN_PHYS_START; /* ODA: if need make hyper version - if (machdep->cmdline_arg) - parse_cmdline_arg(); */ + if (machdep->cmdline_args[0]) + parse_cmdline_args(); */ break; case PRE_GDB: --- crash-4.0-8.8/ppc64.c 2009-04-16 13:18:20.000000000 -0400 +++ crash-4.0-8.9/ppc64.c 2009-04-09 15:27:23.000000000 -0400 @@ -47,7 +47,7 @@ static char * ppc64_check_eframe(struct ppc64_pt_regs *); static void ppc64_print_eframe(char *, struct ppc64_pt_regs *, struct bt_info *); -static void parse_cmdline_arg(void); +static void parse_cmdline_args(void); static void ppc64_paca_init(void); static void ppc64_clear_machdep_cache(void); @@ -75,8 +75,8 @@ machdep->verify_paddr = generic_verify_paddr; machdep->ptrs_per_pgd = PTRS_PER_PGD; machdep->flags |= MACHDEP_BT_TEXT; - if (machdep->cmdline_arg) - parse_cmdline_arg(); + if (machdep->cmdline_args[0]) + parse_cmdline_args(); machdep->clear_machdep_cache = ppc64_clear_machdep_cache; break; @@ -368,6 +368,11 @@ fprintf(fp, " section_size_bits: %ld\n", machdep->section_size_bits); fprintf(fp, " max_physmem_bits: %ld\n", machdep->max_physmem_bits); fprintf(fp, " sections_per_root: %ld\n", machdep->sections_per_root); + for (i = 0; i < MAX_MACHDEP_ARGS; i++) { + fprintf(fp, " cmdline_args[%d]: %s\n", + i, machdep->cmdline_args[i] ? + machdep->cmdline_args[i] : "(unused)"); + } fprintf(fp, " machspec: %lx\n", (ulong)machdep->machspec); fprintf(fp, " hwintrstack[%d]: ", NR_CPUS); for (c = 0; c < NR_CPUS; c++) { @@ -2315,70 +2320,76 @@ */ void -parse_cmdline_arg(void) +parse_cmdline_args(void) { - int i, c, errflag; + int index, i, c, errflag; char *p; char buf[BUFSIZE]; char *arglist[MAXARGS]; int lines = 0; - if (!strstr(machdep->cmdline_arg, "=")) { - error(WARNING, "ignoring --machdep option: %s\n\n", - machdep->cmdline_arg); - return; - } - - strcpy(buf, machdep->cmdline_arg); - - for (p = buf; *p; p++) { - if (*p == ',') - *p = ' '; - } + for (index = 0; index < MAX_MACHDEP_ARGS; index++) { - c = parse_line(buf, arglist); - - for (i = 0; i < c; i++) { - errflag = 0; - - if (STRNEQ(arglist[i], "vm=")) { - p = arglist[i] + strlen("vm="); - if (strlen(p)) { - if (STREQ(p, "orig")) { - machdep->flags |= VM_ORIG; - continue; - } else if (STREQ(p, "2.6.14")) { - machdep->flags |= VM_4_LEVEL; - continue; + if (!machdep->cmdline_args[index]) + break; + + if (!strstr(machdep->cmdline_args[index], "=")) { + error(WARNING, "ignoring --machdep option: %s\n\n", + machdep->cmdline_args[index]); + continue; + } + + strcpy(buf, machdep->cmdline_args[index]); + + for (p = buf; *p; p++) { + if (*p == ',') + *p = ' '; + } + + c = parse_line(buf, arglist); + + for (i = 0; i < c; i++) { + errflag = 0; + + if (STRNEQ(arglist[i], "vm=")) { + p = arglist[i] + strlen("vm="); + if (strlen(p)) { + if (STREQ(p, "orig")) { + machdep->flags |= VM_ORIG; + continue; + } else if (STREQ(p, "2.6.14")) { + machdep->flags |= VM_4_LEVEL; + continue; + } } } - } - - error(WARNING, "ignoring --machdep option: %s\n", arglist[i]); - lines++; - } - - switch (machdep->flags & (VM_ORIG|VM_4_LEVEL)) - { - case VM_ORIG: - error(NOTE, "using original PPC64 VM address ranges\n"); - lines++; - break; - - case VM_4_LEVEL: - error(NOTE, "using 4-level pagetable PPC64 VM address ranges\n"); - lines++; - break; - - case (VM_ORIG|VM_4_LEVEL): - error(WARNING, "cannot set both vm=orig and vm=2.6.14\n"); - lines++; - machdep->flags &= ~(VM_ORIG|VM_4_LEVEL); - break; - } - - if (lines) - fprintf(fp, "\n"); + + error(WARNING, "ignoring --machdep option: %s\n", arglist[i]); + lines++; + } + + switch (machdep->flags & (VM_ORIG|VM_4_LEVEL)) + { + case VM_ORIG: + error(NOTE, "using original PPC64 VM address ranges\n"); + lines++; + break; + + case VM_4_LEVEL: + error(NOTE, "using 4-level pagetable PPC64 VM address ranges\n"); + lines++; + break; + + case (VM_ORIG|VM_4_LEVEL): + error(WARNING, "cannot set both vm=orig and vm=2.6.14\n"); + lines++; + machdep->flags &= ~(VM_ORIG|VM_4_LEVEL); + break; + } + + if (lines) + fprintf(fp, "\n"); + } } /* --- crash-4.0-8.8/x86_64.c 2009-04-16 13:18:20.000000000 -0400 +++ crash-4.0-8.9/x86_64.c 2009-04-16 10:43:41.000000000 -0400 @@ -73,7 +73,7 @@ static void x86_64_cpu_pda_init(void); static void x86_64_ist_init(void); static void x86_64_post_init(void); -static void parse_cmdline_arg(void); +static void parse_cmdline_args(void); static void x86_64_clear_machdep_cache(void); static void x86_64_irq_eframe_link_init(void); static int x86_64_xendump_p2m_create(struct xendump_data *); @@ -102,6 +102,8 @@ void x86_64_init(int when) { + int len, dim; + if (XEN_HYPER_MODE()) { x86_64_init_hyper(when); return; @@ -140,8 +142,8 @@ machdep->flags |= MACHDEP_BT_TEXT; machdep->flags |= FRAMESIZE_DEBUG; machdep->machspec->irq_eframe_link = UNINITIALIZED; - if (machdep->cmdline_arg) - parse_cmdline_arg(); + if (machdep->cmdline_args[0]) + parse_cmdline_args(); break; case PRE_GDB: @@ -312,7 +314,23 @@ machdep->hz = 1000; } machdep->section_size_bits = _SECTION_SIZE_BITS; - machdep->max_physmem_bits = _MAX_PHYSMEM_BITS; + if (!machdep->max_physmem_bits) { + if (THIS_KERNEL_VERSION >= LINUX(2,6,26)) + machdep->max_physmem_bits = + _MAX_PHYSMEM_BITS_2_6_26; + else { + machdep->max_physmem_bits = _MAX_PHYSMEM_BITS; + len = get_array_length("mem_section", &dim, 0); + /* + * Check for patched MAX_PHYSMEM_BITS. + */ + if (((len > 32) && !dim) || + ((len > 8192) && (dim == 1))) + machdep->max_physmem_bits = + _MAX_PHYSMEM_BITS_2_6_26; + } + } + if (XEN()) { if (kt->xen_flags & WRITABLE_PAGE_TABLES) { switch (machdep->flags & VM_FLAGS) @@ -461,6 +479,11 @@ fprintf(fp, " section_size_bits: %ld\n", machdep->section_size_bits); fprintf(fp, " max_physmem_bits: %ld\n", machdep->max_physmem_bits); fprintf(fp, " sections_per_root: %ld\n", machdep->sections_per_root); + for (i = 0; i < MAX_MACHDEP_ARGS; i++) { + fprintf(fp, " cmdline_args[%d]: %s\n", + i, machdep->cmdline_args[i] ? + machdep->cmdline_args[i] : "(unused)"); + } fprintf(fp, " machspec: %016lx\n", (ulong)machdep->machspec); fprintf(fp, " userspace_top: %016lx\n", (ulong)ms->userspace_top); @@ -3698,6 +3721,12 @@ "x86_64_get_dumpfile_stack_frame: cannot find anything useful (task: %lx)\n", bt->task); + if (XEN_CORE_DUMPFILE() && !panic_task && is_task_active(bt->task) && + !(bt->flags & (BT_TEXT_SYMBOLS_ALL|BT_TEXT_SYMBOLS))) + error(FATAL, + "starting backtrace locations of the active (non-crashing) " + "xen tasks\n cannot be determined: try -t or -T options\n"); + bt->flags &= ~(ulonglong)BT_DUMPFILE_SEARCH; machdep->get_stack_frame(bt, rip, rsp); @@ -4235,12 +4264,16 @@ * Force the IRQ stack back-link via: * * --machdep irq_eframe_link= + * + * Force max_physmem_bits via: + * + * --machdep max_physmem_bits= */ void -parse_cmdline_arg(void) +parse_cmdline_args(void) { - int i, c, errflag; + int index, i, c, errflag; char *p; char buf[BUFSIZE]; char *arglist[MAXARGS]; @@ -4249,119 +4282,137 @@ int vm_flag; ulong value; - if (!strstr(machdep->cmdline_arg, "=")) { - error(WARNING, "ignoring --machdep option: %s\n\n", - machdep->cmdline_arg); - return; - } - - strcpy(buf, machdep->cmdline_arg); - - for (p = buf; *p; p++) { - if (*p == ',') - *p = ' '; - } - - c = parse_line(buf, arglist); + for (index = 0; index < MAX_MACHDEP_ARGS; index++) { - for (i = vm_flag = 0; i < c; i++) { - errflag = 0; + if (!machdep->cmdline_args[index]) + break; - if (STRNEQ(arglist[i], "vm=")) { - vm_flag++; - p = arglist[i] + strlen("vm="); - if (strlen(p)) { - if (STREQ(p, "orig")) { - machdep->flags |= VM_ORIG; - continue; - } else if (STREQ(p, "2.6.11")) { - machdep->flags |= VM_2_6_11; - continue; - } else if (STREQ(p, "xen")) { - machdep->flags |= VM_XEN; - continue; - } else if (STREQ(p, "xen-rhel4")) { - machdep->flags |= VM_XEN_RHEL4; - continue; + if (!strstr(machdep->cmdline_args[index], "=")) { + error(WARNING, "ignoring --machdep option: %s\n\n", + machdep->cmdline_args[index]); + continue; + } + + strcpy(buf, machdep->cmdline_args[index]); + + for (p = buf; *p; p++) { + if (*p == ',') + *p = ' '; + } + + c = parse_line(buf, arglist); + + for (i = vm_flag = 0; i < c; i++) { + errflag = 0; + + if (STRNEQ(arglist[i], "vm=")) { + vm_flag++; + p = arglist[i] + strlen("vm="); + if (strlen(p)) { + if (STREQ(p, "orig")) { + machdep->flags |= VM_ORIG; + continue; + } else if (STREQ(p, "2.6.11")) { + machdep->flags |= VM_2_6_11; + continue; + } else if (STREQ(p, "xen")) { + machdep->flags |= VM_XEN; + continue; + } else if (STREQ(p, "xen-rhel4")) { + machdep->flags |= VM_XEN_RHEL4; + continue; + } } - } - } else if (STRNEQ(arglist[i], "phys_base=")) { - megabytes = FALSE; - if ((LASTCHAR(arglist[i]) == 'm') || - (LASTCHAR(arglist[i]) == 'M')) { - LASTCHAR(arglist[i]) = NULLCHAR; - megabytes = TRUE; - } - p = arglist[i] + strlen("phys_base="); - if (strlen(p)) { - if (megabytes) { - value = dtol(p, RETURN_ON_ERROR|QUIET, - &errflag); - } else - value = htol(p, RETURN_ON_ERROR|QUIET, - &errflag); - if (!errflag) { - if (megabytes) - value = MEGABYTES(value); - machdep->machspec->phys_base = value; - error(NOTE, - "setting phys_base to: 0x%lx\n\n", - machdep->machspec->phys_base); - machdep->flags |= PHYS_BASE; - continue; - } - } - } else if (STRNEQ(arglist[i], "irq_eframe_link=")) { - p = arglist[i] + strlen("irq_eframe_link="); - if (strlen(p)) { - value = stol(p, RETURN_ON_ERROR|QUIET, &errflag); - if (!errflag) { - machdep->machspec->irq_eframe_link = value; - continue; + } else if (STRNEQ(arglist[i], "phys_base=")) { + megabytes = FALSE; + if ((LASTCHAR(arglist[i]) == 'm') || + (LASTCHAR(arglist[i]) == 'M')) { + LASTCHAR(arglist[i]) = NULLCHAR; + megabytes = TRUE; + } + p = arglist[i] + strlen("phys_base="); + if (strlen(p)) { + if (megabytes) { + value = dtol(p, RETURN_ON_ERROR|QUIET, + &errflag); + } else + value = htol(p, RETURN_ON_ERROR|QUIET, + &errflag); + if (!errflag) { + if (megabytes) + value = MEGABYTES(value); + machdep->machspec->phys_base = value; + error(NOTE, + "setting phys_base to: 0x%lx\n\n", + machdep->machspec->phys_base); + machdep->flags |= PHYS_BASE; + continue; + } + } + } else if (STRNEQ(arglist[i], "irq_eframe_link=")) { + p = arglist[i] + strlen("irq_eframe_link="); + if (strlen(p)) { + value = stol(p, RETURN_ON_ERROR|QUIET, &errflag); + if (!errflag) { + machdep->machspec->irq_eframe_link = value; + continue; + } + } + } else if (STRNEQ(arglist[i], "max_physmem_bits=")) { + p = arglist[i] + strlen("max_physmem_bits="); + if (strlen(p)) { + value = stol(p, RETURN_ON_ERROR|QUIET, &errflag); + if (!errflag) { + machdep->max_physmem_bits = value; + error(NOTE, + "setting max_physmem_bits to: %ld\n\n", + machdep->max_physmem_bits); + continue; + } } } - } - - error(WARNING, "ignoring --machdep option: %s\n", arglist[i]); - lines++; - } - - if (vm_flag) { - switch (machdep->flags & VM_FLAGS) - { - case 0: - break; - case VM_ORIG: - error(NOTE, "using original x86_64 VM address ranges\n"); + error(WARNING, "ignoring --machdep option: %s\n", arglist[i]); lines++; - break; + } - case VM_2_6_11: - error(NOTE, "using 2.6.11 x86_64 VM address ranges\n"); - lines++; - break; + if (vm_flag) { + switch (machdep->flags & VM_FLAGS) + { + case 0: + break; + + case VM_ORIG: + error(NOTE, "using original x86_64 VM address ranges\n"); + lines++; + break; + + case VM_2_6_11: + error(NOTE, "using 2.6.11 x86_64 VM address ranges\n"); + lines++; + break; + + case VM_XEN: + error(NOTE, "using xen x86_64 VM address ranges\n"); + lines++; + break; - case VM_XEN: - error(NOTE, "using xen x86_64 VM address ranges\n"); - lines++; - break; - - case VM_XEN_RHEL4: - error(NOTE, "using RHEL4 xen x86_64 VM address ranges\n"); - lines++; - break; + case VM_XEN_RHEL4: + error(NOTE, "using RHEL4 xen x86_64 VM address ranges\n"); + lines++; + break; + + default: + error(WARNING, "cannot set multiple vm values\n"); + lines++; + machdep->flags &= ~VM_FLAGS; + break; + } + } - default: - error(WARNING, "cannot set multiple vm values\n"); - lines++; - machdep->flags &= ~VM_FLAGS; - break; - } + if (lines) + fprintf(fp, "\n"); } - - if (lines) - fprintf(fp, "\n"); } void @@ -5531,8 +5582,8 @@ machdep->last_ptbl_read = 0; machdep->verify_paddr = generic_verify_paddr; machdep->ptrs_per_pgd = PTRS_PER_PGD; - if (machdep->cmdline_arg) - parse_cmdline_arg(); + if (machdep->cmdline_args[0]) + parse_cmdline_args(); break; case PRE_GDB: --- crash-4.0-8.8/netdump.c 2009-04-16 13:18:20.000000000 -0400 +++ crash-4.0-8.9/netdump.c 2009-04-15 13:26:19.000000000 -0400 @@ -2031,12 +2031,13 @@ void get_netdump_regs_x86(struct bt_info *bt, ulong *eip, ulong *esp) { - int i, search, panic, panic_task; + int i, search, panic, panic_task, altered; char *sym; ulong *up; ulong ipintr_eip, ipintr_esp, ipintr_func; ulong halt_eip, halt_esp; int check_hardirq, check_softirq; + ulong stackbase, stacktop; if (!is_task_active(bt->task)) { machdep->get_stack_frame(bt, eip, esp); @@ -2045,11 +2046,13 @@ panic_task = tt->panic_task == bt->task ? TRUE : FALSE; - ipintr_eip = ipintr_esp = ipintr_func = panic = 0; + ipintr_eip = ipintr_esp = ipintr_func = panic = altered = 0; halt_eip = halt_esp = 0; check_hardirq = check_softirq = tt->flags & IRQSTACKS ? TRUE : FALSE; search = ((bt->flags & BT_TEXT_SYMBOLS) && (tt->flags & TASK_INIT_DONE)) || (machdep->flags & OMIT_FRAME_PTR); + stackbase = bt->stackbase; + stacktop = bt->stacktop; retry: for (i = 0, up = (ulong *)bt->stackbuf; i < LONGS_PER_STACK; i++, up++){ sym = closest_symbol(*up); @@ -2179,6 +2182,7 @@ alter_stackbuf(bt); bt->flags |= BT_HARDIRQ; check_hardirq = FALSE; + altered = TRUE; goto retry; } @@ -2189,12 +2193,25 @@ alter_stackbuf(bt); bt->flags |= BT_SOFTIRQ; check_softirq = FALSE; + altered = TRUE; goto retry; } if (CRASHDEBUG(1)) error(INFO, "get_netdump_regs_x86: cannot find anything useful (task: %lx)\n", bt->task); + + if (altered) { + bt->stackbase = stackbase; + bt->stacktop = stacktop; + alter_stackbuf(bt); + } + + if (XEN_CORE_DUMPFILE() && !panic_task && is_task_active(bt->task) && + !(bt->flags & (BT_TEXT_SYMBOLS_ALL|BT_TEXT_SYMBOLS))) + error(FATAL, + "starting backtrace locations of the active (non-crashing) " + "xen tasks\n cannot be determined: try -t or -T options\n"); machdep->get_stack_frame(bt, eip, esp); } --- crash-4.0-8.8/diskdump.c 2009-04-16 13:18:20.000000000 -0400 +++ crash-4.0-8.9/diskdump.c 2009-04-09 09:29:04.000000000 -0400 @@ -26,6 +26,7 @@ #define BITMAP_SECT_LEN 4096 struct diskdump_data { + char *filename; ulong flags; /* DISKDUMP_LOCAL, plus anything else... */ int dfd; /* dumpfile file descriptor */ FILE *ofp; /* fprintf(dd->ofp, "xxx"); */ @@ -67,6 +68,81 @@ ulong *diskdump_flags = &diskdump_data.flags; +static int __diskdump_memory_dump(FILE *); + +/* For split dumpfile */ +static struct diskdump_data **dd_list = NULL; +static int num_dd = 0; +static int num_dumpfiles = 0; + +int dumpfile_is_split(void) +{ + return KDUMP_SPLIT(); +} + +static void add_diskdump_data(char* name) +{ +#define DDL_SIZE 16 + int i; + int sz = sizeof(void*); + struct diskdump_data *ddp; + + if (dd_list == NULL) { + dd_list = calloc(DDL_SIZE, sz); + num_dd = DDL_SIZE; + } else { + for (i = 0; i < num_dumpfiles; i++) { + ddp = dd_list[i]; + if (same_file(ddp->filename, name)) + error(FATAL, + "split dumpfiles are identical:\n" + " %s\n %s\n", + ddp->filename, name); + if (memcmp(ddp->header, dd->header, + sizeof(struct disk_dump_header))) + error(FATAL, + "split dumpfiles derived from different vmcores:\n" + " %s\n %s\n", + ddp->filename, name); + } + } + + if (num_dumpfiles == num_dd) { + /* expand list */ + struct diskdump_data **tmp; + tmp = calloc(num_dd*2, sz); + memcpy(tmp, dd_list, sz*num_dd); + free(dd_list); + dd_list = tmp; + num_dd *= 2; + } + + dd_list[num_dumpfiles] = dd; + dd->flags |= DUMPFILE_SPLIT; + dd->filename = name; + + if (CRASHDEBUG(1)) + fprintf(fp, "%s: start_pfn=%lu, end_pfn=%lu\n", name, + dd->sub_header_kdump->start_pfn, + dd->sub_header_kdump->end_pfn); +} + +static void clean_diskdump_data(void) +{ + int i; + + if (dd_list == NULL) + return; + + for (i=1; idfd = fd; return TRUE; } @@ -112,6 +192,7 @@ const off_t failed = (off_t)-1; ulong pfn; int i, j, max_sect_len; + int is_split = 0; if (block_size < 0) return FALSE; @@ -266,10 +347,35 @@ goto err; } - max_sect_len = divideup(header->max_mapnr, BITMAP_SECT_LEN); + /* For split dumpfile */ + if (KDUMP_CMPRS_VALID()) { + is_split = ((dd->header->header_version >= 2) && + (sub_header_kdump->split)); + + if ((is_split && (num_dumpfiles != 0) && (dd_list == NULL))|| + (!is_split && (num_dumpfiles != 0))) { + clean_diskdump_data(); + goto err; + } + + if (is_split) + add_diskdump_data(file); + + num_dumpfiles++; + } + + if (!is_split) { + max_sect_len = divideup(header->max_mapnr, BITMAP_SECT_LEN); + pfn = 0; + } + else { + ulong start = sub_header_kdump->start_pfn; + ulong end = sub_header_kdump->end_pfn; + max_sect_len = divideup(end - start + 1, BITMAP_SECT_LEN); + pfn = start; + } dd->valid_pages = calloc(sizeof(ulong), max_sect_len + 1); - pfn = 0; for (i = 1; i < max_sect_len + 1; i++) { dd->valid_pages[i] = dd->valid_pages[i - 1]; for (j = 0; j < BITMAP_SECT_LEN; j++, pfn++) @@ -297,10 +403,20 @@ pfn_to_pos(ulong pfn) { int desc_pos, j, valid; + ulong p1, p2; + + if (KDUMP_SPLIT()) { + p1 = pfn - dd->sub_header_kdump->start_pfn; + p2 = round(p1, BITMAP_SECT_LEN) + dd->sub_header_kdump->start_pfn; + } + else { + p1 = pfn; + p2 = round(pfn, BITMAP_SECT_LEN); + } - valid = dd->valid_pages[pfn / BITMAP_SECT_LEN]; + valid = dd->valid_pages[p1 / BITMAP_SECT_LEN]; - for (j = round(pfn, BITMAP_SECT_LEN), desc_pos = valid; j <= pfn; j++) + for (j = p2, desc_pos = valid; j <= pfn; j++) if (page_is_dumpable(j)) desc_pos++; @@ -335,7 +451,7 @@ DISKDUMP_VALID() ? "diskdump" : "compressed kdump"); if (CRASHDEBUG(1)) - diskdump_memory_dump(fp); + __diskdump_memory_dump(fp); return TRUE; } @@ -495,6 +611,26 @@ ulong pfn, page_offset; pfn = paddr >> dd->block_shift; + + if (KDUMP_SPLIT()) { + /* Find proper dd */ + int i; + unsigned long start_pfn; + unsigned long end_pfn; + + for (i=0; isub_header_kdump->start_pfn; + end_pfn = dd_list[i]->sub_header_kdump->end_pfn; + if ((pfn >= start_pfn) && (pfn <= end_pfn)) { + dd = dd_list[i]; + break; + } + } + + if (i == num_dumpfiles) + return SEEK_ERROR; + } + curpaddr = paddr & ~((physaddr_t)(dd->block_size-1)); page_offset = paddr & ((physaddr_t)(dd->block_size-1)); @@ -619,7 +755,7 @@ * the diskdump header data. */ int -diskdump_memory_dump(FILE *fp) +__diskdump_memory_dump(FILE *fp) { int i, others, dump_level; struct disk_dump_header *dh; @@ -628,6 +764,7 @@ ulong *tasks; fprintf(fp, "diskdump_data: \n"); + fprintf(fp, " filename: %s\n", dd->filename); fprintf(fp, " flags: %lx (", dd->flags); others = 0; if (dd->flags & DISKDUMP_LOCAL) @@ -771,9 +908,14 @@ others++ ? "|" : ""); others = 0; - fprintf(fp, "%s\n\n", dump_level ? ")" : ""); + fprintf(fp, "%s\n", dump_level ? ")" : ""); } else - fprintf(fp, "(unknown)\n\n"); + fprintf(fp, "(unknown)\n"); + if (KDUMP_SPLIT()) { + fprintf(fp, " start_pfn: %lu\n", dd->sub_header_kdump->start_pfn); + fprintf(fp, " end_pfn: %lu\n", dd->sub_header_kdump->end_pfn); + } + fprintf(fp, "\n"); } else fprintf(fp, "(n/a)\n\n"); @@ -816,6 +958,27 @@ } /* + * Wrapper of __diskdump_memory_dump() + */ +int +diskdump_memory_dump(FILE *fp) +{ + int i; + + if (KDUMP_SPLIT() && (dd_list != NULL)) + for (i = 0; i < num_dumpfiles; i++) { + dd = dd_list[i]; + __diskdump_memory_dump(fp); + fprintf(fp, "\n"); + } + else + __diskdump_memory_dump(fp); + + return 0; +} + + +/* * Get the switch_stack address of the passed-in task. */ ulong @@ -856,3 +1019,23 @@ { return (get_dump_level() > 0 ? TRUE : FALSE); } + +/* + * Used by "sys" command to dump multiple split dumpfiles. + */ +void +show_split_dumpfiles(void) +{ + int i; + struct diskdump_data *ddp; + + for (i = 0; i < num_dumpfiles; i++) { + ddp = dd_list[i]; + fprintf(fp, "%s%s %s", + i ? " " : "", + ddp->filename, + is_partial_diskdump() ? "[PARTIAL DUMP]" : ""); + if ((i+1) < num_dumpfiles) + fprintf(fp, "\n"); + } +} --- crash-4.0-8.8/defs.h 2009-04-16 13:18:20.000000000 -0400 +++ crash-4.0-8.9/defs.h 2009-04-09 15:27:30.000000000 -0400 @@ -225,8 +225,10 @@ #define KDUMP_CMPRS_LOCAL (0x2) #define ERROR_EXCLUDED (0x4) #define ZERO_EXCLUDED (0x8) +#define DUMPFILE_SPLIT (0x10) #define DISKDUMP_VALID() (dd->flags & DISKDUMP_LOCAL) #define KDUMP_CMPRS_VALID() (dd->flags & KDUMP_CMPRS_LOCAL) +#define KDUMP_SPLIT() (dd->flags & DUMPFILE_SPLIT) #define XENDUMP_LOCAL (0x1) #define XENDUMP_VALID() (xd->flags & XENDUMP_LOCAL) @@ -718,6 +720,8 @@ struct xendump_data; struct xen_kdump_data; +#define MAX_MACHDEP_ARGS 5 /* for --machdep/-m machine-specific args */ + struct machdep_table { ulong flags; ulong kvbase; @@ -768,7 +772,7 @@ char *pmd; char *ptbl; int ptrs_per_pgd; - char *cmdline_arg; + char *cmdline_args[MAX_MACHDEP_ARGS]; struct machine_specific *machspec; ulong section_size_bits; ulong max_physmem_bits; @@ -2262,8 +2266,9 @@ #define VALID_LEVEL4_PGT_ADDR(X) \ (((X) == VIRTPAGEBASE(X)) && IS_KVADDR(X) && !IS_VMALLOC_ADDR(X)) -#define _SECTION_SIZE_BITS 27 -#define _MAX_PHYSMEM_BITS 40 +#define _SECTION_SIZE_BITS 27 +#define _MAX_PHYSMEM_BITS 40 +#define _MAX_PHYSMEM_BITS_2_6_26 44 #endif /* X86_64 */ @@ -3686,6 +3691,7 @@ #define BT_START (0x2000000000ULL) #define BT_TEXT_SYMBOLS_ALL (0x4000000000ULL) #define BT_XEN_STOP_THIS_CPU (0x8000000000ULL) +#define BT_THREAD_GROUP (0x10000000000ULL) #define BT_REF_HEXVAL (0x1) #define BT_REF_SYMBOL (0x2) @@ -4146,6 +4152,8 @@ int diskdump_phys_base(unsigned long *); ulong *diskdump_flags; int is_partial_diskdump(void); +int dumpfile_is_split(void); +void show_split_dumpfiles(void); /* * xendump.c --- crash-4.0-8.8/diskdump.h 2009-04-16 13:18:20.000000000 -0400 +++ crash-4.0-8.9/diskdump.h 2009-03-25 11:06:57.000000000 -0400 @@ -57,6 +57,9 @@ struct kdump_sub_header { unsigned long phys_base; int dump_level; /* header_version 1 and later */ + int split; /* header_version 2 and later */ + unsigned long start_pfn; /* header_version 2 and later */ + unsigned long end_pfn; /* header_version 2 and later */ }; /* page flags */