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