Coverage for /Syzygy/pe/pe_file_parser.cc

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

Coverage information generated Thu Jan 14 17:40:38 2016.