Coverage for /Syzygy/pe/pe_file_parser.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
65.6%3845850.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/strings/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  E :    if (!AddRelative(export_dir, &export_dir->Name)) {
 470  i :      LOG(ERROR) << "Unable to add export functions reference.";
 471  i :      return NULL;
 472    :    }
 473    :  
 474    :    // All the references in the export directory should point back into
 475    :    // the export directory, unless they are NULL (empty).
 476    :  
 477  E :    if (export_dir->AddressOfFunctions != 0) {
 478    :      DCHECK_EQ(export_dir_block, address_space_->GetContainingBlock(
 479    :          RelativeAddress(export_dir->AddressOfFunctions),
 480  E :          sizeof(RelativeAddress)));
 481  E :      if (!AddRelative(export_dir, &export_dir->AddressOfFunctions)) {
 482  i :        LOG(ERROR) << "Unable to add export functions reference.";
 483  i :        return NULL;
 484    :      }
 485    :  
 486  E :      PEFileStructPtr<DWORD> function;
 487    :      if (!function.Set(export_dir_block,
 488  E :                        RelativeAddress(export_dir->AddressOfFunctions))) {
 489  i :        LOG(ERROR) << "Unable to parse export function table.";
 490  i :        return NULL;
 491    :      }
 492    :  
 493  E :      for (size_t i = 0; i < export_dir->NumberOfFunctions; ++i) {
 494    :        // TODO(siggi): This could be labeled with the exported function's
 495    :        //    name, if one is available.
 496  E :        if (!AddRelative(function, function.ptr())) {
 497  i :          LOG(ERROR) << "Unable to add reference to exported function.";
 498  i :          return NULL;
 499    :        }
 500    :  
 501  E :        if (!function.Next()) {
 502  i :          LOG(ERROR) << "Unable to parse export function table.";
 503  i :          return NULL;
 504    :        }
 505  E :      }
 506    :    }
 507    :  
 508  E :    if (export_dir->AddressOfNames != 0) {
 509    :      DCHECK_EQ(export_dir_block, address_space_->GetContainingBlock(
 510    :          RelativeAddress(export_dir->AddressOfNames),
 511  E :          sizeof(RelativeAddress)));
 512  E :      if (!AddRelative(export_dir, &export_dir->AddressOfNames)) {
 513  i :        LOG(ERROR) << "Unable to add export address of names reference.";
 514  i :        return NULL;
 515    :      }
 516    :  
 517    :      // Add references to the export function names.
 518  E :      PEFileStructPtr<DWORD> name;
 519    :      if (!name.Set(export_dir_block,
 520  E :                    RelativeAddress(export_dir->AddressOfNames))) {
 521  i :        LOG(ERROR) << "Unable to parse export name table.";
 522    :      }
 523    :  
 524  E :      for (size_t i = 0; i < export_dir->NumberOfNames; ++i) {
 525    :        // All the names in the export directory should point back into
 526    :        // the export directory, sanity check this.
 527    :        DCHECK_EQ(export_dir_block, address_space_->GetContainingBlock(
 528    :            RelativeAddress(*name.ptr()),
 529  E :            sizeof(RelativeAddress)));
 530    :  
 531  E :        if (!AddRelative(name, name.ptr())) {
 532  i :          LOG(ERROR) << "Unable to add reference to export function name.";
 533  i :          return NULL;
 534    :        }
 535    :  
 536  E :        if (!name.Next()) {
 537  i :          LOG(ERROR) << "Unable to parse export function table.";
 538  i :          return NULL;
 539    :        }
 540  E :      }
 541    :    }
 542    :  
 543  E :    if (export_dir->AddressOfNameOrdinals != 0) {
 544    :      DCHECK_EQ(export_dir_block, address_space_->GetContainingBlock(
 545    :          RelativeAddress(export_dir->AddressOfNameOrdinals),
 546  E :          sizeof(RelativeAddress)));
 547  E :      if (!AddRelative(export_dir, &export_dir->AddressOfNameOrdinals)) {
 548  i :        LOG(ERROR) << "Unable to add export address of ordinals reference.";
 549  i :        return NULL;
 550    :      }
 551    :    }
 552    :  
 553  E :    return export_dir_block;
 554  E :  }
 555    :  
 556  E :  size_t PEFileParser::CountImportThunks(RelativeAddress thunk_start) {
 557  E :    size_t num_thunks = 0;
 558  E :    for (; true; ++num_thunks, thunk_start += sizeof(IMAGE_THUNK_DATA)) {
 559  E :      PEFileStructPtr<IMAGE_THUNK_DATA> thunk;
 560  E :      if (!thunk.Read(image_file_, thunk_start)) {
 561    :        // We didn't get to the sentinel, that's an error.
 562  i :        LOG(ERROR) << "Unable to read image import thunk.";
 563  i :        return 0;
 564    :      }
 565    :  
 566  E :      if (thunk->u1.AddressOfData == 0U)
 567  E :        break;
 568  E :    }
 569    :  
 570  E :    return num_thunks;
 571  E :  }
 572    :  
 573    :  bool PEFileParser::ParseImportThunks(RelativeAddress thunk_start,
 574    :                                       size_t num_thunks,
 575    :                                       bool is_bound,
 576    :                                       ThunkTableType table_type,
 577    :                                       const char* thunk_type,
 578  E :                                       const char* import_name) {
 579    :    // Only certain table types may be bound.
 580    :    DCHECK(!is_bound || table_type == kImportAddressTable ||
 581  E :               table_type == kDelayLoadBoundImportAddressTable);
 582    :  
 583    :    // Start by chunking the IAT/INT, including the terminating sentinel.
 584  E :    size_t ixt_size = sizeof(IMAGE_THUNK_DATA) * (num_thunks + 1);
 585    :  
 586    :    std::string ixt_name =
 587  E :        base::StringPrintf("%s for \"%s\"", thunk_type, import_name);
 588    :  
 589  E :    BlockGraph::Block* thunk_block = NULL;
 590  E :    if (table_type == kDelayLoadBoundImportAddressTable) {
 591    :      thunk_block = ChunkDelayBoundIATBlock(thunk_start, ixt_size,
 592  E :                                            ixt_name.c_str());
 593  E :    } else {
 594    :      // Try to add the block.
 595    :      thunk_block = AddBlock(BlockGraph::DATA_BLOCK,
 596    :                             thunk_start,
 597    :                             ixt_size,
 598  E :                             ixt_name.c_str());
 599    :  
 600    :      // The IAT may have been chunked while parsing the IAT data directory,
 601    :      // in which case we want to leave a label for the start of our entries. In
 602    :      // this case we should be wholly contained in an existing block.
 603  E :      if (thunk_block == NULL)
 604  E :        thunk_block = address_space_->GetContainingBlock(thunk_start, ixt_size);
 605    :    }
 606    :  
 607  E :    if (thunk_block == NULL) {
 608  i :      LOG(ERROR) << "Unable to add " << thunk_type
 609    :                 << "block for " << import_name;
 610  i :      return false;
 611    :    }
 612    :  
 613    :    // Add a label to the start of the table.
 614    :    thunk_block->SetLabel(thunk_start - thunk_block->addr(),
 615    :                          ixt_name,
 616  E :                          BlockGraph::DATA_LABEL);
 617    :  
 618    :    // Determine the type of data in the table. We only chunk out names for
 619    :    // import name tables. This prevents us from doing the work twice for an
 620    :    // unbound IAT.
 621  E :    ThunkDataType thunk_data_type = GetThunkDataType(table_type, is_bound);
 622    :    bool chunk_names = table_type == kImportNameTable ||
 623  E :        table_type == kDelayLoadImportNameTable;
 624    :  
 625    :    // Run through and validate the table contents, parsing IMAGE_IMPORT_BY_NAMES
 626    :    // if we're in an import name table.
 627  E :    for (size_t i = 0; i < num_thunks; ++i) {
 628    :      if (!ParseImportThunk(thunk_start, thunk_data_type, thunk_type,
 629  E :                            import_name, chunk_names)) {
 630  i :        return false;
 631    :      }
 632  E :      thunk_start += sizeof(IMAGE_THUNK_DATA);
 633  E :    }
 634    :  
 635  E :    return true;
 636  E :  }
 637    :  
 638    :  bool PEFileParser::ParseImportThunk(RelativeAddress thunk_addr,
 639    :                                      ThunkDataType thunk_data_type,
 640    :                                      const char* thunk_type,
 641    :                                      const char* module_name,
 642  E :                                      bool chunk_name) {
 643    :    // We can only chunk names if we're parsing an IMAGE_THUNK_DATA object.
 644  E :    DCHECK(!chunk_name || thunk_data_type == kImageThunkData);
 645    :  
 646  E :    PEFileStructPtr<IMAGE_THUNK_DATA> thunk;
 647  E :    if (!thunk.Read(image_file_, thunk_addr)) {
 648  i :      LOG(ERROR) << "Unable to read image import thunk.";
 649  i :      return false;
 650    :    }
 651    :  
 652  E :    switch (thunk_data_type) {
 653    :      case kNullThunkData: {
 654  i :        if (thunk->u1.AddressOfData != 0) {
 655  i :          LOG(ERROR) << "Expect NULL " << thunk_type << " thunk, got 0x"
 656    :                     << std::hex << thunk->u1.AddressOfData;
 657  i :          return false;
 658    :        }
 659  i :        break;
 660    :      }
 661    :  
 662    :      case kImageThunkData: {
 663    :        // If it's an ordinal, there's nothing to do.
 664  E :        if (IMAGE_SNAP_BY_ORDINAL(thunk->u1.Ordinal))
 665  E :          break;
 666    :  
 667    :        // It's not an ordinal, so it must contain an RVA to an
 668    :        // IMAGE_IMPORT_BY_NAME.
 669    :  
 670    :        // Add the IAT/INT->thunk reference.
 671  E :        if (!AddRelative(thunk, &thunk->u1.AddressOfData)) {
 672  i :          LOG(ERROR) << "Unable to add import thunk reference.";
 673  i :          return false;
 674    :        }
 675    :  
 676    :        // Read the thunk and name & chunk it out.
 677  E :        PEFileStructPtr<IMAGE_IMPORT_BY_NAME> name_thunk;
 678  E :        RelativeAddress name_thunk_addr(thunk->u1.AddressOfData);
 679  E :        if (!name_thunk.Read(image_file_, name_thunk_addr)) {
 680  i :          LOG(ERROR) << "Unable to read import name thunk.";
 681  i :          return false;
 682    :        }
 683    :  
 684  E :        std::string function_name;
 685    :        RelativeAddress function_name_addr(
 686  E :            name_thunk.AddressOf(&name_thunk->Name));
 687  E :        if (!image_file_.ReadImageString(function_name_addr, &function_name)) {
 688  i :          LOG(ERROR) << "Unable to read import function name.";
 689  i :          return false;
 690    :        }
 691    :  
 692    :        // Calculate the even-padded size of the name thunk.
 693    :        size_t name_thunk_size = common::AlignUp(
 694  E :            offsetof(IMAGE_IMPORT_BY_NAME, Name) + function_name.size() + 1, 2);
 695    :  
 696    :        // Chunk the names only on request, as more than one IAT/INT may
 697    :        // point to the same name blocks.
 698  E :        if (chunk_name) {
 699    :          BlockGraph::Block* thunk = AddBlock(
 700    :              BlockGraph::DATA_BLOCK,
 701    :              name_thunk_addr,
 702    :              name_thunk_size,
 703    :              base::StringPrintf("Import Name Thunk \"%s\" from \"%s\"",
 704    :                                 function_name.c_str(),
 705  E :                                 module_name).c_str());
 706  E :          if (thunk == NULL) {
 707  i :            LOG(ERROR) << "Unable to add function name block.";
 708  i :            return false;
 709    :          }
 710    :  
 711  E :          if (!on_import_thunk_.Run(module_name, function_name.c_str(), thunk)) {
 712  i :            LOG(ERROR) << "OnImportThunk callback failed.";
 713  i :            return false;
 714    :          }
 715  E :        } else {
 716    :  #ifndef NDEBUG
 717    :          // Check that the name blocks exist in debug.
 718    :          BlockGraph::Block* block =
 719  E :              address_space_->GetBlockByAddress(name_thunk_addr);
 720  E :          DCHECK(block != NULL);
 721  E :          DCHECK_EQ(name_thunk_size, block->size());
 722    :  #endif  // NDEBUG
 723    :        }
 724  E :        break;
 725    :      }
 726    :  
 727    :      case kCodeInImageThunkData: {
 728    :        // Add the code reference. This will check that it is in fact a reference
 729    :        // to an address in the image, and track the associated block
 730    :        // automatically.
 731  E :        if (!AddAbsolute(thunk, &thunk->u1.AddressOfData)) {
 732  i :          LOG(ERROR) << "Unable to add import thunk reference.";
 733  i :          return false;
 734    :        }
 735  E :        break;
 736    :      }
 737    :  
 738    :      case kCodeOutOfImageThunkData: {
 739    :        // This is an absolute address to code outside of the image. It may
 740    :        // actually have an address that lies inside our image because the
 741    :        // imported module may have an overlapping preferred load address.
 742  i :        if (thunk->u1.AddressOfData < 0x1000) {
 743  i :          AbsoluteAddress abs_addr(thunk->u1.AddressOfData);
 744  i :          LOG(ERROR) << thunk_type << " thunk to external code has invalid "
 745    :                     << "address: " << abs_addr;
 746  i :          return false;
 747    :        }
 748    :        break;
 749    :      }
 750    :  
 751    :      case kArbitraryThunkData: {
 752    :        // We do nothing. Anything goes!
 753    :        break;
 754    :      }
 755    :    }
 756    :  
 757  E :    return true;
 758  E :  }
 759    :  
 760    :  BlockGraph::Block* PEFileParser::ChunkDelayBoundIATBlock(
 761  E :      RelativeAddress iat_addr, size_t iat_size, const char* iat_name) {
 762    :    BlockGraph::Block* iat_block = AddBlock(BlockGraph::DATA_BLOCK,
 763    :                                            iat_addr,
 764    :                                            iat_size,
 765  E :                                            iat_name);
 766  E :    if (iat_block != NULL)
 767  E :      return iat_block;
 768    :  
 769    :    // If we get here we were unable to create a block, so there must be a
 770    :    // conflict. We've seen the bound IATs for delay-loaded libraries be too
 771    :    // small. That is, one library's bound IAT is overwritten by another library's
 772    :    // bound IAT. We do our best to patch things up, by growing the conflicting
 773    :    // pre-existing block to also cover the range of the block we want to create.
 774    :    //
 775    :    // We extend the existing block by creating new blocks (one to the left, one
 776    :    // to the right) of the conflicting block that cover the portion of the new
 777    :    // table that is not covered. Then, we merge them all.
 778    :  
 779    :    iat_block = address_space_->GetFirstIntersectingBlock(iat_addr,
 780  i :                                                          iat_size);
 781  i :    VLOG(1) << iat_name << " collides with existing block " << iat_block->name()
 782    :            << ".";
 783    :  
 784    :    // If we're completely contained within the conflicting block, there's no
 785    :    // expanding and merging to do.
 786  i :    if (iat_block->Contains(iat_addr, iat_size))
 787  i :      return iat_block;
 788    :  
 789    :    // Create a block to the left of the existing block, if the desired table
 790    :    // extends to the left.
 791  i :    if (iat_addr < iat_block->addr()) {
 792  i :      size_t pre_size = iat_block->addr() - iat_addr;
 793    :      BlockGraph::Block* pre_block = AddBlock(BlockGraph::DATA_BLOCK,
 794    :                                              iat_addr,
 795    :                                              pre_size,
 796  i :                                              iat_name);
 797    :      // This should never fail as iat_block is the *first* intersecting
 798    :      // block.
 799  i :      DCHECK(pre_block != NULL);
 800    :    }
 801    :  
 802    :    // Insert the missing part of this table to the right of the intersecting
 803    :    // block, if there is any needed.
 804  i :    RelativeAddress new_end = iat_addr + iat_size;
 805  i :    RelativeAddress old_end = iat_block->addr() + iat_block->size();
 806  i :    if (new_end > old_end) {
 807    :      BlockGraph::Block* next_block =
 808    :          address_space_->GetFirstIntersectingBlock(
 809  i :              old_end, new_end - old_end);
 810    :  
 811  i :      if (next_block != NULL)
 812  i :        new_end = next_block->addr();
 813    :  
 814  i :      if (new_end > old_end) {
 815    :        BlockGraph::Block* post_block = AddBlock(BlockGraph::DATA_BLOCK,
 816    :                                                 old_end,
 817    :                                                 new_end - old_end,
 818  i :                                                 NULL);
 819    :        // This should never fail as we're inserting after the end of
 820    :        // iat_block, and before the start of the next block in the
 821    :        // address space.
 822  i :        DCHECK(post_block != NULL);
 823    :      }
 824    :    }
 825    :  
 826    :    // Merge the blocks to create one new contiguous block.
 827  i :    BlockGraph::AddressSpace::Range range(iat_addr, iat_size);
 828  i :    if (!address_space_->MergeIntersectingBlocks(range)) {
 829  i :      LOG(ERROR) << "Unable to merge intersecting bound IAT blocks.";
 830  i :      return NULL;
 831    :    }
 832  i :    iat_block = address_space_->GetContainingBlock(iat_addr, iat_size);
 833  i :    DCHECK(iat_block != NULL);
 834    :  
 835  i :    return iat_block;
 836  E :  }
 837    :  
 838    :  BlockGraph::Block* PEFileParser::ParseImportDir(
 839  E :      const IMAGE_DATA_DIRECTORY& dir) {
 840    :    // Read the import descriptor, we're going to iterate it.
 841  E :    RelativeAddress import_descriptor_addr(dir.VirtualAddress);
 842  E :    PEFileStructPtr<IMAGE_IMPORT_DESCRIPTOR> import_descriptor;
 843    :    if (!import_descriptor.Read(image_file_,
 844    :                                import_descriptor_addr,
 845  E :                                dir.Size)) {
 846  i :      LOG(ERROR) << "Unable to read the import directory.";
 847  i :      return NULL;
 848    :    }
 849    :  
 850    :    do {
 851    :      // The last import descriptor is a sentinel.
 852  E :      if (import_descriptor->Characteristics == 0) {
 853  E :        DCHECK_EQ(0U, import_descriptor->Name);
 854  E :        DCHECK_EQ(0U, import_descriptor->FirstThunk);
 855  E :        break;
 856    :      }
 857    :  
 858    :      // Read the name of the imported DLL.
 859  E :      std::string import_name;
 860  E :      RelativeAddress import_name_addr(import_descriptor->Name);
 861  E :      if (!image_file_.ReadImageString(import_name_addr, &import_name)) {
 862  i :        LOG(ERROR) << "Unable to read import name.";
 863  i :        return NULL;
 864    :      }
 865    :  
 866    :      if (!AddBlock(BlockGraph::DATA_BLOCK,
 867    :                    import_name_addr,
 868    :                    common::AlignUp(import_name.size() + 1, 2),
 869    :                    base::StringPrintf("Import DLL Name \"%s\"",
 870  E :                                       import_name.c_str()).c_str())) {
 871  i :        LOG(ERROR) << "Unable to create import name block.";
 872  i :        return NULL;
 873    :      }
 874    :  
 875  E :      if (!AddRelative(import_descriptor, &import_descriptor->Name)) {
 876  i :        LOG(ERROR) << "Unable to add import name reference.";
 877  i :        return NULL;
 878    :      }
 879    :  
 880    :      // Count the number of import name thunks for this import descriptor.
 881    :      RelativeAddress thunk_addr =
 882  E :          RelativeAddress(import_descriptor->OriginalFirstThunk);
 883  E :      size_t num_thunks = CountImportThunks(thunk_addr);
 884  E :      if (num_thunks == 0)
 885  i :        return NULL;
 886    :  
 887    :      // Parse the Import Name Table.
 888    :      if (!ParseImportThunks(thunk_addr, num_thunks, false,
 889  E :                             kImportNameTable, "INT", import_name.c_str())) {
 890  i :        return NULL;
 891    :      }
 892    :  
 893    :      // Parse the Import Address Table.
 894  E :      bool iat_is_bound = import_descriptor->TimeDateStamp != 0;
 895    :      if (!ParseImportThunks(RelativeAddress(import_descriptor->FirstThunk),
 896    :                             num_thunks, iat_is_bound,
 897  E :                             kImportAddressTable, "IAT", import_name.c_str())) {
 898  i :        return NULL;
 899    :      }
 900    :  
 901    :      if (!AddRelative(import_descriptor,
 902  E :                       &import_descriptor->OriginalFirstThunk)) {
 903  i :        LOG(ERROR) << "Unable to add import name table reference.";
 904  i :        return NULL;
 905    :      }
 906    :  
 907  E :      if (!AddRelative(import_descriptor, &import_descriptor->FirstThunk)) {
 908  i :        LOG(ERROR) << "Unable to add import address table reference.";
 909  i :        return NULL;
 910    :      }
 911  E :    } while (import_descriptor.Next());
 912    :  
 913    :    BlockGraph::Block* import_descriptor_block =
 914    :        AddBlock(BlockGraph::DATA_BLOCK,
 915    :                 import_descriptor_addr,
 916    :                 import_descriptor.addr() - import_descriptor_addr +
 917    :                     sizeof(IMAGE_IMPORT_DESCRIPTOR),
 918  E :                 "Import Directory");
 919    :  
 920  E :    return import_descriptor_block;
 921  E :  }
 922    :  
 923    :  BlockGraph::Block *PEFileParser::ParseComDescriptorDir(
 924  i :      const IMAGE_DATA_DIRECTORY &dir) {
 925  i :    LOG(ERROR) << "Parsing for COM descriptors not implemented.";
 926  i :    return NULL;
 927  i :  }
 928    :  
 929    :  BlockGraph::Block *PEFileParser::ParseDelayImportDir(
 930  E :      const IMAGE_DATA_DIRECTORY &dir) {
 931    :    // Read the delay import descriptor, we're going to iterate it.
 932  E :    RelativeAddress import_descriptor_addr(dir.VirtualAddress);
 933  E :    PEFileStructPtr<ImgDelayDescr> import_descriptor;
 934    :    if (!import_descriptor.Read(image_file_,
 935    :                                import_descriptor_addr,
 936  E :                                dir.Size)) {
 937  i :      LOG(ERROR) << "Unable to read the delay import directory.";
 938  i :      return NULL;
 939    :    }
 940    :  
 941    :    do {
 942    :      // The last descriptor is a sentinel.
 943  E :      if (import_descriptor->grAttrs == 0)
 944  E :        break;
 945    :  
 946  E :      if (import_descriptor->grAttrs != dlattrRva) {
 947  i :        LOG(ERROR) << "Unexpected attributes in delay import descriptor 0x"
 948    :                   << std::hex << import_descriptor->grAttrs;
 949  i :        return NULL;
 950    :      }
 951    :  
 952    :      // Read the name of the delay imported DLL.
 953  E :      std::string import_name;
 954  E :      RelativeAddress import_name_addr(import_descriptor->rvaDLLName);
 955  E :      if (!image_file_.ReadImageString(import_name_addr, &import_name)) {
 956  i :        LOG(ERROR) << "Unable to read delay import name.";
 957  i :        return NULL;
 958    :      }
 959    :  
 960    :      if (!AddBlock(BlockGraph::DATA_BLOCK,
 961    :                    import_name_addr,
 962    :                    common::AlignUp(import_name.size() + 1, 2),
 963    :                    base::StringPrintf("Delay import DLL Name \"%s\"",
 964  E :                                       import_name.c_str()).c_str())) {
 965  i :        LOG(ERROR) << "Unable to create import name block.";
 966  i :        return NULL;
 967    :      }
 968    :  
 969  E :      if (!AddRelative(import_descriptor, &import_descriptor->rvaDLLName)) {
 970  i :        LOG(ERROR) << "Unable to add delay import name reference.";
 971  i :        return NULL;
 972    :      }
 973    :  
 974    :      // Chunk the HMODULE for this import.
 975    :      if (!AddBlock(BlockGraph::DATA_BLOCK,
 976    :                    RelativeAddress(import_descriptor->rvaHmod),
 977    :                    sizeof(HMODULE),
 978    :                    base::StringPrintf("Module handle for delay import DLL\"%s\"",
 979  E :                                       import_name.c_str()).c_str())) {
 980  i :        LOG(ERROR) << "Unable to create import module handle block.";
 981  i :        return NULL;
 982    :      }
 983    :  
 984  E :      if (!AddRelative(import_descriptor, &import_descriptor->rvaHmod)) {
 985  i :        LOG(ERROR) << "Unable to delay import module handle reference.";
 986  i :        return NULL;
 987    :      }
 988    :  
 989    :      // Count the number of import name thunks for this import descriptor.
 990  E :      RelativeAddress int_addr(import_descriptor->rvaINT);
 991  E :      size_t num_thunks = CountImportThunks(int_addr);
 992  E :      if (num_thunks == 0)
 993  i :        return NULL;
 994    :  
 995    :      // Parse the Delay Import Name Table.
 996    :      if (!ParseImportThunks(int_addr, num_thunks, false,
 997    :                             kDelayLoadImportNameTable, "DelayINT",
 998  E :                             import_name.c_str())) {
 999  i :        return NULL;
1000    :      }
1001    :  
1002  E :      if (!AddRelative(import_descriptor, &import_descriptor->rvaINT)) {
1003  i :        LOG(ERROR) << "Unable to add delay import name table reference.";
1004  i :        return NULL;
1005    :      }
1006    :  
1007    :      // Parse the Delay Import Address Table.
1008    :      if (!ParseImportThunks(RelativeAddress(import_descriptor->rvaIAT),
1009    :                             num_thunks, false,
1010    :                             kDelayLoadImportAddressTable, "DelayIAT",
1011  E :                             import_name.c_str())) {
1012  i :        return NULL;
1013    :      }
1014    :  
1015  E :      if (!AddRelative(import_descriptor, &import_descriptor->rvaIAT)) {
1016  i :        LOG(ERROR) << "Unable to add delay import address table reference.";
1017  i :        return NULL;
1018    :      }
1019    :  
1020    :      // Parse the Bound Import Address Table.
1021  E :      bool iat_is_bound = import_descriptor->dwTimeStamp != 0;
1022    :      if (!ParseImportThunks(RelativeAddress(import_descriptor->rvaBoundIAT),
1023    :                             num_thunks, iat_is_bound,
1024    :                             kDelayLoadBoundImportAddressTable, "DelayBoundIAT",
1025  E :                             import_name.c_str())) {
1026  i :        return NULL;
1027    :      }
1028    :  
1029  E :      if (!AddRelative(import_descriptor, &import_descriptor->rvaBoundIAT)) {
1030  i :        LOG(ERROR) << "Unable to add delay bound import address table reference.";
1031  i :        return NULL;
1032    :      }
1033    :  
1034  E :      if (import_descriptor->rvaUnloadIAT != 0U) {
1035  i :        LOG(ERROR) << "Unexpected UnloadIAT.";
1036  i :        return NULL;
1037    :      }
1038    :  
1039  E :      if (import_descriptor->dwTimeStamp != 0U) {
1040  i :        LOG(ERROR) << "Unexpected bound delay imports.";
1041  i :        return NULL;
1042    :      }
1043  E :    } while (import_descriptor.Next());
1044    :  
1045    :    BlockGraph::Block* import_descriptor_block =
1046    :        AddBlock(BlockGraph::DATA_BLOCK,
1047    :                 import_descriptor_addr,
1048    :                 import_descriptor.addr() - import_descriptor_addr +
1049    :                     sizeof(ImgDelayDescr),
1050  E :                 "Delay Import Directory");
1051    :  
1052  E :    return import_descriptor_block;
1053  E :  }
1054    :  
1055    :  BlockGraph::Block *PEFileParser::ParseIatDir(
1056  E :      const IMAGE_DATA_DIRECTORY &dir) {
1057    :    return AddBlock(BlockGraph::DATA_BLOCK,
1058    :                    RelativeAddress(dir.VirtualAddress),
1059    :                    dir.Size,
1060  E :                    "Import Address Table");
1061  E :  }
1062    :  
1063    :  BlockGraph::Block *PEFileParser::ParseBoundImportDir(
1064  i :      const IMAGE_DATA_DIRECTORY &dir) {
1065  i :    LOG(ERROR) << "Parsing for bound import dir not implemented.";
1066  i :    return NULL;
1067  i :  }
1068    :  
1069    :  BlockGraph::Block *PEFileParser::ParseGlobalDir(
1070  i :      const IMAGE_DATA_DIRECTORY &dir) {
1071  i :    LOG(ERROR) << "Parsing for global dir not implemented.";
1072  i :    return NULL;
1073  i :  }
1074    :  
1075    :  BlockGraph::Block *PEFileParser::ParseArchitectureDir(
1076  i :      const IMAGE_DATA_DIRECTORY &dir) {
1077  i :    LOG(ERROR) << "Parsing for architecture dir not implemented.";
1078  i :    return NULL;
1079  i :  }
1080    :  
1081    :  BlockGraph::Block *PEFileParser::ParseRelocDir(
1082  E :      const IMAGE_DATA_DIRECTORY &dir) {
1083    :    return AddBlock(BlockGraph::DATA_BLOCK,
1084    :                    RelativeAddress(dir.VirtualAddress),
1085    :                    dir.Size,
1086  E :                    "Relocations");
1087  E :  }
1088    :  
1089    :  BlockGraph::Block *PEFileParser::ParseSecurityDir(
1090  i :      const IMAGE_DATA_DIRECTORY &dir) {
1091  i :    LOG(ERROR) << "Parsing for security dir not implemented.";
1092  i :    return NULL;
1093  i :  }
1094    :  
1095    :  BlockGraph::Block *PEFileParser::ParseExceptionDir(
1096  i :      const IMAGE_DATA_DIRECTORY &dir) {
1097  i :    LOG(ERROR) << "Parsing for exception dir not implemented.";
1098  i :    return NULL;
1099  i :  }
1100    :  
1101    :  BlockGraph::Block* PEFileParser::ParseTlsDir(
1102  E :      const IMAGE_DATA_DIRECTORY& dir) {
1103    :    BlockGraph::Block* tls_directory_block =
1104    :        AddBlock(BlockGraph::DATA_BLOCK,
1105    :                 RelativeAddress(dir.VirtualAddress),
1106    :                 sizeof(IMAGE_TLS_DIRECTORY),
1107  E :                 "Tls Directory");
1108  E :    if (tls_directory_block == NULL)
1109  i :      return NULL;
1110    :  
1111  E :    PEFileStructPtr<IMAGE_TLS_DIRECTORY> tls_directory;
1112  E :    if (!tls_directory.Set(tls_directory_block)) {
1113  i :      LOG(ERROR) << "Unable to read the TLS directory.";
1114  i :      return NULL;
1115    :    }
1116    :  
1117  E :    return tls_directory_block;
1118  E :  }
1119    :  
1120    :  BlockGraph::Block* PEFileParser::ParseLoadConfigDir(
1121  E :      const IMAGE_DATA_DIRECTORY& dir) {
1122    :    // We chunk the load config directory to sizeof(IMAGE_LOAD_CONFIG_DIRECTORY),
1123    :    // because it appears the VC9 linker leaves the data directory entry 8 bytes
1124    :    // short for some strange reason.
1125    :    BlockGraph::Block* load_config_block =
1126    :        AddBlock(BlockGraph::DATA_BLOCK,
1127    :                 RelativeAddress(dir.VirtualAddress),
1128    :                 sizeof(IMAGE_LOAD_CONFIG_DIRECTORY),
1129  E :                 "Load Config Directory");
1130    :  
1131  E :    PEFileStructPtr<IMAGE_LOAD_CONFIG_DIRECTORY> load_config;
1132  E :    if (!load_config.Set(load_config_block)) {
1133  i :      LOG(ERROR) << "Unable to the load config directory.";
1134  i :      return NULL;
1135    :    }
1136    :  
1137    :    if (!AddAbsolute(load_config, &load_config->LockPrefixTable) ||
1138    :        !AddAbsolute(load_config, &load_config->EditList) ||
1139    :        !AddAbsolute(load_config, &load_config->SecurityCookie) ||
1140  E :        !AddAbsolute(load_config, &load_config->SEHandlerTable)) {
1141  i :      LOG(ERROR) << "Unable to add load config directory references.";
1142  i :      return NULL;
1143    :    }
1144    :  
1145    :    // Iterate the exception handlers and add references for them.
1146  E :    RelativeAddress seh_handler;
1147  E :    PEFileStructPtr<DWORD> seh_handlers;
1148    :    if (!image_file_.Translate(AbsoluteAddress(load_config->SEHandlerTable),
1149    :                               &seh_handler) ||
1150    :        !seh_handlers.Read(image_file_, seh_handler,
1151  E :                           load_config->SEHandlerCount * sizeof(DWORD))) {
1152  i :      LOG(ERROR) << "Unable to read SEH handler table.";
1153  i :      return NULL;
1154    :    }
1155    :  
1156  E :    for (size_t i = 0; i < load_config->SEHandlerCount; ++i) {
1157  E :      if (!AddRelative(seh_handlers, seh_handlers.ptr() + i)) {
1158  i :        LOG(ERROR) << "Unable to add SEH handler reference.";
1159  i :        return NULL;
1160    :      }
1161  E :    }
1162    :  
1163  E :    return load_config_block;
1164  E :  }
1165    :  
1166    :  BlockGraph::Block* PEFileParser::ParseDebugDir(
1167  E :      const IMAGE_DATA_DIRECTORY& dir) {
1168    :    BlockGraph::Block* debug_directory_block =
1169    :        AddBlock(BlockGraph::DATA_BLOCK,
1170    :                 RelativeAddress(dir.VirtualAddress),
1171    :                 dir.Size,
1172  E :                 "Debug Directory");
1173  E :    if (debug_directory_block == NULL)
1174  i :      return NULL;
1175    :  
1176  E :    PEFileStructPtr<IMAGE_DEBUG_DIRECTORY> debug_directory;
1177  E :    if (!debug_directory.Set(debug_directory_block)) {
1178  i :      LOG(ERROR) << "Unable to read the debug directory.";
1179  i :      return NULL;
1180    :    }
1181    :  
1182    :    do {
1183    :      if (!AddRelative(debug_directory, &debug_directory->AddressOfRawData) ||
1184  E :          !AddFileOffset(debug_directory, &debug_directory->PointerToRawData)) {
1185  i :        LOG(ERROR) << "Failed to add debug directory references.";
1186  i :        return NULL;
1187    :      }
1188    :  
1189    :      // Chunk the data referenced by the debug directory entry.
1190    :      BlockGraph::Block* debug_data =
1191    :          AddBlock(BlockGraph::DATA_BLOCK,
1192    :                   RelativeAddress(debug_directory->AddressOfRawData),
1193    :                   debug_directory->SizeOfData,
1194  E :                   "Debug Info");
1195  E :    } while (debug_directory.Next());
1196    :  
1197  E :    return debug_directory_block;
1198  E :  }
1199    :  
1200    :  BlockGraph::Block* PEFileParser::ParseResourceDir(
1201  E :      const IMAGE_DATA_DIRECTORY& dir) {
1202    :    BlockGraph::Block* resource_block =
1203    :        AddBlock(BlockGraph::DATA_BLOCK,
1204    :                 RelativeAddress(dir.VirtualAddress),
1205    :                 dir.Size,
1206  E :                 "Resource Directory");
1207  E :    if (resource_block == NULL)
1208  i :      return NULL;
1209    :  
1210  E :    if (!ParseResourceDirImpl(resource_block, 0))
1211  i :      return NULL;
1212    :  
1213  E :    return resource_block;
1214  E :  }
1215    :  
1216    :  bool PEFileParser::ParseResourceDirImpl(BlockGraph::Block* resource_block,
1217  E :                                          size_t root_offset) {
1218  E :    DCHECK(resource_block != NULL);
1219  E :    RelativeAddress root_addr = resource_block->addr();
1220    :  
1221    :    // Setup the directory node we're currently scanning.
1222  E :    PEFileStructPtr<IMAGE_RESOURCE_DIRECTORY> directory;
1223  E :    if (!directory.Set(resource_block, root_addr + root_offset)) {
1224  i :      LOG(ERROR) << "Unable to read the resource directory.";
1225  i :      return false;
1226    :    }
1227    :  
1228    :    // How many entries hang from this node in the resource tree?
1229    :    size_t num_entries = directory->NumberOfNamedEntries +
1230  E :        directory->NumberOfIdEntries;
1231  E :    size_t entry_offset = root_offset + sizeof(IMAGE_RESOURCE_DIRECTORY);
1232    :  
1233    :    // Let's walk through them.
1234  E :    for (size_t i = 0; i < num_entries; ++i) {
1235    :      // Note that the offsets in the directory entries are all relative to
1236    :      // the root address of the resource block.
1237  E :      PEFileStructPtr<IMAGE_RESOURCE_DIRECTORY_ENTRY> directory_entry;
1238  E :      if (!directory_entry.Set(resource_block, root_addr + entry_offset)) {
1239  i :        LOG(ERROR) << "Unable to read the resource directory entry.";
1240  i :        return false;
1241    :      }
1242  E :      if (directory_entry->DataIsDirectory) {
1243    :        if (!ParseResourceDirImpl(resource_block,
1244  E :                                  directory_entry->OffsetToDirectory)) {
1245  i :          return false;
1246    :        }
1247  E :      } else {
1248  E :        PEFileStructPtr<IMAGE_RESOURCE_DATA_ENTRY> data_entry;
1249  E :        RelativeAddress entry_addr(root_addr + directory_entry->OffsetToData);
1250  E :        if (!data_entry.Set(resource_block, entry_addr)) {
1251  i :          LOG(ERROR) << "Unable to read the resource data entry.";
1252  i :          return false;
1253    :        }
1254    :        // The offsets in the data entries are RVAs.
1255  E :        if (!AddRelative(data_entry, &data_entry->OffsetToData)) {
1256  i :          LOG(ERROR) << "Failed to add resouce data reference.";
1257  i :          return false;
1258    :        }
1259    :      }
1260  E :      entry_offset += sizeof(IMAGE_RESOURCE_DIRECTORY_ENTRY);
1261  E :    }
1262    :  
1263  E :    return true;
1264  E :  }
1265    :  
1266    :  bool PEFileParser::AddReference(RelativeAddress src,
1267    :                                  BlockGraph::ReferenceType type,
1268    :                                  BlockGraph::Size size,
1269  E :                                  RelativeAddress dst) {
1270  E :    return add_reference_.Run(src, type, size, dst);
1271  E :  }
1272    :  
1273    :  BlockGraph::Block* PEFileParser::AddBlock(BlockGraph::BlockType type,
1274    :                                            RelativeAddress addr,
1275    :                                            BlockGraph::Size size,
1276  E :                                            const char* name) {
1277  E :    BlockGraph::Block* block = address_space_->AddBlock(type, addr, size, name);
1278  E :    if (block != NULL) {
1279  E :      block->set_attribute(BlockGraph::PE_PARSED);
1280    :  
1281    :      // Mark the source range from whence this block originates.
1282    :      bool pushed = block->source_ranges().Push(
1283    :          BlockGraph::Block::DataRange(0, size),
1284  E :          BlockGraph::Block::SourceRange(addr, size));
1285  E :      DCHECK(pushed);
1286    :  
1287    :      // Set the section for this block. We let blocks that belong to the header
1288    :      // be marked with kInvalidSectionId.
1289  E :      size_t section = image_file_.GetSectionIndex(addr, size);
1290  E :      if (section == BlockGraph::kInvalidSectionId) {
1291    :        // If no section was found for this block, we expect it to be a part of
1292    :        // the header.
1293    :        const RelativeAddress end_of_headers(
1294  E :            image_file_.nt_headers()->OptionalHeader.SizeOfHeaders);
1295  E :        if (addr + size > end_of_headers) {
1296  i :          LOG(ERROR) << "Found a non-header block outside of sections.";
1297  i :          return NULL;
1298    :        }
1299    :      }
1300  E :      block->set_section(section);
1301    :  
1302  E :      const uint8* data = image_file_.GetImageData(addr, size);
1303  E :      if (data != NULL)
1304  E :        block->SetData(data, size);
1305    :    }
1306    :  
1307  E :    return block;
1308  E :  }
1309    :  
1310    :  template <typename ItemType>
1311    :  bool PEFileParser::AddRelative(const PEFileStructPtr<ItemType>& structure,
1312  E :                                 const DWORD* item) {
1313  E :    DCHECK(item != NULL);
1314  E :    if (*item == 0)
1315  E :      return true;
1316    :  
1317    :    return AddReference(structure.AddressOf(item),
1318    :                        BlockGraph::RELATIVE_REF,
1319    :                        sizeof(*item),
1320  E :                        RelativeAddress(*item));
1321  E :  }
1322    :  
1323    :  template <typename ItemType>
1324    :  bool PEFileParser::AddAbsolute(const PEFileStructPtr<ItemType>& structure,
1325  E :                                 const DWORD* item) {
1326  E :    DCHECK(item != NULL);
1327  E :    if (*item == 0)
1328  E :      return true;
1329    :  
1330  E :    AbsoluteAddress abs(*item);
1331  E :    RelativeAddress rel;
1332    :  
1333    :    // We expect item to be the direct (0 offset) absolute address of the
1334    :    // in-image file structure. So, translation to an in-image relative
1335    :    // address is expected to yield a valid RVA.
1336    :    return image_file_.Translate(abs, &rel) &&
1337    :        AddReference(structure.AddressOf(item),
1338    :                     BlockGraph::ABSOLUTE_REF,
1339    :                     sizeof(*item),
1340  E :                     rel);
1341  E :  }
1342    :  
1343    :  template <typename ItemType>
1344    :  bool PEFileParser::AddFileOffset(const PEFileStructPtr<ItemType>& structure,
1345  E :                                   const DWORD* item) {
1346  E :    DCHECK(item != NULL);
1347  E :    if (*item == 0)
1348  i :      return true;
1349    :  
1350  E :    FileOffsetAddress offs(*item);
1351  E :    RelativeAddress rel;
1352    :  
1353    :    // We expect item to be the direct (0 offset) file offset address of the
1354    :    // in-image file structure. So, translation to an in-image relative
1355    :    // address is expected to yield a valid RVA.
1356    :    return image_file_.Translate(offs, &rel) &&
1357    :        AddReference(structure.AddressOf(item),
1358    :                     BlockGraph::FILE_OFFSET_REF,
1359    :                     sizeof(*item),
1360  E :                     rel);
1361  E :  }
1362    :  
1363    :  }  // namespace pe

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