1/* Linux-specific PROCFS manipulation routines.
2   Copyright (C) 2009-2020 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
28static int
29linux_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
57int
58linux_proc_get_tgid (pid_t lwpid)
59{
60  return linux_proc_get_int (lwpid, "Tgid", 1);
61}
62
63/* See linux-procfs.h.  */
64
65pid_t
66linux_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
75enum 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
96static enum proc_state
97parse_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
126static int
127linux_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
154int
155linux_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
179static int
180linux_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
192int
193linux_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
201int
202linux_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
210static int
211linux_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
218int
219linux_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
226int
227linux_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
234const char *
235linux_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
274void
275linux_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
332int
333linux_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
344char *
345linux_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
363void
364linux_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