Bug 15391 - DW_OP_GNU_implicit_pointer bug
Summary: DW_OP_GNU_implicit_pointer bug
Status: RESOLVED FIXED
Alias: None
Product: gdb
Classification: Unclassified
Component: symtab (show other bugs)
Version: HEAD
: P2 normal
Target Milestone: 7.7
Assignee: Tom Tromey
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2013-04-23 12:25 UTC by Jan Kratochvil
Modified: 2017-06-13 13:22 UTC (History)
1 user (show)

See Also:
Host:
Target: x86_64-unknown-linux-gnu
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jan Kratochvil 2013-04-23 12:25:30 UTC
struct S { short a; char b, c; };
volatile int v;
void foo (int x)
{
  struct S s = { x, x + 2, x + 3 };
  char *p = &s.b;
  s.a++;
  v++; /* line 8 */
}
int main ()
{
  foo (1);
  return 0;
}

gcc-4.8.0-2.fc19.x86_64
gcc -g -O2 -fno-inline -fno-ipa-cp -o implptr implptr.c -Wall

gdb ./implptr -ex 'b 8' -ex r -ex 'p p[-1]' -ex c -ex q -q

Actual:
$1 = 3 '\003'

Expected:
$1 = 0 '\000'

Bugreported by Jakub Jelinek.


Abbrev Number: 7 (DW_TAG_variable)
 DW_AT_name     : s  
 DW_AT_location : (DW_OP_breg5 (rdi): 1; DW_OP_stack_value; DW_OP_piece: 2; DW_OP_breg5 (rdi): 2; DW_OP_stack_value; DW_OP_piece: 1; DW_OP_breg5 (rdi): 3; DW_OP_stack_value; DW_OP_piece: 1)

Abbrev Number: 7 (DW_TAG_variable)
 DW_AT_name     : p  
 DW_AT_location : (DW_OP_GNU_implicit_pointer: <0x88> 2)
Comment 1 Sourceware Commits 2013-06-18 18:11:21 UTC
CVSROOT:	/cvs/src
Module name:	src
Changes by:	tromey@sourceware.org	2013-06-18 18:11:19

Modified files:
	gdb            : ChangeLog dwarf2loc.c utils.c utils.h 
	gdb/testsuite  : ChangeLog 
	gdb/testsuite/gdb.dwarf2: implptrconst.exp 
	gdb/testsuite/lib: dwarf.exp 
Added files:
	gdb/testsuite/gdb.dwarf2: implptrpiece.exp 

Log message:
	Fix PR symtab/15391
	
	PR symtab/15391 is a failure with the DW_OP_GNU_implicit_pointer
	feature.
	
	I tracked it down to a logic error in read_pieced_value.  The code
	truncates this_size_bits according to the type size and offset too
	early -- it should do it after taking bits_to_skip into account.
	
	This patch fixes the bug.
	
	While testing this, I also tripped across a latent bug because
	indirect_pieced_value does not sign-extend where needed.  This patch
	fixes this bug as well.
	
	Finally, Pedro pointed out that a previous version implemented sign
	extension incorrectly.  This version introduces a new gdb_sign_extend
	function for this.  A couple of notes on this function:
	
	* It has the gdb_ prefix to avoid clashes with various libraries that
	felt free to avoid proper namespacing.  There is a "sign_extend"
	function in a Tile GX header, in an SOM-related BFD header (and in
	sh64-tdep.c and as a macro in arm-wince-tdep.c, but those are
	ours...)
	
	* I looked at all the sign extensions in gdb and didn't see ones that
	I felt comfortable converting to use this function; in large part
	because I don't have a good way to test the conversion.
	
	Built and regtested on x86-64 Fedora 18.  New test cases included;
	this required a minor addition to the DWARF assembler.  Note that the
	DWARF CU made by implptrpiece.exp uses a funny pointer size in order
	to show the sign-extension bug on all platforms.
	
	* dwarf2loc.c (read_pieced_value): Truncate this_size_bits
	after taking bits_to_skip into account.  Sign extend byte_offset.
	* utils.h (gdb_sign_extend): Declare.
	* utils.c (gdb_sign_extend): New function.
	
	* gdb.dwarf2/implptrpiece.exp: New file.
	* gdb.dwarf2/implptrconst.exp (d): New variable.
	Print d.
	* lib/dwarf2.exp (Dwarf::_location): Handle DW_OP_piece.

Patches:
http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/ChangeLog.diff?cvsroot=src&r1=1.15708&r2=1.15709
http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/dwarf2loc.c.diff?cvsroot=src&r1=1.173&r2=1.174
http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/utils.c.diff?cvsroot=src&r1=1.300&r2=1.301
http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/utils.h.diff?cvsroot=src&r1=1.8&r2=1.9
http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/testsuite/ChangeLog.diff?cvsroot=src&r1=1.3696&r2=1.3697
http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/testsuite/gdb.dwarf2/implptrpiece.exp.diff?cvsroot=src&r1=NONE&r2=1.1
http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/testsuite/gdb.dwarf2/implptrconst.exp.diff?cvsroot=src&r1=1.3&r2=1.4
http://sourceware.org/cgi-bin/cvsweb.cgi/src/gdb/testsuite/lib/dwarf.exp.diff?cvsroot=src&r1=1.9&r2=1.10
Comment 2 Tom Tromey 2013-06-18 18:12:51 UTC
Fixed.
Comment 3 Sourceware Commits 2017-06-13 13:22:40 UTC
The master branch has been updated by Andreas Arnez <arnez@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=d5d1163eff2415a01895f1cff8bbee32b3f0ab66

commit d5d1163eff2415a01895f1cff8bbee32b3f0ab66
Author: Andreas Arnez <arnez@linux.vnet.ibm.com>
Date:   Tue Jun 13 15:20:26 2017 +0200

    write_pieced_value: Fix size capping logic
    
    A field f in a structure composed of DWARF pieces may be located in
    multiple pieces, where the first and last of those may contain bits from
    other fields as well.  So when writing to f, the beginning of the first
    and the end of the last of those pieces may have to be skipped.  But the
    logic in write_pieced_value for handling one of those pieces is flawed
    when the first and last piece are the same, i.e., f is contained in a
    single piece:
    
      < - - - - - - - - - piece_size - - - - - - - - - ->
      +-------------------------------------------------+
      | skipped_bits |   f_bits   | / / / / / / / / / / |
      +-------------------------------------------------+
    
    The current logic determines the size of the sub-piece to operate on by
    limiting the piece size to the bit size of f and then subtracting the
    skipped bits:
    
      min (piece_size, f_bits) - skipped_bits
    
    Instead of:
    
      min (piece_size - skipped_bits, f_bits)
    
    So the resulting sub-piece size is corrupted, leading to wrong handling of
    this piece in write_pieced_value.
    
    Note that the same bug was already found in read_pieced_value and fixed
    there (but not in write_pieced_value), see PR 15391.
    
    This patch swaps the calculations, bringing them into the same (correct)
    order as in read_pieced_value.
    
    gdb/ChangeLog:
    
    	* dwarf2loc.c (write_pieced_value): Fix order of calculations for
    	size capping.
    
    gdb/testsuite/ChangeLog:
    
    	* gdb.dwarf2/var-pieces.exp: Add test case for modifying a
    	variable at nonzero offset.