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