ms_codeview/types/
visitor.rs

1//! Algorithm for traversing ("visiting") the dependency graph within a type stream or between a
2//! symbol stream and a type stream.
3
4use super::{ItemId, ItemIdLe};
5use crate::parser::{Parser, ParserError, ParserMut};
6use crate::types::{Leaf, TypeIndex, TypeIndexLe};
7use crate::types::{PointerFlags, introduces_virtual};
8use anyhow::Context;
9use tracing::error;
10use zerocopy::{LE, U32};
11
12/// Defines the functions needed for generically visiting type indexes within a type record or a
13/// symbol record.
14///
15/// This trait exists in order to allow a single generic function to handle visiting the `TypeIndex`
16/// values within a buffer, generic over the mutability of the access.
17pub trait RecordVisitor {
18    /// True if the parser is empty
19    fn is_empty(&self) -> bool;
20
21    /// Provides access to the rest of the record
22    fn peek_rest(&self) -> &[u8];
23
24    /// Parses a `u16` value
25    fn u16(&mut self) -> Result<u16, ParserError>;
26
27    /// Parses a `u32` value
28    fn u32(&mut self) -> Result<u32, ParserError>;
29
30    /// Skips `n` bytes of input
31    fn skip(&mut self, n: usize) -> Result<(), ParserError>;
32
33    /// Parses the next `ItemId` value and visits the location or value.
34    fn item(&mut self) -> Result<(), ParserError>;
35
36    /// Parses the next `TypeIndex` value and visits the location or value.
37    fn ty(&mut self) -> Result<(), ParserError>;
38
39    /// Parses a `NameIndex` value and visits the location or value.
40    fn name_index(&mut self) -> Result<(), ParserError>;
41
42    /// Parses a `Number`.
43    fn number(&mut self) -> Result<(), ParserError>;
44
45    /// Parses a NUL-terminated string.
46    fn strz(&mut self) -> Result<(), ParserError>;
47}
48
49/// Defines a visitor that visits every ItemId and TypeIndexLe in a record. Allows modification.
50#[allow(missing_docs)]
51pub trait IndexVisitorMut {
52    #[allow(unused_variables)]
53    fn type_index(&mut self, offset: usize, value: &mut TypeIndexLe) -> Result<(), ParserError> {
54        Ok(())
55    }
56
57    #[allow(unused_variables)]
58    fn item_id(&mut self, offset: usize, value: &mut ItemIdLe) -> Result<(), ParserError> {
59        Ok(())
60    }
61
62    #[allow(unused_variables)]
63    fn name_index(&mut self, offset: usize, value: &mut U32<LE>) -> Result<(), ParserError> {
64        Ok(())
65    }
66}
67
68/// Defines a visitor that visits every ItemId and TypeIndexLe in a record.
69#[allow(missing_docs)]
70pub trait IndexVisitor {
71    #[allow(unused_variables)]
72    fn type_index(&mut self, offset: usize, value: TypeIndex) -> Result<(), ParserError> {
73        Ok(())
74    }
75
76    #[allow(unused_variables)]
77    fn item_id(&mut self, offset: usize, value: ItemId) -> Result<(), ParserError> {
78        Ok(())
79    }
80
81    #[allow(unused_variables)]
82    fn name_index(&mut self, offset: usize, value: u32) -> Result<(), ParserError> {
83        Ok(())
84    }
85}
86
87struct RefVisitor<'a, IV: IndexVisitor> {
88    parser: Parser<'a>,
89    original_len: usize,
90    index_visitor: IV,
91}
92
93impl<'a, IV: IndexVisitor> RecordVisitor for RefVisitor<'a, IV> {
94    fn is_empty(&self) -> bool {
95        self.parser.is_empty()
96    }
97
98    fn peek_rest(&self) -> &[u8] {
99        self.parser.peek_rest()
100    }
101
102    fn u16(&mut self) -> Result<u16, ParserError> {
103        self.parser.u16()
104    }
105
106    fn u32(&mut self) -> Result<u32, ParserError> {
107        self.parser.u32()
108    }
109
110    fn skip(&mut self, n: usize) -> Result<(), ParserError> {
111        self.parser.skip(n)
112    }
113
114    fn ty(&mut self) -> Result<(), ParserError> {
115        let offset = self.original_len - self.parser.len();
116        let ti = self.parser.type_index()?;
117        self.index_visitor.type_index(offset, ti)?;
118        Ok(())
119    }
120
121    fn item(&mut self) -> Result<(), ParserError> {
122        let offset = self.original_len - self.parser.len();
123        let ii = self.parser.u32()?;
124        self.index_visitor.item_id(offset, ii)?;
125        Ok(())
126    }
127
128    fn number(&mut self) -> Result<(), ParserError> {
129        self.parser.number()?;
130        Ok(())
131    }
132
133    fn strz(&mut self) -> Result<(), ParserError> {
134        self.parser.skip_strz()
135    }
136
137    fn name_index(&mut self) -> Result<(), ParserError> {
138        let offset = self.original_len - self.parser.len();
139        let ni = self.parser.u32()?;
140        self.index_visitor.name_index(offset, ni)?;
141        Ok(())
142    }
143}
144
145struct MutVisitor<'a, IV: IndexVisitorMut> {
146    parser: ParserMut<'a>,
147    original_len: usize,
148    index_visitor: IV,
149}
150
151impl<'a, IV: IndexVisitorMut> RecordVisitor for MutVisitor<'a, IV> {
152    fn is_empty(&self) -> bool {
153        self.parser.is_empty()
154    }
155
156    fn peek_rest(&self) -> &[u8] {
157        self.parser.peek_rest()
158    }
159
160    fn u16(&mut self) -> Result<u16, ParserError> {
161        self.parser.u16()
162    }
163
164    fn u32(&mut self) -> Result<u32, ParserError> {
165        self.parser.u32()
166    }
167
168    fn skip(&mut self, n: usize) -> Result<(), ParserError> {
169        self.parser.skip(n)
170    }
171
172    fn ty(&mut self) -> Result<(), ParserError> {
173        let offset = self.original_len - self.parser.len();
174        let ti: &mut TypeIndexLe = self.parser.get_mut()?;
175        self.index_visitor.type_index(offset, ti)?;
176        Ok(())
177    }
178
179    fn item(&mut self) -> Result<(), ParserError> {
180        let offset = self.original_len - self.parser.len();
181        let ii: &mut ItemIdLe = self.parser.get_mut()?;
182        self.index_visitor.item_id(offset, ii)?;
183        Ok(())
184    }
185
186    fn number(&mut self) -> Result<(), ParserError> {
187        self.parser.skip_number()
188    }
189
190    fn strz(&mut self) -> Result<(), ParserError> {
191        self.parser.skip_strz()
192    }
193
194    fn name_index(&mut self) -> Result<(), ParserError> {
195        let offset = self.original_len - self.parser.len();
196        let ni: &mut U32<LE> = self.parser.get_mut()?;
197        self.index_visitor.name_index(offset, ni)?;
198        Ok(())
199    }
200}
201
202/// Scans the type indexes within a type record and calls `f` for each type index. This function
203/// can only read data.
204#[inline(never)]
205pub fn visit_type_indexes_in_record_slice<IV: IndexVisitor>(
206    type_kind: Leaf,
207    record_data: &[u8],
208    index_visitor: IV,
209) -> Result<(), anyhow::Error> {
210    let record_data_len = record_data.len();
211
212    let mut v = RefVisitor {
213        original_len: record_data.len(),
214        parser: Parser::new(record_data),
215        index_visitor,
216    };
217
218    visit_type_indexes_in_record(type_kind, &mut v).with_context(|| {
219        let offset = record_data_len - v.parser.len();
220        format!("at byte offset 0x{offset:x} {offset} within type record")
221    })
222}
223
224/// Scans the type indexes within a type record and calls `f` for each type index. This function
225/// can modify the type indexes within the record.
226#[inline(never)]
227pub fn visit_type_indexes_in_record_slice_mut<IV>(
228    type_kind: Leaf,
229    record_data: &mut [u8],
230    index_visitor: IV,
231) -> Result<(), anyhow::Error>
232where
233    IV: IndexVisitorMut,
234{
235    let record_data_len = record_data.len();
236
237    let mut v = MutVisitor {
238        original_len: record_data.len(),
239        parser: ParserMut::new(record_data),
240        index_visitor,
241    };
242
243    visit_type_indexes_in_record(type_kind, &mut v).with_context(|| {
244        let offset = record_data_len - v.parser.len();
245        format!("at byte offset 0x{offset:x} {offset} within type record")
246    })
247}
248
249/// This function examines a type record and traverses the type indexes within it.
250///
251/// The caller provides an implementation of the visitor trait.  The visitor trait provides the
252/// ability to read fields from the type record, and receives notifications that the visitor is
253/// positioned on a type index.
254pub fn visit_type_indexes_in_record<V: RecordVisitor>(
255    type_kind: Leaf,
256    p: &mut V,
257) -> Result<(), ParserError> {
258    match type_kind {
259        Leaf::LF_LABEL => {}
260
261        Leaf::LF_MODIFIER => {
262            p.ty()?;
263        }
264
265        Leaf::LF_POINTER => {
266            p.ty()?; // underlying type
267            let attr = PointerFlags(p.u32()?);
268            match attr.mode() {
269                2 => {
270                    // 2 is pointer to data member
271                    p.ty()?;
272                }
273                3 => {
274                    // 3 is pointer to method
275                    p.ty()?;
276                }
277                _ => {}
278            }
279        }
280
281        Leaf::LF_ALIAS => {
282            p.ty()?;
283        }
284
285        Leaf::LF_ARRAY => {
286            p.ty()?; // element type
287            p.ty()?; // index type
288        }
289
290        Leaf::LF_CLASS | Leaf::LF_STRUCTURE => {
291            p.u16()?; // count
292            p.skip(2)?; // property
293            p.ty()?; // field list
294            p.ty()?; // derivation list
295            p.ty()?; // vtable shape
296        }
297
298        Leaf::LF_ENUM => {
299            p.u16()?; // count
300            p.skip(2)?; // property
301            p.ty()?; // type
302            p.ty()?; // field list
303        }
304
305        Leaf::LF_UNION => {
306            p.u16()?; // count
307            p.skip(2)?; // property
308            p.ty()?; // field list
309        }
310
311        Leaf::LF_PROCEDURE => {
312            p.ty()?; // return type
313            p.skip(4)?; // calling convention, reserved, and num params
314            p.ty()?; // arg list
315        }
316
317        Leaf::LF_MFUNCTION => {
318            p.ty()?; // return type
319            p.ty()?; // class definition
320            p.ty()?; // this type
321            p.skip(4)?; // calling convention, reserved, and num params
322            p.ty()?; // arg list
323        }
324
325        Leaf::LF_ARGLIST => {
326            let num_args = p.u32()?;
327            for _ in 0..num_args {
328                p.ty()?;
329            }
330        }
331
332        Leaf::LF_FIELDLIST => {
333            let mut prev_item_kind = None;
334            loop {
335                let rest = p.peek_rest();
336                if rest.is_empty() {
337                    break;
338                }
339
340                // Check for padding (alignment) bytes.
341                let mut padding_len = 0;
342                while padding_len < rest.len() && rest[padding_len] >= 0xf0 {
343                    padding_len += 1;
344                }
345                if padding_len > 0 {
346                    p.skip(padding_len)?;
347                }
348
349                if p.is_empty() {
350                    break;
351                }
352
353                let item_kind = Leaf(p.u16()?);
354                let after = prev_item_kind.replace(item_kind);
355
356                match item_kind {
357                    Leaf::LF_BCLASS => {
358                        let _attr = p.u16()?;
359                        p.ty()?; // class type
360                        p.number()?; // offset
361                    }
362
363                    Leaf::LF_VBCLASS => {
364                        let _attr = p.u16()?;
365                        p.ty()?; // base class
366                        p.ty()?; // vbtype
367                        p.number()?; // vbpoff
368                        p.number()?; // vbpff
369                    }
370
371                    Leaf::LF_IVBCLASS => {
372                        let _attr = p.u16()?;
373                        p.ty()?; // base class
374                        p.ty()?; // virtual base type
375                        p.number()?; // vbpoff
376                        p.number()?; // vbpff
377                    }
378
379                    Leaf::LF_ENUMERATE => {
380                        // nothing needed
381                        let _attr = p.u16()?;
382                        p.number()?; // value
383                        p.strz()?; // name
384                    }
385
386                    Leaf::LF_FRIENDFCN => {
387                        p.skip(2)?; // padding
388                        p.ty()?; // type
389                        p.strz()?; // name
390                    }
391
392                    Leaf::LF_INDEX => {
393                        p.skip(2)?; // padding
394                        p.ty()?; // index
395                    }
396
397                    Leaf::LF_MEMBER => {
398                        let _attr = p.u16()?;
399                        p.ty()?; // type
400                        p.number()?; // offset
401                        p.strz()?; // name
402                    }
403
404                    Leaf::LF_STMEMBER => {
405                        let _attr = p.u16()?;
406                        p.ty()?; // type
407                        p.strz()?; // name
408                    }
409
410                    Leaf::LF_METHOD => {
411                        let _count = p.u16()?;
412                        p.ty()?; // method list
413                        p.strz()?; // name
414                    }
415
416                    Leaf::LF_NESTEDTYPE => {
417                        p.skip(2)?; // padding
418                        p.ty()?; // index
419                        p.strz()?; // name
420                    }
421
422                    Leaf::LF_VFUNCTAB => {
423                        p.skip(2)?; // padding
424                        p.ty()?; // vtable type
425                    }
426
427                    Leaf::LF_FRIENDCLS => {
428                        p.skip(2)?; // padding
429                        p.ty()?; // friend class type
430                    }
431
432                    Leaf::LF_ONEMETHOD => {
433                        let attr = p.u16()?; // attribute
434                        p.ty()?; // type of method
435                        if introduces_virtual(attr) {
436                            p.u32()?; // vbaseoff
437                        }
438                        p.strz()?; // name
439                    }
440
441                    Leaf::LF_VFUNCOFF => {
442                        p.u16()?; // padding
443                        p.ty()?; // vtable type
444                        p.u32()?; // offset
445                    }
446
447                    Leaf::LF_NESTEDTYPEEX => {
448                        p.u16()?; // attribute
449                        p.ty()?; // nested type
450                        p.strz()?; // name
451                    }
452
453                    unknown_item_kind => {
454                        error!(
455                            ?unknown_item_kind,
456                            ?after,
457                            "unrecognized item within LF_FIELDLIST"
458                        );
459                        break;
460                    }
461                }
462            }
463        }
464
465        Leaf::LF_DERIVED => {
466            let count = p.u32()?;
467            for _ in 0..count {
468                p.ty()?;
469            }
470        }
471
472        Leaf::LF_BITFIELD => {
473            p.ty()?;
474        }
475
476        Leaf::LF_METHODLIST => {
477            while !p.is_empty() {
478                let attr = p.u16()?;
479                p.skip(2)?; // padding
480                p.ty()?;
481                if introduces_virtual(attr) {
482                    p.skip(4)?; // vtable offset
483                }
484            }
485        }
486
487        Leaf::LF_DIMCONU => {
488            p.ty()?; // index type
489        }
490
491        Leaf::LF_DIMCONLU => {
492            p.ty()?; // index type
493        }
494
495        Leaf::LF_DIMVARU => {
496            let rank = p.u32()?;
497            p.ty()?; // index type
498            for _ in 0..rank {
499                p.ty()?; // upper bound for this dimension
500            }
501        }
502
503        // These types do not contain any pointers to other types.
504        Leaf::LF_VTSHAPE | Leaf::LF_PRECOMP | Leaf::LF_ENDPRECOMP | Leaf::LF_SKIP => {}
505
506        Leaf::LF_VFTPATH => {
507            let count = p.u32()?;
508            for _ in 0..count {
509                p.ty()?;
510            }
511        }
512
513        Leaf::LF_VFTABLE => {
514            p.ty()?; // type
515            p.ty()?; // base_vftable
516        }
517
518        Leaf::LF_CLASS2 | Leaf::LF_STRUCTURE2 | Leaf::LF_UNION2 | Leaf::LF_INTERFACE2 => {
519            p.skip(4)?; // property
520            p.ty()?; // field
521            p.ty()?; // derived
522            p.ty()?; // vshape
523        }
524
525        Leaf::LF_FUNC_ID => {
526            p.item()?; // parent scope of the ID, 0 if global
527            p.ty()?; // function type
528        }
529
530        Leaf::LF_MFUNC_ID => {
531            p.ty()?; // parent type
532            p.ty()?; // function type
533        }
534
535        Leaf::LF_BUILDINFO => {
536            let n = p.u16()?;
537            for _ in 0..n {
538                p.item()?;
539            }
540        }
541
542        Leaf::LF_SUBSTR_LIST => {
543            let count = p.u32()?;
544            for _ in 0..count {
545                p.item()?;
546            }
547        }
548
549        Leaf::LF_STRING_ID => {
550            p.item()?; // ID to list of sub string IDs
551        }
552
553        Leaf::LF_UDT_SRC_LINE => {
554            p.ty()?;
555            p.name_index()?; // NameIndex of source file name
556        }
557
558        Leaf::LF_UDT_MOD_SRC_LINE => {
559            p.ty()?;
560            p.name_index()?; // NameIndex of source file name
561        }
562
563        _ => {
564            error!("unrecognized type kind: {:?}", type_kind);
565            return Err(ParserError::new());
566        }
567    }
568
569    Ok(())
570}