1 : // Copyright 2012 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/instrument/transforms/thunk_import_references_transform.h"
16 :
17 : // The Win8 SDK defines this in winerror.h, and it is subsequently redefined by
18 : // delayimp.h
19 : #undef FACILITY_VISUALCPP
20 : #include <delayimp.h>
21 : #include <limits>
22 :
23 : #include "base/logging.h"
24 : #include "base/string_util.h"
25 : #include "base/stringprintf.h"
26 : #include "syzygy/block_graph/basic_block_assembler.h"
27 : #include "syzygy/block_graph/block_builder.h"
28 : #include "syzygy/block_graph/typed_block.h"
29 : #include "syzygy/common/defs.h"
30 : #include "syzygy/pe/pe_utils.h"
31 :
32 : namespace instrument {
33 : namespace transforms {
34 :
35 : namespace {
36 :
37 : using block_graph::BlockGraph;
38 : using block_graph::TypedBlock;
39 : using block_graph::ConstTypedBlock;
40 :
41 : // A simple struct that can be used to let us access strings using TypedBlock.
42 : struct StringStruct {
43 : const char string[1];
44 : };
45 :
46 : typedef BlockGraph::Offset Offset;
47 : typedef TypedBlock<IMAGE_DOS_HEADER> DosHeader;
48 : typedef TypedBlock<IMAGE_IMPORT_BY_NAME> ImageImportByName;
49 : typedef TypedBlock<IMAGE_IMPORT_DESCRIPTOR> ImageImportDescriptor;
50 : typedef TypedBlock<IMAGE_NT_HEADERS> NtHeaders;
51 : typedef TypedBlock<StringStruct> StringBlock;
52 : typedef TypedBlock<ImgDelayDescr> ImageDelayImportDescriptor;
53 :
54 : // We add this suffix to the destination
55 : const char kThunkSuffix[] = "_ImportThunk";
56 : const char kDelayThunkSuffix[] = "_DelayImportThunk";
57 :
58 : } // namespace
59 :
60 : using pe::transforms::PEAddImportsTransform;
61 : using pe::transforms::ImportedModule;
62 :
63 : const char ThunkImportReferencesTransform::kTransformName[] =
64 : "ThunkImportReferencesTransform";
65 :
66 : const char ThunkImportReferencesTransform::kEntryHookName[] =
67 : "_indirect_penter";
68 : const char ThunkImportReferencesTransform::kDefaultInstrumentDll[] =
69 : "call_trace.dll";
70 :
71 : ThunkImportReferencesTransform::ThunkImportReferencesTransform()
72 : : thunk_section_(NULL),
73 E : instrument_dll_name_(kDefaultInstrumentDll) {
74 E : }
75 :
76 : bool ThunkImportReferencesTransform::TransformBlockGraph(
77 : const TransformPolicyInterface* policy,
78 : BlockGraph* block_graph,
79 E : BlockGraph::Block* header_block) {
80 E : DCHECK(policy != NULL);
81 E : DCHECK(block_graph != NULL);
82 E : DCHECK(header_block != NULL);
83 E : DCHECK(thunk_section_ == NULL);
84 :
85 : // We always exclude our own agent DLL from instrumentation.
86 E : modules_to_exclude_.insert(instrument_dll_name_);
87 :
88 : // Start by finding or adding import entries for our instrumentation hook.
89 E : ImportedModule import_module(instrument_dll_name_);
90 : size_t hook_index = import_module.AddSymbol(
91 E : kEntryHookName, ImportedModule::kAlwaysImport);
92 :
93 E : add_imports_transform_.AddModule(&import_module);
94 :
95 : if (!add_imports_transform_.TransformBlockGraph(
96 E : policy, block_graph, header_block)) {
97 i : LOG(ERROR) << "Unable to add imports for instrumentation DLL.";
98 i : return false;
99 : }
100 :
101 E : if (!import_module.GetSymbolReference(hook_index, &hook_ref_)) {
102 i : LOG(ERROR) << "Unable to get import reference for hook.";
103 i : return false;
104 : }
105 :
106 E : ImportAddressLocationNameMap import_locations;
107 : if (!LookupImportLocations(modules_to_exclude_,
108 : header_block,
109 E : &import_locations)) {
110 i : LOG(ERROR) << "Unable to resolve import names and locations.";
111 i : return false;
112 : }
113 : if (!LookupDelayImportLocations(modules_to_exclude_,
114 : header_block,
115 E : &import_locations)) {
116 i : LOG(ERROR) << "Unable to resolve delay import names and locations.";
117 i : return false;
118 : }
119 :
120 : // Now instrument all the import locations we located.
121 E : if (!InstrumentImportReferences(block_graph, import_locations)) {
122 i : LOG(ERROR) << "Unable to instrument import references.";
123 i : return false;
124 : }
125 :
126 E : return true;
127 E : }
128 :
129 : void ThunkImportReferencesTransform::ExcludeModule(
130 E : const base::StringPiece& module_name) {
131 E : modules_to_exclude_.insert(module_name.as_string());
132 E : }
133 :
134 : bool ThunkImportReferencesTransform::ModuleNameLess::operator()(
135 E : const std::string& lhs, const std::string& rhs) const {
136 E : size_t len = std::min(lhs.size(), rhs.size());
137 E : for (size_t i = 0; i < len; ++i) {
138 E : char lhc = base::ToLowerASCII(lhs[i]);
139 E : char rhc = base::ToLowerASCII(rhs[i]);
140 E : if (lhc < rhc)
141 E : return true;
142 E : else if (lhc > rhc)
143 E : return false;
144 E : }
145 :
146 : // The strings are equal the end of the shorter string,
147 : // if the lhs is shorter it's smaller.
148 E : return lhs.size() < rhs.size();
149 E : }
150 :
151 : // This method builds up a set of thunk blocks as well as a thunk table
152 : // containing pointers to these blocks. Existing import references are then
153 : // replaced by references to the thunk table. Since imports are invoked via
154 : // an indirect call or jump instruction, changing the address of the call
155 : // statement from an address into the IAT to an address into the thunk table
156 : // gets the thunk called properly.
157 : bool ThunkImportReferencesTransform::InstrumentImportReferences(
158 : BlockGraph* block_graph,
159 E : const ImportAddressLocationNameMap& import_locations) {
160 : // Find or create the section we put our thunks in.
161 : thunk_section_ = block_graph->FindOrAddSection(common::kThunkSectionName,
162 E : pe::kCodeCharacteristics);
163 E : if (thunk_section_ == NULL) {
164 i : LOG(ERROR) << "Unable to find or create .thunks section.";
165 i : return false;
166 : }
167 :
168 : // Find the set of blocks referred by import_locations.
169 E : BlockSet import_blocks;
170 E : if (!GetImportBlocks(import_locations, &import_blocks)) {
171 i : LOG(ERROR) << "Unable to get import blocks.";
172 i : return false;
173 : }
174 :
175 : // Typedef for the thunk block map. The key is the <iat block, offset> the
176 : // (since all callers can use the same thunk) and the value is the offset into
177 : // the thunk table that points to the thunk block for that IAT entry.
178 : typedef std::pair<const BlockGraph::Block*, BlockGraph::Offset>
179 : ThunkBlockKey;
180 : typedef std::map<ThunkBlockKey, BlockGraph::Offset> ThunkBlockMap;
181 E : ThunkBlockMap thunk_block_map;
182 :
183 : // Create the thunk table - we'll grow it as we go.
184 : BlockGraph::Block* thunk_table_block =
185 E : block_graph->AddBlock(BlockGraph::DATA_BLOCK, 0, "ImportsThunkTable");
186 E : thunk_table_block->set_section(thunk_section_->id());
187 E : BlockGraph::Offset thunk_table_offset = 0;
188 :
189 : // Now iterate through the import blocks and instrument the references.
190 E : BlockSet::const_iterator it = import_blocks.begin();
191 E : for (; it != import_blocks.end(); ++it) {
192 E : BlockGraph::Block* iat_block = *it;
193 :
194 : // Next, list all referrers to get all references into the IAT. For each
195 : // eligible reference, create a thunk (in its own block) and add a pointer
196 : // to it to the thunk table.
197 E : BlockGraph::Block::ReferrerSet iat_referrers(iat_block->referrers());
198 : BlockGraph::Block::ReferrerSet::const_iterator iat_referrer_iter(
199 E : iat_referrers.begin());
200 E : for (; iat_referrer_iter != iat_referrers.end(); ++iat_referrer_iter) {
201 E : BlockGraph::Block* referrer = iat_referrer_iter->first;
202 :
203 E : if (referrer == iat_block) {
204 i : LOG(WARNING) << "Unexpected self-reference in IAT.";
205 i : continue;
206 : }
207 :
208 E : if (referrer->type() != BlockGraph::CODE_BLOCK) {
209 : // We shouldn't see data referring to import table entries, outside
210 : // the PE structures.
211 E : DCHECK(referrer->attributes() & BlockGraph::PE_PARSED);
212 :
213 E : LOG(INFO) << "Skipping non-code block reference from block: '"
214 : << referrer->name() << "'";
215 E : continue;
216 : }
217 :
218 E : if (referrer->attributes() & BlockGraph::THUNK) {
219 E : LOG(INFO) << "Skipping thunk block reference from block: '"
220 : << referrer->name() << "'";
221 E : continue;
222 : }
223 :
224 : // Now that we know the referring block, we need to find out where in the
225 : // IAT it refers to.
226 E : BlockGraph::Reference ref;
227 E : if (!referrer->GetReference(iat_referrer_iter->second, &ref)) {
228 i : LOG(ERROR) << "Unable to get reference from referrer.";
229 i : return false;
230 : }
231 :
232 : // See whether this is an eligible import.
233 : ImportAddressLocationNameMap::const_iterator it(
234 : import_locations.find(
235 E : std::make_pair(ref.referenced(), ref.offset())));
236 E : if (it == import_locations.end()) {
237 : // It's not an eligible location, skip it.
238 E : continue;
239 : }
240 :
241 : // For now, let's not try and thunk thunks. This means that we can't
242 : // e.g. double-instrument, which is a potentially legitimate use case,
243 : // but it should only be supported if there's adequate testing for it.
244 E : if (referrer->section() == thunk_section_->id()) {
245 i : LOG(ERROR) << "Thunking a reference from the thunk section, "
246 : << "in block: '" << referrer->name() << "'";
247 i : return false;
248 : }
249 :
250 : // Look for the reference in the thunk block map, and only create a
251 : // new one if it does not already exist.
252 E : BlockGraph::Block* thunk_block = NULL;
253 E : BlockGraph::Offset new_ref_offset = 0;
254 :
255 E : ThunkBlockKey key(std::make_pair(iat_block, ref.offset()));
256 E : ThunkBlockMap::const_iterator thunk_it = thunk_block_map.find(key);
257 E : if (thunk_it == thunk_block_map.end()) {
258 : // Create the thunk block for this offset into the IAT.
259 E : thunk_block = CreateOneThunk(block_graph, ref, it->second);
260 E : if (thunk_block == NULL) {
261 i : LOG(DFATAL) << "Unable to create thunk block.";
262 i : return false;
263 : }
264 :
265 : // Now add a reference to the thunk in the thunk table.
266 : BlockGraph::Reference thunk_ref(BlockGraph::ABSOLUTE_REF,
267 : sizeof(core::AbsoluteAddress),
268 E : thunk_block, 0, 0);
269 : thunk_table_block->set_size(
270 E : thunk_table_offset + sizeof(core::AbsoluteAddress));
271 E : thunk_table_block->SetReference(thunk_table_offset, thunk_ref);
272 :
273 : // Remember this thunk in case we need to use it again.
274 E : thunk_block_map[key] = thunk_table_offset;
275 E : new_ref_offset = thunk_table_offset;
276 :
277 : // Move to the next empty entry in the thunk table.
278 E : thunk_table_offset += sizeof(core::AbsoluteAddress);
279 : DCHECK_EQ(static_cast<BlockGraph::Size>(thunk_table_offset),
280 E : thunk_table_block->size());
281 E : } else {
282 E : new_ref_offset = thunk_it->second;
283 : }
284 :
285 : // Update the referrer to point to the new location in the thunk table.
286 : BlockGraph::Reference new_ref(ref.type(),
287 : ref.size(),
288 : thunk_table_block,
289 : new_ref_offset,
290 E : 0);
291 E : referrer->SetReference(iat_referrer_iter->second, new_ref);
292 E : }
293 E : }
294 :
295 E : return true;
296 E : }
297 :
298 : BlockGraph::Block* ThunkImportReferencesTransform::CreateOneThunk(
299 : BlockGraph* block_graph,
300 : const BlockGraph::Reference& destination,
301 E : const base::StringPiece& name) {
302 : using block_graph::BasicBlockSubGraph;
303 : using block_graph::BasicBlockAssembler;
304 : using block_graph::BasicCodeBlock;
305 : using block_graph::BlockBuilder;
306 : using block_graph::Operand;
307 : using block_graph::Displacement;
308 :
309 : // Construct the name for the new thunk.
310 E : std::string thunk_name(name.as_string());
311 E : thunk_name.append(kThunkSuffix);
312 :
313 : // Set up a basic block subgraph containing a single block description, with
314 : // that block description containing a single empty basic block, and get an
315 : // assembler writing into that basic block.
316 E : BasicBlockSubGraph bbsg;
317 : BasicBlockSubGraph::BlockDescription* block_desc = bbsg.AddBlockDescription(
318 : thunk_name,
319 : NULL,
320 : BlockGraph::CODE_BLOCK,
321 : thunk_section_->id(),
322 : 1,
323 E : 0);
324 E : BasicCodeBlock* bb = bbsg.AddBasicCodeBlock(name);
325 E : block_desc->basic_block_order.push_back(bb);
326 E : BasicBlockAssembler assm(bb->instructions().begin(), &bb->instructions());
327 :
328 : // The thunk contains this.
329 : // push dword ptr [<import>]
330 : // jmp dword ptr [<entry_hook>]
331 : assm.push(
332 E : Operand(Displacement(destination.referenced(), destination.offset())));
333 E : assm.jmp(Operand(Displacement(hook_ref_.referenced(), hook_ref_.offset())));
334 :
335 : // Condense into a block.
336 E : BlockBuilder block_builder(block_graph);
337 E : if (!block_builder.Merge(&bbsg)) {
338 i : LOG(ERROR) << "Failed to build thunk block.";
339 i : return NULL;
340 : }
341 :
342 : // Exactly one new block should have been created.
343 E : DCHECK_EQ(1u, block_builder.new_blocks().size());
344 E : BlockGraph::Block* thunk = block_builder.new_blocks().front();
345 :
346 E : return thunk;
347 E : }
348 :
349 : bool ThunkImportReferencesTransform::GetImportBlocks(
350 : const ImportAddressLocationNameMap& import_locations,
351 E : BlockSet* import_blocks) {
352 E : DCHECK(import_blocks != NULL);
353 :
354 E : ImportAddressLocationNameMap::const_iterator it;
355 E : BlockGraph::Block* last_block = NULL;
356 E : while (true) {
357 : it = import_locations.upper_bound(
358 E : std::make_pair(last_block, std::numeric_limits<Offset>::max()));
359 :
360 E : if (it == import_locations.end())
361 E : break;
362 :
363 E : last_block = it->first.first;
364 E : import_blocks->insert(last_block);
365 E : }
366 :
367 E : return true;
368 E : }
369 :
370 : bool ThunkImportReferencesTransform::LookupImportLocations(
371 : const ModuleNameSet& exclusions,
372 : BlockGraph::Block* header_block,
373 E : ImportAddressLocationNameMap* import_locations) {
374 E : DCHECK(header_block != NULL);
375 E : DCHECK(import_locations != NULL);
376 :
377 : // Start by retrieving the NT headers.
378 E : DosHeader dos_header;
379 E : NtHeaders nt_headers;
380 : if (!dos_header.Init(0, header_block) ||
381 E : !dos_header.Dereference(dos_header->e_lfanew, &nt_headers)) {
382 i : LOG(ERROR) << "Unable to cast image headers.";
383 i : return false;
384 : }
385 :
386 : // Get to the import directory.
387 : const IMAGE_DATA_DIRECTORY* import_directory =
388 E : &nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
389 :
390 E : ImageImportDescriptor iida;
391 E : if (!nt_headers.Dereference(import_directory->VirtualAddress, &iida)) {
392 i : LOG(ERROR) << "Failed to dereference Image Import Descriptor Array.";
393 i : return false;
394 : }
395 :
396 : // The array is NULL terminated with a potentially incomplete descriptor so
397 : // we can't use ElementCount - 1.
398 : size_t descriptor_count =
399 : (common::AlignUp(iida.block()->size(), sizeof(IMAGE_IMPORT_DESCRIPTOR)) /
400 E : sizeof(IMAGE_IMPORT_DESCRIPTOR)) - 1;
401 :
402 E : for (size_t iida_index = 0; iida_index < descriptor_count; ++iida_index) {
403 E : StringBlock dll_name_block;
404 E : if (!iida.Dereference(iida[iida_index].Name, &dll_name_block)) {
405 i : LOG(ERROR) << "Unable to dereference DLL name.";
406 i : return false;
407 : }
408 :
409 E : size_t len = strnlen(dll_name_block->string, dll_name_block.ElementCount());
410 E : std::string dll_name(dll_name_block->string, dll_name_block->string + len);
411 :
412 : // Move to the next one if this is an excluded module.
413 E : if (exclusions.find(dll_name) != exclusions.end())
414 E : continue;
415 :
416 : // Walk the IAT and the INT(also know as hna) for this module concurrently
417 : // until we come to a zero terminator for one or the other and mark their
418 : // offsets and names in the location names map.
419 E : TypedBlock<IMAGE_IMPORT_BY_NAME*> hna, iat;
420 : if (!iida.Dereference(iida[iida_index].OriginalFirstThunk, &hna) ||
421 E : !iida.Dereference(iida[iida_index].FirstThunk, &iat)) {
422 i : LOG(ERROR) << "Unable to dereference OriginalFirstThunk/FirstThunk.";
423 i : return false;
424 : }
425 :
426 : // Loop through the imports, tag and bag them.
427 E : size_t i = 0;
428 E : for (; i < hna.ElementCount() && i < iat.ElementCount(); ++i) {
429 E : ConstTypedBlock<IMAGE_THUNK_DATA32> thunk;
430 E : if (!thunk.Init(hna.OffsetOf(hna[i]), hna.block())) {
431 i : LOG(ERROR) << "Unable to dereference IMAGE_THUNK_DATA32.";
432 i : return false;
433 : }
434 :
435 : // Construct the location for this entry.
436 : ImportAddressLocation key(
437 E : std::make_pair(iat.block(), iat.OffsetOf(iat[i])));
438 E : std::string import_name = dll_name;
439 :
440 : // Is this an ordinal import?
441 E : if (IMAGE_SNAP_BY_ORDINAL(thunk->u1.Ordinal)) {
442 : // Ordinal imports are named <dll>:#<ordinal>.
443 : base::StringAppendF(&import_name,
444 : ":#%d",
445 E : IMAGE_ORDINAL(thunk->u1.Ordinal));
446 E : } else if (!thunk.HasReference(thunk->u1.AddressOfData)) {
447 : // Have no reference? Then terminate the iteration.
448 : // We sanity check that the actual data is null.
449 E : DCHECK_EQ(0u, thunk->u1.AddressOfData);
450 E : break;
451 i : } else {
452 : // Otherwise this should point to an IMAGE_IMPORT_BY_NAME structure.
453 E : ImageImportByName iibn;
454 E : if (!hna.Dereference(hna[i], &iibn)) {
455 i : LOG(ERROR) << "Unable to dereference IMAGE_IMPORT_BY_NAME.";
456 i : return false;
457 : }
458 : size_t len =
459 : strnlen(iibn->Name,
460 E : iibn.block()->size() - iibn.OffsetOf(iibn->Name));
461 E : std::string function_name(iibn->Name, iibn->Name + len);
462 :
463 E : base::StringAppendF(&import_name, ":%s", function_name.c_str());
464 E : }
465 :
466 : // Tag and name it.
467 : bool inserted =
468 E : import_locations->insert(std::make_pair(key, import_name)).second;
469 :
470 E : DCHECK(inserted);
471 E : }
472 E : }
473 :
474 E : return true;
475 E : }
476 :
477 : bool ThunkImportReferencesTransform::LookupDelayImportLocations(
478 : const ModuleNameSet& exclusions,
479 : BlockGraph::Block* header_block,
480 E : ImportAddressLocationNameMap* import_locations) {
481 E : DCHECK(header_block != NULL);
482 E : DCHECK(import_locations != NULL);
483 :
484 : // Start by retrieving the NT headers.
485 E : DosHeader dos_header;
486 E : NtHeaders nt_headers;
487 : if (!dos_header.Init(0, header_block) ||
488 E : !dos_header.Dereference(dos_header->e_lfanew, &nt_headers)) {
489 i : LOG(ERROR) << "Unable to cast image headers.";
490 i : return false;
491 : }
492 :
493 : // Get to the delay import directory.
494 : const IMAGE_DATA_DIRECTORY* delay_import_directory =
495 : &nt_headers->OptionalHeader
496 E : .DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT];
497 :
498 E : ImageDelayImportDescriptor idida;
499 E : if (!nt_headers.Dereference(delay_import_directory->VirtualAddress, &idida)) {
500 : // Unable to dereference, this is only an error if there are delay imports.
501 E : if (!nt_headers.HasReference(delay_import_directory->VirtualAddress)) {
502 E : DCHECK_EQ(0U, delay_import_directory->VirtualAddress);
503 E : return true;
504 : }
505 :
506 i : LOG(ERROR) << "Failed to dereference delay Image Import Descriptor Array.";
507 i : return false;
508 : }
509 :
510 E : for (size_t idida_idx = 0; idida_idx < idida.ElementCount(); ++idida_idx) {
511 : // The last descriptor is a sentinel.
512 E : if (idida[idida_idx].grAttrs == 0)
513 E : break;
514 :
515 E : StringBlock dll_name_block;
516 E : if (!idida.Dereference(idida[idida_idx].rvaDLLName, &dll_name_block)) {
517 i : LOG(ERROR) << "Unable to dereference DLL name.";
518 i : return false;
519 : }
520 :
521 E : size_t len = strnlen(dll_name_block->string, dll_name_block.ElementCount());
522 E : std::string dll_name(dll_name_block->string, dll_name_block->string + len);
523 :
524 : // Move to the next one if this is an excluded module.
525 E : if (exclusions.find(dll_name) != exclusions.end())
526 i : continue;
527 :
528 : // Walk the IAT and the INT(also know as hna) for this module concurrently
529 : // until we come to a zero terminator for one or the other and mark their
530 : // offsets and names in the location names map.
531 E : TypedBlock<IMAGE_IMPORT_BY_NAME*> hna, iat;
532 : if (!idida.Dereference(idida[idida_idx].rvaINT, &hna) ||
533 E : !idida.Dereference(idida[idida_idx].rvaIAT, &iat)) {
534 i : LOG(ERROR) << "Unable to dereference OriginalFirstThunk/FirstThunk.";
535 i : return false;
536 : }
537 :
538 : // Loop through the imports, tag and bag them.
539 E : size_t i = 0;
540 E : for (; i < hna.ElementCount() && i < iat.ElementCount(); ++i) {
541 E : ConstTypedBlock<IMAGE_THUNK_DATA32> thunk;
542 E : if (!thunk.Init(hna.OffsetOf(hna[i]), hna.block())) {
543 i : LOG(ERROR) << "Unable to dereference IMAGE_THUNK_DATA32.";
544 i : return false;
545 : }
546 :
547 : // Construct the location for this entry.
548 : ImportAddressLocation key(
549 E : std::make_pair(iat.block(), iat.OffsetOf(iat[i])));
550 E : std::string import_name = dll_name;
551 :
552 : // Is this an ordinal import?
553 E : if (IMAGE_SNAP_BY_ORDINAL(thunk->u1.Ordinal)) {
554 : // Ordinal imports are named <dll>:#<ordinal>.
555 : base::StringAppendF(&import_name,
556 : ":#%d",
557 i : IMAGE_ORDINAL(thunk->u1.Ordinal));
558 E : } else if (!thunk.HasReference(thunk->u1.AddressOfData)) {
559 : // Have no reference? Then terminate the iteration.
560 : // We sanity check that the actual data is null.
561 E : DCHECK_EQ(0u, thunk->u1.AddressOfData);
562 E : break;
563 i : } else {
564 : // Otherwise this should point to an IMAGE_IMPORT_BY_NAME structure.
565 E : ImageImportByName iibn;
566 E : if (!hna.Dereference(hna[i], &iibn)) {
567 i : LOG(ERROR) << "Unable to dereference IMAGE_IMPORT_BY_NAME.";
568 i : return false;
569 : }
570 : size_t len =
571 : strnlen(iibn->Name,
572 E : iibn.block()->size() - iibn.OffsetOf(iibn->Name));
573 E : std::string function_name(iibn->Name, iibn->Name + len);
574 :
575 E : base::StringAppendF(&import_name, ":%s", function_name.c_str());
576 E : }
577 :
578 : // Tag and name it.
579 : bool inserted =
580 E : import_locations->insert(std::make_pair(key, import_name)).second;
581 :
582 E : DCHECK(inserted);
583 E : }
584 E : }
585 :
586 E : return true;
587 E : }
588 :
589 : } // namespace transforms
590 : } // namespace instrument
|