aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGary Benson <gbenson@redhat.com>2014-08-08 15:37:41 +0100
committerGary Benson <gbenson@redhat.com>2014-08-29 10:53:56 +0100
commit860789c7d5d6ef2f60e757feb21845bb230582a8 (patch)
tree88d7addfc8242d4c8377d4afcefec92ee71ce34c
parentff55e1b54898ca4e2a90c005749505e33e32215c (diff)
downloadgdb-860789c7d5d6ef2f60e757feb21845bb230582a8.zip
gdb-860789c7d5d6ef2f60e757feb21845bb230582a8.tar.gz
gdb-860789c7d5d6ef2f60e757feb21845bb230582a8.tar.bz2
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.
-rw-r--r--gdb/gdbserver/ChangeLog13
-rw-r--r--gdb/gdbserver/server.c192
-rw-r--r--gdb/gdbserver/server.h7
-rw-r--r--gdb/gdbserver/utils.c10
4 files changed, 125 insertions, 97 deletions
diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index 89cafa6..caa243d 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -1,5 +1,18 @@
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.
(OBS): Add common-exceptions.o.
(common-exceptions.o): New rule.
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index cf1dffe..81cb2e1 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -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)
{
- /* 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 ();
+ /* 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 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);
- }
- }
+ if (exit_requested || run_once)
+ throw_quit ("Quit");
- fprintf (stderr,
- "Remote side has terminated connection. "
- "GDBserver will reopen the connection.\n");
+ 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);
+ /* 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)
+ if (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 (disconnected_tracing)
{
- if (start_non_stop (1))
- non_stop = 1;
+ /* 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. */
+ /* Detaching implicitly resumes all threads;
+ simply disconnecting does not. */
+ }
+ }
+ else
+ {
+ fprintf (stderr,
+ "Disconnected tracing disabled; "
+ "stopping trace run.\n");
+ stop_tracing ();
}
}
- else
+ }
+
+ if (exception.reason == RETURN_ERROR)
+ {
+ if (response_needed)
{
- fprintf (stderr,
- "Disconnected tracing disabled; stopping trace run.\n");
- stop_tracing ();
+ write_enn (own_buf);
+ putpkt (own_buf);
}
}
}
}
+/* 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
diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
index e6b2277..812f533 100644
--- a/gdb/gdbserver/server.h
+++ b/gdb/gdbserver/server.h
@@ -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 */
diff --git a/gdb/gdbserver/utils.c b/gdb/gdbserver/utils.c
index e310b9e..2351a46 100644
--- a/gdb/gdbserver/utils.c
+++ b/gdb/gdbserver/utils.c
@@ -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
}