/* Internal header for GDB/Scheme code.
- Copyright (C) 2014-2018 Free Software Foundation, Inc.
+ Copyright (C) 2014-2019 Free Software Foundation, Inc.
This file is part of GDB.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
+#ifndef GUILE_GUILE_INTERNAL_H
+#define GUILE_GUILE_INTERNAL_H
+
/* See README file in this directory for implementation notes, coding
conventions, et.al. */
-#ifndef GDB_GUILE_INTERNAL_H
-#define GDB_GUILE_INTERNAL_H
#include "hashtab.h"
#include "extension-priv.h"
extern void gdbscm_throw (SCM exception) ATTRIBUTE_NORETURN;
-extern SCM gdbscm_scm_from_gdb_exception (struct gdb_exception exception);
+struct gdbscm_gdb_exception;
+extern SCM gdbscm_scm_from_gdb_exception
+ (const gdbscm_gdb_exception &exception);
-extern void gdbscm_throw_gdb_exception (struct gdb_exception exception)
+extern void gdbscm_throw_gdb_exception (gdbscm_gdb_exception exception)
ATTRIBUTE_NORETURN;
extern void gdbscm_print_exception_with_stack (SCM port, SCM stack,
extern int gdbscm_scm_string_to_int (SCM string);
-extern char *gdbscm_scm_to_c_string (SCM string);
+extern gdb::unique_xmalloc_ptr<char> gdbscm_scm_to_c_string (SCM string);
extern SCM gdbscm_scm_from_c_string (const char *string);
extern SCM gdbscm_scm_from_printf (const char *format, ...)
ATTRIBUTE_PRINTF (1, 2);
-extern char *gdbscm_scm_to_string (SCM string, size_t *lenp,
- const char *charset,
- int strict, SCM *except_scmp);
+extern gdb::unique_xmalloc_ptr<char> gdbscm_scm_to_string
+ (SCM string, size_t *lenp, const char *charset, int strict, SCM *except_scmp);
extern SCM gdbscm_scm_from_string (const char *string, size_t len,
const char *charset, int strict);
-extern char *gdbscm_scm_to_host_string (SCM string, size_t *lenp, SCM *except);
+extern gdb::unique_xmalloc_ptr<char> gdbscm_scm_to_host_string
+ (SCM string, size_t *lenp, SCM *except);
extern SCM gdbscm_scm_from_host_string (const char *string, size_t len);
extern SCM vlscm_scm_from_value (struct value *value);
-extern SCM vlscm_scm_from_value_unsafe (struct value *value);
-
extern struct value *vlscm_convert_typed_value_from_scheme
(const char *func_name, int obj_arg_pos, SCM obj,
int type_arg_pos, SCM type_scm, struct type *type, SCM *except_scmp,
extern void gdbscm_initialize_types (void);
extern void gdbscm_initialize_values (void);
\f
-/* Use these after a TRY_CATCH to throw the appropriate Scheme exception
- if a GDB error occurred. */
+
+/* A complication with the Guile code is that we have two types of
+ exceptions to consider. GDB/C++ exceptions, and Guile/SJLJ
+ exceptions. Code that is facing the Guile interpreter must not
+ throw GDB exceptions, instead Scheme exceptions must be thrown.
+ Also, because Guile exceptions are SJLJ based, Guile-facing code
+ must not use local objects with dtors, unless wrapped in a scope
+ with a TRY/CATCH, because the dtors won't otherwise be run when a
+ Guile exceptions is thrown. */
+
+/* This is a destructor-less clone of gdb_exception. */
+
+struct gdbscm_gdb_exception
+{
+ enum return_reason reason;
+ enum errors error;
+ /* The message is xmalloc'd. */
+ char *message;
+};
+
+/* Return a gdbscm_gdb_exception representing EXC. */
+
+inline gdbscm_gdb_exception
+unpack (const gdb_exception &exc)
+{
+ gdbscm_gdb_exception result;
+ result.reason = exc.reason;
+ result.error = exc.error;
+ if (exc.message == nullptr)
+ result.message = nullptr;
+ else
+ result.message = xstrdup (exc.message->c_str ());
+ /* The message should be NULL iff the reason is zero. */
+ gdb_assert ((result.reason == 0) == (result.message == nullptr));
+ return result;
+}
+
+/* Use this after a TRY/CATCH to throw the appropriate Scheme
+ exception if a GDB error occurred. */
#define GDBSCM_HANDLE_GDB_EXCEPTION(exception) \
do { \
} \
} while (0)
-/* If cleanups are establish outside the TRY_CATCH block, use this version. */
+/* Use this to wrap a callable to throw the appropriate Scheme
+ exception if the callable throws a GDB error. ARGS are forwarded
+ to FUNC. Returns the result of FUNC, unless FUNC returns a Scheme
+ exception, in which case that exception is thrown. Note that while
+ the callable is free to use objects of types with destructors,
+ because GDB errors are C++ exceptions, the caller of gdbscm_wrap
+ must not use such objects, because their destructors would not be
+ called when a Scheme exception is thrown. */
+
+template<typename Function, typename... Args>
+SCM
+gdbscm_wrap (Function &&func, Args &&... args)
+{
+ SCM result = SCM_BOOL_F;
+ gdbscm_gdb_exception exc {};
-#define GDBSCM_HANDLE_GDB_EXCEPTION_WITH_CLEANUPS(exception, cleanups) \
- do { \
- if (exception.reason < 0) \
- { \
- do_cleanups (cleanups); \
- gdbscm_throw_gdb_exception (exception); \
- /*NOTREACHED */ \
- } \
- } while (0)
+ try
+ {
+ result = func (std::forward<Args> (args)...);
+ }
+ catch (const gdb_exception &except)
+ {
+ exc = unpack (except);
+ }
+
+ GDBSCM_HANDLE_GDB_EXCEPTION (exc);
+
+ if (gdbscm_is_exception (result))
+ gdbscm_throw (result);
+
+ return result;
+}
-#endif /* GDB_GUILE_INTERNAL_H */
+#endif /* GUILE_GUILE_INTERNAL_H */