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