* sim/cris/hw/rv-n-cris/irq6.ms: New test.
[platform/upstream/binutils.git] / gdb / proc-api.c
1 /* Machine independent support for SVR4 /proc (process file system) for GDB.
2
3    Copyright (C) 1999, 2000, 2001, 2003, 2005 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 2 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, write to the Free Software Foundation, 
22 Inc., 51 Franklin Street, Fifth Floor,
23 Boston, MA 02110-1301, USA.  */
24
25 /*
26  * Pretty-print trace of api calls to the /proc api
27  * (ioctl or read/write calls).
28  * 
29  */
30
31 #include "defs.h"
32 #include "gdbcmd.h"
33 #include "completer.h"
34
35 #if defined (NEW_PROC_API)
36 #define _STRUCTURED_PROC 1
37 #endif
38
39 #include <stdio.h>
40 #include <sys/types.h>
41 #include <sys/procfs.h>
42 #ifdef HAVE_SYS_PROC_H
43 #include <sys/proc.h>   /* for struct proc */
44 #endif
45 #ifdef HAVE_SYS_USER_H
46 #include <sys/user.h>   /* for struct user */
47 #endif
48 #include <fcntl.h>      /* for O_RDWR etc. */
49 #include "gdb_wait.h"
50
51 #include "proc-utils.h"
52
53 /*  Much of the information used in the /proc interface, particularly for
54     printing status information, is kept as tables of structures of the
55     following form.  These tables can be used to map numeric values to
56     their symbolic names and to a string that describes their specific use. */
57
58 struct trans {
59   long value;                   /* The numeric value */
60   char *name;                   /* The equivalent symbolic value */
61   char *desc;                   /* Short description of value */
62 };
63
64 static int   procfs_trace    = 0;
65 static FILE *procfs_file     = NULL;
66 static char *procfs_filename = "procfs_trace";
67
68 static void
69 prepare_to_trace (void)
70 {
71   if (procfs_trace)                     /* if procfs tracing turned on */
72     if (procfs_file == NULL)            /* if output file not yet open */
73       if (procfs_filename != NULL)      /* if output filename known */
74         procfs_file = fopen (procfs_filename, "a");     /* open output file */
75 }
76
77 static void
78 set_procfs_trace_cmd (char *args, int from_tty, struct cmd_list_element *c)
79 {
80 #if 0   /* not sure what I might actually need to do here, if anything */
81   if (procfs_file)
82     fflush (procfs_file);
83 #endif
84 }
85
86 static void
87 set_procfs_file_cmd (char *args, int from_tty, 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 (int fd, long opcode, void *ptr, char *file, int line)
227 {
228   int i = 0;
229   int ret;
230   int arg1;
231
232   prepare_to_trace ();
233
234   if (procfs_trace)
235     {
236       for (i = 0; ioctl_table[i].name != NULL; i++)
237         if (ioctl_table[i].value == opcode)
238           break;
239
240       if (info_verbose)
241         fprintf (procfs_file ? procfs_file : stdout, 
242                  "%s:%d -- ", file, line);
243       switch (opcode) {
244       case PIOCSET:
245         arg1 = ptr ? *(long *) ptr : 0;
246         fprintf (procfs_file ? procfs_file : stdout, 
247                  "ioctl (PIOCSET,   %s) %s\n", 
248                  arg1 == PR_FORK  ? "PR_FORK"  :
249                  arg1 == PR_RLC   ? "PR_RLC"   :
250 #ifdef PR_ASYNC
251                  arg1 == PR_ASYNC ? "PR_ASYNC" :
252 #endif
253                  "<unknown flag>",
254                  info_verbose ? ioctl_table[i].desc : "");
255         break;
256       case PIOCRESET:
257         arg1 = ptr ? *(long *) ptr : 0;
258         fprintf (procfs_file ? procfs_file : stdout, 
259                  "ioctl (PIOCRESET, %s) %s\n", 
260                  arg1 == PR_FORK  ? "PR_FORK"  :
261                  arg1 == PR_RLC   ? "PR_RLC"   :
262 #ifdef PR_ASYNC
263                  arg1 == PR_ASYNC ? "PR_ASYNC" :
264 #endif
265                  "<unknown flag>",
266                  info_verbose ? ioctl_table[i].desc : "");
267         break;
268       case PIOCSTRACE:
269         fprintf (procfs_file ? procfs_file : stdout, 
270                  "ioctl (PIOCSTRACE) ");
271         proc_prettyfprint_signalset (procfs_file ? procfs_file : stdout,
272                                      (sigset_t *) ptr, 0);
273         break;
274       case PIOCSFAULT:
275         fprintf (procfs_file ? procfs_file : stdout, 
276                  "ioctl (%s) ", 
277                  opcode == PIOCSFAULT ? "PIOCSFAULT" : "PIOCGFAULT");
278         proc_prettyfprint_faultset (procfs_file ? procfs_file : stdout,
279                                     (fltset_t *) ptr, 0);
280         break;
281       case PIOCSENTRY:
282         fprintf (procfs_file ? procfs_file : stdout, 
283                  "ioctl (%s) ", 
284                  opcode == PIOCSENTRY ? "PIOCSENTRY" : "PIOCGENTRY");
285         proc_prettyfprint_syscalls (procfs_file ? procfs_file : stdout,
286                                     (sysset_t *) ptr, 0);
287         break;
288       case PIOCSEXIT:
289         fprintf (procfs_file ? procfs_file : stdout, 
290                  "ioctl (%s) ", 
291                  opcode == PIOCSEXIT ? "PIOCSEXIT" : "PIOCGEXIT");
292         proc_prettyfprint_syscalls (procfs_file ? procfs_file : stdout,
293                                     (sysset_t *) ptr, 0);
294         break;
295       case PIOCSHOLD:
296         fprintf (procfs_file ? procfs_file : stdout, 
297                  "ioctl (%s) ", 
298                  opcode == PIOCSHOLD ? "PIOCSHOLD" : "PIOCGHOLD");
299         proc_prettyfprint_signalset (procfs_file ? procfs_file : stdout,
300                                      (sigset_t *) ptr, 0);
301         break;
302       case PIOCSSIG:
303         fprintf (procfs_file ? procfs_file : stdout, 
304                  "ioctl (PIOCSSIG) ");
305         proc_prettyfprint_signal (procfs_file ? procfs_file : stdout,
306                                   ptr ? ((siginfo_t *) ptr)->si_signo : 0, 
307                                   0);
308         fprintf (procfs_file ? procfs_file : stdout, "\n");
309         break;
310       case PIOCRUN:
311         fprintf (procfs_file ? procfs_file : stdout, 
312                  "ioctl (PIOCRUN) ");
313         
314         arg1 = ptr ? *(long *) ptr : 0;
315         if (arg1 & PRCSIG)
316           fprintf (procfs_file ? procfs_file : stdout, "clearSig ");
317         if (arg1 & PRCFAULT)
318           fprintf (procfs_file ? procfs_file : stdout, "clearFlt ");
319         if (arg1 & PRSTRACE)
320           fprintf (procfs_file ? procfs_file : stdout, "setTrace ");
321         if (arg1 & PRSHOLD)
322           fprintf (procfs_file ? procfs_file : stdout, "setHold ");
323         if (arg1 & PRSFAULT)
324           fprintf (procfs_file ? procfs_file : stdout, "setFlt ");
325         if (arg1 & PRSVADDR)
326           fprintf (procfs_file ? procfs_file : stdout, "setVaddr ");
327         if (arg1 & PRSTEP)
328           fprintf (procfs_file ? procfs_file : stdout, "step ");
329         if (arg1 & PRSABORT)
330           fprintf (procfs_file ? procfs_file : stdout, "syscallAbort ");
331         if (arg1 & PRSTOP)
332           fprintf (procfs_file ? procfs_file : stdout, "stopReq ");
333           
334         fprintf (procfs_file ? procfs_file : stdout, "\n");
335         break;
336       case PIOCKILL:
337         fprintf (procfs_file ? procfs_file : stdout, 
338                  "ioctl (PIOCKILL) ");
339         proc_prettyfprint_signal (procfs_file ? procfs_file : stdout,
340                                   ptr ? *(long *) ptr : 0, 0);
341         fprintf (procfs_file ? procfs_file : stdout, "\n");
342         break;
343 #ifdef PIOCSSPCACT
344       case PIOCSSPCACT:
345         fprintf (procfs_file ? procfs_file : stdout, 
346                  "ioctl (PIOCSSPCACT) ");
347         arg1 = ptr ? *(long *) ptr : 0;
348         if (arg1 & PRFS_STOPFORK)
349           fprintf (procfs_file ? procfs_file : stdout, "stopFork ");
350         if (arg1 & PRFS_STOPEXEC)
351           fprintf (procfs_file ? procfs_file : stdout, "stopExec ");
352         if (arg1 & PRFS_STOPTERM)
353           fprintf (procfs_file ? procfs_file : stdout, "stopTerm ");
354         if (arg1 & PRFS_STOPTCR)
355           fprintf (procfs_file ? procfs_file : stdout, "stopThreadCreate ");
356         if (arg1 & PRFS_STOPTTERM)
357           fprintf (procfs_file ? procfs_file : stdout, "stopThreadTerm ");
358         if (arg1 & PRFS_KOLC)
359           fprintf (procfs_file ? procfs_file : stdout, "killOnLastClose ");
360         fprintf (procfs_file ? procfs_file : stdout, "\n");
361         break;
362 #endif /* PIOCSSPCACT */
363       default:
364         if (ioctl_table[i].name)
365           fprintf (procfs_file ? procfs_file : stdout, 
366                    "ioctl (%s) %s\n", 
367                    ioctl_table[i].name,
368                    info_verbose ? ioctl_table[i].desc : "");
369         else
370           fprintf (procfs_file ? procfs_file : stdout, 
371                    "ioctl (<unknown %ld (0x%lx)) \n", opcode, opcode);
372         break;
373       }
374       if (procfs_file)
375         fflush (procfs_file);
376     }
377   errno = 0;
378   ret = ioctl (fd, opcode, ptr);
379   if (procfs_trace && ret < 0)
380     {
381       fprintf (procfs_file ? procfs_file : stdout, 
382                "[ioctl (%s) FAILED! (%s)]\n",
383                ioctl_table[i].name != NULL ? 
384                ioctl_table[i].name : "<unknown>",
385                safe_strerror (errno));
386       if (procfs_file)
387         fflush (procfs_file);
388     }
389
390   return ret;
391 }
392
393 #else   /* NEW_PROC_API */
394
395 static struct trans rw_table[] = {
396 #ifdef PCAGENT                  /* solaris */
397   { PCAGENT,  "PCAGENT",  "create agent lwp with regs from argument" },
398 #endif
399   { PCCFAULT, "PCCFAULT", "clear current fault" },
400 #ifdef PCCSIG                   /* solaris */
401   { PCCSIG,   "PCCSIG",   "clear current signal" },
402 #endif
403 #ifdef PCDSTOP                  /* solaris */
404   { PCDSTOP,  "PCDSTOP",  "post stop request" },
405 #endif
406   { PCKILL,   "PCKILL",   "post a signal" },
407 #ifdef PCNICE                   /* solaris */
408   { PCNICE,   "PCNICE",   "set nice priority" },
409 #endif
410 #ifdef PCREAD                   /* solaris */
411   { PCREAD,   "PCREAD",   "read from the address space" },
412   { PCWRITE,  "PCWRITE",  "write to the address space" },
413 #endif
414 #ifdef PCRESET                  /* unixware */
415   { PCRESET,  "PCRESET",  "unset modes" },
416 #endif
417   { PCRUN,    "PCRUN",    "make process/lwp runnable" },
418 #ifdef PCSASRS                  /* solaris 2.7 only */
419   { PCSASRS,  "PCSASRS",  "set ancillary state registers" },
420 #endif
421 #ifdef PCSCRED                  /* solaris */
422   { PCSCRED,  "PCSCRED",  "set process credentials" },
423 #endif
424   { PCSENTRY, "PCSENTRY", "set traced syscall entry set" },
425   { PCSET,    "PCSET",    "set modes" },
426   { PCSEXIT,  "PCSEXIT",  "set traced syscall exit  set" },
427   { PCSFAULT, "PCSFAULT", "set traced fault set" },
428   { PCSFPREG, "PCSFPREG", "set floating point registers" },
429 #ifdef PCSHOLD                  /* solaris */
430   { PCSHOLD,  "PCSHOLD",  "set signal mask" },
431 #endif
432   { PCSREG,   "PCSREG",   "set general registers" },
433   { PCSSIG,   "PCSSIG",   "set current signal" },
434   { PCSTOP,   "PCSTOP",   "post stop request and wait" },
435   { PCSTRACE, "PCSTRACE", "set traced signal set" },
436 #ifdef PCSVADDR                 /* solaris */
437   { PCSVADDR, "PCSVADDR", "set pc virtual address" },
438 #endif
439 #ifdef PCSXREG                  /* solaris sparc only */
440   { PCSXREG,  "PCSXREG",  "set extra registers" },
441 #endif
442 #ifdef PCTWSTOP                 /* solaris */
443   { PCTWSTOP, "PCTWSTOP", "wait for stop, with timeout arg" },
444 #endif
445 #ifdef PCUNKILL                 /* solaris */
446   { PCUNKILL, "PCUNKILL", "delete a pending signal" },
447 #endif
448 #ifdef PCUNSET                  /* solaris */
449   { PCUNSET,  "PCUNSET",  "unset modes" },
450 #endif
451 #ifdef PCWATCH                  /* solaris */
452   { PCWATCH,  "PCWATCH",  "set/unset watched memory area" },
453 #endif
454   { PCWSTOP,  "PCWSTOP",  "wait for process/lwp to stop, no timeout" },
455   { 0,        NULL,      NULL }
456 };
457
458 static off_t lseek_offset;
459
460 int
461 write_with_trace (int fd, void *varg, size_t len, char *file, int line)
462 {
463   int i = ARRAY_SIZE (rw_table) - 1;
464   int ret;
465   procfs_ctl_t *arg = (procfs_ctl_t *) varg;
466
467   prepare_to_trace ();
468   if (procfs_trace)
469     {
470       procfs_ctl_t 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 #if PCRESET != PCUNSET
495       case PCRESET:
496 #endif
497 #endif
498         fprintf (procfs_file ? procfs_file : stdout, 
499                  "write (PCRESET, %s) %s\n", 
500                  arg[1] == PR_FORK  ? "PR_FORK"  :
501                  arg[1] == PR_RLC   ? "PR_RLC"   :
502 #ifdef PR_ASYNC
503                  arg[1] == PR_ASYNC ? "PR_ASYNC" :
504 #endif
505                  "<unknown flag>",
506                  info_verbose ? rw_table[i].desc : "");
507         break;
508       case PCSTRACE:
509         fprintf (procfs_file ? procfs_file : stdout, 
510                  "write (PCSTRACE) ");
511         proc_prettyfprint_signalset (procfs_file ? procfs_file : stdout,
512                                      (sigset_t *) &arg[1], 0);
513         break;
514       case PCSFAULT:
515         fprintf (procfs_file ? procfs_file : stdout, 
516                  "write (PCSFAULT) ");
517         proc_prettyfprint_faultset (procfs_file ? procfs_file : stdout,
518                                     (fltset_t *) &arg[1], 0);
519         break;
520       case PCSENTRY:
521         fprintf (procfs_file ? procfs_file : stdout, 
522                  "write (PCSENTRY) ");
523         proc_prettyfprint_syscalls (procfs_file ? procfs_file : stdout,
524                                     (sysset_t *) &arg[1], 0);
525         break;
526       case PCSEXIT:
527         fprintf (procfs_file ? procfs_file : stdout, 
528                  "write (PCSEXIT) ");
529         proc_prettyfprint_syscalls (procfs_file ? procfs_file : stdout,
530                                     (sysset_t *) &arg[1], 0);
531         break;
532 #ifdef PCSHOLD
533       case PCSHOLD:
534         fprintf (procfs_file ? procfs_file : stdout, 
535                  "write (PCSHOLD) ");
536         proc_prettyfprint_signalset (procfs_file ? procfs_file : stdout,
537                                      (sigset_t *) &arg[1], 0);
538         break;
539 #endif
540       case PCSSIG:
541         fprintf (procfs_file ? procfs_file : stdout, 
542                  "write (PCSSIG) ");
543         proc_prettyfprint_signal (procfs_file ? procfs_file : stdout,
544                                   arg[1] ? ((siginfo_t *) &arg[1])->si_signo 
545                                          : 0, 
546                                   0);
547         fprintf (procfs_file ? procfs_file : stdout, "\n");
548         break;
549       case PCRUN:
550         fprintf (procfs_file ? procfs_file : stdout, 
551                  "write (PCRUN) ");
552         if (arg[1] & PRCSIG)
553           fprintf (procfs_file ? procfs_file : stdout, "clearSig ");
554         if (arg[1] & PRCFAULT)
555           fprintf (procfs_file ? procfs_file : stdout, "clearFlt ");
556         if (arg[1] & PRSTEP)
557           fprintf (procfs_file ? procfs_file : stdout, "step ");
558 #ifdef PRSABORT
559         if (arg[1] & PRSABORT)
560           fprintf (procfs_file ? procfs_file : stdout, "syscallAbort ");
561 #endif
562 #ifdef PRSTOP
563         if (arg[1] & PRSTOP)
564           fprintf (procfs_file ? procfs_file : stdout, "stopReq ");
565 #endif
566           
567         fprintf (procfs_file ? procfs_file : stdout, "\n");
568         break;
569       case PCKILL:
570         fprintf (procfs_file ? procfs_file : stdout, 
571                  "write (PCKILL) ");
572         proc_prettyfprint_signal (procfs_file ? procfs_file : stdout,
573                                   arg[1], 0);
574         fprintf (procfs_file ? procfs_file : stdout, "\n");
575         break;
576       default:
577         {
578           if (rw_table[i].name)
579             fprintf (procfs_file ? procfs_file : stdout, 
580                      "write (%s) %s\n", 
581                      rw_table[i].name, 
582                      info_verbose ? rw_table[i].desc : "");
583           else
584             {
585               if (lseek_offset != -1)
586                 fprintf (procfs_file ? procfs_file : stdout, 
587                          "write (<unknown>, %lud bytes at 0x%08lx) \n", 
588                          (unsigned long) len, (unsigned long) lseek_offset);
589               else
590                 fprintf (procfs_file ? procfs_file : stdout, 
591                          "write (<unknown>, %lud bytes) \n", 
592                          (unsigned long) len);
593             }
594           break;
595         }
596       }
597       if (procfs_file)
598         fflush (procfs_file);
599     }
600   errno = 0;
601   ret = write (fd, (void *) arg, len);
602   if (procfs_trace && ret != len)
603     {
604       fprintf (procfs_file ? procfs_file : stdout, 
605                "[write (%s) FAILED! (%s)]\n",
606                rw_table[i].name != NULL ? 
607                rw_table[i].name : "<unknown>", 
608                safe_strerror (errno));
609       if (procfs_file)
610         fflush (procfs_file);
611     }
612
613   lseek_offset = -1;
614   return ret;
615 }
616
617 off_t
618 lseek_with_trace (int fd, off_t offset, int whence, char *file, int line)
619 {
620   off_t ret;
621
622   prepare_to_trace ();
623   errno = 0;
624   ret = lseek (fd, offset, whence);
625   lseek_offset = ret;
626   if (procfs_trace && (ret == -1 || errno != 0))
627     {
628       fprintf (procfs_file ? procfs_file : stdout, 
629                "[lseek (0x%08lx) FAILED! (%s)]\n", 
630                (unsigned long) offset, safe_strerror (errno));
631       if (procfs_file)
632         fflush (procfs_file);
633     }
634
635   return ret;
636 }
637
638 #endif /* NEW_PROC_API */
639
640 int
641 open_with_trace (char *filename, int mode, char *file, int line)
642 {
643   int ret;
644
645   prepare_to_trace ();
646   errno = 0;
647   ret = open (filename, mode);
648   if (procfs_trace)
649     {
650       if (info_verbose)
651         fprintf (procfs_file ? procfs_file : stdout, 
652                  "%s:%d -- ", file, line);
653
654       if (errno)
655         {
656           fprintf (procfs_file ? procfs_file : stdout, 
657                    "[open FAILED! (%s) line %d]\\n", 
658                    safe_strerror (errno), line);
659         }
660       else
661         {
662           fprintf (procfs_file ? procfs_file : stdout, 
663                    "%d = open (%s, ", ret, filename);
664           if (mode == O_RDONLY)
665             fprintf (procfs_file ? procfs_file : stdout, "O_RDONLY) %d\n",
666                      line);
667           else if (mode == O_WRONLY)
668             fprintf (procfs_file ? procfs_file : stdout, "O_WRONLY) %d\n",
669                      line);
670           else if (mode == O_RDWR)
671             fprintf (procfs_file ? procfs_file : stdout, "O_RDWR)   %d\n",
672                      line);
673         }
674       if (procfs_file)
675         fflush (procfs_file);
676     }
677
678   return ret;
679 }
680
681 int
682 close_with_trace (int fd, char *file, int line)
683 {
684   int ret;
685
686   prepare_to_trace ();
687   errno = 0;
688   ret = close (fd);
689   if (procfs_trace)
690     {
691       if (info_verbose)
692         fprintf (procfs_file ? procfs_file : stdout, 
693                  "%s:%d -- ", file, line);
694       if (errno)
695         fprintf (procfs_file ? procfs_file : stdout, 
696                  "[close FAILED! (%s)]\n", safe_strerror (errno));
697       else
698         fprintf (procfs_file ? procfs_file : stdout, 
699                  "%d = close (%d)\n", ret, fd);
700       if (procfs_file)
701         fflush (procfs_file);
702     }
703
704   return ret;
705 }
706
707 pid_t
708 wait_with_trace (int *wstat, char *file, int line)
709 {
710   int ret, lstat = 0;
711
712   prepare_to_trace ();
713   if (procfs_trace)
714     {
715       if (info_verbose)
716         fprintf (procfs_file ? procfs_file : stdout, 
717                  "%s:%d -- ", file, line);
718       fprintf (procfs_file ? procfs_file : stdout, 
719                "wait (line %d) ", line);
720       if (procfs_file)
721         fflush (procfs_file);
722     }
723   errno = 0;
724   ret = wait (&lstat);
725   if (procfs_trace)
726     {
727       if (errno)
728         fprintf (procfs_file ? procfs_file : stdout, 
729                  "[wait FAILED! (%s)]\n", safe_strerror (errno));
730       else
731         fprintf (procfs_file ? procfs_file : stdout, 
732                  "returned pid %d, status 0x%x\n", ret, lstat);
733       if (procfs_file)
734         fflush (procfs_file);
735     }
736   if (wstat)
737     *wstat = lstat;
738
739   return ret;
740 }
741
742 void
743 procfs_note (char *msg, char *file, int line)
744 {
745   prepare_to_trace ();
746   if (procfs_trace)
747     {
748       if (info_verbose)
749         fprintf (procfs_file ? procfs_file : stdout, 
750                  "%s:%d -- ", file, line);
751       fprintf (procfs_file ? procfs_file : stdout, "%s", msg);
752       if (procfs_file)
753         fflush (procfs_file);
754     }
755 }
756
757 void
758 proc_prettyfprint_status (long flags, int why, int what, int thread)
759 {
760   prepare_to_trace ();
761   if (procfs_trace)
762     {
763       if (thread)
764         fprintf (procfs_file ? procfs_file : stdout,
765                  "Thread %d: ", thread);
766
767       proc_prettyfprint_flags (procfs_file ? procfs_file : stdout, 
768                                flags, 0);
769
770       if (flags & (PR_STOPPED | PR_ISTOP))
771         proc_prettyfprint_why (procfs_file ? procfs_file : stdout, 
772                                why, what, 0);
773       if (procfs_file)
774         fflush (procfs_file);
775     }
776 }
777
778
779 void
780 _initialize_proc_api (void)
781 {
782   struct cmd_list_element *c;
783
784   add_setshow_boolean_cmd ("procfs-trace", no_class, &procfs_trace, _("\
785 Set tracing for /proc api calls."), _("\
786 Show tracing for /proc api calls."), NULL,
787                            set_procfs_trace_cmd,
788                            NULL, /* FIXME: i18n: */
789                            &setlist, &showlist);
790
791   add_setshow_filename_cmd ("procfs-file", no_class, &procfs_filename, _("\
792 Set filename for /proc tracefile."), _("\
793 Show filename for /proc tracefile."), NULL,
794                             set_procfs_file_cmd,
795                             NULL, /* FIXME: i18n: */
796                             &setlist, &showlist);
797 }