mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-23 17:30:02 +00:00
s390: fix __EMIT_BUG() macro
Setting a kprobe on getname_flags() failed: $ echo 'p:tmr1 getname_flags +0(%r2):ustring' > kprobe_events -bash: echo: write error: Invalid argument Debugging the kprobes code showed that the address of getname_flags() is contained in the __bug_table. Kprobes doesn't allow to set probes at BUG() locations. $ objdump -j __bug_table -x build/fs/namei.o [..] 0000000000000108 R_390_PC32 .text+0x00000000000075a8 000000000000010c R_390_PC32 .L223+0x0000000000000004 I was expecting getname_flags() to start with a BUG(), but: 7598: e3 20 10 00 00 04 lg %r2,0(%r1) 759e: c0 f4 00 00 00 00 jg 759e <putname+0x7e> 75a0: R_390_PLT32DBL kmem_cache_free+0x2 75a4: a7 f4 00 01 j 75a6 <putname+0x86> 00000000000075a8 <getname_flags>: 75a8: c0 04 00 00 00 00 brcl 0,75a8 <getname_flags> 75ae: eb 6f f0 48 00 24 stmg %r6,%r15,72(%r15) 75b4: b9 04 00 ef lgr %r14,%r15 75b8: e3 f0 ff a8 ff 71 lay %r15,-88(%r15) So the BUG() is actually the last opcode of the previous function. Fix this by switching to using the MONITOR CALL (MC) instruction, and set the entry in __bug_table to the beginning of that MC. Reviewed-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Sven Schnelle <svens@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
This commit is contained in:
parent
45f7a0da60
commit
17248ea036
5 changed files with 46 additions and 16 deletions
|
@ -329,7 +329,7 @@ ENTRY(startup_kdump)
|
||||||
.quad .Lduct # cr5: primary-aste origin
|
.quad .Lduct # cr5: primary-aste origin
|
||||||
.quad 0 # cr6: I/O interrupts
|
.quad 0 # cr6: I/O interrupts
|
||||||
.quad 0 # cr7: secondary space segment table
|
.quad 0 # cr7: secondary space segment table
|
||||||
.quad 0 # cr8: access registers translation
|
.quad 0x0000000000008000 # cr8: access registers translation
|
||||||
.quad 0 # cr9: tracing off
|
.quad 0 # cr9: tracing off
|
||||||
.quad 0 # cr10: tracing off
|
.quad 0 # cr10: tracing off
|
||||||
.quad 0 # cr11: tracing off
|
.quad 0 # cr11: tracing off
|
||||||
|
|
|
@ -10,15 +10,14 @@
|
||||||
|
|
||||||
#define __EMIT_BUG(x) do { \
|
#define __EMIT_BUG(x) do { \
|
||||||
asm_inline volatile( \
|
asm_inline volatile( \
|
||||||
"0: j 0b+2\n" \
|
"0: mc 0,0\n" \
|
||||||
"1:\n" \
|
|
||||||
".section .rodata.str,\"aMS\",@progbits,1\n" \
|
".section .rodata.str,\"aMS\",@progbits,1\n" \
|
||||||
"2: .asciz \""__FILE__"\"\n" \
|
"1: .asciz \""__FILE__"\"\n" \
|
||||||
".previous\n" \
|
".previous\n" \
|
||||||
".section __bug_table,\"awM\",@progbits,%2\n" \
|
".section __bug_table,\"awM\",@progbits,%2\n" \
|
||||||
"3: .long 1b-3b,2b-3b\n" \
|
"2: .long 0b-2b,1b-2b\n" \
|
||||||
" .short %0,%1\n" \
|
" .short %0,%1\n" \
|
||||||
" .org 3b+%2\n" \
|
" .org 2b+%2\n" \
|
||||||
".previous\n" \
|
".previous\n" \
|
||||||
: : "i" (__LINE__), \
|
: : "i" (__LINE__), \
|
||||||
"i" (x), \
|
"i" (x), \
|
||||||
|
@ -29,12 +28,11 @@
|
||||||
|
|
||||||
#define __EMIT_BUG(x) do { \
|
#define __EMIT_BUG(x) do { \
|
||||||
asm_inline volatile( \
|
asm_inline volatile( \
|
||||||
"0: j 0b+2\n" \
|
"0: mc 0,0\n" \
|
||||||
"1:\n" \
|
|
||||||
".section __bug_table,\"awM\",@progbits,%1\n" \
|
".section __bug_table,\"awM\",@progbits,%1\n" \
|
||||||
"2: .long 1b-2b\n" \
|
"1: .long 0b-1b\n" \
|
||||||
" .short %0\n" \
|
" .short %0\n" \
|
||||||
" .org 2b+%1\n" \
|
" .org 1b+%1\n" \
|
||||||
".previous\n" \
|
".previous\n" \
|
||||||
: : "i" (x), \
|
: : "i" (x), \
|
||||||
"i" (sizeof(struct bug_entry))); \
|
"i" (sizeof(struct bug_entry))); \
|
||||||
|
|
|
@ -45,6 +45,7 @@ void specification_exception(struct pt_regs *regs);
|
||||||
void transaction_exception(struct pt_regs *regs);
|
void transaction_exception(struct pt_regs *regs);
|
||||||
void translation_exception(struct pt_regs *regs);
|
void translation_exception(struct pt_regs *regs);
|
||||||
void vector_exception(struct pt_regs *regs);
|
void vector_exception(struct pt_regs *regs);
|
||||||
|
void monitor_event_exception(struct pt_regs *regs);
|
||||||
|
|
||||||
void do_per_trap(struct pt_regs *regs);
|
void do_per_trap(struct pt_regs *regs);
|
||||||
void do_report_trap(struct pt_regs *regs, int si_signo, int si_code, char *str);
|
void do_report_trap(struct pt_regs *regs, int si_signo, int si_code, char *str);
|
||||||
|
|
|
@ -81,7 +81,7 @@ PGM_CHECK_DEFAULT /* 3c */
|
||||||
PGM_CHECK_DEFAULT /* 3d */
|
PGM_CHECK_DEFAULT /* 3d */
|
||||||
PGM_CHECK_DEFAULT /* 3e */
|
PGM_CHECK_DEFAULT /* 3e */
|
||||||
PGM_CHECK_DEFAULT /* 3f */
|
PGM_CHECK_DEFAULT /* 3f */
|
||||||
PGM_CHECK_DEFAULT /* 40 */
|
PGM_CHECK(monitor_event_exception) /* 40 */
|
||||||
PGM_CHECK_DEFAULT /* 41 */
|
PGM_CHECK_DEFAULT /* 41 */
|
||||||
PGM_CHECK_DEFAULT /* 42 */
|
PGM_CHECK_DEFAULT /* 42 */
|
||||||
PGM_CHECK_DEFAULT /* 43 */
|
PGM_CHECK_DEFAULT /* 43 */
|
||||||
|
|
|
@ -53,11 +53,6 @@ void do_report_trap(struct pt_regs *regs, int si_signo, int si_code, char *str)
|
||||||
if (fixup)
|
if (fixup)
|
||||||
regs->psw.addr = extable_fixup(fixup);
|
regs->psw.addr = extable_fixup(fixup);
|
||||||
else {
|
else {
|
||||||
enum bug_trap_type btt;
|
|
||||||
|
|
||||||
btt = report_bug(regs->psw.addr, regs);
|
|
||||||
if (btt == BUG_TRAP_TYPE_WARN)
|
|
||||||
return;
|
|
||||||
die(regs, str);
|
die(regs, str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -245,6 +240,27 @@ void space_switch_exception(struct pt_regs *regs)
|
||||||
do_trap(regs, SIGILL, ILL_PRVOPC, "space switch event");
|
do_trap(regs, SIGILL, ILL_PRVOPC, "space switch event");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void monitor_event_exception(struct pt_regs *regs)
|
||||||
|
{
|
||||||
|
const struct exception_table_entry *fixup;
|
||||||
|
|
||||||
|
if (user_mode(regs))
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (report_bug(regs->psw.addr - (regs->int_code >> 16), regs)) {
|
||||||
|
case BUG_TRAP_TYPE_NONE:
|
||||||
|
fixup = s390_search_extables(regs->psw.addr);
|
||||||
|
if (fixup)
|
||||||
|
regs->psw.addr = extable_fixup(fixup);
|
||||||
|
break;
|
||||||
|
case BUG_TRAP_TYPE_WARN:
|
||||||
|
break;
|
||||||
|
case BUG_TRAP_TYPE_BUG:
|
||||||
|
die(regs, "monitor event");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void kernel_stack_overflow(struct pt_regs *regs)
|
void kernel_stack_overflow(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
bust_spinlocks(1);
|
bust_spinlocks(1);
|
||||||
|
@ -255,8 +271,23 @@ void kernel_stack_overflow(struct pt_regs *regs)
|
||||||
}
|
}
|
||||||
NOKPROBE_SYMBOL(kernel_stack_overflow);
|
NOKPROBE_SYMBOL(kernel_stack_overflow);
|
||||||
|
|
||||||
|
static void test_monitor_call(void)
|
||||||
|
{
|
||||||
|
int val = 1;
|
||||||
|
|
||||||
|
asm volatile(
|
||||||
|
" mc 0,0\n"
|
||||||
|
"0: xgr %0,%0\n"
|
||||||
|
"1:\n"
|
||||||
|
EX_TABLE(0b,1b)
|
||||||
|
: "+d" (val));
|
||||||
|
if (!val)
|
||||||
|
panic("Monitor call doesn't work!\n");
|
||||||
|
}
|
||||||
|
|
||||||
void __init trap_init(void)
|
void __init trap_init(void)
|
||||||
{
|
{
|
||||||
sort_extable(__start_dma_ex_table, __stop_dma_ex_table);
|
sort_extable(__start_dma_ex_table, __stop_dma_ex_table);
|
||||||
local_mcck_enable();
|
local_mcck_enable();
|
||||||
|
test_monitor_call();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue