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 : size_t copy_size = 0;
63 E : if (symbol_name.size() <= sizeof(symbol->N.ShortName)) {
64 E : symbol_name_dst = reinterpret_cast<char*>(symbol->N.ShortName);
65 E : } else {
66 E : size_t string_offset = strings_block->size();
67 E : strings_block->set_size(strings_block->size() + symbol_name.size() + 1);
68 E : strings_block->ResizeData(strings_block->size());
69 : symbol_name_dst = reinterpret_cast<char*>(
70 E : strings_block->GetMutableData()) + string_offset;
71 E : symbol->N.Name.Long = string_offset;
72 : }
73 :
74 : // Copy the symbol name. We don't explicitly copy the terminating NULL, as
75 : // the data structure was initialized with zeros and we don't always need one
76 : // (the case of an 8-byte name, which is stored directly in the symbol).
77 E : ::memcpy(symbol_name_dst, symbol_name.data(), symbol_name.size());
78 :
79 : return;
80 E : }
81 :
82 : void TransferReferrers(BlockGraph::Offset src_offset,
83 : BlockGraph::Offset dst_offset,
84 E : BlockGraph::Block* block) {
85 E : DCHECK_NE(reinterpret_cast<BlockGraph::Block*>(NULL), block);
86 :
87 : // Make a copy of the referrers set because we'll be modifying the original
88 : // as we traverse.
89 E : BlockGraph::Block::ReferrerSet referrers = block->referrers();
90 E : BlockGraph::Block::ReferrerSet::const_iterator ref_it = referrers.begin();
91 E : for (; ref_it != referrers.end(); ++ref_it) {
92 E : BlockGraph::Reference ref;
93 E : CHECK(ref_it->first->GetReference(ref_it->second, &ref));
94 E : DCHECK_EQ(block, ref.referenced());
95 E : if (ref.offset() != src_offset)
96 E : continue;
97 :
98 E : BlockGraph::Offset delta = ref.base() - ref.offset();
99 : ref = BlockGraph::Reference(ref.type(), ref.size(), ref.referenced(),
100 E : dst_offset, dst_offset + delta);
101 E : CHECK(!ref_it->first->SetReference(ref_it->second, ref));
102 E : }
103 E : }
104 :
105 : } // namespace
106 :
107 : const char CoffRenameSymbolsTransform::kTransformName[] =
108 : "CoffRenameSymbolsTransform";
109 :
110 : void CoffRenameSymbolsTransform::AddSymbolMapping(const base::StringPiece& from,
111 E : const base::StringPiece& to) {
112 E : mappings_.push_back(std::make_pair(from.as_string(), to.as_string()));
113 E : }
114 :
115 : bool CoffRenameSymbolsTransform::TransformBlockGraph(
116 : const TransformPolicyInterface* policy,
117 : BlockGraph* block_graph,
118 E : BlockGraph::Block* /* headers_block */) {
119 E : DCHECK_NE(reinterpret_cast<TransformPolicyInterface*>(NULL), policy);
120 E : DCHECK_NE(reinterpret_cast<BlockGraph*>(NULL), block_graph);
121 E : DCHECK_EQ(BlockGraph::COFF_IMAGE, block_graph->image_format());
122 :
123 : BlockGraph::Block* symbols_block;
124 : BlockGraph::Block* strings_block;
125 : if (!FindCoffSpecialBlocks(block_graph,
126 E : NULL, &symbols_block, &strings_block)) {
127 i : LOG(ERROR) << "Block graph is missing some COFF special blocks. "
128 : << "Not a COFF block graph?";
129 i : return false;
130 : }
131 :
132 E : CoffSymbolNameOffsetMap symbol_offset_map;
133 : if (!BuildCoffSymbolNameOffsetMap(symbols_block, strings_block,
134 E : &symbol_offset_map)) {
135 i : return false;
136 : }
137 :
138 E : for (size_t i = 0; i < mappings_.size(); ++i) {
139 E : const std::string& src = mappings_[i].first;
140 E : const std::string& dst = mappings_[i].second;
141 : CoffSymbolNameOffsetMap::const_iterator src_it =
142 E : symbol_offset_map.find(src);
143 E : if (src_it == symbol_offset_map.end()) {
144 E : if (symbols_must_exist_) {
145 E : LOG(ERROR) << "Unable to find source symbol \"" << src << "\".";
146 E : return false;
147 : }
148 :
149 : // Input symbols aren't forced to exist, so continue on to the next one.
150 E : continue;
151 : }
152 E : DCHECK(!src_it->second.empty());
153 :
154 : // Find the destination offset.
155 : CoffSymbolNameOffsetMap::const_iterator dst_it =
156 E : symbol_offset_map.find(dst);
157 E : BlockGraph::Offset dst_offset = 0;
158 E : if (dst_it != symbol_offset_map.end()) {
159 : // If the destination is multiply defined we simply take the first one.
160 E : DCHECK(!dst_it->second.empty());
161 E : dst_offset = *dst_it->second.begin();
162 E : } else {
163 : // If the symbol does not exist, then append it to the strings block.
164 : // Use the first symbol as canonical for the purpose of symbol metadata.
165 E : BlockGraph::Offset src_offset = *src_it->second.begin();
166 : AddSymbol(dst, src_offset, symbols_block, strings_block,
167 E : &dst_offset);
168 : }
169 :
170 : // Iterate over all source symbols with this name and transfer references
171 : // from them to the destination symbol.
172 E : const CoffSymbolOffsets& src_offsets = src_it->second;
173 E : CoffSymbolOffsets::const_iterator src_offset_it = src_offsets.begin();
174 E : for (; src_offset_it != src_offsets.end(); ++src_offset_it) {
175 E : BlockGraph::Offset src_offset = *src_offset_it;
176 E : TransferReferrers(src_offset, dst_offset, symbols_block);
177 E : }
178 E : }
179 :
180 E : return true;
181 E : }
182 :
183 : } // namespace transforms
184 : } // namespace pe
|