123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434 |
- /* Machine independent support for Solaris /proc (process file system) for GDB.
- Copyright (C) 1999-2022 Free Software Foundation, Inc.
- Written by Michael Snyder at Cygnus Solutions.
- Based on work by Fred Fish, Stu Grossman, Geoff Noer, and others.
- This file is part of GDB.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
- /*
- * Pretty-print trace of api calls to the /proc api
- */
- #include "defs.h"
- #include "gdbcmd.h"
- #include "completer.h"
- #include <sys/types.h>
- #include <sys/procfs.h>
- #include <sys/proc.h> /* for struct proc */
- #include <sys/user.h> /* for struct user */
- #include <fcntl.h> /* for O_RDWR etc. */
- #include "gdbsupport/gdb_wait.h"
- #include "proc-utils.h"
- /* Much of the information used in the /proc interface, particularly for
- printing status information, is kept as tables of structures of the
- following form. These tables can be used to map numeric values to
- their symbolic names and to a string that describes their specific use. */
- struct trans {
- long value; /* The numeric value */
- const char *name; /* The equivalent symbolic value */
- const char *desc; /* Short description of value */
- };
- static bool procfs_trace = false;
- static FILE *procfs_file = NULL;
- static std::string procfs_filename = "procfs_trace";
- static void
- prepare_to_trace (void)
- {
- if (procfs_trace) /* if procfs tracing turned on */
- if (procfs_file == NULL) /* if output file not yet open */
- procfs_file = fopen (procfs_filename.c_str (), "a"); /* open output file */
- }
- static void
- set_procfs_trace_cmd (const char *args,
- int from_tty, struct cmd_list_element *c)
- {
- #if 0 /* not sure what I might actually need to do here, if anything */
- if (procfs_file)
- fflush (procfs_file);
- #endif
- }
- static void
- set_procfs_file_cmd (const char *args,
- int from_tty, struct cmd_list_element *c)
- {
- /* Just changed the filename for procfs tracing.
- If a file was already open, close it. */
- if (procfs_file)
- fclose (procfs_file);
- procfs_file = NULL;
- }
- static struct trans rw_table[] = {
- { PCAGENT, "PCAGENT", "create agent lwp with regs from argument" },
- { PCCFAULT, "PCCFAULT", "clear current fault" },
- { PCCSIG, "PCCSIG", "clear current signal" },
- { PCDSTOP, "PCDSTOP", "post stop request" },
- { PCKILL, "PCKILL", "post a signal" },
- { PCNICE, "PCNICE", "set nice priority" },
- { PCREAD, "PCREAD", "read from the address space" },
- { PCWRITE, "PCWRITE", "write to the address space" },
- { PCRUN, "PCRUN", "make process/lwp runnable" },
- { PCSASRS, "PCSASRS", "set ancillary state registers" },
- { PCSCRED, "PCSCRED", "set process credentials" },
- { PCSENTRY, "PCSENTRY", "set traced syscall entry set" },
- { PCSET, "PCSET", "set modes" },
- { PCSEXIT, "PCSEXIT", "set traced syscall exit set" },
- { PCSFAULT, "PCSFAULT", "set traced fault set" },
- { PCSFPREG, "PCSFPREG", "set floating point registers" },
- { PCSHOLD, "PCSHOLD", "set signal mask" },
- { PCSREG, "PCSREG", "set general registers" },
- { PCSSIG, "PCSSIG", "set current signal" },
- { PCSTOP, "PCSTOP", "post stop request and wait" },
- { PCSTRACE, "PCSTRACE", "set traced signal set" },
- { PCSVADDR, "PCSVADDR", "set pc virtual address" },
- { PCSXREG, "PCSXREG", "set extra registers" },
- { PCTWSTOP, "PCTWSTOP", "wait for stop, with timeout arg" },
- { PCUNKILL, "PCUNKILL", "delete a pending signal" },
- { PCUNSET, "PCUNSET", "unset modes" },
- { PCWATCH, "PCWATCH", "set/unset watched memory area" },
- { PCWSTOP, "PCWSTOP", "wait for process/lwp to stop, no timeout" },
- { 0, NULL, NULL }
- };
- static off_t lseek_offset;
- int
- write_with_trace (int fd, void *varg, size_t len, char *file, int line)
- {
- int i = ARRAY_SIZE (rw_table) - 1;
- int ret;
- procfs_ctl_t *arg = (procfs_ctl_t *) varg;
- prepare_to_trace ();
- if (procfs_trace)
- {
- procfs_ctl_t opcode = arg[0];
- for (i = 0; rw_table[i].name != NULL; i++)
- if (rw_table[i].value == opcode)
- break;
- if (info_verbose)
- fprintf (procfs_file ? procfs_file : stdout,
- "%s:%d -- ", file, line);
- switch (opcode) {
- case PCSET:
- fprintf (procfs_file ? procfs_file : stdout,
- "write (PCSET, %s) %s\n",
- arg[1] == PR_FORK ? "PR_FORK" :
- arg[1] == PR_RLC ? "PR_RLC" :
- arg[1] == PR_ASYNC ? "PR_ASYNC" :
- "<unknown flag>",
- info_verbose ? rw_table[i].desc : "");
- break;
- case PCUNSET:
- fprintf (procfs_file ? procfs_file : stdout,
- "write (PCRESET, %s) %s\n",
- arg[1] == PR_FORK ? "PR_FORK" :
- arg[1] == PR_RLC ? "PR_RLC" :
- arg[1] == PR_ASYNC ? "PR_ASYNC" :
- "<unknown flag>",
- info_verbose ? rw_table[i].desc : "");
- break;
- case PCSTRACE:
- fprintf (procfs_file ? procfs_file : stdout,
- "write (PCSTRACE) ");
- proc_prettyfprint_signalset (procfs_file ? procfs_file : stdout,
- (sigset_t *) &arg[1], 0);
- break;
- case PCSFAULT:
- fprintf (procfs_file ? procfs_file : stdout,
- "write (PCSFAULT) ");
- proc_prettyfprint_faultset (procfs_file ? procfs_file : stdout,
- (fltset_t *) &arg[1], 0);
- break;
- case PCSENTRY:
- fprintf (procfs_file ? procfs_file : stdout,
- "write (PCSENTRY) ");
- proc_prettyfprint_syscalls (procfs_file ? procfs_file : stdout,
- (sysset_t *) &arg[1], 0);
- break;
- case PCSEXIT:
- fprintf (procfs_file ? procfs_file : stdout,
- "write (PCSEXIT) ");
- proc_prettyfprint_syscalls (procfs_file ? procfs_file : stdout,
- (sysset_t *) &arg[1], 0);
- break;
- case PCSHOLD:
- fprintf (procfs_file ? procfs_file : stdout,
- "write (PCSHOLD) ");
- proc_prettyfprint_signalset (procfs_file ? procfs_file : stdout,
- (sigset_t *) &arg[1], 0);
- break;
- case PCSSIG:
- fprintf (procfs_file ? procfs_file : stdout,
- "write (PCSSIG) ");
- proc_prettyfprint_signal (procfs_file ? procfs_file : stdout,
- arg[1] ? ((siginfo_t *) &arg[1])->si_signo
- : 0,
- 0);
- fprintf (procfs_file ? procfs_file : stdout, "\n");
- break;
- case PCRUN:
- fprintf (procfs_file ? procfs_file : stdout,
- "write (PCRUN) ");
- if (arg[1] & PRCSIG)
- fprintf (procfs_file ? procfs_file : stdout, "clearSig ");
- if (arg[1] & PRCFAULT)
- fprintf (procfs_file ? procfs_file : stdout, "clearFlt ");
- if (arg[1] & PRSTEP)
- fprintf (procfs_file ? procfs_file : stdout, "step ");
- if (arg[1] & PRSABORT)
- fprintf (procfs_file ? procfs_file : stdout, "syscallAbort ");
- if (arg[1] & PRSTOP)
- fprintf (procfs_file ? procfs_file : stdout, "stopReq ");
-
- fprintf (procfs_file ? procfs_file : stdout, "\n");
- break;
- case PCKILL:
- fprintf (procfs_file ? procfs_file : stdout,
- "write (PCKILL) ");
- proc_prettyfprint_signal (procfs_file ? procfs_file : stdout,
- arg[1], 0);
- fprintf (procfs_file ? procfs_file : stdout, "\n");
- break;
- default:
- {
- if (rw_table[i].name)
- fprintf (procfs_file ? procfs_file : stdout,
- "write (%s) %s\n",
- rw_table[i].name,
- info_verbose ? rw_table[i].desc : "");
- else
- {
- if (lseek_offset != -1)
- fprintf (procfs_file ? procfs_file : stdout,
- "write (<unknown>, %lud bytes at 0x%08lx) \n",
- (unsigned long) len, (unsigned long) lseek_offset);
- else
- fprintf (procfs_file ? procfs_file : stdout,
- "write (<unknown>, %lud bytes) \n",
- (unsigned long) len);
- }
- break;
- }
- }
- if (procfs_file)
- fflush (procfs_file);
- }
- errno = 0;
- ret = write (fd, (void *) arg, len);
- if (procfs_trace && ret != len)
- {
- fprintf (procfs_file ? procfs_file : stdout,
- "[write (%s) FAILED! (%s)]\n",
- rw_table[i].name != NULL ?
- rw_table[i].name : "<unknown>",
- safe_strerror (errno));
- if (procfs_file)
- fflush (procfs_file);
- }
- lseek_offset = -1;
- return ret;
- }
- off_t
- lseek_with_trace (int fd, off_t offset, int whence, char *file, int line)
- {
- off_t ret;
- prepare_to_trace ();
- errno = 0;
- ret = lseek (fd, offset, whence);
- lseek_offset = ret;
- if (procfs_trace && (ret == -1 || errno != 0))
- {
- fprintf (procfs_file ? procfs_file : stdout,
- "[lseek (0x%08lx) FAILED! (%s)]\n",
- (unsigned long) offset, safe_strerror (errno));
- if (procfs_file)
- fflush (procfs_file);
- }
- return ret;
- }
- int
- open_with_trace (char *filename, int mode, char *file, int line)
- {
- int ret;
- prepare_to_trace ();
- errno = 0;
- ret = open (filename, mode);
- if (procfs_trace)
- {
- if (info_verbose)
- fprintf (procfs_file ? procfs_file : stdout,
- "%s:%d -- ", file, line);
- if (errno)
- {
- fprintf (procfs_file ? procfs_file : stdout,
- "[open FAILED! (%s) line %d]\\n",
- safe_strerror (errno), line);
- }
- else
- {
- fprintf (procfs_file ? procfs_file : stdout,
- "%d = open (%s, ", ret, filename);
- if (mode == O_RDONLY)
- fprintf (procfs_file ? procfs_file : stdout, "O_RDONLY) %d\n",
- line);
- else if (mode == O_WRONLY)
- fprintf (procfs_file ? procfs_file : stdout, "O_WRONLY) %d\n",
- line);
- else if (mode == O_RDWR)
- fprintf (procfs_file ? procfs_file : stdout, "O_RDWR) %d\n",
- line);
- }
- if (procfs_file)
- fflush (procfs_file);
- }
- return ret;
- }
- int
- close_with_trace (int fd, char *file, int line)
- {
- int ret;
- prepare_to_trace ();
- errno = 0;
- ret = close (fd);
- if (procfs_trace)
- {
- if (info_verbose)
- fprintf (procfs_file ? procfs_file : stdout,
- "%s:%d -- ", file, line);
- if (errno)
- fprintf (procfs_file ? procfs_file : stdout,
- "[close FAILED! (%s)]\n", safe_strerror (errno));
- else
- fprintf (procfs_file ? procfs_file : stdout,
- "%d = close (%d)\n", ret, fd);
- if (procfs_file)
- fflush (procfs_file);
- }
- return ret;
- }
- pid_t
- wait_with_trace (int *wstat, char *file, int line)
- {
- int ret, lstat = 0;
- prepare_to_trace ();
- if (procfs_trace)
- {
- if (info_verbose)
- fprintf (procfs_file ? procfs_file : stdout,
- "%s:%d -- ", file, line);
- fprintf (procfs_file ? procfs_file : stdout,
- "wait (line %d) ", line);
- if (procfs_file)
- fflush (procfs_file);
- }
- errno = 0;
- ret = wait (&lstat);
- if (procfs_trace)
- {
- if (errno)
- fprintf (procfs_file ? procfs_file : stdout,
- "[wait FAILED! (%s)]\n", safe_strerror (errno));
- else
- fprintf (procfs_file ? procfs_file : stdout,
- "returned pid %d, status 0x%x\n", ret, lstat);
- if (procfs_file)
- fflush (procfs_file);
- }
- if (wstat)
- *wstat = lstat;
- return ret;
- }
- void
- procfs_note (const char *msg, const char *file, int line)
- {
- prepare_to_trace ();
- if (procfs_trace)
- {
- if (info_verbose)
- fprintf (procfs_file ? procfs_file : stdout,
- "%s:%d -- ", file, line);
- fprintf (procfs_file ? procfs_file : stdout, "%s", msg);
- if (procfs_file)
- fflush (procfs_file);
- }
- }
- void
- proc_prettyfprint_status (long flags, int why, int what, int thread)
- {
- prepare_to_trace ();
- if (procfs_trace)
- {
- if (thread)
- fprintf (procfs_file ? procfs_file : stdout,
- "Thread %d: ", thread);
- proc_prettyfprint_flags (procfs_file ? procfs_file : stdout,
- flags, 0);
- if (flags & (PR_STOPPED | PR_ISTOP))
- proc_prettyfprint_why (procfs_file ? procfs_file : stdout,
- why, what, 0);
- if (procfs_file)
- fflush (procfs_file);
- }
- }
- void _initialize_proc_api ();
- void
- _initialize_proc_api ()
- {
- add_setshow_boolean_cmd ("procfs-trace", no_class, &procfs_trace, _("\
- Set tracing for /proc api calls."), _("\
- Show tracing for /proc api calls."), NULL,
- set_procfs_trace_cmd,
- NULL, /* FIXME: i18n: */
- &setlist, &showlist);
- add_setshow_filename_cmd ("procfs-file", no_class, &procfs_filename, _("\
- Set filename for /proc tracefile."), _("\
- Show filename for /proc tracefile."), NULL,
- set_procfs_file_cmd,
- NULL, /* FIXME: i18n: */
- &setlist, &showlist);
- }
|