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. 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> 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 795ffd83dbSDimitry Andric void ObjectFileWasm::Initialize() { 805ffd83dbSDimitry Andric PluginManager::RegisterPlugin(GetPluginNameStatic(), 815ffd83dbSDimitry Andric GetPluginDescriptionStatic(), CreateInstance, 825ffd83dbSDimitry Andric CreateMemoryInstance, GetModuleSpecifications); 835ffd83dbSDimitry Andric } 845ffd83dbSDimitry Andric 855ffd83dbSDimitry Andric void ObjectFileWasm::Terminate() { 865ffd83dbSDimitry Andric PluginManager::UnregisterPlugin(CreateInstance); 875ffd83dbSDimitry Andric } 885ffd83dbSDimitry Andric 895ffd83dbSDimitry Andric ConstString ObjectFileWasm::GetPluginNameStatic() { 905ffd83dbSDimitry Andric static ConstString g_name("wasm"); 915ffd83dbSDimitry Andric return g_name; 925ffd83dbSDimitry Andric } 935ffd83dbSDimitry Andric 945ffd83dbSDimitry Andric ObjectFile * 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 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 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); 1995ffd83dbSDimitry Andric } else if (section_id <= llvm::wasm::WASM_SEC_EVENT) { 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 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 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 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 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 2495ffd83dbSDimitry Andric bool ObjectFileWasm::ParseHeader() { 2505ffd83dbSDimitry Andric // We already parsed the header during initialization. 2515ffd83dbSDimitry Andric return true; 2525ffd83dbSDimitry Andric } 2535ffd83dbSDimitry Andric 2545ffd83dbSDimitry Andric Symtab *ObjectFileWasm::GetSymtab() { return nullptr; } 2555ffd83dbSDimitry Andric 256*e8d8bef9SDimitry Andric static SectionType GetSectionTypeFromName(llvm::StringRef Name) { 257*e8d8bef9SDimitry Andric if (Name.consume_front(".debug_") || Name.consume_front(".zdebug_")) { 258*e8d8bef9SDimitry Andric return llvm::StringSwitch<SectionType>(Name) 259*e8d8bef9SDimitry Andric .Case("abbrev", eSectionTypeDWARFDebugAbbrev) 260*e8d8bef9SDimitry Andric .Case("abbrev.dwo", eSectionTypeDWARFDebugAbbrevDwo) 261*e8d8bef9SDimitry Andric .Case("addr", eSectionTypeDWARFDebugAddr) 262*e8d8bef9SDimitry Andric .Case("aranges", eSectionTypeDWARFDebugAranges) 263*e8d8bef9SDimitry Andric .Case("cu_index", eSectionTypeDWARFDebugCuIndex) 264*e8d8bef9SDimitry Andric .Case("frame", eSectionTypeDWARFDebugFrame) 265*e8d8bef9SDimitry Andric .Case("info", eSectionTypeDWARFDebugInfo) 266*e8d8bef9SDimitry Andric .Case("info.dwo", eSectionTypeDWARFDebugInfoDwo) 267*e8d8bef9SDimitry Andric .Cases("line", "line.dwo", eSectionTypeDWARFDebugLine) 268*e8d8bef9SDimitry Andric .Cases("line_str", "line_str.dwo", eSectionTypeDWARFDebugLineStr) 269*e8d8bef9SDimitry Andric .Case("loc", eSectionTypeDWARFDebugLoc) 270*e8d8bef9SDimitry Andric .Case("loc.dwo", eSectionTypeDWARFDebugLocDwo) 271*e8d8bef9SDimitry Andric .Case("loclists", eSectionTypeDWARFDebugLocLists) 272*e8d8bef9SDimitry Andric .Case("loclists.dwo", eSectionTypeDWARFDebugLocListsDwo) 273*e8d8bef9SDimitry Andric .Case("macinfo", eSectionTypeDWARFDebugMacInfo) 274*e8d8bef9SDimitry Andric .Cases("macro", "macro.dwo", eSectionTypeDWARFDebugMacro) 275*e8d8bef9SDimitry Andric .Case("names", eSectionTypeDWARFDebugNames) 276*e8d8bef9SDimitry Andric .Case("pubnames", eSectionTypeDWARFDebugPubNames) 277*e8d8bef9SDimitry Andric .Case("pubtypes", eSectionTypeDWARFDebugPubTypes) 278*e8d8bef9SDimitry Andric .Case("ranges", eSectionTypeDWARFDebugRanges) 279*e8d8bef9SDimitry Andric .Case("rnglists", eSectionTypeDWARFDebugRngLists) 280*e8d8bef9SDimitry Andric .Case("rnglists.dwo", eSectionTypeDWARFDebugRngListsDwo) 281*e8d8bef9SDimitry Andric .Case("str", eSectionTypeDWARFDebugStr) 282*e8d8bef9SDimitry Andric .Case("str.dwo", eSectionTypeDWARFDebugStrDwo) 283*e8d8bef9SDimitry Andric .Case("str_offsets", eSectionTypeDWARFDebugStrOffsets) 284*e8d8bef9SDimitry Andric .Case("str_offsets.dwo", eSectionTypeDWARFDebugStrOffsetsDwo) 285*e8d8bef9SDimitry Andric .Case("tu_index", eSectionTypeDWARFDebugTuIndex) 286*e8d8bef9SDimitry Andric .Case("types", eSectionTypeDWARFDebugTypes) 287*e8d8bef9SDimitry Andric .Case("types.dwo", eSectionTypeDWARFDebugTypesDwo) 288*e8d8bef9SDimitry Andric .Default(eSectionTypeOther); 289*e8d8bef9SDimitry Andric } 290*e8d8bef9SDimitry Andric return eSectionTypeOther; 291*e8d8bef9SDimitry Andric } 292*e8d8bef9SDimitry Andric 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 { 320*e8d8bef9SDimitry 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 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 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 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 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 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 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