diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2007-04-27 10:01:41 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2007-04-27 10:01:42 -0400 |
commit | bb11e3bdbac08f773a89f3ca287024a956ee8a12 (patch) | |
tree | f0d1f39efbe08c8217d1d18ff7bcb1fdc36ee6d2 /arch/s390/kernel/traps.c | |
parent | 03ff9a235a0602724fc54916469b6e0939c62c9b (diff) |
[S390] Improved oops output.
This patch adds two improvements to the oops output. First it adds an
additional line after the PSW which decodes the different fields of it.
Second a disassembler is added that decodes the instructions surrounding
the faulting PSW. The output of a test oops now looks like this:
kernel BUG at init/main.c:419
illegal operation: 0001 [#1]
CPU: 0 Not tainted
Process swapper (pid: 0, task: 0000000000464968, ksp: 00000000004be000)
Krnl PSW : 0700000180000000 00000000000120b6 (rest_init+0x36/0x38)
R:0 T:1 IO:1 EX:1 Key:0 M:0 W:0 P:0 AS:0 CC:0 PM:0 EA:3
Krnl GPRS: 0000000000000003 00000000004ba017 0000000000000022 0000000000000001
000000000003a5f6 0000000000000000 00000000004be6a8 0000000000000000
0000000000000000 00000000004b8200 0000000000003a50 0000000000008000
0000000000516368 000000000033d008 00000000000120b2 00000000004bdee0
Krnl Code: 00000000000120a6: e3e0f0980024 stg %r14,152(%r15)
00000000000120ac: c0e500014296 brasl %r14,3a5d8
00000000000120b2: a7f40001 brc 15,120b4
>00000000000120b6: 0707 bcr 0,%r7
00000000000120b8: eb7ff0500024 stmg %r7,%r15,80(%r15)
00000000000120be: c0d000195825 larl %r13,33d108
00000000000120c4: a7f13f00 tmll %r15,16128
00000000000120c8: a7840001 brc 8,120ca
Call Trace:
([<00000000000120b2>] rest_init+0x32/0x38)
[<00000000004be614>] start_kernel+0x37c/0x410
[<0000000000012020>] _ehead+0x20/0x80
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel/traps.c')
-rw-r--r-- | arch/s390/kernel/traps.c | 55 |
1 files changed, 17 insertions, 38 deletions
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index f0e5a320e2ec..a6540940190b 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c | |||
@@ -188,18 +188,31 @@ void dump_stack(void) | |||
188 | 188 | ||
189 | EXPORT_SYMBOL(dump_stack); | 189 | EXPORT_SYMBOL(dump_stack); |
190 | 190 | ||
191 | static inline int mask_bits(struct pt_regs *regs, unsigned long bits) | ||
192 | { | ||
193 | return (regs->psw.mask & bits) / ((~bits + 1) & bits); | ||
194 | } | ||
195 | |||
191 | void show_registers(struct pt_regs *regs) | 196 | void show_registers(struct pt_regs *regs) |
192 | { | 197 | { |
193 | mm_segment_t old_fs; | ||
194 | char *mode; | 198 | char *mode; |
195 | int i; | ||
196 | 199 | ||
197 | mode = (regs->psw.mask & PSW_MASK_PSTATE) ? "User" : "Krnl"; | 200 | mode = (regs->psw.mask & PSW_MASK_PSTATE) ? "User" : "Krnl"; |
198 | printk("%s PSW : %p %p", | 201 | printk("%s PSW : %p %p", |
199 | mode, (void *) regs->psw.mask, | 202 | mode, (void *) regs->psw.mask, |
200 | (void *) regs->psw.addr); | 203 | (void *) regs->psw.addr); |
201 | print_symbol(" (%s)\n", regs->psw.addr & PSW_ADDR_INSN); | 204 | print_symbol(" (%s)\n", regs->psw.addr & PSW_ADDR_INSN); |
202 | printk("%s GPRS: " FOURLONG, mode, | 205 | printk(" R:%x T:%x IO:%x EX:%x Key:%x M:%x W:%x " |
206 | "P:%x AS:%x CC:%x PM:%x", mask_bits(regs, PSW_MASK_PER), | ||
207 | mask_bits(regs, PSW_MASK_DAT), mask_bits(regs, PSW_MASK_IO), | ||
208 | mask_bits(regs, PSW_MASK_EXT), mask_bits(regs, PSW_MASK_KEY), | ||
209 | mask_bits(regs, PSW_MASK_MCHECK), mask_bits(regs, PSW_MASK_WAIT), | ||
210 | mask_bits(regs, PSW_MASK_PSTATE), mask_bits(regs, PSW_MASK_ASC), | ||
211 | mask_bits(regs, PSW_MASK_CC), mask_bits(regs, PSW_MASK_PM)); | ||
212 | #ifdef CONFIG_64BIT | ||
213 | printk(" EA:%x", mask_bits(regs, PSW_BASE_BITS)); | ||
214 | #endif | ||
215 | printk("\n%s GPRS: " FOURLONG, mode, | ||
203 | regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]); | 216 | regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]); |
204 | printk(" " FOURLONG, | 217 | printk(" " FOURLONG, |
205 | regs->gprs[4], regs->gprs[5], regs->gprs[6], regs->gprs[7]); | 218 | regs->gprs[4], regs->gprs[5], regs->gprs[6], regs->gprs[7]); |
@@ -208,41 +221,7 @@ void show_registers(struct pt_regs *regs) | |||
208 | printk(" " FOURLONG, | 221 | printk(" " FOURLONG, |
209 | regs->gprs[12], regs->gprs[13], regs->gprs[14], regs->gprs[15]); | 222 | regs->gprs[12], regs->gprs[13], regs->gprs[14], regs->gprs[15]); |
210 | 223 | ||
211 | #if 0 | 224 | show_code(regs); |
212 | /* FIXME: this isn't needed any more but it changes the ksymoops | ||
213 | * input. To remove or not to remove ... */ | ||
214 | save_access_regs(regs->acrs); | ||
215 | printk("%s ACRS: %08x %08x %08x %08x\n", mode, | ||
216 | regs->acrs[0], regs->acrs[1], regs->acrs[2], regs->acrs[3]); | ||
217 | printk(" %08x %08x %08x %08x\n", | ||
218 | regs->acrs[4], regs->acrs[5], regs->acrs[6], regs->acrs[7]); | ||
219 | printk(" %08x %08x %08x %08x\n", | ||
220 | regs->acrs[8], regs->acrs[9], regs->acrs[10], regs->acrs[11]); | ||
221 | printk(" %08x %08x %08x %08x\n", | ||
222 | regs->acrs[12], regs->acrs[13], regs->acrs[14], regs->acrs[15]); | ||
223 | #endif | ||
224 | |||
225 | /* | ||
226 | * Print the first 20 byte of the instruction stream at the | ||
227 | * time of the fault. | ||
228 | */ | ||
229 | old_fs = get_fs(); | ||
230 | if (regs->psw.mask & PSW_MASK_PSTATE) | ||
231 | set_fs(USER_DS); | ||
232 | else | ||
233 | set_fs(KERNEL_DS); | ||
234 | printk("%s Code: ", mode); | ||
235 | for (i = 0; i < 20; i++) { | ||
236 | unsigned char c; | ||
237 | if (__get_user(c, (char __user *)(regs->psw.addr + i))) { | ||
238 | printk(" Bad PSW."); | ||
239 | break; | ||
240 | } | ||
241 | printk("%02x ", c); | ||
242 | } | ||
243 | set_fs(old_fs); | ||
244 | |||
245 | printk("\n"); | ||
246 | } | 225 | } |
247 | 226 | ||
248 | /* This is called from fs/proc/array.c */ | 227 | /* This is called from fs/proc/array.c */ |