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, ConstString(*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, ConstString()});
265 *offset_ptr += (c.tell() + payload_len);
266 } else {
267 // Invalid section id.
268 return false;
269 }
270 return true;
271}
272
275 if (IsInMemory()) {
276 offset += m_memory_addr;
277 }
278
279 while (DecodeNextSection(&offset))
280 ;
281 return true;
282}
283
286 DataExtractorSP &extractor_sp,
287 offset_t file_offset, offset_t length) {
288 if (!ValidateModuleHeader(extractor_sp->GetData()))
289 return {};
290
291 ModuleSpecList specs;
292 specs.Append(ModuleSpec(file, ArchSpec("wasm32")));
293 return specs;
294}
295
297 DataExtractorSP extractor_sp,
298 offset_t data_offset, const FileSpec *file,
299 offset_t offset, offset_t length)
300 : ObjectFile(module_sp, file, offset, length, extractor_sp, data_offset),
301 m_arch("wasm32") {
302 m_data_nsp->SetAddressByteSize(4);
303}
304
306 lldb::WritableDataBufferSP header_data_sp,
307 const lldb::ProcessSP &process_sp,
308 lldb::addr_t header_addr)
309 : ObjectFile(module_sp, process_sp, header_addr,
310 std::make_shared<DataExtractor>(header_data_sp)),
311 m_arch("wasm32") {}
312
314 // We already parsed the header during initialization.
315 return true;
316}
317
319 /// Offset from the section to the start of the function. This points past the
320 /// function size, which some other tools consider part of the function.
322
323 /// Function size, which includes the function header, but not the size ULEB
324 /// that proceeds it.
325 uint32_t size = 0;
326
327 /// Offset from section_offset to the first instruction in the function, past
328 /// the local variable declarations.
329 uint32_t code_offset = 0;
330};
331
332/// The number of imports of each kind. Imports occupy the low indices of the
333/// index space of their kind.
335 uint32_t functions = 0;
336 uint32_t globals = 0;
337};
338
339static llvm::Expected<WasmImports> ParseImports(DataExtractor &import_data) {
340 llvm::DataExtractor data = import_data.GetAsLLVM();
341 llvm::DataExtractor::Cursor c(0);
342
343 llvm::Expected<uint32_t> count = GetULEB32(data, c);
344 if (!count)
345 return count.takeError();
346
347 WasmImports imports;
348 for (uint32_t i = 0; c && i < *count; ++i) {
349 // We don't need module and field names, so we can just get them as raw
350 // strings and discard.
351 llvm::Expected<std::string> module_name = GetWasmString(data, c);
352 if (!module_name)
353 return llvm::joinErrors(
354 llvm::createStringError("failed to parse module name"),
355 module_name.takeError());
356 llvm::Expected<std::string> field_name = GetWasmString(data, c);
357 if (!field_name)
358 return llvm::joinErrors(
359 llvm::createStringError("failed to parse field name"),
360 field_name.takeError());
361
362 // The descriptor differs per kind, so each has to be parsed to find where
363 // the next import starts.
364 const uint8_t kind = data.getU8(c);
365 switch (kind) {
366 case llvm::wasm::WASM_EXTERNAL_FUNCTION:
367 imports.functions++;
368 data.getULEB128(c); // type index
369 break;
370 case llvm::wasm::WASM_EXTERNAL_GLOBAL:
371 imports.globals++;
372 data.getU8(c); // value type
373 data.getU8(c); // mutability
374 break;
375 case llvm::wasm::WASM_EXTERNAL_TAG:
376 data.getU8(c); // attribute
377 data.getULEB128(c); // type index
378 break;
379 case llvm::wasm::WASM_EXTERNAL_TABLE:
380 data.getU8(c); // element type
381 [[fallthrough]];
382 case llvm::wasm::WASM_EXTERNAL_MEMORY: {
383 // Tables and memories are both described by limits.
384 const uint8_t flags = data.getU8(c);
385 data.getULEB128(c); // minimum
386 if (flags & llvm::wasm::WASM_LIMITS_FLAG_HAS_MAX)
387 data.getULEB128(c);
388 break;
389 }
390 default:
391 // The cursor's error has to be consumed before it goes out of scope.
392 return llvm::joinErrors(
393 c.takeError(),
394 llvm::createStringError("unknown import kind %u", kind));
395 }
396 }
397
398 if (!c)
399 return c.takeError();
400
401 return imports;
402}
403
404/// Get the offset in the function to the first instruction.
405static llvm::Expected<uint32_t> GetFunctionCodeOffset(DataExtractor &data,
406 lldb::offset_t offset) {
407 // Wasm function bodies start with:
408 // [local_count: ULEB128]
409 // [local_decl: {count: ULEB128, type: byte}] × local_count
410 // [instructions...]
411 const lldb::offset_t locals_start = offset;
412 const uint32_t local_count = data.GetULEB128(&offset);
413 for (uint32_t i = 0; i < local_count; ++i) {
414 data.GetULEB128(&offset); // count
415 data.GetU8(&offset); // valtype
416 }
417 return offset - locals_start;
418}
419
420static llvm::Expected<std::vector<WasmFunction>>
422 lldb::offset_t offset = 0;
423
424 llvm::Expected<uint32_t> function_count = GetULEB32(data, offset);
425 if (!function_count)
426 return function_count.takeError();
427
428 std::vector<WasmFunction> functions;
429 functions.reserve(*function_count);
430
431 for (uint32_t i = 0; i < *function_count; ++i) {
432 // llvm-objdump considers the ULEB with the function size to be part of the
433 // function. We can't do that here because that would not match the DWARF,
434 // which considers the function to start with the local variable
435 // declarations (the header).
436 llvm::Expected<uint32_t> function_size = GetULEB32(data, offset);
437 if (!function_size)
438 return function_size.takeError();
439
440 // Functions start with with a number of local variable declarations.
441 // They're part of the function but they're not instructions.
442 llvm::Expected<uint32_t> code_offset = GetFunctionCodeOffset(data, offset);
443 if (!code_offset)
444 return code_offset.takeError();
445
446 functions.push_back({offset, *function_size, *code_offset});
447
448 std::optional<lldb::offset_t> next_offset =
449 llvm::checkedAddUnsigned<lldb::offset_t>(offset, *function_size);
450 if (!next_offset)
451 return llvm::createStringError("function offset overflows 64 bits");
452 offset = *next_offset;
453 }
454
455 return functions;
456}
457
473
474static llvm::Expected<std::vector<WasmSegment>> ParseData(DataExtractor &data) {
475 lldb::offset_t offset = 0;
476
477 llvm::Expected<uint32_t> segment_count = GetULEB32(data, offset);
478 if (!segment_count)
479 return segment_count.takeError();
480
481 std::vector<WasmSegment> segments;
482 segments.reserve(*segment_count);
483
484 for (uint32_t i = 0; i < *segment_count; ++i) {
485 llvm::Expected<uint32_t> flags = GetULEB32(data, offset);
486 if (!flags)
487 return flags.takeError();
488
490
491 // Data segments have a mode that identifies them as either passive or
492 // active. An active data segment copies its contents into a memory during
493 // instantiation, as specified by a memory index and a constant expression
494 // defining an offset into that memory.
495 segment.type = (*flags & llvm::wasm::WASM_DATA_SEGMENT_IS_PASSIVE)
498
499 if (*flags & llvm::wasm::WASM_DATA_SEGMENT_HAS_MEMINDEX) {
500 assert(segment.type == WasmSegment::Active);
501 llvm::Expected<uint32_t> memidx = GetULEB32(data, offset);
502 if (!memidx)
503 return memidx.takeError();
504 segment.memory_index = *memidx;
505 }
506
507 if (segment.type == WasmSegment::Active)
508 segment.init_expr_offset = GetWasmOffsetFromInitExpr(data, offset);
509
510 llvm::Expected<uint32_t> segment_size = GetULEB32(data, offset);
511 if (!segment_size)
512 return segment_size.takeError();
513
514 segment.section_offset = offset;
515 segment.size = *segment_size;
516 segments.push_back(segment);
517
518 std::optional<lldb::offset_t> next_offset =
519 llvm::checkedAddUnsigned<lldb::offset_t>(offset, *segment_size);
520 if (!next_offset)
521 return llvm::createStringError("segment offset overflows 64 bits");
522 offset = *next_offset;
523 }
524
525 return segments;
526}
527
528/// Parse the minimum size in bytes of the module's first linear memory. This is
529/// the memory guaranteed to exist at instantiation, and so the upper bound of
530/// the static data region.
531static llvm::Expected<uint64_t> ParseMemoryMinSize(DataExtractor &data) {
532 lldb::offset_t offset = 0;
533
534 llvm::Expected<uint32_t> memory_count = GetULEB32(data, offset);
535 if (!memory_count)
536 return memory_count.takeError();
537 if (*memory_count == 0)
538 return llvm::createStringError("module declares no linear memory");
539
540 // The limits of a memory are a flags byte followed by the minimum, and
541 // optionally the maximum, page count.
542 data.GetU8(&offset);
543 llvm::Expected<uint32_t> min_pages = GetULEB32(data, offset);
544 if (!min_pages)
545 return min_pages.takeError();
546
547 return static_cast<uint64_t>(*min_pages) * llvm::wasm::WasmDefaultPageSize;
548}
549
550/// Size in bytes of a WebAssembly value type, or nothing for the types whose
551/// values cannot be read.
552static std::optional<uint32_t> GetWasmValueTypeSize(uint8_t type) {
553 switch (type) {
554 case llvm::wasm::WASM_TYPE_I32:
555 case llvm::wasm::WASM_TYPE_F32:
556 return 4;
557 case llvm::wasm::WASM_TYPE_I64:
558 case llvm::wasm::WASM_TYPE_F64:
559 return 8;
560 default:
561 return std::nullopt;
562 }
563}
564
565/// Parse the init expr that gives a global its initial value. The result is the
566/// bit pattern of the value, so an operand that has to be evaluated against
567/// module state yields nothing.
568static std::optional<uint64_t> ParseGlobalInitValue(DataExtractor &data,
569 lldb::offset_t &offset) {
570 std::optional<uint64_t> value;
571
572 switch (data.GetU8(&offset)) {
573 case llvm::wasm::WASM_OPCODE_I32_CONST:
574 value = static_cast<uint32_t>(data.GetSLEB128(&offset));
575 break;
576 case llvm::wasm::WASM_OPCODE_I64_CONST:
577 value = static_cast<uint64_t>(data.GetSLEB128(&offset));
578 break;
579 case llvm::wasm::WASM_OPCODE_F32_CONST:
580 value = data.GetU32(&offset);
581 break;
582 case llvm::wasm::WASM_OPCODE_F64_CONST:
583 value = data.GetU64(&offset);
584 break;
585 case llvm::wasm::WASM_OPCODE_GLOBAL_GET:
586 case llvm::wasm::WASM_OPCODE_REF_NULL:
587 // The operand still has to be consumed to find the end of the expression.
588 data.GetULEB128(&offset);
589 break;
590 }
591
592 // An expression this parser does not understand can only be skipped to its
593 // end opcode. If that end never comes the parse is out of step, and there is
594 // no value to report.
595 uint8_t opcode = data.GetU8(&offset);
596 while (opcode != llvm::wasm::WASM_OPCODE_END && data.ValidOffset(offset))
597 opcode = data.GetU8(&offset);
598 if (opcode != llvm::wasm::WASM_OPCODE_END)
599 return std::nullopt;
600
601 return value;
602}
603
604/// Parse the module's own globals, which start at the number of imported ones.
605static llvm::Expected<std::vector<WasmGlobal>>
607 lldb::offset_t offset = 0;
608
609 llvm::Expected<uint32_t> count = GetULEB32(data, offset);
610 if (!count)
611 return count.takeError();
612
613 // The count comes from the file, so it is not a size to allocate up front.
614 std::vector<WasmGlobal> globals;
615
616 for (uint32_t i = 0; i < *count; ++i) {
617 if (!data.ValidOffset(offset))
618 return llvm::createStringError(
619 "global section holds %zu of its %u globals", globals.size(), *count);
620
621 WasmGlobal global;
622 global.size = GetWasmValueTypeSize(data.GetU8(&offset));
623 data.GetU8(&offset); // mutability
624 global.init_expr_value = ParseGlobalInitValue(data, offset);
625 globals.push_back(global);
626 }
627
628 return globals;
629}
630
631static llvm::Expected<std::vector<Symbol>>
632ParseNames(SectionSP code_section_sp, SectionSP global_section_sp,
633 DataExtractor &name_data, const std::vector<WasmFunction> &functions,
634 std::vector<WasmSegment> &segments,
635 const std::vector<WasmGlobal> &globals,
636 uint32_t num_imported_functions, uint32_t num_imported_globals) {
637
638 llvm::DataExtractor data = name_data.GetAsLLVM();
639 llvm::DataExtractor::Cursor c(0);
640 std::vector<Symbol> symbols;
641 while (c && c.tell() < data.size()) {
642 const uint8_t type = data.getU8(c);
643 llvm::Expected<uint32_t> size = GetULEB32(data, c);
644 if (!size)
645 return size.takeError();
646
647 switch (type) {
648 case llvm::wasm::WASM_NAMES_FUNCTION: {
649 const uint64_t count = data.getULEB128(c);
650 if (count > std::numeric_limits<uint32_t>::max())
651 return llvm::joinErrors(
652 c.takeError(),
653 llvm::createStringError("function count overflows uint32_t"));
654
655 for (uint64_t i = 0; c && i < count; ++i) {
656 llvm::Expected<uint32_t> idx = GetULEB32(data, c);
657 if (!idx)
658 return idx.takeError();
659 llvm::Expected<std::string> name = GetWasmString(data, c);
660 if (!name)
661 return name.takeError();
662 if (*idx >= num_imported_functions + functions.size())
663 continue;
664
665 if (*idx < num_imported_functions) {
666 symbols.emplace_back(symbols.size(), *name, lldb::eSymbolTypeCode,
667 /*external=*/true, /*is_debug=*/false,
668 /*is_trampoline=*/false,
669 /*is_artificial=*/false,
670 /*section_sp=*/lldb::SectionSP(),
671 /*value=*/0, /*size=*/0,
672 /*size_is_valid=*/false,
673 /*contains_linker_annotations=*/false,
674 /*flags=*/0);
675 } else {
676 const WasmFunction &func = functions[*idx - num_imported_functions];
677 symbols.emplace_back(symbols.size(), *name, lldb::eSymbolTypeCode,
678 /*external=*/false, /*is_debug=*/false,
679 /*is_trampoline=*/false, /*is_artificial=*/false,
680 code_section_sp, func.section_offset, func.size,
681 /*size_is_valid=*/true,
682 /*contains_linker_annotations=*/false,
683 /*flags=*/0);
684 if (func.code_offset)
685 symbols.back().SetPrologueByteSize(func.code_offset);
686 }
687 }
688 } break;
689 case llvm::wasm::WASM_NAMES_DATA_SEGMENT: {
690 llvm::Expected<uint32_t> count = GetULEB32(data, c);
691 if (!count)
692 return count.takeError();
693 for (uint32_t i = 0; c && i < *count; ++i) {
694 llvm::Expected<uint32_t> idx = GetULEB32(data, c);
695 if (!idx)
696 return idx.takeError();
697 llvm::Expected<std::string> name = GetWasmString(data, c);
698 if (!name)
699 return name.takeError();
700 if (*idx >= segments.size())
701 continue;
702 // Update the segment name.
703 segments[i].name = *name;
704 }
705
706 } break;
707 case llvm::wasm::WASM_NAMES_GLOBAL: {
708 llvm::Expected<uint32_t> count = GetULEB32(data, c);
709 if (!count)
710 return count.takeError();
711 for (uint32_t i = 0; c && i < *count; ++i) {
712 llvm::Expected<uint32_t> idx = GetULEB32(data, c);
713 if (!idx)
714 return idx.takeError();
715 llvm::Expected<std::string> name = GetWasmString(data, c);
716 if (!name)
717 return name.takeError();
718
719 // An imported global has no entry in the global section, and so no
720 // value to bound a read with.
721 if (*idx < num_imported_globals)
722 continue;
723 const uint32_t global_idx = *idx - num_imported_globals;
724 if (global_idx >= globals.size())
725 continue;
726
727 // The section is indexed rather than byte addressed, so a global spans
728 // the one index it occupies. Bounding a read by the size of the value
729 // is the section's business.
730 symbols.emplace_back(symbols.size(), *name, lldb::eSymbolTypeData,
731 /*external=*/true, /*is_debug=*/false,
732 /*is_trampoline=*/false, /*is_artificial=*/false,
733 global_section_sp, /*offset=*/*idx,
734 /*size=*/1,
735 /*size_is_valid=*/true,
736 /*contains_linker_annotations=*/false,
737 /*flags=*/0);
738 }
739 } break;
740 case llvm::wasm::WASM_NAMES_LOCAL:
741 default:
742 std::optional<lldb::offset_t> offset =
743 llvm::checkedAddUnsigned<lldb::offset_t>(c.tell(), *size);
744 if (!offset)
745 return llvm::joinErrors(
746 c.takeError(), llvm::createStringError("offset overflows 64 bits"));
747 c.seek(*offset);
748 }
749 }
750
751 if (!c)
752 return c.takeError();
753
754 return symbols;
755}
756
758 for (const Symbol &symbol : m_symbols)
759 symtab.AddSymbol(symbol);
760
761 symtab.Finalize();
762 m_symbols.clear();
763}
764
765static SectionType GetSectionTypeFromName(llvm::StringRef Name) {
766 if (Name == "name")
768 if (Name.consume_front(".debug_") || Name.consume_front(".zdebug_"))
770 return eSectionTypeOther;
771}
772
773/// A `section` attribute on a data variable lands in a named data segment on
774/// wasm, not a top-level custom section, so formatter sections appear as
775/// segment names rather than section names.
776static SectionType GetSegmentTypeFromName(llvm::StringRef Name) {
777 return llvm::StringSwitch<SectionType>(Name)
778 .Case(".lldbsummaries", eSectionTypeLLDBTypeSummaries)
779 .Case(".lldbformatters", eSectionTypeLLDBFormatters)
780 .Default(eSectionTypeData);
781}
782
783std::optional<ObjectFileWasm::section_info>
784ObjectFileWasm::GetSectionInfo(uint32_t section_id) {
785 for (const section_info &sect_info : m_sect_infos) {
786 if (sect_info.id == section_id)
787 return sect_info;
788 }
789 return std::nullopt;
790}
791
792std::optional<ObjectFileWasm::section_info>
793ObjectFileWasm::GetSectionInfo(llvm::StringRef section_name) {
794 for (const section_info &sect_info : m_sect_infos) {
795 if (sect_info.name == section_name)
796 return sect_info;
797 }
798 return std::nullopt;
799}
800
801void ObjectFileWasm::CreateSections(SectionList &unified_section_list) {
802 Log *log = GetLog(LLDBLog::Object);
803
804 if (m_sections_up)
805 return;
806
807 m_sections_up = std::make_unique<SectionList>();
808
809 if (m_sect_infos.empty()) {
811 }
812
813 for (const section_info &sect_info : m_sect_infos) {
814 SectionType section_type = eSectionTypeOther;
815 ConstString section_name;
816 offset_t file_offset = sect_info.offset & 0xffffffff;
817 addr_t vm_addr = sect_info.offset;
818 size_t vm_size = sect_info.size;
819
820 if (llvm::wasm::WASM_SEC_CODE == sect_info.id) {
821 section_type = eSectionTypeCode;
822 section_name = ConstString("code");
823
824 // A code address in DWARF for WebAssembly is the offset of an
825 // instruction relative within the Code section of the WebAssembly file.
826 // For this reason Section::GetFileAddress() must return zero for the
827 // Code section.
828 vm_addr = 0;
829 } else {
830 section_type = GetSectionTypeFromName(sect_info.name.GetStringRef());
831 if (section_type == eSectionTypeOther)
832 continue;
833 section_name = sect_info.name;
834 if (!IsInMemory()) {
835 vm_size = 0;
836 vm_addr = 0;
837 }
838 }
839
840 SectionSP section_sp = std::make_shared<Section>(
841 GetModule(), // Module to which this section belongs.
842 this, // ObjectFile to which this section belongs and
843 // should read section data from.
844 section_type, // Section ID.
845 section_name, // Section name.
846 section_type, // Section type.
847 vm_addr, // VM address.
848 vm_size, // VM size in bytes of this section.
849 file_offset, // Offset of this section in the file.
850 sect_info.size, // Size of the section as found in the file.
851 0, // Alignment of the section
852 0); // Flags for this section.
853 m_sections_up->AddSection(section_sp);
854 unified_section_list.AddSection(section_sp);
855 }
856
857 // The name section contains names and indexes. First parse the data from the
858 // relevant sections so we can access it by its index.
859 std::vector<WasmFunction> functions;
860 std::vector<WasmSegment> segments;
861
862 // Parse the code section.
863 if (std::optional<section_info> info =
864 GetSectionInfo(llvm::wasm::WASM_SEC_CODE)) {
865 DataExtractor code_data = ReadImageData(info->offset, info->size);
866 llvm::Expected<std::vector<WasmFunction>> maybe_functions =
867 ParseFunctions(code_data);
868 if (!maybe_functions) {
869 LLDB_LOG_ERROR(log, maybe_functions.takeError(),
870 "Failed to parse Wasm code section: {0}");
871 } else {
872 functions = *maybe_functions;
873 }
874 }
875
876 // Parse the import section. The counts are needed because the function and
877 // global index spaces used in the name section include imports.
878 if (std::optional<section_info> info =
879 GetSectionInfo(llvm::wasm::WASM_SEC_IMPORT)) {
880 DataExtractor import_data = ReadImageData(info->offset, info->size);
881 llvm::Expected<WasmImports> imports = ParseImports(import_data);
882 if (!imports) {
883 LLDB_LOG_ERROR(log, imports.takeError(),
884 "Failed to parse Wasm import section: {0}");
885 } else {
886 m_num_imported_functions = imports->functions;
887 m_num_imported_globals = imports->globals;
888 }
889 }
890
891 // Parse the global section.
892 if (std::optional<section_info> info =
893 GetSectionInfo(llvm::wasm::WASM_SEC_GLOBAL)) {
894 DataExtractor global_data = ReadImageData(info->offset, info->size);
895 llvm::Expected<std::vector<WasmGlobal>> globals = ParseGlobals(global_data);
896 if (!globals) {
897 LLDB_LOG_ERROR(log, globals.takeError(),
898 "Failed to parse Wasm global section: {0}");
899 } else {
900 m_globals = *globals;
901 }
902 }
903
904 // Parse the data section.
905 std::optional<section_info> data_info =
906 GetSectionInfo(llvm::wasm::WASM_SEC_DATA);
907 if (data_info) {
908 DataExtractor data_data = ReadImageData(data_info->offset, data_info->size);
909 llvm::Expected<std::vector<WasmSegment>> maybe_segments =
910 ParseData(data_data);
911 if (!maybe_segments) {
912 LLDB_LOG_ERROR(log, maybe_segments.takeError(),
913 "Failed to parse Wasm data section: {0}");
914 } else {
915 segments = *maybe_segments;
916 }
917 }
918
919 // The section maps nothing: it exists to give globals an address, which is
920 // what lets one be named and read. Its size counts globals rather than bytes,
921 // imported ones included, because they share the index space.
922 SectionSP global_section_sp;
923 if (!m_globals.empty()) {
924 global_section_sp = std::make_shared<Section>(
925 GetModule(),
926 /*obj_file=*/this, eSectionTypeWasmGlobal, ConstString("global"),
928 /*file_vm_addr=*/kWasmGlobalFileAddress,
929 /*vm_size=*/m_num_imported_globals + m_globals.size(),
930 /*file_offset=*/0, /*file_size=*/0,
931 /*log2align=*/0, /*flags=*/0);
932 m_sections_up->AddSection(global_section_sp);
933 unified_section_list.AddSection(global_section_sp);
934 }
935
936 if (std::optional<section_info> info = GetSectionInfo("name")) {
937 DataExtractor names_data = ReadImageData(info->offset, info->size);
938 llvm::Expected<std::vector<Symbol>> symbols = ParseNames(
939 m_sections_up->FindSectionByType(lldb::eSectionTypeCode, false),
940 global_section_sp, names_data, functions, segments, m_globals,
942 if (!symbols) {
943 LLDB_LOG_ERROR(log, symbols.takeError(),
944 "Failed to parse Wasm names: {0}");
945 } else {
946 m_symbols = *symbols;
947 }
948 }
949
950 lldb::user_id_t segment_id = 0;
951 lldb::addr_t static_data_end = 0;
952 for (const WasmSegment &segment : segments) {
953 if (segment.type == WasmSegment::Active) {
954 // FIXME: Support segments with a memory index.
955 if (segment.memory_index != 0) {
956 LLDB_LOG(log,
957 "Skipping segment {}: non-zero memory index is "
958 "currently unsupported",
959 segment.name);
960 continue;
961 }
962
963 if (segment.init_expr_offset == LLDB_INVALID_OFFSET) {
964 LLDB_LOG(log, "Skipping segment {}: unsupported init expression",
965 segment.name);
966 continue;
967 }
968 }
969
970 const lldb::addr_t file_vm_addr =
972 ? segment.init_expr_offset
973 : data_info->offset + segment.section_offset;
974 const lldb::offset_t file_offset =
975 data_info->GetFileOffset() + segment.GetFileOffset();
976 SectionSP segment_sp = std::make_shared<Section>(
977 GetModule(),
978 /*obj_file=*/this,
979 ++segment_id << 8, // 1-based segment index, shifted by 8 bits to avoid
980 // collision with section IDs.
982 /*file_vm_addr=*/file_vm_addr,
983 /*vm_size=*/segment.size,
984 /*file_offset=*/file_offset,
985 /*file_size=*/segment.size,
986 /*log2align=*/0, /*flags=*/0);
987 m_sections_up->AddSection(segment_sp);
988 GetModule()->GetSectionList()->AddSection(segment_sp);
989
990 if (segment.type == WasmSegment::Active)
991 static_data_end = std::max(static_data_end, file_vm_addr + segment.size);
992 }
993
994 // Zero-initialized globals (BSS) have no data segment, so the loop above
995 // leaves their linear-memory addresses uncovered by any section, and a static
996 // read of one can't be resolved. Cover the rest of linear memory with a
997 // zero-fill section. SetLoadAddress maps it like a data segment so live reads
998 // still go through process memory.
999 if (std::optional<section_info> mem_info =
1000 GetSectionInfo(llvm::wasm::WASM_SEC_MEMORY)) {
1001 DataExtractor mem_data = ReadImageData(mem_info->offset, mem_info->size);
1002 llvm::Expected<uint64_t> memory_size = ParseMemoryMinSize(mem_data);
1003 if (!memory_size) {
1004 LLDB_LOG_ERROR(log, memory_size.takeError(),
1005 "Failed to parse Wasm memory section: {0}");
1006 } else if (*memory_size > static_data_end) {
1007 SectionSP bss_sp =
1008 std::make_shared<Section>(GetModule(),
1009 /*obj_file=*/this, ++segment_id << 8,
1011 /*file_vm_addr=*/static_data_end,
1012 /*vm_size=*/*memory_size - static_data_end,
1013 /*file_offset=*/0,
1014 /*file_size=*/0,
1015 /*log2align=*/0, /*flags=*/0);
1016 m_sections_up->AddSection(bss_sp);
1017 GetModule()->GetSectionList()->AddSection(bss_sp);
1018 }
1019 }
1020}
1021
1023 lldb::offset_t section_offset, void *dst,
1024 size_t dst_len) {
1025 if (!section || section->GetType() != eSectionTypeWasmGlobal)
1026 return ObjectFile::ReadSectionData(section, section_offset, dst, dst_len);
1027
1028 // The low indices belong to imported globals, which the module does not
1029 // declare and so has no initializer for.
1030 if (section_offset < m_num_imported_globals)
1031 return 0;
1032 const lldb::offset_t index = section_offset - m_num_imported_globals;
1033 if (index >= m_globals.size())
1034 return 0;
1035
1036 const WasmGlobal &global = m_globals[index];
1037 if (!global.init_expr_value || !global.size || dst_len > *global.size)
1038 return 0;
1039
1040 // A global holds a value rather than bytes, and WebAssembly is little-endian.
1041 uint8_t bytes[sizeof(uint64_t)];
1042 llvm::support::endian::write64le(bytes, *global.init_expr_value);
1043 std::memcpy(dst, bytes, dst_len);
1044 return dst_len;
1045}
1046
1048 bool value_is_offset) {
1049 /// In WebAssembly, linear memory is disjointed from code space. The VM can
1050 /// load multiple instances of a module, which logically share the same code.
1051 /// We represent a wasm32 code address with 64-bits, like:
1052 /// 63 32 31 0
1053 /// +---------------+---------------+
1054 /// + module_id | offset |
1055 /// +---------------+---------------+
1056 /// where the lower 32 bits represent a module offset (relative to the module
1057 /// start not to the beginning of the code section) and the higher 32 bits
1058 /// uniquely identify the module in the WebAssembly VM.
1059 /// In other words, we assume that each WebAssembly module is loaded by the
1060 /// engine at a 64-bit address that starts at the boundary of 4GB pages, like
1061 /// 0x0000000400000000 for module_id == 4.
1062 /// These 64-bit addresses will be used to request code ranges for a specific
1063 /// module from the WebAssembly engine.
1064
1066 m_memory_addr == load_address);
1067
1068 ModuleSP module_sp = GetModule();
1069 if (!module_sp)
1070 return false;
1071
1073
1074 size_t num_loaded_sections = 0;
1075 SectionList *section_list = GetSectionList();
1076 if (!section_list)
1077 return false;
1078
1079 const size_t num_sections = section_list->GetSize();
1080 for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) {
1081 SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx));
1082 lldb::addr_t section_load_addr;
1083 switch (section_sp->GetType()) {
1084 case eSectionTypeData:
1089 // These live in linear memory, and the globals in an index space of their
1090 // own, both separate from code. A section's file address already carries
1091 // the space it belongs to, so only the module id comes from the load
1092 // address.
1093 section_load_addr =
1094 (load_address & ~kWasmAddressTypeMask) | section_sp->GetFileAddress();
1095 break;
1096 default:
1097 // Code (and other) sections are addressed by their offset within the
1098 // module in the Object address space.
1099 section_load_addr = load_address | section_sp->GetFileOffset();
1100 break;
1101 }
1102 if (target.SetSectionLoadAddress(section_sp, section_load_addr))
1103 ++num_loaded_sections;
1104 }
1105
1106 return num_loaded_sections > 0;
1107}
1108
1110 DataExtractor data;
1111 if (m_file) {
1112 if (offset < GetByteSize()) {
1113 size = std::min(static_cast<uint64_t>(size), GetByteSize() - offset);
1114 auto buffer_sp = MapFileData(m_file, size, offset);
1115 return DataExtractor(buffer_sp, GetByteOrder(), GetAddressByteSize());
1116 }
1117 } else {
1118 ProcessSP process_sp(m_process_wp.lock());
1119 if (process_sp) {
1120 auto data_up = std::make_unique<DataBufferHeap>(size, 0);
1121 Status readmem_error;
1122 size_t bytes_read = process_sp->ReadMemory(
1123 offset, data_up->GetBytes(), data_up->GetByteSize(), readmem_error);
1124 if (bytes_read > 0) {
1125 DataBufferSP buffer_sp(data_up.release());
1126 data.SetData(buffer_sp);
1127 }
1128 } else if (offset < m_data_nsp->GetByteSize()) {
1129 size = std::min(static_cast<uint64_t>(size),
1130 m_data_nsp->GetByteSize() - offset);
1131 return DataExtractor(m_data_nsp->GetDataStart() + offset, size,
1133 }
1134 }
1135 data.SetByteOrder(GetByteOrder());
1136 return data;
1137}
1138
1140 static ConstString g_sect_name_external_debug_info("external_debug_info");
1141
1142 for (const section_info &sect_info : m_sect_infos) {
1143 if (g_sect_name_external_debug_info == sect_info.name) {
1144 const uint32_t kBufferSize = 1024;
1145 DataExtractor section_header_data =
1146 ReadImageData(sect_info.offset, kBufferSize);
1147
1148 llvm::DataExtractor data = section_header_data.GetAsLLVM();
1149 llvm::DataExtractor::Cursor c(0);
1150 llvm::Expected<std::string> symbols_url = GetWasmString(data, c);
1151 if (!symbols_url) {
1152 llvm::consumeError(symbols_url.takeError());
1153 return std::nullopt;
1154 }
1155 return FileSpec(*symbols_url);
1156 }
1157 }
1158 return std::nullopt;
1159}
1160
1162 ModuleSP module_sp(GetModule());
1163 if (!module_sp)
1164 return;
1165
1166 std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
1167
1168 llvm::raw_ostream &ostream = s->AsRawOstream();
1169 ostream << static_cast<void *>(this) << ": ";
1170 s->Indent();
1171 ostream << "ObjectFileWasm, file = '";
1172 m_file.Dump(ostream);
1173 ostream << "', arch = ";
1174 ostream << GetArchitecture().GetArchitectureName() << "\n";
1175
1176 SectionList *sections = GetSectionList();
1177 if (sections) {
1178 sections->Dump(s->AsRawOstream(), s->GetIndentLevel(), nullptr, true,
1179 UINT32_MAX);
1180 }
1181 ostream << "\n";
1182 DumpSectionHeaders(ostream);
1183 ostream << "\n";
1184}
1185
1186void ObjectFileWasm::DumpSectionHeader(llvm::raw_ostream &ostream,
1187 const section_info &sh) {
1188 ostream << llvm::left_justify(sh.name.GetStringRef(), 16) << " "
1189 << llvm::format_hex(sh.offset, 10) << " "
1190 << llvm::format_hex(sh.size, 10) << " " << llvm::format_hex(sh.id, 6)
1191 << "\n";
1192}
1193
1194void ObjectFileWasm::DumpSectionHeaders(llvm::raw_ostream &ostream) {
1195 ostream << "Section Headers\n";
1196 ostream << "IDX name addr size id\n";
1197 ostream << "==== ---------------- ---------- ---------- ------\n";
1198
1199 uint32_t idx = 0;
1200 for (auto pos = m_sect_infos.begin(); pos != m_sect_infos.end();
1201 ++pos, ++idx) {
1202 ostream << "[" << llvm::format_decimal(idx, 2) << "] ";
1203 ObjectFileWasm::DumpSectionHeader(ostream, *pos);
1204 }
1205}
#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:740
A uniqued constant string class.
Definition ConstString.h:40
llvm::StringRef GetStringRef() const
Get the string value as a llvm::StringRef.
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:57
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition FileSpec.cpp:376
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:779
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:777
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:771
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:685
lldb::ProcessWP m_process_wp
Definition ObjectFile.h:775
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:3495
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
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:56
WasmAddressType
Each WebAssembly module has separate address spaces for Code and Memory.
Definition WasmAddress.h:28
static constexpr uint32_t kWasmAddressTypeShift
Definition WasmAddress.h:46
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:85
std::shared_ptr< lldb_private::Process > ProcessSP
uint64_t user_id_t
Definition lldb-types.h:82
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