agent/src/os/linux/ps_proc.c

changeset 4599
2394a89e89f4
parent 2384
0a8e0d4345b3
child 5797
f2512d89ad0c
     1.1 --- a/agent/src/os/linux/ps_proc.c	Wed Feb 13 11:23:46 2013 +0100
     1.2 +++ b/agent/src/os/linux/ps_proc.c	Wed Feb 13 09:46:19 2013 +0100
     1.3 @@ -1,5 +1,5 @@
     1.4  /*
     1.5 - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
     1.6 + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
     1.7   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.8   *
     1.9   * This code is free software; you can redistribute it and/or modify it
    1.10 @@ -25,6 +25,7 @@
    1.11  #include <stdio.h>
    1.12  #include <stdlib.h>
    1.13  #include <string.h>
    1.14 +#include <signal.h>
    1.15  #include <errno.h>
    1.16  #include <sys/ptrace.h>
    1.17  #include "libproc_impl.h"
    1.18 @@ -142,46 +143,71 @@
    1.19  
    1.20  }
    1.21  
    1.22 +static bool ptrace_continue(pid_t pid, int signal) {
    1.23 +  // pass the signal to the process so we don't swallow it
    1.24 +  if (ptrace(PTRACE_CONT, pid, NULL, signal) < 0) {
    1.25 +    print_debug("ptrace(PTRACE_CONT, ..) failed for %d\n", pid);
    1.26 +    return false;
    1.27 +  }
    1.28 +  return true;
    1.29 +}
    1.30 +
    1.31 +// waits until the ATTACH has stopped the process
    1.32 +// by signal SIGSTOP
    1.33 +static bool ptrace_waitpid(pid_t pid) {
    1.34 +  int ret;
    1.35 +  int status;
    1.36 +  while (true) {
    1.37 +    // Wait for debuggee to stop.
    1.38 +    ret = waitpid(pid, &status, 0);
    1.39 +    if (ret == -1 && errno == ECHILD) {
    1.40 +      // try cloned process.
    1.41 +      ret = waitpid(pid, &status, __WALL);
    1.42 +    }
    1.43 +    if (ret >= 0) {
    1.44 +      if (WIFSTOPPED(status)) {
    1.45 +        // Any signal will stop the thread, make sure it is SIGSTOP. Otherwise SIGSTOP
    1.46 +        // will still be pending and delivered when the process is DETACHED and the process
    1.47 +        // will go to sleep.
    1.48 +        if (WSTOPSIG(status) == SIGSTOP) {
    1.49 +          // Debuggee stopped by SIGSTOP.
    1.50 +          return true;
    1.51 +        }
    1.52 +        if (!ptrace_continue(pid, WSTOPSIG(status))) {
    1.53 +          print_error("Failed to correctly attach to VM. VM might HANG! [PTRACE_CONT failed, stopped by %d]\n", WSTOPSIG(status));
    1.54 +          return false;
    1.55 +        }
    1.56 +      } else {
    1.57 +        print_debug("waitpid(): Child process exited/terminated (status = 0x%x)\n", status);
    1.58 +        return false;
    1.59 +      }
    1.60 +    } else {
    1.61 +      switch (errno) {
    1.62 +        case EINTR:
    1.63 +          continue;
    1.64 +          break;
    1.65 +        case ECHILD:
    1.66 +          print_debug("waitpid() failed. Child process pid (%d) does not exist \n", pid);
    1.67 +          break;
    1.68 +        case EINVAL:
    1.69 +          print_debug("waitpid() failed. Invalid options argument.\n");
    1.70 +          break;
    1.71 +        default:
    1.72 +          print_debug("waitpid() failed. Unexpected error %d\n",errno);
    1.73 +          break;
    1.74 +      }
    1.75 +      return false;
    1.76 +    }
    1.77 +  }
    1.78 +}
    1.79 +
    1.80  // attach to a process/thread specified by "pid"
    1.81  static bool ptrace_attach(pid_t pid) {
    1.82    if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) {
    1.83      print_debug("ptrace(PTRACE_ATTACH, ..) failed for %d\n", pid);
    1.84      return false;
    1.85    } else {
    1.86 -    int ret;
    1.87 -    int status;
    1.88 -    do {
    1.89 -      // Wait for debuggee to stop.
    1.90 -      ret = waitpid(pid, &status, 0);
    1.91 -      if (ret == -1 && errno == ECHILD) {
    1.92 -        // try cloned process.
    1.93 -        ret = waitpid(pid, &status, __WALL);
    1.94 -      }
    1.95 -      if (ret >= 0) {
    1.96 -        if (WIFSTOPPED(status)) {
    1.97 -          // Debuggee stopped.
    1.98 -          return true;
    1.99 -        } else {
   1.100 -          print_debug("waitpid(): Child process exited/terminated (status = 0x%x)\n", status);
   1.101 -          return false;
   1.102 -        }
   1.103 -      } else {
   1.104 -        switch (errno) {
   1.105 -          case EINTR:
   1.106 -            continue;
   1.107 -            break;
   1.108 -          case ECHILD:
   1.109 -            print_debug("waitpid() failed. Child process pid (%d) does not exist \n", pid);
   1.110 -            break;
   1.111 -          case EINVAL:
   1.112 -            print_debug("waitpid() failed. Invalid options argument.\n");
   1.113 -            break;
   1.114 -          default:
   1.115 -            print_debug("waitpid() failed. Unexpected error %d\n",errno);
   1.116 -        }
   1.117 -        return false;
   1.118 -      }
   1.119 -    } while(true);
   1.120 +    return ptrace_waitpid(pid);
   1.121    }
   1.122  }
   1.123  

mercurial