📄 procfs.c
字号:
inferior_pid = pid; push_target (&procfs_ops);}/* Take a program previously attached to and detaches it. The program resumes execution and will no longer stop on signals, etc. We'd better not have left any breakpoints in the program or it'll die when it hits one. For this to work, it may be necessary for the process to have been previously attached. It *might* work if the program was started via the normal ptrace (PTRACE_TRACEME). */static voidprocfs_detach (args, from_tty) char *args; int from_tty;{ int siggnal = 0; if (from_tty) { char *exec_file = get_exec_file (0); if (exec_file == 0) exec_file = ""; printf ("Detaching program: %s pid %d\n", exec_file, inferior_pid); fflush (stdout); } if (args) siggnal = atoi (args); do_detach (siggnal); inferior_pid = 0; unpush_target (&procfs_ops); /* Pop out of handling an inferior */}/* Get ready to modify the registers array. On machines which store individual registers, this doesn't need to do anything. On machines which store all the registers in one fell swoop, this makes sure that registers contains all the registers from the program being debugged. */static voidprocfs_prepare_to_store (){#ifdef CHILD_PREPARE_TO_STORE CHILD_PREPARE_TO_STORE ();#endif}/* Print status information about what we're accessing. */static voidprocfs_files_info (ignore) struct target_ops *ignore;{ printf ("\tUsing the running image of %s process %d via /proc.\n", attach_flag? "attached": "child", inferior_pid);}/* ARGSUSED */static voidprocfs_open (arg, from_tty) char *arg; int from_tty;{ error ("Use the \"run\" command to start a Unix child process.");}/*LOCAL FUNCTION do_attach -- attach to an already existing processSYNOPSIS int do_attach (int pid)DESCRIPTION Attach to an already existing process with the specified process id. If the process is not already stopped, query whether to stop it or not.NOTES The option of stopping at attach time is specific to the /proc versions of gdb. Versions using ptrace force the attachee to stop. (I have changed this version to do so, too. All you have to do is "continue" to make it go on. -- gnu@cygnus.com)*/static intdo_attach (pid) int pid;{ int result; if (!open_proc_file (pid, &pi, O_RDWR)) { perror_with_name (pi.pathname); /* NOTREACHED */ } /* Get current status of process and if it is not already stopped, then stop it. Remember whether or not it was stopped when we first examined it. */ if (ioctl (pi.fd, PIOCSTATUS, &pi.prstatus) < 0) { print_sys_errmsg (pi.pathname, errno); close_proc_file (&pi); error ("PIOCSTATUS failed"); } if (pi.prstatus.pr_flags & (PR_STOPPED | PR_ISTOP)) { pi.was_stopped = 1; } else { pi.was_stopped = 0; if (1 || query ("Process is currently running, stop it? ")) { /* Make it run again when we close it. */#if defined (PIOCSET) /* New method */ { long pr_flags; pr_flags = PR_RLC; result = ioctl (pi.fd, PIOCSET, &pr_flags); }#else#if defined (PIOCSRLC) /* Original method */ result = ioctl (pi.fd, PIOCSRLC, 0);#endif#endif if (result < 0) { print_sys_errmsg (pi.pathname, errno); close_proc_file (&pi); error ("PIOCSRLC or PIOCSET failed"); } if (ioctl (pi.fd, PIOCSTOP, &pi.prstatus) < 0) { print_sys_errmsg (pi.pathname, errno); close_proc_file (&pi); error ("PIOCSTOP failed"); } pi.nopass_next_sigstop = 1; } else { printf ("Ok, gdb will wait for process %u to stop.\n", pid); } } /* Remember some things about the inferior that we will, or might, change so that we can restore them when we detach. */ ioctl (pi.fd, PIOCGTRACE, &pi.saved_trace); ioctl (pi.fd, PIOCGHOLD, &pi.saved_sighold); ioctl (pi.fd, PIOCGFAULT, &pi.saved_fltset); ioctl (pi.fd, PIOCGENTRY, &pi.saved_entryset); ioctl (pi.fd, PIOCGEXIT, &pi.saved_exitset); /* Set up trace and fault sets, as gdb expects them. */ memset (&pi.prrun, 0, sizeof (pi.prrun)); prfillset (&pi.prrun.pr_trace); procfs_notice_signals (); prfillset (&pi.prrun.pr_fault); prdelset (&pi.prrun.pr_fault, FLTPAGE); if (ioctl (pi.fd, PIOCSFAULT, &pi.prrun.pr_fault)) { print_sys_errmsg ("PIOCSFAULT failed", errno); } if (ioctl (pi.fd, PIOCSTRACE, &pi.prrun.pr_trace)) { print_sys_errmsg ("PIOCSTRACE failed", errno); } attach_flag = 1; return (pid);}/*LOCAL FUNCTION do_detach -- detach from an attached-to processSYNOPSIS void do_detach (int signal)DESCRIPTION Detach from the current attachee. If signal is non-zero, the attachee is started running again and sent the specified signal. If signal is zero and the attachee was not already stopped when we attached to it, then we make it runnable again when we detach. Otherwise, we query whether or not to make the attachee runnable again, since we may simply want to leave it in the state it was in when we attached. We report any problems, but do not consider them errors, since we MUST detach even if some things don't seem to go right. This may not be the ideal situation. (FIXME). */static voiddo_detach (signal) int signal;{ int result; if (signal) { set_proc_siginfo (&pi, signal); } if (ioctl (pi.fd, PIOCSEXIT, &pi.saved_exitset) < 0) { print_sys_errmsg (pi.pathname, errno); printf ("PIOCSEXIT failed.\n"); } if (ioctl (pi.fd, PIOCSENTRY, &pi.saved_entryset) < 0) { print_sys_errmsg (pi.pathname, errno); printf ("PIOCSENTRY failed.\n"); } if (ioctl (pi.fd, PIOCSTRACE, &pi.saved_trace) < 0) { print_sys_errmsg (pi.pathname, errno); printf ("PIOCSTRACE failed.\n"); } if (ioctl (pi.fd, PIOCSHOLD, &pi.saved_sighold) < 0) { print_sys_errmsg (pi.pathname, errno); printf ("PIOSCHOLD failed.\n"); } if (ioctl (pi.fd, PIOCSFAULT, &pi.saved_fltset) < 0) { print_sys_errmsg (pi.pathname, errno); printf ("PIOCSFAULT failed.\n"); } if (ioctl (pi.fd, PIOCSTATUS, &pi.prstatus) < 0) { print_sys_errmsg (pi.pathname, errno); printf ("PIOCSTATUS failed.\n"); } else { if (signal || (pi.prstatus.pr_flags & (PR_STOPPED | PR_ISTOP))) { if (signal || !pi.was_stopped || query ("Was stopped when attached, make it runnable again? ")) { /* Clear any fault that might have stopped it. */ if (ioctl (pi.fd, PIOCCFAULT, 0)) { print_sys_errmsg (pi.pathname, errno); printf ("PIOCCFAULT failed.\n"); } /* Make it run again when we close it. */#if defined (PIOCSET) /* New method */ { long pr_flags; pr_flags = PR_RLC; result = ioctl (pi.fd, PIOCSET, &pr_flags); }#else#if defined (PIOCSRLC) /* Original method */ result = ioctl (pi.fd, PIOCSRLC, 0);#endif#endif if (result) { print_sys_errmsg (pi.pathname, errno); printf ("PIOCSRLC or PIOCSET failed.\n"); } } } } close_proc_file (&pi); attach_flag = 0;}/*LOCAL FUNCTION procfs_wait -- emulate wait() as much as possible Wait for child to do something. Return pid of child, or -1 in case of error; store status through argument pointer STATUS.SYNOPSIS int procfs_wait (int *statloc)DESCRIPTION Try to emulate wait() as much as possible. Not sure why we can't just use wait(), but it seems to have problems when applied to a process being controlled with the /proc interface.NOTES We have a race problem here with no obvious solution. We need to let the inferior run until it stops on an event of interest, which means that we need to use the PIOCWSTOP ioctl. However, we cannot use this ioctl if the process is already stopped on something that is not an event of interest, or the call will hang indefinitely. Thus we first use PIOCSTATUS to see if the process is not stopped. If not, then we use PIOCWSTOP. But during the window between the two, if the process stops for any reason that is not an event of interest (such as a job control signal) then gdb will hang. One possible workaround is to set an alarm to wake up every minute of so and check to see if the process is still running, and if so, then reissue the PIOCWSTOP. But this is a real kludge, so has not been implemented. FIXME: investigate alternatives. FIXME: Investigate why wait() seems to have problems with programs being control by /proc routines. */static intprocfs_wait (statloc) int *statloc;{ short what; short why; int statval = 0; int checkerr = 0; int rtnval = -1; if (ioctl (pi.fd, PIOCSTATUS, &pi.prstatus) < 0) { checkerr++; } else if (!(pi.prstatus.pr_flags & (PR_STOPPED | PR_ISTOP))) { if (ioctl (pi.fd, PIOCWSTOP, &pi.prstatus) < 0) { checkerr++; } } if (checkerr) { if (errno == ENOENT) { rtnval = wait (&statval); if (rtnval != inferior_pid) { print_sys_errmsg (pi.pathname, errno); error ("PIOCWSTOP, wait failed, returned %d", rtnval); /* NOTREACHED */ } } else { print_sys_errmsg (pi.pathname, errno); error ("PIOCSTATUS or PIOCWSTOP failed."); /* NOTREACHED */ } } else if (pi.prstatus.pr_flags & (PR_STOPPED | PR_ISTOP)) { rtnval = pi.prstatus.pr_pid; why = pi.prstatus.pr_why; what = pi.prstatus.pr_what; if (why == PR_SIGNALLED) { statval = (what << 8) | 0177; } else if ((why == PR_SYSEXIT) && (#ifdef SYS_exec what == SYS_exec#else 0 == 0#endif#ifdef SYS_execve || what == SYS_execve#endif#ifdef SYS_execv || what == SYS_execv#endif )) { statval = (SIGTRAP << 8) | 0177; } else if (why == PR_REQUESTED) { statval = (SIGSTOP << 8) | 0177; } else if (why == PR_JOBCONTROL) { statval = (what << 8) | 0177; } else if (why == PR_FAULTED) { switch (what) { case FLTPRIV: case FLTILL: statval = (SIGILL << 8) | 0177; break; case FLTBPT: case FLTTRACE: statval = (SIGTRAP << 8) | 0177; break; case FLTSTACK: case FLTACCESS: case FLTBOUNDS: statval = (SIGSEGV << 8) | 0177; break; case FLTIOVF: case FLTIZDIV: case FLTFPE: statval = (SIGFPE << 8) | 0177; break; case FLTPAGE: /* Recoverable page fault */ default: rtnval = -1; error ("PIOCWSTOP, unknown why %d, what %d", why, what); /* NOTREACHED */ } } else { rtnval = -1; error ("PIOCWSTOP, unknown why %d, what %d", why, what); /* NOTREACHED */ } } else { error ("PIOCWSTOP, stopped for unknown/unhandled reason, flags %#x", pi.prstatus.pr_flags); /* NOTREACHED */ } if (statloc) { *statloc = statval; } if (rtnval == -1) /* No more children to wait for */ { fprintf (stderr, "Child process unexpectedly missing.\n"); *statloc = 42; /* Claim it exited with signal 42 */ return rtnval; } return (rtnval);}/*LOCAL FUNCTION set_proc_siginfo - set a process's current signal infoSYNOPSIS void set_proc_siginfo (struct procinfo *pip, int signo);DESCRIPTION Given a pointer to a process info struct in PIP and a signal number in SIGNO, set the process's current signal and its associated signal information. The signal will be delivered to the process immediately after execution is resumed, even if it is being held. In addition, this particular delivery will not cause another PR_SIGNALLED stop even if the signal is being traced. If we are not delivering the same signal that the prstatus siginfo struct contains information about, then synthesize a siginfo struct to match the signal we are doing to deliver, make it of the type "generated by a user process", and send this synthesized copy. When used to set the inferior's signal state, this will be required if we are not currently stopped because of a traced signal, or if we decide to continue with a different signal. Note that when continuing the inferior from a stop due to receipt of a traced signal, we either have set PRCSIG to clear the existing signal, or we have to call this function to do a PIOCSSIG with either the existing siginfo struct from pr_info, or one we have synthesized appropriately for the signal we want to deliver. Otherwise if the signal is still being traced, the inferior will immediately stop again. See siginfo(5) for more details.*/static voidset_proc_siginfo (pip, signo) struct procinfo *pip; int signo;{ struct siginfo newsiginfo; struct siginfo *sip; if (pip -> valid) { if (signo == pip -> prstatus.pr_info.si_signo) { sip = &pip -> prstatus.pr_info; } else { memset ((char *) &newsiginfo, 0, sizeof (newsiginfo)); sip = &newsiginfo; sip -> si_signo = signo; sip -> si_code = 0; sip -> si_errno = 0; sip -> si_pid = getpid (); sip -> si_uid = getuid (); } if (ioctl (pip -> fd, PIOCSSIG, sip) < 0) { print_sys_errmsg (pip -> pathname, errno); warning ("PIOCSSIG failed"); } }}/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -