Commit 9e74a6b8 authored by Christian Borntraeger's avatar Christian Borntraeger Committed by Heiko Carstens

[S390] kernel: show last breaking-event-address on oops

Newer s390 models have a breaking-event-address-recording register.
Each time an instruction causes a break in the sequential instruction
execution, the address is saved in that hardware register. On a program
interrupt the address is copied to the lowcore address 272-279, which
makes it software accessible.

This patch changes the program check handler and the stack overflow
checker to copy the value into the pt_regs argument.
The oops output is enhanced to show the last known breaking address.
It might give additional information if the stack trace is corrupted.

The feature is only available on 64 bit.

The new oops output looks like:

[---------snip----------]
Modules linked in: vmcp sunrpc qeth_l2 dm_mod qeth ccwgroup
CPU: 2 Not tainted 2.6.24zlive-host #8
Process modprobe (pid: 4788, task: 00000000bf3d8718, ksp: 00000000b2b0b8e0)
Krnl PSW : 0704200180000000 000003e000020028 (vmcp_init+0x28/0xe4 [vmcp])
           R:0 T:1 IO:1 EX:1 Key:0 M:1 W:0 P:0 AS:0 CC:2 PM:0 EA:3
Krnl GPRS: 0000000004000002 000003e000020000 0000000000000000 0000000000000001
           000000000015734c ffffffffffffffff 000003e0000b3b00 0000000000000000
           000003e00007ca30 00000000b5bb5d40 00000000b5bb5800 000003e0000b3b00
           000003e0000a2000 00000000003ecf50 00000000b2b0bd50 00000000b2b0bcb0
Krnl Code: 000003e000020018: c0c000040ff4       larl    %r12,3e0000a2000
           000003e00002001e: e3e0f0000024       stg     %r14,0(%r15)
           000003e000020024: a7f40001           brc     15,3e000020026
          >000003e000020028: e310c0100004       lg      %r1,16(%r12)
           000003e00002002e: c020000413dc       larl    %r2,3e0000a27e6
           000003e000020034: c0a00004aee6       larl    %r10,3e0000b5e00
           000003e00002003a: a7490001           lghi    %r4,1
           000003e00002003e: a75900f0           lghi    %r5,240
Call Trace:
([<000000000014b300>] blocking_notifier_call_chain+0x2c/0x40)
 [<000000000015735c>] sys_init_module+0x19d8/0x1b08
 [<0000000000110afc>] sysc_noemu+0x10/0x16
 [<000002000011cda2>] 0x2000011cda2
Last Breaking-Event-Address:
 [<000003e000020024>] vmcp_init+0x24/0xe4 [vmcp]
[---------snip----------]
Signed-off-by: default avatarChristian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarHeiko Carstens <heiko.carstens@de.ibm.com>
parent 1a5debaa
...@@ -475,6 +475,7 @@ pgm_check_handler: ...@@ -475,6 +475,7 @@ pgm_check_handler:
pgm_no_vtime: pgm_no_vtime:
#endif #endif
lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
mvc SP_ARGS(8,%r15),__LC_LAST_BREAK
TRACE_IRQS_OFF TRACE_IRQS_OFF
lgf %r3,__LC_PGM_ILC # load program interruption code lgf %r3,__LC_PGM_ILC # load program interruption code
lghi %r8,0x7f lghi %r8,0x7f
...@@ -847,6 +848,7 @@ stack_overflow: ...@@ -847,6 +848,7 @@ stack_overflow:
je 0f je 0f
la %r1,__LC_SAVE_AREA+32 la %r1,__LC_SAVE_AREA+32
0: mvc SP_R12(32,%r15),0(%r1) # move %r12-%r15 to stack 0: mvc SP_R12(32,%r15),0(%r1) # move %r12-%r15 to stack
mvc SP_ARGS(8,%r15),__LC_LAST_BREAK
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) # clear back chain xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15) # clear back chain
la %r2,SP_PTREGS(%r15) # load pt_regs la %r2,SP_PTREGS(%r15) # load pt_regs
jg kernel_stack_overflow jg kernel_stack_overflow
......
...@@ -195,6 +195,7 @@ void show_regs(struct pt_regs *regs) ...@@ -195,6 +195,7 @@ void show_regs(struct pt_regs *regs)
/* Show stack backtrace if pt_regs is from kernel mode */ /* Show stack backtrace if pt_regs is from kernel mode */
if (!(regs->psw.mask & PSW_MASK_PSTATE)) if (!(regs->psw.mask & PSW_MASK_PSTATE))
show_trace(NULL, (unsigned long *) regs->gprs[15]); show_trace(NULL, (unsigned long *) regs->gprs[15]);
show_last_breaking_event(regs);
} }
extern void kernel_thread_starter(void); extern void kernel_thread_starter(void);
......
...@@ -134,7 +134,6 @@ void show_trace(struct task_struct *task, unsigned long *stack) ...@@ -134,7 +134,6 @@ void show_trace(struct task_struct *task, unsigned long *stack)
else else
__show_trace(sp, S390_lowcore.thread_info, __show_trace(sp, S390_lowcore.thread_info,
S390_lowcore.thread_info + THREAD_SIZE); S390_lowcore.thread_info + THREAD_SIZE);
printk("\n");
if (!task) if (!task)
task = current; task = current;
debug_show_held_locks(task); debug_show_held_locks(task);
...@@ -162,6 +161,15 @@ void show_stack(struct task_struct *task, unsigned long *sp) ...@@ -162,6 +161,15 @@ void show_stack(struct task_struct *task, unsigned long *sp)
show_trace(task, sp); show_trace(task, sp);
} }
#ifdef CONFIG_64BIT
void show_last_breaking_event(struct pt_regs *regs)
{
printk("Last Breaking-Event-Address:\n");
printk(" [<%016lx>] ", regs->args[0] & PSW_ADDR_INSN);
print_symbol("%s\n", regs->args[0] & PSW_ADDR_INSN);
}
#endif
/* /*
* The architecture-independent dump_stack generator * The architecture-independent dump_stack generator
*/ */
......
...@@ -56,6 +56,8 @@ ...@@ -56,6 +56,8 @@
#define __LC_IO_INT_WORD 0x0C0 #define __LC_IO_INT_WORD 0x0C0
#define __LC_MCCK_CODE 0x0E8 #define __LC_MCCK_CODE 0x0E8
#define __LC_LAST_BREAK 0x110
#define __LC_RETURN_PSW 0x200 #define __LC_RETURN_PSW 0x200
#define __LC_SAVE_AREA 0xC00 #define __LC_SAVE_AREA 0xC00
......
...@@ -175,6 +175,13 @@ extern void task_show_regs(struct seq_file *m, struct task_struct *task); ...@@ -175,6 +175,13 @@ extern void task_show_regs(struct seq_file *m, struct task_struct *task);
extern void show_registers(struct pt_regs *regs); extern void show_registers(struct pt_regs *regs);
extern void show_code(struct pt_regs *regs); extern void show_code(struct pt_regs *regs);
extern void show_trace(struct task_struct *task, unsigned long *sp); extern void show_trace(struct task_struct *task, unsigned long *sp);
#ifdef CONFIG_64BIT
extern void show_last_breaking_event(struct pt_regs *regs);
#else
static inline void show_last_breaking_event(struct pt_regs *regs)
{
}
#endif
unsigned long get_wchan(struct task_struct *p); unsigned long get_wchan(struct task_struct *p);
#define task_pt_regs(tsk) ((struct pt_regs *) \ #define task_pt_regs(tsk) ((struct pt_regs *) \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment