GDB (xrefs)
linux-procfs.c
Go to the documentation of this file.
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 #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  FILE *status_file;
33  char buf[100];
34  int retval = -1;
35 
36  snprintf (buf, sizeof (buf), "/proc/%d/status", (int) lwpid);
37  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))
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  fclose (status_file);
53  return retval;
54 }
55 
56 /* Return the TGID of LWPID from /proc/pid/status. Returns -1 if not
57  found. */
58 
59 int
60 linux_proc_get_tgid (pid_t lwpid)
61 {
62  return linux_proc_get_int (lwpid, "Tgid", 1);
63 }
64 
65 /* See linux-procfs.h. */
66 
67 pid_t
69 {
70  return linux_proc_get_int (lwpid, "TracerPid", 0);
71 }
72 
73 /* Fill in BUFFER, a buffer with BUFFER_SIZE bytes with the 'State'
74  line of /proc/PID/status. Returns -1 on failure to open the /proc
75  file, 1 if the line is found, and 0 if not found. If WARN, warn on
76  failure to open the /proc file. */
77 
78 static int
79 linux_proc_pid_get_state (pid_t pid, char *buffer, size_t buffer_size,
80  int warn)
81 {
82  FILE *procfile;
83  int have_state;
84 
85  xsnprintf (buffer, buffer_size, "/proc/%d/status", (int) pid);
86  procfile = gdb_fopen_cloexec (buffer, "r");
87  if (procfile == NULL)
88  {
89  if (warn)
90  warning (_("unable to open /proc file '%s'"), buffer);
91  return -1;
92  }
93 
94  have_state = 0;
95  while (fgets (buffer, buffer_size, procfile) != NULL)
96  if (startswith (buffer, "State:"))
97  {
98  have_state = 1;
99  break;
100  }
101  fclose (procfile);
102  return have_state;
103 }
104 
105 /* See linux-procfs.h declaration. */
106 
107 int
109 {
110  char buffer[100];
111  int have_state;
112 
113  have_state = linux_proc_pid_get_state (pid, buffer, sizeof buffer, 0);
114  if (have_state < 0)
115  {
116  /* If we can't open the status file, assume the thread has
117  disappeared. */
118  return 1;
119  }
120  else if (have_state == 0)
121  {
122  /* No "State:" line, assume thread is alive. */
123  return 0;
124  }
125  else
126  {
127  return (strstr (buffer, "Z (") != NULL
128  || strstr (buffer, "X (") != NULL);
129  }
130 }
131 
132 /* Return non-zero if 'State' of /proc/PID/status contains STATE. If
133  WARN, warn on failure to open the /proc file. */
134 
135 static int
136 linux_proc_pid_has_state (pid_t pid, const char *state, int warn)
137 {
138  char buffer[100];
139  int have_state;
140 
141  have_state = linux_proc_pid_get_state (pid, buffer, sizeof buffer, warn);
142  return (have_state > 0 && strstr (buffer, state) != NULL);
143 }
144 
145 /* Detect `T (stopped)' in `/proc/PID/status'.
146  Other states including `T (tracing stop)' are reported as false. */
147 
148 int
150 {
151  return linux_proc_pid_has_state (pid, "T (stopped)", 1);
152 }
153 
154 /* Detect `T (tracing stop)' in `/proc/PID/status'.
155  Other states including `T (stopped)' are reported as false. */
156 
157 int
159 {
160  return linux_proc_pid_has_state (pid, "T (tracing stop)", 1);
161 }
162 
163 /* Return non-zero if PID is a zombie. If WARN, warn on failure to
164  open the /proc file. */
165 
166 static int
168 {
169  return linux_proc_pid_has_state (pid, "Z (zombie)", warn);
170 }
171 
172 /* See linux-procfs.h declaration. */
173 
174 int
176 {
177  return linux_proc_pid_is_zombie_maybe_warn (pid, 0);
178 }
179 
180 /* See linux-procfs.h declaration. */
181 
182 int
184 {
185  return linux_proc_pid_is_zombie_maybe_warn (pid, 1);
186 }
187 
188 /* See linux-procfs.h. */
189 
190 void
192  linux_proc_attach_lwp_func attach_lwp)
193 {
194  DIR *dir;
195  char pathname[128];
196  int new_threads_found;
197  int iterations;
198 
199  if (linux_proc_get_tgid (pid) != pid)
200  return;
201 
202  xsnprintf (pathname, sizeof (pathname), "/proc/%ld/task", (long) pid);
203  dir = opendir (pathname);
204  if (dir == NULL)
205  {
206  warning (_("Could not open /proc/%ld/task."), (long) pid);
207  return;
208  }
209 
210  /* Scan the task list for existing threads. While we go through the
211  threads, new threads may be spawned. Cycle through the list of
212  threads until we have done two iterations without finding new
213  threads. */
214  for (iterations = 0; iterations < 2; iterations++)
215  {
216  struct dirent *dp;
217 
218  new_threads_found = 0;
219  while ((dp = readdir (dir)) != NULL)
220  {
221  unsigned long lwp;
222 
223  /* Fetch one lwp. */
224  lwp = strtoul (dp->d_name, NULL, 10);
225  if (lwp != 0)
226  {
227  ptid_t ptid = ptid_build (pid, lwp, 0);
228 
229  if (attach_lwp (ptid))
230  new_threads_found = 1;
231  }
232  }
233 
234  if (new_threads_found)
235  {
236  /* Start over. */
237  iterations = -1;
238  }
239 
240  rewinddir (dir);
241  }
242 
243  closedir (dir);
244 }
245 
246 /* See linux-procfs.h. */
247 
248 int
250 {
251  char pathname[128];
252  struct stat buf;
253 
254  xsnprintf (pathname, sizeof (pathname), "/proc/%ld/task", (long) pid);
255  return (stat (pathname, &buf) == 0);
256 }
257 
258 /* See linux-procfs.h. */
259 
260 char *
262 {
263  static char buf[PATH_MAX];
264  char name[PATH_MAX];
265  ssize_t len;
266 
267  xsnprintf (name, PATH_MAX, "/proc/%d/exe", pid);
268  len = readlink (name, buf, PATH_MAX - 1);
269  if (len <= 0)
270  strcpy (buf, name);
271  else
272  buf[len] = '\0';
273 
274  return buf;
275 }
int(* linux_proc_attach_lwp_func)(ptid_t ptid)
Definition: linux-procfs.h:60
int linux_proc_task_list_dir_exists(pid_t pid)
Definition: linux-procfs.c:249
static int linux_proc_pid_has_state(pid_t pid, const char *state, int warn)
Definition: linux-procfs.c:136
void warning(const char *fmt,...)
Definition: errors.c:26
static int linux_proc_pid_get_state(pid_t pid, char *buffer, size_t buffer_size, int warn)
Definition: linux-procfs.c:79
FILE * gdb_fopen_cloexec(const char *filename, const char *opentype)
Definition: filestuff.c:304
#define _(String)
Definition: gdb_locale.h:40
static int linux_proc_get_int(pid_t lwpid, const char *field, int warn)
Definition: linux-procfs.c:29
Definition: ptid.h:35
int linux_proc_pid_is_zombie_nowarn(pid_t pid)
Definition: linux-procfs.c:175
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:68
int linux_proc_get_tgid(pid_t lwpid)
Definition: linux-procfs.c:60
int linux_proc_pid_is_stopped(pid_t pid)
Definition: linux-procfs.c:149
char * linux_proc_pid_to_exec_file(int pid)
Definition: linux-procfs.c:261
static int startswith(const char *string, const char *pattern)
Definition: common-utils.h:75
int linux_proc_pid_is_gone(pid_t pid)
Definition: linux-procfs.c:108
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:68
Definition: buffer.h:23
int linux_proc_pid_is_zombie(pid_t pid)
Definition: linux-procfs.c:183
void linux_proc_attach_tgid_threads(pid_t pid, linux_proc_attach_lwp_func attach_lwp)
Definition: linux-procfs.c:191
static int linux_proc_pid_is_zombie_maybe_warn(pid_t pid, int warn)
Definition: linux-procfs.c:167
mach_port_t mach_port_t name mach_port_t mach_port_t name error_t int int rusage_t pid_t pid
Definition: gnu-nat.c:1818
const ULONGEST const LONGEST len
Definition: target.h:309
int linux_proc_pid_is_trace_stopped_nowarn(pid_t pid)
Definition: linux-procfs.c:158