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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
0.0%001102.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/pdb_crawler.h"
  16    :  
  17    :  #include <string>
  18    :  #include <vector>
  19    :  
  20    :  #include "base/bind.h"
  21    :  #include "base/logging.h"
  22    :  #include "base/strings/pattern.h"
  23    :  #include "base/strings/string16.h"
  24    :  #include "base/strings/stringprintf.h"
  25    :  #include "syzygy/common/align.h"
  26    :  #include "syzygy/core/address.h"
  27    :  #include "syzygy/pdb/omap.h"
  28    :  #include "syzygy/pdb/pdb_dbi_stream.h"
  29    :  #include "syzygy/pdb/pdb_file.h"
  30    :  #include "syzygy/pdb/pdb_reader.h"
  31    :  #include "syzygy/pdb/pdb_reader.h"
  32    :  #include "syzygy/pdb/pdb_symbol_record.h"
  33    :  #include "syzygy/pdb/pdb_type_info_stream_enum.h"
  34    :  #include "syzygy/pdb/pdb_util.h"
  35    :  #include "syzygy/pdb/gen/pdb_type_info_records.h"
  36    :  #include "syzygy/pe/cvinfo_ext.h"
  37    :  #include "syzygy/refinery/types/type.h"
  38    :  #include "syzygy/refinery/types/type_repository.h"
  39    :  
  40  m :  namespace refinery {
  41    :  
  42  m :  namespace {
  43    :  
  44  m :  namespace cci = Microsoft_Cci_Pdb;
  45    :  
  46  m :  const uint16_t kNoLeafType = static_cast<uint16_t>(-1);
  47    :  
  48  m :  class TypeCreator {
  49  m :   public:
  50  m :    TypeCreator(TypeRepository* repository, pdb::PdbStream* stream);
  51  m :    ~TypeCreator();
  52    :  
  53    :    // Crawls @p stream_, creates all types and assigns names to pointers.
  54    :    // @returns true on success, false on failure.
  55  m :    bool CreateTypes();
  56    :  
  57  m :   private:
  58    :    // The following functions parse objects from the data stream.
  59    :    // @returns pointer to the created object or nullptr on failure.
  60  m :    TypePtr CreateUserDefinedType(TypeId type_id);
  61  m :    TypePtr CreateBasicPointerType(TypeId type_id);
  62  m :    TypePtr CreatePointerType(TypeId type_id);
  63  m :    TypePtr CreateArrayType(TypeId type_id);
  64  m :    TypePtr CreateFunctionType(TypeId type_id);
  65  m :    TypePtr CreateBasicType(TypeId type_id);
  66  m :    TypePtr CreateWildcardType(TypeId type_id);
  67    :  
  68    :    // The following functions parse records but do not save them in the type
  69    :    // repository. Instead they just pass out the flags (and bit field values)
  70    :    // to the caller. However they ensure parsing of the underlying types.
  71    :    // @returns pointer to the type underlying the modifier.
  72  m :    TypePtr ReadModifier(TypeId type_id, Type::Flags* flags);
  73  m :    TypePtr ReadPointer(TypeId type_id, Type::Flags* flags);
  74  m :    TypePtr ReadBitfield(TypeId type_id,
  75  m :                         Type::Flags* flags,
  76  m :                         size_t* bit_pos,
  77  m :                         size_t* bit_len);
  78    :  
  79    :    // Processes a base class field and inserts it into given field list.
  80    :    // @param bclass pointer to the (non-virtual) base class field record.
  81    :    // @param fields pointer to the field list.
  82    :    // @returns true on success, false on failure.
  83  m :    bool ProcessBClass(pdb::LeafBClass* bclass, UserDefinedType::Fields* fields);
  84    :  
  85    :    // Processes a member field and inserts it into given field list.
  86    :    // @param member pointer to the member type record.
  87    :    // @param fields pointer to the field list.
  88    :    // @returns true on success, false on failure.
  89  m :    bool ProcessMember(pdb::LeafMember* member, UserDefinedType::Fields* fields);
  90    :  
  91    :    // Processes one method field and adds it as a member function in the member
  92    :    // function list.
  93    :    // @param method pointer to the one method type record.
  94    :    // @param functions pointer to the member function list.
  95    :    // @returns true on success, false on failure.
  96  m :    bool ProcessOneMethod(pdb::LeafOneMethod* method,
  97  m :                          UserDefinedType::Functions* functions);
  98    :  
  99    :    // Processes overloaded method field and add the member functions to the given
 100    :    // list.
 101    :    // @param method pointer to the method type record.
 102    :    // @param functions pointer to the member function list.
 103    :    // @returns true on success, false on failure.
 104  m :    bool ProcessMethod(pdb::LeafMethod* method,
 105  m :                       UserDefinedType::Functions* functions);
 106    :  
 107    :    // Helper function for processesing a virtual function field and inserting it
 108    :    // into given field list.
 109    :    // @param id the type identifier of the virtual function field.
 110    :    // @param offset the offset of the field within the containing class.
 111    :    // @param fields pointer to the field list.
 112    :    // @returns true on success, false on failure.
 113  m :    bool ProcessVFunc(TypeId id,
 114  m :                      ptrdiff_t offset,
 115  m :                      UserDefinedType::Fields* fields);
 116    :  
 117    :    // Processes a virtual function at offset field and inserts it into given
 118    :    // field list.
 119    :    // @param vfunc pointer to the virtual function at offset field record.
 120    :    // @param fields pointer to the field list.
 121    :    // @returns true on success, false on failure.
 122  m :    bool ProcessVFuncOff(pdb::LeafVFuncOff* vfunc,
 123  m :                         UserDefinedType::Fields* fields);
 124    :  
 125    :    // Processes a virtual function field and inserts it into given field list.
 126    :    // @param vfunc pointer to the virtual function field record.
 127    :    // @param fields pointer to the field list.
 128    :    // @returns true on success, false on failure.
 129  m :    bool ProcessVFuncTab(pdb::LeafVFuncTab* vfunc,
 130  m :                         UserDefinedType::Fields* fields);
 131    :  
 132    :    // Parses field list from the data stream and populates the UDT with fields
 133    :    // and member functions.
 134    :    // @param fields pointer to the field list.
 135    :    // @param functions pointer to the member function list.
 136    :    // @returns true on success, false on failure.
 137  m :    bool ReadFieldlist(TypeId type_id,
 138  m :                       UserDefinedType::Fields* fields,
 139  m :                       UserDefinedType::Functions* functions);
 140    :  
 141    :    // Parses arglist from the data stream and populates the given list of
 142    :    // argument types.
 143    :    // @param args pointer to the the argument list.
 144    :    // @returns true on success, false on failure.
 145  m :    bool ReadArglist(TypeId type_id, FunctionType::Arguments* args);
 146    :  
 147    :    // Parses type given by a type from the PDB type info stream.
 148    :    // @param type_id index of the type to create.
 149    :    // @returns pointer to the created object.
 150  m :    TypePtr CreateType(TypeId type_id);
 151    :  
 152    :    // Returns the leaf type of a record with given type index.
 153    :    // @param type_id type index of the record.
 154    :    // @returns type of the record, -1 as an error sentinel.
 155    :    // TODO(manzagop): Add a typedef for the leaf type.
 156  m :    uint16_t GetLeafType(TypeId type_id);
 157    :  
 158    :    // Does a first pass through the stream making the map of type indices for
 159    :    // UDT and saves indices of all types that will get translated to the type
 160    :    // repo.
 161    :    // @returns true on success, false on failure.
 162  m :    bool PrepareData();
 163    :  
 164    :    // Checks if type object exists and constructs one if it does not.
 165    :    // @param type_id type index of the type.
 166    :    // @returns pointer to the type object.
 167  m :    TypePtr FindOrCreateTypeImpl(TypeId type_id);
 168    :  
 169    :    // The following functions are called during parsing to recurse deeper and
 170    :    // validate the references we expect to be there. For better description see
 171    :    // the file pdb_type_info_stream_description.md in the pdb directory.
 172  m :    TypePtr FindOrCreateBasicType(TypeId type_id);
 173  m :    TypePtr FindOrCreateIndexingType(TypeId type_id);
 174  m :    TypePtr FindOrCreateIntegralBasicType(TypeId type_id);
 175  m :    TypePtr FindOrCreateStructuredType(TypeId type_id);
 176  m :    TypePtr FindOrCreateInheritableType(TypeId type_id);
 177  m :    TypePtr FindOrCreateUserDefinedType(TypeId type_id);
 178  m :    TypePtr FindOrCreateModifiableType(TypeId type_id);
 179  m :    TypePtr FindOrCreateSpecificType(TypeId type_id, uint16_t type);
 180    :  
 181    :    // The following function also propagate the flags and bit field information
 182    :    // to their parents.
 183  m :    TypePtr FindOrCreateOptionallyModifiedType(TypeId type_id,
 184  m :                                               Type::Flags* flags);
 185  m :    TypePtr FindOrCreateBitfieldType(TypeId type_id, Type::Flags* flags);
 186  m :    TypePtr FindOrCreatePointableType(TypeId type_id, Type::Flags* flags);
 187  m :    TypePtr FindOrCreateMemberType(TypeId type_id,
 188  m :                                   Type::Flags* flags,
 189  m :                                   size_t* bit_pos,
 190  m :                                   size_t* bit_len);
 191    :  
 192    :    // Accessors for forward references caching.
 193  m :    bool CacheUserDefinedTypeForwardDeclaration(TypeId fwd_id, TypeId class_id);
 194  m :    TypeId LookupConcreteClassForForwardDeclaration(TypeId type_id);
 195    :  
 196    :    // @returns name for a basic type specified by its @p type.
 197  m :    static base::string16 BasicTypeName(size_t type);
 198    :  
 199    :    // @returns size for a basic type specified by its @p type.
 200  m :    static size_t BasicTypeSize(size_t type);
 201    :  
 202    :    // @returns name for a leaf specified by its @p type.
 203  m :    static base::string16 LeafTypeName(size_t type);
 204    :  
 205    :    // @returns size of a pointer given its @p ptr type info record.
 206  m :    static size_t PointerSize(const pdb::LeafPointer& ptr);
 207    :  
 208    :    // Computes size of a pointer to member function or data.
 209    :    // @param pmtype CV_pmtype field of the pointer.
 210    :    // @param ptrtype CV_ptrtype field of the pointer.
 211    :    // @returns size of a member field pointer.
 212  m :    static size_t MemberPointerSize(cci::CV_pmtype pmtype,
 213  m :                                    cci::CV_ptrtype ptrtype);
 214    :  
 215    :    // Pulls CV_prmode out of basic type index.
 216    :    // @param type_id type index of a basic type.
 217    :    // @returns the CV_prmode field.
 218  m :    static cci::CV_prmode TypeIndexToPrMode(TypeId type_id);
 219    :  
 220    :    // Construct string of CV modifiers.
 221    :    // @param is_const true if type is const.
 222    :    // @param is_volatile true if type is volatile.
 223    :    // @returns the string of CV modifiers.
 224  m :    static base::string16 GetCVMod(bool is_const, bool is_volatile);
 225    :  
 226    :    // Creates Type::Flags from the individual bool values.
 227    :    // @param is_const true if type is const.
 228    :    // @param is_volatile true if type is volatile.
 229    :    // @returns type flags.
 230  m :    static Type::Flags CreateTypeFlags(bool is_const, bool is_volatile);
 231    :  
 232    :    // Checks if the type gets translated to a type repository.
 233    :    // @param type the type of this record.
 234    :    // @returns true if this record gets translated to the repository.
 235  m :    static bool IsImportantType(uint32_t type);
 236    :  
 237    :    // Checks if this is actually pointer encoded in basic type index.
 238    :    // @param type_id type index of the record.
 239    :    // @returns true if the record is pointer.
 240  m :    bool IsBasicPointerType(TypeId type_id);
 241    :  
 242    :    // Pointer to the type info repository.
 243  m :    TypeRepository* repository_;
 244    :  
 245    :    // Type info enumerator used to traverse the stream.
 246  m :    pdb::TypeInfoEnumerator type_info_enum_;
 247    :  
 248    :    // Hash to map forward references to the right UDT records. For each unique
 249    :    // decorated name of an UDT, it contains type index of the class definition.
 250  m :    std::unordered_map<base::string16, TypeId> udt_map_;
 251    :  
 252    :    // Hash to store the pdb leaf types of the individual records. Indexed by type
 253    :    // indices.
 254  m :    std::unordered_map<TypeId, uint16_t> types_map_;
 255    :  
 256    :    // Hash which stores for each forward declaration the type index of the
 257    :    // actual class type.
 258  m :    std::unordered_map<TypeId, TypeId> fwd_reference_map_;
 259    :  
 260    :    // Vector of records to process.
 261  m :    std::vector<TypeId> records_to_process_;
 262  m :  };
 263    :  
 264  m :  TypePtr TypeCreator::CreatePointerType(TypeId type_id) {
 265  m :    DCHECK_EQ(GetLeafType(type_id), cci::LF_POINTER);
 266    :  
 267  m :    if (!type_info_enum_.SeekRecord(type_id))
 268  m :      return nullptr;
 269    :  
 270  m :    pdb::TypeInfoEnumerator::BinaryTypeRecordReader reader(
 271  m :        type_info_enum_.CreateRecordReader());
 272  m :    common::BinaryStreamParser parser(&reader);
 273  m :    pdb::LeafPointer type_info;
 274  m :    if (!type_info.Initialize(&parser)) {
 275  m :      LOG(ERROR) << "Unable to read type info record.";
 276  m :      return nullptr;
 277  m :    }
 278    :  
 279    :    // Save type information.
 280  m :    size_t size = PointerSize(type_info);
 281  m :    PointerType::Mode ptr_mode = PointerType::PTR_MODE_PTR;
 282  m :    if (type_info.attr().ptrmode == cci::CV_PTR_MODE_REF)
 283  m :      ptr_mode = PointerType::PTR_MODE_REF;
 284    :  
 285  m :    PointerTypePtr created = new PointerType(size, ptr_mode);
 286  m :    if (!repository_->AddTypeWithId(created, type_id))
 287  m :      return nullptr;
 288    :  
 289    :    // Try to find the object in the repository.
 290  m :    TypeId pointee_id = type_info.body().utype;
 291  m :    Type::Flags pointee_flags = kNoTypeFlags;
 292  m :    TypePtr pointee_type = FindOrCreatePointableType(pointee_id, &pointee_flags);
 293  m :    if (pointee_type == nullptr)
 294  m :      return nullptr;
 295    :  
 296    :    // Setting the flags from the child node - this is needed because of
 297    :    // different semantics between PDB file and Type interface. In PDB pointer
 298    :    // has a const flag when it's const, while here pointer has a const flag if
 299    :    // it points to a const type.
 300  m :    created->Finalize(pointee_flags, pointee_type->type_id());
 301  m :    return created;
 302  m :  }
 303    :  
 304  m :  TypePtr TypeCreator::CreateBasicPointerType(TypeId type_id) {
 305  m :    DCHECK(IsBasicPointerType(type_id));
 306  m :    TypeId basic_index = type_id & (cci::CV_PRIMITIVE_TYPE::CV_TMASK |
 307  m :                                    cci::CV_PRIMITIVE_TYPE::CV_SMASK);
 308  m :    if (FindOrCreateBasicType(basic_index) == nullptr)
 309  m :      return nullptr;
 310    :  
 311    :    // Get pointer size.
 312  m :    size_t size = 0;
 313  m :    cci::CV_prmode prmode = TypeIndexToPrMode(type_id);
 314  m :    switch (prmode) {
 315  m :      case cci::CV_TM_NPTR32:
 316  m :        size = 4;
 317  m :        break;
 318  m :      case cci::CV_TM_NPTR64:
 319  m :        size = 8;
 320  m :        break;
 321  m :      case cci::CV_TM_NPTR128:
 322  m :        size = 16;
 323  m :        break;
 324  m :      default:
 325  m :        return nullptr;
 326  m :    }
 327    :  
 328    :    // Create and finalize type.
 329  m :    PointerTypePtr pointer_type =
 330  m :        new PointerType(size, PointerType::PTR_MODE_PTR);
 331  m :    pointer_type->Finalize(kNoTypeFlags, basic_index);
 332    :  
 333  m :    if (!repository_->AddTypeWithId(pointer_type, type_id))
 334  m :      return nullptr;
 335  m :    return pointer_type;
 336  m :  }
 337    :  
 338  m :  TypePtr TypeCreator::ReadPointer(TypeId type_id, Type::Flags* flags) {
 339  m :    DCHECK(flags);
 340  m :    DCHECK_EQ(GetLeafType(type_id), cci::LF_POINTER);
 341    :  
 342  m :    if (!type_info_enum_.SeekRecord(type_id))
 343  m :      return nullptr;
 344    :  
 345  m :    pdb::TypeInfoEnumerator::BinaryTypeRecordReader reader(
 346  m :        type_info_enum_.CreateRecordReader());
 347  m :    common::BinaryStreamParser parser(&reader);
 348  m :    pdb::LeafPointer type_info;
 349  m :    if (!type_info.Initialize(&parser)) {
 350  m :      LOG(ERROR) << "Unable to read type info record.";
 351  m :      return nullptr;
 352  m :    }
 353    :  
 354  m :    *flags =
 355  m :        CreateTypeFlags(type_info.attr().isconst, type_info.attr().isvolatile);
 356    :  
 357  m :    return FindOrCreateSpecificType(type_info_enum_.type_id(), cci::LF_POINTER);
 358  m :  }
 359    :  
 360  m :  TypePtr TypeCreator::ReadModifier(TypeId type_id, Type::Flags* flags) {
 361  m :    DCHECK(flags);
 362  m :    DCHECK_EQ(GetLeafType(type_id), cci::LF_MODIFIER);
 363    :  
 364  m :    if (!type_info_enum_.SeekRecord(type_id))
 365  m :      return nullptr;
 366    :  
 367  m :    pdb::TypeInfoEnumerator::BinaryTypeRecordReader reader(
 368  m :        type_info_enum_.CreateRecordReader());
 369  m :    common::BinaryStreamParser parser(&reader);
 370  m :    pdb::LeafModifier type_info;
 371  m :    if (!type_info.Initialize(&parser)) {
 372  m :      LOG(ERROR) << "Unable to read type info record.";
 373  m :      return nullptr;
 374  m :    }
 375    :  
 376  m :    TypePtr underlying_type = FindOrCreateModifiableType(type_info.body().type);
 377  m :    if (underlying_type == nullptr)
 378  m :      return nullptr;
 379    :  
 380  m :    *flags = CreateTypeFlags(type_info.attr().mod_const,
 381  m :                             type_info.attr().mod_volatile);
 382  m :    return underlying_type;
 383  m :  }
 384    :  
 385  m :  bool TypeCreator::ReadFieldlist(TypeId type_id,
 386  m :                                  UserDefinedType::Fields* fields,
 387  m :                                  UserDefinedType::Functions* functions) {
 388  m :    DCHECK(fields);
 389  m :    DCHECK(functions);
 390  m :    DCHECK_EQ(GetLeafType(type_id), cci::LF_FIELDLIST);
 391    :  
 392  m :    if (!type_info_enum_.SeekRecord(type_id))
 393  m :      return false;
 394    :  
 395    :    // Grab the leaf size, as sub-parsing moves the enumerator.
 396  m :    size_t leaf_size = type_info_enum_.len();
 397  m :    pdb::TypeInfoEnumerator::BinaryTypeRecordReader local_reader(
 398  m :        type_info_enum_.CreateRecordReader());
 399  m :    common::BinaryStreamParser local_parser(&local_reader);
 400  m :    while (local_reader.Position() < leaf_size) {
 401  m :      uint16_t leaf_type = 0;
 402  m :      if (!local_parser.Read(&leaf_type)) {
 403  m :        LOG(ERROR) << "Unable to read the type of a list field.";
 404  m :        return false;
 405  m :      }
 406    :  
 407  m :      switch (leaf_type) {
 408  m :        case cci::LF_MEMBER: {
 409  m :          pdb::LeafMember type_info;
 410  m :          if (!type_info.Initialize(&local_parser) ||
 411  m :              !ProcessMember(&type_info, fields)) {
 412  m :            return false;
 413  m :          }
 414  m :          break;
 415  m :        }
 416  m :        case cci::LF_BCLASS: {
 417  m :          pdb::LeafBClass type_info;
 418  m :          if (!type_info.Initialize(&local_parser) ||
 419  m :              !ProcessBClass(&type_info, fields)) {
 420  m :            return false;
 421  m :          }
 422  m :          break;
 423  m :        }
 424  m :        case cci::LF_VBCLASS:
 425  m :        case cci::LF_IVBCLASS: {
 426  m :          pdb::LeafVBClass type_info;
 427  m :          if (!type_info.Initialize(&local_parser))
 428  m :            return false;
 429  m :          break;
 430  m :        }
 431  m :        case cci::LF_ENUMERATE: {
 432  m :          pdb::LeafEnumerate type_info;
 433  m :          if (!type_info.Initialize(&local_parser))
 434  m :            return false;
 435  m :          break;
 436  m :        }
 437  m :        case cci::LF_FRIENDFCN: {
 438  m :          pdb::LeafFriendFcn type_info;
 439  m :          if (!type_info.Initialize(&local_parser))
 440  m :            return false;
 441  m :          break;
 442  m :        }
 443  m :        case cci::LF_STMEMBER: {
 444  m :          pdb::LeafSTMember type_info;
 445  m :          if (!type_info.Initialize(&local_parser))
 446  m :            return false;
 447  m :          break;
 448  m :        }
 449  m :        case cci::LF_METHOD: {
 450  m :          pdb::LeafMethod type_info;
 451  m :          if (!type_info.Initialize(&local_parser) ||
 452  m :              !ProcessMethod(&type_info, functions)) {
 453  m :            return false;
 454  m :          }
 455  m :          break;
 456  m :        }
 457  m :        case cci::LF_NESTTYPE: {
 458  m :          pdb::LeafNestType type_info;
 459  m :          if (!type_info.Initialize(&local_parser))
 460  m :            return false;
 461  m :          break;
 462  m :        }
 463  m :        case cci::LF_VFUNCTAB: {
 464  m :          pdb::LeafVFuncTab type_info;
 465  m :          if (!type_info.Initialize(&local_parser) ||
 466  m :              !ProcessVFuncTab(&type_info, fields))
 467  m :            return false;
 468  m :          break;
 469  m :        }
 470  m :        case cci::LF_FRIENDCLS: {
 471  m :          pdb::LeafFriendCls type_info;
 472  m :          if (!type_info.Initialize(&local_parser))
 473  m :            return false;
 474  m :          break;
 475  m :        }
 476  m :        case cci::LF_ONEMETHOD: {
 477  m :          pdb::LeafOneMethod type_info;
 478  m :          if (!type_info.Initialize(&local_parser) ||
 479  m :              !ProcessOneMethod(&type_info, functions)) {
 480  m :            return false;
 481  m :          }
 482  m :          break;
 483  m :        }
 484  m :        case cci::LF_VFUNCOFF: {
 485  m :          pdb::LeafVFuncOff type_info;
 486  m :          if (!type_info.Initialize(&local_parser) ||
 487  m :              !ProcessVFuncOff(&type_info, fields))
 488  m :            return false;
 489  m :          break;
 490  m :        }
 491  m :        case cci::LF_INDEX: {
 492  m :          pdb::LeafIndex type_info;
 493  m :          if (!type_info.Initialize(&local_parser))
 494  m :            return false;
 495    :          // This is always the last record of the fieldlist.
 496    :          // TODO(manzagop): ask siggi@ if he thinks this optimization is wise.
 497  m :          return ReadFieldlist(type_info.body().index, fields, functions);
 498  m :        }
 499  m :        default: {
 500  m :          NOTREACHED();
 501  m :          break;
 502  m :        }
 503  m :      }
 504    :      // The records are aligned to a 4 byte boundary.
 505  m :      const size_t kRecordAlignment = 4;
 506  m :      size_t align = local_reader.Position() % kRecordAlignment;
 507  m :      if (align > 0)
 508  m :        local_reader.Consume(kRecordAlignment - align);
 509    :  
 510  m :      DCHECK_EQ(0U, local_reader.Position() % kRecordAlignment);
 511  m :    }
 512  m :    return true;
 513  m :  }
 514    :  
 515  m :  bool TypeCreator::ReadArglist(TypeId type_id,
 516  m :                                FunctionType::Arguments* arglist) {
 517  m :    DCHECK(arglist);
 518  m :    DCHECK_EQ(GetLeafType(type_id), cci::LF_ARGLIST);
 519    :  
 520  m :    if (!type_info_enum_.SeekRecord(type_id))
 521  m :      return false;
 522    :  
 523  m :    pdb::TypeInfoEnumerator::BinaryTypeRecordReader reader(
 524  m :        type_info_enum_.CreateRecordReader());
 525  m :    common::BinaryStreamParser parser(&reader);
 526    :  
 527  m :    uint32_t num_args = 0;
 528  m :    if (!parser.Read(&num_args))
 529  m :      return false;
 530    :  
 531  m :    while (arglist->size() < num_args) {
 532  m :      uint32_t arg_type_id = 0;
 533  m :      if (!parser.Read(&arg_type_id)) {
 534  m :        LOG(ERROR) << "Unable to read the type index of an argument.";
 535  m :        return false;
 536  m :      }
 537    :  
 538  m :      Type::Flags flags = kNoTypeFlags;
 539  m :      TypePtr arg_type = FindOrCreateOptionallyModifiedType(arg_type_id, &flags);
 540  m :      if (arg_type == nullptr)
 541  m :        return false;
 542    :  
 543  m :      arglist->push_back(FunctionType::ArgumentType(flags, arg_type->type_id()));
 544  m :    }
 545  m :    return true;
 546  m :  }
 547    :  
 548  m :  TypePtr TypeCreator::CreateUserDefinedType(TypeId type_id) {
 549  m :    DCHECK(GetLeafType(type_id) == cci::LF_CLASS ||
 550  m :           GetLeafType(type_id) == cci::LF_STRUCTURE ||
 551  m :           GetLeafType(type_id) == cci::LF_UNION);
 552    :  
 553  m :    if (!type_info_enum_.SeekRecord(type_id))
 554  m :      return nullptr;
 555    :  
 556    :    // Read the values from the PDB records.
 557  m :    LeafPropertyField property = {};
 558  m :    TypeId fieldlist_id = kNoTypeId;
 559  m :    uint64_t size = 0;
 560  m :    base::string16 name;
 561  m :    base::string16 decorated_name;
 562    :  
 563  m :    pdb::TypeInfoEnumerator::BinaryTypeRecordReader reader(
 564  m :        type_info_enum_.CreateRecordReader());
 565  m :    common::BinaryStreamParser parser(&reader);
 566  m :    if (type_info_enum_.type() == cci::LF_CLASS ||
 567  m :        type_info_enum_.type() == cci::LF_STRUCTURE) {
 568  m :      pdb::LeafClass type_info;
 569  m :      if (!type_info.Initialize(&parser)) {
 570  m :        LOG(ERROR) << "Unable to read type info record.";
 571  m :        return nullptr;
 572  m :      }
 573  m :      property = type_info.property();
 574  m :      fieldlist_id = type_info.body().field;
 575  m :      size = type_info.size();
 576  m :      name = type_info.name();
 577  m :      decorated_name = type_info.decorated_name();
 578  m :    } else if (type_info_enum_.type() == cci::LF_UNION) {
 579  m :      pdb::LeafUnion type_info;
 580  m :      if (!type_info.Initialize(&parser)) {
 581  m :        LOG(ERROR) << "Unable to read type info record.";
 582  m :        return nullptr;
 583  m :      }
 584  m :      property = type_info.property();
 585  m :      fieldlist_id = type_info.body().field;
 586  m :      size = type_info.size();
 587  m :      name = type_info.name();
 588  m :      decorated_name = type_info.decorated_name();
 589  m :    }
 590    :  
 591    :    // Set the correct UDT kind.
 592  m :    UserDefinedType::UdtKind udt_kind = UserDefinedType::UDT_CLASS;
 593  m :    switch (type_info_enum_.type()) {
 594  m :      case cci::LF_CLASS: {
 595  m :        udt_kind = UserDefinedType::UDT_CLASS;
 596  m :        break;
 597  m :      }
 598  m :      case cci::LF_STRUCTURE: {
 599  m :        udt_kind = UserDefinedType::UDT_STRUCT;
 600  m :        break;
 601  m :      }
 602  m :      case cci::LF_UNION: {
 603  m :        udt_kind = UserDefinedType::UDT_UNION;
 604  m :        break;
 605  m :      }
 606  m :    }
 607    :  
 608  m :    if (property.fwdref) {
 609    :      // Find the type index of the UDT.
 610  m :      auto real_class_id = udt_map_.find(decorated_name);
 611  m :      if (real_class_id == udt_map_.end()) {
 612    :        // This is a forward reference without real UDT record.
 613  m :        UserDefinedTypePtr udt =
 614  m :            new UserDefinedType(name, decorated_name, size, udt_kind);
 615  m :        udt->SetIsForwardDeclaration();
 616  m :        if (!repository_->AddTypeWithId(udt, type_id))
 617  m :          return nullptr;
 618  m :        return udt;
 619  m :      }
 620    :  
 621    :      // Cache redirection to the real UDT.
 622  m :      if (!CacheUserDefinedTypeForwardDeclaration(type_id, real_class_id->second))
 623  m :        return nullptr;
 624    :  
 625    :      // Force parsing of the UDT.
 626  m :      return FindOrCreateSpecificType(real_class_id->second,
 627  m :                                      type_info_enum_.type());
 628  m :    } else {
 629    :      // Create UDT of the class and find its fieldlist.
 630  m :      UserDefinedTypePtr udt =
 631  m :          new UserDefinedType(name, decorated_name, size, udt_kind);
 632  m :      if (!repository_->AddTypeWithId(udt, type_id))
 633  m :        return nullptr;
 634    :  
 635  m :      UserDefinedType::Fields fieldlist;
 636  m :      UserDefinedType::Functions functionlist;
 637  m :      if (!ReadFieldlist(fieldlist_id, &fieldlist, &functionlist))
 638  m :        return false;
 639    :  
 640  m :      udt->Finalize(&fieldlist, &functionlist);
 641  m :      return udt;
 642  m :    }
 643  m :  }
 644    :  
 645  m :  TypePtr TypeCreator::CreateArrayType(TypeId type_id) {
 646  m :    DCHECK_EQ(GetLeafType(type_id), cci::LF_ARRAY);
 647    :  
 648  m :    if (!type_info_enum_.SeekRecord(type_id))
 649  m :      return nullptr;
 650    :  
 651  m :    pdb::TypeInfoEnumerator::BinaryTypeRecordReader reader(
 652  m :        type_info_enum_.CreateRecordReader());
 653  m :    common::BinaryStreamParser parser(&reader);
 654  m :    pdb::LeafArray type_info;
 655  m :    if (!type_info.Initialize(&parser)) {
 656  m :      LOG(ERROR) << "Unable to read type info record.";
 657  m :      return nullptr;
 658  m :    }
 659    :  
 660  m :    ArrayTypePtr array_type = new ArrayType(type_info.size());
 661  m :    if (!repository_->AddTypeWithId(array_type, type_id))
 662  m :      return nullptr;
 663    :  
 664    :    // Find the types in the repository.
 665  m :    Type::Flags flags = kNoTypeFlags;
 666  m :    TypeId index_id = type_info.body().idxtype;
 667  m :    TypeId elem_id = type_info.body().elemtype;
 668  m :    TypePtr index_type = FindOrCreateIndexingType(index_id);
 669  m :    TypePtr elem_type = FindOrCreateOptionallyModifiedType(elem_id, &flags);
 670  m :    if (index_type == nullptr || elem_type == nullptr)
 671  m :      return nullptr;
 672    :  
 673  m :    size_t num_elements = 0;
 674    :    // TODO(mopler): Once we load everything test against the size not being zero.
 675  m :    if (elem_type->size() != 0)
 676  m :      num_elements = type_info.size() / elem_type->size();
 677  m :    array_type->Finalize(flags, index_type->type_id(), num_elements,
 678  m :                         elem_type->type_id());
 679  m :    return array_type;
 680  m :  }
 681    :  
 682  m :  TypePtr TypeCreator::CreateFunctionType(TypeId type_id) {
 683  m :    DCHECK(GetLeafType(type_id) == cci::LF_PROCEDURE ||
 684  m :           GetLeafType(type_id) == cci::LF_MFUNCTION);
 685    :  
 686  m :    if (!type_info_enum_.SeekRecord(type_id))
 687  m :      return nullptr;
 688    :  
 689  m :    FunctionType::CallConvention call_convention;
 690  m :    TypeId return_type_id = kNoTypeId;
 691  m :    TypeId containing_class_id = kNoTypeId;
 692  m :    TypeId arglist_id = kNoTypeId;
 693    :  
 694  m :    pdb::TypeInfoEnumerator::BinaryTypeRecordReader reader(
 695  m :        type_info_enum_.CreateRecordReader());
 696  m :    common::BinaryStreamParser parser(&reader);
 697  m :    if (type_info_enum_.type() == cci::LF_PROCEDURE) {
 698    :      // Load the procedure record.
 699  m :      pdb::LeafProcedure type_info;
 700  m :      if (!type_info.Initialize(&parser)) {
 701  m :        LOG(ERROR) << "Unable to read type info record.";
 702  m :        return nullptr;
 703  m :      }
 704    :  
 705  m :      call_convention =
 706  m :          static_cast<FunctionType::CallConvention>(type_info.body().calltype);
 707  m :      return_type_id = type_info.body().rvtype;
 708  m :      arglist_id = type_info.body().arglist;
 709  m :    } else if (type_info_enum_.type() == cci::LF_MFUNCTION) {
 710    :      // Load the member function record.
 711  m :      pdb::LeafMFunction type_info;
 712  m :      if (!type_info.Initialize(&parser)) {
 713  m :        LOG(ERROR) << "Unable to read type info record.";
 714  m :        return nullptr;
 715  m :      }
 716    :  
 717  m :      call_convention =
 718  m :          static_cast<FunctionType::CallConvention>(type_info.body().calltype);
 719  m :      return_type_id = type_info.body().rvtype;
 720  m :      arglist_id = type_info.body().arglist;
 721  m :      containing_class_id = type_info.body().classtype;
 722  m :    } else {
 723  m :      return nullptr;
 724  m :    }
 725    :  
 726  m :    FunctionTypePtr function_type = new FunctionType(call_convention);
 727  m :    if (!repository_->AddTypeWithId(function_type, type_id))
 728  m :      return nullptr;
 729    :  
 730  m :    Type::Flags flags = kNoTypeFlags;
 731  m :    TypePtr return_type =
 732  m :        FindOrCreateOptionallyModifiedType(return_type_id, &flags);
 733  m :    if (return_type == nullptr)
 734  m :      return nullptr;
 735    :  
 736    :    // If this is a member function parse the containing class.
 737  m :    if (containing_class_id != kNoTypeId &&
 738  m :        containing_class_id != cci::T_NOTYPE) {
 739  m :      TypePtr class_type = FindOrCreateStructuredType(containing_class_id);
 740  m :      if (class_type == nullptr)
 741  m :        return nullptr;
 742    :  
 743  m :      containing_class_id = class_type->type_id();
 744  m :    }
 745    :  
 746    :    // Parse the argument list.
 747  m :    FunctionType::Arguments arglist;
 748  m :    if (!ReadArglist(arglist_id, &arglist))
 749  m :      return nullptr;
 750    :  
 751  m :    function_type->Finalize(
 752  m :        FunctionType::ArgumentType(flags, return_type->type_id()), arglist,
 753  m :        containing_class_id);
 754  m :    return function_type;
 755  m :  }
 756    :  
 757  m :  TypePtr TypeCreator::ReadBitfield(TypeId type_id,
 758  m :                                    Type::Flags* flags,
 759  m :                                    size_t* bit_pos,
 760  m :                                    size_t* bit_len) {
 761  m :    DCHECK(flags);
 762  m :    DCHECK(bit_pos);
 763  m :    DCHECK(bit_len);
 764  m :    DCHECK(GetLeafType(type_id) == cci::LF_BITFIELD);
 765    :  
 766  m :    if (!type_info_enum_.SeekRecord(type_id))
 767  m :      return nullptr;
 768    :  
 769  m :    pdb::TypeInfoEnumerator::BinaryTypeRecordReader reader(
 770  m :        type_info_enum_.CreateRecordReader());
 771  m :    common::BinaryStreamParser parser(&reader);
 772  m :    pdb::LeafBitfield type_info;
 773  m :    if (!type_info.Initialize(&parser)) {
 774  m :      LOG(ERROR) << "Unable to read type info record.";
 775  m :      return nullptr;
 776  m :    }
 777    :  
 778  m :    const size_t kMaxBitfieldValue = 63;
 779  m :    if (type_info.body().position > kMaxBitfieldValue ||
 780  m :        type_info.body().length > kMaxBitfieldValue) {
 781  m :      LOG(ERROR) << "The bit position or length of bitfield is too large.";
 782  m :      return nullptr;
 783  m :    }
 784    :  
 785  m :    *bit_pos = type_info.body().position;
 786  m :    *bit_len = type_info.body().length;
 787    :  
 788  m :    TypeId underlying_id = type_info.body().type;
 789  m :    *flags = kNoTypeFlags;
 790    :  
 791  m :    return FindOrCreateBitfieldType(underlying_id, flags);
 792  m :  }
 793    :  
 794  m :  TypeCreator::TypeCreator(TypeRepository* repository, pdb::PdbStream* stream)
 795  m :      : type_info_enum_(stream), repository_(repository) {
 796  m :    DCHECK(repository);
 797  m :    DCHECK(stream);
 798  m :  }
 799    :  
 800  m :  TypeCreator::~TypeCreator() {
 801  m :  }
 802    :  
 803  m :  bool TypeCreator::ProcessBClass(pdb::LeafBClass* bclass,
 804  m :                                  UserDefinedType::Fields* fields) {
 805  m :    DCHECK(bclass);
 806  m :    DCHECK(fields);
 807    :  
 808    :    // Ensure the base class' type is created.
 809  m :    TypeId bclass_id = bclass->body().index;
 810  m :    TypePtr bclass_type = FindOrCreateInheritableType(bclass_id);
 811  m :    if (bclass_type == nullptr)
 812  m :      return false;
 813    :  
 814  m :    fields->push_back(new UserDefinedType::BaseClassField(
 815  m :        bclass->offset(), bclass_type->type_id(), repository_));
 816    :  
 817  m :    return true;
 818  m :  }
 819    :  
 820  m :  bool TypeCreator::ProcessMember(pdb::LeafMember* member,
 821  m :                                  UserDefinedType::Fields* fields) {
 822  m :    DCHECK(member);
 823  m :    DCHECK(fields);
 824    :  
 825    :    // TODO(mopler): Should we store the access protection and other info?
 826    :    // Get the member info.
 827  m :    TypeId member_id = member->body().index;
 828  m :    Type::Flags flags = kNoTypeFlags;
 829  m :    size_t bit_pos = 0;
 830  m :    size_t bit_len = 0;
 831  m :    TypePtr member_type =
 832  m :        FindOrCreateMemberType(member_id, &flags, &bit_pos, &bit_len);
 833  m :    if (member_type == nullptr)
 834  m :      return false;
 835    :  
 836  m :    fields->push_back(new UserDefinedType::MemberField(
 837  m :        member->name(), member->offset(), flags, bit_pos, bit_len,
 838  m :        member_type->type_id(), repository_));
 839  m :    return true;
 840  m :  }
 841    :  
 842  m :  bool TypeCreator::ProcessOneMethod(pdb::LeafOneMethod* method,
 843  m :                                     UserDefinedType::Functions* functions) {
 844  m :    DCHECK(method);
 845  m :    DCHECK(functions);
 846    :  
 847    :    // Parse the function type.
 848  m :    TypeId function_id = method->body().index;
 849  m :    if (FindOrCreateSpecificType(function_id, cci::LF_MFUNCTION) == nullptr)
 850  m :      return false;
 851    :  
 852  m :    functions->push_back(UserDefinedType::Function(method->name(), function_id));
 853  m :    return true;
 854  m :  }
 855    :  
 856  m :  bool TypeCreator::ProcessMethod(pdb::LeafMethod* method,
 857  m :                                  UserDefinedType::Functions* functions) {
 858  m :    DCHECK(method);
 859  m :    DCHECK(functions);
 860    :  
 861    :    // Seek the method list record.
 862  m :    if (!type_info_enum_.SeekRecord(method->body().mList) ||
 863  m :        type_info_enum_.type() != cci::LF_METHODLIST) {
 864  m :      return false;
 865  m :    }
 866    :  
 867  m :    pdb::TypeInfoEnumerator::BinaryTypeRecordReader reader(
 868  m :        type_info_enum_.CreateRecordReader());
 869  m :    common::BinaryStreamParser parser(&reader);
 870    :  
 871  m :    uint16_t count = method->body().count;
 872  m :    while (count > 0) {
 873  m :      pdb::MethodListRecord method_record;
 874  m :      if (!method_record.Initialize(&parser)) {
 875  m :        LOG(ERROR) << "Unable to read method list record.";
 876  m :        return false;
 877  m :      }
 878    :  
 879    :      // Parse the function type.
 880  m :      TypeId function_id = method_record.body().index;
 881  m :      if (FindOrCreateSpecificType(function_id, cci::LF_MFUNCTION) == nullptr)
 882  m :        return false;
 883    :  
 884  m :      functions->push_back(
 885  m :          UserDefinedType::Function(method->name(), function_id));
 886    :  
 887  m :      count--;
 888  m :    }
 889  m :    return true;
 890  m :  }
 891    :  
 892  m :  bool TypeCreator::ProcessVFunc(
 893  m :      TypeId id, ptrdiff_t offset, UserDefinedType::Fields* fields) {
 894  m :    DCHECK(fields);
 895    :  
 896    :    // Virtual function pointer fields have as type a pointer type to a virtual
 897    :    // table shape.
 898  m :    TypePtr type = FindOrCreateSpecificType(id, cci::LF_POINTER);
 899  m :    if (type == nullptr)
 900  m :      return false;
 901    :  
 902    :    // Validate the pointer type's content type is a vtable shape.
 903  m :    PointerTypePtr ptr_type;
 904  m :    if (!type->CastTo(&ptr_type))
 905  m :      return false;
 906  m :    DCHECK(ptr_type);
 907  m :    TypePtr content_type = ptr_type->GetContentType();
 908  m :    DCHECK(content_type);
 909    :    // TODO(manzagop): update once virtual tables have their own type.
 910  m :    if (content_type->kind() != Type::WILDCARD_TYPE_KIND)
 911  m :      return false;
 912    :  
 913  m :    fields->push_back(
 914  m :        new UserDefinedType::VfptrField(offset, type->type_id(), repository_));
 915    :  
 916  m :    return true;
 917  m :  }
 918    :  
 919  m :  bool TypeCreator::ProcessVFuncOff(pdb::LeafVFuncOff* vfunc,
 920  m :                                    UserDefinedType::Fields* fields) {
 921  m :    DCHECK(vfunc);
 922  m :    DCHECK(fields);
 923  m :    return ProcessVFunc(vfunc->body().type, vfunc->body().offset, fields);
 924  m :  }
 925    :  
 926  m :  bool TypeCreator::ProcessVFuncTab(pdb::LeafVFuncTab* vfunc,
 927  m :                                    UserDefinedType::Fields* fields) {
 928  m :    DCHECK(vfunc);
 929  m :    DCHECK(fields);
 930  m :    return ProcessVFunc(vfunc->body().type, 0, fields);
 931  m :  }
 932    :  
 933  m :  base::string16 TypeCreator::BasicTypeName(size_t type) {
 934  m :    switch (type) {
 935    :  // Just return the name of the type.
 936    :  #define SPECIAL_TYPE_NAME(record_type, type_name, size) \
 937  m :    case cci::record_type: return L#type_name;
 938  m :      SPECIAL_TYPE_NAME_CASE_TABLE(SPECIAL_TYPE_NAME)
 939    :  #undef SPECIAL_TYPE_NAME
 940  m :    }
 941  m :    return L"unknown_basic_type";
 942  m :  }
 943    :  
 944  m :  size_t TypeCreator::BasicTypeSize(size_t type) {
 945  m :    switch (type) {
 946    :  // Just return the size of the type.
 947    :  #define SPECIAL_TYPE_NAME(record_type, type_name, size) \
 948  m :    case cci::record_type: return size;
 949  m :      SPECIAL_TYPE_NAME_CASE_TABLE(SPECIAL_TYPE_NAME)
 950    :  #undef SPECIAL_TYPE_NAME
 951  m :    }
 952  m :    return 0;
 953  m :  }
 954    :  
 955  m :  base::string16 TypeCreator::LeafTypeName(size_t leaf_type) {
 956  m :    switch (leaf_type) {
 957    :  // Just return the name of the enum.
 958    :  #define LEAF_TYPE_NAME(record_type, unused) \
 959  m :    case cci::record_type: {                  \
 960  m :      return L#record_type;                   \
 961  m :    }
 962  m :      LEAF_CASE_TABLE(LEAF_TYPE_NAME)
 963    :  #undef LEAF_TYPE_NAME
 964  m :      default:
 965  m :        return L"UnknownLeaf";
 966  m :    }
 967  m :  }
 968    :  
 969  m :  size_t TypeCreator::PointerSize(const pdb::LeafPointer& ptr) {
 970  m :    size_t size = 0;
 971  m :    const cci::CV_ptrtype ptrtype =
 972  m :        static_cast<cci::CV_ptrtype>(ptr.attr().ptrtype);
 973    :    // Set the size of the pointer.
 974  m :    switch (ptr.attr().ptrmode) {
 975    :      // The size of a regular pointer or reference can be deduced from its type.
 976    :      // TODO(mopler): Investigate references.
 977  m :      case cci::CV_PTR_MODE_PTR:
 978  m :      case cci::CV_PTR_MODE_REF: {
 979  m :        if (ptrtype == cci::CV_PTR_NEAR32)
 980  m :          size = 4;
 981  m :        else if (ptrtype == cci::CV_PTR_64)
 982  m :          size = 8;
 983  m :        break;
 984  m :      }
 985    :      // However in case of a member field pointer, its size depends on the
 986    :      // properties of the containing class. The pointer contains extra
 987    :      // information about the containing class.
 988  m :      case cci::CV_PTR_MODE_PMFUNC:
 989  m :      case cci::CV_PTR_MODE_PMEM: {
 990  m :        const cci::CV_pmtype pmtype = static_cast<cci::CV_pmtype>(ptr.pmtype());
 991  m :        size = MemberPointerSize(pmtype, ptrtype);
 992  m :        break;
 993  m :      }
 994  m :    }
 995  m :    return size;
 996  m :  }
 997    :  
 998  m :  size_t TypeCreator::MemberPointerSize(cci::CV_pmtype pmtype,
 999  m :                                        cci::CV_ptrtype ptrtype) {
1000  m :    DCHECK(ptrtype == cci::CV_PTR_NEAR32 || ptrtype == cci::CV_PTR_64);
1001    :  
1002    :    // The translation of modes to pointer sizes depends on the compiler. The
1003    :    // following values have been determined experimentally. For details see
1004    :    // https://github.com/google/syzygy/wiki/MemberPointersInPdbFiles.
1005  m :    if (ptrtype == cci::CV_PTR_NEAR32) {
1006  m :      switch (pmtype) {
1007  m :        case cci::CV_PMTYPE_Undef:
1008  m :          return 0;
1009  m :        case cci::CV_PMTYPE_D_Single:
1010  m :          return 4;
1011  m :        case cci::CV_PMTYPE_D_Multiple:
1012  m :          return 4;
1013  m :        case cci::CV_PMTYPE_D_Virtual:
1014  m :          return 8;
1015  m :        case cci::CV_PMTYPE_D_General:
1016  m :          return 12;
1017  m :        case cci::CV_PMTYPE_F_Single:
1018  m :          return 4;
1019  m :        case cci::CV_PMTYPE_F_Multiple:
1020  m :          return 8;
1021  m :        case cci::CV_PMTYPE_F_Virtual:
1022  m :          return 12;
1023  m :        case cci::CV_PMTYPE_F_General:
1024  m :          return 16;
1025  m :      }
1026  m :    } else if (ptrtype == cci::CV_PTR_64) {
1027  m :      switch (pmtype) {
1028  m :        case cci::CV_PMTYPE_Undef:
1029  m :          return 0;
1030  m :        case cci::CV_PMTYPE_D_Single:
1031  m :          return 4;
1032  m :        case cci::CV_PMTYPE_D_Multiple:
1033  m :          return 4;
1034  m :        case cci::CV_PMTYPE_D_Virtual:
1035  m :          return 8;
1036  m :        case cci::CV_PMTYPE_D_General:
1037  m :          return 12;
1038  m :        case cci::CV_PMTYPE_F_Single:
1039  m :          return 8;
1040  m :        case cci::CV_PMTYPE_F_Multiple:
1041  m :          return 16;
1042  m :        case cci::CV_PMTYPE_F_Virtual:
1043  m :          return 16;
1044  m :        case cci::CV_PMTYPE_F_General:
1045  m :          return 24;
1046  m :      }
1047  m :    }
1048    :    // It seems that VS doesn't use the other pointer types in PDB files.
1049  m :    NOTREACHED();
1050  m :    return 0;
1051  m :  }
1052    :  
1053  m :  bool TypeCreator::IsImportantType(uint32_t type) {
1054  m :    switch (type) {
1055  m :      case cci::LF_CLASS:
1056  m :      case cci::LF_STRUCTURE:
1057  m :      case cci::LF_UNION:
1058  m :      case cci::LF_ARRAY:
1059  m :      case cci::LF_POINTER:
1060  m :      case cci::LF_PROCEDURE:
1061  m :      case cci::LF_MFUNCTION:
1062  m :        return true;
1063  m :    }
1064  m :    return false;
1065  m :  }
1066    :  
1067  m :  Type::Flags TypeCreator::CreateTypeFlags(bool is_const, bool is_volatile) {
1068  m :    Type::Flags flags = kNoTypeFlags;
1069  m :    if (is_const)
1070  m :      flags |= Type::FLAG_CONST;
1071  m :    if (is_volatile)
1072  m :      flags |= Type::FLAG_VOLATILE;
1073  m :    return flags;
1074  m :  }
1075    :  
1076  m :  uint16_t TypeCreator::GetLeafType(TypeId type_id) {
1077  m :    if (type_id < cci::CV_PRIMITIVE_TYPE::CV_FIRST_NONPRIM)
1078  m :      return static_cast<uint16_t>(type_id);
1079    :  
1080  m :    auto it = types_map_.find(type_id);
1081  m :    if (it == types_map_.end()) {
1082  m :      LOG(ERROR) << "Couldn't find record with type index " << type_id
1083  m :                 << " in the types map.";
1084  m :      return kNoLeafType;
1085  m :    } else {
1086  m :      return it->second;
1087  m :    }
1088  m :  }
1089    :  
1090  m :  bool TypeCreator::CacheUserDefinedTypeForwardDeclaration(TypeId fwd_id,
1091  m :                                                           TypeId class_id) {
1092  m :    return fwd_reference_map_.insert(std::make_pair(fwd_id, class_id)).second;
1093  m :  }
1094    :  
1095  m :  TypeId TypeCreator::LookupConcreteClassForForwardDeclaration(TypeId type_id) {
1096  m :    auto redir = fwd_reference_map_.find(type_id);
1097  m :    if (redir != fwd_reference_map_.end()) {
1098  m :      return redir->second;
1099  m :    } else {
1100  m :      return kNoTypeId;
1101  m :    }
1102  m :  }
1103    :  
1104  m :  bool TypeCreator::IsBasicPointerType(TypeId type_id) {
1105  m :    if (type_id >= cci::CV_PRIMITIVE_TYPE::CV_FIRST_NONPRIM)
1106  m :      return false;
1107    :  
1108    :    // T_PVOID is used to encode std::nullptr_t which we save as a basic type.
1109  m :    if (type_id == cci::T_PVOID)
1110  m :      return false;
1111    :  
1112  m :    if (TypeIndexToPrMode(type_id) == cci::CV_TM_DIRECT)
1113  m :      return false;
1114    :  
1115  m :    return true;
1116  m :  }
1117    :  
1118  m :  cci::CV_prmode TypeCreator::TypeIndexToPrMode(TypeId type_id) {
1119  m :    return static_cast<cci::CV_prmode>(
1120  m :        (type_id & cci::CV_PRIMITIVE_TYPE::CV_MMASK) >>
1121  m :        cci::CV_PRIMITIVE_TYPE::CV_MSHIFT);
1122  m :  }
1123    :  
1124  m :  TypePtr TypeCreator::CreateBasicType(TypeId type_id) {
1125  m :    DCHECK(type_id < cci::CV_PRIMITIVE_TYPE::CV_FIRST_NONPRIM);
1126    :  
1127  m :    BasicTypePtr basic_type =
1128  m :        new BasicType(BasicTypeName(type_id), BasicTypeSize(type_id));
1129    :  
1130    :    // Save type and additional info.
1131  m :    if (!repository_->AddTypeWithId(basic_type, type_id))
1132  m :      return nullptr;
1133  m :    return basic_type;
1134  m :  }
1135    :  
1136  m :  TypePtr TypeCreator::CreateWildcardType(TypeId type_id) {
1137  m :    base::string16 name = LeafTypeName(GetLeafType(type_id));
1138  m :    TypePtr wildcard_type = new WildcardType(name, name, 0);
1139  m :    if (!repository_->AddTypeWithId(wildcard_type, type_id))
1140  m :      return nullptr;
1141  m :    return wildcard_type;
1142  m :  }
1143    :  
1144  m :  TypePtr TypeCreator::FindOrCreateTypeImpl(TypeId type_id) {
1145  m :    TypeId concrete_type_id = LookupConcreteClassForForwardDeclaration(type_id);
1146  m :    if (concrete_type_id != kNoTypeId)
1147  m :      return repository_->GetType(concrete_type_id);
1148    :  
1149  m :    TypePtr type = repository_->GetType(type_id);
1150  m :    if (type != nullptr)
1151  m :      return type;
1152    :  
1153    :    // We need to create new type object.
1154    :    // Check if it is a regular type index.
1155  m :    if (type_id >= type_info_enum_.type_info_header().type_min) {
1156  m :      return CreateType(type_id);
1157  m :    } else {
1158    :      // Check if this is actually a pointer.
1159  m :      if (IsBasicPointerType(type_id)) {
1160  m :        return CreateBasicPointerType(type_id);
1161  m :      } else {
1162    :        // Otherwise create the basic type.
1163  m :        return CreateBasicType(type_id);
1164  m :      }
1165  m :    }
1166  m :  }
1167    :  
1168  m :  TypePtr TypeCreator::FindOrCreateIndexingType(TypeId type_id) {
1169  m :    if (type_id == cci::T_ULONG || type_id == cci::T_UQUAD)
1170  m :      return FindOrCreateTypeImpl(type_id);
1171    :  
1172  m :    return nullptr;
1173  m :  }
1174    :  
1175  m :  TypePtr TypeCreator::FindOrCreateIntegralBasicType(TypeId type_id) {
1176  m :    TypeId type_mask = (type_id & cci::CV_PRIMITIVE_TYPE::CV_TMASK) >>
1177  m :                       cci::CV_PRIMITIVE_TYPE::CV_TSHIFT;
1178    :  
1179  m :    if (type_mask == cci::CV_SIGNED || type_mask == cci::CV_UNSIGNED ||
1180  m :        type_mask == cci::CV_INT || type_mask == cci::CV_BOOLEAN) {
1181  m :      return FindOrCreateBasicType(type_id);
1182  m :    }
1183    :  
1184  m :    return nullptr;
1185  m :  }
1186    :  
1187  m :  TypePtr TypeCreator::FindOrCreateBasicType(TypeId type_id) {
1188  m :    if (type_id < cci::CV_PRIMITIVE_TYPE::CV_FIRST_NONPRIM &&
1189  m :        !IsBasicPointerType(type_id)) {
1190  m :      return FindOrCreateTypeImpl(type_id);
1191  m :    }
1192    :  
1193  m :    return nullptr;
1194  m :  }
1195    :  
1196  m :  TypePtr TypeCreator::FindOrCreateInheritableType(TypeId type_id) {
1197  m :    uint16_t type = GetLeafType(type_id);
1198  m :    if (type == cci::LF_CLASS || type == cci::LF_STRUCTURE)
1199  m :      return FindOrCreateTypeImpl(type_id);
1200    :  
1201  m :    return nullptr;
1202  m :  }
1203    :  
1204  m :  TypePtr TypeCreator::FindOrCreateStructuredType(TypeId type_id) {
1205  m :    uint16_t type = GetLeafType(type_id);
1206  m :    if (type == cci::LF_UNION)
1207  m :      return FindOrCreateTypeImpl(type_id);
1208    :  
1209  m :    return FindOrCreateInheritableType(type_id);
1210  m :  }
1211    :  
1212  m :  TypePtr TypeCreator::FindOrCreateUserDefinedType(TypeId type_id) {
1213  m :    uint16_t type = GetLeafType(type_id);
1214  m :    if (type == cci::LF_ENUM)
1215  m :      return FindOrCreateTypeImpl(type_id);
1216    :  
1217  m :    return FindOrCreateStructuredType(type_id);
1218  m :  }
1219    :  
1220  m :  TypePtr TypeCreator::FindOrCreateModifiableType(TypeId type_id) {
1221  m :    uint16_t type = GetLeafType(type_id);
1222    :  
1223  m :    if (type < cci::CV_PRIMITIVE_TYPE::CV_FIRST_NONPRIM)
1224  m :      return FindOrCreateBasicType(type_id);
1225    :  
1226  m :    return FindOrCreateUserDefinedType(type_id);
1227  m :  }
1228    :  
1229  m :  TypePtr TypeCreator::FindOrCreateOptionallyModifiedType(TypeId type_id,
1230  m :                                                          Type::Flags* flags) {
1231  m :    DCHECK(flags);
1232  m :    uint16_t type = GetLeafType(type_id);
1233  m :    *flags = kNoTypeFlags;
1234    :  
1235  m :    if (type == cci::LF_MODIFIER)
1236  m :      return ReadModifier(type_id, flags);
1237    :  
1238  m :    if (type == cci::LF_POINTER)
1239  m :      return ReadPointer(type_id, flags);
1240    :  
1241  m :    if (type == cci::LF_ARRAY)
1242  m :      return FindOrCreateTypeImpl(type_id);
1243    :  
1244  m :    if (IsBasicPointerType(type_id))
1245  m :      return FindOrCreateTypeImpl(type_id);
1246    :  
1247  m :    return FindOrCreateModifiableType(type_id);
1248  m :  }
1249    :  
1250  m :  TypePtr TypeCreator::FindOrCreateBitfieldType(TypeId type_id,
1251  m :                                                Type::Flags* flags) {
1252  m :    DCHECK(flags);
1253  m :    uint16_t type = GetLeafType(type_id);
1254  m :    *flags = kNoTypeFlags;
1255    :  
1256  m :    if (type == cci::LF_MODIFIER) {
1257  m :      TypePtr type = ReadModifier(type_id, flags);
1258    :      // TODO(mopler): Once we load enums change the name test to type test.
1259  m :      if (type->kind() == Type::BASIC_TYPE_KIND || type->GetName() == L"LF_ENUM")
1260  m :        return type;
1261    :  
1262  m :      return nullptr;
1263  m :    }
1264    :  
1265  m :    if (type == cci::LF_ENUM)
1266  m :      return FindOrCreateTypeImpl(type_id);
1267    :  
1268  m :    return FindOrCreateIntegralBasicType(type_id);
1269  m :  }
1270    :  
1271  m :  TypePtr TypeCreator::FindOrCreateMemberType(TypeId type_id,
1272  m :                                              Type::Flags* flags,
1273  m :                                              size_t* bit_pos,
1274  m :                                              size_t* bit_len) {
1275  m :    DCHECK(flags);
1276  m :    DCHECK(bit_pos);
1277  m :    DCHECK(bit_len);
1278    :  
1279  m :    uint16_t type = GetLeafType(type_id);
1280  m :    *flags = kNoTypeFlags;
1281  m :    *bit_pos = 0;
1282  m :    *bit_len = 0;
1283    :  
1284  m :    if (type == cci::LF_BITFIELD)
1285  m :      return ReadBitfield(type_id, flags, bit_pos, bit_len);
1286    :  
1287  m :    return FindOrCreateOptionallyModifiedType(type_id, flags);
1288  m :  }
1289    :  
1290  m :  TypePtr TypeCreator::FindOrCreatePointableType(TypeId type_id,
1291  m :                                                 Type::Flags* flags) {
1292  m :    DCHECK(flags);
1293  m :    *flags = kNoTypeFlags;
1294  m :    uint16_t type = GetLeafType(type_id);
1295    :  
1296  m :    if (type == cci::LF_MFUNCTION || type == cci::LF_PROCEDURE ||
1297  m :        type == cci::LF_VTSHAPE) {
1298  m :      return FindOrCreateTypeImpl(type_id);
1299  m :    }
1300    :  
1301  m :    return FindOrCreateOptionallyModifiedType(type_id, flags);
1302  m :  }
1303    :  
1304  m :  TypePtr TypeCreator::FindOrCreateSpecificType(TypeId type_id, uint16_t type) {
1305  m :    DCHECK_NE(kNoLeafType, type);
1306  m :    uint16_t this_type = GetLeafType(type_id);
1307    :  
1308  m :    if (this_type != type)
1309  m :      return nullptr;
1310    :  
1311  m :    return FindOrCreateTypeImpl(type_id);
1312  m :  }
1313    :  
1314  m :  TypePtr TypeCreator::CreateType(TypeId type_id) {
1315  m :    switch (GetLeafType(type_id)) {
1316  m :      case cci::LF_CLASS:
1317  m :      case cci::LF_STRUCTURE:
1318  m :      case cci::LF_UNION: {
1319  m :        return CreateUserDefinedType(type_id);
1320  m :      }
1321  m :      case cci::LF_POINTER: {
1322  m :        return CreatePointerType(type_id);
1323  m :      }
1324  m :      case cci::LF_ARRAY: {
1325  m :        return CreateArrayType(type_id);
1326  m :      }
1327  m :      case cci::LF_PROCEDURE:
1328  m :      case cci::LF_MFUNCTION: {
1329  m :        return CreateFunctionType(type_id);
1330  m :      }
1331  m :      default: { return CreateWildcardType(type_id); }
1332  m :    }
1333  m :  }
1334    :  
1335  m :  bool TypeCreator::PrepareData() {
1336  m :    size_t unexpected_duplicate_types = 0;
1337    :  
1338  m :    while (!type_info_enum_.EndOfStream()) {
1339  m :      if (!type_info_enum_.NextTypeInfoRecord())
1340  m :        return false;
1341    :  
1342  m :      types_map_.insert(
1343  m :          std::make_pair(type_info_enum_.type_id(), type_info_enum_.type()));
1344    :  
1345    :      // We remember ids of the types that we will later descend into.
1346  m :      if (IsImportantType(type_info_enum_.type()))
1347  m :        records_to_process_.push_back(type_info_enum_.type_id());
1348    :  
1349  m :      pdb::TypeInfoEnumerator::BinaryTypeRecordReader reader(
1350  m :          type_info_enum_.CreateRecordReader());
1351  m :      common::BinaryStreamParser parser(&reader);
1352  m :      if (type_info_enum_.type() == cci::LF_CLASS ||
1353  m :          type_info_enum_.type() == cci::LF_STRUCTURE) {
1354  m :        pdb::LeafClass type_info;
1355  m :        if (!type_info.Initialize(&parser)) {
1356  m :          LOG(ERROR) << "Unable to read type info record.";
1357  m :          return false;
1358  m :        }
1359    :  
1360    :        // Populate the decorated name to type index map. Note that this
1361    :        // overwrites any preceding record of the same name, which can occur for
1362    :        // 2 reasons:
1363    :        //   - the unnamed nested structures get assigned the name <unnamed-tag>
1364    :        //   - we've observed UDTs that are identical up to extra LF_NESTTYPE
1365    :        //     (which do not make it to our type representation).
1366    :        // TODO(manzagop): investigate more and consider folding duplicate types.
1367  m :        if (!type_info.property().fwdref) {
1368  m :          if (type_info.name().find(L'<') != 0 &&
1369  m :              udt_map_.find(type_info.decorated_name()) != udt_map_.end()) {
1370  m :            VLOG(1) << "Encountered duplicate decorated name: "
1371  m :                    << type_info.decorated_name();
1372  m :            unexpected_duplicate_types++;
1373  m :          }
1374    :  
1375  m :          udt_map_[type_info.decorated_name()] = type_info_enum_.type_id();
1376  m :        }
1377  m :      }
1378  m :    }
1379    :  
1380  m :    if (unexpected_duplicate_types > 0) {
1381  m :      LOG(INFO) << "Encountered " << unexpected_duplicate_types
1382  m :                << " unexpected duplicate types.";
1383  m :    }
1384    :  
1385  m :    return type_info_enum_.ResetStream();
1386  m :  }
1387    :  
1388  m :  bool TypeCreator::CreateTypes() {
1389  m :    if (!type_info_enum_.Init()) {
1390  m :      LOG(ERROR) << "Unable to initialize type info stream enumerator.";
1391  m :      return false;
1392  m :    }
1393    :  
1394  m :    const TypeId kSmallestUnreservedIndex = 0x1000;
1395  m :    if (type_info_enum_.type_info_header().type_min < kSmallestUnreservedIndex) {
1396  m :      LOG(ERROR) << "Degenerate stream with type indices in the reserved range.";
1397  m :      return false;
1398  m :    }
1399    :  
1400    :    // Create the map of forward declarations and populate the process queue.
1401  m :    if (!PrepareData())
1402  m :      return false;
1403    :  
1404    :    // Process every important type.
1405  m :    for (TypeId type_id : records_to_process_) {
1406  m :      if (FindOrCreateTypeImpl(type_id) == nullptr)
1407  m :        return false;
1408  m :    }
1409    :  
1410  m :    return true;
1411  m :  }
1412    :  
1413  m :  }  // namespace
1414    :  
1415  m :  PdbCrawler::PdbCrawler() {
1416  m :  }
1417    :  
1418  m :  PdbCrawler::~PdbCrawler() {
1419  m :  }
1420    :  
1421  m :  bool PdbCrawler::InitializeForFile(const base::FilePath& path) {
1422  m :    pdb::PdbReader reader;
1423  m :    pdb::PdbFile pdb_file;
1424    :  
1425  m :    if (!reader.Read(path, &pdb_file)) {
1426  m :      LOG(ERROR) << "Failed to read PDB file " << path.value() << ".";
1427  m :      return false;
1428  m :    }
1429    :  
1430    :    // Get the type stream.
1431  m :    tpi_stream_ = pdb_file.GetStream(pdb::kTpiStream);
1432    :  
1433    :    // Get the public symbol stream: it has a variable index, found in the Dbi
1434    :    // stream.
1435  m :    scoped_refptr<pdb::PdbStream> dbi_stream_raw =
1436  m :        pdb_file.GetStream(pdb::kDbiStream);
1437  m :    pdb::DbiStream dbi_stream;
1438  m :    if (dbi_stream_raw.get() == nullptr ||
1439  m :        !dbi_stream.Read(dbi_stream_raw.get())) {
1440  m :      LOG(ERROR) << "No Dbi stream.";
1441  m :      return false;
1442  m :    }
1443    :  
1444    :    // The dbi stream's header contains the index of the public symbol stream.
1445  m :    uint32_t sym_stream_idx = dbi_stream.header().symbol_record_stream;
1446  m :    if (sym_stream_idx != -1) {
1447  m :      sym_stream_ = pdb_file.GetStream(sym_stream_idx);
1448  m :      if (sym_stream_ == nullptr) {
1449  m :        LOG(ERROR) << "Failed to get symbol record stream.";
1450  m :        return false;
1451  m :      }
1452  m :    } else {
1453    :      // The PDB does not have a public symbol stream. This may happen.
1454  m :      LOG(INFO) << "No symbol record stream.";
1455  m :      return true;
1456  m :    }
1457    :  
1458    :    // Get the PE image section information. The DbiDbgHeader contains the index
1459    :    // of a stream that contains this information as an array of
1460    :    // IMAGE_SECTION_HEADER.
1461  m :    uint32_t img_hdr_stream_idx = dbi_stream.dbg_header().section_header;
1462  m :    if (img_hdr_stream_idx == -1) {
1463  m :      LOG(ERROR) << "No section header stream.";
1464  m :      return false;
1465  m :    }
1466  m :    scoped_refptr<pdb::PdbStream> img_hdr_stream =
1467  m :        pdb_file.GetStream(img_hdr_stream_idx);
1468  m :    if (img_hdr_stream == nullptr) {
1469  m :      LOG(ERROR) << "Failed to get image header stream.";
1470  m :      return false;
1471  m :    }
1472  m :    size_t num_elements = img_hdr_stream->length() / sizeof(IMAGE_SECTION_HEADER);
1473  m :    section_headers_.resize(num_elements);
1474  m :    if (num_elements != 0 &&
1475  m :        !img_hdr_stream->ReadBytesAt(0, num_elements, &section_headers_.at(0))) {
1476  m :      LOG(ERROR) << "Failed to read the image header stream.";
1477  m :      return false;
1478  m :    }
1479    :  
1480    :    // The PDB may include OMAP information, used to represent a mapping from
1481    :    // an original PDB address space to a transformed one. The DbiDbgHeader
1482    :    // contains indices for two streams that contain this information as arrays of
1483    :    // OMAP structures. We retrieve only the mapping from the original space to
1484    :    // the transformed space.
1485  m :    if (dbi_stream.dbg_header().omap_from_src >= 0) {
1486  m :      if (!pdb::ReadOmapsFromPdbFile(pdb_file, nullptr, &omap_from_)) {
1487  m :        LOG(ERROR) << "Failed to read the OMAP data.";
1488  m :        return false;
1489  m :      }
1490  m :    }
1491    :  
1492  m :    return true;
1493  m :  }
1494    :  
1495  m :  bool PdbCrawler::GetTypes(TypeRepository* types) {
1496  m :    DCHECK(types);
1497  m :    DCHECK(tpi_stream_);
1498    :  
1499  m :    TypeCreator creator(types, tpi_stream_.get());
1500    :  
1501  m :    return creator.CreateTypes();
1502  m :  }
1503    :  
1504  m :  bool PdbCrawler::GetVFTableRVAForSymbol(
1505  m :      base::hash_set<RelativeAddress>* vftable_rvas,
1506  m :      uint16_t symbol_length,
1507  m :      uint16_t symbol_type,
1508  m :      common::BinaryStreamReader* symbol_reader) {
1509  m :    DCHECK(symbol_reader);
1510  m :    DCHECK(vftable_rvas);
1511    :  
1512    :    // Not a vftable: skip to the next record.
1513  m :    if (symbol_type != cci::S_PUB32)
1514  m :      return true;
1515    :  
1516    :    // Read the symbol.
1517  m :    cci::PubSym32 symbol = {};
1518  m :    size_t to_read = offsetof(cci::PubSym32, name);
1519  m :    common::BinaryStreamParser parser(symbol_reader);
1520  m :    if (!parser.ReadBytes(to_read, &symbol)) {
1521  m :      LOG(ERROR) << "Unable to read symbol.";
1522  m :      return false;
1523  m :    }
1524  m :    std::string symbol_name;
1525  m :    if (!parser.ReadString(&symbol_name)) {
1526  m :      LOG(ERROR) << "Unable to read symbol name.";
1527  m :      return false;
1528  m :    }
1529    :  
1530    :    // Determine if the symbol is a vftable based on its name.
1531    :    // Note: pattern derived from LLVM's MicrosoftMangle.cpp (mangleCXXVFTable).
1532  m :    if (!base::MatchPattern(symbol_name, "\\?\\?_7*@6B*@"))
1533  m :      return true;  // Not a vftable.
1534    :  
1535    :    // Determine the vftable's RVA, then add it to the set.
1536    :  
1537    :    // Note: Segment indexing seems to be 1-based.
1538  m :    DCHECK(symbol.seg > 0);  // 1-based.
1539  m :    if (symbol.seg < 1U || symbol.seg > section_headers_.size()) {
1540  m :      LOG(ERROR) << "Symbol's segment is invalid.";
1541  m :      return false;
1542  m :    }
1543    :  
1544  m :    uint32_t vftable_rva =
1545  m :        section_headers_[symbol.seg - 1].VirtualAddress + symbol.off;
1546    :  
1547    :    // Apply OMAP transformation if necessary.
1548  m :    if (omap_from_.size() > 0) {
1549  m :      core::RelativeAddress rva_omap = pdb::TranslateAddressViaOmap(
1550  m :          omap_from_, core::RelativeAddress(vftable_rva));
1551  m :      vftable_rva = rva_omap.value();
1552  m :    }
1553    :  
1554  m :    vftable_rvas->insert(static_cast<RelativeAddress>(vftable_rva));
1555    :  
1556  m :    return true;
1557  m :  }
1558    :  
1559  m :  bool PdbCrawler::GetVFTableRVAs(base::hash_set<RelativeAddress>* vftable_rvas) {
1560  m :    DCHECK(vftable_rvas);
1561  m :    vftable_rvas->clear();
1562    :  
1563  m :    if (!sym_stream_)
1564  m :      return false;  // The PDB does not have public symbols.
1565    :  
1566  m :    pdb::VisitSymbolsCallback symbol_cb =
1567  m :        base::Bind(&PdbCrawler::GetVFTableRVAForSymbol, base::Unretained(this),
1568  m :                   base::Unretained(vftable_rvas));
1569    :  
1570  m :    return pdb::VisitSymbols(symbol_cb, 0, sym_stream_->length(), false,
1571  m :                             sym_stream_.get());
1572  m :  }
1573    :  
1574  m :  }  // namespace refinery

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