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