[Dwarf-Discuss] Location list entries for caller-saved registers at time of call

Michael Eager eager at eagerm.com
Fri Dec 7 07:56:30 PST 2018


On 12/07/2018 04:36 AM, David Stenberg wrote:
> On tor, 2018-12-06 at 17:47 -0800, Cary Coutant via Dwarf-Discuss
> wrote:
>> But we're getting sidetracked from the OP's question: Does GCC in
>> fact
>> subtract one from the upper bound of a location list entry for a
>> variable contained in a caller-saved register? I can think of no
>> reason why it should do this. If the compiled code does something
>> like
>> this:
>>
>>      A: promote variable X into caller-save register R
>>         ...
>>         call f
>>      B: ...
>>         spill register R back to X
>>      C: ...
>>
>> The location list entry for x should show it live in register R in
>> the
>> range [A..C). The call should not interrupt the range.
>>
>> It sounds like David has an example where the range list entry shows
>> x
>> in register R in the range [A..B-1), then presumably again for
>> [B..C),
>> leaving [B-1..B) uncovered. That would be a bug, in my opinion.
>>
>> David, can you show us an example?
> 
> In the following example I used GCC 7.3.0, and compiled the below
> listed C code using `-O1 -gstrict-dwarf -gdwarf-5'.
> 
>    extern int get();
>    extern void set(int);
>    
>    int main() {
>      int local = get();
>      set(local);
>      local = 123;
>      return local;
>    }
> 
> This produces the following location list for `local':
> 
>      0000000c 000000000000000e 0000000000000014 (DW_OP_reg0 (rax))
>      00000011 0000000000000015 000000000000001f (DW_OP_const1u: 123;
>                                                  DW_OP_stack_value)
> 
>     9:   e8 00 00 00 00          callq  e <main+0xe>
>     e:   89 c7                   mov    %eax,%edi
>    10:   e8 00 00 00 00          callq  15 <main+0x15>
>    15:   b8 7b 00 00 00          mov    $0x7b,%eax
> 
> As seen, there is a one-byte gap at the end of the call instruction to
> set().
> 
> As far as I have understood it, GCC emits a location list like this
> because it knows that the producer will subtract one from the return
> address when doing virtual unwinding. In this way, GDB will print the
> variable as "<optimized out>" when unwinding from set() to main(), even
> though it does not have knowledge of whether or not RAX is caller-
> saved.

Speaking generally, a producer should describe the code generated and
nothing more.  It should not attempt to anticipate or compensate for the
behavior of a consumer.  That leads to bugs in the consumer causing
bugs in the producer.  The reverse is true, naturally, but consumers
often have to adapt to odd (or buggy) producers.

It looks to me that the loclist should be [0xe, 0x15), not as generated.
When the PC is anywhere in the range from 0xe up to but not including
0x15, rax is in reg0.

> If we instead use Clang, there is no gap in the location list for the
> same code:
> 
>      [0x0000000000000008, 0x000000000000000f): DW_OP_reg0 RAX
>      [0x000000000000000f, 0x0000000000000016): DW_OP_consts +123,
>                                                DW_OP_stack_value)
> 
>     3:   e8 00 00 00 00          callq  8 <main+0x8>
>     8:   89 c7                   mov    %eax,%edi
>     a:   e8 00 00 00 00          callq  f <main+0xf>
>     f:   b8 7b 00 00 00          mov    $0x7b,%eax
> 
> When debugging the Clang-built binary in GDB, when unwinding from set()
> to main(), `local' will be evaluated using the value RAX has in set(),
> rather then being printed as "<optimized out>".
> 
> Best regards,
> David
> 

-- 
Michael Eager    eager at eagerm.com
1960 Park Blvd., Palo Alto, CA 94306


More information about the Dwarf-Discuss mailing list