ms_codeview/types/
fields.rs

1//! Decodes items in a `LF_FIELDLIST` complex list.
2
3use super::*;
4use tracing::error;
5
6/// Represents the data stored within an `LF_FIELDLIST` type string. This can be decoded using
7/// the `iter()` method.
8#[derive(Clone)]
9pub struct FieldList<'a> {
10    #[allow(missing_docs)]
11    pub bytes: &'a [u8],
12}
13
14impl<'a> FieldList<'a> {
15    /// Iterates the fields within an `LF_FIELDLIST` type string.
16    pub fn iter(&self) -> IterFields<'a> {
17        IterFields { bytes: self.bytes }
18    }
19}
20
21impl<'a> Debug for FieldList<'a> {
22    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
23        if f.alternate() {
24            let mut list = f.debug_list();
25            for f in self.iter() {
26                list.entry(&f);
27            }
28            list.finish()
29        } else {
30            f.write_str("FieldList")
31        }
32    }
33}
34
35/// Iterates the fields within an `LF_FIELDLIST` type string.
36pub struct IterFields<'a> {
37    #[allow(missing_docs)]
38    pub bytes: &'a [u8],
39}
40
41/// Represents one field within an `LF_FIELDLIST` type string.
42#[derive(Clone, Debug)]
43#[allow(missing_docs)]
44pub enum Field<'a> {
45    BaseClass(BaseClass<'a>),
46    DirectVirtualBaseClass(DirectVirtualBaseClass<'a>),
47    IndirectVirtualBaseClass(IndirectVirtualBaseClass<'a>),
48    Enumerate(Enumerate<'a>),
49    FriendFn(FriendFn<'a>),
50    Index(TypeIndex),
51    Member(Member<'a>),
52    StaticMember(StaticMember<'a>),
53    Method(Method<'a>),
54    NestedType(NestedType<'a>),
55    VFuncTable(TypeIndex),
56    FriendClass(TypeIndex),
57    OneMethod(OneMethod<'a>),
58    VFuncOffset(VFuncOffset),
59    NestedTypeEx(NestedTypeEx<'a>),
60}
61
62#[derive(Clone, Debug)]
63#[allow(missing_docs)]
64pub struct NestedType<'a> {
65    pub nested_ty: TypeIndex,
66    pub name: &'a BStr,
67}
68
69impl<'a> Parse<'a> for NestedType<'a> {
70    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
71        p.skip(2)?; // padding
72        Ok(Self {
73            nested_ty: p.type_index()?,
74            name: p.strz()?,
75        })
76    }
77}
78
79#[derive(Clone, Debug)]
80#[allow(missing_docs)]
81pub struct BaseClass<'a> {
82    pub attr: u16,
83    pub ty: TypeIndex,
84    pub offset: Number<'a>,
85}
86
87impl<'a> Parse<'a> for BaseClass<'a> {
88    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
89        let attr = p.u16()?;
90        let ty = p.type_index()?;
91        let offset = p.number()?;
92        Ok(BaseClass { attr, ty, offset })
93    }
94}
95
96/// This is used by both DirectVirtualBaseClass and IndirectVirtualBaseClass.
97#[allow(missing_docs)]
98#[repr(C)]
99#[derive(Clone, Debug, IntoBytes, FromBytes, Immutable, KnownLayout, Unaligned)]
100pub struct VirtualBaseClassFixed {
101    pub attr: U16<LE>,
102    pub btype: TypeIndexLe,
103    pub vbtype: TypeIndexLe,
104}
105
106#[allow(missing_docs)]
107#[derive(Clone, Debug)]
108pub struct DirectVirtualBaseClass<'a> {
109    pub fixed: &'a VirtualBaseClassFixed,
110    pub vbpoff: Number<'a>,
111    pub vboff: Number<'a>,
112}
113
114impl<'a> Parse<'a> for DirectVirtualBaseClass<'a> {
115    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
116        Ok(Self {
117            fixed: p.get()?,
118            vbpoff: p.number()?,
119            vboff: p.number()?,
120        })
121    }
122}
123
124#[allow(missing_docs)]
125#[derive(Clone, Debug)]
126pub struct IndirectVirtualBaseClass<'a> {
127    pub fixed: &'a VirtualBaseClassFixed,
128    pub vbpoff: Number<'a>,
129    pub vboff: Number<'a>,
130}
131
132impl<'a> Parse<'a> for IndirectVirtualBaseClass<'a> {
133    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
134        let fixed = p.get()?;
135        let vbpoff = p.number()?;
136        let vboff = p.number()?;
137        Ok(Self {
138            fixed,
139            vbpoff,
140            vboff,
141        })
142    }
143}
144
145#[allow(missing_docs)]
146#[derive(Clone)]
147pub struct Enumerate<'a> {
148    pub attr: u16,
149    pub value: Number<'a>,
150    pub name: &'a BStr,
151}
152
153impl<'a> Parse<'a> for Enumerate<'a> {
154    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
155        Ok(Self {
156            attr: p.u16()?,
157            value: p.number()?,
158            name: p.strz()?,
159        })
160    }
161}
162
163impl<'a> Debug for Enumerate<'a> {
164    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
165        write!(f, "{} = {}", self.name, self.value)
166    }
167}
168
169#[allow(missing_docs)]
170#[derive(Clone, Debug)]
171pub struct FriendFn<'a> {
172    pub ty: TypeIndex,
173    pub name: &'a BStr,
174}
175
176impl<'a> Parse<'a> for FriendFn<'a> {
177    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
178        p.skip(2)?; // padding
179        Ok(Self {
180            ty: p.type_index()?,
181            name: p.strz()?,
182        })
183    }
184}
185
186#[allow(missing_docs)]
187#[derive(Clone, Debug)]
188pub struct OneMethod<'a> {
189    pub attr: u16,
190    pub ty: TypeIndex,
191    pub vbaseoff: u32,
192    pub name: &'a BStr,
193}
194
195impl<'a> Parse<'a> for OneMethod<'a> {
196    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
197        let attr = p.u16()?;
198        let ty = p.type_index()?;
199        let vbaseoff = if introduces_virtual(attr) {
200            p.u32()?
201        } else {
202            0
203        };
204        let name = p.strz()?;
205        Ok(OneMethod {
206            attr,
207            ty,
208            vbaseoff,
209            name,
210        })
211    }
212}
213
214#[allow(missing_docs)]
215#[derive(Clone, Debug)]
216pub struct VFuncOffset {
217    pub vtable_ty: TypeIndex,
218    pub offset: u32,
219}
220
221impl<'a> Parse<'a> for VFuncOffset {
222    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
223        p.skip(2)?; // padding
224        let vtable_ty = p.type_index()?;
225        let offset = p.u32()?;
226        Ok(Self { vtable_ty, offset })
227    }
228}
229
230#[allow(missing_docs)]
231#[derive(Clone, Debug)]
232pub struct NestedTypeEx<'a> {
233    pub attr: u16,
234    pub ty: TypeIndex,
235    pub name: &'a BStr,
236}
237
238impl<'a> Parse<'a> for NestedTypeEx<'a> {
239    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
240        let attr = p.u16()?;
241        let ty = p.type_index()?;
242        let name = p.strz()?;
243        Ok(Self { attr, ty, name })
244    }
245}
246
247#[allow(missing_docs)]
248#[derive(Clone, Debug)]
249pub struct Member<'a> {
250    pub attr: u16,
251    pub ty: TypeIndex,
252    pub offset: Number<'a>,
253    pub name: &'a BStr,
254}
255
256impl<'a> Parse<'a> for Member<'a> {
257    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
258        Ok(Self {
259            attr: p.u16()?,
260            ty: p.type_index()?,
261            offset: p.number()?,
262            name: p.strz()?,
263        })
264    }
265}
266
267#[allow(missing_docs)]
268#[derive(Clone, Debug)]
269pub struct StaticMember<'a> {
270    pub attr: u16,
271    pub ty: TypeIndex,
272    pub name: &'a BStr,
273}
274
275impl<'a> Parse<'a> for StaticMember<'a> {
276    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
277        Ok(Self {
278            attr: p.u16()?,
279            ty: p.type_index()?,
280            name: p.strz()?,
281        })
282    }
283}
284
285#[allow(missing_docs)]
286#[derive(Clone, Debug)]
287pub struct Method<'a> {
288    pub count: u16,
289    pub methods: TypeIndex,
290    pub name: &'a BStr,
291}
292
293impl<'a> Parse<'a> for Method<'a> {
294    fn from_parser(p: &mut Parser<'a>) -> Result<Self, ParserError> {
295        Ok(Self {
296            count: p.u16()?,
297            methods: p.type_index()?,
298            name: p.strz()?,
299        })
300    }
301}
302
303impl<'a> Iterator for IterFields<'a> {
304    type Item = Field<'a>;
305
306    fn next(&mut self) -> Option<Self::Item> {
307        if self.bytes.is_empty() {
308            return None;
309        }
310        let mut p = Parser::new(self.bytes);
311
312        let rest = p.peek_rest();
313
314        // Check for padding (alignment) bytes.
315        let mut padding_len = 0;
316        while padding_len < rest.len() && rest[padding_len] >= 0xf0 {
317            padding_len += 1;
318        }
319        if padding_len > 0 {
320            let _ = p.skip(padding_len);
321        }
322
323        if p.is_empty() {
324            return None;
325        }
326
327        match Field::parse(&mut p) {
328            Ok(f) => {
329                self.bytes = p.into_rest();
330                Some(f)
331            }
332            Err(ParserError) => None,
333        }
334    }
335}
336
337impl<'a> Field<'a> {
338    /// Parses one field within an `LF_FIELDLIST` type string.
339    ///
340    /// Unlike most of the `parse()` methods defined in this library, this function requires a
341    /// `Parser` instance, rather than just working directly with `&[u8]`. This is because the
342    /// field records do not have a length field; the type of the field is required to know how
343    /// many bytes to decode in each field.
344    ///
345    /// So the act of parsing a field is what is needed for locating the next field.
346    pub fn parse(p: &mut Parser<'a>) -> Result<Self, ParserError> {
347        let item_kind = Leaf(p.u16()?);
348
349        Ok(match item_kind {
350            Leaf::LF_BCLASS => Self::BaseClass(p.parse()?),
351            Leaf::LF_VBCLASS => Self::DirectVirtualBaseClass(p.parse()?),
352            Leaf::LF_IVBCLASS => Self::IndirectVirtualBaseClass(p.parse()?),
353            Leaf::LF_ENUMERATE => Self::Enumerate(p.parse()?),
354            Leaf::LF_FRIENDFCN => Self::FriendFn(p.parse()?),
355
356            Leaf::LF_INDEX => {
357                p.skip(2)?; // padding
358                let ty = p.type_index()?;
359                Self::Index(ty)
360            }
361
362            Leaf::LF_MEMBER => Self::Member(p.parse()?),
363            Leaf::LF_STMEMBER => Self::StaticMember(p.parse()?),
364            Leaf::LF_METHOD => Self::Method(p.parse()?),
365            Leaf::LF_NESTEDTYPE => Self::NestedType(p.parse()?),
366
367            Leaf::LF_VFUNCTAB => {
368                p.skip(2)?; // padding
369                let vtable_ty = p.type_index()?;
370                Self::VFuncTable(vtable_ty)
371            }
372
373            Leaf::LF_FRIENDCLS => {
374                p.skip(2)?; // padding
375                let ty = p.type_index()?; // friend class type
376                Self::FriendClass(ty)
377            }
378
379            Leaf::LF_ONEMETHOD => Self::OneMethod(p.parse()?),
380            Leaf::LF_VFUNCOFF => Self::VFuncOffset(p.parse()?),
381            Leaf::LF_NESTEDTYPEEX => Self::NestedTypeEx(p.parse()?),
382
383            unknown_item_kind => {
384                error!(?unknown_item_kind, "unrecognized item within LF_FIELDLIST",);
385                return Err(ParserError::new());
386            }
387        })
388    }
389}