ms_pdb/dbi/optional_dbg.rs
1//! Decodes the Optional Debug Header Substream.
2//!
3//! This substream contains an array of stream indexes. The order of the array is significant;
4//! each has a specific purpose. They are enumerated by the [`OptionalDebugHeaderStream`] type.
5//!
6//! # References
7//! * <https://llvm.org/docs/PDB/DbiStream.html#id10>
8//! * [`DBGTYPE` in `pdb.h`](https://github.com/microsoft/microsoft-pdb/blob/805655a28bd8198004be2ac27e6e0290121a5e89/langapi/include/pdb.h#L438)
9
10use super::*;
11
12/// Provides access to the Optional Debug Header.
13pub struct OptionalDebugHeader<'a> {
14 /// Raw access to the stream indexes
15 pub stream_indexes: &'a [StreamIndexU16],
16}
17
18impl<'a> OptionalDebugHeader<'a> {
19 /// Parses the Optional Debug Header Substream.
20 pub fn parse(bytes: &'a [u8]) -> anyhow::Result<Self> {
21 let Ok(stream_indexes) = <[StreamIndexU16]>::ref_from_bytes(bytes) else {
22 bail!("The OptionalDebugHeader has an invalid size. The size is required to be a multiple of 2. Size: {}",
23 bytes.len());
24 };
25
26 Ok(Self { stream_indexes })
27 }
28
29 /// Gets a stream index, given an index into the Optional Debug Header.
30 pub fn stream_by_index(&self, i: usize) -> Option<u32> {
31 self.stream_indexes.get(i)?.get()
32 }
33
34 /// Gets a stream index, given an identifier for a stream within the Optional Debug Header.
35 pub fn stream(&self, s: OptionalDebugHeaderStream) -> Option<u32> {
36 self.stream_by_index(s as usize)
37 }
38
39 /// The number of stream indexes in the Optional Debug Header Substream.
40 pub fn num_streams(&self) -> usize {
41 self.stream_indexes.len()
42 }
43
44 /// Iterates the streams within the Optional Debug Header. The iterated values are
45 /// `(i, stream)` where `i` is an index into the Optional Debug Header.
46 /// `OptionalDebugHeaderStream::try_from(i)`.
47 pub fn iter_streams(&self) -> IterStreams<'_> {
48 IterStreams {
49 stream_indexes: self.stream_indexes,
50 next: 0,
51 }
52 }
53}
54
55/// Iterates streams
56pub struct IterStreams<'a> {
57 stream_indexes: &'a [StreamIndexU16],
58 next: usize,
59}
60
61impl<'a> Iterator for IterStreams<'a> {
62 type Item = (usize, u32);
63
64 fn next(&mut self) -> Option<Self::Item> {
65 while self.next < self.stream_indexes.len() {
66 let i = self.next;
67 let stream_index_or_nil = self.stream_indexes[i].get();
68 self.next += 1;
69
70 if let Some(stream_index) = stream_index_or_nil {
71 return Some((i, stream_index));
72 }
73 }
74 None
75 }
76}
77
78macro_rules! optional_debug_header_streams {
79 (
80 $(
81 $( #[$a:meta] )*
82 $index:literal, $name:ident, $description:expr;
83 )*
84 ) => {
85 /// Identifies the stream indexes stored in the Optional Debug Header.
86 #[derive(Copy, Clone, Eq, PartialEq, Debug)]
87 #[repr(u8)]
88 #[allow(non_camel_case_types)]
89 #[allow(missing_docs)]
90 pub enum OptionalDebugHeaderStream {
91 $(
92 $( #[$a] )*
93 $name = $index,
94 )*
95 }
96
97 /// The short name (identifier) for each of the names in `OptionalDebugHeaderStream`.
98 pub static OPTIONAL_DEBUG_HEADER_STREAM_NAME: [&str; 11] = [
99 $(
100 stringify!($name),
101 )*
102 ];
103
104 /// The for each of the names in `OptionalDebugHeaderStream`.
105 pub static OPTIONAL_DEBUG_HEADER_STREAM_DESCRIPTION: [&str; 11] = [
106 $(
107 $description,
108 )*
109 ];
110
111 impl TryFrom<usize> for OptionalDebugHeaderStream {
112 type Error = ();
113
114 fn try_from(i: usize) -> std::result::Result<Self, Self::Error> {
115 match i {
116 $( $index => Ok(Self::$name), )*
117 _ => Err(()),
118 }
119 }
120 }
121 }
122}
123
124optional_debug_header_streams! {
125 /// Stream contains an array of `FPO_DATA` structures. This contains the relocated contents of
126 /// any `.debug$F` section from any of the linker inputs.
127 0, fpo_data, "";
128 /// Stream contains a debug data directory of type `IMAGE_DEBUG_TYPE_EXCEPTION`.
129 1, exception_data, "";
130 /// Stream contains a debug data directory of type `IMAGE_DEBUG_TYPE_FIXUP`.
131 2, fixup_data, "";
132 /// Stream contains a debug data directory of type `IMAGE_DEBUG_TYPE_OMAP_TO_SRC`.
133 /// This is used for mapping addresses from instrumented code to uninstrumented code.
134 3, omap_to_src_data, "";
135 /// Stream contains a debug data directory of type `IMAGE_DEBUG_TYPE_OMAP_FROM_SRC`.
136 /// This is used for mapping addresses from uninstrumented code to instrumented code.
137 4, omap_from_src_data, "";
138 /// A dump of all section headers from the original executable.
139 5, section_header_data, "";
140 6, token_to_record_id_map, "";
141 /// Exception handler data
142 7, xdata, "";
143 /// Procedure data
144 8, pdata, "";
145 9, new_fpo_data, "";
146 10, original_section_header_data, "";
147}