[Bug debug/108996] Proposal for adding DWARF call site information in GCC with -O0
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108996 Richard Biener changed: What|Removed |Added Last reconfirmed||2023-03-03 Ever confirmed|0 |1 Status|UNCONFIRMED |NEW CC||aoliva at gcc dot gnu.org, ||jakub at gcc dot gnu.org Severity|normal |enhancement Version|unknown |13.0 --- Comment #1 from Richard Biener --- It might be possible to run a reduced dataflow var-tracking at -O0 for this kind of things (the target could provide a set of interesting entry/exit parameters/registers to track). For other targets the biggest issue is when debugging the prologue code. I'm not sure how easy it would be to run var-tracking for a subset of insns/regs and how to then make use of such partial information when outputting DWARF. Alex/Jakub might have some ideas.
[Bug debug/108996] Proposal for adding DWARF call site information in GCC with -O0
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108996 --- Comment #2 from Jakub Jelinek --- I think there are several open PRs about var-tracking at -O0, which would be nice e.g. for VLAs. The main problem is that var-tracking is very expensive, so if we do it, it should track a very small subset of what is normally tracked (say primarily register vars (i.e. what doesn't live at -O0 in memory) and expressions before they are fully initialized and stored into their memory slots. Regarding the call sites, I guess we could get at least some arguments there by just scanning a few instructions before each call rather than actually tracking the values, say on x86_64 the f2 call is: (insn 33 6 8 2 (set (reg:DI 0 ax [84]) (plus:DI (reg/f:DI 6 bp) (const_int -12 [0xfff4]))) "pr108996.C":31:22 241 {*leadi} (nil)) (insn 8 33 9 2 (set (reg:SI 1 dx [85]) (mem/c:SI (plus:DI (reg/f:DI 6 bp) (const_int -8 [0xfff8])) [4 i2+0 S4 A64])) "pr108996.C":31:22 83 {*movsi_internal} (nil)) (insn 9 8 11 2 (set (reg:SI 2 cx [86]) (mem/c:SI (plus:DI (reg/f:DI 6 bp) (const_int -4 [0xfffc])) [4 i1+0 S4 A32])) "pr108996.C":31:22 83 {*movsi_internal} (nil)) (insn 11 9 12 2 (set (reg:SI 4 si) (reg:SI 2 cx [86])) "pr108996.C":31:22 83 {*movsi_internal} (nil)) (insn 12 11 13 2 (set (reg:DI 5 di) (reg:DI 0 ax [84])) "pr108996.C":31:22 82 {*movdi_internal} (nil)) (call_insn 13 12 14 2 (call (mem:QI (symbol_ref:DI ("_Z2f2ii") [flags 0x3] ) [0 f2 S1 A8]) (const_int 0 [0])) "pr108996.C":31:22 1003 {*call} (expr_list:REG_EH_REGION (const_int 0 [0]) (nil)) (expr_list:DI (use (reg:DI 5 di)) (expr_list:SI (use (reg:SI 4 si)) (expr_list:SI (use (reg:SI 1 dx)) (nil) aka leaq-12(%rbp), %rax movl-8(%rbp), %edx movl-4(%rbp), %ecx movl%ecx, %esi movq%rax, %rdi call_Z2f2ii so we could from just scanning the above sequence determine that first argument is &[bp - 12], second argument [bp - 4] and third [bp - 8]. Of course using DW_OP_entry_value in DWARF expressions would be much harder. But, on the other side, the r3 in the powerpc case (aka &b) is spilled in the f2's prologue like other parameters, and e.g. debug info for the b return value says that correctly: mflr 0 std 0,16(1) std 31,-8(1) stdu 1,-64(1) mr 31,1 std 3,32(31) ^^^ above and .byte 0x1 # uleb128 0x1; (DIE (0xcc) DW_TAG_variable) .ascii "b\0" # DW_AT_name # DW_AT_decl_file (1, pr108996.C) .byte 0x1f # DW_AT_decl_line .byte 0x8 # DW_AT_decl_column .4byte 0x2a # DW_AT_type .byte 0x2 # uleb128 0x2; DW_AT_location .byte 0x91 # DW_OP_fbreg .byte 0x68 # sleb128 -24 Like everywhere else, the debug info at -O0 isn't accurate before the corresponding memory slot is initialized, in this case in the first 5 instructions of the function. But otherwise it is there. Except that DWARF doesn't say that b is the return value...
[Bug debug/108996] Proposal for adding DWARF call site information in GCC with -O0
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108996 --- Comment #3 from Jakub Jelinek --- What is done on other arches? I mean the situation is basically the same on x86_64, where the artificial return value pointer argument is spilled early, then clobbered on calls and again b debug info is correct after the spill: pushq %rbp movq%rsp, %rbp subq$16, %rsp movq%rdi, -8(%rbp) movl%esi, -12(%rbp) movl%edx, -16(%rbp) movq-8(%rbp), %rax movq%rax, %rdi call_ZN1BC1Ev movl-12(%rbp), %edx movl-16(%rbp), %eax addl%eax, %edx movq-8(%rbp), %rax movl%edx, (%rax) nop movq-8(%rbp), %rax leave ret ... .byte 0x1 # uleb128 0x1; (DIE (0xcc) DW_TAG_variable) .ascii "b\0"# DW_AT_name # DW_AT_decl_file (1, pr108996.C) .byte 0x1f# DW_AT_decl_line .byte 0x8 # DW_AT_decl_column .long 0x2a# DW_AT_type .byte 0x2 # uleb128 0x2; DW_AT_location .byte 0x91# DW_OP_fbreg .byte 0x64# sleb128 -28
[Bug debug/108996] Proposal for adding DWARF call site information in GCC with -O0
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108996 --- Comment #4 from Ulrich Weigand --- (In reply to Jakub Jelinek from comment #3) > What is done on other arches? That depends on the platform ABI. On some arches, including x86/x86_64 and arm/aarch64, the ABI requires the generated code reloads the return buffer pointer into a defined register at function exit (either the same it was in on function entry, or some other ABI-defined register). On those arches, GDB can at least inspect the return value at the point the function return happens. On a few arches, in particular SPARC and RISC-V, the ABI even guarantees that the return buffer pointer register remains valid throughout execution of the function, so that GDB can inspect and/or modify the return value at any point. But on most other arches, including s390x and ppc/ppc64, the ABI does not guarantee anything, so GDB simply cannot access the function return value at all (after the point the return buffer pointer register is no longer needed by generated code and the register has been reused). However, *if* the debug info contains an entry-value record for that register at the call site in the current caller, then the return buffer can be accessed at any time, on all arches. Given that in this specific case, most callers will actually just point the return buffer register to a local stack buffer (i.e. set the register to "stack pointer plus some constant"), generating an entry-value record for these special cases should actually be quite straightforward for the compiler, without requiring a lot of value-tracking machinery.
[Bug debug/108996] Proposal for adding DWARF call site information in GCC with -O0
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108996 Jakub Jelinek changed: What|Removed |Added CC||mark at gcc dot gnu.org --- Comment #5 from Jakub Jelinek --- (In reply to Ulrich Weigand from comment #4) > (In reply to Jakub Jelinek from comment #3) > > What is done on other arches? > > That depends on the platform ABI. On some arches, including x86/x86_64 and Ah, you're right here, such functions effectively return that invisible return address pointer on x86. Though, relying on DW_OP_entry_value is not reliable, if e.g. tail calls are (or could be) involved, then GDB needs to punt. So, I wonder if we just shouldn't ask for a DWARF 6 extension here, have some way for the compiler to specify DW_AT_location for the return value. Then for -O1+ -g with var-tracking that address could be for PowerPC r3 register in such functions or wherever its initial value is tracked (including DW_OP_entry_value). While for -O0, we'd see we've spilled that parameter to stack and would set DW_AT_location to that place spilled on the stack.
[Bug debug/108996] Proposal for adding DWARF call site information in GCC with -O0
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108996 --- Comment #6 from Mark Wielaard --- (In reply to Jakub Jelinek from comment #5) > So, I wonder if we just shouldn't ask for a DWARF 6 extension here, have > some way for the compiler to specify DW_AT_location for the return value. There is https://dwarfstd.org/ShowIssue.php?issue=221105.1 "Add a mechanism for specifying subprogram return value locations"
[Bug debug/108996] Proposal for adding DWARF call site information in GCC with -O0
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108996 --- Comment #7 from Andrew Pinski --- (In reply to Ulrich Weigand from comment #4) > (In reply to Jakub Jelinek from comment #3) > > What is done on other arches? > > That depends on the platform ABI. On some arches, including x86/x86_64 and > arm/aarch64, the ABI requires the generated code reloads the return buffer > pointer into a defined register at function exit (either the same it was in > on function entry, or some other ABI-defined register). On those arches, > GDB can at least inspect the return value at the point the function return > happens. aarch64 does not require that. GCC produces it yes but that is a missed optimization, see PR 103010 which I filed against GCC for that case.
[Bug debug/108996] Proposal for adding DWARF call site information in GCC with -O0
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108996 --- Comment #8 from Ulrich Weigand --- (In reply to Jakub Jelinek from comment #5) > Though, relying on DW_OP_entry_value is not reliable, if e.g. tail calls are > (or could be) involved, then GDB needs to punt. The only way a tail call could happen is if the return value is passed through directly to the (caller's) caller, so the return buffer address should still be correct, right? > So, I wonder if we just shouldn't ask for a DWARF 6 extension here, have > some way for the compiler to specify DW_AT_location for the return value. > Then for -O1+ -g with var-tracking that address could be for PowerPC r3 > register in such functions or wherever its initial value is tracked > (including DW_OP_entry_value). > While for -O0, we'd see we've spilled that parameter to stack and would set > DW_AT_location to that place spilled on the stack. I don't think it is possible to track the value in the callee - the value may not be available *anywhere* because it is no longer needed. (Also, I don't think the implicit return buffer address is guaranteed to be spilled to the stack even at -O0.)
[Bug debug/108996] Proposal for adding DWARF call site information in GCC with -O0
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108996 --- Comment #9 from Ulrich Weigand --- (In reply to Andrew Pinski from comment #7) > (In reply to Ulrich Weigand from comment #4) > > (In reply to Jakub Jelinek from comment #3) > > > What is done on other arches? > > > > That depends on the platform ABI. On some arches, including x86/x86_64 and > > arm/aarch64, the ABI requires the generated code reloads the return buffer > > pointer into a defined register at function exit (either the same it was in > > on function entry, or some other ABI-defined register). On those arches, > > GDB can at least inspect the return value at the point the function return > > happens. > > aarch64 does not require that. GCC produces it yes but that is a missed > optimization, see PR 103010 which I filed against GCC for that case. Well, I was looking at GDB code that at least *assumes* that the aarch64 ABI does require that: https://sourceware.org/git/?p=binutils-gdb.git;a=blob;f=gdb/aarch64-tdep.c;h=5b1b9921f87e588f8251a77d858f8f312be1e5ac;hb=HEAD#l2500 If this is incorrect, I guess GDB would have to be fixed.
[Bug debug/108996] Proposal for adding DWARF call site information in GCC with -O0
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108996 --- Comment #10 from Jakub Jelinek --- (In reply to Ulrich Weigand from comment #8) > (In reply to Jakub Jelinek from comment #5) > > Though, relying on DW_OP_entry_value is not reliable, if e.g. tail calls are > > (or could be) involved, then GDB needs to punt. > > The only way a tail call could happen is if the return value is > passed through directly to the (caller's) caller, so the return > buffer address should still be correct, right? If there is just a single possible tail call, I think GDB still handles it, so that would be ok. But if you have multiple possible tail calls, I think GDB for DW_OP_entry_value evaluation punts (at least should, because it doesn't know which sequence of calls has been taken). > I don't think it is possible to track the value in the callee - the value > may not be available *anywhere* because it is no longer needed. (Also, I > don't think the implicit return buffer address is guaranteed to be spilled > to the stack even at -O0.) Well, at -O0 we can certainly guarantee it is available somewhere, even if we currently don't do it already (it would surprise me if it is not spilled).