1use crate::dbi::optional_dbg::{OptionalDebugHeaders, OptionalDebugStream};
30use crate::{Container, NIL_STREAM_INDEX};
31use crate::{Stream, get_or_init_err};
32use crate::{StreamIndexIsNilError, StreamIndexU16};
33use anyhow::{Result, bail};
34use ms_codeview::parser::{Parser, ParserError, ParserMut};
35use ms_coff::IMAGE_SECTION_HEADER;
36use std::mem::size_of;
37use std::ops::Range;
38use sync_file::ReadAt;
39use tracing::{error, warn};
40use zerocopy::{
41 FromBytes, FromZeros, I32, Immutable, IntoBytes, KnownLayout, LE, U16, U32, Unaligned,
42};
43
44#[cfg(doc)]
45use crate::Pdb;
46
47pub mod fixups;
48pub mod modules;
49pub mod optional_dbg;
50pub mod section_contrib;
51pub mod section_map;
52pub mod sources;
53
54pub use modules::*;
55#[doc(inline)]
56pub use section_contrib::*;
57#[doc(inline)]
58pub use sources::*;
59
60#[repr(C)]
62#[derive(IntoBytes, FromBytes, KnownLayout, Immutable, Unaligned, Debug, Clone)]
63#[allow(missing_docs)]
64pub struct DbiStreamHeader {
65 pub signature: I32<LE>,
67
68 pub version: U32<LE>,
70
71 pub age: U32<LE>,
74
75 pub global_symbol_index_stream: StreamIndexU16,
79
80 pub build_number: U16<LE>,
81
82 pub public_symbol_index_stream: StreamIndexU16,
85
86 pub pdb_dll_version: U16<LE>,
88
89 pub global_symbol_stream: StreamIndexU16,
92
93 pub pdb_dll_rbld: U16<LE>,
94
95 pub mod_info_size: I32<LE>,
97 pub section_contribution_size: I32<LE>,
98 pub section_map_size: I32<LE>,
99 pub source_info_size: I32<LE>,
100 pub type_server_map_size: I32<LE>,
101 pub mfc_type_server_index: U32<LE>,
103 pub optional_dbg_header_size: I32<LE>,
104 pub edit_and_continue_size: I32<LE>,
105
106 pub flags: U16<LE>,
107 pub machine: U16<LE>,
108 pub padding: U32<LE>,
109}
110
111pub static EMPTY_DBI_STREAM_HEADER: [u8; DBI_STREAM_HEADER_LEN] = [
113 0xFF, 0xFF, 0xFF, 0xFF, 0x77, 0x09, 0x31, 0x01, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ];
134
135#[test]
136fn test_parse_empty_dbi_stream_header() {
137 let h = DbiStreamHeader::read_from_bytes(EMPTY_DBI_STREAM_HEADER.as_slice()).unwrap();
138 assert!(h.global_symbol_index_stream.get().is_none());
139}
140
141impl DbiStreamHeader {
142 pub fn sym_record_stream(&self) -> Result<u32, StreamIndexIsNilError> {
144 self.global_symbol_stream.get_err()
145 }
146
147 pub fn public_stream_index(&self) -> Result<u32, StreamIndexIsNilError> {
149 self.public_symbol_index_stream.get_err()
150 }
151
152 pub fn global_stream_index(&self) -> Result<u32, StreamIndexIsNilError> {
154 self.global_symbol_index_stream.get_err()
155 }
156
157 pub fn modules_range(&self) -> anyhow::Result<Range<usize>> {
159 let start = DBI_STREAM_HEADER_LEN;
160 let size = self.mod_info_size.get() as usize;
161 Ok(start..start + size)
162 }
163
164 pub fn sources_range(&self) -> anyhow::Result<Range<usize>> {
166 let start = DBI_STREAM_HEADER_LEN
167 + self.mod_info_size.get() as usize
168 + self.section_contribution_size.get() as usize
169 + self.section_map_size.get() as usize;
170 let size = self.source_info_size.get() as usize;
171 Ok(start..start + size)
172 }
173
174 pub fn total_substreams_len(&self) -> Option<u32> {
179 u32::try_from(self.mod_info_size.get())
182 .ok()?
183 .checked_add(u32::try_from(self.section_contribution_size.get()).ok()?)?
184 .checked_add(u32::try_from(self.section_map_size.get()).ok()?)?
185 .checked_add(u32::try_from(self.source_info_size.get()).ok()?)?
186 .checked_add(u32::try_from(self.type_server_map_size.get()).ok()?)?
187 .checked_add(u32::try_from(self.optional_dbg_header_size.get()).ok()?)?
188 .checked_add(u32::try_from(self.edit_and_continue_size.get()).ok()?)
189 }
190}
191
192static_assertions::const_assert_eq!(size_of::<DbiStreamHeader>(), DBI_STREAM_HEADER_LEN);
193pub const DBI_STREAM_HEADER_LEN: usize = 64;
195
196pub const DBI_STREAM_VERSION_VC41: u32 = 930803;
198pub const DBI_STREAM_VERSION_V50: u32 = 19960307;
200pub const DBI_STREAM_VERSION_V60: u32 = 19970606;
202pub const DBI_STREAM_VERSION_V70: u32 = 19990903;
204pub const DBI_STREAM_VERSION_V110: u32 = 20091201;
206
207#[derive(Clone)]
213pub struct DbiStream<StreamData = Vec<u8>>
214where
215 StreamData: AsRef<[u8]>,
216{
217 pub stream_data: StreamData,
219
220 pub substreams: DbiSubstreamRanges,
222}
223
224macro_rules! dbi_substreams {
228 (
229 $(
230 $name:ident,
231 $mut_name:ident,
232 $size_field:ident ;
233 )*
234 ) => {
235 #[derive(Clone, Debug, Default)]
237 pub struct DbiSubstreamRanges {
238 $(
239 #[doc = concat!("The range of the ", stringify!($name), " substream.")]
240 pub $name: Range<usize>,
241 )*
242 }
243
244 impl<StreamData: AsRef<[u8]>> DbiStream<StreamData> {
245 $(
246 #[doc = concat!("The unparsed contents of the ", stringify!($name), " substream.")]
247 pub fn $name(&self) -> &[u8] {
248 self.substream_data(self.substreams.$name.clone())
249 }
250
251 #[doc = concat!("The unparsed contents of the ", stringify!($name), " substream.")]
252 pub fn $mut_name(&mut self) -> &mut [u8]
253 where
254 StreamData: AsMut<[u8]>,
255 {
256 self.substream_data_mut(self.substreams.$name.clone())
257 }
258
259 )*
260 }
261
262 impl DbiSubstreamRanges {
263 pub(crate) fn from_sizes(sizes: &DbiStreamHeader, stream_len: usize) -> anyhow::Result<Self> {
264 let mut pos: usize = DBI_STREAM_HEADER_LEN;
265 if pos > stream_len {
266 bail!("DBI stream is too short; pos = {}, stream_len = {}", pos, stream_len);
267 }
268
269 $(
270 assert!(pos <= stream_len);
271 let size: i32 = sizes.$size_field.get();
272 if size < 0 {
273 bail!("Substream {} length in DBI header is invalid (is negative)", stringify!($size_field));
274 }
275
276 let len = size as usize;
277 let available = stream_len - pos;
278 if len > available {
279 bail!("Substream {} length in DBI header is invalid. It extends beyond the end of the stream.", stringify!($size_field));
280 }
281 let start = pos;
282 pos += len;
283
284 let $name = start..pos;
285 )*
286
287 if pos < stream_len {
288 warn!(pos, stream_len, "Something is wrong with the code that finds the ranges of substreams. Expected pos to be equal to stream_len.");
289 } else if pos > stream_len {
290 error!(pos, stream_len, "Something is very wrong with the DBI header. The sum of the subtream lengths (pos) exceeds the stream len.");
291 } else {
292 }
294
295 Ok(Self {
296 $( $name, )*
297 })
298 }
299 }
300 }
301}
302
303dbi_substreams! {
304 modules_bytes, modules_bytes_mut, mod_info_size;
306 section_contributions_bytes, section_contributions_bytes_mut, section_contribution_size;
307 section_map_bytes, section_map_bytes_mut, section_map_size;
308 source_info, source_info_mut, source_info_size;
309 type_server_map, type_server_map_mut, type_server_map_size;
310 edit_and_continue, edit_and_continue_mut, edit_and_continue_size;
311 optional_debug_header_bytes, optional_debug_header_bytes_mut, optional_dbg_header_size;
312}
313
314impl<StreamData: AsRef<[u8]>> DbiStream<StreamData> {
315 pub fn header(&self) -> Result<&DbiStreamHeader> {
317 if let Ok((header, _)) = DbiStreamHeader::ref_from_prefix(self.stream_data.as_ref()) {
318 Ok(header)
319 } else {
320 bail!("The DBI stream is too small to contain a valid header.")
321 }
322 }
323
324 pub fn header_mut(&mut self) -> Result<&mut DbiStreamHeader>
326 where
327 StreamData: AsMut<[u8]>,
328 {
329 if let Ok((header, _)) = DbiStreamHeader::mut_from_prefix(self.stream_data.as_mut()) {
330 Ok(header)
331 } else {
332 bail!("The DBI stream is too small to contain a valid header.")
333 }
334 }
335
336 fn substream_data(&self, range: Range<usize>) -> &[u8] {
337 &self.stream_data.as_ref()[range]
338 }
339
340 fn substream_data_mut(&mut self, range: Range<usize>) -> &mut [u8]
341 where
342 StreamData: AsMut<[u8]>,
343 {
344 &mut self.stream_data.as_mut()[range]
345 }
346
347 pub fn modules(&self) -> ModInfoSubstream<&[u8]> {
349 ModInfoSubstream {
350 substream_data: self.modules_bytes(),
351 }
352 }
353
354 pub fn iter_modules(&self) -> IterModuleInfo<'_> {
356 IterModuleInfo::new(self.modules_bytes())
357 }
358
359 pub fn iter_modules_mut(&mut self) -> IterModuleInfoMut<'_>
361 where
362 StreamData: AsMut<[u8]>,
363 {
364 IterModuleInfoMut::new(self.modules_bytes_mut())
365 }
366
367 pub fn as_slice(&self) -> DbiStream<&[u8]> {
369 DbiStream {
370 stream_data: self.stream_data.as_ref(),
371 substreams: self.substreams.clone(),
372 }
373 }
374
375 pub fn parse(stream_data: StreamData) -> anyhow::Result<Self> {
377 let stream_bytes: &[u8] = stream_data.as_ref();
378
379 if stream_bytes.is_empty() {
380 return Ok(Self {
381 substreams: Default::default(),
382 stream_data,
383 });
384 }
385
386 let mut p = Parser::new(stream_bytes);
387 let dbi_header: &DbiStreamHeader = p.get()?;
388
389 let substreams = DbiSubstreamRanges::from_sizes(dbi_header, stream_bytes.len())?;
390
391 Ok(Self {
397 stream_data,
398 substreams,
399 })
400 }
401
402 pub fn sources(&self) -> anyhow::Result<sources::DbiSourcesSubstream<'_>> {
404 DbiSourcesSubstream::parse(self.source_info())
405 }
406
407 pub fn section_contributions(
410 &self,
411 ) -> anyhow::Result<section_contrib::SectionContributionsSubstream<'_>> {
412 let substream_bytes = self.section_contributions_bytes();
413 section_contrib::SectionContributionsSubstream::parse(substream_bytes)
414 }
415
416 pub fn section_map(&self) -> anyhow::Result<section_map::SectionMap<'_>> {
418 let section_map_bytes = self.section_map_bytes();
419 section_map::SectionMap::parse(section_map_bytes)
420 }
421
422 pub fn optional_debug_header(&self) -> anyhow::Result<optional_dbg::OptionalDebugHeader<'_>> {
424 optional_dbg::OptionalDebugHeader::parse(self.optional_debug_header_bytes())
425 }
426
427 pub fn optional_debug_header_mut(&mut self) -> anyhow::Result<&mut [U16<LE>]>
429 where
430 StreamData: AsMut<[u8]>,
431 {
432 if self.substreams.optional_debug_header_bytes.is_empty() {
433 Ok(&mut [])
434 } else {
435 let substream_bytes =
436 &mut self.stream_data.as_mut()[self.substreams.optional_debug_header_bytes.clone()];
437
438 if let Ok(slice) = <[U16<LE>]>::mut_from_bytes(substream_bytes) {
439 Ok(slice)
440 } else {
441 bail!(
442 "The Optional Debug Header substream within the DBI stream is malformed (length is not valid)."
443 );
444 }
445 }
446 }
447}
448
449pub fn read_dbi_stream_header<F: ReadAt>(msf: &Container<F>) -> anyhow::Result<DbiStreamHeader> {
453 let stream_reader = msf.get_stream_reader(Stream::DBI.into())?;
454 if !stream_reader.is_empty() {
455 let mut dbi_header = DbiStreamHeader::new_zeroed();
456 stream_reader.read_exact_at(dbi_header.as_mut_bytes(), 0)?;
457 Ok(dbi_header)
458 } else {
459 Ok(DbiStreamHeader::read_from_bytes(EMPTY_DBI_STREAM_HEADER.as_slice()).unwrap())
460 }
461}
462
463pub fn read_dbi_stream<F: ReadAt>(
468 container: &Container<F>,
469) -> Result<DbiStream<Vec<u8>>, anyhow::Error> {
470 let mut dbi_stream_data = container.read_stream_to_vec(Stream::DBI.into())?;
471 if dbi_stream_data.is_empty() {
472 dbi_stream_data = EMPTY_DBI_STREAM_HEADER.to_vec();
473 }
474
475 DbiStream::parse(dbi_stream_data)
476}
477
478impl<F: ReadAt> crate::Pdb<F> {
479 pub fn read_dbi_stream_header(&self) -> anyhow::Result<DbiStreamHeader> {
481 read_dbi_stream_header(&self.container)
482 }
483
484 pub fn read_dbi_stream(&self) -> Result<DbiStream<Vec<u8>>, anyhow::Error> {
487 read_dbi_stream(&self.container)
488 }
489
490 fn read_dbi_substream(&self, range: Range<usize>) -> anyhow::Result<Vec<u8>> {
491 let len = range.len();
492 let mut substream_data = vec![0; len];
493 let reader = self.container.get_stream_reader(Stream::DBI.into())?;
494 reader.read_exact_at(&mut substream_data, range.start as u64)?;
495 Ok(substream_data)
496 }
497
498 fn read_dbi_substream_u32(&self, range: Range<usize>) -> anyhow::Result<Vec<u32>> {
499 let len_bytes = range.len();
500 let len_u32 = len_bytes / 4;
501 let mut substream_data = vec![0u32; len_u32];
502 let reader = self.container.get_stream_reader(Stream::DBI.into())?;
503 reader.read_exact_at(substream_data.as_mut_bytes(), range.start as u64)?;
504 Ok(substream_data)
505 }
506
507 pub fn read_modules(&self) -> anyhow::Result<ModInfoSubstream<Vec<u8>>> {
511 let substream_data = self.read_dbi_substream(self.dbi_substreams.modules_bytes.clone())?;
512 Ok(ModInfoSubstream { substream_data })
513 }
514
515 pub fn modules(&self) -> anyhow::Result<&ModInfoSubstream<Vec<u8>>> {
518 get_or_init_err(&self.cached.dbi_modules_cell, || self.read_modules())
519 }
520
521 pub fn read_sources_data(&self) -> Result<Vec<u8>> {
523 self.read_dbi_substream(self.dbi_substreams.source_info.clone())
524 }
525
526 pub fn sources_data(&self) -> Result<&[u8]> {
528 let sources_data =
529 get_or_init_err(&self.cached.dbi_sources_cell, || self.read_sources_data())?;
530 Ok(sources_data)
531 }
532
533 pub fn sources(&self) -> Result<sources::DbiSourcesSubstream<'_>> {
535 let sources_data = self.sources_data()?;
536 sources::DbiSourcesSubstream::parse(sources_data)
537 }
538
539 pub fn drop_sources(&mut self) {
541 self.cached.dbi_sources_cell = Default::default();
542 }
543
544 pub fn read_section_contributions(&self) -> Result<Vec<u32>> {
550 self.read_dbi_substream_u32(self.dbi_substreams.section_contributions_bytes.clone())
551 }
552
553 pub fn read_optional_debug_streams(&self) -> anyhow::Result<OptionalDebugHeaders> {
555 let num_opt_streams = self.dbi_substreams.optional_debug_header_bytes.len() / 2;
556 if num_opt_streams == 0 {
557 return Ok(OptionalDebugHeaders {
558 streams: Vec::new(),
559 });
560 }
561
562 let mut streams: Vec<u16> = vec![0; num_opt_streams];
563 let sr = self.get_stream_reader(Stream::DBI.value() as u32)?;
564 sr.read_exact_at(
565 streams.as_mut_bytes(),
566 self.dbi_substreams.optional_debug_header_bytes.start as u64,
567 )?;
568
569 Ok(OptionalDebugHeaders { streams })
570 }
571
572 pub fn fixup_stream(&self) -> anyhow::Result<Option<u32>> {
574 self.optional_debug_stream(OptionalDebugStream::FIXUP_DATA)
575 }
576
577 pub fn optional_debug_streams(&self) -> anyhow::Result<&OptionalDebugHeaders> {
579 get_or_init_err(&self.cached.optional_dbg_streams, || {
580 self.read_optional_debug_streams()
581 })
582 }
583
584 pub fn optional_debug_stream(&self, i: OptionalDebugStream) -> anyhow::Result<Option<u32>> {
586 let streams = self.optional_debug_streams()?;
587 if let Some(&s) = streams.streams.get(i.0 as usize) {
588 if s != NIL_STREAM_INDEX {
589 Ok(Some(s as u32))
590 } else {
591 Ok(None)
592 }
593 } else {
594 Ok(None)
595 }
596 }
597
598 pub fn read_section_headers(&self) -> anyhow::Result<Box<[IMAGE_SECTION_HEADER]>> {
600 let Some(stream) = self.optional_debug_stream(OptionalDebugStream::SECTION_HEADER_DATA)?
601 else {
602 return Ok(Box::from([]));
604 };
605
606 let sr = self.get_stream_reader(stream)?;
607 let stream_size = sr.stream_size();
608 let num_sections = stream_size as usize / core::mem::size_of::<IMAGE_SECTION_HEADER>();
609 let mut section_headers: Box<[IMAGE_SECTION_HEADER]> =
610 <[IMAGE_SECTION_HEADER]>::new_box_zeroed_with_elems(num_sections).unwrap();
611 sr.read_exact_at(section_headers.as_mut_bytes(), 0)?;
612 Ok(section_headers)
613 }
614
615 pub fn section_headers(&self) -> anyhow::Result<&[IMAGE_SECTION_HEADER]> {
617 get_or_init_err(&self.cached.section_headers, || self.read_section_headers()).map(|v| &**v)
618 }
619}
620
621pub fn validate_dbi_stream(stream_data: &[u8]) -> anyhow::Result<()> {
623 let dbi_stream = DbiStream::parse(stream_data)?;
624
625 let num_modules: usize = dbi_stream.modules().iter().count();
627
628 let sources = DbiSourcesSubstream::parse(dbi_stream.source_info())?;
629 if sources.num_modules() != num_modules {
630 bail!(
631 "Number of modules found in Sources substream ({}) does not match number of Module Info structs found in Modules substream ({}).",
632 sources.num_modules(),
633 num_modules
634 );
635 }
636
637 Ok(())
638}