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