Coverage for /Syzygy/pe/coff_decomposer.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
80.2%4165190.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 section_index = block->section();
 422  E :    size_t cursor = sizeof(uint32);
 423  E :    if (!ParseDebugSymbols(cci::C11, cursor, block->size() - cursor, block))
 424  i :      return false;
 425    :  
 426  E :    return true;
 427  E :  }
 428    :  
 429    :  }  // namespace
 430    :  
 431    :  const char CoffDecomposer::kSectionComdatSep[] = "; COMDAT=";
 432    :  
 433    :  CoffDecomposer::CoffDecomposer(const CoffFile& image_file)
 434    :      : image_file_(image_file),
 435    :        image_layout_(NULL),
 436  E :        image_(NULL) {
 437  E :  }
 438    :  
 439  E :  bool CoffDecomposer::Decompose(ImageLayout* image_layout) {
 440  E :    DCHECK_NE(reinterpret_cast<ImageLayout*>(NULL), image_layout);
 441    :  
 442    :    // Internal temporaries.
 443  E :    DCHECK_EQ(reinterpret_cast<ImageLayout*>(NULL), image_layout_);
 444  E :    DCHECK_EQ(reinterpret_cast<BlockGraph::AddressSpace*>(NULL),image_);
 445  E :    AutoReset<ImageLayout*> auto_reset_image_layout(&image_layout_, image_layout);
 446    :    AutoReset<BlockGraph::AddressSpace*> auto_reset_image(&image_,
 447  E :                                                          &image_layout->blocks);
 448    :  
 449    :    // Set the image format.
 450  E :    image_layout->blocks.graph()->set_image_format(BlockGraph::COFF_IMAGE);
 451    :  
 452    :    // Copy the image headers to the layout.
 453    :    CopySectionHeadersToImageLayout(
 454    :        image_file_.file_header()->NumberOfSections,
 455    :        image_file_.section_headers(),
 456  E :        &image_layout_->sections);
 457    :  
 458  E :    if (!CopySectionInfoToBlockGraph(image_file_, image_->graph()))
 459  i :      return false;
 460    :  
 461  E :    if (!CreateBlocksFromSections())
 462  i :      return false;
 463    :  
 464  E :    if (!CreateBlocksAndReferencesFromNonSections())
 465  i :      return false;
 466    :  
 467  E :    if (!CreateReferencesFromRelocations())
 468  i :      return false;
 469    :  
 470  E :    if (!CreateReferencesFromDebugInfo())
 471  i :      return false;
 472    :  
 473  E :    if (!CreateLabelsFromSymbols())
 474  i :      return false;
 475    :  
 476  E :    return true;
 477  E :  }
 478    :  
 479  E :  bool CoffDecomposer::CreateBlocksAndReferencesFromNonSections() {
 480  E :    DCHECK(image_ != NULL);
 481    :  
 482  E :    if (!CreateBlocksAndReferencesFromSymbolAndStringTables())
 483  i :      return false;
 484    :  
 485  E :    if (!CreateBlocksFromRelocationTables())
 486  i :      return false;
 487    :  
 488  E :    if (!CreateBlocksAndReferencesFromHeaders())
 489  i :      return false;
 490    :  
 491  E :    return true;
 492  E :  }
 493    :  
 494  E :  bool CoffDecomposer::CreateBlocksAndReferencesFromHeaders() {
 495  E :    const IMAGE_FILE_HEADER* file_header = image_file_.file_header();
 496  E :    DCHECK(file_header != NULL);
 497    :  
 498    :    // Create a block for COFF and section headers.
 499    :    size_t headers_size =
 500    :        sizeof(*file_header) +
 501  E :        file_header->NumberOfSections * sizeof(IMAGE_SECTION_HEADER);
 502    :    Block* block = CreateBlock(BlockGraph::DATA_BLOCK, FileOffsetAddress(0),
 503  E :                               headers_size, kHeadersBlockName);
 504  E :    if (block == NULL) {
 505  i :      LOG(ERROR) << "Unable to create block for headers.";
 506  i :      return false;
 507    :    }
 508  E :    block->set_attribute(BlockGraph::COFF_HEADERS);
 509    :  
 510    :    // Create a reference for the symbol table pointer.
 511    :    FileOffsetAddress symbols_ptr_addr(
 512  E :        offsetof(IMAGE_FILE_HEADER, PointerToSymbolTable));
 513    :    if (!CreateFileOffsetReference(
 514    :            symbols_ptr_addr,
 515    :            BlockGraph::FILE_OFFSET_REF,
 516    :            sizeof(file_header->PointerToSymbolTable),
 517  E :            FileOffsetAddress(file_header->PointerToSymbolTable))) {
 518  i :      return false;
 519    :    }
 520    :  
 521    :    // Create a reference for the section and relocation pointers in each section
 522    :    // header.
 523    :    FileOffsetAddress section_headers_start(
 524  E :        sizeof(*file_header) + file_header->SizeOfOptionalHeader);
 525  E :    size_t num_sections = image_file_.file_header()->NumberOfSections;
 526  E :    for (size_t i = 0; i < num_sections; ++i) {
 527  E :      const IMAGE_SECTION_HEADER* header = image_file_.section_header(i);
 528  E :      DCHECK(header != NULL);
 529  E :      FileOffsetAddress start(section_headers_start + i * sizeof(*header));
 530    :  
 531    :      FileOffsetAddress data_ptr_addr(
 532  E :          start + offsetof(IMAGE_SECTION_HEADER, PointerToRawData));
 533    :      if (!CreateFileOffsetReference(
 534    :              data_ptr_addr,
 535    :              BlockGraph::FILE_OFFSET_REF,
 536    :              sizeof(header->PointerToRawData),
 537  E :              FileOffsetAddress(header->PointerToRawData))) {
 538  i :        return false;
 539    :      }
 540    :  
 541    :      FileOffsetAddress relocs_ptr_addr(
 542  E :          start + offsetof(IMAGE_SECTION_HEADER, PointerToRelocations));
 543    :      if (!CreateFileOffsetReference(
 544    :              relocs_ptr_addr,
 545    :              BlockGraph::FILE_OFFSET_REF,
 546    :              sizeof(header->PointerToRelocations),
 547  E :              FileOffsetAddress(header->PointerToRelocations))) {
 548  i :        return false;
 549    :      }
 550  E :    }
 551    :  
 552  E :    return true;
 553  E :  }
 554    :  
 555  E :  bool CoffDecomposer::CreateBlocksAndReferencesFromSymbolAndStringTables() {
 556    :    // Create a block for the symbol table.
 557  E :    FileOffsetAddress symbols_start(image_file_.symbols_address());
 558  E :    size_t symbols_size = image_file_.symbols_size();
 559    :    Block* block = CreateBlock(BlockGraph::DATA_BLOCK,
 560  E :                               symbols_start, symbols_size, kSymbolsBlockName);
 561  E :    if (block == NULL) {
 562  i :      LOG(ERROR) << "Unable to create block for symbols.";
 563  i :      return false;
 564    :    }
 565  E :    block->set_attribute(BlockGraph::COFF_SYMBOL_TABLE);
 566    :  
 567    :    // Create a block for the strings table that follows.
 568  E :    FileOffsetAddress strings_start(image_file_.strings_address());
 569  E :    size_t strings_size = image_file_.strings_size();
 570    :    block = CreateBlock(BlockGraph::DATA_BLOCK,
 571  E :                        strings_start, strings_size, kStringsBlockName);
 572  E :    if (block == NULL) {
 573  i :      LOG(ERROR) << "Unable to create block for strings.";
 574  i :      return false;
 575    :    }
 576  E :    block->set_attribute(BlockGraph::COFF_STRING_TABLE);
 577    :  
 578    :    // Add references.
 579  E :    size_t num_symbols = image_file_.file_header()->NumberOfSymbols;
 580  E :    const IMAGE_SYMBOL* symbol = NULL;
 581  E :    for (size_t i = 0; i < num_symbols; i += 1 + symbol->NumberOfAuxSymbols) {
 582  E :      symbol = image_file_.symbol(i);
 583    :  
 584    :      // Ignore external symbols (no references to blocks) and other kinds of
 585    :      // non-reference symbols.
 586  E :      if (symbol->SectionNumber <= 0)
 587  E :        continue;
 588    :  
 589  E :      FileOffsetAddress start(symbols_start + i * sizeof(*symbol));
 590    :  
 591    :      // Symbols with section storage class simply provide the characteristics
 592    :      // of the section in the symbol value. Other symbols store an actual offset
 593    :      // into a section in the value field.
 594  E :      if (symbol->StorageClass != IMAGE_SYM_CLASS_SECTION) {
 595  E :        FileOffsetAddress value_addr(start + offsetof(IMAGE_SYMBOL, Value));
 596    :        if (!CreateSymbolOffsetReference(
 597    :                value_addr,
 598    :                BlockGraph::SECTION_OFFSET_REF,
 599    :                sizeof(symbol->Value),
 600    :                symbol,
 601  E :                symbol->Value)) {
 602  i :          return false;
 603    :        }
 604    :      }
 605    :  
 606    :      FileOffsetAddress section_addr(
 607  E :          start + offsetof(IMAGE_SYMBOL, SectionNumber));
 608    :      if (!CreateSymbolOffsetReference(
 609    :              section_addr,
 610    :              BlockGraph::SECTION_REF,
 611    :              sizeof(symbol->SectionNumber),
 612    :              symbol,
 613  E :              0)) {
 614  i :        return false;
 615    :      }
 616    :  
 617    :      // Section definitions for associative COMDAT sections require an additional
 618    :      // section reference within the auxiliary symbol.
 619    :      if (symbol->StorageClass == IMAGE_SYM_CLASS_STATIC &&
 620    :          symbol->Type >> 4 != IMAGE_SYM_DTYPE_FUNCTION &&
 621  E :          symbol->NumberOfAuxSymbols == 1) {
 622    :        const IMAGE_AUX_SYMBOL* aux =
 623  E :            reinterpret_cast<const IMAGE_AUX_SYMBOL*>(image_file_.symbol(i + 1));
 624  E :        DCHECK(aux != NULL);
 625  E :        if (aux->Section.Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
 626    :          FileOffsetAddress number_addr(
 627    :              start + sizeof(IMAGE_SYMBOL) +
 628  E :              offsetof(IMAGE_AUX_SYMBOL, Section.Number));
 629    :          if (!CreateSectionOffsetReference(
 630    :                  number_addr,
 631    :                  BlockGraph::SECTION_REF,
 632    :                  sizeof(short),
 633    :                  aux->Section.Number - 1,
 634  E :                  0)) {
 635  i :            return false;
 636    :          }
 637    :        }
 638    :      }
 639  E :    }
 640    :  
 641  E :    return true;
 642  E :  }
 643    :  
 644  E :  bool CoffDecomposer::CreateBlocksFromRelocationTables() {
 645  E :    size_t num_sections = image_file_.file_header()->NumberOfSections;
 646  E :    for (size_t i = 0; i < num_sections; ++i) {
 647  E :      const IMAGE_SECTION_HEADER* header = image_file_.section_header(i);
 648  E :      DCHECK(header != NULL);
 649  E :      if (header->NumberOfRelocations == 0)
 650  E :        continue;
 651    :  
 652  E :      FileOffsetAddress relocs_start(header->PointerToRelocations);
 653  E :      size_t relocs_size(header->NumberOfRelocations * sizeof(IMAGE_RELOCATION));
 654    :  
 655    :      // Create a block for this relocation table.
 656    :      Block* block =
 657    :          CreateBlock(BlockGraph::DATA_BLOCK,
 658  E :                      relocs_start, relocs_size, kRelocsBlockName);
 659  E :      if (block == NULL)
 660  i :        return false;
 661  E :      block->set_attribute(BlockGraph::COFF_RELOC_DATA);
 662  E :    }
 663  E :    return true;
 664  E :  }
 665    :  
 666  E :  bool CoffDecomposer::CreateBlocksFromSections() {
 667  E :    DCHECK(image_ != NULL);
 668    :  
 669    :    // Build COMDAT symbol map, which associates each COMDAT section
 670    :    // with the COMDAT (secondary) symbol. When compiling with
 671    :    // function-level linking (/Gy for MSVC), all data and code lives in
 672    :    // COMDAT sections. Each COMDAT section is associated with at least
 673    :    // one symbol in the symbol table (the primary symbol), but usually
 674    :    // two or more.
 675    :    //
 676    :    // The primary symbol must always be the section symbol, which
 677    :    // indicates which final executable section the COMDAT section will
 678    :    // need to be merged into (e.g., .text or .data).
 679    :    //
 680    :    // The secondary symbol, when it exists, is the first symbol bound
 681    :    // to the COMDAT section that comes after the primary (usually but
 682    :    // not necessarily right after). With function-level linking, the
 683    :    // secondary symbol is always the name of the function or variable
 684    :    // defined in the section.
 685    :    //
 686    :    // The COFF decomposer assumes functions live in their own sections,
 687    :    // which is guaranteed by the MSVC compiler documentation for /Gy,
 688    :    // but is more forgiving when it comes to variables, which may be
 689    :    // grouped together in one or multiple data sections.
 690  E :    ComdatMap comdat_map;
 691  E :    size_t num_symbols = image_file_.file_header()->NumberOfSymbols;
 692  E :    const IMAGE_SYMBOL* symbol = NULL;
 693  E :    for (size_t i = 0; i < num_symbols; i += 1 + symbol->NumberOfAuxSymbols) {
 694  E :      symbol = image_file_.symbol(i);
 695  E :      DCHECK(symbol != NULL);
 696  E :      if (symbol->SectionNumber <= 0)
 697  E :        continue;
 698  E :      size_t section_index = symbol->SectionNumber - 1;
 699    :  
 700    :      // Skip non-COMDAT sections.
 701    :      const IMAGE_SECTION_HEADER* header =
 702  E :          image_file_.section_header(section_index);
 703  E :      DCHECK(header != NULL);
 704  E :      if ((header->Characteristics & IMAGE_SCN_LNK_COMDAT) == 0)
 705  E :        continue;
 706    :  
 707    :      // Skip primary section symbols.
 708  E :      ComdatMap::iterator it = comdat_map.find(section_index);
 709  E :      if (it == comdat_map.end()) {
 710    :        comdat_map.insert(std::make_pair(section_index,
 711  E :                                         static_cast<const char*>(0)));
 712  E :      } else {
 713    :        // Skip symbols after the second one.
 714  E :        if (it->second != NULL)
 715  E :          continue;
 716    :  
 717    :        // This should be the second symbol (assuming the first one is
 718    :        // the section symbol, as mandated by the specifications), that
 719    :        // is, the COMDAT symbol.
 720  E :        it->second = image_file_.GetSymbolName(i);
 721    :      }
 722  E :    }
 723    :  
 724    :    // Build a block for each data or code section.
 725  E :    size_t num_sections = image_file_.file_header()->NumberOfSections;
 726  E :    for (size_t i = 0; i < num_sections; ++i) {
 727  E :      const IMAGE_SECTION_HEADER* header = image_file_.section_header(i);
 728  E :      DCHECK(header != NULL);
 729    :      BlockType block_type = GetSectionType(*header) == kSectionCode ?
 730  E :                             BlockGraph::CODE_BLOCK : BlockGraph::DATA_BLOCK;
 731    :  
 732    :      // Retrieve or make up a suitable name for the block.
 733  E :      std::string name(image_file_.GetSectionName(*header));
 734  E :      ComdatMap::iterator it = comdat_map.find(i);
 735  E :      if (it != comdat_map.end()) {
 736  E :        name.append(kSectionComdatSep);
 737  E :        if (it->second != NULL)
 738  E :          name.append(it->second);
 739    :      }
 740    :  
 741    :      // Compute the address of the block; when using function-level linking,
 742    :      // each function begins at offset zero. Unmapped sections (BSS) get an
 743    :      // unmapped block with an invalid address.
 744  E :      FileOffsetAddress addr(FileOffsetAddress::kInvalidAddress);
 745  E :      if (image_file_.IsSectionMapped(i)) {
 746  E :        CHECK(image_file_.SectionOffsetToFileOffset(i, 0, &addr));
 747    :      }
 748    :  
 749    :      // Put everything together into a block.
 750    :      Block* block = CreateBlock(block_type,
 751  E :                                 addr, header->SizeOfRawData, name.c_str());
 752  E :      if (block == NULL) {
 753  i :        LOG(ERROR) << "Unable to create block for section " << i << " \""
 754    :                   << name << "\".";
 755  i :        return false;
 756    :      }
 757    :  
 758    :      // Assuming block graph section IDs match those of the image file.
 759  E :      block->set_section(i);
 760    :      block->set_attribute(image_file_.IsSectionMapped(i) ?
 761  E :                           BlockGraph::SECTION_CONTRIB : BlockGraph::COFF_BSS);
 762    :  
 763    :      // Add to section-block map so we can find it later.
 764  E :      section_block_map_.insert(std::make_pair(i, block));
 765  E :    }
 766    :  
 767  E :    return true;
 768  E :  }
 769    :  
 770  E :  bool CoffDecomposer::CreateReferencesFromDebugInfo() {
 771  E :    DCHECK(image_ != NULL);
 772    :  
 773    :    // Read debug data directly from the block graph, since debug section
 774    :    // blocks have already been inserted.
 775  E :    BlockGraph::BlockMap& blocks = image_->graph()->blocks_mutable();
 776  E :    BlockGraph::BlockMap::iterator it = blocks.begin();
 777  E :    for (; it != blocks.end(); ++it) {
 778  E :      size_t section_index = it->second.section();
 779    :      BlockGraph::Section* section =
 780  E :          image_->graph()->GetSectionById(section_index);
 781  E :      if (section == NULL || section->name() != ".debug$S")
 782  E :        continue;
 783    :  
 784  E :      Block* block = &it->second;
 785  E :      ConstTypedBlock<uint32> magic;
 786  E :      if (!magic.Init(0, block)) {
 787  i :        LOG(ERROR) << "Unable to read magic number from .debug$S section "
 788    :                   << section_index << ".";
 789  i :        return false;
 790    :      }
 791    :  
 792    :      // Parse subsections.
 793  E :      switch (*magic) {
 794    :        case cci::C11: {
 795  E :          if (!ParseDebugSubsections2(block))
 796  i :            return false;
 797  E :          break;
 798    :        }
 799    :  
 800    :        case cci::C13: {
 801  E :          if (!ParseDebugSubsections4(block))
 802  i :            return false;
 803  E :          break;
 804    :        }
 805    :  
 806    :        default: {
 807  i :          LOG(ERROR) << "Unsupported CV version " << *magic
 808    :                     << " in .debug$S section " << section_index << ".";
 809  i :          return false;
 810    :        }
 811    :      }
 812  E :    }
 813  E :    return true;
 814  E :  }
 815    :  
 816  E :  bool CoffDecomposer::CreateReferencesFromRelocations() {
 817  E :    DCHECK(image_ != NULL);
 818    :  
 819  E :    CoffFile::RelocMap reloc_map;
 820  E :    image_file_.DecodeRelocs(&reloc_map);
 821    :  
 822  E :    CoffFile::RelocMap::iterator it = reloc_map.begin();
 823  E :    for (; it != reloc_map.end(); ++it) {
 824  E :      DCHECK(it->second != NULL);
 825    :      const IMAGE_SYMBOL* symbol =
 826  E :          image_file_.symbol(it->second->SymbolTableIndex);
 827  E :      DCHECK(symbol != NULL);
 828    :  
 829    :      // Compute reference attributes.
 830  E :      ReferenceType ref_type = BlockGraph::REFERENCE_TYPE_MAX;
 831  E :      BlockGraph::Size ref_size = 0;
 832  E :      if (!GetRelocationTypeAndSize(*it->second, &ref_type, &ref_size))
 833  i :        continue;
 834  E :      DCHECK_LT(ref_type, BlockGraph::REFERENCE_TYPE_MAX);
 835  E :      DCHECK_GT(ref_size, 0u);
 836    :  
 837    :      // Add reference.
 838  E :      size_t offset = symbol->SectionNumber == 0 ? 0 : symbol->Value;
 839    :      if (!CreateSymbolOffsetReference(it->first, ref_type, ref_size,
 840  E :                                       symbol, offset)) {
 841  i :        return false;
 842    :      }
 843  E :    }
 844    :  
 845  E :    return true;
 846  E :  }
 847    :  
 848  E :  bool CoffDecomposer::CreateLabelsFromSymbols() {
 849  E :    DCHECK(image_ != NULL);
 850    :  
 851  E :    size_t num_symbols = image_file_.file_header()->NumberOfSymbols;
 852    :    const IMAGE_SYMBOL* symbol;
 853  E :    for (size_t i = 0; i < num_symbols; i += 1 + symbol->NumberOfAuxSymbols) {
 854  E :      symbol = image_file_.symbol(i);
 855    :  
 856    :      // Data labels should reference a valid section, have storage
 857    :      // class STATIC, a non-function type (contrary to static
 858    :      // functions), and no auxiliary record (contrary to section
 859    :      // definitions). Skip the rest.
 860    :      //
 861    :      // MSVC records section descriptions in the symbol table as STATIC
 862    :      // data symbols; hence a section symbol and the first data symbol
 863    :      // at offset zero will have the same storage class and offset;
 864    :      // data symbols, however, occupy a single entry in the table,
 865    :      // whereas section symbols take two records (hence one auxiliary
 866    :      // record with class-specific data in addition of the main
 867    :      // record).
 868    :      if (!(symbol->SectionNumber > 0 &&
 869    :            symbol->StorageClass == IMAGE_SYM_CLASS_STATIC &&
 870    :            symbol->Type >> 4 != IMAGE_SYM_DTYPE_FUNCTION &&
 871  E :            symbol->NumberOfAuxSymbols == 0)) {
 872  E :        continue;
 873    :      }
 874  E :      size_t section_index = symbol->SectionNumber - 1;
 875    :  
 876    :      // Skip labels in non-code sections.
 877    :      const IMAGE_SECTION_HEADER* header =
 878  E :          image_file_.section_header(section_index);
 879  E :      DCHECK(header != NULL);
 880  E :      if (GetSectionType(*header) != kSectionCode)
 881  E :        continue;
 882    :  
 883    :      // Get block and offset.
 884  E :      SectionBlockMap::iterator it = section_block_map_.find(section_index);
 885  E :      DCHECK(it != section_block_map_.end());
 886  E :      Block* block = it->second;
 887  E :      DCHECK(block != NULL);
 888  E :      BlockGraph::Offset offset = symbol->Value;
 889    :  
 890    :      // Tables only appear in code blocks; ignore others.
 891  E :      if (block->type() != BlockGraph::CODE_BLOCK)
 892  i :        continue;
 893    :  
 894    :      // Compute label attributes. Jump tables are always an array of
 895    :      // pointers, thus they coincide exactly with a reference. Case
 896    :      // tables are simple arrays of integer values, thus do not
 897    :      // coincide with a reference.
 898  E :      BlockGraph::LabelAttributes attrs = BlockGraph::DATA_LABEL;
 899  E :      if (block->references().find(offset) != block->references().end()) {
 900  E :        attrs |= BlockGraph::JUMP_TABLE_LABEL;
 901  E :      } else {
 902  E :        attrs |= BlockGraph::CASE_TABLE_LABEL;
 903    :      }
 904    :  
 905    :      // Add label.
 906  E :      const char* name = image_file_.GetSymbolName(i);
 907  E :      if (!AddLabelToBlock(offset, name, attrs, block))
 908  i :        return false;
 909  E :    }
 910  E :    return true;
 911  E :  }
 912    :  
 913    :  Block* CoffDecomposer::CreateBlock(BlockType type,
 914    :                                     FileOffsetAddress addr,
 915    :                                     BlockGraph::Size size,
 916  E :                                     const base::StringPiece& name) {
 917  E :    DCHECK(image_ != NULL);
 918    :  
 919  E :    if (addr == FileOffsetAddress::kInvalidAddress) {
 920    :      // Unmapped block.
 921  E :      Block* block = image_->graph()->AddBlock(type, size, name);
 922  E :      if (block == NULL) {
 923  i :        LOG(ERROR) << "Unable to add unmapped block \"" << name.as_string()
 924    :                   << "\" with size " << size << ".";
 925  i :        return NULL;
 926    :      }
 927  E :      return block;
 928    :    }
 929    :  
 930    :    // Otherwise, we have a normal mapped block.
 931  E :    BlockGraphAddress block_addr(FileOffsetToBlockGraphAddress(addr));
 932  E :    Block* block = image_->AddBlock(type, block_addr, size, name);
 933  E :    if (block == NULL) {
 934  i :      LOG(ERROR) << "Unable to add block \"" << name.as_string() << "\" at "
 935    :                 << block_addr << " with size " << size << ".";
 936  i :      return NULL;
 937    :    }
 938    :  
 939    :    // Mark the source range from whence this block originates.
 940  E :    if (size > 0) {
 941    :      bool pushed = block->source_ranges().Push(
 942    :          Block::DataRange(0, size),
 943  E :          Block::SourceRange(block_addr, size));
 944  E :      DCHECK(pushed);
 945    :    }
 946    :  
 947  E :    const uint8* data = image_file_.GetImageData(addr, size);
 948  E :    if (data != NULL)
 949  E :      block->SetData(data, size);
 950    :  
 951  E :    return block;
 952  E :  }
 953    :  
 954    :  bool CoffDecomposer::CreateReference(FileOffsetAddress src_addr,
 955    :                                       ReferenceType ref_type,
 956    :                                       BlockGraph::Size ref_size,
 957    :                                       Block* target,
 958  E :                                       BlockGraph::Offset offset) {
 959  E :    DCHECK(image_ != NULL);
 960    :  
 961    :    // Get source block and offset.
 962  E :    Block* source = NULL;
 963  E :    BlockGraph::Offset src_offset = -1;
 964  E :    if (!FileOffsetToBlockOffset(src_addr, &source, &src_offset))
 965  i :      return false;
 966  E :    DCHECK(source != NULL);
 967  E :    DCHECK_GE(src_offset, 0);
 968    :  
 969    :    // Read additional offset for relocations.
 970  E :    BlockGraph::Offset extra_offset = 0;
 971  E :    if ((ref_type & BlockGraph::RELOC_REF_BIT) != 0) {
 972  E :      switch (ref_size) {
 973    :        case sizeof(uint32):
 974  E :          if (!ReadRelocationValue<uint32>(source, src_offset, &extra_offset))
 975  i :            return false;
 976  E :          break;
 977    :        case sizeof(uint16):
 978  E :          if (!ReadRelocationValue<uint16>(source, src_offset, &extra_offset))
 979  i :            return false;
 980  E :          break;
 981    :        case sizeof(uint8):
 982    :          // TODO(chrisha): This is really a special 7-bit relocation; we do
 983    :          // not touch these, for now.
 984  i :          break;
 985    :        default:
 986  i :          LOG(ERROR) << "Unsupported relocation value size (" << ref_size << ").";
 987  i :          return false;
 988    :      }
 989    :    }
 990    :  
 991    :    // Find an existing reference, or insert a new one.
 992  E :    Reference ref(ref_type, ref_size, target, offset + extra_offset, offset);
 993    :    Block::ReferenceMap::const_iterator ref_it =
 994  E :        source->references().find(src_offset);
 995  E :    if (ref_it == source->references().end()) {
 996    :      // New reference.
 997  E :      CHECK(source->SetReference(src_offset, ref));
 998  E :    } else {
 999    :      // Collisions are only allowed if the references are identical.
1000  i :      if (!(ref == ref_it->second)) {
1001  i :        LOG(ERROR) << "Block \"" << source->name() << "\" has a conflicting "
1002    :                   << "reference at offset " << src_offset << ".";
1003  i :        return false;
1004    :      }
1005    :    }
1006    :  
1007  E :    return true;
1008  E :  }
1009    :  
1010    :  bool CoffDecomposer::CreateFileOffsetReference(FileOffsetAddress src_addr,
1011    :                                                 ReferenceType ref_type,
1012    :                                                 BlockGraph::Size ref_size,
1013  E :                                                 FileOffsetAddress dst_addr) {
1014  E :    DCHECK(image_ != NULL);
1015    :  
1016    :    // Get target section and offset.
1017  E :    Block* target = NULL;
1018  E :    BlockGraph::Offset offset = -1;
1019  E :    if (!FileOffsetToBlockOffset(dst_addr, &target, &offset))
1020  i :      return false;
1021  E :    DCHECK(target != NULL);
1022  E :    DCHECK_GE(offset, 0);
1023    :  
1024    :    // Add reference.
1025  E :    if (!CreateReference(src_addr, ref_type, ref_size, target, offset))
1026  i :      return false;
1027    :  
1028  E :    return true;
1029  E :  }
1030    :  
1031    :  bool CoffDecomposer::CreateSectionOffsetReference(FileOffsetAddress src_addr,
1032    :                                                    ReferenceType ref_type,
1033    :                                                    BlockGraph::Size ref_size,
1034    :                                                    size_t section_index,
1035  E :                                                    size_t section_offset) {
1036  E :    DCHECK(image_ != NULL);
1037    :  
1038    :    // Get target section and offset.
1039  E :    Block* target = NULL;
1040  E :    BlockGraph::Offset offset = -1;
1041    :    if (!SectionOffsetToBlockOffset(section_index, section_offset,
1042  E :                                    &target, &offset)) {
1043  i :      return false;
1044    :    }
1045  E :    DCHECK(target != NULL);
1046  E :    DCHECK_GE(offset, 0);
1047    :  
1048    :    // Add reference.
1049  E :    if (!CreateReference(src_addr, ref_type, ref_size, target, offset))
1050  i :      return false;
1051    :  
1052  E :    return true;
1053  E :  }
1054    :  
1055    :  bool CoffDecomposer::CreateSymbolOffsetReference(FileOffsetAddress src_addr,
1056    :                                                   ReferenceType ref_type,
1057    :                                                   BlockGraph::Size ref_size,
1058    :                                                   const IMAGE_SYMBOL* symbol,
1059  E :                                                   size_t offset) {
1060  E :    DCHECK(image_ != NULL);
1061  E :    DCHECK(symbol != NULL);
1062    :  
1063  E :    if (symbol->SectionNumber < 0) {
1064  i :      LOG(ERROR) << "Symbol cannot be converted to a reference.";
1065  i :      return false;
1066    :    }
1067    :  
1068  E :    if (symbol->SectionNumber != 0) {
1069    :      // Section symbol.
1070    :      return CreateSectionOffsetReference(src_addr, ref_type, ref_size,
1071  E :                                          symbol->SectionNumber - 1, offset);
1072  i :    } else {
1073    :      // External symbol. As a convention, we use a reference to the symbol
1074    :      // table, since there is no corresponding block. The offset is ignored
1075    :      // (will be inferred from the symbol value and reference type).
1076  E :      size_t symbol_index = symbol - image_file_.symbols();
1077    :      return CreateFileOffsetReference(
1078    :          src_addr, ref_type, ref_size,
1079  E :          image_file_.symbols_address() + symbol_index * sizeof(*symbol));
1080    :    }
1081  E :  }
1082    :  
1083    :  bool CoffDecomposer::FileOffsetToBlockOffset(FileOffsetAddress addr,
1084    :                                               Block** block,
1085  E :                                               BlockGraph::Offset* offset) {
1086  E :    DCHECK(image_ != NULL);
1087  E :    DCHECK(block != NULL);
1088  E :    DCHECK(offset != NULL);
1089    :  
1090    :    // Get block and offset.
1091  E :    BlockGraphAddress actual_addr(FileOffsetToBlockGraphAddress(addr));
1092  E :    Block* containing_block = image_->GetBlockByAddress(actual_addr);
1093  E :    if (containing_block == NULL) {
1094  i :      LOG(ERROR) << "File offset " << addr << " does not lie within a block.";
1095  i :      return false;
1096    :    }
1097  E :    BlockGraphAddress block_addr;
1098  E :    CHECK(image_->GetAddressOf(containing_block, &block_addr));
1099    :  
1100  E :    *block = containing_block;
1101  E :    *offset = actual_addr - block_addr;
1102  E :    return true;
1103  E :  }
1104    :  
1105    :  bool CoffDecomposer::SectionOffsetToBlockOffset(size_t section_index,
1106    :                                                  size_t section_offset,
1107    :                                                  Block** block,
1108  E :                                                  BlockGraph::Offset* offset) {
1109  E :    DCHECK(image_ != NULL);
1110  E :    DCHECK_NE(BlockGraph::kInvalidSectionId, section_index);
1111  E :    DCHECK_LT(section_index, image_file_.file_header()->NumberOfSections);
1112    :    DCHECK_LE(section_offset,
1113  E :              image_file_.section_header(section_index)->SizeOfRawData);
1114  E :    DCHECK(block != NULL);
1115  E :    DCHECK(offset != NULL);
1116    :  
1117    :    // Get block and offset.
1118  E :    SectionBlockMap::iterator it = section_block_map_.find(section_index);
1119  E :    if (it == section_block_map_.end()) {
1120  i :      LOG(ERROR) << "Section " << section_index << " is not mapped to a block.";
1121  i :      return false;
1122    :    }
1123  E :    DCHECK(it->second != NULL);
1124  E :    DCHECK_LE(section_offset, it->second->size());
1125    :  
1126  E :    *block = it->second;
1127  E :    *offset = section_offset;
1128  E :    return true;
1129  E :  }
1130    :  
1131    :  CoffDecomposer::BlockGraphAddress CoffDecomposer::FileOffsetToBlockGraphAddress(
1132  E :      FileOffsetAddress addr) {
1133  E :    return BlockGraphAddress(addr.value());
1134  E :  }
1135    :  
1136    :  }  // namespace pe

Coverage information generated Thu Mar 26 16:15:41 2015.