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    /// Parses the 4-byte CodeView signature that is at the start of a module symbol stream.
49    pub fn get_signature(&mut self) -> Result<[u8; 4], ParserError> {
50        let mut p = Parser::new(self.data);
51        let sig = p.copy()?;
52        self.data = p.into_rest();
53        Ok(sig)
54    }
55
56    /// The remaining unparsed bytes in the symbol stream.
57    pub fn rest(&self) -> &'a [u8] {
58        self.data
59    }
60
61    /// Parses a single record from `data`.
62    pub fn one(data: &'a [u8]) -> Option<Sym<'a>> {
63        Self::new(data).next()
64    }
65}
66
67impl<'a> Iterator for SymIter<'a> {
68    type Item = Sym<'a>;
69
70    fn next(&mut self) -> Option<Self::Item> {
71        if self.data.is_empty() {
72            return None;
73        }
74
75        let mut p = Parser::new(self.data);
76        let record_len = p.u16().ok()?;
77        if record_len < 2 {
78            error!(
79                invalid_record_len = record_len,
80                iterator_pos = self.data.len(),
81                "type record has invalid len"
82            );
83            return None;
84        }
85
86        let kind = SymKind(p.u16().ok()?);
87        let record_data = p.bytes(record_len as usize - 2).ok()?;
88
89        self.data = p.into_rest();
90
91        Some(Sym {
92            kind,
93            data: record_data,
94        })
95    }
96}
97
98#[test]
99fn test_sym_iter() {
100    #[rustfmt::skip]
101    let data: &[u8] = &[
102        // record 0, total size = 8
103        /* 0x0000 */ 6, 0,                              // size
104        /* 0x0002 */ 0x4c, 0x11,                        // S_BUILDINFO
105        /* 0x0004 */ 1, 2, 3, 4,                        // payload (ItemId)
106
107        // record 1, total size = 12
108        /* 0x0008 */ 10, 0,                              // size
109        /* 0x000a */ 0x24, 0x11,                        // S_UNAMESPACE
110        /* 0x000c */ b'b', b'o', b'o', b's',            // payload (6 bytes)
111        /* 0x0010 */ b't', 0,
112        /* 0x0012 */ 0xf1, 0xf2,                        // alignment padding (inside payload)
113
114        // record 2, total size = 12
115        /* 0x0014 */ 10, 0,                             // size
116        /* 0x0016 */ 0x24, 0x11,                        // S_UNAMESPACE
117        /* 0x0018 */ b'a', b'b', b'c', b'd',            // payload
118        /* 0x001c */ b'e', b'f', b'g', 0,               // no alignment padding
119
120        /* 0x0020 : end */
121    ];
122
123    let mut i = SymIter::new(data);
124
125    // parse record 0
126    assert_eq!(i.rest_len(), 0x20);
127    let s0 = i.next().unwrap();
128    assert_eq!(s0.kind, SymKind::S_BUILDINFO);
129    let s0_data = s0.parse().unwrap();
130    assert!(matches!(s0_data, SymData::BuildInfo(_)));
131
132    // parse record 1
133    assert_eq!(i.rest_len(), 0x18);
134    let s1 = i.next().unwrap();
135    assert_eq!(s1.kind, SymKind::S_UNAMESPACE);
136    match s1.parse() {
137        Ok(SymData::UsingNamespace(ns)) => assert_eq!(ns.namespace, "boost"),
138        sd => panic!("wrong: {sd:?}"),
139    }
140
141    // parse record 2
142    assert_eq!(i.rest_len(), 0xc);
143    let s1 = i.next().unwrap();
144    assert_eq!(s1.kind, SymKind::S_UNAMESPACE);
145    match s1.parse() {
146        Ok(SymData::UsingNamespace(ns)) => assert_eq!(ns.namespace, "abcdefg"),
147        sd => panic!("wrong: {sd:?}"),
148    }
149
150    // end
151    assert_eq!(i.rest_len(), 0);
152    assert!(i.next().is_none());
153}
154
155impl<'a> SymIterMut<'a> {
156    /// Creates a new symbol iterator.
157    pub fn new(data: &'a mut [u8]) -> Self {
158        Self { data }
159    }
160
161    /// The remaining unparsed bytes in the symbol stream.
162    pub fn rest(&self) -> &[u8] {
163        self.data
164    }
165
166    /// The remaining unparsed bytes in the symbol stream, with mutable access.
167    pub fn rest_mut(&mut self) -> &mut [u8] {
168        self.data
169    }
170
171    /// Converts this iterator into a mutable reference to the unparsed bytes in the symbol stream.
172    pub fn into_rest(self) -> &'a mut [u8] {
173        self.data
174    }
175}
176
177impl<'a> Iterator for SymIterMut<'a> {
178    type Item = SymMut<'a>;
179
180    fn next(&mut self) -> Option<Self::Item> {
181        if self.data.len() < 4 {
182            return None;
183        }
184
185        // We steal self.data because it is the only way that split_at_mut() can work.
186        let d = core::mem::take(&mut self.data);
187
188        let mut p = Parser::new(d);
189        let record_len = p.u16().ok()?;
190        if record_len < 2 {
191            error!(
192                record_len,
193                iterator_len = self.data.len(),
194                "type record has invalid len"
195            );
196            self.data = d;
197            return None;
198        }
199
200        let kind = SymKind(p.u16().ok()?);
201
202        let (entire_record_data, hi) = d.split_at_mut(2 + record_len as usize);
203        self.data = hi;
204
205        let record_data = &mut entire_record_data[4..];
206
207        Some(SymMut {
208            kind,
209            data: record_data,
210        })
211    }
212}