+static struct symtab_and_line ada_exception_sal (enum exception_catchpoint_kind,
+ char *, char **,
+ const struct breakpoint_ops **);
+static char *ada_exception_catchpoint_cond_string (const char *excep_string);
+
+/* Ada catchpoints.
+
+ In the case of catchpoints on Ada exceptions, the catchpoint will
+ stop the target on every exception the program throws. When a user
+ specifies the name of a specific exception, we translate this
+ request into a condition expression (in text form), and then parse
+ it into an expression stored in each of the catchpoint's locations.
+ We then use this condition to check whether the exception that was
+ raised is the one the user is interested in. If not, then the
+ target is resumed again. We store the name of the requested
+ exception, in order to be able to re-set the condition expression
+ when symbols change. */
+
+/* An instance of this type is used to represent an Ada catchpoint
+ breakpoint location. It includes a "struct bp_location" as a kind
+ of base class; users downcast to "struct bp_location *" when
+ needed. */
+
+struct ada_catchpoint_location
+{
+ /* The base class. */
+ struct bp_location base;
+
+ /* The condition that checks whether the exception that was raised
+ is the specific exception the user specified on catchpoint
+ creation. */
+ struct expression *excep_cond_expr;
+};
+
+/* Implement the DTOR method in the bp_location_ops structure for all
+ Ada exception catchpoint kinds. */
+
+static void
+ada_catchpoint_location_dtor (struct bp_location *bl)
+{
+ struct ada_catchpoint_location *al = (struct ada_catchpoint_location *) bl;
+
+ xfree (al->excep_cond_expr);
+}
+
+/* The vtable to be used in Ada catchpoint locations. */
+
+static const struct bp_location_ops ada_catchpoint_location_ops =
+{
+ ada_catchpoint_location_dtor
+};
+
+/* An instance of this type is used to represent an Ada catchpoint.
+ It includes a "struct breakpoint" as a kind of base class; users
+ downcast to "struct breakpoint *" when needed. */
+
+struct ada_catchpoint
+{
+ /* The base class. */
+ struct breakpoint base;
+
+ /* The name of the specific exception the user specified. */
+ char *excep_string;
+};
+
+/* Parse the exception condition string in the context of each of the
+ catchpoint's locations, and store them for later evaluation. */
+
+static void
+create_excep_cond_exprs (struct ada_catchpoint *c)
+{
+ struct cleanup *old_chain;
+ struct bp_location *bl;
+ char *cond_string;
+
+ /* Nothing to do if there's no specific exception to catch. */
+ if (c->excep_string == NULL)
+ return;
+
+ /* Same if there are no locations... */
+ if (c->base.loc == NULL)
+ return;
+
+ /* Compute the condition expression in text form, from the specific
+ expection we want to catch. */
+ cond_string = ada_exception_catchpoint_cond_string (c->excep_string);
+ old_chain = make_cleanup (xfree, cond_string);
+
+ /* Iterate over all the catchpoint's locations, and parse an
+ expression for each. */
+ for (bl = c->base.loc; bl != NULL; bl = bl->next)
+ {
+ struct ada_catchpoint_location *ada_loc
+ = (struct ada_catchpoint_location *) bl;
+ struct expression *exp = NULL;
+
+ if (!bl->shlib_disabled)
+ {
+ volatile struct gdb_exception e;
+ char *s;
+
+ s = cond_string;
+ TRY_CATCH (e, RETURN_MASK_ERROR)
+ {
+ exp = parse_exp_1 (&s, bl->address,
+ block_for_pc (bl->address), 0);
+ }
+ if (e.reason < 0)
+ warning (_("failed to reevaluate internal exception condition "
+ "for catchpoint %d: %s"),
+ c->base.number, e.message);
+ }
+
+ ada_loc->excep_cond_expr = exp;
+ }
+
+ do_cleanups (old_chain);
+}
+
+/* Implement the DTOR method in the breakpoint_ops structure for all
+ exception catchpoint kinds. */
+
+static void
+dtor_exception (enum exception_catchpoint_kind ex, struct breakpoint *b)
+{
+ struct ada_catchpoint *c = (struct ada_catchpoint *) b;
+
+ xfree (c->excep_string);
+
+ bkpt_breakpoint_ops.dtor (b);
+}
+
+/* Implement the ALLOCATE_LOCATION method in the breakpoint_ops
+ structure for all exception catchpoint kinds. */
+
+static struct bp_location *
+allocate_location_exception (enum exception_catchpoint_kind ex,
+ struct breakpoint *self)
+{
+ struct ada_catchpoint_location *loc;
+
+ loc = XNEW (struct ada_catchpoint_location);
+ init_bp_location (&loc->base, &ada_catchpoint_location_ops, self);
+ loc->excep_cond_expr = NULL;
+ return &loc->base;
+}
+
+/* Implement the RE_SET method in the breakpoint_ops structure for all
+ exception catchpoint kinds. */
+
+static void
+re_set_exception (enum exception_catchpoint_kind ex, struct breakpoint *b)
+{
+ struct ada_catchpoint *c = (struct ada_catchpoint *) b;
+
+ /* Call the base class's method. This updates the catchpoint's
+ locations. */
+ bkpt_breakpoint_ops.re_set (b);
+
+ /* Reparse the exception conditional expressions. One for each
+ location. */
+ create_excep_cond_exprs (c);
+}
+
+/* Returns true if we should stop for this breakpoint hit. If the
+ user specified a specific exception, we only want to cause a stop
+ if the program thrown that exception. */
+
+static int
+should_stop_exception (const struct bp_location *bl)
+{
+ struct ada_catchpoint *c = (struct ada_catchpoint *) bl->owner;
+ const struct ada_catchpoint_location *ada_loc
+ = (const struct ada_catchpoint_location *) bl;
+ volatile struct gdb_exception ex;
+ int stop;
+
+ /* With no specific exception, should always stop. */
+ if (c->excep_string == NULL)
+ return 1;
+
+ if (ada_loc->excep_cond_expr == NULL)
+ {
+ /* We will have a NULL expression if back when we were creating
+ the expressions, this location's had failed to parse. */
+ return 1;
+ }
+
+ stop = 1;
+ TRY_CATCH (ex, RETURN_MASK_ALL)
+ {
+ struct value *mark;
+
+ mark = value_mark ();
+ stop = value_true (evaluate_expression (ada_loc->excep_cond_expr));
+ value_free_to_mark (mark);
+ }
+ if (ex.reason < 0)
+ exception_fprintf (gdb_stderr, ex,
+ _("Error in testing exception condition:\n"));
+ return stop;
+}
+
+/* Implement the CHECK_STATUS method in the breakpoint_ops structure
+ for all exception catchpoint kinds. */
+
+static void
+check_status_exception (enum exception_catchpoint_kind ex, bpstat bs)
+{
+ bs->stop = should_stop_exception (bs->bp_location_at);
+}
+