Mon, 17 Jun 2019 17:20:10 +0100
Merge
1.1 --- a/.hgtags Mon Jun 17 16:41:38 2019 +0100 1.2 +++ b/.hgtags Mon Jun 17 17:20:10 2019 +0100 1.3 @@ -1267,3 +1267,4 @@ 1.4 af43bab3c5d022f0e0b7890f732d8b365b4364cc jdk8u222-b03 1.5 d690709cc3398f8cfd6ffebb89a229105fb3e69a jdk8u222-b04 1.6 1ec20e8a3d8a7a29e9113b14567abec9f0240e9d jdk8u222-b05 1.7 +17778f8991c83d794897f05210dce2d2a7b4eb2d jdk8u222-b06
2.1 --- a/agent/src/os/linux/libproc_impl.c Mon Jun 17 16:41:38 2019 +0100 2.2 +++ b/agent/src/os/linux/libproc_impl.c Mon Jun 17 17:20:10 2019 +0100 2.3 @@ -1,5 +1,5 @@ 2.4 /* 2.5 - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. 2.6 + * Copyright (c) 2003, 2019, 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 @@ -256,6 +256,26 @@ 2.11 return newthr; 2.12 } 2.13 2.14 +void delete_thread_info(struct ps_prochandle* ph, thread_info* thr_to_be_removed) { 2.15 + thread_info* current_thr = ph->threads; 2.16 + 2.17 + if (thr_to_be_removed == ph->threads) { 2.18 + ph->threads = ph->threads->next; 2.19 + } else { 2.20 + thread_info* previous_thr; 2.21 + while (current_thr && current_thr != thr_to_be_removed) { 2.22 + previous_thr = current_thr; 2.23 + current_thr = current_thr->next; 2.24 + } 2.25 + if (current_thr == NULL) { 2.26 + print_error("Could not find the thread to be removed"); 2.27 + return; 2.28 + } 2.29 + previous_thr->next = current_thr->next; 2.30 + } 2.31 + ph->num_threads--; 2.32 + free(current_thr); 2.33 +} 2.34 2.35 // struct used for client data from thread_db callback 2.36 struct thread_db_client_data { 2.37 @@ -278,6 +298,11 @@ 2.38 2.39 print_debug("thread_db : pthread %d (lwp %d)\n", ti.ti_tid, ti.ti_lid); 2.40 2.41 + if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE) { 2.42 + print_debug("Skipping pthread %d (lwp %d)\n", ti.ti_tid, ti.ti_lid); 2.43 + return TD_OK; 2.44 + } 2.45 + 2.46 if (ptr->callback(ptr->ph, ti.ti_tid, ti.ti_lid) != true) 2.47 return TD_ERR; 2.48
3.1 --- a/agent/src/os/linux/libproc_impl.h Mon Jun 17 16:41:38 2019 +0100 3.2 +++ b/agent/src/os/linux/libproc_impl.h Mon Jun 17 17:20:10 2019 +0100 3.3 @@ -1,5 +1,5 @@ 3.4 /* 3.5 - * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. 3.6 + * Copyright (c) 2003, 2019, 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 @@ -113,6 +113,9 @@ 3.11 // reads thread info using libthread_db and calls above callback for each thread 3.12 bool read_thread_info(struct ps_prochandle* ph, thread_info_callback cb); 3.13 3.14 +// deletes a thread from the thread list 3.15 +void delete_thread_info(struct ps_prochandle* ph, thread_info* thr); 3.16 + 3.17 // adds a new shared object to lib list, returns NULL on failure 3.18 lib_info* add_lib_info(struct ps_prochandle* ph, const char* libname, uintptr_t base); 3.19
4.1 --- a/agent/src/os/linux/ps_proc.c Mon Jun 17 16:41:38 2019 +0100 4.2 +++ b/agent/src/os/linux/ps_proc.c Mon Jun 17 17:20:10 2019 +0100 4.3 @@ -28,6 +28,7 @@ 4.4 #include <signal.h> 4.5 #include <errno.h> 4.6 #include <elf.h> 4.7 +#include <ctype.h> 4.8 #include <sys/types.h> 4.9 #include <sys/wait.h> 4.10 #include <sys/ptrace.h> 4.11 @@ -45,6 +46,12 @@ 4.12 // This file has the libproc implementation specific to live process 4.13 // For core files, refer to ps_core.c 4.14 4.15 +typedef enum { 4.16 + ATTACH_SUCCESS, 4.17 + ATTACH_FAIL, 4.18 + ATTACH_THREAD_DEAD 4.19 +} attach_state_t; 4.20 + 4.21 static inline uintptr_t align(uintptr_t ptr, size_t size) { 4.22 return (ptr & ~(size - 1)); 4.23 } 4.24 @@ -167,9 +174,10 @@ 4.25 4.26 // waits until the ATTACH has stopped the process 4.27 // by signal SIGSTOP 4.28 -static bool ptrace_waitpid(pid_t pid) { 4.29 +static attach_state_t ptrace_waitpid(pid_t pid) { 4.30 int ret; 4.31 int status; 4.32 + errno = 0; 4.33 while (true) { 4.34 // Wait for debuggee to stop. 4.35 ret = waitpid(pid, &status, 0); 4.36 @@ -184,15 +192,15 @@ 4.37 // will go to sleep. 4.38 if (WSTOPSIG(status) == SIGSTOP) { 4.39 // Debuggee stopped by SIGSTOP. 4.40 - return true; 4.41 + return ATTACH_SUCCESS; 4.42 } 4.43 if (!ptrace_continue(pid, WSTOPSIG(status))) { 4.44 print_error("Failed to correctly attach to VM. VM might HANG! [PTRACE_CONT failed, stopped by %d]\n", WSTOPSIG(status)); 4.45 - return false; 4.46 + return ATTACH_FAIL; 4.47 } 4.48 } else { 4.49 - print_debug("waitpid(): Child process exited/terminated (status = 0x%x)\n", status); 4.50 - return false; 4.51 + print_debug("waitpid(): Child process %d exited/terminated (status = 0x%x)\n", pid, status); 4.52 + return ATTACH_THREAD_DEAD; 4.53 } 4.54 } else { 4.55 switch (errno) { 4.56 @@ -201,29 +209,89 @@ 4.57 break; 4.58 case ECHILD: 4.59 print_debug("waitpid() failed. Child process pid (%d) does not exist \n", pid); 4.60 - break; 4.61 + return ATTACH_THREAD_DEAD; 4.62 case EINVAL: 4.63 - print_debug("waitpid() failed. Invalid options argument.\n"); 4.64 - break; 4.65 + print_error("waitpid() failed. Invalid options argument.\n"); 4.66 + return ATTACH_FAIL; 4.67 default: 4.68 - print_debug("waitpid() failed. Unexpected error %d\n",errno); 4.69 - break; 4.70 + print_error("waitpid() failed. Unexpected error %d\n",errno); 4.71 + return ATTACH_FAIL; 4.72 } 4.73 - return false; 4.74 + } // else 4.75 + } // while 4.76 +} 4.77 + 4.78 +// checks the state of the thread/process specified by "pid", by reading 4.79 +// in the 'State:' value from the /proc/<pid>/status file. From the proc 4.80 +// man page, "Current state of the process. One of "R (running)", 4.81 +// "S (sleeping)", "D (disk sleep)", "T (stopped)", "T (tracing stop)", 4.82 +// "Z (zombie)", or "X (dead)"." Assumes that the thread is dead if we 4.83 +// don't find the status file or if the status is 'X' or 'Z'. 4.84 +static bool process_doesnt_exist(pid_t pid) { 4.85 + char fname[32]; 4.86 + char buf[30]; 4.87 + FILE *fp = NULL; 4.88 + const char state_string[] = "State:"; 4.89 + 4.90 + sprintf(fname, "/proc/%d/status", pid); 4.91 + fp = fopen(fname, "r"); 4.92 + if (fp == NULL) { 4.93 + print_debug("can't open /proc/%d/status file\n", pid); 4.94 + // Assume the thread does not exist anymore. 4.95 + return true; 4.96 + } 4.97 + bool found_state = false; 4.98 + size_t state_len = strlen(state_string); 4.99 + while (fgets(buf, sizeof(buf), fp) != NULL) { 4.100 + char *state = NULL; 4.101 + if (strncmp (buf, state_string, state_len) == 0) { 4.102 + found_state = true; 4.103 + state = buf + state_len; 4.104 + // Skip the spaces 4.105 + while (isspace(*state)) { 4.106 + state++; 4.107 + } 4.108 + // A state value of 'X' indicates that the thread is dead. 'Z' 4.109 + // indicates that the thread is a zombie. 4.110 + if (*state == 'X' || *state == 'Z') { 4.111 + fclose (fp); 4.112 + return true; 4.113 + } 4.114 + break; 4.115 } 4.116 } 4.117 + // If the state value is not 'X' or 'Z', the thread exists. 4.118 + if (!found_state) { 4.119 + // We haven't found the line beginning with 'State:'. 4.120 + // Assuming the thread exists. 4.121 + print_error("Could not find the 'State:' string in the /proc/%d/status file\n", pid); 4.122 + } 4.123 + fclose (fp); 4.124 + return false; 4.125 } 4.126 4.127 // attach to a process/thread specified by "pid" 4.128 -static bool ptrace_attach(pid_t pid, char* err_buf, size_t err_buf_len) { 4.129 +static attach_state_t ptrace_attach(pid_t pid, char* err_buf, size_t err_buf_len) { 4.130 + errno = 0; 4.131 if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0) { 4.132 + if (errno == EPERM || errno == ESRCH) { 4.133 + // Check if the process/thread is exiting or is a zombie 4.134 + if (process_doesnt_exist(pid)) { 4.135 + print_debug("Thread with pid %d does not exist\n", pid); 4.136 + return ATTACH_THREAD_DEAD; 4.137 + } 4.138 + } 4.139 char buf[200]; 4.140 char* msg = strerror_r(errno, buf, sizeof(buf)); 4.141 snprintf(err_buf, err_buf_len, "ptrace(PTRACE_ATTACH, ..) failed for %d: %s", pid, msg); 4.142 - print_debug("%s\n", err_buf); 4.143 - return false; 4.144 + print_error("%s\n", err_buf); 4.145 + return ATTACH_FAIL; 4.146 } else { 4.147 - return ptrace_waitpid(pid); 4.148 + attach_state_t wait_ret = ptrace_waitpid(pid); 4.149 + if (wait_ret == ATTACH_THREAD_DEAD) { 4.150 + print_debug("Thread with pid %d does not exist\n", pid); 4.151 + } 4.152 + return wait_ret; 4.153 } 4.154 } 4.155 4.156 @@ -345,16 +413,20 @@ 4.157 struct ps_prochandle* Pgrab(pid_t pid, char* err_buf, size_t err_buf_len) { 4.158 struct ps_prochandle* ph = NULL; 4.159 thread_info* thr = NULL; 4.160 + attach_state_t attach_status = ATTACH_SUCCESS; 4.161 4.162 if ( (ph = (struct ps_prochandle*) calloc(1, sizeof(struct ps_prochandle))) == NULL) { 4.163 - snprintf(err_buf, err_buf_len, "can't allocate memory for ps_prochandle"); 4.164 - print_debug("%s\n", err_buf); 4.165 - return NULL; 4.166 + snprintf(err_buf, err_buf_len, "can't allocate memory for ps_prochandle"); 4.167 + print_debug("%s\n", err_buf); 4.168 + return NULL; 4.169 } 4.170 4.171 - if (ptrace_attach(pid, err_buf, err_buf_len) != true) { 4.172 - free(ph); 4.173 - return NULL; 4.174 + if ((attach_status = ptrace_attach(pid, err_buf, err_buf_len)) != ATTACH_SUCCESS) { 4.175 + if (attach_status == ATTACH_THREAD_DEAD) { 4.176 + print_error("The process with pid %d does not exist.\n", pid); 4.177 + } 4.178 + free(ph); 4.179 + return NULL; 4.180 } 4.181 4.182 // initialize ps_prochandle 4.183 @@ -373,14 +445,23 @@ 4.184 4.185 // attach to the threads 4.186 thr = ph->threads; 4.187 + 4.188 while (thr) { 4.189 - // don't attach to the main thread again 4.190 - if (ph->pid != thr->lwp_id && ptrace_attach(thr->lwp_id, err_buf, err_buf_len) != true) { 4.191 - // even if one attach fails, we get return NULL 4.192 - Prelease(ph); 4.193 - return NULL; 4.194 - } 4.195 - thr = thr->next; 4.196 + thread_info* current_thr = thr; 4.197 + thr = thr->next; 4.198 + // don't attach to the main thread again 4.199 + if (ph->pid != current_thr->lwp_id) { 4.200 + if ((attach_status = ptrace_attach(current_thr->lwp_id, err_buf, err_buf_len)) != ATTACH_SUCCESS) { 4.201 + if (attach_status == ATTACH_THREAD_DEAD) { 4.202 + // Remove this thread from the threads list 4.203 + delete_thread_info(ph, current_thr); 4.204 + } 4.205 + else { 4.206 + Prelease(ph); 4.207 + return NULL; 4.208 + } // ATTACH_THREAD_DEAD 4.209 + } // !ATTACH_SUCCESS 4.210 + } 4.211 } 4.212 return ph; 4.213 }