Load binary by UUID from qProcessInfo packet fields

Support three new keys in the qProcessInfo response from the remote
gdb stub to handle the case of attaching to a core running some type
of standalone/firmware code and the stub knows the UUID and load
address-or-slide for the binary.  There will be no proper DynamicLoader
plugin in this scenario, but we can try to locate and load the binary
into lldb at the correct offset.

Differential Revision: https://reviews.llvm.org/D116211
rdar://75191077
This commit is contained in:
Jason Molenda 2021-12-23 15:18:03 -08:00
parent 60509623c4
commit 8a26ba6a02
4 changed files with 133 additions and 0 deletions

View File

@ -1003,6 +1003,9 @@ vendor: is a string that represents the vendor (apple)
endian: is one of "little", "big", or "pdp"
ptrsize: is a number that represents how big pointers are in bytes
main-binary-uuid: is the UUID of a firmware type binary that the gdb stub knows about
main-binary-address: is the load address of the firmware type binary
main-binary-slide: is the slide of the firmware type binary, if address isn't known
//----------------------------------------------------------------------
// "qShlibInfoAddr"

View File

@ -1006,6 +1006,23 @@ GDBRemoteCommunicationClient::GetProcessArchitecture() {
return m_process_arch;
}
bool GDBRemoteCommunicationClient::GetProcessStandaloneBinary(
UUID &uuid, addr_t &value, bool &value_is_offset) {
if (m_qProcessInfo_is_valid == eLazyBoolCalculate)
GetCurrentProcessInfo();
// Return true if we have a UUID or an address/offset of the
// main standalone / firmware binary being used.
if (!m_process_standalone_uuid.IsValid() &&
m_process_standalone_value == LLDB_INVALID_ADDRESS)
return false;
uuid = m_process_standalone_uuid;
value = m_process_standalone_value;
value_is_offset = m_process_standalone_value_is_offset;
return true;
}
bool GDBRemoteCommunicationClient::GetGDBServerVersion() {
if (m_qGDBServerVersion_is_valid == eLazyBoolCalculate) {
m_gdb_server_name.clear();
@ -2147,6 +2164,25 @@ bool GDBRemoteCommunicationClient::GetCurrentProcessInfo(bool allow_lazy) {
} else if (name.equals("elf_abi")) {
elf_abi = std::string(value);
++num_keys_decoded;
} else if (name.equals("main-binary-uuid")) {
m_process_standalone_uuid.SetFromStringRef(value);
++num_keys_decoded;
} else if (name.equals("main-binary-slide")) {
StringExtractor extractor(value);
m_process_standalone_value =
extractor.GetU64(LLDB_INVALID_ADDRESS, 16);
if (m_process_standalone_value != LLDB_INVALID_ADDRESS) {
m_process_standalone_value_is_offset = true;
++num_keys_decoded;
}
} else if (name.equals("main-binary-address")) {
StringExtractor extractor(value);
m_process_standalone_value =
extractor.GetU64(LLDB_INVALID_ADDRESS, 16);
if (m_process_standalone_value != LLDB_INVALID_ADDRESS) {
m_process_standalone_value_is_offset = false;
++num_keys_decoded;
}
}
}
if (num_keys_decoded > 0)

View File

@ -217,6 +217,9 @@ public:
const ArchSpec &GetProcessArchitecture();
bool GetProcessStandaloneBinary(UUID &uuid, lldb::addr_t &value,
bool &value_is_offset);
void GetRemoteQSupported();
bool GetVContSupported(char flavor);
@ -584,6 +587,9 @@ protected:
ArchSpec m_host_arch;
ArchSpec m_process_arch;
UUID m_process_standalone_uuid;
lldb::addr_t m_process_standalone_value = LLDB_INVALID_ADDRESS;
bool m_process_standalone_value_is_offset = false;
llvm::VersionTuple m_os_version;
llvm::VersionTuple m_maccatalyst_version;
std::string m_os_build;

View File

@ -561,6 +561,94 @@ Status ProcessGDBRemote::DoConnectRemote(llvm::StringRef remote_url) {
}
}
// The remote stub may know about the "main binary" in
// the context of a firmware debug session, and can
// give us a UUID and an address/slide of where the
// binary is loaded in memory.
UUID standalone_uuid;
addr_t standalone_value;
bool standalone_value_is_offset;
if (m_gdb_comm.GetProcessStandaloneBinary(
standalone_uuid, standalone_value, standalone_value_is_offset)) {
ModuleSP module_sp;
if (standalone_uuid.IsValid()) {
ModuleSpec module_spec;
module_spec.GetUUID() = standalone_uuid;
// Look up UUID in global module cache before attempting
// a more expensive search.
Status error = ModuleList::GetSharedModule(module_spec, module_sp,
nullptr, nullptr, nullptr);
if (!module_sp) {
// Force a an external lookup, if that tool is available.
if (!module_spec.GetSymbolFileSpec())
Symbols::DownloadObjectAndSymbolFile(module_spec, true);
if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) {
module_sp = std::make_shared<Module>(module_spec);
}
}
// If we couldn't find the binary anywhere else, as a last resort,
// read it out of memory.
if (!module_sp.get() && standalone_value != LLDB_INVALID_ADDRESS &&
!standalone_value_is_offset) {
char namebuf[80];
snprintf(namebuf, sizeof(namebuf), "mem-image-0x%" PRIx64,
standalone_value);
module_sp =
ReadModuleFromMemory(FileSpec(namebuf), standalone_value);
}
Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(
LIBLLDB_LOG_DYNAMIC_LOADER));
if (module_sp.get()) {
target.GetImages().AppendIfNeeded(module_sp, false);
bool changed = false;
if (module_sp->GetObjectFile()) {
if (standalone_value != LLDB_INVALID_ADDRESS) {
if (log)
log->Printf("Loading binary UUID %s at %s 0x%" PRIx64,
standalone_uuid.GetAsString().c_str(),
standalone_value_is_offset ? "offset" : "address",
standalone_value);
module_sp->SetLoadAddress(target, standalone_value,
standalone_value_is_offset, changed);
} else {
// No address/offset/slide, load the binary at file address,
// offset 0.
if (log)
log->Printf("Loading binary UUID %s at file address",
standalone_uuid.GetAsString().c_str());
const bool value_is_slide = true;
module_sp->SetLoadAddress(target, 0, value_is_slide, changed);
}
} else {
// In-memory image, load at its true address, offset 0.
if (log)
log->Printf("Loading binary UUID %s from memory",
standalone_uuid.GetAsString().c_str());
const bool value_is_slide = true;
module_sp->SetLoadAddress(target, 0, value_is_slide, changed);
}
ModuleList added_module;
added_module.Append(module_sp, false);
target.ModulesDidLoad(added_module);
} else {
if (log)
log->Printf("Unable to find binary with UUID %s and load it at "
"%s 0x%" PRIx64,
standalone_uuid.GetAsString().c_str(),
standalone_value_is_offset ? "offset" : "address",
standalone_value);
}
}
}
const StateType state = SetThreadStopInfo(response);
if (state != eStateInvalid) {
SetPrivateState(state);