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