1use std::prelude::v1::*;
4
5use log::{info, trace};
6use std::collections::BTreeSet;
7
8pub type TypeSet = BTreeSet<pdb::TypeIndex>;
9
10pub fn type_name(
11 type_finder: &pdb::TypeFinder<'_>,
12 type_index: pdb::TypeIndex,
13 needed_types: &mut TypeSet,
14) -> pdb::Result<String> {
15 let mut name = match type_finder.find(type_index)?.parse()? {
16 pdb::TypeData::Primitive(data) => {
17 let mut name = match data.kind {
18 pdb::PrimitiveKind::Void => "void".to_string(),
19 pdb::PrimitiveKind::Char => "char".to_string(),
20 pdb::PrimitiveKind::UChar => "unsigned char".to_string(),
21
22 pdb::PrimitiveKind::I8 => "int8_t".to_string(),
23 pdb::PrimitiveKind::U8 => "uint8_t".to_string(),
24 pdb::PrimitiveKind::I16 => "int16_t".to_string(),
25 pdb::PrimitiveKind::U16 => "uint16_t".to_string(),
26 pdb::PrimitiveKind::I32 => "int32_t".to_string(),
27 pdb::PrimitiveKind::U32 => "uint32_t".to_string(),
28 pdb::PrimitiveKind::I64 => "int64_t".to_string(),
29 pdb::PrimitiveKind::U64 => "uint64_t".to_string(),
30
31 pdb::PrimitiveKind::F32 => "float".to_string(),
32 pdb::PrimitiveKind::F64 => "double".to_string(),
33
34 pdb::PrimitiveKind::Bool8 => "bool".to_string(),
35
36 _ => format!("unhandled_primitive.kind /* {:?} */", data.kind),
37 };
38
39 if data.indirection.is_some() {
40 name.push_str(" *");
41 }
42
43 name
44 }
45
46 pdb::TypeData::Class(data) => {
47 needed_types.insert(type_index);
48 data.name.to_string().into_owned()
49 }
50
51 pdb::TypeData::Enumeration(data) => {
52 needed_types.insert(type_index);
53 data.name.to_string().into_owned()
54 }
55
56 pdb::TypeData::Union(data) => {
57 needed_types.insert(type_index);
58 data.name.to_string().into_owned()
59 }
60
61 pdb::TypeData::Pointer(data) => format!(
62 "{}*",
63 type_name(type_finder, data.underlying_type, needed_types)?
64 ),
65
66 pdb::TypeData::Modifier(data) => {
67 if data.constant {
68 format!(
69 "const {}",
70 type_name(type_finder, data.underlying_type, needed_types)?
71 )
72 } else if data.volatile {
73 format!(
74 "volatile {}",
75 type_name(type_finder, data.underlying_type, needed_types)?
76 )
77 } else {
78 type_name(type_finder, data.underlying_type, needed_types)?
80 }
81 }
82
83 pdb::TypeData::Array(data) => {
84 let mut name = type_name(type_finder, data.element_type, needed_types)?;
85 for size in data.dimensions {
86 name = format!("{name}[{size}]");
87 }
88 name
89 }
90
91 x => format!("Type{type_index} /* TODO: figure out how to name it {x:?} */"),
92 };
93
94 if name == "std::basic_string<char,std::char_traits<char>,std::allocator<char> >" {
96 name = "std::string".to_string();
97 }
98
99 Ok(name)
100}
101
102#[derive(Debug, Clone, PartialEq, Eq)]
103pub struct Class<'p> {
104 pub kind: pdb::ClassKind,
105 pub name: pdb::RawString<'p>,
106 pub base_classes: Vec<BaseClass>,
107 pub fields: Vec<Field<'p>>,
108 pub instance_methods: Vec<Method<'p>>,
109 pub static_methods: Vec<Method<'p>>,
110}
111
112impl<'p> Class<'p> {
113 fn add_derived_from(&mut self, _: &pdb::TypeFinder<'p>, _: pdb::TypeIndex, _: &mut TypeSet) {
114 }
116
117 fn add_fields(
118 &mut self,
119 type_finder: &pdb::TypeFinder<'p>,
120 type_index: pdb::TypeIndex,
121 needed_types: &mut TypeSet,
122 ) -> pdb::Result<()> {
123 match type_finder.find(type_index)?.parse()? {
124 pdb::TypeData::FieldList(data) => {
125 for field in &data.fields {
126 self.add_field(type_finder, field, needed_types)?;
127 }
128
129 if let Some(continuation) = data.continuation {
130 self.add_fields(type_finder, continuation, needed_types)?;
132 }
133 }
134 other => {
135 info!(
136 "trying to Class::add_fields() got {} -> {:?}",
137 type_index, other
138 );
139 panic!("unexpected type in Class::add_fields()");
140 }
141 }
142
143 Ok(())
144 }
145
146 fn add_field(
147 &mut self,
148 type_finder: &pdb::TypeFinder<'p>,
149 field: &pdb::TypeData<'p>,
150 needed_types: &mut TypeSet,
151 ) -> pdb::Result<()> {
152 match *field {
153 pdb::TypeData::Member(ref data) => {
154 let bit_offset = match type_finder.find(data.field_type)?.parse()? {
157 pdb::TypeData::Bitfield(bitfield) => bitfield.position,
158 _ => 0,
159 };
160
161 self.fields.push(Field {
162 type_name: type_name(type_finder, data.field_type, needed_types)?,
163 name: data.name,
164 offset: data.offset,
165 bit_offset,
166 });
167 }
168
169 pdb::TypeData::Method(ref data) => {
170 let method = Method::find(
171 data.name,
172 data.attributes,
173 type_finder,
174 data.method_type,
175 needed_types,
176 )?;
177 if data.attributes.is_static() {
178 self.static_methods.push(method);
179 } else {
180 self.instance_methods.push(method);
181 }
182 }
183
184 pdb::TypeData::OverloadedMethod(ref data) => {
185 match type_finder.find(data.method_list)?.parse()? {
188 pdb::TypeData::MethodList(method_list) => {
189 for pdb::MethodListEntry {
190 attributes,
191 method_type,
192 ..
193 } in method_list.methods
194 {
195 let method = Method::find(
197 data.name,
198 attributes,
199 type_finder,
200 method_type,
201 needed_types,
202 )?;
203
204 if attributes.is_static() {
205 self.static_methods.push(method);
206 } else {
207 self.instance_methods.push(method);
208 }
209 }
210 }
211 other => {
212 info!(
213 "processing OverloadedMethod, expected MethodList, got {} -> {:?}",
214 data.method_list, other
215 );
216 panic!("unexpected type in Class::add_field()");
217 }
218 }
219 }
220
221 pdb::TypeData::BaseClass(ref data) => self.base_classes.push(BaseClass {
222 type_name: type_name(type_finder, data.base_class, needed_types)?,
223 offset: data.offset,
224 }),
225
226 pdb::TypeData::VirtualBaseClass(ref data) => self.base_classes.push(BaseClass {
227 type_name: type_name(type_finder, data.base_class, needed_types)?,
228 offset: data.base_pointer_offset,
229 }),
230
231 _ => {
232 }
234 }
235
236 Ok(())
237 }
238}
239
240#[derive(Debug, Clone, PartialEq, Eq)]
241pub struct BaseClass {
242 pub type_name: String,
243 pub offset: u32,
244}
245
246#[derive(Debug, Clone, PartialEq, Eq)]
247pub struct Field<'p> {
248 pub type_name: String,
249 pub name: pdb::RawString<'p>,
250 pub offset: u64,
251 pub bit_offset: u8,
252}
253
254#[derive(Debug, Clone, PartialEq, Eq)]
255pub struct Method<'p> {
256 pub name: pdb::RawString<'p>,
257 pub return_type_name: String,
258 pub arguments: Vec<String>,
259 pub is_virtual: bool,
260}
261
262impl<'p> Method<'p> {
263 fn find(
264 name: pdb::RawString<'p>,
265 attributes: pdb::FieldAttributes,
266 type_finder: &pdb::TypeFinder<'p>,
267 type_index: pdb::TypeIndex,
268 needed_types: &mut TypeSet,
269 ) -> pdb::Result<Method<'p>> {
270 match type_finder.find(type_index)?.parse()? {
271 pdb::TypeData::MemberFunction(data) => Ok(Method {
272 name,
273 return_type_name: type_name(type_finder, data.return_type, needed_types)?,
274 arguments: argument_list(type_finder, data.argument_list, needed_types)?,
275 is_virtual: attributes.is_virtual(),
276 }),
277
278 other => {
279 info!("other: {:?}", other);
280 Err(pdb::Error::UnimplementedFeature("that"))
281 }
282 }
283 }
284}
285
286fn argument_list(
287 type_finder: &pdb::TypeFinder<'_>,
288 type_index: pdb::TypeIndex,
289 needed_types: &mut TypeSet,
290) -> pdb::Result<Vec<String>> {
291 match type_finder.find(type_index)?.parse()? {
292 pdb::TypeData::ArgumentList(data) => {
293 let mut args: Vec<String> = Vec::new();
294 for arg_type in data.arguments {
295 args.push(type_name(type_finder, arg_type, needed_types)?);
296 }
297 Ok(args)
298 }
299 _ => Err(pdb::Error::UnimplementedFeature(
300 "argument list of non-argument-list type",
301 )),
302 }
303}
304
305#[derive(Debug, Clone, PartialEq, Eq)]
306pub struct Enum<'p> {
307 name: pdb::RawString<'p>,
308 underlying_type_name: String,
309 values: Vec<EnumValue<'p>>,
310}
311
312impl<'p> Enum<'p> {
313 fn add_fields(
314 &mut self,
315 type_finder: &pdb::TypeFinder<'p>,
316 type_index: pdb::TypeIndex,
317 needed_types: &mut TypeSet,
318 ) -> pdb::Result<()> {
319 match type_finder.find(type_index)?.parse()? {
320 pdb::TypeData::FieldList(data) => {
321 for field in &data.fields {
322 self.add_field(type_finder, field, needed_types);
323 }
324
325 if let Some(continuation) = data.continuation {
326 self.add_fields(type_finder, continuation, needed_types)?;
328 }
329 }
330 other => {
331 info!(
332 "trying to Enum::add_fields() got {} -> {:?}",
333 type_index, other
334 );
335 panic!("unexpected type in Enum::add_fields()");
336 }
337 }
338
339 Ok(())
340 }
341
342 fn add_field(&mut self, _: &pdb::TypeFinder<'p>, field: &pdb::TypeData<'p>, _: &mut TypeSet) {
343 if let pdb::TypeData::Enumerate(ref data) = field {
345 self.values.push(EnumValue {
346 name: data.name,
347 value: data.value,
348 });
349 }
350 }
351}
352
353#[derive(Debug, Clone, PartialEq, Eq)]
354pub struct EnumValue<'p> {
355 name: pdb::RawString<'p>,
356 value: pdb::Variant,
357}
358
359#[derive(Debug, Clone, PartialEq, Eq)]
360pub struct ForwardReference<'p> {
361 kind: pdb::ClassKind,
362 name: pdb::RawString<'p>,
363}
364
365#[derive(Debug, Clone, PartialEq, Eq)]
366pub struct Data<'p> {
367 pub forward_references: Vec<ForwardReference<'p>>,
368 pub classes: Vec<Class<'p>>,
369 pub enums: Vec<Enum<'p>>,
370}
371
372impl<'p> Data<'p> {
373 pub fn new() -> Data<'p> {
374 Data {
375 forward_references: Vec::new(),
376 classes: Vec::new(),
377 enums: Vec::new(),
378 }
379 }
380
381 pub fn add(
382 &mut self,
383 type_finder: &pdb::TypeFinder<'p>,
384 type_index: pdb::TypeIndex,
385 needed_types: &mut TypeSet,
386 ) -> pdb::Result<()> {
387 match type_finder.find(type_index)?.parse()? {
388 pdb::TypeData::Class(data) => {
389 if data.properties.forward_reference() {
390 self.forward_references.push(ForwardReference {
391 kind: data.kind,
392 name: data.name,
393 });
394
395 return Ok(());
396 }
397
398 let mut class = Class {
399 kind: data.kind,
400 name: data.name,
401 fields: Vec::new(),
402 base_classes: Vec::new(),
403 instance_methods: Vec::new(),
404 static_methods: Vec::new(),
405 };
406
407 if let Some(derived_from) = data.derived_from {
408 class.add_derived_from(type_finder, derived_from, needed_types);
409 }
410
411 if let Some(fields) = data.fields {
412 class.add_fields(type_finder, fields, needed_types)?;
413 }
414
415 self.classes.insert(0, class);
416 }
417
418 pdb::TypeData::Enumeration(data) => {
419 let mut e = Enum {
420 name: data.name,
421 underlying_type_name: type_name(
422 type_finder,
423 data.underlying_type,
424 needed_types,
425 )?,
426 values: Vec::new(),
427 };
428
429 e.add_fields(type_finder, data.fields, needed_types)?;
430
431 self.enums.insert(0, e);
432 }
433
434 other => trace!("don't know how to add {:?}", other),
436 }
437
438 Ok(())
439 }
440}