aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
diff options
context:
space:
mode:
authorJason Molenda <jmolenda@apple.com>2025-03-06 21:29:25 -0800
committerJason Molenda <jmolenda@apple.com>2025-03-06 21:29:38 -0800
commit1a31bb38a4bb2bc94fbbb43fe04d878cb4a5a05b (patch)
treec36b156ceaec7a704a2ea13e21f6aff642fe4073 /lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
parent21b261102504c97fc0b81c101898c0f1c1a7e79c (diff)
downloadllvm-1a31bb38a4bb2bc94fbbb43fe04d878cb4a5a05b.zip
llvm-1a31bb38a4bb2bc94fbbb43fe04d878cb4a5a05b.tar.gz
llvm-1a31bb38a4bb2bc94fbbb43fe04d878cb4a5a05b.tar.bz2
[lldb][Mach-O] Don't read symbol table of specially marked binary (#129967)
We have a binary image on Darwin that has no code, only metadata. It has a large symbol table with many external symbol names that will not be needed in the debugger. And it is possible to not have this binary on the debugger system - so lldb must read all of the symbol names out of memory, one at a time, which can be quite slow. We're adding a section __TEXT,__lldb_no_nlist, to this binary to indicate that lldb should not read the nlist symbols for it when we are reading out of memory. If lldb is run with an on-disk version of the binary, we will load the symbol table as we normally would, there's no benefit to handling this binary differently. I added a test where I create a dylib with this specially named section, launch the process. The main binary deletes the dylib from the disk so lldb is forced to read it out of memory. lldb attaches to the binary, confirms that the dylib is present in the process and is a memory Module. If the binary is not present, or lldb found the on-disk copy because it hasn't been deleted yet, we delete the target, flush the Debugger's module cache, sleep and retry, up to ten times. I create the specially named section by compiling an assembly file that puts a byte in the section which makes for a bit of a messy Makefile (the pre-canned actions to build a dylib don't quite handle this case) but I don't think it's much of a problem. This is a purely skipUnlessDarwin test case. Relanding this change with a restructured Makefiles for the test case that should pass on the CI bots. rdar://146167816
Diffstat (limited to 'lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp')
-rw-r--r--lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp68
1 files changed, 44 insertions, 24 deletions
diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
index a19322f..f31b56b 100644
--- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
+++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
@@ -918,6 +918,11 @@ ConstString ObjectFileMachO::GetSectionNameEHFrame() {
return g_section_name_eh_frame;
}
+ConstString ObjectFileMachO::GetSectionNameLLDBNoNlist() {
+ static ConstString g_section_name_lldb_no_nlist("__lldb_no_nlist");
+ return g_section_name_lldb_no_nlist;
+}
+
bool ObjectFileMachO::MagicBytesMatch(DataBufferSP data_sp,
lldb::addr_t data_offset,
lldb::addr_t data_length) {
@@ -2394,8 +2399,39 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
uint32_t memory_module_load_level = eMemoryModuleLoadLevelComplete;
bool is_shared_cache_image = IsSharedCacheBinary();
bool is_local_shared_cache_image = is_shared_cache_image && !IsInMemory();
+
+ ConstString g_segment_name_TEXT = GetSegmentNameTEXT();
+ ConstString g_segment_name_DATA = GetSegmentNameDATA();
+ ConstString g_segment_name_DATA_DIRTY = GetSegmentNameDATA_DIRTY();
+ ConstString g_segment_name_DATA_CONST = GetSegmentNameDATA_CONST();
+ ConstString g_segment_name_OBJC = GetSegmentNameOBJC();
+ ConstString g_section_name_eh_frame = GetSectionNameEHFrame();
+ ConstString g_section_name_lldb_no_nlist = GetSectionNameLLDBNoNlist();
+ SectionSP text_section_sp(
+ section_list->FindSectionByName(g_segment_name_TEXT));
+ SectionSP data_section_sp(
+ section_list->FindSectionByName(g_segment_name_DATA));
SectionSP linkedit_section_sp(
section_list->FindSectionByName(GetSegmentNameLINKEDIT()));
+ SectionSP data_dirty_section_sp(
+ section_list->FindSectionByName(g_segment_name_DATA_DIRTY));
+ SectionSP data_const_section_sp(
+ section_list->FindSectionByName(g_segment_name_DATA_CONST));
+ SectionSP objc_section_sp(
+ section_list->FindSectionByName(g_segment_name_OBJC));
+ SectionSP eh_frame_section_sp;
+ SectionSP lldb_no_nlist_section_sp;
+ if (text_section_sp.get()) {
+ eh_frame_section_sp = text_section_sp->GetChildren().FindSectionByName(
+ g_section_name_eh_frame);
+ lldb_no_nlist_section_sp = text_section_sp->GetChildren().FindSectionByName(
+ g_section_name_lldb_no_nlist);
+ } else {
+ eh_frame_section_sp =
+ section_list->FindSectionByName(g_section_name_eh_frame);
+ lldb_no_nlist_section_sp =
+ section_list->FindSectionByName(g_section_name_lldb_no_nlist);
+ }
if (process && m_header.filetype != llvm::MachO::MH_OBJECT &&
!is_local_shared_cache_image) {
@@ -2403,6 +2439,14 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
memory_module_load_level = target.GetMemoryModuleLoadLevel();
+ // If __TEXT,__lldb_no_nlist section is present in this binary,
+ // and we're reading it out of memory, do not read any of the
+ // nlist entries. They are not needed in lldb and it may be
+ // expensive to load these. This is to handle a dylib consisting
+ // of only metadata, no code, but it has many nlist entries.
+ if (lldb_no_nlist_section_sp)
+ memory_module_load_level = eMemoryModuleLoadLevelMinimal;
+
// Reading mach file from memory in a process or core file...
if (linkedit_section_sp) {
@@ -2526,30 +2570,6 @@ void ObjectFileMachO::ParseSymtab(Symtab &symtab) {
const bool have_strtab_data = strtab_data.GetByteSize() > 0;
- ConstString g_segment_name_TEXT = GetSegmentNameTEXT();
- ConstString g_segment_name_DATA = GetSegmentNameDATA();
- ConstString g_segment_name_DATA_DIRTY = GetSegmentNameDATA_DIRTY();
- ConstString g_segment_name_DATA_CONST = GetSegmentNameDATA_CONST();
- ConstString g_segment_name_OBJC = GetSegmentNameOBJC();
- ConstString g_section_name_eh_frame = GetSectionNameEHFrame();
- SectionSP text_section_sp(
- section_list->FindSectionByName(g_segment_name_TEXT));
- SectionSP data_section_sp(
- section_list->FindSectionByName(g_segment_name_DATA));
- SectionSP data_dirty_section_sp(
- section_list->FindSectionByName(g_segment_name_DATA_DIRTY));
- SectionSP data_const_section_sp(
- section_list->FindSectionByName(g_segment_name_DATA_CONST));
- SectionSP objc_section_sp(
- section_list->FindSectionByName(g_segment_name_OBJC));
- SectionSP eh_frame_section_sp;
- if (text_section_sp.get())
- eh_frame_section_sp = text_section_sp->GetChildren().FindSectionByName(
- g_section_name_eh_frame);
- else
- eh_frame_section_sp =
- section_list->FindSectionByName(g_section_name_eh_frame);
-
const bool is_arm = (m_header.cputype == llvm::MachO::CPU_TYPE_ARM);
const bool always_thumb = GetArchitecture().IsAlwaysThumbInstructions();