ms_pdb/dbi/
section_contrib.rs1use super::*;
12use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned};
13
14#[allow(missing_docs)]
16#[derive(Unaligned, IntoBytes, FromBytes, Immutable, KnownLayout, Clone, Debug)]
17#[repr(C)]
18pub struct SectionContribEntry {
19 pub section: U16<LE>,
21 pub padding1: [u8; 2],
23 pub offset: I32<LE>,
24 pub size: I32<LE>,
25 pub characteristics: U32<LE>,
26 pub module_index: U16<LE>,
28 pub padding2: [u8; 2],
30 pub data_crc: U32<LE>,
31 pub reloc_crc: U32<LE>,
32}
33
34#[allow(missing_docs)]
36#[derive(Unaligned, IntoBytes, FromBytes, Immutable, KnownLayout, Clone, Debug)]
37#[repr(C)]
38pub struct SectionContribEntry2 {
39 pub base: SectionContribEntry,
40 pub coff_section: U32<LE>,
41}
42
43impl SectionContribEntry {
44 pub fn contains_offset(&self, offset: i32) -> bool {
46 let self_offset = self.offset.get();
47 if offset < self_offset {
48 return false;
49 }
50
51 let overshoot = offset - self_offset;
52 if overshoot >= self.size.get() {
53 return false;
54 }
55
56 true
57 }
58}
59
60pub struct SectionContributionsSubstream<'a> {
62 pub contribs: &'a [SectionContribEntry],
64}
65
66pub const SECTION_CONTRIBUTIONS_SUBSTREAM_VER60: u32 = 0xeffe0000 + 19970605;
68
69impl<'a> SectionContributionsSubstream<'a> {
70 pub fn parse(bytes: &'a [u8]) -> anyhow::Result<Self> {
74 let mut p = Parser::new(bytes);
75 if p.is_empty() {
76 return Ok(Self { contribs: &[] });
77 }
78
79 let version = p.u32()?;
80
81 match version {
82 SECTION_CONTRIBUTIONS_SUBSTREAM_VER60 => {}
83 _ => {
84 bail!(
85 "The Section Contributions Substream has a version number that is not supported. Version: 0x{:08x}",
86 version
87 );
88 }
89 }
90
91 let records_bytes = p.into_rest();
92 let Ok(contribs) = <[SectionContribEntry]>::ref_from_bytes(records_bytes) else {
93 bail!(
94 "The Section Contributions stream has an invalid size. It is not a multiple of the section contribution record size. Size: 0x{:x}",
95 bytes.len()
96 );
97 };
98 Ok(SectionContributionsSubstream { contribs })
99 }
100
101 pub fn find(&self, section: u16, offset: i32) -> Option<&SectionContribEntry> {
104 let i = self.find_index(section, offset)?;
105 Some(&self.contribs[i])
106 }
107
108 pub fn find_index(&self, section: u16, offset: i32) -> Option<usize> {
111 match self
112 .contribs
113 .binary_search_by_key(&(section, offset), |con| {
114 (con.section.get(), con.offset.get())
115 }) {
116 Ok(i) => Some(i),
117 Err(i) => {
118 if i > 0 {
120 let previous = &self.contribs[i - 1];
121 if previous.contains_offset(offset) {
122 return Some(i - 1);
123 }
124 }
125
126 if i + 1 < self.contribs.len() {
127 let next = &self.contribs[i + 1];
128 if next.contains_offset(offset) {
129 return Some(i + 1);
130 }
131 }
132
133 None
134 }
135 }
136 }
137
138 pub fn find_brute(&self, section: u16, offset: i32) -> Option<&SectionContribEntry> {
141 let i = self.find_index_brute(section, offset)?;
142 Some(&self.contribs[i])
143 }
144
145 pub fn find_index_brute(&self, section: u16, offset: i32) -> Option<usize> {
148 self.contribs
149 .iter()
150 .position(|c| c.section.get() == section && c.contains_offset(offset))
151 }
152}
153
154pub struct SectionContributionsSubstreamMut<'a> {
156 pub contribs: &'a mut [SectionContribEntry],
158}
159
160impl<'a> SectionContributionsSubstreamMut<'a> {
161 pub fn parse(bytes: &'a mut [u8]) -> anyhow::Result<Self> {
163 let bytes_len = bytes.len();
164
165 let mut p = ParserMut::new(bytes);
166 if p.is_empty() {
167 return Ok(Self { contribs: &mut [] });
168 }
169
170 let version = p.u32()?;
171
172 match version {
173 SECTION_CONTRIBUTIONS_SUBSTREAM_VER60 => {}
174 _ => {
175 bail!(
176 "The Section Contributions Substream has a version number that is not supported. Version: 0x{:08x}",
177 version
178 );
179 }
180 }
181
182 let records_bytes = p.into_rest();
183
184 let Ok(contribs) = <[SectionContribEntry]>::mut_from_bytes(records_bytes) else {
185 bail!(
186 "The Section Contributions stream has an invalid size. It is not a multiple of the section contribution record size. Size: 0x{:x}",
187 bytes_len
188 );
189 };
190 Ok(Self { contribs })
191 }
192
193 pub fn remap_module_indexes(&mut self, modules_old_to_new: &[u32]) -> anyhow::Result<()> {
196 for (i, contrib) in self.contribs.iter_mut().enumerate() {
197 let old = contrib.module_index.get();
198 if let Some(&new) = modules_old_to_new.get(old as usize) {
199 contrib.module_index.set(new as u16);
200 } else {
201 bail!(
202 "Section contribution record (at contribution index #{i} has module index {old}, \
203 which is out of range (num modules is {})",
204 modules_old_to_new.len()
205 );
206 }
207
208 contrib.padding1 = [0; 2];
210 contrib.padding2 = [0; 2];
211 }
212 Ok(())
213 }
214}