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