1use std::borrow::Cow;
11use std::fmt;
12use std::result;
13
14use crate::common::*;
15use crate::msf::*;
16use crate::{FallibleIterator, SectionCharacteristics};
17
18#[derive(Debug)]
46pub struct DebugInformation<'s> {
47 stream: Stream<'s>,
48 header: DBIHeader,
49 header_len: usize,
50}
51
52impl<'s> DebugInformation<'s> {
53 pub(crate) fn parse(stream: Stream<'s>) -> Result<Self> {
54 let mut buf = stream.parse_buffer();
55 let header = DBIHeader::parse_buf(&mut buf)?;
56 let header_len = buf.pos();
57
58 Ok(DebugInformation {
59 stream,
60 header,
61 header_len,
62 })
63 }
64
65 pub(crate) fn header(&self) -> DBIHeader {
66 self.header
67 }
68
69 pub fn machine_type(&self) -> Result<MachineType> {
71 Ok(self.header.machine_type.into())
72 }
73
74 pub fn age(&self) -> Option<u32> {
85 match self.header.age {
86 0 => None,
87 age => Some(age),
88 }
89 }
90
91 pub fn modules(&self) -> Result<ModuleIter<'_>> {
93 let mut buf = self.stream.parse_buffer();
94 buf.take(self.header_len)?;
96 let modules_buf = buf.take(self.header.module_list_size as usize)?;
97 Ok(ModuleIter {
98 buf: modules_buf.into(),
99 })
100 }
101
102 pub fn section_contributions(&self) -> Result<DBISectionContributionIter<'_>> {
104 let mut buf = self.stream.parse_buffer();
105 buf.take(self.header_len + self.header.module_list_size as usize)?;
107 let contributions_buf = buf.take(self.header.section_contribution_size as usize)?;
108 DBISectionContributionIter::parse(contributions_buf.into())
109 }
110}
111
112#[non_exhaustive]
116#[derive(Debug, Copy, Clone)]
117#[allow(missing_docs)]
118pub enum HeaderVersion {
119 V41,
120 V50,
121 V60,
122 V70,
123 V110,
124 OtherValue(u32),
125}
126
127impl From<u32> for HeaderVersion {
128 #[allow(clippy::inconsistent_digit_grouping)]
129 fn from(v: u32) -> Self {
130 match v {
131 93_08_03 => Self::V41,
132 1996_03_07 => Self::V50,
133 1997_06_06 => Self::V60,
134 1999_09_03 => Self::V70,
135 2009_12_01 => Self::V110,
136 _ => Self::OtherValue(v),
137 }
138 }
139}
140
141#[derive(Debug, Copy, Clone)]
146#[allow(dead_code)] pub(crate) struct DBIHeader {
148 pub signature: u32,
149 pub version: HeaderVersion,
150 pub age: u32,
151 pub gs_symbols_stream: StreamIndex,
152
153 pub internal_version: u16,
170 pub ps_symbols_stream: StreamIndex,
171 pub pdb_dll_build_version: u16,
173
174 pub symbol_records_stream: StreamIndex,
175
176 pub pdb_dll_rbld_version: u16,
178 pub module_list_size: u32,
179 pub section_contribution_size: u32,
180 pub section_map_size: u32,
181 pub file_info_size: u32,
182
183 pub type_server_map_size: u32,
185
186 pub mfc_type_server_index: u32,
188
189 pub debug_header_size: u32,
191
192 pub ec_substream_size: u32,
194
195 pub flags: u16,
203
204 pub machine_type: u16,
205 pub reserved: u32,
206}
207
208impl DBIHeader {
209 pub fn parse(stream: Stream<'_>) -> Result<Self> {
210 Self::parse_buf(&mut stream.parse_buffer())
211 }
212
213 fn parse_buf(buf: &mut ParseBuffer<'_>) -> Result<Self> {
214 let header = Self {
215 signature: buf.parse_u32()?,
216 version: From::from(buf.parse_u32()?),
217 age: buf.parse_u32()?,
218 gs_symbols_stream: buf.parse()?,
219 internal_version: buf.parse_u16()?,
220 ps_symbols_stream: buf.parse()?,
221 pdb_dll_build_version: buf.parse_u16()?,
222 symbol_records_stream: buf.parse()?,
223 pdb_dll_rbld_version: buf.parse_u16()?,
224 module_list_size: buf.parse_u32()?,
225 section_contribution_size: buf.parse_u32()?,
226 section_map_size: buf.parse_u32()?,
227 file_info_size: buf.parse_u32()?,
228 type_server_map_size: buf.parse_u32()?,
229 mfc_type_server_index: buf.parse_u32()?,
230 debug_header_size: buf.parse_u32()?,
231 ec_substream_size: buf.parse_u32()?,
232 flags: buf.parse_u16()?,
233 machine_type: buf.parse_u16()?,
234 reserved: buf.parse_u32()?,
235 };
236
237 if header.signature != u32::max_value() {
238 return Err(Error::UnimplementedFeature("ancient DBI header"));
244 }
245
246 Ok(header)
247 }
248}
249
250#[non_exhaustive]
253#[derive(Clone, Copy, Debug, Eq, PartialEq)]
254pub enum MachineType {
255 Unknown = 0x0,
257 Am33 = 0x13,
259 Amd64 = 0x8664,
261 Arm = 0x1C0,
263 Arm64 = 0xAA64,
265 ArmNT = 0x1C4,
267 Ebc = 0xEBC,
269 X86 = 0x14C,
271 Ia64 = 0x200,
273 M32R = 0x9041,
275 Mips16 = 0x266,
277 MipsFpu = 0x366,
279 MipsFpu16 = 0x466,
281 PowerPC = 0x1F0,
283 PowerPCFP = 0x1F1,
285 R4000 = 0x166,
287 RiscV32 = 0x5032,
289 RiscV64 = 0x5064,
291 RiscV128 = 0x5128,
293 SH3 = 0x1A2,
295 SH3DSP = 0x1A3,
297 SH4 = 0x1A6,
299 SH5 = 0x1A8,
301 Thumb = 0x1C2,
303 WceMipsV2 = 0x169,
305 Invalid = 0xffff,
307}
308
309impl fmt::Display for MachineType {
310 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
311 match self {
312 Self::Invalid => write!(f, "Invalid"),
313 Self::Unknown => write!(f, "Unknown"),
314 Self::Am33 => write!(f, "Am33"),
315 Self::Amd64 => write!(f, "Amd64"),
316 Self::Arm => write!(f, "Arm"),
317 Self::Arm64 => write!(f, "Arm64"),
318 Self::ArmNT => write!(f, "ArmNT"),
319 Self::Ebc => write!(f, "Ebc"),
320 Self::X86 => write!(f, "X86"),
321 Self::Ia64 => write!(f, "Ia64"),
322 Self::M32R => write!(f, "M32R"),
323 Self::Mips16 => write!(f, "Mips16"),
324 Self::MipsFpu => write!(f, "MipsFpu"),
325 Self::MipsFpu16 => write!(f, "MipsFpu16"),
326 Self::PowerPC => write!(f, "PowerPC"),
327 Self::PowerPCFP => write!(f, "PowerPCFP"),
328 Self::R4000 => write!(f, "R4000"),
329 Self::RiscV32 => write!(f, "RiscV32"),
330 Self::RiscV64 => write!(f, "RiscV64"),
331 Self::RiscV128 => write!(f, "RiscV128"),
332 Self::SH3 => write!(f, "SH3"),
333 Self::SH3DSP => write!(f, "SH3DSP"),
334 Self::SH4 => write!(f, "SH4"),
335 Self::SH5 => write!(f, "SH5"),
336 Self::Thumb => write!(f, "Thumb"),
337 Self::WceMipsV2 => write!(f, "WceMipsV2"),
338 }
339 }
340}
341
342impl From<u16> for MachineType {
343 fn from(value: u16) -> Self {
344 match value {
345 0xffff => Self::Invalid,
346 0x0 => Self::Unknown,
347 0x13 => Self::Am33,
348 0x8664 => Self::Amd64,
349 0x1C0 => Self::Arm,
350 0xAA64 => Self::Arm64,
351 0x1C4 => Self::ArmNT,
352 0xEBC => Self::Ebc,
353 0x14C => Self::X86,
354 0x200 => Self::Ia64,
355 0x9041 => Self::M32R,
356 0x266 => Self::Mips16,
357 0x366 => Self::MipsFpu,
358 0x466 => Self::MipsFpu16,
359 0x1F0 => Self::PowerPC,
360 0x1F1 => Self::PowerPCFP,
361 0x166 => Self::R4000,
362 0x5032 => Self::RiscV32,
363 0x5064 => Self::RiscV64,
364 0x5128 => Self::RiscV128,
365 0x1A2 => Self::SH3,
366 0x1A3 => Self::SH3DSP,
367 0x1A6 => Self::SH4,
368 0x1A8 => Self::SH5,
369 0x1C2 => Self::Thumb,
370 0x169 => Self::WceMipsV2,
371 _ => Self::Unknown,
372 }
373 }
374}
375
376#[derive(Debug, Copy, Clone)]
380pub struct DBISectionContribution {
381 pub offset: PdbInternalSectionOffset,
383 pub size: u32,
385 pub characteristics: SectionCharacteristics,
389 pub module: usize,
391 pub data_crc: u32,
393 pub reloc_crc: u32,
395}
396
397impl DBISectionContribution {
398 fn parse(buf: &mut ParseBuffer<'_>) -> Result<Self> {
399 let section = buf.parse_u16()?;
400 let _padding = buf.parse_u16()?;
401 let offset = buf.parse_u32()?;
402 let size = buf.parse_u32()?;
403 let characteristics = buf.parse()?;
404 let module = buf.parse_u16()?.into();
405 let _padding = buf.parse_u16()?;
406
407 Ok(Self {
408 offset: PdbInternalSectionOffset { offset, section },
409 size,
410 characteristics,
411 module,
412 data_crc: buf.parse_u32()?,
413 reloc_crc: buf.parse_u32()?,
414 })
415 }
416}
417
418#[derive(Debug, Copy, Clone)]
423#[allow(dead_code)] pub(crate) struct DBIModuleInfo {
425 pub opened: u32,
427 pub section: DBISectionContribution,
429 pub flags: u16,
433 pub stream: StreamIndex,
435 pub symbols_size: u32,
437 pub lines_size: u32,
439 pub c13_lines_size: u32,
441 pub files: u16,
443 _padding: u16,
444 pub filename_offsets: u32,
446 pub source: u32,
448 pub compiler: u32,
450}
451
452impl DBIModuleInfo {
453 fn parse(buf: &mut ParseBuffer<'_>) -> Result<Self> {
454 Ok(Self {
455 opened: buf.parse_u32()?,
456 section: DBISectionContribution::parse(buf)?,
457 flags: buf.parse_u16()?,
458 stream: buf.parse()?,
459 symbols_size: buf.parse_u32()?,
460 lines_size: buf.parse_u32()?,
461 c13_lines_size: buf.parse_u32()?,
462 files: buf.parse_u16()?,
463 _padding: buf.parse_u16()?,
464 filename_offsets: buf.parse_u32()?,
465 source: buf.parse_u32()?,
466 compiler: buf.parse_u32()?,
467 })
468 }
469}
470
471#[derive(Debug, Clone)]
479pub struct Module<'m> {
480 info: DBIModuleInfo,
481 module_name: RawString<'m>,
482 object_file_name: RawString<'m>,
483}
484
485impl<'m> Module<'m> {
486 pub(crate) fn info(&self) -> &DBIModuleInfo {
488 &self.info
489 }
490 pub fn module_name(&self) -> Cow<'m, str> {
494 self.module_name.to_string()
495 }
496 pub fn object_file_name(&self) -> Cow<'m, str> {
502 self.object_file_name.to_string()
503 }
504}
505
506#[derive(Debug)]
508pub struct ModuleIter<'m> {
509 buf: ParseBuffer<'m>,
510}
511
512impl<'m> FallibleIterator for ModuleIter<'m> {
513 type Item = Module<'m>;
514 type Error = Error;
515
516 fn next(&mut self) -> result::Result<Option<Self::Item>, Self::Error> {
517 if self.buf.is_empty() {
519 return Ok(None);
520 }
521
522 let info = DBIModuleInfo::parse(&mut self.buf)?;
523 let module_name = self.buf.parse_cstring()?;
524 let object_file_name = self.buf.parse_cstring()?;
525 self.buf.align(4)?;
526 Ok(Some(Module {
527 info,
528 module_name,
529 object_file_name,
530 }))
531 }
532}
533
534#[derive(Debug, Copy, Clone, PartialEq)]
536#[allow(missing_docs)]
537enum DBISectionContributionStreamVersion {
538 V60,
539 V2,
540 OtherValue(u32),
541}
542
543impl From<u32> for DBISectionContributionStreamVersion {
544 fn from(v: u32) -> Self {
545 const V60: u32 = 0xeffe_0000 + 19_970_605;
546 const V2: u32 = 0xeffe_0000 + 20_140_516;
547 match v {
548 V60 => Self::V60,
549 V2 => Self::V2,
550 _ => Self::OtherValue(v),
551 }
552 }
553}
554
555#[derive(Debug)]
557pub struct DBISectionContributionIter<'c> {
558 buf: ParseBuffer<'c>,
559 version: DBISectionContributionStreamVersion,
560}
561
562impl<'c> DBISectionContributionIter<'c> {
563 fn parse(mut buf: ParseBuffer<'c>) -> Result<Self> {
564 let version = buf.parse_u32()?.into();
565 Ok(Self { buf, version })
566 }
567}
568
569impl<'c> FallibleIterator for DBISectionContributionIter<'c> {
570 type Item = DBISectionContribution;
571 type Error = Error;
572
573 fn next(&mut self) -> result::Result<Option<Self::Item>, Self::Error> {
574 if self.buf.is_empty() {
576 return Ok(None);
577 }
578
579 let contribution = DBISectionContribution::parse(&mut self.buf)?;
580 if self.version == DBISectionContributionStreamVersion::V2 {
581 self.buf.parse_u32()?;
582 }
583 Ok(Some(contribution))
584 }
585}
586
587#[derive(Debug, Copy, Clone)]
589#[allow(dead_code)] pub(crate) struct DBIExtraStreams {
591 pub fpo: StreamIndex,
602 pub exception: StreamIndex,
603 pub fixup: StreamIndex,
604 pub omap_to_src: StreamIndex,
605 pub omap_from_src: StreamIndex,
606 pub section_headers: StreamIndex,
607 pub token_rid_map: StreamIndex,
608 pub xdata: StreamIndex,
609 pub pdata: StreamIndex,
610 pub framedata: StreamIndex,
611 pub original_section_headers: StreamIndex,
612}
613
614impl DBIExtraStreams {
615 pub(crate) fn new(debug_info: &DebugInformation<'_>) -> Result<Self> {
616 let header = debug_info.header;
618 let offset = debug_info.header_len
619 + (header.module_list_size
620 + header.section_contribution_size
621 + header.section_map_size
622 + header.file_info_size
623 + header.type_server_map_size
624 + header.ec_substream_size) as usize;
625
626 let mut buf = debug_info.stream.parse_buffer();
628 buf.take(offset)?;
629
630 let bytes = buf.take(header.debug_header_size as _)?;
632
633 let mut extra_streams_buf = ParseBuffer::from(bytes);
635 Self::parse(&mut extra_streams_buf)
636 }
637
638 pub(crate) fn parse(buf: &mut ParseBuffer<'_>) -> Result<Self> {
639 if buf.len() % 2 != 0 {
642 return Err(Error::InvalidStreamLength("DbgDataHdr"));
643 }
644
645 fn next_index(buf: &mut ParseBuffer<'_>) -> Result<StreamIndex> {
646 if buf.is_empty() {
647 Ok(StreamIndex::none())
648 } else {
649 buf.parse()
650 }
651 }
652
653 Ok(Self {
654 fpo: next_index(buf)?,
655 exception: next_index(buf)?,
656 fixup: next_index(buf)?,
657 omap_to_src: next_index(buf)?,
658 omap_from_src: next_index(buf)?,
659 section_headers: next_index(buf)?,
660 token_rid_map: next_index(buf)?,
661 xdata: next_index(buf)?,
662 pdata: next_index(buf)?,
663 framedata: next_index(buf)?,
664 original_section_headers: next_index(buf)?,
665 })
666 }
667}
668
669#[cfg(test)]
670mod tests {
671 use crate::dbi::*;
672
673 #[test]
674 fn test_dbi_extra_streams() {
675 let bytes = vec![0xff, 0xff, 0x01, 0x02, 0x03, 0x04, 0xff, 0xff, 0x05, 0x06];
676
677 let mut buf = ParseBuffer::from(bytes.as_slice());
678 let extra_streams = DBIExtraStreams::parse(&mut buf).expect("parse");
679
680 assert_eq!(extra_streams.fpo, StreamIndex::none());
682 assert_eq!(extra_streams.exception, StreamIndex(0x0201));
683 assert_eq!(extra_streams.fixup, StreamIndex(0x0403));
684 assert_eq!(extra_streams.omap_to_src, StreamIndex::none());
685 assert_eq!(extra_streams.omap_from_src, StreamIndex(0x0605));
686
687 assert_eq!(extra_streams.section_headers, StreamIndex::none());
689 assert_eq!(extra_streams.token_rid_map, StreamIndex::none());
690 assert_eq!(extra_streams.original_section_headers, StreamIndex::none());
691 }
692}