[Lldb-commits] [lldb] [lldb][Darwin] debugserver expedite new binary info, lldb use (PR #192754)

via lldb-commits lldb-commits at lists.llvm.org
Fri Apr 17 16:47:29 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lldb

Author: Jason Molenda (jasonmolenda)

<details>
<summary>Changes</summary>

When lldb stops at the "new binaries loaded" internal breakpoint, it must read the list of addresses of the new binaries out of process memory, then send a jGetLoadedDynamicLibrariesInfos packet to debugserver to get the filepath, uuid, and addresses of where all the segments are loaded in memory.  It is possible for debugserver to independently find the address of the "new binaries loaded" function in dyld in the inferior, and tell when it is stopped at that breakpoint.  Finding the number of binaries, and the address of the binaries, is a simple matter of looking at the argument registers.

This PR reduces the packet traffic for a new binary load notifications by

1. When debugserver sees a thread that has hit a breakpoint, and the pc matches the new-binaries-loaded function address, reads the list of binaries that have been newly added and includes them in the stop info packet (or the jThreadsInfo packet) in the `added-binaries` key. The value is a list (array) of binary addresses.

2. If the number of binaries is small (today: one), debugserver may collect the full information that jGetLoadedDynamicLibrariesInfos would send back about it, and also expedite that in the stop info packet (or jThreadsInfo) if the same conditions are met.  The stop info packet is a semicolon separated series of key-values, and the JSON string may contain a semicolon or one of the other gdb remote special characters, so it is included in asciihex format, just like the jstopinfo key that we already send in the stop packet.  In the jThreadsInfo packet, the JSON for the binary information is included in the response as-is.

3. If debugserver isn't given the newly-added-binaries, we will use the same process as before.  However, in
DynamicLoaderMacOS::NotifyBreakpointHit I was reading the load addresses out of memory individually, with each binary having a 24-byte entry.  lldb's memory cache meant we read 512 bytes per 8-byte read, but when 1000 binaries were being loaded at process launch time, that was 24,000 bytes of VM that we would read in 512 byte batches.  This patch changes that to read the entire VM range that we will be accessing in a large memory read (as large as the remote gdb RSP stub will support), dramatically reducing packet traffic in that case.

4. debugserver needs to read the "new binaries loaded" function pointer out of the "dyld_all_image_infos" structure in the inferior, and it is a signed function pointer on arm64e processes, so debugserver needs to strip off the signing bits before comparing the pc.  I hoisted the strip function out of DNBArchImplArm64.cpp into DNBFixAddress(), and the only complicated bit here is in DNBProcessAddrSize(), when an arm64e debugserver is debugging an arm64_32 process on a watch.  It's not a common combination (mostly we will have arm64e debugservers debugging arm64 processes, or arm64_32 debugservers debuggging arm64_32 processe) but it is supported.

5. A very minor enhancement, I have debugserver now include `sizeof_mh_and_loadcmds` in the full binary information that jGetLoadedDynamicLibrariesInfos returns.  When lldb needs to read a binary out of memory, it needs to start by reading the mach header & load commands, and it doesn't know the full size of that, so we end up doing one read of the mach header, then the header + load commands.  I'm not using this information in lldb yet, but I would like to, to improve that.

At an implementation detail level, ProcessGDBRemote collects these two new data from the stop packet / jThreadsInfo, and passes them to the method that creates a new ThreadGDBRemote.  I added two methods to the Thread base class to retrieve the information, if it has been set.  DynamicLoaderMacOS tries to read them from the thread that hit the "new binaries loaded" breakpoint, and if the number of entries matches the number expected by the register values, uses them.  Else it falls back to fetching them the traditional way.  On an old debugserver that doesn't support these new expedited fields, DynamicLoaderMacOS will get back a zero-length of binary addresses and a null StructuredData dictionary for the detailed image information, and behave as it always does.  I tested this patch with both the debugserver changes, and without.

Testing is clearly the big questionmark here - I added none.  While writing these patches, I had some bugs and the lldb testsuite on macOS was very good at finding them, simply with our normal process launching and dlopen'ing in our existing API tests.  I could imagine a test that would capture the packet log and try to ensure that the expedited information is being used by lldb and we are not re-fetching the information, though.

rdar://175033129

---

Patch is 41.24 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/192754.diff


14 Files Affected:

- (modified) lldb/docs/resources/lldbgdbremote.md (+44-6) 
- (modified) lldb/include/lldb/Target/Thread.h (+15) 
- (modified) lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp (+67-26) 
- (modified) lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.h (+3-1) 
- (modified) lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp (+68-9) 
- (modified) lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h (+3-1) 
- (modified) lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp (+18) 
- (modified) lldb/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h (+9) 
- (modified) lldb/tools/debugserver/source/DNB.cpp (+162) 
- (modified) lldb/tools/debugserver/source/DNB.h (+7) 
- (modified) lldb/tools/debugserver/source/JSONGenerator.h (+13) 
- (modified) lldb/tools/debugserver/source/MacOSX/MachProcess.mm (+4) 
- (modified) lldb/tools/debugserver/source/MacOSX/arm64/DNBArchImplARM64.cpp (+14-37) 
- (modified) lldb/tools/debugserver/source/RNBRemote.cpp (+55-2) 


``````````diff
diff --git a/lldb/docs/resources/lldbgdbremote.md b/lldb/docs/resources/lldbgdbremote.md
index 9aa7ad2259a6a..4254a2aba6633 100644
--- a/lldb/docs/resources/lldbgdbremote.md
+++ b/lldb/docs/resources/lldbgdbremote.md
@@ -147,12 +147,28 @@ One requests information on all shared libraries:
 ```
 jGetLoadedDynamicLibrariesInfos:{"fetch_all_solibs":true}
 ```
-with an optional `"report_load_commands":false` which can be added, asking
-that only the dyld SPI information (load addresses, filenames) be returned.
-The default behavior is that debugserver scans the mach-o header and load
-commands of each binary, and returns it in the JSON reply.
 
-And the second requests information about a list of shared libraries, given their load addresses:
+There are two additional keys that can be specified: the older
+`"report_load_commands":false` which specifies that the detailed
+information about the binary should not be included (the Mach-O
+header and load commands), and the newer key that supplants
+`report_load_commands`, `information-level` which takes a string
+argument that is one of `address-only`, `address-name`,
+`address-name-uuid`, `full`.
+
+`"report_load_commands":false` is equivalent to
+`"information-level":"address-only" or so.
+
+`information-level` allows the caller to limit the amount of data
+being returned to one of (address, address+name, address+name+uuid,
+full).  When we first attach to a process, we may want to fetch the
+binary addresses for all binaries loaded in the process, and then
+fetch detailed information in batches, to keep the size of the
+packets from becoming too large.
+
+
+And the second form of jGetLoadedDynamicLibrariesInfos 
+requests information about a list of binaries, given their load addresses:
 ```
 jGetLoadedDynamicLibrariesInfos:{"solib_addresses":[8382824135,3258302053,830202858503]}
 ```
@@ -727,10 +743,19 @@ server to expedite memory that the client is likely to use (e.g., areas around t
 stack pointer, which are needed for computing backtraces) and it reduces the packet
 count.
 
+When a thread has hit the binaries-loaded lldb internal breakpoint
+(if it can detect that), it may expedite information about the
+binaries that have been loaded, to reduce packet traffic that would
+immediately follow.  The key `added-binaries` will have a value of
+an array of binary addresses.  The key `detailed-binaries-info`
+will have a value of a JSON dictionary which is the reply that
+`jGetLoadedDynamicLibrariesInfos` would return for these binaries,
+so lldb doesn't need to request it.
+
 On macOS with debugserver, we expedite the frame pointer backchain for a thread
 (up to 256 entries) by reading 2 pointers worth of bytes at the frame pointer (for
 the previous FP and PC), and follow the backchain. Most backtraces on macOS and
-iOS now don't require us to read any memory!
+iOS now don't require us to read any memory.
 
 **Priority To Implement:** Low
 
@@ -2243,6 +2268,19 @@ following keys and values:
   Specifies how many bits in addresses in high memory are significant for
   addressing, base 10.  AArch64 can have different page table setups for low and
   high memory, and therefore a different number of bits used for addressing.
+* `added-binaries` when the remote stub knows that a thread has stopped
+  at a binaries-loaded breakpoint notification, and it can retrieve the list
+  of binaries that have just been loaded, it may send the list of base16
+  addresses (no 0x prefix) for all of the binaries, to save lldb the need
+  to read it from memory.
+* `detailed-binaries-info` when the remote stub knows that a thread
+  has stopped at a binaries-loaded breakpoint notification, it may
+  be able to gather detailed information about the newly loaded
+  binaries, the information jGetLoadedDynamicLibrariesInfos would
+  return.  If this key is present, the information for all binaries
+  being added at this stop are provided.  The value is asciihex
+  encoded JSON.  It must be asciihex encoded in case a filename
+  includes one of the gdb RSP packet metacharacters or a semicolon.
 
 ### Best Practices
 
diff --git a/lldb/include/lldb/Target/Thread.h b/lldb/include/lldb/Target/Thread.h
index 4353725ca47f6..7ca68227fdc66 100644
--- a/lldb/include/lldb/Target/Thread.h
+++ b/lldb/include/lldb/Target/Thread.h
@@ -1185,6 +1185,21 @@ class Thread : public std::enable_shared_from_this<Thread>,
                              uint32_t num_frames, bool show_frame_info,
                              uint32_t num_frames_with_source, bool show_hidden);
 
+  /// If this thread stopped on a binary-loaded breakpoint, the
+  /// addresses of the newly added binaries may have already been
+  /// provided by the gdb stub in the stop-packet.
+  virtual std::vector<lldb::addr_t> FetchNewlyAddedBinaries() { return {}; }
+
+  /// If this thread stopped on a binary-loaded breakpoint, the
+  /// detailed information about the new binaries may be provided.
+  /// If any detailed information about binaries is provided, it must
+  /// be provided for all binaries that have been loaded at this stop.
+  /// Detailed information is likely to only be provided when the number
+  /// of new binaries is small.
+  virtual lldb_private::StructuredData::ObjectSP FetchDetailedBinariesInfo() {
+    return {};
+  }
+
   // We need a way to verify that even though we have a thread in a shared
   // pointer that the object itself is still valid. Currently this won't be the
   // case if DestroyThread() was called. DestroyThread is called when a thread
diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp
index ad97485373351..73ae06300d135 100644
--- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp
+++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.cpp
@@ -245,7 +245,7 @@ void DynamicLoaderMacOS::DoInitialImageFetch() {
             load_addresses.push_back(val);
         }
       }
-      AddBinaries(load_addresses);
+      AddBinaries(load_addresses, /*expedited_binary_infos=*/{});
     }
   }
 
@@ -326,7 +326,8 @@ bool DynamicLoaderMacOS::NotifyBreakpointHit(void *baton,
     argument_values.PushValue(count_value);
     argument_values.PushValue(headers_value);
 
-    if (abi->GetArgumentValues(exe_ctx.GetThreadRef(), argument_values)) {
+    Thread &thread = exe_ctx.GetThreadRef();
+    if (abi->GetArgumentValues(thread, argument_values)) {
       uint32_t dyld_mode =
           argument_values.GetValueAtIndex(0)->GetScalar().UInt(-1);
       if (dyld_mode != static_cast<uint32_t>(-1)) {
@@ -349,21 +350,39 @@ bool DynamicLoaderMacOS::NotifyBreakpointHit(void *baton,
             //
             // and we only need the imageLoadAddress fields.
 
-            const int addrsize =
-                process->GetTarget().GetArchitecture().GetAddressByteSize();
-            for (uint64_t i = 0; i < image_infos_count; i++) {
-              Status error;
-              addr_t dyld_image_info = header_array + (addrsize * 3 * i);
-              addr_t addr =
-                  process->ReadPointerFromMemory(dyld_image_info, error);
-              if (error.Success()) {
-                image_load_addresses.push_back(addr);
-              } else {
+            // The remote stub may have provided the addresses in the
+            // stop packet already.
+            image_load_addresses = thread.FetchNewlyAddedBinaries();
+            // Or, read them from memory.
+            if (image_load_addresses.size() != image_infos_count) {
+              image_load_addresses.clear();
+              ArchSpec target_arch = process->GetTarget().GetArchitecture();
+              const int addrsize = target_arch.GetAddressByteSize();
+              // Read the entire block of memory that we'll need to
+              // iterate over in one large read, to minimize packets sent.
+              WritableDataBufferSP buffer_sp = std::make_shared<DataBufferHeap>(
+                  addrsize * 3 * image_infos_count, 0);
+              Status read_error;
+              if (process->ReadMemory(header_array, buffer_sp->GetBytes(),
+                                      buffer_sp->GetByteSize(),
+                                      read_error) == buffer_sp->GetByteSize() &&
+                  read_error.Success()) {
+                DataExtractor added_binaries(
+                    buffer_sp, target_arch.GetByteOrder(), addrsize);
+
+                offset_t offset = 0;
+                for (uint64_t i = 0; i < image_infos_count; i++) {
+                  Status error;
+                  addr_t addr = added_binaries.GetAddress(&offset);
+                  image_load_addresses.push_back(addr);
+                  offset += 2 * addrsize;
+                }
+              }
+              if (!read_error.Success())
                 Debugger::ReportWarning(
                     "DynamicLoaderMacOS::NotifyBreakpointHit unable "
                     "to read binary mach-o load address at 0x%" PRIx64,
-                    addr);
-              }
+                    header_array);
             }
             if (dyld_mode == 0) {
               // dyld_notify_adding
@@ -381,7 +400,8 @@ bool DynamicLoaderMacOS::NotifyBreakpointHit(void *baton,
                 dyld_instance->DoInitialImageFetch();
                 dyld_instance->SetNotificationBreakpoint();
               } else {
-                dyld_instance->AddBinaries(image_load_addresses);
+                dyld_instance->AddBinaries(image_load_addresses,
+                                           thread.FetchDetailedBinariesInfo());
               }
             } else if (dyld_mode == 1) {
               // dyld_notify_removing
@@ -435,10 +455,39 @@ bool DynamicLoaderMacOS::NotifyBreakpointHit(void *baton,
   return dyld_instance->GetStopWhenImagesChange();
 }
 
+static size_t library_infos_count(StructuredData::ObjectSP binaries_info_sp) {
+  if (binaries_info_sp && binaries_info_sp->GetAsDictionary() &&
+      binaries_info_sp->GetAsDictionary()->HasKey("images") &&
+      binaries_info_sp->GetAsDictionary()
+          ->GetValueForKey("images")
+          ->GetAsArray())
+    return binaries_info_sp->GetAsDictionary()
+        ->GetValueForKey("images")
+        ->GetAsArray()
+        ->GetSize();
+
+  return 0;
+}
+
 void DynamicLoaderMacOS::AddBinaries(
-    const std::vector<lldb::addr_t> &load_addresses) {
+    const std::vector<lldb::addr_t> &load_addresses,
+    StructuredData::ObjectSP expedited_binary_infos) {
   Log *log = GetLog(LLDBLog::DynamicLoader);
   ImageInfo::collection image_infos;
+  if (load_addresses.size() == 0)
+    return;
+
+  // If the expedited detailed binaries information covers
+  // all of the newly added binaries, use that info and
+  // return.
+  if (library_infos_count(expedited_binary_infos) == load_addresses.size() &&
+      JSONImageInformationIntoImageInfo(expedited_binary_infos, image_infos)) {
+    auto new_images = PreloadModulesFromImageInfos(image_infos);
+    UpdateSpecialBinariesFromPreloadedModules(new_images);
+    AddModulesUsingPreloadedModules(new_images);
+    m_dyld_image_infos_stop_id = m_process->GetStopID();
+    return;
+  }
 
   // For now, hardcode a limit of fetching 600 binaries at once.
   // Fetching the full binary information for a large number of
@@ -460,16 +509,8 @@ void DynamicLoaderMacOS::AddBinaries(
     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)) {
+    if (library_infos_count(binaries_info_sp) == fetch_binaries.size()) {
+      if (JSONImageInformationIntoImageInfo(binaries_info_sp, image_infos)) {
         auto new_images = PreloadModulesFromImageInfos(image_infos);
         UpdateSpecialBinariesFromPreloadedModules(new_images);
         AddModulesUsingPreloadedModules(new_images);
diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.h b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.h
index d40ca3f23dbc6..ea456b8ff3b1d 100644
--- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.h
+++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOS.h
@@ -77,7 +77,9 @@ class DynamicLoaderMacOS : public lldb_private::DynamicLoaderDarwin {
 
   void ClearDYLDHandoverBreakpoint();
 
-  void AddBinaries(const std::vector<lldb::addr_t> &load_addresses);
+  void
+  AddBinaries(const std::vector<lldb::addr_t> &load_addresses,
+              lldb_private::StructuredData::ObjectSP expedited_binary_infos);
 
   void DoClear() override;
 
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 07ef71917f771..3cbc8a31ac788 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -1770,7 +1770,9 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(
     bool queue_vars_valid, // Set to true if queue_name, queue_kind and
                            // queue_serial are valid
     LazyBool associated_with_dispatch_queue, addr_t dispatch_queue_t,
-    std::string &queue_name, QueueKind queue_kind, uint64_t queue_serial) {
+    std::string &queue_name, QueueKind queue_kind, uint64_t queue_serial,
+    std::vector<lldb::addr_t> &added_binaries,
+    StructuredData::ObjectSP &detailed_binaries_info) {
 
   if (tid == LLDB_INVALID_THREAD_ID)
     return nullptr;
@@ -1828,6 +1830,9 @@ ThreadSP ProcessGDBRemote::SetThreadStopInfo(
   if (dispatch_queue_t != LLDB_INVALID_ADDRESS)
     gdb_thread->SetQueueLibdispatchQueueAddress(dispatch_queue_t);
 
+  gdb_thread->SetNewlyAddedBinaries(added_binaries);
+  gdb_thread->SetDetailedBinariesInfo(detailed_binaries_info);
+
   // Make sure we update our thread stop reason just once, but don't overwrite
   // the stop info for threads that haven't moved:
   StopInfoSP current_stop_info_sp = thread_sp->GetPrivateStopInfo(false);
@@ -2120,6 +2125,9 @@ ProcessGDBRemote::SetThreadStopInfo(StructuredData::Dictionary *thread_dict) {
   static constexpr llvm::StringLiteral g_key_memory("memory");
   static constexpr llvm::StringLiteral g_key_description("description");
   static constexpr llvm::StringLiteral g_key_signal("signal");
+  static constexpr llvm::StringLiteral g_added_binaries("added-binaries");
+  static constexpr llvm::StringLiteral g_detailed_binaries_info(
+      "detailed-binaries-info");
 
   // Stop with signal and thread info
   lldb::tid_t tid = LLDB_INVALID_THREAD_ID;
@@ -2137,6 +2145,8 @@ ProcessGDBRemote::SetThreadStopInfo(StructuredData::Dictionary *thread_dict) {
   std::string queue_name;
   QueueKind queue_kind = eQueueKindUnknown;
   uint64_t queue_serial_number = 0;
+  std::vector<addr_t> added_binaries;
+  StructuredData::ObjectSP detailed_binaries_info;
   // Iterate through all of the thread dictionary key/value pairs from the
   // structured data dictionary
 
@@ -2145,7 +2155,8 @@ ProcessGDBRemote::SetThreadStopInfo(StructuredData::Dictionary *thread_dict) {
                         &signo, &reason, &description, &exc_type, &exc_data,
                         &thread_dispatch_qaddr, &queue_vars_valid,
                         &associated_with_dispatch_queue, &dispatch_queue_t,
-                        &queue_name, &queue_kind, &queue_serial_number](
+                        &queue_name, &queue_kind, &queue_serial_number,
+                        &added_binaries, &detailed_binaries_info](
                            llvm::StringRef key,
                            StructuredData::Object *object) -> bool {
     if (key == g_key_tid) {
@@ -2244,17 +2255,43 @@ ProcessGDBRemote::SetThreadStopInfo(StructuredData::Dictionary *thread_dict) {
           return true; // Keep iterating through all array items
         });
       }
-
     } else if (key == g_key_signal)
       signo = object->GetUnsignedIntegerValue(LLDB_INVALID_SIGNAL_NUMBER);
+    else if (key == g_added_binaries) {
+      StructuredData::Array *array = object->GetAsArray();
+      if (array) {
+        array->ForEach([&added_binaries](
+                           StructuredData::Object *object) -> bool {
+          StructuredData::UnsignedInteger *addr =
+              object->GetAsUnsignedInteger();
+          if (addr) {
+            addr_t value = addr->GetUnsignedIntegerValue(LLDB_INVALID_ADDRESS);
+            if (value != LLDB_INVALID_ADDRESS)
+              added_binaries.push_back(value);
+          }
+          return true; // Keep iterating through all array items
+        });
+      }
+    } else if (key == g_detailed_binaries_info) {
+      // Get a string representation and then parse it into
+      // StructuredData to get a separate copy of this part of
+      // the response.  We only have an Object* here, not the
+      // original shared pointer, to increase the ref count.
+      if (object->GetAsDictionary()) {
+        StreamString json_str;
+        object->Dump(json_str);
+        detailed_binaries_info =
+            StructuredData::ParseJSON(json_str.GetString());
+      }
+    }
     return true; // Keep iterating through all dictionary key/value pairs
   });
 
-  return SetThreadStopInfo(tid, expedited_register_map, signo, thread_name,
-                           reason, description, exc_type, exc_data,
-                           thread_dispatch_qaddr, queue_vars_valid,
-                           associated_with_dispatch_queue, dispatch_queue_t,
-                           queue_name, queue_kind, queue_serial_number);
+  return SetThreadStopInfo(
+      tid, expedited_register_map, signo, thread_name, reason, description,
+      exc_type, exc_data, thread_dispatch_qaddr, queue_vars_valid,
+      associated_with_dispatch_queue, dispatch_queue_t, queue_name, queue_kind,
+      queue_serial_number, added_binaries, detailed_binaries_info);
 }
 
 StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) {
@@ -2286,6 +2323,8 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) {
     std::string thread_name;
     std::string reason;
     std::string description;
+    std::vector<addr_t> added_binaries;
+    StructuredData::ObjectSP detailed_binaries_info;
     uint32_t exc_type = 0;
     std::vector<addr_t> exc_data;
     addr_t thread_dispatch_qaddr = LLDB_INVALID_ADDRESS;
@@ -2456,6 +2495,25 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) {
         if (!value.getAsInteger(0, addressing_bits)) {
           addressable_bits.SetHighmemAddressableBits(addressing_bits);
         }
+      } else if (key == "added-binaries") {
+        // A comma separated list of all threads in the current
+        // process that includes the thread for this stop reply packet
+        lldb::addr_t pc;
+        while (!value.empty()) {
+          llvm::StringRef pc_str;
+          std::tie(pc_str, value) = value.split(',');
+          if (pc_str.getAsInteger(16, pc))
+            pc = LLDB_INVALID_ADDRESS;
+          added_binaries.push_back(pc);
+        }
+      } else if (key == "detailed-binaries-info") {
+        StringExtractor json_extractor(value);
+        std::string json;
+        // Now convert the HEX bytes into a string value
+        json_extractor.GetHexByteString(json);
+
+        // This JSON contains detailed information about binares.
+        detailed_binaries_info = StructuredData::ParseJSON(json);
       } else if (key.size() == 2 && ::isxdigit(key[0]) && ::isxdigit(key[1])) {
         uint32_t reg = UINT32_MAX;
         if (!key.getAsInteger(16, reg))
@@ -2492,7 +2550,8 @@ StateType ProcessGDBRemote::SetThreadStopInfo(StringExtractor &stop_packet) {
         tid, expedited_register_map, signo, thread_name, reason, de...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/192754


More information about the lldb-commits mailing list