LLDB mainline
ObjectFileWasm.cpp
Go to the documentation of this file.
1//===-- ObjectFileWasm.cpp ------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "ObjectFileWasm.h"
10#include "lldb/Core/Module.h"
13#include "lldb/Core/Section.h"
14#include "lldb/Target/Process.h"
16#include "lldb/Target/Target.h"
19#include "lldb/Utility/Log.h"
20#include "llvm/ADT/ArrayRef.h"
21#include "llvm/ADT/SmallVector.h"
22#include "llvm/ADT/StringRef.h"
23#include "llvm/ADT/StringSwitch.h"
24#include "llvm/BinaryFormat/Magic.h"
25#include "llvm/BinaryFormat/Wasm.h"
26#include "llvm/Support/CheckedArithmetic.h"
27#include "llvm/Support/Endian.h"
28#include "llvm/Support/Format.h"
29#include <cstring>
30#include <optional>
31
32using namespace lldb;
33using namespace lldb_private;
34using namespace lldb_private::wasm;
35
37
38static const uint32_t kWasmHeaderSize =
39 sizeof(llvm::wasm::WasmMagic) + sizeof(llvm::wasm::WasmVersion);
40
41/// File address the synthetic global section is based at. Code and linear
42/// memory are both addressed from zero, so the globals need a range of their
43/// own to keep a global index from naming a code or data address as well.
46
47/// Helper to read a 32-bit ULEB using LLDB's DataExtractor.
48static inline llvm::Expected<uint32_t> GetULEB32(DataExtractor &data,
49 lldb::offset_t &offset) {
50 const uint64_t value = data.GetULEB128(&offset);
51 if (value > std::numeric_limits<uint32_t>::max())
52 return llvm::createStringError("ULEB exceeds 32 bits");
53 return value;
54}
55
56/// Helper to read a 32-bit ULEB using LLVM's DataExtractor.
57static inline llvm::Expected<uint32_t>
58GetULEB32(llvm::DataExtractor &data, llvm::DataExtractor::Cursor &c) {
59 const uint64_t value = data.getULEB128(c);
60 if (!c)
61 return c.takeError();
62 if (value > std::numeric_limits<uint32_t>::max())
63 return llvm::createStringError("ULEB exceeds 32 bits");
64 return value;
65}
66
67/// Helper to read a Wasm string, whcih is encoded as a vector of UTF-8 codes.
68static inline llvm::Expected<std::string>
69GetWasmString(llvm::DataExtractor &data, llvm::DataExtractor::Cursor &c) {
70 llvm::Expected<uint32_t> len = GetULEB32(data, c);
71 if (!len)
72 return len.takeError();
73
74 llvm::SmallVector<uint8_t, 32> str_storage;
75 data.getU8(c, str_storage, *len);
76 if (!c)
77 return c.takeError();
78
79 return std::string(toStringRef(llvm::ArrayRef(str_storage)));
80}
81
82/// An "init expr" refers to a constant expression used to determine the initial
83/// value of certain elements within a module during instantiation. These
84/// expressions are restricted to operations that can be evaluated at module
85/// instantiation time. Currently we only support simple constant opcodes.
87 lldb::offset_t &offset) {
88 lldb::offset_t init_expr_offset = LLDB_INVALID_OFFSET;
89
90 uint8_t opcode = data.GetU8(&offset);
91 switch (opcode) {
92 case llvm::wasm::WASM_OPCODE_I32_CONST:
93 case llvm::wasm::WASM_OPCODE_I64_CONST:
94 init_expr_offset = data.GetSLEB128(&offset);
95 break;
96 case llvm::wasm::WASM_OPCODE_GLOBAL_GET:
97 init_expr_offset = data.GetULEB128(&offset);
98 break;
99 case llvm::wasm::WASM_OPCODE_F32_CONST:
100 case llvm::wasm::WASM_OPCODE_F64_CONST:
101 // Not a meaningful offset.
102 data.GetFloat(&offset);
103 break;
104 case llvm::wasm::WASM_OPCODE_REF_NULL:
105 // Not a meaningful offset.
106 data.GetULEB128(&offset);
107 break;
108 }
109
110 // Make sure the opcodes we read aren't part of an extended init expr.
111 opcode = data.GetU8(&offset);
112 if (opcode == llvm::wasm::WASM_OPCODE_END)
113 return init_expr_offset;
114
115 // Extended init expressions are not supported, but we still have to parse
116 // them to skip over them and read the next segment. A truncated expression
117 // never reaches the end opcode, so the scan is bounded by the data.
118 while (opcode != llvm::wasm::WASM_OPCODE_END && data.ValidOffset(offset))
119 opcode = data.GetU8(&offset);
120 return LLDB_INVALID_OFFSET;
121}
122
123/// Checks whether the data buffer starts with a valid Wasm module header.
124static bool ValidateModuleHeader(llvm::ArrayRef<uint8_t> data) {
125 if (data.size() < kWasmHeaderSize)
126 return false;
127
128 if (llvm::identify_magic(toStringRef(data)) != llvm::file_magic::wasm_object)
129 return false;
130
131 const uint8_t *Ptr = data.data() + sizeof(llvm::wasm::WasmMagic);
132
133 uint32_t version = llvm::support::endian::read32le(Ptr);
134 return version == llvm::wasm::WasmVersion;
135}
136
138
144
148
150 DataExtractorSP extractor_sp,
151 offset_t data_offset,
152 const FileSpec *file,
153 offset_t file_offset,
154 offset_t length) {
155 Log *log = GetLog(LLDBLog::Object);
156
157 if (!extractor_sp || !extractor_sp->HasData()) {
158 DataBufferSP data_sp = MapFileData(*file, length, file_offset);
159 if (!data_sp) {
160 LLDB_LOGF(log, "Failed to create ObjectFileWasm instance for file %s",
161 file->GetPath().c_str());
162 return nullptr;
163 }
164 extractor_sp = std::make_shared<DataExtractor>(data_sp);
165 data_offset = 0;
166 }
167
168 assert(extractor_sp);
169 if (!ValidateModuleHeader(extractor_sp->GetData())) {
170 LLDB_LOGF(log,
171 "Failed to create ObjectFileWasm instance: invalid Wasm header");
172 return nullptr;
173 }
174
175 // Update the data to contain the entire file if it doesn't contain it
176 // already.
177 if (extractor_sp->GetByteSize() < length) {
178 DataBufferSP data_sp = MapFileData(*file, length, file_offset);
179 if (!data_sp) {
180 LLDB_LOGF(log,
181 "Failed to create ObjectFileWasm instance: cannot read file %s",
182 file->GetPath().c_str());
183 return nullptr;
184 }
185 extractor_sp = std::make_shared<DataExtractor>(data_sp);
186 data_offset = 0;
187 }
188
189 std::unique_ptr<ObjectFileWasm> objfile_up(new ObjectFileWasm(
190 module_sp, extractor_sp, data_offset, file, file_offset, length));
191 ArchSpec spec = objfile_up->GetArchitecture();
192 if (spec && objfile_up->SetModulesArchitecture(spec)) {
193 LLDB_LOGF(log,
194 "%p ObjectFileWasm::CreateInstance() module = %p (%s), file = %s",
195 static_cast<void *>(objfile_up.get()),
196 static_cast<void *>(objfile_up->GetModule().get()),
197 objfile_up->GetModule()->GetSpecificationDescription().c_str(),
198 file ? file->GetPath().c_str() : "<NULL>");
199 return objfile_up.release();
200 }
201
202 LLDB_LOGF(log, "Failed to create ObjectFileWasm instance");
203 return nullptr;
204}
205
207 WritableDataBufferSP data_sp,
208 const ProcessSP &process_sp,
209 addr_t header_addr) {
210 if (!ValidateModuleHeader(data_sp->GetData()))
211 return nullptr;
212
213 std::unique_ptr<ObjectFileWasm> objfile_up(
214 new ObjectFileWasm(module_sp, data_sp, process_sp, header_addr));
215 ArchSpec spec = objfile_up->GetArchitecture();
216 if (spec && objfile_up->SetModulesArchitecture(spec))
217 return objfile_up.release();
218 return nullptr;
219}
220
222 // Buffer sufficient to read a section header and find the pointer to the next
223 // section.
224 const uint32_t kBufferSize = 1024;
225 DataExtractor section_header_data = ReadImageData(*offset_ptr, kBufferSize);
226
227 llvm::DataExtractor data = section_header_data.GetAsLLVM();
228 llvm::DataExtractor::Cursor c(0);
229
230 // Each section consists of:
231 // - a one-byte section id,
232 // - the u32 size of the contents, in bytes,
233 // - the actual contents.
234 uint8_t section_id = data.getU8(c);
235 uint64_t payload_len = data.getULEB128(c);
236 if (!c)
237 return !llvm::errorToBool(c.takeError());
238
239 if (payload_len > std::numeric_limits<uint32_t>::max())
240 return false;
241
242 if (section_id == llvm::wasm::WASM_SEC_CUSTOM) {
243 // Custom sections have the id 0. Their contents consist of a name
244 // identifying the custom section, followed by an uninterpreted sequence
245 // of bytes.
246 lldb::offset_t prev_offset = c.tell();
247 llvm::Expected<std::string> sect_name = GetWasmString(data, c);
248 if (!sect_name) {
249 LLDB_LOG_ERROR(GetLog(LLDBLog::Object), sect_name.takeError(),
250 "failed to parse section name: {0}");
251 return false;
252 }
253
254 if (payload_len < c.tell() - prev_offset)
255 return false;
256
257 uint32_t section_length = payload_len - (c.tell() - prev_offset);
258 m_sect_infos.push_back(section_info{*offset_ptr + c.tell(), section_length,
259 section_id, std::move(*sect_name)});
260 *offset_ptr += (c.tell() + section_length);
261 } else if (section_id <= llvm::wasm::WASM_SEC_LAST_KNOWN) {
262 m_sect_infos.push_back(section_info{*offset_ptr + c.tell(),
263 static_cast<uint32_t>(payload_len),
264 section_id,
265 {}});
266 *offset_ptr += (c.tell() + payload_len);
267 } else {
268 // Invalid section id.
269 return false;
270 }
271 return true;
272}
273
276 if (IsInMemory()) {
277 offset += m_memory_addr;
278 }
279
280 while (DecodeNextSection(&offset))
281 ;
282 return true;
283}
284
287 DataExtractorSP &extractor_sp,
288 offset_t file_offset, offset_t length) {
289 if (!ValidateModuleHeader(extractor_sp->GetData()))
290 return {};
291
292 ModuleSpecList specs;
293 specs.Append(ModuleSpec(file, ArchSpec("wasm32")));
294 return specs;
295}
296
298 DataExtractorSP extractor_sp,
299 offset_t data_offset, const FileSpec *file,
300 offset_t offset, offset_t length)
301 : ObjectFile(module_sp, file, offset, length, extractor_sp, data_offset),
302 m_arch("wasm32") {
303 m_data_nsp->SetAddressByteSize(4);
304}
305
307 lldb::WritableDataBufferSP header_data_sp,
308 const lldb::ProcessSP &process_sp,
309 lldb::addr_t header_addr)
310 : ObjectFile(module_sp, process_sp, header_addr,
311 std::make_shared<DataExtractor>(header_data_sp)),
312 m_arch("wasm32") {}
313
315 // We already parsed the header during initialization.
316 return true;
317}
318
320 /// Offset from the section to the start of the function. This points past the
321 /// function size, which some other tools consider part of the function.
323
324 /// Function size, which includes the function header, but not the size ULEB
325 /// that proceeds it.
326 uint32_t size = 0;
327
328 /// Offset from section_offset to the first instruction in the function, past
329 /// the local variable declarations.
330 uint32_t code_offset = 0;
331};
332
333/// The number of imports of each kind. Imports occupy the low indices of the
334/// index space of their kind.
336 uint32_t functions = 0;
337 uint32_t globals = 0;
338};
339
340static llvm::Expected<WasmImports> ParseImports(DataExtractor &import_data) {
341 llvm::DataExtractor data = import_data.GetAsLLVM();
342 llvm::DataExtractor::Cursor c(0);
343
344 llvm::Expected<uint32_t> count = GetULEB32(data, c);
345 if (!count)
346 return count.takeError();
347
348 WasmImports imports;
349 for (uint32_t i = 0; c && i < *count; ++i) {
350 // We don't need module and field names, so we can just get them as raw
351 // strings and discard.
352 llvm::Expected<std::string> module_name = GetWasmString(data, c);
353 if (!module_name)
354 return llvm::joinErrors(
355 llvm::createStringError("failed to parse module name"),
356 module_name.takeError());
357 llvm::Expected<std::string> field_name = GetWasmString(data, c);
358 if (!field_name)
359 return llvm::joinErrors(
360 llvm::createStringError("failed to parse field name"),
361 field_name.takeError());
362
363 // The descriptor differs per kind, so each has to be parsed to find where
364 // the next import starts.
365 const uint8_t kind = data.getU8(c);
366 switch (kind) {
367 case llvm::wasm::WASM_EXTERNAL_FUNCTION:
368 imports.functions++;
369 data.getULEB128(c); // type index
370 break;
371 case llvm::wasm::WASM_EXTERNAL_GLOBAL:
372 imports.globals++;
373 data.getU8(c); // value type
374 data.getU8(c); // mutability
375 break;
376 case llvm::wasm::WASM_EXTERNAL_TAG:
377 data.getU8(c); // attribute
378 data.getULEB128(c); // type index
379 break;
380 case llvm::wasm::WASM_EXTERNAL_TABLE:
381 data.getU8(c); // element type
382 [[fallthrough]];
383 case llvm::wasm::WASM_EXTERNAL_MEMORY: {
384 // Tables and memories are both described by limits.
385 const uint8_t flags = data.getU8(c);
386 data.getULEB128(c); // minimum
387 if (flags & llvm::wasm::WASM_LIMITS_FLAG_HAS_MAX)
388 data.getULEB128(c);
389 break;
390 }
391 default:
392 // The cursor's error has to be consumed before it goes out of scope.
393 return llvm::joinErrors(
394 c.takeError(),
395 llvm::createStringError("unknown import kind %u", kind));
396 }
397 }
398
399 if (!c)
400 return c.takeError();
401
402 return imports;
403}
404
405/// Get the offset in the function to the first instruction.
406static llvm::Expected<uint32_t> GetFunctionCodeOffset(DataExtractor &data,
407 lldb::offset_t offset) {
408 // Wasm function bodies start with:
409 // [local_count: ULEB128]
410 // [local_decl: {count: ULEB128, type: byte}] × local_count
411 // [instructions...]
412 const lldb::offset_t locals_start = offset;
413 const uint32_t local_count = data.GetULEB128(&offset);
414 for (uint32_t i = 0; i < local_count; ++i) {
415 data.GetULEB128(&offset); // count
416 data.GetU8(&offset); // valtype
417 }
418 return offset - locals_start;
419}
420
421static llvm::Expected<std::vector<WasmFunction>>
423 lldb::offset_t offset = 0;
424
425 llvm::Expected<uint32_t> function_count = GetULEB32(data, offset);
426 if (!function_count)
427 return function_count.takeError();
428
429 std::vector<WasmFunction> functions;
430 functions.reserve(*function_count);
431
432 for (uint32_t i = 0; i < *function_count; ++i) {
433 // llvm-objdump considers the ULEB with the function size to be part of the
434 // function. We can't do that here because that would not match the DWARF,
435 // which considers the function to start with the local variable
436 // declarations (the header).
437 llvm::Expected<uint32_t> function_size = GetULEB32(data, offset);
438 if (!function_size)
439 return function_size.takeError();
440
441 // Functions start with with a number of local variable declarations.
442 // They're part of the function but they're not instructions.
443 llvm::Expected<uint32_t> code_offset = GetFunctionCodeOffset(data, offset);
444 if (!code_offset)
445 return code_offset.takeError();
446
447 functions.push_back({offset, *function_size, *code_offset});
448
449 std::optional<lldb::offset_t> next_offset =
450 llvm::checkedAddUnsigned<lldb::offset_t>(offset, *function_size);
451 if (!next_offset)
452 return llvm::createStringError("function offset overflows 64 bits");
453 offset = *next_offset;
454 }
455
456 return functions;
457}
458
474
475static llvm::Expected<std::vector<WasmSegment>> ParseData(DataExtractor &data) {
476 lldb::offset_t offset = 0;
477
478 llvm::Expected<uint32_t> segment_count = GetULEB32(data, offset);
479 if (!segment_count)
480 return segment_count.takeError();
481
482 std::vector<WasmSegment> segments;
483 segments.reserve(*segment_count);
484
485 for (uint32_t i = 0; i < *segment_count; ++i) {
486 llvm::Expected<uint32_t> flags = GetULEB32(data, offset);
487 if (!flags)
488 return flags.takeError();
489
491
492 // Data segments have a mode that identifies them as either passive or
493 // active. An active data segment copies its contents into a memory during
494 // instantiation, as specified by a memory index and a constant expression
495 // defining an offset into that memory.
496 segment.type = (*flags & llvm::wasm::WASM_DATA_SEGMENT_IS_PASSIVE)
499
500 if (*flags & llvm::wasm::WASM_DATA_SEGMENT_HAS_MEMINDEX) {
501 assert(segment.type == WasmSegment::Active);
502 llvm::Expected<uint32_t> memidx = GetULEB32(data, offset);
503 if (!memidx)
504 return memidx.takeError();
505 segment.memory_index = *memidx;
506 }
507
508 if (segment.type == WasmSegment::Active)
509 segment.init_expr_offset = GetWasmOffsetFromInitExpr(data, offset);
510
511 llvm::Expected<uint32_t> segment_size = GetULEB32(data, offset);
512 if (!segment_size)
513 return segment_size.takeError();
514
515 segment.section_offset = offset;
516 segment.size = *segment_size;
517 segments.push_back(segment);
518
519 std::optional<lldb::offset_t> next_offset =
520 llvm::checkedAddUnsigned<lldb::offset_t>(offset, *segment_size);
521 if (!next_offset)
522 return llvm::createStringError("segment offset overflows 64 bits");
523 offset = *next_offset;
524 }
525
526 return segments;
527}
528
529/// Parse the minimum size in bytes of the module's first linear memory. This is
530/// the memory guaranteed to exist at instantiation, and so the upper bound of
531/// the static data region.
532static llvm::Expected<uint64_t> ParseMemoryMinSize(DataExtractor &data) {
533 lldb::offset_t offset = 0;
534
535 llvm::Expected<uint32_t> memory_count = GetULEB32(data, offset);
536 if (!memory_count)
537 return memory_count.takeError();
538 if (*memory_count == 0)
539 return llvm::createStringError("module declares no linear memory");
540
541 // The limits of a memory are a flags byte followed by the minimum, and
542 // optionally the maximum, page count.
543 data.GetU8(&offset);
544 llvm::Expected<uint32_t> min_pages = GetULEB32(data, offset);
545 if (!min_pages)
546 return min_pages.takeError();
547
548 return static_cast<uint64_t>(*min_pages) * llvm::wasm::WasmDefaultPageSize;
549}
550
551/// Size in bytes of a WebAssembly value type, or nothing for the types whose
552/// values cannot be read.
553static std::optional<uint32_t> GetWasmValueTypeSize(uint8_t type) {
554 switch (type) {
555 case llvm::wasm::WASM_TYPE_I32:
556 case llvm::wasm::WASM_TYPE_F32:
557 return 4;
558 case llvm::wasm::WASM_TYPE_I64:
559 case llvm::wasm::WASM_TYPE_F64:
560 return 8;
561 default:
562 return std::nullopt;
563 }
564}
565
566/// Parse the init expr that gives a global its initial value. The result is the
567/// bit pattern of the value, so an operand that has to be evaluated against
568/// module state yields nothing.
569static std::optional<uint64_t> ParseGlobalInitValue(DataExtractor &data,
570 lldb::offset_t &offset) {
571 std::optional<uint64_t> value;
572
573 switch (data.GetU8(&offset)) {
574 case llvm::wasm::WASM_OPCODE_I32_CONST:
575 value = static_cast<uint32_t>(data.GetSLEB128(&offset));
576 break;
577 case llvm::wasm::WASM_OPCODE_I64_CONST:
578 value = static_cast<uint64_t>(data.GetSLEB128(&offset));
579 break;
580 case llvm::wasm::WASM_OPCODE_F32_CONST:
581 value = data.GetU32(&offset);
582 break;
583 case llvm::wasm::WASM_OPCODE_F64_CONST:
584 value = data.GetU64(&offset);
585 break;
586 case llvm::wasm::WASM_OPCODE_GLOBAL_GET:
587 case llvm::wasm::WASM_OPCODE_REF_NULL:
588 // The operand still has to be consumed to find the end of the expression.
589 data.GetULEB128(&offset);
590 break;
591 }
592
593 // An expression this parser does not understand can only be skipped to its
594 // end opcode. If that end never comes the parse is out of step, and there is
595 // no value to report.
596 uint8_t opcode = data.GetU8(&offset);
597 while (opcode != llvm::wasm::WASM_OPCODE_END && data.ValidOffset(offset))
598 opcode = data.GetU8(&offset);
599 if (opcode != llvm::wasm::WASM_OPCODE_END)
600 return std::nullopt;
601
602 return value;
603}
604
605/// Parse the module's own globals, which start at the number of imported ones.
606static llvm::Expected<std::vector<WasmGlobal>>
608 lldb::offset_t offset = 0;
609
610 llvm::Expected<uint32_t> count = GetULEB32(data, offset);
611 if (!count)
612 return count.takeError();
613
614 // The count comes from the file, so it is not a size to allocate up front.
615 std::vector<WasmGlobal> globals;
616
617 for (uint32_t i = 0; i < *count; ++i) {
618 if (!data.ValidOffset(offset))
619 return llvm::createStringError(
620 "global section holds %zu of its %u globals", globals.size(), *count);
621
622 WasmGlobal global;
623 global.size = GetWasmValueTypeSize(data.GetU8(&offset));
624 data.GetU8(&offset); // mutability
625 global.init_expr_value = ParseGlobalInitValue(data, offset);
626 globals.push_back(global);
627 }
628
629 return globals;
630}
631
632static llvm::Expected<std::vector<Symbol>>
633ParseNames(SectionSP code_section_sp, SectionSP global_section_sp,
634 DataExtractor &name_data, const std::vector<WasmFunction> &functions,
635 std::vector<WasmSegment> &segments,
636 const std::vector<WasmGlobal> &globals,
637 uint32_t num_imported_functions, uint32_t num_imported_globals) {
638
639 llvm::DataExtractor data = name_data.GetAsLLVM();
640 llvm::DataExtractor::Cursor c(0);
641 std::vector<Symbol> symbols;
642 while (c && c.tell() < data.size()) {
643 const uint8_t type = data.getU8(c);
644 llvm::Expected<uint32_t> size = GetULEB32(data, c);
645 if (!size)
646 return size.takeError();
647
648 switch (type) {
649 case llvm::wasm::WASM_NAMES_FUNCTION: {
650 const uint64_t count = data.getULEB128(c);
651 if (count > std::numeric_limits<uint32_t>::max())
652 return llvm::joinErrors(
653 c.takeError(),
654 llvm::createStringError("function count overflows uint32_t"));
655
656 for (uint64_t i = 0; c && i < count; ++i) {
657 llvm::Expected<uint32_t> idx = GetULEB32(data, c);
658 if (!idx)
659 return idx.takeError();
660 llvm::Expected<std::string> name = GetWasmString(data, c);
661 if (!name)
662 return name.takeError();
663 if (*idx >= num_imported_functions + functions.size())
664 continue;
665
666 if (*idx < num_imported_functions) {
667 symbols.emplace_back(symbols.size(), *name, lldb::eSymbolTypeCode,
668 /*external=*/true, /*is_debug=*/false,
669 /*is_trampoline=*/false,
670 /*is_artificial=*/false,
671 /*section_sp=*/lldb::SectionSP(),
672 /*value=*/0, /*size=*/0,
673 /*size_is_valid=*/false,
674 /*contains_linker_annotations=*/false,
675 /*flags=*/0);
676 } else {
677 const WasmFunction &func = functions[*idx - num_imported_functions];
678 symbols.emplace_back(symbols.size(), *name, lldb::eSymbolTypeCode,
679 /*external=*/false, /*is_debug=*/false,
680 /*is_trampoline=*/false, /*is_artificial=*/false,
681 code_section_sp, func.section_offset, func.size,
682 /*size_is_valid=*/true,
683 /*contains_linker_annotations=*/false,
684 /*flags=*/0);
685 if (func.code_offset)
686 symbols.back().SetPrologueByteSize(func.code_offset);
687 }
688 }
689 } break;
690 case llvm::wasm::WASM_NAMES_DATA_SEGMENT: {
691 llvm::Expected<uint32_t> count = GetULEB32(data, c);
692 if (!count)
693 return count.takeError();
694 for (uint32_t i = 0; c && i < *count; ++i) {
695 llvm::Expected<uint32_t> idx = GetULEB32(data, c);
696 if (!idx)
697 return idx.takeError();
698 llvm::Expected<std::string> name = GetWasmString(data, c);
699 if (!name)
700 return name.takeError();
701 if (*idx >= segments.size())
702 continue;
703 // Update the segment name.
704 segments[i].name = *name;
705 }
706
707 } break;
708 case llvm::wasm::WASM_NAMES_GLOBAL: {
709 llvm::Expected<uint32_t> count = GetULEB32(data, c);
710 if (!count)
711 return count.takeError();
712 for (uint32_t i = 0; c && i < *count; ++i) {
713 llvm::Expected<uint32_t> idx = GetULEB32(data, c);
714 if (!idx)
715 return idx.takeError();
716 llvm::Expected<std::string> name = GetWasmString(data, c);
717 if (!name)
718 return name.takeError();
719
720 // An imported global has no entry in the global section, and so no
721 // value to bound a read with.
722 if (*idx < num_imported_globals)
723 continue;
724 const uint32_t global_idx = *idx - num_imported_globals;
725 if (global_idx >= globals.size())
726 continue;
727
728 // The section is indexed rather than byte addressed, so a global spans
729 // the one index it occupies. Bounding a read by the size of the value
730 // is the section's business.
731 symbols.emplace_back(symbols.size(), *name, lldb::eSymbolTypeData,
732 /*external=*/true, /*is_debug=*/false,
733 /*is_trampoline=*/false, /*is_artificial=*/false,
734 global_section_sp, /*offset=*/*idx,
735 /*size=*/1,
736 /*size_is_valid=*/true,
737 /*contains_linker_annotations=*/false,
738 /*flags=*/0);
739 }
740 } break;
741 case llvm::wasm::WASM_NAMES_LOCAL:
742 default:
743 std::optional<lldb::offset_t> offset =
744 llvm::checkedAddUnsigned<lldb::offset_t>(c.tell(), *size);
745 if (!offset)
746 return llvm::joinErrors(
747 c.takeError(), llvm::createStringError("offset overflows 64 bits"));
748 c.seek(*offset);
749 }
750 }
751
752 if (!c)
753 return c.takeError();
754
755 return symbols;
756}
757
759 for (const Symbol &symbol : m_symbols)
760 symtab.AddSymbol(symbol);
761
762 symtab.Finalize();
763 m_symbols.clear();
764}
765
766static SectionType GetSectionTypeFromName(llvm::StringRef Name) {
767 if (Name == "name")
769 if (Name.consume_front(".debug_") || Name.consume_front(".zdebug_"))
771 return eSectionTypeOther;
772}
773
774/// A `section` attribute on a data variable lands in a named data segment on
775/// wasm, not a top-level custom section, so formatter sections appear as
776/// segment names rather than section names.
777static SectionType GetSegmentTypeFromName(llvm::StringRef Name) {
778 return llvm::StringSwitch<SectionType>(Name)
779 .Case(".lldbsummaries", eSectionTypeLLDBTypeSummaries)
780 .Case(".lldbformatters", eSectionTypeLLDBFormatters)
781 .Default(eSectionTypeData);
782}
783
784std::optional<ObjectFileWasm::section_info>
785ObjectFileWasm::GetSectionInfo(uint32_t section_id) {
786 for (const section_info &sect_info : m_sect_infos) {
787 if (sect_info.id == section_id)
788 return sect_info;
789 }
790 return std::nullopt;
791}
792
793std::optional<ObjectFileWasm::section_info>
794ObjectFileWasm::GetSectionInfo(llvm::StringRef section_name) {
795 for (const section_info &sect_info : m_sect_infos) {
796 if (sect_info.name == section_name)
797 return sect_info;
798 }
799 return std::nullopt;
800}
801
802void ObjectFileWasm::CreateSections(SectionList &unified_section_list) {
803 Log *log = GetLog(LLDBLog::Object);
804
805 if (m_sections_up)
806 return;
807
808 m_sections_up = std::make_unique<SectionList>();
809
810 if (m_sect_infos.empty()) {
812 }
813
814 for (const section_info &sect_info : m_sect_infos) {
815 SectionType section_type = eSectionTypeOther;
816 std::string section_name;
817 offset_t file_offset = sect_info.offset & 0xffffffff;
818 addr_t vm_addr = sect_info.offset;
819 size_t vm_size = sect_info.size;
820
821 if (llvm::wasm::WASM_SEC_CODE == sect_info.id) {
822 section_type = eSectionTypeCode;
823 section_name = "code";
824
825 // A code address in DWARF for WebAssembly is the offset of an
826 // instruction relative within the Code section of the WebAssembly file.
827 // For this reason Section::GetFileAddress() must return zero for the
828 // Code section.
829 vm_addr = 0;
830 } else {
831 section_type = GetSectionTypeFromName(sect_info.name);
832 if (section_type == eSectionTypeOther)
833 continue;
834 section_name = sect_info.name;
835 if (!IsInMemory()) {
836 vm_size = 0;
837 vm_addr = 0;
838 }
839 }
840
841 SectionSP section_sp = std::make_shared<Section>(
842 GetModule(), // Module to which this section belongs.
843 this, // ObjectFile to which this section belongs and
844 // should read section data from.
845 section_type, // Section ID.
846 ConstString(section_name), // Section name.
847 section_type, // Section type.
848 vm_addr, // VM address.
849 vm_size, // VM size in bytes of this section.
850 file_offset, // Offset of this section in the file.
851 sect_info.size, // Size of the section as found in the file.
852 0, // Alignment of the section
853 0); // Flags for this section.
854 m_sections_up->AddSection(section_sp);
855 unified_section_list.AddSection(section_sp);
856 }
857
858 // The name section contains names and indexes. First parse the data from the
859 // relevant sections so we can access it by its index.
860 std::vector<WasmFunction> functions;
861 std::vector<WasmSegment> segments;
862
863 // Parse the code section.
864 if (std::optional<section_info> info =
865 GetSectionInfo(llvm::wasm::WASM_SEC_CODE)) {
866 DataExtractor code_data = ReadImageData(info->offset, info->size);
867 llvm::Expected<std::vector<WasmFunction>> maybe_functions =
868 ParseFunctions(code_data);
869 if (!maybe_functions) {
870 LLDB_LOG_ERROR(log, maybe_functions.takeError(),
871 "Failed to parse Wasm code section: {0}");
872 } else {
873 functions = *maybe_functions;
874 }
875 }
876
877 // Parse the import section. The counts are needed because the function and
878 // global index spaces used in the name section include imports.
879 if (std::optional<section_info> info =
880 GetSectionInfo(llvm::wasm::WASM_SEC_IMPORT)) {
881 DataExtractor import_data = ReadImageData(info->offset, info->size);
882 llvm::Expected<WasmImports> imports = ParseImports(import_data);
883 if (!imports) {
884 LLDB_LOG_ERROR(log, imports.takeError(),
885 "Failed to parse Wasm import section: {0}");
886 } else {
887 m_num_imported_functions = imports->functions;
888 m_num_imported_globals = imports->globals;
889 }
890 }
891
892 // Parse the global section.
893 if (std::optional<section_info> info =
894 GetSectionInfo(llvm::wasm::WASM_SEC_GLOBAL)) {
895 DataExtractor global_data = ReadImageData(info->offset, info->size);
896 llvm::Expected<std::vector<WasmGlobal>> globals = ParseGlobals(global_data);
897 if (!globals) {
898 LLDB_LOG_ERROR(log, globals.takeError(),
899 "Failed to parse Wasm global section: {0}");
900 } else {
901 m_globals = *globals;
902 }
903 }
904
905 // Parse the data section.
906 std::optional<section_info> data_info =
907 GetSectionInfo(llvm::wasm::WASM_SEC_DATA);
908 if (data_info) {
909 DataExtractor data_data = ReadImageData(data_info->offset, data_info->size);
910 llvm::Expected<std::vector<WasmSegment>> maybe_segments =
911 ParseData(data_data);
912 if (!maybe_segments) {
913 LLDB_LOG_ERROR(log, maybe_segments.takeError(),
914 "Failed to parse Wasm data section: {0}");
915 } else {
916 segments = *maybe_segments;
917 }
918 }
919
920 // The section maps nothing: it exists to give globals an address, which is
921 // what lets one be named and read. Its size counts globals rather than bytes,
922 // imported ones included, because they share the index space.
923 SectionSP global_section_sp;
924 if (!m_globals.empty()) {
925 global_section_sp = std::make_shared<Section>(
926 GetModule(),
927 /*obj_file=*/this, eSectionTypeWasmGlobal, ConstString("global"),
929 /*file_vm_addr=*/kWasmGlobalFileAddress,
930 /*vm_size=*/m_num_imported_globals + m_globals.size(),
931 /*file_offset=*/0, /*file_size=*/0,
932 /*log2align=*/0, /*flags=*/0);
933 m_sections_up->AddSection(global_section_sp);
934 unified_section_list.AddSection(global_section_sp);
935 }
936
937 if (std::optional<section_info> info = GetSectionInfo("name")) {
938 DataExtractor names_data = ReadImageData(info->offset, info->size);
939 llvm::Expected<std::vector<Symbol>> symbols = ParseNames(
940 m_sections_up->FindSectionByType(lldb::eSectionTypeCode, false),
941 global_section_sp, names_data, functions, segments, m_globals,
943 if (!symbols) {
944 LLDB_LOG_ERROR(log, symbols.takeError(),
945 "Failed to parse Wasm names: {0}");
946 } else {
947 m_symbols = *symbols;
948 }
949 }
950
951 lldb::user_id_t segment_id = 0;
952 lldb::addr_t static_data_end = 0;
953 for (const WasmSegment &segment : segments) {
954 if (segment.type == WasmSegment::Active) {
955 // FIXME: Support segments with a memory index.
956 if (segment.memory_index != 0) {
957 LLDB_LOG(log,
958 "Skipping segment {}: non-zero memory index is "
959 "currently unsupported",
960 segment.name);
961 continue;
962 }
963
964 if (segment.init_expr_offset == LLDB_INVALID_OFFSET) {
965 LLDB_LOG(log, "Skipping segment {}: unsupported init expression",
966 segment.name);
967 continue;
968 }
969 }
970
971 const lldb::addr_t file_vm_addr =
973 ? segment.init_expr_offset
974 : data_info->offset + segment.section_offset;
975 const lldb::offset_t file_offset =
976 data_info->GetFileOffset() + segment.GetFileOffset();
977 SectionSP segment_sp = std::make_shared<Section>(
978 GetModule(),
979 /*obj_file=*/this,
980 ++segment_id << 8, // 1-based segment index, shifted by 8 bits to avoid
981 // collision with section IDs.
983 /*file_vm_addr=*/file_vm_addr,
984 /*vm_size=*/segment.size,
985 /*file_offset=*/file_offset,
986 /*file_size=*/segment.size,
987 /*log2align=*/0, /*flags=*/0);
988 m_sections_up->AddSection(segment_sp);
989 GetModule()->GetSectionList()->AddSection(segment_sp);
990
991 if (segment.type == WasmSegment::Active)
992 static_data_end = std::max(static_data_end, file_vm_addr + segment.size);
993 }
994
995 // Zero-initialized globals (BSS) have no data segment, so the loop above
996 // leaves their linear-memory addresses uncovered by any section, and a static
997 // read of one can't be resolved. Cover the rest of linear memory with a
998 // zero-fill section. SetLoadAddress maps it like a data segment so live reads
999 // still go through process memory.
1000 if (std::optional<section_info> mem_info =
1001 GetSectionInfo(llvm::wasm::WASM_SEC_MEMORY)) {
1002 DataExtractor mem_data = ReadImageData(mem_info->offset, mem_info->size);
1003 llvm::Expected<uint64_t> memory_size = ParseMemoryMinSize(mem_data);
1004 if (!memory_size) {
1005 LLDB_LOG_ERROR(log, memory_size.takeError(),
1006 "Failed to parse Wasm memory section: {0}");
1007 } else if (*memory_size > static_data_end) {
1008 SectionSP bss_sp =
1009 std::make_shared<Section>(GetModule(),
1010 /*obj_file=*/this, ++segment_id << 8,
1012 /*file_vm_addr=*/static_data_end,
1013 /*vm_size=*/*memory_size - static_data_end,
1014 /*file_offset=*/0,
1015 /*file_size=*/0,
1016 /*log2align=*/0, /*flags=*/0);
1017 m_sections_up->AddSection(bss_sp);
1018 GetModule()->GetSectionList()->AddSection(bss_sp);
1019 }
1020 }
1021}
1022
1024 lldb::offset_t section_offset, void *dst,
1025 size_t dst_len) {
1026 if (!section || section->GetType() != eSectionTypeWasmGlobal)
1027 return ObjectFile::ReadSectionData(section, section_offset, dst, dst_len);
1028
1029 // The low indices belong to imported globals, which the module does not
1030 // declare and so has no initializer for.
1031 if (section_offset < m_num_imported_globals)
1032 return 0;
1033 const lldb::offset_t index = section_offset - m_num_imported_globals;
1034 if (index >= m_globals.size())
1035 return 0;
1036
1037 const WasmGlobal &global = m_globals[index];
1038 if (!global.init_expr_value || !global.size || dst_len > *global.size)
1039 return 0;
1040
1041 // A global holds a value rather than bytes, and WebAssembly is little-endian.
1042 uint8_t bytes[sizeof(uint64_t)];
1043 llvm::support::endian::write64le(bytes, *global.init_expr_value);
1044 std::memcpy(dst, bytes, dst_len);
1045 return dst_len;
1046}
1047
1049 bool value_is_offset) {
1050 /// In WebAssembly, linear memory is disjointed from code space. The VM can
1051 /// load multiple instances of a module, which logically share the same code.
1052 /// We represent a wasm32 code address with 64-bits, like:
1053 /// 63 32 31 0
1054 /// +---------------+---------------+
1055 /// + module_id | offset |
1056 /// +---------------+---------------+
1057 /// where the lower 32 bits represent a module offset (relative to the module
1058 /// start not to the beginning of the code section) and the higher 32 bits
1059 /// uniquely identify the module in the WebAssembly VM.
1060 /// In other words, we assume that each WebAssembly module is loaded by the
1061 /// engine at a 64-bit address that starts at the boundary of 4GB pages, like
1062 /// 0x0000000400000000 for module_id == 4.
1063 /// These 64-bit addresses will be used to request code ranges for a specific
1064 /// module from the WebAssembly engine.
1065
1067 m_memory_addr == load_address);
1068
1069 ModuleSP module_sp = GetModule();
1070 if (!module_sp)
1071 return false;
1072
1074
1075 size_t num_loaded_sections = 0;
1076 SectionList *section_list = GetSectionList();
1077 if (!section_list)
1078 return false;
1079
1080 const size_t num_sections = section_list->GetSize();
1081 for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) {
1082 SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx));
1083 lldb::addr_t section_load_addr;
1084 switch (section_sp->GetType()) {
1085 case eSectionTypeData:
1090 // These live in linear memory, and the globals in an index space of their
1091 // own, both separate from code. A section's file address already carries
1092 // the space it belongs to, so only the module id comes from the load
1093 // address.
1094 section_load_addr =
1095 (load_address & ~kWasmAddressTypeMask) | section_sp->GetFileAddress();
1096 break;
1097 default:
1098 // Code (and other) sections are addressed by their offset within the
1099 // module in the Object address space.
1100 section_load_addr = load_address | section_sp->GetFileOffset();
1101 break;
1102 }
1103 if (target.SetSectionLoadAddress(section_sp, section_load_addr))
1104 ++num_loaded_sections;
1105 }
1106
1107 return num_loaded_sections > 0;
1108}
1109
1111 DataExtractor data;
1112 if (m_file) {
1113 if (offset < GetByteSize()) {
1114 size = std::min(static_cast<uint64_t>(size), GetByteSize() - offset);
1115 auto buffer_sp = MapFileData(m_file, size, offset);
1116 return DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize());
1117 }
1118 } else {
1119 ProcessSP process_sp(m_process_wp.lock());
1120 if (process_sp) {
1121 auto data_up = std::make_unique<DataBufferHeap>(size, 0);
1122 Status readmem_error;
1123 size_t bytes_read = process_sp->ReadMemory(
1124 offset, data_up->GetBytes(), data_up->GetByteSize(), readmem_error);
1125 if (bytes_read > 0) {
1126 DataBufferSP buffer_sp(data_up.release());
1127 data.SetData(buffer_sp);
1128 }
1129 } else if (offset < m_data_nsp->GetByteSize()) {
1130 size = std::min(static_cast<uint64_t>(size),
1131 m_data_nsp->GetByteSize() - offset);
1132 return DataExtractor(m_data_nsp->GetDataStart() + offset, size,
1134 }
1135 }
1136 data.SetByteOrder(GetByteOrder());
1137 return data;
1138}
1139
1141 if (m_uuid)
1142 return m_uuid;
1143
1144 // A Wasm module carries the identifier a linker gave it in a custom section,
1145 // as a vector of bytes. It is the only thing that tells one build of a module
1146 // from another, so a module linked without one cannot be identified at all.
1147 static constexpr llvm::StringLiteral g_sect_name_build_id("build_id");
1148 for (const section_info &sect_info : m_sect_infos) {
1149 if (g_sect_name_build_id != sect_info.name)
1150 continue;
1151
1152 DataExtractor section_data =
1153 ReadImageData(sect_info.offset, sect_info.size);
1154 llvm::DataExtractor data = section_data.GetAsLLVM();
1155 llvm::DataExtractor::Cursor c(0);
1156 llvm::Expected<uint32_t> length = GetULEB32(data, c);
1157 if (!length) {
1158 LLDB_LOG_ERROR(GetLog(LLDBLog::Object), length.takeError(),
1159 "failed to parse the build id length: {0}");
1160 return m_uuid;
1161 }
1162 llvm::SmallVector<uint8_t, 32> id(*length, 0);
1163 data.getU8(c, id.data(), id.size());
1164 if (!c) {
1165 LLDB_LOG_ERROR(GetLog(LLDBLog::Object), c.takeError(),
1166 "failed to parse the build id: {0}");
1167 return m_uuid;
1168 }
1169 m_uuid = UUID(id);
1170 break;
1171 }
1172
1173 return m_uuid;
1174}
1175
1177 static constexpr llvm::StringLiteral g_sect_name_external_debug_info(
1178 "external_debug_info");
1179
1180 for (const section_info &sect_info : m_sect_infos) {
1181 if (g_sect_name_external_debug_info == sect_info.name) {
1182 const uint32_t kBufferSize = 1024;
1183 DataExtractor section_header_data =
1184 ReadImageData(sect_info.offset, kBufferSize);
1185
1186 llvm::DataExtractor data = section_header_data.GetAsLLVM();
1187 llvm::DataExtractor::Cursor c(0);
1188 llvm::Expected<std::string> symbols_url = GetWasmString(data, c);
1189 if (!symbols_url) {
1190 llvm::consumeError(symbols_url.takeError());
1191 return std::nullopt;
1192 }
1193 return FileSpec(*symbols_url);
1194 }
1195 }
1196 return std::nullopt;
1197}
1198
1200 ModuleSP module_sp(GetModule());
1201 if (!module_sp)
1202 return;
1203
1204 std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
1205
1206 llvm::raw_ostream &ostream = s->AsRawOstream();
1207 ostream << static_cast<void *>(this) << ": ";
1208 s->Indent();
1209 ostream << "ObjectFileWasm, file = '";
1210 m_file.Dump(ostream);
1211 ostream << "', arch = ";
1212 ostream << GetArchitecture().GetArchitectureName() << "\n";
1213
1214 SectionList *sections = GetSectionList();
1215 if (sections) {
1216 sections->Dump(s->AsRawOstream(), s->GetIndentLevel(), nullptr, true,
1217 UINT32_MAX);
1218 }
1219 ostream << "\n";
1220 DumpSectionHeaders(ostream);
1221 ostream << "\n";
1222}
1223
1224void ObjectFileWasm::DumpSectionHeader(llvm::raw_ostream &ostream,
1225 const section_info &sh) {
1226 ostream << llvm::left_justify(sh.name, 16) << " "
1227 << llvm::format_hex(sh.offset, 10) << " "
1228 << llvm::format_hex(sh.size, 10) << " " << llvm::format_hex(sh.id, 6)
1229 << "\n";
1230}
1231
1232void ObjectFileWasm::DumpSectionHeaders(llvm::raw_ostream &ostream) {
1233 ostream << "Section Headers\n";
1234 ostream << "IDX name addr size id\n";
1235 ostream << "==== ---------------- ---------- ---------- ------\n";
1236
1237 uint32_t idx = 0;
1238 for (auto pos = m_sect_infos.begin(); pos != m_sect_infos.end();
1239 ++pos, ++idx) {
1240 ostream << "[" << llvm::format_decimal(idx, 2) << "] ";
1241 ObjectFileWasm::DumpSectionHeader(ostream, *pos);
1242 }
1243}
#define LLDB_LOG(log,...)
The LLDB_LOG* macros defined below are the way to emit log messages.
Definition Log.h:375
#define LLDB_LOGF(log,...)
Definition Log.h:389
#define LLDB_LOG_ERROR(log, error,...)
Definition Log.h:405
static SectionType GetSectionTypeFromName(llvm::StringRef Name)
static std::optional< uint32_t > GetWasmValueTypeSize(uint8_t type)
Size in bytes of a WebAssembly value type, or nothing for the types whose values cannot be read.
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 llvm::Expected< std::vector< WasmGlobal > > ParseGlobals(DataExtractor &data)
Parse the module's own globals, which start at the number of imported ones.
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< WasmImports > ParseImports(DataExtractor &import_data)
static llvm::Expected< uint32_t > GetFunctionCodeOffset(DataExtractor &data, lldb::offset_t offset)
Get the offset in the function to the first instruction.
static llvm::Expected< std::vector< WasmFunction > > ParseFunctions(DataExtractor &data)
static llvm::Expected< std::vector< Symbol > > ParseNames(SectionSP code_section_sp, SectionSP global_section_sp, DataExtractor &name_data, const std::vector< WasmFunction > &functions, std::vector< WasmSegment > &segments, const std::vector< WasmGlobal > &globals, uint32_t num_imported_functions, uint32_t num_imported_globals)
static bool ValidateModuleHeader(llvm::ArrayRef< uint8_t > data)
Checks whether the data buffer starts with a valid Wasm module header.
static SectionType GetSegmentTypeFromName(llvm::StringRef Name)
A section attribute on a data variable lands in a named data segment on wasm, not a top-level custom ...
static const uint32_t kWasmHeaderSize
static llvm::Expected< uint64_t > ParseMemoryMinSize(DataExtractor &data)
Parse the minimum size in bytes of the module's first linear memory.
static constexpr lldb::addr_t kWasmGlobalFileAddress
File address the synthetic global section is based at.
static std::optional< uint64_t > ParseGlobalInitValue(DataExtractor &data, lldb::offset_t &offset)
Parse the init expr that gives a global its initial value.
static llvm::Expected< std::vector< WasmSegment > > ParseData(DataExtractor &data)
#define LLDB_PLUGIN_DEFINE(PluginName)
An architecture specification class.
Definition ArchSpec.h:32
const char * GetArchitectureName() const
Returns a static string representing the current architecture.
Definition ArchSpec.cpp:742
A uniqued constant string class.
Definition ConstString.h:40
An data extractor class.
uint64_t GetULEB128(lldb::offset_t *offset_ptr) const
Extract a unsigned LEB128 value from *offset_ptr.
float GetFloat(lldb::offset_t *offset_ptr) const
Extract a float from *offset_ptr.
uint64_t GetU64(lldb::offset_t *offset_ptr) const
Extract a uint64_t value from *offset_ptr.
llvm::DataExtractor GetAsLLVM() const
void SetByteOrder(lldb::ByteOrder byte_order)
Set the byte_order value.
uint32_t GetU32(lldb::offset_t *offset_ptr) const
Extract a uint32_t value from *offset_ptr.
bool ValidOffset(lldb::offset_t offset) const
Test the validity of offset.
virtual lldb::offset_t SetData(const void *bytes, lldb::offset_t length, lldb::ByteOrder byte_order)
Set data with a buffer that is caller owned.
int64_t GetSLEB128(lldb::offset_t *offset_ptr) const
Extract a signed LEB128 value from *offset_ptr.
uint8_t GetU8(lldb::offset_t *offset_ptr) const
Extract a uint8_t value from *offset_ptr.
A file utility class.
Definition FileSpec.h:56
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition FileSpec.cpp:380
lldb::ModuleSP GetModule() const
Get const accessor for the module pointer.
void Append(const ModuleSpec &spec)
Definition ModuleSpec.h:371
std::unique_ptr< lldb_private::SectionList > m_sections_up
Definition ObjectFile.h:785
static lldb::DataBufferSP MapFileData(const FileSpec &file, uint64_t Size, uint64_t Offset)
const lldb::addr_t m_memory_addr
Set if the object file only exists in memory.
Definition ObjectFile.h:783
static lldb::SectionType GetDWARFSectionTypeFromName(llvm::StringRef name)
Parses the section type from a section name for DWARF sections.
DataExtractorNSP m_data_nsp
The data for this object file so things can be parsed lazily.
Definition ObjectFile.h:777
virtual SectionList * GetSectionList(bool update_module_section_list=true)
Gets the section list for the currently selected architecture (and object for archives).
ObjectFile(const lldb::ModuleSP &module_sp, const FileSpec *file_spec_ptr, lldb::offset_t file_offset, lldb::offset_t length, lldb::DataExtractorSP extractor_sp, lldb::offset_t data_offset)
Construct with a parent module, offset, and header data.
bool IsInMemory() const
Returns true if the object file exists only in memory.
Definition ObjectFile.h:691
lldb::ProcessWP m_process_wp
Definition ObjectFile.h:781
virtual size_t ReadSectionData(Section *section, lldb::offset_t section_offset, void *dst, size_t dst_len)
virtual lldb::addr_t GetByteSize() const
Definition ObjectFile.h:273
static bool RegisterPlugin(llvm::StringRef name, llvm::StringRef description, ABICreateInstance create_callback)
static bool UnregisterPlugin(ABICreateInstance create_callback)
size_t GetSize() const
Definition Section.h:77
size_t AddSection(const lldb::SectionSP &section_sp)
Definition Section.cpp:483
void Dump(llvm::raw_ostream &s, unsigned indent, Target *target, bool show_header, uint32_t depth) const
Definition Section.cpp:648
lldb::SectionSP GetSectionAtIndex(size_t idx) const
Definition Section.cpp:555
lldb::SectionType GetType() const
Definition Section.h:215
An error handling class.
Definition Status.h:118
A stream class that can stream formatted output to a file.
Definition Stream.h:28
llvm::raw_ostream & AsRawOstream()
Returns a raw_ostream that forwards the data to this Stream object.
Definition Stream.h:405
size_t Indent(llvm::StringRef s="")
Indent the current line in the stream.
Definition Stream.cpp:157
unsigned GetIndentLevel() const
Get the current indentation level.
Definition Stream.cpp:193
uint32_t AddSymbol(const Symbol &symbol)
Definition Symtab.cpp:61
bool SetSectionLoadAddress(const lldb::SectionSP &section, lldb::addr_t load_addr, bool warn_multiple=false)
Definition Target.cpp:3506
Represents UUID's of various sizes.
Definition UUID.h:27
Generic Wasm object file reader.
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...
size_t ReadSectionData(Section *section, lldb::offset_t section_offset, void *dst, size_t dst_len) override
A global has no bytes in the module to read, so serve its initial value when there is no process to a...
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
ObjectFileWasm(const lldb::ModuleSP &module_sp, lldb::DataExtractorSP extractor_sp, lldb::offset_t data_offset, const FileSpec *file, lldb::offset_t offset, lldb::offset_t length)
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
UUID GetUUID() override
Gets the UUID for this object file.
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::DataExtractorSP extractor_sp, lldb::offset_t data_offset, const FileSpec *file, lldb::offset_t file_offset, lldb::offset_t length)
static char ID
LLVM RTTI support.
void ParseSymtab(lldb_private::Symtab &symtab) override
Parse the symbol table into the provides symbol table object.
static ModuleSpecList GetModuleSpecifications(const FileSpec &file, lldb::DataExtractorSP &extractor_sp, lldb::offset_t file_offset, lldb::offset_t length)
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)
std::vector< WasmGlobal > m_globals
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
#define UINT32_MAX
static constexpr uint64_t kWasmAddressTypeMask
Definition WasmAddress.h:57
WasmAddressType
Each WebAssembly module has separate address spaces for Code and Memory.
Definition WasmAddress.h:29
static constexpr uint32_t kWasmAddressTypeShift
Definition WasmAddress.h:47
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.
Definition Log.h:338
uint64_t offset_t
Definition lldb-types.h:86
std::shared_ptr< lldb_private::Process > ProcessSP
uint64_t user_id_t
Definition lldb-types.h:83
std::shared_ptr< lldb_private::DataBuffer > DataBufferSP
std::shared_ptr< lldb_private::Section > SectionSP
std::shared_ptr< lldb_private::WritableDataBuffer > WritableDataBufferSP
uint64_t addr_t
Definition lldb-types.h:80
@ eSectionTypeZeroFill
@ eSectionTypeLLDBFormatters
@ eSectionTypeWasmGlobal
@ eSectionTypeLLDBTypeSummaries
@ eSectionTypeWasmName
std::shared_ptr< lldb_private::DataExtractor > DataExtractorSP
std::shared_ptr< lldb_private::Module > ModuleSP
lldb::offset_t section_offset
Offset from the section to the start of the function.
uint32_t code_offset
Offset from section_offset to the first instruction in the function, past the local variable declarat...
uint32_t size
Function size, which includes the function header, but not the size ULEB that proceeds it.
The number of imports of each kind.
SegmentType type
std::string name
uint32_t memory_index
lldb::offset_t section_offset
lldb::offset_t GetFileOffset() const
lldb::offset_t init_expr_offset
A global declared by the module itself.
std::optional< uint32_t > size
Size of the global's value type, which bounds what a read can produce.
std::optional< uint64_t > init_expr_value
Value the global is initialized with, when the initializer is a constant.
std::string name