Skip to content

Commit 47da4e1

Browse files
authored
Refactor gimli implementation to avoid mk! macro (#379)
This commit refactors a bit to avoid using a macro for constructing a `Mapping` and instead adds a dedicated function. This is a bit easier to navigate and will hopefully help deduplicate construction of a `Mapping` as well.
1 parent 795d882 commit 47da4e1

File tree

4 files changed

+104
-83
lines changed

4 files changed

+104
-83
lines changed

src/symbolize/gimli.rs

+40-35
Original file line numberDiff line numberDiff line change
@@ -54,55 +54,60 @@ mod stash;
5454

5555
const MAPPINGS_CACHE_SIZE: usize = 4;
5656

57-
struct Context<'a> {
58-
dwarf: addr2line::Context<EndianSlice<'a, Endian>>,
59-
object: Object<'a>,
60-
}
61-
6257
struct Mapping {
6358
// 'static lifetime is a lie to hack around lack of support for self-referential structs.
6459
cx: Context<'static>,
6560
_map: Mmap,
6661
_stash: Stash,
6762
}
6863

69-
fn cx<'data>(stash: &'data Stash, object: Object<'data>) -> Option<Context<'data>> {
70-
fn load_section<'data, S>(stash: &'data Stash, obj: &Object<'data>) -> S
64+
impl Mapping {
65+
fn mk<F>(data: Mmap, mk: F) -> Option<Mapping>
7166
where
72-
S: gimli::Section<gimli::EndianSlice<'data, Endian>>,
67+
F: for<'a> Fn(&'a [u8], &'a Stash) -> Option<Context<'a>>,
7368
{
74-
let data = obj.section(stash, S::section_name()).unwrap_or(&[]);
75-
S::from(EndianSlice::new(data, Endian))
69+
let stash = Stash::new();
70+
let cx = mk(&data, &stash)?;
71+
Some(Mapping {
72+
// Convert to 'static lifetimes since the symbols should
73+
// only borrow `map` and `stash` and we're preserving them below.
74+
cx: unsafe { core::mem::transmute::<Context<'_>, Context<'static>>(cx) },
75+
_map: data,
76+
_stash: stash,
77+
})
7678
}
79+
}
7780

78-
let dwarf = addr2line::Context::from_sections(
79-
load_section(stash, &object),
80-
load_section(stash, &object),
81-
load_section(stash, &object),
82-
load_section(stash, &object),
83-
load_section(stash, &object),
84-
load_section(stash, &object),
85-
load_section(stash, &object),
86-
load_section(stash, &object),
87-
load_section(stash, &object),
88-
gimli::EndianSlice::new(&[], Endian),
89-
)
90-
.ok()?;
91-
Some(Context { dwarf, object })
81+
struct Context<'a> {
82+
dwarf: addr2line::Context<EndianSlice<'a, Endian>>,
83+
object: Object<'a>,
9284
}
9385

94-
macro_rules! mk {
95-
(Mapping { $map:expr, $inner:expr, $stash:expr }) => {{
96-
fn assert_lifetimes<'a>(_: &'a Mmap, _: &Context<'a>, _: &'a Stash) {}
97-
assert_lifetimes(&$map, &$inner, &$stash);
98-
Mapping {
99-
// Convert to 'static lifetimes since the symbols should
100-
// only borrow `map` and `stash` and we're preserving them below.
101-
cx: unsafe { core::mem::transmute::<Context<'_>, Context<'static>>($inner) },
102-
_map: $map,
103-
_stash: $stash,
86+
impl<'data> Context<'data> {
87+
fn new(stash: &'data Stash, object: Object<'data>) -> Option<Context<'data>> {
88+
fn load_section<'data, S>(stash: &'data Stash, obj: &Object<'data>) -> S
89+
where
90+
S: gimli::Section<gimli::EndianSlice<'data, Endian>>,
91+
{
92+
let data = obj.section(stash, S::section_name()).unwrap_or(&[]);
93+
S::from(EndianSlice::new(data, Endian))
10494
}
105-
}};
95+
96+
let dwarf = addr2line::Context::from_sections(
97+
load_section(stash, &object),
98+
load_section(stash, &object),
99+
load_section(stash, &object),
100+
load_section(stash, &object),
101+
load_section(stash, &object),
102+
load_section(stash, &object),
103+
load_section(stash, &object),
104+
load_section(stash, &object),
105+
load_section(stash, &object),
106+
gimli::EndianSlice::new(&[], Endian),
107+
)
108+
.ok()?;
109+
Some(Context { dwarf, object })
110+
}
106111
}
107112

108113
fn mmap(path: &Path) -> Option<Mmap> {

src/symbolize/gimli/coff.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::{Context, Mapping, Mmap, Path, Stash, Vec};
1+
use super::{Context, Mapping, Path, Stash, Vec};
22
use core::convert::TryFrom;
33
use object::pe::{ImageDosHeader, ImageSymbol};
44
use object::read::pe::{ImageNtHeaders, ImageOptionalHeader, SectionTable};
@@ -13,9 +13,7 @@ type Pe = object::pe::ImageNtHeaders64;
1313
impl Mapping {
1414
pub fn new(path: &Path) -> Option<Mapping> {
1515
let map = super::mmap(path)?;
16-
let stash = Stash::new();
17-
let cx = super::cx(&stash, Object::parse(&map)?)?;
18-
Some(mk!(Mapping { map, cx, stash }))
16+
Mapping::mk(map, |data, stash| Context::new(stash, Object::parse(data)?))
1917
}
2018
}
2119

src/symbolize/gimli/elf.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::{Context, Mapping, Mmap, Path, Stash, Vec};
1+
use super::{Context, Mapping, Path, Stash, Vec};
22
use core::convert::TryFrom;
33
use object::elf::{ELFCOMPRESS_ZLIB, SHF_COMPRESSED};
44
use object::read::elf::{CompressionHeader, FileHeader, SectionHeader, SectionTable, Sym};
@@ -13,9 +13,7 @@ type Elf = object::elf::FileHeader64<NativeEndian>;
1313
impl Mapping {
1414
pub fn new(path: &Path) -> Option<Mapping> {
1515
let map = super::mmap(path)?;
16-
let stash = Stash::new();
17-
let cx = super::cx(&stash, Object::parse(&map)?)?;
18-
Some(mk!(Mapping { map, cx, stash }))
16+
Mapping::mk(map, |data, stash| Context::new(stash, Object::parse(data)?))
1917
}
2018
}
2119

src/symbolize/gimli/macho.rs

+60-40
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::{Box, Context, Mapping, Mmap, Path, Stash, Vec};
1+
use super::{Box, Context, Mapping, Path, Stash, Vec};
22
use core::convert::TryInto;
33
use object::macho;
44
use object::read::macho::{MachHeader, Nlist, Section, Segment as _};
@@ -30,8 +30,25 @@ impl Mapping {
3030
// contains and try to find a macho file which has a matching UUID as
3131
// the one of our own file. If we find a match that's the dwarf file we
3232
// want to return.
33-
let parent = path.parent()?;
34-
for entry in parent.read_dir().ok()? {
33+
if let Some(parent) = path.parent() {
34+
if let Some(mapping) = Mapping::load_dsym(parent, uuid) {
35+
return Some(mapping);
36+
}
37+
}
38+
39+
// Looks like nothing matched our UUID, so let's at least return our own
40+
// file. This should have the symbol table for at least some
41+
// symbolication purposes.
42+
Mapping::mk(map, |data, stash| {
43+
let (macho, data) = find_header(Bytes(data))?;
44+
let endian = macho.endian().ok()?;
45+
let obj = Object::parse(macho, endian, data)?;
46+
Context::new(stash, obj)
47+
})
48+
}
49+
50+
fn load_dsym(dir: &Path, uuid: [u8; 16]) -> Option<Mapping> {
51+
for entry in dir.read_dir().ok()? {
3552
let entry = entry.ok()?;
3653
let filename = match entry.file_name().into_string() {
3754
Ok(name) => name,
@@ -41,38 +58,36 @@ impl Mapping {
4158
continue;
4259
}
4360
let candidates = entry.path().join("Contents/Resources/DWARF");
44-
if let Some(mapping) = load_dsym(&candidates, uuid) {
61+
if let Some(mapping) = Mapping::try_dsym_candidate(&candidates, uuid) {
4562
return Some(mapping);
4663
}
4764
}
65+
None
66+
}
4867

49-
// Looks like nothing matched our UUID, so let's at least return our own
50-
// file. This should have the symbol table for at least some
51-
// symbolication purposes.
52-
let stash = Stash::new();
53-
let inner = super::cx(&stash, Object::parse(macho, endian, data)?)?;
54-
return Some(mk!(Mapping { map, inner, stash }));
55-
56-
fn load_dsym(dir: &Path, uuid: [u8; 16]) -> Option<Mapping> {
57-
for entry in dir.read_dir().ok()? {
58-
let entry = entry.ok()?;
59-
let map = super::mmap(&entry.path())?;
60-
let (macho, data) = find_header(Bytes(&map))?;
68+
fn try_dsym_candidate(dir: &Path, uuid: [u8; 16]) -> Option<Mapping> {
69+
// Look for files in the `DWARF` directory which have a matching uuid to
70+
// the original object file. If we find one then we found the debug
71+
// information.
72+
for entry in dir.read_dir().ok()? {
73+
let entry = entry.ok()?;
74+
let map = super::mmap(&entry.path())?;
75+
let candidate = Mapping::mk(map, |data, stash| {
76+
let (macho, data) = find_header(Bytes(data))?;
6177
let endian = macho.endian().ok()?;
6278
let entry_uuid = macho.uuid(endian, data).ok()??;
6379
if entry_uuid != uuid {
64-
continue;
65-
}
66-
let stash = Stash::new();
67-
if let Some(cx) =
68-
Object::parse(macho, endian, data).and_then(|o| super::cx(&stash, o))
69-
{
70-
return Some(mk!(Mapping { map, cx, stash }));
80+
return None;
7181
}
82+
let obj = Object::parse(macho, endian, data)?;
83+
Context::new(stash, obj)
84+
});
85+
if let Some(candidate) = candidate {
86+
return Some(candidate);
7287
}
73-
74-
None
7588
}
89+
90+
None
7691
}
7792
}
7893

@@ -269,25 +284,30 @@ fn object_mapping(path: &[u8]) -> Option<Mapping> {
269284
let map;
270285

271286
// `N_OSO` symbol names can be either `/path/to/object.o` or `/path/to/archive.a(object.o)`.
272-
let data = if let Some((archive_path, member_name)) = split_archive_path(path) {
287+
let member_name = if let Some((archive_path, member_name)) = split_archive_path(path) {
273288
map = super::mmap(Path::new(OsStr::from_bytes(archive_path)))?;
274-
let archive = object::read::archive::ArchiveFile::parse(&map).ok()?;
275-
let member = archive
276-
.members()
277-
.filter_map(Result::ok)
278-
.find(|m| m.name() == member_name)?;
279-
Bytes(member.data())
289+
Some(member_name)
280290
} else {
281291
map = super::mmap(Path::new(OsStr::from_bytes(path)))?;
282-
Bytes(&map)
292+
None
283293
};
284-
285-
let (macho, data) = find_header(data)?;
286-
let endian = macho.endian().ok()?;
287-
let object = Object::parse(macho, endian, data)?;
288-
let stash = Stash::new();
289-
let inner = super::cx(&stash, object)?;
290-
Some(mk!(Mapping { map, inner, stash }))
294+
Mapping::mk(map, |data, stash| {
295+
let data = match member_name {
296+
Some(member_name) => {
297+
let archive = object::read::archive::ArchiveFile::parse(data).ok()?;
298+
let member = archive
299+
.members()
300+
.filter_map(Result::ok)
301+
.find(|m| m.name() == member_name)?;
302+
Bytes(member.data())
303+
}
304+
None => Bytes(data),
305+
};
306+
let (macho, data) = find_header(data)?;
307+
let endian = macho.endian().ok()?;
308+
let obj = Object::parse(macho, endian, data)?;
309+
Context::new(stash, obj)
310+
})
291311
}
292312

293313
fn split_archive_path(path: &[u8]) -> Option<(&[u8], &[u8])> {

0 commit comments

Comments
 (0)