[PATCH] Oprofile backtrace support for e500

Andy Fleming afleming at freescale.com
Thu Oct 13 08:37:54 EST 2005


Signed-off-by Andy Fleming <afleming at freescale.com>

* Added support for callgraphs (ie backtracing)

---
commit f3bcff9f931bdd36e8cd527408418ed5f3f7a85b
tree d08362251f25801221ff2c71e0371757b1fc49d0
parent 3294b2b37eb56ee4ad287776998293485a7c122e
author Andrew Fleming <afleming at freescale.com> Wed, 12 Oct 2005 16:09:23 -0500
committer Andrew Fleming <afleming at freescale.com> Wed, 12 Oct 2005 16:09:23 -0500

 arch/ppc/oprofile/Makefile             |    2 -
 arch/ppc/oprofile/backtrace.c          |  126 ++++++++++++++++++++++++++++++++
 arch/ppc/oprofile/common.c             |    6 +-
 arch/ppc/oprofile/op_model_fsl_booke.c |    7 --
 4 files changed, 133 insertions(+), 8 deletions(-)

diff --git a/arch/ppc/oprofile/Makefile b/arch/ppc/oprofile/Makefile
--- a/arch/ppc/oprofile/Makefile
+++ b/arch/ppc/oprofile/Makefile
@@ -6,7 +6,7 @@ DRIVER_OBJS := $(addprefix ../../../driv
 		oprofilefs.o oprofile_stats.o \
 		timer_int.o )
 
-oprofile-y := $(DRIVER_OBJS) common.o
+oprofile-y := $(DRIVER_OBJS) common.o backtrace.o
 
 ifeq ($(CONFIG_FSL_BOOKE),y)
 	oprofile-y += op_model_fsl_booke.o
diff --git a/arch/ppc/oprofile/backtrace.c b/arch/ppc/oprofile/backtrace.c
new file mode 100644
--- /dev/null
+++ b/arch/ppc/oprofile/backtrace.c
@@ -0,0 +1,126 @@
+/*
+ * PPC 32 oprofile support
+ * Based on PPC64 oprofile backtrace support
+ * Copyright (C) 2005 Brian Rogan <bcr6 at cornell.edu>, IBM
+ *
+ * Copyright (C) Freescale Semiconductor, Inc 2005
+ *
+ * Author: Andy Fleming
+ *
+ * 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, or (at your option) any later version.
+ */
+
+#include <linux/oprofile.h>
+#include <linux/sched.h>
+#include <asm/processor.h>
+#include <asm/uaccess.h>
+
+static unsigned int user_putsp32(unsigned int sp, int *is_first) {
+	unsigned int stack_frame[2], rv;
+	unsigned long t = sp;
+
+	/* If the page isn't accessible, then we've done all that we can do,
+	 * a partial stack trace is better than none. 
+	*/
+	rv = __copy_from_user_inatomic(stack_frame, (void *) t, sizeof(stack_frame));
+	if(rv != 0) {
+		/* The most likely reason for this is that we returned -EFAULT, 
+		 * which means that we've done all that we can do from interrupt 
+		 * context.  All other errors though are equally valid reasons to
+		 * abort our backtrace. */
+		return 0;
+	}
+
+
+	/* SVR4 compliant executables have the Link Register offset by 4 bytes 
+	 * from the beginning of the stack page */
+	//printk("Link was: %p\n", stack_frame[1]);
+	if(! *is_first) {
+		oprofile_add_trace(stack_frame[1]);
+	} else {
+		*is_first = 0;
+	}
+
+	/* Sanity check to make sure that the previous stack frame is actually above
+	 * us in memory, like we would expect it to be from the PPC spec. 
+ 	 * 
+	 * The last stack pointer is always at offset 0 from the beginning of the 
+   	 * stack frame.
+	 */
+	rv = stack_frame[0];
+	if(rv > sp) {
+		return rv;
+	} else {
+		return 0;
+	}
+}
+
+static int validate_sp(unsigned long sp)
+{
+	unsigned long prev_sp;
+	unsigned long stack_top;
+
+	prev_sp = (unsigned long) (current->thread_info + 1);
+	stack_top = (unsigned long) current->thread_info + THREAD_SIZE;
+
+	if (sp > prev_sp && sp < stack_top && (sp & 3) == 0)
+		return 1;
+
+	return 0;
+}
+
+static unsigned long kernel_putsp32(unsigned long sp, int *is_first) {
+	unsigned long * stack_frame = (unsigned long *) sp;
+	unsigned long rv;
+
+	if(!validate_sp(sp)) {
+		return 0;
+	}
+
+	//printk("Link was: %p\n", stack_frame[1]);
+	if(! *is_first) {
+		/* Same as before LR is offset 4 bytes from the beginning */
+		oprofile_add_trace(stack_frame[1]);		
+	} else {
+		*is_first = 0;
+	}
+
+	rv = stack_frame[0];
+	if(rv > sp) {
+		return rv;
+	} else {
+		return 0;
+	}
+}
+
+
+void
+op_ppc32_backtrace(struct pt_regs * const regs, unsigned int depth)
+{
+	unsigned long cursp = regs->gpr[1];
+	int first_frame = 1;
+
+	//printk("backtracing\n");
+	if (!user_mode(regs)) {
+		unsigned long sp = cursp;
+		while (depth--)
+		{
+			sp = kernel_putsp32(sp, &first_frame);
+			if(!sp) {
+				break;
+			}
+		}
+		return;
+	} else {
+		unsigned long sp = cursp;	
+		while(depth--) {
+			sp = user_putsp32(sp, &first_frame);
+			if(!sp) {
+				break;
+			}
+		}
+	}
+}
diff --git a/arch/ppc/oprofile/common.c b/arch/ppc/oprofile/common.c
--- a/arch/ppc/oprofile/common.c
+++ b/arch/ppc/oprofile/common.c
@@ -84,6 +84,9 @@ static void op_ppc32_stop(void)
 	on_each_cpu(op_ppc32_cpu_stop, NULL, 0, 1);
 }
 
+extern void 
+op_ppc32_backtrace(struct pt_regs * const regs, unsigned int depth);
+
 static int op_ppc32_create_files(struct super_block *sb, struct dentry *root)
 {
 	int i;
@@ -121,7 +124,8 @@ static struct oprofile_operations oprof_
 	.shutdown	= op_ppc32_shutdown,
 	.start		= op_ppc32_start,
 	.stop		= op_ppc32_stop,
-	.cpu_type	= NULL		/* To be filled in below. */
+	.cpu_type	= NULL,		/* To be filled in below. */
+	.backtrace	= op_ppc32_backtrace,
 };
 
 int __init oprofile_arch_init(struct oprofile_operations *ops)
diff --git a/arch/ppc/oprofile/op_model_fsl_booke.c b/arch/ppc/oprofile/op_model_fsl_booke.c
--- a/arch/ppc/oprofile/op_model_fsl_booke.c
+++ b/arch/ppc/oprofile/op_model_fsl_booke.c
@@ -146,22 +146,17 @@ static void fsl_booke_stop(void)
 static void fsl_booke_handle_interrupt(struct pt_regs *regs,
 				    struct op_counter_config *ctr)
 {
-	unsigned long pc;
-	int is_kernel;
 	int val;
 	int i;
 
 	/* set the PMM bit (see comment below) */
 	mtmsr(mfmsr() | MSR_PMM);
 
-	pc = regs->nip;
-	is_kernel = (pc >= KERNELBASE);
-
 	for (i = 0; i < num_counters; ++i) {
 		val = ctr_read(i);
 		if (val < 0) {
 			if (oprofile_running && ctr[i].enabled) {
-				oprofile_add_pc(pc, is_kernel, i);
+				oprofile_add_sample(regs, i);
 				ctr_write(i, reset_value[i]);
 			} else {
 				ctr_write(i, 0);

* Removed commented code

---
commit 7f50cb2cd6153dda4d999b13418dd8e3609def5c
tree 47ddd0af393ee7cb8dfa911fe5c3d383865fc217
parent f3bcff9f931bdd36e8cd527408418ed5f3f7a85b
author Andrew Fleming <afleming at freescale.com> Wed, 12 Oct 2005 16:12:05 -0500
committer Andrew Fleming <afleming at freescale.com> Wed, 12 Oct 2005 16:12:05 -0500

 arch/ppc/oprofile/backtrace.c |    3 ---
 1 files changed, 0 insertions(+), 3 deletions(-)

diff --git a/arch/ppc/oprofile/backtrace.c b/arch/ppc/oprofile/backtrace.c
--- a/arch/ppc/oprofile/backtrace.c
+++ b/arch/ppc/oprofile/backtrace.c
@@ -37,7 +37,6 @@ static unsigned int user_putsp32(unsigne
 
 	/* SVR4 compliant executables have the Link Register offset by 4 bytes 
 	 * from the beginning of the stack page */
-	//printk("Link was: %p\n", stack_frame[1]);
 	if(! *is_first) {
 		oprofile_add_trace(stack_frame[1]);
 	} else {
@@ -80,7 +79,6 @@ static unsigned long kernel_putsp32(unsi
 		return 0;
 	}
 
-	//printk("Link was: %p\n", stack_frame[1]);
 	if(! *is_first) {
 		/* Same as before LR is offset 4 bytes from the beginning */
 		oprofile_add_trace(stack_frame[1]);		
@@ -103,7 +101,6 @@ op_ppc32_backtrace(struct pt_regs * cons
 	unsigned long cursp = regs->gpr[1];
 	int first_frame = 1;
 
-	//printk("backtracing\n");
 	if (!user_mode(regs)) {
 		unsigned long sp = cursp;
 		while (depth--)



More information about the Linuxppc-embedded mailing list