]> git.saurik.com Git - apple/xnu.git/blob - bsd/dev/arm/fasttrap_isa.c
xnu-4903.221.2.tar.gz
[apple/xnu.git] / bsd / dev / arm / fasttrap_isa.c
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
56 extern 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
61 extern int dtrace_decode_arm(uint32_t instr);
62 extern 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
114 extern int dtrace_arm_condition_true(int cond, int cpsr);
115
116 int
117 fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp,
118 user_addr_t pc, fasttrap_probe_type_t type)
119 {
120 #pragma unused(type)
121 uint32_t instr;
122
123 /*
124 * Read the instruction at the given address out of the process's
125 * address space. We don't have to worry about a debugger
126 * changing this instruction before we overwrite it with our trap
127 * instruction since P_PR_LOCK is set. Since instructions can span
128 * pages, we potentially read the instruction in two parts. If the
129 * second part fails, we just zero out that part of the instruction.
130 */
131 /*
132 * APPLE NOTE: Of course, we do not have a P_PR_LOCK, so this is racey...
133 */
134
135 if (uread(p, &instr, 4, pc) != 0)
136 return (-1);
137
138 /* We want &instr to always point to the saved instruction, so just copy the
139 * whole thing When cast to a pointer to a uint16_t, that will give us a
140 * pointer to the first two bytes, which is the thumb instruction.
141 */
142 tp->ftt_instr = instr;
143
144 if (tp->ftt_fntype != FASTTRAP_FN_DONE_INIT) {
145 switch(tp->ftt_fntype) {
146 case FASTTRAP_FN_UNKNOWN:
147 /* Can't instrument without any information. We can add some heuristics later if necessary. */
148 return (-1);
149
150 case FASTTRAP_FN_USDT:
151 if (IS_ARM_NOP(instr) || IS_ARM_IS_ENABLED(instr)) {
152 tp->ftt_thumb = 0;
153 } else if (IS_THUMB_NOP(THUMB_INSTR(instr)) || IS_THUMB_IS_ENABLED(THUMB_INSTR(instr))) {
154 tp->ftt_thumb = 1;
155 } else {
156 /* Shouldn't reach here - this means we don't recognize
157 * the instruction at one of the USDT probe locations
158 */
159 return (-1);
160 }
161 tp->ftt_fntype = FASTTRAP_FN_DONE_INIT;
162 break;
163
164 case FASTTRAP_FN_ARM:
165 tp->ftt_thumb = 0;
166 tp->ftt_fntype = FASTTRAP_FN_DONE_INIT;
167 break;
168
169 case FASTTRAP_FN_THUMB:
170 tp->ftt_thumb = 1;
171 tp->ftt_fntype = FASTTRAP_FN_DONE_INIT;
172 break;
173
174 default:
175 return (-1);
176 }
177 }
178
179 if (tp->ftt_thumb) {
180 tp->ftt_type = dtrace_decode_thumb(instr);
181 } else {
182 tp->ftt_type = dtrace_decode_arm(instr);
183 }
184
185 if (tp->ftt_type == FASTTRAP_T_INV) {
186 /* This is an instruction we either don't recognize or can't instrument */
187 printf("dtrace: fasttrap: Unrecognized instruction: %08x at %08x\n",
188 (tp->ftt_thumb && dtrace_instr_size(tp->ftt_instr,tp->ftt_thumb) == 2) ? tp->ftt_instr1 : instr, pc);
189 return (-1);
190 }
191
192 return (0);
193 }
194
195 int
196 fasttrap_tracepoint_install(proc_t *p, fasttrap_tracepoint_t *tp)
197 {
198 /* The thumb patch is a 2 byte instruction regardless of the size of the original instruction */
199 uint32_t instr;
200 int size = tp->ftt_thumb ? 2 : 4;
201
202 if (tp->ftt_thumb) {
203 *((uint16_t*) &instr) = FASTTRAP_THUMB_INSTR;
204 } else {
205 instr = FASTTRAP_ARM_INSTR;
206 }
207
208 if (uwrite(p, &instr, size, tp->ftt_pc) != 0)
209 return (-1);
210
211 tp->ftt_installed = 1;
212
213 return (0);
214 }
215
216 int
217 fasttrap_tracepoint_remove(proc_t *p, fasttrap_tracepoint_t *tp)
218 {
219 /* The thumb patch is a 2 byte instruction regardless of the size of the original instruction */
220 uint32_t instr;
221 int size = tp->ftt_thumb ? 2 : 4;
222
223 /*
224 * Distinguish between read or write failures and a changed
225 * instruction.
226 */
227 if (uread(p, &instr, size, tp->ftt_pc) != 0)
228 goto end;
229 if (tp->ftt_thumb) {
230 if (*((uint16_t*) &instr) != FASTTRAP_THUMB_INSTR)
231 goto end;
232 } else {
233 if (instr != FASTTRAP_ARM_INSTR)
234 goto end;
235 }
236 if (uwrite(p, &tp->ftt_instr, size, tp->ftt_pc) != 0)
237 return (-1);
238
239 end:
240 tp->ftt_installed = 0;
241
242 return (0);
243 }
244
245 static void
246 fasttrap_return_common(proc_t *p, arm_saved_state_t *regs, user_addr_t pc, user_addr_t new_pc)
247 {
248 pid_t pid = p->p_pid;
249 fasttrap_tracepoint_t *tp;
250 fasttrap_bucket_t *bucket;
251 fasttrap_id_t *id;
252 lck_mtx_t *pid_mtx;
253 int retire_tp = 1;
254
255 pid_mtx = &cpu_core[CPU->cpu_id].cpuc_pid_lock;
256 lck_mtx_lock(pid_mtx);
257 bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)];
258
259 for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) {
260 if (pid == tp->ftt_pid && pc == tp->ftt_pc &&
261 tp->ftt_proc->ftpc_acount != 0)
262 break;
263 }
264
265 /*
266 * Don't sweat it if we can't find the tracepoint again; unlike
267 * when we're in fasttrap_pid_probe(), finding the tracepoint here
268 * is not essential to the correct execution of the process.
269 */
270 if (tp == NULL) {
271 lck_mtx_unlock(pid_mtx);
272 return;
273 }
274
275 for (id = tp->ftt_retids; id != NULL; id = id->fti_next) {
276 fasttrap_probe_t *probe = id->fti_probe;
277 /*
278 * If there's a branch that could act as a return site, we
279 * need to trace it, and check here if the program counter is
280 * external to the function.
281 */
282 if (tp->ftt_type != FASTTRAP_T_LDM_PC &&
283 tp->ftt_type != FASTTRAP_T_POP_PC &&
284 new_pc - probe->ftp_faddr < probe->ftp_fsize)
285 continue;
286
287 if (probe->ftp_prov->ftp_provider_type == DTFTP_PROVIDER_ONESHOT) {
288 uint8_t already_triggered = atomic_or_8(&probe->ftp_triggered, 1);
289 if (already_triggered) {
290 continue;
291 }
292 }
293 /*
294 * If we have at least one probe associated that
295 * is not a oneshot probe, don't remove the
296 * tracepoint
297 */
298 else {
299 retire_tp = 0;
300 }
301 #ifndef CONFIG_EMBEDDED
302 if (ISSET(current_proc()->p_lflag, P_LNOATTACH)) {
303 dtrace_probe(dtrace_probeid_error, 0 /* state */, id->fti_probe->ftp_id,
304 1 /* ndx */, -1 /* offset */, DTRACEFLT_UPRIV);
305 #else
306 if (FALSE) {
307 #endif
308 } else {
309 dtrace_probe(id->fti_probe->ftp_id,
310 pc - id->fti_probe->ftp_faddr,
311 regs->r[0], 0, 0, 0);
312 }
313 }
314 if (retire_tp) {
315 fasttrap_tracepoint_retire(p, tp);
316 }
317
318 lck_mtx_unlock(pid_mtx);
319 }
320
321 static void
322 fasttrap_sigsegv(proc_t *p, uthread_t t, user_addr_t addr, arm_saved_state_t *regs)
323 {
324 /* TODO: This function isn't implemented yet. In debug mode, panic the system to
325 * find out why we're hitting this point. In other modes, kill the process.
326 */
327 #if DEBUG
328 #pragma unused(p,t,addr,arm_saved_state)
329 panic("fasttrap: sigsegv not yet implemented");
330 #else
331 #pragma unused(p,t,addr)
332 /* Kill the process */
333 regs->pc = 0;
334 #endif
335
336 #if 0
337 proc_lock(p);
338
339 /* Set fault address and mark signal */
340 t->uu_code = addr;
341 t->uu_siglist |= sigmask(SIGSEGV);
342
343 /*
344 * XXX These two line may be redundant; if not, then we need
345 * XXX to potentially set the data address in the machine
346 * XXX specific thread state structure to indicate the address.
347 */
348 t->uu_exception = KERN_INVALID_ADDRESS; /* SIGSEGV */
349 t->uu_subcode = 0; /* XXX pad */
350
351 proc_unlock(p);
352
353 /* raise signal */
354 signal_setast(t->uu_context.vc_thread);
355 #endif
356 }
357
358 static void
359 fasttrap_usdt_args(fasttrap_probe_t *probe, arm_saved_state_t *regs, int argc,
360 uint32_t *argv)
361 {
362 int i, x, cap = MIN(argc, probe->ftp_nargs);
363
364 for (i = 0; i < cap; i++) {
365 x = probe->ftp_argmap[i];
366
367 if (x < 4) {
368 argv[i] = regs->r[x];
369 } else {
370 fasttrap_fuword32_noerr(regs->sp + (x - 4) * sizeof(uint32_t), &argv[i]);
371 }
372 }
373
374 for (; i < argc; i++) {
375 argv[i] = 0;
376 }
377 }
378
379 static void set_thumb_flag(arm_saved_state_t *regs, user_addr_t pc)
380 {
381 if (pc & 1) {
382 regs->cpsr |= PSR_TF;
383 } else {
384 regs->cpsr &= ~PSR_TF;
385 }
386 }
387
388 int
389 fasttrap_pid_probe(arm_saved_state_t *regs)
390 {
391 proc_t *p = current_proc();
392 user_addr_t new_pc = 0;
393 fasttrap_bucket_t *bucket;
394 lck_mtx_t *pid_mtx;
395 fasttrap_tracepoint_t *tp, tp_local;
396 pid_t pid;
397 dtrace_icookie_t cookie;
398 uint_t is_enabled = 0;
399 int instr_size;
400 int was_simulated = 1, retire_tp = 1;
401
402 user_addr_t pc = regs->pc;
403
404 uthread_t uthread = (uthread_t) get_bsdthread_info(current_thread());
405
406 /*
407 * It's possible that a user (in a veritable orgy of bad planning)
408 * could redirect this thread's flow of control before it reached the
409 * return probe fasttrap. In this case we need to kill the process
410 * since it's in a unrecoverable state.
411 */
412 if (uthread->t_dtrace_step) {
413 ASSERT(uthread->t_dtrace_on);
414 fasttrap_sigtrap(p, uthread, pc);
415 return (0);
416 }
417
418 /*
419 * Clear all user tracing flags.
420 */
421 uthread->t_dtrace_ft = 0;
422 uthread->t_dtrace_pc = 0;
423 uthread->t_dtrace_npc = 0;
424 uthread->t_dtrace_scrpc = 0;
425 uthread->t_dtrace_astpc = 0;
426
427 /*
428 * Treat a child created by a call to vfork(2) as if it were its
429 * parent. We know that there's only one thread of control in such a
430 * process: this one.
431 */
432 if (p->p_lflag & P_LINVFORK) {
433 proc_list_lock();
434 while (p->p_lflag & P_LINVFORK)
435 p = p->p_pptr;
436 proc_list_unlock();
437 }
438
439 pid = p->p_pid;
440 pid_mtx = &cpu_core[CPU->cpu_id].cpuc_pid_lock;
441 lck_mtx_lock(pid_mtx);
442 bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid,pc)];
443
444 /*
445 * Lookup the tracepoint that the process just hit.
446 */
447 for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) {
448 if (pid == tp->ftt_pid && pc == tp->ftt_pc &&
449 tp->ftt_proc->ftpc_acount != 0)
450 break;
451 }
452
453 /*
454 * If we couldn't find a matching tracepoint, either a tracepoint has
455 * been inserted without using the pid<pid> ioctl interface (see
456 * fasttrap_ioctl), or somehow we have mislaid this tracepoint.
457 */
458 if (tp == NULL) {
459 lck_mtx_unlock(pid_mtx);
460 return (-1);
461 }
462
463 /* Default to always execute */
464 int condition_code = 0xE;
465 if (tp->ftt_thumb) {
466 uint32_t itstate = GETITSTATE(regs->cpsr);
467 if (itstate != 0) {
468 /* In IT block, make sure it's the last statement in the block */
469 if (ISLASTINIT(itstate)) {
470 condition_code = itstate >> 4;
471 } else {
472 printf("dtrace: fasttrap: Tried to trace instruction %08x at %08x but not at end of IT block\n",
473 (tp->ftt_thumb && dtrace_instr_size(tp->ftt_instr,tp->ftt_thumb) == 2) ? tp->ftt_instr1 : tp->ftt_instr, pc);
474
475 fasttrap_tracepoint_remove(p, tp);
476 lck_mtx_unlock(pid_mtx);
477 return (-1);
478 }
479 }
480 } else {
481 condition_code = ARM_CONDCODE(tp->ftt_instr);
482 }
483
484 if (!tp->ftt_thumb != !(regs->cpsr & PSR_TF)) {
485 /* The ARM/Thumb mode does not match what we expected for this probe.
486 * Remove this probe and bail.
487 */
488 fasttrap_tracepoint_remove(p, tp);
489 lck_mtx_unlock(pid_mtx);
490 return (-1);
491 }
492
493 if (tp->ftt_ids != NULL) {
494 fasttrap_id_t *id;
495
496 uint32_t s4;
497 uint32_t *stack = (uint32_t *)regs->sp;
498
499 /* First four parameters are passed in registers */
500 fasttrap_fuword32_noerr((user_addr_t)(uint32_t)stack, &s4);
501
502 for (id = tp->ftt_ids; id != NULL; id = id->fti_next) {
503 fasttrap_probe_t *probe = id->fti_probe;
504
505 #ifndef CONFIG_EMBEDDED
506 if (ISSET(current_proc()->p_lflag, P_LNOATTACH)) {
507 dtrace_probe(dtrace_probeid_error, 0 /* state */, probe->ftp_id,
508 1 /* ndx */, -1 /* offset */, DTRACEFLT_UPRIV);
509 #else
510 if (FALSE) {
511 #endif
512 } else {
513 if (probe->ftp_prov->ftp_provider_type == DTFTP_PROVIDER_ONESHOT) {
514 uint8_t already_triggered = atomic_or_8(&probe->ftp_triggered, 1);
515 if (already_triggered) {
516 continue;
517 }
518 }
519 /*
520 * If we have at least probe associated that
521 * is not a oneshot probe, don't remove the
522 * tracepoint
523 */
524 else {
525 retire_tp = 0;
526 }
527 if (id->fti_ptype == DTFTP_ENTRY) {
528 /*
529 * We note that this was an entry
530 * probe to help ustack() find the
531 * first caller.
532 */
533 cookie = dtrace_interrupt_disable();
534 DTRACE_CPUFLAG_SET(CPU_DTRACE_ENTRY);
535 dtrace_probe(probe->ftp_id, regs->r[0], regs->r[1], regs->r[2], regs->r[3], s4);
536 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_ENTRY);
537 dtrace_interrupt_enable(cookie);
538 } else if (id->fti_ptype == DTFTP_IS_ENABLED) {
539 /*
540 * Note that in this case, we don't
541 * call dtrace_probe() since it's only
542 * an artificial probe meant to change
543 * the flow of control so that it
544 * encounters the true probe.
545 */
546 is_enabled = 1;
547 } else if (probe->ftp_argmap == NULL) {
548 dtrace_probe(probe->ftp_id, regs->r[0], regs->r[1], regs->r[2], regs->r[3], s4);
549 } else {
550 uint32_t t[5];
551
552 fasttrap_usdt_args(probe, regs, 5, t);
553 dtrace_probe(probe->ftp_id, t[0], t[1], t[2], t[3], t[4]);
554 }
555 }
556 }
557 if (retire_tp) {
558 fasttrap_tracepoint_retire(p, tp);
559 }
560 }
561 /*
562 * We're about to do a bunch of work so we cache a local copy of
563 * the tracepoint to emulate the instruction, and then find the
564 * tracepoint again later if we need to light up any return probes.
565 */
566 tp_local = *tp;
567 lck_mtx_unlock(pid_mtx);
568 tp = &tp_local;
569
570 /*
571 * If there's an is-enabled probe connected to this tracepoint it
572 * means that there was a 'eor r0,r0,r0'
573 * instruction that was placed there by DTrace when the binary was
574 * linked. As this probe is, in fact, enabled, we need to stuff 1
575 * into R0. Accordingly, we can bypass all the instruction
576 * emulation logic since we know the inevitable result. It's possible
577 * that a user could construct a scenario where the 'is-enabled'
578 * probe was on some other instruction, but that would be a rather
579 * exotic way to shoot oneself in the foot.
580 */
581
582 if (is_enabled) {
583 regs->r[0] = 1;
584 new_pc = regs->pc + (tp->ftt_thumb ? 2 : 4);
585 goto done;
586 }
587
588 /* For USDT probes, bypass all the emulation logic for the nop instruction */
589 if ((tp->ftt_thumb && IS_THUMB_NOP(THUMB_INSTR(tp->ftt_instr))) ||
590 (!tp->ftt_thumb && IS_ARM_NOP(tp->ftt_instr))) {
591 new_pc = regs->pc + (tp->ftt_thumb ? 2 : 4);
592 goto done;
593 }
594
595 instr_size = dtrace_instr_size(tp->ftt_instr,tp->ftt_thumb);
596
597 switch (tp->ftt_type) {
598 case FASTTRAP_T_MOV_PC_REG:
599 case FASTTRAP_T_CPY_PC:
600 {
601 if (!dtrace_arm_condition_true(condition_code, regs->cpsr)) {
602 new_pc = pc + instr_size;
603 break;
604 }
605
606 int rm;
607 if (tp->ftt_thumb) {
608 rm = THUMB16_HRM(tp->ftt_instr1);
609 } else {
610 rm = tp->ftt_instr & 0xF;
611 }
612 new_pc = regs->r[rm];
613
614 /* This instruction does not change the Thumb state */
615
616 break;
617 }
618
619 case FASTTRAP_T_STM_LR:
620 case FASTTRAP_T_PUSH_LR:
621 {
622 /*
623 * This is a very common case, so we want to emulate this instruction if
624 * possible. However, on a push, it is possible that we might reach the end
625 * of a page and have to allocate a new page. Most of the time this will not
626 * happen, and we know that the push instruction can store at most 16 words,
627 * so check to see if we are far from the boundary, and if so, emulate. This
628 * can be made more aggressive by checking the actual number of words being
629 * pushed, but we won't do that for now.
630 *
631 * Some of the same issues that apply to POP_PC probably apply here also.
632 */
633
634 int reglist;
635 int ret;
636 uintptr_t* base;
637
638 if (!dtrace_arm_condition_true(condition_code, regs->cpsr)) {
639 new_pc = pc + instr_size;
640 break;
641 }
642
643 base = (uintptr_t*) regs->sp;
644 if (((((uintptr_t) base)-16*4) >> PAGE_SHIFT) != (((uintptr_t) base) >> PAGE_SHIFT)) {
645 /* Crosses the page boundary, go to emulation */
646 goto instr_emulate;
647 }
648
649 if (tp->ftt_thumb) {
650 if (instr_size == 4) {
651 /* We know we have to push lr, never push sp or pc */
652 reglist = tp->ftt_instr2 & 0x1FFF;
653 } else {
654 reglist = tp->ftt_instr1 & 0xFF;
655 }
656 } else {
657 /* We know we have to push lr, never push sp or pc */
658 reglist = tp->ftt_instr & 0x1FFF;
659 }
660
661 /* Push the link register */
662 base--;
663 ret = fasttrap_suword32((uint32_t) base, regs->lr);
664 if (ret == -1) {
665 fasttrap_sigsegv(p, uthread, (user_addr_t) base, regs);
666 new_pc = regs->pc;
667 break;
668 }
669
670 /* Start pushing from $r12 */
671 int regmask = 1 << 12;
672 int regnum = 12;
673
674 while (regmask) {
675 if (reglist & regmask) {
676 base--;
677 ret = fasttrap_suword32((uint32_t) base, regs->r[regnum]);
678 if (ret == -1) {
679 fasttrap_sigsegv(p, uthread, (user_addr_t) base, regs);
680 new_pc = regs->pc;
681 break;
682 }
683 }
684 regmask >>= 1;
685 regnum--;
686 }
687
688 regs->sp = (uintptr_t) base;
689
690 new_pc = pc + instr_size;
691
692 break;
693 }
694
695
696 case FASTTRAP_T_LDM_PC:
697 case FASTTRAP_T_POP_PC:
698 {
699 /* TODO Two issues that will eventually need to be resolved:
700 *
701 * 1. Understand what the hardware does if we have to segfault (data abort) in
702 * the middle of a load multiple. We currently don't have a working segfault
703 * handler anyway, and with no swapfile we should never segfault on this load.
704 * If we do, we'll just kill the process by setting the pc to 0.
705 *
706 * 2. The emulation is no longer atomic. We currently only emulate pop for
707 * function epilogues, and so we should never have a race here because one
708 * thread should never be trying to manipulate another thread's stack frames.
709 * That is almost certainly a bug in the program.
710 *
711 * This will need to be fixed if we ever:
712 * a. Ship dtrace externally, as this could be a potential attack vector
713 * b. Support instruction level tracing, as we might then pop/ldm non epilogues.
714 *
715 */
716
717 /* Assume ldmia! sp/pop ... pc */
718
719 int regnum = 0, reglist;
720 int ret;
721 uintptr_t* base;
722
723 if (!dtrace_arm_condition_true(condition_code, regs->cpsr)) {
724 new_pc = pc + instr_size;
725 break;
726 }
727
728 if (tp->ftt_thumb) {
729 if (instr_size == 4) {
730 /* We know we have to load the pc, don't do it twice */
731 reglist = tp->ftt_instr2 & 0x7FFF;
732 } else {
733 reglist = tp->ftt_instr1 & 0xFF;
734 }
735 } else {
736 /* We know we have to load the pc, don't do it twice */
737 reglist = tp->ftt_instr & 0x7FFF;
738 }
739
740 base = (uintptr_t*) regs->sp;
741 while (reglist) {
742 if (reglist & 1) {
743 ret = fasttrap_fuword32((uint32_t) base, &regs->r[regnum]);
744 if (ret == -1) {
745 fasttrap_sigsegv(p, uthread, (user_addr_t) base, regs);
746 new_pc = regs->pc;
747 break;
748 }
749 base++;
750 }
751 reglist >>= 1;
752 regnum++;
753 }
754
755 ret = fasttrap_fuword32((uint32_t) base, &new_pc);
756 if (ret == -1) {
757 fasttrap_sigsegv(p, uthread, (user_addr_t) base, regs);
758 new_pc = regs->pc;
759 break;
760 }
761 base++;
762
763 regs->sp = (uintptr_t) base;
764
765 set_thumb_flag(regs, new_pc);
766
767 break;
768 }
769
770 case FASTTRAP_T_CB_N_Z:
771 {
772 /* Thumb mode instruction, and not permitted in IT block, so skip the condition code check */
773 int rn = tp->ftt_instr1 & 0x7;
774 int offset = (((tp->ftt_instr1 & 0x00F8) >> 2) | ((tp->ftt_instr1 & 0x0200) >> 3)) + 4;
775 int nonzero = tp->ftt_instr1 & 0x0800;
776 if (!nonzero != !(regs->r[rn] == 0)) {
777 new_pc = pc + offset;
778 } else {
779 new_pc = pc + instr_size;
780 }
781 break;
782 }
783
784 case FASTTRAP_T_B_COND:
785 {
786 /* Use the condition code in the instruction and ignore the ITSTATE */
787
788 int code, offset;
789 if (tp->ftt_thumb) {
790 if (instr_size == 4) {
791 code = (tp->ftt_instr1 >> 6) & 0xF;
792 if (code == 14 || code == 15) {
793 panic("fasttrap: Emulation of invalid branch");
794 }
795 int S = (tp->ftt_instr1 >> 10) & 1,
796 J1 = (tp->ftt_instr2 >> 13) & 1,
797 J2 = (tp->ftt_instr2 >> 11) & 1;
798 offset = 4 + SIGNEXTEND(
799 (S << 20) | (J2 << 19) | (J1 << 18) |
800 ((tp->ftt_instr1 & 0x003F) << 12) |
801 ((tp->ftt_instr2 & 0x07FF) << 1),
802 21);
803 } else {
804 code = (tp->ftt_instr1 >> 8) & 0xF;
805 if (code == 14 || code == 15) {
806 panic("fasttrap: Emulation of invalid branch");
807 }
808 offset = 4 + (SIGNEXTEND(tp->ftt_instr1 & 0xFF, 8) << 1);
809 }
810 } else {
811 code = ARM_CONDCODE(tp->ftt_instr);
812 if (code == 15) {
813 panic("fasttrap: Emulation of invalid branch");
814 }
815 offset = 8 + (SIGNEXTEND(tp->ftt_instr & 0x00FFFFFF, 24) << 2);
816 }
817
818 if (dtrace_arm_condition_true(code, regs->cpsr)) {
819 new_pc = pc + offset;
820 } else {
821 new_pc = pc + instr_size;
822 }
823
824 break;
825 }
826
827 case FASTTRAP_T_B_UNCOND:
828 {
829 int offset;
830
831 /* Unconditional branches can only be taken from Thumb mode */
832 /* (This is different from an ARM branch with condition code "always") */
833 ASSERT(tp->ftt_thumb == 1);
834
835 if (!dtrace_arm_condition_true(condition_code, regs->cpsr)) {
836 new_pc = pc + instr_size;
837 break;
838 }
839
840 if (instr_size == 4) {
841 int S = (tp->ftt_instr1 >> 10) & 1,
842 J1 = (tp->ftt_instr2 >> 13) & 1,
843 J2 = (tp->ftt_instr2 >> 11) & 1;
844 int I1 = (J1 != S) ? 0 : 1, I2 = (J2 != S) ? 0 : 1;
845 offset = 4 + SIGNEXTEND(
846 (S << 24) | (I1 << 23) | (I2 << 22) |
847 ((tp->ftt_instr1 & 0x03FF) << 12) |
848 ((tp->ftt_instr2 & 0x07FF) << 1),
849 25);
850 } else {
851 uint32_t instr1 = tp->ftt_instr1;
852 offset = 4 + (SIGNEXTEND(instr1 & 0x7FF, 11) << 1);
853 }
854
855 new_pc = pc + offset;
856
857 break;
858 }
859
860 case FASTTRAP_T_BX_REG:
861 {
862 int reg;
863
864 if (!dtrace_arm_condition_true(condition_code, regs->cpsr)) {
865 new_pc = pc + instr_size;
866 break;
867 }
868
869 if (tp->ftt_thumb) {
870 reg = THUMB16_HRM(tp->ftt_instr1);
871 } else {
872 reg = ARM_RM(tp->ftt_instr);
873 }
874 new_pc = regs->r[reg];
875 set_thumb_flag(regs, new_pc);
876
877 break;
878 }
879
880 case FASTTRAP_T_LDR_PC_IMMED:
881 case FASTTRAP_T_VLDR_PC_IMMED:
882 /* Handle these instructions by replacing the PC in the instruction with another
883 * register. They are common, so we'd like to support them, and this way we do so
884 * without any risk of having to simulate a segfault.
885 */
886
887 /* Fall through */
888
889 instr_emulate:
890 case FASTTRAP_T_COMMON:
891 {
892 user_addr_t addr;
893 uint8_t scratch[32];
894 uint_t i = 0;
895 fasttrap_instr_t emul_instr;
896 emul_instr.instr32 = tp->ftt_instr;
897 int emul_instr_size;
898
899 /*
900 * Unfortunately sometimes when we emulate the instruction and have to replace the
901 * PC, there is no longer a thumb mode equivalent. We end up having to run the
902 * modified instruction in ARM mode. We use this variable to keep track of which
903 * mode we should emulate in. We still use the original variable to determine
904 * what mode to return to.
905 */
906 uint8_t emul_thumb = tp->ftt_thumb;
907 int save_reg = -1;
908 uint32_t save_val = 0;
909
910 /*
911 * Dealing with condition codes and emulation:
912 * We can't just uniformly do a condition code check here because not all instructions
913 * have condition codes. We currently do not support an instruction by instruction trace,
914 * so we can assume that either: 1. We are executing a Thumb instruction, in which case
915 * we either are not in an IT block and should execute always, or we are last in an IT
916 * block. Either way, the traced instruction will run correctly, and we won't have any
917 * problems when we return to the original code, because we will no longer be in the IT
918 * block. 2. We are executing an ARM instruction, in which case we are ok as long as
919 * we don't attempt to change the condition code.
920 */
921 if (tp->ftt_type == FASTTRAP_T_LDR_PC_IMMED) {
922 /* We know we always have a free register (the one we plan to write the
923 * result value to!). So we'll replace the pc with that one.
924 */
925 int new_reg;
926 if (tp->ftt_thumb) {
927 /* Check to see if thumb or thumb2 */
928 if (instr_size == 2) {
929 /*
930 * Sadness. We need to emulate this instruction in ARM mode
931 * because it has an 8 bit immediate offset. Instead of having
932 * to deal with condition codes in the ARM instruction, we'll
933 * just check the condition and abort if the condition is false.
934 */
935 if (!dtrace_arm_condition_true(condition_code, regs->cpsr)) {
936 new_pc = pc + instr_size;
937 break;
938 }
939
940 new_reg = (tp->ftt_instr1 >> 8) & 0x7;
941 regs->r[new_reg] = ALIGNADDR(regs->pc + 4, 2);
942 emul_thumb = 0;
943 emul_instr.instr32 = 0xE5900000 | (new_reg << 16) | (new_reg << 12) | ((tp->ftt_instr1 & 0xFF) << 2);
944 } else {
945 /* Thumb2. Just replace the register. */
946 new_reg = (tp->ftt_instr2 >> 12) & 0xF;
947 regs->r[new_reg] = ALIGNADDR(regs->pc + 4, 2);
948 emul_instr.instr16.instr1 &= ~0x000F;
949 emul_instr.instr16.instr1 |= new_reg;
950 }
951 } else {
952 /* ARM. Just replace the register. */
953 new_reg = (tp->ftt_instr >> 12) & 0xF;
954 regs->r[new_reg] = ALIGNADDR(regs->pc + 8,2);
955 emul_instr.instr32 &= ~0x000F0000;
956 emul_instr.instr32 |= new_reg << 16;
957 }
958 } else if (tp->ftt_type == FASTTRAP_T_VLDR_PC_IMMED) {
959 /* This instruction only uses one register, and if we're here, we know
960 * it must be the pc. So we'll just replace it with R0.
961 */
962 save_reg = 0;
963 save_val = regs->r[0];
964 regs->r[save_reg] = ALIGNADDR(regs->pc + (tp->ftt_thumb ? 4 : 8), 2);
965 if (tp->ftt_thumb) {
966 emul_instr.instr16.instr1 &= ~0x000F;
967 } else {
968 emul_instr.instr32 &= ~0x000F0000;
969 }
970 }
971
972 emul_instr_size = dtrace_instr_size(emul_instr.instr32, emul_thumb);
973
974 /*
975 * At this point:
976 * tp->ftt_thumb = thumb mode of original instruction
977 * emul_thumb = thumb mode for emulation
978 * emul_instr = instruction we are using to emulate original instruction
979 * emul_instr_size = size of emulating instruction
980 */
981
982 addr = uthread->t_dtrace_scratch->addr;
983
984 if (addr == 0LL) {
985 fasttrap_sigtrap(p, uthread, pc); // Should be killing target proc
986 new_pc = pc;
987 break;
988 }
989
990 uthread->t_dtrace_scrpc = addr;
991 if (emul_thumb) {
992 /*
993 * No way to do an unconditional branch in Thumb mode, shove the address
994 * onto the user stack and go to the next location with a pop. This can
995 * segfault if this push happens to cross a stack page, but that's ok, since
996 * we are running in userland, and the kernel knows how to handle userland
997 * stack expansions correctly.
998 *
999 * Layout of scratch space for Thumb mode:
1000 * Emulated instruction
1001 * ldr save_reg, [pc, #16] (if necessary, restore any register we clobbered)
1002 * push { r0, r1 }
1003 * ldr r0, [pc, #4]
1004 * str r0, [sp, #4]
1005 * pop { r0, pc }
1006 * Location we should return to in original program
1007 * Saved value of clobbered register (if necessary)
1008 */
1009
1010 bcopy(&emul_instr, &scratch[i], emul_instr_size); i += emul_instr_size;
1011
1012 if (save_reg != -1) {
1013 uint16_t restore_inst = 0x4803;
1014 restore_inst |= (save_reg & 0x7) << 8;
1015 SET16(scratch+i, restore_inst); i += 2; // ldr reg, [pc , #16]
1016 }
1017
1018 SET16(scratch+i, 0xB403); i += 2; // push { r0, r1 }
1019 SET16(scratch+i, 0x4801); i += 2; // ldr r0, [pc, #4]
1020 SET16(scratch+i, 0x9001); i += 2; // str r0, [sp, #4]
1021 SET16(scratch+i, 0xBD01); i += 2; // pop { r0, pc }
1022
1023 if (i % 4) {
1024 SET16(scratch+i, 0); i += 2; // padding - saved 32 bit words must be aligned
1025 }
1026 SET32(scratch+i, pc + instr_size + (tp->ftt_thumb ? 1 : 0)); i += 4; // Return address
1027 if (save_reg != -1) {
1028 SET32(scratch+i, save_val); i += 4; // saved value of clobbered register
1029 }
1030
1031 uthread->t_dtrace_astpc = addr + i;
1032 bcopy(&emul_instr, &scratch[i], emul_instr_size); i += emul_instr_size;
1033 SET16(scratch+i, FASTTRAP_THUMB_RET_INSTR); i += 2;
1034 } else {
1035 /*
1036 * Layout of scratch space for ARM mode:
1037 * Emulated instruction
1038 * ldr save_reg, [pc, #12] (if necessary, restore any register we clobbered)
1039 * ldr pc, [pc, #4]
1040 * Location we should return to in original program
1041 * Saved value of clobbered register (if necessary)
1042 */
1043
1044 bcopy(&emul_instr, &scratch[i], emul_instr_size); i += emul_instr_size;
1045
1046 if (save_reg != -1) {
1047 uint32_t restore_inst = 0xE59F0004;
1048 restore_inst |= save_reg << 12;
1049 SET32(scratch+i, restore_inst); i += 4; // ldr reg, [pc, #12]
1050 }
1051 SET32(scratch+i, 0xE51FF004); i += 4; // ldr pc, [pc, #4]
1052
1053 SET32(scratch+i, pc + instr_size + (tp->ftt_thumb ? 1 : 0)); i += 4; // Return address
1054 if (save_reg != -1) {
1055 SET32(scratch+i, save_val); i += 4; // Saved value of clobbered register
1056 }
1057
1058 uthread->t_dtrace_astpc = addr + i;
1059 bcopy(&emul_instr, &scratch[i], emul_instr_size); i += emul_instr_size;
1060 SET32(scratch+i, FASTTRAP_ARM_RET_INSTR); i += 4;
1061 }
1062
1063 if (uwrite(p, scratch, i, uthread->t_dtrace_scratch->write_addr) != KERN_SUCCESS) {
1064 fasttrap_sigtrap(p, uthread, pc);
1065 new_pc = pc;
1066 break;
1067 }
1068
1069 if (tp->ftt_retids != NULL) {
1070 uthread->t_dtrace_step = 1;
1071 uthread->t_dtrace_ret = 1;
1072 new_pc = uthread->t_dtrace_astpc + (emul_thumb ? 1 : 0);
1073 } else {
1074 new_pc = uthread->t_dtrace_scrpc + (emul_thumb ? 1 : 0);
1075 }
1076
1077 uthread->t_dtrace_pc = pc;
1078 uthread->t_dtrace_npc = pc + instr_size;
1079 uthread->t_dtrace_on = 1;
1080 was_simulated = 0;
1081 set_thumb_flag(regs, new_pc);
1082 break;
1083 }
1084
1085 default:
1086 panic("fasttrap: mishandled an instruction");
1087 }
1088
1089 done:
1090 /*
1091 * APPLE NOTE:
1092 *
1093 * We're setting this earlier than Solaris does, to get a "correct"
1094 * ustack() output. In the Sun code, a() -> b() -> c() -> d() is
1095 * reported at: d, b, a. The new way gives c, b, a, which is closer
1096 * to correct, as the return instruction has already exectued.
1097 */
1098 regs->pc = new_pc;
1099
1100 /*
1101 * If there were no return probes when we first found the tracepoint,
1102 * we should feel no obligation to honor any return probes that were
1103 * subsequently enabled -- they'll just have to wait until the next
1104 * time around.
1105 */
1106 if (tp->ftt_retids != NULL) {
1107 /*
1108 * We need to wait until the results of the instruction are
1109 * apparent before invoking any return probes. If this
1110 * instruction was emulated we can just call
1111 * fasttrap_return_common(); if it needs to be executed, we
1112 * need to wait until the user thread returns to the kernel.
1113 */
1114 /*
1115 * It used to be that only common instructions were simulated.
1116 * For performance reasons, we now simulate some instructions
1117 * when safe and go back to userland otherwise. The was_simulated
1118 * flag means we don't need to go back to userland.
1119 */
1120 if (was_simulated) {
1121 fasttrap_return_common(p, regs, pc, new_pc);
1122 } else {
1123 ASSERT(uthread->t_dtrace_ret != 0);
1124 ASSERT(uthread->t_dtrace_pc == pc);
1125 ASSERT(uthread->t_dtrace_scrpc != 0);
1126 ASSERT(new_pc == uthread->t_dtrace_astpc);
1127 }
1128 }
1129
1130 return (0);
1131 }
1132
1133 int
1134 fasttrap_return_probe(arm_saved_state_t *regs)
1135 {
1136 proc_t *p = current_proc();
1137 uthread_t uthread = (uthread_t)get_bsdthread_info(current_thread());
1138 user_addr_t pc = uthread->t_dtrace_pc;
1139 user_addr_t npc = uthread->t_dtrace_npc;
1140
1141 uthread->t_dtrace_pc = 0;
1142 uthread->t_dtrace_npc = 0;
1143 uthread->t_dtrace_scrpc = 0;
1144 uthread->t_dtrace_astpc = 0;
1145
1146 /*
1147 * Treat a child created by a call to vfork(2) as if it were its
1148 * parent. We know that there's only one thread of control in such a
1149 * process: this one.
1150 */
1151 if (p->p_lflag & P_LINVFORK) {
1152 proc_list_lock();
1153 while (p->p_lflag & P_LINVFORK)
1154 p = p->p_pptr;
1155 proc_list_unlock();
1156 }
1157
1158 /*
1159 * We set rp->r_pc to the address of the traced instruction so
1160 * that it appears to dtrace_probe() that we're on the original
1161 * instruction, and so that the user can't easily detect our
1162 * complex web of lies. dtrace_return_probe() (our caller)
1163 * will correctly set %pc after we return.
1164 */
1165 regs->pc = pc;
1166
1167 fasttrap_return_common(p, regs, pc, npc);
1168
1169 return (0);
1170 }
1171
1172 uint64_t
1173 fasttrap_pid_getarg(void *arg, dtrace_id_t id, void *parg, int argno,
1174 int aframes)
1175 {
1176 #pragma unused(arg, id, parg, aframes)
1177 arm_saved_state_t* regs = find_user_regs(current_thread());
1178
1179 /* First four arguments are in registers */
1180 if (argno < 4)
1181 return regs->r[argno];
1182
1183 /* Look on the stack for the rest */
1184 uint32_t value;
1185 uint32_t* sp = (uint32_t*) regs->sp;
1186 DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
1187 value = dtrace_fuword32((user_addr_t) (sp+argno-4));
1188 DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | CPU_DTRACE_BADADDR);
1189
1190 return value;
1191 }
1192
1193 uint64_t
1194 fasttrap_usdt_getarg(void *arg, dtrace_id_t id, void *parg, int argno, int aframes)
1195 {
1196 #pragma unused(arg, id, parg, argno, aframes)
1197 #if 0
1198 return (fasttrap_anarg(ttolwp(curthread)->lwp_regs, 0, argno));
1199 #endif
1200
1201 return 0;
1202 }
1203