1/* Machine independent support for SVR4 /proc (process file system) for GDB.
2
3   Copyright 1999, 2000, 2001, 2003 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
8This file is part of GDB.
9
10This program is free software; you can redistribute it and/or modify
11it under the terms of the GNU General Public License as published by
12the Free Software Foundation; either version 2 of the License, or
13(at your option) any later version.
14
15This program is distributed in the hope that it will be useful,
16but WITHOUT ANY WARRANTY; without even the implied warranty of
17MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18GNU General Public License for more details.
19
20You should have received a copy of the GNU General Public License
21along with this program; if not, write to the Free Software Foundation,
22Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
23
24/*
25 * Pretty-print trace of api calls to the /proc api
26 * (ioctl or read/write calls).
27 *
28 */
29
30#include "defs.h"
31#include "gdbcmd.h"
32#include "completer.h"
33
34#if defined (NEW_PROC_API)
35#define _STRUCTURED_PROC 1
36#endif
37
38#include <stdio.h>
39#include <sys/types.h>
40#include <sys/procfs.h>
41#ifdef HAVE_SYS_PROC_H
42#include <sys/proc.h>	/* for struct proc */
43#endif
44#ifdef HAVE_SYS_USER_H
45#include <sys/user.h>	/* for struct user */
46#endif
47#include <fcntl.h>	/* for O_RDWR etc. */
48#include "gdb_wait.h"
49
50#include "proc-utils.h"
51
52/*  Much of the information used in the /proc interface, particularly for
53    printing status information, is kept as tables of structures of the
54    following form.  These tables can be used to map numeric values to
55    their symbolic names and to a string that describes their specific use. */
56
57struct trans {
58  long value;                   /* The numeric value */
59  char *name;                   /* The equivalent symbolic value */
60  char *desc;                   /* Short description of value */
61};
62
63static int   procfs_trace    = 0;
64static FILE *procfs_file     = NULL;
65static char *procfs_filename = "procfs_trace";
66
67static void
68prepare_to_trace (void)
69{
70  if (procfs_trace)			/* if procfs tracing turned on */
71    if (procfs_file == NULL)		/* if output file not yet open */
72      if (procfs_filename != NULL)	/* if output filename known */
73	procfs_file = fopen (procfs_filename, "a");	/* open output file */
74}
75
76static void
77set_procfs_trace_cmd (char *args, int from_tty, struct cmd_list_element *c)
78{
79#if 0	/* not sure what I might actually need to do here, if anything */
80  if (procfs_file)
81    fflush (procfs_file);
82#endif
83}
84
85static void
86set_procfs_file_cmd (char *args, int from_tty, struct cmd_list_element *c)
87{
88  /* Just changed the filename for procfs tracing.
89     If a file was already open, close it.  */
90  if (procfs_file)
91    fclose (procfs_file);
92  procfs_file = NULL;
93}
94
95
96#ifndef NEW_PROC_API
97
98static struct trans ioctl_table[] = {
99#ifdef PIOCACINFO			/* irix */
100  { PIOCACINFO,    "PIOCACINFO",   "get process account info" },
101#endif
102  { PIOCACTION,    "PIOCACTION",   "get signal action structs" },
103#ifdef PIOCARGUMENTS			/* osf */
104  { PIOCARGUMENTS, "PIOCARGUMENTS", "command line args" },
105#endif
106#ifdef PIOCAUXV				/* solaris aux vectors */
107  { PIOCAUXV,      "PIOCAUXV",     "get aux vector" },
108  { PIOCNAUXV,     "PIOCNAUXV",    "get number of aux vector entries" },
109#endif /* AUXV */
110  { PIOCCFAULT,    "PIOCCFAULT",   "clear current fault" },
111  { PIOCCRED,      "PIOCCRED",     "get process credentials" },
112#ifdef PIOCENEVCTRS			/* irix event counters */
113  { PIOCENEVCTRS,    "PIOCENEVCTRS",    "acquire and start event counters" },
114  { PIOCGETEVCTRL,   "PIOCGETEVCTRL",   "get control info of event counters" },
115  { PIOCGETEVCTRS,   "PIOCGETEVCTRS",   "dump event counters" },
116  { PIOCGETPREVCTRS, "PIOCGETPREVCTRS", "dump event counters & prusage info" },
117  { PIOCRELEVCTRS,   "PIOCRELEVCTRS",   "release/stop event counters" },
118  { PIOCSETEVCTRL,   "PIOCSETEVCTRL",   "set control info of event counters" },
119  { PIOCGETPTIMER,   "PIOCGETPTIMER",   "get process timers" },
120#endif	/* irix event counters */
121  { PIOCGENTRY,    "PIOCGENTRY",   "get traced syscall entry set" },
122#if defined (PIOCGETPR)
123  { PIOCGETPR,     "PIOCGETPR",    "read struct proc" },
124#endif
125#if defined (PIOCGETU)
126  { PIOCGETU,      "PIOCGETU",     "read user area" },
127#endif
128#if defined (PIOCGETUTK) && (defined(KERNEL) || defined(SHOW_UTT)) /* osf */
129  { PIOCGETUTK,  "PIOCGETUTK", "get the utask struct" },
130#endif
131  { PIOCGEXIT,     "PIOCGEXIT",    "get traced syscall exit  set" },
132  { PIOCGFAULT,    "PIOCGFAULT",   "get traced fault set" },
133#ifdef PIOCGFPCR			/* osf */
134  { PIOCGFPCR,     "PIOCGFPCR",    "get FP control register" },
135  { PIOCSFPCR,     "PIOCSFPCR",    "set FP conrtol register" },
136#endif
137  { PIOCGFPREG,    "PIOCGFPREG",   "get floating point registers" },
138  { PIOCGHOLD,     "PIOCGHOLD",    "get held signal set" },
139  { PIOCGREG,      "PIOCGREG",     "get general registers" },
140  { PIOCGROUPS,    "PIOCGROUPS",   "get supplementary groups" },
141#ifdef PIOCGSPCACT			/* osf */
142  { PIOCGSPCACT,   "PIOCGSPCACT",  "get special action" },
143  { PIOCSSPCACT,   "PIOCSSPCACT",  "set special action" },
144#endif
145  { PIOCGTRACE,    "PIOCGTRACE",   "get traced signal set" },
146#ifdef PIOCGWATCH			/* irix watchpoints */
147  { PIOCGWATCH,    "PIOCGWATCH",   "get watchpoint" },
148  { PIOCSWATCH,    "PIOCSWATCH",   "set watchpoint" },
149  { PIOCNWATCH,    "PIOCNWATCH",   "get number of watchpoints" },
150#endif	/* irix watchpoints */
151#ifdef PIOCGWIN				/* solaris sparc */
152  { PIOCGWIN,      "PIOCGWIN",     "get gwindows_t" },
153#endif
154#ifdef PIOCGXREG			/* solaris sparc extra regs */
155  { PIOCGXREGSIZE, "PIOCXREGSIZE", "get extra register state size" },
156  { PIOCGXREG,     "PIOCGXREG",    "get extra register state" },
157  { PIOCSXREG,     "PIOCSXREG",    "set extra register state" },
158#endif /* XREG */
159  { PIOCKILL,      "PIOCKILL",     "send signal" },
160#ifdef PIOCLDT				/* solaris i386 */
161  { PIOCLDT,       "PIOCLDT",      "get LDT" },
162  { PIOCNLDT,      "PIOCNLDT",     "get number of LDT entries" },
163#endif
164#ifdef PIOCLSTATUS			/* solaris and unixware */
165  { PIOCLSTATUS,   "PIOCLSTATUS",  "get status of all lwps" },
166  { PIOCLUSAGE,    "PIOCLUSAGE",   "get resource usage of all lwps" },
167  { PIOCOPENLWP,   "PIOCOPENLWP",  "get lwp file descriptor" },
168  { PIOCLWPIDS,    "PIOCLWPIDS",   "get lwp identifiers" },
169#endif /* LWP */
170  { PIOCMAP,       "PIOCMAP",      "get memory map information" },
171  { PIOCMAXSIG,    "PIOCMAXSIG",   "get max signal number" },
172  { PIOCNICE,      "PIOCNICE",     "set nice priority" },
173  { PIOCNMAP,      "PIOCNMAP",     "get number of memory mappings" },
174  { PIOCOPENM,     "PIOCOPENM",    "open mapped object for reading" },
175#ifdef PIOCOPENMOBS			/* osf */
176  { PIOCOPENMOBS,  "PIOCOPENMOBS", "open mapped object" },
177#endif
178#ifdef PIOCOPENPD	/* solaris */
179  { PIOCOPENPD,    "PIOCOPENPD",   "get page data file descriptor" },
180#endif
181  { PIOCPSINFO,    "PIOCPSINFO",   "get ps(1) information" },
182  { PIOCRESET,     "PIOCRESET",    "reset process flags" },
183  { PIOCRFORK,     "PIOCRFORK",    "reset inherit-on-fork flag" },
184  { PIOCRRLC,      "PIOCRRLC",     "reset run-on-last-close flag" },
185  { PIOCRUN,       "PIOCRUN",      "make process runnable" },
186#ifdef PIOCSAVECCNTRS			/* irix */
187  { PIOCSAVECCNTRS, "PIOCSAVECCNTRS", "parent gets child cntrs" },
188#endif
189  { PIOCSENTRY,    "PIOCSENTRY",   "set traced syscall entry set" },
190  { PIOCSET,       "PIOCSET",      "set process flags" },
191  { PIOCSEXIT,     "PIOCSEXIT",    "set traced syscall exit  set" },
192  { PIOCSFAULT,    "PIOCSFAULT",   "set traced fault set" },
193  { PIOCSFORK,     "PIOCSFORK",    "set inherit-on-fork flag" },
194  { PIOCSFPREG,    "PIOCSFPREG",   "set floating point registers" },
195  { PIOCSHOLD,     "PIOCSHOLD",    "set held signal set" },
196  { PIOCSREG,      "PIOCSREG",     "set general registers" },
197  { PIOCSRLC,      "PIOCSRLC",     "set run-on-last-close flag" },
198  { PIOCSSIG,      "PIOCSSIG",     "set current signal" },
199  { PIOCSTATUS,    "PIOCSTATUS",   "get process status" },
200  { PIOCSTOP,      "PIOCSTOP",     "post stop request" },
201  { PIOCSTRACE,    "PIOCSTRACE",   "set traced signal set" },
202  { PIOCUNKILL,    "PIOCUNKILL",   "delete a signal" },
203#ifdef PIOCUSAGE	/* solaris */
204  { PIOCUSAGE,     "PIOCUSAGE",    "get resource usage" },
205#endif
206  { PIOCWSTOP,     "PIOCWSTOP",    "wait for process to stop" },
207
208#ifdef PIOCNTHR				/* osf threads */
209  { PIOCNTHR,      "PIOCNTHR",     "get thread count" },
210  { PIOCRTINH,     "PIOCRTINH",    "reset inherit-on-thread-creation" },
211  { PIOCSTINH,     "PIOCSTINH",    "set   inherit-on-thread-creation" },
212  { PIOCTLIST,     "PIOCTLIST",    "get thread ids" },
213  { PIOCXPTH,      "PIOCXPTH",     "translate port to thread handle" },
214  { PIOCTRUN,      "PIOCTRUN",     "make thread runnable" },
215  { PIOCTSTATUS,   "PIOCTSTATUS",  "get thread status" },
216  { PIOCTSTOP,     "PIOCTSTOP",    "stop a thread" },
217  /* ... TGTRACE TSTRACE TSSIG TKILL TUNKILL TCFAULT TGFAULT TSFAULT
218     TGFPREG TSFPREG TGREG TSREG TACTION TTERM TABRUN TGENTRY TSENTRY
219     TGEXIT TSEXIT TSHOLD ... thread functions */
220#endif /* osf threads */
221  { -1,            NULL,           NULL }
222};
223
224int
225ioctl_with_trace (int fd, long opcode, void *ptr, char *file, int line)
226{
227  int i = 0;
228  int ret;
229  int arg1;
230
231  prepare_to_trace ();
232
233  if (procfs_trace)
234    {
235      for (i = 0; ioctl_table[i].name != NULL; i++)
236	if (ioctl_table[i].value == opcode)
237	  break;
238
239      if (info_verbose)
240	fprintf (procfs_file ? procfs_file : stdout,
241		 "%s:%d -- ", file, line);
242      switch (opcode) {
243      case PIOCSET:
244	arg1 = ptr ? *(long *) ptr : 0;
245	fprintf (procfs_file ? procfs_file : stdout,
246		 "ioctl (PIOCSET,   %s) %s\n",
247		 arg1 == PR_FORK  ? "PR_FORK"  :
248		 arg1 == PR_RLC   ? "PR_RLC"   :
249#ifdef PR_ASYNC
250		 arg1 == PR_ASYNC ? "PR_ASYNC" :
251#endif
252		 "<unknown flag>",
253		 info_verbose ? ioctl_table[i].desc : "");
254	break;
255      case PIOCRESET:
256	arg1 = ptr ? *(long *) ptr : 0;
257	fprintf (procfs_file ? procfs_file : stdout,
258		 "ioctl (PIOCRESET, %s) %s\n",
259		 arg1 == PR_FORK  ? "PR_FORK"  :
260		 arg1 == PR_RLC   ? "PR_RLC"   :
261#ifdef PR_ASYNC
262		 arg1 == PR_ASYNC ? "PR_ASYNC" :
263#endif
264		 "<unknown flag>",
265		 info_verbose ? ioctl_table[i].desc : "");
266	break;
267      case PIOCSTRACE:
268	fprintf (procfs_file ? procfs_file : stdout,
269		 "ioctl (PIOCSTRACE) ");
270	proc_prettyfprint_signalset (procfs_file ? procfs_file : stdout,
271				     (sigset_t *) ptr, 0);
272	break;
273      case PIOCSFAULT:
274	fprintf (procfs_file ? procfs_file : stdout,
275		 "ioctl (%s) ",
276		 opcode == PIOCSFAULT ? "PIOCSFAULT" : "PIOCGFAULT");
277	proc_prettyfprint_faultset (procfs_file ? procfs_file : stdout,
278				    (fltset_t *) ptr, 0);
279	break;
280      case PIOCSENTRY:
281	fprintf (procfs_file ? procfs_file : stdout,
282		 "ioctl (%s) ",
283		 opcode == PIOCSENTRY ? "PIOCSENTRY" : "PIOCGENTRY");
284	proc_prettyfprint_syscalls (procfs_file ? procfs_file : stdout,
285				    (sysset_t *) ptr, 0);
286	break;
287      case PIOCSEXIT:
288	fprintf (procfs_file ? procfs_file : stdout,
289		 "ioctl (%s) ",
290		 opcode == PIOCSEXIT ? "PIOCSEXIT" : "PIOCGEXIT");
291	proc_prettyfprint_syscalls (procfs_file ? procfs_file : stdout,
292				    (sysset_t *) ptr, 0);
293	break;
294      case PIOCSHOLD:
295	fprintf (procfs_file ? procfs_file : stdout,
296		 "ioctl (%s) ",
297		 opcode == PIOCSHOLD ? "PIOCSHOLD" : "PIOCGHOLD");
298	proc_prettyfprint_signalset (procfs_file ? procfs_file : stdout,
299				     (sigset_t *) ptr, 0);
300	break;
301      case PIOCSSIG:
302	fprintf (procfs_file ? procfs_file : stdout,
303		 "ioctl (PIOCSSIG) ");
304	proc_prettyfprint_signal (procfs_file ? procfs_file : stdout,
305				  ptr ? ((siginfo_t *) ptr)->si_signo : 0,
306				  0);
307	fprintf (procfs_file ? procfs_file : stdout, "\n");
308	break;
309      case PIOCRUN:
310	fprintf (procfs_file ? procfs_file : stdout,
311		 "ioctl (PIOCRUN) ");
312
313	arg1 = ptr ? *(long *) ptr : 0;
314	if (arg1 & PRCSIG)
315	  fprintf (procfs_file ? procfs_file : stdout, "clearSig ");
316	if (arg1 & PRCFAULT)
317	  fprintf (procfs_file ? procfs_file : stdout, "clearFlt ");
318	if (arg1 & PRSTRACE)
319	  fprintf (procfs_file ? procfs_file : stdout, "setTrace ");
320	if (arg1 & PRSHOLD)
321	  fprintf (procfs_file ? procfs_file : stdout, "setHold ");
322	if (arg1 & PRSFAULT)
323	  fprintf (procfs_file ? procfs_file : stdout, "setFlt ");
324	if (arg1 & PRSVADDR)
325	  fprintf (procfs_file ? procfs_file : stdout, "setVaddr ");
326	if (arg1 & PRSTEP)
327	  fprintf (procfs_file ? procfs_file : stdout, "step ");
328	if (arg1 & PRSABORT)
329	  fprintf (procfs_file ? procfs_file : stdout, "syscallAbort ");
330	if (arg1 & PRSTOP)
331	  fprintf (procfs_file ? procfs_file : stdout, "stopReq ");
332
333	fprintf (procfs_file ? procfs_file : stdout, "\n");
334	break;
335      case PIOCKILL:
336	fprintf (procfs_file ? procfs_file : stdout,
337		 "ioctl (PIOCKILL) ");
338	proc_prettyfprint_signal (procfs_file ? procfs_file : stdout,
339				  ptr ? *(long *) ptr : 0, 0);
340	fprintf (procfs_file ? procfs_file : stdout, "\n");
341	break;
342#ifdef PIOCSSPCACT
343      case PIOCSSPCACT:
344	fprintf (procfs_file ? procfs_file : stdout,
345		 "ioctl (PIOCSSPCACT) ");
346	arg1 = ptr ? *(long *) ptr : 0;
347	if (arg1 & PRFS_STOPFORK)
348	  fprintf (procfs_file ? procfs_file : stdout, "stopFork ");
349	if (arg1 & PRFS_STOPEXEC)
350	  fprintf (procfs_file ? procfs_file : stdout, "stopExec ");
351	if (arg1 & PRFS_STOPTERM)
352	  fprintf (procfs_file ? procfs_file : stdout, "stopTerm ");
353	if (arg1 & PRFS_STOPTCR)
354	  fprintf (procfs_file ? procfs_file : stdout, "stopThreadCreate ");
355	if (arg1 & PRFS_STOPTTERM)
356	  fprintf (procfs_file ? procfs_file : stdout, "stopThreadTerm ");
357	if (arg1 & PRFS_KOLC)
358	  fprintf (procfs_file ? procfs_file : stdout, "killOnLastClose ");
359	fprintf (procfs_file ? procfs_file : stdout, "\n");
360	break;
361#endif /* PIOCSSPCACT */
362      default:
363	if (ioctl_table[i].name)
364	  fprintf (procfs_file ? procfs_file : stdout,
365		   "ioctl (%s) %s\n",
366		   ioctl_table[i].name,
367		   info_verbose ? ioctl_table[i].desc : "");
368	else
369	  fprintf (procfs_file ? procfs_file : stdout,
370		   "ioctl (<unknown %ld (0x%lx)) \n", opcode, opcode);
371	break;
372      }
373      if (procfs_file)
374	fflush (procfs_file);
375    }
376  errno = 0;
377  ret = ioctl (fd, opcode, ptr);
378  if (procfs_trace && ret < 0)
379    {
380      fprintf (procfs_file ? procfs_file : stdout,
381	       "[ioctl (%s) FAILED! (%s)]\n",
382	       ioctl_table[i].name != NULL ?
383	       ioctl_table[i].name : "<unknown>",
384	       safe_strerror (errno));
385      if (procfs_file)
386	fflush (procfs_file);
387    }
388
389  return ret;
390}
391
392#else	/* NEW_PROC_API */
393
394static struct trans rw_table[] = {
395#ifdef PCAGENT			/* solaris */
396  { PCAGENT,  "PCAGENT",  "create agent lwp with regs from argument" },
397#endif
398  { PCCFAULT, "PCCFAULT", "clear current fault" },
399#ifdef PCCSIG			/* solaris */
400  { PCCSIG,   "PCCSIG",   "clear current signal" },
401#endif
402#ifdef PCDSTOP			/* solaris */
403  { PCDSTOP,  "PCDSTOP",  "post stop request" },
404#endif
405  { PCKILL,   "PCKILL",   "post a signal" },
406#ifdef PCNICE			/* solaris */
407  { PCNICE,   "PCNICE",   "set nice priority" },
408#endif
409#ifdef PCREAD			/* solaris */
410  { PCREAD,   "PCREAD",   "read from the address space" },
411  { PCWRITE,  "PCWRITE",  "write to the address space" },
412#endif
413#ifdef PCRESET			/* unixware */
414  { PCRESET,  "PCRESET",  "unset modes" },
415#endif
416  { PCRUN,    "PCRUN",    "make process/lwp runnable" },
417#ifdef PCSASRS			/* solaris 2.7 only */
418  { PCSASRS,  "PCSASRS",  "set ancillary state registers" },
419#endif
420#ifdef PCSCRED			/* solaris */
421  { PCSCRED,  "PCSCRED",  "set process credentials" },
422#endif
423  { PCSENTRY, "PCSENTRY", "set traced syscall entry set" },
424  { PCSET,    "PCSET",    "set modes" },
425  { PCSEXIT,  "PCSEXIT",  "set traced syscall exit  set" },
426  { PCSFAULT, "PCSFAULT", "set traced fault set" },
427  { PCSFPREG, "PCSFPREG", "set floating point registers" },
428#ifdef PCSHOLD			/* solaris */
429  { PCSHOLD,  "PCSHOLD",  "set signal mask" },
430#endif
431  { PCSREG,   "PCSREG",   "set general registers" },
432  { PCSSIG,   "PCSSIG",   "set current signal" },
433  { PCSTOP,   "PCSTOP",   "post stop request and wait" },
434  { PCSTRACE, "PCSTRACE", "set traced signal set" },
435#ifdef PCSVADDR			/* solaris */
436  { PCSVADDR, "PCSVADDR", "set pc virtual address" },
437#endif
438#ifdef PCSXREG			/* solaris sparc only */
439  { PCSXREG,  "PCSXREG",  "set extra registers" },
440#endif
441#ifdef PCTWSTOP			/* solaris */
442  { PCTWSTOP, "PCTWSTOP", "wait for stop, with timeout arg" },
443#endif
444#ifdef PCUNKILL			/* solaris */
445  { PCUNKILL, "PCUNKILL", "delete a pending signal" },
446#endif
447#ifdef PCUNSET			/* solaris */
448  { PCUNSET,  "PCUNSET",  "unset modes" },
449#endif
450#ifdef PCWATCH			/* solaris */
451  { PCWATCH,  "PCWATCH",  "set/unset watched memory area" },
452#endif
453  { PCWSTOP,  "PCWSTOP",  "wait for process/lwp to stop, no timeout" },
454  { 0,        NULL,      NULL }
455};
456
457static off_t lseek_offset;
458
459int
460write_with_trace (int fd, void *varg, size_t len, char *file, int line)
461{
462  int i = ARRAY_SIZE (rw_table) - 1;
463  int ret;
464  procfs_ctl_t *arg = (procfs_ctl_t *) varg;
465
466  prepare_to_trace ();
467  if (procfs_trace)
468    {
469      procfs_ctl_t opcode = arg[0];
470      for (i = 0; rw_table[i].name != NULL; i++)
471	if (rw_table[i].value == opcode)
472	  break;
473
474      if (info_verbose)
475	fprintf (procfs_file ? procfs_file : stdout,
476		 "%s:%d -- ", file, line);
477      switch (opcode) {
478      case PCSET:
479	fprintf (procfs_file ? procfs_file : stdout,
480		 "write (PCSET,   %s) %s\n",
481		 arg[1] == PR_FORK  ? "PR_FORK"  :
482		 arg[1] == PR_RLC   ? "PR_RLC"   :
483#ifdef PR_ASYNC
484		 arg[1] == PR_ASYNC ? "PR_ASYNC" :
485#endif
486		 "<unknown flag>",
487		 info_verbose ? rw_table[i].desc : "");
488	break;
489#ifdef PCUNSET
490      case PCUNSET:
491#endif
492#ifdef PCRESET
493#if PCRESET != PCUNSET
494      case PCRESET:
495#endif
496#endif
497	fprintf (procfs_file ? procfs_file : stdout,
498		 "write (PCRESET, %s) %s\n",
499		 arg[1] == PR_FORK  ? "PR_FORK"  :
500		 arg[1] == PR_RLC   ? "PR_RLC"   :
501#ifdef PR_ASYNC
502		 arg[1] == PR_ASYNC ? "PR_ASYNC" :
503#endif
504		 "<unknown flag>",
505		 info_verbose ? rw_table[i].desc : "");
506	break;
507      case PCSTRACE:
508	fprintf (procfs_file ? procfs_file : stdout,
509		 "write (PCSTRACE) ");
510	proc_prettyfprint_signalset (procfs_file ? procfs_file : stdout,
511				     (sigset_t *) &arg[1], 0);
512	break;
513      case PCSFAULT:
514	fprintf (procfs_file ? procfs_file : stdout,
515		 "write (PCSFAULT) ");
516	proc_prettyfprint_faultset (procfs_file ? procfs_file : stdout,
517				    (fltset_t *) &arg[1], 0);
518	break;
519      case PCSENTRY:
520	fprintf (procfs_file ? procfs_file : stdout,
521		 "write (PCSENTRY) ");
522	proc_prettyfprint_syscalls (procfs_file ? procfs_file : stdout,
523				    (sysset_t *) &arg[1], 0);
524	break;
525      case PCSEXIT:
526	fprintf (procfs_file ? procfs_file : stdout,
527		 "write (PCSEXIT) ");
528	proc_prettyfprint_syscalls (procfs_file ? procfs_file : stdout,
529				    (sysset_t *) &arg[1], 0);
530	break;
531#ifdef PCSHOLD
532      case PCSHOLD:
533	fprintf (procfs_file ? procfs_file : stdout,
534		 "write (PCSHOLD) ");
535	proc_prettyfprint_signalset (procfs_file ? procfs_file : stdout,
536				     (sigset_t *) &arg[1], 0);
537	break;
538#endif
539      case PCSSIG:
540	fprintf (procfs_file ? procfs_file : stdout,
541		 "write (PCSSIG) ");
542	proc_prettyfprint_signal (procfs_file ? procfs_file : stdout,
543				  arg[1] ? ((siginfo_t *) &arg[1])->si_signo
544				         : 0,
545				  0);
546	fprintf (procfs_file ? procfs_file : stdout, "\n");
547	break;
548      case PCRUN:
549	fprintf (procfs_file ? procfs_file : stdout,
550		 "write (PCRUN) ");
551	if (arg[1] & PRCSIG)
552	  fprintf (procfs_file ? procfs_file : stdout, "clearSig ");
553	if (arg[1] & PRCFAULT)
554	  fprintf (procfs_file ? procfs_file : stdout, "clearFlt ");
555	if (arg[1] & PRSTEP)
556	  fprintf (procfs_file ? procfs_file : stdout, "step ");
557#ifdef PRSABORT
558	if (arg[1] & PRSABORT)
559	  fprintf (procfs_file ? procfs_file : stdout, "syscallAbort ");
560#endif
561#ifdef PRSTOP
562	if (arg[1] & PRSTOP)
563	  fprintf (procfs_file ? procfs_file : stdout, "stopReq ");
564#endif
565
566	fprintf (procfs_file ? procfs_file : stdout, "\n");
567	break;
568      case PCKILL:
569	fprintf (procfs_file ? procfs_file : stdout,
570		 "write (PCKILL) ");
571	proc_prettyfprint_signal (procfs_file ? procfs_file : stdout,
572				  arg[1], 0);
573	fprintf (procfs_file ? procfs_file : stdout, "\n");
574	break;
575      default:
576	{
577	  if (rw_table[i].name)
578	    fprintf (procfs_file ? procfs_file : stdout,
579		     "write (%s) %s\n",
580		     rw_table[i].name,
581		     info_verbose ? rw_table[i].desc : "");
582	  else
583	    {
584	      if (lseek_offset != -1)
585		fprintf (procfs_file ? procfs_file : stdout,
586			 "write (<unknown>, %lud bytes at 0x%08lx) \n",
587			 (unsigned long) len, (unsigned long) lseek_offset);
588	      else
589		fprintf (procfs_file ? procfs_file : stdout,
590			 "write (<unknown>, %lud bytes) \n",
591			 (unsigned long) len);
592	    }
593	  break;
594	}
595      }
596      if (procfs_file)
597	fflush (procfs_file);
598    }
599  errno = 0;
600  ret = write (fd, (void *) arg, len);
601  if (procfs_trace && ret != len)
602    {
603      fprintf (procfs_file ? procfs_file : stdout,
604	       "[write (%s) FAILED! (%s)]\n",
605	       rw_table[i].name != NULL ?
606	       rw_table[i].name : "<unknown>",
607	       safe_strerror (errno));
608      if (procfs_file)
609	fflush (procfs_file);
610    }
611
612  lseek_offset = -1;
613  return ret;
614}
615
616off_t
617lseek_with_trace (int fd, off_t offset, int whence, char *file, int line)
618{
619  off_t ret;
620
621  prepare_to_trace ();
622  errno = 0;
623  ret = lseek (fd, offset, whence);
624  lseek_offset = ret;
625  if (procfs_trace && (ret == -1 || errno != 0))
626    {
627      fprintf (procfs_file ? procfs_file : stdout,
628	       "[lseek (0x%08lx) FAILED! (%s)]\n",
629	       (unsigned long) offset, safe_strerror (errno));
630      if (procfs_file)
631	fflush (procfs_file);
632    }
633
634  return ret;
635}
636
637#endif /* NEW_PROC_API */
638
639int
640open_with_trace (char *filename, int mode, char *file, int line)
641{
642  int ret;
643
644  prepare_to_trace ();
645  errno = 0;
646  ret = open (filename, mode);
647  if (procfs_trace)
648    {
649      if (info_verbose)
650	fprintf (procfs_file ? procfs_file : stdout,
651		 "%s:%d -- ", file, line);
652
653      if (errno)
654	{
655	  fprintf (procfs_file ? procfs_file : stdout,
656		   "[open FAILED! (%s) line %d]\\n",
657		   safe_strerror (errno), line);
658	}
659      else
660	{
661	  fprintf (procfs_file ? procfs_file : stdout,
662		   "%d = open (%s, ", ret, filename);
663	  if (mode == O_RDONLY)
664	    fprintf (procfs_file ? procfs_file : stdout, "O_RDONLY) %d\n",
665		     line);
666	  else if (mode == O_WRONLY)
667	    fprintf (procfs_file ? procfs_file : stdout, "O_WRONLY) %d\n",
668		     line);
669	  else if (mode == O_RDWR)
670	    fprintf (procfs_file ? procfs_file : stdout, "O_RDWR)   %d\n",
671		     line);
672	}
673      if (procfs_file)
674	fflush (procfs_file);
675    }
676
677  return ret;
678}
679
680int
681close_with_trace (int fd, char *file, int line)
682{
683  int ret;
684
685  prepare_to_trace ();
686  errno = 0;
687  ret = close (fd);
688  if (procfs_trace)
689    {
690      if (info_verbose)
691	fprintf (procfs_file ? procfs_file : stdout,
692		 "%s:%d -- ", file, line);
693      if (errno)
694	fprintf (procfs_file ? procfs_file : stdout,
695		 "[close FAILED! (%s)]\n", safe_strerror (errno));
696      else
697	fprintf (procfs_file ? procfs_file : stdout,
698		 "%d = close (%d)\n", ret, fd);
699      if (procfs_file)
700	fflush (procfs_file);
701    }
702
703  return ret;
704}
705
706pid_t
707wait_with_trace (int *wstat, char *file, int line)
708{
709  int ret, lstat = 0;
710
711  prepare_to_trace ();
712  if (procfs_trace)
713    {
714      if (info_verbose)
715	fprintf (procfs_file ? procfs_file : stdout,
716		 "%s:%d -- ", file, line);
717      fprintf (procfs_file ? procfs_file : stdout,
718	       "wait (line %d) ", line);
719      if (procfs_file)
720	fflush (procfs_file);
721    }
722  errno = 0;
723  ret = wait (&lstat);
724  if (procfs_trace)
725    {
726      if (errno)
727	fprintf (procfs_file ? procfs_file : stdout,
728		 "[wait FAILED! (%s)]\n", safe_strerror (errno));
729      else
730	fprintf (procfs_file ? procfs_file : stdout,
731		 "returned pid %d, status 0x%x\n", ret, lstat);
732      if (procfs_file)
733	fflush (procfs_file);
734    }
735  if (wstat)
736    *wstat = lstat;
737
738  return ret;
739}
740
741void
742procfs_note (char *msg, char *file, int line)
743{
744  prepare_to_trace ();
745  if (procfs_trace)
746    {
747      if (info_verbose)
748	fprintf (procfs_file ? procfs_file : stdout,
749		 "%s:%d -- ", file, line);
750      fprintf (procfs_file ? procfs_file : stdout, "%s", msg);
751      if (procfs_file)
752	fflush (procfs_file);
753    }
754}
755
756void
757proc_prettyfprint_status (long flags, int why, int what, int thread)
758{
759  prepare_to_trace ();
760  if (procfs_trace)
761    {
762      if (thread)
763	fprintf (procfs_file ? procfs_file : stdout,
764		 "Thread %d: ", thread);
765
766      proc_prettyfprint_flags (procfs_file ? procfs_file : stdout,
767			       flags, 0);
768
769      if (flags & (PR_STOPPED | PR_ISTOP))
770	proc_prettyfprint_why (procfs_file ? procfs_file : stdout,
771			       why, what, 0);
772      if (procfs_file)
773	fflush (procfs_file);
774    }
775}
776
777
778void
779_initialize_proc_api (void)
780{
781  struct cmd_list_element *c;
782
783  c = add_set_cmd ("procfs-trace", no_class,
784		   var_boolean, (char *) &procfs_trace,
785		   "Set tracing for /proc api calls.\n", &setlist);
786
787  deprecated_add_show_from_set (c, &showlist);
788  set_cmd_sfunc (c, set_procfs_trace_cmd);
789  set_cmd_completer (c, filename_completer);
790
791  c = add_set_cmd ("procfs-file", no_class, var_filename,
792		   (char *) &procfs_filename,
793		   "Set filename for /proc tracefile.\n", &setlist);
794
795  deprecated_add_show_from_set (c, &showlist);
796  set_cmd_sfunc (c, set_procfs_file_cmd);
797}
798