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 : // Returns a flag denoting whether or not the instrumented application should
74 : // call the fast-path hook.
75 E : bool inline_fast_path() { return set_inline_fast_path_; }
76 :
77 : // Set a flag denoting whether or not the instrumented application should
78 : // call the fast-path hook.
79 E : void set_inline_fast_path(bool value) {
80 E : set_inline_fast_path_ = value;
81 E : }
82 :
83 : protected:
84 : typedef std::map<BlockGraph::Offset, BlockGraph::Block*> ThunkBlockMap;
85 :
86 : friend NamedBlockGraphTransformImpl<BasicBlockEntryHookTransform>;
87 : friend IterativeTransformImpl<BasicBlockEntryHookTransform>;
88 : friend NamedBasicBlockSubGraphTransformImpl<BasicBlockEntryHookTransform>;
89 :
90 : // @name IterativeTransformImpl implementation.
91 : // @{
92 : bool PreBlockGraphIteration(BlockGraph* block_graph,
93 : BlockGraph::Block* header_block);
94 : bool OnBlock(BlockGraph* block_graph, BlockGraph::Block* block);
95 : bool PostBlockGraphIteration(BlockGraph* block_graph,
96 : BlockGraph::Block* header_block);
97 : // @}
98 :
99 : // @name BasicBlockSubGraphTransformInterface methods.
100 : // @{
101 : virtual bool TransformBasicBlockSubGraph(
102 : BlockGraph* block_graph,
103 : BasicBlockSubGraph* basic_block_subgraph) OVERRIDE;
104 : // @}
105 :
106 : // Add basic-block entry counting thunks for all entry points of a
107 : // @p code_block which is not basic-block decomposable.
108 : // @param block_graph The block graph in which to create the thunk.
109 : // @param code_block The code block which cannot be basic-block decomposed.
110 : // @returns true on success; false otherwise.
111 : bool ThunkNonDecomposableCodeBlock(BlockGraph* block_graph,
112 : BlockGraph::Block* code_block);
113 :
114 : // Redirects the given referrer to a thunk, creating the thunk if necessary.
115 : // @param referrer The details of the original referrer.
116 : // @param block_graph The block graph in which to create the thunk.
117 : // @param code_block The target block being thunked.
118 : // @param thunk_block_map A map (by target offset) of the thunks already
119 : // created. We only create a single thunk per target offset, which is
120 : // reused across referrers to the same target offset.
121 : // @returns true on success; false otherwise.
122 : bool EnsureReferrerIsThunked(const BlockGraph::Block::Referrer& referrer,
123 : BlockGraph* block_graph,
124 : BlockGraph::Block* block,
125 : ThunkBlockMap* thunk_block_map);
126 :
127 : // Add a basic-block entry counting thunk for an entry point at a given
128 : // @p offset of a @p code_block which is unsuitable for basic-block
129 : // decomposition.
130 : // @param block_graph The block graph in which to create the thunk.
131 : // @param thunk_block_map A catalog of thunk blocks created by this transform.
132 : // This will be updated if this function creates a new think.
133 : // @param code_block The code block which cannot be basic-block decomposed.
134 : // @param offset The offset of the entry point in @p code_block to thunk.
135 : // @param thunk The newly created thunk will be returned here.
136 : // @returns true on success; false otherwise.
137 : bool FindOrCreateThunk(BlockGraph* block_graph,
138 : ThunkBlockMap* thunk_block_map,
139 : BlockGraph::Block* code_block,
140 : BlockGraph::Offset offset,
141 : BlockGraph::Block** thunk);
142 :
143 : // Create a fast path thunk in the instrumented application which updates the
144 : // basic block count or calls the hook in the agent.
145 : // @param block_graph The block graph in which to create the thunk.
146 : // @param fast_path_block On success, contains the newly created thunk.
147 : // @returns true on success; false otherwise.
148 : bool CreateBasicBlockEntryThunk(BlockGraph* block_graph,
149 : BlockGraph::Block** fast_path_block);
150 :
151 : // Adds the basic-block frequency data referenced by the coverage agent.
152 : AddIndexedFrequencyDataTransform add_frequency_data_;
153 :
154 : // Stores the RVAs in the original image for each instrumented basic block.
155 : RelativeAddressRangeVector bb_ranges_;
156 :
157 : // The entry hook to which basic-block entry events are directed.
158 : BlockGraph::Reference bb_entry_hook_ref_;
159 :
160 : // The entry hook to obtain raw frequency data pointer.
161 : BlockGraph::Reference fd_entry_hook_ref_;
162 :
163 : // The hook to call at each basic block entry.
164 : BlockGraph::Block* fast_bb_entry_block_;
165 :
166 : // The section where the entry-point thunks were placed. This will only be
167 : // non-NULL after a successful application of the transform. This value is
168 : // retained for unit-testing purposes.
169 : BlockGraph::Section* thunk_section_;
170 :
171 : // The instrumentation dll used by this transform.
172 : std::string instrument_dll_name_;
173 :
174 : // If true, the thunks will have src ranges corresponding to the original
175 : // code; otherwise, the thunks will not have src ranges set.
176 : bool set_src_ranges_for_thunks_;
177 :
178 : // If true, the instrumented application calls a fast injected hook before
179 : // falling back to the hook in the agent.
180 : bool set_inline_fast_path_;
181 :
182 : // The name of this transform.
183 : static const char kTransformName[];
184 :
185 : private:
186 : DISALLOW_COPY_AND_ASSIGN(BasicBlockEntryHookTransform);
187 : };
188 :
189 : } // namespace transforms
190 : } // namespace instrument
191 :
192 : #endif // SYZYGY_INSTRUMENT_TRANSFORMS_BASIC_BLOCK_ENTRY_HOOK_TRANSFORM_H_
|