This is the mail archive of the gdb@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: Clang and call-clobbered location list entries


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,

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.

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.

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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]