Rizin
unix-like reverse engineering framework and cli tools
xnu_debug.c
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2015-2019 pancake <pancake@nopcode.org>
2 // SPDX-FileCopyrightText: 2015-2019 alvaro_fe <alvaro.felipe91@gmail.com>
3 // SPDX-License-Identifier: LGPL-3.0-only
4 
5 #include <rz_debug.h>
6 #include <rz_reg.h>
7 #include <rz_lib.h>
8 #include <rz_analysis.h>
9 #include <string.h>
10 #include <mach/mach_host.h>
11 #include <mach/host_priv.h>
12 #include <mach/mach_vm.h>
13 #include <mach/thread_status.h>
14 #include <mach/vm_statistics.h>
15 
16 #include <TargetConditionals.h>
17 
18 static task_t task_dbg = 0;
19 #include "xnu_debug.h"
20 #include "xnu_threads.h"
21 
22 extern int proc_regionfilename(int pid, uint64_t address, void *buffer, uint32_t buffersize);
23 
24 #define MAX_MACH_HEADER_SIZE (64 * 1024)
25 #define DYLD_INFO_COUNT 5
26 #define DYLD_INFO_LEGACY_COUNT 1
27 #define DYLD_INFO_32_COUNT 3
28 #define DYLD_INFO_64_COUNT 5
29 #define DYLD_IMAGE_INFO_32_SIZE 12
30 #define DYLD_IMAGE_INFO_64_SIZE 24
31 #define DEBUG_MAP_TAG_ID 239 /* anonymous page id monitorable (e.g. vmmap) */
32 
33 typedef struct {
38 
39 typedef struct {
44 
45 typedef struct {
50 
51 typedef struct {
56 
57 static task_t task_for_pid_workaround(int Pid) {
58  host_t myhost = mach_host_self();
59  mach_port_t psDefault = 0;
60  mach_port_t psDefault_control = 0;
61  task_array_t tasks = NULL;
62  mach_msg_type_number_t numTasks = 0;
63  int i;
64  if (Pid == -1) {
65  return 0;
66  }
67  kern_return_t kr = processor_set_default(myhost, &psDefault);
68  if (kr != KERN_SUCCESS) {
69  return 0;
70  }
71  kr = host_processor_set_priv(myhost, psDefault, &psDefault_control);
72  if (kr != KERN_SUCCESS) {
73  eprintf("host_processor_set_priv failed with error 0x%x\n", kr);
74  // mach_error ("host_processor_set_priv",kr);
75  return -1;
76  }
77 
78  numTasks = 0;
79  kr = processor_set_tasks(psDefault_control, &tasks, &numTasks);
80  if (kr != KERN_SUCCESS) {
81  eprintf("processor_set_tasks failed with error %x\n", kr);
82  return -1;
83  }
84  /* kernel task */
85  task_t task = -1;
86  if (Pid == 0) {
87  task = tasks[0];
88  } else {
89  for (i = 0; i < numTasks; i++) {
90  pid_t pid = 0;
91  pid_for_task(i, &pid);
92  if (pid == Pid) {
93  task = tasks[i];
94  break;
95  }
96  }
97  }
98  vm_deallocate(myhost, (vm_address_t)tasks, numTasks * sizeof(task_t));
99  return task;
100 }
101 
102 static task_t task_for_pid_ios9pangu(int pid) {
103  task_t task = MACH_PORT_NULL;
104  host_get_special_port(mach_host_self(), HOST_LOCAL_NODE, 4, &task);
105  return task;
106 }
107 
108 int xnu_wait(RzDebug *dbg, int pid) {
109  return xnu_wait_for_exception(dbg, pid, 0, false);
110 }
111 
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 }
132 
133 int xnu_attach(RzDebug *dbg, int pid) {
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 }
159 
160 int xnu_detach(RzDebug *dbg, int pid) {
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 }
181 
182 static int task_suspend_count(task_t task) {
183  kern_return_t kr;
184  struct task_basic_info info;
185  mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT;
186  kr = task_info(task, TASK_BASIC_INFO, (task_info_t)&info, &count);
187  if (kr != KERN_SUCCESS) {
188  eprintf("failed to get task info\n");
189  return -1;
190  }
191  return info.suspend_count;
192 }
193 
194 int xnu_stop(RzDebug *dbg, int pid) {
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 }
226 
227 int xnu_continue(RzDebug *dbg, int pid, int tid, int sig) {
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 }
251 
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 }
274 
275 // rz_debug_select
276 // using getcurthread has some drawbacks. You lose the ability to select
277 // the thread you want to write or read from. but how that feature
278 // is not implemented yet i don't care so much
279 int xnu_reg_write(RzDebug *dbg, int type, const ut8 *buf, int size) {
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 }
314 
315 int xnu_reg_read(RzDebug *dbg, int type, ut8 *buf, int size) {
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 }
345 
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 }
367 
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 }
380 
381 static int xnu_get_kinfo_proc(int pid, struct kinfo_proc *kp) {
382  int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, 0 };
383  int len = 4;
384  size_t kpl = sizeof(struct kinfo_proc);
385 
386  mib[3] = pid;
387  if (sysctl(mib, len, kp, &kpl, NULL, 0) == -1) {
388  perror("sysctl");
389  return -1;
390  }
391  if (kpl < 1) {
392  return -1;
393  }
394  return 0;
395 }
396 
397 RzDebugInfo *xnu_info(RzDebug *dbg, const char *arg) {
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 }
437 
438 /*
439 static void xnu_free_threads_ports (RzDebugPid *p) {
440  kern_return_t kr;
441  if (!p) return;
442  free (p->path);
443  if (p->pid != old_pid) {
444  kr = mach_port_deallocate (old_pid, p->pid);
445  if (kr != KERN_SUCCESS) {
446  eprintf ("error mach_port_deallocate in "
447  "xnu_free_threads ports\n");
448  }
449  }
450 }
451 */
452 
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 }
477 
478 #if 0
479 static vm_prot_t unix_prot_to_darwin(int prot) {
480  return ((prot & 1 << 4) ? VM_PROT_READ : 0 |
481  (prot & 1 << 2) ? VM_PROT_WRITE : 0 |
482  (prot & 1 << 1) ? VM_PROT_EXECUTE : 0);
483 }
484 #endif
485 
486 int xnu_map_protect(RzDebug *dbg, ut64 addr, int size, int perms) {
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 }
497 
498 task_t pid_to_task(int pid) {
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 }
537 
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 }
570 
571 #define xwrz_testwx(x) ((x & 1) << 2) | (x & 2) | ((x & 4) >> 2)
572 #define COMMAND_SIZE(segment_count, segment_command_sz, \
573  thread_count, tstate_size) \
574  segment_count *segment_command_sz + thread_count * sizeof(struct thread_command) + tstate_size *thread_count
575 
576 static void get_mach_header_sizes(size_t *mach_header_sz,
577  size_t *segment_command_sz) {
578 #if __ppc64__ || __x86_64__
579  *mach_header_sz = sizeof(struct mach_header_64);
580  *segment_command_sz = sizeof(struct segment_command_64);
581 #elif __i386__ || __ppc__ || __POWERPC__
582  *mach_header_sz = sizeof(struct mach_header);
583  *segment_command_sz = sizeof(struct segment_command);
584 #else
585 #endif
586  // XXX: What about arm?
587 }
588 
589 // XXX: This function could use less function calls, but works.
590 static cpu_type_t xnu_get_cpu_type(pid_t pid) {
591  int mib[CTL_MAXNAME];
592  size_t len = CTL_MAXNAME;
593  cpu_type_t cpu_type;
594  size_t cpu_type_len = sizeof(cpu_type_t);
595 
596  if (sysctlnametomib("sysctl.proc_cputype", mib, &len) == -1) {
597  perror("sysctlnametomib");
598  return -1;
599  }
600  mib[len++] = pid;
601  if (sysctl(mib, len, &cpu_type, &cpu_type_len, NULL, 0) == -1) {
602  perror("sysctl");
603  return -1;
604  }
605  if (cpu_type_len > 0)
606  return cpu_type;
607  return -1;
608 }
609 
610 static cpu_subtype_t xnu_get_cpu_subtype(void) {
611  size_t size;
612  cpu_subtype_t subtype;
613 
614  size = sizeof(cpu_subtype_t);
615  sysctlbyname("hw.cpusubtype", &subtype, &size, NULL, 0);
616 
617  return subtype;
618 }
619 
620 static void xnu_build_corefile_header(vm_offset_t header,
621  int segment_count, int thread_count, int command_size, pid_t pid) {
622 #if __ppc64__ || __x86_64__ || (defined(TARGET_OS_MAC) && defined(__aarch64__))
623  struct mach_header_64 *mh64;
624  mh64 = (struct mach_header_64 *)header;
625  mh64->magic = MH_MAGIC_64;
626  mh64->cputype = xnu_get_cpu_type(pid);
628  mh64->filetype = MH_CORE;
629  mh64->ncmds = segment_count + thread_count;
630  mh64->sizeofcmds = command_size;
631  mh64->reserved = 0; // 8-byte alignment
632 #elif __i386__ || __ppc__ || __POWERPC__
633  struct mach_header *mh;
634  mh = (struct mach_header *)header;
635  mh->magic = MH_MAGIC;
638  mh->filetype = MH_CORE;
639  mh->ncmds = segment_count + thread_count;
640  mh->sizeofcmds = command_size;
641 #endif
642 }
643 
645  RzListIter *iter, *iter2;
646  xnu_thread_t *thread;
647  mach_msg_type_number_t thread_count;
648  thread_array_t thread_list;
649 
650  mach_error_t kr = task_threads(task_dbg, &thread_list, &thread_count);
651  if (kr != KERN_SUCCESS) {
652  LOG_MACH_ERROR("task_threads", kr);
653  } else {
654  rz_list_foreach_safe (threads, iter, iter2, thread) {
655  mach_port_deallocate(mach_task_self(), thread->port);
656  }
657  vm_deallocate(mach_task_self(), (vm_address_t)thread_list,
658  thread_count * sizeof(thread_act_t));
659  }
660  return kr;
661 }
662 
663 /* XXX This is temporal. Later it will write in a RzBuffer. */
664 /* XXX Apart from writing to the file, it also creates the commands, */
665 /* XXX which follow the header. */
666 /* XXX Maybe this function needs refactoring, but I haven't come up with */
667 /* XXX a better way to do it yet. */
668 static int xnu_write_mem_maps_to_buffer(RzBuffer *buffer, RzList *mem_maps, int start_offset,
669  vm_offset_t header, int header_end, int segment_command_sz, int *hoffset_out) {
670  RzListIter *iter, *iter2;
671  RzDebugMap *curr_map;
672  int foffset = 0; // start_offset;
673  int hoffset = header_end;
674  kern_return_t kr = KERN_SUCCESS;
675  int error = 0;
676  ssize_t rc = 0;
677 
678 #define CAST_DOWN(type, addr) (((type)((uintptr_t)(addr))))
679 #if __ppc64__ || __x86_64__ || (defined(TARGET_OS_MAC) && defined(__aarch64__))
680  struct segment_command_64 *sc64;
681 #elif __i386__ || __ppc__ || __POWERPC__
682  struct segment_command *sc;
683 #endif
684  rz_list_foreach_safe (mem_maps, iter, iter2, curr_map) {
685  eprintf("Writing section from 0x%" PFMT64x " to 0x%" PFMT64x " (%" PFMT64d ")\n",
686  curr_map->addr, curr_map->addr_end, curr_map->size);
687 
688  vm_map_offset_t vmoffset = curr_map->addr;
689 #if __ppc64__ || __x86_64__ || (defined(TARGET_OS_MAC) && defined(__aarch64__))
690  sc64 = (struct segment_command_64 *)(header + hoffset);
691  sc64->cmd = LC_SEGMENT_64;
692  sc64->cmdsize = sizeof(struct segment_command_64);
693  sc64->segname[0] = 0; // XXX curr_map->name OR curr_map->file ???
694  sc64->vmaddr = curr_map->addr;
695  sc64->vmsize = curr_map->size;
696  sc64->maxprot = xwrz_testwx(curr_map->user);
697  sc64->initprot = xwrz_testwx(curr_map->perm);
698  sc64->nsects = 0;
699 #elif __i386__ || __ppc__
700  sc = (struct segment_command *)(header + hoffset);
701  sc->cmd = LC_SEGMENT;
702  sc->cmdsize = sizeof(struct segment_command);
703  sc->segname[0] = 0;
704  sc->vmaddr = CAST_DOWN(vm_offset_t, curr_map->addr); // XXX: Is this needed?
705  sc->vmsize = CAST_DOWN(vm_size_t, curr_map->size);
706  sc->fileoff = CAST_DOWN(ut32, foffset);
707  sc->filesize = CAST_DOWN(ut32, curr_map->size);
708  sc->maxprot = xwrz_testwx(curr_map->user);
709  sc->initprot = xwrz_testwx(curr_map->perm);
710  sc->nsects = 0;
711 #endif
712  if ((curr_map->perm & VM_PROT_READ) == 0) {
713  mach_vm_protect(task_dbg, curr_map->addr, curr_map->size, FALSE,
714  curr_map->perm | VM_PROT_READ);
715  }
716 
717  /* Acording to osxbook, the check should be like this: */
718 #if 0
719  if ((maxprot & VM_PROT_READ) == VM_PROT_READ &&
720  (vbr.user_tag != VM_MEMORY_IOKIT)) {
721 #endif
722  if ((curr_map->perm & VM_PROT_READ) == VM_PROT_READ) {
723  vm_map_size_t tmp_size = curr_map->size;
724 
725  while (tmp_size > 0) {
726  vm_map_size_t xfer_size = tmp_size;
727  vm_offset_t local_address;
728  mach_msg_type_number_t local_size;
729 
730  if (xfer_size > INT_MAX)
731  xfer_size = INT_MAX;
732  kr = mach_vm_read(task_dbg, vmoffset, xfer_size,
733  &local_address, &local_size);
734 
735  if ((kr != KERN_SUCCESS) || (xfer_size != local_size)) {
736  eprintf("Failed to read target memory\n"); // XXX: Improve this message?
737  eprintf("[DEBUG] kr = %d\n", kr);
738  eprintf("[DEBUG] KERN_SUCCESS = %d\n", KERN_SUCCESS);
739  eprintf("[DEBUG] xfer_size = %" PFMT64d "\n", (ut64)xfer_size);
740  eprintf("[DEBUG] local_size = %d\n", local_size);
741  if (kr > 1)
742  error = -1; // XXX: INVALID_ADDRESS is not a bug right know
743  goto cleanup;
744  }
745 #if __ppc64__ || __x86_64__ || __aarch64__ || __arm64__
746  rc = rz_buf_append_bytes(buffer, (const ut8 *)local_address, xfer_size);
747 // #elif __i386__ || __ppc__ || __arm__
748 #else
749  rc = rz_buf_append_bytes(buffer, (void *)CAST_DOWN(ut32, local_address),
750  CAST_DOWN(ut32, xfer_size));
751 #endif
752  if (!rc) {
753  error = errno;
754  eprintf("Failed to write in the destination\n");
755  goto cleanup;
756  }
757 
758  tmp_size -= xfer_size;
759  }
760  }
761 
762  hoffset += segment_command_sz;
763  foffset += curr_map->size;
764  vmoffset += curr_map->size;
765  }
766 
767 cleanup:
768  *hoffset_out = hoffset;
769  return error;
770 }
771 
772 static int xnu_get_thread_status(register thread_t thread, int flavor,
773  thread_state_t tstate, mach_msg_type_number_t *count) {
774  return thread_get_state(thread, flavor, tstate, count);
775 }
776 
777 static void xnu_collect_thread_state(thread_t port, void *tirp) {
779  tir_t *tir = (tir_t *)tirp;
780  struct thread_command *tc;
781  vm_offset_t header;
782  ut64 hoffset;
783  int i;
784 
785  header = tir->header;
786  hoffset = tir->hoffset;
787  flavors = tir->flavors;
788  eprintf("[DEBUG] tc location: 0x%" PFMT64x "\n", hoffset);
789 
790  tc = (struct thread_command *)(header + hoffset);
791  tc->cmd = LC_THREAD;
792  tc->cmdsize = sizeof(struct thread_command) + tir->tstate_size;
793  hoffset += sizeof(struct thread_command);
794 
795  for (i = 0; i < coredump_nflavors; i++) {
796  eprintf("[DEBUG] %d/%d\n", i + 1, coredump_nflavors);
797  *(coredump_thread_state_flavor_t *)(header + hoffset) = flavors[i];
798  hoffset += sizeof(coredump_thread_state_flavor_t);
799  xnu_get_thread_status(port, flavors[i].flavor,
800  (thread_state_t)(header + hoffset), &flavors[i].count);
801  hoffset += flavors[i].count * sizeof(int);
802  }
803  tir->hoffset = hoffset;
804 }
805 
806 #define CORE_ALL_SECT 0
807 
808 #include <sys/sysctl.h>
809 
811  uid_t uid = -1;
812 
813  struct kinfo_proc process;
814  size_t procBufferSize = sizeof(process);
815 
816  // Compose search path for sysctl. Here you can specify PID directly.
817  int path[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, pid };
818  const int pathLenth = (sizeof(path) / sizeof(int));
819  int sysctlResult = sysctl(path, pathLenth, &process, &procBufferSize, NULL, 0);
820  // If sysctl did not fail and process with PID available - take UID.
821  if ((sysctlResult == 0) && (procBufferSize != 0)) {
822  uid = process.kp_eproc.e_ucred.cr_uid;
823  }
824  return uid;
825 }
826 
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 }
906 
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 }
1011 
1013  vm_map_t target_task,
1014  mach_vm_address_t *address,
1015  mach_vm_size_t *size,
1016  natural_t *nesting_depth,
1017  vm_region_recurse_info_t info,
1018  mach_msg_type_number_t *infoCnt);
1019 
1020 static const char *unparse_inheritance(vm_inherit_t i) {
1021  switch (i) {
1022  case VM_INHERIT_SHARE: return "share";
1023  case VM_INHERIT_COPY: return "copy";
1024  case VM_INHERIT_NONE: return "none";
1025  default: return "???";
1026  }
1027 }
1028 
1029 #ifndef KERNEL_LOWER
1030 #define ADDR "%8x"
1031 #define HEADER_SIZE 0x1000
1032 #define IMAGE_OFFSET 0x201000
1033 #define KERNEL_LOWER 0x80000000
1034 #endif
1035 
1036 // it's not used (yet)
1037 vm_address_t get_kernel_base(task_t ___task) {
1038  mach_msg_type_number_t info_count = VM_REGION_SUBMAP_INFO_COUNT_64;
1039  vm_region_submap_info_data_64_t info;
1040  ut64 naddr, addr = KERNEL_LOWER; // lowest possible kernel base address
1041  unsigned int depth = 0;
1042  kern_return_t ret;
1043  task_t task;
1044  ut64 size;
1045  int count;
1046 
1047  ret = task_for_pid(mach_task_self(), 0, &task);
1048  if (ret != KERN_SUCCESS) {
1049  return 0;
1050  }
1051  // eprintf ("%d vs %d\n", task, ___task);
1052  for (count = 128; count; count--) {
1053  // get next memory region
1054  naddr = addr;
1055  ret = vm_region_recurse_64(task, (vm_address_t *)&naddr,
1056  (vm_size_t *)&size, &depth,
1057  (vm_region_info_t)&info, &info_count);
1058  if (ret != KERN_SUCCESS) {
1059  break;
1060  }
1061  if (size < 1) {
1062  break;
1063  }
1064  if (addr == naddr) {
1065  addr += size;
1066  continue;
1067  }
1068  eprintf("0x%08" PFMT64x " size 0x%08" PFMT64x " perm 0x%x\n",
1069  (ut64)addr, (ut64)size, info.max_protection);
1070  // the kernel maps over a GB of RAM at the address where it maps
1071  // itself so we use that fact to detect it's position
1072  if (size > 1024 * 1024 * 1024) {
1073  return addr + IMAGE_OFFSET;
1074  }
1075  addr += size;
1076  }
1077  ret = mach_port_deallocate(mach_task_self(), 0);
1078  if (ret != KERN_SUCCESS) {
1079  eprintf("get_kernel_base: leaking kernel port\n");
1080  }
1081  return (vm_address_t)0;
1082 }
1083 
1084 // TODO: Implement mach0 size.. maybe copypasta from rbin?
1085 static int mach0_size(RzDebug *dbg, ut64 addr) {
1086  return 4096;
1087 }
1088 
1089 static void xnu_map_free(RzDebugMap *map) {
1090  if (map) {
1091  free(map->name);
1092  free(map->file);
1093  free(map);
1094  }
1095 }
1096 
1098 #if __POWERPC__
1099 #warning TODO: xnu_dbg_modules not supported
1100  return NULL;
1101 #else
1102  struct task_dyld_info info;
1103  mach_msg_type_number_t count;
1104  kern_return_t kr;
1105  int size, info_array_count, info_array_size, i;
1106  ut64 info_array_address;
1107  void *info_array = NULL;
1108  // void *header_data = NULL;
1109  char file_path[MAXPATHLEN] = { 0 };
1110  count = TASK_DYLD_INFO_COUNT;
1111  task_t task = pid_to_task(dbg->tid);
1112  ut64 addr, file_path_address;
1113  RzDebugMap *mr = NULL;
1114  RzList *list = NULL;
1115  if (!task) {
1116  return NULL;
1117  }
1118 
1119  kr = task_info(task, TASK_DYLD_INFO, (task_info_t)&info, &count);
1120  if (kr != KERN_SUCCESS) {
1121  rz_list_free(list);
1122  return NULL;
1123  }
1124 
1125  if (info.all_image_info_format == TASK_DYLD_ALL_IMAGE_INFO_64) {
1126  DyldAllImageInfos64 all_infos;
1127  dbg->iob.read_at(dbg->iob.io, info.all_image_info_addr,
1128  (ut8 *)&all_infos, sizeof(DyldAllImageInfos64));
1129  info_array_count = all_infos.info_array_count;
1130  info_array_size = info_array_count * DYLD_IMAGE_INFO_64_SIZE;
1131  info_array_address = all_infos.info_array;
1132  } else {
1133  DyldAllImageInfos32 all_info;
1134  dbg->iob.read_at(dbg->iob.io, info.all_image_info_addr,
1135  (ut8 *)&all_info, sizeof(DyldAllImageInfos32));
1136  info_array_count = all_info.info_array_count;
1137  info_array_size = info_array_count * DYLD_IMAGE_INFO_32_SIZE;
1138  info_array_address = all_info.info_array;
1139  }
1140 
1141  if (info_array_address == 0) {
1142  return NULL;
1143  }
1144  info_array_size = RZ_ABS(info_array_size);
1145  info_array = calloc(1, info_array_size);
1146  if (!info_array) {
1147  eprintf("Cannot allocate info_array_size %d\n",
1148  info_array_size);
1149  return NULL;
1150  }
1151 
1152  dbg->iob.read_at(dbg->iob.io, info_array_address, info_array, info_array_size);
1153 
1155  if (!list) {
1156  free(info_array);
1157  return NULL;
1158  }
1159  for (i = 0; i < info_array_count; i++) {
1160  if (info.all_image_info_format == TASK_DYLD_ALL_IMAGE_INFO_64) {
1161  DyldImageInfo64 *info = info_array +
1163  addr = info->image_load_address;
1164  file_path_address = info->image_file_path;
1165  } else {
1166  DyldImageInfo32 *info = info_array +
1168  addr = info->image_load_address;
1169  file_path_address = info->image_file_path;
1170  }
1171  memset(file_path, 0, MAXPATHLEN);
1172  dbg->iob.read_at(dbg->iob.io, file_path_address,
1173  (ut8 *)file_path, MAXPATHLEN - 1);
1174  // eprintf ("--> %d 0x%08"PFMT64x" %s\n", i, addr, file_path);
1175  size = mach0_size(dbg, addr);
1176  mr = rz_debug_map_new(file_path, addr, addr + size, 7, 7);
1177  if (!mr) {
1178  eprintf("Cannot create rz_debug_map_new\n");
1179  break;
1180  }
1181  mr->file = strdup(file_path);
1182  mr->shared = true;
1184  }
1185  free(info_array);
1186  return list;
1187 #endif
1188 }
1189 
1191  RzListIter *iter;
1192  RzDebugMap *map;
1193  rz_list_foreach (list, iter, map) {
1194  if (RZ_BETWEEN(map->addr, addr, map->addr_end)) {
1195  return map;
1196  }
1197  }
1198  return NULL;
1199 }
1200 
1201 static int cmp(const void *_a, const void *_b) {
1202  const RzDebugMap *a = _a;
1203  const RzDebugMap *b = _b;
1204  if (a->addr > b->addr) {
1205  return 1;
1206  }
1207  if (a->addr < b->addr) {
1208  return -1;
1209  }
1210  return 0;
1211 }
1212 
1215  // memcpy (map, m, sizeof (RzDebugMap));
1216  if (m->name) {
1217  map->name = strdup(m->name);
1218  }
1219  if (m->file) {
1220  map->file = strdup(m->file);
1221  }
1222  return map;
1223 }
1224 
1225 RzList *xnu_dbg_maps(RzDebug *dbg, int only_modules) {
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 }
size_t len
Definition: 6502dis.c:15
lzma_index ** i
Definition: index.h:629
static int cpu_type
Definition: arc-opc.c:143
static bool err
Definition: armass.c:435
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 INT_MAX
Definition: cp-demangle.c:131
#define NULL
Definition: cris-opc.c:27
#define r
Definition: crypto_rc6.c:12
static static fork const void static count static fd const char const char static newpath const char static path const char path
Definition: sflib.h:35
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
uint32_t ut32
RzDebug * dbg
Definition: desil.c:30
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
RZ_API RzDebugMap * rz_debug_map_new(char *name, ut64 addr, ut64 addr_end, int perm, int user)
Definition: dmap.c:7
static char sc[]
Definition: egg_cb.c:6
size_t map(int syms, int left, int len)
Definition: enough.c:237
void cleanup(void)
Definition: enough.c:244
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
voidpf void uLong size
Definition: ioapi.h:138
voidpf void * buf
Definition: ioapi.h:138
snprintf
Definition: kernel.h:364
uint8_t ut8
Definition: lh5801.h:11
return memset(p, 0, total)
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
static RzMain foo[]
Definition: main.c:11
static void list(RzEgg *egg)
Definition: rz-gg.c:52
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 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 ut32 rz_list_length(RZ_NONNULL const RzList *list)
Returns the length of the list.
Definition: list.c:109
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
void * malloc(size_t size)
Definition: malloc.c:123
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
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 static sig const char static mode static oldfd struct tms static buf static getgid static geteuid const char static filename static arg static mask struct ustat static ubuf static getppid static setsid static egid sigset_t static set struct timeval struct timezone static tz fd_set fd_set fd_set struct timeval static timeout const char char static bufsiz const char static swapflags void prot
Definition: sflib.h:115
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
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")
char * dest
Definition: lz4.h:697
#define header(is_bt, len_min, ret_op)
@ LC_SEGMENT
@ LC_THREAD
@ LC_SEGMENT_64
@ VM_PROT_WRITE
@ VM_PROT_EXECUTE
@ VM_PROT_READ
@ MH_MAGIC_64
Definition: mach0_defines.h:63
@ MH_MAGIC
Definition: mach0_defines.h:61
@ MH_CORE
Definition: mach0_defines.h:75
@ RZ_ABS
int n
Definition: mipsasm.c:19
int type
Definition: mipsasm.c:17
#define FALSE
Definition: mybfd.h:102
modules
Definition: regress.py:20
RZ_API RzDebugPid * rz_debug_pid_free(RzDebugPid *pid)
Definition: pid.c:20
RZ_API RzDebugPid * rz_debug_pid_new(const char *path, int pid, int uid, char status, ut64 pc)
Definition: pid.c:6
#define eprintf(x, y...)
Definition: rlcc.c:7
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
RzDebugReasonType
Definition: rz_debug.h:89
@ RZ_DEBUG_REASON_SIGNAL
Definition: rz_debug.h:92
@ 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
void(* RzListFree)(void *ptr)
Definition: rz_list.h:11
#define RZ_LOG_ERROR(fmtstr,...)
Definition: rz_log.h:58
@ 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
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
static const char * rz_str_get_null(const char *str)
Definition: rz_str.h:190
@ RZ_SYS_BITS_32
Definition: rz_sys.h:20
@ RZ_SYS_BITS_64
Definition: rz_sys.h:21
#define RZ_NEWCOPY(x, y)
Definition: rz_types.h:286
#define PFMT64d
Definition: rz_types.h:394
#define RZ_NEW0(x)
Definition: rz_types.h:284
#define PFMT64x
Definition: rz_types.h:393
#define RZ_MIN(x, y)
#define RZ_BETWEEN(x, y, z)
static int
Definition: sfsocketcall.h:114
#define PT_DETACH
Definition: sftypes.h:622
#define EINVAL
Definition: sftypes.h:132
int uid_t
Definition: sftypes.h:44
unsigned int uint32_t
Definition: sftypes.h:29
unsigned long uint64_t
Definition: sftypes.h:28
int pid_t
Definition: sftypes.h:38
int ssize_t
Definition: sftypes.h:39
#define b(i)
Definition: sha256.c:42
#define a(i)
Definition: sha256.c:41
ut32 image_file_mod_date
Definition: xnu_debug.c:42
ut32 image_file_path
Definition: xnu_debug.c:41
ut32 image_load_address
Definition: xnu_debug.c:40
ut64 image_load_address
Definition: xnu_debug.c:52
ut64 image_file_path
Definition: xnu_debug.c:53
ut64 image_file_mod_date
Definition: xnu_debug.c:54
thread_t port
Definition: xnu_threads.h:51
char * name
Definition: xnu_threads.h:52
ut32 state_size
Definition: xnu_threads.h:57
RZ_REG_T gpr
Definition: xnu_threads.h:55
void * state
Definition: xnu_threads.h:56
Definition: buffer.h:15
mach_msg_type_number_t count
Definition: xnu_debug.h:186
uint32_t sizeofcmds
uint32_t filetype
uint32_t reserved
uint32_t cputype
uint32_t cpusubtype
uint32_t filetype
uint32_t magic
uint32_t ncmds
uint32_t cputype
uint32_t cpusubtype
uint32_t sizeofcmds
char * name
Definition: rz_debug.h:137
char * file
Definition: rz_debug.h:142
RzList * threads
Definition: rz_debug.h:251
RzList * maps
Definition: rz_debug.h:306
RzDebugReason reason
Definition: rz_debug.h:276
int bits
Definition: rz_debug.h:243
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
uint32_t cmdsize
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
struct Proc * proc
static uv_thread_t * threads
Definition: threadpool.c:38
void error(const char *msg)
Definition: untgz.c:593
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
static const char * unparse_inheritance(vm_inherit_t i)
Definition: xnu_debug.c:1020
char * xnu_reg_profile(RzDebug *dbg)
Definition: xnu_debug.c:252
bool xnu_step(RzDebug *dbg)
Definition: xnu_debug.c:112
int xnu_map_dealloc(RzDebug *dbg, ut64 addr, int size)
Definition: xnu_debug.c:368
static RzDebugMap * moduleAt(RzList *list, ut64 addr)
Definition: xnu_debug.c:1190
int xnu_continue(RzDebug *dbg, int pid, int tid, int sig)
Definition: xnu_debug.c:227
static task_t task_for_pid_workaround(int Pid)
Definition: xnu_debug.c:57
RzDebugMap * xnu_map_alloc(RzDebug *dbg, ut64 addr, int size)
Definition: xnu_debug.c:346
static int cmp(const void *_a, const void *_b)
Definition: xnu_debug.c:1201
bool xnu_generate_corefile(RzDebug *dbg, RzBuffer *dest)
Definition: xnu_debug.c:827
#define DEBUG_MAP_TAG_ID
Definition: xnu_debug.c:31
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 task_t task_dbg
Definition: xnu_debug.c:18
int xnu_map_protect(RzDebug *dbg, ut64 addr, int size, int perms)
Definition: xnu_debug.c:486
int proc_regionfilename(int pid, uint64_t address, void *buffer, uint32_t buffersize)
RzList * xnu_dbg_maps(RzDebug *dbg, int only_modules)
Definition: xnu_debug.c:1225
static void xnu_collect_thread_state(thread_t port, void *tirp)
Definition: xnu_debug.c:777
RzDebugPid * xnu_get_pid(int pid)
Definition: xnu_debug.c:907
static RzDebugMap * rz_debug_map_clone(RzDebugMap *m)
Definition: xnu_debug.c:1213
int xnu_reg_write(RzDebug *dbg, int type, const ut8 *buf, int size)
Definition: xnu_debug.c:279
int xnu_get_vmmap_entries_for_pid(pid_t pid)
Definition: xnu_debug.c:538
#define DYLD_IMAGE_INFO_64_SIZE
Definition: xnu_debug.c:30
#define DYLD_IMAGE_INFO_32_SIZE
Definition: xnu_debug.c:29
static uid_t uidFromPid(pid_t pid)
Definition: xnu_debug.c:810
int xnu_detach(RzDebug *dbg, int pid)
Definition: xnu_debug.c:160
static int xnu_get_kinfo_proc(int pid, struct kinfo_proc *kp)
Definition: xnu_debug.c:381
int xnu_stop(RzDebug *dbg, int pid)
Definition: xnu_debug.c:194
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 get_mach_header_sizes(size_t *mach_header_sz, size_t *segment_command_sz)
Definition: xnu_debug.c:576
static int xnu_get_thread_status(register thread_t thread, int flavor, thread_state_t tstate, mach_msg_type_number_t *count)
Definition: xnu_debug.c:772
static int task_suspend_count(task_t task)
Definition: xnu_debug.c:182
static void xnu_map_free(RzDebugMap *map)
Definition: xnu_debug.c:1089
static int xnu_dealloc_threads(RzList *threads)
Definition: xnu_debug.c:644
int xnu_reg_read(RzDebug *dbg, int type, ut8 *buf, int size)
Definition: xnu_debug.c:315
static cpu_type_t xnu_get_cpu_type(pid_t pid)
Definition: xnu_debug.c:590
vm_address_t get_kernel_base(task_t ___task)
Definition: xnu_debug.c:1037
#define CAST_DOWN(type, addr)
int xnu_wait(RzDebug *dbg, int pid)
Definition: xnu_debug.c:108
static task_t task_for_pid_ios9pangu(int pid)
Definition: xnu_debug.c:102
int xnu_attach(RzDebug *dbg, int pid)
Definition: xnu_debug.c:133
static int mach0_size(RzDebug *dbg, ut64 addr)
Definition: xnu_debug.c:1085
RzList * xnu_thread_list(RzDebug *dbg, int pid, RzList *list)
Definition: xnu_debug.c:453
static cpu_subtype_t xnu_get_cpu_subtype(void)
Definition: xnu_debug.c:610
task_t pid_to_task(int pid)
Definition: xnu_debug.c:498
#define xwrz_testwx(x)
Definition: xnu_debug.c:571
#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
RzDebugInfo * xnu_info(RzDebug *dbg, const char *arg)
Definition: xnu_debug.c:397
#define MAX_TSTATE_FLAVORS
Definition: xnu_debug.h:259
#define KERNEL_LOWER
Definition: xnu_debug.h:122
#define LOG_MACH_ERROR(name, rc)
Definition: xnu_debug.h:17
#define IMAGE_OFFSET
Definition: xnu_debug.h:121
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)
RZ_IPI bool rz_xnu_thread_set_gpr(RzDebug *dbg, xnu_thread_t *thread)
Definition: xnu_threads.c:130
RZ_IPI int rz_xnu_update_thread_list(RzDebug *dbg)
Definition: xnu_threads.c:290
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
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
static bool xnu_set_trace_bit(RzDebug *dbg, xnu_thread_t *th)
Definition: xnu_threads.h:111
static bool xnu_clear_trace_bit(RzDebug *dbg, xnu_thread_t *th)
Definition: xnu_threads.h:114
static int addr
Definition: z80asm.c:58
static zip_compression_status_t process(void *ud, zip_uint8_t *data, zip_uint64_t *length)