diff --git a/lldb/docs/lldb-gdb-remote.txt b/lldb/docs/lldb-gdb-remote.txt --- a/lldb/docs/lldb-gdb-remote.txt +++ b/lldb/docs/lldb-gdb-remote.txt @@ -1003,6 +1003,9 @@ 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" diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h @@ -217,6 +217,9 @@ 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 @@ 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; diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -1006,6 +1006,23 @@ 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 @@ } 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) diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -561,6 +561,87 @@ } } + // 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.get()) { + // 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_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); + } + + if (module_sp.get()) { + target.GetImages().AppendIfNeeded(module_sp, false); + + bool changed = false; + Log *log(ProcessGDBRemoteLog::GetLogIfAllCategoriesSet( + LIBLLDB_LOG_DYNAMIC_LOADER)); + 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); + } + } + } + const StateType state = SetThreadStopInfo(response); if (state != eStateInvalid) { SetPrivateState(state);