https://github.com/n2h9 updated https://github.com/llvm/llvm-project/pull/174847
>From ee97426b0e0e509be8315e38fe48d752f9db0cb4 Mon Sep 17 00:00:00 2001 From: Nikita B <[email protected]> Date: Thu, 18 Dec 2025 20:51:43 +0100 Subject: [PATCH 01/29] [lldb] [disassembler] chore: add variable annotator to scripting api: add VariableAnnotator to lldb-forward header Signed-off-by: Nikita B <[email protected]> --- lldb/include/lldb/lldb-forward.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h index ccfe5efa19e1d..34f756e7bfd48 100644 --- a/lldb/include/lldb/lldb-forward.h +++ b/lldb/include/lldb/lldb-forward.h @@ -300,6 +300,7 @@ class ValueObjectConstResultImpl; class ValueObjectList; class ValueObjectPrinter; class Variable; +class VariableAnnotator; class VariableList; class Watchpoint; class WatchpointList; @@ -502,6 +503,7 @@ typedef std::shared_ptr<lldb_private::UnwindPlan> UnwindPlanSP; typedef std::shared_ptr<lldb_private::ValueObject> ValueObjectSP; typedef std::shared_ptr<lldb_private::Value> ValueSP; typedef std::shared_ptr<lldb_private::Variable> VariableSP; +typedef std::shared_ptr<lldb_private::VariableAnnotator> VariableAnnotatorSP; typedef std::shared_ptr<lldb_private::VariableList> VariableListSP; typedef std::shared_ptr<lldb_private::ValueObjectList> ValueObjectListSP; typedef std::shared_ptr<lldb_private::Watchpoint> WatchpointSP; >From 8f617d4151014166e9f93b1f90bee3ead722768e Mon Sep 17 00:00:00 2001 From: Nikita B <[email protected]> Date: Thu, 18 Dec 2025 23:57:54 +0100 Subject: [PATCH 02/29] [lldb] [disassembler] chore: add variable annotator to scripting api: SBVariableAnnotator init Signed-off-by: Nikita B <[email protected]> --- lldb/include/lldb/API/SBVariableAnnotator.h | 32 +++++++++++++++++ lldb/source/API/SBVariableAnnotator.cpp | 39 +++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 lldb/include/lldb/API/SBVariableAnnotator.h create mode 100644 lldb/source/API/SBVariableAnnotator.cpp diff --git a/lldb/include/lldb/API/SBVariableAnnotator.h b/lldb/include/lldb/API/SBVariableAnnotator.h new file mode 100644 index 0000000000000..0481d47d4b0c1 --- /dev/null +++ b/lldb/include/lldb/API/SBVariableAnnotator.h @@ -0,0 +1,32 @@ +//===-- SBVariableAnnotator.h -----------------------------------------*- C++ +//-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_API_SBVARIABLEANNOTATOR_H +#define LLDB_API_SBVARIABLEANNOTATOR_H + +#include "lldb/API/SBDefines.h" + +namespace lldb { + +class LLDB_API SBVariableAnnotator { +public: + SBVariableAnnotator(); + + SBVariableAnnotator(const SBVariableAnnotator &rhs); + + const SBVariableAnnotator &operator=(const SBVariableAnnotator &rhs); + + ~SBVariableAnnotator(); + + explicit operator bool() const; + + bool IsValid() const; +}; +} // namespace lldb +#endif // LLDB_API_SBVARIABLEANNOTATOR_H \ No newline at end of file diff --git a/lldb/source/API/SBVariableAnnotator.cpp b/lldb/source/API/SBVariableAnnotator.cpp new file mode 100644 index 0000000000000..4d825afa8c84e --- /dev/null +++ b/lldb/source/API/SBVariableAnnotator.cpp @@ -0,0 +1,39 @@ +//===-- SBVariableAnnotator.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 "lldb/API/SBVariableAnnotator.h" +#include "lldb/Utility/Instrumentation.h" + +using namespace lldb; +using namespace lldb_private; + +SBVariableAnnotator::SBVariableAnnotator() { LLDB_INSTRUMENT_VA(this); } + +SBVariableAnnotator::SBVariableAnnotator(const SBVariableAnnotator &rhs) { + LLDB_INSTRUMENT_VA(this); +} + +const SBVariableAnnotator & +SBVariableAnnotator::operator=(const SBVariableAnnotator &rhs) { + LLDB_INSTRUMENT_VA(this); + + // if (this != &rhs) + // // TODO + return *this; +} + +SBVariableAnnotator::~SBVariableAnnotator() = default; + +SBVariableAnnotator::operator bool() const { + LLDB_INSTRUMENT_VA(this); + + return IsValid(); +} + +bool lldb::SBVariableAnnotator::IsValid() const { return false; } >From 1797af934544fc257b8fcd77a338b7df5cfbf6f1 Mon Sep 17 00:00:00 2001 From: Nikita B <[email protected]> Date: Fri, 19 Dec 2025 21:16:58 +0100 Subject: [PATCH 03/29] [lldb] [disassembler] chore: add variable annotator to scripting api: SBVariableAnnotator: add constructor, getter and setter for pointer Signed-off-by: Nikita B <[email protected]> --- lldb/include/lldb/API/SBVariableAnnotator.h | 10 ++++++++++ lldb/source/API/SBVariableAnnotator.cpp | 18 ++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/lldb/include/lldb/API/SBVariableAnnotator.h b/lldb/include/lldb/API/SBVariableAnnotator.h index 0481d47d4b0c1..ddce843c134fa 100644 --- a/lldb/include/lldb/API/SBVariableAnnotator.h +++ b/lldb/include/lldb/API/SBVariableAnnotator.h @@ -27,6 +27,16 @@ class LLDB_API SBVariableAnnotator { explicit operator bool() const; bool IsValid() const; + +protected: + SBVariableAnnotator(const lldb::VariableAnnotatorSP &annotator_sp); + + lldb::VariableAnnotatorSP GetSP() const; + + void SetSP(const lldb::VariableAnnotatorSP &annotator_sp); + +private: + lldb::VariableAnnotatorSP m_opaque_sp; }; } // namespace lldb #endif // LLDB_API_SBVARIABLEANNOTATOR_H \ No newline at end of file diff --git a/lldb/source/API/SBVariableAnnotator.cpp b/lldb/source/API/SBVariableAnnotator.cpp index 4d825afa8c84e..e5b302a44827d 100644 --- a/lldb/source/API/SBVariableAnnotator.cpp +++ b/lldb/source/API/SBVariableAnnotator.cpp @@ -8,6 +8,7 @@ //===----------------------------------------------------------------------===// #include "lldb/API/SBVariableAnnotator.h" +#include "SBVariableAnnotator.h" #include "lldb/Utility/Instrumentation.h" using namespace lldb; @@ -37,3 +38,20 @@ SBVariableAnnotator::operator bool() const { } bool lldb::SBVariableAnnotator::IsValid() const { return false; } + +lldb::SBVariableAnnotator::SBVariableAnnotator( + const lldb::VariableAnnotatorSP &annotator_sp) + : m_opaque_sp(annotator_sp) { + LLDB_INSTRUMENT_VA(this, annotator_sp); +} + +lldb::VariableAnnotatorSP lldb::SBVariableAnnotator::GetSP() const { + LLDB_INSTRUMENT_VA(this); + return m_opaque_sp; +} + +void lldb::SBVariableAnnotator::SetSP( + const lldb::VariableAnnotatorSP &annotator_sp) { + LLDB_INSTRUMENT_VA(this, annotator_sp); + m_opaque_sp = annotator_sp; +} >From 7d4187117d4f34a8a7260e1303ad7b7624c72fba Mon Sep 17 00:00:00 2001 From: Nikita B <[email protected]> Date: Tue, 23 Dec 2025 00:31:03 +0100 Subject: [PATCH 04/29] [lldb] [disassembler] chore: add variable annotator to scripting api: SBVariableAnnotator: add AnnotateStructured method declaratino and implementation stub --- lldb/include/lldb/API/SBVariableAnnotator.h | 17 +++++++++++++++++ lldb/source/API/SBVariableAnnotator.cpp | 10 ++++++++++ 2 files changed, 27 insertions(+) diff --git a/lldb/include/lldb/API/SBVariableAnnotator.h b/lldb/include/lldb/API/SBVariableAnnotator.h index ddce843c134fa..ca533b96dabbf 100644 --- a/lldb/include/lldb/API/SBVariableAnnotator.h +++ b/lldb/include/lldb/API/SBVariableAnnotator.h @@ -28,6 +28,23 @@ class LLDB_API SBVariableAnnotator { bool IsValid() const; + /// Get variable annotations for this instruction as structured data. + /// Returns an array of dictionaries, each containing: + /// - "variable_name": string name of the variable + /// - "location_description": string description of where variable is stored + /// ("RDI", "R15", "undef", etc.) + /// - "is_live": boolean indicates if variable is live at this instruction + /// - "start_address": unsigned integer address where this annotation becomes + /// valid + /// - "end_address": unsigned integer address where this annotation becomes + /// invalid + /// - "register_kind": unsigned integer indicating the register numbering + /// scheme + /// - "decl_file": string path to the file where variable is declared + /// - "decl_line": unsigned integer line number where variable is declared + /// - "type_name": string type name of the variable + lldb::SBStructuredData AnnotateStructured(SBInstruction &inst); + protected: SBVariableAnnotator(const lldb::VariableAnnotatorSP &annotator_sp); diff --git a/lldb/source/API/SBVariableAnnotator.cpp b/lldb/source/API/SBVariableAnnotator.cpp index e5b302a44827d..a944b1a7296cd 100644 --- a/lldb/source/API/SBVariableAnnotator.cpp +++ b/lldb/source/API/SBVariableAnnotator.cpp @@ -9,6 +9,7 @@ #include "lldb/API/SBVariableAnnotator.h" #include "SBVariableAnnotator.h" +#include "lldb/API/SBStructuredData.h" #include "lldb/Utility/Instrumentation.h" using namespace lldb; @@ -39,6 +40,15 @@ SBVariableAnnotator::operator bool() const { bool lldb::SBVariableAnnotator::IsValid() const { return false; } +lldb::SBStructuredData +lldb::SBVariableAnnotator::AnnotateStructured(SBInstruction &inst) { + LLDB_INSTRUMENT_VA(this, inst); + + // TODO: implement + lldb::SBStructuredData result; + return result; +} + lldb::SBVariableAnnotator::SBVariableAnnotator( const lldb::VariableAnnotatorSP &annotator_sp) : m_opaque_sp(annotator_sp) { >From 6acc07e5dd56722fad612ddb32412af3f4fb7541 Mon Sep 17 00:00:00 2001 From: Nikita B <[email protected]> Date: Tue, 23 Dec 2025 23:46:52 +0100 Subject: [PATCH 05/29] [lldb] [disassembler] chore: add variable annotator to scripting api: SBVariableAnnotator: implement AnnotateStructured method Signed-off-by: Nikita B <[email protected]> --- lldb/include/lldb/API/SBInstruction.h | 1 + lldb/include/lldb/API/SBStructuredData.h | 1 + lldb/include/lldb/API/SBVariableAnnotator.h | 2 +- lldb/source/API/SBVariableAnnotator.cpp | 51 +++++++++++++++++++-- 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/lldb/include/lldb/API/SBInstruction.h b/lldb/include/lldb/API/SBInstruction.h index 755e3b4a47c9b..3cd46907c7866 100644 --- a/lldb/include/lldb/API/SBInstruction.h +++ b/lldb/include/lldb/API/SBInstruction.h @@ -75,6 +75,7 @@ class LLDB_API SBInstruction { protected: friend class SBInstructionList; + friend class SBVariableAnnotator; SBInstruction(const lldb::DisassemblerSP &disasm_sp, const lldb::InstructionSP &inst_sp); diff --git a/lldb/include/lldb/API/SBStructuredData.h b/lldb/include/lldb/API/SBStructuredData.h index 05b9ef4cd06f4..4ec30e5113eb1 100644 --- a/lldb/include/lldb/API/SBStructuredData.h +++ b/lldb/include/lldb/API/SBStructuredData.h @@ -156,6 +156,7 @@ class SBStructuredData { friend class lldb_private::python::SWIGBridge; friend class lldb_private::lua::SWIGBridge; friend class SBCommandInterpreter; + friend class SBVariableAnnotator; SBStructuredData(const lldb_private::StructuredDataImpl &impl); diff --git a/lldb/include/lldb/API/SBVariableAnnotator.h b/lldb/include/lldb/API/SBVariableAnnotator.h index ca533b96dabbf..bd3cd3b8d5257 100644 --- a/lldb/include/lldb/API/SBVariableAnnotator.h +++ b/lldb/include/lldb/API/SBVariableAnnotator.h @@ -43,7 +43,7 @@ class LLDB_API SBVariableAnnotator { /// - "decl_file": string path to the file where variable is declared /// - "decl_line": unsigned integer line number where variable is declared /// - "type_name": string type name of the variable - lldb::SBStructuredData AnnotateStructured(SBInstruction &inst); + lldb::SBStructuredData AnnotateStructured(SBInstruction inst); protected: SBVariableAnnotator(const lldb::VariableAnnotatorSP &annotator_sp); diff --git a/lldb/source/API/SBVariableAnnotator.cpp b/lldb/source/API/SBVariableAnnotator.cpp index a944b1a7296cd..53f6ccf418f4d 100644 --- a/lldb/source/API/SBVariableAnnotator.cpp +++ b/lldb/source/API/SBVariableAnnotator.cpp @@ -9,7 +9,10 @@ #include "lldb/API/SBVariableAnnotator.h" #include "SBVariableAnnotator.h" +#include "lldb/API/SBInstruction.h" #include "lldb/API/SBStructuredData.h" +#include "lldb/Core/Disassembler.h" // containts VariableAnnotator declaration +#include "lldb/Core/StructuredDataImpl.h" #include "lldb/Utility/Instrumentation.h" using namespace lldb; @@ -26,7 +29,7 @@ SBVariableAnnotator::operator=(const SBVariableAnnotator &rhs) { LLDB_INSTRUMENT_VA(this); // if (this != &rhs) - // // TODO + // // TODO implement return *this; } @@ -38,14 +41,56 @@ SBVariableAnnotator::operator bool() const { return IsValid(); } +// TODO: implement bool lldb::SBVariableAnnotator::IsValid() const { return false; } lldb::SBStructuredData -lldb::SBVariableAnnotator::AnnotateStructured(SBInstruction &inst) { +lldb::SBVariableAnnotator::AnnotateStructured(SBInstruction inst) { LLDB_INSTRUMENT_VA(this, inst); - // TODO: implement lldb::SBStructuredData result; + + if (lldb::VariableAnnotatorSP annotator_sp = GetSP()) + if (lldb::InstructionSP inst_sp = inst.GetOpaque()) { + auto array_sp = StructuredData::ArraySP(); + + const std::vector<lldb_private::VariableAnnotation> + structured_annotations = annotator_sp->AnnotateStructured(*inst_sp); + + for (const VariableAnnotation &annotation : structured_annotations) { + auto dict_sp = std::make_shared<StructuredData::Dictionary>(); + + dict_sp->AddStringItem("variable_name", annotation.variable_name); + dict_sp->AddStringItem("location_description", + annotation.location_description); + dict_sp->AddBooleanItem("is_live", annotation.is_live); + if (annotation.address_range.has_value()) { + const auto &range = *annotation.address_range; + dict_sp->AddItem("start_address", + std::make_shared<StructuredData::UnsignedInteger>( + range.GetBaseAddress().GetFileAddress())); + dict_sp->AddItem("end_address", + std::make_shared<StructuredData::UnsignedInteger>( + range.GetBaseAddress().GetFileAddress() + + range.GetByteSize())); + } + dict_sp->AddItem("register_kind", + std::make_shared<StructuredData::UnsignedInteger>( + annotation.register_kind)); + if (annotation.decl_file.has_value()) + dict_sp->AddStringItem("decl_file", *annotation.decl_file); + if (annotation.decl_line.has_value()) + dict_sp->AddItem("decl_line", + std::make_shared<StructuredData::UnsignedInteger>( + *annotation.decl_line)); + if (annotation.type_name.has_value()) + dict_sp->AddStringItem("type_name", *annotation.type_name); + + array_sp->AddItem(dict_sp); + } + + result.m_impl_up->SetObjectSP(array_sp); + } return result; } >From 1b33a7b1c6953d46b5232450c350dda40f2427b3 Mon Sep 17 00:00:00 2001 From: Nikita B <[email protected]> Date: Tue, 23 Dec 2025 23:53:34 +0100 Subject: [PATCH 06/29] [lldb] [disassembler] chore: add variable annotator to scripting api: SBVariableAnnotator: implement bool() operator and IsValid method Signed-off-by: Nikita B <[email protected]> --- lldb/source/API/SBVariableAnnotator.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lldb/source/API/SBVariableAnnotator.cpp b/lldb/source/API/SBVariableAnnotator.cpp index 53f6ccf418f4d..5d7f9ad935b01 100644 --- a/lldb/source/API/SBVariableAnnotator.cpp +++ b/lldb/source/API/SBVariableAnnotator.cpp @@ -38,11 +38,13 @@ SBVariableAnnotator::~SBVariableAnnotator() = default; SBVariableAnnotator::operator bool() const { LLDB_INSTRUMENT_VA(this); - return IsValid(); + return m_opaque_sp.get() != nullptr; } -// TODO: implement -bool lldb::SBVariableAnnotator::IsValid() const { return false; } +bool lldb::SBVariableAnnotator::IsValid() const { + LLDB_INSTRUMENT_VA(this); + return this->operator bool(); +} lldb::SBStructuredData lldb::SBVariableAnnotator::AnnotateStructured(SBInstruction inst) { >From 44647bdd08fab24aa7e0ef2f1fb24e33d3b4c2e8 Mon Sep 17 00:00:00 2001 From: Nikita B <[email protected]> Date: Tue, 23 Dec 2025 23:54:35 +0100 Subject: [PATCH 07/29] [lldb] [disassembler] chore: add variable annotator to scripting api: SBVariableAnnotator: implement operator = Signed-off-by: Nikita B <[email protected]> --- lldb/source/API/SBVariableAnnotator.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lldb/source/API/SBVariableAnnotator.cpp b/lldb/source/API/SBVariableAnnotator.cpp index 5d7f9ad935b01..4e25a09f09837 100644 --- a/lldb/source/API/SBVariableAnnotator.cpp +++ b/lldb/source/API/SBVariableAnnotator.cpp @@ -26,10 +26,10 @@ SBVariableAnnotator::SBVariableAnnotator(const SBVariableAnnotator &rhs) { const SBVariableAnnotator & SBVariableAnnotator::operator=(const SBVariableAnnotator &rhs) { - LLDB_INSTRUMENT_VA(this); + LLDB_INSTRUMENT_VA(this, rhs); - // if (this != &rhs) - // // TODO implement + if (this != &rhs) + m_opaque_sp = rhs.m_opaque_sp; return *this; } >From 6d9a87e7935f71e8a47fb3a5fe34e279f3b52e6d Mon Sep 17 00:00:00 2001 From: Nikita B <[email protected]> Date: Tue, 23 Dec 2025 23:59:30 +0100 Subject: [PATCH 08/29] [lldb] [disassembler] chore: add variable annotator to scripting api: SBVariableAnnotator: implement empty constructor and copy constructor Signed-off-by: Nikita B <[email protected]> --- lldb/source/API/SBVariableAnnotator.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lldb/source/API/SBVariableAnnotator.cpp b/lldb/source/API/SBVariableAnnotator.cpp index 4e25a09f09837..83723d2042318 100644 --- a/lldb/source/API/SBVariableAnnotator.cpp +++ b/lldb/source/API/SBVariableAnnotator.cpp @@ -18,12 +18,15 @@ using namespace lldb; using namespace lldb_private; -SBVariableAnnotator::SBVariableAnnotator() { LLDB_INSTRUMENT_VA(this); } - -SBVariableAnnotator::SBVariableAnnotator(const SBVariableAnnotator &rhs) { +SBVariableAnnotator::SBVariableAnnotator() : m_opaque_sp() { LLDB_INSTRUMENT_VA(this); } +SBVariableAnnotator::SBVariableAnnotator(const SBVariableAnnotator &rhs) + : m_opaque_sp(rhs.m_opaque_sp) { + LLDB_INSTRUMENT_VA(this, rhs); +} + const SBVariableAnnotator & SBVariableAnnotator::operator=(const SBVariableAnnotator &rhs) { LLDB_INSTRUMENT_VA(this, rhs); >From dfd559ecb194e1a5a65022713ca139a26a4d24c1 Mon Sep 17 00:00:00 2001 From: Nikita B <[email protected]> Date: Wed, 24 Dec 2025 00:04:56 +0100 Subject: [PATCH 09/29] [lldb] [disassembler] chore: add variable annotator to scripting api: SBVariableAnnotator: drop lldb namespace prefix in front of SBVariableAnnotator in implementation file Signed-off-by: Nikita B <[email protected]> --- lldb/source/API/SBVariableAnnotator.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/lldb/source/API/SBVariableAnnotator.cpp b/lldb/source/API/SBVariableAnnotator.cpp index 83723d2042318..378b70b23bfe9 100644 --- a/lldb/source/API/SBVariableAnnotator.cpp +++ b/lldb/source/API/SBVariableAnnotator.cpp @@ -44,13 +44,13 @@ SBVariableAnnotator::operator bool() const { return m_opaque_sp.get() != nullptr; } -bool lldb::SBVariableAnnotator::IsValid() const { +bool SBVariableAnnotator::IsValid() const { LLDB_INSTRUMENT_VA(this); return this->operator bool(); } lldb::SBStructuredData -lldb::SBVariableAnnotator::AnnotateStructured(SBInstruction inst) { +SBVariableAnnotator::AnnotateStructured(SBInstruction inst) { LLDB_INSTRUMENT_VA(this, inst); lldb::SBStructuredData result; @@ -99,19 +99,18 @@ lldb::SBVariableAnnotator::AnnotateStructured(SBInstruction inst) { return result; } -lldb::SBVariableAnnotator::SBVariableAnnotator( +SBVariableAnnotator::SBVariableAnnotator( const lldb::VariableAnnotatorSP &annotator_sp) : m_opaque_sp(annotator_sp) { LLDB_INSTRUMENT_VA(this, annotator_sp); } -lldb::VariableAnnotatorSP lldb::SBVariableAnnotator::GetSP() const { +lldb::VariableAnnotatorSP SBVariableAnnotator::GetSP() const { LLDB_INSTRUMENT_VA(this); return m_opaque_sp; } -void lldb::SBVariableAnnotator::SetSP( - const lldb::VariableAnnotatorSP &annotator_sp) { +void SBVariableAnnotator::SetSP(const lldb::VariableAnnotatorSP &annotator_sp) { LLDB_INSTRUMENT_VA(this, annotator_sp); m_opaque_sp = annotator_sp; } >From ecc2a6dd3e3ced972e646481d9678514d044044e Mon Sep 17 00:00:00 2001 From: Nikita B <[email protected]> Date: Wed, 24 Dec 2025 00:11:00 +0100 Subject: [PATCH 10/29] [lldb] [disassembler] chore: add variable annotator to scripting api: SBVariableAnnotator: include header in LLDB.h Signed-off-by: Nikita B <[email protected]> --- lldb/include/lldb/API/LLDB.h | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/include/lldb/API/LLDB.h b/lldb/include/lldb/API/LLDB.h index 6ac35bb4a364b..f861eb702919e 100644 --- a/lldb/include/lldb/API/LLDB.h +++ b/lldb/include/lldb/API/LLDB.h @@ -86,6 +86,7 @@ #include "lldb/API/SBUnixSignals.h" #include "lldb/API/SBValue.h" #include "lldb/API/SBValueList.h" +#include "lldb/API/SBVariableAnnotator.h" #include "lldb/API/SBVariablesOptions.h" #include "lldb/API/SBWatchpoint.h" >From 3b3fbbcb9c08d0753245ee367a3ce9909628f3f0 Mon Sep 17 00:00:00 2001 From: Nikita B <[email protected]> Date: Wed, 24 Dec 2025 00:12:24 +0100 Subject: [PATCH 11/29] [lldb] [disassembler] chore: add variable annotator to scripting api: SBVariableAnnotator: include header in SBDefines.h Signed-off-by: Nikita B <[email protected]> --- lldb/include/lldb/API/SBDefines.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lldb/include/lldb/API/SBDefines.h b/lldb/include/lldb/API/SBDefines.h index 5fcc685050c0b..123b4a6de28e9 100644 --- a/lldb/include/lldb/API/SBDefines.h +++ b/lldb/include/lldb/API/SBDefines.h @@ -134,6 +134,7 @@ class LLDB_API SBTypeSynthetic; class LLDB_API SBTypeList; class LLDB_API SBValue; class LLDB_API SBValueList; +class LLDB_API SBVariableAnnotator; class LLDB_API SBVariablesOptions; class LLDB_API SBWatchpoint; class LLDB_API SBWatchpointOptions; @@ -152,6 +153,6 @@ typedef lldb::CommandReturnObjectCallbackResult (*SBCommandPrintCallback)( typedef lldb::SBError (*SBPlatformLocateModuleCallback)( void *baton, const lldb::SBModuleSpec &module_spec, lldb::SBFileSpec &module_file_spec, lldb::SBFileSpec &symbol_file_spec); -} +} // namespace lldb #endif // LLDB_API_SBDEFINES_H >From ab6ad2b39beb9077512b26a130b1afa04601f0a6 Mon Sep 17 00:00:00 2001 From: Nikita B <[email protected]> Date: Sat, 27 Dec 2025 13:35:04 +0100 Subject: [PATCH 12/29] [lldb] [disassembler] chore: add variable annotator to scripting api: add SBVariableAnnotator.cpp to CMakeLists.txt Signed-off-by: Nikita B <[email protected]> --- lldb/source/API/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt index ac47580d60840..e6c31e768b9e2 100644 --- a/lldb/source/API/CMakeLists.txt +++ b/lldb/source/API/CMakeLists.txt @@ -119,6 +119,7 @@ add_lldb_library(liblldb SHARED ${option_framework} SBUnixSignals.cpp SBValue.cpp SBValueList.cpp + SBVariableAnnotator.cpp SBVariablesOptions.cpp SBWatchpoint.cpp SBWatchpointOptions.cpp >From 90617f69cef26fe52786a844da7e7dd11a6ca564 Mon Sep 17 00:00:00 2001 From: Nikita B <[email protected]> Date: Sat, 27 Dec 2025 13:37:04 +0100 Subject: [PATCH 13/29] [lldb] [disassembler] chore: add variable annotator to scripting api: add SBVariableAnnotatorExtensions.i Signed-off-by: Nikita B <[email protected]> --- .../interface/SBVariableAnnotatorExtensions.i | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 lldb/bindings/interface/SBVariableAnnotatorExtensions.i diff --git a/lldb/bindings/interface/SBVariableAnnotatorExtensions.i b/lldb/bindings/interface/SBVariableAnnotatorExtensions.i new file mode 100644 index 0000000000000..5eb7009ce97e7 --- /dev/null +++ b/lldb/bindings/interface/SBVariableAnnotatorExtensions.i @@ -0,0 +1,52 @@ +STRING_EXTENSION_OUTSIDE(SBVariableAnnotator) + + % extend lldb::SBVariableAnnotator { +#ifdef SWIGPYTHON + % pythoncode % { + def get_annotations_list(self, instruction): + """Get variable annotations as a Python list of dictionaries. + + Args: + instruction: SBInstruction object to annotate + + Returns: + List of dictionaries, each containing variable annotation data + """ + structured_data = self.AnnotateStructured(instruction) + if not structured_data.IsValid(): + return [] + + annotations = [] + for i in range(structured_data.GetSize()): + item = structured_data.GetItemAtIndex(i) + if item.GetType() != lldb.eStructuredDataTypeDictionary: + continue + + annotation = {} + + boolean_fields = ['is_live'] + integer_fields = ['start_address', 'end_address', 'register_kind', 'decl_line'] + string_fields = ['variable_name', 'location_description', 'decl_file', 'type_name'] + + for field in boolean_fields: + value = item.GetValueForKey(field) + if value.IsValid(): + annotation[field] = value.GetBooleanValue() + + for field in integer_fields: + value = item.GetValueForKey(field) + if value.IsValid(): + annotation[field] = value.GetUnsignedIntegerValue() + + for field in string_fields: + value = item.GetValueForKey(field) + if value.IsValid(): + annotation[field] = value.GetStringValue(1024) + + annotations.append(annotation) + + return annotations + % + } +#endif +} \ No newline at end of file >From 40b5ff04be5728034a264cc18e17f0f73dd510b2 Mon Sep 17 00:00:00 2001 From: Nikita B <[email protected]> Date: Sat, 27 Dec 2025 13:37:30 +0100 Subject: [PATCH 14/29] [lldb] [disassembler] chore: add variable annotator to scripting api: add SBVariableAnnotatorDocstrings.i Signed-off-by: Nikita B <[email protected]> --- .../interface/SBVariableAnnotatorDocstrings.i | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 lldb/bindings/interface/SBVariableAnnotatorDocstrings.i diff --git a/lldb/bindings/interface/SBVariableAnnotatorDocstrings.i b/lldb/bindings/interface/SBVariableAnnotatorDocstrings.i new file mode 100644 index 0000000000000..9f3b4c4b514db --- /dev/null +++ b/lldb/bindings/interface/SBVariableAnnotatorDocstrings.i @@ -0,0 +1,83 @@ +%feature("docstring", +"Provides variable annotation functionality for disassembly instructions. + +The SBVariableAnnotator class enables retrieval of structured variable +location information for assembly instructions during debugging. This +allows tools to understand where variables are stored (registers, memory) +at specific instruction addresses, which is essential for debugging +optimized code where variables may move between locations. + +The annotator extracts DWARF debug information to provide: +* Variable names and types +* Current storage location (register name, memory, undefined) +* Address ranges where the location is valid +* Source declaration information + +For example, when debugging optimized code:: + + annotator = lldb.SBVariableAnnotator() + target = lldb.debugger.GetSelectedTarget() + frame = target.GetProcess().GetSelectedThread().GetSelectedFrame() + + # Get instructions for current function + function = frame.GetFunction() + instructions = target.ReadInstructions(function.GetStartAddress(), + function.GetEndAddress()) + + # Annotate each instruction + for i in range(instructions.GetSize()): + inst = instructions.GetInstructionAtIndex(i) + annotations = annotator.AnnotateStructured(inst) + + # Process structured annotation data + for j in range(annotations.GetSize()): + item = annotations.GetItemAtIndex(j) + var_name = item.GetValueForKey('variable_name').GetStringValue(1024) + location = item.GetValueForKey('location_description').GetStringValue(1024) + is_live = item.GetValueForKey('is_live').GetBooleanValue() + + print(f'Variable {var_name} in {location}, live: {is_live}')" +) lldb::SBVariableAnnotator; + +%feature("docstring", " + Create a new variable annotator instance. + + The annotator can be used to extract variable location information + from assembly instructions when debugging programs compiled with + debug information.") +lldb::SBVariableAnnotator::SBVariableAnnotator; + +%feature("docstring", " + Get variable annotations for an instruction as structured data. + + Returns an SBStructuredData object containing an array of dictionaries, + where each dictionary represents one variable annotation with the following keys: + + * 'variable_name' (string): Name of the variable + * 'location_description' (string): Where the variable is stored + (register name like 'RDI', 'R15', or 'undef' if not available) + * 'is_live' (boolean): Whether the variable is live at this instruction + * 'start_address' (integer): Address where this location becomes valid + * 'end_address' (integer): Address where this location becomes invalid + * 'register_kind' (integer): Register numbering scheme identifier + * 'decl_file' (string): Source file where variable is declared (optional) + * 'decl_line' (integer): Line number where variable is declared (optional) + * 'type_name' (string): Type name of the variable (optional) + + Args: + inst: SBInstruction object to annotate + + Returns: + SBStructuredData containing variable annotation array, or invalid + SBStructuredData if no annotations are available + + Example usage:: + + annotations = annotator.AnnotateStructured(instruction) + if annotations.IsValid(): + for i in range(annotations.GetSize()): + item = annotations.GetItemAtIndex(i) + name = item.GetValueForKey('variable_name').GetStringValue(1024) + location = item.GetValueForKey('location_description').GetStringValue(1024) + print(f'{name} -> {location}')") +lldb::SBVariableAnnotator::AnnotateStructured; \ No newline at end of file >From 5849683ce82c84486308c3cb49eed060b5c934f4 Mon Sep 17 00:00:00 2001 From: Nikita B <[email protected]> Date: Sun, 28 Dec 2025 14:00:20 +0100 Subject: [PATCH 15/29] [lldb] [disassembler] chore: add variable annotator to scripting api: fix import in SBVariableAnnotator.cpp Signed-off-by: Nikita B <[email protected]> --- lldb/source/API/SBVariableAnnotator.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/lldb/source/API/SBVariableAnnotator.cpp b/lldb/source/API/SBVariableAnnotator.cpp index 378b70b23bfe9..66b8f93ad6fef 100644 --- a/lldb/source/API/SBVariableAnnotator.cpp +++ b/lldb/source/API/SBVariableAnnotator.cpp @@ -8,7 +8,6 @@ //===----------------------------------------------------------------------===// #include "lldb/API/SBVariableAnnotator.h" -#include "SBVariableAnnotator.h" #include "lldb/API/SBInstruction.h" #include "lldb/API/SBStructuredData.h" #include "lldb/Core/Disassembler.h" // containts VariableAnnotator declaration >From 11df6536257007499583097cd37484b1750f6d98 Mon Sep 17 00:00:00 2001 From: Nikita B <[email protected]> Date: Mon, 29 Dec 2025 14:15:01 +0100 Subject: [PATCH 16/29] [lldb] [disassembler] chore: add variable annotator to scripting api: include SBVariableAnnotator in interfaces.swig Signed-off-by: Nikita B <[email protected]> --- lldb/bindings/interfaces.swig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lldb/bindings/interfaces.swig b/lldb/bindings/interfaces.swig index fddbedf02e835..11c17970b6a8a 100644 --- a/lldb/bindings/interfaces.swig +++ b/lldb/bindings/interfaces.swig @@ -86,6 +86,7 @@ %include "./interface/SBUnixSignalsDocstrings.i" %include "./interface/SBValueDocstrings.i" %include "./interface/SBValueListDocstrings.i" +%include "./interface/SBVariableAnnotatorDocstrings.i" %include "./interface/SBVariablesOptionsDocstrings.i" %include "./interface/SBWatchpointDocstrings.i" %include "./interface/SBWatchpointOptionsDocstrings.i" @@ -169,6 +170,7 @@ %include "lldb/API/SBUnixSignals.h" %include "lldb/API/SBValue.h" %include "lldb/API/SBValueList.h" +%include "lldb/API/SBVariableAnnotator.h" %include "lldb/API/SBVariablesOptions.h" %include "lldb/API/SBWatchpoint.h" %include "lldb/API/SBWatchpointOptions.h" @@ -230,4 +232,5 @@ %include "./interface/SBUnixSignalsExtensions.i" %include "./interface/SBValueExtensions.i" %include "./interface/SBValueListExtensions.i" +%include "./interface/SBVariableAnnotatorExtensions.i" %include "./interface/SBWatchpointExtensions.i" >From ec6aadda1764a1ee89a9d69d51d247f28f4d8e43 Mon Sep 17 00:00:00 2001 From: Nikita B <[email protected]> Date: Mon, 29 Dec 2025 14:16:28 +0100 Subject: [PATCH 17/29] [lldb] [disassembler] chore: add variable annotator to scripting api: add GetDescription to SBVaribaleAnnotator class Signed-off-by: Nikita B <[email protected]> --- lldb/include/lldb/API/SBStream.h | 1 + lldb/include/lldb/API/SBVariableAnnotator.h | 2 ++ lldb/source/API/SBVariableAnnotator.cpp | 9 +++++++++ 3 files changed, 12 insertions(+) diff --git a/lldb/include/lldb/API/SBStream.h b/lldb/include/lldb/API/SBStream.h index 21f9d21e0e717..f336827f3fa65 100644 --- a/lldb/include/lldb/API/SBStream.h +++ b/lldb/include/lldb/API/SBStream.h @@ -106,6 +106,7 @@ class LLDB_API SBStream { friend class SBTypeMemberFunction; friend class SBTypeMember; friend class SBValue; + friend class SBVariableAnnotator; friend class SBWatchpoint; friend class lldb_private::ScriptInterpreter; diff --git a/lldb/include/lldb/API/SBVariableAnnotator.h b/lldb/include/lldb/API/SBVariableAnnotator.h index bd3cd3b8d5257..d442e19431109 100644 --- a/lldb/include/lldb/API/SBVariableAnnotator.h +++ b/lldb/include/lldb/API/SBVariableAnnotator.h @@ -28,6 +28,8 @@ class LLDB_API SBVariableAnnotator { bool IsValid() const; + bool GetDescription(SBStream &description) const; + /// Get variable annotations for this instruction as structured data. /// Returns an array of dictionaries, each containing: /// - "variable_name": string name of the variable diff --git a/lldb/source/API/SBVariableAnnotator.cpp b/lldb/source/API/SBVariableAnnotator.cpp index 66b8f93ad6fef..71a5ef56df4e2 100644 --- a/lldb/source/API/SBVariableAnnotator.cpp +++ b/lldb/source/API/SBVariableAnnotator.cpp @@ -9,6 +9,7 @@ #include "lldb/API/SBVariableAnnotator.h" #include "lldb/API/SBInstruction.h" +#include "lldb/API/SBStream.h" #include "lldb/API/SBStructuredData.h" #include "lldb/Core/Disassembler.h" // containts VariableAnnotator declaration #include "lldb/Core/StructuredDataImpl.h" @@ -48,6 +49,14 @@ bool SBVariableAnnotator::IsValid() const { return this->operator bool(); } +bool SBVariableAnnotator::GetDescription(SBStream &description) const { + LLDB_INSTRUMENT_VA(this, description); + + Stream &strm = description.ref(); + strm.Printf("SBVariableAnnotator"); + return true; +} + lldb::SBStructuredData SBVariableAnnotator::AnnotateStructured(SBInstruction inst) { LLDB_INSTRUMENT_VA(this, inst); >From 635ef109a7d0c6df74d5eb894f1a37a1c72bef47 Mon Sep 17 00:00:00 2001 From: Nikita B <[email protected]> Date: Mon, 29 Dec 2025 14:23:22 +0100 Subject: [PATCH 18/29] [lldb] [disassembler] chore: add variable annotator to scripting api: fix formatting in SBVariableAnnotatorExtensions.i Signed-off-by: Nikita B <[email protected]> --- lldb/bindings/interface/SBVariableAnnotatorExtensions.i | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lldb/bindings/interface/SBVariableAnnotatorExtensions.i b/lldb/bindings/interface/SBVariableAnnotatorExtensions.i index 5eb7009ce97e7..a0e940e7f17af 100644 --- a/lldb/bindings/interface/SBVariableAnnotatorExtensions.i +++ b/lldb/bindings/interface/SBVariableAnnotatorExtensions.i @@ -1,8 +1,8 @@ STRING_EXTENSION_OUTSIDE(SBVariableAnnotator) - % extend lldb::SBVariableAnnotator { +%extend lldb::SBVariableAnnotator { #ifdef SWIGPYTHON - % pythoncode % { + %pythoncode %{ def get_annotations_list(self, instruction): """Get variable annotations as a Python list of dictionaries. @@ -46,7 +46,6 @@ STRING_EXTENSION_OUTSIDE(SBVariableAnnotator) annotations.append(annotation) return annotations - % - } + %} #endif -} \ No newline at end of file +} >From a18f53179ccf6aef78dfbaf92a20ab2fa199dcb9 Mon Sep 17 00:00:00 2001 From: Nikita B <[email protected]> Date: Mon, 29 Dec 2025 23:46:21 +0100 Subject: [PATCH 19/29] [lldb] [disassembler] chore: add variable annotator to scripting api: copy test_structured_annotations_api from draft pr #165163, replace to use new class SBVariableAnnotator Signed-off-by: Nikita B <[email protected]> --- .../TestVariableAnnotationsDisassembler.py | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/lldb/test/API/functionalities/disassembler-variables/TestVariableAnnotationsDisassembler.py b/lldb/test/API/functionalities/disassembler-variables/TestVariableAnnotationsDisassembler.py index f107efbddddeb..b600eed245535 100644 --- a/lldb/test/API/functionalities/disassembler-variables/TestVariableAnnotationsDisassembler.py +++ b/lldb/test/API/functionalities/disassembler-variables/TestVariableAnnotationsDisassembler.py @@ -116,3 +116,103 @@ def test_seed_reg_const_undef(self): print(out) self.assertRegex(out, r"\b(i|argc)\s*=\s*(DW_OP_reg\d+\b|R[A-Z0-9]+)") self.assertNotIn("<decoding error>", out) + + @no_debug_info_test + @skipIf(archs=no_match(["x86_64"])) + def test_structured_annotations_api(self): + """Test SBVariableAnnotator::AnnotateStructured API returns structured data""" + obj = self._build_obj("d_original_example.o") + target = self._create_target(obj) + annotator = lldb.SBVariableAnnotator() + + main_symbols = target.FindSymbols("main") + self.assertTrue( + main_symbols.IsValid() and main_symbols.GetSize() > 0, + "Could not find 'main' symbol", + ) + + main_symbol = main_symbols.GetContextAtIndex(0).GetSymbol() + start_addr = main_symbol.GetStartAddress() + self.assertTrue(start_addr.IsValid(), "Invalid start address for main") + + instructions = target.ReadInstructions(start_addr, 16) + self.assertGreater(instructions.GetSize(), 0, "No instructions read") + + if self.TraceOn(): + print( + f"\nTesting SBVariableAnnotator::AnnotateStructured API on {instructions.GetSize()} instructions" + ) + + expected_vars = ["argc", "argv", "i"] + found_variables = set() + + # Test each instruction. + for i in range(instructions.GetSize()): + inst = instructions.GetInstructionAtIndex(i) + self.assertTrue(inst.IsValid(), f"Invalid instruction at index {i}") + + # TODO use more python convinient get_annotations_list defined in Extensions file. + annotations = annotator.AnnotateStructured(inst) + + self.assertIsInstance( + annotations, + lldb.SBStructuredData, + "AnnotateStructured should return SBStructuredData", + ) + + self.assertTrue( + annotations.GetSize() > 0, + "AnnotateStructured should return non empty array", + ) + + if annotations.GetSize() > 0: + # Validate each annotation. + for j in range(annotations.GetSize()): + ann = annotations.GetItemAtIndex(j) + self.assertTrue(ann.IsValid(), f"Invalid annotation at index {j}") + + self.assertEqual( + ann.GetType(), + lldb.eStructuredDataTypeDictionary, + "Each annotation should be a dictionary", + ) + + var_name_obj = ann.GetValueForKey("variable_name") + self.assertTrue( + var_name_obj.IsValid(), "Missing 'variable_name' field" + ) + + location_obj = ann.GetValueForKey("location_description") + self.assertTrue( + location_obj.IsValid(), "Missing 'location_description' field" + ) + + is_live_obj = ann.GetValueForKey("is_live") + self.assertTrue(is_live_obj.IsValid(), "Missing 'is_live' field") + + start_addr_obj = ann.GetValueForKey("start_address") + self.assertTrue( + start_addr_obj.IsValid(), "Missing 'start_address' field" + ) + + end_addr_obj = ann.GetValueForKey("end_address") + self.assertTrue( + end_addr_obj.IsValid(), "Missing 'end_address' field" + ) + + register_kind_obj = ann.GetValueForKey("register_kind") + self.assertTrue( + register_kind_obj.IsValid(), "Missing 'register_kind' field" + ) + + var_name = var_name_obj.GetStringValue(1024) + + # Check for expected variables in this function. + self.assertIn( + var_name, expected_vars, f"Unexpected variable name: {var_name}" + ) + + found_variables.add(var_name) + + if self.TraceOn(): + print(f"\nTest complete. Found variables: {found_variables}") \ No newline at end of file >From 44b4581c80acab477ae04f3bfba47b468751b9e0 Mon Sep 17 00:00:00 2001 From: Nikita B <[email protected]> Date: Wed, 31 Dec 2025 00:16:06 +0100 Subject: [PATCH 20/29] [lldb] [disassembler] chore: add variable annotator to scripting api: instantiate opaque pointer in default constructor; properly instantiate structured data array Signed-off-by: Nikita B <[email protected]> --- lldb/source/API/SBVariableAnnotator.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lldb/source/API/SBVariableAnnotator.cpp b/lldb/source/API/SBVariableAnnotator.cpp index 71a5ef56df4e2..c59423c771aa3 100644 --- a/lldb/source/API/SBVariableAnnotator.cpp +++ b/lldb/source/API/SBVariableAnnotator.cpp @@ -18,7 +18,8 @@ using namespace lldb; using namespace lldb_private; -SBVariableAnnotator::SBVariableAnnotator() : m_opaque_sp() { +SBVariableAnnotator::SBVariableAnnotator() + : m_opaque_sp(std::make_shared<VariableAnnotator>()) { LLDB_INSTRUMENT_VA(this); } @@ -65,7 +66,8 @@ SBVariableAnnotator::AnnotateStructured(SBInstruction inst) { if (lldb::VariableAnnotatorSP annotator_sp = GetSP()) if (lldb::InstructionSP inst_sp = inst.GetOpaque()) { - auto array_sp = StructuredData::ArraySP(); + StructuredData::ArraySP array_sp = + std::make_shared<StructuredData::Array>(); const std::vector<lldb_private::VariableAnnotation> structured_annotations = annotator_sp->AnnotateStructured(*inst_sp); >From 11f004618c99e1913e653274e1b445f2bc474945 Mon Sep 17 00:00:00 2001 From: Nikita B <[email protected]> Date: Wed, 31 Dec 2025 00:16:51 +0100 Subject: [PATCH 21/29] [lldb] [disassembler] chore: add variable annotator to scripting api: fix typo in comment Signed-off-by: Nikita B <[email protected]> --- lldb/source/API/SBVariableAnnotator.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/source/API/SBVariableAnnotator.cpp b/lldb/source/API/SBVariableAnnotator.cpp index c59423c771aa3..a6fdddb795011 100644 --- a/lldb/source/API/SBVariableAnnotator.cpp +++ b/lldb/source/API/SBVariableAnnotator.cpp @@ -11,7 +11,7 @@ #include "lldb/API/SBInstruction.h" #include "lldb/API/SBStream.h" #include "lldb/API/SBStructuredData.h" -#include "lldb/Core/Disassembler.h" // containts VariableAnnotator declaration +#include "lldb/Core/Disassembler.h" // contains VariableAnnotator declaration #include "lldb/Core/StructuredDataImpl.h" #include "lldb/Utility/Instrumentation.h" >From 17ba027703e3dca6cdbb072081142f6025d2c29a Mon Sep 17 00:00:00 2001 From: Nikita B <[email protected]> Date: Thu, 1 Jan 2026 14:31:06 +0100 Subject: [PATCH 22/29] [lldb] [disassembler] chore: add variable annotator to scripting api: update test to use annotator created once Signed-off-by: Nikita B <[email protected]> --- .../TestVariableAnnotationsDisassembler.py | 138 +++++++++++------- 1 file changed, 82 insertions(+), 56 deletions(-) diff --git a/lldb/test/API/functionalities/disassembler-variables/TestVariableAnnotationsDisassembler.py b/lldb/test/API/functionalities/disassembler-variables/TestVariableAnnotationsDisassembler.py index b600eed245535..c894d0e2559de 100644 --- a/lldb/test/API/functionalities/disassembler-variables/TestVariableAnnotationsDisassembler.py +++ b/lldb/test/API/functionalities/disassembler-variables/TestVariableAnnotationsDisassembler.py @@ -123,7 +123,6 @@ def test_structured_annotations_api(self): """Test SBVariableAnnotator::AnnotateStructured API returns structured data""" obj = self._build_obj("d_original_example.o") target = self._create_target(obj) - annotator = lldb.SBVariableAnnotator() main_symbols = target.FindSymbols("main") self.assertTrue( @@ -144,6 +143,11 @@ def test_structured_annotations_api(self): ) expected_vars = ["argc", "argv", "i"] + + annotator = lldb.SBVariableAnnotator() + + # Track current state of variables across instructions. + active_vars = {} # var_name -> location_description. found_variables = set() # Test each instruction. @@ -151,7 +155,8 @@ def test_structured_annotations_api(self): inst = instructions.GetInstructionAtIndex(i) self.assertTrue(inst.IsValid(), f"Invalid instruction at index {i}") - # TODO use more python convinient get_annotations_list defined in Extensions file. + # TODO: use get_annotations_list from Extensions.i. + # Get annotations (may be empty if nothing changed). annotations = annotator.AnnotateStructured(inst) self.assertIsInstance( @@ -160,59 +165,80 @@ def test_structured_annotations_api(self): "AnnotateStructured should return SBStructuredData", ) - self.assertTrue( - annotations.GetSize() > 0, - "AnnotateStructured should return non empty array", - ) - - if annotations.GetSize() > 0: - # Validate each annotation. - for j in range(annotations.GetSize()): - ann = annotations.GetItemAtIndex(j) - self.assertTrue(ann.IsValid(), f"Invalid annotation at index {j}") - - self.assertEqual( - ann.GetType(), - lldb.eStructuredDataTypeDictionary, - "Each annotation should be a dictionary", - ) - - var_name_obj = ann.GetValueForKey("variable_name") - self.assertTrue( - var_name_obj.IsValid(), "Missing 'variable_name' field" - ) - - location_obj = ann.GetValueForKey("location_description") - self.assertTrue( - location_obj.IsValid(), "Missing 'location_description' field" - ) - - is_live_obj = ann.GetValueForKey("is_live") - self.assertTrue(is_live_obj.IsValid(), "Missing 'is_live' field") - - start_addr_obj = ann.GetValueForKey("start_address") - self.assertTrue( - start_addr_obj.IsValid(), "Missing 'start_address' field" - ) - - end_addr_obj = ann.GetValueForKey("end_address") - self.assertTrue( - end_addr_obj.IsValid(), "Missing 'end_address' field" - ) - - register_kind_obj = ann.GetValueForKey("register_kind") - self.assertTrue( - register_kind_obj.IsValid(), "Missing 'register_kind' field" - ) - - var_name = var_name_obj.GetStringValue(1024) - - # Check for expected variables in this function. - self.assertIn( - var_name, expected_vars, f"Unexpected variable name: {var_name}" - ) - - found_variables.add(var_name) + # Process changes. + for j in range(annotations.GetSize()): + ann = annotations.GetItemAtIndex(j) + self.assertTrue(ann.IsValid(), f"Invalid annotation at index {j}") + + self.assertEqual( + ann.GetType(), + lldb.eStructuredDataTypeDictionary, + "Each annotation should be a dictionary", + ) + + # Validate all required fields are present. + var_name_obj = ann.GetValueForKey("variable_name") + self.assertTrue( + var_name_obj.IsValid(), "Missing 'variable_name' field" + ) + + location_obj = ann.GetValueForKey("location_description") + self.assertTrue( + location_obj.IsValid(), "Missing 'location_description' field" + ) + + is_live_obj = ann.GetValueForKey("is_live") + self.assertTrue(is_live_obj.IsValid(), "Missing 'is_live' field") + + start_addr_obj = ann.GetValueForKey("start_address") + self.assertTrue( + start_addr_obj.IsValid(), "Missing 'start_address' field" + ) + + end_addr_obj = ann.GetValueForKey("end_address") + self.assertTrue( + end_addr_obj.IsValid(), "Missing 'end_address' field" + ) + + register_kind_obj = ann.GetValueForKey("register_kind") + self.assertTrue( + register_kind_obj.IsValid(), "Missing 'register_kind' field" + ) + + var_name = var_name_obj.GetStringValue(1024) + location = location_obj.GetStringValue(1024) + is_live = is_live_obj.GetBooleanValue() + + self.assertIn( + var_name, expected_vars, f"Unexpected variable name: {var_name}" + ) + + found_variables.add(var_name) + + # Update tracking state. + if location == "undef" or not is_live: + # Variable went away. + if var_name in active_vars: + if self.TraceOn(): + print(f" [{i:2d}] {var_name}: {active_vars[var_name]} -> undef") + active_vars.pop(var_name) + else: + # Variable newly live or location changed. + old_location = active_vars.get(var_name) + if old_location != location: + if self.TraceOn(): + if old_location is None: + print(f" [{i:2d}] {var_name}: -> {location} (newly live)") + else: + print(f" [{i:2d}] {var_name}: {old_location} -> {location} (changed)") + active_vars[var_name] = location + + # Validate we find all expected variables. + self.assertEqual( + found_variables, + set(expected_vars), + f"Did not find all expected variables. Expected: {expected_vars}, find: {found_variables}" + ) if self.TraceOn(): - print(f"\nTest complete. Found variables: {found_variables}") \ No newline at end of file + print(f"\nTest complete. All expected variables found: {found_variables}") >From c57962de6f46ca45ee8604a6e82a90652d2b2f5d Mon Sep 17 00:00:00 2001 From: Nikita B <[email protected]> Date: Tue, 6 Jan 2026 18:52:07 +0100 Subject: [PATCH 23/29] [lldb] [disassembler] chore: add variable annotator to scripting api: remove unused protected methods Signed-off-by: Nikita B <[email protected]> --- lldb/include/lldb/API/SBVariableAnnotator.h | 7 ------- lldb/source/API/SBVariableAnnotator.cpp | 4 ++-- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/lldb/include/lldb/API/SBVariableAnnotator.h b/lldb/include/lldb/API/SBVariableAnnotator.h index d442e19431109..14563e3256ea6 100644 --- a/lldb/include/lldb/API/SBVariableAnnotator.h +++ b/lldb/include/lldb/API/SBVariableAnnotator.h @@ -47,13 +47,6 @@ class LLDB_API SBVariableAnnotator { /// - "type_name": string type name of the variable lldb::SBStructuredData AnnotateStructured(SBInstruction inst); -protected: - SBVariableAnnotator(const lldb::VariableAnnotatorSP &annotator_sp); - - lldb::VariableAnnotatorSP GetSP() const; - - void SetSP(const lldb::VariableAnnotatorSP &annotator_sp); - private: lldb::VariableAnnotatorSP m_opaque_sp; }; diff --git a/lldb/source/API/SBVariableAnnotator.cpp b/lldb/source/API/SBVariableAnnotator.cpp index a6fdddb795011..1df8c11fef181 100644 --- a/lldb/source/API/SBVariableAnnotator.cpp +++ b/lldb/source/API/SBVariableAnnotator.cpp @@ -64,13 +64,13 @@ SBVariableAnnotator::AnnotateStructured(SBInstruction inst) { lldb::SBStructuredData result; - if (lldb::VariableAnnotatorSP annotator_sp = GetSP()) + if (m_opaque_sp) if (lldb::InstructionSP inst_sp = inst.GetOpaque()) { StructuredData::ArraySP array_sp = std::make_shared<StructuredData::Array>(); const std::vector<lldb_private::VariableAnnotation> - structured_annotations = annotator_sp->AnnotateStructured(*inst_sp); + structured_annotations = m_opaque_sp->AnnotateStructured(*inst_sp); for (const VariableAnnotation &annotation : structured_annotations) { auto dict_sp = std::make_shared<StructuredData::Dictionary>(); >From b922dedfd1b81863deb3260420e6eb988e55535d Mon Sep 17 00:00:00 2001 From: Nikita B <[email protected]> Date: Tue, 6 Jan 2026 19:08:09 +0100 Subject: [PATCH 24/29] [lldb] [disassembler] chore: add variable annotator to scripting api: remove unused protected methods Signed-off-by: Nikita B <[email protected]> --- lldb/source/API/SBVariableAnnotator.cpp | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/lldb/source/API/SBVariableAnnotator.cpp b/lldb/source/API/SBVariableAnnotator.cpp index 1df8c11fef181..06d33e2ceb8b3 100644 --- a/lldb/source/API/SBVariableAnnotator.cpp +++ b/lldb/source/API/SBVariableAnnotator.cpp @@ -108,19 +108,3 @@ SBVariableAnnotator::AnnotateStructured(SBInstruction inst) { } return result; } - -SBVariableAnnotator::SBVariableAnnotator( - const lldb::VariableAnnotatorSP &annotator_sp) - : m_opaque_sp(annotator_sp) { - LLDB_INSTRUMENT_VA(this, annotator_sp); -} - -lldb::VariableAnnotatorSP SBVariableAnnotator::GetSP() const { - LLDB_INSTRUMENT_VA(this); - return m_opaque_sp; -} - -void SBVariableAnnotator::SetSP(const lldb::VariableAnnotatorSP &annotator_sp) { - LLDB_INSTRUMENT_VA(this, annotator_sp); - m_opaque_sp = annotator_sp; -} >From fd5befc36270a5b300a8bee72ad11d5a7a48ffe3 Mon Sep 17 00:00:00 2001 From: Nikita B <[email protected]> Date: Tue, 6 Jan 2026 19:23:35 +0100 Subject: [PATCH 25/29] [lldb] [disassembler] chore: add variable annotator to scripting api: some minor updates to Docstrings.i description Signed-off-by: Nikita B <[email protected]> --- .../interface/SBVariableAnnotatorDocstrings.i | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/lldb/bindings/interface/SBVariableAnnotatorDocstrings.i b/lldb/bindings/interface/SBVariableAnnotatorDocstrings.i index 9f3b4c4b514db..2bc5a07e2cd83 100644 --- a/lldb/bindings/interface/SBVariableAnnotatorDocstrings.i +++ b/lldb/bindings/interface/SBVariableAnnotatorDocstrings.i @@ -3,9 +3,8 @@ The SBVariableAnnotator class enables retrieval of structured variable location information for assembly instructions during debugging. This -allows tools to understand where variables are stored (registers, memory) -at specific instruction addresses, which is essential for debugging -optimized code where variables may move between locations. +allows to understand where variables are stored (registers, memory) +at specific instruction addresses. The annotator extracts DWARF debug information to provide: * Variable names and types @@ -13,30 +12,29 @@ The annotator extracts DWARF debug information to provide: * Address ranges where the location is valid * Source declaration information -For example, when debugging optimized code:: +For example, when debugging optimized code: annotator = lldb.SBVariableAnnotator() target = lldb.debugger.GetSelectedTarget() frame = target.GetProcess().GetSelectedThread().GetSelectedFrame() - # Get instructions for current function + # Get instructions for current function. function = frame.GetFunction() instructions = target.ReadInstructions(function.GetStartAddress(), function.GetEndAddress()) - # Annotate each instruction + # Annotate each instruction. for i in range(instructions.GetSize()): inst = instructions.GetInstructionAtIndex(i) annotations = annotator.AnnotateStructured(inst) - # Process structured annotation data + # Process structured annotation data. for j in range(annotations.GetSize()): item = annotations.GetItemAtIndex(j) var_name = item.GetValueForKey('variable_name').GetStringValue(1024) location = item.GetValueForKey('location_description').GetStringValue(1024) - is_live = item.GetValueForKey('is_live').GetBooleanValue() - print(f'Variable {var_name} in {location}, live: {is_live}')" + print(f'Variable {var_name} in {location}')" ) lldb::SBVariableAnnotator; %feature("docstring", " >From 8ddc09c04b690d94562fa91769974330d6208d21 Mon Sep 17 00:00:00 2001 From: Nikita B <[email protected]> Date: Tue, 6 Jan 2026 20:50:06 +0100 Subject: [PATCH 26/29] [lldb] [disassembler] chore: add variable annotator to scripting api: remove lldb from Extensions.i Signed-off-by: Nikita B <[email protected]> --- lldb/bindings/interface/SBVariableAnnotatorExtensions.i | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/bindings/interface/SBVariableAnnotatorExtensions.i b/lldb/bindings/interface/SBVariableAnnotatorExtensions.i index a0e940e7f17af..582be364ec14b 100644 --- a/lldb/bindings/interface/SBVariableAnnotatorExtensions.i +++ b/lldb/bindings/interface/SBVariableAnnotatorExtensions.i @@ -19,7 +19,7 @@ STRING_EXTENSION_OUTSIDE(SBVariableAnnotator) annotations = [] for i in range(structured_data.GetSize()): item = structured_data.GetItemAtIndex(i) - if item.GetType() != lldb.eStructuredDataTypeDictionary: + if item.GetType() != eStructuredDataTypeDictionary: continue annotation = {} >From 9c270c4bf693375084a4545b41f3cee9b45d40ab Mon Sep 17 00:00:00 2001 From: Nikita B <[email protected]> Date: Tue, 6 Jan 2026 20:57:04 +0100 Subject: [PATCH 27/29] [lldb] [disassembler] chore: add variable annotator to scripting api: update test to use get_annotations_list python friendly wrapper Signed-off-by: Nikita B <[email protected]> --- .../TestVariableAnnotationsDisassembler.py | 93 +++++-------------- 1 file changed, 23 insertions(+), 70 deletions(-) diff --git a/lldb/test/API/functionalities/disassembler-variables/TestVariableAnnotationsDisassembler.py b/lldb/test/API/functionalities/disassembler-variables/TestVariableAnnotationsDisassembler.py index c894d0e2559de..0def625f4b4d9 100644 --- a/lldb/test/API/functionalities/disassembler-variables/TestVariableAnnotationsDisassembler.py +++ b/lldb/test/API/functionalities/disassembler-variables/TestVariableAnnotationsDisassembler.py @@ -120,7 +120,7 @@ def test_seed_reg_const_undef(self): @no_debug_info_test @skipIf(archs=no_match(["x86_64"])) def test_structured_annotations_api(self): - """Test SBVariableAnnotator::AnnotateStructured API returns structured data""" + """Test SBVariableAnnotator.get_annotations_list() Python API.""" obj = self._build_obj("d_original_example.o") target = self._create_target(obj) @@ -139,7 +139,7 @@ def test_structured_annotations_api(self): if self.TraceOn(): print( - f"\nTesting SBVariableAnnotator::AnnotateStructured API on {instructions.GetSize()} instructions" + f"\nTesting SBVariableAnnotator.get_annotations_list() on {instructions.GetSize()} instructions" ) expected_vars = ["argc", "argv", "i"] @@ -147,7 +147,6 @@ def test_structured_annotations_api(self): annotator = lldb.SBVariableAnnotator() # Track current state of variables across instructions. - active_vars = {} # var_name -> location_description. found_variables = set() # Test each instruction. @@ -155,59 +154,31 @@ def test_structured_annotations_api(self): inst = instructions.GetInstructionAtIndex(i) self.assertTrue(inst.IsValid(), f"Invalid instruction at index {i}") - # TODO: use get_annotations_list from Extensions.i. - # Get annotations (may be empty if nothing changed). - annotations = annotator.AnnotateStructured(inst) + # Get annotations as Python list of dicts (may be empty if nothing changed). + annotations = annotator.get_annotations_list(inst) - self.assertIsInstance( - annotations, - lldb.SBStructuredData, - "AnnotateStructured should return SBStructuredData", - ) - - # Process changes. - for j in range(annotations.GetSize()): - ann = annotations.GetItemAtIndex(j) - self.assertTrue(ann.IsValid(), f"Invalid annotation at index {j}") - - self.assertEqual( - ann.GetType(), - lldb.eStructuredDataTypeDictionary, - "Each annotation should be a dictionary", - ) - - # Validate all required fields are present. - var_name_obj = ann.GetValueForKey("variable_name") - self.assertTrue( - var_name_obj.IsValid(), "Missing 'variable_name' field" - ) - - location_obj = ann.GetValueForKey("location_description") - self.assertTrue( - location_obj.IsValid(), "Missing 'location_description' field" - ) + for ann in annotations: + # Validate required fields are present. + self.assertIn("variable_name", ann, "Missing 'variable_name' field") + self.assertIn("location_description", ann, "Missing 'location_description' field") + self.assertIn("is_live", ann, "Missing 'is_live' field") + self.assertIn("start_address", ann, "Missing 'start_address' field") + self.assertIn("end_address", ann, "Missing 'end_address' field") + self.assertIn("register_kind", ann, "Missing 'register_kind' field") - is_live_obj = ann.GetValueForKey("is_live") - self.assertTrue(is_live_obj.IsValid(), "Missing 'is_live' field") + var_name = ann["variable_name"] - start_addr_obj = ann.GetValueForKey("start_address") - self.assertTrue( - start_addr_obj.IsValid(), "Missing 'start_address' field" - ) + # Validate types and values. + self.assertIsInstance(var_name, str, "variable_name should be string") + self.assertIsInstance(ann["location_description"], str, "location_description should be string") + self.assertIsInstance(ann["is_live"], bool, "is_live should be boolean") + self.assertIsInstance(ann["start_address"], int, "start_address should be integer") + self.assertIsInstance(ann["end_address"], int, "end_address should be integer") + self.assertIsInstance(ann["register_kind"], int, "register_kind should be integer") - end_addr_obj = ann.GetValueForKey("end_address") - self.assertTrue( - end_addr_obj.IsValid(), "Missing 'end_address' field" - ) - - register_kind_obj = ann.GetValueForKey("register_kind") - self.assertTrue( - register_kind_obj.IsValid(), "Missing 'register_kind' field" - ) - - var_name = var_name_obj.GetStringValue(1024) - location = location_obj.GetStringValue(1024) - is_live = is_live_obj.GetBooleanValue() + self.assertGreater(len(var_name), 0, "variable_name should not be empty") + self.assertGreater(len(ann["location_description"]), 0, "location_description should not be empty") + self.assertGreater(ann["end_address"], ann["start_address"], "end_address should be > start_address") self.assertIn( var_name, expected_vars, f"Unexpected variable name: {var_name}" @@ -215,24 +186,6 @@ def test_structured_annotations_api(self): found_variables.add(var_name) - # Update tracking state. - if location == "undef" or not is_live: - # Variable went away. - if var_name in active_vars: - if self.TraceOn(): - print(f" [{i:2d}] {var_name}: {active_vars[var_name]} -> undef") - active_vars.pop(var_name) - else: - # Variable newly live or location changed. - old_location = active_vars.get(var_name) - if old_location != location: - if self.TraceOn(): - if old_location is None: - print(f" [{i:2d}] {var_name}: -> {location} (newly live)") - else: - print(f" [{i:2d}] {var_name}: {old_location} -> {location} (changed)") - active_vars[var_name] = location - # Validate we find all expected variables. self.assertEqual( found_variables, >From dc09acc9197b1fd57b6aae5e7509404c68732070 Mon Sep 17 00:00:00 2001 From: Nikita B <[email protected]> Date: Tue, 6 Jan 2026 21:12:42 +0100 Subject: [PATCH 28/29] [lldb] [disassembler] chore: add variable annotator to scripting api: black formatting Signed-off-by: Nikita B <[email protected]> --- .../TestVariableAnnotationsDisassembler.py | 40 ++++++++++++++----- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/lldb/test/API/functionalities/disassembler-variables/TestVariableAnnotationsDisassembler.py b/lldb/test/API/functionalities/disassembler-variables/TestVariableAnnotationsDisassembler.py index 0def625f4b4d9..19889fbbe0bef 100644 --- a/lldb/test/API/functionalities/disassembler-variables/TestVariableAnnotationsDisassembler.py +++ b/lldb/test/API/functionalities/disassembler-variables/TestVariableAnnotationsDisassembler.py @@ -160,7 +160,9 @@ def test_structured_annotations_api(self): for ann in annotations: # Validate required fields are present. self.assertIn("variable_name", ann, "Missing 'variable_name' field") - self.assertIn("location_description", ann, "Missing 'location_description' field") + self.assertIn( + "location_description", ann, "Missing 'location_description' field" + ) self.assertIn("is_live", ann, "Missing 'is_live' field") self.assertIn("start_address", ann, "Missing 'start_address' field") self.assertIn("end_address", ann, "Missing 'end_address' field") @@ -170,15 +172,35 @@ def test_structured_annotations_api(self): # Validate types and values. self.assertIsInstance(var_name, str, "variable_name should be string") - self.assertIsInstance(ann["location_description"], str, "location_description should be string") + self.assertIsInstance( + ann["location_description"], + str, + "location_description should be string", + ) self.assertIsInstance(ann["is_live"], bool, "is_live should be boolean") - self.assertIsInstance(ann["start_address"], int, "start_address should be integer") - self.assertIsInstance(ann["end_address"], int, "end_address should be integer") - self.assertIsInstance(ann["register_kind"], int, "register_kind should be integer") + self.assertIsInstance( + ann["start_address"], int, "start_address should be integer" + ) + self.assertIsInstance( + ann["end_address"], int, "end_address should be integer" + ) + self.assertIsInstance( + ann["register_kind"], int, "register_kind should be integer" + ) - self.assertGreater(len(var_name), 0, "variable_name should not be empty") - self.assertGreater(len(ann["location_description"]), 0, "location_description should not be empty") - self.assertGreater(ann["end_address"], ann["start_address"], "end_address should be > start_address") + self.assertGreater( + len(var_name), 0, "variable_name should not be empty" + ) + self.assertGreater( + len(ann["location_description"]), + 0, + "location_description should not be empty", + ) + self.assertGreater( + ann["end_address"], + ann["start_address"], + "end_address should be > start_address", + ) self.assertIn( var_name, expected_vars, f"Unexpected variable name: {var_name}" @@ -190,7 +212,7 @@ def test_structured_annotations_api(self): self.assertEqual( found_variables, set(expected_vars), - f"Did not find all expected variables. Expected: {expected_vars}, find: {found_variables}" + f"Did not find all expected variables. Expected: {expected_vars}, find: {found_variables}", ) if self.TraceOn(): >From 21f7b3b67c05cd38ccf9375fc4ba7ff14842574d Mon Sep 17 00:00:00 2001 From: Nikita B <[email protected]> Date: Wed, 7 Jan 2026 18:55:27 +0100 Subject: [PATCH 29/29] [lldb] [disassembler] chore: add variable annotator to scripting api: Docstrings update Signed-off-by: Nikita B <[email protected]> --- lldb/bindings/interface/SBVariableAnnotatorDocstrings.i | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lldb/bindings/interface/SBVariableAnnotatorDocstrings.i b/lldb/bindings/interface/SBVariableAnnotatorDocstrings.i index 2bc5a07e2cd83..de0aa4c051f73 100644 --- a/lldb/bindings/interface/SBVariableAnnotatorDocstrings.i +++ b/lldb/bindings/interface/SBVariableAnnotatorDocstrings.i @@ -12,7 +12,7 @@ The annotator extracts DWARF debug information to provide: * Address ranges where the location is valid * Source declaration information -For example, when debugging optimized code: +For example: annotator = lldb.SBVariableAnnotator() target = lldb.debugger.GetSelectedTarget() @@ -63,7 +63,7 @@ lldb::SBVariableAnnotator::SBVariableAnnotator; * 'type_name' (string): Type name of the variable (optional) Args: - inst: SBInstruction object to annotate + inst: SBInstruction object Returns: SBStructuredData containing variable annotation array, or invalid _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
