1 /* Linux-specific PROCFS manipulation routines. 2 Copyright (C) 2009-2015 Free Software Foundation, Inc. 3 4 This file is part of GDB. 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 18 19 #include "common-defs.h" 20 #include "linux-procfs.h" 21 #include "filestuff.h" 22 #include <dirent.h> 23 24 /* Return the TGID of LWPID from /proc/pid/status. Returns -1 if not 25 found. */ 26 27 static int 28 linux_proc_get_int (pid_t lwpid, const char *field, int warn) 29 { 30 size_t field_len = strlen (field); 31 FILE *status_file; 32 char buf[100]; 33 int retval = -1; 34 35 snprintf (buf, sizeof (buf), "/proc/%d/status", (int) lwpid); 36 status_file = gdb_fopen_cloexec (buf, "r"); 37 if (status_file == NULL) 38 { 39 if (warn) 40 warning (_("unable to open /proc file '%s'"), buf); 41 return -1; 42 } 43 44 while (fgets (buf, sizeof (buf), status_file)) 45 if (strncmp (buf, field, field_len) == 0 && buf[field_len] == ':') 46 { 47 retval = strtol (&buf[field_len + 1], NULL, 10); 48 break; 49 } 50 51 fclose (status_file); 52 return retval; 53 } 54 55 /* Return the TGID of LWPID from /proc/pid/status. Returns -1 if not 56 found. */ 57 58 int 59 linux_proc_get_tgid (pid_t lwpid) 60 { 61 return linux_proc_get_int (lwpid, "Tgid", 1); 62 } 63 64 /* See linux-procfs.h. */ 65 66 pid_t 67 linux_proc_get_tracerpid_nowarn (pid_t lwpid) 68 { 69 return linux_proc_get_int (lwpid, "TracerPid", 0); 70 } 71 72 /* Fill in BUFFER, a buffer with BUFFER_SIZE bytes with the 'State' 73 line of /proc/PID/status. Returns -1 on failure to open the /proc 74 file, 1 if the line is found, and 0 if not found. If WARN, warn on 75 failure to open the /proc file. */ 76 77 static int 78 linux_proc_pid_get_state (pid_t pid, char *buffer, size_t buffer_size, 79 int warn) 80 { 81 FILE *procfile; 82 int have_state; 83 84 xsnprintf (buffer, buffer_size, "/proc/%d/status", (int) pid); 85 procfile = gdb_fopen_cloexec (buffer, "r"); 86 if (procfile == NULL) 87 { 88 if (warn) 89 warning (_("unable to open /proc file '%s'"), buffer); 90 return -1; 91 } 92 93 have_state = 0; 94 while (fgets (buffer, buffer_size, procfile) != NULL) 95 if (strncmp (buffer, "State:", 6) == 0) 96 { 97 have_state = 1; 98 break; 99 } 100 fclose (procfile); 101 return have_state; 102 } 103 104 /* See linux-procfs.h declaration. */ 105 106 int 107 linux_proc_pid_is_gone (pid_t pid) 108 { 109 char buffer[100]; 110 int have_state; 111 112 have_state = linux_proc_pid_get_state (pid, buffer, sizeof buffer, 0); 113 if (have_state < 0) 114 { 115 /* If we can't open the status file, assume the thread has 116 disappeared. */ 117 return 1; 118 } 119 else if (have_state == 0) 120 { 121 /* No "State:" line, assume thread is alive. */ 122 return 0; 123 } 124 else 125 { 126 return (strstr (buffer, "Z (") != NULL 127 || strstr (buffer, "X (") != NULL); 128 } 129 } 130 131 /* Return non-zero if 'State' of /proc/PID/status contains STATE. If 132 WARN, warn on failure to open the /proc file. */ 133 134 static int 135 linux_proc_pid_has_state (pid_t pid, const char *state, int warn) 136 { 137 char buffer[100]; 138 int have_state; 139 140 have_state = linux_proc_pid_get_state (pid, buffer, sizeof buffer, warn); 141 return (have_state > 0 && strstr (buffer, state) != NULL); 142 } 143 144 /* Detect `T (stopped)' in `/proc/PID/status'. 145 Other states including `T (tracing stop)' are reported as false. */ 146 147 int 148 linux_proc_pid_is_stopped (pid_t pid) 149 { 150 return linux_proc_pid_has_state (pid, "T (stopped)", 1); 151 } 152 153 /* Return non-zero if PID is a zombie. If WARN, warn on failure to 154 open the /proc file. */ 155 156 static int 157 linux_proc_pid_is_zombie_maybe_warn (pid_t pid, int warn) 158 { 159 return linux_proc_pid_has_state (pid, "Z (zombie)", warn); 160 } 161 162 /* See linux-procfs.h declaration. */ 163 164 int 165 linux_proc_pid_is_zombie_nowarn (pid_t pid) 166 { 167 return linux_proc_pid_is_zombie_maybe_warn (pid, 0); 168 } 169 170 /* See linux-procfs.h declaration. */ 171 172 int 173 linux_proc_pid_is_zombie (pid_t pid) 174 { 175 return linux_proc_pid_is_zombie_maybe_warn (pid, 1); 176 } 177 178 /* See linux-procfs.h declaration. */ 179 180 char * 181 linux_proc_pid_get_ns (pid_t pid, const char *ns) 182 { 183 char buf[100]; 184 char nsval[64]; 185 int ret; 186 xsnprintf (buf, sizeof (buf), "/proc/%d/ns/%s", (int) pid, ns); 187 ret = readlink (buf, nsval, sizeof (nsval)); 188 if (0 < ret && ret < sizeof (nsval)) 189 { 190 nsval[ret] = '\0'; 191 return xstrdup (nsval); 192 } 193 194 return NULL; 195 } 196 197 /* See linux-procfs.h. */ 198 199 void 200 linux_proc_attach_tgid_threads (pid_t pid, 201 linux_proc_attach_lwp_func attach_lwp) 202 { 203 DIR *dir; 204 char pathname[128]; 205 int new_threads_found; 206 int iterations; 207 208 if (linux_proc_get_tgid (pid) != pid) 209 return; 210 211 xsnprintf (pathname, sizeof (pathname), "/proc/%ld/task", (long) pid); 212 dir = opendir (pathname); 213 if (dir == NULL) 214 { 215 warning (_("Could not open /proc/%ld/task."), (long) pid); 216 return; 217 } 218 219 /* Scan the task list for existing threads. While we go through the 220 threads, new threads may be spawned. Cycle through the list of 221 threads until we have done two iterations without finding new 222 threads. */ 223 for (iterations = 0; iterations < 2; iterations++) 224 { 225 struct dirent *dp; 226 227 new_threads_found = 0; 228 while ((dp = readdir (dir)) != NULL) 229 { 230 unsigned long lwp; 231 232 /* Fetch one lwp. */ 233 lwp = strtoul (dp->d_name, NULL, 10); 234 if (lwp != 0) 235 { 236 ptid_t ptid = ptid_build (pid, lwp, 0); 237 238 if (attach_lwp (ptid)) 239 new_threads_found = 1; 240 } 241 } 242 243 if (new_threads_found) 244 { 245 /* Start over. */ 246 iterations = -1; 247 } 248 249 rewinddir (dir); 250 } 251 252 closedir (dir); 253 } 254