Skip to content

Commit 774ece6

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 (cherry picked from commit eddff61)
1 parent 0bb0fde commit 774ece6

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
@@ -313,6 +313,132 @@ LLDBMemoryReader::resolvePointer(swift::remote::RemoteAddress address,
313313
return tagged_pointer;
314314
}
315315

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

83+
swift::reflection::RemoteAddress
84+
resolveIndirectAddressAtOffset(swift::reflection::RemoteAddress address,
85+
uint64_t offset,
86+
bool directnessEncodedInOffset) override;
87+
8388
bool readBytes(swift::remote::RemoteAddress address, uint8_t *dest,
8489
uint64_t size) override;
8590

0 commit comments

Comments
 (0)