Coverage for /Syzygy/pe/transforms/pe_hot_patching_basic_block_transform.cc

CoverageLines executed / instrumented / missingexe / inst / missLanguageGroup
100.0%40400.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/transforms/pe_hot_patching_basic_block_transform.h"
  16    :  
  17    :  #include "syzygy/block_graph/basic_block_assembler.h"
  18    :  
  19    :  namespace pe {
  20    :  namespace transforms {
  21    :  
  22    :  const char PEHotPatchingBasicBlockTransform::kTransformName[] =
  23    :      "PEHotPatchingBasicBlockTransform";
  24    :  
  25    :  // This is the size of an x86 jump instruction: 0xEA [32-bit absolute address]
  26    :  // The padding inserted at the beginning of the blocks must be big enough to
  27    :  // contain this instruction.
  28    :  const size_t PEHotPatchingBasicBlockTransform::kLongJumpInstructionLength = 5U;
  29    :  
  30    :  namespace {
  31    :  
  32    :  using block_graph::BlockGraph;
  33    :  using block_graph::BasicBlockAssembler;
  34    :  using block_graph::BasicBlockSubGraph;
  35    :  typedef BasicBlockSubGraph::BasicBlock BasicBlock;
  36    :  typedef BasicBlockSubGraph::BasicCodeBlock BasicCodeBlock;
  37    :  
  38    :  }  // namespace
  39    :  
  40    :  bool PEHotPatchingBasicBlockTransform::TransformBasicBlockSubGraph(
  41    :      const TransformPolicyInterface* policy,
  42    :      BlockGraph* block_graph,
  43  E :      BasicBlockSubGraph* basic_block_subgraph) {
  44  E :    EnsureAtomicallyReplaceableFirstInstruction(basic_block_subgraph);
  45  E :    EnsurePaddingForJumpBeforeBlock(basic_block_subgraph);
  46  E :    return true;
  47  E :  }
  48    :  
  49    :  void PEHotPatchingBasicBlockTransform::InsertTwoByteNopAtBlockBeginning(
  50  E :      BasicCodeBlock* bb) {
  51    :    // Insert a two-byte NOP at the beginning.
  52  E :    BasicBlockAssembler assm(bb->instructions().begin(), &bb->instructions());
  53  E :    assm.nop(2U);
  54  E :  }
  55    :  
  56    :  bool PEHotPatchingBasicBlockTransform::IsAtomicallyReplaceableFirstInstruction(
  57  E :      BasicCodeBlock* bb) {
  58    :    // If there are no instructions in the first basic code block it means that
  59    :    // the block begins with a jump which is either 2 or 5 bytes so therefore
  60    :    // atomically replaceable.
  61  E :    if (bb->instructions().size() == 0)
  62  E :      return true;
  63    :  
  64    :    // An at least two-byte aligned and at least two-byte long instruction is
  65    :    // atomically replaceable.
  66  E :    return bb->instructions().front().size() >= 2;
  67  E :  }
  68    :  
  69    :  void PEHotPatchingBasicBlockTransform::
  70    :      EnsureAtomicallyReplaceableFirstInstruction(
  71  E :      BasicBlockSubGraph* bbsg) {
  72  E :    DCHECK_NE(static_cast<BasicBlockSubGraph*>(nullptr), bbsg);
  73  E :    CHECK_EQ(1U, bbsg->block_descriptions().size());
  74    :  
  75    :    // Ensure proper alignment for the first instruction. An alignment of 2
  76    :    // allows to atomically replace the first 2 bytes of a 2-byte or longer
  77    :    // instruction.
  78  E :    if (bbsg->block_descriptions().front().alignment < 2)
  79  E :      bbsg->block_descriptions().front().alignment = 2;
  80    :  
  81  E :    BasicCodeBlock* first_bb = GetFirstBasicCodeBlock(bbsg);
  82    :  
  83  E :    if (!IsAtomicallyReplaceableFirstInstruction(first_bb))
  84  E :      InsertTwoByteNopAtBlockBeginning(first_bb);
  85  E :  }
  86    :  
  87    :  void PEHotPatchingBasicBlockTransform::EnsurePaddingForJumpBeforeBlock(
  88  E :      BasicBlockSubGraph* bbsg) {
  89  E :    DCHECK_NE(static_cast<BasicBlockSubGraph*>(nullptr), bbsg);
  90    :  
  91  E :    CHECK_EQ(1U, bbsg->block_descriptions().size());
  92    :    BasicBlockSubGraph::BlockDescription& block_description =
  93  E :        bbsg->block_descriptions().front();
  94    :  
  95    :    // If padding_before is not 0, it means that some other task wants to use
  96    :    // that place for some other purpose.
  97  E :    CHECK_EQ(0U, block_description.padding_before);
  98    :  
  99  E :    block_description.padding_before = kLongJumpInstructionLength;
 100  E :  }
 101    :  
 102    :  BasicCodeBlock* PEHotPatchingBasicBlockTransform::GetFirstBasicCodeBlock(
 103  E :      BasicBlockSubGraph* bbsg) {
 104  E :    DCHECK_NE(static_cast<BasicBlockSubGraph*>(nullptr), bbsg);
 105    :  
 106    :    // Get the description of the block.
 107  E :    CHECK_EQ(1U, bbsg->block_descriptions().size());
 108    :    BasicBlockSubGraph::BlockDescription& block_description =
 109  E :        bbsg->block_descriptions().front();
 110    :  
 111    :    // Get the first basic block.
 112  E :    CHECK_EQ(false, block_description.basic_block_order.empty());
 113  E :    BasicBlock* first_block = block_description.basic_block_order.front();
 114    :  
 115    :    // Convert to a basic code block.
 116  E :    BasicCodeBlock* first_code_block = BasicCodeBlock::Cast(first_block);
 117  E :    CHECK_NE(static_cast<BasicCodeBlock*>(nullptr), first_code_block);
 118  E :    return first_code_block;
 119  E :  }
 120    :  
 121    :  }  // namespace transforms
 122    :  }  // namespace pe

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