The dyld_all_image_infos structure, at version 13 and higher, has

a UUID for the shared cache libraries that can be used to confirm
that one process' shared cache is the same as another, or that a
process' in-memory shared cache is a match for a given on-disk
dyld_shared_cache binary file.  Use these UUIDs to catch some
uncommon problems when the shared caches are being changed for debug
purposes.
<rdar://problem/13524467>

llvm-svn: 179583
This commit is contained in:
Jason Molenda 2013-04-16 06:24:42 +00:00
parent 73d1739bc4
commit 0e0954c85a
2 changed files with 127 additions and 13 deletions

View File

@ -38,6 +38,11 @@
#include "Plugins/Process/Utility/RegisterContextDarwin_i386.h"
#include "Plugins/Process/Utility/RegisterContextDarwin_x86_64.h"
#if defined (__APPLE__) && defined (__arm__)
// GetLLDBSharedCacheUUID() needs to call dlsym()
#include <dlfcn.h>
#endif
using namespace lldb;
using namespace lldb_private;
using namespace llvm::MachO;
@ -1372,8 +1377,17 @@ ObjectFileMachO::ParseSymtab (bool minimize)
// symbol and string table. Reading all of this symbol and string table
// data across can slow down debug launch times, so we optimize this by
// reading the memory for the __LINKEDIT section from this process.
UUID lldb_shared_cache(GetLLDBSharedCacheUUID());
UUID process_shared_cache(GetProcessSharedCacheUUID(process));
bool use_lldb_cache = true;
if (lldb_shared_cache.IsValid() && process_shared_cache.IsValid() && lldb_shared_cache != process_shared_cache)
{
use_lldb_cache = false;
}
PlatformSP platform_sp (target.GetPlatform());
if (platform_sp && platform_sp->IsHost())
if (platform_sp && platform_sp->IsHost() && use_lldb_cache)
{
data_was_read = true;
nlist_data.SetData((void *)symoff_addr, nlist_data_byte_size, eByteOrderLittle);
@ -1571,16 +1585,6 @@ ObjectFileMachO::ParseSymtab (bool minimize)
// Before we can start mapping the DSC, we need to make certain the target process is actually
// using the cache we can find.
/*
* TODO (FIXME!)
*
* Consider the case of testing with a separate DSC file.
* If we go through the normal code paths, we will give symbols for the wrong DSC, and
* that is bad. We need to read the target process' all_image_infos struct, and look
* at the values of the processDetachedFromSharedRegion field. If that is set, we should skip
* this code section.
*/
// Next we need to determine the correct path for the dyld shared cache.
ArchSpec header_arch(eArchTypeMachO, m_header.cputype, m_header.cpusubtype);
@ -1688,14 +1692,35 @@ ObjectFileMachO::ParseSymtab (bool minimize)
}
}
UUID dsc_uuid;
if (version >= 1)
{
offset = offsetof (struct lldb_copy_dyld_cache_header_v1, uuid);
uint8_t uuid_bytes[sizeof (uuid_t)];
memcpy (uuid_bytes, dsc_header_data.GetData (&offset, sizeof (uuid_t)), sizeof (uuid_t));
dsc_uuid.SetBytes (uuid_bytes);
}
bool uuid_match = true;
if (dsc_uuid.IsValid() && process)
{
UUID shared_cache_uuid(GetProcessSharedCacheUUID(process));
if (shared_cache_uuid.IsValid() && dsc_uuid != shared_cache_uuid)
{
// The on-disk dyld_shared_cache file is not the same as the one in this
// process' memory, don't use it.
uuid_match = false;
}
}
offset = offsetof (struct lldb_copy_dyld_cache_header_v1, mappingOffset);
uint32_t mappingOffset = dsc_header_data.GetU32(&offset);
// If the mappingOffset points to a location inside the header, we've
// opened an old dyld shared cache, and should not proceed further.
if ((version == 0 && mappingOffset >= sizeof(struct lldb_copy_dyld_cache_header_v0))
|| (version >= 1 && mappingOffset >= sizeof(struct lldb_copy_dyld_cache_header_v1)))
if (uuid_match && mappingOffset >= sizeof(struct lldb_copy_dyld_cache_header_v0))
{
DataBufferSP dsc_mapping_info_data_sp = dsc_filespec.MemoryMapFileContents(mappingOffset, sizeof (struct lldb_copy_dyld_cache_mapping_info));
@ -3942,6 +3967,78 @@ ObjectFileMachO::GetArchitecture (ArchSpec &arch)
}
UUID
ObjectFileMachO::GetProcessSharedCacheUUID (Process *process)
{
UUID uuid;
if (process)
{
addr_t all_image_infos = process->GetImageInfoAddress();
// The address returned by GetImageInfoAddress may be the address of dyld (don't want)
// or it may be the address of the dyld_all_image_infos structure (want). The first four
// bytes will be either the version field (all_image_infos) or a Mach-O file magic constant.
// Version 13 and higher of dyld_all_image_infos is required to get the sharedCacheUUID field.
Error err;
uint32_t version_or_magic = process->ReadUnsignedIntegerFromMemory (all_image_infos, 4, -1, err);
if (version_or_magic != -1
&& version_or_magic != HeaderMagic32
&& version_or_magic != HeaderMagic32Swapped
&& version_or_magic != HeaderMagic64
&& version_or_magic != HeaderMagic64Swapped
&& version_or_magic >= 13)
{
addr_t sharedCacheUUID_address = LLDB_INVALID_ADDRESS;
int wordsize = process->GetAddressByteSize();
if (wordsize == 8)
{
sharedCacheUUID_address = all_image_infos + 160; // sharedCacheUUID <mach-o/dyld_images.h>
}
if (wordsize == 4)
{
sharedCacheUUID_address = all_image_infos + 84; // sharedCacheUUID <mach-o/dyld_images.h>
}
if (sharedCacheUUID_address != LLDB_INVALID_ADDRESS)
{
uuid_t shared_cache_uuid;
if (process->ReadMemory (sharedCacheUUID_address, shared_cache_uuid, sizeof (uuid_t), err) == sizeof (uuid_t))
{
uuid.SetBytes (shared_cache_uuid);
}
}
}
}
return uuid;
}
UUID
ObjectFileMachO::GetLLDBSharedCacheUUID ()
{
UUID uuid;
#if defined (__APPLE__) && defined (__arm__)
uint8_t *(*dyld_get_all_image_infos)(void);
dyld_get_all_image_infos = (uint8_t*(*)()) dlsym (RTLD_DEFAULT, "_dyld_get_all_image_infos");
if (dyld_get_all_image_infos)
{
uint8_t *dyld_all_image_infos_address = dyld_get_all_image_infos();
if (dyld_all_image_infos_address)
{
uint32_t version;
memcpy (&version, dyld_all_image_infos_address, 4);
if (version >= 13)
{
uint8_t *sharedCacheUUID_address = 0;
sharedCacheUUID_address = dyld_all_image_infos_address + 84; // sharedCacheUUID <mach-o/dyld_images.h>
uuid.SetBytes (sharedCacheUUID_address);
}
}
}
#endif
return uuid;
}
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------

View File

@ -145,6 +145,23 @@ public:
GetVersion (uint32_t *versions, uint32_t num_versions);
protected:
// Intended for same-host arm device debugging where lldb needs to
// detect libraries in the shared cache and augment the nlist entries
// with an on-disk dyld_shared_cache file. The process will record
// the shared cache UUID so the on-disk cache can be matched or rejected
// correctly.
lldb_private::UUID
GetProcessSharedCacheUUID (lldb_private::Process *);
// Intended for same-host arm device debugging where lldb will read
// shared cache libraries out of its own memory instead of the remote
// process' memory as an optimization. If lldb's shared cache UUID
// does not match the process' shared cache UUID, this optimization
// should not be used.
lldb_private::UUID
GetLLDBSharedCacheUUID ();
llvm::MachO::mach_header m_header;
static const lldb_private::ConstString &GetSegmentNameTEXT();
static const lldb_private::ConstString &GetSegmentNameDATA();