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/coverage_transform.h"
16 :
17 : #include "syzygy/block_graph/basic_block_assembler.h"
18 : #include "syzygy/block_graph/block_util.h"
19 : #include "syzygy/common/indexed_frequency_data.h"
20 : #include "syzygy/core/disassembler_util.h"
21 : #include "syzygy/pe/pe_utils.h"
22 :
23 : namespace instrument {
24 : namespace transforms {
25 :
26 : namespace {
27 :
28 : using common::IndexedFrequencyData;
29 : using common::kBasicBlockCoverageAgentId;
30 : using assm::eax;
31 : using block_graph::ApplyBasicBlockSubGraphTransform;
32 : using block_graph::ApplyBlockGraphTransform;
33 : using block_graph::BasicBlock;
34 : using block_graph::BasicCodeBlock;
35 : using block_graph::BasicBlockAssembler;
36 : using block_graph::BasicBlockReference;
37 : using block_graph::BlockGraph;
38 : using block_graph::Displacement;
39 : using block_graph::Immediate;
40 : using block_graph::Operand;
41 : using block_graph::TransformPolicyInterface;
42 :
43 : typedef CoverageInstrumentationTransform::RelativeAddressRange
44 : RelativeAddressRange;
45 :
46 : const BlockGraph::Offset kFrequencyDataOffset =
47 : offsetof(IndexedFrequencyData, frequency_data);
48 :
49 : // Compares two relative address ranges to see if they overlap. Assumes they
50 : // are already sorted. This is used to validate basic-block ranges.
51 : struct RelativeAddressRangesOverlapFunctor {
52 : bool operator()(const RelativeAddressRange& r1,
53 E : const RelativeAddressRange& r2) const {
54 E : DCHECK_LT(r1.start(), r2.start());
55 :
56 E : if (r1.end() > r2.start())
57 i : return true;
58 :
59 E : return false;
60 E : }
61 : };
62 :
63 : } // namespace
64 :
65 : const char CoverageInstrumentationTransform::kTransformName[] =
66 : "CoverageInstrumentationTransform";
67 :
68 : CoverageInstrumentationTransform::CoverageInstrumentationTransform()
69 : : add_bb_freq_data_tx_(kBasicBlockCoverageAgentId,
70 : "Basic-Block Frequency Data",
71 : common::kBasicBlockFrequencyDataVersion,
72 : common::IndexedFrequencyData::COVERAGE,
73 E : sizeof(common::IndexedFrequencyData)) {
74 : // Initialize the EntryThunkTransform.
75 E : entry_thunk_tx_.set_instrument_unsafe_references(false);
76 E : entry_thunk_tx_.set_only_instrument_module_entry(true);
77 E : }
78 :
79 : bool CoverageInstrumentationTransform::TransformBasicBlockSubGraph(
80 : const TransformPolicyInterface* policy,
81 : BlockGraph* block_graph,
82 E : BasicBlockSubGraph* basic_block_subgraph) {
83 E : DCHECK(policy != NULL);
84 E : DCHECK(block_graph != NULL);
85 E : DCHECK(basic_block_subgraph != NULL);
86 :
87 E : BlockGraph::Block* data_block = add_bb_freq_data_tx_.frequency_data_block();
88 E : DCHECK(data_block != NULL);
89 E : DCHECK_EQ(sizeof(IndexedFrequencyData), data_block->data_size());
90 :
91 : // Iterate over the basic blocks.
92 : BasicBlockSubGraph::BBCollection::iterator it =
93 E : basic_block_subgraph->basic_blocks().begin();
94 E : for (; it != basic_block_subgraph->basic_blocks().end(); ++it) {
95 : // We're only interested in code blocks.
96 E : BasicCodeBlock* bb = BasicCodeBlock::Cast(*it);
97 E : if (bb == NULL)
98 E : continue;
99 :
100 : // Find the source range associated with this basic-block.
101 E : BlockGraph::Block::SourceRange source_range;
102 E : if (!GetBasicBlockSourceRange(*bb, &source_range)) {
103 i : LOG(ERROR) << "Unable to get source range for basic block '"
104 : << bb->name() << "'";
105 i : return false;
106 : }
107 :
108 : // We prepend each basic code block with the following instructions:
109 : // 0. push eax
110 : // 1. mov eax, dword ptr[data.frequency_data]
111 : // 2. mov byte ptr[eax + basic_block_index], 1
112 : // 3. pop eax
113 E : BasicBlockAssembler assm(bb->instructions().begin(), &bb->instructions());
114 :
115 : // Prepend the instrumentation instructions.
116 E : assm.push(eax);
117 E : assm.mov(eax, Operand(Displacement(data_block, kFrequencyDataOffset)));
118 E : assm.mov_b(Operand(eax, Displacement(bb_ranges_.size())), Immediate(1));
119 E : assm.pop(eax);
120 :
121 E : bb_ranges_.push_back(source_range);
122 E : }
123 :
124 E : return true;
125 E : }
126 :
127 : bool CoverageInstrumentationTransform::PreBlockGraphIteration(
128 : const TransformPolicyInterface* policy,
129 : BlockGraph* block_graph,
130 E : BlockGraph::Block* header_block) {
131 E : DCHECK_NE(reinterpret_cast<TransformPolicyInterface*>(NULL), policy);
132 E : DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
133 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), header_block);
134 E : DCHECK_EQ(BlockGraph::PE_IMAGE, block_graph->image_format());
135 :
136 : if (!ApplyBlockGraphTransform(
137 E : &add_bb_freq_data_tx_, policy, block_graph, header_block)) {
138 i : LOG(ERROR) << "Failed to insert basic-block frequency data.";
139 i : return false;
140 : }
141 :
142 E : return true;
143 E : }
144 :
145 : bool CoverageInstrumentationTransform::OnBlock(
146 : const TransformPolicyInterface* policy,
147 : BlockGraph* block_graph,
148 E : BlockGraph::Block* block) {
149 E : DCHECK(policy != NULL);
150 E : DCHECK(block_graph != NULL);
151 E : DCHECK(block != NULL);
152 :
153 : // We only care about blocks that are safe for basic block decomposition.
154 E : if (!policy->BlockIsSafeToBasicBlockDecompose(block))
155 E : return true;
156 :
157 : // Apply our basic block transform.
158 : if (!ApplyBasicBlockSubGraphTransform(
159 E : this, policy, block_graph, block, NULL)) {
160 i : return false;
161 : }
162 :
163 E : return true;
164 E : }
165 :
166 : bool CoverageInstrumentationTransform::PostBlockGraphIteration(
167 : const TransformPolicyInterface* policy,
168 : BlockGraph* block_graph,
169 E : BlockGraph::Block* header_block) {
170 E : DCHECK(policy != NULL);
171 E : DCHECK(block_graph != NULL);
172 E : DCHECK(header_block != NULL);
173 :
174 : // Get a reference to the frequency data and make that the parameter that
175 : // we pass to the entry thunks. We run the thunk transform after the coverage
176 : // instrumentation transform as it creates new code blocks that we don't
177 : // want to instrument.
178 : auto ref_to_freq_data(
179 E : Immediate(add_bb_freq_data_tx_.frequency_data_block(), 0));
180 E : entry_thunk_tx_.SetEntryThunkParameter(ref_to_freq_data);
181 : if (!ApplyBlockGraphTransform(
182 E : &entry_thunk_tx_, policy, block_graph, header_block)) {
183 i : LOG(ERROR) << "Failed to thunk image entry points.";
184 i : return false;
185 : }
186 :
187 E : size_t num_basic_blocks = bb_ranges_.size();
188 E : if (num_basic_blocks == 0) {
189 i : LOG(WARNING) << "Encountered no basic code blocks during instrumentation.";
190 i : return true;
191 : }
192 :
193 : if (!add_bb_freq_data_tx_.ConfigureFrequencyDataBuffer(num_basic_blocks,
194 : 1,
195 E : sizeof(uint8))) {
196 i : LOG(ERROR) << "Failed to configure frequency data buffer.";
197 i : return false;
198 : }
199 :
200 : #ifndef NDEBUG
201 : // If we're in debug mode then sanity check the basic block ranges. When
202 : // sorted, they should not overlap.
203 E : RelativeAddressRangeVector bb_ranges(bb_ranges_);
204 E : std::sort(bb_ranges.begin(), bb_ranges.end());
205 : DCHECK(std::adjacent_find(bb_ranges.begin(), bb_ranges.end(),
206 : RelativeAddressRangesOverlapFunctor()) ==
207 E : bb_ranges.end());
208 : #endif
209 :
210 E : return true;
211 E : }
212 :
213 : } // namespace transforms
214 : } // namespace instrument
|