summaryrefslogtreecommitdiffstats
path: root/arch/s390
diff options
context:
space:
mode:
authorVasily Gorbik <gor@linux.ibm.com>2022-03-05 13:16:07 +0100
committerVasily Gorbik <gor@linux.ibm.com>2022-03-27 22:18:39 +0200
commit708b13763920ab3c191b31da555f2d90eef4c618 (patch)
tree630387a974eaca87727952030397b4191f33d90a /arch/s390
parents390/unwind: recover kretprobe modified return address in stacktrace (diff)
downloadlinux-708b13763920ab3c191b31da555f2d90eef4c618.tar.xz
linux-708b13763920ab3c191b31da555f2d90eef4c618.zip
s390/unwind: avoid duplicated unwinding entries for kretprobes
Currently when unwinding starts from pt_regs or encounters pt_regs along the way unwinder tries to yield 2 unwinding entries: 1. (reliable) ip1: pt_regs->psw.addr, sp1: regs->gprs[15] 2. (non-reliable) ip2: sp1->gprs[8] (r14), sp2: regs->gprs[15] In case of kretprobes those are identical and serves no other purpose than causing confusion over duplicated entries and cause kprobes tests to fail. So, skip a duplicate non-reliable entry in this case. With that kretprobes and unwinder implementation now comply with ARCH_CORRECT_STACKTRACE_ON_KRETPROBE. Reviewed-by: Tobias Huschle <huschle@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Diffstat (limited to 'arch/s390')
-rw-r--r--arch/s390/Kconfig1
-rw-r--r--arch/s390/kernel/unwind_bc.c4
2 files changed, 3 insertions, 2 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index 9b80e8bed3f6..77b5a03de13a 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -58,6 +58,7 @@ config S390
select ALTERNATE_USER_ADDRESS_SPACE
select ARCH_32BIT_USTAT_F_TINODE
select ARCH_BINFMT_ELF_STATE
+ select ARCH_CORRECT_STACKTRACE_ON_KRETPROBE
select ARCH_ENABLE_MEMORY_HOTPLUG if SPARSEMEM
select ARCH_ENABLE_MEMORY_HOTREMOVE
select ARCH_ENABLE_SPLIT_PMD_PTLOCK if PGTABLE_LEVELS > 2
diff --git a/arch/s390/kernel/unwind_bc.c b/arch/s390/kernel/unwind_bc.c
index 984970389bab..0ece156fdd7c 100644
--- a/arch/s390/kernel/unwind_bc.c
+++ b/arch/s390/kernel/unwind_bc.c
@@ -64,8 +64,8 @@ bool unwind_next_frame(struct unwind_state *state)
ip = READ_ONCE_NOCHECK(sf->gprs[8]);
reliable = false;
regs = NULL;
- if (!__kernel_text_address(ip)) {
- /* skip bogus %r14 */
+ /* skip bogus %r14 or if is the same as regs->psw.addr */
+ if (!__kernel_text_address(ip) || state->ip == unwind_recover_ret_addr(state, ip)) {
state->regs = NULL;
return unwind_next_frame(state);
}