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