Skip to content

Commit ac175e2

Browse files
authored
gimli: Implement symbol table searches on macOS (#300)
If dwarf debug info isn't available we fall back to searching the symbol table. Typically this is done with `dladdr` on most platforms but with gimli we typically have all the infrastructure already in place to do the search ourselves. This functionality was already filled out on Linux and Windows, but it wasn't implemented on macOS yet because it wasn't necessary. Implementing a pretty simple version, however, shows substantial speedups for the various benchmarks. Presumably `dladdr` isn't exactly the fastest thing in the world and our sorted list search which is cached must be much faster here! The current comparison of before/after this change looks like: ``` name before ns/iter after ns/iter diff ns/iter diff % speedup new 81,472 9,047 -72,425 -88.90% x 9.01 new_unresolved 2,126 2,009 -117 -5.50% x 1.06 new_unresolved_and_resolve_separate 82,252 9,134 -73,118 -88.90% x 9.01 trace 1,273 1,185 -88 -6.91% x 1.07 trace_and_resolve_callback 67,403 2,123 -65,280 -96.85% x 31.75 trace_and_resolve_separate 76,452 2,822 -73,630 -96.31% x 27.09 ```
1 parent c5f56d1 commit ac175e2

File tree

1 file changed

+18
-7
lines changed

1 file changed

+18
-7
lines changed

src/symbolize/gimli.rs

+18-7
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ cfg_if::cfg_if! {
158158
struct Object<'a> {
159159
macho: MachO<'a>,
160160
dwarf: Option<usize>,
161+
syms: Vec<(&'a str, u64)>,
161162
}
162163

163164
impl<'a> Object<'a> {
@@ -171,7 +172,16 @@ cfg_if::cfg_if! {
171172
.enumerate()
172173
.find(|(_, segment)| segment.name().ok() == Some("__DWARF"))
173174
.map(|p| p.0);
174-
Some(Object { macho, dwarf })
175+
let mut syms = Vec::new();
176+
if let Some(s) = &macho.symbols {
177+
syms = s.iter()
178+
.filter_map(|e| e.ok())
179+
.filter(|(name, nlist)| name.len() > 0 && !nlist.is_undefined())
180+
.map(|(name, nlist)| (name, nlist.n_value))
181+
.collect();
182+
}
183+
syms.sort_unstable_by_key(|(_, addr)| *addr);
184+
Some(Object { macho, dwarf, syms })
175185
}
176186

177187
fn section(&self, name: &str) -> Option<&'a [u8]> {
@@ -194,12 +204,13 @@ cfg_if::cfg_if! {
194204
.map(|p| p.1)
195205
}
196206

197-
fn search_symtab<'b>(&'b self, _addr: u64) -> Option<&'b [u8]> {
198-
// So far it seems that we don't need to implement this. Maybe
199-
// `dladdr` on OSX has us covered? Maybe there's not much in the
200-
// symbol table? In any case our relevant tests are passing
201-
// without this being implemented, so let's skip it for now.
202-
None
207+
fn search_symtab<'b>(&'b self, addr: u64) -> Option<&'b [u8]> {
208+
let i = match self.syms.binary_search_by_key(&addr, |(_, addr)| *addr) {
209+
Ok(i) => i,
210+
Err(i) => i.checked_sub(1)?,
211+
};
212+
let (sym, _addr) = self.syms.get(i)?;
213+
Some(sym.as_bytes())
203214
}
204215
}
205216
} else {

0 commit comments

Comments
 (0)