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