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!!!!
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.
(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?
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.
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)