Re: Clang and call-clobbered location list entries

"David Stenberg via gdb" <[email protected]>
Newsgroups gmane.comp.gdb.devel
Message-ID <[email protected]>
On Sun, 2019-10-13 at 20:20 -0400, Simon Marchi wrote:
> On 2019-10-09 08:34, David Stenberg wrote:
> > Hi!
> > 
> > Currently there is an incompatibility between Clang and GDB for
> > location list entries that are call-clobbered. Variables that are
> > expressed in terms of scratch registers may be printed using
> > incorrect
> > register values when standing in outer frames. Here is an x86-64
> > example:
> > 
> > main.c:
> > 
> >   1 extern int value(void);
> >   2 extern void call(int);
> >   3
> >   4 int main() {
> >   5   int local = value();
> >   6   call(local);
> >   7   return 0;
> >   8 }
> > 
> > callee.c:
> > 
> >   1 int value(void) {
> >   2   return 123;
> >   3 }
> >   4
> >   5 int call(int param) {
> >   6   // Thrash $eax.
> >   7   __asm volatile ("movl $999, %%eax" : : : "%eax");
> >   8   return 0;
> >   9 }
> > 
> > Compiled with Clang (I used 7.0 here, but it's the same on trunk):
> > 
> >   $ clang -O1 -g caller.c callee.c
> > 
> > will produce the following output when run in GDB (8.2.1):
> > 
> >   (gdb) b callee.c:8
> >   Breakpoint 1 at 0x201125: file callee.c, line 8.
> >   (gdb) run
> >   Starting program: /home/david/clang.out
> > 
> >   Breakpoint 1, call (param=123) at callee.c:8
> >   8	  return 0;
> >   (gdb) up
> >   #1  0x00000000002010fd in main () at main.c:6
> >   6	  call(local);
> >   (gdb) print local
> >   $1 = 999
> > 
> > As seen, local is printed with the incorrect value (999 rather than
> > 123).
> > 
> > If the file is compiled with GCC (8.3) the outer frame's variable
> > is
> > instead correctly printed as <optimized out>:
> > 
> >   (gdb) b callee.c:8
> >   Breakpoint 1 at 0x110a: file callee.c, line 8.
> >   (gdb) run
> >   Starting program: /home/david/gcc.out
> > 
> >   Breakpoint 1, call (param=123) at callee.c:8
> >   8	  return 0;
> >   (gdb) up
> >   #1  0x00005555555550f5 in main () at main.c:6
> >   6	  call(local);
> >   (gdb) print local
> >   $1 = <optimized out>
> > 
> > GCC emits a location list entry for `local' that ends one byte
> > inside
> > the call:
> > 
> >   (gdb) info addr local
> >   Symbol "local" is multi-location:
> >     Range 0x5555555550ee-0x5555555550f4: a variable in $rax
> >   .
> >   (gdb) disas main
> >   Dump of assembler code for function main:
> >   => 0x00005555555550e5 <+0>:	sub    $0x8,%rsp
> >      0x00005555555550e9 <+4>:	callq  0x5555555550ff <value>
> >      0x00005555555550ee <+9>:	mov    %eax,%edi
> >      0x00005555555550f0 <+11>:	callq  0x555555555105 <call>
> >      0x00005555555550f5 <+16>:	mov    $0x0,%eax
> >      0x00005555555550fa <+21>:	add    $0x8,%rsp
> >      0x00005555555550fe <+25>:	retq
> >   End of assembler dump.
> > 
> > whereas Clang emits a location list entry which covers the whole
> > call:
> > 
> >   (gdb) info addr local
> >   Symbol "local" is multi-location:
> >     Range 0x2010f6-0x2010fd: a variable in $rax
> >   .
> >   (gdb) disas main
> >   Dump of assembler code for function main:
> >      0x00000000002010f0 <+0>:	push   %rax
> >   => 0x00000000002010f1 <+1>:	callq  0x201110 <value>
> >      0x00000000002010f6 <+6>:	mov    %eax,%edi
> >      0x00000000002010f8 <+8>:	callq  0x201120 <call>
> >      0x00000000002010fd <+13>:	xor    %eax,%eax
> >      0x00000000002010ff <+15>:	pop    %rcx
> >      0x0000000000201100 <+16>:	retq
> >   End of assembler dump.
> > 
> > As I've understood it, GCC emits such location list entry ranges
> > since
> > it knows that when performing virtual unwinding, GDB (and other
> > consumers) will subtract one byte from the return address in order
> > to
> > get the right scope for the call. Utilizing that fact allows for
> > `local' to be printable before executing the call, but not when
> > unwinding back to the frame during the call. In the case of Clang,
> > the
> > location list entry covers the whole call, and the variable is thus
> > printed with the register's unwound value, which is considered the
> > same
> > since there is no CFI that says otherwise.
> > 
> > I'm trying to figure out how to solve this incompatibility between
> > Clang and GDB.
> > 
> > I sent a mail to the dwarf-discuss mailing list about GCC's
> > behavior at
> > the end of last year [0]. I got some push-back, with some comments
> > that the consumer should know which registers are preserved and
> > which
> > are not.
> > 
> > LLDB is aware of which registers are preserved in the ABI, and
> > other
> > registers are considered undefined when unwinding, meaning that the
> > same issue is not seen when debugging Clang-built binaries in LLDB.
> > 
> > Unless I have misunderstood something, it appears that the same is
> > done for some targets in GDB (e.g. rs6000 and s390), by setting the
> > frame register rule to DWARF2_FRAME_REG_UNDEFINED for the scratch
> > registers in {target}_dwarf2_frame_init_reg(). Is that correct, or
> > have I misunderstood what that function does? If that is correct,
> > would you be open to such information being added to other targets,
> > or are there some reasons for not wanting that? (Personally I'm
> > mostly interested in 32- and 64-bit x86.)
> > 
> > Best regards,
> > David
> > 
> > [0]
> > 
http://lists.dwarfstd.org/pipermail/dwarf-discuss-dwarfstd.org/2018-December/004500.html
> > 
> 
> Hi David,

Hi Simon,

Thanks for the reply!

> Personally, I don't really see any problem teaching GDB which
> registers 
> are caller-saved or callee-saved the way you are describing.  I
> think 
> it's natural for debuggers to have such knowledge about the
> ABIs.  GDB 
> already has a ton of knowledge about all the ABIs it supports, for 
> example how to make function calls.
> Of course, doing the change and running the testsuite might reveal
> some 
> problem, we just have to try.

Should I perhaps write a Bugzilla ticket to help keep track of this?

Would it be fine to, at least as an initial step, introduce such
knowledge for some, but not all, of an architecture's ABIs? For example
only add register knowledge for the AMD64 System V ABI, but not for
Windows?

> Perhaps others would know better than me if this has been discussed
> at 
> some point in the past, and if there are reasons for GDB to do what
> it 
> does now.

Yes, that would be interesting to know.

> I don't really expect that clang will change its behavior to match
> gcc, 
> since they are doing something valid and it works for the clang +
> lldb 
> combo.
> 
> Simon

Best regards,
David
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.