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 : #include "syzygy/pe/decomposer.h"
16 :
17 : #include "pcrecpp.h" // NOLINT
18 : #include "base/bind.h"
19 : #include "base/strings/string_split.h"
20 : #include "base/strings/stringprintf.h"
21 : #include "base/strings/utf_string_conversions.h"
22 : #include "base/win/scoped_bstr.h"
23 : #include "base/win/scoped_comptr.h"
24 : #include "syzygy/core/zstream.h"
25 : #include "syzygy/pdb/omap.h"
26 : #include "syzygy/pdb/pdb_byte_stream.h"
27 : #include "syzygy/pdb/pdb_constants.h"
28 : #include "syzygy/pdb/pdb_dbi_stream.h"
29 : #include "syzygy/pdb/pdb_file.h"
30 : #include "syzygy/pdb/pdb_reader.h"
31 : #include "syzygy/pdb/pdb_symbol_record.h"
32 : #include "syzygy/pdb/pdb_util.h"
33 : #include "syzygy/pe/dia_util.h"
34 : #include "syzygy/pe/find.h"
35 : #include "syzygy/pe/pe_file_parser.h"
36 : #include "syzygy/pe/pe_utils.h"
37 : #include "syzygy/pe/serialization.h"
38 : #include "third_party/cci/Files/CvInfo.h"
39 :
40 : namespace cci = Microsoft_Cci_Pdb;
41 :
42 : namespace {
43 :
44 : using block_graph::BlockGraph;
45 : using block_graph::BlockInfo;
46 : using core::AbsoluteAddress;
47 : using core::FileOffsetAddress;
48 : using core::RelativeAddress;
49 :
50 : typedef BlockGraph::Block Block;
51 :
52 : } // namespace
53 :
54 : namespace pe {
55 :
56 : // An intermediate reference representation used while parsing PE blocks.
57 : // This is necessary because at that point we haven't yet chunked the whole
58 : // image into blocks thus some references cannot be resolved.
59 : struct Decomposer::IntermediateReference {
60 : RelativeAddress src_addr;
61 : BlockGraph::ReferenceType type;
62 : BlockGraph::Size size;
63 : RelativeAddress dst_addr;
64 : };
65 :
66 : namespace {
67 :
68 : using base::win::ScopedBstr;
69 : using base::win::ScopedComPtr;
70 : using builder::Callback;
71 : using builder::Opt;
72 : using builder::Or;
73 : using builder::Seq;
74 : using builder::Star;
75 :
76 : typedef BlockGraph::BlockType BlockType;
77 : typedef BlockGraph::Offset Offset;
78 : typedef BlockGraph::Reference Reference;
79 : typedef BlockGraph::ReferenceType ReferenceType;
80 : typedef core::AddressRange<RelativeAddress, size_t> RelativeRange;
81 : typedef Decomposer::IntermediateReference IntermediateReference;
82 : typedef Decomposer::IntermediateReferences IntermediateReferences;
83 : typedef pcrecpp::RE RE;
84 : typedef std::vector<OMAP> OMAPs;
85 : typedef std::vector<pdb::PdbFixup> PdbFixups;
86 :
87 : const char kJumpTable[] = "<jump-table>";
88 : const char kCaseTable[] = "<case-table>";
89 :
90 : // The MS linker pads between code blocks with int3s.
91 : static const uint8_t kInt3 = 0xCC;
92 : static const size_t kPointerSize = BlockGraph::Reference::kMaximumSize;
93 :
94 : // Some helper functions for testing ranges.
95 : template<typename T1, typename T2, typename T3>
96 E : bool InRange(T1 value, T2 lower_bound_incl, T3 length_excl) {
97 E : T1 upper_bound_excl = static_cast<T1>(lower_bound_incl) + length_excl;
98 E : return static_cast<T1>(lower_bound_incl) <= value &&
99 : value < static_cast<T2>(upper_bound_excl);
100 E : }
101 : template<typename T1, typename T2, typename T3>
102 E : bool InRangeIncl(T1 value, T2 lower_bound_incl, T3 length_incl) {
103 E : T1 upper_bound_incl = static_cast<T1>(lower_bound_incl) + length_incl;
104 E : return static_cast<T1>(lower_bound_incl) <= value &&
105 : value <= upper_bound_incl;
106 E : }
107 :
108 : bool InitializeDia(const PEFile& image_file,
109 : const base::FilePath& pdb_path,
110 : IDiaDataSource** dia_source,
111 : IDiaSession** dia_session,
112 E : IDiaSymbol** global) {
113 E : DCHECK_EQ(reinterpret_cast<IDiaDataSource*>(NULL), *dia_source);
114 E : DCHECK_EQ(reinterpret_cast<IDiaSession*>(NULL), *dia_session);
115 E : DCHECK_EQ(reinterpret_cast<IDiaSymbol*>(NULL), *global);
116 :
117 E : if (!CreateDiaSource(dia_source))
118 i : return false;
119 E : DCHECK_NE(reinterpret_cast<IDiaDataSource*>(NULL), *dia_source);
120 :
121 : // We create the session using the PDB file directly, as we've already
122 : // validated that it matches the module.
123 E : if (!CreateDiaSession(pdb_path, *dia_source, dia_session))
124 i : return false;
125 E : DCHECK_NE(reinterpret_cast<IDiaSession*>(NULL), *dia_session);
126 :
127 E : HRESULT hr = (*dia_session)->get_globalScope(global);
128 E : if (hr != S_OK) {
129 i : LOG(ERROR) << "Failed to get the DIA global scope: "
130 : << common::LogHr(hr) << ".";
131 i : return false;
132 : }
133 :
134 E : return true;
135 E : }
136 :
137 : // Given a compiland, returns its compiland details.
138 : bool GetCompilandDetailsForCompiland(IDiaSymbol* compiland,
139 E : IDiaSymbol** compiland_details) {
140 E : DCHECK_NE(reinterpret_cast<IDiaSymbol*>(NULL), compiland);
141 E : DCHECK_NE(reinterpret_cast<IDiaSymbol**>(NULL), compiland_details);
142 E : DCHECK(IsSymTag(compiland, SymTagCompiland));
143 E : DCHECK_EQ(reinterpret_cast<IDiaSymbol*>(NULL), *compiland_details);
144 :
145 : // Get the enumeration of compiland details.
146 E : ScopedComPtr<IDiaEnumSymbols> enum_symbols;
147 E : HRESULT hr = compiland->findChildren(SymTagCompilandDetails, NULL, 0,
148 : enum_symbols.Receive());
149 E : DCHECK_EQ(S_OK, hr);
150 :
151 : // We expect there to be compiland details. For compilands built by
152 : // non-standard toolchains, there usually aren't any.
153 E : LONG count = 0;
154 E : hr = enum_symbols->get_Count(&count);
155 E : DCHECK_EQ(S_OK, hr);
156 E : if (count == 0) {
157 : // We don't log here because we see this quite often.
158 i : return false;
159 : }
160 :
161 : // We do sometimes encounter more than one compiland detail. In fact, for
162 : // import and export tables we get one compiland detail per table entry.
163 : // They are all marked as having been generated by the linker, so using the
164 : // first one is sufficient.
165 :
166 : // Get the compiland details.
167 E : ULONG fetched = 0;
168 E : hr = enum_symbols->Next(1, compiland_details, &fetched);
169 E : DCHECK_EQ(S_OK, hr);
170 E : DCHECK_EQ(1u, fetched);
171 :
172 E : return true;
173 E : }
174 :
175 : // Stores information regarding known compilers.
176 : struct KnownCompilerInfo {
177 : wchar_t* compiler_name;
178 : bool supported;
179 : };
180 :
181 : // A list of known compilers, and their status as being supported or not.
182 : KnownCompilerInfo kKnownCompilerInfos[] = {
183 : { L"Microsoft (R) Macro Assembler", false },
184 : { L"Microsoft (R) Optimizing Compiler", true },
185 : { L"Microsoft (R) LINK", false }
186 : };
187 :
188 : // Given a compiland, determines whether the compiler used is one of those that
189 : // we whitelist.
190 E : bool IsBuiltBySupportedCompiler(IDiaSymbol* compiland) {
191 E : DCHECK_NE(reinterpret_cast<IDiaSymbol*>(NULL), compiland);
192 E : DCHECK(IsSymTag(compiland, SymTagCompiland));
193 :
194 E : ScopedComPtr<IDiaSymbol> compiland_details;
195 E : if (!GetCompilandDetailsForCompiland(compiland,
196 : compiland_details.Receive())) {
197 : // If the compiland has no compiland details we assume the compiler is not
198 : // supported.
199 i : ScopedBstr compiland_name;
200 i : if (compiland->get_name(compiland_name.Receive()) == S_OK) {
201 i : VLOG(1) << "Compiland has no compiland details: "
202 : << common::ToString(compiland_name);
203 : }
204 i : return false;
205 : }
206 E : DCHECK_NE(reinterpret_cast<IDiaSymbol*>(NULL), compiland_details.get());
207 :
208 : // Get the compiler name.
209 E : ScopedBstr compiler_name;
210 E : HRESULT hr = compiland_details->get_compilerName(compiler_name.Receive());
211 E : DCHECK_EQ(S_OK, hr);
212 :
213 : // Check the compiler name against the list of known compilers.
214 E : for (size_t i = 0; i < arraysize(kKnownCompilerInfos); ++i) {
215 E : if (::wcscmp(kKnownCompilerInfos[i].compiler_name, compiler_name) == 0) {
216 E : return kKnownCompilerInfos[i].supported;
217 : }
218 E : }
219 :
220 : // Anything we don't explicitly know about is not supported.
221 E : VLOG(1) << "Encountered unknown compiler: " << compiler_name;
222 E : return false;
223 E : }
224 :
225 : // Adds an intermediate reference to the provided vector. The vector is
226 : // specified as the first parameter (in slight violation of our coding
227 : // standards) because this function is intended to be used by Bind.
228 : bool AddIntermediateReference(IntermediateReferences* references,
229 : RelativeAddress src_addr,
230 : ReferenceType type,
231 : BlockGraph::Size size,
232 E : RelativeAddress dst_addr) {
233 E : DCHECK_NE(reinterpret_cast<IntermediateReferences*>(NULL), references);
234 E : IntermediateReference ref = { src_addr, type, size, dst_addr };
235 E : references->push_back(ref);
236 E : return true;
237 E : }
238 :
239 : // Create a reference as specified. Ignores existing references if they are of
240 : // the exact same type.
241 : bool CreateReference(RelativeAddress src_addr,
242 : BlockGraph::Size ref_size,
243 : ReferenceType ref_type,
244 : RelativeAddress base_addr,
245 : RelativeAddress dst_addr,
246 E : BlockGraph::AddressSpace* image) {
247 E : DCHECK_NE(reinterpret_cast<BlockGraph::AddressSpace*>(NULL), image);
248 :
249 : // Get the source block and offset, and ensure that the reference fits
250 : // within it.
251 E : Block* src_block = image->GetBlockByAddress(src_addr);
252 E : if (src_block == NULL) {
253 i : LOG(ERROR) << "Unable to find block for reference originating at "
254 : << src_addr << ".";
255 i : return false;
256 : }
257 E : RelativeAddress src_block_addr;
258 E : CHECK(image->GetAddressOf(src_block, &src_block_addr));
259 E : Offset src_block_offset = src_addr - src_block_addr;
260 E : if (src_block_offset + ref_size > src_block->size()) {
261 i : LOG(ERROR) << "Reference originating at " << src_addr
262 : << " extends beyond block \"" << src_block->name() << "\".";
263 i : return false;
264 : }
265 :
266 : // Get the destination block and offset.
267 E : Block* dst_block = image->GetBlockByAddress(base_addr);
268 E : if (dst_block == NULL) {
269 i : LOG(ERROR) << "Unable to find block for reference pointing at "
270 : << base_addr << ".";
271 i : return false;
272 : }
273 E : RelativeAddress dst_block_addr;
274 E : CHECK(image->GetAddressOf(dst_block, &dst_block_addr));
275 E : Offset base = base_addr - dst_block_addr;
276 E : Offset offset = dst_addr - dst_block_addr;
277 :
278 E : Reference ref(ref_type, ref_size, dst_block, offset, base);
279 :
280 : // Check if a reference already exists at this offset.
281 : Block::ReferenceMap::const_iterator ref_it =
282 E : src_block->references().find(src_block_offset);
283 E : if (ref_it != src_block->references().end()) {
284 : // If an identical reference already exists then we're done.
285 E : if (ref == ref_it->second)
286 E : return true;
287 i : LOG(ERROR) << "Block \"" << src_block->name() << "\" has a conflicting "
288 : << "reference at offset " << src_block_offset << ".";
289 i : return false;
290 : }
291 :
292 E : CHECK(src_block->SetReference(src_block_offset, ref));
293 :
294 E : return true;
295 E : }
296 :
297 : // Loads FIXUP and OMAP_FROM debug streams.
298 : bool LoadDebugStreams(IDiaSession* dia_session,
299 : PdbFixups* pdb_fixups,
300 E : OMAPs* omap_from) {
301 E : DCHECK_NE(reinterpret_cast<IDiaSession*>(NULL), dia_session);
302 E : DCHECK_NE(reinterpret_cast<PdbFixups*>(NULL), pdb_fixups);
303 E : DCHECK_NE(reinterpret_cast<OMAPs*>(NULL), omap_from);
304 :
305 : // Load the fixups. These must exist.
306 E : SearchResult search_result = FindAndLoadDiaDebugStreamByName(
307 : kFixupDiaDebugStreamName, dia_session, pdb_fixups);
308 E : if (search_result != kSearchSucceeded) {
309 i : if (search_result == kSearchFailed) {
310 i : LOG(ERROR) << "PDB file does not contain a FIXUP stream. Module must be "
311 : "linked with '/PROFILE' or '/DEBUGINFO:FIXUP' flag.";
312 : }
313 i : return false;
314 : }
315 :
316 : // Load the omap_from table. It is not necessary that one exist.
317 E : search_result = FindAndLoadDiaDebugStreamByName(
318 : kOmapFromDiaDebugStreamName, dia_session, omap_from);
319 E : if (search_result == kSearchErrored) {
320 i : LOG(ERROR) << "Error trying to read " << kOmapFromDiaDebugStreamName
321 : << " stream.";
322 i : return false;
323 : }
324 :
325 E : return true;
326 E : }
327 :
328 : bool GetFixupDestinationAndType(const PEFile& image_file,
329 : const pdb::PdbFixup& fixup,
330 : RelativeAddress* dst_addr,
331 E : ReferenceType* ref_type) {
332 E : DCHECK_NE(reinterpret_cast<RelativeAddress*>(NULL), dst_addr);
333 E : DCHECK_NE(reinterpret_cast<ReferenceType*>(NULL), ref_type);
334 :
335 E : RelativeAddress src_addr(fixup.rva_location);
336 :
337 : // Get the destination displacement from the actual image itself. We only see
338 : // fixups for 32-bit references.
339 E : uint32_t data = 0;
340 E : if (!image_file.ReadImage(src_addr, &data, sizeof(data))) {
341 i : LOG(ERROR) << "Unable to read image data for fixup with source address "
342 : << "at" << src_addr << ".";
343 i : return false;
344 : }
345 :
346 : // Translate this to a relative displacement value.
347 E : switch (fixup.type) {
348 : case pdb::PdbFixup::TYPE_ABSOLUTE: {
349 E : *ref_type = BlockGraph::ABSOLUTE_REF;
350 E : *dst_addr = RelativeAddress(image_file.AbsToRelDisplacement(data));
351 E : break;
352 : }
353 :
354 : case pdb::PdbFixup::TYPE_PC_RELATIVE: {
355 E : *ref_type = BlockGraph::PC_RELATIVE_REF;
356 E : *dst_addr = RelativeAddress(fixup.rva_location) + sizeof(data) + data;
357 E : break;
358 : }
359 :
360 : case pdb::PdbFixup::TYPE_RELATIVE: {
361 E : *ref_type = BlockGraph::RELATIVE_REF;
362 E : *dst_addr = RelativeAddress(data);
363 E : break;
364 : }
365 :
366 : default: {
367 i : LOG(ERROR) << "Unexpected fixup type (" << fixup.type << ").";
368 i : return false;
369 : }
370 : }
371 :
372 E : return true;
373 E : }
374 :
375 : // Creates references from the @p pdb_fixups (translating them via the
376 : // provided @p omap_from information if it is not empty), all while removing the
377 : // corresponding entries from @p reloc_set. If @p reloc_set is not empty after
378 : // this then the PDB fixups are out of sync with the image and we are unable to
379 : // safely decompose.
380 : //
381 : // @note This function deliberately ignores fixup information for the resource
382 : // section. This is because chrome.dll gets modified by a manifest tool
383 : // which doesn't update the FIXUPs in the corresponding PDB. They are thus
384 : // out of sync. Even if they were in sync this doesn't harm us as we have no
385 : // need to reach in and modify resource data.
386 : bool CreateReferencesFromFixupsImpl(
387 : const PEFile& image_file,
388 : const PdbFixups& pdb_fixups,
389 : const OMAPs& omap_from,
390 : PEFile::RelocSet* reloc_set,
391 E : BlockGraph::AddressSpace* image) {
392 E : DCHECK_NE(reinterpret_cast<PEFile::RelocSet*>(NULL), reloc_set);
393 E : DCHECK_NE(reinterpret_cast<BlockGraph::AddressSpace*>(NULL), image);
394 :
395 E : bool have_omap = !omap_from.empty();
396 E : size_t fixups_used = 0;
397 :
398 : // The resource section in Chrome is modified post-link by a tool that adds a
399 : // manifest to it. This causes all of the fixups in the resource section (and
400 : // anything beyond it) to be invalid. As long as the resource section is the
401 : // last section in the image, this is not a problem (we can safely ignore the
402 : // .rsrc fixups, which we know how to parse without them). However, if there
403 : // is a section after the resource section, things will have been shifted
404 : // and potentially crucial fixups will be invalid.
405 E : const IMAGE_SECTION_HEADER* rsrc_header = image_file.GetSectionHeader(
406 : kResourceSectionName);
407 E : RelativeAddress rsrc_start(0xffffffff);
408 E : RelativeAddress rsrc_end(0xffffffff);
409 E : if (rsrc_header != NULL) {
410 E : rsrc_start = RelativeAddress(rsrc_header->VirtualAddress);
411 E : rsrc_end = rsrc_start + rsrc_header->Misc.VirtualSize;
412 : }
413 :
414 : // Ensure the fixups are all valid.
415 E : for (size_t i = 0; i < pdb_fixups.size(); ++i) {
416 E : if (!pdb_fixups[i].ValidHeader()) {
417 i : LOG(ERROR) << "Unknown fixup header: "
418 : << base::StringPrintf("0x%08X.", pdb_fixups[i].header);
419 i : return false;
420 : }
421 :
422 : // For now, we skip any offset fixups. We've only seen this in the context
423 : // of TLS data access, and we don't mess with TLS structures.
424 E : if (pdb_fixups[i].is_offset())
425 E : continue;
426 :
427 : // All fixups we handle should be full size pointers.
428 E : DCHECK_EQ(Reference::kMaximumSize, pdb_fixups[i].size());
429 :
430 : // Get the original addresses, and map them through OMAP information.
431 : // Normally DIA takes care of this for us, but there is no API for
432 : // getting DIA to give us FIXUP information, so we have to do it manually.
433 E : RelativeAddress src_addr(pdb_fixups[i].rva_location);
434 E : RelativeAddress base_addr(pdb_fixups[i].rva_base);
435 E : if (have_omap) {
436 i : src_addr = pdb::TranslateAddressViaOmap(omap_from, src_addr);
437 i : base_addr = pdb::TranslateAddressViaOmap(omap_from, base_addr);
438 : }
439 :
440 : // If the reference originates beyond the .rsrc section then we can't
441 : // trust it.
442 E : if (src_addr >= rsrc_end) {
443 i : LOG(ERROR) << "Found fixup originating beyond .rsrc section.";
444 i : return false;
445 : }
446 :
447 : // If the reference originates from a part of the .rsrc section, ignore it.
448 E : if (src_addr >= rsrc_start)
449 E : continue;
450 :
451 : // Get the relative address/displacement of the fixup. This logs on failure.
452 E : RelativeAddress dst_addr;
453 E : ReferenceType type = BlockGraph::RELATIVE_REF;
454 E : if (!GetFixupDestinationAndType(image_file, pdb_fixups[i], &dst_addr,
455 : &type)) {
456 i : return false;
457 : }
458 :
459 : // Finally, create the reference. This logs verbosely for us on failure.
460 E : if (!CreateReference(src_addr, Reference::kMaximumSize, type, base_addr,
461 : dst_addr, image)) {
462 i : return false;
463 : }
464 :
465 : // Remove this reference from the relocs.
466 E : PEFile::RelocSet::iterator reloc_it = reloc_set->find(src_addr);
467 E : if (reloc_it != reloc_set->end()) {
468 : // We should only find a reloc if the fixup was of absolute type.
469 E : if (type != BlockGraph::ABSOLUTE_REF) {
470 i : LOG(ERROR) << "Found a reloc corresponding to a non-absolute fixup.";
471 i : return false;
472 : }
473 :
474 E : reloc_set->erase(reloc_it);
475 : }
476 :
477 E : ++fixups_used;
478 E : }
479 :
480 E : return true;
481 E : }
482 :
483 E : bool GetDataSymbolSize(IDiaSymbol* symbol, size_t* length) {
484 E : DCHECK_NE(reinterpret_cast<IDiaSymbol*>(NULL), symbol);
485 E : DCHECK_NE(reinterpret_cast<size_t*>(NULL), length);
486 :
487 E : *length = 0;
488 E : ScopedComPtr<IDiaSymbol> type;
489 E : HRESULT hr = symbol->get_type(type.Receive());
490 : // This happens if the symbol has no type information.
491 E : if (hr == S_FALSE)
492 E : return true;
493 E : if (hr != S_OK) {
494 i : LOG(ERROR) << "Failed to get type symbol: " << common::LogHr(hr) << ".";
495 i : return false;
496 : }
497 :
498 E : ULONGLONG ull_length = 0;
499 E : hr = type->get_length(&ull_length);
500 E : if (hr != S_OK) {
501 i : LOG(ERROR) << "Failed to retrieve type length properties: "
502 : << common::LogHr(hr) << ".";
503 i : return false;
504 : }
505 E : DCHECK_LE(ull_length, 0xFFFFFFFF);
506 E : *length = static_cast<size_t>(ull_length);
507 :
508 E : return true;
509 E : }
510 :
511 : bool ScopeSymTagToLabelProperties(enum SymTagEnum sym_tag,
512 : size_t scope_count,
513 : BlockGraph::LabelAttributes* attr,
514 E : std::string* name) {
515 E : DCHECK_NE(reinterpret_cast<BlockGraph::LabelAttributes*>(NULL), attr);
516 E : DCHECK_NE(reinterpret_cast<std::string*>(NULL), name);
517 :
518 E : switch (sym_tag) {
519 : case SymTagFuncDebugStart: {
520 E : *attr = BlockGraph::DEBUG_START_LABEL;
521 E : *name = "<debug-start>";
522 E : return true;
523 : }
524 : case SymTagFuncDebugEnd: {
525 E : *attr = BlockGraph::DEBUG_END_LABEL;
526 E : *name = "<debug-end>";
527 E : return true;
528 : }
529 : case SymTagBlock: {
530 E : *attr = BlockGraph::SCOPE_START_LABEL;
531 E : *name = base::StringPrintf("<scope-start-%d>", scope_count);
532 E : return true;
533 : }
534 : default:
535 i : return false;
536 : }
537 i : return false;
538 E : }
539 :
540 : // Reads the linker module symbol stream from the given PDB file. This should
541 : // always exist as the last module.
542 : scoped_refptr<pdb::PdbStream> GetLinkerSymbolStream(
543 E : const pdb::PdbFile& pdb_file) {
544 : static const char kLinkerModuleName[] = "* Linker *";
545 :
546 : // Get the DBI stream.
547 : scoped_refptr<pdb::PdbStream> stream =
548 E : pdb_file.GetStream(pdb::kDbiStream);
549 E : if (stream.get() == NULL) {
550 i : LOG(ERROR) << "PDB does not contain a DBI stream.";
551 i : return false;
552 : }
553 :
554 : // Read the entire thing into memory before parsing it. This makes parsing
555 : // much faster.
556 E : scoped_refptr<pdb::PdbByteStream> dbi_stream(new pdb::PdbByteStream());
557 E : if (!dbi_stream->Init(stream.get())) {
558 i : LOG(ERROR) << "Failed to read DBI stream.";
559 : }
560 :
561 : // Parse the DBI stream.
562 E : pdb::DbiStream dbi;
563 E : if (!dbi.Read(dbi_stream.get())) {
564 i : LOG(ERROR) << "Unable to parse DBI stream.";
565 i : return false;
566 : }
567 :
568 E : if (dbi.modules().empty()) {
569 i : LOG(ERROR) << "DBI stream contains no modules.";
570 i : return false;
571 : }
572 :
573 : // The last module has always been observed to be the linker module.
574 E : const pdb::DbiModuleInfo& linker = dbi.modules().back();
575 E : if (linker.module_name() != kLinkerModuleName) {
576 i : LOG(ERROR) << "Last module is not the linker module.";
577 i : return false;
578 : }
579 :
580 : // Get the symbol stream.
581 E : stream = pdb_file.GetStream(linker.module_info_base().stream);
582 E : if (stream.get() == NULL) {
583 i : LOG(ERROR) << "Unable to open linker symbol stream.";
584 i : return false;
585 : }
586 :
587 : // Also read it entirely into memory for faster parsing.
588 E : scoped_refptr<pdb::PdbByteStream> symbols(new pdb::PdbByteStream());
589 E : if (!symbols->Init(stream.get())) {
590 i : LOG(ERROR) << "Failed to read linker symbol stream.";
591 : }
592 :
593 E : return symbols;
594 E : }
595 :
596 : // Parses a symbol from a PDB symbol stream. The @p buffer is populated with the
597 : // data and upon success this returns the symbol directly cast onto the
598 : // @p buffer data. On failure this returns NULL.
599 : template <typename SymbolType>
600 : const SymbolType* ParseSymbol(uint16_t symbol_length,
601 : common::BinaryStreamReader* reader,
602 E : std::vector<uint8_t>* buffer) {
603 E : DCHECK_NE(static_cast<common::BinaryStreamReader*>(nullptr), reader);
604 E : DCHECK_NE(static_cast<std::vector<uint8_t>*>(nullptr), buffer);
605 :
606 E : buffer->clear();
607 :
608 E : if (symbol_length < sizeof(SymbolType)) {
609 i : LOG(ERROR) << "Symbol too small for casting.";
610 i : return NULL;
611 : }
612 :
613 E : common::BinaryStreamParser parser(reader);
614 E : if (!parser.ReadMultiple(symbol_length, buffer)) {
615 i : LOG(ERROR) << "Failed to read symbol.";
616 i : return NULL;
617 : }
618 :
619 E : return reinterpret_cast<const SymbolType*>(buffer->data());
620 E : }
621 :
622 : // If the given run of bytes consists of a single value repeated, returns that
623 : // value. Otherwise, returns -1.
624 E : int RepeatedValue(const uint8_t* data, size_t size) {
625 E : DCHECK_NE(reinterpret_cast<uint8_t*>(NULL), data);
626 E : const uint8_t* data_end = data + size;
627 E : uint8_t value = *(data++);
628 E : for (; data < data_end; ++data) {
629 E : if (*data != value)
630 i : return -1;
631 E : }
632 E : return value;
633 E : }
634 :
635 : // Searches through the given image layout graph, and labels blocks that are
636 : // simply padding blocks.
637 E : bool FindPaddingBlocks(ImageLayout* image_layout) {
638 E : DCHECK_NE(reinterpret_cast<ImageLayout*>(NULL), image_layout);
639 :
640 E : BlockGraph* block_graph = image_layout->blocks.graph();
641 E : DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
642 :
643 : BlockGraph::BlockMap::iterator block_it =
644 E : block_graph->blocks_mutable().begin();
645 E : for (; block_it != block_graph->blocks_mutable().end(); ++block_it) {
646 E : Block& block = block_it->second;
647 :
648 : // Padding blocks must not have any symbol information: no labels,
649 : // no references, no referrers, and they must be a gap block.
650 : if (block.labels().size() != 0 ||
651 : block.references().size() != 0 ||
652 E : block.referrers().size() != 0 ||
653 : (block.attributes() & BlockGraph::GAP_BLOCK) == 0) {
654 E : continue;
655 : }
656 :
657 E : switch (block.type()) {
658 : // Code blocks should be fully defined and consist of only int3s.
659 : case BlockGraph::CODE_BLOCK: {
660 E : if (block.data_size() != block.size() ||
661 : RepeatedValue(block.data(), block.data_size()) != kInt3)
662 i : continue;
663 E : break;
664 : }
665 :
666 : // Data blocks should be uninitialized or have fully defined data
667 : // consisting only of zeros.
668 : default: {
669 E : DCHECK_EQ(BlockGraph::DATA_BLOCK, block.type());
670 E : if (block.data_size() == 0) // Uninitialized data blocks are padding.
671 E : break;
672 E : if (block.data_size() != block.size() ||
673 : RepeatedValue(block.data(), block.data_size()) != 0)
674 i : continue;
675 : }
676 : }
677 :
678 : // If we fall through to this point, then the block is a padding block.
679 E : block.set_attribute(BlockGraph::PADDING_BLOCK);
680 E : }
681 :
682 E : return true;
683 E : }
684 :
685 E : bool CodeBlockHasAlignedJumpTables(const Block* block) {
686 E : DCHECK_NE(reinterpret_cast<Block*>(NULL), block);
687 E : DCHECK_EQ(BlockGraph::CODE_BLOCK, block->type());
688 :
689 : // Iterate over the labels of this block looking for jump tables.
690 E : bool has_jump_tables = false;
691 : Block::LabelMap::const_iterator label_it =
692 E : block->labels().begin();
693 E : for (; label_it != block->labels().end(); ++label_it) {
694 E : if (!label_it->second.has_attributes(BlockGraph::JUMP_TABLE_LABEL))
695 E : continue;
696 :
697 E : has_jump_tables = true;
698 :
699 : // If the jump table is misaligned we can return false immediately.
700 E : if (label_it->first % kPointerSize != 0)
701 i : return false;
702 E : }
703 :
704 E : return has_jump_tables;
705 E : }
706 :
707 E : bool AlignCodeBlocks(ImageLayout* image_layout) {
708 E : DCHECK_NE(reinterpret_cast<ImageLayout*>(NULL), image_layout);
709 :
710 : BlockGraph::AddressSpace::RangeMapConstIter block_it =
711 E : image_layout->blocks.begin();
712 E : for (; block_it != image_layout->blocks.end(); ++block_it) {
713 E : Block* block = block_it->second;
714 E : if (block->type() != BlockGraph::CODE_BLOCK)
715 E : continue;
716 :
717 : // Preserve alignment for anything built by an unknown compiler. There may
718 : // be inline data that has alignment requirements we don't know about. SSE
719 : // and AVX instructions have 8 and 16 byte alignments, so we preserve
720 : // these. It is not possible for a function to contain both instructions
721 : // and data with an alignment constraint unless the size of the block is at
722 : // least twice the alignment; this is used as a simple filter to avoid
723 : // adding alignment where unnecessary.
724 E : if (block->attributes() & BlockGraph::BUILT_BY_UNSUPPORTED_COMPILER) {
725 E : uint32_t align = std::min(16u, static_cast<uint32_t>(
726 : block_it->first.start().GetAlignment()));
727 E : if (align >= 8 && block->size() >= 2 * align) {
728 E : VLOG(1) << "Preserving alignment of " << BlockInfo(block) << " as "
729 : << align << ".";
730 E : block->set_alignment(align);
731 E : continue;
732 : }
733 : }
734 :
735 : // We only care about code blocks that are already 4-byte aligned but
736 : // whose explicit alignment is currently less than that.
737 E : if (block->alignment() >= kPointerSize)
738 i : continue;
739 E : if (block_it->first.start().value() % kPointerSize != 0)
740 E : continue;
741 :
742 : // Inspect them to see if they have aligned jump tables. If they do,
743 : // set the alignment of the block itself.
744 E : if (CodeBlockHasAlignedJumpTables(block_it->second))
745 E : block->set_alignment(kPointerSize);
746 E : }
747 :
748 E : return true;
749 E : }
750 :
751 : void GuessDataBlockAlignment(uint32_t max_alignment,
752 : RelativeAddress block_rva,
753 E : Block* block) {
754 E : DCHECK_NE(static_cast<Block*>(NULL), block);
755 E : DCHECK_EQ(BlockGraph::DATA_BLOCK, block->type());
756 E : uint32_t alignment = static_cast<uint32_t>(block_rva.GetAlignment());
757 : // Cap the alignment.
758 E : if (alignment > max_alignment)
759 E : alignment = max_alignment;
760 E : block->set_alignment(alignment);
761 E : }
762 :
763 : void GuessDataBlockAlignments(const PEFile& pe_file,
764 E : ImageLayout* image_layout) {
765 E : DCHECK_NE(static_cast<ImageLayout*>(NULL), image_layout);
766 :
767 : uint32_t max_alignment =
768 E : pe_file.nt_headers()->OptionalHeader.SectionAlignment;
769 :
770 E : BlockGraph::AddressSpace::RangeMapConstIter it = image_layout->blocks.begin();
771 E : for (; it != image_layout->blocks.end(); ++it) {
772 E : RelativeAddress block_rva = it->first.start();
773 E : BlockGraph::Block* block = it->second;
774 E : if (block->type() != BlockGraph::DATA_BLOCK)
775 E : continue;
776 E : GuessDataBlockAlignment(max_alignment, block_rva, block);
777 E : }
778 E : }
779 :
780 : } // namespace
781 :
782 : // We use ", " as a separator between symbol names. We sometimes see commas
783 : // in symbol names but do not see whitespace. Thus, this provides a useful
784 : // separator that is also human friendly to read.
785 : const char Decomposer::kLabelNameSep[] = ", ";
786 :
787 : // This is by CreateBlocksFromCoffGroups to communicate shared state to
788 : // VisitLinkerSymbol via the VisitSymbols helper function.
789 : struct Decomposer::VisitLinkerSymbolContext {
790 : int current_group_index;
791 : std::string current_group_prefix;
792 : RelativeAddress current_group_start;
793 :
794 : // These are the set of patterns that indicate bracketing groups. They
795 : // should match both the opening and the closing symbol, and have at least
796 : // one match group returning the common prefix.
797 : std::vector<RE> bracketing_groups;
798 :
799 E : VisitLinkerSymbolContext() : current_group_index(-1) {
800 : // Matches groups like: .CRT$XCA -> .CRT$XCZ
801 E : bracketing_groups.push_back(RE("(\\.CRT\\$X.)[AZ]"));
802 : // Matches groups like: .rtc$IAA -> .rtc$IZZ
803 E : bracketing_groups.push_back(RE("(\\.rtc\\$.*)(AA|ZZ)"));
804 : // Matches exactly: ATL$__a -> ATL$__z
805 E : bracketing_groups.push_back(RE("(ATL\\$__)[az]"));
806 : // Matches exactly: .tls -> .tls$ZZZ
807 E : bracketing_groups.push_back(RE("(\\.tls)(\\$ZZZ)?"));
808 E : }
809 :
810 : private:
811 : DISALLOW_COPY_AND_ASSIGN(VisitLinkerSymbolContext);
812 : };
813 :
814 : Decomposer::Decomposer(const PEFile& image_file)
815 E : : image_file_(image_file), image_layout_(NULL), image_(NULL),
816 E : current_block_(NULL), current_scope_count_(0) {
817 E : }
818 :
819 E : bool Decomposer::Decompose(ImageLayout* image_layout) {
820 E : DCHECK_NE(reinterpret_cast<ImageLayout*>(NULL), image_layout);
821 :
822 : // The temporaries should be NULL.
823 E : DCHECK_EQ(reinterpret_cast<ImageLayout*>(NULL), image_layout_);
824 E : DCHECK_EQ(reinterpret_cast<BlockGraph::AddressSpace*>(NULL), image_);
825 :
826 : // Set the image format.
827 E : image_layout->blocks.graph()->set_image_format(BlockGraph::PE_IMAGE);
828 :
829 : // We start by finding the PDB path.
830 E : if (!FindAndValidatePdbPath())
831 E : return false;
832 E : DCHECK(!pdb_path_.empty());
833 :
834 : // Load the serialized block-graph from the PDB if it exists. This allows
835 : // round-trip decomposition.
836 E : bool stream_exists = false;
837 E : if (LoadBlockGraphFromPdb(
838 : pdb_path_, image_file_, image_layout, &stream_exists)) {
839 E : return true;
840 E : } else if (stream_exists) {
841 : // If the stream exists but hasn't been loaded we return an error. At this
842 : // point an error message has already been logged if there was one.
843 i : return false;
844 : }
845 :
846 : // At this point a full decomposition needs to be performed.
847 E : image_layout_ = image_layout;
848 E : image_ = &(image_layout->blocks);
849 E : bool success = DecomposeImpl();
850 E : image_layout_ = NULL;
851 E : image_ = NULL;
852 :
853 E : return success;
854 E : }
855 :
856 E : bool Decomposer::FindAndValidatePdbPath() {
857 : // Manually find the PDB path if it is not specified.
858 E : if (pdb_path_.empty()) {
859 E : if (!FindPdbForModule(image_file_.path(), &pdb_path_) ||
860 : pdb_path_.empty()) {
861 i : LOG(ERROR) << "Unable to find PDB file for module: "
862 : << image_file_.path().value();
863 i : return false;
864 : }
865 : }
866 E : DCHECK(!pdb_path_.empty());
867 :
868 E : if (!base::PathExists(pdb_path_)) {
869 E : LOG(ERROR) << "Path not found: " << pdb_path_.value();
870 E : return false;
871 : }
872 :
873 E : if (!pe::PeAndPdbAreMatched(image_file_.path(), pdb_path_)) {
874 i : LOG(ERROR) << "PDB file \"" << pdb_path_.value() << "\" does not match "
875 : << "module \"" << image_file_.path().value() << "\".";
876 i : return false;
877 : }
878 :
879 E : return true;
880 E : }
881 :
882 : bool Decomposer::LoadBlockGraphFromPdbStream(
883 : const PEFile& image_file,
884 : pdb::PdbStream* block_graph_stream,
885 E : ImageLayout* image_layout) {
886 E : DCHECK_NE(reinterpret_cast<pdb::PdbStream*>(NULL), block_graph_stream);
887 E : DCHECK_NE(reinterpret_cast<ImageLayout*>(NULL), image_layout);
888 E : LOG(INFO) << "Reading block-graph and image layout from the PDB.";
889 :
890 : // Initialize an input archive pointing to the stream.
891 E : scoped_refptr<pdb::PdbByteStream> byte_stream = new pdb::PdbByteStream();
892 E : if (!byte_stream->Init(block_graph_stream))
893 i : return false;
894 E : DCHECK_NE(reinterpret_cast<pdb::PdbByteStream*>(NULL), byte_stream.get());
895 :
896 E : core::ScopedInStreamPtr pdb_in_stream;
897 E : pdb_in_stream.reset(core::CreateByteInStream(
898 : byte_stream->data(), byte_stream->data() + byte_stream->length()));
899 :
900 : // Read the header.
901 E : uint32_t stream_version = 0;
902 E : unsigned char compressed = 0;
903 : if (!pdb_in_stream->Read(sizeof(stream_version),
904 E : reinterpret_cast<core::Byte*>(&stream_version)) ||
905 : !pdb_in_stream->Read(sizeof(compressed),
906 : reinterpret_cast<core::Byte*>(&compressed))) {
907 i : LOG(ERROR) << "Failed to read existing Syzygy block-graph stream header.";
908 i : return false;
909 : }
910 :
911 : // Check the stream version.
912 E : if (stream_version != pdb::kSyzygyBlockGraphStreamVersion) {
913 E : LOG(ERROR) << "PDB contains an unsupported Syzygy block-graph stream"
914 : << " version (got " << stream_version << ", expected "
915 : << pdb::kSyzygyBlockGraphStreamVersion << ").";
916 E : return false;
917 : }
918 :
919 : // If the stream is compressed insert the decompression filter.
920 E : core::InStream* in_stream = pdb_in_stream.get();
921 E : std::unique_ptr<core::ZInStream> zip_in_stream;
922 E : if (compressed != 0) {
923 E : zip_in_stream.reset(new core::ZInStream(in_stream));
924 E : if (!zip_in_stream->Init()) {
925 i : LOG(ERROR) << "Unable to initialize ZInStream.";
926 i : return false;
927 : }
928 E : in_stream = zip_in_stream.get();
929 : }
930 :
931 : // Deserialize the image-layout.
932 E : core::NativeBinaryInArchive in_archive(in_stream);
933 E : block_graph::BlockGraphSerializer::Attributes attributes = 0;
934 E : if (!LoadBlockGraphAndImageLayout(
935 : image_file, &attributes, image_layout, &in_archive)) {
936 i : LOG(ERROR) << "Failed to deserialize block-graph and image layout.";
937 i : return false;
938 : }
939 :
940 E : return true;
941 E : }
942 :
943 : bool Decomposer::LoadBlockGraphFromPdb(const base::FilePath& pdb_path,
944 : const PEFile& image_file,
945 : ImageLayout* image_layout,
946 E : bool* stream_exists) {
947 E : DCHECK_NE(reinterpret_cast<ImageLayout*>(NULL), image_layout);
948 E : DCHECK_NE(reinterpret_cast<bool*>(NULL), stream_exists);
949 :
950 E : pdb::PdbFile pdb_file;
951 E : pdb::PdbReader pdb_reader;
952 E : if (!pdb_reader.Read(pdb_path, &pdb_file)) {
953 i : LOG(ERROR) << "Unable to read the PDB named \"" << pdb_path.value()
954 : << "\".";
955 i : return NULL;
956 : }
957 :
958 : // Try to get the block-graph stream from the PDB.
959 E : scoped_refptr<pdb::PdbStream> block_graph_stream;
960 : if (!pdb::LoadNamedStreamFromPdbFile(pdb::kSyzygyBlockGraphStreamName,
961 : &pdb_file,
962 E : &block_graph_stream) ||
963 : block_graph_stream.get() == NULL) {
964 E : *stream_exists = false;
965 E : return false;
966 : }
967 E : if (block_graph_stream->length() == 0) {
968 i : *stream_exists = false;
969 i : LOG(WARNING) << "The block-graph stream is empty, ignoring it.";
970 i : return false;
971 : }
972 :
973 : // The PDB contains a block-graph stream, the block-graph and the image layout
974 : // will be read from this stream.
975 E : *stream_exists = true;
976 E : if (!LoadBlockGraphFromPdbStream(image_file, block_graph_stream.get(),
977 : image_layout)) {
978 i : return false;
979 : }
980 :
981 E : return true;
982 E : }
983 :
984 E : bool Decomposer::DecomposeImpl() {
985 : // Instantiate and initialize our Debug Interface Access session. This logs
986 : // verbosely for us.
987 E : ScopedComPtr<IDiaDataSource> dia_source;
988 E : ScopedComPtr<IDiaSession> dia_session;
989 E : ScopedComPtr<IDiaSymbol> global;
990 E : if (!InitializeDia(image_file_, pdb_path_, dia_source.Receive(),
991 : dia_session.Receive(), global.Receive())) {
992 i : return false;
993 : }
994 :
995 : // Copy the image headers to the layout.
996 E : CopySectionHeadersToImageLayout(
997 : image_file_.nt_headers()->FileHeader.NumberOfSections,
998 : image_file_.section_headers(),
999 : &(image_layout_->sections));
1000 :
1001 : // Create the sections in the underlying block-graph.
1002 E : if (!CopySectionInfoToBlockGraph(image_file_, image_->graph()))
1003 i : return false;
1004 :
1005 : // We scope the first few operations so that we don't keep the intermediate
1006 : // references around any longer than we have to.
1007 : {
1008 E : IntermediateReferences references;
1009 :
1010 : // First we parse out the PE blocks.
1011 E : VLOG(1) << "Parsing PE blocks.";
1012 E : if (!CreatePEImageBlocksAndReferences(&references))
1013 i : return false;
1014 :
1015 : // Now we parse the COFF group symbols from the linker's symbol stream.
1016 : // These indicate things like static initializers, which must stay together
1017 : // in a single block.
1018 E : VLOG(1) << "Parsing COFF groups.";
1019 E : if (!CreateBlocksFromCoffGroups())
1020 i : return false;
1021 :
1022 : // Next we parse out section contributions. Some of these may coincide with
1023 : // existing PE parsed blocks, but when they do we expect them to be exact
1024 : // collisions.
1025 E : VLOG(1) << "Parsing section contributions.";
1026 E : if (!CreateBlocksFromSectionContribs(dia_session.get()))
1027 i : return false;
1028 :
1029 E : VLOG(1) << "Finding cold blocks.";
1030 E : if (!FindColdBlocksFromCompilands(dia_session.get()))
1031 i : return false;
1032 :
1033 : // Flesh out the rest of the image with gap blocks.
1034 E : VLOG(1) << "Creating gap blocks.";
1035 E : if (!CreateGapBlocks())
1036 i : return false;
1037 :
1038 : // Finalize the PE-parsed intermediate references.
1039 E : VLOG(1) << "Finalizing intermediate references.";
1040 E : if (!FinalizeIntermediateReferences(references))
1041 i : return false;
1042 E : }
1043 :
1044 : // Parse the fixups and use them to create references.
1045 E : VLOG(1) << "Parsing fixups.";
1046 E : if (!CreateReferencesFromFixups(dia_session.get()))
1047 i : return false;
1048 :
1049 : // Annotate the block-graph with symbol information.
1050 E : VLOG(1) << "Parsing symbols.";
1051 E : if (!ProcessSymbols(global.get()))
1052 i : return false;
1053 :
1054 : // Now, find and label any padding blocks.
1055 E : VLOG(1) << "Labeling padding blocks.";
1056 E : if (!FindPaddingBlocks(image_layout_))
1057 i : return false;
1058 :
1059 : // Set the alignment on code blocks with jump tables. This ensures that the
1060 : // jump tables remain aligned post-transform.
1061 E : VLOG(1) << "Calculating code block alignments.";
1062 E : if (!AlignCodeBlocks(image_layout_))
1063 i : return false;
1064 :
1065 : // Set the alignment of data blocks. This is not precise in that it simply
1066 : // guesses the alignment based on the address of the block. Some instructions
1067 : // have alignment requirements on their data but unfortunately the PDB does
1068 : // not contain explicit alignment information.
1069 E : VLOG(1) << "Guessing data block alignments.";
1070 E : GuessDataBlockAlignments(image_file_, image_layout_);
1071 :
1072 E : return true;
1073 E : }
1074 :
1075 : bool Decomposer::CreatePEImageBlocksAndReferences(
1076 E : IntermediateReferences* references) {
1077 E : DCHECK_NE(reinterpret_cast<IntermediateReferences*>(NULL), references);
1078 :
1079 E : PEFileParser::AddReferenceCallback add_reference(
1080 : base::Bind(&AddIntermediateReference, base::Unretained(references)));
1081 E : PEFileParser parser(image_file_, image_, add_reference);
1082 E : PEFileParser::PEHeader header;
1083 E : if (!parser.ParseImage(&header)) {
1084 i : LOG(ERROR) << "Unable to parse PE image.";
1085 i : return false;
1086 : }
1087 :
1088 E : return true;
1089 E : }
1090 :
1091 E : bool Decomposer::CreateBlocksFromCoffGroups() {
1092 E : pdb::PdbFile pdb_file;
1093 E : pdb::PdbReader pdb_reader;
1094 E : if (!pdb_reader.Read(pdb_path_, &pdb_file)) {
1095 i : LOG(ERROR) << "Failed to load PDB: " << pdb_path_.value();
1096 i : return false;
1097 : }
1098 :
1099 E : scoped_refptr<pdb::PdbStream> symbols = GetLinkerSymbolStream(pdb_file);
1100 :
1101 : // Process the symbols in the linker module symbol stream.
1102 E : VisitLinkerSymbolContext context;
1103 E : pdb::VisitSymbolsCallback callback = base::Bind(
1104 : &Decomposer::VisitLinkerSymbol,
1105 : base::Unretained(this),
1106 : base::Unretained(&context));
1107 E : if (!pdb::VisitSymbols(callback, 0, symbols->length(), true, symbols.get()))
1108 i : return false;
1109 :
1110 : // Bail if we did not encounter a closing bracketing symbol where one was
1111 : // expected.
1112 E : if (context.current_group_index != -1) {
1113 i : LOG(ERROR) << "Unable to close bracketed COFF group \""
1114 : << context.current_group_prefix << "\".";
1115 i : return false;
1116 : }
1117 :
1118 E : return true;
1119 E : }
1120 :
1121 E : bool Decomposer::CreateBlocksFromSectionContribs(IDiaSession* session) {
1122 E : ScopedComPtr<IDiaEnumSectionContribs> section_contribs;
1123 E : SearchResult search_result = FindDiaTable(session,
1124 : section_contribs.Receive());
1125 E : if (search_result != kSearchSucceeded) {
1126 i : if (search_result == kSearchFailed)
1127 i : LOG(ERROR) << "No section contribution table found.";
1128 i : return false;
1129 : }
1130 :
1131 E : size_t rsrc_id = image_file_.GetSectionIndex(kResourceSectionName);
1132 :
1133 E : LONG count = 0;
1134 E : if (section_contribs->get_Count(&count) != S_OK) {
1135 i : LOG(ERROR) << "Failed to get section contributions enumeration length.";
1136 i : return false;
1137 : }
1138 :
1139 E : for (LONG visited = 0; visited < count; ++visited) {
1140 E : ScopedComPtr<IDiaSectionContrib> section_contrib;
1141 E : ULONG fetched = 0;
1142 E : HRESULT hr = section_contribs->Next(1, section_contrib.Receive(), &fetched);
1143 : // The standard way to end an enumeration (according to the docs) is by
1144 : // returning S_FALSE and setting fetched to 0. We don't actually see this,
1145 : // but it wouldn't be an error if we did.
1146 E : if (hr == S_FALSE && fetched == 0)
1147 i : break;
1148 E : if (hr != S_OK) {
1149 i : LOG(ERROR) << "Failed to get DIA section contribution: "
1150 : << common::LogHr(hr) << ".";
1151 i : return false;
1152 : }
1153 : // We actually end up seeing S_OK and fetched == 0 when the enumeration
1154 : // terminates, which goes against the publishes documentations.
1155 E : if (fetched == 0)
1156 i : break;
1157 :
1158 E : DWORD rva = 0;
1159 E : DWORD length = 0;
1160 E : DWORD section_id = 0;
1161 E : BOOL code = FALSE;
1162 E : ScopedComPtr<IDiaSymbol> compiland;
1163 E : ScopedBstr bstr_compiland_name;
1164 : if ((hr = section_contrib->get_relativeVirtualAddress(&rva)) != S_OK ||
1165 : (hr = section_contrib->get_length(&length)) != S_OK ||
1166 : (hr = section_contrib->get_addressSection(§ion_id)) != S_OK ||
1167 : (hr = section_contrib->get_code(&code)) != S_OK ||
1168 E : (hr = section_contrib->get_compiland(compiland.Receive())) != S_OK ||
1169 : (hr = compiland->get_name(bstr_compiland_name.Receive())) != S_OK) {
1170 i : LOG(ERROR) << "Failed to get section contribution properties: "
1171 : << common::LogHr(hr) << ".";
1172 i : return false;
1173 : }
1174 :
1175 : // Determine if this function was built by a supported compiler.
1176 : bool is_built_by_supported_compiler =
1177 E : IsBuiltBySupportedCompiler(compiland.get());
1178 :
1179 : // DIA numbers sections from 1 to n, while we do 0 to n - 1.
1180 E : DCHECK_LT(0u, section_id);
1181 E : --section_id;
1182 :
1183 : // We don't parse the resource section, as it is parsed by the PEFileParser.
1184 E : if (section_id == rsrc_id)
1185 E : continue;
1186 :
1187 E : std::string compiland_name;
1188 E : if (!base::WideToUTF8(bstr_compiland_name, bstr_compiland_name.Length(),
1189 : &compiland_name)) {
1190 i : LOG(ERROR) << "Failed to convert compiland name to UTF8.";
1191 i : return false;
1192 : }
1193 :
1194 : // Give a name to the block based on the basename of the object file. This
1195 : // will eventually be replaced by the full symbol name, if one exists for
1196 : // the block.
1197 E : size_t last_component = compiland_name.find_last_of('\\');
1198 E : size_t extension = compiland_name.find_last_of('.');
1199 E : if (last_component == std::string::npos) {
1200 E : last_component = 0;
1201 E : } else {
1202 : // We don't want to include the last slash.
1203 E : ++last_component;
1204 : }
1205 E : if (extension < last_component)
1206 i : extension = compiland_name.size();
1207 E : std::string name = compiland_name.substr(last_component,
1208 : extension - last_component);
1209 :
1210 : // TODO(chrisha): We see special section contributions with the name
1211 : // "* CIL *". These are concatenations of data symbols and can very
1212 : // likely be chunked using symbols directly. A cursory visual inspection
1213 : // of symbol names hints that these might be related to WPO.
1214 :
1215 : // Create the block.
1216 : BlockType block_type =
1217 E : code ? BlockGraph::CODE_BLOCK : BlockGraph::DATA_BLOCK;
1218 E : Block* block = CreateBlockOrFindCoveringPeBlock(
1219 : block_type, RelativeAddress(rva), length, name);
1220 E : if (block == NULL) {
1221 i : LOG(ERROR) << "Unable to create block for compiland \""
1222 : << compiland_name << "\".";
1223 i : return false;
1224 : }
1225 :
1226 : // Set the block compiland name.
1227 E : block->set_compiland_name(compiland_name);
1228 :
1229 : // Set the block attributes.
1230 E : block->set_attribute(BlockGraph::SECTION_CONTRIB);
1231 E : if (!is_built_by_supported_compiler)
1232 E : block->set_attribute(BlockGraph::BUILT_BY_UNSUPPORTED_COMPILER);
1233 E : }
1234 :
1235 E : return true;
1236 E : }
1237 :
1238 E : bool Decomposer::FindColdBlocksFromCompilands(IDiaSession* session) {
1239 : // Detect hot/cold code separation. Some blocks are outside the function
1240 : // address range and must be handled as separate blocks. When building
1241 : // with PGO, the compiler can split functions into "hot" and "cold" blocks,
1242 : // and move the "cold" blocks out to separate pages, so the function can be
1243 : // noncontiguous.
1244 E : ScopedComPtr<IDiaSymbol> global;
1245 E : if (session->get_globalScope(global.Receive()) != S_OK) {
1246 i : LOG(ERROR) << "Cannot get global symbol.";
1247 i : return false;
1248 : }
1249 :
1250 : // Find compilands within the global scope.
1251 E : ScopedComPtr<IDiaEnumSymbols> compilands;
1252 : HRESULT status =
1253 E : global->findChildren(SymTagCompiland, NULL, 0, compilands.Receive());
1254 E : if (status != S_OK) {
1255 i : LOG(ERROR) << "Finding compilands failed on the global symbol: "
1256 : << common::LogHr(status) << ".";
1257 i : return false;
1258 : }
1259 :
1260 : // For each compiland, process its lexical blocks.
1261 E : while (true) {
1262 E : ULONG count = 0;
1263 E : ScopedComPtr<IDiaSymbol> compiland;
1264 E : if (compilands->Next(1, compiland.Receive(), &count) != S_OK ||
1265 : count != 1) {
1266 E : break;
1267 : }
1268 :
1269 E : ScopedComPtr<IDiaEnumSymbols> compiland_blocks;
1270 E : status = compiland->findChildren(SymTagBlock,
1271 : NULL,
1272 : 0,
1273 : compiland_blocks.Receive());
1274 E : if (status != S_OK) {
1275 i : LOG(ERROR) << "Finding blocks failed on compiland: "
1276 : << common::LogHr(status) << ".";
1277 i : return false;
1278 : }
1279 :
1280 E : LONG blocks_count = 0;
1281 E : if (compiland_blocks->get_Count(&blocks_count) != S_OK) {
1282 i : LOG(ERROR) << "Failed to get compiland blocks enumeration length.";
1283 i : return false;
1284 : }
1285 :
1286 E : for (LONG block_index = 0; block_index < blocks_count; ++block_index) {
1287 E : ScopedComPtr<IDiaSymbol> compiland_block;
1288 E : ULONG fetched = 0;
1289 :
1290 E : status = compiland_blocks->Next(1, compiland_block.Receive(), &fetched);
1291 E : if (status == S_FALSE && fetched == 0)
1292 i : break;
1293 E : if (status != S_OK) {
1294 i : LOG(ERROR) << "Failed to get function block: "
1295 : << common::LogHr(status) << ".";
1296 i : return false;
1297 : }
1298 E : if (fetched == 0)
1299 i : break;
1300 :
1301 E : ScopedComPtr<IDiaSymbol> parent;
1302 E : DWORD parent_tag = 0;
1303 E : if (compiland_block->get_lexicalParent(parent.Receive()) != S_OK ||
1304 : parent->get_symTag(&parent_tag) != S_OK) {
1305 i : LOG(ERROR) << "Cannot retrieve block parent.";
1306 i : return false;
1307 : }
1308 :
1309 : // Only consider function block.
1310 E : if (parent_tag != SymTagFunction)
1311 i : continue;
1312 :
1313 : // Get relative adresses.
1314 : DWORD func_rva, block_rva;
1315 : ULONGLONG func_length;
1316 : if (compiland_block->get_relativeVirtualAddress(&block_rva) != S_OK ||
1317 E : parent->get_relativeVirtualAddress(&func_rva) != S_OK ||
1318 : parent->get_length(&func_length) != S_OK) {
1319 i : LOG(ERROR) << "Cannot retrieve parent address range.";
1320 i : return false;
1321 : }
1322 :
1323 : // Retrieve the function block.
1324 E : Block* func_block = image_->GetBlockByAddress(RelativeAddress(func_rva));
1325 E : if (func_block == NULL) {
1326 i : LOG(ERROR) << "Cannot retrieve parent block.";
1327 i : return false;
1328 : }
1329 :
1330 : // Skip blocks within the range of its parent.
1331 E : if (block_rva >= func_rva && block_rva <= func_rva + func_length)
1332 i : continue;
1333 :
1334 : // A cold block is detected and needs special handling.
1335 E : Block* cold_block = image_->GetBlockByAddress(RelativeAddress(block_rva));
1336 E : if (cold_block == NULL) {
1337 i : LOG(ERROR) << "Cannot retrieve parent block.";
1338 i : return false;
1339 : }
1340 :
1341 E : RelativeAddress cold_block_addr;
1342 E : if (!image_->GetAddressOf(cold_block, &cold_block_addr)) {
1343 i : LOG(ERROR) << "Cannot retrieve cold block address.";
1344 i : return false;
1345 : }
1346 :
1347 : // Add cold_block as a child of the function block.
1348 E : cold_blocks_[func_block][cold_block_addr] = cold_block;
1349 :
1350 : // Set the parent relation for blocks belonging to the function block.
1351 E : cold_blocks_parent_[func_block] = func_block;
1352 E : cold_blocks_parent_[cold_block] = func_block;
1353 E : }
1354 E : }
1355 :
1356 E : return true;
1357 E : }
1358 :
1359 E : bool Decomposer::CreateGapBlocks() {
1360 E : size_t num_sections = image_file_.nt_headers()->FileHeader.NumberOfSections;
1361 :
1362 : // Iterate through all the image sections.
1363 E : for (size_t i = 0; i < num_sections; ++i) {
1364 E : const IMAGE_SECTION_HEADER* header = image_file_.section_header(i);
1365 E : DCHECK_NE(reinterpret_cast<IMAGE_SECTION_HEADER*>(NULL), header);
1366 :
1367 E : BlockType type = BlockGraph::CODE_BLOCK;
1368 E : const char* section_type = NULL;
1369 E : switch (GetSectionType(*header)) {
1370 : case kSectionCode:
1371 E : type = BlockGraph::CODE_BLOCK;
1372 E : section_type = "code";
1373 E : break;
1374 :
1375 : case kSectionData:
1376 E : type = BlockGraph::DATA_BLOCK;
1377 E : section_type = "data";
1378 E : break;
1379 :
1380 : default:
1381 i : continue;
1382 : }
1383 :
1384 E : if (!CreateSectionGapBlocks(header, type)) {
1385 i : LOG(ERROR) << "Unable to create gap blocks for " << section_type
1386 : << " section \"" << header->Name << "\".";
1387 i : return false;
1388 : }
1389 E : }
1390 :
1391 E : return true;
1392 E : }
1393 :
1394 : bool Decomposer::FinalizeIntermediateReferences(
1395 E : const IntermediateReferences& references) {
1396 E : for (size_t i = 0; i < references.size(); ++i) {
1397 : // This logs verbosely for us.
1398 E : if (!CreateReference(references[i].src_addr,
1399 : references[i].size,
1400 : references[i].type,
1401 : references[i].dst_addr,
1402 : references[i].dst_addr,
1403 : image_)) {
1404 i : return false;
1405 : }
1406 E : }
1407 E : return true;
1408 E : }
1409 :
1410 E : bool Decomposer::CreateReferencesFromFixups(IDiaSession* session) {
1411 E : DCHECK_NE(reinterpret_cast<IDiaSession*>(NULL), session);
1412 :
1413 E : PEFile::RelocSet reloc_set;
1414 E : if (!image_file_.DecodeRelocs(&reloc_set))
1415 i : return false;
1416 :
1417 E : OMAPs omap_from;
1418 E : PdbFixups fixups;
1419 E : if (!LoadDebugStreams(session, &fixups, &omap_from))
1420 i : return false;
1421 :
1422 : // While creating references from the fixups this removes the
1423 : // corresponding reference data from the relocs. We use this as a kind of
1424 : // double-entry bookkeeping to ensure all is well and right in the world.
1425 E : if (!CreateReferencesFromFixupsImpl(image_file_, fixups, omap_from,
1426 : &reloc_set, image_)) {
1427 i : return false;
1428 : }
1429 :
1430 E : if (!reloc_set.empty()) {
1431 i : LOG(ERROR) << "Found reloc entries without matching FIXUP entries.";
1432 i : return false;
1433 : }
1434 :
1435 E : return true;
1436 E : }
1437 :
1438 E : bool Decomposer::ProcessSymbols(IDiaSymbol* root) {
1439 E : DCHECK_NE(reinterpret_cast<IDiaSymbol*>(NULL), root);
1440 :
1441 E : DiaBrowser::MatchCallback on_push_function_or_thunk_symbol(
1442 : base::Bind(&Decomposer::OnPushFunctionOrThunkSymbol,
1443 : base::Unretained(this)));
1444 E : DiaBrowser::MatchCallback on_pop_function_or_thunk_symbol(
1445 : base::Bind(&Decomposer::OnPopFunctionOrThunkSymbol,
1446 : base::Unretained(this)));
1447 E : DiaBrowser::MatchCallback on_function_child_symbol(
1448 : base::Bind(&Decomposer::OnFunctionChildSymbol,
1449 : base::Unretained(this)));
1450 E : DiaBrowser::MatchCallback on_data_symbol(
1451 : base::Bind(&Decomposer::OnDataSymbol, base::Unretained(this)));
1452 E : DiaBrowser::MatchCallback on_public_symbol(
1453 : base::Bind(&Decomposer::OnPublicSymbol, base::Unretained(this)));
1454 E : DiaBrowser::MatchCallback on_label_symbol(
1455 : base::Bind(&Decomposer::OnLabelSymbol, base::Unretained(this)));
1456 :
1457 E : DiaBrowser dia_browser;
1458 :
1459 : // Find thunks.
1460 E : dia_browser.AddPattern(Seq(Opt(SymTagCompiland), SymTagThunk),
1461 : on_push_function_or_thunk_symbol,
1462 : on_pop_function_or_thunk_symbol);
1463 :
1464 : // Find functions and all data, labels, callsites, debug start/end and block
1465 : // symbols below them. This is done in one single pattern so that the
1466 : // function pushes/pops happen in the right order.
1467 E : dia_browser.AddPattern(
1468 : Seq(Opt(SymTagCompiland),
1469 : Callback(Or(SymTagFunction, SymTagThunk),
1470 : on_push_function_or_thunk_symbol,
1471 : on_pop_function_or_thunk_symbol),
1472 : Star(SymTagBlock),
1473 : Or(SymTagData,
1474 : SymTagLabel,
1475 : SymTagBlock,
1476 : SymTagFuncDebugStart,
1477 : SymTagFuncDebugEnd,
1478 : SymTagCallSite)),
1479 : on_function_child_symbol);
1480 :
1481 : // Global data and code label symbols.
1482 E : dia_browser.AddPattern(Seq(Opt(SymTagCompiland), SymTagLabel),
1483 : on_label_symbol);
1484 E : dia_browser.AddPattern(Seq(Opt(SymTagCompiland), SymTagData),
1485 : on_data_symbol);
1486 :
1487 : // Public symbols. These provide decorated names without any type info, but
1488 : // are useful for debugging.
1489 E : dia_browser.AddPattern(SymTagPublicSymbol, on_public_symbol);
1490 :
1491 E : return dia_browser.Browse(root);
1492 E : }
1493 :
1494 : bool Decomposer::VisitLinkerSymbol(VisitLinkerSymbolContext* context,
1495 : uint16_t symbol_length,
1496 : uint16_t symbol_type,
1497 E : common::BinaryStreamReader* reader) {
1498 E : DCHECK_NE(static_cast<VisitLinkerSymbolContext*>(NULL), context);
1499 E : DCHECK_NE(static_cast<common::BinaryStreamReader*>(NULL), reader);
1500 :
1501 E : if (symbol_type != cci::S_COFFGROUP)
1502 E : return true;
1503 :
1504 E : std::vector<uint8_t> buffer;
1505 : const cci::CoffGroupSym* coffgroup =
1506 E : ParseSymbol<cci::CoffGroupSym>(symbol_length, reader, &buffer);
1507 E : if (coffgroup == NULL)
1508 i : return false;
1509 :
1510 : // The PDB numbers sections starting at index 1 but we use index 0.
1511 E : RelativeAddress rva(image_layout_->sections[coffgroup->seg - 1].addr +
1512 : coffgroup->off);
1513 :
1514 : // We are looking for an opening symbol.
1515 E : if (context->current_group_index == -1) {
1516 E : for (uint32_t i = 0; i < context->bracketing_groups.size(); ++i) {
1517 E : std::string prefix;
1518 E : if (context->bracketing_groups[i].FullMatch(coffgroup->name, &prefix)) {
1519 E : context->current_group_index = i;
1520 E : context->current_group_prefix = prefix;
1521 E : context->current_group_start = rva;
1522 E : return true;
1523 : }
1524 E : }
1525 :
1526 : // No opening symbol was encountered. We can safely ignore this
1527 : // COFF group symbol.
1528 E : return true;
1529 : }
1530 :
1531 : // If we get here we've found an opening symbol and we're looking for the
1532 : // matching closing symbol.
1533 E : std::string prefix;
1534 E : if (!context->bracketing_groups[context->current_group_index].FullMatch(
1535 : coffgroup->name, &prefix)) {
1536 E : return true;
1537 : }
1538 :
1539 E : if (prefix != context->current_group_prefix) {
1540 : // We see another symbol open/close while already in an opened symbol.
1541 : // This indicates nested bracketing information, which we've never seen
1542 : // before.
1543 i : LOG(ERROR) << "Encountered nested bracket symbol \"" << prefix
1544 : << "\" while in \"" << context->current_group_prefix << "\".";
1545 i : return false;
1546 : }
1547 :
1548 E : RelativeAddress end = rva + coffgroup->cb;
1549 E : DCHECK_LE(context->current_group_start, end);
1550 :
1551 : // If the COFF group is not empty, then create a block corresponding to it.
1552 E : if (context->current_group_start != end) {
1553 : // Create a block for this bracketed COFF group.
1554 E : Block* block = CreateBlock(
1555 : BlockGraph::DATA_BLOCK,
1556 : context->current_group_start,
1557 : end - context->current_group_start,
1558 : base::StringPrintf("Bracketed COFF group: %s", prefix.c_str()));
1559 E : if (block == NULL) {
1560 i : LOG(ERROR) << "Failed to create bracketed COFF group \""
1561 : << prefix << "\".";
1562 i : return false;
1563 : }
1564 E : block->set_attribute(BlockGraph::COFF_GROUP);
1565 : }
1566 :
1567 : // Indicate that this block is closed and we're looking for another opening
1568 : // bracket symbol.
1569 E : context->current_group_index = -1;
1570 E : context->current_group_prefix.clear();
1571 E : context->current_group_start = RelativeAddress(0);
1572 :
1573 E : return true;
1574 E : }
1575 :
1576 : DiaBrowser::BrowserDirective Decomposer::OnPushFunctionOrThunkSymbol(
1577 : const DiaBrowser& dia_browser,
1578 : const DiaBrowser::SymTagVector& sym_tags,
1579 E : const DiaBrowser::SymbolPtrVector& symbols) {
1580 E : DCHECK(!symbols.empty());
1581 E : DCHECK_EQ(sym_tags.size(), symbols.size());
1582 E : DiaBrowser::SymbolPtr symbol = symbols.back();
1583 :
1584 E : DCHECK_EQ(reinterpret_cast<Block*>(NULL), current_block_);
1585 E : DCHECK_EQ(current_address_, RelativeAddress(0));
1586 E : DCHECK_EQ(0u, current_scope_count_);
1587 :
1588 E : HRESULT hr = E_FAIL;
1589 E : DWORD location_type = LocIsNull;
1590 E : DWORD rva = 0;
1591 E : ULONGLONG length = 0;
1592 E : ScopedBstr name_bstr;
1593 : if (FAILED(hr = symbol->get_locationType(&location_type)) ||
1594 : FAILED(hr = symbol->get_relativeVirtualAddress(&rva)) ||
1595 E : FAILED(hr = symbol->get_length(&length)) ||
1596 : FAILED(hr = symbol->get_name(name_bstr.Receive()))) {
1597 i : LOG(ERROR) << "Failed to get function/thunk properties: "
1598 : << common::LogHr(hr) << ".";
1599 i : return DiaBrowser::kBrowserAbort;
1600 : }
1601 :
1602 : // We only care about functions with static storage. We can stop looking at
1603 : // things below this node, as we won't be able to resolve them either.
1604 E : if (location_type != LocIsStatic)
1605 i : return DiaBrowser::kBrowserTerminatePath;
1606 :
1607 E : RelativeAddress addr(rva);
1608 E : Block* block = image_->GetBlockByAddress(addr);
1609 E : CHECK(block != NULL);
1610 E : RelativeAddress block_addr;
1611 E : CHECK(image_->GetAddressOf(block, &block_addr));
1612 E : DCHECK(InRange(addr, block_addr, block->size()));
1613 :
1614 E : std::string name;
1615 E : if (!base::WideToUTF8(name_bstr, name_bstr.Length(), &name)) {
1616 i : LOG(ERROR) << "Failed to convert function/thunk name to UTF8.";
1617 i : return DiaBrowser::kBrowserAbort;
1618 : }
1619 :
1620 : // We know the function starts in this block but we need to make sure its
1621 : // end does not extend past the end of the block.
1622 E : if (addr + length > block_addr + block->size()) {
1623 i : LOG(ERROR) << "Got function/thunk \"" << name << "\" that is not contained "
1624 : << "by section contribution \"" << block->name() << "\".";
1625 i : return DiaBrowser::kBrowserAbort;
1626 : }
1627 :
1628 E : Offset offset = addr - block_addr;
1629 E : if (!AddLabelToBlock(offset, name, BlockGraph::CODE_LABEL, block))
1630 i : return DiaBrowser::kBrowserAbort;
1631 :
1632 : // Keep track of the generated block. We will use this when parsing symbols
1633 : // that belong to this function. This prevents us from having to do repeated
1634 : // lookups and also allows us to associate labels outside of the block to the
1635 : // correct block.
1636 E : current_block_ = block;
1637 E : current_address_ = block_addr;
1638 :
1639 : // Certain properties are not defined on all blocks, so the following calls
1640 : // may return S_FALSE.
1641 E : BOOL no_return = FALSE;
1642 E : if (symbol->get_noReturn(&no_return) != S_OK)
1643 E : no_return = FALSE;
1644 :
1645 E : BOOL has_inl_asm = FALSE;
1646 E : if (symbol->get_hasInlAsm(&has_inl_asm) != S_OK)
1647 E : has_inl_asm = FALSE;
1648 :
1649 E : BOOL has_eh = FALSE;
1650 E : if (symbol->get_hasEH(&has_eh) != S_OK)
1651 E : has_eh = FALSE;
1652 :
1653 E : BOOL has_seh = FALSE;
1654 E : if (symbol->get_hasSEH(&has_seh) != S_OK)
1655 E : has_seh = FALSE;
1656 :
1657 : // Set the block attributes.
1658 E : if (no_return == TRUE)
1659 E : block->set_attribute(BlockGraph::NON_RETURN_FUNCTION);
1660 E : if (has_inl_asm == TRUE)
1661 E : block->set_attribute(BlockGraph::HAS_INLINE_ASSEMBLY);
1662 E : if (has_eh || has_seh)
1663 E : block->set_attribute(BlockGraph::HAS_EXCEPTION_HANDLING);
1664 E : if (IsSymTag(symbol.get(), SymTagThunk))
1665 E : block->set_attribute(BlockGraph::THUNK);
1666 :
1667 E : return DiaBrowser::kBrowserContinue;
1668 E : }
1669 :
1670 : DiaBrowser::BrowserDirective Decomposer::OnPopFunctionOrThunkSymbol(
1671 : const DiaBrowser& dia_browser,
1672 : const DiaBrowser::SymTagVector& sym_tags,
1673 E : const DiaBrowser::SymbolPtrVector& symbols) {
1674 : // Simply clean up the current function block and address.
1675 E : current_block_ = NULL;
1676 E : current_address_ = RelativeAddress(0);
1677 E : current_scope_count_ = 0;
1678 E : return DiaBrowser::kBrowserContinue;
1679 E : }
1680 :
1681 : DiaBrowser::BrowserDirective Decomposer::OnFunctionChildSymbol(
1682 : const DiaBrowser& dia_browser,
1683 : const DiaBrowser::SymTagVector& sym_tags,
1684 E : const DiaBrowser::SymbolPtrVector& symbols) {
1685 E : DCHECK(!symbols.empty());
1686 E : DCHECK_EQ(sym_tags.size(), symbols.size());
1687 :
1688 : // This can only be called from the context of a function, so we expect the
1689 : // parent function block to be set and remembered.
1690 E : DCHECK_NE(reinterpret_cast<Block*>(NULL), current_block_);
1691 :
1692 : // The set of sym tags here should match the pattern used in the DiaBrowser
1693 : // instance set up in ProcessSymbols.
1694 E : switch (sym_tags.back()) {
1695 : case SymTagData:
1696 E : return OnDataSymbol(dia_browser, sym_tags, symbols);
1697 :
1698 : case SymTagLabel:
1699 E : return OnLabelSymbol(dia_browser, sym_tags, symbols);
1700 :
1701 : case SymTagBlock:
1702 : case SymTagFuncDebugStart:
1703 : case SymTagFuncDebugEnd:
1704 E : return OnScopeSymbol(sym_tags.back(), symbols.back());
1705 :
1706 : case SymTagCallSite:
1707 E : return OnCallSiteSymbol(symbols.back());
1708 :
1709 : default:
1710 : break;
1711 : }
1712 :
1713 i : LOG(ERROR) << "Unhandled function child symbol: " << sym_tags.back() << ".";
1714 i : return DiaBrowser::kBrowserAbort;
1715 E : }
1716 :
1717 : DiaBrowser::BrowserDirective Decomposer::OnDataSymbol(
1718 : const DiaBrowser& dia_browser,
1719 : const DiaBrowser::SymTagVector& sym_tags,
1720 E : const DiaBrowser::SymbolPtrVector& symbols) {
1721 E : DCHECK(!symbols.empty());
1722 E : DCHECK_EQ(sym_tags.size(), symbols.size());
1723 E : DiaBrowser::SymbolPtr symbol = symbols.back();
1724 :
1725 E : HRESULT hr = E_FAIL;
1726 E : DWORD location_type = LocIsNull;
1727 E : DWORD rva = 0;
1728 E : ScopedBstr name_bstr;
1729 : if (FAILED(hr = symbol->get_locationType(&location_type)) ||
1730 E : FAILED(hr = symbol->get_relativeVirtualAddress(&rva)) ||
1731 : FAILED(hr = symbol->get_name(name_bstr.Receive()))) {
1732 i : LOG(ERROR) << "Failed to get data properties: " << common::LogHr(hr) << ".";
1733 i : return DiaBrowser::kBrowserAbort;
1734 : }
1735 :
1736 : // Symbols with an address of zero are essentially invalid. They appear to
1737 : // have been optimized away by the compiler, but they are still reported.
1738 E : if (rva == 0)
1739 E : return DiaBrowser::kBrowserTerminatePath;
1740 :
1741 : // We only care about functions with static storage. We can stop looking at
1742 : // things below this node, as we won't be able to resolve them either.
1743 E : if (location_type != LocIsStatic)
1744 i : return DiaBrowser::kBrowserTerminatePath;
1745 :
1746 : // Get the size of this datum from its type info.
1747 E : size_t length = 0;
1748 E : if (!GetDataSymbolSize(symbol.get(), &length))
1749 i : return DiaBrowser::kBrowserAbort;
1750 :
1751 : // Reuse the parent function block if we can. This acts as small lookup
1752 : // cache.
1753 E : RelativeAddress addr(rva);
1754 E : Block* block = current_block_;
1755 E : RelativeAddress block_addr(current_address_);
1756 E : if (block == NULL || !InRange(addr, block_addr, block->size())) {
1757 E : block = image_->GetBlockByAddress(addr);
1758 E : CHECK(block != NULL);
1759 E : CHECK(image_->GetAddressOf(block, &block_addr));
1760 E : DCHECK(InRange(addr, block_addr, block->size()));
1761 : }
1762 :
1763 E : std::string name;
1764 E : if (!base::WideToUTF8(name_bstr, name_bstr.Length(), &name)) {
1765 i : LOG(ERROR) << "Failed to convert label name to UTF8.";
1766 i : return DiaBrowser::kBrowserAbort;
1767 : }
1768 :
1769 : // Zero-length data symbols mark case/jump tables, or are forward declares.
1770 E : BlockGraph::LabelAttributes attr = BlockGraph::DATA_LABEL;
1771 E : Offset offset = addr - block_addr;
1772 E : if (length == 0) {
1773 : // Jump and case tables come in as data symbols with no name. Jump tables
1774 : // are always an array of pointers, thus they coincide exactly with a
1775 : // reference. Case tables are simple arrays of integer values (themselves
1776 : // indices into a jump table), thus do not coincide with a reference.
1777 E : if (name.empty() && block->type() == BlockGraph::CODE_BLOCK) {
1778 E : if (block->references().find(offset) != block->references().end()) {
1779 E : name = kJumpTable;
1780 E : attr |= BlockGraph::JUMP_TABLE_LABEL;
1781 E : } else {
1782 E : name = kCaseTable;
1783 E : attr |= BlockGraph::CASE_TABLE_LABEL;
1784 : }
1785 E : } else {
1786 : // Zero-length data symbols act as 'forward declares' in some sense. They
1787 : // are always followed by a non-zero length data symbol with the same name
1788 : // and location.
1789 E : return DiaBrowser::kBrowserTerminatePath;
1790 : }
1791 : }
1792 :
1793 : // Verify that the data symbol does not exceed the size of the block.
1794 E : if (addr + length > block_addr + block->size()) {
1795 : // The data symbol can exceed the size of the block in the case of data
1796 : // imports. For some reason the toolchain emits a global data symbol with
1797 : // type information equal to the type of the data *pointed* to by the import
1798 : // entry rather than the type of the entry itself. Thus, if the data type
1799 : // is bigger than the entire IAT this symbol will exceed it. To complicate
1800 : // matters even more, a poorly written module can import its own export in
1801 : // which case a linker generated pseudo-import-entry block will be
1802 : // generated. This won't be part of the IAT, so we can't even filter based
1803 : // on that. Instead, we simply ignore global data symbols that exceed the
1804 : // block size.
1805 E : base::StringPiece spname(name);
1806 E : if (sym_tags.size() == 1 && spname.starts_with("_imp_")) {
1807 E : VLOG(1) << "Encountered an imported data symbol \"" << name << "\" that "
1808 : << "extends past its parent block \"" << block->name() << "\".";
1809 E : } else {
1810 i : LOG(ERROR) << "Received data symbol \"" << name << "\" that extends past "
1811 : << "its parent block \"" << block->name() << "\".";
1812 i : return DiaBrowser::kBrowserAbort;
1813 : }
1814 : }
1815 :
1816 E : if (!AddLabelToBlock(offset, name, attr, block))
1817 i : return DiaBrowser::kBrowserAbort;
1818 :
1819 E : return DiaBrowser::kBrowserContinue;
1820 E : }
1821 :
1822 : DiaBrowser::BrowserDirective Decomposer::OnPublicSymbol(
1823 : const DiaBrowser& dia_browser,
1824 : const DiaBrowser::SymTagVector& sym_tags,
1825 E : const DiaBrowser::SymbolPtrVector& symbols) {
1826 E : DCHECK(!symbols.empty());
1827 E : DCHECK_EQ(sym_tags.size(), symbols.size());
1828 E : DCHECK_EQ(reinterpret_cast<Block*>(NULL), current_block_);
1829 E : DiaBrowser::SymbolPtr symbol = symbols.back();
1830 :
1831 E : HRESULT hr = E_FAIL;
1832 E : DWORD rva = 0;
1833 E : ScopedBstr name_bstr;
1834 E : if (FAILED(hr = symbol->get_relativeVirtualAddress(&rva)) ||
1835 : FAILED(hr = symbol->get_name(name_bstr.Receive()))) {
1836 i : LOG(ERROR) << "Failed to get public symbol properties: "
1837 : << common::LogHr(hr) << ".";
1838 i : return DiaBrowser::kBrowserAbort;
1839 : }
1840 :
1841 E : RelativeAddress addr(rva);
1842 E : Block* block = image_->GetBlockByAddress(addr);
1843 E : CHECK(block != NULL);
1844 E : RelativeAddress block_addr;
1845 E : CHECK(image_->GetAddressOf(block, &block_addr));
1846 E : DCHECK(InRange(addr, block_addr, block->size()));
1847 :
1848 E : std::string name;
1849 E : base::WideToUTF8(name_bstr, name_bstr.Length(), &name);
1850 :
1851 : // Public symbol names are mangled. Remove leading '_' as per
1852 : // http://msdn.microsoft.com/en-us/library/00kh39zz(v=vs.80).aspx
1853 E : if (name[0] == '_')
1854 E : name = name.substr(1);
1855 :
1856 E : Offset offset = addr - block_addr;
1857 E : if (!AddLabelToBlock(offset, name, BlockGraph::PUBLIC_SYMBOL_LABEL, block))
1858 i : return DiaBrowser::kBrowserAbort;
1859 :
1860 E : return DiaBrowser::kBrowserContinue;
1861 E : }
1862 :
1863 : DiaBrowser::BrowserDirective Decomposer::OnLabelSymbol(
1864 : const DiaBrowser& dia_browser,
1865 : const DiaBrowser::SymTagVector& sym_tags,
1866 E : const DiaBrowser::SymbolPtrVector& symbols) {
1867 E : DCHECK(!symbols.empty());
1868 E : DCHECK_EQ(sym_tags.size(), symbols.size());
1869 E : DiaBrowser::SymbolPtr symbol = symbols.back();
1870 :
1871 E : HRESULT hr = E_FAIL;
1872 E : DWORD rva = 0;
1873 E : ScopedBstr name_bstr;
1874 E : if (FAILED(hr = symbol->get_relativeVirtualAddress(&rva)) ||
1875 : FAILED(hr = symbol->get_name(name_bstr.Receive()))) {
1876 i : LOG(ERROR) << "Failed to get label symbol properties: " << common::LogHr(hr)
1877 : << ".";
1878 i : return DiaBrowser::kBrowserAbort;
1879 : }
1880 :
1881 : // If we have a current_block_ the label should lie within its scope.
1882 E : RelativeAddress addr(rva);
1883 E : Block* block = current_block_;
1884 E : RelativeAddress block_addr(current_address_);
1885 E : if (block != NULL) {
1886 : // Try to find the block in the cold blocks. The cold blocks aren't in the
1887 : // same address space as the original function.
1888 E : if (!InRangeIncl(addr, block_addr, block->size())) {
1889 :
1890 : // Determine the function block containing this block.
1891 : ColdBlocksParent::iterator function_block =
1892 E : cold_blocks_parent_.find(block);
1893 E : if (function_block != cold_blocks_parent_.end())
1894 E : block = function_block->second;
1895 :
1896 : // Retrieve the first cold block related to that function before |addr|.
1897 E : ColdBlocksMap::iterator cold_blocks_it = cold_blocks_.find(block);
1898 E : if (cold_blocks_it != cold_blocks_.end()) {
1899 E : ColdBlocks& cold_blocks = cold_blocks_it->second;
1900 E : if (!cold_blocks.empty()) {
1901 : // Find the block containing the address |addr|. When |addr| is not
1902 : // the same as the block address, the iterator points to the next
1903 : // block.
1904 E : ColdBlocks::iterator cold_block_it = cold_blocks.lower_bound(addr);
1905 E : if (cold_block_it == cold_blocks.end() ||
1906 : cold_block_it->second->addr() != addr) {
1907 E : cold_block_it--;
1908 : }
1909 :
1910 : // Check whether the address falls into this cold block.
1911 E : DCHECK(cold_block_it != cold_blocks.end());
1912 E : Block* cold_block = cold_block_it->second;
1913 E : if (InRangeIncl(addr, cold_block->addr(), cold_block->size()))
1914 E : block = cold_block;
1915 : }
1916 : }
1917 :
1918 : // Update the block address according to the cold block found.
1919 E : if (!image_->GetAddressOf(block, &block_addr)) {
1920 i : LOG(ERROR) << "Cannot retrieve cold block address.";
1921 i : return DiaBrowser::kBrowserAbort;
1922 : }
1923 : }
1924 :
1925 E : if (!InRangeIncl(addr, block_addr, block->size())) {
1926 i : LOG(ERROR) << "Label falls outside of current block \""
1927 : << block->name() << "\".";
1928 i : return DiaBrowser::kBrowserAbort;
1929 : }
1930 E : } else {
1931 : // If there is no current block this is a compiland scope label.
1932 E : block = image_->GetBlockByAddress(addr);
1933 E : CHECK(block != NULL);
1934 E : CHECK(image_->GetAddressOf(block, &block_addr));
1935 E : DCHECK(InRange(addr, block_addr, block->size()));
1936 :
1937 : // TODO(chrisha): This label is in compiland scope, so we should be
1938 : // finding the block whose section contribution shares the same
1939 : // compiland.
1940 : }
1941 :
1942 E : std::string name;
1943 E : base::WideToUTF8(name_bstr, name_bstr.Length(), &name);
1944 :
1945 E : Offset offset = addr - block_addr;
1946 E : if (!AddLabelToBlock(offset, name, BlockGraph::CODE_LABEL, block))
1947 i : return DiaBrowser::kBrowserAbort;
1948 :
1949 E : return DiaBrowser::kBrowserContinue;
1950 E : }
1951 :
1952 : DiaBrowser::BrowserDirective Decomposer::OnScopeSymbol(
1953 E : enum SymTagEnum type, DiaBrowser::SymbolPtr symbol) {
1954 : // We should only get here via the successful exploration of a SymTagFunction,
1955 : // so current_block_ should be set.
1956 E : DCHECK_NE(reinterpret_cast<Block*>(NULL), current_block_);
1957 :
1958 E : HRESULT hr = E_FAIL;
1959 E : DWORD rva = 0;
1960 E : if (FAILED(hr = symbol->get_relativeVirtualAddress(&rva))) {
1961 i : LOG(ERROR) << "Failed to get scope symbol properties: " << common::LogHr(hr)
1962 : << ".";
1963 i : return DiaBrowser::kBrowserAbort;
1964 : }
1965 :
1966 : // The label may potentially lay at the first byte past the function.
1967 E : RelativeAddress addr(rva);
1968 E : DCHECK_LE(current_address_, addr);
1969 E : DCHECK_LE(addr, current_address_ + current_block_->size());
1970 :
1971 : // Get the attributes for this label.
1972 E : BlockGraph::LabelAttributes attr = 0;
1973 E : std::string name;
1974 E : CHECK(ScopeSymTagToLabelProperties(type, current_scope_count_, &attr, &name));
1975 :
1976 : // Add the label.
1977 E : Offset offset = addr - current_address_;
1978 E : if (!AddLabelToBlock(offset, name, attr, current_block_))
1979 i : return DiaBrowser::kBrowserAbort;
1980 :
1981 : // If this is a scope we extract the length and explicitly add a corresponding
1982 : // end label.
1983 E : if (type == SymTagBlock) {
1984 E : ULONGLONG length = 0;
1985 E : if (symbol->get_length(&length) != S_OK) {
1986 i : LOG(ERROR) << "Failed to extract code scope length for block \""
1987 : << current_block_->name() << "\".";
1988 i : return DiaBrowser::kBrowserAbort;
1989 : }
1990 E : DCHECK_LE(static_cast<size_t>(offset + length), current_block_->size());
1991 E : name = base::StringPrintf("<scope-end-%d>", current_scope_count_);
1992 E : ++current_scope_count_;
1993 E : if (!AddLabelToBlock(offset + length, name,
1994 : BlockGraph::SCOPE_END_LABEL, current_block_)) {
1995 i : return DiaBrowser::kBrowserAbort;
1996 : }
1997 : }
1998 :
1999 E : return DiaBrowser::kBrowserContinue;
2000 E : }
2001 :
2002 : DiaBrowser::BrowserDirective Decomposer::OnCallSiteSymbol(
2003 E : DiaBrowser::SymbolPtr symbol) {
2004 : // We should only get here via the successful exploration of a SymTagFunction,
2005 : // so current_block_ should be set.
2006 E : DCHECK_NE(reinterpret_cast<Block*>(NULL), current_block_);
2007 :
2008 E : HRESULT hr = E_FAIL;
2009 E : DWORD rva = 0;
2010 E : if (FAILED(hr = symbol->get_relativeVirtualAddress(&rva))) {
2011 i : LOG(ERROR) << "Failed to get call site symbol properties: "
2012 : << common::LogHr(hr) << ".";
2013 i : return DiaBrowser::kBrowserAbort;
2014 : }
2015 :
2016 E : RelativeAddress addr(rva);
2017 E : if (!InRange(addr, current_address_, current_block_->size())) {
2018 : // We see this happen under some build configurations (notably debug
2019 : // component builds of Chrome). As long as the label falls entirely
2020 : // outside of the block it is harmless and can be safely ignored.
2021 E : VLOG(1) << "Call site falls outside of current block \""
2022 : << current_block_->name() << "\".";
2023 E : return DiaBrowser::kBrowserContinue;
2024 : }
2025 :
2026 E : Offset offset = addr - current_address_;
2027 E : if (!AddLabelToBlock(offset, "<call-site>", BlockGraph::CALL_SITE_LABEL,
2028 : current_block_)) {
2029 i : return DiaBrowser::kBrowserAbort;
2030 : }
2031 :
2032 E : return DiaBrowser::kBrowserContinue;
2033 E : }
2034 :
2035 : Block* Decomposer::CreateBlock(BlockType type,
2036 : RelativeAddress address,
2037 : BlockGraph::Size size,
2038 E : const base::StringPiece& name) {
2039 E : Block* block = image_->AddBlock(type, address, size, name);
2040 E : if (block == NULL) {
2041 i : LOG(ERROR) << "Unable to add block \"" << name.as_string() << "\" at "
2042 : << address << " with size " << size << ".";
2043 i : return NULL;
2044 : }
2045 :
2046 : // Mark the source range from whence this block originates. This is assuming
2047 : // an untransformed image. To handle transformed images we'd have to use the
2048 : // OMAP information to do this properly.
2049 E : bool pushed = block->source_ranges().Push(
2050 : Block::DataRange(0, size),
2051 : Block::SourceRange(address, size));
2052 E : DCHECK(pushed);
2053 :
2054 E : BlockGraph::SectionId section = image_file_.GetSectionIndex(address, size);
2055 E : if (section == BlockGraph::kInvalidSectionId) {
2056 i : LOG(ERROR) << "Block \"" << name.as_string() << "\" at " << address
2057 : << " with size " << size << " lies outside of all sections.";
2058 i : return NULL;
2059 : }
2060 E : block->set_section(section);
2061 :
2062 E : const uint8_t* data = image_file_.GetImageData(address, size);
2063 E : if (data != NULL)
2064 E : block->SetData(data, size);
2065 :
2066 E : return block;
2067 E : }
2068 :
2069 : Block* Decomposer::CreateBlockOrFindCoveringPeBlock(
2070 : BlockType type,
2071 : RelativeAddress addr,
2072 : BlockGraph::Size size,
2073 E : const base::StringPiece& name) {
2074 E : Block* block = image_->GetBlockByAddress(addr);
2075 E : if (block != NULL) {
2076 E : RelativeAddress block_addr;
2077 E : CHECK(image_->GetAddressOf(block, &block_addr));
2078 :
2079 : // Allow PE-parsed blocks to be grown to reflect reality. For example,
2080 : // in VS2013 the linker makes space for 2 debug directories rather than
2081 : // just one, and the symbols reflect this. We parse the debug directory
2082 : // with the size indicated in the PE header, which conflicts with that
2083 : // indicated by the section contributions.
2084 E : if (name == "* Linker *" && block_addr == addr && size > block->size()) {
2085 E : if (!image_->ResizeBlock(block, size)) {
2086 i : LOG(ERROR) << "Failed to extend PE-parsed "
2087 : << BlockInfo(block, block_addr) << " with linker "
2088 : << "section contribution of size " << size << ".";
2089 :
2090 : // Get the conflicting block and output additional information about
2091 : // it.
2092 i : Block* conflict = image_->GetFirstIntersectingBlock(
2093 : block_addr + block->size(), size - block->size());
2094 i : if (conflict) {
2095 i : RelativeAddress conflict_addr;
2096 i : CHECK(image_->GetAddressOf(conflict, &conflict_addr));
2097 i : LOG(ERROR) << "Conflicts with existing "
2098 : << BlockInfo(conflict, conflict_addr) << ".";
2099 : }
2100 :
2101 i : return NULL;
2102 : }
2103 :
2104 : // Update the data in the extended block.
2105 E : const uint8_t* data = image_file_.GetImageData(addr, size);
2106 E : block->SetData(data, size);
2107 E : return block;
2108 : }
2109 :
2110 : // If this is not a PE parsed or COFF group block that covers us entirely,
2111 : // then this is an error.
2112 : static const BlockGraph::BlockAttributes kCoveringAttributes =
2113 : BlockGraph::PE_PARSED | BlockGraph::COFF_GROUP;
2114 E : RelativeRange existing_block(block_addr, block->size());
2115 E : if ((block->attributes() & kCoveringAttributes) == 0 ||
2116 : !existing_block.Contains(addr, size)) {
2117 i : LOG(ERROR) << "Trying to create block \"" << name.as_string() << "\" at "
2118 : << addr.value() << " with size " << size << " that conflicts "
2119 : << "with existing " << BlockInfo(block, block_addr) << ".";
2120 i : return NULL;
2121 : }
2122 :
2123 E : return block;
2124 : }
2125 E : DCHECK_EQ(reinterpret_cast<Block*>(NULL), block);
2126 :
2127 E : return CreateBlock(type, addr, size, name);
2128 E : }
2129 :
2130 : bool Decomposer::CreateGapBlock(BlockType block_type,
2131 : RelativeAddress address,
2132 E : BlockGraph::Size size) {
2133 E : Block* block = CreateBlock(block_type, address, size,
2134 : base::StringPrintf("Gap Block 0x%08X", address.value()).c_str());
2135 E : if (block == NULL) {
2136 i : LOG(ERROR) << "Unable to create gap block.";
2137 i : return false;
2138 : }
2139 E : block->set_attribute(BlockGraph::GAP_BLOCK);
2140 :
2141 E : return true;
2142 E : }
2143 :
2144 : bool Decomposer::CreateSectionGapBlocks(const IMAGE_SECTION_HEADER* header,
2145 E : BlockType block_type) {
2146 E : RelativeAddress section_begin(header->VirtualAddress);
2147 E : RelativeAddress section_end(section_begin + header->Misc.VirtualSize);
2148 E : RelativeAddress image_end(
2149 : image_file_.nt_headers()->OptionalHeader.SizeOfImage);
2150 :
2151 : // Search for the first and last blocks interesting from the start and end
2152 : // of the section to the end of the image.
2153 : BlockGraph::AddressSpace::RangeMap::const_iterator it(
2154 E : image_->address_space_impl().FindFirstIntersection(
2155 : BlockGraph::AddressSpace::Range(section_begin,
2156 : image_end - section_begin)));
2157 :
2158 : BlockGraph::AddressSpace::RangeMap::const_iterator end =
2159 E : image_->address_space_impl().end();
2160 E : if (section_end < image_end) {
2161 E : end = image_->address_space_impl().FindFirstIntersection(
2162 : BlockGraph::AddressSpace::Range(section_end,
2163 : image_end - section_end));
2164 : }
2165 :
2166 : // The whole section is missing. Cover it with one gap block.
2167 E : if (it == end)
2168 i : return CreateGapBlock(
2169 : block_type, section_begin, section_end - section_begin);
2170 :
2171 : // Create the head gap block if need be.
2172 E : if (section_begin < it->first.start()) {
2173 i : if (!CreateGapBlock(
2174 : block_type, section_begin, it->first.start() - section_begin)) {
2175 i : return false;
2176 : }
2177 : }
2178 :
2179 : // Now iterate the blocks and fill in gaps.
2180 E : for (; it != end; ++it) {
2181 E : const Block* block = it->second;
2182 E : DCHECK_NE(reinterpret_cast<Block*>(NULL), block);
2183 E : RelativeAddress block_end = it->first.start() + block->size();
2184 E : if (block_end >= section_end)
2185 E : break;
2186 :
2187 : // Walk to the next address in turn.
2188 E : BlockGraph::AddressSpace::RangeMap::const_iterator next = it;
2189 E : ++next;
2190 E : if (next == end) {
2191 : // We're at the end of the list. Create the tail gap block.
2192 E : DCHECK_GT(section_end, block_end);
2193 E : if (!CreateGapBlock(block_type, block_end, section_end - block_end))
2194 i : return false;
2195 E : break;
2196 : }
2197 :
2198 : // Create the interstitial gap block.
2199 E : if (block_end < next->first.start()) {
2200 E : if (!CreateGapBlock(
2201 : block_type, block_end, next->first.start() - block_end)) {
2202 i : return false;
2203 : }
2204 : }
2205 E : }
2206 :
2207 E : return true;
2208 E : }
2209 :
2210 : } // namespace pe
|