From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 24300 invoked by alias); 7 Jul 2010 17:11:53 -0000 Received: (qmail 23866 invoked by uid 22791); 7 Jul 2010 17:11:49 -0000 X-SWARE-Spam-Status: No, hits=-5.2 required=5.0 tests=AWL,BAYES_00,KAM_STOCKGEN,RCVD_IN_DNSWL_HI,SPF_HELO_PASS,TW_BJ,T_RP_MATCHES_RCVD X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 07 Jul 2010 17:11:43 +0000 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.13.8/8.13.8) with ESMTP id o67HBfri031173 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Wed, 7 Jul 2010 13:11:42 -0400 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id o67HBffV002810; Wed, 7 Jul 2010 13:11:41 -0400 Received: from opsy.redhat.com (ovpn01.gateway.prod.ext.phx2.redhat.com [10.5.9.1]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id o67HBecF003296; Wed, 7 Jul 2010 13:11:40 -0400 Received: by opsy.redhat.com (Postfix, from userid 500) id 46EFB3784BE; Wed, 7 Jul 2010 11:11:40 -0600 (MDT) From: Tom Tromey To: gdb-patches@sourceware.org Subject: FYI: fix DW_OP_addr and DW_FORM_addr with offsets Date: Wed, 07 Jul 2010 17:11:00 -0000 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux) MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii 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: 2010-07/txt/msg00117.txt.bz2 I'm checking this in. This patch arises from the discussion in this bug: https://bugzilla.redhat.com/show_bug.cgi?id=546017 GCC can emit a DW_AT_const_value using DW_FORM_addr, but gdb fails to apply the needed offsets, leading to an incorrect value. (See the test case in comment #3.) There is a similar bug in our handling of DW_OP_addr. This patch fixes both bugs. It handles DW_FORM_addr by rewriting it into an expression using DW_OP_addr -- this was the simplest way to make things work even when the objfile is relocated. Built and regtested on x86-64 (compile farm). I also tried it on the test case in the PR. Tom 2010-07-07 Tom Tromey * dwarf2read.c (dwarf2_const_value) : Create a LOC_COMPUTED symbol. * dwarf2loc.c (dwarf2_evaluate_loc_desc): Set new field. (dwarf2_loc_desc_needs_frame): Likewise. (compile_dwarf_to_ax) : Use offset. * dwarf2expr.h (struct dwarf_expr_context) : New field. * dwarf2expr.c (execute_stack_op) : Use offset. * dwarf2-frame.c (execute_stack_op): Set 'offset' field. Add 'offset' argument. (struct dwarf2_frame_cache) : New field. (dwarf2_frame_cache): Set new field. (dwarf2_frame_prev_register): Update. (dwarf2_frame_sniffer): Update. (dwarf2_frame_base_sniffer): Update. (dwarf2_frame_find_fde): Add 'out_offset' argument. diff --git a/gdb/dwarf2-frame.c b/gdb/dwarf2-frame.c index 68793cd..bde2a15 100644 --- a/gdb/dwarf2-frame.c +++ b/gdb/dwarf2-frame.c @@ -150,7 +150,8 @@ struct comp_unit bfd_vma tbase; }; -static struct dwarf2_fde *dwarf2_frame_find_fde (CORE_ADDR *pc); +static struct dwarf2_fde *dwarf2_frame_find_fde (CORE_ADDR *pc, + CORE_ADDR *out_offset); static int dwarf2_frame_adjust_regnum (struct gdbarch *gdbarch, int regnum, int eh_frame_p); @@ -369,8 +370,8 @@ register %s (#%d) at %s"), static CORE_ADDR execute_stack_op (const gdb_byte *exp, ULONGEST len, int addr_size, - struct frame_info *this_frame, CORE_ADDR initial, - int initial_in_stack_memory) + CORE_ADDR offset, struct frame_info *this_frame, + CORE_ADDR initial, int initial_in_stack_memory) { struct dwarf_expr_context *ctx; CORE_ADDR result; @@ -381,6 +382,7 @@ execute_stack_op (const gdb_byte *exp, ULONGEST len, int addr_size, ctx->gdbarch = get_frame_arch (this_frame); ctx->addr_size = addr_size; + ctx->offset = offset; ctx->baton = this_frame; ctx->read_reg = read_reg; ctx->read_mem = read_mem; @@ -900,6 +902,9 @@ struct dwarf2_frame_cache /* Target address size in bytes. */ int addr_size; + + /* The .text offset. */ + CORE_ADDR text_offset; }; static struct dwarf2_frame_cache * @@ -943,7 +948,7 @@ dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache) fs->pc = get_frame_address_in_block (this_frame); /* Find the correct FDE. */ - fde = dwarf2_frame_find_fde (&fs->pc); + fde = dwarf2_frame_find_fde (&fs->pc, &cache->text_offset); gdb_assert (fde != NULL); /* Extract any interesting information from the CIE. */ @@ -980,7 +985,8 @@ dwarf2_frame_cache (struct frame_info *this_frame, void **this_cache) case CFA_EXP: cache->cfa = execute_stack_op (fs->regs.cfa_exp, fs->regs.cfa_exp_len, - cache->addr_size, this_frame, 0, 0); + cache->addr_size, cache->text_offset, + this_frame, 0, 0); break; default: @@ -1136,7 +1142,8 @@ dwarf2_frame_prev_register (struct frame_info *this_frame, void **this_cache, case DWARF2_FRAME_REG_SAVED_EXP: addr = execute_stack_op (cache->reg[regnum].loc.exp, cache->reg[regnum].exp_len, - cache->addr_size, this_frame, cache->cfa, 1); + cache->addr_size, cache->text_offset, + this_frame, cache->cfa, 1); return frame_unwind_got_memory (this_frame, regnum, addr); case DWARF2_FRAME_REG_SAVED_VAL_OFFSET: @@ -1146,7 +1153,8 @@ dwarf2_frame_prev_register (struct frame_info *this_frame, void **this_cache, case DWARF2_FRAME_REG_SAVED_VAL_EXP: addr = execute_stack_op (cache->reg[regnum].loc.exp, cache->reg[regnum].exp_len, - cache->addr_size, this_frame, cache->cfa, 1); + cache->addr_size, cache->text_offset, + this_frame, cache->cfa, 1); return frame_unwind_got_constant (this_frame, regnum, addr); case DWARF2_FRAME_REG_UNSPECIFIED: @@ -1196,7 +1204,7 @@ dwarf2_frame_sniffer (const struct frame_unwind *self, extend one byte before its start address or we could potentially select the FDE of the previous function. */ CORE_ADDR block_addr = get_frame_address_in_block (this_frame); - struct dwarf2_fde *fde = dwarf2_frame_find_fde (&block_addr); + struct dwarf2_fde *fde = dwarf2_frame_find_fde (&block_addr, NULL); if (!fde) return 0; @@ -1269,7 +1277,7 @@ dwarf2_frame_base_sniffer (struct frame_info *this_frame) { CORE_ADDR block_addr = get_frame_address_in_block (this_frame); - if (dwarf2_frame_find_fde (&block_addr)) + if (dwarf2_frame_find_fde (&block_addr, NULL)) return &dwarf2_frame_base; return NULL; @@ -1581,7 +1589,7 @@ bsearch_fde_cmp (const void *key, const void *element) inital location associated with it into *PC. */ static struct dwarf2_fde * -dwarf2_frame_find_fde (CORE_ADDR *pc) +dwarf2_frame_find_fde (CORE_ADDR *pc, CORE_ADDR *out_offset) { struct objfile *objfile; @@ -1616,6 +1624,8 @@ dwarf2_frame_find_fde (CORE_ADDR *pc) if (p_fde != NULL) { *pc = (*p_fde)->initial_location + offset; + if (out_offset) + *out_offset = offset; return *p_fde; } } diff --git a/gdb/dwarf2expr.c b/gdb/dwarf2expr.c index 0dc0aaf..7dfcc5b 100644 --- a/gdb/dwarf2expr.c +++ b/gdb/dwarf2expr.c @@ -420,6 +420,12 @@ execute_stack_op (struct dwarf_expr_context *ctx, result = dwarf2_read_address (ctx->gdbarch, op_ptr, op_end, ctx->addr_size); op_ptr += ctx->addr_size; + /* Some versions of GCC emit DW_OP_addr before + DW_OP_GNU_push_tls_address. In this case the value is an + index, not an address. We don't support things like + branching between the address and the TLS op. */ + if (op_ptr >= op_end || *op_ptr != DW_OP_GNU_push_tls_address) + result += ctx->offset; break; case DW_OP_const1u: diff --git a/gdb/dwarf2expr.h b/gdb/dwarf2expr.h index 727e557..8832c35 100644 --- a/gdb/dwarf2expr.h +++ b/gdb/dwarf2expr.h @@ -75,6 +75,9 @@ struct dwarf_expr_context /* Target address size in bytes. */ int addr_size; + /* Offset used to relocate DW_OP_addr argument. */ + CORE_ADDR offset; + /* An opaque argument provided by the caller, which will be passed to all of the callback functions. */ void *baton; diff --git a/gdb/dwarf2loc.c b/gdb/dwarf2loc.c index 46007c2..714da61 100644 --- a/gdb/dwarf2loc.c +++ b/gdb/dwarf2loc.c @@ -892,6 +892,7 @@ dwarf2_evaluate_loc_desc (struct type *type, struct frame_info *frame, struct dwarf_expr_baton baton; struct dwarf_expr_context *ctx; struct cleanup *old_chain; + struct objfile *objfile = dwarf2_per_cu_objfile (per_cu); if (size == 0) { @@ -907,8 +908,9 @@ dwarf2_evaluate_loc_desc (struct type *type, struct frame_info *frame, ctx = new_dwarf_expr_context (); old_chain = make_cleanup_free_dwarf_expr_context (ctx); - ctx->gdbarch = get_objfile_arch (dwarf2_per_cu_objfile (per_cu)); + ctx->gdbarch = get_objfile_arch (objfile); ctx->addr_size = dwarf2_per_cu_addr_size (per_cu); + ctx->offset = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); ctx->baton = &baton; ctx->read_reg = dwarf_expr_read_reg; ctx->read_mem = dwarf_expr_read_mem; @@ -1084,6 +1086,7 @@ dwarf2_loc_desc_needs_frame (const gdb_byte *data, unsigned short size, struct dwarf_expr_context *ctx; int in_reg; struct cleanup *old_chain; + struct objfile *objfile = dwarf2_per_cu_objfile (per_cu); baton.needs_frame = 0; baton.per_cu = per_cu; @@ -1091,8 +1094,9 @@ dwarf2_loc_desc_needs_frame (const gdb_byte *data, unsigned short size, ctx = new_dwarf_expr_context (); old_chain = make_cleanup_free_dwarf_expr_context (ctx); - ctx->gdbarch = get_objfile_arch (dwarf2_per_cu_objfile (per_cu)); + ctx->gdbarch = get_objfile_arch (objfile); ctx->addr_size = dwarf2_per_cu_addr_size (per_cu); + ctx->offset = ANOFFSET (objfile->section_offsets, SECT_OFF_TEXT (objfile)); ctx->baton = &baton; ctx->read_reg = needs_frame_read_reg; ctx->read_mem = needs_frame_read_mem; @@ -1296,8 +1300,19 @@ compile_dwarf_to_ax (struct agent_expr *expr, struct axs_value *loc, case DW_OP_addr: result = dwarf2_read_address (arch, op_ptr, op_end, addr_size); - ax_const_l (expr, result); op_ptr += addr_size; + /* Some versions of GCC emit DW_OP_addr before + DW_OP_GNU_push_tls_address. In this case the value is an + index, not an address. We don't support things like + branching between the address and the TLS op. */ + if (op_ptr >= op_end || *op_ptr != DW_OP_GNU_push_tls_address) + { + struct objfile *objfile = dwarf2_per_cu_objfile (per_cu); + + result += ANOFFSET (objfile->section_offsets, + SECT_OFF_TEXT (objfile)); + } + ax_const_l (expr, result); break; case DW_OP_const1u: diff --git a/gdb/dwarf2read.c b/gdb/dwarf2read.c index bab1fba..4326a97 100644 --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -8981,18 +8981,36 @@ dwarf2_const_value (struct attribute *attr, struct symbol *sym, switch (attr->form) { case DW_FORM_addr: - if (TYPE_LENGTH (SYMBOL_TYPE (sym)) != cu_header->addr_size) - dwarf2_const_value_length_mismatch_complaint (SYMBOL_PRINT_NAME (sym), - cu_header->addr_size, - TYPE_LENGTH (SYMBOL_TYPE - (sym))); - SYMBOL_VALUE_BYTES (sym) = - obstack_alloc (&objfile->objfile_obstack, cu_header->addr_size); - /* NOTE: cagney/2003-05-09: In-lined store_address call with - it's body - store_unsigned_integer. */ - store_unsigned_integer (SYMBOL_VALUE_BYTES (sym), cu_header->addr_size, - byte_order, DW_ADDR (attr)); - SYMBOL_CLASS (sym) = LOC_CONST_BYTES; + { + struct dwarf2_locexpr_baton *baton; + gdb_byte *data; + + if (TYPE_LENGTH (SYMBOL_TYPE (sym)) != cu_header->addr_size) + dwarf2_const_value_length_mismatch_complaint (SYMBOL_PRINT_NAME (sym), + cu_header->addr_size, + TYPE_LENGTH (SYMBOL_TYPE + (sym))); + /* Symbols of this form are reasonably rare, so we just + piggyback on the existing location code rather than writing + a new implementation of symbol_computed_ops. */ + baton = obstack_alloc (&objfile->objfile_obstack, + sizeof (struct dwarf2_locexpr_baton)); + baton->per_cu = cu->per_cu; + gdb_assert (baton->per_cu); + + baton->size = 2 + cu_header->addr_size; + data = obstack_alloc (&objfile->objfile_obstack, baton->size); + baton->data = data; + + data[0] = DW_OP_addr; + store_unsigned_integer (&data[1], cu_header->addr_size, + byte_order, DW_ADDR (attr)); + data[cu_header->addr_size + 1] = DW_OP_stack_value; + + SYMBOL_COMPUTED_OPS (sym) = &dwarf2_locexpr_funcs; + SYMBOL_LOCATION_BATON (sym) = baton; + SYMBOL_CLASS (sym) = LOC_COMPUTED; + } break; case DW_FORM_string: case DW_FORM_strp: