IRIX GCC fixes from 5.0 branch.
[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 (args, from_tty, c)
73      char *args;
74      int from_tty;
75      struct cmd_list_element *c;
76 {
77 #if 0   /* not sure what I might actually need to do here, if anything */
78   if (procfs_file)
79     fflush (procfs_file);
80 #endif
81 }
82
83 static void
84 set_procfs_file_cmd (args, from_tty, c)
85      char *args;
86      int from_tty;
87      struct cmd_list_element *c;
88 {
89   /* Just changed the filename for procfs tracing.
90      If a file was already open, close it.  */
91   if (procfs_file)
92     fclose (procfs_file);
93   procfs_file = NULL;
94 }
95
96
97 #ifndef NEW_PROC_API
98
99 static struct trans ioctl_table[] = {
100 #ifdef PIOCACINFO                       /* irix */
101   { PIOCACINFO,    "PIOCACINFO",   "get process account info" },
102 #endif
103   { PIOCACTION,    "PIOCACTION",   "get signal action structs" },
104 #ifdef PIOCARGUMENTS                    /* osf */
105   { PIOCARGUMENTS, "PIOCARGUMENTS", "command line args" },
106 #endif
107 #ifdef PIOCAUXV                         /* solaris aux vectors */
108   { PIOCAUXV,      "PIOCAUXV",     "get aux vector" },
109   { PIOCNAUXV,     "PIOCNAUXV",    "get number of aux vector entries" },
110 #endif /* AUXV */
111   { PIOCCFAULT,    "PIOCCFAULT",   "clear current fault" },
112   { PIOCCRED,      "PIOCCRED",     "get process credentials" },
113 #ifdef PIOCENEVCTRS                     /* irix event counters */
114   { PIOCENEVCTRS,    "PIOCENEVCTRS",    "acquire and start event counters" },
115   { PIOCGETEVCTRL,   "PIOCGETEVCTRL",   "get control info of event counters" },
116   { PIOCGETEVCTRS,   "PIOCGETEVCTRS",   "dump event counters" },
117   { PIOCGETPREVCTRS, "PIOCGETPREVCTRS", "dump event counters & prusage info" },
118   { PIOCRELEVCTRS,   "PIOCRELEVCTRS",   "release/stop event counters" },
119   { PIOCSETEVCTRL,   "PIOCSETEVCTRL",   "set control info of event counters" },
120   { PIOCGETPTIMER,   "PIOCGETPTIMER",   "get process timers" },
121 #endif  /* irix event counters */
122   { PIOCGENTRY,    "PIOCGENTRY",   "get traced syscall entry set" },
123 #if defined (PIOCGETPR)
124   { PIOCGETPR,     "PIOCGETPR",    "read struct proc" },
125 #endif
126 #if defined (PIOCGETU)
127   { PIOCGETU,      "PIOCGETU",     "read user area" },
128 #endif
129 #if defined (PIOCGETUTK) && (defined(KERNEL) || defined(SHOW_UTT)) /* osf */
130   { PIOCGETUTK,  "PIOCGETUTK", "get the utask struct" },
131 #endif
132   { PIOCGEXIT,     "PIOCGEXIT",    "get traced syscall exit  set" },
133   { PIOCGFAULT,    "PIOCGFAULT",   "get traced fault set" },
134 #ifdef PIOCGFPCR                        /* osf */
135   { PIOCGFPCR,     "PIOCGFPCR",    "get FP control register" },
136   { PIOCSFPCR,     "PIOCSFPCR",    "set FP conrtol register" },
137 #endif
138   { PIOCGFPREG,    "PIOCGFPREG",   "get floating point registers" },
139   { PIOCGHOLD,     "PIOCGHOLD",    "get held signal set" },
140   { PIOCGREG,      "PIOCGREG",     "get general registers" },
141   { PIOCGROUPS,    "PIOCGROUPS",   "get supplementary groups" },
142 #ifdef PIOCGSPCACT                      /* osf */
143   { PIOCGSPCACT,   "PIOCGSPCACT",  "get special action" },
144   { PIOCSSPCACT,   "PIOCSSPCACT",  "set special action" },
145 #endif
146   { PIOCGTRACE,    "PIOCGTRACE",   "get traced signal set" },
147 #ifdef PIOCGWATCH                       /* irix watchpoints */
148   { PIOCGWATCH,    "PIOCGWATCH",   "get watchpoint" },
149   { PIOCSWATCH,    "PIOCSWATCH",   "set watchpoint" },
150   { PIOCNWATCH,    "PIOCNWATCH",   "get number of watchpoints" },
151 #endif  /* irix watchpoints */
152 #ifdef PIOCGWIN                         /* solaris sparc */
153   { PIOCGWIN,      "PIOCGWIN",     "get gwindows_t" },
154 #endif
155 #ifdef PIOCGXREG                        /* solaris sparc extra regs */
156   { PIOCGXREGSIZE, "PIOCXREGSIZE", "get extra register state size" },
157   { PIOCGXREG,     "PIOCGXREG",    "get extra register state" },
158   { PIOCSXREG,     "PIOCSXREG",    "set extra register state" },
159 #endif /* XREG */
160   { PIOCKILL,      "PIOCKILL",     "send signal" },
161 #ifdef PIOCLDT                          /* solaris i386 */
162   { PIOCLDT,       "PIOCLDT",      "get LDT" },
163   { PIOCNLDT,      "PIOCNLDT",     "get number of LDT entries" },
164 #endif
165 #ifdef PIOCLSTATUS                      /* solaris and unixware */
166   { PIOCLSTATUS,   "PIOCLSTATUS",  "get status of all lwps" },
167   { PIOCLUSAGE,    "PIOCLUSAGE",   "get resource usage of all lwps" },
168   { PIOCOPENLWP,   "PIOCOPENLWP",  "get lwp file descriptor" },
169   { PIOCLWPIDS,    "PIOCLWPIDS",   "get lwp identifiers" },
170 #endif /* LWP */
171   { PIOCMAP,       "PIOCMAP",      "get memory map information" },
172   { PIOCMAXSIG,    "PIOCMAXSIG",   "get max signal number" },
173   { PIOCNICE,      "PIOCNICE",     "set nice priority" },
174   { PIOCNMAP,      "PIOCNMAP",     "get number of memory mappings" },
175   { PIOCOPENM,     "PIOCOPENM",    "open mapped object for reading" },
176 #ifdef PIOCOPENMOBS                     /* osf */
177   { PIOCOPENMOBS,  "PIOCOPENMOBS", "open mapped object" },
178 #endif
179 #ifdef PIOCOPENPD       /* solaris */
180   { PIOCOPENPD,    "PIOCOPENPD",   "get page data file descriptor" },
181 #endif
182   { PIOCPSINFO,    "PIOCPSINFO",   "get ps(1) information" },
183   { PIOCRESET,     "PIOCRESET",    "reset process flags" },
184   { PIOCRFORK,     "PIOCRFORK",    "reset inherit-on-fork flag" },
185   { PIOCRRLC,      "PIOCRRLC",     "reset run-on-last-close flag" },
186   { PIOCRUN,       "PIOCRUN",      "make process runnable" },
187 #ifdef PIOCSAVECCNTRS                   /* irix */
188   { PIOCSAVECCNTRS, "PIOCSAVECCNTRS", "parent gets child cntrs" },
189 #endif
190   { PIOCSENTRY,    "PIOCSENTRY",   "set traced syscall entry set" },
191   { PIOCSET,       "PIOCSET",      "set process flags" },
192   { PIOCSEXIT,     "PIOCSEXIT",    "set traced syscall exit  set" },
193   { PIOCSFAULT,    "PIOCSFAULT",   "set traced fault set" },
194   { PIOCSFORK,     "PIOCSFORK",    "set inherit-on-fork flag" },
195   { PIOCSFPREG,    "PIOCSFPREG",   "set floating point registers" },
196   { PIOCSHOLD,     "PIOCSHOLD",    "set held signal set" },
197   { PIOCSREG,      "PIOCSREG",     "set general registers" },
198   { PIOCSRLC,      "PIOCSRLC",     "set run-on-last-close flag" },
199   { PIOCSSIG,      "PIOCSSIG",     "set current signal" },
200   { PIOCSTATUS,    "PIOCSTATUS",   "get process status" },
201   { PIOCSTOP,      "PIOCSTOP",     "post stop request" },
202   { PIOCSTRACE,    "PIOCSTRACE",   "set traced signal set" },
203   { PIOCUNKILL,    "PIOCUNKILL",   "delete a signal" },
204 #ifdef PIOCUSAGE        /* solaris */
205   { PIOCUSAGE,     "PIOCUSAGE",    "get resource usage" },
206 #endif
207   { PIOCWSTOP,     "PIOCWSTOP",    "wait for process to stop" },
208
209 #ifdef PIOCNTHR                         /* osf threads */
210   { PIOCNTHR,      "PIOCNTHR",     "get thread count" },
211   { PIOCRTINH,     "PIOCRTINH",    "reset inherit-on-thread-creation" },
212   { PIOCSTINH,     "PIOCSTINH",    "set   inherit-on-thread-creation" },
213   { PIOCTLIST,     "PIOCTLIST",    "get thread ids" },
214   { PIOCXPTH,      "PIOCXPTH",     "translate port to thread handle" },
215   { PIOCTRUN,      "PIOCTRUN",     "make thread runnable" },
216   { PIOCTSTATUS,   "PIOCTSTATUS",  "get thread status" },
217   { PIOCTSTOP,     "PIOCTSTOP",    "stop a thread" },
218   /* ... TGTRACE TSTRACE TSSIG TKILL TUNKILL TCFAULT TGFAULT TSFAULT
219      TGFPREG TSFPREG TGREG TSREG TACTION TTERM TABRUN TGENTRY TSENTRY
220      TGEXIT TSEXIT TSHOLD ... thread functions */
221 #endif /* osf threads */
222   { -1,            NULL,           NULL }
223 };
224
225 int
226 ioctl_with_trace (fd, opcode, ptr, file, line)
227      int  fd;
228      long opcode;
229      void *ptr;
230      char *file;
231      int  line;
232 {
233   int i, ret, arg1;
234
235   prepare_to_trace ();
236
237   if (procfs_trace)
238     {
239       for (i = 0; ioctl_table[i].name != NULL; i++)
240         if (ioctl_table[i].value == opcode)
241           break;
242
243       if (info_verbose)
244         fprintf (procfs_file ? procfs_file : stdout, 
245                  "%s:%d -- ", file, line);
246       switch (opcode) {
247       case PIOCSET:
248         arg1 = ptr ? *(long *) ptr : 0;
249         fprintf (procfs_file ? procfs_file : stdout, 
250                  "ioctl (PIOCSET,   %s) %s\n", 
251                  arg1 == PR_FORK  ? "PR_FORK"  :
252                  arg1 == PR_RLC   ? "PR_RLC"   :
253 #ifdef PR_ASYNC
254                  arg1 == PR_ASYNC ? "PR_ASYNC" :
255 #endif
256                  "<unknown flag>",
257                  info_verbose ? ioctl_table[i].desc : "");
258         break;
259       case PIOCRESET:
260         arg1 = ptr ? *(long *) ptr : 0;
261         fprintf (procfs_file ? procfs_file : stdout, 
262                  "ioctl (PIOCRESET, %s) %s\n", 
263                  arg1 == PR_FORK  ? "PR_FORK"  :
264                  arg1 == PR_RLC   ? "PR_RLC"   :
265 #ifdef PR_ASYNC
266                  arg1 == PR_ASYNC ? "PR_ASYNC" :
267 #endif
268                  "<unknown flag>",
269                  info_verbose ? ioctl_table[i].desc : "");
270         break;
271       case PIOCSTRACE:
272         fprintf (procfs_file ? procfs_file : stdout, 
273                  "ioctl (PIOCSTRACE) ");
274         proc_prettyfprint_signalset (procfs_file ? procfs_file : stdout,
275                                      (sigset_t *) ptr, 0);
276         break;
277       case PIOCSFAULT:
278         fprintf (procfs_file ? procfs_file : stdout, 
279                  "ioctl (%s) ", 
280                  opcode == PIOCSFAULT ? "PIOCSFAULT" : "PIOCGFAULT");
281         proc_prettyfprint_faultset (procfs_file ? procfs_file : stdout,
282                                     (fltset_t *) ptr, 0);
283         break;
284       case PIOCSENTRY:
285         fprintf (procfs_file ? procfs_file : stdout, 
286                  "ioctl (%s) ", 
287                  opcode == PIOCSENTRY ? "PIOCSENTRY" : "PIOCGENTRY");
288         proc_prettyfprint_syscalls (procfs_file ? procfs_file : stdout,
289                                     (sysset_t *) ptr, 0);
290         break;
291       case PIOCSEXIT:
292         fprintf (procfs_file ? procfs_file : stdout, 
293                  "ioctl (%s) ", 
294                  opcode == PIOCSEXIT ? "PIOCSEXIT" : "PIOCGEXIT");
295         proc_prettyfprint_syscalls (procfs_file ? procfs_file : stdout,
296                                     (sysset_t *) ptr, 0);
297         break;
298       case PIOCSHOLD:
299         fprintf (procfs_file ? procfs_file : stdout, 
300                  "ioctl (%s) ", 
301                  opcode == PIOCSHOLD ? "PIOCSHOLD" : "PIOCGHOLD");
302         proc_prettyfprint_signalset (procfs_file ? procfs_file : stdout,
303                                      (sigset_t *) ptr, 0);
304         break;
305       case PIOCSSIG:
306         fprintf (procfs_file ? procfs_file : stdout, 
307                  "ioctl (PIOCSSIG) ");
308         proc_prettyfprint_signal (procfs_file ? procfs_file : stdout,
309                                   ptr ? ((siginfo_t *) ptr)->si_signo : 0, 
310                                   0);
311         fprintf (procfs_file ? procfs_file : stdout, "\n");
312         break;
313       case PIOCRUN:
314         fprintf (procfs_file ? procfs_file : stdout, 
315                  "ioctl (PIOCRUN) ");
316         
317         arg1 = ptr ? *(long *) ptr : 0;
318         if (arg1 & PRCSIG)
319           fprintf (procfs_file ? procfs_file : stdout, "clearSig ");
320         if (arg1 & PRCFAULT)
321           fprintf (procfs_file ? procfs_file : stdout, "clearFlt ");
322         if (arg1 & PRSTRACE)
323           fprintf (procfs_file ? procfs_file : stdout, "setTrace ");
324         if (arg1 & PRSHOLD)
325           fprintf (procfs_file ? procfs_file : stdout, "setHold ");
326         if (arg1 & PRSFAULT)
327           fprintf (procfs_file ? procfs_file : stdout, "setFlt ");
328         if (arg1 & PRSVADDR)
329           fprintf (procfs_file ? procfs_file : stdout, "setVaddr ");
330         if (arg1 & PRSTEP)
331           fprintf (procfs_file ? procfs_file : stdout, "step ");
332         if (arg1 & PRSABORT)
333           fprintf (procfs_file ? procfs_file : stdout, "syscallAbort ");
334         if (arg1 & PRSTOP)
335           fprintf (procfs_file ? procfs_file : stdout, "stopReq ");
336           
337         fprintf (procfs_file ? procfs_file : stdout, "\n");
338         break;
339       case PIOCKILL:
340         fprintf (procfs_file ? procfs_file : stdout, 
341                  "ioctl (PIOCKILL) ");
342         proc_prettyfprint_signal (procfs_file ? procfs_file : stdout,
343                                   ptr ? *(long *) ptr : 0, 0);
344         fprintf (procfs_file ? procfs_file : stdout, "\n");
345         break;
346 #ifdef PIOCSSPCACT
347       case PIOCSSPCACT:
348         fprintf (procfs_file ? procfs_file : stdout, 
349                  "ioctl (PIOCSSPCACT) ");
350         arg1 = ptr ? *(long *) ptr : 0;
351         if (arg1 & PRFS_STOPFORK)
352           fprintf (procfs_file ? procfs_file : stdout, "stopFork ");
353         if (arg1 & PRFS_STOPEXEC)
354           fprintf (procfs_file ? procfs_file : stdout, "stopExec ");
355         if (arg1 & PRFS_STOPTERM)
356           fprintf (procfs_file ? procfs_file : stdout, "stopTerm ");
357         if (arg1 & PRFS_STOPTCR)
358           fprintf (procfs_file ? procfs_file : stdout, "stopThreadCreate ");
359         if (arg1 & PRFS_STOPTTERM)
360           fprintf (procfs_file ? procfs_file : stdout, "stopThreadTerm ");
361         if (arg1 & PRFS_KOLC)
362           fprintf (procfs_file ? procfs_file : stdout, "killOnLastClose ");
363         fprintf (procfs_file ? procfs_file : stdout, "\n");
364         break;
365 #endif /* PIOCSSPCACT */
366       default:
367         if (ioctl_table[i].name)
368           fprintf (procfs_file ? procfs_file : stdout, 
369                    "ioctl (%s) %s\n", 
370                    ioctl_table[i].name,
371                    info_verbose ? ioctl_table[i].desc : "");
372         else
373           fprintf (procfs_file ? procfs_file : stdout, 
374                    "ioctl (<unknown %ld (0x%lx)) \n", opcode, opcode);
375         break;
376       }
377       if (procfs_file)
378         fflush (procfs_file);
379     }
380   errno = 0;
381   ret = ioctl (fd, opcode, ptr);
382   if (procfs_trace && ret < 0)
383     {
384       fprintf (procfs_file ? procfs_file : stdout, 
385                "[ioctl (%s) FAILED! (%s)]\n",
386                ioctl_table[i].name != NULL ? 
387                ioctl_table[i].name : "<unknown>",
388                safe_strerror (errno));
389       if (procfs_file)
390         fflush (procfs_file);
391     }
392
393   return ret;
394 }
395
396 #else   /* NEW_PROC_API */
397
398 static struct trans rw_table[] = {
399 #ifdef PCAGENT                  /* solaris */
400   { PCAGENT,  "PCAGENT",  "create agent lwp with regs from argument" },
401 #endif
402   { PCCFAULT, "PCCFAULT", "clear current fault" },
403 #ifdef PCCSIG                   /* solaris */
404   { PCCSIG,   "PCCSIG",   "clear current signal" },
405 #endif
406   { PCDSTOP,  "PCDSTOP",  "post stop request" },
407   { PCKILL,   "PCKILL",   "post a signal" },
408   { PCNICE,   "PCNICE",   "set nice priority" },
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   { PCSHOLD,  "PCSHOLD",  "set signal mask" },
429   { PCSREG,   "PCSREG",   "set general registers" },
430   { PCSSIG,   "PCSSIG",   "set current signal" },
431   { PCSTOP,   "PCSTOP",   "post stop request and wait" },
432   { PCSTRACE, "PCSTRACE", "set traced signal set" },
433 #ifdef PCSVADDR                 /* solaris */
434   { PCSVADDR, "PCSVADDR", "set pc virtual address" },
435 #endif
436 #ifdef PCSXREG                  /* solaris sparc only */
437   { PCSXREG,  "PCSXREG",  "set extra registers" },
438 #endif
439 #ifdef PCTWSTOP                 /* solaris */
440   { PCTWSTOP, "PCTWSTOP", "wait for stop, with timeout arg" },
441 #endif
442   { PCUNKILL, "PCUNKILL", "delete a pending signal" },
443 #ifdef PCUNSET                  /* solaris */
444   { PCUNSET,  "PCUNSET",  "unset modes" },
445 #endif
446 #ifdef PCWATCH                  /* solaris */
447   { PCWATCH,  "PCWATCH",  "set/unset watched memory area" },
448 #endif
449   { PCWSTOP,  "PCWSTOP",  "wait for process/lwp to stop, no timeout" },
450   { 0,        NULL,      NULL }
451 };
452
453 static off_t lseek_offset;
454
455 int
456 write_with_trace (fd, varg, len, file, line)
457      int  fd;
458      void *varg;
459      size_t len;
460      char *file;
461      int  line;
462 {
463   int  i;
464   int ret;
465   long *arg = (long *) varg;
466
467   prepare_to_trace ();
468   if (procfs_trace)
469     {
470       long opcode = arg[0];
471       for (i = 0; rw_table[i].name != NULL; i++)
472         if (rw_table[i].value == opcode)
473           break;
474
475       if (info_verbose)
476         fprintf (procfs_file ? procfs_file : stdout, 
477                  "%s:%d -- ", file, line);
478       switch (opcode) {
479       case PCSET:
480         fprintf (procfs_file ? procfs_file : stdout, 
481                  "write (PCSET,   %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 #ifdef PCUNSET
491       case PCUNSET:
492 #endif
493 #ifdef PCRESET
494       case PCRESET:
495 #endif
496         fprintf (procfs_file ? procfs_file : stdout, 
497                  "write (PCRESET, %s) %s\n", 
498                  arg[1] == PR_FORK  ? "PR_FORK"  :
499                  arg[1] == PR_RLC   ? "PR_RLC"   :
500 #ifdef PR_ASYNC
501                  arg[1] == PR_ASYNC ? "PR_ASYNC" :
502 #endif
503                  "<unknown flag>",
504                  info_verbose ? rw_table[i].desc : "");
505         break;
506       case PCSTRACE:
507         fprintf (procfs_file ? procfs_file : stdout, 
508                  "write (PCSTRACE) ");
509         proc_prettyfprint_signalset (procfs_file ? procfs_file : stdout,
510                                      (sigset_t *) &arg[1], 0);
511         break;
512       case PCSFAULT:
513         fprintf (procfs_file ? procfs_file : stdout, 
514                  "write (PCSFAULT) ");
515         proc_prettyfprint_faultset (procfs_file ? procfs_file : stdout,
516                                     (fltset_t *) &arg[1], 0);
517         break;
518       case PCSENTRY:
519         fprintf (procfs_file ? procfs_file : stdout, 
520                  "write (PCSENTRY) ");
521         proc_prettyfprint_syscalls (procfs_file ? procfs_file : stdout,
522                                     (sysset_t *) &arg[1], 0);
523         break;
524       case PCSEXIT:
525         fprintf (procfs_file ? procfs_file : stdout, 
526                  "write (PCSEXIT) ");
527         proc_prettyfprint_syscalls (procfs_file ? procfs_file : stdout,
528                                     (sysset_t *) &arg[1], 0);
529         break;
530       case PCSHOLD:
531         fprintf (procfs_file ? procfs_file : stdout, 
532                  "write (PCSHOLD) ");
533         proc_prettyfprint_signalset (procfs_file ? procfs_file : stdout,
534                                      (sigset_t *) &arg[1], 0);
535         break;
536       case PCSSIG:
537         fprintf (procfs_file ? procfs_file : stdout, 
538                  "write (PCSSIG) ");
539         proc_prettyfprint_signal (procfs_file ? procfs_file : stdout,
540                                   arg[1] ? ((siginfo_t *) &arg[1])->si_signo 
541                                          : 0, 
542                                   0);
543         fprintf (procfs_file ? procfs_file : stdout, "\n");
544         break;
545       case PCRUN:
546         fprintf (procfs_file ? procfs_file : stdout, 
547                  "write (PCRUN) ");
548         if (arg[1] & PRCSIG)
549           fprintf (procfs_file ? procfs_file : stdout, "clearSig ");
550         if (arg[1] & PRCFAULT)
551           fprintf (procfs_file ? procfs_file : stdout, "clearFlt ");
552         if (arg[1] & PRSTEP)
553           fprintf (procfs_file ? procfs_file : stdout, "step ");
554         if (arg[1] & PRSABORT)
555           fprintf (procfs_file ? procfs_file : stdout, "syscallAbort ");
556         if (arg[1] & PRSTOP)
557           fprintf (procfs_file ? procfs_file : stdout, "stopReq ");
558           
559         fprintf (procfs_file ? procfs_file : stdout, "\n");
560         break;
561       case PCKILL:
562         fprintf (procfs_file ? procfs_file : stdout, 
563                  "write (PCKILL) ");
564         proc_prettyfprint_signal (procfs_file ? procfs_file : stdout,
565                                   arg[1], 0);
566         fprintf (procfs_file ? procfs_file : stdout, "\n");
567         break;
568       default:
569         {
570           static unsigned char break_insn[] = BREAKPOINT;
571
572           if (len == sizeof (break_insn) &&
573               memcmp (arg, &break_insn, len) == 0)
574             fprintf (procfs_file ? procfs_file : stdout, 
575                      "write (<breakpoint at 0x%08lx>) \n", 
576                      (unsigned long) lseek_offset);
577           else 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
616 off_t
617 lseek_with_trace (fd, offset, whence, file, line)
618      int fd;
619      off_t offset;
620      int whence;
621      char *file;
622      int line;
623 {
624   off_t ret;
625
626   prepare_to_trace ();
627   errno = 0;
628   ret = lseek (fd, offset, whence);
629   lseek_offset = ret;
630   if (procfs_trace && (ret == -1 || errno != 0))
631     {
632       fprintf (procfs_file ? procfs_file : stdout, 
633                "[lseek (0x%08lx) FAILED! (%s)]\n", 
634                (unsigned long) offset, safe_strerror (errno));
635       if (procfs_file)
636         fflush (procfs_file);
637     }
638
639   return ret;
640 }
641
642 #endif /* NEW_PROC_API */
643
644 int
645 open_with_trace (filename, mode, file, line)
646      char *filename;
647      int   mode;
648      char *file;
649      int   line;
650 {
651   int ret;
652
653   prepare_to_trace ();
654   errno = 0;
655   ret = open (filename, mode);
656   if (procfs_trace)
657     {
658       if (info_verbose)
659         fprintf (procfs_file ? procfs_file : stdout, 
660                  "%s:%d -- ", file, line);
661
662       if (errno)
663         {
664           fprintf (procfs_file ? procfs_file : stdout, 
665                    "[open FAILED! (%s) line %d]\\n", 
666                    safe_strerror (errno), line);
667         }
668       else
669         {
670           fprintf (procfs_file ? procfs_file : stdout, 
671                    "%d = open (%s, ", ret, filename);
672           if (mode == O_RDONLY)
673             fprintf (procfs_file ? procfs_file : stdout, "O_RDONLY) %d\n",
674                      line);
675           else if (mode == O_WRONLY)
676             fprintf (procfs_file ? procfs_file : stdout, "O_WRONLY) %d\n",
677                      line);
678           else if (mode == O_RDWR)
679             fprintf (procfs_file ? procfs_file : stdout, "O_RDWR)   %d\n",
680                      line);
681         }
682       if (procfs_file)
683         fflush (procfs_file);
684     }
685
686   return ret;
687 }
688
689 int
690 close_with_trace (fd, file, line)
691      int   fd;
692      char *file;
693      int   line;
694 {
695   int ret;
696
697   prepare_to_trace ();
698   errno = 0;
699   ret = close (fd);
700   if (procfs_trace)
701     {
702       if (info_verbose)
703         fprintf (procfs_file ? procfs_file : stdout, 
704                  "%s:%d -- ", file, line);
705       if (errno)
706         fprintf (procfs_file ? procfs_file : stdout, 
707                  "[close FAILED! (%s)]\n", safe_strerror (errno));
708       else
709         fprintf (procfs_file ? procfs_file : stdout, 
710                  "%d = close (%d)\n", ret, fd);
711       if (procfs_file)
712         fflush (procfs_file);
713     }
714
715   return ret;
716 }
717
718 pid_t
719 wait_with_trace (wstat, file, line)
720      int  *wstat;
721      char *file;
722      int   line;
723 {
724   int ret, lstat = 0;
725
726   prepare_to_trace ();
727   if (procfs_trace)
728     {
729       if (info_verbose)
730         fprintf (procfs_file ? procfs_file : stdout, 
731                  "%s:%d -- ", file, line);
732       fprintf (procfs_file ? procfs_file : stdout, 
733                "wait (line %d) ", line);
734       if (procfs_file)
735         fflush (procfs_file);
736     }
737   errno = 0;
738   ret = wait (&lstat);
739   if (procfs_trace)
740     {
741       if (errno)
742         fprintf (procfs_file ? procfs_file : stdout, 
743                  "[wait FAILED! (%s)]\n", safe_strerror (errno));
744       else
745         fprintf (procfs_file ? procfs_file : stdout, 
746                  "returned pid %d, status 0x%x\n", ret, lstat);
747       if (procfs_file)
748         fflush (procfs_file);
749     }
750   if (wstat)
751     *wstat = lstat;
752
753   return ret;
754 }
755
756 void
757 procfs_note (msg, file, line)
758      char *msg;
759      char *file;
760      int   line;
761 {
762   prepare_to_trace ();
763   if (procfs_trace)
764     {
765       if (info_verbose)
766         fprintf (procfs_file ? procfs_file : stdout, 
767                  "%s:%d -- ", file, line);
768       fprintf (procfs_file ? procfs_file : stdout, msg);
769       if (procfs_file)
770         fflush (procfs_file);
771     }
772 }
773
774 void
775 proc_prettyfprint_status (flags, why, what, thread)
776      long flags;
777      int  why;
778      int  what;
779      int  thread;
780 {
781   prepare_to_trace ();
782   if (procfs_trace)
783     {
784       if (thread)
785         fprintf (procfs_file ? procfs_file : stdout,
786                  "Thread %d: ", thread);
787
788       proc_prettyfprint_flags (procfs_file ? procfs_file : stdout, 
789                                flags, 0);
790
791       if (flags & (PR_STOPPED | PR_ISTOP))
792         proc_prettyfprint_why (procfs_file ? procfs_file : stdout, 
793                                why, what, 0);
794       if (procfs_file)
795         fflush (procfs_file);
796     }
797 }
798
799
800 void
801 _initialize_proc_api ()
802 {
803   struct cmd_list_element *c;
804
805   c = add_set_cmd ("procfs-trace", no_class,
806                    var_boolean, (char *) &procfs_trace, 
807                    "Set tracing for /proc api calls.\n", &setlist);
808
809   add_show_from_set (c, &showlist);
810   c->function.sfunc = set_procfs_trace_cmd;
811
812   c = add_set_cmd ("procfs-file", no_class, var_filename,
813                    (char *) &procfs_filename, 
814                    "Set filename for /proc tracefile.\n", &setlist);
815
816   add_show_from_set (c, &showlist);
817   c->function.sfunc = set_procfs_file_cmd;
818 }