From a436c3faf4017b0c84b45046f6eedef9229d3e1d Mon Sep 17 00:00:00 2001 From: Miro Bucko Date: Fri, 10 May 2024 12:42:03 -0700 Subject: [PATCH] Add AddressRange to SB API Summary: This adds new SB API calls and classes to allow a user of the SB API to obtain an address range from SBFunction and SBBlock. Test Plan: llvm-lit -sv llvm-project/lldb/test/API/python_api/address_range/TestAddressRange.py Reviewers: clayborg Subscribers: lldb-commits Tasks: Tags: --- lldb/bindings/headers.swig | 2 + .../interface/SBAddressRangeDocstrings.i | 3 + .../interface/SBAddressRangeExtensions.i | 11 + .../interface/SBAddressRangeListDocstrings.i | 3 + .../interface/SBAddressRangeListExtensions.i | 29 ++ lldb/bindings/interfaces.swig | 6 + lldb/include/lldb/API/LLDB.h | 2 + lldb/include/lldb/API/SBAddress.h | 1 + lldb/include/lldb/API/SBAddressRange.h | 66 +++++ lldb/include/lldb/API/SBAddressRangeList.h | 54 ++++ lldb/include/lldb/API/SBBlock.h | 4 + lldb/include/lldb/API/SBDefines.h | 2 + lldb/include/lldb/API/SBFunction.h | 3 + lldb/include/lldb/API/SBStream.h | 2 + lldb/include/lldb/API/SBTarget.h | 1 + lldb/include/lldb/Core/AddressRange.h | 14 + lldb/include/lldb/Core/AddressRangeListImpl.h | 51 ++++ lldb/include/lldb/Symbol/Block.h | 2 + lldb/include/lldb/lldb-forward.h | 3 + lldb/source/API/CMakeLists.txt | 2 + lldb/source/API/SBAddressRange.cpp | 103 +++++++ lldb/source/API/SBAddressRangeList.cpp | 94 +++++++ lldb/source/API/SBBlock.cpp | 10 + lldb/source/API/SBFunction.cpp | 14 + lldb/source/Core/AddressRange.cpp | 43 +++ lldb/source/Core/AddressRangeListImpl.cpp | 50 ++++ lldb/source/Core/CMakeLists.txt | 1 + lldb/source/Symbol/Block.cpp | 16 ++ .../API/python_api/address_range/Makefile | 3 + .../address_range/TestAddressRange.py | 256 ++++++++++++++++++ .../API/python_api/address_range/main.cpp | 8 + 31 files changed, 859 insertions(+) create mode 100644 lldb/bindings/interface/SBAddressRangeDocstrings.i create mode 100644 lldb/bindings/interface/SBAddressRangeExtensions.i create mode 100644 lldb/bindings/interface/SBAddressRangeListDocstrings.i create mode 100644 lldb/bindings/interface/SBAddressRangeListExtensions.i create mode 100644 lldb/include/lldb/API/SBAddressRange.h create mode 100644 lldb/include/lldb/API/SBAddressRangeList.h create mode 100644 lldb/include/lldb/Core/AddressRangeListImpl.h create mode 100644 lldb/source/API/SBAddressRange.cpp create mode 100644 lldb/source/API/SBAddressRangeList.cpp create mode 100644 lldb/source/Core/AddressRangeListImpl.cpp create mode 100644 lldb/test/API/python_api/address_range/Makefile create mode 100644 lldb/test/API/python_api/address_range/TestAddressRange.py create mode 100644 lldb/test/API/python_api/address_range/main.cpp diff --git a/lldb/bindings/headers.swig b/lldb/bindings/headers.swig index ffdc3c31ec883..c91504604b6ac 100644 --- a/lldb/bindings/headers.swig +++ b/lldb/bindings/headers.swig @@ -8,6 +8,8 @@ %{ #include "lldb/lldb-public.h" #include "lldb/API/SBAddress.h" +#include "lldb/API/SBAddressRange.h" +#include "lldb/API/SBAddressRangeList.h" #include "lldb/API/SBAttachInfo.h" #include "lldb/API/SBBlock.h" #include "lldb/API/SBBreakpoint.h" diff --git a/lldb/bindings/interface/SBAddressRangeDocstrings.i b/lldb/bindings/interface/SBAddressRangeDocstrings.i new file mode 100644 index 0000000000000..650195704d73e --- /dev/null +++ b/lldb/bindings/interface/SBAddressRangeDocstrings.i @@ -0,0 +1,3 @@ +%feature("docstring", +"API clients can get address range information." +) lldb::SBAddressRange; diff --git a/lldb/bindings/interface/SBAddressRangeExtensions.i b/lldb/bindings/interface/SBAddressRangeExtensions.i new file mode 100644 index 0000000000000..31bcfcb64590b --- /dev/null +++ b/lldb/bindings/interface/SBAddressRangeExtensions.i @@ -0,0 +1,11 @@ +%extend lldb::SBAddressRange { +#ifdef SWIGPYTHON + %pythoncode%{ + def __repr__(self): + import lldb + stream = lldb.SBStream() + self.GetDescription(stream, lldb.target if lldb.target else lldb.SBTarget()) + return stream.GetData() + %} +#endif +} diff --git a/lldb/bindings/interface/SBAddressRangeListDocstrings.i b/lldb/bindings/interface/SBAddressRangeListDocstrings.i new file mode 100644 index 0000000000000..e4b96b9ca5931 --- /dev/null +++ b/lldb/bindings/interface/SBAddressRangeListDocstrings.i @@ -0,0 +1,3 @@ +%feature("docstring", +"Represents a list of :py:class:`SBAddressRange`." +) lldb::SBAddressRangeList; diff --git a/lldb/bindings/interface/SBAddressRangeListExtensions.i b/lldb/bindings/interface/SBAddressRangeListExtensions.i new file mode 100644 index 0000000000000..e281a84d73d27 --- /dev/null +++ b/lldb/bindings/interface/SBAddressRangeListExtensions.i @@ -0,0 +1,29 @@ +%extend lldb::SBAddressRangeList { +#ifdef SWIGPYTHON + %pythoncode%{ + def __len__(self): + '''Return the number of address ranges in a lldb.SBAddressRangeList object.''' + return self.GetSize() + + def __iter__(self): + '''Iterate over all the address ranges in a lldb.SBAddressRangeList object.''' + return lldb_iter(self, 'GetSize', 'GetAddressRangeAtIndex') + + def __getitem__(self, idx): + '''Get the address range at a given index in an lldb.SBAddressRangeList object.''' + if not isinstance(idx, int): + raise TypeError("unsupported index type: %s" % type(idx)) + count = len(self) + if not (-count <= idx < count): + raise IndexError("list index out of range") + idx %= count + return self.GetAddressRangeAtIndex(idx) + + def __repr__(self): + import lldb + stream = lldb.SBStream() + self.GetDescription(stream, lldb.target if lldb.target else lldb.SBTarget()) + return stream.GetData() + %} +#endif +} diff --git a/lldb/bindings/interfaces.swig b/lldb/bindings/interfaces.swig index 2a29a8dd7ef0b..0953f4c72a910 100644 --- a/lldb/bindings/interfaces.swig +++ b/lldb/bindings/interfaces.swig @@ -12,6 +12,8 @@ /* Docstrings for SB classes and methods */ %include "./interface/SBAddressDocstrings.i" +%include "./interface/SBAddressRangeDocstrings.i" +%include "./interface/SBAddressRangeListDocstrings.i" %include "./interface/SBAttachInfoDocstrings.i" %include "./interface/SBBlockDocstrings.i" %include "./interface/SBBreakpointDocstrings.i" @@ -86,6 +88,8 @@ /* API headers */ %include "lldb/API/SBAddress.h" +%include "lldb/API/SBAddressRange.h" +%include "lldb/API/SBAddressRangeList.h" %include "lldb/API/SBAttachInfo.h" %include "lldb/API/SBBlock.h" %include "lldb/API/SBBreakpoint.h" @@ -163,6 +167,8 @@ /* Extensions for SB classes */ %include "./interface/SBAddressExtensions.i" +%include "./interface/SBAddressRangeExtensions.i" +%include "./interface/SBAddressRangeListExtensions.i" %include "./interface/SBBlockExtensions.i" %include "./interface/SBBreakpointExtensions.i" %include "./interface/SBBreakpointListExtensions.i" diff --git a/lldb/include/lldb/API/LLDB.h b/lldb/include/lldb/API/LLDB.h index b256544326a22..d8cc9f5067fe9 100644 --- a/lldb/include/lldb/API/LLDB.h +++ b/lldb/include/lldb/API/LLDB.h @@ -10,6 +10,8 @@ #define LLDB_API_LLDB_H #include "lldb/API/SBAddress.h" +#include "lldb/API/SBAddressRange.h" +#include "lldb/API/SBAddressRangeList.h" #include "lldb/API/SBAttachInfo.h" #include "lldb/API/SBBlock.h" #include "lldb/API/SBBreakpoint.h" diff --git a/lldb/include/lldb/API/SBAddress.h b/lldb/include/lldb/API/SBAddress.h index 5e5f355ccc390..430dad4862dbf 100644 --- a/lldb/include/lldb/API/SBAddress.h +++ b/lldb/include/lldb/API/SBAddress.h @@ -86,6 +86,7 @@ class LLDB_API SBAddress { lldb::SBLineEntry GetLineEntry(); protected: + friend class SBAddressRange; friend class SBBlock; friend class SBBreakpoint; friend class SBBreakpointLocation; diff --git a/lldb/include/lldb/API/SBAddressRange.h b/lldb/include/lldb/API/SBAddressRange.h new file mode 100644 index 0000000000000..152bd82426af1 --- /dev/null +++ b/lldb/include/lldb/API/SBAddressRange.h @@ -0,0 +1,66 @@ +//===-- SBAddressRange.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_SBADDRESSRANGE_H +#define LLDB_API_SBADDRESSRANGE_H + +#include "lldb/API/SBDefines.h" + +namespace lldb { + +class LLDB_API SBAddressRange { +public: + SBAddressRange(); + + SBAddressRange(const lldb::SBAddressRange &rhs); + + SBAddressRange(lldb::SBAddress addr, lldb::addr_t byte_size); + + ~SBAddressRange(); + + const lldb::SBAddressRange &operator=(const lldb::SBAddressRange &rhs); + + void Clear(); + + /// Check the address range refers to a valid base address and has a byte + /// size greater than zero. + /// + /// \return + /// True if the address range is valid, false otherwise. + bool IsValid() const; + + /// Get the base address of the range. + /// + /// \return + /// Base address object. + lldb::SBAddress GetBaseAddress() const; + + /// Get the byte size of this range. + /// + /// \return + /// The size in bytes of this address range. + lldb::addr_t GetByteSize() const; + + bool operator==(const SBAddressRange &rhs); + + bool operator!=(const SBAddressRange &rhs); + + bool GetDescription(lldb::SBStream &description, const SBTarget target); + +private: + friend class SBAddressRangeList; + friend class SBBlock; + friend class SBFunction; + friend class SBProcess; + + AddressRangeUP m_opaque_up; +}; + +} // namespace lldb + +#endif // LLDB_API_SBADDRESSRANGE_H diff --git a/lldb/include/lldb/API/SBAddressRangeList.h b/lldb/include/lldb/API/SBAddressRangeList.h new file mode 100644 index 0000000000000..a123287ef1b4f --- /dev/null +++ b/lldb/include/lldb/API/SBAddressRangeList.h @@ -0,0 +1,54 @@ +//===-- SBAddressRangeList.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_SBADDRESSRANGELIST_H +#define LLDB_API_SBADDRESSRANGELIST_H + +#include + +#include "lldb/API/SBDefines.h" + +namespace lldb_private { +class AddressRangeListImpl; +} + +namespace lldb { + +class LLDB_API SBAddressRangeList { +public: + SBAddressRangeList(); + + SBAddressRangeList(const lldb::SBAddressRangeList &rhs); + + ~SBAddressRangeList(); + + const lldb::SBAddressRangeList & + operator=(const lldb::SBAddressRangeList &rhs); + + uint32_t GetSize() const; + + void Clear(); + + SBAddressRange GetAddressRangeAtIndex(uint64_t idx); + + void Append(const lldb::SBAddressRange &addr_range); + + void Append(const lldb::SBAddressRangeList &addr_range_list); + + bool GetDescription(lldb::SBStream &description, const SBTarget &target); + +private: + friend class SBBlock; + friend class SBProcess; + + std::unique_ptr m_opaque_up; +}; + +} // namespace lldb + +#endif // LLDB_API_SBADDRESSRANGELIST_H diff --git a/lldb/include/lldb/API/SBBlock.h b/lldb/include/lldb/API/SBBlock.h index 2570099f7652f..de4bb22be2692 100644 --- a/lldb/include/lldb/API/SBBlock.h +++ b/lldb/include/lldb/API/SBBlock.h @@ -9,6 +9,8 @@ #ifndef LLDB_API_SBBLOCK_H #define LLDB_API_SBBLOCK_H +#include "lldb/API/SBAddressRange.h" +#include "lldb/API/SBAddressRangeList.h" #include "lldb/API/SBDefines.h" #include "lldb/API/SBFrame.h" #include "lldb/API/SBTarget.h" @@ -52,6 +54,8 @@ class LLDB_API SBBlock { lldb::SBAddress GetRangeEndAddress(uint32_t idx); + lldb::SBAddressRangeList GetRanges(); + uint32_t GetRangeIndexForBlockAddress(lldb::SBAddress block_addr); lldb::SBValueList GetVariables(lldb::SBFrame &frame, bool arguments, diff --git a/lldb/include/lldb/API/SBDefines.h b/lldb/include/lldb/API/SBDefines.h index 1181920677b46..87c0a1c3661ca 100644 --- a/lldb/include/lldb/API/SBDefines.h +++ b/lldb/include/lldb/API/SBDefines.h @@ -43,6 +43,8 @@ namespace lldb { class LLDB_API SBAddress; +class LLDB_API SBAddressRange; +class LLDB_API SBAddressRangeList; class LLDB_API SBAttachInfo; class LLDB_API SBBlock; class LLDB_API SBBreakpoint; diff --git a/lldb/include/lldb/API/SBFunction.h b/lldb/include/lldb/API/SBFunction.h index 71b372a818e4b..df607fdc7ebf5 100644 --- a/lldb/include/lldb/API/SBFunction.h +++ b/lldb/include/lldb/API/SBFunction.h @@ -10,6 +10,7 @@ #define LLDB_API_SBFUNCTION_H #include "lldb/API/SBAddress.h" +#include "lldb/API/SBAddressRangeList.h" #include "lldb/API/SBDefines.h" #include "lldb/API/SBInstructionList.h" @@ -44,6 +45,8 @@ class LLDB_API SBFunction { lldb::SBAddress GetEndAddress(); + lldb::SBAddressRangeList GetRanges(); + const char *GetArgumentName(uint32_t arg_idx); uint32_t GetPrologueByteSize(); diff --git a/lldb/include/lldb/API/SBStream.h b/lldb/include/lldb/API/SBStream.h index 0e33f05b69916..71caf41fd7549 100644 --- a/lldb/include/lldb/API/SBStream.h +++ b/lldb/include/lldb/API/SBStream.h @@ -62,6 +62,8 @@ class LLDB_API SBStream { protected: friend class SBAddress; + friend class SBAddressRange; + friend class SBAddressRangeList; friend class SBBlock; friend class SBBreakpoint; friend class SBBreakpointLocation; diff --git a/lldb/include/lldb/API/SBTarget.h b/lldb/include/lldb/API/SBTarget.h index feeaa1cb71132..35c2ed9c20a23 100644 --- a/lldb/include/lldb/API/SBTarget.h +++ b/lldb/include/lldb/API/SBTarget.h @@ -943,6 +943,7 @@ class LLDB_API SBTarget { protected: friend class SBAddress; + friend class SBAddressRange; friend class SBBlock; friend class SBBreakpoint; friend class SBBreakpointList; diff --git a/lldb/include/lldb/Core/AddressRange.h b/lldb/include/lldb/Core/AddressRange.h index 4a33c2d795876..68a3ad0edd2d7 100644 --- a/lldb/include/lldb/Core/AddressRange.h +++ b/lldb/include/lldb/Core/AddressRange.h @@ -86,6 +86,8 @@ class AddressRange { /// (LLDB_INVALID_ADDRESS) and a zero byte size. void Clear(); + bool IsValid() const; + /// Check if a section offset address is contained in this range. /// /// \param[in] so_addr @@ -236,12 +238,24 @@ class AddressRange { /// The new size in bytes of this address range. void SetByteSize(lldb::addr_t byte_size) { m_byte_size = byte_size; } + bool GetDescription(Stream *s, Target *target) const; + + bool operator==(const AddressRange &rhs); + + bool operator!=(const AddressRange &rhs); + protected: // Member variables Address m_base_addr; ///< The section offset base address of this range. lldb::addr_t m_byte_size = 0; ///< The size in bytes of this address range. }; +// Forward-declarable wrapper. +class AddressRanges : public std::vector { +public: + using std::vector::vector; +}; + } // namespace lldb_private #endif // LLDB_CORE_ADDRESSRANGE_H diff --git a/lldb/include/lldb/Core/AddressRangeListImpl.h b/lldb/include/lldb/Core/AddressRangeListImpl.h new file mode 100644 index 0000000000000..46ebfe73d4d92 --- /dev/null +++ b/lldb/include/lldb/Core/AddressRangeListImpl.h @@ -0,0 +1,51 @@ +//===-- AddressRangeListImpl.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_CORE_ADDRESSRANGELISTIMPL_H +#define LLDB_CORE_ADDRESSRANGELISTIMPL_H + +#include "lldb/Core/AddressRange.h" +#include + +namespace lldb { +class SBBlock; +} + +namespace lldb_private { + +class AddressRangeListImpl { +public: + AddressRangeListImpl(); + + AddressRangeListImpl(const AddressRangeListImpl &rhs) = default; + + AddressRangeListImpl &operator=(const AddressRangeListImpl &rhs); + + size_t GetSize() const; + + void Reserve(size_t capacity); + + void Append(const AddressRange &sb_region); + + void Append(const AddressRangeListImpl &list); + + void Clear(); + + lldb_private::AddressRange GetAddressRangeAtIndex(size_t index); + +private: + friend class lldb::SBBlock; + + AddressRanges &ref(); + + AddressRanges m_ranges; +}; + +} // namespace lldb_private + +#endif // LLDB_CORE_ADDRESSRANGE_H diff --git a/lldb/include/lldb/Symbol/Block.h b/lldb/include/lldb/Symbol/Block.h index 02fd2add53103..c9c4d5ad767d7 100644 --- a/lldb/include/lldb/Symbol/Block.h +++ b/lldb/include/lldb/Symbol/Block.h @@ -355,6 +355,8 @@ class Block : public UserID, public SymbolContextScope { // be able to get at any of the address ranges in a block. bool GetRangeAtIndex(uint32_t range_idx, AddressRange &range); + AddressRanges GetRanges(); + bool GetStartAddress(Address &addr); void SetDidParseVariables(bool b, bool set_children); diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h index 10ba921b9dac8..6d880b4da03c9 100644 --- a/lldb/include/lldb/lldb-forward.h +++ b/lldb/include/lldb/lldb-forward.h @@ -19,6 +19,8 @@ class ASTResultSynthesizer; class ASTStructExtractor; class Address; class AddressRange; +class AddressRanges; +class AddressRangeList; class AddressResolver; class ArchSpec; class Architecture; @@ -308,6 +310,7 @@ template class StreamBuffer; namespace lldb { typedef std::shared_ptr ABISP; +typedef std::unique_ptr AddressRangeUP; typedef std::shared_ptr BatonSP; typedef std::shared_ptr BlockSP; typedef std::shared_ptr BreakpointSP; diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt index e8228afe103f9..6397101609315 100644 --- a/lldb/source/API/CMakeLists.txt +++ b/lldb/source/API/CMakeLists.txt @@ -42,6 +42,8 @@ set_target_properties(lldb-sbapi-dwarf-enums PROPERTIES FOLDER "LLDB/Tablegennin add_lldb_library(liblldb SHARED ${option_framework} SBAddress.cpp + SBAddressRange.cpp + SBAddressRangeList.cpp SBAttachInfo.cpp SBBlock.cpp SBBreakpoint.cpp diff --git a/lldb/source/API/SBAddressRange.cpp b/lldb/source/API/SBAddressRange.cpp new file mode 100644 index 0000000000000..9b1affdade439 --- /dev/null +++ b/lldb/source/API/SBAddressRange.cpp @@ -0,0 +1,103 @@ +//===-- SBAddressRange.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/SBAddressRange.h" +#include "Utils.h" +#include "lldb/API/SBAddress.h" +#include "lldb/API/SBStream.h" +#include "lldb/API/SBTarget.h" +#include "lldb/Core/AddressRange.h" +#include "lldb/Core/Section.h" +#include "lldb/Utility/Instrumentation.h" +#include "lldb/Utility/Stream.h" +#include +#include + +using namespace lldb; +using namespace lldb_private; + +SBAddressRange::SBAddressRange() + : m_opaque_up(std::make_unique()) { + LLDB_INSTRUMENT_VA(this); +} + +SBAddressRange::SBAddressRange(const SBAddressRange &rhs) { + LLDB_INSTRUMENT_VA(this, rhs); + + m_opaque_up = clone(rhs.m_opaque_up); +} + +SBAddressRange::SBAddressRange(lldb::SBAddress addr, lldb::addr_t byte_size) + : m_opaque_up(std::make_unique(addr.ref(), byte_size)) { + LLDB_INSTRUMENT_VA(this, addr, byte_size); +} + +SBAddressRange::~SBAddressRange() = default; + +const SBAddressRange &SBAddressRange::operator=(const SBAddressRange &rhs) { + LLDB_INSTRUMENT_VA(this, rhs); + + if (this != &rhs) + m_opaque_up = clone(rhs.m_opaque_up); + return *this; +} + +bool SBAddressRange::operator==(const SBAddressRange &rhs) { + LLDB_INSTRUMENT_VA(this, rhs); + + if (!IsValid() || !rhs.IsValid()) + return false; + return m_opaque_up->operator==(*(rhs.m_opaque_up)); +} + +bool SBAddressRange::operator!=(const SBAddressRange &rhs) { + LLDB_INSTRUMENT_VA(this, rhs); + + return !(*this == rhs); +} + +void SBAddressRange::Clear() { + LLDB_INSTRUMENT_VA(this); + + m_opaque_up.reset(); +} + +bool SBAddressRange::IsValid() const { + LLDB_INSTRUMENT_VA(this); + + return m_opaque_up && m_opaque_up->IsValid(); +} + +lldb::SBAddress SBAddressRange::GetBaseAddress() const { + LLDB_INSTRUMENT_VA(this); + + if (!IsValid()) + return lldb::SBAddress(); + return lldb::SBAddress(m_opaque_up->GetBaseAddress()); +} + +lldb::addr_t SBAddressRange::GetByteSize() const { + LLDB_INSTRUMENT_VA(this); + + if (!IsValid()) + return 0; + return m_opaque_up->GetByteSize(); +} + +bool SBAddressRange::GetDescription(SBStream &description, + const SBTarget target) { + LLDB_INSTRUMENT_VA(this, description, target); + + Stream &stream = description.ref(); + if (!IsValid()) { + stream << ""; + return true; + } + m_opaque_up->GetDescription(&stream, target.GetSP().get()); + return true; +} diff --git a/lldb/source/API/SBAddressRangeList.cpp b/lldb/source/API/SBAddressRangeList.cpp new file mode 100644 index 0000000000000..20660b3ff2088 --- /dev/null +++ b/lldb/source/API/SBAddressRangeList.cpp @@ -0,0 +1,94 @@ +//===-- SBAddressRangeList.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/SBAddressRangeList.h" +#include "Utils.h" +#include "lldb/API/SBAddressRange.h" +#include "lldb/API/SBStream.h" +#include "lldb/API/SBTarget.h" +#include "lldb/Core/AddressRangeListImpl.h" +#include "lldb/Utility/Instrumentation.h" +#include "lldb/Utility/Stream.h" + +#include + +using namespace lldb; +using namespace lldb_private; + +SBAddressRangeList::SBAddressRangeList() + : m_opaque_up(std::make_unique()) { + LLDB_INSTRUMENT_VA(this); +} + +SBAddressRangeList::SBAddressRangeList(const SBAddressRangeList &rhs) + : m_opaque_up(std::make_unique(*rhs.m_opaque_up)) { + LLDB_INSTRUMENT_VA(this, rhs); +} + +SBAddressRangeList::~SBAddressRangeList() = default; + +const SBAddressRangeList & +SBAddressRangeList::operator=(const SBAddressRangeList &rhs) { + LLDB_INSTRUMENT_VA(this, rhs); + + if (this != &rhs) + *m_opaque_up = *rhs.m_opaque_up; + return *this; +} + +uint32_t SBAddressRangeList::GetSize() const { + LLDB_INSTRUMENT_VA(this); + + return m_opaque_up->GetSize(); +} + +SBAddressRange SBAddressRangeList::GetAddressRangeAtIndex(uint64_t idx) { + LLDB_INSTRUMENT_VA(this, idx); + + SBAddressRange sb_addr_range; + (*sb_addr_range.m_opaque_up) = m_opaque_up->GetAddressRangeAtIndex(idx); + return sb_addr_range; +} + +void SBAddressRangeList::Clear() { + LLDB_INSTRUMENT_VA(this); + + m_opaque_up->Clear(); +} + +void SBAddressRangeList::Append(const SBAddressRange &sb_addr_range) { + LLDB_INSTRUMENT_VA(this, sb_addr_range); + + m_opaque_up->Append(*sb_addr_range.m_opaque_up); +} + +void SBAddressRangeList::Append(const SBAddressRangeList &sb_addr_range_list) { + LLDB_INSTRUMENT_VA(this, sb_addr_range_list); + + m_opaque_up->Append(*sb_addr_range_list.m_opaque_up); +} + +bool SBAddressRangeList::GetDescription(SBStream &description, + const SBTarget &target) { + LLDB_INSTRUMENT_VA(this, description, target); + + const uint32_t num_ranges = GetSize(); + bool is_first = true; + Stream &stream = description.ref(); + stream << "["; + for (uint32_t i = 0; i < num_ranges; ++i) { + if (is_first) { + is_first = false; + } else { + stream.Printf(", "); + } + GetAddressRangeAtIndex(i).GetDescription(description, target); + } + stream << "]"; + return true; +} diff --git a/lldb/source/API/SBBlock.cpp b/lldb/source/API/SBBlock.cpp index 7d7565340836b..2577b14920f06 100644 --- a/lldb/source/API/SBBlock.cpp +++ b/lldb/source/API/SBBlock.cpp @@ -13,6 +13,7 @@ #include "lldb/API/SBStream.h" #include "lldb/API/SBValue.h" #include "lldb/Core/AddressRange.h" +#include "lldb/Core/AddressRangeListImpl.h" #include "lldb/Core/ValueObjectVariable.h" #include "lldb/Symbol/Block.h" #include "lldb/Symbol/Function.h" @@ -219,6 +220,15 @@ lldb::SBAddress SBBlock::GetRangeEndAddress(uint32_t idx) { return sb_addr; } +lldb::SBAddressRangeList SBBlock::GetRanges() { + LLDB_INSTRUMENT_VA(this); + + lldb::SBAddressRangeList sb_ranges; + if (m_opaque_ptr) + sb_ranges.m_opaque_up->ref() = m_opaque_ptr->GetRanges(); + return sb_ranges; +} + uint32_t SBBlock::GetRangeIndexForBlockAddress(lldb::SBAddress block_addr) { LLDB_INSTRUMENT_VA(this, block_addr); diff --git a/lldb/source/API/SBFunction.cpp b/lldb/source/API/SBFunction.cpp index a01c7f79bbd31..6a97352fc2c2f 100644 --- a/lldb/source/API/SBFunction.cpp +++ b/lldb/source/API/SBFunction.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "lldb/API/SBFunction.h" +#include "lldb/API/SBAddressRange.h" #include "lldb/API/SBProcess.h" #include "lldb/API/SBStream.h" #include "lldb/Core/Disassembler.h" @@ -160,6 +161,19 @@ SBAddress SBFunction::GetEndAddress() { return addr; } +lldb::SBAddressRangeList SBFunction::GetRanges() { + LLDB_INSTRUMENT_VA(this); + + lldb::SBAddressRangeList ranges; + if (m_opaque_ptr) { + lldb::SBAddressRange range; + (*range.m_opaque_up) = m_opaque_ptr->GetAddressRange(); + ranges.Append(std::move(range)); + } + + return ranges; +} + const char *SBFunction::GetArgumentName(uint32_t arg_idx) { LLDB_INSTRUMENT_VA(this, arg_idx); diff --git a/lldb/source/Core/AddressRange.cpp b/lldb/source/Core/AddressRange.cpp index 1830f2ccd47fe..6cef7e149cd20 100644 --- a/lldb/source/Core/AddressRange.cpp +++ b/lldb/source/Core/AddressRange.cpp @@ -14,6 +14,7 @@ #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/Stream.h" #include "lldb/lldb-defines.h" +#include "lldb/lldb-types.h" #include "llvm/Support/Compiler.h" @@ -145,6 +146,10 @@ void AddressRange::Clear() { m_byte_size = 0; } +bool AddressRange::IsValid() const { + return m_base_addr.IsValid() && (m_byte_size > 0); +} + bool AddressRange::Dump(Stream *s, Target *target, Address::DumpStyle style, Address::DumpStyle fallback_style) const { addr_t vmaddr = LLDB_INVALID_ADDRESS; @@ -203,3 +208,41 @@ void AddressRange::DumpDebug(Stream *s) const { static_cast(m_base_addr.GetSection().get()), m_base_addr.GetOffset(), GetByteSize()); } + +bool AddressRange::GetDescription(Stream *s, Target *target) const { + addr_t start_addr = m_base_addr.GetLoadAddress(target); + if (start_addr != LLDB_INVALID_ADDRESS) { + // We have a valid target and the address was resolved, or we have a base + // address with no section. Just print out a raw address range: [, + // ) + s->Printf("[0x%" PRIx64 "-0x%" PRIx64 ")", start_addr, + start_addr + GetByteSize()); + return true; + } + + // Either no target or the address wasn't resolved, print as + // [-) + const char *file_name = ""; + const auto section_sp = m_base_addr.GetSection(); + if (section_sp) { + if (const auto object_file = section_sp->GetObjectFile()) + file_name = object_file->GetFileSpec().GetFilename().AsCString(); + } + start_addr = m_base_addr.GetFileAddress(); + const addr_t end_addr = (start_addr == LLDB_INVALID_ADDRESS) + ? LLDB_INVALID_ADDRESS + : start_addr + GetByteSize(); + s->Printf("%s[0x%" PRIx64 "-0x%" PRIx64 ")", file_name, start_addr, end_addr); + return true; +} + +bool AddressRange::operator==(const AddressRange &rhs) { + if (!IsValid() || !rhs.IsValid()) + return false; + return m_base_addr == rhs.GetBaseAddress() && + m_byte_size == rhs.GetByteSize(); +} + +bool AddressRange::operator!=(const AddressRange &rhs) { + return !(*this == rhs); +} diff --git a/lldb/source/Core/AddressRangeListImpl.cpp b/lldb/source/Core/AddressRangeListImpl.cpp new file mode 100644 index 0000000000000..d405cf0fa3ec3 --- /dev/null +++ b/lldb/source/Core/AddressRangeListImpl.cpp @@ -0,0 +1,50 @@ +//===-- AddressRangeListImpl.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/Core/AddressRangeListImpl.h" + +using namespace lldb; +using namespace lldb_private; + +AddressRangeListImpl::AddressRangeListImpl() : m_ranges() {} + +AddressRangeListImpl & +AddressRangeListImpl::operator=(const AddressRangeListImpl &rhs) { + if (this == &rhs) + return *this; + m_ranges = rhs.m_ranges; + return *this; +} + +size_t AddressRangeListImpl::GetSize() const { return m_ranges.size(); } + +void AddressRangeListImpl::Reserve(size_t capacity) { + m_ranges.reserve(capacity); +} + +void AddressRangeListImpl::Append(const AddressRange &sb_region) { + m_ranges.emplace_back(sb_region); +} + +void AddressRangeListImpl::Append(const AddressRangeListImpl &list) { + Reserve(GetSize() + list.GetSize()); + + for (const auto &range : list.m_ranges) + Append(range); +} + +void AddressRangeListImpl::Clear() { m_ranges.clear(); } + +lldb_private::AddressRange +AddressRangeListImpl::GetAddressRangeAtIndex(size_t index) { + if (index >= GetSize()) + return AddressRange(); + return m_ranges[index]; +} + +AddressRanges &AddressRangeListImpl::ref() { return m_ranges; } diff --git a/lldb/source/Core/CMakeLists.txt b/lldb/source/Core/CMakeLists.txt index f24dbbd45a8e8..dbc620b91b1ed 100644 --- a/lldb/source/Core/CMakeLists.txt +++ b/lldb/source/Core/CMakeLists.txt @@ -20,6 +20,7 @@ endif() add_lldb_library(lldbCore Address.cpp AddressRange.cpp + AddressRangeListImpl.cpp AddressResolver.cpp AddressResolverFileLine.cpp Communication.cpp diff --git a/lldb/source/Symbol/Block.cpp b/lldb/source/Symbol/Block.cpp index 6eeabe0ff5e4d..f7d9c0d2d3306 100644 --- a/lldb/source/Symbol/Block.cpp +++ b/lldb/source/Symbol/Block.cpp @@ -314,6 +314,22 @@ bool Block::GetRangeAtIndex(uint32_t range_idx, AddressRange &range) { return false; } +AddressRanges Block::GetRanges() { + AddressRanges ranges; + Function *function = CalculateSymbolContextFunction(); + if (!function) + return ranges; + for (size_t i = 0, e = m_ranges.GetSize(); i < e; ++i) { + ranges.emplace_back(); + auto &range = ranges.back(); + const Range &vm_range = m_ranges.GetEntryRef(i); + range.GetBaseAddress() = function->GetAddressRange().GetBaseAddress(); + range.GetBaseAddress().Slide(vm_range.GetRangeBase()); + range.SetByteSize(vm_range.GetByteSize()); + } + return ranges; +} + bool Block::GetStartAddress(Address &addr) { if (m_ranges.IsEmpty()) return false; diff --git a/lldb/test/API/python_api/address_range/Makefile b/lldb/test/API/python_api/address_range/Makefile new file mode 100644 index 0000000000000..99998b20bcb05 --- /dev/null +++ b/lldb/test/API/python_api/address_range/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/test/API/python_api/address_range/TestAddressRange.py b/lldb/test/API/python_api/address_range/TestAddressRange.py new file mode 100644 index 0000000000000..8c27558af4752 --- /dev/null +++ b/lldb/test/API/python_api/address_range/TestAddressRange.py @@ -0,0 +1,256 @@ +""" +Test SBAddressRange APIs. +""" + +import lldb +from lldbsuite.test.lldbtest import * + + +class AddressRangeTestCase(TestBase): + NO_DEBUG_INFO_TESTCASE = True + + def setUp(self): + TestBase.setUp(self) + + self.build() + exe = self.getBuildArtifact("a.out") + + self.dbg.SetAsync(True) + + self.target = self.dbg.CreateTarget(exe) + self.assertTrue(self.target, VALID_TARGET) + self.launch_info = self.target.GetLaunchInfo() + self.launch_info.SetWorkingDirectory(self.get_process_working_directory()) + + self.bp1 = self.target.BreakpointCreateByName("main", "a.out") + self.bp2 = self.target.BreakpointCreateByName("foo", "a.out") + self.bp3 = self.target.BreakpointCreateByName("bar", "a.out") + + self.assertTrue(self.bp1.IsValid()) + self.assertTrue(self.bp2.IsValid()) + self.assertTrue(self.bp3.IsValid()) + + self.addr1 = self.bp1.GetLocationAtIndex(0).GetAddress() + self.addr2 = self.bp2.GetLocationAtIndex(0).GetAddress() + self.addr3 = self.bp3.GetLocationAtIndex(0).GetAddress() + + self.assertTrue(self.addr1.IsValid()) + self.assertTrue(self.addr2.IsValid()) + self.assertTrue(self.addr3.IsValid()) + + def test_address_range_default(self): + """Testing default constructor.""" + empty_range = lldb.SBAddressRange() + self.assertEqual(empty_range.IsValid(), False) + + def test_address_range_construction(self): + """Make sure the construction and getters work.""" + range = lldb.SBAddressRange(self.addr1, 8) + self.assertEqual(range.IsValid(), True) + self.assertEqual(range.GetBaseAddress(), self.addr1) + self.assertEqual(range.GetByteSize(), 8) + + def test_address_range_clear(self): + """Make sure the clear method works.""" + range = lldb.SBAddressRange(self.addr1, 8) + self.assertEqual(range.IsValid(), True) + self.assertEqual(range.GetBaseAddress(), self.addr1) + self.assertEqual(range.GetByteSize(), 8) + + range.Clear() + self.assertEqual(range.IsValid(), False) + + def test_function(self): + """Make sure the range works in SBFunction APIs.""" + + # Setup breakpoints in main + loc = self.bp1.GetLocationAtIndex(0) + loc_addr = loc.GetAddress() + func = loc_addr.GetFunction() + ranges = func.GetRanges() + self.assertEqual(ranges.GetSize(), 1) + + range = ranges.GetAddressRangeAtIndex(0) + self.assertEqual( + range.GetByteSize(), + func.GetEndAddress().GetOffset() - func.GetStartAddress().GetOffset(), + ) + self.assertEqual( + range.GetBaseAddress().GetOffset(), + func.GetStartAddress().GetOffset(), + ) + + def test_block(self): + """Make sure the range works in SBBlock APIs.""" + loc = self.bp1.GetLocationAtIndex(0) + loc_addr = loc.GetAddress() + block = loc_addr.GetBlock() + + ranges = block.GetRanges() + self.assertEqual(ranges.GetSize(), 1) + + range = ranges.GetAddressRangeAtIndex(0) + self.assertEqual( + range.GetByteSize(), + block.GetRangeEndAddress(0).GetOffset() + - block.GetRangeStartAddress(0).GetOffset(), + ) + self.assertEqual( + range.GetBaseAddress().GetOffset(), + block.GetRangeStartAddress(0).GetOffset(), + ) + + def test_address_range_list(self): + """Make sure the SBAddressRangeList works by adding and getting ranges.""" + range1 = lldb.SBAddressRange(self.addr1, 8) + range2 = lldb.SBAddressRange(self.addr2, 16) + range3 = lldb.SBAddressRange(self.addr3, 32) + + range_list = lldb.SBAddressRangeList() + self.assertEqual(range_list.GetSize(), 0) + + range_list.Append(range1) + range_list.Append(range2) + range_list.Append(range3) + self.assertEqual(range_list.GetSize(), 3) + self.assertRaises(IndexError, lambda: range_list[3]) + + range1_copy = range_list.GetAddressRangeAtIndex(0) + self.assertEqual(range1.GetByteSize(), range1_copy.GetByteSize()) + self.assertEqual( + range1.GetBaseAddress().GetOffset(), + range1_copy.GetBaseAddress().GetOffset(), + ) + + range2_copy = range_list.GetAddressRangeAtIndex(1) + self.assertEqual(range2.GetByteSize(), range2_copy.GetByteSize()) + self.assertEqual( + range2.GetBaseAddress().GetOffset(), + range2_copy.GetBaseAddress().GetOffset(), + ) + + range3_copy = range_list.GetAddressRangeAtIndex(2) + self.assertEqual(range3.GetByteSize(), range3_copy.GetByteSize()) + self.assertEqual( + range3.GetBaseAddress().GetOffset(), + range3_copy.GetBaseAddress().GetOffset(), + ) + + range_list.Clear() + self.assertEqual(range_list.GetSize(), 0) + + def test_address_range_list_len(self): + """Make sure the len() operator works.""" + range = lldb.SBAddressRange(self.addr1, 8) + + range_list = lldb.SBAddressRangeList() + self.assertEqual(len(range_list), 0) + + range_list.Append(range) + self.assertEqual(len(range_list), 1) + + def test_address_range_list_iterator(self): + """Make sure the SBAddressRangeList iterator works.""" + range1 = lldb.SBAddressRange(self.addr1, 8) + range2 = lldb.SBAddressRange(self.addr2, 16) + range3 = lldb.SBAddressRange(self.addr3, 32) + + range_list = lldb.SBAddressRangeList() + range_list.Append(range1) + range_list.Append(range2) + range_list.Append(range3) + self.assertEqual(range_list.GetSize(), 3) + + # Test the iterator + for range in range_list: + self.assertTrue(range.IsValid()) + + def test_address_range_print_invalid(self): + """Make sure the SBAddressRange can be printed when invalid.""" + range = lldb.SBAddressRange() + self.assertEqual(str(range), "") + + def test_address_range_print_resolved(self): + """Make sure the SBAddressRange can be printed when resolved.""" + lldb.target = self.target + error = lldb.SBError() + process = self.target.Launch(self.launch_info, error) + self.assertTrue(error.Success(), "Make sure process launched successfully") + self.assertTrue(process, PROCESS_IS_VALID) + self.assertState(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED) + + loc = self.bp1.GetLocationAtIndex(0) + loc_addr = loc.GetAddress() + func = loc_addr.GetFunction() + range = func.GetRanges().GetAddressRangeAtIndex(0) + range_str = str(range) + # [0x1000-0x2000] // Resolved with target or addresses without sections + self.assertRegex(range_str, "^\[0x[0-9a-f]+\-0x[0-9a-f]+\)$") + process.Kill() + + def test_address_range_print_no_section_resolved(self): + """Make sure the SBAddressRange can be printed with no secion.""" + lldb.target = self.target + error = lldb.SBError() + process = self.target.Launch(self.launch_info, error) + self.assertTrue(error.Success(), "Make sure process launched successfully") + self.assertTrue(process, PROCESS_IS_VALID) + self.assertState(process.GetState(), lldb.eStateStopped, PROCESS_STOPPED) + + loc = self.bp1.GetLocationAtIndex(0) + loc_addr = loc.GetAddress() + func = loc_addr.GetFunction() + range = func.GetRanges().GetAddressRangeAtIndex(0) + + addr = lldb.SBAddress() + addr.SetAddress(lldb.SBSection(), range.GetBaseAddress().GetOffset()) + self.assertFalse(addr.GetSection().IsValid()) + range = lldb.SBAddressRange(addr, range.GetByteSize()) + + range_str = str(range) + # [0x1000-0x2000] // Resolved with target or addresses without sections + self.assertRegex(range_str, "^\[0x[0-9a-f]+\-0x[0-9a-f]+\)$") + process.Kill() + + def test_address_range_print_not_resolved(self): + """Make sure the SBAddressRange can be printed when not resolved.""" + range = lldb.SBAddressRange(self.addr1, 8) + range_str = str(range) + # a.out[0x1000-0x2000] // Without target + self.assertRegex(range_str, "^a.out\[0x[0-9a-f]+\-0x[0-9a-f]+\)$") + + def test_address_range_list_print(self): + """Make sure the SBAddressRangeList can be printed.""" + range1 = lldb.SBAddressRange(self.addr1, 8) + range2 = lldb.SBAddressRange(self.addr2, 16) + range3 = lldb.SBAddressRange(self.addr3, 32) + self.dbg.SetAsync(True) + + range_list = lldb.SBAddressRangeList() + self.assertEqual(range_list.GetSize(), 0) + + range_list.Append(range1) + range_list.Append(range2) + range_list.Append(range3) + self.assertEqual(range_list.GetSize(), 3) + + range_list_str = str(range_list) + self.assertTrue(range_list_str.startswith("[")) + self.assertGreater(range_list_str.count(","), 1) + self.assertTrue(range_list_str.endswith("]")) + + def test_address_range_list_indexing(self): + """Make sure the SBAddressRangeList can be printed.""" + range1 = lldb.SBAddressRange(self.addr1, 8) + range2 = lldb.SBAddressRange(self.addr2, 16) + range_list = lldb.SBAddressRangeList() + range_list.Append(range1) + range_list.Append(range2) + + self.assertEqual(range_list.GetSize(), 2) + self.assertRaises(IndexError, lambda: range_list[2]) + self.assertRaises(TypeError, lambda: range_list["0"]) + self.assertEqual(range_list[0], range1) + self.assertEqual(range_list[1], range2) + self.assertEqual(range_list[-1], range2) + self.assertEqual(range_list[-2], range1) diff --git a/lldb/test/API/python_api/address_range/main.cpp b/lldb/test/API/python_api/address_range/main.cpp new file mode 100644 index 0000000000000..b6eaec4a23699 --- /dev/null +++ b/lldb/test/API/python_api/address_range/main.cpp @@ -0,0 +1,8 @@ +void foo() {} +void bar() {} + +int main() { + foo(); + bar(); + return 0; +}