Avoid a crash in source_cache::extract_lines
[external/binutils.git] / gdb / proc-api.c
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 }