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