From 02af6b6b7c41dd9d07128070da6f7e924be37545 Mon Sep 17 00:00:00 2001 From: Michael Buch Date: Thu, 6 Mar 2025 21:07:22 +0000 Subject: [PATCH 1/2] [lldb][Expression] Allow specifying a preferred ModuleList for lookup during expression evaluation (#129733) The `TestMemoryHistory.py`/`TestReportData.py` are currently failing on the x86 macOS CI (started after we upgraded the Xcode SDK on that machien). 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 may pick the one from the wrong dylib (this probably changed during the buildbot upgrade and is why it only now started failing). 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. (cherry picked from commit 542d52b1e8a0a7e04538f608487603124c70e1ab) --- .../include/lldb/Expression/IRExecutionUnit.h | 12 +++++++ lldb/include/lldb/Target/Target.h | 13 +++++++ lldb/source/Expression/IRExecutionUnit.cpp | 32 ++++++++++++++--- .../Clang/ClangExpressionParser.cpp | 4 +++ .../Utility/CMakeLists.txt | 1 + .../Utility/ReportRetriever.cpp | 7 ++++ .../Utility/Utility.cpp | 35 +++++++++++++++++++ .../InstrumentationRuntime/Utility/Utility.h | 27 ++++++++++++++ .../MemoryHistory/asan/MemoryHistoryASan.cpp | 8 +++++ 9 files changed, 134 insertions(+), 5 deletions(-) create mode 100644 lldb/source/Plugins/InstrumentationRuntime/Utility/Utility.cpp create mode 100644 lldb/source/Plugins/InstrumentationRuntime/Utility/Utility.h diff --git a/lldb/include/lldb/Expression/IRExecutionUnit.h b/lldb/include/lldb/Expression/IRExecutionUnit.h index a4d628429d3b9..31541aa2483a4 100644 --- a/lldb/include/lldb/Expression/IRExecutionUnit.h +++ b/lldb/include/lldb/Expression/IRExecutionUnit.h @@ -19,6 +19,7 @@ #include "llvm/IR/Module.h" #include "llvm/ADT/StringMap.h" +#include "lldb/Core/ModuleList.h" #include "lldb/Expression/IRMemoryMap.h" #include "lldb/Expression/ObjectFileJIT.h" #include "lldb/Symbol/SymbolContext.h" @@ -168,6 +169,12 @@ class IRExecutionUnit : public std::enable_shared_from_this, return m_jitted_global_variables; } + void AppendPreferredSymbolContexts(SymbolContextList const &contexts) { + for (auto const &ctx : contexts) + if (ctx.module_sp) + m_preferred_modules.Append(ctx.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 @@ -409,6 +416,11 @@ class IRExecutionUnit : public std::enable_shared_from_this, ///< opportunity for relocation. llvm::StringMap m_section_size_map; + + ///< 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 03ce1bf9cd8fb..97eaad79e9da0 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -380,6 +380,14 @@ class EvaluateExpressionOptions { m_language = SourceLanguage(language_type); } + void SetPreferredSymbolContexts(SymbolContextList contexts) { + m_preferred_lookup_contexts = std::move(contexts); + } + + 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. @@ -584,6 +592,11 @@ class EvaluateExpressionOptions { mutable std::string m_pound_line_file; mutable uint32_t m_pound_line_line = 0; bool m_prepare_playground_stub_functions = true; + + ///< 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 cbdf08896678f..ae6d7b0c03bc6 100644 --- a/lldb/source/Expression/IRExecutionUnit.cpp +++ b/lldb/source/Expression/IRExecutionUnit.cpp @@ -56,7 +56,7 @@ IRExecutionUnit::IRExecutionUnit(std::unique_ptr &context_up, 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() {} IRExecutionUnit::~IRExecutionUnit() { std::lock_guard global_context_locker( @@ -818,8 +818,12 @@ IRExecutionUnit::FindInSymbols(const std::vector &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)); + // BEGIN SWIFT if (m_in_populate_symtab) if (lldb::ModuleSP module_sp = m_jit_module_wp.lock()) @@ -835,9 +839,11 @@ IRExecutionUnit::FindInSymbols(const std::vector &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(), @@ -847,6 +853,14 @@ IRExecutionUnit::FindInSymbols(const std::vector &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, @@ -863,6 +877,14 @@ IRExecutionUnit::FindInSymbols(const std::vector &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 b7e368dc881e6..2b00557d2e77b 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -1483,6 +1483,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->AppendPreferredSymbolContexts( + options->GetPreferredSymbolContexts()); + ClangExpressionHelper *type_system_helper = dyn_cast(m_expr.GetTypeSystemHelper()); ClangExpressionDeclMap *decl_map = diff --git a/lldb/source/Plugins/InstrumentationRuntime/Utility/CMakeLists.txt b/lldb/source/Plugins/InstrumentationRuntime/Utility/CMakeLists.txt index dcca47fb0e253..705fe1503fae2 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/Utility/CMakeLists.txt +++ b/lldb/source/Plugins/InstrumentationRuntime/Utility/CMakeLists.txt @@ -1,5 +1,6 @@ add_lldb_library(lldbPluginInstrumentationRuntimeUtility ReportRetriever.cpp + Utility.cpp LINK_LIBS lldbBreakpoint diff --git a/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp b/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp index 04ce339d8f661..00761327a694b 100644 --- a/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp +++ b/lldb/source/Plugins/InstrumentationRuntime/Utility/ReportRetriever.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "ReportRetriever.h" +#include "Utility.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Core/Debugger.h" @@ -82,6 +83,12 @@ ReportRetriever::RetrieveReportData(const ProcessSP process_sp) { 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)); + } + ValueObjectSP return_value_sp; ExecutionContext exe_ctx; frame_sp->CalculateExecutionContext(exe_ctx); diff --git a/lldb/source/Plugins/InstrumentationRuntime/Utility/Utility.cpp b/lldb/source/Plugins/InstrumentationRuntime/Utility/Utility.cpp new file mode 100644 index 0000000000000..3cbd03b24297a --- /dev/null +++ b/lldb/source/Plugins/InstrumentationRuntime/Utility/Utility.cpp @@ -0,0 +1,35 @@ +//===-- Utility.cpp -------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "Utility.h" + +#include "lldb/Core/Module.h" +#include "lldb/Target/Target.h" + +namespace lldb_private { + +///< 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. +lldb::ModuleSP GetPreferredAsanModule(const Target &target) { + lldb::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; +} + +} // namespace lldb_private diff --git a/lldb/source/Plugins/InstrumentationRuntime/Utility/Utility.h b/lldb/source/Plugins/InstrumentationRuntime/Utility/Utility.h new file mode 100644 index 0000000000000..813a0c107989e --- /dev/null +++ b/lldb/source/Plugins/InstrumentationRuntime/Utility/Utility.h @@ -0,0 +1,27 @@ +//===-- Utility.h -----------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_UTILITY_UTILITY_H +#define LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_UTILITY_UTILITY_H + +#include "lldb/lldb-forward.h" + +namespace lldb_private { + +class Target; + +///< 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 +///< when running InstrumentationRuntime utility expressions that use symbols +///< from the sanitizer libraries. This helper searches the target for such a +///< dylib. Returns nullptr if no such dylib was found. +lldb::ModuleSP GetPreferredAsanModule(const Target &target); + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_INSTRUMENTATIONRUNTIME_UTILITY_UTILITY_H diff --git a/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp b/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp index 41df0e85199ce..afaaa57b09587 100644 --- a/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp +++ b/lldb/source/Plugins/MemoryHistory/asan/MemoryHistoryASan.cpp @@ -8,8 +8,10 @@ #include "MemoryHistoryASan.h" +#include "lldb/Symbol/SymbolContext.h" #include "lldb/Target/MemoryHistory.h" +#include "Plugins/InstrumentationRuntime/Utility/Utility.h" #include "Plugins/Process/Utility/HistoryThread.h" #include "lldb/Core/Debugger.h" #include "lldb/Core/Module.h" @@ -174,6 +176,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) { From 558d983616fe54a0549147ebd6763be43ba18d5c Mon Sep 17 00:00:00 2001 From: Michael Buch Date: Fri, 7 Mar 2025 21:04:24 +0000 Subject: [PATCH 2/2] [lldb][test] Skip libsanitizers tests for now (#130305) These are macOS tests only and are currently failing on the x86_64 CI and on arm64 on recent versions of macOS/Xcode. The tests are failing because we're stopping in: ``` Process 17458 stopped * thread #1: tid = 0xbda69a, 0x00000002735bd000 libsystem_malloc.dylib`purgeable_print_self.cold.1, stop reason = EXC_BREAKPOINT (code=1, subcode=0x2735bd000) ``` instead of the libsanitizers library. This seems to be related to `-fsanitize-trivial-abi` support Skip these for now until we figure out the root cause. (cherry picked from commit 6cc8b0bef07f4270303bec0fc203f251a2fde262) --- lldb/test/API/functionalities/asan/TestMemoryHistory.py | 2 +- lldb/test/API/functionalities/asan/TestReportData.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/test/API/functionalities/asan/TestMemoryHistory.py b/lldb/test/API/functionalities/asan/TestMemoryHistory.py index d5e1912e1f322..a1dd43d283079 100644 --- a/lldb/test/API/functionalities/asan/TestMemoryHistory.py +++ b/lldb/test/API/functionalities/asan/TestMemoryHistory.py @@ -20,7 +20,7 @@ def test(self): self.asan_tests() @skipIf(oslist=no_match(["macosx"])) - @skipIfDarwin # rdar://142836595 + @skipIf(bugnumber="rdar://144997976") def test_libsanitizers_asan(self): try: self.build(make_targets=["libsanitizers"]) diff --git a/lldb/test/API/functionalities/asan/TestReportData.py b/lldb/test/API/functionalities/asan/TestReportData.py index 390f73e39619e..fabc985d0ed44 100644 --- a/lldb/test/API/functionalities/asan/TestReportData.py +++ b/lldb/test/API/functionalities/asan/TestReportData.py @@ -20,7 +20,7 @@ def test(self): self.asan_tests() @skipIf(oslist=no_match(["macosx"])) - @skipIfDarwin # rdar://142836595 + @skipIf(bugnumber="rdar://144997976") def test_libsanitizers_asan(self): try: self.build(make_targets=["libsanitizers"])