Skip to content

Commit eddff61

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 903c72f commit eddff61

File tree

2 files changed

+131
-0
lines changed

2 files changed

+131
-0
lines changed

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

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,132 @@ LLDBMemoryReader::resolvePointer(swift::remote::RemoteAddress address,
317317
return tagged_pointer;
318318
}
319319

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