xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/nat/linux-procfs.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /* Linux-specific PROCFS manipulation routines.
2    Copyright (C) 2009-2016 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 /* Process states as discovered in the 'State' line of
74    /proc/PID/status.  Not all possible states are represented here,
75    only those that we care about.  */
76 
77 enum proc_state
78 {
79   /* Some state we don't handle.  */
80   PROC_STATE_UNKNOWN,
81 
82   /* Stopped on a signal.  */
83   PROC_STATE_STOPPED,
84 
85   /* Tracing stop.  */
86   PROC_STATE_TRACING_STOP,
87 
88   /* Dead.  */
89   PROC_STATE_DEAD,
90 
91   /* Zombie.  */
92   PROC_STATE_ZOMBIE,
93 };
94 
95 /* Parse a PROC_STATE out of STATE, a buffer with the state found in
96    the 'State:' line of /proc/PID/status.  */
97 
98 static enum proc_state
99 parse_proc_status_state (const char *state)
100 {
101   state = skip_spaces_const (state);
102 
103   switch (state[0])
104     {
105     case 't':
106       return PROC_STATE_TRACING_STOP;
107     case 'T':
108       /* Before Linux 2.6.33, tracing stop used uppercase T.  */
109       if (strcmp (state, "T (tracing stop)") == 0)
110 	return PROC_STATE_TRACING_STOP;
111       else
112 	return PROC_STATE_STOPPED;
113     case 'X':
114       return PROC_STATE_DEAD;
115     case 'Z':
116       return PROC_STATE_ZOMBIE;
117     }
118 
119   return PROC_STATE_UNKNOWN;
120 }
121 
122 
123 /* Fill in STATE, a buffer with BUFFER_SIZE bytes with the 'State'
124    line of /proc/PID/status.  Returns -1 on failure to open the /proc
125    file, 1 if the line is found, and 0 if not found.  If WARN, warn on
126    failure to open the /proc file.  */
127 
128 static int
129 linux_proc_pid_get_state (pid_t pid, int warn, enum proc_state *state)
130 {
131   FILE *procfile;
132   int have_state;
133   char buffer[100];
134 
135   xsnprintf (buffer, sizeof (buffer), "/proc/%d/status", (int) pid);
136   procfile = gdb_fopen_cloexec (buffer, "r");
137   if (procfile == NULL)
138     {
139       if (warn)
140 	warning (_("unable to open /proc file '%s'"), buffer);
141       return -1;
142     }
143 
144   have_state = 0;
145   while (fgets (buffer, sizeof (buffer), procfile) != NULL)
146     if (startswith (buffer, "State:"))
147       {
148 	have_state = 1;
149 	*state = parse_proc_status_state (buffer + sizeof ("State:") - 1);
150 	break;
151       }
152   fclose (procfile);
153   return have_state;
154 }
155 
156 /* See linux-procfs.h declaration.  */
157 
158 int
159 linux_proc_pid_is_gone (pid_t pid)
160 {
161   int have_state;
162   enum proc_state state;
163 
164   have_state = linux_proc_pid_get_state (pid, 0, &state);
165   if (have_state < 0)
166     {
167       /* If we can't open the status file, assume the thread has
168 	 disappeared.  */
169       return 1;
170     }
171   else if (have_state == 0)
172     {
173       /* No "State:" line, assume thread is alive.  */
174       return 0;
175     }
176   else
177     return (state == PROC_STATE_ZOMBIE || state == PROC_STATE_DEAD);
178 }
179 
180 /* Return non-zero if 'State' of /proc/PID/status contains STATE.  If
181    WARN, warn on failure to open the /proc file.  */
182 
183 static int
184 linux_proc_pid_has_state (pid_t pid, enum proc_state state, int warn)
185 {
186   int have_state;
187   enum proc_state cur_state;
188 
189   have_state = linux_proc_pid_get_state (pid, warn, &cur_state);
190   return (have_state > 0 && cur_state == state);
191 }
192 
193 /* Detect `T (stopped)' in `/proc/PID/status'.
194    Other states including `T (tracing stop)' are reported as false.  */
195 
196 int
197 linux_proc_pid_is_stopped (pid_t pid)
198 {
199   return linux_proc_pid_has_state (pid, PROC_STATE_STOPPED, 1);
200 }
201 
202 /* Detect `t (tracing stop)' in `/proc/PID/status'.
203    Other states including `T (stopped)' are reported as false.  */
204 
205 int
206 linux_proc_pid_is_trace_stopped_nowarn (pid_t pid)
207 {
208   return linux_proc_pid_has_state (pid, PROC_STATE_TRACING_STOP, 1);
209 }
210 
211 /* Return non-zero if PID is a zombie.  If WARN, warn on failure to
212    open the /proc file.  */
213 
214 static int
215 linux_proc_pid_is_zombie_maybe_warn (pid_t pid, int warn)
216 {
217   return linux_proc_pid_has_state (pid, PROC_STATE_ZOMBIE, warn);
218 }
219 
220 /* See linux-procfs.h declaration.  */
221 
222 int
223 linux_proc_pid_is_zombie_nowarn (pid_t pid)
224 {
225   return linux_proc_pid_is_zombie_maybe_warn (pid, 0);
226 }
227 
228 /* See linux-procfs.h declaration.  */
229 
230 int
231 linux_proc_pid_is_zombie (pid_t pid)
232 {
233   return linux_proc_pid_is_zombie_maybe_warn (pid, 1);
234 }
235 
236 /* See linux-procfs.h.  */
237 
238 const char *
239 linux_proc_tid_get_name (ptid_t ptid)
240 {
241 #define TASK_COMM_LEN 16  /* As defined in the kernel's sched.h.  */
242 
243   static char comm_buf[TASK_COMM_LEN];
244   char comm_path[100];
245   FILE *comm_file;
246   const char *comm_val;
247   pid_t pid = ptid_get_pid (ptid);
248   pid_t tid = ptid_lwp_p (ptid) ? ptid_get_lwp (ptid) : ptid_get_pid (ptid);
249 
250   xsnprintf (comm_path, sizeof (comm_path),
251 	     "/proc/%ld/task/%ld/comm", (long) pid, (long) tid);
252 
253   comm_file = gdb_fopen_cloexec (comm_path, "r");
254   if (comm_file == NULL)
255     return NULL;
256 
257   comm_val = fgets (comm_buf, sizeof (comm_buf), comm_file);
258   fclose (comm_file);
259 
260   if (comm_val != NULL)
261     {
262       int i;
263 
264       /* Make sure there is no newline at the end.  */
265       for (i = 0; i < sizeof (comm_buf); i++)
266 	{
267 	  if (comm_buf[i] == '\n')
268 	    {
269 	      comm_buf[i] = '\0';
270 	      break;
271 	    }
272 	}
273     }
274 
275   return comm_val;
276 }
277 
278 /* See linux-procfs.h.  */
279 
280 void
281 linux_proc_attach_tgid_threads (pid_t pid,
282 				linux_proc_attach_lwp_func attach_lwp)
283 {
284   DIR *dir;
285   char pathname[128];
286   int new_threads_found;
287   int iterations;
288 
289   if (linux_proc_get_tgid (pid) != pid)
290     return;
291 
292   xsnprintf (pathname, sizeof (pathname), "/proc/%ld/task", (long) pid);
293   dir = opendir (pathname);
294   if (dir == NULL)
295     {
296       warning (_("Could not open /proc/%ld/task."), (long) pid);
297       return;
298     }
299 
300   /* Scan the task list for existing threads.  While we go through the
301      threads, new threads may be spawned.  Cycle through the list of
302      threads until we have done two iterations without finding new
303      threads.  */
304   for (iterations = 0; iterations < 2; iterations++)
305     {
306       struct dirent *dp;
307 
308       new_threads_found = 0;
309       while ((dp = readdir (dir)) != NULL)
310 	{
311 	  unsigned long lwp;
312 
313 	  /* Fetch one lwp.  */
314 	  lwp = strtoul (dp->d_name, NULL, 10);
315 	  if (lwp != 0)
316 	    {
317 	      ptid_t ptid = ptid_build (pid, lwp, 0);
318 
319 	      if (attach_lwp (ptid))
320 		new_threads_found = 1;
321 	    }
322 	}
323 
324       if (new_threads_found)
325 	{
326 	  /* Start over.  */
327 	  iterations = -1;
328 	}
329 
330       rewinddir (dir);
331     }
332 
333   closedir (dir);
334 }
335 
336 /* See linux-procfs.h.  */
337 
338 int
339 linux_proc_task_list_dir_exists (pid_t pid)
340 {
341   char pathname[128];
342   struct stat buf;
343 
344   xsnprintf (pathname, sizeof (pathname), "/proc/%ld/task", (long) pid);
345   return (stat (pathname, &buf) == 0);
346 }
347 
348 /* See linux-procfs.h.  */
349 
350 char *
351 linux_proc_pid_to_exec_file (int pid)
352 {
353   static char buf[PATH_MAX];
354   char name[PATH_MAX];
355   ssize_t len;
356 
357   xsnprintf (name, PATH_MAX, "/proc/%d/exe", pid);
358   len = readlink (name, buf, PATH_MAX - 1);
359   if (len <= 0)
360     strcpy (buf, name);
361   else
362     buf[len] = '\0';
363 
364   return buf;
365 }
366