Coverage for /Syzygy/pe/hot_patching_writer.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
88.2%45510.C++source

Line-by-line coverage:

   1    :  // Copyright 2015 Google Inc. All Rights Reserved.
   2    :  //
   3    :  // Licensed under the Apache License, Version 2.0 (the "License");
   4    :  // you may not use this file except in compliance with the License.
   5    :  // You may obtain a copy of the License at
   6    :  //
   7    :  //     http://www.apache.org/licenses/LICENSE-2.0
   8    :  //
   9    :  // Unless required by applicable law or agreed to in writing, software
  10    :  // distributed under the License is distributed on an "AS IS" BASIS,
  11    :  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12    :  // See the License for the specific language governing permissions and
  13    :  // limitations under the License.
  14    :  
  15    :  #include "syzygy/pe/hot_patching_writer.h"
  16    :  
  17    :  namespace pe {
  18    :  
  19    :  namespace {
  20    :  
  21    :  using block_graph::BlockGraph;
  22    :  
  23    :  // Finalizes the references in a block that has been copied to executable
  24    :  // memory. This will go through all references of the block and writes the final
  25    :  // absolute of PC-relative address to the block at the offset of the reference.
  26    :  // @param block The block whose references should be finalized.
  27    :  // @pre This assumes that the data of the block has been laid out to its final
  28    :  //     address. Also, all referred blocks must be backed up by in-memory
  29    :  //     executable data.
  30  E :  void FinalizeReferences(BlockGraph::Block* block) {
  31  E :    DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), block);
  32    :  
  33    :    using block_graph::BlockGraph;
  34    :    typedef BlockGraph::Offset Offset;
  35    :  
  36    :    // Loop through the references and update them in the laid out block.
  37  E :    for (auto entry : block->references()) {
  38  E :      Offset offset = entry.first;
  39  E :      const BlockGraph::Reference& ref = entry.second;
  40    :  
  41    :      // We are going to write the new value to this memory address.
  42  E :      uint8* src_addr = const_cast<uint8*>(block->data()) + offset;
  43  E :      DCHECK(src_addr >= block->data());
  44  E :      DCHECK(src_addr < block->data() + block->data_size() - ref.size() + 1);
  45    :  
  46    :      // We only support direct references. This is enough for now, because the
  47    :      // hot patching decomposer does not emit indirect references.
  48  E :      DCHECK(ref.IsDirect());
  49    :  
  50    :      // Calculate the value that we need to write.
  51  E :      uint32 value = 0;
  52  E :      switch (ref.type()) {
  53    :        case BlockGraph::ABSOLUTE_REF: {
  54    :          value = reinterpret_cast<uint32>(ref.referenced()->data() +
  55  E :                                           ref.offset());
  56  E :          break;
  57    :        }
  58    :        case BlockGraph::PC_RELATIVE_REF: {
  59    :          // PC-relative references are always the last operand of an instruction
  60    :          // and expressed relative to the first byte after the instruction
  61    :          // (hence after the reference).
  62    :          value = (ref.referenced()->data() + ref.offset()) -
  63  E :              (block->data() + offset + ref.size());
  64  E :          break;
  65    :        }
  66    :        default:
  67  i :          NOTREACHED();
  68    :      }
  69    :  
  70    :      // Now store the new value.
  71  E :      switch (ref.size()) {
  72    :        case sizeof(uint8): {
  73  E :          *reinterpret_cast<uint8*>(src_addr) = static_cast<uint8>(value);
  74  E :          break;
  75    :        }
  76    :        case sizeof(uint16): {
  77  i :          *reinterpret_cast<uint16*>(src_addr) = static_cast<uint16>(value);
  78  i :          break;
  79    :        }
  80    :        case sizeof(uint32): {
  81  E :          *reinterpret_cast<uint32*>(src_addr) = static_cast<uint32>(value);
  82  E :          break;
  83    :        }
  84    :        default:
  85  i :          NOTREACHED();
  86    :      }
  87  E :    }
  88  E :  }
  89    :  
  90    :  }  // namespace
  91    :  
  92    :  HotPatchingWriter::HotPatchingWriter() :
  93    :      virtual_memory_(nullptr),
  94    :      virtual_memory_size_(0),
  95  E :      virtual_memory_cursor_(nullptr) {
  96  E :  }
  97    :  
  98  E :  HotPatchingWriter::~HotPatchingWriter() {
  99  E :  }
 100    :  
 101    :  size_t HotPatchingWriter::GetUsedMemory() const {
 102    :      return virtual_memory_cursor_ - reinterpret_cast<uint8*>(virtual_memory_);
 103    :  }
 104    :  
 105  E :  bool HotPatchingWriter::Init(size_t virtual_memory_size) {
 106    :    // Allocate virtual memory.
 107    :    virtual_memory_ = ::VirtualAlloc(nullptr,
 108    :                                     virtual_memory_size,
 109    :                                     MEM_COMMIT,
 110  E :                                     PAGE_EXECUTE_READWRITE);
 111  E :    if (virtual_memory_ == nullptr) {
 112  i :      LOG(ERROR) << "Could not allocate virtual memory for hot patching writer.";
 113  i :      return false;
 114    :    }
 115    :  
 116    :    // Set up members.
 117  E :    virtual_memory_cursor_ = static_cast<uint8*>(virtual_memory_);
 118  E :    virtual_memory_size_ = virtual_memory_size;
 119    :  
 120  E :    return true;
 121  E :  }
 122    :  
 123    :  HotPatchingWriter::FunctionPointer HotPatchingWriter::Write(
 124  E :      BlockGraph::Block* block) {
 125  E :    DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), block);
 126    :  
 127    :    // Respect block padding.
 128  E :    uint8* block_location = virtual_memory_cursor_ + block->padding_before();
 129    :  
 130    :    // Respect block alignment.
 131    :    block_location = reinterpret_cast<uint8*>(common::AlignUp(
 132  E :        reinterpret_cast<size_t>(block_location), block->alignment()));
 133    :  
 134    :    // Check if we fit into the allocated memory.
 135    :    if (!(block_location + block->size() <
 136  E :          static_cast<uint8*>(virtual_memory_) + virtual_memory_size_)) {
 137  E :      return false;
 138    :    }
 139    :  
 140    :    // Move the virtual memory cursor ahead.
 141  E :    virtual_memory_cursor_ = block_location + block->size();
 142    :  
 143    :    // Copy the contents of the new block to the virtual memory.
 144  E :    ::memcpy(block_location, block->data(), block->data_size());
 145    :  
 146    :    // Set block data to the final location!
 147  E :    block->SetData(block_location, block->data_size());
 148    :  
 149    :    // Update the bytes of the references to their final value.
 150  E :    FinalizeReferences(block);
 151    :  
 152  E :    return reinterpret_cast<FunctionPointer>(block_location);
 153  E :  }
 154    :  
 155    :  }  // namespace pe

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