[PATCH] gdb.ada/catch_ex.exp, gdb.ada/mi_catch_ex.exp and unsupported catchpoints
Pedro Alves
pedro@codesourcery.com
Sat Dec 10 22:53:00 GMT 2011
On Friday 09 December 2011 18:12:13, Tom Tromey wrote:
> >>>>> "Pedro" == Pedro Alves <pedro@codesourcery.com> writes:
>
> Pedro> Kidding aside, obviously we wouldn't need to convert
> Pedro> everything at once. We could even get away with only handling
> Pedro> the simpler prototypes we care about at first.
>
> Yeah. And to be totally clear, if someone wants to do this, I am in
> favor of it.
Here's a start. I didn't really try to confirm if I was extracting the
arguments correctly for any other function bug the Ada runtime's
function in question, but at least it works in the case we're
interested in. :-)
Unfortunately, libgnat is fully stripped (at least on ubuntu), symbol
table and all, so there'd be a little repackaging work to do to get
rid of the debug info dependency -- otherwise, we still need debug
info to be able to insert the hook breakpoints (but no longer to
be able to extract the hook's argument).
2011-12-10 Pedro Alves <pedro@codesourcery.com>
* ada-lang.c (ada_unhandled_exception_name_addr): Extract the
exception name without using debug info if the gdbarch supports
it.
(ada_exception_name_addr_1): Use ada_unhandled_exception_name_addr
for ex_catch_exception.
* amd64-tdep.c (amd64_extract_arguments_1)
(amd64_extract_arguments): New.
(amd64_init_abi): Install amd64_extract_arguments as
extract_arguments gdbarch method.
* i386-tdep.c (i386_extract_arguments): New.
(i386_gdbarch_init): Install i386_extract_arguments as
extract_arguments gdbarch method.
* gdbarch.sh (extract_arguments): New.
* gdbarch.h, gdbarch.c: Regenerate.
---
gdb/ada-lang.c | 61 ++++++++++++++++++++-
gdb/amd64-tdep.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/gdbarch.c | 33 +++++++++++
gdb/gdbarch.h | 6 ++
gdb/gdbarch.sh | 7 ++
gdb/i386-tdep.c | 50 +++++++++++++++++
6 files changed, 311 insertions(+), 3 deletions(-)
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 3843539..1aecfdb 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10804,7 +10804,63 @@ ada_find_printable_frame (struct frame_info *fi)
static CORE_ADDR
ada_unhandled_exception_name_addr (void)
{
- return parse_and_eval_address ("e.full_name");
+ struct frame_info *frame = get_current_frame ();
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+
+ /* Try to extract the arguments even if debug info for libgnat isn't
+ present. */
+ if (gdbarch_extract_arguments_p (gdbarch))
+ {
+ struct type **args_in = alloca (1 * sizeof (struct type *));
+ struct value **args_out = alloca (1 * sizeof (struct value *));
+ struct type *void_ptr_type
+ = lookup_pointer_type (builtin_type (gdbarch)->builtin_void);
+ CORE_ADDR e;
+ struct value *full_name_val;
+ CORE_ADDR full_name;
+
+ /* Argument is a pointer to a system.standard_library.exception_data
+ object. E.g.,
+
+ <__gnat_debug_raise_exception> (e=0x7ffff7dcc2e0) at s-except.adb:46
+ (gdb) p e
+ $1 = (access system.standard_library.exception_data) 0x7ffff7dcc2e0
+ (gdb) p *e
+ $2 = (
+ not_handled_by_others => false,
+ lang => 65 'A',
+ name_length => 17,
+ full_name => (system.address) 0x7ffff7b624a0,
+ htable_ptr => 0x7ffff7dcc320,
+ import_code => 0,
+ raise_hook => 0
+ )
+
+ We're interested in FULL_NAME, which is at offset 8 of E in
+ all ABIs we care about.
+ */
+
+ /* Extract the sole function's argument. This is a pointer to a
+ system.standard_library.exception_data object. */
+ args_in[0] = void_ptr_type;
+ gdbarch_extract_arguments (gdbarch, frame, 1, args_in, args_out,
+ NULL, NULL);
+
+ /* Get the argument pointer. */
+ e = value_as_address (args_out[0]);
+
+ /* The FULL_NAME pointer is at offset 8 of the object pointed by
+ E. */
+ full_name_val = value_at (void_ptr_type, e + 8);
+ full_name = value_as_address (full_name_val);
+ return full_name;
+ }
+ else
+ {
+ /* No support for extracting arguments. Will need to rely on
+ debug info being present. */
+ return parse_and_eval_address ("e.full_name");
+ }
}
/* Same as ada_unhandled_exception_name_addr, except that this function
@@ -10859,8 +10915,7 @@ ada_exception_name_addr_1 (enum exception_catchpoint_kind ex,
switch (ex)
{
case ex_catch_exception:
- return (parse_and_eval_address ("e.full_name"));
- break;
+ return ada_unhandled_exception_name_addr ();
case ex_catch_exception_unhandled:
return exception_info->unhandled_exception_name_addr ();
diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index 803a20f..4f506ed 100644
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -905,6 +905,162 @@ amd64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
return sp + 16;
}
+
+static void
+amd64_extract_arguments_1 (struct frame_info *frame, int nargs,
+ struct type **args_in, struct value **args_out,
+ int struct_return)
+{
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int *integer_regs = tdep->call_dummy_integer_regs;
+ int num_integer_regs = tdep->call_dummy_num_integer_regs;
+
+ static int sse_regnum[] =
+ {
+ /* %xmm0 ... %xmm7 */
+ AMD64_XMM0_REGNUM + 0, AMD64_XMM1_REGNUM,
+ AMD64_XMM0_REGNUM + 2, AMD64_XMM0_REGNUM + 3,
+ AMD64_XMM0_REGNUM + 4, AMD64_XMM0_REGNUM + 5,
+ AMD64_XMM0_REGNUM + 6, AMD64_XMM0_REGNUM + 7,
+ };
+ struct type **stack_args = alloca (nargs * sizeof (struct type *));
+ /* We ignore that some arguments that are passed by MEMORY are
+ mirrored in registers. */
+ int num_stack_args = 0;
+ int element = 0;
+ int integer_reg = 0;
+ int sse_reg = 0;
+ int i;
+ CORE_ADDR sp;
+
+ gdb_assert (tdep->classify);
+
+ /* Reserve a register for the "hidden" argument. */
+ if (struct_return)
+ integer_reg++;
+
+ for (i = 0; i < nargs; i++)
+ {
+ struct type *type = args_in[i];
+ int len = TYPE_LENGTH (type);
+ enum amd64_reg_class class[2];
+ int needed_integer_regs = 0;
+ int needed_sse_regs = 0;
+ int j;
+
+ /* Classify argument. */
+ tdep->classify (type, class);
+
+ /* Calculate the number of integer and SSE registers needed for
+ this argument. */
+ for (j = 0; j < 2; j++)
+ {
+ if (class[j] == AMD64_INTEGER)
+ needed_integer_regs++;
+ else if (class[j] == AMD64_SSE)
+ needed_sse_regs++;
+ }
+
+ /* Check whether the argument was passed in registers. */
+ if (integer_reg + needed_integer_regs > num_integer_regs
+ || sse_reg + needed_sse_regs > ARRAY_SIZE (sse_regnum)
+ || (needed_integer_regs == 0 && needed_sse_regs == 0))
+ {
+ /* The argument was passed on the stack. */
+ stack_args[num_stack_args] = args_in[i];
+ num_stack_args++;
+ }
+ else
+ {
+ /* The argument was passed in registers. We assume if more
+ than one register was necessary, then N contiguous
+ registers starting from REGNUM were used. */
+
+ struct value *reg_val;
+ int regnum = -1;
+ int offset = 0;
+
+ switch (class[0])
+ {
+ case AMD64_INTEGER:
+ regnum = integer_regs[integer_reg++];
+ break;
+
+ case AMD64_SSE:
+ regnum = sse_regnum[sse_reg++];
+ break;
+
+ case AMD64_SSEUP:
+ gdb_assert (sse_reg > 0);
+ regnum = sse_regnum[sse_reg - 1];
+ offset = 8;
+ break;
+
+ default:
+ gdb_assert (!"Unexpected register class.");
+ }
+
+ gdb_assert (regnum != -1);
+
+ reg_val = allocate_value_lazy (args_in[i]);
+ VALUE_LVAL (reg_val) = lval_register;
+ VALUE_REGNUM (reg_val) = regnum;
+ VALUE_FRAME_ID (reg_val) = get_frame_id (frame);
+ set_value_offset (reg_val, offset);
+
+ args_out[i] = reg_val;
+ }
+ }
+
+ /* Get the first arg's slot, but unwind, rather than assuming a
+ regular frame with frame pointer. */
+ sp = get_frame_register_unsigned (get_prev_frame (frame),
+ AMD64_RSP_REGNUM);
+
+ /* Extract the stack arguments. */
+ for (i = 0; i < num_stack_args; i++)
+ {
+ struct type *type = stack_args[i];
+ int len = TYPE_LENGTH (type);
+ CORE_ADDR arg_addr = sp + element * 8;
+
+ args_out[i] = value_from_contents_and_address (type, NULL, arg_addr);
+ element += ((len + 7) / 8);
+ }
+}
+
+/* Implementation of gdbarch method extract_arguments. */
+
+static void
+amd64_extract_arguments (struct frame_info *frame,
+ int nargs, struct type **args_in,
+ struct value **args_out,
+ struct type *struct_return_in,
+ struct value **struct_return_out)
+{
+ /* Extract arguments. */
+ amd64_extract_arguments_1 (frame, nargs, args_in, args_out,
+ struct_return_in != NULL);
+
+ /* Extract "hidden" argument". */
+ if (struct_return_in)
+ {
+ struct gdbarch *gdbarch = get_frame_arch (frame);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ CORE_ADDR struct_addr;
+ /* The "hidden" argument is passed throught the first argument
+ register. */
+ const int arg_regnum = tdep->call_dummy_integer_regs[0];
+
+ struct_addr = get_frame_register_unsigned (frame, arg_regnum);
+ *struct_return_out
+ = value_from_contents_and_address (struct_return_in,
+ NULL,
+ struct_addr);
+ }
+}
+
/* Displaced instruction handling. */
@@ -2656,6 +2812,7 @@ amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
ARRAY_SIZE (amd64_dummy_call_integer_regs);
tdep->call_dummy_integer_regs = amd64_dummy_call_integer_regs;
tdep->classify = amd64_classify;
+ set_gdbarch_extract_arguments (gdbarch, amd64_extract_arguments);
set_gdbarch_convert_register_p (gdbarch, i387_convert_register_p);
set_gdbarch_register_to_value (gdbarch, i387_register_to_value);
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 1ada504..88e6728 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -183,6 +183,7 @@ struct gdbarch
gdbarch_push_dummy_call_ftype *push_dummy_call;
int call_dummy_location;
gdbarch_push_dummy_code_ftype *push_dummy_code;
+ gdbarch_extract_arguments_ftype *extract_arguments;
gdbarch_print_registers_info_ftype *print_registers_info;
gdbarch_print_float_info_ftype *print_float_info;
gdbarch_print_vector_info_ftype *print_vector_info;
@@ -338,6 +339,7 @@ struct gdbarch startup_gdbarch =
0, /* push_dummy_call */
0, /* call_dummy_location */
0, /* push_dummy_code */
+ 0, /* extract_arguments */
default_print_registers_info, /* print_registers_info */
0, /* print_float_info */
0, /* print_vector_info */
@@ -626,6 +628,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of push_dummy_call, has predicate. */
/* Skip verify of call_dummy_location, invalid_p == 0 */
/* Skip verify of push_dummy_code, has predicate. */
+ /* Skip verify of extract_arguments, has predicate. */
/* Skip verify of print_registers_info, invalid_p == 0 */
/* Skip verify of print_float_info, has predicate. */
/* Skip verify of print_vector_info, has predicate. */
@@ -907,6 +910,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
"gdbarch_dump: elf_make_msymbol_special = <%s>\n",
host_address_to_string (gdbarch->elf_make_msymbol_special));
fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_extract_arguments_p() = %d\n",
+ gdbarch_extract_arguments_p (gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: extract_arguments = <%s>\n",
+ host_address_to_string (gdbarch->extract_arguments));
+ fprintf_unfiltered (file,
"gdbarch_dump: fast_tracepoint_valid_at = <%s>\n",
host_address_to_string (gdbarch->fast_tracepoint_valid_at));
fprintf_unfiltered (file,
@@ -2153,6 +2162,30 @@ set_gdbarch_push_dummy_code (struct gdbarch *gdbarch,
gdbarch->push_dummy_code = push_dummy_code;
}
+int
+gdbarch_extract_arguments_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->extract_arguments != NULL;
+}
+
+void
+gdbarch_extract_arguments (struct gdbarch *gdbarch, struct frame_info *frame, int nargs, struct type **args_in, struct value **args_out, struct type *struct_return_in, struct value **struct_return_out)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->extract_arguments != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_extract_arguments called\n");
+ gdbarch->extract_arguments (frame, nargs, args_in, args_out, struct_return_in, struct_return_out);
+}
+
+void
+set_gdbarch_extract_arguments (struct gdbarch *gdbarch,
+ gdbarch_extract_arguments_ftype extract_arguments)
+{
+ gdbarch->extract_arguments = extract_arguments;
+}
+
void
gdbarch_print_registers_info (struct gdbarch *gdbarch, struct ui_file *file, struct frame_info *frame, int regnum, int all)
{
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 46c5afa..fb0a51c 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -356,6 +356,12 @@ typedef CORE_ADDR (gdbarch_push_dummy_code_ftype) (struct gdbarch *gdbarch, CORE
extern CORE_ADDR gdbarch_push_dummy_code (struct gdbarch *gdbarch, CORE_ADDR sp, CORE_ADDR funaddr, struct value **args, int nargs, struct type *value_type, CORE_ADDR *real_pc, CORE_ADDR *bp_addr, struct regcache *regcache);
extern void set_gdbarch_push_dummy_code (struct gdbarch *gdbarch, gdbarch_push_dummy_code_ftype *push_dummy_code);
+extern int gdbarch_extract_arguments_p (struct gdbarch *gdbarch);
+
+typedef void (gdbarch_extract_arguments_ftype) (struct frame_info *frame, int nargs, struct type **args_in, struct value **args_out, struct type *struct_return_in, struct value **struct_return_out);
+extern void gdbarch_extract_arguments (struct gdbarch *gdbarch, struct frame_info *frame, int nargs, struct type **args_in, struct value **args_out, struct type *struct_return_in, struct value **struct_return_out);
+extern void set_gdbarch_extract_arguments (struct gdbarch *gdbarch, gdbarch_extract_arguments_ftype *extract_arguments);
+
typedef void (gdbarch_print_registers_info_ftype) (struct gdbarch *gdbarch, struct ui_file *file, struct frame_info *frame, int regnum, int all);
extern void gdbarch_print_registers_info (struct gdbarch *gdbarch, struct ui_file *file, struct frame_info *frame, int regnum, int all);
extern void set_gdbarch_print_registers_info (struct gdbarch *gdbarch, gdbarch_print_registers_info_ftype *print_registers_info);
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index a9ca03d..d04f923 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -478,6 +478,13 @@ M:CORE_ADDR:push_dummy_call:struct value *function, struct regcache *regcache, C
v:int:call_dummy_location::::AT_ENTRY_POINT::0
M:CORE_ADDR:push_dummy_code:CORE_ADDR sp, CORE_ADDR funaddr, struct value **args, int nargs, struct type *value_type, CORE_ADDR *real_pc, CORE_ADDR *bp_addr, struct regcache *regcache:sp, funaddr, args, nargs, value_type, real_pc, bp_addr, regcache
+# Given a method prototype defined by NARGS args, with each arg of
+# corresponding type in the ARGS_IN type array, build NARGS value
+# objects that extract each of the arguments from the frame. If
+# STRUCT_RETURN_IN is not NULL, then STRUCT_RETURN_OUT is set to value
+# that extracts the hidden argument of type STRUCT_RETURN_IN
+F:void:extract_arguments:struct frame_info *frame, int nargs, struct type **args_in, struct value **args_out, struct type *struct_return_in, struct value **struct_return_out:frame, nargs, args_in, args_out, struct_return_in, struct_return_out
+
m:void:print_registers_info:struct ui_file *file, struct frame_info *frame, int regnum, int all:file, frame, regnum, all::default_print_registers_info::0
M:void:print_float_info:struct ui_file *file, struct frame_info *frame, const char *args:file, frame, args
M:void:print_vector_info:struct ui_file *file, struct frame_info *frame, const char *args:file, frame, args
diff --git a/gdb/i386-tdep.c b/gdb/i386-tdep.c
index a4e3a22..4ca873d 100644
--- a/gdb/i386-tdep.c
+++ b/gdb/i386-tdep.c
@@ -2417,6 +2417,54 @@ i386_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
return sp + 8;
}
+/* Implementation of gdbarch method extract_arguments. */
+
+static void
+i386_extract_arguments (struct frame_info *frame,
+ int nargs, struct type **args_in,
+ struct value **args_out,
+ struct type *struct_return_in,
+ struct value **struct_return_out)
+{
+ int i;
+ CORE_ADDR sp = 0;
+ int args_space_used = 0;
+
+ /* Get the first arg's slot ( 8(%ebp) ), but unwind, rather than
+ assuming a regular frame with frame pointer. */
+ sp = get_frame_register_unsigned (get_prev_frame (frame),
+ I386_ESP_REGNUM);
+
+ if (struct_return_in)
+ {
+ *struct_return_out
+ = value_from_contents_and_address (struct_return_in, NULL, sp);
+
+ args_space_used += 4;
+ }
+
+ for (i = 0; i < nargs; i++)
+ {
+ int len = TYPE_LENGTH (args_in[i]);
+
+ if (i386_16_byte_align_p (args_in[i]))
+ args_space_used = align_up (args_space_used, 16);
+
+ args_out[i]
+ = value_from_contents_and_address (args_in[i], NULL,
+ (sp + args_space_used));
+
+ /* The System V ABI says that:
+
+ "An argument's size is increased, if necessary, to make it a
+ multiple of [32-bit] words. This may require tail padding,
+ depending on the size of the argument."
+
+ This makes sure the stack stays word-aligned. */
+ args_space_used += align_up (len, 4);
+ }
+}
+
/* These registers are used for returning integers (and on some
targets also for returning `struct' and `union' values when their
size and alignment match an integer type). */
@@ -7369,6 +7417,8 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
set_gdbarch_push_dummy_call (gdbarch, i386_push_dummy_call);
set_gdbarch_frame_align (gdbarch, i386_frame_align);
+ set_gdbarch_extract_arguments (gdbarch, i386_extract_arguments);
+
set_gdbarch_convert_register_p (gdbarch, i386_convert_register_p);
set_gdbarch_register_to_value (gdbarch, i386_register_to_value);
set_gdbarch_value_to_register (gdbarch, i386_value_to_register);
More information about the Gdb-patches
mailing list