xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/proc-api.c (revision 53b02e147d4ed531c0d2a5ca9b3e8026ba3e99b5)
1 /* Machine independent support for Solaris /proc (process file system) for GDB.
2 
3    Copyright (C) 1999-2019 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  */
26 
27 #include "defs.h"
28 #include "gdbcmd.h"
29 #include "completer.h"
30 
31 #define _STRUCTURED_PROC 1
32 
33 #include <sys/types.h>
34 #include <sys/procfs.h>
35 #include <sys/proc.h>	/* for struct proc */
36 #include <sys/user.h>	/* for struct user */
37 #include <fcntl.h>	/* for O_RDWR etc.  */
38 #include "common/gdb_wait.h"
39 
40 #include "proc-utils.h"
41 
42 /*  Much of the information used in the /proc interface, particularly for
43     printing status information, is kept as tables of structures of the
44     following form.  These tables can be used to map numeric values to
45     their symbolic names and to a string that describes their specific use.  */
46 
47 struct trans {
48   long value;                   /* The numeric value */
49   const char *name;             /* The equivalent symbolic value */
50   const char *desc;             /* Short description of value */
51 };
52 
53 static int   procfs_trace    = 0;
54 static FILE *procfs_file     = NULL;
55 static char *procfs_filename;
56 
57 static void
58 prepare_to_trace (void)
59 {
60   if (procfs_trace)			/* if procfs tracing turned on */
61     if (procfs_file == NULL)		/* if output file not yet open */
62       procfs_file = fopen (procfs_filename, "a");	/* open output file */
63 }
64 
65 static void
66 set_procfs_trace_cmd (const char *args,
67 		      int from_tty, struct cmd_list_element *c)
68 {
69 #if 0	/* not sure what I might actually need to do here, if anything */
70   if (procfs_file)
71     fflush (procfs_file);
72 #endif
73 }
74 
75 static void
76 set_procfs_file_cmd (const char *args,
77 		     int from_tty, struct cmd_list_element *c)
78 {
79   /* Just changed the filename for procfs tracing.
80      If a file was already open, close it.  */
81   if (procfs_file)
82     fclose (procfs_file);
83   procfs_file = NULL;
84 }
85 
86 static struct trans rw_table[] = {
87   { PCAGENT,  "PCAGENT",  "create agent lwp with regs from argument" },
88   { PCCFAULT, "PCCFAULT", "clear current fault" },
89   { PCCSIG,   "PCCSIG",   "clear current signal" },
90   { PCDSTOP,  "PCDSTOP",  "post stop request" },
91   { PCKILL,   "PCKILL",   "post a signal" },
92   { PCNICE,   "PCNICE",   "set nice priority" },
93   { PCREAD,   "PCREAD",   "read from the address space" },
94   { PCWRITE,  "PCWRITE",  "write to the address space" },
95   { PCRUN,    "PCRUN",    "make process/lwp runnable" },
96   { PCSASRS,  "PCSASRS",  "set ancillary state registers" },
97   { PCSCRED,  "PCSCRED",  "set process credentials" },
98   { PCSENTRY, "PCSENTRY", "set traced syscall entry set" },
99   { PCSET,    "PCSET",    "set modes" },
100   { PCSEXIT,  "PCSEXIT",  "set traced syscall exit  set" },
101   { PCSFAULT, "PCSFAULT", "set traced fault set" },
102   { PCSFPREG, "PCSFPREG", "set floating point registers" },
103   { PCSHOLD,  "PCSHOLD",  "set signal mask" },
104   { PCSREG,   "PCSREG",   "set general registers" },
105   { PCSSIG,   "PCSSIG",   "set current signal" },
106   { PCSTOP,   "PCSTOP",   "post stop request and wait" },
107   { PCSTRACE, "PCSTRACE", "set traced signal set" },
108   { PCSVADDR, "PCSVADDR", "set pc virtual address" },
109   { PCSXREG,  "PCSXREG",  "set extra registers" },
110   { PCTWSTOP, "PCTWSTOP", "wait for stop, with timeout arg" },
111   { PCUNKILL, "PCUNKILL", "delete a pending signal" },
112   { PCUNSET,  "PCUNSET",  "unset modes" },
113   { PCWATCH,  "PCWATCH",  "set/unset watched memory area" },
114   { PCWSTOP,  "PCWSTOP",  "wait for process/lwp to stop, no timeout" },
115   { 0,        NULL,      NULL }
116 };
117 
118 static off_t lseek_offset;
119 
120 int
121 write_with_trace (int fd, void *varg, size_t len, char *file, int line)
122 {
123   int i = ARRAY_SIZE (rw_table) - 1;
124   int ret;
125   procfs_ctl_t *arg = (procfs_ctl_t *) varg;
126 
127   prepare_to_trace ();
128   if (procfs_trace)
129     {
130       procfs_ctl_t opcode = arg[0];
131       for (i = 0; rw_table[i].name != NULL; i++)
132 	if (rw_table[i].value == opcode)
133 	  break;
134 
135       if (info_verbose)
136 	fprintf (procfs_file ? procfs_file : stdout,
137 		 "%s:%d -- ", file, line);
138       switch (opcode) {
139       case PCSET:
140 	fprintf (procfs_file ? procfs_file : stdout,
141 		 "write (PCSET,   %s) %s\n",
142 		 arg[1] == PR_FORK  ? "PR_FORK"  :
143 		 arg[1] == PR_RLC   ? "PR_RLC"   :
144 		 arg[1] == PR_ASYNC ? "PR_ASYNC" :
145 		 "<unknown flag>",
146 		 info_verbose ? rw_table[i].desc : "");
147 	break;
148       case PCUNSET:
149 	fprintf (procfs_file ? procfs_file : stdout,
150 		 "write (PCRESET, %s) %s\n",
151 		 arg[1] == PR_FORK  ? "PR_FORK"  :
152 		 arg[1] == PR_RLC   ? "PR_RLC"   :
153 		 arg[1] == PR_ASYNC ? "PR_ASYNC" :
154 		 "<unknown flag>",
155 		 info_verbose ? rw_table[i].desc : "");
156 	break;
157       case PCSTRACE:
158 	fprintf (procfs_file ? procfs_file : stdout,
159 		 "write (PCSTRACE) ");
160 	proc_prettyfprint_signalset (procfs_file ? procfs_file : stdout,
161 				     (sigset_t *) &arg[1], 0);
162 	break;
163       case PCSFAULT:
164 	fprintf (procfs_file ? procfs_file : stdout,
165 		 "write (PCSFAULT) ");
166 	proc_prettyfprint_faultset (procfs_file ? procfs_file : stdout,
167 				    (fltset_t *) &arg[1], 0);
168 	break;
169       case PCSENTRY:
170 	fprintf (procfs_file ? procfs_file : stdout,
171 		 "write (PCSENTRY) ");
172 	proc_prettyfprint_syscalls (procfs_file ? procfs_file : stdout,
173 				    (sysset_t *) &arg[1], 0);
174 	break;
175       case PCSEXIT:
176 	fprintf (procfs_file ? procfs_file : stdout,
177 		 "write (PCSEXIT) ");
178 	proc_prettyfprint_syscalls (procfs_file ? procfs_file : stdout,
179 				    (sysset_t *) &arg[1], 0);
180 	break;
181       case PCSHOLD:
182 	fprintf (procfs_file ? procfs_file : stdout,
183 		 "write (PCSHOLD) ");
184 	proc_prettyfprint_signalset (procfs_file ? procfs_file : stdout,
185 				     (sigset_t *) &arg[1], 0);
186 	break;
187       case PCSSIG:
188 	fprintf (procfs_file ? procfs_file : stdout,
189 		 "write (PCSSIG) ");
190 	proc_prettyfprint_signal (procfs_file ? procfs_file : stdout,
191 				  arg[1] ? ((siginfo_t *) &arg[1])->si_signo
192 				         : 0,
193 				  0);
194 	fprintf (procfs_file ? procfs_file : stdout, "\n");
195 	break;
196       case PCRUN:
197 	fprintf (procfs_file ? procfs_file : stdout,
198 		 "write (PCRUN) ");
199 	if (arg[1] & PRCSIG)
200 	  fprintf (procfs_file ? procfs_file : stdout, "clearSig ");
201 	if (arg[1] & PRCFAULT)
202 	  fprintf (procfs_file ? procfs_file : stdout, "clearFlt ");
203 	if (arg[1] & PRSTEP)
204 	  fprintf (procfs_file ? procfs_file : stdout, "step ");
205 	if (arg[1] & PRSABORT)
206 	  fprintf (procfs_file ? procfs_file : stdout, "syscallAbort ");
207 	if (arg[1] & PRSTOP)
208 	  fprintf (procfs_file ? procfs_file : stdout, "stopReq ");
209 
210 	fprintf (procfs_file ? procfs_file : stdout, "\n");
211 	break;
212       case PCKILL:
213 	fprintf (procfs_file ? procfs_file : stdout,
214 		 "write (PCKILL) ");
215 	proc_prettyfprint_signal (procfs_file ? procfs_file : stdout,
216 				  arg[1], 0);
217 	fprintf (procfs_file ? procfs_file : stdout, "\n");
218 	break;
219       default:
220 	{
221 	  if (rw_table[i].name)
222 	    fprintf (procfs_file ? procfs_file : stdout,
223 		     "write (%s) %s\n",
224 		     rw_table[i].name,
225 		     info_verbose ? rw_table[i].desc : "");
226 	  else
227 	    {
228 	      if (lseek_offset != -1)
229 		fprintf (procfs_file ? procfs_file : stdout,
230 			 "write (<unknown>, %lud bytes at 0x%08lx) \n",
231 			 (unsigned long) len, (unsigned long) lseek_offset);
232 	      else
233 		fprintf (procfs_file ? procfs_file : stdout,
234 			 "write (<unknown>, %lud bytes) \n",
235 			 (unsigned long) len);
236 	    }
237 	  break;
238 	}
239       }
240       if (procfs_file)
241 	fflush (procfs_file);
242     }
243   errno = 0;
244   ret = write (fd, (void *) arg, len);
245   if (procfs_trace && ret != len)
246     {
247       fprintf (procfs_file ? procfs_file : stdout,
248 	       "[write (%s) FAILED! (%s)]\n",
249 	       rw_table[i].name != NULL ?
250 	       rw_table[i].name : "<unknown>",
251 	       safe_strerror (errno));
252       if (procfs_file)
253 	fflush (procfs_file);
254     }
255 
256   lseek_offset = -1;
257   return ret;
258 }
259 
260 off_t
261 lseek_with_trace (int fd, off_t offset, int whence, char *file, int line)
262 {
263   off_t ret;
264 
265   prepare_to_trace ();
266   errno = 0;
267   ret = lseek (fd, offset, whence);
268   lseek_offset = ret;
269   if (procfs_trace && (ret == -1 || errno != 0))
270     {
271       fprintf (procfs_file ? procfs_file : stdout,
272 	       "[lseek (0x%08lx) FAILED! (%s)]\n",
273 	       (unsigned long) offset, safe_strerror (errno));
274       if (procfs_file)
275 	fflush (procfs_file);
276     }
277 
278   return ret;
279 }
280 
281 int
282 open_with_trace (char *filename, int mode, char *file, int line)
283 {
284   int ret;
285 
286   prepare_to_trace ();
287   errno = 0;
288   ret = open (filename, mode);
289   if (procfs_trace)
290     {
291       if (info_verbose)
292 	fprintf (procfs_file ? procfs_file : stdout,
293 		 "%s:%d -- ", file, line);
294 
295       if (errno)
296 	{
297 	  fprintf (procfs_file ? procfs_file : stdout,
298 		   "[open FAILED! (%s) line %d]\\n",
299 		   safe_strerror (errno), line);
300 	}
301       else
302 	{
303 	  fprintf (procfs_file ? procfs_file : stdout,
304 		   "%d = open (%s, ", ret, filename);
305 	  if (mode == O_RDONLY)
306 	    fprintf (procfs_file ? procfs_file : stdout, "O_RDONLY) %d\n",
307 		     line);
308 	  else if (mode == O_WRONLY)
309 	    fprintf (procfs_file ? procfs_file : stdout, "O_WRONLY) %d\n",
310 		     line);
311 	  else if (mode == O_RDWR)
312 	    fprintf (procfs_file ? procfs_file : stdout, "O_RDWR)   %d\n",
313 		     line);
314 	}
315       if (procfs_file)
316 	fflush (procfs_file);
317     }
318 
319   return ret;
320 }
321 
322 int
323 close_with_trace (int fd, char *file, int line)
324 {
325   int ret;
326 
327   prepare_to_trace ();
328   errno = 0;
329   ret = close (fd);
330   if (procfs_trace)
331     {
332       if (info_verbose)
333 	fprintf (procfs_file ? procfs_file : stdout,
334 		 "%s:%d -- ", file, line);
335       if (errno)
336 	fprintf (procfs_file ? procfs_file : stdout,
337 		 "[close FAILED! (%s)]\n", safe_strerror (errno));
338       else
339 	fprintf (procfs_file ? procfs_file : stdout,
340 		 "%d = close (%d)\n", ret, fd);
341       if (procfs_file)
342 	fflush (procfs_file);
343     }
344 
345   return ret;
346 }
347 
348 pid_t
349 wait_with_trace (int *wstat, char *file, int line)
350 {
351   int ret, lstat = 0;
352 
353   prepare_to_trace ();
354   if (procfs_trace)
355     {
356       if (info_verbose)
357 	fprintf (procfs_file ? procfs_file : stdout,
358 		 "%s:%d -- ", file, line);
359       fprintf (procfs_file ? procfs_file : stdout,
360 	       "wait (line %d) ", line);
361       if (procfs_file)
362 	fflush (procfs_file);
363     }
364   errno = 0;
365   ret = wait (&lstat);
366   if (procfs_trace)
367     {
368       if (errno)
369 	fprintf (procfs_file ? procfs_file : stdout,
370 		 "[wait FAILED! (%s)]\n", safe_strerror (errno));
371       else
372 	fprintf (procfs_file ? procfs_file : stdout,
373 		 "returned pid %d, status 0x%x\n", ret, lstat);
374       if (procfs_file)
375 	fflush (procfs_file);
376     }
377   if (wstat)
378     *wstat = lstat;
379 
380   return ret;
381 }
382 
383 void
384 procfs_note (const char *msg, const char *file, int line)
385 {
386   prepare_to_trace ();
387   if (procfs_trace)
388     {
389       if (info_verbose)
390 	fprintf (procfs_file ? procfs_file : stdout,
391 		 "%s:%d -- ", file, line);
392       fprintf (procfs_file ? procfs_file : stdout, "%s", msg);
393       if (procfs_file)
394 	fflush (procfs_file);
395     }
396 }
397 
398 void
399 proc_prettyfprint_status (long flags, int why, int what, int thread)
400 {
401   prepare_to_trace ();
402   if (procfs_trace)
403     {
404       if (thread)
405 	fprintf (procfs_file ? procfs_file : stdout,
406 		 "Thread %d: ", thread);
407 
408       proc_prettyfprint_flags (procfs_file ? procfs_file : stdout,
409 			       flags, 0);
410 
411       if (flags & (PR_STOPPED | PR_ISTOP))
412 	proc_prettyfprint_why (procfs_file ? procfs_file : stdout,
413 			       why, what, 0);
414       if (procfs_file)
415 	fflush (procfs_file);
416     }
417 }
418 
419 void
420 _initialize_proc_api (void)
421 {
422   add_setshow_boolean_cmd ("procfs-trace", no_class, &procfs_trace, _("\
423 Set tracing for /proc api calls."), _("\
424 Show tracing for /proc api calls."), NULL,
425 			   set_procfs_trace_cmd,
426 			   NULL, /* FIXME: i18n: */
427 			   &setlist, &showlist);
428 
429   procfs_filename = xstrdup ("procfs_trace");
430   add_setshow_filename_cmd ("procfs-file", no_class, &procfs_filename, _("\
431 Set filename for /proc tracefile."), _("\
432 Show filename for /proc tracefile."), NULL,
433 			    set_procfs_file_cmd,
434 			    NULL, /* FIXME: i18n: */
435 			    &setlist, &showlist);
436 }
437