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