Mon, 28 Oct 2013 21:41:48 +0400
8026950: Nits in agent ps_proc.c file breaks compilation of open hotspot
Summary: Fixed two compilation-breaking nits
Reviewed-by: sla, dholmes
never@3156 | 1 | /* |
rbackman@4599 | 2 | * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. |
never@3156 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
never@3156 | 4 | * |
never@3156 | 5 | * This code is free software; you can redistribute it and/or modify it |
never@3156 | 6 | * under the terms of the GNU General Public License version 2 only, as |
never@3156 | 7 | * published by the Free Software Foundation. |
never@3156 | 8 | * |
never@3156 | 9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
never@3156 | 10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
never@3156 | 11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
never@3156 | 12 | * version 2 for more details (a copy is included in the LICENSE file that |
never@3156 | 13 | * accompanied this code). |
never@3156 | 14 | * |
never@3156 | 15 | * You should have received a copy of the GNU General Public License version |
never@3156 | 16 | * 2 along with this work; if not, write to the Free Software Foundation, |
never@3156 | 17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
never@3156 | 18 | * |
never@3156 | 19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
never@3156 | 20 | * or visit www.oracle.com if you need additional information or have any |
never@3156 | 21 | * questions. |
never@3156 | 22 | * |
never@3156 | 23 | */ |
never@3156 | 24 | |
never@3156 | 25 | #include <limits.h> |
never@3156 | 26 | #include <stdio.h> |
never@3156 | 27 | #include <stdlib.h> |
never@3156 | 28 | #include <string.h> |
never@3156 | 29 | #include <errno.h> |
never@3156 | 30 | #include <sys/types.h> |
never@3156 | 31 | #include <sys/wait.h> |
never@3156 | 32 | #include <sys/ptrace.h> |
never@3156 | 33 | #include <sys/param.h> |
never@3156 | 34 | #include <sys/user.h> |
never@3156 | 35 | #include <elf.h> |
never@3156 | 36 | #include <sys/elf_common.h> |
never@3156 | 37 | #include <sys/link_elf.h> |
never@3156 | 38 | #include <libutil.h> |
never@3156 | 39 | #include "libproc_impl.h" |
never@3156 | 40 | #include "elfmacros.h" |
never@3156 | 41 | |
never@3156 | 42 | // This file has the libproc implementation specific to live process |
never@3156 | 43 | // For core files, refer to ps_core.c |
never@3156 | 44 | |
never@3156 | 45 | static inline uintptr_t align(uintptr_t ptr, size_t size) { |
never@3156 | 46 | return (ptr & ~(size - 1)); |
never@3156 | 47 | } |
never@3156 | 48 | |
never@3156 | 49 | // --------------------------------------------- |
never@3156 | 50 | // ptrace functions |
never@3156 | 51 | // --------------------------------------------- |
never@3156 | 52 | |
never@3156 | 53 | // read "size" bytes of data from "addr" within the target process. |
never@3156 | 54 | // unlike the standard ptrace() function, process_read_data() can handle |
never@3156 | 55 | // unaligned address - alignment check, if required, should be done |
never@3156 | 56 | // before calling process_read_data. |
never@3156 | 57 | |
never@3156 | 58 | static bool process_read_data(struct ps_prochandle* ph, uintptr_t addr, char *buf, size_t size) { |
never@3156 | 59 | int rslt; |
never@3156 | 60 | size_t i, words; |
never@3156 | 61 | uintptr_t end_addr = addr + size; |
never@3156 | 62 | uintptr_t aligned_addr = align(addr, sizeof(int)); |
never@3156 | 63 | |
never@3156 | 64 | if (aligned_addr != addr) { |
never@3156 | 65 | char *ptr = (char *)&rslt; |
never@3156 | 66 | errno = 0; |
never@3156 | 67 | rslt = ptrace(PT_READ_D, ph->pid, (caddr_t) aligned_addr, 0); |
never@3156 | 68 | if (errno) { |
never@3156 | 69 | print_debug("ptrace(PT_READ_D, ..) failed for %d bytes @ %lx\n", size, addr); |
never@3156 | 70 | return false; |
never@3156 | 71 | } |
never@3156 | 72 | for (; aligned_addr != addr; aligned_addr++, ptr++); |
never@3156 | 73 | for (; ((intptr_t)aligned_addr % sizeof(int)) && aligned_addr < end_addr; |
never@3156 | 74 | aligned_addr++) |
never@3156 | 75 | *(buf++) = *(ptr++); |
never@3156 | 76 | } |
never@3156 | 77 | |
never@3156 | 78 | words = (end_addr - aligned_addr) / sizeof(int); |
never@3156 | 79 | |
never@3156 | 80 | // assert((intptr_t)aligned_addr % sizeof(int) == 0); |
never@3156 | 81 | for (i = 0; i < words; i++) { |
never@3156 | 82 | errno = 0; |
never@3156 | 83 | rslt = ptrace(PT_READ_D, ph->pid, (caddr_t) aligned_addr, 0); |
never@3156 | 84 | if (errno) { |
never@3156 | 85 | print_debug("ptrace(PT_READ_D, ..) failed for %d bytes @ %lx\n", size, addr); |
never@3156 | 86 | return false; |
never@3156 | 87 | } |
never@3156 | 88 | *(int *)buf = rslt; |
never@3156 | 89 | buf += sizeof(int); |
never@3156 | 90 | aligned_addr += sizeof(int); |
never@3156 | 91 | } |
never@3156 | 92 | |
never@3156 | 93 | if (aligned_addr != end_addr) { |
never@3156 | 94 | char *ptr = (char *)&rslt; |
never@3156 | 95 | errno = 0; |
never@3156 | 96 | rslt = ptrace(PT_READ_D, ph->pid, (caddr_t) aligned_addr, 0); |
never@3156 | 97 | if (errno) { |
never@3156 | 98 | print_debug("ptrace(PT_READ_D, ..) failed for %d bytes @ %lx\n", size, addr); |
never@3156 | 99 | return false; |
never@3156 | 100 | } |
never@3156 | 101 | for (; aligned_addr != end_addr; aligned_addr++) |
never@3156 | 102 | *(buf++) = *(ptr++); |
never@3156 | 103 | } |
never@3156 | 104 | return true; |
never@3156 | 105 | } |
never@3156 | 106 | |
never@3156 | 107 | // null implementation for write |
never@3156 | 108 | static bool process_write_data(struct ps_prochandle* ph, |
never@3156 | 109 | uintptr_t addr, const char *buf , size_t size) { |
never@3156 | 110 | return false; |
never@3156 | 111 | } |
never@3156 | 112 | |
never@3156 | 113 | // "user" should be a pointer to a reg |
never@3156 | 114 | static bool process_get_lwp_regs(struct ps_prochandle* ph, pid_t pid, struct reg *user) { |
never@3156 | 115 | // we have already attached to all thread 'pid's, just use ptrace call |
never@3156 | 116 | // to get regset now. Note that we don't cache regset upfront for processes. |
never@3156 | 117 | if (ptrace(PT_GETREGS, pid, (caddr_t) user, 0) < 0) { |
never@3156 | 118 | print_debug("ptrace(PTRACE_GETREGS, ...) failed for lwp %d\n", pid); |
never@3156 | 119 | return false; |
never@3156 | 120 | } |
never@3156 | 121 | return true; |
never@3156 | 122 | } |
never@3156 | 123 | |
never@3156 | 124 | // fill in ptrace_lwpinfo for lid |
never@3156 | 125 | static bool process_get_lwp_info(struct ps_prochandle *ph, lwpid_t lwp_id, void *linfo) { |
never@3156 | 126 | errno = 0; |
never@3156 | 127 | ptrace(PT_LWPINFO, lwp_id, linfo, sizeof(struct ptrace_lwpinfo)); |
never@3156 | 128 | |
never@3156 | 129 | return (errno == 0)? true: false; |
never@3156 | 130 | } |
never@3156 | 131 | |
rbackman@4599 | 132 | static bool ptrace_continue(pid_t pid, int signal) { |
rbackman@4599 | 133 | // pass the signal to the process so we don't swallow it |
dsamersoff@6031 | 134 | if (ptrace(PT_CONTINUE, pid, NULL, signal) < 0) { |
rbackman@4599 | 135 | print_debug("ptrace(PTRACE_CONT, ..) failed for %d\n", pid); |
rbackman@4599 | 136 | return false; |
rbackman@4599 | 137 | } |
rbackman@4599 | 138 | return true; |
rbackman@4599 | 139 | } |
rbackman@4599 | 140 | |
rbackman@4599 | 141 | // waits until the ATTACH has stopped the process |
rbackman@4599 | 142 | // by signal SIGSTOP |
rbackman@4599 | 143 | static bool ptrace_waitpid(pid_t pid) { |
rbackman@4599 | 144 | int ret; |
rbackman@4599 | 145 | int status; |
rbackman@4599 | 146 | do { |
rbackman@4599 | 147 | // Wait for debuggee to stop. |
rbackman@4599 | 148 | ret = waitpid(pid, &status, 0); |
rbackman@4599 | 149 | if (ret >= 0) { |
rbackman@4599 | 150 | if (WIFSTOPPED(status)) { |
rbackman@4599 | 151 | // Any signal will stop the thread, make sure it is SIGSTOP. Otherwise SIGSTOP |
rbackman@4599 | 152 | // will still be pending and delivered when the process is DETACHED and the process |
rbackman@4599 | 153 | // will go to sleep. |
rbackman@4599 | 154 | if (WSTOPSIG(status) == SIGSTOP) { |
rbackman@4599 | 155 | // Debuggee stopped by SIGSTOP. |
rbackman@4599 | 156 | return true; |
rbackman@4599 | 157 | } |
rbackman@4599 | 158 | if (!ptrace_continue(pid, WSTOPSIG(status))) { |
rbackman@4599 | 159 | print_error("Failed to correctly attach to VM. VM might HANG! [PTRACE_CONT failed, stopped by %d]\n", WSTOPSIG(status)); |
rbackman@4599 | 160 | return false; |
rbackman@4599 | 161 | } |
rbackman@4599 | 162 | } else { |
rbackman@4599 | 163 | print_debug("waitpid(): Child process exited/terminated (status = 0x%x)\n", status); |
rbackman@4599 | 164 | return false; |
rbackman@4599 | 165 | } |
rbackman@4599 | 166 | } else { |
rbackman@4599 | 167 | switch (errno) { |
rbackman@4599 | 168 | case EINTR: |
rbackman@4599 | 169 | continue; |
rbackman@4599 | 170 | break; |
rbackman@4599 | 171 | case ECHILD: |
rbackman@4599 | 172 | print_debug("waitpid() failed. Child process pid (%d) does not exist \n", pid); |
rbackman@4599 | 173 | break; |
rbackman@4599 | 174 | case EINVAL: |
rbackman@4599 | 175 | print_debug("waitpid() failed. Invalid options argument.\n"); |
rbackman@4599 | 176 | break; |
rbackman@4599 | 177 | default: |
rbackman@4599 | 178 | print_debug("waitpid() failed. Unexpected error %d\n",errno); |
rbackman@4599 | 179 | } |
rbackman@4599 | 180 | return false; |
rbackman@4599 | 181 | } |
rbackman@4599 | 182 | } while(true); |
rbackman@4599 | 183 | } |
rbackman@4599 | 184 | |
never@3156 | 185 | // attach to a process/thread specified by "pid" |
never@3156 | 186 | static bool ptrace_attach(pid_t pid) { |
never@3156 | 187 | if (ptrace(PT_ATTACH, pid, NULL, 0) < 0) { |
never@3156 | 188 | print_debug("ptrace(PTRACE_ATTACH, ..) failed for %d\n", pid); |
never@3156 | 189 | return false; |
never@3156 | 190 | } else { |
rbackman@4599 | 191 | return ptrace_waitpid(pid); |
never@3156 | 192 | } |
never@3156 | 193 | } |
never@3156 | 194 | |
never@3156 | 195 | // ------------------------------------------------------- |
never@3156 | 196 | // functions for obtaining library information |
never@3156 | 197 | // ------------------------------------------------------- |
never@3156 | 198 | |
never@3156 | 199 | // callback for read_thread_info |
never@3156 | 200 | static bool add_new_thread(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id) { |
never@3156 | 201 | return add_thread_info(ph, pthread_id, lwp_id) != NULL; |
never@3156 | 202 | } |
never@3156 | 203 | |
never@3156 | 204 | #if defined(__FreeBSD__) && __FreeBSD_version < 701000 |
never@3156 | 205 | /* |
never@3156 | 206 | * TEXT_START_ADDR from binutils/ld/emulparams/<arch_spec>.sh |
never@3156 | 207 | * Not the most robust but good enough. |
never@3156 | 208 | */ |
never@3156 | 209 | |
never@3156 | 210 | #if defined(amd64) || defined(x86_64) |
never@3156 | 211 | #define TEXT_START_ADDR 0x400000 |
never@3156 | 212 | #elif defined(i386) |
never@3156 | 213 | #define TEXT_START_ADDR 0x8048000 |
never@3156 | 214 | #else |
never@3156 | 215 | #error TEXT_START_ADDR not defined |
never@3156 | 216 | #endif |
never@3156 | 217 | |
never@3156 | 218 | #define BUF_SIZE (PATH_MAX + NAME_MAX + 1) |
never@3156 | 219 | |
never@3156 | 220 | uintptr_t linkmap_addr(struct ps_prochandle *ph) { |
never@3156 | 221 | uintptr_t ehdr_addr, phdr_addr, dyn_addr, dmap_addr, lmap_addr; |
never@3156 | 222 | ELF_EHDR ehdr; |
never@3156 | 223 | ELF_PHDR *phdrs, *phdr; |
never@3156 | 224 | ELF_DYN *dyns, *dyn; |
never@3156 | 225 | struct r_debug dmap; |
never@3156 | 226 | unsigned long hdrs_size; |
never@3156 | 227 | unsigned int i; |
never@3156 | 228 | |
never@3156 | 229 | /* read ELF_EHDR at TEXT_START_ADDR and validate */ |
never@3156 | 230 | |
never@3156 | 231 | ehdr_addr = (uintptr_t)TEXT_START_ADDR; |
never@3156 | 232 | |
never@3156 | 233 | if (process_read_data(ph, ehdr_addr, (char *)&ehdr, sizeof(ehdr)) != true) { |
never@3156 | 234 | print_debug("process_read_data failed for ehdr_addr %p\n", ehdr_addr); |
never@3156 | 235 | return (0); |
never@3156 | 236 | } |
never@3156 | 237 | |
never@3156 | 238 | if (!IS_ELF(ehdr) || |
never@3156 | 239 | ehdr.e_ident[EI_CLASS] != ELF_TARG_CLASS || |
never@3156 | 240 | ehdr.e_ident[EI_DATA] != ELF_TARG_DATA || |
never@3156 | 241 | ehdr.e_ident[EI_VERSION] != EV_CURRENT || |
never@3156 | 242 | ehdr.e_phentsize != sizeof(ELF_PHDR) || |
never@3156 | 243 | ehdr.e_version != ELF_TARG_VER || |
never@3156 | 244 | ehdr.e_machine != ELF_TARG_MACH) { |
never@3156 | 245 | print_debug("not an ELF_EHDR at %p\n", ehdr_addr); |
never@3156 | 246 | return (0); |
never@3156 | 247 | } |
never@3156 | 248 | |
never@3156 | 249 | /* allocate space for all ELF_PHDR's and read */ |
never@3156 | 250 | |
never@3156 | 251 | phdr_addr = ehdr_addr + ehdr.e_phoff; |
never@3156 | 252 | hdrs_size = ehdr.e_phnum * sizeof(ELF_PHDR); |
never@3156 | 253 | |
never@3156 | 254 | if ((phdrs = malloc(hdrs_size)) == NULL) |
never@3156 | 255 | return (0); |
never@3156 | 256 | |
never@3156 | 257 | if (process_read_data(ph, phdr_addr, (char *)phdrs, hdrs_size) != true) { |
never@3156 | 258 | print_debug("process_read_data failed for phdr_addr %p\n", phdr_addr); |
never@3156 | 259 | return (0); |
never@3156 | 260 | } |
never@3156 | 261 | |
never@3156 | 262 | /* find PT_DYNAMIC section */ |
never@3156 | 263 | |
never@3156 | 264 | for (i = 0, phdr = phdrs; i < ehdr.e_phnum; i++, phdr++) { |
never@3156 | 265 | if (phdr->p_type == PT_DYNAMIC) |
never@3156 | 266 | break; |
never@3156 | 267 | } |
never@3156 | 268 | |
never@3156 | 269 | if (i >= ehdr.e_phnum) { |
never@3156 | 270 | print_debug("PT_DYNAMIC section not found!\n"); |
never@3156 | 271 | free(phdrs); |
never@3156 | 272 | return (0); |
never@3156 | 273 | } |
never@3156 | 274 | |
never@3156 | 275 | /* allocate space and read in ELF_DYN headers */ |
never@3156 | 276 | |
never@3156 | 277 | dyn_addr = phdr->p_vaddr; |
never@3156 | 278 | hdrs_size = phdr->p_memsz; |
never@3156 | 279 | free(phdrs); |
never@3156 | 280 | |
never@3156 | 281 | if ((dyns = malloc(hdrs_size)) == NULL) |
never@3156 | 282 | return (0); |
never@3156 | 283 | |
never@3156 | 284 | if (process_read_data(ph, dyn_addr, (char *)dyns, hdrs_size) != true) { |
never@3156 | 285 | print_debug("process_read_data failed for dyn_addr %p\n", dyn_addr); |
never@3156 | 286 | free(dyns); |
never@3156 | 287 | return (0); |
never@3156 | 288 | } |
never@3156 | 289 | |
never@3156 | 290 | /* find DT_DEBUG */ |
never@3156 | 291 | |
never@3156 | 292 | dyn = dyns; |
never@3156 | 293 | while (dyn->d_tag != DT_DEBUG && dyn->d_tag != DT_NULL) { |
never@3156 | 294 | dyn++; |
never@3156 | 295 | } |
never@3156 | 296 | |
never@3156 | 297 | if (dyn->d_tag != DT_DEBUG) { |
never@3156 | 298 | print_debug("failed to find DT_DEBUG\n"); |
never@3156 | 299 | free(dyns); |
never@3156 | 300 | return (0); |
never@3156 | 301 | } |
never@3156 | 302 | |
never@3156 | 303 | /* read struct r_debug into dmap */ |
never@3156 | 304 | |
never@3156 | 305 | dmap_addr = (uintptr_t)dyn->d_un.d_ptr; |
never@3156 | 306 | free(dyns); |
never@3156 | 307 | |
never@3156 | 308 | if (process_read_data(ph, dmap_addr, (char *)&dmap, sizeof(dmap)) != true) { |
never@3156 | 309 | print_debug("process_read_data failed for dmap_addr %p\n", dmap_addr); |
never@3156 | 310 | return (0); |
never@3156 | 311 | } |
never@3156 | 312 | |
never@3156 | 313 | lmap_addr = (uintptr_t)dmap.r_map; |
never@3156 | 314 | |
never@3156 | 315 | return (lmap_addr); |
never@3156 | 316 | } |
never@3156 | 317 | #endif // __FreeBSD__ && __FreeBSD_version < 701000 |
never@3156 | 318 | |
never@3156 | 319 | static bool read_lib_info(struct ps_prochandle* ph) { |
never@3156 | 320 | #if defined(__FreeBSD__) && __FreeBSD_version >= 701000 |
never@3156 | 321 | struct kinfo_vmentry *freep, *kve; |
never@3156 | 322 | int i, cnt; |
never@3156 | 323 | |
never@3156 | 324 | freep = kinfo_getvmmap(ph->pid, &cnt); |
never@3156 | 325 | if (freep == NULL) { |
never@3156 | 326 | print_debug("can't get vm map for pid\n", ph->pid); |
never@3156 | 327 | return false; |
never@3156 | 328 | } |
never@3156 | 329 | |
never@3156 | 330 | for (i = 0; i < cnt; i++) { |
never@3156 | 331 | kve = &freep[i]; |
never@3156 | 332 | if ((kve->kve_flags & KVME_FLAG_COW) && |
never@3156 | 333 | kve->kve_path != NULL && |
never@3156 | 334 | strlen(kve->kve_path) > 0) { |
never@3156 | 335 | |
never@3156 | 336 | if (find_lib(ph, kve->kve_path) == false) { |
never@3156 | 337 | lib_info* lib; |
never@3156 | 338 | if ((lib = add_lib_info(ph, kve->kve_path, |
never@3156 | 339 | (uintptr_t) kve->kve_start)) == NULL) |
never@3156 | 340 | continue; // ignore, add_lib_info prints error |
never@3156 | 341 | |
never@3156 | 342 | // we don't need to keep the library open, symtab is already |
never@3156 | 343 | // built. Only for core dump we need to keep the fd open. |
never@3156 | 344 | close(lib->fd); |
never@3156 | 345 | lib->fd = -1; |
never@3156 | 346 | } |
never@3156 | 347 | } |
never@3156 | 348 | } |
never@3156 | 349 | |
never@3156 | 350 | free(freep); |
never@3156 | 351 | |
never@3156 | 352 | return true; |
never@3156 | 353 | #else |
never@3156 | 354 | char *l_name; |
never@3156 | 355 | struct link_map *lmap; |
never@3156 | 356 | uintptr_t lmap_addr; |
never@3156 | 357 | |
never@3156 | 358 | if ((l_name = malloc(BUF_SIZE)) == NULL) |
never@3156 | 359 | return false; |
never@3156 | 360 | |
never@3156 | 361 | if ((lmap = malloc(sizeof(*lmap))) == NULL) { |
never@3156 | 362 | free(l_name); |
never@3156 | 363 | return false; |
never@3156 | 364 | } |
never@3156 | 365 | |
never@3156 | 366 | lmap_addr = linkmap_addr(ph); |
never@3156 | 367 | |
never@3156 | 368 | if (lmap_addr == 0) { |
never@3156 | 369 | free(l_name); |
never@3156 | 370 | free(lmap); |
never@3156 | 371 | return false; |
never@3156 | 372 | } |
never@3156 | 373 | |
never@3156 | 374 | do { |
never@3156 | 375 | if (process_read_data(ph, lmap_addr, (char *)lmap, sizeof(*lmap)) != true) { |
never@3156 | 376 | print_debug("process_read_data failed for lmap_addr %p\n", lmap_addr); |
never@3156 | 377 | free (l_name); |
never@3156 | 378 | free (lmap); |
never@3156 | 379 | return false; |
never@3156 | 380 | } |
never@3156 | 381 | |
never@3156 | 382 | if (process_read_data(ph, (uintptr_t)lmap->l_name, l_name, |
never@3156 | 383 | BUF_SIZE) != true) { |
never@3156 | 384 | print_debug("process_read_data failed for lmap->l_name %p\n", |
never@3156 | 385 | lmap->l_name); |
never@3156 | 386 | free (l_name); |
never@3156 | 387 | free (lmap); |
never@3156 | 388 | return false; |
never@3156 | 389 | } |
never@3156 | 390 | |
never@3156 | 391 | if (find_lib(ph, l_name) == false) { |
never@3156 | 392 | lib_info* lib; |
never@3156 | 393 | if ((lib = add_lib_info(ph, l_name, |
never@3156 | 394 | (uintptr_t) lmap->l_addr)) == NULL) |
never@3156 | 395 | continue; // ignore, add_lib_info prints error |
never@3156 | 396 | |
never@3156 | 397 | // we don't need to keep the library open, symtab is already |
never@3156 | 398 | // built. Only for core dump we need to keep the fd open. |
never@3156 | 399 | close(lib->fd); |
never@3156 | 400 | lib->fd = -1; |
never@3156 | 401 | } |
never@3156 | 402 | lmap_addr = (uintptr_t)lmap->l_next; |
never@3156 | 403 | } while (lmap->l_next != NULL); |
never@3156 | 404 | |
never@3156 | 405 | free (l_name); |
never@3156 | 406 | free (lmap); |
never@3156 | 407 | |
never@3156 | 408 | return true; |
never@3156 | 409 | #endif |
never@3156 | 410 | } |
never@3156 | 411 | |
never@3156 | 412 | // detach a given pid |
never@3156 | 413 | static bool ptrace_detach(pid_t pid) { |
never@3156 | 414 | if (pid && ptrace(PT_DETACH, pid, (caddr_t)1, 0) < 0) { |
never@3156 | 415 | print_debug("ptrace(PTRACE_DETACH, ..) failed for %d\n", pid); |
never@3156 | 416 | return false; |
never@3156 | 417 | } else { |
never@3156 | 418 | return true; |
never@3156 | 419 | } |
never@3156 | 420 | } |
never@3156 | 421 | |
never@3156 | 422 | static void process_cleanup(struct ps_prochandle* ph) { |
never@3156 | 423 | ptrace_detach(ph->pid); |
never@3156 | 424 | } |
never@3156 | 425 | |
never@3156 | 426 | static ps_prochandle_ops process_ops = { |
never@3156 | 427 | .release= process_cleanup, |
never@3156 | 428 | .p_pread= process_read_data, |
never@3156 | 429 | .p_pwrite= process_write_data, |
never@3156 | 430 | .get_lwp_regs= process_get_lwp_regs, |
never@3156 | 431 | .get_lwp_info= process_get_lwp_info |
never@3156 | 432 | }; |
never@3156 | 433 | |
never@3156 | 434 | // attach to the process. One and only one exposed stuff |
never@3156 | 435 | struct ps_prochandle* Pgrab(pid_t pid) { |
never@3156 | 436 | struct ps_prochandle* ph = NULL; |
never@3156 | 437 | |
never@3156 | 438 | if ( (ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle))) == NULL) { |
never@3156 | 439 | print_debug("can't allocate memory for ps_prochandle\n"); |
never@3156 | 440 | return NULL; |
never@3156 | 441 | } |
never@3156 | 442 | |
never@3156 | 443 | if (ptrace_attach(pid) != true) { |
never@3156 | 444 | free(ph); |
never@3156 | 445 | return NULL; |
never@3156 | 446 | } |
never@3156 | 447 | |
never@3156 | 448 | // initialize ps_prochandle |
never@3156 | 449 | ph->pid = pid; |
never@3156 | 450 | |
never@3156 | 451 | // initialize vtable |
never@3156 | 452 | ph->ops = &process_ops; |
never@3156 | 453 | |
never@3156 | 454 | // read library info and symbol tables, must do this before attaching threads, |
never@3156 | 455 | // as the symbols in the pthread library will be used to figure out |
never@3156 | 456 | // the list of threads within the same process. |
never@3156 | 457 | if (read_lib_info(ph) != true) { |
never@3156 | 458 | ptrace_detach(pid); |
never@3156 | 459 | free(ph); |
never@3156 | 460 | return NULL; |
never@3156 | 461 | } |
never@3156 | 462 | |
never@3156 | 463 | // read thread info |
never@3156 | 464 | read_thread_info(ph, add_new_thread); |
never@3156 | 465 | |
never@3156 | 466 | return ph; |
never@3156 | 467 | } |