Rizin
unix-like reverse engineering framework and cli tools
xnu_debug.h File Reference
#include <rz_util/rz_log.h>
#include <rz_debug.h>
#include <sys/ptrace.h>
#include <sys/proc_info.h>
#include <libproc.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <mach/exception_types.h>
#include <mach/mach_init.h>
#include <mach/mach_port.h>
#include <mach/mach_interface.h>
#include <mach/mach_traps.h>
#include <mach/mach_types.h>
#include <mach/mach_error.h>
#include <mach/task.h>
#include <mach/task_info.h>
#include <mach/thread_act.h>
#include <mach/thread_info.h>
#include <mach/vm_map.h>
#include <mach-o/loader.h>
#include <mach-o/nlist.h>
#include <errno.h>
#include <unistd.h>
#include <sys/sysctl.h>
#include <sys/fcntl.h>
#include <sys/proc.h>
#include <mach/i386/thread_status.h>
#include <sys/ucontext.h>
#include <mach/i386/_structs.h>

Go to the source code of this file.

Classes

struct  coredump_thread_state_flavor_t
 
struct  tir_t
 

Macros

#define LOG_MACH_ERROR(name, rc)
 
#define HAS_LIBPROC
 
#define ADDR   "%8x"
 
#define HEADER_SIZE   0x1000
 
#define IMAGE_OFFSET   0x201000
 
#define KERNEL_LOWER   0x80000000
 
#define REG_PC   ((dbg->bits == RZ_SYS_BITS_64) ? 16 : 10)
 
#define REG_FL   ((dbg->bits == RZ_SYS_BITS_64) ? 17 : 9)
 
#define REG_SP   (7)
 
#define MAX_TSTATE_FLAVORS   10
 
#define DEFAULT_COREFILE_DEST   "core.%u"
 
#define RZ_DEBUG_REASON_MACH_RCV_INTERRUPTED   -2
 

Functions

task_t pid_to_task (int pid)
 
int xnu_get_vmmap_entries_for_pid (pid_t pid)
 
char * xnu_corefile_default_location (void)
 
bool xnu_generate_corefile (RzDebug *dbg, RzBuffer *dest)
 
int xnu_reg_read (RzDebug *dbg, int type, ut8 *buf, int size)
 
int xnu_reg_write (RzDebug *dgb, int type, const ut8 *buf, int size)
 
char * xnu_reg_profile (RzDebug *dbg)
 
int xnu_attach (RzDebug *dbg, int pid)
 
bool xnu_step (RzDebug *dbg)
 
int xnu_detach (RzDebug *dbg, int pid)
 
int xnu_stop (RzDebug *dbg, int pid)
 
int xnu_continue (RzDebug *dbg, int pid, int tid, int sig)
 
RzDebugMapxnu_map_alloc (RzDebug *dbg, ut64 addr, int size)
 
int xnu_map_dealloc (RzDebug *dbg, ut64 addr, int size)
 
int xnu_map_protect (RzDebug *dbg, ut64 addr, int size, int perms)
 
int xnu_init (void)
 
int xnu_wait (RzDebug *dbg, int pid)
 
RzDebugPidxnu_get_pid (int pid)
 
RzListxnu_dbg_maps (RzDebug *dbg, int only_modules)
 
RzListxnu_thread_list (RzDebug *dbg, int pid, RzList *list)
 
RzDebugInfoxnu_info (RzDebug *dbg, const char *arg)
 

Macro Definition Documentation

◆ ADDR

#define ADDR   "%8x"

Definition at line 119 of file xnu_debug.h.

◆ DEFAULT_COREFILE_DEST

#define DEFAULT_COREFILE_DEST   "core.%u"

Definition at line 260 of file xnu_debug.h.

◆ HAS_LIBPROC

#define HAS_LIBPROC

Definition at line 49 of file xnu_debug.h.

◆ HEADER_SIZE

#define HEADER_SIZE   0x1000

Definition at line 120 of file xnu_debug.h.

◆ IMAGE_OFFSET

#define IMAGE_OFFSET   0x201000

Definition at line 121 of file xnu_debug.h.

◆ KERNEL_LOWER

#define KERNEL_LOWER   0x80000000

Definition at line 122 of file xnu_debug.h.

◆ LOG_MACH_ERROR

#define LOG_MACH_ERROR (   name,
  rc 
)
Value:
do { \
const char *str = mach_error_string(rc); \
RZ_LOG_ERROR("%s/%s: %s\n", __FUNCTION__, name, str ? str : "(unknown)"); \
} while (0)
Definition: z80asm.h:102

Definition at line 17 of file xnu_debug.h.

◆ MAX_TSTATE_FLAVORS

#define MAX_TSTATE_FLAVORS   10

Definition at line 259 of file xnu_debug.h.

◆ REG_FL

#define REG_FL   ((dbg->bits == RZ_SYS_BITS_64) ? 17 : 9)

Definition at line 129 of file xnu_debug.h.

◆ REG_PC

#define REG_PC   ((dbg->bits == RZ_SYS_BITS_64) ? 16 : 10)

Definition at line 128 of file xnu_debug.h.

◆ REG_SP

#define REG_SP   (7)

Definition at line 130 of file xnu_debug.h.

◆ RZ_DEBUG_REASON_MACH_RCV_INTERRUPTED

#define RZ_DEBUG_REASON_MACH_RCV_INTERRUPTED   -2

Definition at line 261 of file xnu_debug.h.

Function Documentation

◆ pid_to_task()

task_t pid_to_task ( int  pid)

Definition at line 498 of file xnu_debug.c.

498  {
499  static int old_pid = -1;
500  kern_return_t kr;
501  task_t task = -1;
502  int err;
503  /* it means that we are done with the task*/
504  if (task_dbg != 0 && old_pid == pid) {
505  return task_dbg;
506  }
507  if (task_dbg != 0 && old_pid != pid) {
508  // we changed the process pid so deallocate a ref from the old_task
509  // since we are going to get a new task
510  kr = mach_port_deallocate(mach_task_self(), task_dbg);
511  if (kr != KERN_SUCCESS) {
512  eprintf("pid_to_task: fail to deallocate port\n");
513  /* ignore on purpose to not break process reload: ood */
514  // return 0;
515  }
516  }
517  err = task_for_pid(mach_task_self(), (pid_t)pid, &task);
518  if ((err != KERN_SUCCESS) || !MACH_PORT_VALID(task)) {
520  if (task == 0) {
521  task = task_for_pid_ios9pangu(pid);
522  if (task != MACH_PORT_NULL) {
523  if (pid != -1) {
524  RZ_LOG_ERROR("Failed to get task %d for pid %d.\n",
525  (int)task, (int)pid);
526  RZ_LOG_ERROR("Reason: 0x%x: %s\n", err, rz_str_get_null(mach_error_string(err)));
527  }
528  eprintf("You probably need to run as root\n");
529  return 0;
530  }
531  }
532  }
533  old_pid = pid;
534  task_dbg = task;
535  return task;
536 }
static bool err
Definition: armass.c:435
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
#define eprintf(x, y...)
Definition: rlcc.c:7
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
static const char * rz_str_get_null(const char *str)
Definition: rz_str.h:190
int pid_t
Definition: sftypes.h:38
static task_t task_for_pid_workaround(int Pid)
Definition: xnu_debug.c:57
static task_t task_dbg
Definition: xnu_debug.c:18
static task_t task_for_pid_ios9pangu(int pid)
Definition: xnu_debug.c:102

References eprintf, err, pid, RZ_LOG_ERROR, rz_str_get_null(), task_dbg, task_for_pid_ios9pangu(), and task_for_pid_workaround().

Referenced by rz_xnu_get_cur_thread(), rz_xnu_update_thread_list(), validate_mach_message(), xnu_continue(), xnu_create_exception_thread(), xnu_dbg_maps(), xnu_dbg_modules(), xnu_generate_corefile(), xnu_get_vmmap_entries_for_pid(), xnu_map_protect(), xnu_restore_exception_ports(), xnu_step(), and xnu_stop().

◆ xnu_attach()

int xnu_attach ( RzDebug dbg,
int  pid 
)

Definition at line 133 of file xnu_debug.c.

133  {
134  dbg->pid = pid;
135  // First start listening to exceptions, which will also deliver signals to us
137  RZ_LOG_ERROR("Failed to start listening to mach exceptions");
138  return -1;
139  }
140 
141  // Then do the actual attach.
142  int r = rz_debug_ptrace(dbg, PT_ATTACHEXC, pid, 0, 0);
143  if (r < 0) {
144  perror("ptrace(PT_ATTACHEXC)");
145  RZ_LOG_ERROR("Failed to attach to process");
146  return -1;
147  }
148 
149  // PT_ATTACHEXC will cause a SIGSTOP in the debuggee, so wait for it
150  // Our signal handler will also suspend the task, so no need to call xnu_stop if successful
151  RzDebugReasonType reas = xnu_wait_for_exception(dbg, pid, 1000, true);
152  if (reas != RZ_DEBUG_REASON_SIGNAL || dbg->reason.signum != SIGSTOP) {
153  RZ_LOG_ERROR("SIGSTOP from PT_ATTACHEXC not observed");
154  xnu_stop(dbg, pid);
155  }
156 
157  return pid;
158 }
#define r
Definition: crypto_rc6.c:12
RzDebug * dbg
Definition: desil.c:30
RzDebugReasonType
Definition: rz_debug.h:89
@ RZ_DEBUG_REASON_SIGNAL
Definition: rz_debug.h:92
RzDebugReason reason
Definition: rz_debug.h:276
int xnu_stop(RzDebug *dbg, int pid)
Definition: xnu_debug.c:194
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)

References dbg, rz_debug_t::pid, pid, r, rz_debug_t::reason, RZ_DEBUG_REASON_SIGNAL, RZ_LOG_ERROR, rz_debug_reason_t::signum, xnu_create_exception_thread(), xnu_stop(), and xnu_wait_for_exception().

◆ xnu_continue()

int xnu_continue ( RzDebug dbg,
int  pid,
int  tid,
int  sig 
)

Definition at line 227 of file xnu_debug.c.

227  {
228  task_t task = pid_to_task(pid);
229  if (!task) {
230  return false;
231  }
232  // TODO free refs count threads
234  if (!th) {
235  eprintf("failed to get thread in xnu_continue\n");
236  return false;
237  }
238  // disable trace bit if enable
239  if (th->stepping) {
240  if (!xnu_clear_trace_bit(dbg, th)) {
241  eprintf("error clearing trace bit in xnu_continue\n");
242  return false;
243  }
244  }
245  kern_return_t kr = task_resume(task);
246  if (kr != KERN_SUCCESS) {
247  eprintf("xnu_continue: Warning: Failed to resume task\n");
248  }
249  return true;
250 }
task_t pid_to_task(int pid)
Definition: xnu_debug.c:498
RZ_IPI xnu_thread_t * rz_xnu_get_thread(RzDebug *dbg, int tid)
Definition: xnu_threads.c:378
RZ_IPI thread_t rz_xnu_get_cur_thread(RzDebug *dbg)
Definition: xnu_threads.c:402
static bool xnu_clear_trace_bit(RzDebug *dbg, xnu_thread_t *th)
Definition: xnu_threads.h:114

References dbg, eprintf, pid, pid_to_task(), rz_xnu_get_cur_thread(), rz_xnu_get_thread(), _xnu_thread::stepping, and xnu_clear_trace_bit().

◆ xnu_corefile_default_location()

char* xnu_corefile_default_location ( void  )

◆ xnu_dbg_maps()

RzList* xnu_dbg_maps ( RzDebug dbg,
int  only_modules 
)

Definition at line 1225 of file xnu_debug.c.

1225  {
1226  // bool contiguous = false;
1227  // ut32 oldprot = UT32_MAX;
1228  // ut32 oldmaxprot = UT32_MAX;
1229  char buf[1024];
1230  char module_name[MAXPATHLEN];
1231  mach_vm_address_t address = MACH_VM_MIN_ADDRESS;
1232  mach_vm_size_t size = (mach_vm_size_t)0;
1233  mach_vm_size_t osize = (mach_vm_size_t)0;
1234  natural_t depth = 0;
1235  int tid = dbg->pid;
1236  task_t task = pid_to_task(tid);
1237  RzDebugMap *mr = NULL;
1238  int i = 0;
1239 
1240  if (!task) {
1241  return NULL;
1242  }
1244  if (only_modules) {
1245  return modules;
1246  }
1247 #if __arm64__ || __aarch64__
1248  size = osize = 16384;
1249 #else
1250  size = osize = 4096;
1251 #endif
1252 #if 0
1253  if (dbg->pid == 0) {
1254  vm_address_t base = get_kernel_base (task);
1255  eprintf ("Kernel Base Address: 0x%"PFMT64x"\n", (ut64)base);
1256  return NULL;
1257  }
1258 #endif
1259  RzList *list = rz_list_new();
1260  if (!list) {
1261  return NULL;
1262  }
1263  list->free = (RzListFree)xnu_map_free;
1264  for (;;) {
1265  struct vm_region_submap_info_64 info = { 0 };
1266  mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT_64;
1267  kern_return_t kr = mach_vm_region_recurse(task, &address, &size, &depth,
1268  (vm_region_recurse_info_t)&info, &info_count);
1269  if (kr != KERN_SUCCESS) {
1270  break;
1271  }
1272  if (info.is_submap) {
1273  depth++;
1274  continue;
1275  }
1276  module_name[0] = 0;
1277 #ifndef __POWERPC__
1278  {
1279  int ret = proc_regionfilename(tid, address, module_name,
1280  sizeof(module_name));
1281  module_name[ret] = 0;
1282  }
1283 #endif
1284  if (true) {
1285  char maxperm[32];
1286  char depthstr[32];
1287  if (depth > 0) {
1288  snprintf(depthstr, sizeof(depthstr), "_%d", depth);
1289  } else {
1290  depthstr[0] = 0;
1291  }
1292 
1293  if (info.max_protection != info.protection) {
1294  strcpy(maxperm, rz_str_rwx_i(xwrz_testwx(info.max_protection)));
1295  } else {
1296  maxperm[0] = 0;
1297  }
1298  // XXX: if its shared, it cannot be read?
1299  snprintf(buf, sizeof(buf), "%02x_%s%s%s%s%s%s%s%s",
1300  i, unparse_inheritance(info.inheritance),
1301  info.user_tag ? "_user" : "",
1302  info.is_submap ? "_sub" : "",
1303  "", info.is_submap ? "_submap" : "",
1304  module_name, maxperm, depthstr);
1305  if (!(mr = rz_debug_map_new(buf, address, address + size, xwrz_testwx(info.protection), xwrz_testwx(info.max_protection)))) {
1306  eprintf("Cannot create rz_debug_map_new\n");
1307  break;
1308  }
1309  RzDebugMap *rdm = moduleAt(modules, address);
1310  if (rdm) {
1311  mr->file = strdup(rdm->name);
1312  } else {
1313  if (*module_name) {
1314  mr->file = strdup(module_name);
1315  }
1316  }
1317  if (mr->file) {
1318  if (!strcmp(mr->file, mr->file)) {
1319  mr->name[0] = 0;
1320  const char *slash = rz_str_lchr(mr->file, '/');
1321  if (slash) {
1322  strcpy(mr->name, slash + 1);
1323  }
1324  }
1325  }
1326  i++;
1327  mr->shared = false;
1329  }
1330  if (size < 1) {
1331  eprintf("size error\n");
1332  size = osize;
1333  }
1334  address += size;
1335  size = 0;
1336  }
1337  RzListIter *iter;
1338  RzDebugMap *m;
1339  rz_list_foreach (modules, iter, m) {
1341  if (m2->name && m2->file) {
1342  if (!strcmp(m2->name, m2->file)) {
1343  m2->name[0] = 0;
1344  const char *slash = rz_str_lchr(m2->file, '/');
1345  if (slash) {
1346  strcpy(m2->name, slash + 1);
1347  }
1348  }
1349  }
1350  rz_list_append(list, m2);
1351  }
1352  rz_list_sort(list, cmp);
1354  return list;
1355 }
lzma_index ** i
Definition: index.h:629
RzBinInfo * info(RzBinFile *bf)
Definition: bin_ne.c:86
static int mr(RzAnalysisEsil *esil, ut64 addr, ut8 *buf, int len)
Definition: cmd_analysis.c:471
#define NULL
Definition: cris-opc.c:27
RZ_API RzDebugMap * rz_debug_map_new(char *name, ut64 addr, ut64 addr_end, int perm, int user)
Definition: dmap.c:7
voidpf void uLong size
Definition: ioapi.h:138
voidpf void * buf
Definition: ioapi.h:138
snprintf
Definition: kernel.h:364
static void list(RzEgg *egg)
Definition: rz-gg.c:52
RZ_API RZ_OWN RzList * rz_list_new(void)
Returns a new initialized RzList pointer (free method is not initialized)
Definition: list.c:235
RZ_API void rz_list_sort(RZ_NONNULL RzList *list, RZ_NONNULL RzListComparator cmp)
Sorts via merge sort or via insertion sort a list.
Definition: list.c:743
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
RZ_API void rz_list_free(RZ_NONNULL RzList *list)
Empties the list and frees the list pointer.
Definition: list.c:137
return strdup("=SP r13\n" "=LR r14\n" "=PC r15\n" "=A0 r0\n" "=A1 r1\n" "=A2 r2\n" "=A3 r3\n" "=ZF zf\n" "=SF nf\n" "=OF vf\n" "=CF cf\n" "=SN or0\n" "gpr lr .32 56 0\n" "gpr pc .32 60 0\n" "gpr cpsr .32 64 0 ____tfiae_________________qvczn\n" "gpr or0 .32 68 0\n" "gpr tf .1 64.5 0 thumb\n" "gpr ef .1 64.9 0 endian\n" "gpr jf .1 64.24 0 java\n" "gpr qf .1 64.27 0 sticky_overflow\n" "gpr vf .1 64.28 0 overflow\n" "gpr cf .1 64.29 0 carry\n" "gpr zf .1 64.30 0 zero\n" "gpr nf .1 64.31 0 negative\n" "gpr itc .4 64.10 0 if_then_count\n" "gpr gef .4 64.16 0 great_or_equal\n" "gpr r0 .32 0 0\n" "gpr r1 .32 4 0\n" "gpr r2 .32 8 0\n" "gpr r3 .32 12 0\n" "gpr r4 .32 16 0\n" "gpr r5 .32 20 0\n" "gpr r6 .32 24 0\n" "gpr r7 .32 28 0\n" "gpr r8 .32 32 0\n" "gpr r9 .32 36 0\n" "gpr r10 .32 40 0\n" "gpr r11 .32 44 0\n" "gpr r12 .32 48 0\n" "gpr r13 .32 52 0\n" "gpr r14 .32 56 0\n" "gpr r15 .32 60 0\n" "gpr r16 .32 64 0\n" "gpr r17 .32 68 0\n")
modules
Definition: regress.py:20
void(* RzListFree)(void *ptr)
Definition: rz_list.h:11
RZ_API const char * rz_str_lchr(const char *str, char chr)
Definition: str.c:669
RZ_API const char * rz_str_rwx_i(int rwx)
Definition: str.c:332
#define PFMT64x
Definition: rz_types.h:393
char * name
Definition: rz_debug.h:137
char * file
Definition: rz_debug.h:142
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static const char * unparse_inheritance(vm_inherit_t i)
Definition: xnu_debug.c:1020
static RzDebugMap * moduleAt(RzList *list, ut64 addr)
Definition: xnu_debug.c:1190
static int cmp(const void *_a, const void *_b)
Definition: xnu_debug.c:1201
int proc_regionfilename(int pid, uint64_t address, void *buffer, uint32_t buffersize)
static RzDebugMap * rz_debug_map_clone(RzDebugMap *m)
Definition: xnu_debug.c:1213
static RzList * xnu_dbg_modules(RzDebug *dbg)
Definition: xnu_debug.c:1097
kern_return_t mach_vm_region_recurse(vm_map_t target_task, mach_vm_address_t *address, mach_vm_size_t *size, natural_t *nesting_depth, vm_region_recurse_info_t info, mach_msg_type_number_t *infoCnt)
static void xnu_map_free(RzDebugMap *map)
Definition: xnu_debug.c:1089
vm_address_t get_kernel_base(task_t ___task)
Definition: xnu_debug.c:1037
#define xwrz_testwx(x)
Definition: xnu_debug.c:571

References cmp(), dbg, eprintf, rz_debug_map_t::file, get_kernel_base(), i, info(), list(), regress::m, mach_vm_region_recurse(), moduleAt(), regress::modules, mr(), rz_debug_map_t::name, NULL, PFMT64x, rz_debug_t::pid, pid_to_task(), proc_regionfilename(), rz_debug_map_clone(), rz_debug_map_new(), rz_list_append(), rz_list_free(), rz_list_new(), rz_list_sort(), rz_str_lchr(), rz_str_rwx_i(), snprintf, strdup(), unparse_inheritance(), ut64(), xnu_dbg_modules(), xnu_map_free(), and xwrz_testwx.

◆ xnu_detach()

int xnu_detach ( RzDebug dbg,
int  pid 
)

Definition at line 160 of file xnu_debug.c.

160  {
161  // Not calling PT_DETACH results in a zombie
162  int r = rz_debug_ptrace(dbg, PT_DETACH, pid, 0, 0);
163  if (r < 0) {
164  perror("ptrace(PT_DETACH)");
165  }
166 
167  // do the cleanup necessary
168  // XXX check for errors and ref counts
170  kern_return_t kr = mach_port_deallocate(mach_task_self(), task_dbg);
171  if (kr != KERN_SUCCESS) {
172  eprintf("xnu_detach: failed to deallocate port\n");
173  return false;
174  }
175  // we mark the task as not longer available since we deallocated the ref
176  task_dbg = 0;
178  dbg->threads = NULL;
179  return true;
180 }
#define PT_DETACH
Definition: sftypes.h:622
RzList * threads
Definition: rz_debug.h:251
RZ_IPI bool xnu_restore_exception_ports(int pid)

References dbg, eprintf, NULL, pid, PT_DETACH, r, rz_list_free(), task_dbg, rz_debug_t::threads, and xnu_restore_exception_ports().

◆ xnu_generate_corefile()

bool xnu_generate_corefile ( RzDebug dbg,
RzBuffer dest 
)

Definition at line 827 of file xnu_debug.c.

827  {
828  int error = 0, i;
829  int tstate_size;
830  int segment_count;
831  int command_size;
832  int header_size;
833  size_t mach_header_sz;
834  size_t segment_command_sz;
835  size_t padding_sz;
836  int hoffset;
837 
838  RzBuffer *mem_maps_buffer;
839  vm_offset_t header;
840  ut8 *padding = NULL;
841  RzListIter *iter, *iter2;
842  RzList *threads_list;
843  xnu_thread_t *thread;
844  task_t task = pid_to_task(dbg->pid);
846  tir_t tir;
847 
848  mem_maps_buffer = rz_buf_new_with_bytes(NULL, 0);
849 
850  get_mach_header_sizes(&mach_header_sz, &segment_command_sz);
851  (void)task_suspend(task);
852  threads_list = xnu_thread_list(dbg, dbg->pid, rz_list_new());
853  xnu_dealloc_threads(threads_list);
854 
855  segment_count = xnu_get_vmmap_entries_for_pid(dbg->pid);
856 
857  memcpy(thread_flavor_array, &flavors, sizeof(thread_flavor_array));
858  tstate_size = 0;
859 
860  for (i = 0; i < coredump_nflavors; i++) {
861  tstate_size += sizeof(coredump_thread_state_flavor_t) +
862  (flavors[i].count * sizeof(int));
863  }
864 
865  command_size = COMMAND_SIZE(segment_count, segment_command_sz,
866  rz_list_length(threads_list), tstate_size);
867  header_size = command_size + mach_header_sz; // XXX: Add here the round_page() ?
868  header = (vm_offset_t)calloc(1, header_size);
869  xnu_build_corefile_header(header, segment_count,
870  rz_list_length(threads_list), command_size, dbg->pid);
871 
872  if (!dbg->maps) {
873  perror("There are not loaded maps");
874  }
875  if (xnu_write_mem_maps_to_buffer(mem_maps_buffer, dbg->maps, round_page(header_size),
876  header, mach_header_sz, segment_command_sz, &hoffset) < 0) {
877  eprintf("There was an error while writing the memory maps");
878  error = false;
879  goto cleanup;
880  }
881 
882  tir.header = header;
883  tir.hoffset = hoffset;
884  tir.flavors = flavors;
885  tir.tstate_size = tstate_size;
886 
887  rz_list_foreach_safe (threads_list, iter, iter2, thread) {
888  xnu_collect_thread_state(thread->port, &tir);
889  }
890  xnu_dealloc_threads(threads_list);
891 
892  rz_buf_append_bytes(dest, (const ut8 *)header, header_size);
893  padding_sz = round_page(header_size) - header_size;
894  padding = (ut8 *)calloc(1, padding_sz);
895  rz_buf_append_bytes(dest, (const ut8 *)padding, padding_sz);
896  rz_buf_append_buf(dest, mem_maps_buffer);
897 
898 cleanup:
899  // if (corefile_fd > 0) close (corefile_fd);
900  rz_buf_free(mem_maps_buffer);
901  free((void *)header);
902  free((void *)padding);
903  rz_list_free(threads_list);
904  return !error;
905 }
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void count
Definition: sflib.h:98
void cleanup(void)
Definition: enough.c:244
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
uint8_t ut8
Definition: lh5801.h:11
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
RZ_API ut32 rz_list_length(RZ_NONNULL const RzList *list)
Returns the length of the list.
Definition: list.c:109
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
char * dest
Definition: lz4.h:697
#define header(is_bt, len_min, ret_op)
RZ_API bool rz_buf_append_bytes(RZ_NONNULL RzBuffer *b, RZ_NONNULL const ut8 *buf, ut64 len)
Append an array of bytes to the buffer.
Definition: buf.c:732
RZ_API void rz_buf_free(RzBuffer *b)
Free all internal data hold by the buffer and the buffer.
Definition: buf.c:1253
RZ_API bool rz_buf_append_buf(RZ_NONNULL RzBuffer *b, RZ_NONNULL RzBuffer *a)
Append the content of the buffer a to the buffer b.
Definition: buf.c:685
RZ_API RZ_OWN RzBuffer * rz_buf_new_with_bytes(RZ_NULLABLE RZ_BORROW const ut8 *bytes, ut64 len)
Creates a new buffer with a bytes array.
Definition: buf.c:465
thread_t port
Definition: xnu_threads.h:51
RzList * maps
Definition: rz_debug.h:306
int hoffset
Definition: xnu_debug.h:265
coredump_thread_state_flavor_t * flavors
Definition: xnu_debug.h:267
int tstate_size
Definition: xnu_debug.h:266
vm_offset_t header
Definition: xnu_debug.h:264
void error(const char *msg)
Definition: untgz.c:593
static int xnu_write_mem_maps_to_buffer(RzBuffer *buffer, RzList *mem_maps, int start_offset, vm_offset_t header, int header_end, int segment_command_sz, int *hoffset_out)
Definition: xnu_debug.c:668
static void xnu_collect_thread_state(thread_t port, void *tirp)
Definition: xnu_debug.c:777
int xnu_get_vmmap_entries_for_pid(pid_t pid)
Definition: xnu_debug.c:538
static void get_mach_header_sizes(size_t *mach_header_sz, size_t *segment_command_sz)
Definition: xnu_debug.c:576
static int xnu_dealloc_threads(RzList *threads)
Definition: xnu_debug.c:644
RzList * xnu_thread_list(RzDebug *dbg, int pid, RzList *list)
Definition: xnu_debug.c:453
#define COMMAND_SIZE(segment_count, segment_command_sz, thread_count, tstate_size)
Definition: xnu_debug.c:572
static void xnu_build_corefile_header(vm_offset_t header, int segment_count, int thread_count, int command_size, pid_t pid)
Definition: xnu_debug.c:620
#define MAX_TSTATE_FLAVORS
Definition: xnu_debug.h:259

References calloc(), cleanup(), COMMAND_SIZE, count, dbg, dest, eprintf, error(), tir_t::flavors, free(), get_mach_header_sizes(), tir_t::header, header, tir_t::hoffset, i, rz_debug_t::maps, MAX_TSTATE_FLAVORS, memcpy(), NULL, rz_debug_t::pid, pid_to_task(), _xnu_thread::port, rz_buf_append_buf(), rz_buf_append_bytes(), rz_buf_free(), rz_buf_new_with_bytes(), rz_list_free(), rz_list_length(), rz_list_new(), tir_t::tstate_size, xnu_build_corefile_header(), xnu_collect_thread_state(), xnu_dealloc_threads(), xnu_get_vmmap_entries_for_pid(), xnu_thread_list(), and xnu_write_mem_maps_to_buffer().

◆ xnu_get_pid()

RzDebugPid* xnu_get_pid ( int  pid)

Definition at line 907 of file xnu_debug.c.

907  {
908  int psnamelen, foo, nargs, mib[3], uid;
909  size_t size, argmax = 4096;
910  char *curr_arg, *start_args, *iter_args, *end_args;
911  char *procargs = NULL;
912  char psname[4096];
913 #if 0
914  /* Get the maximum process arguments size. */
915  mib[0] = CTL_KERN;
916  mib[1] = KERN_ARGMAX;
917  size = sizeof(argmax);
918  if (sysctl (mib, 2, &argmax, &size, NULL, 0) == -1) {
919  eprintf ("sysctl() error on getting argmax\n");
920  return NULL;
921  }
922 #endif
923  uid = uidFromPid(pid);
924 
925  /* Allocate space for the arguments. */
926  procargs = (char *)malloc(argmax);
927  if (!procargs) {
928  eprintf("getcmdargs(): insufficient memory for procargs %d\n",
929  (int)(size_t)argmax);
930  return NULL;
931  }
932 
933  /*
934  * Make a sysctl() call to get the raw argument space of the process.
935  */
936  mib[0] = CTL_KERN;
937  mib[1] = KERN_PROCARGS2;
938  mib[2] = pid;
939 
940  size = argmax;
941  procargs[0] = 0;
942  if (sysctl(mib, 3, procargs, &size, NULL, 0) == -1) {
943  if (EINVAL == errno) { // invalid == access denied for some reason
944  // eprintf("EINVAL returned fetching argument space\n");
945  free(procargs);
946  return NULL;
947  }
948  eprintf("sysctl(): unspecified sysctl error - %i\n", errno);
949  free(procargs);
950  return NULL;
951  }
952 
953  // copy the number of argument to nargs
954  memcpy(&nargs, procargs, sizeof(nargs));
955  iter_args = procargs + sizeof(nargs);
956  end_args = &procargs[size - 30]; // end of the argument space
957  if (iter_args >= end_args) {
958  eprintf("getcmdargs(): argument length mismatch");
959  free(procargs);
960  return NULL;
961  }
962 
963  // TODO: save the environment variables to envlist as well
964  // Skip over the exec_path and '\0' characters.
965  // XXX: fix parsing
966 #if 0
967  while (iter_args < end_args && *iter_args != '\0') { iter_args++; }
968  while (iter_args < end_args && *iter_args == '\0') { iter_args++; }
969 #endif
970  if (iter_args == end_args) {
971  free(procargs);
972  return NULL;
973  }
974  curr_arg = iter_args;
975  start_args = iter_args; // reset start position to beginning of cmdline
976  foo = 1;
977  *psname = 0;
978  psnamelen = 0;
979  while (iter_args < end_args && nargs > 0) {
980  if (*iter_args++ == '\0') {
981  int alen = strlen(curr_arg);
982  if (foo) {
983  memcpy(psname, curr_arg, alen + 1);
984  foo = 0;
985  } else {
986  psname[psnamelen] = ' ';
987  memcpy(psname + psnamelen + 1, curr_arg, alen + 1);
988  }
989  psnamelen += alen;
990  // printf("arg[%i]: %s\n", iter_args, curr_arg);
991  /* Fetch next argument */
992  curr_arg = iter_args;
993  nargs--;
994  }
995  }
996 #if 1
997  /*
998  * curr_arg position should be further than the start of the argspace
999  * and number of arguments should be 0 after iterating above. Otherwise
1000  * we had an empty argument space or a missing terminating \0 etc.
1001  */
1002  if (curr_arg == start_args || nargs > 0) {
1003  psname[0] = 0;
1004  // eprintf ("getcmdargs(): argument parsing failed");
1005  free(procargs);
1006  return NULL;
1007  }
1008 #endif
1009  return rz_debug_pid_new(psname, pid, uid, 's', 0); // XXX 's' ??, 0?? must set correct values
1010 }
static RzMain foo[]
Definition: main.c:11
void * malloc(size_t size)
Definition: malloc.c:123
RZ_API RzDebugPid * rz_debug_pid_new(const char *path, int pid, int uid, char status, ut64 pc)
Definition: pid.c:6
#define EINVAL
Definition: sftypes.h:132
static uid_t uidFromPid(pid_t pid)
Definition: xnu_debug.c:810

References EINVAL, eprintf, foo, free(), malloc(), memcpy(), cmd_descs_generate::nargs, NULL, pid, rz_debug_pid_new(), and uidFromPid().

◆ xnu_get_vmmap_entries_for_pid()

int xnu_get_vmmap_entries_for_pid ( pid_t  pid)

Definition at line 538 of file xnu_debug.c.

538  {
539  task_t task = pid_to_task(pid);
540  kern_return_t kr = KERN_SUCCESS;
541  vm_address_t address = 0;
542  vm_size_t size = 0;
543  int n = 1;
544 
545  for (;;) {
546  mach_msg_type_number_t count;
547  struct vm_region_submap_info_64 info;
548  ut32 nesting_depth;
549 
550  count = VM_REGION_SUBMAP_INFO_COUNT_64;
551  kr = vm_region_recurse_64(task, &address, &size, &nesting_depth,
552  (vm_region_info_64_t)&info, &count);
553  if (kr == KERN_INVALID_ADDRESS) {
554  break;
555  }
556  if (kr) {
557  mach_error("vm_region:", kr);
558  break;
559  }
560  if (info.is_submap) {
561  nesting_depth++;
562  } else {
563  address += size;
564  n++;
565  }
566  }
567 
568  return n;
569 }
uint32_t ut32
int n
Definition: mipsasm.c:19

References count, info(), n, pid, and pid_to_task().

Referenced by xnu_generate_corefile().

◆ xnu_info()

RzDebugInfo* xnu_info ( RzDebug dbg,
const char *  arg 
)

Definition at line 397 of file xnu_debug.c.

397  {
398  struct kinfo_proc kp; // XXX This need to be freed?
399  int kinfo_proc_error = 0;
401  if (!rdi)
402  return NULL;
403 
404  kinfo_proc_error = xnu_get_kinfo_proc(dbg->pid, &kp);
405 
406  if (kinfo_proc_error) {
407  eprintf("Error while querying the process info to sysctl\n");
408  return NULL;
409  }
410  rdi->status = RZ_DBG_PROC_SLEEP; // TODO: Fix this w/o libproc ?
411  rdi->pid = dbg->pid;
412  rdi->tid = dbg->tid;
413  rdi->uid = kp.kp_eproc.e_ucred.cr_uid;
414  rdi->gid = kp.kp_eproc.e_ucred.cr_gid;
415 #ifdef HAS_LIBPROC
416  struct proc_bsdinfo proc;
417  rdi->status = 0;
418  char file_path[MAXPATHLEN] = { 0 };
419  int file_path_len;
420  file_path_len = proc_pidpath(rdi->pid, file_path, sizeof(file_path));
421  if (file_path_len > 0) {
422  file_path[file_path_len] = 0;
423  rdi->exe = strdup(file_path);
424  }
425  if (proc_pidinfo(rdi->pid, PROC_PIDTBSDINFO, 0,
426  &proc, PROC_PIDTBSDINFO_SIZE) == PROC_PIDTBSDINFO_SIZE) {
427  if ((proc.pbi_flags & PROC_FLAG_TRACED) != 0) {
428  rdi->status = RZ_DBG_PROC_RUN;
429  }
430  if ((proc.pbi_flags & PROC_FLAG_INEXIT) != 0) {
431  rdi->status = RZ_DBG_PROC_STOP;
432  }
433  }
434 #endif
435  return rdi;
436 }
@ RZ_DBG_PROC_RUN
Definition: rz_debug.h:61
@ RZ_DBG_PROC_STOP
Definition: rz_debug.h:60
@ RZ_DBG_PROC_SLEEP
Definition: rz_debug.h:62
#define RZ_NEW0(x)
Definition: rz_types.h:284
struct Proc * proc
static int xnu_get_kinfo_proc(int pid, struct kinfo_proc *kp)
Definition: xnu_debug.c:381

References dbg, eprintf, NULL, rz_debug_t::pid, proc, rdi, RZ_DBG_PROC_RUN, RZ_DBG_PROC_SLEEP, RZ_DBG_PROC_STOP, RZ_NEW0, strdup(), rz_debug_t::tid, and xnu_get_kinfo_proc().

◆ xnu_init()

int xnu_init ( void  )

◆ xnu_map_alloc()

RzDebugMap* xnu_map_alloc ( RzDebug dbg,
ut64  addr,
int  size 
)

Definition at line 346 of file xnu_debug.c.

346  {
347  kern_return_t ret;
348  ut8 *base = (ut8 *)addr;
350  bool anywhere = !VM_FLAGS_ANYWHERE;
351  if (!th) {
352  return NULL;
353  }
354  if (addr == -1) {
355  anywhere = VM_FLAGS_ANYWHERE;
356  }
357  ret = vm_allocate(th->port, (vm_address_t *)&base,
358  (vm_size_t)size,
359  anywhere | VM_MAKE_TAG(DEBUG_MAP_TAG_ID));
360  if (ret != KERN_SUCCESS) {
361  eprintf("vm_allocate failed\n");
362  return NULL;
363  }
364  rz_debug_map_sync(dbg); // update process memory maps
365  return rz_debug_map_get(dbg, (ut64)base);
366 }
RZ_API RzDebugMap * rz_debug_map_get(RzDebug *dbg, ut64 addr)
Definition: dmap.c:65
RZ_API bool rz_debug_map_sync(RzDebug *dbg)
Definition: dmap.c:33
#define DEBUG_MAP_TAG_ID
Definition: xnu_debug.c:31
static int addr
Definition: z80asm.c:58

References addr, dbg, DEBUG_MAP_TAG_ID, eprintf, NULL, _xnu_thread::port, rz_debug_map_get(), rz_debug_map_sync(), rz_xnu_get_thread(), rz_debug_t::tid, and ut64().

◆ xnu_map_dealloc()

int xnu_map_dealloc ( RzDebug dbg,
ut64  addr,
int  size 
)

Definition at line 368 of file xnu_debug.c.

368  {
370  if (!th) {
371  return false;
372  }
373  mach_error_t ret = vm_deallocate(th->port, (vm_address_t)addr, (vm_size_t)size);
374  if (ret != KERN_SUCCESS) {
375  LOG_MACH_ERROR("vm_deallocate", ret);
376  return false;
377  }
378  return true;
379 }
#define LOG_MACH_ERROR(name, rc)
Definition: xnu_debug.h:17

References addr, dbg, LOG_MACH_ERROR, _xnu_thread::port, rz_xnu_get_thread(), and rz_debug_t::tid.

◆ xnu_map_protect()

int xnu_map_protect ( RzDebug dbg,
ut64  addr,
int  size,
int  perms 
)

Definition at line 486 of file xnu_debug.c.

486  {
487  task_t task = pid_to_task(dbg->tid);
488 #define xwrz_testwx(x) ((x & 1) << 2) | (x & 2) | ((x & 4) >> 2)
489  int xnu_perms = xwrz_testwx(perms);
490  mach_error_t ret = mach_vm_protect(task, (vm_address_t)addr, (vm_size_t)size, (boolean_t)0, xnu_perms); // VM_PROT_COPY | perms);
491  if (ret != KERN_SUCCESS) {
492  LOG_MACH_ERROR("mach_vm_protect", ret);
493  return false;
494  }
495  return true;
496 }

References addr, dbg, LOG_MACH_ERROR, pid_to_task(), rz_debug_t::tid, and xwrz_testwx.

◆ xnu_reg_profile()

char* xnu_reg_profile ( RzDebug dbg)

Definition at line 252 of file xnu_debug.c.

252  {
253 #if __i386__ || __x86_64__
254  if (dbg->bits & RZ_SYS_BITS_32) {
255 #include "reg/darwin-x86.h"
256  } else if (dbg->bits == RZ_SYS_BITS_64) {
257 #include "reg/darwin-x64.h"
258  } else {
259  eprintf("invalid bit size\n");
260  return NULL;
261  }
262 #elif __POWERPC__
263 #include "reg/darwin-ppc.h"
264 #elif __APPLE__ && (__aarch64__ || __arm64__ || __arm__)
265  if (dbg->bits == RZ_SYS_BITS_64) {
266 #include "reg/darwin-arm64.h"
267  } else {
268 #include "reg/darwin-arm.h"
269  }
270 #else
271 #error "Unsupported Apple architecture"
272 #endif
273 }
@ RZ_SYS_BITS_32
Definition: rz_sys.h:20
@ RZ_SYS_BITS_64
Definition: rz_sys.h:21
int bits
Definition: rz_debug.h:243

References rz_debug_t::bits, dbg, eprintf, NULL, RZ_SYS_BITS_32, and RZ_SYS_BITS_64.

◆ xnu_reg_read()

int xnu_reg_read ( RzDebug dbg,
int  type,
ut8 buf,
int  size 
)

Definition at line 315 of file xnu_debug.c.

315  {
317  if (!th) {
318  return 0;
319  }
320  switch (type) {
321  case RZ_REG_TYPE_SEG:
322  case RZ_REG_TYPE_FLG:
323  case RZ_REG_TYPE_GPR:
324  if (!rz_xnu_thread_get_gpr(dbg, th)) {
325  return 0;
326  }
327  break;
328  case RZ_REG_TYPE_DRX:
329  if (!rz_xnu_thread_get_drx(dbg, th)) {
330  return 0;
331  }
332  break;
333  default:
334  return 0;
335  }
336  if (th->state) {
337  int rsz = RZ_MIN(th->state_size, size);
338  if (rsz > 0) {
339  memcpy(buf, th->state, rsz);
340  return rsz;
341  }
342  }
343  return 0;
344 }
int type
Definition: mipsasm.c:17
@ RZ_REG_TYPE_SEG
Definition: rz_reg.h:28
@ RZ_REG_TYPE_GPR
Definition: rz_reg.h:21
@ RZ_REG_TYPE_FLG
Definition: rz_reg.h:27
@ RZ_REG_TYPE_DRX
Definition: rz_reg.h:22
#define RZ_MIN(x, y)
ut32 state_size
Definition: xnu_threads.h:57
void * state
Definition: xnu_threads.h:56
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

References dbg, memcpy(), RZ_MIN, RZ_REG_TYPE_DRX, RZ_REG_TYPE_FLG, RZ_REG_TYPE_GPR, RZ_REG_TYPE_SEG, rz_xnu_get_cur_thread(), rz_xnu_get_thread(), rz_xnu_thread_get_drx(), rz_xnu_thread_get_gpr(), _xnu_thread::state, _xnu_thread::state_size, and type.

◆ xnu_reg_write()

int xnu_reg_write ( RzDebug dgb,
int  type,
const ut8 buf,
int  size 
)

Definition at line 279 of file xnu_debug.c.

279  {
280  bool ret;
282  if (!th) {
283  return 0;
284  }
285  switch (type) {
286  case RZ_REG_TYPE_DRX:
287 #if __x86_64__
288  memcpy(&th->drx.uds.ds32, buf, RZ_MIN(size, sizeof(th->drx)));
289 #elif __i386__
290  memcpy(&th->drx.uds.ds64, buf, RZ_MIN(size, sizeof(th->drx)));
291 #elif __arm64 || __aarch64
292  if (dbg->bits == RZ_SYS_BITS_64) {
293  memcpy(&th->debug.drx64, buf, RZ_MIN(size, sizeof(th->debug.drx64)));
294  } else {
295  memcpy(&th->debug.drx32, buf, RZ_MIN(size, sizeof(th->debug.drx32)));
296  }
297 #elif __arm || __armv7 || __arm__ || __armv7__
298  memcpy(&th->debug.drx, buf, RZ_MIN(size, sizeof(th->debug.drx)));
299 #endif
300  ret = rz_xnu_thread_set_drx(dbg, th);
301  break;
302  default:
303  // th->gpr has a header and the state we should copy on the state only
304 #if __POWERPC__
305 #warning TODO powerpc support here
306 #else
307  memcpy(&th->gpr.uts, buf, RZ_MIN(size, sizeof(th->gpr.uts)));
308 #endif
309  ret = rz_xnu_thread_set_gpr(dbg, th);
310  break;
311  }
312  return ret;
313 }
RZ_REG_T gpr
Definition: xnu_threads.h:55
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

References rz_debug_t::bits, dbg, _xnu_thread::gpr, memcpy(), RZ_MIN, RZ_REG_TYPE_DRX, RZ_SYS_BITS_64, rz_xnu_get_cur_thread(), rz_xnu_get_thread(), rz_xnu_thread_set_drx(), rz_xnu_thread_set_gpr(), and type.

◆ xnu_step()

bool xnu_step ( RzDebug dbg)

Definition at line 112 of file xnu_debug.c.

112  {
113  // we must find a way to get the current thread not just the first one
114  task_t task = pid_to_task(dbg->pid);
115  if (!task) {
116  eprintf("step failed on task %d for pid %d\n", task, dbg->tid);
117  return false;
118  }
120  if (!th) {
121  return false;
122  }
123  int ret = xnu_set_trace_bit(dbg, th);
124  if (!ret) {
125  eprintf("xnu_step modificy_trace_bit error\n");
126  return false;
127  }
128  th->stepping = true;
129  task_resume(task);
130  return ret;
131 }
static bool xnu_set_trace_bit(RzDebug *dbg, xnu_thread_t *th)
Definition: xnu_threads.h:111

References dbg, eprintf, rz_debug_t::pid, pid_to_task(), rz_xnu_get_cur_thread(), rz_xnu_get_thread(), _xnu_thread::stepping, rz_debug_t::tid, and xnu_set_trace_bit().

◆ xnu_stop()

int xnu_stop ( RzDebug dbg,
int  pid 
)

Definition at line 194 of file xnu_debug.c.

194  {
195  task_t task = pid_to_task(pid);
196  if (!task) {
197  return false;
198  }
199 
200  int suspend_count = task_suspend_count(task);
201  if (suspend_count == -1) {
202  return false;
203  }
204  if (suspend_count == 1) {
205  // Hopefully _we_ suspended it.
206  return true;
207  }
208  if (suspend_count > 1) {
209  // This is unexpected.
210  return false;
211  }
212 
213  kern_return_t kr = task_suspend(task);
214  if (kr != KERN_SUCCESS) {
215  eprintf("failed to suspend task\n");
216  return false;
217  }
218 
219  suspend_count = task_suspend_count(task);
220  if (suspend_count != 1) {
221  // This is unexpected.
222  return false;
223  }
224  return true;
225 }
static int task_suspend_count(task_t task)
Definition: xnu_debug.c:182

References eprintf, pid, pid_to_task(), and task_suspend_count().

Referenced by xnu_attach().

◆ xnu_thread_list()

RzList* xnu_thread_list ( RzDebug dbg,
int  pid,
RzList list 
)

Definition at line 453 of file xnu_debug.c.

453  {
454 #if __arm__ || __arm64__ || __aarch_64__
455 #define CPU_PC (dbg->bits == RZ_SYS_BITS_64) ? state.ts_64.__pc : state.ts_32.__pc
456 #elif __POWERPC__
457 #define CPU_PC state.srr0
458 #elif __x86_64__ || __i386__
459 #define CPU_PC (dbg->bits == RZ_SYS_BITS_64) ? state.uts.ts64.__rip : state.uts.ts32.__eip
460 #endif
461  RzListIter *iter;
462  xnu_thread_t *thread;
463  RZ_REG_T state;
466  rz_list_foreach (dbg->threads, iter, thread) {
467  if (!rz_xnu_thread_get_gpr(dbg, thread)) {
468  eprintf("Failed to get gpr registers xnu_thread_list\n");
469  continue;
470  }
471  thread->state_size = sizeof(thread->gpr);
472  memcpy(&state, &thread->gpr, sizeof(RZ_REG_T));
473  rz_list_append(list, rz_debug_pid_new(thread->name, thread->port, getuid(), 's', CPU_PC));
474  }
475  return list;
476 }
RZ_API RzDebugPid * rz_debug_pid_free(RzDebugPid *pid)
Definition: pid.c:20
char * name
Definition: xnu_threads.h:52
Definition: dis.h:43
RZ_IPI int rz_xnu_update_thread_list(RzDebug *dbg)
Definition: xnu_threads.c:290

References dbg, eprintf, _xnu_thread::gpr, list(), memcpy(), _xnu_thread::name, _xnu_thread::port, rz_debug_pid_free(), rz_debug_pid_new(), rz_list_append(), rz_xnu_thread_get_gpr(), rz_xnu_update_thread_list(), _xnu_thread::state_size, and rz_debug_t::threads.

Referenced by xnu_generate_corefile().

◆ xnu_wait()

int xnu_wait ( RzDebug dbg,
int  pid 
)

Definition at line 108 of file xnu_debug.c.

108  {
109  return xnu_wait_for_exception(dbg, pid, 0, false);
110 }

References dbg, pid, and xnu_wait_for_exception().