xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/proc-api.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /* Machine independent support for SVR4 /proc (process file system) for GDB.
2 
3    Copyright (C) 1999-2016 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 }
795