s390/stacktrace: Merge perf_callchain_user() and arch_stack_walk_user()
The two functions perf_callchain_user() and arch_stack_walk_user() are nearly identical. Reduce code duplication and add a common helper which can be called by both functions. Fixes: aa44433ac4ee ("s390: add USER_STACKTRACE support") Reviewed-by: Jens Remus <jremus@linux.ibm.com> Signed-off-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
This commit is contained in:
parent
185445c7c1
commit
ebd912ff99
@ -2,6 +2,7 @@
|
||||
#ifndef _ASM_S390_STACKTRACE_H
|
||||
#define _ASM_S390_STACKTRACE_H
|
||||
|
||||
#include <linux/stacktrace.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/ptrace.h>
|
||||
|
||||
@ -12,6 +13,12 @@ struct stack_frame_user {
|
||||
unsigned long empty2[4];
|
||||
};
|
||||
|
||||
struct perf_callchain_entry_ctx;
|
||||
|
||||
void arch_stack_walk_user_common(stack_trace_consume_fn consume_entry, void *cookie,
|
||||
struct perf_callchain_entry_ctx *entry,
|
||||
const struct pt_regs *regs, bool perf);
|
||||
|
||||
enum stack_type {
|
||||
STACK_TYPE_UNKNOWN,
|
||||
STACK_TYPE_TASK,
|
||||
|
@ -218,39 +218,7 @@ void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
|
||||
void perf_callchain_user(struct perf_callchain_entry_ctx *entry,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
struct stack_frame_user __user *sf;
|
||||
unsigned long ip, sp;
|
||||
bool first = true;
|
||||
|
||||
if (is_compat_task())
|
||||
return;
|
||||
perf_callchain_store(entry, instruction_pointer(regs));
|
||||
sf = (void __user *)user_stack_pointer(regs);
|
||||
pagefault_disable();
|
||||
while (entry->nr < entry->max_stack) {
|
||||
if (__get_user(sp, &sf->back_chain))
|
||||
break;
|
||||
if (__get_user(ip, &sf->gprs[8]))
|
||||
break;
|
||||
if (ip & 0x1) {
|
||||
/*
|
||||
* If the instruction address is invalid, and this
|
||||
* is the first stack frame, assume r14 has not
|
||||
* been written to the stack yet. Otherwise exit.
|
||||
*/
|
||||
if (first && !(regs->gprs[14] & 0x1))
|
||||
ip = regs->gprs[14];
|
||||
else
|
||||
break;
|
||||
}
|
||||
perf_callchain_store(entry, ip);
|
||||
/* Sanity check: ABI requires SP to be aligned 8 bytes. */
|
||||
if (!sp || sp & 0x7)
|
||||
break;
|
||||
sf = (void __user *)sp;
|
||||
first = false;
|
||||
}
|
||||
pagefault_enable();
|
||||
arch_stack_walk_user_common(NULL, NULL, entry, regs, true);
|
||||
}
|
||||
|
||||
/* Perf definitions for PMU event attributes in sysfs */
|
||||
|
@ -5,6 +5,7 @@
|
||||
* Copyright IBM Corp. 2006
|
||||
*/
|
||||
|
||||
#include <linux/perf_event.h>
|
||||
#include <linux/stacktrace.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/compat.h>
|
||||
@ -62,8 +63,23 @@ int arch_stack_walk_reliable(stack_trace_consume_fn consume_entry,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void arch_stack_walk_user(stack_trace_consume_fn consume_entry, void *cookie,
|
||||
const struct pt_regs *regs)
|
||||
static inline bool store_ip(stack_trace_consume_fn consume_entry, void *cookie,
|
||||
struct perf_callchain_entry_ctx *entry, bool perf,
|
||||
unsigned long ip)
|
||||
{
|
||||
#ifdef CONFIG_PERF_EVENTS
|
||||
if (perf) {
|
||||
if (perf_callchain_store(entry, ip))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return consume_entry(cookie, ip);
|
||||
}
|
||||
|
||||
void arch_stack_walk_user_common(stack_trace_consume_fn consume_entry, void *cookie,
|
||||
struct perf_callchain_entry_ctx *entry,
|
||||
const struct pt_regs *regs, bool perf)
|
||||
{
|
||||
struct stack_frame_user __user *sf;
|
||||
unsigned long ip, sp;
|
||||
@ -71,7 +87,8 @@ void arch_stack_walk_user(stack_trace_consume_fn consume_entry, void *cookie,
|
||||
|
||||
if (is_compat_task())
|
||||
return;
|
||||
if (!consume_entry(cookie, instruction_pointer(regs)))
|
||||
ip = instruction_pointer(regs);
|
||||
if (!store_ip(consume_entry, cookie, entry, perf, ip))
|
||||
return;
|
||||
sf = (void __user *)user_stack_pointer(regs);
|
||||
pagefault_disable();
|
||||
@ -91,8 +108,8 @@ void arch_stack_walk_user(stack_trace_consume_fn consume_entry, void *cookie,
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (!consume_entry(cookie, ip))
|
||||
break;
|
||||
if (!store_ip(consume_entry, cookie, entry, perf, ip))
|
||||
return;
|
||||
/* Sanity check: ABI requires SP to be aligned 8 bytes. */
|
||||
if (!sp || sp & 0x7)
|
||||
break;
|
||||
@ -102,6 +119,12 @@ void arch_stack_walk_user(stack_trace_consume_fn consume_entry, void *cookie,
|
||||
pagefault_enable();
|
||||
}
|
||||
|
||||
void arch_stack_walk_user(stack_trace_consume_fn consume_entry, void *cookie,
|
||||
const struct pt_regs *regs)
|
||||
{
|
||||
arch_stack_walk_user_common(consume_entry, cookie, NULL, regs, false);
|
||||
}
|
||||
|
||||
unsigned long return_address(unsigned int n)
|
||||
{
|
||||
struct unwind_state state;
|
||||
|
Loading…
x
Reference in New Issue
Block a user