2 * Copyright (c) 2007 Apple Inc. All rights reserved.
7 * The contents of this file are subject to the terms of the
8 * Common Development and Distribution License, Version 1.0 only
9 * (the "License"). You may not use this file except in compliance
12 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
13 * or http://www.opensolaris.org/os/licensing.
14 * See the License for the specific language governing permissions
15 * and limitations under the License.
17 * When distributing Covered Code, include this CDDL HEADER in each
18 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
19 * If applicable, add the following below this CDDL HEADER, with the
20 * fields enclosed by brackets "[]" replaced with your own identifying
21 * information: Portions Copyright [yyyy] [name of copyright owner]
26 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
27 * Use is subject to license terms.
31 * #pragma ident "@(#)fasttrap_isa.c 1.19 05/09/14 SMI"
36 #define _KERNEL /* Solaris vs. Darwin */
40 #include <sys/fasttrap_isa.h>
41 #include <sys/fasttrap_impl.h>
42 #include <sys/dtrace.h>
43 #include <sys/dtrace_impl.h>
44 #include <kern/task.h>
46 #include <vm/vm_map.h>
47 #include <mach/mach_vm.h>
48 #include <arm/proc_reg.h>
49 #include <arm/caches_internal.h>
51 #include <sys/dtrace_ptss.h>
52 #include <kern/debug.h>
54 #include <pexpert/pexpert.h>
56 extern dtrace_id_t dtrace_probeid_error
;
58 /* Solaris proc_t is the struct. Darwin's proc_t is a pointer to it. */
59 #define proc_t struct proc /* Steer clear of the Darwin typedef for proc_t */
61 extern int dtrace_decode_arm(uint32_t instr
);
62 extern int dtrace_decode_thumb(uint32_t instr
);
65 * Lossless User-Land Tracing on ARM
66 * ---------------------------------
68 * The details here will be fleshed out as more of this is implemented. The
69 * basic design will be the same way as tracing works in x86.
71 * Some ARM specific issues:
73 * We need to patch differently for ARM instructions and Thumb instructions.
74 * When we hit a probe, we check to see if the mode we're currently in is the
75 * same as the mode we're patching for. If not, we remove the tracepoint and
76 * abort. This ARM/Thumb information is pulled in from the arch specific
77 * information in the fasttrap probe.
79 * On ARM, any instruction that uses registers can also use the pc as a
80 * register. This presents problems during emulation because we have copied
81 * the instruction and thus the pc can be different. Currently we've emulated
82 * any instructions that use the pc if they can be used in a return probe.
83 * Eventually we will want to support all instructions that use the pc, but
84 * to do so requires disassembling the instruction and reconstituting it by
85 * substituting a different register.
89 #define THUMB_INSTR(x) (*(uint16_t*) &(x))
91 #define SIGNEXTEND(x,v) ((((int) (x)) << (32-(v))) >> (32-(v)))
92 #define ALIGNADDR(x,v) (((x) >> (v)) << (v))
93 #define GETITSTATE(x) ((((x) >> 8) & 0xFC) | (((x) >> 25) & 0x3))
94 #define ISLASTINIT(x) (((x) & 0xF) == 8)
96 #define SET16(x,w) *((uint16_t*) (x)) = (w)
97 #define SET32(x,w) *((uint32_t*) (x)) = (w)
99 #define IS_ARM_NOP(x) ((x) == 0xE1A00000)
100 /* Marker for is-enabled probes */
101 #define IS_ARM_IS_ENABLED(x) ((x) == 0xE0200000)
103 #define IS_THUMB_NOP(x) ((x) == 0x46C0)
104 /* Marker for is-enabled probes */
105 #define IS_THUMB_IS_ENABLED(x) ((x) == 0x4040)
107 #define ARM_LDM_UF (1 << 23)
108 #define ARM_LDM_PF (1 << 24)
109 #define ARM_LDM_WF (1 << 21)
111 #define ARM_LDR_UF (1 << 23)
112 #define ARM_LDR_BF (1 << 22)
114 extern int dtrace_arm_condition_true(int cond
, int cpsr
);
117 void flush_caches(void)
119 /* TODO There were some problems with flushing just the cache line that had been modified.
120 * For now, we'll flush the entire cache, until we figure out how to flush just the patched block.
123 InvalidatePoU_Icache();
127 fasttrap_tracepoint_init(proc_t
*p
, fasttrap_tracepoint_t
*tp
,
128 user_addr_t pc
, fasttrap_probe_type_t type
)
134 * Read the instruction at the given address out of the process's
135 * address space. We don't have to worry about a debugger
136 * changing this instruction before we overwrite it with our trap
137 * instruction since P_PR_LOCK is set. Since instructions can span
138 * pages, we potentially read the instruction in two parts. If the
139 * second part fails, we just zero out that part of the instruction.
142 * APPLE NOTE: Of course, we do not have a P_PR_LOCK, so this is racey...
145 if (uread(p
, &instr
, 4, pc
) != 0)
148 /* We want &instr to always point to the saved instruction, so just copy the
149 * whole thing When cast to a pointer to a uint16_t, that will give us a
150 * pointer to the first two bytes, which is the thumb instruction.
152 tp
->ftt_instr
= instr
;
154 if (tp
->ftt_fntype
!= FASTTRAP_FN_DONE_INIT
) {
155 switch(tp
->ftt_fntype
) {
156 case FASTTRAP_FN_UNKNOWN
:
157 /* Can't instrument without any information. We can add some heuristics later if necessary. */
160 case FASTTRAP_FN_USDT
:
161 if (IS_ARM_NOP(instr
) || IS_ARM_IS_ENABLED(instr
)) {
163 } else if (IS_THUMB_NOP(THUMB_INSTR(instr
)) || IS_THUMB_IS_ENABLED(THUMB_INSTR(instr
))) {
166 /* Shouldn't reach here - this means we don't recognize
167 * the instruction at one of the USDT probe locations
171 tp
->ftt_fntype
= FASTTRAP_FN_DONE_INIT
;
174 case FASTTRAP_FN_ARM
:
176 tp
->ftt_fntype
= FASTTRAP_FN_DONE_INIT
;
179 case FASTTRAP_FN_THUMB
:
181 tp
->ftt_fntype
= FASTTRAP_FN_DONE_INIT
;
190 tp
->ftt_type
= dtrace_decode_thumb(instr
);
192 tp
->ftt_type
= dtrace_decode_arm(instr
);
195 if (tp
->ftt_type
== FASTTRAP_T_INV
) {
196 /* This is an instruction we either don't recognize or can't instrument */
197 printf("dtrace: fasttrap: Unrecognized instruction: %08x at %08x\n",
198 (tp
->ftt_thumb
&& dtrace_instr_size(tp
->ftt_instr
,tp
->ftt_thumb
) == 2) ? tp
->ftt_instr1
: instr
, pc
);
205 // These are not exported from vm_map.h.
206 extern kern_return_t
vm_map_write_user(vm_map_t map
, void *src_p
, vm_map_address_t dst_addr
, vm_size_t size
);
208 /* Patches the instructions. Almost like uwrite, but need special instructions on ARM to flush the caches. */
210 int patchInst(proc_t
*p
, void *buf
, user_size_t len
, user_addr_t a
)
215 ASSERT(p
->task
!= NULL
);
217 task_t task
= p
->task
;
220 * Grab a reference to the task vm_map_t to make sure
221 * the map isn't pulled out from under us.
223 * Because the proc_lock is not held at all times on all code
224 * paths leading here, it is possible for the proc to have
225 * exited. If the map is null, fail.
227 vm_map_t map
= get_task_map_reference(task
);
229 /* Find the memory permissions. */
230 uint32_t nestingDepth
=999999;
231 vm_region_submap_short_info_data_64_t info
;
232 mach_msg_type_number_t count
= VM_REGION_SUBMAP_SHORT_INFO_COUNT_64
;
233 mach_vm_address_t address
= (mach_vm_address_t
)a
;
234 mach_vm_size_t sizeOfRegion
= (mach_vm_size_t
)len
;
236 ret
= mach_vm_region_recurse(map
, &address
, &sizeOfRegion
, &nestingDepth
, (vm_region_recurse_info_t
)&info
, &count
);
237 if (ret
!= KERN_SUCCESS
)
242 if (!(info
.protection
& VM_PROT_WRITE
)) {
243 /* Save the original protection values for restoration later */
244 reprotect
= info
.protection
;
245 if (info
.max_protection
& VM_PROT_WRITE
) {
246 /* The memory is not currently writable, but can be made writable. */
247 /* Making it both writable and executable at the same time causes warning on embedded */
248 ret
= mach_vm_protect (map
, (mach_vm_offset_t
)a
, (mach_vm_size_t
)len
, 0, (reprotect
& ~VM_PROT_EXECUTE
) | VM_PROT_WRITE
);
251 * The memory is not currently writable, and cannot be made writable. We need to COW this memory.
253 * Strange, we can't just say "reprotect | VM_PROT_COPY", that fails.
255 ret
= mach_vm_protect (map
, (mach_vm_offset_t
)a
, (mach_vm_size_t
)len
, 0, VM_PROT_COPY
| VM_PROT_READ
| VM_PROT_WRITE
);
258 if (ret
!= KERN_SUCCESS
)
262 /* The memory was already writable. */
263 reprotect
= VM_PROT_NONE
;
266 ret
= vm_map_write_user( map
,
273 if (ret
!= KERN_SUCCESS
)
276 if (reprotect
!= VM_PROT_NONE
) {
277 ASSERT(reprotect
& VM_PROT_EXECUTE
);
278 ret
= mach_vm_protect (map
, (mach_vm_offset_t
)a
, (mach_vm_size_t
)len
, 0, reprotect
);
282 vm_map_deallocate(map
);
284 ret
= KERN_TERMINATED
;
290 fasttrap_tracepoint_install(proc_t
*p
, fasttrap_tracepoint_t
*tp
)
292 /* The thumb patch is a 2 byte instruction regardless of the size of the original instruction */
294 int size
= tp
->ftt_thumb
? 2 : 4;
297 *((uint16_t*) &instr
) = FASTTRAP_THUMB_INSTR
;
299 instr
= FASTTRAP_ARM_INSTR
;
302 if (patchInst(p
, &instr
, size
, tp
->ftt_pc
) != 0)
305 tp
->ftt_installed
= 1;
311 fasttrap_tracepoint_remove(proc_t
*p
, fasttrap_tracepoint_t
*tp
)
313 /* The thumb patch is a 2 byte instruction regardless of the size of the original instruction */
315 int size
= tp
->ftt_thumb
? 2 : 4;
318 * Distinguish between read or write failures and a changed
321 if (uread(p
, &instr
, size
, tp
->ftt_pc
) != 0)
324 if (*((uint16_t*) &instr
) != FASTTRAP_THUMB_INSTR
)
327 if (instr
!= FASTTRAP_ARM_INSTR
)
330 if (patchInst(p
, &tp
->ftt_instr
, size
, tp
->ftt_pc
) != 0)
334 tp
->ftt_installed
= 0;
340 fasttrap_return_common(proc_t
*p
, arm_saved_state_t
*regs
, user_addr_t pc
, user_addr_t new_pc
)
342 pid_t pid
= p
->p_pid
;
343 fasttrap_tracepoint_t
*tp
;
344 fasttrap_bucket_t
*bucket
;
349 pid_mtx
= &cpu_core
[CPU
->cpu_id
].cpuc_pid_lock
;
350 lck_mtx_lock(pid_mtx
);
351 bucket
= &fasttrap_tpoints
.fth_table
[FASTTRAP_TPOINTS_INDEX(pid
, pc
)];
353 for (tp
= bucket
->ftb_data
; tp
!= NULL
; tp
= tp
->ftt_next
) {
354 if (pid
== tp
->ftt_pid
&& pc
== tp
->ftt_pc
&&
355 tp
->ftt_proc
->ftpc_acount
!= 0)
360 * Don't sweat it if we can't find the tracepoint again; unlike
361 * when we're in fasttrap_pid_probe(), finding the tracepoint here
362 * is not essential to the correct execution of the process.
365 lck_mtx_unlock(pid_mtx
);
369 for (id
= tp
->ftt_retids
; id
!= NULL
; id
= id
->fti_next
) {
370 fasttrap_probe_t
*probe
= id
->fti_probe
;
372 * If there's a branch that could act as a return site, we
373 * need to trace it, and check here if the program counter is
374 * external to the function.
376 if (tp
->ftt_type
!= FASTTRAP_T_LDM_PC
&&
377 tp
->ftt_type
!= FASTTRAP_T_POP_PC
&&
378 new_pc
- probe
->ftp_faddr
< probe
->ftp_fsize
)
381 if (probe
->ftp_prov
->ftp_provider_type
== DTFTP_PROVIDER_ONESHOT
) {
382 uint8_t already_triggered
= atomic_or_8(&probe
->ftp_triggered
, 1);
383 if (already_triggered
) {
388 * If we have at least one probe associated that
389 * is not a oneshot probe, don't remove the
395 #ifndef CONFIG_EMBEDDED
396 if (ISSET(current_proc()->p_lflag
, P_LNOATTACH
)) {
397 dtrace_probe(dtrace_probeid_error
, 0 /* state */, id
->fti_probe
->ftp_id
,
398 1 /* ndx */, -1 /* offset */, DTRACEFLT_UPRIV
);
403 dtrace_probe(id
->fti_probe
->ftp_id
,
404 pc
- id
->fti_probe
->ftp_faddr
,
405 regs
->r
[0], 0, 0, 0);
409 fasttrap_tracepoint_retire(p
, tp
);
412 lck_mtx_unlock(pid_mtx
);
416 fasttrap_sigsegv(proc_t
*p
, uthread_t t
, user_addr_t addr
, arm_saved_state_t
*regs
)
418 /* TODO: This function isn't implemented yet. In debug mode, panic the system to
419 * find out why we're hitting this point. In other modes, kill the process.
422 #pragma unused(p,t,addr,arm_saved_state)
423 panic("fasttrap: sigsegv not yet implemented");
425 #pragma unused(p,t,addr)
426 /* Kill the process */
433 /* Set fault address and mark signal */
435 t
->uu_siglist
|= sigmask(SIGSEGV
);
438 * XXX These two line may be redundant; if not, then we need
439 * XXX to potentially set the data address in the machine
440 * XXX specific thread state structure to indicate the address.
442 t
->uu_exception
= KERN_INVALID_ADDRESS
; /* SIGSEGV */
443 t
->uu_subcode
= 0; /* XXX pad */
448 signal_setast(t
->uu_context
.vc_thread
);
453 fasttrap_usdt_args(fasttrap_probe_t
*probe
, arm_saved_state_t
*regs
, int argc
,
456 int i
, x
, cap
= MIN(argc
, probe
->ftp_nargs
);
458 for (i
= 0; i
< cap
; i
++) {
459 x
= probe
->ftp_argmap
[i
];
462 argv
[i
] = regs
->r
[x
];
464 fasttrap_fuword32_noerr(regs
->sp
+ (x
- 4) * sizeof(uint32_t), &argv
[i
]);
468 for (; i
< argc
; i
++) {
473 static void set_thumb_flag(arm_saved_state_t
*regs
, user_addr_t pc
)
476 regs
->cpsr
|= PSR_TF
;
478 regs
->cpsr
&= ~PSR_TF
;
483 fasttrap_pid_probe(arm_saved_state_t
*regs
)
485 proc_t
*p
= current_proc();
486 user_addr_t new_pc
= 0;
487 fasttrap_bucket_t
*bucket
;
489 fasttrap_tracepoint_t
*tp
, tp_local
;
491 dtrace_icookie_t cookie
;
492 uint_t is_enabled
= 0;
494 int was_simulated
= 1, retire_tp
= 1;
496 user_addr_t pc
= regs
->pc
;
498 uthread_t uthread
= (uthread_t
) get_bsdthread_info(current_thread());
501 * It's possible that a user (in a veritable orgy of bad planning)
502 * could redirect this thread's flow of control before it reached the
503 * return probe fasttrap. In this case we need to kill the process
504 * since it's in a unrecoverable state.
506 if (uthread
->t_dtrace_step
) {
507 ASSERT(uthread
->t_dtrace_on
);
508 fasttrap_sigtrap(p
, uthread
, pc
);
513 * Clear all user tracing flags.
515 uthread
->t_dtrace_ft
= 0;
516 uthread
->t_dtrace_pc
= 0;
517 uthread
->t_dtrace_npc
= 0;
518 uthread
->t_dtrace_scrpc
= 0;
519 uthread
->t_dtrace_astpc
= 0;
522 * Treat a child created by a call to vfork(2) as if it were its
523 * parent. We know that there's only one thread of control in such a
526 if (p
->p_lflag
& P_LINVFORK
) {
528 while (p
->p_lflag
& P_LINVFORK
)
534 pid_mtx
= &cpu_core
[CPU
->cpu_id
].cpuc_pid_lock
;
535 lck_mtx_lock(pid_mtx
);
536 bucket
= &fasttrap_tpoints
.fth_table
[FASTTRAP_TPOINTS_INDEX(pid
,pc
)];
539 * Lookup the tracepoint that the process just hit.
541 for (tp
= bucket
->ftb_data
; tp
!= NULL
; tp
= tp
->ftt_next
) {
542 if (pid
== tp
->ftt_pid
&& pc
== tp
->ftt_pc
&&
543 tp
->ftt_proc
->ftpc_acount
!= 0)
548 * If we couldn't find a matching tracepoint, either a tracepoint has
549 * been inserted without using the pid<pid> ioctl interface (see
550 * fasttrap_ioctl), or somehow we have mislaid this tracepoint.
553 lck_mtx_unlock(pid_mtx
);
557 /* Default to always execute */
558 int condition_code
= 0xE;
560 uint32_t itstate
= GETITSTATE(regs
->cpsr
);
562 /* In IT block, make sure it's the last statement in the block */
563 if (ISLASTINIT(itstate
)) {
564 condition_code
= itstate
>> 4;
566 printf("dtrace: fasttrap: Tried to trace instruction %08x at %08x but not at end of IT block\n",
567 (tp
->ftt_thumb
&& dtrace_instr_size(tp
->ftt_instr
,tp
->ftt_thumb
) == 2) ? tp
->ftt_instr1
: tp
->ftt_instr
, pc
);
569 fasttrap_tracepoint_remove(p
, tp
);
570 lck_mtx_unlock(pid_mtx
);
575 condition_code
= ARM_CONDCODE(tp
->ftt_instr
);
578 if (!tp
->ftt_thumb
!= !(regs
->cpsr
& PSR_TF
)) {
579 /* The ARM/Thumb mode does not match what we expected for this probe.
580 * Remove this probe and bail.
582 fasttrap_tracepoint_remove(p
, tp
);
583 lck_mtx_unlock(pid_mtx
);
587 if (tp
->ftt_ids
!= NULL
) {
591 uint32_t *stack
= (uint32_t *)regs
->sp
;
593 /* First four parameters are passed in registers */
594 fasttrap_fuword32_noerr((user_addr_t
)(uint32_t)stack
, &s4
);
596 for (id
= tp
->ftt_ids
; id
!= NULL
; id
= id
->fti_next
) {
597 fasttrap_probe_t
*probe
= id
->fti_probe
;
599 #ifndef CONFIG_EMBEDDED
600 if (ISSET(current_proc()->p_lflag
, P_LNOATTACH
)) {
601 dtrace_probe(dtrace_probeid_error
, 0 /* state */, probe
->ftp_id
,
602 1 /* ndx */, -1 /* offset */, DTRACEFLT_UPRIV
);
607 if (probe
->ftp_prov
->ftp_provider_type
== DTFTP_PROVIDER_ONESHOT
) {
608 uint8_t already_triggered
= atomic_or_8(&probe
->ftp_triggered
, 1);
609 if (already_triggered
) {
614 * If we have at least probe associated that
615 * is not a oneshot probe, don't remove the
621 if (id
->fti_ptype
== DTFTP_ENTRY
) {
623 * We note that this was an entry
624 * probe to help ustack() find the
627 cookie
= dtrace_interrupt_disable();
628 DTRACE_CPUFLAG_SET(CPU_DTRACE_ENTRY
);
629 dtrace_probe(probe
->ftp_id
, regs
->r
[0], regs
->r
[1], regs
->r
[2], regs
->r
[3], s4
);
630 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_ENTRY
);
631 dtrace_interrupt_enable(cookie
);
632 } else if (id
->fti_ptype
== DTFTP_IS_ENABLED
) {
634 * Note that in this case, we don't
635 * call dtrace_probe() since it's only
636 * an artificial probe meant to change
637 * the flow of control so that it
638 * encounters the true probe.
641 } else if (probe
->ftp_argmap
== NULL
) {
642 dtrace_probe(probe
->ftp_id
, regs
->r
[0], regs
->r
[1], regs
->r
[2], regs
->r
[3], s4
);
646 fasttrap_usdt_args(probe
, regs
, 5, t
);
647 dtrace_probe(probe
->ftp_id
, t
[0], t
[1], t
[2], t
[3], t
[4]);
652 fasttrap_tracepoint_retire(p
, tp
);
656 * We're about to do a bunch of work so we cache a local copy of
657 * the tracepoint to emulate the instruction, and then find the
658 * tracepoint again later if we need to light up any return probes.
661 lck_mtx_unlock(pid_mtx
);
665 * If there's an is-enabled probe connected to this tracepoint it
666 * means that there was a 'eor r0,r0,r0'
667 * instruction that was placed there by DTrace when the binary was
668 * linked. As this probe is, in fact, enabled, we need to stuff 1
669 * into R0. Accordingly, we can bypass all the instruction
670 * emulation logic since we know the inevitable result. It's possible
671 * that a user could construct a scenario where the 'is-enabled'
672 * probe was on some other instruction, but that would be a rather
673 * exotic way to shoot oneself in the foot.
678 new_pc
= regs
->pc
+ (tp
->ftt_thumb
? 2 : 4);
682 /* For USDT probes, bypass all the emulation logic for the nop instruction */
683 if ((tp
->ftt_thumb
&& IS_THUMB_NOP(THUMB_INSTR(tp
->ftt_instr
))) ||
684 (!tp
->ftt_thumb
&& IS_ARM_NOP(tp
->ftt_instr
))) {
685 new_pc
= regs
->pc
+ (tp
->ftt_thumb
? 2 : 4);
689 instr_size
= dtrace_instr_size(tp
->ftt_instr
,tp
->ftt_thumb
);
691 switch (tp
->ftt_type
) {
692 case FASTTRAP_T_MOV_PC_REG
:
693 case FASTTRAP_T_CPY_PC
:
695 if (!dtrace_arm_condition_true(condition_code
, regs
->cpsr
)) {
696 new_pc
= pc
+ instr_size
;
702 rm
= THUMB16_HRM(tp
->ftt_instr1
);
704 rm
= tp
->ftt_instr
& 0xF;
706 new_pc
= regs
->r
[rm
];
708 /* This instruction does not change the Thumb state */
713 case FASTTRAP_T_STM_LR
:
714 case FASTTRAP_T_PUSH_LR
:
717 * This is a very common case, so we want to emulate this instruction if
718 * possible. However, on a push, it is possible that we might reach the end
719 * of a page and have to allocate a new page. Most of the time this will not
720 * happen, and we know that the push instruction can store at most 16 words,
721 * so check to see if we are far from the boundary, and if so, emulate. This
722 * can be made more aggressive by checking the actual number of words being
723 * pushed, but we won't do that for now.
725 * Some of the same issues that apply to POP_PC probably apply here also.
732 if (!dtrace_arm_condition_true(condition_code
, regs
->cpsr
)) {
733 new_pc
= pc
+ instr_size
;
737 base
= (uintptr_t*) regs
->sp
;
738 if (((((uintptr_t) base
)-16*4) >> PAGE_SHIFT
) != (((uintptr_t) base
) >> PAGE_SHIFT
)) {
739 /* Crosses the page boundary, go to emulation */
744 if (instr_size
== 4) {
745 /* We know we have to push lr, never push sp or pc */
746 reglist
= tp
->ftt_instr2
& 0x1FFF;
748 reglist
= tp
->ftt_instr1
& 0xFF;
751 /* We know we have to push lr, never push sp or pc */
752 reglist
= tp
->ftt_instr
& 0x1FFF;
755 /* Push the link register */
757 ret
= fasttrap_suword32((uint32_t) base
, regs
->lr
);
759 fasttrap_sigsegv(p
, uthread
, (user_addr_t
) base
, regs
);
764 /* Start pushing from $r12 */
765 int regmask
= 1 << 12;
769 if (reglist
& regmask
) {
771 ret
= fasttrap_suword32((uint32_t) base
, regs
->r
[regnum
]);
773 fasttrap_sigsegv(p
, uthread
, (user_addr_t
) base
, regs
);
782 regs
->sp
= (uintptr_t) base
;
784 new_pc
= pc
+ instr_size
;
790 case FASTTRAP_T_LDM_PC
:
791 case FASTTRAP_T_POP_PC
:
793 /* TODO Two issues that will eventually need to be resolved:
795 * 1. Understand what the hardware does if we have to segfault (data abort) in
796 * the middle of a load multiple. We currently don't have a working segfault
797 * handler anyway, and with no swapfile we should never segfault on this load.
798 * If we do, we'll just kill the process by setting the pc to 0.
800 * 2. The emulation is no longer atomic. We currently only emulate pop for
801 * function epilogues, and so we should never have a race here because one
802 * thread should never be trying to manipulate another thread's stack frames.
803 * That is almost certainly a bug in the program.
805 * This will need to be fixed if we ever:
806 * a. Ship dtrace externally, as this could be a potential attack vector
807 * b. Support instruction level tracing, as we might then pop/ldm non epilogues.
811 /* Assume ldmia! sp/pop ... pc */
813 int regnum
= 0, reglist
;
817 if (!dtrace_arm_condition_true(condition_code
, regs
->cpsr
)) {
818 new_pc
= pc
+ instr_size
;
823 if (instr_size
== 4) {
824 /* We know we have to load the pc, don't do it twice */
825 reglist
= tp
->ftt_instr2
& 0x7FFF;
827 reglist
= tp
->ftt_instr1
& 0xFF;
830 /* We know we have to load the pc, don't do it twice */
831 reglist
= tp
->ftt_instr
& 0x7FFF;
834 base
= (uintptr_t*) regs
->sp
;
837 ret
= fasttrap_fuword32((uint32_t) base
, ®s
->r
[regnum
]);
839 fasttrap_sigsegv(p
, uthread
, (user_addr_t
) base
, regs
);
849 ret
= fasttrap_fuword32((uint32_t) base
, &new_pc
);
851 fasttrap_sigsegv(p
, uthread
, (user_addr_t
) base
, regs
);
857 regs
->sp
= (uintptr_t) base
;
859 set_thumb_flag(regs
, new_pc
);
864 case FASTTRAP_T_CB_N_Z
:
866 /* Thumb mode instruction, and not permitted in IT block, so skip the condition code check */
867 int rn
= tp
->ftt_instr1
& 0x7;
868 int offset
= (((tp
->ftt_instr1
& 0x00F8) >> 2) | ((tp
->ftt_instr1
& 0x0200) >> 3)) + 4;
869 int nonzero
= tp
->ftt_instr1
& 0x0800;
870 if (!nonzero
!= !(regs
->r
[rn
] == 0)) {
871 new_pc
= pc
+ offset
;
873 new_pc
= pc
+ instr_size
;
878 case FASTTRAP_T_B_COND
:
880 /* Use the condition code in the instruction and ignore the ITSTATE */
884 if (instr_size
== 4) {
885 code
= (tp
->ftt_instr1
>> 6) & 0xF;
886 if (code
== 14 || code
== 15) {
887 panic("fasttrap: Emulation of invalid branch");
889 int S
= (tp
->ftt_instr1
>> 10) & 1,
890 J1
= (tp
->ftt_instr2
>> 13) & 1,
891 J2
= (tp
->ftt_instr2
>> 11) & 1;
892 offset
= 4 + SIGNEXTEND(
893 (S
<< 20) | (J2
<< 19) | (J1
<< 18) |
894 ((tp
->ftt_instr1
& 0x003F) << 12) |
895 ((tp
->ftt_instr2
& 0x07FF) << 1),
898 code
= (tp
->ftt_instr1
>> 8) & 0xF;
899 if (code
== 14 || code
== 15) {
900 panic("fasttrap: Emulation of invalid branch");
902 offset
= 4 + (SIGNEXTEND(tp
->ftt_instr1
& 0xFF, 8) << 1);
905 code
= ARM_CONDCODE(tp
->ftt_instr
);
907 panic("fasttrap: Emulation of invalid branch");
909 offset
= 8 + (SIGNEXTEND(tp
->ftt_instr
& 0x00FFFFFF, 24) << 2);
912 if (dtrace_arm_condition_true(code
, regs
->cpsr
)) {
913 new_pc
= pc
+ offset
;
915 new_pc
= pc
+ instr_size
;
921 case FASTTRAP_T_B_UNCOND
:
925 /* Unconditional branches can only be taken from Thumb mode */
926 /* (This is different from an ARM branch with condition code "always") */
927 ASSERT(tp
->ftt_thumb
== 1);
929 if (!dtrace_arm_condition_true(condition_code
, regs
->cpsr
)) {
930 new_pc
= pc
+ instr_size
;
934 if (instr_size
== 4) {
935 int S
= (tp
->ftt_instr1
>> 10) & 1,
936 J1
= (tp
->ftt_instr2
>> 13) & 1,
937 J2
= (tp
->ftt_instr2
>> 11) & 1;
938 int I1
= (J1
!= S
) ? 0 : 1, I2
= (J2
!= S
) ? 0 : 1;
939 offset
= 4 + SIGNEXTEND(
940 (S
<< 24) | (I1
<< 23) | (I2
<< 22) |
941 ((tp
->ftt_instr1
& 0x03FF) << 12) |
942 ((tp
->ftt_instr2
& 0x07FF) << 1),
945 uint32_t instr1
= tp
->ftt_instr1
;
946 offset
= 4 + (SIGNEXTEND(instr1
& 0x7FF, 11) << 1);
949 new_pc
= pc
+ offset
;
954 case FASTTRAP_T_BX_REG
:
958 if (!dtrace_arm_condition_true(condition_code
, regs
->cpsr
)) {
959 new_pc
= pc
+ instr_size
;
964 reg
= THUMB16_HRM(tp
->ftt_instr1
);
966 reg
= ARM_RM(tp
->ftt_instr
);
968 new_pc
= regs
->r
[reg
];
969 set_thumb_flag(regs
, new_pc
);
974 case FASTTRAP_T_LDR_PC_IMMED
:
975 case FASTTRAP_T_VLDR_PC_IMMED
:
976 /* Handle these instructions by replacing the PC in the instruction with another
977 * register. They are common, so we'd like to support them, and this way we do so
978 * without any risk of having to simulate a segfault.
984 case FASTTRAP_T_COMMON
:
989 fasttrap_instr_t emul_instr
;
990 emul_instr
.instr32
= tp
->ftt_instr
;
994 * Unfortunately sometimes when we emulate the instruction and have to replace the
995 * PC, there is no longer a thumb mode equivalent. We end up having to run the
996 * modified instruction in ARM mode. We use this variable to keep track of which
997 * mode we should emulate in. We still use the original variable to determine
998 * what mode to return to.
1000 uint8_t emul_thumb
= tp
->ftt_thumb
;
1002 uint32_t save_val
= 0;
1005 * Dealing with condition codes and emulation:
1006 * We can't just uniformly do a condition code check here because not all instructions
1007 * have condition codes. We currently do not support an instruction by instruction trace,
1008 * so we can assume that either: 1. We are executing a Thumb instruction, in which case
1009 * we either are not in an IT block and should execute always, or we are last in an IT
1010 * block. Either way, the traced instruction will run correctly, and we won't have any
1011 * problems when we return to the original code, because we will no longer be in the IT
1012 * block. 2. We are executing an ARM instruction, in which case we are ok as long as
1013 * we don't attempt to change the condition code.
1015 if (tp
->ftt_type
== FASTTRAP_T_LDR_PC_IMMED
) {
1016 /* We know we always have a free register (the one we plan to write the
1017 * result value to!). So we'll replace the pc with that one.
1020 if (tp
->ftt_thumb
) {
1021 /* Check to see if thumb or thumb2 */
1022 if (instr_size
== 2) {
1024 * Sadness. We need to emulate this instruction in ARM mode
1025 * because it has an 8 bit immediate offset. Instead of having
1026 * to deal with condition codes in the ARM instruction, we'll
1027 * just check the condition and abort if the condition is false.
1029 if (!dtrace_arm_condition_true(condition_code
, regs
->cpsr
)) {
1030 new_pc
= pc
+ instr_size
;
1034 new_reg
= (tp
->ftt_instr1
>> 8) & 0x7;
1035 regs
->r
[new_reg
] = ALIGNADDR(regs
->pc
+ 4, 2);
1037 emul_instr
.instr32
= 0xE5900000 | (new_reg
<< 16) | (new_reg
<< 12) | ((tp
->ftt_instr1
& 0xFF) << 2);
1039 /* Thumb2. Just replace the register. */
1040 new_reg
= (tp
->ftt_instr2
>> 12) & 0xF;
1041 regs
->r
[new_reg
] = ALIGNADDR(regs
->pc
+ 4, 2);
1042 emul_instr
.instr16
.instr1
&= ~0x000F;
1043 emul_instr
.instr16
.instr1
|= new_reg
;
1046 /* ARM. Just replace the register. */
1047 new_reg
= (tp
->ftt_instr
>> 12) & 0xF;
1048 regs
->r
[new_reg
] = ALIGNADDR(regs
->pc
+ 8,2);
1049 emul_instr
.instr32
&= ~0x000F0000;
1050 emul_instr
.instr32
|= new_reg
<< 16;
1052 } else if (tp
->ftt_type
== FASTTRAP_T_VLDR_PC_IMMED
) {
1053 /* This instruction only uses one register, and if we're here, we know
1054 * it must be the pc. So we'll just replace it with R0.
1057 save_val
= regs
->r
[0];
1058 regs
->r
[save_reg
] = ALIGNADDR(regs
->pc
+ (tp
->ftt_thumb
? 4 : 8), 2);
1059 if (tp
->ftt_thumb
) {
1060 emul_instr
.instr16
.instr1
&= ~0x000F;
1062 emul_instr
.instr32
&= ~0x000F0000;
1066 emul_instr_size
= dtrace_instr_size(emul_instr
.instr32
, emul_thumb
);
1070 * tp->ftt_thumb = thumb mode of original instruction
1071 * emul_thumb = thumb mode for emulation
1072 * emul_instr = instruction we are using to emulate original instruction
1073 * emul_instr_size = size of emulating instruction
1076 addr
= uthread
->t_dtrace_scratch
->addr
;
1079 fasttrap_sigtrap(p
, uthread
, pc
); // Should be killing target proc
1084 uthread
->t_dtrace_scrpc
= addr
;
1087 * No way to do an unconditional branch in Thumb mode, shove the address
1088 * onto the user stack and go to the next location with a pop. This can
1089 * segfault if this push happens to cross a stack page, but that's ok, since
1090 * we are running in userland, and the kernel knows how to handle userland
1091 * stack expansions correctly.
1093 * Layout of scratch space for Thumb mode:
1094 * Emulated instruction
1095 * ldr save_reg, [pc, #16] (if necessary, restore any register we clobbered)
1100 * Location we should return to in original program
1101 * Saved value of clobbered register (if necessary)
1104 bcopy(&emul_instr
, &scratch
[i
], emul_instr_size
); i
+= emul_instr_size
;
1106 if (save_reg
!= -1) {
1107 uint16_t restore_inst
= 0x4803;
1108 restore_inst
|= (save_reg
& 0x7) << 8;
1109 SET16(scratch
+i
, restore_inst
); i
+= 2; // ldr reg, [pc , #16]
1112 SET16(scratch
+i
, 0xB403); i
+= 2; // push { r0, r1 }
1113 SET16(scratch
+i
, 0x4801); i
+= 2; // ldr r0, [pc, #4]
1114 SET16(scratch
+i
, 0x9001); i
+= 2; // str r0, [sp, #4]
1115 SET16(scratch
+i
, 0xBD01); i
+= 2; // pop { r0, pc }
1118 SET16(scratch
+i
, 0); i
+= 2; // padding - saved 32 bit words must be aligned
1120 SET32(scratch
+i
, pc
+ instr_size
+ (tp
->ftt_thumb
? 1 : 0)); i
+= 4; // Return address
1121 if (save_reg
!= -1) {
1122 SET32(scratch
+i
, save_val
); i
+= 4; // saved value of clobbered register
1125 uthread
->t_dtrace_astpc
= addr
+ i
;
1126 bcopy(&emul_instr
, &scratch
[i
], emul_instr_size
); i
+= emul_instr_size
;
1127 SET16(scratch
+i
, FASTTRAP_THUMB_RET_INSTR
); i
+= 2;
1130 * Layout of scratch space for ARM mode:
1131 * Emulated instruction
1132 * ldr save_reg, [pc, #12] (if necessary, restore any register we clobbered)
1134 * Location we should return to in original program
1135 * Saved value of clobbered register (if necessary)
1138 bcopy(&emul_instr
, &scratch
[i
], emul_instr_size
); i
+= emul_instr_size
;
1140 if (save_reg
!= -1) {
1141 uint32_t restore_inst
= 0xE59F0004;
1142 restore_inst
|= save_reg
<< 12;
1143 SET32(scratch
+i
, restore_inst
); i
+= 4; // ldr reg, [pc, #12]
1145 SET32(scratch
+i
, 0xE51FF004); i
+= 4; // ldr pc, [pc, #4]
1147 SET32(scratch
+i
, pc
+ instr_size
+ (tp
->ftt_thumb
? 1 : 0)); i
+= 4; // Return address
1148 if (save_reg
!= -1) {
1149 SET32(scratch
+i
, save_val
); i
+= 4; // Saved value of clobbered register
1152 uthread
->t_dtrace_astpc
= addr
+ i
;
1153 bcopy(&emul_instr
, &scratch
[i
], emul_instr_size
); i
+= emul_instr_size
;
1154 SET32(scratch
+i
, FASTTRAP_ARM_RET_INSTR
); i
+= 4;
1157 if (patchInst(p
, scratch
, i
, uthread
->t_dtrace_scratch
->write_addr
) != KERN_SUCCESS
) {
1158 fasttrap_sigtrap(p
, uthread
, pc
);
1163 if (tp
->ftt_retids
!= NULL
) {
1164 uthread
->t_dtrace_step
= 1;
1165 uthread
->t_dtrace_ret
= 1;
1166 new_pc
= uthread
->t_dtrace_astpc
+ (emul_thumb
? 1 : 0);
1168 new_pc
= uthread
->t_dtrace_scrpc
+ (emul_thumb
? 1 : 0);
1171 uthread
->t_dtrace_pc
= pc
;
1172 uthread
->t_dtrace_npc
= pc
+ instr_size
;
1173 uthread
->t_dtrace_on
= 1;
1175 set_thumb_flag(regs
, new_pc
);
1180 panic("fasttrap: mishandled an instruction");
1187 * We're setting this earlier than Solaris does, to get a "correct"
1188 * ustack() output. In the Sun code, a() -> b() -> c() -> d() is
1189 * reported at: d, b, a. The new way gives c, b, a, which is closer
1190 * to correct, as the return instruction has already exectued.
1195 * If there were no return probes when we first found the tracepoint,
1196 * we should feel no obligation to honor any return probes that were
1197 * subsequently enabled -- they'll just have to wait until the next
1200 if (tp
->ftt_retids
!= NULL
) {
1202 * We need to wait until the results of the instruction are
1203 * apparent before invoking any return probes. If this
1204 * instruction was emulated we can just call
1205 * fasttrap_return_common(); if it needs to be executed, we
1206 * need to wait until the user thread returns to the kernel.
1209 * It used to be that only common instructions were simulated.
1210 * For performance reasons, we now simulate some instructions
1211 * when safe and go back to userland otherwise. The was_simulated
1212 * flag means we don't need to go back to userland.
1214 if (was_simulated
) {
1215 fasttrap_return_common(p
, regs
, pc
, new_pc
);
1217 ASSERT(uthread
->t_dtrace_ret
!= 0);
1218 ASSERT(uthread
->t_dtrace_pc
== pc
);
1219 ASSERT(uthread
->t_dtrace_scrpc
!= 0);
1220 ASSERT(new_pc
== uthread
->t_dtrace_astpc
);
1228 fasttrap_return_probe(arm_saved_state_t
*regs
)
1230 proc_t
*p
= current_proc();
1231 uthread_t uthread
= (uthread_t
)get_bsdthread_info(current_thread());
1232 user_addr_t pc
= uthread
->t_dtrace_pc
;
1233 user_addr_t npc
= uthread
->t_dtrace_npc
;
1235 uthread
->t_dtrace_pc
= 0;
1236 uthread
->t_dtrace_npc
= 0;
1237 uthread
->t_dtrace_scrpc
= 0;
1238 uthread
->t_dtrace_astpc
= 0;
1241 * Treat a child created by a call to vfork(2) as if it were its
1242 * parent. We know that there's only one thread of control in such a
1243 * process: this one.
1245 if (p
->p_lflag
& P_LINVFORK
) {
1247 while (p
->p_lflag
& P_LINVFORK
)
1253 * We set rp->r_pc to the address of the traced instruction so
1254 * that it appears to dtrace_probe() that we're on the original
1255 * instruction, and so that the user can't easily detect our
1256 * complex web of lies. dtrace_return_probe() (our caller)
1257 * will correctly set %pc after we return.
1261 fasttrap_return_common(p
, regs
, pc
, npc
);
1267 fasttrap_pid_getarg(void *arg
, dtrace_id_t id
, void *parg
, int argno
,
1270 #pragma unused(arg, id, parg, aframes)
1271 arm_saved_state_t
* regs
= find_user_regs(current_thread());
1273 /* First four arguments are in registers */
1275 return regs
->r
[argno
];
1277 /* Look on the stack for the rest */
1279 uint32_t* sp
= (uint32_t*) regs
->sp
;
1280 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT
);
1281 value
= dtrace_fuword32((user_addr_t
) (sp
+argno
-4));
1282 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT
| CPU_DTRACE_BADADDR
);
1288 fasttrap_usdt_getarg(void *arg
, dtrace_id_t id
, void *parg
, int argno
, int aframes
)
1290 #pragma unused(arg, id, parg, argno, aframes)
1292 return (fasttrap_anarg(ttolwp(curthread
)->lwp_regs
, 0, argno
));