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/transforms/add_hot_patching_metadata_transform.h"
16 :
17 : #include "syzygy/block_graph/hot_patching_metadata.h"
18 : #include "syzygy/block_graph/typed_block.h"
19 : #include "syzygy/common/defs.h"
20 : #include "syzygy/pe/pe_utils.h"
21 :
22 : namespace pe {
23 : namespace transforms {
24 :
25 : const char AddHotPatchingMetadataTransform::kTransformName[] =
26 : "AddHotPatchingMetadataTransform";
27 :
28 : AddHotPatchingMetadataTransform::AddHotPatchingMetadataTransform()
29 E : : blocks_prepared_(nullptr) {
30 E : }
31 :
32 : bool AddHotPatchingMetadataTransform::TransformBlockGraph(
33 : const TransformPolicyInterface* policy,
34 : BlockGraph* block_graph,
35 E : BlockGraph::Block* header_block) {
36 E : DCHECK_NE(static_cast<BlockVector*>(nullptr), blocks_prepared_);
37 :
38 : // Add the section that contains the hot patching metadata.
39 E : if (!blocks_prepared_->empty())
40 E : AddHotPatchingSection(block_graph);
41 :
42 E : return true;
43 E : }
44 :
45 : void AddHotPatchingMetadataTransform::AddHotPatchingSection(
46 E : BlockGraph* block_graph) {
47 E : DCHECK_NE(static_cast<BlockGraph*>(nullptr), block_graph);
48 E : DCHECK_NE(static_cast<BlockVector*>(nullptr), blocks_prepared_);
49 :
50 : using block_graph::TypedBlock;
51 : using block_graph::HotPatchingBlockMetadata;
52 : using block_graph::HotPatchingMetadataHeader;
53 :
54 : // Create a block for hot patching metadata.
55 : BlockGraph::Size hp_metadata_size = sizeof(HotPatchingMetadataHeader) +
56 E : sizeof(HotPatchingBlockMetadata) * blocks_prepared_->size();
57 : BlockGraph::Block* hp_metadata_block = block_graph->AddBlock(
58 : BlockGraph::DATA_BLOCK,
59 : hp_metadata_size,
60 E : common::kHotPatchingMetadataSectionName);
61 E : DCHECK_NE(static_cast<BlockGraph::Block*>(nullptr), hp_metadata_block);
62 E : hp_metadata_block->AllocateData(hp_metadata_size);
63 E : DCHECK(hp_metadata_block->owns_data());
64 :
65 : // Create hot patching metadata header.
66 E : TypedBlock<HotPatchingMetadataHeader> hp_header;
67 E : hp_header.Init(0, hp_metadata_block);
68 E : hp_header->version = block_graph::kHotPatchingMetadataVersion;
69 E : hp_header->number_of_blocks = blocks_prepared_->size();
70 :
71 : // Create hot patching block metadata.
72 E : size_t index = 0;
73 E : for (BlockGraph::Block* block : *blocks_prepared_) {
74 E : TypedBlock<HotPatchingBlockMetadata> hp_block_metadata;
75 : hp_block_metadata.Init(sizeof(HotPatchingMetadataHeader) +
76 E : sizeof(HotPatchingBlockMetadata) * index, hp_metadata_block);
77 : hp_block_metadata.SetReference(BlockGraph::RELATIVE_REF,
78 : hp_block_metadata->relative_address,
79 : block,
80 : 0,
81 E : 0);
82 E : hp_block_metadata->code_size = CalculateCodeSize(block);
83 E : hp_block_metadata->block_size = block->data_size();
84 :
85 E : ++index;
86 E : }
87 E : DCHECK_EQ(index, blocks_prepared_->size());
88 :
89 : // Create a section for hot patching metadata and put the block inside.
90 : BlockGraph::Section* hp_section =
91 : block_graph->AddSection(common::kHotPatchingMetadataSectionName,
92 E : kReadOnlyDataCharacteristics);
93 E : DCHECK_NE(static_cast<BlockGraph::Section*>(nullptr), hp_section);
94 E : hp_metadata_block->set_section(hp_section->id());
95 E : }
96 :
97 : size_t AddHotPatchingMetadataTransform::CalculateCodeSize(
98 E : const BlockGraph::Block* block) {
99 : // If we will not encounter a data label, we assume that the whole block
100 : // contains code.
101 E : size_t code_size = block->data_size();
102 :
103 : // Iterate over labels to find a data label. We iterate backwards as data
104 : // labels are at the end and there are far less data labels than code labels.
105 E : for (auto it = block->labels().rbegin(); it != block->labels().rend(); ++it) {
106 E : const BlockGraph::Label& label = it->second;
107 :
108 : // We ignore the debug-end label, as it can come after block data.
109 E : if (label.has_attributes(BlockGraph::DEBUG_END_LABEL))
110 E : continue;
111 :
112 : // Anything that is not a data label means that there are no more data
113 : // labels.
114 E : if (!label.has_attributes(BlockGraph::DATA_LABEL))
115 E : break;
116 :
117 : // Update the code size with the information from the current data label.
118 : // Offsets are represented by signed integers, so we need a conversion.
119 E : DCHECK_GE(it->first, 0);
120 E : code_size = static_cast<size_t>(it->first);
121 :
122 : // Check if the label really points inside the block.
123 E : DCHECK_LE(code_size, block->data_size());
124 E : }
125 :
126 E : return code_size;
127 E : }
128 :
129 : } // namespace transforms
130 : } // namespace pe
|