Fix crash when loading dwp files
[external/binutils.git] / gdb / nat / linux-procfs.c
1 /* Linux-specific PROCFS manipulation routines.
2    Copyright (C) 2009-2019 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/common-defs.h"
20 #include "linux-procfs.h"
21 #include "common/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
66 linux_proc_get_tracerpid_nowarn (pid_t lwpid)
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
75 enum 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
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':
104       return PROC_STATE_TRACING_STOP;
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" */
110         return PROC_STATE_TRACING_STOP;
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
155 linux_proc_pid_is_gone (pid_t pid)
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
193 linux_proc_pid_is_stopped (pid_t pid)
194 {
195   return linux_proc_pid_has_state (pid, PROC_STATE_STOPPED, 1);
196 }
197
198 /* Detect `t (tracing stop)' in `/proc/PID/status'.
199    Other states including `T (stopped)' are reported as false.  */
200
201 int
202 linux_proc_pid_is_trace_stopped_nowarn (pid_t pid)
203 {
204   return linux_proc_pid_has_state (pid, PROC_STATE_TRACING_STOP, 1);
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
211 linux_proc_pid_is_zombie_maybe_warn (pid_t pid, int warn)
212 {
213   return linux_proc_pid_has_state (pid, PROC_STATE_ZOMBIE, warn);
214 }
215
216 /* See linux-procfs.h declaration.  */
217
218 int
219 linux_proc_pid_is_zombie_nowarn (pid_t pid)
220 {
221   return linux_proc_pid_is_zombie_maybe_warn (pid, 0);
222 }
223
224 /* See linux-procfs.h declaration.  */
225
226 int
227 linux_proc_pid_is_zombie (pid_t pid)
228 {
229   return linux_proc_pid_is_zombie_maybe_warn (pid, 1);
230 }
231
232 /* See linux-procfs.h.  */
233
234 const char *
235 linux_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];
241   const char *comm_val;
242   pid_t pid = ptid.pid ();
243   pid_t tid = ptid.lwp_p () ? ptid.lwp () : ptid.pid ();
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
275 linux_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     {
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_t (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
333 linux_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 }
341
342 /* See linux-procfs.h.  */
343
344 char *
345 linux_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 }
360
361 /* See linux-procfs.h.  */
362
363 void
364 linux_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 }