Coverage for /Syzygy/pe/pe_file_parser.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
65.6%3815810.C++source

Line-by-line coverage:

   1    :  // Copyright 2012 Google Inc.
   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/pe_file_parser.h"
  16    :  
  17    :  #include <delayimp.h>
  18    :  
  19    :  #include "base/bind.h"
  20    :  #include "base/stringprintf.h"
  21    :  #include "syzygy/common/align.h"
  22    :  
  23    :  namespace pe {
  24    :  
  25    :  namespace {
  26    :  
  27    :  using block_graph::BlockGraph;
  28    :  using core::AbsoluteAddress;
  29    :  using core::FileOffsetAddress;
  30    :  using core::RelativeAddress;
  31    :  
  32    :  const char* kDirEntryNames[] = {
  33    :      "IMAGE_DIRECTORY_ENTRY_EXPORT",
  34    :      "IMAGE_DIRECTORY_ENTRY_IMPORT",
  35    :      "IMAGE_DIRECTORY_ENTRY_RESOURCE",
  36    :      "IMAGE_DIRECTORY_ENTRY_EXCEPTION",
  37    :      "IMAGE_DIRECTORY_ENTRY_SECURITY",
  38    :      "IMAGE_DIRECTORY_ENTRY_BASERELOC",
  39    :      "IMAGE_DIRECTORY_ENTRY_DEBUG",
  40    :      "IMAGE_DIRECTORY_ENTRY_ARCHITECTURE",
  41    :      "IMAGE_DIRECTORY_ENTRY_GLOBALPTR",
  42    :      "IMAGE_DIRECTORY_ENTRY_TLS",
  43    :      "IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG",
  44    :      "IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT",
  45    :      "IMAGE_DIRECTORY_ENTRY_IAT",
  46    :      "IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT",
  47    :      "IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR",
  48    :  };
  49    :  
  50    :  // Given a table type, and whether or not it is bound, returns the type of
  51    :  // data we can expect to find in the table.
  52    :  PEFileParser::ThunkDataType GetThunkDataType(
  53  E :      PEFileParser::ThunkTableType table_type, bool is_bound) {
  54  E :    switch (table_type) {
  55    :      case PEFileParser::kImportNameTable:
  56  E :        return PEFileParser::kImageThunkData;
  57    :  
  58    :      case PEFileParser::kImportAddressTable:
  59  E :        if (is_bound)
  60  i :          return PEFileParser::kCodeOutOfImageThunkData;
  61    :        else
  62  E :          return PEFileParser::kImageThunkData;
  63    :  
  64    :      case PEFileParser::kDelayLoadImportNameTable:
  65  E :        return PEFileParser::kImageThunkData;
  66    :  
  67    :      case PEFileParser::kDelayLoadImportAddressTable:
  68  E :        return PEFileParser::kCodeInImageThunkData;
  69    :  
  70    :      case PEFileParser::kDelayLoadBoundImportAddressTable:
  71  E :        return PEFileParser::kArbitraryThunkData;
  72    :  
  73    :      default: break;
  74    :    }
  75  i :    NOTREACHED() << "Unknown ThunkDataType.";
  76  i :    return PEFileParser::kArbitraryThunkData;
  77  E :  }
  78    :  
  79    :  bool DummyOnImportThunk(const char* module_name,
  80    :                          const char* symbol_name,
  81  E :                          BlockGraph::Block* thunk) {
  82  E :    return true;
  83  E :  }
  84    :  
  85    :  }  // namespace
  86    :  
  87    :  // This class represents a generic, untyped pointer with a fixed length,
  88    :  // into a PE image at a particular address.
  89    :  class PEFilePtr {
  90    :   public:
  91  E :    PEFilePtr() : ptr_(NULL), len_(0) {
  92  E :    }
  93    :  
  94    :    // Set the pointer to the address and data in @p block.
  95  E :    bool Set(BlockGraph::Block* block) {
  96  E :      return Set(block, block->addr());
  97  E :    }
  98    :  
  99    :    // Set the pointer to the address @p addr, which must be contained
 100    :    // within @p block, and the corresponding data in @p block.
 101  E :    bool Set(BlockGraph::Block* block, RelativeAddress addr) {
 102  E :      const uint8* ptr = block->data();
 103  E :      ptrdiff_t offs = addr - block->addr();
 104  E :      if (ptr == NULL || offs < 0)
 105  i :        return false;
 106  E :      if (static_cast<size_t>(offs) >= block->data_size())
 107  i :        return false;
 108    :  
 109  E :      addr_ = addr;
 110  E :      ptr_ = ptr + offs;
 111  E :      len_ = block->data_size() - offs;
 112    :  
 113  E :      return true;
 114  E :    }
 115    :  
 116    :    // Set the pointer to the address @p addr, and length @p len,
 117    :    // iff the @p image contains that data.
 118  E :    bool Read(const PEFile& image, RelativeAddress addr, size_t len) {
 119  E :      const uint8* ptr = image.GetImageData(addr, len);
 120  E :      if (ptr == NULL)
 121  i :        return false;
 122    :  
 123    :      // Success - store the data we now point to.
 124  E :      addr_ = addr;
 125  E :      ptr_ = ptr;
 126  E :      len_ = len;
 127    :  
 128  E :      return true;
 129  E :    }
 130    :  
 131    :    // Advance the pointer by @p len bytes iff the pointer points to at
 132    :    // least @len bytes.
 133  E :    bool Advance(size_t len) {
 134    :      // Do we have enough remaining?
 135  E :      if (len_ < len)
 136  i :        return false;
 137    :  
 138    :      // Walk forward, and trim the remaining length.
 139  E :      addr_ += len;
 140  E :      ptr_ += len;
 141  E :      len_ -= len;
 142    :  
 143  E :      return true;
 144  E :    }
 145    :  
 146    :    // Accessors.
 147  E :    RelativeAddress addr() const { return addr_; }
 148    :    void set_addr(RelativeAddress addr) { addr_ = addr; }
 149    :  
 150  E :    const uint8* ptr() const { return ptr_; }
 151    :    void set_ptr(const uint8* ptr) { ptr_ = ptr; }
 152    :  
 153  E :    size_t len() const { return len_; }
 154    :    void set_len(size_t len) { len_ = len; }
 155    :  
 156    :   private:
 157    :    RelativeAddress addr_;
 158    :    const uint8* ptr_;
 159    :    size_t len_;
 160    :  };
 161    :  
 162    :  // Represents a typed pointer into a PE image at a given address.
 163    :  // The data pointed to by a struct ptr is always at least sizeof(ItemType).
 164    :  template <typename ItemType>
 165    :  class PEFileStructPtr {
 166    :   public:
 167  E :    PEFileStructPtr() {
 168  E :    }
 169    :  
 170    :    // Set this pointer to the address and data in @p block.
 171    :    // @returns true iff successful.
 172  E :    bool Set(BlockGraph::Block* block) {
 173  E :      if (block->data_size() < sizeof(ItemType))
 174  i :        return false;
 175    :  
 176  E :      return ptr_.Set(block);
 177  E :    }
 178    :  
 179    :    // Set this pointer to addr, which must be contained within @p block,
 180    :    // and the corresponding data in @p block.
 181    :    // @returns true iff successful.
 182  E :    bool Set(BlockGraph::Block* block, RelativeAddress addr) {
 183  E :      if (block->data_size() < sizeof(ItemType))
 184  i :        return false;
 185    :  
 186  E :      return ptr_.Set(block, addr);
 187  E :    }
 188    :  
 189    :    // Read data from @p image at @p addr.
 190  E :    bool Read(const PEFile& image, RelativeAddress addr) {
 191  E :      return Read(image, addr, sizeof(ItemType));
 192  E :    }
 193    :  
 194    :    // Read @p len data bytes from @p image at @p addr.
 195    :    // @note @p len must be greater or equal to sizeof(ItemType).
 196  E :    bool Read(const PEFile& image, RelativeAddress addr, size_t len) {
 197  E :      DCHECK(len >= sizeof(ItemType));
 198  E :      return ptr_.Read(image, addr, len);
 199  E :    }
 200    :  
 201    :    // @returns true iff this pointer is valid.
 202  E :    bool IsValid() const {
 203  E :      return ptr_.ptr() != NULL && ptr_.len() >= sizeof(ItemType);
 204  E :    }
 205    :  
 206    :    // Advance our pointer by sizeof(ItemType) iff this would leave
 207    :    // this pointer valid.
 208  E :    bool Next() {
 209  E :      DCHECK(IsValid());
 210    :  
 211    :      // See whether there's enough room left for another full item.
 212  E :      size_t new_len = ptr_.len() - sizeof(ItemType);
 213  E :      if (new_len < sizeof(ItemType))
 214  E :        return false;
 215    :  
 216    :      // Walk forward one item. We've already checked that there's
 217    :      // sufficient data left, so this must succeed.
 218  E :      bool ret = ptr_.Advance(sizeof(ItemType));
 219  E :      DCHECK(ret && IsValid());
 220    :  
 221  E :      return true;
 222  E :    }
 223    :  
 224  E :    RelativeAddress addr() const { return ptr_.addr(); }
 225    :    void set_addr(RelativeAddress addr) { ptr.set_addr(addr); }
 226    :  
 227  E :    const ItemType* ptr() const {
 228  E :      return reinterpret_cast<const ItemType*>(ptr_.ptr());
 229  E :    }
 230    :  
 231  E :    const ItemType* operator->() const {
 232  E :      return ptr();
 233  E :    }
 234    :  
 235    :    // Returns the image address of the data at ptr.
 236    :    // @note ptr must be within the data we point to.
 237  E :    RelativeAddress AddressOf(const void* ptr) const {
 238  E :      DCHECK(IsValid());
 239    :  
 240  E :      const uint8* tmp = reinterpret_cast<const uint8*>(ptr);
 241  E :      DCHECK(tmp >= ptr_.ptr());
 242  E :      ptrdiff_t offs = tmp - ptr_.ptr();
 243  E :      DCHECK(offs >= 0 && static_cast<size_t>(offs) < ptr_.len());
 244    :  
 245  E :      return ptr_.addr() + offs;
 246  E :    }
 247    :  
 248    :    size_t len() const { return ptr_.len(); }
 249    :  
 250    :   private:
 251    :    PEFilePtr ptr_;
 252    :  
 253    :    DISALLOW_COPY_AND_ASSIGN(PEFileStructPtr);
 254    :  };
 255    :  
 256    :  PEFileParser::PEFileParser(const PEFile& image_file,
 257    :                             BlockGraph::AddressSpace* address_space,
 258    :                             const AddReferenceCallback& add_reference)
 259    :      : image_file_(image_file),
 260    :        address_space_(address_space),
 261    :        add_reference_(add_reference),
 262  E :        on_import_thunk_(base::Bind(&DummyOnImportThunk)) {
 263  E :    DCHECK(!add_reference.is_null());
 264  E :  }
 265    :  
 266    :  const PEFileParser::DataDirParseEntry PEFileParser::parsers_[] = {
 267    :    {
 268    :      IMAGE_DIRECTORY_ENTRY_EXPORT,
 269    :      "export",
 270    :      &PEFileParser::ParseExportDir
 271    :    }, {
 272    :      // We parse the IAT ahead of the imports because if the IAT entry is
 273    :      // present, we want it chunked and ready to reference before we start
 274    :      // parsing imports.
 275    :      IMAGE_DIRECTORY_ENTRY_IAT,
 276    :      "iat",
 277    :      &PEFileParser::ParseIatDir
 278    :    }, {
 279    :      IMAGE_DIRECTORY_ENTRY_IMPORT,
 280    :      "import",
 281    :      &PEFileParser::ParseImportDir
 282    :    }, {
 283    :      IMAGE_DIRECTORY_ENTRY_RESOURCE,
 284    :      "resource",
 285    :      &PEFileParser::ParseResourceDir
 286    :    }, {
 287    :      IMAGE_DIRECTORY_ENTRY_EXCEPTION,
 288    :      "exception",
 289    :      &PEFileParser::ParseExceptionDir
 290    :    }, {
 291    :      IMAGE_DIRECTORY_ENTRY_SECURITY,
 292    :      "security",
 293    :      &PEFileParser::ParseSecurityDir
 294    :    }, {
 295    :      IMAGE_DIRECTORY_ENTRY_BASERELOC,
 296    :      "relocs",
 297    :      &PEFileParser::ParseRelocDir
 298    :    }, {
 299    :      IMAGE_DIRECTORY_ENTRY_DEBUG,
 300    :      "debug",
 301    :      &PEFileParser::ParseDebugDir
 302    :    }, {
 303    :      IMAGE_DIRECTORY_ENTRY_ARCHITECTURE,
 304    :      "architecture",
 305    :      &PEFileParser::ParseArchitectureDir
 306    :    }, {
 307    :      IMAGE_DIRECTORY_ENTRY_GLOBALPTR,
 308    :      "global",
 309    :      &PEFileParser::ParseGlobalDir
 310    :    }, {
 311    :      IMAGE_DIRECTORY_ENTRY_TLS,
 312    :      "tls",
 313    :      &PEFileParser::ParseTlsDir
 314    :    }, {
 315    :      IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG,
 316    :      "load config",
 317    :      &PEFileParser::ParseLoadConfigDir
 318    :    }, {
 319    :      IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT,
 320    :      "bound import",
 321    :      &PEFileParser::ParseBoundImportDir
 322    :    }, {
 323    :      IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT,
 324    :      "delay import",
 325    :      &PEFileParser::ParseDelayImportDir
 326    :    }, {
 327    :      IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR,
 328    :      "com descriptor",
 329    :      &PEFileParser::ParseComDescriptorDir
 330    :    },
 331    :  };
 332    :  
 333  E :  bool PEFileParser::ParseImage(PEHeader* pe_header) {
 334  E :    if (!ParseImageHeader(pe_header)) {
 335  i :      LOG(ERROR) << "Unable to parse image header.";
 336  i :      return false;
 337    :    }
 338    :  
 339  E :    for (size_t i = 0; i < arraysize(parsers_); ++i) {
 340  E :      const DataDirParseEntry& parser = parsers_[i];
 341  E :      DCHECK(parser.entry < IMAGE_NUMBEROF_DIRECTORY_ENTRIES);
 342  E :      DCHECK(parser.parser != NULL);
 343  E :      DCHECK(parser.name != NULL);
 344    :  
 345    :      const IMAGE_DATA_DIRECTORY& entry =
 346  E :          image_file_.nt_headers()->OptionalHeader.DataDirectory[parser.entry];
 347    :  
 348  E :      if (entry.Size != 0) {
 349  E :        DCHECK(entry.VirtualAddress != 0);
 350  E :        BlockGraph::Block* block = (this->*parser.parser)(entry);
 351  E :        if (block == NULL) {
 352  i :          LOG(ERROR) << "Failed to parse data directory " << parser.name << ".";
 353  i :          return false;
 354    :        }
 355    :  
 356  E :        pe_header->data_directory[parser.entry] = block;
 357    :      }
 358  E :    }
 359    :  
 360  E :    return true;
 361  E :  }
 362    :  
 363  E :  bool PEFileParser::ParseImageHeader(PEHeader* header) {
 364    :    // Get the start of the image headers.
 365    :    size_t dos_header_size =
 366    :        reinterpret_cast<const uint8*>(image_file_.nt_headers()) -
 367  E :        reinterpret_cast<const uint8*>(image_file_.dos_header());
 368    :  
 369  E :    if (dos_header_size < sizeof(IMAGE_DOS_HEADER)) {
 370  i :      LOG(ERROR) << "Impossibly small DOS header.";
 371  i :      return false;
 372    :    }
 373    :  
 374  E :    PEFileStructPtr<IMAGE_DOS_HEADER> dos_header_ptr;
 375  E :    if (!dos_header_ptr.Read(image_file_, RelativeAddress(0), dos_header_size)) {
 376  i :      LOG(ERROR) << "No DOS header in image.";
 377  i :      return false;
 378    :    }
 379    :  
 380    :    // The length of the DOS header is the address of the NT headers.
 381  E :    RelativeAddress nt_headers_address(dos_header_size);
 382  E :    DCHECK(nt_headers_address.value() > sizeof(IMAGE_DOS_HEADER));
 383    :  
 384    :    // Chunk out the DOS header and stub.
 385    :    BlockGraph::Block* dos_header = AddBlock(BlockGraph::DATA_BLOCK,
 386    :                                             RelativeAddress(0),
 387    :                                             nt_headers_address.value(),
 388  E :                                             "DOS Header");
 389  E :    if (dos_header == NULL) {
 390  i :      LOG(ERROR) << "Unable to add DOS header block.";
 391  i :      return false;
 392    :    }
 393    :  
 394    :    // Add the reference to the PE header. This reference can be interpreted
 395    :    // either as a disk or a relative reference, as disk and relative addresses
 396    :    // coincide in the image header.
 397    :    COMPILE_ASSERT(sizeof(DWORD) == sizeof(dos_header_ptr->e_lfanew),
 398    :                   dos_header_e_lfanew_is_wrong_size);
 399    :    if (!AddRelative(dos_header_ptr,
 400  E :                     reinterpret_cast<const DWORD*>(&dos_header_ptr->e_lfanew))) {
 401  i :      LOG(ERROR) << "Unable to add DOS to NT headers reference.";
 402  i :      return false;
 403    :    }
 404    :  
 405  E :    PEFileStructPtr<IMAGE_NT_HEADERS> nt_headers_ptr;
 406  E :    if (!nt_headers_ptr.Read(image_file_, nt_headers_address)) {
 407  i :      LOG(ERROR) << "Unable to read NT headers.";
 408  i :      return false;
 409    :    }
 410    :  
 411  E :    for (size_t i = 0; i < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; ++i) {
 412    :      if (!AddRelative(nt_headers_ptr,
 413  E :              &nt_headers_ptr->OptionalHeader.DataDirectory[i].VirtualAddress)) {
 414  i :        LOG(ERROR) << "Unable to add data directory reference for "
 415    :                   << kDirEntryNames[i];
 416  i :        return false;
 417    :      }
 418  E :    }
 419    :  
 420    :    // Calculate the size of the NT headers and section headers.
 421    :    size_t nt_headers_size = sizeof(IMAGE_NT_HEADERS) +
 422    :        nt_headers_ptr->FileHeader.NumberOfSections *
 423  E :            sizeof(IMAGE_SECTION_HEADER);
 424    :    // Chunk the NT & section headers.
 425    :    BlockGraph::Block* nt_headers = AddBlock(BlockGraph::DATA_BLOCK,
 426    :                                             nt_headers_address,
 427    :                                             nt_headers_size,
 428  E :                                             "NT Headers");
 429  E :    if (nt_headers == NULL) {
 430  i :      LOG(ERROR) << "Unable to add NT Headers block.";
 431  i :      return false;
 432    :    }
 433    :  
 434    :    if (!AddRelative(nt_headers_ptr,
 435  E :                     &nt_headers_ptr->OptionalHeader.AddressOfEntryPoint)) {
 436  i :      LOG(ERROR) << "Unable to add entry point reference.";
 437  i :      return false;
 438    :    }
 439    :  
 440  E :    if (header != NULL) {
 441  E :      header->dos_header = dos_header;
 442  E :      header->nt_headers = nt_headers;
 443    :    }
 444    :  
 445  E :    return true;
 446  E :  }
 447    :  
 448    :  BlockGraph::Block* PEFileParser::ParseExportDir(
 449  E :      const IMAGE_DATA_DIRECTORY& dir) {
 450    :    BlockGraph::Block* export_dir_block =
 451    :        AddBlock(BlockGraph::DATA_BLOCK,
 452    :                 RelativeAddress(dir.VirtualAddress),
 453    :                 dir.Size,
 454  E :                 "Export Directory");
 455  E :    if (export_dir_block == NULL) {
 456  i :      LOG(ERROR) << "Failed to create export directory block.";
 457  i :      return NULL;
 458    :    }
 459    :  
 460  E :    PEFileStructPtr<IMAGE_EXPORT_DIRECTORY> export_dir;
 461  E :    if (!export_dir.Set(export_dir_block)) {
 462  i :      LOG(ERROR) << "Unable to read export directory.";
 463  i :      return NULL;
 464    :    }
 465    :  
 466    :    // All the references in the export directory should point back into
 467    :    // the export directory, sanity check this.
 468    :    DCHECK_EQ(export_dir_block, address_space_->GetContainingBlock(
 469    :        RelativeAddress(export_dir->AddressOfFunctions),
 470  E :        sizeof(RelativeAddress)));
 471    :    DCHECK_EQ(export_dir_block, address_space_->GetContainingBlock(
 472    :        RelativeAddress(export_dir->AddressOfNames),
 473  E :        sizeof(RelativeAddress)));
 474    :    DCHECK_EQ(export_dir_block, address_space_->GetContainingBlock(
 475    :        RelativeAddress(export_dir->AddressOfNameOrdinals),
 476  E :        sizeof(RelativeAddress)));
 477    :  
 478    :    // Add the export directory references.
 479  E :    if (!AddRelative(export_dir, &export_dir->Name)) {
 480  i :      LOG(ERROR) << "Unable to add export functions reference.";
 481  i :      return NULL;
 482    :    }
 483    :  
 484  E :    if (!AddRelative(export_dir, &export_dir->AddressOfFunctions)) {
 485  i :      LOG(ERROR) << "Unable to add export functions reference.";
 486  i :      return NULL;
 487    :    }
 488    :  
 489  E :    if (!AddRelative(export_dir, &export_dir->AddressOfNames)) {
 490  i :      LOG(ERROR) << "Unable to add export address of names reference.";
 491  i :      return NULL;
 492    :    }
 493    :  
 494  E :    if (!AddRelative(export_dir, &export_dir->AddressOfNameOrdinals)) {
 495  i :      LOG(ERROR) << "Unable to add export address of ordinals reference.";
 496  i :      return NULL;
 497    :    }
 498    :  
 499  E :    PEFileStructPtr<DWORD> function;
 500    :    if (!function.Set(export_dir_block,
 501  E :                      RelativeAddress(export_dir->AddressOfFunctions))) {
 502  i :      LOG(ERROR) << "Unable to parse export function table.";
 503  i :      return NULL;
 504    :    }
 505    :  
 506  E :    for (size_t i = 0; i < export_dir->NumberOfFunctions; ++i) {
 507    :      // TODO(siggi): This could be labeled with the exported function's
 508    :      //    name, if one is available.
 509  E :      if (!AddRelative(function, function.ptr())) {
 510  i :        LOG(ERROR) << "Unable to add reference to exported function.";
 511  i :        return NULL;
 512    :      }
 513    :  
 514  E :      if (!function.Next()) {
 515  i :        LOG(ERROR) << "Unable to parse export function table.";
 516  i :        return NULL;
 517    :      }
 518  E :    }
 519    :  
 520    :    // Add references to the export function names.
 521  E :    PEFileStructPtr<DWORD> name;
 522    :    if (!name.Set(export_dir_block,
 523  E :                  RelativeAddress(export_dir->AddressOfNames))) {
 524  i :      LOG(ERROR) << "Unable to parse export name table.";
 525    :    }
 526    :  
 527  E :    for (size_t i = 0; i < export_dir->NumberOfNames; ++i) {
 528    :      // All the names in the export directory should point back into
 529    :      // the export directory, sanity check this.
 530    :      DCHECK_EQ(export_dir_block, address_space_->GetContainingBlock(
 531    :          RelativeAddress(*name.ptr()),
 532  E :          sizeof(RelativeAddress)));
 533    :  
 534  E :      if (!AddRelative(name, name.ptr())) {
 535  i :        LOG(ERROR) << "Unable to add reference to export function name.";
 536  i :        return NULL;
 537    :      }
 538    :  
 539  E :      if (!name.Next()) {
 540  i :        LOG(ERROR) << "Unable to parse export function table.";
 541  i :        return NULL;
 542    :      }
 543  E :    }
 544    :  
 545  E :    return export_dir_block;
 546  E :  }
 547    :  
 548  E :  size_t PEFileParser::CountImportThunks(RelativeAddress thunk_start) {
 549  E :    size_t num_thunks = 0;
 550  E :    for (; true; ++num_thunks, thunk_start += sizeof(IMAGE_THUNK_DATA)) {
 551  E :      PEFileStructPtr<IMAGE_THUNK_DATA> thunk;
 552  E :      if (!thunk.Read(image_file_, thunk_start)) {
 553    :        // We didn't get to the sentinel, that's an error.
 554  i :        LOG(ERROR) << "Unable to read image import thunk.";
 555  i :        return 0;
 556    :      }
 557    :  
 558  E :      if (thunk->u1.AddressOfData == 0U)
 559  E :        break;
 560  E :    }
 561    :  
 562  E :    return num_thunks;
 563  E :  }
 564    :  
 565    :  bool PEFileParser::ParseImportThunks(RelativeAddress thunk_start,
 566    :                                       size_t num_thunks,
 567    :                                       bool is_bound,
 568    :                                       ThunkTableType table_type,
 569    :                                       const char* thunk_type,
 570  E :                                       const char* import_name) {
 571    :    // Only certain table types may be bound.
 572    :    DCHECK(!is_bound || table_type == kImportAddressTable ||
 573  E :               table_type == kDelayLoadBoundImportAddressTable);
 574    :  
 575    :    // Start by chunking the IAT/INT, including the terminating sentinel.
 576  E :    size_t ixt_size = sizeof(IMAGE_THUNK_DATA) * (num_thunks + 1);
 577    :  
 578    :    std::string ixt_name =
 579  E :        base::StringPrintf("%s for \"%s\"", thunk_type, import_name);
 580    :  
 581  E :    BlockGraph::Block* thunk_block = NULL;
 582  E :    if (table_type == kDelayLoadBoundImportAddressTable) {
 583    :      thunk_block = ChunkDelayBoundIATBlock(thunk_start, ixt_size,
 584  E :                                            ixt_name.c_str());
 585  E :    } else {
 586    :      // Try to add the block.
 587    :      thunk_block = AddBlock(BlockGraph::DATA_BLOCK,
 588    :                             thunk_start,
 589    :                             ixt_size,
 590  E :                             ixt_name.c_str());
 591    :  
 592    :      // The IAT may have been chunked while parsing the IAT data directory,
 593    :      // in which case we want to leave a label for the start of our entries. In
 594    :      // this case we should be wholly contained in an existing block.
 595  E :      if (thunk_block == NULL) {
 596    :        thunk_block = address_space_->GetContainingBlock(thunk_start,
 597  E :                                                         ixt_size);
 598    :      }
 599    :    }
 600    :  
 601  E :    if (thunk_block == NULL) {
 602  i :      LOG(ERROR) << "Unable to add " << thunk_type
 603    :                 << "block for " << import_name;
 604  i :      return false;
 605    :    }
 606    :  
 607    :    // Add a label to the start of the table.
 608    :    thunk_block->SetLabel(thunk_start - thunk_block->addr(),
 609    :                          ixt_name,
 610  E :                          BlockGraph::DATA_LABEL);
 611    :  
 612    :    // Determine the type of data in the table. We only chunk out names for
 613    :    // import name tables. This prevents us from doing the work twice for an
 614    :    // unbound IAT.
 615  E :    ThunkDataType thunk_data_type = GetThunkDataType(table_type, is_bound);
 616    :    bool chunk_names = table_type == kImportNameTable ||
 617  E :        table_type == kDelayLoadImportNameTable;
 618    :  
 619    :    // Run through and validate the table contents, parsing IMAGE_IMPORT_BY_NAMES
 620    :    // if we're in an import name table.
 621  E :    for (size_t i = 0; i < num_thunks; ++i) {
 622    :      if (!ParseImportThunk(thunk_start, thunk_data_type, thunk_type,
 623  E :                            import_name, chunk_names)) {
 624  i :        return false;
 625    :      }
 626  E :      thunk_start += sizeof(IMAGE_THUNK_DATA);
 627  E :    }
 628    :  
 629  E :    return true;
 630  E :  }
 631    :  
 632    :  bool PEFileParser::ParseImportThunk(RelativeAddress thunk_addr,
 633    :                                      ThunkDataType thunk_data_type,
 634    :                                      const char* thunk_type,
 635    :                                      const char* module_name,
 636  E :                                      bool chunk_name) {
 637    :    // We can only chunk names if we're parsing an IMAGE_THUNK_DATA object.
 638  E :    DCHECK(!chunk_name || thunk_data_type == kImageThunkData);
 639    :  
 640  E :    PEFileStructPtr<IMAGE_THUNK_DATA> thunk;
 641  E :    if (!thunk.Read(image_file_, thunk_addr)) {
 642  i :      LOG(ERROR) << "Unable to read image import thunk.";
 643  i :      return false;
 644    :    }
 645    :  
 646  E :    switch (thunk_data_type) {
 647    :      case kNullThunkData: {
 648  i :        if (thunk->u1.AddressOfData != 0) {
 649  i :          LOG(ERROR) << "Expect NULL " << thunk_type << " thunk, got 0x"
 650    :                     << std::hex << thunk->u1.AddressOfData;
 651  i :          return false;
 652    :        }
 653  i :        break;
 654    :      }
 655    :  
 656    :      case kImageThunkData: {
 657    :        // If it's an ordinal, there's nothing to do.
 658  E :        if (IMAGE_SNAP_BY_ORDINAL(thunk->u1.Ordinal))
 659  E :          break;
 660    :  
 661    :        // It's not an ordinal, so it must contain an RVA to an
 662    :        // IMAGE_IMPORT_BY_NAME.
 663    :  
 664    :        // Add the IAT/INT->thunk reference.
 665  E :        if (!AddRelative(thunk, &thunk->u1.AddressOfData)) {
 666  i :          LOG(ERROR) << "Unable to add import thunk reference.";
 667  i :          return false;
 668    :        }
 669    :  
 670    :        // Read the thunk and name & chunk it out.
 671  E :        PEFileStructPtr<IMAGE_IMPORT_BY_NAME> name_thunk;
 672  E :        RelativeAddress name_thunk_addr(thunk->u1.AddressOfData);
 673  E :        if (!name_thunk.Read(image_file_, name_thunk_addr)) {
 674  i :          LOG(ERROR) << "Unable to read import name thunk.";
 675  i :          return false;
 676    :        }
 677    :  
 678  E :        std::string function_name;
 679    :        RelativeAddress function_name_addr(
 680  E :            name_thunk.AddressOf(&name_thunk->Name));
 681  E :        if (!image_file_.ReadImageString(function_name_addr, &function_name)) {
 682  i :          LOG(ERROR) << "Unable to read import function name.";
 683  i :          return false;
 684    :        }
 685    :  
 686    :        // Calculate the even-padded size of the name thunk.
 687    :        size_t name_thunk_size = common::AlignUp(
 688  E :            offsetof(IMAGE_IMPORT_BY_NAME, Name) + function_name.size() + 1, 2);
 689    :  
 690    :        // Chunk the names only on request, as more than one IAT/INT may
 691    :        // point to the same name blocks.
 692  E :        if (chunk_name) {
 693    :          BlockGraph::Block* thunk = AddBlock(
 694    :              BlockGraph::DATA_BLOCK,
 695    :              name_thunk_addr,
 696    :              name_thunk_size,
 697    :              base::StringPrintf("Import Name Thunk \"%s\" from \"%s\"",
 698    :                                 function_name.c_str(),
 699  E :                                 module_name).c_str());
 700  E :          if (thunk == NULL) {
 701  i :            LOG(ERROR) << "Unable to add function name block.";
 702  i :            return false;
 703    :          }
 704    :  
 705  E :          if (!on_import_thunk_.Run(module_name, function_name.c_str(), thunk)) {
 706  i :            LOG(ERROR) << "OnImportThunk callback failed.";
 707  i :            return false;
 708    :          }
 709  E :        } else {
 710    :  #ifndef NDEBUG
 711    :          // Check that the name blocks exist in debug.
 712    :          BlockGraph::Block* block =
 713  E :              address_space_->GetBlockByAddress(name_thunk_addr);
 714  E :          DCHECK(block != NULL);
 715  E :          DCHECK_EQ(name_thunk_size, block->size());
 716    :  #endif  // NDEBUG
 717    :        }
 718  E :        break;
 719    :      }
 720    :  
 721    :      case kCodeInImageThunkData: {
 722    :        // Add the code reference. This will check that it is in fact a reference
 723    :        // to an address in the image, and track the associated block
 724    :        // automatically.
 725  E :        if (!AddAbsolute(thunk, &thunk->u1.AddressOfData)) {
 726  i :          LOG(ERROR) << "Unable to add import thunk reference.";
 727  i :          return false;
 728    :        }
 729  E :        break;
 730    :      }
 731    :  
 732    :      case kCodeOutOfImageThunkData: {
 733    :        // This is an absolute address to code outside of the image. It may
 734    :        // actually have an address that lies inside our image because the
 735    :        // imported module may have an overlapping preferred load address.
 736  i :        if (thunk->u1.AddressOfData < 0x1000) {
 737  i :          AbsoluteAddress abs_addr(thunk->u1.AddressOfData);
 738  i :          LOG(ERROR) << thunk_type << " thunk to external code has invalid "
 739    :                     << "address: " << abs_addr;
 740  i :          return false;
 741    :        }
 742    :        break;
 743    :      }
 744    :  
 745    :      case kArbitraryThunkData: {
 746    :        // We do nothing. Anything goes!
 747    :        break;
 748    :      }
 749    :    }
 750    :  
 751  E :    return true;
 752  E :  }
 753    :  
 754    :  BlockGraph::Block* PEFileParser::ChunkDelayBoundIATBlock(
 755  E :      RelativeAddress iat_addr, size_t iat_size, const char* iat_name) {
 756    :    BlockGraph::Block* iat_block = AddBlock(BlockGraph::DATA_BLOCK,
 757    :                                            iat_addr,
 758    :                                            iat_size,
 759  E :                                            iat_name);
 760  E :    if (iat_block != NULL)
 761  E :      return iat_block;
 762    :  
 763    :    // If we get here we were unable to create a block, so there must be a
 764    :    // conflict. We've seen the bound IATs for delay-loaded libraries be too
 765    :    // small. That is, one library's bound IAT is overwritten by another library's
 766    :    // bound IAT. We do our best to patch things up, by growing the conflicting
 767    :    // pre-existing block to also cover the range of the block we want to create.
 768    :    //
 769    :    // We extend the existing block by creating new blocks (one to the left, one
 770    :    // to the right) of the conflicting block that cover the portion of the new
 771    :    // table that is not covered. Then, we merge them all.
 772    :  
 773    :    iat_block = address_space_->GetFirstIntersectingBlock(iat_addr,
 774  i :                                                          iat_size);
 775  i :    VLOG(1) << iat_name << " collides with existing block " << iat_block->name()
 776    :            << ".";
 777    :  
 778    :    // If we're completely contained within the conflicting block, there's no
 779    :    // expanding and merging to do.
 780  i :    if (iat_block->Contains(iat_addr, iat_size))
 781  i :      return iat_block;
 782    :  
 783    :    // Create a block to the left of the existing block, if the desired table
 784    :    // extends to the left.
 785  i :    if (iat_addr < iat_block->addr()) {
 786  i :      size_t pre_size = iat_block->addr() - iat_addr;
 787    :      BlockGraph::Block* pre_block = AddBlock(BlockGraph::DATA_BLOCK,
 788    :                                              iat_addr,
 789    :                                              pre_size,
 790  i :                                              iat_name);
 791    :      // This should never fail as iat_block is the *first* intersecting
 792    :      // block.
 793  i :      DCHECK(pre_block != NULL);
 794    :    }
 795    :  
 796    :    // Insert the missing part of this table to the right of the intersecting
 797    :    // block, if there is any needed.
 798  i :    RelativeAddress new_end = iat_addr + iat_size;
 799  i :    RelativeAddress old_end = iat_block->addr() + iat_block->size();
 800  i :    if (new_end > old_end) {
 801    :      BlockGraph::Block* next_block =
 802    :          address_space_->GetFirstIntersectingBlock(
 803  i :              old_end, new_end - old_end);
 804    :  
 805  i :      if (next_block != NULL)
 806  i :        new_end = next_block->addr();
 807    :  
 808  i :      if (new_end > old_end) {
 809    :        BlockGraph::Block* post_block = AddBlock(BlockGraph::DATA_BLOCK,
 810    :                                                 old_end,
 811    :                                                 new_end - old_end,
 812  i :                                                 NULL);
 813    :        // This should never fail as we're inserting after the end of
 814    :        // iat_block, and before the start of the next block in the
 815    :        // address space.
 816  i :        DCHECK(post_block != NULL);
 817    :      }
 818    :    }
 819    :  
 820    :    // Merge the blocks to create one new contiguous block.
 821  i :    BlockGraph::AddressSpace::Range range(iat_addr, iat_size);
 822  i :    if (!address_space_->MergeIntersectingBlocks(range)) {
 823  i :      LOG(ERROR) << "Unable to merge intersecting bound IAT blocks.";
 824  i :      return false;
 825    :    }
 826  i :    iat_block = address_space_->GetContainingBlock(iat_addr, iat_size);
 827  i :    DCHECK(iat_block != NULL);
 828    :  
 829  i :    return iat_block;
 830  E :  }
 831    :  
 832    :  BlockGraph::Block* PEFileParser::ParseImportDir(
 833  E :      const IMAGE_DATA_DIRECTORY& dir) {
 834    :    // Read the import descriptor, we're going to iterate it.
 835  E :    RelativeAddress import_descriptor_addr(dir.VirtualAddress);
 836  E :    PEFileStructPtr<IMAGE_IMPORT_DESCRIPTOR> import_descriptor;
 837    :    if (!import_descriptor.Read(image_file_,
 838    :                                import_descriptor_addr,
 839  E :                                dir.Size)) {
 840  i :      LOG(ERROR) << "Unable to read the import directory.";
 841  i :      return NULL;
 842    :    }
 843    :  
 844    :    do {
 845    :      // The last import descriptor is a sentinel.
 846  E :      if (import_descriptor->Characteristics == 0) {
 847  E :        DCHECK_EQ(0U, import_descriptor->Name);
 848  E :        DCHECK_EQ(0U, import_descriptor->FirstThunk);
 849  E :        break;
 850    :      }
 851    :  
 852    :      // Read the name of the imported DLL.
 853  E :      std::string import_name;
 854  E :      RelativeAddress import_name_addr(import_descriptor->Name);
 855  E :      if (!image_file_.ReadImageString(import_name_addr, &import_name)) {
 856  i :        LOG(ERROR) << "Unable to read import name.";
 857  i :        return NULL;
 858    :      }
 859    :  
 860    :      if (!AddBlock(BlockGraph::DATA_BLOCK,
 861    :                    import_name_addr,
 862    :                    common::AlignUp(import_name.size() + 1, 2),
 863    :                    base::StringPrintf("Import DLL Name \"%s\"",
 864  E :                                       import_name.c_str()).c_str())) {
 865  i :        LOG(ERROR) << "Unable to create import name block.";
 866  i :        return NULL;
 867    :      }
 868    :  
 869  E :      if (!AddRelative(import_descriptor, &import_descriptor->Name)) {
 870  i :        LOG(ERROR) << "Unable to add import name reference.";
 871  i :        return NULL;
 872    :      }
 873    :  
 874    :      // Count the number of import name thunks for this import descriptor.
 875    :      RelativeAddress thunk_addr =
 876  E :          RelativeAddress(import_descriptor->OriginalFirstThunk);
 877  E :      size_t num_thunks = CountImportThunks(thunk_addr);
 878  E :      if (num_thunks == 0)
 879  i :        return false;
 880    :  
 881    :      // Parse the Import Name Table.
 882    :      if (!ParseImportThunks(thunk_addr, num_thunks, false,
 883  E :                             kImportNameTable, "INT", import_name.c_str())) {
 884  i :        return NULL;
 885    :      }
 886    :  
 887    :      // Parse the Import Address Table.
 888  E :      bool iat_is_bound = import_descriptor->TimeDateStamp != 0;
 889    :      if (!ParseImportThunks(RelativeAddress(import_descriptor->FirstThunk),
 890    :                             num_thunks, iat_is_bound,
 891  E :                             kImportAddressTable, "IAT", import_name.c_str())) {
 892  i :        return NULL;
 893    :      }
 894    :  
 895    :      if (!AddRelative(import_descriptor,
 896  E :                       &import_descriptor->OriginalFirstThunk)) {
 897  i :        LOG(ERROR) << "Unable to add import name table reference.";
 898  i :        return NULL;
 899    :      }
 900    :  
 901  E :      if (!AddRelative(import_descriptor, &import_descriptor->FirstThunk)) {
 902  i :        LOG(ERROR) << "Unable to add import address table reference.";
 903  i :        return NULL;
 904    :      }
 905  E :    } while (import_descriptor.Next());
 906    :  
 907    :    BlockGraph::Block* import_descriptor_block =
 908    :        AddBlock(BlockGraph::DATA_BLOCK,
 909    :                 import_descriptor_addr,
 910    :                 import_descriptor.addr() - import_descriptor_addr +
 911    :                     sizeof(IMAGE_IMPORT_DESCRIPTOR),
 912  E :                 "Import Directory");
 913    :  
 914  E :    return import_descriptor_block;
 915  E :  }
 916    :  
 917    :  BlockGraph::Block *PEFileParser::ParseComDescriptorDir(
 918  i :      const IMAGE_DATA_DIRECTORY &dir) {
 919  i :    LOG(ERROR) << "Parsing for COM descriptors not implemented.";
 920  i :    return NULL;
 921  i :  }
 922    :  
 923    :  BlockGraph::Block *PEFileParser::ParseDelayImportDir(
 924  E :      const IMAGE_DATA_DIRECTORY &dir) {
 925    :    // Read the delay import descriptor, we're going to iterate it.
 926  E :    RelativeAddress import_descriptor_addr(dir.VirtualAddress);
 927  E :    PEFileStructPtr<ImgDelayDescr> import_descriptor;
 928    :    if (!import_descriptor.Read(image_file_,
 929    :                                import_descriptor_addr,
 930  E :                                dir.Size)) {
 931  i :      LOG(ERROR) << "Unable to read the delay import directory.";
 932  i :      return NULL;
 933    :    }
 934    :  
 935    :    do {
 936    :      // The last descriptor is a sentinel.
 937  E :      if (import_descriptor->grAttrs == 0)
 938  E :        break;
 939    :  
 940  E :      if (import_descriptor->grAttrs != dlattrRva) {
 941  i :        LOG(ERROR) << "Unexpected attributes in delay import descriptor 0x"
 942    :                   << std::hex << import_descriptor->grAttrs;
 943  i :        return false;
 944    :      }
 945    :  
 946    :      // Read the name of the delay imported DLL.
 947  E :      std::string import_name;
 948  E :      RelativeAddress import_name_addr(import_descriptor->rvaDLLName);
 949  E :      if (!image_file_.ReadImageString(import_name_addr, &import_name)) {
 950  i :        LOG(ERROR) << "Unable to read delay import name.";
 951  i :        return NULL;
 952    :      }
 953    :  
 954    :      if (!AddBlock(BlockGraph::DATA_BLOCK,
 955    :                    import_name_addr,
 956    :                    common::AlignUp(import_name.size() + 1, 2),
 957    :                    base::StringPrintf("Delay import DLL Name \"%s\"",
 958  E :                                       import_name.c_str()).c_str())) {
 959  i :        LOG(ERROR) << "Unable to create import name block.";
 960  i :        return NULL;
 961    :      }
 962    :  
 963  E :      if (!AddRelative(import_descriptor, &import_descriptor->rvaDLLName)) {
 964  i :        LOG(ERROR) << "Unable to add delay import name reference.";
 965  i :        return NULL;
 966    :      }
 967    :  
 968    :      // Chunk the HMODULE for this import.
 969    :      if (!AddBlock(BlockGraph::DATA_BLOCK,
 970    :                    RelativeAddress(import_descriptor->rvaHmod),
 971    :                    sizeof(HMODULE),
 972    :                    base::StringPrintf("Module handle for delay import DLL\"%s\"",
 973  E :                                       import_name.c_str()).c_str())) {
 974  i :        LOG(ERROR) << "Unable to create import module handle block.";
 975  i :        return NULL;
 976    :      }
 977    :  
 978  E :      if (!AddRelative(import_descriptor, &import_descriptor->rvaHmod)) {
 979  i :        LOG(ERROR) << "Unable to delay import module handle reference.";
 980  i :        return NULL;
 981    :      }
 982    :  
 983    :      // Count the number of import name thunks for this import descriptor.
 984  E :      RelativeAddress int_addr(import_descriptor->rvaINT);
 985  E :      size_t num_thunks = CountImportThunks(int_addr);
 986  E :      if (num_thunks == 0)
 987  i :        return false;
 988    :  
 989    :      // Parse the Delay Import Name Table.
 990    :      if (!ParseImportThunks(int_addr, num_thunks, false,
 991    :                             kDelayLoadImportNameTable, "DelayINT",
 992  E :                             import_name.c_str())) {
 993  i :        return NULL;
 994    :      }
 995    :  
 996  E :      if (!AddRelative(import_descriptor, &import_descriptor->rvaINT)) {
 997  i :        LOG(ERROR) << "Unable to add delay import name table reference.";
 998  i :        return NULL;
 999    :      }
1000    :  
1001    :      // Parse the Delay Import Address Table.
1002    :      if (!ParseImportThunks(RelativeAddress(import_descriptor->rvaIAT),
1003    :                             num_thunks, false,
1004    :                             kDelayLoadImportAddressTable, "DelayIAT",
1005  E :                             import_name.c_str())) {
1006  i :        return NULL;
1007    :      }
1008    :  
1009  E :      if (!AddRelative(import_descriptor, &import_descriptor->rvaIAT)) {
1010  i :        LOG(ERROR) << "Unable to add delay import address table reference.";
1011  i :        return NULL;
1012    :      }
1013    :  
1014    :      // Parse the Bound Import Address Table.
1015  E :      bool iat_is_bound = import_descriptor->dwTimeStamp != 0;
1016    :      if (!ParseImportThunks(RelativeAddress(import_descriptor->rvaBoundIAT),
1017    :                             num_thunks, iat_is_bound,
1018    :                             kDelayLoadBoundImportAddressTable, "DelayBoundIAT",
1019  E :                             import_name.c_str())) {
1020  i :        return NULL;
1021    :      }
1022    :  
1023  E :      if (!AddRelative(import_descriptor, &import_descriptor->rvaBoundIAT)) {
1024  i :        LOG(ERROR) << "Unable to add delay bound import address table reference.";
1025  i :        return NULL;
1026    :      }
1027    :  
1028  E :      if (import_descriptor->rvaUnloadIAT != 0U) {
1029  i :        LOG(ERROR) << "Unexpected UnloadIAT.";
1030  i :        return false;
1031    :      }
1032    :  
1033  E :      if (import_descriptor->dwTimeStamp != 0U) {
1034  i :        LOG(ERROR) << "Unexpected bound delay imports.";
1035  i :        return false;
1036    :      }
1037  E :    } while (import_descriptor.Next());
1038    :  
1039    :    BlockGraph::Block* import_descriptor_block =
1040    :        AddBlock(BlockGraph::DATA_BLOCK,
1041    :                 import_descriptor_addr,
1042    :                 import_descriptor.addr() - import_descriptor_addr +
1043    :                     sizeof(ImgDelayDescr),
1044  E :                 "Delay Import Directory");
1045    :  
1046  E :    return import_descriptor_block;
1047  E :  }
1048    :  
1049    :  BlockGraph::Block *PEFileParser::ParseIatDir(
1050  E :      const IMAGE_DATA_DIRECTORY &dir) {
1051    :    return AddBlock(BlockGraph::DATA_BLOCK,
1052    :                    RelativeAddress(dir.VirtualAddress),
1053    :                    dir.Size,
1054  E :                    "Import Address Table");
1055  E :  }
1056    :  
1057    :  BlockGraph::Block *PEFileParser::ParseBoundImportDir(
1058  i :      const IMAGE_DATA_DIRECTORY &dir) {
1059  i :    LOG(ERROR) << "Parsing for bound import dir not implemented.";
1060  i :    return NULL;
1061  i :  }
1062    :  
1063    :  BlockGraph::Block *PEFileParser::ParseGlobalDir(
1064  i :      const IMAGE_DATA_DIRECTORY &dir) {
1065  i :    LOG(ERROR) << "Parsing for global dir not implemented.";
1066  i :    return NULL;
1067  i :  }
1068    :  
1069    :  BlockGraph::Block *PEFileParser::ParseArchitectureDir(
1070  i :      const IMAGE_DATA_DIRECTORY &dir) {
1071  i :    LOG(ERROR) << "Parsing for architecture dir not implemented.";
1072  i :    return NULL;
1073  i :  }
1074    :  
1075    :  BlockGraph::Block *PEFileParser::ParseRelocDir(
1076  E :      const IMAGE_DATA_DIRECTORY &dir) {
1077    :    return AddBlock(BlockGraph::DATA_BLOCK,
1078    :                    RelativeAddress(dir.VirtualAddress),
1079    :                    dir.Size,
1080  E :                    "Relocations");
1081  E :  }
1082    :  
1083    :  BlockGraph::Block *PEFileParser::ParseSecurityDir(
1084  i :      const IMAGE_DATA_DIRECTORY &dir) {
1085  i :    LOG(ERROR) << "Parsing for security dir not implemented.";
1086  i :    return NULL;
1087  i :  }
1088    :  
1089    :  BlockGraph::Block *PEFileParser::ParseExceptionDir(
1090  i :      const IMAGE_DATA_DIRECTORY &dir) {
1091  i :    LOG(ERROR) << "Parsing for exception dir not implemented.";
1092  i :    return NULL;
1093  i :  }
1094    :  
1095    :  BlockGraph::Block* PEFileParser::ParseTlsDir(
1096  E :      const IMAGE_DATA_DIRECTORY& dir) {
1097    :    BlockGraph::Block* tls_directory_block =
1098    :        AddBlock(BlockGraph::DATA_BLOCK,
1099    :                 RelativeAddress(dir.VirtualAddress),
1100    :                 sizeof(IMAGE_TLS_DIRECTORY),
1101  E :                 "Tls Directory");
1102  E :    if (tls_directory_block == NULL)
1103  i :      return NULL;
1104    :  
1105  E :    PEFileStructPtr<IMAGE_TLS_DIRECTORY> tls_directory;
1106  E :    if (!tls_directory.Set(tls_directory_block)) {
1107  i :      LOG(ERROR) << "Unable to read the TLS directory.";
1108  i :      return NULL;
1109    :    }
1110    :  
1111  E :    return tls_directory_block;
1112  E :  }
1113    :  
1114    :  BlockGraph::Block* PEFileParser::ParseLoadConfigDir(
1115  E :      const IMAGE_DATA_DIRECTORY& dir) {
1116    :    // We chunk the load config directory to sizeof(IMAGE_LOAD_CONFIG_DIRECTORY),
1117    :    // because it appears the VC9 linker leaves the data directory entry 8 bytes
1118    :    // short for some strange reason.
1119    :    BlockGraph::Block* load_config_block =
1120    :        AddBlock(BlockGraph::DATA_BLOCK,
1121    :                 RelativeAddress(dir.VirtualAddress),
1122    :                 sizeof(IMAGE_LOAD_CONFIG_DIRECTORY),
1123  E :                 "Load Config Directory");
1124    :  
1125  E :    PEFileStructPtr<IMAGE_LOAD_CONFIG_DIRECTORY> load_config;
1126  E :    if (!load_config.Set(load_config_block)) {
1127  i :      LOG(ERROR) << "Unable to the load config directory.";
1128  i :      return NULL;
1129    :    }
1130    :  
1131    :    if (!AddAbsolute(load_config, &load_config->LockPrefixTable) ||
1132    :        !AddAbsolute(load_config, &load_config->EditList) ||
1133    :        !AddAbsolute(load_config, &load_config->SecurityCookie) ||
1134  E :        !AddAbsolute(load_config, &load_config->SEHandlerTable)) {
1135  i :      LOG(ERROR) << "Unable to add load config directory references.";
1136  i :      return NULL;
1137    :    }
1138    :  
1139    :    // Iterate the exception handlers and add references for them.
1140  E :    RelativeAddress seh_handler;
1141  E :    PEFileStructPtr<DWORD> seh_handlers;
1142    :    if (!image_file_.Translate(AbsoluteAddress(load_config->SEHandlerTable),
1143    :                               &seh_handler) ||
1144    :        !seh_handlers.Read(image_file_, seh_handler,
1145  E :                           load_config->SEHandlerCount * sizeof(DWORD))) {
1146  i :      LOG(ERROR) << "Unable to read SEH handler table.";
1147  i :      return NULL;
1148    :    }
1149    :  
1150  E :    for (size_t i = 0; i < load_config->SEHandlerCount; ++i) {
1151  E :      if (!AddRelative(seh_handlers, seh_handlers.ptr() + i)) {
1152  i :        LOG(ERROR) << "Unable to add SEH handler reference.";
1153  i :        return NULL;
1154    :      }
1155  E :    }
1156    :  
1157  E :    return load_config_block;
1158  E :  }
1159    :  
1160    :  BlockGraph::Block* PEFileParser::ParseDebugDir(
1161  E :      const IMAGE_DATA_DIRECTORY& dir) {
1162    :    BlockGraph::Block* debug_directory_block =
1163    :        AddBlock(BlockGraph::DATA_BLOCK,
1164    :                 RelativeAddress(dir.VirtualAddress),
1165    :                 dir.Size,
1166  E :                 "Debug Directory");
1167  E :    if (debug_directory_block == NULL)
1168  i :      return NULL;
1169    :  
1170  E :    PEFileStructPtr<IMAGE_DEBUG_DIRECTORY> debug_directory;
1171  E :    if (!debug_directory.Set(debug_directory_block)) {
1172  i :      LOG(ERROR) << "Unable to read the debug directory.";
1173  i :      return NULL;
1174    :    }
1175    :  
1176    :    do {
1177    :      if (!AddRelative(debug_directory, &debug_directory->AddressOfRawData) ||
1178  E :          !AddFileOffset(debug_directory, &debug_directory->PointerToRawData)) {
1179  i :        LOG(ERROR) << "Failed to add debug directory references.";
1180  i :        return NULL;
1181    :      }
1182    :  
1183    :      // Chunk the data referenced by the debug directory entry.
1184    :      BlockGraph::Block* debug_data =
1185    :          AddBlock(BlockGraph::DATA_BLOCK,
1186    :                   RelativeAddress(debug_directory->AddressOfRawData),
1187    :                   debug_directory->SizeOfData,
1188  E :                   "Debug Info");
1189  E :    } while (debug_directory.Next());
1190    :  
1191  E :    return debug_directory_block;
1192  E :  }
1193    :  
1194    :  BlockGraph::Block* PEFileParser::ParseResourceDir(
1195  E :      const IMAGE_DATA_DIRECTORY& dir) {
1196    :    BlockGraph::Block* resource_block =
1197    :        AddBlock(BlockGraph::DATA_BLOCK,
1198    :                 RelativeAddress(dir.VirtualAddress),
1199    :                 dir.Size,
1200  E :                 "Resource Directory");
1201  E :    if (resource_block == NULL)
1202  i :      return NULL;
1203    :  
1204  E :    if (!ParseResourceDirImpl(resource_block, 0))
1205  i :      return NULL;
1206    :  
1207  E :    return resource_block;
1208  E :  }
1209    :  
1210    :  bool PEFileParser::ParseResourceDirImpl(BlockGraph::Block* resource_block,
1211  E :                                          size_t root_offset) {
1212  E :    DCHECK(resource_block != NULL);
1213  E :    RelativeAddress root_addr = resource_block->addr();
1214    :  
1215    :    // Setup the directory node we're currently scanning.
1216  E :    PEFileStructPtr<IMAGE_RESOURCE_DIRECTORY> directory;
1217  E :    if (!directory.Set(resource_block, root_addr + root_offset)) {
1218  i :      LOG(ERROR) << "Unable to read the resource directory.";
1219  i :      return false;
1220    :    }
1221    :  
1222    :    // How many entries hang from this node in the resource tree?
1223    :    size_t num_entries = directory->NumberOfNamedEntries +
1224  E :        directory->NumberOfIdEntries;
1225  E :    size_t entry_offset = root_offset + sizeof(IMAGE_RESOURCE_DIRECTORY);
1226    :  
1227    :    // Let's walk through them.
1228  E :    for (size_t i = 0; i < num_entries; ++i) {
1229    :      // Note that the offsets in the directory entries are all relative to
1230    :      // the root address of the resource block.
1231  E :      PEFileStructPtr<IMAGE_RESOURCE_DIRECTORY_ENTRY> directory_entry;
1232  E :      if (!directory_entry.Set(resource_block, root_addr + entry_offset)) {
1233  i :        LOG(ERROR) << "Unable to read the resource directory entry.";
1234  i :        return false;
1235    :      }
1236  E :      if (directory_entry->DataIsDirectory) {
1237    :        if (!ParseResourceDirImpl(resource_block,
1238  E :                                  directory_entry->OffsetToDirectory)) {
1239  i :          return false;
1240    :        }
1241  E :      } else {
1242  E :        PEFileStructPtr<IMAGE_RESOURCE_DATA_ENTRY> data_entry;
1243  E :        RelativeAddress entry_addr(root_addr + directory_entry->OffsetToData);
1244  E :        if (!data_entry.Set(resource_block, entry_addr)) {
1245  i :          LOG(ERROR) << "Unable to read the resource data entry.";
1246  i :          return false;
1247    :        }
1248    :        // The offsets in the data entries are RVAs.
1249  E :        if (!AddRelative(data_entry, &data_entry->OffsetToData)) {
1250  i :          LOG(ERROR) << "Failed to add resouce data reference.";
1251  i :          return false;
1252    :        }
1253    :      }
1254  E :      entry_offset += sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY);
1255  E :    }
1256    :  
1257  E :    return true;
1258  E :  }
1259    :  
1260    :  bool PEFileParser::AddReference(RelativeAddress src,
1261    :                                  BlockGraph::ReferenceType type,
1262    :                                  BlockGraph::Size size,
1263  E :                                  RelativeAddress dst) {
1264  E :    return add_reference_.Run(src, type, size, dst);
1265  E :  }
1266    :  
1267    :  BlockGraph::Block* PEFileParser::AddBlock(BlockGraph::BlockType type,
1268    :                                            RelativeAddress addr,
1269    :                                            BlockGraph::Size size,
1270  E :                                            const char* name) {
1271  E :    BlockGraph::Block* block = address_space_->AddBlock(type, addr, size, name);
1272  E :    if (block != NULL) {
1273  E :      block->set_attribute(BlockGraph::PE_PARSED);
1274    :  
1275    :      // Mark the source range from whence this block originates.
1276    :      bool pushed = block->source_ranges().Push(
1277    :          BlockGraph::Block::DataRange(0, size),
1278  E :          BlockGraph::Block::SourceRange(addr, size));
1279  E :      DCHECK(pushed);
1280    :  
1281    :      // Set the section for this block. We let blocks that belong to the header
1282    :      // be marked with kInvalidSectionId.
1283  E :      size_t section = image_file_.GetSectionIndex(addr, size);
1284  E :      if (section == BlockGraph::kInvalidSectionId) {
1285    :        // If no section was found for this block, we expect it to be a part of
1286    :        // the header.
1287    :        const RelativeAddress end_of_headers(
1288  E :            image_file_.nt_headers()->OptionalHeader.SizeOfHeaders);
1289  E :        if (addr + size > end_of_headers) {
1290  i :          LOG(ERROR) << "Found a non-header block outside of sections.";
1291  i :          return NULL;
1292    :        }
1293    :      }
1294  E :      block->set_section(section);
1295    :  
1296  E :      const uint8* data = image_file_.GetImageData(addr, size);
1297  E :      if (data != NULL)
1298  E :        block->SetData(data, size);
1299    :    }
1300    :  
1301  E :    return block;
1302  E :  }
1303    :  
1304    :  template <typename ItemType>
1305    :  bool PEFileParser::AddRelative(const PEFileStructPtr<ItemType>& structure,
1306  E :                                 const DWORD* item) {
1307  E :    DCHECK(item != NULL);
1308  E :    if (*item == 0)
1309  E :      return true;
1310    :  
1311    :    return AddReference(structure.AddressOf(item),
1312    :                        BlockGraph::RELATIVE_REF,
1313    :                        sizeof(*item),
1314  E :                        RelativeAddress(*item));
1315  E :  }
1316    :  
1317    :  template <typename ItemType>
1318    :  bool PEFileParser::AddAbsolute(const PEFileStructPtr<ItemType>& structure,
1319  E :                                 const DWORD* item) {
1320  E :    DCHECK(item != NULL);
1321  E :    if (*item == 0)
1322  E :      return true;
1323    :  
1324  E :    AbsoluteAddress abs(*item);
1325  E :    RelativeAddress rel;
1326    :  
1327    :    return image_file_.Translate(abs, &rel) &&
1328    :        AddReference(structure.AddressOf(item),
1329    :                     BlockGraph::ABSOLUTE_REF,
1330    :                     sizeof(*item),
1331  E :                     rel);
1332  E :  }
1333    :  
1334    :  template <typename ItemType>
1335    :  bool PEFileParser::AddFileOffset(const PEFileStructPtr<ItemType>& structure,
1336  E :                                   const DWORD* item) {
1337  E :    DCHECK(item != NULL);
1338  E :    if (*item == 0)
1339  i :      return true;
1340    :  
1341  E :    FileOffsetAddress offs(*item);
1342  E :    RelativeAddress rel;
1343    :  
1344    :    return image_file_.Translate(offs, &rel) &&
1345    :        AddReference(structure.AddressOf(item),
1346    :                     BlockGraph::FILE_OFFSET_REF,
1347    :                     sizeof(*item),
1348  E :                     rel);
1349  E :  }
1350    :  
1351    :  }  // namespace pe

Coverage information generated Thu Sep 06 11:30:46 2012.