[S390] kernel: show last breaking-event-address on oops
authorChristian Borntraeger <borntraeger@de.ibm.com>
Thu, 17 Apr 2008 05:46:30 +0000 (07:46 +0200)
committerHeiko Carstens <heiko.carstens@de.ibm.com>
Thu, 17 Apr 2008 05:47:07 +0000 (07:47 +0200)
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: 000003e000020018c0c000040ff4       larl    %r12,3e0000a2000
           000003e00002001ee3e0f0000024       stg     %r14,0(%r15)
           000003e000020024a7f40001           brc     15,3e000020026
          >000003e000020028e310c0100004       lg      %r1,16(%r12)
           000003e00002002ec020000413dc       larl    %r2,3e0000a27e6
           000003e000020034c0a00004aee6       larl    %r10,3e0000b5e00
           000003e00002003aa7490001           lghi    %r4,1
           000003e00002003ea75900f0           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: Christian Borntraeger <borntraeger@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
arch/s390/kernel/entry64.S
arch/s390/kernel/process.c
arch/s390/kernel/traps.c
include/asm-s390/lowcore.h
include/asm-s390/processor.h

index efde6e178f6c22733322ac6c5048cdfed8c7e28b..cd959c0b2e16b4cd225429e960cf2a96e4b7276a 100644 (file)
@@ -475,6 +475,7 @@ pgm_check_handler:
 pgm_no_vtime:
 #endif
        lg      %r9,__LC_THREAD_INFO    # load pointer to thread_info struct
+       mvc     SP_ARGS(8,%r15),__LC_LAST_BREAK
        TRACE_IRQS_OFF
        lgf     %r3,__LC_PGM_ILC        # load program interruption code
        lghi    %r8,0x7f
@@ -847,6 +848,7 @@ stack_overflow:
        je      0f
        la      %r1,__LC_SAVE_AREA+32
 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
        la      %r2,SP_PTREGS(%r15)     # load pt_regs
        jg      kernel_stack_overflow
index dbefd0db395f6d99bf380b3cbc9a541e0fb4cd0b..c1aff194141d892871166a09a82e7ee23a8f23be 100644 (file)
@@ -195,6 +195,7 @@ void show_regs(struct pt_regs *regs)
        /* Show stack backtrace if pt_regs is from kernel mode */
        if (!(regs->psw.mask & PSW_MASK_PSTATE))
                show_trace(NULL, (unsigned long *) regs->gprs[15]);
+       show_last_breaking_event(regs);
 }
 
 extern void kernel_thread_starter(void);
index b3524134f21349bed9f6fb87c88170b6aee64102..57b607b6110010f7fa3dd7cd2f74e1d3b94e0065 100644 (file)
@@ -134,7 +134,6 @@ void show_trace(struct task_struct *task, unsigned long *stack)
        else
                __show_trace(sp, S390_lowcore.thread_info,
                             S390_lowcore.thread_info + THREAD_SIZE);
-       printk("\n");
        if (!task)
                task = current;
        debug_show_held_locks(task);
@@ -162,6 +161,15 @@ void show_stack(struct task_struct *task, unsigned long *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
  */
index 007c8a4941b2e49710c7f11e158fc3477c41d94c..5de3efb31445a88f986a1e5480b059088042d520 100644 (file)
@@ -56,6 +56,8 @@
 #define __LC_IO_INT_WORD                0x0C0
 #define __LC_MCCK_CODE                  0x0E8
 
+#define __LC_LAST_BREAK                0x110
+
 #define __LC_RETURN_PSW                 0x200
 
 #define __LC_SAVE_AREA                  0xC00
index 51d88912aa200857bd6b57fee339f41a3a8421d2..8eaf343a12a8d72e6df3ebfc5c69dc7067c9d8e6 100644 (file)
@@ -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_code(struct pt_regs *regs);
 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);
 #define task_pt_regs(tsk) ((struct pt_regs *) \