ms_codeview/
types.rs

1//! Code for decoding type record streams (the TPI and IPI streams).
2//!
3//! # References
4//! * [CodeView Type Records](https://llvm.org/docs/PDB/CodeViewTypes.html)
5
6mod iter;
7#[doc(inline)]
8pub use iter::*;
9
10mod kind;
11#[doc(inline)]
12pub use kind::*;
13
14pub mod fields;
15pub mod number;
16pub mod primitive;
17pub mod visitor;
18
19mod records;
20#[doc(inline)]
21pub use records::*;
22
23pub use fields::FieldList;
24
25use self::primitive::dump_primitive_type_index;
26use crate::parser::{Number, Parse, Parser, ParserError};
27use bitfield::bitfield;
28use bstr::BStr;
29use std::fmt::Debug;
30use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Unaligned, LE, U16, U32};
31
32/// A type index refers to another type record, or to a primitive type.
33#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
34pub struct TypeIndex(pub u32);
35
36impl TypeIndex {
37    /// The minimum value for a `type_index_begin` value.
38    ///
39    /// This value comes from the fact that the first 0x1000 values are reserved for primitive
40    /// types.  See `primitive_types.md` in the specification.
41    pub const MIN_BEGIN: TypeIndex = TypeIndex(0x1000);
42}
43
44impl std::fmt::Debug for TypeIndex {
45    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
46        if self.0 < TypeIndex::MIN_BEGIN.0 {
47            dump_primitive_type_index(fmt, *self)
48        } else {
49            write!(fmt, "T#0x{:x}", self.0)
50        }
51    }
52}
53
54/// The serialized form of [`TypeIndex`]. This can be embedded directly in data structures
55/// stored on disk.
56#[derive(
57    Copy, Clone, Eq, PartialEq, Hash, FromBytes, IntoBytes, Immutable, KnownLayout, Unaligned,
58)]
59#[repr(transparent)]
60pub struct TypeIndexLe(pub U32<LE>);
61
62impl From<TypeIndex> for TypeIndexLe {
63    #[inline(always)]
64    fn from(value: TypeIndex) -> TypeIndexLe {
65        TypeIndexLe(U32::new(value.0))
66    }
67}
68
69impl Debug for TypeIndexLe {
70    fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::fmt::Result {
71        let ti = self.get();
72        Debug::fmt(&ti, fmt)
73    }
74}
75
76impl TypeIndexLe {
77    /// Converts this value to host byte-order.
78    #[inline(always)]
79    pub fn get(self) -> TypeIndex {
80        TypeIndex(self.0.get())
81    }
82}
83
84/// Parsed details of a type record.
85#[derive(Clone, Debug)]
86#[allow(missing_docs)]
87pub enum TypeData<'a> {
88    Array(Array<'a>),
89    Struct(Struct<'a>),
90    Union(Union<'a>),
91    Enum(Enum<'a>),
92    Proc(&'a Proc),
93    MemberFunc(&'a MemberFunc),
94    VTableShape(VTableShapeData<'a>),
95    Pointer(Pointer<'a>),
96    Modifier(TypeModifier),
97    Bitfield(&'a Bitfield),
98    FieldList(FieldList<'a>),
99    MethodList(MethodListData<'a>),
100    ArgList(ArgList<'a>),
101    Alias(Alias<'a>),
102    UdtSrcLine(&'a UdtSrcLine),
103    UdtModSrcLine(&'a UdtModSrcLine),
104    FuncId(FuncId<'a>),
105    MFuncId(MFuncId<'a>),
106    StringId(StringId<'a>),
107    SubStrList(SubStrList<'a>),
108    BuildInfo(BuildInfo<'a>),
109    VFTable(&'a VFTable),
110    Unknown,
111}
112
113impl<'a> TypeData<'a> {
114    /// Parses the payload of a type record.
115    pub fn parse_bytes(kind: Leaf, bytes: &'a [u8]) -> Result<Self, ParserError> {
116        let mut p = Parser::new(bytes);
117        Self::parse(kind, &mut p)
118    }
119
120    /// Parses the payload of a type record, using a [`Parser`].
121    pub fn parse(kind: Leaf, p: &mut Parser<'a>) -> Result<Self, ParserError> {
122        Ok(match kind {
123            Leaf::LF_ARRAY => Self::Array(p.parse()?),
124            Leaf::LF_CLASS | Leaf::LF_STRUCTURE | Leaf::LF_INTERFACE => Self::Struct(p.parse()?),
125            Leaf::LF_UNION => Self::Union(p.parse()?),
126            Leaf::LF_ENUM => Self::Enum(p.parse()?),
127            Leaf::LF_PROCEDURE => Self::Proc(p.get()?),
128            Leaf::LF_MEMBER => Self::MemberFunc(p.get()?),
129
130            Leaf::LF_VTSHAPE => {
131                let fixed: &VTableShapeFixed = p.get()?;
132                Self::VTableShape(VTableShapeData {
133                    count: fixed.count.get(),
134                    descriptors: p.take_rest(),
135                })
136            }
137
138            Leaf::LF_VFTABLE => Self::VFTable(p.get()?),
139
140            Leaf::LF_POINTER => {
141                let fixed = p.get()?;
142                let variant = p.take_rest();
143                Self::Pointer(Pointer { fixed, variant })
144            }
145
146            Leaf::LF_MFUNCTION => Self::MemberFunc(p.get()?),
147            Leaf::LF_MODIFIER => Self::Modifier(p.copy()?),
148            Leaf::LF_BITFIELD => Self::Bitfield(p.get()?),
149
150            Leaf::LF_FIELDLIST => Self::FieldList(FieldList {
151                bytes: p.take_rest(),
152            }),
153
154            Leaf::LF_METHODLIST => Self::MethodList(MethodListData {
155                bytes: p.take_rest(),
156            }),
157
158            Leaf::LF_ARGLIST => Self::ArgList(p.parse()?),
159            Leaf::LF_ALIAS => Self::Alias(Alias::from_parser(p)?),
160            Leaf::LF_UDT_SRC_LINE => Self::UdtSrcLine(p.get()?),
161            Leaf::LF_UDT_MOD_SRC_LINE => Self::UdtModSrcLine(p.get()?),
162            Leaf::LF_FUNC_ID => Self::FuncId(p.parse()?),
163            Leaf::LF_MFUNC_ID => Self::MFuncId(p.parse()?),
164            Leaf::LF_STRING_ID => Self::StringId(p.parse()?),
165            Leaf::LF_SUBSTR_LIST => Self::SubStrList(p.parse()?),
166            Leaf::LF_BUILDINFO => Self::BuildInfo(p.parse()?),
167
168            _ => Self::Unknown,
169        })
170    }
171
172    /// If this record has a primary "name" field, return it. Else, return `None`.
173    pub fn name(&self) -> Option<&'a BStr> {
174        match self {
175            // From TPI
176            Self::Struct(t) => Some(t.name),
177            Self::Union(t) => Some(t.name),
178            Self::Enum(t) => Some(t.name),
179            Self::Alias(t) => Some(t.name),
180
181            // From IPI
182            Self::FuncId(t) => Some(t.name),
183            Self::StringId(t) => Some(t.name),
184
185            _ => None,
186        }
187    }
188
189    /// Returns the name of this type definition, if it is a UDT (user-defined type) definition.
190    pub fn udt_name(&self) -> Option<&'a BStr> {
191        match self {
192            Self::Struct(t) => Some(t.name),
193            Self::Union(t) => Some(t.name),
194            Self::Enum(t) => Some(t.name),
195            Self::Alias(t) => Some(t.name),
196            _ => None,
197        }
198    }
199}