Coverage for /Syzygy/instrument/transforms/thunk_import_references_transform.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
79.5%2022540.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/instrument/transforms/thunk_import_references_transform.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    :  #include <limits>
  22    :  
  23    :  #include "base/logging.h"
  24    :  #include "base/strings/string_util.h"
  25    :  #include "base/strings/stringprintf.h"
  26    :  #include "syzygy/block_graph/basic_block_assembler.h"
  27    :  #include "syzygy/block_graph/block_builder.h"
  28    :  #include "syzygy/block_graph/typed_block.h"
  29    :  #include "syzygy/common/defs.h"
  30    :  #include "syzygy/pe/pe_utils.h"
  31    :  
  32    :  namespace instrument {
  33    :  namespace transforms {
  34    :  
  35    :  namespace {
  36    :  
  37    :  using block_graph::BlockGraph;
  38    :  using block_graph::TypedBlock;
  39    :  using block_graph::ConstTypedBlock;
  40    :  
  41    :  // A simple struct that can be used to let us access strings using TypedBlock.
  42    :  struct StringStruct {
  43    :    const char string[1];
  44    :  };
  45    :  
  46    :  typedef BlockGraph::Offset Offset;
  47    :  typedef TypedBlock<IMAGE_DOS_HEADER> DosHeader;
  48    :  typedef TypedBlock<IMAGE_IMPORT_BY_NAME> ImageImportByName;
  49    :  typedef TypedBlock<IMAGE_IMPORT_DESCRIPTOR> ImageImportDescriptor;
  50    :  typedef TypedBlock<IMAGE_NT_HEADERS> NtHeaders;
  51    :  typedef TypedBlock<StringStruct> StringBlock;
  52    :  typedef TypedBlock<ImgDelayDescr> ImageDelayImportDescriptor;
  53    :  
  54    :  // We add this suffix to the destination
  55    :  const char kThunkSuffix[] = "_ImportThunk";
  56    :  const char kDelayThunkSuffix[] = "_DelayImportThunk";
  57    :  
  58    :  }  // namespace
  59    :  
  60    :  using pe::transforms::PEAddImportsTransform;
  61    :  using pe::transforms::ImportedModule;
  62    :  
  63    :  const char ThunkImportReferencesTransform::kTransformName[] =
  64    :      "ThunkImportReferencesTransform";
  65    :  
  66    :  const char ThunkImportReferencesTransform::kEntryHookName[] =
  67    :      "_indirect_penter";
  68    :  const char ThunkImportReferencesTransform::kDefaultInstrumentDll[] =
  69    :      "call_trace.dll";
  70    :  
  71    :  ThunkImportReferencesTransform::ThunkImportReferencesTransform()
  72    :      : thunk_section_(NULL),
  73  E :        instrument_dll_name_(kDefaultInstrumentDll) {
  74  E :  }
  75    :  
  76    :  bool ThunkImportReferencesTransform::TransformBlockGraph(
  77    :      const TransformPolicyInterface* policy,
  78    :      BlockGraph* block_graph,
  79  E :      BlockGraph::Block* header_block) {
  80  E :    DCHECK_NE(reinterpret_cast<TransformPolicyInterface*>(NULL), policy);
  81  E :    DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
  82  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), header_block);
  83  E :    DCHECK_EQ(BlockGraph::PE_IMAGE, block_graph->image_format());
  84  E :    DCHECK_EQ(reinterpret_cast<BlockGraph::Section*>(NULL), thunk_section_);
  85    :  
  86    :    // We always exclude our own agent DLL from instrumentation.
  87  E :    modules_to_exclude_.insert(instrument_dll_name_);
  88    :  
  89    :    // Start by finding or adding import entries for our instrumentation hook.
  90  E :    ImportedModule import_module(instrument_dll_name_);
  91    :    size_t hook_index = import_module.AddSymbol(
  92  E :        kEntryHookName, ImportedModule::kAlwaysImport);
  93    :  
  94  E :    add_imports_transform_.AddModule(&import_module);
  95    :  
  96    :    if (!add_imports_transform_.TransformBlockGraph(
  97  E :            policy, block_graph, header_block)) {
  98  i :      LOG(ERROR) << "Unable to add imports for instrumentation DLL.";
  99  i :      return false;
 100    :    }
 101    :  
 102  E :    if (!import_module.GetSymbolReference(hook_index, &hook_ref_)) {
 103  i :      LOG(ERROR) << "Unable to get import reference for hook.";
 104  i :      return false;
 105    :    }
 106    :  
 107  E :    ImportAddressLocationNameMap import_locations;
 108    :    if (!LookupImportLocations(modules_to_exclude_,
 109    :                               header_block,
 110  E :                               &import_locations)) {
 111  i :      LOG(ERROR) << "Unable to resolve import names and locations.";
 112  i :      return false;
 113    :    }
 114    :    if (!LookupDelayImportLocations(modules_to_exclude_,
 115    :                                    header_block,
 116  E :                                    &import_locations)) {
 117  i :      LOG(ERROR) << "Unable to resolve delay import names and locations.";
 118  i :      return false;
 119    :    }
 120    :  
 121    :    // Now instrument all the import locations we located.
 122  E :    if (!InstrumentImportReferences(block_graph, import_locations)) {
 123  i :      LOG(ERROR) << "Unable to instrument import references.";
 124  i :      return false;
 125    :    }
 126    :  
 127  E :    return true;
 128  E :  }
 129    :  
 130    :  void ThunkImportReferencesTransform::ExcludeModule(
 131  E :    const base::StringPiece& module_name) {
 132  E :    modules_to_exclude_.insert(module_name.as_string());
 133  E :  }
 134    :  
 135    :  bool ThunkImportReferencesTransform::ModuleNameLess::operator()(
 136  E :      const std::string& lhs, const std::string& rhs) const {
 137  E :    size_t len = std::min(lhs.size(), rhs.size());
 138  E :    for (size_t i = 0; i < len; ++i) {
 139  E :      char lhc = base::ToLowerASCII(lhs[i]);
 140  E :      char rhc = base::ToLowerASCII(rhs[i]);
 141  E :      if (lhc < rhc)
 142  E :        return true;
 143  E :      else if (lhc > rhc)
 144  E :        return false;
 145  E :    }
 146    :  
 147    :    // The strings are equal the end of the shorter string,
 148    :    // if the lhs is shorter it's smaller.
 149  E :    return lhs.size() < rhs.size();
 150  E :  }
 151    :  
 152    :  // This method builds up a set of thunk blocks as well as a thunk table
 153    :  // containing pointers to these blocks. Existing import references are then
 154    :  // replaced by references to the thunk table. Since imports are invoked via
 155    :  // an indirect call or jump instruction, changing the address of the call
 156    :  // statement from an address into the IAT to an address into the thunk table
 157    :  // gets the thunk called properly.
 158    :  bool ThunkImportReferencesTransform::InstrumentImportReferences(
 159    :      BlockGraph* block_graph,
 160  E :      const ImportAddressLocationNameMap& import_locations) {
 161    :    // Find or create the section we put our thunks in.
 162    :    thunk_section_ = block_graph->FindOrAddSection(common::kThunkSectionName,
 163  E :                                                   pe::kCodeCharacteristics);
 164  E :    if (thunk_section_ == NULL) {
 165  i :      LOG(ERROR) << "Unable to find or create .thunks section.";
 166  i :      return false;
 167    :    }
 168    :  
 169    :    // Find the set of blocks referred by import_locations.
 170  E :    BlockSet import_blocks;
 171  E :    if (!GetImportBlocks(import_locations, &import_blocks)) {
 172  i :      LOG(ERROR) << "Unable to get import blocks.";
 173  i :      return false;
 174    :    }
 175    :  
 176    :    // Typedef for the thunk block map. The key is the <iat block, offset> the
 177    :    // (since all callers can use the same thunk) and the value is the offset into
 178    :    // the thunk table that points to the thunk block for that IAT entry.
 179    :    typedef std::pair<const BlockGraph::Block*, BlockGraph::Offset>
 180    :        ThunkBlockKey;
 181    :    typedef std::map<ThunkBlockKey, BlockGraph::Offset> ThunkBlockMap;
 182  E :    ThunkBlockMap thunk_block_map;
 183    :  
 184    :    // Create the thunk table - we'll grow it as we go.
 185    :    BlockGraph::Block* thunk_table_block =
 186  E :        block_graph->AddBlock(BlockGraph::DATA_BLOCK, 0, "ImportsThunkTable");
 187  E :    thunk_table_block->set_section(thunk_section_->id());
 188  E :    BlockGraph::Offset thunk_table_offset = 0;
 189    :  
 190    :    // Now iterate through the import blocks and instrument the references.
 191  E :    BlockSet::const_iterator it = import_blocks.begin();
 192  E :    for (; it != import_blocks.end(); ++it) {
 193  E :      BlockGraph::Block* iat_block = *it;
 194    :  
 195    :      // Next, list all referrers to get all references into the IAT. For each
 196    :      // eligible reference, create a thunk (in its own block) and add a pointer
 197    :      // to it to the thunk table.
 198  E :      BlockGraph::Block::ReferrerSet iat_referrers(iat_block->referrers());
 199    :      BlockGraph::Block::ReferrerSet::const_iterator iat_referrer_iter(
 200  E :          iat_referrers.begin());
 201  E :      for (; iat_referrer_iter != iat_referrers.end(); ++iat_referrer_iter) {
 202  E :        BlockGraph::Block* referrer = iat_referrer_iter->first;
 203    :  
 204  E :        if (referrer == iat_block) {
 205  i :          LOG(WARNING) << "Unexpected self-reference in IAT.";
 206  i :          continue;
 207    :        }
 208    :  
 209  E :        if (referrer->type() != BlockGraph::CODE_BLOCK) {
 210    :          // We shouldn't see data referring to import table entries, outside
 211    :          // the PE structures.
 212  E :          DCHECK(referrer->attributes() & BlockGraph::PE_PARSED);
 213    :  
 214  E :          LOG(INFO) << "Skipping non-code block reference from block: '"
 215    :                    << referrer->name() << "'";
 216  E :          continue;
 217    :        }
 218    :  
 219  E :        if (referrer->attributes() & BlockGraph::THUNK) {
 220  E :          LOG(INFO) << "Skipping thunk block reference from block: '"
 221    :                    << referrer->name() << "'";
 222  E :          continue;
 223    :        }
 224    :  
 225    :        // Now that we know the referring block, we need to find out where in the
 226    :        // IAT it refers to.
 227  E :        BlockGraph::Reference ref;
 228  E :        if (!referrer->GetReference(iat_referrer_iter->second, &ref)) {
 229  i :          LOG(ERROR) << "Unable to get reference from referrer.";
 230  i :          return false;
 231    :        }
 232    :  
 233    :        // See whether this is an eligible import.
 234    :        ImportAddressLocationNameMap::const_iterator it(
 235    :            import_locations.find(
 236  E :                std::make_pair(ref.referenced(), ref.offset())));
 237  E :        if (it == import_locations.end()) {
 238    :          // It's not an eligible location, skip it.
 239  E :          continue;
 240    :        }
 241    :  
 242    :        // For now, let's not try and thunk thunks. This means that we can't
 243    :        // e.g. double-instrument, which is a potentially legitimate use case,
 244    :        // but it should only be supported if there's adequate testing for it.
 245  E :        if (referrer->section() == thunk_section_->id()) {
 246  i :          LOG(ERROR) << "Thunking a reference from the thunk section, "
 247    :                     << "in block: '" << referrer->name() << "'";
 248  i :          return false;
 249    :        }
 250    :  
 251    :        // Look for the reference in the thunk block map, and only create a
 252    :        // new one if it does not already exist.
 253  E :        BlockGraph::Block* thunk_block = NULL;
 254  E :        BlockGraph::Offset new_ref_offset = 0;
 255    :  
 256  E :        ThunkBlockKey key(std::make_pair(iat_block, ref.offset()));
 257  E :        ThunkBlockMap::const_iterator thunk_it = thunk_block_map.find(key);
 258  E :        if (thunk_it == thunk_block_map.end()) {
 259    :          // Create the thunk block for this offset into the IAT.
 260  E :          thunk_block = CreateOneThunk(block_graph, ref, it->second);
 261  E :          if (thunk_block == NULL) {
 262  i :            LOG(DFATAL) << "Unable to create thunk block.";
 263  i :            return false;
 264    :          }
 265    :  
 266    :          // Now add a reference to the thunk in the thunk table.
 267    :          BlockGraph::Reference thunk_ref(BlockGraph::ABSOLUTE_REF,
 268    :                                          sizeof(core::AbsoluteAddress),
 269  E :                                          thunk_block, 0, 0);
 270    :          thunk_table_block->set_size(
 271  E :              thunk_table_offset + sizeof(core::AbsoluteAddress));
 272  E :          thunk_table_block->SetReference(thunk_table_offset, thunk_ref);
 273    :  
 274    :          // Remember this thunk in case we need to use it again.
 275  E :          thunk_block_map[key] = thunk_table_offset;
 276  E :          new_ref_offset = thunk_table_offset;
 277    :  
 278    :          // Move to the next empty entry in the thunk table.
 279  E :          thunk_table_offset += sizeof(core::AbsoluteAddress);
 280    :          DCHECK_EQ(static_cast<BlockGraph::Size>(thunk_table_offset),
 281  E :                    thunk_table_block->size());
 282  E :        } else {
 283  E :          new_ref_offset = thunk_it->second;
 284    :        }
 285    :  
 286    :        // Update the referrer to point to the new location in the thunk table.
 287    :        BlockGraph::Reference new_ref(ref.type(),
 288    :                                      ref.size(),
 289    :                                      thunk_table_block,
 290    :                                      new_ref_offset,
 291  E :                                      0);
 292  E :        referrer->SetReference(iat_referrer_iter->second, new_ref);
 293  E :      }
 294  E :    }
 295    :  
 296  E :    return true;
 297  E :  }
 298    :  
 299    :  BlockGraph::Block* ThunkImportReferencesTransform::CreateOneThunk(
 300    :      BlockGraph* block_graph,
 301    :      const BlockGraph::Reference& destination,
 302  E :      const base::StringPiece& name) {
 303    :    using block_graph::BasicBlockSubGraph;
 304    :    using block_graph::BasicBlockAssembler;
 305    :    using block_graph::BasicCodeBlock;
 306    :    using block_graph::BlockBuilder;
 307    :    using block_graph::Operand;
 308    :    using block_graph::Displacement;
 309    :  
 310    :    // Construct the name for the new thunk.
 311  E :    std::string thunk_name(name.as_string());
 312  E :    thunk_name.append(kThunkSuffix);
 313    :  
 314    :    // Set up a basic block subgraph containing a single block description, with
 315    :    // that block description containing a single empty basic block, and get an
 316    :    // assembler writing into that basic block.
 317  E :    BasicBlockSubGraph bbsg;
 318    :    BasicBlockSubGraph::BlockDescription* block_desc = bbsg.AddBlockDescription(
 319    :        thunk_name,
 320    :        NULL,
 321    :        BlockGraph::CODE_BLOCK,
 322    :        thunk_section_->id(),
 323    :        1,
 324  E :        0);
 325  E :    BasicCodeBlock* bb = bbsg.AddBasicCodeBlock(name);
 326  E :    block_desc->basic_block_order.push_back(bb);
 327  E :    BasicBlockAssembler assm(bb->instructions().begin(), &bb->instructions());
 328    :  
 329    :    // The thunk contains this.
 330    :    // push  dword ptr [<import>]
 331    :    // jmp   dword ptr [<entry_hook>]
 332    :    assm.push(
 333  E :        Operand(Displacement(destination.referenced(), destination.offset())));
 334  E :    assm.jmp(Operand(Displacement(hook_ref_.referenced(), hook_ref_.offset())));
 335    :  
 336    :    // Condense into a block.
 337  E :    BlockBuilder block_builder(block_graph);
 338  E :    if (!block_builder.Merge(&bbsg)) {
 339  i :      LOG(ERROR) << "Failed to build thunk block.";
 340  i :      return NULL;
 341    :    }
 342    :  
 343    :    // Exactly one new block should have been created.
 344  E :    DCHECK_EQ(1u, block_builder.new_blocks().size());
 345  E :    BlockGraph::Block* thunk = block_builder.new_blocks().front();
 346    :  
 347  E :    return thunk;
 348  E :  }
 349    :  
 350    :  bool ThunkImportReferencesTransform::GetImportBlocks(
 351    :      const ImportAddressLocationNameMap& import_locations,
 352  E :      BlockSet* import_blocks) {
 353  E :    DCHECK(import_blocks != NULL);
 354    :  
 355  E :    ImportAddressLocationNameMap::const_iterator it;
 356  E :    BlockGraph::Block* last_block = NULL;
 357  E :    while (true) {
 358    :      it = import_locations.upper_bound(
 359  E :          std::make_pair(last_block, std::numeric_limits<Offset>::max()));
 360    :  
 361  E :      if (it == import_locations.end())
 362  E :        break;
 363    :  
 364  E :      last_block = it->first.first;
 365  E :      import_blocks->insert(last_block);
 366  E :    }
 367    :  
 368  E :    return true;
 369  E :  }
 370    :  
 371    :  bool ThunkImportReferencesTransform::LookupImportLocations(
 372    :      const ModuleNameSet& exclusions,
 373    :      BlockGraph::Block* header_block,
 374  E :      ImportAddressLocationNameMap* import_locations) {
 375  E :    DCHECK(header_block != NULL);
 376  E :    DCHECK(import_locations != NULL);
 377    :  
 378    :    // Start by retrieving the NT headers.
 379  E :    DosHeader dos_header;
 380  E :    NtHeaders nt_headers;
 381    :    if (!dos_header.Init(0, header_block) ||
 382  E :        !dos_header.Dereference(dos_header->e_lfanew, &nt_headers)) {
 383  i :      LOG(ERROR) << "Unable to cast image headers.";
 384  i :      return false;
 385    :    }
 386    :  
 387    :    // Get to the import directory.
 388    :    const IMAGE_DATA_DIRECTORY* import_directory =
 389  E :        &nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
 390    :  
 391  E :    ImageImportDescriptor iida;
 392  E :    if (!nt_headers.Dereference(import_directory->VirtualAddress, &iida)) {
 393  i :      LOG(ERROR) << "Failed to dereference Image Import Descriptor Array.";
 394  i :      return false;
 395    :    }
 396    :  
 397    :    // The array is NULL terminated with a potentially incomplete descriptor so
 398    :    // we can't use ElementCount - 1.
 399    :    size_t descriptor_count =
 400    :        (common::AlignUp(iida.block()->size(), sizeof(IMAGE_IMPORT_DESCRIPTOR)) /
 401  E :         sizeof(IMAGE_IMPORT_DESCRIPTOR)) - 1;
 402    :  
 403  E :    for (size_t iida_index = 0; iida_index < descriptor_count; ++iida_index) {
 404  E :      StringBlock dll_name_block;
 405  E :      if (!iida.Dereference(iida[iida_index].Name, &dll_name_block)) {
 406  i :        LOG(ERROR) << "Unable to dereference DLL name.";
 407  i :        return false;
 408    :      }
 409    :  
 410  E :      size_t len = strnlen(dll_name_block->string, dll_name_block.ElementCount());
 411  E :      std::string dll_name(dll_name_block->string, dll_name_block->string + len);
 412    :  
 413    :      // Move to the next one if this is an excluded module.
 414  E :      if (exclusions.find(dll_name) != exclusions.end())
 415  E :        continue;
 416    :  
 417    :      // Walk the IAT and the INT(also know as hna) for this module concurrently
 418    :      // until we come to a zero terminator for one or the other and mark their
 419    :      // offsets and names in the location names map.
 420  E :      TypedBlock<IMAGE_IMPORT_BY_NAME*> hna, iat;
 421    :      if (!iida.Dereference(iida[iida_index].OriginalFirstThunk, &hna) ||
 422  E :          !iida.Dereference(iida[iida_index].FirstThunk, &iat)) {
 423  i :        LOG(ERROR) << "Unable to dereference OriginalFirstThunk/FirstThunk.";
 424  i :        return false;
 425    :      }
 426    :  
 427    :      // Loop through the imports, tag and bag them.
 428  E :      size_t i = 0;
 429  E :      for (; i < hna.ElementCount() && i < iat.ElementCount(); ++i) {
 430  E :        ConstTypedBlock<IMAGE_THUNK_DATA32> thunk;
 431  E :        if (!thunk.Init(hna.OffsetOf(hna[i]), hna.block())) {
 432  i :          LOG(ERROR) << "Unable to dereference IMAGE_THUNK_DATA32.";
 433  i :          return false;
 434    :        }
 435    :  
 436    :        // Construct the location for this entry.
 437    :        ImportAddressLocation key(
 438  E :            std::make_pair(iat.block(), iat.OffsetOf(iat[i])));
 439  E :        std::string import_name = dll_name;
 440    :  
 441    :        // Is this an ordinal import?
 442  E :        if (IMAGE_SNAP_BY_ORDINAL(thunk->u1.Ordinal)) {
 443    :          // Ordinal imports are named <dll>:#<ordinal>.
 444    :          base::StringAppendF(&import_name,
 445    :                              ":#%d",
 446  E :                              IMAGE_ORDINAL(thunk->u1.Ordinal));
 447  E :        } else if (!thunk.HasReference(thunk->u1.AddressOfData)) {
 448    :          // Have no reference? Then terminate the iteration.
 449    :          // We sanity check that the actual data is null.
 450  E :          DCHECK_EQ(0u, thunk->u1.AddressOfData);
 451  E :          break;
 452  i :        } else {
 453    :          // Otherwise this should point to an IMAGE_IMPORT_BY_NAME structure.
 454  E :          ImageImportByName iibn;
 455  E :          if (!hna.Dereference(hna[i], &iibn)) {
 456  i :            LOG(ERROR) << "Unable to dereference IMAGE_IMPORT_BY_NAME.";
 457  i :            return false;
 458    :          }
 459    :          size_t len =
 460    :              strnlen(iibn->Name,
 461  E :                      iibn.block()->size() - iibn.OffsetOf(iibn->Name));
 462  E :          std::string function_name(iibn->Name, iibn->Name + len);
 463    :  
 464  E :          base::StringAppendF(&import_name, ":%s", function_name.c_str());
 465  E :        }
 466    :  
 467    :        // Tag and name it.
 468    :        bool inserted =
 469  E :            import_locations->insert(std::make_pair(key, import_name)).second;
 470    :  
 471  E :        DCHECK(inserted);
 472  E :      }
 473  E :    }
 474    :  
 475  E :    return true;
 476  E :  }
 477    :  
 478    :  bool ThunkImportReferencesTransform::LookupDelayImportLocations(
 479    :      const ModuleNameSet& exclusions,
 480    :      BlockGraph::Block* header_block,
 481  E :      ImportAddressLocationNameMap* import_locations) {
 482  E :    DCHECK(header_block != NULL);
 483  E :    DCHECK(import_locations != NULL);
 484    :  
 485    :    // Start by retrieving the NT headers.
 486  E :    DosHeader dos_header;
 487  E :    NtHeaders nt_headers;
 488    :    if (!dos_header.Init(0, header_block) ||
 489  E :        !dos_header.Dereference(dos_header->e_lfanew, &nt_headers)) {
 490  i :      LOG(ERROR) << "Unable to cast image headers.";
 491  i :      return false;
 492    :    }
 493    :  
 494    :    // Get to the delay import directory.
 495    :    const IMAGE_DATA_DIRECTORY* delay_import_directory =
 496    :        &nt_headers->OptionalHeader
 497  E :            .DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT];
 498    :  
 499  E :    ImageDelayImportDescriptor idida;
 500  E :    if (!nt_headers.Dereference(delay_import_directory->VirtualAddress, &idida)) {
 501    :      // Unable to dereference, this is only an error if there are delay imports.
 502  E :      if (!nt_headers.HasReference(delay_import_directory->VirtualAddress)) {
 503  E :        DCHECK_EQ(0U, delay_import_directory->VirtualAddress);
 504  E :        return true;
 505    :      }
 506    :  
 507  i :      LOG(ERROR) << "Failed to dereference delay Image Import Descriptor Array.";
 508  i :      return false;
 509    :    }
 510    :  
 511  E :    for (size_t idida_idx = 0; idida_idx < idida.ElementCount(); ++idida_idx) {
 512    :      // The last descriptor is a sentinel.
 513  E :      if (idida[idida_idx].grAttrs == 0)
 514  E :        break;
 515    :  
 516  E :      StringBlock dll_name_block;
 517  E :      if (!idida.Dereference(idida[idida_idx].rvaDLLName, &dll_name_block)) {
 518  i :        LOG(ERROR) << "Unable to dereference DLL name.";
 519  i :        return false;
 520    :      }
 521    :  
 522  E :      size_t len = strnlen(dll_name_block->string, dll_name_block.ElementCount());
 523  E :      std::string dll_name(dll_name_block->string, dll_name_block->string + len);
 524    :  
 525    :      // Move to the next one if this is an excluded module.
 526  E :      if (exclusions.find(dll_name) != exclusions.end())
 527  i :        continue;
 528    :  
 529    :      // Walk the IAT and the INT(also know as hna) for this module concurrently
 530    :      // until we come to a zero terminator for one or the other and mark their
 531    :      // offsets and names in the location names map.
 532  E :      TypedBlock<IMAGE_IMPORT_BY_NAME*> hna, iat;
 533    :      if (!idida.Dereference(idida[idida_idx].rvaINT, &hna) ||
 534  E :          !idida.Dereference(idida[idida_idx].rvaIAT, &iat)) {
 535  i :        LOG(ERROR) << "Unable to dereference OriginalFirstThunk/FirstThunk.";
 536  i :        return false;
 537    :      }
 538    :  
 539    :      // Loop through the imports, tag and bag them.
 540  E :      size_t i = 0;
 541  E :      for (; i < hna.ElementCount() && i < iat.ElementCount(); ++i) {
 542  E :        ConstTypedBlock<IMAGE_THUNK_DATA32> thunk;
 543  E :        if (!thunk.Init(hna.OffsetOf(hna[i]), hna.block())) {
 544  i :          LOG(ERROR) << "Unable to dereference IMAGE_THUNK_DATA32.";
 545  i :          return false;
 546    :        }
 547    :  
 548    :        // Construct the location for this entry.
 549    :        ImportAddressLocation key(
 550  E :            std::make_pair(iat.block(), iat.OffsetOf(iat[i])));
 551  E :        std::string import_name = dll_name;
 552    :  
 553    :        // Is this an ordinal import?
 554  E :        if (IMAGE_SNAP_BY_ORDINAL(thunk->u1.Ordinal)) {
 555    :          // Ordinal imports are named <dll>:#<ordinal>.
 556    :          base::StringAppendF(&import_name,
 557    :                              ":#%d",
 558  i :                              IMAGE_ORDINAL(thunk->u1.Ordinal));
 559  E :        } else if (!thunk.HasReference(thunk->u1.AddressOfData)) {
 560    :          // Have no reference? Then terminate the iteration.
 561    :          // We sanity check that the actual data is null.
 562  E :          DCHECK_EQ(0u, thunk->u1.AddressOfData);
 563  E :          break;
 564  i :        } else {
 565    :          // Otherwise this should point to an IMAGE_IMPORT_BY_NAME structure.
 566  E :          ImageImportByName iibn;
 567  E :          if (!hna.Dereference(hna[i], &iibn)) {
 568  i :            LOG(ERROR) << "Unable to dereference IMAGE_IMPORT_BY_NAME.";
 569  i :            return false;
 570    :          }
 571    :          size_t len =
 572    :              strnlen(iibn->Name,
 573  E :                      iibn.block()->size() - iibn.OffsetOf(iibn->Name));
 574  E :          std::string function_name(iibn->Name, iibn->Name + len);
 575    :  
 576  E :          base::StringAppendF(&import_name, ":%s", function_name.c_str());
 577  E :        }
 578    :  
 579    :        // Tag and name it.
 580    :        bool inserted =
 581  E :            import_locations->insert(std::make_pair(key, import_name)).second;
 582    :  
 583  E :        DCHECK(inserted);
 584  E :      }
 585  E :    }
 586    :  
 587  E :    return true;
 588  E :  }
 589    :  
 590    :  }  // namespace transforms
 591    :  }  // namespace instrument

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