Commit | Line | Data |
---|---|---|
13da1c97 | 1 | /* Linux-specific PROCFS manipulation routines. |
42a4f53d | 2 | Copyright (C) 2009-2019 Free Software Foundation, Inc. |
13da1c97 LM |
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 | ||
0747795c | 19 | #include "common/common-defs.h" |
13da1c97 | 20 | #include "linux-procfs.h" |
0747795c | 21 | #include "common/filestuff.h" |
8784d563 | 22 | #include <dirent.h> |
2db9a427 | 23 | #include <sys/stat.h> |
13da1c97 LM |
24 | |
25 | /* Return the TGID of LWPID from /proc/pid/status. Returns -1 if not | |
26 | found. */ | |
27 | ||
87b0bb13 | 28 | static int |
8784d563 | 29 | linux_proc_get_int (pid_t lwpid, const char *field, int warn) |
13da1c97 | 30 | { |
87b0bb13 | 31 | size_t field_len = strlen (field); |
13da1c97 | 32 | char buf[100]; |
87b0bb13 | 33 | int retval = -1; |
13da1c97 LM |
34 | |
35 | snprintf (buf, sizeof (buf), "/proc/%d/status", (int) lwpid); | |
d419f42d | 36 | gdb_file_up status_file = gdb_fopen_cloexec (buf, "r"); |
87b0bb13 | 37 | if (status_file == NULL) |
13da1c97 | 38 | { |
8784d563 PA |
39 | if (warn) |
40 | warning (_("unable to open /proc file '%s'"), buf); | |
87b0bb13 | 41 | return -1; |
13da1c97 LM |
42 | } |
43 | ||
d419f42d | 44 | while (fgets (buf, sizeof (buf), status_file.get ())) |
87b0bb13 JK |
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 | ||
87b0bb13 | 51 | return retval; |
13da1c97 | 52 | } |
644cebc9 | 53 | |
87b0bb13 JK |
54 | /* Return the TGID of LWPID from /proc/pid/status. Returns -1 if not |
55 | found. */ | |
644cebc9 PA |
56 | |
57 | int | |
87b0bb13 | 58 | linux_proc_get_tgid (pid_t lwpid) |
644cebc9 | 59 | { |
8784d563 | 60 | return linux_proc_get_int (lwpid, "Tgid", 1); |
87b0bb13 | 61 | } |
644cebc9 | 62 | |
87b0bb13 JK |
63 | /* See linux-procfs.h. */ |
64 | ||
65 | pid_t | |
8784d563 | 66 | linux_proc_get_tracerpid_nowarn (pid_t lwpid) |
87b0bb13 | 67 | { |
8784d563 | 68 | return linux_proc_get_int (lwpid, "TracerPid", 0); |
644cebc9 | 69 | } |
5f572dec | 70 | |
d617208b PA |
71 | /* Process states as discovered in the 'State' line of |
72 | /proc/PID/status. Not all possible states are represented here, | |
73 | only those that we care about. */ | |
74 | ||
75 | enum proc_state | |
76 | { | |
77 | /* Some state we don't handle. */ | |
78 | PROC_STATE_UNKNOWN, | |
79 | ||
80 | /* Stopped on a signal. */ | |
81 | PROC_STATE_STOPPED, | |
82 | ||
83 | /* Tracing stop. */ | |
84 | PROC_STATE_TRACING_STOP, | |
85 | ||
86 | /* Dead. */ | |
87 | PROC_STATE_DEAD, | |
88 | ||
89 | /* Zombie. */ | |
90 | PROC_STATE_ZOMBIE, | |
91 | }; | |
92 | ||
93 | /* Parse a PROC_STATE out of STATE, a buffer with the state found in | |
94 | the 'State:' line of /proc/PID/status. */ | |
95 | ||
96 | static enum proc_state | |
97 | parse_proc_status_state (const char *state) | |
98 | { | |
f1735a53 | 99 | state = skip_spaces (state); |
d617208b PA |
100 | |
101 | switch (state[0]) | |
102 | { | |
0e1a6a51 PA |
103 | case 't': |
104 | return PROC_STATE_TRACING_STOP; | |
d617208b | 105 | case 'T': |
0e1a6a51 | 106 | /* Before Linux 2.6.33, tracing stop used uppercase T. */ |
5c811d30 | 107 | if (strcmp (state, "T (stopped)\n") == 0) |
d617208b | 108 | return PROC_STATE_STOPPED; |
5c811d30 JK |
109 | else /* "T (tracing stop)\n" */ |
110 | return PROC_STATE_TRACING_STOP; | |
d617208b PA |
111 | case 'X': |
112 | return PROC_STATE_DEAD; | |
113 | case 'Z': | |
114 | return PROC_STATE_ZOMBIE; | |
115 | } | |
116 | ||
117 | return PROC_STATE_UNKNOWN; | |
118 | } | |
119 | ||
120 | ||
121 | /* Fill in STATE, a buffer with BUFFER_SIZE bytes with the 'State' | |
8784d563 PA |
122 | line of /proc/PID/status. Returns -1 on failure to open the /proc |
123 | file, 1 if the line is found, and 0 if not found. If WARN, warn on | |
124 | failure to open the /proc file. */ | |
5f572dec | 125 | |
87b0bb13 | 126 | static int |
d617208b | 127 | linux_proc_pid_get_state (pid_t pid, int warn, enum proc_state *state) |
5f572dec | 128 | { |
5f572dec | 129 | int have_state; |
d617208b | 130 | char buffer[100]; |
5f572dec | 131 | |
d617208b | 132 | xsnprintf (buffer, sizeof (buffer), "/proc/%d/status", (int) pid); |
d419f42d | 133 | gdb_file_up procfile = gdb_fopen_cloexec (buffer, "r"); |
5f572dec JK |
134 | if (procfile == NULL) |
135 | { | |
8784d563 PA |
136 | if (warn) |
137 | warning (_("unable to open /proc file '%s'"), buffer); | |
138 | return -1; | |
5f572dec JK |
139 | } |
140 | ||
141 | have_state = 0; | |
d419f42d | 142 | while (fgets (buffer, sizeof (buffer), procfile.get ()) != NULL) |
61012eef | 143 | if (startswith (buffer, "State:")) |
5f572dec JK |
144 | { |
145 | have_state = 1; | |
d617208b | 146 | *state = parse_proc_status_state (buffer + sizeof ("State:") - 1); |
5f572dec JK |
147 | break; |
148 | } | |
8784d563 PA |
149 | return have_state; |
150 | } | |
151 | ||
152 | /* See linux-procfs.h declaration. */ | |
153 | ||
154 | int | |
155 | linux_proc_pid_is_gone (pid_t pid) | |
156 | { | |
8784d563 | 157 | int have_state; |
d617208b | 158 | enum proc_state state; |
8784d563 | 159 | |
d617208b | 160 | have_state = linux_proc_pid_get_state (pid, 0, &state); |
8784d563 PA |
161 | if (have_state < 0) |
162 | { | |
163 | /* If we can't open the status file, assume the thread has | |
164 | disappeared. */ | |
165 | return 1; | |
166 | } | |
167 | else if (have_state == 0) | |
168 | { | |
169 | /* No "State:" line, assume thread is alive. */ | |
170 | return 0; | |
171 | } | |
172 | else | |
d617208b | 173 | return (state == PROC_STATE_ZOMBIE || state == PROC_STATE_DEAD); |
8784d563 PA |
174 | } |
175 | ||
176 | /* Return non-zero if 'State' of /proc/PID/status contains STATE. If | |
177 | WARN, warn on failure to open the /proc file. */ | |
178 | ||
179 | static int | |
d617208b | 180 | linux_proc_pid_has_state (pid_t pid, enum proc_state state, int warn) |
8784d563 | 181 | { |
8784d563 | 182 | int have_state; |
d617208b | 183 | enum proc_state cur_state; |
8784d563 | 184 | |
d617208b PA |
185 | have_state = linux_proc_pid_get_state (pid, warn, &cur_state); |
186 | return (have_state > 0 && cur_state == state); | |
5f572dec | 187 | } |
87b0bb13 JK |
188 | |
189 | /* Detect `T (stopped)' in `/proc/PID/status'. | |
190 | Other states including `T (tracing stop)' are reported as false. */ | |
191 | ||
192 | int | |
193 | linux_proc_pid_is_stopped (pid_t pid) | |
194 | { | |
d617208b | 195 | return linux_proc_pid_has_state (pid, PROC_STATE_STOPPED, 1); |
8784d563 PA |
196 | } |
197 | ||
d617208b | 198 | /* Detect `t (tracing stop)' in `/proc/PID/status'. |
23f238d3 PA |
199 | Other states including `T (stopped)' are reported as false. */ |
200 | ||
201 | int | |
202 | linux_proc_pid_is_trace_stopped_nowarn (pid_t pid) | |
203 | { | |
d617208b | 204 | return linux_proc_pid_has_state (pid, PROC_STATE_TRACING_STOP, 1); |
23f238d3 PA |
205 | } |
206 | ||
8784d563 PA |
207 | /* Return non-zero if PID is a zombie. If WARN, warn on failure to |
208 | open the /proc file. */ | |
209 | ||
210 | static int | |
211 | linux_proc_pid_is_zombie_maybe_warn (pid_t pid, int warn) | |
212 | { | |
d617208b | 213 | return linux_proc_pid_has_state (pid, PROC_STATE_ZOMBIE, warn); |
8784d563 PA |
214 | } |
215 | ||
216 | /* See linux-procfs.h declaration. */ | |
217 | ||
218 | int | |
219 | linux_proc_pid_is_zombie_nowarn (pid_t pid) | |
220 | { | |
221 | return linux_proc_pid_is_zombie_maybe_warn (pid, 0); | |
87b0bb13 JK |
222 | } |
223 | ||
224 | /* See linux-procfs.h declaration. */ | |
225 | ||
226 | int | |
227 | linux_proc_pid_is_zombie (pid_t pid) | |
228 | { | |
8784d563 | 229 | return linux_proc_pid_is_zombie_maybe_warn (pid, 1); |
87b0bb13 | 230 | } |
015de688 | 231 | |
8784d563 PA |
232 | /* See linux-procfs.h. */ |
233 | ||
79efa585 SM |
234 | const char * |
235 | linux_proc_tid_get_name (ptid_t ptid) | |
236 | { | |
237 | #define TASK_COMM_LEN 16 /* As defined in the kernel's sched.h. */ | |
238 | ||
239 | static char comm_buf[TASK_COMM_LEN]; | |
240 | char comm_path[100]; | |
79efa585 | 241 | const char *comm_val; |
e99b03dc | 242 | pid_t pid = ptid.pid (); |
15a9e13e | 243 | pid_t tid = ptid.lwp_p () ? ptid.lwp () : ptid.pid (); |
79efa585 SM |
244 | |
245 | xsnprintf (comm_path, sizeof (comm_path), | |
246 | "/proc/%ld/task/%ld/comm", (long) pid, (long) tid); | |
247 | ||
d419f42d | 248 | gdb_file_up comm_file = gdb_fopen_cloexec (comm_path, "r"); |
79efa585 SM |
249 | if (comm_file == NULL) |
250 | return NULL; | |
251 | ||
d419f42d | 252 | comm_val = fgets (comm_buf, sizeof (comm_buf), comm_file.get ()); |
79efa585 SM |
253 | |
254 | if (comm_val != NULL) | |
255 | { | |
256 | int i; | |
257 | ||
258 | /* Make sure there is no newline at the end. */ | |
259 | for (i = 0; i < sizeof (comm_buf); i++) | |
260 | { | |
261 | if (comm_buf[i] == '\n') | |
262 | { | |
263 | comm_buf[i] = '\0'; | |
264 | break; | |
265 | } | |
266 | } | |
267 | } | |
268 | ||
269 | return comm_val; | |
270 | } | |
271 | ||
272 | /* See linux-procfs.h. */ | |
273 | ||
8784d563 PA |
274 | void |
275 | linux_proc_attach_tgid_threads (pid_t pid, | |
276 | linux_proc_attach_lwp_func attach_lwp) | |
277 | { | |
278 | DIR *dir; | |
279 | char pathname[128]; | |
280 | int new_threads_found; | |
281 | int iterations; | |
282 | ||
283 | if (linux_proc_get_tgid (pid) != pid) | |
284 | return; | |
285 | ||
286 | xsnprintf (pathname, sizeof (pathname), "/proc/%ld/task", (long) pid); | |
287 | dir = opendir (pathname); | |
288 | if (dir == NULL) | |
289 | { | |
92fc2e69 | 290 | warning (_("Could not open /proc/%ld/task."), (long) pid); |
8784d563 PA |
291 | return; |
292 | } | |
293 | ||
294 | /* Scan the task list for existing threads. While we go through the | |
295 | threads, new threads may be spawned. Cycle through the list of | |
296 | threads until we have done two iterations without finding new | |
297 | threads. */ | |
298 | for (iterations = 0; iterations < 2; iterations++) | |
299 | { | |
300 | struct dirent *dp; | |
301 | ||
302 | new_threads_found = 0; | |
303 | while ((dp = readdir (dir)) != NULL) | |
304 | { | |
305 | unsigned long lwp; | |
306 | ||
307 | /* Fetch one lwp. */ | |
308 | lwp = strtoul (dp->d_name, NULL, 10); | |
309 | if (lwp != 0) | |
310 | { | |
fd79271b | 311 | ptid_t ptid = ptid_t (pid, lwp, 0); |
8784d563 PA |
312 | |
313 | if (attach_lwp (ptid)) | |
314 | new_threads_found = 1; | |
315 | } | |
316 | } | |
317 | ||
318 | if (new_threads_found) | |
319 | { | |
320 | /* Start over. */ | |
321 | iterations = -1; | |
322 | } | |
323 | ||
324 | rewinddir (dir); | |
325 | } | |
326 | ||
327 | closedir (dir); | |
328 | } | |
2db9a427 PA |
329 | |
330 | /* See linux-procfs.h. */ | |
331 | ||
332 | int | |
333 | linux_proc_task_list_dir_exists (pid_t pid) | |
334 | { | |
335 | char pathname[128]; | |
336 | struct stat buf; | |
337 | ||
338 | xsnprintf (pathname, sizeof (pathname), "/proc/%ld/task", (long) pid); | |
339 | return (stat (pathname, &buf) == 0); | |
340 | } | |
e0d86d2c GB |
341 | |
342 | /* See linux-procfs.h. */ | |
343 | ||
344 | char * | |
345 | linux_proc_pid_to_exec_file (int pid) | |
346 | { | |
347 | static char buf[PATH_MAX]; | |
348 | char name[PATH_MAX]; | |
349 | ssize_t len; | |
350 | ||
351 | xsnprintf (name, PATH_MAX, "/proc/%d/exe", pid); | |
352 | len = readlink (name, buf, PATH_MAX - 1); | |
353 | if (len <= 0) | |
354 | strcpy (buf, name); | |
355 | else | |
356 | buf[len] = '\0'; | |
357 | ||
358 | return buf; | |
359 | } | |
1b919490 VB |
360 | |
361 | /* See linux-procfs.h. */ | |
362 | ||
363 | void | |
364 | linux_proc_init_warnings () | |
365 | { | |
366 | static bool warned = false; | |
367 | ||
368 | if (warned) | |
369 | return; | |
370 | warned = true; | |
371 | ||
372 | struct stat st; | |
373 | ||
374 | if (stat ("/proc/self", &st) != 0) | |
375 | warning (_("/proc is not accessible.")); | |
376 | } |