Wed, 13 Feb 2013 09:46:19 +0100
8008088: SA can hang the VM
Reviewed-by: mgronlun, sla, dholmes
1.1 --- a/agent/src/os/bsd/libproc_impl.c Wed Feb 13 11:23:46 2013 +0100 1.2 +++ b/agent/src/os/bsd/libproc_impl.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 @@ -91,6 +91,14 @@ 1.11 } 1.12 } 1.13 1.14 +void print_error(const char* format,...) { 1.15 + va_list alist; 1.16 + va_start(alist, format); 1.17 + fputs("ERROR: ", stderr); 1.18 + vfprintf(stderr, format, alist); 1.19 + va_end(alist); 1.20 +} 1.21 + 1.22 bool is_debug() { 1.23 return _libsaproc_debug; 1.24 }
2.1 --- a/agent/src/os/bsd/libproc_impl.h Wed Feb 13 11:23:46 2013 +0100 2.2 +++ b/agent/src/os/bsd/libproc_impl.h Wed Feb 13 09:46:19 2013 +0100 2.3 @@ -1,5 +1,5 @@ 2.4 /* 2.5 - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. 2.6 + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. 2.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 2.8 * 2.9 * This code is free software; you can redistribute it and/or modify it 2.10 @@ -107,6 +107,7 @@ 2.11 int pathmap_open(const char* name); 2.12 2.13 void print_debug(const char* format,...); 2.14 +void print_error(const char* format,...); 2.15 bool is_debug(); 2.16 2.17 typedef bool (*thread_info_callback)(struct ps_prochandle* ph, pthread_t pid, lwpid_t lwpid);
3.1 --- a/agent/src/os/bsd/ps_proc.c Wed Feb 13 11:23:46 2013 +0100 3.2 +++ b/agent/src/os/bsd/ps_proc.c Wed Feb 13 09:46:19 2013 +0100 3.3 @@ -1,5 +1,5 @@ 3.4 /* 3.5 - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 3.6 + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. 3.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3.8 * 3.9 * This code is free software; you can redistribute it and/or modify it 3.10 @@ -129,42 +129,66 @@ 3.11 return (errno == 0)? true: false; 3.12 } 3.13 3.14 +static bool ptrace_continue(pid_t pid, int signal) { 3.15 + // pass the signal to the process so we don't swallow it 3.16 + if (ptrace(PTRACE_CONT, pid, NULL, signal) < 0) { 3.17 + print_debug("ptrace(PTRACE_CONT, ..) failed for %d\n", pid); 3.18 + return false; 3.19 + } 3.20 + return true; 3.21 +} 3.22 + 3.23 +// waits until the ATTACH has stopped the process 3.24 +// by signal SIGSTOP 3.25 +static bool ptrace_waitpid(pid_t pid) { 3.26 + int ret; 3.27 + int status; 3.28 + do { 3.29 + // Wait for debuggee to stop. 3.30 + ret = waitpid(pid, &status, 0); 3.31 + if (ret >= 0) { 3.32 + if (WIFSTOPPED(status)) { 3.33 + // Any signal will stop the thread, make sure it is SIGSTOP. Otherwise SIGSTOP 3.34 + // will still be pending and delivered when the process is DETACHED and the process 3.35 + // will go to sleep. 3.36 + if (WSTOPSIG(status) == SIGSTOP) { 3.37 + // Debuggee stopped by SIGSTOP. 3.38 + return true; 3.39 + } 3.40 + if (!ptrace_continue(pid, WSTOPSIG(status))) { 3.41 + print_error("Failed to correctly attach to VM. VM might HANG! [PTRACE_CONT failed, stopped by %d]\n", WSTOPSIG(status)); 3.42 + return false; 3.43 + } 3.44 + } else { 3.45 + print_debug("waitpid(): Child process exited/terminated (status = 0x%x)\n", status); 3.46 + return false; 3.47 + } 3.48 + } else { 3.49 + switch (errno) { 3.50 + case EINTR: 3.51 + continue; 3.52 + break; 3.53 + case ECHILD: 3.54 + print_debug("waitpid() failed. Child process pid (%d) does not exist \n", pid); 3.55 + break; 3.56 + case EINVAL: 3.57 + print_debug("waitpid() failed. Invalid options argument.\n"); 3.58 + break; 3.59 + default: 3.60 + print_debug("waitpid() failed. Unexpected error %d\n",errno); 3.61 + } 3.62 + return false; 3.63 + } 3.64 + } while(true); 3.65 +} 3.66 + 3.67 // attach to a process/thread specified by "pid" 3.68 static bool ptrace_attach(pid_t pid) { 3.69 if (ptrace(PT_ATTACH, pid, NULL, 0) < 0) { 3.70 print_debug("ptrace(PTRACE_ATTACH, ..) failed for %d\n", pid); 3.71 return false; 3.72 } else { 3.73 - int ret; 3.74 - int status; 3.75 - do { 3.76 - // Wait for debuggee to stop. 3.77 - ret = waitpid(pid, &status, 0); 3.78 - if (ret >= 0) { 3.79 - if (WIFSTOPPED(status)) { 3.80 - // Debuggee stopped. 3.81 - return true; 3.82 - } else { 3.83 - print_debug("waitpid(): Child process exited/terminated (status = 0x%x)\n", status); 3.84 - return false; 3.85 - } 3.86 - } else { 3.87 - switch (errno) { 3.88 - case EINTR: 3.89 - continue; 3.90 - break; 3.91 - case ECHILD: 3.92 - print_debug("waitpid() failed. Child process pid (%d) does not exist \n", pid); 3.93 - break; 3.94 - case EINVAL: 3.95 - print_debug("waitpid() failed. Invalid options argument.\n"); 3.96 - break; 3.97 - default: 3.98 - print_debug("waitpid() failed. Unexpected error %d\n",errno); 3.99 - } 3.100 - return false; 3.101 - } 3.102 - } while(true); 3.103 + return ptrace_waitpid(pid); 3.104 } 3.105 } 3.106
4.1 --- a/agent/src/os/linux/libproc_impl.c Wed Feb 13 11:23:46 2013 +0100 4.2 +++ b/agent/src/os/linux/libproc_impl.c Wed Feb 13 09:46:19 2013 +0100 4.3 @@ -1,5 +1,5 @@ 4.4 /* 4.5 - * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved. 4.6 + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. 4.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4.8 * 4.9 * This code is free software; you can redistribute it and/or modify it 4.10 @@ -92,6 +92,14 @@ 4.11 } 4.12 } 4.13 4.14 +void print_error(const char* format,...) { 4.15 + va_list alist; 4.16 + va_start(alist, format); 4.17 + fputs("ERROR: ", stderr); 4.18 + vfprintf(stderr, format, alist); 4.19 + va_end(alist); 4.20 +} 4.21 + 4.22 bool is_debug() { 4.23 return _libsaproc_debug; 4.24 }
5.1 --- a/agent/src/os/linux/libproc_impl.h Wed Feb 13 11:23:46 2013 +0100 5.2 +++ b/agent/src/os/linux/libproc_impl.h Wed Feb 13 09:46:19 2013 +0100 5.3 @@ -1,5 +1,5 @@ 5.4 /* 5.5 - * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. 5.6 + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. 5.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5.8 * 5.9 * This code is free software; you can redistribute it and/or modify it 5.10 @@ -105,6 +105,7 @@ 5.11 int pathmap_open(const char* name); 5.12 5.13 void print_debug(const char* format,...); 5.14 +void print_error(const char* format,...); 5.15 bool is_debug(); 5.16 5.17 typedef bool (*thread_info_callback)(struct ps_prochandle* ph, pthread_t pid, lwpid_t lwpid);
6.1 --- a/agent/src/os/linux/ps_proc.c Wed Feb 13 11:23:46 2013 +0100 6.2 +++ b/agent/src/os/linux/ps_proc.c Wed Feb 13 09:46:19 2013 +0100 6.3 @@ -1,5 +1,5 @@ 6.4 /* 6.5 - * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 6.6 + * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. 6.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6.8 * 6.9 * This code is free software; you can redistribute it and/or modify it 6.10 @@ -25,6 +25,7 @@ 6.11 #include <stdio.h> 6.12 #include <stdlib.h> 6.13 #include <string.h> 6.14 +#include <signal.h> 6.15 #include <errno.h> 6.16 #include <sys/ptrace.h> 6.17 #include "libproc_impl.h" 6.18 @@ -142,46 +143,71 @@ 6.19 6.20 } 6.21 6.22 +static bool ptrace_continue(pid_t pid, int signal) { 6.23 + // pass the signal to the process so we don't swallow it 6.24 + if (ptrace(PTRACE_CONT, pid, NULL, signal) < 0) { 6.25 + print_debug("ptrace(PTRACE_CONT, ..) failed for %d\n", pid); 6.26 + return false; 6.27 + } 6.28 + return true; 6.29 +} 6.30 + 6.31 +// waits until the ATTACH has stopped the process 6.32 +// by signal SIGSTOP 6.33 +static bool ptrace_waitpid(pid_t pid) { 6.34 + int ret; 6.35 + int status; 6.36 + while (true) { 6.37 + // Wait for debuggee to stop. 6.38 + ret = waitpid(pid, &status, 0); 6.39 + if (ret == -1 && errno == ECHILD) { 6.40 + // try cloned process. 6.41 + ret = waitpid(pid, &status, __WALL); 6.42 + } 6.43 + if (ret >= 0) { 6.44 + if (WIFSTOPPED(status)) { 6.45 + // Any signal will stop the thread, make sure it is SIGSTOP. Otherwise SIGSTOP 6.46 + // will still be pending and delivered when the process is DETACHED and the process 6.47 + // will go to sleep. 6.48 + if (WSTOPSIG(status) == SIGSTOP) { 6.49 + // Debuggee stopped by SIGSTOP. 6.50 + return true; 6.51 + } 6.52 + if (!ptrace_continue(pid, WSTOPSIG(status))) { 6.53 + print_error("Failed to correctly attach to VM. VM might HANG! [PTRACE_CONT failed, stopped by %d]\n", WSTOPSIG(status)); 6.54 + return false; 6.55 + } 6.56 + } else { 6.57 + print_debug("waitpid(): Child process exited/terminated (status = 0x%x)\n", status); 6.58 + return false; 6.59 + } 6.60 + } else { 6.61 + switch (errno) { 6.62 + case EINTR: 6.63 + continue; 6.64 + break; 6.65 + case ECHILD: 6.66 + print_debug("waitpid() failed. Child process pid (%d) does not exist \n", pid); 6.67 + break; 6.68 + case EINVAL: 6.69 + print_debug("waitpid() failed. Invalid options argument.\n"); 6.70 + break; 6.71 + default: 6.72 + print_debug("waitpid() failed. Unexpected error %d\n",errno); 6.73 + break; 6.74 + } 6.75 + return false; 6.76 + } 6.77 + } 6.78 +} 6.79 + 6.80 // attach to a process/thread specified by "pid" 6.81 static bool ptrace_attach(pid_t pid) { 6.82 if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) { 6.83 print_debug("ptrace(PTRACE_ATTACH, ..) failed for %d\n", pid); 6.84 return false; 6.85 } else { 6.86 - int ret; 6.87 - int status; 6.88 - do { 6.89 - // Wait for debuggee to stop. 6.90 - ret = waitpid(pid, &status, 0); 6.91 - if (ret == -1 && errno == ECHILD) { 6.92 - // try cloned process. 6.93 - ret = waitpid(pid, &status, __WALL); 6.94 - } 6.95 - if (ret >= 0) { 6.96 - if (WIFSTOPPED(status)) { 6.97 - // Debuggee stopped. 6.98 - return true; 6.99 - } else { 6.100 - print_debug("waitpid(): Child process exited/terminated (status = 0x%x)\n", status); 6.101 - return false; 6.102 - } 6.103 - } else { 6.104 - switch (errno) { 6.105 - case EINTR: 6.106 - continue; 6.107 - break; 6.108 - case ECHILD: 6.109 - print_debug("waitpid() failed. Child process pid (%d) does not exist \n", pid); 6.110 - break; 6.111 - case EINVAL: 6.112 - print_debug("waitpid() failed. Invalid options argument.\n"); 6.113 - break; 6.114 - default: 6.115 - print_debug("waitpid() failed. Unexpected error %d\n",errno); 6.116 - } 6.117 - return false; 6.118 - } 6.119 - } while(true); 6.120 + return ptrace_waitpid(pid); 6.121 } 6.122 } 6.123