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 E : BlockGraph::Size hp_metadata_size = sizeof(HotPatchingMetadataHeader) +
56 : sizeof(HotPatchingBlockMetadata) * blocks_prepared_->size();
57 E : BlockGraph::Block* hp_metadata_block = block_graph->AddBlock(
58 : BlockGraph::DATA_BLOCK,
59 : hp_metadata_size,
60 : 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 E : hp_block_metadata.Init(sizeof(HotPatchingMetadataHeader) +
76 : sizeof(HotPatchingBlockMetadata) * index, hp_metadata_block);
77 E : hp_block_metadata.SetReference(BlockGraph::RELATIVE_REF,
78 : hp_block_metadata->relative_address,
79 : block,
80 : 0,
81 : 0);
82 E : hp_block_metadata->code_size =
83 : static_cast<uint16_t>(CalculateCodeSize(block));
84 E : hp_block_metadata->block_size = static_cast<uint16_t>(block->data_size());
85 :
86 E : ++index;
87 E : }
88 E : DCHECK_EQ(index, blocks_prepared_->size());
89 :
90 : // Create a section for hot patching metadata and put the block inside.
91 : BlockGraph::Section* hp_section =
92 E : block_graph->AddSection(common::kHotPatchingMetadataSectionName,
93 : kReadOnlyDataCharacteristics);
94 E : DCHECK_NE(static_cast<BlockGraph::Section*>(nullptr), hp_section);
95 E : hp_metadata_block->set_section(hp_section->id());
96 E : }
97 :
98 : size_t AddHotPatchingMetadataTransform::CalculateCodeSize(
99 E : const BlockGraph::Block* block) {
100 : // If we will not encounter a data label, we assume that the whole block
101 : // contains code.
102 E : size_t code_size = block->data_size();
103 :
104 : // Iterate over labels to find a data label. We iterate backwards as data
105 : // labels are at the end and there are far less data labels than code labels.
106 E : for (auto it = block->labels().rbegin(); it != block->labels().rend(); ++it) {
107 E : const BlockGraph::Label& label = it->second;
108 :
109 : // We ignore the debug-end label, as it can come after block data.
110 E : if (label.has_attributes(BlockGraph::DEBUG_END_LABEL))
111 E : continue;
112 :
113 : // Anything that is not a data label means that there are no more data
114 : // labels.
115 E : if (!label.has_attributes(BlockGraph::DATA_LABEL))
116 E : break;
117 :
118 : // Update the code size with the information from the current data label.
119 : // Offsets are represented by signed integers, so we need a conversion.
120 E : DCHECK_GE(it->first, 0);
121 E : code_size = static_cast<size_t>(it->first);
122 :
123 : // Check if the label really points inside the block.
124 E : DCHECK_LE(code_size, block->data_size());
125 E : }
126 :
127 E : return code_size;
128 E : }
129 :
130 : } // namespace transforms
131 : } // namespace pe
|