1 : // Copyright 2012 Google Inc.
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 : // Implements the BasicBlockEntryHookTransform class.
16 :
17 : #include "syzygy/instrument/transforms/basic_block_entry_hook_transform.h"
18 :
19 : #include "base/logging.h"
20 : #include "syzygy/pe/block_util.h"
21 : #include "syzygy/pe/pe_utils.h"
22 : #include "syzygy/pe/transforms/add_imports_transform.h"
23 :
24 : namespace instrument {
25 : namespace transforms {
26 :
27 : const char BasicBlockEntryHookTransform::kDefaultModuleName[] =
28 : "basic_block_entry.dll";
29 :
30 : const char BasicBlockEntryHookTransform::kDefaultFunctionName[] =
31 : "_basic_block_enter";
32 :
33 : const char BasicBlockEntryHookTransform::kTransformName[] =
34 : "BasicBlockEntryHookTransform";
35 :
36 : BasicBlockEntryHookTransform::BasicBlockEntryHookTransform()
37 E : : module_name_(kDefaultModuleName), function_name_(kDefaultFunctionName) {
38 E : }
39 :
40 : BasicBlockEntryHookTransform::BasicBlockEntryHookTransform(
41 : const base::StringPiece& module_name,
42 : const base::StringPiece& function_name)
43 : : module_name_(module_name.begin(), module_name.end()),
44 E : function_name_(function_name.begin(), function_name.end()) {
45 E : DCHECK(!module_name.empty());
46 E : DCHECK(!function_name.empty());
47 E : }
48 :
49 : bool BasicBlockEntryHookTransform::PreBlockGraphIteration(
50 : BlockGraph* block_graph,
51 E : BlockGraph::Block* header_block) {
52 E : pe::transforms::AddImportsTransform::ImportedModule module(module_name_);
53 E : size_t function_index = module.AddSymbol(function_name_);
54 :
55 E : pe::transforms::AddImportsTransform add_imports;
56 E : add_imports.AddModule(&module);
57 :
58 E : if (!ApplyBlockGraphTransform(&add_imports, block_graph, header_block)) {
59 i : LOG(ERROR) << "Unable to add import entry for basic-block hook function.";
60 i : return false;
61 : }
62 :
63 E : if (!module.GetSymbolReference(function_index, &bb_entry_hook_ref_)) {
64 i : LOG(ERROR) << "Unable to get reference to basic-block entry hook import "
65 : << module_name_ << ":" << function_name_ << ".";
66 i : return false;
67 : }
68 :
69 E : DCHECK(bb_entry_hook_ref_.IsValid());
70 :
71 E : return true;
72 E : }
73 :
74 : bool BasicBlockEntryHookTransform::OnBlock(BlockGraph* block_graph,
75 E : BlockGraph::Block* block) {
76 E : DCHECK(block_graph != NULL);
77 E : DCHECK(block != NULL);
78 :
79 E : if (block->type() != BlockGraph::CODE_BLOCK)
80 E : return true;
81 :
82 E : if (!pe::CodeBlockIsBasicBlockDecomposable(block))
83 E : return true;
84 :
85 E : if (!ApplyBasicBlockSubGraphTransform(this, block_graph, block, NULL))
86 i : return false;
87 :
88 E : return true;
89 E : }
90 :
91 : bool BasicBlockEntryHookTransform::TransformBasicBlockSubGraph(
92 E : BlockGraph* block_graph , BasicBlockSubGraph* subgraph) {
93 E : DCHECK(block_graph != NULL);
94 E : DCHECK(subgraph != NULL);
95 E : DCHECK(bb_entry_hook_ref_.IsValid());
96 :
97 : // Insert a call to the basic-block entry hook at the top of each code
98 : // basic-block. We use the id_generator_ to assign an ID to each basic-block.
99 : BasicBlockSubGraph::BBCollection::iterator it =
100 E : subgraph->basic_blocks().begin();
101 E : for (; it != subgraph->basic_blocks().end(); ++it) {
102 E : BasicBlock& bb = it->second;
103 E : if (bb.type() != BasicBlock::BASIC_CODE_BLOCK)
104 E : continue;
105 :
106 : block_graph::BasicBlockAssembler bb_asm(bb.instructions().begin(),
107 E : &bb.instructions());
108 :
109 E : bb_asm.push(block_graph::Immediate(bb_addresses_.size(), core::kSize32Bit));
110 : bb_asm.call(block_graph::Immediate(bb_entry_hook_ref_.referenced(),
111 E : bb_entry_hook_ref_.offset()));
112 :
113 : // Find the source range associated with this basic-block and translate
114 : // that to an RVA.
115 : // TODO(rogerm): Replace this with a call to request the RVA directly from
116 : // a basic-block, once that call becomes available.
117 : const BlockGraph::Block::SourceRanges::RangePair* bb_range_pair =
118 : subgraph->original_block()->source_ranges().FindRangePair(
119 E : BlockGraph::Block::SourceRanges::SourceRange(bb.offset(), 1));
120 E : DCHECK(bb_range_pair != NULL);
121 E : const BlockGraph::Block::DataRange& data_range = bb_range_pair->first;
122 E : const BlockGraph::Block::SourceRange& src_range = bb_range_pair->second;
123 : core::RelativeAddress bb_addr = src_range.start() +
124 E : (bb.offset() - data_range.start());
125 :
126 : // Add the basic-block address to the id-to-address vector.
127 E : bb_addresses_.push_back(bb_addr);
128 E : }
129 :
130 E : return true;
131 E : }
132 :
133 : } // namespace transforms
134 : } // namespace instrument
|