xref: /netbsd-src/external/gpl3/gdb/dist/gdbsupport/common-exceptions.h (revision 5ba1f45f2a09259cc846f20c7c5501604d633c90)
18dffb485Schristos /* Exception (throw catch) mechanism, for GDB, the GNU debugger.
28dffb485Schristos 
3*5ba1f45fSchristos    Copyright (C) 1986-2024 Free Software Foundation, Inc.
48dffb485Schristos 
58dffb485Schristos    This file is part of GDB.
68dffb485Schristos 
78dffb485Schristos    This program is free software; you can redistribute it and/or modify
88dffb485Schristos    it under the terms of the GNU General Public License as published by
98dffb485Schristos    the Free Software Foundation; either version 3 of the License, or
108dffb485Schristos    (at your option) any later version.
118dffb485Schristos 
128dffb485Schristos    This program is distributed in the hope that it will be useful,
138dffb485Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
148dffb485Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
158dffb485Schristos    GNU General Public License for more details.
168dffb485Schristos 
178dffb485Schristos    You should have received a copy of the GNU General Public License
188dffb485Schristos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
198dffb485Schristos 
208dffb485Schristos #ifndef COMMON_COMMON_EXCEPTIONS_H
218dffb485Schristos #define COMMON_COMMON_EXCEPTIONS_H
228dffb485Schristos 
238dffb485Schristos #include <setjmp.h>
248dffb485Schristos #include <new>
258dffb485Schristos #include <memory>
268dffb485Schristos #include <string>
274b169a6bSchristos #include <functional>
288dffb485Schristos 
29*5ba1f45fSchristos #include "gdbsupport/underlying.h"
30*5ba1f45fSchristos 
318dffb485Schristos /* Reasons for calling throw_exceptions().  NOTE: all reason values
328dffb485Schristos    must be different from zero.  enum value 0 is reserved for internal
338dffb485Schristos    use as the return value from an initial setjmp().  */
348dffb485Schristos 
358dffb485Schristos enum return_reason
368dffb485Schristos   {
37*5ba1f45fSchristos     /* SIGTERM sent to GDB.  */
38*5ba1f45fSchristos     RETURN_FORCED_QUIT = -3,
398dffb485Schristos     /* User interrupt.  */
408dffb485Schristos     RETURN_QUIT = -2,
418dffb485Schristos     /* Any other error.  */
428dffb485Schristos     RETURN_ERROR
438dffb485Schristos   };
448dffb485Schristos 
458dffb485Schristos #define RETURN_MASK(reason)	(1 << (int)(-reason))
468dffb485Schristos 
478dffb485Schristos typedef enum
488dffb485Schristos {
49*5ba1f45fSchristos   RETURN_MASK_FORCED_QUIT = RETURN_MASK (RETURN_FORCED_QUIT),
508dffb485Schristos   RETURN_MASK_QUIT = RETURN_MASK (RETURN_QUIT),
518dffb485Schristos   RETURN_MASK_ERROR = RETURN_MASK (RETURN_ERROR),
52*5ba1f45fSchristos   RETURN_MASK_ALL = (RETURN_MASK_FORCED_QUIT | RETURN_MASK_QUIT | RETURN_MASK_ERROR)
538dffb485Schristos } return_mask;
548dffb485Schristos 
558dffb485Schristos /* Describe all exceptions.  */
568dffb485Schristos 
578dffb485Schristos enum errors {
588dffb485Schristos   GDB_NO_ERROR,
598dffb485Schristos 
608dffb485Schristos   /* Any generic error, the corresponding text is in
618dffb485Schristos      exception.message.  */
628dffb485Schristos   GENERIC_ERROR,
638dffb485Schristos 
648dffb485Schristos   /* Something requested was not found.  */
658dffb485Schristos   NOT_FOUND_ERROR,
668dffb485Schristos 
678dffb485Schristos   /* Thread library lacks support necessary for finding thread local
688dffb485Schristos      storage.  */
698dffb485Schristos   TLS_NO_LIBRARY_SUPPORT_ERROR,
708dffb485Schristos 
718dffb485Schristos   /* Load module not found while attempting to find thread local storage.  */
728dffb485Schristos   TLS_LOAD_MODULE_NOT_FOUND_ERROR,
738dffb485Schristos 
748dffb485Schristos   /* Thread local storage has not been allocated yet.  */
758dffb485Schristos   TLS_NOT_ALLOCATED_YET_ERROR,
768dffb485Schristos 
778dffb485Schristos   /* Something else went wrong while attempting to find thread local
788dffb485Schristos      storage.  The ``struct gdb_exception'' message field provides
798dffb485Schristos      more detail.  */
808dffb485Schristos   TLS_GENERIC_ERROR,
818dffb485Schristos 
828dffb485Schristos   /* Problem parsing an XML document.  */
838dffb485Schristos   XML_PARSE_ERROR,
848dffb485Schristos 
858dffb485Schristos   /* Error accessing memory.  */
868dffb485Schristos   MEMORY_ERROR,
878dffb485Schristos 
888dffb485Schristos   /* Value not available.  E.g., a register was not collected in a
898dffb485Schristos      traceframe.  */
908dffb485Schristos   NOT_AVAILABLE_ERROR,
918dffb485Schristos 
928dffb485Schristos   /* Value was optimized out.  Note: if the value was a register, this
938dffb485Schristos      means the register was not saved in the frame.  */
948dffb485Schristos   OPTIMIZED_OUT_ERROR,
958dffb485Schristos 
968dffb485Schristos   /* DW_OP_entry_value resolving failed.  */
978dffb485Schristos   NO_ENTRY_VALUE_ERROR,
988dffb485Schristos 
998dffb485Schristos   /* Target throwing an error has been closed.  Current command should be
1008dffb485Schristos      aborted as the inferior state is no longer valid.  */
1018dffb485Schristos   TARGET_CLOSE_ERROR,
1028dffb485Schristos 
1038dffb485Schristos   /* An undefined command was executed.  */
1048dffb485Schristos   UNDEFINED_COMMAND_ERROR,
1058dffb485Schristos 
1068dffb485Schristos   /* Requested feature, method, mechanism, etc. is not supported.  */
1078dffb485Schristos   NOT_SUPPORTED_ERROR,
1088dffb485Schristos 
1098dffb485Schristos   /* The number of candidates generated during line completion has
1108dffb485Schristos      reached the user's specified limit.  This isn't an error, this exception
1118dffb485Schristos      is used to halt searching for more completions, but for consistency
1128dffb485Schristos      "_ERROR" is appended to the name.  */
1138dffb485Schristos   MAX_COMPLETIONS_REACHED_ERROR,
1148dffb485Schristos 
1158dffb485Schristos   /* Add more errors here.  */
1168dffb485Schristos   NR_ERRORS
1178dffb485Schristos };
1188dffb485Schristos 
1198dffb485Schristos struct gdb_exception
1208dffb485Schristos {
1218dffb485Schristos   gdb_exception ()
1228dffb485Schristos     : reason ((enum return_reason) 0),
1238dffb485Schristos       error (GDB_NO_ERROR)
1248dffb485Schristos   {
1258dffb485Schristos   }
1268dffb485Schristos 
1278dffb485Schristos   gdb_exception (enum return_reason r, enum errors e)
1288dffb485Schristos     : reason (r),
1298dffb485Schristos       error (e)
1308dffb485Schristos   {
1318dffb485Schristos   }
1328dffb485Schristos 
1338dffb485Schristos   gdb_exception (enum return_reason r, enum errors e,
1348dffb485Schristos 		 const char *fmt, va_list ap)
1358dffb485Schristos     ATTRIBUTE_PRINTF (4, 0)
1368dffb485Schristos     : reason (r),
1378dffb485Schristos       error (e),
1388dffb485Schristos       message (std::make_shared<std::string> (string_vprintf (fmt, ap)))
1398dffb485Schristos   {
1408dffb485Schristos   }
1418dffb485Schristos 
1428dffb485Schristos   /* The move constructor exists so that we can mark it "noexcept",
1438dffb485Schristos      which is a good practice for any sort of exception object.  */
1448dffb485Schristos   explicit gdb_exception (gdb_exception &&other) noexcept = default;
1458dffb485Schristos 
1468dffb485Schristos   /* The copy constructor exists so that we can mark it "noexcept",
1478dffb485Schristos      which is a good practice for any sort of exception object.  */
1488dffb485Schristos   gdb_exception (const gdb_exception &other) noexcept
1498dffb485Schristos     : reason (other.reason),
1508dffb485Schristos       error (other.error),
1518dffb485Schristos       message (other.message)
1528dffb485Schristos   {
1538dffb485Schristos   }
1548dffb485Schristos 
1558dffb485Schristos   /* The assignment operator exists so that we can mark it "noexcept",
1568dffb485Schristos      which is a good practice for any sort of exception object.  */
1578dffb485Schristos   gdb_exception &operator= (const gdb_exception &other) noexcept
1588dffb485Schristos   {
1598dffb485Schristos     reason = other.reason;
1608dffb485Schristos     error = other.error;
1618dffb485Schristos     message = other.message;
1628dffb485Schristos     return *this;
1638dffb485Schristos   }
1648dffb485Schristos 
1658dffb485Schristos   gdb_exception &operator= (gdb_exception &&other) noexcept = default;
1668dffb485Schristos 
1678dffb485Schristos   /* Return the contents of the exception message, as a C string.  The
1688dffb485Schristos      string remains owned by the exception object.  */
1698dffb485Schristos   const char *what () const noexcept
1708dffb485Schristos   {
1718dffb485Schristos     return message->c_str ();
1728dffb485Schristos   }
1738dffb485Schristos 
1744b169a6bSchristos   /* Compare two exceptions.  */
1754b169a6bSchristos   bool operator== (const gdb_exception &other) const
1764b169a6bSchristos   {
1774b169a6bSchristos     const char *msg1 = message == nullptr ? "" : what ();
1784b169a6bSchristos     const char *msg2 = other.message == nullptr ? "" : other.what ();
1794b169a6bSchristos 
1804b169a6bSchristos     return (reason == other.reason
1814b169a6bSchristos 	    && error == other.error
1824b169a6bSchristos 	    && strcmp (msg1, msg2) == 0);
1834b169a6bSchristos   }
1844b169a6bSchristos 
1854b169a6bSchristos   /* Compare two exceptions.  */
1864b169a6bSchristos   bool operator!= (const gdb_exception &other) const
1874b169a6bSchristos   {
1884b169a6bSchristos     return !(*this == other);
1894b169a6bSchristos   }
1904b169a6bSchristos 
1918dffb485Schristos   enum return_reason reason;
1928dffb485Schristos   enum errors error;
1938dffb485Schristos   std::shared_ptr<std::string> message;
1948dffb485Schristos };
1958dffb485Schristos 
1964b169a6bSchristos namespace std
1974b169a6bSchristos {
1984b169a6bSchristos 
1994b169a6bSchristos /* Specialization of std::hash for gdb_exception.  */
2004b169a6bSchristos template<>
2014b169a6bSchristos struct hash<gdb_exception>
2024b169a6bSchristos {
2034b169a6bSchristos   size_t operator() (const gdb_exception &exc) const
2044b169a6bSchristos   {
205*5ba1f45fSchristos     size_t result = to_underlying (exc.reason) + to_underlying (exc.error);
2064b169a6bSchristos     if (exc.message != nullptr)
2074b169a6bSchristos       result += std::hash<std::string> {} (*exc.message);
2084b169a6bSchristos     return result;
2094b169a6bSchristos   }
2104b169a6bSchristos };
2114b169a6bSchristos 
2124b169a6bSchristos }
2134b169a6bSchristos 
2148dffb485Schristos /* Functions to drive the sjlj-based exceptions state machine.  Though
2158dffb485Schristos    declared here by necessity, these functions should be considered
2168dffb485Schristos    internal to the exceptions subsystem and not used other than via
2178dffb485Schristos    the TRY/CATCH (or TRY_SJLJ/CATCH_SJLJ) macros defined below.  */
2188dffb485Schristos 
2198dffb485Schristos extern jmp_buf *exceptions_state_mc_init (void);
2208dffb485Schristos extern int exceptions_state_mc_action_iter (void);
2218dffb485Schristos extern int exceptions_state_mc_action_iter_1 (void);
2228dffb485Schristos extern int exceptions_state_mc_catch (struct gdb_exception *, int);
2238dffb485Schristos 
2248dffb485Schristos /* Macro to wrap up standard try/catch behavior.
2258dffb485Schristos 
2268dffb485Schristos    The double loop lets us correctly handle code "break"ing out of the
2278dffb485Schristos    try catch block.  (It works as the "break" only exits the inner
2288dffb485Schristos    "while" loop, the outer for loop detects this handling it
2298dffb485Schristos    correctly.)  Of course "return" and "goto" are not so lucky.
2308dffb485Schristos 
2318dffb485Schristos    For instance:
2328dffb485Schristos 
2338dffb485Schristos    *INDENT-OFF*
2348dffb485Schristos 
2358dffb485Schristos    TRY_SJLJ
2368dffb485Schristos      {
2378dffb485Schristos      }
2388dffb485Schristos    CATCH_SJLJ (e, RETURN_MASK_ERROR)
2398dffb485Schristos      {
2408dffb485Schristos        switch (e.reason)
2418dffb485Schristos 	 {
2428dffb485Schristos 	   case RETURN_ERROR: ...
2438dffb485Schristos 	 }
2448dffb485Schristos      }
2458dffb485Schristos    END_CATCH_SJLJ
2468dffb485Schristos 
2478dffb485Schristos    The SJLJ variants are needed in some cases where gdb exceptions
2488dffb485Schristos    need to cross third-party library code compiled without exceptions
2498dffb485Schristos    support (e.g., readline).  */
2508dffb485Schristos 
2518dffb485Schristos #define TRY_SJLJ \
2528dffb485Schristos      { \
2538dffb485Schristos        jmp_buf *buf = \
2548dffb485Schristos 	 exceptions_state_mc_init (); \
2558dffb485Schristos        setjmp (*buf); \
2568dffb485Schristos      } \
2578dffb485Schristos      while (exceptions_state_mc_action_iter ()) \
2588dffb485Schristos        while (exceptions_state_mc_action_iter_1 ())
2598dffb485Schristos 
2608dffb485Schristos #define CATCH_SJLJ(EXCEPTION, MASK)				\
2618dffb485Schristos   {							\
2628dffb485Schristos     struct gdb_exception EXCEPTION;				\
2638dffb485Schristos     if (exceptions_state_mc_catch (&(EXCEPTION), MASK))
2648dffb485Schristos 
2658dffb485Schristos #define END_CATCH_SJLJ				\
2668dffb485Schristos   }
2678dffb485Schristos 
2688dffb485Schristos /* The exception types client code may catch.  They're just shims
2698dffb485Schristos    around gdb_exception that add nothing but type info.  Which is used
2708dffb485Schristos    is selected depending on the MASK argument passed to CATCH.  */
2718dffb485Schristos 
2728dffb485Schristos struct gdb_exception_error : public gdb_exception
2738dffb485Schristos {
2748dffb485Schristos   gdb_exception_error (enum errors e, const char *fmt, va_list ap)
2758dffb485Schristos     ATTRIBUTE_PRINTF (3, 0)
2768dffb485Schristos     : gdb_exception (RETURN_ERROR, e, fmt, ap)
2778dffb485Schristos   {
2788dffb485Schristos   }
2798dffb485Schristos 
2808dffb485Schristos   explicit gdb_exception_error (gdb_exception &&ex) noexcept
2818dffb485Schristos     : gdb_exception (std::move (ex))
2828dffb485Schristos   {
2838dffb485Schristos     gdb_assert (ex.reason == RETURN_ERROR);
2848dffb485Schristos   }
2858dffb485Schristos };
2868dffb485Schristos 
2878dffb485Schristos struct gdb_exception_quit : public gdb_exception
2888dffb485Schristos {
2898dffb485Schristos   gdb_exception_quit (const char *fmt, va_list ap)
2908dffb485Schristos     ATTRIBUTE_PRINTF (2, 0)
2918dffb485Schristos     : gdb_exception (RETURN_QUIT, GDB_NO_ERROR, fmt, ap)
2928dffb485Schristos   {
2938dffb485Schristos   }
2948dffb485Schristos 
2958dffb485Schristos   explicit gdb_exception_quit (gdb_exception &&ex) noexcept
2968dffb485Schristos     : gdb_exception (std::move (ex))
2978dffb485Schristos   {
2988dffb485Schristos     gdb_assert (ex.reason == RETURN_QUIT);
2998dffb485Schristos   }
3008dffb485Schristos };
3018dffb485Schristos 
302*5ba1f45fSchristos struct gdb_exception_forced_quit : public gdb_exception
303*5ba1f45fSchristos {
304*5ba1f45fSchristos   gdb_exception_forced_quit (const char *fmt, va_list ap)
305*5ba1f45fSchristos     ATTRIBUTE_PRINTF (2, 0)
306*5ba1f45fSchristos     : gdb_exception (RETURN_FORCED_QUIT, GDB_NO_ERROR, fmt, ap)
307*5ba1f45fSchristos   {
308*5ba1f45fSchristos   }
309*5ba1f45fSchristos 
310*5ba1f45fSchristos   explicit gdb_exception_forced_quit (gdb_exception &&ex) noexcept
311*5ba1f45fSchristos     : gdb_exception (std::move (ex))
312*5ba1f45fSchristos   {
313*5ba1f45fSchristos     gdb_assert (ex.reason == RETURN_FORCED_QUIT);
314*5ba1f45fSchristos   }
315*5ba1f45fSchristos };
316*5ba1f45fSchristos 
3178dffb485Schristos /* An exception type that inherits from both std::bad_alloc and a gdb
3188dffb485Schristos    exception.  This is necessary because operator new can only throw
3198dffb485Schristos    std::bad_alloc, and OTOH, we want exceptions thrown due to memory
3208dffb485Schristos    allocation error to be caught by all the CATCH/RETURN_MASK_ALL
3218dffb485Schristos    spread around the codebase.  */
3228dffb485Schristos 
3238dffb485Schristos struct gdb_quit_bad_alloc
3248dffb485Schristos   : public gdb_exception_quit,
3258dffb485Schristos     public std::bad_alloc
3268dffb485Schristos {
3278dffb485Schristos   explicit gdb_quit_bad_alloc (gdb_exception &&ex) noexcept
3288dffb485Schristos     : gdb_exception_quit (std::move (ex)),
3298dffb485Schristos       std::bad_alloc ()
3308dffb485Schristos   {
3318dffb485Schristos   }
3328dffb485Schristos };
3338dffb485Schristos 
3348dffb485Schristos /* *INDENT-ON* */
3358dffb485Schristos 
3368dffb485Schristos /* Throw an exception (as described by "struct gdb_exception"),
3378dffb485Schristos    landing in the inner most containing exception handler established
3388dffb485Schristos    using TRY/CATCH.  */
3398dffb485Schristos extern void throw_exception (gdb_exception &&exception)
3408dffb485Schristos      ATTRIBUTE_NORETURN;
3418dffb485Schristos 
3428dffb485Schristos /* Throw an exception by executing a LONG JUMP to the inner most
3438dffb485Schristos    containing exception handler established using TRY_SJLJ.  Necessary
3448dffb485Schristos    in some cases where we need to throw GDB exceptions across
3458dffb485Schristos    third-party library code (e.g., readline).  */
3468dffb485Schristos extern void throw_exception_sjlj (const struct gdb_exception &exception)
3478dffb485Schristos      ATTRIBUTE_NORETURN;
3488dffb485Schristos 
3498dffb485Schristos /* Convenience wrappers around throw_exception that throw GDB
3508dffb485Schristos    errors.  */
3518dffb485Schristos extern void throw_verror (enum errors, const char *fmt, va_list ap)
3528dffb485Schristos      ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (2, 0);
3538dffb485Schristos extern void throw_vquit (const char *fmt, va_list ap)
3548dffb485Schristos      ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (1, 0);
3558dffb485Schristos extern void throw_error (enum errors error, const char *fmt, ...)
3568dffb485Schristos      ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (2, 3);
3578dffb485Schristos extern void throw_quit (const char *fmt, ...)
3588dffb485Schristos      ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (1, 2);
359*5ba1f45fSchristos extern void throw_forced_quit (const char *fmt, ...)
360*5ba1f45fSchristos      ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF (1, 2);
3618dffb485Schristos 
3628dffb485Schristos #endif /* COMMON_COMMON_EXCEPTIONS_H */
363