From 9be87b006aaceacd81a91741e9ec0f34f5414797 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 3 Mar 2020 11:07:21 -0800 Subject: [PATCH] gimli: Implement symbol table searches on macOS 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 ``` --- src/symbolize/gimli.rs | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/symbolize/gimli.rs b/src/symbolize/gimli.rs index 1529a90a0..03124a350 100644 --- a/src/symbolize/gimli.rs +++ b/src/symbolize/gimli.rs @@ -158,6 +158,7 @@ cfg_if::cfg_if! { struct Object<'a> { macho: MachO<'a>, dwarf: Option, + syms: Vec<(&'a str, u64)>, } impl<'a> Object<'a> { @@ -171,7 +172,16 @@ cfg_if::cfg_if! { .enumerate() .find(|(_, segment)| segment.name().ok() == Some("__DWARF")) .map(|p| p.0); - Some(Object { macho, dwarf }) + let mut syms = Vec::new(); + if let Some(s) = &macho.symbols { + syms = s.iter() + .filter_map(|e| e.ok()) + .filter(|(name, nlist)| name.len() > 0 && !nlist.is_undefined()) + .map(|(name, nlist)| (name, nlist.n_value)) + .collect(); + } + syms.sort_unstable_by_key(|(_, addr)| *addr); + Some(Object { macho, dwarf, syms }) } fn section(&self, name: &str) -> Option<&'a [u8]> { @@ -194,12 +204,13 @@ cfg_if::cfg_if! { .map(|p| p.1) } - fn search_symtab<'b>(&'b self, _addr: u64) -> Option<&'b [u8]> { - // So far it seems that we don't need to implement this. Maybe - // `dladdr` on OSX has us covered? Maybe there's not much in the - // symbol table? In any case our relevant tests are passing - // without this being implemented, so let's skip it for now. - None + fn search_symtab<'b>(&'b self, addr: u64) -> Option<&'b [u8]> { + let i = match self.syms.binary_search_by_key(&addr, |(_, addr)| *addr) { + Ok(i) => i, + Err(i) => i.checked_sub(1)?, + }; + let (sym, _addr) = self.syms.get(i)?; + Some(sym.as_bytes()) } } } else {