Coverage for /Syzygy/pe/decomposer.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
80.1%85610680.C++source

Line-by-line coverage:

   1    :  // Copyright 2012 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/pe/decomposer.h"
  16    :  
  17    :  #include "pcrecpp.h"  // NOLINT
  18    :  #include "base/bind.h"
  19    :  #include "base/strings/string_split.h"
  20    :  #include "base/strings/stringprintf.h"
  21    :  #include "base/strings/utf_string_conversions.h"
  22    :  #include "base/win/scoped_bstr.h"
  23    :  #include "base/win/scoped_comptr.h"
  24    :  #include "syzygy/core/zstream.h"
  25    :  #include "syzygy/pdb/omap.h"
  26    :  #include "syzygy/pdb/pdb_byte_stream.h"
  27    :  #include "syzygy/pdb/pdb_constants.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_symbol_record.h"
  32    :  #include "syzygy/pdb/pdb_util.h"
  33    :  #include "syzygy/pe/dia_util.h"
  34    :  #include "syzygy/pe/find.h"
  35    :  #include "syzygy/pe/pe_file_parser.h"
  36    :  #include "syzygy/pe/pe_utils.h"
  37    :  #include "syzygy/pe/serialization.h"
  38    :  #include "third_party/cci/Files/CvInfo.h"
  39    :  
  40    :  namespace cci = Microsoft_Cci_Pdb;
  41    :  
  42    :  namespace {
  43    :  
  44    :  using block_graph::BlockGraph;
  45    :  using block_graph::BlockInfo;
  46    :  using core::AbsoluteAddress;
  47    :  using core::FileOffsetAddress;
  48    :  using core::RelativeAddress;
  49    :  
  50    :  typedef BlockGraph::Block Block;
  51    :  
  52    :  }  // namespace
  53    :  
  54    :  namespace pe {
  55    :  
  56    :  // An intermediate reference representation used while parsing PE blocks.
  57    :  // This is necessary because at that point we haven't yet chunked the whole
  58    :  // image into blocks thus some references cannot be resolved.
  59    :  struct Decomposer::IntermediateReference {
  60    :    RelativeAddress src_addr;
  61    :    BlockGraph::ReferenceType type;
  62    :    BlockGraph::Size size;
  63    :    RelativeAddress dst_addr;
  64    :  };
  65    :  
  66    :  namespace {
  67    :  
  68    :  using base::win::ScopedBstr;
  69    :  using base::win::ScopedComPtr;
  70    :  using builder::Callback;
  71    :  using builder::Opt;
  72    :  using builder::Or;
  73    :  using builder::Seq;
  74    :  using builder::Star;
  75    :  
  76    :  typedef BlockGraph::BlockType BlockType;
  77    :  typedef BlockGraph::Offset Offset;
  78    :  typedef BlockGraph::Reference Reference;
  79    :  typedef BlockGraph::ReferenceType ReferenceType;
  80    :  typedef core::AddressRange<RelativeAddress, size_t> RelativeRange;
  81    :  typedef Decomposer::IntermediateReference IntermediateReference;
  82    :  typedef Decomposer::IntermediateReferences IntermediateReferences;
  83    :  typedef pcrecpp::RE RE;
  84    :  typedef std::vector<OMAP> OMAPs;
  85    :  typedef std::vector<pdb::PdbFixup> PdbFixups;
  86    :  
  87    :  const char kJumpTable[] = "<jump-table>";
  88    :  const char kCaseTable[] = "<case-table>";
  89    :  
  90    :  // The MS linker pads between code blocks with int3s.
  91    :  static const uint8_t kInt3 = 0xCC;
  92    :  static const size_t kPointerSize = BlockGraph::Reference::kMaximumSize;
  93    :  
  94    :  // Some helper functions for testing ranges.
  95    :  template<typename T1, typename T2, typename T3>
  96  E :  bool InRange(T1 value, T2 lower_bound_incl, T3 length_excl) {
  97  E :    T1 upper_bound_excl = static_cast<T1>(lower_bound_incl) + length_excl;
  98  E :    return static_cast<T1>(lower_bound_incl) <= value &&
  99    :        value < static_cast<T2>(upper_bound_excl);
 100  E :  }
 101    :  template<typename T1, typename T2, typename T3>
 102  E :  bool InRangeIncl(T1 value, T2 lower_bound_incl, T3 length_incl) {
 103  E :    T1 upper_bound_incl = static_cast<T1>(lower_bound_incl) + length_incl;
 104  E :    return static_cast<T1>(lower_bound_incl) <= value &&
 105    :        value <= upper_bound_incl;
 106  E :  }
 107    :  
 108    :  bool InitializeDia(const PEFile& image_file,
 109    :                     const base::FilePath& pdb_path,
 110    :                     IDiaDataSource** dia_source,
 111    :                     IDiaSession** dia_session,
 112  E :                     IDiaSymbol** global) {
 113  E :    DCHECK_EQ(reinterpret_cast<IDiaDataSource*>(NULL), *dia_source);
 114  E :    DCHECK_EQ(reinterpret_cast<IDiaSession*>(NULL), *dia_session);
 115  E :    DCHECK_EQ(reinterpret_cast<IDiaSymbol*>(NULL), *global);
 116    :  
 117  E :    if (!CreateDiaSource(dia_source))
 118  i :      return false;
 119  E :    DCHECK_NE(reinterpret_cast<IDiaDataSource*>(NULL), *dia_source);
 120    :  
 121    :    // We create the session using the PDB file directly, as we've already
 122    :    // validated that it matches the module.
 123  E :    if (!CreateDiaSession(pdb_path, *dia_source, dia_session))
 124  i :      return false;
 125  E :    DCHECK_NE(reinterpret_cast<IDiaSession*>(NULL), *dia_session);
 126    :  
 127  E :    HRESULT hr = (*dia_session)->get_globalScope(global);
 128  E :    if (hr != S_OK) {
 129  i :      LOG(ERROR) << "Failed to get the DIA global scope: "
 130    :                 << common::LogHr(hr) << ".";
 131  i :      return false;
 132    :    }
 133    :  
 134  E :    return true;
 135  E :  }
 136    :  
 137    :  // Given a compiland, returns its compiland details.
 138    :  bool GetCompilandDetailsForCompiland(IDiaSymbol* compiland,
 139  E :                                       IDiaSymbol** compiland_details) {
 140  E :    DCHECK_NE(reinterpret_cast<IDiaSymbol*>(NULL), compiland);
 141  E :    DCHECK_NE(reinterpret_cast<IDiaSymbol**>(NULL), compiland_details);
 142  E :    DCHECK(IsSymTag(compiland, SymTagCompiland));
 143  E :    DCHECK_EQ(reinterpret_cast<IDiaSymbol*>(NULL), *compiland_details);
 144    :  
 145    :    // Get the enumeration of compiland details.
 146  E :    ScopedComPtr<IDiaEnumSymbols> enum_symbols;
 147  E :    HRESULT hr = compiland->findChildren(SymTagCompilandDetails, NULL, 0,
 148    :                                         enum_symbols.Receive());
 149  E :    DCHECK_EQ(S_OK, hr);
 150    :  
 151    :    // We expect there to be compiland details. For compilands built by
 152    :    // non-standard toolchains, there usually aren't any.
 153  E :    LONG count = 0;
 154  E :    hr = enum_symbols->get_Count(&count);
 155  E :    DCHECK_EQ(S_OK, hr);
 156  E :    if (count == 0) {
 157    :      // We don't log here because we see this quite often.
 158  i :      return false;
 159    :    }
 160    :  
 161    :    // We do sometimes encounter more than one compiland detail. In fact, for
 162    :    // import and export tables we get one compiland detail per table entry.
 163    :    // They are all marked as having been generated by the linker, so using the
 164    :    // first one is sufficient.
 165    :  
 166    :    // Get the compiland details.
 167  E :    ULONG fetched = 0;
 168  E :    hr = enum_symbols->Next(1, compiland_details, &fetched);
 169  E :    DCHECK_EQ(S_OK, hr);
 170  E :    DCHECK_EQ(1u, fetched);
 171    :  
 172  E :    return true;
 173  E :  }
 174    :  
 175    :  // Stores information regarding known compilers.
 176    :  struct KnownCompilerInfo {
 177    :    wchar_t* compiler_name;
 178    :    bool supported;
 179    :  };
 180    :  
 181    :  // A list of known compilers, and their status as being supported or not.
 182    :  KnownCompilerInfo kKnownCompilerInfos[] = {
 183    :    { L"Microsoft (R) Macro Assembler", false },
 184    :    { L"Microsoft (R) Optimizing Compiler", true },
 185    :    { L"Microsoft (R) LINK", false }
 186    :  };
 187    :  
 188    :  // Given a compiland, determines whether the compiler used is one of those that
 189    :  // we whitelist.
 190  E :  bool IsBuiltBySupportedCompiler(IDiaSymbol* compiland) {
 191  E :    DCHECK_NE(reinterpret_cast<IDiaSymbol*>(NULL), compiland);
 192  E :    DCHECK(IsSymTag(compiland, SymTagCompiland));
 193    :  
 194  E :    ScopedComPtr<IDiaSymbol> compiland_details;
 195  E :    if (!GetCompilandDetailsForCompiland(compiland,
 196    :                                         compiland_details.Receive())) {
 197    :      // If the compiland has no compiland details we assume the compiler is not
 198    :      // supported.
 199  i :      ScopedBstr compiland_name;
 200  i :      if (compiland->get_name(compiland_name.Receive()) == S_OK) {
 201  i :        VLOG(1) << "Compiland has no compiland details: "
 202    :                << common::ToString(compiland_name);
 203    :      }
 204  i :      return false;
 205    :    }
 206  E :    DCHECK_NE(reinterpret_cast<IDiaSymbol*>(NULL), compiland_details.get());
 207    :  
 208    :    // Get the compiler name.
 209  E :    ScopedBstr compiler_name;
 210  E :    HRESULT hr = compiland_details->get_compilerName(compiler_name.Receive());
 211  E :    DCHECK_EQ(S_OK, hr);
 212    :  
 213    :    // Check the compiler name against the list of known compilers.
 214  E :    for (size_t i = 0; i < arraysize(kKnownCompilerInfos); ++i) {
 215  E :      if (::wcscmp(kKnownCompilerInfos[i].compiler_name, compiler_name) == 0) {
 216  E :        return kKnownCompilerInfos[i].supported;
 217    :      }
 218  E :    }
 219    :  
 220    :    // Anything we don't explicitly know about is not supported.
 221  E :    VLOG(1) << "Encountered unknown compiler: " << compiler_name;
 222  E :    return false;
 223  E :  }
 224    :  
 225    :  // Adds an intermediate reference to the provided vector. The vector is
 226    :  // specified as the first parameter (in slight violation of our coding
 227    :  // standards) because this function is intended to be used by Bind.
 228    :  bool AddIntermediateReference(IntermediateReferences* references,
 229    :                                RelativeAddress src_addr,
 230    :                                ReferenceType type,
 231    :                                BlockGraph::Size size,
 232  E :                                RelativeAddress dst_addr) {
 233  E :    DCHECK_NE(reinterpret_cast<IntermediateReferences*>(NULL), references);
 234  E :    IntermediateReference ref = { src_addr, type, size, dst_addr };
 235  E :    references->push_back(ref);
 236  E :    return true;
 237  E :  }
 238    :  
 239    :  // Create a reference as specified. Ignores existing references if they are of
 240    :  // the exact same type.
 241    :  bool CreateReference(RelativeAddress src_addr,
 242    :                       BlockGraph::Size ref_size,
 243    :                       ReferenceType ref_type,
 244    :                       RelativeAddress base_addr,
 245    :                       RelativeAddress dst_addr,
 246  E :                       BlockGraph::AddressSpace* image) {
 247  E :    DCHECK_NE(reinterpret_cast<BlockGraph::AddressSpace*>(NULL), image);
 248    :  
 249    :    // Get the source block and offset, and ensure that the reference fits
 250    :    // within it.
 251  E :    Block* src_block = image->GetBlockByAddress(src_addr);
 252  E :    if (src_block == NULL) {
 253  i :      LOG(ERROR) << "Unable to find block for reference originating at "
 254    :                 << src_addr << ".";
 255  i :      return false;
 256    :    }
 257  E :    RelativeAddress src_block_addr;
 258  E :    CHECK(image->GetAddressOf(src_block, &src_block_addr));
 259  E :    Offset src_block_offset = src_addr - src_block_addr;
 260  E :    if (src_block_offset + ref_size > src_block->size()) {
 261  i :      LOG(ERROR) << "Reference originating at " << src_addr
 262    :                 << " extends beyond block \"" << src_block->name() << "\".";
 263  i :      return false;
 264    :    }
 265    :  
 266    :    // Get the destination block and offset.
 267  E :    Block* dst_block = image->GetBlockByAddress(base_addr);
 268  E :    if (dst_block == NULL) {
 269  i :      LOG(ERROR) << "Unable to find block for reference pointing at "
 270    :                 << base_addr << ".";
 271  i :      return false;
 272    :    }
 273  E :    RelativeAddress dst_block_addr;
 274  E :    CHECK(image->GetAddressOf(dst_block, &dst_block_addr));
 275  E :    Offset base = base_addr - dst_block_addr;
 276  E :    Offset offset = dst_addr - dst_block_addr;
 277    :  
 278  E :    Reference ref(ref_type, ref_size, dst_block, offset, base);
 279    :  
 280    :    // Check if a reference already exists at this offset.
 281    :    Block::ReferenceMap::const_iterator ref_it =
 282  E :        src_block->references().find(src_block_offset);
 283  E :    if (ref_it != src_block->references().end()) {
 284    :      // If an identical reference already exists then we're done.
 285  E :      if (ref == ref_it->second)
 286  E :        return true;
 287  i :      LOG(ERROR) << "Block \"" << src_block->name() << "\" has a conflicting "
 288    :                 << "reference at offset " << src_block_offset << ".";
 289  i :      return false;
 290    :    }
 291    :  
 292  E :    CHECK(src_block->SetReference(src_block_offset, ref));
 293    :  
 294  E :    return true;
 295  E :  }
 296    :  
 297    :  // Loads FIXUP and OMAP_FROM debug streams.
 298    :  bool LoadDebugStreams(IDiaSession* dia_session,
 299    :                        PdbFixups* pdb_fixups,
 300  E :                        OMAPs* omap_from) {
 301  E :    DCHECK_NE(reinterpret_cast<IDiaSession*>(NULL), dia_session);
 302  E :    DCHECK_NE(reinterpret_cast<PdbFixups*>(NULL), pdb_fixups);
 303  E :    DCHECK_NE(reinterpret_cast<OMAPs*>(NULL), omap_from);
 304    :  
 305    :    // Load the fixups. These must exist.
 306  E :    SearchResult search_result = FindAndLoadDiaDebugStreamByName(
 307    :        kFixupDiaDebugStreamName, dia_session, pdb_fixups);
 308  E :    if (search_result != kSearchSucceeded) {
 309  i :      if (search_result == kSearchFailed) {
 310  i :        LOG(ERROR) << "PDB file does not contain a FIXUP stream. Module must be "
 311    :                      "linked with '/PROFILE' or '/DEBUGINFO:FIXUP' flag.";
 312    :      }
 313  i :      return false;
 314    :    }
 315    :  
 316    :    // Load the omap_from table. It is not necessary that one exist.
 317  E :    search_result = FindAndLoadDiaDebugStreamByName(
 318    :        kOmapFromDiaDebugStreamName, dia_session, omap_from);
 319  E :    if (search_result == kSearchErrored) {
 320  i :      LOG(ERROR) << "Error trying to read " << kOmapFromDiaDebugStreamName
 321    :                 << " stream.";
 322  i :      return false;
 323    :    }
 324    :  
 325  E :    return true;
 326  E :  }
 327    :  
 328    :  bool GetFixupDestinationAndType(const PEFile& image_file,
 329    :                                  const pdb::PdbFixup& fixup,
 330    :                                  RelativeAddress* dst_addr,
 331  E :                                  ReferenceType* ref_type) {
 332  E :    DCHECK_NE(reinterpret_cast<RelativeAddress*>(NULL), dst_addr);
 333  E :    DCHECK_NE(reinterpret_cast<ReferenceType*>(NULL), ref_type);
 334    :  
 335  E :    RelativeAddress src_addr(fixup.rva_location);
 336    :  
 337    :    // Get the destination displacement from the actual image itself. We only see
 338    :    // fixups for 32-bit references.
 339  E :    uint32_t data = 0;
 340  E :    if (!image_file.ReadImage(src_addr, &data, sizeof(data))) {
 341  i :      LOG(ERROR) << "Unable to read image data for fixup with source address "
 342    :                 << "at" << src_addr << ".";
 343  i :      return false;
 344    :    }
 345    :  
 346    :    // Translate this to a relative displacement value.
 347  E :    switch (fixup.type) {
 348    :      case pdb::PdbFixup::TYPE_ABSOLUTE: {
 349  E :        *ref_type = BlockGraph::ABSOLUTE_REF;
 350  E :        *dst_addr = RelativeAddress(image_file.AbsToRelDisplacement(data));
 351  E :        break;
 352    :      }
 353    :  
 354    :      case pdb::PdbFixup::TYPE_PC_RELATIVE: {
 355  E :        *ref_type = BlockGraph::PC_RELATIVE_REF;
 356  E :        *dst_addr = RelativeAddress(fixup.rva_location) + sizeof(data) + data;
 357  E :        break;
 358    :      }
 359    :  
 360    :      case pdb::PdbFixup::TYPE_RELATIVE: {
 361  E :        *ref_type = BlockGraph::RELATIVE_REF;
 362  E :        *dst_addr = RelativeAddress(data);
 363  E :        break;
 364    :      }
 365    :  
 366    :      default: {
 367  i :        LOG(ERROR) << "Unexpected fixup type (" << fixup.type << ").";
 368  i :        return false;
 369    :      }
 370    :    }
 371    :  
 372  E :    return true;
 373  E :  }
 374    :  
 375    :  // Creates references from the @p pdb_fixups (translating them via the
 376    :  // provided @p omap_from information if it is not empty), all while removing the
 377    :  // corresponding entries from @p reloc_set. If @p reloc_set is not empty after
 378    :  // this then the PDB fixups are out of sync with the image and we are unable to
 379    :  // safely decompose.
 380    :  //
 381    :  // @note This function deliberately ignores fixup information for the resource
 382    :  //     section. This is because chrome.dll gets modified by a manifest tool
 383    :  //     which doesn't update the FIXUPs in the corresponding PDB. They are thus
 384    :  //     out of sync. Even if they were in sync this doesn't harm us as we have no
 385    :  //     need to reach in and modify resource data.
 386    :  bool CreateReferencesFromFixupsImpl(
 387    :      const PEFile& image_file,
 388    :      const PdbFixups& pdb_fixups,
 389    :      const OMAPs& omap_from,
 390    :      PEFile::RelocSet* reloc_set,
 391  E :      BlockGraph::AddressSpace* image) {
 392  E :    DCHECK_NE(reinterpret_cast<PEFile::RelocSet*>(NULL), reloc_set);
 393  E :    DCHECK_NE(reinterpret_cast<BlockGraph::AddressSpace*>(NULL), image);
 394    :  
 395  E :    bool have_omap = !omap_from.empty();
 396  E :    size_t fixups_used = 0;
 397    :  
 398    :    // The resource section in Chrome is modified post-link by a tool that adds a
 399    :    // manifest to it. This causes all of the fixups in the resource section (and
 400    :    // anything beyond it) to be invalid. As long as the resource section is the
 401    :    // last section in the image, this is not a problem (we can safely ignore the
 402    :    // .rsrc fixups, which we know how to parse without them). However, if there
 403    :    // is a section after the resource section, things will have been shifted
 404    :    // and potentially crucial fixups will be invalid.
 405  E :    const IMAGE_SECTION_HEADER* rsrc_header = image_file.GetSectionHeader(
 406    :        kResourceSectionName);
 407  E :    RelativeAddress rsrc_start(0xffffffff);
 408  E :    RelativeAddress rsrc_end(0xffffffff);
 409  E :    if (rsrc_header != NULL) {
 410  E :      rsrc_start = RelativeAddress(rsrc_header->VirtualAddress);
 411  E :      rsrc_end = rsrc_start + rsrc_header->Misc.VirtualSize;
 412    :    }
 413    :  
 414    :    // Ensure the fixups are all valid.
 415  E :    for (size_t i = 0; i < pdb_fixups.size(); ++i) {
 416  E :      if (!pdb_fixups[i].ValidHeader()) {
 417  i :        LOG(ERROR) << "Unknown fixup header: "
 418    :                   << base::StringPrintf("0x%08X.", pdb_fixups[i].header);
 419  i :        return false;
 420    :      }
 421    :  
 422    :      // For now, we skip any offset fixups. We've only seen this in the context
 423    :      // of TLS data access, and we don't mess with TLS structures.
 424  E :      if (pdb_fixups[i].is_offset())
 425  E :        continue;
 426    :  
 427    :      // All fixups we handle should be full size pointers.
 428  E :      DCHECK_EQ(Reference::kMaximumSize, pdb_fixups[i].size());
 429    :  
 430    :      // Get the original addresses, and map them through OMAP information.
 431    :      // Normally DIA takes care of this for us, but there is no API for
 432    :      // getting DIA to give us FIXUP information, so we have to do it manually.
 433  E :      RelativeAddress src_addr(pdb_fixups[i].rva_location);
 434  E :      RelativeAddress base_addr(pdb_fixups[i].rva_base);
 435  E :      if (have_omap) {
 436  i :        src_addr = pdb::TranslateAddressViaOmap(omap_from, src_addr);
 437  i :        base_addr = pdb::TranslateAddressViaOmap(omap_from, base_addr);
 438    :      }
 439    :  
 440    :      // If the reference originates beyond the .rsrc section then we can't
 441    :      // trust it.
 442  E :      if (src_addr >= rsrc_end) {
 443  i :        LOG(ERROR) << "Found fixup originating beyond .rsrc section.";
 444  i :        return false;
 445    :      }
 446    :  
 447    :      // If the reference originates from a part of the .rsrc section, ignore it.
 448  E :      if (src_addr >= rsrc_start)
 449  E :        continue;
 450    :  
 451    :      // Get the relative address/displacement of the fixup. This logs on failure.
 452  E :      RelativeAddress dst_addr;
 453  E :      ReferenceType type = BlockGraph::RELATIVE_REF;
 454  E :      if (!GetFixupDestinationAndType(image_file, pdb_fixups[i], &dst_addr,
 455    :                                      &type)) {
 456  i :        return false;
 457    :      }
 458    :  
 459    :      // Finally, create the reference. This logs verbosely for us on failure.
 460  E :      if (!CreateReference(src_addr, Reference::kMaximumSize, type, base_addr,
 461    :                           dst_addr, image)) {
 462  i :        return false;
 463    :      }
 464    :  
 465    :      // Remove this reference from the relocs.
 466  E :      PEFile::RelocSet::iterator reloc_it = reloc_set->find(src_addr);
 467  E :      if (reloc_it != reloc_set->end()) {
 468    :        // We should only find a reloc if the fixup was of absolute type.
 469  E :        if (type != BlockGraph::ABSOLUTE_REF) {
 470  i :          LOG(ERROR) << "Found a reloc corresponding to a non-absolute fixup.";
 471  i :          return false;
 472    :        }
 473    :  
 474  E :        reloc_set->erase(reloc_it);
 475    :      }
 476    :  
 477  E :      ++fixups_used;
 478  E :    }
 479    :  
 480  E :    return true;
 481  E :  }
 482    :  
 483  E :  bool GetDataSymbolSize(IDiaSymbol* symbol, size_t* length) {
 484  E :    DCHECK_NE(reinterpret_cast<IDiaSymbol*>(NULL), symbol);
 485  E :    DCHECK_NE(reinterpret_cast<size_t*>(NULL), length);
 486    :  
 487  E :    *length = 0;
 488  E :    ScopedComPtr<IDiaSymbol> type;
 489  E :    HRESULT hr = symbol->get_type(type.Receive());
 490    :    // This happens if the symbol has no type information.
 491  E :    if (hr == S_FALSE)
 492  E :      return true;
 493  E :    if (hr != S_OK) {
 494  i :      LOG(ERROR) << "Failed to get type symbol: " << common::LogHr(hr) << ".";
 495  i :      return false;
 496    :    }
 497    :  
 498  E :    ULONGLONG ull_length = 0;
 499  E :    hr = type->get_length(&ull_length);
 500  E :    if (hr != S_OK) {
 501  i :      LOG(ERROR) << "Failed to retrieve type length properties: "
 502    :                 << common::LogHr(hr) << ".";
 503  i :      return false;
 504    :    }
 505  E :    DCHECK_LE(ull_length, 0xFFFFFFFF);
 506  E :    *length = static_cast<size_t>(ull_length);
 507    :  
 508  E :    return true;
 509  E :  }
 510    :  
 511    :  bool ScopeSymTagToLabelProperties(enum SymTagEnum sym_tag,
 512    :                                    size_t scope_count,
 513    :                                    BlockGraph::LabelAttributes* attr,
 514  E :                                    std::string* name) {
 515  E :    DCHECK_NE(reinterpret_cast<BlockGraph::LabelAttributes*>(NULL), attr);
 516  E :    DCHECK_NE(reinterpret_cast<std::string*>(NULL), name);
 517    :  
 518  E :    switch (sym_tag) {
 519    :      case SymTagFuncDebugStart: {
 520  E :        *attr = BlockGraph::DEBUG_START_LABEL;
 521  E :        *name = "<debug-start>";
 522  E :        return true;
 523    :      }
 524    :      case SymTagFuncDebugEnd: {
 525  E :        *attr = BlockGraph::DEBUG_END_LABEL;
 526  E :        *name = "<debug-end>";
 527  E :        return true;
 528    :      }
 529    :      case SymTagBlock: {
 530  E :        *attr = BlockGraph::SCOPE_START_LABEL;
 531  E :        *name = base::StringPrintf("<scope-start-%d>", scope_count);
 532  E :        return true;
 533    :      }
 534    :      default:
 535  i :        return false;
 536    :    }
 537  i :    return false;
 538  E :  }
 539    :  
 540    :  // Reads the linker module symbol stream from the given PDB file. This should
 541    :  // always exist as the last module.
 542    :  scoped_refptr<pdb::PdbStream> GetLinkerSymbolStream(
 543  E :      const pdb::PdbFile& pdb_file) {
 544    :    static const char kLinkerModuleName[] = "* Linker *";
 545    :  
 546    :    // Get the DBI stream.
 547    :    scoped_refptr<pdb::PdbStream> stream =
 548  E :        pdb_file.GetStream(pdb::kDbiStream);
 549  E :    if (stream.get() == NULL) {
 550  i :      LOG(ERROR) << "PDB does not contain a DBI stream.";
 551  i :      return false;
 552    :    }
 553    :  
 554    :    // Read the entire thing into memory before parsing it. This makes parsing
 555    :    // much faster.
 556  E :    scoped_refptr<pdb::PdbByteStream> dbi_stream(new pdb::PdbByteStream());
 557  E :    if (!dbi_stream->Init(stream.get())) {
 558  i :      LOG(ERROR) << "Failed to read DBI stream.";
 559    :    }
 560    :  
 561    :    // Parse the DBI stream.
 562  E :    pdb::DbiStream dbi;
 563  E :    if (!dbi.Read(dbi_stream.get())) {
 564  i :      LOG(ERROR) << "Unable to parse DBI stream.";
 565  i :      return false;
 566    :    }
 567    :  
 568  E :    if (dbi.modules().empty()) {
 569  i :      LOG(ERROR) << "DBI stream contains no modules.";
 570  i :      return false;
 571    :    }
 572    :  
 573    :    // The last module has always been observed to be the linker module.
 574  E :    const pdb::DbiModuleInfo& linker = dbi.modules().back();
 575  E :    if (linker.module_name() != kLinkerModuleName) {
 576  i :      LOG(ERROR) << "Last module is not the linker module.";
 577  i :      return false;
 578    :    }
 579    :  
 580    :    // Get the symbol stream.
 581  E :    stream = pdb_file.GetStream(linker.module_info_base().stream);
 582  E :    if (stream.get() == NULL) {
 583  i :      LOG(ERROR) << "Unable to open linker symbol stream.";
 584  i :      return false;
 585    :    }
 586    :  
 587    :    // Also read it entirely into memory for faster parsing.
 588  E :    scoped_refptr<pdb::PdbByteStream> symbols(new pdb::PdbByteStream());
 589  E :    if (!symbols->Init(stream.get())) {
 590  i :      LOG(ERROR) << "Failed to read linker symbol stream.";
 591    :    }
 592    :  
 593  E :    return symbols;
 594  E :  }
 595    :  
 596    :  // Parses a symbol from a PDB symbol stream. The @p buffer is populated with the
 597    :  // data and upon success this returns the symbol directly cast onto the
 598    :  // @p buffer data. On failure this returns NULL.
 599    :  template <typename SymbolType>
 600    :  const SymbolType* ParseSymbol(uint16_t symbol_length,
 601    :                                common::BinaryStreamReader* reader,
 602  E :                                std::vector<uint8_t>* buffer) {
 603  E :    DCHECK_NE(static_cast<common::BinaryStreamReader*>(nullptr), reader);
 604  E :    DCHECK_NE(static_cast<std::vector<uint8_t>*>(nullptr), buffer);
 605    :  
 606  E :    buffer->clear();
 607    :  
 608  E :    if (symbol_length < sizeof(SymbolType)) {
 609  i :      LOG(ERROR) << "Symbol too small for casting.";
 610  i :      return NULL;
 611    :    }
 612    :  
 613  E :    common::BinaryStreamParser parser(reader);
 614  E :    if (!parser.ReadMultiple(symbol_length, buffer)) {
 615  i :      LOG(ERROR) << "Failed to read symbol.";
 616  i :      return NULL;
 617    :    }
 618    :  
 619  E :    return reinterpret_cast<const SymbolType*>(buffer->data());
 620  E :  }
 621    :  
 622    :  // If the given run of bytes consists of a single value repeated, returns that
 623    :  // value. Otherwise, returns -1.
 624  E :  int RepeatedValue(const uint8_t* data, size_t size) {
 625  E :    DCHECK_NE(reinterpret_cast<uint8_t*>(NULL), data);
 626  E :    const uint8_t* data_end = data + size;
 627  E :    uint8_t value = *(data++);
 628  E :    for (; data < data_end; ++data) {
 629  E :      if (*data != value)
 630  i :        return -1;
 631  E :    }
 632  E :    return value;
 633  E :  }
 634    :  
 635    :  // Searches through the given image layout graph, and labels blocks that are
 636    :  // simply padding blocks.
 637  E :  bool FindPaddingBlocks(ImageLayout* image_layout) {
 638  E :    DCHECK_NE(reinterpret_cast<ImageLayout*>(NULL), image_layout);
 639    :  
 640  E :    BlockGraph* block_graph = image_layout->blocks.graph();
 641  E :    DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
 642    :  
 643    :    BlockGraph::BlockMap::iterator block_it =
 644  E :        block_graph->blocks_mutable().begin();
 645  E :    for (; block_it != block_graph->blocks_mutable().end(); ++block_it) {
 646  E :      Block& block = block_it->second;
 647    :  
 648    :      // Padding blocks must not have any symbol information: no labels,
 649    :      // no references, no referrers, and they must be a gap block.
 650    :      if (block.labels().size() != 0 ||
 651    :          block.references().size() != 0 ||
 652  E :          block.referrers().size() != 0 ||
 653    :          (block.attributes() & BlockGraph::GAP_BLOCK) == 0) {
 654  E :        continue;
 655    :      }
 656    :  
 657  E :      switch (block.type()) {
 658    :        // Code blocks should be fully defined and consist of only int3s.
 659    :        case BlockGraph::CODE_BLOCK: {
 660  E :          if (block.data_size() != block.size() ||
 661    :              RepeatedValue(block.data(), block.data_size()) != kInt3)
 662  i :            continue;
 663  E :          break;
 664    :        }
 665    :  
 666    :        // Data blocks should be uninitialized or have fully defined data
 667    :        // consisting only of zeros.
 668    :        default: {
 669  E :          DCHECK_EQ(BlockGraph::DATA_BLOCK, block.type());
 670  E :          if (block.data_size() == 0)  // Uninitialized data blocks are padding.
 671  E :            break;
 672  E :          if (block.data_size() != block.size() ||
 673    :              RepeatedValue(block.data(), block.data_size()) != 0)
 674  i :            continue;
 675    :        }
 676    :      }
 677    :  
 678    :      // If we fall through to this point, then the block is a padding block.
 679  E :      block.set_attribute(BlockGraph::PADDING_BLOCK);
 680  E :    }
 681    :  
 682  E :    return true;
 683  E :  }
 684    :  
 685  E :  bool CodeBlockHasAlignedJumpTables(const Block* block) {
 686  E :    DCHECK_NE(reinterpret_cast<Block*>(NULL), block);
 687  E :    DCHECK_EQ(BlockGraph::CODE_BLOCK, block->type());
 688    :  
 689    :    // Iterate over the labels of this block looking for jump tables.
 690  E :    bool has_jump_tables = false;
 691    :    Block::LabelMap::const_iterator label_it =
 692  E :        block->labels().begin();
 693  E :    for (; label_it != block->labels().end(); ++label_it) {
 694  E :      if (!label_it->second.has_attributes(BlockGraph::JUMP_TABLE_LABEL))
 695  E :        continue;
 696    :  
 697  E :      has_jump_tables = true;
 698    :  
 699    :      // If the jump table is misaligned we can return false immediately.
 700  E :      if (label_it->first % kPointerSize != 0)
 701  i :        return false;
 702  E :    }
 703    :  
 704  E :    return has_jump_tables;
 705  E :  }
 706    :  
 707  E :  bool AlignCodeBlocks(ImageLayout* image_layout) {
 708  E :    DCHECK_NE(reinterpret_cast<ImageLayout*>(NULL), image_layout);
 709    :  
 710    :    BlockGraph::AddressSpace::RangeMapConstIter block_it =
 711  E :        image_layout->blocks.begin();
 712  E :    for (; block_it != image_layout->blocks.end(); ++block_it) {
 713  E :      Block* block = block_it->second;
 714  E :      if (block->type() != BlockGraph::CODE_BLOCK)
 715  E :        continue;
 716    :  
 717    :      // Preserve alignment for anything built by an unknown compiler. There may
 718    :      // be inline data that has alignment requirements we don't know about. SSE
 719    :      // and AVX instructions have 8 and 16 byte alignments, so we preserve
 720    :      // these. It is not possible for a function to contain both instructions
 721    :      // and data with an alignment constraint unless the size of the block is at
 722    :      // least twice the alignment; this is used as a simple filter to avoid
 723    :      // adding alignment where unnecessary.
 724  E :      if (block->attributes() & BlockGraph::BUILT_BY_UNSUPPORTED_COMPILER) {
 725  E :        uint32_t align = std::min(16u, static_cast<uint32_t>(
 726    :            block_it->first.start().GetAlignment()));
 727  E :        if (align >= 8 && block->size() >= 2 * align) {
 728  E :          VLOG(1) << "Preserving alignment of " << BlockInfo(block) << " as "
 729    :                  << align << ".";
 730  E :          block->set_alignment(align);
 731  E :          continue;
 732    :        }
 733    :      }
 734    :  
 735    :      // We only care about code blocks that are already 4-byte aligned but
 736    :      // whose explicit alignment is currently less than that.
 737  E :      if (block->alignment() >= kPointerSize)
 738  i :        continue;
 739  E :      if (block_it->first.start().value() % kPointerSize != 0)
 740  E :        continue;
 741    :  
 742    :      // Inspect them to see if they have aligned jump tables. If they do,
 743    :      // set the alignment of the block itself.
 744  E :      if (CodeBlockHasAlignedJumpTables(block_it->second))
 745  E :        block->set_alignment(kPointerSize);
 746  E :    }
 747    :  
 748  E :    return true;
 749  E :  }
 750    :  
 751    :  void GuessDataBlockAlignment(uint32_t max_alignment,
 752    :                               RelativeAddress block_rva,
 753  E :                               Block* block) {
 754  E :    DCHECK_NE(static_cast<Block*>(NULL), block);
 755  E :    DCHECK_EQ(BlockGraph::DATA_BLOCK, block->type());
 756  E :    uint32_t alignment = static_cast<uint32_t>(block_rva.GetAlignment());
 757    :    // Cap the alignment.
 758  E :    if (alignment > max_alignment)
 759  E :      alignment = max_alignment;
 760  E :    block->set_alignment(alignment);
 761  E :  }
 762    :  
 763    :  void GuessDataBlockAlignments(const PEFile& pe_file,
 764  E :                                ImageLayout* image_layout) {
 765  E :    DCHECK_NE(static_cast<ImageLayout*>(NULL), image_layout);
 766    :  
 767    :    uint32_t max_alignment =
 768  E :        pe_file.nt_headers()->OptionalHeader.SectionAlignment;
 769    :  
 770  E :    BlockGraph::AddressSpace::RangeMapConstIter it = image_layout->blocks.begin();
 771  E :    for (; it != image_layout->blocks.end(); ++it) {
 772  E :      RelativeAddress block_rva = it->first.start();
 773  E :      BlockGraph::Block* block = it->second;
 774  E :      if (block->type() != BlockGraph::DATA_BLOCK)
 775  E :        continue;
 776  E :      GuessDataBlockAlignment(max_alignment, block_rva, block);
 777  E :    }
 778  E :  }
 779    :  
 780    :  }  // namespace
 781    :  
 782    :  // We use ", " as a separator between symbol names. We sometimes see commas
 783    :  // in symbol names but do not see whitespace. Thus, this provides a useful
 784    :  // separator that is also human friendly to read.
 785    :  const char Decomposer::kLabelNameSep[] = ", ";
 786    :  
 787    :  // This is by CreateBlocksFromCoffGroups to communicate shared state to
 788    :  // VisitLinkerSymbol via the VisitSymbols helper function.
 789    :  struct Decomposer::VisitLinkerSymbolContext {
 790    :    int current_group_index;
 791    :    std::string current_group_prefix;
 792    :    RelativeAddress current_group_start;
 793    :  
 794    :    // These are the set of patterns that indicate bracketing groups. They
 795    :    // should match both the opening and the closing symbol, and have at least
 796    :    // one match group returning the common prefix.
 797    :    std::vector<RE> bracketing_groups;
 798    :  
 799  E :    VisitLinkerSymbolContext() : current_group_index(-1) {
 800    :      // Matches groups like: .CRT$XCA -> .CRT$XCZ
 801  E :      bracketing_groups.push_back(RE("(\\.CRT\\$X.)[AZ]"));
 802    :      // Matches groups like: .rtc$IAA -> .rtc$IZZ
 803  E :      bracketing_groups.push_back(RE("(\\.rtc\\$.*)(AA|ZZ)"));
 804    :      // Matches exactly: ATL$__a -> ATL$__z
 805  E :      bracketing_groups.push_back(RE("(ATL\\$__)[az]"));
 806    :      // Matches exactly: .tls -> .tls$ZZZ
 807  E :      bracketing_groups.push_back(RE("(\\.tls)(\\$ZZZ)?"));
 808  E :    }
 809    :  
 810    :   private:
 811    :    DISALLOW_COPY_AND_ASSIGN(VisitLinkerSymbolContext);
 812    :  };
 813    :  
 814    :  Decomposer::Decomposer(const PEFile& image_file)
 815  E :      : image_file_(image_file), image_layout_(NULL), image_(NULL),
 816  E :        current_block_(NULL), current_scope_count_(0) {
 817  E :  }
 818    :  
 819  E :  bool Decomposer::Decompose(ImageLayout* image_layout) {
 820  E :    DCHECK_NE(reinterpret_cast<ImageLayout*>(NULL), image_layout);
 821    :  
 822    :    // The temporaries should be NULL.
 823  E :    DCHECK_EQ(reinterpret_cast<ImageLayout*>(NULL), image_layout_);
 824  E :    DCHECK_EQ(reinterpret_cast<BlockGraph::AddressSpace*>(NULL), image_);
 825    :  
 826    :    // Set the image format.
 827  E :    image_layout->blocks.graph()->set_image_format(BlockGraph::PE_IMAGE);
 828    :  
 829    :    // We start by finding the PDB path.
 830  E :    if (!FindAndValidatePdbPath())
 831  E :      return false;
 832  E :    DCHECK(!pdb_path_.empty());
 833    :  
 834    :    // Load the serialized block-graph from the PDB if it exists. This allows
 835    :    // round-trip decomposition.
 836  E :    bool stream_exists = false;
 837  E :    if (LoadBlockGraphFromPdb(
 838    :            pdb_path_, image_file_, image_layout, &stream_exists)) {
 839  E :      return true;
 840  E :    } else if (stream_exists) {
 841    :      // If the stream exists but hasn't been loaded we return an error. At this
 842    :      // point an error message has already been logged if there was one.
 843  i :      return false;
 844    :    }
 845    :  
 846    :    // At this point a full decomposition needs to be performed.
 847  E :    image_layout_ = image_layout;
 848  E :    image_ = &(image_layout->blocks);
 849  E :    bool success = DecomposeImpl();
 850  E :    image_layout_ = NULL;
 851  E :    image_ = NULL;
 852    :  
 853  E :    return success;
 854  E :  }
 855    :  
 856  E :  bool Decomposer::FindAndValidatePdbPath() {
 857    :    // Manually find the PDB path if it is not specified.
 858  E :    if (pdb_path_.empty()) {
 859  E :      if (!FindPdbForModule(image_file_.path(), &pdb_path_) ||
 860    :          pdb_path_.empty()) {
 861  i :        LOG(ERROR) << "Unable to find PDB file for module: "
 862    :                   << image_file_.path().value();
 863  i :        return false;
 864    :      }
 865    :    }
 866  E :    DCHECK(!pdb_path_.empty());
 867    :  
 868  E :    if (!base::PathExists(pdb_path_)) {
 869  E :      LOG(ERROR) << "Path not found: " << pdb_path_.value();
 870  E :      return false;
 871    :    }
 872    :  
 873  E :    if (!pe::PeAndPdbAreMatched(image_file_.path(), pdb_path_)) {
 874  i :      LOG(ERROR) << "PDB file \"" << pdb_path_.value() << "\" does not match "
 875    :                 << "module \"" << image_file_.path().value() << "\".";
 876  i :      return false;
 877    :    }
 878    :  
 879  E :    return true;
 880  E :  }
 881    :  
 882    :  bool Decomposer::LoadBlockGraphFromPdbStream(
 883    :      const PEFile& image_file,
 884    :      pdb::PdbStream* block_graph_stream,
 885  E :      ImageLayout* image_layout) {
 886  E :    DCHECK_NE(reinterpret_cast<pdb::PdbStream*>(NULL), block_graph_stream);
 887  E :    DCHECK_NE(reinterpret_cast<ImageLayout*>(NULL), image_layout);
 888  E :    LOG(INFO) << "Reading block-graph and image layout from the PDB.";
 889    :  
 890    :    // Initialize an input archive pointing to the stream.
 891  E :    scoped_refptr<pdb::PdbByteStream> byte_stream = new pdb::PdbByteStream();
 892  E :    if (!byte_stream->Init(block_graph_stream))
 893  i :      return false;
 894  E :    DCHECK_NE(reinterpret_cast<pdb::PdbByteStream*>(NULL), byte_stream.get());
 895    :  
 896  E :    core::ScopedInStreamPtr pdb_in_stream;
 897  E :    pdb_in_stream.reset(core::CreateByteInStream(
 898    :        byte_stream->data(), byte_stream->data() + byte_stream->length()));
 899    :  
 900    :    // Read the header.
 901  E :    uint32_t stream_version = 0;
 902  E :    unsigned char compressed = 0;
 903    :    if (!pdb_in_stream->Read(sizeof(stream_version),
 904  E :                             reinterpret_cast<core::Byte*>(&stream_version)) ||
 905    :        !pdb_in_stream->Read(sizeof(compressed),
 906    :                             reinterpret_cast<core::Byte*>(&compressed))) {
 907  i :      LOG(ERROR) << "Failed to read existing Syzygy block-graph stream header.";
 908  i :      return false;
 909    :    }
 910    :  
 911    :    // Check the stream version.
 912  E :    if (stream_version != pdb::kSyzygyBlockGraphStreamVersion) {
 913  E :      LOG(ERROR) << "PDB contains an unsupported Syzygy block-graph stream"
 914    :                 << " version (got " << stream_version << ", expected "
 915    :                 << pdb::kSyzygyBlockGraphStreamVersion << ").";
 916  E :      return false;
 917    :    }
 918    :  
 919    :    // If the stream is compressed insert the decompression filter.
 920  E :    core::InStream* in_stream = pdb_in_stream.get();
 921  E :    std::unique_ptr<core::ZInStream> zip_in_stream;
 922  E :    if (compressed != 0) {
 923  E :      zip_in_stream.reset(new core::ZInStream(in_stream));
 924  E :      if (!zip_in_stream->Init()) {
 925  i :        LOG(ERROR) << "Unable to initialize ZInStream.";
 926  i :        return false;
 927    :      }
 928  E :      in_stream = zip_in_stream.get();
 929    :    }
 930    :  
 931    :    // Deserialize the image-layout.
 932  E :    core::NativeBinaryInArchive in_archive(in_stream);
 933  E :    block_graph::BlockGraphSerializer::Attributes attributes = 0;
 934  E :    if (!LoadBlockGraphAndImageLayout(
 935    :        image_file, &attributes, image_layout, &in_archive)) {
 936  i :      LOG(ERROR) << "Failed to deserialize block-graph and image layout.";
 937  i :      return false;
 938    :    }
 939    :  
 940  E :    return true;
 941  E :  }
 942    :  
 943    :  bool Decomposer::LoadBlockGraphFromPdb(const base::FilePath& pdb_path,
 944    :                                            const PEFile& image_file,
 945    :                                            ImageLayout* image_layout,
 946  E :                                            bool* stream_exists) {
 947  E :    DCHECK_NE(reinterpret_cast<ImageLayout*>(NULL), image_layout);
 948  E :    DCHECK_NE(reinterpret_cast<bool*>(NULL), stream_exists);
 949    :  
 950  E :    pdb::PdbFile pdb_file;
 951  E :    pdb::PdbReader pdb_reader;
 952  E :    if (!pdb_reader.Read(pdb_path, &pdb_file)) {
 953  i :      LOG(ERROR) << "Unable to read the PDB named \"" << pdb_path.value()
 954    :                 << "\".";
 955  i :      return NULL;
 956    :    }
 957    :  
 958    :    // Try to get the block-graph stream from the PDB.
 959  E :    scoped_refptr<pdb::PdbStream> block_graph_stream;
 960    :    if (!pdb::LoadNamedStreamFromPdbFile(pdb::kSyzygyBlockGraphStreamName,
 961    :                                         &pdb_file,
 962  E :                                         &block_graph_stream) ||
 963    :        block_graph_stream.get() == NULL) {
 964  E :      *stream_exists = false;
 965  E :      return false;
 966    :    }
 967  E :    if (block_graph_stream->length() == 0) {
 968  i :      *stream_exists = false;
 969  i :      LOG(WARNING) << "The block-graph stream is empty, ignoring it.";
 970  i :      return false;
 971    :    }
 972    :  
 973    :    // The PDB contains a block-graph stream, the block-graph and the image layout
 974    :    // will be read from this stream.
 975  E :    *stream_exists = true;
 976  E :    if (!LoadBlockGraphFromPdbStream(image_file, block_graph_stream.get(),
 977    :                                     image_layout)) {
 978  i :      return false;
 979    :    }
 980    :  
 981  E :    return true;
 982  E :  }
 983    :  
 984  E :  bool Decomposer::DecomposeImpl() {
 985    :    // Instantiate and initialize our Debug Interface Access session. This logs
 986    :    // verbosely for us.
 987  E :    ScopedComPtr<IDiaDataSource> dia_source;
 988  E :    ScopedComPtr<IDiaSession> dia_session;
 989  E :    ScopedComPtr<IDiaSymbol> global;
 990  E :    if (!InitializeDia(image_file_, pdb_path_, dia_source.Receive(),
 991    :                       dia_session.Receive(), global.Receive())) {
 992  i :      return false;
 993    :    }
 994    :  
 995    :    // Copy the image headers to the layout.
 996  E :    CopySectionHeadersToImageLayout(
 997    :        image_file_.nt_headers()->FileHeader.NumberOfSections,
 998    :        image_file_.section_headers(),
 999    :        &(image_layout_->sections));
1000    :  
1001    :    // Create the sections in the underlying block-graph.
1002  E :    if (!CopySectionInfoToBlockGraph(image_file_, image_->graph()))
1003  i :      return false;
1004    :  
1005    :    // We scope the first few operations so that we don't keep the intermediate
1006    :    // references around any longer than we have to.
1007    :    {
1008  E :      IntermediateReferences references;
1009    :  
1010    :      // First we parse out the PE blocks.
1011  E :      VLOG(1) << "Parsing PE blocks.";
1012  E :      if (!CreatePEImageBlocksAndReferences(&references))
1013  i :        return false;
1014    :  
1015    :      // Now we parse the COFF group symbols from the linker's symbol stream.
1016    :      // These indicate things like static initializers, which must stay together
1017    :      // in a single block.
1018  E :      VLOG(1) << "Parsing COFF groups.";
1019  E :      if (!CreateBlocksFromCoffGroups())
1020  i :        return false;
1021    :  
1022    :      // Next we parse out section contributions. Some of these may coincide with
1023    :      // existing PE parsed blocks, but when they do we expect them to be exact
1024    :      // collisions.
1025  E :      VLOG(1) << "Parsing section contributions.";
1026  E :      if (!CreateBlocksFromSectionContribs(dia_session.get()))
1027  i :        return false;
1028    :  
1029  E :      VLOG(1) << "Finding cold blocks.";
1030  E :      if (!FindColdBlocksFromCompilands(dia_session.get()))
1031  i :        return false;
1032    :  
1033    :      // Flesh out the rest of the image with gap blocks.
1034  E :      VLOG(1) << "Creating gap blocks.";
1035  E :      if (!CreateGapBlocks())
1036  i :        return false;
1037    :  
1038    :      // Finalize the PE-parsed intermediate references.
1039  E :      VLOG(1) << "Finalizing intermediate references.";
1040  E :      if (!FinalizeIntermediateReferences(references))
1041  i :        return false;
1042  E :    }
1043    :  
1044    :    // Parse the fixups and use them to create references.
1045  E :    VLOG(1) << "Parsing fixups.";
1046  E :    if (!CreateReferencesFromFixups(dia_session.get()))
1047  i :      return false;
1048    :  
1049    :    // Annotate the block-graph with symbol information.
1050  E :    VLOG(1) << "Parsing symbols.";
1051  E :    if (!ProcessSymbols(global.get()))
1052  i :      return false;
1053    :  
1054    :    // Now, find and label any padding blocks.
1055  E :    VLOG(1) << "Labeling padding blocks.";
1056  E :    if (!FindPaddingBlocks(image_layout_))
1057  i :      return false;
1058    :  
1059    :    // Set the alignment on code blocks with jump tables. This ensures that the
1060    :    // jump tables remain aligned post-transform.
1061  E :    VLOG(1) << "Calculating code block alignments.";
1062  E :    if (!AlignCodeBlocks(image_layout_))
1063  i :      return false;
1064    :  
1065    :    // Set the alignment of data blocks. This is not precise in that it simply
1066    :    // guesses the alignment based on the address of the block. Some instructions
1067    :    // have alignment requirements on their data but unfortunately the PDB does
1068    :    // not contain explicit alignment information.
1069  E :    VLOG(1) << "Guessing data block alignments.";
1070  E :    GuessDataBlockAlignments(image_file_, image_layout_);
1071    :  
1072  E :    return true;
1073  E :  }
1074    :  
1075    :  bool Decomposer::CreatePEImageBlocksAndReferences(
1076  E :      IntermediateReferences* references) {
1077  E :    DCHECK_NE(reinterpret_cast<IntermediateReferences*>(NULL), references);
1078    :  
1079  E :    PEFileParser::AddReferenceCallback add_reference(
1080    :        base::Bind(&AddIntermediateReference, base::Unretained(references)));
1081  E :    PEFileParser parser(image_file_, image_, add_reference);
1082  E :    PEFileParser::PEHeader header;
1083  E :    if (!parser.ParseImage(&header)) {
1084  i :      LOG(ERROR) << "Unable to parse PE image.";
1085  i :      return false;
1086    :    }
1087    :  
1088  E :    return true;
1089  E :  }
1090    :  
1091  E :  bool Decomposer::CreateBlocksFromCoffGroups() {
1092  E :    pdb::PdbFile pdb_file;
1093  E :    pdb::PdbReader pdb_reader;
1094  E :    if (!pdb_reader.Read(pdb_path_, &pdb_file)) {
1095  i :      LOG(ERROR) << "Failed to load PDB: " << pdb_path_.value();
1096  i :      return false;
1097    :    }
1098    :  
1099  E :    scoped_refptr<pdb::PdbStream> symbols = GetLinkerSymbolStream(pdb_file);
1100    :  
1101    :    // Process the symbols in the linker module symbol stream.
1102  E :    VisitLinkerSymbolContext context;
1103  E :    pdb::VisitSymbolsCallback callback = base::Bind(
1104    :        &Decomposer::VisitLinkerSymbol,
1105    :        base::Unretained(this),
1106    :        base::Unretained(&context));
1107  E :    if (!pdb::VisitSymbols(callback, 0, symbols->length(), true, symbols.get()))
1108  i :      return false;
1109    :  
1110    :    // Bail if we did not encounter a closing bracketing symbol where one was
1111    :    // expected.
1112  E :    if (context.current_group_index != -1) {
1113  i :      LOG(ERROR) << "Unable to close bracketed COFF group \""
1114    :                 << context.current_group_prefix << "\".";
1115  i :      return false;
1116    :    }
1117    :  
1118  E :    return true;
1119  E :  }
1120    :  
1121  E :  bool Decomposer::CreateBlocksFromSectionContribs(IDiaSession* session) {
1122  E :    ScopedComPtr<IDiaEnumSectionContribs> section_contribs;
1123  E :    SearchResult search_result = FindDiaTable(session,
1124    :                                              section_contribs.Receive());
1125  E :    if (search_result != kSearchSucceeded) {
1126  i :      if (search_result == kSearchFailed)
1127  i :        LOG(ERROR) << "No section contribution table found.";
1128  i :      return false;
1129    :    }
1130    :  
1131  E :    size_t rsrc_id = image_file_.GetSectionIndex(kResourceSectionName);
1132    :  
1133  E :    LONG count = 0;
1134  E :    if (section_contribs->get_Count(&count) != S_OK) {
1135  i :      LOG(ERROR) << "Failed to get section contributions enumeration length.";
1136  i :      return false;
1137    :    }
1138    :  
1139  E :    for (LONG visited = 0; visited < count; ++visited) {
1140  E :      ScopedComPtr<IDiaSectionContrib> section_contrib;
1141  E :      ULONG fetched = 0;
1142  E :      HRESULT hr = section_contribs->Next(1, section_contrib.Receive(), &fetched);
1143    :      // The standard way to end an enumeration (according to the docs) is by
1144    :      // returning S_FALSE and setting fetched to 0. We don't actually see this,
1145    :      // but it wouldn't be an error if we did.
1146  E :      if (hr == S_FALSE && fetched == 0)
1147  i :        break;
1148  E :      if (hr != S_OK) {
1149  i :        LOG(ERROR) << "Failed to get DIA section contribution: "
1150    :                   << common::LogHr(hr) << ".";
1151  i :        return false;
1152    :      }
1153    :      // We actually end up seeing S_OK and fetched == 0 when the enumeration
1154    :      // terminates, which goes against the publishes documentations.
1155  E :      if (fetched == 0)
1156  i :        break;
1157    :  
1158  E :      DWORD rva = 0;
1159  E :      DWORD length = 0;
1160  E :      DWORD section_id = 0;
1161  E :      BOOL code = FALSE;
1162  E :      ScopedComPtr<IDiaSymbol> compiland;
1163  E :      ScopedBstr bstr_compiland_name;
1164    :      if ((hr = section_contrib->get_relativeVirtualAddress(&rva)) != S_OK ||
1165    :          (hr = section_contrib->get_length(&length)) != S_OK ||
1166    :          (hr = section_contrib->get_addressSection(&section_id)) != S_OK ||
1167    :          (hr = section_contrib->get_code(&code)) != S_OK ||
1168  E :          (hr = section_contrib->get_compiland(compiland.Receive())) != S_OK ||
1169    :          (hr = compiland->get_name(bstr_compiland_name.Receive())) != S_OK) {
1170  i :        LOG(ERROR) << "Failed to get section contribution properties: "
1171    :                   << common::LogHr(hr) << ".";
1172  i :        return false;
1173    :      }
1174    :  
1175    :      // Determine if this function was built by a supported compiler.
1176    :      bool is_built_by_supported_compiler =
1177  E :          IsBuiltBySupportedCompiler(compiland.get());
1178    :  
1179    :      // DIA numbers sections from 1 to n, while we do 0 to n - 1.
1180  E :      DCHECK_LT(0u, section_id);
1181  E :      --section_id;
1182    :  
1183    :      // We don't parse the resource section, as it is parsed by the PEFileParser.
1184  E :      if (section_id == rsrc_id)
1185  E :        continue;
1186    :  
1187  E :      std::string compiland_name;
1188  E :      if (!base::WideToUTF8(bstr_compiland_name, bstr_compiland_name.Length(),
1189    :                            &compiland_name)) {
1190  i :        LOG(ERROR) << "Failed to convert compiland name to UTF8.";
1191  i :        return false;
1192    :      }
1193    :  
1194    :      // Give a name to the block based on the basename of the object file. This
1195    :      // will eventually be replaced by the full symbol name, if one exists for
1196    :      // the block.
1197  E :      size_t last_component = compiland_name.find_last_of('\\');
1198  E :      size_t extension = compiland_name.find_last_of('.');
1199  E :      if (last_component == std::string::npos) {
1200  E :        last_component = 0;
1201  E :      } else {
1202    :        // We don't want to include the last slash.
1203  E :        ++last_component;
1204    :      }
1205  E :      if (extension < last_component)
1206  i :        extension = compiland_name.size();
1207  E :      std::string name = compiland_name.substr(last_component,
1208    :                                               extension - last_component);
1209    :  
1210    :      // TODO(chrisha): We see special section contributions with the name
1211    :      //     "* CIL *". These are concatenations of data symbols and can very
1212    :      //     likely be chunked using symbols directly. A cursory visual inspection
1213    :      //     of symbol names hints that these might be related to WPO.
1214    :  
1215    :      // Create the block.
1216    :      BlockType block_type =
1217  E :          code ? BlockGraph::CODE_BLOCK : BlockGraph::DATA_BLOCK;
1218  E :      Block* block = CreateBlockOrFindCoveringPeBlock(
1219    :          block_type, RelativeAddress(rva), length, name);
1220  E :      if (block == NULL) {
1221  i :        LOG(ERROR) << "Unable to create block for compiland \""
1222    :                   << compiland_name << "\".";
1223  i :        return false;
1224    :      }
1225    :  
1226    :      // Set the block compiland name.
1227  E :      block->set_compiland_name(compiland_name);
1228    :  
1229    :      // Set the block attributes.
1230  E :      block->set_attribute(BlockGraph::SECTION_CONTRIB);
1231  E :      if (!is_built_by_supported_compiler)
1232  E :        block->set_attribute(BlockGraph::BUILT_BY_UNSUPPORTED_COMPILER);
1233  E :    }
1234    :  
1235  E :    return true;
1236  E :  }
1237    :  
1238  E :  bool Decomposer::FindColdBlocksFromCompilands(IDiaSession* session) {
1239    :    // Detect hot/cold code separation. Some blocks are outside the function
1240    :    // address range and must be handled as separate blocks. When building
1241    :    // with PGO, the compiler can split functions into "hot" and "cold" blocks,
1242    :    // and move the "cold" blocks out to separate pages, so the function can be
1243    :    // noncontiguous.
1244  E :    ScopedComPtr<IDiaSymbol> global;
1245  E :    if (session->get_globalScope(global.Receive()) != S_OK) {
1246  i :      LOG(ERROR) << "Cannot get global symbol.";
1247  i :      return false;
1248    :    }
1249    :  
1250    :    // Find compilands within the global scope.
1251  E :    ScopedComPtr<IDiaEnumSymbols> compilands;
1252    :    HRESULT status =
1253  E :        global->findChildren(SymTagCompiland, NULL, 0, compilands.Receive());
1254  E :    if (status != S_OK) {
1255  i :      LOG(ERROR) << "Finding compilands failed on the global symbol: "
1256    :                 << common::LogHr(status) << ".";
1257  i :      return false;
1258    :    }
1259    :  
1260    :    // For each compiland, process its lexical blocks.
1261  E :    while (true) {
1262  E :      ULONG count = 0;
1263  E :      ScopedComPtr<IDiaSymbol> compiland;
1264  E :      if (compilands->Next(1, compiland.Receive(), &count) != S_OK ||
1265    :          count != 1) {
1266  E :        break;
1267    :      }
1268    :  
1269  E :      ScopedComPtr<IDiaEnumSymbols> compiland_blocks;
1270  E :      status = compiland->findChildren(SymTagBlock,
1271    :                                       NULL,
1272    :                                       0,
1273    :                                       compiland_blocks.Receive());
1274  E :      if (status != S_OK) {
1275  i :        LOG(ERROR) << "Finding blocks failed on compiland: "
1276    :                   << common::LogHr(status) << ".";
1277  i :        return false;
1278    :      }
1279    :  
1280  E :      LONG blocks_count = 0;
1281  E :      if (compiland_blocks->get_Count(&blocks_count) != S_OK) {
1282  i :        LOG(ERROR) << "Failed to get compiland blocks enumeration length.";
1283  i :        return false;
1284    :      }
1285    :  
1286  E :      for (LONG block_index = 0; block_index < blocks_count; ++block_index) {
1287  E :        ScopedComPtr<IDiaSymbol> compiland_block;
1288  E :        ULONG fetched = 0;
1289    :  
1290  E :        status = compiland_blocks->Next(1, compiland_block.Receive(), &fetched);
1291  E :        if (status == S_FALSE && fetched == 0)
1292  i :          break;
1293  E :        if (status != S_OK) {
1294  i :            LOG(ERROR) << "Failed to get function block: "
1295    :                       << common::LogHr(status) << ".";
1296  i :          return false;
1297    :        }
1298  E :        if (fetched == 0)
1299  i :          break;
1300    :  
1301  E :        ScopedComPtr<IDiaSymbol> parent;
1302  E :        DWORD parent_tag = 0;
1303  E :        if (compiland_block->get_lexicalParent(parent.Receive()) != S_OK ||
1304    :            parent->get_symTag(&parent_tag) != S_OK) {
1305  i :          LOG(ERROR) << "Cannot retrieve block parent.";
1306  i :          return false;
1307    :        }
1308    :  
1309    :        // Only consider function block.
1310  E :        if (parent_tag != SymTagFunction)
1311  i :          continue;
1312    :  
1313    :        // Get relative adresses.
1314    :        DWORD func_rva, block_rva;
1315    :        ULONGLONG func_length;
1316    :        if (compiland_block->get_relativeVirtualAddress(&block_rva) != S_OK ||
1317  E :            parent->get_relativeVirtualAddress(&func_rva) != S_OK ||
1318    :            parent->get_length(&func_length) != S_OK) {
1319  i :          LOG(ERROR) << "Cannot retrieve parent address range.";
1320  i :          return false;
1321    :        }
1322    :  
1323    :        // Retrieve the function block.
1324  E :        Block* func_block = image_->GetBlockByAddress(RelativeAddress(func_rva));
1325  E :        if (func_block == NULL) {
1326  i :          LOG(ERROR) << "Cannot retrieve parent block.";
1327  i :          return false;
1328    :        }
1329    :  
1330    :        // Skip blocks within the range of its parent.
1331  E :        if (block_rva >= func_rva && block_rva <= func_rva + func_length)
1332  i :          continue;
1333    :  
1334    :        // A cold block is detected and needs special handling.
1335  E :        Block* cold_block = image_->GetBlockByAddress(RelativeAddress(block_rva));
1336  E :        if (cold_block == NULL) {
1337  i :          LOG(ERROR) << "Cannot retrieve parent block.";
1338  i :          return false;
1339    :        }
1340    :  
1341  E :        RelativeAddress cold_block_addr;
1342  E :        if (!image_->GetAddressOf(cold_block, &cold_block_addr)) {
1343  i :          LOG(ERROR) << "Cannot retrieve cold block address.";
1344  i :          return false;
1345    :        }
1346    :  
1347    :        // Add cold_block as a child of the function block.
1348  E :        cold_blocks_[func_block][cold_block_addr] = cold_block;
1349    :  
1350    :        // Set the parent relation for blocks belonging to the function block.
1351  E :        cold_blocks_parent_[func_block] = func_block;
1352  E :        cold_blocks_parent_[cold_block] = func_block;
1353  E :      }
1354  E :    }
1355    :  
1356  E :    return true;
1357  E :  }
1358    :  
1359  E :  bool Decomposer::CreateGapBlocks() {
1360  E :    size_t num_sections = image_file_.nt_headers()->FileHeader.NumberOfSections;
1361    :  
1362    :    // Iterate through all the image sections.
1363  E :    for (size_t i = 0; i < num_sections; ++i) {
1364  E :      const IMAGE_SECTION_HEADER* header = image_file_.section_header(i);
1365  E :      DCHECK_NE(reinterpret_cast<IMAGE_SECTION_HEADER*>(NULL), header);
1366    :  
1367  E :      BlockType type = BlockGraph::CODE_BLOCK;
1368  E :      const char* section_type = NULL;
1369  E :      switch (GetSectionType(*header)) {
1370    :        case kSectionCode:
1371  E :          type = BlockGraph::CODE_BLOCK;
1372  E :          section_type = "code";
1373  E :          break;
1374    :  
1375    :        case kSectionData:
1376  E :          type = BlockGraph::DATA_BLOCK;
1377  E :          section_type = "data";
1378  E :          break;
1379    :  
1380    :        default:
1381  i :          continue;
1382    :      }
1383    :  
1384  E :      if (!CreateSectionGapBlocks(header, type)) {
1385  i :        LOG(ERROR) << "Unable to create gap blocks for " << section_type
1386    :                   << " section \"" << header->Name << "\".";
1387  i :        return false;
1388    :      }
1389  E :    }
1390    :  
1391  E :    return true;
1392  E :  }
1393    :  
1394    :  bool Decomposer::FinalizeIntermediateReferences(
1395  E :      const IntermediateReferences& references) {
1396  E :    for (size_t i = 0; i < references.size(); ++i) {
1397    :      // This logs verbosely for us.
1398  E :      if (!CreateReference(references[i].src_addr,
1399    :                           references[i].size,
1400    :                           references[i].type,
1401    :                           references[i].dst_addr,
1402    :                           references[i].dst_addr,
1403    :                           image_)) {
1404  i :        return false;
1405    :      }
1406  E :    }
1407  E :    return true;
1408  E :  }
1409    :  
1410  E :  bool Decomposer::CreateReferencesFromFixups(IDiaSession* session) {
1411  E :    DCHECK_NE(reinterpret_cast<IDiaSession*>(NULL), session);
1412    :  
1413  E :    PEFile::RelocSet reloc_set;
1414  E :    if (!image_file_.DecodeRelocs(&reloc_set))
1415  i :      return false;
1416    :  
1417  E :    OMAPs omap_from;
1418  E :    PdbFixups fixups;
1419  E :    if (!LoadDebugStreams(session, &fixups, &omap_from))
1420  i :      return false;
1421    :  
1422    :    // While creating references from the fixups this removes the
1423    :    // corresponding reference data from the relocs. We use this as a kind of
1424    :    // double-entry bookkeeping to ensure all is well and right in the world.
1425  E :    if (!CreateReferencesFromFixupsImpl(image_file_, fixups, omap_from,
1426    :                                        &reloc_set, image_)) {
1427  i :      return false;
1428    :    }
1429    :  
1430  E :    if (!reloc_set.empty()) {
1431  i :      LOG(ERROR) << "Found reloc entries without matching FIXUP entries.";
1432  i :      return false;
1433    :    }
1434    :  
1435  E :    return true;
1436  E :  }
1437    :  
1438  E :  bool Decomposer::ProcessSymbols(IDiaSymbol* root) {
1439  E :    DCHECK_NE(reinterpret_cast<IDiaSymbol*>(NULL), root);
1440    :  
1441  E :    DiaBrowser::MatchCallback on_push_function_or_thunk_symbol(
1442    :        base::Bind(&Decomposer::OnPushFunctionOrThunkSymbol,
1443    :                   base::Unretained(this)));
1444  E :    DiaBrowser::MatchCallback on_pop_function_or_thunk_symbol(
1445    :        base::Bind(&Decomposer::OnPopFunctionOrThunkSymbol,
1446    :                   base::Unretained(this)));
1447  E :    DiaBrowser::MatchCallback on_function_child_symbol(
1448    :        base::Bind(&Decomposer::OnFunctionChildSymbol,
1449    :                   base::Unretained(this)));
1450  E :    DiaBrowser::MatchCallback on_data_symbol(
1451    :        base::Bind(&Decomposer::OnDataSymbol, base::Unretained(this)));
1452  E :    DiaBrowser::MatchCallback on_public_symbol(
1453    :        base::Bind(&Decomposer::OnPublicSymbol, base::Unretained(this)));
1454  E :    DiaBrowser::MatchCallback on_label_symbol(
1455    :        base::Bind(&Decomposer::OnLabelSymbol, base::Unretained(this)));
1456    :  
1457  E :    DiaBrowser dia_browser;
1458    :  
1459    :    // Find thunks.
1460  E :    dia_browser.AddPattern(Seq(Opt(SymTagCompiland), SymTagThunk),
1461    :                           on_push_function_or_thunk_symbol,
1462    :                           on_pop_function_or_thunk_symbol);
1463    :  
1464    :    // Find functions and all data, labels, callsites, debug start/end and block
1465    :    // symbols below them. This is done in one single pattern so that the
1466    :    // function pushes/pops happen in the right order.
1467  E :    dia_browser.AddPattern(
1468    :        Seq(Opt(SymTagCompiland),
1469    :            Callback(Or(SymTagFunction, SymTagThunk),
1470    :                     on_push_function_or_thunk_symbol,
1471    :                     on_pop_function_or_thunk_symbol),
1472    :            Star(SymTagBlock),
1473    :            Or(SymTagData,
1474    :               SymTagLabel,
1475    :               SymTagBlock,
1476    :               SymTagFuncDebugStart,
1477    :               SymTagFuncDebugEnd,
1478    :               SymTagCallSite)),
1479    :        on_function_child_symbol);
1480    :  
1481    :    // Global data and code label symbols.
1482  E :    dia_browser.AddPattern(Seq(Opt(SymTagCompiland), SymTagLabel),
1483    :                           on_label_symbol);
1484  E :    dia_browser.AddPattern(Seq(Opt(SymTagCompiland), SymTagData),
1485    :                           on_data_symbol);
1486    :  
1487    :    // Public symbols. These provide decorated names without any type info, but
1488    :    // are useful for debugging.
1489  E :    dia_browser.AddPattern(SymTagPublicSymbol, on_public_symbol);
1490    :  
1491  E :    return dia_browser.Browse(root);
1492  E :  }
1493    :  
1494    :  bool Decomposer::VisitLinkerSymbol(VisitLinkerSymbolContext* context,
1495    :                                     uint16_t symbol_length,
1496    :                                     uint16_t symbol_type,
1497  E :                                     common::BinaryStreamReader* reader) {
1498  E :    DCHECK_NE(static_cast<VisitLinkerSymbolContext*>(NULL), context);
1499  E :    DCHECK_NE(static_cast<common::BinaryStreamReader*>(NULL), reader);
1500    :  
1501  E :    if (symbol_type != cci::S_COFFGROUP)
1502  E :      return true;
1503    :  
1504  E :    std::vector<uint8_t> buffer;
1505    :    const cci::CoffGroupSym* coffgroup =
1506  E :        ParseSymbol<cci::CoffGroupSym>(symbol_length, reader, &buffer);
1507  E :    if (coffgroup == NULL)
1508  i :      return false;
1509    :  
1510    :    // The PDB numbers sections starting at index 1 but we use index 0.
1511  E :    RelativeAddress rva(image_layout_->sections[coffgroup->seg - 1].addr +
1512    :        coffgroup->off);
1513    :  
1514    :    // We are looking for an opening symbol.
1515  E :    if (context->current_group_index == -1) {
1516  E :      for (uint32_t i = 0; i < context->bracketing_groups.size(); ++i) {
1517  E :        std::string prefix;
1518  E :        if (context->bracketing_groups[i].FullMatch(coffgroup->name, &prefix)) {
1519  E :          context->current_group_index = i;
1520  E :          context->current_group_prefix = prefix;
1521  E :          context->current_group_start = rva;
1522  E :          return true;
1523    :        }
1524  E :      }
1525    :  
1526    :      // No opening symbol was encountered. We can safely ignore this
1527    :      // COFF group symbol.
1528  E :      return true;
1529    :    }
1530    :  
1531    :    // If we get here we've found an opening symbol and we're looking for the
1532    :    // matching closing symbol.
1533  E :    std::string prefix;
1534  E :    if (!context->bracketing_groups[context->current_group_index].FullMatch(
1535    :            coffgroup->name, &prefix)) {
1536  E :      return true;
1537    :    }
1538    :  
1539  E :    if (prefix != context->current_group_prefix) {
1540    :      // We see another symbol open/close while already in an opened symbol.
1541    :      // This indicates nested bracketing information, which we've never seen
1542    :      // before.
1543  i :      LOG(ERROR) << "Encountered nested bracket symbol \"" << prefix
1544    :                 << "\" while in \"" << context->current_group_prefix << "\".";
1545  i :      return false;
1546    :    }
1547    :  
1548  E :    RelativeAddress end = rva + coffgroup->cb;
1549  E :    DCHECK_LE(context->current_group_start, end);
1550    :  
1551    :    // If the COFF group is not empty, then create a block corresponding to it.
1552  E :    if (context->current_group_start != end) {
1553    :      // Create a block for this bracketed COFF group.
1554  E :      Block* block = CreateBlock(
1555    :          BlockGraph::DATA_BLOCK,
1556    :          context->current_group_start,
1557    :          end - context->current_group_start,
1558    :          base::StringPrintf("Bracketed COFF group: %s", prefix.c_str()));
1559  E :      if (block == NULL) {
1560  i :        LOG(ERROR) << "Failed to create bracketed COFF group \""
1561    :                   << prefix << "\".";
1562  i :        return false;
1563    :      }
1564  E :      block->set_attribute(BlockGraph::COFF_GROUP);
1565    :    }
1566    :  
1567    :    // Indicate that this block is closed and we're looking for another opening
1568    :    // bracket symbol.
1569  E :    context->current_group_index = -1;
1570  E :    context->current_group_prefix.clear();
1571  E :    context->current_group_start = RelativeAddress(0);
1572    :  
1573  E :    return true;
1574  E :  }
1575    :  
1576    :  DiaBrowser::BrowserDirective Decomposer::OnPushFunctionOrThunkSymbol(
1577    :      const DiaBrowser& dia_browser,
1578    :      const DiaBrowser::SymTagVector& sym_tags,
1579  E :      const DiaBrowser::SymbolPtrVector& symbols) {
1580  E :    DCHECK(!symbols.empty());
1581  E :    DCHECK_EQ(sym_tags.size(), symbols.size());
1582  E :    DiaBrowser::SymbolPtr symbol = symbols.back();
1583    :  
1584  E :    DCHECK_EQ(reinterpret_cast<Block*>(NULL), current_block_);
1585  E :    DCHECK_EQ(current_address_, RelativeAddress(0));
1586  E :    DCHECK_EQ(0u, current_scope_count_);
1587    :  
1588  E :    HRESULT hr = E_FAIL;
1589  E :    DWORD location_type = LocIsNull;
1590  E :    DWORD rva = 0;
1591  E :    ULONGLONG length = 0;
1592  E :    ScopedBstr name_bstr;
1593    :    if (FAILED(hr = symbol->get_locationType(&location_type)) ||
1594    :        FAILED(hr = symbol->get_relativeVirtualAddress(&rva)) ||
1595  E :        FAILED(hr = symbol->get_length(&length)) ||
1596    :        FAILED(hr = symbol->get_name(name_bstr.Receive()))) {
1597  i :      LOG(ERROR) << "Failed to get function/thunk properties: "
1598    :                 << common::LogHr(hr) << ".";
1599  i :      return DiaBrowser::kBrowserAbort;
1600    :    }
1601    :  
1602    :    // We only care about functions with static storage. We can stop looking at
1603    :    // things below this node, as we won't be able to resolve them either.
1604  E :    if (location_type != LocIsStatic)
1605  i :      return DiaBrowser::kBrowserTerminatePath;
1606    :  
1607  E :    RelativeAddress addr(rva);
1608  E :    Block* block = image_->GetBlockByAddress(addr);
1609  E :    CHECK(block != NULL);
1610  E :    RelativeAddress block_addr;
1611  E :    CHECK(image_->GetAddressOf(block, &block_addr));
1612  E :    DCHECK(InRange(addr, block_addr, block->size()));
1613    :  
1614  E :    std::string name;
1615  E :    if (!base::WideToUTF8(name_bstr, name_bstr.Length(), &name)) {
1616  i :      LOG(ERROR) << "Failed to convert function/thunk name to UTF8.";
1617  i :      return DiaBrowser::kBrowserAbort;
1618    :    }
1619    :  
1620    :    // We know the function starts in this block but we need to make sure its
1621    :    // end does not extend past the end of the block.
1622  E :    if (addr + length > block_addr + block->size()) {
1623  i :      LOG(ERROR) << "Got function/thunk \"" << name << "\" that is not contained "
1624    :                 << "by section contribution \"" << block->name() << "\".";
1625  i :      return DiaBrowser::kBrowserAbort;
1626    :    }
1627    :  
1628  E :    Offset offset = addr - block_addr;
1629  E :    if (!AddLabelToBlock(offset, name, BlockGraph::CODE_LABEL, block))
1630  i :      return DiaBrowser::kBrowserAbort;
1631    :  
1632    :    // Keep track of the generated block. We will use this when parsing symbols
1633    :    // that belong to this function. This prevents us from having to do repeated
1634    :    // lookups and also allows us to associate labels outside of the block to the
1635    :    // correct block.
1636  E :    current_block_ = block;
1637  E :    current_address_ = block_addr;
1638    :  
1639    :    // Certain properties are not defined on all blocks, so the following calls
1640    :    // may return S_FALSE.
1641  E :    BOOL no_return = FALSE;
1642  E :    if (symbol->get_noReturn(&no_return) != S_OK)
1643  E :      no_return = FALSE;
1644    :  
1645  E :    BOOL has_inl_asm = FALSE;
1646  E :    if (symbol->get_hasInlAsm(&has_inl_asm) != S_OK)
1647  E :      has_inl_asm = FALSE;
1648    :  
1649  E :    BOOL has_eh = FALSE;
1650  E :    if (symbol->get_hasEH(&has_eh) != S_OK)
1651  E :      has_eh = FALSE;
1652    :  
1653  E :    BOOL has_seh = FALSE;
1654  E :    if (symbol->get_hasSEH(&has_seh) != S_OK)
1655  E :      has_seh = FALSE;
1656    :  
1657    :    // Set the block attributes.
1658  E :    if (no_return == TRUE)
1659  E :      block->set_attribute(BlockGraph::NON_RETURN_FUNCTION);
1660  E :    if (has_inl_asm == TRUE)
1661  E :      block->set_attribute(BlockGraph::HAS_INLINE_ASSEMBLY);
1662  E :    if (has_eh || has_seh)
1663  E :      block->set_attribute(BlockGraph::HAS_EXCEPTION_HANDLING);
1664  E :    if (IsSymTag(symbol.get(), SymTagThunk))
1665  E :      block->set_attribute(BlockGraph::THUNK);
1666    :  
1667  E :    return DiaBrowser::kBrowserContinue;
1668  E :  }
1669    :  
1670    :  DiaBrowser::BrowserDirective Decomposer::OnPopFunctionOrThunkSymbol(
1671    :      const DiaBrowser& dia_browser,
1672    :      const DiaBrowser::SymTagVector& sym_tags,
1673  E :      const DiaBrowser::SymbolPtrVector& symbols) {
1674    :    // Simply clean up the current function block and address.
1675  E :    current_block_ = NULL;
1676  E :    current_address_ = RelativeAddress(0);
1677  E :    current_scope_count_ = 0;
1678  E :    return DiaBrowser::kBrowserContinue;
1679  E :  }
1680    :  
1681    :  DiaBrowser::BrowserDirective Decomposer::OnFunctionChildSymbol(
1682    :        const DiaBrowser& dia_browser,
1683    :        const DiaBrowser::SymTagVector& sym_tags,
1684  E :        const DiaBrowser::SymbolPtrVector& symbols) {
1685  E :    DCHECK(!symbols.empty());
1686  E :    DCHECK_EQ(sym_tags.size(), symbols.size());
1687    :  
1688    :    // This can only be called from the context of a function, so we expect the
1689    :    // parent function block to be set and remembered.
1690  E :    DCHECK_NE(reinterpret_cast<Block*>(NULL), current_block_);
1691    :  
1692    :    // The set of sym tags here should match the pattern used in the DiaBrowser
1693    :    // instance set up in ProcessSymbols.
1694  E :    switch (sym_tags.back()) {
1695    :      case SymTagData:
1696  E :        return OnDataSymbol(dia_browser, sym_tags, symbols);
1697    :  
1698    :      case SymTagLabel:
1699  E :        return OnLabelSymbol(dia_browser, sym_tags, symbols);
1700    :  
1701    :      case SymTagBlock:
1702    :      case SymTagFuncDebugStart:
1703    :      case SymTagFuncDebugEnd:
1704  E :        return OnScopeSymbol(sym_tags.back(), symbols.back());
1705    :  
1706    :      case SymTagCallSite:
1707  E :        return OnCallSiteSymbol(symbols.back());
1708    :  
1709    :      default:
1710    :        break;
1711    :    }
1712    :  
1713  i :    LOG(ERROR) << "Unhandled function child symbol: " << sym_tags.back() << ".";
1714  i :    return DiaBrowser::kBrowserAbort;
1715  E :  }
1716    :  
1717    :  DiaBrowser::BrowserDirective Decomposer::OnDataSymbol(
1718    :      const DiaBrowser& dia_browser,
1719    :      const DiaBrowser::SymTagVector& sym_tags,
1720  E :      const DiaBrowser::SymbolPtrVector& symbols) {
1721  E :    DCHECK(!symbols.empty());
1722  E :    DCHECK_EQ(sym_tags.size(), symbols.size());
1723  E :    DiaBrowser::SymbolPtr symbol = symbols.back();
1724    :  
1725  E :    HRESULT hr = E_FAIL;
1726  E :    DWORD location_type = LocIsNull;
1727  E :    DWORD rva = 0;
1728  E :    ScopedBstr name_bstr;
1729    :    if (FAILED(hr = symbol->get_locationType(&location_type)) ||
1730  E :        FAILED(hr = symbol->get_relativeVirtualAddress(&rva)) ||
1731    :        FAILED(hr = symbol->get_name(name_bstr.Receive()))) {
1732  i :      LOG(ERROR) << "Failed to get data properties: " << common::LogHr(hr) << ".";
1733  i :      return DiaBrowser::kBrowserAbort;
1734    :    }
1735    :  
1736    :    // Symbols with an address of zero are essentially invalid. They appear to
1737    :    // have been optimized away by the compiler, but they are still reported.
1738  E :    if (rva == 0)
1739  E :      return DiaBrowser::kBrowserTerminatePath;
1740    :  
1741    :    // We only care about functions with static storage. We can stop looking at
1742    :    // things below this node, as we won't be able to resolve them either.
1743  E :    if (location_type != LocIsStatic)
1744  i :      return DiaBrowser::kBrowserTerminatePath;
1745    :  
1746    :    // Get the size of this datum from its type info.
1747  E :    size_t length = 0;
1748  E :    if (!GetDataSymbolSize(symbol.get(), &length))
1749  i :      return DiaBrowser::kBrowserAbort;
1750    :  
1751    :    // Reuse the parent function block if we can. This acts as small lookup
1752    :    // cache.
1753  E :    RelativeAddress addr(rva);
1754  E :    Block* block = current_block_;
1755  E :    RelativeAddress block_addr(current_address_);
1756  E :    if (block == NULL || !InRange(addr, block_addr, block->size())) {
1757  E :      block = image_->GetBlockByAddress(addr);
1758  E :      CHECK(block != NULL);
1759  E :      CHECK(image_->GetAddressOf(block, &block_addr));
1760  E :      DCHECK(InRange(addr, block_addr, block->size()));
1761    :    }
1762    :  
1763  E :    std::string name;
1764  E :    if (!base::WideToUTF8(name_bstr, name_bstr.Length(), &name)) {
1765  i :      LOG(ERROR) << "Failed to convert label name to UTF8.";
1766  i :      return DiaBrowser::kBrowserAbort;
1767    :    }
1768    :  
1769    :    // Zero-length data symbols mark case/jump tables, or are forward declares.
1770  E :    BlockGraph::LabelAttributes attr = BlockGraph::DATA_LABEL;
1771  E :    Offset offset = addr - block_addr;
1772  E :    if (length == 0) {
1773    :      // Jump and case tables come in as data symbols with no name. Jump tables
1774    :      // are always an array of pointers, thus they coincide exactly with a
1775    :      // reference. Case tables are simple arrays of integer values (themselves
1776    :      // indices into a jump table), thus do not coincide with a reference.
1777  E :      if (name.empty() && block->type() == BlockGraph::CODE_BLOCK) {
1778  E :        if (block->references().find(offset) != block->references().end()) {
1779  E :          name = kJumpTable;
1780  E :          attr |= BlockGraph::JUMP_TABLE_LABEL;
1781  E :        } else {
1782  E :          name = kCaseTable;
1783  E :          attr |= BlockGraph::CASE_TABLE_LABEL;
1784    :        }
1785  E :      } else {
1786    :        // Zero-length data symbols act as 'forward declares' in some sense. They
1787    :        // are always followed by a non-zero length data symbol with the same name
1788    :        // and location.
1789  E :        return DiaBrowser::kBrowserTerminatePath;
1790    :      }
1791    :    }
1792    :  
1793    :    // Verify that the data symbol does not exceed the size of the block.
1794  E :    if (addr + length > block_addr + block->size()) {
1795    :      // The data symbol can exceed the size of the block in the case of data
1796    :      // imports. For some reason the toolchain emits a global data symbol with
1797    :      // type information equal to the type of the data *pointed* to by the import
1798    :      // entry rather than the type of the entry itself. Thus, if the data type
1799    :      // is bigger than the entire IAT this symbol will exceed it. To complicate
1800    :      // matters even more, a poorly written module can import its own export in
1801    :      // which case a linker generated pseudo-import-entry block will be
1802    :      // generated. This won't be part of the IAT, so we can't even filter based
1803    :      // on that. Instead, we simply ignore global data symbols that exceed the
1804    :      // block size.
1805  E :      base::StringPiece spname(name);
1806  E :      if (sym_tags.size() == 1 && spname.starts_with("_imp_")) {
1807  E :        VLOG(1) << "Encountered an imported data symbol \"" << name << "\" that "
1808    :                << "extends past its parent block \"" << block->name() << "\".";
1809  E :      } else {
1810  i :        LOG(ERROR) << "Received data symbol \"" << name << "\" that extends past "
1811    :                   << "its parent block \"" << block->name() << "\".";
1812  i :        return DiaBrowser::kBrowserAbort;
1813    :      }
1814    :    }
1815    :  
1816  E :    if (!AddLabelToBlock(offset, name, attr, block))
1817  i :      return DiaBrowser::kBrowserAbort;
1818    :  
1819  E :    return DiaBrowser::kBrowserContinue;
1820  E :  }
1821    :  
1822    :  DiaBrowser::BrowserDirective Decomposer::OnPublicSymbol(
1823    :      const DiaBrowser& dia_browser,
1824    :      const DiaBrowser::SymTagVector& sym_tags,
1825  E :      const DiaBrowser::SymbolPtrVector& symbols) {
1826  E :    DCHECK(!symbols.empty());
1827  E :    DCHECK_EQ(sym_tags.size(), symbols.size());
1828  E :    DCHECK_EQ(reinterpret_cast<Block*>(NULL), current_block_);
1829  E :    DiaBrowser::SymbolPtr symbol = symbols.back();
1830    :  
1831  E :    HRESULT hr = E_FAIL;
1832  E :    DWORD rva = 0;
1833  E :    ScopedBstr name_bstr;
1834  E :    if (FAILED(hr = symbol->get_relativeVirtualAddress(&rva)) ||
1835    :        FAILED(hr = symbol->get_name(name_bstr.Receive()))) {
1836  i :      LOG(ERROR) << "Failed to get public symbol properties: "
1837    :                 << common::LogHr(hr) << ".";
1838  i :      return DiaBrowser::kBrowserAbort;
1839    :    }
1840    :  
1841  E :    RelativeAddress addr(rva);
1842  E :    Block* block = image_->GetBlockByAddress(addr);
1843  E :    CHECK(block != NULL);
1844  E :    RelativeAddress block_addr;
1845  E :    CHECK(image_->GetAddressOf(block, &block_addr));
1846  E :    DCHECK(InRange(addr, block_addr, block->size()));
1847    :  
1848  E :    std::string name;
1849  E :    base::WideToUTF8(name_bstr, name_bstr.Length(), &name);
1850    :  
1851    :    // Public symbol names are mangled. Remove leading '_' as per
1852    :    // http://msdn.microsoft.com/en-us/library/00kh39zz(v=vs.80).aspx
1853  E :    if (name[0] == '_')
1854  E :      name = name.substr(1);
1855    :  
1856  E :    Offset offset = addr - block_addr;
1857  E :    if (!AddLabelToBlock(offset, name, BlockGraph::PUBLIC_SYMBOL_LABEL, block))
1858  i :      return DiaBrowser::kBrowserAbort;
1859    :  
1860  E :    return DiaBrowser::kBrowserContinue;
1861  E :  }
1862    :  
1863    :  DiaBrowser::BrowserDirective Decomposer::OnLabelSymbol(
1864    :      const DiaBrowser& dia_browser,
1865    :      const DiaBrowser::SymTagVector& sym_tags,
1866  E :      const DiaBrowser::SymbolPtrVector& symbols) {
1867  E :    DCHECK(!symbols.empty());
1868  E :    DCHECK_EQ(sym_tags.size(), symbols.size());
1869  E :    DiaBrowser::SymbolPtr symbol = symbols.back();
1870    :  
1871  E :    HRESULT hr = E_FAIL;
1872  E :    DWORD rva = 0;
1873  E :    ScopedBstr name_bstr;
1874  E :    if (FAILED(hr = symbol->get_relativeVirtualAddress(&rva)) ||
1875    :        FAILED(hr = symbol->get_name(name_bstr.Receive()))) {
1876  i :      LOG(ERROR) << "Failed to get label symbol properties: " << common::LogHr(hr)
1877    :                 << ".";
1878  i :      return DiaBrowser::kBrowserAbort;
1879    :    }
1880    :  
1881    :    // If we have a current_block_ the label should lie within its scope.
1882  E :    RelativeAddress addr(rva);
1883  E :    Block* block = current_block_;
1884  E :    RelativeAddress block_addr(current_address_);
1885  E :    if (block != NULL) {
1886    :      // Try to find the block in the cold blocks. The cold blocks aren't in the
1887    :      // same address space as the original function.
1888  E :      if (!InRangeIncl(addr, block_addr, block->size())) {
1889    :  
1890    :        // Determine the function block containing this block.
1891    :        ColdBlocksParent::iterator function_block =
1892  E :            cold_blocks_parent_.find(block);
1893  E :        if (function_block != cold_blocks_parent_.end())
1894  E :          block = function_block->second;
1895    :  
1896    :        // Retrieve the first cold block related to that function before |addr|.
1897  E :        ColdBlocksMap::iterator cold_blocks_it = cold_blocks_.find(block);
1898  E :        if (cold_blocks_it != cold_blocks_.end()) {
1899  E :          ColdBlocks& cold_blocks = cold_blocks_it->second;
1900  E :          if (!cold_blocks.empty()) {
1901    :            // Find the block containing the address |addr|. When |addr| is not
1902    :            // the same as the block address, the iterator points to the next
1903    :            // block.
1904  E :            ColdBlocks::iterator cold_block_it = cold_blocks.lower_bound(addr);
1905  E :            if (cold_block_it == cold_blocks.end() ||
1906    :                cold_block_it->second->addr() != addr) {
1907  E :              cold_block_it--;
1908    :            }
1909    :  
1910    :            // Check whether the address falls into this cold block.
1911  E :            DCHECK(cold_block_it != cold_blocks.end());
1912  E :            Block* cold_block = cold_block_it->second;
1913  E :            if (InRangeIncl(addr, cold_block->addr(), cold_block->size()))
1914  E :              block = cold_block;
1915    :          }
1916    :        }
1917    :  
1918    :        // Update the block address according to the cold block found.
1919  E :        if (!image_->GetAddressOf(block, &block_addr)) {
1920  i :          LOG(ERROR) << "Cannot retrieve cold block address.";
1921  i :          return DiaBrowser::kBrowserAbort;
1922    :        }
1923    :      }
1924    :  
1925  E :      if (!InRangeIncl(addr, block_addr, block->size())) {
1926  i :        LOG(ERROR) << "Label falls outside of current block \""
1927    :                   << block->name() << "\".";
1928  i :        return DiaBrowser::kBrowserAbort;
1929    :      }
1930  E :    } else {
1931    :      // If there is no current block this is a compiland scope label.
1932  E :      block = image_->GetBlockByAddress(addr);
1933  E :      CHECK(block != NULL);
1934  E :      CHECK(image_->GetAddressOf(block, &block_addr));
1935  E :      DCHECK(InRange(addr, block_addr, block->size()));
1936    :  
1937    :      // TODO(chrisha): This label is in compiland scope, so we should be
1938    :      //     finding the block whose section contribution shares the same
1939    :      //     compiland.
1940    :    }
1941    :  
1942  E :    std::string name;
1943  E :    base::WideToUTF8(name_bstr, name_bstr.Length(), &name);
1944    :  
1945  E :    Offset offset = addr - block_addr;
1946  E :    if (!AddLabelToBlock(offset, name, BlockGraph::CODE_LABEL, block))
1947  i :      return DiaBrowser::kBrowserAbort;
1948    :  
1949  E :    return DiaBrowser::kBrowserContinue;
1950  E :  }
1951    :  
1952    :  DiaBrowser::BrowserDirective Decomposer::OnScopeSymbol(
1953  E :      enum SymTagEnum type, DiaBrowser::SymbolPtr symbol) {
1954    :    // We should only get here via the successful exploration of a SymTagFunction,
1955    :    // so current_block_ should be set.
1956  E :    DCHECK_NE(reinterpret_cast<Block*>(NULL), current_block_);
1957    :  
1958  E :    HRESULT hr = E_FAIL;
1959  E :    DWORD rva = 0;
1960  E :    if (FAILED(hr = symbol->get_relativeVirtualAddress(&rva))) {
1961  i :      LOG(ERROR) << "Failed to get scope symbol properties: " << common::LogHr(hr)
1962    :                 << ".";
1963  i :      return DiaBrowser::kBrowserAbort;
1964    :    }
1965    :  
1966    :    // The label may potentially lay at the first byte past the function.
1967  E :    RelativeAddress addr(rva);
1968  E :    DCHECK_LE(current_address_, addr);
1969  E :    DCHECK_LE(addr, current_address_ + current_block_->size());
1970    :  
1971    :    // Get the attributes for this label.
1972  E :    BlockGraph::LabelAttributes attr = 0;
1973  E :    std::string name;
1974  E :    CHECK(ScopeSymTagToLabelProperties(type, current_scope_count_, &attr, &name));
1975    :  
1976    :    // Add the label.
1977  E :    Offset offset = addr - current_address_;
1978  E :    if (!AddLabelToBlock(offset, name, attr, current_block_))
1979  i :      return DiaBrowser::kBrowserAbort;
1980    :  
1981    :    // If this is a scope we extract the length and explicitly add a corresponding
1982    :    // end label.
1983  E :    if (type == SymTagBlock) {
1984  E :      ULONGLONG length = 0;
1985  E :      if (symbol->get_length(&length) != S_OK) {
1986  i :        LOG(ERROR) << "Failed to extract code scope length for block \""
1987    :                    << current_block_->name() << "\".";
1988  i :        return DiaBrowser::kBrowserAbort;
1989    :      }
1990  E :      DCHECK_LE(static_cast<size_t>(offset + length), current_block_->size());
1991  E :      name = base::StringPrintf("<scope-end-%d>", current_scope_count_);
1992  E :      ++current_scope_count_;
1993  E :      if (!AddLabelToBlock(offset + length, name,
1994    :                           BlockGraph::SCOPE_END_LABEL, current_block_)) {
1995  i :        return DiaBrowser::kBrowserAbort;
1996    :      }
1997    :    }
1998    :  
1999  E :    return DiaBrowser::kBrowserContinue;
2000  E :  }
2001    :  
2002    :  DiaBrowser::BrowserDirective Decomposer::OnCallSiteSymbol(
2003  E :      DiaBrowser::SymbolPtr symbol) {
2004    :    // We should only get here via the successful exploration of a SymTagFunction,
2005    :    // so current_block_ should be set.
2006  E :    DCHECK_NE(reinterpret_cast<Block*>(NULL), current_block_);
2007    :  
2008  E :    HRESULT hr = E_FAIL;
2009  E :    DWORD rva = 0;
2010  E :    if (FAILED(hr = symbol->get_relativeVirtualAddress(&rva))) {
2011  i :      LOG(ERROR) << "Failed to get call site symbol properties: "
2012    :                 << common::LogHr(hr) << ".";
2013  i :      return DiaBrowser::kBrowserAbort;
2014    :    }
2015    :  
2016  E :    RelativeAddress addr(rva);
2017  E :    if (!InRange(addr, current_address_, current_block_->size())) {
2018    :      // We see this happen under some build configurations (notably debug
2019    :      // component builds of Chrome). As long as the label falls entirely
2020    :      // outside of the block it is harmless and can be safely ignored.
2021  E :      VLOG(1) << "Call site falls outside of current block \""
2022    :              << current_block_->name() << "\".";
2023  E :      return DiaBrowser::kBrowserContinue;
2024    :    }
2025    :  
2026  E :    Offset offset = addr - current_address_;
2027  E :    if (!AddLabelToBlock(offset, "<call-site>", BlockGraph::CALL_SITE_LABEL,
2028    :                         current_block_)) {
2029  i :      return DiaBrowser::kBrowserAbort;
2030    :    }
2031    :  
2032  E :    return DiaBrowser::kBrowserContinue;
2033  E :  }
2034    :  
2035    :  Block* Decomposer::CreateBlock(BlockType type,
2036    :                                    RelativeAddress address,
2037    :                                    BlockGraph::Size size,
2038  E :                                    const base::StringPiece& name) {
2039  E :    Block* block = image_->AddBlock(type, address, size, name);
2040  E :    if (block == NULL) {
2041  i :      LOG(ERROR) << "Unable to add block \"" << name.as_string() << "\" at "
2042    :                 << address << " with size " << size << ".";
2043  i :      return NULL;
2044    :    }
2045    :  
2046    :    // Mark the source range from whence this block originates. This is assuming
2047    :    // an untransformed image. To handle transformed images we'd have to use the
2048    :    // OMAP information to do this properly.
2049  E :    bool pushed = block->source_ranges().Push(
2050    :        Block::DataRange(0, size),
2051    :        Block::SourceRange(address, size));
2052  E :    DCHECK(pushed);
2053    :  
2054  E :    BlockGraph::SectionId section = image_file_.GetSectionIndex(address, size);
2055  E :    if (section == BlockGraph::kInvalidSectionId) {
2056  i :      LOG(ERROR) << "Block \"" << name.as_string() << "\" at " << address
2057    :                 << " with size " << size << " lies outside of all sections.";
2058  i :      return NULL;
2059    :    }
2060  E :    block->set_section(section);
2061    :  
2062  E :    const uint8_t* data = image_file_.GetImageData(address, size);
2063  E :    if (data != NULL)
2064  E :      block->SetData(data, size);
2065    :  
2066  E :    return block;
2067  E :  }
2068    :  
2069    :  Block* Decomposer::CreateBlockOrFindCoveringPeBlock(
2070    :      BlockType type,
2071    :      RelativeAddress addr,
2072    :      BlockGraph::Size size,
2073  E :      const base::StringPiece& name) {
2074  E :    Block* block = image_->GetBlockByAddress(addr);
2075  E :    if (block != NULL) {
2076  E :      RelativeAddress block_addr;
2077  E :      CHECK(image_->GetAddressOf(block, &block_addr));
2078    :  
2079    :      // Allow PE-parsed blocks to be grown to reflect reality. For example,
2080    :      // in VS2013 the linker makes space for 2 debug directories rather than
2081    :      // just one, and the symbols reflect this. We parse the debug directory
2082    :      // with the size indicated in the PE header, which conflicts with that
2083    :      // indicated by the section contributions.
2084  E :      if (name == "* Linker *" && block_addr == addr && size > block->size()) {
2085  E :        if (!image_->ResizeBlock(block, size)) {
2086  i :          LOG(ERROR) << "Failed to extend PE-parsed "
2087    :                     << BlockInfo(block, block_addr) << " with linker "
2088    :                     << "section contribution of size " << size << ".";
2089    :  
2090    :          // Get the conflicting block and output additional information about
2091    :          // it.
2092  i :          Block* conflict = image_->GetFirstIntersectingBlock(
2093    :              block_addr + block->size(), size - block->size());
2094  i :          if (conflict) {
2095  i :            RelativeAddress conflict_addr;
2096  i :            CHECK(image_->GetAddressOf(conflict, &conflict_addr));
2097  i :            LOG(ERROR) << "Conflicts with existing "
2098    :                       << BlockInfo(conflict, conflict_addr) << ".";
2099    :          }
2100    :  
2101  i :          return NULL;
2102    :        }
2103    :  
2104    :        // Update the data in the extended block.
2105  E :        const uint8_t* data = image_file_.GetImageData(addr, size);
2106  E :        block->SetData(data, size);
2107  E :        return block;
2108    :      }
2109    :  
2110    :      // If this is not a PE parsed or COFF group block that covers us entirely,
2111    :      // then this is an error.
2112    :      static const BlockGraph::BlockAttributes kCoveringAttributes =
2113    :          BlockGraph::PE_PARSED | BlockGraph::COFF_GROUP;
2114  E :      RelativeRange existing_block(block_addr, block->size());
2115  E :      if ((block->attributes() & kCoveringAttributes) == 0 ||
2116    :          !existing_block.Contains(addr, size)) {
2117  i :        LOG(ERROR) << "Trying to create block \"" << name.as_string() << "\" at "
2118    :                   << addr.value() << " with size " << size << " that conflicts "
2119    :                   << "with existing " << BlockInfo(block, block_addr) << ".";
2120  i :        return NULL;
2121    :      }
2122    :  
2123  E :      return block;
2124    :    }
2125  E :    DCHECK_EQ(reinterpret_cast<Block*>(NULL), block);
2126    :  
2127  E :    return CreateBlock(type, addr, size, name);
2128  E :  }
2129    :  
2130    :  bool Decomposer::CreateGapBlock(BlockType block_type,
2131    :                                     RelativeAddress address,
2132  E :                                     BlockGraph::Size size) {
2133  E :    Block* block = CreateBlock(block_type, address, size,
2134    :        base::StringPrintf("Gap Block 0x%08X", address.value()).c_str());
2135  E :    if (block == NULL) {
2136  i :      LOG(ERROR) << "Unable to create gap block.";
2137  i :      return false;
2138    :    }
2139  E :    block->set_attribute(BlockGraph::GAP_BLOCK);
2140    :  
2141  E :    return true;
2142  E :  }
2143    :  
2144    :  bool Decomposer::CreateSectionGapBlocks(const IMAGE_SECTION_HEADER* header,
2145  E :                                             BlockType block_type) {
2146  E :    RelativeAddress section_begin(header->VirtualAddress);
2147  E :    RelativeAddress section_end(section_begin + header->Misc.VirtualSize);
2148  E :    RelativeAddress image_end(
2149    :        image_file_.nt_headers()->OptionalHeader.SizeOfImage);
2150    :  
2151    :    // Search for the first and last blocks interesting from the start and end
2152    :    // of the section to the end of the image.
2153    :    BlockGraph::AddressSpace::RangeMap::const_iterator it(
2154  E :        image_->address_space_impl().FindFirstIntersection(
2155    :            BlockGraph::AddressSpace::Range(section_begin,
2156    :                                            image_end - section_begin)));
2157    :  
2158    :    BlockGraph::AddressSpace::RangeMap::const_iterator end =
2159  E :        image_->address_space_impl().end();
2160  E :    if (section_end < image_end) {
2161  E :      end = image_->address_space_impl().FindFirstIntersection(
2162    :          BlockGraph::AddressSpace::Range(section_end,
2163    :                                          image_end - section_end));
2164    :    }
2165    :  
2166    :    // The whole section is missing. Cover it with one gap block.
2167  E :    if (it == end)
2168  i :      return CreateGapBlock(
2169    :          block_type, section_begin, section_end - section_begin);
2170    :  
2171    :    // Create the head gap block if need be.
2172  E :    if (section_begin < it->first.start()) {
2173  i :      if (!CreateGapBlock(
2174    :          block_type, section_begin, it->first.start() - section_begin)) {
2175  i :        return false;
2176    :      }
2177    :    }
2178    :  
2179    :    // Now iterate the blocks and fill in gaps.
2180  E :    for (; it != end; ++it) {
2181  E :      const Block* block = it->second;
2182  E :      DCHECK_NE(reinterpret_cast<Block*>(NULL), block);
2183  E :      RelativeAddress block_end = it->first.start() + block->size();
2184  E :      if (block_end >= section_end)
2185  E :        break;
2186    :  
2187    :      // Walk to the next address in turn.
2188  E :      BlockGraph::AddressSpace::RangeMap::const_iterator next = it;
2189  E :      ++next;
2190  E :      if (next == end) {
2191    :        // We're at the end of the list. Create the tail gap block.
2192  E :        DCHECK_GT(section_end, block_end);
2193  E :        if (!CreateGapBlock(block_type, block_end, section_end - block_end))
2194  i :          return false;
2195  E :        break;
2196    :      }
2197    :  
2198    :      // Create the interstitial gap block.
2199  E :      if (block_end < next->first.start()) {
2200  E :        if (!CreateGapBlock(
2201    :            block_type, block_end, next->first.start() - block_end)) {
2202  i :          return false;
2203    :        }
2204    :      }
2205  E :    }
2206    :  
2207  E :    return true;
2208  E :  }
2209    :  
2210    :  }  // namespace pe

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