OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /
    from Rev 1762 to Rev 1763
    Reverse comparison

Rev 1762 → Rev 1763

/trunk/gdb-6.8/gdb/inflow.c
0,0 → 1,776
/* Low level interface to ptrace, for GDB when running under Unix.
Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
Free Software Foundation, Inc.
 
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/>. */
 
#include "defs.h"
#include "frame.h"
#include "inferior.h"
#include "command.h"
#include "serial.h"
#include "terminal.h"
#include "target.h"
#include "gdbthread.h"
 
#include "gdb_string.h"
#include <signal.h>
#include <fcntl.h>
#include "gdb_select.h"
 
#include "inflow.h"
 
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
 
#ifndef O_NOCTTY
#define O_NOCTTY 0
#endif
 
#if defined (SIGIO) && defined (FASYNC) && defined (FD_SET) && defined (F_SETOWN)
static void handle_sigio (int);
#endif
 
extern void _initialize_inflow (void);
 
static void pass_signal (int);
 
static void kill_command (char *, int);
 
static void terminal_ours_1 (int);
/* Record terminal status separately for debugger and inferior. */
 
static struct serial *stdin_serial;
 
/* TTY state for the inferior. We save it whenever the inferior stops, and
restore it when it resumes. */
static serial_ttystate inferior_ttystate;
 
/* 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;
 
/* fcntl flags for us and the inferior. Saved and restored just like
{our,inferior}_ttystate. */
static int tflags_inferior;
static int tflags_ours;
 
#ifdef PROCESS_GROUP_TYPE
/* Process group for us and the inferior. Saved and restored just like
{our,inferior}_ttystate. */
PROCESS_GROUP_TYPE our_process_group;
PROCESS_GROUP_TYPE inferior_process_group;
#endif
 
/* 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) ();
 
/* The name of the tty (from the `tty' command) that we gave to the inferior
when it was last started. */
 
static const char *inferior_thisrun_terminal;
 
/* Nonzero if our terminal settings are in effect. Zero if the
inferior's settings are in effect. Ignored if !gdb_has_a_terminal
(). */
 
int terminal_is_ours;
 
enum
{
yes, no, have_not_checked
}
gdb_has_a_terminal_flag = have_not_checked;
 
/* Does GDB have a terminal (on stdin)? */
int
gdb_has_a_terminal (void)
{
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
 
gdb_has_a_terminal_flag = no;
if (stdin_serial != NULL)
{
our_ttystate = serial_get_tty_state (stdin_serial);
 
if (our_ttystate != NULL)
{
gdb_has_a_terminal_flag = yes;
#ifdef HAVE_TERMIOS
our_process_group = tcgetpgrp (0);
#endif
#ifdef HAVE_TERMIO
our_process_group = getpgrp ();
#endif
#ifdef HAVE_SGTTY
ioctl (0, TIOCGPGRP, &our_process_group);
#endif
}
}
 
return gdb_has_a_terminal_flag == yes;
default:
/* "Can't happen". */
return 0;
}
}
 
/* Macro for printing errors from ioctl operations */
 
#define OOPSY(what) \
if (result == -1) \
fprintf_unfiltered(gdb_stderr, "[%s failed in terminal_inferior: %s]\n", \
what, safe_strerror (errno))
 
static void terminal_ours_1 (int);
 
/* Initialize the terminal settings we record for the inferior,
before we actually run the inferior. */
 
void
terminal_init_inferior_with_pgrp (int pgrp)
{
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)
xfree (inferior_ttystate);
inferior_ttystate = serial_get_tty_state (stdin_serial);
 
#ifdef PROCESS_GROUP_TYPE
inferior_process_group = pgrp;
#endif
 
/* 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;
}
}
 
/* Save the terminal settings again. This is necessary for the TUI
when it switches to TUI or non-TUI mode; curses changes the terminal
and gdb must be able to restore it correctly. */
 
void
terminal_save_ours (void)
{
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 (our_ttystate)
xfree (our_ttystate);
our_ttystate = serial_get_tty_state (stdin_serial);
}
}
 
void
terminal_init_inferior (void)
{
#ifdef PROCESS_GROUP_TYPE
/* This is for Lynx, and should be cleaned up by having Lynx be a separate
debugging target with a version of target_terminal_init_inferior which
passes in the process group to a generic routine which does all the work
(and the non-threaded child_terminal_init_inferior can just pass in
inferior_ptid to the same routine). */
/* We assume INFERIOR_PID is also the child's process group. */
terminal_init_inferior_with_pgrp (PIDGET (inferior_ptid));
#endif /* PROCESS_GROUP_TYPE */
}
 
/* Put the inferior's terminal settings into effect.
This is preparation for starting or resuming the inferior. */
 
void
terminal_inferior (void)
{
if (gdb_has_a_terminal () && terminal_is_ours
&& inferior_ttystate != NULL
&& inferior_thisrun_terminal == 0)
{
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
 
/* 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);
OOPSY ("setting tty state");
 
if (!job_control)
{
sigint_ours = (void (*)()) signal (SIGINT, SIG_IGN);
#ifdef SIGQUIT
sigquit_ours = (void (*)()) signal (SIGQUIT, SIG_IGN);
#endif
}
 
/* 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 the tty state, but ignore errors
setting the process group, which will happen if we are not
sharing a terminal). */
 
if (job_control)
{
#ifdef HAVE_TERMIOS
result = tcsetpgrp (0, inferior_process_group);
if (!attach_flag)
OOPSY ("tcsetpgrp");
#endif
 
#ifdef HAVE_SGTTY
result = ioctl (0, TIOCSPGRP, &inferior_process_group);
if (!attach_flag)
OOPSY ("TIOCSPGRP");
#endif
}
 
}
terminal_is_ours = 0;
}
 
/* Put some of our terminal settings into effect,
enough to get proper results from our output,
but do not change into or out of RAW mode
so that no input is discarded.
 
After doing this, either terminal_ours or terminal_inferior
should be called to get back to a normal state of affairs. */
 
void
terminal_ours_for_output (void)
{
terminal_ours_1 (1);
}
 
/* Put our terminal settings into effect.
First record the inferior's terminal settings
so they can be restored properly later. */
 
void
terminal_ours (void)
{
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 (int output_only)
{
/* 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. 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)
{
#ifdef SIGTTOU
/* Ignore this signal since it will happen when we try to set the
pgrp. */
void (*osigttou) () = NULL;
#endif
int result;
 
terminal_is_ours = 1;
 
#ifdef SIGTTOU
if (job_control)
osigttou = (void (*)()) signal (SIGTTOU, SIG_IGN);
#endif
 
if (inferior_ttystate)
xfree (inferior_ttystate);
inferior_ttystate = serial_get_tty_state (stdin_serial);
#ifdef HAVE_TERMIOS
inferior_process_group = tcgetpgrp (0);
#endif
#ifdef HAVE_TERMIO
inferior_process_group = getpgrp ();
#endif
#ifdef HAVE_SGTTY
ioctl (0, TIOCGPGRP, &inferior_process_group);
#endif
 
/* 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.
FIXME-maybe: However, query() expects non-raw mode and doesn't
use readline. Maybe query should use readline (on the other hand,
this only matters for HAVE_SGTTY, not termio or termios, I think). */
 
/* 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);
 
if (job_control)
{
#ifdef HAVE_TERMIOS
result = tcsetpgrp (0, our_process_group);
#if 0
/* This fails on Ultrix with EINVAL if you run the testsuite
in the background with nohup, and then log out. GDB never
used to check for an error here, so perhaps there are other
such situations as well. */
if (result == -1)
fprintf_unfiltered (gdb_stderr, "[tcsetpgrp failed in terminal_ours: %s]\n",
safe_strerror (errno));
#endif
#endif /* termios */
 
#ifdef HAVE_SGTTY
result = ioctl (0, TIOCSPGRP, &our_process_group);
#endif
}
 
#ifdef SIGTTOU
if (job_control)
signal (SIGTTOU, osigttou);
#endif
 
if (!job_control)
{
signal (SIGINT, sigint_ours);
#ifdef SIGQUIT
signal (SIGQUIT, sigquit_ours);
#endif
}
 
#ifdef F_GETFL
tflags_inferior = fcntl (0, F_GETFL, 0);
 
/* 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
}
}
 
void
term_info (char *arg, int from_tty)
{
target_terminal_info (arg, from_tty);
}
 
void
child_terminal_info (char *args, int from_tty)
{
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"));
 
/* First the fcntl flags. */
{
int flags;
 
flags = tflags_inferior;
 
printf_filtered ("File descriptor flags = ");
 
#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
 
if (flags & O_APPEND)
printf_filtered (" | O_APPEND");
flags &= ~O_APPEND;
 
#if defined (O_BINARY)
if (flags & O_BINARY)
printf_filtered (" | O_BINARY");
flags &= ~O_BINARY;
#endif
 
if (flags)
printf_filtered (" | 0x%x", flags);
printf_filtered ("\n");
}
 
#ifdef PROCESS_GROUP_TYPE
printf_filtered ("Process group = %d\n",
(int) inferior_process_group);
#endif
 
serial_print_tty_state (stdin_serial, inferior_ttystate, gdb_stdout);
}
/* NEW_TTY_PREFORK is called before forking a new child process,
so we can record the state of ttys in the child to be formed.
TTYNAME is null if we are to share the terminal with gdb;
or points to a string containing the name of the desired tty.
 
NEW_TTY is called in new child processes under Unix, which will
become debugger target processes. This actually switches to
the terminal specified in the NEW_TTY_PREFORK call. */
 
void
new_tty_prefork (const char *ttyname)
{
/* Save the name for later, for determining whether we and the child
are sharing a tty. */
inferior_thisrun_terminal = ttyname;
}
 
/* JPB: Some picky Ubuntu GCC compilers don't like the result of dup being
ignored (even if you cast it to void). So capture the value and ignore
THAT. */
void
new_tty (void)
{
int res; /* For dup result */
int tty;
 
if (inferior_thisrun_terminal == 0)
return;
#if !defined(__GO32__) && !defined(_WIN32)
#ifdef TIOCNOTTY
/* 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
 
/* Now open the specified new terminal. */
tty = open (inferior_thisrun_terminal, O_RDWR | O_NOCTTY);
if (tty == -1)
{
print_sys_errmsg (inferior_thisrun_terminal, errno);
_exit (1);
}
 
/* Avoid use of dup2; doesn't exist on all systems. */
if (tty != 0)
{
close (0);
res = dup (tty);
}
if (tty != 1)
{
close (1);
res = dup (tty);
}
if (tty != 2)
{
close (2);
res = dup (tty);
}
if (tty > 2)
close (tty);
#endif /* !go32 && !win32 */
}
/* Kill the inferior process. Make us have no inferior. */
 
static void
kill_command (char *arg, int from_tty)
{
/* FIXME: This should not really be inferior_ptid (or target_has_execution).
It should be a distinct flag that indicates that a target is active, cuz
some targets don't have processes! */
 
if (ptid_equal (inferior_ptid, null_ptid))
error (_("The program is not being run."));
if (!query ("Kill the program being debugged? "))
error (_("Not confirmed."));
target_kill ();
 
init_thread_list (); /* Destroy thread info */
 
/* Killing off the inferior can leave us with a core file. If so,
print the state we are left in. */
if (target_has_stack)
{
printf_filtered (_("In %s,\n"), target_longname);
print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC);
}
bfd_cache_close_all ();
}
/* Call set_sigint_trap when you need to pass a signal on to an attached
process when handling SIGINT */
 
static void
pass_signal (int signo)
{
#ifndef _WIN32
kill (PIDGET (inferior_ptid), SIGINT);
#endif
}
 
static void (*osig) ();
 
void
set_sigint_trap (void)
{
if (attach_flag || inferior_thisrun_terminal)
{
osig = (void (*)()) signal (SIGINT, pass_signal);
}
}
 
void
clear_sigint_trap (void)
{
if (attach_flag || inferior_thisrun_terminal)
{
signal (SIGINT, osig);
}
}
#if defined (SIGIO) && defined (FASYNC) && defined (FD_SET) && defined (F_SETOWN)
static void (*old_sigio) ();
 
static void
handle_sigio (int signo)
{
int numfds;
fd_set readfds;
 
signal (SIGIO, handle_sigio);
 
FD_ZERO (&readfds);
FD_SET (target_activity_fd, &readfds);
numfds = gdb_select (target_activity_fd + 1, &readfds, NULL, NULL, NULL);
if (numfds >= 0 && FD_ISSET (target_activity_fd, &readfds))
{
#ifndef _WIN32
if ((*target_activity_function) ())
kill (PIDGET (inferior_ptid), SIGINT);
#endif
}
}
 
static int old_fcntl_flags;
 
void
set_sigio_trap (void)
{
if (target_activity_function)
{
old_sigio = (void (*)()) signal (SIGIO, handle_sigio);
fcntl (target_activity_fd, F_SETOWN, getpid ());
old_fcntl_flags = fcntl (target_activity_fd, F_GETFL, 0);
fcntl (target_activity_fd, F_SETFL, old_fcntl_flags | FASYNC);
}
}
 
void
clear_sigio_trap (void)
{
if (target_activity_function)
{
signal (SIGIO, old_sigio);
fcntl (target_activity_fd, F_SETFL, old_fcntl_flags);
}
}
#else /* No SIGIO. */
void
set_sigio_trap (void)
{
if (target_activity_function)
internal_error (__FILE__, __LINE__, _("failed internal consistency check"));
}
 
void
clear_sigio_trap (void)
{
if (target_activity_function)
internal_error (__FILE__, __LINE__, _("failed internal consistency check"));
}
#endif /* No SIGIO. */
 
/* This is here because this is where we figure out whether we (probably)
have job control. Just using job_control only does part of it because
setpgid or setpgrp might not exist on a system without job control.
It might be considered misplaced (on the other hand, process groups and
job control are closely related to ttys).
 
For a more clean implementation, in libiberty, put a setpgid which merely
calls setpgrp and a setpgrp which does nothing (any system with job control
will have one or the other). */
int
gdb_setpgid (void)
{
int retval = 0;
 
if (job_control)
{
#if defined (HAVE_TERMIOS) || defined (TIOCGPGRP)
#ifdef HAVE_SETPGID
/* The call setpgid (0, 0) is supposed to work and mean the same
thing as this, but on Ultrix 4.2A it fails with EPERM (and
setpgid (getpid (), getpid ()) succeeds). */
retval = setpgid (getpid (), getpid ());
#else
#ifdef HAVE_SETPGRP
#ifdef SETPGRP_VOID
retval = setpgrp ();
#else
retval = setpgrp (getpid (), getpid ());
#endif
#endif /* HAVE_SETPGRP */
#endif /* HAVE_SETPGID */
#endif /* defined (HAVE_TERMIOS) || defined (TIOCGPGRP) */
}
 
return retval;
}
 
/* Get all the current tty settings (including whether we have a
tty at all!). We can't do this in _initialize_inflow because
serial_fdopen() won't work until the serial_ops_list is
initialized, but we don't want to do it lazily either, so
that we can guarantee stdin_serial is opened if there is
a terminal. */
void
initialize_stdin_serial (void)
{
stdin_serial = serial_fdopen (0);
}
 
void
_initialize_inflow (void)
{
add_info ("terminal", term_info,
_("Print inferior's saved terminal status."));
 
add_com ("kill", class_run, kill_command,
_("Kill execution of program being debugged."));
 
inferior_ptid = null_ptid;
 
terminal_is_ours = 1;
 
/* OK, figure out whether we have job control. If neither termios nor
sgtty (i.e. termio or go32), leave job_control 0. */
 
#if defined (HAVE_TERMIOS)
/* Do all systems with termios have the POSIX way of identifying job
control? I hope so. */
#ifdef _POSIX_JOB_CONTROL
job_control = 1;
#else
#ifdef _SC_JOB_CONTROL
job_control = sysconf (_SC_JOB_CONTROL);
#else
job_control = 0; /* have to assume the worst */
#endif /* _SC_JOB_CONTROL */
#endif /* _POSIX_JOB_CONTROL */
#endif /* HAVE_TERMIOS */
 
#ifdef HAVE_SGTTY
#ifdef TIOCGPGRP
job_control = 1;
#else
job_control = 0;
#endif /* TIOCGPGRP */
#endif /* sgtty */
}
/trunk/gdb-6.8/gdb/or1k-jtag.c
301,7 → 301,9
/*----------------------------------------------------------------------------*/
/*!Resets the local JTAG via JP1
 
Only works if this is a local connection
Only works if this is a local connection. The old code used to ignore the
write function results, but that upsets some particularly picky Ubuntu GCC
compilers, so we get the result and do nothing with it.
 
Writes:
@verbatim
317,6 → 319,7
{
unsigned char data;
int lp = or1k_jtag_connection.device.lp; /* CZ */
ssize_t res; /* So don't ignore results */
 
if (OR1K_JTAG_LOCAL != or1k_jtag_connection.location)
{
324,11 → 327,11
}
 
data = 0;
(void)write (lp, &data, sizeof (data)); // Cast to help Ubuntu
res = write (lp, &data, sizeof (data));
JP1_WAIT ();
 
data = JP1_TRST;
(void)write (lp, &data, sizeof (data) ); // Cast to help Ubuntu
res = write (lp, &data, sizeof (data) );
JP1_WAIT ();
 
} /* jp1_ll_reset_jp1() */
384,6 → 387,10
Rewritten by Jeremy Bennett to work whatever the TMS and TDI bit positions
in JP1.
 
The old code used to ignore the write function results, but that upsets
some particularly picky Ubuntu GCC compilers, so we get the result and do
nothing with it.
 
Writes:
@verbatim
TCK=0 TRST=1 TMS=tms TDI=tdi
400,6 → 407,7
{
unsigned char data;
int lp = or1k_jtag_connection.device.lp; /* CZ */
ssize_t res; /* So don't ignore results */
 
if (OR1K_JTAG_LOCAL != or1k_jtag_connection.location)
{
409,12 → 417,12
data = (tms ? JP1_TDI : 0) |
(tdi ? JP1_TMS : 0) |
JP1_TRST;
(void)write (lp, &data, sizeof (data) ); // Cast to help Ubuntu
res = write (lp, &data, sizeof (data) );
JP1_WAIT ();
/* rise clock */
data |= JP1_TCK;
(void)write (lp, &data, sizeof (data) ); // Cast to help Ubuntu
res = write (lp, &data, sizeof (data) );
JP1_WAIT ();
 
/* Update the CRC for this TDI bit */
/trunk/gdb-6.8/gdb/top.c
0,0 → 1,1667
/* Top level stuff for GDB, the GNU debugger.
 
Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
2008 Free Software Foundation, Inc.
 
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/>. */
 
#include "defs.h"
#include "gdbcmd.h"
#include "call-cmds.h"
#include "cli/cli-cmds.h"
#include "cli/cli-script.h"
#include "cli/cli-setshow.h"
#include "cli/cli-decode.h"
#include "symtab.h"
#include "inferior.h"
#include "exceptions.h"
#include <signal.h>
#include "target.h"
#include "breakpoint.h"
#include "gdbtypes.h"
#include "expression.h"
#include "value.h"
#include "language.h"
#include "terminal.h" /* For job_control. */
#include "annotate.h"
#include "completer.h"
#include "top.h"
#include "version.h"
#include "serial.h"
#include "doublest.h"
#include "gdb_assert.h"
#include "main.h"
#include "event-loop.h"
 
/* readline include files */
#include "readline/readline.h"
#include "readline/history.h"
 
/* readline defines this. */
#undef savestring
 
#include <sys/types.h>
 
#include "event-top.h"
#include "gdb_string.h"
#include "gdb_stat.h"
#include <ctype.h>
#include "ui-out.h"
#include "cli-out.h"
 
/* Default command line prompt. This is overriden in some configs. */
 
#ifndef DEFAULT_PROMPT
#define DEFAULT_PROMPT "(gdb) "
#endif
 
/* Initialization file name for gdb. This is overridden in some configs. */
 
#ifndef PATH_MAX
# ifdef FILENAME_MAX
# define PATH_MAX FILENAME_MAX
# else
# define PATH_MAX 512
# endif
#endif
 
#ifndef GDBINIT_FILENAME
#define GDBINIT_FILENAME ".gdbinit"
#endif
char gdbinit[PATH_MAX + 1] = GDBINIT_FILENAME;
 
int inhibit_gdbinit = 0;
 
/* If nonzero, and GDB has been configured to be able to use windows,
attempt to open them upon startup. */
 
int use_windows = 0;
 
extern char lang_frame_mismatch_warn[]; /* language.c */
 
/* Flag for whether we want all the "from_tty" gubbish printed. */
 
int caution = 1; /* Default is yes, sigh. */
static void
show_caution (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("\
Whether to confirm potentially dangerous operations is %s.\n"),
value);
}
 
/* stdio stream that command input is being read from. Set to stdin normally.
Set by source_command to the file we are sourcing. Set to NULL if we are
executing a user-defined command or interacting via a GUI. */
 
FILE *instream;
 
/* Flag to indicate whether a user defined command is currently running. */
 
int in_user_command;
 
/* Current working directory. */
 
char *current_directory;
 
/* The directory name is actually stored here (usually). */
char gdb_dirbuf[1024];
 
/* Function to call before reading a command, if nonzero.
The function receives two args: an input stream,
and a prompt string. */
 
void (*window_hook) (FILE *, char *);
 
int epoch_interface;
int xgdb_verbose;
 
/* gdb prints this when reading a command interactively */
static char *gdb_prompt_string; /* the global prompt string */
 
/* Buffer used for reading command lines, and the size
allocated for it so far. */
 
char *line;
int linesize = 100;
 
/* Nonzero if the current command is modified by "server ". This
affects things like recording into the command history, commands
repeating on RETURN, etc. This is so a user interface (emacs, GUI,
whatever) can issue its own commands and also send along commands
from the user, and have the user not notice that the user interface
is issuing commands too. */
int server_command;
 
/* Baud rate specified for talking to serial target systems. Default
is left as -1, so targets can choose their own defaults. */
/* FIXME: This means that "show remotebaud" and gr_files_info can print -1
or (unsigned int)-1. This is a Bad User Interface. */
 
int baud_rate = -1;
 
/* Timeout limit for response from target. */
 
/* The default value has been changed many times over the years. It
was originally 5 seconds. But that was thought to be a long time
to sit and wait, so it was changed to 2 seconds. That was thought
to be plenty unless the connection was going through some terminal
server or multiplexer or other form of hairy serial connection.
 
In mid-1996, remote_timeout was moved from remote.c to top.c and
it began being used in other remote-* targets. It appears that the
default was changed to 20 seconds at that time, perhaps because the
Renesas E7000 ICE didn't always respond in a timely manner.
 
But if 5 seconds is a long time to sit and wait for retransmissions,
20 seconds is far worse. This demonstrates the difficulty of using
a single variable for all protocol timeouts.
 
As remote.c is used much more than remote-e7000.c, it was changed
back to 2 seconds in 1999. */
 
int remote_timeout = 2;
 
/* Non-zero tells remote* modules to output debugging info. */
 
int remote_debug = 0;
 
/* Non-zero means the target is running. Note: this is different from
saying that there is an active target and we are stopped at a
breakpoint, for instance. This is a real indicator whether the
target is off and running, which gdb is doing something else. */
int target_executing = 0;
 
/* Sbrk location on entry to main. Used for statistics only. */
#ifdef HAVE_SBRK
char *lim_at_start;
#endif
 
/* Signal to catch ^Z typed while reading a command: SIGTSTP or SIGCONT. */
 
#ifndef STOP_SIGNAL
#ifdef SIGTSTP
#define STOP_SIGNAL SIGTSTP
static void stop_sig (int);
#endif
#endif
 
/* Hooks for alternate command interfaces. */
 
/* Called after most modules have been initialized, but before taking users
command file.
 
If the UI fails to initialize and it wants GDB to continue
using the default UI, then it should clear this hook before returning. */
 
void (*deprecated_init_ui_hook) (char *argv0);
 
/* This hook is called from within gdb's many mini-event loops which could
steal control from a real user interface's event loop. It returns
non-zero if the user is requesting a detach, zero otherwise. */
 
int (*deprecated_ui_loop_hook) (int);
 
/* Called instead of command_loop at top level. Can be invoked via
throw_exception(). */
 
void (*deprecated_command_loop_hook) (void);
 
 
/* Called from print_frame_info to list the line we stopped in. */
 
void (*deprecated_print_frame_info_listing_hook) (struct symtab * s, int line,
int stopline, int noerror);
/* Replaces most of query. */
 
int (*deprecated_query_hook) (const char *, va_list);
 
/* Replaces most of warning. */
 
void (*deprecated_warning_hook) (const char *, va_list);
 
/* These three functions support getting lines of text from the user.
They are used in sequence. First deprecated_readline_begin_hook is
called with a text string that might be (for example) a message for
the user to type in a sequence of commands to be executed at a
breakpoint. If this function calls back to a GUI, it might take
this opportunity to pop up a text interaction window with this
message. Next, deprecated_readline_hook is called with a prompt
that is emitted prior to collecting the user input. It can be
called multiple times. Finally, deprecated_readline_end_hook is
called to notify the GUI that we are done with the interaction
window and it can close it. */
 
void (*deprecated_readline_begin_hook) (char *, ...);
char *(*deprecated_readline_hook) (char *);
void (*deprecated_readline_end_hook) (void);
 
/* Called as appropriate to notify the interface of the specified breakpoint
conditions. */
 
void (*deprecated_create_breakpoint_hook) (struct breakpoint * bpt);
void (*deprecated_delete_breakpoint_hook) (struct breakpoint * bpt);
void (*deprecated_modify_breakpoint_hook) (struct breakpoint * bpt);
 
/* Called as appropriate to notify the interface that we have attached
to or detached from an already running process. */
 
void (*deprecated_attach_hook) (void);
void (*deprecated_detach_hook) (void);
 
/* Called during long calculations to allow GUI to repair window damage, and to
check for stop buttons, etc... */
 
void (*deprecated_interactive_hook) (void);
 
/* Tell the GUI someone changed the register REGNO. -1 means
that the caller does not know which register changed or
that several registers have changed (see value_assign). */
void (*deprecated_register_changed_hook) (int regno);
 
/* Tell the GUI someone changed LEN bytes of memory at ADDR */
void (*deprecated_memory_changed_hook) (CORE_ADDR addr, int len);
 
/* Called when going to wait for the target. Usually allows the GUI to run
while waiting for target events. */
 
ptid_t (*deprecated_target_wait_hook) (ptid_t ptid,
struct target_waitstatus * status);
 
/* Used by UI as a wrapper around command execution. May do various things
like enabling/disabling buttons, etc... */
 
void (*deprecated_call_command_hook) (struct cmd_list_element * c, char *cmd,
int from_tty);
 
/* Called after a `set' command has finished. Is only run if the
`set' command succeeded. */
 
void (*deprecated_set_hook) (struct cmd_list_element * c);
 
/* Called when the current thread changes. Argument is thread id. */
 
void (*deprecated_context_hook) (int id);
 
/* Takes control from error (). Typically used to prevent longjmps out of the
middle of the GUI. Usually used in conjunction with a catch routine. */
 
void (*deprecated_error_hook) (void);
 
/* Handler for SIGHUP. */
 
#ifdef SIGHUP
/* NOTE 1999-04-29: This function will be static again, once we modify
gdb to use the event loop as the default command loop and we merge
event-top.c into this file, top.c */
/* static */ int
quit_cover (void *s)
{
caution = 0; /* Throw caution to the wind -- we're exiting.
This prevents asking the user dumb questions. */
quit_command ((char *) 0, 0);
return 0;
}
#endif /* defined SIGHUP */
/* Line number we are currently in in a file which is being sourced. */
/* NOTE 1999-04-29: This variable will be static again, once we modify
gdb to use the event loop as the default command loop and we merge
event-top.c into this file, top.c */
/* static */ int source_line_number;
 
/* Name of the file we are sourcing. */
/* NOTE 1999-04-29: This variable will be static again, once we modify
gdb to use the event loop as the default command loop and we merge
event-top.c into this file, top.c */
/* static */ char *source_file_name;
 
/* Clean up on error during a "source" command (or execution of a
user-defined command). */
 
void
do_restore_instream_cleanup (void *stream)
{
/* Restore the previous input stream. */
instream = stream;
}
 
/* Read commands from STREAM. */
void
read_command_file (FILE *stream)
{
struct cleanup *cleanups;
 
cleanups = make_cleanup (do_restore_instream_cleanup, instream);
instream = stream;
command_loop ();
do_cleanups (cleanups);
}
void (*pre_init_ui_hook) (void);
 
#ifdef __MSDOS__
void
do_chdir_cleanup (void *old_dir)
{
chdir (old_dir);
xfree (old_dir);
}
#endif
 
/* Execute the line P as a command.
Pass FROM_TTY as second argument to the defining function. */
 
void
execute_command (char *p, int from_tty)
{
struct cmd_list_element *c;
enum language flang;
static int warned = 0;
char *line;
free_all_values ();
 
/* Force cleanup of any alloca areas if using C alloca instead of
a builtin alloca. */
alloca (0);
 
/* This can happen when command_line_input hits end of file. */
if (p == NULL)
return;
 
target_log_command (p);
 
while (*p == ' ' || *p == '\t')
p++;
if (*p)
{
char *arg;
line = p;
 
/* If trace-commands is set then this will print this command. */
print_command_trace (p);
 
c = lookup_cmd (&p, cmdlist, "", 0, 1);
 
/* If the target is running, we allow only a limited set of
commands. */
if (target_can_async_p () && target_executing)
if (strcmp (c->name, "help") != 0
&& strcmp (c->name, "pwd") != 0
&& strcmp (c->name, "show") != 0
&& strcmp (c->name, "stop") != 0)
error (_("Cannot execute this command while the target is running."));
 
/* Pass null arg rather than an empty one. */
arg = *p ? p : 0;
 
/* FIXME: cagney/2002-02-02: The c->type test is pretty dodgy
while the is_complete_command(cfunc) test is just plain
bogus. They should both be replaced by a test of the form
c->strip_trailing_white_space_p. */
/* NOTE: cagney/2002-02-02: The function.cfunc in the below
can't be replaced with func. This is because it is the
cfunc, and not the func, that has the value that the
is_complete_command hack is testing for. */
/* Clear off trailing whitespace, except for set and complete
command. */
if (arg
&& c->type != set_cmd
&& !is_complete_command (c))
{
p = arg + strlen (arg) - 1;
while (p >= arg && (*p == ' ' || *p == '\t'))
p--;
*(p + 1) = '\0';
}
 
/* If this command has been pre-hooked, run the hook first. */
execute_cmd_pre_hook (c);
 
if (c->flags & DEPRECATED_WARN_USER)
deprecated_cmd_warning (&line);
 
if (c->class == class_user)
execute_user_command (c, arg);
else if (c->type == set_cmd || c->type == show_cmd)
do_setshow_command (arg, from_tty & caution, c);
else if (!cmd_func_p (c))
error (_("That is not a command, just a help topic."));
else if (deprecated_call_command_hook)
deprecated_call_command_hook (c, arg, from_tty & caution);
else
cmd_func (c, arg, from_tty & caution);
/* If this command has been post-hooked, run the hook last. */
execute_cmd_post_hook (c);
 
}
 
/* Tell the user if the language has changed (except first time). */
if (current_language != expected_language)
{
if (language_mode == language_mode_auto)
{
language_info (1); /* Print what changed. */
}
warned = 0;
}
 
/* Warn the user if the working language does not match the
language of the current frame. Only warn the user if we are
actually running the program, i.e. there is a stack. */
/* FIXME: This should be cacheing the frame and only running when
the frame changes. */
 
if (target_has_stack)
{
flang = get_frame_language ();
if (!warned
&& flang != language_unknown
&& flang != current_language->la_language)
{
printf_filtered ("%s\n", lang_frame_mismatch_warn);
warned = 1;
}
}
}
 
/* Read commands from `instream' and execute them
until end of file or error reading instream. */
 
void
command_loop (void)
{
struct cleanup *old_chain;
char *command;
int stdin_is_tty = ISATTY (stdin);
long time_at_cmd_start;
#ifdef HAVE_SBRK
long space_at_cmd_start = 0;
#endif
extern int display_time;
extern int display_space;
 
while (instream && !feof (instream))
{
if (window_hook && instream == stdin)
(*window_hook) (instream, get_prompt ());
 
quit_flag = 0;
if (instream == stdin && stdin_is_tty)
reinitialize_more_filter ();
old_chain = make_cleanup (null_cleanup, 0);
 
/* Get a command-line. This calls the readline package. */
command = command_line_input (instream == stdin ?
get_prompt () : (char *) NULL,
instream == stdin, "prompt");
if (command == 0)
return;
 
time_at_cmd_start = get_run_time ();
 
if (display_space)
{
#ifdef HAVE_SBRK
char *lim = (char *) sbrk (0);
space_at_cmd_start = lim - lim_at_start;
#endif
}
 
execute_command (command, instream == stdin);
/* Do any commands attached to breakpoint we stopped at. */
bpstat_do_actions (&stop_bpstat);
do_cleanups (old_chain);
 
if (display_time)
{
long cmd_time = get_run_time () - time_at_cmd_start;
 
printf_unfiltered (_("Command execution time: %ld.%06ld\n"),
cmd_time / 1000000, cmd_time % 1000000);
}
 
if (display_space)
{
#ifdef HAVE_SBRK
char *lim = (char *) sbrk (0);
long space_now = lim - lim_at_start;
long space_diff = space_now - space_at_cmd_start;
 
printf_unfiltered (_("Space used: %ld (%s%ld for this command)\n"),
space_now,
(space_diff >= 0 ? "+" : ""),
space_diff);
#endif
}
}
}
 
/* Read commands from `instream' and execute them until end of file or
error reading instream. This command loop doesnt care about any
such things as displaying time and space usage. If the user asks
for those, they won't work. */
void
simplified_command_loop (char *(*read_input_func) (char *),
void (*execute_command_func) (char *, int))
{
struct cleanup *old_chain;
char *command;
int stdin_is_tty = ISATTY (stdin);
 
while (instream && !feof (instream))
{
quit_flag = 0;
if (instream == stdin && stdin_is_tty)
reinitialize_more_filter ();
old_chain = make_cleanup (null_cleanup, 0);
 
/* Get a command-line. */
command = (*read_input_func) (instream == stdin ?
get_prompt () : (char *) NULL);
 
if (command == 0)
return;
 
(*execute_command_func) (command, instream == stdin);
 
/* Do any commands attached to breakpoint we stopped at. */
bpstat_do_actions (&stop_bpstat);
 
do_cleanups (old_chain);
}
}
/* Commands call this if they do not want to be repeated by null lines. */
 
void
dont_repeat (void)
{
if (server_command)
return;
 
/* If we aren't reading from standard input, we are saving the last
thing read from stdin in line and don't want to delete it. Null lines
won't repeat here in any case. */
if (instream == stdin)
*line = 0;
}
/* Read a line from the stream "instream" without command line editing.
 
It prints PROMPT_ARG once at the start.
Action is compatible with "readline", e.g. space for the result is
malloc'd and should be freed by the caller.
 
A NULL return means end of file. */
char *
gdb_readline (char *prompt_arg)
{
int c;
char *result;
int input_index = 0;
int result_size = 80;
 
if (prompt_arg)
{
/* Don't use a _filtered function here. It causes the assumed
character position to be off, since the newline we read from
the user is not accounted for. */
fputs_unfiltered (prompt_arg, gdb_stdout);
gdb_flush (gdb_stdout);
}
 
result = (char *) xmalloc (result_size);
 
while (1)
{
/* Read from stdin if we are executing a user defined command.
This is the right thing for prompt_for_continue, at least. */
c = fgetc (instream ? instream : stdin);
 
if (c == EOF)
{
if (input_index > 0)
/* The last line does not end with a newline. Return it, and
if we are called again fgetc will still return EOF and
we'll return NULL then. */
break;
xfree (result);
return NULL;
}
 
if (c == '\n')
{
if (input_index > 0 && result[input_index - 1] == '\r')
input_index--;
break;
}
 
result[input_index++] = c;
while (input_index >= result_size)
{
result_size *= 2;
result = (char *) xrealloc (result, result_size);
}
}
 
result[input_index++] = '\0';
return result;
}
 
/* Variables which control command line editing and history
substitution. These variables are given default values at the end
of this file. */
static int command_editing_p;
 
/* NOTE 1999-04-29: This variable will be static again, once we modify
gdb to use the event loop as the default command loop and we merge
event-top.c into this file, top.c */
 
/* static */ int history_expansion_p;
 
static int write_history_p;
static void
show_write_history_p (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("Saving of the history record on exit is %s.\n"),
value);
}
 
static int history_size;
static void
show_history_size (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("The size of the command history is %s.\n"),
value);
}
 
static char *history_filename;
static void
show_history_filename (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("\
The filename in which to record the command history is \"%s\".\n"),
value);
}
 
/* This is like readline(), but it has some gdb-specific behavior.
gdb may want readline in both the synchronous and async modes during
a single gdb invocation. At the ordinary top-level prompt we might
be using the async readline. That means we can't use
rl_pre_input_hook, since it doesn't work properly in async mode.
However, for a secondary prompt (" >", such as occurs during a
`define'), gdb wants a synchronous response.
 
We used to call readline() directly, running it in synchronous
mode. But mixing modes this way is not supported, and as of
readline 5.x it no longer works; the arrow keys come unbound during
the synchronous call. So we make a nested call into the event
loop. That's what gdb_readline_wrapper is for. */
 
/* A flag set as soon as gdb_readline_wrapper_line is called; we can't
rely on gdb_readline_wrapper_result, which might still be NULL if
the user types Control-D for EOF. */
static int gdb_readline_wrapper_done;
 
/* The result of the current call to gdb_readline_wrapper, once a newline
is seen. */
static char *gdb_readline_wrapper_result;
 
/* Any intercepted hook. Operate-and-get-next sets this, expecting it
to be called after the newline is processed (which will redisplay
the prompt). But in gdb_readline_wrapper we will not get a new
prompt until the next call, or until we return to the event loop.
So we disable this hook around the newline and restore it before we
return. */
static void (*saved_after_char_processing_hook) (void);
 
/* This function is called when readline has seen a complete line of
text. */
 
static void
gdb_readline_wrapper_line (char *line)
{
gdb_assert (!gdb_readline_wrapper_done);
gdb_readline_wrapper_result = line;
gdb_readline_wrapper_done = 1;
 
/* Prevent operate-and-get-next from acting too early. */
saved_after_char_processing_hook = after_char_processing_hook;
after_char_processing_hook = NULL;
 
/* Prevent parts of the prompt from being redisplayed if annotations
are enabled, and readline's state getting out of sync. */
if (async_command_editing_p)
rl_callback_handler_remove ();
}
 
struct gdb_readline_wrapper_cleanup
{
void (*handler_orig) (char *);
int already_prompted_orig;
};
 
static void
gdb_readline_wrapper_cleanup (void *arg)
{
struct gdb_readline_wrapper_cleanup *cleanup = arg;
 
rl_already_prompted = cleanup->already_prompted_orig;
 
gdb_assert (input_handler == gdb_readline_wrapper_line);
input_handler = cleanup->handler_orig;
gdb_readline_wrapper_result = NULL;
gdb_readline_wrapper_done = 0;
 
after_char_processing_hook = saved_after_char_processing_hook;
saved_after_char_processing_hook = NULL;
 
xfree (cleanup);
}
 
char *
gdb_readline_wrapper (char *prompt)
{
struct cleanup *back_to;
struct gdb_readline_wrapper_cleanup *cleanup;
char *retval;
 
cleanup = xmalloc (sizeof (*cleanup));
cleanup->handler_orig = input_handler;
input_handler = gdb_readline_wrapper_line;
 
cleanup->already_prompted_orig = rl_already_prompted;
 
back_to = make_cleanup (gdb_readline_wrapper_cleanup, cleanup);
 
/* Display our prompt and prevent double prompt display. */
display_gdb_prompt (prompt);
rl_already_prompted = 1;
 
if (after_char_processing_hook)
(*after_char_processing_hook) ();
gdb_assert (after_char_processing_hook == NULL);
 
/* gdb_do_one_event argument is unused. */
while (gdb_do_one_event (NULL) >= 0)
if (gdb_readline_wrapper_done)
break;
 
retval = gdb_readline_wrapper_result;
do_cleanups (back_to);
return retval;
}
 
#ifdef STOP_SIGNAL
static void
stop_sig (int signo)
{
#if STOP_SIGNAL == SIGTSTP
signal (SIGTSTP, SIG_DFL);
#if HAVE_SIGPROCMASK
{
sigset_t zero;
 
sigemptyset (&zero);
sigprocmask (SIG_SETMASK, &zero, 0);
}
#elif HAVE_SIGSETMASK
sigsetmask (0);
#endif
kill (getpid (), SIGTSTP);
signal (SIGTSTP, stop_sig);
#else
signal (STOP_SIGNAL, stop_sig);
#endif
printf_unfiltered ("%s", get_prompt ());
gdb_flush (gdb_stdout);
 
/* Forget about any previous command -- null line now will do nothing. */
dont_repeat ();
}
#endif /* STOP_SIGNAL */
 
/* Initialize signal handlers. */
static void
float_handler (int signo)
{
/* This message is based on ANSI C, section 4.7. Note that integer
divide by zero causes this, so "float" is a misnomer. */
signal (SIGFPE, float_handler);
error (_("Erroneous arithmetic operation."));
}
 
static void
do_nothing (int signo)
{
/* Under System V the default disposition of a signal is reinstated after
the signal is caught and delivered to an application process. On such
systems one must restore the replacement signal handler if one wishes
to continue handling the signal in one's program. On BSD systems this
is not needed but it is harmless, and it simplifies the code to just do
it unconditionally. */
signal (signo, do_nothing);
}
 
/* The current saved history number from operate-and-get-next.
This is -1 if not valid. */
static int operate_saved_history = -1;
 
/* This is put on the appropriate hook and helps operate-and-get-next
do its work. */
static void
gdb_rl_operate_and_get_next_completion (void)
{
int delta = where_history () - operate_saved_history;
/* The `key' argument to rl_get_previous_history is ignored. */
rl_get_previous_history (delta, 0);
operate_saved_history = -1;
 
/* readline doesn't automatically update the display for us. */
rl_redisplay ();
 
after_char_processing_hook = NULL;
rl_pre_input_hook = NULL;
}
 
/* This is a gdb-local readline command handler. It accepts the
current command line (like RET does) and, if this command was taken
from the history, arranges for the next command in the history to
appear on the command line when the prompt returns.
We ignore the arguments. */
static int
gdb_rl_operate_and_get_next (int count, int key)
{
int where;
 
/* Use the async hook. */
after_char_processing_hook = gdb_rl_operate_and_get_next_completion;
 
/* Find the current line, and find the next line to use. */
where = where_history();
 
/* FIXME: kettenis/20020817: max_input_history is renamed into
history_max_entries in readline-4.2. When we do a new readline
import, we should probably change it here too, even though
readline maintains backwards compatibility for now by still
defining max_input_history. */
if ((history_is_stifled () && (history_length >= max_input_history)) ||
(where >= history_length - 1))
operate_saved_history = where;
else
operate_saved_history = where + 1;
 
return rl_newline (1, key);
}
/* Read one line from the command input stream `instream'
into the local static buffer `linebuffer' (whose current length
is `linelength').
The buffer is made bigger as necessary.
Returns the address of the start of the line.
 
NULL is returned for end of file.
 
*If* the instream == stdin & stdin is a terminal, the line read
is copied into the file line saver (global var char *line,
length linesize) so that it can be duplicated.
 
This routine either uses fancy command line editing or
simple input as the user has requested. */
 
char *
command_line_input (char *prompt_arg, int repeat, char *annotation_suffix)
{
static char *linebuffer = 0;
static unsigned linelength = 0;
char *p;
char *p1;
char *rl;
char *local_prompt = prompt_arg;
char *nline;
char got_eof = 0;
 
/* The annotation suffix must be non-NULL. */
if (annotation_suffix == NULL)
annotation_suffix = "";
 
if (annotation_level > 1 && instream == stdin)
{
local_prompt = alloca ((prompt_arg == NULL ? 0 : strlen (prompt_arg))
+ strlen (annotation_suffix) + 40);
if (prompt_arg == NULL)
local_prompt[0] = '\0';
else
strcpy (local_prompt, prompt_arg);
strcat (local_prompt, "\n\032\032");
strcat (local_prompt, annotation_suffix);
strcat (local_prompt, "\n");
}
 
if (linebuffer == 0)
{
linelength = 80;
linebuffer = (char *) xmalloc (linelength);
}
 
p = linebuffer;
 
/* Control-C quits instantly if typed while in this loop
since it should not wait until the user types a newline. */
immediate_quit++;
#ifdef STOP_SIGNAL
if (job_control)
signal (STOP_SIGNAL, handle_stop_sig);
#endif
 
while (1)
{
/* Make sure that all output has been output. Some machines may let
you get away with leaving out some of the gdb_flush, but not all. */
wrap_here ("");
gdb_flush (gdb_stdout);
gdb_flush (gdb_stderr);
 
if (source_file_name != NULL)
++source_line_number;
 
if (annotation_level > 1 && instream == stdin)
{
puts_unfiltered ("\n\032\032pre-");
puts_unfiltered (annotation_suffix);
puts_unfiltered ("\n");
}
 
/* Don't use fancy stuff if not talking to stdin. */
if (deprecated_readline_hook && input_from_terminal_p ())
{
rl = (*deprecated_readline_hook) (local_prompt);
}
else if (command_editing_p && input_from_terminal_p ())
{
rl = gdb_readline_wrapper (local_prompt);
}
else
{
rl = gdb_readline (local_prompt);
}
 
if (annotation_level > 1 && instream == stdin)
{
puts_unfiltered ("\n\032\032post-");
puts_unfiltered (annotation_suffix);
puts_unfiltered ("\n");
}
 
if (!rl || rl == (char *) EOF)
{
got_eof = 1;
break;
}
if (strlen (rl) + 1 + (p - linebuffer) > linelength)
{
linelength = strlen (rl) + 1 + (p - linebuffer);
nline = (char *) xrealloc (linebuffer, linelength);
p += nline - linebuffer;
linebuffer = nline;
}
p1 = rl;
/* Copy line. Don't copy null at end. (Leaves line alone
if this was just a newline) */
while (*p1)
*p++ = *p1++;
 
xfree (rl); /* Allocated in readline. */
 
if (p == linebuffer || *(p - 1) != '\\')
break;
 
p--; /* Put on top of '\'. */
local_prompt = (char *) 0;
}
 
#ifdef STOP_SIGNAL
if (job_control)
signal (STOP_SIGNAL, SIG_DFL);
#endif
immediate_quit--;
 
if (got_eof)
return NULL;
 
#define SERVER_COMMAND_LENGTH 7
server_command =
(p - linebuffer > SERVER_COMMAND_LENGTH)
&& strncmp (linebuffer, "server ", SERVER_COMMAND_LENGTH) == 0;
if (server_command)
{
/* Note that we don't set `line'. Between this and the check in
dont_repeat, this insures that repeating will still do the
right thing. */
*p = '\0';
return linebuffer + SERVER_COMMAND_LENGTH;
}
 
/* Do history expansion if that is wished. */
if (history_expansion_p && instream == stdin
&& ISATTY (instream))
{
char *history_value;
int expanded;
 
*p = '\0'; /* Insert null now. */
expanded = history_expand (linebuffer, &history_value);
if (expanded)
{
/* Print the changes. */
printf_unfiltered ("%s\n", history_value);
 
/* If there was an error, call this function again. */
if (expanded < 0)
{
xfree (history_value);
return command_line_input (prompt_arg, repeat, annotation_suffix);
}
if (strlen (history_value) > linelength)
{
linelength = strlen (history_value) + 1;
linebuffer = (char *) xrealloc (linebuffer, linelength);
}
strcpy (linebuffer, history_value);
p = linebuffer + strlen (linebuffer);
}
xfree (history_value);
}
 
/* If we just got an empty line, and that is supposed
to repeat the previous command, return the value in the
global buffer. */
if (repeat && p == linebuffer)
return line;
for (p1 = linebuffer; *p1 == ' ' || *p1 == '\t'; p1++);
if (repeat && !*p1)
return line;
 
*p = 0;
 
/* Add line to history if appropriate. */
if (instream == stdin
&& ISATTY (stdin) && *linebuffer)
add_history (linebuffer);
 
/* Note: lines consisting solely of comments are added to the command
history. This is useful when you type a command, and then
realize you don't want to execute it quite yet. You can comment
out the command and then later fetch it from the value history
and remove the '#'. The kill ring is probably better, but some
people are in the habit of commenting things out. */
if (*p1 == '#')
*p1 = '\0'; /* Found a comment. */
 
/* Save into global buffer if appropriate. */
if (repeat)
{
if (linelength > linesize)
{
line = xrealloc (line, linelength);
linesize = linelength;
}
strcpy (line, linebuffer);
return line;
}
 
return linebuffer;
}
/* Print the GDB banner. */
void
print_gdb_version (struct ui_file *stream)
{
/* From GNU coding standards, first line is meant to be easy for a
program to parse, and is just canonical program name and version
number, which starts after last space. */
 
fprintf_filtered (stream, "GNU gdb %s\n", version);
 
/* Second line is a copyright notice. */
 
fprintf_filtered (stream, "Copyright (C) 2008 Free Software Foundation, Inc.\n");
 
/* Following the copyright is a brief statement that the program is
free software, that users are free to copy and change it on
certain conditions, that it is covered by the GNU GPL, and that
there is no warranty. */
 
fprintf_filtered (stream, "\
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n\
This is free software: you are free to change and redistribute it.\n\
There is NO WARRANTY, to the extent permitted by law. Type \"show copying\"\n\
and \"show warranty\" for details.\n");
 
/* After the required info we print the configuration information. */
 
fprintf_filtered (stream, "This GDB was configured as \"");
if (strcmp (host_name, target_name) != 0)
{
fprintf_filtered (stream, "--host=%s --target=%s", host_name, target_name);
}
else
{
fprintf_filtered (stream, "%s", host_name);
}
fprintf_filtered (stream, "\".");
}
/* get_prompt: access method for the GDB prompt string. */
 
char *
get_prompt (void)
{
return PROMPT (0);
}
 
void
set_prompt (char *s)
{
/* ??rehrauer: I don't know why this fails, since it looks as though
assignments to prompt are wrapped in calls to savestring...
if (prompt != NULL)
xfree (prompt);
*/
PROMPT (0) = savestring (s, strlen (s));
}
 
/* If necessary, make the user confirm that we should quit. Return
non-zero if we should quit, zero if we shouldn't. */
 
int
quit_confirm (void)
{
if (! ptid_equal (inferior_ptid, null_ptid) && target_has_execution)
{
char *s;
 
/* This is something of a hack. But there's no reliable way to
see if a GUI is running. The `use_windows' variable doesn't
cut it. */
if (deprecated_init_ui_hook)
s = "A debugging session is active.\nDo you still want to close the debugger?";
else if (attach_flag)
s = "The program is running. Quit anyway (and detach it)? ";
else
s = "The program is running. Exit anyway? ";
 
if (!query ("%s", s))
return 0;
}
 
return 1;
}
 
/* Helper routine for quit_force that requires error handling. */
 
struct qt_args
{
char *args;
int from_tty;
};
 
static int
quit_target (void *arg)
{
struct qt_args *qt = (struct qt_args *)arg;
 
if (! ptid_equal (inferior_ptid, null_ptid) && target_has_execution)
{
if (attach_flag)
target_detach (qt->args, qt->from_tty);
else
target_kill ();
}
 
/* UDI wants this, to kill the TIP. */
target_close (&current_target, 1);
 
/* Save the history information if it is appropriate to do so. */
if (write_history_p && history_filename)
write_history (history_filename);
 
do_final_cleanups (ALL_CLEANUPS); /* Do any final cleanups before exiting */
 
return 0;
}
 
/* Quit without asking for confirmation. */
 
void
quit_force (char *args, int from_tty)
{
int exit_code = 0;
struct qt_args qt;
 
/* An optional expression may be used to cause gdb to terminate with the
value of that expression. */
if (args)
{
struct value *val = parse_and_eval (args);
 
exit_code = (int) value_as_long (val);
}
else if (return_child_result)
exit_code = return_child_result_value;
 
qt.args = args;
qt.from_tty = from_tty;
 
/* We want to handle any quit errors and exit regardless. */
catch_errors (quit_target, &qt,
"Quitting: ", RETURN_MASK_ALL);
 
exit (exit_code);
}
 
/* Returns whether GDB is running on a terminal and input is
currently coming from that terminal. */
 
int
input_from_terminal_p (void)
{
if (gdb_has_a_terminal () && instream == stdin)
return 1;
 
/* If INSTREAM is unset, and we are not in a user command, we
must be in Insight. That's like having a terminal, for our
purposes. */
if (instream == NULL && !in_user_command)
return 1;
 
return 0;
}
static void
dont_repeat_command (char *ignored, int from_tty)
{
*line = 0; /* Can't call dont_repeat here because we're not
necessarily reading from stdin. */
}
/* Functions to manipulate command line editing control variables. */
 
/* Number of commands to print in each call to show_commands. */
#define Hist_print 10
void
show_commands (char *args, int from_tty)
{
/* Index for history commands. Relative to history_base. */
int offset;
 
/* Number of the history entry which we are planning to display next.
Relative to history_base. */
static int num = 0;
 
/* The first command in the history which doesn't exist (i.e. one more
than the number of the last command). Relative to history_base. */
int hist_len;
 
/* Print out some of the commands from the command history. */
/* First determine the length of the history list. */
hist_len = history_size;
for (offset = 0; offset < history_size; offset++)
{
if (!history_get (history_base + offset))
{
hist_len = offset;
break;
}
}
 
if (args)
{
if (args[0] == '+' && args[1] == '\0')
/* "info editing +" should print from the stored position. */
;
else
/* "info editing <exp>" should print around command number <exp>. */
num = (parse_and_eval_long (args) - history_base) - Hist_print / 2;
}
/* "show commands" means print the last Hist_print commands. */
else
{
num = hist_len - Hist_print;
}
 
if (num < 0)
num = 0;
 
/* If there are at least Hist_print commands, we want to display the last
Hist_print rather than, say, the last 6. */
if (hist_len - num < Hist_print)
{
num = hist_len - Hist_print;
if (num < 0)
num = 0;
}
 
for (offset = num; offset < num + Hist_print && offset < hist_len; offset++)
{
printf_filtered ("%5d %s\n", history_base + offset,
(history_get (history_base + offset))->line);
}
 
/* The next command we want to display is the next one that we haven't
displayed yet. */
num += Hist_print;
 
/* If the user repeats this command with return, it should do what
"show commands +" does. This is unnecessary if arg is null,
because "show commands +" is not useful after "show commands". */
if (from_tty && args)
{
args[0] = '+';
args[1] = '\0';
}
}
 
/* Called by do_setshow_command. */
static void
set_history_size_command (char *args, int from_tty, struct cmd_list_element *c)
{
if (history_size == INT_MAX)
unstifle_history ();
else if (history_size >= 0)
stifle_history (history_size);
else
{
history_size = INT_MAX;
error (_("History size must be non-negative"));
}
}
 
void
set_history (char *args, int from_tty)
{
printf_unfiltered (_("\"set history\" must be followed by the name of a history subcommand.\n"));
help_list (sethistlist, "set history ", -1, gdb_stdout);
}
 
void
show_history (char *args, int from_tty)
{
cmd_show_list (showhistlist, from_tty, "");
}
 
int info_verbose = 0; /* Default verbose msgs off */
 
/* Called by do_setshow_command. An elaborate joke. */
void
set_verbose (char *args, int from_tty, struct cmd_list_element *c)
{
char *cmdname = "verbose";
struct cmd_list_element *showcmd;
 
showcmd = lookup_cmd_1 (&cmdname, showlist, NULL, 1);
 
if (info_verbose)
{
c->doc = "Set verbose printing of informational messages.";
showcmd->doc = "Show verbose printing of informational messages.";
}
else
{
c->doc = "Set verbosity.";
showcmd->doc = "Show verbosity.";
}
}
 
/* Init the history buffer. Note that we are called after the init file(s)
* have been read so that the user can change the history file via his
* .gdbinit file (for instance). The GDBHISTFILE environment variable
* overrides all of this.
*/
 
void
init_history (void)
{
char *tmpenv;
 
tmpenv = getenv ("HISTSIZE");
if (tmpenv)
history_size = atoi (tmpenv);
else if (!history_size)
history_size = 256;
 
stifle_history (history_size);
 
tmpenv = getenv ("GDBHISTFILE");
if (tmpenv)
history_filename = savestring (tmpenv, strlen (tmpenv));
else if (!history_filename)
{
/* We include the current directory so that if the user changes
directories the file written will be the same as the one
that was read. */
#ifdef __MSDOS__
/* No leading dots in file names are allowed on MSDOS. */
history_filename = concat (current_directory, "/_gdb_history",
(char *)NULL);
#else
history_filename = concat (current_directory, "/.gdb_history",
(char *)NULL);
#endif
}
read_history (history_filename);
}
 
static void
show_new_async_prompt (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("Gdb's prompt is \"%s\".\n"), value);
}
 
static void
show_async_command_editing_p (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("\
Editing of command lines as they are typed is %s.\n"),
value);
}
 
static void
show_annotation_level (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("Annotation_level is %s.\n"), value);
}
 
static void
show_exec_done_display_p (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("\
Notification of completion for asynchronous execution commands is %s.\n"),
value);
}
static void
init_main (void)
{
struct cmd_list_element *c;
 
/* initialize the prompt stack to a simple "(gdb) " prompt or to
whatever the DEFAULT_PROMPT is. */
the_prompts.top = 0;
PREFIX (0) = "";
PROMPT (0) = savestring (DEFAULT_PROMPT, strlen (DEFAULT_PROMPT));
SUFFIX (0) = "";
/* Set things up for annotation_level > 1, if the user ever decides
to use it. */
async_annotation_suffix = "prompt";
/* Set the variable associated with the setshow prompt command. */
new_async_prompt = savestring (PROMPT (0), strlen (PROMPT (0)));
 
/* If gdb was started with --annotate=2, this is equivalent to the
user entering the command 'set annotate 2' at the gdb prompt, so
we need to do extra processing. */
if (annotation_level > 1)
set_async_annotation_level (NULL, 0, NULL);
 
/* Set the important stuff up for command editing. */
command_editing_p = 1;
history_expansion_p = 0;
write_history_p = 0;
 
/* Setup important stuff for command line editing. */
rl_completion_entry_function = readline_line_completion_function;
rl_completer_word_break_characters = default_word_break_characters ();
rl_completer_quote_characters = get_gdb_completer_quote_characters ();
rl_readline_name = "gdb";
rl_terminal_name = getenv ("TERM");
 
/* The name for this defun comes from Bash, where it originated.
15 is Control-o, the same binding this function has in Bash. */
rl_add_defun ("operate-and-get-next", gdb_rl_operate_and_get_next, 15);
 
add_setshow_string_cmd ("prompt", class_support,
&new_async_prompt, _("\
Set gdb's prompt"), _("\
Show gdb's prompt"), NULL,
set_async_prompt,
show_new_async_prompt,
&setlist, &showlist);
 
add_com ("dont-repeat", class_support, dont_repeat_command, _("\
Don't repeat this command.\n\
Primarily used inside of user-defined commands that should not be repeated when\n\
hitting return."));
 
add_setshow_boolean_cmd ("editing", class_support,
&async_command_editing_p, _("\
Set editing of command lines as they are typed."), _("\
Show editing of command lines as they are typed."), _("\
Use \"on\" to enable the editing, and \"off\" to disable it.\n\
Without an argument, command line editing is enabled. To edit, use\n\
EMACS-like or VI-like commands like control-P or ESC."),
set_async_editing_command,
show_async_command_editing_p,
&setlist, &showlist);
 
add_setshow_boolean_cmd ("save", no_class, &write_history_p, _("\
Set saving of the history record on exit."), _("\
Show saving of the history record on exit."), _("\
Use \"on\" to enable the saving, and \"off\" to disable it.\n\
Without an argument, saving is enabled."),
NULL,
show_write_history_p,
&sethistlist, &showhistlist);
 
add_setshow_integer_cmd ("size", no_class, &history_size, _("\
Set the size of the command history,"), _("\
Show the size of the command history,"), _("\
ie. the number of previous commands to keep a record of."),
set_history_size_command,
show_history_size,
&sethistlist, &showhistlist);
 
add_setshow_filename_cmd ("filename", no_class, &history_filename, _("\
Set the filename in which to record the command history"), _("\
Show the filename in which to record the command history"), _("\
(the list of previous commands of which a record is kept)."),
NULL,
show_history_filename,
&sethistlist, &showhistlist);
 
add_setshow_boolean_cmd ("confirm", class_support, &caution, _("\
Set whether to confirm potentially dangerous operations."), _("\
Show whether to confirm potentially dangerous operations."), NULL,
NULL,
show_caution,
&setlist, &showlist);
 
add_setshow_zinteger_cmd ("annotate", class_obscure, &annotation_level, _("\
Set annotation_level."), _("\
Show annotation_level."), _("\
0 == normal; 1 == fullname (for use when running under emacs)\n\
2 == output annotated suitably for use by programs that control GDB."),
set_async_annotation_level,
show_annotation_level,
&setlist, &showlist);
 
add_setshow_boolean_cmd ("exec-done-display", class_support,
&exec_done_display_p, _("\
Set notification of completion for asynchronous execution commands."), _("\
Show notification of completion for asynchronous execution commands."), _("\
Use \"on\" to enable the notification, and \"off\" to disable it."),
NULL,
show_exec_done_display_p,
&setlist, &showlist);
}
 
/* JPB: Some picky Ubuntu GCC compilers don't like the result of getcwd being
ignored (even if you cast it to void). So capture the value and ignore
THAT. */
void
gdb_init (char *argv0)
{
char *res; /* For getcwd result */
if (pre_init_ui_hook)
pre_init_ui_hook ();
 
/* Run the init function of each source file */
 
res = getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)); /* JPB */
current_directory = gdb_dirbuf;
 
#ifdef __MSDOS__
/* Make sure we return to the original directory upon exit, come
what may, since the OS doesn't do that for us. */
make_final_cleanup (do_chdir_cleanup, xstrdup (current_directory));
#endif
 
init_cmd_lists (); /* This needs to be done first */
initialize_targets (); /* Setup target_terminal macros for utils.c */
initialize_utils (); /* Make errors and warnings possible */
initialize_all_files ();
initialize_current_architecture ();
init_cli_cmds();
init_main (); /* But that omits this file! Do it now */
 
initialize_stdin_serial ();
 
async_init_signals ();
 
/* We need a default language for parsing expressions, so simple things like
"set width 0" won't fail if no language is explicitly set in a config file
or implicitly set by reading an executable during startup. */
set_language (language_c);
expected_language = current_language; /* don't warn about the change. */
 
/* Allow another UI to initialize. If the UI fails to initialize,
and it wants GDB to revert to the CLI, it should clear
deprecated_init_ui_hook. */
if (deprecated_init_ui_hook)
deprecated_init_ui_hook (argv0);
}
/trunk/gdb-6.8/gdb/mi/mi-cmd-env.c
0,0 → 1,285
/* MI Command Set - environment commands.
 
Copyright (C) 2002, 2003, 2004, 2007, 2008 Free Software Foundation, Inc.
 
Contributed by Red Hat Inc.
 
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/>. */
 
#include "defs.h"
#include "inferior.h"
#include "value.h"
#include "mi-out.h"
#include "mi-cmds.h"
#include "mi-getopt.h"
#include "symtab.h"
#include "target.h"
#include "environ.h"
#include "command.h"
#include "ui-out.h"
#include "top.h"
 
#include "gdb_string.h"
#include "gdb_stat.h"
 
static void env_mod_path (char *dirname, char **which_path);
extern void _initialize_mi_cmd_env (void);
 
static const char path_var_name[] = "PATH";
static char *orig_path = NULL;
 
/* The following is copied from mi-main.c so for m1 and below we can
perform old behavior and use cli commands. If ARGS is non-null,
append it to the CMD. */
static void
env_execute_cli_command (const char *cmd, const char *args)
{
if (cmd != 0)
{
struct cleanup *old_cleanups;
char *run;
if (args != NULL)
run = xstrprintf ("%s %s", cmd, args);
else
run = xstrdup (cmd);
old_cleanups = make_cleanup (xfree, run);
execute_command ( /*ui */ run, 0 /*from_tty */ );
do_cleanups (old_cleanups);
return;
}
}
 
 
/* Print working directory. */
/* JPB: Some picky Ubuntu GCC compilers don't like the result of getcwd being
ignored (even if you cast it to void). So capture the value and ignore
THAT. */
enum mi_cmd_result
mi_cmd_env_pwd (char *command, char **argv, int argc)
{
char *res; /* For getcwd result */
if (argc > 0)
error (_("mi_cmd_env_pwd: No arguments required"));
if (mi_version (uiout) < 2)
{
env_execute_cli_command ("pwd", NULL);
return MI_CMD_DONE;
}
/* Otherwise the mi level is 2 or higher. */
 
res = getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)); /* JPB */
ui_out_field_string (uiout, "cwd", gdb_dirbuf);
 
return MI_CMD_DONE;
}
 
/* Change working directory. */
enum mi_cmd_result
mi_cmd_env_cd (char *command, char **argv, int argc)
{
if (argc == 0 || argc > 1)
error (_("mi_cmd_env_cd: Usage DIRECTORY"));
env_execute_cli_command ("cd", argv[0]);
 
return MI_CMD_DONE;
}
 
static void
env_mod_path (char *dirname, char **which_path)
{
if (dirname == 0 || dirname[0] == '\0')
return;
 
/* Call add_path with last arg 0 to indicate not to parse for
separator characters. */
add_path (dirname, which_path, 0);
}
 
/* Add one or more directories to start of executable search path. */
enum mi_cmd_result
mi_cmd_env_path (char *command, char **argv, int argc)
{
char *exec_path;
char *env;
int reset = 0;
int optind = 0;
int i;
char *optarg;
enum opt
{
RESET_OPT
};
static struct mi_opt opts[] =
{
{"r", RESET_OPT, 0},
{ 0, 0, 0 }
};
 
dont_repeat ();
 
if (mi_version (uiout) < 2)
{
for (i = argc - 1; i >= 0; --i)
env_execute_cli_command ("path", argv[i]);
return MI_CMD_DONE;
}
 
/* Otherwise the mi level is 2 or higher. */
while (1)
{
int opt = mi_getopt ("mi_cmd_env_path", argc, argv, opts,
&optind, &optarg);
if (opt < 0)
break;
switch ((enum opt) opt)
{
case RESET_OPT:
reset = 1;
break;
}
}
argv += optind;
argc -= optind;
 
 
if (reset)
{
/* Reset implies resetting to original path first. */
exec_path = xstrdup (orig_path);
}
else
{
/* Otherwise, get current path to modify. */
env = get_in_environ (inferior_environ, path_var_name);
 
/* Can be null if path is not set. */
if (!env)
env = "";
exec_path = xstrdup (env);
}
 
for (i = argc - 1; i >= 0; --i)
env_mod_path (argv[i], &exec_path);
 
set_in_environ (inferior_environ, path_var_name, exec_path);
xfree (exec_path);
env = get_in_environ (inferior_environ, path_var_name);
ui_out_field_string (uiout, "path", env);
 
return MI_CMD_DONE;
}
 
/* Add zero or more directories to the front of the source path. */
enum mi_cmd_result
mi_cmd_env_dir (char *command, char **argv, int argc)
{
int i;
int optind = 0;
int reset = 0;
char *optarg;
enum opt
{
RESET_OPT
};
static struct mi_opt opts[] =
{
{"r", RESET_OPT, 0},
{ 0, 0, 0 }
};
 
dont_repeat ();
 
if (mi_version (uiout) < 2)
{
for (i = argc - 1; i >= 0; --i)
env_execute_cli_command ("dir", argv[i]);
return MI_CMD_DONE;
}
 
/* Otherwise mi level is 2 or higher. */
while (1)
{
int opt = mi_getopt ("mi_cmd_env_dir", argc, argv, opts,
&optind, &optarg);
if (opt < 0)
break;
switch ((enum opt) opt)
{
case RESET_OPT:
reset = 1;
break;
}
}
argv += optind;
argc -= optind;
 
if (reset)
{
/* Reset means setting to default path first. */
xfree (source_path);
init_source_path ();
}
 
for (i = argc - 1; i >= 0; --i)
env_mod_path (argv[i], &source_path);
init_last_source_visited ();
 
ui_out_field_string (uiout, "source-path", source_path);
forget_cached_source_info ();
 
return MI_CMD_DONE;
}
 
/* Set the inferior terminal device name. */
enum mi_cmd_result
mi_cmd_inferior_tty_set (char *command, char **argv, int argc)
{
set_inferior_io_terminal (argv[0]);
 
return MI_CMD_DONE;
}
 
/* Print the inferior terminal device name */
enum mi_cmd_result
mi_cmd_inferior_tty_show (char *command, char **argv, int argc)
{
const char *inferior_io_terminal = get_inferior_io_terminal ();
if ( !mi_valid_noargs ("mi_cmd_inferior_tty_show", argc, argv))
error (_("mi_cmd_inferior_tty_show: Usage: No args"));
 
if (inferior_io_terminal)
ui_out_field_string (uiout, "inferior_tty_terminal", inferior_io_terminal);
 
return MI_CMD_DONE;
}
 
void
_initialize_mi_cmd_env (void)
{
char *env;
 
/* We want original execution path to reset to, if desired later. */
env = get_in_environ (inferior_environ, path_var_name);
 
/* Can be null if path is not set. */
if (!env)
env = "";
orig_path = xstrdup (env);
}
/trunk/gdb-6.8/gdb/main.c
0,0 → 1,976
/* Top level stuff for GDB, the GNU debugger.
 
Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
Free Software Foundation, Inc.
 
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/>. */
 
#include "defs.h"
#include "top.h"
#include "target.h"
#include "inferior.h"
#include "symfile.h"
#include "gdbcore.h"
 
#include "exceptions.h"
#include "getopt.h"
 
#include <sys/types.h>
#include "gdb_stat.h"
#include <ctype.h>
 
#include "gdb_string.h"
#include "event-loop.h"
#include "ui-out.h"
 
#include "interps.h"
#include "main.h"
 
/* If nonzero, display time usage both at startup and for each command. */
 
int display_time;
 
/* If nonzero, display space usage both at startup and for each command. */
 
int display_space;
 
/* The selected interpreter. This will be used as a set command
variable, so it should always be malloc'ed - since
do_setshow_command will free it. */
char *interpreter_p;
 
/* Whether xdb commands will be handled */
int xdb_commands = 0;
 
/* Whether dbx commands will be handled */
int dbx_commands = 0;
 
/* System root path, used to find libraries etc. */
char *gdb_sysroot = 0;
 
struct ui_file *gdb_stdout;
struct ui_file *gdb_stderr;
struct ui_file *gdb_stdlog;
struct ui_file *gdb_stdin;
/* target IO streams */
struct ui_file *gdb_stdtargin;
struct ui_file *gdb_stdtarg;
struct ui_file *gdb_stdtargerr;
 
/* Support for the --batch-silent option. */
int batch_silent = 0;
 
/* Support for --return-child-result option.
Set the default to -1 to return error in the case
that the program does not run or does not complete. */
int return_child_result = 0;
int return_child_result_value = -1;
 
/* Whether to enable writing into executable and core files */
extern int write_files;
 
static void print_gdb_help (struct ui_file *);
 
/* These two are used to set the external editor commands when gdb is farming
out files to be edited by another program. */
 
extern char *external_editor_command;
 
/* Call command_loop. If it happens to return, pass that through as a
non-zero return status. */
 
static int
captured_command_loop (void *data)
{
current_interp_command_loop ();
/* FIXME: cagney/1999-11-05: A correct command_loop() implementaton
would clean things up (restoring the cleanup chain) to the state
they were just prior to the call. Technically, this means that
the do_cleanups() below is redundant. Unfortunately, many FUNCs
are not that well behaved. do_cleanups should either be replaced
with a do_cleanups call (to cover the problem) or an assertion
check to detect bad FUNCs code. */
do_cleanups (ALL_CLEANUPS);
/* If the command_loop returned, normally (rather than threw an
error) we try to quit. If the quit is aborted, catch_errors()
which called this catch the signal and restart the command
loop. */
quit_command (NULL, instream == stdin);
return 1;
}
 
/* JPB: Some picky Ubuntu GCC compilers don't like the result of getcwd being
ignored (even if you cast it to void). So capture the value and ignore
THAT. */
static int
captured_main (void *data)
{
char *res; /* For getcwd result */
 
struct captured_main_args *context = data;
int argc = context->argc;
char **argv = context->argv;
static int quiet = 0;
static int batch = 0;
static int set_args = 0;
 
/* Pointers to various arguments from command line. */
char *symarg = NULL;
char *execarg = NULL;
char *pidarg = NULL;
char *corearg = NULL;
char *pid_or_core_arg = NULL;
char *cdarg = NULL;
char *ttyarg = NULL;
 
/* These are static so that we can take their address in an initializer. */
static int print_help;
static int print_version;
 
/* Pointers to all arguments of --command option. */
struct cmdarg {
enum {
CMDARG_FILE,
CMDARG_COMMAND
} type;
char *string;
} *cmdarg;
/* Allocated size of cmdarg. */
int cmdsize;
/* Number of elements of cmdarg used. */
int ncmd;
 
/* Indices of all arguments of --directory option. */
char **dirarg;
/* Allocated size. */
int dirsize;
/* Number of elements used. */
int ndir;
 
struct stat homebuf, cwdbuf;
char *homedir;
 
int i;
 
long time_at_startup = get_run_time ();
 
#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES)
setlocale (LC_MESSAGES, "");
#endif
#if defined (HAVE_SETLOCALE)
setlocale (LC_CTYPE, "");
#endif
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
 
#ifdef HAVE_SBRK
lim_at_start = (char *) sbrk (0);
#endif
 
cmdsize = 1;
cmdarg = (struct cmdarg *) xmalloc (cmdsize * sizeof (*cmdarg));
ncmd = 0;
dirsize = 1;
dirarg = (char **) xmalloc (dirsize * sizeof (*dirarg));
ndir = 0;
 
quit_flag = 0;
line = (char *) xmalloc (linesize);
line[0] = '\0'; /* Terminate saved (now empty) cmd line */
instream = stdin;
 
res = getcwd (gdb_dirbuf, sizeof (gdb_dirbuf)); /* JPB */
current_directory = gdb_dirbuf;
 
gdb_stdout = stdio_fileopen (stdout);
gdb_stderr = stdio_fileopen (stderr);
gdb_stdlog = gdb_stderr; /* for moment */
gdb_stdtarg = gdb_stderr; /* for moment */
gdb_stdin = stdio_fileopen (stdin);
gdb_stdtargerr = gdb_stderr; /* for moment */
gdb_stdtargin = gdb_stdin; /* for moment */
 
/* Set the sysroot path. */
#ifdef TARGET_SYSTEM_ROOT_RELOCATABLE
gdb_sysroot = make_relative_prefix (argv[0], BINDIR, TARGET_SYSTEM_ROOT);
if (gdb_sysroot)
{
struct stat s;
int res = 0;
 
if (stat (gdb_sysroot, &s) == 0)
if (S_ISDIR (s.st_mode))
res = 1;
 
if (res == 0)
{
xfree (gdb_sysroot);
gdb_sysroot = xstrdup (TARGET_SYSTEM_ROOT);
}
}
else
gdb_sysroot = xstrdup (TARGET_SYSTEM_ROOT);
#else
gdb_sysroot = xstrdup (TARGET_SYSTEM_ROOT);
#endif
 
/* Canonicalize the sysroot path. */
if (*gdb_sysroot)
{
char *canon_sysroot = lrealpath (gdb_sysroot);
if (canon_sysroot)
{
xfree (gdb_sysroot);
gdb_sysroot = canon_sysroot;
}
}
 
#ifdef DEBUGDIR_RELOCATABLE
debug_file_directory = make_relative_prefix (argv[0], BINDIR, DEBUGDIR);
if (debug_file_directory)
{
struct stat s;
int res = 0;
 
if (stat (debug_file_directory, &s) == 0)
if (S_ISDIR (s.st_mode))
res = 1;
 
if (res == 0)
{
xfree (debug_file_directory);
debug_file_directory = xstrdup (DEBUGDIR);
}
}
else
debug_file_directory = xstrdup (DEBUGDIR);
#else
debug_file_directory = xstrdup (DEBUGDIR);
#endif
 
/* Canonicalize the debugfile path. */
if (*debug_file_directory)
{
char *canon_debug = lrealpath (debug_file_directory);
if (canon_debug)
{
xfree (debug_file_directory);
debug_file_directory = canon_debug;
}
}
 
/* There will always be an interpreter. Either the one passed into
this captured main, or one specified by the user at start up, or
the console. Initialize the interpreter to the one requested by
the application. */
interpreter_p = xstrdup (context->interpreter_p);
 
/* Parse arguments and options. */
{
int c;
/* When var field is 0, use flag field to record the equivalent
short option (or arbitrary numbers starting at 10 for those
with no equivalent). */
enum {
OPT_SE = 10,
OPT_CD,
OPT_ANNOTATE,
OPT_STATISTICS,
OPT_TUI,
OPT_NOWINDOWS,
OPT_WINDOWS
};
static struct option long_options[] =
{
{"tui", no_argument, 0, OPT_TUI},
{"xdb", no_argument, &xdb_commands, 1},
{"dbx", no_argument, &dbx_commands, 1},
{"readnow", no_argument, &readnow_symbol_files, 1},
{"r", no_argument, &readnow_symbol_files, 1},
{"quiet", no_argument, &quiet, 1},
{"q", no_argument, &quiet, 1},
{"silent", no_argument, &quiet, 1},
{"nx", no_argument, &inhibit_gdbinit, 1},
{"n", no_argument, &inhibit_gdbinit, 1},
{"batch-silent", no_argument, 0, 'B'},
{"batch", no_argument, &batch, 1},
{"epoch", no_argument, &epoch_interface, 1},
 
/* This is a synonym for "--annotate=1". --annotate is now preferred,
but keep this here for a long time because people will be running
emacses which use --fullname. */
{"fullname", no_argument, 0, 'f'},
{"f", no_argument, 0, 'f'},
 
{"annotate", required_argument, 0, OPT_ANNOTATE},
{"help", no_argument, &print_help, 1},
{"se", required_argument, 0, OPT_SE},
{"symbols", required_argument, 0, 's'},
{"s", required_argument, 0, 's'},
{"exec", required_argument, 0, 'e'},
{"e", required_argument, 0, 'e'},
{"core", required_argument, 0, 'c'},
{"c", required_argument, 0, 'c'},
{"pid", required_argument, 0, 'p'},
{"p", required_argument, 0, 'p'},
{"command", required_argument, 0, 'x'},
{"eval-command", required_argument, 0, 'X'},
{"version", no_argument, &print_version, 1},
{"x", required_argument, 0, 'x'},
{"ex", required_argument, 0, 'X'},
#ifdef GDBTK
{"tclcommand", required_argument, 0, 'z'},
{"enable-external-editor", no_argument, 0, 'y'},
{"editor-command", required_argument, 0, 'w'},
#endif
{"ui", required_argument, 0, 'i'},
{"interpreter", required_argument, 0, 'i'},
{"i", required_argument, 0, 'i'},
{"directory", required_argument, 0, 'd'},
{"d", required_argument, 0, 'd'},
{"cd", required_argument, 0, OPT_CD},
{"tty", required_argument, 0, 't'},
{"baud", required_argument, 0, 'b'},
{"b", required_argument, 0, 'b'},
{"nw", no_argument, NULL, OPT_NOWINDOWS},
{"nowindows", no_argument, NULL, OPT_NOWINDOWS},
{"w", no_argument, NULL, OPT_WINDOWS},
{"windows", no_argument, NULL, OPT_WINDOWS},
{"statistics", no_argument, 0, OPT_STATISTICS},
{"write", no_argument, &write_files, 1},
{"args", no_argument, &set_args, 1},
{"l", required_argument, 0, 'l'},
{"return-child-result", no_argument, &return_child_result, 1},
{0, no_argument, 0, 0}
};
 
while (1)
{
int option_index;
 
c = getopt_long_only (argc, argv, "",
long_options, &option_index);
if (c == EOF || set_args)
break;
 
/* Long option that takes an argument. */
if (c == 0 && long_options[option_index].flag == 0)
c = long_options[option_index].val;
 
switch (c)
{
case 0:
/* Long option that just sets a flag. */
break;
case OPT_SE:
symarg = optarg;
execarg = optarg;
break;
case OPT_CD:
cdarg = optarg;
break;
case OPT_ANNOTATE:
/* FIXME: what if the syntax is wrong (e.g. not digits)? */
annotation_level = atoi (optarg);
break;
case OPT_STATISTICS:
/* Enable the display of both time and space usage. */
display_time = 1;
display_space = 1;
break;
case OPT_TUI:
/* --tui is equivalent to -i=tui. */
#ifdef TUI
xfree (interpreter_p);
interpreter_p = xstrdup (INTERP_TUI);
#else
fprintf_unfiltered (gdb_stderr,
_("%s: TUI mode is not supported\n"),
argv[0]);
exit (1);
#endif
break;
case OPT_WINDOWS:
/* FIXME: cagney/2003-03-01: Not sure if this option is
actually useful, and if it is, what it should do. */
#ifdef GDBTK
/* --windows is equivalent to -i=insight. */
xfree (interpreter_p);
interpreter_p = xstrdup (INTERP_INSIGHT);
#endif
use_windows = 1;
break;
case OPT_NOWINDOWS:
/* -nw is equivalent to -i=console. */
xfree (interpreter_p);
interpreter_p = xstrdup (INTERP_CONSOLE);
use_windows = 0;
break;
case 'f':
annotation_level = 1;
/* We have probably been invoked from emacs. Disable window interface. */
use_windows = 0;
break;
case 's':
symarg = optarg;
break;
case 'e':
execarg = optarg;
break;
case 'c':
corearg = optarg;
break;
case 'p':
pidarg = optarg;
break;
case 'x':
cmdarg[ncmd].type = CMDARG_FILE;
cmdarg[ncmd++].string = optarg;
if (ncmd >= cmdsize)
{
cmdsize *= 2;
cmdarg = xrealloc ((char *) cmdarg,
cmdsize * sizeof (*cmdarg));
}
break;
case 'X':
cmdarg[ncmd].type = CMDARG_COMMAND;
cmdarg[ncmd++].string = optarg;
if (ncmd >= cmdsize)
{
cmdsize *= 2;
cmdarg = xrealloc ((char *) cmdarg,
cmdsize * sizeof (*cmdarg));
}
break;
case 'B':
batch = batch_silent = 1;
gdb_stdout = ui_file_new();
break;
#ifdef GDBTK
case 'z':
{
extern int gdbtk_test (char *);
if (!gdbtk_test (optarg))
{
fprintf_unfiltered (gdb_stderr, _("%s: unable to load tclcommand file \"%s\""),
argv[0], optarg);
exit (1);
}
break;
}
case 'y':
/* Backwards compatibility only. */
break;
case 'w':
{
external_editor_command = xstrdup (optarg);
break;
}
#endif /* GDBTK */
case 'i':
xfree (interpreter_p);
interpreter_p = xstrdup (optarg);
break;
case 'd':
dirarg[ndir++] = optarg;
if (ndir >= dirsize)
{
dirsize *= 2;
dirarg = (char **) xrealloc ((char *) dirarg,
dirsize * sizeof (*dirarg));
}
break;
case 't':
ttyarg = optarg;
break;
case 'q':
quiet = 1;
break;
case 'b':
{
int i;
char *p;
 
i = strtol (optarg, &p, 0);
if (i == 0 && p == optarg)
 
/* Don't use *_filtered or warning() (which relies on
current_target) until after initialize_all_files(). */
 
fprintf_unfiltered
(gdb_stderr,
_("warning: could not set baud rate to `%s'.\n"), optarg);
else
baud_rate = i;
}
break;
case 'l':
{
int i;
char *p;
 
i = strtol (optarg, &p, 0);
if (i == 0 && p == optarg)
 
/* Don't use *_filtered or warning() (which relies on
current_target) until after initialize_all_files(). */
 
fprintf_unfiltered
(gdb_stderr,
_("warning: could not set timeout limit to `%s'.\n"), optarg);
else
remote_timeout = i;
}
break;
 
case '?':
fprintf_unfiltered (gdb_stderr,
_("Use `%s --help' for a complete list of options.\n"),
argv[0]);
exit (1);
}
}
 
/* If --help or --version, disable window interface. */
if (print_help || print_version)
{
use_windows = 0;
}
 
if (set_args)
{
/* The remaining options are the command-line options for the
inferior. The first one is the sym/exec file, and the rest
are arguments. */
if (optind >= argc)
{
fprintf_unfiltered (gdb_stderr,
_("%s: `--args' specified but no program specified\n"),
argv[0]);
exit (1);
}
symarg = argv[optind];
execarg = argv[optind];
++optind;
set_inferior_args_vector (argc - optind, &argv[optind]);
}
else
{
/* OK, that's all the options. */
 
/* The first argument, if specified, is the name of the
executable. */
if (optind < argc)
{
symarg = argv[optind];
execarg = argv[optind];
optind++;
}
 
/* If the user hasn't already specified a PID or the name of a
core file, then a second optional argument is allowed. If
present, this argument should be interpreted as either a
PID or a core file, whichever works. */
if (pidarg == NULL && corearg == NULL && optind < argc)
{
pid_or_core_arg = argv[optind];
optind++;
}
 
/* Any argument left on the command line is unexpected and
will be ignored. Inform the user. */
if (optind < argc)
fprintf_unfiltered (gdb_stderr, _("\
Excess command line arguments ignored. (%s%s)\n"),
argv[optind],
(optind == argc - 1) ? "" : " ...");
}
if (batch)
quiet = 1;
}
 
/* Initialize all files. Give the interpreter a chance to take
control of the console via the deprecated_init_ui_hook (). */
gdb_init (argv[0]);
 
/* Do these (and anything which might call wrap_here or *_filtered)
after initialize_all_files() but before the interpreter has been
installed. Otherwize the help/version messages will be eaten by
the interpreter's output handler. */
 
if (print_version)
{
print_gdb_version (gdb_stdout);
wrap_here ("");
printf_filtered ("\n");
exit (0);
}
 
if (print_help)
{
print_gdb_help (gdb_stdout);
fputs_unfiltered ("\n", gdb_stdout);
exit (0);
}
 
/* FIXME: cagney/2003-02-03: The big hack (part 1 of 2) that lets
GDB retain the old MI1 interpreter startup behavior. Output the
copyright message before the interpreter is installed. That way
it isn't encapsulated in MI output. */
if (!quiet && strcmp (interpreter_p, INTERP_MI1) == 0)
{
/* Print all the junk at the top, with trailing "..." if we are about
to read a symbol file (possibly slowly). */
print_gdb_version (gdb_stdout);
if (symarg)
printf_filtered ("..");
wrap_here ("");
printf_filtered ("\n");
gdb_flush (gdb_stdout); /* Force to screen during slow operations */
}
 
 
/* Install the default UI. All the interpreters should have had a
look at things by now. Initialize the default interpreter. */
 
{
/* Find it. */
struct interp *interp = interp_lookup (interpreter_p);
if (interp == NULL)
error (_("Interpreter `%s' unrecognized"), interpreter_p);
/* Install it. */
if (!interp_set (interp))
{
fprintf_unfiltered (gdb_stderr,
"Interpreter `%s' failed to initialize.\n",
interpreter_p);
exit (1);
}
}
 
/* FIXME: cagney/2003-02-03: The big hack (part 2 of 2) that lets
GDB retain the old MI1 interpreter startup behavior. Output the
copyright message after the interpreter is installed when it is
any sane interpreter. */
if (!quiet && !current_interp_named_p (INTERP_MI1))
{
/* Print all the junk at the top, with trailing "..." if we are about
to read a symbol file (possibly slowly). */
print_gdb_version (gdb_stdout);
if (symarg)
printf_filtered ("..");
wrap_here ("");
printf_filtered ("\n");
gdb_flush (gdb_stdout); /* Force to screen during slow operations */
}
 
/* Set off error and warning messages with a blank line. */
error_pre_print = "\n";
quit_pre_print = error_pre_print;
warning_pre_print = _("\nwarning: ");
 
/* Read and execute $HOME/.gdbinit file, if it exists. This is done
*before* all the command line arguments are processed; it sets
global parameters, which are independent of what file you are
debugging or what directory you are in. */
homedir = getenv ("HOME");
if (homedir)
{
char *homeinit = xstrprintf ("%s/%s", homedir, gdbinit);
 
if (!inhibit_gdbinit)
{
catch_command_errors (source_script, homeinit, 0, RETURN_MASK_ALL);
}
 
/* Do stats; no need to do them elsewhere since we'll only
need them if homedir is set. Make sure that they are
zero in case one of them fails (this guarantees that they
won't match if either exists). */
 
memset (&homebuf, 0, sizeof (struct stat));
memset (&cwdbuf, 0, sizeof (struct stat));
 
stat (homeinit, &homebuf);
stat (gdbinit, &cwdbuf); /* We'll only need this if
homedir was set. */
xfree (homeinit);
}
 
/* Now perform all the actions indicated by the arguments. */
if (cdarg != NULL)
{
catch_command_errors (cd_command, cdarg, 0, RETURN_MASK_ALL);
}
 
for (i = 0; i < ndir; i++)
catch_command_errors (directory_switch, dirarg[i], 0, RETURN_MASK_ALL);
xfree (dirarg);
 
if (execarg != NULL
&& symarg != NULL
&& strcmp (execarg, symarg) == 0)
{
/* The exec file and the symbol-file are the same. If we can't
open it, better only print one error message.
catch_command_errors returns non-zero on success! */
if (catch_command_errors (exec_file_attach, execarg, !batch, RETURN_MASK_ALL))
catch_command_errors (symbol_file_add_main, symarg, 0, RETURN_MASK_ALL);
}
else
{
if (execarg != NULL)
catch_command_errors (exec_file_attach, execarg, !batch, RETURN_MASK_ALL);
if (symarg != NULL)
catch_command_errors (symbol_file_add_main, symarg, 0, RETURN_MASK_ALL);
}
 
if (corearg && pidarg)
error (_("\
Can't attach to process and specify a core file at the same time."));
 
if (corearg != NULL)
catch_command_errors (core_file_command, corearg,
!batch, RETURN_MASK_ALL);
else if (pidarg != NULL)
catch_command_errors (attach_command, pidarg,
!batch, RETURN_MASK_ALL);
else if (pid_or_core_arg)
{
/* The user specified 'gdb program pid' or gdb program core'.
If pid_or_core_arg's first character is a digit, try attach
first and then corefile. Otherwise try just corefile. */
 
if (isdigit (pid_or_core_arg[0]))
{
if (catch_command_errors (attach_command, pid_or_core_arg,
!batch, RETURN_MASK_ALL) == 0)
catch_command_errors (core_file_command, pid_or_core_arg,
!batch, RETURN_MASK_ALL);
}
else /* Can't be a pid, better be a corefile. */
catch_command_errors (core_file_command, pid_or_core_arg,
!batch, RETURN_MASK_ALL);
}
 
if (ttyarg != NULL)
catch_command_errors (tty_command, ttyarg, !batch, RETURN_MASK_ALL);
 
/* Error messages should no longer be distinguished with extra output. */
error_pre_print = NULL;
quit_pre_print = NULL;
warning_pre_print = _("warning: ");
 
/* Read the .gdbinit file in the current directory, *if* it isn't
the same as the $HOME/.gdbinit file (it should exist, also). */
 
if (!homedir
|| memcmp ((char *) &homebuf, (char *) &cwdbuf, sizeof (struct stat)))
if (!inhibit_gdbinit)
{
catch_command_errors (source_script, gdbinit, 0, RETURN_MASK_ALL);
}
 
for (i = 0; i < ncmd; i++)
{
#if 0
/* NOTE: cagney/1999-11-03: SET_TOP_LEVEL() was a macro that
expanded into a call to setjmp(). */
if (!SET_TOP_LEVEL ()) /* NB: This is #if 0'd out */
{
/* NOTE: I am commenting this out, because it is not clear
where this feature is used. It is very old and
undocumented. ezannoni: 1999-05-04 */
#if 0
if (cmdarg[i][0] == '-' && cmdarg[i][1] == '\0')
read_command_file (stdin);
else
#endif
source_script (cmdarg[i], !batch);
do_cleanups (ALL_CLEANUPS);
}
#endif
if (cmdarg[i].type == CMDARG_FILE)
catch_command_errors (source_script, cmdarg[i].string,
!batch, RETURN_MASK_ALL);
else /* cmdarg[i].type == CMDARG_COMMAND */
catch_command_errors (execute_command, cmdarg[i].string,
!batch, RETURN_MASK_ALL);
}
xfree (cmdarg);
 
/* Read in the old history after all the command files have been read. */
init_history ();
 
if (batch)
{
/* We have hit the end of the batch file. */
quit_force (NULL, 0);
}
 
/* Do any host- or target-specific hacks. This is used for i960 targets
to force the user to set a nindy target and spec its parameters. */
 
#ifdef BEFORE_MAIN_LOOP_HOOK
BEFORE_MAIN_LOOP_HOOK;
#endif
 
/* Show time and/or space usage. */
 
if (display_time)
{
long init_time = get_run_time () - time_at_startup;
 
printf_unfiltered (_("Startup time: %ld.%06ld\n"),
init_time / 1000000, init_time % 1000000);
}
 
if (display_space)
{
#ifdef HAVE_SBRK
extern char **environ;
char *lim = (char *) sbrk (0);
 
printf_unfiltered (_("Startup size: data size %ld\n"),
(long) (lim - (char *) &environ));
#endif
}
 
#if 0
/* FIXME: cagney/1999-11-06: The original main loop was like: */
while (1)
{
if (!SET_TOP_LEVEL ())
{
do_cleanups (ALL_CLEANUPS); /* Do complete cleanup */
/* GUIs generally have their own command loop, mainloop, or
whatever. This is a good place to gain control because
many error conditions will end up here via longjmp(). */
if (deprecated_command_loop_hook)
deprecated_command_loop_hook ();
else
deprecated_command_loop ();
quit_command ((char *) 0, instream == stdin);
}
}
/* NOTE: If the command_loop() returned normally, the loop would
attempt to exit by calling the function quit_command(). That
function would either call exit() or throw an error returning
control to SET_TOP_LEVEL. */
/* NOTE: The function do_cleanups() was called once each time round
the loop. The usefulness of the call isn't clear. If an error
was thrown, everything would have already been cleaned up. If
command_loop() returned normally and quit_command() was called,
either exit() or error() (again cleaning up) would be called. */
#endif
/* NOTE: cagney/1999-11-07: There is probably no reason for not
moving this loop and the code found in captured_command_loop()
into the command_loop() proper. The main thing holding back that
change - SET_TOP_LEVEL() - has been eliminated. */
while (1)
{
catch_errors (captured_command_loop, 0, "", RETURN_MASK_ALL);
}
/* No exit -- exit is through quit_command. */
}
 
int
gdb_main (struct captured_main_args *args)
{
use_windows = args->use_windows;
catch_errors (captured_main, args, "", RETURN_MASK_ALL);
/* The only way to end up here is by an error (normal exit is
handled by quit_force()), hence always return an error status. */
return 1;
}
 
 
/* Don't use *_filtered for printing help. We don't want to prompt
for continue no matter how small the screen or how much we're going
to print. */
 
static void
print_gdb_help (struct ui_file *stream)
{
fputs_unfiltered (_("\
This is the GNU debugger. Usage:\n\n\
gdb [options] [executable-file [core-file or process-id]]\n\
gdb [options] --args executable-file [inferior-arguments ...]\n\n\
Options:\n\n\
"), stream);
fputs_unfiltered (_("\
--args Arguments after executable-file are passed to inferior\n\
"), stream);
fputs_unfiltered (_("\
-b BAUDRATE Set serial port baud rate used for remote debugging.\n\
--batch Exit after processing options.\n\
--batch-silent As for --batch, but suppress all gdb stdout output.\n\
--return-child-result\n\
GDB exit code will be the child's exit code.\n\
--cd=DIR Change current directory to DIR.\n\
--command=FILE, -x Execute GDB commands from FILE.\n\
--eval-command=COMMAND, -ex\n\
Execute a single GDB command.\n\
May be used multiple times and in conjunction\n\
with --command.\n\
--core=COREFILE Analyze the core dump COREFILE.\n\
--pid=PID Attach to running process PID.\n\
"), stream);
fputs_unfiltered (_("\
--dbx DBX compatibility mode.\n\
--directory=DIR Search for source files in DIR.\n\
--epoch Output information used by epoch emacs-GDB interface.\n\
--exec=EXECFILE Use EXECFILE as the executable.\n\
--fullname Output information used by emacs-GDB interface.\n\
--help Print this message.\n\
"), stream);
fputs_unfiltered (_("\
--interpreter=INTERP\n\
Select a specific interpreter / user interface\n\
"), stream);
fputs_unfiltered (_("\
-l TIMEOUT Set timeout in seconds for remote debugging.\n\
--nw Do not use a window interface.\n\
--nx Do not read "), stream);
fputs_unfiltered (gdbinit, stream);
fputs_unfiltered (_(" file.\n\
--quiet Do not print version number on startup.\n\
--readnow Fully read symbol files on first access.\n\
"), stream);
fputs_unfiltered (_("\
--se=FILE Use FILE as symbol file and executable file.\n\
--symbols=SYMFILE Read symbols from SYMFILE.\n\
--tty=TTY Use TTY for input/output by the program being debugged.\n\
"), stream);
#if defined(TUI)
fputs_unfiltered (_("\
--tui Use a terminal user interface.\n\
"), stream);
#endif
fputs_unfiltered (_("\
--version Print version information and then exit.\n\
-w Use a window interface.\n\
--write Set writing into executable and core files.\n\
--xdb XDB compatibility mode.\n\
"), stream);
fputs_unfiltered (_("\n\
For more information, type \"help\" from within GDB, or consult the\n\
GDB manual (available as on-line info or a printed manual).\n\
Report bugs to \"bug-gdb@gnu.org\".\
"), stream);
}
/trunk/gdb-6.8/gdb/cli/cli-cmds.c
0,0 → 1,1431
/* GDB CLI commands.
 
Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2007, 2008
Free Software Foundation, Inc.
 
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/>. */
 
#include "defs.h"
#include "readline/readline.h"
#include "readline/tilde.h"
#include "completer.h"
#include "target.h" /* For baud_rate, remote_debug and remote_timeout */
#include "gdb_wait.h" /* For shell escape implementation */
#include "gdb_regex.h" /* Used by apropos_command */
#include "gdb_string.h"
#include "gdb_vfork.h"
#include "linespec.h"
#include "expression.h"
#include "frame.h"
#include "value.h"
#include "language.h"
#include "filenames.h" /* for DOSish file names */
#include "objfiles.h"
#include "source.h"
#include "disasm.h"
 
#include "ui-out.h"
 
#include "top.h"
#include "cli/cli-decode.h"
#include "cli/cli-script.h"
#include "cli/cli-setshow.h"
#include "cli/cli-cmds.h"
 
#ifdef TUI
#include "tui/tui.h" /* For tui_active et.al. */
#endif
 
#include <fcntl.h>
 
/* Prototypes for local command functions */
 
static void complete_command (char *, int);
 
static void echo_command (char *, int);
 
static void pwd_command (char *, int);
 
static void show_version (char *, int);
 
static void help_command (char *, int);
 
static void show_command (char *, int);
 
static void info_command (char *, int);
 
static void show_debug (char *, int);
 
static void set_debug (char *, int);
 
static void show_user (char *, int);
 
static void make_command (char *, int);
 
static void shell_escape (char *, int);
 
static void edit_command (char *, int);
 
static void list_command (char *, int);
 
void apropos_command (char *, int);
 
/* Prototypes for local utility functions */
 
static void ambiguous_line_spec (struct symtabs_and_lines *);
/* Limit the call depth of user-defined commands */
int max_user_call_depth;
 
/* Define all cmd_list_elements. */
 
/* Chain containing all defined commands. */
 
struct cmd_list_element *cmdlist;
 
/* Chain containing all defined info subcommands. */
 
struct cmd_list_element *infolist;
 
/* Chain containing all defined enable subcommands. */
 
struct cmd_list_element *enablelist;
 
/* Chain containing all defined disable subcommands. */
 
struct cmd_list_element *disablelist;
 
/* Chain containing all defined toggle subcommands. */
 
struct cmd_list_element *togglelist;
 
/* Chain containing all defined stop subcommands. */
 
struct cmd_list_element *stoplist;
 
/* Chain containing all defined delete subcommands. */
 
struct cmd_list_element *deletelist;
 
/* Chain containing all defined detach subcommands. */
 
struct cmd_list_element *detachlist;
 
/* Chain containing all defined "enable breakpoint" subcommands. */
 
struct cmd_list_element *enablebreaklist;
 
/* Chain containing all defined set subcommands */
 
struct cmd_list_element *setlist;
 
/* Chain containing all defined unset subcommands */
 
struct cmd_list_element *unsetlist;
 
/* Chain containing all defined show subcommands. */
 
struct cmd_list_element *showlist;
 
/* Chain containing all defined \"set history\". */
 
struct cmd_list_element *sethistlist;
 
/* Chain containing all defined \"show history\". */
 
struct cmd_list_element *showhistlist;
 
/* Chain containing all defined \"unset history\". */
 
struct cmd_list_element *unsethistlist;
 
/* Chain containing all defined maintenance subcommands. */
 
struct cmd_list_element *maintenancelist;
 
/* Chain containing all defined "maintenance info" subcommands. */
 
struct cmd_list_element *maintenanceinfolist;
 
/* Chain containing all defined "maintenance print" subcommands. */
 
struct cmd_list_element *maintenanceprintlist;
 
struct cmd_list_element *setprintlist;
 
struct cmd_list_element *showprintlist;
 
struct cmd_list_element *setdebuglist;
 
struct cmd_list_element *showdebuglist;
 
struct cmd_list_element *setchecklist;
 
struct cmd_list_element *showchecklist;
 
/* Command tracing state. */
 
int source_verbose = 0;
int trace_commands = 0;
/* Utility used everywhere when at least one argument is needed and
none is supplied. */
 
void
error_no_arg (char *why)
{
error (_("Argument required (%s)."), why);
}
 
/* The "info" command is defined as a prefix, with allow_unknown = 0.
Therefore, its own definition is called only for "info" with no args. */
 
static void
info_command (char *arg, int from_tty)
{
printf_unfiltered (_("\"info\" must be followed by the name of an info command.\n"));
help_list (infolist, "info ", -1, gdb_stdout);
}
 
/* The "show" command with no arguments shows all the settings. */
 
static void
show_command (char *arg, int from_tty)
{
cmd_show_list (showlist, from_tty, "");
}
/* Provide documentation on command or list given by COMMAND. FROM_TTY
is ignored. */
 
static void
help_command (char *command, int from_tty)
{
help_cmd (command, gdb_stdout);
}
/* String compare function for qsort. */
static int
compare_strings (const void *arg1, const void *arg2)
{
const char **s1 = (const char **) arg1;
const char **s2 = (const char **) arg2;
return strcmp (*s1, *s2);
}
 
/* The "complete" command is used by Emacs to implement completion. */
 
static void
complete_command (char *arg, int from_tty)
{
int i;
int argpoint;
char **completions, *point, *arg_prefix;
 
dont_repeat ();
 
if (arg == NULL)
arg = "";
argpoint = strlen (arg);
 
/* complete_line assumes that its first argument is somewhere within,
and except for filenames at the beginning of, the word to be completed.
The following crude imitation of readline's word-breaking tries to
accomodate this. */
point = arg + argpoint;
while (point > arg)
{
if (strchr (rl_completer_word_break_characters, point[-1]) != 0)
break;
point--;
}
 
arg_prefix = alloca (point - arg + 1);
memcpy (arg_prefix, arg, point - arg);
arg_prefix[point - arg] = 0;
 
completions = complete_line (point, arg, argpoint);
 
if (completions)
{
int item, size;
 
for (size = 0; completions[size]; ++size)
;
qsort (completions, size, sizeof (char *), compare_strings);
 
/* We do extra processing here since we only want to print each
unique item once. */
item = 0;
while (item < size)
{
int next_item;
printf_unfiltered ("%s%s\n", arg_prefix, completions[item]);
next_item = item + 1;
while (next_item < size
&& ! strcmp (completions[item], completions[next_item]))
{
xfree (completions[next_item]);
++next_item;
}
 
xfree (completions[item]);
item = next_item;
}
 
xfree (completions);
}
}
 
int
is_complete_command (struct cmd_list_element *c)
{
return cmd_cfunc_eq (c, complete_command);
}
 
static void
show_version (char *args, int from_tty)
{
immediate_quit++;
print_gdb_version (gdb_stdout);
printf_filtered ("\n");
immediate_quit--;
}
 
/* Handle the quit command. */
 
void
quit_command (char *args, int from_tty)
{
if (!quit_confirm ())
error (_("Not confirmed."));
quit_force (args, from_tty);
}
 
 
/* JPB: Some picky Ubuntu GCC compilers don't like the result of getcwd being
ignored (even if you cast it to void). So capture the value and ignore
THAT. */
static void
pwd_command (char *args, int from_tty)
{
char *res; /* For getcwd result */
if (args)
error (_("The \"pwd\" command does not take an argument: %s"), args);
res = getcwd (gdb_dirbuf, sizeof (gdb_dirbuf));
 
if (strcmp (gdb_dirbuf, current_directory) != 0)
printf_unfiltered (_("Working directory %s\n (canonically %s).\n"),
current_directory, gdb_dirbuf);
else
printf_unfiltered (_("Working directory %s.\n"), current_directory);
}
 
void
cd_command (char *dir, int from_tty)
{
int len;
/* Found something other than leading repetitions of "/..". */
int found_real_path;
char *p;
 
/* If the new directory is absolute, repeat is a no-op; if relative,
repeat might be useful but is more likely to be a mistake. */
dont_repeat ();
 
if (dir == 0)
error_no_arg (_("new working directory"));
 
dir = tilde_expand (dir);
make_cleanup (xfree, dir);
 
if (chdir (dir) < 0)
perror_with_name (dir);
 
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
/* There's too much mess with DOSish names like "d:", "d:.",
"d:./foo" etc. Instead of having lots of special #ifdef'ed code,
simply get the canonicalized name of the current directory. */
dir = getcwd (gdb_dirbuf, sizeof (gdb_dirbuf));
#endif
 
len = strlen (dir);
if (IS_DIR_SEPARATOR (dir[len - 1]))
{
/* Remove the trailing slash unless this is a root directory
(including a drive letter on non-Unix systems). */
if (!(len == 1) /* "/" */
#ifdef HAVE_DOS_BASED_FILE_SYSTEM
&& !(len == 3 && dir[1] == ':') /* "d:/" */
#endif
)
len--;
}
 
dir = savestring (dir, len);
if (IS_ABSOLUTE_PATH (dir))
current_directory = dir;
else
{
if (IS_DIR_SEPARATOR (current_directory[strlen (current_directory) - 1]))
current_directory = concat (current_directory, dir, (char *)NULL);
else
current_directory = concat (current_directory, SLASH_STRING,
dir, (char *)NULL);
xfree (dir);
}
 
/* Now simplify any occurrences of `.' and `..' in the pathname. */
 
found_real_path = 0;
for (p = current_directory; *p;)
{
if (IS_DIR_SEPARATOR (p[0]) && p[1] == '.'
&& (p[2] == 0 || IS_DIR_SEPARATOR (p[2])))
strcpy (p, p + 2);
else if (IS_DIR_SEPARATOR (p[0]) && p[1] == '.' && p[2] == '.'
&& (p[3] == 0 || IS_DIR_SEPARATOR (p[3])))
{
if (found_real_path)
{
/* Search backwards for the directory just before the "/.."
and obliterate it and the "/..". */
char *q = p;
while (q != current_directory && !IS_DIR_SEPARATOR (q[-1]))
--q;
 
if (q == current_directory)
/* current_directory is
a relative pathname ("can't happen"--leave it alone). */
++p;
else
{
strcpy (q - 1, p + 3);
p = q - 1;
}
}
else
/* We are dealing with leading repetitions of "/..", for example
"/../..", which is the Mach super-root. */
p += 3;
}
else
{
found_real_path = 1;
++p;
}
}
 
forget_cached_source_info ();
 
if (from_tty)
pwd_command ((char *) 0, 1);
}
void
source_script (char *file, int from_tty)
{
FILE *stream;
struct cleanup *old_cleanups;
char *full_pathname = NULL;
int fd;
 
if (file == NULL || *file == 0)
{
error (_("source command requires file name of file to source."));
}
 
file = tilde_expand (file);
old_cleanups = make_cleanup (xfree, file);
 
/* Search for and open 'file' on the search path used for source
files. Put the full location in 'full_pathname'. */
fd = openp (source_path, OPF_TRY_CWD_FIRST,
file, O_RDONLY, 0, &full_pathname);
 
/* Use the full path name, if it is found. */
if (full_pathname != NULL && fd != -1)
{
file = full_pathname;
}
 
if (fd == -1)
{
if (from_tty)
perror_with_name (file);
else
return;
}
 
stream = fdopen (fd, FOPEN_RT);
script_from_file (stream, file);
 
do_cleanups (old_cleanups);
}
 
/* Return the source_verbose global variable to its previous state
on exit from the source command, by whatever means. */
static void
source_verbose_cleanup (void *old_value)
{
source_verbose = *(int *)old_value;
xfree (old_value);
}
 
static void
source_command (char *args, int from_tty)
{
struct cleanup *old_cleanups;
char *file = args;
int *old_source_verbose = xmalloc (sizeof(int));
 
*old_source_verbose = source_verbose;
old_cleanups = make_cleanup (source_verbose_cleanup, old_source_verbose);
 
/* -v causes the source command to run in verbose mode.
We still have to be able to handle filenames with spaces in a
backward compatible way, so buildargv is not appropriate. */
 
if (args)
{
/* Make sure leading white space does not break the comparisons. */
while (isspace(args[0]))
args++;
 
/* Is -v the first thing in the string? */
if (args[0] == '-' && args[1] == 'v' && isspace (args[2]))
{
source_verbose = 1;
 
/* Trim -v and whitespace from the filename. */
file = &args[3];
while (isspace (file[0]))
file++;
}
}
 
source_script (file, from_tty);
}
 
 
static void
echo_command (char *text, int from_tty)
{
char *p = text;
int c;
 
if (text)
while ((c = *p++) != '\0')
{
if (c == '\\')
{
/* \ at end of argument is used after spaces
so they won't be lost. */
if (*p == 0)
return;
 
c = parse_escape (&p);
if (c >= 0)
printf_filtered ("%c", c);
}
else
printf_filtered ("%c", c);
}
 
/* Force this output to appear now. */
wrap_here ("");
gdb_flush (gdb_stdout);
}
 
static void
shell_escape (char *arg, int from_tty)
{
#if defined(CANT_FORK) || \
(!defined(HAVE_WORKING_VFORK) && !defined(HAVE_WORKING_FORK))
/* If ARG is NULL, they want an inferior shell, but `system' just
reports if the shell is available when passed a NULL arg. */
int rc = system (arg ? arg : "");
 
if (!arg)
arg = "inferior shell";
 
if (rc == -1)
{
fprintf_unfiltered (gdb_stderr, "Cannot execute %s: %s\n", arg,
safe_strerror (errno));
gdb_flush (gdb_stderr);
}
else if (rc)
{
fprintf_unfiltered (gdb_stderr, "%s exited with status %d\n", arg, rc);
gdb_flush (gdb_stderr);
}
#ifdef GLOBAL_CURDIR
/* Make sure to return to the directory GDB thinks it is, in case the
shell command we just ran changed it. */
chdir (current_directory);
#endif
#else /* Can fork. */
int rc, status, pid;
 
if ((pid = vfork ()) == 0)
{
char *p, *user_shell;
 
if ((user_shell = (char *) getenv ("SHELL")) == NULL)
user_shell = "/bin/sh";
 
/* Get the name of the shell for arg0 */
if ((p = strrchr (user_shell, '/')) == NULL)
p = user_shell;
else
p++; /* Get past '/' */
 
if (!arg)
execl (user_shell, p, (char *) 0);
else
execl (user_shell, p, "-c", arg, (char *) 0);
 
fprintf_unfiltered (gdb_stderr, "Cannot execute %s: %s\n", user_shell,
safe_strerror (errno));
gdb_flush (gdb_stderr);
_exit (0177);
}
 
if (pid != -1)
while ((rc = wait (&status)) != pid && rc != -1)
;
else
error (_("Fork failed"));
#endif /* Can fork. */
}
 
static void
edit_command (char *arg, int from_tty)
{
struct symtabs_and_lines sals;
struct symtab_and_line sal;
struct symbol *sym;
char *arg1;
int cmdlen, log10;
unsigned m;
char *editor;
char *p, *fn;
 
/* Pull in the current default source line if necessary */
if (arg == 0)
{
set_default_source_symtab_and_line ();
sal = get_current_source_symtab_and_line ();
}
 
/* bare "edit" edits file with present line. */
 
if (arg == 0)
{
if (sal.symtab == 0)
error (_("No default source file yet."));
sal.line += get_lines_to_list () / 2;
}
else
{
 
/* Now should only be one argument -- decode it in SAL */
 
arg1 = arg;
sals = decode_line_1 (&arg1, 0, 0, 0, 0, 0);
 
if (! sals.nelts) return; /* C++ */
if (sals.nelts > 1) {
ambiguous_line_spec (&sals);
xfree (sals.sals);
return;
}
 
sal = sals.sals[0];
xfree (sals.sals);
 
if (*arg1)
error (_("Junk at end of line specification."));
 
/* if line was specified by address,
first print exactly which line, and which file.
In this case, sal.symtab == 0 means address is outside
of all known source files, not that user failed to give a filename. */
if (*arg == '*')
{
if (sal.symtab == 0)
/* FIXME-32x64--assumes sal.pc fits in long. */
error (_("No source file for address %s."),
hex_string ((unsigned long) sal.pc));
sym = find_pc_function (sal.pc);
if (sym)
{
deprecated_print_address_numeric (sal.pc, 1, gdb_stdout);
printf_filtered (" is in ");
fputs_filtered (SYMBOL_PRINT_NAME (sym), gdb_stdout);
printf_filtered (" (%s:%d).\n", sal.symtab->filename, sal.line);
}
else
{
deprecated_print_address_numeric (sal.pc, 1, gdb_stdout);
printf_filtered (" is at %s:%d.\n",
sal.symtab->filename, sal.line);
}
}
 
/* If what was given does not imply a symtab, it must be an undebuggable
symbol which means no source code. */
 
if (sal.symtab == 0)
error (_("No line number known for %s."), arg);
}
 
if ((editor = (char *) getenv ("EDITOR")) == NULL)
editor = "/bin/ex";
 
/* Approximate base-10 log of line to 1 unit for digit count */
for(log10=32, m=0x80000000; !(sal.line & m) && log10>0; log10--, m=m>>1);
log10 = 1 + (int)((log10 + (0 == ((m-1) & sal.line)))/3.32192809);
 
/* If we don't already know the full absolute file name of the
source file, find it now. */
if (!sal.symtab->fullname)
{
fn = symtab_to_fullname (sal.symtab);
if (!fn)
fn = "unknown";
}
else
fn = sal.symtab->fullname;
 
/* Quote the file name, in case it has whitespace or other special
characters. */
p = xstrprintf ("%s +%d \"%s\"", editor, sal.line, fn);
shell_escape(p, from_tty);
xfree(p);
}
 
static void
list_command (char *arg, int from_tty)
{
struct symtabs_and_lines sals, sals_end;
struct symtab_and_line sal = { 0 };
struct symtab_and_line sal_end = { 0 };
struct symtab_and_line cursal = { 0 };
struct symbol *sym;
char *arg1;
int no_end = 1;
int dummy_end = 0;
int dummy_beg = 0;
int linenum_beg = 0;
char *p;
 
/* Pull in the current default source line if necessary */
if (arg == 0 || arg[0] == '+' || arg[0] == '-')
{
set_default_source_symtab_and_line ();
cursal = get_current_source_symtab_and_line ();
}
 
/* "l" or "l +" lists next ten lines. */
 
if (arg == 0 || strcmp (arg, "+") == 0)
{
print_source_lines (cursal.symtab, cursal.line,
cursal.line + get_lines_to_list (), 0);
return;
}
 
/* "l -" lists previous ten lines, the ones before the ten just listed. */
if (strcmp (arg, "-") == 0)
{
print_source_lines (cursal.symtab,
max (get_first_line_listed () - get_lines_to_list (), 1),
get_first_line_listed (), 0);
return;
}
 
/* Now if there is only one argument, decode it in SAL
and set NO_END.
If there are two arguments, decode them in SAL and SAL_END
and clear NO_END; however, if one of the arguments is blank,
set DUMMY_BEG or DUMMY_END to record that fact. */
 
if (!have_full_symbols () && !have_partial_symbols ())
error (_("No symbol table is loaded. Use the \"file\" command."));
 
arg1 = arg;
if (*arg1 == ',')
dummy_beg = 1;
else
{
sals = decode_line_1 (&arg1, 0, 0, 0, 0, 0);
 
if (!sals.nelts)
return; /* C++ */
if (sals.nelts > 1)
{
ambiguous_line_spec (&sals);
xfree (sals.sals);
return;
}
 
sal = sals.sals[0];
xfree (sals.sals);
}
 
/* Record whether the BEG arg is all digits. */
 
for (p = arg; p != arg1 && *p >= '0' && *p <= '9'; p++);
linenum_beg = (p == arg1);
 
while (*arg1 == ' ' || *arg1 == '\t')
arg1++;
if (*arg1 == ',')
{
no_end = 0;
arg1++;
while (*arg1 == ' ' || *arg1 == '\t')
arg1++;
if (*arg1 == 0)
dummy_end = 1;
else
{
if (dummy_beg)
sals_end = decode_line_1 (&arg1, 0, 0, 0, 0, 0);
else
sals_end = decode_line_1 (&arg1, 0, sal.symtab, sal.line, 0, 0);
if (sals_end.nelts == 0)
return;
if (sals_end.nelts > 1)
{
ambiguous_line_spec (&sals_end);
xfree (sals_end.sals);
return;
}
sal_end = sals_end.sals[0];
xfree (sals_end.sals);
}
}
 
if (*arg1)
error (_("Junk at end of line specification."));
 
if (!no_end && !dummy_beg && !dummy_end
&& sal.symtab != sal_end.symtab)
error (_("Specified start and end are in different files."));
if (dummy_beg && dummy_end)
error (_("Two empty args do not say what lines to list."));
 
/* if line was specified by address,
first print exactly which line, and which file.
In this case, sal.symtab == 0 means address is outside
of all known source files, not that user failed to give a filename. */
if (*arg == '*')
{
if (sal.symtab == 0)
/* FIXME-32x64--assumes sal.pc fits in long. */
error (_("No source file for address %s."),
hex_string ((unsigned long) sal.pc));
sym = find_pc_function (sal.pc);
if (sym)
{
deprecated_print_address_numeric (sal.pc, 1, gdb_stdout);
printf_filtered (" is in ");
fputs_filtered (SYMBOL_PRINT_NAME (sym), gdb_stdout);
printf_filtered (" (%s:%d).\n", sal.symtab->filename, sal.line);
}
else
{
deprecated_print_address_numeric (sal.pc, 1, gdb_stdout);
printf_filtered (" is at %s:%d.\n",
sal.symtab->filename, sal.line);
}
}
 
/* If line was not specified by just a line number,
and it does not imply a symtab, it must be an undebuggable symbol
which means no source code. */
 
if (!linenum_beg && sal.symtab == 0)
error (_("No line number known for %s."), arg);
 
/* If this command is repeated with RET,
turn it into the no-arg variant. */
 
if (from_tty)
*arg = 0;
 
if (dummy_beg && sal_end.symtab == 0)
error (_("No default source file yet. Do \"help list\"."));
if (dummy_beg)
print_source_lines (sal_end.symtab,
max (sal_end.line - (get_lines_to_list () - 1), 1),
sal_end.line + 1, 0);
else if (sal.symtab == 0)
error (_("No default source file yet. Do \"help list\"."));
else if (no_end)
{
int first_line = sal.line - get_lines_to_list () / 2;
 
if (first_line < 1) first_line = 1;
 
print_source_lines (sal.symtab,
first_line,
first_line + get_lines_to_list (),
0);
}
else
print_source_lines (sal.symtab, sal.line,
(dummy_end
? sal.line + get_lines_to_list ()
: sal_end.line + 1),
0);
}
 
/* Dump a specified section of assembly code. With no command line
arguments, this command will dump the assembly code for the
function surrounding the pc value in the selected frame. With one
argument, it will dump the assembly code surrounding that pc value.
Two arguments are interpeted as bounds within which to dump
assembly. */
 
static void
disassemble_command (char *arg, int from_tty)
{
CORE_ADDR low, high;
char *name;
CORE_ADDR pc, pc_masked;
char *space_index;
#if 0
asection *section;
#endif
 
name = NULL;
if (!arg)
{
pc = get_frame_pc (get_selected_frame (_("No frame selected.")));
if (find_pc_partial_function (pc, &name, &low, &high) == 0)
error (_("No function contains program counter for selected frame."));
#if defined(TUI)
/* NOTE: cagney/2003-02-13 The `tui_active' was previously
`tui_version'. */
if (tui_active)
/* FIXME: cagney/2004-02-07: This should be an observer. */
low = tui_get_low_disassembly_address (low, pc);
#endif
low += gdbarch_deprecated_function_start_offset (current_gdbarch);
}
else if (!(space_index = (char *) strchr (arg, ' ')))
{
/* One argument. */
pc = parse_and_eval_address (arg);
if (find_pc_partial_function (pc, &name, &low, &high) == 0)
error (_("No function contains specified address."));
#if defined(TUI)
/* NOTE: cagney/2003-02-13 The `tui_active' was previously
`tui_version'. */
if (tui_active)
/* FIXME: cagney/2004-02-07: This should be an observer. */
low = tui_get_low_disassembly_address (low, pc);
#endif
low += gdbarch_deprecated_function_start_offset (current_gdbarch);
}
else
{
/* Two arguments. */
*space_index = '\0';
low = parse_and_eval_address (arg);
high = parse_and_eval_address (space_index + 1);
}
 
#if defined(TUI)
if (!tui_is_window_visible (DISASSEM_WIN))
#endif
{
printf_filtered ("Dump of assembler code ");
if (name != NULL)
{
printf_filtered ("for function %s:\n", name);
}
else
{
printf_filtered ("from ");
deprecated_print_address_numeric (low, 1, gdb_stdout);
printf_filtered (" to ");
deprecated_print_address_numeric (high, 1, gdb_stdout);
printf_filtered (":\n");
}
 
/* Dump the specified range. */
gdb_disassembly (uiout, 0, 0, 0, -1, low, high);
 
printf_filtered ("End of assembler dump.\n");
gdb_flush (gdb_stdout);
}
#if defined(TUI)
else
{
tui_show_assembly (low);
}
#endif
}
 
static void
make_command (char *arg, int from_tty)
{
char *p;
 
if (arg == 0)
p = "make";
else
{
p = xmalloc (sizeof ("make ") + strlen (arg));
strcpy (p, "make ");
strcpy (p + sizeof ("make ") - 1, arg);
}
 
shell_escape (p, from_tty);
}
 
static void
show_user (char *args, int from_tty)
{
struct cmd_list_element *c;
extern struct cmd_list_element *cmdlist;
 
if (args)
{
c = lookup_cmd (&args, cmdlist, "", 0, 1);
if (c->class != class_user)
error (_("Not a user command."));
show_user_1 (c, gdb_stdout);
}
else
{
for (c = cmdlist; c; c = c->next)
{
if (c->class == class_user)
show_user_1 (c, gdb_stdout);
}
}
}
 
/* Search through names of commands and documentations for a certain
regular expression.
*/
void
apropos_command (char *searchstr, int from_tty)
{
extern struct cmd_list_element *cmdlist; /*This is the main command list*/
regex_t pattern;
char *pattern_fastmap;
char errorbuffer[512];
pattern_fastmap = xcalloc (256, sizeof (char));
if (searchstr == NULL)
error (_("REGEXP string is empty"));
 
if (regcomp(&pattern,searchstr,REG_ICASE) == 0)
{
pattern.fastmap=pattern_fastmap;
re_compile_fastmap(&pattern);
apropos_cmd (gdb_stdout,cmdlist,&pattern,"");
}
else
{
regerror(regcomp(&pattern,searchstr,REG_ICASE),NULL,errorbuffer,512);
error (_("Error in regular expression:%s"),errorbuffer);
}
xfree (pattern_fastmap);
}
/* Print a list of files and line numbers which a user may choose from
in order to list a function which was specified ambiguously (as with
`list classname::overloadedfuncname', for example). The vector in
SALS provides the filenames and line numbers. */
 
static void
ambiguous_line_spec (struct symtabs_and_lines *sals)
{
int i;
 
for (i = 0; i < sals->nelts; ++i)
printf_filtered (_("file: \"%s\", line number: %d\n"),
sals->sals[i].symtab->filename, sals->sals[i].line);
}
 
static void
set_debug (char *arg, int from_tty)
{
printf_unfiltered (_("\"set debug\" must be followed by the name of a print subcommand.\n"));
help_list (setdebuglist, "set debug ", -1, gdb_stdout);
}
 
static void
show_debug (char *args, int from_tty)
{
cmd_show_list (showdebuglist, from_tty, "");
}
 
void
init_cmd_lists (void)
{
max_user_call_depth = 1024;
 
cmdlist = NULL;
infolist = NULL;
enablelist = NULL;
disablelist = NULL;
togglelist = NULL;
stoplist = NULL;
deletelist = NULL;
detachlist = NULL;
enablebreaklist = NULL;
setlist = NULL;
unsetlist = NULL;
showlist = NULL;
sethistlist = NULL;
showhistlist = NULL;
unsethistlist = NULL;
maintenancelist = NULL;
maintenanceinfolist = NULL;
maintenanceprintlist = NULL;
setprintlist = NULL;
showprintlist = NULL;
setchecklist = NULL;
showchecklist = NULL;
}
 
static void
show_info_verbose (struct ui_file *file, int from_tty,
struct cmd_list_element *c,
const char *value)
{
if (info_verbose)
fprintf_filtered (file, _("\
Verbose printing of informational messages is %s.\n"), value);
else
fprintf_filtered (file, _("Verbosity is %s.\n"), value);
}
 
static void
show_history_expansion_p (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("History expansion on command input is %s.\n"),
value);
}
 
static void
show_baud_rate (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("Baud rate for remote serial I/O is %s.\n"),
value);
}
 
static void
show_remote_debug (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("Debugging of remote protocol is %s.\n"),
value);
}
 
static void
show_remote_timeout (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("\
Timeout limit to wait for target to respond is %s.\n"),
value);
}
 
static void
show_max_user_call_depth (struct ui_file *file, int from_tty,
struct cmd_list_element *c, const char *value)
{
fprintf_filtered (file, _("\
The max call depth for user-defined commands is %s.\n"),
value);
}
 
void
init_cli_cmds (void)
{
struct cmd_list_element *c;
char *source_help_text;
 
/* Define the classes of commands.
They will appear in the help list in the reverse of this order. */
 
add_cmd ("internals", class_maintenance, NULL, _("\
Maintenance commands.\n\
Some gdb commands are provided just for use by gdb maintainers.\n\
These commands are subject to frequent change, and may not be as\n\
well documented as user commands."),
&cmdlist);
add_cmd ("obscure", class_obscure, NULL, _("Obscure features."), &cmdlist);
add_cmd ("aliases", class_alias, NULL, _("Aliases of other commands."), &cmdlist);
add_cmd ("user-defined", class_user, NULL, _("\
User-defined commands.\n\
The commands in this class are those defined by the user.\n\
Use the \"define\" command to define a command."), &cmdlist);
add_cmd ("support", class_support, NULL, _("Support facilities."), &cmdlist);
if (!dbx_commands)
add_cmd ("status", class_info, NULL, _("Status inquiries."), &cmdlist);
add_cmd ("files", class_files, NULL, _("Specifying and examining files."),
&cmdlist);
add_cmd ("breakpoints", class_breakpoint, NULL,
_("Making program stop at certain points."), &cmdlist);
add_cmd ("data", class_vars, NULL, _("Examining data."), &cmdlist);
add_cmd ("stack", class_stack, NULL, _("\
Examining the stack.\n\
The stack is made up of stack frames. Gdb assigns numbers to stack frames\n\
counting from zero for the innermost (currently executing) frame.\n\n\
At any time gdb identifies one frame as the \"selected\" frame.\n\
Variable lookups are done with respect to the selected frame.\n\
When the program being debugged stops, gdb selects the innermost frame.\n\
The commands below can be used to select other frames by number or address."),
&cmdlist);
add_cmd ("running", class_run, NULL, _("Running the program."), &cmdlist);
 
/* Define general commands. */
 
add_com ("pwd", class_files, pwd_command, _("\
Print working directory. This is used for your program as well."));
c = add_cmd ("cd", class_files, cd_command, _("\
Set working directory to DIR for debugger and program being debugged.\n\
The change does not take effect for the program being debugged\n\
until the next time it is started."), &cmdlist);
set_cmd_completer (c, filename_completer);
 
add_com ("echo", class_support, echo_command, _("\
Print a constant string. Give string as argument.\n\
C escape sequences may be used in the argument.\n\
No newline is added at the end of the argument;\n\
use \"\\n\" if you want a newline to be printed.\n\
Since leading and trailing whitespace are ignored in command arguments,\n\
if you want to print some you must use \"\\\" before leading whitespace\n\
to be printed or after trailing whitespace."));
add_com ("document", class_support, document_command, _("\
Document a user-defined command.\n\
Give command name as argument. Give documentation on following lines.\n\
End with a line of just \"end\"."));
add_com ("define", class_support, define_command, _("\
Define a new command name. Command name is argument.\n\
Definition appears on following lines, one command per line.\n\
End with a line of just \"end\".\n\
Use the \"document\" command to give documentation for the new command.\n\
Commands defined in this way may have up to ten arguments."));
 
source_help_text = xstrprintf (_("\
Read commands from a file named FILE.\n\
Optional -v switch (before the filename) causes each command in\n\
FILE to be echoed as it is executed.\n\
Note that the file \"%s\" is read automatically in this way\n\
when GDB is started."), gdbinit);
c = add_cmd ("source", class_support, source_command,
source_help_text, &cmdlist);
set_cmd_completer (c, filename_completer);
 
add_com ("quit", class_support, quit_command, _("Exit gdb."));
c = add_com ("help", class_support, help_command,
_("Print list of commands."));
set_cmd_completer (c, command_completer);
add_com_alias ("q", "quit", class_support, 1);
add_com_alias ("h", "help", class_support, 1);
 
add_setshow_boolean_cmd ("verbose", class_support, &info_verbose, _("\
Set verbosity."), _("\
Show verbosity."), NULL,
set_verbose,
show_info_verbose,
&setlist, &showlist);
 
add_prefix_cmd ("history", class_support, set_history,
_("Generic command for setting command history parameters."),
&sethistlist, "set history ", 0, &setlist);
add_prefix_cmd ("history", class_support, show_history,
_("Generic command for showing command history parameters."),
&showhistlist, "show history ", 0, &showlist);
 
add_setshow_boolean_cmd ("expansion", no_class, &history_expansion_p, _("\
Set history expansion on command input."), _("\
Show history expansion on command input."), _("\
Without an argument, history expansion is enabled."),
NULL,
show_history_expansion_p,
&sethistlist, &showhistlist);
 
add_prefix_cmd ("info", class_info, info_command, _("\
Generic command for showing things about the program being debugged."),
&infolist, "info ", 0, &cmdlist);
add_com_alias ("i", "info", class_info, 1);
 
add_com ("complete", class_obscure, complete_command,
_("List the completions for the rest of the line as a command."));
 
add_prefix_cmd ("show", class_info, show_command,
_("Generic command for showing things about the debugger."),
&showlist, "show ", 0, &cmdlist);
/* Another way to get at the same thing. */
add_info ("set", show_command, _("Show all GDB settings."));
 
add_cmd ("commands", no_class, show_commands, _("\
Show the history of commands you typed.\n\
You can supply a command number to start with, or a `+' to start after\n\
the previous command number shown."),
&showlist);
 
add_cmd ("version", no_class, show_version,
_("Show what version of GDB this is."), &showlist);
 
add_com ("while", class_support, while_command, _("\
Execute nested commands WHILE the conditional expression is non zero.\n\
The conditional expression must follow the word `while' and must in turn be\n\
followed by a new line. The nested commands must be entered one per line,\n\
and should be terminated by the word `end'."));
 
add_com ("if", class_support, if_command, _("\
Execute nested commands once IF the conditional expression is non zero.\n\
The conditional expression must follow the word `if' and must in turn be\n\
followed by a new line. The nested commands must be entered one per line,\n\
and should be terminated by the word 'else' or `end'. If an else clause\n\
is used, the same rules apply to its nested commands as to the first ones."));
 
/* If target is open when baud changes, it doesn't take effect until the
next open (I think, not sure). */
add_setshow_zinteger_cmd ("remotebaud", no_class, &baud_rate, _("\
Set baud rate for remote serial I/O."), _("\
Show baud rate for remote serial I/O."), _("\
This value is used to set the speed of the serial port when debugging\n\
using remote targets."),
NULL,
show_baud_rate,
&setlist, &showlist);
 
add_setshow_zinteger_cmd ("remote", no_class, &remote_debug, _("\
Set debugging of remote protocol."), _("\
Show debugging of remote protocol."), _("\
When enabled, each packet sent or received with the remote target\n\
is displayed."),
NULL,
show_remote_debug,
&setdebuglist, &showdebuglist);
 
add_setshow_integer_cmd ("remotetimeout", no_class, &remote_timeout, _("\
Set timeout limit to wait for target to respond."), _("\
Show timeout limit to wait for target to respond."), _("\
This value is used to set the time limit for gdb to wait for a response\n\
from the target."),
NULL,
show_remote_timeout,
&setlist, &showlist);
 
add_prefix_cmd ("debug", no_class, set_debug,
_("Generic command for setting gdb debugging flags"),
&setdebuglist, "set debug ", 0, &setlist);
 
add_prefix_cmd ("debug", no_class, show_debug,
_("Generic command for showing gdb debugging flags"),
&showdebuglist, "show debug ", 0, &showlist);
 
c = add_com ("shell", class_support, shell_escape, _("\
Execute the rest of the line as a shell command.\n\
With no arguments, run an inferior shell."));
set_cmd_completer (c, filename_completer);
 
c = add_com ("edit", class_files, edit_command, _("\
Edit specified file or function.\n\
With no argument, edits file containing most recent line listed.\n\
Editing targets can be specified in these ways:\n\
FILE:LINENUM, to edit at that line in that file,\n\
FUNCTION, to edit at the beginning of that function,\n\
FILE:FUNCTION, to distinguish among like-named static functions.\n\
*ADDRESS, to edit at the line containing that address.\n\
Uses EDITOR environment variable contents as editor (or ex as default)."));
 
c->completer = location_completer;
 
add_com ("list", class_files, list_command, _("\
List specified function or line.\n\
With no argument, lists ten more lines after or around previous listing.\n\
\"list -\" lists the ten lines before a previous ten-line listing.\n\
One argument specifies a line, and ten lines are listed around that line.\n\
Two arguments with comma between specify starting and ending lines to list.\n\
Lines can be specified in these ways:\n\
LINENUM, to list around that line in current file,\n\
FILE:LINENUM, to list around that line in that file,\n\
FUNCTION, to list around beginning of that function,\n\
FILE:FUNCTION, to distinguish among like-named static functions.\n\
*ADDRESS, to list around the line containing that address.\n\
With two args if one is empty it stands for ten lines away from the other arg."));
 
if (!xdb_commands)
add_com_alias ("l", "list", class_files, 1);
else
add_com_alias ("v", "list", class_files, 1);
 
if (dbx_commands)
add_com_alias ("file", "list", class_files, 1);
 
c = add_com ("disassemble", class_vars, disassemble_command, _("\
Disassemble a specified section of memory.\n\
Default is the function surrounding the pc of the selected frame.\n\
With a single argument, the function surrounding that address is dumped.\n\
Two arguments are taken as a range of memory to dump."));
set_cmd_completer (c, location_completer);
if (xdb_commands)
add_com_alias ("va", "disassemble", class_xdb, 0);
 
/* NOTE: cagney/2000-03-20: Being able to enter ``(gdb) !ls'' would
be a really useful feature. Unfortunately, the below wont do
this. Instead it adds support for the form ``(gdb) ! ls''
(i.e. the space is required). If the ``!'' command below is
added the complains about no ``!'' command would be replaced by
complains about how the ``!'' command is broken :-) */
if (xdb_commands)
add_com_alias ("!", "shell", class_support, 0);
 
c = add_com ("make", class_support, make_command, _("\
Run the ``make'' program using the rest of the line as arguments."));
set_cmd_completer (c, filename_completer);
add_cmd ("user", no_class, show_user, _("\
Show definitions of user defined commands.\n\
Argument is the name of the user defined command.\n\
With no argument, show definitions of all user defined commands."), &showlist);
add_com ("apropos", class_support, apropos_command,
_("Search for commands matching a REGEXP"));
 
add_setshow_integer_cmd ("max-user-call-depth", no_class,
&max_user_call_depth, _("\
Set the max call depth for user-defined commands."), _("\
Show the max call depth for user-defined commands."), NULL,
NULL,
show_max_user_call_depth,
&setlist, &showlist);
 
add_setshow_boolean_cmd ("trace-commands", no_class, &trace_commands, _("\
Set tracing of GDB CLI commands."), _("\
Show state of GDB CLI command tracing."), _("\
When 'on', each command is displayed as it is executed."),
NULL,
NULL,
&setlist, &showlist);
}
/trunk/gdb-6.8/gdb/ui-file.c
0,0 → 1,620
/* UI_FILE - a generic STDIO like output stream.
 
Copyright (C) 1999, 2000, 2001, 2002, 2007, 2008
Free Software Foundation, Inc.
 
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/>. */
 
/* Implement the ``struct ui_file'' object. */
 
#include "defs.h"
#include "ui-file.h"
#include "gdb_string.h"
 
#include <errno.h>
 
static ui_file_isatty_ftype null_file_isatty;
static ui_file_write_ftype null_file_write;
static ui_file_fputs_ftype null_file_fputs;
static ui_file_read_ftype null_file_read;
static ui_file_flush_ftype null_file_flush;
static ui_file_delete_ftype null_file_delete;
static ui_file_rewind_ftype null_file_rewind;
static ui_file_put_ftype null_file_put;
 
struct ui_file
{
int *magic;
ui_file_flush_ftype *to_flush;
ui_file_write_ftype *to_write;
ui_file_fputs_ftype *to_fputs;
ui_file_read_ftype *to_read;
ui_file_delete_ftype *to_delete;
ui_file_isatty_ftype *to_isatty;
ui_file_rewind_ftype *to_rewind;
ui_file_put_ftype *to_put;
void *to_data;
};
int ui_file_magic;
 
struct ui_file *
ui_file_new (void)
{
struct ui_file *file = xmalloc (sizeof (struct ui_file));
file->magic = &ui_file_magic;
set_ui_file_data (file, NULL, null_file_delete);
set_ui_file_flush (file, null_file_flush);
set_ui_file_write (file, null_file_write);
set_ui_file_fputs (file, null_file_fputs);
set_ui_file_read (file, null_file_read);
set_ui_file_isatty (file, null_file_isatty);
set_ui_file_rewind (file, null_file_rewind);
set_ui_file_put (file, null_file_put);
return file;
}
 
void
ui_file_delete (struct ui_file *file)
{
file->to_delete (file);
xfree (file);
}
 
static int
null_file_isatty (struct ui_file *file)
{
return 0;
}
 
static void
null_file_rewind (struct ui_file *file)
{
return;
}
 
static void
null_file_put (struct ui_file *file,
ui_file_put_method_ftype *write,
void *dest)
{
return;
}
 
static void
null_file_flush (struct ui_file *file)
{
return;
}
 
static void
null_file_write (struct ui_file *file,
const char *buf,
long sizeof_buf)
{
if (file->to_fputs == null_file_fputs)
/* Both the write and fputs methods are null. Discard the
request. */
return;
else
{
/* The fputs method isn't null, slowly pass the write request
onto that. FYI, this isn't as bad as it may look - the
current (as of 1999-11-07) printf_* function calls fputc and
fputc does exactly the below. By having a write function it
is possible to clean up that code. */
int i;
char b[2];
b[1] = '\0';
for (i = 0; i < sizeof_buf; i++)
{
b[0] = buf[i];
file->to_fputs (b, file);
}
return;
}
}
 
static long
null_file_read (struct ui_file *file,
char *buf,
long sizeof_buf)
{
errno = EBADF;
return 0;
}
 
static void
null_file_fputs (const char *buf, struct ui_file *file)
{
if (file->to_write == null_file_write)
/* Both the write and fputs methods are null. Discard the
request. */
return;
else
{
/* The write method was implemented, use that. */
file->to_write (file, buf, strlen (buf));
}
}
 
static void
null_file_delete (struct ui_file *file)
{
return;
}
 
void *
ui_file_data (struct ui_file *file)
{
if (file->magic != &ui_file_magic)
internal_error (__FILE__, __LINE__,
_("ui_file_data: bad magic number"));
return file->to_data;
}
 
void
gdb_flush (struct ui_file *file)
{
file->to_flush (file);
}
 
int
ui_file_isatty (struct ui_file *file)
{
return file->to_isatty (file);
}
 
void
ui_file_rewind (struct ui_file *file)
{
file->to_rewind (file);
}
 
void
ui_file_put (struct ui_file *file,
ui_file_put_method_ftype *write,
void *dest)
{
file->to_put (file, write, dest);
}
 
void
ui_file_write (struct ui_file *file,
const char *buf,
long length_buf)
{
file->to_write (file, buf, length_buf);
}
 
long
ui_file_read (struct ui_file *file, char *buf, long length_buf)
{
return file->to_read (file, buf, length_buf);
}
 
void
fputs_unfiltered (const char *buf, struct ui_file *file)
{
file->to_fputs (buf, file);
}
 
void
set_ui_file_flush (struct ui_file *file, ui_file_flush_ftype *flush)
{
file->to_flush = flush;
}
 
void
set_ui_file_isatty (struct ui_file *file, ui_file_isatty_ftype *isatty)
{
file->to_isatty = isatty;
}
 
void
set_ui_file_rewind (struct ui_file *file, ui_file_rewind_ftype *rewind)
{
file->to_rewind = rewind;
}
 
void
set_ui_file_put (struct ui_file *file, ui_file_put_ftype *put)
{
file->to_put = put;
}
 
void
set_ui_file_write (struct ui_file *file,
ui_file_write_ftype *write)
{
file->to_write = write;
}
 
void
set_ui_file_read (struct ui_file *file, ui_file_read_ftype *read)
{
file->to_read = read;
}
 
void
set_ui_file_fputs (struct ui_file *file, ui_file_fputs_ftype *fputs)
{
file->to_fputs = fputs;
}
 
void
set_ui_file_data (struct ui_file *file, void *data,
ui_file_delete_ftype *delete)
{
file->to_data = data;
file->to_delete = delete;
}
 
/* ui_file utility function for converting a ``struct ui_file'' into
a memory buffer''. */
 
struct accumulated_ui_file
{
char *buffer;
long length;
};
 
static void
do_ui_file_xstrdup (void *context, const char *buffer, long length)
{
struct accumulated_ui_file *acc = context;
if (acc->buffer == NULL)
acc->buffer = xmalloc (length + 1);
else
acc->buffer = xrealloc (acc->buffer, acc->length + length + 1);
memcpy (acc->buffer + acc->length, buffer, length);
acc->length += length;
acc->buffer[acc->length] = '\0';
}
 
char *
ui_file_xstrdup (struct ui_file *file,
long *length)
{
struct accumulated_ui_file acc;
acc.buffer = NULL;
acc.length = 0;
ui_file_put (file, do_ui_file_xstrdup, &acc);
if (acc.buffer == NULL)
acc.buffer = xstrdup ("");
*length = acc.length;
return acc.buffer;
}
/* A pure memory based ``struct ui_file'' that can be used an output
buffer. The buffers accumulated contents are available via
ui_file_put(). */
 
struct mem_file
{
int *magic;
char *buffer;
int sizeof_buffer;
int length_buffer;
};
 
static ui_file_rewind_ftype mem_file_rewind;
static ui_file_put_ftype mem_file_put;
static ui_file_write_ftype mem_file_write;
static ui_file_delete_ftype mem_file_delete;
static struct ui_file *mem_file_new (void);
static int mem_file_magic;
 
static struct ui_file *
mem_file_new (void)
{
struct mem_file *stream = XMALLOC (struct mem_file);
struct ui_file *file = ui_file_new ();
set_ui_file_data (file, stream, mem_file_delete);
set_ui_file_rewind (file, mem_file_rewind);
set_ui_file_put (file, mem_file_put);
set_ui_file_write (file, mem_file_write);
stream->magic = &mem_file_magic;
stream->buffer = NULL;
stream->sizeof_buffer = 0;
stream->length_buffer = 0;
return file;
}
 
static void
mem_file_delete (struct ui_file *file)
{
struct mem_file *stream = ui_file_data (file);
if (stream->magic != &mem_file_magic)
internal_error (__FILE__, __LINE__,
_("mem_file_delete: bad magic number"));
if (stream->buffer != NULL)
xfree (stream->buffer);
xfree (stream);
}
 
struct ui_file *
mem_fileopen (void)
{
return mem_file_new ();
}
 
static void
mem_file_rewind (struct ui_file *file)
{
struct mem_file *stream = ui_file_data (file);
if (stream->magic != &mem_file_magic)
internal_error (__FILE__, __LINE__,
_("mem_file_rewind: bad magic number"));
stream->length_buffer = 0;
}
 
static void
mem_file_put (struct ui_file *file,
ui_file_put_method_ftype *write,
void *dest)
{
struct mem_file *stream = ui_file_data (file);
if (stream->magic != &mem_file_magic)
internal_error (__FILE__, __LINE__,
_("mem_file_put: bad magic number"));
if (stream->length_buffer > 0)
write (dest, stream->buffer, stream->length_buffer);
}
 
void
mem_file_write (struct ui_file *file,
const char *buffer,
long length_buffer)
{
struct mem_file *stream = ui_file_data (file);
if (stream->magic != &mem_file_magic)
internal_error (__FILE__, __LINE__,
_("mem_file_write: bad magic number"));
if (stream->buffer == NULL)
{
stream->length_buffer = length_buffer;
stream->sizeof_buffer = length_buffer;
stream->buffer = xmalloc (stream->sizeof_buffer);
memcpy (stream->buffer, buffer, length_buffer);
}
else
{
int new_length = stream->length_buffer + length_buffer;
if (new_length >= stream->sizeof_buffer)
{
stream->sizeof_buffer = new_length;
stream->buffer = xrealloc (stream->buffer, stream->sizeof_buffer);
}
memcpy (stream->buffer + stream->length_buffer, buffer, length_buffer);
stream->length_buffer = new_length;
}
}
/* ``struct ui_file'' implementation that maps directly onto
<stdio.h>'s FILE. */
 
static ui_file_write_ftype stdio_file_write;
static ui_file_fputs_ftype stdio_file_fputs;
static ui_file_read_ftype stdio_file_read;
static ui_file_isatty_ftype stdio_file_isatty;
static ui_file_delete_ftype stdio_file_delete;
static struct ui_file *stdio_file_new (FILE * file, int close_p);
static ui_file_flush_ftype stdio_file_flush;
 
static int stdio_file_magic;
 
struct stdio_file
{
int *magic;
FILE *file;
int close_p;
};
 
static struct ui_file *
stdio_file_new (FILE *file, int close_p)
{
struct ui_file *ui_file = ui_file_new ();
struct stdio_file *stdio = xmalloc (sizeof (struct stdio_file));
stdio->magic = &stdio_file_magic;
stdio->file = file;
stdio->close_p = close_p;
set_ui_file_data (ui_file, stdio, stdio_file_delete);
set_ui_file_flush (ui_file, stdio_file_flush);
set_ui_file_write (ui_file, stdio_file_write);
set_ui_file_fputs (ui_file, stdio_file_fputs);
set_ui_file_read (ui_file, stdio_file_read);
set_ui_file_isatty (ui_file, stdio_file_isatty);
return ui_file;
}
 
static void
stdio_file_delete (struct ui_file *file)
{
struct stdio_file *stdio = ui_file_data (file);
if (stdio->magic != &stdio_file_magic)
internal_error (__FILE__, __LINE__,
_("stdio_file_delete: bad magic number"));
if (stdio->close_p)
{
fclose (stdio->file);
}
xfree (stdio);
}
 
static void
stdio_file_flush (struct ui_file *file)
{
struct stdio_file *stdio = ui_file_data (file);
if (stdio->magic != &stdio_file_magic)
internal_error (__FILE__, __LINE__,
_("stdio_file_flush: bad magic number"));
fflush (stdio->file);
}
 
static long
stdio_file_read (struct ui_file *file, char *buf, long length_buf)
{
struct stdio_file *stdio = ui_file_data (file);
if (stdio->magic != &stdio_file_magic)
internal_error (__FILE__, __LINE__,
_("stdio_file_read: bad magic number"));
return read (fileno (stdio->file), buf, length_buf);
}
 
/* JPB: Some picky Ubuntu GCC compilers don't like the result of fwrite being
ignored (even if you cast it to void). So capture the value and ignore
THAT. */
static void
stdio_file_write (struct ui_file *file, const char *buf, long length_buf)
{
int res; /* For fwrite result */
struct stdio_file *stdio = ui_file_data (file);
if (stdio->magic != &stdio_file_magic)
internal_error (__FILE__, __LINE__,
_("stdio_file_write: bad magic number"));
res = fwrite (buf, length_buf, 1, stdio->file);
}
 
static void
stdio_file_fputs (const char *linebuffer, struct ui_file *file)
{
struct stdio_file *stdio = ui_file_data (file);
if (stdio->magic != &stdio_file_magic)
internal_error (__FILE__, __LINE__,
_("stdio_file_fputs: bad magic number"));
fputs (linebuffer, stdio->file);
}
 
static int
stdio_file_isatty (struct ui_file *file)
{
struct stdio_file *stdio = ui_file_data (file);
if (stdio->magic != &stdio_file_magic)
internal_error (__FILE__, __LINE__,
_("stdio_file_isatty: bad magic number"));
return (isatty (fileno (stdio->file)));
}
 
/* Like fdopen(). Create a ui_file from a previously opened FILE. */
 
struct ui_file *
stdio_fileopen (FILE *file)
{
return stdio_file_new (file, 0);
}
 
struct ui_file *
gdb_fopen (char *name, char *mode)
{
FILE *f = fopen (name, mode);
if (f == NULL)
return NULL;
return stdio_file_new (f, 1);
}
 
/* ``struct ui_file'' implementation that maps onto two ui-file objects. */
 
static ui_file_write_ftype tee_file_write;
static ui_file_fputs_ftype tee_file_fputs;
static ui_file_isatty_ftype tee_file_isatty;
static ui_file_delete_ftype tee_file_delete;
static ui_file_flush_ftype tee_file_flush;
 
static int tee_file_magic;
 
struct tee_file
{
int *magic;
struct ui_file *one, *two;
int close_one, close_two;
};
 
struct ui_file *
tee_file_new (struct ui_file *one, int close_one,
struct ui_file *two, int close_two)
{
struct ui_file *ui_file = ui_file_new ();
struct tee_file *tee = xmalloc (sizeof (struct tee_file));
tee->magic = &tee_file_magic;
tee->one = one;
tee->two = two;
tee->close_one = close_one;
tee->close_two = close_two;
set_ui_file_data (ui_file, tee, tee_file_delete);
set_ui_file_flush (ui_file, tee_file_flush);
set_ui_file_write (ui_file, tee_file_write);
set_ui_file_fputs (ui_file, tee_file_fputs);
set_ui_file_isatty (ui_file, tee_file_isatty);
return ui_file;
}
 
static void
tee_file_delete (struct ui_file *file)
{
struct tee_file *tee = ui_file_data (file);
if (tee->magic != &tee_file_magic)
internal_error (__FILE__, __LINE__,
_("tee_file_delete: bad magic number"));
if (tee->close_one)
ui_file_delete (tee->one);
if (tee->close_two)
ui_file_delete (tee->two);
 
xfree (tee);
}
 
static void
tee_file_flush (struct ui_file *file)
{
struct tee_file *tee = ui_file_data (file);
if (tee->magic != &tee_file_magic)
internal_error (__FILE__, __LINE__,
_("tee_file_flush: bad magic number"));
tee->one->to_flush (tee->one);
tee->two->to_flush (tee->two);
}
 
static void
tee_file_write (struct ui_file *file, const char *buf, long length_buf)
{
struct tee_file *tee = ui_file_data (file);
if (tee->magic != &tee_file_magic)
internal_error (__FILE__, __LINE__,
_("tee_file_write: bad magic number"));
ui_file_write (tee->one, buf, length_buf);
ui_file_write (tee->two, buf, length_buf);
}
 
static void
tee_file_fputs (const char *linebuffer, struct ui_file *file)
{
struct tee_file *tee = ui_file_data (file);
if (tee->magic != &tee_file_magic)
internal_error (__FILE__, __LINE__,
_("tee_file_fputs: bad magic number"));
tee->one->to_fputs (linebuffer, tee->one);
tee->two->to_fputs (linebuffer, tee->two);
}
 
static int
tee_file_isatty (struct ui_file *file)
{
struct tee_file *tee = ui_file_data (file);
if (tee->magic != &tee_file_magic)
internal_error (__FILE__, __LINE__,
_("tee_file_isatty: bad magic number"));
return (0);
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.