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

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

Coverage information generated Fri Jul 29 11:00:21 2016.