1.1 --- a/agent/src/os/bsd/libproc_impl.c Wed Mar 13 17:34:29 2013 -0400 1.2 +++ b/agent/src/os/bsd/libproc_impl.c Thu Mar 14 00:33:08 2013 -0700 1.3 @@ -21,12 +21,6 @@ 1.4 * questions. 1.5 * 1.6 */ 1.7 -#include <stdarg.h> 1.8 -#include <stdio.h> 1.9 -#include <stdlib.h> 1.10 -#include <string.h> 1.11 -#include <fcntl.h> 1.12 -#include <thread_db.h> 1.13 #include "libproc_impl.h" 1.14 1.15 static const char* alt_root = NULL; 1.16 @@ -34,61 +28,65 @@ 1.17 1.18 #define SA_ALTROOT "SA_ALTROOT" 1.19 1.20 +off_t ltell(int fd) { 1.21 + return lseek(fd, 0, SEEK_CUR); 1.22 +} 1.23 + 1.24 static void init_alt_root() { 1.25 - if (alt_root_len == -1) { 1.26 - alt_root = getenv(SA_ALTROOT); 1.27 - if (alt_root) { 1.28 - alt_root_len = strlen(alt_root); 1.29 - } else { 1.30 - alt_root_len = 0; 1.31 - } 1.32 - } 1.33 + if (alt_root_len == -1) { 1.34 + alt_root = getenv(SA_ALTROOT); 1.35 + if (alt_root) { 1.36 + alt_root_len = strlen(alt_root); 1.37 + } else { 1.38 + alt_root_len = 0; 1.39 + } 1.40 + } 1.41 } 1.42 1.43 int pathmap_open(const char* name) { 1.44 - int fd; 1.45 - char alt_path[PATH_MAX + 1]; 1.46 + int fd; 1.47 + char alt_path[PATH_MAX + 1]; 1.48 1.49 - init_alt_root(); 1.50 - fd = open(name, O_RDONLY); 1.51 - if (fd >= 0) { 1.52 + init_alt_root(); 1.53 + 1.54 + if (alt_root_len > 0) { 1.55 + strcpy(alt_path, alt_root); 1.56 + strcat(alt_path, name); 1.57 + fd = open(alt_path, O_RDONLY); 1.58 + if (fd >= 0) { 1.59 + print_debug("path %s substituted for %s\n", alt_path, name); 1.60 return fd; 1.61 - } 1.62 + } 1.63 1.64 - if (alt_root_len > 0) { 1.65 + if (strrchr(name, '/')) { 1.66 strcpy(alt_path, alt_root); 1.67 - strcat(alt_path, name); 1.68 + strcat(alt_path, strrchr(name, '/')); 1.69 fd = open(alt_path, O_RDONLY); 1.70 if (fd >= 0) { 1.71 - print_debug("path %s substituted for %s\n", alt_path, name); 1.72 - return fd; 1.73 + print_debug("path %s substituted for %s\n", alt_path, name); 1.74 + return fd; 1.75 } 1.76 - 1.77 - if (strrchr(name, '/')) { 1.78 - strcpy(alt_path, alt_root); 1.79 - strcat(alt_path, strrchr(name, '/')); 1.80 - fd = open(alt_path, O_RDONLY); 1.81 - if (fd >= 0) { 1.82 - print_debug("path %s substituted for %s\n", alt_path, name); 1.83 - return fd; 1.84 - } 1.85 - } 1.86 - } 1.87 - 1.88 - return -1; 1.89 + } 1.90 + } else { 1.91 + fd = open(name, O_RDONLY); 1.92 + if (fd >= 0) { 1.93 + return fd; 1.94 + } 1.95 + } 1.96 + return -1; 1.97 } 1.98 1.99 static bool _libsaproc_debug; 1.100 1.101 void print_debug(const char* format,...) { 1.102 - if (_libsaproc_debug) { 1.103 - va_list alist; 1.104 + if (_libsaproc_debug) { 1.105 + va_list alist; 1.106 1.107 - va_start(alist, format); 1.108 - fputs("libsaproc DEBUG: ", stderr); 1.109 - vfprintf(stderr, format, alist); 1.110 - va_end(alist); 1.111 - } 1.112 + va_start(alist, format); 1.113 + fputs("libsaproc DEBUG: ", stderr); 1.114 + vfprintf(stderr, format, alist); 1.115 + va_end(alist); 1.116 + } 1.117 } 1.118 1.119 void print_error(const char* format,...) { 1.120 @@ -100,172 +98,235 @@ 1.121 } 1.122 1.123 bool is_debug() { 1.124 - return _libsaproc_debug; 1.125 + return _libsaproc_debug; 1.126 } 1.127 1.128 +#ifdef __APPLE__ 1.129 +// get arch offset in file 1.130 +bool get_arch_off(int fd, cpu_type_t cputype, off_t *offset) { 1.131 + struct fat_header fatheader; 1.132 + struct fat_arch fatarch; 1.133 + off_t img_start = 0; 1.134 + 1.135 + off_t pos = ltell(fd); 1.136 + if (read(fd, (void *)&fatheader, sizeof(struct fat_header)) != sizeof(struct fat_header)) { 1.137 + return false; 1.138 + } 1.139 + if (fatheader.magic == FAT_CIGAM) { 1.140 + int i; 1.141 + for (i = 0; i < ntohl(fatheader.nfat_arch); i++) { 1.142 + if (read(fd, (void *)&fatarch, sizeof(struct fat_arch)) != sizeof(struct fat_arch)) { 1.143 + return false; 1.144 + } 1.145 + if (ntohl(fatarch.cputype) == cputype) { 1.146 + print_debug("fat offset=%x\n", ntohl(fatarch.offset)); 1.147 + img_start = ntohl(fatarch.offset); 1.148 + break; 1.149 + } 1.150 + } 1.151 + if (img_start == 0) { 1.152 + return false; 1.153 + } 1.154 + } 1.155 + lseek(fd, pos, SEEK_SET); 1.156 + *offset = img_start; 1.157 + return true; 1.158 +} 1.159 + 1.160 +bool is_macho_file(int fd) { 1.161 + mach_header_64 fhdr; 1.162 + off_t x86_64_off; 1.163 + 1.164 + if (fd < 0) { 1.165 + print_debug("Invalid file handle passed to is_macho_file\n"); 1.166 + return false; 1.167 + } 1.168 + 1.169 + off_t pos = ltell(fd); 1.170 + // check fat header 1.171 + if (!get_arch_off(fd, CPU_TYPE_X86_64, &x86_64_off)) { 1.172 + print_debug("failed to get fat header\n"); 1.173 + return false; 1.174 + } 1.175 + lseek(fd, x86_64_off, SEEK_SET); 1.176 + if (read(fd, (void *)&fhdr, sizeof(mach_header_64)) != sizeof(mach_header_64)) { 1.177 + return false; 1.178 + } 1.179 + lseek(fd, pos, SEEK_SET); // restore 1.180 + print_debug("fhdr.magic %x\n", fhdr.magic); 1.181 + return (fhdr.magic == MH_MAGIC_64 || fhdr.magic == MH_CIGAM_64); 1.182 +} 1.183 + 1.184 +#endif //__APPLE__ 1.185 + 1.186 // initialize libproc 1.187 bool init_libproc(bool debug) { 1.188 - // init debug mode 1.189 _libsaproc_debug = debug; 1.190 - 1.191 +#ifndef __APPLE__ 1.192 // initialize the thread_db library 1.193 if (td_init() != TD_OK) { 1.194 print_debug("libthread_db's td_init failed\n"); 1.195 return false; 1.196 } 1.197 - 1.198 +#endif // __APPLE__ 1.199 return true; 1.200 } 1.201 1.202 -static void destroy_lib_info(struct ps_prochandle* ph) { 1.203 - lib_info* lib = ph->libs; 1.204 - while (lib) { 1.205 - lib_info *next = lib->next; 1.206 - if (lib->symtab) { 1.207 - destroy_symtab(lib->symtab); 1.208 - } 1.209 - free(lib); 1.210 - lib = next; 1.211 - } 1.212 +void destroy_lib_info(struct ps_prochandle* ph) { 1.213 + lib_info* lib = ph->libs; 1.214 + while (lib) { 1.215 + lib_info* next = lib->next; 1.216 + if (lib->symtab) { 1.217 + destroy_symtab(lib->symtab); 1.218 + } 1.219 + free(lib); 1.220 + lib = next; 1.221 + } 1.222 } 1.223 1.224 -static void destroy_thread_info(struct ps_prochandle* ph) { 1.225 - thread_info* thr = ph->threads; 1.226 - while (thr) { 1.227 - thread_info *next = thr->next; 1.228 - free(thr); 1.229 - thr = next; 1.230 - } 1.231 +void destroy_thread_info(struct ps_prochandle* ph) { 1.232 + sa_thread_info* thr = ph->threads; 1.233 + while (thr) { 1.234 + sa_thread_info* n = thr->next; 1.235 + free(thr); 1.236 + thr = n; 1.237 + } 1.238 } 1.239 1.240 // ps_prochandle cleanup 1.241 - 1.242 -// ps_prochandle cleanup 1.243 void Prelease(struct ps_prochandle* ph) { 1.244 - // do the "derived class" clean-up first 1.245 - ph->ops->release(ph); 1.246 - destroy_lib_info(ph); 1.247 - destroy_thread_info(ph); 1.248 - free(ph); 1.249 + // do the "derived class" clean-up first 1.250 + ph->ops->release(ph); 1.251 + destroy_lib_info(ph); 1.252 + destroy_thread_info(ph); 1.253 + free(ph); 1.254 } 1.255 1.256 lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t base) { 1.257 - return add_lib_info_fd(ph, libname, -1, base); 1.258 + return add_lib_info_fd(ph, libname, -1, base); 1.259 } 1.260 1.261 lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, uintptr_t base) { 1.262 lib_info* newlib; 1.263 + print_debug("add_lib_info_fd %s\n", libname); 1.264 1.265 - if ( (newlib = (lib_info*) calloc(1, sizeof(struct lib_info))) == NULL) { 1.266 - print_debug("can't allocate memory for lib_info\n"); 1.267 - return NULL; 1.268 - } 1.269 + if ( (newlib = (lib_info*) calloc(1, sizeof(struct lib_info))) == NULL) { 1.270 + print_debug("can't allocate memory for lib_info\n"); 1.271 + return NULL; 1.272 + } 1.273 1.274 - strncpy(newlib->name, libname, sizeof(newlib->name)); 1.275 - newlib->base = base; 1.276 + strncpy(newlib->name, libname, sizeof(newlib->name)); 1.277 + newlib->base = base; 1.278 1.279 - if (fd == -1) { 1.280 - if ( (newlib->fd = pathmap_open(newlib->name)) < 0) { 1.281 - print_debug("can't open shared object %s\n", newlib->name); 1.282 - free(newlib); 1.283 - return NULL; 1.284 - } 1.285 - } else { 1.286 - newlib->fd = fd; 1.287 - } 1.288 - 1.289 - // check whether we have got an ELF file. /proc/<pid>/map 1.290 - // gives out all file mappings and not just shared objects 1.291 - if (is_elf_file(newlib->fd) == false) { 1.292 - close(newlib->fd); 1.293 + if (fd == -1) { 1.294 + if ( (newlib->fd = pathmap_open(newlib->name)) < 0) { 1.295 + print_debug("can't open shared object %s\n", newlib->name); 1.296 free(newlib); 1.297 return NULL; 1.298 - } 1.299 + } 1.300 + } else { 1.301 + newlib->fd = fd; 1.302 + } 1.303 1.304 - newlib->symtab = build_symtab(newlib->fd); 1.305 - if (newlib->symtab == NULL) { 1.306 - print_debug("symbol table build failed for %s\n", newlib->name); 1.307 - } 1.308 - else { 1.309 - print_debug("built symbol table for %s\n", newlib->name); 1.310 - } 1.311 +#ifdef __APPLE__ 1.312 + // check whether we have got an Macho file. 1.313 + if (is_macho_file(newlib->fd) == false) { 1.314 + close(newlib->fd); 1.315 + free(newlib); 1.316 + print_debug("not a mach-o file\n"); 1.317 + return NULL; 1.318 + } 1.319 +#else 1.320 + // check whether we have got an ELF file. /proc/<pid>/map 1.321 + // gives out all file mappings and not just shared objects 1.322 + if (is_elf_file(newlib->fd) == false) { 1.323 + close(newlib->fd); 1.324 + free(newlib); 1.325 + return NULL; 1.326 + } 1.327 +#endif // __APPLE__ 1.328 1.329 - // even if symbol table building fails, we add the lib_info. 1.330 - // This is because we may need to read from the ELF file for core file 1.331 - // address read functionality. lookup_symbol checks for NULL symtab. 1.332 - if (ph->libs) { 1.333 - ph->lib_tail->next = newlib; 1.334 - ph->lib_tail = newlib; 1.335 - } else { 1.336 - ph->libs = ph->lib_tail = newlib; 1.337 - } 1.338 - ph->num_libs++; 1.339 + newlib->symtab = build_symtab(newlib->fd); 1.340 + if (newlib->symtab == NULL) { 1.341 + print_debug("symbol table build failed for %s\n", newlib->name); 1.342 + } else { 1.343 + print_debug("built symbol table for %s\n", newlib->name); 1.344 + } 1.345 1.346 - return newlib; 1.347 + // even if symbol table building fails, we add the lib_info. 1.348 + // This is because we may need to read from the ELF file or MachO file for core file 1.349 + // address read functionality. lookup_symbol checks for NULL symtab. 1.350 + if (ph->libs) { 1.351 + ph->lib_tail->next = newlib; 1.352 + ph->lib_tail = newlib; 1.353 + } else { 1.354 + ph->libs = ph->lib_tail = newlib; 1.355 + } 1.356 + ph->num_libs++; 1.357 + return newlib; 1.358 } 1.359 1.360 // lookup for a specific symbol 1.361 uintptr_t lookup_symbol(struct ps_prochandle* ph, const char* object_name, 1.362 const char* sym_name) { 1.363 - // ignore object_name. search in all libraries 1.364 - // FIXME: what should we do with object_name?? The library names are obtained 1.365 - // by parsing /proc/<pid>/maps, which may not be the same as object_name. 1.366 - // What we need is a utility to map object_name to real file name, something 1.367 - // dlopen() does by looking at LD_LIBRARY_PATH and /etc/ld.so.cache. For 1.368 - // now, we just ignore object_name and do a global search for the symbol. 1.369 + // ignore object_name. search in all libraries 1.370 + // FIXME: what should we do with object_name?? The library names are obtained 1.371 + // by parsing /proc/<pid>/maps, which may not be the same as object_name. 1.372 + // What we need is a utility to map object_name to real file name, something 1.373 + // dlopen() does by looking at LD_LIBRARY_PATH and /etc/ld.so.cache. For 1.374 + // now, we just ignore object_name and do a global search for the symbol. 1.375 1.376 - lib_info* lib = ph->libs; 1.377 - while (lib) { 1.378 - if (lib->symtab) { 1.379 - uintptr_t res = search_symbol(lib->symtab, lib->base, sym_name, NULL); 1.380 - if (res) return res; 1.381 - } 1.382 - lib = lib->next; 1.383 - } 1.384 + lib_info* lib = ph->libs; 1.385 + while (lib) { 1.386 + if (lib->symtab) { 1.387 + uintptr_t res = search_symbol(lib->symtab, lib->base, sym_name, NULL); 1.388 + if (res) return res; 1.389 + } 1.390 + lib = lib->next; 1.391 + } 1.392 1.393 - print_debug("lookup failed for symbol '%s' in obj '%s'\n", 1.394 + print_debug("lookup failed for symbol '%s' in obj '%s'\n", 1.395 sym_name, object_name); 1.396 - return (uintptr_t) NULL; 1.397 + return (uintptr_t) NULL; 1.398 } 1.399 1.400 - 1.401 const char* symbol_for_pc(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* poffset) { 1.402 - const char* res = NULL; 1.403 - lib_info* lib = ph->libs; 1.404 - while (lib) { 1.405 - if (lib->symtab && addr >= lib->base) { 1.406 - res = nearest_symbol(lib->symtab, addr - lib->base, poffset); 1.407 - if (res) return res; 1.408 - } 1.409 - lib = lib->next; 1.410 - } 1.411 - return NULL; 1.412 + const char* res = NULL; 1.413 + lib_info* lib = ph->libs; 1.414 + while (lib) { 1.415 + if (lib->symtab && addr >= lib->base) { 1.416 + res = nearest_symbol(lib->symtab, addr - lib->base, poffset); 1.417 + if (res) return res; 1.418 + } 1.419 + lib = lib->next; 1.420 + } 1.421 + return NULL; 1.422 } 1.423 1.424 // add a thread to ps_prochandle 1.425 -thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id) { 1.426 - thread_info* newthr; 1.427 - if ( (newthr = (thread_info*) calloc(1, sizeof(thread_info))) == NULL) { 1.428 - print_debug("can't allocate memory for thread_info\n"); 1.429 - return NULL; 1.430 - } 1.431 +sa_thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id) { 1.432 + sa_thread_info* newthr; 1.433 + if ( (newthr = (sa_thread_info*) calloc(1, sizeof(sa_thread_info))) == NULL) { 1.434 + print_debug("can't allocate memory for thread_info\n"); 1.435 + return NULL; 1.436 + } 1.437 1.438 - // initialize thread info 1.439 - newthr->pthread_id = pthread_id; 1.440 - newthr->lwp_id = lwp_id; 1.441 + // initialize thread info 1.442 + newthr->pthread_id = pthread_id; 1.443 + newthr->lwp_id = lwp_id; 1.444 1.445 - // add new thread to the list 1.446 - newthr->next = ph->threads; 1.447 - ph->threads = newthr; 1.448 - ph->num_threads++; 1.449 - return newthr; 1.450 + // add new thread to the list 1.451 + newthr->next = ph->threads; 1.452 + ph->threads = newthr; 1.453 + ph->num_threads++; 1.454 + return newthr; 1.455 } 1.456 1.457 - 1.458 +#ifndef __APPLE__ 1.459 // struct used for client data from thread_db callback 1.460 struct thread_db_client_data { 1.461 - struct ps_prochandle* ph; 1.462 - thread_info_callback callback; 1.463 + struct ps_prochandle* ph; 1.464 + thread_info_callback callback; 1.465 }; 1.466 1.467 // callback function for libthread_db 1.468 @@ -314,6 +375,7 @@ 1.469 return true; 1.470 } 1.471 1.472 +#endif // __APPLE__ 1.473 1.474 // get number of threads 1.475 int get_num_threads(struct ps_prochandle* ph) { 1.476 @@ -322,18 +384,54 @@ 1.477 1.478 // get lwp_id of n'th thread 1.479 lwpid_t get_lwp_id(struct ps_prochandle* ph, int index) { 1.480 - int count = 0; 1.481 - thread_info* thr = ph->threads; 1.482 - while (thr) { 1.483 - if (count == index) { 1.484 - return thr->lwp_id; 1.485 - } 1.486 - count++; 1.487 - thr = thr->next; 1.488 - } 1.489 - return -1; 1.490 + int count = 0; 1.491 + sa_thread_info* thr = ph->threads; 1.492 + while (thr) { 1.493 + if (count == index) { 1.494 + return thr->lwp_id; 1.495 + } 1.496 + count++; 1.497 + thr = thr->next; 1.498 + } 1.499 + return 0; 1.500 } 1.501 1.502 +#ifdef __APPLE__ 1.503 +// set lwp_id of n'th thread 1.504 +bool set_lwp_id(struct ps_prochandle* ph, int index, lwpid_t lwpid) { 1.505 + int count = 0; 1.506 + sa_thread_info* thr = ph->threads; 1.507 + while (thr) { 1.508 + if (count == index) { 1.509 + thr->lwp_id = lwpid; 1.510 + return true; 1.511 + } 1.512 + count++; 1.513 + thr = thr->next; 1.514 + } 1.515 + return false; 1.516 +} 1.517 + 1.518 +// get regs of n-th thread, only used in fillThreads the first time called 1.519 +bool get_nth_lwp_regs(struct ps_prochandle* ph, int index, struct reg* regs) { 1.520 + int count = 0; 1.521 + sa_thread_info* thr = ph->threads; 1.522 + while (thr) { 1.523 + if (count == index) { 1.524 + break; 1.525 + } 1.526 + count++; 1.527 + thr = thr->next; 1.528 + } 1.529 + if (thr != NULL) { 1.530 + memcpy(regs, &thr->regs, sizeof(struct reg)); 1.531 + return true; 1.532 + } 1.533 + return false; 1.534 +} 1.535 + 1.536 +#endif // __APPLE__ 1.537 + 1.538 // get regs for a given lwp 1.539 bool get_lwp_regs(struct ps_prochandle* ph, lwpid_t lwp_id, struct reg* regs) { 1.540 return ph->ops->get_lwp_regs(ph, lwp_id, regs); 1.541 @@ -341,35 +439,35 @@ 1.542 1.543 // get number of shared objects 1.544 int get_num_libs(struct ps_prochandle* ph) { 1.545 - return ph->num_libs; 1.546 + return ph->num_libs; 1.547 } 1.548 1.549 // get name of n'th solib 1.550 const char* get_lib_name(struct ps_prochandle* ph, int index) { 1.551 - int count = 0; 1.552 - lib_info* lib = ph->libs; 1.553 - while (lib) { 1.554 - if (count == index) { 1.555 - return lib->name; 1.556 - } 1.557 - count++; 1.558 - lib = lib->next; 1.559 - } 1.560 - return NULL; 1.561 + int count = 0; 1.562 + lib_info* lib = ph->libs; 1.563 + while (lib) { 1.564 + if (count == index) { 1.565 + return lib->name; 1.566 + } 1.567 + count++; 1.568 + lib = lib->next; 1.569 + } 1.570 + return NULL; 1.571 } 1.572 1.573 // get base address of a lib 1.574 uintptr_t get_lib_base(struct ps_prochandle* ph, int index) { 1.575 - int count = 0; 1.576 - lib_info* lib = ph->libs; 1.577 - while (lib) { 1.578 - if (count == index) { 1.579 - return lib->base; 1.580 - } 1.581 - count++; 1.582 - lib = lib->next; 1.583 - } 1.584 - return (uintptr_t)NULL; 1.585 + int count = 0; 1.586 + lib_info* lib = ph->libs; 1.587 + while (lib) { 1.588 + if (count == index) { 1.589 + return lib->base; 1.590 + } 1.591 + count++; 1.592 + lib = lib->next; 1.593 + } 1.594 + return (uintptr_t)NULL; 1.595 } 1.596 1.597 bool find_lib(struct ps_prochandle* ph, const char *lib_name) { 1.598 @@ -425,6 +523,7 @@ 1.599 va_end(alist); 1.600 } 1.601 1.602 +#ifndef __APPLE__ 1.603 // ------------------------------------------------------------------------ 1.604 // Functions below this point are not yet implemented. They are here only 1.605 // to make the linker happy. 1.606 @@ -458,3 +557,4 @@ 1.607 print_debug("ps_pcontinue not implemented\n"); 1.608 return PS_OK; 1.609 } 1.610 +#endif // __APPLE__