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    FieldList(FieldList<'a>),
98    MethodList(MethodListData<'a>),
99    ArgList(ArgList<'a>),
100    Alias(Alias<'a>),
101    UdtSrcLine(&'a UdtSrcLine),
102    UdtModSrcLine(&'a UdtModSrcLine),
103    FuncId(FuncId<'a>),
104    MFuncId(MFuncId<'a>),
105    StringId(StringId<'a>),
106    SubStrList(SubStrList<'a>),
107    BuildInfo(BuildInfo<'a>),
108    VFTable(&'a VFTable),
109    Unknown,
110}
111
112impl<'a> TypeData<'a> {
113    /// Parses the payload of a type record.
114    pub fn parse_bytes(kind: Leaf, bytes: &'a [u8]) -> Result<Self, ParserError> {
115        let mut p = Parser::new(bytes);
116        Self::parse(kind, &mut p)
117    }
118
119    /// Parses the payload of a type record, using a [`Parser`].
120    pub fn parse(kind: Leaf, p: &mut Parser<'a>) -> Result<Self, ParserError> {
121        Ok(match kind {
122            Leaf::LF_ARRAY => Self::Array(p.parse()?),
123            Leaf::LF_CLASS | Leaf::LF_STRUCTURE | Leaf::LF_INTERFACE => Self::Struct(p.parse()?),
124            Leaf::LF_UNION => Self::Union(p.parse()?),
125            Leaf::LF_ENUM => Self::Enum(p.parse()?),
126            Leaf::LF_PROCEDURE => Self::Proc(p.get()?),
127            Leaf::LF_MEMBER => Self::MemberFunc(p.get()?),
128
129            Leaf::LF_VTSHAPE => {
130                let fixed: &VTableShapeFixed = p.get()?;
131                Self::VTableShape(VTableShapeData {
132                    count: fixed.count.get(),
133                    descriptors: p.take_rest(),
134                })
135            }
136
137            Leaf::LF_VFTABLE => Self::VFTable(p.get()?),
138
139            Leaf::LF_POINTER => {
140                let fixed = p.get()?;
141                let variant = p.take_rest();
142                Self::Pointer(Pointer { fixed, variant })
143            }
144
145            Leaf::LF_MFUNCTION => Self::MemberFunc(p.get()?),
146            Leaf::LF_MODIFIER => Self::Modifier(p.copy()?),
147
148            Leaf::LF_FIELDLIST => Self::FieldList(FieldList {
149                bytes: p.take_rest(),
150            }),
151
152            Leaf::LF_METHODLIST => Self::MethodList(MethodListData {
153                bytes: p.take_rest(),
154            }),
155
156            Leaf::LF_ARGLIST => Self::ArgList(p.parse()?),
157            Leaf::LF_ALIAS => Self::Alias(Alias::from_parser(p)?),
158            Leaf::LF_UDT_SRC_LINE => Self::UdtSrcLine(p.get()?),
159            Leaf::LF_UDT_MOD_SRC_LINE => Self::UdtModSrcLine(p.get()?),
160            Leaf::LF_FUNC_ID => Self::FuncId(p.parse()?),
161            Leaf::LF_MFUNC_ID => Self::MFuncId(p.parse()?),
162            Leaf::LF_STRING_ID => Self::StringId(p.parse()?),
163            Leaf::LF_SUBSTR_LIST => Self::SubStrList(p.parse()?),
164            Leaf::LF_BUILDINFO => Self::BuildInfo(p.parse()?),
165
166            _ => Self::Unknown,
167        })
168    }
169
170    /// If this record has a primary "name" field, return it. Else, return `None`.
171    pub fn name(&self) -> Option<&'a BStr> {
172        match self {
173            // From TPI
174            Self::Struct(t) => Some(t.name),
175            Self::Union(t) => Some(t.name),
176            Self::Enum(t) => Some(t.name),
177            Self::Alias(t) => Some(t.name),
178
179            // From IPI
180            Self::FuncId(t) => Some(t.name),
181            Self::StringId(t) => Some(t.name),
182
183            _ => None,
184        }
185    }
186
187    /// Returns the name of this type definition, if it is a UDT (user-defined type) definition.
188    pub fn udt_name(&self) -> Option<&'a BStr> {
189        match self {
190            Self::Struct(t) => Some(t.name),
191            Self::Union(t) => Some(t.name),
192            Self::Enum(t) => Some(t.name),
193            Self::Alias(t) => Some(t.name),
194            _ => None,
195        }
196    }
197}