From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 28735 invoked by alias); 10 Dec 2011 19:27:07 -0000 Received: (qmail 28725 invoked by uid 22791); 10 Dec 2011 19:27:05 -0000 X-SWARE-Spam-Status: No, hits=-1.7 required=5.0 tests=AWL,BAYES_00,TW_BG,TW_EG X-Spam-Check-By: sourceware.org Received: from relay1.mentorg.com (HELO relay1.mentorg.com) (192.94.38.131) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sat, 10 Dec 2011 19:26:48 +0000 Received: from nat-ies.mentorg.com ([192.94.31.2] helo=EU1-MAIL.mgc.mentorg.com) by relay1.mentorg.com with esmtp id 1RZSZJ-0004dW-CY from pedro_alves@mentor.com ; Sat, 10 Dec 2011 11:26:45 -0800 Received: from scottsdale.localnet ([172.16.63.104]) by EU1-MAIL.mgc.mentorg.com with Microsoft SMTPSVC(6.0.3790.1830); Sat, 10 Dec 2011 19:26:42 +0000 From: Pedro Alves To: Tom Tromey Subject: Re: [PATCH] gdb.ada/catch_ex.exp, gdb.ada/mi_catch_ex.exp and unsupported catchpoints Date: Sat, 10 Dec 2011 22:53:00 -0000 User-Agent: KMail/1.13.6 (Linux/2.6.38-13-generic; KDE/4.7.2; x86_64; ; ) Cc: Joel Brobecker , gdb-patches@sourceware.org References: <201112061718.50031.pedro@codesourcery.com> <201112091800.02236.pedro@codesourcery.com> In-Reply-To: MIME-Version: 1.0 Content-Type: Text/Plain; charset="iso-8859-15" Content-Transfer-Encoding: 7bit Message-Id: <201112101926.40691.pedro@codesourcery.com> X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2011-12/txt/msg00321.txt.bz2 On Friday 09 December 2011 18:12:13, Tom Tromey wrote: > >>>>> "Pedro" == Pedro Alves 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 * 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);