--- crash-4.0-8.10/main.c 2009-06-30 11:34:05.000000000 -0400 +++ crash-4.0-8.11/main.c 2009-06-26 11:48:42.000000000 -0400 @@ -416,6 +416,10 @@ pc->readmem = read_xendump; pc->writemem = write_xendump; + } else if (is_system_map(argv[optind])) { + pc->system_map = argv[optind]; + pc->flags |= (SYSMAP|SYSMAP_ARG); + } else if (is_diskdump(argv[optind])) { if ((pc->flags & MEMORY_SOURCES) && (!dumpfile_is_split())) { @@ -439,10 +443,6 @@ pc->readmem = read_lkcd_dumpfile; pc->writemem = write_lkcd_dumpfile; - } else if (is_system_map(argv[optind])) { - pc->system_map = argv[optind]; - pc->flags |= (SYSMAP|SYSMAP_ARG); - } else if (is_mclx_compressed_dump(argv[optind])) { if (pc->flags & MEMORY_SOURCES) { error(INFO, --- crash-4.0-8.10/tools.c 2009-06-30 11:34:05.000000000 -0400 +++ crash-4.0-8.11/tools.c 2009-06-17 11:15:52.000000000 -0400 @@ -41,6 +41,7 @@ { int end_of_line, new_line; char buf[BUFSIZE]; + char *spacebuf; ulong retaddr[NUMBER_STACKFRAMES] = { 0 }; va_list ap; @@ -66,26 +67,36 @@ else if (pc->flags & PLEASE_WAIT) new_line = TRUE; + if (type == CONT) + spacebuf = space(strlen(pc->curcmd)); + if (pc->stdpipe) { - fprintf(pc->stdpipe, "%s%s: %s%s", - new_line ? "\n" : "", pc->curcmd, + fprintf(pc->stdpipe, "%s%s%s %s%s", + new_line ? "\n" : "", + type == CONT ? spacebuf : pc->curcmd, + type == CONT ? " " : ":", type == WARNING ? "WARNING: " : type == NOTE ? "NOTE: " : "", buf); fflush(pc->stdpipe); } else { - fprintf(stdout, "%s%s: %s%s", + fprintf(stdout, "%s%s%s %s%s", new_line || end_of_line ? "\n" : "", type == WARNING ? "WARNING" : - type == NOTE ? "NOTE" : pc->curcmd, + type == NOTE ? "NOTE" : + type == CONT ? spacebuf : pc->curcmd, + type == CONT ? " " : ":", buf, end_of_line ? "\n" : ""); fflush(stdout); } if ((fp != stdout) && (fp != pc->stdpipe)) { - fprintf(fp, "%s%s: %s", new_line ? "\n" : "", + fprintf(fp, "%s%s%s %s", new_line ? "\n" : "", type == WARNING ? "WARNING" : - type == NOTE ? "NOTE" : pc->curcmd, buf); + type == NOTE ? "NOTE" : + type == CONT ? spacebuf : pc->curcmd, + type == CONT ? " " : ":", + buf); fflush(fp); } @@ -1663,11 +1674,9 @@ void cmd_set(void) { - int i; - int c; + int i, c; ulong value; - int cpu; - int runtime; + int cpu, runtime; char buf[BUFSIZE]; char *extra_message; struct task_context *tc; @@ -1675,7 +1684,7 @@ extra_message = NULL; runtime = pc->flags & RUNTIME; - while ((c = getopt(argcnt, args, "pvc:")) != EOF) { + while ((c = getopt(argcnt, args, "pvc:a:")) != EOF) { switch(c) { case 'c': @@ -1722,6 +1731,44 @@ show_options(); return; + case 'a': + if (XEN_HYPER_MODE()) + option_not_supported(c); + + if (!runtime) + return; + + if (ACTIVE()) + error(FATAL, + "-a option not allowed on live systems\n"); + + switch (str_to_context(optarg, &value, &tc)) + { + case STR_PID: + if ((i = TASKS_PER_PID(value)) > 1) + error(FATAL, + "pid %d has %d tasks: " + "use a task address\n", + value, i); + break; + + case STR_TASK: + break; + + case STR_INVALID: + error(FATAL, "invalid task or pid value: %s\n", + optarg); + } + + cpu = tc->processor; + tt->active_set[cpu] = tc->task; + if (tt->panic_threads[cpu]) + tt->panic_threads[cpu] = tc->task; + fprintf(fp, + "\"%s\" task %lx has been marked as the active task on cpu %d\n", + tc->comm, tc->task, cpu); + return; + default: argerrs++; break; --- crash-4.0-8.10/memory.c 2009-06-30 11:34:05.000000000 -0400 +++ crash-4.0-8.11/memory.c 2009-06-30 10:50:01.000000000 -0400 @@ -180,12 +180,13 @@ static int get_kmem_cache_list(ulong **); static int get_kmem_cache_slub_data(long, struct meminfo *); static ulong compound_head(ulong); -static long count_partial(ulong); +static long count_partial(ulong, struct meminfo *); static ulong get_freepointer(struct meminfo *, void *); static int count_free_objects(struct meminfo *, ulong); char *is_slab_page(struct meminfo *, char *); static void do_node_lists_slub(struct meminfo *, ulong, int); static void check_devmem_is_allowed(void); +static int verify_pfn(ulong); /* * Memory display modes specific to this file. @@ -7370,6 +7371,7 @@ if (vt->flags & KMALLOC_SLUB) { kmem_cache_init_slub(); + please_wait_done(); return; } @@ -11856,6 +11858,9 @@ node_start_mapnr = node_start_pfn; node_start_paddr = PTOB(node_start_pfn); if (badaddr && IS_SPARSEMEM()) { + if (!verify_pfn(node_start_pfn)) + error(WARNING, "questionable node_start_pfn: %lx\n", + node_start_pfn); phys = PTOB(node_start_pfn); if (phys_to_page(phys, &pp)) node_mem_map = pp; @@ -12137,6 +12142,28 @@ dump_mem_sections(); } +/* + * At least verify that page-shifted physical address. + */ +static int +verify_pfn(ulong pfn) +{ + int i; + physaddr_t mask; + + if (!machdep->max_physmem_bits) + return TRUE; + + mask = 0; + for (i = machdep->max_physmem_bits; i < machdep->bits; i++) + mask |= ((physaddr_t)1 << i); + + if (mask & BTOP(pfn)) + return FALSE; + + return TRUE; +} + static void dump_zone_stats(void) { @@ -12741,6 +12768,14 @@ ulong addr; ulong *mem_sec = vt->mem_sec; + if (IS_SPARSEMEM_EX()) { + if (SECTION_NR_TO_ROOT(nr) >= NR_SECTION_ROOTS()) { + error(WARNING, + "sparsemem: invalid section number: %ld\n", nr); + return 0; + } + } + if ((mem_sec[SECTION_NR_TO_ROOT(nr)] == 0) || !IS_KVADDR(mem_sec[SECTION_NR_TO_ROOT(nr)])) return 0; @@ -12863,7 +12898,7 @@ mkstring(buf2, VADDR_PRLEN, CENTER|LJUST, "CODED_MEM_MAP"), mkstring(buf3, VADDR_PRLEN, CENTER|LJUST, "MEM_MAP")); - for (nr = 0; nr <= nr_mem_sections ; nr++) { + for (nr = 0; nr < nr_mem_sections ; nr++) { if ((addr = valid_section_nr(nr))) { coded_mem_map = section_mem_map_addr(addr); mem_map = sparse_decode_mem_map(coded_mem_map,nr); @@ -13742,7 +13777,7 @@ switch (cmd) { case GET_SLUB_OBJECTS: - if ((p = count_partial(node_ptr)) < 0) + if ((p = count_partial(node_ptr, si)) < 0) return FALSE; total_objects += p; break; @@ -14055,6 +14090,12 @@ if (!readmem(next, KVADDR, &next, sizeof(ulong), "page.lru.next", RETURN_ON_ERROR)) return; + + if (!IS_KVADDR(next)) { + error(INFO, "%s: partial list: page.lru.next: %lx\n", + si->curname, next); + return; + } } #define SLAB_STORE_USER (0x00010000UL) @@ -14086,6 +14127,12 @@ if (!readmem(next, KVADDR, &next, sizeof(ulong), "page.lru.next", RETURN_ON_ERROR)) return; + + if (!IS_KVADDR(next)) { + error(INFO, "%s: full list: page.lru.next: %lx\n", + si->curname, next); + return; + } } } @@ -14210,7 +14257,7 @@ } long -count_partial(ulong node) +count_partial(ulong node, struct meminfo *si) { ulong list_head, next; short inuse; @@ -14223,13 +14270,23 @@ return -1; while (next != list_head) { - if (!readmem(next - OFFSET(page_lru) + OFFSET(page_inuse), KVADDR, &inuse, - sizeof(ushort), "page.inuse", RETURN_ON_ERROR)) + if (!readmem(next - OFFSET(page_lru) + OFFSET(page_inuse), + KVADDR, &inuse, sizeof(ushort), "page.inuse", RETURN_ON_ERROR)) return -1; + if (inuse == -1) { + error(INFO, "%s: partial list: page.inuse: -1\n", + si->curname); + break; + } total_inuse += inuse; if (!readmem(next, KVADDR, &next, sizeof(ulong), "page.lru.next", RETURN_ON_ERROR)) return -1; + if (!IS_KVADDR(next)) { + error(INFO, "%s: partial list: page.lru.next: %lx\n", + si->curname, next); + break; + } } return total_inuse; } --- crash-4.0-8.10/help.c 2009-06-30 11:34:05.000000000 -0400 +++ crash-4.0-8.11/help.c 2009-06-24 15:53:46.000000000 -0400 @@ -641,11 +641,12 @@ char *help_set[] = { "set", "set a process context or internal %s variable", -"[pid | taskp | [-c cpu] | -p] | [%s_variable [setting]] | -v", +"[[-a] [pid | taskp] | [-c cpu] | -p] | [%s_variable [setting]] | -v", " This command either sets a new context, or gets the current context for", " display. The context can be set by the use of:\n", " pid a process PID.", " taskp a hexadecimal task_struct pointer.", +" -a sets the pid or task as the active task on its cpu (dumpfiles only).", " -c cpu sets the context to the active task on a cpu (dumpfiles only).", " -p sets the context to the panic task, or back to the %s task on", " a live system.", @@ -1773,18 +1774,23 @@ "runq", "run queue", " ", -" This command displays the tasks on the run queue.", +" This command displays the tasks on the run queues of each cpu.", "\nEXAMPLES", " %s> runq", -" PID: 435 TASK: c322c000 CPU: 1 COMMAND: \"httpd\"", -" PID: 253 TASK: c6580000 CPU: 0 COMMAND: \"portmap\"", -" PID: 5655 TASK: c0a86000 CPU: 1 COMMAND: \"nfsd\"", -" PID: 3 TASK: c0fa0000 CPU: 1 COMMAND: \"kflushd\"", -" PID: 318 TASK: c6734000 CPU: 1 COMMAND: \"syslogd\"", -" PID: 5657 TASK: c129e000 CPU: 1 COMMAND: \"nfsd\"", -" PID: 5653 TASK: c0d26000 CPU: 1 COMMAND: \"nfsd\"", -" PID: 329 TASK: c4138000 CPU: 1 COMMAND: \"klogd\"", -" PID: 2 TASK: c03dc000 CPU: 0 COMMAND: \"kswapd\"", +" CPU 0 RUNQUEUE: ffff880001cdb460", +" CURRENT: PID: 2739 TASK: ffff8800320fa7e0 COMMAND: \"bash\"", +" ACTIVE PRIO_ARRAY: ffff880001cdb4d8", +" [115] PID: 2739 TASK: ffff8800320fa7e0 COMMAND: \"bash\"", +" PID: 1776 TASK: ffff88003217d820 COMMAND: \"syslogd\"", +" EXPIRED PRIO_ARRAY: ffff880001cdbdb8", +" [no tasks queued]", +" ", +" CPU 1 RUNQUEUE: ffff880001ce3460", +" CURRENT: PID: 1779 TASK: ffff88003207a860 COMMAND: \"klogd\"", +" ACTIVE PRIO_ARRAY: ffff880001ce34d8", +" [115] PID: 1779 TASK: ffff88003207a860 COMMAND: \"klogd\"", +" EXPIRED PRIO_ARRAY: ffff880001ce3db8", +" [no tasks queued]", NULL }; @@ -1864,31 +1870,57 @@ "dev", "device data", "[-i | -p]", -" If no argument is entered, this command dumps the contents of the chrdevs", -" and blkdevs arrays.\n", +" If no argument is entered, this command dumps character and block", +" device data.\n", " -i display I/O port usage; on 2.4 kernels, also display I/O memory usage.", " -p display PCI device data.", "\nEXAMPLES", -" Display the chrdevs and blkdevs array contents:\n", +" Display character and block device data:\n", " %s> dev", -" CHRDEV NAME OPERATIONS", -" 1 mem c02c9580 ", -" 2 pty c02c9280 ", -" 3 ttyp c02c9280 ", -" 4 ttyS c02c9280 ", -" 5 cua c02c9280 ", -" 7 vcs c02ca940 ", -" 10 misc c02c5480 ", -" 128 ptm c02c9280 ", -" 136 pts c02c9280 ", -" 162 raw c02ca880 ", -" ", -" BLKDEV NAME OPERATIONS", -" 2 fd c02c4fc0 ", -" 8 sd c02cec80 ", -" 22 ide1 c02c4274 ", -" 65 sd c02cec80 ", -" 66 sd c02cec80 ", +" CHRDEV NAME CDEV OPERATIONS", +" 1 mem f79b83c0 memory_fops", +" 4 /dev/vc/0 c07bc560 console_fops", +" 4 tty f7af5004 tty_fops", +" 4 ttyS f7b02204 tty_fops", +" 5 /dev/tty c07bc440 tty_fops", +" 5 /dev/console c07bc4a0 console_fops", +" 5 /dev/ptmx c07bc500 ptmx_fops", +" 6 lp c5797e40 lp_fops", +" 7 vcs f7b03d40 vcs_fops", +" 10 misc f7f68640 misc_fops", +" 13 input f79b8840 input_fops", +" 21 sg f7f12840 sg_fops", +" 29 fb f7f8c640 fb_fops", +" 128 ptm f7b02604 tty_fops", +" 136 pts f7b02404 tty_fops", +" 162 raw c0693e40 raw_fops", +" 180 usb f79b8bc0 usb_fops", +" 189 usb_device c06a0300 usbfs_device_file_operations", +" 216 rfcomm f5961a04 tty_fops", +" 254 pcmcia f79b82c0 ds_fops", +" ", +" BLKDEV NAME GENDISK OPERATIONS", +" 1 ramdisk f7b23480 rd_bd_op", +" 8 sd f7cab280 sd_fops", +" 9 md f7829b80 md_fops", +" 11 sr f75c24c0 sr_bdops", +" 65 sd (none) ", +" 66 sd (none) ", +" 67 sd (none) ", +" 68 sd (none) ", +" 69 sd (none) ", +" 70 sd (none) ", +" 71 sd (none) ", +" 128 sd (none) ", +" 129 sd (none) ", +" 130 sd (none) ", +" 131 sd (none) ", +" 132 sd (none) ", +" 133 sd (none) ", +" 134 sd (none) ", +" 135 sd (none) ", +" 253 device-mapper c57a0ac0 dm_blk_dops", +" 254 mdp (none) ", "\n Display PCI data:\n", " %s> dev -p", --- crash-4.0-8.10/task.c 2009-06-30 11:34:05.000000000 -0400 +++ crash-4.0-8.11/task.c 2009-06-24 10:32:06.000000000 -0400 @@ -452,6 +452,8 @@ tt->this_task = pid_to_task(active_pid); } else { + if (KDUMP_DUMPFILE()) + map_cpus_to_prstatus(); please_wait("determining panic task"); set_context(get_panic_context(), NO_PID); please_wait_done(); @@ -6139,7 +6141,8 @@ return FALSE; - if (!(tt->active_set = (ulong *)calloc(NR_CPUS, sizeof(ulong)))) + if (!tt->active_set && + !(tt->active_set = (ulong *)calloc(NR_CPUS, sizeof(ulong)))) error(FATAL, "cannot malloc active_set array"); runqbuf = GETBUF(SIZE(runqueue)); @@ -6568,6 +6571,7 @@ ulong runq, offset; char *runqbuf; ulong active, expired, arrays; + struct task_context *tc; int per_cpu; @@ -6579,6 +6583,7 @@ per_cpu = TRUE; } + get_active_set(); runqbuf = GETBUF(SIZE(runqueue)); for (cpu = 0; cpu < kt->cpus; cpu++, runq += SIZE(runqueue)) { @@ -6590,7 +6595,15 @@ runq = symbol_value("per_cpu__runqueues"); } - fprintf(fp, "RUNQUEUES[%d]: %lx\n", cpu, runq); + fprintf(fp, "%sCPU %d RUNQUEUE: %lx\n", cpu ? "\n" : "", + cpu, runq); + + fprintf(fp, " CURRENT: "); + if ((tc = task_to_context(tt->active_set[cpu]))) + fprintf(fp, "PID: %-5ld TASK: %lx COMMAND: \"%s\"\n", + tc->pid, tc->task, tc->comm); + else + fprintf(fp, "%lx\n", tt->active_set[cpu]); readmem(runq, KVADDR, runqbuf, SIZE(runqueue), "runqueues array entry", FAULT_ON_ERROR); @@ -6617,7 +6630,7 @@ static void dump_prio_array(int which, ulong k_prio_array, char *u_prio_array) { - int i, c, cnt, qheads, nr_active; + int i, c, cnt, tot, qheads, nr_active; ulong offset, kvaddr, uvaddr; ulong list_head[2]; struct list_data list_data, *ld; @@ -6633,20 +6646,25 @@ nr_active = INT(u_prio_array + OFFSET(prio_array_nr_active)); console("nr_active: %d\n", nr_active); - fprintf(fp, " %s PRIO_ARRAY: %lx\n", + fprintf(fp, " %s PRIO_ARRAY: %lx\n", which == RUNQ_ACTIVE ? "ACTIVE" : "EXPIRED", k_prio_array); + if (CRASHDEBUG(1)) + fprintf(fp, "nr_active: %d\n", nr_active); + ld = &list_data; - for (i = 0; i < 140; i++) { + for (i = tot = 0; i < 140; i++) { offset = OFFSET(prio_array_queue) + (i * SIZE(list_head)); kvaddr = k_prio_array + offset; uvaddr = (ulong)u_prio_array + offset; BCOPY((char *)uvaddr, (char *)&list_head[0], sizeof(ulong)*2); if (CRASHDEBUG(1)) - fprintf(fp, "prio_array[%d] @ %lx => %lx/%lx\n", - i, kvaddr, list_head[0], list_head[1]); + fprintf(fp, "prio_array[%d] @ %lx => %lx/%lx %s\n", + i, kvaddr, list_head[0], list_head[1], + (list_head[0] == list_head[1]) && + (list_head[0] == kvaddr) ? "(empty)" : ""); if ((list_head[0] == kvaddr) && (list_head[1] == kvaddr)) continue; @@ -6654,7 +6672,7 @@ console("[%d] %lx => %lx-%lx ", i, kvaddr, list_head[0], list_head[1]); - fprintf(fp, " [%3d] ", i); + fprintf(fp, " [%3d] ", i); BZERO(ld, sizeof(struct list_data)); ld->start = list_head[0]; @@ -6670,11 +6688,18 @@ if (!(tc = task_to_context(tlist[c]))) continue; if (c) - INDENT(8); - print_task_header(fp, tc, FALSE); + INDENT(11); + fprintf(fp, "PID: %-5ld TASK: %lx COMMAND: \"%s\"\n", + tc->pid, tc->task, tc->comm); } + tot += cnt; FREEBUF(tlist); } + + if (!tot) { + INDENT(5); + fprintf(fp, "[no tasks queued]\n"); + } } /* @@ -6767,7 +6792,7 @@ static void dump_CFS_runqueues(void) { - int cpu; + int tot, prio, cpu; ulong runq, cfs_rq; char *runqbuf, *cfs_rq_buf; ulong leftmost, tasks_timeline; @@ -6790,6 +6815,8 @@ MEMBER_OFFSET_INIT(rt_rq_active, "rt_rq", "active"); MEMBER_OFFSET_INIT(task_struct_run_list, "task_struct", "run_list"); + MEMBER_OFFSET_INIT(task_struct_prio, "task_struct", + "prio"); } if (!symbol_exists("per_cpu__runqueues")) @@ -6801,6 +6828,8 @@ cfs_rq_buf = symbol_exists("per_cpu__init_cfs_rq") ? GETBUF(SIZE(cfs_rq)) : NULL; + get_active_set(); + for (cpu = 0; cpu < kt->cpus; cpu++) { if ((kt->flags & SMP) && (kt->flags & PER_CPU_OFF)) { runq = symbol_value("per_cpu__runqueues") + @@ -6808,7 +6837,16 @@ } else runq = symbol_value("per_cpu__runqueues"); - fprintf(fp, "RUNQUEUES[%d]: %lx\n", cpu, runq); + fprintf(fp, "%sCPU %d RUNQUEUE: %lx\n", cpu ? "\n" : "", + cpu, runq); + + fprintf(fp, " CURRENT: "); + if ((tc = task_to_context(tt->active_set[cpu]))) + fprintf(fp, "PID: %-5ld TASK: %lx COMMAND: \"%s\"\n", + tc->pid, tc->task, tc->comm); + else + fprintf(fp, "%lx\n", tt->active_set[cpu]); + readmem(runq, KVADDR, runqbuf, SIZE(runqueue), "per-cpu rq", FAULT_ON_ERROR); @@ -6848,18 +6886,25 @@ runq + OFFSET(rq_rt) + OFFSET(rt_rq_active), &runqbuf[OFFSET(rq_rt) + OFFSET(rt_rq_active)]); - fprintf(fp, " CFS RB_ROOT: %lx\n", (ulong)root); - - if (!leftmost) - continue; + fprintf(fp, " CFS RB_ROOT: %lx\n", (ulong)root); - for (node = rb_first(root); node; node = rb_next(node)) { + for (node = rb_first(root), tot = 0; leftmost && node; + node = rb_next(node)) { tc = task_to_context((ulong)node - OFFSET(task_struct_se) - OFFSET(sched_entity_run_node)); if (!tc) continue; - INDENT(2); - print_task_header(fp, tc, FALSE); + readmem(tc->task + OFFSET(task_struct_prio), KVADDR, + &prio, sizeof(int), "task prio", FAULT_ON_ERROR); + fprintf(fp, " [%3d] ", prio); + fprintf(fp, "PID: %-5ld TASK: %lx COMMAND: \"%s\"\n", + tc->pid, tc->task, tc->comm); + tot++; + } + + if (!tot) { + INDENT(5); + fprintf(fp, "[no tasks queued]\n"); } } @@ -6871,24 +6916,27 @@ static void dump_RT_prio_array(int active, ulong k_prio_array, char *u_prio_array) { - int i, c, cnt, qheads; + int i, c, tot, cnt, qheads; ulong offset, kvaddr, uvaddr; ulong list_head[2]; struct list_data list_data, *ld; struct task_context *tc; ulong *tlist; - fprintf(fp, " RT PRIO_ARRAY: %lx\n", k_prio_array); + fprintf(fp, " RT PRIO_ARRAY: %lx\n", k_prio_array); - if (!active) + if (!active) { + INDENT(5); + fprintf(fp, "[no tasks queued]\n"); return; + } qheads = (i = ARRAY_LENGTH(prio_array_queue)) ? i : get_array_length("prio_array.queue", NULL, SIZE(list_head)); ld = &list_data; - for (i = 0; i < qheads; i++) { + for (i = tot = 0; i < qheads; i++) { offset = OFFSET(prio_array_queue) + (i * SIZE(list_head)); kvaddr = k_prio_array + offset; uvaddr = (ulong)u_prio_array + offset; @@ -6901,7 +6949,7 @@ if ((list_head[0] == kvaddr) && (list_head[1] == kvaddr)) continue; - fprintf(fp, " [%3d] ", i); + fprintf(fp, " [%3d] ", i); BZERO(ld, sizeof(struct list_data)); ld->start = list_head[0]; @@ -6916,11 +6964,18 @@ if (!(tc = task_to_context(tlist[c]))) continue; if (c) - INDENT(8); - print_task_header(fp, tc, FALSE); + INDENT(11); + fprintf(fp, "PID: %-5ld TASK: %lx COMMAND: \"%s\"\n", + tc->pid, tc->task, tc->comm); + tot++; } FREEBUF(tlist); } + + if (!tot) { + INDENT(5); + fprintf(fp, "[no tasks queued]\n"); + } } #undef _NSIG --- crash-4.0-8.10/kernel.c 2009-06-30 11:34:05.000000000 -0400 +++ crash-4.0-8.11/kernel.c 2009-06-26 13:49:52.000000000 -0400 @@ -463,7 +463,26 @@ "char_device_struct", "fops"); MEMBER_OFFSET_INIT(char_device_struct_major, "char_device_struct", "major"); - } + MEMBER_OFFSET_INIT(char_device_struct_baseminor, + "char_device_struct", "baseminor"); + MEMBER_OFFSET_INIT(char_device_struct_cdev, + "char_device_struct", "cdev"); + } + + STRUCT_SIZE_INIT(cdev, "cdev"); + if (VALID_STRUCT(cdev)) + MEMBER_OFFSET_INIT(cdev_ops, "cdev", "ops"); + + STRUCT_SIZE_INIT(probe, "probe"); + if (VALID_STRUCT(probe)) { + MEMBER_OFFSET_INIT(probe_next, "probe", "next"); + MEMBER_OFFSET_INIT(probe_dev, "probe", "dev"); + MEMBER_OFFSET_INIT(probe_data, "probe", "data"); + } + + STRUCT_SIZE_INIT(kobj_map, "kobj_map"); + if (VALID_STRUCT(kobj_map)) + MEMBER_OFFSET_INIT(kobj_map_probes, "kobj_map", "probes"); MEMBER_OFFSET_INIT(module_kallsyms_start, "module", "kallsyms_start"); @@ -2171,6 +2190,17 @@ return; } + if (ACTIVE() && !INSTACK(esp, bt)) { + sprintf(buf, "/proc/%ld", bt->tc->pid); + if (!file_exists(buf, NULL)) + error(INFO, "task no longer exists\n"); + else + error(INFO, + "invalid/stale stack pointer for this task: %lx\n", + esp); + return; + } + if (bt->flags & (BT_TEXT_SYMBOLS|BT_TEXT_SYMBOLS_PRINT|BT_TEXT_SYMBOLS_NOPRINT)) { @@ -2513,7 +2543,7 @@ module_init(void) { int i, c; - ulong mod, mod_next; + ulong size, mod, mod_next; uint nsyms; ulong total, numksyms; char *modbuf, *kallsymsbuf; @@ -2681,10 +2711,27 @@ break; case KALLSYMS_V2: - if (THIS_KERNEL_VERSION >= LINUX(2,6,27)) + if (THIS_KERNEL_VERSION >= LINUX(2,6,27)) { numksyms = UINT(modbuf + OFFSET(module_num_symtab)); - else + size = UINT(modbuf + OFFSET(module_core_size)); + } else { numksyms = ULONG(modbuf + OFFSET(module_num_symtab)); + size = ULONG(modbuf + OFFSET(module_core_size)); + } + + if (!size) { + /* + * Bail out here instead of a crashing with a + * getbuf(0) failure during storage later on. + */ + error(WARNING, + "invalid kernel module size: 0\n"); + kt->mods_installed = 0; + kt->flags |= NO_MODULE_ACCESS; + FREEBUF(modbuf); + return; + } + total += numksyms; break; } --- crash-4.0-8.10/dev.c 2009-06-30 11:34:05.000000000 -0400 +++ crash-4.0-8.11/dev.c 2009-06-15 16:30:29.000000000 -0400 @@ -20,6 +20,9 @@ static void dump_blkdevs(ulong); static void dump_chrdevs(ulong); static void dump_blkdevs_v2(ulong); +static void dump_blkdevs_v3(ulong); +static ulong search_cdev_map_probes(char *, int, int, ulong *); +static ulong search_bdev_map_probes(char *, int, int, ulong *); static void do_pci(void); static void do_io(void); static void do_resource_list(ulong, char *, int); @@ -111,15 +114,19 @@ if (argerrs) cmd_usage(pc->curcmd, SYNOPSIS); - if (argcnt == 1) { - dump_chrdevs(flags); - fprintf(fp, "\n"); - dump_blkdevs(flags); - } + dump_chrdevs(flags); + fprintf(fp, "\n"); + dump_blkdevs(flags); } #define MAX_DEV (255) +#define MINORBITS 20 +#define MINORMASK ((1U << MINORBITS) - 1) + +#define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS)) +#define MINOR(dev) ((unsigned int) ((dev) & MINORMASK)) + char *chrdev_hdr = "CHRDEV NAME "; char *blkdev_hdr = "BLKDEV NAME "; @@ -139,8 +146,8 @@ } chrdevs[MAX_DEV], *cp; ulong *cdp; char *char_device_struct_buf; - ulong next, savenext, name, fops; - int major; + ulong next, savenext, name, fops, cdev; + int major, minor; int name_typecode; size_t name_size; @@ -154,8 +161,9 @@ readmem(addr, KVADDR, &chrdevs[0], size * MAX_DEV, "chrdevs array", FAULT_ON_ERROR); - fprintf(fp, "%s%s\n", chrdev_hdr, - mkstring(buf, VADDR_PRLEN, CENTER, "OPERATIONS")); + fprintf(fp, "%s %s", chrdev_hdr, VADDR_PRLEN == 8 ? " " : ""); + fprintf(fp, "%s ", mkstring(buf, VADDR_PRLEN, CENTER, "CDEV")); + fprintf(fp, "%s\n", mkstring(buf, VADDR_PRLEN, LJUST, "OPERATIONS")); if (VALID_STRUCT(char_device_struct)) goto char_device_struct; @@ -217,33 +225,54 @@ break; } - fops = ULONG(char_device_struct_buf + - OFFSET(char_device_struct_fops)); major = INT(char_device_struct_buf + OFFSET(char_device_struct_major)); + minor = INT(char_device_struct_buf + + OFFSET(char_device_struct_baseminor)); + + cdev = fops = 0; + if (VALID_MEMBER(char_device_struct_cdev) && + VALID_STRUCT(cdev)) { + cdev = ULONG(char_device_struct_buf + + OFFSET(char_device_struct_cdev)); + if (cdev) { + addr = cdev + OFFSET(cdev_ops); + readmem(addr, KVADDR, &fops, + sizeof(void *), + "cdev ops", FAULT_ON_ERROR); + } + } else { + fops = ULONG(char_device_struct_buf + + OFFSET(char_device_struct_fops)); + } + + if (!fops) + fops = search_cdev_map_probes(buf, major, minor, &cdev); - fprintf(fp, " %3d ", major); - fprintf(fp, "%-12s ", buf); if (!fops) { - sprintf(buf2, "%s%%%ds ", - strlen("OPERATIONS") < VADDR_PRLEN ? " " : " ", - VADDR_PRLEN); - fprintf(fp, buf2, "(none)"); + fprintf(fp, " %3d ", major); + fprintf(fp, "%-13s ", buf); + fprintf(fp, "%s%s\n", VADDR_PRLEN == 8 ? " " : " ", + mkstring(buf, VADDR_PRLEN, CENTER, "(none)")); } else { - sprintf(buf2, "%s%%%dlx ", - strlen("OPERATIONS") < VADDR_PRLEN ? " " : " ", - VADDR_PRLEN); - fprintf(fp, buf2, fops); - value_to_symstr(fops, buf2, 0); - if (strlen(buf2)) - fprintf(fp, "<%s>", buf2); + fprintf(fp, " %3d ", major); + fprintf(fp, "%-13s ", buf); + sprintf(buf2, "%s%%%dlx ", + strlen("OPERATIONS") < VADDR_PRLEN ? " " : " ", + VADDR_PRLEN); + fprintf(fp, buf2, cdev); + value_to_symstr(fops, buf2, 0); + if (strlen(buf2)) + fprintf(fp, "%s", buf2); + else + fprintf(fp, "%lx", fops); + fprintf(fp, "\n"); } - fprintf(fp, "\n"); if (CRASHDEBUG(1)) fprintf(fp, - "%lx: major: %d name: %s next: %lx fops: %lx\n", - *cdp, major, buf, next, fops); + "%lx: major: %d minor: %d name: %s next: %lx cdev: %lx fops: %lx\n", + *cdp, major, minor, buf, next, cdev, fops); while (next) { readmem(savenext = next, KVADDR, char_device_struct_buf, @@ -267,39 +296,113 @@ break; } - fops = ULONG(char_device_struct_buf + - OFFSET(char_device_struct_fops)); major = INT(char_device_struct_buf + OFFSET(char_device_struct_major)); + minor = INT(char_device_struct_buf + + OFFSET(char_device_struct_baseminor)); + + fops = cdev = 0; + if (VALID_MEMBER(char_device_struct_cdev) && + VALID_STRUCT(cdev)) { + cdev = ULONG(char_device_struct_buf + + OFFSET(char_device_struct_cdev)); + if (cdev) { + addr = cdev + OFFSET(cdev_ops); + readmem(addr, KVADDR, &fops, + sizeof(void *), + "cdev ops", FAULT_ON_ERROR); + } + } else { + fops = ULONG(char_device_struct_buf + + OFFSET(char_device_struct_fops)); + } + + if (!fops) + fops = search_cdev_map_probes(buf, major, minor, &cdev); - fprintf(fp, " %3d ", major); - fprintf(fp, "%-12s ", buf); if (!fops) { - sprintf(buf2, "%s%%%ds ", - strlen("OPERATIONS") < VADDR_PRLEN ? - " " : " ", VADDR_PRLEN); - fprintf(fp, buf2, "(none)"); + fprintf(fp, " %3d ", major); + fprintf(fp, "%-13s ", buf); + fprintf(fp, "%s%s\n", VADDR_PRLEN == 8 ? " " : " ", + mkstring(buf, VADDR_PRLEN, CENTER, "(none)")); } else { - sprintf(buf2, "%s%%%dlx ", - strlen("OPERATIONS") < VADDR_PRLEN ? + fprintf(fp, " %3d ", major); + fprintf(fp, "%-13s ", buf); + sprintf(buf2, "%s%%%dlx ", + strlen("OPERATIONS") < VADDR_PRLEN ? " " : " ", VADDR_PRLEN); - fprintf(fp, buf2, fops); - value_to_symstr(fops, buf2, 0); - if (strlen(buf2)) - fprintf(fp, "<%s>", buf2); + fprintf(fp, buf2, cdev); + value_to_symstr(fops, buf2, 0); + if (strlen(buf2)) + fprintf(fp, "%s", buf2); + else + fprintf(fp, "%lx", fops); + fprintf(fp, "\n"); } - fprintf(fp, "\n"); if (CRASHDEBUG(1)) fprintf(fp, - "%lx: major: %d name: %s next: %lx fops: %lx\n", - savenext, major, buf, next, fops); + "%lx: major: %d minor: %d name: %s next: %lx cdev: %lx fops: %lx\n", + savenext, major, minor, buf, next, cdev, fops); } } FREEBUF(char_device_struct_buf); } +/* + * Search for a major/minor match by following the list headed + * by the kobj_map.probes[major] array entry. The "data" member + * points to a cdev structure containing the file_operations + * pointer. + */ +static ulong +search_cdev_map_probes(char *name, int major, int minor, ulong *cdev) +{ + char *probe_buf; + ulong probes[MAX_DEV]; + ulong cdev_map, addr, next, ops, probe_data; + uint probe_dev; + + if (kernel_symbol_exists("cdev_map")) + get_symbol_data("cdev_map", sizeof(ulong), &cdev_map); + else + return 0; + + addr = cdev_map + OFFSET(kobj_map_probes); + if (!readmem(addr, KVADDR, &probes[0], sizeof(void *) * MAX_DEV, + "cdev_map.probes[]", QUIET|RETURN_ON_ERROR)) + return 0; + + ops = 0; + probe_buf = GETBUF(SIZE(probe)); + next = probes[major]; + + while (next) { + if (!readmem(next, KVADDR, probe_buf, SIZE(probe), + "struct probe", QUIET|RETURN_ON_ERROR)) + break; + + probe_dev = UINT(probe_buf + OFFSET(probe_dev)); + + if ((MAJOR(probe_dev) == major) && + (MINOR(probe_dev) == minor)) { + probe_data = ULONG(probe_buf + OFFSET(probe_data)); + addr = probe_data + OFFSET(cdev_ops); + if (!readmem(addr, KVADDR, &ops, sizeof(void *), + "cdev ops", QUIET|RETURN_ON_ERROR)) + ops = 0; + else + *cdev = probe_data; + break; + } + + next = ULONG(probe_buf + OFFSET(probe_next)); + } + + FREEBUF(probe_buf); + return ops; +} /* * Dump the block device data. @@ -315,6 +418,12 @@ ulong ops; } blkdevs[MAX_DEV], *bp; + if (kernel_symbol_exists("major_names") && + kernel_symbol_exists("bdev_map")) { + dump_blkdevs_v3(flags); + return; + } + if (symbol_exists("all_bdevs")) { dump_blkdevs_v2(flags); return; @@ -524,6 +633,128 @@ FREEBUF(blk_major_name_buf); } +static void +dump_blkdevs_v3(ulong flags) +{ + int i, len; + ulong blk_major_name; + char *blk_major_name_buf; + char buf[BUFSIZE]; + uint major; + ulong gendisk, addr, next, fops; + + if (!(len = get_array_length("major_names", NULL, 0))) + len = MAX_DEV; + + fprintf(fp, "%s %s", blkdev_hdr, VADDR_PRLEN == 8 ? " " : ""); + fprintf(fp, "%s ", mkstring(buf, VADDR_PRLEN, CENTER|RJUST, "GENDISK")); + fprintf(fp, "%s\n", mkstring(buf, VADDR_PRLEN, LJUST, "OPERATIONS")); + + blk_major_name_buf = GETBUF(SIZE(blk_major_name)); + + for (i = 0; i < len; i++) { + addr = symbol_value("major_names") + (i * sizeof(void *)); + readmem(addr, KVADDR, &blk_major_name, sizeof(void *), + "major_names[] entry", FAULT_ON_ERROR); + + if (!blk_major_name) + continue; + + readmem(blk_major_name, KVADDR, blk_major_name_buf, + SIZE(blk_major_name), "blk_major_name", FAULT_ON_ERROR); + + major = UINT(blk_major_name_buf + + OFFSET(blk_major_name_major)); + buf[0] = NULLCHAR; + strncpy(buf, blk_major_name_buf + + OFFSET(blk_major_name_name), 16); + next = ULONG(blk_major_name_buf + + OFFSET(blk_major_name_next)); + + fops = search_bdev_map_probes(buf, major == i ? major : i, + UNUSED, &gendisk); + + if (CRASHDEBUG(1)) + fprintf(fp, "blk_major_name: %lx block major: %d name: %s gendisk: %lx fops: %lx\n", + blk_major_name, major, buf, gendisk, fops); + + if (!fops) { + fprintf(fp, " %3d ", major); + fprintf(fp, "%-13s ", + strlen(buf) ? buf : "(unknown)"); + fprintf(fp, "%s%s\n", VADDR_PRLEN == 8 ? " " : " ", + mkstring(buf, VADDR_PRLEN, CENTER, "(none)")); + continue; + } + + fprintf(fp, " %3d ", major); + fprintf(fp, "%-13s ", strlen(buf) ? buf : "(unknown)"); + sprintf(buf, "%s%%%dlx ", + strlen("OPERATIONS") < VADDR_PRLEN ? " " : " ", + VADDR_PRLEN); + fprintf(fp, buf, gendisk); + value_to_symstr(fops, buf, 0); + if (strlen(buf)) + fprintf(fp, "%s", buf); + else + fprintf(fp, "%lx", fops); + fprintf(fp, "\n"); + } +} + +static ulong +search_bdev_map_probes(char *name, int major, int minor, ulong *gendisk) +{ + char *probe_buf, *gendisk_buf; + ulong probes[MAX_DEV]; + ulong bdev_map, addr, next, probe_data, fops; + uint probe_dev; + + get_symbol_data("bdev_map", sizeof(ulong), &bdev_map); + + addr = bdev_map + OFFSET(kobj_map_probes); + if (!readmem(addr, KVADDR, &probes[0], sizeof(void *) * MAX_DEV, + "bdev_map.probes[]", QUIET|RETURN_ON_ERROR)) + return 0; + + probe_buf = GETBUF(SIZE(probe)); + gendisk_buf = GETBUF(SIZE(gendisk)); + + fops = 0; + + for (next = probes[major]; next; + next = ULONG(probe_buf + OFFSET(probe_next))) { + + if (!readmem(next, KVADDR, probe_buf, SIZE(probe), + "struct probe", QUIET|RETURN_ON_ERROR)) + break; + + probe_data = ULONG(probe_buf + OFFSET(probe_data)); + if (!probe_data) + continue; + + probe_dev = UINT(probe_buf + OFFSET(probe_dev)); + if (MAJOR(probe_dev) != major) + continue; + + if (!readmem(probe_data, KVADDR, gendisk_buf, + SIZE(gendisk), "gendisk buffer", + QUIET|RETURN_ON_ERROR)) + break; + + fops = ULONG(gendisk_buf + OFFSET(gendisk_fops)); + + if (fops) { + *gendisk = probe_data; + break; + } + } + + FREEBUF(probe_buf); + FREEBUF(gendisk_buf); + return fops; +} + void dump_dev_table(void) { --- crash-4.0-8.10/ppc64.c 2009-06-30 11:34:05.000000000 -0400 +++ crash-4.0-8.11/ppc64.c 2009-06-11 11:53:07.000000000 -0400 @@ -1847,10 +1847,13 @@ ulong task; struct ppc64_pt_regs regs; + ip = 0; task = bt->task; stack = (ulong *)bt->stackbuf; sp = ppc64_get_sp(task); + if (!INSTACK(sp, bt)) + goto out; readmem(sp+STACK_FRAME_OVERHEAD, KVADDR, ®s, sizeof(struct ppc64_pt_regs), "PPC64 pt_regs", FAULT_ON_ERROR); @@ -1865,9 +1868,14 @@ * Need to skip 2 frames. */ sp = stack[(sp - bt->stackbase)/sizeof(ulong)]; + if (!INSTACK(sp, bt)) + goto out; sp = stack[(sp - bt->stackbase)/sizeof(ulong)]; + if (!INSTACK(sp+16, bt)) + goto out; ip = stack[(sp + 16 - bt->stackbase)/sizeof(ulong)]; } +out: *getsp = sp; *getpc = ip; } @@ -2407,13 +2415,16 @@ if (!symbol_exists("paca")) error(FATAL, "PPC64: Could not find 'paca' symbol\n"); - if (cpu_map_addr("present")) + if (cpu_map_addr("possible")) + map = POSSIBLE; + else if (cpu_map_addr("present")) map = PRESENT; else if (cpu_map_addr("online")) map = ONLINE; else - error(FATAL, - "PPC64: cannot find 'cpu_present_map' or 'cpu_online_map' symbols\n"); + error(FATAL, + "PPC64: cannot find 'cpu_possible_map' or\ + 'cpu_present_map' or 'cpu_online_map' symbols\n"); if (!MEMBER_EXISTS("paca_struct", "data_offset")) return; @@ -2423,8 +2434,8 @@ cpu_paca_buf = GETBUF(SIZE(ppc64_paca)); - if (!(nr_paca = get_array_length("paca", NULL, 0))) - nr_paca = NR_CPUS; + if (!(nr_paca = get_array_length("paca", NULL, 0))) + nr_paca = (kt->kernel_NR_CPUS ? kt->kernel_NR_CPUS : NR_CPUS); if (nr_paca > NR_CPUS) { error(WARNING, @@ -2435,7 +2446,7 @@ for (i = cpus = 0; i < nr_paca; i++) { /* - * CPU present (or online)? + * CPU present or online or can exist in the system(possible)? */ if (!in_cpu_map(map, i)) continue; --- crash-4.0-8.10/x86_64.c 2009-06-30 11:34:05.000000000 -0400 +++ crash-4.0-8.11/x86_64.c 2009-06-30 08:57:16.000000000 -0400 @@ -93,6 +93,7 @@ static int x86_64_framesize_cache_func(int, ulong, int *); static int x86_64_get_framesize(struct bt_info *, ulong); static void x86_64_framesize_debug(struct bt_info *); +static void x86_64_get_active_set(void); struct machine_specific x86_64_machine_specific = { 0 }; @@ -254,6 +255,22 @@ break; case POST_GDB: + if (THIS_KERNEL_VERSION >= LINUX(2,6,26) && + THIS_KERNEL_VERSION < LINUX(2,6,31)) { + machdep->machspec->vmalloc_start_addr = VMALLOC_START_ADDR_2_6_26; + } + if (THIS_KERNEL_VERSION >= LINUX(2,6,27) && + THIS_KERNEL_VERSION < LINUX(2,6,31)) { + machdep->machspec->modules_end = MODULES_END_2_6_27; + } + if (THIS_KERNEL_VERSION >= LINUX(2,6,31)) { + machdep->machspec->vmalloc_start_addr = VMALLOC_START_ADDR_2_6_31; + machdep->machspec->vmalloc_end = VMALLOC_END_2_6_31; + machdep->machspec->vmemmap_vaddr = VMEMMAP_VADDR_2_6_31; + machdep->machspec->vmemmap_end = VMEMMAP_END_2_6_31; + machdep->machspec->modules_vaddr = MODULES_VADDR_2_6_31; + machdep->machspec->modules_end = MODULES_END_2_6_31; + } STRUCT_SIZE_INIT(cpuinfo_x86, "cpuinfo_x86"); STRUCT_SIZE_INIT(gate_struct, "gate_struct"); STRUCT_SIZE_INIT(e820map, "e820map"); @@ -319,7 +336,10 @@ } machdep->section_size_bits = _SECTION_SIZE_BITS; if (!machdep->max_physmem_bits) { - if (THIS_KERNEL_VERSION >= LINUX(2,6,26)) + if (THIS_KERNEL_VERSION >= LINUX(2,6,31)) + machdep->max_physmem_bits = + _MAX_PHYSMEM_BITS_2_6_31; + else if (THIS_KERNEL_VERSION >= LINUX(2,6,26)) machdep->max_physmem_bits = _MAX_PHYSMEM_BITS_2_6_26; else { @@ -364,6 +384,7 @@ case POST_INIT: x86_64_post_init(); + x86_64_get_active_set(); break; } } @@ -537,6 +558,32 @@ fprintf(fp, " rsp: %ld\n", ms->pto.rsp); fprintf(fp, " ss: %ld\n", ms->pto.ss); } + +#define CPU_SPACES(C) \ + ((C) < 10 ? 3 : (C) < 100 ? 2 : (C) < 1000 ? 1 : 0) + + fprintf(fp, "%s current[%d]:%s", + space(CPU_SPACES(kt->cpus)), kt->cpus, + ms->current ? "\n " : " (unused)\n"); + for (c = 0; ms->current && (c < kt->cpus); c++) { + if (c && !(c%4)) + fprintf(fp, "\n "); + fprintf(fp, "%016lx ", ms->current[c]); + } + if (ms->current) + fprintf(fp, "\n"); + + fprintf(fp, "%s crash_nmi_rsp[%d]:%s", + space(CPU_SPACES(kt->cpus)), kt->cpus, + ms->crash_nmi_rsp ? "\n " : " (unused)\n"); + for (c = 0; ms->crash_nmi_rsp && (c < kt->cpus); c++) { + if (c && !(c%4)) + fprintf(fp, "\n "); + fprintf(fp, "%016lx ", ms->crash_nmi_rsp[c]); + } + if (ms->crash_nmi_rsp) + fprintf(fp, "\n"); + fprintf(fp, " stkinfo: esize: %d%sisize: %d\n", ms->stkinfo.esize, machdep->flags & NO_TSS ? " (NO TSS) " : " ", @@ -610,6 +657,12 @@ else _boot_cpu_pda = FALSE; } + + if (DUMPFILE() && + !(machdep->machspec->current = calloc(nr_pda, sizeof(ulong)))) + error(FATAL, "cannot calloc %d x86_64 current pointers!\n", + nr_pda); + for (i = cpus = 0; i < nr_pda; i++) { if (_cpu_pda) { if (_boot_cpu_pda) { @@ -644,10 +697,16 @@ machdep->machspec->stkinfo.ibase[i] = ULONG(cpu_pda_buf + OFFSET(x8664_pda_irqstackptr)); + if (DUMPFILE()) + machdep->machspec->current[i] = ULONG(cpu_pda_buf + + OFFSET(x8664_pda_pcurrent)); if (CRASHDEBUG(2)) - fprintf(fp, "CPU%d: level4_pgt: %lx data_offset: %lx\n", - i, level4_pgt, data_offset); + fprintf(fp, + "CPU%d: level4_pgt: %lx " + "data_offset: %lx pcurrent: %lx\n", + i, level4_pgt, data_offset, + DUMPFILE() ? machdep->machspec->current[i] : 0); } if (!LKCD_KERNTYPES() && @@ -708,6 +767,7 @@ x86_64_per_cpu_init(void) { int i, cpus, cpunumber; + struct machine_specific *ms; if (!(kt->flags & PER_CPU_OFF)) return; @@ -716,6 +776,8 @@ !symbol_exists("per_cpu__irq_stack_union")) return; + ms = machdep->machspec; + for (i = cpus = 0; i < NR_CPUS; i++) { readmem(symbol_value("per_cpu__cpu_number") + kt->__per_cpu_offset[i], @@ -726,14 +788,14 @@ break; cpus++; - machdep->machspec->stkinfo.ibase[i] = + ms->stkinfo.ibase[i] = symbol_value("per_cpu__irq_stack_union") + kt->__per_cpu_offset[i]; } - if ((machdep->machspec->stkinfo.isize = + if ((ms->stkinfo.isize = MEMBER_SIZE("irq_stack_union", "irq_stack")) <= 0) - machdep->machspec->stkinfo.isize = 16384; + ms->stkinfo.isize = 16384; if (CRASHDEBUG(2)) fprintf(fp, "x86_64_per_cpu_init: " @@ -747,6 +809,19 @@ else kt->cpus = cpus; + if (DUMPFILE() && symbol_exists("per_cpu__current_task")) { + if ((ms->current = calloc(kt->cpus, sizeof(ulong))) == NULL) + error(FATAL, + "cannot calloc %d x86_64 current pointers!\n", + kt->cpus); + for (i = 0; i < kt->cpus; i++) + if (!readmem(symbol_value("per_cpu__current_task") + + kt->__per_cpu_offset[i], KVADDR, + &ms->current[i], sizeof(ulong), + "current_task (per_cpu)", RETURN_ON_ERROR)) + continue; + } + verify_spinlock(); } @@ -854,8 +929,13 @@ * Check whether each cpu was stopped by an NMI. */ ms = machdep->machspec; + + if (DUMPFILE() && + (ms->crash_nmi_rsp = calloc(kt->cpus, sizeof(ulong))) == NULL) + error(FATAL, "cannot calloc %d x86_64 NMI rsp values\n", + kt->cpus); - for (c = 0; c < kt->cpus; c++) { + for (c = 0; DUMPFILE() && (c < kt->cpus); c++) { if (ms->stkinfo.ebase[c][NMI_STACK] == 0) break; @@ -883,6 +963,12 @@ if (spc && STREQ(spc->name, "die_nmi")) clues += 2; } + + if (STREQ(spt->name, "crash_nmi_callback")) { + up = (ulong *)(&ms->irqstack[ms->stkinfo.esize]); + up -= 2; + ms->crash_nmi_rsp[c] = *up; + } } if (clues >= 2) @@ -2013,6 +2099,9 @@ if (rsp < bt->frameptr) return; + if (!INSTACK(rsp, bt) || !INSTACK(bt->frameptr, bt)) + return; + words = (rsp - bt->frameptr) / sizeof(ulong) + 1; addr = bt->frameptr; @@ -2358,7 +2447,7 @@ #define STACK_TRANSITION_ERRMSG_E_I_P \ "cannot transition from exception stack to IRQ stack to current process stack:\n exception stack pointer: %lx\n IRQ stack pointer: %lx\n process stack pointer: %lx\n current stack base: %lx\n" #define STACK_TRANSITION_ERRMSG_E_P \ -"cannot transition from exception stack to current process stack:\n exception stack pointer: %lx\n process stack pointer: %lx\n current_stack_base: %lx\n" +"cannot transition from exception stack to current process stack:\n exception stack pointer: %lx\n process stack pointer: %lx\n current stack base: %lx\n" #define STACK_TRANSITION_ERRMSG_I_P \ "cannot transition from IRQ stack to current process stack:\n IRQ stack pointer: %lx\n process stack pointer: %lx\n current stack base: %lx\n" @@ -4558,7 +4647,8 @@ if (STREQ(link_register, "%rbp")) machdep->machspec->irq_eframe_link = 40; - + else if (THIS_KERNEL_VERSION >= LINUX(2,6,29)) + machdep->machspec->irq_eframe_link = 40; } #include "netdump.h" @@ -6020,4 +6110,65 @@ break; } } + +static void +x86_64_get_active_set(void) +{ + int c; + ulong current; + struct task_context *actctx, *curctx; + struct machine_specific *ms; + + if (ACTIVE()) + return; + + if (CRASHDEBUG(1)) + fprintf(fp, "x86_64_get_active_set: runqueue vs. %s\n", + VALID_STRUCT(x8664_pda) ? "x8664_pda" : "current_task"); + + ms = machdep->machspec; + + for (c = 0; c < kt->cpus; c++) { + + if (!tt->active_set[c]) + continue; + + current = ms->current[c]; + curctx = task_to_context(current); + actctx = task_to_context(tt->active_set[c]); + + if (CRASHDEBUG(1)) + fprintf(fp, " [%d]: %016lx %016lx %s%s\n", + c, tt->active_set[c], current, + curctx ? "" : "(invalid task)", + curctx && (curctx->processor != c) ? + "(wrong processor)" : ""); + + if (!curctx || (curctx->processor != c)) + continue; + + if (tt->active_set[c] == current) + continue; + + if (tt->active_set[c] == tt->panic_task) + continue; + + if (stkptr_to_task(ms->crash_nmi_rsp[c]) == curctx->task) + tt->active_set[c] = tt->panic_threads[c] = current; + + error(INFO, + "inconsistent active task indications for CPU %d:\n", c); + error(CONT, + " %srunqueue: %lx \"%s\" (default)\n", + VALID_STRUCT(x8664_pda) ? "" : " ", + actctx->task, actctx->comm); + error(CONT, + "%s: %lx \"%s\" %s\n%s", + VALID_STRUCT(x8664_pda) ? " x8664_pda" : "current_task", + current, curctx->comm, + tt->active_set[c] == current ? "(reassigned)" : "", + CRASHDEBUG(1) ? "" : "\n"); + } +} + #endif /* X86_64 */ --- crash-4.0-8.10/symbols.c 2009-06-30 11:34:05.000000000 -0400 +++ crash-4.0-8.11/symbols.c 2009-06-26 09:58:01.000000000 -0400 @@ -6020,6 +6020,8 @@ OFFSET(task_struct_nsproxy)); fprintf(fp, " task_struct_rlim: %ld\n", OFFSET(task_struct_rlim)); + fprintf(fp, " task_struct_prio: %ld\n", + OFFSET(task_struct_prio)); fprintf(fp, " thread_info_task: %ld\n", OFFSET(thread_info_task)); @@ -7024,6 +7026,21 @@ OFFSET(char_device_struct_fops)); fprintf(fp, " char_device_struct_major: %ld\n", OFFSET(char_device_struct_major)); + fprintf(fp, " char_device_struct_baseminor: %ld\n", + OFFSET(char_device_struct_baseminor)); + fprintf(fp, " char_device_struct_cdev: %ld\n", + OFFSET(char_device_struct_cdev)); + + fprintf(fp, " cdev_ops: %ld\n", OFFSET(cdev_ops)); + + fprintf(fp, " probe_next: %ld\n", + OFFSET(probe_next)); + fprintf(fp, " probe_dev: %ld\n", + OFFSET(probe_dev)); + fprintf(fp, " probe_data: %ld\n", + OFFSET(probe_data)); + fprintf(fp, " kobj_map_probes: %ld\n", + OFFSET(kobj_map_probes)); fprintf(fp, " blk_major_name_next: %ld\n", OFFSET(blk_major_name_next)); @@ -7266,6 +7283,12 @@ SIZE(pcpu_info)); fprintf(fp, " vcpu_struct: %ld\n", SIZE(vcpu_struct)); + fprintf(fp, " cdev: %ld\n", + SIZE(cdev)); + fprintf(fp, " probe: %ld\n", + SIZE(probe)); + fprintf(fp, " kobj_map: %ld\n", + SIZE(kobj_map)); fprintf(fp, "\n array_table:\n"); /* --- crash-4.0-8.10/netdump.c 2009-06-30 11:34:05.000000000 -0400 +++ crash-4.0-8.11/netdump.c 2009-06-09 15:56:10.000000000 -0400 @@ -45,6 +45,46 @@ (machine_type("IA64") || machine_type("PPC64")) /* + * kdump installs NT_PRSTATUS elf notes only to the cpus + * that were online during dumping. Hence we call into + * this function after reading the cpu map from the kernel, + * to remap the NT_PRSTATUS notes only to the online cpus. + */ +void +map_cpus_to_prstatus(void) +{ + void **nt_ptr; + int online, i, j, nrcpus; + size_t size; + + if (!(online = get_cpus_online()) || (online == kt->cpus)) + return; + + if (CRASHDEBUG(1)) + error(INFO, + "cpus: %d online: %d NT_PRSTATUS notes: %d (remapping)\n", + kt->cpus, online, nd->num_prstatus_notes); + + size = NR_CPUS * sizeof(void *); + + nt_ptr = (void **)GETBUF(size); + BCOPY(nd->nt_prstatus_percpu, nt_ptr, size); + BZERO(nd->nt_prstatus_percpu, size); + + /* + * Re-populate the array with the notes mapping to online cpus + */ + nrcpus = (kt->kernel_NR_CPUS ? kt->kernel_NR_CPUS : NR_CPUS); + + for (i = 0, j = 0; i < nrcpus; i++) { + if (in_cpu_map(ONLINE, i)) + nd->nt_prstatus_percpu[i] = nt_ptr[j++]; + } + + FREEBUF(nt_ptr); +} + +/* * Determine whether a file is a netdump/diskdump/kdump creation, * and if TRUE, initialize the vmcore_data structure. */ @@ -618,7 +658,7 @@ crashing_cpu = -1; if (kernel_symbol_exists("crashing_cpu")) { get_symbol_data("crashing_cpu", sizeof(int), &i); - if ((i >= 0) && (i < nd->num_prstatus_notes)) { + if ((i >= 0) && in_cpu_map(ONLINE, i)) { crashing_cpu = i; if (CRASHDEBUG(1)) error(INFO, @@ -2236,7 +2276,7 @@ * CPUs if they responded to an IPI. */ if (nd->num_prstatus_notes > 1) { - if (bt->tc->processor >= nd->num_prstatus_notes) + if (!nd->nt_prstatus_percpu[bt->tc->processor]) error(FATAL, "cannot determine NT_PRSTATUS ELF note " "for %s task: %lx\n", --- crash-4.0-8.10/defs.h 2009-06-30 11:34:05.000000000 -0400 +++ crash-4.0-8.11/defs.h 2009-06-30 11:11:58.000000000 -0400 @@ -260,6 +260,7 @@ #define FATAL_RESTART (3) #define WARNING (4) #define NOTE (5) +#define CONT (6) #define FATAL_ERROR(x) (((x) == FATAL) || ((x) == FATAL_RESTART)) #define CONSOLE_OFF(x) ((x) = console_off()) @@ -1466,6 +1467,14 @@ long sched_info_last_arrival; long page_objects; long kmem_cache_oo; + long char_device_struct_cdev; + long char_device_struct_baseminor; + long cdev_ops; + long probe_next; + long probe_dev; + long probe_data; + long kobj_map_probes; + long task_struct_prio; }; struct size_table { /* stash of commonly-used sizes */ @@ -1571,6 +1580,9 @@ long cfs_rq; long pcpu_info; long vcpu_struct; + long cdev; + long probe; + long kobj_map; }; struct array_table { @@ -2141,7 +2153,10 @@ #define VMEMMAP_VADDR_2_6_24 0xffffe20000000000 #define VMEMMAP_END_2_6_24 0xffffe2ffffffffff +#define VMALLOC_START_ADDR_2_6_26 0xffffffffa0000000 + #define PAGE_OFFSET_2_6_27 0xffff880000000000 +#define MODULES_END_2_6_27 0xffffffffff000000 #define USERSPACE_TOP_XEN 0x0000800000000000 #define PAGE_OFFSET_XEN 0xffff880000000000 @@ -2157,6 +2172,13 @@ #define MODULES_VADDR_XEN_RHEL4 0xffffffffa0000000 #define MODULES_END_XEN_RHEL4 0xffffffffafffffff +#define VMALLOC_START_ADDR_2_6_31 0xffffc90000000000 +#define VMALLOC_END_2_6_31 0xffffe8ffffffffff +#define VMEMMAP_VADDR_2_6_31 0xffffea0000000000 +#define VMEMMAP_END_2_6_31 0xffffeaffffffffff +#define MODULES_VADDR_2_6_31 0xffffffffa0000000 +#define MODULES_END_2_6_31 0xffffffffff000000 + #define PTOV(X) ((unsigned long)(X)+(machdep->kvbase)) #define VTOP(X) x86_64_VTOP((ulong)(X)) #define IS_VMALLOC_ADDR(X) x86_64_IS_VMALLOC_ADDR((ulong)(X)) @@ -2243,29 +2265,29 @@ #define _CPU_PDA_READ2(CPU, BUFFER) \ ((readmem(symbol_value("_cpu_pda"), \ KVADDR, &cpu_pda_addr, sizeof(unsigned long), \ - "_cpu_pda addr", FAULT_ON_ERROR)) && \ + "_cpu_pda addr", RETURN_ON_ERROR)) && \ (readmem(cpu_pda_addr + ((CPU) * sizeof(void *)), \ KVADDR, &cpu_pda_addr, sizeof(unsigned long), \ - "_cpu_pda addr", FAULT_ON_ERROR)) && \ + "_cpu_pda addr", RETURN_ON_ERROR)) && \ (cpu_pda_addr) && \ (readmem(cpu_pda_addr, KVADDR, (BUFFER), SIZE(x8664_pda), \ - "cpu_pda entry", FAULT_ON_ERROR))) + "cpu_pda entry", RETURN_ON_ERROR))) #define _CPU_PDA_READ(CPU, BUFFER) \ ((STRNEQ("_cpu_pda", closest_symbol((symbol_value("_cpu_pda") + \ ((CPU) * sizeof(unsigned long)))))) && \ (readmem(symbol_value("_cpu_pda") + ((CPU) * sizeof(void *)), \ KVADDR, &cpu_pda_addr, sizeof(unsigned long), \ - "_cpu_pda addr", FAULT_ON_ERROR)) && \ + "_cpu_pda addr", RETURN_ON_ERROR)) && \ (readmem(cpu_pda_addr, KVADDR, (BUFFER), SIZE(x8664_pda), \ - "cpu_pda entry", FAULT_ON_ERROR))) + "cpu_pda entry", RETURN_ON_ERROR))) #define CPU_PDA_READ(CPU, BUFFER) \ (STRNEQ("cpu_pda", closest_symbol((symbol_value("cpu_pda") + \ ((CPU) * SIZE(x8664_pda))))) && \ readmem(symbol_value("cpu_pda") + ((CPU) * SIZE(x8664_pda)), \ KVADDR, (BUFFER), SIZE(x8664_pda), "cpu_pda entry", \ - FAULT_ON_ERROR)) + RETURN_ON_ERROR)) #define VALID_LEVEL4_PGT_ADDR(X) \ (((X) == VIRTPAGEBASE(X)) && IS_KVADDR(X) && !IS_VMALLOC_ADDR(X)) @@ -2273,6 +2295,7 @@ #define _SECTION_SIZE_BITS 27 #define _MAX_PHYSMEM_BITS 40 #define _MAX_PHYSMEM_BITS_2_6_26 44 +#define _MAX_PHYSMEM_BITS_2_6_31 46 #endif /* X86_64 */ @@ -3852,6 +3875,8 @@ ulong irq_eframe_link; struct x86_64_pt_regs_offsets pto; struct x86_64_stkinfo stkinfo; + ulong *current; + ulong *crash_nmi_rsp; }; #define KSYMS_START (0x1) @@ -4141,6 +4166,7 @@ int xen_minor_version(void); int get_netdump_arch(void); void *get_regs_from_elf_notes(struct task_context *); +void map_cpus_to_prstatus(void); /* * diskdump.c --- crash-4.0-8.10/lkcd_dump_v8.h 2009-06-30 11:34:05.000000000 -0400 +++ crash-4.0-8.11/lkcd_dump_v8.h 2009-06-10 14:10:04.000000000 -0400 @@ -445,9 +445,9 @@ */ typedef struct dump_CPU_info_s { struct pt_regs dha_smp_regs; - uint64_t dha_smp_current_task; - uint64_t dha_stack; - uint64_t dha_stack_ptr; + uint32_t dha_smp_current_task; + uint32_t dha_stack; + uint32_t dha_stack_ptr; } __attribute__ ((packed)) dump_CPU_info_t; --- crash-4.0-8.10/Makefile 2009-06-30 11:34:18.000000000 -0400 +++ crash-4.0-8.11/Makefile 2009-06-30 11:34:17.000000000 -0400 @@ -480,7 +480,7 @@ show_files: @if [ -f ${PROGRAM} ]; then \ - ./${PROGRAM} --no_scroll --no_crashrc -h README > README; echo $?; fi + ./${PROGRAM} --no_scroll --no_crashrc -h README > README; fi @echo ${SOURCE_FILES} Makefile ${GDB_FILES} ${GDB_PATCH_FILES} COPYING README \ .rh_rpm_package crash.8 ${EXTENSION_SOURCE_FILES} --- crash-4.0-8.10/gdb-6.1/gdb/dwarf2read.c 2009-06-30 11:34:05.000000000 -0400 +++ crash-4.0-8.11/gdb-6.1/gdb/dwarf2read.c 2009-06-24 16:12:47.000000000 -0400 @@ -1210,7 +1210,7 @@ cu.objfile = objfile; info_ptr = read_comp_unit_head (&cu.header, info_ptr, abfd); - if (cu.header.version != 2) + if (cu.header.version != 2 && cu.header.version != 3) { error ("Dwarf Error: wrong version in compilation unit header (is %d, should be %d) [in module %s]", cu.header.version, 2, bfd_get_filename (abfd)); return;