Coverage for /Syzygy/pe/coff_decomposer.cc

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

Coverage information generated Wed Dec 11 11:34:16 2013.