Skip to content

Commit

Permalink
buncha stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
0vercl0k committed Jun 11, 2024
1 parent 5ec62e3 commit 61f4c63
Show file tree
Hide file tree
Showing 12 changed files with 355 additions and 98 deletions.
7 changes: 6 additions & 1 deletion crates/symbolizer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,9 @@ anyhow = "1.0.86"
[dev-dependencies]
kdmp-parser = "0.2"
udmp-parser = "0.2"
object = {version = "0.36.0", default-features = false, features = ["read", "read_core", "pe", "std"]}
object = { version = "0.36.0", default-features = false, features = [
"read",
"read_core",
"pe",
"std",
] }
62 changes: 28 additions & 34 deletions crates/symbolizer/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,44 @@ pub struct Symcache(PathBuf);

/// Builder for [`Symbolizer`].
#[derive(Default, Debug)]
pub struct Builder<SC, M> {
pub struct Builder<SC> {
symcache: SC,
modules: Vec<Module>,
mode: M,
mode: PdbLookupMode,
}

#[derive(Default)]
pub struct Offline;
pub struct Online(Vec<String>);
impl<SC> Builder<SC> {
pub fn msft_symsrv(self) -> Builder<SC> {
let Self {
symcache, modules, ..
} = self;

impl<SC> Builder<SC, Offline> {
pub fn online(self, symsrvs: impl Iterator<Item = impl Into<String>>) -> Builder<SC, Online> {
Builder {
symcache,
modules,
mode: PdbLookupMode::Online {
symsrvs: vec!["https://msdl.microsoft.com/download/symbols/".into()],
},
}
}

pub fn online(self, symsrvs: impl Iterator<Item = impl Into<String>>) -> Builder<SC> {
let Self {
symcache, modules, ..
} = self;

Builder {
symcache,
modules,
mode: Online(symsrvs.map(Into::into).collect()),
mode: PdbLookupMode::Online {
symsrvs: symsrvs.map(Into::into).collect(),
},
}
}
}

impl<M> Builder<NoSymcache, M> {
pub fn symcache(self, cache: &impl AsRef<Path>) -> Builder<Symcache, M> {
impl Builder<NoSymcache> {
pub fn symcache(self, cache: &impl AsRef<Path>) -> Builder<Symcache> {
let Self { modules, mode, .. } = self;

Builder {
Expand All @@ -47,34 +59,16 @@ impl<M> Builder<NoSymcache, M> {
}
}

impl<SC, M> Builder<SC, M> {
pub fn modules(mut self, modules: impl Iterator<Item = Module>) -> Self {
self.modules = modules.collect();
impl<SC> Builder<SC> {
pub fn modules<'a>(mut self, modules: impl IntoIterator<Item = &'a Module>) -> Self {
self.modules = modules.into_iter().cloned().collect();

self
}
}

impl Builder<Symcache, Offline> {
pub fn build<AS>(self, addr_space: AS) -> Result<Symbolizer<AS>>
where
AS: AddrSpace,
{
let Self {
symcache, modules, ..
} = self;
let config = Config {
symcache: symcache.0,
modules,
mode: PdbLookupMode::Offline,
};

Symbolizer::new(addr_space, config)
}
}

impl Builder<Symcache, Online> {
pub fn build<AS>(self, addr_space: AS) -> Result<Symbolizer<AS>>
impl Builder<Symcache> {
pub fn build<AS>(self, addr_space: &mut AS) -> Result<Symbolizer<AS>>
where
AS: AddrSpace,
{
Expand All @@ -86,7 +80,7 @@ impl Builder<Symcache, Online> {
let config = Config {
symcache: symcache.0,
modules,
mode: PdbLookupMode::Online { symcache: mode.0 },
mode,
};

Symbolizer::new(addr_space, config)
Expand Down
11 changes: 8 additions & 3 deletions crates/symbolizer/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// Axel '0vercl0k' Souchet - May 27 2024
use std::io;
use std::num::TryFromIntError;
use std::num::{ParseIntError, TryFromIntError};
use std::path::PathBuf;
use std::str::Utf8Error;
use std::string::FromUtf8Error;

use pdb::PdbInternalSectionOffset;
Expand All @@ -16,9 +17,13 @@ pub enum Error {
#[error("pdb error: {0}")]
Pdb(#[from] pdb::Error),
#[error("from int error: {0}")]
FromIntError(#[from] TryFromIntError),
FromInt(#[from] TryFromIntError),
#[error("parse int error: {0}")]
ParseInt(#[from] ParseIntError),
#[error("utf8: {0}")]
Utf8(#[from] FromUtf8Error),
Utf8(#[from] Utf8Error),
#[error("from utf8: {0}")]
FromUtf8(#[from] FromUtf8Error),
#[error("pdb path {0:?} does not have a filename")]
PdbPathNoName(PathBuf),
#[error("failed to perform an i/o: {0}")]
Expand Down
103 changes: 102 additions & 1 deletion crates/symbolizer/src/guid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,42 @@
//! This module contains the implementation of the [`Guid`] type.
use std::fmt::Display;

use anyhow::anyhow;

use crate::Error;

/// A GUID.
#[derive(Default, Debug)]
#[derive(Default, Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub struct Guid {
d0: u32,
d1: u16,
d2: u16,
d3: [u8; 8],
}

impl TryFrom<&str> for Guid {
type Error = Error;

fn try_from(value: &str) -> Result<Self, Self::Error> {
if value.len() != 32 {
return Err(anyhow!("the guid str ({value:?}) should be 32 bytes long").into());
}

let mut bytes = [0; 16];
for (n, chunk) in value.as_bytes().chunks_exact(2).enumerate() {
let s = std::str::from_utf8(chunk)?;
bytes[n] = u8::from_str_radix(s, 16)?;
}

let d0 = u32::from_be_bytes(bytes[0..4].try_into().unwrap());
let d1 = u16::from_be_bytes(bytes[4..6].try_into().unwrap());
let d2 = u16::from_be_bytes(bytes[6..8].try_into().unwrap());
let d3 = bytes[8..].try_into().unwrap();

Ok(Self { d0, d1, d2, d3 })
}
}

impl From<[u8; 16]> for Guid {
fn from(value: [u8; 16]) -> Self {
let d0 = u32::from_le_bytes(value[0..4].try_into().unwrap());
Expand Down Expand Up @@ -40,3 +67,77 @@ impl Display for Guid {
))
}
}

#[cfg(test)]
mod tests {
use crate::Guid;

const NTDLL_GUID: Guid = Guid {
d0: 0x8d5d5ed5,
d1: 0xd5b8,
d2: 0xaa60,
d3: [0x9a, 0x82, 0x60, 0x0c, 0x14, 0xe3, 0x00, 0x4d],
};

#[test]
fn malformed_guids() {
assert!(Guid::try_from("8D5D5ED5D5B8AA609A82600C14E3004D1").is_err());

assert!(Guid::try_from("8D5D5ED5D5B8AA609A82600C14E3004").is_err());
}

#[test]
fn non_hex_guids() {
assert!(Guid::try_from("8D5D5ED5D5B8AA609A82600C14E3004Z").is_err());
}

#[test]
fn str() {
// 0:000> lmvm ntdll
// Browse full module list
// start end module name
// 00007ff9`aa450000 00007ff9`aa667000 ntdll (pdb symbols)
// c:\dbg\sym\ntdll.pdb\8D5D5ED5D5B8AA609A82600C14E3004D1\ntdll.pdb
assert_eq!(
Guid::try_from("8D5D5ED5D5B8AA609A82600C14E3004D").unwrap(),
NTDLL_GUID
)
}

#[test]
fn from() {
// 0:000> !dh ntdll
// ...
// SECTION HEADER #5
// .rdata name
// 4D210 virtual size
// 132000 virtual address
// 4E000 size of raw data
// 132000 file pointer to raw data
// 0 file pointer to relocation table
// 0 file pointer to line numbers
// 0 number of relocations
// 0 number of line numbers
// 40000040 flags
// Initialized Data
// (no align specified)
// Read Only
// ...
// Debug Directories(4)
// Type Size Address Pointer
// cv 22 15b880 15b880 Format: RSDS, guid, 1, ntdll.pdb
//
// 0:000> db ntdll+15b880
// 00007ff9`aa5ab880 52 53 44 53 d5 5e 5d 8d-b8 d5 60 aa 9a 82 60 0c
// RSDS.^]...`...`. 00007ff9`aa5ab890 14 e3 00 4d 01 00 00 00-6e 74 64
// 6c 6c 2e 70 64 ...M....ntdll.pd

assert_eq!(
Guid::from([
0xd5, 0x5e, 0x5d, 0x8d, 0xb8, 0xd5, 0x60, 0xaa, 0x9a, 0x82, 0x60, 0x0c, 0x14, 0xe3,
0x00, 0x4d
]),
NTDLL_GUID
)
}
}
2 changes: 2 additions & 0 deletions crates/symbolizer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ mod symbolizer;
pub use addr_space::AddrSpace;
pub use builder::Builder;
pub use error::{Error, Result};
pub use guid::Guid;
pub use modules::{Module, Modules};
pub use pe::PdbId;
pub use stats::Stats;
pub use symbolizer::Symbolizer;
2 changes: 1 addition & 1 deletion crates/symbolizer/src/modules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::ops::Range;
use crate::misc::Rva;

/// A user or kernel module.
#[derive(Debug, Default)]
#[derive(Debug, Default, Clone)]
pub struct Module {
/// Where the module is loaded into virtual memory.
pub at: Range<u64>,
Expand Down
5 changes: 3 additions & 2 deletions crates/symbolizer/src/pe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ pub const IMAGE_DEBUG_TYPE_CODEVIEW: u32 = 2;
///
/// To download a PDB off Microsoft's Symbol Server, we need three pieces of
/// information: the pdb name, a guid and its age.
#[derive(Debug, Default)]
#[derive(Debug, Default, PartialEq, Eq, Hash, Clone)]
pub struct PdbId {
pub path: PathBuf,
pub guid: Guid,
Expand All @@ -206,7 +206,8 @@ impl Display for PdbId {
}

impl PdbId {
pub fn new(path: PathBuf, guid: Guid, age: u32) -> Result<Self> {
pub fn new(path: impl Into<PathBuf>, guid: Guid, age: u32) -> Result<Self> {
let path = path.into();
if path.file_name().is_none() {
return Err(E::PdbPathNoName(path));
}
Expand Down
44 changes: 34 additions & 10 deletions crates/symbolizer/src/stats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,59 @@
//! This module contains the [`Stats`] type that is used to keep track of
//! various statistics when symbolizing.
use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt::Debug;

use crate::pe::PdbId;

#[derive(Debug, Default)]
pub struct StatsBuilder {
inner: RefCell<Stats>,
}

/// Various statistics that the symbolizer keeps track of.
#[derive(Default, Clone, Copy, Debug)]
#[derive(Default, Clone, Debug)]
pub struct Stats {
/// The number of addresses symbolized.
pub n_addrs: u64,
/// The number of downloaded PDB files.
pub n_downloads: u64,
/// The total size in bytes of downloads.
pub size_downloaded: u64,
/// The PDB identifiers that have been downloaded & the associated file size
/// in bytes.
pub downloaded: HashMap<PdbId, u64>,
/// The number of time the address cache was a hit.
pub cache_hit: u64,
}

impl Stats {
pub fn did_download(&self, pdb_id: PdbId) -> bool {
self.downloaded.contains_key(&pdb_id)
}

pub fn amount_downloaded(&self) -> u64 {
let mut total = 0u64;
for value in self.downloaded.values() {
total = total.saturating_add(*value);
}

total
}

pub fn amount_pdb_downloaded(&self) -> usize {
self.downloaded.len()
}
}

impl StatsBuilder {
pub fn build(&self) -> Stats {
*self.inner.borrow()
self.inner.borrow().clone()
}

pub fn downloaded_file(&self, size: u64) {
let mut inner = self.inner.borrow_mut();
inner.n_downloads += 1;
inner.size_downloaded += size;
pub fn downloaded_file(&self, pdb_id: PdbId, size: u64) {
assert!(self
.inner
.borrow_mut()
.downloaded
.insert(pdb_id, size)
.is_none());
}

pub fn addr_symbolized(&self) {
Expand Down
Loading

0 comments on commit 61f4c63

Please sign in to comment.