Skip to content

Commit

Permalink
Merge branch 'master' into omap
Browse files Browse the repository at this point in the history
* master:
  Exclude fixtures from the packaged crate
  Expose the machine type from the DBI stream
  Add support for module private procedure symbols
  Expand stream_names example a little bit
  Move `BigMSF` and its related bits into a `big` submodule, and add a `small` submodule currently containing only the small MSF `MAGIC` constant.
  Initial cut at using scroll+scroll_derive for BigMSF.
  • Loading branch information
jan-auer committed Feb 19, 2019
2 parents 1243a2a + beff20a commit fc1e00c
Show file tree
Hide file tree
Showing 10 changed files with 638 additions and 372 deletions.
219 changes: 158 additions & 61 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@ repository = "https://github.com/willglynn/pdb"
authors = ["Will Glynn <[email protected]>"]
readme = "README.md"
license = "MIT OR Apache-2.0"
exclude = [
"fixtures/*",
]

[dependencies]
fallible-iterator = "0.1.4"
byteorder = "1.0.0"
scroll = { version = "0.9.0", features = ["derive"] }
uuid = "0.5.0"

[dev-dependencies]
Expand Down
3 changes: 3 additions & 0 deletions examples/pdb_symbols.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ fn print_symbol(symbol: &pdb::Symbol) -> pdb::Result<()> {
pdb::SymbolData::DataSymbol(data) => {
print_row(data.segment, data.offset, "data", symbol.name()?);
}
pdb::SymbolData::Procedure(data) => {
print_row(data.segment, data.offset, "function", symbol.name()?);
}
_ => {
// ignore everything else
}
Expand Down
3 changes: 2 additions & 1 deletion examples/stream_names.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ fn dump_stream_names(filename: &OsStr) -> pdb::Result<()> {
let names = info.stream_names()?;
println!("index, name");
for name in names.iter() {
println!("{:5}, {}", name.stream_id, name.name);
let stream = pdb.raw_stream(name.stream_id)?;
println!("{:5}, {} {} bytes", name.stream_id, name.name, stream.parse_buffer().len());
}
Ok(())
}
Expand Down
177 changes: 54 additions & 123 deletions src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ use std::fmt;
use std::io;
use std::result;

use byteorder::{ByteOrder,LittleEndian};
use scroll::{self, Endian, Pread, LE};
use scroll::ctx::TryFromCtx;

/// `TypeIndex` refers to a type somewhere in `PDB.type_information()`.
pub type TypeIndex = u32;
Expand Down Expand Up @@ -67,6 +68,9 @@ pub enum Error {

/// Variable-length numeric parsing encountered an unexpected prefix.
UnexpectedNumericPrefix(u16),

/// A parse error from scroll.
ScrollError(scroll::Error),
}

impl error::Error for Error {
Expand All @@ -87,6 +91,7 @@ impl error::Error for Error {
Error::TypeNotIndexed(_, _) => "Type not indexed",
Error::UnimplementedTypeKind(_) => "Support for types of this kind is not implemented",
Error::UnexpectedNumericPrefix(_) => "Variable-length numeric parsing encountered an unexpected prefix",
Error::ScrollError(ref e) => e.description(),
}
}
}
Expand Down Expand Up @@ -116,13 +121,43 @@ impl convert::From<io::Error> for Error {
}
}

impl convert::From<scroll::Error> for Error {
fn from(e: scroll::Error) -> Self {
match e {
// Convert a couple of scroll errors into EOF.
scroll::Error::BadOffset(_) | scroll::Error::TooBig { .. } => Error::UnexpectedEof,
_ => Error::ScrollError(e),
}
}
}

pub type Result<T> = result::Result<T, Error>;

/// Provides little-endian access to a &[u8].
#[doc(hidden)]
#[derive(Debug,Clone)]
pub struct ParseBuffer<'b> (&'b [u8], usize);

macro_rules! def_parse {
( $( ($n:ident, $t:ty) ),* $(,)* ) => {
$(#[doc(hidden)]
#[inline]
pub fn $n(&mut self) -> Result<$t> {
Ok(self.parse()?)
})*
}
}

macro_rules! def_peek {
( $( ($n:ident, $t:ty) ),* $(,)* ) => {
$(#[doc(hidden)]
#[inline]
pub fn $n(&mut self) -> Result<$t> {
Ok(self.0.pread_with(self.1, LE)?)
})*
}
}

impl<'b> ParseBuffer<'b> {
/// Return the remaining length of the buffer.
#[doc(hidden)]
Expand Down Expand Up @@ -152,96 +187,26 @@ impl<'b> ParseBuffer<'b> {
Ok(())
}

/// Parse a `u8` from the input.
#[doc(hidden)]
#[inline]
pub fn parse_u8(&mut self) -> Result<u8> {
let input = &self.0[self.1..];
if input.len() < 1 {
Err(Error::UnexpectedEof)
} else {
self.1 += 1;
Ok(input[0])
}
}

/// Peek at the next u8 without advancing the cursor.
#[doc(hidden)]
#[inline]
pub fn peek_u8(&mut self) -> Result<u8> {
let input = &self.0[self.1..];
if input.len() < 1 {
Err(Error::UnexpectedEof)
} else {
Ok(input[0])
}
}

/// Parse a `u16` from the input.
#[doc(hidden)]
#[inline]
pub fn parse_u16(&mut self) -> Result<u16> {
let input = &self.0[self.1..];
if input.len() < 2 {
Err(Error::UnexpectedEof)
} else {
self.1 += 2;
Ok(LittleEndian::read_u16(input))
}
}

/// Parse an `i16` from the input.
#[doc(hidden)]
#[inline]
pub fn parse_i16(&mut self) -> Result<i16> {
let input = &self.0[self.1..];
if input.len() < 2 {
Err(Error::UnexpectedEof)
} else {
self.1 += 2;
Ok(LittleEndian::read_i16(input))
}
}

/// Peek at the next u16 without advancing the cursor.
#[doc(hidden)]
#[inline]
pub fn peek_u16(&mut self) -> Result<u16> {
let input = &self.0[self.1..];
if input.len() < 2 {
Err(Error::UnexpectedEof)
} else {
Ok(LittleEndian::read_u16(input))
}
}

/// Parse a `u32` from the input.
#[doc(hidden)]
#[inline]
pub fn parse_u32(&mut self) -> Result<u32>
pub fn parse<T>(&mut self) -> Result<T>
where T: TryFromCtx<'b, Endian, [u8], Error=scroll::Error, Size=usize>,
{
let input = &self.0[self.1..];
if input.len() < 4 {
Err(Error::UnexpectedEof)
} else {
self.1 += 4;
Ok(LittleEndian::read_u32(input))
}
Ok(self.0.gread_with(&mut self.1, LE)?)
}

/// Parse an `i32` from the input.
#[doc(hidden)]
#[inline]
pub fn parse_i32(&mut self) -> Result<i32>
{
let input = &self.0[self.1..];
if input.len() < 4 {
Err(Error::UnexpectedEof)
} else {
self.1 += 4;
Ok(LittleEndian::read_i32(input))
}
}
def_parse!(
(parse_u8, u8),
(parse_u16, u16),
(parse_i16, i16),
(parse_u32, u32),
(parse_i32, i32),
(parse_u64, u64),
(parse_i64, i64),
);

def_peek!(
(peek_u8, u8),
(peek_u16, u16),
);

/// Parse a NUL-terminated string from the input.
#[doc(hidden)]
Expand All @@ -258,46 +223,12 @@ impl<'b> ParseBuffer<'b> {
}
}

/// Parse a `u64` from the input.
#[doc(hidden)]
#[inline]
pub fn parse_u64(&mut self) -> Result<u64>
{
let input = &self.0[self.1..];
if input.len() < 8 {
Err(Error::UnexpectedEof)
} else {
self.1 += 8;
Ok(LittleEndian::read_u64(input))
}
}

/// Parse an `i64` from the input.
#[doc(hidden)]
#[inline]
pub fn parse_i64(&mut self) -> Result<i64>
{
let input = &self.0[self.1..];
if input.len() < 8 {
Err(Error::UnexpectedEof)
} else {
self.1 += 8;
Ok(LittleEndian::read_i64(input))
}
}

/// Parse a u8-length-prefixed string from the input.
#[doc(hidden)]
#[inline]
pub fn parse_u8_pascal_string(&mut self) -> Result<RawString<'b>> {
let length = self.parse_u8()? as usize;
let input = &self.0[self.1..];
if input.len() >= length {
self.1 += length;
Ok(RawString::from(&input[..length]))
} else {
Err(Error::UnexpectedEof)
}
Ok(RawString::from(self.take(length)?))
}

/// Take n bytes from the input
Expand Down
91 changes: 91 additions & 0 deletions src/dbi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ pub struct DebugInformation<'s> {
}

impl<'s> DebugInformation<'s> {
/// Returns the target's machine type (architecture).
pub fn machine_type(&self) -> Result<MachineType> {
Ok(self.header.machine_type.into())
}
/// Returns an iterator that can traverse the modules list in sequential order.
pub fn modules(&self) -> Result<ModuleIter> {
let mut buf = self.stream.parse_buffer();
Expand Down Expand Up @@ -201,6 +205,93 @@ pub fn parse_header(buf: &mut ParseBuffer) -> Result<Header> {
Ok(header)
}

/// The target machine's architecture.
// Reference: https://github.com/llvm-mirror/llvm/blob/8e47a8d1a66b89cd59fbc2fdc7e19dbe7a15c6f8/include/llvm/DebugInfo/PDB/PDBTypes.h#L124
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum MachineType {
Invalid = 0xffff,
Unknown = 0x0,
Am33 = 0x13,
Amd64 = 0x8664,
Arm = 0x1C0,
ArmNT = 0x1C4,
Ebc = 0xEBC,
X86 = 0x14C,
Ia64 = 0x200,
M32R = 0x9041,
Mips16 = 0x266,
MipsFpu = 0x366,
MipsFpu16 = 0x466,
PowerPC = 0x1F0,
PowerPCFP = 0x1F1,
R4000 = 0x166,
SH3 = 0x1A2,
SH3DSP = 0x1A3,
SH4 = 0x1A6,
SH5 = 0x1A8,
Thumb = 0x1C2,
WceMipsV2 = 0x169,
}

impl ::std::fmt::Display for MachineType {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
match *self {
MachineType::Invalid => write!(f, "Invalid"),
MachineType::Unknown => write!(f, "Unknown"),
MachineType::Am33 => write!(f, "Am33"),
MachineType::Amd64 => write!(f, "Amd64"),
MachineType::Arm => write!(f, "Arm"),
MachineType::ArmNT => write!(f, "ArmNT"),
MachineType::Ebc => write!(f, "Ebc"),
MachineType::X86 => write!(f, "X86"),
MachineType::Ia64 => write!(f, "Ia64"),
MachineType::M32R => write!(f, "M32R"),
MachineType::Mips16 => write!(f, "Mips16"),
MachineType::MipsFpu => write!(f, "MipsFpu"),
MachineType::MipsFpu16 => write!(f, "MipsFpu16"),
MachineType::PowerPC => write!(f, "PowerPC"),
MachineType::PowerPCFP => write!(f, "PowerPCFP"),
MachineType::R4000 => write!(f, "R4000"),
MachineType::SH3 => write!(f, "SH3"),
MachineType::SH3DSP => write!(f, "SH3DSP"),
MachineType::SH4 => write!(f, "SH4"),
MachineType::SH5 => write!(f, "SH5"),
MachineType::Thumb => write!(f, "Thumb"),
MachineType::WceMipsV2 => write!(f, "WceMipsV2"),
}
}
}

impl From<u16> for MachineType {
fn from(value: u16) -> Self {
match value {
0xffff => MachineType::Invalid,
0x0 => MachineType::Unknown,
0x13 => MachineType::Am33,
0x8664 => MachineType::Amd64,
0x1C0 => MachineType::Arm,
0x1C4 => MachineType::ArmNT,
0xEBC => MachineType::Ebc,
0x14C => MachineType::X86,
0x200 => MachineType::Ia64,
0x9041 => MachineType::M32R,
0x266 => MachineType::Mips16,
0x366 => MachineType::MipsFpu,
0x466 => MachineType::MipsFpu16,
0x1F0 => MachineType::PowerPC,
0x1F1 => MachineType::PowerPCFP,
0x166 => MachineType::R4000,
0x1A2 => MachineType::SH3,
0x1A3 => MachineType::SH3DSP,
0x1A6 => MachineType::SH4,
0x1A8 => MachineType::SH5,
0x1C2 => MachineType::Thumb,
0x169 => MachineType::WceMipsV2,
_ => MachineType::Unknown,
}
}
}

/// Information about a module's contribution to a section.
/// `struct SC` in Microsoft's code:
/// https://github.com/Microsoft/microsoft-pdb/blob/082c5290e5aff028ae84e43affa8be717aa7af73/PDB/include/dbicommon.h#L42
Expand Down
4 changes: 3 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
extern crate byteorder;
extern crate fallible_iterator;
#[macro_use]
extern crate scroll;
extern crate uuid;

// modules
Expand All @@ -62,7 +64,7 @@ mod omap;

// exports
pub use common::{Error,Result,TypeIndex,RawString,Variant};
pub use dbi::{DebugInformation, Module, ModuleIter};
pub use dbi::{DebugInformation, MachineType, Module, ModuleIter};
pub use module_info::ModuleInfo;
pub use pdbi::{NameIter, PDBInformation, StreamName, StreamNames};
pub use pdb::PDB;
Expand Down
Loading

0 comments on commit fc1e00c

Please sign in to comment.