gdb/break-catch-throw.c - gdb

Global variables defined

Data types defined

Functions defined

Source code

  1. /* Everything about catch/throw catchpoints, for GDB.

  2.    Copyright (C) 1986-2015 Free Software Foundation, Inc.

  3.    This file is part of GDB.

  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 3 of the License, or
  7.    (at your option) any later version.

  8.    This program is distributed in the hope that it will be useful,
  9.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.    GNU General Public License for more details.

  12.    You should have received a copy of the GNU General Public License
  13.    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */

  14. #include "defs.h"
  15. #include "arch-utils.h"
  16. #include <ctype.h>
  17. #include "breakpoint.h"
  18. #include "gdbcmd.h"
  19. #include "inferior.h"
  20. #include "annotate.h"
  21. #include "valprint.h"
  22. #include "cli/cli-utils.h"
  23. #include "completer.h"
  24. #include "gdb_obstack.h"
  25. #include "mi/mi-common.h"
  26. #include "linespec.h"
  27. #include "probe.h"
  28. #include "objfiles.h"
  29. #include "cp-abi.h"
  30. #include "gdb_regex.h"
  31. #include "cp-support.h"

  32. /* Enums for exception-handling support.  */
  33. enum exception_event_kind
  34. {
  35.   EX_EVENT_THROW,
  36.   EX_EVENT_RETHROW,
  37.   EX_EVENT_CATCH
  38. };

  39. /* Each spot where we may place an exception-related catchpoint has
  40.    two names: the SDT probe point and the function name.  This
  41.    structure holds both.  */

  42. struct exception_names
  43. {
  44.   /* The name of the probe point to try, in the form accepted by
  45.      'parse_probes'.  */

  46.   const char *probe;

  47.   /* The name of the corresponding function.  */

  48.   const char *function;
  49. };

  50. /* Names of the probe points and functions on which to break.  This is
  51.    indexed by exception_event_kind.  */
  52. static const struct exception_names exception_functions[] =
  53. {
  54.   { "-probe-stap libstdcxx:throw", "__cxa_throw" },
  55.   { "-probe-stap libstdcxx:rethrow", "__cxa_rethrow" },
  56.   { "-probe-stap libstdcxx:catch", "__cxa_begin_catch" }
  57. };

  58. static struct breakpoint_ops gnu_v3_exception_catchpoint_ops;

  59. /* The type of an exception catchpoint.  */

  60. struct exception_catchpoint
  61. {
  62.   /* The base class.  */

  63.   struct breakpoint base;

  64.   /* The kind of exception catchpoint.  */

  65.   enum exception_event_kind kind;

  66.   /* If non-NULL, an xmalloc'd string holding the source form of the
  67.      regular expression to match against.  */

  68.   char *exception_rx;

  69.   /* If non-NULL, an xmalloc'd, compiled regular expression which is
  70.      used to determine which exceptions to stop on.  */

  71.   regex_t *pattern;
  72. };



  73. /* A helper function that fetches exception probe arguments.  This
  74.    fills in *ARG0 (if non-NULL) and *ARG1 (which must be non-NULL).
  75.    It will throw an exception on any kind of failure.  */

  76. static void
  77. fetch_probe_arguments (struct value **arg0, struct value **arg1)
  78. {
  79.   struct frame_info *frame = get_selected_frame (_("No frame selected"));
  80.   CORE_ADDR pc = get_frame_pc (frame);
  81.   struct bound_probe pc_probe;
  82.   const struct sym_probe_fns *pc_probe_fns;
  83.   unsigned n_args;

  84.   pc_probe = find_probe_by_pc (pc);
  85.   if (pc_probe.probe == NULL
  86.       || strcmp (pc_probe.probe->provider, "libstdcxx") != 0
  87.       || (strcmp (pc_probe.probe->name, "catch") != 0
  88.           && strcmp (pc_probe.probe->name, "throw") != 0
  89.           && strcmp (pc_probe.probe->name, "rethrow") != 0))
  90.     error (_("not stopped at a C++ exception catchpoint"));

  91.   n_args = get_probe_argument_count (pc_probe.probe, frame);
  92.   if (n_args < 2)
  93.     error (_("C++ exception catchpoint has too few arguments"));

  94.   if (arg0 != NULL)
  95.     *arg0 = evaluate_probe_argument (pc_probe.probe, 0, frame);
  96.   *arg1 = evaluate_probe_argument (pc_probe.probe, 1, frame);

  97.   if ((arg0 != NULL && *arg0 == NULL) || *arg1 == NULL)
  98.     error (_("error computing probe argument at c++ exception catchpoint"));
  99. }



  100. /* A helper function that returns a value indicating the kind of the
  101.    exception catchpoint B.  */

  102. static enum exception_event_kind
  103. classify_exception_breakpoint (struct breakpoint *b)
  104. {
  105.   struct exception_catchpoint *cp = (struct exception_catchpoint *) b;

  106.   return cp->kind;
  107. }

  108. /* Implement the 'dtor' method.  */

  109. static void
  110. dtor_exception_catchpoint (struct breakpoint *self)
  111. {
  112.   struct exception_catchpoint *cp = (struct exception_catchpoint *) self;

  113.   xfree (cp->exception_rx);
  114.   if (cp->pattern != NULL)
  115.     regfree (cp->pattern);
  116.   bkpt_breakpoint_ops.dtor (self);
  117. }

  118. /* Implement the 'check_status' method.  */

  119. static void
  120. check_status_exception_catchpoint (struct bpstats *bs)
  121. {
  122.   struct exception_catchpoint *self
  123.     = (struct exception_catchpoint *) bs->breakpoint_at;
  124.   char *typename = NULL;
  125.   volatile struct gdb_exception e;

  126.   bkpt_breakpoint_ops.check_status (bs);
  127.   if (bs->stop == 0)
  128.     return;

  129.   if (self->pattern == NULL)
  130.     return;

  131.   TRY_CATCH (e, RETURN_MASK_ERROR)
  132.     {
  133.       struct value *typeinfo_arg;
  134.       char *canon;

  135.       fetch_probe_arguments (NULL, &typeinfo_arg);
  136.       typename = cplus_typename_from_type_info (typeinfo_arg);

  137.       canon = cp_canonicalize_string (typename);
  138.       if (canon != NULL)
  139.         {
  140.           xfree (typename);
  141.           typename = canon;
  142.         }
  143.     }

  144.   if (e.reason < 0)
  145.     exception_print (gdb_stderr, e);
  146.   else if (regexec (self->pattern, typename, 0, NULL, 0) != 0)
  147.     bs->stop = 0;

  148.   xfree (typename);
  149. }

  150. /* Implement the 're_set' method.  */

  151. static void
  152. re_set_exception_catchpoint (struct breakpoint *self)
  153. {
  154.   struct symtabs_and_lines sals = {0};
  155.   struct symtabs_and_lines sals_end = {0};
  156.   volatile struct gdb_exception e;
  157.   struct cleanup *cleanup;
  158.   enum exception_event_kind kind = classify_exception_breakpoint (self);

  159.   /* We first try to use the probe interface.  */
  160.   TRY_CATCH (e, RETURN_MASK_ERROR)
  161.     {
  162.       char *spec = ASTRDUP (exception_functions[kind].probe);

  163.       sals = parse_probes (&spec, NULL);
  164.     }

  165.   if (e.reason < 0)
  166.     {
  167.       volatile struct gdb_exception ex;

  168.       /* Using the probe interface failed.  Let's fallback to the normal
  169.          catchpoint mode.  */
  170.       TRY_CATCH (ex, RETURN_MASK_ERROR)
  171.         {
  172.           char *spec = ASTRDUP (exception_functions[kind].function);

  173.           self->ops->decode_linespec (self, &spec, &sals);
  174.         }

  175.       /* NOT_FOUND_ERROR just means the breakpoint will be pending, so
  176.          let it through.  */
  177.       if (ex.reason < 0 && ex.error != NOT_FOUND_ERROR)
  178.         throw_exception (ex);
  179.     }

  180.   cleanup = make_cleanup (xfree, sals.sals);
  181.   update_breakpoint_locations (self, sals, sals_end);
  182.   do_cleanups (cleanup);
  183. }

  184. static enum print_stop_action
  185. print_it_exception_catchpoint (bpstat bs)
  186. {
  187.   struct ui_out *uiout = current_uiout;
  188.   struct breakpoint *b = bs->breakpoint_at;
  189.   int bp_temp;
  190.   enum exception_event_kind kind = classify_exception_breakpoint (b);

  191.   annotate_catchpoint (b->number);

  192.   bp_temp = b->disposition == disp_del;
  193.   ui_out_text (uiout,
  194.                bp_temp ? "Temporary catchpoint "
  195.                        : "Catchpoint ");
  196.   if (!ui_out_is_mi_like_p (uiout))
  197.     ui_out_field_int (uiout, "bkptno", b->number);
  198.   ui_out_text (uiout,
  199.                (kind == EX_EVENT_THROW ? " (exception thrown), "
  200.                 : (kind == EX_EVENT_CATCH ? " (exception caught), "
  201.                    : " (exception rethrown), ")));
  202.   if (ui_out_is_mi_like_p (uiout))
  203.     {
  204.       ui_out_field_string (uiout, "reason",
  205.                            async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
  206.       ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition));
  207.       ui_out_field_int (uiout, "bkptno", b->number);
  208.     }
  209.   return PRINT_SRC_AND_LOC;
  210. }

  211. static void
  212. print_one_exception_catchpoint (struct breakpoint *b,
  213.                                 struct bp_location **last_loc)
  214. {
  215.   struct value_print_options opts;
  216.   struct ui_out *uiout = current_uiout;
  217.   enum exception_event_kind kind = classify_exception_breakpoint (b);

  218.   get_user_print_options (&opts);
  219.   if (opts.addressprint)
  220.     {
  221.       annotate_field (4);
  222.       if (b->loc == NULL || b->loc->shlib_disabled)
  223.         ui_out_field_string (uiout, "addr", "<PENDING>");
  224.       else
  225.         ui_out_field_core_addr (uiout, "addr",
  226.                                 b->loc->gdbarch, b->loc->address);
  227.     }
  228.   annotate_field (5);
  229.   if (b->loc)
  230.     *last_loc = b->loc;

  231.   switch (kind)
  232.     {
  233.     case EX_EVENT_THROW:
  234.       ui_out_field_string (uiout, "what", "exception throw");
  235.       if (ui_out_is_mi_like_p (uiout))
  236.         ui_out_field_string (uiout, "catch-type", "throw");
  237.       break;

  238.     case EX_EVENT_RETHROW:
  239.       ui_out_field_string (uiout, "what", "exception rethrow");
  240.       if (ui_out_is_mi_like_p (uiout))
  241.         ui_out_field_string (uiout, "catch-type", "rethrow");
  242.       break;

  243.     case EX_EVENT_CATCH:
  244.       ui_out_field_string (uiout, "what", "exception catch");
  245.       if (ui_out_is_mi_like_p (uiout))
  246.         ui_out_field_string (uiout, "catch-type", "catch");
  247.       break;
  248.     }
  249. }

  250. /* Implement the 'print_one_detail' method.  */

  251. static void
  252. print_one_detail_exception_catchpoint (const struct breakpoint *b,
  253.                                        struct ui_out *uiout)
  254. {
  255.   const struct exception_catchpoint *cp
  256.     = (const struct exception_catchpoint *) b;

  257.   if (cp->exception_rx != NULL)
  258.     {
  259.       ui_out_text (uiout, _("\tmatching: "));
  260.       ui_out_field_string (uiout, "regexp", cp->exception_rx);
  261.       ui_out_text (uiout, "\n");
  262.     }
  263. }

  264. static void
  265. print_mention_exception_catchpoint (struct breakpoint *b)
  266. {
  267.   struct ui_out *uiout = current_uiout;
  268.   int bp_temp;
  269.   enum exception_event_kind kind = classify_exception_breakpoint (b);

  270.   bp_temp = b->disposition == disp_del;
  271.   ui_out_text (uiout, bp_temp ? _("Temporary catchpoint ")
  272.                               : _("Catchpoint "));
  273.   ui_out_field_int (uiout, "bkptno", b->number);
  274.   ui_out_text (uiout, (kind == EX_EVENT_THROW ? _(" (throw)")
  275.                        : (kind == EX_EVENT_CATCH ? _(" (catch)")
  276.                           : _(" (rethrow)"))));
  277. }

  278. /* Implement the "print_recreate" breakpoint_ops method for throw and
  279.    catch catchpoints.  */

  280. static void
  281. print_recreate_exception_catchpoint (struct breakpoint *b,
  282.                                      struct ui_file *fp)
  283. {
  284.   int bp_temp;
  285.   enum exception_event_kind kind = classify_exception_breakpoint (b);

  286.   bp_temp = b->disposition == disp_del;
  287.   fprintf_unfiltered (fp, bp_temp ? "tcatch " : "catch ");
  288.   switch (kind)
  289.     {
  290.     case EX_EVENT_THROW:
  291.       fprintf_unfiltered (fp, "throw");
  292.       break;
  293.     case EX_EVENT_CATCH:
  294.       fprintf_unfiltered (fp, "catch");
  295.       break;
  296.     case EX_EVENT_RETHROW:
  297.       fprintf_unfiltered (fp, "rethrow");
  298.       break;
  299.     }
  300.   print_recreate_thread (b, fp);
  301. }

  302. static void
  303. handle_gnu_v3_exceptions (int tempflag, char *except_rx, char *cond_string,
  304.                           enum exception_event_kind ex_event, int from_tty)
  305. {
  306.   struct exception_catchpoint *cp;
  307.   struct cleanup *cleanup = make_cleanup (null_cleanup, NULL);
  308.   regex_t *pattern = NULL;

  309.   if (except_rx != NULL)
  310.     {
  311.       pattern = XNEW (regex_t);
  312.       make_cleanup (xfree, pattern);

  313.       compile_rx_or_error (pattern, except_rx,
  314.                            _("invalid type-matching regexp"));
  315.     }

  316.   cp = XCNEW (struct exception_catchpoint);
  317.   make_cleanup (xfree, cp);

  318.   init_catchpoint (&cp->base, get_current_arch (), tempflag, cond_string,
  319.                    &gnu_v3_exception_catchpoint_ops);
  320.   /* We need to reset 'type' in order for code in breakpoint.c to do
  321.      the right thing.  */
  322.   cp->base.type = bp_breakpoint;
  323.   cp->kind = ex_event;
  324.   cp->exception_rx = except_rx;
  325.   cp->pattern = pattern;

  326.   re_set_exception_catchpoint (&cp->base);

  327.   install_breakpoint (0, &cp->base, 1);
  328.   discard_cleanups (cleanup);
  329. }

  330. /* Look for an "if" token in *STRING.  The "if" token must be preceded
  331.    by whitespace.

  332.    If there is any non-whitespace text between *STRING and the "if"
  333.    token, then it is returned in a newly-xmalloc'd string.  Otherwise,
  334.    this returns NULL.

  335.    STRING is updated to point to the "if" token, if it exists, or to
  336.    the end of the string.  */

  337. static char *
  338. extract_exception_regexp (char **string)
  339. {
  340.   char *start;
  341.   char *last, *last_space;

  342.   start = skip_spaces (*string);

  343.   last = start;
  344.   last_space = start;
  345.   while (*last != '\0')
  346.     {
  347.       char *if_token = last;

  348.       /* Check for the "if".  */
  349.       if (check_for_argument (&if_token, "if", 2))
  350.         break;

  351.       /* No "if" token here.  Skip to the next word start.  */
  352.       last_space = skip_to_space (last);
  353.       last = skip_spaces (last_space);
  354.     }

  355.   *string = last;
  356.   if (last_space > start)
  357.     return savestring (start, last_space - start);
  358.   return NULL;
  359. }

  360. /* Deal with "catch catch", "catch throw", and "catch rethrow"
  361.    commands.  */

  362. static void
  363. catch_exception_command_1 (enum exception_event_kind ex_event, char *arg,
  364.                            int tempflag, int from_tty)
  365. {
  366.   char *except_rx;
  367.   char *cond_string = NULL;
  368.   struct cleanup *cleanup;

  369.   if (!arg)
  370.     arg = "";
  371.   arg = skip_spaces (arg);

  372.   except_rx = extract_exception_regexp (&arg);
  373.   cleanup = make_cleanup (xfree, except_rx);

  374.   cond_string = ep_parse_optional_if_clause (&arg);

  375.   if ((*arg != '\0') && !isspace (*arg))
  376.     error (_("Junk at end of arguments."));

  377.   if (ex_event != EX_EVENT_THROW
  378.       && ex_event != EX_EVENT_CATCH
  379.       && ex_event != EX_EVENT_RETHROW)
  380.     error (_("Unsupported or unknown exception event; cannot catch it"));

  381.   handle_gnu_v3_exceptions (tempflag, except_rx, cond_string,
  382.                             ex_event, from_tty);

  383.   discard_cleanups (cleanup);
  384. }

  385. /* Implementation of "catch catch" command.  */

  386. static void
  387. catch_catch_command (char *arg, int from_tty, struct cmd_list_element *command)
  388. {
  389.   int tempflag = get_cmd_context (command) == CATCH_TEMPORARY;

  390.   catch_exception_command_1 (EX_EVENT_CATCH, arg, tempflag, from_tty);
  391. }

  392. /* Implementation of "catch throw" command.  */

  393. static void
  394. catch_throw_command (char *arg, int from_tty, struct cmd_list_element *command)
  395. {
  396.   int tempflag = get_cmd_context (command) == CATCH_TEMPORARY;

  397.   catch_exception_command_1 (EX_EVENT_THROW, arg, tempflag, from_tty);
  398. }

  399. /* Implementation of "catch rethrow" command.  */

  400. static void
  401. catch_rethrow_command (char *arg, int from_tty,
  402.                        struct cmd_list_element *command)
  403. {
  404.   int tempflag = get_cmd_context (command) == CATCH_TEMPORARY;

  405.   catch_exception_command_1 (EX_EVENT_RETHROW, arg, tempflag, from_tty);
  406. }



  407. /* Implement the 'make_value' method for the $_exception
  408.    internalvar.  */

  409. static struct value *
  410. compute_exception (struct gdbarch *argc, struct internalvar *var, void *ignore)
  411. {
  412.   struct value *arg0, *arg1;
  413.   struct type *obj_type;

  414.   fetch_probe_arguments (&arg0, &arg1);

  415.   /* ARG0 is a pointer to the exception object.  ARG1 is a pointer to
  416.      the std::type_info for the exception.  Now we find the type from
  417.      the type_info and cast the result.  */
  418.   obj_type = cplus_type_from_type_info (arg1);
  419.   return value_ind (value_cast (make_pointer_type (obj_type, NULL), arg0));
  420. }

  421. /* Implementation of the '$_exception' variable.  */

  422. static const struct internalvar_funcs exception_funcs =
  423. {
  424.   compute_exception,
  425.   NULL,
  426.   NULL
  427. };



  428. static void
  429. initialize_throw_catchpoint_ops (void)
  430. {
  431.   struct breakpoint_ops *ops;

  432.   initialize_breakpoint_ops ();

  433.   /* GNU v3 exception catchpoints.  */
  434.   ops = &gnu_v3_exception_catchpoint_ops;
  435.   *ops = bkpt_breakpoint_ops;
  436.   ops->dtor = dtor_exception_catchpoint;
  437.   ops->re_set = re_set_exception_catchpoint;
  438.   ops->print_it = print_it_exception_catchpoint;
  439.   ops->print_one = print_one_exception_catchpoint;
  440.   ops->print_mention = print_mention_exception_catchpoint;
  441.   ops->print_recreate = print_recreate_exception_catchpoint;
  442.   ops->print_one_detail = print_one_detail_exception_catchpoint;
  443.   ops->check_status = check_status_exception_catchpoint;
  444. }

  445. initialize_file_ftype _initialize_break_catch_throw;

  446. void
  447. _initialize_break_catch_throw (void)
  448. {
  449.   initialize_throw_catchpoint_ops ();

  450.   /* Add catch and tcatch sub-commands.  */
  451.   add_catch_command ("catch", _("\
  452. Catch an exception, when caught."),
  453.                      catch_catch_command,
  454.                      NULL,
  455.                      CATCH_PERMANENT,
  456.                      CATCH_TEMPORARY);
  457.   add_catch_command ("throw", _("\
  458. Catch an exception, when thrown."),
  459.                      catch_throw_command,
  460.                      NULL,
  461.                      CATCH_PERMANENT,
  462.                      CATCH_TEMPORARY);
  463.   add_catch_command ("rethrow", _("\
  464. Catch an exception, when rethrown."),
  465.                      catch_rethrow_command,
  466.                      NULL,
  467.                      CATCH_PERMANENT,
  468.                      CATCH_TEMPORARY);

  469.   create_internalvar_type_lazy ("_exception", &exception_funcs, NULL);
  470. }