We have sadump, and it can work when the OS is out of controll( for example: dead loop, dead lock). When we use sadump, some user application may be running, and the sp/ip is in user stack. We should deal with it like kvm dump.
>From c437d677ea91fbf8c1239b219231b7b0fbeb2c7b Mon Sep 17 00:00:00 2001 From: Wen Congyang <wency@xxxxxxxxxxxxxx> Date: Fri, 8 Jul 2011 13:07:06 +0800 Subject: [PATCH] output regs if sp is in user stack --- defs.h | 26 +++++++++++++++ diskdump.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++ netdump.c | 7 ++++ x86.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++- x86_64.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 299 insertions(+), 6 deletions(-) diff --git a/defs.h b/defs.h index 55a94a4..8bffbf4 100644 --- a/defs.h +++ b/defs.h @@ -1577,6 +1577,31 @@ struct offset_table { /* stash of commonly-used offsets */ long s390_stack_frame_back_chain; long s390_stack_frame_r14; long user_regs_struct_eip; + long user_regs_struct_rax; + long user_regs_struct_eax; + long user_regs_struct_rbx; + long user_regs_struct_ebx; + long user_regs_struct_rcx; + long user_regs_struct_ecx; + long user_regs_struct_rdx; + long user_regs_struct_edx; + long user_regs_struct_rsi; + long user_regs_struct_esi; + long user_regs_struct_rdi; + long user_regs_struct_edi; + long user_regs_struct_ds; + long user_regs_struct_es; + long user_regs_struct_fs; + long user_regs_struct_gs; + long user_regs_struct_rbp; + long user_regs_struct_r8; + long user_regs_struct_r9; + long user_regs_struct_r10; + long user_regs_struct_r11; + long user_regs_struct_r12; + long user_regs_struct_r13; + long user_regs_struct_r14; + long user_regs_struct_r15; }; struct size_table { /* stash of commonly-used sizes */ @@ -4622,6 +4647,7 @@ void show_split_dumpfiles(void); void x86_process_elf_notes(void *, unsigned long); void *diskdump_get_prstatus_percpu(int); void map_cpus_to_prstatus_kdump_cmprs(void); +void diskdump_display_regs(int, FILE*); /* * makedumpfile.c diff --git a/diskdump.c b/diskdump.c index 631c196..3c105c0 100644 --- a/diskdump.c +++ b/diskdump.c @@ -1463,3 +1463,85 @@ diskdump_get_osrelease(void) else pc->flags2 &= ~GET_OSRELEASE; } + +void +diskdump_display_regs(int cpu, FILE *ofp) +{ + Elf32_Nhdr *note32; + Elf64_Nhdr *note64; + char *user_regs; + size_t len; + + if (cpu >= NR_CPUS || dd->nt_prstatus_percpu[cpu] == NULL) { + error(INFO, "registers not collected for cpu %d\n", cpu); + return; + } + + if (machine_type("X86_64")) { + note64 = dd->nt_prstatus_percpu[cpu]; + len = sizeof(Elf64_Nhdr); + 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(ofp, + " RIP: %016llx RSP: %016llx RFLAGS: %08llx\n" + " RAX: %016llx RBX: %016llx RCX: %016llx\n" + " RDX: %016llx RSI: %016llx RDI: %016llx\n" + " RBP: %016llx R8: %016llx R9: %016llx\n" + " R10: %016llx R11: %016llx R12: %016llx\n" + " R13: %016llx R14: %016llx R15: %016llx\n" + " CS: %04x SS: %04x\n", + ULONGLONG(user_regs + OFFSET(user_regs_struct_rip)), + ULONGLONG(user_regs + OFFSET(user_regs_struct_rsp)), + ULONGLONG(user_regs + OFFSET(user_regs_struct_eflags)), + ULONGLONG(user_regs + OFFSET(user_regs_struct_rax)), + ULONGLONG(user_regs + OFFSET(user_regs_struct_rbx)), + ULONGLONG(user_regs + OFFSET(user_regs_struct_rcx)), + ULONGLONG(user_regs + OFFSET(user_regs_struct_rdx)), + ULONGLONG(user_regs + OFFSET(user_regs_struct_rsi)), + ULONGLONG(user_regs + OFFSET(user_regs_struct_rdi)), + ULONGLONG(user_regs + OFFSET(user_regs_struct_rbp)), + ULONGLONG(user_regs + OFFSET(user_regs_struct_r8)), + ULONGLONG(user_regs + OFFSET(user_regs_struct_r9)), + ULONGLONG(user_regs + OFFSET(user_regs_struct_r10)), + ULONGLONG(user_regs + OFFSET(user_regs_struct_r11)), + ULONGLONG(user_regs + OFFSET(user_regs_struct_r12)), + ULONGLONG(user_regs + OFFSET(user_regs_struct_r13)), + ULONGLONG(user_regs + OFFSET(user_regs_struct_r14)), + ULONGLONG(user_regs + OFFSET(user_regs_struct_r15)), + USHORT(user_regs + OFFSET(user_regs_struct_cs)), + USHORT(user_regs + OFFSET(user_regs_struct_ss)) + ); + } + + if (machine_type("X86")) { + note32 = dd->nt_prstatus_percpu[cpu]; + len = sizeof(Elf32_Nhdr); + len = roundup(len + note32->n_namesz, 4); + len = roundup(len + note32->n_descsz, 4); + user_regs = (char *)note32 + len - SIZE(user_regs_struct) - sizeof(int); + 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" + " GS: %04x SS: %04x\n" + " EBP: %08x EFLAGS: %08x\n", + UINT(user_regs + OFFSET(user_regs_struct_eax)), + UINT(user_regs + OFFSET(user_regs_struct_ebx)), + UINT(user_regs + OFFSET(user_regs_struct_ecx)), + UINT(user_regs + OFFSET(user_regs_struct_edx)), + UINT(user_regs + OFFSET(user_regs_struct_esp)), + UINT(user_regs + OFFSET(user_regs_struct_eip)), + UINT(user_regs + OFFSET(user_regs_struct_esi)), + UINT(user_regs + OFFSET(user_regs_struct_edi)), + USHORT(user_regs + OFFSET(user_regs_struct_cs)), + USHORT(user_regs + OFFSET(user_regs_struct_ds)), + USHORT(user_regs + OFFSET(user_regs_struct_es)), + USHORT(user_regs + OFFSET(user_regs_struct_fs)), + USHORT(user_regs + OFFSET(user_regs_struct_gs)), + USHORT(user_regs + OFFSET(user_regs_struct_ss)), + UINT(user_regs + OFFSET(user_regs_struct_ebp)), + UINT(user_regs + OFFSET(user_regs_struct_eflags)) + ); + } +} diff --git a/netdump.c b/netdump.c index bc62148..c20821e 100644 --- a/netdump.c +++ b/netdump.c @@ -2502,6 +2502,13 @@ next_sysrq: *esp = sp; return; } + + if (!is_kernel_text(ip) && in_user_stack(bt->tc->task, sp)) { + bt->flags |= BT_USER_SPACE; + *eip = ip; + *esp = sp; + return; + } } if (CRASHDEBUG(1)) diff --git a/x86.c b/x86.c index cceb35f..c705580 100644 --- a/x86.c +++ b/x86.c @@ -677,8 +677,11 @@ db_stack_trace_cmd(addr, have_addr, count, modif, task, flags) struct eframe eframe, *ep; char dbuf[BUFSIZE]; - if ((bt->flags & BT_USER_SPACE) && KVMDUMP_DUMPFILE()) { - kvmdump_display_regs(bt->tc->processor, fp); + if (bt->flags & BT_USER_SPACE) { + if (KVMDUMP_DUMPFILE()) + kvmdump_display_regs(bt->tc->processor, fp); + if (ELF_NOTES_VALID() && DISKDUMP_DUMPFILE()) + diskdump_display_regs(bt->tc->processor, fp); fprintf(fp, " #0 [user space]\n"); return; } else if ((bt->flags & BT_KERNEL_SPACE) && KVMDUMP_DUMPFILE()) @@ -1806,6 +1809,60 @@ x86_init(int when) else MEMBER_OFFSET_INIT(user_regs_struct_eip, "user_regs_struct", "ip"); + if (MEMBER_EXISTS("user_regs_struct", "eax")) + MEMBER_OFFSET_INIT(user_regs_struct_eax, + "user_regs_struct", "eax"); + else + MEMBER_OFFSET_INIT(user_regs_struct_eax, + "user_regs_struct", "ax"); + if (MEMBER_EXISTS("user_regs_struct", "ebx")) + MEMBER_OFFSET_INIT(user_regs_struct_ebx, + "user_regs_struct", "ebx"); + else + MEMBER_OFFSET_INIT(user_regs_struct_ebx, + "user_regs_struct", "bx"); + if (MEMBER_EXISTS("user_regs_struct", "ecx")) + MEMBER_OFFSET_INIT(user_regs_struct_ecx, + "user_regs_struct", "ecx"); + else + MEMBER_OFFSET_INIT(user_regs_struct_ecx, + "user_regs_struct", "cx"); + if (MEMBER_EXISTS("user_regs_struct", "edx")) + MEMBER_OFFSET_INIT(user_regs_struct_edx, + "user_regs_struct", "edx"); + else + MEMBER_OFFSET_INIT(user_regs_struct_edx, + "user_regs_struct", "dx"); + if (MEMBER_EXISTS("user_regs_struct", "esi")) + MEMBER_OFFSET_INIT(user_regs_struct_esi, + "user_regs_struct", "esi"); + else + MEMBER_OFFSET_INIT(user_regs_struct_esi, + "user_regs_struct", "si"); + if (MEMBER_EXISTS("user_regs_struct", "edi")) + MEMBER_OFFSET_INIT(user_regs_struct_edi, + "user_regs_struct", "edi"); + else + MEMBER_OFFSET_INIT(user_regs_struct_edi, + "user_regs_struct", "di"); + if (MEMBER_EXISTS("user_regs_struct", "eflags")) + MEMBER_OFFSET_INIT(user_regs_struct_eflags, + "user_regs_struct", "eflags"); + else + MEMBER_OFFSET_INIT(user_regs_struct_eflags, + "user_regs_struct", "flags"); + MEMBER_OFFSET_INIT(user_regs_struct_cs, + "user_regs_struct", "cs"); + MEMBER_OFFSET_INIT(user_regs_struct_ds, + "user_regs_struct", "ds"); + MEMBER_OFFSET_INIT(user_regs_struct_es, + "user_regs_struct", "es"); + MEMBER_OFFSET_INIT(user_regs_struct_fs, + "user_regs_struct", "fs"); + MEMBER_OFFSET_INIT(user_regs_struct_gs, + "user_regs_struct", "gs"); + MEMBER_OFFSET_INIT(user_regs_struct_ss, + "user_regs_struct", "ss"); if (!VALID_STRUCT(user_regs_struct)) { /* Use this hardwired version -- sometimes the * debuginfo doesn't pick this up even though @@ -1828,6 +1885,32 @@ x86_init(int when) offsetof(struct x86_user_regs_struct, esp); ASSIGN_OFFSET(user_regs_struct_eip) = offsetof(struct x86_user_regs_struct, eip); + ASSIGN_OFFSET(user_regs_struct_eax) = + offsetof(struct x86_user_regs_struct, eax); + ASSIGN_OFFSET(user_regs_struct_ebx) = + offsetof(struct x86_user_regs_struct, ebx); + ASSIGN_OFFSET(user_regs_struct_ecx) = + offsetof(struct x86_user_regs_struct, ecx); + ASSIGN_OFFSET(user_regs_struct_edx) = + offsetof(struct x86_user_regs_struct, edx); + ASSIGN_OFFSET(user_regs_struct_esi) = + offsetof(struct x86_user_regs_struct, esi); + ASSIGN_OFFSET(user_regs_struct_edi) = + offsetof(struct x86_user_regs_struct, edi); + ASSIGN_OFFSET(user_regs_struct_eflags) = + offsetof(struct x86_user_regs_struct, eflags); + ASSIGN_OFFSET(user_regs_struct_cs) = + offsetof(struct x86_user_regs_struct, cs); + ASSIGN_OFFSET(user_regs_struct_ds) = + offsetof(struct x86_user_regs_struct, ds); + ASSIGN_OFFSET(user_regs_struct_es) = + offsetof(struct x86_user_regs_struct, es); + ASSIGN_OFFSET(user_regs_struct_fs) = + offsetof(struct x86_user_regs_struct, fs); + ASSIGN_OFFSET(user_regs_struct_gs) = + offsetof(struct x86_user_regs_struct, gs); + ASSIGN_OFFSET(user_regs_struct_ss) = + offsetof(struct x86_user_regs_struct, ss); } MEMBER_OFFSET_INIT(thread_struct_cr3, "thread_struct", "cr3"); STRUCT_SIZE_INIT(cpuinfo_x86, "cpuinfo_x86"); diff --git a/x86_64.c b/x86_64.c index a114b96..2c58c8c 100644 --- a/x86_64.c +++ b/x86_64.c @@ -337,6 +337,57 @@ x86_64_init(int when) "user_regs_struct", "cs"); MEMBER_OFFSET_INIT(user_regs_struct_ss, "user_regs_struct", "ss"); + MEMBER_OFFSET_INIT(user_regs_struct_rax, + "user_regs_struct", "rax"); + if (INVALID_MEMBER(user_regs_struct_rax)) + MEMBER_OFFSET_INIT(user_regs_struct_rax, + "user_regs_struct", "ax"); + MEMBER_OFFSET_INIT(user_regs_struct_rbx, + "user_regs_struct", "rbx"); + if (INVALID_MEMBER(user_regs_struct_rbx)) + MEMBER_OFFSET_INIT(user_regs_struct_rbx, + "user_regs_struct", "bx"); + MEMBER_OFFSET_INIT(user_regs_struct_rcx, + "user_regs_struct", "rcx"); + if (INVALID_MEMBER(user_regs_struct_rcx)) + MEMBER_OFFSET_INIT(user_regs_struct_rcx, + "user_regs_struct", "cx"); + MEMBER_OFFSET_INIT(user_regs_struct_rdx, + "user_regs_struct", "rdx"); + if (INVALID_MEMBER(user_regs_struct_rdx)) + MEMBER_OFFSET_INIT(user_regs_struct_rdx, + "user_regs_struct", "dx"); + MEMBER_OFFSET_INIT(user_regs_struct_rsi, + "user_regs_struct", "rsi"); + if (INVALID_MEMBER(user_regs_struct_rsi)) + MEMBER_OFFSET_INIT(user_regs_struct_rsi, + "user_regs_struct", "si"); + MEMBER_OFFSET_INIT(user_regs_struct_rdi, + "user_regs_struct", "rdi"); + if (INVALID_MEMBER(user_regs_struct_rdi)) + MEMBER_OFFSET_INIT(user_regs_struct_rdi, + "user_regs_struct", "di"); + MEMBER_OFFSET_INIT(user_regs_struct_rbp, + "user_regs_struct", "rbp"); + if (INVALID_MEMBER(user_regs_struct_rbp)) + MEMBER_OFFSET_INIT(user_regs_struct_rbp, + "user_regs_struct", "bp"); + MEMBER_OFFSET_INIT(user_regs_struct_r8, + "user_regs_struct", "r8"); + MEMBER_OFFSET_INIT(user_regs_struct_r9, + "user_regs_struct", "r9"); + MEMBER_OFFSET_INIT(user_regs_struct_r10, + "user_regs_struct", "r10"); + MEMBER_OFFSET_INIT(user_regs_struct_r11, + "user_regs_struct", "r11"); + MEMBER_OFFSET_INIT(user_regs_struct_r12, + "user_regs_struct", "r12"); + MEMBER_OFFSET_INIT(user_regs_struct_r13, + "user_regs_struct", "r13"); + MEMBER_OFFSET_INIT(user_regs_struct_r14, + "user_regs_struct", "r14"); + MEMBER_OFFSET_INIT(user_regs_struct_r15, + "user_regs_struct", "r15"); STRUCT_SIZE_INIT(user_regs_struct, "user_regs_struct"); if (!VALID_STRUCT(user_regs_struct)) { /* Use this hardwired version -- sometimes the @@ -362,6 +413,36 @@ x86_64_init(int when) offsetof(struct x86_64_user_regs_struct, cs); ASSIGN_OFFSET(user_regs_struct_ss) = offsetof(struct x86_64_user_regs_struct, ss); + ASSIGN_OFFSET(user_regs_struct_rax) = + offsetof(struct x86_64_user_regs_struct, ax); + ASSIGN_OFFSET(user_regs_struct_rbx) = + offsetof(struct x86_64_user_regs_struct, bx); + ASSIGN_OFFSET(user_regs_struct_rcx) = + offsetof(struct x86_64_user_regs_struct, cx); + ASSIGN_OFFSET(user_regs_struct_rdx) = + offsetof(struct x86_64_user_regs_struct, dx); + ASSIGN_OFFSET(user_regs_struct_rsi) = + offsetof(struct x86_64_user_regs_struct, si); + ASSIGN_OFFSET(user_regs_struct_rdi) = + offsetof(struct x86_64_user_regs_struct, di); + ASSIGN_OFFSET(user_regs_struct_rbp) = + offsetof(struct x86_64_user_regs_struct, bp); + ASSIGN_OFFSET(user_regs_struct_r8) = + offsetof(struct x86_64_user_regs_struct, r8); + ASSIGN_OFFSET(user_regs_struct_r9) = + offsetof(struct x86_64_user_regs_struct, r9); + ASSIGN_OFFSET(user_regs_struct_r10) = + offsetof(struct x86_64_user_regs_struct, r10); + ASSIGN_OFFSET(user_regs_struct_r11) = + offsetof(struct x86_64_user_regs_struct, r11); + ASSIGN_OFFSET(user_regs_struct_r12) = + offsetof(struct x86_64_user_regs_struct, r12); + ASSIGN_OFFSET(user_regs_struct_r13) = + offsetof(struct x86_64_user_regs_struct, r13); + ASSIGN_OFFSET(user_regs_struct_r14) = + offsetof(struct x86_64_user_regs_struct, r14); + ASSIGN_OFFSET(user_regs_struct_r15) = + offsetof(struct x86_64_user_regs_struct, r15); } machdep->vmalloc_start = x86_64_vmalloc_start; vt->vmalloc_start = machdep->vmalloc_start(); @@ -2750,7 +2831,11 @@ x86_64_low_budget_back_trace_cmd(struct bt_info *bt_in) last_process_stack_eframe = 0; bt->call_target = NULL; rsp = bt->stkptr; - if (!rsp || !accessible(rsp)) { + /* If rsp is in user stack, the memory may not be included in vmcore, and + * we only output the registers value. So it's not necessary to check + * whether it can be accessieble. + */ + if (!(bt->flags & BT_USER_SPACE) && (!rsp || !accessible(rsp))) { error(INFO, "cannot determine starting stack pointer\n"); return; } @@ -2761,6 +2846,8 @@ x86_64_low_budget_back_trace_cmd(struct bt_info *bt_in) ofp = fp; if (bt->flags & BT_TEXT_SYMBOLS) { + if (bt->flags & BT_USER_SPACE) + return; if (!(bt->flags & BT_TEXT_SYMBOLS_ALL)) fprintf(ofp, "%sSTART: %s%s at %lx\n", space(VADDR_PRLEN > 8 ? 14 : 6), @@ -2768,10 +2855,16 @@ x86_64_low_budget_back_trace_cmd(struct bt_info *bt_in) STREQ(closest_symbol(bt->instptr), "thread_return") ? " (schedule)" : "", bt->instptr); - } else if ((bt->flags & BT_USER_SPACE) && KVMDUMP_DUMPFILE()) { + } else if (bt->flags & BT_USER_SPACE) { fprintf(ofp, " [exception RIP: user space]\n"); - kvmdump_display_regs(bt->tc->processor, ofp); - return; + if(KVMDUMP_DUMPFILE()) { + kvmdump_display_regs(bt->tc->processor, ofp); + return; + } + if (ELF_NOTES_VALID() && DISKDUMP_DUMPFILE()) { + diskdump_display_regs(bt->tc->processor, ofp); + return; + } } else if ((bt->flags & BT_KERNEL_SPACE) && KVMDUMP_DUMPFILE()) { fprintf(ofp, " [exception RIP: "); if ((sp = value_search(bt->instptr, &offset))) { @@ -4252,6 +4345,8 @@ skip_stage: if (ur_rip && ur_rsp) { *rip = ur_rip; *rsp = ur_rsp; + if (!is_kernel_text(ur_rip) && in_user_stack(bt->tc->task, ur_rsp)) + bt_in->flags |= BT_USER_SPACE; return; } -- 1.7.1
-- Crash-utility mailing list Crash-utility@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/crash-utility