#include <CoreSymbolication/CoreSymbolication.h>
#include <CoreSymbolication/CoreSymbolicationPrivate.h>
#include <mach/mach.h>
#include <mach/mach_vm.h>
#include <mach/mach_error.h>
#include <servers/bootstrap.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#import <sys/sysctl.h>
#include <System/sys/proc_info.h>
#define uint_t __Solaris_uint_t
#import "libproc.h"
#import "libproc_apple.h"
#import <spawn.h>
#import <pthread.h>
#include <crt_externs.h>
extern void dt_dprintf(const char *, ...);
extern int _dtrace_mangled;
CSSymbolOwnerRef symbolOwnerForName(CSSymbolicatorRef symbolicator, const char* name) {
if (strcmp(name, "a.out") == 0) {
__block CSSymbolOwnerRef owner = kCSNull;
if (CSSymbolicatorForeachSymbolOwnerWithFlagsAtTime(symbolicator, kCSSymbolOwnerIsAOut, kCSNow, ^(CSSymbolOwnerRef t) { owner = t; }) == 1) {
return owner;
}
return kCSNull;
}
__block CSSymbolOwnerRef owner = kCSNull;
if (CSSymbolicatorForeachSymbolOwnerWithPathAtTime(symbolicator, name, kCSNow, ^(CSSymbolOwnerRef t) { if (CSIsNull(owner)) owner = t; }) > 0)
return owner;
if (CSSymbolicatorForeachSymbolOwnerWithNameAtTime(symbolicator, name, kCSNow, ^(CSSymbolOwnerRef t) { if (CSIsNull(owner)) owner = t; }) > 0)
return owner;
size_t nameLength = strlen(name);
CSSymbolicatorForeachSymbolOwnerAtTime(symbolicator, kCSNow, ^(CSSymbolOwnerRef candidate) {
if (CSIsNull(owner)) {
const char* candidateName = CSSymbolOwnerGetName(candidate);
size_t candidateNameLength = strlen(candidateName);
if (nameLength < candidateNameLength) {
if (strstr(candidateName, name) == candidateName) {
if (candidateName[nameLength] == '.') {
owner = candidate;
}
}
}
}
});
return owner;
}
#define APPLE_PCREATE_BAD_SYMBOLICATOR 0x0F000001
#define APPLE_PCREATE_BAD_ARCHITECTURE 0x0F000002
static struct ps_prochandle* createProcAndSymbolicator(pid_t pid, task_t task, int* perr, bool should_queue_proc_activity_notices) {
struct ps_prochandle* proc = calloc(sizeof(struct ps_prochandle), 1);
proc->current_symbol_owner_generation = 1; proc->status.pr_pid = pid;
(void) pthread_mutex_init(&proc->proc_activity_queue_mutex, NULL);
(void) pthread_cond_init(&proc->proc_activity_queue_cond, NULL);
if (should_queue_proc_activity_notices)
proc->proc_activity_queue_enabled = true;
CSSymbolicatorRef symbolicator = CSSymbolicatorCreateWithTaskFlagsAndNotification(task, kCSSymbolicatorTrackDyldActivity, ^(uint32_t notification_type, CSNotificationData data) {
switch (notification_type) {
case kCSNotificationPing:
dt_dprintf("pid %d: kCSNotificationPing (value: %d)\n", CSSymbolicatorGetPid(data.symbolicator), data.u.ping.value);
if (should_queue_proc_activity_notices)
Pcreate_sync_proc_activity(proc, RD_POSTINIT);
break;
case kCSNotificationInitialized:
dt_dprintf("pid %d: kCSNotificationInitialized\n", CSSymbolicatorGetPid(data.symbolicator));
if (should_queue_proc_activity_notices)
Pcreate_async_proc_activity(proc, RD_PREINIT);
break;
case kCSNotificationDyldLoad:
dt_dprintf("pid %d: kCSNotificationDyldLoad %s\n", CSSymbolicatorGetPid(data.symbolicator), CSSymbolOwnerGetPath(data.u.dyldLoad.symbolOwner));
if (should_queue_proc_activity_notices)
Pcreate_sync_proc_activity(proc, RD_DLACTIVITY);
break;
case kCSNotificationDyldUnload:
dt_dprintf("pid %d: kCSNotificationDyldUnload %s\n", CSSymbolicatorGetPid(data.symbolicator), CSSymbolOwnerGetPath(data.u.dyldLoad.symbolOwner));
break;
case kCSNotificationTimeout:
dt_dprintf("pid %d: kCSNotificationTimeout\n", CSSymbolicatorGetPid(data.symbolicator));
if (should_queue_proc_activity_notices)
Pcreate_async_proc_activity(proc, RD_DYLD_LOST);
break;
case kCSNotificationTaskExit:
dt_dprintf("pid %d: kCSNotificationTaskExit\n", CSSymbolicatorGetPid(data.symbolicator));
if (should_queue_proc_activity_notices)
Pcreate_async_proc_activity(proc, RD_DYLD_EXIT);
break;
case kCSNotificationFini:
dt_dprintf("pid %d: kCSNotificationFini\n", CSSymbolicatorGetPid(data.symbolicator));
break;
default:
dt_dprintf("pid %d: 0x%x UNHANDLED notification from CoreSymbolication\n", CSSymbolicatorGetPid(data.symbolicator), notification_type);
}
});
if (!CSIsNull(symbolicator)) {
proc->symbolicator = symbolicator; proc->status.pr_dmodel = CSArchitectureIs64Bit(CSSymbolicatorGetArchitecture(symbolicator)) ? PR_MODEL_LP64 : PR_MODEL_ILP32;
} else {
free(proc);
proc = NULL;
*perr = APPLE_PCREATE_BAD_SYMBOLICATOR;
}
return proc;
}
struct ps_prochandle *
Pcreate(const char *file,
char *const *argv,
int *perr,
char *path,
size_t len,
cpu_type_t arch)
{
struct ps_prochandle* proc = NULL;
int pid;
posix_spawnattr_t attr;
task_t task;
*perr = posix_spawnattr_init(&attr);
if (0 != *perr) goto destroy_attr;
if (arch != CPU_TYPE_ANY) {
*perr = posix_spawnattr_setbinpref_np(&attr, 1, &arch, NULL);
if (0 != *perr) goto destroy_attr;
}
*perr = posix_spawnattr_setflags(&attr, POSIX_SPAWN_START_SUSPENDED);
if (0 != *perr) goto destroy_attr;
setenv("DYLD_INSERT_LIBRARIES", "/usr/lib/dtrace/libdtrace_dyld.dylib", 1);
*perr = posix_spawnp(&pid, file, NULL, &attr, argv, *_NSGetEnviron());
unsetenv("DYLD_INSERT_LIBRARIES");
destroy_attr:
posix_spawnattr_destroy(&attr);
if (0 == *perr) {
*perr = task_for_pid(mach_task_self(), pid, &task);
if (*perr == KERN_SUCCESS) {
proc = createProcAndSymbolicator(pid, task, perr, true);
} else {
*perr = -(*perr); }
} else if (*perr == EBADARCH) {
*perr = APPLE_PCREATE_BAD_ARCHITECTURE;
}
return proc;
}
const char *
Pcreate_error(int error)
{
const char *str;
switch (error) {
case C_FORK:
str = "cannot fork";
break;
case C_PERM:
str = "file is set-id or unreadable [Note: the '-c' option requires a full pathname to the file]\n";
break;
case C_NOEXEC:
str = "cannot execute file";
break;
case C_INTR:
str = "operation interrupted";
break;
case C_LP64:
str = "program is _LP64, self is not";
break;
case C_STRANGE:
str = "unanticipated system error";
break;
case C_NOENT:
str = "cannot find executable file";
break;
case APPLE_PCREATE_BAD_SYMBOLICATOR:
str = "Could not create symbolicator for task";
break;
case APPLE_PCREATE_BAD_ARCHITECTURE:
str = "requested architecture missing from executable";
break;
default:
if (error < 0)
str = mach_error_string(-error);
else
str = "unknown error";
break;
}
return (str);
}
#define APPLE_PGRAB_BAD_SYMBOLICATOR 0x0F0F0F0E
#define APPLE_PGRAB_UNSUPPORTED_FLAGS 0x0F0F0F0F
struct ps_prochandle *Pgrab(pid_t pid, int flags, int *perr) {
struct ps_prochandle* proc = NULL;
if (flags & PGRAB_RDONLY || (0 == flags)) {
task_t task;
*perr = task_for_pid(mach_task_self(), pid, &task);
if (*perr == KERN_SUCCESS) {
if (0 == (flags & PGRAB_RDONLY))
(void)task_suspend(task);
proc = createProcAndSymbolicator(pid, task, perr, (flags & PGRAB_RDONLY) ? false : true);
}
} else {
*perr = APPLE_PGRAB_UNSUPPORTED_FLAGS;
}
return proc;
}
const char *Pgrab_error(int err) {
const char* str;
switch (err) {
case APPLE_PGRAB_BAD_SYMBOLICATOR:
str = "Pgrab could not create symbolicator for pid";
case APPLE_PGRAB_UNSUPPORTED_FLAGS:
str = "Pgrab was called with unsupported flags";
default:
str = mach_error_string(err);
}
return str;
}
void Prelease(struct ps_prochandle *P, int flags) {
if (0 == flags) {
if (P->status.pr_flags & PR_KLC)
(void)kill(P->status.pr_pid, SIGKILL);
} else if (flags & PRELEASE_KILL) {
(void)kill(P->status.pr_pid, SIGKILL);
} else if (flags & PRELEASE_HANG)
(void)kill(P->status.pr_pid, SIGSTOP);
pthread_mutex_lock(&P->proc_activity_queue_mutex);
P->proc_activity_queue_enabled = false;
struct ps_proc_activity_event* temp = P->proc_activity_queue;
while (temp != NULL) {
struct ps_proc_activity_event* next = temp->next;
Pdestroy_proc_activity(temp);
temp = next;
}
pthread_mutex_unlock(&P->proc_activity_queue_mutex);
CSRelease(P->symbolicator);
(void) pthread_mutex_destroy(&P->proc_activity_queue_mutex);
(void) pthread_cond_destroy(&P->proc_activity_queue_cond);
free(P);
}
int Psetbkpt(struct ps_prochandle *P, uintptr_t addr, ulong_t *instr) {
return 0;
}
int Pdelbkpt(struct ps_prochandle *P, uintptr_t addr, ulong_t instr) {
return 0;
}
int Pxecbkpt(struct ps_prochandle *P, ulong_t instr) {
return 0;
}
int Psetflags(struct ps_prochandle *P, long flags) {
P->status.pr_flags |= flags;
return 0;
}
int Punsetflags(struct ps_prochandle *P, long flags) {
P->status.pr_flags &= ~flags;
return 0;
}
int pr_open(struct ps_prochandle *P, const char *foo, int bar, mode_t baz) {
printf("libProc.a UNIMPLEMENTED: pr_open()");
return 0;
}
int pr_close(struct ps_prochandle *P, int foo) {
printf("libProc.a UNIMPLEMENTED: pr_close");
return 0;
}
int pr_ioctl(struct ps_prochandle *P, int foo, int bar, void *baz, size_t blah) {
printf("libProc.a UNIMPLEMENTED: pr_ioctl");
return 0;
}
int Pxlookup_by_name(
struct ps_prochandle *P,
Lmid_t lmid,
const char *oname,
const char *sname,
GElf_Sym *symp,
prsyminfo_t *sip)
{
int err = -1;
__block CSSymbolRef symbol = kCSNull;
if (oname != NULL) {
CSSymbolOwnerRef owner = symbolOwnerForName(P->symbolicator, oname);
if (_dtrace_mangled) {
CSSymbolOwnerForeachSymbolWithMangledName(owner, sname, ^(CSSymbolRef s) { if (CSIsNull(symbol)) symbol = s; });
} else {
CSSymbolOwnerForeachSymbolWithName(owner, sname, ^(CSSymbolRef s) { if (CSIsNull(symbol)) symbol = s; });
}
} else {
if (_dtrace_mangled) {
CSSymbolicatorForeachSymbolWithMangledNameAtTime(P->symbolicator, sname, kCSNow, ^(CSSymbolRef s) { if (CSIsNull(symbol)) symbol = s; });
} else {
CSSymbolicatorForeachSymbolWithNameAtTime(P->symbolicator, sname, kCSNow, ^(CSSymbolRef s) { if (CSIsNull(symbol)) symbol = s; });
}
}
if (!CSIsNull(symbol)) {
if (CSSymbolIsDyldStub(symbol)) symbol = kCSNull;
if (!CSSymbolIsFunction(symbol)) symbol = kCSNull;
}
if (!CSIsNull(symbol)) {
err = 0;
if (symp) {
CSRange addressRange = CSSymbolGetRange(symbol);
symp->st_name = 0;
symp->st_info = GELF_ST_INFO((STB_GLOBAL), (STT_FUNC));
symp->st_other = 0;
symp->st_shndx = SHN_MACHO;
symp->st_value = addressRange.location;
symp->st_size = addressRange.length;
}
if (sip) {
sip->prs_lmid = LM_ID_BASE;
}
}
return err;
}
int
Pxlookup_by_addr(
struct ps_prochandle *P,
mach_vm_address_t addr,
char *sym_name_buffer,
size_t bufsize,
GElf_Sym *symbolp,
prsyminfo_t *sip)
{
int err = -1;
CSSymbolRef symbol = CSSymbolicatorGetSymbolWithAddressAtTime(P->symbolicator, (mach_vm_address_t)addr, kCSNow);
if (!CSIsNull(symbol)) {
if (CSSymbolIsUnnamed(symbol)) {
if (CSArchitectureIs64Bit(CSSymbolOwnerGetArchitecture(CSSymbolGetSymbolOwner(symbol))))
snprintf(sym_name_buffer, bufsize, "0x%016llx", CSSymbolGetRange(symbol).location);
else
snprintf(sym_name_buffer, bufsize, "0x%08llx", CSSymbolGetRange(symbol).location);
} else {
if (_dtrace_mangled) {
const char *mangledName = CSSymbolGetMangledName(symbol);
if (strlen(mangledName) >= 3 &&
mangledName[0] == '_' &&
mangledName[1] == '_' &&
mangledName[2] == 'Z') {
strncpy(sym_name_buffer, mangledName, bufsize);
} else {
strncpy(sym_name_buffer, CSSymbolGetName(symbol), bufsize);
}
} else
strncpy(sym_name_buffer, CSSymbolGetName(symbol), bufsize);
}
err = 0;
if (symbolp) {
CSRange addressRange = CSSymbolGetRange(symbol);
symbolp->st_name = 0;
symbolp->st_info = GELF_ST_INFO((STB_GLOBAL), (STT_FUNC));
symbolp->st_other = 0;
symbolp->st_shndx = SHN_MACHO;
symbolp->st_value = addressRange.location;
symbolp->st_size = addressRange.length;
}
if (sip) {
CSSymbolOwnerRef owner = CSSymbolGetSymbolOwner(symbol);
sip->prs_name = (bufsize == 0 ? NULL : sym_name_buffer);
sip->prs_object = CSSymbolOwnerGetName(owner);
sip->prs_lmid = LM_ID_BASE;
}
}
return err;
}
int Plookup_by_addr(struct ps_prochandle *P, mach_vm_address_t addr, char *buf, size_t size, GElf_Sym *symp) {
return Pxlookup_by_addr(P, addr, buf, size, symp, NULL);
}
int Psetrun(struct ps_prochandle *P,
int sig,
int flags )
{
if (P->status.pr_flags & PR_KLC)
return kill(P->status.pr_pid, SIGCONT); else
return (int)task_resume(CSSymbolicatorGetTask(P->symbolicator));
}
ssize_t Pread(struct ps_prochandle *P, void *buf, size_t nbyte, mach_vm_address_t address) {
vm_offset_t mapped_address;
mach_msg_type_number_t mapped_size;
ssize_t bytes_read = 0;
kern_return_t err = mach_vm_read(CSSymbolicatorGetTask(P->symbolicator), (mach_vm_address_t)address, (mach_vm_size_t)nbyte, &mapped_address, &mapped_size);
if (! err) {
bytes_read = nbyte;
memcpy(buf, (void*)mapped_address, nbyte);
vm_deallocate(mach_task_self(), (vm_address_t)mapped_address, (vm_size_t)mapped_size);
}
return bytes_read;
}
int Pobject_iter(struct ps_prochandle *P, proc_map_f *func, void *cd) {
__block int err = 0;
CSSymbolicatorForeachSymbolOwnerAtTime(P->symbolicator, kCSNow, ^(CSSymbolOwnerRef owner) {
uintptr_t generation = CSSymbolOwnerGetTransientUserData(owner);
if (generation == 0 || generation == P->current_symbol_owner_generation) {
if (generation == 0)
CSSymbolOwnerSetTransientUserData(owner, P->current_symbol_owner_generation);
if (err) return;
prmap_t map;
const char* name = CSSymbolOwnerGetName(owner);
map.pr_vaddr = CSSymbolOwnerGetBaseAddress(owner);
map.pr_mflags = MA_READ;
err = func(cd, &map, name);
}
});
return err;
}
const prmap_t *Paddr_to_map(struct ps_prochandle *P, mach_vm_address_t addr, prmap_t* map) {
CSSymbolOwnerRef owner = CSSymbolicatorGetSymbolOwnerWithAddressAtTime(P->symbolicator, addr, kCSNow);
if (!CSIsNull(owner)) {
map->pr_vaddr = CSSymbolOwnerGetBaseAddress(owner);
map->pr_mflags = MA_READ;
return map;
}
return NULL;
}
const prmap_t *Pname_to_map(struct ps_prochandle *P, const char *name, prmap_t* map) {
return (Plmid_to_map(P, PR_LMID_EVERY, name, map));
}
const prmap_t *Plmid_to_map(struct ps_prochandle *P, Lmid_t ignored, const char *cname, prmap_t* map) {
if (cname == PR_OBJ_LDSO)
cname = "dyld";
CSSymbolOwnerRef owner = symbolOwnerForName(P->symbolicator, cname);
if (!CSIsNull(owner)) {
map->pr_vaddr = CSSymbolOwnerGetBaseAddress(owner);
map->pr_mflags = MA_READ;
return map;
}
return NULL;
}
char *Pobjname(struct ps_prochandle *P, mach_vm_address_t addr, char *buffer, size_t bufsize) {
CSSymbolOwnerRef owner = CSSymbolicatorGetSymbolOwnerWithAddressAtTime(P->symbolicator, addr, kCSNow);
if (!CSIsNull(owner)) {
strncpy(buffer, CSSymbolOwnerGetPath(owner), bufsize);
buffer[bufsize-1] = 0; return buffer;
}
buffer[0] = 0;
return NULL;
}
int Plmid(struct ps_prochandle *P, mach_vm_address_t addr, Lmid_t *lmidp) {
*lmidp = LM_ID_BASE;
return 0;
}
int Pobjc_method_iter(struct ps_prochandle *P, proc_objc_f *func, void *cd) {
__block int err = 0;
CSSymbolicatorForeachSymbolOwnerAtTime(P->symbolicator, kCSNow, ^(CSSymbolOwnerRef owner) {
uintptr_t generation = CSSymbolOwnerGetTransientUserData(owner);
if (generation == 0 || generation == P->current_symbol_owner_generation) {
if (generation == 0)
CSSymbolOwnerSetTransientUserData(owner, P->current_symbol_owner_generation);
if (err) return;
CSSymbolOwnerForeachSymbol(owner, ^(CSSymbolRef symbol) {
if (err) return;
if (CSSymbolIsObjcMethod(symbol)) {
GElf_Sym gelf_sym;
CSRange addressRange = CSSymbolGetRange(symbol);
gelf_sym.st_name = 0;
gelf_sym.st_info = GELF_ST_INFO((STB_GLOBAL), (STT_FUNC));
gelf_sym.st_other = 0;
gelf_sym.st_shndx = SHN_MACHO;
gelf_sym.st_value = addressRange.location;
gelf_sym.st_size = addressRange.length;
const char* symbolName = CSSymbolGetName(symbol);
size_t symbolNameLength = strlen(symbolName);
size_t split_index = 0;
while (symbolName[split_index] != ' ' && symbolName[split_index] != 0)
split_index++;
if (split_index < symbolNameLength) {
char backingStore[256];
char* className = (symbolNameLength < sizeof(backingStore)) ? backingStore : malloc(symbolNameLength);
size_t classNameLength = &symbolName[split_index] - &symbolName[2];
strncpy(className, &symbolName[2], classNameLength);
char* methodName = &className[classNameLength];
*methodName++ = 0; *methodName++ = symbolName[0]; size_t methodNameLength = &symbolName[symbolNameLength] - &symbolName[split_index+1] - 1;
strncpy(methodName, &symbolName[split_index+1], methodNameLength);
methodName[methodNameLength] = 0; methodName -= 1;
err = func(cd, &gelf_sym, className, methodName);
if (className != backingStore)
free(className);
}
}
});
}
});
return err;
}
int Psymbol_iter_by_addr(struct ps_prochandle *P, const char *object_name, int which, int mask, proc_sym_f *func, void *cd) {
__block int err = 0;
if (which != PR_SYMTAB)
return err;
CSSymbolOwnerRef owner = symbolOwnerForName(P->symbolicator, object_name);
if (!CSIsNull(owner)) {
uintptr_t generation = CSSymbolOwnerGetTransientUserData(owner);
if (generation == 0 || generation == P->current_symbol_owner_generation) {
if (generation == 0)
CSSymbolOwnerSetTransientUserData(owner, P->current_symbol_owner_generation);
CSSymbolOwnerForeachSymbol(owner, ^(CSSymbolRef symbol) {
if (err)
return;
if (CSSymbolIsDyldStub(symbol)) return;
if (CSSymbolIsUnnamed(symbol)) return;
if ((mask & TYPE_FUNC) && !CSSymbolIsFunction(symbol))
return;
GElf_Sym gelf_sym;
CSRange addressRange = CSSymbolGetRange(symbol);
gelf_sym.st_name = 0;
gelf_sym.st_info = GELF_ST_INFO((STB_GLOBAL), (STT_FUNC));
gelf_sym.st_other = 0;
gelf_sym.st_shndx = SHN_MACHO;
gelf_sym.st_value = addressRange.location;
gelf_sym.st_size = addressRange.length;
const char *mangledName;
if (_dtrace_mangled &&
(mangledName = CSSymbolGetMangledName(symbol)) &&
strlen(mangledName) >= 3 &&
mangledName[0] == '_' &&
mangledName[1] == '_' &&
mangledName[2] == 'Z') {
err = func(cd, &gelf_sym, mangledName);
} else {
err = func(cd, &gelf_sym, CSSymbolGetName(symbol));
}
});
}
} else {
err = -1;
}
return err;
}
void Pupdate_maps(struct ps_prochandle *P) {
}
void Pcheckpoint_syms(struct ps_prochandle *P) {
P->current_symbol_owner_generation++;
}
void Pupdate_syms(struct ps_prochandle *P) {
}
const char *Ppltdest(struct ps_prochandle *P, mach_vm_address_t addr) {
const char* err = NULL;
CSSymbolRef symbol = CSSymbolicatorGetSymbolWithAddressAtTime(P->symbolicator, addr, kCSNow);
if (!CSIsNull(symbol) && (CSSymbolIsDyldStub(symbol) || !CSSymbolIsFunction(symbol)))
err = "Ppltdest is not implemented";
return err;
}
rd_agent_t *Prd_agent(struct ps_prochandle *P) {
return (rd_agent_t *)P; }
void Penqueue_proc_activity(struct ps_prochandle* P, struct ps_proc_activity_event* activity)
{
pthread_mutex_lock(&P->proc_activity_queue_mutex);
if (P->proc_activity_queue_enabled) {
if (P->proc_activity_queue) {
struct ps_proc_activity_event* temp = P->proc_activity_queue;
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = activity;
} else {
P->proc_activity_queue = activity;
}
} else {
Pdestroy_proc_activity(activity);
}
pthread_cond_broadcast(&P->proc_activity_queue_cond);
pthread_mutex_unlock(&P->proc_activity_queue_mutex);
}
void Pcreate_async_proc_activity(struct ps_prochandle* P, rd_event_e type)
{
struct ps_proc_activity_event* activity = malloc(sizeof(struct ps_proc_activity_event));
activity->rd_event.type = type;
activity->rd_event.u.state = RD_CONSISTENT;
activity->synchronous = false;
activity->destroyed = false;
activity->next = NULL;
Penqueue_proc_activity(P, activity);
}
void Pcreate_sync_proc_activity(struct ps_prochandle* P, rd_event_e type)
{
struct ps_proc_activity_event activity;
activity.rd_event.type = type;
activity.rd_event.u.state = RD_CONSISTENT;
activity.synchronous = true;
activity.destroyed = false;
activity.next = NULL;
pthread_mutex_init(&activity.synchronous_mutex, NULL);
pthread_cond_init(&activity.synchronous_cond, NULL);
Penqueue_proc_activity(P, &activity);
pthread_mutex_lock(&activity.synchronous_mutex);
while (!activity.destroyed) {
pthread_cond_wait(&activity.synchronous_cond, &activity.synchronous_mutex);
}
pthread_mutex_unlock(&activity.synchronous_mutex);
pthread_mutex_destroy(&activity.synchronous_mutex);
pthread_cond_destroy(&activity.synchronous_cond);
return;
}
void* Pdequeue_proc_activity(struct ps_prochandle* P)
{
struct ps_proc_activity_event* ret = NULL;
pthread_mutex_lock(&P->proc_activity_queue_mutex);
while (P->proc_activity_queue_enabled && !P->proc_activity_queue)
pthread_cond_wait(&P->proc_activity_queue_cond, &P->proc_activity_queue_mutex);
if ((ret = P->proc_activity_queue)) {
P->proc_activity_queue = ret->next;
P->rd_event = ret->rd_event;
}
pthread_mutex_unlock(&P->proc_activity_queue_mutex);
if (ret && (ret->rd_event.type == RD_NONE)) {
Pdestroy_proc_activity((void*)ret);
ret = NULL;
}
return ret;
}
void Pdestroy_proc_activity(void* opaque)
{
if (opaque) {
struct ps_proc_activity_event* activity = (struct ps_proc_activity_event*)opaque;
if (activity->synchronous) {
pthread_mutex_lock(&activity->synchronous_mutex);
activity->destroyed = true;
pthread_cond_broadcast(&activity->synchronous_cond);
pthread_mutex_unlock(&activity->synchronous_mutex);
} else {
free(activity);
}
}
}
rd_err_e rd_event_getmsg(rd_agent_t *oo7, rd_event_msg_t *rdm) {
struct ps_prochandle *P = (struct ps_prochandle *)oo7;
*rdm = P->rd_event;
return RD_OK;
}
psaddr_t rd_event_mock_addr(struct ps_prochandle *P)
{
return (psaddr_t)(P->rd_event.type);
}
rd_err_e rd_event_enable(rd_agent_t *oo7, int onoff) {
return RD_OK;
}
rd_err_e rd_event_addr(rd_agent_t *oo7, rd_event_e ev, rd_notify_t *rdn)
{
rdn->type = RD_NOTIFY_BPT;
rdn->u.bptaddr = (psaddr_t)ev;
return RD_OK;
}
char *rd_errstr(rd_err_e err) {
switch (err) {
case RD_ERR:
return "RD_ERR";
case RD_OK:
return "RD_OK";
case RD_NOCAPAB:
return "RD_NOCAPAB";
case RD_DBERR:
return "RD_DBERR";
case RD_NOBASE:
return "RD_NOBASE";
case RD_NODYNAM:
return "RD_NODYNAM";
case RD_NOMAPS:
return "RD_NOMAPS";
default:
return "RD_UNKNOWN";
}
}
extern int proc_pidinfo(int pid, int flavor, uint64_t arg, void *buffer, int buffersize);
int Pstate(struct ps_prochandle *P) {
int retval = 0;
struct proc_bsdinfo pbsd;
if (P->rd_event.type == RD_DYLD_LOST)
return PS_LOST;
if (P->rd_event.type == RD_DYLD_EXIT)
return PS_UNDEAD;
retval = proc_pidinfo(P->status.pr_pid, PROC_PIDTBSDINFO, (uint64_t)0, &pbsd, sizeof(struct proc_bsdinfo));
if (retval == -1) {
return -1;
} else if (retval == 0) {
return PS_LOST;
} else {
switch(pbsd.pbi_status) {
case SIDL:
return PS_IDLE;
case SRUN:
return PS_RUN;
case SSTOP:
return PS_STOP;
case SZOMB:
return PS_UNDEAD;
case SSLEEP:
return PS_RUN;
default:
return -1;
}
}
}
const pstatus_t *Pstatus(struct ps_prochandle *P) {
return &P->status;
}