Bug 99480 - glibc contains invalid DWARF frames
Summary: glibc contains invalid DWARF frames
Status: RESOLVED FIXED
Alias: None
Product: SUSE LINUX 10.0
Classification: openSUSE
Component: Basesystem (show other bugs)
Version: Stable Snapshot 2
Hardware: i686 All
: P5 - None : Normal
Target Milestone: ---
Assignee: Andreas Schwab
QA Contact: E-mail List
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-07-29 15:40 UTC by Michael Matz
Modified: 2007-06-05 12:39 UTC (History)
1 user (show)

See Also:
Found By: Other
Services Priority:
Business Priority:
Blocker: ---
Marketing QA Status: ---
IT Deployment: ---


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Michael Matz 2005-07-29 15:40:10 UTC
Do this: 
% readelf -wf /lib/tls/libpthread.so.0 > /dev/null 
readelf: Warning: unsupported or unknown DW_CFA_50 
readelf: Warning: unsupported or unknown DW_CFA_50 
 
This also happens on 9.3 already (I haven't tested back earlier).  This 
currently confuses valgrind 3.0 's dwarf reader on SuSE Linux, making it 
work suboptimally. 
 
Same happens when looking at /lib/tls/libc.so.6 .  The problem is in the fsync 
and close syscalls.  I created a buildsystem for STABLE, and looked at the 
.os files: 
 
% readelf -wf cc-nptl/misc/fsync.os 
The section .eh_frame contains: 
 
00000000 00000014 00000000 CIE 
  Version:               1 
  Augmentation:          "zR" 
  Code alignment factor: 1 
  Data alignment factor: -4 
  Return address column: 8 
  Augmentation data:     1b 
 
  DW_CFA_def_cfa: r4 ofs 4 
  DW_CFA_offset: r8 at cfa-4 
  DW_CFA_nop 
  DW_CFA_nop 
 
00000018 00000020 0000001c FDE cie=00000000 pc=00000000..00000065 
  DW_CFA_advance_loc: 12 to 0000000c 
  DW_CFA_register: r3 in r2 
  DW_CFA_advance_loc: 13 to 00000019 
  DW_CFA_restore: r3 
  DW_CFA_advance_loc: 31 to 00000038 
  DW_CFA_def_cfa_offset: 8 
readelf: Warning: unsupported or unknown DW_CFA_50 
 
(same for cc-nptl/io/close.os).  The problem is how NPTL syscalls with 1 
argument are constructed, for which no arch specific one exists.  E.g. 
the fsync syscall is constructed by feeding GCC with this on stdin: 
------------------------------------------ 
#include <sysdep-cancel.h> 
PSEUDO (__libc_fsync, fsync, 1) 
 ret 
PSEUDO_END(__libc_fsync) 
libc_hidden_def (__libc_fsync) 
weak_alias (__libc_fsync, fsync) 
libc_hidden_weak (fsync) 
------------------------------------------ 
 
This expands directly to assembler, parts of it are: 
 
__libc_fsync: .L__libc_fsyncSTART: cmpl $0, %gs:12 
 jne .Lpseudo_cancel 
 .type __fsync_nocancel,@function 
 .globl __fsync_nocancel 
 __fsync_nocancel: movl %ebx, %edx 
 .LSAVEBX1: movl 4(%esp), %ebx 
 movl $118, %eax 
 int $0x80 
 movl %edx, %ebx 
 .LRESTBX1: 
 cmpl $-4095, %eax 
 jae 0f 
 ret 
 .size __fsync_nocancel,.-__fsync_nocancel 
 .Lpseudo_cancel: call __libc_enable_asynccancel 
 movl %eax, %ecx 
 movl %ebx, %edx 
 .LSAVEBX2: movl 4(%esp), %ebx 
 movl $118, %eax 
 int $0x80 
 
 movl %edx, %ebx 
 .LRESTBX2: 
 pushl %eax 
 .LPUSHSTATE: movl %ecx, %eax 
 call __libc_disable_asynccancel 
 popl %eax 
 .LPOPSTATE: cmpl $-4095, %eax 
 jae 0f 
 .Lpseudo_end: 
 
.... 
 
.section .eh_frame,"a",@progbits 
.... 
 .LSTARTFDE: .long .LSTARTFDE-.LSTARTFRAME 
 .long .L__libc_fsyncSTART-. 
 .long .L__libc_fsyncEND-.L__libc_fsyncSTART 
 .uleb128 0 
 .byte 0x40+.LSAVEBX1-.L__libc_fsyncSTART 
 .byte 9 
 .uleb128 3 
 .uleb128 2 
 .byte 0x40+.LRESTBX1-.LSAVEBX1 
 .byte 0xc3 
 .byte 0x40+.LPUSHSTATE-.LRESTBX1 
 .byte 14 
 .uleb128 8 
 .byte 0x40+.LSAVEBX2-.LPUSHSTATE  <<<<<<<<<<<< here 
 .byte 9 
 .uleb128 3 
 .uleb128 2 
 .byte 0x40+.LRESTBX2-.LSAVEBX2 
 .byte 0xc3 
 .byte 0x40+.LPOPSTATE-.LRESTBX2 
 .byte 14 
 .uleb128 4 
 .align 4 
 .LENDFDE: 
 
On the marked line the difference .LSAVEBX2-.LPUSHSTATE is used, but 
.LSAVEBX2 is in front of .LPUSHSTATE, hence it is negative, and in our 
case results in 0x32 overall, i.e. our 50 readelf complains about. 
 
I looked a bit at nptl/sysdeps/unix/sysv/linux/i386/sysdep-cancel.h . 
The body of the syscalls is this: 
  L(pseudo_cancel): 
    CENABLE 
    SAVE_OLDTYPE_##args 
    PUSHCARGS_##args 
    DOCARGS_##args 
    movl $SYS_ify (syscall_name), %eax; 
    ENTER_KERNEL; 
    POPCARGS_##args; 
    POPSTATE_##args 
    cmpl $-4095, %eax; 
    jae SYSCALL_ERROR_LABEL; 
  L(pseudo_end): 
 
Now look at some more macros: 
# define SAVE_OLDTYPE_0 movl %eax, %ecx; 
# define SAVE_OLDTYPE_1 SAVE_OLDTYPE_0 
# define SAVE_OLDTYPE_2 pushl %eax; L(PUSHSTATE): 
 
# define POPSTATE_0 \ 
 pushl %eax; L(PUSHSTATE): movl %ecx, %eax; CDISABLE; popl %eax; L(POPSTATE): 
# define POPSTATE_1     POPSTATE_0 
# define POPSTATE_2     xchgl (%esp), %eax; CDISABLE; popl %eax; L(POPSTATE): 
 
Look at how with 2 or more args .LPUSHSTATE is set before the PUSHCARGS macro 
(which contains the .LSAVEBX2 label for instance, for all args).  But 
with 0 and 1 argument this label is set by POPSTATE, hence after the use 
of the PUSHCARGS macro.  For 0 arguments this doesn't matter it seems, 
as the macro setting up eh_frame for 0 args doesn't refer to .LSAVEBX2. 
 
But EH_FRAME_1 has this expression: 
    .byte 0x40+L(SAVEBX2)-L(PUSHSTATE);         /* DW_CFA_advance_loc+N */ 
hence it needs SAVEBX2 _after_ PUSHSTATE, but that's only the case for 
2 or more args. 
 
So something must be changed, I'm just not sure what.  If someone from the 
glibc maintainers could look at this, it would be nice.
Comment 1 Andreas Schwab 2005-07-29 15:56:14 UTC
The right way to fix this is to use the CFI directives of the assembler as
it is already done in HEAD.  Probably just copying sysdep-cancel.h from
HEAD will do.
Comment 2 Andreas Jaeger 2005-07-31 13:41:44 UTC
I cannot reproduce this with preview3, I get no output at all:
aj@x40:~> readelf -wf /lib/tls/libpthread.so.0 > /dev/null
aj@x40:~> readelf -wf /lib/tls/libc.so.6 > /dev/null

Could you double check preview3, please?
Comment 3 Michael Matz 2005-07-31 21:07:09 UTC
Are you sure?  I just tried again in a buildsystem of STABLE (i386) and can reproduce 
just fine.  I don't have preview3 immediately ready, but can't think of reasons why it 
should behave differently than STABLE in this regard.  But will try tomorrow. 
Comment 4 Michael Matz 2005-08-01 07:35:09 UTC
Andreas S.: yes, it seems to work when I use the CVS sysdep-cancel.h, 
and look at fsync.S.  I need this patch additionally: 
 
--- sysdeps/i386/sysdep.h       2005-08-01 07:30:55.633685071 +0000 
+++ sysdeps/i386/sysdep.h.mm    2005-08-01 07:28:53.095269000 +0000 
@@ -57,10 +57,12 @@ 
   .align ALIGNARG(4);                                                       \ 
   STABS_FUN(name)                                                           \ 
   C_LABEL(name)                                                             \ 
+  cfi_startproc;                                                            \ 
   CALL_MCOUNT 
 
 #undef END 
 #define END(name)                                                           \ 
+  cfi_endproc;                                                              \ 
   ASM_SIZE_DIRECTIVE(name)                                                  \ 
   STABS_FUN_END(name) 
 
I have not completely built glibc with these changes.  Can someone please 
try this and submit it?  From the ChangeLog I read that adding the 
cfi_startproc and cfi_endproc to i386/sysdep.h might need other changes 
in different files too, but I don't have time to look at this. 
Comment 6 Andreas Jaeger 2005-08-01 09:53:13 UTC
Andreas, could you take it, please?
Comment 7 Andreas Schwab 2005-08-01 22:37:29 UTC
Fixed.