summaryrefslogtreecommitdiff
path: root/lldb/include
AgeCommit message (Collapse)Author
2025-11-22[lldb] [disassembler] chore: update VariableAnnotator::Annotate to except ↵n2h9
only Instruction as param and drop module and target (#168276)
2025-11-21[lldb] Remove Base::unique from NonNullSharedPtr (#169130)Keith Smiley
It seems like this fails on macOS with C++20
2025-11-21[lldb] Add assert to NonNullSharedPtr move constructor (#168979)Jonas Devlieghere
As suggested by Augusto, add an assert to the NonNullSharedPtr move constructor.
2025-11-20[lldb] Eliminate SupportFileSP nullptr derefs (#168624)Jonas Devlieghere
This patch fixes and eliminates the possibility of SupportFileSP ever being nullptr. The support file was originally treated like a value type, but became a polymorphic type and therefore has to be stored and passed around as a pointer. To avoid having all the callers check the validity of the pointer, I introduced the invariant that SupportFileSP is never null and always default constructed. However, without enforcement at the type level, that's fragile and indeed, we already identified two crashes where someone accidentally broke that invariant. This PR introduces a NonNullSharedPtr to prevent that. NonNullSharedPtr is a smart pointer wrapper around std::shared_ptr that guarantees the pointer is never null. If default-constructed, it creates a default-constructed instance of the contained type. Note that I'm using private inheritance because you shouldn't inherit from standard library classes due to the lack of virtual destructor. So while the new abstraction looks like a `std::shared_ptr`, it is in fact **not** a shared pointer. Given that our destructor is trivial, we could use public inheritance, but currently there's no need for it. rdar://164989579
2025-11-19[NFC][lldb] move DiagnosticsRendering to Host (#168696)Charles Zablit
NFC patch which moves `DiagnosticsRendering` from `Utility` to `Host`. This refactoring is needed for https://github.com/llvm/llvm-project/pull/168603. It adds a method to check whether the current terminal supports Unicode or not. This will be OS dependent and a better fit for `Host`. Since `Utility` cannot depend on `Host`, `DiagnosticsRendering` must live in `Host` instead.
2025-11-18[LLDB] Add log channel for InstrumentationRuntime plugins (#168508)Dan Liew
This patch adds `LLDBLog::InstrumentationRuntime` as a log channel to provide an appropriate channel for instrumentation runtime plugins as previously one did not exist. A small use of the channel is added to illustrate its use. The logging added is not intended to be comprehensive. This is primarily motivated by an `-fbounds-safety` instrumentation plugin (https://github.com/swiftlang/llvm-project/pull/11835). rdar://164920875
2025-11-18[lldb] Support integer registers with more than 64 bits. (#166363)Matej Košík
In this PR we are proposing to change LLDB codebase so that LLDB is able to print values of integer registers that have more than 64-bits (even if the number of bits is not equal to 128). --------- Co-authored-by: Matej Košík <matej.kosik@codasip.com> Co-authored-by: Jonas Devlieghere <jonas@devlieghere.com>
2025-11-17[lldb] Ensure FILE* access mode is correctly specified when creating a ↵John Harrison
NativeFile. (#167764) If we open a `NativeFile` with a `FILE*`, the OpenOptions default to `eOpenOptionReadOnly`. This is an issue in python scripts if you try to write to one of the files like `print("Hi", file=lldb.debugger.GetOutputFileHandle())`. To address this, we need to specify the access mode whenever we create a `NativeFile` from a `FILE*`. I also added an assert on the `NativeFile` that validates the file is opened with the correct access mode and updated `NativeFile::Read` and `NativeFile::Write` to check the access mode. Before these changes: ``` $ lldb -b -O 'script lldb.debugger.GetOutputFileHandle().write("abc")' (lldb) script lldb.debugger.GetOutputFileHandle().write("abc") Traceback (most recent call last): File "<input>", line 1, in <module> io.UnsupportedOperation: not writable ``` After: ``` $ lldb -b -O 'script lldb.debugger.GetOutputFileHandle().write("abc")' (lldb) script lldb.debugger.GetOutputFileHandle().write("abc") abc3 ``` Fixes #122387
2025-11-17[lldb][nfc] Fix comment about UINT32_MAX in UnwindAssemblyInstruction (#168339)Felipe de Azevedo Piovezan
2025-11-14[lldb] fix parallel module loading deadlock for Linux DYLD (#166480)Tom Yang
Another attempt at resolving the deadlock issue @GeorgeHuyubo discovered (his previous [attempt](https://github.com/llvm/llvm-project/pull/160225)). This change can be summarized as the following: * Plumb through a boolean flag to force no preload in `GetOrCreateModules` all the way through to `LoadModuleAtAddress`. * Parallelize `Module::PreloadSymbols` separately from `Target::GetOrCreateModule` and its caller `LoadModuleAtAddress` (this is what avoids the deadlock). These changes roughly maintain the performance characteristics of the previous implementation of parallel module loading. Testing on targets with between 5000 and 14000 modules, I saw similar numbers as before, often more than 10% faster in the new implementation across multiple trials for these massive targets. I think it's because we have less lock contention with this approach. # The deadlock See [bt.txt](https://github.com/user-attachments/files/22524471/bt.txt) for a sample backtrace of LLDB when the deadlock occurs. As @GeorgeHuyubo explains in his [PR](https://github.com/llvm/llvm-project/pull/160225), the deadlock occurs from an ABBA deadlock that happens when a thread context-switches out of `Module::PreloadSymbols`, goes into `Target::GetOrCreateModule` for another module, possibly entering this block: ``` if (!module_sp) { // The platform is responsible for finding and caching an appropriate // module in the shared module cache. if (m_platform_sp) { error = m_platform_sp->GetSharedModule( module_spec, m_process_sp.get(), module_sp, &search_paths, &old_modules, &did_create_module); } else { error = Status::FromErrorString("no platform is currently set"); } } ``` `Module::PreloadSymbols` holds a module-level mutex, and then `GetSharedModule` *attempts* to hold the mutex of the global shared `ModuleList`. So, this thread holds the module mutex, and waits on the global shared `ModuleList` mutex. A competing thread may execute `Target::GetOrCreateModule`, enter the same block as above, grabbing the global shared `ModuleList` mutex. Then, in `ModuleList::GetSharedModule`, we eventually call `ModuleList::FindModules` which eventually waits for the `Module` mutex held by the first thread (via `Module::GetUUID`). Thus, we deadlock. ## Reproducing the deadlock It might be worth noting that I've never been able to observe this deadlock issue during live debugging (e.g. launching or attaching to processes), however we were able to consistently reproduce this issue with coredumps when using the following settings: ``` (lldb) settings set target.parallel-module-load true (lldb) settings set target.preload-symbols true (lldb) settings set symbols.load-on-demand false (lldb) target create --core /some/core/file/here # deadlock happens ``` ## How this change avoids this deadlock This change avoids concurrent executions of `Module::PreloadSymbols` with `Target::GetOrCreateModule` by waiting until after the `Target::GetOrCreateModule` executions to run `Module::PreloadSymbols` in parallel. This avoids the ordering of holding a Module lock *then* the ModuleList lock, as `Target::GetOrCreateModule` executions maintain the ordering of the shared ModuleList lock first (from what I've read and tested). ## Why not read-write lock? Some feedback in https://github.com/llvm/llvm-project/pull/160225 was to modify mutexes used in these components with read-write locks. This might be a good idea overall, but I don't think it would *easily* resolve this specific deadlock. `Module::PreloadSymbols` would probably need a write lock to Module, so even if we had a read lock in `Module::GetUUID` we would still contend. Maybe the `ModuleList` lock could be a read lock that converts to a write lock if it chooses to update the module, but it seems likely that some thread would try to update the shared module list and then the write lock would contend again. Perhaps with deeper architectural changes, we could fix this issue? # Other attempts One downside of this approach (and the former approach of parallel module loading) is that each DYLD would need to implement this pattern themselves. With @clayborg's help, I looked at a few other approaches: * In `Target::GetOrCreateModule`, backgrounding the `Module::PreloadSymbols` call by adding it directly to the thread pool via `Debugger::GetThreadPool().async()`. This required adding a lock to `Module::SetLoadAddress` (probably should be one there already) since `ObjectFileELF::SetLoadAddress` is not thread-safe (updates sections). Unfortunately, during execution, this causes the preload symbols to run synchronously with `Target::GetOrCreateModule`, preventing us from truly parallelizing the execution. * In `Module::PreloadSymbols`, backgrounding the `symtab` and `sym_file` `PreloadSymbols` calls individually, but similar issues as the above. * Passing a callback function like https://github.com/swiftlang/llvm-project/pull/10746 instead of the boolean I use in this change. It's functionally the same change IMO, with some design tradeoffs: * Pro: the caller doesn't need to explicitly call `Module::PreloadSymbols` itself, and can instead call whatever function is passed into the callback. * Con: the caller needs to delay the execution of the callback such that it occurs after the `GetOrCreateModule` logic, otherwise we run into the same issue. I thought this would be trickier for the caller, requiring some kinda condition variable or otherwise storing the calls to execute afterwards. # Test Plan: ``` ninja check-lldb ``` --------- Co-authored-by: Tom Yang <toyang@fb.com>
2025-11-14[lldb][nfc] Simplify instruction iteration in UnwindAssemblyInstEmulation ↵Felipe de Azevedo Piovezan
(#167914)
2025-11-12[lldb][Language] Pass SymbolNameFitsToLanguage parameter by const-ref (#167684)Michael Buch
We've been seeing (rare) crashes from both `CPlusPlusLanguage::SymbolNameFitsToLanguage` and `ObjCLanguage::SymbolNameFitsToLanguage` when we try to read contents of the `ConstString`s of the `Mangled` parameter. I'm not entirely sure how that can happen (current theory is corrupted stack somehow which overwrites `ConstString::m_string` to an invalid pointer) but I'm not able to confirm that. One thing these crashes had in common is that they operate on the `Mangled` object we copied into `SymbolNameFitsToLanguage` by value. While I can't see off the top why that would cause it to contain unintiailized/corrupt `ConstString`s, the class is sufficiently large enough to probably pass it by `const &` anyway. This is what this patch does. rdar://164519648
2025-11-12Revert "[lldb] Introduce ScriptedFrameProvider for real threads" (#167662)Michael Buch
The new test fails on x86 and arm64 public macOS bots: ``` 09:27:59 ====================================================================== 09:27:59 FAIL: test_append_frames (TestScriptedFrameProvider.ScriptedFrameProviderTestCase) 09:27:59 Test that we can add frames after real stack. 09:27:59 ---------------------------------------------------------------------- 09:27:59 Traceback (most recent call last): 09:27:59 File "/Users/ec2-user/jenkins/workspace/llvm.org/as-lldb-cmake/llvm-project/lldb/test/API/functionalities/scripted_frame_provider/TestScriptedFrameProvider.py", line 122, in test_append_frames 09:27:59 self.assertEqual(new_frame_count, original_frame_count + 1) 09:27:59 AssertionError: 5 != 6 09:27:59 Config=arm64-/Users/ec2-user/jenkins/workspace/llvm.org/as-lldb-cmake/lldb-build/bin/clang 09:27:59 ====================================================================== 09:27:59 FAIL: test_applies_to_thread (TestScriptedFrameProvider.ScriptedFrameProviderTestCase) 09:27:59 Test that applies_to_thread filters which threads get the provider. 09:27:59 ---------------------------------------------------------------------- 09:27:59 Traceback (most recent call last): 09:27:59 File "/Users/ec2-user/jenkins/workspace/llvm.org/as-lldb-cmake/llvm-project/lldb/test/API/functionalities/scripted_frame_provider/TestScriptedFrameProvider.py", line 218, in test_applies_to_thread 09:27:59 self.assertEqual( 09:27:59 AssertionError: 5 != 1 : Thread with ID 1 should have 1 synthetic frame 09:27:59 Config=arm64-/Users/ec2-user/jenkins/workspace/llvm.org/as-lldb-cmake/lldb-build/bin/clang 09:27:59 ====================================================================== 09:27:59 FAIL: test_prepend_frames (TestScriptedFrameProvider.ScriptedFrameProviderTestCase) 09:27:59 Test that we can add frames before real stack. 09:27:59 ---------------------------------------------------------------------- 09:27:59 Traceback (most recent call last): 09:27:59 File "/Users/ec2-user/jenkins/workspace/llvm.org/as-lldb-cmake/llvm-project/lldb/test/API/functionalities/scripted_frame_provider/TestScriptedFrameProvider.py", line 84, in test_prepend_frames 09:27:59 self.assertEqual(new_frame_count, original_frame_count + 2) 09:27:59 AssertionError: 5 != 7 09:27:59 Config=arm64-/Users/ec2-user/jenkins/workspace/llvm.org/as-lldb-cmake/lldb-build/bin/clang 09:27:59 ====================================================================== 09:27:59 FAIL: test_remove_frame_provider_by_id (TestScriptedFrameProvider.ScriptedFrameProviderTestCase) 09:27:59 Test that RemoveScriptedFrameProvider removes a specific provider by ID. 09:27:59 ---------------------------------------------------------------------- 09:27:59 Traceback (most recent call last): 09:27:59 File "/Users/ec2-user/jenkins/workspace/llvm.org/as-lldb-cmake/llvm-project/lldb/test/API/functionalities/scripted_frame_provider/TestScriptedFrameProvider.py", line 272, in test_remove_frame_provider_by_id 09:27:59 self.assertEqual(thread.GetNumFrames(), 3, "Should have 3 synthetic frames") 09:27:59 AssertionError: 5 != 3 : Should have 3 synthetic frames 09:27:59 Config=arm64-/Users/ec2-user/jenkins/workspace/llvm.org/as-lldb-cmake/lldb-build/bin/clang 09:27:59 ====================================================================== 09:27:59 FAIL: test_replace_all_frames (TestScriptedFrameProvider.ScriptedFrameProviderTestCase) 09:27:59 Test that we can replace the entire stack. 09:27:59 ---------------------------------------------------------------------- 09:27:59 Traceback (most recent call last): 09:27:59 File "/Users/ec2-user/jenkins/workspace/llvm.org/as-lldb-cmake/llvm-project/lldb/test/API/functionalities/scripted_frame_provider/TestScriptedFrameProvider.py", line 41, in test_replace_all_frames 09:27:59 self.assertEqual(thread.GetNumFrames(), 3, "Should have 3 synthetic frames") 09:27:59 AssertionError: 5 != 3 : Should have 3 synthetic frames 09:27:59 Config=arm64-/Users/ec2-user/jenkins/workspace/llvm.org/as-lldb-cmake/lldb-build/bin/clang 09:27:59 ====================================================================== 09:27:59 FAIL: test_scripted_frame_objects (TestScriptedFrameProvider.ScriptedFrameProviderTestCase) 09:27:59 Test that provider can return ScriptedFrame objects. 09:27:59 ---------------------------------------------------------------------- 09:27:59 Traceback (most recent call last): 09:27:59 File "/Users/ec2-user/jenkins/workspace/llvm.org/as-lldb-cmake/llvm-project/lldb/test/API/functionalities/scripted_frame_provider/TestScriptedFrameProvider.py", line 159, in test_scripted_frame_objects 09:27:59 self.assertEqual(frame0.GetFunctionName(), "custom_scripted_frame_0") 09:27:59 AssertionError: 'thread_func(int)' != 'custom_scripted_frame_0' 09:27:59 - thread_func(int) 09:27:59 + custom_scripted_frame_0 09:27:59 09:27:59 Config=arm64-/Users/ec2-user/jenkins/workspace/llvm.org/as-lldb-cmake/lldb-build/bin/clang 09:27:59 ---------------------------------------------------------------------- 09:27:59 Ran 6 tests in 14.242s 09:27:59 09:27:59 FAILED (failures=6) ``` Reverts llvm/llvm-project#161870
2025-11-11[lldb] Introduce ScriptedFrameProvider for real threads (#161870)Med Ismail Bennani
This patch extends ScriptedFrame to work with real (non-scripted) threads, enabling frame providers to synthesize frames for native processes. Previously, ScriptedFrame only worked within ScriptedProcess/ScriptedThread contexts. This patch decouples ScriptedFrame from ScriptedThread, allowing users to augment or replace stack frames in real debugging sessions for use cases like custom calling conventions, reconstructing corrupted frames from core files, or adding diagnostic frames. Key changes: - ScriptedFrame::Create() now accepts ThreadSP instead of requiring ScriptedThread, extracting architecture from the target triple rather than ScriptedProcess.arch - Added SBTarget::RegisterScriptedFrameProvider() and ClearScriptedFrameProvider() APIs, with Target storing a SyntheticFrameProviderDescriptor template for new threads - Added "target frame-provider register/clear" commands for CLI access - Thread class gains LoadScriptedFrameProvider(), ClearScriptedFrameProvider(), and GetFrameProvider() methods for per-thread frame provider management - New SyntheticStackFrameList overrides FetchFramesUpTo() to lazily provide frames from either the frame provider or the real stack This enables practical use of the SyntheticFrameProvider infrastructure in real debugging workflows. rdar://161834688 Signed-off-by: Med Ismail Bennani <ismail@bennani.ma> Signed-off-by: Med Ismail Bennani <ismail@bennani.ma>
2025-11-10[lldb] Fix crash in BreakpointSite::BumpHitCounts (#166876)Jonas Devlieghere
Fix crash in `BreakpointSite::BumpHitCounts` due to missing synchronization. When bumping the hit count, we were correctly acquiring the constituents mutex, but didn't protect the breakpoint location collection. This PR fixes the issue by making the iterator returned by the collection a `LockingAdaptedIterable`. rdar://163760832
2025-11-08Fix missing include from #166664Walter Lee
2025-11-06[LLDB] Fix debuginfo ELF files overwriting Unified Section List (#166635)Jacob Lalonde
Recently I've been deep diving ELF cores in LLDB, aspiring to move LLDB closer to GDB in capability. One issue I encountered was a system lib losing it's unwind plan when loading the debuginfo. The reason for this was the debuginfo has the eh_frame section stripped and the main executable did not. The root cause of this was this line in [ObjectFileElf](https://github.com/llvm/llvm-project/blob/163933e9e7099f352ff8df1973f9a9c3d7def6c5/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp#L1972) ``` // For eTypeDebugInfo files, the Symbol Vendor will take care of updating the // unified section list. if (GetType() != eTypeDebugInfo) unified_section_list = *m_sections_up; ``` This would always be executed because CalculateType can never return an eTypeDebugInfo ``` ObjectFile::Type ObjectFileELF::CalculateType() { switch (m_header.e_type) { case llvm::ELF::ET_NONE: // 0 - No file type return eTypeUnknown; case llvm::ELF::ET_REL: // 1 - Relocatable file return eTypeObjectFile; case llvm::ELF::ET_EXEC: // 2 - Executable file return eTypeExecutable; case llvm::ELF::ET_DYN: // 3 - Shared object file return eTypeSharedLibrary; case ET_CORE: // 4 - Core file return eTypeCoreFile; default: break; } return eTypeUnknown; } ``` This makes sense as there isn't a explicit sh_type to denote that this file is a debuginfo. After some discussion with @clayborg and @GeorgeHuyubo we settled on joining the exciting unified section list with whatever new sections were being added. Adding each new unique section, or taking the section with the maximum file size. We picked this strategy to pick the section with the most information. In most scenarios, LHS should be SHT_NOBITS and RHS would be SHT_PROGBITS. Here is a diagram documenting the existing vs proposed new way. <img width="1666" height="1093" alt="image" src="https://github.com/user-attachments/assets/73ba9620-c737-439e-9934-ac350d88a3b5" />
2025-11-06[lldb] Add function to tell if a section is a GOT section (#165936)Augusto Noronha
A global offset table is a section that holds the address of functions that are dynamically linked. The Swift plugin needs to know if sections are a global offset table or not.
2025-11-06[lldb] Enable locate module callback for all module loading (#160199)GeorgeHuyubo
Main executables were bypassing the locate module callback that shared libraries use, preventing custom symbol file location logic from working consistently. This PR fix this by * Adding target context to ModuleSpec * Leveraging that context to use target search path and platform's locate module callback in ModuleList::GetSharedModule This ensures both main executables and shared libraries get the same callback treatment for symbol file resolution. --------- Co-authored-by: George Hu <hyubo@meta.com> Co-authored-by: George Hu <georgehuyubo@gmail.com>
2025-11-06[lldb/Interpreter] Implement ScriptedFrameProvider{,Python}Interface (#166662)Med Ismail Bennani
This patch implements the base and python interface for the ScriptedFrameProvider class. This is necessary to call python APIs from the ScriptedFrameProvider that will come in a follow-up. Signed-off-by: Med Ismail Bennani <ismail@bennani.ma> Signed-off-by: Med Ismail Bennani <ismail@bennani.ma>
2025-11-06[lldb/Target] Add SyntheticFrameProvider class (#166664)Med Ismail Bennani
This patch introduces a new way to reconstruct the thread stackframe list. New `SyntheticFrameProvider` classes can lazy fetch a StackFrame at index using a provided StackFrameList. In can either be the real unwinder StackFrameList or we could also chain SyntheticFrameProviders to each others. This is the foundation work to implement ScriptedFrameProviders, which will come in a follow-up patch. Signed-off-by: Med Ismail Bennani <ismail@bennani.ma> Signed-off-by: Med Ismail Bennani <ismail@bennani.ma>
2025-11-05[lldb] Introduce SBFrameList for lazy frame iteration (#166651)Med Ismail Bennani
This patch introduces `SBFrameList`, a new SBAPI class that allows iterating over stack frames lazily without calling `SBThread::GetFrameAtIndex` in a loop. The new `SBThread::GetFrames()` method returns an `SBFrameList` that supports Python iteration (`for frame in frame_list:`), indexing (`frame_list[0]`, `frame_list[-1]`), and length queries (`len()`). The implementation uses `StackFrameListSP` as the opaque pointer, sharing the thread's underlying frame list to ensure frames are materialized on-demand. This is particularly useful for ScriptedFrameProviders, where user scripts will be to iterate, filter, and replace frames lazily without materializing the entire stack upfront. Signed-off-by: Med Ismail Bennani <ismail@bennani.ma>
2025-11-05[lldb] Mark single-argument SourceLanguage constructors explicit (#166527)Michael Buch
This avoids unintentional comparisons between `SourceLanguage` and `LanguageType`. Also marks `operator bool` explicit so we don't implicitly convert to bool.
2025-11-04[lldb][Runtime] Move VerboseTrapFrameRecognizer into CPPLanguageRuntime ↵Michael Buch
(#166157) https://github.com/llvm/llvm-project/pull/165996 is adding a Clang dependency to Target because we're moving some of the functionality of the VerboseTrapFrameRecognizer into libClang. To avoid adding this dependency this patch moves VerboseTrapFrameRecognizer into the CPPLanguageRuntime. Most of the frame recognizers already live in the various runtime plugins. An alternative discussed was to create a common `CLanguageRuntime` whose currently sole responsibility was to register the `VerboseTrapFrameRecognizer` and `AssertStackFrameRecognizer`. The main issue I ran into here was frame recognizers aren't uniqued in the target. Currently this only manifests when re-running a target, which re-triggers all the recognizer registration (added a test with a FIXME for this). If we had a common `CLanguageRuntime` that `CPPLanguageRuntime` and `ObjCLanguageRuntime` inherited from, I didn't find a great way to avoid registering the recognizer multiple times. We can't just call_once on it because we do want the recognisers to be re-registered for new targets in the same debugger session. If the recognisers were stored in something like a UniqueVector in the Target, then we wouldn't have that issue. But currently that's not the case, and it would take a bit of refactoring to de-dupe the recognisers. There may very well be solutions I haven't considered, but all the things I've tried so far I wasn't very happy with. So in the end I just moved this to the C++ runtime for now in order to unblock https://github.com/llvm/llvm-project/pull/165996. The C++ language runtime is always available (even for C targets) if the C++ language plugin is available. Which it should also be unless someone is using an LLDB with the C++ plugin compiled out. But at that point numerous things wouldn't work when even debugging just C.
2025-11-03[NFC][LLDB][BoundsSatety] Add `InstrumentationRuntime::MatchAllModules` ↵Dan Liew
(#166001) This adds a virtual method that allows `InstrumentationRuntime` sub classes to match against all modules rather than just a library that matches a particular regex. When the implementation returns true `GetPatternForRuntimeLibrary()` is ignored and all modules are iterated over. The default implementation returns false which was the previous behavior which uses `GetPatternForRuntimeLibrary()` to only match a particular runtime library. The intended use case here is for implementing an `InstrumentationRuntime` where the runtime library of interest can have multiple implementations and whose name is not known ahead of time. The concrete use case here is for a `InstrumentationRuntime` plugin for implementations of the `-fbounds-safety` soft-trap runtime which can have multiple different implementations and so the module containing the runtime functions isn't known ahead of time. This plug-in will be upstreamed as part of the process of upstreaming `-fbounds-safety`. An alternative to this would be for the `GetPatternForRuntimeLibrary()` function to return a regex that matches everything. While that technically works this new API more clearly indicates in the intent. We probably also save a little perf by not executing the regex match for every loaded module but I have not measured this. rdar://163230807
2025-11-03[lldb] Fix indentation when printing stop hooks (#165945)Julian Lettner
This commit aggregates the following changes: 1. Fix the format (i.e., indentation) when printing stop hooks via `target stop-hook list`. 2. Add `IndentScope Stream::MakeIndentScope()` to make managing (and restoring!) of the indentation level on `Stream` instances more ergonomic and less error prone. 3. Simplify printing of stop hooks using the new `IndentScope`.
2025-10-31[lldb] Emit a progress event from the source manager (#165802)Jonas Devlieghere
Reading a source file might take a while, for example because it's located on a virtual file system that's fetching the data on demand. This PR emits a progress event to convey this to the user when reading the file exceeds a certain threshold (500ms). Although it doesn't speed up the operation, it still greatly improves the user experience by helping them understand what's going on. rdar://163750392
2025-10-31[lldb] Refactor LLDB Breakpoint Event Notifications to centralize and ↵Piyush Jaiswal
eliminate code duplication (#164739) ### Summary This PR refactors breakpoint event notification in LLDB to centralize and eliminate code duplication. It creates a unified method in the `Target` class for sending breakpoint change events. The new methods check if listeners exist before broadcasting events ### Test <img width="1532" height="76" alt="Screenshot 2025-10-23 at 12 49 31 PM" src="https://github.com/user-attachments/assets/6d6a6da6-9684-463c-aeeb-90663cdbd077" /> --------- Co-authored-by: Piyush Jaiswal <piyushjais@meta.com>
2025-10-31[lldb][TypeSystem] Remove count parameter from ↵Michael Buch
TypeSystem::IsFloatingPointType (#165707) Similar motivation to https://github.com/llvm/llvm-project/pull/165702. It was unused in all callsites and inconsistent with other APIs like `IsIntegerType` (which doesn't take a `count` parameter). If we ever need a "how many elements does this type represent", we can implement one with a new TypeSystem API that does exactly that. Some callsites checked for `count == 1` previously, but I suspect what they intended to do is check for whether it's a vector type or complex type, before reading the FP register. I'm somewhat confident that's the case because the `TypeSystemClang::GetTypeInfo` currently incorrectly sets the integer and floating point bits for complex and vector types (will fix separately). But some architectures might choose to pass single-element vectors in scalar registers. I should probably changes these to check the vector element size. All the `count == 2 && is_complex` were redundant because `count == 2` iff `is_complex == true`. So I just removed the count check there.
2025-10-31[lldb][TypeSystem] Remove count parameter from TypeSystem::GetEncoding (#165702)Michael Buch
There were a couple of quirks with this parameter: 1. It wasn't being set consistently. E.g., vector types would be of count `1` but complex types would be `2`. Hence, it wasn't clear what count was referring to. 2. `count` was not being set if the input type was invalid, possibly leaving the input reference uninitialized. 3. Only one callsite actually made use of `count`, and that in itself seems like it could be improved (added a FIXME). If we ever need a "how many elements does this type represent", we can implement one with a new `TypeSystem` API that does exactly that.
2025-10-30[lldb] Add alternative SBThread::GetStopDescription (#165379)Ebuka Ezike
the function signature for `GetStopDescription` is `lldb::SBThread::GetStopDescription(char *dst_or_null, size_t len)`. To get a description you need to call the function first time to get the buffer size. a second time to get the description. This is little worse from the python size as the signature is `lldb.SBThread.GetStopDescription(int: len) -> list[str]` the user has to pass the max size as possible with no way of checking if it is enough. This patch adds a new api `lldb.SBThread.GetStopDescription(desc: lldb.SBStream()) -> bool` `bool lldb::SBThread::GetStopDescription(lldb::SBStream &description)` which handles this case. Adds new Test case for lua.
2025-10-30[NFCI][lldb] Omit redundant member initializer list (#164451)Raul Tambre
These all have member initializers of the same value so they're redundant. Fixes: 47b9aadb3215e914119d0c45827ea58cb7499204
2025-10-29[lldb] Do not narrow `GetIndexOfChildWithName` return type to int (#165453)Ebuka Ezike
Modify the python wrapper to return uint32_t, which prevents incorrect child name-to-index mapping and avoids performing redundant operations on non-existent SBValues.
2025-10-27Avoid stalls when MainLoop::Interrupt fails to wake up the MainLoop (#164905)jimingham
Turns out there's a bug in the current lldb sources that if you fork, set the stdio file handles to close on exec and then exec lldb with some commands and the `--batch` flag, lldb will stall on exit. The first cause of the bug is that the Python session handler - and probably other places in lldb - think 0, 1, and 2 HAVE TO BE the stdio file handles, and open and close and dup them as needed. NB: I am NOT trying to fix that bug. I'm not convinced running the lldb driver headless is worth a lot of effort, it's just as easy to redirect them to /dev/null, which does work. But I would like to keep lldb from stalling on the way out when this happens. The reason we stall is that we have a MainLoop waiting for signals, and we try to Interrupt it, but because stdio was closed, the interrupt pipe for the MainLoop gets the file descriptor 0, which gets closed by the Python session handler if you run some script command. So the Interrupt fails. We were running the Write to the interrupt pipe wrapped in `llvm::cantFail`, but in a no asserts build that just drops the error on the floor. So then lldb went on to call std::thread::join on the still active MainLoop, and that stalls I made Interrupt (and AddCallback & AddPendingCallback) return a bool for "interrupt success" instead. All the places where code was requesting termination, I added checks for that failure, and skip the std::thread::join call on the MainLoop thread, since that is almost certainly going to stall at this point. I didn't do the same for the Windows MainLoop, as I don't know if/when the WSASetEvent call can fail, so I always return true here. I also didn't turn the test off for Windows. According to the Python docs all the API's I used should work on Windows... If that turns out not to be true I'll make the test Darwin/Unix only.
2025-10-24[lldb] Introduce internal stop hooks (#164506)Julian Lettner
Introduce the concept of internal stop hooks. These are similar to LLDB's internal breakpoints: LLDB itself will add them and users of LLDB will not be able to add or remove them. This change adds the following 3 independently-useful concepts: * Maintain a list of internal stop hooks that will be populated by LLDB and cannot be added to or removed from by users. They are managed in a separate list in `Target::m_internal_stop_hooks`. * `StopHookKind:CodeBased` and `StopHookCoded` represent a stop hook defined by a C++ code callback (instead of command line expressions or a Python class). * Stop hooks that do not print any output can now also suppress the printing of their header and description when they are hit via `StopHook::GetSuppressOutput`. Combining these 3 concepts we can model "internal stop hooks" which serve the same function as LLDB's internal breakpoints: executing built-in, LLDB-defined behavior, leveraging the existing mechanism of stop hooks. This change also simplifies `Target::RunStopHooks`. We already have to materialize a new list for combining internal and user stop hooks. Filter and only add active hooks to this list to avoid the need for "isActive?" checks later on.
2025-10-21[lldb-dap] Send a 'process' event on restart. (#163833)John Harrison
When we restart a process, send an updated 'process' event describing the newly launched process. I also updated the `isLocalProcess` value based on if we're on the 'host' platform or not.
2025-10-21[lldb] Implement Process::ReadMemoryRanges (#163651)Felipe de Azevedo Piovezan
This commit introduces a base-class implementation for a method that reads memory from multiple ranges at once. This implementation simply calls the underlying `ReadMemoryFromInferior` method on each requested range, intentionally bypassing the memory caching mechanism (though this may be easily changed in the future). `Process` implementations that can be perform this operation more efficiently - e.g. with the MultiMemPacket described in [1] - are expected to override this method. As an example, this commit changes AppleObjCClassDescriptorV2 to use the new API. Note about the API ------------------ In the RFC, we discussed having the API return some kind of class `ReadMemoryRangesResult`. However, while writing such a class, it became clear that it was merely wrapping a vector, without providing anything useful. For example, this class: ``` struct ReadMemoryRangesResult { ReadMemoryRangesResult( llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> ranges) : ranges(std::move(ranges)) {} llvm::ArrayRef<llvm::MutableArrayRef<uint8_t>> getRanges() const { return ranges; } private: llvm::SmallVector<llvm::MutableArrayRef<uint8_t>> ranges; }; ``` As can be seen in the added test and in the added use-case (AppleObjCClassDescriptorV2), users of this API will just iterate over the vector of memory buffers. So they want a return type that can be iterated over, and the vector seems more natural than creating a new class and defining iterators for it. Likewise, in the RFC, we discussed wrapping the result into an `Expected`. Upon experimenting with the code, this feels like it limits what the API is able to do as the base class implementation never needs to fail the entire result, it's the individual reads that may fail and this is expressed through a zero-length result. Any derived classes overriding `ReadMemoryRanges` should also never produce a top level failure: if they did, they can just fall back to the base class implementation, which would produce a better result. The choice of having the caller allocate a buffer and pass it to `Process::ReadMemoryRanges` is done mostly to follow conventions already done in the Process class. [1]: https://discourse.llvm.org/t/rfc-a-new-vectorized-memory-read-packet/
2025-10-21[lldb][DeclVendor] Remove ClangDeclVendor (#164380)Michael Buch
The `ClangDeclVendor` used to contain more Clang-specific code than it does nowadays. But at this point, all it does is wrap the `DeclVendor::FindDecls` call and copy the resulting decls into `std::vector<clang::NamedDecl*>`. I.e., it converts the generic `CompilerDecl`s to `clang::NamedDecl*`s. In my opinion at this point it doesn't do enough to justify making it part of the `DeclVendor` hierarchy. This patch removes the `ClangDeclVendor` and instead does the conversion at callsite.
2025-10-21[lldb][ValueObject][NFC] Remove unused SyntheticChildrenFrontEnd member ↵Michael Buch
(#164249) These `IsValid`/`SetValid` APIs are only ever used from 1 data-formatter in the Swift LLDB fork. Since all the APIs on `SyntheticChildrenFrontEnd` are meant to be overriden, there is no good way to enforce calling `IsValid` from the base. And we should just let that 1 data-formatter manage its own `IsValid` state.
2025-10-20Fix a potential use-after-free in StopInfoBreakpoint. (#163471)jimingham
StopInfoBreakpoint keeps a BreakpointLocationCollection for all the breakpoint locations at the BreakpointSite that was hit. It is also lives through the time a given thread is stopped, so there are plenty of opportunities for one of the owning breakpoints to get deleted. But BreakpointLocations don't keep their owner Breakpoints alive, so if the BreakpointLocationCollection can live past when some code gets a chance to delete an owner breakpoint, and then you ask that location for some breakpoint information, it will access freed memory. This wasn't a problem before PR #158128 because the StopInfoBreakpoint just kept the BreakpointSite that was hit, and when you asked it questions, it relooked up that list. That was not great, however, because if you hit breakpoints 5 & 6, deleted 5 and then asked which breakpoints got hit, you would just get 6. For that and other reasons that PR changed to storing a BreakpointLocationCollection of the breakpoints that were hit. That's better from a UI perspective but caused this potential problem. I fix it by adding a variant of the BreakpointLocationCollection that also holds onto a shared pointer to the Breakpoints that own the locations that were hit, thus keeping them alive till the StopInfoBreakpoint goes away. This fixed the ASAN assertion. I also added a test that works harder to cause trouble by deleting breakpoints during a stop.
2025-10-20[lldb] Add try_lock to SBMutex (#164109)Jonas Devlieghere
Add `try_lock` to confirm to Lockable, which is necessary to use it with `std::scoped_lock`.
2025-10-17[lldb] Fix misaligned loads violation in DataExtractor (#163880)Alex Langford
The implementation of the templated `Get` function contains UB. For example, the "GetDoubleUnaligned" unit test causes `Get` to perform an unaligned 8 byte read. This violates the `double` alignment requirement. Furthermore, it violates strict aliasing rules in C++. (We construct a `const double *` from a `const uint8_t *` and perform a read on the resulting double pointer). DataExtractor should be able to read unaligned data to deal with different data formats, but we need to be careful to not perform unaligned reads/writes or violate strict aliasing rules. rdar://160385383
2025-10-16[lldb-dap] Improve the runInTerminal ux. (#163830)John Harrison
This updates lldb-dap to clear the screen when using `"console": "integratedTerminal"` or `"console": "externalTerminal"`. VSCode will reuse the same terminal for a given debug configuration. After the process exits it will return to the shell but if the debug session is launched again it will be invoked in the same terminal. VSCode is sending the terminal the launch args as terminal input which means the terminal would now have a string like `lldb-dap --comm-file ... --launch-target ...` and the scrollback buffer from any previous output or shell commands used in the terminal. To address this, I've updated LaunchRunInTerminalTarget to reset the cursor, clear the screen and clear the scrollback buffer to soft 'reset' the terminal prior to launching the process. --------- Co-authored-by: Jonas Devlieghere <jonas@devlieghere.com>
2025-10-15[lldb] Correct bridgeOS -> BridgeOS spelling (#163479)Jonas Devlieghere
The BridgeOS SDK is capitalized, but previously failed to parse because we were looking for bridgeOS. This PR updates the enum value and the canonical spelling. rdar://162641896
2025-10-14[lldb][Darwin] Add `process launch --memory-tagging` option (#162944)Julian Lettner
For debugging and bug-finding workflows on Darwin, support launching processes with memory tagging for binaries that are not entitled. This will cause the process to behave as if the binary was entitled with: ``` <key>com.apple.security.hardened-process.checked-allocations</key> <true/> ``` This has no effect on hardware without MTE support. --------- Co-authored-by: Jonas Devlieghere <jonas@devlieghere.com>
2025-10-13[lldb] Support OSC escape codes for native progress (#162162)Jonas Devlieghere
This PR adds support for emitting the OSC `9;4` sequences to show a GUI native progress bar. There's a limited number of terminal emulators that support this, so for now this requires explicit opt-in through a setting. I'm reusing the existing `show-progress` setting, which became a NOOP with the introduction of the statusline. The option now defaults to off. Implements #160369
2025-10-10[lldb] Add a missing <atomic> include. NFC. (#162809)Martin Storsjö
This fixes building LLDB for mingw with libstdc++, after 8ae30a3facd25c9c7c2cfb96b69466a6c4d22baa. Previously, building errored out with errors like these: In file included from llvm-project/lldb/include/lldb/Protocol/MCP/Transport.h:12, from llvm-project/lldb/include/lldb/Protocol/MCP/Server.h:16, from llvm-project/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.h:15, from llvm-project/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.cpp:9: llvm-project/lldb/include/lldb/Host/JSONTransport.h:608:23: error: field ‘replied’ has incomplete type ‘std::atomic<bool>’ 608 | std::atomic<bool> replied = {false}; | ^~~~~~~ In file included from gcc-mingw/x86_64-w64-mingw32/include/c++/12.1.0/bits/shared_ptr_atomic.h:33, from gcc-mingw/x86_64-w64-mingw32/include/c++/12.1.0/memory:78, from llvm-project/lldb/include/lldb/Host/Socket.h:12, from llvm-project/lldb/include/lldb/Core/ProtocolServer.h:13, from llvm-project/lldb/source/Plugins/Protocol/MCP/ProtocolServerMCP.h:12: gcc-mingw/x86_64-w64-mingw32/include/c++/12.1.0/bits/atomic_base.h:162:12: note: declaration of ‘struct std::atomic<bool>’ 162 | struct atomic; | ^~~~~~
2025-10-09Add a scripted way to re-present a stop location (#158128)jimingham
This patch adds the notion of "Facade" locations which can be reported from a ScriptedResolver instead of the actual underlying breakpoint location for the breakpoint. Also add a "was_hit" method to the scripted resolver that allows the breakpoint to say which of these "Facade" locations was hit, and "get_location_description" to provide a description for the facade locations. I apologize in advance for the size of the patch. Almost all of what's here was necessary to (a) make the feature testable and (b) not break any of the current behavior. The motivation for this feature is given in the "Providing Facade Locations" section that I added to the python-reference.rst so I won't repeat it here. rdar://152112327
2025-10-08[lldb] Fix use after free on ModuleList::RemoveSharedModuleIfOrphaned (#155331)Augusto Noronha
This fixes a potential use after free where ModuleList::RemoveSharedModuleIfOrphaned -> SharedModuleList::RemoveIfOrphaned -> SharedModuleList::RemoveFromMap would potentially dereference a freed pointer. This fixes it by not calling ModuleList::RemoveSharedModuleIfOrphaned at all if the pointer was just freed.
2025-10-07Fix an API that was changed w/o changing the header doc (#162401)jimingham
This was causing bot failures if you build with -Werror -Wdocumentation. Fix the docs to reflect the new headers.