]> git.ipfire.org Git - thirdparty/tvheadend.git/commit
FreeBSD: Add libunwind trap support for FreeBSD only.
authorE.Smith <31170571+azlm8t@users.noreply.github.com>
Mon, 1 Oct 2018 17:05:26 +0000 (18:05 +0100)
committerJaroslav Kysela <perex@perex.cz>
Wed, 3 Oct 2018 07:47:31 +0000 (09:47 +0200)
commit8dc9995d5f64e6f84a16f436a90811bfe1e27820
treecc80fafc59bda5836ac0f44dd606b2537414f463
parent19b94586321f8f0aac2c0f4b5e210a87db75199d
FreeBSD: Add libunwind trap support for FreeBSD only.

Although the existing backtrace works correctly on Linux, on
FreeBSD it frequently generates a backtrace with completely
wrong function names. (FreeBSD 11.2, current latest version).

For example, making htsp_build_dvrentry crash with SEGV, it
would either not generate a stacktrace or would generate a
backtrace of:
-pthread_sigmask
-pthread_getspecific
-service_remove_unseen
-htsp_get_subscription_status
-htsp_init
-tcp_server_done
-tvhthread_create.

...instead of the correct backtrace of:
-<signal>
-htsp_build_dvrentry
-htsp_method_async
-htsp_read_loop
-htsp_serve...

So on FreeBSD only, we use libunwind to generate the
backtrace and function names. We explicitly make
libunwind and libexecinfo mutually exclusive since
FreeBSD has both.

Line are logged similar to:
  CRASH: htsp_build_dvrentry+5d (ip=11f659d sp=7fffd8bc3930)

Note that it does not have line numbers since the addr2line
does not appear to work on FreeBSD (even with the original
backtrace code).

An example of the problem with the old backtrace code using
the frame from htsp_method_async from within the tvheadend
traphandler after the retrieval of the stack frames:

(gdb) print frames
$38 = {0x806473954, 0x806472eb2, 0x7ffffffff193, 0x11f1638 <htsp_method_async+1640>, 0x11fe400 <htsp_read_loop+880>, 0x11f58e6 <htsp_serve+502>, 0x11b9b11 <tcp_server_start+401>,
  0x11af45e <thread_wrapper+302>, 0x80646dc06, 0x0 <repeats 91 times>}

(gdb) print dladdr(0x11f1638, &dli)    <--- addr of htsp_method_async from frame 4.
$39 = 1  <--- success

(gdb) print dli
$40 = {dli_fname = 0x7fffffffef97 ".../build.freebsd/tvheadend", dli_fbase = 0x1021000, dli_sname = 0x1044f91 "service_remove_unseen",   <--- but wrong name
    dli_saddr = 0x11eff80 <service_remove_unseen>}   <--- and this is nearest symbol address

(gdb) print htsp_method_async+1640
    $41 = (htsmsg_t *(*)(htsp_connection_t *, htsmsg_t *)) 0x11f1638 <htsp_method_async+1640>   <---but gdb knows the original address is htsp_method_async

(gdb) print service_remove_unseen
    $42 = {void (const char *, int)} 0x11eff80 <service_remove_unseen> <--- and gdb knows sevice_remove_unseen is at the dli_saddr.

By contrast, with libunwind, we get:

(gdb) print buf
$50 = "htsp_method_async", '\000' <repeats 110 times> <--- libunwind detected correct function name

(gdb) where 10  <--- even though our signal has been delivered on its own stack
 #0  traphandler_libunwind () at src/trap.c:162
 #1  0x000000000120cf06 in traphandler (sig=11, si=0x7fffdbbdb860, UC=0x7fffdbbdb4f0) at src/trap.c:221
 #2  0x0000000806673954 in ?? ()
 #3  0x0000000000000000 in ?? ()

(gdb) print ip
$51 = 18814904

(gdb) disass 18814904  <--- and gdb knows that ip address is for the same method as libunwind detected
Dump of assembler code for function htsp_method_async:
   0x00000000011f1150 <+0>:     push   %rbp
configure
src/trap.c