1 : // Copyright 2015 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/refinery/types/dia_crawler.h"
16 :
17 : #include <hash_map>
18 :
19 : #include "base/strings/string_util.h"
20 : #include "base/strings/stringprintf.h"
21 : #include "base/win/scoped_bstr.h"
22 : #include "syzygy/pe/dia_util.h"
23 : #include "syzygy/refinery/types/type_namer.h"
24 : #include "syzygy/refinery/types/type_repository.h"
25 :
26 : namespace refinery {
27 :
28 : namespace {
29 :
30 E : bool GetSymFlags(IDiaSymbol* symbol, Type::Flags* flags) {
31 E : DCHECK(symbol); DCHECK(flags);
32 E : *flags = 0;
33 :
34 E : bool is_const = false;
35 E : bool is_volatile = false;
36 E : if (!pe::GetSymQualifiers(symbol, &is_const, &is_volatile))
37 i : return false;
38 :
39 E : if (is_const)
40 E : *flags |= UserDefinedType::FLAG_CONST;
41 E : if (is_volatile)
42 E : *flags |= UserDefinedType::FLAG_VOLATILE;
43 :
44 E : return true;
45 E : }
46 :
47 E : bool GetSymSize(IDiaSymbol* symbol, size_t* size) {
48 E : DCHECK(symbol); DCHECK(size);
49 :
50 E : ULONGLONG length = 0;
51 E : HRESULT hr = symbol->get_length(&length);
52 E : if (hr != S_OK)
53 i : return false;
54 :
55 E : *size = static_cast<size_t>(length);
56 E : return true;
57 E : }
58 :
59 E : bool GetSymBitPos(IDiaSymbol* symbol, size_t* bit_position) {
60 E : DCHECK(symbol); DCHECK(bit_position);
61 :
62 E : DWORD temp = 0;
63 E : HRESULT hr = symbol->get_bitPosition(&temp);
64 E : if (hr != S_OK)
65 i : return false;
66 :
67 E : *bit_position = static_cast<size_t>(temp);
68 E : return true;
69 E : }
70 :
71 : bool GetSymArrayIndexType(IDiaSymbol* symbol,
72 E : base::win::ScopedComPtr<IDiaSymbol>* type) {
73 E : DCHECK(symbol);
74 E : DCHECK(type);
75 E : base::win::ScopedComPtr<IDiaSymbol> tmp;
76 E : HRESULT hr = symbol->get_arrayIndexType(tmp.Receive());
77 E : if (hr != S_OK)
78 i : return false;
79 :
80 E : *type = tmp;
81 E : return true;
82 E : }
83 :
84 E : bool GetSymIndexId(IDiaSymbol* symbol, DWORD* index_id) {
85 E : DCHECK(symbol); DCHECK(index_id);
86 E : DWORD tmp = 0;
87 E : HRESULT hr = symbol->get_symIndexId(&tmp);
88 E : if (!SUCCEEDED(hr))
89 i : return false;
90 E : *index_id = tmp;
91 E : return true;
92 E : }
93 :
94 E : bool GetSymPtrMode(IDiaSymbol* symbol, PointerType::Mode* is_reference) {
95 E : DCHECK(symbol);
96 E : DCHECK(is_reference);
97 : BOOL is_ref;
98 E : HRESULT hr = symbol->get_reference(&is_ref);
99 E : if (hr != S_OK)
100 i : return false;
101 E : *is_reference = PointerType::PTR_MODE_PTR;
102 E : if (is_ref)
103 E : *is_reference = PointerType::PTR_MODE_REF;
104 E : return true;
105 E : }
106 :
107 : bool GetSymCallingConvention(IDiaSymbol* symbol,
108 E : FunctionType::CallConvention* call_convention) {
109 E : DCHECK(symbol);
110 E : DCHECK(call_convention);
111 E : DWORD tmp = 0;
112 E : HRESULT hr = symbol->get_callingConvention(&tmp);
113 E : if (!SUCCEEDED(hr))
114 i : return false;
115 E : *call_convention = static_cast<FunctionType::CallConvention>(tmp);
116 E : return true;
117 E : }
118 :
119 E : bool GetSymUdtKind(IDiaSymbol* symbol, UserDefinedType::UdtKind* udt_kind) {
120 E : DCHECK(symbol);
121 E : DCHECK(udt_kind);
122 : DWORD cci_udt_kind;
123 E : HRESULT hr = symbol->get_udtKind(&cci_udt_kind);
124 E : if (hr != S_OK)
125 i : return false;
126 :
127 E : switch (cci_udt_kind) {
128 : case UdtStruct: {
129 E : *udt_kind = UserDefinedType::UDT_STRUCT;
130 E : break;
131 : }
132 : case UdtClass: {
133 E : *udt_kind = UserDefinedType::UDT_CLASS;
134 E : break;
135 : }
136 : case UdtUnion: {
137 E : *udt_kind = UserDefinedType::UDT_UNION;
138 E : break;
139 : }
140 : case UdtInterface: {
141 i : NOTREACHED() << "Stumbled upon interface UDT kind which we don't expect.";
142 : }
143 : }
144 :
145 E : return true;
146 E : }
147 :
148 : class TypeCreator {
149 : public:
150 : explicit TypeCreator(TypeRepository* repository);
151 :
152 : // Crawls @p global, creates all types and assigns names to pointers.
153 : bool CreateTypes(IDiaSymbol* global);
154 :
155 : private:
156 : bool CreateTypesOfKind(enum SymTagEnum kind, IDiaSymbol* global);
157 : bool CreateGlobalDataTypes(IDiaSymbol* global);
158 :
159 : // Assigns names to all pointer, array and function types that have been
160 : // created.
161 : bool AssignTypeNames();
162 :
163 : // Finds or creates the type corresponding to @p symbol.
164 : // The type will be registered by a unique name in @p existing_types_.
165 : TypePtr FindOrCreateType(IDiaSymbol* symbol);
166 :
167 : TypePtr CreateType(IDiaSymbol* symbol);
168 : TypePtr CreateUDT(IDiaSymbol* symbol);
169 : TypePtr CreateEnum(IDiaSymbol* symbol);
170 : TypePtr CreateFunctionType(IDiaSymbol* symbol);
171 : TypePtr CreateBaseType(IDiaSymbol* symbol);
172 : TypePtr CreatePointerType(IDiaSymbol* symbol);
173 : TypePtr CreateTypedefType(IDiaSymbol* symbol);
174 : TypePtr CreateArrayType(IDiaSymbol* symbol);
175 :
176 : TypePtr CreateGlobalType(IDiaSymbol* symbol,
177 : const base::string16& name,
178 : uint64_t rva);
179 :
180 : bool FinalizeUDT(IDiaSymbol* symbol, UserDefinedTypePtr udt);
181 : bool FinalizePointer(IDiaSymbol* symbol, PointerTypePtr ptr);
182 : bool FinalizeArray(IDiaSymbol* symbol, ArrayTypePtr type);
183 : bool FinalizeFunction(IDiaSymbol* symbol, FunctionTypePtr type);
184 : bool FinalizeType(IDiaSymbol* symbol, TypePtr type);
185 :
186 : struct CreatedType {
187 E : CreatedType() : type_id(kNoTypeId), is_finalized(false) {
188 E : }
189 :
190 : TypeId type_id;
191 : bool is_finalized;
192 : };
193 : typedef base::hash_map<DWORD, CreatedType> CreatedTypeMap;
194 :
195 : // Maps from DIA symbol index ID to the created TypeId. Also keeps a flag
196 : // that's set when a type is finalized, as DIA has a nasty habit of
197 : // enumerating the same type multiple times.
198 : CreatedTypeMap created_types_;
199 : TypeRepository* repository_;
200 :
201 : TypeNamer type_namer_;
202 : };
203 :
204 : TypeCreator::TypeCreator(TypeRepository* repository)
205 E : : repository_(repository), type_namer_(false) {
206 E : DCHECK(repository);
207 E : }
208 :
209 E : bool TypeCreator::CreateTypesOfKind(enum SymTagEnum kind, IDiaSymbol* global) {
210 E : base::win::ScopedComPtr<IDiaEnumSymbols> matching_types;
211 : HRESULT hr = global->findChildren(kind,
212 : nullptr,
213 : nsNone,
214 E : matching_types.Receive());
215 E : if (!SUCCEEDED(hr))
216 i : return false;
217 :
218 : // The function get_Count from DIA has either a bug or is really badly
219 : // implemented thus taking forever to finish. Therefore we simply load next
220 : // symbol until reaching the end.
221 E : base::win::ScopedComPtr<IDiaSymbol> symbol;
222 E : ULONG received = 0;
223 E : hr = matching_types->Next(1, symbol.Receive(), &received);
224 :
225 E : while (hr == S_OK) {
226 E : scoped_refptr<Type> type = FindOrCreateType(symbol.get());
227 E : if (!type)
228 i : return false;
229 :
230 E : if (!FinalizeType(symbol.get(), type))
231 i : return false;
232 :
233 E : symbol.Release();
234 E : received = 0;
235 E : hr = matching_types->Next(1, symbol.Receive(), &received);
236 E : }
237 :
238 E : if (!SUCCEEDED(hr))
239 i : return false;
240 :
241 E : return true;
242 E : }
243 :
244 E : bool TypeCreator::CreateGlobalDataTypes(IDiaSymbol* global) {
245 E : base::win::ScopedComPtr<IDiaEnumSymbols> matching_types;
246 : HRESULT hr = global->findChildren(SymTagData, nullptr, nsNone,
247 E : matching_types.Receive());
248 E : if (!SUCCEEDED(hr))
249 i : return false;
250 :
251 E : ULONG received = 0;
252 E : while (true) {
253 E : base::win::ScopedComPtr<IDiaSymbol> symbol;
254 E : hr = matching_types->Next(1, symbol.Receive(), &received);
255 E : if (hr != S_OK)
256 E : break;
257 :
258 : // Filter here for symbols that have all the required properties.
259 E : LocationType location_type = LocIsNull;
260 E : DataKind data_kind = DataIsUnknown;
261 E : if (!pe::GetLocationType(symbol.get(), &location_type))
262 i : return false;
263 E : if (location_type != LocIsStatic)
264 E : continue;
265 :
266 E : if (!pe::GetDataKind(symbol.get(), &data_kind))
267 i : return false;
268 :
269 E : switch (data_kind) {
270 : case DataIsUnknown:
271 : case DataIsLocal:
272 : case DataIsParam:
273 : case DataIsObjectPtr:
274 : case DataIsMember:
275 : case DataIsStaticMember:
276 : case DataIsConstant:
277 i : continue;
278 :
279 : case DataIsStaticLocal:
280 : case DataIsFileStatic:
281 : case DataIsGlobal:
282 : // This data should have an RVA.
283 : break;
284 : }
285 :
286 E : base::string16 name;
287 E : if (!pe::GetSymName(symbol.get(), &name))
288 i : return false;
289 :
290 E : DWORD rva = 0;
291 E : HRESULT hr = symbol->get_relativeVirtualAddress(&rva);
292 E : if (hr != S_OK) {
293 : // This condition occurs for precisely two symbols that we've noticed.
294 : if (name == L"__safe_se_handler_count" ||
295 E : name == L"__safe_se_handler_table") {
296 E : continue;
297 : }
298 :
299 : // Make sure to err out for other cases for now.
300 : // TODO(siggi): Revisit this once the reason for this anomaly is
301 : // understood.
302 i : LOG(ERROR) << "Symbol " << name << " has no RVA!";
303 i : return false;
304 : }
305 :
306 : // See whether the type has been created.
307 E : DWORD index_id = 0;
308 E : if (!GetSymIndexId(symbol.get(), &index_id))
309 i : return false;
310 :
311 E : auto it = created_types_.find(index_id);
312 E : if (it != created_types_.end())
313 i : continue;
314 :
315 : // Ok, we need to create it.
316 E : TypePtr created = CreateGlobalType(symbol.get(), name, rva);
317 E : DCHECK(created);
318 E : CreatedType& entry = created_types_[index_id];
319 E : entry.type_id = repository_->AddType(created);
320 E : entry.is_finalized = false;
321 :
322 E : if (!FinalizeType(symbol.get(), created))
323 i : return false;
324 E : }
325 :
326 E : if (!SUCCEEDED(hr))
327 i : return false;
328 :
329 E : return true;
330 E : }
331 :
332 E : bool TypeCreator::FinalizeType(IDiaSymbol* symbol, TypePtr type) {
333 : // See whether this type needs finalizing.
334 E : DWORD index_id = 0;
335 E : if (!GetSymIndexId(symbol, &index_id))
336 i : return false;
337 :
338 E : DCHECK_EQ(type->type_id(), created_types_[index_id].type_id);
339 E : if (created_types_[index_id].is_finalized) {
340 : // This is a re-visit of the same type. DIA has a nasty habit of doing
341 : // this, e.g. yielding the same type multiple times in an iteration.
342 E : return true;
343 : }
344 :
345 E : created_types_[index_id].is_finalized = true;
346 :
347 E : switch (type->kind()) {
348 : case Type::USER_DEFINED_TYPE_KIND: {
349 E : UserDefinedTypePtr udt;
350 E : if (!type->CastTo(&udt))
351 i : return false;
352 :
353 E : return FinalizeUDT(symbol, udt);
354 : }
355 :
356 : case Type::POINTER_TYPE_KIND: {
357 E : PointerTypePtr ptr;
358 E : if (!type->CastTo(&ptr))
359 i : return false;
360 :
361 E : return FinalizePointer(symbol, ptr);
362 : }
363 :
364 : case Type::ARRAY_TYPE_KIND: {
365 E : ArrayTypePtr array;
366 E : if (!type->CastTo(&array))
367 i : return false;
368 :
369 E : return FinalizeArray(symbol, array);
370 : }
371 :
372 : case Type::FUNCTION_TYPE_KIND: {
373 E : FunctionTypePtr function;
374 E : if (!type->CastTo(&function))
375 i : return false;
376 :
377 E : return FinalizeFunction(symbol, function);
378 : }
379 :
380 : default:
381 E : return true;
382 : }
383 E : }
384 :
385 E : bool TypeCreator::CreateTypes(IDiaSymbol* global) {
386 : if (!CreateTypesOfKind(SymTagUDT, global) ||
387 : !CreateTypesOfKind(SymTagEnum, global) ||
388 : !CreateTypesOfKind(SymTagTypedef, global) ||
389 : !CreateTypesOfKind(SymTagPointerType, global) ||
390 : !CreateTypesOfKind(SymTagArrayType, global) ||
391 : !CreateTypesOfKind(SymTagFunctionType, global) ||
392 E : !CreateGlobalDataTypes(global)) {
393 i : return false;
394 : }
395 :
396 E : return AssignTypeNames();
397 E : }
398 :
399 E : bool TypeCreator::AssignTypeNames() {
400 E : for (auto type : *repository_) {
401 E : if (!type_namer_.EnsureTypeName(type))
402 i : return false;
403 E : }
404 :
405 E : return true;
406 E : }
407 :
408 E : TypePtr TypeCreator::FindOrCreateType(IDiaSymbol* symbol) {
409 E : DCHECK(symbol);
410 :
411 E : DWORD index_id = 0;
412 E : if (!GetSymIndexId(symbol, &index_id))
413 i : return false;
414 :
415 E : auto it = created_types_.find(index_id);
416 E : if (it != created_types_.end())
417 E : return repository_->GetType(it->second.type_id);
418 :
419 : // Note that this will recurse on pointer types, but the recursion should
420 : // terminate on a basic type or a UDT at some point - assuming the type
421 : // graph is sane.
422 : // TODO(siggi): It'd be better never to recurse, and this can be avoided for
423 : // pointers by doing two-phase construction on them as for UDTs. To assign
424 : // unique, human-readable names to pointers requires another pass yet.
425 E : TypePtr created = CreateType(symbol);
426 E : DCHECK(created);
427 E : CreatedType& entry = created_types_[index_id];
428 E : entry.type_id = repository_->AddType(created);
429 E : entry.is_finalized = false;
430 :
431 : // Pointers to base types will not get enumerated by DIA and therefore need to
432 : // be finalized manually. We do so here.
433 E : if (created->kind() == Type::POINTER_TYPE_KIND) {
434 E : base::win::ScopedComPtr<IDiaSymbol> contained_type_sym;
435 E : if (!pe::GetSymType(symbol, &contained_type_sym))
436 i : return nullptr;
437 E : enum SymTagEnum contained_sym_tag = SymTagNull;
438 E : if (!pe::GetSymTag(contained_type_sym.get(), &contained_sym_tag))
439 i : return nullptr;
440 E : if (contained_sym_tag == SymTagBaseType) {
441 E : if (!FinalizeType(symbol, created))
442 i : return nullptr;
443 : }
444 E : }
445 :
446 E : return created;
447 E : }
448 :
449 E : TypePtr TypeCreator::CreateType(IDiaSymbol* symbol) {
450 E : DCHECK(symbol);
451 :
452 E : enum SymTagEnum sym_tag = SymTagNull;
453 E : if (!pe::GetSymTag(symbol, &sym_tag))
454 i : return nullptr;
455 :
456 E : switch (sym_tag) {
457 : case SymTagUDT:
458 E : return CreateUDT(symbol);
459 : case SymTagEnum:
460 E : return CreateEnum(symbol);
461 : case SymTagBaseType:
462 E : return CreateBaseType(symbol);
463 : case SymTagFunctionType:
464 E : return CreateFunctionType(symbol);
465 : case SymTagPointerType:
466 E : return CreatePointerType(symbol);
467 : case SymTagTypedef:
468 E : return CreateTypedefType(symbol);
469 : case SymTagArrayType:
470 E : return CreateArrayType(symbol);
471 : case SymTagVTableShape:
472 E : return new WildcardType(L"VTableShape", 0);
473 : case SymTagVTable:
474 i : return new WildcardType(L"VTable", 0);
475 : default:
476 i : return nullptr;
477 : }
478 E : }
479 :
480 E : TypePtr TypeCreator::CreateUDT(IDiaSymbol* symbol) {
481 E : DCHECK(symbol);
482 E : DCHECK(pe::IsSymTag(symbol, SymTagUDT));
483 :
484 E : base::string16 name;
485 E : size_t size = 0;
486 : UserDefinedType::UdtKind udt_kind;
487 : if (!pe::GetSymName(symbol, &name) || !GetSymSize(symbol, &size) ||
488 E : !GetSymUdtKind(symbol, &udt_kind)) {
489 i : return nullptr;
490 : }
491 :
492 E : return new UserDefinedType(name, size, udt_kind);
493 E : }
494 :
495 E : TypePtr TypeCreator::CreateEnum(IDiaSymbol* symbol) {
496 E : DCHECK(symbol);
497 E : DCHECK(pe::IsSymTag(symbol, SymTagEnum));
498 :
499 E : base::string16 name;
500 E : size_t size = 0;
501 E : if (!pe::GetSymName(symbol, &name) || !GetSymSize(symbol, &size))
502 i : return nullptr;
503 :
504 : // TODO(siggi): Implement an enum type.
505 E : return new WildcardType(name, size);
506 E : }
507 :
508 E : bool TypeCreator::FinalizeUDT(IDiaSymbol* symbol, UserDefinedTypePtr udt) {
509 E : DCHECK(symbol);
510 E : DCHECK(udt);
511 E : DCHECK(pe::IsSymTag(symbol, SymTagUDT));
512 :
513 : // Enumerate the fields and add them.
514 E : base::win::ScopedComPtr<IDiaEnumSymbols> enum_children;
515 : HRESULT hr = symbol->findChildren(
516 E : SymTagNull, NULL, nsNone, enum_children.Receive());
517 E : if (!SUCCEEDED(hr))
518 i : return false;
519 :
520 E : LONG count = 0;
521 E : hr = enum_children->get_Count(&count);
522 E : if (!SUCCEEDED(hr))
523 i : return false;
524 :
525 E : UserDefinedType::Fields fields;
526 E : UserDefinedType::Functions functions;
527 E : for (LONG i = 0; i < count; ++i) {
528 E : base::win::ScopedComPtr<IDiaSymbol> field_sym;
529 E : hr = enum_children->Item(i, field_sym.Receive());
530 E : if (!SUCCEEDED(hr))
531 i : return false;
532 :
533 E : enum SymTagEnum sym_tag = SymTagNull;
534 E : if (!pe::GetSymTag(field_sym.get(), &sym_tag))
535 i : return false;
536 :
537 : // We only care about data and functions.
538 E : if (sym_tag == SymTagData) {
539 : // TODO(siggi): Also process VTables?
540 E : DataKind data_kind = DataIsUnknown;
541 E : if (!pe::GetDataKind(field_sym.get(), &data_kind))
542 i : return false;
543 : // We only care about member data.
544 E : if (data_kind != DataIsMember)
545 E : continue;
546 :
547 : // The location udt and the symbol udt are a little conflated in the case
548 : // of bitfields. For bitfieds, the bit length and bit offset of the udt
549 : // are stored against the data symbol, and not its udt.
550 E : LocationType loc_type = LocIsNull;
551 E : if (!pe::GetLocationType(field_sym.get(), &loc_type))
552 i : return false;
553 E : DCHECK(loc_type == LocIsThisRel || loc_type == LocIsBitField);
554 :
555 E : base::win::ScopedComPtr<IDiaSymbol> field_type_sym;
556 E : base::string16 field_name;
557 E : ptrdiff_t field_offset = 0;
558 E : size_t field_size = 0;
559 E : Type::Flags field_flags = 0;
560 : if (!pe::GetSymType(field_sym.get(), &field_type_sym) ||
561 : !pe::GetSymName(field_sym.get(), &field_name) ||
562 : !pe::GetSymOffset(field_sym.get(), &field_offset) ||
563 : !GetSymSize(field_type_sym.get(), &field_size) ||
564 E : !GetSymFlags(field_type_sym.get(), &field_flags)) {
565 i : return false;
566 : }
567 :
568 E : TypePtr field_type;
569 E : field_type = FindOrCreateType(field_type_sym.get());
570 E : size_t bit_length = 0;
571 E : size_t bit_pos = 0;
572 E : if (loc_type == LocIsBitField) {
573 : // For bitfields we need the bit size and length.
574 : if (!GetSymSize(field_sym.get(), &bit_length) ||
575 E : !GetSymBitPos(field_sym.get(), &bit_pos)) {
576 i : return false;
577 E : }
578 E : } else if (loc_type != LocIsThisRel) {
579 i : NOTREACHED() << "Impossible location udt!";
580 : }
581 :
582 : fields.push_back(UserDefinedType::Field(field_name, field_offset,
583 : field_flags, bit_pos, bit_length,
584 E : field_type->type_id()));
585 E : } else if (sym_tag == SymTagFunction) {
586 E : base::win::ScopedComPtr<IDiaSymbol> function_type_sym;
587 E : base::string16 function_name;
588 :
589 : if (!pe::GetSymType(field_sym.get(), &function_type_sym) ||
590 E : !pe::GetSymName(field_sym.get(), &function_name)) {
591 i : return false;
592 : }
593 :
594 E : TypePtr function_type;
595 E : function_type = FindOrCreateType(function_type_sym.get());
596 E : if (!function_type)
597 i : return false;
598 :
599 : functions.push_back(
600 E : UserDefinedType::Function(function_name, function_type->type_id()));
601 E : }
602 E : }
603 :
604 E : DCHECK_EQ(0UL, udt->fields().size());
605 E : DCHECK_EQ(0UL, udt->functions().size());
606 E : udt->Finalize(fields, functions);
607 E : return true;
608 E : }
609 :
610 E : bool TypeCreator::FinalizePointer(IDiaSymbol* symbol, PointerTypePtr ptr) {
611 E : DCHECK(symbol);
612 E : DCHECK(ptr);
613 E : DCHECK(pe::IsSymTag(symbol, SymTagPointerType));
614 :
615 E : base::win::ScopedComPtr<IDiaSymbol> contained_type_sym;
616 E : if (!pe::GetSymType(symbol, &contained_type_sym))
617 i : return false;
618 :
619 E : Type::Flags flags = 0;
620 E : if (!GetSymFlags(contained_type_sym.get(), &flags))
621 i : return false;
622 :
623 E : TypePtr contained_type = FindOrCreateType(contained_type_sym.get());
624 E : if (!contained_type)
625 i : return false;
626 :
627 E : ptr->Finalize(flags, contained_type->type_id());
628 E : return true;
629 E : }
630 :
631 E : bool TypeCreator::FinalizeArray(IDiaSymbol* symbol, ArrayTypePtr array) {
632 E : DCHECK(symbol);
633 E : DCHECK(array);
634 E : DCHECK(pe::IsSymTag(symbol, SymTagArrayType));
635 :
636 E : base::win::ScopedComPtr<IDiaSymbol> index_type_sym;
637 E : if (!GetSymArrayIndexType(symbol, &index_type_sym))
638 i : return false;
639 :
640 E : size_t element_count = 0;
641 E : if (!pe::GetSymCount(symbol, &element_count))
642 i : return false;
643 :
644 E : base::win::ScopedComPtr<IDiaSymbol> element_type_sym;
645 E : if (!pe::GetSymType(symbol, &element_type_sym))
646 i : return false;
647 :
648 E : Type::Flags flags = 0;
649 E : if (!GetSymFlags(element_type_sym.get(), &flags))
650 i : return false;
651 :
652 E : TypePtr index_type = FindOrCreateType(index_type_sym.get());
653 E : if (!index_type)
654 i : return false;
655 E : TypePtr element_type = FindOrCreateType(element_type_sym.get());
656 E : if (!element_type)
657 i : return false;
658 :
659 : array->Finalize(flags, index_type->type_id(), element_count,
660 E : element_type->type_id());
661 E : return true;
662 E : }
663 :
664 : bool TypeCreator::FinalizeFunction(IDiaSymbol* symbol,
665 E : FunctionTypePtr function) {
666 E : DCHECK(symbol);
667 E : DCHECK(function);
668 E : DCHECK(pe::IsSymTag(symbol, SymTagFunctionType));
669 :
670 : // Determine the return type.
671 E : base::win::ScopedComPtr<IDiaSymbol> return_type_sym;
672 E : if (!pe::GetSymType(symbol, &return_type_sym))
673 i : return false;
674 :
675 E : Type::Flags return_flags = 0;
676 E : if (!GetSymFlags(return_type_sym.get(), &return_flags))
677 i : return false;
678 :
679 E : TypePtr return_type = FindOrCreateType(return_type_sym.get());
680 E : if (!return_type)
681 i : return false;
682 :
683 : // Determine the containing class, if any.
684 E : TypeId containing_class_id = kNoTypeId;
685 E : base::win::ScopedComPtr<IDiaSymbol> parent_type_sym;
686 E : if (!pe::GetSymClassParent(symbol, &parent_type_sym))
687 i : return false;
688 E : if (parent_type_sym.get() != nullptr) {
689 E : TypePtr parent_type = FindOrCreateType(parent_type_sym.get());
690 E : if (!parent_type)
691 i : return false;
692 E : containing_class_id = parent_type->type_id();
693 E : }
694 :
695 : // Process arguments.
696 E : base::win::ScopedComPtr<IDiaEnumSymbols> argument_types;
697 : HRESULT hr = symbol->findChildren(SymTagFunctionArgType, nullptr, nsNone,
698 E : argument_types.Receive());
699 E : if (!SUCCEEDED(hr))
700 i : return false;
701 :
702 E : base::win::ScopedComPtr<IDiaSymbol> arg_sym;
703 E : ULONG received = 0;
704 E : hr = argument_types->Next(1, arg_sym.Receive(), &received);
705 :
706 E : FunctionType::Arguments args;
707 E : while (hr == S_OK) {
708 E : base::win::ScopedComPtr<IDiaSymbol> arg_type_sym;
709 E : if (!pe::GetSymType(arg_sym.get(), &arg_type_sym))
710 i : return false;
711 :
712 E : TypePtr arg_type = FindOrCreateType(arg_type_sym.get());
713 E : if (!arg_type)
714 i : return false;
715 :
716 E : Type::Flags arg_flags = 0;
717 E : if (!GetSymFlags(arg_type_sym.get(), &arg_flags))
718 i : return false;
719 :
720 E : args.push_back(FunctionType::ArgumentType(arg_flags, arg_type->type_id()));
721 :
722 E : arg_sym.Release();
723 E : received = 0;
724 E : hr = argument_types->Next(1, arg_sym.Receive(), &received);
725 E : }
726 :
727 E : if (!SUCCEEDED(hr))
728 i : return false;
729 :
730 : function->Finalize(
731 : FunctionType::ArgumentType(return_flags, return_type->type_id()), args,
732 E : containing_class_id);
733 E : return true;
734 E : }
735 :
736 E : TypePtr TypeCreator::CreateBaseType(IDiaSymbol* symbol) {
737 : // Note that the void base type has zero size.
738 E : DCHECK(symbol);
739 E : DCHECK(pe::IsSymTag(symbol, SymTagBaseType));
740 :
741 E : base::string16 base_type_name;
742 E : size_t size = 0;
743 : if (!GetSymBaseTypeName(symbol, &base_type_name) ||
744 E : !GetSymSize(symbol, &size)) {
745 i : return nullptr;
746 : }
747 :
748 E : return new BasicType(base_type_name, size);
749 E : }
750 :
751 E : TypePtr TypeCreator::CreateFunctionType(IDiaSymbol* symbol) {
752 E : DCHECK(symbol);
753 E : DCHECK(pe::IsSymTag(symbol, SymTagFunctionType));
754 :
755 : FunctionType::CallConvention call_convention;
756 :
757 E : if (!GetSymCallingConvention(symbol, &call_convention))
758 i : return nullptr;
759 :
760 E : return new FunctionType(call_convention);
761 E : }
762 :
763 E : TypePtr TypeCreator::CreatePointerType(IDiaSymbol* symbol) {
764 : // Note that the void base type has zero size.
765 E : DCHECK(symbol);
766 E : DCHECK(pe::IsSymTag(symbol, SymTagPointerType));
767 :
768 E : size_t size = 0;
769 E : PointerType::Mode ptr_mode = PointerType::PTR_MODE_PTR;
770 E : if (!GetSymSize(symbol, &size) || !GetSymPtrMode(symbol, &ptr_mode))
771 i : return nullptr;
772 :
773 E : return new PointerType(size, ptr_mode);
774 E : }
775 :
776 E : TypePtr TypeCreator::CreateTypedefType(IDiaSymbol* symbol) {
777 E : DCHECK(symbol);
778 E : DCHECK(pe::IsSymTag(symbol, SymTagTypedef));
779 :
780 E : base::string16 name;
781 E : if (!pe::GetSymName(symbol, &name))
782 i : return nullptr;
783 :
784 : // TODO(siggi): Implement a typedef type.
785 E : return new WildcardType(name, 0);
786 E : }
787 :
788 E : TypePtr TypeCreator::CreateArrayType(IDiaSymbol* symbol) {
789 E : DCHECK(symbol);
790 E : DCHECK(pe::IsSymTag(symbol, SymTagArrayType));
791 :
792 E : size_t size = 0;
793 E : if (!GetSymSize(symbol, &size)) {
794 i : return nullptr;
795 : }
796 :
797 E : return new ArrayType(size);
798 E : }
799 :
800 : TypePtr TypeCreator::CreateGlobalType(IDiaSymbol* symbol,
801 : const base::string16& name,
802 E : uint64_t rva) {
803 E : DCHECK(symbol);
804 E : DCHECK(pe::IsSymTag(symbol, SymTagData));
805 :
806 E : base::win::ScopedComPtr<IDiaSymbol> global_type;
807 E : if (!pe::GetSymType(symbol, &global_type))
808 i : return nullptr;
809 :
810 E : TypePtr type = FindOrCreateType(global_type.get());
811 E : if (!type)
812 i : return false;
813 :
814 E : return new GlobalType(name, rva, type->type_id(), type->size());
815 E : }
816 :
817 : } // namespace
818 :
819 E : DiaCrawler::DiaCrawler() {
820 E : }
821 :
822 E : DiaCrawler::~DiaCrawler() {
823 E : }
824 :
825 E : bool DiaCrawler::InitializeForFile(const base::FilePath& path) {
826 E : base::win::ScopedComPtr<IDiaDataSource> source;
827 E : if (!pe::CreateDiaSource(source.Receive()))
828 i : return false;
829 :
830 E : base::win::ScopedComPtr<IDiaSession> session;
831 E : if (!pe::CreateDiaSession(path, source.get(), session.Receive()))
832 i : return false;
833 :
834 E : return InitializeForSession(source, session);
835 E : }
836 :
837 : bool DiaCrawler::InitializeForSession(
838 : base::win::ScopedComPtr<IDiaDataSource> source,
839 E : base::win::ScopedComPtr<IDiaSession> session) {
840 E : DCHECK(source.get()); DCHECK(session.get());
841 :
842 E : HRESULT hr = session->get_globalScope(global_.Receive());
843 E : if (!SUCCEEDED(hr) || !global_)
844 i : return false;
845 :
846 E : source_ = source;
847 E : session_ = session;
848 :
849 E : return true;
850 E : }
851 :
852 E : bool DiaCrawler::GetTypes(TypeRepository* types) {
853 E : DCHECK(types); DCHECK(global_);
854 :
855 : // For each type in the PDB:
856 : // Create a unique name for the type.
857 : // Find or create the type by its unique name.
858 : // Finalize the type, e.g.
859 : // For each relevant "child" of the type.
860 : // Create a unique name for the child.
861 : // Find or create the child by its unique name.
862 E : TypeCreator creator(types);
863 :
864 E : return creator.CreateTypes(global_.get());
865 E : }
866 :
867 E : bool DiaCrawler::GetVFTableRVAs(base::hash_set<Address>* vftable_rvas) {
868 E : DCHECK(vftable_rvas); DCHECK(global_);
869 E : vftable_rvas->clear();
870 :
871 : // VFTables are represented as public symbols. Note: we search through all
872 : // public symbols as we match on the undecorated name, not on the name.
873 E : base::win::ScopedComPtr<IDiaEnumSymbols> public_symbols;
874 : HRESULT hr = global_->findChildren(SymTagPublicSymbol, nullptr, nsNone,
875 E : public_symbols.Receive());
876 E : if (!SUCCEEDED(hr))
877 i : return false;
878 :
879 : // Note: the function get_Count from DIA has either a bug or is really badly
880 : // implemented thus taking forever to finish. Therefore we simply load next
881 : // symbol until reaching the end. Unfortunately, this also means we don't use
882 : // it for reserving the container's size.
883 E : base::win::ScopedComPtr<IDiaSymbol> symbol;
884 E : ULONG received = 0;
885 E : hr = public_symbols->Next(1, symbol.Receive(), &received);
886 :
887 E : while (hr == S_OK) {
888 E : base::string16 undecorated_name;
889 E : if (!pe::GetSymUndecoratedName(symbol.get(), &undecorated_name))
890 i : return false; // Public symbols are expected to have names.
891 :
892 : // Vftable names should look like:
893 : // const std::Foo::`vftable'
894 : // const testing::Foo::`vftable'{for `testing::Foo'}
895 E : if (undecorated_name.find(L"::`vftable'") != base::string16::npos) {
896 E : LocationType location_type = LocIsNull;
897 E : if (!pe::GetLocationType(symbol.get(), &location_type))
898 i : return false;
899 E : if (location_type != LocIsStatic) {
900 i : LOG(ERROR) << "Unexpected vftable location type: " << location_type;
901 i : return false;
902 : }
903 :
904 E : DWORD rva = 0U;
905 E : HRESULT hr = symbol->get_relativeVirtualAddress(&rva);
906 E : if (hr != S_OK) {
907 i : LOG(ERROR) << "Unable to get vftable's RVA: " << common::LogHr(hr)
908 : << ".";
909 i : return false;
910 : }
911 :
912 E : vftable_rvas->insert(static_cast<Address>(rva));
913 : }
914 :
915 E : symbol.Release();
916 E : received = 0;
917 E : hr = public_symbols->Next(1, symbol.Receive(), &received);
918 E : }
919 :
920 E : if (!SUCCEEDED(hr))
921 i : return false;
922 :
923 E : return true;
924 E : }
925 :
926 : } // namespace refinery
|