GNU/Linux: Stop using libthread_db/td_ta_thr_iter
[deliverable/binutils-gdb.git] / gdb / nat / linux-procfs.c
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
68 linux_proc_get_tracerpid_nowarn (pid_t lwpid)
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 (strncmp (buffer, "State:", 6) == 0)
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
108 linux_proc_pid_is_gone (pid_t pid)
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
149 linux_proc_pid_is_stopped (pid_t pid)
150 {
151 return linux_proc_pid_has_state (pid, "T (stopped)", 1);
152 }
153
154 /* Return non-zero if PID is a zombie. If WARN, warn on failure to
155 open the /proc file. */
156
157 static int
158 linux_proc_pid_is_zombie_maybe_warn (pid_t pid, int warn)
159 {
160 return linux_proc_pid_has_state (pid, "Z (zombie)", warn);
161 }
162
163 /* See linux-procfs.h declaration. */
164
165 int
166 linux_proc_pid_is_zombie_nowarn (pid_t pid)
167 {
168 return linux_proc_pid_is_zombie_maybe_warn (pid, 0);
169 }
170
171 /* See linux-procfs.h declaration. */
172
173 int
174 linux_proc_pid_is_zombie (pid_t pid)
175 {
176 return linux_proc_pid_is_zombie_maybe_warn (pid, 1);
177 }
178
179 /* See linux-procfs.h declaration. */
180
181 char *
182 linux_proc_pid_get_ns (pid_t pid, const char *ns)
183 {
184 char buf[100];
185 char nsval[64];
186 int ret;
187 xsnprintf (buf, sizeof (buf), "/proc/%d/ns/%s", (int) pid, ns);
188 ret = readlink (buf, nsval, sizeof (nsval));
189 if (0 < ret && ret < sizeof (nsval))
190 {
191 nsval[ret] = '\0';
192 return xstrdup (nsval);
193 }
194
195 return NULL;
196 }
197
198 /* See linux-procfs.h. */
199
200 void
201 linux_proc_attach_tgid_threads (pid_t pid,
202 linux_proc_attach_lwp_func attach_lwp)
203 {
204 DIR *dir;
205 char pathname[128];
206 int new_threads_found;
207 int iterations;
208
209 if (linux_proc_get_tgid (pid) != pid)
210 return;
211
212 xsnprintf (pathname, sizeof (pathname), "/proc/%ld/task", (long) pid);
213 dir = opendir (pathname);
214 if (dir == NULL)
215 {
216 warning (_("Could not open /proc/%ld/task."), (long) pid);
217 return;
218 }
219
220 /* Scan the task list for existing threads. While we go through the
221 threads, new threads may be spawned. Cycle through the list of
222 threads until we have done two iterations without finding new
223 threads. */
224 for (iterations = 0; iterations < 2; iterations++)
225 {
226 struct dirent *dp;
227
228 new_threads_found = 0;
229 while ((dp = readdir (dir)) != NULL)
230 {
231 unsigned long lwp;
232
233 /* Fetch one lwp. */
234 lwp = strtoul (dp->d_name, NULL, 10);
235 if (lwp != 0)
236 {
237 ptid_t ptid = ptid_build (pid, lwp, 0);
238
239 if (attach_lwp (ptid))
240 new_threads_found = 1;
241 }
242 }
243
244 if (new_threads_found)
245 {
246 /* Start over. */
247 iterations = -1;
248 }
249
250 rewinddir (dir);
251 }
252
253 closedir (dir);
254 }
255
256 /* See linux-procfs.h. */
257
258 int
259 linux_proc_task_list_dir_exists (pid_t pid)
260 {
261 char pathname[128];
262 struct stat buf;
263
264 xsnprintf (pathname, sizeof (pathname), "/proc/%ld/task", (long) pid);
265 return (stat (pathname, &buf) == 0);
266 }
This page took 0.03802 seconds and 5 git commands to generate.