Coverage for /Syzygy/pe/pe_file_parser.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
65.5%3815820.C++source

Line-by-line coverage:

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

Coverage information generated Thu Jul 04 09:34:53 2013.