Rizin
unix-like reverse engineering framework and cli tools
xnu_excthreads.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2022 Florian Märkl <info@florianmaerkl.de>
2 // SPDX-FileCopyrightText: 2015 alvarofe <alvaro.felipe91@gmail.com>
3 // SPDX-License-Identifier: LGPL-3.0-only
4 
5 // FIXME deallocate all the port when they are not longer needed
6 
7 #include "xnu_debug.h"
8 #include "xnu_threads.h"
9 
10 #if defined __i386__ || __x86_64__ // intel processors
11 
12 /* Set/clear bit 8 (Trap Flag) of the EFLAGS processor control
13  register to enable/disable single-step mode.
14  ENABLE is a boolean, indicating whether to set (1) the Trap Flag
15  or clear it (0). */
16 
17 RZ_IPI bool xnu_modify_trace_bit(RzDebug *dbg, xnu_thread_t *th, int enable) {
18  RZ_REG_T *state;
19  int ret;
20  ret = rz_xnu_thread_get_gpr(dbg, th);
21  if (!ret) {
22  eprintf("error to get gpr registers in trace bit intel\n");
23  return false;
24  }
25  state = (RZ_REG_T *)&th->gpr;
26  if (state->tsh.flavor == x86_THREAD_STATE32) {
27  state->uts.ts32.__eflags = (state->uts.ts32.__eflags &
28  ~0x100UL) |
29  (enable ? 0x100UL : 0);
30  } else if (state->tsh.flavor == x86_THREAD_STATE64) {
31  state->uts.ts64.__rflags = (state->uts.ts64.__rflags &
32  ~0x100UL) |
33  (enable ? 0x100UL : 0);
34  } else {
35  eprintf("Invalid bit size\n");
36  return false;
37  }
38  if (!rz_xnu_thread_set_gpr(dbg, th)) {
39  eprintf("error xnu_thread_set_gpr in modify_trace_bit intel\n");
40  return false;
41  }
42  return true;
43 }
44 
45 #elif __POWERPC__ // ppc processor
46 // XXX poor support at this stage i don't care so much. Once intel and arm done it could be done
47 // TODO add better support for ppc
48 RZ_IPI bool xnu_modify_trace_bit(RzDebug *dbg, void *th, int enable) {
49  return false;
50 }
51 #if 0
52 static bool xnu_modify_trace_bit(RzDebug *dbg, xnu_thread *th, int enable) {
53  return false;
54  RZ_REG_T state;
55  unsigned int state_count = RZ_REG_STATE_SZ;
56  kern_return_t kr;
57  kr = thread_get_state (th->tid, RZ_REG_STATE_T,
58  (thread_state_t)&state, &state_count);
59  if (kr != KERN_SUCCESS) {
60  eprintf ("error modify_trace_bit\n");
61  return false;
62  }
63  state.srr1 = (state.srr1 & ~0x400UL) | (enable ? 0x400UL : 0);
64  kr = thread_set_state (th->tid, RZ_REG_STATE_T,
65  (thread_state_t)&state, state_count);
66  if (kr != KERN_SUCCESS) {
67  eprintf ("Error to set thread state modificy_trace_bit ppc\n");
68  return false;
69  }
70  return true;
71 }
72 #endif
73 
74 #elif __arm || __arm64 || __aarch64 // arm processor
75 
76 // BCR address match type
77 #define BCR_M_IMVA_MATCH ((uint32_t)(0u << 21))
78 #define BCR_M_CONTEXT_ID_MATCH ((uint32_t)(1u << 21))
79 #define BCR_M_IMVA_MISMATCH ((uint32_t)(2u << 21))
80 #define BCR_M_RESERVED ((uint32_t)(3u << 21))
81 
82 // Link a BVR/BCR or WVR/WCR pair to another
83 #define E_ENABLE_LINKING ((uint32_t)(1u << 20))
84 
85 // Byte Address Select
86 #define BAS_IMVA_PLUS_0 ((uint32_t)(1u << 5))
87 #define BAS_IMVA_PLUS_1 ((uint32_t)(1u << 6))
88 #define BAS_IMVA_PLUS_2 ((uint32_t)(1u << 7))
89 #define BAS_IMVA_PLUS_3 ((uint32_t)(1u << 8))
90 #define BAS_IMVA_0_1 ((uint32_t)(3u << 5))
91 #define BAS_IMVA_2_3 ((uint32_t)(3u << 7))
92 #define BAS_IMVA_ALL ((uint32_t)(0xfu << 5))
93 
94 // Break only in privileged or user mode
95 #define S_RSVD ((uint32_t)(0u << 1))
96 #define S_PRIV ((uint32_t)(1u << 1))
97 #define S_USER ((uint32_t)(2u << 1))
98 #define S_PRIV_USER ((S_PRIV) | (S_USER))
99 
100 #define BCR_ENABLE ((uint32_t)(1u))
101 #define WCR_ENABLE ((uint32_t)(1u))
102 
103 // Watchpoint load/store
104 #define WCR_LOAD ((uint32_t)(1u << 3))
105 #define WCR_STORE ((uint32_t)(1u << 4))
106 
107 // Single instruction step
108 // (SS bit in the MDSCR_EL1 register)
109 #define SS_ENABLE ((uint32_t)(1u))
110 
111 #if __arm || __arm__ || __armv7 || __armv7__
112 static bool is_thumb_32(ut16 op) {
113  return (((op & 0xE000) == 0xE000) && (op & 0x1800));
114 }
115 #endif
116 
117 RZ_IPI bool xnu_modify_trace_bit(RzDebug *dbg, xnu_thread_t *th, int enable) {
118  int ret = rz_xnu_thread_get_drx(dbg, th);
119  if (!ret) {
120  eprintf("error to get drx registers modificy_trace_bit arm\n");
121  return false;
122  }
123 #if __arm64 || __arm64__ || __aarch64 || __aarch64__
124  if (th->flavor == ARM_DEBUG_STATE32) {
125  arm_debug_state32_t *state = &th->debug.drx32;
126  if (enable) {
127  state->__mdscr_el1 = state->__mdscr_el1 | SS_ENABLE;
128  } else {
129  state->__mdscr_el1 = state->__mdscr_el1 & ~SS_ENABLE;
130  }
131  } else if (th->flavor == ARM_DEBUG_STATE64) {
132  arm_debug_state64_t *state = &th->debug.drx64;
133  if (enable) {
134  state->__mdscr_el1 = state->__mdscr_el1 | SS_ENABLE;
135  } else {
136  state->__mdscr_el1 = state->__mdscr_el1 & ~SS_ENABLE;
137  }
138  } else
139 #elif __arm || __arm__ || __armv7 || __armv7__
140  if (th->flavor == ARM_DEBUG_STATE) {
141  int i = 0;
142  arm_debug_state_t *state = &th->debug.drx;
143  RZ_REG_T *regs;
144  ret = rz_xnu_thread_get_gpr(dbg, th);
145  if (!ret) {
146  eprintf("error to get gpr register modificy_trace_bit arm\n");
147  return false;
148  }
149  regs = (RZ_REG_T *)&th->gpr;
150  if (enable) {
151  static ut64 chained_address = 0;
152  RzIOBind *bio = &dbg->iob;
153  // set a breakpoint that will stop when the PC doesn't
154  // match the current one
155  // set the current PC as the breakpoint address
156  if (chained_address) {
157  state->__bvr[i] = chained_address & 0xFFFFFFFCu;
158  chained_address = 0;
159  } else {
160  state->__bvr[i] = regs->ts_32.__pc & 0xFFFFFFFCu;
161  }
162  state->__bcr[i] = BCR_M_IMVA_MISMATCH | // stop on
163  // address
164  // mismatch
165  S_USER | // stop only in user mode
166  BCR_ENABLE; // enable this breakpoint
167  if (regs->ts_32.__cpsr & 0x20) {
168  ut16 op;
169  // Thumb breakpoint
170  if (regs->ts_32.__pc & 2)
171  state->__bcr[i] |= BAS_IMVA_2_3;
172  else
173  state->__bcr[i] |= BAS_IMVA_0_1;
174  if (bio->read_at(bio->io, regs->ts_32.__pc, (void *)&op, 2) < 1) {
175  eprintf("Failed to read opcode modify_trace_bit\n");
176  return false;
177  }
178  if (is_thumb_32(op)) {
179  chained_address = regs->ts_32.__pc + 2;
180  } else {
181  // Extend the number of bits to ignore for the mismatch
182  state->__bcr[i] |= BAS_IMVA_ALL;
183  }
184  } else {
185  // ARM breakpoint
186  state->__bcr[i] |= BAS_IMVA_ALL; // Stop when any address bits change
187  }
188  // disable bits
189  for (i = i + 1; i < 16; i++) {
190  // Disable all others
191  state->__bcr[i] = 0;
192  state->__bvr[i] = 0;
193  }
194  } else {
195  if (state->__bcr[i] & BCR_ENABLE) {
196  state->__bvr[i] = 0;
197  state->__bcr[i] = 0;
198  }
199  }
200  } else
201 #endif
202  {
203  eprintf("Bad flavor modificy_trace_bit arm\n");
204  return false;
205  }
206  // set state
207  if (!rz_xnu_thread_set_drx(dbg, th)) {
208  eprintf("error to set drx modificy_trace_bit arm\n");
209  return false;
210  }
211  return true;
212 }
213 
214 #elif __POWERPC__
215 // no need to do this here
216 static int modify_trace_bit(RzDebug *dbg, xnu_thread *th, int enable) {
217  return true;
218 }
219 #else
220 #error "unknown architecture"
221 #endif
222 
223 // TODO: Tuck this into RzDebug; `void *user` seems like a good candidate.
224 static xnu_exception_info ex = { { 0 } };
225 
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 }
247 
248 // TODO review more closely we are failing here
249 static void encode_reply(mig_reply_error_t *reply, mach_msg_header_t *hdr, int code) {
250  mach_msg_header_t *rh = &reply->Head;
251  rh->msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(hdr->msgh_bits), 0);
252  rh->msgh_remote_port = hdr->msgh_remote_port;
253  rh->msgh_size = (mach_msg_size_t)sizeof(mig_reply_error_t);
254  rh->msgh_local_port = MACH_PORT_NULL;
255  rh->msgh_id = hdr->msgh_id + 100;
256  reply->NDR = NDR_record;
257  reply->RetCode = code;
258 }
259 
261  kern_return_t kr;
262 #if __POWERPC__
263  return false;
264 #else
265  /*check if the message is for us*/
266  if (msg->hdr.msgh_local_port != ex.exception_port) {
267  return false;
268  }
269  /*gdb from apple check this so why not us*/
270  if (!(msg->hdr.msgh_bits & MACH_MSGH_BITS_COMPLEX)) {
271  return false;
272  }
273  /*Mach exception we are interested*/
274  // XXX for i386 this id seems to be different
275  if (msg->hdr.msgh_id > 2405 || msg->hdr.msgh_id < 2401) {
276  return false;
277  }
278  /* check descriptors. */
279  if (msg->hdr.msgh_size <
280  sizeof(mach_msg_header_t) + sizeof(mach_msg_body_t) +
281  2 * sizeof(mach_msg_port_descriptor_t) +
282  sizeof(NDR_record_t) + sizeof(exception_type_t) +
283  sizeof(mach_msg_type_number_t) +
284  sizeof(mach_exception_data_t))
285  return false;
286  /* check data representation. */
287  if (msg->NDR.mig_vers != NDR_PROTOCOL_2_0 ||
288  msg->NDR.if_vers != NDR_PROTOCOL_2_0 ||
289  msg->NDR.mig_encoding != NDR_record.mig_encoding ||
290  msg->NDR.int_rep != NDR_record.int_rep ||
291  msg->NDR.char_rep != NDR_record.char_rep ||
292  msg->NDR.float_rep != NDR_record.float_rep) {
293  return false;
294  }
295  if (pid_to_task(dbg->pid) != msg->task.name) {
296  // we receive a exception from an unknown process this could
297  // happen if the child fork, as the created process will inherit
298  // its exception port
299  /*we got new rights to the task, get rid of it.*/
300  kr = mach_port_deallocate(mach_task_self(), msg->task.name);
301  if (kr != KERN_SUCCESS) {
302  eprintf("validate_mach_message: failed to deallocate task port\n");
303  }
304  kr = mach_port_deallocate(mach_task_self(), msg->thread.name);
305  if (kr != KERN_SUCCESS) {
306  eprintf("validate_mach_message2: failed to deallocated task port\n");
307  }
308  return false;
309  }
310  return true;
311 #endif
312 }
313 
315  if (msg->hdr.msgh_id == 0x48) {
316  dbg->pid = -1;
317  return true;
318  }
319  return false;
320 }
321 
322 static int handle_exception_message(RzDebug *dbg, exc_msg *msg, int *ret_code, bool quiet_signal) {
323  int ret = RZ_DEBUG_REASON_UNKNOWN;
324  kern_return_t kr;
325  *ret_code = KERN_SUCCESS;
326  ut64 code = (ut64)msg->code[0] | ((ut64)msg->code[1] << 32);
327  ut64 subcode = (ut64)msg->code[2] | ((ut64)msg->code[3] << 32);
328  switch (msg->exception) {
329  case EXC_BAD_ACCESS:
331  *ret_code = KERN_FAILURE;
332  kr = task_suspend(msg->task.name);
333  if (kr != KERN_SUCCESS) {
334  eprintf("failed to suspend task bad access\n");
335  }
336  eprintf("EXC_BAD_ACCESS\n");
337  break;
338  case EXC_BAD_INSTRUCTION:
340  *ret_code = KERN_FAILURE;
341  kr = task_suspend(msg->task.name);
342  if (kr != KERN_SUCCESS) {
343  eprintf("failed to suspend task bad instruction\n");
344  }
345  eprintf("EXC_BAD_INSTRUCTION\n");
346  break;
347  case EXC_ARITHMETIC:
348  eprintf("EXC_ARITHMETIC\n");
349  break;
350  case EXC_EMULATION:
351  eprintf("EXC_EMULATION\n");
352  break;
353  case EXC_SOFTWARE:
354  // TODO: make these eprintfs RZ_LOG_INFO
355  // Right now we can't because the default log level is < info and the info about the
356  // signal is important to the user.
357  if (!quiet_signal) {
358  eprintf("EXC_SOFTWARE: ");
359  }
360  if (code == EXC_SOFT_SIGNAL) {
361  // standard unix signal
363  dbg->reason.signum = subcode;
364  if (!quiet_signal) {
365  eprintf(" EXC_SOFT_SIGNAL %" PFMT64u, subcode);
366  const char *signame = rz_signal_to_string((int)subcode);
367  if (signame) {
368  eprintf(" = %s", signame);
369  }
370  eprintf("\n");
371  }
372  } else {
373  eprintf("code = 0x%" PFMT64u ", subcode = 0x%" PFMT64u "\n", code, subcode);
374  }
375  // We want to stop and examine when getting signals
376  kr = task_suspend(msg->task.name);
377  if (kr != KERN_SUCCESS) {
378  RZ_LOG_ERROR("Failed to suspend after EXC_SOFTWARE");
379  }
380  break;
381  case EXC_BREAKPOINT:
382  kr = task_suspend(msg->task.name);
383  if (kr != KERN_SUCCESS) {
384  eprintf("failed to suspend task breakpoint\n");
385  }
387  break;
388  default:
389  eprintf("UNKNOWN\n");
390  break;
391  }
392  kr = mach_port_deallocate(mach_task_self(), msg->task.name);
393  if (kr != KERN_SUCCESS) {
394  eprintf("failed to deallocate task port\n");
395  }
396  kr = mach_port_deallocate(mach_task_self(), msg->thread.name);
397  if (kr != KERN_SUCCESS) {
398  eprintf("failed to deallocated task port\n");
399  }
400  return ret;
401 }
402 
409 RZ_IPI RzDebugReasonType xnu_wait_for_exception(RzDebug *dbg, int pid, ut32 timeout_ms, bool quiet_signal) {
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 }
478 
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 }
ut8 op
Definition: 6502dis.c:13
static char * regs[]
Definition: analysis_sh.c:203
#define RZ_IPI
Definition: analysis_wasm.c:11
lzma_index ** i
Definition: index.h:629
uint16_t ut16
uint32_t ut32
RzDebug * dbg
Definition: desil.c:30
RZ_API ut64 rz_debug_reg_get(RzDebug *dbg, const char *name)
Definition: dreg.c:99
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
@ x86_THREAD_STATE64
@ x86_THREAD_STATE32
const char * code
Definition: pal.c:98
#define eprintf(x, y...)
Definition: rlcc.c:7
#define rz_return_val_if_fail(expr, val)
Definition: rz_assert.h:108
RzDebugReasonType
Definition: rz_debug.h:89
@ RZ_DEBUG_REASON_DEAD
Definition: rz_debug.h:90
@ RZ_DEBUG_REASON_ILLEGAL
Definition: rz_debug.h:102
@ RZ_DEBUG_REASON_UNKNOWN
Definition: rz_debug.h:103
@ RZ_DEBUG_REASON_BREAKPOINT
Definition: rz_debug.h:94
@ RZ_DEBUG_REASON_ERROR
Definition: rz_debug.h:104
@ RZ_DEBUG_REASON_SEGFAULT
Definition: rz_debug.h:93
@ RZ_DEBUG_REASON_SIGNAL
Definition: rz_debug.h:92
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
RZ_API const char * rz_signal_to_string(int code)
Definition: signal.c:63
#define PFMT64u
Definition: rz_types.h:395
static struct sockaddr static addrlen static backlog const void msg
Definition: sfsocketcall.h:119
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
RZ_REG_T gpr
Definition: xnu_threads.h:55
Definition: inftree9.h:24
ut64 stopaddr
Definition: rz_debug.h:278
RzDebugReason reason
Definition: rz_debug.h:276
RzIOBind iob
Definition: rz_debug.h:293
RzIOReadAt read_at
Definition: rz_io.h:240
RzIO * io
Definition: rz_io.h:232
Definition: dis.h:43
Definition: dis.c:32
if(dbg->bits==RZ_SYS_BITS_64)
Definition: windows-arm64.h:4
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
task_t pid_to_task(int pid)
Definition: xnu_debug.c:498
#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 xnu_exception_info ex
static int handle_exception_message(RzDebug *dbg, exc_msg *msg, int *ret_code, bool quiet_signal)
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)
RZ_IPI bool xnu_create_exception_thread(RzDebug *dbg)
static void encode_reply(mig_reply_error_t *reply, mach_msg_header_t *hdr, int code)
RZ_IPI bool rz_xnu_thread_set_gpr(RzDebug *dbg, xnu_thread_t *thread)
Definition: xnu_threads.c:130
RZ_IPI bool rz_xnu_thread_set_drx(RzDebug *dbg, xnu_thread_t *thread)
Definition: xnu_threads.c:70
RZ_IPI bool rz_xnu_thread_get_gpr(RzDebug *dbg, xnu_thread_t *thread)
Definition: xnu_threads.c:184
RZ_IPI bool rz_xnu_thread_get_drx(RzDebug *dbg, xnu_thread_t *thread)
Definition: xnu_threads.c:26
#define RETURN_ON_MACH_ERROR(msg, retval)
Definition: xnu_threads.h:33
struct _exc_msg exc_msg
RZ_IPI bool xnu_modify_trace_bit(RzDebug *dbg, xnu_thread_t *th, int enable)