1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
|
//+build darwin,macnative
#include "threads_darwin.h"
int
write_memory(task_t task, mach_vm_address_t addr, void *d, mach_msg_type_number_t len) {
kern_return_t kret;
vm_region_submap_short_info_data_64_t info;
mach_msg_type_number_t count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
mach_vm_size_t l = len;
mach_port_t objname;
if (len == 1) l = 2;
kret = mach_vm_region((vm_map_t)task, &(mach_vm_address_t){addr}, (mach_vm_size_t*)&l, VM_REGION_BASIC_INFO_64, (vm_region_info_t)&info, &count, &objname);
if (kret != KERN_SUCCESS) return -1;
// Set permissions to enable writing to this memory location
kret = mach_vm_protect(task, addr, len, FALSE, VM_PROT_WRITE|VM_PROT_COPY|VM_PROT_READ);
if (kret != KERN_SUCCESS) return -1;
kret = mach_vm_write((vm_map_t)task, addr, (vm_offset_t)d, len);
if (kret != KERN_SUCCESS) return -1;
// Restore virtual memory permissions
kret = mach_vm_protect(task, addr, len, FALSE, info.protection);
if (kret != KERN_SUCCESS) return -1;
return 0;
}
int
read_memory(task_t task, mach_vm_address_t addr, void *d, mach_msg_type_number_t len) {
kern_return_t kret;
pointer_t data;
mach_msg_type_number_t count;
kret = mach_vm_read((vm_map_t)task, addr, len, &data, &count);
if (kret != KERN_SUCCESS) return -1;
memcpy(d, (void *)data, len);
kret = vm_deallocate(task, data, len);
if (kret != KERN_SUCCESS) return -1;
return count;
}
kern_return_t
get_registers(mach_port_name_t task, x86_thread_state64_t *state) {
kern_return_t kret;
mach_msg_type_number_t stateCount = x86_THREAD_STATE64_COUNT;
// TODO(dp) - possible memory leak - vm_deallocate state
return thread_get_state(task, x86_THREAD_STATE64, (thread_state_t)state, &stateCount);
}
kern_return_t
get_fpu_registers(mach_port_name_t task, x86_float_state64_t *state) {
kern_return_t kret;
mach_msg_type_number_t stateCount = x86_FLOAT_STATE64_COUNT;
return thread_get_state(task, x86_FLOAT_STATE64, (thread_state_t)state, &stateCount);
}
kern_return_t
get_identity(mach_port_name_t task, thread_identifier_info_data_t *idinfo) {
mach_msg_type_number_t idinfoCount = THREAD_IDENTIFIER_INFO_COUNT;
return thread_info(task, THREAD_IDENTIFIER_INFO, (thread_info_t)idinfo, &idinfoCount);
}
kern_return_t
set_registers(mach_port_name_t task, x86_thread_state64_t *state) {
mach_msg_type_number_t stateCount = x86_THREAD_STATE64_COUNT;
return thread_set_state(task, x86_THREAD_STATE64, (thread_state_t)state, stateCount);
}
kern_return_t
set_pc(thread_act_t task, uint64_t pc) {
kern_return_t kret;
x86_thread_state64_t state;
mach_msg_type_number_t stateCount = x86_THREAD_STATE64_COUNT;
kret = thread_get_state(task, x86_THREAD_STATE64, (thread_state_t)&state, &stateCount);
if (kret != KERN_SUCCESS) return kret;
state.__rip = pc;
return thread_set_state(task, x86_THREAD_STATE64, (thread_state_t)&state, stateCount);
}
kern_return_t
single_step(thread_act_t thread) {
kern_return_t kret;
x86_thread_state64_t regs;
mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
kret = thread_get_state(thread, x86_THREAD_STATE64, (thread_state_t)®s, &count);
if (kret != KERN_SUCCESS) return kret;
// Set trap bit in rflags
regs.__rflags |= 0x100UL;
kret = thread_set_state(thread, x86_THREAD_STATE64, (thread_state_t)®s, count);
if (kret != KERN_SUCCESS) return kret;
return resume_thread(thread);
}
kern_return_t
resume_thread(thread_act_t thread) {
kern_return_t kret;
struct thread_basic_info info;
unsigned int info_count = THREAD_BASIC_INFO_COUNT;
kret = thread_info((thread_t)thread, THREAD_BASIC_INFO, (thread_info_t)&info, &info_count);
if (kret != KERN_SUCCESS) return kret;
for (int i = 0; i < info.suspend_count; i++) {
kret = thread_resume(thread);
if (kret != KERN_SUCCESS) return kret;
}
return KERN_SUCCESS;
}
kern_return_t
clear_trap_flag(thread_act_t thread) {
kern_return_t kret;
x86_thread_state64_t regs;
mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT;
kret = thread_get_state(thread, x86_THREAD_STATE64, (thread_state_t)®s, &count);
if (kret != KERN_SUCCESS) return kret;
// Clear trap bit in rflags
regs.__rflags ^= 0x100UL;
return thread_set_state(thread, x86_THREAD_STATE64, (thread_state_t)®s, count);
}
int
thread_blocked(thread_act_t thread) {
kern_return_t kret;
struct thread_basic_info info;
unsigned int info_count = THREAD_BASIC_INFO_COUNT;
kret = thread_info((thread_t)thread, THREAD_BASIC_INFO, (thread_info_t)&info, &info_count);
if (kret != KERN_SUCCESS) return -1;
return info.suspend_count;
}
int
num_running_threads(task_t task) {
kern_return_t kret;
thread_act_array_t list;
mach_msg_type_number_t count;
int i, n = 0;
kret = task_threads(task, &list, &count);
if (kret != KERN_SUCCESS) {
return -kret;
}
for (i = 0; i < count; ++i) {
thread_act_t thread = list[i];
struct thread_basic_info info;
unsigned int info_count = THREAD_BASIC_INFO_COUNT;
kret = thread_info((thread_t)thread, THREAD_BASIC_INFO, (thread_info_t)&info, &info_count);
if (kret == KERN_SUCCESS) {
if (info.suspend_count == 0) {
++n;
} else {
}
}
}
kret = vm_deallocate(mach_task_self(), (vm_address_t) list, count * sizeof(list[0]));
if (kret != KERN_SUCCESS) return -kret;
return n;
}
|