1//===- WasmObjectFile.cpp - Wasm object file implementation ---------------===//
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 "llvm/ADT/ArrayRef.h"
10#include "llvm/ADT/DenseSet.h"
11#include "llvm/ADT/SmallSet.h"
12#include "llvm/ADT/StringRef.h"
13#include "llvm/ADT/StringSet.h"
14#include "llvm/ADT/StringSwitch.h"
15#include "llvm/BinaryFormat/Wasm.h"
16#include "llvm/Object/Binary.h"
17#include "llvm/Object/Error.h"
18#include "llvm/Object/ObjectFile.h"
19#include "llvm/Object/SymbolicFile.h"
20#include "llvm/Object/Wasm.h"
21#include "llvm/Support/Endian.h"
22#include "llvm/Support/Error.h"
23#include "llvm/Support/ErrorHandling.h"
24#include "llvm/Support/Format.h"
25#include "llvm/Support/LEB128.h"
26#include "llvm/Support/ScopedPrinter.h"
27#include "llvm/TargetParser/SubtargetFeature.h"
28#include "llvm/TargetParser/Triple.h"
29#include <algorithm>
30#include <cassert>
31#include <cstdint>
32#include <cstring>
33#include <limits>
34
35#define DEBUG_TYPE "wasm-object"
36
37using namespace llvm;
38using namespace object;
39
40void WasmSymbol::print(raw_ostream &Out) const {
41 Out << "Name=" << Info.Name
42 << ", Kind=" << toString(type: wasm::WasmSymbolType(Info.Kind)) << ", Flags=0x"
43 << Twine::utohexstr(Val: Info.Flags) << " [";
44 switch (getBinding()) {
45 case wasm::WASM_SYMBOL_BINDING_GLOBAL: Out << "global"; break;
46 case wasm::WASM_SYMBOL_BINDING_LOCAL: Out << "local"; break;
47 case wasm::WASM_SYMBOL_BINDING_WEAK: Out << "weak"; break;
48 }
49 if (isHidden()) {
50 Out << ", hidden";
51 } else {
52 Out << ", default";
53 }
54 Out << "]";
55 if (!isTypeData()) {
56 Out << ", ElemIndex=" << Info.ElementIndex;
57 } else if (isDefined()) {
58 Out << ", Segment=" << Info.DataRef.Segment;
59 Out << ", Offset=" << Info.DataRef.Offset;
60 Out << ", Size=" << Info.DataRef.Size;
61 }
62}
63
64#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
65LLVM_DUMP_METHOD void WasmSymbol::dump() const { print(dbgs()); }
66#endif
67
68Expected<std::unique_ptr<WasmObjectFile>>
69ObjectFile::createWasmObjectFile(MemoryBufferRef Buffer) {
70 Error Err = Error::success();
71 auto ObjectFile = std::make_unique<WasmObjectFile>(args&: Buffer, args&: Err);
72 if (Err)
73 return std::move(Err);
74
75 return std::move(ObjectFile);
76}
77
78#define VARINT7_MAX ((1 << 7) - 1)
79#define VARINT7_MIN (-(1 << 7))
80#define VARUINT7_MAX (1 << 7)
81#define VARUINT1_MAX (1)
82
83static uint8_t readUint8(WasmObjectFile::ReadContext &Ctx) {
84 if (Ctx.Ptr == Ctx.End)
85 report_fatal_error(reason: "EOF while reading uint8");
86 return *Ctx.Ptr++;
87}
88
89static uint32_t readUint32(WasmObjectFile::ReadContext &Ctx) {
90 if (Ctx.Ptr + 4 > Ctx.End)
91 report_fatal_error(reason: "EOF while reading uint32");
92 uint32_t Result = support::endian::read32le(P: Ctx.Ptr);
93 Ctx.Ptr += 4;
94 return Result;
95}
96
97static int32_t readFloat32(WasmObjectFile::ReadContext &Ctx) {
98 if (Ctx.Ptr + 4 > Ctx.End)
99 report_fatal_error(reason: "EOF while reading float64");
100 int32_t Result = 0;
101 memcpy(dest: &Result, src: Ctx.Ptr, n: sizeof(Result));
102 Ctx.Ptr += sizeof(Result);
103 return Result;
104}
105
106static int64_t readFloat64(WasmObjectFile::ReadContext &Ctx) {
107 if (Ctx.Ptr + 8 > Ctx.End)
108 report_fatal_error(reason: "EOF while reading float64");
109 int64_t Result = 0;
110 memcpy(dest: &Result, src: Ctx.Ptr, n: sizeof(Result));
111 Ctx.Ptr += sizeof(Result);
112 return Result;
113}
114
115static uint64_t readULEB128(WasmObjectFile::ReadContext &Ctx) {
116 unsigned Count;
117 const char *Error = nullptr;
118 uint64_t Result = decodeULEB128(p: Ctx.Ptr, n: &Count, end: Ctx.End, error: &Error);
119 if (Error)
120 report_fatal_error(reason: Error);
121 Ctx.Ptr += Count;
122 return Result;
123}
124
125static StringRef readString(WasmObjectFile::ReadContext &Ctx) {
126 uint32_t StringLen = readULEB128(Ctx);
127 if (Ctx.Ptr + StringLen > Ctx.End)
128 report_fatal_error(reason: "EOF while reading string");
129 StringRef Return =
130 StringRef(reinterpret_cast<const char *>(Ctx.Ptr), StringLen);
131 Ctx.Ptr += StringLen;
132 return Return;
133}
134
135static int64_t readLEB128(WasmObjectFile::ReadContext &Ctx) {
136 unsigned Count;
137 const char *Error = nullptr;
138 uint64_t Result = decodeSLEB128(p: Ctx.Ptr, n: &Count, end: Ctx.End, error: &Error);
139 if (Error)
140 report_fatal_error(reason: Error);
141 Ctx.Ptr += Count;
142 return Result;
143}
144
145static uint8_t readVaruint1(WasmObjectFile::ReadContext &Ctx) {
146 int64_t Result = readLEB128(Ctx);
147 if (Result > VARUINT1_MAX || Result < 0)
148 report_fatal_error(reason: "LEB is outside Varuint1 range");
149 return Result;
150}
151
152static int32_t readVarint32(WasmObjectFile::ReadContext &Ctx) {
153 int64_t Result = readLEB128(Ctx);
154 if (Result > INT32_MAX || Result < INT32_MIN)
155 report_fatal_error(reason: "LEB is outside Varint32 range");
156 return Result;
157}
158
159static uint32_t readVaruint32(WasmObjectFile::ReadContext &Ctx) {
160 uint64_t Result = readULEB128(Ctx);
161 if (Result > UINT32_MAX)
162 report_fatal_error(reason: "LEB is outside Varuint32 range");
163 return Result;
164}
165
166static int64_t readVarint64(WasmObjectFile::ReadContext &Ctx) {
167 return readLEB128(Ctx);
168}
169
170static uint64_t readVaruint64(WasmObjectFile::ReadContext &Ctx) {
171 return readULEB128(Ctx);
172}
173
174static uint8_t readOpcode(WasmObjectFile::ReadContext &Ctx) {
175 return readUint8(Ctx);
176}
177
178static wasm::ValType parseValType(WasmObjectFile::ReadContext &Ctx,
179 uint32_t Code) {
180 // only directly encoded FUNCREF/EXTERNREF/EXNREF are supported
181 // (not ref null func, ref null extern, or ref null exn)
182 switch (Code) {
183 case wasm::WASM_TYPE_I32:
184 case wasm::WASM_TYPE_I64:
185 case wasm::WASM_TYPE_F32:
186 case wasm::WASM_TYPE_F64:
187 case wasm::WASM_TYPE_V128:
188 case wasm::WASM_TYPE_FUNCREF:
189 case wasm::WASM_TYPE_EXTERNREF:
190 case wasm::WASM_TYPE_EXNREF:
191 return wasm::ValType(Code);
192 }
193 if (Code == wasm::WASM_TYPE_NULLABLE || Code == wasm::WASM_TYPE_NONNULLABLE) {
194 /* Discard HeapType */ readVarint64(Ctx);
195 }
196 return wasm::ValType(wasm::ValType::OTHERREF);
197}
198
199static Error readInitExpr(wasm::WasmInitExpr &Expr,
200 WasmObjectFile::ReadContext &Ctx) {
201 auto Start = Ctx.Ptr;
202
203 Expr.Extended = false;
204 Expr.Inst.Opcode = readOpcode(Ctx);
205 switch (Expr.Inst.Opcode) {
206 case wasm::WASM_OPCODE_I32_CONST:
207 Expr.Inst.Value.Int32 = readVarint32(Ctx);
208 break;
209 case wasm::WASM_OPCODE_I64_CONST:
210 Expr.Inst.Value.Int64 = readVarint64(Ctx);
211 break;
212 case wasm::WASM_OPCODE_F32_CONST:
213 Expr.Inst.Value.Float32 = readFloat32(Ctx);
214 break;
215 case wasm::WASM_OPCODE_F64_CONST:
216 Expr.Inst.Value.Float64 = readFloat64(Ctx);
217 break;
218 case wasm::WASM_OPCODE_GLOBAL_GET:
219 Expr.Inst.Value.Global = readULEB128(Ctx);
220 break;
221 case wasm::WASM_OPCODE_REF_NULL: {
222 /* Discard type */ parseValType(Ctx, Code: readVaruint32(Ctx));
223 break;
224 }
225 default:
226 Expr.Extended = true;
227 }
228
229 if (!Expr.Extended) {
230 uint8_t EndOpcode = readOpcode(Ctx);
231 if (EndOpcode != wasm::WASM_OPCODE_END)
232 Expr.Extended = true;
233 }
234
235 if (Expr.Extended) {
236 Ctx.Ptr = Start;
237 while (true) {
238 uint8_t Opcode = readOpcode(Ctx);
239 switch (Opcode) {
240 case wasm::WASM_OPCODE_I32_CONST:
241 case wasm::WASM_OPCODE_GLOBAL_GET:
242 case wasm::WASM_OPCODE_REF_NULL:
243 case wasm::WASM_OPCODE_REF_FUNC:
244 case wasm::WASM_OPCODE_I64_CONST:
245 readULEB128(Ctx);
246 break;
247 case wasm::WASM_OPCODE_F32_CONST:
248 readFloat32(Ctx);
249 break;
250 case wasm::WASM_OPCODE_F64_CONST:
251 readFloat64(Ctx);
252 break;
253 case wasm::WASM_OPCODE_I32_ADD:
254 case wasm::WASM_OPCODE_I32_SUB:
255 case wasm::WASM_OPCODE_I32_MUL:
256 case wasm::WASM_OPCODE_I64_ADD:
257 case wasm::WASM_OPCODE_I64_SUB:
258 case wasm::WASM_OPCODE_I64_MUL:
259 break;
260 case wasm::WASM_OPCODE_GC_PREFIX:
261 break;
262 // The GC opcodes are in a separate (prefixed space). This flat switch
263 // structure works as long as there is no overlap between the GC and
264 // general opcodes used in init exprs.
265 case wasm::WASM_OPCODE_STRUCT_NEW:
266 case wasm::WASM_OPCODE_STRUCT_NEW_DEFAULT:
267 case wasm::WASM_OPCODE_ARRAY_NEW:
268 case wasm::WASM_OPCODE_ARRAY_NEW_DEFAULT:
269 readULEB128(Ctx); // heap type index
270 break;
271 case wasm::WASM_OPCODE_ARRAY_NEW_FIXED:
272 readULEB128(Ctx); // heap type index
273 readULEB128(Ctx); // array size
274 break;
275 case wasm::WASM_OPCODE_REF_I31:
276 break;
277 case wasm::WASM_OPCODE_END:
278 Expr.Body = ArrayRef<uint8_t>(Start, Ctx.Ptr - Start);
279 return Error::success();
280 default:
281 return make_error<GenericBinaryError>(
282 Args: Twine("invalid opcode in init_expr: ") + Twine(unsigned(Opcode)),
283 Args: object_error::parse_failed);
284 }
285 }
286 }
287
288 return Error::success();
289}
290
291static wasm::WasmLimits readLimits(WasmObjectFile::ReadContext &Ctx) {
292 wasm::WasmLimits Result;
293 Result.Flags = readVaruint32(Ctx);
294 Result.Minimum = readVaruint64(Ctx);
295 if (Result.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX)
296 Result.Maximum = readVaruint64(Ctx);
297 return Result;
298}
299
300static wasm::WasmTableType readTableType(WasmObjectFile::ReadContext &Ctx) {
301 wasm::WasmTableType TableType;
302 auto ElemType = parseValType(Ctx, Code: readVaruint32(Ctx));
303 TableType.ElemType = ElemType;
304 TableType.Limits = readLimits(Ctx);
305 return TableType;
306}
307
308static Error readSection(WasmSection &Section, WasmObjectFile::ReadContext &Ctx,
309 WasmSectionOrderChecker &Checker) {
310 Section.Type = readUint8(Ctx);
311 LLVM_DEBUG(dbgs() << "readSection type=" << Section.Type << "\n");
312 // When reading the section's size, store the size of the LEB used to encode
313 // it. This allows objcopy/strip to reproduce the binary identically.
314 const uint8_t *PreSizePtr = Ctx.Ptr;
315 uint32_t Size = readVaruint32(Ctx);
316 Section.HeaderSecSizeEncodingLen = Ctx.Ptr - PreSizePtr;
317 Section.Offset = Ctx.Ptr - Ctx.Start;
318 if (Size == 0)
319 return make_error<StringError>(Args: "zero length section",
320 Args: object_error::parse_failed);
321 if (Ctx.Ptr + Size > Ctx.End)
322 return make_error<StringError>(Args: "section too large",
323 Args: object_error::parse_failed);
324 if (Section.Type == wasm::WASM_SEC_CUSTOM) {
325 WasmObjectFile::ReadContext SectionCtx;
326 SectionCtx.Start = Ctx.Ptr;
327 SectionCtx.Ptr = Ctx.Ptr;
328 SectionCtx.End = Ctx.Ptr + Size;
329
330 Section.Name = readString(Ctx&: SectionCtx);
331
332 uint32_t SectionNameSize = SectionCtx.Ptr - SectionCtx.Start;
333 Ctx.Ptr += SectionNameSize;
334 Size -= SectionNameSize;
335 }
336
337 if (!Checker.isValidSectionOrder(ID: Section.Type, CustomSectionName: Section.Name)) {
338 return make_error<StringError>(Args: "out of order section type: " +
339 llvm::to_string(Value: Section.Type),
340 Args: object_error::parse_failed);
341 }
342
343 Section.Content = ArrayRef<uint8_t>(Ctx.Ptr, Size);
344 Ctx.Ptr += Size;
345 return Error::success();
346}
347
348WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err)
349 : ObjectFile(Binary::ID_Wasm, Buffer) {
350 ErrorAsOutParameter ErrAsOutParam(&Err);
351 Header.Magic = getData().substr(Start: 0, N: 4);
352 if (Header.Magic != StringRef("\0asm", 4)) {
353 Err = make_error<StringError>(Args: "invalid magic number",
354 Args: object_error::parse_failed);
355 return;
356 }
357
358 ReadContext Ctx;
359 Ctx.Start = getData().bytes_begin();
360 Ctx.Ptr = Ctx.Start + 4;
361 Ctx.End = Ctx.Start + getData().size();
362
363 if (Ctx.Ptr + 4 > Ctx.End) {
364 Err = make_error<StringError>(Args: "missing version number",
365 Args: object_error::parse_failed);
366 return;
367 }
368
369 Header.Version = readUint32(Ctx);
370 if (Header.Version != wasm::WasmVersion) {
371 Err = make_error<StringError>(Args: "invalid version number: " +
372 Twine(Header.Version),
373 Args: object_error::parse_failed);
374 return;
375 }
376
377 WasmSectionOrderChecker Checker;
378 while (Ctx.Ptr < Ctx.End) {
379 WasmSection Sec;
380 if ((Err = readSection(Section&: Sec, Ctx, Checker)))
381 return;
382 if ((Err = parseSection(Sec)))
383 return;
384
385 Sections.push_back(x: Sec);
386 }
387}
388
389Error WasmObjectFile::parseSection(WasmSection &Sec) {
390 ReadContext Ctx;
391 Ctx.Start = Sec.Content.data();
392 Ctx.End = Ctx.Start + Sec.Content.size();
393 Ctx.Ptr = Ctx.Start;
394 switch (Sec.Type) {
395 case wasm::WASM_SEC_CUSTOM:
396 return parseCustomSection(Sec, Ctx);
397 case wasm::WASM_SEC_TYPE:
398 return parseTypeSection(Ctx);
399 case wasm::WASM_SEC_IMPORT:
400 return parseImportSection(Ctx);
401 case wasm::WASM_SEC_FUNCTION:
402 return parseFunctionSection(Ctx);
403 case wasm::WASM_SEC_TABLE:
404 return parseTableSection(Ctx);
405 case wasm::WASM_SEC_MEMORY:
406 return parseMemorySection(Ctx);
407 case wasm::WASM_SEC_TAG:
408 return parseTagSection(Ctx);
409 case wasm::WASM_SEC_GLOBAL:
410 return parseGlobalSection(Ctx);
411 case wasm::WASM_SEC_EXPORT:
412 return parseExportSection(Ctx);
413 case wasm::WASM_SEC_START:
414 return parseStartSection(Ctx);
415 case wasm::WASM_SEC_ELEM:
416 return parseElemSection(Ctx);
417 case wasm::WASM_SEC_CODE:
418 return parseCodeSection(Ctx);
419 case wasm::WASM_SEC_DATA:
420 return parseDataSection(Ctx);
421 case wasm::WASM_SEC_DATACOUNT:
422 return parseDataCountSection(Ctx);
423 default:
424 return make_error<GenericBinaryError>(
425 Args: "invalid section type: " + Twine(Sec.Type), Args: object_error::parse_failed);
426 }
427}
428
429Error WasmObjectFile::parseDylinkSection(ReadContext &Ctx) {
430 // Legacy "dylink" section support.
431 // See parseDylink0Section for the current "dylink.0" section parsing.
432 HasDylinkSection = true;
433 DylinkInfo.MemorySize = readVaruint32(Ctx);
434 DylinkInfo.MemoryAlignment = readVaruint32(Ctx);
435 DylinkInfo.TableSize = readVaruint32(Ctx);
436 DylinkInfo.TableAlignment = readVaruint32(Ctx);
437 uint32_t Count = readVaruint32(Ctx);
438 while (Count--) {
439 DylinkInfo.Needed.push_back(x: readString(Ctx));
440 }
441
442 if (Ctx.Ptr != Ctx.End)
443 return make_error<GenericBinaryError>(Args: "dylink section ended prematurely",
444 Args: object_error::parse_failed);
445 return Error::success();
446}
447
448Error WasmObjectFile::parseDylink0Section(ReadContext &Ctx) {
449 // See
450 // https://github.com/WebAssembly/tool-conventions/blob/main/DynamicLinking.md
451 HasDylinkSection = true;
452
453 const uint8_t *OrigEnd = Ctx.End;
454 while (Ctx.Ptr < OrigEnd) {
455 Ctx.End = OrigEnd;
456 uint8_t Type = readUint8(Ctx);
457 uint32_t Size = readVaruint32(Ctx);
458 LLVM_DEBUG(dbgs() << "readSubsection type=" << int(Type) << " size=" << Size
459 << "\n");
460 Ctx.End = Ctx.Ptr + Size;
461 uint32_t Count;
462 switch (Type) {
463 case wasm::WASM_DYLINK_MEM_INFO:
464 DylinkInfo.MemorySize = readVaruint32(Ctx);
465 DylinkInfo.MemoryAlignment = readVaruint32(Ctx);
466 DylinkInfo.TableSize = readVaruint32(Ctx);
467 DylinkInfo.TableAlignment = readVaruint32(Ctx);
468 break;
469 case wasm::WASM_DYLINK_NEEDED:
470 Count = readVaruint32(Ctx);
471 while (Count--) {
472 DylinkInfo.Needed.push_back(x: readString(Ctx));
473 }
474 break;
475 case wasm::WASM_DYLINK_EXPORT_INFO: {
476 uint32_t Count = readVaruint32(Ctx);
477 while (Count--) {
478 DylinkInfo.ExportInfo.push_back(x: {.Name: readString(Ctx), .Flags: readVaruint32(Ctx)});
479 }
480 break;
481 }
482 case wasm::WASM_DYLINK_IMPORT_INFO: {
483 uint32_t Count = readVaruint32(Ctx);
484 while (Count--) {
485 DylinkInfo.ImportInfo.push_back(
486 x: {.Module: readString(Ctx), .Field: readString(Ctx), .Flags: readVaruint32(Ctx)});
487 }
488 break;
489 }
490 default:
491 LLVM_DEBUG(dbgs() << "unknown dylink.0 sub-section: " << Type << "\n");
492 Ctx.Ptr += Size;
493 break;
494 }
495 if (Ctx.Ptr != Ctx.End) {
496 return make_error<GenericBinaryError>(
497 Args: "dylink.0 sub-section ended prematurely", Args: object_error::parse_failed);
498 }
499 }
500
501 if (Ctx.Ptr != Ctx.End)
502 return make_error<GenericBinaryError>(Args: "dylink.0 section ended prematurely",
503 Args: object_error::parse_failed);
504 return Error::success();
505}
506
507Error WasmObjectFile::parseNameSection(ReadContext &Ctx) {
508 llvm::DenseSet<uint64_t> SeenFunctions;
509 llvm::DenseSet<uint64_t> SeenGlobals;
510 llvm::DenseSet<uint64_t> SeenSegments;
511
512 // If we have linking section (symbol table) or if we are parsing a DSO
513 // then we don't use the name section for symbol information.
514 bool PopulateSymbolTable = !HasLinkingSection && !HasDylinkSection;
515
516 // If we are using the name section for symbol information then it will
517 // supersede any symbols created by the export section.
518 if (PopulateSymbolTable)
519 Symbols.clear();
520
521 while (Ctx.Ptr < Ctx.End) {
522 uint8_t Type = readUint8(Ctx);
523 uint32_t Size = readVaruint32(Ctx);
524 const uint8_t *SubSectionEnd = Ctx.Ptr + Size;
525
526 switch (Type) {
527 case wasm::WASM_NAMES_FUNCTION:
528 case wasm::WASM_NAMES_GLOBAL:
529 case wasm::WASM_NAMES_DATA_SEGMENT: {
530 uint32_t Count = readVaruint32(Ctx);
531 while (Count--) {
532 uint32_t Index = readVaruint32(Ctx);
533 StringRef Name = readString(Ctx);
534 wasm::NameType nameType = wasm::NameType::FUNCTION;
535 wasm::WasmSymbolInfo Info{.Name: Name,
536 /*Kind */ wasm::WASM_SYMBOL_TYPE_FUNCTION,
537 /* Flags */ 0,
538 /* ImportModule */ std::nullopt,
539 /* ImportName */ std::nullopt,
540 /* ExportName */ std::nullopt,
541 {/* ElementIndex */ Index}};
542 const wasm::WasmSignature *Signature = nullptr;
543 const wasm::WasmGlobalType *GlobalType = nullptr;
544 const wasm::WasmTableType *TableType = nullptr;
545 if (Type == wasm::WASM_NAMES_FUNCTION) {
546 if (!SeenFunctions.insert(V: Index).second)
547 return make_error<GenericBinaryError>(
548 Args: "function named more than once", Args: object_error::parse_failed);
549 if (!isValidFunctionIndex(Index) || Name.empty())
550 return make_error<GenericBinaryError>(Args: "invalid function name entry",
551 Args: object_error::parse_failed);
552
553 if (isDefinedFunctionIndex(Index)) {
554 wasm::WasmFunction &F = getDefinedFunction(Index);
555 F.DebugName = Name;
556 Signature = &Signatures[F.SigIndex];
557 if (F.ExportName) {
558 Info.ExportName = F.ExportName;
559 Info.Flags |= wasm::WASM_SYMBOL_BINDING_GLOBAL;
560 } else {
561 Info.Flags |= wasm::WASM_SYMBOL_BINDING_LOCAL;
562 }
563 } else {
564 Info.Flags |= wasm::WASM_SYMBOL_UNDEFINED;
565 }
566 } else if (Type == wasm::WASM_NAMES_GLOBAL) {
567 if (!SeenGlobals.insert(V: Index).second)
568 return make_error<GenericBinaryError>(Args: "global named more than once",
569 Args: object_error::parse_failed);
570 if (!isValidGlobalIndex(Index) || Name.empty())
571 return make_error<GenericBinaryError>(Args: "invalid global name entry",
572 Args: object_error::parse_failed);
573 nameType = wasm::NameType::GLOBAL;
574 Info.Kind = wasm::WASM_SYMBOL_TYPE_GLOBAL;
575 if (isDefinedGlobalIndex(Index)) {
576 GlobalType = &getDefinedGlobal(Index).Type;
577 } else {
578 Info.Flags |= wasm::WASM_SYMBOL_UNDEFINED;
579 }
580 } else {
581 if (!SeenSegments.insert(V: Index).second)
582 return make_error<GenericBinaryError>(
583 Args: "segment named more than once", Args: object_error::parse_failed);
584 if (Index > DataSegments.size())
585 return make_error<GenericBinaryError>(Args: "invalid data segment name entry",
586 Args: object_error::parse_failed);
587 nameType = wasm::NameType::DATA_SEGMENT;
588 Info.Kind = wasm::WASM_SYMBOL_TYPE_DATA;
589 Info.Flags |= wasm::WASM_SYMBOL_BINDING_LOCAL;
590 assert(Index < DataSegments.size());
591 Info.DataRef = wasm::WasmDataReference{
592 .Segment: Index, .Offset: 0, .Size: DataSegments[Index].Data.Content.size()};
593 }
594 DebugNames.push_back(x: wasm::WasmDebugName{.Type: nameType, .Index: Index, .Name: Name});
595 if (PopulateSymbolTable)
596 Symbols.emplace_back(args&: Info, args&: GlobalType, args&: TableType, args&: Signature);
597 }
598 break;
599 }
600 // Ignore local names for now
601 case wasm::WASM_NAMES_LOCAL:
602 default:
603 Ctx.Ptr += Size;
604 break;
605 }
606 if (Ctx.Ptr != SubSectionEnd)
607 return make_error<GenericBinaryError>(
608 Args: "name sub-section ended prematurely", Args: object_error::parse_failed);
609 }
610
611 if (Ctx.Ptr != Ctx.End)
612 return make_error<GenericBinaryError>(Args: "name section ended prematurely",
613 Args: object_error::parse_failed);
614 return Error::success();
615}
616
617Error WasmObjectFile::parseLinkingSection(ReadContext &Ctx) {
618 HasLinkingSection = true;
619
620 LinkingData.Version = readVaruint32(Ctx);
621 if (LinkingData.Version != wasm::WasmMetadataVersion) {
622 return make_error<GenericBinaryError>(
623 Args: "unexpected metadata version: " + Twine(LinkingData.Version) +
624 " (Expected: " + Twine(wasm::WasmMetadataVersion) + ")",
625 Args: object_error::parse_failed);
626 }
627
628 const uint8_t *OrigEnd = Ctx.End;
629 while (Ctx.Ptr < OrigEnd) {
630 Ctx.End = OrigEnd;
631 uint8_t Type = readUint8(Ctx);
632 uint32_t Size = readVaruint32(Ctx);
633 LLVM_DEBUG(dbgs() << "readSubsection type=" << int(Type) << " size=" << Size
634 << "\n");
635 Ctx.End = Ctx.Ptr + Size;
636 switch (Type) {
637 case wasm::WASM_SYMBOL_TABLE:
638 if (Error Err = parseLinkingSectionSymtab(Ctx))
639 return Err;
640 break;
641 case wasm::WASM_SEGMENT_INFO: {
642 uint32_t Count = readVaruint32(Ctx);
643 if (Count > DataSegments.size())
644 return make_error<GenericBinaryError>(Args: "too many segment names",
645 Args: object_error::parse_failed);
646 for (uint32_t I = 0; I < Count; I++) {
647 DataSegments[I].Data.Name = readString(Ctx);
648 DataSegments[I].Data.Alignment = readVaruint32(Ctx);
649 DataSegments[I].Data.LinkingFlags = readVaruint32(Ctx);
650 }
651 break;
652 }
653 case wasm::WASM_INIT_FUNCS: {
654 uint32_t Count = readVaruint32(Ctx);
655 LinkingData.InitFunctions.reserve(n: Count);
656 for (uint32_t I = 0; I < Count; I++) {
657 wasm::WasmInitFunc Init;
658 Init.Priority = readVaruint32(Ctx);
659 Init.Symbol = readVaruint32(Ctx);
660 if (!isValidFunctionSymbol(Index: Init.Symbol))
661 return make_error<GenericBinaryError>(Args: "invalid function symbol: " +
662 Twine(Init.Symbol),
663 Args: object_error::parse_failed);
664 LinkingData.InitFunctions.emplace_back(args&: Init);
665 }
666 break;
667 }
668 case wasm::WASM_COMDAT_INFO:
669 if (Error Err = parseLinkingSectionComdat(Ctx))
670 return Err;
671 break;
672 default:
673 Ctx.Ptr += Size;
674 break;
675 }
676 if (Ctx.Ptr != Ctx.End)
677 return make_error<GenericBinaryError>(
678 Args: "linking sub-section ended prematurely", Args: object_error::parse_failed);
679 }
680 if (Ctx.Ptr != OrigEnd)
681 return make_error<GenericBinaryError>(Args: "linking section ended prematurely",
682 Args: object_error::parse_failed);
683 return Error::success();
684}
685
686Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
687 uint32_t Count = readVaruint32(Ctx);
688 // Clear out any symbol information that was derived from the exports
689 // section.
690 Symbols.clear();
691 Symbols.reserve(n: Count);
692 StringSet<> SymbolNames;
693
694 std::vector<wasm::WasmImport *> ImportedGlobals;
695 std::vector<wasm::WasmImport *> ImportedFunctions;
696 std::vector<wasm::WasmImport *> ImportedTags;
697 std::vector<wasm::WasmImport *> ImportedTables;
698 ImportedGlobals.reserve(n: Imports.size());
699 ImportedFunctions.reserve(n: Imports.size());
700 ImportedTags.reserve(n: Imports.size());
701 ImportedTables.reserve(n: Imports.size());
702 for (auto &I : Imports) {
703 if (I.Kind == wasm::WASM_EXTERNAL_FUNCTION)
704 ImportedFunctions.emplace_back(args: &I);
705 else if (I.Kind == wasm::WASM_EXTERNAL_GLOBAL)
706 ImportedGlobals.emplace_back(args: &I);
707 else if (I.Kind == wasm::WASM_EXTERNAL_TAG)
708 ImportedTags.emplace_back(args: &I);
709 else if (I.Kind == wasm::WASM_EXTERNAL_TABLE)
710 ImportedTables.emplace_back(args: &I);
711 }
712
713 while (Count--) {
714 wasm::WasmSymbolInfo Info;
715 const wasm::WasmSignature *Signature = nullptr;
716 const wasm::WasmGlobalType *GlobalType = nullptr;
717 const wasm::WasmTableType *TableType = nullptr;
718
719 Info.Kind = readUint8(Ctx);
720 Info.Flags = readVaruint32(Ctx);
721 bool IsDefined = (Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0;
722
723 switch (Info.Kind) {
724 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
725 Info.ElementIndex = readVaruint32(Ctx);
726 if (!isValidFunctionIndex(Index: Info.ElementIndex) ||
727 IsDefined != isDefinedFunctionIndex(Index: Info.ElementIndex))
728 return make_error<GenericBinaryError>(Args: "invalid function symbol index",
729 Args: object_error::parse_failed);
730 if (IsDefined) {
731 Info.Name = readString(Ctx);
732 unsigned FuncIndex = Info.ElementIndex - NumImportedFunctions;
733 wasm::WasmFunction &Function = Functions[FuncIndex];
734 Signature = &Signatures[Function.SigIndex];
735 if (Function.SymbolName.empty())
736 Function.SymbolName = Info.Name;
737 } else {
738 wasm::WasmImport &Import = *ImportedFunctions[Info.ElementIndex];
739 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
740 Info.Name = readString(Ctx);
741 Info.ImportName = Import.Field;
742 } else {
743 Info.Name = Import.Field;
744 }
745 Signature = &Signatures[Import.SigIndex];
746 Info.ImportModule = Import.Module;
747 }
748 break;
749
750 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
751 Info.ElementIndex = readVaruint32(Ctx);
752 if (!isValidGlobalIndex(Index: Info.ElementIndex) ||
753 IsDefined != isDefinedGlobalIndex(Index: Info.ElementIndex))
754 return make_error<GenericBinaryError>(Args: "invalid global symbol index",
755 Args: object_error::parse_failed);
756 if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
757 wasm::WASM_SYMBOL_BINDING_WEAK)
758 return make_error<GenericBinaryError>(Args: "undefined weak global symbol",
759 Args: object_error::parse_failed);
760 if (IsDefined) {
761 Info.Name = readString(Ctx);
762 unsigned GlobalIndex = Info.ElementIndex - NumImportedGlobals;
763 wasm::WasmGlobal &Global = Globals[GlobalIndex];
764 GlobalType = &Global.Type;
765 if (Global.SymbolName.empty())
766 Global.SymbolName = Info.Name;
767 } else {
768 wasm::WasmImport &Import = *ImportedGlobals[Info.ElementIndex];
769 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
770 Info.Name = readString(Ctx);
771 Info.ImportName = Import.Field;
772 } else {
773 Info.Name = Import.Field;
774 }
775 GlobalType = &Import.Global;
776 Info.ImportModule = Import.Module;
777 }
778 break;
779
780 case wasm::WASM_SYMBOL_TYPE_TABLE:
781 Info.ElementIndex = readVaruint32(Ctx);
782 if (!isValidTableNumber(Index: Info.ElementIndex) ||
783 IsDefined != isDefinedTableNumber(Index: Info.ElementIndex))
784 return make_error<GenericBinaryError>(Args: "invalid table symbol index",
785 Args: object_error::parse_failed);
786 if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
787 wasm::WASM_SYMBOL_BINDING_WEAK)
788 return make_error<GenericBinaryError>(Args: "undefined weak table symbol",
789 Args: object_error::parse_failed);
790 if (IsDefined) {
791 Info.Name = readString(Ctx);
792 unsigned TableNumber = Info.ElementIndex - NumImportedTables;
793 wasm::WasmTable &Table = Tables[TableNumber];
794 TableType = &Table.Type;
795 if (Table.SymbolName.empty())
796 Table.SymbolName = Info.Name;
797 } else {
798 wasm::WasmImport &Import = *ImportedTables[Info.ElementIndex];
799 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
800 Info.Name = readString(Ctx);
801 Info.ImportName = Import.Field;
802 } else {
803 Info.Name = Import.Field;
804 }
805 TableType = &Import.Table;
806 Info.ImportModule = Import.Module;
807 }
808 break;
809
810 case wasm::WASM_SYMBOL_TYPE_DATA:
811 Info.Name = readString(Ctx);
812 if (IsDefined) {
813 auto Index = readVaruint32(Ctx);
814 auto Offset = readVaruint64(Ctx);
815 auto Size = readVaruint64(Ctx);
816 if (!(Info.Flags & wasm::WASM_SYMBOL_ABSOLUTE)) {
817 if (static_cast<size_t>(Index) >= DataSegments.size())
818 return make_error<GenericBinaryError>(
819 Args: "invalid data segment index: " + Twine(Index),
820 Args: object_error::parse_failed);
821 size_t SegmentSize = DataSegments[Index].Data.Content.size();
822 if (Offset > SegmentSize)
823 return make_error<GenericBinaryError>(
824 Args: "invalid data symbol offset: `" + Info.Name +
825 "` (offset: " + Twine(Offset) +
826 " segment size: " + Twine(SegmentSize) + ")",
827 Args: object_error::parse_failed);
828 }
829 Info.DataRef = wasm::WasmDataReference{.Segment: Index, .Offset: Offset, .Size: Size};
830 }
831 break;
832
833 case wasm::WASM_SYMBOL_TYPE_SECTION: {
834 if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) !=
835 wasm::WASM_SYMBOL_BINDING_LOCAL)
836 return make_error<GenericBinaryError>(
837 Args: "section symbols must have local binding",
838 Args: object_error::parse_failed);
839 Info.ElementIndex = readVaruint32(Ctx);
840 // Use somewhat unique section name as symbol name.
841 StringRef SectionName = Sections[Info.ElementIndex].Name;
842 Info.Name = SectionName;
843 break;
844 }
845
846 case wasm::WASM_SYMBOL_TYPE_TAG: {
847 Info.ElementIndex = readVaruint32(Ctx);
848 if (!isValidTagIndex(Index: Info.ElementIndex) ||
849 IsDefined != isDefinedTagIndex(Index: Info.ElementIndex))
850 return make_error<GenericBinaryError>(Args: "invalid tag symbol index",
851 Args: object_error::parse_failed);
852 if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
853 wasm::WASM_SYMBOL_BINDING_WEAK)
854 return make_error<GenericBinaryError>(Args: "undefined weak global symbol",
855 Args: object_error::parse_failed);
856 if (IsDefined) {
857 Info.Name = readString(Ctx);
858 unsigned TagIndex = Info.ElementIndex - NumImportedTags;
859 wasm::WasmTag &Tag = Tags[TagIndex];
860 Signature = &Signatures[Tag.SigIndex];
861 if (Tag.SymbolName.empty())
862 Tag.SymbolName = Info.Name;
863
864 } else {
865 wasm::WasmImport &Import = *ImportedTags[Info.ElementIndex];
866 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
867 Info.Name = readString(Ctx);
868 Info.ImportName = Import.Field;
869 } else {
870 Info.Name = Import.Field;
871 }
872 Signature = &Signatures[Import.SigIndex];
873 Info.ImportModule = Import.Module;
874 }
875 break;
876 }
877
878 default:
879 return make_error<GenericBinaryError>(Args: "invalid symbol type: " +
880 Twine(unsigned(Info.Kind)),
881 Args: object_error::parse_failed);
882 }
883
884 if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) !=
885 wasm::WASM_SYMBOL_BINDING_LOCAL &&
886 !SymbolNames.insert(key: Info.Name).second)
887 return make_error<GenericBinaryError>(Args: "duplicate symbol name " +
888 Twine(Info.Name),
889 Args: object_error::parse_failed);
890 Symbols.emplace_back(args&: Info, args&: GlobalType, args&: TableType, args&: Signature);
891 LLVM_DEBUG(dbgs() << "Adding symbol: " << Symbols.back() << "\n");
892 }
893
894 return Error::success();
895}
896
897Error WasmObjectFile::parseLinkingSectionComdat(ReadContext &Ctx) {
898 uint32_t ComdatCount = readVaruint32(Ctx);
899 StringSet<> ComdatSet;
900 for (unsigned ComdatIndex = 0; ComdatIndex < ComdatCount; ++ComdatIndex) {
901 StringRef Name = readString(Ctx);
902 if (Name.empty() || !ComdatSet.insert(key: Name).second)
903 return make_error<GenericBinaryError>(Args: "bad/duplicate COMDAT name " +
904 Twine(Name),
905 Args: object_error::parse_failed);
906 LinkingData.Comdats.emplace_back(args&: Name);
907 uint32_t Flags = readVaruint32(Ctx);
908 if (Flags != 0)
909 return make_error<GenericBinaryError>(Args: "unsupported COMDAT flags",
910 Args: object_error::parse_failed);
911
912 uint32_t EntryCount = readVaruint32(Ctx);
913 while (EntryCount--) {
914 unsigned Kind = readVaruint32(Ctx);
915 unsigned Index = readVaruint32(Ctx);
916 switch (Kind) {
917 default:
918 return make_error<GenericBinaryError>(Args: "invalid COMDAT entry type",
919 Args: object_error::parse_failed);
920 case wasm::WASM_COMDAT_DATA:
921 if (Index >= DataSegments.size())
922 return make_error<GenericBinaryError>(
923 Args: "COMDAT data index out of range", Args: object_error::parse_failed);
924 if (DataSegments[Index].Data.Comdat != UINT32_MAX)
925 return make_error<GenericBinaryError>(Args: "data segment in two COMDATs",
926 Args: object_error::parse_failed);
927 DataSegments[Index].Data.Comdat = ComdatIndex;
928 break;
929 case wasm::WASM_COMDAT_FUNCTION:
930 if (!isDefinedFunctionIndex(Index))
931 return make_error<GenericBinaryError>(
932 Args: "COMDAT function index out of range", Args: object_error::parse_failed);
933 if (getDefinedFunction(Index).Comdat != UINT32_MAX)
934 return make_error<GenericBinaryError>(Args: "function in two COMDATs",
935 Args: object_error::parse_failed);
936 getDefinedFunction(Index).Comdat = ComdatIndex;
937 break;
938 case wasm::WASM_COMDAT_SECTION:
939 if (Index >= Sections.size())
940 return make_error<GenericBinaryError>(
941 Args: "COMDAT section index out of range", Args: object_error::parse_failed);
942 if (Sections[Index].Type != wasm::WASM_SEC_CUSTOM)
943 return make_error<GenericBinaryError>(
944 Args: "non-custom section in a COMDAT", Args: object_error::parse_failed);
945 Sections[Index].Comdat = ComdatIndex;
946 break;
947 }
948 }
949 }
950 return Error::success();
951}
952
953Error WasmObjectFile::parseProducersSection(ReadContext &Ctx) {
954 llvm::SmallSet<StringRef, 3> FieldsSeen;
955 uint32_t Fields = readVaruint32(Ctx);
956 for (size_t I = 0; I < Fields; ++I) {
957 StringRef FieldName = readString(Ctx);
958 if (!FieldsSeen.insert(V: FieldName).second)
959 return make_error<GenericBinaryError>(
960 Args: "producers section does not have unique fields",
961 Args: object_error::parse_failed);
962 std::vector<std::pair<std::string, std::string>> *ProducerVec = nullptr;
963 if (FieldName == "language") {
964 ProducerVec = &ProducerInfo.Languages;
965 } else if (FieldName == "processed-by") {
966 ProducerVec = &ProducerInfo.Tools;
967 } else if (FieldName == "sdk") {
968 ProducerVec = &ProducerInfo.SDKs;
969 } else {
970 return make_error<GenericBinaryError>(
971 Args: "producers section field is not named one of language, processed-by, "
972 "or sdk",
973 Args: object_error::parse_failed);
974 }
975 uint32_t ValueCount = readVaruint32(Ctx);
976 llvm::SmallSet<StringRef, 8> ProducersSeen;
977 for (size_t J = 0; J < ValueCount; ++J) {
978 StringRef Name = readString(Ctx);
979 StringRef Version = readString(Ctx);
980 if (!ProducersSeen.insert(V: Name).second) {
981 return make_error<GenericBinaryError>(
982 Args: "producers section contains repeated producer",
983 Args: object_error::parse_failed);
984 }
985 ProducerVec->emplace_back(args: std::string(Name), args: std::string(Version));
986 }
987 }
988 if (Ctx.Ptr != Ctx.End)
989 return make_error<GenericBinaryError>(Args: "producers section ended prematurely",
990 Args: object_error::parse_failed);
991 return Error::success();
992}
993
994Error WasmObjectFile::parseTargetFeaturesSection(ReadContext &Ctx) {
995 llvm::SmallSet<std::string, 8> FeaturesSeen;
996 uint32_t FeatureCount = readVaruint32(Ctx);
997 for (size_t I = 0; I < FeatureCount; ++I) {
998 wasm::WasmFeatureEntry Feature;
999 Feature.Prefix = readUint8(Ctx);
1000 switch (Feature.Prefix) {
1001 case wasm::WASM_FEATURE_PREFIX_USED:
1002 case wasm::WASM_FEATURE_PREFIX_REQUIRED:
1003 case wasm::WASM_FEATURE_PREFIX_DISALLOWED:
1004 break;
1005 default:
1006 return make_error<GenericBinaryError>(Args: "unknown feature policy prefix",
1007 Args: object_error::parse_failed);
1008 }
1009 Feature.Name = std::string(readString(Ctx));
1010 if (!FeaturesSeen.insert(V: Feature.Name).second)
1011 return make_error<GenericBinaryError>(
1012 Args: "target features section contains repeated feature \"" +
1013 Feature.Name + "\"",
1014 Args: object_error::parse_failed);
1015 TargetFeatures.push_back(x: Feature);
1016 }
1017 if (Ctx.Ptr != Ctx.End)
1018 return make_error<GenericBinaryError>(
1019 Args: "target features section ended prematurely",
1020 Args: object_error::parse_failed);
1021 return Error::success();
1022}
1023
1024Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
1025 uint32_t SectionIndex = readVaruint32(Ctx);
1026 if (SectionIndex >= Sections.size())
1027 return make_error<GenericBinaryError>(Args: "invalid section index",
1028 Args: object_error::parse_failed);
1029 WasmSection &Section = Sections[SectionIndex];
1030 uint32_t RelocCount = readVaruint32(Ctx);
1031 uint32_t EndOffset = Section.Content.size();
1032 uint32_t PreviousOffset = 0;
1033 while (RelocCount--) {
1034 wasm::WasmRelocation Reloc = {};
1035 uint32_t type = readVaruint32(Ctx);
1036 Reloc.Type = type;
1037 Reloc.Offset = readVaruint32(Ctx);
1038 if (Reloc.Offset < PreviousOffset)
1039 return make_error<GenericBinaryError>(Args: "relocations not in offset order",
1040 Args: object_error::parse_failed);
1041
1042 auto badReloc = [&](StringRef msg) {
1043 return make_error<GenericBinaryError>(
1044 Args: msg + ": " + Twine(Symbols[Reloc.Index].Info.Name),
1045 Args: object_error::parse_failed);
1046 };
1047
1048 PreviousOffset = Reloc.Offset;
1049 Reloc.Index = readVaruint32(Ctx);
1050 switch (type) {
1051 case wasm::R_WASM_FUNCTION_INDEX_LEB:
1052 case wasm::R_WASM_FUNCTION_INDEX_I32:
1053 case wasm::R_WASM_TABLE_INDEX_SLEB:
1054 case wasm::R_WASM_TABLE_INDEX_SLEB64:
1055 case wasm::R_WASM_TABLE_INDEX_I32:
1056 case wasm::R_WASM_TABLE_INDEX_I64:
1057 case wasm::R_WASM_TABLE_INDEX_REL_SLEB:
1058 case wasm::R_WASM_TABLE_INDEX_REL_SLEB64:
1059 if (!isValidFunctionSymbol(Index: Reloc.Index))
1060 return badReloc("invalid function relocation");
1061 break;
1062 case wasm::R_WASM_TABLE_NUMBER_LEB:
1063 if (!isValidTableSymbol(Index: Reloc.Index))
1064 return badReloc("invalid table relocation");
1065 break;
1066 case wasm::R_WASM_TYPE_INDEX_LEB:
1067 if (Reloc.Index >= Signatures.size())
1068 return badReloc("invalid relocation type index");
1069 break;
1070 case wasm::R_WASM_GLOBAL_INDEX_LEB:
1071 // R_WASM_GLOBAL_INDEX_LEB are can be used against function and data
1072 // symbols to refer to their GOT entries.
1073 if (!isValidGlobalSymbol(Index: Reloc.Index) &&
1074 !isValidDataSymbol(Index: Reloc.Index) &&
1075 !isValidFunctionSymbol(Index: Reloc.Index))
1076 return badReloc("invalid global relocation");
1077 break;
1078 case wasm::R_WASM_GLOBAL_INDEX_I32:
1079 if (!isValidGlobalSymbol(Index: Reloc.Index))
1080 return badReloc("invalid global relocation");
1081 break;
1082 case wasm::R_WASM_TAG_INDEX_LEB:
1083 if (!isValidTagSymbol(Index: Reloc.Index))
1084 return badReloc("invalid tag relocation");
1085 break;
1086 case wasm::R_WASM_MEMORY_ADDR_LEB:
1087 case wasm::R_WASM_MEMORY_ADDR_SLEB:
1088 case wasm::R_WASM_MEMORY_ADDR_I32:
1089 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:
1090 case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB:
1091 case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32:
1092 if (!isValidDataSymbol(Index: Reloc.Index))
1093 return badReloc("invalid data relocation");
1094 Reloc.Addend = readVarint32(Ctx);
1095 break;
1096 case wasm::R_WASM_MEMORY_ADDR_LEB64:
1097 case wasm::R_WASM_MEMORY_ADDR_SLEB64:
1098 case wasm::R_WASM_MEMORY_ADDR_I64:
1099 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64:
1100 case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB64:
1101 if (!isValidDataSymbol(Index: Reloc.Index))
1102 return badReloc("invalid data relocation");
1103 Reloc.Addend = readVarint64(Ctx);
1104 break;
1105 case wasm::R_WASM_FUNCTION_OFFSET_I32:
1106 if (!isValidFunctionSymbol(Index: Reloc.Index))
1107 return badReloc("invalid function relocation");
1108 Reloc.Addend = readVarint32(Ctx);
1109 break;
1110 case wasm::R_WASM_FUNCTION_OFFSET_I64:
1111 if (!isValidFunctionSymbol(Index: Reloc.Index))
1112 return badReloc("invalid function relocation");
1113 Reloc.Addend = readVarint64(Ctx);
1114 break;
1115 case wasm::R_WASM_SECTION_OFFSET_I32:
1116 if (!isValidSectionSymbol(Index: Reloc.Index))
1117 return badReloc("invalid section relocation");
1118 Reloc.Addend = readVarint32(Ctx);
1119 break;
1120 default:
1121 return make_error<GenericBinaryError>(Args: "invalid relocation type: " +
1122 Twine(type),
1123 Args: object_error::parse_failed);
1124 }
1125
1126 // Relocations must fit inside the section, and must appear in order. They
1127 // also shouldn't overlap a function/element boundary, but we don't bother
1128 // to check that.
1129 uint64_t Size = 5;
1130 if (Reloc.Type == wasm::R_WASM_MEMORY_ADDR_LEB64 ||
1131 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_SLEB64 ||
1132 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_REL_SLEB64)
1133 Size = 10;
1134 if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I32 ||
1135 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I32 ||
1136 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_LOCREL_I32 ||
1137 Reloc.Type == wasm::R_WASM_SECTION_OFFSET_I32 ||
1138 Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I32 ||
1139 Reloc.Type == wasm::R_WASM_FUNCTION_INDEX_I32 ||
1140 Reloc.Type == wasm::R_WASM_GLOBAL_INDEX_I32)
1141 Size = 4;
1142 if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I64 ||
1143 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I64 ||
1144 Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I64)
1145 Size = 8;
1146 if (Reloc.Offset + Size > EndOffset)
1147 return make_error<GenericBinaryError>(Args: "invalid relocation offset",
1148 Args: object_error::parse_failed);
1149
1150 Section.Relocations.push_back(x: Reloc);
1151 }
1152 if (Ctx.Ptr != Ctx.End)
1153 return make_error<GenericBinaryError>(Args: "reloc section ended prematurely",
1154 Args: object_error::parse_failed);
1155 return Error::success();
1156}
1157
1158Error WasmObjectFile::parseCustomSection(WasmSection &Sec, ReadContext &Ctx) {
1159 if (Sec.Name == "dylink") {
1160 if (Error Err = parseDylinkSection(Ctx))
1161 return Err;
1162 } else if (Sec.Name == "dylink.0") {
1163 if (Error Err = parseDylink0Section(Ctx))
1164 return Err;
1165 } else if (Sec.Name == "name") {
1166 if (Error Err = parseNameSection(Ctx))
1167 return Err;
1168 } else if (Sec.Name == "linking") {
1169 if (Error Err = parseLinkingSection(Ctx))
1170 return Err;
1171 } else if (Sec.Name == "producers") {
1172 if (Error Err = parseProducersSection(Ctx))
1173 return Err;
1174 } else if (Sec.Name == "target_features") {
1175 if (Error Err = parseTargetFeaturesSection(Ctx))
1176 return Err;
1177 } else if (Sec.Name.starts_with(Prefix: "reloc.")) {
1178 if (Error Err = parseRelocSection(Name: Sec.Name, Ctx))
1179 return Err;
1180 }
1181 return Error::success();
1182}
1183
1184Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
1185 auto parseFieldDef = [&]() {
1186 uint32_t TypeCode = readVaruint32((Ctx));
1187 /* Discard StorageType */ parseValType(Ctx, Code: TypeCode);
1188 /* Discard Mutability */ readVaruint32(Ctx);
1189 };
1190
1191 uint32_t Count = readVaruint32(Ctx);
1192 Signatures.reserve(n: Count);
1193 while (Count--) {
1194 wasm::WasmSignature Sig;
1195 uint8_t Form = readUint8(Ctx);
1196 if (Form == wasm::WASM_TYPE_REC) {
1197 // Rec groups expand the type index space (beyond what was declared at
1198 // the top of the section, and also consume one element in that space.
1199 uint32_t RecSize = readVaruint32(Ctx);
1200 if (RecSize == 0)
1201 return make_error<GenericBinaryError>(Args: "Rec group size cannot be 0",
1202 Args: object_error::parse_failed);
1203 Signatures.reserve(n: Signatures.size() + RecSize);
1204 Count += RecSize;
1205 Sig.Kind = wasm::WasmSignature::Placeholder;
1206 Signatures.push_back(x: std::move(Sig));
1207 HasUnmodeledTypes = true;
1208 continue;
1209 }
1210 if (Form != wasm::WASM_TYPE_FUNC) {
1211 // Currently LLVM only models function types, and not other composite
1212 // types. Here we parse the type declarations just enough to skip past
1213 // them in the binary.
1214 if (Form == wasm::WASM_TYPE_SUB || Form == wasm::WASM_TYPE_SUB_FINAL) {
1215 uint32_t Supers = readVaruint32(Ctx);
1216 if (Supers > 0) {
1217 if (Supers != 1)
1218 return make_error<GenericBinaryError>(
1219 Args: "Invalid number of supertypes", Args: object_error::parse_failed);
1220 /* Discard SuperIndex */ readVaruint32(Ctx);
1221 }
1222 Form = readVaruint32(Ctx);
1223 }
1224 if (Form == wasm::WASM_TYPE_STRUCT) {
1225 uint32_t FieldCount = readVaruint32(Ctx);
1226 while (FieldCount--) {
1227 parseFieldDef();
1228 }
1229 } else if (Form == wasm::WASM_TYPE_ARRAY) {
1230 parseFieldDef();
1231 } else {
1232 return make_error<GenericBinaryError>(Args: "bad form",
1233 Args: object_error::parse_failed);
1234 }
1235 Sig.Kind = wasm::WasmSignature::Placeholder;
1236 Signatures.push_back(x: std::move(Sig));
1237 HasUnmodeledTypes = true;
1238 continue;
1239 }
1240
1241 uint32_t ParamCount = readVaruint32(Ctx);
1242 Sig.Params.reserve(N: ParamCount);
1243 while (ParamCount--) {
1244 uint32_t ParamType = readUint8(Ctx);
1245 Sig.Params.push_back(Elt: parseValType(Ctx, Code: ParamType));
1246 continue;
1247 }
1248 uint32_t ReturnCount = readVaruint32(Ctx);
1249 while (ReturnCount--) {
1250 uint32_t ReturnType = readUint8(Ctx);
1251 Sig.Returns.push_back(Elt: parseValType(Ctx, Code: ReturnType));
1252 }
1253
1254 Signatures.push_back(x: std::move(Sig));
1255 }
1256 if (Ctx.Ptr != Ctx.End)
1257 return make_error<GenericBinaryError>(Args: "type section ended prematurely",
1258 Args: object_error::parse_failed);
1259 return Error::success();
1260}
1261
1262Error WasmObjectFile::parseImportSection(ReadContext &Ctx) {
1263 uint32_t Count = readVaruint32(Ctx);
1264 uint32_t NumTypes = Signatures.size();
1265 Imports.reserve(n: Count);
1266 for (uint32_t I = 0; I < Count; I++) {
1267 wasm::WasmImport Im;
1268 Im.Module = readString(Ctx);
1269 Im.Field = readString(Ctx);
1270 Im.Kind = readUint8(Ctx);
1271 switch (Im.Kind) {
1272 case wasm::WASM_EXTERNAL_FUNCTION:
1273 NumImportedFunctions++;
1274 Im.SigIndex = readVaruint32(Ctx);
1275 if (Im.SigIndex >= NumTypes)
1276 return make_error<GenericBinaryError>(Args: "invalid function type",
1277 Args: object_error::parse_failed);
1278 break;
1279 case wasm::WASM_EXTERNAL_GLOBAL:
1280 NumImportedGlobals++;
1281 Im.Global.Type = readUint8(Ctx);
1282 Im.Global.Mutable = readVaruint1(Ctx);
1283 break;
1284 case wasm::WASM_EXTERNAL_MEMORY:
1285 Im.Memory = readLimits(Ctx);
1286 if (Im.Memory.Flags & wasm::WASM_LIMITS_FLAG_IS_64)
1287 HasMemory64 = true;
1288 break;
1289 case wasm::WASM_EXTERNAL_TABLE: {
1290 Im.Table = readTableType(Ctx);
1291 NumImportedTables++;
1292 auto ElemType = Im.Table.ElemType;
1293 if (ElemType != wasm::ValType::FUNCREF &&
1294 ElemType != wasm::ValType::EXTERNREF &&
1295 ElemType != wasm::ValType::EXNREF &&
1296 ElemType != wasm::ValType::OTHERREF)
1297 return make_error<GenericBinaryError>(Args: "invalid table element type",
1298 Args: object_error::parse_failed);
1299 break;
1300 }
1301 case wasm::WASM_EXTERNAL_TAG:
1302 NumImportedTags++;
1303 if (readUint8(Ctx) != 0) // Reserved 'attribute' field
1304 return make_error<GenericBinaryError>(Args: "invalid attribute",
1305 Args: object_error::parse_failed);
1306 Im.SigIndex = readVaruint32(Ctx);
1307 if (Im.SigIndex >= NumTypes)
1308 return make_error<GenericBinaryError>(Args: "invalid tag type",
1309 Args: object_error::parse_failed);
1310 break;
1311 default:
1312 return make_error<GenericBinaryError>(Args: "unexpected import kind",
1313 Args: object_error::parse_failed);
1314 }
1315 Imports.push_back(x: Im);
1316 }
1317 if (Ctx.Ptr != Ctx.End)
1318 return make_error<GenericBinaryError>(Args: "import section ended prematurely",
1319 Args: object_error::parse_failed);
1320 return Error::success();
1321}
1322
1323Error WasmObjectFile::parseFunctionSection(ReadContext &Ctx) {
1324 uint32_t Count = readVaruint32(Ctx);
1325 Functions.reserve(n: Count);
1326 uint32_t NumTypes = Signatures.size();
1327 while (Count--) {
1328 uint32_t Type = readVaruint32(Ctx);
1329 if (Type >= NumTypes)
1330 return make_error<GenericBinaryError>(Args: "invalid function type",
1331 Args: object_error::parse_failed);
1332 wasm::WasmFunction F;
1333 F.SigIndex = Type;
1334 Functions.push_back(x: F);
1335 }
1336 if (Ctx.Ptr != Ctx.End)
1337 return make_error<GenericBinaryError>(Args: "function section ended prematurely",
1338 Args: object_error::parse_failed);
1339 return Error::success();
1340}
1341
1342Error WasmObjectFile::parseTableSection(ReadContext &Ctx) {
1343 TableSection = Sections.size();
1344 uint32_t Count = readVaruint32(Ctx);
1345 Tables.reserve(n: Count);
1346 while (Count--) {
1347 wasm::WasmTable T;
1348 T.Type = readTableType(Ctx);
1349 T.Index = NumImportedTables + Tables.size();
1350 Tables.push_back(x: T);
1351 auto ElemType = Tables.back().Type.ElemType;
1352 if (ElemType != wasm::ValType::FUNCREF &&
1353 ElemType != wasm::ValType::EXTERNREF &&
1354 ElemType != wasm::ValType::EXNREF &&
1355 ElemType != wasm::ValType::OTHERREF) {
1356 return make_error<GenericBinaryError>(Args: "invalid table element type",
1357 Args: object_error::parse_failed);
1358 }
1359 }
1360 if (Ctx.Ptr != Ctx.End)
1361 return make_error<GenericBinaryError>(Args: "table section ended prematurely",
1362 Args: object_error::parse_failed);
1363 return Error::success();
1364}
1365
1366Error WasmObjectFile::parseMemorySection(ReadContext &Ctx) {
1367 uint32_t Count = readVaruint32(Ctx);
1368 Memories.reserve(n: Count);
1369 while (Count--) {
1370 auto Limits = readLimits(Ctx);
1371 if (Limits.Flags & wasm::WASM_LIMITS_FLAG_IS_64)
1372 HasMemory64 = true;
1373 Memories.push_back(x: Limits);
1374 }
1375 if (Ctx.Ptr != Ctx.End)
1376 return make_error<GenericBinaryError>(Args: "memory section ended prematurely",
1377 Args: object_error::parse_failed);
1378 return Error::success();
1379}
1380
1381Error WasmObjectFile::parseTagSection(ReadContext &Ctx) {
1382 TagSection = Sections.size();
1383 uint32_t Count = readVaruint32(Ctx);
1384 Tags.reserve(n: Count);
1385 uint32_t NumTypes = Signatures.size();
1386 while (Count--) {
1387 if (readUint8(Ctx) != 0) // Reserved 'attribute' field
1388 return make_error<GenericBinaryError>(Args: "invalid attribute",
1389 Args: object_error::parse_failed);
1390 uint32_t Type = readVaruint32(Ctx);
1391 if (Type >= NumTypes)
1392 return make_error<GenericBinaryError>(Args: "invalid tag type",
1393 Args: object_error::parse_failed);
1394 wasm::WasmTag Tag;
1395 Tag.Index = NumImportedTags + Tags.size();
1396 Tag.SigIndex = Type;
1397 Signatures[Type].Kind = wasm::WasmSignature::Tag;
1398 Tags.push_back(x: Tag);
1399 }
1400
1401 if (Ctx.Ptr != Ctx.End)
1402 return make_error<GenericBinaryError>(Args: "tag section ended prematurely",
1403 Args: object_error::parse_failed);
1404 return Error::success();
1405}
1406
1407Error WasmObjectFile::parseGlobalSection(ReadContext &Ctx) {
1408 GlobalSection = Sections.size();
1409 const uint8_t *SectionStart = Ctx.Ptr;
1410 uint32_t Count = readVaruint32(Ctx);
1411 Globals.reserve(n: Count);
1412 while (Count--) {
1413 wasm::WasmGlobal Global;
1414 Global.Index = NumImportedGlobals + Globals.size();
1415 const uint8_t *GlobalStart = Ctx.Ptr;
1416 Global.Offset = static_cast<uint32_t>(GlobalStart - SectionStart);
1417 auto GlobalOpcode = readVaruint32(Ctx);
1418 Global.Type.Type = (uint8_t)parseValType(Ctx, Code: GlobalOpcode);
1419 Global.Type.Mutable = readVaruint1(Ctx);
1420 if (Error Err = readInitExpr(Expr&: Global.InitExpr, Ctx))
1421 return Err;
1422 Global.Size = static_cast<uint32_t>(Ctx.Ptr - GlobalStart);
1423 Globals.push_back(x: Global);
1424 }
1425 if (Ctx.Ptr != Ctx.End)
1426 return make_error<GenericBinaryError>(Args: "global section ended prematurely",
1427 Args: object_error::parse_failed);
1428 return Error::success();
1429}
1430
1431Error WasmObjectFile::parseExportSection(ReadContext &Ctx) {
1432 uint32_t Count = readVaruint32(Ctx);
1433 Exports.reserve(n: Count);
1434 Symbols.reserve(n: Count);
1435 for (uint32_t I = 0; I < Count; I++) {
1436 wasm::WasmExport Ex;
1437 Ex.Name = readString(Ctx);
1438 Ex.Kind = readUint8(Ctx);
1439 Ex.Index = readVaruint32(Ctx);
1440 const wasm::WasmSignature *Signature = nullptr;
1441 const wasm::WasmGlobalType *GlobalType = nullptr;
1442 const wasm::WasmTableType *TableType = nullptr;
1443 wasm::WasmSymbolInfo Info;
1444 Info.Name = Ex.Name;
1445 Info.Flags = 0;
1446 switch (Ex.Kind) {
1447 case wasm::WASM_EXTERNAL_FUNCTION: {
1448 if (!isDefinedFunctionIndex(Index: Ex.Index))
1449 return make_error<GenericBinaryError>(Args: "invalid function export",
1450 Args: object_error::parse_failed);
1451 getDefinedFunction(Index: Ex.Index).ExportName = Ex.Name;
1452 Info.Kind = wasm::WASM_SYMBOL_TYPE_FUNCTION;
1453 Info.ElementIndex = Ex.Index;
1454 unsigned FuncIndex = Info.ElementIndex - NumImportedFunctions;
1455 wasm::WasmFunction &Function = Functions[FuncIndex];
1456 Signature = &Signatures[Function.SigIndex];
1457 break;
1458 }
1459 case wasm::WASM_EXTERNAL_GLOBAL: {
1460 if (!isValidGlobalIndex(Index: Ex.Index))
1461 return make_error<GenericBinaryError>(Args: "invalid global export",
1462 Args: object_error::parse_failed);
1463 Info.Kind = wasm::WASM_SYMBOL_TYPE_DATA;
1464 uint64_t Offset = 0;
1465 if (isDefinedGlobalIndex(Index: Ex.Index)) {
1466 auto Global = getDefinedGlobal(Index: Ex.Index);
1467 if (!Global.InitExpr.Extended) {
1468 auto Inst = Global.InitExpr.Inst;
1469 if (Inst.Opcode == wasm::WASM_OPCODE_I32_CONST) {
1470 Offset = Inst.Value.Int32;
1471 } else if (Inst.Opcode == wasm::WASM_OPCODE_I64_CONST) {
1472 Offset = Inst.Value.Int64;
1473 }
1474 }
1475 }
1476 Info.DataRef = wasm::WasmDataReference{.Segment: 0, .Offset: Offset, .Size: 0};
1477 break;
1478 }
1479 case wasm::WASM_EXTERNAL_TAG:
1480 if (!isValidTagIndex(Index: Ex.Index))
1481 return make_error<GenericBinaryError>(Args: "invalid tag export",
1482 Args: object_error::parse_failed);
1483 Info.Kind = wasm::WASM_SYMBOL_TYPE_TAG;
1484 Info.ElementIndex = Ex.Index;
1485 break;
1486 case wasm::WASM_EXTERNAL_MEMORY:
1487 break;
1488 case wasm::WASM_EXTERNAL_TABLE:
1489 Info.Kind = wasm::WASM_SYMBOL_TYPE_TABLE;
1490 Info.ElementIndex = Ex.Index;
1491 break;
1492 default:
1493 return make_error<GenericBinaryError>(Args: "unexpected export kind",
1494 Args: object_error::parse_failed);
1495 }
1496 Exports.push_back(x: Ex);
1497 if (Ex.Kind != wasm::WASM_EXTERNAL_MEMORY) {
1498 Symbols.emplace_back(args&: Info, args&: GlobalType, args&: TableType, args&: Signature);
1499 LLVM_DEBUG(dbgs() << "Adding symbol: " << Symbols.back() << "\n");
1500 }
1501 }
1502 if (Ctx.Ptr != Ctx.End)
1503 return make_error<GenericBinaryError>(Args: "export section ended prematurely",
1504 Args: object_error::parse_failed);
1505 return Error::success();
1506}
1507
1508bool WasmObjectFile::isValidFunctionIndex(uint32_t Index) const {
1509 return Index < NumImportedFunctions + Functions.size();
1510}
1511
1512bool WasmObjectFile::isDefinedFunctionIndex(uint32_t Index) const {
1513 return Index >= NumImportedFunctions && isValidFunctionIndex(Index);
1514}
1515
1516bool WasmObjectFile::isValidGlobalIndex(uint32_t Index) const {
1517 return Index < NumImportedGlobals + Globals.size();
1518}
1519
1520bool WasmObjectFile::isValidTableNumber(uint32_t Index) const {
1521 return Index < NumImportedTables + Tables.size();
1522}
1523
1524bool WasmObjectFile::isDefinedGlobalIndex(uint32_t Index) const {
1525 return Index >= NumImportedGlobals && isValidGlobalIndex(Index);
1526}
1527
1528bool WasmObjectFile::isDefinedTableNumber(uint32_t Index) const {
1529 return Index >= NumImportedTables && isValidTableNumber(Index);
1530}
1531
1532bool WasmObjectFile::isValidTagIndex(uint32_t Index) const {
1533 return Index < NumImportedTags + Tags.size();
1534}
1535
1536bool WasmObjectFile::isDefinedTagIndex(uint32_t Index) const {
1537 return Index >= NumImportedTags && isValidTagIndex(Index);
1538}
1539
1540bool WasmObjectFile::isValidFunctionSymbol(uint32_t Index) const {
1541 return Index < Symbols.size() && Symbols[Index].isTypeFunction();
1542}
1543
1544bool WasmObjectFile::isValidTableSymbol(uint32_t Index) const {
1545 return Index < Symbols.size() && Symbols[Index].isTypeTable();
1546}
1547
1548bool WasmObjectFile::isValidGlobalSymbol(uint32_t Index) const {
1549 return Index < Symbols.size() && Symbols[Index].isTypeGlobal();
1550}
1551
1552bool WasmObjectFile::isValidTagSymbol(uint32_t Index) const {
1553 return Index < Symbols.size() && Symbols[Index].isTypeTag();
1554}
1555
1556bool WasmObjectFile::isValidDataSymbol(uint32_t Index) const {
1557 return Index < Symbols.size() && Symbols[Index].isTypeData();
1558}
1559
1560bool WasmObjectFile::isValidSectionSymbol(uint32_t Index) const {
1561 return Index < Symbols.size() && Symbols[Index].isTypeSection();
1562}
1563
1564wasm::WasmFunction &WasmObjectFile::getDefinedFunction(uint32_t Index) {
1565 assert(isDefinedFunctionIndex(Index));
1566 return Functions[Index - NumImportedFunctions];
1567}
1568
1569const wasm::WasmFunction &
1570WasmObjectFile::getDefinedFunction(uint32_t Index) const {
1571 assert(isDefinedFunctionIndex(Index));
1572 return Functions[Index - NumImportedFunctions];
1573}
1574
1575const wasm::WasmGlobal &WasmObjectFile::getDefinedGlobal(uint32_t Index) const {
1576 assert(isDefinedGlobalIndex(Index));
1577 return Globals[Index - NumImportedGlobals];
1578}
1579
1580wasm::WasmTag &WasmObjectFile::getDefinedTag(uint32_t Index) {
1581 assert(isDefinedTagIndex(Index));
1582 return Tags[Index - NumImportedTags];
1583}
1584
1585Error WasmObjectFile::parseStartSection(ReadContext &Ctx) {
1586 StartFunction = readVaruint32(Ctx);
1587 if (!isValidFunctionIndex(Index: StartFunction))
1588 return make_error<GenericBinaryError>(Args: "invalid start function",
1589 Args: object_error::parse_failed);
1590 return Error::success();
1591}
1592
1593Error WasmObjectFile::parseCodeSection(ReadContext &Ctx) {
1594 CodeSection = Sections.size();
1595 uint32_t FunctionCount = readVaruint32(Ctx);
1596 if (FunctionCount != Functions.size()) {
1597 return make_error<GenericBinaryError>(Args: "invalid function count",
1598 Args: object_error::parse_failed);
1599 }
1600
1601 for (uint32_t i = 0; i < FunctionCount; i++) {
1602 wasm::WasmFunction& Function = Functions[i];
1603 const uint8_t *FunctionStart = Ctx.Ptr;
1604 uint32_t Size = readVaruint32(Ctx);
1605 const uint8_t *FunctionEnd = Ctx.Ptr + Size;
1606
1607 Function.CodeOffset = Ctx.Ptr - FunctionStart;
1608 Function.Index = NumImportedFunctions + i;
1609 Function.CodeSectionOffset = FunctionStart - Ctx.Start;
1610 Function.Size = FunctionEnd - FunctionStart;
1611
1612 uint32_t NumLocalDecls = readVaruint32(Ctx);
1613 Function.Locals.reserve(n: NumLocalDecls);
1614 while (NumLocalDecls--) {
1615 wasm::WasmLocalDecl Decl;
1616 Decl.Count = readVaruint32(Ctx);
1617 Decl.Type = readUint8(Ctx);
1618 Function.Locals.push_back(x: Decl);
1619 }
1620
1621 uint32_t BodySize = FunctionEnd - Ctx.Ptr;
1622 // Ensure that Function is within Ctx's buffer.
1623 if (Ctx.Ptr + BodySize > Ctx.End) {
1624 return make_error<GenericBinaryError>(Args: "Function extends beyond buffer",
1625 Args: object_error::parse_failed);
1626 }
1627 Function.Body = ArrayRef<uint8_t>(Ctx.Ptr, BodySize);
1628 // This will be set later when reading in the linking metadata section.
1629 Function.Comdat = UINT32_MAX;
1630 Ctx.Ptr += BodySize;
1631 assert(Ctx.Ptr == FunctionEnd);
1632 }
1633 if (Ctx.Ptr != Ctx.End)
1634 return make_error<GenericBinaryError>(Args: "code section ended prematurely",
1635 Args: object_error::parse_failed);
1636 return Error::success();
1637}
1638
1639Error WasmObjectFile::parseElemSection(ReadContext &Ctx) {
1640 uint32_t Count = readVaruint32(Ctx);
1641 ElemSegments.reserve(n: Count);
1642 while (Count--) {
1643 wasm::WasmElemSegment Segment;
1644 Segment.Flags = readVaruint32(Ctx);
1645
1646 uint32_t SupportedFlags = wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER |
1647 wasm::WASM_ELEM_SEGMENT_IS_PASSIVE |
1648 wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS;
1649 if (Segment.Flags & ~SupportedFlags)
1650 return make_error<GenericBinaryError>(
1651 Args: "Unsupported flags for element segment", Args: object_error::parse_failed);
1652
1653 bool IsPassive = (Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_PASSIVE) != 0;
1654 bool IsDeclarative =
1655 IsPassive && (Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_DECLARATIVE);
1656 bool HasTableNumber =
1657 !IsPassive &&
1658 (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER);
1659 bool HasInitExprs =
1660 (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS);
1661 bool HasElemKind =
1662 (Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND) &&
1663 !HasInitExprs;
1664
1665 if (HasTableNumber)
1666 Segment.TableNumber = readVaruint32(Ctx);
1667 else
1668 Segment.TableNumber = 0;
1669
1670 if (!isValidTableNumber(Index: Segment.TableNumber))
1671 return make_error<GenericBinaryError>(Args: "invalid TableNumber",
1672 Args: object_error::parse_failed);
1673
1674 if (IsPassive || IsDeclarative) {
1675 Segment.Offset.Extended = false;
1676 Segment.Offset.Inst.Opcode = wasm::WASM_OPCODE_I32_CONST;
1677 Segment.Offset.Inst.Value.Int32 = 0;
1678 } else {
1679 if (Error Err = readInitExpr(Expr&: Segment.Offset, Ctx))
1680 return Err;
1681 }
1682
1683 if (HasElemKind) {
1684 auto ElemKind = readVaruint32(Ctx);
1685 if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS) {
1686 Segment.ElemKind = parseValType(Ctx, Code: ElemKind);
1687 if (Segment.ElemKind != wasm::ValType::FUNCREF &&
1688 Segment.ElemKind != wasm::ValType::EXTERNREF &&
1689 Segment.ElemKind != wasm::ValType::EXNREF &&
1690 Segment.ElemKind != wasm::ValType::OTHERREF) {
1691 return make_error<GenericBinaryError>(Args: "invalid elem type",
1692 Args: object_error::parse_failed);
1693 }
1694 } else {
1695 if (ElemKind != 0)
1696 return make_error<GenericBinaryError>(Args: "invalid elem type",
1697 Args: object_error::parse_failed);
1698 Segment.ElemKind = wasm::ValType::FUNCREF;
1699 }
1700 } else if (HasInitExprs) {
1701 auto ElemType = parseValType(Ctx, Code: readVaruint32(Ctx));
1702 Segment.ElemKind = ElemType;
1703 } else {
1704 Segment.ElemKind = wasm::ValType::FUNCREF;
1705 }
1706
1707 uint32_t NumElems = readVaruint32(Ctx);
1708
1709 if (HasInitExprs) {
1710 while (NumElems--) {
1711 wasm::WasmInitExpr Expr;
1712 if (Error Err = readInitExpr(Expr, Ctx))
1713 return Err;
1714 }
1715 } else {
1716 while (NumElems--) {
1717 Segment.Functions.push_back(x: readVaruint32(Ctx));
1718 }
1719 }
1720 ElemSegments.push_back(x: Segment);
1721 }
1722 if (Ctx.Ptr != Ctx.End)
1723 return make_error<GenericBinaryError>(Args: "elem section ended prematurely",
1724 Args: object_error::parse_failed);
1725 return Error::success();
1726}
1727
1728Error WasmObjectFile::parseDataSection(ReadContext &Ctx) {
1729 DataSection = Sections.size();
1730 uint32_t Count = readVaruint32(Ctx);
1731 if (DataCount && Count != *DataCount)
1732 return make_error<GenericBinaryError>(
1733 Args: "number of data segments does not match DataCount section");
1734 DataSegments.reserve(n: Count);
1735 while (Count--) {
1736 WasmSegment Segment;
1737 Segment.Data.InitFlags = readVaruint32(Ctx);
1738 Segment.Data.MemoryIndex =
1739 (Segment.Data.InitFlags & wasm::WASM_DATA_SEGMENT_HAS_MEMINDEX)
1740 ? readVaruint32(Ctx)
1741 : 0;
1742 if ((Segment.Data.InitFlags & wasm::WASM_DATA_SEGMENT_IS_PASSIVE) == 0) {
1743 if (Error Err = readInitExpr(Expr&: Segment.Data.Offset, Ctx))
1744 return Err;
1745 } else {
1746 Segment.Data.Offset.Extended = false;
1747 Segment.Data.Offset.Inst.Opcode = wasm::WASM_OPCODE_I32_CONST;
1748 Segment.Data.Offset.Inst.Value.Int32 = 0;
1749 }
1750 uint32_t Size = readVaruint32(Ctx);
1751 if (Size > (size_t)(Ctx.End - Ctx.Ptr))
1752 return make_error<GenericBinaryError>(Args: "invalid segment size",
1753 Args: object_error::parse_failed);
1754 Segment.Data.Content = ArrayRef<uint8_t>(Ctx.Ptr, Size);
1755 // The rest of these Data fields are set later, when reading in the linking
1756 // metadata section.
1757 Segment.Data.Alignment = 0;
1758 Segment.Data.LinkingFlags = 0;
1759 Segment.Data.Comdat = UINT32_MAX;
1760 Segment.SectionOffset = Ctx.Ptr - Ctx.Start;
1761 Ctx.Ptr += Size;
1762 DataSegments.push_back(x: Segment);
1763 }
1764 if (Ctx.Ptr != Ctx.End)
1765 return make_error<GenericBinaryError>(Args: "data section ended prematurely",
1766 Args: object_error::parse_failed);
1767 return Error::success();
1768}
1769
1770Error WasmObjectFile::parseDataCountSection(ReadContext &Ctx) {
1771 DataCount = readVaruint32(Ctx);
1772 return Error::success();
1773}
1774
1775const wasm::WasmObjectHeader &WasmObjectFile::getHeader() const {
1776 return Header;
1777}
1778
1779void WasmObjectFile::moveSymbolNext(DataRefImpl &Symb) const { Symb.d.b++; }
1780
1781Expected<uint32_t> WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const {
1782 uint32_t Result = SymbolRef::SF_None;
1783 const WasmSymbol &Sym = getWasmSymbol(Symb);
1784
1785 LLVM_DEBUG(dbgs() << "getSymbolFlags: ptr=" << &Sym << " " << Sym << "\n");
1786 if (Sym.isBindingWeak())
1787 Result |= SymbolRef::SF_Weak;
1788 if (!Sym.isBindingLocal())
1789 Result |= SymbolRef::SF_Global;
1790 if (Sym.isHidden())
1791 Result |= SymbolRef::SF_Hidden;
1792 if (!Sym.isDefined())
1793 Result |= SymbolRef::SF_Undefined;
1794 if (Sym.isTypeFunction())
1795 Result |= SymbolRef::SF_Executable;
1796 return Result;
1797}
1798
1799basic_symbol_iterator WasmObjectFile::symbol_begin() const {
1800 DataRefImpl Ref;
1801 Ref.d.a = 1; // Arbitrary non-zero value so that Ref.p is non-null
1802 Ref.d.b = 0; // Symbol index
1803 return BasicSymbolRef(Ref, this);
1804}
1805
1806basic_symbol_iterator WasmObjectFile::symbol_end() const {
1807 DataRefImpl Ref;
1808 Ref.d.a = 1; // Arbitrary non-zero value so that Ref.p is non-null
1809 Ref.d.b = Symbols.size(); // Symbol index
1810 return BasicSymbolRef(Ref, this);
1811}
1812
1813const WasmSymbol &WasmObjectFile::getWasmSymbol(const DataRefImpl &Symb) const {
1814 return Symbols[Symb.d.b];
1815}
1816
1817const WasmSymbol &WasmObjectFile::getWasmSymbol(const SymbolRef &Symb) const {
1818 return getWasmSymbol(Symb: Symb.getRawDataRefImpl());
1819}
1820
1821Expected<StringRef> WasmObjectFile::getSymbolName(DataRefImpl Symb) const {
1822 return getWasmSymbol(Symb).Info.Name;
1823}
1824
1825Expected<uint64_t> WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const {
1826 auto &Sym = getWasmSymbol(Symb);
1827 if (!Sym.isDefined())
1828 return 0;
1829 Expected<section_iterator> Sec = getSymbolSection(Symb);
1830 if (!Sec)
1831 return Sec.takeError();
1832 uint32_t SectionAddress = getSectionAddress(Sec: Sec.get()->getRawDataRefImpl());
1833 if (Sym.Info.Kind == wasm::WASM_SYMBOL_TYPE_FUNCTION &&
1834 isDefinedFunctionIndex(Index: Sym.Info.ElementIndex)) {
1835 return getDefinedFunction(Index: Sym.Info.ElementIndex).CodeSectionOffset +
1836 SectionAddress;
1837 }
1838 if (Sym.Info.Kind == wasm::WASM_SYMBOL_TYPE_GLOBAL &&
1839 isDefinedGlobalIndex(Index: Sym.Info.ElementIndex)) {
1840 return getDefinedGlobal(Index: Sym.Info.ElementIndex).Offset + SectionAddress;
1841 }
1842
1843 return getSymbolValue(Symb);
1844}
1845
1846uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol &Sym) const {
1847 switch (Sym.Info.Kind) {
1848 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1849 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1850 case wasm::WASM_SYMBOL_TYPE_TAG:
1851 case wasm::WASM_SYMBOL_TYPE_TABLE:
1852 return Sym.Info.ElementIndex;
1853 case wasm::WASM_SYMBOL_TYPE_DATA: {
1854 // The value of a data symbol is the segment offset, plus the symbol
1855 // offset within the segment.
1856 uint32_t SegmentIndex = Sym.Info.DataRef.Segment;
1857 const wasm::WasmDataSegment &Segment = DataSegments[SegmentIndex].Data;
1858 if (Segment.Offset.Extended) {
1859 llvm_unreachable("extended init exprs not supported");
1860 } else if (Segment.Offset.Inst.Opcode == wasm::WASM_OPCODE_I32_CONST) {
1861 return Segment.Offset.Inst.Value.Int32 + Sym.Info.DataRef.Offset;
1862 } else if (Segment.Offset.Inst.Opcode == wasm::WASM_OPCODE_I64_CONST) {
1863 return Segment.Offset.Inst.Value.Int64 + Sym.Info.DataRef.Offset;
1864 } else if (Segment.Offset.Inst.Opcode == wasm::WASM_OPCODE_GLOBAL_GET) {
1865 return Sym.Info.DataRef.Offset;
1866 } else {
1867 llvm_unreachable("unknown init expr opcode");
1868 }
1869 }
1870 case wasm::WASM_SYMBOL_TYPE_SECTION:
1871 return 0;
1872 }
1873 llvm_unreachable("invalid symbol type");
1874}
1875
1876uint64_t WasmObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
1877 return getWasmSymbolValue(Sym: getWasmSymbol(Symb));
1878}
1879
1880uint32_t WasmObjectFile::getSymbolAlignment(DataRefImpl Symb) const {
1881 llvm_unreachable("not yet implemented");
1882 return 0;
1883}
1884
1885uint64_t WasmObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
1886 llvm_unreachable("not yet implemented");
1887 return 0;
1888}
1889
1890Expected<SymbolRef::Type>
1891WasmObjectFile::getSymbolType(DataRefImpl Symb) const {
1892 const WasmSymbol &Sym = getWasmSymbol(Symb);
1893
1894 switch (Sym.Info.Kind) {
1895 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1896 return SymbolRef::ST_Function;
1897 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1898 return SymbolRef::ST_Other;
1899 case wasm::WASM_SYMBOL_TYPE_DATA:
1900 return SymbolRef::ST_Data;
1901 case wasm::WASM_SYMBOL_TYPE_SECTION:
1902 return SymbolRef::ST_Debug;
1903 case wasm::WASM_SYMBOL_TYPE_TAG:
1904 return SymbolRef::ST_Other;
1905 case wasm::WASM_SYMBOL_TYPE_TABLE:
1906 return SymbolRef::ST_Other;
1907 }
1908
1909 llvm_unreachable("unknown WasmSymbol::SymbolType");
1910 return SymbolRef::ST_Other;
1911}
1912
1913Expected<section_iterator>
1914WasmObjectFile::getSymbolSection(DataRefImpl Symb) const {
1915 const WasmSymbol &Sym = getWasmSymbol(Symb);
1916 if (Sym.isUndefined())
1917 return section_end();
1918
1919 DataRefImpl Ref;
1920 Ref.d.a = getSymbolSectionIdImpl(Symb: Sym);
1921 return section_iterator(SectionRef(Ref, this));
1922}
1923
1924uint32_t WasmObjectFile::getSymbolSectionId(SymbolRef Symb) const {
1925 const WasmSymbol &Sym = getWasmSymbol(Symb);
1926 return getSymbolSectionIdImpl(Symb: Sym);
1927}
1928
1929uint32_t WasmObjectFile::getSymbolSectionIdImpl(const WasmSymbol &Sym) const {
1930 switch (Sym.Info.Kind) {
1931 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1932 return CodeSection;
1933 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1934 return GlobalSection;
1935 case wasm::WASM_SYMBOL_TYPE_DATA:
1936 return DataSection;
1937 case wasm::WASM_SYMBOL_TYPE_SECTION:
1938 return Sym.Info.ElementIndex;
1939 case wasm::WASM_SYMBOL_TYPE_TAG:
1940 return TagSection;
1941 case wasm::WASM_SYMBOL_TYPE_TABLE:
1942 return TableSection;
1943 default:
1944 llvm_unreachable("unknown WasmSymbol::SymbolType");
1945 }
1946}
1947
1948uint32_t WasmObjectFile::getSymbolSize(SymbolRef Symb) const {
1949 const WasmSymbol &Sym = getWasmSymbol(Symb);
1950 if (!Sym.isDefined())
1951 return 0;
1952 if (Sym.isTypeGlobal())
1953 return getDefinedGlobal(Index: Sym.Info.ElementIndex).Size;
1954 if (Sym.isTypeData())
1955 return Sym.Info.DataRef.Size;
1956 if (Sym.isTypeFunction())
1957 return functions()[Sym.Info.ElementIndex - getNumImportedFunctions()].Size;
1958 // Currently symbol size is only tracked for data segments and functions. In
1959 // principle we could also track size (e.g. binary size) for tables, globals
1960 // and element segments etc too.
1961 return 0;
1962}
1963
1964void WasmObjectFile::moveSectionNext(DataRefImpl &Sec) const { Sec.d.a++; }
1965
1966Expected<StringRef> WasmObjectFile::getSectionName(DataRefImpl Sec) const {
1967 const WasmSection &S = Sections[Sec.d.a];
1968 if (S.Type == wasm::WASM_SEC_CUSTOM)
1969 return S.Name;
1970 if (S.Type > wasm::WASM_SEC_LAST_KNOWN)
1971 return createStringError(EC: object_error::invalid_section_index, S: "");
1972 return wasm::sectionTypeToString(type: S.Type);
1973}
1974
1975uint64_t WasmObjectFile::getSectionAddress(DataRefImpl Sec) const {
1976 // For object files, use 0 for section addresses, and section offsets for
1977 // symbol addresses. For linked files, use file offsets.
1978 // See also getSymbolAddress.
1979 return isRelocatableObject() || isSharedObject() ? 0
1980 : Sections[Sec.d.a].Offset;
1981}
1982
1983uint64_t WasmObjectFile::getSectionIndex(DataRefImpl Sec) const {
1984 return Sec.d.a;
1985}
1986
1987uint64_t WasmObjectFile::getSectionSize(DataRefImpl Sec) const {
1988 const WasmSection &S = Sections[Sec.d.a];
1989 return S.Content.size();
1990}
1991
1992Expected<ArrayRef<uint8_t>>
1993WasmObjectFile::getSectionContents(DataRefImpl Sec) const {
1994 const WasmSection &S = Sections[Sec.d.a];
1995 // This will never fail since wasm sections can never be empty (user-sections
1996 // must have a name and non-user sections each have a defined structure).
1997 return S.Content;
1998}
1999
2000uint64_t WasmObjectFile::getSectionAlignment(DataRefImpl Sec) const {
2001 return 1;
2002}
2003
2004bool WasmObjectFile::isSectionCompressed(DataRefImpl Sec) const {
2005 return false;
2006}
2007
2008bool WasmObjectFile::isSectionText(DataRefImpl Sec) const {
2009 return getWasmSection(Ref: Sec).Type == wasm::WASM_SEC_CODE;
2010}
2011
2012bool WasmObjectFile::isSectionData(DataRefImpl Sec) const {
2013 return getWasmSection(Ref: Sec).Type == wasm::WASM_SEC_DATA;
2014}
2015
2016bool WasmObjectFile::isSectionBSS(DataRefImpl Sec) const { return false; }
2017
2018bool WasmObjectFile::isSectionVirtual(DataRefImpl Sec) const { return false; }
2019
2020relocation_iterator WasmObjectFile::section_rel_begin(DataRefImpl Ref) const {
2021 DataRefImpl RelocRef;
2022 RelocRef.d.a = Ref.d.a;
2023 RelocRef.d.b = 0;
2024 return relocation_iterator(RelocationRef(RelocRef, this));
2025}
2026
2027relocation_iterator WasmObjectFile::section_rel_end(DataRefImpl Ref) const {
2028 const WasmSection &Sec = getWasmSection(Ref);
2029 DataRefImpl RelocRef;
2030 RelocRef.d.a = Ref.d.a;
2031 RelocRef.d.b = Sec.Relocations.size();
2032 return relocation_iterator(RelocationRef(RelocRef, this));
2033}
2034
2035void WasmObjectFile::moveRelocationNext(DataRefImpl &Rel) const { Rel.d.b++; }
2036
2037uint64_t WasmObjectFile::getRelocationOffset(DataRefImpl Ref) const {
2038 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
2039 return Rel.Offset;
2040}
2041
2042symbol_iterator WasmObjectFile::getRelocationSymbol(DataRefImpl Ref) const {
2043 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
2044 if (Rel.Type == wasm::R_WASM_TYPE_INDEX_LEB)
2045 return symbol_end();
2046 DataRefImpl Sym;
2047 Sym.d.a = 1;
2048 Sym.d.b = Rel.Index;
2049 return symbol_iterator(SymbolRef(Sym, this));
2050}
2051
2052uint64_t WasmObjectFile::getRelocationType(DataRefImpl Ref) const {
2053 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
2054 return Rel.Type;
2055}
2056
2057void WasmObjectFile::getRelocationTypeName(
2058 DataRefImpl Ref, SmallVectorImpl<char> &Result) const {
2059 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
2060 StringRef Res = "Unknown";
2061
2062#define WASM_RELOC(name, value) \
2063 case wasm::name: \
2064 Res = #name; \
2065 break;
2066
2067 switch (Rel.Type) {
2068#include "llvm/BinaryFormat/WasmRelocs.def"
2069 }
2070
2071#undef WASM_RELOC
2072
2073 Result.append(in_start: Res.begin(), in_end: Res.end());
2074}
2075
2076section_iterator WasmObjectFile::section_begin() const {
2077 DataRefImpl Ref;
2078 Ref.d.a = 0;
2079 return section_iterator(SectionRef(Ref, this));
2080}
2081
2082section_iterator WasmObjectFile::section_end() const {
2083 DataRefImpl Ref;
2084 Ref.d.a = Sections.size();
2085 return section_iterator(SectionRef(Ref, this));
2086}
2087
2088uint8_t WasmObjectFile::getBytesInAddress() const {
2089 return HasMemory64 ? 8 : 4;
2090}
2091
2092StringRef WasmObjectFile::getFileFormatName() const { return "WASM"; }
2093
2094Triple::ArchType WasmObjectFile::getArch() const {
2095 return HasMemory64 ? Triple::wasm64 : Triple::wasm32;
2096}
2097
2098Expected<SubtargetFeatures> WasmObjectFile::getFeatures() const {
2099 return SubtargetFeatures();
2100}
2101
2102bool WasmObjectFile::isRelocatableObject() const { return HasLinkingSection; }
2103
2104bool WasmObjectFile::isSharedObject() const { return HasDylinkSection; }
2105
2106const WasmSection &WasmObjectFile::getWasmSection(DataRefImpl Ref) const {
2107 assert(Ref.d.a < Sections.size());
2108 return Sections[Ref.d.a];
2109}
2110
2111const WasmSection &
2112WasmObjectFile::getWasmSection(const SectionRef &Section) const {
2113 return getWasmSection(Ref: Section.getRawDataRefImpl());
2114}
2115
2116const wasm::WasmRelocation &
2117WasmObjectFile::getWasmRelocation(const RelocationRef &Ref) const {
2118 return getWasmRelocation(Ref: Ref.getRawDataRefImpl());
2119}
2120
2121const wasm::WasmRelocation &
2122WasmObjectFile::getWasmRelocation(DataRefImpl Ref) const {
2123 assert(Ref.d.a < Sections.size());
2124 const WasmSection &Sec = Sections[Ref.d.a];
2125 assert(Ref.d.b < Sec.Relocations.size());
2126 return Sec.Relocations[Ref.d.b];
2127}
2128
2129int WasmSectionOrderChecker::getSectionOrder(unsigned ID,
2130 StringRef CustomSectionName) {
2131 switch (ID) {
2132 case wasm::WASM_SEC_CUSTOM:
2133 return StringSwitch<unsigned>(CustomSectionName)
2134 .Case(S: "dylink", Value: WASM_SEC_ORDER_DYLINK)
2135 .Case(S: "dylink.0", Value: WASM_SEC_ORDER_DYLINK)
2136 .Case(S: "linking", Value: WASM_SEC_ORDER_LINKING)
2137 .StartsWith(S: "reloc.", Value: WASM_SEC_ORDER_RELOC)
2138 .Case(S: "name", Value: WASM_SEC_ORDER_NAME)
2139 .Case(S: "producers", Value: WASM_SEC_ORDER_PRODUCERS)
2140 .Case(S: "target_features", Value: WASM_SEC_ORDER_TARGET_FEATURES)
2141 .Default(Value: WASM_SEC_ORDER_NONE);
2142 case wasm::WASM_SEC_TYPE:
2143 return WASM_SEC_ORDER_TYPE;
2144 case wasm::WASM_SEC_IMPORT:
2145 return WASM_SEC_ORDER_IMPORT;
2146 case wasm::WASM_SEC_FUNCTION:
2147 return WASM_SEC_ORDER_FUNCTION;
2148 case wasm::WASM_SEC_TABLE:
2149 return WASM_SEC_ORDER_TABLE;
2150 case wasm::WASM_SEC_MEMORY:
2151 return WASM_SEC_ORDER_MEMORY;
2152 case wasm::WASM_SEC_GLOBAL:
2153 return WASM_SEC_ORDER_GLOBAL;
2154 case wasm::WASM_SEC_EXPORT:
2155 return WASM_SEC_ORDER_EXPORT;
2156 case wasm::WASM_SEC_START:
2157 return WASM_SEC_ORDER_START;
2158 case wasm::WASM_SEC_ELEM:
2159 return WASM_SEC_ORDER_ELEM;
2160 case wasm::WASM_SEC_CODE:
2161 return WASM_SEC_ORDER_CODE;
2162 case wasm::WASM_SEC_DATA:
2163 return WASM_SEC_ORDER_DATA;
2164 case wasm::WASM_SEC_DATACOUNT:
2165 return WASM_SEC_ORDER_DATACOUNT;
2166 case wasm::WASM_SEC_TAG:
2167 return WASM_SEC_ORDER_TAG;
2168 default:
2169 return WASM_SEC_ORDER_NONE;
2170 }
2171}
2172
2173// Represents the edges in a directed graph where any node B reachable from node
2174// A is not allowed to appear before A in the section ordering, but may appear
2175// afterward.
2176int WasmSectionOrderChecker::DisallowedPredecessors
2177 [WASM_NUM_SEC_ORDERS][WASM_NUM_SEC_ORDERS] = {
2178 // WASM_SEC_ORDER_NONE
2179 {},
2180 // WASM_SEC_ORDER_TYPE
2181 {WASM_SEC_ORDER_TYPE, WASM_SEC_ORDER_IMPORT},
2182 // WASM_SEC_ORDER_IMPORT
2183 {WASM_SEC_ORDER_IMPORT, WASM_SEC_ORDER_FUNCTION},
2184 // WASM_SEC_ORDER_FUNCTION
2185 {WASM_SEC_ORDER_FUNCTION, WASM_SEC_ORDER_TABLE},
2186 // WASM_SEC_ORDER_TABLE
2187 {WASM_SEC_ORDER_TABLE, WASM_SEC_ORDER_MEMORY},
2188 // WASM_SEC_ORDER_MEMORY
2189 {WASM_SEC_ORDER_MEMORY, WASM_SEC_ORDER_TAG},
2190 // WASM_SEC_ORDER_TAG
2191 {WASM_SEC_ORDER_TAG, WASM_SEC_ORDER_GLOBAL},
2192 // WASM_SEC_ORDER_GLOBAL
2193 {WASM_SEC_ORDER_GLOBAL, WASM_SEC_ORDER_EXPORT},
2194 // WASM_SEC_ORDER_EXPORT
2195 {WASM_SEC_ORDER_EXPORT, WASM_SEC_ORDER_START},
2196 // WASM_SEC_ORDER_START
2197 {WASM_SEC_ORDER_START, WASM_SEC_ORDER_ELEM},
2198 // WASM_SEC_ORDER_ELEM
2199 {WASM_SEC_ORDER_ELEM, WASM_SEC_ORDER_DATACOUNT},
2200 // WASM_SEC_ORDER_DATACOUNT
2201 {WASM_SEC_ORDER_DATACOUNT, WASM_SEC_ORDER_CODE},
2202 // WASM_SEC_ORDER_CODE
2203 {WASM_SEC_ORDER_CODE, WASM_SEC_ORDER_DATA},
2204 // WASM_SEC_ORDER_DATA
2205 {WASM_SEC_ORDER_DATA, WASM_SEC_ORDER_LINKING},
2206
2207 // Custom Sections
2208 // WASM_SEC_ORDER_DYLINK
2209 {WASM_SEC_ORDER_DYLINK, WASM_SEC_ORDER_TYPE},
2210 // WASM_SEC_ORDER_LINKING
2211 {WASM_SEC_ORDER_LINKING, WASM_SEC_ORDER_RELOC, WASM_SEC_ORDER_NAME},
2212 // WASM_SEC_ORDER_RELOC (can be repeated)
2213 {},
2214 // WASM_SEC_ORDER_NAME
2215 {WASM_SEC_ORDER_NAME, WASM_SEC_ORDER_PRODUCERS},
2216 // WASM_SEC_ORDER_PRODUCERS
2217 {WASM_SEC_ORDER_PRODUCERS, WASM_SEC_ORDER_TARGET_FEATURES},
2218 // WASM_SEC_ORDER_TARGET_FEATURES
2219 {WASM_SEC_ORDER_TARGET_FEATURES}};
2220
2221bool WasmSectionOrderChecker::isValidSectionOrder(unsigned ID,
2222 StringRef CustomSectionName) {
2223 int Order = getSectionOrder(ID, CustomSectionName);
2224 if (Order == WASM_SEC_ORDER_NONE)
2225 return true;
2226
2227 // Disallowed predecessors we need to check for
2228 SmallVector<int, WASM_NUM_SEC_ORDERS> WorkList;
2229
2230 // Keep track of completed checks to avoid repeating work
2231 bool Checked[WASM_NUM_SEC_ORDERS] = {};
2232
2233 int Curr = Order;
2234 while (true) {
2235 // Add new disallowed predecessors to work list
2236 for (size_t I = 0;; ++I) {
2237 int Next = DisallowedPredecessors[Curr][I];
2238 if (Next == WASM_SEC_ORDER_NONE)
2239 break;
2240 if (Checked[Next])
2241 continue;
2242 WorkList.push_back(Elt: Next);
2243 Checked[Next] = true;
2244 }
2245
2246 if (WorkList.empty())
2247 break;
2248
2249 // Consider next disallowed predecessor
2250 Curr = WorkList.pop_back_val();
2251 if (Seen[Curr])
2252 return false;
2253 }
2254
2255 // Have not seen any disallowed predecessors
2256 Seen[Order] = true;
2257 return true;
2258}
2259