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

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
90.4%6046680.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/asan_transform.h"
  16    :  
  17    :  #include <algorithm>
  18    :  #include <list>
  19    :  #include <vector>
  20    :  
  21    :  #include "base/logging.h"
  22    :  #include "base/rand_util.h"
  23    :  #include "base/memory/ref_counted.h"
  24    :  #include "base/memory/scoped_vector.h"
  25    :  #include "base/strings/string_util.h"
  26    :  #include "base/strings/stringprintf.h"
  27    :  #include "syzygy/block_graph/basic_block.h"
  28    :  #include "syzygy/block_graph/basic_block_assembler.h"
  29    :  #include "syzygy/block_graph/block_builder.h"
  30    :  #include "syzygy/block_graph/block_util.h"
  31    :  #include "syzygy/block_graph/typed_block.h"
  32    :  #include "syzygy/common/defs.h"
  33    :  #include "syzygy/instrument/transforms/asan_intercepts.h"
  34    :  #include "syzygy/pe/pe_utils.h"
  35    :  #include "syzygy/pe/transforms/coff_add_imports_transform.h"
  36    :  #include "syzygy/pe/transforms/coff_rename_symbols_transform.h"
  37    :  #include "syzygy/pe/transforms/pe_add_imports_transform.h"
  38    :  #include "third_party/distorm/files/include/mnemonics.h"
  39    :  #include "third_party/distorm/files/src/x86defs.h"
  40    :  
  41    :  namespace instrument {
  42    :  namespace transforms {
  43    :  namespace {
  44    :  
  45    :  using block_graph::BasicBlock;
  46    :  using block_graph::BasicCodeBlock;
  47    :  using block_graph::BasicBlockAssembler;
  48    :  using block_graph::BasicBlockSubGraph;
  49    :  using block_graph::BasicBlockReference;
  50    :  using block_graph::BlockBuilder;
  51    :  using block_graph::BlockGraph;
  52    :  using block_graph::Displacement;
  53    :  using block_graph::Immediate;
  54    :  using block_graph::Instruction;
  55    :  using block_graph::Operand;
  56    :  using block_graph::TransformPolicyInterface;
  57    :  using block_graph::TypedBlock;
  58    :  using block_graph::analysis::LivenessAnalysis;
  59    :  using block_graph::analysis::MemoryAccessAnalysis;
  60    :  using assm::Register32;
  61    :  using pe::transforms::CoffAddImportsTransform;
  62    :  using pe::transforms::ImportedModule;
  63    :  using pe::transforms::PEAddImportsTransform;
  64    :  
  65    :  // A simple struct that can be used to let us access strings using TypedBlock.
  66    :  struct StringStruct {
  67    :    const char string[1];
  68    :  };
  69    :  
  70    :  typedef AsanBasicBlockTransform::MemoryAccessMode AsanMemoryAccessMode;
  71    :  typedef AsanBasicBlockTransform::AsanHookMap HookMap;
  72    :  typedef std::vector<AsanBasicBlockTransform::AsanHookMapEntryKey>
  73    :      AccessHookParamVector;
  74    :  typedef TypedBlock<IMAGE_IMPORT_DESCRIPTOR> ImageImportDescriptor;
  75    :  typedef TypedBlock<StringStruct> String;
  76    :  
  77    :  // The timestamp 1 corresponds to Thursday, 01 Jan 1970 00:00:01 GMT. Setting
  78    :  // the timestamp of the image import descriptor to this value allows us to
  79    :  // temporarily bind the library until the loader finishes loading this module.
  80    :  // As the value is far in the past this means that the entries in the IAT for
  81    :  // this module will all be replaced by pointers into the actual library.
  82    :  // We need to bind the IAT for our module to make sure the stub is used until
  83    :  // the sandbox lets the loader finish patching the IAT entries.
  84    :  static const size_t kDateInThePast = 1;
  85    :  
  86    :  // Returns true iff opcode should be instrumented.
  87  E :  bool ShouldInstrumentOpcode(uint16 opcode) {
  88  E :    switch (opcode) {
  89    :      // LEA does not actually access memory.
  90    :      case I_LEA:
  91  E :        return false;
  92    :  
  93    :      // We can ignore the prefetch and clflush instructions. The instrumentation
  94    :      // will detect memory errors if and when the memory is actually accessed.
  95    :      case I_CLFLUSH:
  96    :      case I_PREFETCH:
  97    :      case I_PREFETCHNTA:
  98    :      case I_PREFETCHT0:
  99    :      case I_PREFETCHT1:
 100    :      case I_PREFETCHT2:
 101    :      case I_PREFETCHW:
 102  i :        return false;
 103    :    }
 104  E :    return true;
 105  E :  }
 106    :  
 107    :  // Computes the correct displacement, if any, for operand
 108    :  // number @p operand of @p instr.
 109    :  BasicBlockAssembler::Displacement ComputeDisplacementForOperand(
 110  E :      const Instruction& instr, size_t operand) {
 111  E :    const _DInst& repr = instr.representation();
 112    :  
 113    :    DCHECK(repr.ops[operand].type == O_SMEM ||
 114  E :           repr.ops[operand].type == O_MEM);
 115    :  
 116  E :    size_t access_size_bytes = repr.ops[operand].size / 8;
 117  E :    if (repr.dispSize == 0)
 118  E :      return Displacement(access_size_bytes - 1);
 119    :  
 120  E :    BasicBlockReference reference;
 121  E :    if (instr.FindOperandReference(operand, &reference)) {
 122  E :      if (reference.referred_type() == BasicBlockReference::REFERRED_TYPE_BLOCK) {
 123    :        return Displacement(reference.block(),
 124  E :                            reference.offset() + access_size_bytes - 1);
 125  i :      } else {
 126  E :        return Displacement(reference.basic_block());
 127    :      }
 128  i :    } else {
 129  E :      return Displacement(repr.disp + access_size_bytes - 1);
 130    :    }
 131  E :  }
 132    :  
 133    :  // Returns true if operand @p op is instrumentable, e.g.
 134    :  // if it implies a memory access.
 135  E :  bool IsInstrumentable(const _Operand& op) {
 136  E :    switch (op.type) {
 137    :      case O_SMEM:
 138    :      case O_MEM:
 139  E :        return true;
 140    :  
 141    :      default:
 142  E :        return false;
 143    :    }
 144  E :  }
 145    :  
 146    :  // Returns true if opcode @p opcode is a special instruction.
 147    :  // Memory checks for special instructions (string instructions, instructions
 148    :  // with prefix, etc) are handled by calling specialized functions rather than
 149    :  // the standard memory checks.
 150  E :  bool IsSpecialInstruction(uint16_t opcode) {
 151  E :    switch (opcode) {
 152    :      case I_CMPS:
 153    :      case I_STOS:
 154    :      case I_MOVS:
 155  E :        return true;
 156    :  
 157    :      default:
 158  E :        return false;
 159    :    }
 160  E :  }
 161    :  
 162    :  // Decodes the first O_MEM or O_SMEM operand of @p instr, if any to the
 163    :  // corresponding Operand.
 164    :  bool DecodeMemoryAccess(const Instruction& instr,
 165    :      BasicBlockAssembler::Operand* access,
 166  E :      AsanBasicBlockTransform::MemoryAccessInfo* info) {
 167  E :    DCHECK(access != NULL);
 168  E :    DCHECK(info != NULL);
 169  E :    const _DInst& repr = instr.representation();
 170    :  
 171    :    // Figure out which operand we're instrumenting.
 172  E :    size_t mem_op_id = -1;
 173  E :    if (IsInstrumentable(repr.ops[0]) && IsInstrumentable(repr.ops[1])) {
 174    :      // This happens with instructions like: MOVS [EDI], [ESI].
 175  E :      DCHECK(repr.ops[0].size == repr.ops[1].size);
 176  E :      mem_op_id = 0;
 177  E :    } else if (IsInstrumentable(repr.ops[0])) {
 178    :      // The first operand is instrumentable.
 179  E :      mem_op_id = 0;
 180  E :    } else if (IsInstrumentable(repr.ops[1])) {
 181    :      // The second operand is instrumentable.
 182  E :      mem_op_id = 1;
 183  E :    } else {
 184    :      // Neither of the first two operands is instrumentable.
 185  E :      return false;
 186    :    }
 187    :  
 188    :    // Determine the size of the access.
 189  E :    info->size = repr.ops[mem_op_id].size / 8;
 190    :  
 191    :    // Determine the kind of access (read/write/instr/repz).
 192  E :    if (FLAG_GET_PREFIX(repr.flags) & FLAG_REPNZ) {
 193  i :      info->mode = AsanBasicBlockTransform::kRepnzAccess;
 194  E :    } else if (FLAG_GET_PREFIX(repr.flags) & FLAG_REP) {
 195  E :      info->mode = AsanBasicBlockTransform::kRepzAccess;
 196  E :    } else if (IsSpecialInstruction(instr.opcode())) {
 197  E :      info->mode = AsanBasicBlockTransform::kInstrAccess;
 198  E :    } else if ((repr.flags & FLAG_DST_WR) && mem_op_id == 0) {
 199    :      // The first operand is written to.
 200  E :      info->mode = AsanBasicBlockTransform::kWriteAccess;
 201  E :    } else {
 202  E :      info->mode = AsanBasicBlockTransform::kReadAccess;
 203    :    }
 204    :  
 205    :    // Determine the opcode of this instruction (when needed).
 206    :    if (info->mode == AsanBasicBlockTransform::kRepnzAccess ||
 207    :        info->mode == AsanBasicBlockTransform::kRepzAccess ||
 208  E :        info->mode == AsanBasicBlockTransform::kInstrAccess) {
 209  E :      info->opcode = instr.opcode();
 210    :    }
 211    :  
 212    :    // Determine operand of the access.
 213  E :    if (repr.ops[mem_op_id].type == O_SMEM) {
 214    :      // Simple memory dereference with optional displacement.
 215    :      const Register32& base_reg = assm::CastAsRegister32(
 216  E :          core::GetRegister(repr.ops[mem_op_id].index));
 217    :  
 218    :      // Get the displacement for the operand.
 219  E :      auto displ = ComputeDisplacementForOperand(instr, mem_op_id);
 220  E :      *access = Operand(base_reg, displ);
 221  E :    } else if (repr.ops[0].type == O_MEM || repr.ops[1].type == O_MEM) {
 222    :      // Complex memory dereference.
 223    :      const Register32& index_reg = assm::CastAsRegister32(
 224  E :          core::GetRegister(repr.ops[mem_op_id].index));
 225    :  
 226  E :      assm::ScaleFactor scale = assm::kTimes1;
 227  E :      switch (repr.scale) {
 228    :        case 2:
 229  E :          scale = assm::kTimes2;
 230  E :          break;
 231    :        case 4:
 232  E :          scale = assm::kTimes4;
 233  E :          break;
 234    :        case 8:
 235  E :          scale = assm::kTimes8;
 236    :          break;
 237    :        default:
 238    :          break;
 239    :      }
 240    :  
 241    :      // Get the displacement for the operand (if any).
 242  E :      auto displ = ComputeDisplacementForOperand(instr, mem_op_id);
 243    :  
 244    :      // Compute the full operand.
 245  E :      if (repr.base != R_NONE) {
 246    :        const Register32& base_reg = assm::CastAsRegister32(
 247  E :            core::GetRegister(repr.base));
 248    :  
 249  E :        if (displ.size() == assm::kSizeNone) {
 250    :          // No displacement, it's a [base + index * scale] access.
 251  i :          *access = Operand(base_reg, index_reg, scale);
 252  i :        } else {
 253    :          // This is a [base + index * scale + displ] access.
 254  E :          *access = Operand(base_reg, index_reg, scale, displ);
 255    :        }
 256  E :      } else {
 257    :        // No base, this is an [index * scale + displ] access.
 258    :        // TODO(siggi): AFAIK, there's no encoding for [index * scale] without
 259    :        //    a displacement. If this assert fires, I'm proven wrong.
 260  E :        DCHECK_NE(assm::kSizeNone, displ.size());
 261    :  
 262  E :        *access = Operand(index_reg, scale, displ);
 263    :      }
 264  E :    } else {
 265  i :      NOTREACHED();
 266  i :      return false;
 267    :    }
 268    :  
 269  E :    return true;
 270  E :  }
 271    :  
 272    :  // Use @p bb_asm to inject a hook to @p hook to instrument the access to the
 273    :  // address stored in the operand @p op.
 274    :  void InjectAsanHook(BasicBlockAssembler* bb_asm,
 275    :                      const AsanBasicBlockTransform::MemoryAccessInfo& info,
 276    :                      const BasicBlockAssembler::Operand& op,
 277    :                      BlockGraph::Reference* hook,
 278    :                      const LivenessAnalysis::State& state,
 279  E :                      BlockGraph::ImageFormat image_format) {
 280  E :    DCHECK(hook != NULL);
 281    :  
 282    :    // Determine which kind of probe to inject.
 283    :    //   - The standard load/store probe assume the address is in EDX.
 284    :    //     It restore the original version of EDX and cleanup the stack.
 285    :    //   - The special instruction probe take addresses directly in registers.
 286    :    //     The probe doesn't have any effects on stack, registers and flags.
 287    :    if (info.mode == AsanBasicBlockTransform::kReadAccess ||
 288  E :        info.mode == AsanBasicBlockTransform::kWriteAccess) {
 289    :      // Load/store probe.
 290  E :      bb_asm->push(assm::edx);
 291  E :      bb_asm->lea(assm::edx, op);
 292    :    }
 293    :  
 294    :    // Call the hook.
 295  E :    if (image_format == BlockGraph::PE_IMAGE) {
 296    :      // In PE images the hooks are brought in as imports, so they are indirect
 297    :      // references.
 298  E :      bb_asm->call(Operand(Displacement(hook->referenced(), hook->offset())));
 299  E :    } else {
 300  E :      DCHECK_EQ(BlockGraph::COFF_IMAGE, image_format);
 301    :      // In COFF images the hooks are brought in as symbols, so they are direct
 302    :      // references.
 303  E :      bb_asm->call(Immediate(hook->referenced(), hook->offset()));
 304    :    }
 305  E :  }
 306    :  
 307    :  // Get the name of an asan check access function for an @p access_mode access.
 308    :  // @param info The memory access information, e.g. the size on a load/store,
 309    :  //     the instruction opcode and the kind of access.
 310    :  std::string GetAsanCheckAccessFunctionName(
 311    :      AsanBasicBlockTransform::MemoryAccessInfo info,
 312  E :      BlockGraph::ImageFormat image_format) {
 313  E :    DCHECK(info.mode != AsanBasicBlockTransform::kNoAccess);
 314  E :    DCHECK_NE(0U, info.size);
 315    :    DCHECK(info.mode == AsanBasicBlockTransform::kReadAccess ||
 316    :           info.mode == AsanBasicBlockTransform::kWriteAccess ||
 317  E :           info.opcode != 0);
 318    :  
 319  E :    const char* rep_str = NULL;
 320  E :    if (info.mode == AsanBasicBlockTransform::kRepzAccess)
 321  E :      rep_str = "_repz";
 322  E :    else if (info.mode == AsanBasicBlockTransform::kRepnzAccess)
 323  i :      rep_str = "_repnz";
 324  i :    else
 325  E :      rep_str = "";
 326    :  
 327  E :    const char* access_mode_str = NULL;
 328  E :    if (info.mode == AsanBasicBlockTransform::kReadAccess)
 329  E :      access_mode_str = "read";
 330  E :    else if (info.mode == AsanBasicBlockTransform::kWriteAccess)
 331  E :      access_mode_str = "write";
 332  E :    else
 333  E :      access_mode_str = reinterpret_cast<char*>(GET_MNEMONIC_NAME(info.opcode));
 334    :  
 335    :    // For COFF images we use the decorated function name, which contains a
 336    :    // leading underscore.
 337    :    std::string function_name =
 338    :        base::StringPrintf("%sasan_check%s_%d_byte_%s_access%s",
 339    :                           image_format == BlockGraph::PE_IMAGE ? "" : "_",
 340    :                           rep_str,
 341    :                           info.size,
 342    :                           access_mode_str,
 343  E :                           info.save_flags ? "" : "_no_flags");
 344  E :    StringToLowerASCII(&function_name);
 345  E :    return function_name;
 346  E :  }
 347    :  
 348    :  // Add imports from the specified module to the block graph, altering the
 349    :  // contents of its header/special blocks.
 350    :  // @param policy the policy object restricting how the transform is applied.
 351    :  // @param block_graph the block graph to modify.
 352    :  // @param header_block the header block of @p block_graph.
 353    :  // @param module the module to import, with its symbols.
 354    :  // @returns true on success, or false on failure.
 355    :  bool AddImportsFromModule(const TransformPolicyInterface* policy,
 356    :                            BlockGraph* block_graph,
 357    :                            BlockGraph::Block* header_block,
 358  E :                            ImportedModule* module) {
 359  E :    if (block_graph->image_format() == BlockGraph::PE_IMAGE) {
 360  E :      PEAddImportsTransform transform;
 361  E :      transform.AddModule(module);
 362    :      if (!ApplyBlockGraphTransform(&transform, policy,
 363  E :                                    block_graph, header_block)) {
 364  i :        return false;
 365    :      }
 366  E :    } else {
 367  E :      DCHECK_EQ(BlockGraph::COFF_IMAGE, block_graph->image_format());
 368  E :      CoffAddImportsTransform transform;
 369  E :      transform.AddModule(module);
 370    :      if (!ApplyBlockGraphTransform(&transform, policy,
 371  E :                                    block_graph, header_block)) {
 372  i :        return false;
 373    :      }
 374  E :    }
 375    :  
 376  E :    return true;
 377  E :  }
 378    :  
 379    :  // Add the imports for the asan check access hooks to the block-graph.
 380    :  // @param hooks_param_vector A vector of hook parameter values.
 381    :  // @param default_stub_map Stubs for the asan check access functions.
 382    :  // @param import_module The module for which the import should be added.
 383    :  // @param check_access_hook_map The map where the reference to the imports
 384    :  //     should be stored.
 385    :  // @param policy The policy object restricting how the transform is applied.
 386    :  // @param block_graph The block-graph to populate.
 387    :  // @param header_block The block containing the module's DOS header of this
 388    :  //     block-graph.
 389    :  // @returns True on success, false otherwise.
 390    :  bool AddAsanCheckAccessHooks(
 391    :      const AccessHookParamVector& hook_param_vector,
 392    :      const AsanBasicBlockTransform::AsanDefaultHookMap& default_stub_map,
 393    :      ImportedModule* import_module,
 394    :      HookMap* check_access_hook_map,
 395    :      const TransformPolicyInterface* policy,
 396    :      BlockGraph* block_graph,
 397  E :      BlockGraph::Block* header_block) {
 398  E :    DCHECK(import_module != NULL);
 399  E :    DCHECK(check_access_hook_map != NULL);
 400  E :    DCHECK(policy != NULL);
 401  E :    DCHECK(block_graph != NULL);
 402  E :    DCHECK(header_block != NULL);
 403    :  
 404    :    typedef std::map<AsanBasicBlockTransform::AsanHookMapEntryKey, size_t>
 405    :        HooksParamsToIdxMap;
 406  E :    HooksParamsToIdxMap hooks_params_to_idx;
 407    :  
 408    :    // Add the hooks to the import module.
 409  E :    AccessHookParamVector::const_iterator iter_params = hook_param_vector.begin();
 410  E :    for (; iter_params != hook_param_vector.end(); ++iter_params) {
 411    :      size_t symbol_idx = import_module->AddSymbol(
 412    :          GetAsanCheckAccessFunctionName(*iter_params,
 413    :                                         block_graph->image_format()),
 414  E :          ImportedModule::kAlwaysImport);
 415  E :      hooks_params_to_idx[*iter_params] = symbol_idx;
 416  E :    }
 417    :  
 418  E :    DCHECK_EQ(hooks_params_to_idx.size(), hook_param_vector.size());
 419    :  
 420    :    // Add the imports. This takes care of invoking the appropriate format
 421    :    // specific transform.
 422  E :    if (!AddImportsFromModule(policy, block_graph, header_block, import_module)) {
 423  i :      LOG(ERROR) << "Unable to add imports for Asan instrumentation DLL.";
 424  i :      return false;
 425    :    }
 426    :  
 427    :    // Get a reference to each hook and put it in the hooks map.
 428  E :    HooksParamsToIdxMap::iterator iter_hooks = hooks_params_to_idx.begin();
 429  E :    for (; iter_hooks != hooks_params_to_idx.end(); ++iter_hooks) {
 430  E :      BlockGraph::Reference import_reference;
 431    :      if (!import_module->GetSymbolReference(iter_hooks->second,
 432  E :                                             &import_reference)) {
 433  i :        LOG(ERROR) << "Unable to get import reference for Asan.";
 434  i :        return false;
 435    :      }
 436  E :      HookMap& hook_map = *check_access_hook_map;
 437  E :      hook_map[iter_hooks->first] = import_reference;
 438    :  
 439    :      // We only need dummy implementation stubs for PE images, as the hooks are
 440    :      // imported. COFF instrumented images contain the hooks directly.
 441  E :      if (block_graph->image_format() == BlockGraph::PE_IMAGE) {
 442    :        // In a Chrome sandboxed process the NtMapViewOfSection function is
 443    :        // intercepted by the sandbox agent. This causes execution in the
 444    :        // executable before imports have been resolved, as the ntdll patch
 445    :        // invokes into the executable while resolving imports. As the Asan
 446    :        // instrumentation directly refers to the IAT entries we need to
 447    :        // temporarily stub these function until the Asan imports are resolved. To
 448    :        // do this we need to make the IAT entries for those functions point to a
 449    :        // temporarily block and we need to mark the image import descriptor for
 450    :        // this DLL as bound.
 451    :        AsanBasicBlockTransform::AsanDefaultHookMap::const_iterator
 452  E :            stub_reference = default_stub_map.find(iter_hooks->first.mode);
 453  E :        if (stub_reference == default_stub_map.end()) {
 454  i :           LOG(ERROR) << "Could not find the default hook for "
 455    :                      << GetAsanCheckAccessFunctionName(iter_hooks->first,
 456    :                                                        BlockGraph::PE_IMAGE)
 457    :                      << ".";
 458  i :          return false;
 459    :        }
 460    :  
 461    :        import_reference.referenced()->SetReference(import_reference.offset(),
 462  E :                                                    stub_reference->second);
 463    :      }
 464  E :    }
 465    :  
 466  E :    return true;
 467  E :  }
 468    :  
 469    :  // Create a stub for the asan_check_access functions. For load/store, the stub
 470    :  // consists of a small block of code that restores the value of EDX and returns
 471    :  // to the caller. Otherwise, the stub do return.
 472    :  // @param block_graph The block-graph to populate with the stub.
 473    :  // @param stub_name The stub's name.
 474    :  // @param mode The kind of memory access.
 475    :  // @param reference Will receive the reference to the created hook.
 476    :  // @returns true on success, false otherwise.
 477    :  bool CreateHooksStub(BlockGraph* block_graph,
 478    :                       const base::StringPiece& stub_name,
 479    :                       AsanBasicBlockTransform::MemoryAccessMode mode,
 480  E :                       BlockGraph::Reference* reference) {
 481  E :    DCHECK(reference != NULL);
 482    :  
 483    :    // Find or create the section we put our thunks in.
 484    :    BlockGraph::Section* thunk_section = block_graph->FindOrAddSection(
 485  E :        common::kThunkSectionName, pe::kCodeCharacteristics);
 486    :  
 487  E :    if (thunk_section == NULL) {
 488  i :      LOG(ERROR) << "Unable to find or create .thunks section.";
 489  i :      return false;
 490    :    }
 491    :  
 492    :    std::string stub_name_with_id = base::StringPrintf(
 493  E :        "%.*s%d", stub_name.length(), stub_name.data(), mode);
 494    :  
 495    :    // Create the thunk for standard "load/store" (received address in EDX).
 496  E :    BasicBlockSubGraph bbsg;
 497    :    BasicBlockSubGraph::BlockDescription* block_desc = bbsg.AddBlockDescription(
 498    :        stub_name_with_id,
 499    :        thunk_section->name(),
 500    :        BlockGraph::CODE_BLOCK,
 501    :        thunk_section->id(),
 502    :        1,
 503  E :        0);
 504    :  
 505  E :    BasicCodeBlock* bb = bbsg.AddBasicCodeBlock(stub_name_with_id);
 506  E :    block_desc->basic_block_order.push_back(bb);
 507  E :    BasicBlockAssembler assm(bb->instructions().begin(), &bb->instructions());
 508    :  
 509    :    if (mode == AsanBasicBlockTransform::kReadAccess ||
 510  E :        mode == AsanBasicBlockTransform::kWriteAccess) {
 511    :      // The thunk body restores the original value of EDX and cleans the stack on
 512    :      // return.
 513  E :      assm.mov(assm::edx, Operand(assm::esp, Displacement(4)));
 514  E :      assm.ret(4);
 515  E :    } else {
 516  E :      assm.ret();
 517    :    }
 518    :  
 519    :    // Condense into a block.
 520  E :    BlockBuilder block_builder(block_graph);
 521  E :    if (!block_builder.Merge(&bbsg)) {
 522  i :      LOG(ERROR) << "Failed to build thunk block.";
 523  i :      return NULL;
 524    :    }
 525    :  
 526    :    // Exactly one new block should have been created.
 527  E :    DCHECK_EQ(1u, block_builder.new_blocks().size());
 528  E :    BlockGraph::Block* thunk = block_builder.new_blocks().front();
 529    :  
 530  E :    *reference = BlockGraph::Reference(BlockGraph::ABSOLUTE_REF, 4, thunk, 0, 0);
 531    :  
 532  E :    return true;
 533  E :  }
 534    :  
 535    :  // Since MSVS 2012 the implementation of the CRT _heap_init function has changed
 536    :  // and as a result the CRT defers all its allocation to the process heap.
 537    :  //
 538    :  // As we don't want to replace the process heap by an Asan heap we need to patch
 539    :  // this function to make it use ::HeapCreate instead of ::GetProcessHeap. We
 540    :  // can't simply intercept it like we do for the other functions because we need
 541    :  // to update the value of the _crtheap variable, adding an export for it will
 542    :  // make the instrumentation agent depend on the instrumented image.
 543    :  //
 544    :  // Here's the assembly code that we're injecting to replace this function.
 545    :  //
 546    :  // push    0
 547    :  // push    1000h
 548    :  // push    0
 549    :  // call    syzyasan_rtl!asan_HeapCreate
 550    :  // mov     dword ptr [module!crt_heap], eax
 551    :  // mov     eax,1
 552    :  // ret
 553    :  //
 554    :  // TODO(sebmarchand): Also patch the _heap_term function. This function isn't
 555    :  //     always present and is just used to reset the crt_heap pointer and free
 556    :  //     the underlying heap. This isn't so important in this case because it only
 557    :  //     happen when the process terminate and the heap will be automatically
 558    :  //     freed when we unload the SyzyAsan agent DLL.
 559    :  //
 560    :  // @param block_graph The block-graph to populate with the stub.
 561    :  // @param header_block the header block of @p block_graph.
 562    :  // @param policy the policy object restricting how the transform is applied.
 563    :  // @returns true on success, false otherwise.
 564    :  bool PatchCRTHeapInitialization(BlockGraph* block_graph,
 565    :                                  BlockGraph::Block* header_block,
 566  E :                                  const TransformPolicyInterface* policy) {
 567  E :    DCHECK_NE(static_cast<BlockGraph*>(nullptr), block_graph);
 568  E :    DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), header_block);
 569  E :    DCHECK_NE(static_cast<const TransformPolicyInterface*>(nullptr), policy);
 570    :  
 571    :    // The original _heap_init block.
 572  E :    BlockGraph::Block* heap_init_block = nullptr;
 573    :    // The data block to _crtheap.
 574  E :    BlockGraph::Block* crtheap_block = nullptr;
 575    :  
 576  E :    for (auto& iter : block_graph->blocks_mutable()) {
 577  E :      if (::strcmp(iter.second.name().c_str(), "_heap_init") == 0) {
 578  E :        DCHECK_EQ(static_cast<BlockGraph::Block*>(nullptr), heap_init_block);
 579  E :         heap_init_block = &(iter.second);
 580  E :      } else if (::strcmp(iter.second.name().c_str(), "_crtheap") == 0) {
 581  E :        DCHECK_EQ(static_cast<BlockGraph::Block*>(nullptr), crtheap_block);
 582  E :        crtheap_block = &(iter.second);
 583    :      }
 584    :  
 585  E :      if (heap_init_block != nullptr && crtheap_block != nullptr)
 586  E :        break;
 587  E :    }
 588    :  
 589  E :    if (heap_init_block == nullptr || crtheap_block == nullptr)
 590  E :      return true;
 591    :  
 592    :    // Find or create the section we put our thunks in.
 593    :    BlockGraph::Section* thunk_section = block_graph->FindOrAddSection(
 594  E :        common::kThunkSectionName, pe::kCodeCharacteristics);
 595    :  
 596  E :    if (thunk_section == NULL) {
 597  i :      LOG(ERROR) << "Unable to find or create .thunks section.";
 598  i :      return false;
 599    :    }
 600    :  
 601    :    // Find the asan_HeapCreate import.
 602  E :    PEAddImportsTransform find_imports;
 603  E :    ImportedModule kernel32_module(AsanTransform::kSyzyAsanDll);
 604  E :    kernel32_module.AddSymbol("asan_HeapCreate", ImportedModule::kAlwaysImport);
 605  E :    find_imports.AddModule(&kernel32_module);
 606  E :    if (!find_imports.TransformBlockGraph(policy, block_graph, header_block)) {
 607  i :      LOG(ERROR) << "Unable to find the asan_HeapCreate import.";
 608  i :      return false;
 609    :    }
 610  E :    BlockGraph::Reference heap_create_ref;
 611  E :    CHECK(kernel32_module.GetSymbolReference(0, &heap_create_ref));
 612    :  
 613  E :    std::string stub_name = "asan_heap_init";
 614  E :    BasicBlockSubGraph bbsg;
 615    :    BasicBlockSubGraph::BlockDescription* block_desc = bbsg.AddBlockDescription(
 616    :        stub_name,
 617    :        thunk_section->name(),
 618    :        BlockGraph::CODE_BLOCK,
 619    :        thunk_section->id(),
 620    :        1,
 621  E :        0);
 622    :  
 623  E :    BasicCodeBlock* bb = bbsg.AddBasicCodeBlock(stub_name);
 624  E :    block_desc->basic_block_order.push_back(bb);
 625  E :    BasicBlockAssembler assm(bb->instructions().begin(), &bb->instructions());
 626  E :    assm.push(Immediate(0U, assm::kSize32Bit));
 627  E :    assm.push(Immediate(0x1000U, assm::kSize32Bit));
 628  E :    assm.push(Immediate(0U, assm::kSize32Bit));
 629    :    assm.call(Operand(Displacement(heap_create_ref.referenced(),
 630  E :                                   heap_create_ref.offset())));
 631  E :    assm.mov(Operand(Displacement(crtheap_block, 0U)), assm::eax);
 632  E :    assm.mov(assm::eax, Immediate(1U));
 633  E :    assm.ret();
 634    :  
 635    :    // Condense into a block.
 636  E :    BlockBuilder block_builder(block_graph);
 637  E :    if (!block_builder.Merge(&bbsg)) {
 638  i :      LOG(ERROR) << "Failed to build thunk block.";
 639  i :      return NULL;
 640    :    }
 641    :  
 642    :    // Exactly one new block should have been created.
 643  E :    DCHECK_EQ(1u, block_builder.new_blocks().size());
 644  E :    BlockGraph::Block* heap_init_thunk = block_builder.new_blocks().front();
 645    :  
 646    :    heap_init_block->TransferReferrers(0U, heap_init_thunk,
 647  E :        BlockGraph::Block::kTransferInternalReferences);
 648    :  
 649    :    if (!heap_init_block->RemoveAllReferences() ||
 650  E :        !block_graph->RemoveBlock(heap_init_block)) {
 651  i :      LOG(ERROR) << "Unable to remove the original _heap_init block.";
 652  i :      return false;
 653    :    }
 654    :  
 655  E :    return true;
 656  E :  }
 657    :  
 658    :  typedef std::map<std::string, size_t> ImportNameIndexMap;
 659    :  
 660    :  bool PeFindImportsToIntercept(bool use_interceptors,
 661    :                                const AsanIntercept* intercepts,
 662    :                                const TransformPolicyInterface* policy,
 663    :                                BlockGraph* block_graph,
 664    :                                BlockGraph::Block* header_block,
 665    :                                ScopedVector<ImportedModule>* imported_modules,
 666    :                                ImportNameIndexMap* import_name_index_map,
 667  E :                                ImportedModule* asan_rtl) {
 668  E :    DCHECK_NE(reinterpret_cast<AsanIntercept*>(NULL), intercepts);
 669  E :    DCHECK_NE(reinterpret_cast<TransformPolicyInterface*>(NULL), policy);
 670  E :    DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
 671  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), header_block);
 672    :    DCHECK_NE(reinterpret_cast<ScopedVector<ImportedModule>*>(NULL),
 673  E :              imported_modules);
 674  E :    DCHECK_NE(reinterpret_cast<ImportNameIndexMap*>(NULL), import_name_index_map);
 675  E :    DCHECK_NE(reinterpret_cast<ImportedModule*>(NULL), asan_rtl);
 676    :  
 677    :    // Process all of the import intercepts.
 678  E :    PEAddImportsTransform find_imports;
 679  E :    ImportedModule* current_module = NULL;
 680  E :    const char* current_module_name = NULL;
 681  E :    const AsanIntercept* intercept = intercepts;
 682  E :    for (; intercept->undecorated_name != NULL; ++intercept) {
 683    :      // Create a new module to house these imports.
 684  E :      if (intercept->module != current_module_name) {
 685  E :        current_module_name = intercept->module;
 686  E :        current_module = NULL;
 687  E :        if (current_module_name) {
 688  E :          current_module = new ImportedModule(current_module_name);
 689  E :          imported_modules->push_back(current_module);
 690  E :          find_imports.AddModule(current_module);
 691    :        }
 692    :      }
 693    :  
 694    :      // If no module name is specified then this interception is not an import
 695    :      // interception.
 696  E :      if (current_module_name == NULL)
 697  E :        continue;
 698    :  
 699    :      // Don't process optional intercepts unless asked to.
 700  E :      if (!use_interceptors && intercept->optional)
 701  E :        continue;
 702    :  
 703    :      current_module->AddSymbol(intercept->undecorated_name,
 704  E :                                ImportedModule::kFindOnly);
 705  E :    }
 706    :  
 707    :    // Query the imports to see which ones are present.
 708  E :    if (!find_imports.TransformBlockGraph(policy, block_graph, header_block)) {
 709  i :      LOG(ERROR) << "Unable to find imports for redirection.";
 710  i :      return false;
 711    :    }
 712    :  
 713    :    // Add Asan imports for those functions found in the import tables. These will
 714    :    // later be redirected.
 715  E :    for (const auto& module : *imported_modules) {
 716  E :      for (size_t i = 0; i < module->size(); ++i) {
 717  E :        if (!module->SymbolIsImported(i))
 718  E :          continue;
 719    :  
 720    :        // The function should not already be imported. If it is then the
 721    :        // intercepts data contains duplicates.
 722  E :        const std::string& function_name = module->GetSymbolName(i);
 723  E :        DCHECK(import_name_index_map->find(function_name) ==
 724    :                   import_name_index_map->end());
 725    :  
 726  E :        std::string asan_function_name = kUndecoratedAsanInterceptPrefix;
 727  E :        asan_function_name += function_name;
 728    :        size_t index = asan_rtl->AddSymbol(asan_function_name,
 729  E :                                           ImportedModule::kAlwaysImport);
 730  E :        import_name_index_map->insert(std::make_pair(function_name, index));
 731  E :      }
 732  E :    }
 733    :  
 734  E :    return true;
 735  E :  }
 736    :  
 737    :  void PeFindStaticallyLinkedFunctionsToIntercept(
 738    :      bool use_interceptors,
 739    :      const AsanIntercept* intercepts,
 740    :      BlockGraph* block_graph,
 741    :      std::vector<BlockGraph::Block*>* static_blocks,
 742    :      ImportNameIndexMap* import_name_index_map,
 743  E :      ImportedModule* asan_rtl) {
 744  E :    DCHECK_NE(reinterpret_cast<AsanIntercept*>(NULL), intercepts);
 745  E :    DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
 746    :    DCHECK_NE(reinterpret_cast<std::vector<BlockGraph::Block*>*>(NULL),
 747  E :              static_blocks);
 748  E :    DCHECK_NE(reinterpret_cast<ImportNameIndexMap*>(NULL), import_name_index_map);
 749  E :    DCHECK_NE(reinterpret_cast<ImportedModule*>(NULL), asan_rtl);
 750    :  
 751    :    // Populate the filter with known hashes.
 752  E :    AsanInterceptorFilter filter;
 753  E :    filter.InitializeContentHashes(intercepts, use_interceptors);
 754  E :    if (filter.empty())
 755  E :      return;
 756    :  
 757    :    // Discover statically linked functions that need to be intercepted.
 758    :    BlockGraph::BlockMap::iterator block_it =
 759  E :        block_graph->blocks_mutable().begin();
 760  E :    for (; block_it != block_graph->blocks_mutable().end(); ++block_it) {
 761  E :      BlockGraph::Block* block = &block_it->second;
 762  E :      if (!filter.ShouldIntercept(block))
 763  E :        continue;
 764  E :      static_blocks->push_back(block);
 765    :  
 766    :      // Don't add an import entry for names that have already been processed.
 767    :      if (import_name_index_map->find(block->name()) !=
 768  E :              import_name_index_map->end()) {
 769  i :        continue;
 770    :      }
 771    :  
 772  E :      std::string name = kUndecoratedAsanInterceptPrefix;
 773  E :      name += block->name();
 774    :      size_t index = asan_rtl->AddSymbol(name,
 775  E :                                        ImportedModule::kAlwaysImport);
 776  E :      import_name_index_map->insert(std::make_pair(block->name(), index));
 777  E :    }
 778  E :  }
 779    :  
 780    :  void PeGetRedirectsForInterceptedImports(
 781    :      const ScopedVector<ImportedModule>& imported_modules,
 782    :      const ImportNameIndexMap& import_name_index_map,
 783    :      const ImportedModule& asan_rtl,
 784  E :      pe::ReferenceMap* reference_redirect_map) {
 785  E :    DCHECK_NE(reinterpret_cast<pe::ReferenceMap*>(NULL), reference_redirect_map);
 786    :  
 787    :    // Register redirections related to the original.
 788  E :    for (const auto& module : imported_modules) {
 789  E :      for (size_t j = 0; j < module->size(); ++j) {
 790  E :        if (!module->SymbolIsImported(j))
 791  E :          continue;
 792    :  
 793    :        // Get a reference to the original import.
 794  E :        BlockGraph::Reference src;
 795  E :        CHECK(module->GetSymbolReference(j, &src));
 796    :  
 797    :        // Get a reference to the newly created import.
 798  E :        const std::string& name = module->GetSymbolName(j);
 799    :        ImportNameIndexMap::const_iterator import_it =
 800  E :            import_name_index_map.find(name);
 801  E :        DCHECK(import_it != import_name_index_map.end());
 802  E :        BlockGraph::Reference dst;
 803  E :        CHECK(asan_rtl.GetSymbolReference(import_it->second, &dst));
 804    :  
 805    :        // Record the reference mapping.
 806    :        reference_redirect_map->insert(
 807    :            std::make_pair(pe::ReferenceDest(src.referenced(), src.offset()),
 808  E :                           pe::ReferenceDest(dst.referenced(), dst.offset())));
 809  E :      }
 810  E :    }
 811  E :  }
 812    :  
 813    :  bool PeGetRedirectsForStaticallyLinkedFunctions(
 814    :      const std::vector<BlockGraph::Block*>& static_blocks,
 815    :      const ImportNameIndexMap& import_name_index_map,
 816    :      const ImportedModule& asan_rtl,
 817    :      BlockGraph* block_graph,
 818  E :      pe::ReferenceMap* reference_redirect_map) {
 819  E :    DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
 820  E :    DCHECK_NE(reinterpret_cast<pe::ReferenceMap*>(NULL), reference_redirect_map);
 821    :  
 822    :    BlockGraph::Section* thunk_section = block_graph->FindOrAddSection(
 823  E :        common::kThunkSectionName, pe::kCodeCharacteristics);
 824  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Section*>(NULL), thunk_section);
 825    :  
 826    :    typedef std::map<std::string, BlockGraph::Block*> ThunkMap;
 827  E :    ThunkMap thunk_map;
 828  E :    for (size_t i = 0; i < static_blocks.size(); ++i) {
 829  E :      BlockGraph::Block* block = static_blocks[i];
 830    :  
 831  E :      ThunkMap::iterator thunk_it = thunk_map.find(block->name());
 832  E :      if (thunk_it == thunk_map.end()) {
 833    :        // Generate the name of the thunk for this function.
 834  E :        std::string thunk_name = kUndecoratedAsanInterceptPrefix;
 835  E :        thunk_name += block->name();
 836  E :        thunk_name += "_thunk";
 837    :  
 838    :        // Get a reference to the newly created import.
 839    :        ImportNameIndexMap::const_iterator import_it =
 840  E :            import_name_index_map.find(block->name());
 841  E :        DCHECK(import_it != import_name_index_map.end());
 842  E :        BlockGraph::Reference import_ref;
 843  E :        CHECK(asan_rtl.GetSymbolReference(import_it->second, &import_ref));
 844    :  
 845    :        // Generate a basic code block for this thunk.
 846  E :        BasicBlockSubGraph bbsg;
 847    :        BasicBlockSubGraph::BlockDescription* block_desc =
 848    :            bbsg.AddBlockDescription(thunk_name,
 849    :                                     thunk_section->name(),
 850    :                                     BlockGraph::CODE_BLOCK,
 851    :                                     thunk_section->id(),
 852    :                                     1,
 853  E :                                     0);
 854    :  
 855  E :        BasicCodeBlock* bb = bbsg.AddBasicCodeBlock(thunk_name);
 856  E :        block_desc->basic_block_order.push_back(bb);
 857    :        BasicBlockAssembler assm(bb->instructions().begin(),
 858  E :                                 &bb->instructions());
 859    :        assm.jmp(Operand(Displacement(import_ref.referenced(),
 860  E :                                      import_ref.offset())));
 861    :  
 862    :        // Condense into a block.
 863  E :        BlockBuilder block_builder(block_graph);
 864  E :        if (!block_builder.Merge(&bbsg)) {
 865  i :          LOG(ERROR) << "Failed to build thunk block \"" << thunk_name << "\".";
 866  i :          return false;
 867    :        }
 868    :  
 869    :        // Exactly one new block should have been created.
 870  E :        DCHECK_EQ(1u, block_builder.new_blocks().size());
 871  E :        BlockGraph::Block* thunk = block_builder.new_blocks().front();
 872  E :        thunk_it = thunk_map.insert(std::make_pair(block->name(), thunk)).first;
 873  E :      }
 874  E :      DCHECK(thunk_it != thunk_map.end());
 875    :  
 876    :      // Register a redirection of references, from the original block to the
 877    :      // newly created thunk.
 878    :      reference_redirect_map->insert(std::make_pair(
 879    :          pe::ReferenceDest(block, 0),
 880  E :          pe::ReferenceDest(thunk_it->second, 0)));
 881  E :    }
 882    :  
 883  E :    return true;
 884  E :  }
 885    :  
 886    :  }  // namespace
 887    :  
 888    :  const char AsanBasicBlockTransform::kTransformName[] =
 889    :      "SyzyAsanBasicBlockTransform";
 890    :  
 891    :  bool AsanBasicBlockTransform::InstrumentBasicBlock(
 892    :      BasicCodeBlock* basic_block,
 893    :      StackAccessMode stack_mode,
 894  E :      BlockGraph::ImageFormat image_format) {
 895  E :    DCHECK_NE(reinterpret_cast<BasicCodeBlock*>(NULL), basic_block);
 896    :  
 897  E :    if (instrumentation_rate_ == 0.0)
 898  E :      return true;
 899    :  
 900    :    // Pre-compute liveness information for each instruction.
 901  E :    std::list<LivenessAnalysis::State> states;
 902  E :    LivenessAnalysis::State state;
 903  E :    if (use_liveness_analysis_) {
 904  E :      liveness_.GetStateAtExitOf(basic_block, &state);
 905    :  
 906    :      BasicBlock::Instructions::reverse_iterator rev_iter_inst =
 907  E :          basic_block->instructions().rbegin();
 908    :      BasicBlock::Instructions::const_reverse_iterator rev_iter_inst_end =
 909  E :          basic_block->instructions().rend();
 910  E :      for (; rev_iter_inst != rev_iter_inst_end; ++rev_iter_inst) {
 911  E :        const Instruction& instr = *rev_iter_inst;
 912  E :        liveness_.PropagateBackward(instr, &state);
 913  E :        states.push_front(state);
 914  E :      }
 915    :  
 916  E :      DCHECK_EQ(states.size(), basic_block->instructions().size());
 917    :    }
 918    :  
 919    :    // Get the memory accesses information for this basic block.
 920  E :    MemoryAccessAnalysis::State memory_state;
 921  E :    if (remove_redundant_checks_)
 922  E :      memory_accesses_.GetStateAtEntryOf(basic_block, &memory_state);
 923    :  
 924    :    // Process each instruction and inject a call to Asan when we find an
 925    :    // instrumentable memory access.
 926    :    BasicBlock::Instructions::iterator iter_inst =
 927  E :        basic_block->instructions().begin();
 928  E :    std::list<LivenessAnalysis::State>::iterator iter_state = states.begin();
 929  E :    for (; iter_inst != basic_block->instructions().end(); ++iter_inst) {
 930  E :      auto operand(Operand(assm::eax));
 931  E :      const Instruction& instr = *iter_inst;
 932  E :      const _DInst& repr = instr.representation();
 933    :  
 934    :      MemoryAccessInfo info;
 935  E :      info.mode = kNoAccess;
 936  E :      info.size = 0;
 937  E :      info.opcode = 0;
 938  E :      info.save_flags = true;
 939    :  
 940    :      // Get current instruction liveness information.
 941  E :      if (use_liveness_analysis_) {
 942  E :        state = *iter_state;
 943  E :        ++iter_state;
 944    :      }
 945    :  
 946    :      // When activated, skip redundant memory access check.
 947  E :      if (remove_redundant_checks_) {
 948  E :        bool need_memory_access_check = false;
 949  E :        if (memory_state.HasNonRedundantAccess(instr))
 950  E :          need_memory_access_check = true;
 951    :  
 952    :        // Update the memory accesses information for the current instruction.
 953  E :        memory_accesses_.PropagateForward(instr, &memory_state);
 954    :  
 955  E :        if (!need_memory_access_check)
 956  E :          continue;
 957    :      }
 958    :  
 959    :      // Insert hook for a standard instruction.
 960  E :      if (!DecodeMemoryAccess(instr, &operand, &info))
 961  E :        continue;
 962    :  
 963    :      // Bail if this is not a memory access.
 964  E :      if (info.mode == kNoAccess)
 965  i :        continue;
 966    :  
 967    :      // A basic block reference means that can be either a computed jump,
 968    :      // or a load from a case table. In either case it doesn't make sense
 969    :      // to instrument the access.
 970    :      if (operand.displacement().reference().referred_type() ==
 971  E :          BasicBlockReference::REFERRED_TYPE_BASIC_BLOCK) {
 972  E :        continue;
 973    :      }
 974    :  
 975    :      // A block reference means this instruction is reading or writing to
 976    :      // a global variable or some such. It's viable to pad and align global
 977    :      // variables and to red-zone the padding, but without that, there's nothing
 978    :      // to gain by instrumenting these accesses.
 979    :      if (operand.displacement().reference().referred_type() ==
 980  E :          BasicBlockReference::REFERRED_TYPE_BLOCK) {
 981  E :        continue;
 982    :      }
 983    :  
 984    :      // Is this an instruction we should be instrumenting.
 985  E :      if (!ShouldInstrumentOpcode(repr.opcode))
 986  E :        continue;
 987    :  
 988    :      // If there are no unconventional manipulations of the stack frame, we can
 989    :      // skip instrumenting stack-based memory access (based on ESP or EBP).
 990    :      // Conventionally, accesses through ESP/EBP are always on stack.
 991    :      if (stack_mode == kSafeStackAccess &&
 992    :          (operand.base() == assm::kRegisterEsp ||
 993  E :           operand.base() == assm::kRegisterEbp)) {
 994  E :        continue;
 995    :      }
 996    :  
 997    :      // We do not instrument memory accesses through special segments.
 998    :      // FS is used for thread local specifics and GS for CPU info.
 999  E :      uint8_t segment = SEGMENT_GET(repr.segment);
1000  E :      if (segment == R_FS || segment == R_GS)
1001  E :        continue;
1002    :  
1003    :      // Don't instrument any filtered instructions.
1004  E :      if (IsFiltered(*iter_inst))
1005  E :        continue;
1006    :  
1007    :      // Randomly sample to effect partial instrumentation.
1008    :      if (instrumentation_rate_ < 1.0 &&
1009  E :          base::RandDouble() >= instrumentation_rate_) {
1010  E :        continue;
1011    :      }
1012    :  
1013    :      // Create a BasicBlockAssembler to insert new instruction.
1014  E :      BasicBlockAssembler bb_asm(iter_inst, &basic_block->instructions());
1015    :  
1016    :      // Configure the assembler to copy the SourceRange information of the
1017    :      // current instrumented instruction into newly created instructions. This is
1018    :      // a hack to allow valid stack walking and better error reporting, but
1019    :      // breaks the 1:1 OMAP mapping and may confuse some debuggers.
1020  E :      if (debug_friendly_)
1021  E :        bb_asm.set_source_range(instr.source_range());
1022    :  
1023    :      if (use_liveness_analysis_ &&
1024  E :          (info.mode == kReadAccess || info.mode == kWriteAccess)) {
1025    :        // Use the liveness information to skip saving the flags if possible.
1026  E :        info.save_flags = state.AreArithmeticFlagsLive();
1027    :      }
1028    :  
1029    :      // Mark that an instrumentation will happen. Do this before selecting a
1030    :      // hook so we can call a dry run without hooks present.
1031  E :      instrumentation_happened_ = true;
1032    :  
1033  E :      if (!dry_run_) {
1034    :        // Insert hook for standard instructions.
1035  E :        AsanHookMap::iterator hook = check_access_hooks_->find(info);
1036  E :        if (hook == check_access_hooks_->end()) {
1037  i :          LOG(ERROR) << "Invalid access : "
1038    :                     << GetAsanCheckAccessFunctionName(info, image_format);
1039  i :          return false;
1040    :        }
1041    :  
1042    :        // Instrument this instruction.
1043    :        InjectAsanHook(
1044  E :            &bb_asm, info, operand, &hook->second, state, image_format);
1045    :      }
1046    :  
1047  E :    }
1048    :  
1049  E :    DCHECK(iter_state == states.end());
1050    :  
1051  E :    return true;
1052  E :  }
1053    :  
1054    :  void AsanBasicBlockTransform::set_instrumentation_rate(
1055  E :      double instrumentation_rate) {
1056    :    // Set the instrumentation rate, capping it between 0 and 1.
1057  E :    instrumentation_rate_ = std::max(0.0, std::min(1.0, instrumentation_rate));
1058  E :  }
1059    :  
1060    :  bool AsanBasicBlockTransform::TransformBasicBlockSubGraph(
1061    :      const TransformPolicyInterface* policy,
1062    :      BlockGraph* block_graph,
1063  E :      BasicBlockSubGraph* subgraph) {
1064  E :    DCHECK(policy != NULL);
1065  E :    DCHECK(block_graph != NULL);
1066  E :    DCHECK(subgraph != NULL);
1067    :  
1068    :    // Perform a global liveness analysis.
1069  E :    if (use_liveness_analysis_)
1070  E :      liveness_.Analyze(subgraph);
1071    :  
1072    :    // Perform a redundant memory access analysis.
1073  E :    if (remove_redundant_checks_)
1074  E :      memory_accesses_.Analyze(subgraph);
1075    :  
1076    :    // Determines if this subgraph uses unconventional stack pointer
1077    :    // manipulations.
1078  E :    StackAccessMode stack_mode = kUnsafeStackAccess;
1079  E :    if (!block_graph::HasUnexpectedStackFrameManipulation(subgraph))
1080  E :      stack_mode = kSafeStackAccess;
1081    :  
1082    :    // Iterates through each basic block and instruments it.
1083    :    BasicBlockSubGraph::BBCollection::iterator it =
1084  E :        subgraph->basic_blocks().begin();
1085  E :    for (; it != subgraph->basic_blocks().end(); ++it) {
1086  E :      BasicCodeBlock* bb = BasicCodeBlock::Cast(*it);
1087    :      if (bb != NULL &&
1088  E :          !InstrumentBasicBlock(bb, stack_mode, block_graph->image_format())) {
1089  i :        return false;
1090    :      }
1091  E :    }
1092  E :    return true;
1093  E :  }
1094    :  
1095    :  const char AsanTransform::kTransformName[] = "SyzyAsanTransform";
1096    :  
1097    :  const char AsanTransform::kAsanHookStubName[] = "asan_hook_stub";
1098    :  
1099    :  const char AsanTransform::kSyzyAsanDll[] = "syzyasan_rtl.dll";
1100    :  
1101    :  AsanTransform::AsanTransform()
1102    :      : asan_dll_name_(kSyzyAsanDll),
1103    :        debug_friendly_(false),
1104    :        use_liveness_analysis_(false),
1105    :        remove_redundant_checks_(false),
1106    :        use_interceptors_(false),
1107    :        instrumentation_rate_(1.0),
1108    :        asan_parameters_(NULL),
1109    :        check_access_hooks_ref_(),
1110  E :        asan_parameters_block_(NULL) {
1111  E :  }
1112    :  
1113  E :  void AsanTransform::set_instrumentation_rate(double instrumentation_rate) {
1114    :    // Set the instrumentation rate, capping it between 0 and 1.
1115  E :    instrumentation_rate_ = std::max(0.0, std::min(1.0, instrumentation_rate));
1116  E :  }
1117    :  
1118    :  bool AsanTransform::PreBlockGraphIteration(
1119    :      const TransformPolicyInterface* policy,
1120    :      BlockGraph* block_graph,
1121  E :      BlockGraph::Block* header_block) {
1122  E :    DCHECK_NE(reinterpret_cast<TransformPolicyInterface*>(NULL), policy);
1123  E :    DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
1124  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), header_block);
1125    :    DCHECK(block_graph->image_format() == BlockGraph::PE_IMAGE ||
1126  E :           block_graph->image_format() == BlockGraph::COFF_IMAGE);
1127    :  
1128    :    // Ensure that this image has not already been instrumented.
1129  E :    if (block_graph->FindSection(common::kThunkSectionName)) {
1130  i :      LOG(ERROR) << "The image is already instrumented.";
1131  i :      return false;
1132    :    }
1133    :  
1134  E :    AccessHookParamVector access_hook_param_vec;
1135  E :    AsanBasicBlockTransform::AsanDefaultHookMap default_stub_map;
1136    :  
1137    :    // We only need to add stubs for PE images. COFF images use direct references,
1138    :    // and the linker takes care of dragging in the appropriate code for us.
1139  E :    if (block_graph->image_format() == BlockGraph::PE_IMAGE) {
1140    :      // Create the hook stub for read/write instructions.
1141  E :      BlockGraph::Reference read_write_hook;
1142    :      if (!CreateHooksStub(block_graph, kAsanHookStubName,
1143    :                           AsanBasicBlockTransform::kReadAccess,
1144  E :                           &read_write_hook)) {
1145  i :        return false;
1146    :      }
1147    :  
1148    :      // Create the hook stub for strings instructions.
1149  E :      BlockGraph::Reference instr_hook;
1150    :      if (!CreateHooksStub(block_graph, kAsanHookStubName,
1151    :                           AsanBasicBlockTransform::kInstrAccess,
1152  E :                           &instr_hook)) {
1153  i :        return false;
1154    :      }
1155    :  
1156    :      // Map each memory access kind to an appropriate stub.
1157  E :      default_stub_map[AsanBasicBlockTransform::kReadAccess] = read_write_hook;
1158  E :      default_stub_map[AsanBasicBlockTransform::kWriteAccess] = read_write_hook;
1159  E :      default_stub_map[AsanBasicBlockTransform::kInstrAccess] = instr_hook;
1160  E :      default_stub_map[AsanBasicBlockTransform::kRepzAccess] = instr_hook;
1161  E :      default_stub_map[AsanBasicBlockTransform::kRepnzAccess] = instr_hook;
1162    :    }
1163    :  
1164    :    // Add an import entry for the Asan runtime.
1165  E :    ImportedModule import_module(asan_dll_name_, kDateInThePast);
1166    :  
1167    :    // Import the hooks for the read/write accesses.
1168  E :    for (int access_size = 1; access_size <= 32; access_size *= 2) {
1169    :      MemoryAccessInfo read_info =
1170  E :          { AsanBasicBlockTransform::kReadAccess, access_size, 0, true };
1171  E :      access_hook_param_vec.push_back(read_info);
1172  E :      if (use_liveness_analysis()) {
1173  E :        read_info.save_flags = false;
1174  E :        access_hook_param_vec.push_back(read_info);
1175    :      }
1176    :  
1177    :      MemoryAccessInfo write_info =
1178  E :          { AsanBasicBlockTransform::kWriteAccess, access_size, 0, true };
1179  E :      access_hook_param_vec.push_back(write_info);
1180  E :      if (use_liveness_analysis()) {
1181  E :        write_info.save_flags = false;
1182  E :        access_hook_param_vec.push_back(write_info);
1183    :      }
1184  E :    }
1185    :  
1186    :    // Import the hooks for the read/write 10-bytes accesses.
1187    :    MemoryAccessInfo read_info_10 =
1188  E :        { AsanBasicBlockTransform::kReadAccess, 10, 0, true };
1189  E :    access_hook_param_vec.push_back(read_info_10);
1190  E :    if (use_liveness_analysis()) {
1191  E :      read_info_10.save_flags = false;
1192  E :      access_hook_param_vec.push_back(read_info_10);
1193    :    }
1194    :  
1195    :    MemoryAccessInfo write_info_10 =
1196  E :        { AsanBasicBlockTransform::kWriteAccess, 10, 0, true };
1197  E :    access_hook_param_vec.push_back(write_info_10);
1198  E :    if (use_liveness_analysis()) {
1199  E :      write_info_10.save_flags = false;
1200  E :      access_hook_param_vec.push_back(write_info_10);
1201    :    }
1202    :  
1203    :    // Import the hooks for strings/prefix memory accesses.
1204  E :    const _InstructionType strings[] = { I_CMPS, I_MOVS, I_STOS };
1205  E :    int strings_length = sizeof(strings)/sizeof(_InstructionType);
1206    :  
1207  E :    for (int access_size = 1; access_size <= 4; access_size *= 2) {
1208  E :      for (int inst = 0; inst < strings_length; ++inst) {
1209    :        MemoryAccessInfo repz_inst_info = {
1210    :           AsanBasicBlockTransform::kRepzAccess,
1211    :           access_size,
1212    :           strings[inst],
1213    :           true
1214  E :        };
1215  E :        access_hook_param_vec.push_back(repz_inst_info);
1216    :  
1217    :        MemoryAccessInfo inst_info = {
1218    :            AsanBasicBlockTransform::kInstrAccess,
1219    :            access_size,
1220    :            strings[inst],
1221    :            true
1222  E :        };
1223  E :        access_hook_param_vec.push_back(inst_info);
1224  E :      }
1225  E :    }
1226    :  
1227    :    if (!AddAsanCheckAccessHooks(access_hook_param_vec,
1228    :                                 default_stub_map,
1229    :                                 &import_module,
1230    :                                 &check_access_hooks_ref_,
1231    :                                 policy,
1232    :                                 block_graph,
1233  E :                                 header_block)) {
1234  i :      return false;
1235    :    }
1236  E :    return true;
1237  E :  }
1238    :  
1239    :  bool AsanTransform::OnBlock(const TransformPolicyInterface* policy,
1240    :                              BlockGraph* block_graph,
1241  E :                              BlockGraph::Block* block) {
1242  E :    DCHECK(policy != NULL);
1243  E :    DCHECK(block_graph != NULL);
1244  E :    DCHECK(block != NULL);
1245    :  
1246  E :    if (!policy->BlockIsSafeToBasicBlockDecompose(block))
1247  E :      return true;
1248    :  
1249    :    // Use the filter that was passed to us for our child transform.
1250  E :    AsanBasicBlockTransform transform(&check_access_hooks_ref_);
1251  E :    transform.set_debug_friendly(debug_friendly());
1252  E :    transform.set_use_liveness_analysis(use_liveness_analysis());
1253  E :    transform.set_remove_redundant_checks(remove_redundant_checks());
1254  E :    transform.set_filter(filter());
1255  E :    transform.set_instrumentation_rate(instrumentation_rate_);
1256    :  
1257    :    if (!ApplyBasicBlockSubGraphTransform(
1258  E :            &transform, policy, block_graph, block, NULL)) {
1259  i :      return false;
1260    :    }
1261    :  
1262  E :    return true;
1263  E :  }
1264    :  
1265    :  bool AsanTransform::PostBlockGraphIteration(
1266    :      const TransformPolicyInterface* policy,
1267    :      BlockGraph* block_graph,
1268  E :      BlockGraph::Block* header_block) {
1269  E :    DCHECK(policy != NULL);
1270  E :    DCHECK(block_graph != NULL);
1271  E :    DCHECK(header_block != NULL);
1272    :  
1273  E :    if (block_graph->image_format() == BlockGraph::PE_IMAGE) {
1274    :      if (!PeInterceptFunctions(kAsanIntercepts, policy, block_graph,
1275  E :                                header_block)) {
1276  i :        return false;
1277    :      }
1278    :  
1279  E :      if (!PeInjectAsanParameters(policy, block_graph, header_block))
1280  i :        return false;
1281  E :    } else {
1282  E :      DCHECK_EQ(BlockGraph::COFF_IMAGE, block_graph->image_format());
1283    :      if (!CoffInterceptFunctions(kAsanIntercepts, policy, block_graph,
1284  E :                                  header_block)) {
1285  i :        return false;
1286    :      }
1287    :    }
1288    :  
1289  E :    if (!PatchCRTHeapInitialization(block_graph, header_block, policy))
1290  i :      return false;
1291    :  
1292  E :    return true;
1293  E :  }
1294    :  
1295    :  bool AsanTransform::PeInterceptFunctions(
1296    :      const AsanIntercept* intercepts,
1297    :      const TransformPolicyInterface* policy,
1298    :      BlockGraph* block_graph,
1299  E :      BlockGraph::Block* header_block) {
1300  E :    DCHECK_NE(reinterpret_cast<AsanIntercept*>(NULL), intercepts);
1301  E :    DCHECK_NE(reinterpret_cast<TransformPolicyInterface*>(NULL), policy);
1302  E :    DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
1303  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), header_block);
1304  E :    DCHECK_EQ(BlockGraph::PE_IMAGE, block_graph->image_format());
1305    :  
1306    :    // This is used to keep track of the index of imports to the Asan RTL.
1307  E :    ImportNameIndexMap import_name_index_map;
1308    :  
1309    :    // Keeps track of all imported modules with imports that we intercept.
1310  E :    ScopedVector<ImportedModule> imported_modules;
1311    :  
1312  E :    ImportedModule asan_rtl(asan_dll_name_, kDateInThePast);
1313    :  
1314    :    // Determines what PE imports need to be intercepted, adding them to
1315    :    // |asan_rtl| and |import_name_index_map|.
1316    :    if (!PeFindImportsToIntercept(use_interceptors_,
1317    :                                  intercepts,
1318    :                                  policy,
1319    :                                  block_graph,
1320    :                                  header_block,
1321    :                                  &imported_modules,
1322    :                                  &import_name_index_map,
1323  E :                                  &asan_rtl)) {
1324  i :      return false;
1325    :    }
1326    :  
1327    :    // Keep track of how many import redirections are to be performed. This allows
1328    :    // a minor optimization later on when there are none to be performed.
1329  E :    size_t import_redirection_count = asan_rtl.size();
1330    :  
1331    :    // Find statically linked function blocks to intercept, adding them to
1332    :    // |asan_rtl| and |import_name_index_map|.
1333  E :    std::vector<BlockGraph::Block*> static_blocks;
1334    :    PeFindStaticallyLinkedFunctionsToIntercept(use_interceptors_,
1335    :                                               intercepts,
1336    :                                               block_graph,
1337    :                                               &static_blocks,
1338    :                                               &import_name_index_map,
1339  E :                                               &asan_rtl);
1340    :  
1341    :    // If no imports were found at all, then there are no redirections to perform.
1342  E :    if (asan_rtl.size() == 0)
1343  i :      return true;
1344    :  
1345    :    // Add the Asan RTL imports to the image.
1346  E :    PEAddImportsTransform add_imports_transform;
1347  E :    add_imports_transform.AddModule(&asan_rtl);
1348    :    if (!add_imports_transform.TransformBlockGraph(
1349  E :            policy, block_graph, header_block)) {
1350  i :      LOG(ERROR) << "Unable to add imports for redirection.";
1351  i :      return false;
1352    :    }
1353    :  
1354    :    // This keeps track of reference redirections that need to be performed.
1355  E :    pe::ReferenceMap reference_redirect_map;
1356    :  
1357  E :    if (import_redirection_count > 0) {
1358    :      PeGetRedirectsForInterceptedImports(imported_modules,
1359    :                                          import_name_index_map,
1360    :                                          asan_rtl,
1361  E :                                          &reference_redirect_map);
1362    :    }
1363    :  
1364    :    // Adds redirect information for any intercepted statically linked functions.
1365  E :    if (!static_blocks.empty()) {
1366    :      if (!PeGetRedirectsForStaticallyLinkedFunctions(static_blocks,
1367    :                                                      import_name_index_map,
1368    :                                                      asan_rtl,
1369    :                                                      block_graph,
1370  E :                                                      &reference_redirect_map)) {
1371  i :        return false;
1372    :      }
1373    :    }
1374    :  
1375    :    // Finally, redirect all references to intercepted functions.
1376  E :    pe::RedirectReferences(reference_redirect_map);
1377    :  
1378  E :    return true;
1379  E :  }
1380    :  
1381    :  bool AsanTransform::PeInjectAsanParameters(
1382    :      const TransformPolicyInterface* policy,
1383    :      BlockGraph* block_graph,
1384  E :      BlockGraph::Block* header_block) {
1385  E :    DCHECK_NE(reinterpret_cast<TransformPolicyInterface*>(NULL), policy);
1386  E :    DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
1387  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), header_block);
1388  E :    DCHECK_EQ(BlockGraph::PE_IMAGE, block_graph->image_format());
1389    :  
1390    :    // If there are no parameters then do nothing.
1391  E :    if (asan_parameters_ == NULL)
1392  E :      return true;
1393    :  
1394    :    // Serialize the parameters into a new block.
1395  E :    common::FlatAsanParameters fparams(*asan_parameters_);
1396    :    BlockGraph::Block* params_block = block_graph->AddBlock(
1397  E :        BlockGraph::DATA_BLOCK, fparams.data().size(), "AsanParameters");
1398  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), params_block);
1399  E :    params_block->CopyData(fparams.data().size(), fparams.data().data());
1400    :  
1401    :    // Wire up any references that are required.
1402    :    COMPILE_ASSERT(8 == common::kAsanParametersVersion,
1403    :                   pointers_in_the_params_must_be_linked_up_here);
1404  E :    block_graph::TypedBlock<common::AsanParameters> params;
1405  E :    CHECK(params.Init(0, params_block));
1406  E :    if (fparams->ignored_stack_ids != NULL) {
1407    :      size_t offset = reinterpret_cast<const uint8*>(fparams->ignored_stack_ids) -
1408  E :          reinterpret_cast<const uint8*>(&fparams.params());
1409    :      CHECK(params.SetReference(BlockGraph::ABSOLUTE_REF,
1410    :                                params->ignored_stack_ids,
1411    :                                params_block,
1412    :                                offset,
1413  E :                                offset));
1414    :    }
1415    :  
1416    :    // Create an appropriately named section and put the parameters there. The
1417    :    // RTL looks for this named section to find the parameters.
1418    :    BlockGraph::Section* section = block_graph->FindOrAddSection(
1419    :        common::kAsanParametersSectionName,
1420  E :        common::kAsanParametersSectionCharacteristics);
1421  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Section*>(NULL), section);
1422  E :    params_block->set_section(section->id());
1423    :  
1424    :    // Remember the block containing the parameters. This is a unittesting seam.
1425  E :    asan_parameters_block_ = params_block;
1426    :  
1427  E :    return true;
1428  E :  }
1429    :  
1430    :  bool AsanTransform::CoffInterceptFunctions(
1431    :      const AsanIntercept* intercepts,
1432    :      const TransformPolicyInterface* policy,
1433    :      BlockGraph* block_graph,
1434  E :      BlockGraph::Block* header_block) {
1435  E :    DCHECK_NE(reinterpret_cast<AsanIntercept*>(NULL), intercepts);
1436  E :    DCHECK_NE(reinterpret_cast<TransformPolicyInterface*>(NULL), policy);
1437  E :    DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
1438  E :    DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), header_block);
1439    :  
1440    :    // Extract the existing symbols.
1441  E :    pe::CoffSymbolNameOffsetMap symbol_map;
1442  E :    BlockGraph::Block* symbols_block = NULL;
1443  E :    BlockGraph::Block* strings_block = NULL;
1444    :    if (!pe::FindCoffSpecialBlocks(block_graph, NULL, &symbols_block,
1445  E :                                   &strings_block)) {
1446  i :      LOG(ERROR) << "Unable to find COFF header blocks.";
1447  i :      return false;
1448    :    }
1449  E :    if (!pe::BuildCoffSymbolNameOffsetMap(block_graph, &symbol_map)) {
1450  i :      LOG(ERROR) << "Unable to build symbol map.";
1451  i :      return false;
1452    :    }
1453    :  
1454    :    // Populate a COFF symbol rename transform for each function to be
1455    :    // intercepted. We simply try to rename all possible symbols that may exist
1456    :    // and allow the transform to ignore any that aren't present.
1457  E :    pe::transforms::CoffRenameSymbolsTransform rename_tx;
1458  E :    rename_tx.set_symbols_must_exist(false);
1459  E :    const AsanIntercept* intercept = intercepts;
1460  E :    bool defines_asan_functions = false;
1461  E :    for (; intercept->undecorated_name != NULL; ++intercept) {
1462    :      // Skip disabled optional functions.
1463  E :      if (!use_interceptors_ && intercept->optional)
1464  i :        continue;
1465    :  
1466    :      // Skip functions for which we have no decorated name.
1467  E :      if (intercept->decorated_name == NULL)
1468  E :        continue;
1469    :  
1470    :      // Build the name of the imported version of this symbol.
1471  E :      std::string imp_name(kDecoratedImportPrefix);
1472  E :      imp_name += intercept->decorated_name;
1473    :  
1474    :      // Build the name of the Asan instrumented version of this symbol.
1475  E :      std::string asan_name(kDecoratedAsanInterceptPrefix);
1476  E :      asan_name += intercept->decorated_name;
1477    :  
1478    :      // Build the name of the Asan instrumented imported version of this symbol.
1479  E :      std::string imp_asan_name(kDecoratedImportPrefix);
1480  E :      imp_asan_name += asan_name;
1481    :  
1482    :      // Build symbol rename mappings for the direct and indirect versions of the
1483    :      // function.
1484  E :      rename_tx.AddSymbolMapping(intercept->decorated_name, asan_name);
1485  E :      rename_tx.AddSymbolMapping(imp_name, imp_asan_name);
1486    :  
1487    :      // We use the add imports transform to try to find names for the Asan
1488    :      // implementation. If these already exist in the object file then our
1489    :      // instrumentation will fail.
1490  E :      const std::string* names[] = { &asan_name, &imp_asan_name };
1491  E :      for (size_t i = 0; i < arraysize(names); ++i) {
1492  E :        if (symbol_map.count(*names[i])) {
1493  i :          LOG(ERROR) << "Object file being instrumented defines Asan function \""
1494    :                     << asan_name << "\".";
1495  i :          defines_asan_functions = true;
1496    :        }
1497  E :      }
1498  E :    }
1499    :  
1500  E :    if (defines_asan_functions)
1501  i :      return false;
1502    :  
1503    :    // Apply the rename transform.
1504    :    if (!block_graph::ApplyBlockGraphTransform(&rename_tx,
1505    :                                               policy,
1506    :                                               block_graph,
1507  E :                                               header_block)) {
1508  i :      LOG(ERROR) << "Failed to apply COFF symbol rename transform.";
1509  i :      return false;
1510    :    }
1511    :  
1512  E :    return true;
1513  E :  }
1514    :  
1515    :  bool operator<(const AsanBasicBlockTransform::MemoryAccessInfo& left,
1516  E :                 const AsanBasicBlockTransform::MemoryAccessInfo& right) {
1517  E :    if (left.mode != right.mode)
1518  E :      return left.mode < right.mode;
1519  E :    if (left.size != right.size)
1520  E :      return left.size < right.size;
1521  E :    if (left.save_flags != right.save_flags)
1522  E :      return left.save_flags < right.save_flags;
1523  E :    return left.opcode < right.opcode;
1524  E :  }
1525    :  
1526    :  }  // namespace transforms
1527    :  }  // namespace instrument

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