Re: Clang and call-clobbered location list entries
Simon Marchi <[email protected]>
| Newsgroups | gmane.comp.gdb.devel |
|---|---|
| Message-ID | <[email protected]> |
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