123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321 |
- /* Exception (throw catch) mechanism, for GDB, the GNU debugger.
- Copyright (C) 1986-2022 Free Software Foundation, Inc.
- This file is part of GDB.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
- #ifndef COMMON_COMMON_EXCEPTIONS_H
- #define COMMON_COMMON_EXCEPTIONS_H
- #include <setjmp.h>
- #include <new>
- #include <memory>
- #include <string>
- /* Reasons for calling throw_exceptions(). NOTE: all reason values
- must be different from zero. enum value 0 is reserved for internal
- use as the return value from an initial setjmp(). */
- enum return_reason
- {
- /* User interrupt. */
- RETURN_QUIT = -2,
- /* Any other error. */
- RETURN_ERROR
- };
- #define RETURN_MASK(reason) (1 << (int)(-reason))
- typedef enum
- {
- RETURN_MASK_QUIT = RETURN_MASK (RETURN_QUIT),
- RETURN_MASK_ERROR = RETURN_MASK (RETURN_ERROR),
- RETURN_MASK_ALL = (RETURN_MASK_QUIT | RETURN_MASK_ERROR)
- } return_mask;
- /* Describe all exceptions. */
- enum errors {
- GDB_NO_ERROR,
- /* Any generic error, the corresponding text is in
- exception.message. */
- GENERIC_ERROR,
- /* Something requested was not found. */
- NOT_FOUND_ERROR,
- /* Thread library lacks support necessary for finding thread local
- storage. */
- TLS_NO_LIBRARY_SUPPORT_ERROR,
- /* Load module not found while attempting to find thread local storage. */
- TLS_LOAD_MODULE_NOT_FOUND_ERROR,
- /* Thread local storage has not been allocated yet. */
- TLS_NOT_ALLOCATED_YET_ERROR,
- /* Something else went wrong while attempting to find thread local
- storage. The ``struct gdb_exception'' message field provides
- more detail. */
- TLS_GENERIC_ERROR,
- /* Problem parsing an XML document. */
- XML_PARSE_ERROR,
- /* Error accessing memory. */
- MEMORY_ERROR,
- /* Value not available. E.g., a register was not collected in a
- traceframe. */
- NOT_AVAILABLE_ERROR,
- /* Value was optimized out. Note: if the value was a register, this
- means the register was not saved in the frame. */
- OPTIMIZED_OUT_ERROR,
- /* DW_OP_entry_value resolving failed. */
- NO_ENTRY_VALUE_ERROR,
- /* Target throwing an error has been closed. Current command should be
- aborted as the inferior state is no longer valid. */
- TARGET_CLOSE_ERROR,
- /* An undefined command was executed. */
- UNDEFINED_COMMAND_ERROR,
- /* Requested feature, method, mechanism, etc. is not supported. */
- NOT_SUPPORTED_ERROR,
- /* The number of candidates generated during line completion has
- reached the user's specified limit. This isn't an error, this exception
- is used to halt searching for more completions, but for consistency
- "_ERROR" is appended to the name. */
- MAX_COMPLETIONS_REACHED_ERROR,
- /* Add more errors here. */
- NR_ERRORS
- };
- struct gdb_exception
- {
- gdb_exception ()
- : reason ((enum return_reason) 0),
- error (GDB_NO_ERROR)
- {
- }
- gdb_exception (enum return_reason r, enum errors e)
- : reason (r),
- error (e)
- {
- }
- gdb_exception (enum return_reason r, enum errors e,
- const char *fmt, va_list ap)
- ATTRIBUTE_PRINTF (4, 0)
- : reason (r),
- error (e),
- message (std::make_shared<std::string> (string_vprintf (fmt, ap)))
- {
- }
- /* The move constructor exists so that we can mark it "noexcept",
- which is a good practice for any sort of exception object. */
- explicit gdb_exception (gdb_exception &&other) noexcept = default;
- /* The copy constructor exists so that we can mark it "noexcept",
- which is a good practice for any sort of exception object. */
- gdb_exception (const gdb_exception &other) noexcept
- : reason (other.reason),
- error (other.error),
- message (other.message)
- {
- }
- /* The assignment operator exists so that we can mark it "noexcept",
- which is a good practice for any sort of exception object. */
- gdb_exception &operator= (const gdb_exception &other) noexcept
- {
- reason = other.reason;
- error = other.error;
- message = other.message;
- return *this;
- }
- gdb_exception &operator= (gdb_exception &&other) noexcept = default;
- /* Return the contents of the exception message, as a C string. The
- string remains owned by the exception object. */
- const char *what () const noexcept
- {
- return message->c_str ();
- }
- /* Compare two exceptions. */
- bool operator== (const gdb_exception &other) const
- {
- const char *msg1 = message == nullptr ? "" : what ();
- const char *msg2 = other.message == nullptr ? "" : other.what ();
- return (reason == other.reason
- && error == other.error
- && strcmp (msg1, msg2) == 0);
- }
- /* Compare two exceptions. */
- bool operator!= (const gdb_exception &other) const
- {
- return !(*this == other);
- }
- enum return_reason reason;
- enum errors error;
- std::shared_ptr<std::string> message;
- };
- /* Functions to drive the sjlj-based exceptions state machine. Though
- declared here by necessity, these functions should be considered
- internal to the exceptions subsystem and not used other than via
- the TRY/CATCH (or TRY_SJLJ/CATCH_SJLJ) macros defined below. */
- extern jmp_buf *exceptions_state_mc_init (void);
- extern int exceptions_state_mc_action_iter (void);
- extern int exceptions_state_mc_action_iter_1 (void);
- extern int exceptions_state_mc_catch (struct gdb_exception *, int);
- /* Macro to wrap up standard try/catch behavior.
- The double loop lets us correctly handle code "break"ing out of the
- try catch block. (It works as the "break" only exits the inner
- "while" loop, the outer for loop detects this handling it
- correctly.) Of course "return" and "goto" are not so lucky.
- For instance:
- *INDENT-OFF*
- TRY_SJLJ
- {
- }
- CATCH_SJLJ (e, RETURN_MASK_ERROR)
- {
- switch (e.reason)
- {
- case RETURN_ERROR: ...
- }
- }
- END_CATCH_SJLJ
- The SJLJ variants are needed in some cases where gdb exceptions
- need to cross third-party library code compiled without exceptions
- support (e.g., readline). */
- #define TRY_SJLJ \
- { \
- jmp_buf *buf = \
- exceptions_state_mc_init (); \
- setjmp (*buf); \
- } \
- while (exceptions_state_mc_action_iter ()) \
- while (exceptions_state_mc_action_iter_1 ())
- #define CATCH_SJLJ(EXCEPTION, MASK) \
- { \
- struct gdb_exception EXCEPTION; \
- if (exceptions_state_mc_catch (&(EXCEPTION), MASK))
- #define END_CATCH_SJLJ \
- }
- /* The exception types client code may catch. They're just shims
- around gdb_exception that add nothing but type info. Which is used
- is selected depending on the MASK argument passed to CATCH. */
- struct gdb_exception_error : public gdb_exception
- {
- gdb_exception_error (enum errors e, const char *fmt, va_list ap)
- ATTRIBUTE_PRINTF (3, 0)
- : gdb_exception (RETURN_ERROR, e, fmt, ap)
- {
- }
- explicit gdb_exception_error (gdb_exception &&ex) noexcept
- : gdb_exception (std::move (ex))
- {
- gdb_assert (ex.reason == RETURN_ERROR);
- }
- };
- struct gdb_exception_quit : public gdb_exception
- {
- gdb_exception_quit (const char *fmt, va_list ap)
- ATTRIBUTE_PRINTF (2, 0)
- : gdb_exception (RETURN_QUIT, GDB_NO_ERROR, fmt, ap)
- {
- }
- explicit gdb_exception_quit (gdb_exception &&ex) noexcept
- : gdb_exception (std::move (ex))
- {
- gdb_assert (ex.reason == RETURN_QUIT);
- }
- };
- /* An exception type that inherits from both std::bad_alloc and a gdb
- exception. This is necessary because operator new can only throw
- std::bad_alloc, and OTOH, we want exceptions thrown due to memory
- allocation error to be caught by all the CATCH/RETURN_MASK_ALL
- spread around the codebase. */
- struct gdb_quit_bad_alloc
- : public gdb_exception_quit,
- public std::bad_alloc
- {
- explicit gdb_quit_bad_alloc (gdb_exception &&ex) noexcept
- : gdb_exception_quit (std::move (ex)),
- std::bad_alloc ()
- {
- }
- };
- /* *INDENT-ON* */
- /* Throw an exception (as described by "struct gdb_exception"),
- landing in the inner most containing exception handler established
- using TRY/CATCH. */
- extern void throw_exception (gdb_exception &&exception)
- ATTRIBUTE_NORETURN;
- /* Throw an exception by executing a LONG JUMP to the inner most
- containing exception handler established using TRY_SJLJ. Necessary
- in some cases where we need to throw GDB exceptions across
- third-party library code (e.g., readline). */
- extern void throw_exception_sjlj (const struct gdb_exception &exception)
- ATTRIBUTE_NORETURN;
- /* Convenience wrappers around throw_exception that throw GDB
- errors. */
- extern void throw_verror (enum errors, const char *fmt, va_list ap)
- ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (2, 0);
- extern void throw_vquit (const char *fmt, va_list ap)
- ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (1, 0);
- extern void throw_error (enum errors error, const char *fmt, ...)
- ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (2, 3);
- extern void throw_quit (const char *fmt, ...)
- ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (1, 2);
- #endif /* COMMON_COMMON_EXCEPTIONS_H */
|