xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/proc-api.c (revision 7330f729ccf0bd976a06f95fad452fe774fc7fd1)
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 }
795