commit b4af1d9b48998186aef8cd9abc47c6d59e36114e Author: Dave Anderson Date: Tue Dec 2 17:26:40 2014 -0500 Fix for finding the starting stack and instruction pointer hooks for the active tasks in x86_64 ELF or compressed dumpfiles created by the KVM "virsh dump --memory-only" facility. Without the patch, the backtraces of active tasks may show an invalid starting frame that indicates "__schedule". The fix displays the exception RIP and dumps the register contents that are stored in the dumpfile header. If the active task was operating in the kernel, the backtrace continues from there; if the task was operating in user-space, the backtrace is complete at that point. (anderson@redhat.com) diff --git a/defs.h b/defs.h index 2e52bc4..dc2d65a 100644 --- a/defs.h +++ b/defs.h @@ -5547,6 +5547,7 @@ int write_proc_kcore(int, void *, int, ulong, physaddr_t); int kcore_memory_dump(FILE *); void dump_registers_for_qemu_mem_dump(void); void kdump_backup_region_init(void); +void display_regs_from_elf_notes(int, FILE *); /* * ramdump.c diff --git a/diskdump.c b/diskdump.c index 3d33fdc..6b2aab5 100644 --- a/diskdump.c +++ b/diskdump.c @@ -102,6 +102,9 @@ map_cpus_to_prstatus_kdump_cmprs(void) int online, i, j, nrcpus; size_t size; + if (pc->flags2 & QEMU_MEM_DUMP_COMPRESSED) /* notes exist for all cpus */ + return; + if (!(online = get_cpus_online()) || (online == kt->cpus)) return; diff --git a/netdump.c b/netdump.c index 903faa0..6029a54 100644 --- a/netdump.c +++ b/netdump.c @@ -72,6 +72,9 @@ map_cpus_to_prstatus(void) int online, i, j, nrcpus; size_t size; + if (pc->flags2 & QEMU_MEM_DUMP_ELF) /* notes exist for all cpus */ + return; + if (!(online = get_cpus_online()) || (online == kt->cpus)) return; @@ -2398,8 +2401,8 @@ get_regs_from_note(char *note, ulong *ip, ulong *sp) return user_regs; } -static void -display_regs_from_elf_notes(int cpu) +void +display_regs_from_elf_notes(int cpu, FILE *ofp) { Elf32_Nhdr *note32; Elf64_Nhdr *note64; @@ -2408,13 +2411,16 @@ display_regs_from_elf_notes(int cpu) int c, skipped_count; /* - * NT_PRSTATUS notes are only related to online cpus, offline cpus - * should be skipped. + * Kdump NT_PRSTATUS notes are only related to online cpus, + * so offline cpus should be skipped. */ - skipped_count = 0; - for (c = 0; c < cpu; c++) { - if (check_offline_cpu(c)) - skipped_count++; + if (pc->flags2 & QEMU_MEM_DUMP_ELF) + skipped_count = 0; + else { + for (c = skipped_count = 0; c < cpu; c++) { + if (check_offline_cpu(c)) + skipped_count++; + } } if ((cpu - skipped_count) >= nd->num_prstatus_notes) { @@ -2433,7 +2439,7 @@ display_regs_from_elf_notes(int cpu) len = roundup(len + note64->n_descsz, 4); user_regs = ((char *)note64) + len - SIZE(user_regs_struct) - sizeof(long); - fprintf(fp, + fprintf(ofp, " RIP: %016llx RSP: %016llx RFLAGS: %08llx\n" " RAX: %016llx RBX: %016llx RCX: %016llx\n" " RDX: %016llx RSI: %016llx RDI: %016llx\n" @@ -2473,7 +2479,7 @@ display_regs_from_elf_notes(int cpu) len = roundup(len + note32->n_descsz, 4); user_regs = ((char *)note32) + len - SIZE(user_regs_struct) - sizeof(long); - fprintf(fp, + fprintf(ofp, " EAX: %08x EBX: %08x ECX: %08x EDX: %08x\n" " ESP: %08x EIP: %08x ESI: %08x EDI: %08x\n" " CS: %04x DS: %04x ES: %04x FS: %04x\n" @@ -2506,7 +2512,7 @@ display_regs_from_elf_notes(int cpu) len = roundup(len + note64->n_namesz, 4); len = roundup(len + note64->n_descsz, 4); // user_regs = ((char *)note64) + len - SIZE(user_regs_struct) - sizeof(long); - fprintf(fp, "display_regs_from_elf_notes: ARM64 register dump TBD\n"); + fprintf(ofp, "display_regs_from_elf_notes: ARM64 register dump TBD\n"); } } @@ -2519,7 +2525,7 @@ dump_registers_for_elf_dumpfiles(void) error(FATAL, "-r option not supported for this dumpfile\n"); if (NETDUMP_DUMPFILE()) { - display_regs_from_elf_notes(0); + display_regs_from_elf_notes(0, fp); return; } @@ -2530,7 +2536,7 @@ dump_registers_for_elf_dumpfiles(void) } fprintf(fp, "%sCPU %d:\n", c ? "\n" : "", c); - display_regs_from_elf_notes(c); + display_regs_from_elf_notes(c, fp); } } @@ -2556,7 +2562,8 @@ get_netdump_regs_x86_64(struct bt_info *bt, ulong *ripp, ulong *rspp) bt->flags |= BT_DUMPFILE_SEARCH; if (((NETDUMP_DUMPFILE() || KDUMP_DUMPFILE()) && - VALID_STRUCT(user_regs_struct) && (bt->task == tt->panic_task)) || + VALID_STRUCT(user_regs_struct) && + ((bt->task == tt->panic_task) || (pc->flags2 & QEMU_MEM_DUMP_ELF))) || (KDUMP_DUMPFILE() && (kt->flags & DWARF_UNWIND) && (bt->flags & BT_DUMPFILE_SEARCH))) { if (nd->num_prstatus_notes > 1) diff --git a/task.c b/task.c index f5bbe64..147ff5c 100644 --- a/task.c +++ b/task.c @@ -483,7 +483,7 @@ task_init(void) tt->this_task = pid_to_task(active_pid); } else { - if (KDUMP_DUMPFILE() && !(pc->flags2 & QEMU_MEM_DUMP_ELF)) + if (KDUMP_DUMPFILE()) map_cpus_to_prstatus(); else if (ELF_NOTES_VALID() && DISKDUMP_DUMPFILE()) map_cpus_to_prstatus_kdump_cmprs(); diff --git a/x86_64.c b/x86_64.c index bbf1326..df6c561 100644 --- a/x86_64.c +++ b/x86_64.c @@ -2963,11 +2963,13 @@ x86_64_low_budget_back_trace_cmd(struct bt_info *bt_in) diskdump_display_regs(bt->tc->processor, ofp); else if (SADUMP_DUMPFILE()) sadump_display_regs(bt->tc->processor, ofp); + else if (pc->flags2 & QEMU_MEM_DUMP_ELF) + display_regs_from_elf_notes(bt->tc->processor, ofp); return; } else if ((bt->flags & BT_KERNEL_SPACE) && (KVMDUMP_DUMPFILE() || (ELF_NOTES_VALID() && DISKDUMP_DUMPFILE()) || - SADUMP_DUMPFILE())) { + SADUMP_DUMPFILE() || (pc->flags2 & QEMU_MEM_DUMP_ELF))) { fprintf(ofp, " [exception RIP: "); if ((sp = value_search(bt->instptr, &offset))) { fprintf(ofp, "%s", sp->name); @@ -2983,6 +2985,9 @@ x86_64_low_budget_back_trace_cmd(struct bt_info *bt_in) diskdump_display_regs(bt->tc->processor, ofp); else if (SADUMP_DUMPFILE()) sadump_display_regs(bt->tc->processor, ofp); + else if (pc->flags2 & QEMU_MEM_DUMP_ELF) + display_regs_from_elf_notes(bt->tc->processor, ofp); + } else if (bt->flags & BT_START) { x86_64_print_stack_entry(bt, ofp, level, 0, bt->instptr); @@ -4565,7 +4570,7 @@ skip_stage: *rip = ur_rip; *rsp = ur_rsp; if (is_kernel_text(ur_rip) && - (INSTACK(ur_rsp, bt) || + (INSTACK(ur_rsp, bt_in) || in_alternate_stack(bt->tc->processor, ur_rsp))) bt_in->flags |= BT_KERNEL_SPACE; if (!is_kernel_text(ur_rip) && in_user_stack(bt->tc->task, ur_rsp)) @@ -4596,14 +4601,14 @@ skip_stage: ur_rip = ULONG(user_regs + OFFSET(user_regs_struct_rip)); ur_rsp = ULONG(user_regs + OFFSET(user_regs_struct_rsp)); if (!in_alternate_stack(bt->tc->processor, ur_rsp) && - !stkptr_to_task(bt->task)) { + !stkptr_to_task(ur_rsp)) { if (CRASHDEBUG(1)) error(INFO, "x86_64_get_dumpfile_stack_frame: " "ELF mismatch: RSP: %lx task: %lx\n", ur_rsp, bt->task); } else { - if (is_kernel_text(ur_rip) && (INSTACK(ur_rsp, bt) || + if (is_kernel_text(ur_rip) && (INSTACK(ur_rsp, bt_in) || in_alternate_stack(bt->tc->processor, ur_rsp))) bt_in->flags |= BT_KERNEL_SPACE; if (!is_kernel_text(ur_rip) && in_user_stack(bt->tc->task, ur_rsp))