mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-05-30 07:49:07 +08:00
import gdb-1999-05-10
This commit is contained in:
741
gdb/event-loop.c
Normal file
741
gdb/event-loop.c
Normal file
@ -0,0 +1,741 @@
|
|||||||
|
/* Event loop machinery for GDB, the GNU debugger.
|
||||||
|
Copyright 1999 Free Software Foundation, Inc.
|
||||||
|
Written by Elena Zannoni <ezannoni@cygnus.com> of Cygnus Solutions.
|
||||||
|
|
||||||
|
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 2 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, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||||
|
|
||||||
|
#include "event-loop.h"
|
||||||
|
#include <readline/readline.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
#include "top.h"
|
||||||
|
|
||||||
|
/* For config.h which may define HAVE_POLL */
|
||||||
|
#include "defs.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_POLL
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#endif
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
/* Event queue:
|
||||||
|
- the first event in the queue is the head of the queue.
|
||||||
|
It will be the next to be serviced.
|
||||||
|
- the last event in the queue
|
||||||
|
|
||||||
|
Events can be inserted at the front of the queue or at the end of
|
||||||
|
the queue. Events will be extracted from the queue for processing
|
||||||
|
starting from the head. Therefore, events inserted at the head of
|
||||||
|
the queue will be processed in a last in first out fashoin, while
|
||||||
|
those inserted at the tail of the queue will be processed in a first
|
||||||
|
in first out manner. All the fields are NULL if the queue is
|
||||||
|
empty. */
|
||||||
|
|
||||||
|
static struct
|
||||||
|
{
|
||||||
|
gdb_event *first_event; /* First pending event */
|
||||||
|
gdb_event *last_event; /* Last pending event */
|
||||||
|
}
|
||||||
|
event_queue;
|
||||||
|
|
||||||
|
/* Gdb_notifier is just a list of file descriptors gdb is interested in.
|
||||||
|
These are the input file descriptor, and the target file
|
||||||
|
descriptor. We have two flavors of the notifier, one for platforms
|
||||||
|
that have the POLL function, the other for those that don't, and
|
||||||
|
only support SELECT. Each of the elements in the gdb_notifier list is
|
||||||
|
basically a description of what kind of events gdb is interested
|
||||||
|
in, for each fd. */
|
||||||
|
|
||||||
|
/* As of 4/30/99 only the input file descriptor is registered with the
|
||||||
|
event loop. */
|
||||||
|
|
||||||
|
#ifdef HAVE_POLL
|
||||||
|
/* Poll based implementation of the notifier. */
|
||||||
|
|
||||||
|
static struct
|
||||||
|
{
|
||||||
|
/* Ptr to head of file handler list. */
|
||||||
|
file_handler *first_file_handler;
|
||||||
|
|
||||||
|
/* Ptr to array of pollfd structures. */
|
||||||
|
struct pollfd *poll_fds;
|
||||||
|
|
||||||
|
/* Number of file descriptors to monitor. */
|
||||||
|
int num_fds;
|
||||||
|
|
||||||
|
}
|
||||||
|
gdb_notifier;
|
||||||
|
|
||||||
|
#else /* ! HAVE_POLL */
|
||||||
|
|
||||||
|
/* Select based implementation of the notifier. */
|
||||||
|
|
||||||
|
static struct
|
||||||
|
{
|
||||||
|
/* Ptr to head of file handler list. */
|
||||||
|
file_handler *first_file_handler;
|
||||||
|
|
||||||
|
/* Masks to be used in the next call to select.
|
||||||
|
Bits are set in response to calls to create_file_handler. */
|
||||||
|
fd_mask check_masks[3 * MASK_SIZE];
|
||||||
|
|
||||||
|
/* What file descriptors were found ready by select. */
|
||||||
|
fd_mask ready_masks[3 * MASK_SIZE];
|
||||||
|
|
||||||
|
/* Number of valid bits (highest fd value + 1). */
|
||||||
|
int num_fds;
|
||||||
|
|
||||||
|
}
|
||||||
|
gdb_notifier;
|
||||||
|
|
||||||
|
#endif /* HAVE_POLL */
|
||||||
|
|
||||||
|
/* All the async_signal_handlers gdb is interested in are kept onto
|
||||||
|
this list. */
|
||||||
|
static struct
|
||||||
|
{
|
||||||
|
/* Pointer to first in handler list. */
|
||||||
|
async_signal_handler *first_handler;
|
||||||
|
|
||||||
|
/* Pointer to last in handler list. */
|
||||||
|
async_signal_handler *last_handler;
|
||||||
|
}
|
||||||
|
sighandler_list;
|
||||||
|
|
||||||
|
/* Is any of the handlers ready? Check this variable using
|
||||||
|
check_async_ready. This is used by process_event, to determine
|
||||||
|
whether or not to invoke the invoke_async_signal_handler
|
||||||
|
function. */
|
||||||
|
static int async_handler_ready = 0;
|
||||||
|
|
||||||
|
static void invoke_async_signal_handler PARAMS ((void));
|
||||||
|
static int gdb_wait_for_event PARAMS ((void));
|
||||||
|
static int check_async_ready PARAMS ((void));
|
||||||
|
extern display_gdb_prompt PARAMS ((char *));
|
||||||
|
|
||||||
|
|
||||||
|
/* Insert an event object into the gdb event queue at
|
||||||
|
the specified position.
|
||||||
|
POSITION can be head or tail, with values TAIL, HEAD.
|
||||||
|
EVENT_PTR points to the event to be inserted into the queue.
|
||||||
|
The caller must allocate memory for the event. It is freed
|
||||||
|
after the event has ben handled.
|
||||||
|
Events in the queue will be processed head to tail, therefore,
|
||||||
|
events inserted at the head of the queue will be processed
|
||||||
|
as last in first out. Event appended at the tail of the queue
|
||||||
|
will be processed first in first out. */
|
||||||
|
static void
|
||||||
|
async_queue_event (event_ptr, position)
|
||||||
|
gdb_event *event_ptr;
|
||||||
|
queue_position position;
|
||||||
|
{
|
||||||
|
if (position == TAIL)
|
||||||
|
{
|
||||||
|
/* The event will become the new last_event. */
|
||||||
|
|
||||||
|
event_ptr->next_event = NULL;
|
||||||
|
if (event_queue.first_event == NULL)
|
||||||
|
event_queue.first_event = event_ptr;
|
||||||
|
else
|
||||||
|
event_queue.last_event->next_event = event_ptr;
|
||||||
|
event_queue.last_event = event_ptr;
|
||||||
|
}
|
||||||
|
else if (position == HEAD)
|
||||||
|
{
|
||||||
|
/* The event becomes the new first_event. */
|
||||||
|
|
||||||
|
event_ptr->next_event = event_queue.first_event;
|
||||||
|
if (event_queue.first_event == NULL)
|
||||||
|
event_queue.last_event = event_ptr;
|
||||||
|
event_queue.first_event = event_ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process one event.
|
||||||
|
The event can be the next one to be serviced in the event queue,
|
||||||
|
or an asynchronous event handler can be invoked in response to
|
||||||
|
the reception of a signal.
|
||||||
|
If an event was processed (either way), 1 is returned otherwise
|
||||||
|
0 is returned.
|
||||||
|
Scan the queue from head to tail, processing therefore the high
|
||||||
|
priority events first, by invoking the associated event handler
|
||||||
|
procedure. */
|
||||||
|
static int
|
||||||
|
process_event ()
|
||||||
|
{
|
||||||
|
gdb_event *event_ptr, *prev_ptr;
|
||||||
|
event_handler_func *proc;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
/* First let's see if there are any asynchronous event handlers that
|
||||||
|
are ready. These would be the result of invoking any of the
|
||||||
|
signal handlers. */
|
||||||
|
|
||||||
|
if (check_async_ready ())
|
||||||
|
{
|
||||||
|
invoke_async_signal_handler ();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Look in the event queue to find an event that is ready
|
||||||
|
to be processed. */
|
||||||
|
|
||||||
|
for (event_ptr = event_queue.first_event; event_ptr != NULL;
|
||||||
|
event_ptr = event_ptr->next_event)
|
||||||
|
{
|
||||||
|
/* Call the handler for the event. */
|
||||||
|
|
||||||
|
proc = event_ptr->proc;
|
||||||
|
fd = event_ptr->fd;
|
||||||
|
|
||||||
|
/* Let's get rid of the event from the event queue. We need to
|
||||||
|
do this now because while processing the event, the proc
|
||||||
|
function could end up calling 'error' and therefore jump out
|
||||||
|
to the caller of this function, gdb_do_one_event. In that
|
||||||
|
case, we would have on the event queue an event wich has been
|
||||||
|
processed, but not deleted. */
|
||||||
|
|
||||||
|
if (event_queue.first_event == event_ptr)
|
||||||
|
{
|
||||||
|
event_queue.first_event = event_ptr->next_event;
|
||||||
|
if (event_ptr->next_event == NULL)
|
||||||
|
event_queue.last_event = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
prev_ptr = event_queue.first_event;
|
||||||
|
while (prev_ptr->next_event != event_ptr)
|
||||||
|
prev_ptr = prev_ptr->next_event;
|
||||||
|
|
||||||
|
prev_ptr->next_event = event_ptr->next_event;
|
||||||
|
if (event_ptr->next_event == NULL)
|
||||||
|
event_queue.last_event = prev_ptr;
|
||||||
|
}
|
||||||
|
free ((char *) event_ptr);
|
||||||
|
|
||||||
|
/* Now call the procedure associted with the event. */
|
||||||
|
(*proc) (fd);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* this is the case if there are no event on the event queue. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process one high level event. If nothing is ready at this time,
|
||||||
|
wait for something to happen (via gdb_wait_for_event), then process
|
||||||
|
it. Returns 1 if something was done otherwise returns 0 (this can
|
||||||
|
happen if there are no event sources to wait for). */
|
||||||
|
int
|
||||||
|
gdb_do_one_event ()
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (!SET_TOP_LEVEL ())
|
||||||
|
{
|
||||||
|
/* Any events already waiting in the queue? */
|
||||||
|
if (process_event ())
|
||||||
|
{
|
||||||
|
result = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Wait for a new event. If gdb_wait_for_event returns -1,
|
||||||
|
we should get out because this means that there are no
|
||||||
|
event sources left. This will make the event loop stop,
|
||||||
|
and the application exit. */
|
||||||
|
|
||||||
|
result = gdb_wait_for_event ();
|
||||||
|
if (result < 0)
|
||||||
|
{
|
||||||
|
result = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle any new events occurred while waiting. */
|
||||||
|
if (process_event ())
|
||||||
|
{
|
||||||
|
result = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If gdb_wait_for_event has returned 1, it means that one
|
||||||
|
event has been handled. We break out of the loop. */
|
||||||
|
if (result)
|
||||||
|
break;
|
||||||
|
} /* end of if !set_top_level */
|
||||||
|
else
|
||||||
|
{
|
||||||
|
display_gdb_prompt (0);
|
||||||
|
/* Maybe better to set a flag to be checked somewhere as to
|
||||||
|
whether display the prompt or not. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Add a file handler/descriptor to the list of descriptors we are
|
||||||
|
interested in.
|
||||||
|
FD is the file descriptor for the file/stream to be listened to.
|
||||||
|
For the poll case, MASK is a combination (OR) of
|
||||||
|
POLLIN, POLLRDNORM, POLLRDBAND, POLLPRI, POLLOUT, POLLWRNORM,
|
||||||
|
POLLWRBAND: these are the events we are interested in. If any of them
|
||||||
|
occurs, proc should be called.
|
||||||
|
For the select case, MASK is a combination of READABLE, WRITABLE, EXCEPTION.
|
||||||
|
PROC is the procedure that will be called when an event occurs for
|
||||||
|
FD. CLIENT_DATA is the argument to pass to PROC. */
|
||||||
|
void
|
||||||
|
create_file_handler (fd, mask, proc, client_data)
|
||||||
|
int fd;
|
||||||
|
int mask;
|
||||||
|
file_handler_func *proc;
|
||||||
|
gdb_client_data client_data;
|
||||||
|
{
|
||||||
|
file_handler *file_ptr;
|
||||||
|
|
||||||
|
#ifndef HAVE_POLL
|
||||||
|
int index, bit;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Do we already have a file handler for this file? (We may be
|
||||||
|
changing its associated procedure). */
|
||||||
|
for (file_ptr = gdb_notifier.first_file_handler; file_ptr != NULL;
|
||||||
|
file_ptr = file_ptr->next_file)
|
||||||
|
{
|
||||||
|
if (file_ptr->fd == fd)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* It is a new file descriptor. */
|
||||||
|
if (file_ptr == NULL)
|
||||||
|
{
|
||||||
|
file_ptr = (file_handler *) xmalloc (sizeof (file_handler));
|
||||||
|
file_ptr->fd = fd;
|
||||||
|
file_ptr->ready_mask = 0;
|
||||||
|
file_ptr->next_file = gdb_notifier.first_file_handler;
|
||||||
|
gdb_notifier.first_file_handler = file_ptr;
|
||||||
|
}
|
||||||
|
file_ptr->proc = proc;
|
||||||
|
file_ptr->client_data = client_data;
|
||||||
|
file_ptr->mask = mask;
|
||||||
|
|
||||||
|
#ifdef HAVE_POLL
|
||||||
|
|
||||||
|
gdb_notifier.num_fds++;
|
||||||
|
gdb_notifier.poll_fds =
|
||||||
|
(struct pollfd *) realloc (gdb_notifier.poll_fds,
|
||||||
|
(gdb_notifier.num_fds) * sizeof (struct pollfd));
|
||||||
|
(gdb_notifier.poll_fds + gdb_notifier.num_fds - 1)->fd = fd;
|
||||||
|
(gdb_notifier.poll_fds + gdb_notifier.num_fds - 1)->events = mask;
|
||||||
|
(gdb_notifier.poll_fds + gdb_notifier.num_fds - 1)->revents = 0;
|
||||||
|
|
||||||
|
#else /* ! HAVE_POLL */
|
||||||
|
|
||||||
|
index = fd / (NBBY * sizeof (fd_mask));
|
||||||
|
bit = 1 << (fd % (NBBY * sizeof (fd_mask)));
|
||||||
|
|
||||||
|
if (mask & GDB_READABLE)
|
||||||
|
gdb_notifier.check_masks[index] |= bit;
|
||||||
|
else
|
||||||
|
gdb_notifier.check_masks[index] &= ~bit;
|
||||||
|
|
||||||
|
if (mask & GDB_WRITABLE)
|
||||||
|
(gdb_notifier.check_masks + MASK_SIZE)[index] |= bit;
|
||||||
|
else
|
||||||
|
(gdb_notifier.check_masks + MASK_SIZE)[index] &= ~bit;
|
||||||
|
|
||||||
|
if (mask & GDB_EXCEPTION)
|
||||||
|
(gdb_notifier.check_masks + 2 * (MASK_SIZE))[index] |= bit;
|
||||||
|
else
|
||||||
|
(gdb_notifier.check_masks + 2 * (MASK_SIZE))[index] &= ~bit;
|
||||||
|
|
||||||
|
if (gdb_notifier.num_fds <= fd)
|
||||||
|
gdb_notifier.num_fds = fd + 1;
|
||||||
|
|
||||||
|
#endif /* HAVE_POLL */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove the file descriptor FD from the list of monitored fd's:
|
||||||
|
i.e. we don't care anymore about events on the FD. */
|
||||||
|
void
|
||||||
|
delete_file_handler (fd)
|
||||||
|
int fd;
|
||||||
|
{
|
||||||
|
file_handler *file_ptr, *prev_ptr = NULL;
|
||||||
|
int i, j;
|
||||||
|
struct pollfd *new_poll_fds;
|
||||||
|
#ifndef HAVE_POLL
|
||||||
|
int index, bit;
|
||||||
|
unsigned long flags;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Find the entry for the given file. */
|
||||||
|
|
||||||
|
for (file_ptr = gdb_notifier.first_file_handler; file_ptr != NULL;
|
||||||
|
file_ptr = file_ptr->next_file)
|
||||||
|
{
|
||||||
|
if (file_ptr->fd == fd)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_ptr == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Deactivate the file descriptor, by clearing its mask,
|
||||||
|
so that it will not fire again. */
|
||||||
|
|
||||||
|
file_ptr->mask = 0;
|
||||||
|
|
||||||
|
#ifdef HAVE_POLL
|
||||||
|
/* Create a new poll_fds array by copying every fd's information but the
|
||||||
|
one we want to get rid of. */
|
||||||
|
|
||||||
|
new_poll_fds =
|
||||||
|
(struct pollfd *) xmalloc ((gdb_notifier.num_fds - 1) * sizeof (struct pollfd));
|
||||||
|
|
||||||
|
for (i = 0, j = 0; i < gdb_notifier.num_fds; i++)
|
||||||
|
{
|
||||||
|
if ((gdb_notifier.poll_fds + i)->fd != fd)
|
||||||
|
{
|
||||||
|
(new_poll_fds + j)->fd = (gdb_notifier.poll_fds + i)->fd;
|
||||||
|
(new_poll_fds + j)->events = (gdb_notifier.poll_fds + i)->events;
|
||||||
|
(new_poll_fds + j)->revents = (gdb_notifier.poll_fds + i)->revents;
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free (gdb_notifier.poll_fds);
|
||||||
|
gdb_notifier.poll_fds = new_poll_fds;
|
||||||
|
gdb_notifier.num_fds--;
|
||||||
|
|
||||||
|
#else /* ! HAVE_POLL */
|
||||||
|
|
||||||
|
index = fd / (NBBY * sizeof (fd_mask));
|
||||||
|
bit = 1 << (fd % (NBBY * sizeof (fd_mask)));
|
||||||
|
|
||||||
|
if (file_ptr->mask & GDB_READABLE)
|
||||||
|
gdb_notifier.check_masks[index] &= ~bit;
|
||||||
|
if (file_ptr->mask & GDB_WRITABLE)
|
||||||
|
(gdb_notifier.check_masks + MASK_SIZE)[index] &= ~bit;
|
||||||
|
if (file_ptr->mask & GDB_EXCEPTION)
|
||||||
|
(gdb_notifier.check_masks + 2 * (MASK_SIZE))[index] &= ~bit;
|
||||||
|
|
||||||
|
/* Find current max fd. */
|
||||||
|
|
||||||
|
if ((fd + 1) == gdb_notifier.num_fds)
|
||||||
|
{
|
||||||
|
for (gdb_notifier.num_fds = 0; index >= 0; index--)
|
||||||
|
{
|
||||||
|
flags = gdb_notifier.check_masks[index]
|
||||||
|
| (gdb_notifier.check_masks + MASK_SIZE)[index]
|
||||||
|
| (gdb_notifier.check_masks + 2 * (MASK_SIZE))[index];
|
||||||
|
if (flags)
|
||||||
|
{
|
||||||
|
for (i = (NBBY * sizeof (fd_mask)); i > 0; i--)
|
||||||
|
{
|
||||||
|
if (flags & (((unsigned long) 1) << (i - 1)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
gdb_notifier.num_fds = index * (NBBY * sizeof (fd_mask)) + i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* HAVE_POLL */
|
||||||
|
|
||||||
|
/* Get rid of the file handler in the file handler list. */
|
||||||
|
if (file_ptr == gdb_notifier.first_file_handler)
|
||||||
|
gdb_notifier.first_file_handler = file_ptr->next_file;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (prev_ptr = gdb_notifier.first_file_handler;
|
||||||
|
prev_ptr->next_file == file_ptr;
|
||||||
|
prev_ptr = prev_ptr->next_file)
|
||||||
|
;
|
||||||
|
prev_ptr->next_file = file_ptr->next_file;
|
||||||
|
}
|
||||||
|
free ((char *) file_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle the given event by calling the procedure associated to the
|
||||||
|
corresponding file handler. Called by process_event indirectly,
|
||||||
|
through event_ptr->proc. EVENT_FILE_DESC is file descriptor of the
|
||||||
|
event in the front of the event queue. */
|
||||||
|
static void
|
||||||
|
handle_file_event (event_file_desc)
|
||||||
|
int event_file_desc;
|
||||||
|
{
|
||||||
|
file_handler *file_ptr;
|
||||||
|
int mask, error_mask;
|
||||||
|
|
||||||
|
/* Search the file handler list to find one that matches the fd in
|
||||||
|
the event. */
|
||||||
|
for (file_ptr = gdb_notifier.first_file_handler; file_ptr != NULL;
|
||||||
|
file_ptr = file_ptr->next_file)
|
||||||
|
{
|
||||||
|
if (file_ptr->fd == event_file_desc)
|
||||||
|
{
|
||||||
|
/* With poll, the ready_mask could have any of three events
|
||||||
|
set to 1: POLLHUP, POLLERR, POLLNVAL. These events cannot
|
||||||
|
be used in the requested event mask (events), but they
|
||||||
|
can be returned in the return mask (revents). We need to
|
||||||
|
check for those event too, and add them to the mask which
|
||||||
|
will be passed to the handler. */
|
||||||
|
|
||||||
|
/* See if the desired events (mask) match the received
|
||||||
|
events (ready_mask). */
|
||||||
|
|
||||||
|
#ifdef HAVE_POLL
|
||||||
|
error_mask = POLLHUP | POLLERR | POLLNVAL;
|
||||||
|
mask = (file_ptr->ready_mask & file_ptr->mask) |
|
||||||
|
(file_ptr->ready_mask & error_mask);
|
||||||
|
|
||||||
|
#else /* ! HAVE_POLL */
|
||||||
|
mask = file_ptr->ready_mask & file_ptr->mask;
|
||||||
|
#endif /* HAVE_POLL */
|
||||||
|
|
||||||
|
/* Clear the received events for next time around. */
|
||||||
|
file_ptr->ready_mask = 0;
|
||||||
|
|
||||||
|
/* If there was a match, then call the handler. */
|
||||||
|
if (mask != 0)
|
||||||
|
(*file_ptr->proc) (file_ptr->client_data, mask);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called by gdb_do_one_event to wait for new events on the
|
||||||
|
monitored file descriptors. Queue file events as they are
|
||||||
|
detected by the poll.
|
||||||
|
If there are no events, this function will block in the
|
||||||
|
call to poll.
|
||||||
|
Return -1 if there are no files descriptors to monitor,
|
||||||
|
otherwise return 0. */
|
||||||
|
static int
|
||||||
|
gdb_wait_for_event ()
|
||||||
|
{
|
||||||
|
file_handler *file_ptr;
|
||||||
|
gdb_event *file_event_ptr;
|
||||||
|
int num_found, i;
|
||||||
|
|
||||||
|
#ifndef HAVE_POLL
|
||||||
|
int mask, bit, index;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (gdb_notifier.num_fds == 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
#ifdef HAVE_POLL
|
||||||
|
num_found =
|
||||||
|
poll (gdb_notifier.poll_fds, (unsigned long) gdb_notifier.num_fds, -1);
|
||||||
|
|
||||||
|
#else /* ! HAVE_POLL */
|
||||||
|
memcpy (gdb_notifier.ready_masks,
|
||||||
|
gdb_notifier.check_masks,
|
||||||
|
3 * MASK_SIZE * sizeof (fd_mask));
|
||||||
|
num_found = select (gdb_notifier.num_fds,
|
||||||
|
(SELECT_MASK *) & gdb_notifier.ready_masks[0],
|
||||||
|
(SELECT_MASK *) & gdb_notifier.ready_masks[MASK_SIZE],
|
||||||
|
(SELECT_MASK *) & gdb_notifier.ready_masks[2 * MASK_SIZE],
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
/* Clear the masks after an error from select. */
|
||||||
|
if (num_found == -1)
|
||||||
|
memset (gdb_notifier.ready_masks,
|
||||||
|
0, 3 * MASK_SIZE * sizeof (fd_mask));
|
||||||
|
|
||||||
|
#endif /* HAVE_POLL */
|
||||||
|
|
||||||
|
/* Enqueue all detected file events. */
|
||||||
|
|
||||||
|
#ifdef HAVE_POLL
|
||||||
|
|
||||||
|
for (i = 0; (i < gdb_notifier.num_fds) && (num_found > 0); i++)
|
||||||
|
{
|
||||||
|
if ((gdb_notifier.poll_fds + i)->revents)
|
||||||
|
num_found--;
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (file_ptr = gdb_notifier.first_file_handler;
|
||||||
|
file_ptr != NULL;
|
||||||
|
file_ptr = file_ptr->next_file)
|
||||||
|
{
|
||||||
|
if (file_ptr->fd == (gdb_notifier.poll_fds + i)->fd)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_ptr)
|
||||||
|
{
|
||||||
|
/* Enqueue an event only if this is still a new event for
|
||||||
|
this fd. */
|
||||||
|
if (file_ptr->ready_mask == 0)
|
||||||
|
{
|
||||||
|
file_event_ptr =
|
||||||
|
(gdb_event *) xmalloc (sizeof (gdb_event));
|
||||||
|
file_event_ptr->proc = handle_file_event;
|
||||||
|
file_event_ptr->fd = file_ptr->fd;
|
||||||
|
async_queue_event (file_event_ptr, TAIL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
file_ptr->ready_mask = (gdb_notifier.poll_fds + i)->revents;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* ! HAVE_POLL */
|
||||||
|
for (file_ptr = gdb_notifier.first_file_handler;
|
||||||
|
(file_ptr != NULL) && (num_found > 0);
|
||||||
|
file_ptr = file_ptr->next_file)
|
||||||
|
{
|
||||||
|
index = file_ptr->fd / (NBBY * sizeof (fd_mask));
|
||||||
|
bit = 1 << (file_ptr->fd % (NBBY * sizeof (fd_mask)));
|
||||||
|
mask = 0;
|
||||||
|
|
||||||
|
if (gdb_notifier.ready_masks[index] & bit)
|
||||||
|
mask |= GDB_READABLE;
|
||||||
|
if ((gdb_notifier.ready_masks + MASK_SIZE)[index] & bit)
|
||||||
|
mask |= GDB_WRITABLE;
|
||||||
|
if ((gdb_notifier.ready_masks + 2 * (MASK_SIZE))[index] & bit)
|
||||||
|
mask |= GDB_EXCEPTION;
|
||||||
|
|
||||||
|
if (!mask)
|
||||||
|
continue;
|
||||||
|
else
|
||||||
|
num_found--;
|
||||||
|
|
||||||
|
/* Enqueue an event only if this is still a new event for
|
||||||
|
this fd. */
|
||||||
|
|
||||||
|
if (file_ptr->ready_mask == 0)
|
||||||
|
{
|
||||||
|
file_event_ptr =
|
||||||
|
(gdb_event *) xmalloc (sizeof (gdb_event));
|
||||||
|
file_event_ptr->proc = handle_file_event;
|
||||||
|
file_event_ptr->fd = file_ptr->fd;
|
||||||
|
async_queue_event (file_event_ptr, TAIL);
|
||||||
|
}
|
||||||
|
file_ptr->ready_mask = mask;
|
||||||
|
}
|
||||||
|
#endif /* HAVE_POLL */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Create an asynchronous handler, allocating memory for it.
|
||||||
|
Return a pointer to the newly created handler.
|
||||||
|
This pointer will be used to invoke the handler by
|
||||||
|
invoke_async_signal_handler.
|
||||||
|
PROC is the function to call with CLIENT_DATA argument
|
||||||
|
whenever the handler is invoked. */
|
||||||
|
async_signal_handler *
|
||||||
|
create_async_signal_handler (proc, client_data)
|
||||||
|
async_handler_func *proc;
|
||||||
|
gdb_client_data client_data;
|
||||||
|
{
|
||||||
|
async_signal_handler *async_handler_ptr;
|
||||||
|
|
||||||
|
async_handler_ptr =
|
||||||
|
(async_signal_handler *) xmalloc (sizeof (async_signal_handler));
|
||||||
|
async_handler_ptr->ready = 0;
|
||||||
|
async_handler_ptr->next_handler = NULL;
|
||||||
|
async_handler_ptr->proc = proc;
|
||||||
|
async_handler_ptr->client_data = client_data;
|
||||||
|
if (sighandler_list.first_handler == NULL)
|
||||||
|
sighandler_list.first_handler = async_handler_ptr;
|
||||||
|
else
|
||||||
|
sighandler_list.last_handler->next_handler = async_handler_ptr;
|
||||||
|
sighandler_list.last_handler = async_handler_ptr;
|
||||||
|
return async_handler_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Mark the handler (ASYNC_HANDLER_PTR) as ready. This information will
|
||||||
|
be used when the handlers are invoked, after we have waited for
|
||||||
|
some event. The caller of this function is the interrupt handler
|
||||||
|
associated with a signal. */
|
||||||
|
void
|
||||||
|
mark_async_signal_handler (async_handler_ptr)
|
||||||
|
async_signal_handler *async_handler_ptr;
|
||||||
|
{
|
||||||
|
((async_signal_handler *) async_handler_ptr)->ready = 1;
|
||||||
|
async_handler_ready = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Call all the handlers that are ready. */
|
||||||
|
static void
|
||||||
|
invoke_async_signal_handler ()
|
||||||
|
{
|
||||||
|
async_signal_handler *async_handler_ptr;
|
||||||
|
|
||||||
|
if (async_handler_ready == 0)
|
||||||
|
return;
|
||||||
|
async_handler_ready = 0;
|
||||||
|
|
||||||
|
/* Invoke ready handlers. */
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
for (async_handler_ptr = sighandler_list.first_handler;
|
||||||
|
async_handler_ptr != NULL;
|
||||||
|
async_handler_ptr = async_handler_ptr->next_handler)
|
||||||
|
{
|
||||||
|
if (async_handler_ptr->ready)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (async_handler_ptr == NULL)
|
||||||
|
break;
|
||||||
|
async_handler_ptr->ready = 0;
|
||||||
|
(*async_handler_ptr->proc) (async_handler_ptr->client_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Delete an asynchronous handler (ASYNC_HANDLER_PTR).
|
||||||
|
Free the space allocated for it. */
|
||||||
|
void
|
||||||
|
delete_async_signal_handler (async_handler_ptr)
|
||||||
|
async_signal_handler *async_handler_ptr;
|
||||||
|
{
|
||||||
|
async_signal_handler *prev_ptr;
|
||||||
|
|
||||||
|
if (sighandler_list.first_handler == async_handler_ptr)
|
||||||
|
{
|
||||||
|
sighandler_list.first_handler = async_handler_ptr->next_handler;
|
||||||
|
if (sighandler_list.first_handler == NULL)
|
||||||
|
sighandler_list.last_handler = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
prev_ptr = sighandler_list.first_handler;
|
||||||
|
while (prev_ptr->next_handler != async_handler_ptr)
|
||||||
|
prev_ptr = prev_ptr->next_handler;
|
||||||
|
prev_ptr->next_handler = async_handler_ptr->next_handler;
|
||||||
|
if (sighandler_list.last_handler == async_handler_ptr)
|
||||||
|
sighandler_list.last_handler = prev_ptr;
|
||||||
|
}
|
||||||
|
free ((char *) async_handler_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Is it necessary to call invoke_async_signal_handler? */
|
||||||
|
static int
|
||||||
|
check_async_ready ()
|
||||||
|
{
|
||||||
|
return async_handler_ready;
|
||||||
|
}
|
241
gdb/event-loop.h
Normal file
241
gdb/event-loop.h
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
/* Definitions used by the GDB event loop.
|
||||||
|
Copyright 1999 Free Software Foundation, Inc.
|
||||||
|
Written by Elena Zannoni <ezannoni@cygnus.com> of Cygnus Solutions.
|
||||||
|
|
||||||
|
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 2 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, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include "defs.h"
|
||||||
|
|
||||||
|
/* An event loop listens for events from multiple event sources. When
|
||||||
|
an event arrives, it is queued and processed by calling the
|
||||||
|
appropriate event handler. The event loop then continues to listen
|
||||||
|
for more events. An event loop completes when there are no event
|
||||||
|
sources to listen on. External event sources can be plugged into
|
||||||
|
the loop.
|
||||||
|
|
||||||
|
There are 3 main components:
|
||||||
|
- a list of file descriptors to be monitored, GDB_NOTIFIER.
|
||||||
|
- a list of events that have occurred, EVENT_QUEUE.
|
||||||
|
- a list of signal handling functions, SIGHANDLER_LIST.
|
||||||
|
|
||||||
|
GDB_NOTIFIER keeps track of the event sources. Event sources for
|
||||||
|
gdb are currently the UI and the target. Gdb communicates with the
|
||||||
|
command line user interface via the readline library and usually
|
||||||
|
communicates with remote targets via a serial port. Serial ports
|
||||||
|
are represented in GDB as file descriptors and select/poll calls.
|
||||||
|
For native targets instead, the communication consists of calls to
|
||||||
|
ptrace and waits (via signals) or calls to poll/select (via file
|
||||||
|
descriptors). In the current gdb, the code handling events related
|
||||||
|
to the target resides in the wait_for_inferior function and in
|
||||||
|
various target specific files (*-tdep.c).
|
||||||
|
|
||||||
|
EVENT_QUEUE keeps track of the events that have happened during the
|
||||||
|
last iteration of the event loop, and need to be processed. An
|
||||||
|
event is represented by a procedure to be invoked in order to
|
||||||
|
process the event. The queue is scanned head to tail. If the
|
||||||
|
event of interest is a change of state in a file descriptor, then a
|
||||||
|
call to poll or select will be made to detect it.
|
||||||
|
|
||||||
|
If the events generate signals, they are also queued by special
|
||||||
|
functions that are invoked through traditional signal handlers.
|
||||||
|
The actions to be taken is response to such events will be executed
|
||||||
|
when the SIGHANDLER_LIST is scanned, the next time through the
|
||||||
|
infinite loop.
|
||||||
|
|
||||||
|
Corollary tasks are the creation and deletion of event sources. */
|
||||||
|
|
||||||
|
typedef PTR gdb_client_data;
|
||||||
|
typedef struct gdb_event gdb_event;
|
||||||
|
|
||||||
|
typedef void (file_handler_func) PARAMS ((gdb_client_data, int mask));
|
||||||
|
typedef void (async_handler_func) PARAMS ((gdb_client_data));
|
||||||
|
typedef void (event_handler_func) PARAMS ((int));
|
||||||
|
|
||||||
|
/* Event for the GDB event system. Events are queued by calling
|
||||||
|
async_queue_event and serviced later on by gdb_do_one_event. An
|
||||||
|
event can be, for instance, a file descriptor becoming ready to be
|
||||||
|
read. Servicing an event simply means that the procedure PROC will
|
||||||
|
be called. We have 2 queues, one for file handlers that we listen
|
||||||
|
to in the event loop, and one for the file handlers+events that are
|
||||||
|
ready. The procedure PROC associated with each event is always the
|
||||||
|
same (handle_file_event). Its duty is to invoke the handler
|
||||||
|
associated with the file descriptor whose state change generated
|
||||||
|
the event, plus doing other cleanups adn such. */
|
||||||
|
|
||||||
|
struct gdb_event
|
||||||
|
{
|
||||||
|
event_handler_func *proc; /* Procedure to call to service this event. */
|
||||||
|
int fd; /* File descriptor that is ready. */
|
||||||
|
struct gdb_event *next_event; /* Next in list of events or NULL. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Information about each file descriptor we register with the event
|
||||||
|
loop. */
|
||||||
|
|
||||||
|
typedef struct file_handler
|
||||||
|
{
|
||||||
|
int fd; /* File descriptor. */
|
||||||
|
int mask; /* Events we want to monitor: POLLIN, etc. */
|
||||||
|
int ready_mask; /* Events that have been seen since
|
||||||
|
the last time. */
|
||||||
|
file_handler_func *proc; /* Procedure to call when fd is ready. */
|
||||||
|
gdb_client_data client_data; /* Argument to pass to proc. */
|
||||||
|
struct file_handler *next_file; /* Next registered file descriptor. */
|
||||||
|
}
|
||||||
|
file_handler;
|
||||||
|
|
||||||
|
/* PROC is a function to be invoked when the READY flag is set. This
|
||||||
|
happens when there has been a signal and the corresponding signal
|
||||||
|
handler has 'triggered' this async_signal_handler for
|
||||||
|
execution. The actual work to be done in response to a signal will
|
||||||
|
be carried out by PROC at a later time, within process_event. This
|
||||||
|
provides a deferred execution of signal handlers.
|
||||||
|
Async_init_signals takes care of setting up such an
|
||||||
|
asyn_signal_handler for each interesting signal. */
|
||||||
|
|
||||||
|
typedef struct async_signal_handler
|
||||||
|
{
|
||||||
|
int ready; /* If ready, call this handler from the main event loop,
|
||||||
|
using invoke_async_handler. */
|
||||||
|
struct async_signal_handler *next_handler; /* Ptr to next handler */
|
||||||
|
async_handler_func *proc; /* Function to call to do the work */
|
||||||
|
gdb_client_data client_data; /* Argument to async_handler_func */
|
||||||
|
}
|
||||||
|
async_signal_handler;
|
||||||
|
|
||||||
|
/* Where to add an event onto the event queue, by queue_event. */
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
/* Add at tail of queue. It will be processed in first in first
|
||||||
|
out order. */
|
||||||
|
TAIL,
|
||||||
|
/* Add at head of queue. It will be processed in last in first out
|
||||||
|
order. */
|
||||||
|
HEAD
|
||||||
|
}
|
||||||
|
queue_position;
|
||||||
|
|
||||||
|
/* Tell create_file_handler what events we are interested in.
|
||||||
|
This is used by the select version of the event loop. */
|
||||||
|
|
||||||
|
#define GDB_READABLE (1<<1)
|
||||||
|
#define GDB_WRITABLE (1<<2)
|
||||||
|
#define GDB_EXCEPTION (1<<3)
|
||||||
|
|
||||||
|
/* Type of the mask arguments to select. */
|
||||||
|
|
||||||
|
#ifndef NO_FD_SET
|
||||||
|
#define SELECT_MASK fd_set
|
||||||
|
#else
|
||||||
|
#ifndef _AIX
|
||||||
|
typedef long fd_mask;
|
||||||
|
#endif
|
||||||
|
#if defined(_IBMR2)
|
||||||
|
#define SELECT_MASK void
|
||||||
|
#else
|
||||||
|
#define SELECT_MASK int
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Define "NBBY" (number of bits per byte) if it's not already defined. */
|
||||||
|
|
||||||
|
#ifndef NBBY
|
||||||
|
#define NBBY 8
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Define the number of fd_masks in an fd_set */
|
||||||
|
|
||||||
|
#ifndef FD_SETSIZE
|
||||||
|
#ifdef OPEN_MAX
|
||||||
|
#define FD_SETSIZE OPEN_MAX
|
||||||
|
#else
|
||||||
|
#define FD_SETSIZE 256
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#if !defined(howmany)
|
||||||
|
#define howmany(x, y) (((x)+((y)-1))/(y))
|
||||||
|
#endif
|
||||||
|
#ifndef NFDBITS
|
||||||
|
#define NFDBITS NBBY*sizeof(fd_mask)
|
||||||
|
#endif
|
||||||
|
#define MASK_SIZE howmany(FD_SETSIZE, NFDBITS)
|
||||||
|
|
||||||
|
|
||||||
|
/* Stack for prompts. Each prompt is composed as a prefix, a prompt
|
||||||
|
and a suffix. The prompt to be displayed at any given time is the
|
||||||
|
one on top of the stack. A stack is necessary because of cases in
|
||||||
|
which the execution of a gdb command requires further input from
|
||||||
|
the user, like for instance 'commands' for breakpoints and
|
||||||
|
'actions' for tracepoints. In these cases, the prompt is '>' and
|
||||||
|
gdb should process input using the asynchronous readline interface
|
||||||
|
and the event loop. In order to achieve this, we need to save
|
||||||
|
somewhere the state of GDB, i.e. that it is processing user input
|
||||||
|
as part of a command and not as part of the top level command loop.
|
||||||
|
The prompt stack represents part of the saved state. Another part
|
||||||
|
would be the function that readline would invoke after a whole line
|
||||||
|
of input has ben entered. This second piece would be something
|
||||||
|
like, for instance, where to return within the code for the actions
|
||||||
|
commands after a line has been read. This latter portion has not
|
||||||
|
beeen implemented yet. The need for a 3-part prompt arises from
|
||||||
|
the annotation level. When this is set to 2, the prompt is actually
|
||||||
|
composed of a prefix, the prompt itself and a suffix. */
|
||||||
|
|
||||||
|
/* At any particular time there will be always at least one prompt on
|
||||||
|
the stack, the one being currently displayed by gdb. If gdb is
|
||||||
|
using annotation level equal 2, there will be 2 prompts on the
|
||||||
|
stack: the usual one, w/o prefix and suffix (at top - 1), and the
|
||||||
|
'composite' one with prefix and suffix added (at top). At this
|
||||||
|
time, this is the only use of the prompt stack. Resetting annotate
|
||||||
|
to 0 or 1, pops the top of the stack, resetting its size to one
|
||||||
|
element. The MAXPROMPTS limit is safe, for now. Once other cases
|
||||||
|
are dealt with (like the different prompts used for 'commands' or
|
||||||
|
'actions') this array implementation of the prompt stack may have
|
||||||
|
to change. */
|
||||||
|
|
||||||
|
#define MAXPROMPTS 10
|
||||||
|
struct prompts
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
char *prefix;
|
||||||
|
char *prompt;
|
||||||
|
char *suffix;
|
||||||
|
}
|
||||||
|
prompt_stack[MAXPROMPTS];
|
||||||
|
int top;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PROMPT(X) the_prompts.prompt_stack[the_prompts.top + X].prompt
|
||||||
|
#define PREFIX(X) the_prompts.prompt_stack[the_prompts.top + X].prefix
|
||||||
|
#define SUFFIX(X) the_prompts.prompt_stack[the_prompts.top + X].suffix
|
||||||
|
|
||||||
|
extern void delete_file_handler PARAMS ((int));
|
||||||
|
extern void
|
||||||
|
create_file_handler PARAMS ((int, int, file_handler_func, gdb_client_data));
|
||||||
|
extern int gdb_do_one_event PARAMS ((void));
|
||||||
|
extern void mark_async_signal_handler PARAMS ((async_signal_handler *));
|
||||||
|
extern async_signal_handler *
|
||||||
|
create_async_signal_handler PARAMS ((async_handler_func *, gdb_client_data));
|
||||||
|
|
950
gdb/event-top.c
Normal file
950
gdb/event-top.c
Normal file
@ -0,0 +1,950 @@
|
|||||||
|
/* Top level stuff for GDB, the GNU debugger.
|
||||||
|
Copyright 1999 Free Software Foundation, Inc.
|
||||||
|
Written by Elena Zannoni <ezannoni@cygnus.com> of Cygnus Solutions.
|
||||||
|
|
||||||
|
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 2 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, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||||
|
|
||||||
|
#include "defs.h"
|
||||||
|
#include "event-loop.h"
|
||||||
|
#ifdef HAVE_POLL
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#endif
|
||||||
|
#include "inferior.h"
|
||||||
|
|
||||||
|
/* readline include files */
|
||||||
|
#include <readline/readline.h>
|
||||||
|
#include <readline/history.h>
|
||||||
|
|
||||||
|
/* readline defines this. */
|
||||||
|
#undef savestring
|
||||||
|
|
||||||
|
extern FILE *instream;
|
||||||
|
|
||||||
|
static void command_line_handler PARAMS ((char *));
|
||||||
|
static void gdb_readline2 PARAMS ((void));
|
||||||
|
static void pop_prompt PARAMS ((void));
|
||||||
|
static void push_prompt PARAMS ((char *, char *, char *));
|
||||||
|
|
||||||
|
/* Signal handlers. */
|
||||||
|
void handle_sigint PARAMS ((int));
|
||||||
|
void handle_sigquit PARAMS ((int));
|
||||||
|
void handle_sighup PARAMS ((int));
|
||||||
|
void handle_sigfpe PARAMS ((int));
|
||||||
|
void handle_sigwinch PARAMS ((int));
|
||||||
|
|
||||||
|
/* Functions to be invoked by the event loop in response to
|
||||||
|
signals. */
|
||||||
|
void async_request_quit PARAMS ((void));
|
||||||
|
void async_do_nothing PARAMS ((void));
|
||||||
|
void async_disconnect PARAMS ((void));
|
||||||
|
void async_float_handler PARAMS ((void));
|
||||||
|
|
||||||
|
/* Functions from top.c. */
|
||||||
|
extern void command_loop_marker PARAMS ((int));
|
||||||
|
extern int quit_cover PARAMS ((PTR));
|
||||||
|
extern void quit_command PARAMS ((char *, int));
|
||||||
|
extern void execute_command PARAMS ((char *, int));
|
||||||
|
|
||||||
|
/* Variables from top.c. */
|
||||||
|
extern int source_line_number;
|
||||||
|
extern char *source_file_name;
|
||||||
|
extern char *source_error;
|
||||||
|
extern char *source_pre_error;
|
||||||
|
extern int history_expansion_p;
|
||||||
|
extern int server_command;
|
||||||
|
|
||||||
|
/* If this definition isn't overridden by the header files, assume
|
||||||
|
that isatty and fileno exist on this system. */
|
||||||
|
#ifndef ISATTY
|
||||||
|
#define ISATTY(FP) (isatty (fileno (FP)))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Hook for alternate command interface. */
|
||||||
|
void (*async_hook) PARAMS ((void));
|
||||||
|
|
||||||
|
/* Readline offers an alternate interface, via callback
|
||||||
|
functions. These are all included in the file callback.c in the
|
||||||
|
readline distribution. This file provides (mainly) a function, which
|
||||||
|
the event loop uses as callback (i.e. event handler) whenever an event
|
||||||
|
is detected on the standard input file descriptor.
|
||||||
|
readline_callback_read_char is called (by the GDB event loop) whenever
|
||||||
|
there is a new character ready on the input stream. This function
|
||||||
|
incrementally builds a buffer internal to readline where it
|
||||||
|
accumulates the line read up to the point of invocation. In the
|
||||||
|
special case in which the character read is newline, the function
|
||||||
|
invokes a GDB supplied callback routine, which does the processing of
|
||||||
|
a full command line. This latter routine is the asynchronous analog
|
||||||
|
of the old command_line_input in gdb. Instead of invoking (and waiting
|
||||||
|
for) readline to read the command line and pass it back to
|
||||||
|
command_loop for processing, the new command_line_handler function has
|
||||||
|
the command line already available as its parameter. INPUT_HANDLER is
|
||||||
|
to be set to the function that readline will invoke when a complete
|
||||||
|
line of input is ready. CALL_READLINE is to be set to the function
|
||||||
|
that readline offers as callback to the event_loop. */
|
||||||
|
|
||||||
|
void (*input_handler) PARAMS ((char *));
|
||||||
|
void (*call_readline) PARAMS ((void));
|
||||||
|
|
||||||
|
/* Important variables for the event loop. */
|
||||||
|
|
||||||
|
/* This is used to determine if GDB is using the readline library or
|
||||||
|
its own simplified form of readline. It is used by the asynchronous
|
||||||
|
form of the set editing command.
|
||||||
|
ezannoni: as of 4/29/99 I expect that this
|
||||||
|
variable will not be used after gdb is changed to use the event
|
||||||
|
loop as default engine, and event-top.c is merged into top.c. */
|
||||||
|
int async_command_editing_p;
|
||||||
|
|
||||||
|
/* This variable contains the new prompt that the user sets with the
|
||||||
|
set prompt command. */
|
||||||
|
char *new_async_prompt;
|
||||||
|
|
||||||
|
/* This is the annotation suffix that will be used when the
|
||||||
|
annotation_level is 2. */
|
||||||
|
char *async_annotation_suffix;
|
||||||
|
|
||||||
|
/* This is the file descriptor for the input stream that GDB uses to
|
||||||
|
read commands from. */
|
||||||
|
int input_fd;
|
||||||
|
|
||||||
|
/* This is the prompt stack. Prompts will be pushed on the stack as
|
||||||
|
needed by the different 'kinds' of user inputs GDB is asking
|
||||||
|
for. See event-loop.h. */
|
||||||
|
struct prompts the_prompts;
|
||||||
|
|
||||||
|
/* signal handling variables */
|
||||||
|
/* Each of these is a pointer to a function that the event loop will
|
||||||
|
invoke if the corresponding signal has received. The real signal
|
||||||
|
handlers mark these functions as ready to be executed and the event
|
||||||
|
loop, in a later iteration, calls them. See the function
|
||||||
|
invoke_async_signal_handler. */
|
||||||
|
async_signal_handler *sigint_token;
|
||||||
|
#ifdef SIGHUP
|
||||||
|
async_signal_handler *sighup_token;
|
||||||
|
#endif
|
||||||
|
async_signal_handler *sigquit_token;
|
||||||
|
async_signal_handler *sigfpe_token;
|
||||||
|
#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER)
|
||||||
|
async_signal_handler *sigwinch_token;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Structure to save a partially entered command. This is used when
|
||||||
|
the user types '\' at the end of a command line. This is necessary
|
||||||
|
because each line of input is handled by a different call to
|
||||||
|
command_line_handler, and normally there is no state retained
|
||||||
|
between different calls. */
|
||||||
|
int more_to_come = 0;
|
||||||
|
|
||||||
|
struct readline_input_state
|
||||||
|
{
|
||||||
|
char *linebuffer;
|
||||||
|
char *linebuffer_ptr;
|
||||||
|
}
|
||||||
|
readline_input_state;
|
||||||
|
|
||||||
|
|
||||||
|
/* Initialize all the necessary variables, start the event loop,
|
||||||
|
register readline, and stdin. */
|
||||||
|
void
|
||||||
|
setup_event_loop ()
|
||||||
|
{
|
||||||
|
int length = strlen (PREFIX (0)) + strlen (PROMPT (0)) + strlen (SUFFIX (0)) + 1;
|
||||||
|
char *a_prompt = (char *) xmalloc (length);
|
||||||
|
|
||||||
|
/* Set things up for readline to be invoked via the alternate
|
||||||
|
interface, i.e. via a callback function (rl_callback_read_char). */
|
||||||
|
call_readline = rl_callback_read_char;
|
||||||
|
|
||||||
|
/* When readline has read an end-of-line character, it passes the
|
||||||
|
complete line to gdb for processing. command_line_handler is the
|
||||||
|
function that does this. */
|
||||||
|
input_handler = command_line_handler;
|
||||||
|
|
||||||
|
/* Tell readline what the prompt to display is and what function it
|
||||||
|
will need to call after a whole line is read. */
|
||||||
|
strcpy (a_prompt, PREFIX (0));
|
||||||
|
strcat (a_prompt, PROMPT (0));
|
||||||
|
strcat (a_prompt, SUFFIX (0));
|
||||||
|
rl_callback_handler_install (a_prompt, input_handler);
|
||||||
|
|
||||||
|
/* Tell readline to use the same input stream that gdb uses. */
|
||||||
|
rl_instream = instream;
|
||||||
|
/* Get a file descriptor for the input stream, so that we can
|
||||||
|
register it with the event loop. */
|
||||||
|
input_fd = fileno (instream);
|
||||||
|
|
||||||
|
/* Now we need to create the event sources for the input file descriptor. */
|
||||||
|
/* At this point in time, this is the only event source that we
|
||||||
|
register with the even loop. Another source is going to be the
|
||||||
|
target program (inferior), but that must be registered only when
|
||||||
|
it actually exists (I.e. after we say 'run' or after we connect
|
||||||
|
to a remote target. */
|
||||||
|
#ifdef HAVE_POLL
|
||||||
|
create_file_handler (input_fd, POLLIN,
|
||||||
|
(file_handler_func *) call_readline, 0);
|
||||||
|
#else
|
||||||
|
create_file_handler (input_fd, GDB_READABLE,
|
||||||
|
(file_handler_func *) call_readline, 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Loop until there is something to do. This is the entry point to
|
||||||
|
the event loop engine. gdb_do_one_event will process one event
|
||||||
|
for each invocation. It always returns 1, unless there are no
|
||||||
|
more event sources registered. In this case it returns 0. */
|
||||||
|
while (gdb_do_one_event () != 0)
|
||||||
|
;
|
||||||
|
|
||||||
|
/* We are done with the event loop. There are no more event sources
|
||||||
|
to listen to. So we exit GDB. */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Change the function to be invoked every time there is a character
|
||||||
|
ready on stdin. This is used when the user sets the editing off,
|
||||||
|
therefore bypassing readline, and letting gdb handle the input
|
||||||
|
itself, via gdb_readline2. Also it is used in the opposite case in
|
||||||
|
which the user sets editing on again, by restoring readline
|
||||||
|
handling of the input. */
|
||||||
|
void
|
||||||
|
change_line_handler ()
|
||||||
|
{
|
||||||
|
if (async_command_editing_p)
|
||||||
|
{
|
||||||
|
/* Turn on editing by using readline. */
|
||||||
|
call_readline = rl_callback_read_char;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Turn off editing by using gdb_readline2. */
|
||||||
|
rl_callback_handler_remove ();
|
||||||
|
call_readline = gdb_readline2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* To tell the event loop to change the handler associated with the
|
||||||
|
input file descriptor, we need to create a new event source,
|
||||||
|
corresponding to the same fd, but with a new event handler
|
||||||
|
function. */
|
||||||
|
delete_file_handler (input_fd);
|
||||||
|
#ifdef HAVE_POLL
|
||||||
|
create_file_handler (input_fd, POLLIN,
|
||||||
|
(file_handler_func *) call_readline, 0);
|
||||||
|
#else
|
||||||
|
create_file_handler (input_fd, GDB_READABLE,
|
||||||
|
(file_handler_func *) call_readline, 0);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Displays the prompt. The prompt that is displayed is the current
|
||||||
|
top of the prompt stack, if the argument NEW_PROMPT is
|
||||||
|
0. Otherwise, it displays whatever NEW_PROMPT is. This is used
|
||||||
|
after each gdb command has completed, and in the following cases:
|
||||||
|
1. when the user enters a command line which is ended by '\'
|
||||||
|
indicating that the command will continue on the next line.
|
||||||
|
In that case the prompt that is displayed is the empty string.
|
||||||
|
2. When the user is entering 'commands' for a breakpoint, or
|
||||||
|
actions for a tracepoint. In this case the prompt will be '>'
|
||||||
|
3. Other????
|
||||||
|
FIXME: 2. & 3. not implemented yet for async. */
|
||||||
|
void
|
||||||
|
display_gdb_prompt (new_prompt)
|
||||||
|
char *new_prompt;
|
||||||
|
{
|
||||||
|
int prompt_length = 0;
|
||||||
|
|
||||||
|
if (!new_prompt)
|
||||||
|
{
|
||||||
|
/* Just use the top of the prompt stack. */
|
||||||
|
prompt_length = strlen (PREFIX (0)) +
|
||||||
|
strlen (SUFFIX (0)) +
|
||||||
|
strlen (PROMPT (0)) + 1;
|
||||||
|
|
||||||
|
new_prompt = (char *) alloca (prompt_length);
|
||||||
|
|
||||||
|
/* Prefix needs to have new line at end. */
|
||||||
|
strcpy (new_prompt, PREFIX (0));
|
||||||
|
strcat (new_prompt, PROMPT (0));
|
||||||
|
/* Suffix needs to have a new line at end and \032 \032 at
|
||||||
|
beginning. */
|
||||||
|
strcat (new_prompt, SUFFIX (0));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (async_command_editing_p)
|
||||||
|
{
|
||||||
|
rl_callback_handler_remove ();
|
||||||
|
rl_callback_handler_install (new_prompt, input_handler);
|
||||||
|
}
|
||||||
|
else if (new_prompt)
|
||||||
|
{
|
||||||
|
/* 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 (new_prompt, gdb_stdout);
|
||||||
|
|
||||||
|
#ifdef MPW
|
||||||
|
/* Move to a new line so the entered line doesn't have a prompt
|
||||||
|
on the front of it. */
|
||||||
|
fputs_unfiltered ("\n", gdb_stdout);
|
||||||
|
#endif /* MPW */
|
||||||
|
gdb_flush (gdb_stdout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Used when the user requests a different annotation level, with
|
||||||
|
'set annotate'. It pushes a new prompt (with prefix and suffix) on top
|
||||||
|
of the prompt stack, if the annotation level desired is 2, otherwise
|
||||||
|
it pops the top of the prompt stack when we want the annotation level
|
||||||
|
to be the normal ones (1 or 2). */
|
||||||
|
void
|
||||||
|
change_annotation_level ()
|
||||||
|
{
|
||||||
|
char *prefix, *suffix;
|
||||||
|
|
||||||
|
if (!PREFIX (0) || !PROMPT (0) || !SUFFIX (0))
|
||||||
|
{
|
||||||
|
/* The prompt stack has not been initialized to "", we are
|
||||||
|
using gdb w/o the --async switch */
|
||||||
|
warning ("Command has same effect as set annotate");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (annotation_level > 1)
|
||||||
|
{
|
||||||
|
if (!strcmp (PREFIX (0), "") && !strcmp (SUFFIX (0), ""))
|
||||||
|
{
|
||||||
|
/* Push a new prompt if the previous annotation_level was not >1. */
|
||||||
|
prefix = (char *) alloca (strlen (async_annotation_suffix) + 10);
|
||||||
|
strcpy (prefix, "\n\032\032pre-");
|
||||||
|
strcat (prefix, async_annotation_suffix);
|
||||||
|
strcat (prefix, "\n");
|
||||||
|
|
||||||
|
suffix = (char *) alloca (strlen (async_annotation_suffix) + 6);
|
||||||
|
strcpy (suffix, "\n\032\032");
|
||||||
|
strcat (suffix, async_annotation_suffix);
|
||||||
|
strcat (suffix, "\n");
|
||||||
|
|
||||||
|
push_prompt (prefix, (char *) 0, suffix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (strcmp (PREFIX (0), "") && strcmp (SUFFIX (0), ""))
|
||||||
|
{
|
||||||
|
/* Pop the top of the stack, we are going back to annotation < 1. */
|
||||||
|
pop_prompt ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pushes a new prompt on the prompt stack. Each prompt has three
|
||||||
|
parts: prefix, prompt, suffix. Usually prefix and suffix are empty
|
||||||
|
strings, except when the annotation level is 2. Memory is allocated
|
||||||
|
within savestring for the new prompt. */
|
||||||
|
static void
|
||||||
|
push_prompt (prefix, prompt, suffix)
|
||||||
|
char *prefix;
|
||||||
|
char *prompt;
|
||||||
|
char *suffix;
|
||||||
|
{
|
||||||
|
the_prompts.top++;
|
||||||
|
PREFIX (0) = savestring (prefix, strlen (prefix));
|
||||||
|
|
||||||
|
if (prompt)
|
||||||
|
PROMPT (0) = savestring (prompt, strlen (prompt));
|
||||||
|
else
|
||||||
|
PROMPT (0) = savestring (PROMPT (-1), strlen (PROMPT (-1)));
|
||||||
|
|
||||||
|
SUFFIX (0) = savestring (suffix, strlen (suffix));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pops the top of the prompt stack, and frees the memory allocated for it. */
|
||||||
|
static void
|
||||||
|
pop_prompt ()
|
||||||
|
{
|
||||||
|
if (strcmp (PROMPT (0), PROMPT (-1)))
|
||||||
|
{
|
||||||
|
free (PROMPT (-1));
|
||||||
|
PROMPT (-1) = savestring (PROMPT (0), strlen (PROMPT (0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
free (PREFIX (0));
|
||||||
|
free (PROMPT (0));
|
||||||
|
free (SUFFIX (0));
|
||||||
|
the_prompts.top--;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handles a gdb command. This function is called by
|
||||||
|
command_line_handler, which has processed one or more input lines
|
||||||
|
into COMMAND. */
|
||||||
|
/* NOTE: 4/30/99 This is the asynchronous version of the command_loop
|
||||||
|
function. The command_loop function will be obsolete when we
|
||||||
|
switch to use the event loop at every execution of gdb. */
|
||||||
|
void
|
||||||
|
command_handler (command)
|
||||||
|
char *command;
|
||||||
|
{
|
||||||
|
struct cleanup *old_chain;
|
||||||
|
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;
|
||||||
|
|
||||||
|
#if defined(TUI)
|
||||||
|
extern int insert_mode;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
quit_flag = 0;
|
||||||
|
if (instream == stdin && stdin_is_tty)
|
||||||
|
reinitialize_more_filter ();
|
||||||
|
old_chain = make_cleanup ((make_cleanup_func) command_loop_marker, 0);
|
||||||
|
|
||||||
|
#if defined(TUI)
|
||||||
|
insert_mode = 0;
|
||||||
|
#endif
|
||||||
|
/* If readline returned a NULL command, it means that the
|
||||||
|
connection with the terminal is gone. This happens at the
|
||||||
|
end of a testsuite run, after Expect has hung up
|
||||||
|
but GDB is still alive. In such a case, we just quit gdb
|
||||||
|
killing the inferior program too. */
|
||||||
|
if (command == 0)
|
||||||
|
quit_command ((char *) 0, stdin == instream);
|
||||||
|
|
||||||
|
time_at_cmd_start = get_run_time ();
|
||||||
|
|
||||||
|
if (display_space)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_SBRK
|
||||||
|
extern char **environ;
|
||||||
|
char *lim = (char *) sbrk (0);
|
||||||
|
|
||||||
|
space_at_cmd_start = (long) (lim - (char *) &environ);
|
||||||
|
#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
|
||||||
|
extern char **environ;
|
||||||
|
char *lim = (char *) sbrk (0);
|
||||||
|
long space_now = lim - (char *) &environ;
|
||||||
|
long space_diff = space_now - space_at_cmd_start;
|
||||||
|
|
||||||
|
printf_unfiltered ("Space used: %ld (%c%ld for this command)\n",
|
||||||
|
space_now,
|
||||||
|
(space_diff >= 0 ? '+' : '-'),
|
||||||
|
space_diff);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle a complete line of input. This is called by the callback
|
||||||
|
mechanism within the readline library. Deal with incomplete commands
|
||||||
|
as well, by saving the partial input in a global buffer. */
|
||||||
|
|
||||||
|
/* NOTE: 4/30/99 This is the asynchronous version of the
|
||||||
|
command_line_input function. command_line_input will become
|
||||||
|
obsolete once we use the event loop as the default mechanism in
|
||||||
|
GDB. */
|
||||||
|
static void
|
||||||
|
command_line_handler (rl)
|
||||||
|
char *rl;
|
||||||
|
{
|
||||||
|
static char *linebuffer = 0;
|
||||||
|
static unsigned linelength = 0;
|
||||||
|
register char *p;
|
||||||
|
char *p1;
|
||||||
|
int change_prompt = 0;
|
||||||
|
extern char *line;
|
||||||
|
extern int linesize;
|
||||||
|
char *nline;
|
||||||
|
char got_eof = 0;
|
||||||
|
|
||||||
|
|
||||||
|
int repeat = (instream == stdin);
|
||||||
|
|
||||||
|
if (annotation_level > 1 && instream == stdin)
|
||||||
|
{
|
||||||
|
printf_unfiltered ("\n\032\032post-");
|
||||||
|
printf_unfiltered (async_annotation_suffix);
|
||||||
|
printf_unfiltered ("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (linebuffer == 0)
|
||||||
|
{
|
||||||
|
linelength = 80;
|
||||||
|
linebuffer = (char *) xmalloc (linelength);
|
||||||
|
}
|
||||||
|
|
||||||
|
p = linebuffer;
|
||||||
|
|
||||||
|
if (more_to_come)
|
||||||
|
{
|
||||||
|
strcpy (linebuffer, readline_input_state.linebuffer);
|
||||||
|
p = readline_input_state.linebuffer_ptr;
|
||||||
|
free (readline_input_state.linebuffer);
|
||||||
|
more_to_come = 0;
|
||||||
|
change_prompt = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef STOP_SIGNAL
|
||||||
|
if (job_control)
|
||||||
|
signal (STOP_SIGNAL, stop_sig);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
sprintf (source_error,
|
||||||
|
"%s%s:%d: Error in sourced command file:\n",
|
||||||
|
source_pre_error,
|
||||||
|
source_file_name,
|
||||||
|
source_line_number);
|
||||||
|
error_pre_print = source_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we are in this case, then command_handler will call quit
|
||||||
|
and exit from gdb. */
|
||||||
|
if (!rl || rl == (char *) EOF)
|
||||||
|
{
|
||||||
|
got_eof = 1;
|
||||||
|
command_handler (0);
|
||||||
|
}
|
||||||
|
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++;
|
||||||
|
|
||||||
|
free (rl); /* Allocated in readline. */
|
||||||
|
|
||||||
|
if (p == linebuffer || *(p - 1) == '\\')
|
||||||
|
{
|
||||||
|
/* We come here also if the line entered is empty (just a 'return') */
|
||||||
|
p--; /* Put on top of '\'. */
|
||||||
|
|
||||||
|
if (*p == '\\')
|
||||||
|
{
|
||||||
|
readline_input_state.linebuffer = savestring (linebuffer,
|
||||||
|
strlen (linebuffer));
|
||||||
|
readline_input_state.linebuffer_ptr = p;
|
||||||
|
|
||||||
|
/* We will not invoke a execute_command if there is more
|
||||||
|
input expected to complete the command. So, we need to
|
||||||
|
print an empty prompt here. */
|
||||||
|
display_gdb_prompt ("");
|
||||||
|
more_to_come = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef STOP_SIGNAL
|
||||||
|
if (job_control)
|
||||||
|
signal (STOP_SIGNAL, SIG_DFL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SERVER_COMMAND_LENGTH 7
|
||||||
|
server_command =
|
||||||
|
(p - linebuffer > SERVER_COMMAND_LENGTH)
|
||||||
|
&& STREQN (linebuffer, "server ", SERVER_COMMAND_LENGTH);
|
||||||
|
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';
|
||||||
|
command_handler (linebuffer + SERVER_COMMAND_LENGTH);
|
||||||
|
display_gdb_prompt (0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
free (history_value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (strlen (history_value) > linelength)
|
||||||
|
{
|
||||||
|
linelength = strlen (history_value) + 1;
|
||||||
|
linebuffer = (char *) xrealloc (linebuffer, linelength);
|
||||||
|
}
|
||||||
|
strcpy (linebuffer, history_value);
|
||||||
|
p = linebuffer + strlen (linebuffer);
|
||||||
|
free (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 && *p != '\\')
|
||||||
|
{
|
||||||
|
command_handler (line);
|
||||||
|
display_gdb_prompt (0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (p1 = linebuffer; *p1 == ' ' || *p1 == '\t'; p1++);
|
||||||
|
if (repeat && !*p1)
|
||||||
|
{
|
||||||
|
command_handler (line);
|
||||||
|
display_gdb_prompt (0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
*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);
|
||||||
|
if (!more_to_come)
|
||||||
|
{
|
||||||
|
command_handler (line);
|
||||||
|
display_gdb_prompt (0);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
command_handler (linebuffer);
|
||||||
|
display_gdb_prompt (0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Does reading of input from terminal w/o the editing features
|
||||||
|
provided by the readline library. */
|
||||||
|
|
||||||
|
/* NOTE: 4/30/99 Asynchronous version of gdb_readline. gdb_readline
|
||||||
|
will become obsolete when the event loop is made the default
|
||||||
|
execution for gdb. */
|
||||||
|
static void
|
||||||
|
gdb_readline2 ()
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
char *result;
|
||||||
|
int input_index = 0;
|
||||||
|
int result_size = 80;
|
||||||
|
|
||||||
|
result = (char *) xmalloc (result_size);
|
||||||
|
|
||||||
|
/* We still need the while loop here, even though it would seem
|
||||||
|
obvious to invoke gdb_readline2 at every character entered. If
|
||||||
|
not using the readline library, the terminal is in cooked mode,
|
||||||
|
which sends the characters all at once. Poll will notice that the
|
||||||
|
input fd has changed state only after enter is pressed. At this
|
||||||
|
point we still need to fetch all the chars entered. */
|
||||||
|
|
||||||
|
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;
|
||||||
|
free (result);
|
||||||
|
command_line_handler (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == '\n')
|
||||||
|
#ifndef CRLF_SOURCE_FILES
|
||||||
|
break;
|
||||||
|
#else
|
||||||
|
{
|
||||||
|
if (input_index > 0 && result[input_index - 1] == '\r')
|
||||||
|
input_index--;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
result[input_index++] = c;
|
||||||
|
while (input_index >= result_size)
|
||||||
|
{
|
||||||
|
result_size *= 2;
|
||||||
|
result = (char *) xrealloc (result, result_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result[input_index++] = '\0';
|
||||||
|
command_line_handler (result);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Initialization of signal handlers and tokens. There is a function
|
||||||
|
handle_sig* for each of the signals GDB cares about. Specifically:
|
||||||
|
SIGINT, SIGFPE, SIGQUIT, SIGTSTP, SIGHUP, SIGWINCH. These
|
||||||
|
functions are the actual signal handlers associated to the signals
|
||||||
|
via calls to signal(). The only job for these functions is to
|
||||||
|
enqueue the appropriate event/procedure with the event loop. Such
|
||||||
|
procedures are the old signal handlers. The event loop will take
|
||||||
|
care of invoking the queued procedures to perform the usual tasks
|
||||||
|
associated with the reception of the signal. */
|
||||||
|
/* NOTE: 4/30/99 This is the asynchronous version of init_signals.
|
||||||
|
init_signals will become obsolete as we move to have to event loop
|
||||||
|
as the default for gdb. */
|
||||||
|
void
|
||||||
|
async_init_signals ()
|
||||||
|
{
|
||||||
|
signal (SIGINT, handle_sigint);
|
||||||
|
sigint_token =
|
||||||
|
create_async_signal_handler ((async_handler_func *) async_request_quit, NULL);
|
||||||
|
|
||||||
|
/* If SIGTRAP was set to SIG_IGN, then the SIG_IGN will get passed
|
||||||
|
to the inferior and breakpoints will be ignored. */
|
||||||
|
#ifdef SIGTRAP
|
||||||
|
signal (SIGTRAP, SIG_DFL);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* If we initialize SIGQUIT to SIG_IGN, then the SIG_IGN will get
|
||||||
|
passed to the inferior, which we don't want. It would be
|
||||||
|
possible to do a "signal (SIGQUIT, SIG_DFL)" after we fork, but
|
||||||
|
on BSD4.3 systems using vfork, that can affect the
|
||||||
|
GDB process as well as the inferior (the signal handling tables
|
||||||
|
might be in memory, shared between the two). Since we establish
|
||||||
|
a handler for SIGQUIT, when we call exec it will set the signal
|
||||||
|
to SIG_DFL for us. */
|
||||||
|
signal (SIGQUIT, handle_sigquit);
|
||||||
|
sigquit_token =
|
||||||
|
create_async_signal_handler ((async_handler_func *) async_do_nothing, NULL);
|
||||||
|
#ifdef SIGHUP
|
||||||
|
if (signal (SIGHUP, handle_sighup) != SIG_IGN)
|
||||||
|
sighup_token =
|
||||||
|
create_async_signal_handler ((async_handler_func *) async_disconnect, NULL);
|
||||||
|
else
|
||||||
|
sighup_token =
|
||||||
|
create_async_signal_handler ((async_handler_func *) async_do_nothing, NULL);
|
||||||
|
#endif
|
||||||
|
signal (SIGFPE, handle_sigfpe);
|
||||||
|
sigfpe_token =
|
||||||
|
create_async_signal_handler ((async_handler_func *) async_float_handler, NULL);
|
||||||
|
|
||||||
|
#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER)
|
||||||
|
signal (SIGWINCH, handle_sigwinch);
|
||||||
|
sigwinch_token =
|
||||||
|
create_async_signal_handler ((async_handler_func *) SIGWINCH_HANDLER, NULL);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tell the event loop what to do if SIGINT is received.
|
||||||
|
See event-signal.c. */
|
||||||
|
void
|
||||||
|
handle_sigint (sig)
|
||||||
|
int sig;
|
||||||
|
{
|
||||||
|
signal (sig, handle_sigint);
|
||||||
|
|
||||||
|
/* If immediate_quit is set, we go ahead and process the SIGINT right
|
||||||
|
away, even if we usually would defer this to the event loop. The
|
||||||
|
assumption here is that it is safe to process ^C immediately if
|
||||||
|
immediate_quit is set. If we didn't, SIGINT would be really
|
||||||
|
processed only the next time through the event loop. To get to
|
||||||
|
that point, though, the command that we want to interrupt needs to
|
||||||
|
finish first, which is unacceptable. */
|
||||||
|
if (immediate_quit)
|
||||||
|
async_request_quit ();
|
||||||
|
else
|
||||||
|
/* If immediate quit is not set, we process SIGINT the next time
|
||||||
|
through the loop, which is fine. */
|
||||||
|
mark_async_signal_handler (sigint_token);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do the quit. All the checks have been done by the caller. */
|
||||||
|
void
|
||||||
|
async_request_quit ()
|
||||||
|
{
|
||||||
|
quit_flag = 1;
|
||||||
|
#ifdef REQUEST_QUIT
|
||||||
|
REQUEST_QUIT;
|
||||||
|
#else
|
||||||
|
quit ();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tell the event loop what to do if SIGQUIT is received.
|
||||||
|
See event-signal.c. */
|
||||||
|
void
|
||||||
|
handle_sigquit (sig)
|
||||||
|
int sig;
|
||||||
|
{
|
||||||
|
mark_async_signal_handler (sigquit_token);
|
||||||
|
signal (sig, handle_sigquit);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called by the event loop in response to a SIGQUIT. */
|
||||||
|
void
|
||||||
|
async_do_nothing ()
|
||||||
|
{
|
||||||
|
/* Empty function body. */
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef SIGHUP
|
||||||
|
/* Tell the event loop what to do if SIGHUP is received.
|
||||||
|
See event-signal.c. */
|
||||||
|
void
|
||||||
|
handle_sighup (sig)
|
||||||
|
int sig;
|
||||||
|
{
|
||||||
|
mark_async_signal_handler (sighup_token);
|
||||||
|
signal (sig, handle_sighup);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called by the event loop to process a SIGHUP. */
|
||||||
|
void
|
||||||
|
async_disconnect ()
|
||||||
|
{
|
||||||
|
catch_errors (quit_cover, NULL,
|
||||||
|
"Could not kill the program being debugged",
|
||||||
|
RETURN_MASK_ALL);
|
||||||
|
signal (SIGHUP, SIG_DFL); /*FIXME: ??????????? */
|
||||||
|
kill (getpid (), SIGHUP);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Tell the event loop what to do if SIGFPE is received.
|
||||||
|
See event-signal.c. */
|
||||||
|
void
|
||||||
|
handle_sigfpe (sig)
|
||||||
|
int sig;
|
||||||
|
{
|
||||||
|
mark_async_signal_handler (sigfpe_token);
|
||||||
|
signal (sig, handle_sigfpe);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Event loop will call this functin to process a SIGFPE. */
|
||||||
|
void
|
||||||
|
async_float_handler ()
|
||||||
|
{
|
||||||
|
/* This message is based on ANSI C, section 4.7. Note that integer
|
||||||
|
divide by zero causes this, so "float" is a misnomer. */
|
||||||
|
error ("Erroneous arithmetic operation.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tell the event loop what to do if SIGWINCH is received.
|
||||||
|
See event-signal.c. */
|
||||||
|
#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER)
|
||||||
|
void
|
||||||
|
handle_sigwinch (sig)
|
||||||
|
int sig;
|
||||||
|
{
|
||||||
|
mark_async_signal_handler (sigwinch_token);
|
||||||
|
signal (sig, handle_sigwinch);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Called by do_setshow_command. */
|
||||||
|
/* ARGSUSED */
|
||||||
|
void
|
||||||
|
set_async_editing_command (args, from_tty, c)
|
||||||
|
char *args;
|
||||||
|
int from_tty;
|
||||||
|
struct cmd_list_element *c;
|
||||||
|
{
|
||||||
|
change_line_handler ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called by do_setshow_command. */
|
||||||
|
/* ARGSUSED */
|
||||||
|
void
|
||||||
|
set_async_annotation_level (args, from_tty, c)
|
||||||
|
char *args;
|
||||||
|
int from_tty;
|
||||||
|
struct cmd_list_element *c;
|
||||||
|
{
|
||||||
|
change_annotation_level ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called by do_setshow_command. */
|
||||||
|
/* ARGSUSED */
|
||||||
|
void
|
||||||
|
set_async_prompt (args, from_tty, c)
|
||||||
|
char *args;
|
||||||
|
int from_tty;
|
||||||
|
struct cmd_list_element *c;
|
||||||
|
{
|
||||||
|
PROMPT (0) = savestring (new_async_prompt, strlen (new_async_prompt));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Reference in New Issue
Block a user