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 (¤t_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); |
} |