#ifdef KERNEL
#ifndef _KERNEL
-#define _KERNEL /* Solaris vs. Darwin */
+#define _KERNEL /* Solaris vs. Darwin */
#endif
#endif
#define THUMB_INSTR(x) (*(uint16_t*) &(x))
-#define SIGNEXTEND(x,v) ((((int) (x)) << (32-(v))) >> (32-(v)))
-#define ALIGNADDR(x,v) (((x) >> (v)) << (v))
+#define SIGNEXTEND(x, v) ((((int) (x)) << (32-(v))) >> (32-(v)))
+#define ALIGNADDR(x, v) (((x) >> (v)) << (v))
#define GETITSTATE(x) ((((x) >> 8) & 0xFC) | (((x) >> 25) & 0x3))
#define ISLASTINIT(x) (((x) & 0xF) == 8)
-#define SET16(x,w) *((uint16_t*) (x)) = (w)
-#define SET32(x,w) *((uint32_t*) (x)) = (w)
+#define SET16(x, w) *((uint16_t*) (x)) = (w)
+#define SET32(x, w) *((uint32_t*) (x)) = (w)
#define IS_ARM_NOP(x) ((x) == 0xE1A00000)
/* Marker for is-enabled probes */
extern int dtrace_arm_condition_true(int cond, int cpsr);
-static
-void flush_caches(void)
-{
- /* TODO There were some problems with flushing just the cache line that had been modified.
- * For now, we'll flush the entire cache, until we figure out how to flush just the patched block.
- */
- FlushPoU_Dcache();
- InvalidatePoU_Icache();
-}
-
int
fasttrap_tracepoint_init(proc_t *p, fasttrap_tracepoint_t *tp,
- user_addr_t pc, fasttrap_probe_type_t type)
+ user_addr_t pc, fasttrap_probe_type_t type)
{
#pragma unused(type)
uint32_t instr;
* pages, we potentially read the instruction in two parts. If the
* second part fails, we just zero out that part of the instruction.
*/
- /*
+ /*
* APPLE NOTE: Of course, we do not have a P_PR_LOCK, so this is racey...
- */
+ */
- if (uread(p, &instr, 4, pc) != 0)
- return (-1);
+ if (uread(p, &instr, 4, pc) != 0) {
+ return -1;
+ }
/* We want &instr to always point to the saved instruction, so just copy the
* whole thing When cast to a pointer to a uint16_t, that will give us a
tp->ftt_instr = instr;
if (tp->ftt_fntype != FASTTRAP_FN_DONE_INIT) {
- switch(tp->ftt_fntype) {
- case FASTTRAP_FN_UNKNOWN:
- /* Can't instrument without any information. We can add some heuristics later if necessary. */
- return (-1);
-
- case FASTTRAP_FN_USDT:
- if (IS_ARM_NOP(instr) || IS_ARM_IS_ENABLED(instr)) {
- tp->ftt_thumb = 0;
- } else if (IS_THUMB_NOP(THUMB_INSTR(instr)) || IS_THUMB_IS_ENABLED(THUMB_INSTR(instr))) {
- tp->ftt_thumb = 1;
- } else {
- /* Shouldn't reach here - this means we don't recognize
- * the instruction at one of the USDT probe locations
- */
- return (-1);
- }
- tp->ftt_fntype = FASTTRAP_FN_DONE_INIT;
- break;
+ switch (tp->ftt_fntype) {
+ case FASTTRAP_FN_UNKNOWN:
+ /* Can't instrument without any information. We can add some heuristics later if necessary. */
+ return -1;
- case FASTTRAP_FN_ARM:
+ case FASTTRAP_FN_USDT:
+ if (IS_ARM_NOP(instr) || IS_ARM_IS_ENABLED(instr)) {
tp->ftt_thumb = 0;
- tp->ftt_fntype = FASTTRAP_FN_DONE_INIT;
- break;
-
- case FASTTRAP_FN_THUMB:
+ } else if (IS_THUMB_NOP(THUMB_INSTR(instr)) || IS_THUMB_IS_ENABLED(THUMB_INSTR(instr))) {
tp->ftt_thumb = 1;
- tp->ftt_fntype = FASTTRAP_FN_DONE_INIT;
- break;
+ } else {
+ /* Shouldn't reach here - this means we don't recognize
+ * the instruction at one of the USDT probe locations
+ */
+ return -1;
+ }
+ tp->ftt_fntype = FASTTRAP_FN_DONE_INIT;
+ break;
- default:
- return (-1);
+ case FASTTRAP_FN_ARM:
+ tp->ftt_thumb = 0;
+ tp->ftt_fntype = FASTTRAP_FN_DONE_INIT;
+ break;
+
+ case FASTTRAP_FN_THUMB:
+ tp->ftt_thumb = 1;
+ tp->ftt_fntype = FASTTRAP_FN_DONE_INIT;
+ break;
+
+ default:
+ return -1;
}
}
if (tp->ftt_type == FASTTRAP_T_INV) {
/* This is an instruction we either don't recognize or can't instrument */
printf("dtrace: fasttrap: Unrecognized instruction: %08x at %08x\n",
- (tp->ftt_thumb && dtrace_instr_size(tp->ftt_instr,tp->ftt_thumb) == 2) ? tp->ftt_instr1 : instr, pc);
- return (-1);
+ (tp->ftt_thumb && dtrace_instr_size(tp->ftt_instr, tp->ftt_thumb) == 2) ? tp->ftt_instr1 : instr, pc);
+ return -1;
}
- return (0);
-}
-
-// These are not exported from vm_map.h.
-extern kern_return_t vm_map_write_user(vm_map_t map, void *src_p, vm_map_address_t dst_addr, vm_size_t size);
-
-/* Patches the instructions. Almost like uwrite, but need special instructions on ARM to flush the caches. */
-static
-int patchInst(proc_t *p, void *buf, user_size_t len, user_addr_t a)
-{
- kern_return_t ret;
-
- ASSERT(p != NULL);
- ASSERT(p->task != NULL);
-
- task_t task = p->task;
-
- /*
- * Grab a reference to the task vm_map_t to make sure
- * the map isn't pulled out from under us.
- *
- * Because the proc_lock is not held at all times on all code
- * paths leading here, it is possible for the proc to have
- * exited. If the map is null, fail.
- */
- vm_map_t map = get_task_map_reference(task);
- if (map) {
- /* Find the memory permissions. */
- uint32_t nestingDepth=999999;
- vm_region_submap_short_info_data_64_t info;
- mach_msg_type_number_t count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
- mach_vm_address_t address = (mach_vm_address_t)a;
- mach_vm_size_t sizeOfRegion = (mach_vm_size_t)len;
-
- ret = mach_vm_region_recurse(map, &address, &sizeOfRegion, &nestingDepth, (vm_region_recurse_info_t)&info, &count);
- if (ret != KERN_SUCCESS)
- goto done;
-
- vm_prot_t reprotect;
-
- if (!(info.protection & VM_PROT_WRITE)) {
- /* Save the original protection values for restoration later */
- reprotect = info.protection;
- if (info.max_protection & VM_PROT_WRITE) {
- /* The memory is not currently writable, but can be made writable. */
- /* Making it both writable and executable at the same time causes warning on embedded */
- ret = mach_vm_protect (map, (mach_vm_offset_t)a, (mach_vm_size_t)len, 0, (reprotect & ~VM_PROT_EXECUTE) | VM_PROT_WRITE);
- } else {
- /*
- * The memory is not currently writable, and cannot be made writable. We need to COW this memory.
- *
- * Strange, we can't just say "reprotect | VM_PROT_COPY", that fails.
- */
- 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);
- }
-
- if (ret != KERN_SUCCESS)
- goto done;
-
- } else {
- /* The memory was already writable. */
- reprotect = VM_PROT_NONE;
- }
-
- ret = vm_map_write_user( map,
- buf,
- (vm_map_address_t)a,
- (vm_size_t)len);
-
- flush_caches();
-
- if (ret != KERN_SUCCESS)
- goto done;
-
- if (reprotect != VM_PROT_NONE) {
- ASSERT(reprotect & VM_PROT_EXECUTE);
- ret = mach_vm_protect (map, (mach_vm_offset_t)a, (mach_vm_size_t)len, 0, reprotect);
- }
-
-done:
- vm_map_deallocate(map);
- } else
- ret = KERN_TERMINATED;
-
- return (int)ret;
+ return 0;
}
int
instr = FASTTRAP_ARM_INSTR;
}
- if (patchInst(p, &instr, size, tp->ftt_pc) != 0)
- return (-1);
+ if (uwrite(p, &instr, size, tp->ftt_pc) != 0) {
+ return -1;
+ }
tp->ftt_installed = 1;
- return (0);
+ return 0;
}
int
* Distinguish between read or write failures and a changed
* instruction.
*/
- if (uread(p, &instr, size, tp->ftt_pc) != 0)
+ if (uread(p, &instr, size, tp->ftt_pc) != 0) {
goto end;
+ }
if (tp->ftt_thumb) {
- if (*((uint16_t*) &instr) != FASTTRAP_THUMB_INSTR)
+ if (*((uint16_t*) &instr) != FASTTRAP_THUMB_INSTR) {
goto end;
+ }
} else {
- if (instr != FASTTRAP_ARM_INSTR)
+ if (instr != FASTTRAP_ARM_INSTR) {
goto end;
+ }
+ }
+ if (uwrite(p, &tp->ftt_instr, size, tp->ftt_pc) != 0) {
+ return -1;
}
- if (patchInst(p, &tp->ftt_instr, size, tp->ftt_pc) != 0)
- return (-1);
end:
tp->ftt_installed = 0;
- return (0);
+ return 0;
}
static void
for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) {
if (pid == tp->ftt_pid && pc == tp->ftt_pc &&
- tp->ftt_proc->ftpc_acount != 0)
+ tp->ftt_proc->ftpc_acount != 0) {
break;
+ }
}
/*
* Don't sweat it if we can't find the tracepoint again; unlike
* when we're in fasttrap_pid_probe(), finding the tracepoint here
* is not essential to the correct execution of the process.
- */
+ */
if (tp == NULL) {
lck_mtx_unlock(pid_mtx);
return;
*/
if (tp->ftt_type != FASTTRAP_T_LDM_PC &&
tp->ftt_type != FASTTRAP_T_POP_PC &&
- new_pc - probe->ftp_faddr < probe->ftp_fsize)
+ new_pc - probe->ftp_faddr < probe->ftp_fsize) {
continue;
+ }
if (probe->ftp_prov->ftp_provider_type == DTFTP_PROVIDER_ONESHOT) {
uint8_t already_triggered = atomic_or_8(&probe->ftp_triggered, 1);
#ifndef CONFIG_EMBEDDED
if (ISSET(current_proc()->p_lflag, P_LNOATTACH)) {
dtrace_probe(dtrace_probeid_error, 0 /* state */, id->fti_probe->ftp_id,
- 1 /* ndx */, -1 /* offset */, DTRACEFLT_UPRIV);
+ 1 /* ndx */, -1 /* offset */, DTRACEFLT_UPRIV);
#else
if (FALSE) {
#endif
} else {
dtrace_probe(id->fti_probe->ftp_id,
- pc - id->fti_probe->ftp_faddr,
- regs->r[0], 0, 0, 0);
+ pc - id->fti_probe->ftp_faddr,
+ regs->r[0], 0, 0, 0);
}
}
if (retire_tp) {
t->uu_code = addr;
t->uu_siglist |= sigmask(SIGSEGV);
- /*
+ /*
* XXX These two line may be redundant; if not, then we need
* XXX to potentially set the data address in the machine
* XXX specific thread state structure to indicate the address.
- */
+ */
t->uu_exception = KERN_INVALID_ADDRESS; /* SIGSEGV */
t->uu_subcode = 0; /* XXX pad */
-
- proc_unlock(p);
-
+
+ proc_unlock(p);
+
/* raise signal */
signal_setast(t->uu_context.vc_thread);
#endif
}
}
-static void set_thumb_flag(arm_saved_state_t *regs, user_addr_t pc)
+static void
+set_thumb_flag(arm_saved_state_t *regs, user_addr_t pc)
{
if (pc & 1) {
regs->cpsr |= PSR_TF;
if (uthread->t_dtrace_step) {
ASSERT(uthread->t_dtrace_on);
fasttrap_sigtrap(p, uthread, pc);
- return (0);
+ return 0;
}
/*
*/
if (p->p_lflag & P_LINVFORK) {
proc_list_lock();
- while (p->p_lflag & P_LINVFORK)
+ while (p->p_lflag & P_LINVFORK) {
p = p->p_pptr;
+ }
proc_list_unlock();
}
pid = p->p_pid;
pid_mtx = &cpu_core[CPU->cpu_id].cpuc_pid_lock;
lck_mtx_lock(pid_mtx);
- bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid,pc)];
+ bucket = &fasttrap_tpoints.fth_table[FASTTRAP_TPOINTS_INDEX(pid, pc)];
/*
* Lookup the tracepoint that the process just hit.
*/
for (tp = bucket->ftb_data; tp != NULL; tp = tp->ftt_next) {
if (pid == tp->ftt_pid && pc == tp->ftt_pc &&
- tp->ftt_proc->ftpc_acount != 0)
+ tp->ftt_proc->ftpc_acount != 0) {
break;
+ }
}
/*
*/
if (tp == NULL) {
lck_mtx_unlock(pid_mtx);
- return (-1);
+ return -1;
}
/* Default to always execute */
condition_code = itstate >> 4;
} else {
printf("dtrace: fasttrap: Tried to trace instruction %08x at %08x but not at end of IT block\n",
- (tp->ftt_thumb && dtrace_instr_size(tp->ftt_instr,tp->ftt_thumb) == 2) ? tp->ftt_instr1 : tp->ftt_instr, pc);
+ (tp->ftt_thumb && dtrace_instr_size(tp->ftt_instr, tp->ftt_thumb) == 2) ? tp->ftt_instr1 : tp->ftt_instr, pc);
fasttrap_tracepoint_remove(p, tp);
lck_mtx_unlock(pid_mtx);
- return (-1);
+ return -1;
}
}
} else {
*/
fasttrap_tracepoint_remove(p, tp);
lck_mtx_unlock(pid_mtx);
- return (-1);
+ return -1;
}
if (tp->ftt_ids != NULL) {
#ifndef CONFIG_EMBEDDED
if (ISSET(current_proc()->p_lflag, P_LNOATTACH)) {
dtrace_probe(dtrace_probeid_error, 0 /* state */, probe->ftp_id,
- 1 /* ndx */, -1 /* offset */, DTRACEFLT_UPRIV);
+ 1 /* ndx */, -1 /* offset */, DTRACEFLT_UPRIV);
#else
if (FALSE) {
#endif
goto done;
}
- instr_size = dtrace_instr_size(tp->ftt_instr,tp->ftt_thumb);
+ instr_size = dtrace_instr_size(tp->ftt_instr, tp->ftt_thumb);
switch (tp->ftt_type) {
- case FASTTRAP_T_MOV_PC_REG:
- case FASTTRAP_T_CPY_PC:
- {
- if (!dtrace_arm_condition_true(condition_code, regs->cpsr)) {
- new_pc = pc + instr_size;
- break;
- }
+ case FASTTRAP_T_MOV_PC_REG:
+ case FASTTRAP_T_CPY_PC:
+ {
+ if (!dtrace_arm_condition_true(condition_code, regs->cpsr)) {
+ new_pc = pc + instr_size;
+ break;
+ }
- int rm;
- if (tp->ftt_thumb) {
- rm = THUMB16_HRM(tp->ftt_instr1);
- } else {
- rm = tp->ftt_instr & 0xF;
- }
- new_pc = regs->r[rm];
+ int rm;
+ if (tp->ftt_thumb) {
+ rm = THUMB16_HRM(tp->ftt_instr1);
+ } else {
+ rm = tp->ftt_instr & 0xF;
+ }
+ new_pc = regs->r[rm];
- /* This instruction does not change the Thumb state */
+ /* This instruction does not change the Thumb state */
- break;
- }
+ break;
+ }
- case FASTTRAP_T_STM_LR:
- case FASTTRAP_T_PUSH_LR:
- {
- /*
- * This is a very common case, so we want to emulate this instruction if
- * possible. However, on a push, it is possible that we might reach the end
- * of a page and have to allocate a new page. Most of the time this will not
- * happen, and we know that the push instruction can store at most 16 words,
- * so check to see if we are far from the boundary, and if so, emulate. This
- * can be made more aggressive by checking the actual number of words being
- * pushed, but we won't do that for now.
- *
- * Some of the same issues that apply to POP_PC probably apply here also.
- */
+ case FASTTRAP_T_STM_LR:
+ case FASTTRAP_T_PUSH_LR:
+ {
+ /*
+ * This is a very common case, so we want to emulate this instruction if
+ * possible. However, on a push, it is possible that we might reach the end
+ * of a page and have to allocate a new page. Most of the time this will not
+ * happen, and we know that the push instruction can store at most 16 words,
+ * so check to see if we are far from the boundary, and if so, emulate. This
+ * can be made more aggressive by checking the actual number of words being
+ * pushed, but we won't do that for now.
+ *
+ * Some of the same issues that apply to POP_PC probably apply here also.
+ */
- int reglist;
- int ret;
- uintptr_t* base;
+ int reglist;
+ int ret;
+ uintptr_t* base;
- if (!dtrace_arm_condition_true(condition_code, regs->cpsr)) {
- new_pc = pc + instr_size;
- break;
- }
+ if (!dtrace_arm_condition_true(condition_code, regs->cpsr)) {
+ new_pc = pc + instr_size;
+ break;
+ }
- base = (uintptr_t*) regs->sp;
- if (((((uintptr_t) base)-16*4) >> PAGE_SHIFT) != (((uintptr_t) base) >> PAGE_SHIFT)) {
- /* Crosses the page boundary, go to emulation */
- goto instr_emulate;
- }
+ base = (uintptr_t*) regs->sp;
+ if (((((uintptr_t) base) - 16 * 4) >> PAGE_SHIFT) != (((uintptr_t) base) >> PAGE_SHIFT)) {
+ /* Crosses the page boundary, go to emulation */
+ goto instr_emulate;
+ }
- if (tp->ftt_thumb) {
- if (instr_size == 4) {
- /* We know we have to push lr, never push sp or pc */
- reglist = tp->ftt_instr2 & 0x1FFF;
- } else {
- reglist = tp->ftt_instr1 & 0xFF;
- }
- } else {
+ if (tp->ftt_thumb) {
+ if (instr_size == 4) {
/* We know we have to push lr, never push sp or pc */
- reglist = tp->ftt_instr & 0x1FFF;
+ reglist = tp->ftt_instr2 & 0x1FFF;
+ } else {
+ reglist = tp->ftt_instr1 & 0xFF;
}
+ } else {
+ /* We know we have to push lr, never push sp or pc */
+ reglist = tp->ftt_instr & 0x1FFF;
+ }
- /* Push the link register */
- base--;
- ret = fasttrap_suword32((uint32_t) base, regs->lr);
- if (ret == -1) {
- fasttrap_sigsegv(p, uthread, (user_addr_t) base, regs);
- new_pc = regs->pc;
- break;
- }
+ /* Push the link register */
+ base--;
+ ret = fasttrap_suword32((uint32_t) base, regs->lr);
+ if (ret == -1) {
+ fasttrap_sigsegv(p, uthread, (user_addr_t) base, regs);
+ new_pc = regs->pc;
+ break;
+ }
- /* Start pushing from $r12 */
- int regmask = 1 << 12;
- int regnum = 12;
-
- while (regmask) {
- if (reglist & regmask) {
- base--;
- ret = fasttrap_suword32((uint32_t) base, regs->r[regnum]);
- if (ret == -1) {
- fasttrap_sigsegv(p, uthread, (user_addr_t) base, regs);
- new_pc = regs->pc;
- break;
- }
+ /* Start pushing from $r12 */
+ int regmask = 1 << 12;
+ int regnum = 12;
+
+ while (regmask) {
+ if (reglist & regmask) {
+ base--;
+ ret = fasttrap_suword32((uint32_t) base, regs->r[regnum]);
+ if (ret == -1) {
+ fasttrap_sigsegv(p, uthread, (user_addr_t) base, regs);
+ new_pc = regs->pc;
+ break;
}
- regmask >>= 1;
- regnum--;
}
-
- regs->sp = (uintptr_t) base;
-
- new_pc = pc + instr_size;
-
- break;
+ regmask >>= 1;
+ regnum--;
}
+ regs->sp = (uintptr_t) base;
- case FASTTRAP_T_LDM_PC:
- case FASTTRAP_T_POP_PC:
- {
- /* TODO Two issues that will eventually need to be resolved:
- *
- * 1. Understand what the hardware does if we have to segfault (data abort) in
- * the middle of a load multiple. We currently don't have a working segfault
- * handler anyway, and with no swapfile we should never segfault on this load.
- * If we do, we'll just kill the process by setting the pc to 0.
- *
- * 2. The emulation is no longer atomic. We currently only emulate pop for
- * function epilogues, and so we should never have a race here because one
- * thread should never be trying to manipulate another thread's stack frames.
- * That is almost certainly a bug in the program.
- *
- * This will need to be fixed if we ever:
- * a. Ship dtrace externally, as this could be a potential attack vector
- * b. Support instruction level tracing, as we might then pop/ldm non epilogues.
- *
- */
-
- /* Assume ldmia! sp/pop ... pc */
-
- int regnum = 0, reglist;
- int ret;
- uintptr_t* base;
-
- if (!dtrace_arm_condition_true(condition_code, regs->cpsr)) {
- new_pc = pc + instr_size;
- break;
- }
+ new_pc = pc + instr_size;
- if (tp->ftt_thumb) {
- if (instr_size == 4) {
- /* We know we have to load the pc, don't do it twice */
- reglist = tp->ftt_instr2 & 0x7FFF;
- } else {
- reglist = tp->ftt_instr1 & 0xFF;
- }
- } else {
- /* We know we have to load the pc, don't do it twice */
- reglist = tp->ftt_instr & 0x7FFF;
- }
+ break;
+ }
- base = (uintptr_t*) regs->sp;
- while (reglist) {
- if (reglist & 1) {
- ret = fasttrap_fuword32((uint32_t) base, ®s->r[regnum]);
- if (ret == -1) {
- fasttrap_sigsegv(p, uthread, (user_addr_t) base, regs);
- new_pc = regs->pc;
- break;
- }
- base++;
- }
- reglist >>= 1;
- regnum++;
- }
- ret = fasttrap_fuword32((uint32_t) base, &new_pc);
- if (ret == -1) {
- fasttrap_sigsegv(p, uthread, (user_addr_t) base, regs);
- new_pc = regs->pc;
- break;
- }
- base++;
+ case FASTTRAP_T_LDM_PC:
+ case FASTTRAP_T_POP_PC:
+ {
+ /* TODO Two issues that will eventually need to be resolved:
+ *
+ * 1. Understand what the hardware does if we have to segfault (data abort) in
+ * the middle of a load multiple. We currently don't have a working segfault
+ * handler anyway, and with no swapfile we should never segfault on this load.
+ * If we do, we'll just kill the process by setting the pc to 0.
+ *
+ * 2. The emulation is no longer atomic. We currently only emulate pop for
+ * function epilogues, and so we should never have a race here because one
+ * thread should never be trying to manipulate another thread's stack frames.
+ * That is almost certainly a bug in the program.
+ *
+ * This will need to be fixed if we ever:
+ * a. Ship dtrace externally, as this could be a potential attack vector
+ * b. Support instruction level tracing, as we might then pop/ldm non epilogues.
+ *
+ */
- regs->sp = (uintptr_t) base;
+ /* Assume ldmia! sp/pop ... pc */
- set_thumb_flag(regs, new_pc);
+ int regnum = 0, reglist;
+ int ret;
+ uintptr_t* base;
+ if (!dtrace_arm_condition_true(condition_code, regs->cpsr)) {
+ new_pc = pc + instr_size;
break;
}
- case FASTTRAP_T_CB_N_Z:
- {
- /* Thumb mode instruction, and not permitted in IT block, so skip the condition code check */
- int rn = tp->ftt_instr1 & 0x7;
- int offset = (((tp->ftt_instr1 & 0x00F8) >> 2) | ((tp->ftt_instr1 & 0x0200) >> 3)) + 4;
- int nonzero = tp->ftt_instr1 & 0x0800;
- if (!nonzero != !(regs->r[rn] == 0)) {
- new_pc = pc + offset;
+ if (tp->ftt_thumb) {
+ if (instr_size == 4) {
+ /* We know we have to load the pc, don't do it twice */
+ reglist = tp->ftt_instr2 & 0x7FFF;
} else {
- new_pc = pc + instr_size;
+ reglist = tp->ftt_instr1 & 0xFF;
}
- break;
+ } else {
+ /* We know we have to load the pc, don't do it twice */
+ reglist = tp->ftt_instr & 0x7FFF;
}
- case FASTTRAP_T_B_COND:
- {
- /* Use the condition code in the instruction and ignore the ITSTATE */
-
- int code, offset;
- if (tp->ftt_thumb) {
- if (instr_size == 4) {
- code = (tp->ftt_instr1 >> 6) & 0xF;
- if (code == 14 || code == 15) {
- panic("fasttrap: Emulation of invalid branch");
- }
- int S = (tp->ftt_instr1 >> 10) & 1,
- J1 = (tp->ftt_instr2 >> 13) & 1,
- J2 = (tp->ftt_instr2 >> 11) & 1;
- offset = 4 + SIGNEXTEND(
- (S << 20) | (J2 << 19) | (J1 << 18) |
- ((tp->ftt_instr1 & 0x003F) << 12) |
- ((tp->ftt_instr2 & 0x07FF) << 1),
- 21);
- } else {
- code = (tp->ftt_instr1 >> 8) & 0xF;
- if (code == 14 || code == 15) {
- panic("fasttrap: Emulation of invalid branch");
- }
- offset = 4 + (SIGNEXTEND(tp->ftt_instr1 & 0xFF, 8) << 1);
- }
- } else {
- code = ARM_CONDCODE(tp->ftt_instr);
- if (code == 15) {
- panic("fasttrap: Emulation of invalid branch");
+ base = (uintptr_t*) regs->sp;
+ while (reglist) {
+ if (reglist & 1) {
+ ret = fasttrap_fuword32((uint32_t) base, ®s->r[regnum]);
+ if (ret == -1) {
+ fasttrap_sigsegv(p, uthread, (user_addr_t) base, regs);
+ new_pc = regs->pc;
+ break;
}
- offset = 8 + (SIGNEXTEND(tp->ftt_instr & 0x00FFFFFF, 24) << 2);
- }
-
- if (dtrace_arm_condition_true(code, regs->cpsr)) {
- new_pc = pc + offset;
- } else {
- new_pc = pc + instr_size;
+ base++;
}
+ reglist >>= 1;
+ regnum++;
+ }
+ ret = fasttrap_fuword32((uint32_t) base, &new_pc);
+ if (ret == -1) {
+ fasttrap_sigsegv(p, uthread, (user_addr_t) base, regs);
+ new_pc = regs->pc;
break;
}
+ base++;
- case FASTTRAP_T_B_UNCOND:
- {
- int offset;
+ regs->sp = (uintptr_t) base;
- /* Unconditional branches can only be taken from Thumb mode */
- /* (This is different from an ARM branch with condition code "always") */
- ASSERT(tp->ftt_thumb == 1);
+ set_thumb_flag(regs, new_pc);
- if (!dtrace_arm_condition_true(condition_code, regs->cpsr)) {
- new_pc = pc + instr_size;
- break;
- }
+ break;
+ }
+ case FASTTRAP_T_CB_N_Z:
+ {
+ /* Thumb mode instruction, and not permitted in IT block, so skip the condition code check */
+ int rn = tp->ftt_instr1 & 0x7;
+ int offset = (((tp->ftt_instr1 & 0x00F8) >> 2) | ((tp->ftt_instr1 & 0x0200) >> 3)) + 4;
+ int nonzero = tp->ftt_instr1 & 0x0800;
+ if (!nonzero != !(regs->r[rn] == 0)) {
+ new_pc = pc + offset;
+ } else {
+ new_pc = pc + instr_size;
+ }
+ break;
+ }
+
+ case FASTTRAP_T_B_COND:
+ {
+ /* Use the condition code in the instruction and ignore the ITSTATE */
+
+ int code, offset;
+ if (tp->ftt_thumb) {
if (instr_size == 4) {
+ code = (tp->ftt_instr1 >> 6) & 0xF;
+ if (code == 14 || code == 15) {
+ panic("fasttrap: Emulation of invalid branch");
+ }
int S = (tp->ftt_instr1 >> 10) & 1,
J1 = (tp->ftt_instr2 >> 13) & 1,
J2 = (tp->ftt_instr2 >> 11) & 1;
- int I1 = (J1 != S) ? 0 : 1, I2 = (J2 != S) ? 0 : 1;
offset = 4 + SIGNEXTEND(
- (S << 24) | (I1 << 23) | (I2 << 22) |
- ((tp->ftt_instr1 & 0x03FF) << 12) |
- ((tp->ftt_instr2 & 0x07FF) << 1),
- 25);
+ (S << 20) | (J2 << 19) | (J1 << 18) |
+ ((tp->ftt_instr1 & 0x003F) << 12) |
+ ((tp->ftt_instr2 & 0x07FF) << 1),
+ 21);
} else {
- uint32_t instr1 = tp->ftt_instr1;
- offset = 4 + (SIGNEXTEND(instr1 & 0x7FF, 11) << 1);
+ code = (tp->ftt_instr1 >> 8) & 0xF;
+ if (code == 14 || code == 15) {
+ panic("fasttrap: Emulation of invalid branch");
+ }
+ offset = 4 + (SIGNEXTEND(tp->ftt_instr1 & 0xFF, 8) << 1);
+ }
+ } else {
+ code = ARM_CONDCODE(tp->ftt_instr);
+ if (code == 15) {
+ panic("fasttrap: Emulation of invalid branch");
}
+ offset = 8 + (SIGNEXTEND(tp->ftt_instr & 0x00FFFFFF, 24) << 2);
+ }
+ if (dtrace_arm_condition_true(code, regs->cpsr)) {
new_pc = pc + offset;
+ } else {
+ new_pc = pc + instr_size;
+ }
+ break;
+ }
+
+ case FASTTRAP_T_B_UNCOND:
+ {
+ int offset;
+
+ /* Unconditional branches can only be taken from Thumb mode */
+ /* (This is different from an ARM branch with condition code "always") */
+ ASSERT(tp->ftt_thumb == 1);
+
+ if (!dtrace_arm_condition_true(condition_code, regs->cpsr)) {
+ new_pc = pc + instr_size;
break;
}
- case FASTTRAP_T_BX_REG:
- {
- int reg;
+ if (instr_size == 4) {
+ int S = (tp->ftt_instr1 >> 10) & 1,
+ J1 = (tp->ftt_instr2 >> 13) & 1,
+ J2 = (tp->ftt_instr2 >> 11) & 1;
+ int I1 = (J1 != S) ? 0 : 1, I2 = (J2 != S) ? 0 : 1;
+ offset = 4 + SIGNEXTEND(
+ (S << 24) | (I1 << 23) | (I2 << 22) |
+ ((tp->ftt_instr1 & 0x03FF) << 12) |
+ ((tp->ftt_instr2 & 0x07FF) << 1),
+ 25);
+ } else {
+ uint32_t instr1 = tp->ftt_instr1;
+ offset = 4 + (SIGNEXTEND(instr1 & 0x7FF, 11) << 1);
+ }
- if (!dtrace_arm_condition_true(condition_code, regs->cpsr)) {
- new_pc = pc + instr_size;
- break;
- }
+ new_pc = pc + offset;
- if (tp->ftt_thumb) {
- reg = THUMB16_HRM(tp->ftt_instr1);
- } else {
- reg = ARM_RM(tp->ftt_instr);
- }
- new_pc = regs->r[reg];
- set_thumb_flag(regs, new_pc);
+ break;
+ }
+ case FASTTRAP_T_BX_REG:
+ {
+ int reg;
+
+ if (!dtrace_arm_condition_true(condition_code, regs->cpsr)) {
+ new_pc = pc + instr_size;
break;
}
- case FASTTRAP_T_LDR_PC_IMMED:
- case FASTTRAP_T_VLDR_PC_IMMED:
- /* Handle these instructions by replacing the PC in the instruction with another
- * register. They are common, so we'd like to support them, and this way we do so
- * without any risk of having to simulate a segfault.
- */
+ if (tp->ftt_thumb) {
+ reg = THUMB16_HRM(tp->ftt_instr1);
+ } else {
+ reg = ARM_RM(tp->ftt_instr);
+ }
+ new_pc = regs->r[reg];
+ set_thumb_flag(regs, new_pc);
- /* Fall through */
+ break;
+ }
- instr_emulate:
- case FASTTRAP_T_COMMON:
- {
- user_addr_t addr;
- uint8_t scratch[32];
- uint_t i = 0;
- fasttrap_instr_t emul_instr;
- emul_instr.instr32 = tp->ftt_instr;
- int emul_instr_size;
+ case FASTTRAP_T_LDR_PC_IMMED:
+ case FASTTRAP_T_VLDR_PC_IMMED:
+ /* Handle these instructions by replacing the PC in the instruction with another
+ * register. They are common, so we'd like to support them, and this way we do so
+ * without any risk of having to simulate a segfault.
+ */
- /*
- * Unfortunately sometimes when we emulate the instruction and have to replace the
- * PC, there is no longer a thumb mode equivalent. We end up having to run the
- * modified instruction in ARM mode. We use this variable to keep track of which
- * mode we should emulate in. We still use the original variable to determine
- * what mode to return to.
- */
- uint8_t emul_thumb = tp->ftt_thumb;
- int save_reg = -1;
- uint32_t save_val = 0;
+ /* Fall through */
- /*
- * Dealing with condition codes and emulation:
- * We can't just uniformly do a condition code check here because not all instructions
- * have condition codes. We currently do not support an instruction by instruction trace,
- * so we can assume that either: 1. We are executing a Thumb instruction, in which case
- * we either are not in an IT block and should execute always, or we are last in an IT
- * block. Either way, the traced instruction will run correctly, and we won't have any
- * problems when we return to the original code, because we will no longer be in the IT
- * block. 2. We are executing an ARM instruction, in which case we are ok as long as
- * we don't attempt to change the condition code.
+instr_emulate:
+ case FASTTRAP_T_COMMON:
+ {
+ user_addr_t addr;
+ uint8_t scratch[32];
+ uint_t i = 0;
+ fasttrap_instr_t emul_instr;
+ emul_instr.instr32 = tp->ftt_instr;
+ int emul_instr_size;
+
+ /*
+ * Unfortunately sometimes when we emulate the instruction and have to replace the
+ * PC, there is no longer a thumb mode equivalent. We end up having to run the
+ * modified instruction in ARM mode. We use this variable to keep track of which
+ * mode we should emulate in. We still use the original variable to determine
+ * what mode to return to.
+ */
+ uint8_t emul_thumb = tp->ftt_thumb;
+ int save_reg = -1;
+ uint32_t save_val = 0;
+
+ /*
+ * Dealing with condition codes and emulation:
+ * We can't just uniformly do a condition code check here because not all instructions
+ * have condition codes. We currently do not support an instruction by instruction trace,
+ * so we can assume that either: 1. We are executing a Thumb instruction, in which case
+ * we either are not in an IT block and should execute always, or we are last in an IT
+ * block. Either way, the traced instruction will run correctly, and we won't have any
+ * problems when we return to the original code, because we will no longer be in the IT
+ * block. 2. We are executing an ARM instruction, in which case we are ok as long as
+ * we don't attempt to change the condition code.
+ */
+ if (tp->ftt_type == FASTTRAP_T_LDR_PC_IMMED) {
+ /* We know we always have a free register (the one we plan to write the
+ * result value to!). So we'll replace the pc with that one.
*/
- if (tp->ftt_type == FASTTRAP_T_LDR_PC_IMMED) {
- /* We know we always have a free register (the one we plan to write the
- * result value to!). So we'll replace the pc with that one.
- */
- int new_reg;
- if (tp->ftt_thumb) {
- /* Check to see if thumb or thumb2 */
- if (instr_size == 2) {
- /*
- * Sadness. We need to emulate this instruction in ARM mode
- * because it has an 8 bit immediate offset. Instead of having
- * to deal with condition codes in the ARM instruction, we'll
- * just check the condition and abort if the condition is false.
- */
- if (!dtrace_arm_condition_true(condition_code, regs->cpsr)) {
- new_pc = pc + instr_size;
- break;
- }
-
- new_reg = (tp->ftt_instr1 >> 8) & 0x7;
- regs->r[new_reg] = ALIGNADDR(regs->pc + 4, 2);
- emul_thumb = 0;
- emul_instr.instr32 = 0xE5900000 | (new_reg << 16) | (new_reg << 12) | ((tp->ftt_instr1 & 0xFF) << 2);
- } else {
- /* Thumb2. Just replace the register. */
- new_reg = (tp->ftt_instr2 >> 12) & 0xF;
- regs->r[new_reg] = ALIGNADDR(regs->pc + 4, 2);
- emul_instr.instr16.instr1 &= ~0x000F;
- emul_instr.instr16.instr1 |= new_reg;
+ int new_reg;
+ if (tp->ftt_thumb) {
+ /* Check to see if thumb or thumb2 */
+ if (instr_size == 2) {
+ /*
+ * Sadness. We need to emulate this instruction in ARM mode
+ * because it has an 8 bit immediate offset. Instead of having
+ * to deal with condition codes in the ARM instruction, we'll
+ * just check the condition and abort if the condition is false.
+ */
+ if (!dtrace_arm_condition_true(condition_code, regs->cpsr)) {
+ new_pc = pc + instr_size;
+ break;
}
+
+ new_reg = (tp->ftt_instr1 >> 8) & 0x7;
+ regs->r[new_reg] = ALIGNADDR(regs->pc + 4, 2);
+ emul_thumb = 0;
+ emul_instr.instr32 = 0xE5900000 | (new_reg << 16) | (new_reg << 12) | ((tp->ftt_instr1 & 0xFF) << 2);
} else {
- /* ARM. Just replace the register. */
- new_reg = (tp->ftt_instr >> 12) & 0xF;
- regs->r[new_reg] = ALIGNADDR(regs->pc + 8,2);
- emul_instr.instr32 &= ~0x000F0000;
- emul_instr.instr32 |= new_reg << 16;
- }
- } else if (tp->ftt_type == FASTTRAP_T_VLDR_PC_IMMED) {
- /* This instruction only uses one register, and if we're here, we know
- * it must be the pc. So we'll just replace it with R0.
- */
- save_reg = 0;
- save_val = regs->r[0];
- regs->r[save_reg] = ALIGNADDR(regs->pc + (tp->ftt_thumb ? 4 : 8), 2);
- if (tp->ftt_thumb) {
+ /* Thumb2. Just replace the register. */
+ new_reg = (tp->ftt_instr2 >> 12) & 0xF;
+ regs->r[new_reg] = ALIGNADDR(regs->pc + 4, 2);
emul_instr.instr16.instr1 &= ~0x000F;
- } else {
- emul_instr.instr32 &= ~0x000F0000;
+ emul_instr.instr16.instr1 |= new_reg;
}
+ } else {
+ /* ARM. Just replace the register. */
+ new_reg = (tp->ftt_instr >> 12) & 0xF;
+ regs->r[new_reg] = ALIGNADDR(regs->pc + 8, 2);
+ emul_instr.instr32 &= ~0x000F0000;
+ emul_instr.instr32 |= new_reg << 16;
}
-
- emul_instr_size = dtrace_instr_size(emul_instr.instr32, emul_thumb);
-
- /*
- * At this point:
- * tp->ftt_thumb = thumb mode of original instruction
- * emul_thumb = thumb mode for emulation
- * emul_instr = instruction we are using to emulate original instruction
- * emul_instr_size = size of emulating instruction
+ } else if (tp->ftt_type == FASTTRAP_T_VLDR_PC_IMMED) {
+ /* This instruction only uses one register, and if we're here, we know
+ * it must be the pc. So we'll just replace it with R0.
*/
+ save_reg = 0;
+ save_val = regs->r[0];
+ regs->r[save_reg] = ALIGNADDR(regs->pc + (tp->ftt_thumb ? 4 : 8), 2);
+ if (tp->ftt_thumb) {
+ emul_instr.instr16.instr1 &= ~0x000F;
+ } else {
+ emul_instr.instr32 &= ~0x000F0000;
+ }
+ }
- addr = uthread->t_dtrace_scratch->addr;
+ emul_instr_size = dtrace_instr_size(emul_instr.instr32, emul_thumb);
- if (addr == 0LL) {
- fasttrap_sigtrap(p, uthread, pc); // Should be killing target proc
- new_pc = pc;
- break;
- }
+ /*
+ * At this point:
+ * tp->ftt_thumb = thumb mode of original instruction
+ * emul_thumb = thumb mode for emulation
+ * emul_instr = instruction we are using to emulate original instruction
+ * emul_instr_size = size of emulating instruction
+ */
- uthread->t_dtrace_scrpc = addr;
- if (emul_thumb) {
- /*
- * No way to do an unconditional branch in Thumb mode, shove the address
- * onto the user stack and go to the next location with a pop. This can
- * segfault if this push happens to cross a stack page, but that's ok, since
- * we are running in userland, and the kernel knows how to handle userland
- * stack expansions correctly.
- *
- * Layout of scratch space for Thumb mode:
- * Emulated instruction
- * ldr save_reg, [pc, #16] (if necessary, restore any register we clobbered)
- * push { r0, r1 }
- * ldr r0, [pc, #4]
- * str r0, [sp, #4]
- * pop { r0, pc }
- * Location we should return to in original program
- * Saved value of clobbered register (if necessary)
- */
+ addr = uthread->t_dtrace_scratch->addr;
- bcopy(&emul_instr, &scratch[i], emul_instr_size); i += emul_instr_size;
+ if (addr == 0LL) {
+ fasttrap_sigtrap(p, uthread, pc); // Should be killing target proc
+ new_pc = pc;
+ break;
+ }
- if (save_reg != -1) {
- uint16_t restore_inst = 0x4803;
- restore_inst |= (save_reg & 0x7) << 8;
- SET16(scratch+i, restore_inst); i += 2; // ldr reg, [pc , #16]
- }
+ uthread->t_dtrace_scrpc = addr;
+ if (emul_thumb) {
+ /*
+ * No way to do an unconditional branch in Thumb mode, shove the address
+ * onto the user stack and go to the next location with a pop. This can
+ * segfault if this push happens to cross a stack page, but that's ok, since
+ * we are running in userland, and the kernel knows how to handle userland
+ * stack expansions correctly.
+ *
+ * Layout of scratch space for Thumb mode:
+ * Emulated instruction
+ * ldr save_reg, [pc, #16] (if necessary, restore any register we clobbered)
+ * push { r0, r1 }
+ * ldr r0, [pc, #4]
+ * str r0, [sp, #4]
+ * pop { r0, pc }
+ * Location we should return to in original program
+ * Saved value of clobbered register (if necessary)
+ */
- SET16(scratch+i, 0xB403); i += 2; // push { r0, r1 }
- SET16(scratch+i, 0x4801); i += 2; // ldr r0, [pc, #4]
- SET16(scratch+i, 0x9001); i += 2; // str r0, [sp, #4]
- SET16(scratch+i, 0xBD01); i += 2; // pop { r0, pc }
+ bcopy(&emul_instr, &scratch[i], emul_instr_size); i += emul_instr_size;
- if (i % 4) {
- SET16(scratch+i, 0); i += 2; // padding - saved 32 bit words must be aligned
- }
- SET32(scratch+i, pc + instr_size + (tp->ftt_thumb ? 1 : 0)); i += 4; // Return address
- if (save_reg != -1) {
- SET32(scratch+i, save_val); i += 4; // saved value of clobbered register
- }
+ if (save_reg != -1) {
+ uint16_t restore_inst = 0x4803;
+ restore_inst |= (save_reg & 0x7) << 8;
+ SET16(scratch + i, restore_inst); i += 2; // ldr reg, [pc , #16]
+ }
- uthread->t_dtrace_astpc = addr + i;
- bcopy(&emul_instr, &scratch[i], emul_instr_size); i += emul_instr_size;
- SET16(scratch+i, FASTTRAP_THUMB_RET_INSTR); i += 2;
- } else {
- /*
- * Layout of scratch space for ARM mode:
- * Emulated instruction
- * ldr save_reg, [pc, #12] (if necessary, restore any register we clobbered)
- * ldr pc, [pc, #4]
- * Location we should return to in original program
- * Saved value of clobbered register (if necessary)
- */
+ SET16(scratch + i, 0xB403); i += 2; // push { r0, r1 }
+ SET16(scratch + i, 0x4801); i += 2; // ldr r0, [pc, #4]
+ SET16(scratch + i, 0x9001); i += 2; // str r0, [sp, #4]
+ SET16(scratch + i, 0xBD01); i += 2; // pop { r0, pc }
- bcopy(&emul_instr, &scratch[i], emul_instr_size); i += emul_instr_size;
+ if (i % 4) {
+ SET16(scratch + i, 0); i += 2; // padding - saved 32 bit words must be aligned
+ }
+ SET32(scratch + i, pc + instr_size + (tp->ftt_thumb ? 1 : 0)); i += 4; // Return address
+ if (save_reg != -1) {
+ SET32(scratch + i, save_val); i += 4; // saved value of clobbered register
+ }
- if (save_reg != -1) {
- uint32_t restore_inst = 0xE59F0004;
- restore_inst |= save_reg << 12;
- SET32(scratch+i, restore_inst); i += 4; // ldr reg, [pc, #12]
- }
- SET32(scratch+i, 0xE51FF004); i += 4; // ldr pc, [pc, #4]
+ uthread->t_dtrace_astpc = addr + i;
+ bcopy(&emul_instr, &scratch[i], emul_instr_size); i += emul_instr_size;
+ SET16(scratch + i, FASTTRAP_THUMB_RET_INSTR); i += 2;
+ } else {
+ /*
+ * Layout of scratch space for ARM mode:
+ * Emulated instruction
+ * ldr save_reg, [pc, #12] (if necessary, restore any register we clobbered)
+ * ldr pc, [pc, #4]
+ * Location we should return to in original program
+ * Saved value of clobbered register (if necessary)
+ */
- SET32(scratch+i, pc + instr_size + (tp->ftt_thumb ? 1 : 0)); i += 4; // Return address
- if (save_reg != -1) {
- SET32(scratch+i, save_val); i += 4; // Saved value of clobbered register
- }
+ bcopy(&emul_instr, &scratch[i], emul_instr_size); i += emul_instr_size;
- uthread->t_dtrace_astpc = addr + i;
- bcopy(&emul_instr, &scratch[i], emul_instr_size); i += emul_instr_size;
- SET32(scratch+i, FASTTRAP_ARM_RET_INSTR); i += 4;
+ if (save_reg != -1) {
+ uint32_t restore_inst = 0xE59F0004;
+ restore_inst |= save_reg << 12;
+ SET32(scratch + i, restore_inst); i += 4; // ldr reg, [pc, #12]
}
+ SET32(scratch + i, 0xE51FF004); i += 4; // ldr pc, [pc, #4]
- if (patchInst(p, scratch, i, uthread->t_dtrace_scratch->write_addr) != KERN_SUCCESS) {
- fasttrap_sigtrap(p, uthread, pc);
- new_pc = pc;
- break;
+ SET32(scratch + i, pc + instr_size + (tp->ftt_thumb ? 1 : 0)); i += 4; // Return address
+ if (save_reg != -1) {
+ SET32(scratch + i, save_val); i += 4; // Saved value of clobbered register
}
- if (tp->ftt_retids != NULL) {
- uthread->t_dtrace_step = 1;
- uthread->t_dtrace_ret = 1;
- new_pc = uthread->t_dtrace_astpc + (emul_thumb ? 1 : 0);
- } else {
- new_pc = uthread->t_dtrace_scrpc + (emul_thumb ? 1 : 0);
- }
+ uthread->t_dtrace_astpc = addr + i;
+ bcopy(&emul_instr, &scratch[i], emul_instr_size); i += emul_instr_size;
+ SET32(scratch + i, FASTTRAP_ARM_RET_INSTR); i += 4;
+ }
- uthread->t_dtrace_pc = pc;
- uthread->t_dtrace_npc = pc + instr_size;
- uthread->t_dtrace_on = 1;
- was_simulated = 0;
- set_thumb_flag(regs, new_pc);
+ if (uwrite(p, scratch, i, uthread->t_dtrace_scratch->write_addr) != KERN_SUCCESS) {
+ fasttrap_sigtrap(p, uthread, pc);
+ new_pc = pc;
break;
}
- default:
- panic("fasttrap: mishandled an instruction");
+ if (tp->ftt_retids != NULL) {
+ uthread->t_dtrace_step = 1;
+ uthread->t_dtrace_ret = 1;
+ new_pc = uthread->t_dtrace_astpc + (emul_thumb ? 1 : 0);
+ } else {
+ new_pc = uthread->t_dtrace_scrpc + (emul_thumb ? 1 : 0);
+ }
+
+ uthread->t_dtrace_pc = pc;
+ uthread->t_dtrace_npc = pc + instr_size;
+ uthread->t_dtrace_on = 1;
+ was_simulated = 0;
+ set_thumb_flag(regs, new_pc);
+ break;
+ }
+
+ default:
+ panic("fasttrap: mishandled an instruction");
}
done:
*/
regs->pc = new_pc;
- /*
+ /*
* If there were no return probes when we first found the tracepoint,
* we should feel no obligation to honor any return probes that were
* subsequently enabled -- they'll just have to wait until the next
- * time around.
- */
+ * time around.
+ */
if (tp->ftt_retids != NULL) {
/*
* We need to wait until the results of the instruction are
}
}
- return (0);
+ return 0;
}
int
*/
if (p->p_lflag & P_LINVFORK) {
proc_list_lock();
- while (p->p_lflag & P_LINVFORK)
+ while (p->p_lflag & P_LINVFORK) {
p = p->p_pptr;
+ }
proc_list_unlock();
}
* complex web of lies. dtrace_return_probe() (our caller)
* will correctly set %pc after we return.
*/
- regs->pc = pc;
+ regs->pc = pc;
fasttrap_return_common(p, regs, pc, npc);
- return (0);
+ return 0;
}
uint64_t
fasttrap_pid_getarg(void *arg, dtrace_id_t id, void *parg, int argno,
- int aframes)
+ int aframes)
{
#pragma unused(arg, id, parg, aframes)
arm_saved_state_t* regs = find_user_regs(current_thread());
/* First four arguments are in registers */
- if (argno < 4)
+ if (argno < 4) {
return regs->r[argno];
+ }
/* Look on the stack for the rest */
uint32_t value;
uint32_t* sp = (uint32_t*) regs->sp;
DTRACE_CPUFLAG_SET(CPU_DTRACE_NOFAULT);
- value = dtrace_fuword32((user_addr_t) (sp+argno-4));
+ value = dtrace_fuword32((user_addr_t) (sp + argno - 4));
DTRACE_CPUFLAG_CLEAR(CPU_DTRACE_NOFAULT | CPU_DTRACE_BADADDR);
return value;
{
#pragma unused(arg, id, parg, argno, aframes)
#if 0
- return (fasttrap_anarg(ttolwp(curthread)->lwp_regs, 0, argno));
+ return fasttrap_anarg(ttolwp(curthread)->lwp_regs, 0, argno);
#endif
return 0;
}
-