15ffd83dbSDimitry Andric //===-- ObjectFileWasm.cpp ------------------------------------------------===//
25ffd83dbSDimitry Andric //
35ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65ffd83dbSDimitry Andric //
75ffd83dbSDimitry Andric //===----------------------------------------------------------------------===//
85ffd83dbSDimitry Andric
95ffd83dbSDimitry Andric #include "ObjectFileWasm.h"
105ffd83dbSDimitry Andric #include "lldb/Core/Module.h"
115ffd83dbSDimitry Andric #include "lldb/Core/ModuleSpec.h"
125ffd83dbSDimitry Andric #include "lldb/Core/PluginManager.h"
135ffd83dbSDimitry Andric #include "lldb/Core/Section.h"
145ffd83dbSDimitry Andric #include "lldb/Target/Process.h"
155ffd83dbSDimitry Andric #include "lldb/Target/SectionLoadList.h"
165ffd83dbSDimitry Andric #include "lldb/Target/Target.h"
175ffd83dbSDimitry Andric #include "lldb/Utility/DataBufferHeap.h"
185ffd83dbSDimitry Andric #include "lldb/Utility/Log.h"
195ffd83dbSDimitry Andric #include "llvm/ADT/ArrayRef.h"
205ffd83dbSDimitry Andric #include "llvm/ADT/SmallVector.h"
215ffd83dbSDimitry Andric #include "llvm/ADT/StringRef.h"
225ffd83dbSDimitry Andric #include "llvm/BinaryFormat/Magic.h"
235ffd83dbSDimitry Andric #include "llvm/BinaryFormat/Wasm.h"
245ffd83dbSDimitry Andric #include "llvm/Support/Endian.h"
255ffd83dbSDimitry Andric #include "llvm/Support/Format.h"
265ffd83dbSDimitry Andric
275ffd83dbSDimitry Andric using namespace lldb;
285ffd83dbSDimitry Andric using namespace lldb_private;
295ffd83dbSDimitry Andric using namespace lldb_private::wasm;
305ffd83dbSDimitry Andric
315ffd83dbSDimitry Andric LLDB_PLUGIN_DEFINE(ObjectFileWasm)
325ffd83dbSDimitry Andric
335ffd83dbSDimitry Andric static const uint32_t kWasmHeaderSize =
345ffd83dbSDimitry Andric sizeof(llvm::wasm::WasmMagic) + sizeof(llvm::wasm::WasmVersion);
355ffd83dbSDimitry Andric
365ffd83dbSDimitry Andric /// Checks whether the data buffer starts with a valid Wasm module header.
ValidateModuleHeader(const DataBufferSP & data_sp)375ffd83dbSDimitry Andric static bool ValidateModuleHeader(const DataBufferSP &data_sp) {
385ffd83dbSDimitry Andric if (!data_sp || data_sp->GetByteSize() < kWasmHeaderSize)
395ffd83dbSDimitry Andric return false;
405ffd83dbSDimitry Andric
415ffd83dbSDimitry Andric if (llvm::identify_magic(toStringRef(data_sp->GetData())) !=
425ffd83dbSDimitry Andric llvm::file_magic::wasm_object)
435ffd83dbSDimitry Andric return false;
445ffd83dbSDimitry Andric
455ffd83dbSDimitry Andric uint8_t *Ptr = data_sp->GetBytes() + sizeof(llvm::wasm::WasmMagic);
465ffd83dbSDimitry Andric
475ffd83dbSDimitry Andric uint32_t version = llvm::support::endian::read32le(Ptr);
485ffd83dbSDimitry Andric return version == llvm::wasm::WasmVersion;
495ffd83dbSDimitry Andric }
505ffd83dbSDimitry Andric
515ffd83dbSDimitry Andric static llvm::Optional<ConstString>
GetWasmString(llvm::DataExtractor & data,llvm::DataExtractor::Cursor & c)525ffd83dbSDimitry Andric GetWasmString(llvm::DataExtractor &data, llvm::DataExtractor::Cursor &c) {
535ffd83dbSDimitry Andric // A Wasm string is encoded as a vector of UTF-8 codes.
545ffd83dbSDimitry Andric // Vectors are encoded with their u32 length followed by the element
555ffd83dbSDimitry Andric // sequence.
565ffd83dbSDimitry Andric uint64_t len = data.getULEB128(c);
575ffd83dbSDimitry Andric if (!c) {
585ffd83dbSDimitry Andric consumeError(c.takeError());
595ffd83dbSDimitry Andric return llvm::None;
605ffd83dbSDimitry Andric }
615ffd83dbSDimitry Andric
625ffd83dbSDimitry Andric if (len >= (uint64_t(1) << 32)) {
635ffd83dbSDimitry Andric return llvm::None;
645ffd83dbSDimitry Andric }
655ffd83dbSDimitry Andric
665ffd83dbSDimitry Andric llvm::SmallVector<uint8_t, 32> str_storage;
675ffd83dbSDimitry Andric data.getU8(c, str_storage, len);
685ffd83dbSDimitry Andric if (!c) {
695ffd83dbSDimitry Andric consumeError(c.takeError());
705ffd83dbSDimitry Andric return llvm::None;
715ffd83dbSDimitry Andric }
725ffd83dbSDimitry Andric
735ffd83dbSDimitry Andric llvm::StringRef str = toStringRef(makeArrayRef(str_storage));
745ffd83dbSDimitry Andric return ConstString(str);
755ffd83dbSDimitry Andric }
765ffd83dbSDimitry Andric
775ffd83dbSDimitry Andric char ObjectFileWasm::ID;
785ffd83dbSDimitry Andric
Initialize()795ffd83dbSDimitry Andric void ObjectFileWasm::Initialize() {
805ffd83dbSDimitry Andric PluginManager::RegisterPlugin(GetPluginNameStatic(),
815ffd83dbSDimitry Andric GetPluginDescriptionStatic(), CreateInstance,
825ffd83dbSDimitry Andric CreateMemoryInstance, GetModuleSpecifications);
835ffd83dbSDimitry Andric }
845ffd83dbSDimitry Andric
Terminate()855ffd83dbSDimitry Andric void ObjectFileWasm::Terminate() {
865ffd83dbSDimitry Andric PluginManager::UnregisterPlugin(CreateInstance);
875ffd83dbSDimitry Andric }
885ffd83dbSDimitry Andric
GetPluginNameStatic()895ffd83dbSDimitry Andric ConstString ObjectFileWasm::GetPluginNameStatic() {
905ffd83dbSDimitry Andric static ConstString g_name("wasm");
915ffd83dbSDimitry Andric return g_name;
925ffd83dbSDimitry Andric }
935ffd83dbSDimitry Andric
945ffd83dbSDimitry Andric ObjectFile *
CreateInstance(const ModuleSP & module_sp,DataBufferSP & data_sp,offset_t data_offset,const FileSpec * file,offset_t file_offset,offset_t length)955ffd83dbSDimitry Andric ObjectFileWasm::CreateInstance(const ModuleSP &module_sp, DataBufferSP &data_sp,
965ffd83dbSDimitry Andric offset_t data_offset, const FileSpec *file,
975ffd83dbSDimitry Andric offset_t file_offset, offset_t length) {
985ffd83dbSDimitry Andric Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT));
995ffd83dbSDimitry Andric
1005ffd83dbSDimitry Andric if (!data_sp) {
1015ffd83dbSDimitry Andric data_sp = MapFileData(*file, length, file_offset);
1025ffd83dbSDimitry Andric if (!data_sp) {
1035ffd83dbSDimitry Andric LLDB_LOGF(log, "Failed to create ObjectFileWasm instance for file %s",
1045ffd83dbSDimitry Andric file->GetPath().c_str());
1055ffd83dbSDimitry Andric return nullptr;
1065ffd83dbSDimitry Andric }
1075ffd83dbSDimitry Andric data_offset = 0;
1085ffd83dbSDimitry Andric }
1095ffd83dbSDimitry Andric
1105ffd83dbSDimitry Andric assert(data_sp);
1115ffd83dbSDimitry Andric if (!ValidateModuleHeader(data_sp)) {
1125ffd83dbSDimitry Andric LLDB_LOGF(log,
1135ffd83dbSDimitry Andric "Failed to create ObjectFileWasm instance: invalid Wasm header");
1145ffd83dbSDimitry Andric return nullptr;
1155ffd83dbSDimitry Andric }
1165ffd83dbSDimitry Andric
1175ffd83dbSDimitry Andric // Update the data to contain the entire file if it doesn't contain it
1185ffd83dbSDimitry Andric // already.
1195ffd83dbSDimitry Andric if (data_sp->GetByteSize() < length) {
1205ffd83dbSDimitry Andric data_sp = MapFileData(*file, length, file_offset);
1215ffd83dbSDimitry Andric if (!data_sp) {
1225ffd83dbSDimitry Andric LLDB_LOGF(log,
1235ffd83dbSDimitry Andric "Failed to create ObjectFileWasm instance: cannot read file %s",
1245ffd83dbSDimitry Andric file->GetPath().c_str());
1255ffd83dbSDimitry Andric return nullptr;
1265ffd83dbSDimitry Andric }
1275ffd83dbSDimitry Andric data_offset = 0;
1285ffd83dbSDimitry Andric }
1295ffd83dbSDimitry Andric
1305ffd83dbSDimitry Andric std::unique_ptr<ObjectFileWasm> objfile_up(new ObjectFileWasm(
1315ffd83dbSDimitry Andric module_sp, data_sp, data_offset, file, file_offset, length));
1325ffd83dbSDimitry Andric ArchSpec spec = objfile_up->GetArchitecture();
1335ffd83dbSDimitry Andric if (spec && objfile_up->SetModulesArchitecture(spec)) {
1345ffd83dbSDimitry Andric LLDB_LOGF(log,
1355ffd83dbSDimitry Andric "%p ObjectFileWasm::CreateInstance() module = %p (%s), file = %s",
1365ffd83dbSDimitry Andric static_cast<void *>(objfile_up.get()),
1375ffd83dbSDimitry Andric static_cast<void *>(objfile_up->GetModule().get()),
1385ffd83dbSDimitry Andric objfile_up->GetModule()->GetSpecificationDescription().c_str(),
1395ffd83dbSDimitry Andric file ? file->GetPath().c_str() : "<NULL>");
1405ffd83dbSDimitry Andric return objfile_up.release();
1415ffd83dbSDimitry Andric }
1425ffd83dbSDimitry Andric
1435ffd83dbSDimitry Andric LLDB_LOGF(log, "Failed to create ObjectFileWasm instance");
1445ffd83dbSDimitry Andric return nullptr;
1455ffd83dbSDimitry Andric }
1465ffd83dbSDimitry Andric
CreateMemoryInstance(const ModuleSP & module_sp,DataBufferSP & data_sp,const ProcessSP & process_sp,addr_t header_addr)1475ffd83dbSDimitry Andric ObjectFile *ObjectFileWasm::CreateMemoryInstance(const ModuleSP &module_sp,
1485ffd83dbSDimitry Andric DataBufferSP &data_sp,
1495ffd83dbSDimitry Andric const ProcessSP &process_sp,
1505ffd83dbSDimitry Andric addr_t header_addr) {
1515ffd83dbSDimitry Andric if (!ValidateModuleHeader(data_sp))
1525ffd83dbSDimitry Andric return nullptr;
1535ffd83dbSDimitry Andric
1545ffd83dbSDimitry Andric std::unique_ptr<ObjectFileWasm> objfile_up(
1555ffd83dbSDimitry Andric new ObjectFileWasm(module_sp, data_sp, process_sp, header_addr));
1565ffd83dbSDimitry Andric ArchSpec spec = objfile_up->GetArchitecture();
1575ffd83dbSDimitry Andric if (spec && objfile_up->SetModulesArchitecture(spec))
1585ffd83dbSDimitry Andric return objfile_up.release();
1595ffd83dbSDimitry Andric return nullptr;
1605ffd83dbSDimitry Andric }
1615ffd83dbSDimitry Andric
DecodeNextSection(lldb::offset_t * offset_ptr)1625ffd83dbSDimitry Andric bool ObjectFileWasm::DecodeNextSection(lldb::offset_t *offset_ptr) {
1635ffd83dbSDimitry Andric // Buffer sufficient to read a section header and find the pointer to the next
1645ffd83dbSDimitry Andric // section.
1655ffd83dbSDimitry Andric const uint32_t kBufferSize = 1024;
1665ffd83dbSDimitry Andric DataExtractor section_header_data = ReadImageData(*offset_ptr, kBufferSize);
1675ffd83dbSDimitry Andric
1685ffd83dbSDimitry Andric llvm::DataExtractor data = section_header_data.GetAsLLVM();
1695ffd83dbSDimitry Andric llvm::DataExtractor::Cursor c(0);
1705ffd83dbSDimitry Andric
1715ffd83dbSDimitry Andric // Each section consists of:
1725ffd83dbSDimitry Andric // - a one-byte section id,
1735ffd83dbSDimitry Andric // - the u32 size of the contents, in bytes,
1745ffd83dbSDimitry Andric // - the actual contents.
1755ffd83dbSDimitry Andric uint8_t section_id = data.getU8(c);
1765ffd83dbSDimitry Andric uint64_t payload_len = data.getULEB128(c);
1775ffd83dbSDimitry Andric if (!c)
1785ffd83dbSDimitry Andric return !llvm::errorToBool(c.takeError());
1795ffd83dbSDimitry Andric
1805ffd83dbSDimitry Andric if (payload_len >= (uint64_t(1) << 32))
1815ffd83dbSDimitry Andric return false;
1825ffd83dbSDimitry Andric
1835ffd83dbSDimitry Andric if (section_id == llvm::wasm::WASM_SEC_CUSTOM) {
1845ffd83dbSDimitry Andric // Custom sections have the id 0. Their contents consist of a name
1855ffd83dbSDimitry Andric // identifying the custom section, followed by an uninterpreted sequence
1865ffd83dbSDimitry Andric // of bytes.
1875ffd83dbSDimitry Andric lldb::offset_t prev_offset = c.tell();
1885ffd83dbSDimitry Andric llvm::Optional<ConstString> sect_name = GetWasmString(data, c);
1895ffd83dbSDimitry Andric if (!sect_name)
1905ffd83dbSDimitry Andric return false;
1915ffd83dbSDimitry Andric
1925ffd83dbSDimitry Andric if (payload_len < c.tell() - prev_offset)
1935ffd83dbSDimitry Andric return false;
1945ffd83dbSDimitry Andric
1955ffd83dbSDimitry Andric uint32_t section_length = payload_len - (c.tell() - prev_offset);
1965ffd83dbSDimitry Andric m_sect_infos.push_back(section_info{*offset_ptr + c.tell(), section_length,
1975ffd83dbSDimitry Andric section_id, *sect_name});
1985ffd83dbSDimitry Andric *offset_ptr += (c.tell() + section_length);
199*5f7ddb14SDimitry Andric } else if (section_id <= llvm::wasm::WASM_SEC_TAG) {
2005ffd83dbSDimitry Andric m_sect_infos.push_back(section_info{*offset_ptr + c.tell(),
2015ffd83dbSDimitry Andric static_cast<uint32_t>(payload_len),
2025ffd83dbSDimitry Andric section_id, ConstString()});
2035ffd83dbSDimitry Andric *offset_ptr += (c.tell() + payload_len);
2045ffd83dbSDimitry Andric } else {
2055ffd83dbSDimitry Andric // Invalid section id.
2065ffd83dbSDimitry Andric return false;
2075ffd83dbSDimitry Andric }
2085ffd83dbSDimitry Andric return true;
2095ffd83dbSDimitry Andric }
2105ffd83dbSDimitry Andric
DecodeSections()2115ffd83dbSDimitry Andric bool ObjectFileWasm::DecodeSections() {
2125ffd83dbSDimitry Andric lldb::offset_t offset = kWasmHeaderSize;
2135ffd83dbSDimitry Andric if (IsInMemory()) {
2145ffd83dbSDimitry Andric offset += m_memory_addr;
2155ffd83dbSDimitry Andric }
2165ffd83dbSDimitry Andric
2175ffd83dbSDimitry Andric while (DecodeNextSection(&offset))
2185ffd83dbSDimitry Andric ;
2195ffd83dbSDimitry Andric return true;
2205ffd83dbSDimitry Andric }
2215ffd83dbSDimitry Andric
GetModuleSpecifications(const FileSpec & file,DataBufferSP & data_sp,offset_t data_offset,offset_t file_offset,offset_t length,ModuleSpecList & specs)2225ffd83dbSDimitry Andric size_t ObjectFileWasm::GetModuleSpecifications(
2235ffd83dbSDimitry Andric const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset,
2245ffd83dbSDimitry Andric offset_t file_offset, offset_t length, ModuleSpecList &specs) {
2255ffd83dbSDimitry Andric if (!ValidateModuleHeader(data_sp)) {
2265ffd83dbSDimitry Andric return 0;
2275ffd83dbSDimitry Andric }
2285ffd83dbSDimitry Andric
2295ffd83dbSDimitry Andric ModuleSpec spec(file, ArchSpec("wasm32-unknown-unknown-wasm"));
2305ffd83dbSDimitry Andric specs.Append(spec);
2315ffd83dbSDimitry Andric return 1;
2325ffd83dbSDimitry Andric }
2335ffd83dbSDimitry Andric
ObjectFileWasm(const ModuleSP & module_sp,DataBufferSP & data_sp,offset_t data_offset,const FileSpec * file,offset_t offset,offset_t length)2345ffd83dbSDimitry Andric ObjectFileWasm::ObjectFileWasm(const ModuleSP &module_sp, DataBufferSP &data_sp,
2355ffd83dbSDimitry Andric offset_t data_offset, const FileSpec *file,
2365ffd83dbSDimitry Andric offset_t offset, offset_t length)
2375ffd83dbSDimitry Andric : ObjectFile(module_sp, file, offset, length, data_sp, data_offset),
2385ffd83dbSDimitry Andric m_arch("wasm32-unknown-unknown-wasm") {
2395ffd83dbSDimitry Andric m_data.SetAddressByteSize(4);
2405ffd83dbSDimitry Andric }
2415ffd83dbSDimitry Andric
ObjectFileWasm(const lldb::ModuleSP & module_sp,lldb::DataBufferSP & header_data_sp,const lldb::ProcessSP & process_sp,lldb::addr_t header_addr)2425ffd83dbSDimitry Andric ObjectFileWasm::ObjectFileWasm(const lldb::ModuleSP &module_sp,
2435ffd83dbSDimitry Andric lldb::DataBufferSP &header_data_sp,
2445ffd83dbSDimitry Andric const lldb::ProcessSP &process_sp,
2455ffd83dbSDimitry Andric lldb::addr_t header_addr)
2465ffd83dbSDimitry Andric : ObjectFile(module_sp, process_sp, header_addr, header_data_sp),
2475ffd83dbSDimitry Andric m_arch("wasm32-unknown-unknown-wasm") {}
2485ffd83dbSDimitry Andric
ParseHeader()2495ffd83dbSDimitry Andric bool ObjectFileWasm::ParseHeader() {
2505ffd83dbSDimitry Andric // We already parsed the header during initialization.
2515ffd83dbSDimitry Andric return true;
2525ffd83dbSDimitry Andric }
2535ffd83dbSDimitry Andric
GetSymtab()2545ffd83dbSDimitry Andric Symtab *ObjectFileWasm::GetSymtab() { return nullptr; }
2555ffd83dbSDimitry Andric
GetSectionTypeFromName(llvm::StringRef Name)256af732203SDimitry Andric static SectionType GetSectionTypeFromName(llvm::StringRef Name) {
257af732203SDimitry Andric if (Name.consume_front(".debug_") || Name.consume_front(".zdebug_")) {
258af732203SDimitry Andric return llvm::StringSwitch<SectionType>(Name)
259af732203SDimitry Andric .Case("abbrev", eSectionTypeDWARFDebugAbbrev)
260af732203SDimitry Andric .Case("abbrev.dwo", eSectionTypeDWARFDebugAbbrevDwo)
261af732203SDimitry Andric .Case("addr", eSectionTypeDWARFDebugAddr)
262af732203SDimitry Andric .Case("aranges", eSectionTypeDWARFDebugAranges)
263af732203SDimitry Andric .Case("cu_index", eSectionTypeDWARFDebugCuIndex)
264af732203SDimitry Andric .Case("frame", eSectionTypeDWARFDebugFrame)
265af732203SDimitry Andric .Case("info", eSectionTypeDWARFDebugInfo)
266af732203SDimitry Andric .Case("info.dwo", eSectionTypeDWARFDebugInfoDwo)
267af732203SDimitry Andric .Cases("line", "line.dwo", eSectionTypeDWARFDebugLine)
268af732203SDimitry Andric .Cases("line_str", "line_str.dwo", eSectionTypeDWARFDebugLineStr)
269af732203SDimitry Andric .Case("loc", eSectionTypeDWARFDebugLoc)
270af732203SDimitry Andric .Case("loc.dwo", eSectionTypeDWARFDebugLocDwo)
271af732203SDimitry Andric .Case("loclists", eSectionTypeDWARFDebugLocLists)
272af732203SDimitry Andric .Case("loclists.dwo", eSectionTypeDWARFDebugLocListsDwo)
273af732203SDimitry Andric .Case("macinfo", eSectionTypeDWARFDebugMacInfo)
274af732203SDimitry Andric .Cases("macro", "macro.dwo", eSectionTypeDWARFDebugMacro)
275af732203SDimitry Andric .Case("names", eSectionTypeDWARFDebugNames)
276af732203SDimitry Andric .Case("pubnames", eSectionTypeDWARFDebugPubNames)
277af732203SDimitry Andric .Case("pubtypes", eSectionTypeDWARFDebugPubTypes)
278af732203SDimitry Andric .Case("ranges", eSectionTypeDWARFDebugRanges)
279af732203SDimitry Andric .Case("rnglists", eSectionTypeDWARFDebugRngLists)
280af732203SDimitry Andric .Case("rnglists.dwo", eSectionTypeDWARFDebugRngListsDwo)
281af732203SDimitry Andric .Case("str", eSectionTypeDWARFDebugStr)
282af732203SDimitry Andric .Case("str.dwo", eSectionTypeDWARFDebugStrDwo)
283af732203SDimitry Andric .Case("str_offsets", eSectionTypeDWARFDebugStrOffsets)
284af732203SDimitry Andric .Case("str_offsets.dwo", eSectionTypeDWARFDebugStrOffsetsDwo)
285af732203SDimitry Andric .Case("tu_index", eSectionTypeDWARFDebugTuIndex)
286af732203SDimitry Andric .Case("types", eSectionTypeDWARFDebugTypes)
287af732203SDimitry Andric .Case("types.dwo", eSectionTypeDWARFDebugTypesDwo)
288af732203SDimitry Andric .Default(eSectionTypeOther);
289af732203SDimitry Andric }
290af732203SDimitry Andric return eSectionTypeOther;
291af732203SDimitry Andric }
292af732203SDimitry Andric
CreateSections(SectionList & unified_section_list)2935ffd83dbSDimitry Andric void ObjectFileWasm::CreateSections(SectionList &unified_section_list) {
2945ffd83dbSDimitry Andric if (m_sections_up)
2955ffd83dbSDimitry Andric return;
2965ffd83dbSDimitry Andric
2975ffd83dbSDimitry Andric m_sections_up = std::make_unique<SectionList>();
2985ffd83dbSDimitry Andric
2995ffd83dbSDimitry Andric if (m_sect_infos.empty()) {
3005ffd83dbSDimitry Andric DecodeSections();
3015ffd83dbSDimitry Andric }
3025ffd83dbSDimitry Andric
3035ffd83dbSDimitry Andric for (const section_info §_info : m_sect_infos) {
3045ffd83dbSDimitry Andric SectionType section_type = eSectionTypeOther;
3055ffd83dbSDimitry Andric ConstString section_name;
3065ffd83dbSDimitry Andric offset_t file_offset = sect_info.offset & 0xffffffff;
3075ffd83dbSDimitry Andric addr_t vm_addr = file_offset;
3085ffd83dbSDimitry Andric size_t vm_size = sect_info.size;
3095ffd83dbSDimitry Andric
3105ffd83dbSDimitry Andric if (llvm::wasm::WASM_SEC_CODE == sect_info.id) {
3115ffd83dbSDimitry Andric section_type = eSectionTypeCode;
3125ffd83dbSDimitry Andric section_name = ConstString("code");
3135ffd83dbSDimitry Andric
3145ffd83dbSDimitry Andric // A code address in DWARF for WebAssembly is the offset of an
3155ffd83dbSDimitry Andric // instruction relative within the Code section of the WebAssembly file.
3165ffd83dbSDimitry Andric // For this reason Section::GetFileAddress() must return zero for the
3175ffd83dbSDimitry Andric // Code section.
3185ffd83dbSDimitry Andric vm_addr = 0;
3195ffd83dbSDimitry Andric } else {
320af732203SDimitry Andric section_type = GetSectionTypeFromName(sect_info.name.GetStringRef());
3215ffd83dbSDimitry Andric if (section_type == eSectionTypeOther)
3225ffd83dbSDimitry Andric continue;
3235ffd83dbSDimitry Andric section_name = sect_info.name;
3245ffd83dbSDimitry Andric if (!IsInMemory()) {
3255ffd83dbSDimitry Andric vm_size = 0;
3265ffd83dbSDimitry Andric vm_addr = 0;
3275ffd83dbSDimitry Andric }
3285ffd83dbSDimitry Andric }
3295ffd83dbSDimitry Andric
3305ffd83dbSDimitry Andric SectionSP section_sp(
3315ffd83dbSDimitry Andric new Section(GetModule(), // Module to which this section belongs.
3325ffd83dbSDimitry Andric this, // ObjectFile to which this section belongs and
3335ffd83dbSDimitry Andric // should read section data from.
3345ffd83dbSDimitry Andric section_type, // Section ID.
3355ffd83dbSDimitry Andric section_name, // Section name.
3365ffd83dbSDimitry Andric section_type, // Section type.
3375ffd83dbSDimitry Andric vm_addr, // VM address.
3385ffd83dbSDimitry Andric vm_size, // VM size in bytes of this section.
3395ffd83dbSDimitry Andric file_offset, // Offset of this section in the file.
3405ffd83dbSDimitry Andric sect_info.size, // Size of the section as found in the file.
3415ffd83dbSDimitry Andric 0, // Alignment of the section
3425ffd83dbSDimitry Andric 0, // Flags for this section.
3435ffd83dbSDimitry Andric 1)); // Number of host bytes per target byte
3445ffd83dbSDimitry Andric m_sections_up->AddSection(section_sp);
3455ffd83dbSDimitry Andric unified_section_list.AddSection(section_sp);
3465ffd83dbSDimitry Andric }
3475ffd83dbSDimitry Andric }
3485ffd83dbSDimitry Andric
SetLoadAddress(Target & target,lldb::addr_t load_address,bool value_is_offset)3495ffd83dbSDimitry Andric bool ObjectFileWasm::SetLoadAddress(Target &target, lldb::addr_t load_address,
3505ffd83dbSDimitry Andric bool value_is_offset) {
3515ffd83dbSDimitry Andric /// In WebAssembly, linear memory is disjointed from code space. The VM can
3525ffd83dbSDimitry Andric /// load multiple instances of a module, which logically share the same code.
3535ffd83dbSDimitry Andric /// We represent a wasm32 code address with 64-bits, like:
3545ffd83dbSDimitry Andric /// 63 32 31 0
3555ffd83dbSDimitry Andric /// +---------------+---------------+
3565ffd83dbSDimitry Andric /// + module_id | offset |
3575ffd83dbSDimitry Andric /// +---------------+---------------+
3585ffd83dbSDimitry Andric /// where the lower 32 bits represent a module offset (relative to the module
3595ffd83dbSDimitry Andric /// start not to the beginning of the code section) and the higher 32 bits
3605ffd83dbSDimitry Andric /// uniquely identify the module in the WebAssembly VM.
3615ffd83dbSDimitry Andric /// In other words, we assume that each WebAssembly module is loaded by the
3625ffd83dbSDimitry Andric /// engine at a 64-bit address that starts at the boundary of 4GB pages, like
3635ffd83dbSDimitry Andric /// 0x0000000400000000 for module_id == 4.
3645ffd83dbSDimitry Andric /// These 64-bit addresses will be used to request code ranges for a specific
3655ffd83dbSDimitry Andric /// module from the WebAssembly engine.
3665ffd83dbSDimitry Andric
3675ffd83dbSDimitry Andric assert(m_memory_addr == LLDB_INVALID_ADDRESS ||
3685ffd83dbSDimitry Andric m_memory_addr == load_address);
3695ffd83dbSDimitry Andric
3705ffd83dbSDimitry Andric ModuleSP module_sp = GetModule();
3715ffd83dbSDimitry Andric if (!module_sp)
3725ffd83dbSDimitry Andric return false;
3735ffd83dbSDimitry Andric
3745ffd83dbSDimitry Andric DecodeSections();
3755ffd83dbSDimitry Andric
3765ffd83dbSDimitry Andric size_t num_loaded_sections = 0;
3775ffd83dbSDimitry Andric SectionList *section_list = GetSectionList();
3785ffd83dbSDimitry Andric if (!section_list)
3795ffd83dbSDimitry Andric return false;
3805ffd83dbSDimitry Andric
3815ffd83dbSDimitry Andric const size_t num_sections = section_list->GetSize();
3825ffd83dbSDimitry Andric for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) {
3835ffd83dbSDimitry Andric SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx));
3845ffd83dbSDimitry Andric if (target.SetSectionLoadAddress(
3855ffd83dbSDimitry Andric section_sp, load_address | section_sp->GetFileOffset())) {
3865ffd83dbSDimitry Andric ++num_loaded_sections;
3875ffd83dbSDimitry Andric }
3885ffd83dbSDimitry Andric }
3895ffd83dbSDimitry Andric
3905ffd83dbSDimitry Andric return num_loaded_sections > 0;
3915ffd83dbSDimitry Andric }
3925ffd83dbSDimitry Andric
ReadImageData(offset_t offset,uint32_t size)3935ffd83dbSDimitry Andric DataExtractor ObjectFileWasm::ReadImageData(offset_t offset, uint32_t size) {
3945ffd83dbSDimitry Andric DataExtractor data;
3955ffd83dbSDimitry Andric if (m_file) {
3965ffd83dbSDimitry Andric if (offset < GetByteSize()) {
3975ffd83dbSDimitry Andric size = std::min(static_cast<uint64_t>(size), GetByteSize() - offset);
3985ffd83dbSDimitry Andric auto buffer_sp = MapFileData(m_file, size, offset);
3995ffd83dbSDimitry Andric return DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize());
4005ffd83dbSDimitry Andric }
4015ffd83dbSDimitry Andric } else {
4025ffd83dbSDimitry Andric ProcessSP process_sp(m_process_wp.lock());
4035ffd83dbSDimitry Andric if (process_sp) {
4045ffd83dbSDimitry Andric auto data_up = std::make_unique<DataBufferHeap>(size, 0);
4055ffd83dbSDimitry Andric Status readmem_error;
4065ffd83dbSDimitry Andric size_t bytes_read = process_sp->ReadMemory(
4075ffd83dbSDimitry Andric offset, data_up->GetBytes(), data_up->GetByteSize(), readmem_error);
4085ffd83dbSDimitry Andric if (bytes_read > 0) {
4095ffd83dbSDimitry Andric DataBufferSP buffer_sp(data_up.release());
4105ffd83dbSDimitry Andric data.SetData(buffer_sp, 0, buffer_sp->GetByteSize());
4115ffd83dbSDimitry Andric }
4125ffd83dbSDimitry Andric }
4135ffd83dbSDimitry Andric }
4145ffd83dbSDimitry Andric
4155ffd83dbSDimitry Andric data.SetByteOrder(GetByteOrder());
4165ffd83dbSDimitry Andric return data;
4175ffd83dbSDimitry Andric }
4185ffd83dbSDimitry Andric
GetExternalDebugInfoFileSpec()4195ffd83dbSDimitry Andric llvm::Optional<FileSpec> ObjectFileWasm::GetExternalDebugInfoFileSpec() {
4205ffd83dbSDimitry Andric static ConstString g_sect_name_external_debug_info("external_debug_info");
4215ffd83dbSDimitry Andric
4225ffd83dbSDimitry Andric for (const section_info §_info : m_sect_infos) {
4235ffd83dbSDimitry Andric if (g_sect_name_external_debug_info == sect_info.name) {
4245ffd83dbSDimitry Andric const uint32_t kBufferSize = 1024;
4255ffd83dbSDimitry Andric DataExtractor section_header_data =
4265ffd83dbSDimitry Andric ReadImageData(sect_info.offset, kBufferSize);
4275ffd83dbSDimitry Andric llvm::DataExtractor data = section_header_data.GetAsLLVM();
4285ffd83dbSDimitry Andric llvm::DataExtractor::Cursor c(0);
4295ffd83dbSDimitry Andric llvm::Optional<ConstString> symbols_url = GetWasmString(data, c);
4305ffd83dbSDimitry Andric if (symbols_url)
4315ffd83dbSDimitry Andric return FileSpec(symbols_url->GetStringRef());
4325ffd83dbSDimitry Andric }
4335ffd83dbSDimitry Andric }
4345ffd83dbSDimitry Andric return llvm::None;
4355ffd83dbSDimitry Andric }
4365ffd83dbSDimitry Andric
Dump(Stream * s)4375ffd83dbSDimitry Andric void ObjectFileWasm::Dump(Stream *s) {
4385ffd83dbSDimitry Andric ModuleSP module_sp(GetModule());
4395ffd83dbSDimitry Andric if (!module_sp)
4405ffd83dbSDimitry Andric return;
4415ffd83dbSDimitry Andric
4425ffd83dbSDimitry Andric std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
4435ffd83dbSDimitry Andric
4445ffd83dbSDimitry Andric llvm::raw_ostream &ostream = s->AsRawOstream();
4455ffd83dbSDimitry Andric ostream << static_cast<void *>(this) << ": ";
4465ffd83dbSDimitry Andric s->Indent();
4475ffd83dbSDimitry Andric ostream << "ObjectFileWasm, file = '";
4485ffd83dbSDimitry Andric m_file.Dump(ostream);
4495ffd83dbSDimitry Andric ostream << "', arch = ";
4505ffd83dbSDimitry Andric ostream << GetArchitecture().GetArchitectureName() << "\n";
4515ffd83dbSDimitry Andric
4525ffd83dbSDimitry Andric SectionList *sections = GetSectionList();
4535ffd83dbSDimitry Andric if (sections) {
4545ffd83dbSDimitry Andric sections->Dump(s->AsRawOstream(), s->GetIndentLevel(), nullptr, true,
4555ffd83dbSDimitry Andric UINT32_MAX);
4565ffd83dbSDimitry Andric }
4575ffd83dbSDimitry Andric ostream << "\n";
4585ffd83dbSDimitry Andric DumpSectionHeaders(ostream);
4595ffd83dbSDimitry Andric ostream << "\n";
4605ffd83dbSDimitry Andric }
4615ffd83dbSDimitry Andric
DumpSectionHeader(llvm::raw_ostream & ostream,const section_info_t & sh)4625ffd83dbSDimitry Andric void ObjectFileWasm::DumpSectionHeader(llvm::raw_ostream &ostream,
4635ffd83dbSDimitry Andric const section_info_t &sh) {
4645ffd83dbSDimitry Andric ostream << llvm::left_justify(sh.name.GetStringRef(), 16) << " "
4655ffd83dbSDimitry Andric << llvm::format_hex(sh.offset, 10) << " "
4665ffd83dbSDimitry Andric << llvm::format_hex(sh.size, 10) << " " << llvm::format_hex(sh.id, 6)
4675ffd83dbSDimitry Andric << "\n";
4685ffd83dbSDimitry Andric }
4695ffd83dbSDimitry Andric
DumpSectionHeaders(llvm::raw_ostream & ostream)4705ffd83dbSDimitry Andric void ObjectFileWasm::DumpSectionHeaders(llvm::raw_ostream &ostream) {
4715ffd83dbSDimitry Andric ostream << "Section Headers\n";
4725ffd83dbSDimitry Andric ostream << "IDX name addr size id\n";
4735ffd83dbSDimitry Andric ostream << "==== ---------------- ---------- ---------- ------\n";
4745ffd83dbSDimitry Andric
4755ffd83dbSDimitry Andric uint32_t idx = 0;
4765ffd83dbSDimitry Andric for (auto pos = m_sect_infos.begin(); pos != m_sect_infos.end();
4775ffd83dbSDimitry Andric ++pos, ++idx) {
4785ffd83dbSDimitry Andric ostream << "[" << llvm::format_decimal(idx, 2) << "] ";
4795ffd83dbSDimitry Andric ObjectFileWasm::DumpSectionHeader(ostream, *pos);
4805ffd83dbSDimitry Andric }
4815ffd83dbSDimitry Andric }
482