[Lldb-commits] [lldb] [lldb] Fix a typo in documentation (PR #146115)
https://github.com/kazutakahirata closed https://github.com/llvm/llvm-project/pull/146115 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] 9f5061d - [lldb] Fix a typo in documentation (#146115)
Author: Kazu Hirata Date: 2025-06-27T14:26:32-07:00 New Revision: 9f5061d4f00456d882db9eb606f4a82b2c40e7a8 URL: https://github.com/llvm/llvm-project/commit/9f5061d4f00456d882db9eb606f4a82b2c40e7a8 DIFF: https://github.com/llvm/llvm-project/commit/9f5061d4f00456d882db9eb606f4a82b2c40e7a8.diff LOG: [lldb] Fix a typo in documentation (#146115) Added: Modified: lldb/docs/resources/contributing.rst Removed: diff --git a/lldb/docs/resources/contributing.rst b/lldb/docs/resources/contributing.rst index e7d46c9061d53..7e84df41c3fbd 100644 --- a/lldb/docs/resources/contributing.rst +++ b/lldb/docs/resources/contributing.rst @@ -104,7 +104,7 @@ making sense for the particular pair of plugins). Unfortunately, due to historic reasons, not all plugin dependencies follow this rule, which is why we have another category called `LLDB_TOLERATED_PLUGIN_DEPENDENCIES`. New dependencies are forbidden (even though they are accepted by CMake) and existing ones should -be removed whereever possible. +be removed wherever possible. .. _Error handling: ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Fix evaluating expressions without JIT in an object context (PR #145599)
https://github.com/igorkudrin closed https://github.com/llvm/llvm-project/pull/145599 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] 442f99d - [lldb] Fix evaluating expressions without JIT in an object context (#145599)
Author: Igor Kudrin Date: 2025-06-27T14:30:24-07:00 New Revision: 442f99d7698a4ca87ebb16cb22df610c45d4698a URL: https://github.com/llvm/llvm-project/commit/442f99d7698a4ca87ebb16cb22df610c45d4698a DIFF: https://github.com/llvm/llvm-project/commit/442f99d7698a4ca87ebb16cb22df610c45d4698a.diff LOG: [lldb] Fix evaluating expressions without JIT in an object context (#145599) If a server does not support allocating memory in an inferior process or when debugging a core file, evaluating an expression in the context of a value object results in an error: ``` error: :43:1: use of undeclared identifier '$__lldb_class' 43 | $__lldb_class::$__lldb_expr(void *$__lldb_arg) | ^ ``` Such expressions require a live address to be stored in the value object. However, `EntityResultVariable::Dematerialize()` only sets `ret->m_live_sp` if JIT is available, even if the address points to the process memory and no custom allocations were made. Similarly, `EntityPersistentVariable::Dematerialize()` tries to deallocate memory based on the same check, resulting in an error if the memory was not previously allocated in `EntityPersistentVariable::Materialize()`. As an unintended bonus, the patch also fixes a FIXME case in `TestCxxChar8_t.py`. Added: lldb/test/API/functionalities/postmortem/elf-core/expr/TestExpr.py lldb/test/API/functionalities/postmortem/elf-core/expr/linux-x86_64.core lldb/test/API/functionalities/postmortem/elf-core/expr/linux-x86_64.out lldb/test/API/functionalities/postmortem/elf-core/expr/main.cpp Modified: lldb/include/lldb/Expression/IRMemoryMap.h lldb/source/Expression/IRMemoryMap.cpp lldb/source/Expression/Materializer.cpp lldb/test/API/lang/cpp/char8_t/TestCxxChar8_t.py Removed: diff --git a/lldb/include/lldb/Expression/IRMemoryMap.h b/lldb/include/lldb/Expression/IRMemoryMap.h index acbffd1e40b94..58b95c56c1c36 100644 --- a/lldb/include/lldb/Expression/IRMemoryMap.h +++ b/lldb/include/lldb/Expression/IRMemoryMap.h @@ -51,10 +51,13 @@ class IRMemoryMap { ///only in the process. }; + // If 'policy' is 'eAllocationPolicyMirror' but it is impossible to allocate + // memory in the process, 'eAllocationPolicyHostOnly' will be used instead. + // The actual policy is returned via 'used_policy'. llvm::Expected Malloc(size_t size, uint8_t alignment, uint32_t permissions, - AllocationPolicy policy, - bool zero_memory); + AllocationPolicy policy, bool zero_memory, + AllocationPolicy *used_policy = nullptr); void Leak(lldb::addr_t process_address, Status &error); void Free(lldb::addr_t process_address, Status &error); diff --git a/lldb/source/Expression/IRMemoryMap.cpp b/lldb/source/Expression/IRMemoryMap.cpp index f500272cfb302..150699352a2e3 100644 --- a/lldb/source/Expression/IRMemoryMap.cpp +++ b/lldb/source/Expression/IRMemoryMap.cpp @@ -319,10 +319,10 @@ IRMemoryMap::Allocation::Allocation(lldb::addr_t process_alloc, } } -llvm::Expected IRMemoryMap::Malloc(size_t size, uint8_t alignment, - uint32_t permissions, - AllocationPolicy policy, - bool zero_memory) { +llvm::Expected +IRMemoryMap::Malloc(size_t size, uint8_t alignment, uint32_t permissions, +AllocationPolicy policy, bool zero_memory, +AllocationPolicy *used_policy) { lldb_private::Log *log(GetLog(LLDBLog::Expressions)); lldb::ProcessSP process_sp; @@ -454,6 +454,9 @@ llvm::Expected IRMemoryMap::Malloc(size_t size, uint8_t alignment, (uint64_t)permissions, policy_string, aligned_address); } + if (used_policy) +*used_policy = policy; + return aligned_address; } diff --git a/lldb/source/Expression/Materializer.cpp b/lldb/source/Expression/Materializer.cpp index 96add56f92180..17ea1596806d0 100644 --- a/lldb/source/Expression/Materializer.cpp +++ b/lldb/source/Expression/Materializer.cpp @@ -75,11 +75,12 @@ class EntityPersistentVariable : public Materializer::Entity { // contents. const bool zero_memory = false; +IRMemoryMap::AllocationPolicy used_policy; auto address_or_error = map.Malloc( llvm::expectedToOptional(m_persistent_variable_sp->GetByteSize()) .value_or(0), 8, lldb::ePermissionsReadable | lldb::ePermissionsWritable, -IRMemoryMap::eAllocationPolicyMirror, zero_memory); +IRMemoryMap::eAllocationPolicyMirror, zero_memory, &used_policy); if (!address_or_error) { err = Status::FromErrorStringWithFormat( "couldn't allocate a memory area to store %
[Lldb-commits] [lldb] Add option to not loading all DWOs when dumping separate_debug-info (PR #146166)
llvmbot wrote: @llvm/pr-subscribers-lldb Author: None (qxy11) Changes ### Summary Currently `target modules dump separate separate-debug-info` automatically loads up all DWO files, even if deferred loading is enabled through debug_names. Then, as expected all DWO files (assuming there is no error loading it), get marked as "loaded". This change adds the option `--defer-load-all-debug-info` or `--d` for short to dump this debug info without loading it up, if it hasn't been loaded yet, so that the correct DWO files will show up for each modules as "loaded" or not "loaded", which could be helpful in cases such as when DWO files are not getting loaded eagerly for correctly labeling files as loaded or not loaded. ### Testing Unit Tests Added additional unit tests `test_dwos_defer_loaded_json_with_debug_names` and `test_dwos_loaded_symbols_on_demand_defer_load_all`. ``` bin/lldb-dotest -p TestDumpDwo ~/llvm-project/lldb/test/API/commands/target/dump-separate-debug-info/dwo ``` Manual Testing Compiled a simple binary w/ `--gsplit-dwarf --gpubnames` and loaded it up: ``` (lldb) target create "./a.out" Current executable set to '/home/qxy11/hello-world/a.out' (x86_64). (lldb) help target modules dump separate-debug-info List the separate debug info symbol files for one or more target modules. Syntax: target modules dump separate-debug-info[ [ [...]]] Command Options Usage: target modules dump separate-debug-info [-dej] [ [ [...]]] -d ( --defer-load-all-debug-info ) Defer loading all debug info files. -e ( --errors-only ) Filter to show only debug info files with errors. -j ( --json ) Output the details in JSON format. This command takes options and free-form arguments. If your arguments resemble option specifiers (i.e., they start with a - or --), you must use ' -- ' between the end of the command options and the beginning of the arguments. (lldb) target modules dump separate-debug-info --j --d [ { "separate-debug-info-files": [ { ... "dwo_name": "main.dwo", "loaded": false }, { ... "dwo_name": "foo.dwo", "loaded": false }, { ... "dwo_name": "bar.dwo", "loaded": false } ], } ] (lldb) b main Breakpoint 1: where = a.out`main + 15 at main.cc:3:12, address = 0x11ff (lldb) target modules dump separate-debug-info --j --d [ { "separate-debug-info-files": [ { ... "dwo_name": "main.dwo", "loaded": true, "resolved_dwo_path": "/home/qxy11/hello-world/main.dwo" }, { ... "dwo_name": "foo.dwo", "loaded": false }, { ... "dwo_name": "bar.dwo", "loaded": false } ], } ] (lldb) b foo Breakpoint 2: where = a.out`foo(int) + 11 at foo.cc:12:11, address = 0x121b (lldb) target modules dump separate-debug-info --j --d [ { "separate-debug-info-files": [ { ... "dwo_name": "main.dwo", "loaded": true, "resolved_dwo_path": "/home/qxy11/hello-world/main.dwo" }, { ... "dwo_name": "foo.dwo", "loaded": true, "resolved_dwo_path": "/home/qxy11/hello-world/foo.dwo" }, { ... "dwo_name": "bar.dwo", "loaded": false } ], } ] (lldb) b bar Breakpoint 3: where = a.out`bar(int) + 11 at bar.cc:10:9, address = 0x126b (lldb) target modules dump separate-debug-info --j --d [ { "separate-debug-info-files": [ { ... "dwo_name": "main.dwo", "loaded": true, "resolved_dwo_path": "/home/qxy11/hello-world/main.dwo" }, { ... "dwo_name": "foo.dwo", "loaded": true, "resolved_dwo_path": "/home/qxy11/hello-world/foo.dwo" }, { ... "dwo_name": "bar.dwo", "loaded": true, "resolved_dwo_path": "/home/qxy11/hello-world/bar.dwo" } ], } ] ``` --- Full diff: https://github.com/llvm/llvm-project/pull/146166.diff 10 Files Affected: - (modified) lldb/include/lldb/Symbol/SymbolFile.h (+4-1) - (modified) lldb/include/lldb/Symbol/SymbolFileOnDemand.h (+4-3) - (modified) lldb/source/Commands/CommandObjectTarget.cpp (+41-24) - (modified) lldb/source/Commands/Options.td (+3) - (modified) lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp (+3-2) - (modified) lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h (+2-2) - (modified) lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp (+2-1) - (modified) lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h (+2-2) - (modified) lldb/test/API/commands/target/dump-separate-debug-info/dwo/Makefile (+1-1) - (modified) lldb/test/API/commands/target/dump-separate-debug-info/dwo/TestDumpDwo.py (+75-2) ``diff diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/incl
[Lldb-commits] [lldb] [lldb] Adding file and pipe support to lldb_private::MainLoopWindows. (PR #145621)
https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/145621 >From 79c10b6f6630b3ceaa85af45956aeafdf372b5be Mon Sep 17 00:00:00 2001 From: John Harrison Date: Wed, 25 Jun 2025 18:03:39 -0700 Subject: [PATCH 1/5] [lldb] Adding file and pipe support to lldb_private::MainLoopWindows. This updates MainLoopWindows to support events for reading from a file and a socket type. This unifies both handle types using WaitForMultipleEvents which can listen to both sockets and files for change events. This should allow us to unify how we handle watching files/pipes/sockets on Windows and Posix systems. --- lldb/include/lldb/Host/File.h | 2 + lldb/include/lldb/Host/Socket.h | 2 + .../lldb/Host/windows/MainLoopWindows.h | 3 +- lldb/include/lldb/Utility/IOObject.h | 8 +- lldb/source/Host/common/File.cpp | 18 +++ lldb/source/Host/common/Socket.cpp| 49 +++- .../posix/ConnectionFileDescriptorPosix.cpp | 14 ++- lldb/source/Host/windows/MainLoopWindows.cpp | 116 +- lldb/source/Utility/IOObject.cpp | 9 ++ lldb/unittests/Host/FileTest.cpp | 16 ++- lldb/unittests/Host/MainLoopTest.cpp | 26 11 files changed, 190 insertions(+), 73 deletions(-) diff --git a/lldb/include/lldb/Host/File.h b/lldb/include/lldb/Host/File.h index 9e2d0abe0b1af..36cb192281289 100644 --- a/lldb/include/lldb/Host/File.h +++ b/lldb/include/lldb/Host/File.h @@ -127,6 +127,7 @@ class File : public IOObject { /// \return /// a valid handle or IOObject::kInvalidHandleValue WaitableHandle GetWaitableHandle() override; + bool HasReadableData() override; /// Get the file specification for this file, if possible. /// @@ -400,6 +401,7 @@ class NativeFile : public File { Status Write(const void *buf, size_t &num_bytes) override; Status Close() override; WaitableHandle GetWaitableHandle() override; + bool HasReadableData() override; Status GetFileSpec(FileSpec &file_spec) const override; int GetDescriptor() const override; FILE *GetStream() override; diff --git a/lldb/include/lldb/Host/Socket.h b/lldb/include/lldb/Host/Socket.h index 89953ee7fd5b6..6569e9e6ea818 100644 --- a/lldb/include/lldb/Host/Socket.h +++ b/lldb/include/lldb/Host/Socket.h @@ -158,6 +158,7 @@ class Socket : public IOObject { bool IsValid() const override { return m_socket != kInvalidSocketValue; } WaitableHandle GetWaitableHandle() override; + bool HasReadableData() override; static llvm::Expected DecodeHostAndPort(llvm::StringRef host_and_port); @@ -185,6 +186,7 @@ class Socket : public IOObject { SocketProtocol m_protocol; NativeSocket m_socket; + WaitableHandle m_waitable_handle; bool m_should_close_fd; }; diff --git a/lldb/include/lldb/Host/windows/MainLoopWindows.h b/lldb/include/lldb/Host/windows/MainLoopWindows.h index 3937a24645d95..43b7d13a0e445 100644 --- a/lldb/include/lldb/Host/windows/MainLoopWindows.h +++ b/lldb/include/lldb/Host/windows/MainLoopWindows.h @@ -37,11 +37,10 @@ class MainLoopWindows : public MainLoopBase { void Interrupt() override; private: - void ProcessReadObject(IOObject::WaitableHandle handle); llvm::Expected Poll(); struct FdInfo { -void *event; +lldb::IOObjectSP object_sp; Callback callback; }; llvm::DenseMap m_read_fds; diff --git a/lldb/include/lldb/Utility/IOObject.h b/lldb/include/lldb/Utility/IOObject.h index 8cf42992e7be5..48a8a2076581f 100644 --- a/lldb/include/lldb/Utility/IOObject.h +++ b/lldb/include/lldb/Utility/IOObject.h @@ -14,6 +14,7 @@ #include #include "lldb/lldb-private.h" +#include "lldb/lldb-types.h" namespace lldb_private { @@ -24,9 +25,9 @@ class IOObject { eFDTypeSocket, // Socket requiring send/recv }; - // TODO: On Windows this should be a HANDLE, and wait should use - // WaitForMultipleObjects - typedef int WaitableHandle; + // A handle for integrating with the host event loop model. + using WaitableHandle = lldb::file_t; + static const WaitableHandle kInvalidHandleValue; IOObject(FDType type) : m_fd_type(type) {} @@ -40,6 +41,7 @@ class IOObject { FDType GetFdType() const { return m_fd_type; } virtual WaitableHandle GetWaitableHandle() = 0; + virtual bool HasReadableData() = 0; protected: FDType m_fd_type; diff --git a/lldb/source/Host/common/File.cpp b/lldb/source/Host/common/File.cpp index 9aa95ffda44cb..2d33f9e2028c4 100644 --- a/lldb/source/Host/common/File.cpp +++ b/lldb/source/Host/common/File.cpp @@ -118,6 +118,8 @@ IOObject::WaitableHandle File::GetWaitableHandle() { return IOObject::kInvalidHandleValue; } +bool File::HasReadableData() { return false; } + Status File::GetFileSpec(FileSpec &file_spec) const { file_spec.Clear(); return std::error_code(ENOTSUP, std::system_category()); @@ -274,7 +276,23 @@ int NativeFile::GetDescriptor() const { } IOObject::WaitableHandle N
[Lldb-commits] [lldb] Add option to not loading all DWOs when dumping separate_debug-info (PR #146166)
https://github.com/qxy11 created https://github.com/llvm/llvm-project/pull/146166 ### Summary Currently `target modules dump separate separate-debug-info` automatically loads up all DWO files, even if deferred loading is enabled through debug_names. Then, as expected all DWO files (assuming there is no error loading it), get marked as "loaded". This change adds the option `--defer-load-all-debug-info` or `--d` for short to dump this debug info without loading it up, if it hasn't been loaded yet, so that the correct DWO files will show up for each modules as "loaded" or not "loaded", which could be helpful in cases such as when DWO files are not getting loaded eagerly for correctly labeling files as loaded or not loaded. ### Testing Unit Tests Added additional unit tests `test_dwos_defer_loaded_json_with_debug_names` and `test_dwos_loaded_symbols_on_demand_defer_load_all`. ``` bin/lldb-dotest -p TestDumpDwo ~/llvm-project/lldb/test/API/commands/target/dump-separate-debug-info/dwo ``` Manual Testing Compiled a simple binary w/ `--gsplit-dwarf --gpubnames` and loaded it up: ``` (lldb) target create "./a.out" Current executable set to '/home/qxy11/hello-world/a.out' (x86_64). (lldb) help target modules dump separate-debug-info List the separate debug info symbol files for one or more target modules. Syntax: target modules dump separate-debug-info [ [ [...]]] Command Options Usage: target modules dump separate-debug-info [-dej] [ [ [...]]] -d ( --defer-load-all-debug-info ) Defer loading all debug info files. -e ( --errors-only ) Filter to show only debug info files with errors. -j ( --json ) Output the details in JSON format. This command takes options and free-form arguments. If your arguments resemble option specifiers (i.e., they start with a - or --), you must use ' -- ' between the end of the command options and the beginning of the arguments. (lldb) target modules dump separate-debug-info --j --d [ { "separate-debug-info-files": [ { ... "dwo_name": "main.dwo", "loaded": false }, { ... "dwo_name": "foo.dwo", "loaded": false }, { ... "dwo_name": "bar.dwo", "loaded": false } ], } ] (lldb) b main Breakpoint 1: where = a.out`main + 15 at main.cc:3:12, address = 0x11ff (lldb) target modules dump separate-debug-info --j --d [ { "separate-debug-info-files": [ { ... "dwo_name": "main.dwo", "loaded": true, "resolved_dwo_path": "/home/qxy11/hello-world/main.dwo" }, { ... "dwo_name": "foo.dwo", "loaded": false }, { ... "dwo_name": "bar.dwo", "loaded": false } ], } ] (lldb) b foo Breakpoint 2: where = a.out`foo(int) + 11 at foo.cc:12:11, address = 0x121b (lldb) target modules dump separate-debug-info --j --d [ { "separate-debug-info-files": [ { ... "dwo_name": "main.dwo", "loaded": true, "resolved_dwo_path": "/home/qxy11/hello-world/main.dwo" }, { ... "dwo_name": "foo.dwo", "loaded": true, "resolved_dwo_path": "/home/qxy11/hello-world/foo.dwo" }, { ... "dwo_name": "bar.dwo", "loaded": false } ], } ] (lldb) b bar Breakpoint 3: where = a.out`bar(int) + 11 at bar.cc:10:9, address = 0x126b (lldb) target modules dump separate-debug-info --j --d [ { "separate-debug-info-files": [ { ... "dwo_name": "main.dwo", "loaded": true, "resolved_dwo_path": "/home/qxy11/hello-world/main.dwo" }, { ... "dwo_name": "foo.dwo", "loaded": true, "resolved_dwo_path": "/home/qxy11/hello-world/foo.dwo" }, { ... "dwo_name": "bar.dwo", "loaded": true, "resolved_dwo_path": "/home/qxy11/hello-world/bar.dwo" } ], } ] ``` >From 65cdc870c365592f354663eabf1a009e4bdd3c52 Mon Sep 17 00:00:00 2001 From: Janet Yang Date: Wed, 18 Jun 2025 15:58:10 -0700 Subject: [PATCH] Add defer-load-all-debug-info option to dumping separate_debug-info The target modules dump separate separate-debug-info option automatically loads up all DWO files, even if deferred loading is enabled through debug_names. This adds the option to get the debug info without loading it up, if it hasn't been loaded yet, so that the correct DWO files will show up for each modules as "loaded" or not "loaded", which could be more informational to the user. --- lldb/include/lldb/Symbol/SymbolFile.h | 5 +- lldb/include/lldb/Symbol/SymbolFileOnDemand.h | 7 +- lldb/source/Commands/CommandObjectTarget.cpp | 65 ++-- lldb/source/Commands/Options.td | 3 + .../SymbolFile/DWARF/SymbolFileDWARF.cpp | 5 +- .../SymbolFile/DWARF/SymbolFileDWARF.h| 4 +- .../DWARF/SymbolFileDWARFDe
[Lldb-commits] [lldb] [lldb] Adding pipe support to lldb_private::MainLoopWindows. (PR #145621)
https://github.com/ashgti edited https://github.com/llvm/llvm-project/pull/145621 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb][Mach-O] Allow "process metadata" LC_NOTE to supply registers (PR #144627)
https://github.com/jasonmolenda updated https://github.com/llvm/llvm-project/pull/144627 >From 92348b28fb02901e9437b92c1ddf8cfed31c Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Tue, 17 Jun 2025 18:57:11 -0700 Subject: [PATCH 01/13] [lldb][Mach-O] Allow "process metadata" LC_NOTE to supply registers The "process metadata" LC_NOTE allows for thread IDs to be specified in a Mach-O corefile. This extends the JSON recognzied in that LC_NOTE to allow for additional registers to be supplied on a per-thread basis. The registers included in a Mach-O corefile LC_THREAD load command can only be one of the register flavors that the kernel (xnu) defines in for arm64 -- the general purpose registers, floating point registers, exception registers. JTAG style corefile producers may have access to many additional registers beyond these that EL0 programs typically use, for instance TCR_EL1 on AArch64, and people developing low level code need access to these registers. This patch defines a format for including these registers for any thread. The JSON in "process metadata" is a dictionary that must have a `threads` key. The value is an array of entries, one per LC_THREAD in the Mach-O corefile. The number of entries must match the LC_THREADs so they can be correctly associated. Each thread's dictionary must have two keys, `sets`, and `registers`. `sets` is an array of register set names. If a register set name matches one from the LC_THREAD core registers, any registers that are defined will be added to that register set. e.g. metadata can add a register to the "General Purpose Registers" set that lldb shows users. `registers` is an array of dictionaries, one per register. Each register must have the keys `name`, `value`, `bitsize`, and `set`. It may provide additional keys like `alt-name`, that `DynamicRegisterInfo::SetRegisterInfo` recognizes. This `sets` + `registers` formatting is the same that is used by the `target.process.python-os-plugin-path` script interface uses, both are parsed by `DynamicRegisterInfo`. The one addition is that in this LC_NOTE metadata, each register must also have a `value` field, with the value provided in big-endian base 10, as usual with JSON. In RegisterContextUnifiedCore, I combine the register sets & registers from the LC_THREAD for a specific thread, and the metadata sets & registers for that thread from the LC_NOTE. Even if no LC_NOTE is present, this class ingests the LC_THREAD register contexts and reformats it to its internal stores before returning itself as the RegisterContex, instead of shortcutting and returning the core's native RegisterContext. I could have gone either way with that, but in the end I decided if the code is correct, we should live on it always. I added a test where we process save-core to create a userland corefile, then use a utility "add-lcnote" to strip the existing "process metadata" LC_NOTE that lldb put in it, and adds a new one from a JSON string. rdar://74358787 --- lldb/include/lldb/Symbol/ObjectFile.h | 17 +- .../ObjectFile/Mach-O/ObjectFileMachO.cpp | 61 ++- .../ObjectFile/Mach-O/ObjectFileMachO.h | 2 + .../Plugins/Process/mach-core/CMakeLists.txt | 1 + .../mach-core/RegisterContextUnifiedCore.cpp | 293 + .../mach-core/RegisterContextUnifiedCore.h| 57 +++ .../Process/mach-core/ThreadMachCore.cpp | 55 ++- .../lc-note/additional-registers/Makefile | 11 + .../TestMetadataRegisters.py | 100 + .../additional-registers/add-lcnote.cpp | 384 ++ .../lc-note/additional-registers/main.c | 11 + 11 files changed, 957 insertions(+), 35 deletions(-) create mode 100644 lldb/source/Plugins/Process/mach-core/RegisterContextUnifiedCore.cpp create mode 100644 lldb/source/Plugins/Process/mach-core/RegisterContextUnifiedCore.h create mode 100644 lldb/test/API/macosx/lc-note/additional-registers/Makefile create mode 100644 lldb/test/API/macosx/lc-note/additional-registers/TestMetadataRegisters.py create mode 100644 lldb/test/API/macosx/lc-note/additional-registers/add-lcnote.cpp create mode 100644 lldb/test/API/macosx/lc-note/additional-registers/main.c diff --git a/lldb/include/lldb/Symbol/ObjectFile.h b/lldb/include/lldb/Symbol/ObjectFile.h index 43567592dd447..1b9ae1fb31a69 100644 --- a/lldb/include/lldb/Symbol/ObjectFile.h +++ b/lldb/include/lldb/Symbol/ObjectFile.h @@ -18,6 +18,7 @@ #include "lldb/Utility/Endian.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/FileSpecList.h" +#include "lldb/Utility/StructuredData.h" #include "lldb/Utility/UUID.h" #include "lldb/lldb-private.h" #include "llvm/Support/Threading.h" @@ -544,9 +545,9 @@ class ObjectFile : public std::enable_shared_from_this, return false; } - /// Get metadata about threads from the corefile. + /// Get metadata about thread ids from the corefile. /// - /// The corefile may have metadata (e.g. a Mach-O "thread ext
[Lldb-commits] [lldb] Add option to not loading all DWOs when dumping separate_debug-info (PR #146166)
@@ -2547,6 +2561,7 @@ class CommandObjectTargetModulesDumpSeparateDebugInfoFiles OptionValueBoolean m_json = false; OptionValueBoolean m_errors_only = false; +OptionValueBoolean m_load_all_debug_info = true; dmpots wrote: I wonder if it would be better to disable loading all of the debug info by default. Then instead of adding the `--defer-load-all-debug-info` flag we could add a flag like `--force-load-all-debug-info` that would force loading it. It seems a bit odd to me that a `dump` command would modify state like this by default by loading up the debug info instead of reporting the current state. But this would be a behavior change from the current lldb so maybe not desirable. @JDevlieghere @jeffreytan81 @clayborg any thoughts on this? https://github.com/llvm/llvm-project/pull/146166 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb][Mach-O] Allow "process metadata" LC_NOTE to supply registers (PR #144627)
https://github.com/jasonmolenda updated https://github.com/llvm/llvm-project/pull/144627 >From 92348b28fb02901e9437b92c1ddf8cfed31c Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Tue, 17 Jun 2025 18:57:11 -0700 Subject: [PATCH 01/17] [lldb][Mach-O] Allow "process metadata" LC_NOTE to supply registers The "process metadata" LC_NOTE allows for thread IDs to be specified in a Mach-O corefile. This extends the JSON recognzied in that LC_NOTE to allow for additional registers to be supplied on a per-thread basis. The registers included in a Mach-O corefile LC_THREAD load command can only be one of the register flavors that the kernel (xnu) defines in for arm64 -- the general purpose registers, floating point registers, exception registers. JTAG style corefile producers may have access to many additional registers beyond these that EL0 programs typically use, for instance TCR_EL1 on AArch64, and people developing low level code need access to these registers. This patch defines a format for including these registers for any thread. The JSON in "process metadata" is a dictionary that must have a `threads` key. The value is an array of entries, one per LC_THREAD in the Mach-O corefile. The number of entries must match the LC_THREADs so they can be correctly associated. Each thread's dictionary must have two keys, `sets`, and `registers`. `sets` is an array of register set names. If a register set name matches one from the LC_THREAD core registers, any registers that are defined will be added to that register set. e.g. metadata can add a register to the "General Purpose Registers" set that lldb shows users. `registers` is an array of dictionaries, one per register. Each register must have the keys `name`, `value`, `bitsize`, and `set`. It may provide additional keys like `alt-name`, that `DynamicRegisterInfo::SetRegisterInfo` recognizes. This `sets` + `registers` formatting is the same that is used by the `target.process.python-os-plugin-path` script interface uses, both are parsed by `DynamicRegisterInfo`. The one addition is that in this LC_NOTE metadata, each register must also have a `value` field, with the value provided in big-endian base 10, as usual with JSON. In RegisterContextUnifiedCore, I combine the register sets & registers from the LC_THREAD for a specific thread, and the metadata sets & registers for that thread from the LC_NOTE. Even if no LC_NOTE is present, this class ingests the LC_THREAD register contexts and reformats it to its internal stores before returning itself as the RegisterContex, instead of shortcutting and returning the core's native RegisterContext. I could have gone either way with that, but in the end I decided if the code is correct, we should live on it always. I added a test where we process save-core to create a userland corefile, then use a utility "add-lcnote" to strip the existing "process metadata" LC_NOTE that lldb put in it, and adds a new one from a JSON string. rdar://74358787 --- lldb/include/lldb/Symbol/ObjectFile.h | 17 +- .../ObjectFile/Mach-O/ObjectFileMachO.cpp | 61 ++- .../ObjectFile/Mach-O/ObjectFileMachO.h | 2 + .../Plugins/Process/mach-core/CMakeLists.txt | 1 + .../mach-core/RegisterContextUnifiedCore.cpp | 293 + .../mach-core/RegisterContextUnifiedCore.h| 57 +++ .../Process/mach-core/ThreadMachCore.cpp | 55 ++- .../lc-note/additional-registers/Makefile | 11 + .../TestMetadataRegisters.py | 100 + .../additional-registers/add-lcnote.cpp | 384 ++ .../lc-note/additional-registers/main.c | 11 + 11 files changed, 957 insertions(+), 35 deletions(-) create mode 100644 lldb/source/Plugins/Process/mach-core/RegisterContextUnifiedCore.cpp create mode 100644 lldb/source/Plugins/Process/mach-core/RegisterContextUnifiedCore.h create mode 100644 lldb/test/API/macosx/lc-note/additional-registers/Makefile create mode 100644 lldb/test/API/macosx/lc-note/additional-registers/TestMetadataRegisters.py create mode 100644 lldb/test/API/macosx/lc-note/additional-registers/add-lcnote.cpp create mode 100644 lldb/test/API/macosx/lc-note/additional-registers/main.c diff --git a/lldb/include/lldb/Symbol/ObjectFile.h b/lldb/include/lldb/Symbol/ObjectFile.h index 43567592dd447..1b9ae1fb31a69 100644 --- a/lldb/include/lldb/Symbol/ObjectFile.h +++ b/lldb/include/lldb/Symbol/ObjectFile.h @@ -18,6 +18,7 @@ #include "lldb/Utility/Endian.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/FileSpecList.h" +#include "lldb/Utility/StructuredData.h" #include "lldb/Utility/UUID.h" #include "lldb/lldb-private.h" #include "llvm/Support/Threading.h" @@ -544,9 +545,9 @@ class ObjectFile : public std::enable_shared_from_this, return false; } - /// Get metadata about threads from the corefile. + /// Get metadata about thread ids from the corefile. /// - /// The corefile may have metadata (e.g. a Mach-O "thread ext
[Lldb-commits] [lldb] [lldb][Mach-O] Allow "process metadata" LC_NOTE to supply registers (PR #144627)
https://github.com/jasonmolenda updated https://github.com/llvm/llvm-project/pull/144627 >From 92348b28fb02901e9437b92c1ddf8cfed31c Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Tue, 17 Jun 2025 18:57:11 -0700 Subject: [PATCH 01/16] [lldb][Mach-O] Allow "process metadata" LC_NOTE to supply registers The "process metadata" LC_NOTE allows for thread IDs to be specified in a Mach-O corefile. This extends the JSON recognzied in that LC_NOTE to allow for additional registers to be supplied on a per-thread basis. The registers included in a Mach-O corefile LC_THREAD load command can only be one of the register flavors that the kernel (xnu) defines in for arm64 -- the general purpose registers, floating point registers, exception registers. JTAG style corefile producers may have access to many additional registers beyond these that EL0 programs typically use, for instance TCR_EL1 on AArch64, and people developing low level code need access to these registers. This patch defines a format for including these registers for any thread. The JSON in "process metadata" is a dictionary that must have a `threads` key. The value is an array of entries, one per LC_THREAD in the Mach-O corefile. The number of entries must match the LC_THREADs so they can be correctly associated. Each thread's dictionary must have two keys, `sets`, and `registers`. `sets` is an array of register set names. If a register set name matches one from the LC_THREAD core registers, any registers that are defined will be added to that register set. e.g. metadata can add a register to the "General Purpose Registers" set that lldb shows users. `registers` is an array of dictionaries, one per register. Each register must have the keys `name`, `value`, `bitsize`, and `set`. It may provide additional keys like `alt-name`, that `DynamicRegisterInfo::SetRegisterInfo` recognizes. This `sets` + `registers` formatting is the same that is used by the `target.process.python-os-plugin-path` script interface uses, both are parsed by `DynamicRegisterInfo`. The one addition is that in this LC_NOTE metadata, each register must also have a `value` field, with the value provided in big-endian base 10, as usual with JSON. In RegisterContextUnifiedCore, I combine the register sets & registers from the LC_THREAD for a specific thread, and the metadata sets & registers for that thread from the LC_NOTE. Even if no LC_NOTE is present, this class ingests the LC_THREAD register contexts and reformats it to its internal stores before returning itself as the RegisterContex, instead of shortcutting and returning the core's native RegisterContext. I could have gone either way with that, but in the end I decided if the code is correct, we should live on it always. I added a test where we process save-core to create a userland corefile, then use a utility "add-lcnote" to strip the existing "process metadata" LC_NOTE that lldb put in it, and adds a new one from a JSON string. rdar://74358787 --- lldb/include/lldb/Symbol/ObjectFile.h | 17 +- .../ObjectFile/Mach-O/ObjectFileMachO.cpp | 61 ++- .../ObjectFile/Mach-O/ObjectFileMachO.h | 2 + .../Plugins/Process/mach-core/CMakeLists.txt | 1 + .../mach-core/RegisterContextUnifiedCore.cpp | 293 + .../mach-core/RegisterContextUnifiedCore.h| 57 +++ .../Process/mach-core/ThreadMachCore.cpp | 55 ++- .../lc-note/additional-registers/Makefile | 11 + .../TestMetadataRegisters.py | 100 + .../additional-registers/add-lcnote.cpp | 384 ++ .../lc-note/additional-registers/main.c | 11 + 11 files changed, 957 insertions(+), 35 deletions(-) create mode 100644 lldb/source/Plugins/Process/mach-core/RegisterContextUnifiedCore.cpp create mode 100644 lldb/source/Plugins/Process/mach-core/RegisterContextUnifiedCore.h create mode 100644 lldb/test/API/macosx/lc-note/additional-registers/Makefile create mode 100644 lldb/test/API/macosx/lc-note/additional-registers/TestMetadataRegisters.py create mode 100644 lldb/test/API/macosx/lc-note/additional-registers/add-lcnote.cpp create mode 100644 lldb/test/API/macosx/lc-note/additional-registers/main.c diff --git a/lldb/include/lldb/Symbol/ObjectFile.h b/lldb/include/lldb/Symbol/ObjectFile.h index 43567592dd447..1b9ae1fb31a69 100644 --- a/lldb/include/lldb/Symbol/ObjectFile.h +++ b/lldb/include/lldb/Symbol/ObjectFile.h @@ -18,6 +18,7 @@ #include "lldb/Utility/Endian.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/FileSpecList.h" +#include "lldb/Utility/StructuredData.h" #include "lldb/Utility/UUID.h" #include "lldb/lldb-private.h" #include "llvm/Support/Threading.h" @@ -544,9 +545,9 @@ class ObjectFile : public std::enable_shared_from_this, return false; } - /// Get metadata about threads from the corefile. + /// Get metadata about thread ids from the corefile. /// - /// The corefile may have metadata (e.g. a Mach-O "thread ext
[Lldb-commits] [lldb] [lldb][Mach-O] Allow "process metadata" LC_NOTE to supply registers (PR #144627)
https://github.com/jasonmolenda updated https://github.com/llvm/llvm-project/pull/144627 >From 92348b28fb02901e9437b92c1ddf8cfed31c Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Tue, 17 Jun 2025 18:57:11 -0700 Subject: [PATCH 01/15] [lldb][Mach-O] Allow "process metadata" LC_NOTE to supply registers The "process metadata" LC_NOTE allows for thread IDs to be specified in a Mach-O corefile. This extends the JSON recognzied in that LC_NOTE to allow for additional registers to be supplied on a per-thread basis. The registers included in a Mach-O corefile LC_THREAD load command can only be one of the register flavors that the kernel (xnu) defines in for arm64 -- the general purpose registers, floating point registers, exception registers. JTAG style corefile producers may have access to many additional registers beyond these that EL0 programs typically use, for instance TCR_EL1 on AArch64, and people developing low level code need access to these registers. This patch defines a format for including these registers for any thread. The JSON in "process metadata" is a dictionary that must have a `threads` key. The value is an array of entries, one per LC_THREAD in the Mach-O corefile. The number of entries must match the LC_THREADs so they can be correctly associated. Each thread's dictionary must have two keys, `sets`, and `registers`. `sets` is an array of register set names. If a register set name matches one from the LC_THREAD core registers, any registers that are defined will be added to that register set. e.g. metadata can add a register to the "General Purpose Registers" set that lldb shows users. `registers` is an array of dictionaries, one per register. Each register must have the keys `name`, `value`, `bitsize`, and `set`. It may provide additional keys like `alt-name`, that `DynamicRegisterInfo::SetRegisterInfo` recognizes. This `sets` + `registers` formatting is the same that is used by the `target.process.python-os-plugin-path` script interface uses, both are parsed by `DynamicRegisterInfo`. The one addition is that in this LC_NOTE metadata, each register must also have a `value` field, with the value provided in big-endian base 10, as usual with JSON. In RegisterContextUnifiedCore, I combine the register sets & registers from the LC_THREAD for a specific thread, and the metadata sets & registers for that thread from the LC_NOTE. Even if no LC_NOTE is present, this class ingests the LC_THREAD register contexts and reformats it to its internal stores before returning itself as the RegisterContex, instead of shortcutting and returning the core's native RegisterContext. I could have gone either way with that, but in the end I decided if the code is correct, we should live on it always. I added a test where we process save-core to create a userland corefile, then use a utility "add-lcnote" to strip the existing "process metadata" LC_NOTE that lldb put in it, and adds a new one from a JSON string. rdar://74358787 --- lldb/include/lldb/Symbol/ObjectFile.h | 17 +- .../ObjectFile/Mach-O/ObjectFileMachO.cpp | 61 ++- .../ObjectFile/Mach-O/ObjectFileMachO.h | 2 + .../Plugins/Process/mach-core/CMakeLists.txt | 1 + .../mach-core/RegisterContextUnifiedCore.cpp | 293 + .../mach-core/RegisterContextUnifiedCore.h| 57 +++ .../Process/mach-core/ThreadMachCore.cpp | 55 ++- .../lc-note/additional-registers/Makefile | 11 + .../TestMetadataRegisters.py | 100 + .../additional-registers/add-lcnote.cpp | 384 ++ .../lc-note/additional-registers/main.c | 11 + 11 files changed, 957 insertions(+), 35 deletions(-) create mode 100644 lldb/source/Plugins/Process/mach-core/RegisterContextUnifiedCore.cpp create mode 100644 lldb/source/Plugins/Process/mach-core/RegisterContextUnifiedCore.h create mode 100644 lldb/test/API/macosx/lc-note/additional-registers/Makefile create mode 100644 lldb/test/API/macosx/lc-note/additional-registers/TestMetadataRegisters.py create mode 100644 lldb/test/API/macosx/lc-note/additional-registers/add-lcnote.cpp create mode 100644 lldb/test/API/macosx/lc-note/additional-registers/main.c diff --git a/lldb/include/lldb/Symbol/ObjectFile.h b/lldb/include/lldb/Symbol/ObjectFile.h index 43567592dd447..1b9ae1fb31a69 100644 --- a/lldb/include/lldb/Symbol/ObjectFile.h +++ b/lldb/include/lldb/Symbol/ObjectFile.h @@ -18,6 +18,7 @@ #include "lldb/Utility/Endian.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/FileSpecList.h" +#include "lldb/Utility/StructuredData.h" #include "lldb/Utility/UUID.h" #include "lldb/lldb-private.h" #include "llvm/Support/Threading.h" @@ -544,9 +545,9 @@ class ObjectFile : public std::enable_shared_from_this, return false; } - /// Get metadata about threads from the corefile. + /// Get metadata about thread ids from the corefile. /// - /// The corefile may have metadata (e.g. a Mach-O "thread ext
[Lldb-commits] [lldb] [lldb][RPC] Upstream lldb-rpc-gen tool (PR #138031)
https://github.com/bulbazord approved this pull request. Let's get this patch in and iterate on the tool. Please watch the bots after landing. https://github.com/llvm/llvm-project/pull/138031 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Adding pipe support to lldb_private::MainLoopWindows. (PR #145621)
https://github.com/ashgti edited https://github.com/llvm/llvm-project/pull/145621 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb][Mach-O] Allow "process metadata" LC_NOTE to supply registers (PR #144627)
https://github.com/jasonmolenda updated https://github.com/llvm/llvm-project/pull/144627 >From 92348b28fb02901e9437b92c1ddf8cfed31c Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Tue, 17 Jun 2025 18:57:11 -0700 Subject: [PATCH 01/14] [lldb][Mach-O] Allow "process metadata" LC_NOTE to supply registers The "process metadata" LC_NOTE allows for thread IDs to be specified in a Mach-O corefile. This extends the JSON recognzied in that LC_NOTE to allow for additional registers to be supplied on a per-thread basis. The registers included in a Mach-O corefile LC_THREAD load command can only be one of the register flavors that the kernel (xnu) defines in for arm64 -- the general purpose registers, floating point registers, exception registers. JTAG style corefile producers may have access to many additional registers beyond these that EL0 programs typically use, for instance TCR_EL1 on AArch64, and people developing low level code need access to these registers. This patch defines a format for including these registers for any thread. The JSON in "process metadata" is a dictionary that must have a `threads` key. The value is an array of entries, one per LC_THREAD in the Mach-O corefile. The number of entries must match the LC_THREADs so they can be correctly associated. Each thread's dictionary must have two keys, `sets`, and `registers`. `sets` is an array of register set names. If a register set name matches one from the LC_THREAD core registers, any registers that are defined will be added to that register set. e.g. metadata can add a register to the "General Purpose Registers" set that lldb shows users. `registers` is an array of dictionaries, one per register. Each register must have the keys `name`, `value`, `bitsize`, and `set`. It may provide additional keys like `alt-name`, that `DynamicRegisterInfo::SetRegisterInfo` recognizes. This `sets` + `registers` formatting is the same that is used by the `target.process.python-os-plugin-path` script interface uses, both are parsed by `DynamicRegisterInfo`. The one addition is that in this LC_NOTE metadata, each register must also have a `value` field, with the value provided in big-endian base 10, as usual with JSON. In RegisterContextUnifiedCore, I combine the register sets & registers from the LC_THREAD for a specific thread, and the metadata sets & registers for that thread from the LC_NOTE. Even if no LC_NOTE is present, this class ingests the LC_THREAD register contexts and reformats it to its internal stores before returning itself as the RegisterContex, instead of shortcutting and returning the core's native RegisterContext. I could have gone either way with that, but in the end I decided if the code is correct, we should live on it always. I added a test where we process save-core to create a userland corefile, then use a utility "add-lcnote" to strip the existing "process metadata" LC_NOTE that lldb put in it, and adds a new one from a JSON string. rdar://74358787 --- lldb/include/lldb/Symbol/ObjectFile.h | 17 +- .../ObjectFile/Mach-O/ObjectFileMachO.cpp | 61 ++- .../ObjectFile/Mach-O/ObjectFileMachO.h | 2 + .../Plugins/Process/mach-core/CMakeLists.txt | 1 + .../mach-core/RegisterContextUnifiedCore.cpp | 293 + .../mach-core/RegisterContextUnifiedCore.h| 57 +++ .../Process/mach-core/ThreadMachCore.cpp | 55 ++- .../lc-note/additional-registers/Makefile | 11 + .../TestMetadataRegisters.py | 100 + .../additional-registers/add-lcnote.cpp | 384 ++ .../lc-note/additional-registers/main.c | 11 + 11 files changed, 957 insertions(+), 35 deletions(-) create mode 100644 lldb/source/Plugins/Process/mach-core/RegisterContextUnifiedCore.cpp create mode 100644 lldb/source/Plugins/Process/mach-core/RegisterContextUnifiedCore.h create mode 100644 lldb/test/API/macosx/lc-note/additional-registers/Makefile create mode 100644 lldb/test/API/macosx/lc-note/additional-registers/TestMetadataRegisters.py create mode 100644 lldb/test/API/macosx/lc-note/additional-registers/add-lcnote.cpp create mode 100644 lldb/test/API/macosx/lc-note/additional-registers/main.c diff --git a/lldb/include/lldb/Symbol/ObjectFile.h b/lldb/include/lldb/Symbol/ObjectFile.h index 43567592dd447..1b9ae1fb31a69 100644 --- a/lldb/include/lldb/Symbol/ObjectFile.h +++ b/lldb/include/lldb/Symbol/ObjectFile.h @@ -18,6 +18,7 @@ #include "lldb/Utility/Endian.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/FileSpecList.h" +#include "lldb/Utility/StructuredData.h" #include "lldb/Utility/UUID.h" #include "lldb/lldb-private.h" #include "llvm/Support/Threading.h" @@ -544,9 +545,9 @@ class ObjectFile : public std::enable_shared_from_this, return false; } - /// Get metadata about threads from the corefile. + /// Get metadata about thread ids from the corefile. /// - /// The corefile may have metadata (e.g. a Mach-O "thread ext
[Lldb-commits] [lldb] [lldb][Mach-O] Allow "process metadata" LC_NOTE to supply registers (PR #144627)
@@ -70,27 +77,49 @@ lldb::RegisterContextSP ThreadMachCore::GetRegisterContext() { lldb::RegisterContextSP ThreadMachCore::CreateRegisterContextForFrame(StackFrame *frame) { - lldb::RegisterContextSP reg_ctx_sp; uint32_t concrete_frame_idx = 0; if (frame) concrete_frame_idx = frame->GetConcreteFrameIndex(); + if (concrete_frame_idx > 0) +return GetUnwinder().CreateRegisterContextForFrame(frame); + + if (m_thread_reg_ctx_sp) +return m_thread_reg_ctx_sp; - if (concrete_frame_idx == 0) { -if (!m_thread_reg_ctx_sp) { - ProcessSP process_sp(GetProcess()); + ProcessSP process_sp(GetProcess()); jasonmolenda wrote: I mean, a Thread that wasn't constructed with a Process, you've got Problems. :) https://github.com/llvm/llvm-project/pull/144627 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb][Mach-O] Allow "process metadata" LC_NOTE to supply registers (PR #144627)
https://github.com/jasonmolenda updated https://github.com/llvm/llvm-project/pull/144627 >From 92348b28fb02901e9437b92c1ddf8cfed31c Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Tue, 17 Jun 2025 18:57:11 -0700 Subject: [PATCH 01/18] [lldb][Mach-O] Allow "process metadata" LC_NOTE to supply registers The "process metadata" LC_NOTE allows for thread IDs to be specified in a Mach-O corefile. This extends the JSON recognzied in that LC_NOTE to allow for additional registers to be supplied on a per-thread basis. The registers included in a Mach-O corefile LC_THREAD load command can only be one of the register flavors that the kernel (xnu) defines in for arm64 -- the general purpose registers, floating point registers, exception registers. JTAG style corefile producers may have access to many additional registers beyond these that EL0 programs typically use, for instance TCR_EL1 on AArch64, and people developing low level code need access to these registers. This patch defines a format for including these registers for any thread. The JSON in "process metadata" is a dictionary that must have a `threads` key. The value is an array of entries, one per LC_THREAD in the Mach-O corefile. The number of entries must match the LC_THREADs so they can be correctly associated. Each thread's dictionary must have two keys, `sets`, and `registers`. `sets` is an array of register set names. If a register set name matches one from the LC_THREAD core registers, any registers that are defined will be added to that register set. e.g. metadata can add a register to the "General Purpose Registers" set that lldb shows users. `registers` is an array of dictionaries, one per register. Each register must have the keys `name`, `value`, `bitsize`, and `set`. It may provide additional keys like `alt-name`, that `DynamicRegisterInfo::SetRegisterInfo` recognizes. This `sets` + `registers` formatting is the same that is used by the `target.process.python-os-plugin-path` script interface uses, both are parsed by `DynamicRegisterInfo`. The one addition is that in this LC_NOTE metadata, each register must also have a `value` field, with the value provided in big-endian base 10, as usual with JSON. In RegisterContextUnifiedCore, I combine the register sets & registers from the LC_THREAD for a specific thread, and the metadata sets & registers for that thread from the LC_NOTE. Even if no LC_NOTE is present, this class ingests the LC_THREAD register contexts and reformats it to its internal stores before returning itself as the RegisterContex, instead of shortcutting and returning the core's native RegisterContext. I could have gone either way with that, but in the end I decided if the code is correct, we should live on it always. I added a test where we process save-core to create a userland corefile, then use a utility "add-lcnote" to strip the existing "process metadata" LC_NOTE that lldb put in it, and adds a new one from a JSON string. rdar://74358787 --- lldb/include/lldb/Symbol/ObjectFile.h | 17 +- .../ObjectFile/Mach-O/ObjectFileMachO.cpp | 61 ++- .../ObjectFile/Mach-O/ObjectFileMachO.h | 2 + .../Plugins/Process/mach-core/CMakeLists.txt | 1 + .../mach-core/RegisterContextUnifiedCore.cpp | 293 + .../mach-core/RegisterContextUnifiedCore.h| 57 +++ .../Process/mach-core/ThreadMachCore.cpp | 55 ++- .../lc-note/additional-registers/Makefile | 11 + .../TestMetadataRegisters.py | 100 + .../additional-registers/add-lcnote.cpp | 384 ++ .../lc-note/additional-registers/main.c | 11 + 11 files changed, 957 insertions(+), 35 deletions(-) create mode 100644 lldb/source/Plugins/Process/mach-core/RegisterContextUnifiedCore.cpp create mode 100644 lldb/source/Plugins/Process/mach-core/RegisterContextUnifiedCore.h create mode 100644 lldb/test/API/macosx/lc-note/additional-registers/Makefile create mode 100644 lldb/test/API/macosx/lc-note/additional-registers/TestMetadataRegisters.py create mode 100644 lldb/test/API/macosx/lc-note/additional-registers/add-lcnote.cpp create mode 100644 lldb/test/API/macosx/lc-note/additional-registers/main.c diff --git a/lldb/include/lldb/Symbol/ObjectFile.h b/lldb/include/lldb/Symbol/ObjectFile.h index 43567592dd447..1b9ae1fb31a69 100644 --- a/lldb/include/lldb/Symbol/ObjectFile.h +++ b/lldb/include/lldb/Symbol/ObjectFile.h @@ -18,6 +18,7 @@ #include "lldb/Utility/Endian.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/FileSpecList.h" +#include "lldb/Utility/StructuredData.h" #include "lldb/Utility/UUID.h" #include "lldb/lldb-private.h" #include "llvm/Support/Threading.h" @@ -544,9 +545,9 @@ class ObjectFile : public std::enable_shared_from_this, return false; } - /// Get metadata about threads from the corefile. + /// Get metadata about thread ids from the corefile. /// - /// The corefile may have metadata (e.g. a Mach-O "thread ext
[Lldb-commits] [lldb] [lldb] Fix evaluating expressions without JIT in an object context (PR #145599)
https://github.com/igorkudrin updated https://github.com/llvm/llvm-project/pull/145599 >From fac89bb1b51496761b156f22dcff85cbe86bf9d2 Mon Sep 17 00:00:00 2001 From: Igor Kudrin Date: Mon, 23 Jun 2025 23:39:52 -0700 Subject: [PATCH 1/2] [lldb] Fix evaluating expressions without JIT in an object context If a server does not support allocating memory in an inferior process or when debugging a core file, evaluating an expression in the context of a value object results in an error: ``` error: :43:1: use of undeclared identifier '$__lldb_class' 43 | $__lldb_class::$__lldb_expr(void *$__lldb_arg) | ^ ``` Such expressions require a live address to be stored in the value object. However, `EntityResultVariable::Dematerialize()` only sets `ret->m_live_sp` if JIT is available, even if the address points to the process memory and no custom allocations were made. Similarly, `EntityPersistentVariable::Dematerialize()` tries to deallocate memory based on the same check, resulting in an error if the memory was not previously allocated in `EntityPersistentVariable::Materialize()`. As an unintended bonus, the patch also fixes a FIXME case in `TestCxxChar8_t.py`. --- lldb/source/Expression/Materializer.cpp | 29 --- .../postmortem/elf-core/expr/TestExpr.py | 48 ++ .../elf-core/expr/linux-x86_64.core | Bin 0 -> 40960 bytes .../postmortem/elf-core/expr/linux-x86_64.out | Bin 0 -> 10816 bytes .../postmortem/elf-core/expr/main.cpp | 15 ++ .../API/lang/cpp/char8_t/TestCxxChar8_t.py| 4 +- 6 files changed, 73 insertions(+), 23 deletions(-) create mode 100644 lldb/test/API/functionalities/postmortem/elf-core/expr/TestExpr.py create mode 100644 lldb/test/API/functionalities/postmortem/elf-core/expr/linux-x86_64.core create mode 100755 lldb/test/API/functionalities/postmortem/elf-core/expr/linux-x86_64.out create mode 100644 lldb/test/API/functionalities/postmortem/elf-core/expr/main.cpp diff --git a/lldb/source/Expression/Materializer.cpp b/lldb/source/Expression/Materializer.cpp index 79c804c6c4214..5f0dcd42289f6 100644 --- a/lldb/source/Expression/Materializer.cpp +++ b/lldb/source/Expression/Materializer.cpp @@ -329,22 +329,10 @@ class EntityPersistentVariable : public Materializer::Entity { return; } -lldb::ProcessSP process_sp = -map.GetBestExecutionContextScope()->CalculateProcess(); -if (!process_sp || !process_sp->CanJIT()) { - // Allocations are not persistent so persistent variables cannot stay - // materialized. - - m_persistent_variable_sp->m_flags |= - ExpressionVariable::EVNeedsAllocation; - - DestroyAllocation(map, err); - if (!err.Success()) -return; -} else if (m_persistent_variable_sp->m_flags & - ExpressionVariable::EVNeedsAllocation && - !(m_persistent_variable_sp->m_flags & - ExpressionVariable::EVKeepInTarget)) { +if (m_persistent_variable_sp->m_flags & +ExpressionVariable::EVNeedsAllocation && +!(m_persistent_variable_sp->m_flags & + ExpressionVariable::EVKeepInTarget)) { DestroyAllocation(map, err); if (!err.Success()) return; @@ -1086,9 +1074,8 @@ class EntityResultVariable : public Materializer::Entity { m_delegate->DidDematerialize(ret); } -bool can_persist = -(m_is_program_reference && process_sp && process_sp->CanJIT() && - !(address >= frame_bottom && address < frame_top)); +bool can_persist = m_is_program_reference && + !(address >= frame_bottom && address < frame_top); if (can_persist && m_keep_in_memory) { ret->m_live_sp = ValueObjectConstResult::Create(exe_scope, m_type, name, @@ -1118,7 +1105,9 @@ class EntityResultVariable : public Materializer::Entity { map.Free(m_temporary_allocation, free_error); } } else { - ret->m_flags |= ExpressionVariable::EVIsLLDBAllocated; + ret->m_flags |= m_is_program_reference + ? ExpressionVariable::EVIsProgramReference + : ExpressionVariable::EVIsLLDBAllocated; } m_temporary_allocation = LLDB_INVALID_ADDRESS; diff --git a/lldb/test/API/functionalities/postmortem/elf-core/expr/TestExpr.py b/lldb/test/API/functionalities/postmortem/elf-core/expr/TestExpr.py new file mode 100644 index 0..b397359e7a476 --- /dev/null +++ b/lldb/test/API/functionalities/postmortem/elf-core/expr/TestExpr.py @@ -0,0 +1,48 @@ +""" +Test evaluating expressions when debugging core file. +""" + +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +@skipIfLLVMTargetMissing("X86") +class CoreExprTestCase(TestBase): +def test_result_var(self): +"""Test that the result variable can be used in subsequent expressions.""" + +target = self.dbg.CreateT
[Lldb-commits] [lldb] Add option to not loading all DWOs when dumping separate_debug-info (PR #146166)
@@ -2030,7 +2032,8 @@ class CommandObjectTargetModulesDumpSymtab } if (INTERRUPT_REQUESTED(GetDebugger(), "Interrupted in dump all symtabs with {0} " - "of {1} dumped.", num_dumped, num_modules)) + "of {1} dumped.", dmpots wrote: It looks like there are some formatting changes here that are not related to the functional change. We should split those out into a separate NFC PR if we want to include them. It looks like all the `INTERRRUPT_REQUESTED` changes fall into that category. https://github.com/llvm/llvm-project/pull/146166 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Adding file and pipe support to lldb_private::MainLoopWindows. (PR #145621)
ashgti wrote: On my windows VM, all tests are passing now and it looks like this is also working for Linux. I think the current CI check is a no-op on Windows for lldb. https://github.com/llvm/llvm-project/pull/145621 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Document MCP support in LLDB (PR #145935)
https://github.com/adrian-prantl approved this pull request. https://github.com/llvm/llvm-project/pull/145935 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb][RPC] Upstream lldb-rpc-gen tool (PR #138031)
https://github.com/chelcassanova updated https://github.com/llvm/llvm-project/pull/138031 >From bf72ec458e7788ddd8d7cb7d42fbf55a9112722f Mon Sep 17 00:00:00 2001 From: Chelsea Cassanova Date: Wed, 30 Apr 2025 14:15:39 -0700 Subject: [PATCH] [lldb][RPC] Upstream lldb-rpc-gen tool This commit upstreams the `lldb-rpc-gen` tool, a ClangTool that generates the LLDB RPC client and server interfaces. https://discourse.llvm.org/t/rfc-upstreaming-lldb-rpc/85804 --- lldb/cmake/modules/LLDBConfig.cmake | 2 + .../Tests/CheckRPCGenToolByproducts.test | 11 + lldb/test/Shell/helper/toolchain.py | 8 + lldb/tools/CMakeLists.txt | 3 + lldb/tools/lldb-rpc/CMakeLists.txt| 22 + lldb/tools/lldb-rpc/LLDBRPCGeneration.cmake | 58 ++ lldb/tools/lldb-rpc/LLDBRPCHeaders.cmake | 101 .../lldb-rpc/lldb-rpc-gen/CMakeLists.txt | 21 + .../tools/lldb-rpc/lldb-rpc-gen/RPCCommon.cpp | 501 ++ lldb/tools/lldb-rpc/lldb-rpc-gen/RPCCommon.h | 108 .../lldb-rpc/lldb-rpc-gen/lldb-rpc-gen.cpp| 341 11 files changed, 1176 insertions(+) create mode 100644 lldb/test/Shell/RPC/Generator/Tests/CheckRPCGenToolByproducts.test create mode 100644 lldb/tools/lldb-rpc/CMakeLists.txt create mode 100644 lldb/tools/lldb-rpc/LLDBRPCGeneration.cmake create mode 100644 lldb/tools/lldb-rpc/LLDBRPCHeaders.cmake create mode 100644 lldb/tools/lldb-rpc/lldb-rpc-gen/CMakeLists.txt create mode 100644 lldb/tools/lldb-rpc/lldb-rpc-gen/RPCCommon.cpp create mode 100644 lldb/tools/lldb-rpc/lldb-rpc-gen/RPCCommon.h create mode 100644 lldb/tools/lldb-rpc/lldb-rpc-gen/lldb-rpc-gen.cpp diff --git a/lldb/cmake/modules/LLDBConfig.cmake b/lldb/cmake/modules/LLDBConfig.cmake index 37b823feb584b..069b5412d03f8 100644 --- a/lldb/cmake/modules/LLDBConfig.cmake +++ b/lldb/cmake/modules/LLDBConfig.cmake @@ -322,4 +322,6 @@ else() set(LLDB_CAN_USE_DEBUGSERVER OFF) endif() +set(LLDB_BUILD_LLDBRPC ON CACHE BOOL "") + include(LLDBGenerateConfig) diff --git a/lldb/test/Shell/RPC/Generator/Tests/CheckRPCGenToolByproducts.test b/lldb/test/Shell/RPC/Generator/Tests/CheckRPCGenToolByproducts.test new file mode 100644 index 0..be3eefc69b20a --- /dev/null +++ b/lldb/test/Shell/RPC/Generator/Tests/CheckRPCGenToolByproducts.test @@ -0,0 +1,11 @@ +# For this test, we're not checking any specific output from a generated file, +# but we do need a file to pass into lldb-rpc-gen so use SBAddress.h from source. +RUN: %lldb-rpc-gen --output-dir=%t %S/../../../../../include/lldb/API/SBAddress.h + +RUN: ls %t | FileCheck %s + +# We're just making sure that the tool emits the class names, +# methods and skipped methods file in the output directory. +CHECK: SBAPI.def +CHECK: SBClasses.def +CHECK: SkippedMethods.txt diff --git a/lldb/test/Shell/helper/toolchain.py b/lldb/test/Shell/helper/toolchain.py index 42968128f2702..95437dba55b7d 100644 --- a/lldb/test/Shell/helper/toolchain.py +++ b/lldb/test/Shell/helper/toolchain.py @@ -156,6 +156,14 @@ def use_lldb_substitutions(config): extra_args=["platform"], unresolved="ignore", ), +ToolSubst( +"%lldb-rpc-gen", +command=FindTool("lldb-rpc-gen"), +extra_args=[ +'--extra-arg="-resource-dir=' + config.clang_resource_dir + '"' +], +unresolved="ignore", +), "lldb-test", "lldb-dap", ToolSubst( diff --git a/lldb/tools/CMakeLists.txt b/lldb/tools/CMakeLists.txt index 6804dc234555b..73ffbbbee3056 100644 --- a/lldb/tools/CMakeLists.txt +++ b/lldb/tools/CMakeLists.txt @@ -10,6 +10,9 @@ add_subdirectory(lldb-fuzzer EXCLUDE_FROM_ALL) add_lldb_tool_subdirectory(lldb-instr) add_lldb_tool_subdirectory(lldb-dap) +if (LLDB_BUILD_LLDBRPC) + add_lldb_tool_subdirectory(lldb-rpc) +endif() if (CMAKE_SYSTEM_NAME MATCHES "Darwin") add_lldb_tool_subdirectory(darwin-debug) diff --git a/lldb/tools/lldb-rpc/CMakeLists.txt b/lldb/tools/lldb-rpc/CMakeLists.txt new file mode 100644 index 0..fdd6cf9163e96 --- /dev/null +++ b/lldb/tools/lldb-rpc/CMakeLists.txt @@ -0,0 +1,22 @@ +include(CheckCXXCompilerFlag) +# Umbrella target for the entire framework is a default target. +add_custom_target(lldb-rpc ALL) + +if(LLDB_CODESIGN_IDENTITY) + # Use explicit LLDB identity + set(LLVM_CODESIGNING_IDENTITY ${LLDB_CODESIGN_IDENTITY}) +else() + # Use explicit LLVM identity or default to ad-hoc signing if empty + if(NOT LLVM_CODESIGNING_IDENTITY) +set(LLVM_CODESIGNING_IDENTITY -) + endif() +endif() + +# LLDBRPCGeneration.cmake needs the LLDB_RPC_GEN_EXE variable +# which gets defined in the lldb-rpc-gen folder, so we're adding +# this folder before we add that file. +add_lldb_tool_subdirectory(lldb-rpc-gen) +include(${CMAKE_CURRENT_SOURCE_DIR}/LLDBRPCGeneration.cmake) +include(${CMAKE_CURRENT_SOURCE_DIR}/LLDBRPCHeaders.cmake) + +add_dependencies(lldb-rpc lldb-rp
[Lldb-commits] [lldb] [lldb][RPC] Upstream lldb-rpc-gen tool (PR #138031)
chelcassanova wrote: When I updated the patch, the test now fails because of the error that it's missing the clang resource dir. That repros locally and I haven't changed anything about how the tool is built outside of adding a CMake variable, investigating. https://github.com/llvm/llvm-project/pull/138031 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb][Mach-O] Allow "process metadata" LC_NOTE to supply registers (PR #144627)
@@ -0,0 +1,300 @@ +//===-- RegisterContextUnifiedCore.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 "RegisterContextUnifiedCore.h" +#include "lldb/Target/DynamicRegisterInfo.h" +#include "lldb/Target/Process.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/StructuredData.h" + +using namespace lldb; +using namespace lldb_private; + +RegisterContextUnifiedCore::RegisterContextUnifiedCore( +Thread &thread, uint32_t concrete_frame_idx, +RegisterContextSP core_thread_regctx_sp, +StructuredData::ObjectSP metadata_thread_registers) +: RegisterContext(thread, concrete_frame_idx) { + + ProcessSP process_sp(thread.GetProcess()); + Target &target = process_sp->GetTarget(); + StructuredData::Dictionary *metadata_registers_dict = nullptr; + + // If we have thread metadata, check if the keys for register + // definitions are present; if not, clear the ObjectSP. + if (metadata_thread_registers && + metadata_thread_registers->GetAsDictionary() && + metadata_thread_registers->GetAsDictionary()->HasKey("register_info")) { +metadata_registers_dict = metadata_thread_registers->GetAsDictionary() + ->GetValueForKey("register_info") + ->GetAsDictionary(); +if (metadata_registers_dict) + if (!metadata_registers_dict->HasKey("sets") || + !metadata_registers_dict->HasKey("registers")) +metadata_registers_dict = nullptr; + } + + // When creating a register set list from the two sources, + // the LC_THREAD aka core_thread_regctx_sp register sets + // will be used at the same indexes. + // Any additional sets named by the thread metadata registers + // will be added after them. If the thread metadata + // specify a set with the same name as LC_THREAD, the already-used + // index from the core register context will be used in + // the RegisterInfo. + std::map metadata_regset_to_combined_regset; + + // Calculate the total size of the register store buffer we need + // for all registers. The corefile register definitions may include + // RegisterInfo descriptions of registers that aren't actually + // available. For simplicity, calculate the size of all registers + // as if they are available, so we can maintain the same offsets into + // the buffer. + uint32_t core_buffer_end = 0; + for (size_t idx = 0; idx < core_thread_regctx_sp->GetRegisterCount(); idx++) { +const RegisterInfo *reginfo = +core_thread_regctx_sp->GetRegisterInfoAtIndex(idx); +core_buffer_end = +std::max(reginfo->byte_offset + reginfo->byte_size, core_buffer_end); + } + + // Add metadata register sizes to the total buffer size. + uint32_t combined_buffer_end = core_buffer_end; + if (metadata_registers_dict) { +StructuredData::Array *registers = nullptr; +if (metadata_registers_dict->GetValueForKeyAsArray("registers", registers)) + registers->ForEach( + [&combined_buffer_end](StructuredData::Object *ent) -> bool { +uint32_t bitsize; +if (!ent->GetAsDictionary()->GetValueForKeyAsInteger("bitsize", + bitsize)) + return false; +combined_buffer_end += (bitsize / 8); +return true; + }); + } + m_register_data.resize(combined_buffer_end, 0); + + // Copy the core register values into our combined data buffer, + // skip registers that are contained within another (e.g. w0 vs. x0) + // and registers that return as "unavailable". + for (size_t idx = 0; idx < core_thread_regctx_sp->GetRegisterCount(); idx++) { +const RegisterInfo *reginfo = +core_thread_regctx_sp->GetRegisterInfoAtIndex(idx); +RegisterValue val; +if (!reginfo->value_regs && +core_thread_regctx_sp->ReadRegister(reginfo, val)) + memcpy(m_register_data.data() + reginfo->byte_offset, val.GetBytes(), + val.GetByteSize()); + } + + // Set 'offset' fields for each register definition into our combined + // register data buffer. DynamicRegisterInfo needs + // this field set to parse the JSON. + // Also copy the values of the registers into our register data buffer. + if (metadata_registers_dict) { +size_t offset = core_buffer_end; +ByteOrder byte_order = core_thread_regctx_sp->GetByteOrder(); +StructuredData::Array *registers; +if (metadata_registers_dict->GetValueForKeyAsArray("registers", registers)) + registers->ForEach([this, &offset, + byte_order](StructuredData::Object *ent) -> bool { +uint64_t bitsize;
[Lldb-commits] [clang] [lldb] [llvm] [lldb] Fix object format in the Triple of Mach-O files (approach 4) (PR #145157)
@@ -463,6 +463,27 @@ class Triple { const std::string &str() const { return Data; } + /// Return the triple string but only keep the first \p N components. + /// + /// The returned string will preserve the first \p N components exactly the + /// same as the original (including the leading "-" and the value, empty or + /// not). + /// + /// E.g. Triple("arm64-apple-ios").str(5) == "arm64-apple-ios" + /// E.g. Triple("arm64-apple-ios--").str(5) == "arm64-apple-ios--" + /// E.g. Triple("arm64-apple-ios--").str(4) == "arm64-apple-ios-" + /// E.g. Triple("arm64-apple-ios--").str(3) == "arm64-apple-ios" + /// E.g. Triple("arm64-apple-ios--").str(2) == "arm64-apple" + /// E.g. Triple("arm64-apple-ios--").str(1) == "arm64" + /// E.g. Triple("arm64-apple-ios--").str(0) == "" + /// + /// This method does not normalize any triple strings. Clients that need to + /// handle the non-canonical triples that users often specify should use the + /// normalize method. + /// + /// \returns the (shorterned) triple string. + StringRef str(size_t N) const; dmpots wrote: It looks like we already have this capability in the `normalize` method https://github.com/llvm/llvm-project/blob/3ea1296b3724ec5c05f616c98dd883b54b672ff9/llvm/include/llvm/TargetParser/Triple.h#L388 For the use cases in this PR we could do `triple.normalize(CanonicalForm::FOUR_IDENT)` https://github.com/llvm/llvm-project/pull/145157 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [clang] [lldb] [llvm] [lldb] Fix object format in the Triple of Mach-O files (approach 4) (PR #145157)
@@ -642,9 +642,9 @@ bool SBDebugger::GetDefaultArchitecture(char *arch_name, size_t arch_name_len) { ArchSpec default_arch = Target::GetDefaultArchitecture(); if (default_arch.IsValid()) { - const std::string &triple_str = default_arch.GetTriple().str(); + const llvm::StringRef triple_str = default_arch.GetTriple().str(4); dmpots wrote: I think it would be good to add a couple of methods to `ArchSpec` so that we have a single place that specifies how we format the triple. ``` class ArchSpec { ... static std::string GetTripleStr(const llvm::Triple &triple) { return triple.normalize(CanonicalForm::FOUR_IDENT); } std::string GetTripleStr() { return GetTripleStr(GetTriple()); } }; ``` Then if we have an `ArchSpec` we can just call the `GetTripleStr()` function on it and if we just have the `Triple` we can still use the static version. https://github.com/llvm/llvm-project/pull/145157 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb][RPC] Upstream lldb-rpc-gen tool (PR #138031)
chelcassanova wrote: Actually, the test fails locally for me. On the pre-commit CI it's error message is `home/gha/actions-runner/_work/llvm-project/llvm-project/build/tools/lldb/test/Shell/RPC/Generator/Tests/Output/CheckRPCGenToolByproducts.test.script: line 1: fg: no job control`, which means that it doesn't recognize that the tool's binary is there. As an aside, is there a way to retrigger a pre-commit CI check without having to push again? https://github.com/llvm/llvm-project/pull/138031 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb][Mach-O] Allow "process metadata" LC_NOTE to supply registers (PR #144627)
@@ -0,0 +1,300 @@ +//===-- RegisterContextUnifiedCore.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 "RegisterContextUnifiedCore.h" +#include "lldb/Target/DynamicRegisterInfo.h" +#include "lldb/Target/Process.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/StructuredData.h" + +using namespace lldb; +using namespace lldb_private; + +RegisterContextUnifiedCore::RegisterContextUnifiedCore( +Thread &thread, uint32_t concrete_frame_idx, +RegisterContextSP core_thread_regctx_sp, +StructuredData::ObjectSP metadata_thread_registers) +: RegisterContext(thread, concrete_frame_idx) { + + ProcessSP process_sp(thread.GetProcess()); + Target &target = process_sp->GetTarget(); + StructuredData::Dictionary *metadata_registers_dict = nullptr; + + // If we have thread metadata, check if the keys for register + // definitions are present; if not, clear the ObjectSP. + if (metadata_thread_registers && + metadata_thread_registers->GetAsDictionary() && + metadata_thread_registers->GetAsDictionary()->HasKey("register_info")) { +metadata_registers_dict = metadata_thread_registers->GetAsDictionary() + ->GetValueForKey("register_info") + ->GetAsDictionary(); +if (metadata_registers_dict) + if (!metadata_registers_dict->HasKey("sets") || + !metadata_registers_dict->HasKey("registers")) +metadata_registers_dict = nullptr; + } + + // When creating a register set list from the two sources, + // the LC_THREAD aka core_thread_regctx_sp register sets + // will be used at the same indexes. + // Any additional sets named by the thread metadata registers + // will be added after them. If the thread metadata + // specify a set with the same name as LC_THREAD, the already-used + // index from the core register context will be used in + // the RegisterInfo. + std::map metadata_regset_to_combined_regset; + + // Calculate the total size of the register store buffer we need + // for all registers. The corefile register definitions may include + // RegisterInfo descriptions of registers that aren't actually + // available. For simplicity, calculate the size of all registers + // as if they are available, so we can maintain the same offsets into + // the buffer. + uint32_t core_buffer_end = 0; + for (size_t idx = 0; idx < core_thread_regctx_sp->GetRegisterCount(); idx++) { +const RegisterInfo *reginfo = +core_thread_regctx_sp->GetRegisterInfoAtIndex(idx); +core_buffer_end = +std::max(reginfo->byte_offset + reginfo->byte_size, core_buffer_end); + } + + // Add metadata register sizes to the total buffer size. + uint32_t combined_buffer_end = core_buffer_end; + if (metadata_registers_dict) { +StructuredData::Array *registers = nullptr; +if (metadata_registers_dict->GetValueForKeyAsArray("registers", registers)) + registers->ForEach( + [&combined_buffer_end](StructuredData::Object *ent) -> bool { +uint32_t bitsize; +if (!ent->GetAsDictionary()->GetValueForKeyAsInteger("bitsize", + bitsize)) + return false; +combined_buffer_end += (bitsize / 8); +return true; + }); + } + m_register_data.resize(combined_buffer_end, 0); + + // Copy the core register values into our combined data buffer, + // skip registers that are contained within another (e.g. w0 vs. x0) + // and registers that return as "unavailable". + for (size_t idx = 0; idx < core_thread_regctx_sp->GetRegisterCount(); idx++) { +const RegisterInfo *reginfo = +core_thread_regctx_sp->GetRegisterInfoAtIndex(idx); +RegisterValue val; +if (!reginfo->value_regs && +core_thread_regctx_sp->ReadRegister(reginfo, val)) + memcpy(m_register_data.data() + reginfo->byte_offset, val.GetBytes(), + val.GetByteSize()); + } + + // Set 'offset' fields for each register definition into our combined + // register data buffer. DynamicRegisterInfo needs + // this field set to parse the JSON. + // Also copy the values of the registers into our register data buffer. + if (metadata_registers_dict) { +size_t offset = core_buffer_end; +ByteOrder byte_order = core_thread_regctx_sp->GetByteOrder(); +StructuredData::Array *registers; +if (metadata_registers_dict->GetValueForKeyAsArray("registers", registers)) + registers->ForEach([this, &offset, + byte_order](StructuredData::Object *ent) -> bool { +uint64_t bitsize;
[Lldb-commits] [lldb] [lldb] Add Model Context Protocol (MCP) support to LLDB (PR #143628)
DavidSpickett wrote: @JDevlieghere Release note please. Feel free to put it at the the top for maximum buzzword power :) Include a link to the documentation page once you've added that. https://github.com/llvm/llvm-project/pull/143628 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Support disassembling RISC-V proprietary instructions (PR #145793)
DavidSpickett wrote: > Upon realising that almost all of our custom extensions are only used in > assembly Which is surprising to me, but if I looked at all the assembly only extensions for Arm I'd find the the same thing. I just rarely have to deal with those. > And that's how we get here: filtering the output of objdump is fine, but it > would be great to also support users inside their disassembler 😄 Yes I see how you'd get there. Even if we want to be super reductive, printing the bytes out at least means you can decode by hand. Which you can't do today. So I like the direction. > MCDisassembler::suggestBytesToSkip, which the Arm/AArch64 backends use for > realigning the disassembly flow. We maybe should implement this given we know > the instruction alignment in RISC-V is either 2 or 4, but we don't at the > moment. I should check how this ends up displaying in lldb. AArch64 unlikely to be a problem but Thumb is variable so I hope we at least show the bytes. @tedwoodward I think this change might be more clearly pitched as: * Currently when an instruction is not decoded lldb prints nothing useful * You have made lldb print something useful in this situation, for humans and scripts * In addition, this format enables the use of external filters Which I think is a net positive. Still unsure about `if riscv` in this generic code but if there's no other use case for it then it's fine. That's just a code organisation issue. Arm M profile has https://developer.arm.com/Architectures/Arm%20Custom%20Instructions, I'll look into that and see if it would benefit from a change of output format too. Just in theory though, I don't think we shipped support for open source debuggers and I'm not about to implement it myself. https://github.com/llvm/llvm-project/pull/145793 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Update DIL to handle smart pointers; add more tests. (PR #143786)
https://github.com/labath commented: I meant adding a new test method (`def test_something(self): self.build(); self.run(); your code`), but this is fine too, especially if the switch to the new implementation is imminent. https://github.com/llvm/llvm-project/pull/143786 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Update DIL to handle smart pointers; add more tests. (PR #143786)
https://github.com/labath approved this pull request. https://github.com/llvm/llvm-project/pull/143786 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Use llvm::is_contained (NFC) (PR #146012)
https://github.com/tgymnich approved this pull request. https://github.com/llvm/llvm-project/pull/146012 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] 2c90c0b - [lldb] Extract debug server location code (#145706)
Author: Pavel Labath Date: 2025-06-27T11:16:57+02:00 New Revision: 2c90c0b90cbdfbd069b2e79d6a2c3e3b160bf896 URL: https://github.com/llvm/llvm-project/commit/2c90c0b90cbdfbd069b2e79d6a2c3e3b160bf896 DIFF: https://github.com/llvm/llvm-project/commit/2c90c0b90cbdfbd069b2e79d6a2c3e3b160bf896.diff LOG: [lldb] Extract debug server location code (#145706) .. from the guts of GDBRemoteCommunication to ~top level. This is motivated by #131519 and by the fact that's impossible to guess whether the author of a symlink intended it to be a "convenience shortcut" -- meaning it should be resolved before looking for related files; or an "implementation detail" -- meaning the related files should be located near the symlink itself. This debate is particularly ridiculous when it comes to lldb-server running in platform mode, because it also functions as a debug server, so what we really just need to do is to pass /proc/self/exe in a platform-independent manner. Moving the location logic higher up achieves that as lldb-platform (on non-macos) can pass `HostInfo::GetProgramFileSpec`, while liblldb can use the existing complex logic (which only worked on liblldb anyway as lldb-platform doesn't have a lldb_private::Platform instance). Another benefit of this patch is a reduction in dependency from GDBRemoteCommunication to the rest of liblldb (achieved by avoiding the Platform dependency). Added: Modified: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.cpp lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerPlatform.h lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp lldb/test/API/commands/platform/launchgdbserver/TestPlatformLaunchGDBServer.py lldb/test/API/tools/lldb-dap/console/TestDAP_console.py lldb/tools/lldb-server/lldb-platform.cpp Removed: diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp index 4bb85f5d53616..d7e4b2b9546b2 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp @@ -11,7 +11,6 @@ #include "lldb/Host/Config.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/Host.h" -#include "lldb/Host/HostInfo.h" #include "lldb/Host/Pipe.h" #include "lldb/Host/ProcessLaunchInfo.h" #include "lldb/Host/Socket.h" @@ -33,14 +32,6 @@ #include #include -#if defined(__APPLE__) -#define DEBUGSERVER_BASENAME "debugserver" -#elif defined(_WIN32) -#define DEBUGSERVER_BASENAME "lldb-server.exe" -#else -#define DEBUGSERVER_BASENAME "lldb-server" -#endif - #if HAVE_LIBCOMPRESSION #include #endif @@ -836,77 +827,11 @@ GDBRemoteCommunication::CheckForPacket(const uint8_t *src, size_t src_len, return GDBRemoteCommunication::PacketType::Invalid; } -FileSpec GDBRemoteCommunication::GetDebugserverPath(Platform *platform) { - Log *log = GetLog(GDBRLog::Process); - // If we locate debugserver, keep that located version around - static FileSpec g_debugserver_file_spec; - FileSpec debugserver_file_spec; - - Environment host_env = Host::GetEnvironment(); - - // Always check to see if we have an environment override for the path to the - // debugserver to use and use it if we do. - std::string env_debugserver_path = host_env.lookup("LLDB_DEBUGSERVER_PATH"); - if (!env_debugserver_path.empty()) { -debugserver_file_spec.SetFile(env_debugserver_path, - FileSpec::Style::native); -LLDB_LOGF(log, - "GDBRemoteCommunication::%s() gdb-remote stub exe path set " - "from environment variable: %s", - __FUNCTION__, env_debugserver_path.c_str()); - } else -debugserver_file_spec = g_debugserver_file_spec; - bool debugserver_exists = - FileSystem::Instance().Exists(debugserver_file_spec); - if (!debugserver_exists) { -// The debugserver binary is in the LLDB.framework/Resources directory. -debugserver_file_spec = HostInfo::GetSupportExeDir(); -if (debugserver_file_spec) { - debugserver_file_spec.AppendPathComponent(DEBUGSERVER_BASENAME); - debugserver_exists = FileSystem::Instance().Exists(debugserver_file_spec); - if (debugserver_exists) { -LLDB_LOGF(log, - "GDBRemoteCommunication::%s() found gdb-remote stub exe '%s'", - __FUNCTION__, debugserver_file_spec.GetPath().c_str()); - -g_debugserver_file_spec = debugserver_file_spec; - } else { -if (platform) - debugserver_file_spec = - platform->LocateExecutable(DEBUGSERVER_BASENAME); -else - debugserver_file_spec.Clear(); -if (debugserver_
[Lldb-commits] [lldb] [lldb] Extract debug server location code (PR #145706)
https://github.com/labath closed https://github.com/llvm/llvm-project/pull/145706 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Document MCP support in LLDB (PR #145935)
@@ -0,0 +1,68 @@ +# Model Context Protocol (MCP) + +LLDB supports for the [Model Context Protocol][1] (MCP). This structured, +machine-friendly protocol allows AI models to access and interact with external +tools, such as the debugger. Using MCP, an AI agent can execute LLDB commands +to control the debugger: set breakpoints, inspect memory, step through code. +This can range from helping you run a specific command you can't immediately +remember to a fully agent-driven debugging experiences + +## MCP Server + +To start the MCP server in LLDB, use the `protocol-server start` command. +Specify `MCP` as the protocol and provide a URI to listen on. For example, to +start listening for local TCP connections on port `5`, use the following +command: + +``` +(lldb) protocol-server start MCP listen://localhost:5 +MCP server started with connection listeners: connection://[::1]:5, connection://[127.0.0.1]:5 +``` + +The server will automatically stop when exiting LLDB, or it can be stopped +explicitly with the `protocol-server stop` command. DavidSpickett wrote: Also, how do you check if it is active? `protocol-server` start again and it errors? https://github.com/llvm/llvm-project/pull/145935 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Document MCP support in LLDB (PR #145935)
@@ -0,0 +1,68 @@ +# Model Context Protocol (MCP) + +LLDB supports for the [Model Context Protocol][1] (MCP). This structured, +machine-friendly protocol allows AI models to access and interact with external +tools, such as the debugger. Using MCP, an AI agent can execute LLDB commands +to control the debugger: set breakpoints, inspect memory, step through code. +This can range from helping you run a specific command you can't immediately +remember to a fully agent-driven debugging experiences + +## MCP Server + +To start the MCP server in LLDB, use the `protocol-server start` command. +Specify `MCP` as the protocol and provide a URI to listen on. For example, to +start listening for local TCP connections on port `5`, use the following +command: + +``` +(lldb) protocol-server start MCP listen://localhost:5 +MCP server started with connection listeners: connection://[::1]:5, connection://[127.0.0.1]:5 +``` + +The server will automatically stop when exiting LLDB, or it can be stopped +explicitly with the `protocol-server stop` command. + +``` +(lldb) protocol-server stop MCP +``` + +## MCP Client + +MCP uses standard input/output (stdio) for communication between client and +server. The exact configuration depends on the client, but most applications +allow you to specify an MCP server as a binary and arguments. This means that +you need to use something like `netcat` to connect to LLDB's MCP server and +forward communication over stdio over the network connection. + +Configuration example for [Claude Code][2]: + +``` +{ + "mcpServers": { +"tool": { + "command": "/usr/bin/nc", + "args": ["localhost", "5"] +} + } +} +``` + +Configuration example for [Visual Studio Code][3]: + +``` +{ + "mcp": { +"servers": { + "lldb": { +"type": "stdio", +"command": "/usr/bin/nc", +"args": ["localhost", "5"] + } +} + } +} +``` + DavidSpickett wrote: Is there any way to know that you've connected properly? I suppose the MCP client says something if it cannot connect, right? Are there log channels on LLDB's side you could enable if you had problems with it? https://github.com/llvm/llvm-project/pull/145935 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb][NFC] Inline ResolveSDKPathFromDebugInfo in one of its call site (PR #146062)
https://github.com/charles-zablit edited https://github.com/llvm/llvm-project/pull/146062 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb][NFC] Inline ResolveSDKPathFromDebugInfo in one of its call site (PR #146062)
https://github.com/charles-zablit created https://github.com/llvm/llvm-project/pull/146062 This patch is part of an effort to remove the ResolveSDKPathFromDebugInfo method, and more specifically the variant which takes a Module as argument. This PR should be merged after https://github.com/llvm/llvm-project/pull/144913. >From 6ce75177264d47ffedbf0e6ee44831eac1d3ea55 Mon Sep 17 00:00:00 2001 From: Charles Zablit Date: Fri, 27 Jun 2025 12:49:53 +0100 Subject: [PATCH] [lldb][NFC] Inline ResolveSDKPathFromDebugInfo in one of its call site --- .../Platform/MacOSX/PlatformDarwin.cpp| 32 +++ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp index 262a7dc731713..ae46ac63e756a 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp @@ -1130,13 +1130,33 @@ void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( if (target) { if (ModuleSP exe_module_sp = target->GetExecutableModule()) { - auto path_or_err = ResolveSDKPathFromDebugInfo(*exe_module_sp); - if (path_or_err) { -sysroot_spec = FileSpec(*path_or_err); + SymbolFile *sym_file = exe_module_sp->GetSymbolFile(); + if (!sym_file) +return; + + XcodeSDK merged_sdk; + for (unsigned i = 0; i < sym_file->GetNumCompileUnits(); ++i) { +if (auto cu_sp = sym_file->GetCompileUnitAtIndex(i)) { + auto cu_sdk = sym_file->ParseXcodeSDK(*cu_sp); + merged_sdk.Merge(cu_sdk); +} + } + + // TODO: The result of this loop is almost equivalent to deriving the SDK + // from the target triple, which would be a lot cheaper. + + if (FileSystem::Instance().Exists(merged_sdk.GetSysroot())) { +sysroot_spec = merged_sdk.GetSysroot(); } else { -LLDB_LOG_ERROR(GetLog(LLDBLog::Types | LLDBLog::Host), - path_or_err.takeError(), - "Failed to resolve SDK path: {0}"); +auto path_or_err = +HostInfo::GetSDKRoot(HostInfo::SDKOptions{merged_sdk}); +if (path_or_err) { + sysroot_spec = FileSpec(*path_or_err); +} else { + LLDB_LOG_ERROR(GetLog(LLDBLog::Types | LLDBLog::Host), + path_or_err.takeError(), + "Failed to resolve SDK path: {0}"); +} } } } ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb][NFC] Inline ResolveSDKPathFromDebugInfo in one of its call site (PR #146062)
llvmbot wrote: @llvm/pr-subscribers-lldb Author: Charles Zablit (charles-zablit) Changes This patch is part of an effort to remove the ResolveSDKPathFromDebugInfo method, and more specifically the variant which takes a Module as argument. This PR should be merged after https://github.com/llvm/llvm-project/pull/144913. --- Full diff: https://github.com/llvm/llvm-project/pull/146062.diff 1 Files Affected: - (modified) lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp (+26-6) ``diff diff --git a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp index 262a7dc731713..ae46ac63e756a 100644 --- a/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp +++ b/lldb/source/Plugins/Platform/MacOSX/PlatformDarwin.cpp @@ -1130,13 +1130,33 @@ void PlatformDarwin::AddClangModuleCompilationOptionsForSDKType( if (target) { if (ModuleSP exe_module_sp = target->GetExecutableModule()) { - auto path_or_err = ResolveSDKPathFromDebugInfo(*exe_module_sp); - if (path_or_err) { -sysroot_spec = FileSpec(*path_or_err); + SymbolFile *sym_file = exe_module_sp->GetSymbolFile(); + if (!sym_file) +return; + + XcodeSDK merged_sdk; + for (unsigned i = 0; i < sym_file->GetNumCompileUnits(); ++i) { +if (auto cu_sp = sym_file->GetCompileUnitAtIndex(i)) { + auto cu_sdk = sym_file->ParseXcodeSDK(*cu_sp); + merged_sdk.Merge(cu_sdk); +} + } + + // TODO: The result of this loop is almost equivalent to deriving the SDK + // from the target triple, which would be a lot cheaper. + + if (FileSystem::Instance().Exists(merged_sdk.GetSysroot())) { +sysroot_spec = merged_sdk.GetSysroot(); } else { -LLDB_LOG_ERROR(GetLog(LLDBLog::Types | LLDBLog::Host), - path_or_err.takeError(), - "Failed to resolve SDK path: {0}"); +auto path_or_err = +HostInfo::GetSDKRoot(HostInfo::SDKOptions{merged_sdk}); +if (path_or_err) { + sysroot_spec = FileSpec(*path_or_err); +} else { + LLDB_LOG_ERROR(GetLog(LLDBLog::Types | LLDBLog::Host), + path_or_err.takeError(), + "Failed to resolve SDK path: {0}"); +} } } } `` https://github.com/llvm/llvm-project/pull/146062 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Fix a bug in the breakpoint ID verifier in CommandObjectBreakpoint. (PR #145994)
DavidSpickett wrote: Already done by https://github.com/llvm/llvm-project/commit/3f00cff5c7871dbde3871d31fffbf183b3ce3419. https://github.com/llvm/llvm-project/pull/145994 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add type summaries for MSVC STL strings (PR #143177)
@@ -299,6 +299,8 @@ def parseOptionsAndInitTestdirs(): configuration.libcxx_library_dir = args.libcxx_library_dir configuration.cmake_build_type = args.cmake_build_type.lower() +configuration.target_triple = args.target_triple + DavidSpickett wrote: Also I'm bothered that there isn't any explicit enabling of the MSVC STL in the compiler flags, but I suppose that's what you and Pavel have been debating this whole time :) What you've got is a predicate that says "does this compiler by default use MSVC STL" then the tests deliberately don't add any stlib related flags, so that they get that default. And as you mentioned above, there is no "opt in" to MSVC STL anyway. Do I understand correctly? If so I think that is a reasonable way to do this. The fact that it relies on implicit selection seems to be out of your control. https://github.com/llvm/llvm-project/pull/143177 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] make PlatformAndroid/AdbClient::GetSyncService threadsafe (PR #145382)
cs01 wrote: Thank you both for the feedback. I started working on changes that add more mutexes to adbclient methods, use a shared pointer for the sync service, and has cleaner/less path dependent creation of the syncservice (I agree with your comments labath). I will push an update either today or sometime next week. https://github.com/llvm/llvm-project/pull/145382 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add type summaries for MSVC STL strings (PR #143177)
@@ -0,0 +1,4 @@ +CXX_SOURCES := main.cpp + +CXXFLAGS_EXTRAS := -std=c++20 -O0 DavidSpickett wrote: Is there a specific reason for this to be C++20? Trying to enable as many features in u8string as possible perhaps? https://github.com/llvm/llvm-project/pull/143177 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add type summaries for MSVC STL strings (PR #143177)
@@ -299,6 +299,8 @@ def parseOptionsAndInitTestdirs(): configuration.libcxx_library_dir = args.libcxx_library_dir configuration.cmake_build_type = args.cmake_build_type.lower() +configuration.target_triple = args.target_triple + DavidSpickett wrote: ...unless someone has a mingw compiler and wants to use MSVC STL but I think that's A: asking for trouble and B: defeating part of the point of mingw? Hmm. Anyway, the tests will run on a buildbot that will be running for a few years to come, that's the main thing here. https://github.com/llvm/llvm-project/pull/143177 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb][RISCV] fix LR/SC atomic sequence handling in lldb-server (PR #146072)
https://github.com/DavidSpickett approved this pull request. Please describe in the PR description the changes made since it was reverted (even as trivial as they are here). This helps git archaeology a bit, and users who might want to check the state of a feature later and might be confused by a revert/reland sequence. Otherwise, LGTM. https://github.com/llvm/llvm-project/pull/146072 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [llvm] [NFC][DebugInfo][DWARF] Create new low-level dwarf library (PR #145081)
llvm-ci wrote: LLVM Buildbot has detected a new failure on builder `flang-aarch64-sharedlibs` running on `linaro-flang-aarch64-sharedlibs` while building `bolt,lldb,llvm,utils` at step 5 "build-unified-tree". Full details are available at: https://lab.llvm.org/buildbot/#/builders/80/builds/14255 Here is the relevant piece of the build log for the reference ``` Step 5 (build-unified-tree) failure: build (failure) ... 341.980 [3462/162/4077] Building CXX object tools/clang/lib/Sema/CMakeFiles/obj.clangSema.dir/SemaConsumer.cpp.o 341.982 [3461/162/4078] Building CXX object tools/clang/lib/Sema/CMakeFiles/obj.clangSema.dir/SemaDirectX.cpp.o 341.986 [3460/162/4079] Building CXX object tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/CodeGenAction.cpp.o 341.991 [3459/162/4080] Building CXX object tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/CodeGenModule.cpp.o 341.994 [3458/162/4081] Building CXX object tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/CodeGenPGO.cpp.o 341.998 [3457/162/4082] Building CXX object tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/CoverageMappingGen.cpp.o 342.001 [3456/162/4083] Building CXX object tools/clang/lib/CodeGen/CMakeFiles/obj.clangCodeGen.dir/ObjectFilePCHContainerWriter.cpp.o 342.004 [3455/162/4084] Building CXX object tools/clang/lib/AST/CMakeFiles/obj.clangAST.dir/CommentSema.cpp.o 342.007 [3454/162/4085] Building CXX object tools/clang/lib/AST/CMakeFiles/obj.clangAST.dir/Expr.cpp.o 342.009 [3453/162/4086] Linking CXX shared library lib/libLLVMDebugInfoLogicalView.so.21.0git FAILED: lib/libLLVMDebugInfoLogicalView.so.21.0git : && /usr/local/bin/c++ -fPIC -fPIC -fno-semantic-interposition -fvisibility-inlines-hidden -Werror=date-time -Werror=unguarded-availability-new -Wall -Wextra -Wno-unused-parameter -Wwrite-strings -Wcast-qual -Wmissing-field-initializers -pedantic -Wno-long-long -Wc++98-compat-extra-semi -Wimplicit-fallthrough -Wcovered-switch-default -Wno-noexcept-type -Wnon-virtual-dtor -Wdelete-non-virtual-dtor -Wsuggest-override -Wstring-conversion -Wmisleading-indentation -Wctad-maybe-unsupported -fdiagnostics-color -ffunction-sections -fdata-sections -O3 -DNDEBUG -Wl,-z,defs -Wl,-z,nodelete -Wl,-rpath-link,/home/tcwg-buildbot/worker/flang-aarch64-sharedlibs/build/./lib -Wl,--gc-sections -shared -Wl,-soname,libLLVMDebugInfoLogicalView.so.21.0git -o lib/libLLVMDebugInfoLogicalView.so.21.0git lib/DebugInfo/LogicalView/CMakeFiles/LLVMDebugInfoLogicalView.dir/Core/LVCompare.cpp.o lib/DebugInfo/LogicalView/CMakeFiles/LLVMDebugInfoLogicalView.dir/Core/LVElement.cpp.o lib/DebugInfo/LogicalView/CMakeFiles/LLVMDebugInfoLogicalView.dir/Core/LVLine.cpp.o lib/DebugInfo/LogicalView/CMakeFiles/LLVMDebugInfoLogicalView.dir/Core/LVLocation.cpp.o lib/DebugInfo/LogicalView/CMakeFiles/LLVMDebugInfoLogicalView.dir/Core/LVObject.cpp.o lib/DebugInfo/LogicalView/CMakeFiles/LLVMDebugInfoLogicalView.dir/Core/LVOptions.cpp.o lib/DebugInfo/LogicalView/CMakeFiles/LLVMDebugInfoLogicalView.dir/Core/LVRange.cpp.o lib/DebugInfo/LogicalView/CMakeFiles/LLVMDebugInfoLogicalView.dir/Core/LVReader.cpp.o lib/DebugInfo/LogicalView/CMakeFiles/LLVMDebugInfoLogicalView.dir/Core/LVScope.cpp.o lib/DebugInfo/LogicalView/CMakeFiles/LLVMDebugInfoLogicalView.dir/Core/LVSort.cpp.o lib/DebugInfo/LogicalView/CMakeFiles/LLVMDebugInfoLogicalView.dir/Core/LVSourceLanguage.cpp.o lib/DebugInfo/LogicalView/CMakeFiles/LLVMDebugInfoLogicalView.dir/Core/LVSupport.cpp.o lib/DebugInfo/LogicalView/CMakeFiles/LLVMDebugInfoLogicalView.dir/Core/LVSymbol.cpp.o lib/DebugInfo/LogicalView/CMakeFiles/LLVMDebugInfoLogicalView.dir/Core/LVType.cpp.o lib/DebugInfo/LogicalView/CMakeFiles/LLVMDebugInfoLogicalView.dir/LVReaderHandler.cpp.o lib/DebugInfo/LogicalView/CMakeFiles/LLVMDebugInfoLogicalView.dir/Readers/LVBinaryReader.cpp.o lib/DebugInfo/LogicalView/CMakeFiles/LLVMDebugInfoLogicalView.dir/Readers/LVCodeViewReader.cpp.o lib/DebugInfo/LogicalView/CMakeFiles/LLVMDebugInfoLogicalView.dir/Readers/LVCodeViewVisitor.cpp.o lib/DebugInfo/LogicalView/CMakeFiles/LLVMDebugInfoLogicalView.dir/Readers/LVDWARFReader.cpp.o -Wl,-rpath,"\$ORIGIN/../lib:/home/tcwg-buildbot/worker/flang-aarch64-sharedlibs/build/lib:" lib/libLLVMDebugInfoDWARF.so.21.0git lib/libLLVMDebugInfoPDB.so.21.0git lib/libLLVMObject.so.21.0git lib/libLLVMMC.so.21.0git lib/libLLVMBinaryFormat.so.21.0git lib/libLLVMTargetParser.so.21.0git lib/libLLVMDebugInfoCodeView.so.21.0git lib/libLLVMSupport.so.21.0git lib/libLLVMDemangle.so.21.0git -Wl,-rpath-link,/home/tcwg-buildbot/worker/flang-aarch64-sharedlibs/build/lib && : /usr/bin/ld: lib/DebugInfo/LogicalView/CMakeFiles/LLVMDebugInfoLogicalView.dir/Readers/LVDWARFReader.cpp.o: in function `llvm::logicalview::LVDWARFReader::processLocationList(llvm::dwarf::Attribute, llvm::DWARFFormValue const&, llvm::DWARFDie const&, unsigned long, bool)::$_0::operator()(llvm::DWARFExpression const&) const': LVDWARFRead
[Lldb-commits] [lldb] Fix a bug in the breakpoint ID verifier in CommandObjectBreakpoint. (PR #145994)
slydiman wrote: The buildbot [lldb-x86_64-win](https://lab.llvm.org/staging/#/builders/211/builds/700) is broken after this patch. Please fix it ASAP. We are planning to switch this buildbot to the production mode soon. https://github.com/llvm/llvm-project/pull/145994 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Adding file and pipe support to lldb_private::MainLoopWindows. (PR #145621)
@@ -21,7 +24,9 @@ using namespace lldb; using namespace lldb_private; -static DWORD ToTimeout(std::optional point) { +namespace { labath wrote: according to the [coding standards](https://llvm.org/docs/CodingStandards.html#restrict-visibility) anonymous namespaces should be as small as possible. That means the function should stay static and (large) methods should be defined out of line (and out of the namespace) https://github.com/llvm/llvm-project/pull/145621 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Adding file and pipe support to lldb_private::MainLoopWindows. (PR #145621)
@@ -493,7 +496,12 @@ ConnectionFileDescriptor::BytesAvailable(const Timeout &timeout, break; // Lets keep reading to until we timeout } } else { +#if defined(_WIN32) +if (const auto *sock = static_cast(m_io_sp.get()); labath wrote: probably check m_io_sp->GetFdType() first. https://github.com/llvm/llvm-project/pull/145621 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Adding file and pipe support to lldb_private::MainLoopWindows. (PR #145621)
@@ -31,20 +31,27 @@ class MainLoopWindows : public MainLoopBase { Status Run() override; + struct FdInfo { +FdInfo(intptr_t event, Callback callback) +: event(event), callback(callback) {} +virtual ~FdInfo() {} +virtual void WillPoll() {} +virtual void DidPoll() {} +virtual void Disarm() {} +intptr_t event; labath wrote: could we use some more specific type for this? IOObject::WaitableHandle maybe? https://github.com/llvm/llvm-project/pull/145621 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Adding file and pipe support to lldb_private::MainLoopWindows. (PR #145621)
@@ -31,20 +31,27 @@ class MainLoopWindows : public MainLoopBase { Status Run() override; + struct FdInfo { +FdInfo(intptr_t event, Callback callback) +: event(event), callback(callback) {} +virtual ~FdInfo() {} +virtual void WillPoll() {} +virtual void DidPoll() {} +virtual void Disarm() {} +intptr_t event; +Callback callback; labath wrote: A struct with virtual methods reminds me of lldb-dap, in a bad way. Let's put these behind an accessor. https://github.com/llvm/llvm-project/pull/145621 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Adding file and pipe support to lldb_private::MainLoopWindows. (PR #145621)
@@ -31,6 +36,127 @@ static DWORD ToTimeout(std::optional point) { return ceil(dur).count(); } +class PipeFdInfo : public MainLoopWindows::FdInfo { +public: + explicit PipeFdInfo(HANDLE handle, MainLoopBase::Callback callback) + : FdInfo((intptr_t)CreateEventW(NULL, /*bManualReset=*/FALSE, + /*bInitialState=*/FALSE, NULL), + callback), +handle(handle), ready(CreateEventW(NULL, /*bManualReset=*/FALSE, + /*bInitialState=*/FALSE, NULL)) { +assert(event && ready); + } + + ~PipeFdInfo() override { +if (monitor_thread.joinable()) { labath wrote: Can we drop the read thread? Did [this implementation](https://github.com/llvm/llvm-project/commit/6675e03763c7d64e3335f1582c0fd7bc639be7d7) not work? I believe it should be possible to plug the event from the read operation into the WaitForMultipleObjects call. https://github.com/llvm/llvm-project/pull/145621 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Adding file and pipe support to lldb_private::MainLoopWindows. (PR #145621)
@@ -313,8 +318,39 @@ Socket::DecodeHostAndPort(llvm::StringRef host_and_port) { } IOObject::WaitableHandle Socket::GetWaitableHandle() { - // TODO: On Windows, use WSAEventSelect +#ifdef _WIN32 + if (m_socket == kInvalidSocketValue) +return kInvalidHandleValue; + + if (m_waitable_handle == kInvalidHandleValue) { +m_waitable_handle = WSACreateEvent(); +assert(m_waitable_handle != WSA_INVALID_EVENT); +if (WSAEventSelect(m_socket, m_waitable_handle, + FD_ACCEPT | FD_READ | FD_WRITE) != 0) labath wrote: I think it should be fine as long as we call (like you do now) WSAEventSelect right before blocking. It probably won't work if those selects happen on different threads (concurrently), but I'm not worried about that. The "use case" I have in mind is someone getting a callback notification doing *another* select to confirm that the data is indeed readable (that's kind of what happens with ConnectionFileDescriptor right now). https://github.com/llvm/llvm-project/pull/145621 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Adding file and pipe support to lldb_private::MainLoopWindows. (PR #145621)
@@ -31,8 +31,11 @@ #include #include #include +#include #include +#include #include +#include labath wrote: Are all of these still used? https://github.com/llvm/llvm-project/pull/145621 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Adding file and pipe support to lldb_private::MainLoopWindows. (PR #145621)
https://github.com/labath commented: This looks much better. My two main questions now are: - do we need regular file support - do we need the pipe *thread* (I think/hope the answer is "no" on both counts). https://github.com/llvm/llvm-project/pull/145621 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Adding file and pipe support to lldb_private::MainLoopWindows. (PR #145621)
https://github.com/labath edited https://github.com/llvm/llvm-project/pull/145621 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Adding file and pipe support to lldb_private::MainLoopWindows. (PR #145621)
@@ -274,7 +276,23 @@ int NativeFile::GetDescriptor() const { } IOObject::WaitableHandle NativeFile::GetWaitableHandle() { +#ifdef _WIN32 + return (HANDLE)_get_osfhandle(GetDescriptor()); +#else return GetDescriptor(); +#endif +} + +bool NativeFile::HasReadableData() { +#ifdef _WIN32 + DWORD available_bytes = 0; + return !PeekNamedPipe((HANDLE)_get_osfhandle(GetDescriptor()), NULL, 0, NULL, labath wrote: That's better, but I do have a question, and a comment :) - Do we need to support selecting on actual files? That doesn't even work on posix systems (the file just always comes back as "readable" -- which makes sense because select just tells you whether the operation will block), so if anything, I think we should emulate that. Waiting for file modification requires things like inotify(7), and fortunately, noone has had a use case for that for now. If we ever needed to support it, that should probably be a separate kind of an event. I'm assuming that `GetFileType` on a pipe handle will return `FILE_TYPE_PIPE`, even if that handle was passed as `stdin`. - it my long term vision, I would like lldb-dap to create Pipe IOObject directly (perhaps via some helper on the File class) instead of having the MainLoop class guess it. However, given that Pipe is not an IOObject right now, this is something I can live with. https://github.com/llvm/llvm-project/pull/145621 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Document MCP support in LLDB (PR #145935)
@@ -0,0 +1,68 @@ +# Model Context Protocol (MCP) + +LLDB supports for the [Model Context Protocol][1] (MCP). This structured, +machine-friendly protocol allows AI models to access and interact with external +tools, such as the debugger. Using MCP, an AI agent can execute LLDB commands +to control the debugger: set breakpoints, inspect memory, step through code. +This can range from helping you run a specific command you can't immediately +remember to a fully agent-driven debugging experiences + +## MCP Server + +To start the MCP server in LLDB, use the `protocol-server start` command. +Specify `MCP` as the protocol and provide a URI to listen on. For example, to +start listening for local TCP connections on port `5`, use the following +command: + +``` +(lldb) protocol-server start MCP listen://localhost:5 +MCP server started with connection listeners: connection://[::1]:5, connection://[127.0.0.1]:5 +``` + +The server will automatically stop when exiting LLDB, or it can be stopped +explicitly with the `protocol-server stop` command. + +``` +(lldb) protocol-server stop MCP +``` + +## MCP Client + +MCP uses standard input/output (stdio) for communication between client and +server. The exact configuration depends on the client, but most applications +allow you to specify an MCP server as a binary and arguments. This means that +you need to use something like `netcat` to connect to LLDB's MCP server and +forward communication over stdio over the network connection. + +Configuration example for [Claude Code][2]: + +``` +{ + "mcpServers": { +"tool": { + "command": "/usr/bin/nc", + "args": ["localhost", "5"] +} + } +} +``` + +Configuration example for [Visual Studio Code][3]: + +``` +{ + "mcp": { +"servers": { + "lldb": { +"type": "stdio", +"command": "/usr/bin/nc", +"args": ["localhost", "5"] + } +} + } +} +``` + +[1]: https://modelcontextprotocol.io +[2]: https://modelcontextprotocol.io/quickstart/user +[3]: https://code.visualstudio.com/docs/copilot/chat/mcp-servers DavidSpickett wrote: I would add these links to the text instead of making them citations like this. If you're feeling adventurous you could see if https://github.blog/changelog/2021-09-30-footnotes-now-supported-in-markdown-fields/ works in our docs generator, but I think links within the text is cleaner anyway. https://github.com/llvm/llvm-project/pull/145935 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Document MCP support in LLDB (PR #145935)
@@ -0,0 +1,68 @@ +# Model Context Protocol (MCP) + +LLDB supports for the [Model Context Protocol][1] (MCP). This structured, +machine-friendly protocol allows AI models to access and interact with external +tools, such as the debugger. Using MCP, an AI agent can execute LLDB commands +to control the debugger: set breakpoints, inspect memory, step through code. +This can range from helping you run a specific command you can't immediately +remember to a fully agent-driven debugging experiences + +## MCP Server + +To start the MCP server in LLDB, use the `protocol-server start` command. +Specify `MCP` as the protocol and provide a URI to listen on. For example, to +start listening for local TCP connections on port `5`, use the following +command: + +``` +(lldb) protocol-server start MCP listen://localhost:5 +MCP server started with connection listeners: connection://[::1]:5, connection://[127.0.0.1]:5 +``` + +The server will automatically stop when exiting LLDB, or it can be stopped +explicitly with the `protocol-server stop` command. + +``` +(lldb) protocol-server stop MCP DavidSpickett wrote: Implies you can run multiple servers one on each transport type? Also can you have multiple? Here would be a good place to note whether you can or cannot. https://github.com/llvm/llvm-project/pull/145935 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Document MCP support in LLDB (PR #145935)
@@ -0,0 +1,68 @@ +# Model Context Protocol (MCP) + +LLDB supports for the [Model Context Protocol][1] (MCP). This structured, DavidSpickett wrote: `supports the`, drop the `for` https://github.com/llvm/llvm-project/pull/145935 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Document MCP support in LLDB (PR #145935)
@@ -0,0 +1,68 @@ +# Model Context Protocol (MCP) + +LLDB supports for the [Model Context Protocol][1] (MCP). This structured, +machine-friendly protocol allows AI models to access and interact with external +tools, such as the debugger. Using MCP, an AI agent can execute LLDB commands +to control the debugger: set breakpoints, inspect memory, step through code. +This can range from helping you run a specific command you can't immediately +remember to a fully agent-driven debugging experiences + +## MCP Server + +To start the MCP server in LLDB, use the `protocol-server start` command. +Specify `MCP` as the protocol and provide a URI to listen on. For example, to +start listening for local TCP connections on port `5`, use the following +command: + +``` +(lldb) protocol-server start MCP listen://localhost:5 +MCP server started with connection listeners: connection://[::1]:5, connection://[127.0.0.1]:5 +``` + +The server will automatically stop when exiting LLDB, or it can be stopped +explicitly with the `protocol-server stop` command. + +``` +(lldb) protocol-server stop MCP +``` + +## MCP Client + +MCP uses standard input/output (stdio) for communication between client and +server. The exact configuration depends on the client, but most applications +allow you to specify an MCP server as a binary and arguments. This means that +you need to use something like `netcat` to connect to LLDB's MCP server and +forward communication over stdio over the network connection. DavidSpickett wrote: Add a "diagram" to show the flow like: ``` LLDB <--> socket <--> netcat <--> stdio <--> MCP client ``` https://github.com/llvm/llvm-project/pull/145935 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Document MCP support in LLDB (PR #145935)
@@ -0,0 +1,68 @@ +# Model Context Protocol (MCP) + +LLDB supports for the [Model Context Protocol][1] (MCP). This structured, +machine-friendly protocol allows AI models to access and interact with external +tools, such as the debugger. Using MCP, an AI agent can execute LLDB commands DavidSpickett wrote: `such as a debugger` if you're going to generically refer to debuggers. Or `such as LLDB` if you prefer. https://github.com/llvm/llvm-project/pull/145935 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Document MCP support in LLDB (PR #145935)
@@ -0,0 +1,68 @@ +# Model Context Protocol (MCP) + +LLDB supports for the [Model Context Protocol][1] (MCP). This structured, +machine-friendly protocol allows AI models to access and interact with external +tools, such as the debugger. Using MCP, an AI agent can execute LLDB commands +to control the debugger: set breakpoints, inspect memory, step through code. +This can range from helping you run a specific command you can't immediately DavidSpickett wrote: I prefer to expand contractions in a technical document: can't -> cannot https://github.com/llvm/llvm-project/pull/145935 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Document MCP support in LLDB (PR #145935)
@@ -0,0 +1,68 @@ +# Model Context Protocol (MCP) + +LLDB supports for the [Model Context Protocol][1] (MCP). This structured, +machine-friendly protocol allows AI models to access and interact with external +tools, such as the debugger. Using MCP, an AI agent can execute LLDB commands +to control the debugger: set breakpoints, inspect memory, step through code. +This can range from helping you run a specific command you can't immediately +remember to a fully agent-driven debugging experiences DavidSpickett wrote: `to full agent-driven`, drop the `a`. Or rephrase `to a fully agent-driven debugging experience` singular. https://github.com/llvm/llvm-project/pull/145935 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Document MCP support in LLDB (PR #145935)
@@ -0,0 +1,68 @@ +# Model Context Protocol (MCP) + +LLDB supports for the [Model Context Protocol][1] (MCP). This structured, +machine-friendly protocol allows AI models to access and interact with external +tools, such as the debugger. Using MCP, an AI agent can execute LLDB commands +to control the debugger: set breakpoints, inspect memory, step through code. +This can range from helping you run a specific command you can't immediately +remember to a fully agent-driven debugging experiences + +## MCP Server + +To start the MCP server in LLDB, use the `protocol-server start` command. +Specify `MCP` as the protocol and provide a URI to listen on. For example, to DavidSpickett wrote: I presume MCP is the only supported protocol at this time and the command will complain if you give it anything else, right? No need to mention it if the command is going to give a decent error anyway. https://github.com/llvm/llvm-project/pull/145935 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] da2969b - [LLDB] Update DIL to handle smart pointers; add more tests. (#143786)
Author: cmtice Date: 2025-06-27T07:30:14-07:00 New Revision: da2969b1051f4adf57d4395cd2f3e1e8c33b3d1b URL: https://github.com/llvm/llvm-project/commit/da2969b1051f4adf57d4395cd2f3e1e8c33b3d1b DIFF: https://github.com/llvm/llvm-project/commit/da2969b1051f4adf57d4395cd2f3e1e8c33b3d1b.diff LOG: [LLDB] Update DIL to handle smart pointers; add more tests. (#143786) This updates the DIL implementation to handle smart pointers (accessing field members and dereferencing) in the same way the current 'frame variable' implementation does. It also adds tests for handling smart pointers, as well as some additional DIL tests. Added: lldb/test/API/commands/frame/var-dil/basics/BitField/Makefile lldb/test/API/commands/frame/var-dil/basics/BitField/TestFrameVarDILBitField.py lldb/test/API/commands/frame/var-dil/basics/BitField/main.cpp lldb/test/API/commands/frame/var-dil/basics/Indirection/Makefile lldb/test/API/commands/frame/var-dil/basics/Indirection/TestFrameVarDILIndirection.py lldb/test/API/commands/frame/var-dil/basics/Indirection/main.cpp lldb/test/API/commands/frame/var-dil/basics/PointerDereference/Makefile lldb/test/API/commands/frame/var-dil/basics/PointerDereference/TestFrameVarDILPointerDereference.py lldb/test/API/commands/frame/var-dil/basics/PointerDereference/main.cpp lldb/test/API/commands/frame/var-dil/basics/QualifiedId/Makefile lldb/test/API/commands/frame/var-dil/basics/QualifiedId/TestFrameVarDILQualifiedId.py lldb/test/API/commands/frame/var-dil/basics/QualifiedId/main.cpp lldb/test/API/commands/frame/var-dil/basics/SyntheticDereference/Makefile lldb/test/API/commands/frame/var-dil/basics/SyntheticDereference/TestFrameVarDILSyntheticDereference.py lldb/test/API/commands/frame/var-dil/basics/SyntheticDereference/main.cpp lldb/test/API/commands/frame/var-dil/basics/SyntheticDereference/wrapPtrSynthProvider.py Modified: lldb/source/ValueObject/DILEval.cpp lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/shared_ptr/TestDataFormatterLibcxxSharedPtr.py lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/shared_ptr/main.cpp lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/TestDataFormatterLibcxxUniquePtr.py lldb/test/API/functionalities/data-formatter/data-formatter-stl/libcxx/unique_ptr/main.cpp Removed: diff --git a/lldb/source/ValueObject/DILEval.cpp b/lldb/source/ValueObject/DILEval.cpp index b2bb4e20ddc24..4293990208c77 100644 --- a/lldb/source/ValueObject/DILEval.cpp +++ b/lldb/source/ValueObject/DILEval.cpp @@ -253,6 +253,12 @@ Interpreter::Visit(const UnaryOpNode *node) { rhs = dynamic_rhs; lldb::ValueObjectSP child_sp = rhs->Dereference(error); +if (!child_sp && m_use_synthetic) { + if (lldb::ValueObjectSP synth_obj_sp = rhs->GetSyntheticValue()) { +error.Clear(); +child_sp = synth_obj_sp->Dereference(error); + } +} if (error.Fail()) return llvm::make_error(m_expr, error.AsCString(), node->GetLocation()); @@ -280,6 +286,7 @@ Interpreter::Visit(const MemberOfNode *node) { auto base_or_err = Evaluate(node->GetBase()); if (!base_or_err) return base_or_err; + bool expr_is_ptr = node->GetIsArrow(); lldb::ValueObjectSP base = *base_or_err; // Perform some basic type & correctness checking. @@ -319,11 +326,11 @@ Interpreter::Visit(const MemberOfNode *node) { return llvm::make_error( m_expr, errMsg, node->GetLocation(), node->GetFieldName().size()); } + expr_is_ptr = false; } } if (m_check_ptr_vs_member) { -bool expr_is_ptr = node->GetIsArrow(); bool base_is_ptr = base->IsPointerType(); if (expr_is_ptr != base_is_ptr) { diff --git a/lldb/test/API/commands/frame/var-dil/basics/BitField/Makefile b/lldb/test/API/commands/frame/var-dil/basics/BitField/Makefile new file mode 100644 index 0..8b20bcb05 --- /dev/null +++ b/lldb/test/API/commands/frame/var-dil/basics/BitField/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/test/API/commands/frame/var-dil/basics/BitField/TestFrameVarDILBitField.py b/lldb/test/API/commands/frame/var-dil/basics/BitField/TestFrameVarDILBitField.py new file mode 100644 index 0..0e35069519093 --- /dev/null +++ b/lldb/test/API/commands/frame/var-dil/basics/BitField/TestFrameVarDILBitField.py @@ -0,0 +1,43 @@ +""" +Make sure 'frame var' using DIL parser/evaluator works for bit fields. +""" + +import lldb +from lldbsuite.test.lldbtest import * +from lldbsuite.test.decorators import * +from lldbsuite.test import lldbutil + +import os +import shutil +import time + + +class TestFrameVarDILBitField(TestBase): +# If your test case doesn't stress debug
[Lldb-commits] [lldb] [LLDB] Update DIL to handle smart pointers; add more tests. (PR #143786)
https://github.com/cmtice closed https://github.com/llvm/llvm-project/pull/143786 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Support disassembling RISC-V proprietary instructions (PR #145793)
@@ -0,0 +1,87 @@ +""" +Defines a command, fdis, that does filtered disassembly. The command does the +lldb disassemble command with -b and any other arguments passed in, and +pipes that through a provided filter program. + +The intention is to support disassembly of RISC-V proprietary instructions. +This is handled with llvm-objdump by piping the output of llvm-objdump through +a filter program. This script is intended to mimic that workflow. +""" + +import lldb +import subprocess + +filter_program = "crustfilt" + +def __lldb_init_module(debugger, dict): +debugger.HandleCommand( +'command script add -f filter_disasm.fdis fdis') +print("Disassembly filter command (fdis) loaded") +print("Filter program set to %s" % filter_program) + + +def fdis(debugger, args, result, dict): DavidSpickett wrote: I presume you already read https://lldb.llvm.org/use/python-reference.html#create-a-new-lldb-command-using-a-python-function or at least some of it (it's a lot). https://github.com/llvm/llvm-project/blob/main/lldb/examples/python/cmdtemplate.py shows the style I was thinking of, which should get you the same help formatting as a built in command. https://github.com/llvm/llvm-project/pull/145793 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [LLDB] Add type summaries for MSVC STL strings (PR #143177)
@@ -299,6 +299,8 @@ def parseOptionsAndInitTestdirs(): configuration.libcxx_library_dir = args.libcxx_library_dir configuration.cmake_build_type = args.cmake_build_type.lower() +configuration.target_triple = args.target_triple + DavidSpickett wrote: > I did apply your commit onto main, rather than building the PR branch so it > could be a different change causing that. The unexpected passes are due to this change specifically. https://github.com/llvm/llvm-project/pull/143177 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Support disassembling RISC-V proprietary instructions (PR #145793)
@@ -658,8 +658,13 @@ void Instruction::Dump(lldb_private::Stream *s, uint32_t max_opcode_byte_size, // the byte dump to be able to always show 15 bytes (3 chars each) plus a // space if (max_opcode_byte_size > 0) -m_opcode.Dump(&ss, max_opcode_byte_size * 3 + 1); - else +// make RISC-V opcode dump look like llvm-objdump DavidSpickett wrote: If you say instead "Pretty print RISC-V opcodes in the same format that llvm-objdump uses." this hints at the motivation and what keywords to look for in llvm-objdump's source. https://github.com/llvm/llvm-project/pull/145793 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Support disassembling RISC-V proprietary instructions (PR #145793)
@@ -658,8 +658,13 @@ void Instruction::Dump(lldb_private::Stream *s, uint32_t max_opcode_byte_size, // the byte dump to be able to always show 15 bytes (3 chars each) plus a // space if (max_opcode_byte_size > 0) -m_opcode.Dump(&ss, max_opcode_byte_size * 3 + 1); - else +// make RISC-V opcode dump look like llvm-objdump +if (exe_ctx && +exe_ctx->GetTargetSP()->GetArchitecture().GetTriple().isRISCV()) + m_opcode.DumpRISCV(&ss, max_opcode_byte_size * 3 + 1); DavidSpickett wrote: Pull the minimum size out into: ``` auto min_byte_width = max_opcode_byte_size * 3 + 1; ``` Then use it in both calls, so it's clear they use the same minimum. https://github.com/llvm/llvm-project/pull/145793 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Support disassembling RISC-V proprietary instructions (PR #145793)
DavidSpickett wrote: > Arm M profile has > https://developer.arm.com/Architectures/Arm%20Custom%20Instructions, I'll > look into that and see if it would benefit from a change of output format > too. Just in theory though, I don't think we shipped support for open source > debuggers and I'm not about to implement it myself. CDE works by assigning one of the co-processors to be the encodings for the custom instructions and it has a few fixed formats you can use. It's not like RISC-V where the layout can be anything you want. Which means that the disassembler would probably print some form, with encoding, and that can already be used to filter if you wanted to. I also checked how AArch64 works: `` $ cat /tmp/test.c int main() { asm volatile(".inst 0x4321"); return 0; } ``` objdump shows the bytes: ``` 0714 : 714: d10043ff sub sp, sp, #0x10 718: 2a1f03e0 mov w0, wzr 71c: b9000fff str wzr, [sp, #0xc] 720: 4321 724: 910043ff add sp, sp, #0x10 728: d65f03c0 ret ``` As does LLDB: ``` (lldb) dis -b test.o`main: 0xa714 <+0>: 0xd10043ff subsp, sp, #0x10 0xa718 <+4>: 0x2a1f03e0 movw0, wzr 0xa71c <+8>: 0xb9000fff strwzr, [sp, #0xc] -> 0xa720 <+12>: 0x4321; unknown opcode 0xa724 <+16>: 0x910043ff addsp, sp, #0x10 0xa728 <+20>: 0xd65f03c0 ret ``` So for AArch64 we happen to mostly match objdump's output, and it's useful enough for humans and scripts because it can only ever be 32-bit encodings. Also having looked at the pretty printer system in llvm-objdump, I think `if riscv` is ok here. LLDB is effectively a selective objdumper and the only difference between what you're adding here and what llvm-objdump has is the framework around it. Which we do not need when only RISC-V wants this. https://github.com/llvm/llvm-project/pull/145793 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] Support disassembling RISC-V proprietary instructions (PR #145793)
@@ -78,6 +78,44 @@ lldb::ByteOrder Opcode::GetDataByteOrder() const { return eByteOrderInvalid; } +// make RISC-V byte dumps look like llvm-objdump, instead of just dumping bytes +int Opcode::DumpRISCV(Stream *s, uint32_t min_byte_width) { + const uint32_t previous_bytes = s->GetWrittenBytes(); + // if m_type is not bytes, call Dump + if (m_type != Opcode::eTypeBytes) +return Dump(s, min_byte_width); + + // from RISCVPrettyPrinter in llvm-objdump.cpp + // if size % 4 == 0, print as 1 or 2 32 bit values (32 or 64 bit inst) + // else if size % 2 == 0, print as 1 or 3 16 bit values (16 or 48 bit inst) + // else fall back and print bytes DavidSpickett wrote: I would put these comments next to the ifs they refer to, I have to read the code anyway so it makes more sense to me to have the commentary interleaved. https://github.com/llvm/llvm-project/pull/145793 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb][Mach-O] Allow "process metadata" LC_NOTE to supply registers (PR #144627)
@@ -0,0 +1,300 @@ +//===-- RegisterContextUnifiedCore.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 "RegisterContextUnifiedCore.h" +#include "lldb/Target/DynamicRegisterInfo.h" +#include "lldb/Target/Process.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/StructuredData.h" + +using namespace lldb; +using namespace lldb_private; + +RegisterContextUnifiedCore::RegisterContextUnifiedCore( +Thread &thread, uint32_t concrete_frame_idx, +RegisterContextSP core_thread_regctx_sp, +StructuredData::ObjectSP metadata_thread_registers) +: RegisterContext(thread, concrete_frame_idx) { + + ProcessSP process_sp(thread.GetProcess()); + Target &target = process_sp->GetTarget(); + StructuredData::Dictionary *metadata_registers_dict = nullptr; + + // If we have thread metadata, check if the keys for register + // definitions are present; if not, clear the ObjectSP. + if (metadata_thread_registers && + metadata_thread_registers->GetAsDictionary() && + metadata_thread_registers->GetAsDictionary()->HasKey("register_info")) { +metadata_registers_dict = metadata_thread_registers->GetAsDictionary() + ->GetValueForKey("register_info") + ->GetAsDictionary(); +if (metadata_registers_dict) + if (!metadata_registers_dict->HasKey("sets") || + !metadata_registers_dict->HasKey("registers")) +metadata_registers_dict = nullptr; + } + + // When creating a register set list from the two sources, + // the LC_THREAD aka core_thread_regctx_sp register sets + // will be used at the same indexes. + // Any additional sets named by the thread metadata registers + // will be added after them. If the thread metadata + // specify a set with the same name as LC_THREAD, the already-used + // index from the core register context will be used in + // the RegisterInfo. + std::map metadata_regset_to_combined_regset; + + // Calculate the total size of the register store buffer we need + // for all registers. The corefile register definitions may include + // RegisterInfo descriptions of registers that aren't actually + // available. For simplicity, calculate the size of all registers + // as if they are available, so we can maintain the same offsets into + // the buffer. + uint32_t core_buffer_end = 0; + for (size_t idx = 0; idx < core_thread_regctx_sp->GetRegisterCount(); idx++) { +const RegisterInfo *reginfo = +core_thread_regctx_sp->GetRegisterInfoAtIndex(idx); +core_buffer_end = +std::max(reginfo->byte_offset + reginfo->byte_size, core_buffer_end); + } + + // Add metadata register sizes to the total buffer size. + uint32_t combined_buffer_end = core_buffer_end; + if (metadata_registers_dict) { +StructuredData::Array *registers = nullptr; +if (metadata_registers_dict->GetValueForKeyAsArray("registers", registers)) + registers->ForEach( + [&combined_buffer_end](StructuredData::Object *ent) -> bool { +uint32_t bitsize; +if (!ent->GetAsDictionary()->GetValueForKeyAsInteger("bitsize", + bitsize)) + return false; +combined_buffer_end += (bitsize / 8); +return true; + }); + } + m_register_data.resize(combined_buffer_end, 0); + + // Copy the core register values into our combined data buffer, + // skip registers that are contained within another (e.g. w0 vs. x0) + // and registers that return as "unavailable". + for (size_t idx = 0; idx < core_thread_regctx_sp->GetRegisterCount(); idx++) { +const RegisterInfo *reginfo = +core_thread_regctx_sp->GetRegisterInfoAtIndex(idx); +RegisterValue val; +if (!reginfo->value_regs && +core_thread_regctx_sp->ReadRegister(reginfo, val)) + memcpy(m_register_data.data() + reginfo->byte_offset, val.GetBytes(), + val.GetByteSize()); + } + + // Set 'offset' fields for each register definition into our combined + // register data buffer. DynamicRegisterInfo needs + // this field set to parse the JSON. + // Also copy the values of the registers into our register data buffer. + if (metadata_registers_dict) { +size_t offset = core_buffer_end; +ByteOrder byte_order = core_thread_regctx_sp->GetByteOrder(); +StructuredData::Array *registers; +if (metadata_registers_dict->GetValueForKeyAsArray("registers", registers)) + registers->ForEach([this, &offset, + byte_order](StructuredData::Object *ent) -> bool { +uint64_t bitsize;
[Lldb-commits] [lldb] [lldb][Mach-O] Allow "process metadata" LC_NOTE to supply registers (PR #144627)
https://github.com/jasonmolenda updated https://github.com/llvm/llvm-project/pull/144627 >From 92348b28fb02901e9437b92c1ddf8cfed31c Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Tue, 17 Jun 2025 18:57:11 -0700 Subject: [PATCH 01/19] [lldb][Mach-O] Allow "process metadata" LC_NOTE to supply registers The "process metadata" LC_NOTE allows for thread IDs to be specified in a Mach-O corefile. This extends the JSON recognzied in that LC_NOTE to allow for additional registers to be supplied on a per-thread basis. The registers included in a Mach-O corefile LC_THREAD load command can only be one of the register flavors that the kernel (xnu) defines in for arm64 -- the general purpose registers, floating point registers, exception registers. JTAG style corefile producers may have access to many additional registers beyond these that EL0 programs typically use, for instance TCR_EL1 on AArch64, and people developing low level code need access to these registers. This patch defines a format for including these registers for any thread. The JSON in "process metadata" is a dictionary that must have a `threads` key. The value is an array of entries, one per LC_THREAD in the Mach-O corefile. The number of entries must match the LC_THREADs so they can be correctly associated. Each thread's dictionary must have two keys, `sets`, and `registers`. `sets` is an array of register set names. If a register set name matches one from the LC_THREAD core registers, any registers that are defined will be added to that register set. e.g. metadata can add a register to the "General Purpose Registers" set that lldb shows users. `registers` is an array of dictionaries, one per register. Each register must have the keys `name`, `value`, `bitsize`, and `set`. It may provide additional keys like `alt-name`, that `DynamicRegisterInfo::SetRegisterInfo` recognizes. This `sets` + `registers` formatting is the same that is used by the `target.process.python-os-plugin-path` script interface uses, both are parsed by `DynamicRegisterInfo`. The one addition is that in this LC_NOTE metadata, each register must also have a `value` field, with the value provided in big-endian base 10, as usual with JSON. In RegisterContextUnifiedCore, I combine the register sets & registers from the LC_THREAD for a specific thread, and the metadata sets & registers for that thread from the LC_NOTE. Even if no LC_NOTE is present, this class ingests the LC_THREAD register contexts and reformats it to its internal stores before returning itself as the RegisterContex, instead of shortcutting and returning the core's native RegisterContext. I could have gone either way with that, but in the end I decided if the code is correct, we should live on it always. I added a test where we process save-core to create a userland corefile, then use a utility "add-lcnote" to strip the existing "process metadata" LC_NOTE that lldb put in it, and adds a new one from a JSON string. rdar://74358787 --- lldb/include/lldb/Symbol/ObjectFile.h | 17 +- .../ObjectFile/Mach-O/ObjectFileMachO.cpp | 61 ++- .../ObjectFile/Mach-O/ObjectFileMachO.h | 2 + .../Plugins/Process/mach-core/CMakeLists.txt | 1 + .../mach-core/RegisterContextUnifiedCore.cpp | 293 + .../mach-core/RegisterContextUnifiedCore.h| 57 +++ .../Process/mach-core/ThreadMachCore.cpp | 55 ++- .../lc-note/additional-registers/Makefile | 11 + .../TestMetadataRegisters.py | 100 + .../additional-registers/add-lcnote.cpp | 384 ++ .../lc-note/additional-registers/main.c | 11 + 11 files changed, 957 insertions(+), 35 deletions(-) create mode 100644 lldb/source/Plugins/Process/mach-core/RegisterContextUnifiedCore.cpp create mode 100644 lldb/source/Plugins/Process/mach-core/RegisterContextUnifiedCore.h create mode 100644 lldb/test/API/macosx/lc-note/additional-registers/Makefile create mode 100644 lldb/test/API/macosx/lc-note/additional-registers/TestMetadataRegisters.py create mode 100644 lldb/test/API/macosx/lc-note/additional-registers/add-lcnote.cpp create mode 100644 lldb/test/API/macosx/lc-note/additional-registers/main.c diff --git a/lldb/include/lldb/Symbol/ObjectFile.h b/lldb/include/lldb/Symbol/ObjectFile.h index 43567592dd447..1b9ae1fb31a69 100644 --- a/lldb/include/lldb/Symbol/ObjectFile.h +++ b/lldb/include/lldb/Symbol/ObjectFile.h @@ -18,6 +18,7 @@ #include "lldb/Utility/Endian.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/FileSpecList.h" +#include "lldb/Utility/StructuredData.h" #include "lldb/Utility/UUID.h" #include "lldb/lldb-private.h" #include "llvm/Support/Threading.h" @@ -544,9 +545,9 @@ class ObjectFile : public std::enable_shared_from_this, return false; } - /// Get metadata about threads from the corefile. + /// Get metadata about thread ids from the corefile. /// - /// The corefile may have metadata (e.g. a Mach-O "thread ext
[Lldb-commits] [lldb] a64db49 - [lldb][Mach-O] Allow "process metadata" LC_NOTE to supply registers (#144627)
Author: Jason Molenda Date: 2025-06-27T18:43:41-07:00 New Revision: a64db49371f040859a9de7c0f4fbfb655d8dda17 URL: https://github.com/llvm/llvm-project/commit/a64db49371f040859a9de7c0f4fbfb655d8dda17 DIFF: https://github.com/llvm/llvm-project/commit/a64db49371f040859a9de7c0f4fbfb655d8dda17.diff LOG: [lldb][Mach-O] Allow "process metadata" LC_NOTE to supply registers (#144627) The "process metadata" LC_NOTE allows for thread IDs to be specified in a Mach-O corefile. This extends the JSON recognzied in that LC_NOTE to allow for additional registers to be supplied on a per-thread basis. The registers included in a Mach-O corefile LC_THREAD load command can only be one of the register flavors that the kernel (xnu) defines in for arm64 -- the general purpose registers, floating point registers, exception registers. JTAG style corefile producers may have access to many additional registers beyond these that EL0 programs typically use, for instance TCR_EL1 on AArch64, and people developing low level code need access to these registers. This patch defines a format for including these registers for any thread. The JSON in "process metadata" is a dictionary that must have a `threads` key. The value is an array of entries, one per LC_THREAD in the Mach-O corefile. The number of entries must match the LC_THREADs so they can be correctly associated. Each thread's dictionary must have two keys, `sets`, and `registers`. `sets` is an array of register set names. If a register set name matches one from the LC_THREAD core registers, any registers that are defined will be added to that register set. e.g. metadata can add a register to the "General Purpose Registers" set that lldb shows users. `registers` is an array of dictionaries, one per register. Each register must have the keys `name`, `value`, `bitsize`, and `set`. It may provide additional keys like `alt-name`, that `DynamicRegisterInfo::SetRegisterInfo` recognizes. This `sets` + `registers` formatting is the same that is used by the `target.process.python-os-plugin-path` script interface uses, both are parsed by `DynamicRegisterInfo`. The one addition is that in this LC_NOTE metadata, each register must also have a `value` field, with the value provided in big-endian base 10, as usual with JSON. In RegisterContextUnifiedCore, I combine the register sets & registers from the LC_THREAD for a specific thread, and the metadata sets & registers for that thread from the LC_NOTE. Even if no LC_NOTE is present, this class ingests the LC_THREAD register contexts and reformats it to its internal stores before returning itself as the RegisterContex, instead of shortcutting and returning the core's native RegisterContext. I could have gone either way with that, but in the end I decided if the code is correct, we should live on it always. I added a test where we process save-core to create a userland corefile, then use a utility "add-lcnote" to strip the existing "process metadata" LC_NOTE that lldb put in it, and adds a new one from a JSON string. rdar://74358787 - Co-authored-by: Jonas Devlieghere Added: lldb/source/Plugins/Process/mach-core/RegisterContextUnifiedCore.cpp lldb/source/Plugins/Process/mach-core/RegisterContextUnifiedCore.h lldb/test/API/macosx/lc-note/additional-registers/Makefile lldb/test/API/macosx/lc-note/additional-registers/TestMetadataRegisters.py lldb/test/API/macosx/lc-note/additional-registers/add-lcnote.cpp lldb/test/API/macosx/lc-note/additional-registers/main.c Modified: lldb/include/lldb/Symbol/ObjectFile.h lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.h lldb/source/Plugins/Process/mach-core/CMakeLists.txt lldb/source/Plugins/Process/mach-core/ThreadMachCore.cpp Removed: diff --git a/lldb/include/lldb/Symbol/ObjectFile.h b/lldb/include/lldb/Symbol/ObjectFile.h index 43567592dd447..1b9ae1fb31a69 100644 --- a/lldb/include/lldb/Symbol/ObjectFile.h +++ b/lldb/include/lldb/Symbol/ObjectFile.h @@ -18,6 +18,7 @@ #include "lldb/Utility/Endian.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/FileSpecList.h" +#include "lldb/Utility/StructuredData.h" #include "lldb/Utility/UUID.h" #include "lldb/lldb-private.h" #include "llvm/Support/Threading.h" @@ -544,9 +545,9 @@ class ObjectFile : public std::enable_shared_from_this, return false; } - /// Get metadata about threads from the corefile. + /// Get metadata about thread ids from the corefile. /// - /// The corefile may have metadata (e.g. a Mach-O "thread extrainfo" + /// The corefile may have metadata (e.g. a Mach-O "process metadata" /// LC_NOTE) which for the threads in the process; this method tries /// to retrieve them. /// @@ -568,6 +569,18 @@ class ObjectFile : public std::enable_shared_from_this, return false; } + ///
[Lldb-commits] [lldb] [lldb][Mach-O] Allow "process metadata" LC_NOTE to supply registers (PR #144627)
@@ -0,0 +1,300 @@ +//===-- RegisterContextUnifiedCore.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 "RegisterContextUnifiedCore.h" +#include "lldb/Target/DynamicRegisterInfo.h" +#include "lldb/Target/Process.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/StructuredData.h" + +using namespace lldb; +using namespace lldb_private; + +RegisterContextUnifiedCore::RegisterContextUnifiedCore( +Thread &thread, uint32_t concrete_frame_idx, +RegisterContextSP core_thread_regctx_sp, +StructuredData::ObjectSP metadata_thread_registers) +: RegisterContext(thread, concrete_frame_idx) { + + ProcessSP process_sp(thread.GetProcess()); + Target &target = process_sp->GetTarget(); + StructuredData::Dictionary *metadata_registers_dict = nullptr; + + // If we have thread metadata, check if the keys for register + // definitions are present; if not, clear the ObjectSP. + if (metadata_thread_registers && + metadata_thread_registers->GetAsDictionary() && + metadata_thread_registers->GetAsDictionary()->HasKey("register_info")) { +metadata_registers_dict = metadata_thread_registers->GetAsDictionary() + ->GetValueForKey("register_info") + ->GetAsDictionary(); +if (metadata_registers_dict) + if (!metadata_registers_dict->HasKey("sets") || + !metadata_registers_dict->HasKey("registers")) +metadata_registers_dict = nullptr; + } + + // When creating a register set list from the two sources, + // the LC_THREAD aka core_thread_regctx_sp register sets + // will be used at the same indexes. + // Any additional sets named by the thread metadata registers + // will be added after them. If the thread metadata + // specify a set with the same name as LC_THREAD, the already-used + // index from the core register context will be used in + // the RegisterInfo. + std::map metadata_regset_to_combined_regset; + + // Calculate the total size of the register store buffer we need + // for all registers. The corefile register definitions may include + // RegisterInfo descriptions of registers that aren't actually + // available. For simplicity, calculate the size of all registers + // as if they are available, so we can maintain the same offsets into + // the buffer. + uint32_t core_buffer_end = 0; + for (size_t idx = 0; idx < core_thread_regctx_sp->GetRegisterCount(); idx++) { +const RegisterInfo *reginfo = +core_thread_regctx_sp->GetRegisterInfoAtIndex(idx); +core_buffer_end = +std::max(reginfo->byte_offset + reginfo->byte_size, core_buffer_end); + } + + // Add metadata register sizes to the total buffer size. + uint32_t combined_buffer_end = core_buffer_end; + if (metadata_registers_dict) { +StructuredData::Array *registers = nullptr; +if (metadata_registers_dict->GetValueForKeyAsArray("registers", registers)) + registers->ForEach( + [&combined_buffer_end](StructuredData::Object *ent) -> bool { +uint32_t bitsize; +if (!ent->GetAsDictionary()->GetValueForKeyAsInteger("bitsize", + bitsize)) + return false; +combined_buffer_end += (bitsize / 8); +return true; + }); + } + m_register_data.resize(combined_buffer_end, 0); + + // Copy the core register values into our combined data buffer, + // skip registers that are contained within another (e.g. w0 vs. x0) + // and registers that return as "unavailable". + for (size_t idx = 0; idx < core_thread_regctx_sp->GetRegisterCount(); idx++) { +const RegisterInfo *reginfo = +core_thread_regctx_sp->GetRegisterInfoAtIndex(idx); +RegisterValue val; +if (!reginfo->value_regs && +core_thread_regctx_sp->ReadRegister(reginfo, val)) + memcpy(m_register_data.data() + reginfo->byte_offset, val.GetBytes(), + val.GetByteSize()); + } + + // Set 'offset' fields for each register definition into our combined + // register data buffer. DynamicRegisterInfo needs + // this field set to parse the JSON. + // Also copy the values of the registers into our register data buffer. + if (metadata_registers_dict) { +size_t offset = core_buffer_end; +ByteOrder byte_order = core_thread_regctx_sp->GetByteOrder(); +StructuredData::Array *registers; +if (metadata_registers_dict->GetValueForKeyAsArray("registers", registers)) + registers->ForEach([this, &offset, + byte_order](StructuredData::Object *ent) -> bool { +uint64_t bitsize;
[Lldb-commits] [lldb] [llvm] [NFC][DebugInfo][DWARF] Create new low-level dwarf library (PR #145081)
llvm-ci wrote: LLVM Buildbot has detected a new failure on builder `clang-s390x-linux` running on `systemz-1` while building `bolt,lldb,llvm,utils` at step 5 "ninja check 1". Full details are available at: https://lab.llvm.org/buildbot/#/builders/42/builds/5136 Here is the relevant piece of the build log for the reference ``` Step 5 (ninja check 1) failure: stage 1 checked (failure) TEST 'libFuzzer-s390x-default-Linux :: fuzzer-timeout.test' FAILED Exit Code: 1 Command Output (stderr): -- /home/uweigand/sandbox/buildbot/clang-s390x-linux/stage1/./bin/clang -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta --driver-mode=g++ -O2 -gline-tables-only -fsanitize=address,fuzzer -I/home/uweigand/sandbox/buildbot/clang-s390x-linux/llvm/compiler-rt/lib/fuzzer /home/uweigand/sandbox/buildbot/clang-s390x-linux/llvm/compiler-rt/test/fuzzer/TimeoutTest.cpp -o /home/uweigand/sandbox/buildbot/clang-s390x-linux/stage1/runtimes/runtimes-bins/compiler-rt/test/fuzzer/S390XDefaultLinuxConfig/Output/fuzzer-timeout.test.tmp-TimeoutTest # RUN: at line 1 + /home/uweigand/sandbox/buildbot/clang-s390x-linux/stage1/./bin/clang -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta --driver-mode=g++ -O2 -gline-tables-only -fsanitize=address,fuzzer -I/home/uweigand/sandbox/buildbot/clang-s390x-linux/llvm/compiler-rt/lib/fuzzer /home/uweigand/sandbox/buildbot/clang-s390x-linux/llvm/compiler-rt/test/fuzzer/TimeoutTest.cpp -o /home/uweigand/sandbox/buildbot/clang-s390x-linux/stage1/runtimes/runtimes-bins/compiler-rt/test/fuzzer/S390XDefaultLinuxConfig/Output/fuzzer-timeout.test.tmp-TimeoutTest /home/uweigand/sandbox/buildbot/clang-s390x-linux/stage1/./bin/clang -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta --driver-mode=g++ -O2 -gline-tables-only -fsanitize=address,fuzzer -I/home/uweigand/sandbox/buildbot/clang-s390x-linux/llvm/compiler-rt/lib/fuzzer /home/uweigand/sandbox/buildbot/clang-s390x-linux/llvm/compiler-rt/test/fuzzer/TimeoutEmptyTest.cpp -o /home/uweigand/sandbox/buildbot/clang-s390x-linux/stage1/runtimes/runtimes-bins/compiler-rt/test/fuzzer/S390XDefaultLinuxConfig/Output/fuzzer-timeout.test.tmp-TimeoutEmptyTest # RUN: at line 2 + /home/uweigand/sandbox/buildbot/clang-s390x-linux/stage1/./bin/clang -Wthread-safety -Wthread-safety-reference -Wthread-safety-beta --driver-mode=g++ -O2 -gline-tables-only -fsanitize=address,fuzzer -I/home/uweigand/sandbox/buildbot/clang-s390x-linux/llvm/compiler-rt/lib/fuzzer /home/uweigand/sandbox/buildbot/clang-s390x-linux/llvm/compiler-rt/test/fuzzer/TimeoutEmptyTest.cpp -o /home/uweigand/sandbox/buildbot/clang-s390x-linux/stage1/runtimes/runtimes-bins/compiler-rt/test/fuzzer/S390XDefaultLinuxConfig/Output/fuzzer-timeout.test.tmp-TimeoutEmptyTest not /home/uweigand/sandbox/buildbot/clang-s390x-linux/stage1/runtimes/runtimes-bins/compiler-rt/test/fuzzer/S390XDefaultLinuxConfig/Output/fuzzer-timeout.test.tmp-TimeoutTest -timeout=1 2>&1 | FileCheck /home/uweigand/sandbox/buildbot/clang-s390x-linux/llvm/compiler-rt/test/fuzzer/fuzzer-timeout.test --check-prefix=TimeoutTest # RUN: at line 3 + FileCheck /home/uweigand/sandbox/buildbot/clang-s390x-linux/llvm/compiler-rt/test/fuzzer/fuzzer-timeout.test --check-prefix=TimeoutTest + not /home/uweigand/sandbox/buildbot/clang-s390x-linux/stage1/runtimes/runtimes-bins/compiler-rt/test/fuzzer/S390XDefaultLinuxConfig/Output/fuzzer-timeout.test.tmp-TimeoutTest -timeout=1 /home/uweigand/sandbox/buildbot/clang-s390x-linux/llvm/compiler-rt/test/fuzzer/fuzzer-timeout.test:7:14: error: TimeoutTest: expected string not found in input TimeoutTest: #0 ^ :20:44: note: scanning from here ==1619650== ERROR: libFuzzer: timeout after 1 seconds ^ :25:104: note: possible intended match here AddressSanitizer: CHECK failed: asan_report.cpp:227 "((current_error_.kind)) == ((kErrorKindInvalid))" (0x1, 0x0) (tid=1619650) ^ Input file: Check file: /home/uweigand/sandbox/buildbot/clang-s390x-linux/llvm/compiler-rt/test/fuzzer/fuzzer-timeout.test -dump-input=help explains the following input dump. Input was: << . . . 15: MS: 2 ShuffleBytes-InsertByte-; base unit: 94dd9e08c129c785f7f256e82fbe0a30e6d1ae40 16: 0x48,0x69,0x21, 17: Hi! 18: artifact_prefix='./'; Test unit written to ./timeout-c0a0ad26a634840c67a210fefdda76577b03a111 19: Base64: SGkh 20: ==1619650== ERROR: libFuzzer: timeout after 1 seconds check:7'0X~~ error: no match found 21: AddressSanitizer:DEADLYSIGNAL check:7'0 ~~ 22: = check:7'0
[Lldb-commits] [lldb] [lldb] Adding file and pipe support to lldb_private::MainLoopWindows. (PR #145621)
https://github.com/ashgti updated https://github.com/llvm/llvm-project/pull/145621 >From 954f107c85f766ee75370b349eb039819f456db5 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Wed, 25 Jun 2025 18:03:39 -0700 Subject: [PATCH 1/4] [lldb] Adding file and pipe support to lldb_private::MainLoopWindows. This updates MainLoopWindows to support events for reading from a file and a socket type. This unifies both handle types using WaitForMultipleEvents which can listen to both sockets and files for change events. This should allow us to unify how we handle watching files/pipes/sockets on Windows and Posix systems. --- lldb/include/lldb/Host/File.h | 2 + lldb/include/lldb/Host/Socket.h | 2 + .../lldb/Host/windows/MainLoopWindows.h | 3 +- lldb/include/lldb/Utility/IOObject.h | 8 +- lldb/source/Host/common/File.cpp | 18 +++ lldb/source/Host/common/Socket.cpp| 49 +++- .../posix/ConnectionFileDescriptorPosix.cpp | 14 ++- lldb/source/Host/windows/MainLoopWindows.cpp | 116 +- lldb/source/Utility/IOObject.cpp | 9 ++ lldb/unittests/Host/FileTest.cpp | 16 ++- lldb/unittests/Host/MainLoopTest.cpp | 26 11 files changed, 190 insertions(+), 73 deletions(-) diff --git a/lldb/include/lldb/Host/File.h b/lldb/include/lldb/Host/File.h index 9e2d0abe0b1af3..36cb1922812898 100644 --- a/lldb/include/lldb/Host/File.h +++ b/lldb/include/lldb/Host/File.h @@ -127,6 +127,7 @@ class File : public IOObject { /// \return /// a valid handle or IOObject::kInvalidHandleValue WaitableHandle GetWaitableHandle() override; + bool HasReadableData() override; /// Get the file specification for this file, if possible. /// @@ -400,6 +401,7 @@ class NativeFile : public File { Status Write(const void *buf, size_t &num_bytes) override; Status Close() override; WaitableHandle GetWaitableHandle() override; + bool HasReadableData() override; Status GetFileSpec(FileSpec &file_spec) const override; int GetDescriptor() const override; FILE *GetStream() override; diff --git a/lldb/include/lldb/Host/Socket.h b/lldb/include/lldb/Host/Socket.h index 89953ee7fd5b6e..6569e9e6ea8185 100644 --- a/lldb/include/lldb/Host/Socket.h +++ b/lldb/include/lldb/Host/Socket.h @@ -158,6 +158,7 @@ class Socket : public IOObject { bool IsValid() const override { return m_socket != kInvalidSocketValue; } WaitableHandle GetWaitableHandle() override; + bool HasReadableData() override; static llvm::Expected DecodeHostAndPort(llvm::StringRef host_and_port); @@ -185,6 +186,7 @@ class Socket : public IOObject { SocketProtocol m_protocol; NativeSocket m_socket; + WaitableHandle m_waitable_handle; bool m_should_close_fd; }; diff --git a/lldb/include/lldb/Host/windows/MainLoopWindows.h b/lldb/include/lldb/Host/windows/MainLoopWindows.h index 3937a24645d955..43b7d13a0e445d 100644 --- a/lldb/include/lldb/Host/windows/MainLoopWindows.h +++ b/lldb/include/lldb/Host/windows/MainLoopWindows.h @@ -37,11 +37,10 @@ class MainLoopWindows : public MainLoopBase { void Interrupt() override; private: - void ProcessReadObject(IOObject::WaitableHandle handle); llvm::Expected Poll(); struct FdInfo { -void *event; +lldb::IOObjectSP object_sp; Callback callback; }; llvm::DenseMap m_read_fds; diff --git a/lldb/include/lldb/Utility/IOObject.h b/lldb/include/lldb/Utility/IOObject.h index 8cf42992e7be5c..48a8a2076581f3 100644 --- a/lldb/include/lldb/Utility/IOObject.h +++ b/lldb/include/lldb/Utility/IOObject.h @@ -14,6 +14,7 @@ #include #include "lldb/lldb-private.h" +#include "lldb/lldb-types.h" namespace lldb_private { @@ -24,9 +25,9 @@ class IOObject { eFDTypeSocket, // Socket requiring send/recv }; - // TODO: On Windows this should be a HANDLE, and wait should use - // WaitForMultipleObjects - typedef int WaitableHandle; + // A handle for integrating with the host event loop model. + using WaitableHandle = lldb::file_t; + static const WaitableHandle kInvalidHandleValue; IOObject(FDType type) : m_fd_type(type) {} @@ -40,6 +41,7 @@ class IOObject { FDType GetFdType() const { return m_fd_type; } virtual WaitableHandle GetWaitableHandle() = 0; + virtual bool HasReadableData() = 0; protected: FDType m_fd_type; diff --git a/lldb/source/Host/common/File.cpp b/lldb/source/Host/common/File.cpp index 9aa95ffda44cba..2d33f9e2028c4b 100644 --- a/lldb/source/Host/common/File.cpp +++ b/lldb/source/Host/common/File.cpp @@ -118,6 +118,8 @@ IOObject::WaitableHandle File::GetWaitableHandle() { return IOObject::kInvalidHandleValue; } +bool File::HasReadableData() { return false; } + Status File::GetFileSpec(FileSpec &file_spec) const { file_spec.Clear(); return std::error_code(ENOTSUP, std::system_category()); @@ -274,7 +276,23 @@ int NativeFile::GetDescriptor() const { } IOObject::Waitab
[Lldb-commits] [lldb] [lldb] Adding file and pipe support to lldb_private::MainLoopWindows. (PR #145621)
@@ -493,7 +496,12 @@ ConnectionFileDescriptor::BytesAvailable(const Timeout &timeout, break; // Lets keep reading to until we timeout } } else { +#if defined(_WIN32) +if (const auto *sock = static_cast(m_io_sp.get()); ashgti wrote: Removed this change. https://github.com/llvm/llvm-project/pull/145621 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Adding file and pipe support to lldb_private::MainLoopWindows. (PR #145621)
@@ -31,8 +31,11 @@ #include #include #include +#include #include +#include #include +#include ashgti wrote: Removed. https://github.com/llvm/llvm-project/pull/145621 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Adding file and pipe support to lldb_private::MainLoopWindows. (PR #145621)
@@ -31,20 +31,27 @@ class MainLoopWindows : public MainLoopBase { Status Run() override; + struct FdInfo { +FdInfo(intptr_t event, Callback callback) +: event(event), callback(callback) {} +virtual ~FdInfo() {} +virtual void WillPoll() {} +virtual void DidPoll() {} +virtual void Disarm() {} +intptr_t event; ashgti wrote: Changed to `IOObject::WaitableHandle`. https://github.com/llvm/llvm-project/pull/145621 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [compiler-rt] [lldb] [llvm] Reapply "[NFC][DebugInfo][DWARF] Create new low-level dwarf library (#… (#145959) (PR #146112)
https://github.com/dwblaikie approved this pull request. https://github.com/llvm/llvm-project/pull/146112 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Adding file and pipe support to lldb_private::MainLoopWindows. (PR #145621)
@@ -31,20 +31,27 @@ class MainLoopWindows : public MainLoopBase { Status Run() override; + struct FdInfo { +FdInfo(intptr_t event, Callback callback) +: event(event), callback(callback) {} +virtual ~FdInfo() {} +virtual void WillPoll() {} +virtual void DidPoll() {} +virtual void Disarm() {} +intptr_t event; +Callback callback; ashgti wrote: I reverted this so we have the previous `struct FdInfo` and made the event into its own `IOEvent` type instead. I also made this a class and used accessors instead of making ivars public. https://github.com/llvm/llvm-project/pull/145621 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [compiler-rt] [lldb] [llvm] Reapply "[NFC][DebugInfo][DWARF] Create new low-level dwarf library (#… (#145959) (PR #146112)
https://github.com/Sterling-Augustine closed https://github.com/llvm/llvm-project/pull/146112 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Fix evaluating expressions without JIT in an object context (PR #145599)
https://github.com/jimingham approved this pull request. This one is ready then. https://github.com/llvm/llvm-project/pull/145599 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb] Correctly restore the cursor column after resizing the statusline (PR #146132)
https://github.com/JDevlieghere created https://github.com/llvm/llvm-project/pull/146132 This PR ensures we correctly restore the cursor column after resizing the statusline. To ensure we have space for the statusline, we have to emit a newline to move up everything on screen. The newline causes the cursor to move to the start of the next line, which needs to be undone. Normally, we would use escape codes to save & restore the cursor position, but that doesn't work here, as the cursor position may have (purposely) changed. Instead, we move the cursor up one line using an escape code, but we weren't restoring the column. Interestingly, Editline was able to recover from this issue through the LineInfo struct which contains the buffer and the cursor location, which allows us to compute the column. This PR addresses the bug by having Editline "refresh" the cursor position. Fixes #134064 >From e601025c14fb609635dc6a9adea5b1ae8b8e4540 Mon Sep 17 00:00:00 2001 From: Jonas Devlieghere Date: Fri, 27 Jun 2025 11:08:08 -0700 Subject: [PATCH] [lldb] Correctly restore the cursor column after resizing the statusline This PR ensures we correctly restore the cursor column after resizing the statusline. To ensure we have space for the statusline, we have to emit a newline to move up everything on screen. The newline causes the cursor to move to the start of the next line, which needs to be undone. Normally, we would use escape codes to save & restore the cursor position, but that doesn't work here, as the cursor position may have (purposely) changed. Instead, we move the cursor up one line using an escape code, but we weren't restoring the column. Interestingly, Editline was able to recover from this issue through the LineInfo struct which contains the buffer and the cursor location, which allows us to compute the column. This PR addresses the bug by having Editline "refresh" the cursor position. Fixes #134064 --- lldb/include/lldb/Core/Debugger.h| 2 ++ lldb/include/lldb/Core/IOHandler.h | 4 lldb/include/lldb/Host/Editline.h| 2 ++ lldb/source/Core/Debugger.cpp| 7 +++ lldb/source/Core/IOHandler.cpp | 7 +++ lldb/source/Core/Statusline.cpp | 19 +++ lldb/source/Host/common/Editline.cpp | 7 +++ 7 files changed, 40 insertions(+), 8 deletions(-) diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h index 2087ef2a11562..504f936fe317a 100644 --- a/lldb/include/lldb/Core/Debugger.h +++ b/lldb/include/lldb/Core/Debugger.h @@ -227,6 +227,8 @@ class Debugger : public std::enable_shared_from_this, const char *GetIOHandlerHelpPrologue(); + void RefreshIOHandler(); + void ClearIOHandlers(); bool EnableLog(llvm::StringRef channel, diff --git a/lldb/include/lldb/Core/IOHandler.h b/lldb/include/lldb/Core/IOHandler.h index 2fb3d7a7c9cc3..2672bbe5da2b3 100644 --- a/lldb/include/lldb/Core/IOHandler.h +++ b/lldb/include/lldb/Core/IOHandler.h @@ -90,6 +90,8 @@ class IOHandler { virtual void TerminalSizeChanged() {} + virtual void Refresh() {} + virtual const char *GetPrompt() { // Prompt support isn't mandatory return nullptr; @@ -404,6 +406,8 @@ class IOHandlerEditline : public IOHandler { void PrintAsync(const char *s, size_t len, bool is_stdout) override; + void Refresh() override; + private: #if LLDB_ENABLE_LIBEDIT bool IsInputCompleteCallback(Editline *editline, StringList &lines); diff --git a/lldb/include/lldb/Host/Editline.h b/lldb/include/lldb/Host/Editline.h index c202a76758e13..947ad3bfe5ec6 100644 --- a/lldb/include/lldb/Host/Editline.h +++ b/lldb/include/lldb/Host/Editline.h @@ -267,6 +267,8 @@ class Editline { size_t GetTerminalHeight() { return m_terminal_height; } + void Refresh(); + private: /// Sets the lowest line number for multi-line editing sessions. A value of /// zero suppresses line number printing in the prompt. diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 445baf1f63785..ed674ee1275c7 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -1445,6 +1445,13 @@ bool Debugger::PopIOHandler(const IOHandlerSP &pop_reader_sp) { return true; } +void Debugger::RefreshIOHandler() { + std::lock_guard guard(m_io_handler_stack.GetMutex()); + IOHandlerSP reader_sp(m_io_handler_stack.Top()); + if (reader_sp) +reader_sp->Refresh(); +} + StreamUP Debugger::GetAsyncOutputStream() { return std::make_unique(*this, StreamAsynchronousIO::STDOUT); diff --git a/lldb/source/Core/IOHandler.cpp b/lldb/source/Core/IOHandler.cpp index 8aac507eaa0c2..f65a1113f3592 100644 --- a/lldb/source/Core/IOHandler.cpp +++ b/lldb/source/Core/IOHandler.cpp @@ -663,3 +663,10 @@ void IOHandlerEditline::PrintAsync(const char *s, size_t len, bool is_stdout) { #endif } } + +void IOHandlerEditline::Refresh() { +#if LLDB_ENABLE_LIBEDIT + if
[Lldb-commits] [lldb] [lldb] Correctly restore the cursor column after resizing the statusline (PR #146132)
llvmbot wrote: @llvm/pr-subscribers-lldb Author: Jonas Devlieghere (JDevlieghere) Changes This PR ensures we correctly restore the cursor column after resizing the statusline. To ensure we have space for the statusline, we have to emit a newline to move up everything on screen. The newline causes the cursor to move to the start of the next line, which needs to be undone. Normally, we would use escape codes to save & restore the cursor position, but that doesn't work here, as the cursor position may have (purposely) changed. Instead, we move the cursor up one line using an escape code, but we weren't restoring the column. Interestingly, Editline was able to recover from this issue through the LineInfo struct which contains the buffer and the cursor location, which allows us to compute the column. This PR addresses the bug by having Editline "refresh" the cursor position. Fixes #134064 --- Full diff: https://github.com/llvm/llvm-project/pull/146132.diff 7 Files Affected: - (modified) lldb/include/lldb/Core/Debugger.h (+2) - (modified) lldb/include/lldb/Core/IOHandler.h (+4) - (modified) lldb/include/lldb/Host/Editline.h (+2) - (modified) lldb/source/Core/Debugger.cpp (+7) - (modified) lldb/source/Core/IOHandler.cpp (+7) - (modified) lldb/source/Core/Statusline.cpp (+11-8) - (modified) lldb/source/Host/common/Editline.cpp (+7) ``diff diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h index 2087ef2a11562..504f936fe317a 100644 --- a/lldb/include/lldb/Core/Debugger.h +++ b/lldb/include/lldb/Core/Debugger.h @@ -227,6 +227,8 @@ class Debugger : public std::enable_shared_from_this, const char *GetIOHandlerHelpPrologue(); + void RefreshIOHandler(); + void ClearIOHandlers(); bool EnableLog(llvm::StringRef channel, diff --git a/lldb/include/lldb/Core/IOHandler.h b/lldb/include/lldb/Core/IOHandler.h index 2fb3d7a7c9cc3..2672bbe5da2b3 100644 --- a/lldb/include/lldb/Core/IOHandler.h +++ b/lldb/include/lldb/Core/IOHandler.h @@ -90,6 +90,8 @@ class IOHandler { virtual void TerminalSizeChanged() {} + virtual void Refresh() {} + virtual const char *GetPrompt() { // Prompt support isn't mandatory return nullptr; @@ -404,6 +406,8 @@ class IOHandlerEditline : public IOHandler { void PrintAsync(const char *s, size_t len, bool is_stdout) override; + void Refresh() override; + private: #if LLDB_ENABLE_LIBEDIT bool IsInputCompleteCallback(Editline *editline, StringList &lines); diff --git a/lldb/include/lldb/Host/Editline.h b/lldb/include/lldb/Host/Editline.h index c202a76758e13..947ad3bfe5ec6 100644 --- a/lldb/include/lldb/Host/Editline.h +++ b/lldb/include/lldb/Host/Editline.h @@ -267,6 +267,8 @@ class Editline { size_t GetTerminalHeight() { return m_terminal_height; } + void Refresh(); + private: /// Sets the lowest line number for multi-line editing sessions. A value of /// zero suppresses line number printing in the prompt. diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 445baf1f63785..ed674ee1275c7 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -1445,6 +1445,13 @@ bool Debugger::PopIOHandler(const IOHandlerSP &pop_reader_sp) { return true; } +void Debugger::RefreshIOHandler() { + std::lock_guard guard(m_io_handler_stack.GetMutex()); + IOHandlerSP reader_sp(m_io_handler_stack.Top()); + if (reader_sp) +reader_sp->Refresh(); +} + StreamUP Debugger::GetAsyncOutputStream() { return std::make_unique(*this, StreamAsynchronousIO::STDOUT); diff --git a/lldb/source/Core/IOHandler.cpp b/lldb/source/Core/IOHandler.cpp index 8aac507eaa0c2..f65a1113f3592 100644 --- a/lldb/source/Core/IOHandler.cpp +++ b/lldb/source/Core/IOHandler.cpp @@ -663,3 +663,10 @@ void IOHandlerEditline::PrintAsync(const char *s, size_t len, bool is_stdout) { #endif } } + +void IOHandlerEditline::Refresh() { +#if LLDB_ENABLE_LIBEDIT + if (m_editline_up) +m_editline_up->Refresh(); +#endif +} diff --git a/lldb/source/Core/Statusline.cpp b/lldb/source/Core/Statusline.cpp index 8a8640805cac0..8ec57c9fa5bac 100644 --- a/lldb/source/Core/Statusline.cpp +++ b/lldb/source/Core/Statusline.cpp @@ -103,20 +103,23 @@ void Statusline::UpdateScrollWindow(ScrollWindowMode mode) { (mode == DisableStatusline) ? m_terminal_height : m_terminal_height - 1; LockedStreamFile locked_stream = stream_sp->Lock(); + + if (mode == EnableStatusline) { +// Move everything on the screen up. +locked_stream << '\n'; +locked_stream.Printf(ANSI_UP_ROWS, 1); + } + locked_stream << ANSI_SAVE_CURSOR; locked_stream.Printf(ANSI_SET_SCROLL_ROWS, scroll_height); locked_stream << ANSI_RESTORE_CURSOR; - switch (mode) { - case EnableStatusline: -// Move everything on the screen up. -locked_stream.Printf(ANSI_UP_ROWS, 1); -locked_stream << '\n'; -break; - case DisableStatu
[Lldb-commits] [lldb] [lldb] Correctly restore the cursor column after resizing the statusline (PR #145823)
JDevlieghere wrote: Alternative approach: https://github.com/llvm/llvm-project/pull/146132 https://github.com/llvm/llvm-project/pull/145823 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb][Mach-O] Allow "process metadata" LC_NOTE to supply registers (PR #144627)
@@ -5857,6 +5838,50 @@ bool ObjectFileMachO::GetCorefileThreadExtraInfos( return false; } +StructuredData::ObjectSP ObjectFileMachO::GetCorefileProcessMetadata() { + ModuleSP module_sp(GetModule()); + if (!module_sp) +return {}; + + Log *log(GetLog(LLDBLog::Object | LLDBLog::Process | LLDBLog::Thread)); + std::lock_guard guard(module_sp->GetMutex()); + auto lc_notes = FindLC_NOTEByName("process metadata"); + if (lc_notes.size() == 0) +return {}; + + if (lc_notes.size() > 1) +LLDB_LOGF( +log, +"Multiple 'process metadata' LC_NOTEs found, only using the first."); + + offset_t payload_offset = std::get<0>(lc_notes[0]); + offset_t strsize = std::get<1>(lc_notes[0]); JDevlieghere wrote: FWIW, with structured bindings in C++17 you can now write this like: ```suggestion auto [payload_offset, strsize] = lc_notes[0]; ``` https://github.com/llvm/llvm-project/pull/144627 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb][Mach-O] Allow "process metadata" LC_NOTE to supply registers (PR #144627)
@@ -0,0 +1,300 @@ +//===-- RegisterContextUnifiedCore.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 "RegisterContextUnifiedCore.h" +#include "lldb/Target/DynamicRegisterInfo.h" +#include "lldb/Target/Process.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/StructuredData.h" + +using namespace lldb; +using namespace lldb_private; + +RegisterContextUnifiedCore::RegisterContextUnifiedCore( +Thread &thread, uint32_t concrete_frame_idx, +RegisterContextSP core_thread_regctx_sp, +StructuredData::ObjectSP metadata_thread_registers) +: RegisterContext(thread, concrete_frame_idx) { + + ProcessSP process_sp(thread.GetProcess()); + Target &target = process_sp->GetTarget(); + StructuredData::Dictionary *metadata_registers_dict = nullptr; + + // If we have thread metadata, check if the keys for register + // definitions are present; if not, clear the ObjectSP. + if (metadata_thread_registers && + metadata_thread_registers->GetAsDictionary() && + metadata_thread_registers->GetAsDictionary()->HasKey("register_info")) { +metadata_registers_dict = metadata_thread_registers->GetAsDictionary() + ->GetValueForKey("register_info") + ->GetAsDictionary(); +if (metadata_registers_dict) + if (!metadata_registers_dict->HasKey("sets") || + !metadata_registers_dict->HasKey("registers")) +metadata_registers_dict = nullptr; + } + + // When creating a register set list from the two sources, + // the LC_THREAD aka core_thread_regctx_sp register sets + // will be used at the same indexes. + // Any additional sets named by the thread metadata registers + // will be added after them. If the thread metadata + // specify a set with the same name as LC_THREAD, the already-used + // index from the core register context will be used in + // the RegisterInfo. + std::map metadata_regset_to_combined_regset; + + // Calculate the total size of the register store buffer we need + // for all registers. The corefile register definitions may include + // RegisterInfo descriptions of registers that aren't actually + // available. For simplicity, calculate the size of all registers + // as if they are available, so we can maintain the same offsets into + // the buffer. + uint32_t core_buffer_end = 0; + for (size_t idx = 0; idx < core_thread_regctx_sp->GetRegisterCount(); idx++) { +const RegisterInfo *reginfo = +core_thread_regctx_sp->GetRegisterInfoAtIndex(idx); +core_buffer_end = +std::max(reginfo->byte_offset + reginfo->byte_size, core_buffer_end); + } + + // Add metadata register sizes to the total buffer size. + uint32_t combined_buffer_end = core_buffer_end; + if (metadata_registers_dict) { +StructuredData::Array *registers = nullptr; +if (metadata_registers_dict->GetValueForKeyAsArray("registers", registers)) + registers->ForEach( + [&combined_buffer_end](StructuredData::Object *ent) -> bool { +uint32_t bitsize; +if (!ent->GetAsDictionary()->GetValueForKeyAsInteger("bitsize", + bitsize)) + return false; +combined_buffer_end += (bitsize / 8); +return true; + }); + } + m_register_data.resize(combined_buffer_end, 0); + + // Copy the core register values into our combined data buffer, + // skip registers that are contained within another (e.g. w0 vs. x0) + // and registers that return as "unavailable". + for (size_t idx = 0; idx < core_thread_regctx_sp->GetRegisterCount(); idx++) { +const RegisterInfo *reginfo = +core_thread_regctx_sp->GetRegisterInfoAtIndex(idx); +RegisterValue val; +if (!reginfo->value_regs && +core_thread_regctx_sp->ReadRegister(reginfo, val)) + memcpy(m_register_data.data() + reginfo->byte_offset, val.GetBytes(), + val.GetByteSize()); + } + + // Set 'offset' fields for each register definition into our combined + // register data buffer. DynamicRegisterInfo needs + // this field set to parse the JSON. + // Also copy the values of the registers into our register data buffer. + if (metadata_registers_dict) { +size_t offset = core_buffer_end; +ByteOrder byte_order = core_thread_regctx_sp->GetByteOrder(); +StructuredData::Array *registers; +if (metadata_registers_dict->GetValueForKeyAsArray("registers", registers)) + registers->ForEach([this, &offset, + byte_order](StructuredData::Object *ent) -> bool { +uint64_t bitsize;
[Lldb-commits] [lldb] [lldb][Mach-O] Allow "process metadata" LC_NOTE to supply registers (PR #144627)
@@ -5857,6 +5838,50 @@ bool ObjectFileMachO::GetCorefileThreadExtraInfos( return false; } +StructuredData::ObjectSP ObjectFileMachO::GetCorefileProcessMetadata() { + ModuleSP module_sp(GetModule()); + if (!module_sp) +return {}; + + Log *log(GetLog(LLDBLog::Object | LLDBLog::Process | LLDBLog::Thread)); + std::lock_guard guard(module_sp->GetMutex()); + auto lc_notes = FindLC_NOTEByName("process metadata"); + if (lc_notes.size() == 0) +return {}; + + if (lc_notes.size() > 1) +LLDB_LOGF( +log, +"Multiple 'process metadata' LC_NOTEs found, only using the first."); + + offset_t payload_offset = std::get<0>(lc_notes[0]); + offset_t strsize = std::get<1>(lc_notes[0]); + std::string buf(strsize, '\0'); + if (m_data.CopyData(payload_offset, strsize, buf.data()) != strsize) { +LLDB_LOGF(log, + "Unable to read %" PRIu64 + " bytes of 'process metadata' LC_NOTE JSON contents", + strsize); +return {}; + } + while (buf.back() == '\0') +buf.resize(buf.size() - 1); + StructuredData::ObjectSP object_sp = StructuredData::ParseJSON(buf); + if (!object_sp) { +LLDB_LOGF(log, "Unable to read 'process metadata' LC_NOTE, did not " + "parse as valid JSON."); JDevlieghere wrote: No need to change anything, but another way to handle this is to make this function return an `Expected` and do the logging on the caller side. The advantage of that is that if you can do better than logging, it's easy to percolate the error up, while now it never leaves the function. https://github.com/llvm/llvm-project/pull/144627 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb][Mach-O] Allow "process metadata" LC_NOTE to supply registers (PR #144627)
@@ -0,0 +1,300 @@ +//===-- RegisterContextUnifiedCore.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 "RegisterContextUnifiedCore.h" +#include "lldb/Target/DynamicRegisterInfo.h" +#include "lldb/Target/Process.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/StructuredData.h" + +using namespace lldb; +using namespace lldb_private; + +RegisterContextUnifiedCore::RegisterContextUnifiedCore( +Thread &thread, uint32_t concrete_frame_idx, +RegisterContextSP core_thread_regctx_sp, +StructuredData::ObjectSP metadata_thread_registers) +: RegisterContext(thread, concrete_frame_idx) { + + ProcessSP process_sp(thread.GetProcess()); + Target &target = process_sp->GetTarget(); + StructuredData::Dictionary *metadata_registers_dict = nullptr; + + // If we have thread metadata, check if the keys for register + // definitions are present; if not, clear the ObjectSP. + if (metadata_thread_registers && + metadata_thread_registers->GetAsDictionary() && + metadata_thread_registers->GetAsDictionary()->HasKey("register_info")) { +metadata_registers_dict = metadata_thread_registers->GetAsDictionary() + ->GetValueForKey("register_info") + ->GetAsDictionary(); +if (metadata_registers_dict) + if (!metadata_registers_dict->HasKey("sets") || + !metadata_registers_dict->HasKey("registers")) +metadata_registers_dict = nullptr; + } + + // When creating a register set list from the two sources, + // the LC_THREAD aka core_thread_regctx_sp register sets + // will be used at the same indexes. + // Any additional sets named by the thread metadata registers + // will be added after them. If the thread metadata + // specify a set with the same name as LC_THREAD, the already-used + // index from the core register context will be used in + // the RegisterInfo. + std::map metadata_regset_to_combined_regset; + + // Calculate the total size of the register store buffer we need + // for all registers. The corefile register definitions may include + // RegisterInfo descriptions of registers that aren't actually + // available. For simplicity, calculate the size of all registers + // as if they are available, so we can maintain the same offsets into + // the buffer. + uint32_t core_buffer_end = 0; + for (size_t idx = 0; idx < core_thread_regctx_sp->GetRegisterCount(); idx++) { +const RegisterInfo *reginfo = +core_thread_regctx_sp->GetRegisterInfoAtIndex(idx); +core_buffer_end = +std::max(reginfo->byte_offset + reginfo->byte_size, core_buffer_end); + } + + // Add metadata register sizes to the total buffer size. + uint32_t combined_buffer_end = core_buffer_end; + if (metadata_registers_dict) { +StructuredData::Array *registers = nullptr; +if (metadata_registers_dict->GetValueForKeyAsArray("registers", registers)) + registers->ForEach( + [&combined_buffer_end](StructuredData::Object *ent) -> bool { +uint32_t bitsize; +if (!ent->GetAsDictionary()->GetValueForKeyAsInteger("bitsize", + bitsize)) + return false; +combined_buffer_end += (bitsize / 8); +return true; + }); + } + m_register_data.resize(combined_buffer_end, 0); + + // Copy the core register values into our combined data buffer, + // skip registers that are contained within another (e.g. w0 vs. x0) + // and registers that return as "unavailable". + for (size_t idx = 0; idx < core_thread_regctx_sp->GetRegisterCount(); idx++) { +const RegisterInfo *reginfo = +core_thread_regctx_sp->GetRegisterInfoAtIndex(idx); +RegisterValue val; +if (!reginfo->value_regs && +core_thread_regctx_sp->ReadRegister(reginfo, val)) + memcpy(m_register_data.data() + reginfo->byte_offset, val.GetBytes(), + val.GetByteSize()); + } + + // Set 'offset' fields for each register definition into our combined + // register data buffer. DynamicRegisterInfo needs + // this field set to parse the JSON. + // Also copy the values of the registers into our register data buffer. + if (metadata_registers_dict) { +size_t offset = core_buffer_end; +ByteOrder byte_order = core_thread_regctx_sp->GetByteOrder(); +StructuredData::Array *registers; +if (metadata_registers_dict->GetValueForKeyAsArray("registers", registers)) + registers->ForEach([this, &offset, + byte_order](StructuredData::Object *ent) -> bool { +uint64_t bitsize;
[Lldb-commits] [lldb] [lldb][Mach-O] Allow "process metadata" LC_NOTE to supply registers (PR #144627)
@@ -0,0 +1,300 @@ +//===-- RegisterContextUnifiedCore.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 "RegisterContextUnifiedCore.h" +#include "lldb/Target/DynamicRegisterInfo.h" +#include "lldb/Target/Process.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/StructuredData.h" + +using namespace lldb; +using namespace lldb_private; + +RegisterContextUnifiedCore::RegisterContextUnifiedCore( +Thread &thread, uint32_t concrete_frame_idx, +RegisterContextSP core_thread_regctx_sp, +StructuredData::ObjectSP metadata_thread_registers) +: RegisterContext(thread, concrete_frame_idx) { + + ProcessSP process_sp(thread.GetProcess()); + Target &target = process_sp->GetTarget(); + StructuredData::Dictionary *metadata_registers_dict = nullptr; + + // If we have thread metadata, check if the keys for register + // definitions are present; if not, clear the ObjectSP. + if (metadata_thread_registers && + metadata_thread_registers->GetAsDictionary() && + metadata_thread_registers->GetAsDictionary()->HasKey("register_info")) { +metadata_registers_dict = metadata_thread_registers->GetAsDictionary() + ->GetValueForKey("register_info") + ->GetAsDictionary(); +if (metadata_registers_dict) + if (!metadata_registers_dict->HasKey("sets") || + !metadata_registers_dict->HasKey("registers")) +metadata_registers_dict = nullptr; + } + + // When creating a register set list from the two sources, + // the LC_THREAD aka core_thread_regctx_sp register sets + // will be used at the same indexes. + // Any additional sets named by the thread metadata registers + // will be added after them. If the thread metadata + // specify a set with the same name as LC_THREAD, the already-used + // index from the core register context will be used in + // the RegisterInfo. + std::map metadata_regset_to_combined_regset; + + // Calculate the total size of the register store buffer we need + // for all registers. The corefile register definitions may include + // RegisterInfo descriptions of registers that aren't actually + // available. For simplicity, calculate the size of all registers + // as if they are available, so we can maintain the same offsets into + // the buffer. + uint32_t core_buffer_end = 0; + for (size_t idx = 0; idx < core_thread_regctx_sp->GetRegisterCount(); idx++) { +const RegisterInfo *reginfo = +core_thread_regctx_sp->GetRegisterInfoAtIndex(idx); +core_buffer_end = +std::max(reginfo->byte_offset + reginfo->byte_size, core_buffer_end); + } + + // Add metadata register sizes to the total buffer size. + uint32_t combined_buffer_end = core_buffer_end; + if (metadata_registers_dict) { +StructuredData::Array *registers = nullptr; +if (metadata_registers_dict->GetValueForKeyAsArray("registers", registers)) + registers->ForEach( + [&combined_buffer_end](StructuredData::Object *ent) -> bool { +uint32_t bitsize; +if (!ent->GetAsDictionary()->GetValueForKeyAsInteger("bitsize", + bitsize)) + return false; +combined_buffer_end += (bitsize / 8); +return true; + }); + } + m_register_data.resize(combined_buffer_end, 0); + + // Copy the core register values into our combined data buffer, + // skip registers that are contained within another (e.g. w0 vs. x0) + // and registers that return as "unavailable". + for (size_t idx = 0; idx < core_thread_regctx_sp->GetRegisterCount(); idx++) { +const RegisterInfo *reginfo = +core_thread_regctx_sp->GetRegisterInfoAtIndex(idx); +RegisterValue val; +if (!reginfo->value_regs && +core_thread_regctx_sp->ReadRegister(reginfo, val)) + memcpy(m_register_data.data() + reginfo->byte_offset, val.GetBytes(), + val.GetByteSize()); + } + + // Set 'offset' fields for each register definition into our combined + // register data buffer. DynamicRegisterInfo needs + // this field set to parse the JSON. JDevlieghere wrote: Nit: looks like this needs to be reflowed. https://github.com/llvm/llvm-project/pull/144627 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb][Mach-O] Allow "process metadata" LC_NOTE to supply registers (PR #144627)
https://github.com/JDevlieghere edited https://github.com/llvm/llvm-project/pull/144627 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb][Mach-O] Allow "process metadata" LC_NOTE to supply registers (PR #144627)
@@ -0,0 +1,300 @@ +//===-- RegisterContextUnifiedCore.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 "RegisterContextUnifiedCore.h" +#include "lldb/Target/DynamicRegisterInfo.h" +#include "lldb/Target/Process.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/StructuredData.h" + +using namespace lldb; +using namespace lldb_private; + +RegisterContextUnifiedCore::RegisterContextUnifiedCore( +Thread &thread, uint32_t concrete_frame_idx, +RegisterContextSP core_thread_regctx_sp, +StructuredData::ObjectSP metadata_thread_registers) +: RegisterContext(thread, concrete_frame_idx) { + + ProcessSP process_sp(thread.GetProcess()); + Target &target = process_sp->GetTarget(); + StructuredData::Dictionary *metadata_registers_dict = nullptr; + + // If we have thread metadata, check if the keys for register + // definitions are present; if not, clear the ObjectSP. + if (metadata_thread_registers && + metadata_thread_registers->GetAsDictionary() && + metadata_thread_registers->GetAsDictionary()->HasKey("register_info")) { +metadata_registers_dict = metadata_thread_registers->GetAsDictionary() + ->GetValueForKey("register_info") + ->GetAsDictionary(); +if (metadata_registers_dict) + if (!metadata_registers_dict->HasKey("sets") || + !metadata_registers_dict->HasKey("registers")) +metadata_registers_dict = nullptr; + } + + // When creating a register set list from the two sources, + // the LC_THREAD aka core_thread_regctx_sp register sets + // will be used at the same indexes. + // Any additional sets named by the thread metadata registers + // will be added after them. If the thread metadata + // specify a set with the same name as LC_THREAD, the already-used + // index from the core register context will be used in + // the RegisterInfo. + std::map metadata_regset_to_combined_regset; + + // Calculate the total size of the register store buffer we need + // for all registers. The corefile register definitions may include + // RegisterInfo descriptions of registers that aren't actually + // available. For simplicity, calculate the size of all registers + // as if they are available, so we can maintain the same offsets into + // the buffer. + uint32_t core_buffer_end = 0; + for (size_t idx = 0; idx < core_thread_regctx_sp->GetRegisterCount(); idx++) { +const RegisterInfo *reginfo = +core_thread_regctx_sp->GetRegisterInfoAtIndex(idx); +core_buffer_end = +std::max(reginfo->byte_offset + reginfo->byte_size, core_buffer_end); + } + + // Add metadata register sizes to the total buffer size. + uint32_t combined_buffer_end = core_buffer_end; + if (metadata_registers_dict) { +StructuredData::Array *registers = nullptr; +if (metadata_registers_dict->GetValueForKeyAsArray("registers", registers)) + registers->ForEach( + [&combined_buffer_end](StructuredData::Object *ent) -> bool { +uint32_t bitsize; +if (!ent->GetAsDictionary()->GetValueForKeyAsInteger("bitsize", + bitsize)) + return false; +combined_buffer_end += (bitsize / 8); +return true; + }); + } + m_register_data.resize(combined_buffer_end, 0); + + // Copy the core register values into our combined data buffer, + // skip registers that are contained within another (e.g. w0 vs. x0) + // and registers that return as "unavailable". + for (size_t idx = 0; idx < core_thread_regctx_sp->GetRegisterCount(); idx++) { +const RegisterInfo *reginfo = +core_thread_regctx_sp->GetRegisterInfoAtIndex(idx); +RegisterValue val; +if (!reginfo->value_regs && +core_thread_regctx_sp->ReadRegister(reginfo, val)) + memcpy(m_register_data.data() + reginfo->byte_offset, val.GetBytes(), + val.GetByteSize()); + } + + // Set 'offset' fields for each register definition into our combined + // register data buffer. DynamicRegisterInfo needs + // this field set to parse the JSON. + // Also copy the values of the registers into our register data buffer. + if (metadata_registers_dict) { +size_t offset = core_buffer_end; +ByteOrder byte_order = core_thread_regctx_sp->GetByteOrder(); +StructuredData::Array *registers; +if (metadata_registers_dict->GetValueForKeyAsArray("registers", registers)) + registers->ForEach([this, &offset, + byte_order](StructuredData::Object *ent) -> bool { +uint64_t bitsize;
[Lldb-commits] [lldb] [lldb][Mach-O] Allow "process metadata" LC_NOTE to supply registers (PR #144627)
@@ -133,6 +133,8 @@ class ObjectFileMachO : public lldb_private::ObjectFile { bool GetCorefileThreadExtraInfos(std::vector &tids) override; + lldb_private::StructuredData::ObjectSP GetCorefileProcessMetadata() override; JDevlieghere wrote: ```suggestion StructuredData::ObjectSP GetCorefileProcessMetadata() override; ``` https://github.com/llvm/llvm-project/pull/144627 ___ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
[Lldb-commits] [lldb] [lldb][Mach-O] Allow "process metadata" LC_NOTE to supply registers (PR #144627)
@@ -0,0 +1,300 @@ +//===-- RegisterContextUnifiedCore.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 "RegisterContextUnifiedCore.h" +#include "lldb/Target/DynamicRegisterInfo.h" +#include "lldb/Target/Process.h" +#include "lldb/Utility/DataExtractor.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/StructuredData.h" + +using namespace lldb; +using namespace lldb_private; + +RegisterContextUnifiedCore::RegisterContextUnifiedCore( +Thread &thread, uint32_t concrete_frame_idx, +RegisterContextSP core_thread_regctx_sp, +StructuredData::ObjectSP metadata_thread_registers) +: RegisterContext(thread, concrete_frame_idx) { + + ProcessSP process_sp(thread.GetProcess()); + Target &target = process_sp->GetTarget(); + StructuredData::Dictionary *metadata_registers_dict = nullptr; + + // If we have thread metadata, check if the keys for register + // definitions are present; if not, clear the ObjectSP. + if (metadata_thread_registers && + metadata_thread_registers->GetAsDictionary() && + metadata_thread_registers->GetAsDictionary()->HasKey("register_info")) { +metadata_registers_dict = metadata_thread_registers->GetAsDictionary() + ->GetValueForKey("register_info") + ->GetAsDictionary(); +if (metadata_registers_dict) + if (!metadata_registers_dict->HasKey("sets") || + !metadata_registers_dict->HasKey("registers")) +metadata_registers_dict = nullptr; + } + + // When creating a register set list from the two sources, + // the LC_THREAD aka core_thread_regctx_sp register sets + // will be used at the same indexes. + // Any additional sets named by the thread metadata registers + // will be added after them. If the thread metadata + // specify a set with the same name as LC_THREAD, the already-used + // index from the core register context will be used in + // the RegisterInfo. + std::map metadata_regset_to_combined_regset; + + // Calculate the total size of the register store buffer we need + // for all registers. The corefile register definitions may include + // RegisterInfo descriptions of registers that aren't actually + // available. For simplicity, calculate the size of all registers + // as if they are available, so we can maintain the same offsets into + // the buffer. + uint32_t core_buffer_end = 0; + for (size_t idx = 0; idx < core_thread_regctx_sp->GetRegisterCount(); idx++) { +const RegisterInfo *reginfo = +core_thread_regctx_sp->GetRegisterInfoAtIndex(idx); +core_buffer_end = +std::max(reginfo->byte_offset + reginfo->byte_size, core_buffer_end); + } + + // Add metadata register sizes to the total buffer size. + uint32_t combined_buffer_end = core_buffer_end; + if (metadata_registers_dict) { +StructuredData::Array *registers = nullptr; +if (metadata_registers_dict->GetValueForKeyAsArray("registers", registers)) + registers->ForEach( + [&combined_buffer_end](StructuredData::Object *ent) -> bool { +uint32_t bitsize; +if (!ent->GetAsDictionary()->GetValueForKeyAsInteger("bitsize", + bitsize)) + return false; +combined_buffer_end += (bitsize / 8); +return true; + }); + } + m_register_data.resize(combined_buffer_end, 0); + + // Copy the core register values into our combined data buffer, + // skip registers that are contained within another (e.g. w0 vs. x0) + // and registers that return as "unavailable". + for (size_t idx = 0; idx < core_thread_regctx_sp->GetRegisterCount(); idx++) { +const RegisterInfo *reginfo = +core_thread_regctx_sp->GetRegisterInfoAtIndex(idx); +RegisterValue val; +if (!reginfo->value_regs && +core_thread_regctx_sp->ReadRegister(reginfo, val)) + memcpy(m_register_data.data() + reginfo->byte_offset, val.GetBytes(), + val.GetByteSize()); + } + + // Set 'offset' fields for each register definition into our combined + // register data buffer. DynamicRegisterInfo needs + // this field set to parse the JSON. + // Also copy the values of the registers into our register data buffer. + if (metadata_registers_dict) { +size_t offset = core_buffer_end; +ByteOrder byte_order = core_thread_regctx_sp->GetByteOrder(); +StructuredData::Array *registers; +if (metadata_registers_dict->GetValueForKeyAsArray("registers", registers)) + registers->ForEach([this, &offset, + byte_order](StructuredData::Object *ent) -> bool { +uint64_t bitsize;