diff options
Diffstat (limited to 'lldb/source/Plugins/ObjectFile')
12 files changed, 669 insertions, 44 deletions
diff --git a/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp b/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp index b83b2efb492f3..bd8eeedce57d4 100644 --- a/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp +++ b/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp @@ -1,4 +1,4 @@ -//===-- BreakpadRecords.cpp ----------------------------------- -*- C++ -*-===// +//===-- BreakpadRecords.cpp -----------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -205,7 +205,7 @@ llvm::Optional<InfoRecord> InfoRecord::parse(llvm::StringRef Line) { // use this as the UUID. Otherwise, we should revert back to the module ID. UUID ID; if (Line.trim().empty()) { - if (Str.empty() || ID.SetFromStringRef(Str, Str.size() / 2) != Str.size()) + if (Str.empty() || !ID.SetFromStringRef(Str)) return llvm::None; } return InfoRecord(std::move(ID)); diff --git a/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.h b/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.h index 27bef975125dd..1620a1210b840 100644 --- a/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.h +++ b/lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_PLUGINS_OBJECTFILE_BREAKPAD_BREAKPADRECORDS_H -#define LLDB_PLUGINS_OBJECTFILE_BREAKPAD_BREAKPADRECORDS_H +#ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_BREAKPAD_BREAKPADRECORDS_H +#define LLDB_SOURCE_PLUGINS_OBJECTFILE_BREAKPAD_BREAKPADRECORDS_H #include "lldb/Utility/UUID.h" #include "lldb/lldb-types.h" @@ -183,4 +183,4 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const StackWinRecord &R); } // namespace breakpad } // namespace lldb_private -#endif // LLDB_PLUGINS_OBJECTFILE_BREAKPAD_BREAKPADRECORDS_H +#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_BREAKPAD_BREAKPADRECORDS_H diff --git a/lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp b/lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp index 3b9e0e2092a93..7a9163ddb8801 100644 --- a/lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp +++ b/lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp @@ -1,4 +1,4 @@ -//===-- ObjectFileBreakpad.cpp -------------------------------- -*- C++ -*-===// +//===-- ObjectFileBreakpad.cpp --------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -16,6 +16,8 @@ using namespace lldb; using namespace lldb_private; using namespace lldb_private::breakpad; +LLDB_PLUGIN_DEFINE(ObjectFileBreakpad) + namespace { struct Header { ArchSpec arch; diff --git a/lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h b/lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h index cb4bba01fb718..8724feaa422d3 100644 --- a/lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h +++ b/lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LLDB_PLUGINS_OBJECTFILE_BREAKPAD_OBJECTFILEBREAKPAD_H -#define LLDB_PLUGINS_OBJECTFILE_BREAKPAD_OBJECTFILEBREAKPAD_H +#ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_BREAKPAD_OBJECTFILEBREAKPAD_H +#define LLDB_SOURCE_PLUGINS_OBJECTFILE_BREAKPAD_OBJECTFILEBREAKPAD_H #include "lldb/Symbol/ObjectFile.h" #include "lldb/Utility/ArchSpec.h" @@ -103,4 +103,4 @@ private: } // namespace breakpad } // namespace lldb_private -#endif // LLDB_PLUGINS_OBJECTFILE_BREAKPAD_OBJECTFILEBREAKPAD_H +#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_BREAKPAD_OBJECTFILEBREAKPAD_H diff --git a/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp b/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp index aa9871071b0e0..f0496beba2ef4 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp @@ -1,4 +1,4 @@ -//===-- ELFHeader.cpp ----------------------------------------- -*- C++ -*-===// +//===-- ELFHeader.cpp -----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h b/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h index bb228e269d406..963cc850736ff 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h +++ b/lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h @@ -17,8 +17,8 @@ /// reading both 32 and 64 bit instances of the object. //===----------------------------------------------------------------------===// -#ifndef liblldb_ELFHeader_h_ -#define liblldb_ELFHeader_h_ +#ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_ELF_ELFHEADER_H +#define LLDB_SOURCE_PLUGINS_OBJECTFILE_ELF_ELFHEADER_H #include "llvm/BinaryFormat/ELF.h" @@ -391,4 +391,4 @@ struct ELFRela { } // End namespace elf. -#endif // #ifndef liblldb_ELFHeader_h_ +#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_ELF_ELFHEADER_H diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp index 8b62afa18cd6d..bca575b7f8842 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp @@ -1,4 +1,4 @@ -//===-- ObjectFileELF.cpp ------------------------------------- -*- C++ -*-===// +//===-- ObjectFileELF.cpp -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -51,6 +51,8 @@ using namespace lldb_private; using namespace elf; using namespace llvm::ELF; +LLDB_PLUGIN_DEFINE(ObjectFileELF) + namespace { // ELF note owner definitions @@ -206,7 +208,9 @@ unsigned ELFRelocation::RelocAddend64(const ELFRelocation &rel) { } // end anonymous namespace -static user_id_t SegmentID(size_t PHdrIndex) { return ~PHdrIndex; } +static user_id_t SegmentID(size_t PHdrIndex) { + return ~user_id_t(PHdrIndex); +} bool ELFNote::Parse(const DataExtractor &data, lldb::offset_t *offset) { // Read all fields. @@ -537,7 +541,8 @@ size_t ObjectFileELF::GetModuleSpecifications( __FUNCTION__, file.GetPath().c_str()); } - data_sp = MapFileData(file, -1, file_offset); + if (data_sp->GetByteSize() < length) + data_sp = MapFileData(file, -1, file_offset); if (data_sp) data.SetData(data_sp); // In case there is header extension in the section #0, the header we @@ -576,8 +581,7 @@ size_t ObjectFileELF::GetModuleSpecifications( func_cat, "Calculating module crc32 %s with size %" PRIu64 " KiB", file.GetLastPathComponent().AsCString(), - (FileSystem::Instance().GetByteSize(file) - file_offset) / - 1024); + (length - file_offset) / 1024); // For core files - which usually don't happen to have a // gnu_debuglink, and are pretty bulky - calculating whole @@ -899,7 +903,7 @@ size_t ObjectFileELF::ParseDependentModules() { if (m_filespec_up) return m_filespec_up->GetSize(); - m_filespec_up.reset(new FileSpecList()); + m_filespec_up = std::make_unique<FileSpecList>(); if (!ParseSectionHeaders()) return 0; @@ -1235,7 +1239,7 @@ void ObjectFileELF::ParseARMAttributes(DataExtractor &data, uint64_t length, lldb::offset_t Offset = 0; uint8_t FormatVersion = data.GetU8(&Offset); - if (FormatVersion != llvm::ARMBuildAttrs::Format_Version) + if (FormatVersion != llvm::ELFAttrs::Format_Version) return; Offset = Offset + sizeof(uint32_t); // Section Length @@ -1588,6 +1592,7 @@ static SectionType GetSectionTypeFromName(llvm::StringRef Name) { .Case("str.dwo", eSectionTypeDWARFDebugStrDwo) .Case("str_offsets", eSectionTypeDWARFDebugStrOffsets) .Case("str_offsets.dwo", eSectionTypeDWARFDebugStrOffsetsDwo) + .Case("tu_index", eSectionTypeDWARFDebugTuIndex) .Case("types", eSectionTypeDWARFDebugTypes) .Case("types.dwo", eSectionTypeDWARFDebugTypesDwo) .Default(eSectionTypeOther); @@ -1696,7 +1701,7 @@ class VMAddressProvider { public: VMAddressProvider(ObjectFile::Type Type, llvm::StringRef SegmentName) - : ObjectType(Type), SegmentName(SegmentName) {} + : ObjectType(Type), SegmentName(std::string(SegmentName)) {} std::string GetNextSegmentName() const { return llvm::formatv("{0}[{1}]", SegmentName, SegmentCount).str(); @@ -2230,8 +2235,7 @@ unsigned ObjectFileELF::ParseSymbols(Symtab *symtab, user_id_t start_id, if (!mangled_name.empty()) mangled.SetMangledName(ConstString((mangled_name + suffix).str())); - ConstString demangled = - mangled.GetDemangledName(lldb::eLanguageTypeUnknown); + ConstString demangled = mangled.GetDemangledName(); llvm::StringRef demangled_name = demangled.GetStringRef(); if (!demangled_name.empty()) mangled.SetDemangledName(ConstString((demangled_name + suffix).str())); @@ -2713,7 +2717,7 @@ Symtab *ObjectFileELF::GetSymtab() { Section *symtab = section_list->FindSectionByType(eSectionTypeELFSymbolTable, true).get(); if (symtab) { - m_symtab_up.reset(new Symtab(symtab->GetObjectFile())); + m_symtab_up = std::make_unique<Symtab>(symtab->GetObjectFile()); symbol_id += ParseSymbolTable(m_symtab_up.get(), symbol_id, symtab); } @@ -2730,7 +2734,7 @@ Symtab *ObjectFileELF::GetSymtab() { .get(); if (dynsym) { if (!m_symtab_up) - m_symtab_up.reset(new Symtab(dynsym->GetObjectFile())); + m_symtab_up = std::make_unique<Symtab>(dynsym->GetObjectFile()); symbol_id += ParseSymbolTable(m_symtab_up.get(), symbol_id, dynsym); } } @@ -2757,7 +2761,8 @@ Symtab *ObjectFileELF::GetSymtab() { assert(reloc_header); if (m_symtab_up == nullptr) - m_symtab_up.reset(new Symtab(reloc_section->GetObjectFile())); + m_symtab_up = + std::make_unique<Symtab>(reloc_section->GetObjectFile()); ParseTrampolineSymbols(m_symtab_up.get(), symbol_id, reloc_header, reloc_id); @@ -2767,17 +2772,17 @@ Symtab *ObjectFileELF::GetSymtab() { if (DWARFCallFrameInfo *eh_frame = GetModule()->GetUnwindTable().GetEHFrameInfo()) { if (m_symtab_up == nullptr) - m_symtab_up.reset(new Symtab(this)); + m_symtab_up = std::make_unique<Symtab>(this); ParseUnwindSymbols(m_symtab_up.get(), eh_frame); } // If we still don't have any symtab then create an empty instance to avoid // do the section lookup next time. if (m_symtab_up == nullptr) - m_symtab_up.reset(new Symtab(this)); + m_symtab_up = std::make_unique<Symtab>(this); // In the event that there's no symbol entry for the entry point we'll - // artifically create one. We delegate to the symtab object the figuring + // artificially create one. We delegate to the symtab object the figuring // out of the proper size, this will usually make it span til the next // symbol it finds in the section. This means that if there are missing // symbols the entry point might span beyond its function definition. @@ -2874,7 +2879,7 @@ void ObjectFileELF::ParseUnwindSymbols(Symtab *symbol_table, return; // First we save the new symbols into a separate list and add them to the - // symbol table after we colleced all symbols we want to add. This is + // symbol table after we collected all symbols we want to add. This is // neccessary because adding a new symbol invalidates the internal index of // the symtab what causing the next lookup to be slow because it have to // recalculate the index first. @@ -2953,7 +2958,8 @@ void ObjectFileELF::Dump(Stream *s) { s->EOL(); SectionList *section_list = GetSectionList(); if (section_list) - section_list->Dump(s, nullptr, true, UINT32_MAX); + section_list->Dump(s->AsRawOstream(), s->GetIndentLevel(), nullptr, true, + UINT32_MAX); Symtab *symtab = GetSymtab(); if (symtab) symtab->Dump(s, nullptr, eSortOrderNone); diff --git a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h index 3b273896cb598..062271f1caf0f 100644 --- a/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h +++ b/lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ObjectFileELF_h_ -#define liblldb_ObjectFileELF_h_ +#ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_ELF_OBJECTFILEELF_H +#define LLDB_SOURCE_PLUGINS_OBJECTFILE_ELF_OBJECTFILEELF_H #include <stdint.h> @@ -328,9 +328,6 @@ private: /// section index 0 is never valid). lldb::user_id_t GetSectionIndexByName(const char *name); - // Returns the ID of the first section that has the given type. - lldb::user_id_t GetSectionIndexByType(unsigned type); - /// Returns the section header with the given id or NULL. const ELFSectionHeaderInfo *GetSectionHeaderByIndex(lldb::user_id_t id); @@ -397,4 +394,4 @@ private: std::shared_ptr<ObjectFileELF> GetGnuDebugDataObjectFile(); }; -#endif // liblldb_ObjectFileELF_h_ +#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_ELF_OBJECTFILEELF_H diff --git a/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp b/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp index c55b96d9110b3..93c2c9f945fe9 100644 --- a/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp +++ b/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp @@ -1,4 +1,4 @@ -//===-- ObjectFileJIT.cpp ---------------------------------------*- C++ -*-===// +//===-- ObjectFileJIT.cpp -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -39,6 +39,8 @@ using namespace lldb; using namespace lldb_private; +LLDB_PLUGIN_DEFINE(ObjectFileJIT) + char ObjectFileJIT::ID; void ObjectFileJIT::Initialize() { @@ -118,7 +120,7 @@ Symtab *ObjectFileJIT::GetSymtab() { if (module_sp) { std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); if (m_symtab_up == nullptr) { - m_symtab_up.reset(new Symtab(this)); + m_symtab_up = std::make_unique<Symtab>(this); std::lock_guard<std::recursive_mutex> symtab_guard( m_symtab_up->GetMutex()); ObjectFileJITDelegateSP delegate_sp(m_delegate_wp.lock()); @@ -137,7 +139,7 @@ bool ObjectFileJIT::IsStripped() { void ObjectFileJIT::CreateSections(SectionList &unified_section_list) { if (!m_sections_up) { - m_sections_up.reset(new SectionList()); + m_sections_up = std::make_unique<SectionList>(); ObjectFileJITDelegateSP delegate_sp(m_delegate_wp.lock()); if (delegate_sp) { delegate_sp->PopulateSectionList(this, *m_sections_up); @@ -161,7 +163,8 @@ void ObjectFileJIT::Dump(Stream *s) { SectionList *sections = GetSectionList(); if (sections) - sections->Dump(s, nullptr, true, UINT32_MAX); + sections->Dump(s->AsRawOstream(), s->GetIndentLevel(), nullptr, true, + UINT32_MAX); if (m_symtab_up) m_symtab_up->Dump(s, nullptr, eSortOrderNone); diff --git a/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h b/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h index c992683cfc3ce..a3a1acea916aa 100644 --- a/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h +++ b/lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef liblldb_ObjectFileJIT_h_ -#define liblldb_ObjectFileJIT_h_ +#ifndef LLDB_SOURCE_PLUGINS_OBJECTFILE_JIT_OBJECTFILEJIT_H +#define LLDB_SOURCE_PLUGINS_OBJECTFILE_JIT_OBJECTFILEJIT_H #include "lldb/Core/Address.h" #include "lldb/Symbol/ObjectFile.h" @@ -104,4 +104,4 @@ protected: lldb::ObjectFileJITDelegateWP m_delegate_wp; }; -#endif // liblldb_ObjectFileJIT_h_ +#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_JIT_OBJECTFILEJIT_H diff --git a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp new file mode 100644 index 0000000000000..91150fa02ebca --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp @@ -0,0 +1,466 @@ +//===-- ObjectFileWasm.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 "ObjectFileWasm.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/ModuleSpec.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Core/Section.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/SectionLoadList.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/Log.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/BinaryFormat/Magic.h" +#include "llvm/BinaryFormat/Wasm.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/Format.h" + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::wasm; + +LLDB_PLUGIN_DEFINE(ObjectFileWasm) + +static const uint32_t kWasmHeaderSize = + sizeof(llvm::wasm::WasmMagic) + sizeof(llvm::wasm::WasmVersion); + +/// Checks whether the data buffer starts with a valid Wasm module header. +static bool ValidateModuleHeader(const DataBufferSP &data_sp) { + if (!data_sp || data_sp->GetByteSize() < kWasmHeaderSize) + return false; + + if (llvm::identify_magic(toStringRef(data_sp->GetData())) != + llvm::file_magic::wasm_object) + return false; + + uint8_t *Ptr = data_sp->GetBytes() + sizeof(llvm::wasm::WasmMagic); + + uint32_t version = llvm::support::endian::read32le(Ptr); + return version == llvm::wasm::WasmVersion; +} + +static llvm::Optional<ConstString> +GetWasmString(llvm::DataExtractor &data, llvm::DataExtractor::Cursor &c) { + // A Wasm string is encoded as a vector of UTF-8 codes. + // Vectors are encoded with their u32 length followed by the element + // sequence. + uint64_t len = data.getULEB128(c); + if (!c) { + consumeError(c.takeError()); + return llvm::None; + } + + if (len >= (uint64_t(1) << 32)) { + return llvm::None; + } + + llvm::SmallVector<uint8_t, 32> str_storage; + data.getU8(c, str_storage, len); + if (!c) { + consumeError(c.takeError()); + return llvm::None; + } + + llvm::StringRef str = toStringRef(makeArrayRef(str_storage)); + return ConstString(str); +} + +char ObjectFileWasm::ID; + +void ObjectFileWasm::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + GetPluginDescriptionStatic(), CreateInstance, + CreateMemoryInstance, GetModuleSpecifications); +} + +void ObjectFileWasm::Terminate() { + PluginManager::UnregisterPlugin(CreateInstance); +} + +ConstString ObjectFileWasm::GetPluginNameStatic() { + static ConstString g_name("wasm"); + return g_name; +} + +ObjectFile * +ObjectFileWasm::CreateInstance(const ModuleSP &module_sp, DataBufferSP &data_sp, + offset_t data_offset, const FileSpec *file, + offset_t file_offset, offset_t length) { + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + + if (!data_sp) { + data_sp = MapFileData(*file, length, file_offset); + if (!data_sp) { + LLDB_LOGF(log, "Failed to create ObjectFileWasm instance for file %s", + file->GetPath().c_str()); + return nullptr; + } + data_offset = 0; + } + + assert(data_sp); + if (!ValidateModuleHeader(data_sp)) { + LLDB_LOGF(log, + "Failed to create ObjectFileWasm instance: invalid Wasm header"); + return nullptr; + } + + // Update the data to contain the entire file if it doesn't contain it + // already. + if (data_sp->GetByteSize() < length) { + data_sp = MapFileData(*file, length, file_offset); + if (!data_sp) { + LLDB_LOGF(log, + "Failed to create ObjectFileWasm instance: cannot read file %s", + file->GetPath().c_str()); + return nullptr; + } + data_offset = 0; + } + + std::unique_ptr<ObjectFileWasm> objfile_up(new ObjectFileWasm( + module_sp, data_sp, data_offset, file, file_offset, length)); + ArchSpec spec = objfile_up->GetArchitecture(); + if (spec && objfile_up->SetModulesArchitecture(spec)) { + LLDB_LOGF(log, + "%p ObjectFileWasm::CreateInstance() module = %p (%s), file = %s", + static_cast<void *>(objfile_up.get()), + static_cast<void *>(objfile_up->GetModule().get()), + objfile_up->GetModule()->GetSpecificationDescription().c_str(), + file ? file->GetPath().c_str() : "<NULL>"); + return objfile_up.release(); + } + + LLDB_LOGF(log, "Failed to create ObjectFileWasm instance"); + return nullptr; +} + +ObjectFile *ObjectFileWasm::CreateMemoryInstance(const ModuleSP &module_sp, + DataBufferSP &data_sp, + const ProcessSP &process_sp, + addr_t header_addr) { + if (!ValidateModuleHeader(data_sp)) + return nullptr; + + std::unique_ptr<ObjectFileWasm> objfile_up( + new ObjectFileWasm(module_sp, data_sp, process_sp, header_addr)); + ArchSpec spec = objfile_up->GetArchitecture(); + if (spec && objfile_up->SetModulesArchitecture(spec)) + return objfile_up.release(); + return nullptr; +} + +bool ObjectFileWasm::DecodeNextSection(lldb::offset_t *offset_ptr) { + // Buffer sufficient to read a section header and find the pointer to the next + // section. + const uint32_t kBufferSize = 1024; + DataExtractor section_header_data = ReadImageData(*offset_ptr, kBufferSize); + + llvm::DataExtractor data = section_header_data.GetAsLLVM(); + llvm::DataExtractor::Cursor c(0); + + // Each section consists of: + // - a one-byte section id, + // - the u32 size of the contents, in bytes, + // - the actual contents. + uint8_t section_id = data.getU8(c); + uint64_t payload_len = data.getULEB128(c); + if (!c) + return !llvm::errorToBool(c.takeError()); + + if (payload_len >= (uint64_t(1) << 32)) + return false; + + if (section_id == llvm::wasm::WASM_SEC_CUSTOM) { + // Custom sections have the id 0. Their contents consist of a name + // identifying the custom section, followed by an uninterpreted sequence + // of bytes. + lldb::offset_t prev_offset = c.tell(); + llvm::Optional<ConstString> sect_name = GetWasmString(data, c); + if (!sect_name) + return false; + + if (payload_len < c.tell() - prev_offset) + return false; + + uint32_t section_length = payload_len - (c.tell() - prev_offset); + m_sect_infos.push_back(section_info{*offset_ptr + c.tell(), section_length, + section_id, *sect_name}); + *offset_ptr += (c.tell() + section_length); + } else if (section_id <= llvm::wasm::WASM_SEC_EVENT) { + m_sect_infos.push_back(section_info{*offset_ptr + c.tell(), + static_cast<uint32_t>(payload_len), + section_id, ConstString()}); + *offset_ptr += (c.tell() + payload_len); + } else { + // Invalid section id. + return false; + } + return true; +} + +bool ObjectFileWasm::DecodeSections() { + lldb::offset_t offset = kWasmHeaderSize; + if (IsInMemory()) { + offset += m_memory_addr; + } + + while (DecodeNextSection(&offset)) + ; + return true; +} + +size_t ObjectFileWasm::GetModuleSpecifications( + const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset, + offset_t file_offset, offset_t length, ModuleSpecList &specs) { + if (!ValidateModuleHeader(data_sp)) { + return 0; + } + + ModuleSpec spec(file, ArchSpec("wasm32-unknown-unknown-wasm")); + specs.Append(spec); + return 1; +} + +ObjectFileWasm::ObjectFileWasm(const ModuleSP &module_sp, DataBufferSP &data_sp, + offset_t data_offset, const FileSpec *file, + offset_t offset, offset_t length) + : ObjectFile(module_sp, file, offset, length, data_sp, data_offset), + m_arch("wasm32-unknown-unknown-wasm") { + m_data.SetAddressByteSize(4); +} + +ObjectFileWasm::ObjectFileWasm(const lldb::ModuleSP &module_sp, + lldb::DataBufferSP &header_data_sp, + const lldb::ProcessSP &process_sp, + lldb::addr_t header_addr) + : ObjectFile(module_sp, process_sp, header_addr, header_data_sp), + m_arch("wasm32-unknown-unknown-wasm") {} + +bool ObjectFileWasm::ParseHeader() { + // We already parsed the header during initialization. + return true; +} + +Symtab *ObjectFileWasm::GetSymtab() { return nullptr; } + +void ObjectFileWasm::CreateSections(SectionList &unified_section_list) { + if (m_sections_up) + return; + + m_sections_up = std::make_unique<SectionList>(); + + if (m_sect_infos.empty()) { + DecodeSections(); + } + + for (const section_info §_info : m_sect_infos) { + SectionType section_type = eSectionTypeOther; + ConstString section_name; + offset_t file_offset = sect_info.offset & 0xffffffff; + addr_t vm_addr = file_offset; + size_t vm_size = sect_info.size; + + if (llvm::wasm::WASM_SEC_CODE == sect_info.id) { + section_type = eSectionTypeCode; + section_name = ConstString("code"); + + // A code address in DWARF for WebAssembly is the offset of an + // instruction relative within the Code section of the WebAssembly file. + // For this reason Section::GetFileAddress() must return zero for the + // Code section. + vm_addr = 0; + } else { + section_type = + llvm::StringSwitch<SectionType>(sect_info.name.GetStringRef()) + .Case(".debug_abbrev", eSectionTypeDWARFDebugAbbrev) + .Case(".debug_addr", eSectionTypeDWARFDebugAddr) + .Case(".debug_aranges", eSectionTypeDWARFDebugAranges) + .Case(".debug_cu_index", eSectionTypeDWARFDebugCuIndex) + .Case(".debug_frame", eSectionTypeDWARFDebugFrame) + .Case(".debug_info", eSectionTypeDWARFDebugInfo) + .Case(".debug_line", eSectionTypeDWARFDebugLine) + .Case(".debug_line_str", eSectionTypeDWARFDebugLineStr) + .Case(".debug_loc", eSectionTypeDWARFDebugLoc) + .Case(".debug_loclists", eSectionTypeDWARFDebugLocLists) + .Case(".debug_macinfo", eSectionTypeDWARFDebugMacInfo) + .Case(".debug_macro", eSectionTypeDWARFDebugMacro) + .Case(".debug_names", eSectionTypeDWARFDebugNames) + .Case(".debug_pubnames", eSectionTypeDWARFDebugPubNames) + .Case(".debug_pubtypes", eSectionTypeDWARFDebugPubTypes) + .Case(".debug_ranges", eSectionTypeDWARFDebugRanges) + .Case(".debug_rnglists", eSectionTypeDWARFDebugRngLists) + .Case(".debug_str", eSectionTypeDWARFDebugStr) + .Case(".debug_str_offsets", eSectionTypeDWARFDebugStrOffsets) + .Case(".debug_types", eSectionTypeDWARFDebugTypes) + .Default(eSectionTypeOther); + if (section_type == eSectionTypeOther) + continue; + section_name = sect_info.name; + if (!IsInMemory()) { + vm_size = 0; + vm_addr = 0; + } + } + + SectionSP section_sp( + new Section(GetModule(), // Module to which this section belongs. + this, // ObjectFile to which this section belongs and + // should read section data from. + section_type, // Section ID. + section_name, // Section name. + section_type, // Section type. + vm_addr, // VM address. + vm_size, // VM size in bytes of this section. + file_offset, // Offset of this section in the file. + sect_info.size, // Size of the section as found in the file. + 0, // Alignment of the section + 0, // Flags for this section. + 1)); // Number of host bytes per target byte + m_sections_up->AddSection(section_sp); + unified_section_list.AddSection(section_sp); + } +} + +bool ObjectFileWasm::SetLoadAddress(Target &target, lldb::addr_t load_address, + bool value_is_offset) { + /// In WebAssembly, linear memory is disjointed from code space. The VM can + /// load multiple instances of a module, which logically share the same code. + /// We represent a wasm32 code address with 64-bits, like: + /// 63 32 31 0 + /// +---------------+---------------+ + /// + module_id | offset | + /// +---------------+---------------+ + /// where the lower 32 bits represent a module offset (relative to the module + /// start not to the beginning of the code section) and the higher 32 bits + /// uniquely identify the module in the WebAssembly VM. + /// In other words, we assume that each WebAssembly module is loaded by the + /// engine at a 64-bit address that starts at the boundary of 4GB pages, like + /// 0x0000000400000000 for module_id == 4. + /// These 64-bit addresses will be used to request code ranges for a specific + /// module from the WebAssembly engine. + + assert(m_memory_addr == LLDB_INVALID_ADDRESS || + m_memory_addr == load_address); + + ModuleSP module_sp = GetModule(); + if (!module_sp) + return false; + + DecodeSections(); + + size_t num_loaded_sections = 0; + SectionList *section_list = GetSectionList(); + if (!section_list) + return false; + + const size_t num_sections = section_list->GetSize(); + for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) { + SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); + if (target.SetSectionLoadAddress( + section_sp, load_address | section_sp->GetFileOffset())) { + ++num_loaded_sections; + } + } + + return num_loaded_sections > 0; +} + +DataExtractor ObjectFileWasm::ReadImageData(offset_t offset, uint32_t size) { + DataExtractor data; + if (m_file) { + if (offset < GetByteSize()) { + size = std::min(static_cast<uint64_t>(size), GetByteSize() - offset); + auto buffer_sp = MapFileData(m_file, size, offset); + return DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize()); + } + } else { + ProcessSP process_sp(m_process_wp.lock()); + if (process_sp) { + auto data_up = std::make_unique<DataBufferHeap>(size, 0); + Status readmem_error; + size_t bytes_read = process_sp->ReadMemory( + offset, data_up->GetBytes(), data_up->GetByteSize(), readmem_error); + if (bytes_read > 0) { + DataBufferSP buffer_sp(data_up.release()); + data.SetData(buffer_sp, 0, buffer_sp->GetByteSize()); + } + } + } + + data.SetByteOrder(GetByteOrder()); + return data; +} + +llvm::Optional<FileSpec> ObjectFileWasm::GetExternalDebugInfoFileSpec() { + static ConstString g_sect_name_external_debug_info("external_debug_info"); + + for (const section_info §_info : m_sect_infos) { + if (g_sect_name_external_debug_info == sect_info.name) { + const uint32_t kBufferSize = 1024; + DataExtractor section_header_data = + ReadImageData(sect_info.offset, kBufferSize); + llvm::DataExtractor data = section_header_data.GetAsLLVM(); + llvm::DataExtractor::Cursor c(0); + llvm::Optional<ConstString> symbols_url = GetWasmString(data, c); + if (symbols_url) + return FileSpec(symbols_url->GetStringRef()); + } + } + return llvm::None; +} + +void ObjectFileWasm::Dump(Stream *s) { + ModuleSP module_sp(GetModule()); + if (!module_sp) + return; + + std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); + + llvm::raw_ostream &ostream = s->AsRawOstream(); + ostream << static_cast<void *>(this) << ": "; + s->Indent(); + ostream << "ObjectFileWasm, file = '"; + m_file.Dump(ostream); + ostream << "', arch = "; + ostream << GetArchitecture().GetArchitectureName() << "\n"; + + SectionList *sections = GetSectionList(); + if (sections) { + sections->Dump(s->AsRawOstream(), s->GetIndentLevel(), nullptr, true, + UINT32_MAX); + } + ostream << "\n"; + DumpSectionHeaders(ostream); + ostream << "\n"; +} + +void ObjectFileWasm::DumpSectionHeader(llvm::raw_ostream &ostream, + const section_info_t &sh) { + ostream << llvm::left_justify(sh.name.GetStringRef(), 16) << " " + << llvm::format_hex(sh.offset, 10) << " " + << llvm::format_hex(sh.size, 10) << " " << llvm::format_hex(sh.id, 6) + << "\n"; +} + +void ObjectFileWasm::DumpSectionHeaders(llvm::raw_ostream &ostream) { + ostream << "Section Headers\n"; + ostream << "IDX name addr size id\n"; + ostream << "==== ---------------- ---------- ---------- ------\n"; + + uint32_t idx = 0; + for (auto pos = m_sect_infos.begin(); pos != m_sect_infos.end(); + ++pos, ++idx) { + ostream << "[" << llvm::format_decimal(idx, 2) << "] "; + ObjectFileWasm::DumpSectionHeader(ostream, *pos); + } +} diff --git a/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h new file mode 100644 index 0000000000000..b6e906a7b15f5 --- /dev/null +++ b/lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h @@ -0,0 +1,151 @@ +//===-- ObjectFileWasm.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_SOURCE_PLUGINS_OBJECTFILE_WASM_OBJECTFILEWASM_H +#define LLDB_SOURCE_PLUGINS_OBJECTFILE_WASM_OBJECTFILEWASM_H + +#include "lldb/Symbol/ObjectFile.h" +#include "lldb/Utility/ArchSpec.h" + +namespace lldb_private { +namespace wasm { + +/// Generic Wasm object file reader. +/// +/// This class provides a generic wasm32 reader plugin implementing the +/// ObjectFile protocol. +class ObjectFileWasm : public ObjectFile { +public: + static void Initialize(); + static void Terminate(); + + static ConstString GetPluginNameStatic(); + static const char *GetPluginDescriptionStatic() { + return "WebAssembly object file reader."; + } + + static ObjectFile * + CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, const FileSpec *file, + lldb::offset_t file_offset, lldb::offset_t length); + + static ObjectFile *CreateMemoryInstance(const lldb::ModuleSP &module_sp, + lldb::DataBufferSP &data_sp, + const lldb::ProcessSP &process_sp, + lldb::addr_t header_addr); + + static size_t GetModuleSpecifications(const FileSpec &file, + lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, + lldb::offset_t file_offset, + lldb::offset_t length, + ModuleSpecList &specs); + + /// PluginInterface protocol. + /// \{ + ConstString GetPluginName() override { return GetPluginNameStatic(); } + uint32_t GetPluginVersion() override { return 1; } + /// \} + + /// LLVM RTTI support + /// \{ + static char ID; + bool isA(const void *ClassID) const override { + return ClassID == &ID || ObjectFile::isA(ClassID); + } + static bool classof(const ObjectFile *obj) { return obj->isA(&ID); } + /// \} + + /// ObjectFile Protocol. + /// \{ + bool ParseHeader() override; + + lldb::ByteOrder GetByteOrder() const override { + return m_arch.GetByteOrder(); + } + + bool IsExecutable() const override { return false; } + + uint32_t GetAddressByteSize() const override { + return m_arch.GetAddressByteSize(); + } + + AddressClass GetAddressClass(lldb::addr_t file_addr) override { + return AddressClass::eInvalid; + } + + Symtab *GetSymtab() override; + + bool IsStripped() override { return !!GetExternalDebugInfoFileSpec(); } + + void CreateSections(SectionList &unified_section_list) override; + + void Dump(Stream *s) override; + + ArchSpec GetArchitecture() override { return m_arch; } + + UUID GetUUID() override { return m_uuid; } + + uint32_t GetDependentModules(FileSpecList &files) override { return 0; } + + Type CalculateType() override { return eTypeSharedLibrary; } + + Strata CalculateStrata() override { return eStrataUser; } + + bool SetLoadAddress(lldb_private::Target &target, lldb::addr_t value, + bool value_is_offset) override; + + lldb_private::Address GetBaseAddress() override { + return IsInMemory() ? Address(m_memory_addr) : Address(0); + } + /// \} + + /// A Wasm module that has external DWARF debug information should contain a + /// custom section named "external_debug_info", whose payload is an UTF-8 + /// encoded string that points to a Wasm module that contains the debug + /// information for this module. + llvm::Optional<FileSpec> GetExternalDebugInfoFileSpec(); + +private: + ObjectFileWasm(const lldb::ModuleSP &module_sp, lldb::DataBufferSP &data_sp, + lldb::offset_t data_offset, const FileSpec *file, + lldb::offset_t offset, lldb::offset_t length); + ObjectFileWasm(const lldb::ModuleSP &module_sp, + lldb::DataBufferSP &header_data_sp, + const lldb::ProcessSP &process_sp, lldb::addr_t header_addr); + + /// Wasm section decoding routines. + /// \{ + bool DecodeNextSection(lldb::offset_t *offset_ptr); + bool DecodeSections(); + /// \} + + /// Read a range of bytes from the Wasm module. + DataExtractor ReadImageData(lldb::offset_t offset, uint32_t size); + + typedef struct section_info { + lldb::offset_t offset; + uint32_t size; + uint32_t id; + ConstString name; + } section_info_t; + + /// Wasm section header dump routines. + /// \{ + void DumpSectionHeader(llvm::raw_ostream &ostream, const section_info_t &sh); + void DumpSectionHeaders(llvm::raw_ostream &ostream); + /// \} + + std::vector<section_info_t> m_sect_infos; + ArchSpec m_arch; + UUID m_uuid; +}; + +} // namespace wasm +} // namespace lldb_private +#endif // LLDB_SOURCE_PLUGINS_OBJECTFILE_WASM_OBJECTFILEWASM_H |