Skip to content

Commit 459c4a2

Browse files
committed
[lldb] Fix LLDBMemoryReader resolving GOT pointers incorrectly
The DYLD shared cache, as an optimization, can merge GOT pointers from multiple images into one location, and fix all relative offsets to point to the new updated location. When reading metadata, LLDB tries, as an optimization, to read memory from local files instead of live memory. This means that the relative offset will point to the old location in the GOT section. In this case, LLDB needs to re-read the offset from live memory, to get the correct offset in live memory. rdar://160837587
1 parent eff752e commit 459c4a2

File tree

2 files changed

+149
-0
lines changed

2 files changed

+149
-0
lines changed

lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.cpp

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,150 @@ LLDBMemoryReader::resolvePointer(swift::remote::RemoteAddress address,
316316
return tagged_pointer;
317317
}
318318

319+
swift::reflection::RemoteAddress
320+
LLDBMemoryReader::resolveIndirectAddressAtOffset(
321+
swift::reflection::RemoteAddress address, uint64_t offset,
322+
bool directnessEncodedInOffset) {
323+
// Usually, simply adding the address with the offset will produce the correct
324+
// remote address.
325+
//
326+
// However, on Apple platforms, the shared cache can coalesce pointers in the
327+
// global offset table from multiple images into one location, patch all the
328+
// uses to point to the new location, and zero out the original pointer. In
329+
// this case, LLDBMemoryReader needs to be conservative and re-fetch the
330+
// offset from live memory to ensure it points to the new, coalesced location
331+
// instead.
332+
Log *log = GetLog(LLDBLog::Types);
333+
334+
LLDB_LOGV(log,
335+
"[MemoryReader::resolveAddressAtOffset] Asked to resolve address "
336+
"{0:x} at offset {1:x}",
337+
address.getRawAddress(), offset);
338+
339+
auto offset_address = address + offset;
340+
341+
if (!readMetadataFromFileCacheEnabled())
342+
return offset_address;
343+
344+
// Addresses in the process don't apply.
345+
if (offset_address.getAddressSpace() ==
346+
swift::reflection::RemoteAddress::DefaultAddressSpace)
347+
return offset_address;
348+
349+
// Check if offset_address points to a GOT entry.
350+
std::optional<Address> maybeAddr =
351+
resolveRemoteAddressFromSymbolObjectFile(offset_address);
352+
353+
if (!maybeAddr)
354+
maybeAddr = remoteAddressToLLDBAddress(offset_address);
355+
356+
if (!maybeAddr) {
357+
LLDB_LOGV(log,
358+
"[MemoryReader::resolveAddressAtOffset] could not resolve "
359+
"address {0:x}",
360+
offset_address.getRawAddress());
361+
return offset_address;
362+
}
363+
364+
auto lldb_offset_address = *maybeAddr;
365+
if (!lldb_offset_address.IsSectionOffset()) {
366+
LLDB_LOGV(
367+
log,
368+
"[MemoryReader::resolveAddressAtOffset] lldb offset address has no "
369+
"section {0:x}",
370+
offset_address.getRawAddress());
371+
return offset_address;
372+
}
373+
374+
// This is only necessary on Apple platforms.
375+
auto *obj_file = lldb_offset_address.GetModule()->GetObjectFile();
376+
if (!obj_file || !obj_file->GetArchitecture().GetTriple().isAppleMachO())
377+
return offset_address;
378+
379+
auto section = lldb_offset_address.GetSection();
380+
auto segment = section->GetParent();
381+
if (!segment) {
382+
LLDB_LOGV(
383+
log,
384+
"[MemoryReader::resolveAddressAtOffset] lldb offset address has no "
385+
"section {0:x}",
386+
offset_address.getRawAddress());
387+
return offset_address;
388+
}
389+
390+
// The segment/section pair has to be:
391+
//__DATA_CONST,__got, __AUTH_CONST,__auth_got or __AUTH_CONST,__auth_ptr.
392+
bool is_data_const_got =
393+
segment->GetName() == "__DATA_CONST" && section->GetName() == "__got";
394+
bool is_auth_const_ptr = segment->GetName() == "__AUTH_CONST" &&
395+
(section->GetName() == "__auth_got" ||
396+
section->GetName() == "__auth_ptr");
397+
398+
if (!is_data_const_got && !is_auth_const_ptr)
399+
return offset_address;
400+
401+
// offset_address is in a GOT section. Re-read the offset from the base
402+
// address in live memory, since the offset in live memory can have been
403+
// patched in the shared cache to point somewhere else.
404+
std::optional<Address> maybe_lldb_addr =
405+
resolveRemoteAddressFromSymbolObjectFile(address);
406+
407+
if (!maybe_lldb_addr)
408+
maybe_lldb_addr = remoteAddressToLLDBAddress(address);
409+
410+
if (!maybe_lldb_addr) {
411+
LLDB_LOGV(log,
412+
"[MemoryReader::resolveAddressAtOffset] could not resolve offset "
413+
"address {0:x}",
414+
address.getRawAddress());
415+
return offset_address;
416+
}
417+
418+
auto lldb_addr = *maybe_lldb_addr;
419+
Target &target(m_process.GetTarget());
420+
Status error;
421+
const bool force_live_memory = true;
422+
bool did_read_live_memory = false;
423+
424+
// Relative offsets are always 4 bytes long, regardless of target.
425+
uint32_t live_offset = 0;
426+
auto size = sizeof(live_offset);
427+
if (size !=
428+
target.ReadMemory(lldb_addr, &live_offset, size, error, force_live_memory,
429+
/*load_addr_ptr=*/nullptr, &did_read_live_memory)) {
430+
LLDB_LOG(log,
431+
"[MemoryReader::resolveAddressAtOffset] Resolve address returned "
432+
"different bytes than asked "
433+
"for {0:x}",
434+
lldb_addr.GetLoadAddress(&target));
435+
return offset_address;
436+
}
437+
if (error.Fail()) {
438+
LLDB_LOG(log,
439+
"[MemoryReader::resolveAddressAtOffset] memory read returned "
440+
"error: {0}",
441+
error.AsCString());
442+
return offset_address;
443+
}
444+
// Some Swift metadata encodes the directness directly into the offset,
445+
// in that case clear the directness bit.
446+
if (directnessEncodedInOffset)
447+
live_offset &= ~1u;
448+
449+
// Now, get the live address counterpart of the lldb address this function
450+
// started with, and add the live offset we just read to it.
451+
auto live_address = lldb_addr.GetLoadAddress(&target);
452+
LLDB_LOGV(
453+
log,
454+
"[MemoryReader::resolveAddressAtOffset] Succesfully resolved address "
455+
"into live address {0:x} and offset {1:x} resulting in address {2:x}",
456+
live_address, live_offset, live_address + live_offset);
457+
458+
return swift::remote::RemoteAddress(
459+
live_address + live_offset,
460+
swift::remote::RemoteAddress::DefaultAddressSpace);
461+
}
462+
319463
bool LLDBMemoryReader::readBytes(swift::remote::RemoteAddress address,
320464
uint8_t *dest, uint64_t size) {
321465
auto read_bytes_result = readBytesImpl(address, dest, size);

lldb/source/Plugins/LanguageRuntime/Swift/LLDBMemoryReader.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@ class LLDBMemoryReader : public swift::remote::MemoryReader {
8787
std::optional<swift::remote::RemoteAddress>
8888
resolveRemoteAddress(swift::remote::RemoteAddress address) const override;
8989

90+
swift::reflection::RemoteAddress
91+
resolveIndirectAddressAtOffset(swift::reflection::RemoteAddress address,
92+
uint64_t offset,
93+
bool directnessEncodedInOffset) override;
94+
9095
bool readBytes(swift::remote::RemoteAddress address, uint8_t *dest,
9196
uint64_t size) override;
9297

0 commit comments

Comments
 (0)