Skip to content

Commit 3046003

Browse files
committed
s390/entry: Add CFI statements to pgm_check_handler
When debugging kernel crashes using GDB, it is helpful to be able to obtain a backtrace after pgm_check_handler(). Currently this does not work, because pgm_check_handler() lacks CFI. Add missing CFI statements. Old PSW should be obtained from lowcore, which is not addressed relative to CFA. GNU assembler does not have directives for this, so synthesize a DW_OP_const8u expression using .cfi_escape. Make use of uleb128() and data8() directives introduced in binutils 2.45 for this; add a fallback in case they are not available. Introduce CFI_OFFSET_MULTIPLE() and CFI_RESTORE_MULTIPLE() macros for describing the effects of STMG and LMG. Unfortunately .cfi_offset and .cfi_restore do not work with variables like .Lreg, so synthesize the respective instructions using .cfi_escape. With this unwinding begins to work. For example, manually corrupting do_execveat_common()'s filename and setting a breakpoint on __do_pgm_check() produces the following backtrace: Thread 8 hit Breakpoint 3, __do_pgm_check (regs=0x37fe0a23b18) at ./arch/s390/include/asm/lowcore.h:224 224 asm_inline( (gdb) bt #0 __do_pgm_check (regs=0x37fe0a23b18) at ./arch/s390/include/asm/lowcore.h:224 #1 0x000003ffe0cc08f4 in pgm_check_handler () at arch/s390/kernel/entry.S:339 #2 0x000003ffe04f2510 in __set_nameidata (p=0x37fe0a23c78, dfd=<optimized out>, name=0xfffffff666666667) at fs/namei.c:668 #3 set_nameidata (p=0x37fe0a23c78, dfd=<optimized out>, name=0xfffffff666666667, root=0x0 <fini>) at fs/namei.c:679 #4 do_filp_open (dfd=-100, pathname=0xfffffff666666667, op=0x37fe0a23db0, op@entry=0x3ffe04e5cc2 <do_open_execat+178>) at fs/namei.c:4160 #5 0x000003ffe04e5c72 in do_open_execat (fd=fd@entry=-100, name=name@entry=0xfffffff666666667, flags=flags@entry=0) at fs/exec.c:783 torvalds#6 0x000003ffe04e5dee in alloc_bprm (fd=fd@entry=-100, filename=filename@entry=0xfffffff666666667, flags=0) at fs/exec.c:1410 torvalds#7 0x000003ffe04e6040 in do_execveat_common (fd=fd@entry=-100, filename=0xfffffff666666667, argv=..., envp=..., envp@entry=..., flags=flags@entry=0) at fs/exec.c:1811 torvalds#8 0x000003ffe04e69c6 in do_execve (filename=<optimized out>, __argv=<optimized out>, __envp=0x2aa21a6bb60) at fs/exec.c:1934 torvalds#9 __do_sys_execve (filename=<optimized out>, argv=<optimized out>, envp=0x2aa21a6bb60) at fs/exec.c:2010 torvalds#10 __se_sys_execve (filename=<optimized out>, argv=<optimized out>, envp=2929732270944) at fs/exec.c:2005 torvalds#11 __s390x_sys_execve (regs=<optimized out>) at fs/exec.c:2005 torvalds#12 0x000003ffe0cb3cb6 in __do_syscall (regs=0x37fe0a23f40, per_trap=<optimized out>) at arch/s390/kernel/syscall.c:125 torvalds#13 0x000003ffe0cc078e in system_call () at arch/s390/kernel/entry.S:261 Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
1 parent d9043c7 commit 3046003

File tree

3 files changed

+50
-0
lines changed

3 files changed

+50
-0
lines changed

arch/s390/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,8 @@ endif
103103

104104
# Test CFI features of binutils
105105
cfi := $(call as-instr,.cfi_startproc\n.cfi_val_offset 15$(comma)-160\n.cfi_endproc,-DCONFIG_AS_CFI_VAL_OFFSET=1)
106+
cfi += $(call as-instr,.cfi_startproc\n.cfi_escape uleb128(0)\n.cfi_endproc,-DCONFIG_AS_CFI_ESCAPE_LEB128=1)
107+
cfi += $(call as-instr,.cfi_startproc\n.cfi_escape data8(0)\n.cfi_endproc,-DCONFIG_AS_CFI_ESCAPE_DATA=1)
106108

107109
KBUILD_CFLAGS += -mpacked-stack -mbackchain -msoft-float $(cflags-y)
108110
KBUILD_CFLAGS += -pipe -Wno-sign-compare

arch/s390/include/asm/dwarf.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,45 @@
3333
.cfi_sections .eh_frame, .debug_frame
3434
#endif
3535

36+
#define DW_CFA_restore_extended 0x06
37+
#define DW_CFA_expression 0x10
38+
#define DW_CFA_offset_extended_sf 0x11
39+
40+
#define DW_OP_const8u 0x0e
41+
42+
.macro CFI_GLOBAL reg, addr
43+
#if defined(CONFIG_AS_CFI_ESCAPE_LEB128) && defined(CONFIG_AS_CFI_ESCAPE_DATA)
44+
.cfi_escape DW_CFA_expression, uleb128(\reg), 9, DW_OP_const8u, data8(\addr)
45+
#else
46+
.cfi_undefined \reg
47+
#endif
48+
.endm
49+
50+
.macro CFI_GLOBAL_MULTIPLE reg1, reg2, addr
51+
.set .Lreg, (\reg1)
52+
.rept (\reg2)-(\reg1)+1
53+
CFI_GLOBAL .Lreg, (\addr)+(.Lreg-(\reg1))*8
54+
.set .Lreg, .Lreg+1
55+
.endr
56+
.endm
57+
58+
.macro CFI_OFFSET_MULTIPLE reg1, reg2, off
59+
.set .Lreg, (\reg1)
60+
.rept (\reg2)-(\reg1)+1
61+
.cfi_escape DW_CFA_offset_extended_sf, uleb128(.Lreg), \
62+
sleb128(-(\off)/8-(.Lreg-(\reg1)))
63+
.set .Lreg, .Lreg+1
64+
.endr
65+
.endm
66+
67+
.macro CFI_RESTORE_MULTIPLE reg1, reg2
68+
.set .Lreg, (\reg1)
69+
.rept (\reg2)-(\reg1)+1
70+
.cfi_escape DW_CFA_restore_extended, uleb128(.Lreg)
71+
.set .Lreg, .Lreg+1
72+
.endr
73+
.endm
74+
3675
#endif /* __ASSEMBLER__ */
3776

3877
#endif /* _ASM_S390_DWARF_H */

arch/s390/kernel/entry.S

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,7 +289,10 @@ SYM_CODE_END(ret_from_fork)
289289
*/
290290

291291
SYM_CODE_START(pgm_check_handler)
292+
CFI_STARTPROC
293+
CFI_GLOBAL_MULTIPLE 64,65,__LC_PGM_OLD_PSW
292294
STMG_LC %r8,%r15,__LC_SAVE_AREA
295+
CFI_GLOBAL_MULTIPLE 8,15,__LC_SAVE_AREA
293296
GET_LC %r13
294297
stpt __LC_SYS_ENTER_TIMER(%r13)
295298
BPOFF
@@ -317,9 +320,12 @@ SYM_CODE_START(pgm_check_handler)
317320
stg %r10,__PT_FLAGS(%r11)
318321
xc __SF_BACKCHAIN(8,%r15),__SF_BACKCHAIN(%r15)
319322
stmg %r0,%r7,__PT_R0(%r11)
323+
CFI_OFFSET_MULTIPLE 0,7,__PT_R0
320324
mvc __PT_R8(64,%r11),__LC_SAVE_AREA(%r13)
325+
CFI_OFFSET_MULTIPLE 8,15,__PT_R0+64
321326
mvc __PT_LAST_BREAK(8,%r11),__LC_PGM_LAST_BREAK(%r13)
322327
stmg %r8,%r9,__PT_PSW(%r11)
328+
CFI_OFFSET_MULTIPLE 64,65,__PT_PSW
323329
# clear user controlled registers to prevent speculative use
324330
xgr %r0,%r0
325331
xgr %r1,%r1
@@ -338,9 +344,12 @@ SYM_CODE_START(pgm_check_handler)
338344
stpt __LC_EXIT_TIMER(%r13)
339345
.Lpgm_exit_kernel:
340346
mvc __LC_RETURN_PSW(16,%r13),STACK_FRAME_OVERHEAD+__PT_PSW(%r15)
347+
CFI_GLOBAL_MULTIPLE 64,65,__LC_RETURN_PSW
341348
LBEAR STACK_FRAME_OVERHEAD+__PT_LAST_BREAK(%r15)
342349
lmg %r0,%r15,STACK_FRAME_OVERHEAD+__PT_R0(%r15)
350+
CFI_RESTORE_MULTIPLE 0,15
343351
LPSWEY __LC_RETURN_PSW,__LC_RETURN_LPSWE
352+
CFI_ENDPROC
344353

345354
#
346355
# single stepped system call

0 commit comments

Comments
 (0)