Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 13 Jun 2012 06:38:26 +0000 (UTC)
From:      Fabien Thomas <fabient@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r236997 - in head/sys: arm/include dev/hwpmc
Message-ID:  <201206130638.q5D6cQvD001663@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: fabient
Date: Wed Jun 13 06:38:25 2012
New Revision: 236997
URL: http://svn.freebsd.org/changeset/base/236997

Log:
  Add ARM callchain support for hwpmc.
  
  Sponsored by: NETASQ
  MFC after:	3 days

Modified:
  head/sys/arm/include/pmc_mdep.h
  head/sys/dev/hwpmc/hwpmc_arm.c

Modified: head/sys/arm/include/pmc_mdep.h
==============================================================================
--- head/sys/arm/include/pmc_mdep.h	Wed Jun 13 06:19:08 2012	(r236996)
+++ head/sys/arm/include/pmc_mdep.h	Wed Jun 13 06:38:25 2012	(r236997)
@@ -50,9 +50,17 @@ union pmc_md_pmc {
 	struct pmc_md_xscale_pmc	pm_xscale;
 };
 
-#define	PMC_TRAPFRAME_TO_PC(TF)	((TF)->tf_pc)
-#define	PMC_TRAPFRAME_TO_FP(TF)	((TF)->tf_usr_lr)
-#define	PMC_TRAPFRAME_TO_SP(TF)	((TF)->tf_usr_sp)
+#define	PMC_IN_KERNEL_STACK(S,START,END)		\
+	((S) >= (START) && (S) < (END))
+#define	PMC_IN_KERNEL(va) (((va) >= USRSTACK) &&	\
+	((va) < VM_MAX_KERNEL_ADDRESS))
+
+#define	PMC_IN_USERSPACE(va) ((va) <= VM_MAXUSER_ADDRESS)
+
+#define	PMC_TRAPFRAME_TO_PC(TF)		((TF)->tf_pc)
+#define	PMC_TRAPFRAME_TO_FP(TF)		((TF)->tf_r11)
+#define	PMC_TRAPFRAME_TO_SVC_SP(TF)	((TF)->tf_svc_sp)
+#define	PMC_TRAPFRAME_TO_USR_SP(TF)	((TF)->tf_usr_sp)
 
 /* Build a fake kernel trapframe from current instruction pointer. */
 #define PMC_FAKE_TRAPFRAME(TF)						\

Modified: head/sys/dev/hwpmc/hwpmc_arm.c
==============================================================================
--- head/sys/dev/hwpmc/hwpmc_arm.c	Wed Jun 13 06:19:08 2012	(r236996)
+++ head/sys/dev/hwpmc/hwpmc_arm.c	Wed Jun 13 06:38:25 2012	(r236997)
@@ -30,10 +30,16 @@ __FBSDID("$FreeBSD$");
 
 #include <sys/param.h>
 #include <sys/pmc.h>
+#include <sys/proc.h>
 #include <sys/systm.h>
 
-#include <machine/pmc_mdep.h>
+#include <machine/cpu.h>
 #include <machine/md_var.h>
+#include <machine/pmc_mdep.h>
+
+#include <vm/vm.h>
+#include <vm/vm_param.h>
+#include <vm/pmap.h>
 
 struct pmc_mdep *
 pmc_md_initialize()
@@ -58,27 +64,101 @@ pmc_md_finalize(struct pmc_mdep *md)
 #endif
 }
 
-static int
-pmc_save_callchain(uintptr_t *cc, int maxsamples,
-    struct trapframe *tf)
-{
-
-	*cc = PMC_TRAPFRAME_TO_PC(tf);
-	return (1);
-}
-
 int
 pmc_save_kernel_callchain(uintptr_t *cc, int maxsamples,
     struct trapframe *tf)
 {
+	uintptr_t pc, r, stackstart, stackend, fp;
+	struct thread *td;
+	int count;
+
+	KASSERT(TRAPF_USERMODE(tf) == 0,("[arm,%d] not a kernel backtrace",
+	    __LINE__));
+
+	pc = PMC_TRAPFRAME_TO_PC(tf);
+	*cc++ = pc;
+
+	if ((td = curthread) == NULL)
+		return (1);
+
+	if (maxsamples <= 1)
+		return (1);
+
+	stackstart = (uintptr_t) td->td_kstack;
+	stackend = (uintptr_t) td->td_kstack + td->td_kstack_pages * PAGE_SIZE;
+	fp = PMC_TRAPFRAME_TO_FP(tf);
+
+	if (!PMC_IN_KERNEL(pc) ||
+	    !PMC_IN_KERNEL_STACK(fp, stackstart, stackend))
+		return (1);
+
+	for (count = 1; count < maxsamples; count++) {
+		/* Use saved lr as pc. */
+		r = fp - sizeof(uintptr_t);
+		if (!PMC_IN_KERNEL_STACK(r, stackstart, stackend))
+			break;
+		pc = *(uintptr_t *)r;
+		if (!PMC_IN_KERNEL(pc))
+			break;
+
+		*cc++ = pc;
+
+		/* Switch to next frame up */
+		r = fp - 3 * sizeof(uintptr_t);
+		if (!PMC_IN_KERNEL_STACK(r, stackstart, stackend))
+			break;
+		fp = *(uintptr_t *)r;
+		if (!PMC_IN_KERNEL_STACK(fp, stackstart, stackend))
+			break;
+	}
 
-	return pmc_save_callchain(cc, maxsamples, tf);
+	return (count);
 }
 
 int
 pmc_save_user_callchain(uintptr_t *cc, int maxsamples,
     struct trapframe *tf)
 {
+	uintptr_t pc, r, oldfp, fp;
+	struct thread *td;
+	int count;
+
+	KASSERT(TRAPF_USERMODE(tf), ("[x86,%d] Not a user trap frame tf=%p",
+	    __LINE__, (void *) tf));
+
+	pc = PMC_TRAPFRAME_TO_PC(tf);
+	*cc++ = pc;
+
+	if ((td = curthread) == NULL)
+		return (1);
+
+	if (maxsamples <= 1)
+		return (1);
+
+	oldfp = fp = PMC_TRAPFRAME_TO_FP(tf);
+
+	if (!PMC_IN_USERSPACE(pc) ||
+	    !PMC_IN_USERSPACE(fp))
+		return (1);
+
+	for (count = 1; count < maxsamples; count++) {
+		/* Use saved lr as pc. */
+		r = fp - sizeof(uintptr_t);
+		if (copyin((void *)r, &pc, sizeof(pc)) != 0)
+			break;
+		if (!PMC_IN_USERSPACE(pc))
+			break;
+
+		*cc++ = pc;
+
+		/* Switch to next frame up */
+		oldfp = fp;
+		r = fp - 3 * sizeof(uintptr_t);
+		if (copyin((void *)r, &fp, sizeof(fp)) != 0)
+			break;
+		if (fp < oldfp || !PMC_IN_USERSPACE(fp))
+			break;
+	}
 
-	return pmc_save_callchain(cc, maxsamples, tf);
+	return (count);
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201206130638.q5D6cQvD001663>