1 /* Linux-specific PROCFS manipulation routines.
2    Copyright (C) 2009-2021 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 "gdbsupport/common-defs.h"
20 #include "linux-procfs.h"
21 #include "gdbsupport/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
linux_proc_get_int(pid_t lwpid,const char * field,int warn)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
linux_proc_get_tgid(pid_t lwpid)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
linux_proc_get_tracerpid_nowarn(pid_t lwpid)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
parse_proc_status_state(const char * 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
linux_proc_pid_get_state(pid_t pid,int warn,enum proc_state * state)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
linux_proc_pid_is_gone(pid_t pid)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
linux_proc_pid_has_state(pid_t pid,enum proc_state state,int warn)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
linux_proc_pid_is_stopped(pid_t pid)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
linux_proc_pid_is_trace_stopped_nowarn(pid_t pid)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
linux_proc_pid_is_zombie_maybe_warn(pid_t pid,int warn)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
linux_proc_pid_is_zombie_nowarn(pid_t pid)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
linux_proc_pid_is_zombie(pid_t pid)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 *
linux_proc_tid_get_name(ptid_t ptid)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
linux_proc_attach_tgid_threads(pid_t pid,linux_proc_attach_lwp_func attach_lwp)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
linux_proc_task_list_dir_exists(pid_t pid)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 *
linux_proc_pid_to_exec_file(int pid)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
linux_proc_init_warnings()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 }
377