s390: Fix backtrace code

This patch fixes several bugs in the s390 stack backtrace code
* Add panic stack as second interrupt stack
* Fix printing of access registers (4 bytes instead of 8 bytes)
* Use u64 for s390x register 14
* Fix interrupt stack handling for s390x (use 160 byte overhead instead of 96)
---
 s390.c  |   46 ++++++++++++++++++-------------
 s390x.c |   94 +++++++++++++++++++++++++++++++++++-----------------------------
 2 files changed, 79 insertions(+), 61 deletions(-)

--- a/s390.c
+++ b/s390.c
@@ -37,7 +37,7 @@
 #define S390_PTE_INVALID_MASK   0x80000900
 #define S390_PTE_INVALID(x) ((x) & S390_PTE_INVALID_MASK)
 
-#define ASYNC_STACK_SIZE  STACKSIZE() // can be 4096 or 8192
+#define INT_STACK_SIZE    STACKSIZE() // can be 4096 or 8192
 #define KERNEL_STACK_SIZE STACKSIZE() // can be 4096 or 8192
 
 #define LOWCORE_SIZE 4096
@@ -570,20 +570,21 @@ s390_get_lowcore(int cpu, char* lowcore)
 		FAULT_ON_ERROR);
 }
 
-/* 
- * read in the async stack
+/*
+ * Read interrupt stack (either "async_stack" or "panic_stack");
  */
-static void
-s390_get_async_stack(char* lowcore, char* async_stack, unsigned long* start, unsigned long* end)
+static void s390_get_int_stack(char *stack_name, char* lc, char* int_stack,
+			       unsigned long* start, unsigned long* end)
 {
-	unsigned long async_stack_ptr;
+	unsigned long stack_addr;
 
-	async_stack_ptr = ULONG(lowcore + 
-				MEMBER_OFFSET("_lowcore","async_stack"));
-	readmem(async_stack_ptr-ASYNC_STACK_SIZE,KVADDR, async_stack, 
-		ASYNC_STACK_SIZE, "async_stack", FAULT_ON_ERROR);
-	*start=async_stack_ptr-ASYNC_STACK_SIZE;
-	*end=async_stack_ptr;
+	if (!MEMBER_EXISTS("_lowcore", stack_name))
+		return;
+	stack_addr = ULONG(lc + MEMBER_OFFSET("_lowcore", stack_name));
+	readmem(stack_addr - INT_STACK_SIZE, KVADDR, int_stack,
+		INT_STACK_SIZE, stack_name, FAULT_ON_ERROR);
+	*start = stack_addr - INT_STACK_SIZE;
+	*end = stack_addr;
 }
 
 /*
@@ -593,16 +594,18 @@ static void
 s390_back_trace_cmd(struct bt_info *bt)
 {
 	char* stack;
-	char async_stack[ASYNC_STACK_SIZE];
+	char async_stack[INT_STACK_SIZE];
+	char panic_stack[INT_STACK_SIZE];
 	long ksp,backchain,old_backchain;
 	int i=0, r14_offset,bc_offset,r14, skip_first_frame=0;
-	unsigned long async_start,async_end, stack_end, stack_start, stack_base;
+	unsigned long async_start = 0, async_end = 0;
+	unsigned long panic_start = 0, panic_end = 0;
+	unsigned long stack_end, stack_start, stack_base;
 
 	if (bt->hp && bt->hp->eip) {
 		error(WARNING,
 		"instruction pointer argument ignored on this architecture!\n");
 	}
-	async_end = async_start = 0;
 	ksp = bt->stkptr;
 
 	/* print lowcore and get async stack when task has cpu */
@@ -622,9 +625,10 @@ s390_back_trace_cmd(struct bt_info *bt)
 				s390_print_lowcore(lowcore,bt,0);
 				return;
 		}
-
-		s390_get_async_stack(lowcore,async_stack,&async_start,
-				     &async_end);
+		s390_get_int_stack("async_stack", lowcore, async_stack,
+				   &async_start, &async_end);
+		s390_get_int_stack("panic_stack", lowcore, panic_stack,
+				   &panic_start, &panic_end);
 		s390_print_lowcore(lowcore,bt,1);
 		fprintf(fp,"\n");
 		skip_first_frame=1;
@@ -653,7 +657,7 @@ s390_back_trace_cmd(struct bt_info *bt)
 		unsigned long r14_stack_off;
 		int j;
 
-		/* Find stack: Either async stack or task stack */
+		/* Find stack: Either async, panic stack or task stack */
 		if((backchain > stack_start) && (backchain < stack_end)){
 			stack = bt->stackbuf;
 			stack_base = stack_start;
@@ -661,6 +665,10 @@ s390_back_trace_cmd(struct bt_info *bt)
 			  && s390_has_cpu(bt)){
 			stack = async_stack;
 			stack_base = async_start;
+		} else if((backchain > panic_start) && (backchain < panic_end)
+			  && s390_has_cpu(bt)){
+			stack = panic_stack;
+			stack_base = panic_start;
 		} else {
 			/* invalid stackframe */
 			break;
--- a/s390x.c
+++ b/s390x.c
@@ -36,7 +36,7 @@
 #define S390X_PTE_INVALID_MASK  0x900ULL
 #define S390X_PTE_INVALID(x) ((x) & S390X_PTE_INVALID_MASK)
 
-#define ASYNC_STACK_SIZE  STACKSIZE() // can be 8192 or 16384
+#define INT_STACK_SIZE    STACKSIZE() // can be 8192 or 16384
 #define KERNEL_STACK_SIZE STACKSIZE() // can be 8192 or 16384
 
 #define LOWCORE_SIZE 8192
@@ -803,19 +803,20 @@ s390x_get_lowcore(struct bt_info *bt, ch
 }
 
 /*
- * read in the async stack
+ * Read interrupt stack (either "async_stack" or "panic_stack");
  */
-static void
-s390x_get_async_stack(char* lowcore, char* async_stack, unsigned long* start, unsigned long* end)
+static void s390x_get_int_stack(char *stack_name, char* lc, char* int_stack,
+				unsigned long* start, unsigned long* end)
 {
-	unsigned long async_stack_ptr;
+	unsigned long stack_addr;
 
-	async_stack_ptr = ULONG(lowcore + 
-				MEMBER_OFFSET("_lowcore","async_stack"));
-	readmem(async_stack_ptr-ASYNC_STACK_SIZE,KVADDR, async_stack, 
-		ASYNC_STACK_SIZE, "async_stack", FAULT_ON_ERROR);
-	*start=async_stack_ptr-ASYNC_STACK_SIZE;
-	*end=async_stack_ptr;
+	if (!MEMBER_EXISTS("_lowcore", stack_name))
+		return;
+	stack_addr = ULONG(lc + MEMBER_OFFSET("_lowcore", stack_name));
+	readmem(stack_addr - INT_STACK_SIZE, KVADDR, int_stack,
+		INT_STACK_SIZE, stack_name, FAULT_ON_ERROR);
+	*start = stack_addr - INT_STACK_SIZE;
+	*end = stack_addr;
 }
 
 /*
@@ -825,11 +826,14 @@ static void
 s390x_back_trace_cmd(struct bt_info *bt)
 {
 	char* stack;
-	char async_stack[ASYNC_STACK_SIZE];
+	char async_stack[INT_STACK_SIZE];
+	char panic_stack[INT_STACK_SIZE];
 	long ksp,backchain,old_backchain;
-	int i=0, r14_offset,bc_offset,r14, skip_first_frame=0;
+	int i=0, r14_offset,bc_offset, skip_first_frame=0;
 	unsigned long async_start = 0, async_end = 0;
+	unsigned long panic_start = 0, panic_end = 0;
 	unsigned long stack_end, stack_start, stack_base;
+	unsigned long r14;
 
 	if (bt->hp && bt->hp->eip) {
 		error(WARNING,
@@ -854,9 +858,10 @@ s390x_back_trace_cmd(struct bt_info *bt)
 			s390x_print_lowcore(lowcore,bt,0);
 			return;
 		}
-
-		s390x_get_async_stack(lowcore,async_stack,&async_start,
-				     &async_end);
+		s390x_get_int_stack("async_stack", lowcore, async_stack,
+				    &async_start, &async_end);
+		s390x_get_int_stack("panic_stack", lowcore, panic_stack,
+				    &panic_start, &panic_end);
 		s390x_print_lowcore(lowcore,bt,1);
 		fprintf(fp,"\n");
 		skip_first_frame=1;
@@ -885,7 +890,7 @@ s390x_back_trace_cmd(struct bt_info *bt)
 		unsigned long r14_stack_off;
 		int j;
 
-		/* Find stack: Either async stack or task stack */
+		/* Find stack: Either async, panic stack or task stack */
 		if((backchain > stack_start) && (backchain < stack_end)){
 			stack = bt->stackbuf;
 			stack_base = stack_start;
@@ -893,6 +898,10 @@ s390x_back_trace_cmd(struct bt_info *bt)
 			  && s390x_has_cpu(bt)){
 			stack = async_stack;
 			stack_base = async_start;
+		} else if((backchain > panic_start) && (backchain < panic_end)
+			  && s390x_has_cpu(bt)){
+			stack = panic_stack;
+			stack_base = panic_start;
 		} else {
 			/* invalid stackframe */
 			break;
@@ -913,7 +922,7 @@ s390x_back_trace_cmd(struct bt_info *bt)
 			skip_first_frame=0;
 		} else {
 			fprintf(fp," #%i [%08lx] ",i,backchain);
-			fprintf(fp,"%s at %x\n", closest_symbol(r14), r14);
+			fprintf(fp,"%s at %lx\n", closest_symbol(r14), r14);
 			if (bt->flags & BT_LINE_NUMBERS)
 				s390x_dump_line_number(r14);
 			i++;
@@ -944,19 +953,20 @@ s390x_back_trace_cmd(struct bt_info *bt)
 		}
 
 		/* Check for interrupt stackframe */
-		if((backchain == 0) && (stack == async_stack)){
-			unsigned long psw_flags,r15;
+		if((backchain == 0) &&
+		   (stack == async_stack || stack == panic_stack)) {
+			int pt_regs_off = old_backchain - stack_base + 160;
+			unsigned long psw_flags;
 
-			psw_flags = ULONG(&stack[old_backchain - stack_base 
-					  +96 +MEMBER_OFFSET("pt_regs","psw")]);
+			psw_flags = ULONG(&stack[pt_regs_off +
+					  MEMBER_OFFSET("pt_regs", "psw")]);
 			if(psw_flags & 0x1000000000000ULL){
 				/* User psw: should not happen */
 				break;
 			}
-			r15 = ULONG(&stack[old_backchain - stack_base +
-				    96 + MEMBER_OFFSET("pt_regs",
-				    "gprs") + 15 * S390X_WORD_SIZE]);
-			backchain=r15;
+			backchain = ULONG(&stack[pt_regs_off +
+					  MEMBER_OFFSET("pt_regs", "gprs") +
+					  15 * S390X_WORD_SIZE]);
 			fprintf(fp," - Interrupt -\n");
 		}
       } while(backchain != 0);
@@ -1036,28 +1046,28 @@ s390x_print_lowcore(char* lc, struct bt_
 
 	fprintf(fp,"  -access registers:\n");
 	ptr = lc + MEMBER_OFFSET("_lowcore","access_regs_save_area");
-	tmp[0]=ULONG(ptr);
-	tmp[1]=ULONG(ptr + 4);
-	tmp[2]=ULONG(ptr + 2 * 4);
-	tmp[3]=ULONG(ptr + 3 * 4);
+	tmp[0]=UINT(ptr);
+	tmp[1]=UINT(ptr + 4);
+	tmp[2]=UINT(ptr + 2 * 4);
+	tmp[3]=UINT(ptr + 3 * 4);
 	fprintf(fp,"     %#010lx %#010lx %#010lx %#010lx\n", 
 		tmp[0], tmp[1], tmp[2], tmp[3]);
-	tmp[0]=ULONG(ptr + 4 * 4);
-	tmp[1]=ULONG(ptr + 5 * 4);
-	tmp[2]=ULONG(ptr + 6 * 4);
-	tmp[3]=ULONG(ptr + 7 * 4);
+	tmp[0]=UINT(ptr + 4 * 4);
+	tmp[1]=UINT(ptr + 5 * 4);
+	tmp[2]=UINT(ptr + 6 * 4);
+	tmp[3]=UINT(ptr + 7 * 4);
 	fprintf(fp,"     %#010lx %#010lx %#010lx %#010lx\n", 
 		tmp[0], tmp[1], tmp[2], tmp[3]);
-	tmp[0]=ULONG(ptr + 8 * 4);
-	tmp[1]=ULONG(ptr + 9 * 4);
-	tmp[2]=ULONG(ptr + 10* 4);
-	tmp[3]=ULONG(ptr + 11* 4);
+	tmp[0]=UINT(ptr + 8 * 4);
+	tmp[1]=UINT(ptr + 9 * 4);
+	tmp[2]=UINT(ptr + 10 * 4);
+	tmp[3]=UINT(ptr + 11 * 4);
 	fprintf(fp,"     %#010lx %#010lx %#010lx %#010lx\n", 
 		tmp[0], tmp[1], tmp[2], tmp[3]);
-	tmp[0]=ULONG(ptr + 12* 4);
-	tmp[1]=ULONG(ptr + 13* 4);
-	tmp[2]=ULONG(ptr + 14* 4);
-	tmp[3]=ULONG(ptr + 15* 4);
+	tmp[0]=UINT(ptr + 12 * 4);
+	tmp[1]=UINT(ptr + 13 * 4);
+	tmp[2]=UINT(ptr + 14 * 4);
+	tmp[3]=UINT(ptr + 15 * 4);
 	fprintf(fp,"     %#010lx %#010lx %#010lx %#010lx\n", 
 		tmp[0], tmp[1], tmp[2], tmp[3]);
 
