>From c437d677ea91fbf8c1239b219231b7b0fbeb2c7b Mon Sep 17 00:00:00 2001
From: Wen Congyang <wency@cn.fujitsu.com>
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

