[Lldb-commits] [lldb] af0471c - [lldb][Darwin] Fetch detailed binary info in chunks (#190720)
via lldb-commits
lldb-commits at lists.llvm.org
Mon Apr 13 16:51:55 PDT 2026
Author: Jason Molenda
Date: 2026-04-13T16:51:51-07:00
New Revision: af0471c1918ab76915bb3750655ffd3281a0b9e7
URL: https://github.com/llvm/llvm-project/commit/af0471c1918ab76915bb3750655ffd3281a0b9e7
DIFF: https://github.com/llvm/llvm-project/commit/af0471c1918ab76915bb3750655ffd3281a0b9e7.diff
LOG: [lldb][Darwin] Fetch detailed binary info in chunks (#190720)
When binaries have been loaded into a process on Darwin, lldb sends a
jGetLoadedDynamicLibrariesInfos packet to get the filepath, uuid, load
address, and detailed information from the mach header/load commands.
For a large UI app, the number of binaries that can be loaded (through
various dependencies) can exceed a thousand these days, and requesting
detailed information on all of those can result in debugserver
allocating too much memory when running in constrained environments, and
being killed.
In 2023 I laid the groundwork to fetch detailed information in chunks,
instead of one large request. The main challenge with this is when we
first attach to a process that is running, we send a "tell me about all
binaries loaded", and that prevents lldb from chunking the reply; the
packet design for jGetLoadedDynamicLibrariesInfos assumes the entire
reply is sent in one packet, instead of the typical gdb remote serial
protocol trick of a response with partial data starting with 'm' and a
response with a complete reply starting with 'l'. The 2023 change is to
add a new key to this packet, `report_load_commands` and when that is
set to `false`, only the load address of the binaries is reported.
lldb then uses the array of load addresses of all the binaries to fetch
detailed information about them in smaller groupings.
This PR implements the lldb side of that work.
Process::GetLoadedDynamicLibrariesInfos now takes a `bool
include_mh_and_load_commands`, ProcessGDBRemote sends that as an
argument in the jGetLoadedDynamicLibrariesInfos packet.
DynamicLoaderMacOS::DoInitialImageFetch is changed to only get the load
addresses on initial attach. If the reply includes the full binary
information (not just load addresses) -- when talking to an old
debugserver -- we will use that information instead of re-fetching it.
On a newer debugserver that only sent the load addresses, we'll send
this list of addresses to the standard method we use when dyld has told
us to load binaries at addresses already.
DynamicLoaderMacOS::AddBinaries, which takes a list of addresses and
fetches detailed information about them, is updated to request only 600
binaries at a time. A typical UI app will be in the 700-1000 binary
range these days, so this will turn one large fetch into two, in most
cases. There are some system UI processes that have many dependencies
that could require three fetches. I picked this number so most debug
sessions will be handled by two requests.
In debugserver MachProcess::FormatDynamicLibrariesIntoJSON, I removed
the obsolete-for-three-years-now `mod_date` field. I was sending back
the binary filepaths for this "don't send the detailed information"
version of the packet - I don't need that, and it just increases the
size, so I stopped sending filepaths in this mode.
I also added a new field for when we ARE sending detailed information,
`sizeof_mh_and_loadcmds`. I don't use this in lldb yet, but when we are
told about a binary and need to read it from memory today, we have an
initial read to get the mach header, which tells us the size of the load
commands. Then we have a second read of the mach header plus load
commands, before we can start binary processing in earnest. This is an
extra read packet and very unnecessary, given that debugserver knows how
large the mach header + load commands are. So I'm returning it here, and
at some point I'll find a way to pipe that into a new memory object file
creation method in lldb. It's one of those "I should really find a way
to remove that extra read some day" cleanups, and while I was in this
area, I'd add this first piece of that.
I don't have a test for this. I've been thinking about an API test that
creates 700 dylibs with empty functions in each, runs it, and confirms
all of the dylibs were loaded. I'd have to grab a packet log to be
completely sure we didn't read the full binary list in one go. But I
worry that compiling and linking even 700 do-nothing dylibs might be too
much. Maybe I should add a setting in DynamicLoaderMacOS::AddBinaries to
reduce the maximum number of binaries that can be read at once, and have
a small nubmer of dylibs. When by-hand testing this, I had a maximum of
5 binaries being queried in one packet.
rdar://109428337
Added:
Modified:
lldb/include/lldb/Target/Process.h
lldb/include/lldb/lldb-enumerations.h
lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp
lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
lldb/source/Plugins/Process/scripted/ScriptedProcess.h
lldb/tools/debugserver/source/DNB.cpp
lldb/tools/debugserver/source/DNB.h
lldb/tools/debugserver/source/DNBDefs.h
lldb/tools/debugserver/source/MacOSX/MachProcess.h
lldb/tools/debugserver/source/MacOSX/MachProcess.mm
lldb/tools/debugserver/source/RNBRemote.cpp
Removed:
################################################################################
diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h
index 307b4e932d396..e32a484198668 100644
--- a/lldb/include/lldb/Target/Process.h
+++ b/lldb/include/lldb/Target/Process.h
@@ -1332,16 +1332,47 @@ class Process : public std::enable_shared_from_this<Process>,
return StructuredData::ObjectSP();
}
- // On macOS 10.12, tvOS 10, iOS 10, watchOS 3 and newer, debugserver can
- // return the full list of loaded shared libraries without needing any input.
+ /// Retrieve a StructuredData dictionary about all of the binaries
+ /// loaded in the process at this time.
+ /// A Darwin target specific behavior, only supported by debugserver,
+ /// response will include load address, filepath, uuid, and may also
+ /// include the fully parsed mach header and load commands.
+ ///
+ /// \param [in] information_level
+ /// How much information about each binary should be returned;
+ /// there may be performance reasons to retrieve a minimal set
+ /// of information about all binaries, and then retrieve the
+ /// full information for a subset of the whole group.
+ ///
+ /// \return
+ /// A StructuredData object with the information that could be
+ /// retrieved.
virtual lldb_private::StructuredData::ObjectSP
- GetLoadedDynamicLibrariesInfos() {
+ GetLoadedDynamicLibrariesInfos(lldb::BinaryInformationLevel info_level) {
return StructuredData::ObjectSP();
}
- // On macOS 10.12, tvOS 10, iOS 10, watchOS 3 and newer, debugserver can
- // return information about binaries given their load addresses.
+ /// Retrieve a StructuredData dictionary about the binaries at
+ /// the provided load addresses.
+ /// A Darwin target specific behavior, only supported by debugserver,
+ /// response will include load address, filepath, uuid, fully parsed
+ /// mach header and load commands.
+ ///
+ /// \param [in] information_level
+ /// How much information about each binary should be returned;
+ /// there may be performance reasons to retrieve a minimal set
+ /// of information about all binaries, and then retrieve the
+ /// full information for a subset of the whole group.
+ ///
+ /// \param [in] load_addresses
+ /// The virtual address of the start of binaries to fetch
+ /// information.
+ ///
+ /// \return
+ /// A StructuredData object with the information that could be
+ /// retrieved..
virtual lldb_private::StructuredData::ObjectSP GetLoadedDynamicLibrariesInfos(
+ lldb::BinaryInformationLevel info_level,
const std::vector<lldb::addr_t> &load_addresses) {
return StructuredData::ObjectSP();
}
diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h
index 4d31c4db5c20b..68b659102e698 100644
--- a/lldb/include/lldb/lldb-enumerations.h
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -1446,6 +1446,19 @@ enum DILMode {
eDILModeFull
};
+/// When the Process plugin can retrieve information
+/// about all binaries loaded in the target process,
+/// or given a list of binary load addresses, this
+/// enum specifies how much information needed from
+/// the Process plugin; there may be performance reasons
+/// to limit the amount of information returned.
+enum BinaryInformationLevel {
+ eBinaryInformationLevelAddrOnly,
+ eBinaryInformationLevelAddrName,
+ eBinaryInformationLevelAddrNameUUID,
+ eBinaryInformationLevelFull
+};
+
} // namespace lldb
#endif // LLDB_LLDB_ENUMERATIONS_H
diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp
index feafa82c6eff4..ad97485373351 100644
--- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp
+++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp
@@ -189,10 +189,6 @@ void DynamicLoaderMacOS::ClearNotificationBreakpoint() {
}
}
-// Try and figure out where dyld is by first asking the Process if it knows
-// (which currently calls down in the lldb::Process to get the DYLD info
-// (available on SnowLeopard only). If that fails, then check in the default
-// addresses.
void DynamicLoaderMacOS::DoInitialImageFetch() {
Log *log = GetLog(LLDBLog::DynamicLoader);
@@ -203,7 +199,8 @@ void DynamicLoaderMacOS::DoInitialImageFetch() {
UnloadAllImages();
StructuredData::ObjectSP all_image_info_json_sp(
- m_process->GetLoadedDynamicLibrariesInfos());
+ m_process->GetLoadedDynamicLibrariesInfos(
+ eBinaryInformationLevelAddrOnly));
ImageInfo::collection image_infos;
if (all_image_info_json_sp.get() &&
all_image_info_json_sp->GetAsDictionary() &&
@@ -211,14 +208,44 @@ void DynamicLoaderMacOS::DoInitialImageFetch() {
all_image_info_json_sp->GetAsDictionary()
->GetValueForKey("images")
->GetAsArray()) {
- if (JSONImageInformationIntoImageInfo(all_image_info_json_sp,
- image_infos)) {
- LLDB_LOGF(log, "Initial module fetch: Adding %" PRId64 " modules.\n",
- (uint64_t)image_infos.size());
-
- auto images = PreloadModulesFromImageInfos(image_infos);
- UpdateSpecialBinariesFromPreloadedModules(images);
- AddModulesUsingPreloadedModules(images);
+
+ // Older debugserver (pre-2024-ish) will not recognize the
+ // eBinaryInformationLevelAddrOnly enum above, and
+ // will return the full binary information including mach
+ // header and segments/load commands. The response includes
+ // the full information on all binaries.
+ StructuredData::Array *images = all_image_info_json_sp->GetAsDictionary()
+ ->GetValueForKey("images")
+ ->GetAsArray();
+ if (images->GetSize() > 0 && images->GetItemAtIndex(0)->GetAsDictionary() &&
+ images->GetItemAtIndex(0)->GetAsDictionary()->HasKey("mach_header")) {
+ if (JSONImageInformationIntoImageInfo(all_image_info_json_sp,
+ image_infos)) {
+ LLDB_LOGF(log, "Initial module fetch: Adding %" PRIu64 " modules.\n",
+ (uint64_t)image_infos.size());
+
+ auto new_images = PreloadModulesFromImageInfos(image_infos);
+ UpdateSpecialBinariesFromPreloadedModules(new_images);
+ AddModulesUsingPreloadedModules(new_images);
+ }
+ } else {
+ // This is a newer debugserver which only replied with
+ // `load_address` for all binaries loaded in the process.
+ // We can request detailed information in smaller chunks,
+ // instead of one gigantic packet.
+ size_t image_count = images->GetSize();
+ std::vector<addr_t> load_addresses;
+ for (size_t i = 0; i < image_count; i++) {
+ StructuredData::Dictionary *image =
+ images->GetItemAtIndex(i)->GetAsDictionary();
+ if (image && image->HasKey("load_address")) {
+ addr_t val = image->GetValueForKey("load_address")
+ ->GetUnsignedIntegerValue(LLDB_INVALID_ADDRESS);
+ if (val != LLDB_INVALID_ADDRESS)
+ load_addresses.push_back(val);
+ }
+ }
+ AddBinaries(load_addresses);
}
}
@@ -413,26 +440,44 @@ void DynamicLoaderMacOS::AddBinaries(
Log *log = GetLog(LLDBLog::DynamicLoader);
ImageInfo::collection image_infos;
- LLDB_LOGF(log, "Adding %" PRId64 " modules.",
- (uint64_t)load_addresses.size());
- StructuredData::ObjectSP binaries_info_sp =
- m_process->GetLoadedDynamicLibrariesInfos(load_addresses);
- if (binaries_info_sp.get() && binaries_info_sp->GetAsDictionary() &&
- binaries_info_sp->GetAsDictionary()->HasKey("images") &&
- binaries_info_sp->GetAsDictionary()
- ->GetValueForKey("images")
- ->GetAsArray() &&
- binaries_info_sp->GetAsDictionary()
- ->GetValueForKey("images")
- ->GetAsArray()
- ->GetSize() == load_addresses.size()) {
- if (JSONImageInformationIntoImageInfo(binaries_info_sp, image_infos)) {
- auto images = PreloadModulesFromImageInfos(image_infos);
- UpdateSpecialBinariesFromPreloadedModules(images);
- AddModulesUsingPreloadedModules(images);
+ // For now, hardcode a limit of fetching 600 binaries at once.
+ // Fetching the full binary information for a large number of
+ // binaries can cause debugserver to use too much memory on
+ // memory-limited environments, and get killed.
+ const size_t image_fetch_max = 600;
+ size_t fetched = 0;
+ size_t total_image_size = load_addresses.size();
+ while (fetched < total_image_size) {
+ size_t this_fetch_amt =
+ std::min(image_fetch_max, total_image_size - fetched);
+ std::vector<addr_t> fetch_binaries(load_addresses.begin() + fetched,
+ load_addresses.begin() + fetched +
+ this_fetch_amt);
+
+ LLDB_LOGF(log, "Adding %" PRId64 " modules.",
+ (uint64_t)fetch_binaries.size());
+ image_infos.clear();
+ StructuredData::ObjectSP binaries_info_sp =
+ m_process->GetLoadedDynamicLibrariesInfos(eBinaryInformationLevelFull,
+ fetch_binaries);
+ if (binaries_info_sp && binaries_info_sp->GetAsDictionary() &&
+ binaries_info_sp->GetAsDictionary()->HasKey("images") &&
+ binaries_info_sp->GetAsDictionary()
+ ->GetValueForKey("images")
+ ->GetAsArray()) {
+ StructuredData::Array *images = binaries_info_sp->GetAsDictionary()
+ ->GetValueForKey("images")
+ ->GetAsArray();
+ if (images->GetSize() == fetch_binaries.size() &&
+ JSONImageInformationIntoImageInfo(binaries_info_sp, image_infos)) {
+ auto new_images = PreloadModulesFromImageInfos(image_infos);
+ UpdateSpecialBinariesFromPreloadedModules(new_images);
+ AddModulesUsingPreloadedModules(new_images);
+ }
}
- m_dyld_image_infos_stop_id = m_process->GetStopID();
+ fetched += this_fetch_amt;
}
+ m_dyld_image_infos_stop_id = m_process->GetStopID();
}
// Dump the _dyld_all_image_infos members and all current image infos that we
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 1ae0aeeba55f9..07ef71917f771 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -4212,15 +4212,38 @@ StructuredData::ObjectSP ProcessGDBRemote::GetLoadedDynamicLibrariesInfos(
return GetLoadedDynamicLibrariesInfos_sender(args_dict);
}
-StructuredData::ObjectSP ProcessGDBRemote::GetLoadedDynamicLibrariesInfos() {
+static std::string
+BinaryInformationLevelToJSONKey(BinaryInformationLevel info_level) {
+ std::string info_level_str;
+ if (info_level == eBinaryInformationLevelAddrOnly)
+ info_level_str = "address-only";
+ else if (info_level == eBinaryInformationLevelAddrName)
+ info_level_str = "address-name";
+ else if (info_level == eBinaryInformationLevelAddrNameUUID)
+ info_level_str = "address-name-uuid";
+ else if (info_level == eBinaryInformationLevelFull)
+ info_level_str = "full";
+
+ return info_level_str;
+}
+
+StructuredData::ObjectSP ProcessGDBRemote::GetLoadedDynamicLibrariesInfos(
+ BinaryInformationLevel info_level) {
StructuredData::ObjectSP args_dict(new StructuredData::Dictionary());
args_dict->GetAsDictionary()->AddBooleanItem("fetch_all_solibs", true);
+ if (info_level != eBinaryInformationLevelFull)
+ args_dict->GetAsDictionary()->AddBooleanItem("report_load_commands", false);
+ std::string info_level_str = BinaryInformationLevelToJSONKey(info_level);
+ if (!info_level_str.empty())
+ args_dict->GetAsDictionary()->AddStringItem("information-level",
+ info_level_str.c_str());
return GetLoadedDynamicLibrariesInfos_sender(args_dict);
}
StructuredData::ObjectSP ProcessGDBRemote::GetLoadedDynamicLibrariesInfos(
+ BinaryInformationLevel info_level,
const std::vector<lldb::addr_t> &load_addresses) {
StructuredData::ObjectSP args_dict(new StructuredData::Dictionary());
StructuredData::ArraySP addresses(new StructuredData::Array);
@@ -4230,6 +4253,11 @@ StructuredData::ObjectSP ProcessGDBRemote::GetLoadedDynamicLibrariesInfos(
args_dict->GetAsDictionary()->AddItem("solib_addresses", addresses);
+ std::string info_level_str = BinaryInformationLevelToJSONKey(info_level);
+ if (!info_level_str.empty())
+ args_dict->GetAsDictionary()->AddStringItem("information-level",
+ info_level_str.c_str());
+
return GetLoadedDynamicLibrariesInfos_sender(args_dict);
}
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
index 434c4f29201e5..fc3b0c0f513d9 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -233,9 +233,11 @@ class ProcessGDBRemote : public Process,
ConfigureStructuredData(llvm::StringRef type_name,
const StructuredData::ObjectSP &config_sp) override;
- StructuredData::ObjectSP GetLoadedDynamicLibrariesInfos() override;
+ StructuredData::ObjectSP GetLoadedDynamicLibrariesInfos(
+ lldb::BinaryInformationLevel info_level) override;
StructuredData::ObjectSP GetLoadedDynamicLibrariesInfos(
+ lldb::BinaryInformationLevel info_level,
const std::vector<lldb::addr_t> &load_addresses) override;
StructuredData::ObjectSP
diff --git a/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp b/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
index b1327964bb69a..b8e2e4933bcc7 100644
--- a/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
+++ b/lldb/source/Plugins/Process/scripted/ScriptedProcess.cpp
@@ -420,7 +420,8 @@ bool ScriptedProcess::GetProcessInfo(ProcessInstanceInfo &info) {
}
lldb_private::StructuredData::ObjectSP
-ScriptedProcess::GetLoadedDynamicLibrariesInfos() {
+ScriptedProcess::GetLoadedDynamicLibrariesInfos(
+ BinaryInformationLevel info_level) {
Status error;
auto error_with_message = [&error](llvm::StringRef message) {
return ScriptedInterface::ErrorWithMessage<bool>(LLVM_PRETTY_FUNCTION,
diff --git a/lldb/source/Plugins/Process/scripted/ScriptedProcess.h b/lldb/source/Plugins/Process/scripted/ScriptedProcess.h
index dad4e6f1e61fe..8371180734217 100644
--- a/lldb/source/Plugins/Process/scripted/ScriptedProcess.h
+++ b/lldb/source/Plugins/Process/scripted/ScriptedProcess.h
@@ -84,8 +84,8 @@ class ScriptedProcess : public Process {
bool GetProcessInfo(ProcessInstanceInfo &info) override;
- lldb_private::StructuredData::ObjectSP
- GetLoadedDynamicLibrariesInfos() override;
+ lldb_private::StructuredData::ObjectSP GetLoadedDynamicLibrariesInfos(
+ lldb::BinaryInformationLevel info_level) override;
lldb_private::StructuredData::DictionarySP GetMetadata() override;
@@ -98,7 +98,8 @@ class ScriptedProcess : public Process {
// dictionary before emitting the private stop event to avoid having the
// module loading happen while the process state is changing.
if (StateIsStoppedState(state, true))
- GetLoadedDynamicLibrariesInfos();
+ GetLoadedDynamicLibrariesInfos(
+ lldb::BinaryInformationLevel::eBinaryInformationLevelFull);
SetPrivateState(state);
}
diff --git a/lldb/tools/debugserver/source/DNB.cpp b/lldb/tools/debugserver/source/DNB.cpp
index 4d5afcf93a44b..86d7fa0a81647 100644
--- a/lldb/tools/debugserver/source/DNB.cpp
+++ b/lldb/tools/debugserver/source/DNB.cpp
@@ -1080,20 +1080,23 @@ DNBGetMainBinaryCPUTypes(nub_process_t pid) {
}
JSONGenerator::ObjectSP
-DNBGetAllLoadedLibrariesInfos(nub_process_t pid, bool report_load_commands) {
+DNBGetAllLoadedLibrariesInfos(nub_process_t pid,
+ DNBBinaryInformationLevel info_level) {
MachProcessSP procSP;
if (GetProcessSP(pid, procSP)) {
- return procSP->GetAllLoadedLibrariesInfos(pid, report_load_commands);
+ return procSP->GetAllLoadedLibrariesInfos(pid, info_level);
}
return JSONGenerator::ObjectSP();
}
JSONGenerator::ObjectSP
DNBGetLibrariesInfoForAddresses(nub_process_t pid,
+ DNBBinaryInformationLevel info_level,
std::vector<uint64_t> &macho_addresses) {
MachProcessSP procSP;
if (GetProcessSP(pid, procSP)) {
- return procSP->GetLibrariesInfoForAddresses(pid, macho_addresses);
+ return procSP->GetLibrariesInfoForAddresses(pid, info_level,
+ macho_addresses);
}
return JSONGenerator::ObjectSP();
}
diff --git a/lldb/tools/debugserver/source/DNB.h b/lldb/tools/debugserver/source/DNB.h
index 1f3d5392c588f..007d8d812e115 100644
--- a/lldb/tools/debugserver/source/DNB.h
+++ b/lldb/tools/debugserver/source/DNB.h
@@ -216,13 +216,14 @@ DNBGetTSDAddressForThread(nub_process_t pid, nub_thread_t tid,
std::optional<std::pair<cpu_type_t, cpu_subtype_t>>
DNBGetMainBinaryCPUTypes(nub_process_t pid);
JSONGenerator::ObjectSP
-DNBGetAllLoadedLibrariesInfos(nub_process_t pid, bool report_load_commands);
+DNBGetAllLoadedLibrariesInfos(nub_process_t pid,
+ DNBBinaryInformationLevel info_level);
JSONGenerator::ObjectSP
DNBGetLibrariesInfoForAddresses(nub_process_t pid,
+ DNBBinaryInformationLevel info_level,
std::vector<uint64_t> &macho_addresses);
JSONGenerator::ObjectSP DNBGetSharedCacheInfo(nub_process_t pid);
-//
// Breakpoint functions
nub_bool_t DNBBreakpointSet(nub_process_t pid, nub_addr_t addr, nub_size_t size,
nub_bool_t hardware);
diff --git a/lldb/tools/debugserver/source/DNBDefs.h b/lldb/tools/debugserver/source/DNBDefs.h
index d98399aed5e19..780b045f9bde7 100644
--- a/lldb/tools/debugserver/source/DNBDefs.h
+++ b/lldb/tools/debugserver/source/DNBDefs.h
@@ -392,6 +392,13 @@ enum DNBProfileDataScanType {
eProfileAll = 0xffffffff
};
+enum DNBBinaryInformationLevel {
+ eBinaryInformationLevelAddrOnly,
+ eBinaryInformationLevelAddrName,
+ eBinaryInformationLevelAddrNameUUID,
+ eBinaryInformationLevelFull
+};
+
typedef nub_addr_t (*DNBCallbackNameToAddress)(nub_process_t pid,
const char *name,
const char *shlib_regex,
diff --git a/lldb/tools/debugserver/source/MacOSX/MachProcess.h b/lldb/tools/debugserver/source/MacOSX/MachProcess.h
index e4749f28106a6..43852801a8169 100644
--- a/lldb/tools/debugserver/source/MacOSX/MachProcess.h
+++ b/lldb/tools/debugserver/source/MacOSX/MachProcess.h
@@ -265,7 +265,7 @@ class MachProcess {
struct mach_o_information &inf);
JSONGenerator::ObjectSP FormatDynamicLibrariesIntoJSON(
const std::vector<struct binary_image_information> &image_infos,
- bool report_load_commands);
+ DNBBinaryInformationLevel info_level);
uint32_t GetPlatform();
/// Get the runtime platform from DYLD via SPI.
uint32_t GetProcessPlatformViaDYLDSPI();
@@ -279,10 +279,11 @@ class MachProcess {
std::vector<struct binary_image_information> &image_infos);
JSONGenerator::ObjectSP
GetLibrariesInfoForAddresses(nub_process_t pid,
+ DNBBinaryInformationLevel info_level,
std::vector<uint64_t> &macho_addresses);
JSONGenerator::ObjectSP
GetAllLoadedLibrariesInfos(nub_process_t pid,
- bool fetch_report_load_commands);
+ DNBBinaryInformationLevel info_level);
bool GetDebugserverSharedCacheInfo(uuid_t &uuid,
std::string &shared_cache_path);
bool GetInferiorSharedCacheFilepathAndSize(std::string &inferior_sc_path,
diff --git a/lldb/tools/debugserver/source/MacOSX/MachProcess.mm b/lldb/tools/debugserver/source/MacOSX/MachProcess.mm
index dce86d479bb7a..b2be3636bcce8 100644
--- a/lldb/tools/debugserver/source/MacOSX/MachProcess.mm
+++ b/lldb/tools/debugserver/source/MacOSX/MachProcess.mm
@@ -953,7 +953,7 @@ static bool mach_header_validity_test(uint32_t magic, uint32_t cputype) {
// with all the details we want to send to lldb.
JSONGenerator::ObjectSP MachProcess::FormatDynamicLibrariesIntoJSON(
const std::vector<struct binary_image_information> &image_infos,
- bool report_load_commands) {
+ DNBBinaryInformationLevel info_level) {
JSONGenerator::ArraySP image_infos_array_sp(new JSONGenerator::Array());
@@ -963,19 +963,20 @@ static bool mach_header_validity_test(uint32_t magic, uint32_t cputype) {
// If we should report the Mach-O header and load commands,
// and those were unreadable, don't report anything about this
// binary.
- if (report_load_commands && !image_infos[i].is_valid_mach_header)
+ if (info_level == eBinaryInformationLevelFull &&
+ !image_infos[i].is_valid_mach_header)
continue;
JSONGenerator::DictionarySP image_info_dict_sp(
new JSONGenerator::Dictionary());
image_info_dict_sp->AddIntegerItem("load_address",
image_infos[i].load_address);
- // TODO: lldb currently rejects a response without this, but it
- // is always zero from dyld. It can be removed once we've had time
- // for lldb's that require it to be present are obsolete.
- image_info_dict_sp->AddIntegerItem("mod_date", 0);
- image_info_dict_sp->AddStringItem("pathname", image_infos[i].filename);
+ if (info_level == eBinaryInformationLevelAddrOnly) {
+ image_infos_array_sp->AddItem(image_info_dict_sp);
+ continue;
+ }
- if (!report_load_commands) {
+ image_info_dict_sp->AddStringItem("pathname", image_infos[i].filename);
+ if (info_level == eBinaryInformationLevelAddrName) {
image_infos_array_sp->AddItem(image_info_dict_sp);
continue;
}
@@ -983,6 +984,10 @@ static bool mach_header_validity_test(uint32_t magic, uint32_t cputype) {
uuid_string_t uuidstr;
uuid_unparse_upper(image_infos[i].macho_info.uuid, uuidstr);
image_info_dict_sp->AddStringItem("uuid", uuidstr);
+ if (info_level == eBinaryInformationLevelAddrNameUUID) {
+ image_infos_array_sp->AddItem(image_info_dict_sp);
+ continue;
+ }
if (!image_infos[i].macho_info.min_version_os_name.empty() &&
!image_infos[i].macho_info.min_version_os_version.empty()) {
@@ -1119,12 +1124,12 @@ static bool mach_header_validity_test(uint32_t magic, uint32_t cputype) {
// macOS 10.12, iOS 10, tvOS 10, watchOS 3 and newer.
JSONGenerator::ObjectSP
MachProcess::GetAllLoadedLibrariesInfos(nub_process_t pid,
- bool report_load_commands) {
+ DNBBinaryInformationLevel info_level) {
int pointer_size = GetInferiorAddrSize(pid);
std::vector<struct binary_image_information> image_infos;
GetAllLoadedBinariesViaDYLDSPI(image_infos);
- if (report_load_commands) {
+ if (info_level == eBinaryInformationLevelFull) {
uint32_t platform = GetPlatform();
const size_t image_count = image_infos.size();
for (size_t i = 0; i < image_count; i++) {
@@ -1135,7 +1140,7 @@ static bool mach_header_validity_test(uint32_t magic, uint32_t cputype) {
}
}
}
- return FormatDynamicLibrariesIntoJSON(image_infos, report_load_commands);
+ return FormatDynamicLibrariesIntoJSON(image_infos, info_level);
}
std::optional<std::pair<cpu_type_t, cpu_subtype_t>>
@@ -1159,7 +1164,8 @@ static bool mach_header_validity_test(uint32_t magic, uint32_t cputype) {
// using the
// dyld SPIs that exist in macOS 10.12, iOS 10, tvOS 10, watchOS 3 and newer.
JSONGenerator::ObjectSP MachProcess::GetLibrariesInfoForAddresses(
- nub_process_t pid, std::vector<uint64_t> &macho_addresses) {
+ nub_process_t pid, DNBBinaryInformationLevel info_level,
+ std::vector<uint64_t> &macho_addresses) {
int pointer_size = GetInferiorAddrSize(pid);
@@ -1202,8 +1208,7 @@ static bool mach_header_validity_test(uint32_t magic, uint32_t cputype) {
image_infos[i].is_valid_mach_header = true;
}
}
- return FormatDynamicLibrariesIntoJSON(image_infos,
- /* report_load_commands = */ true);
+ return FormatDynamicLibrariesIntoJSON(image_infos, info_level);
}
bool MachProcess::GetDebugserverSharedCacheInfo(
diff --git a/lldb/tools/debugserver/source/RNBRemote.cpp b/lldb/tools/debugserver/source/RNBRemote.cpp
index 11b93710444f2..57ffbc08d2590 100644
--- a/lldb/tools/debugserver/source/RNBRemote.cpp
+++ b/lldb/tools/debugserver/source/RNBRemote.cpp
@@ -5424,6 +5424,53 @@ get_integer_value_for_key_name_from_json(const char *key,
// Returns true if it was able to find the key name, and sets the 'value'
// argument to the value found.
+static bool get_string_value_for_key_name_from_json(const char *key,
+ const char *json_string,
+ std::string &value) {
+ value.clear();
+ std::string key_with_quotes = "\"";
+ key_with_quotes += key;
+ key_with_quotes += "\"";
+ const char *c = strstr(json_string, key_with_quotes.c_str());
+ if (!c)
+ return false;
+
+ c += key_with_quotes.size();
+
+ while (*c != '\0' && (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r'))
+ c++;
+
+ if (*c == ':') {
+ c++;
+
+ while (*c != '\0' && (*c == ' ' || *c == '\t' || *c == '\n' || *c == '\r'))
+ c++;
+
+ if (*c == '\0')
+ return false;
+
+ bool escaped_char = false;
+ while (*++c != '\0') {
+ if (escaped_char) {
+ value += *c;
+ escaped_char = false;
+ continue;
+ }
+ if (*c == '\\') {
+ value += *c;
+ escaped_char = true;
+ continue;
+ }
+ if (*c == '"')
+ break;
+
+ value += *c;
+ }
+ return true;
+ }
+ return false;
+}
+
static bool get_boolean_value_for_key_name_from_json(const char *key,
const char *json_string,
bool &value) {
@@ -6015,14 +6062,31 @@ RNBRemote::HandlePacket_jGetLoadedDynamicLibrariesInfos(const char *p) {
bool report_load_commands = true;
get_boolean_value_for_key_name_from_json("report_load_commands", p,
report_load_commands);
+ DNBBinaryInformationLevel info_level = eBinaryInformationLevelFull;
+ if (!report_load_commands)
+ info_level = eBinaryInformationLevelAddrOnly;
+
+ std::string level_str;
+ if (get_string_value_for_key_name_from_json("information-level", p,
+ level_str)) {
+ if (level_str == "address-only")
+ info_level = eBinaryInformationLevelAddrOnly;
+ else if (level_str == "address-name")
+ info_level = eBinaryInformationLevelAddrName;
+ else if (level_str == "address-name-uuid")
+ info_level = eBinaryInformationLevelAddrNameUUID;
+ else if (level_str == "full")
+ info_level = eBinaryInformationLevelFull;
+ }
if (get_boolean_value_for_key_name_from_json("fetch_all_solibs", p,
fetch_all_solibs) &&
fetch_all_solibs) {
- json_sp = DNBGetAllLoadedLibrariesInfos(pid, report_load_commands);
+ json_sp = DNBGetAllLoadedLibrariesInfos(pid, info_level);
} else if (get_array_of_ints_value_for_key_name_from_json(
"solib_addresses", p, macho_addresses)) {
- json_sp = DNBGetLibrariesInfoForAddresses(pid, macho_addresses);
+ json_sp =
+ DNBGetLibrariesInfoForAddresses(pid, info_level, macho_addresses);
}
if (json_sp.get()) {
More information about the lldb-commits
mailing list