@@ -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+
319463bool LLDBMemoryReader::readBytes (swift::remote::RemoteAddress address,
320464 uint8_t *dest, uint64_t size) {
321465 auto read_bytes_result = readBytesImpl (address, dest, size);
0 commit comments