use std::mem;
use crate::common::*;
use crate::dbi::Module;
use crate::msf::Stream;
use crate::symbol::SymbolIter;
use crate::FallibleIterator;
mod c13;
mod constants;
#[derive(Clone, Copy, Debug)]
enum LinesSize {
C11(usize),
C13(usize),
}
pub struct ModuleInfo<'s> {
stream: Stream<'s>,
symbols_size: usize,
lines_size: LinesSize,
}
impl<'s> ModuleInfo<'s> {
pub(crate) fn parse(stream: Stream<'s>, module: &Module<'_>) -> Result<Self> {
let info = module.info();
let mut buf = stream.parse_buffer();
if buf.parse_u32()? != constants::CV_SIGNATURE_C13 {
return Err(Error::UnimplementedFeature(
"Unsupported module info format",
));
}
let lines_size = if info.lines_size > 0 {
LinesSize::C11(info.lines_size as usize)
} else {
LinesSize::C13(info.c13_lines_size as usize)
};
let symbols_size = info.symbols_size as usize;
Ok(ModuleInfo {
stream,
symbols_size,
lines_size,
})
}
pub fn symbols(&self) -> Result<SymbolIter<'_>> {
let mut buf = self.stream.parse_buffer();
buf.parse_u32()?;
let symbols = buf.take(self.symbols_size - mem::size_of::<u32>())?;
Ok(SymbolIter::new(symbols.into()))
}
pub fn line_program(&self) -> Result<LineProgram<'_>> {
let start = self.symbols_size as usize;
let inner = match self.lines_size {
LinesSize::C11(_size) => return Err(Error::UnimplementedFeature("C11 line programs")),
LinesSize::C13(size) => {
let data = &self.stream[start..start + size];
LineProgramInner::C13(c13::C13LineProgram::parse(data)?)
}
};
Ok(LineProgram { inner })
}
}
#[derive(Clone, Debug)]
pub enum FileChecksum<'a> {
None,
Md5(&'a [u8]),
Sha1(&'a [u8]),
Sha256(&'a [u8]),
}
impl PartialEq for FileChecksum<'_> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(&FileChecksum::Md5(lhs), &FileChecksum::Md5(rhs)) => lhs == rhs,
(&FileChecksum::Sha1(lhs), &FileChecksum::Sha1(rhs)) => lhs == rhs,
(&FileChecksum::Sha256(lhs), &FileChecksum::Sha256(rhs)) => lhs == rhs,
_ => false,
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct FileInfo<'a> {
pub name: StringRef,
pub checksum: FileChecksum<'a>,
}
#[derive(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct FileIndex(pub u32);
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum LineInfoKind {
Expression,
Statement,
}
#[derive(Clone, Debug)]
pub struct LineInfo {
pub offset: PdbInternalSectionOffset,
pub file_index: FileIndex,
pub line_start: u32,
pub line_end: u32,
pub column_start: Option<u16>,
pub column_end: Option<u16>,
pub kind: LineInfoKind,
}
enum LineProgramInner<'a> {
C13(c13::C13LineProgram<'a>),
}
pub struct LineProgram<'a> {
inner: LineProgramInner<'a>,
}
impl<'a> LineProgram<'a> {
pub fn lines(&self) -> LineIterator<'a> {
match self.inner {
LineProgramInner::C13(ref inner) => LineIterator {
inner: LineIteratorInner::C13(inner.lines()),
},
}
}
pub fn files(&self) -> FileIterator<'a> {
match self.inner {
LineProgramInner::C13(ref inner) => FileIterator {
inner: FileIteratorInner::C13(inner.files()),
},
}
}
pub fn lines_at_offset(&self, offset: PdbInternalSectionOffset) -> LineIterator {
match self.inner {
LineProgramInner::C13(ref inner) => LineIterator {
inner: LineIteratorInner::C13(inner.lines_at_offset(offset)),
},
}
}
pub fn get_file_info(&self, offset: FileIndex) -> Result<FileInfo<'a>> {
match self.inner {
LineProgramInner::C13(ref inner) => inner.get_file_info(offset),
}
}
}
#[derive(Clone, Debug)]
enum LineIteratorInner<'a> {
C13(c13::C13LineIterator<'a>),
}
#[derive(Clone, Debug)]
pub struct LineIterator<'a> {
inner: LineIteratorInner<'a>,
}
impl Default for LineIterator<'_> {
fn default() -> Self {
LineIterator {
inner: LineIteratorInner::C13(Default::default()),
}
}
}
impl<'a> FallibleIterator for LineIterator<'a> {
type Item = LineInfo;
type Error = Error;
fn next(&mut self) -> Result<Option<Self::Item>> {
match self.inner {
LineIteratorInner::C13(ref mut inner) => inner.next(),
}
}
}
#[derive(Clone, Debug)]
enum FileIteratorInner<'a> {
C13(c13::C13FileIterator<'a>),
}
#[derive(Clone, Debug)]
pub struct FileIterator<'a> {
inner: FileIteratorInner<'a>,
}
impl Default for FileIterator<'_> {
fn default() -> Self {
FileIterator {
inner: FileIteratorInner::C13(Default::default()),
}
}
}
impl<'a> FallibleIterator for FileIterator<'a> {
type Item = FileInfo<'a>;
type Error = Error;
fn next(&mut self) -> Result<Option<Self::Item>> {
match self.inner {
FileIteratorInner::C13(ref mut inner) => inner.next(),
}
}
}