ms_pdb/syms/
iter.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
use super::*;
use crate::utils::iter::HasRestLen;
use std::mem::take;
use tracing::error;

/// Parses [`Sym`] records from a symbol stream.
#[derive(Clone)]
pub struct SymIter<'a> {
    data: &'a [u8],
}

impl<'a> HasRestLen for SymIter<'a> {
    fn rest_len(&self) -> usize {
        self.data.len()
    }
}

/// Parses [`SymMut`] records from a symbol stream.
///
/// This iterator allows you to modify the payload of a symbol record but not to change its length
/// or its kind.
pub struct SymIterMut<'a> {
    data: &'a mut [u8],
}

impl<'a> SymIterMut<'a> {
    /// Parses the 4-byte CodeView signature that is at the start of a module symbol stream.
    pub fn get_signature(&mut self) -> Result<[u8; 4], ParserError> {
        let mut p = ParserMut::new(take(&mut self.data));
        let sig = p.copy()?;
        self.data = p.into_rest();
        Ok(sig)
    }
}

impl<'a> HasRestLen for SymIterMut<'a> {
    fn rest_len(&self) -> usize {
        self.data.len()
    }
}

impl<'a> SymIter<'a> {
    /// Creates a new symbol iterator.
    pub fn new(data: &'a [u8]) -> Self {
        Self { data }
    }

    /// Parses the 4-byte CodeView signature that is at the start of a module symbol stream.
    pub fn get_signature(&mut self) -> Result<[u8; 4], ParserError> {
        let mut p = Parser::new(self.data);
        let sig = p.copy()?;
        self.data = p.into_rest();
        Ok(sig)
    }

    /// The remaining unparsed bytes in the symbol stream.
    pub fn rest(&self) -> &'a [u8] {
        self.data
    }

    /// Parses a single record from `data`.
    pub fn one(data: &'a [u8]) -> Option<Sym<'a>> {
        Self::new(data).next()
    }
}

impl<'a> Iterator for SymIter<'a> {
    type Item = Sym<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.data.is_empty() {
            return None;
        }

        let mut p = Parser::new(self.data);
        let record_len = p.u16().ok()?;
        if record_len < 2 {
            error!(
                invalid_record_len = record_len,
                iterator_pos = self.data.len(),
                "type record has invalid len"
            );
            return None;
        }

        let kind = SymKind(p.u16().ok()?);
        let record_data = p.bytes(record_len as usize - 2).ok()?;

        self.data = p.into_rest();

        Some(Sym {
            kind,
            data: record_data,
        })
    }
}

#[test]
fn test_sym_iter() {
    #[rustfmt::skip]
    let data: &[u8] = &[
        // record 0, total size = 8
        /* 0x0000 */ 6, 0,                              // size
        /* 0x0002 */ 0x4c, 0x11,                        // S_BUILDINFO
        /* 0x0004 */ 1, 2, 3, 4,                        // payload (ItemId)

        // record 1, total size = 12
        /* 0x0008 */ 10, 0,                              // size
        /* 0x000a */ 0x24, 0x11,                        // S_UNAMESPACE
        /* 0x000c */ b'b', b'o', b'o', b's',            // payload (6 bytes)
        /* 0x0010 */ b't', 0,
        /* 0x0012 */ 0xf1, 0xf2,                        // alignment padding (inside payload)

        // record 2, total size = 12
        /* 0x0014 */ 10, 0,                             // size
        /* 0x0016 */ 0x24, 0x11,                        // S_UNAMESPACE
        /* 0x0018 */ b'a', b'b', b'c', b'd',            // payload
        /* 0x001c */ b'e', b'f', b'g', 0,               // no alignment padding

        /* 0x0020 : end */
    ];

    let mut i = SymIter::new(data);

    // parse record 0
    assert_eq!(i.rest_len(), 0x20);
    let s0 = i.next().unwrap();
    assert_eq!(s0.kind, SymKind::S_BUILDINFO);
    let s0_data = s0.parse().unwrap();
    assert!(matches!(s0_data, SymData::BuildInfo(_)));

    // parse record 1
    assert_eq!(i.rest_len(), 0x18);
    let s1 = i.next().unwrap();
    assert_eq!(s1.kind, SymKind::S_UNAMESPACE);
    match s1.parse() {
        Ok(SymData::UsingNamespace(ns)) => assert_eq!(ns.namespace, "boost"),
        sd => panic!("wrong: {sd:?}"),
    }

    // parse record 2
    assert_eq!(i.rest_len(), 0xc);
    let s1 = i.next().unwrap();
    assert_eq!(s1.kind, SymKind::S_UNAMESPACE);
    match s1.parse() {
        Ok(SymData::UsingNamespace(ns)) => assert_eq!(ns.namespace, "abcdefg"),
        sd => panic!("wrong: {sd:?}"),
    }

    // end
    assert_eq!(i.rest_len(), 0);
    assert!(i.next().is_none());
}

impl<'a> SymIterMut<'a> {
    /// Creates a new symbol iterator.
    pub fn new(data: &'a mut [u8]) -> Self {
        Self { data }
    }

    /// The remaining unparsed bytes in the symbol stream.
    pub fn rest(&self) -> &[u8] {
        self.data
    }

    /// The remaining unparsed bytes in the symbol stream, with mutable access.
    pub fn rest_mut(&mut self) -> &mut [u8] {
        self.data
    }

    /// Converts this iterator into a mutable reference to the unparsed bytes in the symbol stream.
    pub fn into_rest(self) -> &'a mut [u8] {
        self.data
    }
}

impl<'a> Iterator for SymIterMut<'a> {
    type Item = SymMut<'a>;

    fn next(&mut self) -> Option<Self::Item> {
        if self.data.len() < 4 {
            return None;
        }

        // We steal self.data because it is the only way that split_at_mut() can work.
        let d = core::mem::take(&mut self.data);

        let mut p = Parser::new(d);
        let record_len = p.u16().ok()?;
        if record_len < 2 {
            error!(
                record_len,
                iterator_len = self.data.len(),
                "type record has invalid len"
            );
            self.data = d;
            return None;
        }

        let kind = SymKind(p.u16().ok()?);

        let (entire_record_data, hi) = d.split_at_mut(2 + record_len as usize);
        self.data = hi;

        let record_data = &mut entire_record_data[4..];

        Some(SymMut {
            kind,
            data: record_data,
        })
    }
}