Rizin
unix-like reverse engineering framework and cli tools
xnu_threads.h File Reference
#include <rz_debug.h>
#include <mach/mach_vm.h>

Go to the source code of this file.

Classes

struct  _exception_info
 
struct  _xnu_thread
 
struct  _exc_msg
 
struct  _rep_msg
 

Macros

#define RETURN_ON_MACH_ERROR(msg, retval)
 

Typedefs

typedef struct _exception_info xnu_exception_info
 
typedef struct _xnu_thread xnu_thread_t
 
typedef struct _exc_msg exc_msg
 
typedef struct _rep_msg rep_msg
 

Functions

RZ_IPI int rz_xnu_update_thread_list (RzDebug *dbg)
 
RZ_IPI xnu_thread_trz_xnu_get_thread (RzDebug *dbg, int tid)
 
RZ_IPI thread_t rz_xnu_get_cur_thread (RzDebug *dbg)
 
RZ_IPI bool rz_xnu_thread_set_drx (RzDebug *dbg, xnu_thread_t *thread)
 
RZ_IPI bool rz_xnu_thread_set_gpr (RzDebug *dbg, xnu_thread_t *thread)
 
RZ_IPI bool rz_xnu_thread_get_gpr (RzDebug *dbg, xnu_thread_t *thread)
 
RZ_IPI bool rz_xnu_thread_get_drx (RzDebug *dbg, xnu_thread_t *thread)
 
RZ_IPI bool xnu_modify_trace_bit (RzDebug *dbg, xnu_thread_t *th, int enable)
 
static bool xnu_set_trace_bit (RzDebug *dbg, xnu_thread_t *th)
 
static bool xnu_clear_trace_bit (RzDebug *dbg, xnu_thread_t *th)
 
RZ_IPI bool xnu_create_exception_thread (RzDebug *dbg)
 
RZ_IPI bool xnu_restore_exception_ports (int pid)
 
RZ_IPI RzDebugReasonType xnu_wait_for_exception (RzDebug *dbg, int pid, ut32 timeout_ms, bool quiet_signal)
 

Macro Definition Documentation

◆ RETURN_ON_MACH_ERROR

#define RETURN_ON_MACH_ERROR (   msg,
  retval 
)
Value:
if (kr != KERN_SUCCESS) { \
mach_error(msg, kr); \
return ((retval)); \
}
static struct sockaddr static addrlen static backlog const void msg
Definition: sfsocketcall.h:119

Definition at line 33 of file xnu_threads.h.

Typedef Documentation

◆ exc_msg

typedef struct _exc_msg exc_msg

◆ rep_msg

typedef struct _rep_msg rep_msg

◆ xnu_exception_info

◆ xnu_thread_t

typedef struct _xnu_thread xnu_thread_t

Function Documentation

◆ rz_xnu_get_cur_thread()

RZ_IPI thread_t rz_xnu_get_cur_thread ( RzDebug dbg)

Definition at line 402 of file xnu_threads.c.

402  {
403  thread_t th;
404  thread_array_t threads = NULL;
405  unsigned int n_threads = 0;
406  task_t t = pid_to_task(dbg->pid);
407  if (!t) {
408  return -1;
409  }
410  if (task_threads(t, &threads, &n_threads) != KERN_SUCCESS) {
411  return -1;
412  }
413  if (n_threads > 0) {
414  memcpy(&th, threads, sizeof(th));
415  } else {
416  th = -1;
417  }
418  vm_deallocate(mach_task_self(), (vm_address_t)threads, n_threads * sizeof(thread_act_t));
419  return th;
420 }
#define NULL
Definition: cris-opc.c:27
RzDebug * dbg
Definition: desil.c:30
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
static uv_thread_t * threads
Definition: threadpool.c:38
task_t pid_to_task(int pid)
Definition: xnu_debug.c:498

References dbg, memcpy(), NULL, rz_debug_t::pid, pid_to_task(), and threads.

Referenced by rz_xnu_get_thread(), xnu_continue(), xnu_reg_read(), xnu_reg_write(), and xnu_step().

◆ rz_xnu_get_thread()

RZ_IPI xnu_thread_t* rz_xnu_get_thread ( RzDebug dbg,
int  tid 
)

Definition at line 378 of file xnu_threads.c.

378  {
379  if (!dbg || tid < 0) {
380  return NULL;
381  }
383  eprintf("Failed to update thread_list xnu_udpate_thread_list\n");
384  return NULL;
385  }
386  // TODO get the current thread
387  RzListIter *it = rz_list_find(dbg->threads, (const void *)(size_t)&tid,
389  if (!it) {
390  tid = rz_xnu_get_cur_thread(dbg);
391  it = rz_list_find(dbg->threads, (const void *)(size_t)&tid,
393  if (!it) {
394  eprintf("Thread not found get_xnu_thread\n");
395  return NULL;
396  }
397  }
398  return (xnu_thread_t *)it->data;
399 }
RZ_API RZ_BORROW RzListIter * rz_list_find(RZ_NONNULL const RzList *list, const void *p, RZ_NONNULL RzListComparator cmp)
Returns RzListIter element which matches via the RzListComparator.
Definition: list.c:620
#define eprintf(x, y...)
Definition: rlcc.c:7
int(* RzListComparator)(const void *value, const void *list_data)
Definition: rz_list.h:33
RzList * threads
Definition: rz_debug.h:251
void * data
Definition: rz_list.h:14
RZ_IPI int rz_xnu_update_thread_list(RzDebug *dbg)
Definition: xnu_threads.c:290
RZ_IPI thread_t rz_xnu_get_cur_thread(RzDebug *dbg)
Definition: xnu_threads.c:402
static int thread_find(thread_t *port, xnu_thread_t *a)
Definition: xnu_threads.c:286

References rz_list_iter_t::data, dbg, eprintf, NULL, rz_list_find(), rz_xnu_get_cur_thread(), rz_xnu_update_thread_list(), thread_find(), and rz_debug_t::threads.

Referenced by xnu_continue(), xnu_map_alloc(), xnu_map_dealloc(), xnu_reg_read(), xnu_reg_write(), and xnu_step().

◆ rz_xnu_thread_get_drx()

RZ_IPI bool rz_xnu_thread_get_drx ( RzDebug dbg,
xnu_thread_t thread 
)

Definition at line 26 of file xnu_threads.c.

26  {
27  rz_return_val_if_fail(dbg && thread, false);
28  kern_return_t rc;
29 #if __x86_64__ || __i386__
30  thread->flavor = x86_DEBUG_STATE;
31  thread->count = x86_DEBUG_STATE_COUNT;
32  thread->state_size = (dbg->bits == RZ_SYS_BITS_64)
33  ? sizeof(x86_debug_state64_t)
34  : sizeof(x86_debug_state32_t);
35  thread->state = &thread->drx.uds;
36  rc = thread_get_state(thread->port, thread->flavor,
37  (thread_state_t)&thread->drx, &thread->count);
38 #elif __arm64__ || __arm64 || __aarch64 || __aarch64__
39  if (dbg->bits == RZ_SYS_BITS_64) {
40  thread->count = ARM_DEBUG_STATE64_COUNT;
41  thread->flavor = ARM_DEBUG_STATE64;
42  rc = thread_get_state(thread->port, thread->flavor,
43  (thread_state_t)&thread->debug.drx64,
44  &thread->count);
45  } else {
46  thread->count = ARM_DEBUG_STATE32_COUNT;
47  thread->flavor = ARM_DEBUG_STATE32;
48  rc = thread_get_state(thread->port, thread->flavor,
49  (thread_state_t)&thread->debug.drx32,
50  &thread->count);
51  }
52 #elif __arm__ || __arm || __armv7__
53  thread->count = ARM_DEBUG_STATE_COUNT;
54  thread->flavor = ARM_DEBUG_STATE;
55  rc = thread_get_state(thread->port, thread->flavor,
56  (thread_state_t)&thread->debug.drx,
57  &thread->count);
58 #else
59 #warning xnu_thread_get_drx: Unsupported architecture
60  rc = KERN_FAILURE;
61 #endif
62  if (rc != KERN_SUCCESS) {
63  LOG_MACH_ERROR("thread_get_state", rc);
64  thread->count = 0;
65  return false;
66  }
67  return true;
68 }
@ x86_DEBUG_STATE
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
@ RZ_SYS_BITS_64
Definition: rz_sys.h:21
thread_t port
Definition: xnu_threads.h:51
ut32 state_size
Definition: xnu_threads.h:57
void * state
Definition: xnu_threads.h:56
int bits
Definition: rz_debug.h:243
#define LOG_MACH_ERROR(name, rc)
Definition: xnu_debug.h:17

References rz_debug_t::bits, _xnu_thread::count, dbg, _xnu_thread::flavor, LOG_MACH_ERROR, _xnu_thread::port, rz_return_val_if_fail, RZ_SYS_BITS_64, _xnu_thread::state, _xnu_thread::state_size, and x86_DEBUG_STATE.

Referenced by xnu_reg_read().

◆ rz_xnu_thread_get_gpr()

RZ_IPI bool rz_xnu_thread_get_gpr ( RzDebug dbg,
xnu_thread_t thread 
)

Definition at line 184 of file xnu_threads.c.

184  {
185  rz_return_val_if_fail(dbg && thread, false);
186  RZ_REG_T *regs = &thread->gpr;
187  if (!regs) {
188  return false;
189  }
190  kern_return_t rc;
191 #if __POWERPC__
192  thread->state = regs;
193 #elif __arm64 || __aarch64 || __aarch64__ || __arm64__
194  // thread->state = regs;
195  thread->state = &regs->uts;
196  if (dbg->bits == RZ_SYS_BITS_64) {
197  thread->flavor = ARM_THREAD_STATE64;
198  thread->count = ARM_THREAD_STATE64_COUNT;
199  thread->state_size = sizeof(arm_thread_state64_t);
200  } else {
201  thread->flavor = ARM_THREAD_STATE;
202  thread->count = ARM_THREAD_STATE_COUNT;
203  thread->state_size = sizeof(arm_thread_state32_t);
204  }
205 #elif __arm || __arm__ || __armv7__
206  thread->state = regs;
207  thread->flavor = ARM_THREAD_STATE;
208  thread->count = ARM_THREAD_STATE_COUNT;
209  thread->state_size = sizeof(arm_thread_state_t);
210 #elif __x86_64__ || __i386__
211  thread->state = &regs->uts;
212  thread->flavor = x86_THREAD_STATE;
213  thread->count = x86_THREAD_STATE_COUNT;
214  thread->state_size = (dbg->bits == RZ_SYS_BITS_64) ? sizeof(x86_thread_state64_t) : sizeof(x86_thread_state32_t);
215 #endif
216  rc = thread_get_state(thread->port, thread->flavor,
217  (thread_state_t)regs, &thread->count);
218  if (rc != KERN_SUCCESS) {
219  LOG_MACH_ERROR("thread_get_state", rc);
220  thread->count = 0;
221  return false;
222  }
223  return true;
224 }
static char * regs[]
Definition: analysis_sh.c:203
#define x86_THREAD_STATE_COUNT
@ x86_THREAD_STATE
RZ_REG_T gpr
Definition: xnu_threads.h:55

References rz_debug_t::bits, _xnu_thread::count, dbg, _xnu_thread::flavor, _xnu_thread::gpr, LOG_MACH_ERROR, _xnu_thread::port, regs, rz_return_val_if_fail, RZ_SYS_BITS_64, _xnu_thread::state, _xnu_thread::state_size, x86_THREAD_STATE, and x86_THREAD_STATE_COUNT.

Referenced by xnu_reg_read(), and xnu_thread_list().

◆ rz_xnu_thread_set_drx()

RZ_IPI bool rz_xnu_thread_set_drx ( RzDebug dbg,
xnu_thread_t thread 
)

Definition at line 70 of file xnu_threads.c.

70  {
71  rz_return_val_if_fail(dbg && thread, false);
72  kern_return_t rc;
73 #if __i386__ || __x86_64__
74  x86_debug_state_t *regs = &thread->drx;
75  if (!regs) {
76  return false;
77  }
78  thread->flavor = x86_DEBUG_STATE;
79  thread->count = x86_DEBUG_STATE_COUNT;
80  if (dbg->bits == RZ_SYS_BITS_64) {
81  regs->dsh.flavor = x86_DEBUG_STATE64;
82  regs->dsh.count = x86_DEBUG_STATE64_COUNT;
83  } else {
84  regs->dsh.flavor = x86_DEBUG_STATE32;
85  regs->dsh.count = x86_DEBUG_STATE32_COUNT;
86  }
87  rc = thread_set_state(thread->port, thread->flavor,
88  (thread_state_t)regs, thread->count);
89 #elif __arm64__ || __arm64 || __aarch64 || __aarch64__
90  if (dbg->bits == RZ_SYS_BITS_64) {
91  thread->count = ARM_DEBUG_STATE64_COUNT;
92  thread->flavor = ARM_DEBUG_STATE64;
93  rc = thread_set_state(thread->port, thread->flavor,
94  (thread_state_t)&thread->debug.drx64,
95  thread->count);
96  } else {
97  thread->count = ARM_DEBUG_STATE32_COUNT;
98  thread->flavor = ARM_DEBUG_STATE32;
99  rc = thread_set_state(thread->port, thread->flavor,
100  (thread_state_t)&thread->debug.drx32,
101  thread->count);
102  }
103 #elif __arm__ || __arm || __armv7__
104  thread->count = ARM_DEBUG_STATE_COUNT;
105  thread->flavor = ARM_DEBUG_STATE;
106  rc = thread_set_state(thread->port, thread->flavor,
107  (thread_state_t)&thread->debug.drx,
108  &thread->count);
109 #elif __POWERPC__
110 /* not supported */
111 #ifndef PPC_DEBUG_STATE32
112 #define PPC_DEBUG_STATE32 1
113 #endif
114  ppc_debug_state_t *regs;
115  // thread->flavor = PPC_DEBUG_STATE32;
116  // thread->count = RZ_MIN (thread->count, sizeof (regs->uds.ds32));
117  return false;
118 #else
119  regs->dsh.flavor = 0;
120  thread->count = 0;
121 #endif
122  if (rc != KERN_SUCCESS) {
123  LOG_MACH_ERROR("thread_set_state", rc);
124  thread->count = 0;
125  return false;
126  }
127  return true;
128 }
@ x86_DEBUG_STATE64
@ x86_DEBUG_STATE32

References rz_debug_t::bits, _xnu_thread::count, dbg, _xnu_thread::flavor, LOG_MACH_ERROR, _xnu_thread::port, regs, rz_return_val_if_fail, RZ_SYS_BITS_64, x86_DEBUG_STATE, x86_DEBUG_STATE32, and x86_DEBUG_STATE64.

Referenced by xnu_reg_write().

◆ rz_xnu_thread_set_gpr()

RZ_IPI bool rz_xnu_thread_set_gpr ( RzDebug dbg,
xnu_thread_t thread 
)

Definition at line 130 of file xnu_threads.c.

130  {
131  rz_return_val_if_fail(dbg && thread, false);
132  kern_return_t rc;
133  RZ_REG_T *regs = (RZ_REG_T *)&thread->gpr;
134  if (!regs) {
135  return false;
136  }
137 #if __i386__ || __x86_64__
138  // thread->flavor is used in a switch+case but in regs->tsh.flavor we
139  // specify
140  thread->state = &regs->uts;
141  // thread->state = regs;
142  thread->flavor = x86_THREAD_STATE;
143  thread->count = x86_THREAD_STATE_COUNT;
144  if (dbg->bits == RZ_SYS_BITS_64) {
145  regs->tsh.flavor = x86_THREAD_STATE64;
146  regs->tsh.count = x86_THREAD_STATE64_COUNT;
147  } else {
148  regs->tsh.flavor = x86_THREAD_STATE32;
149  regs->tsh.count = x86_THREAD_STATE32_COUNT;
150  }
151 #elif __arm64 || __aarch64 || __arm64__ || __aarch64__
152 #if 0
153  /* unified doesnt seems to work */
154  thread->flavor = ARM_UNIFIED_THREAD_STATE;
155  thread->count = ARM_UNIFIED_THREAD_STATE_COUNT;
156 #endif
157  // thread->state = regs;
158  thread->state = &regs->uts;
159  if (dbg->bits == RZ_SYS_BITS_64) {
160  thread->flavor = ARM_THREAD_STATE64;
161  thread->count = ARM_THREAD_STATE64_COUNT;
162  thread->state_size = sizeof(arm_thread_state64_t);
163  } else {
164  thread->flavor = ARM_THREAD_STATE32;
165  thread->count = ARM_THREAD_STATE32_COUNT;
166  thread->state_size = sizeof(arm_thread_state32_t);
167  }
168 #elif __arm || __arm__ || __armv7__
169  thread->flavor = ARM_THREAD_STATE;
170  thread->count = ARM_THREAD_STATE_COUNT;
171  thread->state_size = sizeof(arm_thread_state_t);
172 
173 #endif
174  rc = thread_set_state(thread->port, thread->flavor,
175  (thread_state_t)regs, thread->count);
176  if (rc != KERN_SUCCESS) {
177  LOG_MACH_ERROR("thread_set_state", rc);
178  thread->count = 0;
179  return false;
180  }
181  return true;
182 }
@ x86_THREAD_STATE64
@ x86_THREAD_STATE32
#define x86_THREAD_STATE64_COUNT
if(dbg->bits==RZ_SYS_BITS_64)
Definition: windows-arm64.h:4

References rz_debug_t::bits, _xnu_thread::count, dbg, _xnu_thread::flavor, _xnu_thread::gpr, if(), LOG_MACH_ERROR, _xnu_thread::port, regs, rz_return_val_if_fail, RZ_SYS_BITS_64, _xnu_thread::state, _xnu_thread::state_size, x86_THREAD_STATE, x86_THREAD_STATE32, x86_THREAD_STATE64, x86_THREAD_STATE64_COUNT, and x86_THREAD_STATE_COUNT.

Referenced by xnu_reg_write().

◆ rz_xnu_update_thread_list()

RZ_IPI int rz_xnu_update_thread_list ( RzDebug dbg)

Definition at line 290 of file xnu_threads.c.

290  {
291  thread_array_t thread_list = NULL;
292  unsigned int thread_count = 0;
293  xnu_thread_t *thread;
294  kern_return_t kr;
295  task_t task;
296  int i;
297 
298  if (!dbg->threads) {
300  if (!dbg->threads) {
301  return false;
302  }
303  }
304  // ok we have the list that will hold our threads, now is time to get
305  // them
306  task = pid_to_task(dbg->pid);
307  if (!task) {
308  return false;
309  }
310  kr = task_threads(task, &thread_list, &thread_count);
311  if (kr != KERN_SUCCESS) {
312  // we can get into this when the process has terminated but we
313  // still hold the old task because we are caching it
314  eprintf("Failed to get list of task's threads\n");
315  return false;
316  }
317  if (rz_list_empty(dbg->threads)) {
318  // it's the first time write all threads inside the list
319  for (i = 0; i < thread_count; i++) {
320  thread = xnu_get_thread_with_info(dbg, thread_list[i]);
321  if (!thread) {
322  eprintf("Failed to fill_thread\n");
323  continue;
324  }
325  if (!rz_list_append(dbg->threads, thread)) {
326  eprintf("Failed to add thread to list\n");
327  xnu_thread_free(thread);
328  }
329  }
330  } else {
331  RzListIter *iter, *iter2;
332  // first pass to get rid of those threads that are not longer
333  // alive
334  rz_list_foreach_safe (dbg->threads, iter, iter2, thread) {
335  bool flag = true; // this flag will denote when delete
336  // a thread
337  for (i = 0; i < thread_count; i++) {
338  if (thread->port == thread_list[i]) {
339  flag = false;
340  break;
341  }
342  }
343  if (flag) {
344  // it is not longer alive so remove from the
345  // list
347  } else {
348  // otherwise update the info
349  xnu_update_thread_info(dbg, thread);
350  }
351  }
352  // ok now we have to insert those threads that we don't have
353  for (i = 0; i < thread_count; i++) {
354  xnu_thread_t *t;
355  iter = rz_list_find(dbg->threads, &thread_list[i],
357  // it means is already in our list
358  if (iter) {
359  // free the ownership over the thread
360  kr = mach_port_deallocate(mach_task_self(),
361  thread_list[i]);
362  if (kr != KERN_SUCCESS) {
363  eprintf("Failed to deallocate port\n");
364  }
365  continue;
366  }
367  // otherwise insert it
368  t = xnu_get_thread_with_info(dbg, thread_list[i]);
370  }
371  }
372  // once that is over we need to free the buffer
373  (void)vm_deallocate(mach_task_self(), (mach_vm_address_t)thread_list,
374  thread_count * sizeof(thread_t));
375  return true;
376 }
lzma_index ** i
Definition: index.h:629
RZ_API RZ_OWN RzList * rz_list_newf(RzListFree f)
Returns a new initialized RzList pointer and sets the free method.
Definition: list.c:248
RZ_API void rz_list_delete(RZ_NONNULL RzList *list, RZ_NONNULL RzListIter *iter)
Removes an entry in the list by using the RzListIter pointer.
Definition: list.c:162
RZ_API RZ_BORROW RzListIter * rz_list_append(RZ_NONNULL RzList *list, void *data)
Appends at the end of the list a new element.
Definition: list.c:288
void(* RzListFree)(void *ptr)
Definition: rz_list.h:11
static void xnu_thread_free(xnu_thread_t *thread)
Definition: xnu_threads.c:10
static int xnu_update_thread_info(RzDebug *dbg, xnu_thread_t *thread)
Definition: xnu_threads.c:278
static xnu_thread_t * xnu_get_thread_with_info(RzDebug *dbg, thread_t port)
Definition: xnu_threads.c:265

References dbg, eprintf, i, NULL, rz_debug_t::pid, pid_to_task(), _xnu_thread::port, rz_list_append(), rz_list_delete(), rz_list_find(), rz_list_newf(), thread_find(), rz_debug_t::threads, xnu_get_thread_with_info(), xnu_thread_free(), and xnu_update_thread_info().

Referenced by rz_xnu_get_thread(), and xnu_thread_list().

◆ xnu_clear_trace_bit()

static bool xnu_clear_trace_bit ( RzDebug dbg,
xnu_thread_t th 
)
inlinestatic

Definition at line 114 of file xnu_threads.h.

114  {
115  return xnu_modify_trace_bit(dbg, th, 0);
116 }
RZ_IPI bool xnu_modify_trace_bit(RzDebug *dbg, xnu_thread_t *th, int enable)

References dbg, and xnu_modify_trace_bit().

Referenced by xnu_continue().

◆ xnu_create_exception_thread()

RZ_IPI bool xnu_create_exception_thread ( RzDebug dbg)

Definition at line 479 of file xnu_excthreads.c.

479  {
480 #if __POWERPC__
481  return false;
482 #else
483  kern_return_t kr;
484  mach_port_t exception_port = MACH_PORT_NULL;
485  mach_port_t req_port;
486  // Got the Mach port for the current process
487  mach_port_t task_self = mach_task_self();
488  task_t task = pid_to_task(dbg->pid);
489  if (!task) {
490  eprintf("error to get task for the debuggee process"
491  " xnu_start_exception_thread\n");
492  return false;
493  }
494  if (!MACH_PORT_VALID(task_self)) {
495  eprintf("error to get the task for the current process"
496  " xnu_start_exception_thread\n");
497  return false;
498  }
499  // Allocate an exception port that we will use to track our child process
500  kr = mach_port_allocate(task_self, MACH_PORT_RIGHT_RECEIVE,
501  &exception_port);
502  RETURN_ON_MACH_ERROR("error to allocate mach_port exception\n", false);
503  // Add the ability to send messages on the new exception port
504  kr = mach_port_insert_right(task_self, exception_port, exception_port,
505  MACH_MSG_TYPE_MAKE_SEND);
506  RETURN_ON_MACH_ERROR("error to allocate insert right\n", false);
507  // Atomically swap out (and save) the child process's exception ports
508  // for the one we just created. We'll want to receive all exceptions.
509  ex.count = (sizeof(ex.ports) / sizeof(*ex.ports));
510  kr = task_swap_exception_ports(task, EXC_MASK_ALL, exception_port,
511  EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, THREAD_STATE_NONE,
513  RETURN_ON_MACH_ERROR("failed to swap exception ports\n", false);
514  // get notification when process die
515  kr = mach_port_request_notification(task_self, task, MACH_NOTIFY_DEAD_NAME,
516  0, exception_port, MACH_MSG_TYPE_MAKE_SEND_ONCE, &req_port);
517  if (kr != KERN_SUCCESS) {
518  eprintf("Termination notification request failed\n");
519  }
520  ex.exception_port = exception_port;
521  return true;
522 #endif
523 }
mach_msg_type_number_t count
Definition: xnu_threads.h:44
mach_port_t exception_port
Definition: xnu_threads.h:46
mach_port_t ports[EXC_TYPES_COUNT]
Definition: xnu_threads.h:41
thread_state_flavor_t flavors[EXC_TYPES_COUNT]
Definition: xnu_threads.h:43
exception_mask_t masks[EXC_TYPES_COUNT]
Definition: xnu_threads.h:40
exception_behavior_t behaviors[EXC_TYPES_COUNT]
Definition: xnu_threads.h:42
static xnu_exception_info ex
#define RETURN_ON_MACH_ERROR(msg, retval)
Definition: xnu_threads.h:33

References _exception_info::behaviors, _exception_info::count, dbg, eprintf, ex, _exception_info::exception_port, _exception_info::flavors, _exception_info::masks, rz_debug_t::pid, pid_to_task(), _exception_info::ports, and RETURN_ON_MACH_ERROR.

Referenced by xnu_attach().

◆ xnu_modify_trace_bit()

RZ_IPI bool xnu_modify_trace_bit ( RzDebug dbg,
xnu_thread_t th,
int  enable 
)

◆ xnu_restore_exception_ports()

RZ_IPI bool xnu_restore_exception_ports ( int  pid)

Definition at line 226 of file xnu_excthreads.c.

226  {
227  kern_return_t kr;
228  int i;
229  task_t task = pid_to_task(pid);
230  if (!task)
231  return false;
232  for (i = 0; i < ex.count; i++) {
233  kr = task_set_exception_ports(task, ex.masks[i], ex.ports[i],
234  ex.behaviors[i], ex.flavors[i]);
235  if (kr != KERN_SUCCESS) {
236  eprintf("fail to restore exception ports\n");
237  return false;
238  }
239  }
240  kr = mach_port_deallocate(mach_task_self(), ex.exception_port);
241  if (kr != KERN_SUCCESS) {
242  eprintf("failed to deallocate exception port\n");
243  return false;
244  }
245  return true;
246 }
static static fork const void static count static fd const char const char static newpath char char char static envp time_t static t const char static mode static whence const char static dir time_t static t unsigned static seconds const char struct utimbuf static buf static inc pid
Definition: sflib.h:64

References _exception_info::behaviors, _exception_info::count, eprintf, ex, _exception_info::exception_port, _exception_info::flavors, i, _exception_info::masks, pid, pid_to_task(), and _exception_info::ports.

Referenced by xnu_detach().

◆ xnu_set_trace_bit()

static bool xnu_set_trace_bit ( RzDebug dbg,
xnu_thread_t th 
)
inlinestatic

Definition at line 111 of file xnu_threads.h.

111  {
112  return xnu_modify_trace_bit(dbg, th, 1);
113 }

References dbg, and xnu_modify_trace_bit().

Referenced by xnu_step().

◆ xnu_wait_for_exception()

RZ_IPI RzDebugReasonType xnu_wait_for_exception ( RzDebug dbg,
int  pid,
ut32  timeout_ms,
bool  quiet_signal 
)

Wait for a Mach exception, reply to it and handle it.

Parameters
timeout_msif zero, wait infinitely, otherwise specifies a timeout for receiving
quiet_signaldon't print when receiving a standard unix signal

Definition at line 409 of file xnu_excthreads.c.

409  {
411  kern_return_t kr;
412  int ret_code;
414  mig_reply_error_t reply;
415  bool ret;
416  exc_msg msg = { 0 };
417  if (!dbg) {
418  return reason;
419  }
420  msg.hdr.msgh_local_port = ex.exception_port;
421  msg.hdr.msgh_size = sizeof(exc_msg);
422  for (;;) {
423  kr = mach_msg(
424  &msg.hdr,
425  MACH_RCV_MSG | MACH_RCV_INTERRUPT | (timeout_ms ? MACH_RCV_TIMEOUT : 0), 0,
426  sizeof(exc_msg), ex.exception_port,
427  timeout_ms ? timeout_ms : MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
428  if (kr == MACH_RCV_INTERRUPTED) {
430  break;
431  } else if (kr == MACH_RCV_TIMED_OUT) {
432  RZ_LOG_ERROR("Waiting for Mach exception timed out");
433  reason = RZ_DEBUG_REASON_UNKNOWN;
434  break;
435  } else if (kr != MACH_MSG_SUCCESS) {
436  RZ_LOG_ERROR("message didn't succeeded\n");
437  break;
438  }
439  ret = validate_mach_message(dbg, &msg);
440  if (!ret) {
441  ret = handle_dead_notify(dbg, &msg);
442  if (ret) {
443  reason = RZ_DEBUG_REASON_DEAD;
444  break;
445  }
446  }
447  if (!ret) {
448  encode_reply(&reply, &msg.hdr, KERN_FAILURE);
449  kr = mach_msg(&reply.Head, MACH_SEND_MSG | MACH_SEND_INTERRUPT,
450  reply.Head.msgh_size, 0,
451  MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE,
452  MACH_PORT_NULL);
453  if (reply.Head.msgh_remote_port != 0 && kr != MACH_MSG_SUCCESS) {
454  kr = mach_port_deallocate(mach_task_self(), reply.Head.msgh_remote_port);
455  if (kr != KERN_SUCCESS) {
456  eprintf("failed to deallocate reply port\n");
457  }
458  }
459  continue;
460  }
461 
462  reason = handle_exception_message(dbg, &msg, &ret_code, quiet_signal);
463  encode_reply(&reply, &msg.hdr, ret_code);
464  kr = mach_msg(&reply.Head, MACH_SEND_MSG | MACH_SEND_INTERRUPT,
465  reply.Head.msgh_size, 0,
466  MACH_PORT_NULL, 0,
467  MACH_PORT_NULL);
468  if (reply.Head.msgh_remote_port != 0 && kr != MACH_MSG_SUCCESS) {
469  kr = mach_port_deallocate(mach_task_self(), reply.Head.msgh_remote_port);
470  if (kr != KERN_SUCCESS)
471  eprintf("failed to deallocate reply port\n");
472  }
473  break; // to avoid infinite loops
474  }
475  dbg->stopaddr = rz_debug_reg_get(dbg, "PC");
476  return reason;
477 }
RZ_API ut64 rz_debug_reg_get(RzDebug *dbg, const char *name)
Definition: dreg.c:99
RzDebugReasonType
Definition: rz_debug.h:89
@ RZ_DEBUG_REASON_DEAD
Definition: rz_debug.h:90
@ RZ_DEBUG_REASON_UNKNOWN
Definition: rz_debug.h:103
@ RZ_DEBUG_REASON_ERROR
Definition: rz_debug.h:104
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
ut64 stopaddr
Definition: rz_debug.h:278
#define RZ_DEBUG_REASON_MACH_RCV_INTERRUPTED
Definition: xnu_debug.h:261
static bool validate_mach_message(RzDebug *dbg, exc_msg *msg)
static bool handle_dead_notify(RzDebug *dbg, exc_msg *msg)
static int handle_exception_message(RzDebug *dbg, exc_msg *msg, int *ret_code, bool quiet_signal)
static void encode_reply(mig_reply_error_t *reply, mach_msg_header_t *hdr, int code)
struct _exc_msg exc_msg

References dbg, encode_reply(), eprintf, ex, _exception_info::exception_port, handle_dead_notify(), handle_exception_message(), msg, RZ_DEBUG_REASON_DEAD, RZ_DEBUG_REASON_ERROR, RZ_DEBUG_REASON_MACH_RCV_INTERRUPTED, RZ_DEBUG_REASON_UNKNOWN, rz_debug_reg_get(), RZ_LOG_ERROR, rz_return_val_if_fail, rz_debug_t::stopaddr, and validate_mach_message().

Referenced by xnu_attach(), and xnu_wait().