1 : // Copyright 2015 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/hot_patching_decomposer.h"
16 :
17 : #include "base/bind.h"
18 : #include "syzygy/common/defs.h"
19 : #include "syzygy/pe/pe_utils.h"
20 :
21 : namespace pe {
22 :
23 : namespace {
24 :
25 : using block_graph::BlockGraph;
26 : using block_graph::BlockInfo;
27 : using core::AbsoluteAddress;
28 : using core::FileOffsetAddress;
29 : using core::RelativeAddress;
30 :
31 : typedef BlockGraph::Block Block;
32 :
33 : // NOTE: This is based on GetSectionName in from pe_coff_file_impl.h.
34 E : std::string GetSectionName(const IMAGE_SECTION_HEADER& section) {
35 E : const char* name = reinterpret_cast<const char*>(section.Name);
36 E : return std::string(name, strnlen(name, arraysize(section.Name)));
37 E : }
38 :
39 : // NOTE: This is based on CopySectionInfoToBlockGraph in pe_utils_impl.h.
40 : // Added the section_index parameter to create an index used later in
41 : // CreateBlock.
42 : bool CopySectionInfoToBlockGraph(
43 : const base::win::PEImage& image_file,
44 : BlockGraph* block_graph,
45 E : HotPatchingDecomposer::SectionIdMap* section_index) {
46 E : DCHECK_NE(static_cast<BlockGraph*>(nullptr), block_graph);
47 : DCHECK_NE(static_cast<HotPatchingDecomposer::SectionIdMap*>(nullptr),
48 E : section_index);
49 :
50 : // Iterate through the image sections, and create sections in the BlockGraph.
51 E : size_t num_sections = image_file.GetNTHeaders()->FileHeader.NumberOfSections;
52 E : for (size_t i = 0; i < num_sections; ++i) {
53 E : const IMAGE_SECTION_HEADER* header = image_file.GetSectionHeader(i);
54 E : std::string name = GetSectionName(*header);
55 : BlockGraph::Section* section = block_graph->AddSection(
56 E : name, header->Characteristics);
57 E : DCHECK_NE(static_cast<BlockGraph::Section*>(nullptr), section);
58 :
59 : // For now, we expect them to have been created with the same IDs as those
60 : // in the original image.
61 E : if (section->id() != i) {
62 i : LOG(ERROR) << "Unexpected section ID.";
63 i : return false;
64 : }
65 :
66 E : section_index->insert(std::make_pair(header, section->id()));
67 E : }
68 :
69 E : return true;
70 E : }
71 :
72 : // Interprets the 32-bit unsigned integer parameter as a pointer, and checks
73 : // if it points to the block's data, after a specific offset.
74 : // @param displacement The 32-bit unsigned integer.
75 : // @param block The block to check.
76 : // @param offset The pointer must point after this offset.
77 : // @returns true if the conditions are met, false otherwise.
78 : bool DisplacementPointsIntoBlockAfterOffset(uint32 displacement,
79 : const BlockGraph::Block* block,
80 E : size_t offset) {
81 E : DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), block);
82 :
83 : return reinterpret_cast<uint8*>(displacement) >=
84 : block->data() + offset &&
85 : reinterpret_cast<uint8*>(displacement) <
86 E : block->data() + block->data_size();
87 E : }
88 :
89 : // This function is called when we didn't manage to parse an instruction.
90 : // We do some sanity DCHECKs to verify that the instruction does not contain
91 : // a reference that we failed to recover.
92 : // @param block The block containing the instructions.
93 : // @param inst The instruction to examine.
94 : void ExecuteSanityChecks(BlockGraph::Block* block,
95 : BlockGraph::Offset offset,
96 E : const _DInst& inst) {
97 E : DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), block);
98 :
99 E : for (int i = 0; i < arraysize(inst.ops); ++i) {
100 : // Fail if we see PC-relative operand.
101 E : if (inst.ops[i].type == O_PC)
102 i : NOTREACHED();
103 :
104 : // Fail if we see an absolute pointer in the displacement that can be
105 : // interpreted as a pointer to anywhere inside the block. This is
106 : // probably some unknown construct that needs to be handled.
107 E : if (inst.ops[i].type == O_SMEM || inst.ops[i].type == O_MEM) {
108 : if (inst.dispSize == 32U &&
109 E : DisplacementPointsIntoBlockAfterOffset(inst.disp, block, 0U)) {
110 i : LOG(ERROR) << "Pointer-like displacement: " << inst.disp;
111 i : NOTREACHED();
112 : }
113 : }
114 E : }
115 E : }
116 :
117 : // Adds a data label to a block. If a data label already exists at the offset
118 : // that is neither a case table nor a jump table label, it will be replaced.
119 : // Otherwise a DCHECK will be used to check if the old and the desired labels
120 : // have the same attributes.
121 : // @param block The block to add the label to.
122 : // @param offset The offset of the desired label.
123 : // @param label_name The name of the desired label.
124 : // @param additional_attribute Specifies whether the desired label is a
125 : // JUMP_TABLE_LABEL or CASE_TABLE_LABEL.
126 : void AddDataLabel(BlockGraph::Block* block,
127 : BlockGraph::Offset offset,
128 : const std::string& label_name,
129 E : BlockGraph::LabelAttributesEnum additional_attribute) {
130 E : DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), block);
131 : DCHECK(additional_attribute == BlockGraph::JUMP_TABLE_LABEL ||
132 E : additional_attribute == BlockGraph::CASE_TABLE_LABEL);
133 :
134 : BlockGraph::LabelAttributes label_attributes =
135 E : BlockGraph::DATA_LABEL | additional_attribute;
136 :
137 E : if (block->HasLabel(offset)) {
138 : // The label already exists, just update the attribute if needed.
139 E : BlockGraph::Label old_label;
140 E : block->GetLabel(offset, &old_label);
141 E : DCHECK(old_label.has_attributes(BlockGraph::DATA_LABEL));
142 :
143 E : if (old_label.attributes() == BlockGraph::DATA_LABEL) {
144 : // A simple DATA_LABEL is created by the decomposer at the end of the code
145 : // block. We replace this label with a more specific one.
146 :
147 : // The data part may not start with a case table.
148 E : DCHECK_EQ(additional_attribute, BlockGraph::JUMP_TABLE_LABEL);
149 :
150 : // We can't change the label, so remove it and add a new one.
151 E : block->RemoveLabel(offset);
152 E : } else {
153 : // Sanity check: no case table and jump table at the same location.
154 i : DCHECK_EQ(old_label.name(), label_name);
155 i : DCHECK_EQ(old_label.attributes(), label_attributes);
156 :
157 : // The label is already there, no need to add it again.
158 i : return;
159 : }
160 E : }
161 :
162 E : if (!block->SetLabel(offset, label_name, label_attributes)) {
163 : // SetLabel returns false if the label already existed, which can't happen
164 : // because we've just removed it.
165 i : NOTREACHED();
166 : }
167 E : }
168 :
169 : } // namespace
170 :
171 : HotPatchingDecomposer::HotPatchingDecomposer(HMODULE module)
172 : : image_layout_(nullptr),
173 : image_(nullptr),
174 : last_code_block_id_(0U),
175 E : module_(module) {
176 E : }
177 :
178 E : HotPatchingDecomposer::~HotPatchingDecomposer() { }
179 :
180 E : bool HotPatchingDecomposer::Decompose(ImageLayout* image_layout) {
181 E : DCHECK_NE(static_cast<ImageLayout*>(nullptr), image_layout);
182 :
183 : // The temporaries should be nullptr.
184 E : DCHECK_EQ(static_cast<ImageLayout*>(nullptr), image_layout_);
185 E : DCHECK_EQ(static_cast<BlockGraph::AddressSpace*>(nullptr), image_);
186 :
187 E : image_layout_ = image_layout;
188 E : image_ = &(image_layout->blocks);
189 :
190 : // Initialize in-memory PE wrapper.
191 E : pe_image_ = std::make_unique<base::win::PEImage>(module_);
192 :
193 : // Set the image format.
194 E : image_->graph()->set_image_format(BlockGraph::PE_IN_MEMORY_IMAGE);
195 :
196 : // Process sections in image.
197 E : if (!LoadSectionInformation())
198 i : return false;
199 :
200 : // Process blocks using the hot patching metadata.
201 E : if (!LoadHotPatchableBlocks())
202 i : return false;
203 :
204 E : return true;
205 E : }
206 :
207 : // NOTE: This is based on Decomposer::CreateBlock.
208 : Block* HotPatchingDecomposer::CreateBlock(BlockType type,
209 : RelativeAddress address,
210 : BlockGraph::Size size,
211 E : const base::StringPiece& name) {
212 E : Block* block = image_->AddBlock(type, address, size, name);
213 E : if (block == nullptr) {
214 i : LOG(ERROR) << "Unable to add block \"" << name.as_string() << "\" at "
215 : << address << " with size " << size << ".";
216 i : return nullptr;
217 : }
218 :
219 : // Mark the source range from whence this block originates.
220 : bool pushed = block->source_ranges().Push(
221 : Block::DataRange(0, size),
222 E : Block::SourceRange(address, size));
223 E : DCHECK(pushed);
224 :
225 : // Search section id in the index.
226 : const IMAGE_SECTION_HEADER* block_section_header =
227 E : pe_image_->GetImageSectionFromAddr(pe_image_->RVAToAddr(address.value()));
228 E : if (block_section_header == nullptr) {
229 i : LOG(ERROR) << "Block \"" << name.as_string() << "\" at " << address
230 : << " with size " << size << " lies outside of all sections.";
231 i : return nullptr;
232 : }
233 E : const auto it = section_index_.find(block_section_header);
234 E : DCHECK(it != section_index_.end());
235 E : block->set_section(it->second);
236 :
237 : const uint8* data = static_cast<const uint8*>(
238 E : pe_image_->RVAToAddr(address.value()));
239 E : if (data != nullptr)
240 E : block->SetData(data, size);
241 :
242 E : return block;
243 E : }
244 :
245 : bool HotPatchingDecomposer::InferCodeReferences(Block* block,
246 E : size_t code_size) {
247 E : DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), block);
248 :
249 : // Disassemble the block
250 E : size_t offset = 0;
251 E : while (offset < code_size) {
252 : _DInst inst;
253 :
254 : // Try to decode the next instruction.
255 E : const uint8* inst_data = block->data() + offset;
256 E : if (!core::DecodeOneInstruction(inst_data, code_size - offset, &inst)) {
257 i : LOG(ERROR) << "Failed to decode instruction at offset " << offset
258 : << " in block " << BlockInfo(block);
259 i : return false;
260 : }
261 :
262 : // Try to recover reference from the instruction.
263 E : bool parsed = false;
264 E : if (!ParsePCRelativeBranchAndCallInstuction(block, offset, inst, &parsed))
265 i : return false;
266 E : if (!parsed && !ParseJumpTableCall(block, offset, inst, code_size, &parsed))
267 i : return false;
268 E : if (!parsed && !ParseCaseTableRead(block, offset, inst, code_size, &parsed))
269 i : return false;
270 :
271 : // Do some sanity checks in DCHECK builds if we see no reference.
272 E : if (!parsed)
273 E : ExecuteSanityChecks(block, offset, inst);
274 :
275 E : offset += inst.size;
276 E : }
277 :
278 E : return true;
279 E : }
280 :
281 : bool HotPatchingDecomposer::InferJumpTableReferences(Block* block,
282 E : size_t code_size) {
283 E : DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), block);
284 :
285 E : const uint8* block_start = block->data();
286 E : const uint8* block_end = block->data() + block->data_size();
287 :
288 E : for (auto it = block->labels().begin(); it != block->labels().end();) {
289 E : BlockGraph::Offset offset = it->first;
290 E : const BlockGraph::Label& label = it->second;
291 :
292 : // We increment the iterator here because we want to access the next label
293 : // below. The current label is already saved in |label|.
294 E : ++it;
295 :
296 E : if (label.has_attributes(BlockGraph::JUMP_TABLE_LABEL)) {
297 : // The jump table ends at the next label or at the end of the block.
298 E : BlockGraph::Offset end_offset = 0;
299 E : if (it != block->labels().end()) {
300 E : end_offset = it->first;
301 E : } else {
302 E : end_offset = block->data_size();
303 : }
304 :
305 : // Calculate start and end relative addresses.
306 E : RelativeAddress addr = block->addr() + offset;
307 E : const RelativeAddress end_addr = block->addr() + end_offset;
308 :
309 : // While we have more than 4 bytes remaining.
310 E : for (; addr <= end_addr - 4; addr += 4) {
311 :
312 : // Interpret the 4 bytes starting at |addr| as a pointer.
313 : const uint8* const* target_location =
314 : reinterpret_cast<const uint8* const*>(
315 E : block->data() + (addr - block->addr()));
316 E : const uint8* target_as_pointer = *target_location;
317 :
318 : // Add an absolute reference if this address points into the block.
319 E : if (block_start <= target_as_pointer && target_as_pointer < block_end) {
320 E : BlockGraph::Offset target_offset = target_as_pointer - block_start;
321 E : DCHECK_GE(target_offset, 0);
322 : // The reference should not point into the data part of the block.
323 E : DCHECK_LT(target_offset, static_cast<int>(code_size));
324 :
325 : if (!block->SetReference(addr - block->addr(),
326 : BlockGraph::Reference(
327 : BlockGraph::ABSOLUTE_REF,
328 : 4,
329 : block,
330 : target_offset,
331 E : target_offset))) {
332 i : return false;
333 : }
334 : }
335 E : }
336 : }
337 E : }
338 :
339 E : return true;
340 E : }
341 :
342 E : bool HotPatchingDecomposer::LoadHotPatchableBlocks() {
343 : PIMAGE_SECTION_HEADER hp_sect_hdr = pe_image_->GetImageSectionHeaderByName(
344 E : common::kHotPatchingMetadataSectionName);
345 E : DCHECK_NE(static_cast<PIMAGE_SECTION_HEADER>(nullptr), hp_sect_hdr);
346 :
347 : // Load metadata section header.
348 : block_graph::HotPatchingMetadataHeader* hp_metadata_header =
349 : static_cast<block_graph::HotPatchingMetadataHeader*>(
350 E : pe_image_->RVAToAddr(hp_sect_hdr->VirtualAddress));
351 : DCHECK_NE(static_cast<block_graph::HotPatchingMetadataHeader*>(nullptr),
352 E : hp_metadata_header);
353 : if (block_graph::kHotPatchingMetadataVersion !=
354 E : hp_metadata_header->version) {
355 i : return false;
356 : }
357 :
358 : // Locate the block metadata array. The (hp_metadata_header + 1) expression is
359 : // a pointer pointing to the location after the header.
360 : block_graph::HotPatchingBlockMetadata* hp_block_metadata_arr =
361 : reinterpret_cast<block_graph::HotPatchingBlockMetadata*>(
362 E : hp_metadata_header + 1);
363 :
364 : // Create hot patchable code blocks and their labels based on the hot
365 : // patching metadata.
366 E : for (size_t i = 0; i < hp_metadata_header->number_of_blocks; ++i) {
367 E : Block* block = ProcessHotPatchableCodeBlock(hp_block_metadata_arr[i]);
368 E : DCHECK_NE(static_cast<Block*>(nullptr), block);
369 E : }
370 :
371 : // Create references for hot patchable code blocks.
372 : //
373 : // This must run after all hot patchable blocks have been created because it
374 : // searches for the referred block and creates a dummy block if the referred
375 : // block is not found.
376 E : for (size_t i = 0; i < hp_metadata_header->number_of_blocks; ++i) {
377 : Block* block = image_layout_->blocks.GetBlockByAddress(
378 E : RelativeAddress(hp_block_metadata_arr[i].relative_address));
379 :
380 E : DCHECK_NE(static_cast<Block*>(nullptr), block);
381 :
382 E : InferCodeReferences(block, hp_block_metadata_arr[i].code_size);
383 :
384 : if (hp_block_metadata_arr[i].code_size <
385 E : hp_block_metadata_arr[i].block_size) {
386 E : InferJumpTableReferences(block, hp_block_metadata_arr[i].code_size);
387 : }
388 E : }
389 :
390 E : return true;
391 E : }
392 :
393 E : bool HotPatchingDecomposer::LoadSectionInformation() {
394 : // Create sections in the image layout.
395 : CopySectionHeadersToImageLayout(
396 : pe_image_->GetNTHeaders()->FileHeader.NumberOfSections,
397 : pe_image_->GetSectionHeader(0),
398 E : &(image_layout_->sections));
399 :
400 : // Create the sections in the underlying block-graph.
401 : if (!CopySectionInfoToBlockGraph(*pe_image_,
402 : image_->graph(),
403 E : §ion_index_)) {
404 i : return false;
405 : }
406 :
407 E : return true;
408 E : }
409 :
410 : bool HotPatchingDecomposer::ParseCaseTableRead(BlockGraph::Block* block,
411 : BlockGraph::Offset offset,
412 : const _DInst &inst,
413 : size_t code_size,
414 E : bool* parsed) {
415 E : DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), block);
416 E : DCHECK_NE(static_cast<bool*>(nullptr), parsed);
417 :
418 : // Check if the instruction is a case table read.
419 : *parsed = inst.opcode == I_MOVZX &&
420 : inst.ops[0].type == O_REG &&
421 : inst.ops[1].type == O_SMEM &&
422 : inst.dispSize == 32U &&
423 : inst.ops[2].type == O_NONE &&
424 E : DisplacementPointsIntoBlockAfterOffset(inst.disp, block, code_size);
425 :
426 : // Return early if not.
427 E : if (!*parsed)
428 E : return true;
429 :
430 E : int reference_size = inst.dispSize / 8;
431 :
432 : BlockGraph::Offset ref_source_offset =
433 E : offset + inst.size - reference_size;
434 : BlockGraph::Offset ref_target_offset =
435 E : reinterpret_cast<uint8*>(inst.disp) - block->data();
436 :
437 : // The displacement is at the end of this instruction.
438 : if (!block->SetReference(ref_source_offset,
439 : BlockGraph::Reference(
440 : BlockGraph::ABSOLUTE_REF,
441 : reference_size,
442 : block,
443 : ref_target_offset,
444 E : ref_target_offset))) {
445 i : LOG(ERROR) << "Failed to create self reference in block "
446 : << BlockInfo(block) << " from offset "
447 : << ref_source_offset << " to offset " << ref_target_offset;
448 i : return false;
449 : }
450 :
451 : // Insert a case table label.
452 : AddDataLabel(block,
453 : ref_target_offset,
454 : "case-table",
455 E : BlockGraph::CASE_TABLE_LABEL);
456 :
457 E : return true;
458 E : }
459 :
460 : bool HotPatchingDecomposer::ParseJumpTableCall(BlockGraph::Block* block,
461 : BlockGraph::Offset offset,
462 : const _DInst &inst,
463 : size_t code_size,
464 E : bool* parsed) {
465 E : DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), block);
466 E : DCHECK_NE(static_cast<bool*>(nullptr), parsed);
467 :
468 : // Check if the instruction is a jump using a jump table.
469 : *parsed = inst.opcode == I_JMP &&
470 : inst.ops[0].type == O_MEM &&
471 : inst.ops[1].type == O_NONE &&
472 : inst.scale == 4U &&
473 : inst.dispSize == 32U &&
474 : DisplacementPointsIntoBlockAfterOffset(inst.disp, block,
475 E : code_size);
476 :
477 : // Return early if not.
478 E : if (!*parsed)
479 E : return true;
480 :
481 E : int reference_size = inst.dispSize / 8;
482 :
483 : BlockGraph::Offset ref_source_offset =
484 E : offset + inst.size - reference_size;
485 : BlockGraph::Offset ref_target_offset =
486 E : reinterpret_cast<uint8*>(inst.disp) - block->data();
487 :
488 : // The displacement is always at the end of a one-operand instruction.
489 : if (!block->SetReference(ref_source_offset,
490 : BlockGraph::Reference(
491 : BlockGraph::ABSOLUTE_REF,
492 : reference_size,
493 : block,
494 : ref_target_offset,
495 E : ref_target_offset))) {
496 i : LOG(ERROR) << "Failed to create self reference in block "
497 : << BlockInfo(block) << " from offset "
498 : << ref_source_offset << " to offset " << ref_target_offset;
499 i : return false;
500 : }
501 :
502 : // Insert a jump table label.
503 : AddDataLabel(block,
504 : ref_target_offset,
505 : "jump-table",
506 E : BlockGraph::JUMP_TABLE_LABEL);
507 :
508 E : return true;
509 E : }
510 :
511 : bool HotPatchingDecomposer::ParsePCRelativeBranchAndCallInstuction(
512 : BlockGraph::Block* block,
513 : BlockGraph::Offset offset,
514 : const _DInst &inst,
515 E : bool* parsed) {
516 E : DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), block);
517 E : DCHECK_NE(static_cast<bool*>(nullptr), parsed);
518 :
519 : *parsed = (core::IsBranch(inst) || core::IsCall(inst)) &&
520 E : inst.ops[0].type == O_PC;
521 E : if (!*parsed)
522 E : return true;
523 :
524 E : CHECK(inst.ops[1].type == O_NONE);
525 :
526 E : int reference_size = inst.ops[0].size / 8;
527 :
528 E : if (reference_size == 4) {
529 : // Insert a reference for 32-bit PC-relative jump and call instructions.
530 :
531 : // Create the reference.
532 E : BlockGraph::Offset pc_relative_address = inst.imm.addr;
533 : RelativeAddress target_relative_address = RelativeAddress(
534 E : block->addr().value() + offset + pc_relative_address + inst.size);
535 : Block* referenced_block = image_layout_->blocks.GetBlockByAddress(
536 E : target_relative_address);
537 :
538 E : BlockGraph::Offset ref_target_offset = 0;
539 :
540 E : if (referenced_block != nullptr) {
541 : ref_target_offset =
542 E : target_relative_address - referenced_block->addr();
543 :
544 E : if (referenced_block != block) {
545 : // If the following check fails that means that we have an
546 : // inter-block reference pointing inside a hot patchable block.
547 E : CHECK_EQ(target_relative_address, referenced_block->addr());
548 : }
549 E : } else {
550 : // There is no block at the referred location. This means that the
551 : // referred block is not hot patchable. Create a dummy code block that
552 : // can be referenced.
553 : referenced_block = CreateBlock(BlockGraph::CODE_BLOCK,
554 : target_relative_address,
555 : 1,
556 E : "TargetBlock");
557 E : DCHECK_NE(static_cast<Block*>(nullptr), referenced_block);
558 : // We set the BUILT_BY_UNSUPPORTED_COMPILER attribute on dummy blocks.
559 : // This attribute expresses that the block can't be moved and the data
560 : // of the block should not be interpreted.
561 : referenced_block->set_attribute(
562 E : BlockGraph::BUILT_BY_UNSUPPORTED_COMPILER);
563 :
564 E : ref_target_offset = 0;
565 : }
566 :
567 E : DCHECK_GE(inst.size, 1 + reference_size);
568 E : DCHECK_GE(2 + reference_size, inst.size);
569 :
570 : // The reference is always at the end of the instruction.
571 : if (!block->SetReference(offset + inst.size - reference_size,
572 : BlockGraph::Reference(
573 : BlockGraph::PC_RELATIVE_REF,
574 : reference_size,
575 : referenced_block,
576 : ref_target_offset,
577 E : ref_target_offset))) {
578 i : return false;
579 : }
580 E : ++parsed;
581 : } else {
582 : // We don't deal with smaller references. These are in-block references
583 : // that are resolved by the basic block decomposer.
584 : }
585 :
586 E : return true;
587 E : }
588 :
589 : Block *HotPatchingDecomposer::ProcessHotPatchableCodeBlock(
590 E : const block_graph::HotPatchingBlockMetadata& block_metadata) {
591 :
592 : // The relative address will point to the correct field as it should be
593 : // relocated.
594 E : RelativeAddress data_address(block_metadata.relative_address);
595 E : size_t block_size = block_metadata.block_size;
596 :
597 : // Generate a unique name for the block.
598 E : ++last_code_block_id_;
599 E : std::string block_name = "CodeBlock" + std::to_string(last_code_block_id_);
600 :
601 : // Add the block to the block graph.
602 : Block* block = CreateBlock(BlockGraph::CODE_BLOCK,
603 : data_address,
604 : block_size,
605 E : block_name);
606 E : if (block == nullptr) {
607 i : LOG(ERROR) << "Unable to add code block at "
608 : << data_address << " with size " << block_size << ".";
609 i : return nullptr;
610 : }
611 :
612 : // Add a code label to the beginning of the block.
613 E : block->SetLabel(0, "CODE", BlockGraph::CODE_LABEL);
614 :
615 : // If the code does not fill the whole data, put a data label at the end of
616 : // the code.
617 E : if (block_metadata.code_size != block_metadata.block_size) {
618 : block->SetLabel(static_cast<int>(block_metadata.code_size),
619 E : "DATA", BlockGraph::DATA_LABEL);
620 : }
621 :
622 E : return block;
623 E : }
624 :
625 : } // namespace pe
|