[Lldb-commits] [lldb] [lldb] Add SubtargetFeatures to ArchSpec (PR #173046)
via lldb-commits
lldb-commits at lists.llvm.org
Thu Feb 5 09:27:11 PST 2026
https://github.com/daniilavdeev updated https://github.com/llvm/llvm-project/pull/173046
>From 4f2ee91216d83ca8c0eb2c85496e2cbf7f9ca992 Mon Sep 17 00:00:00 2001
From: Daniil Avdeev <daniilavdeev237 at gmail.com>
Date: Tue, 18 Nov 2025 05:23:58 +0000
Subject: [PATCH 1/3] [lldb] Add SubtargetFeatures to ArchSpec
This patch introduces SubtargetFeatures in ArchSpec to enable consistent
handling of architecture-specific extensions in LLDB. For RISCV targets
in particular, it allows LLDB to propagate target extension features
from ELF attributes to expression evaluation and disassembly.
---
lldb/include/lldb/Utility/ArchSpec.h | 11 ++
.../Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 121 ++++++++++++++++++
.../Plugins/ObjectFile/ELF/ObjectFileELF.h | 4 +
3 files changed, 136 insertions(+)
diff --git a/lldb/include/lldb/Utility/ArchSpec.h b/lldb/include/lldb/Utility/ArchSpec.h
index 361108fd8f0e7..438a5e1faf86d 100644
--- a/lldb/include/lldb/Utility/ArchSpec.h
+++ b/lldb/include/lldb/Utility/ArchSpec.h
@@ -14,6 +14,7 @@
#include "lldb/lldb-forward.h"
#include "lldb/lldb-private-enumerations.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/TargetParser/SubtargetFeature.h"
#include "llvm/TargetParser/Triple.h"
#include <cstddef>
#include <cstdint>
@@ -542,6 +543,14 @@ class ArchSpec {
void SetFlags(const std::string &elf_abi);
+ const llvm::SubtargetFeatures &GetSubtargetFeatures() const {
+ return m_subtarget_features;
+ }
+
+ void SetSubtargetFeatures(llvm::SubtargetFeatures &&subtarget_features) {
+ m_subtarget_features = std::move(subtarget_features);
+ }
+
protected:
void UpdateCore();
@@ -553,6 +562,8 @@ class ArchSpec {
// these are application specific extensions like micromips, mips16 etc.
uint32_t m_flags = 0;
+ llvm::SubtargetFeatures m_subtarget_features;
+
// Called when m_def or m_entry are changed. Fills in all remaining members
// with default values.
void CoreUpdated(bool update_triple);
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index 7d783d5dd6b9f..00c5170f4a6d2 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -27,6 +27,7 @@
#include "lldb/Target/Target.h"
#include "lldb/Utility/ArchSpec.h"
#include "lldb/Utility/DataBufferHeap.h"
+#include "lldb/Utility/DataExtractor.h"
#include "lldb/Utility/FileSpecList.h"
#include "lldb/Utility/LLDBLog.h"
#include "lldb/Utility/Log.h"
@@ -45,6 +46,9 @@
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/MipsABIFlags.h"
+#include "llvm/Support/RISCVAttributes.h"
+#include "llvm/TargetParser/RISCVISAInfo.h"
+#include "llvm/TargetParser/SubtargetFeature.h"
#define CASE_AND_STREAM(s, def, width) \
case def: \
@@ -1405,6 +1409,112 @@ void ObjectFileELF::ParseARMAttributes(DataExtractor &data, uint64_t length,
}
}
+static std::optional<lldb::offset_t>
+FindSubSectionOffsetByName(const DataExtractor &data, lldb::offset_t offset,
+ uint32_t length, llvm::StringRef name) {
+ uint32_t section_length = 0;
+ llvm::StringRef section_name;
+ do {
+ offset += section_length;
+ // Sub-section's size and name are included in the total sub-section length.
+ // Don't shift the offset here, so it will point at the beginning of the
+ // sub-section and could be used as a return value.
+ auto tmp_offset = offset;
+ section_length = data.GetU32(&tmp_offset);
+ section_name = data.GetCStr(&tmp_offset);
+ } while (section_name != name && offset + section_length < length);
+ if (section_name == name)
+ return offset;
+ return std::nullopt;
+}
+
+static std::optional<lldb::offset_t>
+FindSubSubSectionOffsetByTag(const DataExtractor &data, lldb::offset_t offset,
+ unsigned tag) {
+ // Consume a sub-section size and name to shift the offset at the beginning of
+ // the sub-sub-sections list.
+ auto upper_section_length = data.GetU32(&offset);
+ data.GetCStr(&offset);
+ auto upper_section_end_offset = offset + upper_section_length;
+
+ uint32_t section_length = 0;
+ unsigned section_tag = 0;
+ do {
+ offset += section_length;
+ // Similar to sub-section sub-sub-section's tag and size are included in the
+ // total sub-sub-section length.
+ auto tmp_offset = offset;
+ section_tag = data.GetULEB128(&tmp_offset);
+ section_length = data.GetU32(&tmp_offset);
+ } while (section_tag != tag &&
+ offset + section_length < upper_section_end_offset);
+ if (section_tag == tag)
+ return offset;
+ return std::nullopt;
+}
+
+static std::optional<std::variant<uint64_t, llvm::StringRef>>
+GetSubSubSubSectionValue(const DataExtractor &data, lldb::offset_t offset,
+ unsigned tag) {
+ // Consume a sub-sub-section tag and size to shift the offset at the beginning
+ // of the sub-sub-sub-sections list.
+ data.GetULEB128(&offset);
+ auto upper_section_length = data.GetU32(&offset);
+ auto upper_section_end_offset = offset + upper_section_length;
+
+ std::variant<uint64_t, llvm::StringRef> result;
+ unsigned section_tag = 0;
+ do {
+ section_tag = data.GetULEB128(&offset);
+ // From the riscv psABI document:
+ // RISC-V attributes have a string value if the tag number is odd and an
+ // integer value if the tag number is even.
+ if (section_tag % 2)
+ result = data.GetCStr(&offset);
+ else
+ result = data.GetULEB128(&offset);
+ } while (section_tag != tag && offset < upper_section_end_offset);
+ if (section_tag == tag)
+ return result;
+ return std::nullopt;
+}
+
+void ObjectFileELF::ParseRISCVAttributes(DataExtractor &data, uint64_t length,
+ ArchSpec &arch_spec) {
+ lldb::offset_t offset = 0;
+
+ uint8_t format_version = data.GetU8(&offset);
+ if (format_version != llvm::ELFAttrs::Format_Version)
+ return;
+
+ auto subsection_or_opt =
+ FindSubSectionOffsetByName(data, offset, length, "riscv");
+ if (!subsection_or_opt.has_value()) {
+ // In fact 'riscv' sub-section is mandatory, so we shouldn't be here.
+ return;
+ }
+
+ auto subsubsection_or_opt = FindSubSubSectionOffsetByTag(
+ data, *subsection_or_opt, llvm::ELFAttrs::File);
+ if (!subsubsection_or_opt.has_value())
+ return;
+
+ auto value_or_opt = GetSubSubSubSectionValue(data, *subsubsection_or_opt,
+ llvm::RISCVAttrs::ARCH);
+ if (!value_or_opt.has_value())
+ return;
+
+ auto isa_info = llvm::RISCVISAInfo::parseArchString(
+ std::get<llvm::StringRef>(*value_or_opt),
+ /* EnableExperimentalExtension=*/true);
+ if (llvm::errorToBool(isa_info.takeError()))
+ return;
+
+ llvm::SubtargetFeatures features;
+ features.addFeaturesVector((*isa_info)->toFeatures());
+ arch_spec.SetSubtargetFeatures(std::move(features));
+}
+
// GetSectionHeaderInfo
size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl §ion_headers,
DataExtractor &object_data,
@@ -1622,6 +1732,17 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl §ion_headers,
ParseARMAttributes(data, section_size, arch_spec);
}
+ if (arch_spec.GetMachine() == llvm::Triple::riscv32 ||
+ arch_spec.GetMachine() == llvm::Triple::riscv64) {
+ DataExtractor data;
+
+ if (sheader.sh_type == llvm::ELF::SHT_RISCV_ATTRIBUTES &&
+ section_size != 0 &&
+ data.SetData(object_data, sheader.sh_offset, section_size) ==
+ section_size)
+ ParseRISCVAttributes(data, section_size, arch_spec);
+ }
+
if (name == g_sect_name_gnu_debuglink) {
DataExtractor data;
if (section_size && (data.SetData(object_data, sheader.sh_offset,
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
index 2927e6969230c..a98f6604dfe39 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
@@ -275,6 +275,10 @@ class ObjectFileELF : public lldb_private::ObjectFile {
uint64_t length,
lldb_private::ArchSpec &arch_spec);
+ static void ParseRISCVAttributes(lldb_private::DataExtractor &data,
+ uint64_t length,
+ lldb_private::ArchSpec &arch_spec);
+
/// Parses the elf section headers and returns the uuid, debug link name,
/// crc, archspec.
static size_t GetSectionHeaderInfo(SectionHeaderColl §ion_headers,
>From 941529fe827c4fb06311ad0220fc36cddb41c425 Mon Sep 17 00:00:00 2001
From: Daniil Avdeev <daniilavdeev237 at gmail.com>
Date: Fri, 16 Jan 2026 09:02:13 +0000
Subject: [PATCH 2/3] fix
---
.../Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index 00c5170f4a6d2..f07e08ba95779 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -1481,6 +1481,8 @@ GetSubSubSubSectionValue(const DataExtractor &data, lldb::offset_t offset,
void ObjectFileELF::ParseRISCVAttributes(DataExtractor &data, uint64_t length,
ArchSpec &arch_spec) {
+ Log *log = GetLog(LLDBLog::Modules);
+
lldb::offset_t offset = 0;
uint8_t format_version = data.GetU8(&offset);
@@ -1489,19 +1491,22 @@ void ObjectFileELF::ParseRISCVAttributes(DataExtractor &data, uint64_t length,
auto subsection_or_opt =
FindSubSectionOffsetByName(data, offset, length, "riscv");
- if (!subsection_or_opt.has_value()) {
- // In fact 'riscv' sub-section is mandatory, so we shouldn't be here.
+ if (!subsection_or_opt) {
+ LLDB_LOGF(log,
+ "ObjectFileELF::%s Ill-formed .riscv.attributes section: "
+ "mandatory 'riscv' sub-section was not preserved",
+ __FUNCTION__);
return;
}
auto subsubsection_or_opt = FindSubSubSectionOffsetByTag(
data, *subsection_or_opt, llvm::ELFAttrs::File);
- if (!subsubsection_or_opt.has_value())
+ if (!subsubsection_or_opt)
return;
auto value_or_opt = GetSubSubSubSectionValue(data, *subsubsection_or_opt,
llvm::RISCVAttrs::ARCH);
- if (!value_or_opt.has_value())
+ if (!value_or_opt)
return;
auto isa_info = llvm::RISCVISAInfo::parseArchString(
@@ -1732,10 +1737,8 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl §ion_headers,
ParseARMAttributes(data, section_size, arch_spec);
}
- if (arch_spec.GetMachine() == llvm::Triple::riscv32 ||
- arch_spec.GetMachine() == llvm::Triple::riscv64) {
+ if (arch_spec.GetTriple().isRISCV()) {
DataExtractor data;
-
if (sheader.sh_type == llvm::ELF::SHT_RISCV_ATTRIBUTES &&
section_size != 0 &&
data.SetData(object_data, sheader.sh_offset, section_size) ==
>From 977d5d9d167dabdde8e1a5d82a08d64ec69c2fdb Mon Sep 17 00:00:00 2001
From: Daniil Avdeev <daniilavdeev237 at gmail.com>
Date: Thu, 5 Feb 2026 17:26:19 +0000
Subject: [PATCH 3/3] fix
---
.../Plugins/ObjectFile/ELF/ObjectFileELF.cpp | 77 +++++++++++++++----
1 file changed, 62 insertions(+), 15 deletions(-)
diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
index f07e08ba95779..f284641323536 100644
--- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
+++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -1423,8 +1423,10 @@ FindSubSectionOffsetByName(const DataExtractor &data, lldb::offset_t offset,
section_length = data.GetU32(&tmp_offset);
section_name = data.GetCStr(&tmp_offset);
} while (section_name != name && offset + section_length < length);
+
if (section_name == name)
return offset;
+
return std::nullopt;
}
@@ -1433,9 +1435,9 @@ FindSubSubSectionOffsetByTag(const DataExtractor &data, lldb::offset_t offset,
unsigned tag) {
// Consume a sub-section size and name to shift the offset at the beginning of
// the sub-sub-sections list.
- auto upper_section_length = data.GetU32(&offset);
+ auto parent_section_length = data.GetU32(&offset);
data.GetCStr(&offset);
- auto upper_section_end_offset = offset + upper_section_length;
+ auto parent_section_end_offset = offset + parent_section_length;
uint32_t section_length = 0;
unsigned section_tag = 0;
@@ -1447,35 +1449,39 @@ FindSubSubSectionOffsetByTag(const DataExtractor &data, lldb::offset_t offset,
section_tag = data.GetULEB128(&tmp_offset);
section_length = data.GetU32(&tmp_offset);
} while (section_tag != tag &&
- offset + section_length < upper_section_end_offset);
+ offset + section_length < parent_section_end_offset);
+
if (section_tag == tag)
return offset;
+
return std::nullopt;
}
static std::optional<std::variant<uint64_t, llvm::StringRef>>
-GetSubSubSubSectionValue(const DataExtractor &data, lldb::offset_t offset,
- unsigned tag) {
+GetAttributeValueByTag(const DataExtractor &data, lldb::offset_t offset,
+ unsigned tag) {
// Consume a sub-sub-section tag and size to shift the offset at the beginning
- // of the sub-sub-sub-sections list.
+ // of the attribute list.
data.GetULEB128(&offset);
- auto upper_section_length = data.GetU32(&offset);
- auto upper_section_end_offset = offset + upper_section_length;
+ auto parent_section_length = data.GetU32(&offset);
+ auto parent_section_end_offset = offset + parent_section_length;
std::variant<uint64_t, llvm::StringRef> result;
- unsigned section_tag = 0;
+ unsigned attribute_tag = 0;
do {
- section_tag = data.GetULEB128(&offset);
+ attribute_tag = data.GetULEB128(&offset);
// From the riscv psABI document:
// RISC-V attributes have a string value if the tag number is odd and an
// integer value if the tag number is even.
- if (section_tag % 2)
+ if (attribute_tag % 2)
result = data.GetCStr(&offset);
else
result = data.GetULEB128(&offset);
- } while (section_tag != tag && offset < upper_section_end_offset);
- if (section_tag == tag)
+ } while (attribute_tag != tag && offset < parent_section_end_offset);
+
+ if (attribute_tag == tag)
return result;
+
return std::nullopt;
}
@@ -1485,6 +1491,47 @@ void ObjectFileELF::ParseRISCVAttributes(DataExtractor &data, uint64_t length,
lldb::offset_t offset = 0;
+ // According to the riscv psABI, the .riscv.attributes section has the
+ // following hierarchical structure:
+ //
+ // Section:
+ // .riscv.attributes {
+ // - (uint8_t) format
+ // - Sub-Section 1 {
+ // * (uint32_t) length
+ // * (c_str) name
+ // * Sub-Sub-Section 1.1 {
+ // > (uleb128_t) tag
+ // > (uint32_t) length
+ // > (uleb128_t) attribute_tag_1.1.1
+ // $ (c_str or uleb128_t) value
+ // > (uleb128_t) attribute_tag_1.1.2
+ // $ (c_str or uleb128_t) value
+ // ...
+ // Other attributes...
+ // ...
+ // > (uleb128_t) attribute_tag_1.1.N
+ // $ (c_str or uleb128_t) value
+ // }
+ // * Sub-Sub-Section 1.2 {
+ // ...
+ // Sub-Sub-Section structure...
+ // ...
+ // }
+ // ...
+ // Other sub-sub-sections...
+ // ...
+ // }
+ // - Sub-Section 2 {
+ // ...
+ // Sub-Section structure...
+ // ...
+ // }
+ // ...
+ // Other sub-sections...
+ // ...
+ // }
+
uint8_t format_version = data.GetU8(&offset);
if (format_version != llvm::ELFAttrs::Format_Version)
return;
@@ -1504,8 +1551,8 @@ void ObjectFileELF::ParseRISCVAttributes(DataExtractor &data, uint64_t length,
if (!subsubsection_or_opt)
return;
- auto value_or_opt = GetSubSubSubSectionValue(data, *subsubsection_or_opt,
- llvm::RISCVAttrs::ARCH);
+ auto value_or_opt = GetAttributeValueByTag(data, *subsubsection_or_opt,
+ llvm::RISCVAttrs::ARCH);
if (!value_or_opt)
return;
More information about the lldb-commits
mailing list