From owner-svn-src-head@FreeBSD.ORG Wed Sep 17 02:43:48 2014 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 5FF6A3B2; Wed, 17 Sep 2014 02:43:48 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 4A36E16A; Wed, 17 Sep 2014 02:43:48 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id s8H2hmP9047080; Wed, 17 Sep 2014 02:43:48 GMT (envelope-from jhibbits@FreeBSD.org) Received: (from jhibbits@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id s8H2hlei047078; Wed, 17 Sep 2014 02:43:47 GMT (envelope-from jhibbits@FreeBSD.org) Message-Id: <201409170243.s8H2hlei047078@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: jhibbits set sender to jhibbits@FreeBSD.org using -f From: Justin Hibbits Date: Wed, 17 Sep 2014 02:43:47 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r271697 - in head/sys/cddl/dev: dtrace/powerpc fbt/powerpc X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 17 Sep 2014 02:43:48 -0000 Author: jhibbits Date: Wed Sep 17 02:43:47 2014 New Revision: 271697 URL: http://svnweb.freebsd.org/changeset/base/271697 Log: Fix the stack tracing for dtrace/powerpc. Summary: Fix the stack tracing for dtrace/powerpc by using the trapexit/asttrapexit return address sentinels instead of checking within the kernel address space. As part of this, I had to add new inline functions. FBT traces the kernel, so we have to have special case handling for this, since a trap will create a full new trap frame, and there's no way to pass around the 'real' stack. I handle this by special-casing 'aframes == 0' with the trap frame. If aframes counts out to the trap frame, then assume we're looking for the full kernel trap frame, so switch to the real stack pointer. Test Plan: Tested on powerpc64 Reviewers: rpaulo, markj, nwhitehorn Reviewed By: markj, nwhitehorn Differential Revision: https://reviews.freebsd.org/D788 MFC after: 3 week Relnotes: Yes Modified: head/sys/cddl/dev/dtrace/powerpc/dtrace_isa.c head/sys/cddl/dev/fbt/powerpc/fbt_isa.c Modified: head/sys/cddl/dev/dtrace/powerpc/dtrace_isa.c ============================================================================== --- head/sys/cddl/dev/dtrace/powerpc/dtrace_isa.c Wed Sep 17 02:32:22 2014 (r271696) +++ head/sys/cddl/dev/dtrace/powerpc/dtrace_isa.c Wed Sep 17 02:43:47 2014 (r271697) @@ -52,9 +52,103 @@ /* Offset to LR Save word (ppc64). CR Save area sits between back chain and LR */ #define RETURN_OFFSET64 16 +#ifdef __powerpc64__ +#define OFFSET 4 /* Account for the TOC reload slot */ +#else +#define OFFSET 0 +#endif + #define INKERNEL(x) ((x) <= VM_MAX_KERNEL_ADDRESS && \ (x) >= VM_MIN_KERNEL_ADDRESS) +static __inline int +dtrace_sp_inkernel(uintptr_t sp, int aframes) +{ + vm_offset_t callpc; + +#ifdef __powerpc64__ + callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64); +#else + callpc = *(vm_offset_t *)(sp + RETURN_OFFSET); +#endif + if ((callpc & 3) || (callpc < 0x100)) + return (0); + + /* + * trapexit() and asttrapexit() are sentinels + * for kernel stack tracing. + * + * Special-case this for 'aframes == 0', because fbt sets aframes to the + * trap callchain depth, so we want to break out of it. + */ + if ((callpc + OFFSET == (vm_offset_t) &trapexit || + callpc + OFFSET == (vm_offset_t) &asttrapexit) && + aframes != 0) + return (0); + + return (1); +} + +static __inline uintptr_t +dtrace_next_sp(uintptr_t sp) +{ + vm_offset_t callpc; + +#ifdef __powerpc64__ + callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64); +#else + callpc = *(vm_offset_t *)(sp + RETURN_OFFSET); +#endif + + /* + * trapexit() and asttrapexit() are sentinels + * for kernel stack tracing. + * + * Special-case this for 'aframes == 0', because fbt sets aframes to the + * trap callchain depth, so we want to break out of it. + */ + if ((callpc + OFFSET == (vm_offset_t) &trapexit || + callpc + OFFSET == (vm_offset_t) &asttrapexit)) + /* Access the trap frame */ +#ifdef __powerpc64__ + return (*(uintptr_t *)sp + 48 + sizeof(register_t)); +#else + return (*(uintptr_t *)sp + 8 + sizeof(register_t)); +#endif + + return (*(uintptr_t*)sp); +} + +static __inline uintptr_t +dtrace_get_pc(uintptr_t sp) +{ + vm_offset_t callpc; + +#ifdef __powerpc64__ + callpc = *(vm_offset_t *)(sp + RETURN_OFFSET64); +#else + callpc = *(vm_offset_t *)(sp + RETURN_OFFSET); +#endif + + /* + * trapexit() and asttrapexit() are sentinels + * for kernel stack tracing. + * + * Special-case this for 'aframes == 0', because fbt sets aframes to the + * trap callchain depth, so we want to break out of it. + */ + if ((callpc + OFFSET == (vm_offset_t) &trapexit || + callpc + OFFSET == (vm_offset_t) &asttrapexit)) + /* Access the trap frame */ +#ifdef __powerpc64__ + return (*(uintptr_t *)sp + 48 + offsetof(struct trapframe, lr)); +#else + return (*(uintptr_t *)sp + 8 + offsetof(struct trapframe, lr)); +#endif + + return (callpc); +} + greg_t dtrace_getfp(void) { @@ -66,10 +160,11 @@ dtrace_getpcstack(pc_t *pcstack, int pcs uint32_t *intrpc) { int depth = 0; - register_t sp; + uintptr_t osp, sp; vm_offset_t callpc; pc_t caller = (pc_t) solaris_cpu[curcpu].cpu_dtrace_caller; + osp = PAGE_SIZE; if (intrpc != 0) pcstack[depth++] = (pc_t) intrpc; @@ -78,17 +173,12 @@ dtrace_getpcstack(pc_t *pcstack, int pcs sp = dtrace_getfp(); while (depth < pcstack_limit) { - if (!INKERNEL((long) sp)) + if (sp <= osp) break; -#ifdef __powerpc64__ - callpc = *(uintptr_t *)(sp + RETURN_OFFSET64); -#else - callpc = *(uintptr_t *)(sp + RETURN_OFFSET); -#endif - - if (!INKERNEL(callpc)) + if (!dtrace_sp_inkernel(sp, aframes)) break; + callpc = dtrace_get_pc(sp); if (aframes > 0) { aframes--; @@ -100,7 +190,8 @@ dtrace_getpcstack(pc_t *pcstack, int pcs pcstack[depth++] = callpc; } - sp = *(uintptr_t*)sp; + osp = sp; + sp = dtrace_next_sp(sp); } for (; depth < pcstack_limit; depth++) { @@ -368,8 +459,11 @@ dtrace_getarg(int arg, int aframes) * On ppc32 AIM, and booke, trapexit() is the immediately following * label. On ppc64 AIM trapexit() follows a nop. */ - if (((long)(fp[1]) == (long)trapexit) || - (((long)(fp[1]) + 4 == (long)trapexit))) { +#ifdef __powerpc64__ + if ((long)(fp[2]) + 4 == (long)trapexit) { +#else + if ((long)(fp[1]) == (long)trapexit) { +#endif /* * In the case of powerpc, we will use the pointer to the regs * structure that was pushed when we took the trap. To get this @@ -433,23 +527,31 @@ int dtrace_getstackdepth(int aframes) { int depth = 0; - register_t sp; + uintptr_t osp, sp; + vm_offset_t callpc; + osp = PAGE_SIZE; aframes++; sp = dtrace_getfp(); depth++; for(;;) { - if (!INKERNEL((long) sp)) + if (sp <= osp) break; - if (!INKERNEL((long) *(void **)sp)) + + if (!dtrace_sp_inkernel(sp, aframes)) break; - depth++; + + if (aframes == 0) + depth++; + else + aframes--; + osp = sp; sp = *(uintptr_t *)sp; } if (depth < aframes) - return 0; - else - return depth - aframes; + return (0); + + return (depth); } ulong_t Modified: head/sys/cddl/dev/fbt/powerpc/fbt_isa.c ============================================================================== --- head/sys/cddl/dev/fbt/powerpc/fbt_isa.c Wed Sep 17 02:32:22 2014 (r271696) +++ head/sys/cddl/dev/fbt/powerpc/fbt_isa.c Wed Sep 17 02:43:47 2014 (r271697) @@ -147,7 +147,7 @@ fbt_provide_module_function(linker_file_ fbt = malloc(sizeof (fbt_probe_t), M_FBT, M_WAITOK | M_ZERO); fbt->fbtp_name = name; fbt->fbtp_id = dtrace_probe_create(fbt_id, modname, - name, FBT_ENTRY, 3, fbt); + name, FBT_ENTRY, 7, fbt); fbt->fbtp_patchpoint = instr; fbt->fbtp_ctl = lf; fbt->fbtp_loadcnt = lf->loadcnt; @@ -210,7 +210,7 @@ again: if (retfbt == NULL) { fbt->fbtp_id = dtrace_probe_create(fbt_id, modname, - name, FBT_RETURN, 5, fbt); + name, FBT_RETURN, 7, fbt); } else { retfbt->fbtp_next = fbt; fbt->fbtp_id = retfbt->fbtp_id;