Rizin
unix-like reverse engineering framework and cli tools
xnu_debug.c File Reference
#include <rz_debug.h>
#include <rz_reg.h>
#include <rz_lib.h>
#include <rz_analysis.h>
#include <string.h>
#include <mach/mach_host.h>
#include <mach/host_priv.h>
#include <mach/mach_vm.h>
#include <mach/thread_status.h>
#include <mach/vm_statistics.h>
#include <TargetConditionals.h>
#include "xnu_debug.h"
#include "xnu_threads.h"
#include <sys/sysctl.h>

Go to the source code of this file.

Classes

struct  DyldAllImageInfos32
 
struct  DyldImageInfo32
 
struct  DyldAllImageInfos64
 
struct  DyldImageInfo64
 

Macros

#define MAX_MACH_HEADER_SIZE   (64 * 1024)
 
#define DYLD_INFO_COUNT   5
 
#define DYLD_INFO_LEGACY_COUNT   1
 
#define DYLD_INFO_32_COUNT   3
 
#define DYLD_INFO_64_COUNT   5
 
#define DYLD_IMAGE_INFO_32_SIZE   12
 
#define DYLD_IMAGE_INFO_64_SIZE   24
 
#define DEBUG_MAP_TAG_ID   239 /* anonymous page id monitorable (e.g. vmmap) */
 
#define xwrz_testwx(x)   ((x & 1) << 2) | (x & 2) | ((x & 4) >> 2)
 
#define xwrz_testwx(x)   ((x & 1) << 2) | (x & 2) | ((x & 4) >> 2)
 
#define COMMAND_SIZE(segment_count, segment_command_sz, thread_count, tstate_size)    segment_count *segment_command_sz + thread_count * sizeof(struct thread_command) + tstate_size *thread_count
 
#define CAST_DOWN(type, addr)   (((type)((uintptr_t)(addr))))
 
#define CORE_ALL_SECT   0
 

Functions

int proc_regionfilename (int pid, uint64_t address, void *buffer, uint32_t buffersize)
 
static task_t task_for_pid_workaround (int Pid)
 
static task_t task_for_pid_ios9pangu (int pid)
 
int xnu_wait (RzDebug *dbg, int pid)
 
bool xnu_step (RzDebug *dbg)
 
int xnu_attach (RzDebug *dbg, int pid)
 
int xnu_detach (RzDebug *dbg, int pid)
 
static int task_suspend_count (task_t task)
 
int xnu_stop (RzDebug *dbg, int pid)
 
int xnu_continue (RzDebug *dbg, int pid, int tid, int sig)
 
char * xnu_reg_profile (RzDebug *dbg)
 
int xnu_reg_write (RzDebug *dbg, int type, const ut8 *buf, int size)
 
int xnu_reg_read (RzDebug *dbg, int type, ut8 *buf, int size)
 
RzDebugMapxnu_map_alloc (RzDebug *dbg, ut64 addr, int size)
 
int xnu_map_dealloc (RzDebug *dbg, ut64 addr, int size)
 
static int xnu_get_kinfo_proc (int pid, struct kinfo_proc *kp)
 
RzDebugInfoxnu_info (RzDebug *dbg, const char *arg)
 
RzListxnu_thread_list (RzDebug *dbg, int pid, RzList *list)
 
int xnu_map_protect (RzDebug *dbg, ut64 addr, int size, int perms)
 
task_t pid_to_task (int pid)
 
int xnu_get_vmmap_entries_for_pid (pid_t pid)
 
static void get_mach_header_sizes (size_t *mach_header_sz, size_t *segment_command_sz)
 
static cpu_type_t xnu_get_cpu_type (pid_t pid)
 
static cpu_subtype_t xnu_get_cpu_subtype (void)
 
static void xnu_build_corefile_header (vm_offset_t header, int segment_count, int thread_count, int command_size, pid_t pid)
 
static int xnu_dealloc_threads (RzList *threads)
 
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)
 
static int xnu_get_thread_status (register thread_t thread, int flavor, thread_state_t tstate, mach_msg_type_number_t *count)
 
static void xnu_collect_thread_state (thread_t port, void *tirp)
 
static uid_t uidFromPid (pid_t pid)
 
bool xnu_generate_corefile (RzDebug *dbg, RzBuffer *dest)
 
RzDebugPidxnu_get_pid (int pid)
 
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 const char * unparse_inheritance (vm_inherit_t i)
 
vm_address_t get_kernel_base (task_t ___task)
 
static int mach0_size (RzDebug *dbg, ut64 addr)
 
static void xnu_map_free (RzDebugMap *map)
 
static RzListxnu_dbg_modules (RzDebug *dbg)
 
static RzDebugMapmoduleAt (RzList *list, ut64 addr)
 
static int cmp (const void *_a, const void *_b)
 
static RzDebugMaprz_debug_map_clone (RzDebugMap *m)
 
RzListxnu_dbg_maps (RzDebug *dbg, int only_modules)
 

Variables

static task_t task_dbg = 0
 

Macro Definition Documentation

◆ CAST_DOWN

#define CAST_DOWN (   type,
  addr 
)    (((type)((uintptr_t)(addr))))

◆ COMMAND_SIZE

#define COMMAND_SIZE (   segment_count,
  segment_command_sz,
  thread_count,
  tstate_size 
)     segment_count *segment_command_sz + thread_count * sizeof(struct thread_command) + tstate_size *thread_count

Definition at line 572 of file xnu_debug.c.

◆ CORE_ALL_SECT

#define CORE_ALL_SECT   0

Definition at line 806 of file xnu_debug.c.

◆ DEBUG_MAP_TAG_ID

#define DEBUG_MAP_TAG_ID   239 /* anonymous page id monitorable (e.g. vmmap) */

Definition at line 31 of file xnu_debug.c.

◆ DYLD_IMAGE_INFO_32_SIZE

#define DYLD_IMAGE_INFO_32_SIZE   12

Definition at line 29 of file xnu_debug.c.

◆ DYLD_IMAGE_INFO_64_SIZE

#define DYLD_IMAGE_INFO_64_SIZE   24

Definition at line 30 of file xnu_debug.c.

◆ DYLD_INFO_32_COUNT

#define DYLD_INFO_32_COUNT   3

Definition at line 27 of file xnu_debug.c.

◆ DYLD_INFO_64_COUNT

#define DYLD_INFO_64_COUNT   5

Definition at line 28 of file xnu_debug.c.

◆ DYLD_INFO_COUNT

#define DYLD_INFO_COUNT   5

Definition at line 25 of file xnu_debug.c.

◆ DYLD_INFO_LEGACY_COUNT

#define DYLD_INFO_LEGACY_COUNT   1

Definition at line 26 of file xnu_debug.c.

◆ MAX_MACH_HEADER_SIZE

#define MAX_MACH_HEADER_SIZE   (64 * 1024)

Definition at line 24 of file xnu_debug.c.

◆ xwrz_testwx [1/2]

#define xwrz_testwx (   x)    ((x & 1) << 2) | (x & 2) | ((x & 4) >> 2)

Definition at line 571 of file xnu_debug.c.

◆ xwrz_testwx [2/2]

#define xwrz_testwx (   x)    ((x & 1) << 2) | (x & 2) | ((x & 4) >> 2)

Definition at line 571 of file xnu_debug.c.

Function Documentation

◆ cmp()

static int cmp ( const void *  _a,
const void *  _b 
)
static

Definition at line 1201 of file xnu_debug.c.

1201  {
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 }
#define b(i)
Definition: sha256.c:42
#define a(i)
Definition: sha256.c:41

References a, and b.

Referenced by xnu_dbg_maps().

◆ get_kernel_base()

vm_address_t get_kernel_base ( task_t  ___task)

Definition at line 1037 of file xnu_debug.c.

1037  {
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 }
RzBinInfo * info(RzBinFile *bf)
Definition: bin_ne.c:86
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
voidpf void uLong size
Definition: ioapi.h:138
#define eprintf(x, y...)
Definition: rlcc.c:7
#define PFMT64x
Definition: rz_types.h:393
ut64(WINAPI *w32_GetEnabledXStateFeatures)()
#define KERNEL_LOWER
Definition: xnu_debug.h:122
#define IMAGE_OFFSET
Definition: xnu_debug.h:121
static int addr
Definition: z80asm.c:58

References addr, count, eprintf, IMAGE_OFFSET, info(), KERNEL_LOWER, PFMT64x, and ut64().

Referenced by xnu_dbg_maps().

◆ get_mach_header_sizes()

static void get_mach_header_sizes ( size_t mach_header_sz,
size_t segment_command_sz 
)
static

Definition at line 576 of file xnu_debug.c.

577  {
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 }

Referenced by xnu_generate_corefile().

◆ mach0_size()

static int mach0_size ( RzDebug dbg,
ut64  addr 
)
static

Definition at line 1085 of file xnu_debug.c.

1085  {
1086  return 4096;
1087 }

Referenced by xnu_dbg_modules().

◆ mach_vm_region_recurse()

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 
)

Referenced by xnu_dbg_maps().

◆ moduleAt()

static RzDebugMap* moduleAt ( RzList list,
ut64  addr 
)
static

Definition at line 1190 of file xnu_debug.c.

1190  {
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 }
#define NULL
Definition: cris-opc.c:27
size_t map(int syms, int left, int len)
Definition: enough.c:237
static void list(RzEgg *egg)
Definition: rz-gg.c:52
#define RZ_BETWEEN(x, y, z)

References addr, list(), map(), NULL, and RZ_BETWEEN.

Referenced by xnu_dbg_maps().

◆ 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 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().

◆ proc_regionfilename()

int proc_regionfilename ( int  pid,
uint64_t  address,
void *  buffer,
uint32_t  buffersize 
)

Referenced by xnu_dbg_maps().

◆ rz_debug_map_clone()

static RzDebugMap* rz_debug_map_clone ( RzDebugMap m)
static

Definition at line 1213 of file xnu_debug.c.

1213  {
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 }
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")
#define RZ_NEWCOPY(x, y)
Definition: rz_types.h:286

References regress::m, map(), RZ_NEWCOPY, and strdup().

Referenced by xnu_dbg_maps().

◆ task_for_pid_ios9pangu()

static task_t task_for_pid_ios9pangu ( int  pid)
static

Definition at line 102 of file xnu_debug.c.

102  {
103  task_t task = MACH_PORT_NULL;
104  host_get_special_port(mach_host_self(), HOST_LOCAL_NODE, 4, &task);
105  return task;
106 }

Referenced by pid_to_task().

◆ task_for_pid_workaround()

static task_t task_for_pid_workaround ( int  Pid)
static

Definition at line 57 of file xnu_debug.c.

57  {
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 }
lzma_index ** i
Definition: index.h:629

References eprintf, i, NULL, and pid.

Referenced by pid_to_task().

◆ task_suspend_count()

static int task_suspend_count ( task_t  task)
static

Definition at line 182 of file xnu_debug.c.

182  {
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 }

References count, eprintf, and info().

Referenced by xnu_stop().

◆ uidFromPid()

static uid_t uidFromPid ( pid_t  pid)
static

Definition at line 810 of file xnu_debug.c.

810  {
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 }
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
int uid_t
Definition: sftypes.h:44
static zip_compression_status_t process(void *ud, zip_uint8_t *data, zip_uint64_t *length)

References NULL, path, pid, and process().

Referenced by xnu_get_pid().

◆ unparse_inheritance()

static const char* unparse_inheritance ( vm_inherit_t  i)
static

Definition at line 1020 of file xnu_debug.c.

1020  {
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 }

References i.

Referenced by xnu_dbg_maps().

◆ 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_build_corefile_header()

static void xnu_build_corefile_header ( vm_offset_t  header,
int  segment_count,
int  thread_count,
int  command_size,
pid_t  pid 
)
static

Definition at line 620 of file xnu_debug.c.

621  {
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 }
#define header(is_bt, len_min, ret_op)
@ MH_MAGIC_64
Definition: mach0_defines.h:63
@ MH_MAGIC
Definition: mach0_defines.h:61
@ MH_CORE
Definition: mach0_defines.h:75
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
static cpu_type_t xnu_get_cpu_type(pid_t pid)
Definition: xnu_debug.c:590
static cpu_subtype_t xnu_get_cpu_subtype(void)
Definition: xnu_debug.c:610

References mach_header::cpusubtype, mach_header_64::cpusubtype, mach_header::cputype, mach_header_64::cputype, mach_header::filetype, mach_header_64::filetype, header, mach_header::magic, mach_header_64::magic, MH_CORE, MH_MAGIC, MH_MAGIC_64, mach_header::ncmds, mach_header_64::ncmds, pid, mach_header_64::reserved, mach_header::sizeofcmds, mach_header_64::sizeofcmds, xnu_get_cpu_subtype(), and xnu_get_cpu_type().

Referenced by xnu_generate_corefile().

◆ xnu_collect_thread_state()

static void xnu_collect_thread_state ( thread_t  port,
void *  tirp 
)
static

Definition at line 777 of file xnu_debug.c.

777  {
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 }
@ LC_THREAD
static int
Definition: sfsocketcall.h:114
mach_msg_type_number_t count
Definition: xnu_debug.h:186
uint32_t cmdsize
int hoffset
Definition: xnu_debug.h:265
coredump_thread_state_flavor_t * flavors
Definition: xnu_debug.h:267
vm_offset_t header
Definition: xnu_debug.h:264
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

References thread_command::cmd, thread_command::cmdsize, coredump_thread_state_flavor_t::count, count, eprintf, tir_t::flavors, tir_t::header, header, tir_t::hoffset, i, int, LC_THREAD, PFMT64x, ut64(), and xnu_get_thread_status().

Referenced by xnu_generate_corefile().

◆ 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_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 }
static int mr(RzAnalysisEsil *esil, ut64 addr, ut8 *buf, int len)
Definition: cmd_analysis.c:471
RZ_API RzDebugMap * rz_debug_map_new(char *name, ut64 addr, ut64 addr_end, int perm, int user)
Definition: dmap.c:7
voidpf void * buf
Definition: ioapi.h:138
snprintf
Definition: kernel.h:364
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
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
char * name
Definition: rz_debug.h:137
char * file
Definition: rz_debug.h:142
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_dbg_modules()

static RzList* xnu_dbg_modules ( RzDebug dbg)
static

Definition at line 1097 of file xnu_debug.c.

1097  {
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 }
RZ_API void Ht_() free(HtName_(Ht) *ht)
Definition: ht_inc.c:130
uint8_t ut8
Definition: lh5801.h:11
return memset(p, 0, total)
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
void * calloc(size_t number, size_t size)
Definition: malloc.c:102
@ RZ_ABS
RzIOBind iob
Definition: rz_debug.h:293
RzIOReadAt read_at
Definition: rz_io.h:240
RzIO * io
Definition: rz_io.h:232
#define DYLD_IMAGE_INFO_64_SIZE
Definition: xnu_debug.c:30
#define DYLD_IMAGE_INFO_32_SIZE
Definition: xnu_debug.c:29
static int mach0_size(RzDebug *dbg, ut64 addr)
Definition: xnu_debug.c:1085

References addr, calloc(), count, dbg, DYLD_IMAGE_INFO_32_SIZE, DYLD_IMAGE_INFO_64_SIZE, eprintf, free(), i, info(), DyldAllImageInfos32::info_array, DyldAllImageInfos64::info_array, DyldAllImageInfos32::info_array_count, DyldAllImageInfos64::info_array_count, rz_io_bind_t::io, rz_debug_t::iob, list(), mach0_size(), memset(), mr(), NULL, pid_to_task(), rz_io_bind_t::read_at, RZ_ABS, rz_debug_map_new(), rz_list_append(), rz_list_free(), rz_list_newf(), strdup(), rz_debug_t::tid, ut64(), and xnu_map_free().

Referenced by xnu_dbg_maps().

◆ xnu_dealloc_threads()

static int xnu_dealloc_threads ( RzList threads)
static

Definition at line 644 of file xnu_debug.c.

644  {
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 }
thread_t port
Definition: xnu_threads.h:51
static uv_thread_t * threads
Definition: threadpool.c:38
#define LOG_MACH_ERROR(name, rc)
Definition: xnu_debug.h:17

References LOG_MACH_ERROR, _xnu_thread::port, task_dbg, and threads.

Referenced by xnu_generate_corefile().

◆ 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 }
void cleanup(void)
Definition: enough.c:244
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
char * dest
Definition: lz4.h:697
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
RzList * maps
Definition: rz_debug.h:306
int tstate_size
Definition: xnu_debug.h:266
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_cpu_subtype()

static cpu_subtype_t xnu_get_cpu_subtype ( void  )
static

Definition at line 610 of file xnu_debug.c.

610  {
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 }

References NULL.

Referenced by xnu_build_corefile_header().

◆ xnu_get_cpu_type()

static cpu_type_t xnu_get_cpu_type ( pid_t  pid)
static

Definition at line 590 of file xnu_debug.c.

590  {
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 }
size_t len
Definition: 6502dis.c:15
static int cpu_type
Definition: arc-opc.c:143

References cpu_type, len, NULL, and pid.

Referenced by xnu_build_corefile_header().

◆ xnu_get_kinfo_proc()

static int xnu_get_kinfo_proc ( int  pid,
struct kinfo_proc *  kp 
)
static

Definition at line 381 of file xnu_debug.c.

381  {
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 }

References len, NULL, and pid.

Referenced by xnu_info().

◆ 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_thread_status()

static int xnu_get_thread_status ( register thread_t  thread,
int  flavor,
thread_state_t  tstate,
mach_msg_type_number_t *  count 
)
static

Definition at line 772 of file xnu_debug.c.

773  {
774  return thread_get_state(thread, flavor, tstate, count);
775 }

References count.

Referenced by xnu_collect_thread_state().

◆ 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_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

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 }

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

◆ xnu_map_free()

static void xnu_map_free ( RzDebugMap map)
static

Definition at line 1089 of file xnu_debug.c.

1089  {
1090  if (map) {
1091  free(map->name);
1092  free(map->file);
1093  free(map);
1094  }
1095 }

References free(), and map().

Referenced by xnu_dbg_maps(), and xnu_dbg_modules().

◆ 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 dbg,
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().

◆ xnu_write_mem_maps_to_buffer()

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 
)
static

Definition at line 668 of file xnu_debug.c.

669  {
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 }
#define INT_MAX
Definition: cp-demangle.c:131
static char sc[]
Definition: egg_cb.c:6
@ LC_SEGMENT
@ LC_SEGMENT_64
@ VM_PROT_READ
#define FALSE
Definition: mybfd.h:102
#define PFMT64d
Definition: rz_types.h:394
int ssize_t
Definition: sftypes.h:39
Definition: buffer.h:15
#define CAST_DOWN(type, addr)

References rz_debug_map_t::addr, rz_debug_map_t::addr_end, CAST_DOWN, cleanup(), segment_command_64::cmd, segment_command_64::cmdsize, eprintf, error(), FALSE, header, segment_command_64::initprot, INT_MAX, LC_SEGMENT, LC_SEGMENT_64, segment_command::maxprot, segment_command_64::maxprot, segment_command_64::nsects, rz_debug_map_t::perm, PFMT64d, PFMT64x, rz_buf_append_bytes(), sc, segment_command_64::segname, rz_debug_map_t::size, task_dbg, rz_debug_map_t::user, ut64(), VM_PROT_READ, segment_command_64::vmaddr, segment_command_64::vmsize, and xwrz_testwx.

Referenced by xnu_generate_corefile().

Variable Documentation

◆ task_dbg

task_t task_dbg = 0
static