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