GDB (xrefs)
linux-procfs.c
Go to the documentation of this file.
1 /* Linux-specific PROCFS manipulation routines.
2  Copyright (C) 2009-2018 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 #include <sys/stat.h>
24 
25 /* Return the TGID of LWPID from /proc/pid/status. Returns -1 if not
26  found. */
27 
28 static int
29 linux_proc_get_int (pid_t lwpid, const char *field, int warn)
30 {
31  size_t field_len = strlen (field);
32  char buf[100];
33  int retval = -1;
34 
35  snprintf (buf, sizeof (buf), "/proc/%d/status", (int) lwpid);
36  gdb_file_up 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.get ()))
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  return retval;
52 }
53 
54 /* Return the TGID of LWPID from /proc/pid/status. Returns -1 if not
55  found. */
56 
57 int
58 linux_proc_get_tgid (pid_t lwpid)
59 {
60  return linux_proc_get_int (lwpid, "Tgid", 1);
61 }
62 
63 /* See linux-procfs.h. */
64 
65 pid_t
67 {
68  return linux_proc_get_int (lwpid, "TracerPid", 0);
69 }
70 
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 
76 {
77  /* Some state we don't handle. */
79 
80  /* Stopped on a signal. */
82 
83  /* Tracing stop. */
85 
86  /* Dead. */
88 
89  /* 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 {
99  state = skip_spaces (state);
100 
101  switch (state[0])
102  {
103  case 't':
105  case 'T':
106  /* Before Linux 2.6.33, tracing stop used uppercase T. */
107  if (strcmp (state, "T (stopped)\n") == 0)
108  return PROC_STATE_STOPPED;
109  else /* "T (tracing stop)\n" */
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'
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. */
125 
126 static int
127 linux_proc_pid_get_state (pid_t pid, int warn, enum proc_state *state)
128 {
129  int have_state;
130  char buffer[100];
131 
132  xsnprintf (buffer, sizeof (buffer), "/proc/%d/status", (int) pid);
133  gdb_file_up procfile = gdb_fopen_cloexec (buffer, "r");
134  if (procfile == NULL)
135  {
136  if (warn)
137  warning (_("unable to open /proc file '%s'"), buffer);
138  return -1;
139  }
140 
141  have_state = 0;
142  while (fgets (buffer, sizeof (buffer), procfile.get ()) != NULL)
143  if (startswith (buffer, "State:"))
144  {
145  have_state = 1;
146  *state = parse_proc_status_state (buffer + sizeof ("State:") - 1);
147  break;
148  }
149  return have_state;
150 }
151 
152 /* See linux-procfs.h declaration. */
153 
154 int
156 {
157  int have_state;
158  enum proc_state state;
159 
160  have_state = linux_proc_pid_get_state (pid, 0, &state);
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
173  return (state == PROC_STATE_ZOMBIE || state == PROC_STATE_DEAD);
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
180 linux_proc_pid_has_state (pid_t pid, enum proc_state state, int warn)
181 {
182  int have_state;
183  enum proc_state cur_state;
184 
185  have_state = linux_proc_pid_get_state (pid, warn, &cur_state);
186  return (have_state > 0 && cur_state == state);
187 }
188 
189 /* Detect `T (stopped)' in `/proc/PID/status'.
190  Other states including `T (tracing stop)' are reported as false. */
191 
192 int
194 {
196 }
197 
198 /* Detect `t (tracing stop)' in `/proc/PID/status'.
199  Other states including `T (stopped)' are reported as false. */
200 
201 int
203 {
205 }
206 
207 /* Return non-zero if PID is a zombie. If WARN, warn on failure to
208  open the /proc file. */
209 
210 static int
212 {
214 }
215 
216 /* See linux-procfs.h declaration. */
217 
218 int
220 {
222 }
223 
224 /* See linux-procfs.h declaration. */
225 
226 int
228 {
230 }
231 
232 /* See linux-procfs.h. */
233 
234 const char *
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];
241  const char *comm_val;
242  pid_t pid = ptid_get_pid (ptid);
243  pid_t tid = ptid_lwp_p (ptid) ? ptid_get_lwp (ptid) : ptid_get_pid (ptid);
244 
245  xsnprintf (comm_path, sizeof (comm_path),
246  "/proc/%ld/task/%ld/comm", (long) pid, (long) tid);
247 
248  gdb_file_up comm_file = gdb_fopen_cloexec (comm_path, "r");
249  if (comm_file == NULL)
250  return NULL;
251 
252  comm_val = fgets (comm_buf, sizeof (comm_buf), comm_file.get ());
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 
274 void
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  {
290  warning (_("Could not open /proc/%ld/task."), (long) pid);
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  {
311  ptid_t ptid = ptid_build (pid, lwp, 0);
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 }
329 
330 /* See linux-procfs.h. */
331 
332 int
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 }
341 
342 /* See linux-procfs.h. */
343 
344 char *
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 }
static constexpr ptid_t tid
int(* linux_proc_attach_lwp_func)(ptid_t ptid)
Definition: linux-procfs.h:67
int linux_proc_task_list_dir_exists(pid_t pid)
Definition: linux-procfs.c:333
int ptid_get_pid(const ptid_t &ptid)
Definition: ptid.c:47
mach_port_t mach_port_t name mach_port_t mach_port_t name kern_return_t int int rusage_t pid_t pid
Definition: gnu-nat.c:1824
void warning(const char *fmt,...)
Definition: errors.c:26
const char * linux_proc_tid_get_name(ptid_t ptid)
Definition: linux-procfs.c:235
static int linux_proc_pid_get_state(pid_t pid, int warn, enum proc_state *state)
Definition: linux-procfs.c:127
char * skip_spaces(char *chp)
Definition: common-utils.c:337
#define _(String)
Definition: gdb_locale.h:35
static int linux_proc_pid_has_state(pid_t pid, enum proc_state state, int warn)
Definition: linux-procfs.c:180
static int linux_proc_get_int(pid_t lwpid, const char *field, int warn)
Definition: linux-procfs.c:29
#define TASK_COMM_LEN
int linux_proc_pid_is_zombie_nowarn(pid_t pid)
Definition: linux-procfs.c:219
ptid_t ptid_build(int pid, long lwp, long tid)
Definition: ptid.c:31
def warn(msg)
Definition: elinos.py:23
const char *const name
Definition: aarch64-tdep.c:76
static enum proc_state parse_proc_status_state(const char *state)
Definition: linux-procfs.c:97
std::unique_ptr< FILE, gdb_file_deleter > gdb_file_up
Definition: filestuff.h:59
Definition: ptid.h:35
int linux_proc_get_tgid(pid_t lwpid)
Definition: linux-procfs.c:58
int linux_proc_pid_is_stopped(pid_t pid)
Definition: linux-procfs.c:193
char * linux_proc_pid_to_exec_file(int pid)
Definition: linux-procfs.c:345
gdb_file_up gdb_fopen_cloexec(const char *filename, const char *opentype)
Definition: filestuff.c:296
static int startswith(const char *string, const char *pattern)
Definition: common-utils.h:107
long ptid_get_lwp(const ptid_t &ptid)
Definition: ptid.c:55
proc_state
Definition: linux-procfs.c:75
int ptid_lwp_p(const ptid_t &ptid)
Definition: ptid.c:87
int linux_proc_pid_is_gone(pid_t pid)
Definition: linux-procfs.c:155
int xsnprintf(char *str, size_t size, const char *format,...)
Definition: common-utils.c:134
pid_t linux_proc_get_tracerpid_nowarn(pid_t lwpid)
Definition: linux-procfs.c:66
Definition: buffer.h:23
static constexpr ptid_t lwp
int linux_proc_pid_is_zombie(pid_t pid)
Definition: linux-procfs.c:227
void linux_proc_attach_tgid_threads(pid_t pid, linux_proc_attach_lwp_func attach_lwp)
Definition: linux-procfs.c:275
static int linux_proc_pid_is_zombie_maybe_warn(pid_t pid, int warn)
Definition: linux-procfs.c:211
int linux_proc_pid_is_trace_stopped_nowarn(pid_t pid)
Definition: linux-procfs.c:202