Skip to content

Commit d850888

Browse files
authored
Allow loading of multiple firmware binaries (#5064)
* Allow firmware binaries to be specified only by load address Add support to Mach-O corefiles and to live gdb remote serial protocol connections for the corefile/remote stub to provide a list of load addresses of binaries that should be found & loaded by lldb, and nothing else. lldb will try to parse the binary out of memory, and if it can find a UUID, try to find a binary & its debug information based on the UUID, falling back to using the memory image if it must. A bit of code unification from three parts of lldb that were loading individual binaries already, so there is a shared method in DynamicLoader to handle all of the variations they were doing. Re-landing this with a uuid_is_null() implementation added to Utility/UuidCompatibility.h for non-Darwin systems. Differential Revision: https://reviews.llvm.org/D130813 rdar://94249937 rdar://94249384 (cherry picked from commit 96d1218) * Inline my uuid_is_null() implementation in a header file This either needs to be static, or forced inline, or in a separate source file. Given that we only have one function in this UuidCompatibility.h, I think forced inline for the handful of uses of it may be best. (cherry picked from commit 318454a)
1 parent 1a0c6d9 commit d850888

File tree

15 files changed

+952
-208
lines changed

15 files changed

+952
-208
lines changed

lldb/docs/lldb-gdb-remote.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,6 +1007,12 @@ main-binary-uuid: is the UUID of a firmware type binary that the gdb stub knows
10071007
main-binary-address: is the load address of the firmware type binary
10081008
main-binary-slide: is the slide of the firmware type binary, if address isn't known
10091009

1010+
binary-addresses: A comma-separated list of binary load addresses base16.
1011+
lldb will parse the binaries in memory to get UUIDs, then
1012+
try to find the binaries & debug info by UUID. Intended for
1013+
use with a small number of firmware type binaries where the
1014+
search for binary/debug info may be expensive.
1015+
10101016
//----------------------------------------------------------------------
10111017
// "qShlibInfoAddr"
10121018
//

lldb/include/lldb/Target/DynamicLoader.h

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,52 @@ class DynamicLoader : public PluginInterface {
208208
lldb::addr_t base_addr,
209209
bool base_addr_is_offset);
210210

211+
/// Find/load a binary into lldb given a UUID and the address where it is
212+
/// loaded in memory, or a slide to be applied to the file address.
213+
/// May force an expensive search on the computer to find the binary by
214+
/// UUID, should not be used for a large number of binaries - intended for
215+
/// an environment where there may be one, or a few, binaries resident in
216+
/// memory.
217+
///
218+
/// Given a UUID, search for a binary and load it at the address provided,
219+
/// or with the slide applied, or at the file address unslid.
220+
///
221+
/// Given an address, try to read the binary out of memory, get the UUID,
222+
/// find the file if possible and load it unslid, or add the memory module.
223+
///
224+
/// \param[in] process
225+
/// The process to add this binary to.
226+
///
227+
/// \param[in] uuid
228+
/// UUID of the binary to be loaded. UUID may be empty, and if a
229+
/// load address is supplied, will read the binary from memory, get
230+
/// a UUID and try to find a local binary. There is a performance
231+
/// cost to doing this, it is not preferable.
232+
///
233+
/// \param[in] value
234+
/// Address where the binary should be loaded, or read out of memory.
235+
/// Or a slide value, to be applied to the file addresses of the binary.
236+
///
237+
/// \param[in] value_is_offset
238+
/// A flag indicating that \p value is an address, or an offset to
239+
/// be applied to the file addresses.
240+
///
241+
/// \param[in] force_symbol_search
242+
/// Allow the search to do a possibly expensive external search for
243+
/// the ObjectFile and/or SymbolFile.
244+
///
245+
/// \param[in] notify
246+
/// Whether ModulesDidLoad should be called when a binary has been added
247+
/// to the Target. The caller may prefer to batch up these when loading
248+
/// multiple binaries.
249+
///
250+
/// \return
251+
/// Returns a shared pointer for the Module that has been added.
252+
static lldb::ModuleSP
253+
LoadBinaryWithUUIDAndAddress(Process *process, UUID uuid, lldb::addr_t value,
254+
bool value_is_offset, bool force_symbol_search,
255+
bool notify);
256+
211257
/// Get information about the shared cache for a process, if possible.
212258
///
213259
/// On some systems (e.g. Darwin based systems), a set of libraries that are

lldb/source/Core/DynamicLoader.cpp

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,15 @@
1313
#include "lldb/Core/ModuleSpec.h"
1414
#include "lldb/Core/PluginManager.h"
1515
#include "lldb/Core/Section.h"
16+
#include "lldb/Symbol/LocateSymbolFile.h"
1617
#include "lldb/Symbol/ObjectFile.h"
1718
#include "lldb/Target/MemoryRegionInfo.h"
19+
#include "lldb/Target/Platform.h"
1820
#include "lldb/Target/Process.h"
1921
#include "lldb/Target/Target.h"
2022
#include "lldb/Utility/ConstString.h"
23+
#include "lldb/Utility/LLDBLog.h"
24+
#include "lldb/Utility/Log.h"
2125
#include "lldb/lldb-private-interfaces.h"
2226

2327
#include "llvm/ADT/StringRef.h"
@@ -213,6 +217,100 @@ ModuleSP DynamicLoader::LoadModuleAtAddress(const FileSpec &file,
213217
return module_sp;
214218
}
215219

220+
static ModuleSP ReadUnnamedMemoryModule(Process *process, addr_t addr) {
221+
char namebuf[80];
222+
snprintf(namebuf, sizeof(namebuf), "memory-image-0x%" PRIx64, addr);
223+
return process->ReadModuleFromMemory(FileSpec(namebuf), addr);
224+
}
225+
226+
ModuleSP DynamicLoader::LoadBinaryWithUUIDAndAddress(Process *process,
227+
UUID uuid, addr_t value,
228+
bool value_is_offset,
229+
bool force_symbol_search,
230+
bool notify) {
231+
ModuleSP memory_module_sp;
232+
ModuleSP module_sp;
233+
PlatformSP platform_sp = process->GetTarget().GetPlatform();
234+
Target &target = process->GetTarget();
235+
Status error;
236+
ModuleSpec module_spec;
237+
module_spec.GetUUID() = uuid;
238+
239+
if (!uuid.IsValid() && !value_is_offset) {
240+
memory_module_sp = ReadUnnamedMemoryModule(process, value);
241+
242+
if (memory_module_sp)
243+
uuid = memory_module_sp->GetUUID();
244+
}
245+
246+
if (uuid.IsValid()) {
247+
ModuleSpec module_spec;
248+
module_spec.GetUUID() = uuid;
249+
250+
if (!module_sp)
251+
module_sp = target.GetOrCreateModule(module_spec, false, &error);
252+
253+
// If we haven't found a binary, or we don't have a SymbolFile, see
254+
// if there is an external search tool that can find it.
255+
if (force_symbol_search &&
256+
(!module_sp || !module_sp->GetSymbolFileFileSpec())) {
257+
Symbols::DownloadObjectAndSymbolFile(module_spec, error, true);
258+
if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) {
259+
module_sp = std::make_shared<Module>(module_spec);
260+
}
261+
}
262+
}
263+
264+
// If we couldn't find the binary anywhere else, as a last resort,
265+
// read it out of memory.
266+
if (!module_sp.get() && value != LLDB_INVALID_ADDRESS && !value_is_offset) {
267+
if (!memory_module_sp)
268+
memory_module_sp = ReadUnnamedMemoryModule(process, value);
269+
if (memory_module_sp)
270+
module_sp = memory_module_sp;
271+
}
272+
273+
Log *log = GetLog(LLDBLog::DynamicLoader);
274+
if (module_sp.get()) {
275+
target.GetImages().AppendIfNeeded(module_sp, false);
276+
277+
bool changed = false;
278+
if (module_sp->GetObjectFile()) {
279+
if (value != LLDB_INVALID_ADDRESS) {
280+
LLDB_LOGF(log, "Loading binary UUID %s at %s 0x%" PRIx64,
281+
uuid.GetAsString().c_str(),
282+
value_is_offset ? "offset" : "address", value);
283+
module_sp->SetLoadAddress(target, value, value_is_offset, changed);
284+
} else {
285+
// No address/offset/slide, load the binary at file address,
286+
// offset 0.
287+
LLDB_LOGF(log, "Loading binary UUID %s at file address",
288+
uuid.GetAsString().c_str());
289+
module_sp->SetLoadAddress(target, 0, true /* value_is_slide */,
290+
changed);
291+
}
292+
} else {
293+
// In-memory image, load at its true address, offset 0.
294+
LLDB_LOGF(log, "Loading binary UUID %s from memory at address 0x%" PRIx64,
295+
uuid.GetAsString().c_str(), value);
296+
module_sp->SetLoadAddress(target, 0, true /* value_is_slide */, changed);
297+
}
298+
299+
if (notify) {
300+
ModuleList added_module;
301+
added_module.Append(module_sp, false);
302+
target.ModulesDidLoad(added_module);
303+
}
304+
} else {
305+
LLDB_LOGF(log, "Unable to find binary with UUID %s and load it at "
306+
"%s 0x%" PRIx64,
307+
uuid.GetAsString().c_str(),
308+
value_is_offset ? "offset" : "address", value);
309+
}
310+
311+
return module_sp;
312+
}
313+
216314
int64_t DynamicLoader::ReadUnsignedIntWithSizeInBytes(addr_t addr,
217315
int size_in_bytes) {
218316
Status error;

lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp

Lines changed: 33 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5760,7 +5760,8 @@ bool ObjectFileMachO::GetCorefileMainBinaryInfo(addr_t &value,
57605760
}
57615761

57625762
if (m_data.CopyData(offset, sizeof(uuid_t), raw_uuid) != 0) {
5763-
uuid = UUID::fromOptionalData(raw_uuid, sizeof(uuid_t));
5763+
if (!uuid_is_null(raw_uuid))
5764+
uuid = UUID::fromOptionalData(raw_uuid, sizeof(uuid_t));
57645765
// convert the "main bin spec" type into our
57655766
// ObjectFile::BinaryType enum
57665767
switch (binspec_type) {
@@ -7079,7 +7080,8 @@ ObjectFileMachO::GetCorefileAllImageInfos() {
70797080

70807081
MachOCorefileImageEntry image_entry;
70817082
image_entry.filename = (const char *)m_data.GetCStr(&filepath_offset);
7082-
image_entry.uuid = UUID::fromData(uuid, sizeof(uuid_t));
7083+
if (!uuid_is_null(uuid))
7084+
image_entry.uuid = UUID::fromData(uuid, sizeof(uuid_t));
70837085
image_entry.load_address = load_address;
70847086
image_entry.currently_executing = currently_executing;
70857087

@@ -7110,9 +7112,11 @@ ObjectFileMachO::GetCorefileAllImageInfos() {
71107112

71117113
MachOCorefileImageEntry image_entry;
71127114
image_entry.filename = filename;
7113-
image_entry.uuid = UUID::fromData(uuid, sizeof(uuid_t));
7115+
if (!uuid_is_null(uuid))
7116+
image_entry.uuid = UUID::fromData(uuid, sizeof(uuid_t));
71147117
image_entry.load_address = load_address;
71157118
image_entry.slide = slide;
7119+
image_entry.currently_executing = true;
71167120
image_infos.all_image_infos.push_back(image_entry);
71177121
}
71187122
}
@@ -7129,42 +7133,41 @@ bool ObjectFileMachO::LoadCoreFileImages(lldb_private::Process &process) {
71297133

71307134
ModuleList added_modules;
71317135
for (const MachOCorefileImageEntry &image : image_infos.all_image_infos) {
7132-
ModuleSpec module_spec;
7133-
module_spec.GetUUID() = image.uuid;
7134-
if (image.filename.empty()) {
7135-
char namebuf[80];
7136-
if (image.load_address != LLDB_INVALID_ADDRESS)
7137-
snprintf(namebuf, sizeof(namebuf), "mem-image-0x%" PRIx64,
7138-
image.load_address);
7139-
else
7140-
snprintf(namebuf, sizeof(namebuf), "mem-image+0x%" PRIx64, image.slide);
7141-
module_spec.GetFileSpec() = FileSpec(namebuf);
7142-
} else {
7143-
module_spec.GetFileSpec() = FileSpec(image.filename.c_str());
7144-
}
7145-
if (image.currently_executing) {
7136+
ModuleSP module_sp;
7137+
7138+
if (!image.filename.empty()) {
71467139
Status error;
7147-
Symbols::DownloadObjectAndSymbolFile(module_spec, error, true);
7148-
if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) {
7149-
process.GetTarget().GetOrCreateModule(module_spec, false);
7140+
ModuleSpec module_spec;
7141+
module_spec.GetUUID() = image.uuid;
7142+
module_spec.GetFileSpec() = FileSpec(image.filename.c_str());
7143+
if (image.currently_executing) {
7144+
Symbols::DownloadObjectAndSymbolFile(module_spec, error, true);
7145+
if (FileSystem::Instance().Exists(module_spec.GetFileSpec())) {
7146+
process.GetTarget().GetOrCreateModule(module_spec, false);
7147+
}
71507148
}
7151-
}
7152-
Status error;
7153-
ModuleSP module_sp =
7154-
process.GetTarget().GetOrCreateModule(module_spec, false, &error);
7155-
if (!module_sp.get() || !module_sp->GetObjectFile()) {
7149+
module_sp =
7150+
process.GetTarget().GetOrCreateModule(module_spec, false, &error);
7151+
process.GetTarget().GetImages().AppendIfNeeded(module_sp,
7152+
false /* notify */);
7153+
} else {
71567154
if (image.load_address != LLDB_INVALID_ADDRESS) {
7157-
module_sp = process.ReadModuleFromMemory(module_spec.GetFileSpec(),
7158-
image.load_address);
7155+
module_sp = DynamicLoader::LoadBinaryWithUUIDAndAddress(
7156+
&process, image.uuid, image.load_address,
7157+
false /* value_is_offset */, image.currently_executing,
7158+
false /* notify */);
7159+
} else if (image.slide != LLDB_INVALID_ADDRESS) {
7160+
module_sp = DynamicLoader::LoadBinaryWithUUIDAndAddress(
7161+
&process, image.uuid, image.slide, true /* value_is_offset */,
7162+
image.currently_executing, false /* notify */);
71597163
}
71607164
}
7165+
71617166
if (module_sp.get()) {
71627167
// Will call ModulesDidLoad with all modules once they've all
71637168
// been added to the Target with load addresses. Don't notify
71647169
// here, before the load address is set.
7165-
const bool notify = false;
7166-
process.GetTarget().GetImages().AppendIfNeeded(module_sp, notify);
7167-
added_modules.Append(module_sp, notify);
7170+
added_modules.Append(module_sp, false /* notify */);
71687171
if (image.segment_load_addresses.size() > 0) {
71697172
if (log) {
71707173
std::string uuidstr = image.uuid.GetAsString();

lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,6 +1029,13 @@ bool GDBRemoteCommunicationClient::GetProcessStandaloneBinary(
10291029
return true;
10301030
}
10311031

1032+
std::vector<addr_t>
1033+
GDBRemoteCommunicationClient::GetProcessStandaloneBinaries() {
1034+
if (m_qProcessInfo_is_valid == eLazyBoolCalculate)
1035+
GetCurrentProcessInfo();
1036+
return m_binary_addresses;
1037+
}
1038+
10321039
bool GDBRemoteCommunicationClient::GetGDBServerVersion() {
10331040
if (m_qGDBServerVersion_is_valid == eLazyBoolCalculate) {
10341041
m_gdb_server_name.clear();
@@ -2188,6 +2195,14 @@ bool GDBRemoteCommunicationClient::GetCurrentProcessInfo(bool allow_lazy) {
21882195
m_process_standalone_value_is_offset = false;
21892196
++num_keys_decoded;
21902197
}
2198+
} else if (name.equals("binary-addresses")) {
2199+
addr_t addr;
2200+
while (!value.empty()) {
2201+
llvm::StringRef addr_str;
2202+
std::tie(addr_str, value) = value.split(',');
2203+
if (!addr_str.getAsInteger(16, addr))
2204+
m_binary_addresses.push_back(addr);
2205+
}
21912206
}
21922207
}
21932208
if (num_keys_decoded > 0)

lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,8 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase {
220220
bool GetProcessStandaloneBinary(UUID &uuid, lldb::addr_t &value,
221221
bool &value_is_offset);
222222

223+
std::vector<lldb::addr_t> GetProcessStandaloneBinaries();
224+
223225
void GetRemoteQSupported();
224226

225227
bool GetVContSupported(char flavor);
@@ -587,6 +589,7 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase {
587589
UUID m_process_standalone_uuid;
588590
lldb::addr_t m_process_standalone_value = LLDB_INVALID_ADDRESS;
589591
bool m_process_standalone_value_is_offset = false;
592+
std::vector<lldb::addr_t> m_binary_addresses;
590593
llvm::VersionTuple m_os_version;
591594
llvm::VersionTuple m_maccatalyst_version;
592595
std::string m_os_build;

0 commit comments

Comments
 (0)