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

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

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