| OLD | NEW |
| (Empty) | |
| 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/instrument/transforms/filler_transform.h" |
| 16 |
| 17 #include "base/logging.h" |
| 18 #include "syzygy/assm/assembler_base.h" |
| 19 #include "syzygy/block_graph/basic_block_assembler.h" |
| 20 #include "syzygy/block_graph/basic_block_subgraph.h" |
| 21 #include "syzygy/block_graph/block_util.h" |
| 22 #include "syzygy/block_graph/transform_policy.h" |
| 23 |
| 24 namespace instrument { |
| 25 namespace transforms { |
| 26 |
| 27 const char FillerBasicBlockTransform::kTransformName[] = |
| 28 "FillerBasicBlockTransform"; |
| 29 |
| 30 const char FillerTransform::kTransformName[] = "FillerTransform"; |
| 31 |
| 32 size_t NopInjector::Inject(BasicBlock::Instructions* instructions) const { |
| 33 size_t num_injected = 0LL; |
| 34 // Since the locations in |nop_spec_| are sorted, we can perform a parallel |
| 35 // visit of |nop_spec_| and |instructions| to inject NOPs. |
| 36 NopSpec::const_iterator nop_it = nop_spec_.begin(); |
| 37 BasicBlock::Instructions::iterator inst_it = instructions->begin(); |
| 38 size_t offset = 0LL; |
| 39 while (nop_it != nop_spec_.end() && inst_it != instructions->end()) { |
| 40 // Always increase offset. For each offset, either add NOP or proceed to |
| 41 // the next instruction. |
| 42 if (nop_it->first == offset) { |
| 43 block_graph::BasicBlockAssembler assm(inst_it, instructions); |
| 44 assm.nop(nop_it->second); |
| 45 ++nop_it; |
| 46 ++num_injected; |
| 47 } else { |
| 48 ++inst_it; |
| 49 } |
| 50 ++offset; |
| 51 } |
| 52 return num_injected; |
| 53 } |
| 54 |
| 55 bool FillerBasicBlockTransform::TransformBasicBlockSubGraph( |
| 56 const TransformPolicyInterface* policy, |
| 57 BlockGraph* block_graph, |
| 58 BasicBlockSubGraph* basic_block_subgraph) { |
| 59 DCHECK(nullptr != policy); |
| 60 DCHECK(nullptr != block_graph); |
| 61 DCHECK(nullptr != basic_block_subgraph); |
| 62 |
| 63 // Locations for code injection. |
| 64 NopInjector nop_injector({{1, NopInjector::NOP1}}); |
| 65 |
| 66 // Visit each basic code block and inject NOPs. |
| 67 BasicBlockSubGraph::BBCollection& basic_blocks = |
| 68 basic_block_subgraph->basic_blocks(); |
| 69 for (auto bb = basic_blocks.begin(); bb != basic_blocks.end(); ++bb) { |
| 70 BasicCodeBlock* bc_block = BasicCodeBlock::Cast(*bb); |
| 71 if (bc_block != nullptr) |
| 72 nop_injector.Inject(&bc_block->instructions()); |
| 73 } |
| 74 return true; |
| 75 } |
| 76 |
| 77 FillerTransform::FillerTransform(const std::vector<std::string>& target_list) |
| 78 : basic_block_transform_(new FillerBasicBlockTransform()), |
| 79 num_block_(0), |
| 80 num_code_block_(0), |
| 81 num_target_updated_(0) { |
| 82 // Targets are not found yet, so initialize value to false. |
| 83 for (const std::string& target : target_list) |
| 84 target_names_[target] = false; |
| 85 } |
| 86 |
| 87 bool FillerTransform::ShouldProcessBlock(Block* block) const { |
| 88 return target_names_.find(block->name()) != target_names_.end(); |
| 89 } |
| 90 |
| 91 void FillerTransform::CheckAllTargetFound() const { |
| 92 bool has_missing = false; |
| 93 for (auto it = target_names_.begin(); it != target_names_.end(); ++it) { |
| 94 if (it->second) |
| 95 continue; |
| 96 if (!has_missing) { |
| 97 LOG(ERROR) << "There are missing target(s):"; |
| 98 has_missing = true; |
| 99 } |
| 100 LOG(ERROR) << " " << it->first; |
| 101 } |
| 102 } |
| 103 |
| 104 bool FillerTransform::PreBlockGraphIteration( |
| 105 const TransformPolicyInterface* policy, |
| 106 BlockGraph* block_graph, |
| 107 Block* header_block) { |
| 108 return true; |
| 109 } |
| 110 |
| 111 bool FillerTransform::OnBlock(const TransformPolicyInterface* policy, |
| 112 BlockGraph* block_graph, |
| 113 Block* block) { |
| 114 DCHECK(nullptr != policy); |
| 115 DCHECK(nullptr != block_graph); |
| 116 DCHECK(nullptr != block); |
| 117 |
| 118 ++num_block_; |
| 119 if (block->type() != BlockGraph::CODE_BLOCK) |
| 120 return true; |
| 121 |
| 122 ++num_code_block_; |
| 123 if (!ShouldProcessBlock(block)) |
| 124 return true; |
| 125 |
| 126 // Mark target as found. |
| 127 std::string name(block->name()); |
| 128 auto target_it = target_names_.find(block->name()); |
| 129 if (target_it != target_names_.end()) |
| 130 target_it->second = true; |
| 131 |
| 132 // Skip blocks that aren't eligible for basic-block decomposition. |
| 133 if (!policy->BlockIsSafeToBasicBlockDecompose(block)) |
| 134 return true; |
| 135 |
| 136 ++num_target_updated_; |
| 137 // Apply the basic block transform. |
| 138 return ApplyBasicBlockSubGraphTransform( |
| 139 basic_block_transform_.get(), policy, block_graph, block, NULL); |
| 140 } |
| 141 |
| 142 bool FillerTransform::PostBlockGraphIteration( |
| 143 const TransformPolicyInterface* policy, |
| 144 BlockGraph* block_graph, |
| 145 Block* header_block) { |
| 146 LOG(INFO) << "Found " << num_block_ << " block(s)."; |
| 147 LOG(INFO) << "Found " << num_code_block_ << " code block(s)."; |
| 148 LOG(INFO) << "Updated " << num_target_updated_ << " blocks(s)."; |
| 149 CheckAllTargetFound(); |
| 150 return true; |
| 151 } |
| 152 |
| 153 } // namespace transforms |
| 154 } // namespace instrument |
| OLD | NEW |