]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/nat/linux-procfs.c
binutils testsuite: canonicalize subtest names in libctf
[thirdparty/binutils-gdb.git] / gdb / nat / linux-procfs.c
1 /* Linux-specific PROCFS manipulation routines.
2 Copyright (C) 2009-2024 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 "linux-procfs.h"
20 #include "gdbsupport/filestuff.h"
21 #include <dirent.h>
22 #include <sys/stat.h>
23 #include <unordered_set>
24 #include <utility>
25
26 /* Return the TGID of LWPID from /proc/pid/status. Returns -1 if not
27 found. */
28
29 static int
30 linux_proc_get_int (pid_t lwpid, const char *field, int warn)
31 {
32 size_t field_len = strlen (field);
33 char buf[100];
34 int retval = -1;
35
36 snprintf (buf, sizeof (buf), "/proc/%d/status", (int) lwpid);
37 gdb_file_up status_file = gdb_fopen_cloexec (buf, "r");
38 if (status_file == NULL)
39 {
40 if (warn)
41 warning (_("unable to open /proc file '%s'"), buf);
42 return -1;
43 }
44
45 while (fgets (buf, sizeof (buf), status_file.get ()))
46 if (strncmp (buf, field, field_len) == 0 && buf[field_len] == ':')
47 {
48 retval = strtol (&buf[field_len + 1], NULL, 10);
49 break;
50 }
51
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 /* Process states as discovered in the 'State' line of
73 /proc/PID/status. Not all possible states are represented here,
74 only those that we care about. */
75
76 enum proc_state
77 {
78 /* Some state we don't handle. */
79 PROC_STATE_UNKNOWN,
80
81 /* Stopped on a signal. */
82 PROC_STATE_STOPPED,
83
84 /* Tracing stop. */
85 PROC_STATE_TRACING_STOP,
86
87 /* Dead. */
88 PROC_STATE_DEAD,
89
90 /* Zombie. */
91 PROC_STATE_ZOMBIE,
92 };
93
94 /* Parse a PROC_STATE out of STATE, a buffer with the state found in
95 the 'State:' line of /proc/PID/status. */
96
97 static enum proc_state
98 parse_proc_status_state (const char *state)
99 {
100 state = skip_spaces (state);
101
102 switch (state[0])
103 {
104 case 't':
105 return PROC_STATE_TRACING_STOP;
106 case 'T':
107 /* Before Linux 2.6.33, tracing stop used uppercase T. */
108 if (strcmp (state, "T (stopped)\n") == 0)
109 return PROC_STATE_STOPPED;
110 else /* "T (tracing stop)\n" */
111 return PROC_STATE_TRACING_STOP;
112 case 'X':
113 return PROC_STATE_DEAD;
114 case 'Z':
115 return PROC_STATE_ZOMBIE;
116 }
117
118 return PROC_STATE_UNKNOWN;
119 }
120
121
122 /* Fill in STATE, a buffer with BUFFER_SIZE bytes with the 'State'
123 line of /proc/PID/status. Returns -1 on failure to open the /proc
124 file, 1 if the line is found, and 0 if not found. If WARN, warn on
125 failure to open the /proc file. */
126
127 static int
128 linux_proc_pid_get_state (pid_t pid, int warn, enum proc_state *state)
129 {
130 int have_state;
131 char buffer[100];
132
133 xsnprintf (buffer, sizeof (buffer), "/proc/%d/status", (int) pid);
134 gdb_file_up procfile = gdb_fopen_cloexec (buffer, "r");
135 if (procfile == NULL)
136 {
137 if (warn)
138 warning (_("unable to open /proc file '%s'"), buffer);
139 return -1;
140 }
141
142 have_state = 0;
143 while (fgets (buffer, sizeof (buffer), procfile.get ()) != NULL)
144 if (startswith (buffer, "State:"))
145 {
146 have_state = 1;
147 *state = parse_proc_status_state (buffer + sizeof ("State:") - 1);
148 break;
149 }
150 return have_state;
151 }
152
153 /* See linux-procfs.h declaration. */
154
155 int
156 linux_proc_pid_is_gone (pid_t pid)
157 {
158 int have_state;
159 enum proc_state state;
160
161 have_state = linux_proc_pid_get_state (pid, 0, &state);
162 if (have_state < 0)
163 {
164 /* If we can't open the status file, assume the thread has
165 disappeared. */
166 return 1;
167 }
168 else if (have_state == 0)
169 {
170 /* No "State:" line, assume thread is alive. */
171 return 0;
172 }
173 else
174 return (state == PROC_STATE_ZOMBIE || state == PROC_STATE_DEAD);
175 }
176
177 /* Return non-zero if 'State' of /proc/PID/status contains STATE. If
178 WARN, warn on failure to open the /proc file. */
179
180 static int
181 linux_proc_pid_has_state (pid_t pid, enum proc_state state, int warn)
182 {
183 int have_state;
184 enum proc_state cur_state;
185
186 have_state = linux_proc_pid_get_state (pid, warn, &cur_state);
187 return (have_state > 0 && cur_state == state);
188 }
189
190 /* Detect `T (stopped)' in `/proc/PID/status'.
191 Other states including `T (tracing stop)' are reported as false. */
192
193 int
194 linux_proc_pid_is_stopped (pid_t pid)
195 {
196 return linux_proc_pid_has_state (pid, PROC_STATE_STOPPED, 1);
197 }
198
199 /* Detect `t (tracing stop)' in `/proc/PID/status'.
200 Other states including `T (stopped)' are reported as false. */
201
202 int
203 linux_proc_pid_is_trace_stopped_nowarn (pid_t pid)
204 {
205 return linux_proc_pid_has_state (pid, PROC_STATE_TRACING_STOP, 1);
206 }
207
208 /* Return non-zero if PID is a zombie. If WARN, warn on failure to
209 open the /proc file. */
210
211 static int
212 linux_proc_pid_is_zombie_maybe_warn (pid_t pid, int warn)
213 {
214 return linux_proc_pid_has_state (pid, PROC_STATE_ZOMBIE, warn);
215 }
216
217 /* See linux-procfs.h declaration. */
218
219 int
220 linux_proc_pid_is_zombie_nowarn (pid_t pid)
221 {
222 return linux_proc_pid_is_zombie_maybe_warn (pid, 0);
223 }
224
225 /* See linux-procfs.h declaration. */
226
227 int
228 linux_proc_pid_is_zombie (pid_t pid)
229 {
230 return linux_proc_pid_is_zombie_maybe_warn (pid, 1);
231 }
232
233 /* See linux-procfs.h. */
234
235 std::optional<std::string>
236 linux_proc_get_stat_field (ptid_t ptid, int field)
237 {
238 /* We never need to read PID from the stat file, and there's
239 command_from_pid to read the comm field. */
240 gdb_assert (field >= LINUX_PROC_STAT_STATE);
241
242 std::string filename = string_printf ("/proc/%ld/task/%ld/stat",
243 (long) ptid.pid (), (long) ptid.lwp ());
244
245 std::optional<std::string> content
246 = read_text_file_to_string (filename.c_str ());
247 if (!content.has_value ())
248 return {};
249
250 /* ps command also relies on no trailing fields ever containing ')'. */
251 std::string::size_type pos = content->find_last_of (')');
252 if (pos == std::string::npos)
253 return {};
254
255 /* The first field after program name is LINUX_PROC_STAT_STATE. */
256 for (int i = LINUX_PROC_STAT_STATE; i <= field; ++i)
257 {
258 /* Find separator. */
259 pos = content->find_first_of (' ', pos);
260 if (pos == std::string::npos)
261 return {};
262
263 /* Find beginning of field. */
264 pos = content->find_first_not_of (' ', pos);
265 if (pos == std::string::npos)
266 return {};
267 }
268
269 /* Find end of field. */
270 std::string::size_type end_pos = content->find_first_of (' ', pos);
271 if (end_pos == std::string::npos)
272 return content->substr (pos);
273 else
274 return content->substr (pos, end_pos - pos);
275 }
276
277 /* Get the start time of thread PTID. */
278
279 static std::optional<ULONGEST>
280 linux_proc_get_starttime (ptid_t ptid)
281 {
282 std::optional<std::string> field
283 = linux_proc_get_stat_field (ptid, LINUX_PROC_STAT_STARTTIME);
284
285 if (!field.has_value ())
286 return {};
287
288 errno = 0;
289 const char *trailer;
290 ULONGEST starttime = strtoulst (field->c_str (), &trailer, 10);
291 if (starttime == ULONGEST_MAX && errno == ERANGE)
292 return {};
293 else if (*trailer != '\0')
294 /* There were unexpected characters. */
295 return {};
296
297 return starttime;
298 }
299
300 /* See linux-procfs.h. */
301
302 const char *
303 linux_proc_tid_get_name (ptid_t ptid)
304 {
305 #define TASK_COMM_LEN 16 /* As defined in the kernel's sched.h. */
306
307 static char comm_buf[TASK_COMM_LEN];
308 char comm_path[100];
309 const char *comm_val;
310 pid_t pid = ptid.pid ();
311 pid_t tid = ptid.lwp_p () ? ptid.lwp () : ptid.pid ();
312
313 xsnprintf (comm_path, sizeof (comm_path),
314 "/proc/%ld/task/%ld/comm", (long) pid, (long) tid);
315
316 gdb_file_up comm_file = gdb_fopen_cloexec (comm_path, "r");
317 if (comm_file == NULL)
318 return NULL;
319
320 comm_val = fgets (comm_buf, sizeof (comm_buf), comm_file.get ());
321
322 if (comm_val != NULL)
323 {
324 int i;
325
326 /* Make sure there is no newline at the end. */
327 for (i = 0; i < sizeof (comm_buf); i++)
328 {
329 if (comm_buf[i] == '\n')
330 {
331 comm_buf[i] = '\0';
332 break;
333 }
334 }
335 }
336
337 return comm_val;
338 }
339
340 /* See linux-procfs.h. */
341
342 void
343 linux_proc_attach_tgid_threads (pid_t pid,
344 linux_proc_attach_lwp_func attach_lwp)
345 {
346 char pathname[128];
347 int new_threads_found;
348 int iterations;
349
350 if (linux_proc_get_tgid (pid) != pid)
351 return;
352
353 xsnprintf (pathname, sizeof (pathname), "/proc/%ld/task", (long) pid);
354 gdb_dir_up dir (opendir (pathname));
355 if (dir == NULL)
356 {
357 warning (_("Could not open %s."), pathname);
358 return;
359 }
360
361 /* Callable object to hash elements in visited_lpws. */
362 struct pair_hash
363 {
364 std::size_t operator() (const std::pair<unsigned long, ULONGEST> &v) const
365 {
366 return (std::hash<unsigned long>() (v.first)
367 ^ std::hash<ULONGEST>() (v.second));
368 }
369 };
370
371 /* Keeps track of the LWPs we have already visited in /proc,
372 identified by their PID and starttime to detect PID reuse. */
373 std::unordered_set<std::pair<unsigned long, ULONGEST>,
374 pair_hash> visited_lwps;
375
376 /* Scan the task list for existing threads. While we go through the
377 threads, new threads may be spawned. Cycle through the list of
378 threads until we have done two iterations without finding new
379 threads. */
380 for (iterations = 0; iterations < 2; iterations++)
381 {
382 struct dirent *dp;
383
384 new_threads_found = 0;
385 while ((dp = readdir (dir.get ())) != NULL)
386 {
387 unsigned long lwp;
388
389 /* Fetch one lwp. */
390 lwp = strtoul (dp->d_name, NULL, 10);
391 if (lwp != 0)
392 {
393 ptid_t ptid = ptid_t (pid, lwp);
394 std::optional<ULONGEST> starttime
395 = linux_proc_get_starttime (ptid);
396
397 if (starttime.has_value ())
398 {
399 std::pair<unsigned long, ULONGEST> key (lwp, *starttime);
400
401 /* If we already visited this LWP, skip it this time. */
402 if (visited_lwps.find (key) != visited_lwps.cend ())
403 continue;
404
405 visited_lwps.insert (key);
406 }
407
408 if (attach_lwp (ptid))
409 new_threads_found = 1;
410 }
411 }
412
413 if (new_threads_found)
414 {
415 /* Start over. */
416 iterations = -1;
417 }
418
419 rewinddir (dir.get ());
420 }
421 }
422
423 /* See linux-procfs.h. */
424
425 int
426 linux_proc_task_list_dir_exists (pid_t pid)
427 {
428 char pathname[128];
429 struct stat buf;
430
431 xsnprintf (pathname, sizeof (pathname), "/proc/%ld/task", (long) pid);
432 return (stat (pathname, &buf) == 0);
433 }
434
435 /* See linux-procfs.h. */
436
437 const char *
438 linux_proc_pid_to_exec_file (int pid)
439 {
440 static char buf[PATH_MAX];
441 char name[PATH_MAX];
442 ssize_t len;
443
444 xsnprintf (name, PATH_MAX, "/proc/%d/exe", pid);
445 len = readlink (name, buf, PATH_MAX - 1);
446 if (len <= 0)
447 strcpy (buf, name);
448 else
449 buf[len] = '\0';
450
451 /* Use /proc/PID/exe if the actual file can't be read, but /proc/PID/exe
452 can be. */
453 if (access (buf, R_OK) != 0 && access (name, R_OK) == 0)
454 strcpy (buf, name);
455
456 return buf;
457 }
458
459 /* See linux-procfs.h. */
460
461 void
462 linux_proc_init_warnings ()
463 {
464 static bool warned = false;
465
466 if (warned)
467 return;
468 warned = true;
469
470 struct stat st;
471
472 if (stat ("/proc/self", &st) != 0)
473 warning (_("/proc is not accessible."));
474 }