[rfc breakpoint] Catch exceptions

Daniel Jacobowitz
2003-03-25T03:01:10Z

I'm just looking for feedback on this patch. It's mostly complete except
for some mass re-indenting that some of the changes would require; I'm not
entirely happy with the design yet though, so I'm looking for comments.

The feature being implemented here is "catch catch" and "catch throw". This
patch just does gcc v3; gcc v2.95 is easy to add afterwards, and I also have
a patch to remove the ancient GNU support for this feature for some 1.x g++
versions (or maybe early 2.x?). HP, as usual, supports this in a completely
different way.

The basic idea is that these "catchpoints" are just normal breakpoints and
should be handled as such. But we'd like to print them a little
differently, for clarity.

Here's the interesting bit, from struct breakpoint:
+ enum print_stop_action (*print) (struct breakpoint *);
+
+ void (*print_one) (struct breakpoint *, CORE_ADDR *);
+
+ void (*print_mention) (struct breakpoint *);

i.e. it adds function pointers to the breakpoint to describe the action to
take. Logical next steps include a function to determine whether to stop
(for catch throw TYPE) and maybe even a function to take action when hit (to
simplify longjmp and step_resume breakpoints, etc. - breakpoint.c could be
simplified by this mechanism long-term).

[Why three subtly different print functions? Because there were three
places I needed a hook and they were all different. This sucks. At least
two of them can be condensed... I think... eventually. I'm not interested
in doing that level of cleanup right now, particularly.]

Comments? If no one has any, I'll look to commit this (with reformatting)
in a while. Maybe a week or so.

--
Daniel Jacobowitz
MontaVista Software Debian GNU/Linux Developer

Index: breakpoint.c
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/gdb/breakpoint.c,v
retrieving revision 1.114
diff -u -p -r1.114 breakpoint.c
--- breakpoint.c 11 Mar 2003 19:07:01 -0000 1.114
+++ breakpoint.c 25 Mar 2003 02:49:23 -0000
@@ -2017,6 +2013,9 @@ print_it_typical (bpstat bs)
if (bs->breakpoint_at == NULL)
return PRINT_UNKNOWN;

+ if (bs->breakpoint_at->print != NULL)
+ return (*bs->breakpoint_at->print) (bs->breakpoint_at);
+
switch (bs->breakpoint_at->type)
{
case bp_breakpoint:
@@ -3272,7 +3271,10 @@ print_one_breakpoint (struct breakpoint
else
strcat (wrap_indent, " ");
}
- switch (b->type)
+
+ if (b->print_one != NULL)
+ (*b->print_one) (b, last_addr);
+ else switch (b->type)
{
case bp_none:
internal_error (__FILE__, __LINE__,
@@ -4420,7 +4423,9 @@ mention (struct breakpoint *b)
create_breakpoint_hook (b);
breakpoint_create_event (b->number);

- switch (b->type)
+ if (b->print_mention != NULL)
+ (*b->print_mention) (b);
+ else switch (b->type)
{
case bp_none:
printf_filtered ("(apparently deleted?) Eventpoint %d: ", b->number);
@@ -6192,6 +6016,84 @@ create_exception_catchpoint (int tempfla
mention (b);
}

+static enum print_stop_action
+print_exception_catchpoint (struct breakpoint *b)
+{
+ annotate_catchpoint (b->number);
+
+ if (strstr (b->addr_string, "throw") != NULL)
+ printf_filtered ("\nCatchpoint %d (exception thrown)\n",
+ b->number);
+ else
+ printf_filtered ("\nCatchpoint %d (exception caught)\n",
+ b->number);
+
+ return PRINT_SRC_AND_LOC;
+}
+
+static void
+print_one_exception_catchpoint (struct breakpoint *b, CORE_ADDR *last_addr)
+{
+ if (addressprint)
+ {
+ annotate_field (4);
+ ui_out_field_core_addr (uiout, "addr", b->address);
+ }
+ annotate_field (5);
+ *last_addr = b->address;
+ if (strstr (b->addr_string, "throw") != NULL)
+ ui_out_field_string (uiout, "what", "exception throw");
+ else
+ ui_out_field_string (uiout, "what", "exception catch");
+}
+
+static void
+print_mention_exception_catchpoint (struct breakpoint *b)
+{
+ if (strstr (b->addr_string, "throw") != NULL)
+ printf_filtered ("Catchpoint %d (throw)", b->number);
+ else
+ printf_filtered ("Catchpoint %d (catch)", b->number);
+}
+
+static int
+handle_gnu_v3_exceptions (int tempflag, char *cond_string,
+ enum exception_event_kind ex_event, int from_tty)
+{
+ struct minimal_symbol *trigger_func;
+ const char *trigger_func_name;
+ struct symtab_and_line sal;
+ struct breakpoint *b;
+
+ if (ex_event == EX_EVENT_CATCH)
+ trigger_func_name = "__cxa_begin_catch";
+ else
+ trigger_func_name = "__cxa_throw";
+
+ trigger_func = lookup_minimal_symbol (trigger_func_name, NULL, NULL);
+ if (trigger_func == 0)
+ return 0;
+ sal = find_msymbol_start_sal (trigger_func, 1);
+
+ b = set_raw_breakpoint (sal, bp_breakpoint);
+ set_breakpoint_count (breakpoint_count + 1);
+ b->number = breakpoint_count;
+ b->cond = NULL;
+ b->cond_string = (cond_string == NULL) ?
+ NULL : savestring (cond_string, strlen (cond_string));
+ b->thread = -1;
+ b->addr_string = xstrdup (trigger_func_name);
+ b->enable_state = bp_enabled;
+ b->disposition = tempflag ? disp_del : disp_donttouch;
+ mention (b);
+ b->ep_type = ep_gnuv3;
+
+ b->print = print_exception_catchpoint;
+ b->print_one = print_one_exception_catchpoint;
+ b->print_mention = print_mention_exception_catchpoint;
+ return 1;
+}
+
/* Deal with "catch catch" and "catch throw" commands */

static void
@@ -6212,6 +6114,9 @@ catch_exception_command_1 (enum exceptio
(ex_event != EX_EVENT_CATCH))
error ("Unsupported or unknown exception event; cannot catch it");

+ if (handle_gnu_v3_exceptions (tempflag, cond_string, ex_event, from_tty))
+ return;
+
/* See if we can find a callback routine */
sal = target_enable_exception_callback (ex_event, 1);

Index: breakpoint.h
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/gdb/breakpoint.h,v
retrieving revision 1.19
diff -u -p -r1.19 breakpoint.h
--- breakpoint.h 20 Feb 2003 00:01:05 -0000 1.19
+++ breakpoint.h 25 Mar 2003 02:46:57 -0000
@@ -305,6 +305,14 @@ struct breakpoint
triggered. */
char *exec_pathname;

+ enum {ep_normal, ep_gnuv2, ep_gnuv3} ep_type;
+
+ enum print_stop_action (*print) (struct breakpoint *);
+
+ void (*print_one) (struct breakpoint *, CORE_ADDR *);
+
+ void (*print_mention) (struct breakpoint *);
+
asection *section;
};
\f
Index: linespec.c
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/gdb/linespec.c,v
retrieving revision 1.45
diff -u -p -r1.45 linespec.c
--- linespec.c 3 Mar 2003 17:20:24 -0000 1.45
+++ linespec.c 17 Mar 2003 17:06:34 -0000
@@ -1543,14 +1543,7 @@ minsym_found (int funfirstline, struct m

values.sals = (struct symtab_and_line *)
xmalloc (sizeof (struct symtab_and_line));
- values.sals[0] = find_pc_sect_line (SYMBOL_VALUE_ADDRESS (msymbol),
- (struct sec *) 0, 0);
- values.sals[0].section = SYMBOL_BFD_SECTION (msymbol);
- if (funfirstline)
- {
- values.sals[0].pc += FUNCTION_START_OFFSET;
- values.sals[0].pc = SKIP_PROLOGUE (values.sals[0].pc);
- }
+ values.sals[0] = find_msymbol_start_sal (msymbol, funfirstline);
values.nelts = 1;
return values;
}
Index: symtab.c
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/gdb/symtab.c,v
retrieving revision 1.99
diff -u -p -r1.99 symtab.c
--- symtab.c 4 Mar 2003 17:06:21 -0000 1.99
+++ symtab.c 17 Mar 2003 17:08:01 -0000
@@ -2462,6 +2462,27 @@ find_function_start_sal (struct symbol *
return sal;
}

+/* Given a minimal symbol MSYMBOL, build a corresponding struct
+ symtabs_and_lines.
+ If the argument FUNFIRSTLINE is nonzero, we want the first line
+ of real code inside the function, so skip the prologue. */
+
+struct symtab_and_line
+find_msymbol_start_sal (struct minimal_symbol *msymbol, int funfirstline)
+{
+ struct symtab_and_line sal;
+
+ sal = find_pc_sect_line (SYMBOL_VALUE_ADDRESS (msymbol),
+ (struct sec *) 0, 0);
+ sal.section = SYMBOL_BFD_SECTION (msymbol);
+ if (funfirstline)
+ {
+ sal.pc += FUNCTION_START_OFFSET;
+ sal.pc = SKIP_PROLOGUE (sal.pc);
+ }
+ return sal;
+}
+
/* If P is of the form "operator[ \t]+..." where `...' is
some legitimate operator text, return a pointer to the
beginning of the substring of the operator text.
Index: symtab.h
===================================================================
RCS file: /big/fsf/rsync/src-cvs/src/gdb/symtab.h,v
retrieving revision 1.65
diff -u -p -r1.65 symtab.h
--- symtab.h 3 Mar 2003 18:34:12 -0000 1.65
+++ symtab.h 17 Mar 2003 17:07:03 -0000
@@ -1272,6 +1272,9 @@ extern struct symtab *find_line_symtab (
extern struct symtab_and_line find_function_start_sal (struct symbol *sym,
int);

+extern struct symtab_and_line find_msymbol_start_sal (struct minimal_symbol *,
+ int);
+
/* symfile.c */

extern void clear_symtab_users (void);