use std::fmt;
use crate::common::*;
use crate::dbi::Module;
use crate::msf::Stream;
use crate::symbol::SymbolIter;
use crate::FallibleIterator;
mod c13;
mod constants;
pub use c13::{
CrossModuleExportIter, CrossModuleExports, CrossModuleImports, Inlinee, InlineeIterator,
InlineeLineIterator,
};
#[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<'_>) -> Self {
let info = module.info();
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;
ModuleInfo {
stream,
symbols_size,
lines_size,
}
}
fn lines_data(&self, size: usize) -> &[u8] {
let start = self.symbols_size as usize;
&self.stream[start..start + size]
}
pub fn symbols(&self) -> Result<SymbolIter<'_>> {
let mut buf = self.stream.parse_buffer();
buf.truncate(self.symbols_size)?;
if self.symbols_size > 0 {
let sig = buf.parse_u32()?;
if sig != constants::CV_SIGNATURE_C13 {
return Err(Error::UnimplementedFeature(
"Unsupported symbol data format",
));
}
}
Ok(SymbolIter::new(buf))
}
pub fn symbols_at(&self, index: SymbolIndex) -> Result<SymbolIter<'_>> {
let mut iter = self.symbols()?;
iter.seek(index);
Ok(iter)
}
pub fn line_program(&self) -> Result<LineProgram<'_>> {
let inner = match self.lines_size {
LinesSize::C11(_size) => return Err(Error::UnimplementedFeature("C11 line programs")),
LinesSize::C13(size) => {
LineProgramInner::C13(c13::LineProgram::parse(self.lines_data(size))?)
}
};
Ok(LineProgram { inner })
}
pub fn inlinees(&self) -> Result<InlineeIterator<'_>> {
Ok(match self.lines_size {
LinesSize::C11(_size) => Default::default(),
LinesSize::C13(size) => InlineeIterator::parse(self.lines_data(size))?,
})
}
pub fn exports(&self) -> Result<CrossModuleExports> {
Ok(match self.lines_size {
LinesSize::C11(_size) => Default::default(),
LinesSize::C13(size) => CrossModuleExports::parse(self.lines_data(size))?,
})
}
pub fn imports(&self) -> Result<CrossModuleImports<'_>> {
Ok(match self.lines_size {
LinesSize::C11(_size) => Default::default(),
LinesSize::C13(size) => CrossModuleImports::parse(self.lines_data(size))?,
})
}
}
#[derive(Clone, Debug)]
#[allow(missing_docs)]
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, Eq, PartialEq)]
pub enum LineInfoKind {
Expression,
Statement,
}
impl Default for LineInfoKind {
fn default() -> Self {
LineInfoKind::Statement
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct LineInfo {
pub offset: PdbInternalSectionOffset,
pub length: Option<u32>,
pub file_index: FileIndex,
pub line_start: u32,
pub line_end: u32,
pub column_start: Option<u32>,
pub column_end: Option<u32>,
pub kind: LineInfoKind,
}
enum LineProgramInner<'a> {
C13(c13::LineProgram<'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::LineIterator<'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::FileIterator<'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(),
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct ModuleRef(pub StringRef);
impl fmt::Display for ModuleRef {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct CrossModuleRef<I: ItemIndex>(pub ModuleRef, pub Local<I>);
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum CrossModuleExport {
Type(Local<TypeIndex>, TypeIndex),
Id(Local<IdIndex>, IdIndex),
}