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