1 : // Copyright 2013 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/coff_rename_symbols_transform.h"
16 :
17 : #include <string>
18 : #include <vector>
19 :
20 : #include "base/bind.h"
21 : #include "syzygy/block_graph/typed_block.h"
22 : #include "syzygy/pe/coff_utils.h"
23 :
24 : namespace pe {
25 : namespace transforms {
26 :
27 : namespace {
28 :
29 : using block_graph::BlockGraph;
30 : using block_graph::TypedBlock;
31 :
32 : void AddSymbol(const base::StringPiece& symbol_name,
33 : BlockGraph::Offset template_offset,
34 : BlockGraph::Block* symbols_block,
35 : BlockGraph::Block* strings_block,
36 E : BlockGraph::Offset* symbol_offset) {
37 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), symbols_block);
38 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), strings_block);
39 E : DCHECK_NE(reinterpret_cast<BlockGraph::Offset*>(NULL), symbol_offset);
40 :
41 E : TypedBlock<IMAGE_SYMBOL> symbols;
42 E : CHECK(symbols.Init(0, symbols_block));
43 E : size_t symbol_count = symbols.ElementCount();
44 E : *symbol_offset = sizeof(IMAGE_SYMBOL) * symbol_count;
45 E : symbols_block->InsertData(*symbol_offset, sizeof(IMAGE_SYMBOL), true);
46 E : size_t template_index = template_offset / sizeof(IMAGE_SYMBOL);
47 E : IMAGE_SYMBOL* orig = &symbols[template_index];
48 E : IMAGE_SYMBOL* symbol = &symbols[symbol_count];
49 :
50 : // Copy the metadata from the template symbol. We set the section number to
51 : // zero to indicate that this is an external symbol that has no definition in
52 : // this COFF file. It will be satisfied at link time.
53 E : symbol->Value = orig->Value;
54 E : symbol->SectionNumber = 0;
55 E : symbol->Type = orig->Type;
56 E : symbol->StorageClass = orig->StorageClass;
57 E : symbol->NumberOfAuxSymbols = 0;
58 :
59 : // Determine whether the name goes in the string table or is embedded in the
60 : // symbol record itself.
61 E : char* symbol_name_dst = NULL;
62 E : if (symbol_name.size() <= sizeof(symbol->N.ShortName)) {
63 E : symbol_name_dst = reinterpret_cast<char*>(symbol->N.ShortName);
64 E : } else {
65 E : size_t string_offset = strings_block->size();
66 E : strings_block->set_size(strings_block->size() + symbol_name.size() + 1);
67 E : strings_block->ResizeData(strings_block->size());
68 : symbol_name_dst = reinterpret_cast<char*>(
69 E : strings_block->GetMutableData()) + string_offset;
70 E : symbol->N.Name.Long = string_offset;
71 : }
72 :
73 : // Copy the symbol name. We don't explicitly copy the terminating NULL, as
74 : // the data structure was initialized with zeros and we don't always need one
75 : // (the case of an 8-byte name, which is stored directly in the symbol).
76 E : ::memcpy(symbol_name_dst, symbol_name.data(), symbol_name.size());
77 :
78 : return;
79 E : }
80 :
81 : void TransferReferrers(BlockGraph::Offset src_offset,
82 : BlockGraph::Offset dst_offset,
83 E : BlockGraph::Block* block) {
84 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), block);
85 :
86 : // Make a copy of the referrers set because we'll be modifying the original
87 : // as we traverse.
88 E : BlockGraph::Block::ReferrerSet referrers = block->referrers();
89 E : BlockGraph::Block::ReferrerSet::const_iterator ref_it = referrers.begin();
90 E : for (; ref_it != referrers.end(); ++ref_it) {
91 E : BlockGraph::Reference ref;
92 E : CHECK(ref_it->first->GetReference(ref_it->second, &ref));
93 E : DCHECK_EQ(block, ref.referenced());
94 E : if (ref.offset() != src_offset)
95 E : continue;
96 :
97 E : BlockGraph::Offset delta = ref.base() - ref.offset();
98 : ref = BlockGraph::Reference(ref.type(), ref.size(), ref.referenced(),
99 E : dst_offset, dst_offset + delta);
100 E : CHECK(!ref_it->first->SetReference(ref_it->second, ref));
101 E : }
102 E : }
103 :
104 : } // namespace
105 :
106 : const char CoffRenameSymbolsTransform::kTransformName[] =
107 : "CoffRenameSymbolsTransform";
108 :
109 : void CoffRenameSymbolsTransform::AddSymbolMapping(const base::StringPiece& from,
110 E : const base::StringPiece& to) {
111 E : mappings_.push_back(std::make_pair(from.as_string(), to.as_string()));
112 E : }
113 :
114 : bool CoffRenameSymbolsTransform::TransformBlockGraph(
115 : const TransformPolicyInterface* policy,
116 : BlockGraph* block_graph,
117 E : BlockGraph::Block* /* headers_block */) {
118 E : DCHECK_NE(reinterpret_cast<TransformPolicyInterface*>(NULL), policy);
119 E : DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
120 E : DCHECK_EQ(BlockGraph::COFF_IMAGE, block_graph->image_format());
121 :
122 : BlockGraph::Block* symbols_block;
123 : BlockGraph::Block* strings_block;
124 : if (!FindCoffSpecialBlocks(block_graph,
125 E : NULL, &symbols_block, &strings_block)) {
126 i : LOG(ERROR) << "Block graph is missing some COFF special blocks. "
127 : << "Not a COFF block graph?";
128 i : return false;
129 : }
130 :
131 E : CoffSymbolNameOffsetMap symbol_offset_map;
132 : if (!BuildCoffSymbolNameOffsetMap(symbols_block, strings_block,
133 E : &symbol_offset_map)) {
134 i : return false;
135 : }
136 :
137 E : for (size_t i = 0; i < mappings_.size(); ++i) {
138 E : const std::string& src = mappings_[i].first;
139 E : const std::string& dst = mappings_[i].second;
140 : CoffSymbolNameOffsetMap::const_iterator src_it =
141 E : symbol_offset_map.find(src);
142 E : if (src_it == symbol_offset_map.end()) {
143 E : if (symbols_must_exist_) {
144 E : LOG(ERROR) << "Unable to find source symbol \"" << src << "\".";
145 E : return false;
146 : }
147 :
148 : // Input symbols aren't forced to exist, so continue on to the next one.
149 E : continue;
150 : }
151 E : DCHECK(!src_it->second.empty());
152 :
153 : // Find the destination offset.
154 : CoffSymbolNameOffsetMap::const_iterator dst_it =
155 E : symbol_offset_map.find(dst);
156 E : BlockGraph::Offset dst_offset = 0;
157 E : if (dst_it != symbol_offset_map.end()) {
158 : // If the destination is multiply defined we simply take the first one.
159 E : DCHECK(!dst_it->second.empty());
160 E : dst_offset = *dst_it->second.begin();
161 E : } else {
162 : // If the symbol does not exist, then append it to the strings block.
163 : // Use the first symbol as canonical for the purpose of symbol metadata.
164 E : BlockGraph::Offset src_offset = *src_it->second.begin();
165 : AddSymbol(dst, src_offset, symbols_block, strings_block,
166 E : &dst_offset);
167 : }
168 :
169 : // Iterate over all source symbols with this name and transfer references
170 : // from them to the destination symbol.
171 E : const CoffSymbolOffsets& src_offsets = src_it->second;
172 E : CoffSymbolOffsets::const_iterator src_offset_it = src_offsets.begin();
173 E : for (; src_offset_it != src_offsets.end(); ++src_offset_it) {
174 E : BlockGraph::Offset src_offset = *src_offset_it;
175 E : TransferReferrers(src_offset, dst_offset, symbols_block);
176 E : }
177 E : }
178 :
179 E : return true;
180 E : }
181 :
182 : } // namespace transforms
183 : } // namespace pe
|