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 : // static
33 : void FillerBasicBlockTransform::InjectNop(
34 : const NopSpec& nop_spec,
35 : bool debug_friendly,
36 E : BasicBlock::Instructions* instructions) {
37 E : BasicBlock::Instructions::iterator inst_it = instructions->begin();
38 E : NopSpec::const_iterator nop_it = nop_spec.begin();
39 E : size_t write_index = 0LL;
40 E : while (inst_it != instructions->end() && nop_it != nop_spec.end()) {
41 E : if (nop_it->first == write_index) {
42 E : block_graph::BasicBlockAssembler assm(inst_it, instructions);
43 : // If specified, set source range for successive NOPs to to be that of the
44 : // current instruction (which follows the NOPs). Caveat: This breaks the
45 : // 1:1 OMAP mapping and may confuse some debuggers.
46 E : if (debug_friendly)
47 E : assm.set_source_range(inst_it->source_range());
48 : // Add all NOPs with consecutive instruction indexes.
49 E : while (nop_it != nop_spec.end() && nop_it->first == write_index) {
50 E : assm.nop(nop_it->second);
51 E : ++nop_it;
52 E : ++write_index;
53 E : }
54 : }
55 E : ++inst_it;
56 E : ++write_index;
57 E : }
58 E : }
59 :
60 : bool FillerBasicBlockTransform::TransformBasicBlockSubGraph(
61 : const TransformPolicyInterface* policy,
62 : BlockGraph* block_graph,
63 E : BasicBlockSubGraph* basic_block_subgraph) {
64 E : DCHECK(nullptr != policy);
65 E : DCHECK(nullptr != block_graph);
66 E : DCHECK(nullptr != basic_block_subgraph);
67 :
68 : // Visit each basic code block and inject NOPs.
69 : BasicBlockSubGraph::BBCollection& basic_blocks =
70 E : basic_block_subgraph->basic_blocks();
71 E : for (auto& bb : basic_blocks) {
72 E : BasicCodeBlock* bc_block = BasicCodeBlock::Cast(bb);
73 E : if (bc_block != nullptr) {
74 E : BasicBlock::Instructions* instructions = &bc_block->instructions();
75 E : NopSpec nop_spec;
76 E : size_t size = instructions->size();
77 : // Inject NOP after every instruction, except the last.
78 E : for (size_t i = 1; i < size; ++i) {
79 E : nop_spec[i * 2 - 1] = NopSizes::NOP1;
80 E : }
81 E : InjectNop(nop_spec, debug_friendly_, instructions);
82 E : }
83 E : }
84 E : return true;
85 E : }
86 :
87 : FillerTransform::FillerTransform(const std::set<std::string>& target_set,
88 : bool add_copy)
89 : : debug_friendly_(false),
90 : num_blocks_(0),
91 : num_code_blocks_(0),
92 : num_targets_updated_(0),
93 E : add_copy_(add_copy) {
94 : // Targets are not found yet, so initialize value to null.
95 E : for (const std::string& target : target_set)
96 E : target_visited_[target] = false;
97 E : }
98 :
99 E : bool FillerTransform::ShouldProcessBlock(Block* block) const {
100 E : return target_visited_.find(block->name()) != target_visited_.end();
101 E : }
102 :
103 E : void FillerTransform::CheckAllTargetsFound() const {
104 E : bool has_missing = false;
105 E : for (const auto& it : target_visited_) {
106 E : if (it.second)
107 E : continue;
108 i : if (!has_missing) {
109 i : LOG(WARNING) << "There are missing target(s):";
110 i : has_missing = true;
111 : }
112 i : LOG(WARNING) << " " << it.first;
113 i : }
114 E : }
115 :
116 : bool FillerTransform::PreBlockGraphIteration(
117 : const TransformPolicyInterface* policy,
118 : BlockGraph* block_graph,
119 E : Block* header_block) {
120 E : return true;
121 E : }
122 :
123 : bool FillerTransform::OnBlock(const TransformPolicyInterface* policy,
124 : BlockGraph* block_graph,
125 E : Block* block) {
126 E : DCHECK(nullptr != policy);
127 E : DCHECK(nullptr != block_graph);
128 E : DCHECK(nullptr != block);
129 :
130 E : ++num_blocks_;
131 E : if (block->type() != BlockGraph::CODE_BLOCK)
132 E : return true;
133 :
134 E : ++num_code_blocks_;
135 E : if (!ShouldProcessBlock(block))
136 E : return true;
137 :
138 : // Mark target as found. Add copy of target if specified to do so.
139 E : std::string name(block->name());
140 E : auto target_it = target_visited_.find(block->name());
141 E : if (target_it != target_visited_.end()) {
142 E : target_it->second = true;
143 E : if (add_copy_)
144 E : block_graph->CopyBlock(block, block->name() + "_copy");
145 : }
146 :
147 : // Skip blocks that aren't eligible for basic-block decomposition.
148 E : if (!policy->BlockIsSafeToBasicBlockDecompose(block))
149 i : return true;
150 :
151 E : ++num_targets_updated_;
152 : // Apply the basic block transform.
153 E : FillerBasicBlockTransform basic_block_transform;
154 E : basic_block_transform.set_debug_friendly(debug_friendly());
155 : return ApplyBasicBlockSubGraphTransform(
156 E : &basic_block_transform, policy, block_graph, block, NULL);
157 E : }
158 :
159 : bool FillerTransform::PostBlockGraphIteration(
160 : const TransformPolicyInterface* policy,
161 : BlockGraph* block_graph,
162 E : Block* header_block) {
163 E : LOG(INFO) << "Found " << num_blocks_ << " block(s).";
164 E : LOG(INFO) << "Found " << num_code_blocks_ << " code block(s).";
165 E : LOG(INFO) << "Updated " << num_targets_updated_ << " blocks(s).";
166 E : CheckAllTargetsFound();
167 E : return true;
168 E : }
169 :
170 : } // namespace transforms
171 : } // namespace instrument
|