llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-lldb Author: Santhosh Kumar Ellendula (santhoshe447) <details> <summary>Changes</summary> Parse ELF attributes to automatically set disassembler features. llvm-objdump calls ELFObjectFile::getFeatures, then turns that into a cstr to pass to createMCSubtargetInfo. The lldb disassembler builds features for various architectures manually and adds in the value from the command line. If this is empty, it uses the default. then it turns that into a cstr and passes it to createMCSubtargetInfo. For Hexagon and RISC-V, parse the attributes, set up features, add anything else needed. If this is empty, pick the default. Then turn into a cstr and pass to createMCSubtargetInfo (via MCDisasmInstance::Create). This patch adds RISCV feature attribute support and allows overriding additional(default) feature. --- Full diff: https://github.com/llvm/llvm-project/pull/147990.diff 8 Files Affected: - (modified) lldb/include/lldb/Utility/ArchSpec.h (+12) - (modified) lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp (+42-3) - (modified) lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.h (+4) - (modified) lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp (+49) - (modified) lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h (+8) - (modified) lldb/source/Utility/ArchSpec.cpp (+8) - (added) lldb/test/Shell/Disassemble/Inputs/riscv_xqci.out () - (added) lldb/test/Shell/Disassemble/TestDisassembleRISCVXqciInstrutions.test (+11) ``````````diff diff --git a/lldb/include/lldb/Utility/ArchSpec.h b/lldb/include/lldb/Utility/ArchSpec.h index 7e9bc23a75acb..b39636f5882b6 100644 --- a/lldb/include/lldb/Utility/ArchSpec.h +++ b/lldb/include/lldb/Utility/ArchSpec.h @@ -537,6 +537,15 @@ class ArchSpec { void SetFlags(const std::string &elf_abi); + // Sets the target specific disassembly feature string + // for ELF disassembly. + void SetAdditionalDisassemblyFeatureStr(llvm::StringRef additional_features); + + // Get the current target disassembly feature string. + llvm::StringRef GetAdditionalDisassemblyFeatureStr() const { + return llvm::StringRef(m_additional_disassembly_feature_str); + } + protected: void UpdateCore(); @@ -548,6 +557,9 @@ class ArchSpec { // these are application specific extensions like micromips, mips16 etc. uint32_t m_flags = 0; + // Holds the additional disassembly feature string. + std::string m_additional_disassembly_feature_str; + // 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/Disassembler/LLVMC/DisassemblerLLVMC.cpp b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp index ed6047f8f4ef3..1ca780cc21a16 100644 --- a/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp +++ b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.cpp @@ -1436,6 +1436,37 @@ bool DisassemblerLLVMC::MCDisasmInstance::IsAuthenticated( return InstrDesc.isAuthenticated() || IsBrkC47x; } +void DisassemblerLLVMC::UpdateFeatureString(llvm::StringRef additional_features, + std::string &features) { + // Allow users to override default additional features. + size_t start = 0, end; + while (!additional_features.empty() && start < additional_features.size()) { + end = additional_features.find(',', start); + if (end == llvm::StringRef::npos) { + end = additional_features.size(); + } + llvm::StringRef flag = + additional_features.substr(start, end - start).trim(); + if (!flag.empty()) { + if (flag.starts_with('+')) { + std::string dissable_flag = "-" + flag.substr(1).str(); + if (features.find(dissable_flag) == std::string::npos) { + if (flag.back() != ',') { + features = ',' + features; + } + features = flag.str() + features; + } + } else { + if (flag.back() != ',') { + features = ',' + features; + } + features = flag.str() + features; + } + } + start = end + 1; + } +} + DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch, const char *flavor_string, const char *cpu_string, @@ -1583,6 +1614,15 @@ DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch, features_str += "+a,+m,"; } + const char *additional_features = + arch.GetAdditionalDisassemblyFeatureStr().data(); + // Prepend the additional_features if it's not already in the features_str to + // avoid duplicates. + if (additional_features && + features_str.find(additional_features) == std::string::npos) { + UpdateFeatureString(additional_features, features_str); + } + // We use m_disasm_up.get() to tell whether we are valid or not, so if this // isn't good for some reason, we won't be valid and FindPlugin will fail and // we won't get used. @@ -1595,9 +1635,8 @@ DisassemblerLLVMC::DisassemblerLLVMC(const ArchSpec &arch, // thumb instruction disassembler. if (llvm_arch == llvm::Triple::arm) { std::string thumb_triple(thumb_arch.GetTriple().getTriple()); - m_alternate_disasm_up = - MCDisasmInstance::Create(thumb_triple.c_str(), "", features_str.c_str(), - flavor, *this); + m_alternate_disasm_up = MCDisasmInstance::Create( + thumb_triple.c_str(), "", features_str.c_str(), flavor, *this); if (!m_alternate_disasm_up) m_disasm_up.reset(); diff --git a/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.h b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.h index d6b3d70934989..adfe1e9d0aadd 100644 --- a/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.h +++ b/lldb/source/Plugins/Disassembler/LLVMC/DisassemblerLLVMC.h @@ -21,6 +21,10 @@ class InstructionLLVMC; class DisassemblerLLVMC : public lldb_private::Disassembler { +private: + void UpdateFeatureString(llvm::StringRef additional_features, + std::string &features); + public: DisassemblerLLVMC(const lldb_private::ArchSpec &arch, const char *flavor, const char *cpu, const char *features); diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index f69358de6a288..03da2594b136a 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -45,6 +45,7 @@ #include "llvm/Support/MathExtras.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/MipsABIFlags.h" +#include "llvm/Support/RISCVAttributes.h" #define CASE_AND_STREAM(s, def, width) \ case def: \ @@ -1284,6 +1285,44 @@ ObjectFileELF::RefineModuleDetailsFromNote(lldb_private::DataExtractor &data, return error; } +void ObjectFileELF::ParseRISCVAttributes(DataExtractor &data, uint64_t length, + ArchSpec &arch_spec) { + lldb::offset_t Offset = 0; + + uint8_t FormatVersion = data.GetU8(&Offset); + if (FormatVersion != llvm::ELFAttrs::Format_Version) + return; + + Offset = Offset + sizeof(uint32_t); // Section Length + llvm::StringRef VendorName = data.GetCStr(&Offset); + + if (VendorName != "riscv") + return; + + llvm::StringRef attr = ""; + + while (Offset < length) { + uint8_t Tag = data.GetU8(&Offset); + uint32_t Size = data.GetU32(&Offset); + + if (Tag != llvm::ELFAttrs::File || Size == 0) + continue; + + while (Offset < length) { + uint64_t Tag = data.GetULEB128(&Offset); + if (Tag == llvm::RISCVAttrs::ARCH) { + attr = data.GetCStr(&Offset); + break; + } else { + data.GetULEB128(&Offset); + } + } + } + if (!attr.empty() && attr.contains("xqci")) { + arch_spec.SetAdditionalDisassemblyFeatureStr("+xqci,"); + } +} + void ObjectFileELF::ParseARMAttributes(DataExtractor &data, uint64_t length, ArchSpec &arch_spec) { lldb::offset_t Offset = 0; @@ -1569,6 +1608,16 @@ size_t ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl §ion_headers, if (sheader.sh_type == SHT_ARM_ATTRIBUTES && section_size != 0 && data.SetData(object_data, sheader.sh_offset, section_size) == section_size) ParseARMAttributes(data, section_size, arch_spec); + } else if (arch_spec.GetMachine() == llvm::Triple::riscv32 || + arch_spec.GetMachine() == llvm::Triple::riscv64) { + DataExtractor data; + if (sheader.sh_type == SHT_RISCV_ATTRIBUTES && section_size != 0 && + (data.SetData(object_data, sheader.sh_offset, section_size) == + section_size) && + !arch_spec.GetAdditionalDisassemblyFeatureStr().contains( + "xqci")) { + ParseRISCVAttributes(data, section_size, arch_spec); + } } if (name == g_sect_name_gnu_debuglink) { diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h index 41b8ce189e41d..fb20753fe334c 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h @@ -269,6 +269,14 @@ class ObjectFileELF : public lldb_private::ObjectFile { lldb::SectionType GetSectionType(const ELFSectionHeaderInfo &H) const; + // Parse and ELF header section to detect the RISCV attributes. + // This function traverses the section headers of the ELF object file to + // verify the presence of the Xqci feature extension in the RISCV attributes. + // If the extension is found, it updates the '+xqci' feature string. + static void ParseRISCVAttributes(lldb_private::DataExtractor &data, + uint64_t length, + lldb_private::ArchSpec &arch_spec); + static void ParseARMAttributes(lldb_private::DataExtractor &data, uint64_t length, lldb_private::ArchSpec &arch_spec); diff --git a/lldb/source/Utility/ArchSpec.cpp b/lldb/source/Utility/ArchSpec.cpp index 70b9800f4dade..a9f75749b18f5 100644 --- a/lldb/source/Utility/ArchSpec.cpp +++ b/lldb/source/Utility/ArchSpec.cpp @@ -617,6 +617,14 @@ void ArchSpec::SetFlags(const std::string &elf_abi) { SetFlags(flag); } +void ArchSpec::SetAdditionalDisassemblyFeatureStr( + llvm::StringRef additional_features) { + if (m_additional_disassembly_feature_str.find(additional_features.str()) == + std::string::npos) { + m_additional_disassembly_feature_str += additional_features.str(); + } +} + std::string ArchSpec::GetClangTargetCPU() const { std::string cpu; if (IsMIPS()) { diff --git a/lldb/test/Shell/Disassemble/Inputs/riscv_xqci.out b/lldb/test/Shell/Disassemble/Inputs/riscv_xqci.out new file mode 100755 index 0000000000000..e5f1dc63e7717 Binary files /dev/null and b/lldb/test/Shell/Disassemble/Inputs/riscv_xqci.out differ diff --git a/lldb/test/Shell/Disassemble/TestDisassembleRISCVXqciInstrutions.test b/lldb/test/Shell/Disassemble/TestDisassembleRISCVXqciInstrutions.test new file mode 100644 index 0000000000000..f0a364e26088c --- /dev/null +++ b/lldb/test/Shell/Disassemble/TestDisassembleRISCVXqciInstrutions.test @@ -0,0 +1,11 @@ +# REQUIRES: target=riscv32-{{.*}} + +# RUN: %lldb -b -o "disassemble -b -n main" %p/Inputs/riscv_xqci.out | FileCheck %s + +# CHECK: 1f 05 58 00 00 00 qc.e.li a0, 0x58 +# CHECK: 16 15 qc.extu a0, a0, 0x6, 0x0 + +# RUN: %lldb -b -o "disassemble -b -n main -Y -xqci,+c" %p/Inputs/riscv_xqci.out | FileCheck --check-prefix=CHECK-NOXQCI %s + +# CHECK-NOXQCI: <invalid> + `````````` </details> https://github.com/llvm/llvm-project/pull/147990 _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits