[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