1/*
2 * Copyright (c) 2006-2008 Apple Computer, Inc.  All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <CoreSymbolication/CoreSymbolication.h>
25#include <CoreSymbolication/CoreSymbolicationPrivate.h>
26
27#include <mach/mach.h>
28#include <mach/mach_vm.h>
29#include <mach/mach_error.h>
30#include <servers/bootstrap.h>
31#include <unistd.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <stdbool.h>
35#include <sys/sysctl.h>
36
37// /System//Library/Frameworks/System.framework/Versions/B/PrivateHeaders/sys/proc_info.h
38#include <System/sys/proc_info.h>
39#include <System/sys/codesign.h>
40
41#if !TARGET_OS_EMBEDDED
42#include <System/sys/csr.h>
43#include <sandbox/rootless.h>
44#endif
45
46// This must be done *after* any references to Foundation.h!
47#define uint_t  __Solaris_uint_t
48
49#include "libproc.h"
50#include "libproc_apple.h"
51
52#include <spawn.h>
53#include <pthread.h>
54
55#include <crt_externs.h>
56
57// We cannot import dt_impl.h, so define this here.
58extern void dt_dprintf(const char *, ...);
59
60extern int _dtrace_mangled;
61
62
63/*
64 * Check if DTrace will be able to attach to the process with the current
65 * security configuration. The functions returns true if there is no issue,
66 * otherwise false is returner.
67 */
68bool
69canAttachToProcess(pid_t pid)
70{
71	bool canAttach = true;
72
73	assert(pid != -1);
74
75#if !TARGET_OS_EMBEDDED
76	/*
77	 * If rootless is enabled, ensure that the process is signed with the
78	 * following entitlements: com.apple.security.get-task-allow
79	 */
80	if (csr_check(CSR_ALLOW_TASK_FOR_PID) != 0) {
81		canAttach = rootless_allows_task_for_pid(pid);
82	}
83#endif
84
85	return canAttach;
86}
87
88/*
89 * This is a helper method, it does extended lookups following roughly these rules
90 *
91 * 1. An exact match (i.e. a full pathname): "/usr/lib/libc.so.1"
92 * 2. An exact basename match: "libc.so.1"
93 * 3. An initial basename match up to a '.' suffix: "libc.so" or "libc"
94 * 4. The literal string "a.out" is an alias for the executable mapping
95 */
96CSSymbolOwnerRef symbolOwnerForName(CSSymbolicatorRef symbolicator, const char* name) {
97	// Check for a.out specifically
98	if (strcmp(name, "a.out") == 0) {
99		__block CSSymbolOwnerRef owner = kCSNull;
100		if (CSSymbolicatorForeachSymbolOwnerWithFlagsAtTime(symbolicator, kCSSymbolOwnerIsAOut, kCSNow, ^(CSSymbolOwnerRef t) { owner = t; }) == 1) {
101			return owner;
102		}
103
104		return kCSNull;
105	}
106
107	// Try path based matching. Multile matches are legal, take the first.
108	__block CSSymbolOwnerRef owner = kCSNull;
109	if (CSSymbolicatorForeachSymbolOwnerWithPathAtTime(symbolicator, name, kCSNow, ^(CSSymbolOwnerRef t) { if (CSIsNull(owner)) owner = t; }) > 0)
110		return owner;
111
112	// Try name based matching. Multiple matches are legal, take the first.
113	if (CSSymbolicatorForeachSymbolOwnerWithNameAtTime(symbolicator, name, kCSNow, ^(CSSymbolOwnerRef t) { if (CSIsNull(owner)) owner = t; }) > 0)
114		return owner;
115
116	// Strip off extensions. We know there are no direct matches now.
117	size_t nameLength = strlen(name);
118	CSSymbolicatorForeachSymbolOwnerAtTime(symbolicator, kCSNow, ^(CSSymbolOwnerRef candidate) {
119		// We check CSIsNull to skip remaining work after finding a match.
120		if (CSIsNull(owner)) {
121			const char* candidateName = CSSymbolOwnerGetName(candidate);
122			size_t candidateNameLength = strlen(candidateName);
123
124			// We're going to cheat a bit.
125			//
126			// A match at this point will always be a prefix match. I.E. libSystem match against libSystem.B.dylib
127			// We make the following assertions
128			// 1) For a match to be possible, the candidate must always be longer than the search name
129			// 2) The match must always begin at the root of the candidate name
130			// 3) The next character in the candidate must be a '.'
131			if (nameLength < candidateNameLength) {
132				if (strstr(candidateName, name) == candidateName) {
133					if (candidateName[nameLength] == '.') {
134						// Its a match!
135						owner = candidate;
136					}
137				}
138			}
139		}
140	});
141
142	return owner;
143}
144
145#define APPLE_PCREATE_BAD_SYMBOLICATOR		0x0F000001
146#define APPLE_PCREATE_BAD_ARCHITECTURE		0x0F000002
147#define APPLE_EXECUTABLE_RESTRICTED		0x0F000003
148#define APPLE_EXECUTABLE_NOT_ATTACHABLE		0x0F000004
149
150//
151// Helper function so that Pcreate & Pgrab can use the same code.
152//
153// NOTE!
154//
155// We're doing something really hideous here.
156//
157// For each target process, there are *two* threads created. A dtrace control thread, and a CoreSymbolication
158// dyld listener thread. The listener thread does not directly call into dtrace. The reason is that the thread
159// calling into dtrace sometimes gets put to sleep. If dtrace decides to release/deallocate due to a notice
160// from the listener thread, it deadlocks waiting for the listener to acknowledge that it has shut down.
161static struct ps_prochandle* createProcAndSymbolicator(pid_t pid, task_t task, int* perr, bool should_queue_proc_activity_notices) {
162	// The symbolicator block captures proc, and actually uses it before completing.
163	// We allocate and initialize it first.
164	struct ps_prochandle* proc = calloc(sizeof(struct ps_prochandle), 1);
165	proc->current_symbol_owner_generation = 1; // MUST start with generation of 1 or higher.
166	proc->status.pr_pid = pid;
167
168	(void) pthread_mutex_init(&proc->proc_activity_queue_mutex, NULL);
169	(void) pthread_cond_init(&proc->proc_activity_queue_cond, NULL);
170
171	// Only enable this if we're going to generate events...
172	if (should_queue_proc_activity_notices)
173		proc->proc_activity_queue_enabled = true;
174
175	CSSymbolicatorRef symbolicator = CSSymbolicatorCreateWithTaskFlagsAndNotification(task, kCSSymbolicatorTrackDyldActivity, ^(uint32_t notification_type, CSNotificationData data) {
176		switch (notification_type) {
177			case kCSNotificationPing:
178				dt_dprintf("pid %d: kCSNotificationPing (value: %d)\n", CSSymbolicatorGetPid(data.symbolicator), data.u.ping.value);
179				// We're faking a "POSTINIT" breakpoint here.
180				if (should_queue_proc_activity_notices)
181					Pcreate_sync_proc_activity(proc, RD_POSTINIT);
182				break;
183
184			case kCSNotificationInitialized:
185				dt_dprintf("pid %d: kCSNotificationInitialized\n", CSSymbolicatorGetPid(data.symbolicator));
186				// We're faking a "PREINIT" breakpoint here. NOTE! The target is not actually suspended at this point. Racey!
187				if (should_queue_proc_activity_notices)
188					Pcreate_async_proc_activity(proc, RD_PREINIT);
189				break;
190
191			case kCSNotificationDyldLoad:
192				dt_dprintf("pid %d: kCSNotificationDyldLoad %s\n", CSSymbolicatorGetPid(data.symbolicator), CSSymbolOwnerGetPath(data.u.dyldLoad.symbolOwner));
193				if (should_queue_proc_activity_notices)
194					Pcreate_sync_proc_activity(proc, RD_DLACTIVITY);
195				break;
196
197			case kCSNotificationDyldUnload:
198				dt_dprintf("pid %d: kCSNotificationDyldUnload %s\n", CSSymbolicatorGetPid(data.symbolicator), CSSymbolOwnerGetPath(data.u.dyldLoad.symbolOwner));
199				break;
200
201			case kCSNotificationTimeout:
202				dt_dprintf("pid %d: kCSNotificationTimeout\n", CSSymbolicatorGetPid(data.symbolicator));
203				if (should_queue_proc_activity_notices)
204					Pcreate_async_proc_activity(proc, RD_DYLD_LOST);
205				break;
206
207			case kCSNotificationTaskExit:
208				dt_dprintf("pid %d: kCSNotificationTaskExit\n", CSSymbolicatorGetPid(data.symbolicator));
209				if (should_queue_proc_activity_notices)
210					Pcreate_async_proc_activity(proc, RD_DYLD_EXIT);
211				break;
212
213			case kCSNotificationFini:
214				dt_dprintf("pid %d: kCSNotificationFini\n", CSSymbolicatorGetPid(data.symbolicator));
215				break;
216
217			default:
218				dt_dprintf("pid %d: 0x%x UNHANDLED notification from CoreSymbolication\n", CSSymbolicatorGetPid(data.symbolicator), notification_type);
219		}
220	});
221	if (!CSIsNull(symbolicator)) {
222		proc->symbolicator = symbolicator; // Starts with a retain count of 1
223		proc->status.pr_dmodel = CSArchitectureIs64Bit(CSSymbolicatorGetArchitecture(symbolicator)) ? PR_MODEL_LP64 : PR_MODEL_ILP32;
224	} else {
225		free(proc);
226		proc = NULL;
227		*perr = APPLE_PCREATE_BAD_SYMBOLICATOR;
228	}
229
230	return proc;
231}
232
233struct ps_prochandle *
234Pcreate(const char *file,	/* executable file name */
235        char *const *argv,	/* argument vector */
236        int *perr,		    /* pointer to error return code */
237        char *path,		    /* if non-null, holds exec path name on return */
238        size_t len, 	    /* size of the path buffer */
239        cpu_type_t arch)    /* architecture to launch */
240{
241	struct ps_prochandle* proc = NULL;
242
243	int pid;
244	posix_spawnattr_t attr;
245	task_t task;
246	uint32_t flags;
247
248	*perr = posix_spawnattr_init(&attr);
249	if (0 != *perr) goto destroy_attr;
250
251	if (arch != CPU_TYPE_ANY) {
252		*perr = posix_spawnattr_setbinpref_np(&attr, 1, &arch, NULL);
253		if (0 != *perr) goto destroy_attr;
254	}
255
256	*perr = posix_spawnattr_setflags(&attr, POSIX_SPAWN_START_SUSPENDED);
257	if (0 != *perr) goto destroy_attr;
258
259	setenv("DYLD_INSERT_LIBRARIES", "/usr/lib/dtrace/libdtrace_dyld.dylib", 1);
260
261	*perr = posix_spawnp(&pid, file, NULL, &attr, argv, *_NSGetEnviron());
262
263	unsetenv("DYLD_INSERT_LIBRARIES"); /* children must not have this present in their env */
264
265destroy_attr:
266	posix_spawnattr_destroy(&attr);
267
268	if (0 == *perr) {
269		/*
270		 * <rdar://problem/13969762>:
271		 * If the process is signed with restricted entitlements, the libdtrace_dyld
272		 * library will not be injected in the process. In this case we kill the
273		 * process and report an error.
274		 */
275		if (csops(pid, CS_OPS_STATUS, &flags, sizeof(flags)) != -1
276			&& (flags & CS_RESTRICT))
277		{
278			if (kill(pid, SIGKILL))
279				perror("kill()");
280			*perr = APPLE_EXECUTABLE_RESTRICTED;
281			return NULL;
282		}
283
284		/*
285		 * Check if DTrace will be able to attach to the process.
286		 */
287		if (!canAttachToProcess(pid)) {
288			*perr = APPLE_EXECUTABLE_NOT_ATTACHABLE;
289			return NULL;
290		}
291
292
293		*perr = task_for_pid(mach_task_self(), pid, &task);
294		if (*perr == KERN_SUCCESS) {
295			proc = createProcAndSymbolicator(pid, task, perr, true);
296		} else {
297			*perr = -(*perr); // Make room for mach errors
298		}
299	} else if (*perr == EBADARCH) {
300		*perr = APPLE_PCREATE_BAD_ARCHITECTURE;
301	}
302
303	return proc;
304}
305
306/*
307 * Return a printable string corresponding to a Pcreate() error return.
308 */
309const char *
310Pcreate_error(int error)
311{
312	const char *str;
313
314	switch (error) {
315		case C_FORK:
316			str = "cannot fork";
317			break;
318		case C_PERM:
319			str = "file is set-id or unreadable [Note: the '-c' option requires a full pathname to the file]\n";
320			break;
321		case C_NOEXEC:
322			str = "cannot execute file";
323			break;
324		case C_INTR:
325			str = "operation interrupted";
326			break;
327		case C_LP64:
328			str = "program is _LP64, self is not";
329			break;
330		case C_STRANGE:
331			str = "unanticipated system error";
332			break;
333		case C_NOENT:
334			str = "cannot find executable file";
335			break;
336		case APPLE_PCREATE_BAD_SYMBOLICATOR:
337			str = "Could not create symbolicator for task";
338			break;
339		case APPLE_PCREATE_BAD_ARCHITECTURE:
340			str = "requested architecture missing from executable";
341			break;
342		case APPLE_EXECUTABLE_RESTRICTED:
343			str = "dtrace cannot control executables signed with restricted entitlements";
344			break;
345		case APPLE_EXECUTABLE_NOT_ATTACHABLE:
346			str= "the current security restriction (rootless enabled) prevent dtrace from attaching to an executable not signed "
347			     "with the [com.apple.security.get-task-allow] entitlement";
348		default:
349			if (error < 0)
350				str = mach_error_string(-error);
351			else
352				str = "unknown error";
353			break;
354	}
355
356	return (str);
357}
358
359
360/*
361 * Grab an existing process.
362 * Return an opaque pointer to its process control structure.
363 *
364 * pid:		UNIX process ID.
365 * flags:
366 *	PGRAB_RETAIN	Retain tracing flags (default clears all tracing flags).
367 *	PGRAB_FORCE	Grab regardless of whether process is already traced.
368 *	PGRAB_RDONLY	Open the address space file O_RDONLY instead of O_RDWR,
369 *                      and do not open the process control file.
370 *	PGRAB_NOSTOP	Open the process but do not force it to stop.
371 * perr:	pointer to error return code.
372 */
373/*
374 * APPLE NOTE:
375 *
376 * We don't seem to have an equivalent to the tracing
377 * flag(s), so we're also going to punt on them for now.
378 */
379
380#define APPLE_PGRAB_BAD_SYMBOLICATOR  0x0F0F0F0E
381#define APPLE_PGRAB_UNSUPPORTED_FLAGS 0x0F0F0F0F
382
383struct ps_prochandle *Pgrab(pid_t pid, int flags, int *perr) {
384	struct ps_prochandle* proc = NULL;
385
386	if (flags & PGRAB_RDONLY || (0 == flags)) {
387		task_t task;
388
389		/*
390		 * Check if DTrace will be able to attach to the process.
391		 */
392		if (!canAttachToProcess(pid)) {
393			*perr = APPLE_EXECUTABLE_NOT_ATTACHABLE;
394			return NULL;
395		}
396
397		*perr = task_for_pid(mach_task_self(), pid, &task);
398		if (*perr == KERN_SUCCESS) {
399			if (0 == (flags & PGRAB_RDONLY))
400				(void)task_suspend(task);
401
402			proc = createProcAndSymbolicator(pid, task, perr, (flags & PGRAB_RDONLY) ? false : true);
403		}
404	} else {
405		*perr = APPLE_PGRAB_UNSUPPORTED_FLAGS;
406	}
407
408	return proc;
409}
410
411const char *Pgrab_error(int err) {
412	const char* str;
413
414	switch (err) {
415		case APPLE_PGRAB_BAD_SYMBOLICATOR:
416			str = "Pgrab could not create symbolicator for pid";
417			break;
418		case APPLE_PGRAB_UNSUPPORTED_FLAGS:
419			str = "Pgrab was called with unsupported flags";
420			break;
421		case APPLE_EXECUTABLE_NOT_ATTACHABLE:
422			str = "the current security restriction (rootless enabled) prevent dtrace from attaching to an executable not signed "
423			      "with the [com.apple.security.get-task-allow] entitlement";
424			break;
425		default:
426			str = mach_error_string(err);
427	}
428
429	return str;
430}
431
432/*
433 * Release the process.  Frees the process control structure.
434 * flags:
435 *	PRELEASE_CLEAR	Clear all tracing flags.
436 *	PRELEASE_RETAIN	Retain current tracing flags.
437 *	PRELEASE_HANG	Leave the process stopped and abandoned.
438 *	PRELEASE_KILL	Terminate the process with SIGKILL.
439 */
440/*
441 * APPLE NOTE:
442 *
443 * We're ignoring most flags for now. They will eventually need to be honored.
444 */
445void Prelease(struct ps_prochandle *P, int flags) {
446	if (0 == flags) {
447		if (P->status.pr_flags & PR_KLC)
448			(void)kill(P->status.pr_pid, SIGKILL);
449	} else if (flags & PRELEASE_KILL) {
450		(void)kill(P->status.pr_pid, SIGKILL);
451	} else if (flags & PRELEASE_HANG)
452		(void)kill(P->status.pr_pid, SIGSTOP);
453
454	// Shouldn't be leaking events. Do this before releasing the symbolicator,
455	// so the dyld activity thread isn't blocked waiting on an event.
456	pthread_mutex_lock(&P->proc_activity_queue_mutex);
457	// Prevent any new events from being queue'd
458	P->proc_activity_queue_enabled = false;
459	// Destroy any existing events.
460	struct ps_proc_activity_event* temp = P->proc_activity_queue;
461	while (temp != NULL) {
462		struct ps_proc_activity_event* next = temp->next;
463		Pdestroy_proc_activity(temp);
464		temp = next;
465	}
466	pthread_mutex_unlock(&P->proc_activity_queue_mutex);
467
468	// We don't have to check for kCSNull...
469	CSRelease(P->symbolicator);
470
471	(void) pthread_mutex_destroy(&P->proc_activity_queue_mutex);
472	(void) pthread_cond_destroy(&P->proc_activity_queue_cond);
473
474	free(P);
475}
476
477/*
478 * APPLE NOTE:
479 *
480 * These low-level breakpoint functions are no-ops. We expect dyld to make RPC
481 * calls to give us roughly the same functionality.
482 *
483 */
484int Psetbkpt(struct ps_prochandle *P, uintptr_t addr, ulong_t *instr) {
485	return 0;
486}
487
488int Pdelbkpt(struct ps_prochandle *P, uintptr_t addr, ulong_t instr) {
489	return 0;
490}
491
492int	Pxecbkpt(struct ps_prochandle *P, ulong_t instr) {
493	return 0;
494}
495
496/*
497 * APPLE NOTE:
498 *
499 * Psetflags/Punsetflags has three caller values at this time.
500 * PR_KLC - proc kill on last close
501 * PR_RLC - proc resume/run on last close
502 * PR_BPTAD - x86 only, breakpoint adjust eip
503 *
504 * We are not supporting any of these at this time.
505 */
506
507int Psetflags(struct ps_prochandle *P, long flags) {
508	P->status.pr_flags |= flags;
509	return 0;
510}
511
512int Punsetflags(struct ps_prochandle *P, long flags) {
513	P->status.pr_flags &= ~flags;
514	return 0;
515}
516
517int pr_open(struct ps_prochandle *P, const char *foo, int bar, mode_t baz) {
518	printf("libProc.a UNIMPLEMENTED: pr_open()");
519	return 0;
520}
521
522int pr_close(struct ps_prochandle *P, int foo) {
523	printf("libProc.a UNIMPLEMENTED: pr_close");
524	return 0;
525}
526
527int pr_ioctl(struct ps_prochandle *P, int foo, int bar, void *baz, size_t blah) {
528	printf("libProc.a UNIMPLEMENTED: pr_ioctl");
529	return 0;
530}
531
532/*
533 * Search the process symbol tables looking for a symbol whose name matches the
534 * specified name and whose object and link map optionally match the specified
535 * parameters.  On success, the function returns 0 and fills in the GElf_Sym
536 * symbol table entry.  On failure, -1 is returned.
537 */
538/*
539 * APPLE NOTE:
540 *
541 * We're completely blowing off the lmid.
542 *
543 * It looks like the only GElf_Sym entries used are value & size.
544 * Most of the time, prsyminfo_t is null, and when it is used, only
545 * prs_lmid is set.
546 */
547int Pxlookup_by_name(
548		     struct ps_prochandle *P,
549		     Lmid_t lmid,		/* link map to match, or -1 (PR_LMID_EVERY) for any */
550		     const char *oname,		/* load object name */
551		     const char *sname,		/* symbol name */
552		     GElf_Sym *symp,		/* returned symbol table entry */
553		     prsyminfo_t *sip)		/* returned symbol info */
554{
555	int err = -1;
556
557	__block CSSymbolRef symbol = kCSNull;
558	if (oname != NULL) {
559		CSSymbolOwnerRef owner = symbolOwnerForName(P->symbolicator, oname);
560		if (_dtrace_mangled) {
561			CSSymbolOwnerForeachSymbolWithMangledName(owner, sname, ^(CSSymbolRef s) { if (CSIsNull(symbol)) symbol = s; });
562		} else {
563			CSSymbolOwnerForeachSymbolWithName(owner, sname, ^(CSSymbolRef s) { if (CSIsNull(symbol)) symbol = s; });
564		}
565	} else {
566		if (_dtrace_mangled) {
567			CSSymbolicatorForeachSymbolWithMangledNameAtTime(P->symbolicator, sname, kCSNow, ^(CSSymbolRef s) { if (CSIsNull(symbol)) symbol = s; });
568		} else {
569			CSSymbolicatorForeachSymbolWithNameAtTime(P->symbolicator, sname, kCSNow, ^(CSSymbolRef s) { if (CSIsNull(symbol)) symbol = s; });
570		}
571	}
572
573	// Filter out symbols we do not want to instrument
574	if (!CSIsNull(symbol)) {
575		if (CSSymbolIsDyldStub(symbol)) symbol = kCSNull;
576		if (!CSSymbolIsFunction(symbol)) symbol = kCSNull;
577	}
578
579	if (!CSIsNull(symbol)) {
580		err = 0;
581
582		if (symp) {
583			CSRange addressRange = CSSymbolGetRange(symbol);
584
585			symp->st_name = 0;
586			symp->st_info = GELF_ST_INFO((STB_GLOBAL), (STT_FUNC));
587#if defined(__arm__) || defined(__arm64__)
588			if (CSSymbolIsArm(symbol)) {
589				symp->st_arch_subinfo = 1;
590			} else {
591				symp->st_arch_subinfo = 2;
592			}
593#endif
594			symp->st_other = 0;
595			symp->st_shndx = SHN_MACHO;
596			symp->st_value = addressRange.location;
597			symp->st_size = addressRange.length;
598		}
599
600		if (sip) {
601			sip->prs_lmid = LM_ID_BASE;
602		}
603	}
604
605	return err;
606}
607
608
609/*
610 * Search the process symbol tables looking for a symbol whose
611 * value to value+size contain the address specified by addr.
612 * Return values are:
613 *	sym_name_buffer containing the symbol name
614 *	GElf_Sym symbol table entry
615 *	prsyminfo_t ancillary symbol information
616 * Returns 0 on success, -1 on failure.
617 */
618/*
619 * APPLE NOTE:
620 *
621 * This function is called directly by the plockstat binary and it passes the
622 * psyminfo_t argument We only set fields that plockstat actually uses.
623 * sip->prs_table and sip->prs_id are not used by plockstat so we don't
624 * attempt to set them.
625 */
626int
627Pxlookup_by_addr(
628                 struct ps_prochandle *P,
629                 mach_vm_address_t addr,			/* process address being sought */
630                 char *sym_name_buffer,		/* buffer for the symbol name */
631                 size_t bufsize,		/* size of sym_name_buffer */
632                 GElf_Sym *symbolp,		/* returned symbol table entry */
633                 prsyminfo_t *sip)		/* returned symbol info (used only by plockstat) */
634{
635	int err = -1;
636
637	CSSymbolRef symbol = CSSymbolicatorGetSymbolWithAddressAtTime(P->symbolicator, (mach_vm_address_t)addr, kCSNow);
638
639	// See comments in Ppltdest()
640	// Filter out symbols we do not want to instrument
641	// if ([symbol isDyldStub]) symbol = nil;
642	// if (![symbol isFunction]) symbol = nil;
643
644	if (!CSIsNull(symbol)) {
645		if (CSSymbolIsUnnamed(symbol)) {
646			if (CSArchitectureIs64Bit(CSSymbolOwnerGetArchitecture(CSSymbolGetSymbolOwner(symbol))))
647				snprintf(sym_name_buffer, bufsize, "0x%016llx", CSSymbolGetRange(symbol).location);
648			else
649				snprintf(sym_name_buffer, bufsize, "0x%08llx", CSSymbolGetRange(symbol).location);
650		} else {
651			if (_dtrace_mangled) {
652				const char *mangledName = CSSymbolGetMangledName(symbol);
653				if (strlen(mangledName) >= 3 &&
654				    mangledName[0] == '_' &&
655				    mangledName[1] == '_' &&
656				    mangledName[2] == 'Z') {
657					// mangled name - use it
658					strncpy(sym_name_buffer, mangledName, bufsize);
659				} else {
660					strncpy(sym_name_buffer, CSSymbolGetName(symbol), bufsize);
661				}
662			} else
663				strncpy(sym_name_buffer, CSSymbolGetName(symbol), bufsize);
664		}
665		err = 0;
666
667		if (symbolp) {
668			CSRange addressRange = CSSymbolGetRange(symbol);
669
670			symbolp->st_name = 0;
671			symbolp->st_info = GELF_ST_INFO((STB_GLOBAL), (STT_FUNC));
672			symbolp->st_other = 0;
673#if defined(__arm__) || defined(__arm64__)
674			if (CSSymbolIsArm(symbol)) {
675				symbolp->st_arch_subinfo = 1;
676			} else {
677				symbolp->st_arch_subinfo = 2;
678			}
679#endif
680			symbolp->st_shndx = SHN_MACHO;
681			symbolp->st_value = addressRange.location;
682			symbolp->st_size = addressRange.length;
683		}
684
685		if (sip) {
686			CSSymbolOwnerRef owner = CSSymbolGetSymbolOwner(symbol);
687			sip->prs_name = (bufsize == 0 ? NULL : sym_name_buffer);
688
689			sip->prs_object = CSSymbolOwnerGetName(owner);
690
691			// APPLE: The following fields set by Solaris code are not used by
692			// plockstat, hence we don't return them.
693			//sip->prs_id = (symp == sym1p) ? i1 : i2;
694			//sip->prs_table = (symp == sym1p) ? PR_SYMTAB : PR_DYNSYM;
695
696			// FIXME:!!!
697			//sip->prs_lmid = (fptr->file_lo == NULL) ? LM_ID_BASE : fptr->file_lo->rl_lmident;
698			sip->prs_lmid = LM_ID_BASE;
699		}
700	}
701
702	return err;
703}
704
705
706int Plookup_by_addr(struct ps_prochandle *P, mach_vm_address_t addr, char *buf, size_t size, GElf_Sym *symp) {
707	return Pxlookup_by_addr(P, addr, buf, size, symp, NULL);
708}
709
710/*
711 * APPLE NOTE:
712 *
713 * We're just calling task_resume(). Returns 0 on success, -1 on failure.
714 */
715int Psetrun(struct ps_prochandle *P,
716	    int sig,	/* Ignored in OS X. Nominally supposed to be the signal passed to the target process */
717	    int flags	/* Ignored in OS X. PRSTEP|PRSABORT|PRSTOP|PRCSIG|PRCFAULT */)
718{
719	/* If PR_KLC is set, we created the process with posix_spawn(); otherwise we grabbed it with task_suspend. */
720	if (P->status.pr_flags & PR_KLC)
721		return kill(P->status.pr_pid, SIGCONT); // Advances BSD p_stat from SSTOP to SRUN
722	else
723		return (int)task_resume(CSSymbolicatorGetTask(P->symbolicator));
724}
725
726ssize_t Pread(struct ps_prochandle *P, void *buf, size_t nbyte, mach_vm_address_t address) {
727	vm_offset_t mapped_address;
728	mach_msg_type_number_t mapped_size;
729	ssize_t bytes_read = 0;
730
731	kern_return_t err = mach_vm_read(CSSymbolicatorGetTask(P->symbolicator), (mach_vm_address_t)address, (mach_vm_size_t)nbyte, &mapped_address, &mapped_size);
732	if (! err) {
733		bytes_read = nbyte;
734		memcpy(buf, (void*)mapped_address, nbyte);
735		vm_deallocate(mach_task_self(), (vm_address_t)mapped_address, (vm_size_t)mapped_size);
736	}
737
738	return bytes_read;
739}
740
741int Pobject_iter(struct ps_prochandle *P, proc_map_f *func, void *cd) {
742	__block int err = 0;
743
744	CSSymbolicatorForeachSymbolOwnerAtTime(P->symbolicator, kCSNow, ^(CSSymbolOwnerRef owner) {
745
746		// We work through "generations of symbol owners. At any given point, we only want to
747		// look at what has changed since the last processing attempt. Dyld may load library after
748		// library with the same load timestamp. So we mark the symbol owners with a "generation"
749		// and only look at those that are unmarked, or are the current generation.
750		uintptr_t generation = CSSymbolOwnerGetTransientUserData(owner);
751		if (generation == 0 || generation == P->current_symbol_owner_generation) {
752			if (generation == 0)
753				CSSymbolOwnerSetTransientUserData(owner, P->current_symbol_owner_generation);
754
755			if (err) return; // skip everything after error
756
757			prmap_t map;
758			const char* name = CSSymbolOwnerGetName(owner);
759			map.pr_vaddr = CSSymbolOwnerGetBaseAddress(owner);
760			map.pr_mflags = MA_READ;
761
762			err = func(cd, &map, name);
763		}
764	});
765
766	return err;
767}
768
769// The solaris version of XYZ_to_map() didn't require the prmap_t* map argument.
770// They relied on their backing store to allocate and manage the prmap_t's. We don't
771// have an equivalent, and these are cheaper to fill in on the fly than to store.
772
773const prmap_t *Paddr_to_map(struct ps_prochandle *P, mach_vm_address_t addr, prmap_t* map) {
774	CSSymbolOwnerRef owner = CSSymbolicatorGetSymbolOwnerWithAddressAtTime(P->symbolicator, addr, kCSNow);
775
776	// <rdar://problem/4877551>
777	if (!CSIsNull(owner)) {
778		map->pr_vaddr = CSSymbolOwnerGetBaseAddress(owner);
779		map->pr_mflags = MA_READ; // Anything we get from a symbolicator is readable
780
781		return map;
782	}
783
784	return NULL;
785}
786
787const prmap_t *Pname_to_map(struct ps_prochandle *P, const char *name, prmap_t* map) {
788	return (Plmid_to_map(P, PR_LMID_EVERY, name, map));
789}
790
791/*
792 * Given a shared object name, return the map_info_t for it.  If no matching
793 * object is found, return NULL.  Normally, the link maps contain the full
794 * object pathname, e.g. /usr/lib/libc.so.1.  We allow the object name to
795 * take one of the following forms:
796 *
797 * 1. An exact match (i.e. a full pathname): "/usr/lib/libc.so.1"
798 * 2. An exact basename match: "libc.so.1"
799 * 3. An initial basename match up to a '.' suffix: "libc.so" or "libc"
800 * 4. The literal string "a.out" is an alias for the executable mapping
801 *
802 * The third case is a convenience for callers and may not be necessary.
803 *
804 * As the exact same object name may be loaded on different link maps (see
805 * dlmopen(3DL)), we also allow the caller to resolve the object name by
806 * specifying a particular link map id.  If lmid is PR_LMID_EVERY, the
807 * first matching name will be returned, regardless of the link map id.
808 */
809/*
810 * APPLE NOTE:
811 *
812 * It appears there are only 3 uses of this currently. A check for ld.so (dtrace fails against static exe's),
813 * and a test for a.out'ness. dtrace looks up the map for a.out, and the map for the module, and makes sure
814 * they share the same v_addr.
815 */
816
817const prmap_t *Plmid_to_map(struct ps_prochandle *P, Lmid_t ignored, const char *cname, prmap_t* map) {
818	// Need to handle some special case defines
819	if (cname == PR_OBJ_LDSO)
820		cname = "dyld";
821
822	CSSymbolOwnerRef owner = symbolOwnerForName(P->symbolicator, cname);
823	// CSSymbolOwnerRef owner = CSSymbolicatorGetSymbolOwnerWithNameAtTime(P->symbolicator, cname, kCSNow);
824
825	// <rdar://problem/4877551>
826	if (!CSIsNull(owner)) {
827		map->pr_vaddr = CSSymbolOwnerGetBaseAddress(owner);
828		map->pr_mflags = MA_READ; // Anything we get from a symbolicator is readable
829
830		return map;
831	}
832
833	return NULL;
834}
835
836/*
837 * Given a virtual address, return the name of the underlying
838 * mapped object (file), as provided by the dynamic linker.
839 * Return NULL on failure (no underlying shared library).
840 */
841char *Pobjname(struct ps_prochandle *P, mach_vm_address_t addr, char *buffer, size_t bufsize) {
842	CSSymbolOwnerRef owner = CSSymbolicatorGetSymbolOwnerWithAddressAtTime(P->symbolicator, addr, kCSNow);
843	if (!CSIsNull(owner)) {
844		strncpy(buffer, CSSymbolOwnerGetPath(owner), bufsize);
845		buffer[bufsize-1] = 0; // Make certain buffer is NULL terminated.
846		return buffer;
847	}
848	buffer[0] = 0;
849	return NULL;
850}
851
852/*
853 * Given a virtual address, return the link map id of the underlying mapped
854 * object (file), as provided by the dynamic linker.  Return -1 on failure.
855 */
856/*
857 * APPLE NOTE:
858 *
859 * We are treating everything as being in the base map, so no work is needed.
860 */
861int Plmid(struct ps_prochandle *P, mach_vm_address_t addr, Lmid_t *lmidp) {
862	*lmidp = LM_ID_BASE;
863	return 0;
864}
865
866/*
867 * This is an Apple only proc method. It is used by the objc provider,
868 * to iterate all classes and methods.
869 */
870int Pobjc_method_iter(struct ps_prochandle *P, proc_objc_f *func, void *cd) {
871	__block int err = 0;
872	CSSymbolicatorForeachSymbolOwnerAtTime(P->symbolicator, kCSNow, ^(CSSymbolOwnerRef owner) {
873		// We work through "generations of symbol owners. At any given point, we only want to
874		// look at what has changed since the last processing attempt. Dyld may load library after
875		// library with the same load timestamp. So we mark the symbol owners with a "generation"
876		// and only look at those that are unmarked, or are the current generation.
877		uintptr_t generation = CSSymbolOwnerGetTransientUserData(owner);
878		if (generation == 0 || generation == P->current_symbol_owner_generation) {
879			if (generation == 0)
880				CSSymbolOwnerSetTransientUserData(owner, P->current_symbol_owner_generation);
881
882			if (err) return; // Have to bail out on error condition
883
884			CSSymbolOwnerForeachSymbol(owner, ^(CSSymbolRef symbol) {
885
886				if (err) return; // Have to bail out on error condition
887
888				if (CSSymbolIsObjcMethod(symbol)) {
889					GElf_Sym gelf_sym;
890					CSRange addressRange = CSSymbolGetRange(symbol);
891
892					gelf_sym.st_name = 0;
893					gelf_sym.st_info = GELF_ST_INFO((STB_GLOBAL), (STT_FUNC));
894					gelf_sym.st_other = 0;
895#if defined(__arm__) || defined(__arm64__)
896					if (CSSymbolIsArm(symbol)) {
897						gelf_sym.st_arch_subinfo = 1;
898					} else {
899						gelf_sym.st_arch_subinfo = 2;
900					}
901#endif
902					gelf_sym.st_shndx = SHN_MACHO;
903					gelf_sym.st_value = addressRange.location;
904					gelf_sym.st_size = addressRange.length;
905
906					const char* symbolName = CSSymbolGetName(symbol);
907					size_t symbolNameLength = strlen(symbolName);
908
909					// First find the split point
910					size_t split_index = 0;
911					while (symbolName[split_index] != ' ' && symbolName[split_index] != 0)
912						split_index++;
913
914					if (split_index < symbolNameLength) {
915						// We know the combined length will be +1 byte for an extra NULL, and -3 for  no '[', ']', or ' '
916						char backingStore[256];
917						char* className = (symbolNameLength < sizeof(backingStore)) ? backingStore : malloc(symbolNameLength);
918
919						// Class name range is [2, split_index)
920						size_t classNameLength = &symbolName[split_index] - &symbolName[2];
921						strncpy(className, &symbolName[2], classNameLength);
922
923						// method name range is [split_index+1, length-1)
924						char* methodName = &className[classNameLength];
925						*methodName++ = 0; // Null terminate the className string;
926						*methodName++ = symbolName[0]; // Apply the -/+ instance/class modifier.
927						size_t methodNameLength = &symbolName[symbolNameLength] - &symbolName[split_index+1] - 1;
928						strncpy(methodName, &symbolName[split_index+1], methodNameLength);
929						methodName[methodNameLength] = 0; // Null terminate!
930						methodName -= 1; // Move back to cover the modifier.
931
932						err = func(cd, &gelf_sym, className, methodName);
933
934						// Free any memory we had to allocate
935						if (className != backingStore)
936							free(className);
937					}
938				}
939			});
940		}
941	});
942
943	return err;
944}
945
946/*
947 * APPLE NOTE:
948 *
949 * object_name == CSSymbolOwner name
950 * which == PR_SYMTAB || PR_DYNSYM
951 * mask == BIND_ANY | TYPE_FUNC (Binding type and func vs data?)
952 * cd = caller data, pass through
953 *
954 * If which is not PR_SYMTAB, return success without doing any work
955 * We're ignoring the binding type, but honoring TYPE_FUNC
956 *
957 * Note that we do not actually iterate in address order!
958 */
959
960int Psymbol_iter_by_addr(struct ps_prochandle *P, const char *object_name, int which, int mask, proc_sym_f *func, void *cd) {
961	__block int err = 0;
962
963	if (which != PR_SYMTAB)
964		return err;
965
966	CSSymbolOwnerRef owner = symbolOwnerForName(P->symbolicator, object_name);
967
968	// <rdar://problem/4877551>
969	if (!CSIsNull(owner)) {
970		// We work through "generations of symbol owners. At any given point, we only want to
971		// look at what has changed since the last processing attempt. Dyld may load library after
972		// library with the same load timestamp. So we mark the symbol owners with a "generation"
973		// and only look at those that are unmarked, or are the current generation.
974		uintptr_t generation = CSSymbolOwnerGetTransientUserData(owner);
975		if (generation == 0 || generation == P->current_symbol_owner_generation) {
976			if (generation == 0)
977				CSSymbolOwnerSetTransientUserData(owner, P->current_symbol_owner_generation);
978
979			CSSymbolOwnerForeachSymbol(owner, ^(CSSymbolRef symbol) {
980				if (err)
981					return; // Bail out on error.
982
983				if (CSSymbolIsDyldStub(symbol)) // We never instrument dyld stubs
984					return;
985
986				if (CSSymbolIsUnnamed(symbol)) // Do not use symbols with NULL names
987					return;
988
989				if ((mask & TYPE_FUNC) && !CSSymbolIsFunction(symbol))
990					return;
991
992				GElf_Sym gelf_sym;
993				CSRange addressRange = CSSymbolGetRange(symbol);
994
995				gelf_sym.st_name = 0;
996				gelf_sym.st_info = GELF_ST_INFO((STB_GLOBAL), (STT_FUNC));
997				gelf_sym.st_other = 0;
998#if defined(__arm__) || defined(__arm64__)
999				if (CSSymbolIsArm(symbol)) {
1000					gelf_sym.st_arch_subinfo = 1;
1001				} else {
1002					gelf_sym.st_arch_subinfo = 2;
1003				}
1004#endif
1005				gelf_sym.st_shndx = SHN_MACHO;
1006				gelf_sym.st_value = addressRange.location;
1007				gelf_sym.st_size = addressRange.length;
1008
1009				const char *mangledName;
1010				if (_dtrace_mangled &&
1011				    (mangledName = CSSymbolGetMangledName(symbol)) &&
1012				    strlen(mangledName) >= 3 &&
1013				    mangledName[0] == '_' &&
1014				    mangledName[1] == '_' &&
1015				    mangledName[2] == 'Z') {
1016					// mangled name - use it
1017					err = func(cd, &gelf_sym, mangledName);
1018				} else {
1019					err = func(cd, &gelf_sym, CSSymbolGetName(symbol));
1020				}
1021			});
1022		}
1023	} else {
1024		// We must fail if the owner cannot be found
1025		err = -1;
1026	}
1027
1028	return err;
1029}
1030
1031void Pupdate_maps(struct ps_prochandle *P) {
1032}
1033
1034//
1035// This method is called after dtrace has handled dyld activity.
1036// It should "checkpoint" the timestamp of the most recently processed library.
1037// Following invocations to "iter_by_xyz()" should only process libraries newer
1038// than the checkpoint time.
1039//
1040void Pcheckpoint_syms(struct ps_prochandle *P) {
1041	// In future iterations of the symbolicator, we will only process symbol owners older than what we have already seen.
1042	P->current_symbol_owner_generation++;
1043}
1044
1045void Pupdate_syms(struct ps_prochandle *P) {
1046}
1047
1048/*
1049 * Given an address, Ppltdest() determines if this is part of a PLT, and if
1050 * so returns a pointer to the symbol name that will be used for resolution.
1051 * If the specified address is not part of a PLT, the function returns NULL.
1052 */
1053/*
1054 * APPLE NOTE:
1055 *
1056 * I believe a PLT is equivalent to our dyld stubs. This method is difficult
1057 * to implement properly, there isn't a good place to free a string allocated
1058 * here. Currently, the only use of this method does not actually use the
1059 * returned string, it simply checks !NULL.
1060 *
1061 * We're cheating in one other way. Plookup_by_addr() is used in dt_pid.c to
1062 * match functions to instrument in the pid provider. For that use, we want to
1063 * screen out (!functions && dyldStubs). However, the stack backtrace also uses
1064 * Plookup_by_addr(), and should be able to find dyldStubs.
1065 *
1066 * Because dt_pid.c calls this method just before lookups, we're going to overload
1067 * it to also screen out !functions.
1068 */
1069const char *Ppltdest(struct ps_prochandle *P, mach_vm_address_t addr) {
1070	const char* err = NULL;
1071
1072	CSSymbolRef symbol = CSSymbolicatorGetSymbolWithAddressAtTime(P->symbolicator, addr, kCSNow);
1073
1074	// Do not allow dyld stubs, !functions, or commpage entries (<rdar://problem/4877551>)
1075	if (!CSIsNull(symbol) && (CSSymbolIsDyldStub(symbol) || !CSSymbolIsFunction(symbol)))
1076		err = "Ppltdest is not implemented";
1077
1078	return err;
1079}
1080
1081rd_agent_t *Prd_agent(struct ps_prochandle *P) {
1082	return (rd_agent_t *)P; // rd_agent_t is type punned onto ps_proc_handle (see below).
1083}
1084
1085void Penqueue_proc_activity(struct ps_prochandle* P, struct ps_proc_activity_event* activity)
1086{
1087	pthread_mutex_lock(&P->proc_activity_queue_mutex);
1088
1089	if (P->proc_activity_queue_enabled) {
1090		// Events are processed in order. Add the new activity to the end.
1091		if (P->proc_activity_queue) {
1092			struct ps_proc_activity_event* temp = P->proc_activity_queue;
1093			while (temp->next != NULL) {
1094				temp = temp->next;
1095			}
1096			temp->next = activity;
1097		} else {
1098			P->proc_activity_queue = activity;
1099		}
1100	} else {
1101		// The queue is disabled. destroy the events.
1102		Pdestroy_proc_activity(activity);
1103	}
1104
1105	pthread_cond_broadcast(&P->proc_activity_queue_cond);
1106	pthread_mutex_unlock(&P->proc_activity_queue_mutex);
1107}
1108
1109void Pcreate_async_proc_activity(struct ps_prochandle* P, rd_event_e type)
1110{
1111	struct ps_proc_activity_event* activity = malloc(sizeof(struct ps_proc_activity_event));
1112
1113	activity->rd_event.type = type;
1114	activity->rd_event.u.state = RD_CONSISTENT;
1115	activity->synchronous = false;
1116	activity->destroyed = false;
1117	activity->next = NULL;
1118
1119	Penqueue_proc_activity(P, activity);
1120}
1121
1122void Pcreate_sync_proc_activity(struct ps_prochandle* P, rd_event_e type)
1123{
1124	// Sync proc activity can use stack allocation.
1125	struct ps_proc_activity_event activity;
1126
1127	activity.rd_event.type = type;
1128	activity.rd_event.u.state = RD_CONSISTENT;
1129	activity.synchronous = true;
1130	activity.destroyed = false;
1131	activity.next = NULL;
1132
1133	pthread_mutex_init(&activity.synchronous_mutex, NULL);
1134	pthread_cond_init(&activity.synchronous_cond, NULL);
1135
1136	Penqueue_proc_activity(P, &activity);
1137
1138	// Now wait for the activity to be processed.
1139	pthread_mutex_lock(&activity.synchronous_mutex);
1140	while (!activity.destroyed) {
1141		pthread_cond_wait(&activity.synchronous_cond, &activity.synchronous_mutex);
1142	}
1143	pthread_mutex_unlock(&activity.synchronous_mutex);
1144
1145	pthread_mutex_destroy(&activity.synchronous_mutex);
1146	pthread_cond_destroy(&activity.synchronous_cond);
1147
1148	return;
1149}
1150
1151void* Pdequeue_proc_activity(struct ps_prochandle* P)
1152{
1153	struct ps_proc_activity_event* ret = NULL;
1154
1155	pthread_mutex_lock(&P->proc_activity_queue_mutex);
1156
1157	while (P->proc_activity_queue_enabled && !P->proc_activity_queue)
1158		pthread_cond_wait(&P->proc_activity_queue_cond, &P->proc_activity_queue_mutex);
1159
1160	// Did we get anything?
1161	if ((ret = P->proc_activity_queue)) {
1162		P->proc_activity_queue = ret->next;
1163		P->rd_event = ret->rd_event;
1164	}
1165
1166	pthread_mutex_unlock(&P->proc_activity_queue_mutex);
1167
1168	// RD_NONE is used to wakeup the control thread.
1169	// Return NULL to indicate that.
1170	if (ret && (ret->rd_event.type == RD_NONE)) {
1171		Pdestroy_proc_activity((void*)ret);
1172		ret = NULL;
1173	}
1174
1175	return ret;
1176}
1177
1178void Pdestroy_proc_activity(void* opaque)
1179{
1180	if (opaque) {
1181		struct ps_proc_activity_event* activity = (struct ps_proc_activity_event*)opaque;
1182
1183		// sync events own their memory, we just notify them.
1184		if (activity->synchronous) {
1185			pthread_mutex_lock(&activity->synchronous_mutex);
1186			activity->destroyed = true;
1187			pthread_cond_broadcast(&activity->synchronous_cond);
1188			pthread_mutex_unlock(&activity->synchronous_mutex);
1189		} else {
1190			free(activity);
1191		}
1192	}
1193}
1194
1195//
1196// Shims for Solaris run-time loader SPI.
1197// The (opaque) rd_agent type is type punned onto ps_prochandle.
1198// "breakpoint" addresses corresponding to rd_events are mapped to the event type (a small enum value),
1199// that's sufficient to uniquely identify the event.
1200//
1201
1202rd_err_e rd_event_getmsg(rd_agent_t *oo7, rd_event_msg_t *rdm) {
1203	struct ps_prochandle *P = (struct ps_prochandle *)oo7;
1204
1205	*rdm = P->rd_event;
1206	return RD_OK;
1207}
1208
1209//
1210// Procedural replacement called from dt_proc_bpmatch() to simulate "psp->pr_reg[R_PC]"
1211//
1212psaddr_t rd_event_mock_addr(struct ps_prochandle *P)
1213{
1214	return (psaddr_t)(P->rd_event.type);
1215}
1216
1217rd_err_e rd_event_enable(rd_agent_t *oo7, int onoff) {
1218	return RD_OK;
1219}
1220
1221rd_err_e rd_event_addr(rd_agent_t *oo7, rd_event_e ev, rd_notify_t *rdn)
1222{
1223	rdn->type = RD_NOTIFY_BPT;
1224	rdn->u.bptaddr = (psaddr_t)ev;
1225
1226	return RD_OK;
1227}
1228
1229char *rd_errstr(rd_err_e err) {
1230	switch (err) {
1231		case RD_ERR:
1232			return "RD_ERR";
1233		case RD_OK:
1234			return "RD_OK";
1235		case RD_NOCAPAB:
1236			return "RD_NOCAPAB";
1237		case RD_DBERR:
1238			return "RD_DBERR";
1239		case RD_NOBASE:
1240			return "RD_NOBASE";
1241		case RD_NODYNAM:
1242			return "RD_NODYNAM";
1243		case RD_NOMAPS:
1244			return "RD_NOMAPS";
1245		default:
1246			return "RD_UNKNOWN";
1247	}
1248	/* NOTREACHED */
1249}
1250
1251extern int proc_pidinfo(int pid, int flavor, uint64_t arg,  void *buffer, int buffersize);
1252
1253int Pstate(struct ps_prochandle *P) {
1254	int retval = 0;
1255	struct proc_bsdinfo pbsd;
1256
1257	// Overloaded usage. If we received an explicity LOST/EXIT, dont querry proc_pidinfo
1258	if (P->rd_event.type == RD_DYLD_LOST)
1259		return PS_LOST;
1260
1261	if (P->rd_event.type == RD_DYLD_EXIT)
1262		return PS_UNDEAD;
1263
1264	retval = proc_pidinfo(P->status.pr_pid, PROC_PIDTBSDINFO, (uint64_t)0, &pbsd, sizeof(struct proc_bsdinfo));
1265	if (retval == -1) {
1266		return -1;
1267	} else if (retval == 0) {
1268		return PS_LOST;
1269	} else {
1270		switch(pbsd.pbi_status) {
1271			case SIDL:
1272				return PS_IDLE;
1273			case SRUN:
1274				return PS_RUN;
1275			case SSTOP:
1276				return PS_STOP;
1277			case SZOMB:
1278				return PS_UNDEAD;
1279			case SSLEEP:
1280				return PS_RUN;
1281			default:
1282				return -1;
1283		}
1284	}
1285	/* NOTREACHED */
1286}
1287
1288const pstatus_t *Pstatus(struct ps_prochandle *P) {
1289	return &P->status;
1290}
1291