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/strings/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 : // 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::BasicBlockSubGraph BasicBlockSubGraph;
46 : typedef block_graph::BlockGraph BlockGraph;
47 : typedef block_graph::TransformPolicyInterface TransformPolicyInterface;
48 : typedef core::RelativeAddress RelativeAddress;
49 : typedef core::AddressRange<RelativeAddress, size_t> RelativeAddressRange;
50 : typedef std::vector<RelativeAddressRange> RelativeAddressRangeVector;
51 :
52 : // Initialize a new BasicBlockEntryHookTransform instance using the default
53 : // module and function names.
54 : BasicBlockEntryHookTransform();
55 :
56 : // @returns the RVAs and sizes in the original image of the instrumented basic
57 : // blocks. They are in the order in which they were encountered during
58 : // instrumentation, such that the index of the BB in the vector serves
59 : // as its unique ID.
60 E : const RelativeAddressRangeVector& bb_ranges() const { return bb_ranges_; }
61 :
62 : // Overrides the default instrument dll name used by this transform.
63 E : void set_instrument_dll_name(const base::StringPiece& value) {
64 E : DCHECK(!value.empty());
65 E : instrument_dll_name_.assign(value.begin(), value.end());
66 E : }
67 :
68 : // Set a flag denoting whether or not src ranges should be created for the
69 : // thunks to the module entry hooks.
70 E : void set_src_ranges_for_thunks(bool value) {
71 E : set_src_ranges_for_thunks_ = value;
72 E : }
73 :
74 : // Returns a flag denoting whether or not the instrumented application should
75 : // call the fast-path hook.
76 E : bool inline_fast_path() { return set_inline_fast_path_; }
77 :
78 : // Set a flag denoting whether or not the instrumented application should
79 : // call the fast-path hook.
80 E : void set_inline_fast_path(bool value) {
81 E : set_inline_fast_path_ = value;
82 E : }
83 :
84 : protected:
85 : typedef std::map<BlockGraph::Offset, BlockGraph::Block*> ThunkBlockMap;
86 :
87 : friend NamedBlockGraphTransformImpl<BasicBlockEntryHookTransform>;
88 : friend IterativeTransformImpl<BasicBlockEntryHookTransform>;
89 : friend NamedBasicBlockSubGraphTransformImpl<BasicBlockEntryHookTransform>;
90 :
91 : // @name IterativeTransformImpl implementation.
92 : // @{
93 : bool PreBlockGraphIteration(const TransformPolicyInterface* policy,
94 : BlockGraph* block_graph,
95 : BlockGraph::Block* header_block);
96 : bool OnBlock(const TransformPolicyInterface* policy,
97 : BlockGraph* block_graph,
98 : BlockGraph::Block* block);
99 : bool PostBlockGraphIteration(const TransformPolicyInterface* policy,
100 : BlockGraph* block_graph,
101 : BlockGraph::Block* header_block);
102 : // @}
103 :
104 : // @name BasicBlockSubGraphTransformInterface implementation.
105 : // @{
106 : virtual bool TransformBasicBlockSubGraph(
107 : const TransformPolicyInterface* policy,
108 : BlockGraph* block_graph,
109 : BasicBlockSubGraph* basic_block_subgraph) override;
110 : // @}
111 :
112 : // Add basic-block entry counting thunks for all entry points of a
113 : // @p code_block which is not basic-block decomposable.
114 : // @param block_graph The block graph in which to create the thunk.
115 : // @param code_block The code block which cannot be basic-block decomposed.
116 : // @returns true on success; false otherwise.
117 : bool ThunkNonDecomposableCodeBlock(BlockGraph* block_graph,
118 : BlockGraph::Block* code_block);
119 :
120 : // Redirects the given referrer to a thunk, creating the thunk if necessary.
121 : // @param referrer The details of the original referrer.
122 : // @param block_graph The block graph in which to create the thunk.
123 : // @param code_block The target block being thunked.
124 : // @param thunk_block_map A map (by target offset) of the thunks already
125 : // created. We only create a single thunk per target offset, which is
126 : // reused across referrers to the same target offset.
127 : // @returns true on success; false otherwise.
128 : bool EnsureReferrerIsThunked(const BlockGraph::Block::Referrer& referrer,
129 : BlockGraph* block_graph,
130 : BlockGraph::Block* block,
131 : ThunkBlockMap* thunk_block_map);
132 :
133 : // Add a basic-block entry counting thunk for an entry point at a given
134 : // @p offset of a @p code_block which is unsuitable for basic-block
135 : // decomposition.
136 : // @param block_graph The block graph in which to create the thunk.
137 : // @param thunk_block_map A catalog of thunk blocks created by this transform.
138 : // This will be updated if this function creates a new think.
139 : // @param code_block The code block which cannot be basic-block decomposed.
140 : // @param offset The offset of the entry point in @p code_block to thunk.
141 : // @param thunk The newly created thunk will be returned here.
142 : // @returns true on success; false otherwise.
143 : bool FindOrCreateThunk(BlockGraph* block_graph,
144 : ThunkBlockMap* thunk_block_map,
145 : BlockGraph::Block* code_block,
146 : BlockGraph::Offset offset,
147 : BlockGraph::Block** thunk);
148 :
149 : // Create a fast path thunk in the instrumented application which updates the
150 : // basic block count or calls the hook in the agent.
151 : // @param block_graph The block graph in which to create the thunk.
152 : // @param fast_path_block On success, contains the newly created thunk.
153 : // @returns true on success; false otherwise.
154 : bool CreateBasicBlockEntryThunk(BlockGraph* block_graph,
155 : BlockGraph::Block** fast_path_block);
156 :
157 : // Adds the basic-block frequency data referenced by the coverage agent.
158 : AddIndexedFrequencyDataTransform add_frequency_data_;
159 :
160 : // Stores the RVAs in the original image for each instrumented basic block.
161 : RelativeAddressRangeVector bb_ranges_;
162 :
163 : // The entry hook to which basic-block entry events are directed.
164 : BlockGraph::Reference bb_entry_hook_ref_;
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_
|