ms_codeview/syms/
iter.rs

1use super::*;
2use crate::utils::iter::HasRestLen;
3use std::mem::take;
4use tracing::error;
5
6/// Parses [`Sym`] records from a symbol stream.
7#[derive(Clone)]
8pub struct SymIter<'a> {
9    data: &'a [u8],
10}
11
12impl<'a> HasRestLen for SymIter<'a> {
13    fn rest_len(&self) -> usize {
14        self.data.len()
15    }
16}
17
18/// Parses [`SymMut`] records from a symbol stream.
19///
20/// This iterator allows you to modify the payload of a symbol record but not to change its length
21/// or its kind.
22pub struct SymIterMut<'a> {
23    data: &'a mut [u8],
24}
25
26impl<'a> SymIterMut<'a> {
27    /// Parses the 4-byte CodeView signature that is at the start of a module symbol stream.
28    pub fn get_signature(&mut self) -> Result<[u8; 4], ParserError> {
29        let mut p = ParserMut::new(take(&mut self.data));
30        let sig = p.copy()?;
31        self.data = p.into_rest();
32        Ok(sig)
33    }
34}
35
36impl<'a> HasRestLen for SymIterMut<'a> {
37    fn rest_len(&self) -> usize {
38        self.data.len()
39    }
40}
41
42impl<'a> SymIter<'a> {
43    /// Creates a new symbol iterator.
44    pub fn new(data: &'a [u8]) -> Self {
45        Self { data }
46    }
47
48    /// Skip 4 bytes for the header of a module stream
49    pub fn skip_module_prefix(&mut self) {
50        if self.data.len() >= 4 {
51            self.data = &self.data[4..];
52        }
53    }
54
55    /// Creates a new symbol iterator for symbols stored in a module stream.
56    ///
57    /// The symbol data in a module stream begins with a 4-byte header. This function ignores
58    /// the 4-byte header.
59    pub fn for_module_syms(data: &'a [u8]) -> Self {
60        Self {
61            data: if data.len() < 4 { &[] } else { &data[4..] },
62        }
63    }
64
65    /// Parses the 4-byte CodeView signature that is at the start of a module symbol stream.
66    pub fn get_signature(&mut self) -> Result<[u8; 4], ParserError> {
67        let mut p = Parser::new(self.data);
68        let sig = p.copy()?;
69        self.data = p.into_rest();
70        Ok(sig)
71    }
72
73    /// The remaining unparsed bytes in the symbol stream.
74    pub fn rest(&self) -> &'a [u8] {
75        self.data
76    }
77
78    /// Parses a single record from `data`.
79    pub fn one(data: &'a [u8]) -> Option<Sym<'a>> {
80        Self::new(data).next()
81    }
82}
83
84impl<'a> Iterator for SymIter<'a> {
85    type Item = Sym<'a>;
86
87    fn next(&mut self) -> Option<Self::Item> {
88        if self.data.is_empty() {
89            return None;
90        }
91
92        let mut p = Parser::new(self.data);
93        let record_len = p.u16().ok()?;
94        if record_len < 2 {
95            error!(
96                invalid_record_len = record_len,
97                iterator_pos = self.data.len(),
98                "type record has invalid len"
99            );
100            return None;
101        }
102
103        let kind = SymKind(p.u16().ok()?);
104        let record_data = p.bytes(record_len as usize - 2).ok()?;
105
106        self.data = p.into_rest();
107
108        Some(Sym {
109            kind,
110            data: record_data,
111        })
112    }
113}
114
115#[test]
116fn test_sym_iter() {
117    #[rustfmt::skip]
118    let data: &[u8] = &[
119        // record 0, total size = 8
120        /* 0x0000 */ 6, 0,                              // size
121        /* 0x0002 */ 0x4c, 0x11,                        // S_BUILDINFO
122        /* 0x0004 */ 1, 2, 3, 4,                        // payload (ItemId)
123
124        // record 1, total size = 12
125        /* 0x0008 */ 10, 0,                              // size
126        /* 0x000a */ 0x24, 0x11,                        // S_UNAMESPACE
127        /* 0x000c */ b'b', b'o', b'o', b's',            // payload (6 bytes)
128        /* 0x0010 */ b't', 0,
129        /* 0x0012 */ 0xf1, 0xf2,                        // alignment padding (inside payload)
130
131        // record 2, total size = 12
132        /* 0x0014 */ 10, 0,                             // size
133        /* 0x0016 */ 0x24, 0x11,                        // S_UNAMESPACE
134        /* 0x0018 */ b'a', b'b', b'c', b'd',            // payload
135        /* 0x001c */ b'e', b'f', b'g', 0,               // no alignment padding
136
137        /* 0x0020 : end */
138    ];
139
140    let mut i = SymIter::new(data);
141
142    // parse record 0
143    assert_eq!(i.rest_len(), 0x20);
144    let s0 = i.next().unwrap();
145    assert_eq!(s0.kind, SymKind::S_BUILDINFO);
146    let s0_data = s0.parse().unwrap();
147    assert!(matches!(s0_data, SymData::BuildInfo(_)));
148
149    // parse record 1
150    assert_eq!(i.rest_len(), 0x18);
151    let s1 = i.next().unwrap();
152    assert_eq!(s1.kind, SymKind::S_UNAMESPACE);
153    match s1.parse() {
154        Ok(SymData::UsingNamespace(ns)) => assert_eq!(ns.namespace, "boost"),
155        sd => panic!("wrong: {sd:?}"),
156    }
157
158    // parse record 2
159    assert_eq!(i.rest_len(), 0xc);
160    let s1 = i.next().unwrap();
161    assert_eq!(s1.kind, SymKind::S_UNAMESPACE);
162    match s1.parse() {
163        Ok(SymData::UsingNamespace(ns)) => assert_eq!(ns.namespace, "abcdefg"),
164        sd => panic!("wrong: {sd:?}"),
165    }
166
167    // end
168    assert_eq!(i.rest_len(), 0);
169    assert!(i.next().is_none());
170}
171
172impl<'a> SymIterMut<'a> {
173    /// Creates a new symbol iterator.
174    pub fn new(data: &'a mut [u8]) -> Self {
175        Self { data }
176    }
177
178    /// The remaining unparsed bytes in the symbol stream.
179    pub fn rest(&self) -> &[u8] {
180        self.data
181    }
182
183    /// The remaining unparsed bytes in the symbol stream, with mutable access.
184    pub fn rest_mut(&mut self) -> &mut [u8] {
185        self.data
186    }
187
188    /// Converts this iterator into a mutable reference to the unparsed bytes in the symbol stream.
189    pub fn into_rest(self) -> &'a mut [u8] {
190        self.data
191    }
192}
193
194impl<'a> Iterator for SymIterMut<'a> {
195    type Item = SymMut<'a>;
196
197    fn next(&mut self) -> Option<Self::Item> {
198        if self.data.len() < 4 {
199            return None;
200        }
201
202        // We steal self.data because it is the only way that split_at_mut() can work.
203        let d = core::mem::take(&mut self.data);
204
205        let mut p = Parser::new(d);
206        let record_len = p.u16().ok()?;
207        if record_len < 2 {
208            error!(
209                record_len,
210                iterator_len = self.data.len(),
211                "type record has invalid len"
212            );
213            self.data = d;
214            return None;
215        }
216
217        let kind = SymKind(p.u16().ok()?);
218
219        let (entire_record_data, hi) = d.split_at_mut(2 + record_len as usize);
220        self.data = hi;
221
222        let record_data = &mut entire_record_data[4..];
223
224        Some(SymMut {
225            kind,
226            data: record_data,
227        })
228    }
229}