ms_pdb/dbi/
section_contrib.rsuse super::*;
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned};
#[allow(missing_docs)]
#[derive(Unaligned, IntoBytes, FromBytes, Immutable, KnownLayout, Clone, Debug)]
#[repr(C)]
pub struct SectionContribEntry {
pub section: U16<LE>,
pub padding1: [u8; 2],
pub offset: I32<LE>,
pub size: I32<LE>,
pub characteristics: U32<LE>,
pub module_index: U16<LE>,
pub padding2: [u8; 2],
pub data_crc: U32<LE>,
pub reloc_crc: U32<LE>,
}
#[allow(missing_docs)]
#[derive(Unaligned, IntoBytes, FromBytes, Immutable, KnownLayout, Clone, Debug)]
#[repr(C)]
pub struct SectionContribEntry2 {
pub base: SectionContribEntry,
pub coff_section: U32<LE>,
}
impl SectionContribEntry {
pub fn contains_offset(&self, offset: i32) -> bool {
let self_offset = self.offset.get();
if offset < self_offset {
return false;
}
let overshoot = offset - self_offset;
if overshoot >= self.size.get() {
return false;
}
true
}
}
pub struct SectionContributionsSubstream<'a> {
pub contribs: &'a [SectionContribEntry],
}
pub const SECTION_CONTRIBUTIONS_SUBSTREAM_VER60: u32 = 0xeffe0000 + 19970605;
impl<'a> SectionContributionsSubstream<'a> {
pub fn parse(bytes: &'a [u8]) -> anyhow::Result<Self> {
let mut p = Parser::new(bytes);
if p.is_empty() {
return Ok(Self { contribs: &[] });
}
let version = p.u32()?;
match version {
SECTION_CONTRIBUTIONS_SUBSTREAM_VER60 => {}
_ => {
bail!("The Section Contributions Substream has a version number that is not supported. Version: 0x{:08x}", version);
}
}
let records_bytes = p.into_rest();
let Ok(contribs) = <[SectionContribEntry]>::ref_from_bytes(records_bytes) else {
bail!("The Section Contributions stream has an invalid size. It is not a multiple of the section contribution record size. Size: 0x{:x}",
bytes.len());
};
Ok(SectionContributionsSubstream { contribs })
}
pub fn find(&self, section: u16, offset: i32) -> Option<&SectionContribEntry> {
let i = self.find_index(section, offset)?;
Some(&self.contribs[i])
}
pub fn find_index(&self, section: u16, offset: i32) -> Option<usize> {
match self
.contribs
.binary_search_by_key(&(section, offset), |con| {
(con.section.get(), con.offset.get())
}) {
Ok(i) => Some(i),
Err(i) => {
if i > 0 {
let previous = &self.contribs[i - 1];
if previous.contains_offset(offset) {
return Some(i - 1);
}
}
if i + 1 < self.contribs.len() {
let next = &self.contribs[i + 1];
if next.contains_offset(offset) {
return Some(i + 1);
}
}
None
}
}
}
pub fn find_brute(&self, section: u16, offset: i32) -> Option<&SectionContribEntry> {
let i = self.find_index_brute(section, offset)?;
Some(&self.contribs[i])
}
pub fn find_index_brute(&self, section: u16, offset: i32) -> Option<usize> {
self.contribs
.iter()
.position(|c| c.section.get() == section && c.contains_offset(offset))
}
}
pub struct SectionContributionsSubstreamMut<'a> {
pub contribs: &'a mut [SectionContribEntry],
}
impl<'a> SectionContributionsSubstreamMut<'a> {
pub fn parse(bytes: &'a mut [u8]) -> anyhow::Result<Self> {
let bytes_len = bytes.len();
let mut p = ParserMut::new(bytes);
if p.is_empty() {
return Ok(Self { contribs: &mut [] });
}
let version = p.u32()?;
match version {
SECTION_CONTRIBUTIONS_SUBSTREAM_VER60 => {}
_ => {
bail!("The Section Contributions Substream has a version number that is not supported. Version: 0x{:08x}", version);
}
}
let records_bytes = p.into_rest();
let Ok(contribs) = <[SectionContribEntry]>::mut_from_bytes(records_bytes) else {
bail!("The Section Contributions stream has an invalid size. It is not a multiple of the section contribution record size. Size: 0x{:x}",
bytes_len);
};
Ok(Self { contribs })
}
pub fn remap_module_indexes(&mut self, modules_old_to_new: &[u32]) -> anyhow::Result<()> {
for (i, contrib) in self.contribs.iter_mut().enumerate() {
let old = contrib.module_index.get();
if let Some(&new) = modules_old_to_new.get(old as usize) {
contrib.module_index.set(new as u16);
} else {
bail!("Section contribution record (at contribution index #{i} has module index {old}, \
which is out of range (num modules is {})",
modules_old_to_new.len());
}
contrib.padding1 = [0; 2];
contrib.padding2 = [0; 2];
}
Ok(())
}
}