Skip to content

Commit 52a1f73

Browse files
committed
s390/fault: Print unmodified PSW address on protection exception
In case of a kernel crash caused by a protection exception, print the unmodified PSW address as reported by the CPU. The protection exception handler modifies the PSW address in order to keep fault handling easy, however that leads to misleading call traces. Therefore restore the original PSW address before printing it. Before this change the output in case of a protection exception looks like this: Oops: 0004 ilc:2 [#1]SMP Krnl PSW : 0704c00180000000 000003ffe0b40d78 (sysrq_handle_crash+0x28/0x40) R:0 T:1 IO:1 EX:1 Key:0 M:1 W:0 P:0 AS:3 CC:0 PM:0 RI:0 EA:3 ... Krnl Code: 000003ffe0b40d66: e3e0f0980024 stg %r14,152(%r15) 000003ffe0b40d6c: c010fffffff2 larl %r1,000003ffe0b40d50 #000003ffe0b40d72: c0200046b6bc larl %r2,000003ffe1417aea >000003ffe0b40d78: 92021000 mvi 0(%r1),2 000003ffe0b40d7c: c0e5ffae03d6 brasl %r14,000003ffe0101528 With this change it looks like this: Oops: 0004 ilc:2 [#1]SMP Krnl PSW : 0704c00180000000 000003ffe0b40dfc (sysrq_handle_crash+0x2c/0x40) R:0 T:1 IO:1 EX:1 Key:0 M:1 W:0 P:0 AS:3 CC:0 PM:0 RI:0 EA:3 ... Krnl Code: 000003ffe0b40dec: c010fffffff2 larl %r1,000003ffe0b40dd0 000003ffe0b40df2: c0200046b67c larl %r2,000003ffe1417aea *000003ffe0b40df8: 92021000 mvi 0(%r1),2 >000003ffe0b40dfc: c0e5ffae03b6 brasl %r14,000003ffe0101568 000003ffe0b40e02: 0707 bcr 0,%r7 Note that with this change the PSW address points to the instruction behind the instruction which caused the exception like it is expected for protection exceptions. This also replaces the '#' marker in the disassembly with '*', which allows to distinguish between new and old behavior. Reviewed-by: Alexander Gordeev <agordeev@linux.ibm.com> Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
1 parent a603a00 commit 52a1f73

4 files changed

Lines changed: 21 additions & 10 deletions

File tree

arch/s390/include/asm/ptrace.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@
1414
#include <asm/tpi.h>
1515

1616
#define PIF_SYSCALL 0 /* inside a system call */
17+
#define PIF_PSW_ADDR_ADJUSTED 1 /* psw address has been adjusted */
1718
#define PIF_SYSCALL_RET_SET 2 /* return value was set via ptrace */
1819
#define PIF_GUEST_FAULT 3 /* indicates program check in sie64a */
1920
#define PIF_FTRACE_FULL_REGS 4 /* all register contents valid (ftrace) */
2021

2122
#define _PIF_SYSCALL BIT(PIF_SYSCALL)
23+
#define _PIF_ADDR_PSW_ADJUSTED BIT(PIF_PSW_ADDR_ADJUSTED)
2224
#define _PIF_SYSCALL_RET_SET BIT(PIF_SYSCALL_RET_SET)
2325
#define _PIF_GUEST_FAULT BIT(PIF_GUEST_FAULT)
2426
#define _PIF_FTRACE_FULL_REGS BIT(PIF_FTRACE_FULL_REGS)

arch/s390/kernel/dis.c

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -503,24 +503,27 @@ static int copy_from_regs(struct pt_regs *regs, void *dst, void *src, int len)
503503
void show_code(struct pt_regs *regs)
504504
{
505505
char *mode = user_mode(regs) ? "User" : "Krnl";
506+
unsigned long addr, pswaddr;
506507
unsigned char code[64];
507508
char buffer[128], *ptr;
508-
unsigned long addr;
509509
int start, end, opsize, hops, i;
510510

511+
pswaddr = regs->psw.addr;
512+
if (test_pt_regs_flag(regs, PIF_PSW_ADDR_ADJUSTED))
513+
pswaddr = __forward_psw(regs->psw, regs->int_code >> 16);
511514
/* Get a snapshot of the 64 bytes surrounding the fault address. */
512-
for (start = 32; start && regs->psw.addr >= 34 - start; start -= 2) {
513-
addr = regs->psw.addr - 34 + start;
515+
for (start = 32; start && pswaddr >= 34 - start; start -= 2) {
516+
addr = pswaddr - 34 + start;
514517
if (copy_from_regs(regs, code + start - 2, (void *)addr, 2))
515518
break;
516519
}
517520
for (end = 32; end < 64; end += 2) {
518-
addr = regs->psw.addr + end - 32;
521+
addr = pswaddr + end - 32;
519522
if (copy_from_regs(regs, code + end, (void *)addr, 2))
520523
break;
521524
}
522525
/* Code snapshot usable ? */
523-
if ((regs->psw.addr & 1) || start >= end) {
526+
if ((pswaddr & 1) || start >= end) {
524527
printk("%s Code: Bad PSW.\n", mode);
525528
return;
526529
}
@@ -543,12 +546,12 @@ void show_code(struct pt_regs *regs)
543546
while (start < end && hops < 8) {
544547
opsize = insn_length(code[start]);
545548
if (start + opsize == 32)
546-
*ptr++ = '#';
549+
*ptr++ = '*';
547550
else if (start == 32)
548551
*ptr++ = '>';
549552
else
550553
*ptr++ = ' ';
551-
addr = regs->psw.addr + start - 32;
554+
addr = pswaddr + start - 32;
552555
ptr += sprintf(ptr, "%px: ", (void *)addr);
553556
if (start + opsize >= end)
554557
break;

arch/s390/kernel/dumpstack.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -155,12 +155,16 @@ static void show_last_breaking_event(struct pt_regs *regs)
155155
void show_registers(struct pt_regs *regs)
156156
{
157157
struct psw_bits *psw = &psw_bits(regs->psw);
158+
unsigned long pswaddr;
158159
char *mode;
159160

161+
pswaddr = regs->psw.addr;
162+
if (test_pt_regs_flag(regs, PIF_PSW_ADDR_ADJUSTED))
163+
pswaddr = __forward_psw(regs->psw, regs->int_code >> 16);
160164
mode = user_mode(regs) ? "User" : "Krnl";
161-
printk("%s PSW : %px %px", mode, (void *)regs->psw.mask, (void *)regs->psw.addr);
165+
printk("%s PSW : %px %px", mode, (void *)regs->psw.mask, (void *)pswaddr);
162166
if (!user_mode(regs))
163-
pr_cont(" (%pSR)", (void *)regs->psw.addr);
167+
pr_cont(" (%pSR)", (void *)pswaddr);
164168
pr_cont("\n");
165169
printk(" R:%x T:%x IO:%x EX:%x Key:%x M:%x W:%x "
166170
"P:%x AS:%x CC:%x PM:%x", psw->per, psw->dat, psw->io, psw->ext,

arch/s390/mm/fault.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,8 +374,10 @@ void do_protection_exception(struct pt_regs *regs)
374374
* The exception to this rule are aborted transactions, for these
375375
* the PSW already points to the correct location.
376376
*/
377-
if (!(regs->int_code & 0x200))
377+
if (!(regs->int_code & 0x200)) {
378378
regs->psw.addr = __rewind_psw(regs->psw, regs->int_code >> 16);
379+
set_pt_regs_flag(regs, PIF_PSW_ADDR_ADJUSTED);
380+
}
379381
/*
380382
* If bit 61 if the TEID is not set, the remainder of the
381383
* TEID is unpredictable. Special handling is required.

0 commit comments

Comments
 (0)