ms_pdb/dbi/modules.rs
1//! DBI Modules Substream
2
3use super::*;
4use crate::StreamIndexU16;
5use bstr::BStr;
6use ms_codeview::HasRestLen;
7use std::mem::take;
8use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned};
9
10/// The header of a Module Info record. Module Info records are stored in the DBI stream.
11///
12/// See `dbi.h`, `MODI_60_Persist`
13#[derive(Unaligned, IntoBytes, FromBytes, Immutable, KnownLayout, Clone, Debug)]
14#[repr(C)]
15pub struct ModuleInfoFixed {
16 /// This appears to be a module index field, but it is not always set.
17 ///
18 /// In some PDBs, we see this field being set to the zero-based index of this Module Info record
19 /// in the DBI Modules Substream. In other PDBs, this value is 0. Set this to 0.
20 pub unused1: U32<LE>,
21
22 /// This module's first section contribution.
23 pub section_contrib: SectionContribEntry,
24
25 /// Various flags
26 ///
27 /// * bit 0: set to 1 if this module has been written since DBI opened
28 /// * bit 1: set to 1 if this module has EC symbolic information
29 /// * bits 2-7: not used
30 /// * bits 8-15: index into TSM list for this mods server
31 pub flags: U16<LE>,
32
33 /// Stream index of the Module Stream for this module, which contains the symbols and line data
34 /// for this module. If this is 0xffff, then this module does not have a module info stream.
35 pub stream: StreamIndexU16,
36
37 /// Specifies the size of the symbols substream within the Module Stream.
38 pub sym_byte_size: U32<LE>,
39
40 /// Specifies the length of the C11 Line Data in a Module Information Stream.
41 /// C11 line data is obsolete and is not supported.
42 pub c11_byte_size: U32<LE>,
43
44 /// Specifies the length of the C13 Line Data in a Module Information Stream.
45 pub c13_byte_size: U32<LE>,
46
47 /// Number of files contributing to this module.
48 pub source_file_count: U16<LE>,
49
50 /// Alignment padding.
51 pub padding: [u8; 2],
52
53 /// Do not read. Set to 0 when encoding.
54 pub unused2: U32<LE>,
55
56 /// Unknown; possible that this relates to Edit-and-Continue.
57 pub source_file_name_index: U32<LE>,
58
59 /// Unknown; possible that this relates to Edit-and-Continue.
60 pub pdb_file_path_name_index: U32<LE>,
61}
62
63impl ModuleInfoFixed {
64 /// Gets the stream for this module, if any. This stream contains the symbol data and C13 Line
65 /// Data for the module.
66 pub fn stream(&self) -> Option<u32> {
67 self.stream.get()
68 }
69}
70
71/// Holds or refers to the data of a substream within a Module Info record.
72#[derive(Clone)]
73pub struct ModInfoSubstream<D: AsRef<[u8]>> {
74 /// The substream data.
75 pub substream_data: D,
76}
77
78impl<D: AsRef<[u8]>> ModInfoSubstream<D> {
79 /// Iterates the Module Info records contained within the DBI Stream.
80 pub fn iter(&self) -> IterModuleInfo<'_> {
81 IterModuleInfo {
82 rest: self.substream_data.as_ref(),
83 }
84 }
85}
86
87/// An in-memory representation of a Module Info record.
88///
89/// The `IterModInfo` iterator produces these items.
90#[allow(missing_docs)]
91pub struct ModuleInfo<'a> {
92 pub header: &'a ModuleInfoFixed,
93 pub module_name: &'a BStr,
94 pub obj_file: &'a BStr,
95}
96
97/// A mutable view of a Module Info record.
98#[allow(missing_docs)]
99pub struct ModuleInfoMut<'a> {
100 pub header: &'a mut ModuleInfoFixed,
101 pub module_name: &'a BStr,
102 pub obj_file: &'a BStr,
103}
104
105impl<'a> ModuleInfo<'a> {
106 /// The name of the module.
107 ///
108 /// * For simple object files, this is the same as `file_name()`.
109 /// * For DLL import libraries, this is the name of the DLL, e.g. `KernelBase.dll`.
110 /// * For static libraries, this is the name (and possibly path) of the object file within the
111 /// static library, not the static library itself.
112 pub fn module_name(&self) -> &'a BStr {
113 self.module_name
114 }
115
116 /// The file name of this module.
117 ///
118 /// * For individual `*.obj` files that are passed directly to the linker (not in a static
119 /// library), this is the filename.
120 /// * For static libraries, this is the `*.lib` file, not the modules within it.
121 /// * For DLL import libraries, this is the import library, e.g. `KernelBase.lib`.
122 pub fn obj_file(&self) -> &'a BStr {
123 self.obj_file
124 }
125
126 /// The header of this Module Info record.
127 pub fn header(&self) -> &'a ModuleInfoFixed {
128 self.header
129 }
130
131 /// The stream index of the stream which contains the symbols defined by this module.
132 ///
133 /// Some modules do not have a symbol stream. In that case, this function will return `None`.
134 pub fn stream(&self) -> Option<u32> {
135 self.header.stream()
136 }
137
138 /// Gets the size in bytes of the C11 Line Data.
139 pub fn c11_size(&self) -> u32 {
140 self.header.c11_byte_size.get()
141 }
142
143 /// Gets the size in bytes of the C13 Line Data.
144 pub fn c13_size(&self) -> u32 {
145 self.header.c13_byte_size.get()
146 }
147
148 /// Gets the size in bytes of the symbol stream for this module. This value includes the size
149 /// of the 4-byte symbol stream header.
150 pub fn sym_size(&self) -> u32 {
151 self.header.sym_byte_size.get()
152 }
153}
154
155/// Iterates module info records
156pub struct IterModuleInfo<'a> {
157 rest: &'a [u8],
158}
159
160impl<'a> IterModuleInfo<'a> {
161 #[allow(missing_docs)]
162 pub fn new(data: &'a [u8]) -> Self {
163 Self { rest: data }
164 }
165
166 /// Returns the data in the iterator that has not yet been parsed.
167 pub fn rest(&self) -> &'a [u8] {
168 self.rest
169 }
170}
171
172impl<'a> HasRestLen for IterModuleInfo<'a> {
173 fn rest_len(&self) -> usize {
174 self.rest.len()
175 }
176}
177
178impl<'a> Iterator for IterModuleInfo<'a> {
179 type Item = ModuleInfo<'a>;
180
181 fn next(&mut self) -> Option<Self::Item> {
182 if self.rest.is_empty() {
183 return None;
184 }
185
186 let mut p = Parser::new(self.rest);
187
188 let len_before = p.len();
189 let header: &ModuleInfoFixed = p.get().ok()?;
190 let module_name = p.strz().ok()?;
191 let obj_file = p.strz().ok()?;
192
193 // Each ModInfo structures is variable-length. It ends with two NUL-terminated strings.
194 // However, the ModInfo structures have an alignment requirement, so if the strings
195 // did not land us on an aligned boundary, we have to skip a few bytes to restore
196 // alignment.
197
198 // Find the number of bytes that were used for this structure.
199 let mod_record_bytes = len_before - p.len();
200 let alignment = (4 - (mod_record_bytes & 3)) & 3;
201 p.bytes(alignment).ok()?;
202
203 // Save iterator position.
204 self.rest = p.into_rest();
205
206 Some(ModuleInfo {
207 header,
208 module_name,
209 obj_file,
210 })
211 }
212}
213
214/// Mutable iterator
215pub struct IterModuleInfoMut<'a> {
216 rest: &'a mut [u8],
217}
218
219impl<'a> IterModuleInfoMut<'a> {
220 #[allow(missing_docs)]
221 pub fn new(data: &'a mut [u8]) -> Self {
222 Self { rest: data }
223 }
224}
225
226impl<'a> Iterator for IterModuleInfoMut<'a> {
227 type Item = ModuleInfoMut<'a>;
228
229 fn next(&mut self) -> Option<Self::Item> {
230 if self.rest.is_empty() {
231 return None;
232 }
233
234 // TODO: note that we steal the byte slice, which means that
235 // if anything goes wrong, we'll never put it back.
236 let mut p = ParserMut::new(take(&mut self.rest));
237
238 let len_before = p.len();
239 let header: &mut ModuleInfoFixed = p.get_mut().ok()?;
240 let module_name = p.strz().ok()?;
241 let obj_file = p.strz().ok()?;
242
243 // Each ModInfo structures is variable-length. It ends with two NUL-terminated strings.
244 // However, the ModInfo structures have an alignment requirement, so if the strings
245 // did not land us on an aligned boundary, we have to skip a few bytes to restore
246 // alignment.
247
248 // Find the number of bytes that were used for this structure.
249 let mod_record_bytes = len_before - p.len();
250 let alignment = (4 - (mod_record_bytes & 3)) & 3;
251 p.bytes(alignment).ok()?;
252
253 // Save iterator position.
254 self.rest = p.into_rest();
255 Some(ModuleInfoMut {
256 header,
257 module_name,
258 obj_file,
259 })
260 }
261}