gdb: add target_ops::supports_displaced_step
[deliverable/binutils-gdb.git] / gdb / proc-api.c
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 #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 "gdbsupport/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 bool procfs_trace = false;
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 _initialize_proc_api ();
420 void
421 _initialize_proc_api ()
422 {
423 add_setshow_boolean_cmd ("procfs-trace", no_class, &procfs_trace, _("\
424 Set tracing for /proc api calls."), _("\
425 Show tracing for /proc api calls."), NULL,
426 set_procfs_trace_cmd,
427 NULL, /* FIXME: i18n: */
428 &setlist, &showlist);
429
430 procfs_filename = xstrdup ("procfs_trace");
431 add_setshow_filename_cmd ("procfs-file", no_class, &procfs_filename, _("\
432 Set filename for /proc tracefile."), _("\
433 Show filename for /proc tracefile."), NULL,
434 set_procfs_file_cmd,
435 NULL, /* FIXME: i18n: */
436 &setlist, &showlist);
437 }
This page took 0.039276 seconds and 4 git commands to generate.