X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=gdb%2Finflow.c;h=b4844662dd58b7754f455c241e9b9f37b9f83041;hb=cf3e377e61e7861677252feb4d06ba8fcea1e5c1;hp=698cfb4f8be48f8a8494102b442f3bc58cddf31e;hpb=7d9884b92772d5b4fa0de57de5caca2d9308c16c;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/inflow.c b/gdb/inflow.c index 698cfb4f8b..b4844662dd 100644 --- a/gdb/inflow.c +++ b/gdb/inflow.c @@ -1,5 +1,5 @@ /* Low level interface to ptrace, for GDB when running under Unix. - Copyright (C) 1986, 1987, 1989, 1991 Free Software Foundation, Inc. + Copyright 1986, 1987, 1989, 1991, 1992 Free Software Foundation, Inc. This file is part of GDB. @@ -17,13 +17,12 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include #include "defs.h" #include "frame.h" #include "inferior.h" #include "command.h" #include "signals.h" -#include "terminal.h" +#include "serial.h" #include "target.h" #ifdef USG @@ -35,10 +34,13 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include -#include #include -extern struct target_ops child_ops; +static void +kill_command PARAMS ((char *, int)); + +static void +terminal_ours_1 PARAMS ((int)); /* Nonzero if we are debugging an attached outside process rather than an inferior. */ @@ -48,75 +50,103 @@ int attach_flag; /* Record terminal status separately for debugger and inferior. */ -static TERMINAL sg_inferior; -static TERMINAL sg_ours; +static serial_t stdin_serial; -static int tflags_inferior; -static int tflags_ours; +/* TTY state for the inferior. We save it whenever the inferior stops, and + restore it when it resumes. */ +static serial_ttystate inferior_ttystate; -#if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN) -static struct tchars tc_inferior; -static struct tchars tc_ours; -#endif +/* Our own tty state, which we restore every time we need to deal with the + terminal. We only set it once, when GDB first starts. The settings of + flags which readline saves and restores and unimportant. */ +static serial_ttystate our_ttystate; -#if defined(TIOCGLTC) && !defined(TIOCGLTC_BROKEN) -static struct ltchars ltc_inferior; -static struct ltchars ltc_ours; -#endif - -#ifdef TIOCLGET -static int lmode_inferior; -static int lmode_ours; -#endif +/* fcntl flags for us and the inferior. Saved and restored just like + {our,inferior}_ttystate. */ +static int tflags_inferior; +static int tflags_ours; -#ifdef TIOCGPGRP -# ifdef SHORT_PGRP -static short pgrp_inferior; -static short pgrp_ours; -# else -static int pgrp_inferior; -static int pgrp_ours; -# endif -#else +/* While the inferior is running, we want SIGINT and SIGQUIT to go to the + inferior only. If we have job control, that takes care of it. If not, + we save our handlers in these two variables and set SIGINT and SIGQUIT + to SIG_IGN. */ static void (*sigint_ours) (); static void (*sigquit_ours) (); -#endif /* TIOCGPGRP */ -/* Copy of inferior_io_terminal when inferior was last started. */ +/* The name of the tty (from the `tty' command) that we gave to the inferior + when it was last started. */ + static char *inferior_thisrun_terminal; -static void terminal_ours_1 (); +/* Nonzero if our terminal settings are in effect. Zero if the + inferior's settings are in effect. Ignored if !gdb_has_a_terminal + (). */ -/* Nonzero if our terminal settings are in effect. - Zero if the inferior's settings are in effect. */ static int terminal_is_ours; -/* Initialize the terminal settings we record for the inferior, - before we actually run the inferior. */ +enum {yes, no, have_not_checked} gdb_has_a_terminal_flag = have_not_checked; -void -terminal_init_inferior () +/* Does GDB have a terminal (on stdin)? */ +int +gdb_has_a_terminal () { - sg_inferior = sg_ours; - tflags_inferior = tflags_ours; - -#if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN) - tc_inferior = tc_ours; + switch (gdb_has_a_terminal_flag) + { + case yes: + return 1; + case no: + return 0; + case have_not_checked: + /* Get all the current tty settings (including whether we have a tty at + all!). Can't do this in _initialize_inflow because SERIAL_FDOPEN + won't work until the serial_ops_list is initialized. */ + +#ifdef F_GETFL + tflags_ours = fcntl (0, F_GETFL, 0); #endif -#if defined(TIOCGLTC) && !defined(TIOCGLTC_BROKEN) - ltc_inferior = ltc_ours; -#endif + gdb_has_a_terminal_flag = no; + stdin_serial = SERIAL_FDOPEN (0); + if (stdin_serial != NULL) + { + our_ttystate = SERIAL_GET_TTY_STATE (stdin_serial); + if (our_ttystate != NULL) + gdb_has_a_terminal_flag = yes; + } -#ifdef TIOCLGET - lmode_inferior = lmode_ours; -#endif + return gdb_has_a_terminal_flag == yes; + } +} -#ifdef TIOCGPGRP - pgrp_inferior = inferior_pid; -#endif /* TIOCGPGRP */ +/* Macro for printing errors from ioctl operations */ - terminal_is_ours = 1; +#define OOPSY(what) \ + if (result == -1) \ + fprintf(stderr, "[%s failed in terminal_inferior: %s]\n", \ + what, strerror (errno)) + +static void terminal_ours_1 PARAMS ((int)); + +/* Initialize the terminal settings we record for the inferior, + before we actually run the inferior. */ + +void +terminal_init_inferior () +{ + if (gdb_has_a_terminal ()) + { + /* We could just as well copy our_ttystate (if we felt like adding + a new function SERIAL_COPY_TTY_STATE). */ + if (inferior_ttystate) + free (inferior_ttystate); + inferior_ttystate = SERIAL_GET_TTY_STATE (stdin_serial); + SERIAL_SET_PROCESS_GROUP (stdin_serial, inferior_ttystate, inferior_pid); + + /* Make sure that next time we call terminal_inferior (which will be + before the program runs, as it needs to be), we install the new + process group. */ + terminal_is_ours = 1; + } } /* Put the inferior's terminal settings into effect. @@ -125,28 +155,45 @@ terminal_init_inferior () void terminal_inferior () { - if (terminal_is_ours && inferior_thisrun_terminal == 0) + if (gdb_has_a_terminal () && terminal_is_ours + && inferior_thisrun_terminal == 0) { - fcntl (0, F_SETFL, tflags_inferior); - fcntl (0, F_SETFL, tflags_inferior); - ioctl (0, TIOCSETN, &sg_inferior); - -#if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN) - ioctl (0, TIOCSETC, &tc_inferior); -#endif -#if defined(TIOCGLTC) && !defined(TIOCGLTC_BROKEN) - ioctl (0, TIOCSLTC, <c_inferior); -#endif -#ifdef TIOCLGET - ioctl (0, TIOCLSET, &lmode_inferior); + int result; + +#ifdef F_GETFL + /* Is there a reason this is being done twice? It happens both + places we use F_SETFL, so I'm inclined to think perhaps there + is some reason, however perverse. Perhaps not though... */ + result = fcntl (0, F_SETFL, tflags_inferior); + result = fcntl (0, F_SETFL, tflags_inferior); + OOPSY ("fcntl F_SETFL"); #endif -#ifdef TIOCGPGRP - ioctl (0, TIOCSPGRP, &pgrp_inferior); -#else - sigint_ours = (void (*) ()) signal (SIGINT, SIG_IGN); - sigquit_ours = (void (*) ()) signal (SIGQUIT, SIG_IGN); -#endif /* TIOCGPGRP */ + /* Because we were careful to not change in or out of raw mode in + terminal_ours, we will not change in our out of raw mode with + this call, so we don't flush any input. */ + result = SERIAL_SET_TTY_STATE (stdin_serial, inferior_ttystate); + + /* If attach_flag is set, we don't know whether we are sharing a + terminal with the inferior or not. (attaching a process + without a terminal is one case where we do not; attaching a + process which we ran from the same shell as GDB via `&' is + one case where we do, I think (but perhaps this is not + `sharing' in the sense that we need to save and restore tty + state)). I don't know if there is any way to tell whether we + are sharing a terminal. So what we do is to go through all + the saving and restoring of terminal state, but ignore errors + (which will occur, in tcsetpgrp, if we are not sharing a + terminal). */ + + if (!attach_flag) + OOPSY ("setting tty state"); + + if (!job_control) + { + sigint_ours = (void (*) ()) signal (SIGINT, SIG_IGN); + sigquit_ours = (void (*) ()) signal (SIGQUIT, SIG_IGN); + } } terminal_is_ours = 0; } @@ -175,82 +222,75 @@ terminal_ours () terminal_ours_1 (0); } +/* output_only is not used, and should not be used unless we introduce + separate terminal_is_ours and terminal_is_ours_for_output + flags. */ + static void terminal_ours_1 (output_only) int output_only; { -#ifdef TIOCGPGRP - /* Ignore this signal since it will happen when we try to set the pgrp. */ - void (*osigttou) (); -#endif /* TIOCGPGRP */ - - /* The check for inferior_thisrun_terminal had been commented out - when the call to ioctl (TIOCNOTTY) was commented out. - Checking inferior_thisrun_terminal is necessary so that + /* Checking inferior_thisrun_terminal is necessary so that if GDB is running in the background, it won't block trying - to do the ioctl()'s below. */ - if (inferior_thisrun_terminal != 0) + to do the ioctl()'s below. Checking gdb_has_a_terminal + avoids attempting all the ioctl's when running in batch. */ + if (inferior_thisrun_terminal != 0 || gdb_has_a_terminal () == 0) return; if (!terminal_is_ours) { + /* Ignore this signal since it will happen when we try to set the + pgrp. */ + void (*osigttou) (); + int result; + terminal_is_ours = 1; -#ifdef TIOCGPGRP - osigttou = (void (*) ()) signal (SIGTTOU, SIG_IGN); +#ifdef SIGTTOU + if (job_control) + osigttou = (void (*) ()) signal (SIGTTOU, SIG_IGN); +#endif - ioctl (0, TIOCGPGRP, &pgrp_inferior); - ioctl (0, TIOCSPGRP, &pgrp_ours); + if (inferior_ttystate) + free (inferior_ttystate); + inferior_ttystate = SERIAL_GET_TTY_STATE (stdin_serial); + + /* Here we used to set ICANON in our ttystate, but I believe this + was an artifact from before when we used readline. Readline sets + the tty state when it needs to. */ + + /* Set tty state to our_ttystate. We don't change in our out of raw + mode, to avoid flushing input. We need to do the same thing + regardless of output_only, because we don't have separate + terminal_is_ours and terminal_is_ours_for_output flags. It's OK, + though, since readline will deal with raw mode when/if it needs to. + */ + SERIAL_NOFLUSH_SET_TTY_STATE (stdin_serial, our_ttystate, + inferior_ttystate); + +#ifdef SIGTTOU + if (job_control) + signal (SIGTTOU, osigttou); +#endif - signal (SIGTTOU, osigttou); -#else - signal (SIGINT, sigint_ours); - signal (SIGQUIT, sigquit_ours); -#endif /* TIOCGPGRP */ + if (!job_control) + { + signal (SIGINT, sigint_ours); + signal (SIGQUIT, sigquit_ours); + } +#ifdef F_GETFL tflags_inferior = fcntl (0, F_GETFL, 0); - ioctl (0, TIOCGETP, &sg_inferior); -#if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN) - ioctl (0, TIOCGETC, &tc_inferior); -#endif -#if defined(TIOCGLTC) && !defined(TIOCGLTC_BROKEN) - ioctl (0, TIOCGLTC, <c_inferior); -#endif -#ifdef TIOCLGET - ioctl (0, TIOCLGET, &lmode_inferior); + /* Is there a reason this is being done twice? It happens both + places we use F_SETFL, so I'm inclined to think perhaps there + is some reason, however perverse. Perhaps not though... */ + result = fcntl (0, F_SETFL, tflags_ours); + result = fcntl (0, F_SETFL, tflags_ours); #endif - } -#ifdef HAVE_TERMIO - sg_ours.c_lflag |= ICANON; - if (output_only && !(sg_inferior.c_lflag & ICANON)) - sg_ours.c_lflag &= ~ICANON; -#else /* not HAVE_TERMIO */ - sg_ours.sg_flags &= ~RAW & ~CBREAK; - if (output_only) - sg_ours.sg_flags |= (RAW | CBREAK) & sg_inferior.sg_flags; -#endif /* not HAVE_TERMIO */ - - fcntl (0, F_SETFL, tflags_ours); - fcntl (0, F_SETFL, tflags_ours); - ioctl (0, TIOCSETN, &sg_ours); - -#if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN) - ioctl (0, TIOCSETC, &tc_ours); -#endif -#if defined(TIOCGLTC) && !defined(TIOCGLTC_BROKEN) - ioctl (0, TIOCSLTC, <c_ours); -#endif -#ifdef TIOCLGET - ioctl (0, TIOCLSET, &lmode_ours); -#endif - -#ifdef HAVE_TERMIO - sg_ours.c_lflag |= ICANON; -#else /* not HAVE_TERMIO */ - sg_ours.sg_flags &= ~RAW & ~CBREAK; -#endif /* not HAVE_TERMIO */ + result = result; /* lint */ + } } /* ARGSUSED */ @@ -268,45 +308,65 @@ child_terminal_info (args, from_tty) char *args; int from_tty; { - register int i; + if (!gdb_has_a_terminal ()) + { + printf_filtered ("This GDB does not control a terminal.\n"); + return; + } printf_filtered ("Inferior's terminal status (currently saved by GDB):\n"); -#ifdef HAVE_TERMIO - - printf_filtered ("fcntl flags = 0x%x, c_iflag = 0x%x, c_oflag = 0x%x,\n", - tflags_inferior, sg_inferior.c_iflag, sg_inferior.c_oflag); - printf_filtered ("c_cflag = 0x%x, c_lflag = 0x%x, c_line = 0x%x.\n", - sg_inferior.c_cflag, sg_inferior.c_lflag, sg_inferior.c_line); - printf_filtered ("c_cc: "); - for (i = 0; (i < NCC); i += 1) - printf_filtered ("0x%x ", sg_inferior.c_cc[i]); - printf_filtered ("\n"); + /* First the fcntl flags. */ + { + int flags; + + flags = tflags_inferior; -#else /* not HAVE_TERMIO */ + printf_filtered ("File descriptor flags = "); - printf_filtered ("fcntl flags = 0x%x, sgttyb.sg_flags = 0x%x, owner pid = %d.\n", - tflags_inferior, sg_inferior.sg_flags, pgrp_inferior); +#ifndef O_ACCMODE +#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR) +#endif + /* (O_ACCMODE) parens are to avoid Ultrix header file bug */ + switch (flags & (O_ACCMODE)) + { + case O_RDONLY: printf_filtered ("O_RDONLY"); break; + case O_WRONLY: printf_filtered ("O_WRONLY"); break; + case O_RDWR: printf_filtered ("O_RDWR"); break; + } + flags &= ~(O_ACCMODE); + +#ifdef O_NONBLOCK + if (flags & O_NONBLOCK) + printf_filtered (" | O_NONBLOCK"); + flags &= ~O_NONBLOCK; +#endif + +#if defined (O_NDELAY) + /* If O_NDELAY and O_NONBLOCK are defined to the same thing, we will + print it as O_NONBLOCK, which is good cause that is what POSIX + has, and the flag will already be cleared by the time we get here. */ + if (flags & O_NDELAY) + printf_filtered (" | O_NDELAY"); + flags &= ~O_NDELAY; +#endif -#endif /* not HAVE_TERMIO */ + if (flags & O_APPEND) + printf_filtered (" | O_APPEND"); + flags &= ~O_APPEND; -#if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN) - printf_filtered ("tchars: "); - for (i = 0; i < (int)sizeof (struct tchars); i++) - printf_filtered ("0x%x ", ((char *)&tc_inferior)[i]); - printf_filtered ("\n"); +#if defined (O_BINARY) + if (flags & O_BINARY) + printf_filtered (" | O_BINARY"); + flags &= ~O_BINARY; #endif -#if defined(TIOCGLTC) && !defined(TIOCGLTC_BROKEN) - printf_filtered ("ltchars: "); - for (i = 0; i < (int)sizeof (struct ltchars); i++) - printf_filtered ("0x%x ", ((char *)<c_inferior)[i]); - printf_filtered ("\n"); -#endif - -#ifdef TIOCLGET - printf_filtered ("lmode: 0x%x\n", lmode_inferior); -#endif + if (flags) + printf_filtered (" | 0x%x", flags); + printf_filtered ("\n"); + } + + SERIAL_PRINT_TTY_STATE (stdin_serial, inferior_ttystate); } /* NEW_TTY_PREFORK is called before forking a new child process, @@ -334,14 +394,20 @@ new_tty () if (inferior_thisrun_terminal == 0) return; - +#if !defined(__GO32__) #ifdef TIOCNOTTY - /* Disconnect the child process from our controlling terminal. */ + /* Disconnect the child process from our controlling terminal. On some + systems (SVR4 for example), this may cause a SIGTTOU, so temporarily + ignore SIGTTOU. */ tty = open("/dev/tty", O_RDWR); if (tty > 0) { + void (*osigttou) (); + + osigttou = (void (*)()) signal(SIGTTOU, SIG_IGN); ioctl(tty, TIOCNOTTY, 0); close(tty); + signal(SIGTTOU, osigttou); } #endif @@ -367,6 +433,7 @@ new_tty () { close (2); dup (tty); } if (tty > 2) close(tty); +#endif /* !go32 */ } /* Kill the inferior process. Make us have no inferior. */ @@ -377,11 +444,12 @@ kill_command (arg, from_tty) char *arg; int from_tty; { + /* Shouldn't this be target_has_execution? FIXME. */ if (inferior_pid == 0) error ("The program is not being run."); - if (!query ("Kill the inferior process? ")) + if (!query ("Kill the program being debugged? ")) error ("Not confirmed."); - target_kill (arg, from_tty); + target_kill (); /* Killing off the inferior can leave us with a core file. If so, print the state we are left in. */ @@ -401,7 +469,7 @@ generic_mourn_inferior () { inferior_pid = 0; attach_flag = 0; - mark_breakpoints_out (); + breakpoint_init_inferior (); registers_changed (); #ifdef CLEAR_DEFERRED_STORES @@ -410,64 +478,37 @@ generic_mourn_inferior () #endif reopen_exec_file (); - if (target_has_stack) { - set_current_frame ( create_new_frame (read_register (FP_REGNUM), - read_pc ())); - select_frame (get_current_frame (), 0); - } else { - set_current_frame (0); - select_frame ((FRAME) 0, -1); - } + reinit_frame_cache (); + /* It is confusing to the user for ignore counts to stick around from previous runs of the inferior. So clear them. */ breakpoint_clear_ignore_counts (); } - -void -child_mourn_inferior () -{ - unpush_target (&child_ops); - generic_mourn_inferior (); -} -#if 0 -/* This function is just for testing, and on some systems (Sony NewsOS - 3.2) also includes which leads to errors - (since on this system at least sys/time.h is not protected against - multiple inclusion). */ +/* Call set_sigint_trap when you need to pass a signal on to an attached + process when handling SIGINT */ + /* ARGSUSED */ static void -try_writing_regs_command (arg, from_tty) - char *arg; - int from_tty; +pass_signal (signo) + int signo; { - register int i; - register int value; + kill (inferior_pid, SIGINT); +} - if (inferior_pid == 0) - error ("There is no inferior process now."); - - /* A Sun 3/50 or 3/60 (at least) running SunOS 4.0.3 will have a - kernel panic if we try to write past the end of the user area. - Presumably Sun will fix this bug (it has been reported), but it - is tacky to crash the system, so at least on SunOS4 we need to - stop writing when we hit the end of the user area. */ - for (i = 0; i < sizeof (struct user); i += 2) - { - QUIT; - errno = 0; - value = call_ptrace (3, inferior_pid, i, 0); - call_ptrace (6, inferior_pid, i, value); - if (errno == 0) - { - printf (" Succeeded with address 0x%x; value 0x%x (%d).\n", - i, value, value); - } - else if ((i & 0377) == 0) - printf (" Failed at 0x%x.\n", i); - } +static void (*osig)(); + +void +set_sigint_trap() +{ + osig = (void (*) ()) signal (SIGINT, pass_signal); +} + +void +clear_sigint_trap() +{ + signal (SIGINT, osig); } -#endif void _initialize_inflow () @@ -475,34 +516,10 @@ _initialize_inflow () add_info ("terminal", term_info, "Print inferior's saved terminal status."); -#if 0 - add_com ("try-writing-regs", class_obscure, try_writing_regs_command, - "Try writing all locations in inferior's system block.\n\ -Report which ones can be written."); -#endif - add_com ("kill", class_run, kill_command, "Kill execution of program being debugged."); inferior_pid = 0; - ioctl (0, TIOCGETP, &sg_ours); - tflags_ours = fcntl (0, F_GETFL, 0); - -#if defined(TIOCGETC) && !defined(TIOCGETC_BROKEN) - ioctl (0, TIOCGETC, &tc_ours); -#endif -#if defined(TIOCGLTC) && !defined(TIOCGLTC_BROKEN) - ioctl (0, TIOCGLTC, <c_ours); -#endif -#ifdef TIOCLGET - ioctl (0, TIOCLGET, &lmode_ours); -#endif - -#ifdef TIOCGPGRP - ioctl (0, TIOCGPGRP, &pgrp_ours); -#endif /* TIOCGPGRP */ - terminal_is_ours = 1; } -