1*5ffd83dbSDimitry Andric //===-- ObjectFileWasm.cpp ------------------------------------------------===// 2*5ffd83dbSDimitry Andric // 3*5ffd83dbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*5ffd83dbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*5ffd83dbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*5ffd83dbSDimitry Andric // 7*5ffd83dbSDimitry Andric //===----------------------------------------------------------------------===// 8*5ffd83dbSDimitry Andric 9*5ffd83dbSDimitry Andric #include "ObjectFileWasm.h" 10*5ffd83dbSDimitry Andric #include "lldb/Core/Module.h" 11*5ffd83dbSDimitry Andric #include "lldb/Core/ModuleSpec.h" 12*5ffd83dbSDimitry Andric #include "lldb/Core/PluginManager.h" 13*5ffd83dbSDimitry Andric #include "lldb/Core/Section.h" 14*5ffd83dbSDimitry Andric #include "lldb/Target/Process.h" 15*5ffd83dbSDimitry Andric #include "lldb/Target/SectionLoadList.h" 16*5ffd83dbSDimitry Andric #include "lldb/Target/Target.h" 17*5ffd83dbSDimitry Andric #include "lldb/Utility/DataBufferHeap.h" 18*5ffd83dbSDimitry Andric #include "lldb/Utility/Log.h" 19*5ffd83dbSDimitry Andric #include "llvm/ADT/ArrayRef.h" 20*5ffd83dbSDimitry Andric #include "llvm/ADT/SmallVector.h" 21*5ffd83dbSDimitry Andric #include "llvm/ADT/StringRef.h" 22*5ffd83dbSDimitry Andric #include "llvm/BinaryFormat/Magic.h" 23*5ffd83dbSDimitry Andric #include "llvm/BinaryFormat/Wasm.h" 24*5ffd83dbSDimitry Andric #include "llvm/Support/Endian.h" 25*5ffd83dbSDimitry Andric #include "llvm/Support/Format.h" 26*5ffd83dbSDimitry Andric 27*5ffd83dbSDimitry Andric using namespace lldb; 28*5ffd83dbSDimitry Andric using namespace lldb_private; 29*5ffd83dbSDimitry Andric using namespace lldb_private::wasm; 30*5ffd83dbSDimitry Andric 31*5ffd83dbSDimitry Andric LLDB_PLUGIN_DEFINE(ObjectFileWasm) 32*5ffd83dbSDimitry Andric 33*5ffd83dbSDimitry Andric static const uint32_t kWasmHeaderSize = 34*5ffd83dbSDimitry Andric sizeof(llvm::wasm::WasmMagic) + sizeof(llvm::wasm::WasmVersion); 35*5ffd83dbSDimitry Andric 36*5ffd83dbSDimitry Andric /// Checks whether the data buffer starts with a valid Wasm module header. 37*5ffd83dbSDimitry Andric static bool ValidateModuleHeader(const DataBufferSP &data_sp) { 38*5ffd83dbSDimitry Andric if (!data_sp || data_sp->GetByteSize() < kWasmHeaderSize) 39*5ffd83dbSDimitry Andric return false; 40*5ffd83dbSDimitry Andric 41*5ffd83dbSDimitry Andric if (llvm::identify_magic(toStringRef(data_sp->GetData())) != 42*5ffd83dbSDimitry Andric llvm::file_magic::wasm_object) 43*5ffd83dbSDimitry Andric return false; 44*5ffd83dbSDimitry Andric 45*5ffd83dbSDimitry Andric uint8_t *Ptr = data_sp->GetBytes() + sizeof(llvm::wasm::WasmMagic); 46*5ffd83dbSDimitry Andric 47*5ffd83dbSDimitry Andric uint32_t version = llvm::support::endian::read32le(Ptr); 48*5ffd83dbSDimitry Andric return version == llvm::wasm::WasmVersion; 49*5ffd83dbSDimitry Andric } 50*5ffd83dbSDimitry Andric 51*5ffd83dbSDimitry Andric static llvm::Optional<ConstString> 52*5ffd83dbSDimitry Andric GetWasmString(llvm::DataExtractor &data, llvm::DataExtractor::Cursor &c) { 53*5ffd83dbSDimitry Andric // A Wasm string is encoded as a vector of UTF-8 codes. 54*5ffd83dbSDimitry Andric // Vectors are encoded with their u32 length followed by the element 55*5ffd83dbSDimitry Andric // sequence. 56*5ffd83dbSDimitry Andric uint64_t len = data.getULEB128(c); 57*5ffd83dbSDimitry Andric if (!c) { 58*5ffd83dbSDimitry Andric consumeError(c.takeError()); 59*5ffd83dbSDimitry Andric return llvm::None; 60*5ffd83dbSDimitry Andric } 61*5ffd83dbSDimitry Andric 62*5ffd83dbSDimitry Andric if (len >= (uint64_t(1) << 32)) { 63*5ffd83dbSDimitry Andric return llvm::None; 64*5ffd83dbSDimitry Andric } 65*5ffd83dbSDimitry Andric 66*5ffd83dbSDimitry Andric llvm::SmallVector<uint8_t, 32> str_storage; 67*5ffd83dbSDimitry Andric data.getU8(c, str_storage, len); 68*5ffd83dbSDimitry Andric if (!c) { 69*5ffd83dbSDimitry Andric consumeError(c.takeError()); 70*5ffd83dbSDimitry Andric return llvm::None; 71*5ffd83dbSDimitry Andric } 72*5ffd83dbSDimitry Andric 73*5ffd83dbSDimitry Andric llvm::StringRef str = toStringRef(makeArrayRef(str_storage)); 74*5ffd83dbSDimitry Andric return ConstString(str); 75*5ffd83dbSDimitry Andric } 76*5ffd83dbSDimitry Andric 77*5ffd83dbSDimitry Andric char ObjectFileWasm::ID; 78*5ffd83dbSDimitry Andric 79*5ffd83dbSDimitry Andric void ObjectFileWasm::Initialize() { 80*5ffd83dbSDimitry Andric PluginManager::RegisterPlugin(GetPluginNameStatic(), 81*5ffd83dbSDimitry Andric GetPluginDescriptionStatic(), CreateInstance, 82*5ffd83dbSDimitry Andric CreateMemoryInstance, GetModuleSpecifications); 83*5ffd83dbSDimitry Andric } 84*5ffd83dbSDimitry Andric 85*5ffd83dbSDimitry Andric void ObjectFileWasm::Terminate() { 86*5ffd83dbSDimitry Andric PluginManager::UnregisterPlugin(CreateInstance); 87*5ffd83dbSDimitry Andric } 88*5ffd83dbSDimitry Andric 89*5ffd83dbSDimitry Andric ConstString ObjectFileWasm::GetPluginNameStatic() { 90*5ffd83dbSDimitry Andric static ConstString g_name("wasm"); 91*5ffd83dbSDimitry Andric return g_name; 92*5ffd83dbSDimitry Andric } 93*5ffd83dbSDimitry Andric 94*5ffd83dbSDimitry Andric ObjectFile * 95*5ffd83dbSDimitry Andric ObjectFileWasm::CreateInstance(const ModuleSP &module_sp, DataBufferSP &data_sp, 96*5ffd83dbSDimitry Andric offset_t data_offset, const FileSpec *file, 97*5ffd83dbSDimitry Andric offset_t file_offset, offset_t length) { 98*5ffd83dbSDimitry Andric Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); 99*5ffd83dbSDimitry Andric 100*5ffd83dbSDimitry Andric if (!data_sp) { 101*5ffd83dbSDimitry Andric data_sp = MapFileData(*file, length, file_offset); 102*5ffd83dbSDimitry Andric if (!data_sp) { 103*5ffd83dbSDimitry Andric LLDB_LOGF(log, "Failed to create ObjectFileWasm instance for file %s", 104*5ffd83dbSDimitry Andric file->GetPath().c_str()); 105*5ffd83dbSDimitry Andric return nullptr; 106*5ffd83dbSDimitry Andric } 107*5ffd83dbSDimitry Andric data_offset = 0; 108*5ffd83dbSDimitry Andric } 109*5ffd83dbSDimitry Andric 110*5ffd83dbSDimitry Andric assert(data_sp); 111*5ffd83dbSDimitry Andric if (!ValidateModuleHeader(data_sp)) { 112*5ffd83dbSDimitry Andric LLDB_LOGF(log, 113*5ffd83dbSDimitry Andric "Failed to create ObjectFileWasm instance: invalid Wasm header"); 114*5ffd83dbSDimitry Andric return nullptr; 115*5ffd83dbSDimitry Andric } 116*5ffd83dbSDimitry Andric 117*5ffd83dbSDimitry Andric // Update the data to contain the entire file if it doesn't contain it 118*5ffd83dbSDimitry Andric // already. 119*5ffd83dbSDimitry Andric if (data_sp->GetByteSize() < length) { 120*5ffd83dbSDimitry Andric data_sp = MapFileData(*file, length, file_offset); 121*5ffd83dbSDimitry Andric if (!data_sp) { 122*5ffd83dbSDimitry Andric LLDB_LOGF(log, 123*5ffd83dbSDimitry Andric "Failed to create ObjectFileWasm instance: cannot read file %s", 124*5ffd83dbSDimitry Andric file->GetPath().c_str()); 125*5ffd83dbSDimitry Andric return nullptr; 126*5ffd83dbSDimitry Andric } 127*5ffd83dbSDimitry Andric data_offset = 0; 128*5ffd83dbSDimitry Andric } 129*5ffd83dbSDimitry Andric 130*5ffd83dbSDimitry Andric std::unique_ptr<ObjectFileWasm> objfile_up(new ObjectFileWasm( 131*5ffd83dbSDimitry Andric module_sp, data_sp, data_offset, file, file_offset, length)); 132*5ffd83dbSDimitry Andric ArchSpec spec = objfile_up->GetArchitecture(); 133*5ffd83dbSDimitry Andric if (spec && objfile_up->SetModulesArchitecture(spec)) { 134*5ffd83dbSDimitry Andric LLDB_LOGF(log, 135*5ffd83dbSDimitry Andric "%p ObjectFileWasm::CreateInstance() module = %p (%s), file = %s", 136*5ffd83dbSDimitry Andric static_cast<void *>(objfile_up.get()), 137*5ffd83dbSDimitry Andric static_cast<void *>(objfile_up->GetModule().get()), 138*5ffd83dbSDimitry Andric objfile_up->GetModule()->GetSpecificationDescription().c_str(), 139*5ffd83dbSDimitry Andric file ? file->GetPath().c_str() : "<NULL>"); 140*5ffd83dbSDimitry Andric return objfile_up.release(); 141*5ffd83dbSDimitry Andric } 142*5ffd83dbSDimitry Andric 143*5ffd83dbSDimitry Andric LLDB_LOGF(log, "Failed to create ObjectFileWasm instance"); 144*5ffd83dbSDimitry Andric return nullptr; 145*5ffd83dbSDimitry Andric } 146*5ffd83dbSDimitry Andric 147*5ffd83dbSDimitry Andric ObjectFile *ObjectFileWasm::CreateMemoryInstance(const ModuleSP &module_sp, 148*5ffd83dbSDimitry Andric DataBufferSP &data_sp, 149*5ffd83dbSDimitry Andric const ProcessSP &process_sp, 150*5ffd83dbSDimitry Andric addr_t header_addr) { 151*5ffd83dbSDimitry Andric if (!ValidateModuleHeader(data_sp)) 152*5ffd83dbSDimitry Andric return nullptr; 153*5ffd83dbSDimitry Andric 154*5ffd83dbSDimitry Andric std::unique_ptr<ObjectFileWasm> objfile_up( 155*5ffd83dbSDimitry Andric new ObjectFileWasm(module_sp, data_sp, process_sp, header_addr)); 156*5ffd83dbSDimitry Andric ArchSpec spec = objfile_up->GetArchitecture(); 157*5ffd83dbSDimitry Andric if (spec && objfile_up->SetModulesArchitecture(spec)) 158*5ffd83dbSDimitry Andric return objfile_up.release(); 159*5ffd83dbSDimitry Andric return nullptr; 160*5ffd83dbSDimitry Andric } 161*5ffd83dbSDimitry Andric 162*5ffd83dbSDimitry Andric bool ObjectFileWasm::DecodeNextSection(lldb::offset_t *offset_ptr) { 163*5ffd83dbSDimitry Andric // Buffer sufficient to read a section header and find the pointer to the next 164*5ffd83dbSDimitry Andric // section. 165*5ffd83dbSDimitry Andric const uint32_t kBufferSize = 1024; 166*5ffd83dbSDimitry Andric DataExtractor section_header_data = ReadImageData(*offset_ptr, kBufferSize); 167*5ffd83dbSDimitry Andric 168*5ffd83dbSDimitry Andric llvm::DataExtractor data = section_header_data.GetAsLLVM(); 169*5ffd83dbSDimitry Andric llvm::DataExtractor::Cursor c(0); 170*5ffd83dbSDimitry Andric 171*5ffd83dbSDimitry Andric // Each section consists of: 172*5ffd83dbSDimitry Andric // - a one-byte section id, 173*5ffd83dbSDimitry Andric // - the u32 size of the contents, in bytes, 174*5ffd83dbSDimitry Andric // - the actual contents. 175*5ffd83dbSDimitry Andric uint8_t section_id = data.getU8(c); 176*5ffd83dbSDimitry Andric uint64_t payload_len = data.getULEB128(c); 177*5ffd83dbSDimitry Andric if (!c) 178*5ffd83dbSDimitry Andric return !llvm::errorToBool(c.takeError()); 179*5ffd83dbSDimitry Andric 180*5ffd83dbSDimitry Andric if (payload_len >= (uint64_t(1) << 32)) 181*5ffd83dbSDimitry Andric return false; 182*5ffd83dbSDimitry Andric 183*5ffd83dbSDimitry Andric if (section_id == llvm::wasm::WASM_SEC_CUSTOM) { 184*5ffd83dbSDimitry Andric // Custom sections have the id 0. Their contents consist of a name 185*5ffd83dbSDimitry Andric // identifying the custom section, followed by an uninterpreted sequence 186*5ffd83dbSDimitry Andric // of bytes. 187*5ffd83dbSDimitry Andric lldb::offset_t prev_offset = c.tell(); 188*5ffd83dbSDimitry Andric llvm::Optional<ConstString> sect_name = GetWasmString(data, c); 189*5ffd83dbSDimitry Andric if (!sect_name) 190*5ffd83dbSDimitry Andric return false; 191*5ffd83dbSDimitry Andric 192*5ffd83dbSDimitry Andric if (payload_len < c.tell() - prev_offset) 193*5ffd83dbSDimitry Andric return false; 194*5ffd83dbSDimitry Andric 195*5ffd83dbSDimitry Andric uint32_t section_length = payload_len - (c.tell() - prev_offset); 196*5ffd83dbSDimitry Andric m_sect_infos.push_back(section_info{*offset_ptr + c.tell(), section_length, 197*5ffd83dbSDimitry Andric section_id, *sect_name}); 198*5ffd83dbSDimitry Andric *offset_ptr += (c.tell() + section_length); 199*5ffd83dbSDimitry Andric } else if (section_id <= llvm::wasm::WASM_SEC_EVENT) { 200*5ffd83dbSDimitry Andric m_sect_infos.push_back(section_info{*offset_ptr + c.tell(), 201*5ffd83dbSDimitry Andric static_cast<uint32_t>(payload_len), 202*5ffd83dbSDimitry Andric section_id, ConstString()}); 203*5ffd83dbSDimitry Andric *offset_ptr += (c.tell() + payload_len); 204*5ffd83dbSDimitry Andric } else { 205*5ffd83dbSDimitry Andric // Invalid section id. 206*5ffd83dbSDimitry Andric return false; 207*5ffd83dbSDimitry Andric } 208*5ffd83dbSDimitry Andric return true; 209*5ffd83dbSDimitry Andric } 210*5ffd83dbSDimitry Andric 211*5ffd83dbSDimitry Andric bool ObjectFileWasm::DecodeSections() { 212*5ffd83dbSDimitry Andric lldb::offset_t offset = kWasmHeaderSize; 213*5ffd83dbSDimitry Andric if (IsInMemory()) { 214*5ffd83dbSDimitry Andric offset += m_memory_addr; 215*5ffd83dbSDimitry Andric } 216*5ffd83dbSDimitry Andric 217*5ffd83dbSDimitry Andric while (DecodeNextSection(&offset)) 218*5ffd83dbSDimitry Andric ; 219*5ffd83dbSDimitry Andric return true; 220*5ffd83dbSDimitry Andric } 221*5ffd83dbSDimitry Andric 222*5ffd83dbSDimitry Andric size_t ObjectFileWasm::GetModuleSpecifications( 223*5ffd83dbSDimitry Andric const FileSpec &file, DataBufferSP &data_sp, offset_t data_offset, 224*5ffd83dbSDimitry Andric offset_t file_offset, offset_t length, ModuleSpecList &specs) { 225*5ffd83dbSDimitry Andric if (!ValidateModuleHeader(data_sp)) { 226*5ffd83dbSDimitry Andric return 0; 227*5ffd83dbSDimitry Andric } 228*5ffd83dbSDimitry Andric 229*5ffd83dbSDimitry Andric ModuleSpec spec(file, ArchSpec("wasm32-unknown-unknown-wasm")); 230*5ffd83dbSDimitry Andric specs.Append(spec); 231*5ffd83dbSDimitry Andric return 1; 232*5ffd83dbSDimitry Andric } 233*5ffd83dbSDimitry Andric 234*5ffd83dbSDimitry Andric ObjectFileWasm::ObjectFileWasm(const ModuleSP &module_sp, DataBufferSP &data_sp, 235*5ffd83dbSDimitry Andric offset_t data_offset, const FileSpec *file, 236*5ffd83dbSDimitry Andric offset_t offset, offset_t length) 237*5ffd83dbSDimitry Andric : ObjectFile(module_sp, file, offset, length, data_sp, data_offset), 238*5ffd83dbSDimitry Andric m_arch("wasm32-unknown-unknown-wasm") { 239*5ffd83dbSDimitry Andric m_data.SetAddressByteSize(4); 240*5ffd83dbSDimitry Andric } 241*5ffd83dbSDimitry Andric 242*5ffd83dbSDimitry Andric ObjectFileWasm::ObjectFileWasm(const lldb::ModuleSP &module_sp, 243*5ffd83dbSDimitry Andric lldb::DataBufferSP &header_data_sp, 244*5ffd83dbSDimitry Andric const lldb::ProcessSP &process_sp, 245*5ffd83dbSDimitry Andric lldb::addr_t header_addr) 246*5ffd83dbSDimitry Andric : ObjectFile(module_sp, process_sp, header_addr, header_data_sp), 247*5ffd83dbSDimitry Andric m_arch("wasm32-unknown-unknown-wasm") {} 248*5ffd83dbSDimitry Andric 249*5ffd83dbSDimitry Andric bool ObjectFileWasm::ParseHeader() { 250*5ffd83dbSDimitry Andric // We already parsed the header during initialization. 251*5ffd83dbSDimitry Andric return true; 252*5ffd83dbSDimitry Andric } 253*5ffd83dbSDimitry Andric 254*5ffd83dbSDimitry Andric Symtab *ObjectFileWasm::GetSymtab() { return nullptr; } 255*5ffd83dbSDimitry Andric 256*5ffd83dbSDimitry Andric void ObjectFileWasm::CreateSections(SectionList &unified_section_list) { 257*5ffd83dbSDimitry Andric if (m_sections_up) 258*5ffd83dbSDimitry Andric return; 259*5ffd83dbSDimitry Andric 260*5ffd83dbSDimitry Andric m_sections_up = std::make_unique<SectionList>(); 261*5ffd83dbSDimitry Andric 262*5ffd83dbSDimitry Andric if (m_sect_infos.empty()) { 263*5ffd83dbSDimitry Andric DecodeSections(); 264*5ffd83dbSDimitry Andric } 265*5ffd83dbSDimitry Andric 266*5ffd83dbSDimitry Andric for (const section_info §_info : m_sect_infos) { 267*5ffd83dbSDimitry Andric SectionType section_type = eSectionTypeOther; 268*5ffd83dbSDimitry Andric ConstString section_name; 269*5ffd83dbSDimitry Andric offset_t file_offset = sect_info.offset & 0xffffffff; 270*5ffd83dbSDimitry Andric addr_t vm_addr = file_offset; 271*5ffd83dbSDimitry Andric size_t vm_size = sect_info.size; 272*5ffd83dbSDimitry Andric 273*5ffd83dbSDimitry Andric if (llvm::wasm::WASM_SEC_CODE == sect_info.id) { 274*5ffd83dbSDimitry Andric section_type = eSectionTypeCode; 275*5ffd83dbSDimitry Andric section_name = ConstString("code"); 276*5ffd83dbSDimitry Andric 277*5ffd83dbSDimitry Andric // A code address in DWARF for WebAssembly is the offset of an 278*5ffd83dbSDimitry Andric // instruction relative within the Code section of the WebAssembly file. 279*5ffd83dbSDimitry Andric // For this reason Section::GetFileAddress() must return zero for the 280*5ffd83dbSDimitry Andric // Code section. 281*5ffd83dbSDimitry Andric vm_addr = 0; 282*5ffd83dbSDimitry Andric } else { 283*5ffd83dbSDimitry Andric section_type = 284*5ffd83dbSDimitry Andric llvm::StringSwitch<SectionType>(sect_info.name.GetStringRef()) 285*5ffd83dbSDimitry Andric .Case(".debug_abbrev", eSectionTypeDWARFDebugAbbrev) 286*5ffd83dbSDimitry Andric .Case(".debug_addr", eSectionTypeDWARFDebugAddr) 287*5ffd83dbSDimitry Andric .Case(".debug_aranges", eSectionTypeDWARFDebugAranges) 288*5ffd83dbSDimitry Andric .Case(".debug_cu_index", eSectionTypeDWARFDebugCuIndex) 289*5ffd83dbSDimitry Andric .Case(".debug_frame", eSectionTypeDWARFDebugFrame) 290*5ffd83dbSDimitry Andric .Case(".debug_info", eSectionTypeDWARFDebugInfo) 291*5ffd83dbSDimitry Andric .Case(".debug_line", eSectionTypeDWARFDebugLine) 292*5ffd83dbSDimitry Andric .Case(".debug_line_str", eSectionTypeDWARFDebugLineStr) 293*5ffd83dbSDimitry Andric .Case(".debug_loc", eSectionTypeDWARFDebugLoc) 294*5ffd83dbSDimitry Andric .Case(".debug_loclists", eSectionTypeDWARFDebugLocLists) 295*5ffd83dbSDimitry Andric .Case(".debug_macinfo", eSectionTypeDWARFDebugMacInfo) 296*5ffd83dbSDimitry Andric .Case(".debug_macro", eSectionTypeDWARFDebugMacro) 297*5ffd83dbSDimitry Andric .Case(".debug_names", eSectionTypeDWARFDebugNames) 298*5ffd83dbSDimitry Andric .Case(".debug_pubnames", eSectionTypeDWARFDebugPubNames) 299*5ffd83dbSDimitry Andric .Case(".debug_pubtypes", eSectionTypeDWARFDebugPubTypes) 300*5ffd83dbSDimitry Andric .Case(".debug_ranges", eSectionTypeDWARFDebugRanges) 301*5ffd83dbSDimitry Andric .Case(".debug_rnglists", eSectionTypeDWARFDebugRngLists) 302*5ffd83dbSDimitry Andric .Case(".debug_str", eSectionTypeDWARFDebugStr) 303*5ffd83dbSDimitry Andric .Case(".debug_str_offsets", eSectionTypeDWARFDebugStrOffsets) 304*5ffd83dbSDimitry Andric .Case(".debug_types", eSectionTypeDWARFDebugTypes) 305*5ffd83dbSDimitry Andric .Default(eSectionTypeOther); 306*5ffd83dbSDimitry Andric if (section_type == eSectionTypeOther) 307*5ffd83dbSDimitry Andric continue; 308*5ffd83dbSDimitry Andric section_name = sect_info.name; 309*5ffd83dbSDimitry Andric if (!IsInMemory()) { 310*5ffd83dbSDimitry Andric vm_size = 0; 311*5ffd83dbSDimitry Andric vm_addr = 0; 312*5ffd83dbSDimitry Andric } 313*5ffd83dbSDimitry Andric } 314*5ffd83dbSDimitry Andric 315*5ffd83dbSDimitry Andric SectionSP section_sp( 316*5ffd83dbSDimitry Andric new Section(GetModule(), // Module to which this section belongs. 317*5ffd83dbSDimitry Andric this, // ObjectFile to which this section belongs and 318*5ffd83dbSDimitry Andric // should read section data from. 319*5ffd83dbSDimitry Andric section_type, // Section ID. 320*5ffd83dbSDimitry Andric section_name, // Section name. 321*5ffd83dbSDimitry Andric section_type, // Section type. 322*5ffd83dbSDimitry Andric vm_addr, // VM address. 323*5ffd83dbSDimitry Andric vm_size, // VM size in bytes of this section. 324*5ffd83dbSDimitry Andric file_offset, // Offset of this section in the file. 325*5ffd83dbSDimitry Andric sect_info.size, // Size of the section as found in the file. 326*5ffd83dbSDimitry Andric 0, // Alignment of the section 327*5ffd83dbSDimitry Andric 0, // Flags for this section. 328*5ffd83dbSDimitry Andric 1)); // Number of host bytes per target byte 329*5ffd83dbSDimitry Andric m_sections_up->AddSection(section_sp); 330*5ffd83dbSDimitry Andric unified_section_list.AddSection(section_sp); 331*5ffd83dbSDimitry Andric } 332*5ffd83dbSDimitry Andric } 333*5ffd83dbSDimitry Andric 334*5ffd83dbSDimitry Andric bool ObjectFileWasm::SetLoadAddress(Target &target, lldb::addr_t load_address, 335*5ffd83dbSDimitry Andric bool value_is_offset) { 336*5ffd83dbSDimitry Andric /// In WebAssembly, linear memory is disjointed from code space. The VM can 337*5ffd83dbSDimitry Andric /// load multiple instances of a module, which logically share the same code. 338*5ffd83dbSDimitry Andric /// We represent a wasm32 code address with 64-bits, like: 339*5ffd83dbSDimitry Andric /// 63 32 31 0 340*5ffd83dbSDimitry Andric /// +---------------+---------------+ 341*5ffd83dbSDimitry Andric /// + module_id | offset | 342*5ffd83dbSDimitry Andric /// +---------------+---------------+ 343*5ffd83dbSDimitry Andric /// where the lower 32 bits represent a module offset (relative to the module 344*5ffd83dbSDimitry Andric /// start not to the beginning of the code section) and the higher 32 bits 345*5ffd83dbSDimitry Andric /// uniquely identify the module in the WebAssembly VM. 346*5ffd83dbSDimitry Andric /// In other words, we assume that each WebAssembly module is loaded by the 347*5ffd83dbSDimitry Andric /// engine at a 64-bit address that starts at the boundary of 4GB pages, like 348*5ffd83dbSDimitry Andric /// 0x0000000400000000 for module_id == 4. 349*5ffd83dbSDimitry Andric /// These 64-bit addresses will be used to request code ranges for a specific 350*5ffd83dbSDimitry Andric /// module from the WebAssembly engine. 351*5ffd83dbSDimitry Andric 352*5ffd83dbSDimitry Andric assert(m_memory_addr == LLDB_INVALID_ADDRESS || 353*5ffd83dbSDimitry Andric m_memory_addr == load_address); 354*5ffd83dbSDimitry Andric 355*5ffd83dbSDimitry Andric ModuleSP module_sp = GetModule(); 356*5ffd83dbSDimitry Andric if (!module_sp) 357*5ffd83dbSDimitry Andric return false; 358*5ffd83dbSDimitry Andric 359*5ffd83dbSDimitry Andric DecodeSections(); 360*5ffd83dbSDimitry Andric 361*5ffd83dbSDimitry Andric size_t num_loaded_sections = 0; 362*5ffd83dbSDimitry Andric SectionList *section_list = GetSectionList(); 363*5ffd83dbSDimitry Andric if (!section_list) 364*5ffd83dbSDimitry Andric return false; 365*5ffd83dbSDimitry Andric 366*5ffd83dbSDimitry Andric const size_t num_sections = section_list->GetSize(); 367*5ffd83dbSDimitry Andric for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) { 368*5ffd83dbSDimitry Andric SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx)); 369*5ffd83dbSDimitry Andric if (target.SetSectionLoadAddress( 370*5ffd83dbSDimitry Andric section_sp, load_address | section_sp->GetFileOffset())) { 371*5ffd83dbSDimitry Andric ++num_loaded_sections; 372*5ffd83dbSDimitry Andric } 373*5ffd83dbSDimitry Andric } 374*5ffd83dbSDimitry Andric 375*5ffd83dbSDimitry Andric return num_loaded_sections > 0; 376*5ffd83dbSDimitry Andric } 377*5ffd83dbSDimitry Andric 378*5ffd83dbSDimitry Andric DataExtractor ObjectFileWasm::ReadImageData(offset_t offset, uint32_t size) { 379*5ffd83dbSDimitry Andric DataExtractor data; 380*5ffd83dbSDimitry Andric if (m_file) { 381*5ffd83dbSDimitry Andric if (offset < GetByteSize()) { 382*5ffd83dbSDimitry Andric size = std::min(static_cast<uint64_t>(size), GetByteSize() - offset); 383*5ffd83dbSDimitry Andric auto buffer_sp = MapFileData(m_file, size, offset); 384*5ffd83dbSDimitry Andric return DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize()); 385*5ffd83dbSDimitry Andric } 386*5ffd83dbSDimitry Andric } else { 387*5ffd83dbSDimitry Andric ProcessSP process_sp(m_process_wp.lock()); 388*5ffd83dbSDimitry Andric if (process_sp) { 389*5ffd83dbSDimitry Andric auto data_up = std::make_unique<DataBufferHeap>(size, 0); 390*5ffd83dbSDimitry Andric Status readmem_error; 391*5ffd83dbSDimitry Andric size_t bytes_read = process_sp->ReadMemory( 392*5ffd83dbSDimitry Andric offset, data_up->GetBytes(), data_up->GetByteSize(), readmem_error); 393*5ffd83dbSDimitry Andric if (bytes_read > 0) { 394*5ffd83dbSDimitry Andric DataBufferSP buffer_sp(data_up.release()); 395*5ffd83dbSDimitry Andric data.SetData(buffer_sp, 0, buffer_sp->GetByteSize()); 396*5ffd83dbSDimitry Andric } 397*5ffd83dbSDimitry Andric } 398*5ffd83dbSDimitry Andric } 399*5ffd83dbSDimitry Andric 400*5ffd83dbSDimitry Andric data.SetByteOrder(GetByteOrder()); 401*5ffd83dbSDimitry Andric return data; 402*5ffd83dbSDimitry Andric } 403*5ffd83dbSDimitry Andric 404*5ffd83dbSDimitry Andric llvm::Optional<FileSpec> ObjectFileWasm::GetExternalDebugInfoFileSpec() { 405*5ffd83dbSDimitry Andric static ConstString g_sect_name_external_debug_info("external_debug_info"); 406*5ffd83dbSDimitry Andric 407*5ffd83dbSDimitry Andric for (const section_info §_info : m_sect_infos) { 408*5ffd83dbSDimitry Andric if (g_sect_name_external_debug_info == sect_info.name) { 409*5ffd83dbSDimitry Andric const uint32_t kBufferSize = 1024; 410*5ffd83dbSDimitry Andric DataExtractor section_header_data = 411*5ffd83dbSDimitry Andric ReadImageData(sect_info.offset, kBufferSize); 412*5ffd83dbSDimitry Andric llvm::DataExtractor data = section_header_data.GetAsLLVM(); 413*5ffd83dbSDimitry Andric llvm::DataExtractor::Cursor c(0); 414*5ffd83dbSDimitry Andric llvm::Optional<ConstString> symbols_url = GetWasmString(data, c); 415*5ffd83dbSDimitry Andric if (symbols_url) 416*5ffd83dbSDimitry Andric return FileSpec(symbols_url->GetStringRef()); 417*5ffd83dbSDimitry Andric } 418*5ffd83dbSDimitry Andric } 419*5ffd83dbSDimitry Andric return llvm::None; 420*5ffd83dbSDimitry Andric } 421*5ffd83dbSDimitry Andric 422*5ffd83dbSDimitry Andric void ObjectFileWasm::Dump(Stream *s) { 423*5ffd83dbSDimitry Andric ModuleSP module_sp(GetModule()); 424*5ffd83dbSDimitry Andric if (!module_sp) 425*5ffd83dbSDimitry Andric return; 426*5ffd83dbSDimitry Andric 427*5ffd83dbSDimitry Andric std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); 428*5ffd83dbSDimitry Andric 429*5ffd83dbSDimitry Andric llvm::raw_ostream &ostream = s->AsRawOstream(); 430*5ffd83dbSDimitry Andric ostream << static_cast<void *>(this) << ": "; 431*5ffd83dbSDimitry Andric s->Indent(); 432*5ffd83dbSDimitry Andric ostream << "ObjectFileWasm, file = '"; 433*5ffd83dbSDimitry Andric m_file.Dump(ostream); 434*5ffd83dbSDimitry Andric ostream << "', arch = "; 435*5ffd83dbSDimitry Andric ostream << GetArchitecture().GetArchitectureName() << "\n"; 436*5ffd83dbSDimitry Andric 437*5ffd83dbSDimitry Andric SectionList *sections = GetSectionList(); 438*5ffd83dbSDimitry Andric if (sections) { 439*5ffd83dbSDimitry Andric sections->Dump(s->AsRawOstream(), s->GetIndentLevel(), nullptr, true, 440*5ffd83dbSDimitry Andric UINT32_MAX); 441*5ffd83dbSDimitry Andric } 442*5ffd83dbSDimitry Andric ostream << "\n"; 443*5ffd83dbSDimitry Andric DumpSectionHeaders(ostream); 444*5ffd83dbSDimitry Andric ostream << "\n"; 445*5ffd83dbSDimitry Andric } 446*5ffd83dbSDimitry Andric 447*5ffd83dbSDimitry Andric void ObjectFileWasm::DumpSectionHeader(llvm::raw_ostream &ostream, 448*5ffd83dbSDimitry Andric const section_info_t &sh) { 449*5ffd83dbSDimitry Andric ostream << llvm::left_justify(sh.name.GetStringRef(), 16) << " " 450*5ffd83dbSDimitry Andric << llvm::format_hex(sh.offset, 10) << " " 451*5ffd83dbSDimitry Andric << llvm::format_hex(sh.size, 10) << " " << llvm::format_hex(sh.id, 6) 452*5ffd83dbSDimitry Andric << "\n"; 453*5ffd83dbSDimitry Andric } 454*5ffd83dbSDimitry Andric 455*5ffd83dbSDimitry Andric void ObjectFileWasm::DumpSectionHeaders(llvm::raw_ostream &ostream) { 456*5ffd83dbSDimitry Andric ostream << "Section Headers\n"; 457*5ffd83dbSDimitry Andric ostream << "IDX name addr size id\n"; 458*5ffd83dbSDimitry Andric ostream << "==== ---------------- ---------- ---------- ------\n"; 459*5ffd83dbSDimitry Andric 460*5ffd83dbSDimitry Andric uint32_t idx = 0; 461*5ffd83dbSDimitry Andric for (auto pos = m_sect_infos.begin(); pos != m_sect_infos.end(); 462*5ffd83dbSDimitry Andric ++pos, ++idx) { 463*5ffd83dbSDimitry Andric ostream << "[" << llvm::format_decimal(idx, 2) << "] "; 464*5ffd83dbSDimitry Andric ObjectFileWasm::DumpSectionHeader(ostream, *pos); 465*5ffd83dbSDimitry Andric } 466*5ffd83dbSDimitry Andric } 467