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