* NEWS: Update.
* break-catch-throw.c (compute_exception): New function.
(exception_funcs): New global.
(_initialize_break_catch_throw): Create $_exception.
* cp-abi.c (cplus_type_from_type_info): New function.
* cp-abi.h (cplus_type_from_type_info): Declare.
(struct cp_abi_ops) <get_type_from_type_info>: New field.
* gnu-v3-abi.c (gnuv3_get_typename_from_type_info)
(gnuv3_get_type_from_type_info): New functions.
(init_gnuv3_ops): Set get_type_from_type_info ABI field.
gdb/doc
* gdb.texinfo (Set Catchpoints): Document $_exception.
(Convenience Vars): Mention $_exception.
gdb/testsuite
* gdb.base/default.exp: Update for $_exception.
* gdb.cp/exceptprint.cc: New file.
* gdb.cp/exceptprint.exp: New file.
* lib/gdb.exp (skip_libstdcxx_probe_tests): New proc.
+2013-04-15 Tom Tromey <tromey@redhat.com>
+
+ PR c++/15176:
+ * NEWS: Update.
+ * break-catch-throw.c (compute_exception): New function.
+ (exception_funcs): New global.
+ (_initialize_break_catch_throw): Create $_exception.
+ * cp-abi.c (cplus_type_from_type_info): New function.
+ * cp-abi.h (cplus_type_from_type_info): Declare.
+ (struct cp_abi_ops) <get_type_from_type_info>: New field.
+ * gnu-v3-abi.c (gnuv3_get_typename_from_type_info)
+ (gnuv3_get_type_from_type_info): New functions.
+ (init_gnuv3_ops): Set get_type_from_type_info ABI field.
+
2013-04-15 Tom Tromey <tromey@redhat.com>
* break-catch-throw.c (struct exception_names): New.
* 'info proc' now works on some core files.
+* The new convenience variable $_exception holds the exception being
+ thrown or caught at an exception-related catchpoint.
+
* Python scripting
** Vectors can be created with gdb.Type.vector.
#include "exceptions.h"
#include "linespec.h"
#include "probe.h"
+#include "objfiles.h"
+#include "cp-abi.h"
/* Enums for exception-handling support. */
enum exception_event_kind
\f
+/* Implement the 'make_value' method for the $_exception
+ internalvar. */
+
+static struct value *
+compute_exception (struct gdbarch *argc, struct internalvar *var, void *ignore)
+{
+ struct frame_info *frame = get_selected_frame (_("No frame selected"));
+ CORE_ADDR pc = get_frame_pc (frame);
+ struct probe *pc_probe;
+ const struct sym_probe_fns *pc_probe_fns;
+ unsigned n_args;
+ struct value *arg0, *arg1;
+ struct type *obj_type;
+
+ pc_probe = find_probe_by_pc (pc);
+ if (pc_probe == NULL
+ || strcmp (pc_probe->provider, "libstdcxx") != 0
+ || (strcmp (pc_probe->name, "catch") != 0
+ && strcmp (pc_probe->name, "throw") != 0
+ && strcmp (pc_probe->name, "rethrow") != 0))
+ error (_("not stopped at a C++ exception catchpoint"));
+
+ gdb_assert (pc_probe->objfile != NULL);
+ gdb_assert (pc_probe->objfile->sf != NULL);
+ gdb_assert (pc_probe->objfile->sf->sym_probe_fns != NULL);
+
+ pc_probe_fns = pc_probe->objfile->sf->sym_probe_fns;
+ n_args = pc_probe_fns->sym_get_probe_argument_count (pc_probe);
+ if (n_args < 2)
+ error (_("C++ exception catchpoint has too few arguments"));
+
+ arg0 = pc_probe_fns->sym_evaluate_probe_argument (pc_probe, 0);
+ arg1 = pc_probe_fns->sym_evaluate_probe_argument (pc_probe, 1);
+
+ if (arg0 == NULL || arg1 == NULL)
+ error (_("error computing probe argument at c++ exception catchpoint"));
+
+ /* ARG0 is a pointer to the exception object. ARG1 is a pointer to
+ the std::type_info for the exception. Now we find the type from
+ the type_info and cast the result. */
+ obj_type = cplus_type_from_type_info (arg1);
+ return value_ind (value_cast (make_pointer_type (obj_type, NULL), arg0));
+}
+
+/* Implementation of the '$_exception' variable. */
+
+static const struct internalvar_funcs exception_funcs =
+{
+ compute_exception,
+ NULL,
+ NULL
+};
+
+\f
+
static void
initialize_throw_catchpoint_ops (void)
{
NULL,
CATCH_PERMANENT,
CATCH_TEMPORARY);
+
+ create_internalvar_type_lazy ("_exception", &exception_funcs, NULL);
}
return (*current_cp_abi.get_typeid_type) (gdbarch);
}
+/* See cp-abi.h. */
+
+struct type *
+cplus_type_from_type_info (struct value *value)
+{
+ if (current_cp_abi.get_type_from_type_info == NULL)
+ error (_("GDB cannot find the type from a std::type_info on this target"));
+ return (*current_cp_abi.get_type_from_type_info) (value);
+}
+
int
cp_pass_by_reference (struct type *type)
{
extern struct type *cplus_typeid_type (struct gdbarch *gdbarch);
+/* Given a value which holds a pointer to a std::type_info, return the
+ type which that type_info represents. Throw an exception if the
+ type cannot be found. */
+
+extern struct type *cplus_type_from_type_info (struct value *value);
+
/* Determine if we are currently in a C++ thunk. If so, get the
address of the routine we are thunking to and continue to there
instead. */
void (*print_vtable) (struct value *);
struct value *(*get_typeid) (struct value *value);
struct type *(*get_typeid_type) (struct gdbarch *gdbarch);
+ struct type *(*get_type_from_type_info) (struct value *value);
CORE_ADDR (*skip_trampoline) (struct frame_info *, CORE_ADDR);
int (*pass_by_reference) (struct type *type);
};
+2013-04-15 Tom Tromey <tromey@redhat.com>
+
+ * gdb.texinfo (Set Catchpoints): Document $_exception.
+ (Convenience Vars): Mention $_exception.
+
2013-04-15 Tom Tromey <tromey@redhat.com>
* gdb.texinfo (Set Catchpoints): Reorganize exception
@cindex stop on C@t{++} exceptions
The throwing, re-throwing, or catching of a C@t{++} exception.
+@vindex $_exception@r{, convenience variable}
+The convenience variable @code{$_exception} is available at an
+exception-related catchpoint, on some systems. This holds the
+exception being thrown.
+
There are currently some limitations to C@t{++} exception handling in
@value{GDBN}:
systems using the @samp{gnu-v3} C@t{++} ABI (@pxref{ABI}) are
supported.
+@item
+The @code{$_exception} convenience variable relies on the presence of
+some SDT probes in @code{libstdc++}. If these probes are not present,
+then this variable cannot be used.
+
+@item
+The @code{$_exception} convenience variable is only valid at the
+instruction at which an exception-related catchpoint is set.
+
@item
When an exception-related catchpoint is hit, @value{GDBN} stops at a
location in the system library which implements runtime exception
The variable @code{$_exitcode} is automatically set to the exit code when
the program being debugged terminates.
+@item $_exception
+The variable @code{$_exception} is set to the exception object being
+thrown at an exception-related catchpoint. @xref{Set Catchpoints}.
+
@item $_probe_argc
@itemx $_probe_arg0@dots{}$_probe_arg11
Arguments to a static probe. @xref{Static Probe Points}.
return result;
}
+/* Get the type name given a type_info object. */
+
+static char *
+gnuv3_get_typename_from_type_info (struct value *type_info_ptr)
+{
+ struct gdbarch *gdbarch = get_type_arch (value_type (type_info_ptr));
+ struct bound_minimal_symbol typeinfo_sym;
+ CORE_ADDR addr;
+ const char *symname;
+ const char *class_name;
+ const char *atsign;
+
+ addr = value_as_address (type_info_ptr);
+ typeinfo_sym = lookup_minimal_symbol_by_pc (addr);
+ if (typeinfo_sym.minsym == NULL)
+ error (_("could not find minimal symbol for typeinfo address %s"),
+ paddress (gdbarch, addr));
+
+#define TYPEINFO_PREFIX "typeinfo for "
+#define TYPEINFO_PREFIX_LEN (sizeof (TYPEINFO_PREFIX) - 1)
+ symname = SYMBOL_DEMANGLED_NAME (typeinfo_sym.minsym);
+ if (symname == NULL || strncmp (symname, TYPEINFO_PREFIX,
+ TYPEINFO_PREFIX_LEN))
+ error (_("typeinfo symbol '%s' has unexpected name"),
+ SYMBOL_LINKAGE_NAME (typeinfo_sym.minsym));
+ class_name = symname + TYPEINFO_PREFIX_LEN;
+
+ /* Strip off @plt and version suffixes. */
+ atsign = strchr (class_name, '@');
+ if (atsign != NULL)
+ return savestring (class_name, atsign - class_name);
+ return xstrdup (class_name);
+}
+
+/* Implement the 'get_type_from_type_info' method. */
+
+static struct type *
+gnuv3_get_type_from_type_info (struct value *type_info_ptr)
+{
+ char *typename;
+ struct cleanup *cleanup;
+ struct value *type_val;
+ struct expression *expr;
+ struct type *result;
+
+ typename = gnuv3_get_typename_from_type_info (type_info_ptr);
+ cleanup = make_cleanup (xfree, typename);
+
+ /* We have to parse the type name, since in general there is not a
+ symbol for a type. This is somewhat bogus since there may be a
+ mis-parse. Another approach might be to re-use the demangler's
+ internal form to reconstruct the type somehow. */
+
+ expr = parse_expression (typename);
+ make_cleanup (xfree, expr);
+
+ type_val = evaluate_type (expr);
+ result = value_type (type_val);
+
+ do_cleanups (cleanup);
+ return result;
+}
+
/* Determine if we are currently in a C++ thunk. If so, get the address
of the routine we are thunking to and continue to there instead. */
gnu_v3_abi_ops.print_vtable = gnuv3_print_vtable;
gnu_v3_abi_ops.get_typeid = gnuv3_get_typeid;
gnu_v3_abi_ops.get_typeid_type = gnuv3_get_typeid_type;
+ gnu_v3_abi_ops.get_type_from_type_info = gnuv3_get_type_from_type_info;
gnu_v3_abi_ops.skip_trampoline = gnuv3_skip_trampoline;
gnu_v3_abi_ops.pass_by_reference = gnuv3_pass_by_reference;
}
+2013-04-15 Tom Tromey <tromey@redhat.com>
+
+ * gdb.base/default.exp: Update for $_exception.
+ * gdb.cp/exceptprint.cc: New file.
+ * gdb.cp/exceptprint.exp: New file.
+ * lib/gdb.exp (skip_libstdcxx_probe_tests): New proc.
+
2013-04-15 Tom Tromey <tromey@redhat.com>
* gdb.cp/typeid.cc: New file.
{$_sdata = void} \
{$_siginfo = void} \
{$_thread = 0} \
+ {$_exception = <error: No frame selected>} \
{$_probe_argc = <error: No frame selected>} \
{$_probe_arg0 = <error: No frame selected>} \
{$_probe_arg1 = <error: No frame selected>} \
--- /dev/null
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2013 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/>. */
+
+template<typename T>
+void
+throwit (T val)
+{
+ throw val;
+}
+
+template<typename T>
+void
+rethrowit (T val)
+{
+ try
+ {
+ try
+ {
+ throwit (val);
+ }
+ catch (...)
+ {
+ throw;
+ }
+ }
+ catch (...)
+ {
+ // Ignore.
+ }
+}
+
+struct maude
+{
+ int mv;
+
+ maude (int x) : mv (x) { }
+};
+
+int
+main (int argc, char **argv)
+{
+ maude mm (77);
+ maude &mmm (mm);
+
+ rethrowit ("hi bob");
+ rethrowit (23);
+ rethrowit (mm);
+ rethrowit (mmm);
+
+ return 0;
+}
--- /dev/null
+# Copyright 2013 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/>.
+
+standard_testfile .cc
+
+if {[skip_cplus_tests]} {
+ return -1
+}
+
+if {[prepare_for_testing $testfile.exp $testfile $srcfile {debug c++}]} {
+ return -1
+}
+
+if {![runto_main]} {
+ return -1
+}
+
+if {![skip_libstdcxx_probe_tests]} {
+ untested "could not find libstdc++ stap probe"
+ return -1
+}
+
+proc do_continue_to_catchpoint {name} {
+ global gdb_prompt
+
+ gdb_test_multiple "continue" $name {
+ -re "Continuing.*Catchpoint \[0-9\].*\r\n$gdb_prompt $" {
+ pass $name
+ }
+ }
+}
+
+proc do_exceptprint_tests {prefix output} {
+ with_test_prefix $prefix {
+ do_continue_to_catchpoint "continue to throw"
+ gdb_test "print \$_exception" " = $output" \
+ "print exception value at throw"
+
+ do_continue_to_catchpoint "continue to catch"
+ gdb_test "print \$_exception" " = $output" \
+ "print exception value at catch"
+
+ do_continue_to_catchpoint "continue to rethrow"
+ gdb_test "print \$_exception" " = $output" \
+ "print exception value at rethrow"
+
+ do_continue_to_catchpoint "continue to final catch"
+ }
+}
+
+gdb_test "catch catch" "Catchpoint \[0-9\]+ \\(catch\\)" \
+ "catch catch"
+gdb_test "catch throw" "Catchpoint \[0-9\]+ \\(throw\\)" \
+ "catch throw"
+gdb_test "catch rethrow" "Catchpoint \[0-9\]+ \\(rethrow\\)" \
+ "catch rethrow"
+
+do_exceptprint_tests string "$hex \"hi bob\""
+do_exceptprint_tests int 23
+do_exceptprint_tests struct "{mv = 77}"
+do_exceptprint_tests "reference to struct" "{mv = 77}"
return $ok
}
+# Return 0 if we should skip tests that require the libstdc++ stap
+# probes. This must be invoked while gdb is running, after shared
+# libraries have been loaded.
+
+proc skip_libstdcxx_probe_tests {} {
+ global gdb_prompt
+
+ set ok 0
+ gdb_test_multiple "info probe" "check for stap probe in libstdc++" {
+ -re ".*libstdcxx.*catch.*\r\n$gdb_prompt $" {
+ set ok 1
+ }
+ -re "\r\n$gdb_prompt $" {
+ }
+ }
+ return $ok
+}
+
set compiler_info "unknown"
set gcc_compiled 0
set hp_cc_compiler 0