1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/agent/src/os/bsd/libproc_impl.c Wed Apr 27 01:25:04 2016 +0800 1.3 @@ -0,0 +1,560 @@ 1.4 +/* 1.5 + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.23 + * or visit www.oracle.com if you need additional information or have any 1.24 + * questions. 1.25 + * 1.26 + */ 1.27 +#include "libproc_impl.h" 1.28 + 1.29 +static const char* alt_root = NULL; 1.30 +static int alt_root_len = -1; 1.31 + 1.32 +#define SA_ALTROOT "SA_ALTROOT" 1.33 + 1.34 +off_t ltell(int fd) { 1.35 + return lseek(fd, 0, SEEK_CUR); 1.36 +} 1.37 + 1.38 +static void init_alt_root() { 1.39 + if (alt_root_len == -1) { 1.40 + alt_root = getenv(SA_ALTROOT); 1.41 + if (alt_root) { 1.42 + alt_root_len = strlen(alt_root); 1.43 + } else { 1.44 + alt_root_len = 0; 1.45 + } 1.46 + } 1.47 +} 1.48 + 1.49 +int pathmap_open(const char* name) { 1.50 + int fd; 1.51 + char alt_path[PATH_MAX + 1]; 1.52 + 1.53 + init_alt_root(); 1.54 + 1.55 + if (alt_root_len > 0) { 1.56 + strcpy(alt_path, alt_root); 1.57 + strcat(alt_path, name); 1.58 + fd = open(alt_path, O_RDONLY); 1.59 + if (fd >= 0) { 1.60 + print_debug("path %s substituted for %s\n", alt_path, name); 1.61 + return fd; 1.62 + } 1.63 + 1.64 + if (strrchr(name, '/')) { 1.65 + strcpy(alt_path, alt_root); 1.66 + strcat(alt_path, strrchr(name, '/')); 1.67 + fd = open(alt_path, O_RDONLY); 1.68 + if (fd >= 0) { 1.69 + print_debug("path %s substituted for %s\n", alt_path, name); 1.70 + return fd; 1.71 + } 1.72 + } 1.73 + } else { 1.74 + fd = open(name, O_RDONLY); 1.75 + if (fd >= 0) { 1.76 + return fd; 1.77 + } 1.78 + } 1.79 + return -1; 1.80 +} 1.81 + 1.82 +static bool _libsaproc_debug; 1.83 + 1.84 +void print_debug(const char* format,...) { 1.85 + if (_libsaproc_debug) { 1.86 + va_list alist; 1.87 + 1.88 + va_start(alist, format); 1.89 + fputs("libsaproc DEBUG: ", stderr); 1.90 + vfprintf(stderr, format, alist); 1.91 + va_end(alist); 1.92 + } 1.93 +} 1.94 + 1.95 +void print_error(const char* format,...) { 1.96 + va_list alist; 1.97 + va_start(alist, format); 1.98 + fputs("ERROR: ", stderr); 1.99 + vfprintf(stderr, format, alist); 1.100 + va_end(alist); 1.101 +} 1.102 + 1.103 +bool is_debug() { 1.104 + return _libsaproc_debug; 1.105 +} 1.106 + 1.107 +#ifdef __APPLE__ 1.108 +// get arch offset in file 1.109 +bool get_arch_off(int fd, cpu_type_t cputype, off_t *offset) { 1.110 + struct fat_header fatheader; 1.111 + struct fat_arch fatarch; 1.112 + off_t img_start = 0; 1.113 + 1.114 + off_t pos = ltell(fd); 1.115 + if (read(fd, (void *)&fatheader, sizeof(struct fat_header)) != sizeof(struct fat_header)) { 1.116 + return false; 1.117 + } 1.118 + if (fatheader.magic == FAT_CIGAM) { 1.119 + int i; 1.120 + for (i = 0; i < ntohl(fatheader.nfat_arch); i++) { 1.121 + if (read(fd, (void *)&fatarch, sizeof(struct fat_arch)) != sizeof(struct fat_arch)) { 1.122 + return false; 1.123 + } 1.124 + if (ntohl(fatarch.cputype) == cputype) { 1.125 + print_debug("fat offset=%x\n", ntohl(fatarch.offset)); 1.126 + img_start = ntohl(fatarch.offset); 1.127 + break; 1.128 + } 1.129 + } 1.130 + if (img_start == 0) { 1.131 + return false; 1.132 + } 1.133 + } 1.134 + lseek(fd, pos, SEEK_SET); 1.135 + *offset = img_start; 1.136 + return true; 1.137 +} 1.138 + 1.139 +bool is_macho_file(int fd) { 1.140 + mach_header_64 fhdr; 1.141 + off_t x86_64_off; 1.142 + 1.143 + if (fd < 0) { 1.144 + print_debug("Invalid file handle passed to is_macho_file\n"); 1.145 + return false; 1.146 + } 1.147 + 1.148 + off_t pos = ltell(fd); 1.149 + // check fat header 1.150 + if (!get_arch_off(fd, CPU_TYPE_X86_64, &x86_64_off)) { 1.151 + print_debug("failed to get fat header\n"); 1.152 + return false; 1.153 + } 1.154 + lseek(fd, x86_64_off, SEEK_SET); 1.155 + if (read(fd, (void *)&fhdr, sizeof(mach_header_64)) != sizeof(mach_header_64)) { 1.156 + return false; 1.157 + } 1.158 + lseek(fd, pos, SEEK_SET); // restore 1.159 + print_debug("fhdr.magic %x\n", fhdr.magic); 1.160 + return (fhdr.magic == MH_MAGIC_64 || fhdr.magic == MH_CIGAM_64); 1.161 +} 1.162 + 1.163 +#endif //__APPLE__ 1.164 + 1.165 +// initialize libproc 1.166 +bool init_libproc(bool debug) { 1.167 + _libsaproc_debug = debug; 1.168 +#ifndef __APPLE__ 1.169 + // initialize the thread_db library 1.170 + if (td_init() != TD_OK) { 1.171 + print_debug("libthread_db's td_init failed\n"); 1.172 + return false; 1.173 + } 1.174 +#endif // __APPLE__ 1.175 + return true; 1.176 +} 1.177 + 1.178 +void destroy_lib_info(struct ps_prochandle* ph) { 1.179 + lib_info* lib = ph->libs; 1.180 + while (lib) { 1.181 + lib_info* next = lib->next; 1.182 + if (lib->symtab) { 1.183 + destroy_symtab(lib->symtab); 1.184 + } 1.185 + free(lib); 1.186 + lib = next; 1.187 + } 1.188 +} 1.189 + 1.190 +void destroy_thread_info(struct ps_prochandle* ph) { 1.191 + sa_thread_info* thr = ph->threads; 1.192 + while (thr) { 1.193 + sa_thread_info* n = thr->next; 1.194 + free(thr); 1.195 + thr = n; 1.196 + } 1.197 +} 1.198 + 1.199 +// ps_prochandle cleanup 1.200 +void Prelease(struct ps_prochandle* ph) { 1.201 + // do the "derived class" clean-up first 1.202 + ph->ops->release(ph); 1.203 + destroy_lib_info(ph); 1.204 + destroy_thread_info(ph); 1.205 + free(ph); 1.206 +} 1.207 + 1.208 +lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t base) { 1.209 + return add_lib_info_fd(ph, libname, -1, base); 1.210 +} 1.211 + 1.212 +lib_info* add_lib_info_fd(struct ps_prochandle* ph, const char* libname, int fd, uintptr_t base) { 1.213 + lib_info* newlib; 1.214 + print_debug("add_lib_info_fd %s\n", libname); 1.215 + 1.216 + if ( (newlib = (lib_info*) calloc(1, sizeof(struct lib_info))) == NULL) { 1.217 + print_debug("can't allocate memory for lib_info\n"); 1.218 + return NULL; 1.219 + } 1.220 + 1.221 + strncpy(newlib->name, libname, sizeof(newlib->name)); 1.222 + newlib->base = base; 1.223 + 1.224 + if (fd == -1) { 1.225 + if ( (newlib->fd = pathmap_open(newlib->name)) < 0) { 1.226 + print_debug("can't open shared object %s\n", newlib->name); 1.227 + free(newlib); 1.228 + return NULL; 1.229 + } 1.230 + } else { 1.231 + newlib->fd = fd; 1.232 + } 1.233 + 1.234 +#ifdef __APPLE__ 1.235 + // check whether we have got an Macho file. 1.236 + if (is_macho_file(newlib->fd) == false) { 1.237 + close(newlib->fd); 1.238 + free(newlib); 1.239 + print_debug("not a mach-o file\n"); 1.240 + return NULL; 1.241 + } 1.242 +#else 1.243 + // check whether we have got an ELF file. /proc/<pid>/map 1.244 + // gives out all file mappings and not just shared objects 1.245 + if (is_elf_file(newlib->fd) == false) { 1.246 + close(newlib->fd); 1.247 + free(newlib); 1.248 + return NULL; 1.249 + } 1.250 +#endif // __APPLE__ 1.251 + 1.252 + newlib->symtab = build_symtab(newlib->fd); 1.253 + if (newlib->symtab == NULL) { 1.254 + print_debug("symbol table build failed for %s\n", newlib->name); 1.255 + } else { 1.256 + print_debug("built symbol table for %s\n", newlib->name); 1.257 + } 1.258 + 1.259 + // even if symbol table building fails, we add the lib_info. 1.260 + // This is because we may need to read from the ELF file or MachO file for core file 1.261 + // address read functionality. lookup_symbol checks for NULL symtab. 1.262 + if (ph->libs) { 1.263 + ph->lib_tail->next = newlib; 1.264 + ph->lib_tail = newlib; 1.265 + } else { 1.266 + ph->libs = ph->lib_tail = newlib; 1.267 + } 1.268 + ph->num_libs++; 1.269 + return newlib; 1.270 +} 1.271 + 1.272 +// lookup for a specific symbol 1.273 +uintptr_t lookup_symbol(struct ps_prochandle* ph, const char* object_name, 1.274 + const char* sym_name) { 1.275 + // ignore object_name. search in all libraries 1.276 + // FIXME: what should we do with object_name?? The library names are obtained 1.277 + // by parsing /proc/<pid>/maps, which may not be the same as object_name. 1.278 + // What we need is a utility to map object_name to real file name, something 1.279 + // dlopen() does by looking at LD_LIBRARY_PATH and /etc/ld.so.cache. For 1.280 + // now, we just ignore object_name and do a global search for the symbol. 1.281 + 1.282 + lib_info* lib = ph->libs; 1.283 + while (lib) { 1.284 + if (lib->symtab) { 1.285 + uintptr_t res = search_symbol(lib->symtab, lib->base, sym_name, NULL); 1.286 + if (res) return res; 1.287 + } 1.288 + lib = lib->next; 1.289 + } 1.290 + 1.291 + print_debug("lookup failed for symbol '%s' in obj '%s'\n", 1.292 + sym_name, object_name); 1.293 + return (uintptr_t) NULL; 1.294 +} 1.295 + 1.296 +const char* symbol_for_pc(struct ps_prochandle* ph, uintptr_t addr, uintptr_t* poffset) { 1.297 + const char* res = NULL; 1.298 + lib_info* lib = ph->libs; 1.299 + while (lib) { 1.300 + if (lib->symtab && addr >= lib->base) { 1.301 + res = nearest_symbol(lib->symtab, addr - lib->base, poffset); 1.302 + if (res) return res; 1.303 + } 1.304 + lib = lib->next; 1.305 + } 1.306 + return NULL; 1.307 +} 1.308 + 1.309 +// add a thread to ps_prochandle 1.310 +sa_thread_info* add_thread_info(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id) { 1.311 + sa_thread_info* newthr; 1.312 + if ( (newthr = (sa_thread_info*) calloc(1, sizeof(sa_thread_info))) == NULL) { 1.313 + print_debug("can't allocate memory for thread_info\n"); 1.314 + return NULL; 1.315 + } 1.316 + 1.317 + // initialize thread info 1.318 + newthr->pthread_id = pthread_id; 1.319 + newthr->lwp_id = lwp_id; 1.320 + 1.321 + // add new thread to the list 1.322 + newthr->next = ph->threads; 1.323 + ph->threads = newthr; 1.324 + ph->num_threads++; 1.325 + return newthr; 1.326 +} 1.327 + 1.328 +#ifndef __APPLE__ 1.329 +// struct used for client data from thread_db callback 1.330 +struct thread_db_client_data { 1.331 + struct ps_prochandle* ph; 1.332 + thread_info_callback callback; 1.333 +}; 1.334 + 1.335 +// callback function for libthread_db 1.336 +static int thread_db_callback(const td_thrhandle_t *th_p, void *data) { 1.337 + struct thread_db_client_data* ptr = (struct thread_db_client_data*) data; 1.338 + td_thrinfo_t ti; 1.339 + td_err_e err; 1.340 + 1.341 + memset(&ti, 0, sizeof(ti)); 1.342 + err = td_thr_get_info(th_p, &ti); 1.343 + if (err != TD_OK) { 1.344 + print_debug("libthread_db : td_thr_get_info failed, can't get thread info\n"); 1.345 + return err; 1.346 + } 1.347 + 1.348 + print_debug("thread_db : pthread %d (lwp %d)\n", ti.ti_tid, ti.ti_lid); 1.349 + 1.350 + if (ptr->callback(ptr->ph, (pthread_t)ti.ti_tid, ti.ti_lid) != true) 1.351 + return TD_ERR; 1.352 + 1.353 + return TD_OK; 1.354 +} 1.355 + 1.356 +// read thread_info using libthread_db 1.357 +bool read_thread_info(struct ps_prochandle* ph, thread_info_callback cb) { 1.358 + struct thread_db_client_data mydata; 1.359 + td_thragent_t* thread_agent = NULL; 1.360 + if (td_ta_new(ph, &thread_agent) != TD_OK) { 1.361 + print_debug("can't create libthread_db agent\n"); 1.362 + return false; 1.363 + } 1.364 + 1.365 + mydata.ph = ph; 1.366 + mydata.callback = cb; 1.367 + 1.368 + // we use libthread_db iterator to iterate thru list of threads. 1.369 + if (td_ta_thr_iter(thread_agent, thread_db_callback, &mydata, 1.370 + TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, 1.371 + TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS) != TD_OK) { 1.372 + td_ta_delete(thread_agent); 1.373 + return false; 1.374 + } 1.375 + 1.376 + // delete thread agent 1.377 + td_ta_delete(thread_agent); 1.378 + return true; 1.379 +} 1.380 + 1.381 +#endif // __APPLE__ 1.382 + 1.383 +// get number of threads 1.384 +int get_num_threads(struct ps_prochandle* ph) { 1.385 + return ph->num_threads; 1.386 +} 1.387 + 1.388 +// get lwp_id of n'th thread 1.389 +lwpid_t get_lwp_id(struct ps_prochandle* ph, int index) { 1.390 + int count = 0; 1.391 + sa_thread_info* thr = ph->threads; 1.392 + while (thr) { 1.393 + if (count == index) { 1.394 + return thr->lwp_id; 1.395 + } 1.396 + count++; 1.397 + thr = thr->next; 1.398 + } 1.399 + return 0; 1.400 +} 1.401 + 1.402 +#ifdef __APPLE__ 1.403 +// set lwp_id of n'th thread 1.404 +bool set_lwp_id(struct ps_prochandle* ph, int index, lwpid_t lwpid) { 1.405 + int count = 0; 1.406 + sa_thread_info* thr = ph->threads; 1.407 + while (thr) { 1.408 + if (count == index) { 1.409 + thr->lwp_id = lwpid; 1.410 + return true; 1.411 + } 1.412 + count++; 1.413 + thr = thr->next; 1.414 + } 1.415 + return false; 1.416 +} 1.417 + 1.418 +// get regs of n-th thread, only used in fillThreads the first time called 1.419 +bool get_nth_lwp_regs(struct ps_prochandle* ph, int index, struct reg* regs) { 1.420 + int count = 0; 1.421 + sa_thread_info* thr = ph->threads; 1.422 + while (thr) { 1.423 + if (count == index) { 1.424 + break; 1.425 + } 1.426 + count++; 1.427 + thr = thr->next; 1.428 + } 1.429 + if (thr != NULL) { 1.430 + memcpy(regs, &thr->regs, sizeof(struct reg)); 1.431 + return true; 1.432 + } 1.433 + return false; 1.434 +} 1.435 + 1.436 +#endif // __APPLE__ 1.437 + 1.438 +// get regs for a given lwp 1.439 +bool get_lwp_regs(struct ps_prochandle* ph, lwpid_t lwp_id, struct reg* regs) { 1.440 + return ph->ops->get_lwp_regs(ph, lwp_id, regs); 1.441 +} 1.442 + 1.443 +// get number of shared objects 1.444 +int get_num_libs(struct ps_prochandle* ph) { 1.445 + return ph->num_libs; 1.446 +} 1.447 + 1.448 +// get name of n'th solib 1.449 +const char* get_lib_name(struct ps_prochandle* ph, int index) { 1.450 + int count = 0; 1.451 + lib_info* lib = ph->libs; 1.452 + while (lib) { 1.453 + if (count == index) { 1.454 + return lib->name; 1.455 + } 1.456 + count++; 1.457 + lib = lib->next; 1.458 + } 1.459 + return NULL; 1.460 +} 1.461 + 1.462 +// get base address of a lib 1.463 +uintptr_t get_lib_base(struct ps_prochandle* ph, int index) { 1.464 + int count = 0; 1.465 + lib_info* lib = ph->libs; 1.466 + while (lib) { 1.467 + if (count == index) { 1.468 + return lib->base; 1.469 + } 1.470 + count++; 1.471 + lib = lib->next; 1.472 + } 1.473 + return (uintptr_t)NULL; 1.474 +} 1.475 + 1.476 +bool find_lib(struct ps_prochandle* ph, const char *lib_name) { 1.477 + lib_info *p = ph->libs; 1.478 + while (p) { 1.479 + if (strcmp(p->name, lib_name) == 0) { 1.480 + return true; 1.481 + } 1.482 + p = p->next; 1.483 + } 1.484 + return false; 1.485 +} 1.486 + 1.487 +//-------------------------------------------------------------------------- 1.488 +// proc service functions 1.489 + 1.490 +// ps_pglobal_lookup() looks up the symbol sym_name in the symbol table 1.491 +// of the load object object_name in the target process identified by ph. 1.492 +// It returns the symbol's value as an address in the target process in 1.493 +// *sym_addr. 1.494 + 1.495 +ps_err_e ps_pglobal_lookup(struct ps_prochandle *ph, const char *object_name, 1.496 + const char *sym_name, psaddr_t *sym_addr) { 1.497 + *sym_addr = (psaddr_t) lookup_symbol(ph, object_name, sym_name); 1.498 + return (*sym_addr ? PS_OK : PS_NOSYM); 1.499 +} 1.500 + 1.501 +// read "size" bytes info "buf" from address "addr" 1.502 +ps_err_e ps_pread(struct ps_prochandle *ph, psaddr_t addr, 1.503 + void *buf, size_t size) { 1.504 + return ph->ops->p_pread(ph, (uintptr_t) addr, buf, size)? PS_OK: PS_ERR; 1.505 +} 1.506 + 1.507 +// write "size" bytes of data to debuggee at address "addr" 1.508 +ps_err_e ps_pwrite(struct ps_prochandle *ph, psaddr_t addr, 1.509 + const void *buf, size_t size) { 1.510 + return ph->ops->p_pwrite(ph, (uintptr_t)addr, buf, size)? PS_OK: PS_ERR; 1.511 +} 1.512 + 1.513 +// fill in ptrace_lwpinfo for lid 1.514 +ps_err_e ps_linfo(struct ps_prochandle *ph, lwpid_t lwp_id, void *linfo) { 1.515 + return ph->ops->get_lwp_info(ph, lwp_id, linfo)? PS_OK: PS_ERR; 1.516 +} 1.517 + 1.518 +// needed for when libthread_db is compiled with TD_DEBUG defined 1.519 +void 1.520 +ps_plog (const char *format, ...) 1.521 +{ 1.522 + va_list alist; 1.523 + 1.524 + va_start(alist, format); 1.525 + vfprintf(stderr, format, alist); 1.526 + va_end(alist); 1.527 +} 1.528 + 1.529 +#ifndef __APPLE__ 1.530 +// ------------------------------------------------------------------------ 1.531 +// Functions below this point are not yet implemented. They are here only 1.532 +// to make the linker happy. 1.533 + 1.534 +ps_err_e ps_lsetfpregs(struct ps_prochandle *ph, lwpid_t lid, const prfpregset_t *fpregs) { 1.535 + print_debug("ps_lsetfpregs not implemented\n"); 1.536 + return PS_OK; 1.537 +} 1.538 + 1.539 +ps_err_e ps_lsetregs(struct ps_prochandle *ph, lwpid_t lid, const prgregset_t gregset) { 1.540 + print_debug("ps_lsetregs not implemented\n"); 1.541 + return PS_OK; 1.542 +} 1.543 + 1.544 +ps_err_e ps_lgetfpregs(struct ps_prochandle *ph, lwpid_t lid, prfpregset_t *fpregs) { 1.545 + print_debug("ps_lgetfpregs not implemented\n"); 1.546 + return PS_OK; 1.547 +} 1.548 + 1.549 +ps_err_e ps_lgetregs(struct ps_prochandle *ph, lwpid_t lid, prgregset_t gregset) { 1.550 + print_debug("ps_lgetfpregs not implemented\n"); 1.551 + return PS_OK; 1.552 +} 1.553 + 1.554 +ps_err_e ps_lstop(struct ps_prochandle *ph, lwpid_t lid) { 1.555 + print_debug("ps_lstop not implemented\n"); 1.556 + return PS_OK; 1.557 +} 1.558 + 1.559 +ps_err_e ps_pcontinue(struct ps_prochandle *ph) { 1.560 + print_debug("ps_pcontinue not implemented\n"); 1.561 + return PS_OK; 1.562 +} 1.563 +#endif // __APPLE__