Better addr2line (#2989)
* better addr2line * delete unused * more * fixer? * lol * class * mm * take care of non pie binary or pie binary * user mode only
This commit is contained in:
parent
0aba2c4520
commit
8b49d81406
@ -3,11 +3,9 @@
|
|||||||
|
|
||||||
use core::{fmt, slice};
|
use core::{fmt, slice};
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Cow,
|
|
||||||
env,
|
env,
|
||||||
fmt::{Debug, Display, Write},
|
fmt::{Debug, Display},
|
||||||
fs,
|
fs,
|
||||||
path::PathBuf,
|
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
sync::Mutex,
|
sync::Mutex,
|
||||||
};
|
};
|
||||||
@ -21,19 +19,13 @@ use libc::{
|
|||||||
};
|
};
|
||||||
use meminterval::{Interval, IntervalTree};
|
use meminterval::{Interval, IntervalTree};
|
||||||
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
use num_enum::{IntoPrimitive, TryFromPrimitive};
|
||||||
use object::Object;
|
|
||||||
use rangemap::RangeMap;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
emu::EmulatorModules,
|
emu::EmulatorModules,
|
||||||
modules::{
|
modules::{
|
||||||
calls::FullBacktraceCollector,
|
calls::FullBacktraceCollector,
|
||||||
snapshot::SnapshotModule,
|
snapshot::SnapshotModule,
|
||||||
utils::{
|
utils::filters::{HasAddressFilter, StdAddressFilter},
|
||||||
addr2line_legacy,
|
|
||||||
filters::{HasAddressFilter, StdAddressFilter},
|
|
||||||
load_file_section,
|
|
||||||
},
|
|
||||||
AddressFilter, EmulatorModule, EmulatorModuleTuple,
|
AddressFilter, EmulatorModule, EmulatorModuleTuple,
|
||||||
},
|
},
|
||||||
qemu::{Hook, MemAccessInfo, QemuHooks, SyscallHookResult},
|
qemu::{Hook, MemAccessInfo, QemuHooks, SyscallHookResult},
|
||||||
@ -1348,126 +1340,8 @@ where
|
|||||||
/// # Safety
|
/// # Safety
|
||||||
/// Will access the global [`FullBacktraceCollector`].
|
/// Will access the global [`FullBacktraceCollector`].
|
||||||
/// Calling this function concurrently might be racey.
|
/// Calling this function concurrently might be racey.
|
||||||
#[expect(clippy::too_many_lines, clippy::unnecessary_cast)]
|
|
||||||
pub unsafe fn asan_report(rt: &AsanGiovese, qemu: Qemu, pc: GuestAddr, err: &AsanError) {
|
pub unsafe fn asan_report(rt: &AsanGiovese, qemu: Qemu, pc: GuestAddr, err: &AsanError) {
|
||||||
let mut regions = HashMap::new();
|
let resolver = crate::modules::utils::addr2line::AddressResolver::new(&qemu);
|
||||||
for region in qemu.mappings() {
|
|
||||||
if let Some(path) = region.path() {
|
|
||||||
let start = region.start();
|
|
||||||
let end = region.end();
|
|
||||||
let entry = regions.entry(path.to_owned()).or_insert(start..end);
|
|
||||||
if start < entry.start {
|
|
||||||
*entry = start..entry.end;
|
|
||||||
}
|
|
||||||
if end > entry.end {
|
|
||||||
*entry = entry.start..end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut resolvers = vec![];
|
|
||||||
let mut images = vec![];
|
|
||||||
let mut ranges = RangeMap::new();
|
|
||||||
|
|
||||||
for (path, rng) in regions {
|
|
||||||
let data = fs::read(&path);
|
|
||||||
if data.is_err() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let data = data.unwrap();
|
|
||||||
let idx = images.len();
|
|
||||||
images.push((path, data));
|
|
||||||
ranges.insert(rng, idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
let arena_data = typed_arena::Arena::new();
|
|
||||||
|
|
||||||
for img in &images {
|
|
||||||
if let Ok(obj) = object::read::File::parse(&*img.1) {
|
|
||||||
let endian = if obj.is_little_endian() {
|
|
||||||
addr2line::gimli::RunTimeEndian::Little
|
|
||||||
} else {
|
|
||||||
addr2line::gimli::RunTimeEndian::Big
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut load_section = |id: addr2line::gimli::SectionId| -> Result<_, _> {
|
|
||||||
load_file_section(id, &obj, endian, &arena_data)
|
|
||||||
};
|
|
||||||
|
|
||||||
let dwarf = addr2line::gimli::Dwarf::load(&mut load_section).unwrap();
|
|
||||||
let ctx = addr2line::Context::from_dwarf(dwarf)
|
|
||||||
.expect("Failed to create an addr2line context");
|
|
||||||
|
|
||||||
//let ctx = addr2line::Context::new(&obj).expect("Failed to create an addr2line context");
|
|
||||||
resolvers.push(Some((obj, ctx)));
|
|
||||||
} else {
|
|
||||||
resolvers.push(None);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let resolve_addr = |addr: GuestAddr| -> String {
|
|
||||||
let mut info = String::new();
|
|
||||||
if let Some((rng, idx)) = ranges.get_key_value(&addr) {
|
|
||||||
let raddr = (addr - rng.start) as u64;
|
|
||||||
if let Some((obj, ctx)) = resolvers[*idx].as_ref() {
|
|
||||||
let symbols = obj.symbol_map();
|
|
||||||
let mut func = symbols.get(raddr).map(|x| x.name().to_string());
|
|
||||||
|
|
||||||
if func.is_none() {
|
|
||||||
let pathname = PathBuf::from(images[*idx].0.clone());
|
|
||||||
let mut split_dwarf_loader = addr2line_legacy::SplitDwarfLoader::new(
|
|
||||||
|data, endian| {
|
|
||||||
addr2line::gimli::EndianSlice::new(
|
|
||||||
arena_data.alloc(Cow::Owned(data.into_owned())),
|
|
||||||
endian,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
Some(pathname),
|
|
||||||
);
|
|
||||||
|
|
||||||
let frames = ctx.find_frames(raddr);
|
|
||||||
if let Ok(mut frames) = split_dwarf_loader.run(frames) {
|
|
||||||
if let Some(frame) = frames.next().unwrap_or(None) {
|
|
||||||
if let Some(function) = frame.function {
|
|
||||||
if let Ok(name) = function.raw_name() {
|
|
||||||
let demangled =
|
|
||||||
addr2line::demangle_auto(name, function.language);
|
|
||||||
func = Some(demangled.to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(name) = func {
|
|
||||||
info += " in ";
|
|
||||||
info += &name;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(loc) = ctx.find_location(raddr).unwrap_or(None) {
|
|
||||||
if info.is_empty() {
|
|
||||||
info += " in";
|
|
||||||
}
|
|
||||||
info += " ";
|
|
||||||
if let Some(file) = loc.file {
|
|
||||||
info += file;
|
|
||||||
}
|
|
||||||
if let Some(line) = loc.line {
|
|
||||||
info += ":";
|
|
||||||
info += &line.to_string();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let _ = write!(&mut info, " ({}+{raddr:#x})", images[*idx].0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if info.is_empty() {
|
|
||||||
let _ = write!(&mut info, " ({}+{raddr:#x})", images[*idx].0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
info
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO, make a class Resolver for resolving the addresses??
|
|
||||||
eprintln!("=================================================================");
|
eprintln!("=================================================================");
|
||||||
let backtrace = FullBacktraceCollector::backtrace()
|
let backtrace = FullBacktraceCollector::backtrace()
|
||||||
.map(|r| {
|
.map(|r| {
|
||||||
@ -1478,7 +1352,7 @@ pub unsafe fn asan_report(rt: &AsanGiovese, qemu: Qemu, pc: GuestAddr, err: &Asa
|
|||||||
.unwrap_or(vec![pc]);
|
.unwrap_or(vec![pc]);
|
||||||
eprintln!("AddressSanitizer Error: {err}");
|
eprintln!("AddressSanitizer Error: {err}");
|
||||||
for (i, addr) in backtrace.iter().rev().enumerate() {
|
for (i, addr) in backtrace.iter().rev().enumerate() {
|
||||||
eprintln!("\t#{i} {addr:#x}{}", resolve_addr(*addr));
|
eprintln!("\t#{i} {addr:#x}{}", resolver.resolve(*addr));
|
||||||
}
|
}
|
||||||
let addr = match err {
|
let addr = match err {
|
||||||
AsanError::Read(addr, _) | AsanError::Write(addr, _) | AsanError::BadFree(addr, _) => {
|
AsanError::Read(addr, _) | AsanError::Write(addr, _) | AsanError::BadFree(addr, _) => {
|
||||||
@ -1493,13 +1367,13 @@ pub unsafe fn asan_report(rt: &AsanGiovese, qemu: Qemu, pc: GuestAddr, err: &Asa
|
|||||||
} else {
|
} else {
|
||||||
eprintln!("Freed at:");
|
eprintln!("Freed at:");
|
||||||
for (i, addr) in item.free_backtrace.iter().rev().enumerate() {
|
for (i, addr) in item.free_backtrace.iter().rev().enumerate() {
|
||||||
eprintln!("\t#{i} {addr:#x}{}", resolve_addr(*addr));
|
eprintln!("\t#{i} {addr:#x}{}", resolver.resolve(*addr));
|
||||||
}
|
}
|
||||||
eprintln!("And previously allocated at:");
|
eprintln!("And previously allocated at:");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i, addr) in item.backtrace.iter().rev().enumerate() {
|
for (i, addr) in item.backtrace.iter().rev().enumerate() {
|
||||||
eprintln!("\t#{i} {addr:#x}{}", resolve_addr(*addr));
|
eprintln!("\t#{i} {addr:#x}{}", resolver.resolve(*addr));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
166
libafl_qemu/src/modules/utils/addr2line.rs
Normal file
166
libafl_qemu/src/modules/utils/addr2line.rs
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
//! Utils for addr2line
|
||||||
|
|
||||||
|
use std::{borrow::Cow, fmt::Write, fs};
|
||||||
|
|
||||||
|
use addr2line::{fallible_iterator::FallibleIterator, Loader};
|
||||||
|
use goblin::elf::dynamic::{DF_1_PIE, DT_FLAGS_1};
|
||||||
|
use hashbrown::HashMap;
|
||||||
|
use libafl_qemu_sys::GuestAddr;
|
||||||
|
use rangemap::RangeMap;
|
||||||
|
|
||||||
|
use crate::Qemu;
|
||||||
|
// (almost) Copy paste from addr2line/src/bin/addr2line.rs
|
||||||
|
fn print_function(name: Option<&str>, language: Option<addr2line::gimli::DwLang>) -> String {
|
||||||
|
let ret = if let Some(name) = name {
|
||||||
|
addr2line::demangle_auto(Cow::from(name), language).to_string()
|
||||||
|
} else {
|
||||||
|
"??".to_string()
|
||||||
|
};
|
||||||
|
// println!("{ret:?}");
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
/// check if this binary is pie (for 64bit binary only)
|
||||||
|
#[must_use]
|
||||||
|
pub fn is_pie(file: object::File<'_>) -> bool {
|
||||||
|
let is_pie = match file {
|
||||||
|
object::File::Elf64(elf) => {
|
||||||
|
let mut is_pie = false;
|
||||||
|
let table = elf.elf_section_table();
|
||||||
|
let dyn_sec = table.dynamic(elf.endian(), elf.data());
|
||||||
|
if let Ok(Some(d)) = dyn_sec {
|
||||||
|
let arr = d.0;
|
||||||
|
for v in arr {
|
||||||
|
if v.d_tag.get(elf.endian()) == DT_FLAGS_1
|
||||||
|
&& v.d_val.get(elf.endian()) & DF_1_PIE == DF_1_PIE
|
||||||
|
{
|
||||||
|
is_pie = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
is_pie
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
is_pie
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AddressResolver {
|
||||||
|
ranges: RangeMap<GuestAddr, usize>,
|
||||||
|
images: Vec<(String, Vec<u8>)>,
|
||||||
|
resolvers: Vec<Option<(Loader, bool)>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AddressResolver {
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(qemu: &Qemu) -> Self {
|
||||||
|
let mut regions = HashMap::new();
|
||||||
|
for region in qemu.mappings() {
|
||||||
|
if let Some(path) = region.path() {
|
||||||
|
let start = region.start();
|
||||||
|
let end = region.end();
|
||||||
|
let entry = regions.entry(path.to_owned()).or_insert(start..end);
|
||||||
|
if start < entry.start {
|
||||||
|
*entry = start..entry.end;
|
||||||
|
}
|
||||||
|
if end > entry.end {
|
||||||
|
*entry = entry.start..end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut resolvers = vec![];
|
||||||
|
let mut images = vec![];
|
||||||
|
let mut ranges: RangeMap<GuestAddr, usize> = RangeMap::new();
|
||||||
|
|
||||||
|
for (path, rng) in regions {
|
||||||
|
let data = fs::read(&path);
|
||||||
|
if data.is_err() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let data = data.unwrap();
|
||||||
|
let idx = images.len();
|
||||||
|
images.push((path, data));
|
||||||
|
ranges.insert(rng, idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
for img in &images {
|
||||||
|
if let Ok(obj) = object::read::File::parse(&*img.1) {
|
||||||
|
let is_pie = is_pie(obj);
|
||||||
|
|
||||||
|
let ctx = Loader::new(img.0.clone()).unwrap();
|
||||||
|
resolvers.push(Some((ctx, is_pie)));
|
||||||
|
} else {
|
||||||
|
resolvers.push(None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self {
|
||||||
|
ranges,
|
||||||
|
images,
|
||||||
|
resolvers,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn resolve(&self, pc: GuestAddr) -> String {
|
||||||
|
let resolve_addr = |addr: GuestAddr| -> String {
|
||||||
|
let mut info = String::new();
|
||||||
|
if let Some((range, idx)) = self.ranges.get_key_value(&addr) {
|
||||||
|
if let Some((ctx, is_pie)) = self.resolvers[*idx].as_ref() {
|
||||||
|
let raddr = if *is_pie { addr - range.start } else { addr };
|
||||||
|
let mut frames = ctx.find_frames(raddr.into()).unwrap().peekable();
|
||||||
|
let mut fname = None;
|
||||||
|
while let Some(frame) = frames.next().unwrap() {
|
||||||
|
// Only use the symbol table if this isn't an inlined function.
|
||||||
|
let symbol = if matches!(frames.peek(), Ok(None)) {
|
||||||
|
ctx.find_symbol(raddr.into())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
if symbol.is_some() {
|
||||||
|
// Prefer the symbol table over the DWARF name because:
|
||||||
|
// - the symbol can include a clone suffix
|
||||||
|
// - llvm may omit the linkage name in the DWARF with -g1
|
||||||
|
fname = Some(print_function(symbol, None));
|
||||||
|
} else if let Some(func) = frame.function {
|
||||||
|
fname = Some(print_function(
|
||||||
|
func.raw_name().ok().as_deref(),
|
||||||
|
func.language,
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
fname = Some(print_function(None, None));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(name) = fname {
|
||||||
|
info += " in ";
|
||||||
|
info += &name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(loc) = ctx.find_location(raddr.into()).unwrap_or(None) {
|
||||||
|
if info.is_empty() {
|
||||||
|
info += " in";
|
||||||
|
}
|
||||||
|
info += " ";
|
||||||
|
if let Some(file) = loc.file {
|
||||||
|
info += file;
|
||||||
|
}
|
||||||
|
if let Some(line) = loc.line {
|
||||||
|
info += ":";
|
||||||
|
info += &line.to_string();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let _ = write!(&mut info, " ({}+{addr:#x})", self.images[*idx].0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if info.is_empty() {
|
||||||
|
let _ = write!(&mut info, " ({}+{addr:#x})", self.images[*idx].0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info
|
||||||
|
};
|
||||||
|
|
||||||
|
resolve_addr(pc)
|
||||||
|
}
|
||||||
|
}
|
@ -1,191 +0,0 @@
|
|||||||
use std::borrow::Cow;
|
|
||||||
|
|
||||||
use object::{Object, ObjectSection};
|
|
||||||
|
|
||||||
pub fn load_file_section<'input, 'arena, Endian: addr2line::gimli::Endianity>(
|
|
||||||
id: addr2line::gimli::SectionId,
|
|
||||||
file: &object::File<'input>,
|
|
||||||
endian: Endian,
|
|
||||||
arena_data: &'arena typed_arena::Arena<Cow<'input, [u8]>>,
|
|
||||||
) -> Result<addr2line::gimli::EndianSlice<'arena, Endian>, object::Error> {
|
|
||||||
// TODO: Unify with dwarfdump.rs in gimli.
|
|
||||||
let name = id.name();
|
|
||||||
match file.section_by_name(name) {
|
|
||||||
Some(section) => match section.uncompressed_data()? {
|
|
||||||
Cow::Borrowed(b) => Ok(addr2line::gimli::EndianSlice::new(b, endian)),
|
|
||||||
Cow::Owned(b) => Ok(addr2line::gimli::EndianSlice::new(
|
|
||||||
arena_data.alloc(b.into()),
|
|
||||||
endian,
|
|
||||||
)),
|
|
||||||
},
|
|
||||||
None => Ok(addr2line::gimli::EndianSlice::new(&[][..], endian)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Taken from `addr2line` [v0.22](https://github.com/gimli-rs/addr2line/blob/5c3c83f74f992220b2d9a17b3ac498a89214bf92/src/builtin_split_dwarf_loader.rs)
|
|
||||||
/// has been removed in version v0.23 for some reason.
|
|
||||||
/// TODO: find another cleaner solution.
|
|
||||||
pub mod addr2line_legacy {
|
|
||||||
use std::{borrow::Cow, env, ffi::OsString, fs::File, path::PathBuf, sync::Arc};
|
|
||||||
|
|
||||||
use addr2line::{gimli, LookupContinuation, LookupResult};
|
|
||||||
use object::Object;
|
|
||||||
|
|
||||||
#[cfg(unix)]
|
|
||||||
fn convert_path<R: gimli::Reader<Endian = gimli::RunTimeEndian>>(
|
|
||||||
r: &R,
|
|
||||||
) -> Result<PathBuf, gimli::Error> {
|
|
||||||
use std::{ffi::OsStr, os::unix::ffi::OsStrExt};
|
|
||||||
let bytes = r.to_slice()?;
|
|
||||||
let s = OsStr::from_bytes(&bytes);
|
|
||||||
Ok(PathBuf::from(s))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(unix))]
|
|
||||||
fn convert_path<R: gimli::Reader<Endian = gimli::RunTimeEndian>>(
|
|
||||||
r: &R,
|
|
||||||
) -> Result<PathBuf, gimli::Error> {
|
|
||||||
let bytes = r.to_slice()?;
|
|
||||||
let s = str::from_utf8(&bytes).map_err(|_| gimli::Error::BadUtf8)?;
|
|
||||||
Ok(PathBuf::from(s))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_section<'data, O, R, F>(
|
|
||||||
id: gimli::SectionId,
|
|
||||||
file: &O,
|
|
||||||
endian: R::Endian,
|
|
||||||
loader: &mut F,
|
|
||||||
) -> R
|
|
||||||
where
|
|
||||||
O: Object<'data>,
|
|
||||||
R: gimli::Reader<Endian = gimli::RunTimeEndian>,
|
|
||||||
F: FnMut(Cow<'data, [u8]>, R::Endian) -> R,
|
|
||||||
{
|
|
||||||
use object::ObjectSection;
|
|
||||||
|
|
||||||
let data = id
|
|
||||||
.dwo_name()
|
|
||||||
.and_then(|dwo_name| {
|
|
||||||
file.section_by_name(dwo_name)
|
|
||||||
.and_then(|section| section.uncompressed_data().ok())
|
|
||||||
})
|
|
||||||
.unwrap_or(Cow::Borrowed(&[]));
|
|
||||||
loader(data, endian)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A simple builtin split DWARF loader.
|
|
||||||
pub struct SplitDwarfLoader<R, F>
|
|
||||||
where
|
|
||||||
R: gimli::Reader<Endian = gimli::RunTimeEndian>,
|
|
||||||
F: FnMut(Cow<'_, [u8]>, R::Endian) -> R,
|
|
||||||
{
|
|
||||||
loader: F,
|
|
||||||
dwarf_package: Option<gimli::DwarfPackage<R>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R, F> SplitDwarfLoader<R, F>
|
|
||||||
where
|
|
||||||
R: gimli::Reader<Endian = gimli::RunTimeEndian>,
|
|
||||||
F: FnMut(Cow<'_, [u8]>, R::Endian) -> R,
|
|
||||||
{
|
|
||||||
fn load_dwarf_package(
|
|
||||||
loader: &mut F,
|
|
||||||
path: Option<PathBuf>,
|
|
||||||
) -> Option<gimli::DwarfPackage<R>> {
|
|
||||||
let mut path = path.map_or_else(env::current_exe, Ok).ok()?;
|
|
||||||
let dwp_extension = path.extension().map_or_else(
|
|
||||||
|| OsString::from("dwp"),
|
|
||||||
|previous_extension| {
|
|
||||||
let mut previous_extension = previous_extension.to_os_string();
|
|
||||||
previous_extension.push(".dwp");
|
|
||||||
previous_extension
|
|
||||||
},
|
|
||||||
);
|
|
||||||
path.set_extension(dwp_extension);
|
|
||||||
let file = File::open(&path).ok()?;
|
|
||||||
let map = unsafe { memmap2::Mmap::map(&file).ok()? };
|
|
||||||
let dwp = object::File::parse(&*map).ok()?;
|
|
||||||
|
|
||||||
let endian = if dwp.is_little_endian() {
|
|
||||||
gimli::RunTimeEndian::Little
|
|
||||||
} else {
|
|
||||||
gimli::RunTimeEndian::Big
|
|
||||||
};
|
|
||||||
|
|
||||||
let empty = loader(Cow::Borrowed(&[]), endian);
|
|
||||||
gimli::DwarfPackage::load::<_, gimli::Error>(
|
|
||||||
|section_id| Ok(load_section(section_id, &dwp, endian, loader)),
|
|
||||||
empty,
|
|
||||||
)
|
|
||||||
.ok()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a new split DWARF loader.
|
|
||||||
pub fn new(mut loader: F, path: Option<PathBuf>) -> SplitDwarfLoader<R, F> {
|
|
||||||
let dwarf_package = SplitDwarfLoader::load_dwarf_package(&mut loader, path);
|
|
||||||
SplitDwarfLoader {
|
|
||||||
loader,
|
|
||||||
dwarf_package,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Run the provided `LookupResult` to completion, loading any necessary
|
|
||||||
/// split DWARF along the way.
|
|
||||||
pub fn run<L>(&mut self, mut l: LookupResult<L>) -> L::Output
|
|
||||||
where
|
|
||||||
L: LookupContinuation<Buf = R>,
|
|
||||||
{
|
|
||||||
loop {
|
|
||||||
let (load, continuation) = match l {
|
|
||||||
LookupResult::Output(output) => break output,
|
|
||||||
LookupResult::Load { load, continuation } => (load, continuation),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut r: Option<Arc<gimli::Dwarf<_>>> = None;
|
|
||||||
if let Some(dwp) = self.dwarf_package.as_ref() {
|
|
||||||
if let Ok(Some(cu)) = dwp.find_cu(load.dwo_id, &load.parent) {
|
|
||||||
r = Some(Arc::new(cu));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if r.is_none() {
|
|
||||||
let mut path = PathBuf::new();
|
|
||||||
if let Some(p) = load.comp_dir.as_ref() {
|
|
||||||
if let Ok(p) = convert_path(p) {
|
|
||||||
path.push(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(p) = load.path.as_ref() {
|
|
||||||
if let Ok(p) = convert_path(p) {
|
|
||||||
path.push(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Ok(file) = File::open(&path) {
|
|
||||||
if let Ok(map) = unsafe { memmap2::Mmap::map(&file) } {
|
|
||||||
if let Ok(file) = object::File::parse(&*map) {
|
|
||||||
let endian = if file.is_little_endian() {
|
|
||||||
gimli::RunTimeEndian::Little
|
|
||||||
} else {
|
|
||||||
gimli::RunTimeEndian::Big
|
|
||||||
};
|
|
||||||
|
|
||||||
r = gimli::Dwarf::load::<_, gimli::Error>(|id| {
|
|
||||||
Ok(load_section(id, &file, endian, &mut self.loader))
|
|
||||||
})
|
|
||||||
.ok()
|
|
||||||
.map(|mut dwo_dwarf| {
|
|
||||||
dwo_dwarf.make_dwo(&load.parent);
|
|
||||||
Arc::new(dwo_dwarf)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
l = continuation.resume(r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,3 +1,6 @@
|
|||||||
pub mod addr2lines;
|
|
||||||
pub mod filters;
|
pub mod filters;
|
||||||
pub use addr2lines::*;
|
|
||||||
|
#[cfg(feature = "usermode")]
|
||||||
|
pub use addr2line::*;
|
||||||
|
#[cfg(feature = "usermode")]
|
||||||
|
pub mod addr2line;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user