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 : // Implementation of the basic-block entry hook instrumentation transform.
16 :
17 : #ifndef SYZYGY_INSTRUMENT_TRANSFORMS_BASIC_BLOCK_ENTRY_HOOK_TRANSFORM_H_
18 : #define SYZYGY_INSTRUMENT_TRANSFORMS_BASIC_BLOCK_ENTRY_HOOK_TRANSFORM_H_
19 :
20 : #include <string>
21 : #include <vector>
22 :
23 : #include "base/string_piece.h"
24 : #include "syzygy/block_graph/basic_block_assembler.h"
25 : #include "syzygy/block_graph/iterate.h"
26 : #include "syzygy/block_graph/transforms/iterative_transform.h"
27 : #include "syzygy/block_graph/transforms/named_transform.h"
28 : #include "syzygy/instrument/transforms/add_indexed_frequency_data_transform.h"
29 :
30 : namespace instrument {
31 : namespace transforms {
32 :
33 : // An iterative block transformation that augments the binary with an import
34 : // for a basic-block entry-hook function and, for each code basic-block,
35 : // prepends a call to the entry-hook function taking a unique basic-block ID.
36 : // The entry-hook function is responsible for being non-disruptive to the
37 : // the calling environment. I.e., it must preserve all volatile registers, any
38 : // registers it uses, and the processor flags.
39 : class BasicBlockEntryHookTransform
40 : : public block_graph::transforms::IterativeTransformImpl<
41 : BasicBlockEntryHookTransform>,
42 : public block_graph::transforms::NamedBasicBlockSubGraphTransformImpl<
43 : BasicBlockEntryHookTransform> {
44 : public:
45 : typedef block_graph::BlockGraph BlockGraph;
46 : typedef block_graph::BasicBlockSubGraph BasicBlockSubGraph;
47 : typedef core::RelativeAddress RelativeAddress;
48 : typedef core::AddressRange<RelativeAddress, size_t> RelativeAddressRange;
49 : typedef std::vector<RelativeAddressRange> RelativeAddressRangeVector;
50 :
51 : // Initialize a new BasicBlockEntryHookTransform instance using the default
52 : // module and function names.
53 : BasicBlockEntryHookTransform();
54 :
55 : // @returns the RVAs and sizes in the original image of the instrumented basic
56 : // blocks. They are in the order in which they were encountered during
57 : // instrumentation, such that the index of the BB in the vector serves
58 : // as its unique ID.
59 E : const RelativeAddressRangeVector& bb_ranges() const { return bb_ranges_; }
60 :
61 : // Overrides the default instrument dll name used by this transform.
62 E : void set_instrument_dll_name(const base::StringPiece& value) {
63 E : DCHECK(!value.empty());
64 E : instrument_dll_name_.assign(value.begin(), value.end());
65 E : }
66 :
67 : // Set a flag denoting whether or not src ranges should be created for the
68 : // thunks to the module entry hooks.
69 E : void set_src_ranges_for_thunks(bool value) {
70 E : set_src_ranges_for_thunks_ = value;
71 E : }
72 :
73 : protected:
74 : typedef std::map<BlockGraph::Offset, BlockGraph::Block*> ThunkBlockMap;
75 :
76 : friend NamedBlockGraphTransformImpl<BasicBlockEntryHookTransform>;
77 : friend IterativeTransformImpl<BasicBlockEntryHookTransform>;
78 : friend NamedBasicBlockSubGraphTransformImpl<BasicBlockEntryHookTransform>;
79 :
80 : // @name IterativeTransformImpl implementation.
81 : // @{
82 : bool PreBlockGraphIteration(BlockGraph* block_graph,
83 : BlockGraph::Block* header_block);
84 : bool OnBlock(BlockGraph* block_graph, BlockGraph::Block* block);
85 : bool PostBlockGraphIteration(BlockGraph* block_graph,
86 : BlockGraph::Block* header_block);
87 : // @}
88 :
89 : // @name BasicBlockSubGraphTransformInterface methods.
90 : // @{
91 : virtual bool TransformBasicBlockSubGraph(
92 : BlockGraph* block_graph,
93 : BasicBlockSubGraph* basic_block_subgraph) OVERRIDE;
94 : // @}
95 :
96 : // Add basic-block entry counting thunks for all entry points of a
97 : // @p code_block which is not basic-block decomposable.
98 : // @param block_graph The block graph in which to create the thunk.
99 : // @param code_block The code block which cannot be basic-block decomposed.
100 : // @returns true on success; false otherwise.
101 : bool ThunkNonDecomposableCodeBlock(BlockGraph* block_graph,
102 : BlockGraph::Block* code_block);
103 :
104 : // Redirects the given referrer to a thunk, creating the thunk if necessary.
105 : // @param referrer The details of the original referrer.
106 : // @param block_graph The block graph in which to create the thunk.
107 : // @param code_block The target block being thunked.
108 : // @param thunk_block_map A map (by target offset) of the thunks already
109 : // created. We only create a single thunk per target offset, which is
110 : // reused across referrers to the same target offset.
111 : // @returns true on success; false otherwise.
112 : bool EnsureReferrerIsThunked(const BlockGraph::Block::Referrer& referrer,
113 : BlockGraph* block_graph,
114 : BlockGraph::Block* block,
115 : ThunkBlockMap* thunk_block_map);
116 :
117 : // Add a basic-block entry counting thunk for an entry point at a given
118 : // @p offset of a @p code_block which is unsuitable for basic-block
119 : // decomposition.
120 : // @param block_graph The block graph in which to create the thunk.
121 : // @param thunk_block_map A catalog of thunk blocks created by this transform.
122 : // This will be updated if this function creates a new think.
123 : // @param code_block The code block which cannot be basic-block decomposed.
124 : // @param offset The offset of the entry point in @p code_block to thunk.
125 : // @param thunk The newly created thunk will be returned here.
126 : // @returns true on success; false otherwise.
127 : bool FindOrCreateThunk(BlockGraph* block_graph,
128 : ThunkBlockMap* thunk_block_map,
129 : BlockGraph::Block* code_block,
130 : BlockGraph::Offset offset,
131 : BlockGraph::Block** thunk);
132 :
133 : // Adds the basic-block frequency data referenced by the coverage agent.
134 : AddIndexedFrequencyDataTransform add_frequency_data_;
135 :
136 : // Stores the RVAs in the original image for each instrumented basic block.
137 : RelativeAddressRangeVector bb_ranges_;
138 :
139 : // The entry hook to which basic-block entry events are directed.
140 : BlockGraph::Reference bb_entry_hook_ref_;
141 :
142 : // The section where the entry-point thunks were placed. This will only be
143 : // non-NULL after a successful application of the transform. This value is
144 : // retained for unit-testing purposes.
145 : BlockGraph::Section* thunk_section_;
146 :
147 : // The instrumentation dll used by this transform.
148 : std::string instrument_dll_name_;
149 :
150 : // If true, the thunks will have src ranges corresponding to the original
151 : // code; otherwise, the thunks will not have src ranges set.
152 : bool set_src_ranges_for_thunks_;
153 :
154 : // The name of this transform.
155 : static const char kTransformName[];
156 :
157 : private:
158 : DISALLOW_COPY_AND_ASSIGN(BasicBlockEntryHookTransform);
159 : };
160 :
161 : } // namespace transforms
162 : } // namespace instrument
163 :
164 : #endif // SYZYGY_INSTRUMENT_TRANSFORMS_BASIC_BLOCK_ENTRY_HOOK_TRANSFORM_H_
|