https://github.com/daniilavdeev created https://github.com/llvm/llvm-project/pull/173046
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. >From 4f2ee91216d83ca8c0eb2c85496e2cbf7f9ca992 Mon Sep 17 00:00:00 2001 From: Daniil Avdeev <[email protected]> Date: Tue, 18 Nov 2025 05:23:58 +0000 Subject: [PATCH] [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, _______________________________________________ lldb-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
