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