Skip to content

Commit 04845bb

Browse files
author
Kai Luo
committed
Parse xcoff member in big archive
1 parent 0374e47 commit 04845bb

File tree

3 files changed

+93
-32
lines changed

3 files changed

+93
-32
lines changed

src/symbolize/gimli.rs

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,8 @@ struct Cache {
235235

236236
struct Library {
237237
name: OsString,
238+
#[cfg(target_os = "aix")]
239+
member_name: OsString,
238240
/// Segments of this library loaded into memory, and where they're loaded.
239241
segments: Vec<LibrarySegment>,
240242
/// The "bias" of this library, typically where it's loaded into memory.
@@ -254,6 +256,19 @@ struct LibrarySegment {
254256
len: usize,
255257
}
256258

259+
#[cfg(target_os = "aix")]
260+
fn create_map(lib: &Library) -> Option<Mapping> {
261+
let name = &lib.name;
262+
let member_name = &lib.member_name;
263+
Mapping::new(name.as_ref(), member_name)
264+
}
265+
266+
#[cfg(not(target_os = "aix"))]
267+
fn create_map(lib: &Library) -> Option<Mapping> {
268+
let name = &lib.name;
269+
Mapping::new(name.as_ref())
270+
}
271+
257272
// unsafe because this is required to be externally synchronized
258273
pub unsafe fn clear_symbol_cache() {
259274
Cache::with_global(|cache| cache.mappings.clear());
@@ -334,8 +349,7 @@ impl Cache {
334349
// When the mapping is not in the cache, create a new mapping,
335350
// insert it into the front of the cache, and evict the oldest cache
336351
// entry if necessary.
337-
let name = &self.libraries[lib].name;
338-
let mapping = Mapping::new(name.as_ref())?;
352+
let mapping = create_map(&self.libraries[lib])?;
339353

340354
if self.mappings.len() == MAPPINGS_CACHE_SIZE {
341355
self.mappings.pop();

src/symbolize/gimli/libs_aix.rs

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use super::mystd::env;
33
use super::mystd::ffi::{CStr, OsStr};
44
use super::mystd::io::Error;
55
use super::mystd::os::unix::prelude::*;
6-
use super::{mmap, xcoff};
6+
use super::xcoff;
77
use super::{Library, LibrarySegment, Vec};
88
use alloc::vec;
99
use core::mem;
@@ -32,26 +32,27 @@ pub(super) fn native_libraries() -> Vec<Library> {
3232
let mut current = buffer.as_ptr() as *mut libc::ld_info;
3333
loop {
3434
let text_base = (*current).ldinfo_textorg as usize;
35-
if text_base != 0 {
36-
let bytes = CStr::from_ptr(&(*current).ldinfo_filename[0]).to_bytes();
37-
let mut name = OsStr::from_bytes(bytes).to_owned();
38-
if text_base == EXE_IMAGE_BASE as usize {
39-
if let Ok(exe) = env::current_exe() {
40-
name = exe.into_os_string();
41-
}
35+
let filename_ptr: *const i8 = &(*current).ldinfo_filename[0];
36+
let bytes = CStr::from_ptr(filename_ptr).to_bytes();
37+
let member_name_ptr = filename_ptr.offset((bytes.len() + 1) as isize);
38+
let mut filename = OsStr::from_bytes(bytes).to_owned();
39+
if text_base == EXE_IMAGE_BASE as usize {
40+
if let Ok(exe) = env::current_exe() {
41+
filename = exe.into_os_string();
4242
}
43-
if let Some(map) = mmap(name.as_ref()) {
44-
if let Some(image) = xcoff::get_text_image(&map) {
45-
ret.push(Library {
46-
name,
47-
segments: vec![LibrarySegment {
48-
stated_virtual_memory_address: image.base as usize,
49-
len: image.size,
50-
}],
51-
bias: (text_base + image.offset).wrapping_sub(image.base as usize),
52-
});
53-
}
54-
};
43+
}
44+
let bytes = CStr::from_ptr(member_name_ptr).to_bytes();
45+
let member_name = OsStr::from_bytes(bytes).to_owned();
46+
if let Some(image) = xcoff::parse_image(filename.as_ref(), &member_name) {
47+
ret.push(Library {
48+
name: filename,
49+
member_name,
50+
segments: vec![LibrarySegment {
51+
stated_virtual_memory_address: image.base as usize,
52+
len: image.size,
53+
}],
54+
bias: (text_base + image.offset).wrapping_sub(image.base as usize),
55+
});
5556
}
5657
if (*current).ldinfo_next == 0 {
5758
break;

src/symbolize/gimli/xcoff.rs

Lines changed: 56 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1+
use super::mystd::ffi::{OsStr, OsString};
2+
use super::mystd::os::unix::ffi::OsStrExt;
13
use super::mystd::str;
24
use super::{Context, Mapping, Path, Stash, Vec};
5+
use core::ops::Deref;
6+
use object::read::archive::ArchiveFile;
37
use object::read::xcoff::FileHeader;
48
use object::read::xcoff::SectionHeader;
59
use object::read::xcoff::XcoffFile;
@@ -13,10 +17,26 @@ type Xcoff = object::xcoff::FileHeader32;
1317
type Xcoff = object::xcoff::FileHeader64;
1418

1519
impl Mapping {
16-
pub fn new(path: &Path) -> Option<Mapping> {
20+
pub fn new(path: &Path, member_name: &OsString) -> Option<Mapping> {
1721
let map = super::mmap(path)?;
1822
Mapping::mk(map, |data, stash| {
19-
Context::new(stash, Object::parse(data)?, None)
23+
if member_name.is_empty() {
24+
Context::new(stash, Object::parse(data)?, None)
25+
} else {
26+
let archive = ArchiveFile::parse(data).ok()?;
27+
for member in archive.members() {
28+
if let Ok(member) = member {
29+
let name = OsStr::from_bytes(member.name());
30+
if name == member_name {
31+
let member_data = member.data(data).ok()?;
32+
if let Some(obj) = Object::parse(member_data) {
33+
return Context::new(stash, obj, None);
34+
}
35+
}
36+
}
37+
}
38+
None
39+
}
2040
})
2141
}
2242
}
@@ -38,10 +58,10 @@ pub struct Image {
3858
pub size: usize,
3959
}
4060

41-
pub fn get_text_image(data: &[u8]) -> Option<Image> {
61+
pub fn parse_xcoff(data: &[u8]) -> Option<Image> {
4262
let mut offset = 0;
4363
let header = Xcoff::parse(data, &mut offset).ok()?;
44-
let aux_header = header.aux_header(data, &mut offset).ok()?;
64+
let _ = header.aux_header(data, &mut offset).ok()?;
4565
let sections = header.sections(data, &mut offset).ok()?;
4666
if let Some(section) = sections.iter().find(|s| {
4767
let name = str::from_utf8(&s.s_name()[0..5]).unwrap();
@@ -56,19 +76,45 @@ pub fn get_text_image(data: &[u8]) -> Option<Image> {
5676
return None;
5777
}
5878

79+
pub fn parse_image(path: &Path, member_name: &OsString) -> Option<Image> {
80+
let map = super::mmap(path)?;
81+
let data = map.deref();
82+
if member_name.is_empty() {
83+
return parse_xcoff(data);
84+
} else {
85+
let archive = ArchiveFile::parse(data).ok()?;
86+
for member in archive.members() {
87+
if let Ok(member) = member {
88+
let name = OsStr::from_bytes(member.name());
89+
if name == member_name {
90+
let member_data = member.data(data).ok()?;
91+
if let Some(image) = parse_xcoff(member_data) {
92+
return Some(image);
93+
}
94+
}
95+
}
96+
}
97+
return None;
98+
}
99+
}
100+
59101
impl<'a> Object<'a> {
60102
fn parse(data: &'a [u8]) -> Option<Object<'a>> {
61103
let file = XcoffFile::parse(data).ok()?;
62104
let mut syms = file
63105
.symbols()
64-
.map(|sym| {
106+
.filter_map(|sym| {
65107
let address = sym.address();
66108
let size = sym.size();
67109
let name = sym.name().map_or("", |v| v);
68-
ParsedSym {
69-
address,
70-
size,
71-
name,
110+
if name == ".text" || name == ".data" {
111+
None
112+
} else {
113+
Some(ParsedSym {
114+
address,
115+
size,
116+
name,
117+
})
72118
}
73119
})
74120
.collect::<Vec<_>>();
@@ -87,7 +133,7 @@ impl<'a> Object<'a> {
87133
};
88134
let sym = self.syms.get(i)?;
89135
if (sym.address..sym.address + sym.size).contains(&addr) {
90-
Some(sym.name.strip_prefix(".")?.as_bytes())
136+
Some(sym.name.trim_start_matches(".").as_bytes())
91137
} else {
92138
None
93139
}

0 commit comments

Comments
 (0)