1/* Machine independent support for Solaris /proc (process file system) for GDB.
2
3   Copyright (C) 1999-2020 Free Software Foundation, Inc.
4
5   Written by Michael Snyder at Cygnus Solutions.
6   Based on work by Fred Fish, Stu Grossman, Geoff Noer, and others.
7
8   This file is part of GDB.
9
10   This program is free software; you can redistribute it and/or modify
11   it under the terms of the GNU General Public License as published by
12   the Free Software Foundation; either version 3 of the License, or
13   (at your option) any later version.
14
15   This program is distributed in the hope that it will be useful,
16   but WITHOUT ANY WARRANTY; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18   GNU General Public License for more details.
19
20   You should have received a copy of the GNU General Public License
21   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
22
23/*
24 * Pretty-print trace of api calls to the /proc api
25 */
26
27#include "defs.h"
28#include "gdbcmd.h"
29#include "completer.h"
30
31#include <sys/types.h>
32#include <sys/procfs.h>
33#include <sys/proc.h>	/* for struct proc */
34#include <sys/user.h>	/* for struct user */
35#include <fcntl.h>	/* for O_RDWR etc.  */
36#include "gdbsupport/gdb_wait.h"
37
38#include "proc-utils.h"
39
40/*  Much of the information used in the /proc interface, particularly for
41    printing status information, is kept as tables of structures of the
42    following form.  These tables can be used to map numeric values to
43    their symbolic names and to a string that describes their specific use.  */
44
45struct trans {
46  long value;                   /* The numeric value */
47  const char *name;             /* The equivalent symbolic value */
48  const char *desc;             /* Short description of value */
49};
50
51static bool  procfs_trace   = false;
52static FILE *procfs_file     = NULL;
53static char *procfs_filename;
54
55static void
56prepare_to_trace (void)
57{
58  if (procfs_trace)			/* if procfs tracing turned on */
59    if (procfs_file == NULL)		/* if output file not yet open */
60      procfs_file = fopen (procfs_filename, "a");	/* open output file */
61}
62
63static void
64set_procfs_trace_cmd (const char *args,
65		      int from_tty, struct cmd_list_element *c)
66{
67#if 0	/* not sure what I might actually need to do here, if anything */
68  if (procfs_file)
69    fflush (procfs_file);
70#endif
71}
72
73static void
74set_procfs_file_cmd (const char *args,
75		     int from_tty, struct cmd_list_element *c)
76{
77  /* Just changed the filename for procfs tracing.
78     If a file was already open, close it.  */
79  if (procfs_file)
80    fclose (procfs_file);
81  procfs_file = NULL;
82}
83
84static struct trans rw_table[] = {
85  { PCAGENT,  "PCAGENT",  "create agent lwp with regs from argument" },
86  { PCCFAULT, "PCCFAULT", "clear current fault" },
87  { PCCSIG,   "PCCSIG",   "clear current signal" },
88  { PCDSTOP,  "PCDSTOP",  "post stop request" },
89  { PCKILL,   "PCKILL",   "post a signal" },
90  { PCNICE,   "PCNICE",   "set nice priority" },
91  { PCREAD,   "PCREAD",   "read from the address space" },
92  { PCWRITE,  "PCWRITE",  "write to the address space" },
93  { PCRUN,    "PCRUN",    "make process/lwp runnable" },
94  { PCSASRS,  "PCSASRS",  "set ancillary state registers" },
95  { PCSCRED,  "PCSCRED",  "set process credentials" },
96  { PCSENTRY, "PCSENTRY", "set traced syscall entry set" },
97  { PCSET,    "PCSET",    "set modes" },
98  { PCSEXIT,  "PCSEXIT",  "set traced syscall exit  set" },
99  { PCSFAULT, "PCSFAULT", "set traced fault set" },
100  { PCSFPREG, "PCSFPREG", "set floating point registers" },
101  { PCSHOLD,  "PCSHOLD",  "set signal mask" },
102  { PCSREG,   "PCSREG",   "set general registers" },
103  { PCSSIG,   "PCSSIG",   "set current signal" },
104  { PCSTOP,   "PCSTOP",   "post stop request and wait" },
105  { PCSTRACE, "PCSTRACE", "set traced signal set" },
106  { PCSVADDR, "PCSVADDR", "set pc virtual address" },
107  { PCSXREG,  "PCSXREG",  "set extra registers" },
108  { PCTWSTOP, "PCTWSTOP", "wait for stop, with timeout arg" },
109  { PCUNKILL, "PCUNKILL", "delete a pending signal" },
110  { PCUNSET,  "PCUNSET",  "unset modes" },
111  { PCWATCH,  "PCWATCH",  "set/unset watched memory area" },
112  { PCWSTOP,  "PCWSTOP",  "wait for process/lwp to stop, no timeout" },
113  { 0,        NULL,      NULL }
114};
115
116static off_t lseek_offset;
117
118int
119write_with_trace (int fd, void *varg, size_t len, char *file, int line)
120{
121  int i = ARRAY_SIZE (rw_table) - 1;
122  int ret;
123  procfs_ctl_t *arg = (procfs_ctl_t *) varg;
124
125  prepare_to_trace ();
126  if (procfs_trace)
127    {
128      procfs_ctl_t opcode = arg[0];
129      for (i = 0; rw_table[i].name != NULL; i++)
130	if (rw_table[i].value == opcode)
131	  break;
132
133      if (info_verbose)
134	fprintf (procfs_file ? procfs_file : stdout,
135		 "%s:%d -- ", file, line);
136      switch (opcode) {
137      case PCSET:
138	fprintf (procfs_file ? procfs_file : stdout,
139		 "write (PCSET,   %s) %s\n",
140		 arg[1] == PR_FORK  ? "PR_FORK"  :
141		 arg[1] == PR_RLC   ? "PR_RLC"   :
142		 arg[1] == PR_ASYNC ? "PR_ASYNC" :
143		 "<unknown flag>",
144		 info_verbose ? rw_table[i].desc : "");
145	break;
146      case PCUNSET:
147	fprintf (procfs_file ? procfs_file : stdout,
148		 "write (PCRESET, %s) %s\n",
149		 arg[1] == PR_FORK  ? "PR_FORK"  :
150		 arg[1] == PR_RLC   ? "PR_RLC"   :
151		 arg[1] == PR_ASYNC ? "PR_ASYNC" :
152		 "<unknown flag>",
153		 info_verbose ? rw_table[i].desc : "");
154	break;
155      case PCSTRACE:
156	fprintf (procfs_file ? procfs_file : stdout,
157		 "write (PCSTRACE) ");
158	proc_prettyfprint_signalset (procfs_file ? procfs_file : stdout,
159				     (sigset_t *) &arg[1], 0);
160	break;
161      case PCSFAULT:
162	fprintf (procfs_file ? procfs_file : stdout,
163		 "write (PCSFAULT) ");
164	proc_prettyfprint_faultset (procfs_file ? procfs_file : stdout,
165				    (fltset_t *) &arg[1], 0);
166	break;
167      case PCSENTRY:
168	fprintf (procfs_file ? procfs_file : stdout,
169		 "write (PCSENTRY) ");
170	proc_prettyfprint_syscalls (procfs_file ? procfs_file : stdout,
171				    (sysset_t *) &arg[1], 0);
172	break;
173      case PCSEXIT:
174	fprintf (procfs_file ? procfs_file : stdout,
175		 "write (PCSEXIT) ");
176	proc_prettyfprint_syscalls (procfs_file ? procfs_file : stdout,
177				    (sysset_t *) &arg[1], 0);
178	break;
179      case PCSHOLD:
180	fprintf (procfs_file ? procfs_file : stdout,
181		 "write (PCSHOLD) ");
182	proc_prettyfprint_signalset (procfs_file ? procfs_file : stdout,
183				     (sigset_t *) &arg[1], 0);
184	break;
185      case PCSSIG:
186	fprintf (procfs_file ? procfs_file : stdout,
187		 "write (PCSSIG) ");
188	proc_prettyfprint_signal (procfs_file ? procfs_file : stdout,
189				  arg[1] ? ((siginfo_t *) &arg[1])->si_signo
190				         : 0,
191				  0);
192	fprintf (procfs_file ? procfs_file : stdout, "\n");
193	break;
194      case PCRUN:
195	fprintf (procfs_file ? procfs_file : stdout,
196		 "write (PCRUN) ");
197	if (arg[1] & PRCSIG)
198	  fprintf (procfs_file ? procfs_file : stdout, "clearSig ");
199	if (arg[1] & PRCFAULT)
200	  fprintf (procfs_file ? procfs_file : stdout, "clearFlt ");
201	if (arg[1] & PRSTEP)
202	  fprintf (procfs_file ? procfs_file : stdout, "step ");
203	if (arg[1] & PRSABORT)
204	  fprintf (procfs_file ? procfs_file : stdout, "syscallAbort ");
205	if (arg[1] & PRSTOP)
206	  fprintf (procfs_file ? procfs_file : stdout, "stopReq ");
207
208	fprintf (procfs_file ? procfs_file : stdout, "\n");
209	break;
210      case PCKILL:
211	fprintf (procfs_file ? procfs_file : stdout,
212		 "write (PCKILL) ");
213	proc_prettyfprint_signal (procfs_file ? procfs_file : stdout,
214				  arg[1], 0);
215	fprintf (procfs_file ? procfs_file : stdout, "\n");
216	break;
217      default:
218	{
219	  if (rw_table[i].name)
220	    fprintf (procfs_file ? procfs_file : stdout,
221		     "write (%s) %s\n",
222		     rw_table[i].name,
223		     info_verbose ? rw_table[i].desc : "");
224	  else
225	    {
226	      if (lseek_offset != -1)
227		fprintf (procfs_file ? procfs_file : stdout,
228			 "write (<unknown>, %lud bytes at 0x%08lx) \n",
229			 (unsigned long) len, (unsigned long) lseek_offset);
230	      else
231		fprintf (procfs_file ? procfs_file : stdout,
232			 "write (<unknown>, %lud bytes) \n",
233			 (unsigned long) len);
234	    }
235	  break;
236	}
237      }
238      if (procfs_file)
239	fflush (procfs_file);
240    }
241  errno = 0;
242  ret = write (fd, (void *) arg, len);
243  if (procfs_trace && ret != len)
244    {
245      fprintf (procfs_file ? procfs_file : stdout,
246	       "[write (%s) FAILED! (%s)]\n",
247	       rw_table[i].name != NULL ?
248	       rw_table[i].name : "<unknown>",
249	       safe_strerror (errno));
250      if (procfs_file)
251	fflush (procfs_file);
252    }
253
254  lseek_offset = -1;
255  return ret;
256}
257
258off_t
259lseek_with_trace (int fd, off_t offset, int whence, char *file, int line)
260{
261  off_t ret;
262
263  prepare_to_trace ();
264  errno = 0;
265  ret = lseek (fd, offset, whence);
266  lseek_offset = ret;
267  if (procfs_trace && (ret == -1 || errno != 0))
268    {
269      fprintf (procfs_file ? procfs_file : stdout,
270	       "[lseek (0x%08lx) FAILED! (%s)]\n",
271	       (unsigned long) offset, safe_strerror (errno));
272      if (procfs_file)
273	fflush (procfs_file);
274    }
275
276  return ret;
277}
278
279int
280open_with_trace (char *filename, int mode, char *file, int line)
281{
282  int ret;
283
284  prepare_to_trace ();
285  errno = 0;
286  ret = open (filename, mode);
287  if (procfs_trace)
288    {
289      if (info_verbose)
290	fprintf (procfs_file ? procfs_file : stdout,
291		 "%s:%d -- ", file, line);
292
293      if (errno)
294	{
295	  fprintf (procfs_file ? procfs_file : stdout,
296		   "[open FAILED! (%s) line %d]\\n",
297		   safe_strerror (errno), line);
298	}
299      else
300	{
301	  fprintf (procfs_file ? procfs_file : stdout,
302		   "%d = open (%s, ", ret, filename);
303	  if (mode == O_RDONLY)
304	    fprintf (procfs_file ? procfs_file : stdout, "O_RDONLY) %d\n",
305		     line);
306	  else if (mode == O_WRONLY)
307	    fprintf (procfs_file ? procfs_file : stdout, "O_WRONLY) %d\n",
308		     line);
309	  else if (mode == O_RDWR)
310	    fprintf (procfs_file ? procfs_file : stdout, "O_RDWR)   %d\n",
311		     line);
312	}
313      if (procfs_file)
314	fflush (procfs_file);
315    }
316
317  return ret;
318}
319
320int
321close_with_trace (int fd, char *file, int line)
322{
323  int ret;
324
325  prepare_to_trace ();
326  errno = 0;
327  ret = close (fd);
328  if (procfs_trace)
329    {
330      if (info_verbose)
331	fprintf (procfs_file ? procfs_file : stdout,
332		 "%s:%d -- ", file, line);
333      if (errno)
334	fprintf (procfs_file ? procfs_file : stdout,
335		 "[close FAILED! (%s)]\n", safe_strerror (errno));
336      else
337	fprintf (procfs_file ? procfs_file : stdout,
338		 "%d = close (%d)\n", ret, fd);
339      if (procfs_file)
340	fflush (procfs_file);
341    }
342
343  return ret;
344}
345
346pid_t
347wait_with_trace (int *wstat, char *file, int line)
348{
349  int ret, lstat = 0;
350
351  prepare_to_trace ();
352  if (procfs_trace)
353    {
354      if (info_verbose)
355	fprintf (procfs_file ? procfs_file : stdout,
356		 "%s:%d -- ", file, line);
357      fprintf (procfs_file ? procfs_file : stdout,
358	       "wait (line %d) ", line);
359      if (procfs_file)
360	fflush (procfs_file);
361    }
362  errno = 0;
363  ret = wait (&lstat);
364  if (procfs_trace)
365    {
366      if (errno)
367	fprintf (procfs_file ? procfs_file : stdout,
368		 "[wait FAILED! (%s)]\n", safe_strerror (errno));
369      else
370	fprintf (procfs_file ? procfs_file : stdout,
371		 "returned pid %d, status 0x%x\n", ret, lstat);
372      if (procfs_file)
373	fflush (procfs_file);
374    }
375  if (wstat)
376    *wstat = lstat;
377
378  return ret;
379}
380
381void
382procfs_note (const char *msg, const char *file, int line)
383{
384  prepare_to_trace ();
385  if (procfs_trace)
386    {
387      if (info_verbose)
388	fprintf (procfs_file ? procfs_file : stdout,
389		 "%s:%d -- ", file, line);
390      fprintf (procfs_file ? procfs_file : stdout, "%s", msg);
391      if (procfs_file)
392	fflush (procfs_file);
393    }
394}
395
396void
397proc_prettyfprint_status (long flags, int why, int what, int thread)
398{
399  prepare_to_trace ();
400  if (procfs_trace)
401    {
402      if (thread)
403	fprintf (procfs_file ? procfs_file : stdout,
404		 "Thread %d: ", thread);
405
406      proc_prettyfprint_flags (procfs_file ? procfs_file : stdout,
407			       flags, 0);
408
409      if (flags & (PR_STOPPED | PR_ISTOP))
410	proc_prettyfprint_why (procfs_file ? procfs_file : stdout,
411			       why, what, 0);
412      if (procfs_file)
413	fflush (procfs_file);
414    }
415}
416
417void _initialize_proc_api ();
418void
419_initialize_proc_api ()
420{
421  add_setshow_boolean_cmd ("procfs-trace", no_class, &procfs_trace, _("\
422Set tracing for /proc api calls."), _("\
423Show tracing for /proc api calls."), NULL,
424			   set_procfs_trace_cmd,
425			   NULL, /* FIXME: i18n: */
426			   &setlist, &showlist);
427
428  procfs_filename = xstrdup ("procfs_trace");
429  add_setshow_filename_cmd ("procfs-file", no_class, &procfs_filename, _("\
430Set filename for /proc tracefile."), _("\
431Show filename for /proc tracefile."), NULL,
432			    set_procfs_file_cmd,
433			    NULL, /* FIXME: i18n: */
434			    &setlist, &showlist);
435}
436