Coverage for /Syzygy/refinery/types/dia_crawler.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
83.6%4485360.C++source

Line-by-line coverage:

   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

Coverage information generated Thu Jan 14 17:40:38 2016.