[Lldb-commits] [lldb] [lldb][Expression] Allow specifying a preferred ModuleList for lookup during expression evaluation (PR #129733)
via lldb-commits
lldb-commits at lists.llvm.org
Wed Mar 5 04:43:55 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lldb
Author: Michael Buch (Michael137)
<details>
<summary>Changes</summary>
The `TestMemoryHistory.py` is currently failing on the x86 macOS CI. The LLDB ASAN utility expression is failing to run with following error:
```
(lldb) image lookup -n __asan_get_alloc_stack
1 match found in /usr/lib/system/libsystem_sanitizers.dylib:
Address: libsystem_sanitizers.dylib[0x00007ffd11e673f7] (libsystem_sanitizers.dylib.__TEXT.__text + 11287)
Summary: libsystem_sanitizers.dylib`__asan_get_alloc_stack
1 match found in /Users/michaelbuch/Git/lldb-build-main-no-modules/lib/clang/21/lib/darwin/libclang_rt.asan_osx_dynamic.dylib:
Address: libclang_rt.asan_osx_dynamic.dylib[0x0000000000009ec0] (libclang_rt.asan_osx_dynamic.dylib.__TEXT.__text + 34352)
Summary: libclang_rt.asan_osx_dynamic.dylib`::__asan_get_alloc_stack(__sanitizer::uptr, __sanitizer::uptr *, __sanitizer::uptr, __sanitizer::u32 *) at asan_debugging.cpp:132
(lldb) memory history 'pointer'
Assertion failed: ((uintptr_t)addr == report.access.address), function __asan_get_alloc_stack, file debugger_abi.cpp, line 62.
warning: cannot evaluate AddressSanitizer expression:
error: Expression execution was interrupted: signal SIGABRT.
The process has been returned to the state before expression evaluation.
```
The reason for this is that the system sanitizer dylib and the locally built libclang_rt contain the same symbol `__asan_get_alloc_stack`, and depending on the order in which they're loaded we pick the one from the wrong dylib. Based on discussion with @<!-- -->wrotki we always want to pick the one that's in the libclang_rt dylib if it was loaded, and libsystem_sanitizers otherwise.
This patch addresses this by adding a "preferred lookup context list" to the expression evaluator. Currently this is only exposed in the `EvaluateExpressionOptions`. We make it a `SymbolContextList` in case we want the lookup contexts to be contexts other than modules (e.g., source files, etc.). In `IRExecutionUnit` we make it a `ModuleList` because it makes the symbol lookup implementation simpler and we only do module lookups here anyway. If we ever need it to be a `SymbolContext`, that transformation shouldn't be too difficult.
---
Full diff: https://github.com/llvm/llvm-project/pull/129733.diff
5 Files Affected:
- (modified) lldb/include/lldb/Expression/IRExecutionUnit.h (+12)
- (modified) lldb/include/lldb/Target/Target.h (+14)
- (modified) lldb/source/Expression/IRExecutionUnit.cpp (+26-5)
- (modified) lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp (+4)
- (modified) lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp (+26)
``````````diff
diff --git a/lldb/include/lldb/Expression/IRExecutionUnit.h b/lldb/include/lldb/Expression/IRExecutionUnit.h
index 58f12bf8b64f5..77d53daf80c1b 100644
--- a/lldb/include/lldb/Expression/IRExecutionUnit.h
+++ b/lldb/include/lldb/Expression/IRExecutionUnit.h
@@ -17,6 +17,7 @@
#include "llvm/ExecutionEngine/SectionMemoryManager.h"
#include "llvm/IR/Module.h"
+#include "lldb/Core/ModuleList.h"
#include "lldb/Expression/IRMemoryMap.h"
#include "lldb/Expression/ObjectFileJIT.h"
#include "lldb/Symbol/SymbolContext.h"
@@ -161,6 +162,12 @@ class IRExecutionUnit : public std::enable_shared_from_this<IRExecutionUnit>,
return m_jitted_global_variables;
}
+ void SetPreferredModules(SymbolContextList const &modules) {
+ for (auto const &m : modules)
+ if (m.module_sp)
+ m_preferred_modules.Append(m.module_sp);
+ }
+
private:
/// Look up the object in m_address_map that contains a given address, find
/// where it was copied to, and return the remote address at the same offset
@@ -396,6 +403,11 @@ class IRExecutionUnit : public std::enable_shared_from_this<IRExecutionUnit>,
///< defining no functions using that variable, would do this.) If this
///< is true, any allocations need to be committed immediately -- no
///< opportunity for relocation.
+
+ ///< Any Module in this list will be used for symbol/function lookup
+ ///< before any other module (except for the module corresponding to the
+ ///< current frame).
+ ModuleList m_preferred_modules;
};
} // namespace lldb_private
diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h
index f31ac381391b4..a4059cdb2a819 100644
--- a/lldb/include/lldb/Target/Target.h
+++ b/lldb/include/lldb/Target/Target.h
@@ -25,6 +25,7 @@
#include "lldb/Core/UserSettingsController.h"
#include "lldb/Expression/Expression.h"
#include "lldb/Host/ProcessLaunchInfo.h"
+#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/TypeSystem.h"
#include "lldb/Target/ExecutionContextScope.h"
#include "lldb/Target/PathMappingList.h"
@@ -332,6 +333,14 @@ class EvaluateExpressionOptions {
m_language = SourceLanguage(language_type);
}
+ void SetPreferredSymbolContexts(SymbolContextList modules) {
+ m_preferred_lookup_contexts = std::move(modules);
+ }
+
+ const SymbolContextList &GetPreferredSymbolContexts() const {
+ return m_preferred_lookup_contexts;
+ }
+
/// Set the language using a pair of language code and version as
/// defined by the DWARF 6 specification.
/// WARNING: These codes may change until DWARF 6 is finalized.
@@ -500,6 +509,11 @@ class EvaluateExpressionOptions {
// originates
mutable std::string m_pound_line_file;
mutable uint32_t m_pound_line_line = 0;
+
+ ///< During expression evaluation, any SymbolContext in this list will be
+ ///< used for symbol/function lookup before any other context (except for
+ ///< the module corresponding to the current frame).
+ SymbolContextList m_preferred_lookup_contexts;
};
// Target
diff --git a/lldb/source/Expression/IRExecutionUnit.cpp b/lldb/source/Expression/IRExecutionUnit.cpp
index c8b4ddf705ec4..06b0cb7769f64 100644
--- a/lldb/source/Expression/IRExecutionUnit.cpp
+++ b/lldb/source/Expression/IRExecutionUnit.cpp
@@ -52,7 +52,7 @@ IRExecutionUnit::IRExecutionUnit(std::unique_ptr<llvm::LLVMContext> &context_up,
m_cpu_features(cpu_features), m_name(name), m_sym_ctx(sym_ctx),
m_did_jit(false), m_function_load_addr(LLDB_INVALID_ADDRESS),
m_function_end_load_addr(LLDB_INVALID_ADDRESS),
- m_reported_allocations(false) {}
+ m_reported_allocations(false), m_preferred_modules() {}
lldb::addr_t IRExecutionUnit::WriteNow(const uint8_t *bytes, size_t size,
Status &error) {
@@ -782,8 +782,11 @@ IRExecutionUnit::FindInSymbols(const std::vector<ConstString> &names,
}
ModuleList non_local_images = target->GetImages();
- // We'll process module_sp separately, before the other modules.
+ // We'll process module_sp and any preferred modules separately, before the
+ // other modules.
non_local_images.Remove(sc.module_sp);
+ for (size_t i = 0; i < m_preferred_modules.GetSize(); ++i)
+ non_local_images.Remove(m_preferred_modules.GetModuleAtIndex(i));
LoadAddressResolver resolver(target, symbol_was_missing_weak);
@@ -794,9 +797,11 @@ IRExecutionUnit::FindInSymbols(const std::vector<ConstString> &names,
for (const ConstString &name : names) {
// The lookup order here is as follows:
// 1) Functions in `sc.module_sp`
- // 2) Functions in the other modules
- // 3) Symbols in `sc.module_sp`
- // 4) Symbols in the other modules
+ // 2) Functions in the preferred modules list
+ // 3) Functions in the other modules
+ // 4) Symbols in `sc.module_sp`
+ // 5) Symbols in the preferred modules list
+ // 6) Symbols in the other modules
if (sc.module_sp) {
SymbolContextList sc_list;
sc.module_sp->FindFunctions(name, CompilerDeclContext(),
@@ -806,6 +811,14 @@ IRExecutionUnit::FindInSymbols(const std::vector<ConstString> &names,
return *load_addr;
}
+ {
+ SymbolContextList sc_list;
+ m_preferred_modules.FindFunctions(name, lldb::eFunctionNameTypeFull,
+ function_options, sc_list);
+ if (auto load_addr = resolver.Resolve(sc_list))
+ return *load_addr;
+ }
+
{
SymbolContextList sc_list;
non_local_images.FindFunctions(name, lldb::eFunctionNameTypeFull,
@@ -822,6 +835,14 @@ IRExecutionUnit::FindInSymbols(const std::vector<ConstString> &names,
return *load_addr;
}
+ {
+ SymbolContextList sc_list;
+ m_preferred_modules.FindSymbolsWithNameAndType(name, lldb::eSymbolTypeAny,
+ sc_list);
+ if (auto load_addr = resolver.Resolve(sc_list))
+ return *load_addr;
+ }
+
{
SymbolContextList sc_list;
non_local_images.FindSymbolsWithNameAndType(name, lldb::eSymbolTypeAny,
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index f1573bae2651b..cefa226175855 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -1539,6 +1539,10 @@ lldb_private::Status ClangExpressionParser::DoPrepareForExecution(
function_name, exe_ctx.GetTargetSP(), sc,
m_compiler->getTargetOpts().Features);
+ if (auto *options = m_expr.GetOptions())
+ execution_unit_sp->SetPreferredModules(
+ options->GetPreferredSymbolContexts());
+
ClangExpressionHelper *type_system_helper =
dyn_cast<ClangExpressionHelper>(m_expr.GetTypeSystemHelper());
ClangExpressionDeclMap *decl_map =
diff --git a/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp b/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp
index 41df0e85199ce..b806bbf15ac5f 100644
--- a/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp
+++ b/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp
@@ -8,6 +8,7 @@
#include "MemoryHistoryASan.h"
+#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Target/MemoryHistory.h"
#include "Plugins/Process/Utility/HistoryThread.h"
@@ -61,6 +62,25 @@ MemoryHistoryASan::MemoryHistoryASan(const ProcessSP &process_sp) {
m_process_wp = process_sp;
}
+///< On Darwin, if LLDB loaded libclang_rt, it's coming from a locally built
+///< compiler-rt, and we should prefer it in favour of the system sanitizers.
+///< This helper searches the target for such a dylib. Returns nullptr if no
+///< such dylib was found.
+static ModuleSP GetPreferredAsanModule(const Target &target) {
+ ModuleSP module;
+ llvm::Regex pattern(R"(libclang_rt\.asan_.*_dynamic\.dylib)");
+ target.GetImages().ForEach([&](const lldb::ModuleSP &m) {
+ if (pattern.match(m->GetFileSpec().GetFilename().GetStringRef())) {
+ module = m;
+ return false;
+ }
+
+ return true;
+ });
+
+ return module;
+}
+
const char *memory_history_asan_command_prefix = R"(
extern "C"
{
@@ -174,6 +194,12 @@ HistoryThreads MemoryHistoryASan::GetHistoryThreads(lldb::addr_t address) {
options.SetAutoApplyFixIts(false);
options.SetLanguage(eLanguageTypeObjC_plus_plus);
+ if (auto m = GetPreferredAsanModule(process_sp->GetTarget())) {
+ SymbolContextList sc_list;
+ sc_list.Append(SymbolContext(std::move(m)));
+ options.SetPreferredSymbolContexts(std::move(sc_list));
+ }
+
ExpressionResults expr_result = UserExpression::Evaluate(
exe_ctx, options, expr.GetString(), "", return_value_sp);
if (expr_result != eExpressionCompleted) {
``````````
</details>
https://github.com/llvm/llvm-project/pull/129733
More information about the lldb-commits
mailing list