agent/src/os/linux/ps_proc.c

Fri, 13 Jun 2014 05:10:44 -0700

author
dsamersoff
date
Fri, 13 Jun 2014 05:10:44 -0700
changeset 9751
c751303497d5
parent 9683
fba8dbd018a6
child 9756
2be326848943
permissions
-rw-r--r--

8038392: Generating prelink cache breaks JAVA 'jinfo' utility normal behaviour
Summary: Better parsing of /proc/pid/maps in sa
Reviewed-by: sspitsyn, sla

duke@435 1 /*
rbackman@4599 2 * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
duke@435 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@435 4 *
duke@435 5 * This code is free software; you can redistribute it and/or modify it
duke@435 6 * under the terms of the GNU General Public License version 2 only, as
duke@435 7 * published by the Free Software Foundation.
duke@435 8 *
duke@435 9 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@435 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@435 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@435 12 * version 2 for more details (a copy is included in the LICENSE file that
duke@435 13 * accompanied this code).
duke@435 14 *
duke@435 15 * You should have received a copy of the GNU General Public License version
duke@435 16 * 2 along with this work; if not, write to the Free Software Foundation,
duke@435 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@435 18 *
trims@1907 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
trims@1907 20 * or visit www.oracle.com if you need additional information or have any
trims@1907 21 * questions.
duke@435 22 *
duke@435 23 */
duke@435 24
duke@435 25 #include <stdio.h>
duke@435 26 #include <stdlib.h>
duke@435 27 #include <string.h>
rbackman@4599 28 #include <signal.h>
duke@435 29 #include <errno.h>
dlong@7586 30 #include <elf.h>
adinn@9683 31 #include <ctype.h>
twisti@5797 32 #include <sys/types.h>
twisti@5797 33 #include <sys/wait.h>
duke@435 34 #include <sys/ptrace.h>
dlong@7586 35 #include <sys/uio.h>
duke@435 36 #include "libproc_impl.h"
duke@435 37
duke@435 38 #if defined(x86_64) && !defined(amd64)
duke@435 39 #define amd64 1
duke@435 40 #endif
duke@435 41
duke@435 42 #ifndef __WALL
duke@435 43 #define __WALL 0x40000000 // Copied from /usr/include/linux/wait.h
duke@435 44 #endif
duke@435 45
duke@435 46 // This file has the libproc implementation specific to live process
duke@435 47 // For core files, refer to ps_core.c
duke@435 48
adinn@9683 49 typedef enum {
adinn@9683 50 ATTACH_SUCCESS,
adinn@9683 51 ATTACH_FAIL,
adinn@9683 52 ATTACH_THREAD_DEAD
adinn@9683 53 } attach_state_t;
adinn@9683 54
duke@435 55 static inline uintptr_t align(uintptr_t ptr, size_t size) {
duke@435 56 return (ptr & ~(size - 1));
duke@435 57 }
duke@435 58
duke@435 59 // ---------------------------------------------
duke@435 60 // ptrace functions
duke@435 61 // ---------------------------------------------
duke@435 62
duke@435 63 // read "size" bytes of data from "addr" within the target process.
duke@435 64 // unlike the standard ptrace() function, process_read_data() can handle
duke@435 65 // unaligned address - alignment check, if required, should be done
duke@435 66 // before calling process_read_data.
duke@435 67
duke@435 68 static bool process_read_data(struct ps_prochandle* ph, uintptr_t addr, char *buf, size_t size) {
duke@435 69 long rslt;
duke@435 70 size_t i, words;
duke@435 71 uintptr_t end_addr = addr + size;
duke@435 72 uintptr_t aligned_addr = align(addr, sizeof(long));
duke@435 73
duke@435 74 if (aligned_addr != addr) {
duke@435 75 char *ptr = (char *)&rslt;
duke@435 76 errno = 0;
duke@435 77 rslt = ptrace(PTRACE_PEEKDATA, ph->pid, aligned_addr, 0);
duke@435 78 if (errno) {
duke@435 79 print_debug("ptrace(PTRACE_PEEKDATA, ..) failed for %d bytes @ %lx\n", size, addr);
duke@435 80 return false;
duke@435 81 }
duke@435 82 for (; aligned_addr != addr; aligned_addr++, ptr++);
duke@435 83 for (; ((intptr_t)aligned_addr % sizeof(long)) && aligned_addr < end_addr;
duke@435 84 aligned_addr++)
duke@435 85 *(buf++) = *(ptr++);
duke@435 86 }
duke@435 87
duke@435 88 words = (end_addr - aligned_addr) / sizeof(long);
duke@435 89
duke@435 90 // assert((intptr_t)aligned_addr % sizeof(long) == 0);
duke@435 91 for (i = 0; i < words; i++) {
duke@435 92 errno = 0;
duke@435 93 rslt = ptrace(PTRACE_PEEKDATA, ph->pid, aligned_addr, 0);
duke@435 94 if (errno) {
duke@435 95 print_debug("ptrace(PTRACE_PEEKDATA, ..) failed for %d bytes @ %lx\n", size, addr);
duke@435 96 return false;
duke@435 97 }
duke@435 98 *(long *)buf = rslt;
duke@435 99 buf += sizeof(long);
duke@435 100 aligned_addr += sizeof(long);
duke@435 101 }
duke@435 102
duke@435 103 if (aligned_addr != end_addr) {
duke@435 104 char *ptr = (char *)&rslt;
duke@435 105 errno = 0;
duke@435 106 rslt = ptrace(PTRACE_PEEKDATA, ph->pid, aligned_addr, 0);
duke@435 107 if (errno) {
duke@435 108 print_debug("ptrace(PTRACE_PEEKDATA, ..) failed for %d bytes @ %lx\n", size, addr);
duke@435 109 return false;
duke@435 110 }
duke@435 111 for (; aligned_addr != end_addr; aligned_addr++)
duke@435 112 *(buf++) = *(ptr++);
duke@435 113 }
duke@435 114 return true;
duke@435 115 }
duke@435 116
duke@435 117 // null implementation for write
duke@435 118 static bool process_write_data(struct ps_prochandle* ph,
duke@435 119 uintptr_t addr, const char *buf , size_t size) {
duke@435 120 return false;
duke@435 121 }
duke@435 122
duke@435 123 // "user" should be a pointer to a user_regs_struct
duke@435 124 static bool process_get_lwp_regs(struct ps_prochandle* ph, pid_t pid, struct user_regs_struct *user) {
duke@435 125 // we have already attached to all thread 'pid's, just use ptrace call
duke@435 126 // to get regset now. Note that we don't cache regset upfront for processes.
duke@435 127 // Linux on x86 and sparc are different. On x86 ptrace(PTRACE_GETREGS, ...)
duke@435 128 // uses pointer from 4th argument and ignores 3rd argument. On sparc it uses
duke@435 129 // pointer from 3rd argument and ignores 4th argument
duke@435 130 #if defined(sparc) || defined(sparcv9)
duke@435 131 #define ptrace_getregs(request, pid, addr, data) ptrace(request, pid, addr, data)
duke@435 132 #else
duke@435 133 #define ptrace_getregs(request, pid, addr, data) ptrace(request, pid, data, addr)
duke@435 134 #endif
duke@435 135
kevinw@2332 136 #if defined(_LP64) && defined(PTRACE_GETREGS64)
duke@435 137 #define PTRACE_GETREGS_REQ PTRACE_GETREGS64
kevinw@2332 138 #elif defined(PTRACE_GETREGS)
kevinw@2332 139 #define PTRACE_GETREGS_REQ PTRACE_GETREGS
kevinw@2332 140 #elif defined(PT_GETREGS)
kevinw@2332 141 #define PTRACE_GETREGS_REQ PT_GETREGS
duke@435 142 #endif
duke@435 143
duke@435 144 #ifdef PTRACE_GETREGS_REQ
duke@435 145 if (ptrace_getregs(PTRACE_GETREGS_REQ, pid, user, NULL) < 0) {
duke@435 146 print_debug("ptrace(PTRACE_GETREGS, ...) failed for lwp %d\n", pid);
duke@435 147 return false;
duke@435 148 }
duke@435 149 return true;
dlong@7586 150 #elif defined(PTRACE_GETREGSET)
dlong@7586 151 struct iovec iov;
dlong@7586 152 iov.iov_base = user;
dlong@7586 153 iov.iov_len = sizeof(*user);
dlong@7586 154 if (ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, (void*) &iov) < 0) {
dlong@7586 155 print_debug("ptrace(PTRACE_GETREGSET, ...) failed for lwp %d\n", pid);
dlong@7586 156 return false;
dlong@7586 157 }
dlong@7586 158 return true;
duke@435 159 #else
duke@435 160 print_debug("ptrace(PTRACE_GETREGS, ...) not supported\n");
duke@435 161 return false;
duke@435 162 #endif
duke@435 163
duke@435 164 }
duke@435 165
rbackman@4599 166 static bool ptrace_continue(pid_t pid, int signal) {
rbackman@4599 167 // pass the signal to the process so we don't swallow it
rbackman@4599 168 if (ptrace(PTRACE_CONT, pid, NULL, signal) < 0) {
rbackman@4599 169 print_debug("ptrace(PTRACE_CONT, ..) failed for %d\n", pid);
rbackman@4599 170 return false;
rbackman@4599 171 }
rbackman@4599 172 return true;
rbackman@4599 173 }
rbackman@4599 174
rbackman@4599 175 // waits until the ATTACH has stopped the process
rbackman@4599 176 // by signal SIGSTOP
adinn@9683 177 static attach_state_t ptrace_waitpid(pid_t pid) {
rbackman@4599 178 int ret;
rbackman@4599 179 int status;
adinn@9683 180 errno = 0;
rbackman@4599 181 while (true) {
rbackman@4599 182 // Wait for debuggee to stop.
rbackman@4599 183 ret = waitpid(pid, &status, 0);
rbackman@4599 184 if (ret == -1 && errno == ECHILD) {
rbackman@4599 185 // try cloned process.
rbackman@4599 186 ret = waitpid(pid, &status, __WALL);
rbackman@4599 187 }
rbackman@4599 188 if (ret >= 0) {
rbackman@4599 189 if (WIFSTOPPED(status)) {
rbackman@4599 190 // Any signal will stop the thread, make sure it is SIGSTOP. Otherwise SIGSTOP
rbackman@4599 191 // will still be pending and delivered when the process is DETACHED and the process
rbackman@4599 192 // will go to sleep.
rbackman@4599 193 if (WSTOPSIG(status) == SIGSTOP) {
rbackman@4599 194 // Debuggee stopped by SIGSTOP.
adinn@9683 195 return ATTACH_SUCCESS;
rbackman@4599 196 }
rbackman@4599 197 if (!ptrace_continue(pid, WSTOPSIG(status))) {
rbackman@4599 198 print_error("Failed to correctly attach to VM. VM might HANG! [PTRACE_CONT failed, stopped by %d]\n", WSTOPSIG(status));
adinn@9683 199 return ATTACH_FAIL;
rbackman@4599 200 }
rbackman@4599 201 } else {
adinn@9683 202 print_debug("waitpid(): Child process %d exited/terminated (status = 0x%x)\n", pid, status);
adinn@9683 203 return ATTACH_THREAD_DEAD;
rbackman@4599 204 }
rbackman@4599 205 } else {
rbackman@4599 206 switch (errno) {
rbackman@4599 207 case EINTR:
rbackman@4599 208 continue;
rbackman@4599 209 break;
rbackman@4599 210 case ECHILD:
rbackman@4599 211 print_debug("waitpid() failed. Child process pid (%d) does not exist \n", pid);
adinn@9683 212 return ATTACH_THREAD_DEAD;
rbackman@4599 213 case EINVAL:
adinn@9683 214 print_error("waitpid() failed. Invalid options argument.\n");
adinn@9683 215 return ATTACH_FAIL;
rbackman@4599 216 default:
adinn@9683 217 print_error("waitpid() failed. Unexpected error %d\n",errno);
adinn@9683 218 return ATTACH_FAIL;
rbackman@4599 219 }
adinn@9683 220 } // else
adinn@9683 221 } // while
adinn@9683 222 }
adinn@9683 223
adinn@9683 224 // checks the state of the thread/process specified by "pid", by reading
adinn@9683 225 // in the 'State:' value from the /proc/<pid>/status file. From the proc
adinn@9683 226 // man page, "Current state of the process. One of "R (running)",
adinn@9683 227 // "S (sleeping)", "D (disk sleep)", "T (stopped)", "T (tracing stop)",
adinn@9683 228 // "Z (zombie)", or "X (dead)"." Assumes that the thread is dead if we
adinn@9683 229 // don't find the status file or if the status is 'X' or 'Z'.
adinn@9683 230 static bool process_doesnt_exist(pid_t pid) {
adinn@9683 231 char fname[32];
adinn@9683 232 char buf[30];
adinn@9683 233 FILE *fp = NULL;
adinn@9683 234 const char state_string[] = "State:";
adinn@9683 235
adinn@9683 236 sprintf(fname, "/proc/%d/status", pid);
adinn@9683 237 fp = fopen(fname, "r");
adinn@9683 238 if (fp == NULL) {
adinn@9683 239 print_debug("can't open /proc/%d/status file\n", pid);
adinn@9683 240 // Assume the thread does not exist anymore.
adinn@9683 241 return true;
adinn@9683 242 }
adinn@9683 243 bool found_state = false;
adinn@9683 244 size_t state_len = strlen(state_string);
adinn@9683 245 while (fgets(buf, sizeof(buf), fp) != NULL) {
adinn@9683 246 char *state = NULL;
adinn@9683 247 if (strncmp (buf, state_string, state_len) == 0) {
adinn@9683 248 found_state = true;
adinn@9683 249 state = buf + state_len;
adinn@9683 250 // Skip the spaces
adinn@9683 251 while (isspace(*state)) {
adinn@9683 252 state++;
adinn@9683 253 }
adinn@9683 254 // A state value of 'X' indicates that the thread is dead. 'Z'
adinn@9683 255 // indicates that the thread is a zombie.
adinn@9683 256 if (*state == 'X' || *state == 'Z') {
adinn@9683 257 fclose (fp);
adinn@9683 258 return true;
adinn@9683 259 }
adinn@9683 260 break;
rbackman@4599 261 }
rbackman@4599 262 }
adinn@9683 263 // If the state value is not 'X' or 'Z', the thread exists.
adinn@9683 264 if (!found_state) {
adinn@9683 265 // We haven't found the line beginning with 'State:'.
adinn@9683 266 // Assuming the thread exists.
adinn@9683 267 print_error("Could not find the 'State:' string in the /proc/%d/status file\n", pid);
adinn@9683 268 }
adinn@9683 269 fclose (fp);
adinn@9683 270 return false;
rbackman@4599 271 }
rbackman@4599 272
duke@435 273 // attach to a process/thread specified by "pid"
adinn@9683 274 static attach_state_t ptrace_attach(pid_t pid, char* err_buf, size_t err_buf_len) {
adinn@9683 275 errno = 0;
duke@435 276 if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
adinn@9683 277 if (errno == EPERM || errno == ESRCH) {
adinn@9683 278 // Check if the process/thread is exiting or is a zombie
adinn@9683 279 if (process_doesnt_exist(pid)) {
adinn@9683 280 print_debug("Thread with pid %d does not exist\n", pid);
adinn@9683 281 return ATTACH_THREAD_DEAD;
adinn@9683 282 }
adinn@9683 283 }
sla@8197 284 char buf[200];
sla@8197 285 char* msg = strerror_r(errno, buf, sizeof(buf));
sla@8197 286 snprintf(err_buf, err_buf_len, "ptrace(PTRACE_ATTACH, ..) failed for %d: %s", pid, msg);
adinn@9683 287 print_error("%s\n", err_buf);
adinn@9683 288 return ATTACH_FAIL;
duke@435 289 } else {
adinn@9683 290 attach_state_t wait_ret = ptrace_waitpid(pid);
adinn@9683 291 if (wait_ret == ATTACH_THREAD_DEAD) {
adinn@9683 292 print_debug("Thread with pid %d does not exist\n", pid);
adinn@9683 293 }
adinn@9683 294 return wait_ret;
duke@435 295 }
duke@435 296 }
duke@435 297
duke@435 298 // -------------------------------------------------------
duke@435 299 // functions for obtaining library information
duke@435 300 // -------------------------------------------------------
duke@435 301
duke@435 302 /*
duke@435 303 * splits a string _str_ into substrings with delimiter _delim_ by replacing old * delimiters with _new_delim_ (ideally, '\0'). the address of each substring
duke@435 304 * is stored in array _ptrs_ as the return value. the maximum capacity of _ptrs_ * array is specified by parameter _n_.
duke@435 305 * RETURN VALUE: total number of substrings (always <= _n_)
duke@435 306 * NOTE: string _str_ is modified if _delim_!=_new_delim_
duke@435 307 */
duke@435 308 static int split_n_str(char * str, int n, char ** ptrs, char delim, char new_delim)
duke@435 309 {
duke@435 310 int i;
duke@435 311 for(i = 0; i < n; i++) ptrs[i] = NULL;
duke@435 312 if (str == NULL || n < 1 ) return 0;
duke@435 313
duke@435 314 i = 0;
duke@435 315
duke@435 316 // skipping leading blanks
duke@435 317 while(*str&&*str==delim) str++;
duke@435 318
duke@435 319 while(*str&&i<n){
duke@435 320 ptrs[i++] = str;
duke@435 321 while(*str&&*str!=delim) str++;
duke@435 322 while(*str&&*str==delim) *(str++) = new_delim;
duke@435 323 }
duke@435 324
duke@435 325 return i;
duke@435 326 }
duke@435 327
duke@435 328 /*
duke@435 329 * fgets without storing '\n' at the end of the string
duke@435 330 */
duke@435 331 static char * fgets_no_cr(char * buf, int n, FILE *fp)
duke@435 332 {
duke@435 333 char * rslt = fgets(buf, n, fp);
duke@435 334 if (rslt && buf && *buf){
duke@435 335 char *p = strchr(buf, '\0');
duke@435 336 if (*--p=='\n') *p='\0';
duke@435 337 }
duke@435 338 return rslt;
duke@435 339 }
duke@435 340
duke@435 341 // callback for read_thread_info
duke@435 342 static bool add_new_thread(struct ps_prochandle* ph, pthread_t pthread_id, lwpid_t lwp_id) {
duke@435 343 return add_thread_info(ph, pthread_id, lwp_id) != NULL;
duke@435 344 }
duke@435 345
duke@435 346 static bool read_lib_info(struct ps_prochandle* ph) {
duke@435 347 char fname[32];
dsamersoff@9751 348 char buf[PATH_MAX];
duke@435 349 FILE *fp = NULL;
duke@435 350
duke@435 351 sprintf(fname, "/proc/%d/maps", ph->pid);
duke@435 352 fp = fopen(fname, "r");
duke@435 353 if (fp == NULL) {
duke@435 354 print_debug("can't open /proc/%d/maps file\n", ph->pid);
duke@435 355 return false;
duke@435 356 }
duke@435 357
dsamersoff@9751 358 while(fgets_no_cr(buf, PATH_MAX, fp)){
dsamersoff@9751 359 char * word[7];
dsamersoff@9751 360 int nwords = split_n_str(buf, 7, word, ' ', '\0');
dsamersoff@9751 361
dsamersoff@9751 362 if (nwords < 6) {
dsamersoff@9751 363 // not a shared library entry. ignore.
dsamersoff@9751 364 continue;
dsamersoff@9751 365 }
dsamersoff@9751 366
dsamersoff@9751 367 // SA does not handle the lines with patterns:
dsamersoff@9751 368 // "[stack]", "[heap]", "[vdso]", "[vsyscall]", etc.
dsamersoff@9751 369 if (word[5][0] == '[') {
dsamersoff@9751 370 // not a shared library entry. ignore.
dsamersoff@9751 371 continue;
dsamersoff@9751 372 }
dsamersoff@9751 373
dsamersoff@9751 374 if (nwords > 6) {
dsamersoff@9751 375 // prelink altered mapfile when the program is running.
dsamersoff@9751 376 // Entries like one below have to be skipped
dsamersoff@9751 377 // /lib64/libc-2.15.so (deleted)
dsamersoff@9751 378 // SO name in entries like one below have to be stripped.
dsamersoff@9751 379 // /lib64/libpthread-2.15.so.#prelink#.EECVts
dsamersoff@9751 380 char *s = strstr(word[5],".#prelink#");
dsamersoff@9751 381 if (s == NULL) {
dsamersoff@9751 382 // No prelink keyword. skip deleted library
dsamersoff@9751 383 print_debug("skip shared object %s deleted by prelink\n", word[5]);
dsamersoff@9751 384 continue;
dsamersoff@9751 385 }
dsamersoff@9751 386
dsamersoff@9751 387 // Fall through
dsamersoff@9751 388 print_debug("rectifying shared object name %s changed by prelink\n", word[5]);
dsamersoff@9751 389 *s = 0;
dsamersoff@9751 390 }
dsamersoff@9751 391
dsamersoff@9751 392 if (find_lib(ph, word[5]) == false) {
duke@435 393 intptr_t base;
duke@435 394 lib_info* lib;
bobv@2036 395 #ifdef _LP64
duke@435 396 sscanf(word[0], "%lx", &base);
bobv@2036 397 #else
bobv@2036 398 sscanf(word[0], "%x", &base);
bobv@2036 399 #endif
duke@435 400 if ((lib = add_lib_info(ph, word[5], (uintptr_t)base)) == NULL)
duke@435 401 continue; // ignore, add_lib_info prints error
duke@435 402
duke@435 403 // we don't need to keep the library open, symtab is already
duke@435 404 // built. Only for core dump we need to keep the fd open.
duke@435 405 close(lib->fd);
duke@435 406 lib->fd = -1;
duke@435 407 }
duke@435 408 }
duke@435 409 fclose(fp);
duke@435 410 return true;
duke@435 411 }
duke@435 412
duke@435 413 // detach a given pid
duke@435 414 static bool ptrace_detach(pid_t pid) {
duke@435 415 if (pid && ptrace(PTRACE_DETACH, pid, NULL, NULL) < 0) {
duke@435 416 print_debug("ptrace(PTRACE_DETACH, ..) failed for %d\n", pid);
duke@435 417 return false;
duke@435 418 } else {
duke@435 419 return true;
duke@435 420 }
duke@435 421 }
duke@435 422
duke@435 423 // detach all pids of a ps_prochandle
duke@435 424 static void detach_all_pids(struct ps_prochandle* ph) {
duke@435 425 thread_info* thr = ph->threads;
duke@435 426 while (thr) {
duke@435 427 ptrace_detach(thr->lwp_id);
duke@435 428 thr = thr->next;
duke@435 429 }
duke@435 430 }
duke@435 431
duke@435 432 static void process_cleanup(struct ps_prochandle* ph) {
duke@435 433 detach_all_pids(ph);
duke@435 434 }
duke@435 435
duke@435 436 static ps_prochandle_ops process_ops = {
dcubed@485 437 .release= process_cleanup,
dcubed@485 438 .p_pread= process_read_data,
dcubed@485 439 .p_pwrite= process_write_data,
dcubed@485 440 .get_lwp_regs= process_get_lwp_regs
duke@435 441 };
duke@435 442
duke@435 443 // attach to the process. One and only one exposed stuff
sla@8197 444 struct ps_prochandle* Pgrab(pid_t pid, char* err_buf, size_t err_buf_len) {
duke@435 445 struct ps_prochandle* ph = NULL;
duke@435 446 thread_info* thr = NULL;
adinn@9683 447 attach_state_t attach_status = ATTACH_SUCCESS;
duke@435 448
duke@435 449 if ( (ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle))) == NULL) {
adinn@9683 450 snprintf(err_buf, err_buf_len, "can't allocate memory for ps_prochandle");
adinn@9683 451 print_debug("%s\n", err_buf);
adinn@9683 452 return NULL;
duke@435 453 }
duke@435 454
adinn@9683 455 if ((attach_status = ptrace_attach(pid, err_buf, err_buf_len)) != ATTACH_SUCCESS) {
adinn@9683 456 if (attach_status == ATTACH_THREAD_DEAD) {
adinn@9683 457 print_error("The process with pid %d does not exist.\n", pid);
adinn@9683 458 }
adinn@9683 459 free(ph);
adinn@9683 460 return NULL;
duke@435 461 }
duke@435 462
duke@435 463 // initialize ps_prochandle
duke@435 464 ph->pid = pid;
duke@435 465
duke@435 466 // initialize vtable
duke@435 467 ph->ops = &process_ops;
duke@435 468
duke@435 469 // read library info and symbol tables, must do this before attaching threads,
duke@435 470 // as the symbols in the pthread library will be used to figure out
duke@435 471 // the list of threads within the same process.
duke@435 472 read_lib_info(ph);
duke@435 473
duke@435 474 // read thread info
duke@435 475 read_thread_info(ph, add_new_thread);
duke@435 476
duke@435 477 // attach to the threads
duke@435 478 thr = ph->threads;
adinn@9683 479
duke@435 480 while (thr) {
adinn@9683 481 thread_info* current_thr = thr;
adinn@9683 482 thr = thr->next;
adinn@9683 483 // don't attach to the main thread again
adinn@9683 484 if (ph->pid != current_thr->lwp_id) {
adinn@9683 485 if ((attach_status = ptrace_attach(current_thr->lwp_id, err_buf, err_buf_len)) != ATTACH_SUCCESS) {
adinn@9683 486 if (attach_status == ATTACH_THREAD_DEAD) {
adinn@9683 487 // Remove this thread from the threads list
adinn@9683 488 delete_thread_info(ph, current_thr);
adinn@9683 489 }
adinn@9683 490 else {
adinn@9683 491 Prelease(ph);
adinn@9683 492 return NULL;
adinn@9683 493 } // ATTACH_THREAD_DEAD
adinn@9683 494 } // !ATTACH_SUCCESS
adinn@9683 495 }
duke@435 496 }
duke@435 497 return ph;
duke@435 498 }

mercurial