Coverage for /Syzygy/pe/coff_decomposer.cc

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

Line-by-line coverage:

   1    :  // Copyright 2013 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/coff_decomposer.h"
  16    :  
  17    :  #include "base/auto_reset.h"
  18    :  #include "base/strings/string_split.h"
  19    :  #include "syzygy/block_graph/typed_block.h"
  20    :  #include "syzygy/common/align.h"
  21    :  #include "syzygy/pe/cvinfo_ext.h"
  22    :  #include "syzygy/pe/pe_utils.h"
  23    :  
  24    :  namespace pe {
  25    :  
  26    :  namespace {
  27    :  
  28    :  namespace cci = Microsoft_Cci_Pdb;
  29    :  
  30    :  using base::AutoReset;
  31    :  using block_graph::BlockGraph;
  32    :  using block_graph::ConstTypedBlock;
  33    :  using core::AbsoluteAddress;
  34    :  using core::RelativeAddress;
  35    :  
  36    :  typedef BlockGraph::Block Block;
  37    :  typedef BlockGraph::BlockType BlockType;
  38    :  typedef BlockGraph::Reference Reference;
  39    :  typedef BlockGraph::ReferenceType ReferenceType;
  40    :  
  41    :  typedef std::map<size_t, const char*> ComdatMap;
  42    :  
  43    :  const char kHeadersBlockName[] = "<headers>";
  44    :  const char kSymbolsBlockName[] = "<symbols>";
  45    :  const char kStringsBlockName[] = "<strings>";
  46    :  const char kRelocsBlockName[] = "<relocs>";
  47    :  
  48    :  const size_t kDebugSubsectionAlignment = 4;
  49    :  
  50    :  // Retrieve the relocation type and size for the specified COFF relocation.
  51    :  //
  52    :  // @param reloc the relocation.
  53    :  // @param ref_type where to store the resulting reference type.
  54    :  // @param ref_size where to store the resulting reference size.
  55    :  // @returns true on success, or false if the information cannot be determined
  56    :  //     for the specified relocation.
  57    :  bool GetRelocationTypeAndSize(const IMAGE_RELOCATION& reloc,
  58    :                                ReferenceType* ref_type,
  59  E :                                BlockGraph::Size* ref_size) {
  60  E :    DCHECK(ref_type != NULL);
  61  E :    DCHECK(ref_size != NULL);
  62    :  
  63  E :    switch (reloc.Type) {
  64    :      case IMAGE_REL_I386_ABSOLUTE:
  65    :        // Ignored, as per the specifications.
  66  i :        return false;
  67    :      case IMAGE_REL_I386_DIR32:
  68  E :        *ref_type = BlockGraph::RELOC_ABSOLUTE_REF;
  69  E :        *ref_size = sizeof(uint32);
  70  E :        return true;
  71    :      case IMAGE_REL_I386_DIR32NB:
  72  E :        *ref_type = BlockGraph::RELOC_RELATIVE_REF;
  73  E :        *ref_size = sizeof(uint32);
  74  E :        return true;
  75    :      case IMAGE_REL_I386_SECTION:
  76  E :        *ref_type = BlockGraph::RELOC_SECTION_REF;
  77  E :        *ref_size = sizeof(uint16);
  78  E :        return true;
  79    :      case IMAGE_REL_I386_SECREL:
  80  E :        *ref_type = BlockGraph::RELOC_SECTION_OFFSET_REF;
  81  E :        *ref_size = sizeof(uint32);
  82  E :        return true;
  83    :      case IMAGE_REL_I386_SECREL7:
  84  i :        *ref_type = BlockGraph::RELOC_SECTION_OFFSET_REF;
  85    :        // TODO(chrisha): This is actually a 7-bit offset;
  86    :        // BlockGraph::Reference only represents byte sizes. We pass as a 1-byte
  87    :        // reference as there are no actual 8-bit references in COFF files.
  88  i :        *ref_size = 1;
  89  i :        return true;
  90    :      case IMAGE_REL_I386_REL32:
  91  E :        *ref_type = BlockGraph::RELOC_PC_RELATIVE_REF;
  92  E :        *ref_size = sizeof(uint32);
  93  E :        return true;
  94    :      default:
  95    :        // Ignore other types; they are either explicitly mentioned as unsupported
  96    :        // in the specifications, or for managed code.
  97  i :        LOG(WARNING) << "Unexpected COFF relocation type.";
  98  i :        return false;
  99    :    }
 100  E :  }
 101    :  
 102    :  // Retrieve the relocation encoded value at the relocated location.
 103    :  //
 104    :  // @tparam ValueType the type of data to read.
 105    :  // @param source the source block.
 106    :  // @param src_offset the offset of the relocated location.
 107    :  // @param extra_offset where to place the additional offset read.
 108    :  // @returns true on success, or false on failure.
 109    :  template <typename ValueType>
 110    :  bool ReadRelocationValue(Block* source,
 111    :                           BlockGraph::Offset src_offset,
 112  E :                           BlockGraph::Offset* extra_offset) {
 113  E :    ConstTypedBlock<ValueType> value;
 114  E :    if (!value.Init(src_offset, source)) {
 115  i :      LOG(ERROR) << "Unable to read relocation location value.";
 116  i :      return false;
 117    :    }
 118  E :    *extra_offset = *value;
 119  E :    return true;
 120  E :  }
 121    :  
 122    :  // Parse a CodeView debug symbol subsection, adding references and attributes as
 123    :  // needed to @p block.
 124    :  //
 125    :  // @param version The CodeView version to use in parsing the symbol stream.
 126    :  // @param start the offset to the beginning of the contents (excluding type and
 127    :  //     length) of the subsection inside @p block.
 128    :  // @param size the size of the subsection.
 129    :  // @param block the debug section block.
 130    :  // @returns true on success, or false on failure.
 131    :  bool ParseDebugSymbols(
 132  E :      cci::CV_SIGNATURE version, size_t start, size_t size, Block* block) {
 133  E :    DCHECK(version == cci::C11 || version == cci::C13);
 134  E :    DCHECK_NE(reinterpret_cast<Block*>(NULL), block);
 135  E :    DCHECK_GT(block->data_size(), start);
 136  E :    DCHECK_GE(block->data_size(), start + size);
 137    :  
 138    :    // We assume that functions do not nest, hence dependent debug symbols should
 139    :    // all refer to the last function symbol, whose block is stored in
 140    :    // current_func.
 141  E :    size_t section_index = block->section();
 142  E :    Block* current_func = NULL;
 143  E :    size_t cursor = start;
 144  E :    while (cursor < size) {
 145  E :      ConstTypedBlock<cci::SYMTYPE> dsym;
 146  E :      if (!dsym.Init(cursor, block)) {
 147  i :        LOG(ERROR) << "Unable to read debug symbol header at offset "
 148    :                   << cursor << " in .debug$S section " << section_index << ".";
 149  i :        return false;
 150    :      }
 151  E :      cursor += sizeof(*dsym);
 152    :  
 153  E :      switch (dsym->rectyp) {
 154    :        case cci::S_GPROC32:
 155    :        case cci::S_LPROC32:
 156    :        case cci::S_GPROC32_VS2013:
 157    :        case cci::S_LPROC32_VS2013: {
 158  E :          ConstTypedBlock<cci::ProcSym32> proc;
 159  E :          if (!proc.Init(cursor, block)) {
 160  i :            LOG(ERROR) << "Unable to read debug procedure (" << dsym->rectyp
 161    :                       << ") symbol at offset " << cursor
 162    :                       << " in .debug$S section " << section_index << ".";
 163  i :            return false;
 164    :          }
 165    :  
 166    :          // Get the existing relocation reference that points to the correct
 167    :          // function block.
 168  E :          Reference reloc_ref;
 169    :          if (!block->GetReference(cursor + offsetof(cci::ProcSym32, off),
 170  E :                                   &reloc_ref)) {
 171  i :            LOG(ERROR) << "No relocation reference in ProcSym32 "
 172    :                       << "(missing COFF relocation?) at offset "
 173    :                       << cursor + offsetof(cci::ProcSym32, off)
 174    :                       << " in .debug$S section " << section_index << ".";
 175  i :            return false;
 176    :          }
 177  E :          current_func = reloc_ref.referenced();
 178    :  
 179    :          // These are function-relative offsets; we can use section offsets as we
 180    :          // assume function-level linking.
 181    :          if (!block->SetReference(cursor + offsetof(cci::ProcSym32, dbgStart),
 182    :                                   Reference(BlockGraph::SECTION_OFFSET_REF,
 183    :                                             sizeof(proc->dbgStart),
 184    :                                             current_func,
 185  E :                                             proc->dbgStart, proc->dbgStart))) {
 186  i :            LOG(ERROR) << "Unable to create reference at offset "
 187    :                       << cursor + offsetof(cci::ProcSym32, dbgStart)
 188    :                       << " in .debug$S section " << section_index << ".";
 189  i :            return false;
 190    :          }
 191    :          if (!block->SetReference(cursor + offsetof(cci::ProcSym32, dbgEnd),
 192    :                                   Reference(BlockGraph::SECTION_OFFSET_REF,
 193    :                                             sizeof(proc->dbgEnd),
 194    :                                             current_func,
 195  E :                                             proc->dbgEnd, proc->dbgEnd))) {
 196  i :            LOG(ERROR) << "Unable to create reference at offset "
 197    :                       << cursor + offsetof(cci::ProcSym32, dbgEnd)
 198    :                       << " in .debug$S section " << section_index << ".";
 199  i :            return false;
 200    :          }
 201  E :          break;
 202    :        }
 203    :  
 204    :        case cci::S_FRAMEPROC: {
 205  E :          ConstTypedBlock<cci::FrameProcSym> frame;
 206  E :          if (!frame.Init(cursor, block)) {
 207  i :            LOG(ERROR) << "Unable to read debug frame (" << dsym->rectyp
 208    :                       << ") symbol at offset " << cursor
 209    :                       << " in .debug$S section " << section_index << ".";
 210  i :            return false;
 211    :          }
 212    :  
 213  E :          DCHECK(current_func != NULL);
 214  E :          if ((frame->flags & cci::fHasInlAsm) != 0)
 215  i :            current_func->set_attribute(BlockGraph::HAS_INLINE_ASSEMBLY);
 216  E :          if ((frame->flags & cci::fHasSEH) != 0)
 217  i :            current_func->set_attribute(BlockGraph::HAS_EXCEPTION_HANDLING);
 218  E :          break;
 219    :        }
 220    :  
 221    :        case cci::S_ANNOTATION:
 222    :        case cci::S_BLOCK32:
 223    :        case cci::S_BPREL32:
 224    :        case cci::S_CALLSITEINFO:
 225    :        case cci::S_CONSTANT:
 226    :        case cci::S_END:
 227    :        case cci::S_FRAMECOOKIE:
 228    :        case cci::S_GDATA32:
 229    :        case cci::S_GDATA32_ST:
 230    :        case cci::S_GTHREAD32:
 231    :        case cci::S_LABEL32:
 232    :        case cci::S_LDATA32:
 233    :        case cci::S_LDATA32_ST:
 234    :        case cci::S_LTHREAD32:
 235    :        case cci::S_OBJNAME:
 236    :        case cci::S_REGISTER:
 237    :        case cci::S_REGREL32:
 238    :        case cci::S_THUNK32:
 239    :        case cci::S_UDT:
 240    :        case cci::S_UDT_ST:
 241  E :          break;
 242    :  
 243    :        case cci::S_COMPILE3:
 244    :        case cci::S_MSTOOLENV_V3:
 245  E :          break;
 246    :  
 247    :        // CodeView2 symbols that we can safely ignore.
 248    :        case cci::S_COMPILE_CV2:
 249    :        case cci::S_COMPILE2_ST:
 250    :        case cci::S_OBJNAME_CV2:
 251  E :          break;
 252    :  
 253    :        // These are unknown symbol types, but currently seen. From inspection
 254    :        // they don't appear to contain references that need to be parsed.
 255    :        // TODO(chrisha): Figure out what these symbols are. Many of them appear
 256    :        //     to have been added only as of VS2013.
 257    :        case 0x113E:
 258    :        case 0x1141:
 259    :        case 0x1142:
 260    :        case 0x1143:
 261    :        case 0x1144:
 262    :        case 0x1145:
 263    :        case 0x114D:
 264    :        case 0x114E:
 265    :        case 0x1153:
 266    :        case 0x115A:
 267  i :          break;
 268    :  
 269    :        default:
 270  i :          LOG(ERROR) << "Unsupported debug symbol type 0x"
 271    :                     << std::hex << dsym->rectyp << std::dec
 272    :                     << " at offset "
 273    :                     << cursor - sizeof(*dsym) + offsetof(cci::SYMTYPE, rectyp)
 274    :                     << " in .debug$S section " << section_index << ".";
 275  i :          return false;
 276    :      }
 277  E :      cursor += dsym->reclen - sizeof(*dsym) + sizeof(dsym->reclen);
 278  E :    }
 279  E :    return true;
 280  E :  }
 281    :  
 282    :  // Parse a CodeView debug line number subsection, adding references as needed
 283    :  // to @p block.
 284    :  //
 285    :  // @param start the offset to the beginning of the contents (excluding type and
 286    :  //     length) of the subsection inside @p block.
 287    :  // @param size the size of the subsection.
 288    :  // @param block the debug section block.
 289    :  // @returns true on success, or false on failure.
 290  E :  bool ParseDebugLines(size_t start, size_t size, Block* block) {
 291  E :    DCHECK(block != NULL);
 292    :  
 293  E :    size_t section_index = block->section();
 294  E :    size_t cursor = start;
 295    :  
 296    :    // Parse the section info.
 297  E :    ConstTypedBlock<cci::CV_LineSection> line_section;
 298  E :    if (!line_section.Init(cursor, block)) {
 299  i :      LOG(ERROR) << "Unable to read debug line section header at offset "
 300    :                 << cursor << " in .debug$S section " << section_index << ".";
 301  i :      return false;
 302    :    }
 303    :  
 304    :    // Get the existing relocation reference that points to the function block
 305    :    // these lines are for.
 306  E :    Reference reloc_ref;
 307    :    if (!block->GetReference(cursor + offsetof(cci::CV_LineSection, off),
 308  E :                             &reloc_ref)) {
 309  i :      LOG(ERROR) << "No relocation reference in CV_LineSection "
 310    :                 << "(missing COFF relocation?) at offset "
 311    :                 << cursor + offsetof(cci::ProcSym32, off)
 312    :                 << " in .debug$S section " << section_index << ".";
 313  i :      return false;
 314    :    }
 315  E :    Block* func = reloc_ref.referenced();
 316  E :    cursor += sizeof(*line_section);
 317    :  
 318    :    // Parse the source info.
 319  E :    ConstTypedBlock<cci::CV_SourceFile> line_file;
 320  E :    if (!line_file.Init(cursor, block)) {
 321  i :      LOG(ERROR) << "Unable to read debug line file header at offset "
 322    :                 << cursor << " in .debug$S section " << section_index << ".";
 323  i :      return false;
 324    :    }
 325  E :    DCHECK_GE(size, line_file->linsiz);
 326  E :    cursor += sizeof(*line_file);
 327    :  
 328    :    // The rest of the subsection is an array of CV_Line structures.
 329  E :    ConstTypedBlock<cci::CV_Line> lines;
 330  E :    if (!lines.Init(cursor, block)) {
 331  i :      LOG(ERROR) << "Unable to read debug line file header at offset "
 332    :                 << cursor << " in .debug$S section " << section_index << ".";
 333  i :      return false;
 334    :    }
 335  E :    DCHECK_GE(lines.ElementCount(), line_file->count);
 336    :  
 337  E :    for (size_t i = 0; i < line_file->count; ++i) {
 338    :      // This should be a function-relative offset; we can use a section offset as
 339    :      // we assume function-level linking.
 340    :      Reference ref(BlockGraph::SECTION_OFFSET_REF, sizeof(lines[i].offset),
 341  E :                    func, lines[i].offset, lines[i].offset);
 342  E :      if (!block->SetReference(cursor + offsetof(cci::CV_Line, offset), ref)) {
 343  i :        LOG(ERROR) << "Unable to create reference at offset "
 344    :                   << cursor + offsetof(cci::CV_Line, offset)
 345    :                   << " in .debug$S section " << section_index << ".";
 346  i :        return false;
 347    :      }
 348  E :      cursor += sizeof(lines[i]);
 349  E :    }
 350    :  
 351  E :    return true;
 352  E :  }
 353    :  
 354    :  // Parse all CodeView4 debug subsections in the specified debug section block.
 355    :  //
 356    :  // @param block the debug section block.
 357    :  // @returns true on success, or false on failure.
 358  E :  bool ParseDebugSubsections4(Block* block) {
 359  E :    DCHECK(block != NULL);
 360    :  
 361  E :    size_t section_index = block->section();
 362  E :    size_t cursor = sizeof(uint32);
 363  E :    while (cursor < block->data_size()) {
 364  E :      ConstTypedBlock<uint32> type;
 365  E :      if (!type.Init(cursor, block)) {
 366  i :        LOG(ERROR) << "Unable to read debug subsection type at offset "
 367    :                   << cursor << " in .debug$S section " << section_index << ".";
 368  i :        return false;
 369    :      }
 370  E :      cursor += sizeof(*type);
 371    :  
 372  E :      ConstTypedBlock<uint32> size;
 373  E :      if (!size.Init(cursor, block)) {
 374  i :        LOG(ERROR) << "Unable to read debug subsection size at offset "
 375    :                   << cursor << " in .debug$S section " << section_index << ".";
 376  i :        return false;
 377    :      }
 378  E :      cursor += sizeof(*size);
 379    :  
 380    :      // A sentinel bit marks some sections ignored. We parse them even if they
 381    :      // are ignored.
 382  E :      switch (*type & ~cci::DEBUG_S_IGNORE) {
 383    :        case cci::DEBUG_S_SYMBOLS:
 384  E :          if (!ParseDebugSymbols(cci::C13, cursor, *size, block))
 385  i :            return false;
 386  E :          break;
 387    :        case cci::DEBUG_S_LINES:
 388  E :          if (!ParseDebugLines(cursor, *size, block))
 389  i :            return false;
 390  E :          break;
 391    :        case cci::DEBUG_S_STRINGTABLE:
 392    :        case cci::DEBUG_S_FILECHKSMS:
 393    :        case cci::DEBUG_S_FRAMEDATA:
 394  E :          break;
 395    :  
 396    :        // This is a new debug symbol type as of VS2013.
 397    :        // TODO(chrisha): Figure out the contents of this subsection type.
 398    :        case 0xF6:
 399  i :          break;
 400    :  
 401    :        default:
 402  i :          LOG(ERROR) << "Unsupported debug subsection type " << std::hex << *type
 403    :                     << std::dec << " at offset " << cursor
 404    :                     << " in .debug$S section " << section_index << ".";
 405  i :          return false;
 406    :      }
 407  E :      cursor += common::AlignUp(*size, sizeof(kDebugSubsectionAlignment));
 408  E :    }
 409  E :    return true;
 410  E :  }
 411    :  
 412    :  // Parse all CodeView2 debug subsections in the specified debug section block.
 413    :  // This is simply a raw stream of code view symbols, like a CodeView4
 414    :  // DEBUG_S_SYMBOLS subsection.
 415    :  //
 416    :  // @param block the debug section block.
 417    :  // @returns true on success, or false on failure.
 418  E :  bool ParseDebugSubsections2(Block* block) {
 419  E :    DCHECK(block != NULL);
 420    :  
 421  E :    size_t cursor = sizeof(uint32);
 422  E :    if (!ParseDebugSymbols(cci::C11, cursor, block->size() - cursor, block))
 423  i :      return false;
 424    :  
 425  E :    return true;
 426  E :  }
 427    :  
 428    :  }  // namespace
 429    :  
 430    :  const char CoffDecomposer::kSectionComdatSep[] = "; COMDAT=";
 431    :  
 432    :  CoffDecomposer::CoffDecomposer(const CoffFile& image_file)
 433    :      : image_file_(image_file),
 434    :        image_layout_(NULL),
 435  E :        image_(NULL) {
 436  E :  }
 437    :  
 438  E :  bool CoffDecomposer::Decompose(ImageLayout* image_layout) {
 439  E :    DCHECK_NE(reinterpret_cast<ImageLayout*>(NULL), image_layout);
 440    :  
 441    :    // Internal temporaries.
 442  E :    DCHECK_EQ(reinterpret_cast<ImageLayout*>(NULL), image_layout_);
 443  E :    DCHECK_EQ(reinterpret_cast<BlockGraph::AddressSpace*>(NULL),image_);
 444  E :    AutoReset<ImageLayout*> auto_reset_image_layout(&image_layout_, image_layout);
 445    :    AutoReset<BlockGraph::AddressSpace*> auto_reset_image(&image_,
 446  E :                                                          &image_layout->blocks);
 447    :  
 448    :    // Set the image format.
 449  E :    image_layout->blocks.graph()->set_image_format(BlockGraph::COFF_IMAGE);
 450    :  
 451    :    // Copy the image headers to the layout.
 452    :    CopySectionHeadersToImageLayout(
 453    :        image_file_.file_header()->NumberOfSections,
 454    :        image_file_.section_headers(),
 455  E :        &image_layout_->sections);
 456    :  
 457  E :    if (!CopySectionInfoToBlockGraph(image_file_, image_->graph()))
 458  i :      return false;
 459    :  
 460  E :    if (!CreateBlocksFromSections())
 461  i :      return false;
 462    :  
 463  E :    if (!CreateBlocksAndReferencesFromNonSections())
 464  i :      return false;
 465    :  
 466  E :    if (!CreateReferencesFromRelocations())
 467  i :      return false;
 468    :  
 469  E :    if (!CreateReferencesFromDebugInfo())
 470  i :      return false;
 471    :  
 472  E :    if (!CreateLabelsFromSymbols())
 473  i :      return false;
 474    :  
 475  E :    return true;
 476  E :  }
 477    :  
 478  E :  bool CoffDecomposer::CreateBlocksAndReferencesFromNonSections() {
 479  E :    DCHECK(image_ != NULL);
 480    :  
 481  E :    if (!CreateBlocksAndReferencesFromSymbolAndStringTables())
 482  i :      return false;
 483    :  
 484  E :    if (!CreateBlocksFromRelocationTables())
 485  i :      return false;
 486    :  
 487  E :    if (!CreateBlocksAndReferencesFromHeaders())
 488  i :      return false;
 489    :  
 490  E :    return true;
 491  E :  }
 492    :  
 493  E :  bool CoffDecomposer::CreateBlocksAndReferencesFromHeaders() {
 494  E :    const IMAGE_FILE_HEADER* file_header = image_file_.file_header();
 495  E :    DCHECK(file_header != NULL);
 496    :  
 497    :    // Create a block for COFF and section headers.
 498    :    size_t headers_size =
 499    :        sizeof(*file_header) +
 500  E :        file_header->NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
 501    :    Block* block = CreateBlock(BlockGraph::DATA_BLOCK, FileOffsetAddress(0),
 502  E :                               headers_size, kHeadersBlockName);
 503  E :    if (block == NULL) {
 504  i :      LOG(ERROR) << "Unable to create block for headers.";
 505  i :      return false;
 506    :    }
 507  E :    block->set_attribute(BlockGraph::COFF_HEADERS);
 508    :  
 509    :    // Create a reference for the symbol table pointer.
 510    :    FileOffsetAddress symbols_ptr_addr(
 511  E :        offsetof(IMAGE_FILE_HEADER, PointerToSymbolTable));
 512    :    if (!CreateFileOffsetReference(
 513    :            symbols_ptr_addr,
 514    :            BlockGraph::FILE_OFFSET_REF,
 515    :            sizeof(file_header->PointerToSymbolTable),
 516  E :            FileOffsetAddress(file_header->PointerToSymbolTable))) {
 517  i :      return false;
 518    :    }
 519    :  
 520    :    // Create a reference for the section and relocation pointers in each section
 521    :    // header.
 522    :    FileOffsetAddress section_headers_start(
 523  E :        sizeof(*file_header) + file_header->SizeOfOptionalHeader);
 524  E :    size_t num_sections = image_file_.file_header()->NumberOfSections;
 525  E :    for (size_t i = 0; i < num_sections; ++i) {
 526  E :      const IMAGE_SECTION_HEADER* header = image_file_.section_header(i);
 527  E :      DCHECK(header != NULL);
 528  E :      FileOffsetAddress start(section_headers_start + i * sizeof(*header));
 529    :  
 530    :      FileOffsetAddress data_ptr_addr(
 531  E :          start + offsetof(IMAGE_SECTION_HEADER, PointerToRawData));
 532    :      if (!CreateFileOffsetReference(
 533    :              data_ptr_addr,
 534    :              BlockGraph::FILE_OFFSET_REF,
 535    :              sizeof(header->PointerToRawData),
 536  E :              FileOffsetAddress(header->PointerToRawData))) {
 537  i :        return false;
 538    :      }
 539    :  
 540    :      FileOffsetAddress relocs_ptr_addr(
 541  E :          start + offsetof(IMAGE_SECTION_HEADER, PointerToRelocations));
 542    :      if (!CreateFileOffsetReference(
 543    :              relocs_ptr_addr,
 544    :              BlockGraph::FILE_OFFSET_REF,
 545    :              sizeof(header->PointerToRelocations),
 546  E :              FileOffsetAddress(header->PointerToRelocations))) {
 547  i :        return false;
 548    :      }
 549  E :    }
 550    :  
 551  E :    return true;
 552  E :  }
 553    :  
 554  E :  bool CoffDecomposer::CreateBlocksAndReferencesFromSymbolAndStringTables() {
 555    :    // Create a block for the symbol table.
 556  E :    FileOffsetAddress symbols_start(image_file_.symbols_address());
 557  E :    size_t symbols_size = image_file_.symbols_size();
 558    :    Block* block = CreateBlock(BlockGraph::DATA_BLOCK,
 559  E :                               symbols_start, symbols_size, kSymbolsBlockName);
 560  E :    if (block == NULL) {
 561  i :      LOG(ERROR) << "Unable to create block for symbols.";
 562  i :      return false;
 563    :    }
 564  E :    block->set_attribute(BlockGraph::COFF_SYMBOL_TABLE);
 565    :  
 566    :    // Create a block for the strings table that follows.
 567  E :    FileOffsetAddress strings_start(image_file_.strings_address());
 568  E :    size_t strings_size = image_file_.strings_size();
 569    :    block = CreateBlock(BlockGraph::DATA_BLOCK,
 570  E :                        strings_start, strings_size, kStringsBlockName);
 571  E :    if (block == NULL) {
 572  i :      LOG(ERROR) << "Unable to create block for strings.";
 573  i :      return false;
 574    :    }
 575  E :    block->set_attribute(BlockGraph::COFF_STRING_TABLE);
 576    :  
 577    :    // Add references.
 578  E :    size_t num_symbols = image_file_.file_header()->NumberOfSymbols;
 579  E :    const IMAGE_SYMBOL* symbol = NULL;
 580  E :    for (size_t i = 0; i < num_symbols; i += 1 + symbol->NumberOfAuxSymbols) {
 581  E :      symbol = image_file_.symbol(i);
 582    :  
 583    :      // Ignore external symbols (no references to blocks) and other kinds of
 584    :      // non-reference symbols.
 585  E :      if (symbol->SectionNumber <= 0)
 586  E :        continue;
 587    :  
 588  E :      FileOffsetAddress start(symbols_start + i * sizeof(*symbol));
 589    :  
 590    :      // Symbols with section storage class simply provide the characteristics
 591    :      // of the section in the symbol value. Other symbols store an actual offset
 592    :      // into a section in the value field.
 593  E :      if (symbol->StorageClass != IMAGE_SYM_CLASS_SECTION) {
 594  E :        FileOffsetAddress value_addr(start + offsetof(IMAGE_SYMBOL, Value));
 595    :        if (!CreateSymbolOffsetReference(
 596    :                value_addr,
 597    :                BlockGraph::SECTION_OFFSET_REF,
 598    :                sizeof(symbol->Value),
 599    :                symbol,
 600  E :                symbol->Value)) {
 601  i :          return false;
 602    :        }
 603    :      }
 604    :  
 605    :      FileOffsetAddress section_addr(
 606  E :          start + offsetof(IMAGE_SYMBOL, SectionNumber));
 607    :      if (!CreateSymbolOffsetReference(
 608    :              section_addr,
 609    :              BlockGraph::SECTION_REF,
 610    :              sizeof(symbol->SectionNumber),
 611    :              symbol,
 612  E :              0)) {
 613  i :        return false;
 614    :      }
 615    :  
 616    :      // Section definitions for associative COMDAT sections require an additional
 617    :      // section reference within the auxiliary symbol.
 618    :      if (symbol->StorageClass == IMAGE_SYM_CLASS_STATIC &&
 619    :          symbol->Type >> 4 != IMAGE_SYM_DTYPE_FUNCTION &&
 620  E :          symbol->NumberOfAuxSymbols == 1) {
 621    :        const IMAGE_AUX_SYMBOL* aux =
 622  E :            reinterpret_cast<const IMAGE_AUX_SYMBOL*>(image_file_.symbol(i + 1));
 623  E :        DCHECK(aux != NULL);
 624  E :        if (aux->Section.Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
 625    :          FileOffsetAddress number_addr(
 626    :              start + sizeof(IMAGE_SYMBOL) +
 627  E :              offsetof(IMAGE_AUX_SYMBOL, Section.Number));
 628    :          if (!CreateSectionOffsetReference(
 629    :                  number_addr,
 630    :                  BlockGraph::SECTION_REF,
 631    :                  sizeof(short),
 632    :                  aux->Section.Number - 1,
 633  E :                  0)) {
 634  i :            return false;
 635    :          }
 636    :        }
 637    :      }
 638  E :    }
 639    :  
 640  E :    return true;
 641  E :  }
 642    :  
 643  E :  bool CoffDecomposer::CreateBlocksFromRelocationTables() {
 644  E :    size_t num_sections = image_file_.file_header()->NumberOfSections;
 645  E :    for (size_t i = 0; i < num_sections; ++i) {
 646  E :      const IMAGE_SECTION_HEADER* header = image_file_.section_header(i);
 647  E :      DCHECK(header != NULL);
 648  E :      if (header->NumberOfRelocations == 0)
 649  E :        continue;
 650    :  
 651  E :      FileOffsetAddress relocs_start(header->PointerToRelocations);
 652  E :      size_t relocs_size(header->NumberOfRelocations * sizeof(IMAGE_RELOCATION));
 653    :  
 654    :      // Create a block for this relocation table.
 655    :      Block* block =
 656    :          CreateBlock(BlockGraph::DATA_BLOCK,
 657  E :                      relocs_start, relocs_size, kRelocsBlockName);
 658  E :      if (block == NULL)
 659  i :        return false;
 660  E :      block->set_attribute(BlockGraph::COFF_RELOC_DATA);
 661  E :    }
 662  E :    return true;
 663  E :  }
 664    :  
 665  E :  bool CoffDecomposer::CreateBlocksFromSections() {
 666  E :    DCHECK(image_ != NULL);
 667    :  
 668    :    // Build COMDAT symbol map, which associates each COMDAT section
 669    :    // with the COMDAT (secondary) symbol. When compiling with
 670    :    // function-level linking (/Gy for MSVC), all data and code lives in
 671    :    // COMDAT sections. Each COMDAT section is associated with at least
 672    :    // one symbol in the symbol table (the primary symbol), but usually
 673    :    // two or more.
 674    :    //
 675    :    // The primary symbol must always be the section symbol, which
 676    :    // indicates which final executable section the COMDAT section will
 677    :    // need to be merged into (e.g., .text or .data).
 678    :    //
 679    :    // The secondary symbol, when it exists, is the first symbol bound
 680    :    // to the COMDAT section that comes after the primary (usually but
 681    :    // not necessarily right after). With function-level linking, the
 682    :    // secondary symbol is always the name of the function or variable
 683    :    // defined in the section.
 684    :    //
 685    :    // The COFF decomposer assumes functions live in their own sections,
 686    :    // which is guaranteed by the MSVC compiler documentation for /Gy,
 687    :    // but is more forgiving when it comes to variables, which may be
 688    :    // grouped together in one or multiple data sections.
 689  E :    ComdatMap comdat_map;
 690  E :    size_t num_symbols = image_file_.file_header()->NumberOfSymbols;
 691  E :    const IMAGE_SYMBOL* symbol = NULL;
 692  E :    for (size_t i = 0; i < num_symbols; i += 1 + symbol->NumberOfAuxSymbols) {
 693  E :      symbol = image_file_.symbol(i);
 694  E :      DCHECK(symbol != NULL);
 695  E :      if (symbol->SectionNumber <= 0)
 696  E :        continue;
 697  E :      size_t section_index = symbol->SectionNumber - 1;
 698    :  
 699    :      // Skip non-COMDAT sections.
 700    :      const IMAGE_SECTION_HEADER* header =
 701  E :          image_file_.section_header(section_index);
 702  E :      DCHECK(header != NULL);
 703  E :      if ((header->Characteristics & IMAGE_SCN_LNK_COMDAT) == 0)
 704  E :        continue;
 705    :  
 706    :      // Skip primary section symbols.
 707  E :      ComdatMap::iterator it = comdat_map.find(section_index);
 708  E :      if (it == comdat_map.end()) {
 709    :        comdat_map.insert(std::make_pair(section_index,
 710  E :                                         static_cast<const char*>(0)));
 711  E :      } else {
 712    :        // Skip symbols after the second one.
 713  E :        if (it->second != NULL)
 714  E :          continue;
 715    :  
 716    :        // This should be the second symbol (assuming the first one is
 717    :        // the section symbol, as mandated by the specifications), that
 718    :        // is, the COMDAT symbol.
 719  E :        it->second = image_file_.GetSymbolName(i);
 720    :      }
 721  E :    }
 722    :  
 723    :    // Build a block for each data or code section.
 724  E :    size_t num_sections = image_file_.file_header()->NumberOfSections;
 725  E :    for (size_t i = 0; i < num_sections; ++i) {
 726  E :      const IMAGE_SECTION_HEADER* header = image_file_.section_header(i);
 727  E :      DCHECK(header != NULL);
 728    :      BlockType block_type = GetSectionType(*header) == kSectionCode ?
 729  E :                             BlockGraph::CODE_BLOCK : BlockGraph::DATA_BLOCK;
 730    :  
 731    :      // Retrieve or make up a suitable name for the block.
 732  E :      std::string name(image_file_.GetSectionName(*header));
 733  E :      ComdatMap::iterator it = comdat_map.find(i);
 734  E :      if (it != comdat_map.end()) {
 735  E :        name.append(kSectionComdatSep);
 736  E :        if (it->second != NULL)
 737  E :          name.append(it->second);
 738    :      }
 739    :  
 740    :      // Compute the address of the block; when using function-level linking,
 741    :      // each function begins at offset zero. Unmapped sections (BSS) get an
 742    :      // unmapped block with an invalid address.
 743  E :      FileOffsetAddress addr(FileOffsetAddress::kInvalidAddress);
 744  E :      if (image_file_.IsSectionMapped(i)) {
 745  E :        CHECK(image_file_.SectionOffsetToFileOffset(i, 0, &addr));
 746    :      }
 747    :  
 748    :      // Put everything together into a block.
 749    :      Block* block = CreateBlock(block_type,
 750  E :                                 addr, header->SizeOfRawData, name.c_str());
 751  E :      if (block == NULL) {
 752  i :        LOG(ERROR) << "Unable to create block for section " << i << " \""
 753    :                   << name << "\".";
 754  i :        return false;
 755    :      }
 756    :  
 757    :      // Assuming block graph section IDs match those of the image file.
 758  E :      block->set_section(i);
 759    :      block->set_attribute(image_file_.IsSectionMapped(i) ?
 760  E :                           BlockGraph::SECTION_CONTRIB : BlockGraph::COFF_BSS);
 761    :  
 762    :      // Add to section-block map so we can find it later.
 763  E :      section_block_map_.insert(std::make_pair(i, block));
 764  E :    }
 765    :  
 766  E :    return true;
 767  E :  }
 768    :  
 769  E :  bool CoffDecomposer::CreateReferencesFromDebugInfo() {
 770  E :    DCHECK(image_ != NULL);
 771    :  
 772    :    // Read debug data directly from the block graph, since debug section
 773    :    // blocks have already been inserted.
 774  E :    BlockGraph::BlockMap& blocks = image_->graph()->blocks_mutable();
 775  E :    BlockGraph::BlockMap::iterator it = blocks.begin();
 776  E :    for (; it != blocks.end(); ++it) {
 777  E :      size_t section_index = it->second.section();
 778    :      BlockGraph::Section* section =
 779  E :          image_->graph()->GetSectionById(section_index);
 780  E :      if (section == NULL || section->name() != ".debug$S")
 781  E :        continue;
 782    :  
 783  E :      Block* block = &it->second;
 784  E :      ConstTypedBlock<uint32> magic;
 785  E :      if (!magic.Init(0, block)) {
 786  i :        LOG(ERROR) << "Unable to read magic number from .debug$S section "
 787    :                   << section_index << ".";
 788  i :        return false;
 789    :      }
 790    :  
 791    :      // Parse subsections.
 792  E :      switch (*magic) {
 793    :        case cci::C11: {
 794  E :          if (!ParseDebugSubsections2(block))
 795  i :            return false;
 796  E :          break;
 797    :        }
 798    :  
 799    :        case cci::C13: {
 800  E :          if (!ParseDebugSubsections4(block))
 801  i :            return false;
 802  E :          break;
 803    :        }
 804    :  
 805    :        default: {
 806  i :          LOG(ERROR) << "Unsupported CV version " << *magic
 807    :                     << " in .debug$S section " << section_index << ".";
 808  i :          return false;
 809    :        }
 810    :      }
 811  E :    }
 812  E :    return true;
 813  E :  }
 814    :  
 815  E :  bool CoffDecomposer::CreateReferencesFromRelocations() {
 816  E :    DCHECK(image_ != NULL);
 817    :  
 818  E :    CoffFile::RelocMap reloc_map;
 819  E :    image_file_.DecodeRelocs(&reloc_map);
 820    :  
 821  E :    CoffFile::RelocMap::iterator it = reloc_map.begin();
 822  E :    for (; it != reloc_map.end(); ++it) {
 823  E :      DCHECK(it->second != NULL);
 824    :      const IMAGE_SYMBOL* symbol =
 825  E :          image_file_.symbol(it->second->SymbolTableIndex);
 826  E :      DCHECK(symbol != NULL);
 827    :  
 828    :      // Compute reference attributes.
 829  E :      ReferenceType ref_type = BlockGraph::REFERENCE_TYPE_MAX;
 830  E :      BlockGraph::Size ref_size = 0;
 831  E :      if (!GetRelocationTypeAndSize(*it->second, &ref_type, &ref_size))
 832  i :        continue;
 833  E :      DCHECK_LT(ref_type, BlockGraph::REFERENCE_TYPE_MAX);
 834  E :      DCHECK_GT(ref_size, 0u);
 835    :  
 836    :      // Add reference.
 837  E :      size_t offset = symbol->SectionNumber == 0 ? 0 : symbol->Value;
 838    :      if (!CreateSymbolOffsetReference(it->first, ref_type, ref_size,
 839  E :                                       symbol, offset)) {
 840  i :        return false;
 841    :      }
 842  E :    }
 843    :  
 844  E :    return true;
 845  E :  }
 846    :  
 847  E :  bool CoffDecomposer::CreateLabelsFromSymbols() {
 848  E :    DCHECK(image_ != NULL);
 849    :  
 850  E :    size_t num_symbols = image_file_.file_header()->NumberOfSymbols;
 851    :    const IMAGE_SYMBOL* symbol;
 852  E :    for (size_t i = 0; i < num_symbols; i += 1 + symbol->NumberOfAuxSymbols) {
 853  E :      symbol = image_file_.symbol(i);
 854    :  
 855    :      // Data labels should reference a valid section, have storage
 856    :      // class STATIC, a non-function type (contrary to static
 857    :      // functions), and no auxiliary record (contrary to section
 858    :      // definitions). Skip the rest.
 859    :      //
 860    :      // MSVC records section descriptions in the symbol table as STATIC
 861    :      // data symbols; hence a section symbol and the first data symbol
 862    :      // at offset zero will have the same storage class and offset;
 863    :      // data symbols, however, occupy a single entry in the table,
 864    :      // whereas section symbols take two records (hence one auxiliary
 865    :      // record with class-specific data in addition of the main
 866    :      // record).
 867    :      if (!(symbol->SectionNumber > 0 &&
 868    :            symbol->StorageClass == IMAGE_SYM_CLASS_STATIC &&
 869    :            symbol->Type >> 4 != IMAGE_SYM_DTYPE_FUNCTION &&
 870  E :            symbol->NumberOfAuxSymbols == 0)) {
 871  E :        continue;
 872    :      }
 873  E :      size_t section_index = symbol->SectionNumber - 1;
 874    :  
 875    :      // Skip labels in non-code sections.
 876    :      const IMAGE_SECTION_HEADER* header =
 877  E :          image_file_.section_header(section_index);
 878  E :      DCHECK(header != NULL);
 879  E :      if (GetSectionType(*header) != kSectionCode)
 880  E :        continue;
 881    :  
 882    :      // Get block and offset.
 883  E :      SectionBlockMap::iterator it = section_block_map_.find(section_index);
 884  E :      DCHECK(it != section_block_map_.end());
 885  E :      Block* block = it->second;
 886  E :      DCHECK(block != NULL);
 887  E :      BlockGraph::Offset offset = symbol->Value;
 888    :  
 889    :      // Tables only appear in code blocks; ignore others.
 890  E :      if (block->type() != BlockGraph::CODE_BLOCK)
 891  i :        continue;
 892    :  
 893    :      // Compute label attributes. Jump tables are always an array of
 894    :      // pointers, thus they coincide exactly with a reference. Case
 895    :      // tables are simple arrays of integer values, thus do not
 896    :      // coincide with a reference.
 897  E :      BlockGraph::LabelAttributes attrs = BlockGraph::DATA_LABEL;
 898  E :      if (block->references().find(offset) != block->references().end()) {
 899  E :        attrs |= BlockGraph::JUMP_TABLE_LABEL;
 900  E :      } else {
 901  E :        attrs |= BlockGraph::CASE_TABLE_LABEL;
 902    :      }
 903    :  
 904    :      // Add label.
 905  E :      const char* name = image_file_.GetSymbolName(i);
 906  E :      if (!AddLabelToBlock(offset, name, attrs, block))
 907  i :        return false;
 908  E :    }
 909  E :    return true;
 910  E :  }
 911    :  
 912    :  Block* CoffDecomposer::CreateBlock(BlockType type,
 913    :                                     FileOffsetAddress addr,
 914    :                                     BlockGraph::Size size,
 915  E :                                     const base::StringPiece& name) {
 916  E :    DCHECK(image_ != NULL);
 917    :  
 918  E :    if (addr == FileOffsetAddress::kInvalidAddress) {
 919    :      // Unmapped block.
 920  E :      Block* block = image_->graph()->AddBlock(type, size, name);
 921  E :      if (block == NULL) {
 922  i :        LOG(ERROR) << "Unable to add unmapped block \"" << name.as_string()
 923    :                   << "\" with size " << size << ".";
 924  i :        return NULL;
 925    :      }
 926  E :      return block;
 927    :    }
 928    :  
 929    :    // Otherwise, we have a normal mapped block.
 930  E :    BlockGraphAddress block_addr(FileOffsetToBlockGraphAddress(addr));
 931  E :    Block* block = image_->AddBlock(type, block_addr, size, name);
 932  E :    if (block == NULL) {
 933  i :      LOG(ERROR) << "Unable to add block \"" << name.as_string() << "\" at "
 934    :                 << block_addr << " with size " << size << ".";
 935  i :      return NULL;
 936    :    }
 937    :  
 938    :    // Mark the source range from whence this block originates.
 939  E :    if (size > 0) {
 940    :      bool pushed = block->source_ranges().Push(
 941    :          Block::DataRange(0, size),
 942  E :          Block::SourceRange(block_addr, size));
 943  E :      DCHECK(pushed);
 944    :    }
 945    :  
 946  E :    const uint8* data = image_file_.GetImageData(addr, size);
 947  E :    if (data != NULL)
 948  E :      block->SetData(data, size);
 949    :  
 950  E :    return block;
 951  E :  }
 952    :  
 953    :  bool CoffDecomposer::CreateReference(FileOffsetAddress src_addr,
 954    :                                       ReferenceType ref_type,
 955    :                                       BlockGraph::Size ref_size,
 956    :                                       Block* target,
 957  E :                                       BlockGraph::Offset offset) {
 958  E :    DCHECK(image_ != NULL);
 959    :  
 960    :    // Get source block and offset.
 961  E :    Block* source = NULL;
 962  E :    BlockGraph::Offset src_offset = -1;
 963  E :    if (!FileOffsetToBlockOffset(src_addr, &source, &src_offset))
 964  i :      return false;
 965  E :    DCHECK(source != NULL);
 966  E :    DCHECK_GE(src_offset, 0);
 967    :  
 968    :    // Read additional offset for relocations.
 969  E :    BlockGraph::Offset extra_offset = 0;
 970  E :    if ((ref_type & BlockGraph::RELOC_REF_BIT) != 0) {
 971  E :      switch (ref_size) {
 972    :        case sizeof(uint32):
 973  E :          if (!ReadRelocationValue<uint32>(source, src_offset, &extra_offset))
 974  i :            return false;
 975  E :          break;
 976    :        case sizeof(uint16):
 977  E :          if (!ReadRelocationValue<uint16>(source, src_offset, &extra_offset))
 978  i :            return false;
 979  E :          break;
 980    :        case sizeof(uint8):
 981    :          // TODO(chrisha): This is really a special 7-bit relocation; we do
 982    :          // not touch these, for now.
 983  i :          break;
 984    :        default:
 985  i :          LOG(ERROR) << "Unsupported relocation value size (" << ref_size << ").";
 986  i :          return false;
 987    :      }
 988    :    }
 989    :  
 990    :    // Find an existing reference, or insert a new one.
 991  E :    Reference ref(ref_type, ref_size, target, offset + extra_offset, offset);
 992    :    Block::ReferenceMap::const_iterator ref_it =
 993  E :        source->references().find(src_offset);
 994  E :    if (ref_it == source->references().end()) {
 995    :      // New reference.
 996  E :      CHECK(source->SetReference(src_offset, ref));
 997  E :    } else {
 998    :      // Collisions are only allowed if the references are identical.
 999  i :      if (!(ref == ref_it->second)) {
1000  i :        LOG(ERROR) << "Block \"" << source->name() << "\" has a conflicting "
1001    :                   << "reference at offset " << src_offset << ".";
1002  i :        return false;
1003    :      }
1004    :    }
1005    :  
1006  E :    return true;
1007  E :  }
1008    :  
1009    :  bool CoffDecomposer::CreateFileOffsetReference(FileOffsetAddress src_addr,
1010    :                                                 ReferenceType ref_type,
1011    :                                                 BlockGraph::Size ref_size,
1012  E :                                                 FileOffsetAddress dst_addr) {
1013  E :    DCHECK(image_ != NULL);
1014    :  
1015    :    // Get target section and offset.
1016  E :    Block* target = NULL;
1017  E :    BlockGraph::Offset offset = -1;
1018  E :    if (!FileOffsetToBlockOffset(dst_addr, &target, &offset))
1019  i :      return false;
1020  E :    DCHECK(target != NULL);
1021  E :    DCHECK_GE(offset, 0);
1022    :  
1023    :    // Add reference.
1024  E :    if (!CreateReference(src_addr, ref_type, ref_size, target, offset))
1025  i :      return false;
1026    :  
1027  E :    return true;
1028  E :  }
1029    :  
1030    :  bool CoffDecomposer::CreateSectionOffsetReference(FileOffsetAddress src_addr,
1031    :                                                    ReferenceType ref_type,
1032    :                                                    BlockGraph::Size ref_size,
1033    :                                                    size_t section_index,
1034  E :                                                    size_t section_offset) {
1035  E :    DCHECK(image_ != NULL);
1036    :  
1037    :    // Get target section and offset.
1038  E :    Block* target = NULL;
1039  E :    BlockGraph::Offset offset = -1;
1040    :    if (!SectionOffsetToBlockOffset(section_index, section_offset,
1041  E :                                    &target, &offset)) {
1042  i :      return false;
1043    :    }
1044  E :    DCHECK(target != NULL);
1045  E :    DCHECK_GE(offset, 0);
1046    :  
1047    :    // Add reference.
1048  E :    if (!CreateReference(src_addr, ref_type, ref_size, target, offset))
1049  i :      return false;
1050    :  
1051  E :    return true;
1052  E :  }
1053    :  
1054    :  bool CoffDecomposer::CreateSymbolOffsetReference(FileOffsetAddress src_addr,
1055    :                                                   ReferenceType ref_type,
1056    :                                                   BlockGraph::Size ref_size,
1057    :                                                   const IMAGE_SYMBOL* symbol,
1058  E :                                                   size_t offset) {
1059  E :    DCHECK(image_ != NULL);
1060  E :    DCHECK(symbol != NULL);
1061    :  
1062  E :    if (symbol->SectionNumber < 0) {
1063  i :      LOG(ERROR) << "Symbol cannot be converted to a reference.";
1064  i :      return false;
1065    :    }
1066    :  
1067  E :    if (symbol->SectionNumber != 0) {
1068    :      // Section symbol.
1069    :      return CreateSectionOffsetReference(src_addr, ref_type, ref_size,
1070  E :                                          symbol->SectionNumber - 1, offset);
1071  i :    } else {
1072    :      // External symbol. As a convention, we use a reference to the symbol
1073    :      // table, since there is no corresponding block. The offset is ignored
1074    :      // (will be inferred from the symbol value and reference type).
1075  E :      size_t symbol_index = symbol - image_file_.symbols();
1076    :      return CreateFileOffsetReference(
1077    :          src_addr, ref_type, ref_size,
1078  E :          image_file_.symbols_address() + symbol_index * sizeof(*symbol));
1079    :    }
1080  E :  }
1081    :  
1082    :  bool CoffDecomposer::FileOffsetToBlockOffset(FileOffsetAddress addr,
1083    :                                               Block** block,
1084  E :                                               BlockGraph::Offset* offset) {
1085  E :    DCHECK(image_ != NULL);
1086  E :    DCHECK(block != NULL);
1087  E :    DCHECK(offset != NULL);
1088    :  
1089    :    // Get block and offset.
1090  E :    BlockGraphAddress actual_addr(FileOffsetToBlockGraphAddress(addr));
1091  E :    Block* containing_block = image_->GetBlockByAddress(actual_addr);
1092  E :    if (containing_block == NULL) {
1093  i :      LOG(ERROR) << "File offset " << addr << " does not lie within a block.";
1094  i :      return false;
1095    :    }
1096  E :    BlockGraphAddress block_addr;
1097  E :    CHECK(image_->GetAddressOf(containing_block, &block_addr));
1098    :  
1099  E :    *block = containing_block;
1100  E :    *offset = actual_addr - block_addr;
1101  E :    return true;
1102  E :  }
1103    :  
1104    :  bool CoffDecomposer::SectionOffsetToBlockOffset(size_t section_index,
1105    :                                                  size_t section_offset,
1106    :                                                  Block** block,
1107  E :                                                  BlockGraph::Offset* offset) {
1108  E :    DCHECK(image_ != NULL);
1109  E :    DCHECK_NE(BlockGraph::kInvalidSectionId, section_index);
1110  E :    DCHECK_LT(section_index, image_file_.file_header()->NumberOfSections);
1111    :    DCHECK_LE(section_offset,
1112  E :              image_file_.section_header(section_index)->SizeOfRawData);
1113  E :    DCHECK(block != NULL);
1114  E :    DCHECK(offset != NULL);
1115    :  
1116    :    // Get block and offset.
1117  E :    SectionBlockMap::iterator it = section_block_map_.find(section_index);
1118  E :    if (it == section_block_map_.end()) {
1119  i :      LOG(ERROR) << "Section " << section_index << " is not mapped to a block.";
1120  i :      return false;
1121    :    }
1122  E :    DCHECK(it->second != NULL);
1123  E :    DCHECK_LE(section_offset, it->second->size());
1124    :  
1125  E :    *block = it->second;
1126  E :    *offset = section_offset;
1127  E :    return true;
1128  E :  }
1129    :  
1130    :  CoffDecomposer::BlockGraphAddress CoffDecomposer::FileOffsetToBlockGraphAddress(
1131  E :      FileOffsetAddress addr) {
1132  E :    return BlockGraphAddress(addr.value());
1133  E :  }
1134    :  
1135    :  }  // namespace pe

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