Skip to content

Commit ef961e2

Browse files
authored
Merge pull request #513 from khuey/addr2line-0.20
2 parents 4245978 + 57af7c2 commit ef961e2

File tree

8 files changed

+178
-44
lines changed

8 files changed

+178
-44
lines changed

Diff for: .github/workflows/main.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ jobs:
229229
with:
230230
submodules: true
231231
- name: Install Rust
232-
run: rustup update 1.42.0 && rustup default 1.42.0
232+
run: rustup update 1.55.0 && rustup default 1.55.0
233233
- run: cargo build
234234

235235
miri:

Diff for: Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ rustc-serialize = { version = "0.3", optional = true }
3737
# Optionally demangle C++ frames' symbols in backtraces.
3838
cpp_demangle = { default-features = false, version = "0.4.0", optional = true, features = ["alloc"] }
3939

40-
addr2line = { version = "0.19.0", default-features = false }
40+
addr2line = { version = "0.20.0", default-features = false }
4141
miniz_oxide = { version = "0.6.0", default-features = false }
4242

4343
[dependencies.object]

Diff for: crates/as-if-std/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ bench = false
1515
cfg-if = "1.0"
1616
rustc-demangle = "0.1.4"
1717
libc = { version = "0.2.45", default-features = false }
18-
addr2line = { version = "0.16.0", default-features = false, optional = true }
18+
addr2line = { version = "0.20.0", default-features = false, optional = true }
1919
miniz_oxide = { version = "0.4.0", default-features = false }
2020

2121
[dependencies.object]

Diff for: src/symbolize/gimli.rs

+59-13
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ struct Mapping {
5858
// 'static lifetime is a lie to hack around lack of support for self-referential structs.
5959
cx: Context<'static>,
6060
_map: Mmap,
61-
_stash: Stash,
61+
stash: Stash,
6262
}
6363

6464
enum Either<A, B> {
@@ -97,21 +97,23 @@ impl Mapping {
9797
// only borrow `map` and `stash` and we're preserving them below.
9898
cx: unsafe { core::mem::transmute::<Context<'_>, Context<'static>>(cx) },
9999
_map: data,
100-
_stash: stash,
100+
stash: stash,
101101
})
102102
}
103103
}
104104

105105
struct Context<'a> {
106106
dwarf: addr2line::Context<EndianSlice<'a, Endian>>,
107107
object: Object<'a>,
108+
package: Option<gimli::DwarfPackage<EndianSlice<'a, Endian>>>,
108109
}
109110

110111
impl<'data> Context<'data> {
111112
fn new(
112113
stash: &'data Stash,
113114
object: Object<'data>,
114115
sup: Option<Object<'data>>,
116+
dwp: Option<Object<'data>>,
115117
) -> Option<Context<'data>> {
116118
let mut sections = gimli::Dwarf::load(|id| -> Result<_, ()> {
117119
let data = object.section(stash, id.name()).unwrap_or(&[]);
@@ -129,7 +131,46 @@ impl<'data> Context<'data> {
129131
}
130132
let dwarf = addr2line::Context::from_dwarf(sections).ok()?;
131133

132-
Some(Context { dwarf, object })
134+
let mut package = None;
135+
if let Some(dwp) = dwp {
136+
package = Some(
137+
gimli::DwarfPackage::load(
138+
|id| -> Result<_, gimli::Error> {
139+
let data = id
140+
.dwo_name()
141+
.and_then(|name| dwp.section(stash, name))
142+
.unwrap_or(&[]);
143+
Ok(EndianSlice::new(data, Endian))
144+
},
145+
EndianSlice::new(&[], Endian),
146+
)
147+
.ok()?,
148+
);
149+
}
150+
151+
Some(Context {
152+
dwarf,
153+
object,
154+
package,
155+
})
156+
}
157+
158+
fn find_frames(
159+
&'_ self,
160+
stash: &'data Stash,
161+
probe: u64,
162+
) -> gimli::Result<addr2line::FrameIter<'_, EndianSlice<'data, Endian>>> {
163+
use addr2line::{LookupContinuation, LookupResult};
164+
165+
let mut l = self.dwarf.find_frames(probe);
166+
loop {
167+
let (load, continuation) = match l {
168+
LookupResult::Output(output) => break output,
169+
LookupResult::Load { load, continuation } => (load, continuation),
170+
};
171+
172+
l = continuation.resume(handle_split_dwarf(self.package.as_ref(), stash, load));
173+
}
133174
}
134175
}
135176

@@ -142,18 +183,18 @@ fn mmap(path: &Path) -> Option<Mmap> {
142183
cfg_if::cfg_if! {
143184
if #[cfg(windows)] {
144185
mod coff;
145-
use self::coff::Object;
186+
use self::coff::{handle_split_dwarf, Object};
146187
} else if #[cfg(any(
147188
target_os = "macos",
148189
target_os = "ios",
149190
target_os = "tvos",
150191
target_os = "watchos",
151192
))] {
152193
mod macho;
153-
use self::macho::Object;
194+
use self::macho::{handle_split_dwarf, Object};
154195
} else {
155196
mod elf;
156-
use self::elf::Object;
197+
use self::elf::{handle_split_dwarf, Object};
157198
}
158199
}
159200

@@ -302,7 +343,7 @@ impl Cache {
302343
.next()
303344
}
304345

305-
fn mapping_for_lib<'a>(&'a mut self, lib: usize) -> Option<&'a mut Context<'a>> {
346+
fn mapping_for_lib<'a>(&'a mut self, lib: usize) -> Option<(&'a mut Context<'a>, &'a Stash)> {
306347
let idx = self.mappings.iter().position(|(idx, _)| *idx == lib);
307348

308349
// Invariant: after this conditional completes without early returning
@@ -328,10 +369,15 @@ impl Cache {
328369
self.mappings.insert(0, (lib, mapping));
329370
}
330371

331-
let cx: &'a mut Context<'static> = &mut self.mappings[0].1.cx;
372+
let mapping = &mut self.mappings[0].1;
373+
let cx: &'a mut Context<'static> = &mut mapping.cx;
374+
let stash: &'a Stash = &mapping.stash;
332375
// don't leak the `'static` lifetime, make sure it's scoped to just
333376
// ourselves
334-
Some(unsafe { mem::transmute::<&'a mut Context<'static>, &'a mut Context<'a>>(cx) })
377+
Some((
378+
unsafe { mem::transmute::<&'a mut Context<'static>, &'a mut Context<'a>>(cx) },
379+
stash,
380+
))
335381
}
336382
}
337383

@@ -353,12 +399,12 @@ pub unsafe fn resolve(what: ResolveWhat<'_>, cb: &mut dyn FnMut(&super::Symbol))
353399

354400
// Finally, get a cached mapping or create a new mapping for this file, and
355401
// evaluate the DWARF info to find the file/line/name for this address.
356-
let cx = match cache.mapping_for_lib(lib) {
357-
Some(cx) => cx,
402+
let (cx, stash) = match cache.mapping_for_lib(lib) {
403+
Some((cx, stash)) => (cx, stash),
358404
None => return,
359405
};
360406
let mut any_frames = false;
361-
if let Ok(mut frames) = cx.dwarf.find_frames(addr as u64) {
407+
if let Ok(mut frames) = cx.find_frames(stash, addr as u64) {
362408
while let Ok(Some(frame)) = frames.next() {
363409
any_frames = true;
364410
let name = match frame.function {
@@ -374,7 +420,7 @@ pub unsafe fn resolve(what: ResolveWhat<'_>, cb: &mut dyn FnMut(&super::Symbol))
374420
}
375421
if !any_frames {
376422
if let Some((object_cx, object_addr)) = cx.object.search_object_map(addr as u64) {
377-
if let Ok(mut frames) = object_cx.dwarf.find_frames(object_addr) {
423+
if let Ok(mut frames) = object_cx.find_frames(stash, object_addr) {
378424
while let Ok(Some(frame)) = frames.next() {
379425
any_frames = true;
380426
call(Symbol::Frame {

Diff for: src/symbolize/gimli/coff.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
use super::{Context, Mapping, Path, Stash, Vec};
1+
use super::{gimli, Context, Endian, EndianSlice, Mapping, Path, Stash, Vec};
2+
use alloc::sync::Arc;
23
use core::convert::TryFrom;
34
use object::pe::{ImageDosHeader, ImageSymbol};
45
use object::read::pe::{ImageNtHeaders, ImageOptionalHeader, SectionTable};
@@ -14,7 +15,7 @@ impl Mapping {
1415
pub fn new(path: &Path) -> Option<Mapping> {
1516
let map = super::mmap(path)?;
1617
Mapping::mk(map, |data, stash| {
17-
Context::new(stash, Object::parse(data)?, None)
18+
Context::new(stash, Object::parse(data)?, None, None)
1819
})
1920
}
2021
}
@@ -106,3 +107,11 @@ impl<'a> Object<'a> {
106107
None
107108
}
108109
}
110+
111+
pub(super) fn handle_split_dwarf<'data>(
112+
_package: Option<&gimli::DwarfPackage<EndianSlice<'data, Endian>>>,
113+
_stash: &'data Stash,
114+
_load: addr2line::SplitDwarfLoad<EndianSlice<'data, Endian>>,
115+
) -> Option<Arc<gimli::Dwarf<EndianSlice<'data, Endian>>>> {
116+
None
117+
}

Diff for: src/symbolize/gimli/elf.rs

+82-10
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ use super::mystd::fs;
33
use super::mystd::os::unix::ffi::{OsStrExt, OsStringExt};
44
use super::mystd::path::{Path, PathBuf};
55
use super::Either;
6-
use super::{Context, Mapping, Stash, Vec};
6+
use super::{gimli, Context, Endian, EndianSlice, Mapping, Stash, Vec};
7+
use alloc::sync::Arc;
78
use core::convert::{TryFrom, TryInto};
89
use core::str;
910
use object::elf::{ELFCOMPRESS_ZLIB, ELF_NOTE_GNU, NT_GNU_BUILD_ID, SHF_COMPRESSED};
@@ -24,24 +25,26 @@ impl Mapping {
2425

2526
// Try to locate an external debug file using the build ID.
2627
if let Some(path_debug) = object.build_id().and_then(locate_build_id) {
27-
if let Some(mapping) = Mapping::new_debug(path_debug, None) {
28+
if let Some(mapping) = Mapping::new_debug(path, path_debug, None) {
2829
return Some(Either::A(mapping));
2930
}
3031
}
3132

3233
// Try to locate an external debug file using the GNU debug link section.
3334
if let Some((path_debug, crc)) = object.gnu_debuglink_path(path) {
34-
if let Some(mapping) = Mapping::new_debug(path_debug, Some(crc)) {
35+
if let Some(mapping) = Mapping::new_debug(path, path_debug, Some(crc)) {
3536
return Some(Either::A(mapping));
3637
}
3738
}
3839

39-
Context::new(stash, object, None).map(Either::B)
40+
let dwp = Mapping::load_dwarf_package(path, stash);
41+
42+
Context::new(stash, object, None, dwp).map(Either::B)
4043
})
4144
}
4245

4346
/// Load debuginfo from an external debug file.
44-
fn new_debug(path: PathBuf, crc: Option<u32>) -> Option<Mapping> {
47+
fn new_debug(original_path: &Path, path: PathBuf, crc: Option<u32>) -> Option<Mapping> {
4548
let map = super::mmap(&path)?;
4649
Mapping::mk(map, |map, stash| {
4750
let object = Object::parse(&map)?;
@@ -51,20 +54,45 @@ impl Mapping {
5154
}
5255

5356
// Try to locate a supplementary object file.
57+
let mut sup = None;
5458
if let Some((path_sup, build_id_sup)) = object.gnu_debugaltlink_path(&path) {
5559
if let Some(map_sup) = super::mmap(&path_sup) {
56-
let map_sup = stash.set_mmap_aux(map_sup);
57-
if let Some(sup) = Object::parse(map_sup) {
58-
if sup.build_id() == Some(build_id_sup) {
59-
return Context::new(stash, object, Some(sup));
60+
let map_sup = stash.cache_mmap(map_sup);
61+
if let Some(sup_) = Object::parse(map_sup) {
62+
if sup_.build_id() == Some(build_id_sup) {
63+
sup = Some(sup_);
6064
}
6165
}
6266
}
6367
}
6468

65-
Context::new(stash, object, None)
69+
let dwp = Mapping::load_dwarf_package(original_path, stash);
70+
71+
Context::new(stash, object, sup, dwp)
6672
})
6773
}
74+
75+
/// Try to locate a DWARF package file.
76+
fn load_dwarf_package<'data>(path: &Path, stash: &'data Stash) -> Option<Object<'data>> {
77+
let mut path_dwp = path.to_path_buf();
78+
let dwp_extension = path
79+
.extension()
80+
.map(|previous_extension| {
81+
let mut previous_extension = previous_extension.to_os_string();
82+
previous_extension.push(".dwp");
83+
previous_extension
84+
})
85+
.unwrap_or_else(|| "dwp".into());
86+
path_dwp.set_extension(dwp_extension);
87+
if let Some(map_dwp) = super::mmap(&path_dwp) {
88+
let map_dwp = stash.cache_mmap(map_dwp);
89+
if let Some(dwp_) = Object::parse(map_dwp) {
90+
return Some(dwp_);
91+
}
92+
}
93+
94+
None
95+
}
6896
}
6997

7098
struct ParsedSym {
@@ -421,3 +449,47 @@ fn locate_debugaltlink(path: &Path, filename: &[u8], build_id: &[u8]) -> Option<
421449

422450
locate_build_id(build_id)
423451
}
452+
453+
fn convert_path<R: gimli::Reader>(r: &R) -> Result<PathBuf, gimli::Error> {
454+
let bytes = r.to_slice()?;
455+
Ok(PathBuf::from(OsStr::from_bytes(&bytes)))
456+
}
457+
458+
pub(super) fn handle_split_dwarf<'data>(
459+
package: Option<&gimli::DwarfPackage<EndianSlice<'data, Endian>>>,
460+
stash: &'data Stash,
461+
load: addr2line::SplitDwarfLoad<EndianSlice<'data, Endian>>,
462+
) -> Option<Arc<gimli::Dwarf<EndianSlice<'data, Endian>>>> {
463+
if let Some(dwp) = package.as_ref() {
464+
if let Ok(Some(cu)) = dwp.find_cu(load.dwo_id, &load.parent) {
465+
return Some(Arc::new(cu));
466+
}
467+
}
468+
469+
let mut path = PathBuf::new();
470+
if let Some(p) = load.comp_dir.as_ref() {
471+
path.push(convert_path(p).ok()?);
472+
}
473+
474+
path.push(convert_path(load.path.as_ref()?).ok()?);
475+
476+
if let Some(map_dwo) = super::mmap(&path) {
477+
let map_dwo = stash.cache_mmap(map_dwo);
478+
if let Some(dwo) = Object::parse(map_dwo) {
479+
return gimli::Dwarf::load(|id| -> Result<_, ()> {
480+
let data = id
481+
.dwo_name()
482+
.and_then(|name| dwo.section(stash, name))
483+
.unwrap_or(&[]);
484+
Ok(EndianSlice::new(data, Endian))
485+
})
486+
.ok()
487+
.map(|mut dwo_dwarf| {
488+
dwo_dwarf.make_dwo(&load.parent);
489+
Arc::new(dwo_dwarf)
490+
});
491+
}
492+
}
493+
494+
None
495+
}

Diff for: src/symbolize/gimli/macho.rs

+13-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
use super::{Box, Context, Mapping, Path, Stash, Vec};
1+
use super::{gimli, Box, Context, Endian, EndianSlice, Mapping, Path, Stash, Vec};
2+
use alloc::sync::Arc;
23
use core::convert::TryInto;
34
use object::macho;
45
use object::read::macho::{MachHeader, Nlist, Section, Segment as _};
@@ -45,7 +46,7 @@ impl Mapping {
4546
let (macho, data) = find_header(data)?;
4647
let endian = macho.endian().ok()?;
4748
let obj = Object::parse(macho, endian, data)?;
48-
Context::new(stash, obj, None)
49+
Context::new(stash, obj, None, None)
4950
})
5051
}
5152

@@ -82,7 +83,7 @@ impl Mapping {
8283
return None;
8384
}
8485
let obj = Object::parse(macho, endian, data)?;
85-
Context::new(stash, obj, None)
86+
Context::new(stash, obj, None, None)
8687
});
8788
if let Some(candidate) = candidate {
8889
return Some(candidate);
@@ -309,7 +310,7 @@ fn object_mapping(path: &[u8]) -> Option<Mapping> {
309310
let (macho, data) = find_header(data)?;
310311
let endian = macho.endian().ok()?;
311312
let obj = Object::parse(macho, endian, data)?;
312-
Context::new(stash, obj, None)
313+
Context::new(stash, obj, None, None)
313314
})
314315
}
315316

@@ -322,3 +323,11 @@ fn split_archive_path(path: &[u8]) -> Option<(&[u8], &[u8])> {
322323
let (archive, rest) = path.split_at(index);
323324
Some((archive, &rest[1..]))
324325
}
326+
327+
pub(super) fn handle_split_dwarf<'data>(
328+
_package: Option<&gimli::DwarfPackage<EndianSlice<'data, Endian>>>,
329+
_stash: &'data Stash,
330+
_load: addr2line::SplitDwarfLoad<EndianSlice<'data, Endian>>,
331+
) -> Option<Arc<gimli::Dwarf<EndianSlice<'data, Endian>>>> {
332+
None
333+
}

0 commit comments

Comments
 (0)