20#include "llvm/ADT/ArrayRef.h"
21#include "llvm/ADT/SmallVector.h"
22#include "llvm/ADT/StringRef.h"
23#include "llvm/BinaryFormat/Magic.h"
24#include "llvm/BinaryFormat/Wasm.h"
25#include "llvm/Support/CheckedArithmetic.h"
26#include "llvm/Support/Endian.h"
27#include "llvm/Support/Format.h"
42 const uint64_t value = data.GetULEB128(&offset);
43 if (value > std::numeric_limits<uint32_t>::max())
44 return llvm::createStringError(
"ULEB exceeds 32 bits");
49static inline llvm::Expected<uint32_t>
50GetULEB32(llvm::DataExtractor &data, llvm::DataExtractor::Cursor &c) {
51 const uint64_t value = data.getULEB128(c);
54 if (value > std::numeric_limits<uint32_t>::max())
55 return llvm::createStringError(
"ULEB exceeds 32 bits");
60static inline llvm::Expected<std::string>
61GetWasmString(llvm::DataExtractor &data, llvm::DataExtractor::Cursor &c) {
62 llvm::Expected<uint32_t> len =
GetULEB32(data, c);
64 return len.takeError();
66 llvm::SmallVector<uint8_t, 32> str_storage;
67 data.getU8(c, str_storage, *len);
71 return std::string(toStringRef(llvm::ArrayRef(str_storage)));
82 uint8_t opcode = data.
GetU8(&offset);
84 case llvm::wasm::WASM_OPCODE_I32_CONST:
85 case llvm::wasm::WASM_OPCODE_I64_CONST:
88 case llvm::wasm::WASM_OPCODE_GLOBAL_GET:
91 case llvm::wasm::WASM_OPCODE_F32_CONST:
92 case llvm::wasm::WASM_OPCODE_F64_CONST:
96 case llvm::wasm::WASM_OPCODE_REF_NULL:
103 opcode = data.
GetU8(&offset);
104 if (opcode == llvm::wasm::WASM_OPCODE_END)
105 return init_expr_offset;
110 opcode = data.
GetU8(&offset);
111 }
while (opcode != llvm::wasm::WASM_OPCODE_END);
120 if (llvm::identify_magic(toStringRef(data_sp->GetData())) !=
121 llvm::file_magic::wasm_object)
124 const uint8_t *Ptr = data_sp->GetBytes() +
sizeof(llvm::wasm::WasmMagic);
126 uint32_t version = llvm::support::endian::read32le(Ptr);
127 return version == llvm::wasm::WasmVersion;
151 LLDB_LOGF(log,
"Failed to create ObjectFileWasm instance for file %s",
161 "Failed to create ObjectFileWasm instance: invalid Wasm header");
167 if (data_sp->GetByteSize() < length) {
171 "Failed to create ObjectFileWasm instance: cannot read file %s",
179 module_sp, data_sp, data_offset, file, file_offset, length));
180 ArchSpec spec = objfile_up->GetArchitecture();
181 if (spec && objfile_up->SetModulesArchitecture(spec)) {
183 "%p ObjectFileWasm::CreateInstance() module = %p (%s), file = %s",
184 static_cast<void *
>(objfile_up.get()),
185 static_cast<void *
>(objfile_up->GetModule().get()),
186 objfile_up->GetModule()->GetSpecificationDescription().c_str(),
187 file ? file->
GetPath().c_str() :
"<NULL>");
188 return objfile_up.release();
191 LLDB_LOGF(log,
"Failed to create ObjectFileWasm instance");
202 std::unique_ptr<ObjectFileWasm> objfile_up(
204 ArchSpec spec = objfile_up->GetArchitecture();
205 if (spec && objfile_up->SetModulesArchitecture(spec))
206 return objfile_up.release();
213 const uint32_t kBufferSize = 1024;
216 llvm::DataExtractor data = section_header_data.
GetAsLLVM();
217 llvm::DataExtractor::Cursor c(0);
223 uint8_t section_id = data.getU8(c);
224 uint64_t payload_len = data.getULEB128(c);
226 return !llvm::errorToBool(c.takeError());
228 if (payload_len > std::numeric_limits<uint32_t>::max())
231 if (section_id == llvm::wasm::WASM_SEC_CUSTOM) {
236 llvm::Expected<std::string> sect_name =
GetWasmString(data, c);
239 "failed to parse section name: {0}");
243 if (payload_len < c.tell() - prev_offset)
246 uint32_t section_length = payload_len - (c.tell() - prev_offset);
249 *offset_ptr += (c.tell() + section_length);
250 }
else if (section_id <= llvm::wasm::WASM_SEC_LAST_KNOWN) {
252 static_cast<uint32_t
>(payload_len),
254 *offset_ptr += (c.tell() + payload_len);
288 :
ObjectFile(module_sp, file, offset, length, data_sp, data_offset),
289 m_arch(
"wasm32-unknown-unknown-wasm") {
290 m_data.SetAddressByteSize(4);
297 :
ObjectFile(module_sp, process_sp, header_addr, header_data_sp),
298 m_arch(
"wasm32-unknown-unknown-wasm") {}
310static llvm::Expected<std::vector<WasmFunction>>
314 llvm::Expected<uint32_t> function_count =
GetULEB32(data, offset);
316 return function_count.takeError();
318 std::vector<WasmFunction> functions;
319 functions.reserve(*function_count);
321 for (uint32_t i = 0; i < *function_count; ++i) {
322 llvm::Expected<uint32_t> function_size =
GetULEB32(data, offset);
324 return function_size.takeError();
328 functions.push_back({offset, *function_size});
330 std::optional<lldb::offset_t> next_offset =
331 llvm::checkedAddUnsigned<lldb::offset_t>(offset, *function_size);
333 return llvm::createStringError(
"function offset overflows 64 bits");
334 offset = *next_offset;
359 llvm::Expected<uint32_t> segment_count =
GetULEB32(data, offset);
361 return segment_count.takeError();
363 std::vector<WasmSegment> segments;
364 segments.reserve(*segment_count);
366 for (uint32_t i = 0; i < *segment_count; ++i) {
367 llvm::Expected<uint32_t> flags =
GetULEB32(data, offset);
369 return flags.takeError();
377 segment.
type = (*flags & llvm::wasm::WASM_DATA_SEGMENT_IS_PASSIVE)
381 if (*flags & llvm::wasm::WASM_DATA_SEGMENT_HAS_MEMINDEX) {
383 llvm::Expected<uint32_t> memidx =
GetULEB32(data, offset);
385 return memidx.takeError();
392 llvm::Expected<uint32_t> segment_size =
GetULEB32(data, offset);
394 return segment_size.takeError();
397 segment.
size = *segment_size;
398 segments.push_back(segment);
400 std::optional<lldb::offset_t> next_offset =
401 llvm::checkedAddUnsigned<lldb::offset_t>(offset, *segment_size);
403 return llvm::createStringError(
"segment offset overflows 64 bits");
404 offset = *next_offset;
410static llvm::Expected<std::vector<Symbol>>
412 const std::vector<WasmFunction> &functions,
413 std::vector<WasmSegment> &segments) {
415 llvm::DataExtractor data = name_data.
GetAsLLVM();
416 llvm::DataExtractor::Cursor c(0);
417 std::vector<Symbol> symbols;
418 while (c && c.tell() < data.size()) {
419 const uint8_t type = data.getU8(c);
420 llvm::Expected<uint32_t> size =
GetULEB32(data, c);
422 return size.takeError();
425 case llvm::wasm::WASM_NAMES_FUNCTION: {
426 const uint64_t count = data.getULEB128(c);
427 if (count > std::numeric_limits<uint32_t>::max())
428 return llvm::createStringError(
"function count overflows uint32_t");
430 for (uint64_t i = 0; c && i < count; ++i) {
431 llvm::Expected<uint32_t> idx =
GetULEB32(data, c);
433 return idx.takeError();
436 return name.takeError();
437 if (*idx >= functions.size())
439 symbols.emplace_back(
442 false, code_section_sp,
443 functions[i].section_offset, functions[i].size,
448 case llvm::wasm::WASM_NAMES_DATA_SEGMENT: {
449 llvm::Expected<uint32_t> count =
GetULEB32(data, c);
451 return count.takeError();
452 for (uint32_t i = 0; c && i < *count; ++i) {
453 llvm::Expected<uint32_t> idx =
GetULEB32(data, c);
455 return idx.takeError();
458 return name.takeError();
459 if (*idx >= segments.size())
462 segments[i].name = *name;
466 case llvm::wasm::WASM_NAMES_GLOBAL:
467 case llvm::wasm::WASM_NAMES_LOCAL:
469 std::optional<lldb::offset_t> offset =
470 llvm::checkedAddUnsigned<lldb::offset_t>(c.tell(), *size);
472 return llvm::createStringError(
"offset overflows 64 bits");
478 return c.takeError();
494 if (Name.consume_front(
".debug_") || Name.consume_front(
".zdebug_"))
499std::optional<ObjectFileWasm::section_info>
502 if (sect_info.id == section_id)
508std::optional<ObjectFileWasm::section_info>
511 if (sect_info.name == section_name)
532 offset_t file_offset = sect_info.offset & 0xffffffff;
533 addr_t vm_addr = sect_info.offset;
534 size_t vm_size = sect_info.size;
536 if (llvm::wasm::WASM_SEC_CODE == sect_info.id) {
549 section_name = sect_info.name;
556 SectionSP section_sp = std::make_shared<Section>(
576 std::vector<WasmFunction> functions;
577 std::vector<WasmSegment> segments;
580 if (std::optional<section_info> info =
583 llvm::Expected<std::vector<WasmFunction>> maybe_functions =
585 if (!maybe_functions) {
587 "Failed to parse Wasm code section: {0}");
589 functions = *maybe_functions;
594 std::optional<section_info> data_info =
598 llvm::Expected<std::vector<WasmSegment>> maybe_segments =
600 if (!maybe_segments) {
602 "Failed to parse Wasm data section: {0}");
604 segments = *maybe_segments;
610 llvm::Expected<std::vector<Symbol>> symbols =
ParseNames(
612 names_data, functions, segments);
615 "Failed to parse Wasm names: {0}");
625 if (segment.memory_index != 0) {
626 LLDB_LOG(log,
"Skipping segment {0}: non-zero memory index is "
627 "currently unsupported");
632 LLDB_LOG(log,
"Skipping segment {0}: unsupported init expression");
639 ? segment.init_expr_offset
640 : data_info->offset + segment.section_offset;
642 data_info->GetFileOffset() + segment.GetFileOffset();
643 SectionSP segment_sp = std::make_shared<Section>(
655 GetModule()->GetSectionList()->AddSection(segment_sp);
660 bool value_is_offset) {
686 size_t num_loaded_sections = 0;
691 const size_t num_sections = section_list->
GetSize();
692 for (
size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) {
695 section_sp, load_address | section_sp->GetFileOffset())) {
696 ++num_loaded_sections;
700 return num_loaded_sections > 0;
707 size = std::min(
static_cast<uint64_t
>(size),
GetByteSize() - offset);
714 auto data_up = std::make_unique<DataBufferHeap>(size, 0);
716 size_t bytes_read = process_sp->ReadMemory(
717 offset, data_up->GetBytes(), data_up->GetByteSize(), readmem_error);
718 if (bytes_read > 0) {
720 data.
SetData(buffer_sp, 0, buffer_sp->GetByteSize());
722 }
else if (offset <
m_data.GetByteSize()) {
724 std::min(
static_cast<uint64_t
>(size),
m_data.GetByteSize() - offset);
734 static ConstString g_sect_name_external_debug_info(
"external_debug_info");
737 if (g_sect_name_external_debug_info == sect_info.name) {
738 const uint32_t kBufferSize = 1024;
742 llvm::DataExtractor data = section_header_data.
GetAsLLVM();
743 llvm::DataExtractor::Cursor c(0);
744 llvm::Expected<std::string> symbols_url =
GetWasmString(data, c);
746 llvm::consumeError(symbols_url.takeError());
760 std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
763 ostream << static_cast<void *>(
this) <<
": ";
765 ostream <<
"ObjectFileWasm, file = '";
767 ostream <<
"', arch = ";
783 << llvm::format_hex(sh.
offset, 10) <<
" "
784 << llvm::format_hex(sh.
size, 10) <<
" " << llvm::format_hex(sh.
id, 6)
789 ostream <<
"Section Headers\n";
790 ostream <<
"IDX name addr size id\n";
791 ostream <<
"==== ---------------- ---------- ---------- ------\n";
796 ostream <<
"[" << llvm::format_decimal(idx, 2) <<
"] ";
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
#define LLDB_LOGF(log,...)
#define LLDB_LOG_ERROR(log, error,...)
static SectionType GetSectionTypeFromName(llvm::StringRef Name)
static lldb::offset_t GetWasmOffsetFromInitExpr(DataExtractor &data, lldb::offset_t &offset)
An "init expr" refers to a constant expression used to determine the initial value of certain element...
static bool ValidateModuleHeader(const DataBufferSP &data_sp)
Checks whether the data buffer starts with a valid Wasm module header.
static llvm::Expected< std::string > GetWasmString(llvm::DataExtractor &data, llvm::DataExtractor::Cursor &c)
Helper to read a Wasm string, whcih is encoded as a vector of UTF-8 codes.
static llvm::Expected< uint32_t > GetULEB32(DataExtractor &data, lldb::offset_t &offset)
Helper to read a 32-bit ULEB using LLDB's DataExtractor.
static llvm::Expected< std::vector< WasmFunction > > ParseFunctions(DataExtractor &data)
static const uint32_t kWasmHeaderSize
static llvm::Expected< std::vector< Symbol > > ParseNames(SectionSP code_section_sp, DataExtractor &name_data, const std::vector< WasmFunction > &functions, std::vector< WasmSegment > &segments)
static llvm::Expected< std::vector< WasmSegment > > ParseData(DataExtractor &data)
#define LLDB_PLUGIN_DEFINE(PluginName)
An architecture specification class.
const char * GetArchitectureName() const
Returns a static string representing the current architecture.
A uniqued constant string class.
llvm::StringRef GetStringRef() const
Get the string value as a llvm::StringRef.
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
lldb::ModuleSP GetModule() const
Get const accessor for the module pointer.
void Append(const ModuleSpec &spec)
A plug-in interface definition class for object file parsers.
DataExtractor m_data
The data for this object file so things can be parsed lazily.
std::unique_ptr< lldb_private::SectionList > m_sections_up
static lldb::DataBufferSP MapFileData(const FileSpec &file, uint64_t Size, uint64_t Offset)
ObjectFile(const lldb::ModuleSP &module_sp, const FileSpec *file_spec_ptr, lldb::offset_t file_offset, lldb::offset_t length, lldb::DataBufferSP data_sp, lldb::offset_t data_offset)
Construct with a parent module, offset, and header data.
const lldb::addr_t m_memory_addr
Set if the object file only exists in memory.
static lldb::SectionType GetDWARFSectionTypeFromName(llvm::StringRef name)
Parses the section type from a section name for DWARF sections.
virtual SectionList * GetSectionList(bool update_module_section_list=true)
Gets the section list for the currently selected architecture (and object for archives).
bool IsInMemory() const
Returns true if the object file exists only in memory.
lldb::ProcessWP m_process_wp
virtual lldb::addr_t GetByteSize() const
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description, ABICreateInstance create_callback)
static bool UnregisterPlugin(ABICreateInstance create_callback)
size_t AddSection(const lldb::SectionSP §ion_sp)
void Dump(llvm::raw_ostream &s, unsigned indent, Target *target, bool show_header, uint32_t depth) const
lldb::SectionSP GetSectionAtIndex(size_t idx) const
A stream class that can stream formatted output to a file.
llvm::raw_ostream & AsRawOstream()
Returns a raw_ostream that forwards the data to this Stream object.
size_t Indent(llvm::StringRef s="")
Indent the current line in the stream.
unsigned GetIndentLevel() const
Get the current indentation level.
uint32_t AddSymbol(const Symbol &symbol)
bool SetSectionLoadAddress(const lldb::SectionSP §ion, lldb::addr_t load_addr, bool warn_multiple=false)
Generic Wasm object file reader.
ObjectFileWasm(const lldb::ModuleSP &module_sp, lldb::DataBufferSP data_sp, lldb::offset_t data_offset, const FileSpec *file, lldb::offset_t offset, lldb::offset_t length)
ArchSpec GetArchitecture() override
Get the ArchSpec for this object file.
std::optional< FileSpec > GetExternalDebugInfoFileSpec()
A Wasm module that has external DWARF debug information should contain a custom section named "extern...
bool SetLoadAddress(lldb_private::Target &target, lldb::addr_t value, bool value_is_offset) override
Sets the load address for an entire module, assuming a rigid slide of sections, if possible in the im...
bool DecodeNextSection(lldb::offset_t *offset_ptr)
Wasm section decoding routines.
lldb::ByteOrder GetByteOrder() const override
Gets whether endian swapping should occur when extracting data from this object file.
void CreateSections(SectionList &unified_section_list) override
std::optional< section_info > GetSectionInfo(uint32_t section_id)
void Dump(Stream *s) override
Dump a description of this object to a Stream.
static llvm::StringRef GetPluginNameStatic()
std::vector< section_info > m_sect_infos
static size_t GetModuleSpecifications(const FileSpec &file, lldb::DataBufferSP &data_sp, lldb::offset_t data_offset, lldb::offset_t file_offset, lldb::offset_t length, ModuleSpecList &specs)
void DumpSectionHeader(llvm::raw_ostream &ostream, const section_info &sh)
Wasm section header dump routines.
void DumpSectionHeaders(llvm::raw_ostream &ostream)
static ObjectFile * CreateInstance(const lldb::ModuleSP &module_sp, lldb::DataBufferSP data_sp, lldb::offset_t data_offset, const FileSpec *file, lldb::offset_t file_offset, lldb::offset_t length)
static char ID
LLVM RTTI support.
std::vector< Symbol > m_symbols
void ParseSymtab(lldb_private::Symtab &symtab) override
Parse the symbol table into the provides symbol table object.
uint32_t GetAddressByteSize() const override
Gets the address size in bytes for the current object file.
static ObjectFile * CreateMemoryInstance(const lldb::ModuleSP &module_sp, lldb::WritableDataBufferSP data_sp, const lldb::ProcessSP &process_sp, lldb::addr_t header_addr)
bool ParseHeader() override
ObjectFile Protocol.
static const char * GetPluginDescriptionStatic()
DataExtractor ReadImageData(lldb::offset_t offset, uint32_t size)
Read a range of bytes from the Wasm module.
#define LLDB_INVALID_ADDRESS
#define LLDB_INVALID_OFFSET
A class that represents a running process on the host machine.
Log * GetLog(Cat mask)
Retrieve the Log object for the channel associated with the given log enum.
std::shared_ptr< lldb_private::Process > ProcessSP
std::shared_ptr< lldb_private::DataBuffer > DataBufferSP
std::shared_ptr< lldb_private::Section > SectionSP
std::shared_ptr< lldb_private::WritableDataBuffer > WritableDataBufferSP
std::shared_ptr< lldb_private::Module > ModuleSP
lldb::offset_t section_offset
lldb::offset_t section_offset
lldb::offset_t GetFileOffset() const
lldb::offset_t init_expr_offset