[llvm-branch-commits] [lldb] [lldb] Use linkage names for primary JIT symbol lookup (PR #232697)
Karim Alweheshy via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Fri Oct 16 05:00:10 PDT 2026
https://github.com/karim-alweheshy updated https://github.com/llvm/llvm-project/pull/232697
>From 5d83cb4e1674a04a7c44ede5734d425defd214f0 Mon Sep 17 00:00:00 2001
From: Karim Alweheshy <karim.alweheshy at reddit.com>
Date: Fri, 16 Oct 2026 13:00:41 +0200
Subject: [PATCH] [lldb] Use linkage names for primary JIT symbol lookup
Resolve original JIT symbol requests with the exact linkage-name path while retaining source-name lookup for function-call-label and alternate C++ fallbacks. Preserve module order, platform exclusions, weak-symbol handling, and trampoline filtering.
Assisted-by: OpenAI Codex
---
.../include/lldb/Expression/IRExecutionUnit.h | 3 +-
lldb/source/Expression/IRExecutionUnit.cpp | 51 +++++++++----
.../expression/linkage_lookup/Makefile | 10 +++
.../TestIRExecutionUnitLinkageLookup.py | 75 +++++++++++++++++++
.../expression/linkage_lookup/decoy.cpp | 5 ++
.../expression/linkage_lookup/main.cpp | 10 +++
.../expression/linkage_lookup/probe.cpp | 10 +++
7 files changed, 150 insertions(+), 14 deletions(-)
create mode 100644 lldb/test/API/commands/expression/linkage_lookup/Makefile
create mode 100644 lldb/test/API/commands/expression/linkage_lookup/TestIRExecutionUnitLinkageLookup.py
create mode 100644 lldb/test/API/commands/expression/linkage_lookup/decoy.cpp
create mode 100644 lldb/test/API/commands/expression/linkage_lookup/main.cpp
create mode 100644 lldb/test/API/commands/expression/linkage_lookup/probe.cpp
diff --git a/lldb/include/lldb/Expression/IRExecutionUnit.h b/lldb/include/lldb/Expression/IRExecutionUnit.h
index 6ba0dc52d3db16..f8cf310be1d26c 100644
--- a/lldb/include/lldb/Expression/IRExecutionUnit.h
+++ b/lldb/include/lldb/Expression/IRExecutionUnit.h
@@ -224,7 +224,8 @@ class IRExecutionUnit : public std::enable_shared_from_this<IRExecutionUnit>,
lldb::addr_t FindInSymbols(const std::vector<ConstString> &names,
const lldb_private::SymbolContext &sc,
- bool &symbol_was_missing_weak);
+ bool &symbol_was_missing_weak,
+ bool lookup_by_linkage);
lldb::addr_t FindInRuntimes(const std::vector<ConstString> &names,
const lldb_private::SymbolContext &sc);
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp
index 17e131512ef0f6..95d5df967fb4b1 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -716,7 +716,8 @@ ResolveFunctionCallLabel(FunctionCallLabel &label,
lldb::addr_t
IRExecutionUnit::FindInSymbols(const std::vector<ConstString> &names,
const lldb_private::SymbolContext &sc,
- bool &symbol_was_missing_weak) {
+ bool &symbol_was_missing_weak,
+ bool lookup_by_linkage) {
symbol_was_missing_weak = false;
Target *target = sc.target_sp.get();
@@ -745,6 +746,24 @@ IRExecutionUnit::FindInSymbols(const std::vector<ConstString> &names,
ModuleFunctionSearchOptions function_options;
function_options.include_symbols = true;
function_options.include_inlines = false;
+ function_options.match_linkage_names = lookup_by_linkage;
+
+ auto resolve = [&](SymbolContextList &sc_list) {
+ if (lookup_by_linkage) {
+ // General linkage queries retain named trampolines. The ordinary name
+ // indexes exclude them, so retain that exclusion for JIT resolution.
+ for (size_t i = sc_list.GetSize(); i > 0; --i) {
+ const SymbolContext &context = sc_list[i - 1];
+ if (!context.symbol || !context.symbol->IsTrampoline())
+ continue;
+ if (context.function)
+ sc_list.SetSymbolAtIndex(i - 1, nullptr);
+ else
+ sc_list.RemoveContextAtIndex(i - 1);
+ }
+ }
+ return resolver.Resolve(sc_list);
+ };
for (const ConstString &name : names) {
// The lookup order here is as follows:
@@ -759,7 +778,7 @@ IRExecutionUnit::FindInSymbols(const std::vector<ConstString> &names,
sc.module_sp->FindFunctions(name, CompilerDeclContext(),
lldb::eFunctionNameTypeFull, function_options,
sc_list);
- if (auto load_addr = resolver.Resolve(sc_list))
+ if (auto load_addr = resolve(sc_list))
return *load_addr;
}
@@ -767,7 +786,7 @@ IRExecutionUnit::FindInSymbols(const std::vector<ConstString> &names,
SymbolContextList sc_list;
m_preferred_modules.FindFunctions(name, lldb::eFunctionNameTypeFull,
function_options, sc_list);
- if (auto load_addr = resolver.Resolve(sc_list))
+ if (auto load_addr = resolve(sc_list))
return *load_addr;
}
@@ -775,31 +794,31 @@ IRExecutionUnit::FindInSymbols(const std::vector<ConstString> &names,
SymbolContextList sc_list;
non_local_images.FindFunctions(name, lldb::eFunctionNameTypeFull,
function_options, sc_list);
- if (auto load_addr = resolver.Resolve(sc_list))
+ if (auto load_addr = resolve(sc_list))
return *load_addr;
}
if (sc.module_sp) {
SymbolContextList sc_list;
sc.module_sp->FindSymbolsWithNameAndType(name, lldb::eSymbolTypeAny,
- sc_list);
- if (auto load_addr = resolver.Resolve(sc_list))
+ sc_list, lookup_by_linkage);
+ if (auto load_addr = resolve(sc_list))
return *load_addr;
}
{
SymbolContextList sc_list;
- m_preferred_modules.FindSymbolsWithNameAndType(name, lldb::eSymbolTypeAny,
- sc_list);
- if (auto load_addr = resolver.Resolve(sc_list))
+ m_preferred_modules.FindSymbolsWithNameAndType(
+ name, lldb::eSymbolTypeAny, sc_list, lookup_by_linkage);
+ if (auto load_addr = resolve(sc_list))
return *load_addr;
}
{
SymbolContextList sc_list;
non_local_images.FindSymbolsWithNameAndType(name, lldb::eSymbolTypeAny,
- sc_list);
- if (auto load_addr = resolver.Resolve(sc_list))
+ sc_list, lookup_by_linkage);
+ if (auto load_addr = resolve(sc_list))
return *load_addr;
}
@@ -856,6 +875,9 @@ lldb::addr_t IRExecutionUnit::FindInUserDefinedSymbols(
lldb::addr_t IRExecutionUnit::FindSymbol(lldb_private::ConstString name,
bool &missing_weak) {
+ // Original JIT/interpreter requests use linkage spellings. Source names
+ // recovered from function-call labels retain their compatibility lookup.
+ bool lookup_by_linkage = true;
if (name.GetStringRef().starts_with(FunctionCallLabelPrefix)) {
auto label_or_err = FunctionCallLabel::fromString(name);
if (!label_or_err) {
@@ -878,6 +900,7 @@ lldb::addr_t IRExecutionUnit::FindSymbol(lldb_private::ConstString name,
// a different lldb_private::Module than it's declaration. Meaning
// we couldn't pin-point it using the information encoded in the label.
name.SetString(label_or_err->lookup_name);
+ lookup_by_linkage = false;
}
}
@@ -889,7 +912,8 @@ lldb::addr_t IRExecutionUnit::FindSymbol(lldb_private::ConstString name,
CollectCandidateCNames(candidate_C_names, name);
- lldb::addr_t ret = FindInSymbols(candidate_C_names, m_sym_ctx, missing_weak);
+ lldb::addr_t ret = FindInSymbols(candidate_C_names, m_sym_ctx, missing_weak,
+ lookup_by_linkage);
if (ret != LLDB_INVALID_ADDRESS)
return ret;
@@ -906,7 +930,8 @@ lldb::addr_t IRExecutionUnit::FindSymbol(lldb_private::ConstString name,
CollectCandidateCPlusPlusNames(candidate_CPlusPlus_names, candidate_C_names,
m_sym_ctx);
- ret = FindInSymbols(candidate_CPlusPlus_names, m_sym_ctx, missing_weak);
+ ret = FindInSymbols(candidate_CPlusPlus_names, m_sym_ctx, missing_weak,
+ /*lookup_by_linkage=*/false);
return ret;
}
diff --git a/lldb/test/API/commands/expression/linkage_lookup/Makefile b/lldb/test/API/commands/expression/linkage_lookup/Makefile
new file mode 100644
index 00000000000000..c3058836fd41fe
--- /dev/null
+++ b/lldb/test/API/commands/expression/linkage_lookup/Makefile
@@ -0,0 +1,10 @@
+CXX_SOURCES := main.cpp decoy.cpp
+DYLIB_NAME := LinkageProbe
+DYLIB_CXX_SOURCES := probe.cpp
+LD_EXTRAS := -Wl,-U,_missing_weak
+
+include Makefile.rules
+
+# Keep the decoys in the symbol table without adding DWARF functions. This
+# isolates the JIT's symbol-name lookup from the debug-info function lookup.
+decoy.o: CXXFLAGS += -g0
diff --git a/lldb/test/API/commands/expression/linkage_lookup/TestIRExecutionUnitLinkageLookup.py b/lldb/test/API/commands/expression/linkage_lookup/TestIRExecutionUnitLinkageLookup.py
new file mode 100644
index 00000000000000..1cf80f9e8072bf
--- /dev/null
+++ b/lldb/test/API/commands/expression/linkage_lookup/TestIRExecutionUnitLinkageLookup.py
@@ -0,0 +1,75 @@
+"""Keep primary JIT linkage lookup separate from compatibility aliases."""
+
+import lldb
+from lldbsuite.test.decorators import skipUnlessDarwin
+from lldbsuite.test.lldbtest import TestBase
+from lldbsuite.test import lldbutil
+
+
+class TestIRExecutionUnitLinkageLookup(TestBase):
+ def launch(self):
+ self.build()
+ self.runCmd("settings set target.preload-symbols false")
+ self.runCmd("settings set target.load-script-from-symbol-file false")
+ self.target, _, thread, _ = lldbutil.run_to_source_breakpoint(
+ self, "break here", lldb.SBFileSpec("main.cpp")
+ )
+ self.frame = thread.frames[0]
+
+ def value(self, expression, declarations=""):
+ options = lldb.SBExpressionOptions()
+ options.SetLanguage(lldb.eLanguageTypeC_plus_plus)
+ options.SetPrefix(declarations)
+ result = self.frame.EvaluateExpression(expression, options)
+ self.assertSuccess(result.GetError())
+ return result.GetValueAsSigned()
+
+ @skipUnlessDarwin
+ def test_primary_c_linkage_ignores_symbol_only_cpp_decoy(self):
+ self.launch()
+ self.assertEqual(
+ self.value("linkage_target()", 'extern "C" int linkage_target();'),
+ 42,
+ )
+
+ @skipUnlessDarwin
+ def test_global_and_weak_symbols(self):
+ self.launch()
+ self.assertEqual(
+ self.value("linkage_global", 'extern "C" { extern int linkage_global; }'),
+ 73,
+ )
+ self.assertEqual(
+ self.value(
+ "missing_weak == nullptr",
+ 'extern "C" int missing_weak() __attribute__((weak_import));',
+ ),
+ 1,
+ )
+ self.assertEqual(
+ self.value(
+ "present_weak()",
+ 'extern "C" int present_weak() __attribute__((weak_import));',
+ ),
+ 29,
+ )
+
+ @skipUnlessDarwin
+ def test_cpp_and_function_call_label_fallbacks(self):
+ self.launch()
+ self.assertEqual(
+ self.value("cpp_fallback_target()", "int cpp_fallback_target();"), 17
+ )
+ self.assertEqual(
+ self.value(
+ "labelled_fallback()",
+ 'int labelled_fallback() asm("$__lldb_func:generic:'
+ '0xffffffffffffffff:0:fcl_alias_target");',
+ ),
+ 19,
+ )
+
+ @skipUnlessDarwin
+ def test_dwarf_callable(self):
+ self.launch()
+ self.assertEqual(self.value("dwarf_callable()"), 31)
diff --git a/lldb/test/API/commands/expression/linkage_lookup/decoy.cpp b/lldb/test/API/commands/expression/linkage_lookup/decoy.cpp
new file mode 100644
index 00000000000000..8f510190e66b9a
--- /dev/null
+++ b/lldb/test/API/commands/expression/linkage_lookup/decoy.cpp
@@ -0,0 +1,5 @@
+// The primary JIT relocation "linkage_target" must not bind to this C++
+// function through the basename alias in the general symbol-name index.
+int linkage_target() { return 11; }
+
+int fcl_alias_target() { return 19; }
diff --git a/lldb/test/API/commands/expression/linkage_lookup/main.cpp b/lldb/test/API/commands/expression/linkage_lookup/main.cpp
new file mode 100644
index 00000000000000..dd964f5d2babd0
--- /dev/null
+++ b/lldb/test/API/commands/expression/linkage_lookup/main.cpp
@@ -0,0 +1,10 @@
+extern "C" int linkage_library_anchor();
+extern "C" int missing_weak() __attribute__((weak_import));
+
+__attribute__((noinline)) static int dwarf_callable() { return 31; }
+
+int main() {
+ int (*volatile missing_address)() = missing_weak;
+ volatile int observed = dwarf_callable() + linkage_library_anchor();
+ return observed + (missing_address != nullptr); // break here
+}
diff --git a/lldb/test/API/commands/expression/linkage_lookup/probe.cpp b/lldb/test/API/commands/expression/linkage_lookup/probe.cpp
new file mode 100644
index 00000000000000..f02de4709565ca
--- /dev/null
+++ b/lldb/test/API/commands/expression/linkage_lookup/probe.cpp
@@ -0,0 +1,10 @@
+extern "C" {
+int linkage_library_anchor() { return 0; }
+int linkage_target() { return 42; }
+int linkage_global = 73;
+int present_weak() { return 29; }
+
+// A C++ expression declaration intentionally omits extern "C". The existing
+// alternate-mangling and basename fallback must still find this C definition.
+int cpp_fallback_target() { return 17; }
+}
More information about the llvm-branch-commits
mailing list