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 : // Declares the decomposer, which decomposes a PE file into an ImageLayout and
16 : // its corresponding BlockGraph.
17 :
18 : #ifndef SYZYGY_PE_DECOMPOSER_H_
19 : #define SYZYGY_PE_DECOMPOSER_H_
20 :
21 : #include <windows.h> // NOLINT
22 : #include <dia2.h>
23 : #include <vector>
24 :
25 : #include "syzygy/pdb/pdb_file.h"
26 : #include "syzygy/pdb/pdb_stream.h"
27 : #include "syzygy/pe/dia_browser.h"
28 : #include "syzygy/pe/image_layout.h"
29 : #include "syzygy/pe/pe_file.h"
30 :
31 : namespace pe {
32 :
33 : // Forward declaration of a helper class where we hide our implementation
34 : // details.
35 : class DecomposerImpl;
36 :
37 : class Decomposer {
38 : public:
39 : struct IntermediateReference;
40 : typedef std::vector<IntermediateReference> IntermediateReferences;
41 :
42 : // The separator that is used between the multiple symbol names that can be
43 : // associated with a single label.
44 : static const char kLabelNameSep[];
45 :
46 : // Initialize the decomposer for a given image file.
47 : // @param image_file the image file to decompose. This must outlive the
48 : // instance of the decomposer.
49 : explicit Decomposer(const PEFile& image_file);
50 :
51 : // Decomposes the image file into a BlockGraph and an ImageLayout, which
52 : // have the breakdown of code and data blocks with typed references and
53 : // information on where the blocks resided in the original image,
54 : // respectively.
55 : // @returns true on success, false on failure.
56 : bool Decompose(ImageLayout* image_layout);
57 :
58 : // @name Mutators.
59 : // @{
60 : // Sets the PDB path to be used. If this is not called it will be inferred
61 : // using the information in the module, and searched for using the OS
62 : // search functionality.
63 : // @param pdb_path the path to the PDB file to be used in decomposing the
64 : // image.
65 E : void set_pdb_path(const base::FilePath& pdb_path) { pdb_path_ = pdb_path; }
66 : // @}
67 :
68 : // @name Accessors
69 : // @{
70 : // Accessor to the PDB path. If Decompose has been called successfully this
71 : // will reflect the path of the PDB file that was used to perform the
72 : // decomposition.
73 : // @returns the PDB path.
74 E : const base::FilePath& pdb_path() const { return pdb_path_; }
75 : // @}
76 :
77 : protected:
78 : typedef block_graph::BlockGraph BlockGraph;
79 : typedef core::RelativeAddress RelativeAddress;
80 :
81 : // Searches for (if necessary) the PDB file to be used in the decomposition,
82 : // and validates that the file exists and matches the module.
83 : bool FindAndValidatePdbPath();
84 :
85 : // @name Used for round-trip decomposition when a serialized block graph is
86 : // in the PDB. Exposed here for unittesting.
87 : // @{
88 : static bool LoadBlockGraphFromPdbStream(const PEFile& image_file,
89 : pdb::PdbStream* block_graph_stream,
90 : ImageLayout* image_layout);
91 : static bool LoadBlockGraphFromPdb(const base::FilePath& pdb_path,
92 : const PEFile& image_file,
93 : ImageLayout* image_layout,
94 : bool* stream_exists);
95 : // @}
96 :
97 : // @name Decomposition steps, in order.
98 : // @{
99 : // Performs the actual decomposition.
100 : bool DecomposeImpl();
101 : // Parses PE-related blocks and references.
102 : bool CreatePEImageBlocksAndReferences(IntermediateReferences* references);
103 : // Creates blocks from the COFF group symbols in the linker symbol stream.
104 : bool CreateBlocksFromCoffGroups();
105 : // Processes the SectionContribution table, creating code/data blocks from it.
106 : bool CreateBlocksFromSectionContribs(IDiaSession* session);
107 : // Processes the Compiland table and finds cold blocks.
108 : bool FindColdBlocksFromCompilands(IDiaSession* session);
109 : // Creates gap blocks to flesh out the image. After this has been run all
110 : // references should be resolvable.
111 : bool CreateGapBlocks();
112 : // Finalizes the given vector of intermediate references.
113 : bool FinalizeIntermediateReferences(const IntermediateReferences& references);
114 : // Creates inter-block references from fixups.
115 : bool CreateReferencesFromFixups(IDiaSession* session);
116 : // Processes symbols from the PDB, setting block names and labels. This
117 : // step is purely optional and only necessary to provide debug information.
118 : // This adds names to blocks, adds code labels and their names, and adds
119 : // more informative names to data labels.
120 : bool ProcessSymbols(IDiaSymbol* root);
121 : // @}
122 :
123 : // @{
124 : // @name Callbacks and context structures used by the COFF group parsing
125 : // mechanism.
126 : struct VisitLinkerSymbolContext;
127 : bool VisitLinkerSymbol(VisitLinkerSymbolContext* context,
128 : uint16 symbol_length,
129 : uint16 symbol_type,
130 : pdb::PdbStream* stream);
131 : // @}
132 :
133 : // @{
134 : // @name Callbacks used when parsing DIA symbols. Symbols only need to be
135 : // parsed for debug information and can be completely ignored otherwise.
136 : DiaBrowser::BrowserDirective OnPushFunctionOrThunkSymbol(
137 : const DiaBrowser& dia_browser,
138 : const DiaBrowser::SymTagVector& sym_tags,
139 : const DiaBrowser::SymbolPtrVector& symbols);
140 : DiaBrowser::BrowserDirective OnPopFunctionOrThunkSymbol(
141 : const DiaBrowser& dia_browser,
142 : const DiaBrowser::SymTagVector& sym_tags,
143 : const DiaBrowser::SymbolPtrVector& symbols);
144 : DiaBrowser::BrowserDirective OnFunctionChildSymbol(
145 : const DiaBrowser& dia_browser,
146 : const DiaBrowser::SymTagVector& sym_tags,
147 : const DiaBrowser::SymbolPtrVector& symbols);
148 : DiaBrowser::BrowserDirective OnDataSymbol(
149 : const DiaBrowser& dia_browser,
150 : const DiaBrowser::SymTagVector& sym_tags,
151 : const DiaBrowser::SymbolPtrVector& symbols);
152 : DiaBrowser::BrowserDirective OnPublicSymbol(
153 : const DiaBrowser& dia_browser,
154 : const DiaBrowser::SymTagVector& sym_tags,
155 : const DiaBrowser::SymbolPtrVector& symbols);
156 : DiaBrowser::BrowserDirective OnLabelSymbol(
157 : const DiaBrowser& dia_browser,
158 : const DiaBrowser::SymTagVector& sym_tags,
159 : const DiaBrowser::SymbolPtrVector& symbols);
160 : // @}
161 :
162 : // @name These are called within the scope of OnFunctionChildSymbol, during
163 : // which current_block_ is always set.
164 : // @{
165 : DiaBrowser::BrowserDirective OnScopeSymbol(enum SymTagEnum type,
166 : DiaBrowser::SymbolPtr symbol);
167 : DiaBrowser::BrowserDirective OnCallSiteSymbol(DiaBrowser::SymbolPtr symbol);
168 : // @}
169 :
170 : // @name Block creation members.
171 : // @{
172 : // Creates a new block with the given properties, and attaches the
173 : // data to it. This assumes that no conflicting block exists.
174 : BlockGraph::Block* CreateBlock(BlockGraph::BlockType type,
175 : RelativeAddress address,
176 : BlockGraph::Size size,
177 : const base::StringPiece& name);
178 : // Creates a new block with the given properties, or finds an existing PE
179 : // parsed block that subsumes it.
180 : BlockGraph::Block* CreateBlockOrFindCoveringPeBlock(
181 : BlockGraph::BlockType type,
182 : RelativeAddress address,
183 : BlockGraph::Size size,
184 : const base::StringPiece& name);
185 : // Creates a gap block of type @p block_type for the given range. For use by
186 : // CreateSectionGapBlocks.
187 : bool CreateGapBlock(BlockGraph::BlockType block_type,
188 : RelativeAddress address,
189 : BlockGraph::Size size);
190 : // Create blocks of type @p block_type for any gaps in the image
191 : // section represented by @p header.
192 : bool CreateSectionGapBlocks(const IMAGE_SECTION_HEADER* header,
193 : BlockGraph::BlockType block_type);
194 : // @}
195 :
196 : // The PEFile that is being decomposed.
197 : const PEFile& image_file_;
198 : // The path to corresponding PDB file.
199 : base::FilePath pdb_path_;
200 :
201 : // @name Temporaries that are only valid while inside DecomposeImpl.
202 : // Prevents us from having to pass these around everywhere.
203 : // @{
204 : // The image layout we're building.
205 : ImageLayout* image_layout_;
206 : // The image address space we're decomposing to.
207 : BlockGraph::AddressSpace* image_;
208 : // @}
209 :
210 : // Data structures holding the relation between functions and their cold
211 : // blocks outside of the function address space.
212 : // @{
213 : typedef std::map<core::RelativeAddress, BlockGraph::Block*> ColdBlocks;
214 : typedef std::map<BlockGraph::Block*, ColdBlocks> ColdBlocksMap;
215 : typedef std::map<BlockGraph::Block*, BlockGraph::Block*> ColdBlocksParent;
216 : ColdBlocksMap cold_blocks_;
217 : ColdBlocksParent cold_blocks_parent_;
218 : // @}
219 :
220 : // @name Temporaries that are only valid while in DiaBrowser.
221 : // @{
222 : BlockGraph::Block* current_block_;
223 : RelativeAddress current_address_;
224 : size_t current_scope_count_;
225 : // @}
226 : };
227 :
228 : } // namespace pe
229 :
230 : #endif // SYZYGY_PE_DECOMPOSER_H_
|