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