Skip to content

[lldb][Darwin] Read Mach-O binaries out of memory more efficiently#200072

Merged
jasonmolenda merged 3 commits into
llvm:mainfrom
jasonmolenda:refine-memory-module-reading-packets
May 27, 2026
Merged

[lldb][Darwin] Read Mach-O binaries out of memory more efficiently#200072
jasonmolenda merged 3 commits into
llvm:mainfrom
jasonmolenda:refine-memory-module-reading-packets

Conversation

@jasonmolenda

Copy link
Copy Markdown
Contributor

When lldb needs to read a Mach-O binary out of memory, it first reads 512 bytes to get the mach header, which includes the size of the load commands, and then does a second read to get the mach header and load commands.

I am changing the initial read to get 3192 bytes, which will include the full load commands for most binaries.

In April I changed debugserver to return the correct size of the mach header and load commands in a sizeof_mh_and_loadcmds key. If this number is provided, refine the amount we read to this size.

This reduces the number of memory read packets we issue from 2 to 1 for a memory module, outside of packets that may be needed to get the symbol table.

When lldb needs to read a Mach-O binary out of memory, it first
reads 512 bytes to get the mach header, which includes the size
of the load commands, and then does a second read to get the
mach header and load commands.

I am changing the initial read to get 3192 bytes, which will
include the full load commands for most binaries.

In April I changed debugserver to return the correct size of
the mach header and load commands in a `sizeof_mh_and_loadcmds`
key.  If this number is provided, refine the amount we read
to this size.

This reduces the number of memory read packets we issue from
2 to 1 for a memory module, outside of packets that may be
needed to get the symbol table.
@llvmorg-github-actions

Copy link
Copy Markdown

@llvm/pr-subscribers-lldb

Author: Jason Molenda (jasonmolenda)

Changes

When lldb needs to read a Mach-O binary out of memory, it first reads 512 bytes to get the mach header, which includes the size of the load commands, and then does a second read to get the mach header and load commands.

I am changing the initial read to get 3192 bytes, which will include the full load commands for most binaries.

In April I changed debugserver to return the correct size of the mach header and load commands in a sizeof_mh_and_loadcmds key. If this number is provided, refine the amount we read to this size.

This reduces the number of memory read packets we issue from 2 to 1 for a memory module, outside of packets that may be needed to get the symbol table.


Full diff: https://github.com/llvm/llvm-project/pull/200072.diff

1 Files Affected:

  • (modified) lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp (+4-1)
diff --git a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
index f666795c25860..65516cdb2ac47 100644
--- a/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
+++ b/lldb/source/Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderDarwin.cpp
@@ -177,7 +177,7 @@ ModuleSP DynamicLoaderDarwin::FindTargetModuleForImageInfo(
   // added to the target, don't let it be called for every one.
   if (!module_sp || module_sp->GetObjectFile() == nullptr) {
     llvm::Expected<ModuleSP> module_sp_or_err = m_process->ReadModuleFromMemory(
-        image_info.file_spec, image_info.address);
+        image_info.file_spec, image_info.address, image_info.mh_and_load_cmd_size);
     if (auto err = module_sp_or_err.takeError()) {
       LLDB_LOG_ERROR(GetLog(LLDBLog::DynamicLoader), std::move(err),
                      "Failed to load module from memory: {0}");
@@ -445,6 +445,9 @@ bool DynamicLoaderDarwin::JSONImageInformationIntoImageInfo(
         mh->GetValueForKey("cpusubtype")->GetUnsignedIntegerValue();
     image_infos[i].header.filetype =
         mh->GetValueForKey("filetype")->GetUnsignedIntegerValue();
+    if (mh->HasKey("sizeof_mh_and_loadcmds"))
+      image_infos[i].mh_and_load_cmd_size = 
+          mh->GetValueForKey("sizeof_mh_and_loadcmds")->GetUnsignedIntegerValue();
 
     if (image->HasKey("min_version_os_name")) {
       std::string os_name =

@github-actions

github-actions Bot commented May 27, 2026

Copy link
Copy Markdown

✅ With the latest revision this PR passed the C/C++ code formatter.

@bulbazord bulbazord left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a fun one

@jasonmolenda
jasonmolenda merged commit 9409c07 into llvm:main May 27, 2026
10 checks passed
@jasonmolenda
jasonmolenda deleted the refine-memory-module-reading-packets branch May 27, 2026 22:46
mh->GetValueForKey("cpusubtype")->GetUnsignedIntegerValue();
image_infos[i].header.filetype =
mh->GetValueForKey("filetype")->GetUnsignedIntegerValue();
if (mh->HasKey("sizeof_h_and_loadcmds"))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo?

Suggested change
if (mh->HasKey("sizeof_h_and_loadcmds"))
if (mh->HasKey("sizeof_mh_and_loadcmds"))

JDevlieghere pushed a commit to swiftlang/llvm-project that referenced this pull request Jun 1, 2026
…lvm#200072)

When lldb needs to read a Mach-O binary out of memory, it first reads
512 bytes to get the mach header, which includes the size of the load
commands, and then does a second read to get the mach header and load
commands.

I am changing the initial read to get 3192 bytes, which will include the
full load commands for most binaries.

In April I changed debugserver to return the correct size of the mach
header and load commands in a `sizeof_mh_and_loadcmds` key. If this
number is provided, refine the amount we read to this size.

This reduces the number of memory read packets we issue from 2 to 1 for
a memory module, outside of packets that may be needed to get the symbol
table.

(cherry picked from commit 9409c07)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants