From 96038c93f70fca6ffc0fc1d5507be392a305ba69 Mon Sep 17 00:00:00 2001 From: Toka Date: Thu, 13 Feb 2025 17:29:13 +0100 Subject: [PATCH] do --- libafl_qemu/src/modules/usermode/asan.rs | 197 +------------------- libafl_qemu/src/modules/utils/addr2lines.rs | 191 +++++++++++++++++++ libafl_qemu/src/modules/utils/mod.rs | 2 + 3 files changed, 200 insertions(+), 190 deletions(-) create mode 100644 libafl_qemu/src/modules/utils/addr2lines.rs diff --git a/libafl_qemu/src/modules/usermode/asan.rs b/libafl_qemu/src/modules/usermode/asan.rs index d9055c8ca5..b1e62c3065 100644 --- a/libafl_qemu/src/modules/usermode/asan.rs +++ b/libafl_qemu/src/modules/usermode/asan.rs @@ -21,7 +21,7 @@ use libc::{ }; use meminterval::{Interval, IntervalTree}; use num_enum::{IntoPrimitive, TryFromPrimitive}; -use object::{Object, ObjectSection}; +use object::Object; use rangemap::RangeMap; use crate::{ @@ -29,7 +29,11 @@ use crate::{ modules::{ calls::FullBacktraceCollector, snapshot::SnapshotModule, - utils::filters::{HasAddressFilter, StdAddressFilter}, + utils::{ + addr2line_legacy, + filters::{HasAddressFilter, StdAddressFilter}, + load_file_section, + }, AddressFilter, EmulatorModule, EmulatorModuleTuple, }, qemu::{Hook, MemAccessInfo, QemuHooks, SyscallHookResult}, @@ -1341,194 +1345,6 @@ where } } -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>, -) -> Result, 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. -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: &R, - ) -> Result { - 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: &R, - ) -> Result { - 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, - 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 - where - R: gimli::Reader, - F: FnMut(Cow<'_, [u8]>, R::Endian) -> R, - { - loader: F, - dwarf_package: Option>, - } - - impl SplitDwarfLoader - where - R: gimli::Reader, - F: FnMut(Cow<'_, [u8]>, R::Endian) -> R, - { - fn load_dwarf_package( - loader: &mut F, - path: Option, - ) -> Option> { - 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) -> SplitDwarfLoader { - 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(&mut self, mut l: LookupResult) -> L::Output - where - L: LookupContinuation, - { - loop { - let (load, continuation) = match l { - LookupResult::Output(output) => break output, - LookupResult::Load { load, continuation } => (load, continuation), - }; - - let mut r: Option>> = 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); - } - } - } -} - /// # Safety /// Will access the global [`FullBacktraceCollector`]. /// Calling this function concurrently might be racey. @@ -1651,6 +1467,7 @@ pub unsafe fn asan_report(rt: &AsanGiovese, qemu: Qemu, pc: GuestAddr, err: &Asa info }; + // TODO, make a class Resolver for resolving the addresses?? eprintln!("================================================================="); let backtrace = FullBacktraceCollector::backtrace() .map(|r| { diff --git a/libafl_qemu/src/modules/utils/addr2lines.rs b/libafl_qemu/src/modules/utils/addr2lines.rs new file mode 100644 index 0000000000..0719eb2f87 --- /dev/null +++ b/libafl_qemu/src/modules/utils/addr2lines.rs @@ -0,0 +1,191 @@ +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>, +) -> Result, 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: &R, + ) -> Result { + 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: &R, + ) -> Result { + 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, + 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 + where + R: gimli::Reader, + F: FnMut(Cow<'_, [u8]>, R::Endian) -> R, + { + loader: F, + dwarf_package: Option>, + } + + impl SplitDwarfLoader + where + R: gimli::Reader, + F: FnMut(Cow<'_, [u8]>, R::Endian) -> R, + { + fn load_dwarf_package( + loader: &mut F, + path: Option, + ) -> Option> { + 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) -> SplitDwarfLoader { + 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(&mut self, mut l: LookupResult) -> L::Output + where + L: LookupContinuation, + { + loop { + let (load, continuation) = match l { + LookupResult::Output(output) => break output, + LookupResult::Load { load, continuation } => (load, continuation), + }; + + let mut r: Option>> = 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); + } + } + } +} diff --git a/libafl_qemu/src/modules/utils/mod.rs b/libafl_qemu/src/modules/utils/mod.rs index 2589ce38d4..54dc6737e9 100644 --- a/libafl_qemu/src/modules/utils/mod.rs +++ b/libafl_qemu/src/modules/utils/mod.rs @@ -1 +1,3 @@ +pub mod addr2lines; pub mod filters; +pub use addr2lines::*;