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