]> git.saurik.com Git - apple/xnu.git/blame - bsd/dev/arm/fasttrap_isa.c
xnu-4570.71.2.tar.gz
[apple/xnu.git] / bsd / dev / arm / fasttrap_isa.c
CommitLineData
5ba3f43e
A
1/*
2 * Copyright (c) 2007 Apple Inc. All rights reserved.
3 */
4/*
5 * CDDL HEADER START
6 *
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
10 * with the License.
11 *
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.
16 *
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]
22 *
23 * CDDL HEADER END
24 */
25/*
26 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
27 * Use is subject to license terms.
28 */
29
30/*
31 * #pragma ident "@(#)fasttrap_isa.c 1.19 05/09/14 SMI"
32 */
33
34#ifdef KERNEL
35#ifndef _KERNEL
36#define _KERNEL /* Solaris vs. Darwin */
37#endif
38#endif
39
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>
45#include <vm/pmap.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>
50
51#include <sys/dtrace_ptss.h>
52#include <kern/debug.h>
53
54#include <pexpert/pexpert.h>
55
56extern dtrace_id_t dtrace_probeid_error;
57
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 */
60
61extern int dtrace_decode_arm(uint32_t instr);
62extern int dtrace_decode_thumb(uint32_t instr);
63
64/*
65 * Lossless User-Land Tracing on ARM
66 * ---------------------------------
67 *
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.
70 *
71 * Some ARM specific issues:
72 *
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.
78 *
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.
86 *
87 */
88
89#define THUMB_INSTR(x) (*(uint16_t*) &(x))
90
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)
95
96#define SET16(x,w) *((uint16_t*) (x)) = (w)
97#define SET32(x,w) *((uint32_t*) (x)) = (w)
98
99#define IS_ARM_NOP(x) ((x) == 0xE1A00000)
100/* Marker for is-enabled probes */
101#define IS_ARM_IS_ENABLED(x) ((x) == 0xE0200000)
102
103#define IS_THUMB_NOP(x) ((x) == 0x46C0)
104/* Marker for is-enabled probes */
105#define IS_THUMB_IS_ENABLED(x) ((x) == 0x4040)
106
107#define ARM_LDM_UF (1 << 23)
108#define ARM_LDM_PF (1 << 24)
109#define ARM_LDM_WF (1 << 21)
110
111#define ARM_LDR_UF (1 << 23)
112#define ARM_LDR_BF (1 << 22)
113
114extern int dtrace_arm_condition_true(int cond, int cpsr);
115
116static
117void flush_caches(void)
118{
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.
121 */
122 FlushPoU_Dcache();
123 InvalidatePoU_Icache();
124}
125
126int
127fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp,
128 user_addr_t pc, fasttrap_probe_type_t type)
129{
130#pragma unused(type)
131 uint32_t instr;
132
133 /*
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.
140 */
141 /*
142 * APPLE NOTE: Of course, we do not have a P_PR_LOCK, so this is racey...
143 */
144
145 if (uread(p, &instr, 4, pc) != 0)
146 return (-1);
147
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.
151 */
152 tp->ftt_instr = instr;
153
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. */
158 return (-1);
159
160 case FASTTRAP_FN_USDT:
161 if (IS_ARM_NOP(instr) || IS_ARM_IS_ENABLED(instr)) {
162 tp->ftt_thumb = 0;
163 } else if (IS_THUMB_NOP(THUMB_INSTR(instr)) || IS_THUMB_IS_ENABLED(THUMB_INSTR(instr))) {
164 tp->ftt_thumb = 1;
165 } else {
166 /* Shouldn't reach here - this means we don't recognize
167 * the instruction at one of the USDT probe locations
168 */
169 return (-1);
170 }
171 tp->ftt_fntype = FASTTRAP_FN_DONE_INIT;
172 break;
173
174 case FASTTRAP_FN_ARM:
175 tp->ftt_thumb = 0;
176 tp->ftt_fntype = FASTTRAP_FN_DONE_INIT;
177 break;
178
179 case FASTTRAP_FN_THUMB:
180 tp->ftt_thumb = 1;
181 tp->ftt_fntype = FASTTRAP_FN_DONE_INIT;
182 break;
183
184 default:
185 return (-1);
186 }
187 }
188
189 if (tp->ftt_thumb) {
190 tp->ftt_type = dtrace_decode_thumb(instr);
191 } else {
192 tp->ftt_type = dtrace_decode_arm(instr);
193 }
194
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);
199 return (-1);
200 }
201
202 return (0);
203}
204
205// These are not exported from vm_map.h.
206extern kern_return_t vm_map_write_user(vm_map_t map, void *src_p, vm_map_address_t dst_addr, vm_size_t size);
207
208/* Patches the instructions. Almost like uwrite, but need special instructions on ARM to flush the caches. */
209static
210int patchInst(proc_t *p, void *buf, user_size_t len, user_addr_t a)
211{
212 kern_return_t ret;
213
214 ASSERT(p != NULL);
215 ASSERT(p->task != NULL);
216
217 task_t task = p->task;
218
219 /*
220 * Grab a reference to the task vm_map_t to make sure
221 * the map isn't pulled out from under us.
222 *
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.
226 */
227 vm_map_t map = get_task_map_reference(task);
228 if (map) {
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;
235
236 ret = mach_vm_region_recurse(map, &address, &sizeOfRegion, &nestingDepth, (vm_region_recurse_info_t)&info, &count);
237 if (ret != KERN_SUCCESS)
238 goto done;
239
240 vm_prot_t reprotect;
241
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);
249 } else {
250 /*
251 * The memory is not currently writable, and cannot be made writable. We need to COW this memory.
252 *
253 * Strange, we can't just say "reprotect | VM_PROT_COPY", that fails.
254 */
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);
256 }
257
258 if (ret != KERN_SUCCESS)
259 goto done;
260
261 } else {
262 /* The memory was already writable. */
263 reprotect = VM_PROT_NONE;
264 }
265
266 ret = vm_map_write_user( map,
267 buf,
268 (vm_map_address_t)a,
269 (vm_size_t)len);
270
271 flush_caches();
272
273 if (ret != KERN_SUCCESS)
274 goto done;
275
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);
279 }
280
281done:
282 vm_map_deallocate(map);
283 } else
284 ret = KERN_TERMINATED;
285
286 return (int)ret;
287}
288
289int
290fasttrap_tracepoint_install(proc_t *p, fasttrap_tracepoint_t *tp)
291{
292 /* The thumb patch is a 2 byte instruction regardless of the size of the original instruction */
293 uint32_t instr;
294 int size = tp->ftt_thumb ? 2 : 4;
295
296 if (tp->ftt_thumb) {
297 *((uint16_t*) &instr) = FASTTRAP_THUMB_INSTR;
298 } else {
299 instr = FASTTRAP_ARM_INSTR;
300 }
301
302 if (patchInst(p, &instr, size, tp->ftt_pc) != 0)
303 return (-1);
304
305 tp->ftt_installed = 1;
306
307 return (0);
308}
309
310int
311fasttrap_tracepoint_remove(proc_t *p, fasttrap_tracepoint_t *tp)
312{
313 /* The thumb patch is a 2 byte instruction regardless of the size of the original instruction */
314 uint32_t instr;
315 int size = tp->ftt_thumb ? 2 : 4;
316
317 /*
318 * Distinguish between read or write failures and a changed
319 * instruction.
320 */
321 if (uread(p, &instr, size, tp->ftt_pc) != 0)
322 goto end;
323 if (tp->ftt_thumb) {
324 if (*((uint16_t*) &instr) != FASTTRAP_THUMB_INSTR)
325 goto end;
326 } else {
327 if (instr != FASTTRAP_ARM_INSTR)
328 goto end;
329 }
330 if (patchInst(p, &tp->ftt_instr, size, tp->ftt_pc) != 0)
331 return (-1);
332
333end:
334 tp->ftt_installed = 0;
335
336 return (0);
337}
338
339static void
340fasttrap_return_common(proc_t *p, arm_saved_state_t *regs, user_addr_t pc, user_addr_t new_pc)
341{
342 pid_t pid = p->p_pid;
343 fasttrap_tracepoint_t *tp;
344 fasttrap_bucket_t *bucket;
345 fasttrap_id_t *id;
346 lck_mtx_t *pid_mtx;
347 int retire_tp = 1;
348
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)];
352
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)
356 break;
357 }
358
359 /*
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.
363 */
364 if (tp == NULL) {
365 lck_mtx_unlock(pid_mtx);
366 return;
367 }
368
369 for (id = tp->ftt_retids; id != NULL; id = id->fti_next) {
370 fasttrap_probe_t *probe = id->fti_probe;
371 /*
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.
375 */
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)
379 continue;
380
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) {
384 continue;
385 }
386 }
387 /*
388 * If we have at least one probe associated that
389 * is not a oneshot probe, don't remove the
390 * tracepoint
391 */
392 else {
393 retire_tp = 0;
394 }
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);
399#else
400 if (FALSE) {
401#endif
402 } else {
403 dtrace_probe(id->fti_probe->ftp_id,
404 pc - id->fti_probe->ftp_faddr,
405 regs->r[0], 0, 0, 0);
406 }
407 }
408 if (retire_tp) {
409 fasttrap_tracepoint_retire(p, tp);
410 }
411
412 lck_mtx_unlock(pid_mtx);
413}
414
415static void
416fasttrap_sigsegv(proc_t *p, uthread_t t, user_addr_t addr, arm_saved_state_t *regs)
417{
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.
420 */
421#if DEBUG
422#pragma unused(p,t,addr,arm_saved_state)
423 panic("fasttrap: sigsegv not yet implemented");
424#else
425#pragma unused(p,t,addr)
426 /* Kill the process */
427 regs->pc = 0;
428#endif
429
430#if 0
431 proc_lock(p);
432
433 /* Set fault address and mark signal */
434 t->uu_code = addr;
435 t->uu_siglist |= sigmask(SIGSEGV);
436
437 /*
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.
441 */
442 t->uu_exception = KERN_INVALID_ADDRESS; /* SIGSEGV */
443 t->uu_subcode = 0; /* XXX pad */
444
445 proc_unlock(p);
446
447 /* raise signal */
448 signal_setast(t->uu_context.vc_thread);
449#endif
450}
451
452static void
453fasttrap_usdt_args(fasttrap_probe_t *probe, arm_saved_state_t *regs, int argc,
454 uint32_t *argv)
455{
456 int i, x, cap = MIN(argc, probe->ftp_nargs);
457
458 for (i = 0; i < cap; i++) {
459 x = probe->ftp_argmap[i];
460
461 if (x < 4) {
462 argv[i] = regs->r[x];
463 } else {
464 fasttrap_fuword32_noerr(regs->sp + (x - 4) * sizeof(uint32_t), &argv[i]);
465 }
466 }
467
468 for (; i < argc; i++) {
469 argv[i] = 0;
470 }
471}
472
473static void set_thumb_flag(arm_saved_state_t *regs, user_addr_t pc)
474{
475 if (pc & 1) {
476 regs->cpsr |= PSR_TF;
477 } else {
478 regs->cpsr &= ~PSR_TF;
479 }
480}
481
482int
483fasttrap_pid_probe(arm_saved_state_t *regs)
484{
485 proc_t *p = current_proc();
486 user_addr_t new_pc = 0;
487 fasttrap_bucket_t *bucket;
488 lck_mtx_t *pid_mtx;
489 fasttrap_tracepoint_t *tp, tp_local;
490 pid_t pid;
491 dtrace_icookie_t cookie;
492 uint_t is_enabled = 0;
493 int instr_size;
494 int was_simulated = 1, retire_tp = 1;
495
496 user_addr_t pc = regs->pc;
497
498 uthread_t uthread = (uthread_t) get_bsdthread_info(current_thread());
499
500 /*
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.
505 */
506 if (uthread->t_dtrace_step) {
507 ASSERT(uthread->t_dtrace_on);
508 fasttrap_sigtrap(p, uthread, pc);
509 return (0);
510 }
511
512 /*
513 * Clear all user tracing flags.
514 */
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;
520
521 /*
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
524 * process: this one.
525 */
526 if (p->p_lflag & P_LINVFORK) {
527 proc_list_lock();
528 while (p->p_lflag & P_LINVFORK)
529 p = p->p_pptr;
530 proc_list_unlock();
531 }
532
533 pid = p->p_pid;
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)];
537
538 /*
539 * Lookup the tracepoint that the process just hit.
540 */
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)
544 break;
545 }
546
547 /*
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.
551 */
552 if (tp == NULL) {
553 lck_mtx_unlock(pid_mtx);
554 return (-1);
555 }
556
557 /* Default to always execute */
558 int condition_code = 0xE;
559 if (tp->ftt_thumb) {
560 uint32_t itstate = GETITSTATE(regs->cpsr);
561 if (itstate != 0) {
562 /* In IT block, make sure it's the last statement in the block */
563 if (ISLASTINIT(itstate)) {
564 condition_code = itstate >> 4;
565 } else {
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);
568
569 fasttrap_tracepoint_remove(p, tp);
570 lck_mtx_unlock(pid_mtx);
571 return (-1);
572 }
573 }
574 } else {
575 condition_code = ARM_CONDCODE(tp->ftt_instr);
576 }
577
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.
581 */
582 fasttrap_tracepoint_remove(p, tp);
583 lck_mtx_unlock(pid_mtx);
584 return (-1);
585 }
586
587 if (tp->ftt_ids != NULL) {
588 fasttrap_id_t *id;
589
590 uint32_t s4;
591 uint32_t *stack = (uint32_t *)regs->sp;
592
593 /* First four parameters are passed in registers */
594 fasttrap_fuword32_noerr((user_addr_t)(uint32_t)stack, &s4);
595
596 for (id = tp->ftt_ids; id != NULL; id = id->fti_next) {
597 fasttrap_probe_t *probe = id->fti_probe;
598
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);
603#else
604 if (FALSE) {
605#endif
606 } else {
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) {
610 continue;
611 }
612 }
613 /*
614 * If we have at least probe associated that
615 * is not a oneshot probe, don't remove the
616 * tracepoint
617 */
618 else {
619 retire_tp = 0;
620 }
621 if (id->fti_ptype == DTFTP_ENTRY) {
622 /*
623 * We note that this was an entry
624 * probe to help ustack() find the
625 * first caller.
626 */
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) {
633 /*
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.
639 */
640 is_enabled = 1;
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);
643 } else {
644 uint32_t t[5];
645
646 fasttrap_usdt_args(probe, regs, 5, t);
647 dtrace_probe(probe->ftp_id, t[0], t[1], t[2], t[3], t[4]);
648 }
649 }
650 }
651 if (retire_tp) {
652 fasttrap_tracepoint_retire(p, tp);
653 }
654 }
655 /*
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.
659 */
660 tp_local = *tp;
661 lck_mtx_unlock(pid_mtx);
662 tp = &tp_local;
663
664 /*
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.
674 */
675
676 if (is_enabled) {
677 regs->r[0] = 1;
678 new_pc = regs->pc + (tp->ftt_thumb ? 2 : 4);
679 goto done;
680 }
681
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);
686 goto done;
687 }
688
689 instr_size = dtrace_instr_size(tp->ftt_instr,tp->ftt_thumb);
690
691 switch (tp->ftt_type) {
692 case FASTTRAP_T_MOV_PC_REG:
693 case FASTTRAP_T_CPY_PC:
694 {
695 if (!dtrace_arm_condition_true(condition_code, regs->cpsr)) {
696 new_pc = pc + instr_size;
697 break;
698 }
699
700 int rm;
701 if (tp->ftt_thumb) {
702 rm = THUMB16_HRM(tp->ftt_instr1);
703 } else {
704 rm = tp->ftt_instr & 0xF;
705 }
706 new_pc = regs->r[rm];
707
708 /* This instruction does not change the Thumb state */
709
710 break;
711 }
712
713 case FASTTRAP_T_STM_LR:
714 case FASTTRAP_T_PUSH_LR:
715 {
716 /*
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.
724 *
725 * Some of the same issues that apply to POP_PC probably apply here also.
726 */
727
728 int reglist;
729 int ret;
730 uintptr_t* base;
731
732 if (!dtrace_arm_condition_true(condition_code, regs->cpsr)) {
733 new_pc = pc + instr_size;
734 break;
735 }
736
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 */
740 goto instr_emulate;
741 }
742
743 if (tp->ftt_thumb) {
744 if (instr_size == 4) {
745 /* We know we have to push lr, never push sp or pc */
746 reglist = tp->ftt_instr2 & 0x1FFF;
747 } else {
748 reglist = tp->ftt_instr1 & 0xFF;
749 }
750 } else {
751 /* We know we have to push lr, never push sp or pc */
752 reglist = tp->ftt_instr & 0x1FFF;
753 }
754
755 /* Push the link register */
756 base--;
757 ret = fasttrap_suword32((uint32_t) base, regs->lr);
758 if (ret == -1) {
759 fasttrap_sigsegv(p, uthread, (user_addr_t) base, regs);
760 new_pc = regs->pc;
761 break;
762 }
763
764 /* Start pushing from $r12 */
765 int regmask = 1 << 12;
766 int regnum = 12;
767
768 while (regmask) {
769 if (reglist & regmask) {
770 base--;
771 ret = fasttrap_suword32((uint32_t) base, regs->r[regnum]);
772 if (ret == -1) {
773 fasttrap_sigsegv(p, uthread, (user_addr_t) base, regs);
774 new_pc = regs->pc;
775 break;
776 }
777 }
778 regmask >>= 1;
779 regnum--;
780 }
781
782 regs->sp = (uintptr_t) base;
783
784 new_pc = pc + instr_size;
785
786 break;
787 }
788
789
790 case FASTTRAP_T_LDM_PC:
791 case FASTTRAP_T_POP_PC:
792 {
793 /* TODO Two issues that will eventually need to be resolved:
794 *
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.
799 *
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.
804 *
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.
808 *
809 */
810
811 /* Assume ldmia! sp/pop ... pc */
812
813 int regnum = 0, reglist;
814 int ret;
815 uintptr_t* base;
816
817 if (!dtrace_arm_condition_true(condition_code, regs->cpsr)) {
818 new_pc = pc + instr_size;
819 break;
820 }
821
822 if (tp->ftt_thumb) {
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;
826 } else {
827 reglist = tp->ftt_instr1 & 0xFF;
828 }
829 } else {
830 /* We know we have to load the pc, don't do it twice */
831 reglist = tp->ftt_instr & 0x7FFF;
832 }
833
834 base = (uintptr_t*) regs->sp;
835 while (reglist) {
836 if (reglist & 1) {
837 ret = fasttrap_fuword32((uint32_t) base, &regs->r[regnum]);
838 if (ret == -1) {
839 fasttrap_sigsegv(p, uthread, (user_addr_t) base, regs);
840 new_pc = regs->pc;
841 break;
842 }
843 base++;
844 }
845 reglist >>= 1;
846 regnum++;
847 }
848
849 ret = fasttrap_fuword32((uint32_t) base, &new_pc);
850 if (ret == -1) {
851 fasttrap_sigsegv(p, uthread, (user_addr_t) base, regs);
852 new_pc = regs->pc;
853 break;
854 }
855 base++;
856
857 regs->sp = (uintptr_t) base;
858
859 set_thumb_flag(regs, new_pc);
860
861 break;
862 }
863
864 case FASTTRAP_T_CB_N_Z:
865 {
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;
872 } else {
873 new_pc = pc + instr_size;
874 }
875 break;
876 }
877
878 case FASTTRAP_T_B_COND:
879 {
880 /* Use the condition code in the instruction and ignore the ITSTATE */
881
882 int code, offset;
883 if (tp->ftt_thumb) {
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");
888 }
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),
896 21);
897 } else {
898 code = (tp->ftt_instr1 >> 8) & 0xF;
899 if (code == 14 || code == 15) {
900 panic("fasttrap: Emulation of invalid branch");
901 }
902 offset = 4 + (SIGNEXTEND(tp->ftt_instr1 & 0xFF, 8) << 1);
903 }
904 } else {
905 code = ARM_CONDCODE(tp->ftt_instr);
906 if (code == 15) {
907 panic("fasttrap: Emulation of invalid branch");
908 }
909 offset = 8 + (SIGNEXTEND(tp->ftt_instr & 0x00FFFFFF, 24) << 2);
910 }
911
912 if (dtrace_arm_condition_true(code, regs->cpsr)) {
913 new_pc = pc + offset;
914 } else {
915 new_pc = pc + instr_size;
916 }
917
918 break;
919 }
920
921 case FASTTRAP_T_B_UNCOND:
922 {
923 int offset;
924
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);
928
929 if (!dtrace_arm_condition_true(condition_code, regs->cpsr)) {
930 new_pc = pc + instr_size;
931 break;
932 }
933
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),
943 25);
944 } else {
945 uint32_t instr1 = tp->ftt_instr1;
946 offset = 4 + (SIGNEXTEND(instr1 & 0x7FF, 11) << 1);
947 }
948
949 new_pc = pc + offset;
950
951 break;
952 }
953
954 case FASTTRAP_T_BX_REG:
955 {
956 int reg;
957
958 if (!dtrace_arm_condition_true(condition_code, regs->cpsr)) {
959 new_pc = pc + instr_size;
960 break;
961 }
962
963 if (tp->ftt_thumb) {
964 reg = THUMB16_HRM(tp->ftt_instr1);
965 } else {
966 reg = ARM_RM(tp->ftt_instr);
967 }
968 new_pc = regs->r[reg];
969 set_thumb_flag(regs, new_pc);
970
971 break;
972 }
973
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.
979 */
980
981 /* Fall through */
982
983 instr_emulate:
984 case FASTTRAP_T_COMMON:
985 {
986 user_addr_t addr;
987 uint8_t scratch[32];
988 uint_t i = 0;
989 fasttrap_instr_t emul_instr;
990 emul_instr.instr32 = tp->ftt_instr;
991 int emul_instr_size;
992
993 /*
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.
999 */
1000 uint8_t emul_thumb = tp->ftt_thumb;
1001 int save_reg = -1;
1002 uint32_t save_val = 0;
1003
1004 /*
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.
1014 */
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.
1018 */
1019 int new_reg;
1020 if (tp->ftt_thumb) {
1021 /* Check to see if thumb or thumb2 */
1022 if (instr_size == 2) {
1023 /*
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.
1028 */
1029 if (!dtrace_arm_condition_true(condition_code, regs->cpsr)) {
1030 new_pc = pc + instr_size;
1031 break;
1032 }
1033
1034 new_reg = (tp->ftt_instr1 >> 8) & 0x7;
1035 regs->r[new_reg] = ALIGNADDR(regs->pc + 4, 2);
1036 emul_thumb = 0;
1037 emul_instr.instr32 = 0xE5900000 | (new_reg << 16) | (new_reg << 12) | ((tp->ftt_instr1 & 0xFF) << 2);
1038 } else {
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;
1044 }
1045 } else {
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;
1051 }
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.
1055 */
1056 save_reg = 0;
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;
1061 } else {
1062 emul_instr.instr32 &= ~0x000F0000;
1063 }
1064 }
1065
1066 emul_instr_size = dtrace_instr_size(emul_instr.instr32, emul_thumb);
1067
1068 /*
1069 * At this point:
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
1074 */
1075
1076 addr = uthread->t_dtrace_scratch->addr;
1077
1078 if (addr == 0LL) {
1079 fasttrap_sigtrap(p, uthread, pc); // Should be killing target proc
1080 new_pc = pc;
1081 break;
1082 }
1083
1084 uthread->t_dtrace_scrpc = addr;
1085 if (emul_thumb) {
1086 /*
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.
1092 *
1093 * Layout of scratch space for Thumb mode:
1094 * Emulated instruction
1095 * ldr save_reg, [pc, #16] (if necessary, restore any register we clobbered)
1096 * push { r0, r1 }
1097 * ldr r0, [pc, #4]
1098 * str r0, [sp, #4]
1099 * pop { r0, pc }
1100 * Location we should return to in original program
1101 * Saved value of clobbered register (if necessary)
1102 */
1103
1104 bcopy(&emul_instr, &scratch[i], emul_instr_size); i += emul_instr_size;
1105
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]
1110 }
1111
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 }
1116
1117 if (i % 4) {
1118 SET16(scratch+i, 0); i += 2; // padding - saved 32 bit words must be aligned
1119 }
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
1123 }
1124
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;
1128 } else {
1129 /*
1130 * Layout of scratch space for ARM mode:
1131 * Emulated instruction
1132 * ldr save_reg, [pc, #12] (if necessary, restore any register we clobbered)
1133 * ldr pc, [pc, #4]
1134 * Location we should return to in original program
1135 * Saved value of clobbered register (if necessary)
1136 */
1137
1138 bcopy(&emul_instr, &scratch[i], emul_instr_size); i += emul_instr_size;
1139
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]
1144 }
1145 SET32(scratch+i, 0xE51FF004); i += 4; // ldr pc, [pc, #4]
1146
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
1150 }
1151
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;
1155 }
1156
1157 if (patchInst(p, scratch, i, uthread->t_dtrace_scratch->write_addr) != KERN_SUCCESS) {
1158 fasttrap_sigtrap(p, uthread, pc);
1159 new_pc = pc;
1160 break;
1161 }
1162
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);
1167 } else {
1168 new_pc = uthread->t_dtrace_scrpc + (emul_thumb ? 1 : 0);
1169 }
1170
1171 uthread->t_dtrace_pc = pc;
1172 uthread->t_dtrace_npc = pc + instr_size;
1173 uthread->t_dtrace_on = 1;
1174 was_simulated = 0;
1175 set_thumb_flag(regs, new_pc);
1176 break;
1177 }
1178
1179 default:
1180 panic("fasttrap: mishandled an instruction");
1181 }
1182
1183done:
1184 /*
1185 * APPLE NOTE:
1186 *
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.
1191 */
1192 regs->pc = new_pc;
1193
1194 /*
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
1198 * time around.
1199 */
1200 if (tp->ftt_retids != NULL) {
1201 /*
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.
1207 */
1208 /*
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.
1213 */
1214 if (was_simulated) {
1215 fasttrap_return_common(p, regs, pc, new_pc);
1216 } else {
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);
1221 }
1222 }
1223
1224 return (0);
1225}
1226
1227int
1228fasttrap_return_probe(arm_saved_state_t *regs)
1229{
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;
1234
1235 uthread->t_dtrace_pc = 0;
1236 uthread->t_dtrace_npc = 0;
1237 uthread->t_dtrace_scrpc = 0;
1238 uthread->t_dtrace_astpc = 0;
1239
1240 /*
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.
1244 */
1245 if (p->p_lflag & P_LINVFORK) {
1246 proc_list_lock();
1247 while (p->p_lflag & P_LINVFORK)
1248 p = p->p_pptr;
1249 proc_list_unlock();
1250 }
1251
1252 /*
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.
1258 */
1259 regs->pc = pc;
1260
1261 fasttrap_return_common(p, regs, pc, npc);
1262
1263 return (0);
1264}
1265
1266uint64_t
1267fasttrap_pid_getarg(void *arg, dtrace_id_t id, void *parg, int argno,
1268 int aframes)
1269{
1270#pragma unused(arg, id, parg, aframes)
1271 arm_saved_state_t* regs = find_user_regs(current_thread());
1272
1273 /* First four arguments are in registers */
1274 if (argno < 4)
1275 return regs->r[argno];
1276
1277 /* Look on the stack for the rest */
1278 uint32_t value;
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);
1283
1284 return value;
1285}
1286
1287uint64_t
1288fasttrap_usdt_getarg(void *arg, dtrace_id_t id, void *parg, int argno, int aframes)
1289{
1290#pragma unused(arg, id, parg, argno, aframes)
1291#if 0
1292 return (fasttrap_anarg(ttolwp(curthread)->lwp_regs, 0, argno));
1293#endif
1294
1295 return 0;
1296}
1297