Bug 959422 - TLS variable wrongly relocated on .debug_info
Summary: TLS variable wrongly relocated on .debug_info
Status: CLOSED ERRATA
Alias: None
Product: Red Hat Enterprise Linux 6
Classification: Red Hat
Component: binutils
Version: 6.4
Hardware: s390x
OS: Linux
unspecified
unspecified
Target Milestone: rc
: ---
Assignee: Patsy Franklin
QA Contact: Miloš Prchlík
URL:
Whiteboard:
Keywords:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2013-05-03 12:38 UTC by Sergio Durigan Junior
Modified: 2014-10-14 04:40 UTC (History)
6 users (show)

(edit)
Cause: The linker incorrectly handled certain relocations appearing in debugging (dwarf) sections.

Consequence: Debugging information for some variables in TLS sections could be incorrect.

Fix: The linker now correctly handles TLS relocations appearing in debug sections.

Result: Debugging information for variables in TLS sections is correct, allowing those variables to be examined by debuggers and other tools.
Clone Of:
(edit)
Last Closed: 2014-10-14 04:40:42 UTC


Attachments (Terms of Use)


External Trackers
Tracker ID Priority Status Summary Last Updated
Red Hat Product Errata RHBA-2014:1414 normal SHIPPED_LIVE binutils bug fix update 2014-10-14 00:54:49 UTC

Description Sergio Durigan Junior 2013-05-03 12:38:18 UTC
Description of problem:

Consider the following test file:

#include <pthread.h>
__thread const char *tls_var = "hello";
int main ()
{
  return 0;
}

When you try to debug this on GDB, and print "tls_var", you get:

[root@ibm-z10-05 build-g3]# gcc -lpthread -g3 -O0 ld-fail.c -o ld-fail
[root@ibm-z10-05 build-g3]# gdb ./ld-fail -q -ex start -ex 'print tls_var'
Reading symbols from /root/sergiodj/src/build-g3/ld-fail...done.
Temporary breakpoint 1 at 0x8000057e: file ld-fail.c, line 5.
Starting program: /root/sergiodj/src/build-g3/ld-fail 
[Thread debugging using libthread_db enabled]

Temporary breakpoint 1, main () at ld-fail.c:5
5         return 0;
$1 = 0x0

However, when you modify the test file to:

#include <pthread.h>
__thread const char *tls_var = "hello";
int main ()
{
  const char *p = tls_var;
  return 0;
}

The debugging works:

[root@ibm-z10-05 build-g3]# gcc -lpthread -g3 -O0 ld-ok.c -o ld-ok
[root@ibm-z10-05 build-g3]# gdb ./ld-ok -q -ex start -ex 'print tls_var'
Reading symbols from /root/sergiodj/src/build-g3/ld-ok...done.
Temporary breakpoint 1 at 0x8000058a: file ld-ok.c, line 5.
Starting program: /root/sergiodj/src/build-g3/ld-ok 
[Thread debugging using libthread_db enabled]

Temporary breakpoint 1, main () at ld-ok.c:5
5         const char *p = tls_var;
$1 = 0x800006d8 "hello"

Jan Kratochvil and I did some investigation, and here is what has been found:

Using below this sample program to see more there the TLS offsets:

#include <pthread.h>
__thread const char *tls_var = "hello";
__thread const char *tls_var2 = "hello2";
__thread const char *tls_var3 = "hello3";
int main ()
{
  const char *p = tls_var;
  const char *p2 = tls_var2;
  int i = 10;
  const char *p3 = tls_var3;
  return 0;
}


So some investigations:

(1) It works without -g, just with .symtab:
    (gdb) p *(char **)&tls_var
    $1 = 0x80000728 "hello"

    .symtab really looks fine with all the cases I tried:
    70: 0000000000000000     8 TLS     GLOBAL DEFAULT   18 tls_var
    61: 0000000000000008     8 TLS     GLOBAL DEFAULT   18 tls_var2
    72: 0000000000000010     8 TLS     GLOBAL DEFAULT   18 tls_var3

    Wrong is only DWARF there:
     <1><173>: Abbrev Number: 8 (DW_TAG_variable)
         DW_AT_name        : tls_var
         DW_AT_location    : 10 byte block: 3 ff ff ff ff ff ff ff e8 e0    (DW_OP_addr: ffffffffffffffe8; DW_OP_GNU_push_tls_address)
     <1><18e>: Abbrev Number: 8 (DW_TAG_variable)
         DW_AT_name        : tls_var2
         DW_AT_location    : 10 byte block: 3 ff ff ff ff ff ff ff f0 e0    (DW_OP_addr: fffffffffffffff0; DW_OP_GNU_push_tls_address)
     <1><1aa>: Abbrev Number: 8 (DW_TAG_variable)
         DW_AT_name        : tls_var3
         DW_AT_location    : 10 byte block: 3 ff ff ff ff ff ff ff f8 e0    (DW_OP_addr: fffffffffffffff8; DW_OP_GNU_push_tls_address)


(2) Even with DWARF when I adjusted the offset GDB works then fine:
    linux-thread-db.c:
             So a 32-bit debugger can not access 64-bit TLS through this.  */
    offset-=0xffffffffffffffe8;
          err = info->td_thr_tls_get_addr_p (&thread_info->private->th,

The .S file looks somehow fine to me, as you wrote above:
>         .quad   tls_var@DTPOFF

In fact .o file also looks fine to me:
Relocation section '.rela.debug_info' at offset 0xfb8 contains 12 entries:
    Offset             Info             Type               Symbol's Value  Symbol's Name + Addend
0000000000000185  0000001200000035 R_390_TLS_LDO64        0000000000000000 tls_var + 0
00000000000001a1  0000001300000035 R_390_TLS_LDO64        0000000000000008 tls_var2 + 0
00000000000001bd  0000001400000035 R_390_TLS_LDO64        0000000000000010 tls_var3 + 0
Symbol table '.symtab' contains 22 entries:
   Num:    Value          Size Type    Bind   Vis      Ndx Name
    18: 0000000000000000     8 TLS     GLOBAL DEFAULT   12 tls_var
    19: 0000000000000008     8 TLS     GLOBAL DEFAULT   12 tls_var2
    20: 0000000000000010     8 TLS     GLOBAL DEFAULT   12 tls_var3

But the binary has wrongly relocated .debug_info.

Therefore the bug is in ld.

Version-Release number of selected component (if applicable):

binutils-2.20.51.0.2-5.36.el6.s390x

How reproducible:

Always.

Steps to Reproduce:

Described above.
  
Actual results:

TLS variable is not printed correctly due to wrongly relocated .debug_info.

Expected results:

TLS variable should be printed correctly.

Comment 4 errata-xmlrpc 2014-10-14 04:40:42 UTC
Since the problem described in this bug report should be
resolved in a recent advisory, it has been closed with a
resolution of ERRATA.

For information on the advisory, and where to find the updated
files, follow the link below.

If the solution does not work for you, open a new bug report.

http://rhn.redhat.com/errata/RHBA-2014-1414.html


Note You need to log in before you can comment on or make changes to this bug.