pelite\pe32/
msvc.rs

1/*!
2Some MSVC structs for RTTI and exception handling.
3
4References:
5
6[1]: [Reversing Microsoft Visual C++ Part I: Exception Handling](http://www.openrce.org/articles/full_view/21)  
7[2]: [Reversing Microsoft Visual C++ Part II: Classes, Methods and RTTI](http://www.openrce.org/articles/full_view/23)  
8*/
9
10use std::mem;
11
12use crate::{util::CStr, Pod};
13
14use super::Ptr;
15
16//----------------------------------------------------------------
17
18/// Represents the C++ `std::type_info` class returned by the `typeid` operator.
19#[derive(Debug)]
20#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
21#[repr(C)]
22pub struct TypeDescriptor {
23	/// Vtable of the `type_info` class.
24	pub vftable: Ptr,
25	/// Used to keep the demangled name returned by `type_info::name()`.
26	pub spare: Ptr<CStr>,
27	/// Inlined mangled type name, nul terminated.
28	#[cfg_attr(feature = "serde", serde(skip))]
29	pub name: [u8; 0],
30}
31
32/// Pointer-to-member displacement info.
33#[derive(Copy, Clone, Debug)]
34#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
35#[repr(C)]
36pub struct PMD {
37	/// Member displacement.
38	pub mdisp: i32,
39	/// Vbtable (virtual base class table) displacement.
40	pub pdisp: i32,
41	/// Displacement inside the vbtable.
42	pub vdisp: i32,
43}
44
45//----------------------------------------------------------------
46
47/// Fully describes all try/catch blocks and unwindable objects in the function.
48#[derive(Copy, Clone, Debug)]
49#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
50#[repr(C)]
51pub struct FuncInfo {
52	/// Compiler version.
53	///
54	/// * `0x19930520`: up to VC6
55	/// * `0x19930521`: VC7.x (2002-2003)
56	/// * `0x19930522`: VC8 (2005)
57	pub magic_number: u32,
58	/// Number of entries in the unwind table.
59	pub max_state: i32,
60	/// Table of unwind destructors.
61	pub unwind_map: Ptr,
62	/// Number of try blocks in the function.
63	pub try_blocks: u32,
64	/// Mapping of catch blocks to try blocks.
65	pub try_block_map: Ptr<UnwindMapEntry>,
66	pub ip_map_entries: u32,
67	pub ip_to_state_map: Ptr,
68	/// VC7+ only, expected exceptions list (function "throw" specifier).
69	pub es_type_list: Ptr<ESTypeList>,
70	/// VC8+ only, bit `0` set if function was compiled with `/EHs`.
71	pub eh_flags: i32,
72}
73
74#[derive(Copy, Clone, Debug)]
75#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
76#[repr(C)]
77pub struct UnwindMapEntry {
78	/// Target state.
79	pub to_state: i32,
80	/// Action to perform (unwind funclet address).
81	///
82	/// Pointer to function with signature `fn()`.
83	pub action: Ptr,
84}
85
86/// Try block descriptor.
87///
88/// Describes a try block with associated catches.
89#[derive(Copy, Clone, Debug)]
90#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
91#[repr(C)]
92pub struct TryBlockMapEntry {
93	/// This `try {}` covers states ranging from `try_low` to `try_high`.
94	pub try_low: i32,
95	pub try_high: i32,
96	/// Highest state inside catch handlers of this try.
97	pub catch_high: i32,
98	/// Number of catch handlers.
99	pub catches: i32,
100	/// Catch handlers table.
101	pub handler_array: Ptr<[HandlerType]>,
102}
103
104/// Catch block descriptor.
105///
106/// Describes a single catch of a try block.
107#[derive(Copy, Clone, Debug)]
108#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
109#[repr(C)]
110pub struct HandlerType {
111	/// * `0x01`: const
112	/// * `0x02`: volatile
113	/// * `0x08`: reference
114	pub adjectives: u32,
115	/// RTTI descriptor of the exception type. `0` = any (ellipsis).
116	pub ty: Ptr<TypeDescriptor>,
117	/// EBP-based offset of the exception object in the function stack. `0` = no object (catch by type).
118	pub disp_catch_obj: i32,
119	/// Address of the catch handler Code.
120	///
121	/// Returns address where to continues execution (i.e. code after the try block).
122	pub address_of_handler: Ptr,
123}
124
125/// List of expected exceptions.
126#[derive(Copy, Clone, Debug)]
127#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
128#[repr(C)]
129pub struct ESTypeList {
130	/// Number of entries in the list.
131	pub count: i32,
132	/// List of exceptions; it seems only pType field in HandlerType is used.
133	pub type_array: Ptr<[HandlerType]>,
134}
135
136//----------------------------------------------------------------
137
138#[derive(Copy, Clone, Debug)]
139#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
140#[repr(C)]
141pub struct ThrowInfo {
142	/// * `0x01`: const
143	/// * `0x02`: volatile
144	pub attributes: u32,
145	/// Exception destructor.
146	///
147	/// Pointer to function with signature `fn()`.
148	pub unwind: Ptr,
149	/// Forward compatibility handler.
150	///
151	/// Pointer to function with signature `fn() -> i32`.
152	pub forward_compat: Ptr,
153	/// List of types that can catch this exception; i.e. the actual type and all its ancestors.
154	pub catchable_type_array: Ptr<CatchableTypeArray>,
155}
156
157#[derive(Debug)]
158#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
159#[repr(C)]
160pub struct CatchableTypeArray {
161	/// Number of entries in the following array.
162	pub catchable_types: i32,
163	/// Array of pointers to catchable types.
164	#[cfg_attr(feature = "serde", serde(skip))]
165	pub array: [Ptr<CatchableType>; 0],
166}
167
168/// Describes a type that can catch this exception.
169#[derive(Copy, Clone, Debug)]
170#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
171#[repr(C)]
172pub struct CatchableType {
173	/// * `0x01`: simple type (can be copied by memmove)
174	/// * `0x02`: can be caught by reference only
175	/// * `0x04`: has virtual bases
176	pub properties: u32,
177	/// Pointer to its type descriptor.
178	pub type_descriptor: Ptr<TypeDescriptor>,
179	/// How to cast the thrown object to this type.
180	pub pmd: PMD,
181	/// Object size.
182	pub size_or_offset: i32,
183	/// Copy constructor address.
184	pub copy_function: Ptr,
185}
186
187//----------------------------------------------------------------
188
189/// Complete Object Locator.
190///
191/// MSVC compiler puts a pointer to this structure just before the vftable.
192/// The structure is called so because it lets you find the location to the complete object from a specific vftable pointer.
193///
194/// Every vftable has its own Complete Object Locator.
195#[derive(Copy, Clone, Debug)]
196#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
197#[repr(C)]
198pub struct RTTICompleteObjectLocator {
199	/// Always zero?
200	pub signature: u32,
201	/// Offset of this vtable in the complete class.
202	pub offset: u32,
203	/// Constructor displacement offset.
204	pub cd_offset: u32,
205	/// Pointer to the type descriptor of the complete class.
206	pub type_descriptor: Ptr<TypeDescriptor>,
207	/// Pointer to the class hierarchy descriptor.
208	pub class_descriptor: Ptr<RTTIClassHierarchyDescriptor>,
209}
210
211/// Class Hierarchy Descriptor.
212///
213/// Describes the inheritance hierarchy of the class, it is shared by all [COL](struct.RTTICompleteObjectLocator.html)s.
214#[derive(Copy, Clone, Debug)]
215#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
216#[repr(C)]
217pub struct RTTIClassHierarchyDescriptor {
218	/// Always zero?
219	pub signature: u32,
220	/// Bit `0` set = multiple inheritance, bit `1` set = virtual inheritance.
221	pub attributes: u32,
222	/// Number of classes in `base_class_array`.
223	pub num_base_classes: u32,
224	/// Pointer to an array of pointers to base class descriptors.
225	pub base_class_array: Ptr<[Ptr<RTTIBaseClassDescriptor>]>,
226}
227
228/// Entry in the [Base Class Array](struct.RTTIClassHierarchyDescriptor.html#base_class_array.v).
229#[derive(Copy, Clone, Debug)]
230#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
231#[repr(C)]
232pub struct RTTIBaseClassDescriptor {
233	/// Type descriptor of the class.
234	pub type_descriptor: Ptr<TypeDescriptor>,
235	/// Number of nested classes following in the `base_class_array`.
236	pub num_contained_bases: u32,
237	/// Pointer-to-member displacement info.
238	pub pmd: PMD,
239	/// Flags, usually `0`. (?)
240	pub attributes: u32,
241}
242
243//----------------------------------------------------------------
244
245unsafe impl Pod for TypeDescriptor {}
246unsafe impl Pod for PMD {}
247unsafe impl Pod for FuncInfo {}
248unsafe impl Pod for UnwindMapEntry {}
249unsafe impl Pod for TryBlockMapEntry {}
250unsafe impl Pod for HandlerType {}
251unsafe impl Pod for ESTypeList {}
252unsafe impl Pod for ThrowInfo {}
253unsafe impl Pod for CatchableTypeArray {}
254unsafe impl Pod for CatchableType {}
255unsafe impl Pod for RTTICompleteObjectLocator {}
256unsafe impl Pod for RTTIClassHierarchyDescriptor {}
257unsafe impl Pod for RTTIBaseClassDescriptor {}
258
259//----------------------------------------------------------------
260
261const _: [(); 8] = [(); mem::size_of::<TypeDescriptor>()]; // Unsized
262const _: [(); 12] = [(); mem::size_of::<PMD>()];
263const _: [(); 36] = [(); mem::size_of::<FuncInfo>()];
264const _: [(); 8] = [(); mem::size_of::<UnwindMapEntry>()];
265const _: [(); 20] = [(); mem::size_of::<TryBlockMapEntry>()];
266const _: [(); 16] = [(); mem::size_of::<HandlerType>()];
267const _: [(); 8] = [(); mem::size_of::<ESTypeList>()];
268const _: [(); 16] = [(); mem::size_of::<ThrowInfo>()];
269const _: [(); 4] = [(); mem::size_of::<CatchableTypeArray>()]; // Unsized
270const _: [(); 28] = [(); mem::size_of::<CatchableType>()];
271const _: [(); 20] = [(); mem::size_of::<RTTICompleteObjectLocator>()];
272const _: [(); 16] = [(); mem::size_of::<RTTIClassHierarchyDescriptor>()];
273const _: [(); 24] = [(); mem::size_of::<RTTIBaseClassDescriptor>()];