From owner-svn-src-head@FreeBSD.ORG Thu Mar 5 17:55:33 2015 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 825B3354; Thu, 5 Mar 2015 17:55:33 +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 6C2F3E18; Thu, 5 Mar 2015 17:55:33 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.9/8.14.9) with ESMTP id t25HtXWN084196; Thu, 5 Mar 2015 17:55:33 GMT (envelope-from andrew@FreeBSD.org) Received: (from andrew@localhost) by svn.freebsd.org (8.14.9/8.14.9/Submit) id t25HtVtg084188; Thu, 5 Mar 2015 17:55:31 GMT (envelope-from andrew@FreeBSD.org) Message-Id: <201503051755.t25HtVtg084188@svn.freebsd.org> X-Authentication-Warning: svn.freebsd.org: andrew set sender to andrew@FreeBSD.org using -f From: Andrew Turner Date: Thu, 5 Mar 2015 17:55:31 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r279667 - in head/sys: arm/arm cddl/contrib/opensolaris/uts/common/sys cddl/dev/dtrace/arm cddl/dev/fbt/arm 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: Thu, 05 Mar 2015 17:55:33 -0000 Author: andrew Date: Thu Mar 5 17:55:31 2015 New Revision: 279667 URL: https://svnweb.freebsd.org/changeset/base/279667 Log: Add the MD parts of dtrace needed to use fbt on ARM. For this we need to emulate the instructions used in function entry and exit. For function entry ARM will use a push instruction to push up to 16 registers to the stack. While we don't expect all 16 to be used we need to handle any combination the compiler may generate, even if it doesn't make sense (e.g. pushing the program counter). On function return we will either have a pop or branch instruction. The former is similar to the push instruction, but with care to make sure we update the stack pointer and program counter correctly in the cases they are either in the list of registers or not. For branch we need to take the 24-bit offset, sign-extend it, and add that number of 4-byte words to the program counter. Care needs to be taken as, due to historical reasons, the address the branch is relative to is not the current instruction, but 8 bytes later. This allows us to use the following probes on ARM boards: dtrace -n 'fbt::malloc:entry { stack() }' and dtrace -n 'fbt::free:return { stack() }' Differential Revision: https://reviews.freebsd.org/D2007 Reviewed by: gnn, rpaulo Sponsored by: ABT Systems Ltd Modified: head/sys/arm/arm/db_trace.c head/sys/arm/arm/exception.S head/sys/arm/arm/undefined.c head/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h head/sys/cddl/dev/dtrace/arm/dtrace_subr.c head/sys/cddl/dev/fbt/arm/fbt_isa.c Modified: head/sys/arm/arm/db_trace.c ============================================================================== --- head/sys/arm/arm/db_trace.c Thu Mar 5 17:17:11 2015 (r279666) +++ head/sys/arm/arm/db_trace.c Thu Mar 5 17:55:31 2015 (r279667) @@ -66,7 +66,7 @@ db_stack_trace_cmd(struct unwind_state * finished = false; while (!finished) { - finished = unwind_stack_one(state, 0); + finished = unwind_stack_one(state, 1); /* Print the frame details */ sym = db_search_symbol(state->start_pc, DB_STGY_ANY, &offset); Modified: head/sys/arm/arm/exception.S ============================================================================== --- head/sys/arm/arm/exception.S Thu Mar 5 17:17:11 2015 (r279666) +++ head/sys/arm/arm/exception.S Thu Mar 5 17:55:31 2015 (r279667) @@ -57,11 +57,6 @@ __FBSDID("$FreeBSD$"); #ifdef KDTRACE_HOOKS .bss .align 4 - .global _C_LABEL(dtrace_invop_jump_addr) -_C_LABEL(dtrace_invop_jump_addr): - .word 0 - .word 0 - .global _C_LABEL(dtrace_invop_calltrap_addr) _C_LABEL(dtrace_invop_calltrap_addr): .word 0 @@ -162,7 +157,8 @@ _C_LABEL(dtrace_invop_calltrap_addr): msr cpsr_c, r2; /* Punch into SVC mode */ \ mov r2, sp; /* Save SVC sp */ \ bic sp, sp, #7; /* Align sp to an 8-byte addrress */ \ - sub sp, sp, #4; /* Pad trapframe to keep alignment */ \ + sub sp, sp, #(4 * 17); /* Pad trapframe to keep alignment */ \ + /* and for dtrace to emulate push/pop */ \ str r0, [sp, #-4]!; /* Push return address */ \ str lr, [sp, #-4]!; /* Push SVC lr */ \ str r2, [sp, #-4]!; /* Push SVC sp */ \ @@ -199,7 +195,8 @@ _C_LABEL(dtrace_invop_calltrap_addr): msr cpsr_c, r2; /* Punch into SVC mode */ \ mov r2, sp; /* Save SVC sp */ \ bic sp, sp, #7; /* Align sp to an 8-byte addrress */ \ - sub sp, sp, #4; /* Pad trapframe to keep alignment */ \ + sub sp, sp, #(4 * 17); /* Pad trapframe to keep alignment */ \ + /* and for dtrace to emulate push/pop */ \ str r0, [sp, #-4]!; /* Push return address */ \ str lr, [sp, #-4]!; /* Push SVC lr */ \ str r2, [sp, #-4]!; /* Push SVC sp */ \ Modified: head/sys/arm/arm/undefined.c ============================================================================== --- head/sys/arm/arm/undefined.c Thu Mar 5 17:17:11 2015 (r279666) +++ head/sys/arm/arm/undefined.c Thu Mar 5 17:55:31 2015 (r279667) @@ -86,6 +86,10 @@ __FBSDID("$FreeBSD$"); #include #endif +#ifdef KDTRACE_HOOKS +int (*dtrace_invop_jump_addr)(struct trapframe *); +#endif + static int gdb_trapper(u_int, u_int, struct trapframe *, int); LIST_HEAD(, undefined_handler) undefined_handlers[MAX_COPROCS]; @@ -286,7 +290,14 @@ undefinedinstruction(struct trapframe *f printf("No debugger in kernel.\n"); #endif return; - } else + } +#ifdef KDTRACE_HOOKS + else if (dtrace_invop_jump_addr != 0) { + dtrace_invop_jump_addr(frame); + return; + } +#endif + else panic("Undefined instruction in kernel.\n"); } Modified: head/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h ============================================================================== --- head/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h Thu Mar 5 17:17:11 2015 (r279666) +++ head/sys/cddl/contrib/opensolaris/uts/common/sys/dtrace.h Thu Mar 5 17:55:31 2015 (r279667) @@ -2436,6 +2436,10 @@ extern void dtrace_helpers_destroy(proc_ #elif defined(__arm__) +#define DTRACE_INVOP_SHIFT 4 +#define DTRACE_INVOP_MASK ((1 << DTRACE_INVOP_SHIFT) - 1) +#define DTRACE_INVOP_DATA(x) ((x) >> DTRACE_INVOP_SHIFT) + #define DTRACE_INVOP_PUSHM 1 #define DTRACE_INVOP_POPM 2 #define DTRACE_INVOP_B 3 Modified: head/sys/cddl/dev/dtrace/arm/dtrace_subr.c ============================================================================== --- head/sys/cddl/dev/dtrace/arm/dtrace_subr.c Thu Mar 5 17:17:11 2015 (r279666) +++ head/sys/cddl/dev/dtrace/arm/dtrace_subr.c Thu Mar 5 17:55:31 2015 (r279667) @@ -46,7 +46,11 @@ __FBSDID("$FreeBSD$"); #include #define DELAYBRANCH(x) ((int)(x) < 0) - + +#define BIT_PC 15 +#define BIT_LR 14 +#define BIT_SP 13 + extern uintptr_t dtrace_in_probe_addr; extern int dtrace_in_probe; extern dtrace_id_t dtrace_probeid_error; @@ -231,16 +235,97 @@ dtrace_probe_error(dtrace_state_t *state static int dtrace_invop_start(struct trapframe *frame) { - printf("IMPLEMENT ME: %s\n", __func__); - switch (dtrace_invop(frame->tf_pc, (uintptr_t *)frame, frame->tf_pc)) { + register_t *r0, *sp; + int data, invop, reg, update_sp; + + invop = dtrace_invop(frame->tf_pc, (uintptr_t *)frame, frame->tf_pc); + switch (invop & DTRACE_INVOP_MASK) { case DTRACE_INVOP_PUSHM: - // TODO: + sp = (register_t *)frame->tf_svc_sp; + r0 = &frame->tf_r0; + data = DTRACE_INVOP_DATA(invop); + + /* + * Store the pc, lr, and sp. These have their own + * entries in the struct. + */ + if (data & (1 << BIT_PC)) { + sp--; + *sp = frame->tf_pc; + } + if (data & (1 << BIT_LR)) { + sp--; + *sp = frame->tf_svc_lr; + } + if (data & (1 << BIT_SP)) { + sp--; + *sp = frame->tf_svc_sp; + } + + /* Store the general registers */ + for (reg = 12; reg >= 0; reg--) { + if (data & (1 << reg)) { + sp--; + *sp = r0[reg]; + } + } + + /* Update the stack pointer and program counter to continue */ + frame->tf_svc_sp = (register_t)sp; + frame->tf_pc += 4; break; case DTRACE_INVOP_POPM: - // TODO: + sp = (register_t *)frame->tf_svc_sp; + r0 = &frame->tf_r0; + data = DTRACE_INVOP_DATA(invop); + + /* Read the general registers */ + for (reg = 0; reg <= 12; reg++) { + if (data & (1 << reg)) { + r0[reg] = *sp; + sp++; + } + } + + /* + * Set the stack pointer. If we don't update it here we will + * need to update it at the end as the instruction would do + */ + update_sp = 1; + if (data & (1 << BIT_SP)) { + frame->tf_svc_sp = *sp; + *sp++; + update_sp = 0; + } + + /* Update the link register, we need to use the correct copy */ + if (data & (1 << BIT_LR)) { + frame->tf_svc_lr = *sp; + *sp++; + } + /* + * And the program counter. If it's not in the list skip over + * it when we return so to not hit this again. + */ + if (data & (1 << BIT_PC)) { + frame->tf_pc = *sp; + *sp++; + } else + frame->tf_pc += 4; + + /* Update the stack pointer if we haven't already done so */ + if (update_sp) + frame->tf_svc_sp = (register_t)sp; break; case DTRACE_INVOP_B: - // TODO + data = DTRACE_INVOP_DATA(invop) & 0x00ffffff; + /* Sign extend the data */ + if ((data & (1 << 23)) != 0) + data |= 0xff000000; + /* The data is the number of 4-byte words to change the pc */ + data *= 4; + data += 8; + frame->tf_pc += data; break; default: return (-1); Modified: head/sys/cddl/dev/fbt/arm/fbt_isa.c ============================================================================== --- head/sys/cddl/dev/fbt/arm/fbt_isa.c Thu Mar 5 17:17:11 2015 (r279666) +++ head/sys/cddl/dev/fbt/arm/fbt_isa.c Thu Mar 5 17:55:31 2015 (r279667) @@ -38,7 +38,7 @@ #include "fbt.h" -#define FBT_PATCHVAL 0xe06a0cfe /* illegal instruction */ +#define FBT_PATCHVAL 0xe7f000f0 /* Specified undefined instruction */ #define FBT_PUSHM 0xe92d0000 #define FBT_POPM 0xe8bd0000 @@ -66,7 +66,7 @@ fbt_invop(uintptr_t addr, uintptr_t *sta cpu->cpu_dtrace_caller = 0; - return (fbt->fbtp_rval); + return (fbt->fbtp_rval | (fbt->fbtp_savedval << DTRACE_INVOP_SHIFT)); } }