]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gdb/nat/linux-procfs.c
Update copyright year range in header of all files managed by GDB
[thirdparty/binutils-gdb.git] / gdb / nat / linux-procfs.c
CommitLineData
13da1c97 1/* Linux-specific PROCFS manipulation routines.
213516ef 2 Copyright (C) 2009-2023 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
268a13a5 19#include "gdbsupport/common-defs.h"
13da1c97 20#include "linux-procfs.h"
268a13a5 21#include "gdbsupport/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 28static int
8784d563 29linux_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
57int
87b0bb13 58linux_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
65pid_t
8784d563 66linux_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
75enum 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
96static enum proc_state
97parse_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 126static int
d617208b 127linux_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
154int
155linux_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
179static int
d617208b 180linux_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
192int
193linux_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
201int
202linux_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
210static int
211linux_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
218int
219linux_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
226int
227linux_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
234const char *
235linux_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
274void
275linux_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 {
184ea2f7 311 ptid_t ptid = ptid_t (pid, lwp);
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
332int
333linux_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
0e90c441 344const char *
e0d86d2c
GB
345linux_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
363void
364linux_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}