All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/2] Implement perf_callchain_user
@ 2011-08-11  0:36 Holger Hans Peter Freyther
  2011-08-11  0:36 ` [PATCH 1/2] MIPS: Move userspace stack unwinding into kernel/user_backtrace.c Holger Hans Peter Freyther
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Holger Hans Peter Freyther @ 2011-08-11  0:36 UTC (permalink / raw)
  To: linux-mips; +Cc: Holger Hans Peter Freyther

Hi,
this is moving code from oprofile/backtrace.c to a commom
place and then implements perf_callchain_user using the common
code. Right now the unwind_user_frame will always be compiled
into the kernel.


Holger Hans Peter Freyther (2):
  MIPS: Move userspace stack unwinding into kernel/user_backtrace.c
  MIPS: Implement perf_callchain_user using unwind_user_frame

 arch/mips/include/asm/stacktrace.h |   10 +++
 arch/mips/kernel/Makefile          |    3 +-
 arch/mips/kernel/perf_event.c      |   14 ++++
 arch/mips/kernel/user_backtrace.c  |  129 ++++++++++++++++++++++++++++++++++
 arch/mips/oprofile/backtrace.c     |  133 ++----------------------------------
 5 files changed, 160 insertions(+), 129 deletions(-)
 create mode 100644 arch/mips/kernel/user_backtrace.c

-- 
1.7.4.1

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/2] MIPS: Move userspace stack unwinding into kernel/user_backtrace.c
  2011-08-11  0:36 [PATCH 0/2] Implement perf_callchain_user Holger Hans Peter Freyther
@ 2011-08-11  0:36 ` Holger Hans Peter Freyther
  2011-08-11  0:36 ` [PATCH 2/2] MIPS: Implement perf_callchain_user using unwind_user_frame Holger Hans Peter Freyther
  2011-08-22 17:32 ` [PATCH 0/2] Implement perf_callchain_user Holger Freyther
  2 siblings, 0 replies; 8+ messages in thread
From: Holger Hans Peter Freyther @ 2011-08-11  0:36 UTC (permalink / raw)
  To: linux-mips; +Cc: Holger Hans Peter Freyther, Holger Freyther

Move the OProfile userspace stack unwinding into
arch/mips/kernel/user_backtrace.c to be shared with the perf
callchain implementation.

Rename struct stackframe to user_stackframe, add a GPLv2 header
to the source with the original author of the code.

Always export the unwind_user_frame symbol to make it easy to
use the OProfile module on an already built kernel.

Signed-off-by: Holger Freyther <holger@moiji-mobile.com>
---
 arch/mips/include/asm/stacktrace.h |   10 +++
 arch/mips/kernel/Makefile          |    3 +-
 arch/mips/kernel/user_backtrace.c  |  129 ++++++++++++++++++++++++++++++++++
 arch/mips/oprofile/backtrace.c     |  133 ++----------------------------------
 4 files changed, 146 insertions(+), 129 deletions(-)
 create mode 100644 arch/mips/kernel/user_backtrace.c

diff --git a/arch/mips/include/asm/stacktrace.h b/arch/mips/include/asm/stacktrace.h
index 780ee2c..f713da1 100644
--- a/arch/mips/include/asm/stacktrace.h
+++ b/arch/mips/include/asm/stacktrace.h
@@ -49,4 +49,14 @@ static __always_inline void prepare_frametrace(struct pt_regs *regs)
 		: : "memory");
 }
 
+struct user_stackframe {
+	unsigned long sp;
+	unsigned long pc;
+	unsigned long ra;
+};
+
+int unwind_user_frame(struct user_stackframe *old_frame,
+			const unsigned int max_instr_check);
+
+
 #endif /* _ASM_STACKTRACE_H */
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index 83bba33..ce82fbf 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -6,7 +6,8 @@ extra-y		:= head.o init_task.o vmlinux.lds
 
 obj-y		+= cpu-probe.o branch.o entry.o genex.o irq.o process.o \
 		   ptrace.o reset.o setup.o signal.o syscall.o \
-		   time.o topology.o traps.o unaligned.o watch.o vdso.o
+		   time.o topology.o traps.o unaligned.o watch.o vdso.o \
+		   user_backtrace.o
 
 ifdef CONFIG_FUNCTION_TRACER
 CFLAGS_REMOVE_ftrace.o = -pg
diff --git a/arch/mips/kernel/user_backtrace.c b/arch/mips/kernel/user_backtrace.c
new file mode 100644
index 0000000..cc1a8be
--- /dev/null
+++ b/arch/mips/kernel/user_backtrace.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2011  Daniel Kalmar
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License..
+ */
+
+#include <linux/uaccess.h>
+#include <linux/module.h>
+
+#include <asm/stacktrace.h>
+#include <asm/sections.h>
+#include <asm/inst.h>
+
+static inline int get_mem(unsigned long addr, unsigned long *result)
+{
+	unsigned long *address = (unsigned long *) addr;
+	if (!access_ok(VERIFY_READ, addr, sizeof(unsigned long)))
+		return -1;
+	if (__copy_from_user_inatomic(result, address, sizeof(unsigned long)))
+		return -3;
+	return 0;
+}
+
+/*
+ * These two instruction helpers were taken from process.c
+ */
+static inline int is_ra_save_ins(union mips_instruction *ip)
+{
+	/* sw / sd $ra, offset($sp) */
+	return (ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op)
+		&& ip->i_format.rs == 29 && ip->i_format.rt == 31;
+}
+
+static inline int is_sp_move_ins(union mips_instruction *ip)
+{
+	/* addiu/daddiu sp,sp,-imm */
+	if (ip->i_format.rs != 29 || ip->i_format.rt != 29)
+		return 0;
+	if (ip->i_format.opcode == addiu_op || ip->i_format.opcode == daddiu_op)
+		return 1;
+	return 0;
+}
+
+/*
+ * Looks for specific instructions that mark the end of a function.
+ * This usually means we ran into the code area of the previous function.
+ */
+static inline int is_end_of_function_marker(union mips_instruction *ip)
+{
+	/* jr ra */
+	if (ip->r_format.func == jr_op && ip->r_format.rs == 31)
+		return 1;
+	/* lui gp */
+	if (ip->i_format.opcode == lui_op && ip->i_format.rt == 28)
+		return 1;
+	return 0;
+}
+
+/*
+ * TODO for userspace stack unwinding:
+ * - handle cases where the stack is adjusted inside a function
+ *     (generally doesn't happen)
+ * - find optimal value for max_instr_check
+ * - try to find a way to handle leaf functions
+ */
+
+int unwind_user_frame(struct user_stackframe *old_frame,
+	    	const unsigned int max_instr_check)
+{
+	struct user_stackframe new_frame = *old_frame;
+	off_t ra_offset = 0;
+	size_t stack_size = 0;
+	unsigned long addr;
+
+	if (old_frame->pc == 0 || old_frame->sp == 0 || old_frame->ra == 0)
+		return -9;
+
+	for (addr = new_frame.pc; (addr + max_instr_check > new_frame.pc)
+		&& (!ra_offset || !stack_size); --addr) {
+		union mips_instruction ip;
+
+		if (get_mem(addr, (unsigned long *) &ip))
+			return -11;
+
+		if (is_sp_move_ins(&ip)) {
+			int stack_adjustment = ip.i_format.simmediate;
+			if (stack_adjustment > 0)
+				/* This marks the end of the previous function,
+				   which means we overran. */
+				break;
+			stack_size = (unsigned) stack_adjustment;
+		} else if (is_ra_save_ins(&ip)) {
+			int ra_slot = ip.i_format.simmediate;
+			if (ra_slot < 0)
+				/* This shouldn't happen. */
+				break;
+			ra_offset = ra_slot;
+		} else if (is_end_of_function_marker(&ip))
+			break;
+	}
+
+	if (!ra_offset || !stack_size)
+		return -1;
+
+	if (ra_offset) {
+		new_frame.ra = old_frame->sp + ra_offset;
+		if (get_mem(new_frame.ra, &(new_frame.ra)))
+			return -13;
+	}
+
+	if (stack_size) {
+		new_frame.sp = old_frame->sp + stack_size;
+		if (get_mem(new_frame.sp, &(new_frame.sp)))
+			return -14;
+	}
+
+	if (new_frame.sp > old_frame->sp)
+		return -2;
+
+	new_frame.pc = old_frame->ra;
+	*old_frame = new_frame;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(unwind_user_frame);
+
diff --git a/arch/mips/oprofile/backtrace.c b/arch/mips/oprofile/backtrace.c
index 6854ed5..265d26c 100644
--- a/arch/mips/oprofile/backtrace.c
+++ b/arch/mips/oprofile/backtrace.c
@@ -1,134 +1,11 @@
 #include <linux/oprofile.h>
 #include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/uaccess.h>
+
 #include <asm/ptrace.h>
 #include <asm/stacktrace.h>
-#include <linux/stacktrace.h>
-#include <linux/kernel.h>
-#include <asm/sections.h>
-#include <asm/inst.h>
-
-struct stackframe {
-	unsigned long sp;
-	unsigned long pc;
-	unsigned long ra;
-};
-
-static inline int get_mem(unsigned long addr, unsigned long *result)
-{
-	unsigned long *address = (unsigned long *) addr;
-	if (!access_ok(VERIFY_READ, addr, sizeof(unsigned long)))
-		return -1;
-	if (__copy_from_user_inatomic(result, address, sizeof(unsigned long)))
-		return -3;
-	return 0;
-}
-
-/*
- * These two instruction helpers were taken from process.c
- */
-static inline int is_ra_save_ins(union mips_instruction *ip)
-{
-	/* sw / sd $ra, offset($sp) */
-	return (ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op)
-		&& ip->i_format.rs == 29 && ip->i_format.rt == 31;
-}
-
-static inline int is_sp_move_ins(union mips_instruction *ip)
-{
-	/* addiu/daddiu sp,sp,-imm */
-	if (ip->i_format.rs != 29 || ip->i_format.rt != 29)
-		return 0;
-	if (ip->i_format.opcode == addiu_op || ip->i_format.opcode == daddiu_op)
-		return 1;
-	return 0;
-}
-
-/*
- * Looks for specific instructions that mark the end of a function.
- * This usually means we ran into the code area of the previous function.
- */
-static inline int is_end_of_function_marker(union mips_instruction *ip)
-{
-	/* jr ra */
-	if (ip->r_format.func == jr_op && ip->r_format.rs == 31)
-		return 1;
-	/* lui gp */
-	if (ip->i_format.opcode == lui_op && ip->i_format.rt == 28)
-		return 1;
-	return 0;
-}
-
-/*
- * TODO for userspace stack unwinding:
- * - handle cases where the stack is adjusted inside a function
- *     (generally doesn't happen)
- * - find optimal value for max_instr_check
- * - try to find a way to handle leaf functions
- */
-
-static inline int unwind_user_frame(struct stackframe *old_frame,
-				    const unsigned int max_instr_check)
-{
-	struct stackframe new_frame = *old_frame;
-	off_t ra_offset = 0;
-	size_t stack_size = 0;
-	unsigned long addr;
-
-	if (old_frame->pc == 0 || old_frame->sp == 0 || old_frame->ra == 0)
-		return -9;
-
-	for (addr = new_frame.pc; (addr + max_instr_check > new_frame.pc)
-		&& (!ra_offset || !stack_size); --addr) {
-		union mips_instruction ip;
-
-		if (get_mem(addr, (unsigned long *) &ip))
-			return -11;
-
-		if (is_sp_move_ins(&ip)) {
-			int stack_adjustment = ip.i_format.simmediate;
-			if (stack_adjustment > 0)
-				/* This marks the end of the previous function,
-				   which means we overran. */
-				break;
-			stack_size = (unsigned) stack_adjustment;
-		} else if (is_ra_save_ins(&ip)) {
-			int ra_slot = ip.i_format.simmediate;
-			if (ra_slot < 0)
-				/* This shouldn't happen. */
-				break;
-			ra_offset = ra_slot;
-		} else if (is_end_of_function_marker(&ip))
-			break;
-	}
-
-	if (!ra_offset || !stack_size)
-		return -1;
-
-	if (ra_offset) {
-		new_frame.ra = old_frame->sp + ra_offset;
-		if (get_mem(new_frame.ra, &(new_frame.ra)))
-			return -13;
-	}
-
-	if (stack_size) {
-		new_frame.sp = old_frame->sp + stack_size;
-		if (get_mem(new_frame.sp, &(new_frame.sp)))
-			return -14;
-	}
-
-	if (new_frame.sp > old_frame->sp)
-		return -2;
-
-	new_frame.pc = old_frame->ra;
-	*old_frame = new_frame;
-
-	return 0;
-}
 
 static inline void do_user_backtrace(unsigned long low_addr,
-				     struct stackframe *frame,
+				     struct user_stackframe *frame,
 				     unsigned int depth)
 {
 	const unsigned int max_instr_check = 512;
@@ -143,11 +20,11 @@ static inline void do_user_backtrace(unsigned long low_addr,
 
 #ifndef CONFIG_KALLSYMS
 static inline void do_kernel_backtrace(unsigned long low_addr,
-				       struct stackframe *frame,
+				       struct user_stackframe *frame,
 				       unsigned int depth) { }
 #else
 static inline void do_kernel_backtrace(unsigned long low_addr,
-				       struct stackframe *frame,
+				       struct user_stackframe *frame,
 				       unsigned int depth)
 {
 	while (depth-- && frame->pc) {
@@ -162,7 +39,7 @@ static inline void do_kernel_backtrace(unsigned long low_addr,
 
 void notrace op_mips_backtrace(struct pt_regs *const regs, unsigned int depth)
 {
-	struct stackframe frame = { .sp = regs->regs[29],
+	struct user_stackframe frame = { .sp = regs->regs[29],
 				    .pc = regs->cp0_epc,
 				    .ra = regs->regs[31] };
 	const int userspace = user_mode(regs);
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/2] MIPS: Implement perf_callchain_user using unwind_user_frame
  2011-08-11  0:36 [PATCH 0/2] Implement perf_callchain_user Holger Hans Peter Freyther
  2011-08-11  0:36 ` [PATCH 1/2] MIPS: Move userspace stack unwinding into kernel/user_backtrace.c Holger Hans Peter Freyther
@ 2011-08-11  0:36 ` Holger Hans Peter Freyther
  2011-08-22 17:32 ` [PATCH 0/2] Implement perf_callchain_user Holger Freyther
  2 siblings, 0 replies; 8+ messages in thread
From: Holger Hans Peter Freyther @ 2011-08-11  0:36 UTC (permalink / raw)
  To: linux-mips; +Cc: Holger Hans Peter Freyther, Holger Freyther

Implement perf_callchain_user using the unwind_user_frame
method, allow up to PAGE_SIZE / 4 instructions to be checked.

Signed-off-by: Holger Freyther <holger@moiji-mobile.com>
---
 arch/mips/kernel/perf_event.c |   14 ++++++++++++++
 1 files changed, 14 insertions(+), 0 deletions(-)

diff --git a/arch/mips/kernel/perf_event.c b/arch/mips/kernel/perf_event.c
index 0aee944..7ea4d3c 100644
--- a/arch/mips/kernel/perf_event.c
+++ b/arch/mips/kernel/perf_event.c
@@ -540,6 +540,20 @@ handle_associated_event(struct cpu_hw_events *cpuc,
 void perf_callchain_user(struct perf_callchain_entry *entry,
 		    struct pt_regs *regs)
 {
+	struct user_stackframe frame = { .sp = regs->regs[29],
+				    .pc = regs->cp0_epc,
+				    .ra = regs->regs[31] };
+	const unsigned long low_addr = ALIGN(frame.sp, THREAD_SIZE);
+	const unsigned int max_instr_check = PAGE_SIZE / 4;
+	const unsigned long high_addr = low_addr + THREAD_SIZE;
+
+
+	while (entry->nr < PERF_MAX_STACK_DEPTH &&
+			!unwind_user_frame(&frame, max_instr_check)) {
+		perf_callchain_store(entry, frame.ra);
+		if (frame.sp < low_addr || frame.sp > high_addr)
+			break;
+	}
 }
 
 static void save_raw_perf_callchain(struct perf_callchain_entry *entry,
-- 
1.7.4.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 0/2] Implement perf_callchain_user
  2011-08-11  0:36 [PATCH 0/2] Implement perf_callchain_user Holger Hans Peter Freyther
  2011-08-11  0:36 ` [PATCH 1/2] MIPS: Move userspace stack unwinding into kernel/user_backtrace.c Holger Hans Peter Freyther
  2011-08-11  0:36 ` [PATCH 2/2] MIPS: Implement perf_callchain_user using unwind_user_frame Holger Hans Peter Freyther
@ 2011-08-22 17:32 ` Holger Freyther
  2014-04-21  8:51   ` Holger Freyther
  2 siblings, 1 reply; 8+ messages in thread
From: Holger Freyther @ 2011-08-22 17:32 UTC (permalink / raw)
  To: linux-mips

Holger Hans Peter Freyther <zecke <at> selfish.org> writes:

> 
> Hi,
> this is moving code from oprofile/backtrace.c to a commom
> place and then implements perf_callchain_user using the common
> code. Right now the unwind_user_frame will always be compiled
> into the kernel.

Comments? Should this go somewhere else?

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 0/2] Implement perf_callchain_user
  2011-08-22 17:32 ` [PATCH 0/2] Implement perf_callchain_user Holger Freyther
@ 2014-04-21  8:51   ` Holger Freyther
  2014-04-22  0:31     ` David Daney
  0 siblings, 1 reply; 8+ messages in thread
From: Holger Freyther @ 2014-04-21  8:51 UTC (permalink / raw)
  To: linux-mips

Holger Freyther <zecke <at> selfish.org> writes:


> 
> Comments? Should this go somewhere else?

looking at the latest kernel userspace backtrace support does
not appear to be implemented for perf? Do you intend to support
it anytime soon?

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 0/2] Implement perf_callchain_user
  2014-04-21  8:51   ` Holger Freyther
@ 2014-04-22  0:31     ` David Daney
  2014-04-22  6:36       ` Holger Hans Peter Freyther
  0 siblings, 1 reply; 8+ messages in thread
From: David Daney @ 2014-04-22  0:31 UTC (permalink / raw)
  To: Holger Freyther; +Cc: linux-mips

On 04/21/2014 01:51 AM, Holger Freyther wrote:
> Holger Freyther <zecke <at> selfish.org> writes:
>
>
>>
>> Comments? Should this go somewhere else?
>
> looking at the latest kernel userspace backtrace support does
> not appear to be implemented for perf? Do you intend to support
> it anytime soon?
>

I implemented it for MIPS, the patches are on the relevant mailing 
lists.  Perhaps some day they will get merged.

David Daney

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 0/2] Implement perf_callchain_user
  2014-04-22  0:31     ` David Daney
@ 2014-04-22  6:36       ` Holger Hans Peter Freyther
  2014-04-22 21:37         ` David Daney
  0 siblings, 1 reply; 8+ messages in thread
From: Holger Hans Peter Freyther @ 2014-04-22  6:36 UTC (permalink / raw)
  To: David Daney; +Cc: linux-mips

On Mon, Apr 21, 2014 at 05:31:32PM -0700, David Daney wrote:

Hi!

> I implemented it for MIPS, the patches are on the relevant mailing lists.
> Perhaps some day they will get merged.

this was a ping for my patches from 2011. Is linux-mips following a
different review/patch posting scheme? 

cheers
	holger

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 0/2] Implement perf_callchain_user
  2014-04-22  6:36       ` Holger Hans Peter Freyther
@ 2014-04-22 21:37         ` David Daney
  0 siblings, 0 replies; 8+ messages in thread
From: David Daney @ 2014-04-22 21:37 UTC (permalink / raw)
  To: Holger Hans Peter Freyther; +Cc: linux-mips

On 04/21/2014 11:36 PM, Holger Hans Peter Freyther wrote:
> On Mon, Apr 21, 2014 at 05:31:32PM -0700, David Daney wrote:
>
> Hi!
>
>> I implemented it for MIPS, the patches are on the relevant mailing lists.
>> Perhaps some day they will get merged.
>
> this was a ping for my patches from 2011. Is linux-mips following a
> different review/patch posting scheme?
>

That was unclear.  Now that almost three years have passed, the only 
reasonable thing to do is resend the patches rebased against the current 
kernel.

That said, given the fact that stackframe analysis is not reliable, 
coupled with the fact that we have DWARF based unwinding of userspace 
threads working in perf with captured stack images, makes me think that 
the patches should not be merged.

David Daney



> cheers
> 	holger
>

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2014-04-22 21:37 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-08-11  0:36 [PATCH 0/2] Implement perf_callchain_user Holger Hans Peter Freyther
2011-08-11  0:36 ` [PATCH 1/2] MIPS: Move userspace stack unwinding into kernel/user_backtrace.c Holger Hans Peter Freyther
2011-08-11  0:36 ` [PATCH 2/2] MIPS: Implement perf_callchain_user using unwind_user_frame Holger Hans Peter Freyther
2011-08-22 17:32 ` [PATCH 0/2] Implement perf_callchain_user Holger Freyther
2014-04-21  8:51   ` Holger Freyther
2014-04-22  0:31     ` David Daney
2014-04-22  6:36       ` Holger Hans Peter Freyther
2014-04-22 21:37         ` David Daney

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.