Use exceptions and cleanups in gdbserver

This commit replaces the hacky "exception" system in gdbserver with
the exceptions and cleanups subsystem from GDB.

Only the catch/cleanup code in what was "main" has been updated to
use the new system.  Other parts of gdbserver can now be converted
to use TRY_CATCH and cleanups on an as-needed basis.

A side-effect of this commit is that some error messages will change
slightly, and in cases with multiple errors the error messages will
be printed in a different order.

gdb/gdbserver/ChangeLog:

	* server.h (setjmp.h): Do not include.
	(toplevel): Do not declare.
	(common-exceptions.h): Include.
	(cleanups.h): Likewise.
	* server.c (toplevel): Do not define.
	(exit_code): New static global.
	(detach_or_kill_for_exit_cleanup): New function.
	(main): New function.  Original main renamed to...
	(captured_main): New function.
	* utils.c (verror) [!IN_PROCESS_AGENT]: Use throw_verror.
This commit is contained in:
Gary Benson 2014-08-08 15:37:41 +01:00
parent ff55e1b548
commit 860789c7d5
4 changed files with 132 additions and 104 deletions

View File

@ -1,3 +1,16 @@
2014-08-29 Gary Benson <gbenson@redhat.com>
* server.h (setjmp.h): Do not include.
(toplevel): Do not declare.
(common-exceptions.h): Include.
(cleanups.h): Likewise.
* server.c (toplevel): Do not define.
(exit_code): New static global.
(detach_or_kill_for_exit_cleanup): New function.
(main): New function. Original main renamed to...
(captured_main): New function.
* utils.c (verror) [!IN_PROCESS_AGENT]: Use throw_verror.
2014-08-29 Gary Benson <gbenson@redhat.com>
* Makefile.in (SFILES): Add common/common-exceptions.c.

View File

@ -76,8 +76,6 @@ int pass_signals[GDB_SIGNAL_LAST];
int program_signals[GDB_SIGNAL_LAST];
int program_signals_p;
jmp_buf toplevel;
/* The PID of the originally created or attached inferior. Used to
send signals to the process when GDB sends us an asynchronous interrupt
(user hitting Control-C in the client), and to wait for the child to exit
@ -3013,8 +3011,34 @@ detach_or_kill_for_exit (void)
for_each_inferior (&all_processes, detach_or_kill_inferior_callback);
}
int
main (int argc, char *argv[])
/* Value that will be passed to exit(3) when gdbserver exits. */
static int exit_code;
/* Cleanup version of detach_or_kill_for_exit. */
static void
detach_or_kill_for_exit_cleanup (void *ignore)
{
volatile struct gdb_exception exception;
TRY_CATCH (exception, RETURN_MASK_ALL)
{
detach_or_kill_for_exit ();
}
if (exception.reason < 0)
{
fflush (stdout);
fprintf (stderr, "Detach or kill failed: %s\n", exception.message);
exit_code = 1;
}
}
/* Main function. This is called by the real "main" function,
wrapped in a TRY_CATCH that handles any uncaught exceptions. */
static void ATTRIBUTE_NORETURN
captured_main (int argc, char *argv[])
{
int bad_attach;
int pid;
@ -3138,12 +3162,6 @@ main (int argc, char *argv[])
continue;
}
if (setjmp (toplevel))
{
fprintf (stderr, "Exiting\n");
exit (1);
}
port = *next_arg;
next_arg++;
if (port == NULL || (!attach && !multi_mode && *next_arg == NULL))
@ -3226,6 +3244,7 @@ main (int argc, char *argv[])
last_status.value.integer = 0;
last_ptid = minus_one_ptid;
}
make_cleanup (detach_or_kill_for_exit_cleanup, NULL);
initialize_notif ();
@ -3234,19 +3253,6 @@ main (int argc, char *argv[])
shared library event" notice on gdb side. */
dlls_changed = 0;
if (setjmp (toplevel))
{
/* If something fails and longjmps while detaching or killing
inferiors, we'd end up here again, stuck in an infinite loop
trap. Be sure that if that happens, we exit immediately
instead. */
if (setjmp (toplevel) == 0)
detach_or_kill_for_exit ();
else
fprintf (stderr, "Detach or kill failed. Exiting\n");
exit (1);
}
if (last_status.kind == TARGET_WAITKIND_EXITED
|| last_status.kind == TARGET_WAITKIND_SIGNALLED)
was_running = 0;
@ -3254,13 +3260,12 @@ main (int argc, char *argv[])
was_running = 1;
if (!was_running && !multi_mode)
{
fprintf (stderr, "No program to debug. GDBserver exiting.\n");
exit (1);
}
error ("No program to debug");
while (1)
{
volatile struct gdb_exception exception;
noack_mode = 0;
multi_process = 0;
/* Be sure we're out of tfind mode. */
@ -3268,82 +3273,97 @@ main (int argc, char *argv[])
remote_open (port);
if (setjmp (toplevel) != 0)
TRY_CATCH (exception, RETURN_MASK_ERROR)
{
/* Wait for events. This will return when all event sources
are removed from the event loop. */
start_event_loop ();
/* If an exit was requested (using the "monitor exit"
command), terminate now. The only other way to get
here is for getpkt to fail; close the connection
and reopen it at the top of the loop. */
if (exit_requested || run_once)
throw_quit ("Quit");
fprintf (stderr,
"Remote side has terminated connection. "
"GDBserver will reopen the connection.\n");
/* Get rid of any pending statuses. An eventual reconnection
(by the same GDB instance or another) will refresh all its
state from scratch. */
discard_queued_stop_replies (-1);
for_each_inferior (&all_threads,
clear_pending_status_callback);
if (tracing)
{
if (disconnected_tracing)
{
/* Try to enable non-stop/async mode, so we we can
both wait for an async socket accept, and handle
async target events simultaneously. There's also
no point either in having the target always stop
all threads, when we're going to pass signals
down without informing GDB. */
if (!non_stop)
{
if (start_non_stop (1))
non_stop = 1;
/* Detaching implicitly resumes all threads;
simply disconnecting does not. */
}
}
else
{
fprintf (stderr,
"Disconnected tracing disabled; "
"stopping trace run.\n");
stop_tracing ();
}
}
}
if (exception.reason == RETURN_ERROR)
{
/* An error occurred. */
if (response_needed)
{
write_enn (own_buf);
putpkt (own_buf);
}
}
/* Wait for events. This will return when all event sources are
removed from the event loop. */
start_event_loop ();
/* If an exit was requested (using the "monitor exit" command),
terminate now. The only other way to get here is for
getpkt to fail; close the connection and reopen it at the
top of the loop. */
if (exit_requested || run_once)
{
/* If something fails and longjmps while detaching or
killing inferiors, we'd end up here again, stuck in an
infinite loop trap. Be sure that if that happens, we
exit immediately instead. */
if (setjmp (toplevel) == 0)
{
detach_or_kill_for_exit ();
exit (0);
}
else
{
fprintf (stderr, "Detach or kill failed. Exiting\n");
exit (1);
}
}
fprintf (stderr,
"Remote side has terminated connection. "
"GDBserver will reopen the connection.\n");
/* Get rid of any pending statuses. An eventual reconnection
(by the same GDB instance or another) will refresh all its
state from scratch. */
discard_queued_stop_replies (-1);
for_each_inferior (&all_threads, clear_pending_status_callback);
if (tracing)
{
if (disconnected_tracing)
{
/* Try to enable non-stop/async mode, so we we can both
wait for an async socket accept, and handle async
target events simultaneously. There's also no point
either in having the target always stop all threads,
when we're going to pass signals down without
informing GDB. */
if (!non_stop)
{
if (start_non_stop (1))
non_stop = 1;
/* Detaching implicitly resumes all threads; simply
disconnecting does not. */
}
}
else
{
fprintf (stderr,
"Disconnected tracing disabled; stopping trace run.\n");
stop_tracing ();
}
}
}
}
/* Main function. */
int
main (int argc, char *argv[])
{
volatile struct gdb_exception exception;
TRY_CATCH (exception, RETURN_MASK_ALL)
{
captured_main (argc, argv);
}
/* captured_main should never return. */
gdb_assert (exception.reason < 0);
if (exception.reason == RETURN_ERROR)
{
fflush (stdout);
fprintf (stderr, "%s\n", exception.message);
fprintf (stderr, "Exiting\n");
exit_code = 1;
}
exit (exit_code);
}
/* Skip PACKET until the next semi-colon (or end of string). */
static void

View File

@ -29,8 +29,6 @@ gdb_static_assert (sizeof (CORE_ADDR) >= sizeof (void *));
#include "version.h"
#include <setjmp.h>
#ifdef HAVE_ALLOCA_H
#include <alloca.h>
#endif
@ -89,8 +87,6 @@ extern int pass_signals[];
extern int program_signals[];
extern int program_signals_p;
extern jmp_buf toplevel;
extern int disable_packet_vCont;
extern int disable_packet_Tthread;
extern int disable_packet_qC;
@ -129,4 +125,7 @@ extern int handle_target_event (int err, gdb_client_data client_data);
as large as the largest register set supported by gdbserver. */
#define PBUFSIZ 16384
#include "common-exceptions.h"
#include "cleanups.h"
#endif /* SERVER_H */

View File

@ -76,17 +76,13 @@ perror_with_name (const char *string)
void
verror (const char *string, va_list args)
{
#ifndef IN_PROCESS_AGENT
extern jmp_buf toplevel;
#endif
#ifdef IN_PROCESS_AGENT
fflush (stdout);
vfprintf (stderr, string, args);
fprintf (stderr, "\n");
#ifndef IN_PROCESS_AGENT
longjmp (toplevel, 1);
#else
exit (1);
#else
throw_verror (GENERIC_ERROR, string, args);
#endif
}