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

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

Coverage information generated Wed Dec 11 11:34:16 2013.