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 E : 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 : uint32_t num_sections =
52 E : image_file.GetNTHeaders()->FileHeader.NumberOfSections;
53 E : for (uint32_t i = 0; i < num_sections; ++i) {
54 E : const IMAGE_SECTION_HEADER* header = image_file.GetSectionHeader(i);
55 E : std::string name = GetSectionName(*header);
56 E : BlockGraph::Section* section = block_graph->AddSection(
57 : name, header->Characteristics);
58 E : DCHECK_NE(static_cast<BlockGraph::Section*>(nullptr), section);
59 :
60 : // For now, we expect them to have been created with the same IDs as those
61 : // in the original image.
62 E : if (section->id() != i) {
63 i : LOG(ERROR) << "Unexpected section ID.";
64 i : return false;
65 : }
66 :
67 E : section_index->insert(std::make_pair(header, section->id()));
68 E : }
69 :
70 E : return true;
71 E : }
72 :
73 : // Interprets the 32-bit unsigned integer parameter as a pointer, and checks
74 : // if it points to the block's data, after a specific offset.
75 : // @param displacement The 32-bit unsigned integer.
76 : // @param block The block to check.
77 : // @param offset The pointer must point after this offset.
78 : // @returns true if the conditions are met, false otherwise.
79 : bool DisplacementPointsIntoBlockAfterOffset(uint32_t displacement,
80 : const BlockGraph::Block* block,
81 E : size_t offset) {
82 E : DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), block);
83 :
84 E : return reinterpret_cast<uint8_t*>(displacement) >= block->data() + offset &&
85 : reinterpret_cast<uint8_t*>(displacement) <
86 : 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 E : if (inst.dispSize == 32U &&
109 : 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 E : DCHECK(additional_attribute == BlockGraph::JUMP_TABLE_LABEL ||
132 : 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 E : : image_layout_(nullptr),
173 E : image_(nullptr),
174 E : 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 E : bool pushed = block->source_ranges().Push(
221 : Block::DataRange(0, size),
222 : 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_t* data =
238 E : static_cast<const uint8_t*>(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_t* inst_data = block->data() + offset;
256 E : if (!core::DecodeOneInstruction(inst_data,
257 : static_cast<int>(code_size - offset),
258 : &inst)) {
259 i : LOG(ERROR) << "Failed to decode instruction at offset " << offset
260 : << " in block " << BlockInfo(block);
261 i : return false;
262 : }
263 :
264 : // Try to recover reference from the instruction.
265 E : bool parsed = false;
266 E : if (!ParsePCRelativeBranchAndCallInstuction(block, offset, inst, &parsed))
267 i : return false;
268 E : if (!parsed && !ParseJumpTableCall(block, offset, inst, code_size, &parsed))
269 i : return false;
270 E : if (!parsed && !ParseCaseTableRead(block, offset, inst, code_size, &parsed))
271 i : return false;
272 :
273 : // Do some sanity checks in DCHECK builds if we see no reference.
274 E : if (!parsed)
275 E : ExecuteSanityChecks(block, offset, inst);
276 :
277 E : offset += inst.size;
278 E : }
279 :
280 E : return true;
281 E : }
282 :
283 : bool HotPatchingDecomposer::InferJumpTableReferences(Block* block,
284 E : size_t code_size) {
285 E : DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), block);
286 :
287 E : const uint8_t* block_start = block->data();
288 E : const uint8_t* block_end = block->data() + block->data_size();
289 :
290 E : for (auto it = block->labels().begin(); it != block->labels().end();) {
291 E : BlockGraph::Offset offset = it->first;
292 E : const BlockGraph::Label& label = it->second;
293 :
294 : // We increment the iterator here because we want to access the next label
295 : // below. The current label is already saved in |label|.
296 E : ++it;
297 :
298 E : if (label.has_attributes(BlockGraph::JUMP_TABLE_LABEL)) {
299 : // The jump table ends at the next label or at the end of the block.
300 E : BlockGraph::Offset end_offset = 0;
301 E : if (it != block->labels().end()) {
302 E : end_offset = it->first;
303 E : } else {
304 E : end_offset = block->data_size();
305 : }
306 :
307 : // Calculate start and end relative addresses.
308 E : RelativeAddress addr = block->addr() + offset;
309 E : const RelativeAddress end_addr = block->addr() + end_offset;
310 :
311 : // While we have more than 4 bytes remaining.
312 E : for (; addr <= end_addr - 4; addr += 4) {
313 :
314 : // Interpret the 4 bytes starting at |addr| as a pointer.
315 : const uint8_t* const* target_location =
316 E : reinterpret_cast<const uint8_t* const*>(block->data() +
317 : (addr - block->addr()));
318 E : const uint8_t* target_as_pointer = *target_location;
319 :
320 : // Add an absolute reference if this address points into the block.
321 E : if (block_start <= target_as_pointer && target_as_pointer < block_end) {
322 E : BlockGraph::Offset target_offset = target_as_pointer - block_start;
323 E : DCHECK_GE(target_offset, 0);
324 : // The reference should not point into the data part of the block.
325 E : DCHECK_LT(target_offset, static_cast<int>(code_size));
326 :
327 E : if (!block->SetReference(addr - block->addr(),
328 : BlockGraph::Reference(
329 : BlockGraph::ABSOLUTE_REF,
330 : 4,
331 : block,
332 : target_offset,
333 : target_offset))) {
334 i : return false;
335 : }
336 : }
337 E : }
338 : }
339 E : }
340 :
341 E : return true;
342 E : }
343 :
344 E : bool HotPatchingDecomposer::LoadHotPatchableBlocks() {
345 E : PIMAGE_SECTION_HEADER hp_sect_hdr = pe_image_->GetImageSectionHeaderByName(
346 : common::kHotPatchingMetadataSectionName);
347 E : DCHECK_NE(static_cast<PIMAGE_SECTION_HEADER>(nullptr), hp_sect_hdr);
348 :
349 : // Load metadata section header.
350 : block_graph::HotPatchingMetadataHeader* hp_metadata_header =
351 : static_cast<block_graph::HotPatchingMetadataHeader*>(
352 E : pe_image_->RVAToAddr(hp_sect_hdr->VirtualAddress));
353 E : DCHECK_NE(static_cast<block_graph::HotPatchingMetadataHeader*>(nullptr),
354 E : hp_metadata_header);
355 E : if (block_graph::kHotPatchingMetadataVersion !=
356 : hp_metadata_header->version) {
357 i : return false;
358 : }
359 :
360 : // Locate the block metadata array. The (hp_metadata_header + 1) expression is
361 : // a pointer pointing to the location after the header.
362 : block_graph::HotPatchingBlockMetadata* hp_block_metadata_arr =
363 : reinterpret_cast<block_graph::HotPatchingBlockMetadata*>(
364 E : hp_metadata_header + 1);
365 :
366 : // Create hot patchable code blocks and their labels based on the hot
367 : // patching metadata.
368 E : for (size_t i = 0; i < hp_metadata_header->number_of_blocks; ++i) {
369 E : Block* block = ProcessHotPatchableCodeBlock(hp_block_metadata_arr[i]);
370 E : DCHECK_NE(static_cast<Block*>(nullptr), block);
371 E : }
372 :
373 : // Create references for hot patchable code blocks.
374 : //
375 : // This must run after all hot patchable blocks have been created because it
376 : // searches for the referred block and creates a dummy block if the referred
377 : // block is not found.
378 E : for (size_t i = 0; i < hp_metadata_header->number_of_blocks; ++i) {
379 E : Block* block = image_layout_->blocks.GetBlockByAddress(
380 : RelativeAddress(hp_block_metadata_arr[i].relative_address));
381 :
382 E : DCHECK_NE(static_cast<Block*>(nullptr), block);
383 :
384 E : InferCodeReferences(block, hp_block_metadata_arr[i].code_size);
385 :
386 E : if (hp_block_metadata_arr[i].code_size <
387 : hp_block_metadata_arr[i].block_size) {
388 E : InferJumpTableReferences(block, hp_block_metadata_arr[i].code_size);
389 : }
390 E : }
391 :
392 E : return true;
393 E : }
394 :
395 E : bool HotPatchingDecomposer::LoadSectionInformation() {
396 : // Create sections in the image layout.
397 E : CopySectionHeadersToImageLayout(
398 : pe_image_->GetNTHeaders()->FileHeader.NumberOfSections,
399 : pe_image_->GetSectionHeader(0),
400 : &(image_layout_->sections));
401 :
402 : // Create the sections in the underlying block-graph.
403 E : if (!CopySectionInfoToBlockGraph(*pe_image_,
404 : image_->graph(),
405 : §ion_index_)) {
406 i : return false;
407 : }
408 :
409 E : return true;
410 E : }
411 :
412 : bool HotPatchingDecomposer::ParseCaseTableRead(BlockGraph::Block* block,
413 : BlockGraph::Offset offset,
414 : const _DInst &inst,
415 : size_t code_size,
416 E : bool* parsed) {
417 E : DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), block);
418 E : DCHECK_NE(static_cast<bool*>(nullptr), parsed);
419 :
420 : // Check if the instruction is a case table read.
421 E : *parsed = inst.opcode == I_MOVZX &&
422 : inst.ops[0].type == O_REG &&
423 : inst.ops[1].type == O_SMEM &&
424 : inst.dispSize == 32U &&
425 : inst.ops[2].type == O_NONE &&
426 : DisplacementPointsIntoBlockAfterOffset(inst.disp, block, code_size);
427 :
428 : // Return early if not.
429 E : if (!*parsed)
430 E : return true;
431 :
432 E : int reference_size = inst.dispSize / 8;
433 :
434 : BlockGraph::Offset ref_source_offset =
435 E : offset + inst.size - reference_size;
436 : BlockGraph::Offset ref_target_offset =
437 E : reinterpret_cast<uint8_t*>(inst.disp) - block->data();
438 :
439 : // The displacement is at the end of this instruction.
440 E : if (!block->SetReference(ref_source_offset,
441 : BlockGraph::Reference(
442 : BlockGraph::ABSOLUTE_REF,
443 : reference_size,
444 : block,
445 : ref_target_offset,
446 : ref_target_offset))) {
447 i : LOG(ERROR) << "Failed to create self reference in block "
448 : << BlockInfo(block) << " from offset "
449 : << ref_source_offset << " to offset " << ref_target_offset;
450 i : return false;
451 : }
452 :
453 : // Insert a case table label.
454 E : AddDataLabel(block,
455 : ref_target_offset,
456 : "case-table",
457 : BlockGraph::CASE_TABLE_LABEL);
458 :
459 E : return true;
460 E : }
461 :
462 : bool HotPatchingDecomposer::ParseJumpTableCall(BlockGraph::Block* block,
463 : BlockGraph::Offset offset,
464 : const _DInst &inst,
465 : size_t code_size,
466 E : bool* parsed) {
467 E : DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), block);
468 E : DCHECK_NE(static_cast<bool*>(nullptr), parsed);
469 :
470 : // Check if the instruction is a jump using a jump table.
471 E : *parsed = inst.opcode == I_JMP &&
472 : inst.ops[0].type == O_MEM &&
473 : inst.ops[1].type == O_NONE &&
474 : inst.scale == 4U &&
475 : inst.dispSize == 32U &&
476 : DisplacementPointsIntoBlockAfterOffset(inst.disp, block,
477 : code_size);
478 :
479 : // Return early if not.
480 E : if (!*parsed)
481 E : return true;
482 :
483 E : int reference_size = inst.dispSize / 8;
484 :
485 : BlockGraph::Offset ref_source_offset =
486 E : offset + inst.size - reference_size;
487 : BlockGraph::Offset ref_target_offset =
488 E : reinterpret_cast<uint8_t*>(inst.disp) - block->data();
489 :
490 : // The displacement is always at the end of a one-operand instruction.
491 E : if (!block->SetReference(ref_source_offset,
492 : BlockGraph::Reference(
493 : BlockGraph::ABSOLUTE_REF,
494 : reference_size,
495 : block,
496 : ref_target_offset,
497 : ref_target_offset))) {
498 i : LOG(ERROR) << "Failed to create self reference in block "
499 : << BlockInfo(block) << " from offset "
500 : << ref_source_offset << " to offset " << ref_target_offset;
501 i : return false;
502 : }
503 :
504 : // Insert a jump table label.
505 E : AddDataLabel(block,
506 : ref_target_offset,
507 : "jump-table",
508 : BlockGraph::JUMP_TABLE_LABEL);
509 :
510 E : return true;
511 E : }
512 :
513 : bool HotPatchingDecomposer::ParsePCRelativeBranchAndCallInstuction(
514 : BlockGraph::Block* block,
515 : BlockGraph::Offset offset,
516 : const _DInst &inst,
517 E : bool* parsed) {
518 E : DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), block);
519 E : DCHECK_NE(static_cast<bool*>(nullptr), parsed);
520 :
521 E : *parsed = (core::IsBranch(inst) || core::IsCall(inst)) &&
522 : inst.ops[0].type == O_PC;
523 E : if (!*parsed)
524 E : return true;
525 :
526 E : CHECK(inst.ops[1].type == O_NONE);
527 :
528 E : int reference_size = inst.ops[0].size / 8;
529 :
530 E : if (reference_size == 4) {
531 : // Insert a reference for 32-bit PC-relative jump and call instructions.
532 :
533 : // Create the reference.
534 E : BlockGraph::Offset pc_relative_address = inst.imm.addr;
535 E : RelativeAddress target_relative_address = RelativeAddress(
536 : block->addr().value() + offset + pc_relative_address + inst.size);
537 E : Block* referenced_block = image_layout_->blocks.GetBlockByAddress(
538 : target_relative_address);
539 :
540 E : BlockGraph::Offset ref_target_offset = 0;
541 :
542 E : if (referenced_block != nullptr) {
543 E : ref_target_offset =
544 : target_relative_address - referenced_block->addr();
545 :
546 E : if (referenced_block != block) {
547 : // If the following check fails that means that we have an
548 : // inter-block reference pointing inside a hot patchable block.
549 E : CHECK_EQ(target_relative_address, referenced_block->addr());
550 : }
551 E : } else {
552 : // There is no block at the referred location. This means that the
553 : // referred block is not hot patchable. Create a dummy code block that
554 : // can be referenced.
555 E : referenced_block = CreateBlock(BlockGraph::CODE_BLOCK,
556 : target_relative_address,
557 : 1,
558 : "TargetBlock");
559 E : DCHECK_NE(static_cast<Block*>(nullptr), referenced_block);
560 : // We set the BUILT_BY_UNSUPPORTED_COMPILER attribute on dummy blocks.
561 : // This attribute expresses that the block can't be moved and the data
562 : // of the block should not be interpreted.
563 E : referenced_block->set_attribute(
564 : BlockGraph::BUILT_BY_UNSUPPORTED_COMPILER);
565 :
566 E : ref_target_offset = 0;
567 : }
568 :
569 E : DCHECK_GE(inst.size, 1 + reference_size);
570 E : DCHECK_GE(2 + reference_size, inst.size);
571 :
572 : // The reference is always at the end of the instruction.
573 E : if (!block->SetReference(offset + inst.size - reference_size,
574 : BlockGraph::Reference(
575 : BlockGraph::PC_RELATIVE_REF,
576 : reference_size,
577 : referenced_block,
578 : ref_target_offset,
579 : ref_target_offset))) {
580 i : return false;
581 : }
582 E : ++parsed;
583 : } else {
584 : // We don't deal with smaller references. These are in-block references
585 : // that are resolved by the basic block decomposer.
586 : }
587 :
588 E : return true;
589 E : }
590 :
591 : Block *HotPatchingDecomposer::ProcessHotPatchableCodeBlock(
592 E : const block_graph::HotPatchingBlockMetadata& block_metadata) {
593 :
594 : // The relative address will point to the correct field as it should be
595 : // relocated.
596 E : RelativeAddress data_address(block_metadata.relative_address);
597 E : size_t block_size = block_metadata.block_size;
598 :
599 : // Generate a unique name for the block.
600 E : ++last_code_block_id_;
601 E : std::string block_name = "CodeBlock" + std::to_string(last_code_block_id_);
602 :
603 : // Add the block to the block graph.
604 E : Block* block = CreateBlock(BlockGraph::CODE_BLOCK,
605 : data_address,
606 : block_size,
607 : block_name);
608 E : if (block == nullptr) {
609 i : LOG(ERROR) << "Unable to add code block at "
610 : << data_address << " with size " << block_size << ".";
611 i : return nullptr;
612 : }
613 :
614 : // Add a code label to the beginning of the block.
615 E : block->SetLabel(0, "CODE", BlockGraph::CODE_LABEL);
616 :
617 : // If the code does not fill the whole data, put a data label at the end of
618 : // the code.
619 E : if (block_metadata.code_size != block_metadata.block_size) {
620 E : block->SetLabel(static_cast<int>(block_metadata.code_size),
621 : "DATA", BlockGraph::DATA_LABEL);
622 : }
623 :
624 E : return block;
625 E : }
626 :
627 : } // namespace pe
|