Bug 19356 - unwind stack failed if stack including syscall on armv7
Summary: unwind stack failed if stack including syscall on armv7
Status: NEW
Alias: None
Product: glibc
Classification: Unclassified
Component: libc (show other bugs)
Version: 2.20
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2015-12-11 11:08 UTC by Guonic
Modified: 2015-12-15 02:26 UTC (History)
2 users (show)

See Also:
Host: linux
Target: arm-linux-gnueabi
Build:
Last reconfirmed:
fweimer: security-


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Guonic 2015-12-11 11:08:09 UTC
Scenario:
using libunwind in a signal handler to output backtrace, always failed if backtrace including syscall function.
Wrong Backtrace:
   1 ip:0xb6443990 sp:0xbe9c38a8 /usr/lib/libc-2.20.so(syscall + 32)                                                  
   2 ip:0xb6e9d0af sp:0xbe9c38a8 /usr/lib/libuv.so.11.0.0(uv__epoll_wait + 22)                                        
   3 ip:0xb6e9d2f8 sp:0xbe9c38c0 /usr/lib/libuv.so.11.0.0(__aeabi_uldivmod + 44)  

Right Backtrace:
   1 ip:0xb63d7990 sp:0xbeab48a8 /usr/lib/libc-2.20.so(syscall + 32) 
   2 ip:0xb6e310af sp:0xbeab48b8 /usr/lib/libuv.so.11.0.0(uv__epoll_wait + 22) 
   3 ip:0xb6e300a7 sp:0xbeab48d0 /usr/lib/libuv.so.11.0.0(uv__io_poll + 266)
   4 ip:0xb6e285a1 sp:0xbeab8918 /usr/lib/libuv.so.11.0.0(uv_run + 144)
   5 ip:0xb66af495 sp:0xbeab8950 /usr/lib/libbase.so.1.0.0(yunos::Looper::run() + 72) 
   6 ip:0xb6e8dd9b sp:0xbeab8960 /usr/lib/libnode.so(node::Start(int, char**) + 1050)
   7 ip:0xb631d6d4 sp:0xbeab8ae8 /usr/lib/libc-2.20.so(__libc_start_main + 276)
   8 ip:0x10800 sp:0xbeab8c28 /usr/bin/node(_start + 44) 

After investigate with syscall & unwind info with readelf/objdump, the root cause is wrong unwind info provided from libc-2.20.so


Dissembled code of syscall:

000d1948 <setlogmask>:                                                                                                
   d1948:       e59f3010        ldr     r3, [pc, #16]   ; d1960 <setlogmask+0x18>                                     
   d194c:       e2502000        subs    r2, r0, #0                                                                    
   d1950:       e08f3003        add     r3, pc, r3                                                                    
   d1954:       e593000c        ldr     r0, [r3, #12]                                                                 
   d1958:       1583200c        strne   r2, [r3, #12]                                                                 
   d195c:       e12fff1e        bx      lr                                                                            
   d1960:       00078950        andeq   r8, r7, r0, asr r9                                                            
        ...                                                                                                           
                                                                                                                      
000d1970 <syscall>:                                                                                                   
   d1970:       e1a0c00d        mov     ip, sp                                                                        
   d1974:       e92d00f0        push    {r4, r5, r6, r7}                                                              
   d1978:       e1a07000        mov     r7, r0                                                                        
   d197c:       e1a00001        mov     r0, r1                                                                        
   d1980:       e1a01002        mov     r1, r2                                                                        
   d1984:       e1a02003        mov     r2, r3                                                                        
   d1988:       e89c0078        ldm     ip, {r3, r4, r5, r6}                                                          
   d198c:       ef000000        svc     0x00000000                                                                    
   d1990:       e8bd00f0        pop     {r4, r5, r6, r7}     ######## PC point here                                                             
   d1994:       e3700a01        cmn     r0, #4096       ; 0x1000                                                      
   d1998:       312fff1e        bxcc    lr                                                                            
   d199c:       eafd17a3        b       17830 <__libc_start_main+0x270>    



Unwind info of syscall:
0xd1890: @0x12fe40
  Personality routine: 0x17a80

0xd1948: 0x80b0b0b0         #####  Executed unwind frame if PC was in syscall 
  Compact model index: 0
  0xb0      finish
  0xb0      finish
  0xb0      finish

0xd19a0: 0x801aabb0
  Compact model index: 0
  0x1a      vsp = vsp + 108
  0xab      pop {r4, r5, r6, r7, r14}
  0xb0      finish


Actually no syscall unwind info in .arm.exidx section, the executed unwind info is pointed 0xd1948, it failed after frame point to uv__epoll_wait, because of lost to 
pop four register (R4, R5, R6, R7} on syscall frame.

I have write the patch to execute unwind info when pc point to syscalll(addr: d1990) ike this:
  0xa3      pop {r4, r5, r6, r7}
  0xb0      finish
  0xb0      finish
then get the right backtrace like gdb output.

Is there anything i can do to get the right unwind info from libc-2.20.so without to change libunwind? 

Appreciated in advance!!!!
Comment 1 jsm-csl@polyomino.org.uk 2015-12-11 12:49:09 UTC
If one function has unwind info that relates to another function (as 
opposed to EXIDX_CANTUNWIND for a function with no unwind info), that's a 
bug in the static linker ld that was used to link glibc, not a bug in 
glibc.  ld is meant to insert EXIDX_CANTUNWIND automatically for address 
ranges without unwind info.
Comment 2 Guonic 2015-12-12 23:15:34 UTC
(In reply to joseph@codesourcery.com from comment #1)
> If one function has unwind info that relates to another function (as 
> opposed to EXIDX_CANTUNWIND for a function with no unwind info), that's a 
> bug in the static linker ld that was used to link glibc, not a bug in 
> glibc.  ld is meant to insert EXIDX_CANTUNWIND automatically for address 
> ranges without unwind info.

hi joseph,
thanks for your feedback, i think the unwind function for syscall(range 000d1970 - d199c) should be like
0xd1970: 0x80a3b0b0
  Compact model index: 0
  0xa3      pop {r4, r5, r6, r7}
  0xb0      finish
  0xb0      finish
, which can keep the register of SP is same, after unwind from syscall.

Did you mean this is the bug for ld?
Comment 3 jsm-csl@polyomino.org.uk 2015-12-14 22:49:21 UTC
If the .os file for syscall that was linked into libc.so did not have 
unwind info or had correct unwind info, but libc.so applies unwind info 
from another function to syscall, then the bug is in ld.
Comment 4 Guonic 2015-12-15 02:25:08 UTC
i have found the source code of syscall, implemented by ASM, and insert some of unwind INS,which will fix the problem, could you help me to review it?

diff --git a/sysdeps/unix/sysv/linux/arm/syscall.S b/sysdeps/unix/sysv/linux/arm/syscall.S
index c5582f8..71519fa 100644
--- a/sysdeps/unix/sysv/linux/arm/syscall.S
+++ b/sysdeps/unix/sysv/linux/arm/syscall.S
@@ -23,6 +23,8 @@
 
 ENTRY (syscall)
 	mov	ip, sp
+    .fnstart
+    .save {r4, r5, r6, r7}
 	push	{r4, r5, r6, r7}
 	cfi_adjust_cfa_offset (16)
 	cfi_rel_offset (r4, 0)
@@ -41,6 +43,7 @@ ENTRY (syscall)
 	cfi_restore (r5)
 	cfi_restore (r6)
 	cfi_restore (r7)
+    .fnend
 	cmn	r0, #4096
 	it	cc
 	RETINSTR(cc, lr)