http://sourceware.org/ml/gdb-patches/2011-09/msg00451.html Subject: [patch 2/2] Fix DW_OP_GNU_implicit_pointer for DWARF32 v3+ on 64-bit arches Hi, on 64-bit targets DWARF-3+ is used DW_OP_GNU_implicit_pointer does not work. DWARF-2 says: This type of reference (DW_FORM_ref_addr) is the size of an address on the target architecture; DWARF-3 says: 1.5.1 Upward Compatibility References that use the attribute form DW_FORM_ref_addr are specified to be four bytes in the DWARF 32-bit format and eight bytes in the DWARF 64-bit format, while DWARF Version 2 specifies that such references have the same size as an address on the target system (see Sections 7.4 and 7.5.4). (DW_FORM_ref_addr) In the 32-bit DWARF format, this offset is a 4-byte unsigned value; in the 64-bit DWARF format, it is an 8-byte unsigned value (see Section 7.4). GDB currently parsed DW_OP_GNU_implicit_pointer the DWARF-2 way, being incompatible with DWARF-3+. I think DW_OP_GNU_implicit_pointer does not make sense to be used from .debug_frame (DWARF-5 is not yet released to say more) so for .debug_frame its use is just not permitted (the code would be more complicated otherwise). No regressions on {x86_64,x86_64-m32,i686}-fedora16pre-linux-gnu. Thanks, Jan gdb/ 2011-09-26 Jan Kratochvil Fix DW_OP_GNU_implicit_pointer for DWARF32 v3+ on 64-bit arches. * dwarf2-frame.c (execute_stack_op): Initialize ctx->ref_addr_size. * dwarf2expr.c (execute_stack_op) : Use ctx->ref_addr_size. Handle its invalid value. * dwarf2expr.h (struct dwarf_expr_context): New field ref_addr_size. * dwarf2loc.c (dwarf2_evaluate_loc_desc_full) (dwarf2_loc_desc_needs_frame): Initialize ctx->ref_addr_size. * dwarf2loc.h (dwarf2_per_cu_ref_addr_size): New declaration. * dwarf2read.c (decode_locdesc): Initialize ctx->ref_addr_size. (dwarf2_per_cu_ref_addr_size): New function. gdb/testsuite/ 2011-09-26 Jan Kratochvil Fix DW_OP_GNU_implicit_pointer for DWARF32 v3+ on 64-bit arches. * gdb.dwarf2/implptr-64bit.S: New file. * gdb.dwarf2/implptr-64bit.exp: New file. --- a/gdb/dwarf2-frame.c +++ b/gdb/dwarf2-frame.c @@ -371,6 +371,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->ref_addr_size = -1; ctx->offset = offset; ctx->baton = this_frame; ctx->funcs = &dwarf2_frame_ctx_funcs; --- a/gdb/dwarf2expr.c +++ b/gdb/dwarf2expr.c @@ -709,10 +709,14 @@ execute_stack_op (struct dwarf_expr_context *ctx, ULONGEST die; LONGEST len; + if (ctx->ref_addr_size == -1) + error (_("DWARF-2 expression error: DW_OP_GNU_implicit_pointer " + "is not allowed in frame context")); + /* The referred-to DIE. */ - ctx->len = extract_unsigned_integer (op_ptr, ctx->addr_size, + ctx->len = extract_unsigned_integer (op_ptr, ctx->ref_addr_size, byte_order); - op_ptr += ctx->addr_size; + op_ptr += ctx->ref_addr_size; /* The byte offset into the data. */ op_ptr = read_sleb128 (op_ptr, op_end, &len); --- a/gdb/dwarf2expr.h +++ b/gdb/dwarf2expr.h @@ -125,6 +125,10 @@ struct dwarf_expr_context /* Target address size in bytes. */ int addr_size; + /* DW_FORM_ref_addr size in bytes. If -1 DWARF is executed from a frame + context and operations depending on DW_FORM_ref_addr are not allowed. */ + int ref_addr_size; + /* Offset used to relocate DW_OP_addr argument. */ CORE_ADDR offset; --- a/gdb/dwarf2loc.c +++ b/gdb/dwarf2loc.c @@ -1118,6 +1118,7 @@ dwarf2_evaluate_loc_desc_full (struct type *type, struct frame_info *frame, ctx->gdbarch = get_objfile_arch (objfile); ctx->addr_size = dwarf2_per_cu_addr_size (per_cu); + ctx->ref_addr_size = dwarf2_per_cu_ref_addr_size (per_cu); ctx->offset = dwarf2_per_cu_text_offset (per_cu); ctx->baton = &baton; ctx->funcs = &dwarf_expr_ctx_funcs; @@ -1398,6 +1399,7 @@ dwarf2_loc_desc_needs_frame (const gdb_byte *data, unsigned short size, ctx->gdbarch = get_objfile_arch (objfile); ctx->addr_size = dwarf2_per_cu_addr_size (per_cu); + ctx->ref_addr_size = dwarf2_per_cu_ref_addr_size (per_cu); ctx->offset = dwarf2_per_cu_text_offset (per_cu); ctx->baton = &baton; ctx->funcs = &needs_frame_ctx_funcs; --- a/gdb/dwarf2loc.h +++ b/gdb/dwarf2loc.h @@ -39,6 +39,10 @@ struct objfile *dwarf2_per_cu_objfile (struct dwarf2_per_cu_data *cu); /* Return the address size given in the compilation unit header for CU. */ CORE_ADDR dwarf2_per_cu_addr_size (struct dwarf2_per_cu_data *cu); +/* Return the DW_FORM_ref_addr size given in the compilation unit header for + CU. */ +int dwarf2_per_cu_ref_addr_size (struct dwarf2_per_cu_data *cu); + /* Return the offset size given in the compilation unit header for CU. */ int dwarf2_per_cu_offset_size (struct dwarf2_per_cu_data *cu); --- a/gdb/dwarf2read.c +++ b/gdb/dwarf2read.c @@ -15238,6 +15239,22 @@ dwarf2_per_cu_offset_size (struct dwarf2_per_cu_data *per_cu) return cu_headerp->offset_size; } +/* See its dwarf2loc.h declaration. */ + +int +dwarf2_per_cu_ref_addr_size (struct dwarf2_per_cu_data *per_cu) +{ + struct comp_unit_head cu_header_local; + const struct comp_unit_head *cu_headerp; + + cu_headerp = per_cu_header_read_in (&cu_header_local, per_cu); + + if (cu_headerp->version == 2) + return cu_headerp->addr_size; + else + return cu_headerp->offset_size; +} + /* Return the text offset of the CU. The returned offset comes from this CU's objfile. If this objfile came from a separate debuginfo file, then the offset may be different from the corresponding --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/implptr-64bit.S @@ -0,0 +1,197 @@ +/* Copyright 2010, 2011 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 . */ + + .section .debug_info +d: + /* Length of Compilation Unit Info */ +#if OFFSET_SIZE == 4 +# define OFFSET .4byte + .4byte debug_end - 1f +#elif OFFSET_SIZE == 8 +# define OFFSET .8byte + .4byte 0xffffffff + .8byte debug_end - 1f +#else +# error +#endif +#if ADDR_SIZE == 4 +# define ADDR .4byte +#elif ADDR_SIZE == 8 +# define ADDR .8byte +#else +# error +#endif +#if REF_ADDR_SIZE == 4 +# define REF_ADDR .4byte +#elif REF_ADDR_SIZE == 8 +# define REF_ADDR .8byte +#else +# error +#endif +1: + .2byte DWARF_VERSION /* DWARF version number */ + OFFSET .Ldebug_abbrev0 /* Offset Into Abbrev. Section */ + .byte ADDR_SIZE /* Pointer Size (in bytes) */ + + .uleb128 0x1 /* (DIE (0xb) DW_TAG_compile_unit) */ + .ascii "GNU C 4.4.3\0" /* DW_AT_producer */ + .byte 0x1 /* DW_AT_language */ + .ascii "1.c\0" /* DW_AT_name */ + +.Ltype_int: + .uleb128 0x7 /* DW_TAG_base_type */ + .byte 0x4 /* DW_AT_byte_size */ + .byte 0x5 /* DW_AT_encoding */ + .ascii "int\0" /* DW_AT_name */ + +.Ltype_struct: + .uleb128 0x2 /* DW_TAG_structure_type */ + .ascii "s\0" /* DW_AT_name */ + .byte 4 /* DW_AT_byte_size */ + + .uleb128 0x3 /* DW_TAG_member */ + .ascii "f\0" /* DW_AT_name */ + .4byte .Ltype_int - d /* DW_AT_type */ + .byte 0 /* DW_AT_data_member_location */ + + .byte 0x0 /* end of children of DW_TAG_structure_type */ + + .uleb128 6 /* Abbrev: DW_TAG_subprogram */ + .ascii "main\0" /* DW_AT_name */ + ADDR main /* DW_AT_low_pc */ + ADDR main + 0x100 /* DW_AT_high_pc */ + .4byte .Ltype_int - d /* DW_AT_type */ + .byte 1 /* DW_AT_external */ + +.Ltype_structptr: + .uleb128 0x5 /* DW_TAG_pointer_type */ + .byte ADDR_SIZE /* DW_AT_byte_size */ + .4byte .Ltype_struct - d /* DW_AT_type */ + +.Lvar_out: + .uleb128 0x4 /* (DW_TAG_variable) */ + .ascii "v\0" /* DW_AT_name */ + .byte 2f - 1f /* DW_AT_location: DW_FORM_block1 */ +1: + .byte 0x9e /* DW_OP_implicit_value */ + .uleb128 2f - 3f +3: + .byte 1, 1, 1, 1 +2: + .4byte .Ltype_struct - d /* DW_AT_type */ + + .uleb128 0x4 /* (DW_TAG_variable) */ + .ascii "p\0" /* DW_AT_name */ + .byte 2f - 1f /* DW_AT_location: DW_FORM_block1 */ +1: + .byte 0xf2 /* DW_OP_GNU_implicit_pointer */ + REF_ADDR .Lvar_out - d /* referenced DIE */ + .sleb128 0 /* offset */ +2: + .4byte .Ltype_structptr - d /* DW_AT_type */ + + .byte 0x0 /* end of children of main */ + + .byte 0x0 /* end of children of CU */ +debug_end: + + .section .debug_abbrev +.Ldebug_abbrev0: + + .uleb128 0x1 /* (abbrev code) */ + .uleb128 0x11 /* (TAG: DW_TAG_compile_unit) */ + .byte 0x1 /* DW_children_yes */ + .uleb128 0x25 /* (DW_AT_producer) */ + .uleb128 0x8 /* (DW_FORM_string) */ + .uleb128 0x13 /* (DW_AT_language) */ + .uleb128 0xb /* (DW_FORM_data1) */ + .uleb128 0x3 /* (DW_AT_name) */ + .uleb128 0x8 /* (DW_FORM_string) */ + .byte 0x0 + .byte 0x0 + + .uleb128 0x2 /* (abbrev code) */ + .uleb128 0x13 /* (TAG: DW_TAG_structure_type) */ + .byte 0x1 /* DW_children_yes */ + .uleb128 0x3 /* (DW_AT_name) */ + .uleb128 0x8 /* (DW_FORM_string) */ + .uleb128 0xb /* (DW_AT_byte_size) */ + .uleb128 0xb /* (DW_FORM_data1) */ + .byte 0 + .byte 0 + + .uleb128 0x3 /* (abbrev code) */ + .uleb128 0xd /* (TAG: DW_TAG_member) */ + .byte 0 /* DW_children_no */ + .uleb128 0x3 /* (DW_AT_name) */ + .uleb128 0x8 /* (DW_FORM_string) */ + .uleb128 0x49 /* (DW_AT_type) */ + .uleb128 0x13 /* (DW_FORM_ref4) */ + .uleb128 0x38 /* (DW_AT_data_member_location) */ + .uleb128 0xb /* (DW_FORM_data1) */ + .byte 0 + .byte 0 + + .uleb128 0x4 /* (abbrev code) */ + .uleb128 0x34 /* (TAG: DW_TAG_variable) */ + .byte 0x0 /* DW_children_yes */ + .uleb128 0x3 /* (DW_AT_name) */ + .uleb128 0x8 /* (DW_FORM_string) */ + .uleb128 0x02 /* (DW_AT_location) */ + .uleb128 0xa /* (DW_FORM_block1) */ + .uleb128 0x49 /* (DW_AT_type) */ + .uleb128 0x13 /* (DW_FORM_ref4) */ + .byte 0x0 + .byte 0x0 + + .uleb128 0x5 /* (abbrev code) */ + .uleb128 0xf /* (TAG: DW_TAG_pointer_type) */ + .byte 0x0 /* DW_children_no */ + .uleb128 0xb /* (DW_AT_byte_size) */ + .uleb128 0xb /* (DW_FORM_data1) */ + .uleb128 0x49 /* (DW_AT_type) */ + .uleb128 0x13 /* (DW_FORM_ref4) */ + .byte 0x0 + .byte 0x0 + + .uleb128 6 /* Abbrev code */ + .uleb128 0x2e /* DW_TAG_subprogram */ + .byte 1 /* has_children */ + .uleb128 0x3 /* DW_AT_name */ + .uleb128 0x8 /* DW_FORM_string */ + .uleb128 0x11 /* DW_AT_low_pc */ + .uleb128 0x1 /* DW_FORM_addr */ + .uleb128 0x12 /* DW_AT_high_pc */ + .uleb128 0x1 /* DW_FORM_addr */ + .uleb128 0x49 /* DW_AT_type */ + .uleb128 0x13 /* DW_FORM_ref4 */ + .uleb128 0x3f /* DW_AT_external */ + .uleb128 0xc /* DW_FORM_flag */ + .byte 0x0 /* Terminator */ + .byte 0x0 /* Terminator */ + + .uleb128 0x7 /* (abbrev code) */ + .uleb128 0x24 /* (TAG: DW_TAG_base_type) */ + .byte 0 /* DW_children_no */ + .uleb128 0xb /* (DW_AT_byte_size) */ + .uleb128 0xb /* (DW_FORM_data1) */ + .uleb128 0x3e /* (DW_AT_encoding) */ + .uleb128 0xb /* (DW_FORM_data1) */ + .uleb128 0x3 /* (DW_AT_name) */ + .uleb128 0x8 /* (DW_FORM_string) */ + .byte 0 + .byte 0 + + .byte 0x0 --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/implptr-64bit.exp @@ -0,0 +1,51 @@ +# Copyright 2011 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 . +load_lib dwarf.exp + +# This test can only be run on targets which support DWARF-2 and use gas. +if {![dwarf2_support]} { + return 0 +} + +set testfile "implptr-64bit" +set srcfile ${testfile}.S +set mainfile main.c + +proc test { dwarf_version offset_size addr_size ref_addr_size } { + global testfile srcfile mainfile + + set opts {} + foreach n { dwarf_version offset_size addr_size ref_addr_size } { + lappend opts "additional_flags=-D[string toupper $n]=[expr "\$$n"]" + } + + set name "d${dwarf_version}o${offset_size}a${addr_size}r${ref_addr_size}" + set executable ${testfile}-${name} + if [prepare_for_testing ${testfile}.exp $executable "${srcfile} ${mainfile}" $opts] { + return -1 + } + + if ![runto_main] { + return -1 + } + + gdb_test "p/x p->f" " = 0x1010101" $name +} + +# DWARF_VERSION OFFSET_SIZE ADDR_SIZE REF_ADDR_SIZE +test 2 8 4 4 +test 2 4 8 8 +test 3 8 4 8 +test 3 4 8 4