summaryrefslogtreecommitdiff
path: root/lldb/source/Plugins/ObjectFile
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins/ObjectFile')
-rw-r--r--lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.cpp4
-rw-r--r--lldb/source/Plugins/ObjectFile/Breakpad/BreakpadRecords.h6
-rw-r--r--lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.cpp4
-rw-r--r--lldb/source/Plugins/ObjectFile/Breakpad/ObjectFileBreakpad.h6
-rw-r--r--lldb/source/Plugins/ObjectFile/ELF/ELFHeader.cpp2
-rw-r--r--lldb/source/Plugins/ObjectFile/ELF/ELFHeader.h6
-rw-r--r--lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp42
-rw-r--r--lldb/source/Plugins/ObjectFile/ELF/ObjectFileELF.h9
-rw-r--r--lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.cpp11
-rw-r--r--lldb/source/Plugins/ObjectFile/JIT/ObjectFileJIT.h6
-rw-r--r--lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.cpp466
-rw-r--r--lldb/source/Plugins/ObjectFile/wasm/ObjectFileWasm.h151
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 b83b2efb492f..bd8eeedce57d 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 27bef975125d..1620a1210b84 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 3b9e0e2092a9..7a9163ddb880 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 cb4bba01fb71..8724feaa422d 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 aa9871071b0e..f0496beba2ef 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 bb228e269d40..963cc850736f 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 8b62afa18cd6..bca575b7f884 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 3b273896cb59..062271f1caf0 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 c55b96d9110b..93c2c9f945fe 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 c992683cfc3c..a3a1acea916a 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 000000000000..91150fa02ebc
--- /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 &sect_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 &sect_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 000000000000..b6e906a7b15f
--- /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