Re: Suspected bug in DW_OP_addr handling

Simon Marchi via Gdb <[email protected]>
Newsgroups gmane.comp.gdb.devel
Message-ID <[email protected]>

On 2022-05-06 23:54, Yichao Yu via Gdb wrote:
> I noticed that gdb unwind failed with read of invalid memory address
> when I used `DW_OP_addr` in my unwind info. Upon checking, it seems
> that the handling of this operation in the dwarf interpreter is very
> suspicious.
> 
> The interpreter for the op code has a comment[1] sayijng,
> 
>> Some versions of GCC emit DW_OP_addr before
>> DW_OP_GNU_push_tls_address. In this case the value is an
>> index, not an address.
> 
> However, the code appears to check for exactly the opposite condition
> `op_ptr >= op_end || *op_ptr != DW_OP_GNU_push_tls_address` to decide
> whether the result should be used as index. This was added 12 years
> ago in commit ac56253ddece [2].
> 
> Am I missing something or is this a long-standing bug?

My understanding is:

 - normally, a value given by DW_OP_addr is an address that should be
   relocated with the base address of the objfile
 - the DW_OP_GNU_push_tls_address operation (now called
   DW_OP_form_tls_address in DWARF 5) expects some kind of value on top
   of the stack, identifying the TLS variable to fetch.  It's
   implementation-defined what this value means, but in practice it
   means it's some value that should not be relocated.
 - a contemporary version of GCC produces something like this for a TLS
   variable's DW_AT_location:

     DW_OP_const8u 0x4, DW_OP_form_tls_address

 - A version of gcc in the past must have used this instead:

     DW_OP_addr 0x4, DW_OP_form_tls_address

The usage of DW_OP_addr was wrong, and it made so GDB had to avoid
relocating the DW_OP_addr value in this particular case.  So it is
checking, if we have DW_OP_addr followed by DW_OP_form_tls_address, then
we don't relocate, because we are in this buggy situation.

And so the condition:

	  if (op_ptr >= op_end || *op_ptr != DW_OP_GNU_push_tls_address)
	    result += this->m_per_objfile->objfile->text_section_offset ();

looks right to me.  It says, only relocate if:

 - DW_OP_addr is the last operation of the sequence
 - the following op is not DW_OP_form_tls_address / DW_OP_GNU_push_tls_address

Simon
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.