Skip to content

Commit f76b004

Browse files
committed
Fall back to dladdr on Unix in more places
Currently CoreSymbolication will fall back to `dladdr` but this also applies the same logic to the `libbacktrace` symbolication strategy since libbacktrace (especially on OSX) can't always get symbol name information. Instead these platforms will all fall back to `dladdr` if no symbol information is learned from libbacktrace. This involved some refactoring internally since all invocations calling the `dladdr` function are now shared instead of having three separate ones throughout.
1 parent 2b8aae5 commit f76b004

File tree

5 files changed

+177
-74
lines changed

5 files changed

+177
-74
lines changed

src/symbolize/coresymbolication.rs

+9-9
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,10 @@ use core::mem;
2929
use core::ptr;
3030
use core::slice;
3131

32-
use libc::{self, c_char, c_int, Dl_info};
32+
use libc::{self, c_char, c_int};
3333

3434
use symbolize::ResolveWhat;
35+
use symbolize::dladdr;
3536
use types::{c_void, BytesOrWideString};
3637
use SymbolName;
3738

@@ -55,14 +56,14 @@ pub enum Symbol {
5556
name: *const c_char,
5657
addr: *mut c_void,
5758
},
58-
Dladdr(Dl_info),
59+
Dladdr(dladdr::Symbol),
5960
}
6061

6162
impl Symbol {
6263
pub fn name(&self) -> Option<SymbolName> {
6364
let name = match *self {
6465
Symbol::Core { name, .. } => name,
65-
Symbol::Dladdr(ref info) => info.dli_sname,
66+
Symbol::Dladdr(ref info) => return info.name(),
6667
};
6768
if name.is_null() {
6869
None
@@ -77,7 +78,7 @@ impl Symbol {
7778
pub fn addr(&self) -> Option<*mut c_void> {
7879
match *self {
7980
Symbol::Core { addr, .. } => Some(addr),
80-
Symbol::Dladdr(ref info) => Some(info.dli_saddr as *mut _),
81+
Symbol::Dladdr(ref info) => info.addr(),
8182
}
8283
}
8384

@@ -269,10 +270,9 @@ pub unsafe fn resolve(what: ResolveWhat, cb: &mut FnMut(&super::Symbol)) {
269270
if try_resolve(addr, cb) {
270271
return;
271272
}
272-
let mut info: Dl_info = mem::zeroed();
273-
if libc::dladdr(addr as *mut _, &mut info) != 0 {
273+
dladdr::resolve(addr, &mut |sym| {
274274
cb(&super::Symbol {
275-
inner: Symbol::Dladdr(info),
276-
});
277-
}
275+
inner: Symbol::Dladdr(sym),
276+
})
277+
})
278278
}

src/symbolize/dladdr.rs

+77-46
Original file line numberDiff line numberDiff line change
@@ -8,63 +8,94 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
//! Symbolication strategy using `dladdr`
12-
//!
13-
//! The `dladdr` API is available on most Unix implementations but it's quite
14-
//! basic, not handling inline frame information at all. Since it's so prevalent
15-
//! though we have an option to use it!
11+
//! Common support for resolving with `dladdr`, often used as a fallback if
12+
//! other strategies don't work.
1613
17-
use core::{mem, slice};
14+
#![allow(dead_code)]
1815

19-
use types::{BytesOrWideString, c_void};
20-
use libc::{self, Dl_info};
21-
use symbolize::ResolveWhat;
16+
cfg_if! {
17+
if #[cfg(all(unix, not(target_os = "emscripten"), feature = "dladdr"))] {
18+
use core::{mem, slice};
2219

23-
use SymbolName;
20+
use types::{BytesOrWideString, c_void};
21+
use libc::{self, Dl_info};
2422

25-
pub struct Symbol {
26-
inner: Dl_info,
27-
}
23+
use SymbolName;
24+
25+
pub struct Symbol {
26+
inner: Dl_info,
27+
}
28+
29+
impl Symbol {
30+
pub fn name(&self) -> Option<SymbolName> {
31+
if self.inner.dli_sname.is_null() {
32+
None
33+
} else {
34+
let ptr = self.inner.dli_sname as *const u8;
35+
unsafe {
36+
let len = libc::strlen(self.inner.dli_sname);
37+
Some(SymbolName::new(slice::from_raw_parts(ptr, len)))
38+
}
39+
}
40+
}
41+
42+
pub fn addr(&self) -> Option<*mut c_void> {
43+
Some(self.inner.dli_saddr as *mut _)
44+
}
2845

29-
impl Symbol {
30-
pub fn name(&self) -> Option<SymbolName> {
31-
if self.inner.dli_sname.is_null() {
32-
None
33-
} else {
34-
let ptr = self.inner.dli_sname as *const u8;
35-
unsafe {
36-
let len = libc::strlen(self.inner.dli_sname);
37-
Some(SymbolName::new(slice::from_raw_parts(ptr, len)))
46+
pub fn filename_raw(&self) -> Option<BytesOrWideString> {
47+
None
48+
}
49+
50+
#[cfg(feature = "std")]
51+
pub fn filename(&self) -> Option<&::std::path::Path> {
52+
None
53+
}
54+
55+
pub fn lineno(&self) -> Option<u32> {
56+
None
3857
}
3958
}
40-
}
4159

42-
pub fn addr(&self) -> Option<*mut c_void> {
43-
Some(self.inner.dli_saddr as *mut _)
44-
}
60+
pub unsafe fn resolve(addr: *mut c_void, cb: &mut FnMut(Symbol)) {
61+
let mut info = Symbol {
62+
inner: mem::zeroed(),
63+
};
64+
if libc::dladdr(addr as *mut _, &mut info.inner) != 0 {
65+
cb(info)
66+
}
67+
}
68+
} else {
69+
use types::{BytesOrWideString, c_void};
70+
use symbolize::SymbolName;
4571

46-
pub fn filename_raw(&self) -> Option<BytesOrWideString> {
47-
None
48-
}
72+
pub enum Symbol {}
4973

50-
#[cfg(feature = "std")]
51-
pub fn filename(&self) -> Option<&::std::path::Path> {
52-
None
53-
}
74+
impl Symbol {
75+
pub fn name(&self) -> Option<SymbolName> {
76+
match *self {}
77+
}
5478

55-
pub fn lineno(&self) -> Option<u32> {
56-
None
57-
}
58-
}
79+
pub fn addr(&self) -> Option<*mut c_void> {
80+
match *self {}
81+
}
82+
83+
pub fn filename_raw(&self) -> Option<BytesOrWideString> {
84+
match *self {}
85+
}
86+
87+
#[cfg(feature = "std")]
88+
pub fn filename(&self) -> Option<&::std::path::Path> {
89+
match *self {}
90+
}
5991

60-
pub unsafe fn resolve(what: ResolveWhat, cb: &mut FnMut(&super::Symbol)) {
61-
let addr = what.address_or_ip();
62-
let mut info: super::Symbol = super::Symbol {
63-
inner: Symbol {
64-
inner: mem::zeroed(),
65-
},
66-
};
67-
if libc::dladdr(addr as *mut _, &mut info.inner.inner) != 0 {
68-
cb(&info)
92+
pub fn lineno(&self) -> Option<u32> {
93+
match *self {}
94+
}
95+
}
96+
97+
pub unsafe fn resolve(addr: *mut c_void, cb: &mut FnMut(Symbol)) {
98+
drop((addr, cb));
99+
}
69100
}
70101
}

src/symbolize/dladdr_resolve.rs

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! Symbolication strategy using `dladdr`
12+
//!
13+
//! The `dladdr` API is available on most Unix implementations but it's quite
14+
//! basic, not handling inline frame information at all. Since it's so prevalent
15+
//! though we have an option to use it!
16+
17+
use types::{BytesOrWideString, c_void};
18+
use symbolize::{dladdr, SymbolName, ResolveWhat};
19+
20+
pub struct Symbol(dladdr::Symbol);
21+
22+
impl Symbol {
23+
pub fn name(&self) -> Option<SymbolName> {
24+
self.0.name()
25+
}
26+
27+
pub fn addr(&self) -> Option<*mut c_void> {
28+
self.0.addr()
29+
}
30+
31+
pub fn filename_raw(&self) -> Option<BytesOrWideString> {
32+
self.0.filename_raw()
33+
}
34+
35+
#[cfg(feature = "std")]
36+
pub fn filename(&self) -> Option<&::std::path::Path> {
37+
self.0.filename()
38+
}
39+
40+
pub fn lineno(&self) -> Option<u32> {
41+
self.0.lineno()
42+
}
43+
}
44+
45+
pub unsafe fn resolve(what: ResolveWhat, cb: &mut FnMut(&Symbol)) {
46+
dladdr::resolve(what.address_or_ip(), &mut |sym| {
47+
cb(Symbol(sym))
48+
});
49+
}

src/symbolize/libbacktrace.rs

+37-16
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,10 @@
3636
extern crate backtrace_sys as bt;
3737

3838
use core::{ptr, slice};
39-
4039
use libc::{self, c_char, c_int, c_void, uintptr_t};
4140

42-
use SymbolName;
43-
44-
use symbolize::ResolveWhat;
41+
use symbolize::{ResolveWhat, SymbolName};
42+
use symbolize::dladdr;
4543
use types::BytesOrWideString;
4644

4745
pub enum Symbol {
@@ -56,6 +54,7 @@ pub enum Symbol {
5654
function: *const c_char,
5755
symname: *const c_char,
5856
},
57+
Dladdr(dladdr::Symbol),
5958
}
6059

6160
impl Symbol {
@@ -90,13 +89,15 @@ impl Symbol {
9089
}
9190
symbol(symname)
9291
}
92+
Symbol::Dladdr(ref s) => s.name(),
9393
}
9494
}
9595

9696
pub fn addr(&self) -> Option<*mut c_void> {
9797
let pc = match *self {
9898
Symbol::Syminfo { pc, .. } => pc,
9999
Symbol::Pcinfo { pc, .. } => pc,
100+
Symbol::Dladdr(ref s) => return s.addr(),
100101
};
101102
if pc == 0 {
102103
None
@@ -115,6 +116,7 @@ impl Symbol {
115116
Some(slice::from_raw_parts(ptr, len))
116117
}
117118
}
119+
Symbol::Dladdr(_) => None,
118120
}
119121
}
120122

@@ -146,6 +148,7 @@ impl Symbol {
146148
match *self {
147149
Symbol::Syminfo { .. } => None,
148150
Symbol::Pcinfo { lineno, .. } => Some(lineno as u32),
151+
Symbol::Dladdr(ref s) => s.lineno(),
149152
}
150153
}
151154
}
@@ -425,7 +428,7 @@ pub unsafe fn resolve(what: ResolveWhat, cb: &mut FnMut(&super::Symbol)) {
425428
// backtrace errors are currently swept under the rug
426429
let state = init_state();
427430
if state.is_null() {
428-
return;
431+
return dladdr_fallback(what.address_or_ip(), cb);
429432
}
430433

431434
// Call the `backtrace_syminfo` API first. This is (from reading the code)
@@ -434,15 +437,33 @@ pub unsafe fn resolve(what: ResolveWhat, cb: &mut FnMut(&super::Symbol)) {
434437
//
435438
// Note that we do this since `syminfo` will consult the symbol table,
436439
// finding symbol names even if there's no debug information in the binary.
437-
let mut syminfo_state = SyminfoState {
438-
pc: symaddr,
439-
cb: cb,
440-
};
441-
bt::backtrace_syminfo(
442-
state,
443-
symaddr as uintptr_t,
444-
syminfo_cb,
445-
error_cb,
446-
&mut syminfo_state as *mut _ as *mut _,
447-
);
440+
let mut called = false;
441+
{
442+
let mut syminfo_state = SyminfoState {
443+
pc: symaddr,
444+
cb: &mut |sym| {
445+
called = true;
446+
cb(sym);
447+
},
448+
};
449+
bt::backtrace_syminfo(
450+
state,
451+
symaddr as uintptr_t,
452+
syminfo_cb,
453+
error_cb,
454+
&mut syminfo_state as *mut _ as *mut _,
455+
);
456+
}
457+
458+
if !called {
459+
dladdr_fallback(what.address_or_ip(), cb);
460+
}
461+
}
462+
463+
unsafe fn dladdr_fallback(addr: *mut c_void, cb: &mut FnMut(&super::Symbol)) {
464+
dladdr::resolve(addr, &mut |sym| {
465+
cb(&super::Symbol {
466+
inner: Symbol::Dladdr(sym),
467+
})
468+
});
448469
}

src/symbolize/mod.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,8 @@ cfg_if! {
405405
}
406406
}
407407

408+
mod dladdr;
409+
408410
cfg_if! {
409411
if #[cfg(all(windows, target_env = "msvc", feature = "dbghelp"))] {
410412
mod dbghelp;
@@ -435,9 +437,9 @@ cfg_if! {
435437
} else if #[cfg(all(unix,
436438
not(target_os = "emscripten"),
437439
feature = "dladdr"))] {
438-
mod dladdr;
439-
use self::dladdr::resolve as resolve_imp;
440-
use self::dladdr::Symbol as SymbolImp;
440+
mod dladdr_resolve;
441+
use self::dladdr_resolve::resolve as resolve_imp;
442+
use self::dladdr_resolve::Symbol as SymbolImp;
441443
} else {
442444
mod noop;
443445
use self::noop::resolve as resolve_imp;

0 commit comments

Comments
 (0)