[RFAv2] (Ada) Add gdb-mi support for stopping at start of exception handler.

Message ID 1515402878-30564-1-git-send-email-roirand@adacore.com
State New, archived
Headers

Commit Message

Xavier Roirand Jan. 8, 2018, 9:14 a.m. UTC
  Following my previous commit which add support for stopping at start of
exception handler, this commit adds required gdb-mi support for this
feature.

gdb/ChangeLog:

        * ada-lang.c (catch_ada_exception_command_split,
        create_ada_exception_catchpoint, catch_ada_assert_command_split)
        <cond_string>: Change parameter type.  Update code accordingly.
        Update callers.
        (catch_ada_exception_command, catch_ada_handlers_command,
        catch_assert_command): Use std::string instead of char*.
        * ada-lang.h (create_ada_exception_catchpoint) <cond_string>:
        Update declaration.
        * mi/mi-cmd-catch.c (mi_cmd_catch_assert): Use std::string
        instead of char* for condition string.
        (mi_cmd_catch_exception): Use std::string instead of char* for
        condition string.  Remove uneeded xstrdup.
        (mi_cmd_catch_handlers): New function for -catch-handlers command.
        * mi/mi-cmds.c (struct mi_cmds): Add catch-handlers command.
        * mi/mi-cmds.h (mi_cmd_catch_handlers): Add external declaration.
        * NEWS: Document "-catch-handlers" command.

gdb/doc/ChangeLog:

        * gdb.texinfo (Ada Exception gdb/mi Catchpoints): Add
        documentation for new "-catch-handlers" command.

gdb/testsuite/ChangeLog:

        * gdb.ada/mi_catch_ex_hand.exp: New testcase.
        * gdb.ada/mi_catch_ex_hand/foo.adb: New file.

Tested on x86_64-linux.
---
 gdb/NEWS                                       |   4 +
 gdb/ada-lang.c                                 |  27 ++---
 gdb/ada-lang.h                                 |   4 +-
 gdb/doc/gdb.texinfo                            |  44 ++++++++
 gdb/mi/mi-cmd-catch.c                          |  91 +++++++++++++---
 gdb/mi/mi-cmds.c                               |   2 +
 gdb/mi/mi-cmds.h                               |   1 +
 gdb/testsuite/gdb.ada/mi_catch_ex_hand.exp     | 137 +++++++++++++++++++++++++
 gdb/testsuite/gdb.ada/mi_catch_ex_hand/foo.adb |  33 ++++++
 9 files changed, 314 insertions(+), 29 deletions(-)
 create mode 100644 gdb/testsuite/gdb.ada/mi_catch_ex_hand.exp
 create mode 100644 gdb/testsuite/gdb.ada/mi_catch_ex_hand/foo.adb
  

Comments

Eli Zaretskii Jan. 8, 2018, 6:38 p.m. UTC | #1
> From: Xavier Roirand <roirand@adacore.com>
> Cc: Xavier Roirand <roirand@adacore.com>,	simon.marchi@ericsson.com,	brobecker@adacore.com
> Date: Mon,  8 Jan 2018 10:14:38 +0100
> 
> Following my previous commit which add support for stopping at start of
> exception handler, this commit adds required gdb-mi support for this
> feature.
> 
> gdb/ChangeLog:
> 
>         * ada-lang.c (catch_ada_exception_command_split,
>         create_ada_exception_catchpoint, catch_ada_assert_command_split)
>         <cond_string>: Change parameter type.  Update code accordingly.
>         Update callers.
>         (catch_ada_exception_command, catch_ada_handlers_command,
>         catch_assert_command): Use std::string instead of char*.
>         * ada-lang.h (create_ada_exception_catchpoint) <cond_string>:
>         Update declaration.
>         * mi/mi-cmd-catch.c (mi_cmd_catch_assert): Use std::string
>         instead of char* for condition string.
>         (mi_cmd_catch_exception): Use std::string instead of char* for
>         condition string.  Remove uneeded xstrdup.
>         (mi_cmd_catch_handlers): New function for -catch-handlers command.
>         * mi/mi-cmds.c (struct mi_cmds): Add catch-handlers command.
>         * mi/mi-cmds.h (mi_cmd_catch_handlers): Add external declaration.
>         * NEWS: Document "-catch-handlers" command.
> 
> gdb/doc/ChangeLog:
> 
>         * gdb.texinfo (Ada Exception gdb/mi Catchpoints): Add
>         documentation for new "-catch-handlers" command.
> 
> gdb/testsuite/ChangeLog:
> 
>         * gdb.ada/mi_catch_ex_hand.exp: New testcase.
>         * gdb.ada/mi_catch_ex_hand/foo.adb: New file.

The documentation parts of this patch are approved, with this single
comment:

> +@subsubheading @value{GDBN} Command
> +
> +The corresponding @value{GDBN} command is @samp{catch handlers}.

Please add here a cross-reference to where "catch handlers" is
described.

Thanks.
  
Joel Brobecker Jan. 23, 2018, 11:43 a.m. UTC | #2
Hi Xavier,

On Mon, Jan 08, 2018 at 10:14:38AM +0100, Xavier Roirand wrote:
> Following my previous commit which add support for stopping at start of
> exception handler, this commit adds required gdb-mi support for this
> feature.

Can you split this patch in two. It's better, IMO, as although
the -catch-handlers patch eventually depends on the the fact
that cond_string becomes an std::string reference in
catch_ada_exception_command_split, it's really two separate
patches.

Git makes it really easy to split a patch ("git reset", "git commit -p").
If you're not sure how to do it, please let me know.

> gdb/ChangeLog:
> 
>         * ada-lang.c (catch_ada_exception_command_split,
>         create_ada_exception_catchpoint, catch_ada_assert_command_split)

For symbol names between '(' and ')', we have to close them at
the end of the line, and then re-open them at the next:

       * ada-lang.c (catch_ada_exception_command_split)
       (create_ada_exception_catchpoint, catch_ada_assert_command_split)

Same for some other entries below.

In this case, however, I would like to ask that you list the changes
in the order they are made. Otherwise, this is turns the review of
this ChangeLog entry into a mental exercise, verifying that each
entry is correct, and then that nothing is missing.

>         <cond_string>: Change parameter type.  Update code accordingly.
>         Update callers.
>         (catch_ada_exception_command, catch_ada_handlers_command,
>         catch_assert_command): Use std::string instead of char*.
>         * ada-lang.h (create_ada_exception_catchpoint) <cond_string>:
>         Update declaration.
>         * mi/mi-cmd-catch.c (mi_cmd_catch_assert): Use std::string
>         instead of char* for condition string.
>         (mi_cmd_catch_exception): Use std::string instead of char* for
>         condition string.  Remove uneeded xstrdup.

uneeded -> unneeded

>         (mi_cmd_catch_handlers): New function for -catch-handlers command.

No need to change this here, but FYI: "New function" just good enough.

>         * mi/mi-cmds.c (struct mi_cmds): Add catch-handlers command.
>         * mi/mi-cmds.h (mi_cmd_catch_handlers): Add external declaration.
>         * NEWS: Document "-catch-handlers" command.
> 
> gdb/doc/ChangeLog:
> 
>         * gdb.texinfo (Ada Exception gdb/mi Catchpoints): Add
>         documentation for new "-catch-handlers" command.
> 
> gdb/testsuite/ChangeLog:
> 
>         * gdb.ada/mi_catch_ex_hand.exp: New testcase.
>         * gdb.ada/mi_catch_ex_hand/foo.adb: New file.
> 
> Tested on x86_64-linux.
> ---
>  gdb/NEWS                                       |   4 +
>  gdb/ada-lang.c                                 |  27 ++---
>  gdb/ada-lang.h                                 |   4 +-
>  gdb/doc/gdb.texinfo                            |  44 ++++++++
>  gdb/mi/mi-cmd-catch.c                          |  91 +++++++++++++---
>  gdb/mi/mi-cmds.c                               |   2 +
>  gdb/mi/mi-cmds.h                               |   1 +
>  gdb/testsuite/gdb.ada/mi_catch_ex_hand.exp     | 137 +++++++++++++++++++++++++
>  gdb/testsuite/gdb.ada/mi_catch_ex_hand/foo.adb |  33 ++++++
>  9 files changed, 314 insertions(+), 29 deletions(-)
>  create mode 100644 gdb/testsuite/gdb.ada/mi_catch_ex_hand.exp
>  create mode 100644 gdb/testsuite/gdb.ada/mi_catch_ex_hand/foo.adb
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 2f834c6..8d01b1a 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -374,6 +374,10 @@ show disassembler-options
>    List the shared libraries in the program.  This is
>    equivalent to the CLI command "info shared".
>  
> +-catch-handlers
> +  Catchpoints stopping the program when Ada exceptions are
> +  handled.  This is equivalent to the CLI command "catch handlers".
> +
>  *** Changes in GDB 7.12
>  
>  * GDB and GDBserver now build with a C++ compiler by default.
> diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
> index 622cfd0..1303dad 100644
> --- a/gdb/ada-lang.c
> +++ b/gdb/ada-lang.c
> @@ -13129,7 +13129,7 @@ catch_ada_exception_command_split (const char *args,
>  				   bool is_catch_handlers_cmd,
>                                     enum ada_exception_catchpoint_kind *ex,
>  				   char **excep_string,
> -				   char **cond_string)
> +				   std::string &cond_string)
>  {
>    struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
>    char *exception_name;
> @@ -13196,7 +13196,8 @@ catch_ada_exception_command_split (const char *args,
>        *ex = ada_catch_exception;
>        *excep_string = exception_name;
>      }
> -  *cond_string = cond;
> +  if (cond != NULL)
> +    cond_string.assign(cond);
>  }
>  
>  /* Return the name of the symbol on which we should break in order to
> @@ -13387,7 +13388,7 @@ void
>  create_ada_exception_catchpoint (struct gdbarch *gdbarch,
>  				 enum ada_exception_catchpoint_kind ex_kind,
>  				 char *excep_string,
> -				 char *cond_string,
> +				 std::string &cond_string,

Since we are not changing the cond_string, let's mark it "const".

>  				 int tempflag,
>  				 int disabled,
>  				 int from_tty)
> @@ -13402,8 +13403,8 @@ create_ada_exception_catchpoint (struct gdbarch *gdbarch,
>  				 ops, tempflag, disabled, from_tty);
>    c->excep_string = excep_string;
>    create_excep_cond_exprs (c.get (), ex_kind);
> -  if (cond_string != NULL)
> -    set_breakpoint_condition (c.get (), cond_string, from_tty);
> +  if (!cond_string.empty ())
> +    set_breakpoint_condition (c.get (), cond_string.c_str (), from_tty);
>    install_breakpoint (0, std::move (c), 1);
>  }
>  
> @@ -13418,14 +13419,14 @@ catch_ada_exception_command (const char *arg_entry, int from_tty,
>    int tempflag;
>    enum ada_exception_catchpoint_kind ex_kind;
>    char *excep_string = NULL;
> -  char *cond_string = NULL;
> +  std::string cond_string;
>  
>    tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
>  
>    if (!arg)
>      arg = "";
>    catch_ada_exception_command_split (arg, false, &ex_kind, &excep_string,
> -				     &cond_string);
> +				     cond_string);
>    create_ada_exception_catchpoint (gdbarch, ex_kind,
>  				   excep_string, cond_string,
>  				   tempflag, 1 /* enabled */,
> @@ -13443,14 +13444,14 @@ catch_ada_handlers_command (const char *arg_entry, int from_tty,
>    int tempflag;
>    enum ada_exception_catchpoint_kind ex_kind;
>    char *excep_string = NULL;
> -  char *cond_string = NULL;
> +  std::string cond_string;
>  
>    tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
>  
>    if (!arg)
>      arg = "";
>    catch_ada_exception_command_split (arg, true, &ex_kind, &excep_string,
> -				     &cond_string);
> +				     cond_string);
>    create_ada_exception_catchpoint (gdbarch, ex_kind,
>  				   excep_string, cond_string,
>  				   tempflag, 1 /* enabled */,
> @@ -13466,7 +13467,7 @@ catch_ada_handlers_command (const char *arg_entry, int from_tty,
>     (the memory needs to be deallocated after use).  */
>  
>  static void
> -catch_ada_assert_command_split (const char *args, char **cond_string)
> +catch_ada_assert_command_split (const char *args, std::string cond_string)

Please make the cond_string parameter a reference (to avoid an
unnecessary copy of the parameter).

I suspect we might also need to add a test which verified "catch assert
if [...]" because ...

>  {
>    args = skip_spaces (args);
>  
> @@ -13478,7 +13479,7 @@ catch_ada_assert_command_split (const char *args, char **cond_string)
>        args = skip_spaces (args);
>        if (args[0] == '\0')
>          error (_("condition missing after `if' keyword"));
> -      *cond_string = xstrdup (args);
> +      cond_string.assign (args);

... I think that, before I asked you to pass the string by reference,
the above was doing the assignment to the copy, and therefore had
no effect on the string being given.

My guess based on reading the code is taht you would probably have seen
a regression if there was such a test in our testsuite. Can you add
such a test (as a separate patch, preliminary to this patch, for both
GDB/MI and GDB/CLI)?

No further comments past this point.

>      }
>  
>    /* Otherwise, there should be no other argument at the end of
> @@ -13496,13 +13497,13 @@ catch_assert_command (const char *arg_entry, int from_tty,
>    const char *arg = arg_entry;
>    struct gdbarch *gdbarch = get_current_arch ();
>    int tempflag;
> -  char *cond_string = NULL;
> +  std::string cond_string;
>  
>    tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
>  
>    if (!arg)
>      arg = "";
> -  catch_ada_assert_command_split (arg, &cond_string);
> +  catch_ada_assert_command_split (arg, cond_string);
>    create_ada_exception_catchpoint (gdbarch, ada_catch_assert,
>  				   NULL, cond_string,
>  				   tempflag, 1 /* enabled */,
> diff --git a/gdb/ada-lang.h b/gdb/ada-lang.h
> index bac6c06..a3b2183 100644
> --- a/gdb/ada-lang.h
> +++ b/gdb/ada-lang.h
> @@ -379,8 +379,8 @@ extern std::string ada_name_for_lookup (const char *name);
>  
>  extern void create_ada_exception_catchpoint
>    (struct gdbarch *gdbarch, enum ada_exception_catchpoint_kind ex_kind,
> -   char *excep_string, char *cond_string, int tempflag, int disabled,
> -   int from_tty);
> +   char *excep_string, std::string &cond_string, int tempflag,
> +   int disabled, int from_tty);
>  
>  /* Some information about a given Ada exception.  */
>  
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index 8bdafb0..809dbcd 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -28512,6 +28512,50 @@ times="0",original-location="__gnat_debug_raise_exception"@}
>  (gdb)
>  @end smallexample
>  
> +@subheading The @code{-catch-handlers} Command
> +@findex -catch-handlers
> +
> +@subsubheading Synopsis
> +
> +@smallexample
> + -catch-handlers [ -c @var{condition}] [ -d ] [ -e @var{exception-name} ]
> +    [ -t ]
> +@end smallexample
> +
> +Add a catchpoint stopping when Ada exceptions are handled.
> +By default, the command stops the program when any Ada exception
> +gets handled.  But it is also possible, by using some of the
> +optional parameters described below, to create more selective
> +catchpoints.
> +
> +The possible optional parameters for this command are:
> +
> +@table @samp
> +@item -c @var{condition}
> +Make the catchpoint conditional on @var{condition}.
> +@item -d
> +Create a disabled catchpoint.
> +@item -e @var{exception-name}
> +Only stop when @var{exception-name} is handled.
> +@item -t
> +Create a temporary catchpoint.
> +@end table
> +
> +@subsubheading @value{GDBN} Command
> +
> +The corresponding @value{GDBN} command is @samp{catch handlers}.
> +
> +@subsubheading Example
> +
> +@smallexample
> +-catch-handlers -e Constraint_Error
> +^done,bkptno="4",bkpt=@{number="4",type="breakpoint",disp="keep",
> +enabled="y",addr="0x0000000000402f68",
> +what="`Constraint_Error' Ada exception handlers",thread-groups=["i1"],
> +times="0",original-location="__gnat_begin_handler"@}
> +(gdb)
> +@end smallexample
> +
>  @c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
>  @node GDB/MI Program Context
>  @section @sc{gdb/mi}  Program Context
> diff --git a/gdb/mi/mi-cmd-catch.c b/gdb/mi/mi-cmd-catch.c
> index 38b96cc..f124f56 100644
> --- a/gdb/mi/mi-cmd-catch.c
> +++ b/gdb/mi/mi-cmd-catch.c
> @@ -32,7 +32,7 @@ void
>  mi_cmd_catch_assert (const char *cmd, char *argv[], int argc)
>  {
>    struct gdbarch *gdbarch = get_current_arch();
> -  char *condition = NULL;
> +  std::string condition;
>    int enabled = 1;
>    int temp = 0;
>  
> @@ -62,7 +62,7 @@ mi_cmd_catch_assert (const char *cmd, char *argv[], int argc)
>        switch ((enum opt) opt)
>          {
>  	case OPT_CONDITION:
> -	  condition = oarg;
> +	  condition.assign (oarg);
>  	  break;
>  	case OPT_DISABLED:
>  	  enabled = 0;
> @@ -79,10 +79,6 @@ mi_cmd_catch_assert (const char *cmd, char *argv[], int argc)
>      error (_("Invalid argument: %s"), argv[oind]);
>  
>    scoped_restore restore_breakpoint_reporting = setup_breakpoint_reporting ();
> -  /* create_ada_exception_catchpoint needs CONDITION to be xstrdup'ed,
> -     and will assume control of its lifetime.  */
> -  if (condition != NULL)
> -    condition = xstrdup (condition);
>    create_ada_exception_catchpoint (gdbarch, ada_catch_assert,
>  				   NULL, condition, temp, enabled, 0);
>  }
> @@ -93,7 +89,7 @@ void
>  mi_cmd_catch_exception (const char *cmd, char *argv[], int argc)
>  {
>    struct gdbarch *gdbarch = get_current_arch();
> -  char *condition = NULL;
> +  std::string condition;
>    int enabled = 1;
>    char *exception_name = NULL;
>    int temp = 0;
> @@ -128,7 +124,7 @@ mi_cmd_catch_exception (const char *cmd, char *argv[], int argc)
>        switch ((enum opt) opt)
>          {
>  	case OPT_CONDITION:
> -	  condition = oarg;
> +	  condition.assign (oarg);
>  	  break;
>  	case OPT_DISABLED:
>  	  enabled = 0;
> @@ -156,15 +152,82 @@ mi_cmd_catch_exception (const char *cmd, char *argv[], int argc)
>      error (_("\"-e\" and \"-u\" are mutually exclusive"));
>  
>    scoped_restore restore_breakpoint_reporting = setup_breakpoint_reporting ();
> -  /* create_ada_exception_catchpoint needs EXCEPTION_NAME and CONDITION
> -     to be xstrdup'ed, and will assume control of their lifetime.  */
> +  /* create_ada_exception_catchpoint needs EXCEPTION_NAME to be
> +     xstrdup'ed, and will assume control of its lifetime.  */
>    if (exception_name != NULL)
>      exception_name = xstrdup (exception_name);
> -  if (condition != NULL)
> -    condition = xstrdup (condition);
>    create_ada_exception_catchpoint (gdbarch, ex_kind,
> -				   exception_name, condition,
> -				   temp, enabled, 0);
> +				   exception_name,
> +				   condition, temp, enabled, 0);
> +}
> +
> +/* Handler for the -catch-handlers command.  */
> +
> +void
> +mi_cmd_catch_handlers (const char *cmd, char *argv[], int argc)
> +{
> +  struct gdbarch *gdbarch = get_current_arch ();
> +  std::string condition;
> +  int enabled = 1;
> +  char *exception_name = NULL;
> +  int temp = 0;
> +  enum ada_exception_catchpoint_kind ex_kind = ada_catch_handlers;
> +
> +  int oind = 0;
> +  char *oarg;
> +
> +  enum opt
> +    {
> +      OPT_CONDITION, OPT_DISABLED, OPT_EXCEPTION_NAME, OPT_TEMP
> +    };
> +  static const struct mi_opt opts[] =
> +    {
> +      { "c", OPT_CONDITION, 1},
> +      { "d", OPT_DISABLED, 0 },
> +      { "e", OPT_EXCEPTION_NAME, 1 },
> +      { "t", OPT_TEMP, 0 },
> +      { 0, 0, 0 }
> +    };
> +
> +  for (;;)
> +    {
> +      int opt = mi_getopt ("-catch-handlers", argc, argv, opts,
> +			   &oind, &oarg);
> +
> +      if (opt < 0)
> +        break;
> +
> +      switch ((enum opt) opt)
> +        {
> +	case OPT_CONDITION:
> +	  condition.assign (oarg);
> +	  break;
> +	case OPT_DISABLED:
> +	  enabled = 0;
> +	  break;
> +	case OPT_EXCEPTION_NAME:
> +	  exception_name = oarg;
> +	  break;
> +	case OPT_TEMP:
> +	  temp = 1;
> +	  break;
> +        }
> +    }
> +
> +  /* This command does not accept any argument.  Make sure the user
> +     did not provide any.  */
> +  if (oind != argc)
> +    error (_("Invalid argument: %s"), argv[oind]);
> +
> +  scoped_restore restore_breakpoint_reporting
> +    = setup_breakpoint_reporting ();
> +  /* create_ada_exception_catchpoint needs EXCEPTION_NAME to be
> +     xstrdup'ed, and will assume control of its lifetime.  */
> +  if (exception_name != NULL)
> +    exception_name = xstrdup (exception_name);
> +  create_ada_exception_catchpoint (gdbarch, ex_kind,
> +				   exception_name,
> +				   condition, temp, enabled, 0);
>  }
>  
>  /* Common path for the -catch-load and -catch-unload.  */
> diff --git a/gdb/mi/mi-cmds.c b/gdb/mi/mi-cmds.c
> index c9ffda1..51014ed 100644
> --- a/gdb/mi/mi-cmds.c
> +++ b/gdb/mi/mi-cmds.c
> @@ -69,6 +69,8 @@ static struct mi_cmd mi_cmds[] =
>                     &mi_suppress_notification.breakpoint),
>    DEF_MI_CMD_MI_1 ("catch-exception", mi_cmd_catch_exception,
>                     &mi_suppress_notification.breakpoint),
> +  DEF_MI_CMD_MI_1 ("catch-handlers", mi_cmd_catch_handlers,
> +                   &mi_suppress_notification.breakpoint),
>    DEF_MI_CMD_MI_1 ("catch-load", mi_cmd_catch_load,
>                     &mi_suppress_notification.breakpoint),
>    DEF_MI_CMD_MI_1 ("catch-unload", mi_cmd_catch_unload,
> diff --git a/gdb/mi/mi-cmds.h b/gdb/mi/mi-cmds.h
> index c27f3ba..af96585 100644
> --- a/gdb/mi/mi-cmds.h
> +++ b/gdb/mi/mi-cmds.h
> @@ -41,6 +41,7 @@ extern mi_cmd_argv_ftype mi_cmd_break_passcount;
>  extern mi_cmd_argv_ftype mi_cmd_break_watch;
>  extern mi_cmd_argv_ftype mi_cmd_catch_assert;
>  extern mi_cmd_argv_ftype mi_cmd_catch_exception;
> +extern mi_cmd_argv_ftype mi_cmd_catch_handlers;
>  extern mi_cmd_argv_ftype mi_cmd_catch_load;
>  extern mi_cmd_argv_ftype mi_cmd_catch_unload;
>  extern mi_cmd_argv_ftype mi_cmd_disassemble;
> diff --git a/gdb/testsuite/gdb.ada/mi_catch_ex_hand.exp b/gdb/testsuite/gdb.ada/mi_catch_ex_hand.exp
> new file mode 100644
> index 0000000..0137add
> --- /dev/null
> +++ b/gdb/testsuite/gdb.ada/mi_catch_ex_hand.exp
> @@ -0,0 +1,137 @@
> +# Copyright 2011-2018 Free Software Foundation, Inc.
> +#
> +# 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/>.
> +
> +load_lib "ada.exp"
> +
> +standard_ada_testfile foo
> +
> +if {[gdb_compile_ada "${srcfile}" "${binfile}" executable [list debug additional_flags=-gnata ]] != "" } {
> +  return -1
> +}
> +
> +# A global variable used to simplify the maintenance of some of
> +# the regular expressions below.
> +set eol "\[\r\n\]+"
> +
> +# Before going any further, verify that we can insert exception
> +# handlers catchpoints...  That way, we won't have to do this while
> +# doing the actual GDB/MI testing.
> +
> +clean_restart ${testfile}
> +
> +if ![runto_main] then {
> +   fail "cannot run to main, testcase aborted"
> +   return 0
> +}
> +
> +set msg "insert catchpoint on all Ada exceptions handlers"
> +gdb_test_multiple "catch handlers" $msg {
> +    -re "Catchpoint $decimal: all Ada exceptions handlers$eol$gdb_prompt $" {
> +	pass $msg
> +    }
> +    -re "Your Ada runtime appears to be missing some debugging information.*\[\r\n\]+$gdb_prompt $" {
> +	# If the runtime was not built with enough debug information,
> +	# or if it was stripped, we can not test exception
> +	# catchpoints.
> +	unsupported $msg
> +	return -1
> +    }
> +}
> +
> +# Now, we can start the GDB/MI testing itself...
> +
> +load_lib mi-support.exp
> +set MIFLAGS "-i=mi"
> +
> +gdb_exit
> +if [mi_gdb_start] {
> +    continue
> +}
> +
> +#############################################
> +# 1. Try catching all exceptions handlers.  #
> +#############################################
> +
> +if ![mi_run_to_main] then {
> +   fail "cannot run to main, testcase aborted"
> +   return 0
> +}
> +
> +mi_gdb_test "-catch-handlers" \
> +            "\\^done,bkptno=\"$decimal\",bkpt={.*disp=\"keep\",enabled=\"y\",addr=\"$hex\",what=\"all Ada exceptions handlers\",.*}" \
> +            "catch all exceptions handlers"
> +
> +# Continue to exception handler.
> +
> +proc continue_to_exception_handler { test line } {
> +
> +    global decimal
> +
> +    mi_send_resuming_command "exec-continue" "$test"
> +
> +    # Now MI stream output.
> +    mi_expect_stop \
> +	"breakpoint-hit\",disp=\"keep\",bkptno=\"$decimal\",exception-name=\"exception\"?" \
> +	"foo" "" ".*" "$line" \
> +	".*" \
> +        $test
> +}
> +
> +# We don't have the exception name info when stopping at the exception handlers
> +# breakpoint so we use source line to check if the inferior stops at the
> +# right location.
> +
> +set bp_ce_location [gdb_get_line_number "BREAK1" ${testdir}/foo.adb]
> +continue_to_exception_handler \
> +    "continue until CE handling caught by all-exceptions handlers catchpoint" \
> +    "$bp_ce_location"
> +
> +set bp_pe_location [gdb_get_line_number "BREAK2" ${testdir}/foo.adb]
> +continue_to_exception_handler \
> +    "continue until PE handling caught by all-exceptions handlers catchpoint" \
> +    "$bp_pe_location"
> +
> +##########################################################
> +# 2. Try catching only some of the exceptions handlers.  #
> +##########################################################
> +
> +# Here is the scenario:
> +#  - Restart the debugger from scratch, runto_main
> +#  - We'll catch only "Constraint_Error handlers"
> +#  - continue, we should stop at the Constraint_Error exception handler
> +#  - continue, we should not stop at the Program_Error exception handler
> +#    but exit instead.
> +
> +if ![mi_run_to_main] then {
> +   fail "cannot run to main, testcase aborted"
> +   return 0
> +}
> +
> +mi_gdb_test "-catch-handlers -e Constraint_Error" \
> +            "\\^done,bkptno=\"$decimal\",bkpt={.*disp=\"keep\",enabled=\"y\",addr=\"$hex\",what=\"`Constraint_Error' Ada exception handlers\",.*}" \
> +            "catch Constraint_Error"
> +
> +mi_execute_to "exec-continue" \
> +              "breakpoint-hit\",disp=\"keep\",bkptno=\"$decimal\",exception-name=\"exception\"?" \
> +              "foo" "" ".*" "$bp_ce_location" \
> +              ".*" \
> +              "continue to exception catchpoint hit"
> +
> +# Exit the inferior.
> +mi_send_resuming_command "exec-continue" "continuing to inferior exit"
> +mi_expect_stop "exited-normally" "" "" "" "" "" "exit normally"
> +
> +mi_gdb_exit
> +return 0
> diff --git a/gdb/testsuite/gdb.ada/mi_catch_ex_hand/foo.adb b/gdb/testsuite/gdb.ada/mi_catch_ex_hand/foo.adb
> new file mode 100644
> index 0000000..da701a3
> --- /dev/null
> +++ b/gdb/testsuite/gdb.ada/mi_catch_ex_hand/foo.adb
> @@ -0,0 +1,33 @@
> +--  Copyright 2007-2018 Free Software Foundation, Inc.
> +--
> +--  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/>.
> +
> +procedure Foo is
> +begin
> +
> +   begin
> +      raise Constraint_Error;
> +   exception
> +      when Constraint_Error => -- BREAK1
> +         null;
> +   end;
> +
> +   begin
> +      raise Program_Error;
> +   exception
> +      when Program_Error => -- BREAK2
> +         null;
> +   end;
> +
> +end Foo;
> -- 
> 2.7.4
  

Patch

diff --git a/gdb/NEWS b/gdb/NEWS
index 2f834c6..8d01b1a 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -374,6 +374,10 @@  show disassembler-options
   List the shared libraries in the program.  This is
   equivalent to the CLI command "info shared".
 
+-catch-handlers
+  Catchpoints stopping the program when Ada exceptions are
+  handled.  This is equivalent to the CLI command "catch handlers".
+
 *** Changes in GDB 7.12
 
 * GDB and GDBserver now build with a C++ compiler by default.
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 622cfd0..1303dad 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -13129,7 +13129,7 @@  catch_ada_exception_command_split (const char *args,
 				   bool is_catch_handlers_cmd,
                                    enum ada_exception_catchpoint_kind *ex,
 				   char **excep_string,
-				   char **cond_string)
+				   std::string &cond_string)
 {
   struct cleanup *old_chain = make_cleanup (null_cleanup, NULL);
   char *exception_name;
@@ -13196,7 +13196,8 @@  catch_ada_exception_command_split (const char *args,
       *ex = ada_catch_exception;
       *excep_string = exception_name;
     }
-  *cond_string = cond;
+  if (cond != NULL)
+    cond_string.assign(cond);
 }
 
 /* Return the name of the symbol on which we should break in order to
@@ -13387,7 +13388,7 @@  void
 create_ada_exception_catchpoint (struct gdbarch *gdbarch,
 				 enum ada_exception_catchpoint_kind ex_kind,
 				 char *excep_string,
-				 char *cond_string,
+				 std::string &cond_string,
 				 int tempflag,
 				 int disabled,
 				 int from_tty)
@@ -13402,8 +13403,8 @@  create_ada_exception_catchpoint (struct gdbarch *gdbarch,
 				 ops, tempflag, disabled, from_tty);
   c->excep_string = excep_string;
   create_excep_cond_exprs (c.get (), ex_kind);
-  if (cond_string != NULL)
-    set_breakpoint_condition (c.get (), cond_string, from_tty);
+  if (!cond_string.empty ())
+    set_breakpoint_condition (c.get (), cond_string.c_str (), from_tty);
   install_breakpoint (0, std::move (c), 1);
 }
 
@@ -13418,14 +13419,14 @@  catch_ada_exception_command (const char *arg_entry, int from_tty,
   int tempflag;
   enum ada_exception_catchpoint_kind ex_kind;
   char *excep_string = NULL;
-  char *cond_string = NULL;
+  std::string cond_string;
 
   tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
 
   if (!arg)
     arg = "";
   catch_ada_exception_command_split (arg, false, &ex_kind, &excep_string,
-				     &cond_string);
+				     cond_string);
   create_ada_exception_catchpoint (gdbarch, ex_kind,
 				   excep_string, cond_string,
 				   tempflag, 1 /* enabled */,
@@ -13443,14 +13444,14 @@  catch_ada_handlers_command (const char *arg_entry, int from_tty,
   int tempflag;
   enum ada_exception_catchpoint_kind ex_kind;
   char *excep_string = NULL;
-  char *cond_string = NULL;
+  std::string cond_string;
 
   tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
 
   if (!arg)
     arg = "";
   catch_ada_exception_command_split (arg, true, &ex_kind, &excep_string,
-				     &cond_string);
+				     cond_string);
   create_ada_exception_catchpoint (gdbarch, ex_kind,
 				   excep_string, cond_string,
 				   tempflag, 1 /* enabled */,
@@ -13466,7 +13467,7 @@  catch_ada_handlers_command (const char *arg_entry, int from_tty,
    (the memory needs to be deallocated after use).  */
 
 static void
-catch_ada_assert_command_split (const char *args, char **cond_string)
+catch_ada_assert_command_split (const char *args, std::string cond_string)
 {
   args = skip_spaces (args);
 
@@ -13478,7 +13479,7 @@  catch_ada_assert_command_split (const char *args, char **cond_string)
       args = skip_spaces (args);
       if (args[0] == '\0')
         error (_("condition missing after `if' keyword"));
-      *cond_string = xstrdup (args);
+      cond_string.assign (args);
     }
 
   /* Otherwise, there should be no other argument at the end of
@@ -13496,13 +13497,13 @@  catch_assert_command (const char *arg_entry, int from_tty,
   const char *arg = arg_entry;
   struct gdbarch *gdbarch = get_current_arch ();
   int tempflag;
-  char *cond_string = NULL;
+  std::string cond_string;
 
   tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
 
   if (!arg)
     arg = "";
-  catch_ada_assert_command_split (arg, &cond_string);
+  catch_ada_assert_command_split (arg, cond_string);
   create_ada_exception_catchpoint (gdbarch, ada_catch_assert,
 				   NULL, cond_string,
 				   tempflag, 1 /* enabled */,
diff --git a/gdb/ada-lang.h b/gdb/ada-lang.h
index bac6c06..a3b2183 100644
--- a/gdb/ada-lang.h
+++ b/gdb/ada-lang.h
@@ -379,8 +379,8 @@  extern std::string ada_name_for_lookup (const char *name);
 
 extern void create_ada_exception_catchpoint
   (struct gdbarch *gdbarch, enum ada_exception_catchpoint_kind ex_kind,
-   char *excep_string, char *cond_string, int tempflag, int disabled,
-   int from_tty);
+   char *excep_string, std::string &cond_string, int tempflag,
+   int disabled, int from_tty);
 
 /* Some information about a given Ada exception.  */
 
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 8bdafb0..809dbcd 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -28512,6 +28512,50 @@  times="0",original-location="__gnat_debug_raise_exception"@}
 (gdb)
 @end smallexample
 
+@subheading The @code{-catch-handlers} Command
+@findex -catch-handlers
+
+@subsubheading Synopsis
+
+@smallexample
+ -catch-handlers [ -c @var{condition}] [ -d ] [ -e @var{exception-name} ]
+    [ -t ]
+@end smallexample
+
+Add a catchpoint stopping when Ada exceptions are handled.
+By default, the command stops the program when any Ada exception
+gets handled.  But it is also possible, by using some of the
+optional parameters described below, to create more selective
+catchpoints.
+
+The possible optional parameters for this command are:
+
+@table @samp
+@item -c @var{condition}
+Make the catchpoint conditional on @var{condition}.
+@item -d
+Create a disabled catchpoint.
+@item -e @var{exception-name}
+Only stop when @var{exception-name} is handled.
+@item -t
+Create a temporary catchpoint.
+@end table
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} command is @samp{catch handlers}.
+
+@subsubheading Example
+
+@smallexample
+-catch-handlers -e Constraint_Error
+^done,bkptno="4",bkpt=@{number="4",type="breakpoint",disp="keep",
+enabled="y",addr="0x0000000000402f68",
+what="`Constraint_Error' Ada exception handlers",thread-groups=["i1"],
+times="0",original-location="__gnat_begin_handler"@}
+(gdb)
+@end smallexample
+
 @c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 @node GDB/MI Program Context
 @section @sc{gdb/mi}  Program Context
diff --git a/gdb/mi/mi-cmd-catch.c b/gdb/mi/mi-cmd-catch.c
index 38b96cc..f124f56 100644
--- a/gdb/mi/mi-cmd-catch.c
+++ b/gdb/mi/mi-cmd-catch.c
@@ -32,7 +32,7 @@  void
 mi_cmd_catch_assert (const char *cmd, char *argv[], int argc)
 {
   struct gdbarch *gdbarch = get_current_arch();
-  char *condition = NULL;
+  std::string condition;
   int enabled = 1;
   int temp = 0;
 
@@ -62,7 +62,7 @@  mi_cmd_catch_assert (const char *cmd, char *argv[], int argc)
       switch ((enum opt) opt)
         {
 	case OPT_CONDITION:
-	  condition = oarg;
+	  condition.assign (oarg);
 	  break;
 	case OPT_DISABLED:
 	  enabled = 0;
@@ -79,10 +79,6 @@  mi_cmd_catch_assert (const char *cmd, char *argv[], int argc)
     error (_("Invalid argument: %s"), argv[oind]);
 
   scoped_restore restore_breakpoint_reporting = setup_breakpoint_reporting ();
-  /* create_ada_exception_catchpoint needs CONDITION to be xstrdup'ed,
-     and will assume control of its lifetime.  */
-  if (condition != NULL)
-    condition = xstrdup (condition);
   create_ada_exception_catchpoint (gdbarch, ada_catch_assert,
 				   NULL, condition, temp, enabled, 0);
 }
@@ -93,7 +89,7 @@  void
 mi_cmd_catch_exception (const char *cmd, char *argv[], int argc)
 {
   struct gdbarch *gdbarch = get_current_arch();
-  char *condition = NULL;
+  std::string condition;
   int enabled = 1;
   char *exception_name = NULL;
   int temp = 0;
@@ -128,7 +124,7 @@  mi_cmd_catch_exception (const char *cmd, char *argv[], int argc)
       switch ((enum opt) opt)
         {
 	case OPT_CONDITION:
-	  condition = oarg;
+	  condition.assign (oarg);
 	  break;
 	case OPT_DISABLED:
 	  enabled = 0;
@@ -156,15 +152,82 @@  mi_cmd_catch_exception (const char *cmd, char *argv[], int argc)
     error (_("\"-e\" and \"-u\" are mutually exclusive"));
 
   scoped_restore restore_breakpoint_reporting = setup_breakpoint_reporting ();
-  /* create_ada_exception_catchpoint needs EXCEPTION_NAME and CONDITION
-     to be xstrdup'ed, and will assume control of their lifetime.  */
+  /* create_ada_exception_catchpoint needs EXCEPTION_NAME to be
+     xstrdup'ed, and will assume control of its lifetime.  */
   if (exception_name != NULL)
     exception_name = xstrdup (exception_name);
-  if (condition != NULL)
-    condition = xstrdup (condition);
   create_ada_exception_catchpoint (gdbarch, ex_kind,
-				   exception_name, condition,
-				   temp, enabled, 0);
+				   exception_name,
+				   condition, temp, enabled, 0);
+}
+
+/* Handler for the -catch-handlers command.  */
+
+void
+mi_cmd_catch_handlers (const char *cmd, char *argv[], int argc)
+{
+  struct gdbarch *gdbarch = get_current_arch ();
+  std::string condition;
+  int enabled = 1;
+  char *exception_name = NULL;
+  int temp = 0;
+  enum ada_exception_catchpoint_kind ex_kind = ada_catch_handlers;
+
+  int oind = 0;
+  char *oarg;
+
+  enum opt
+    {
+      OPT_CONDITION, OPT_DISABLED, OPT_EXCEPTION_NAME, OPT_TEMP
+    };
+  static const struct mi_opt opts[] =
+    {
+      { "c", OPT_CONDITION, 1},
+      { "d", OPT_DISABLED, 0 },
+      { "e", OPT_EXCEPTION_NAME, 1 },
+      { "t", OPT_TEMP, 0 },
+      { 0, 0, 0 }
+    };
+
+  for (;;)
+    {
+      int opt = mi_getopt ("-catch-handlers", argc, argv, opts,
+			   &oind, &oarg);
+
+      if (opt < 0)
+        break;
+
+      switch ((enum opt) opt)
+        {
+	case OPT_CONDITION:
+	  condition.assign (oarg);
+	  break;
+	case OPT_DISABLED:
+	  enabled = 0;
+	  break;
+	case OPT_EXCEPTION_NAME:
+	  exception_name = oarg;
+	  break;
+	case OPT_TEMP:
+	  temp = 1;
+	  break;
+        }
+    }
+
+  /* This command does not accept any argument.  Make sure the user
+     did not provide any.  */
+  if (oind != argc)
+    error (_("Invalid argument: %s"), argv[oind]);
+
+  scoped_restore restore_breakpoint_reporting
+    = setup_breakpoint_reporting ();
+  /* create_ada_exception_catchpoint needs EXCEPTION_NAME to be
+     xstrdup'ed, and will assume control of its lifetime.  */
+  if (exception_name != NULL)
+    exception_name = xstrdup (exception_name);
+  create_ada_exception_catchpoint (gdbarch, ex_kind,
+				   exception_name,
+				   condition, temp, enabled, 0);
 }
 
 /* Common path for the -catch-load and -catch-unload.  */
diff --git a/gdb/mi/mi-cmds.c b/gdb/mi/mi-cmds.c
index c9ffda1..51014ed 100644
--- a/gdb/mi/mi-cmds.c
+++ b/gdb/mi/mi-cmds.c
@@ -69,6 +69,8 @@  static struct mi_cmd mi_cmds[] =
                    &mi_suppress_notification.breakpoint),
   DEF_MI_CMD_MI_1 ("catch-exception", mi_cmd_catch_exception,
                    &mi_suppress_notification.breakpoint),
+  DEF_MI_CMD_MI_1 ("catch-handlers", mi_cmd_catch_handlers,
+                   &mi_suppress_notification.breakpoint),
   DEF_MI_CMD_MI_1 ("catch-load", mi_cmd_catch_load,
                    &mi_suppress_notification.breakpoint),
   DEF_MI_CMD_MI_1 ("catch-unload", mi_cmd_catch_unload,
diff --git a/gdb/mi/mi-cmds.h b/gdb/mi/mi-cmds.h
index c27f3ba..af96585 100644
--- a/gdb/mi/mi-cmds.h
+++ b/gdb/mi/mi-cmds.h
@@ -41,6 +41,7 @@  extern mi_cmd_argv_ftype mi_cmd_break_passcount;
 extern mi_cmd_argv_ftype mi_cmd_break_watch;
 extern mi_cmd_argv_ftype mi_cmd_catch_assert;
 extern mi_cmd_argv_ftype mi_cmd_catch_exception;
+extern mi_cmd_argv_ftype mi_cmd_catch_handlers;
 extern mi_cmd_argv_ftype mi_cmd_catch_load;
 extern mi_cmd_argv_ftype mi_cmd_catch_unload;
 extern mi_cmd_argv_ftype mi_cmd_disassemble;
diff --git a/gdb/testsuite/gdb.ada/mi_catch_ex_hand.exp b/gdb/testsuite/gdb.ada/mi_catch_ex_hand.exp
new file mode 100644
index 0000000..0137add
--- /dev/null
+++ b/gdb/testsuite/gdb.ada/mi_catch_ex_hand.exp
@@ -0,0 +1,137 @@ 
+# Copyright 2011-2018 Free Software Foundation, Inc.
+#
+# 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/>.
+
+load_lib "ada.exp"
+
+standard_ada_testfile foo
+
+if {[gdb_compile_ada "${srcfile}" "${binfile}" executable [list debug additional_flags=-gnata ]] != "" } {
+  return -1
+}
+
+# A global variable used to simplify the maintenance of some of
+# the regular expressions below.
+set eol "\[\r\n\]+"
+
+# Before going any further, verify that we can insert exception
+# handlers catchpoints...  That way, we won't have to do this while
+# doing the actual GDB/MI testing.
+
+clean_restart ${testfile}
+
+if ![runto_main] then {
+   fail "cannot run to main, testcase aborted"
+   return 0
+}
+
+set msg "insert catchpoint on all Ada exceptions handlers"
+gdb_test_multiple "catch handlers" $msg {
+    -re "Catchpoint $decimal: all Ada exceptions handlers$eol$gdb_prompt $" {
+	pass $msg
+    }
+    -re "Your Ada runtime appears to be missing some debugging information.*\[\r\n\]+$gdb_prompt $" {
+	# If the runtime was not built with enough debug information,
+	# or if it was stripped, we can not test exception
+	# catchpoints.
+	unsupported $msg
+	return -1
+    }
+}
+
+# Now, we can start the GDB/MI testing itself...
+
+load_lib mi-support.exp
+set MIFLAGS "-i=mi"
+
+gdb_exit
+if [mi_gdb_start] {
+    continue
+}
+
+#############################################
+# 1. Try catching all exceptions handlers.  #
+#############################################
+
+if ![mi_run_to_main] then {
+   fail "cannot run to main, testcase aborted"
+   return 0
+}
+
+mi_gdb_test "-catch-handlers" \
+            "\\^done,bkptno=\"$decimal\",bkpt={.*disp=\"keep\",enabled=\"y\",addr=\"$hex\",what=\"all Ada exceptions handlers\",.*}" \
+            "catch all exceptions handlers"
+
+# Continue to exception handler.
+
+proc continue_to_exception_handler { test line } {
+
+    global decimal
+
+    mi_send_resuming_command "exec-continue" "$test"
+
+    # Now MI stream output.
+    mi_expect_stop \
+	"breakpoint-hit\",disp=\"keep\",bkptno=\"$decimal\",exception-name=\"exception\"?" \
+	"foo" "" ".*" "$line" \
+	".*" \
+        $test
+}
+
+# We don't have the exception name info when stopping at the exception handlers
+# breakpoint so we use source line to check if the inferior stops at the
+# right location.
+
+set bp_ce_location [gdb_get_line_number "BREAK1" ${testdir}/foo.adb]
+continue_to_exception_handler \
+    "continue until CE handling caught by all-exceptions handlers catchpoint" \
+    "$bp_ce_location"
+
+set bp_pe_location [gdb_get_line_number "BREAK2" ${testdir}/foo.adb]
+continue_to_exception_handler \
+    "continue until PE handling caught by all-exceptions handlers catchpoint" \
+    "$bp_pe_location"
+
+##########################################################
+# 2. Try catching only some of the exceptions handlers.  #
+##########################################################
+
+# Here is the scenario:
+#  - Restart the debugger from scratch, runto_main
+#  - We'll catch only "Constraint_Error handlers"
+#  - continue, we should stop at the Constraint_Error exception handler
+#  - continue, we should not stop at the Program_Error exception handler
+#    but exit instead.
+
+if ![mi_run_to_main] then {
+   fail "cannot run to main, testcase aborted"
+   return 0
+}
+
+mi_gdb_test "-catch-handlers -e Constraint_Error" \
+            "\\^done,bkptno=\"$decimal\",bkpt={.*disp=\"keep\",enabled=\"y\",addr=\"$hex\",what=\"`Constraint_Error' Ada exception handlers\",.*}" \
+            "catch Constraint_Error"
+
+mi_execute_to "exec-continue" \
+              "breakpoint-hit\",disp=\"keep\",bkptno=\"$decimal\",exception-name=\"exception\"?" \
+              "foo" "" ".*" "$bp_ce_location" \
+              ".*" \
+              "continue to exception catchpoint hit"
+
+# Exit the inferior.
+mi_send_resuming_command "exec-continue" "continuing to inferior exit"
+mi_expect_stop "exited-normally" "" "" "" "" "" "exit normally"
+
+mi_gdb_exit
+return 0
diff --git a/gdb/testsuite/gdb.ada/mi_catch_ex_hand/foo.adb b/gdb/testsuite/gdb.ada/mi_catch_ex_hand/foo.adb
new file mode 100644
index 0000000..da701a3
--- /dev/null
+++ b/gdb/testsuite/gdb.ada/mi_catch_ex_hand/foo.adb
@@ -0,0 +1,33 @@ 
+--  Copyright 2007-2018 Free Software Foundation, Inc.
+--
+--  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/>.
+
+procedure Foo is
+begin
+
+   begin
+      raise Constraint_Error;
+   exception
+      when Constraint_Error => -- BREAK1
+         null;
+   end;
+
+   begin
+      raise Program_Error;
+   exception
+      when Program_Error => -- BREAK2
+         null;
+   end;
+
+end Foo;