pfaffe created this revision. pfaffe added reviewers: labath, DavidSpickett. Herald added a project: All. pfaffe requested review of this revision. Herald added subscribers: lldb-commits, aheejin. Herald added a project: LLDB.
Parsing DWARF expressions currently does not support DW_OPs that are vendor extensions. With this change expression parsing calls into SymbolFileDWARF for unknown opcodes, which is the semantically "closest" plugin that we have right now. Plugins can then extend SymbolFileDWARF to add support for vendor extensions. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D137247 Files: lldb/include/lldb/Expression/DWARFExpression.h lldb/include/lldb/Target/Platform.h lldb/source/Expression/DWARFExpression.cpp lldb/source/Expression/DWARFExpressionList.cpp lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h lldb/unittests/Expression/DWARFExpressionTest.cpp
Index: lldb/unittests/Expression/DWARFExpressionTest.cpp =================================================================== --- lldb/unittests/Expression/DWARFExpressionTest.cpp +++ lldb/unittests/Expression/DWARFExpressionTest.cpp @@ -9,9 +9,11 @@ #include "lldb/Expression/DWARFExpression.h" #include "Plugins/Platform/Linux/PlatformLinux.h" #include "Plugins/SymbolFile/DWARF/DWARFDebugInfo.h" +#include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h" #include "Plugins/TypeSystem/Clang/TypeSystemClang.h" #include "TestingSupport/Symbol/YAMLModuleTester.h" #include "lldb/Core/Debugger.h" +#include "lldb/Core/PluginManager.h" #include "lldb/Core/Value.h" #include "lldb/Core/dwarf.h" #include "lldb/Host/HostInfo.h" @@ -514,3 +516,251 @@ ASSERT_EQ(result.GetValueType(), Value::ValueType::LoadAddress); ASSERT_EQ(result.GetScalar().UInt(), 0x5678u); } + +class CustomSymbolFileDWARF : public SymbolFileDWARF { + static char ID; + +public: + using SymbolFileDWARF::SymbolFileDWARF; + + bool isA(const void *ClassID) const override { + return ClassID == &ID || SymbolFile::isA(ClassID); + } + static bool classof(const SymbolFile *obj) { return obj->isA(&ID); } + + static llvm::StringRef GetPluginNameStatic() { return "custom_dwarf"; } + + static llvm::StringRef GetPluginDescriptionStatic() { + return "Symbol file reader with expression extensions."; + } + + static void Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + SymbolFileDWARF::DebuggerInitialize); + } + + static void Terminate() { PluginManager::UnregisterPlugin(CreateInstance); } + + static lldb_private::SymbolFile * + CreateInstance(lldb::ObjectFileSP objfile_sp) { + return new CustomSymbolFileDWARF(std::move(objfile_sp), + /*dwo_section_list*/ nullptr); + } + + lldb::offset_t + GetVendorDWARFOpcodeSize(const lldb_private::DataExtractor &data, + const lldb::offset_t data_offset, + const uint8_t op) const final { + auto offset = data_offset; + if (op != DW_OP_WASM_location) { + return LLDB_INVALID_OFFSET; + } + + // DW_OP_WASM_location WASM_GLOBAL:0x03 index:u32 + // Called with "arguments" 0x03, 0x04, 0x00, 0x00, 0x00 + // Location type: + if (data.GetU8(&offset) != /* global */ 0x03) { + return LLDB_INVALID_OFFSET; + } + + // Index + if (data.GetU32(&offset) != 0x04) { + return LLDB_INVALID_OFFSET; + } + + // Report the skipped distance: + return offset - data_offset; + } + + bool + ParseVendorDWARFOpcode(uint8_t op, const lldb_private::DataExtractor &opcodes, + lldb::offset_t &offset, + std::vector<lldb_private::Value> &stack) const final { + if (op != DW_OP_WASM_location) { + return false; + } + + // DW_OP_WASM_location WASM_GLOBAL:0x03 index:u32 + // Called with "arguments" 0x03, 0x04, 0x00, 0x00, 0x00 + // Location type: + if (opcodes.GetU8(&offset) != /* global */ 0x03) { + return false; + } + + // Index: + if (opcodes.GetU32(&offset) != 0x04) { + return false; + } + + // Return some value: + stack.push_back({GetScalar(32, 42, false)}); + return true; + } +}; + +char CustomSymbolFileDWARF::ID; + +TEST(DWARFExpression, Extensions) { + const char *yamldata = R"( +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_386 +DWARF: + debug_abbrev: + - Table: + - Code: 0x00000001 + Tag: DW_TAG_compile_unit + Children: DW_CHILDREN_no + debug_info: + - Version: 4 + AddrSize: 4 + Entries: + - AbbrCode: 0x1 + - AbbrCode: 0x0 +)"; + + SubsystemRAII<FileSystem, HostInfo, TypeSystemClang, ObjectFileELF, + CustomSymbolFileDWARF> + subsystems; + + llvm::Expected<TestFile> file = TestFile::fromYaml(yamldata); + EXPECT_THAT_EXPECTED(file, llvm::Succeeded()); + + auto module_sp = std::make_shared<Module>(file->moduleSpec()); + auto &symfile = + *llvm::cast<CustomSymbolFileDWARF>(module_sp->GetSymbolFile()); + auto *dwarf_unit = symfile.DebugInfo().GetUnitAtIndex(0); + + // Test that expression extensions can be evaluated, for example + // DW_OP_WASM_location which is not currently handled by DWARFExpression: + // DW_OP_WASM_location WASM_GLOBAL:0x03 index:u32 + EXPECT_THAT_EXPECTED(Evaluate({DW_OP_WASM_location, 0x03, 0x04, 0x00, 0x00, + 0x00, DW_OP_stack_value}, + module_sp, dwarf_unit), + llvm::HasValue(GetScalar(32, 42, false))); + + // Test that searches for opcodes work in the presence of extensions: + uint8_t expr[] = {DW_OP_WASM_location, 0x03, 0x04, 0x00, 0x00, 0x00, + DW_OP_form_tls_address}; + DataExtractor extractor(expr, sizeof(expr), lldb::eByteOrderLittle, + /*addr_size*/ 4); + DWARFExpression dwarf_expr(extractor); + ASSERT_TRUE(dwarf_expr.ContainsThreadLocalStorage(*dwarf_unit)); +} + +TEST(DWARFExpression, ExtensionsDWO) { + const char *skeleton_yamldata = R"( +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_386 +DWARF: + debug_abbrev: + - Table: + - Code: 0x00000001 + Tag: DW_TAG_skeleton_unit + Children: DW_CHILDREN_no + Attributes: + - Attribute: DW_AT_dwo_name + Form: DW_FORM_string + - Attribute: DW_AT_dwo_id + Form: DW_FORM_data4 + debug_info: + - Version: 4 + AddrSize: 4 + Entries: + - AbbrCode: 0x1 + Values: + - CStr: "dwo_unit" + - Value: 0x01020304 + - AbbrCode: 0x0 +)"; + + // .dwo sections aren't currently supported by dwarfyaml. The dwo_yamldata + // contents where generated by roundtripping the following yaml through + // yaml2obj | obj2yaml and renaming the sections. This works because the + // structure of the .dwo and non-.dwo sections is identical. + // + // --- !ELF + // FileHeader: + // Class: ELFCLASS64 + // Data: ELFDATA2LSB + // Type: ET_EXEC + // Machine: EM_386 + // DWARF: + // debug_abbrev: #.dwo + // - Table: + // - Code: 0x00000001 + // Tag: DW_TAG_compile_unit + // Children: DW_CHILDREN_no + // Attributes: + // - Attribute: DW_AT_dwo_id + // Form: DW_FORM_data4 + // debug_info: #.dwo + // - Version: 4 + // AddrSize: 4 + // Entries: + // - AbbrCode: 0x1 + // Values: + // - Value: 0x01020304 + // - AbbrCode: 0x0 + const char *dwo_yamldata = R"( +--- !ELF +FileHeader: + Class: ELFCLASS64 + Data: ELFDATA2LSB + Type: ET_EXEC + Machine: EM_386 +Sections: + - Name: .debug_abbrev.dwo + Type: SHT_PROGBITS + AddressAlign: 0x1 + Content: '0111007506000000' + - Name: .debug_info.dwo + Type: SHT_PROGBITS + AddressAlign: 0x1 + Content: 0D00000004000000000004010403020100 +)"; + + SubsystemRAII<FileSystem, HostInfo, ObjectFileELF, CustomSymbolFileDWARF> + subsystems; + + llvm::Expected<TestFile> skeleton_file = + TestFile::fromYaml(skeleton_yamldata); + EXPECT_THAT_EXPECTED(skeleton_file, llvm::Succeeded()); + llvm::Expected<TestFile> dwo_file = TestFile::fromYaml(dwo_yamldata); + EXPECT_THAT_EXPECTED(dwo_file, llvm::Succeeded()); + + auto skeleton_module_sp = + std::make_shared<Module>(skeleton_file->moduleSpec()); + auto &skeleton_symfile = + *llvm::cast<CustomSymbolFileDWARF>(skeleton_module_sp->GetSymbolFile()); + + auto dwo_module_sp = std::make_shared<Module>(dwo_file->moduleSpec()); + SymbolFileDWARFDwo dwo_symfile( + skeleton_symfile, dwo_module_sp->GetObjectFile()->shared_from_this(), + 0x01020304); + auto *dwo_dwarf_unit = dwo_symfile.DebugInfo().GetUnitAtIndex(0); + + // Test that expression extensions can be evaluated, for example + // DW_OP_WASM_location which is not currently handled by DWARFExpression: + // DW_OP_WASM_location WASM_GLOBAL:0x03 index:u32 + EXPECT_THAT_EXPECTED(Evaluate({DW_OP_WASM_location, 0x03, 0x04, 0x00, 0x00, + 0x00, DW_OP_stack_value}, + dwo_module_sp, dwo_dwarf_unit), + llvm::HasValue(GetScalar(32, 42, false))); + + // Test that searches for opcodes work in the presence of extensions: + uint8_t expr[] = {DW_OP_WASM_location, 0x03, 0x04, 0x00, 0x00, 0x00, + DW_OP_form_tls_address}; + DataExtractor extractor(expr, sizeof(expr), lldb::eByteOrderLittle, + /*addr_size*/ 4); + DWARFExpression dwarf_expr(extractor); + ASSERT_TRUE(dwarf_expr.ContainsThreadLocalStorage(*dwo_dwarf_unit)); +} Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h +++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h @@ -42,6 +42,8 @@ llvm::Optional<uint32_t> GetDwoNum() override { return GetID() >> 32; } + SymbolFileDWARF &GetBaseSymbolFile() const { return m_base_symbol_file; } + protected: DIEToTypePtr &GetDIEToType() override; @@ -60,8 +62,6 @@ const DWARFDIE &die, lldb_private::ConstString type_name, bool must_be_implementation) override; - SymbolFileDWARF &GetBaseSymbolFile() { return m_base_symbol_file; } - /// If this file contains exactly one compile unit, this function will return /// it. Otherwise it returns nullptr. DWARFCompileUnit *FindSingleCompileUnit(); Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -331,6 +331,21 @@ return m_parse_time; } + virtual lldb::offset_t + GetVendorDWARFOpcodeSize(const lldb_private::DataExtractor &data, + const lldb::offset_t data_offset, + const uint8_t op) const { + return LLDB_INVALID_OFFSET; + } + + virtual bool + ParseVendorDWARFOpcode(uint8_t op, + const lldb_private::DataExtractor &opcodes, + lldb::offset_t &offset, + std::vector<lldb_private::Value> &stack) const { + return false; + } + lldb_private::ConstString ConstructFunctionDemangledName(const DWARFDIE &die); protected: Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp =================================================================== --- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -3466,7 +3466,8 @@ if (exe_file_addr != LLDB_INVALID_ADDRESS) { DWARFExpression *location = location_list.GetMutableExpressionAtAddress(); - if (location->Update_DW_OP_addr(exe_file_addr)) { + if (location->Update_DW_OP_addr(*die.GetCU(), + exe_file_addr)) { linked_oso_file_addr = true; symbol_context_scope = exe_symbol; } @@ -3486,7 +3487,7 @@ // Update the file address for this variable DWARFExpression *location = location_list.GetMutableExpressionAtAddress(); - location->Update_DW_OP_addr(exe_file_addr); + location->Update_DW_OP_addr(*die.GetCU(), exe_file_addr); } else { // Variable didn't make it into the final executable return nullptr; Index: lldb/source/Expression/DWARFExpressionList.cpp =================================================================== --- lldb/source/Expression/DWARFExpressionList.cpp +++ lldb/source/Expression/DWARFExpressionList.cpp @@ -90,7 +90,7 @@ return false; const DWARFExpression &expr = m_exprs.GetEntryRef(0).data; - return expr.ContainsThreadLocalStorage(); + return expr.ContainsThreadLocalStorage(*m_dwarf_cu); } bool DWARFExpressionList::LinkThreadLocalStorage( @@ -107,7 +107,7 @@ // If we linked the TLS address correctly, update the module so that when the // expression is evaluated it can resolve the file address to a load address // and read the TLS data - if (expr.LinkThreadLocalStorage(link_address_callback)) + if (expr.LinkThreadLocalStorage(*m_dwarf_cu, link_address_callback)) m_module_wp = new_module_sp; return true; } Index: lldb/source/Expression/DWARFExpression.cpp =================================================================== --- lldb/source/Expression/DWARFExpression.cpp +++ lldb/source/Expression/DWARFExpression.cpp @@ -38,8 +38,10 @@ #include "lldb/Target/Thread.h" #include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h" #include "llvm/DebugInfo/DWARF/DWARFExpression.h" +#include "llvm/Support/Casting.h" #include "Plugins/SymbolFile/DWARF/DWARFUnit.h" +#include "Plugins/SymbolFile/DWARF/SymbolFileDWARFDwo.h" using namespace lldb; using namespace lldb_private; @@ -131,7 +133,8 @@ /// are made on the state of \p data after this call. static offset_t GetOpcodeDataSize(const DataExtractor &data, const lldb::offset_t data_offset, - const uint8_t op) { + const uint8_t op, + const SymbolFileDWARF &symbol_file) { lldb::offset_t offset = data_offset; switch (op) { case DW_OP_addr: @@ -333,9 +336,13 @@ } default: - break; + if (auto *dwo_symbol_file = + llvm::dyn_cast<SymbolFileDWARFDwo>(&symbol_file)) { + return dwo_symbol_file->GetBaseSymbolFile().GetVendorDWARFOpcodeSize( + data, data_offset, op); + } + return symbol_file.GetVendorDWARFOpcodeSize(data, data_offset, op); } - return LLDB_INVALID_OFFSET; } lldb::addr_t DWARFExpression::GetLocation_DW_OP_addr(const DWARFUnit *dwarf_cu, @@ -364,7 +371,8 @@ } ++curr_op_addr_idx; } else { - const offset_t op_arg_size = GetOpcodeDataSize(m_data, offset, op); + const offset_t op_arg_size = + GetOpcodeDataSize(m_data, offset, op, dwarf_cu->GetSymbolFileDWARF()); if (op_arg_size == LLDB_INVALID_OFFSET) { error = true; break; @@ -375,7 +383,7 @@ return LLDB_INVALID_ADDRESS; } -bool DWARFExpression::Update_DW_OP_addr(lldb::addr_t file_addr) { +bool DWARFExpression::Update_DW_OP_addr(const DWARFUnit &dwarf_cu, lldb::addr_t file_addr) { lldb::offset_t offset = 0; while (m_data.ValidOffset(offset)) { const uint8_t op = m_data.GetU8(&offset); @@ -402,7 +410,8 @@ m_data.SetData(encoder.GetDataBuffer()); return true; } else { - const offset_t op_arg_size = GetOpcodeDataSize(m_data, offset, op); + const offset_t op_arg_size = + GetOpcodeDataSize(m_data, offset, op, dwarf_cu.GetSymbolFileDWARF()); if (op_arg_size == LLDB_INVALID_OFFSET) break; offset += op_arg_size; @@ -411,21 +420,22 @@ return false; } -bool DWARFExpression::ContainsThreadLocalStorage() const { +bool DWARFExpression::ContainsThreadLocalStorage(const DWARFUnit &dwarf_cu) const { lldb::offset_t offset = 0; while (m_data.ValidOffset(offset)) { const uint8_t op = m_data.GetU8(&offset); if (op == DW_OP_form_tls_address || op == DW_OP_GNU_push_tls_address) return true; - const offset_t op_arg_size = GetOpcodeDataSize(m_data, offset, op); + const offset_t op_arg_size = + GetOpcodeDataSize(m_data, offset, op, dwarf_cu.GetSymbolFileDWARF()); if (op_arg_size == LLDB_INVALID_OFFSET) return false; offset += op_arg_size; } return false; } -bool DWARFExpression::LinkThreadLocalStorage( +bool DWARFExpression::LinkThreadLocalStorage(const DWARFUnit &dwarf_cu, std::function<lldb::addr_t(lldb::addr_t file_addr)> const &link_address_callback) { const uint32_t addr_byte_size = m_data.GetAddressByteSize(); @@ -496,7 +506,8 @@ } if (!decoded_data) { - const offset_t op_arg_size = GetOpcodeDataSize(m_data, offset, op); + const offset_t op_arg_size = + GetOpcodeDataSize(m_data, offset, op, dwarf_cu.GetSymbolFileDWARF()); if (op_arg_size == LLDB_INVALID_OFFSET) return false; else @@ -2557,6 +2568,16 @@ } default: + if (dwarf_cu) { + auto *symbol_file = &dwarf_cu->GetSymbolFileDWARF(); + if (auto *dwo_symbol_file = + llvm::dyn_cast<SymbolFileDWARFDwo>(symbol_file)) { + symbol_file = &dwo_symbol_file->GetBaseSymbolFile(); + } + if (symbol_file->ParseVendorDWARFOpcode(op, opcodes, offset, stack)) { + break; + } + } if (error_ptr) error_ptr->SetErrorStringWithFormatv( "Unhandled opcode {0} in DWARFExpression", LocationAtom(op)); Index: lldb/include/lldb/Target/Platform.h =================================================================== --- lldb/include/lldb/Target/Platform.h +++ lldb/include/lldb/Target/Platform.h @@ -956,7 +956,6 @@ ResolveRemoteExecutable(const ModuleSpec &module_spec, lldb::ModuleSP &exe_module_sp, const FileSpecList *module_search_paths_ptr); - private: typedef std::function<Status(const ModuleSpec &)> ModuleResolver; Index: lldb/include/lldb/Expression/DWARFExpression.h =================================================================== --- lldb/include/lldb/Expression/DWARFExpression.h +++ lldb/include/lldb/Expression/DWARFExpression.h @@ -75,14 +75,15 @@ lldb::addr_t GetLocation_DW_OP_addr(const DWARFUnit *dwarf_cu, uint32_t op_addr_idx, bool &error) const; - bool Update_DW_OP_addr(lldb::addr_t file_addr); + bool Update_DW_OP_addr(const DWARFUnit &dwarf_cu, lldb::addr_t file_addr); void UpdateValue(uint64_t const_value, lldb::offset_t const_value_byte_size, uint8_t addr_byte_size); - bool ContainsThreadLocalStorage() const; + bool ContainsThreadLocalStorage(const DWARFUnit &dwarf_cu) const; bool LinkThreadLocalStorage( + const DWARFUnit &dwarf_cu, std::function<lldb::addr_t(lldb::addr_t file_addr)> const &link_address_callback);
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits