[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 04:46:23 PDT 2026
https://github.com/karim-alweheshy created https://github.com/llvm/llvm-project/pull/232697
Resolve original JIT symbol requests through exact linkage names, avoiding demangled-name indexing and C++ basename decoys on the primary path. Retain compatibility lookup for alternate C++ names and recovered function-call-label source names.
Depends on #232694. Preserve module search order, runtime/user-symbol fallbacks, platform exclusions, weak-symbol handling and trampoline filtering. This excludes changes to global-data lookup order.
History checked: retain the dyld/platform exclusions from #201829, module-based mangling behavior from #224595, and NativePDB function-call labels from #227021. The weak-zero ordering issue discussed in open #161733 remains outside this change.
Validation: All eight active Darwin expression variants pass with this change over its prerequisite; eight unsupported debug-format variants are excluded. Coverage includes a C++ basename decoy, global data, present/missing weak imports, alternate C++ lookup, generic function-call-label fallback, and DWARF callables. On the prerequisite alone, both C linkage variants return the decoy value 11 instead of 42 while the six compatibility variants pass.
Assisted-by: OpenAI Codex
<!-- av pr metadata
This information is embedded by the av CLI when creating PRs to track the status of stacks when using Aviator. Please do not delete or edit this section of the PR.
```
{"parent":"users/karim-alweheshy/lldb-exact-c-symbol-lookup","parentHead":"2888d6d184552bee1b635bbc575968b12360e79a","parentPull":232694,"trunk":"main"}
```
-->
>From f2c14a4bde2a755008daa81a8bf2cdd37773ff9f 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