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/STLExtras.h"
12 #include "llvm/ADT/SmallSet.h"
13 #include "llvm/ADT/StringRef.h"
14 #include "llvm/ADT/StringSet.h"
15 #include "llvm/ADT/StringSwitch.h"
16 #include "llvm/ADT/Triple.h"
17 #include "llvm/BinaryFormat/Wasm.h"
18 #include "llvm/MC/SubtargetFeature.h"
19 #include "llvm/Object/Binary.h"
20 #include "llvm/Object/Error.h"
21 #include "llvm/Object/ObjectFile.h"
22 #include "llvm/Object/SymbolicFile.h"
23 #include "llvm/Object/Wasm.h"
24 #include "llvm/Support/Endian.h"
25 #include "llvm/Support/Error.h"
26 #include "llvm/Support/ErrorHandling.h"
27 #include "llvm/Support/LEB128.h"
28 #include "llvm/Support/ScopedPrinter.h"
29 #include <algorithm>
30 #include <cassert>
31 #include <cstdint>
32 #include <cstring>
33 #include <system_error>
34
35 #define DEBUG_TYPE "wasm-object"
36
37 using namespace llvm;
38 using namespace object;
39
print(raw_ostream & Out) const40 void WasmSymbol::print(raw_ostream &Out) const {
41 Out << "Name=" << Info.Name
42 << ", Kind=" << toString(wasm::WasmSymbolType(Info.Kind)) << ", Flags=0x"
43 << Twine::utohexstr(Info.Flags);
44 if (!isTypeData()) {
45 Out << ", ElemIndex=" << Info.ElementIndex;
46 } else if (isDefined()) {
47 Out << ", Segment=" << Info.DataRef.Segment;
48 Out << ", Offset=" << Info.DataRef.Offset;
49 Out << ", Size=" << Info.DataRef.Size;
50 }
51 }
52
53 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump() const54 LLVM_DUMP_METHOD void WasmSymbol::dump() const { print(dbgs()); }
55 #endif
56
57 Expected<std::unique_ptr<WasmObjectFile>>
createWasmObjectFile(MemoryBufferRef Buffer)58 ObjectFile::createWasmObjectFile(MemoryBufferRef Buffer) {
59 Error Err = Error::success();
60 auto ObjectFile = std::make_unique<WasmObjectFile>(Buffer, Err);
61 if (Err)
62 return std::move(Err);
63
64 return std::move(ObjectFile);
65 }
66
67 #define VARINT7_MAX ((1 << 7) - 1)
68 #define VARINT7_MIN (-(1 << 7))
69 #define VARUINT7_MAX (1 << 7)
70 #define VARUINT1_MAX (1)
71
readUint8(WasmObjectFile::ReadContext & Ctx)72 static uint8_t readUint8(WasmObjectFile::ReadContext &Ctx) {
73 if (Ctx.Ptr == Ctx.End)
74 report_fatal_error("EOF while reading uint8");
75 return *Ctx.Ptr++;
76 }
77
readUint32(WasmObjectFile::ReadContext & Ctx)78 static uint32_t readUint32(WasmObjectFile::ReadContext &Ctx) {
79 if (Ctx.Ptr + 4 > Ctx.End)
80 report_fatal_error("EOF while reading uint32");
81 uint32_t Result = support::endian::read32le(Ctx.Ptr);
82 Ctx.Ptr += 4;
83 return Result;
84 }
85
readFloat32(WasmObjectFile::ReadContext & Ctx)86 static int32_t readFloat32(WasmObjectFile::ReadContext &Ctx) {
87 if (Ctx.Ptr + 4 > Ctx.End)
88 report_fatal_error("EOF while reading float64");
89 int32_t Result = 0;
90 memcpy(&Result, Ctx.Ptr, sizeof(Result));
91 Ctx.Ptr += sizeof(Result);
92 return Result;
93 }
94
readFloat64(WasmObjectFile::ReadContext & Ctx)95 static int64_t readFloat64(WasmObjectFile::ReadContext &Ctx) {
96 if (Ctx.Ptr + 8 > Ctx.End)
97 report_fatal_error("EOF while reading float64");
98 int64_t Result = 0;
99 memcpy(&Result, Ctx.Ptr, sizeof(Result));
100 Ctx.Ptr += sizeof(Result);
101 return Result;
102 }
103
readULEB128(WasmObjectFile::ReadContext & Ctx)104 static uint64_t readULEB128(WasmObjectFile::ReadContext &Ctx) {
105 unsigned Count;
106 const char *Error = nullptr;
107 uint64_t Result = decodeULEB128(Ctx.Ptr, &Count, Ctx.End, &Error);
108 if (Error)
109 report_fatal_error(Error);
110 Ctx.Ptr += Count;
111 return Result;
112 }
113
readString(WasmObjectFile::ReadContext & Ctx)114 static StringRef readString(WasmObjectFile::ReadContext &Ctx) {
115 uint32_t StringLen = readULEB128(Ctx);
116 if (Ctx.Ptr + StringLen > Ctx.End)
117 report_fatal_error("EOF while reading string");
118 StringRef Return =
119 StringRef(reinterpret_cast<const char *>(Ctx.Ptr), StringLen);
120 Ctx.Ptr += StringLen;
121 return Return;
122 }
123
readLEB128(WasmObjectFile::ReadContext & Ctx)124 static int64_t readLEB128(WasmObjectFile::ReadContext &Ctx) {
125 unsigned Count;
126 const char *Error = nullptr;
127 uint64_t Result = decodeSLEB128(Ctx.Ptr, &Count, Ctx.End, &Error);
128 if (Error)
129 report_fatal_error(Error);
130 Ctx.Ptr += Count;
131 return Result;
132 }
133
readVaruint1(WasmObjectFile::ReadContext & Ctx)134 static uint8_t readVaruint1(WasmObjectFile::ReadContext &Ctx) {
135 int64_t Result = readLEB128(Ctx);
136 if (Result > VARUINT1_MAX || Result < 0)
137 report_fatal_error("LEB is outside Varuint1 range");
138 return Result;
139 }
140
readVarint32(WasmObjectFile::ReadContext & Ctx)141 static int32_t readVarint32(WasmObjectFile::ReadContext &Ctx) {
142 int64_t Result = readLEB128(Ctx);
143 if (Result > INT32_MAX || Result < INT32_MIN)
144 report_fatal_error("LEB is outside Varint32 range");
145 return Result;
146 }
147
readVaruint32(WasmObjectFile::ReadContext & Ctx)148 static uint32_t readVaruint32(WasmObjectFile::ReadContext &Ctx) {
149 uint64_t Result = readULEB128(Ctx);
150 if (Result > UINT32_MAX)
151 report_fatal_error("LEB is outside Varuint32 range");
152 return Result;
153 }
154
readVarint64(WasmObjectFile::ReadContext & Ctx)155 static int64_t readVarint64(WasmObjectFile::ReadContext &Ctx) {
156 return readLEB128(Ctx);
157 }
158
readVaruint64(WasmObjectFile::ReadContext & Ctx)159 static uint64_t readVaruint64(WasmObjectFile::ReadContext &Ctx) {
160 return readULEB128(Ctx);
161 }
162
readOpcode(WasmObjectFile::ReadContext & Ctx)163 static uint8_t readOpcode(WasmObjectFile::ReadContext &Ctx) {
164 return readUint8(Ctx);
165 }
166
readInitExpr(wasm::WasmInitExpr & Expr,WasmObjectFile::ReadContext & Ctx)167 static Error readInitExpr(wasm::WasmInitExpr &Expr,
168 WasmObjectFile::ReadContext &Ctx) {
169 Expr.Opcode = readOpcode(Ctx);
170
171 switch (Expr.Opcode) {
172 case wasm::WASM_OPCODE_I32_CONST:
173 Expr.Value.Int32 = readVarint32(Ctx);
174 break;
175 case wasm::WASM_OPCODE_I64_CONST:
176 Expr.Value.Int64 = readVarint64(Ctx);
177 break;
178 case wasm::WASM_OPCODE_F32_CONST:
179 Expr.Value.Float32 = readFloat32(Ctx);
180 break;
181 case wasm::WASM_OPCODE_F64_CONST:
182 Expr.Value.Float64 = readFloat64(Ctx);
183 break;
184 case wasm::WASM_OPCODE_GLOBAL_GET:
185 Expr.Value.Global = readULEB128(Ctx);
186 break;
187 case wasm::WASM_OPCODE_REF_NULL: {
188 wasm::ValType Ty = static_cast<wasm::ValType>(readULEB128(Ctx));
189 if (Ty != wasm::ValType::EXTERNREF) {
190 return make_error<GenericBinaryError>("invalid type for ref.null",
191 object_error::parse_failed);
192 }
193 break;
194 }
195 default:
196 return make_error<GenericBinaryError>("invalid opcode in init_expr",
197 object_error::parse_failed);
198 }
199
200 uint8_t EndOpcode = readOpcode(Ctx);
201 if (EndOpcode != wasm::WASM_OPCODE_END) {
202 return make_error<GenericBinaryError>("invalid init_expr",
203 object_error::parse_failed);
204 }
205 return Error::success();
206 }
207
readLimits(WasmObjectFile::ReadContext & Ctx)208 static wasm::WasmLimits readLimits(WasmObjectFile::ReadContext &Ctx) {
209 wasm::WasmLimits Result;
210 Result.Flags = readVaruint32(Ctx);
211 Result.Minimum = readVaruint64(Ctx);
212 if (Result.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX)
213 Result.Maximum = readVaruint64(Ctx);
214 return Result;
215 }
216
readTableType(WasmObjectFile::ReadContext & Ctx)217 static wasm::WasmTableType readTableType(WasmObjectFile::ReadContext &Ctx) {
218 wasm::WasmTableType TableType;
219 TableType.ElemType = readUint8(Ctx);
220 TableType.Limits = readLimits(Ctx);
221 return TableType;
222 }
223
readSection(WasmSection & Section,WasmObjectFile::ReadContext & Ctx,WasmSectionOrderChecker & Checker)224 static Error readSection(WasmSection &Section, WasmObjectFile::ReadContext &Ctx,
225 WasmSectionOrderChecker &Checker) {
226 Section.Offset = Ctx.Ptr - Ctx.Start;
227 Section.Type = readUint8(Ctx);
228 LLVM_DEBUG(dbgs() << "readSection type=" << Section.Type << "\n");
229 uint32_t Size = readVaruint32(Ctx);
230 if (Size == 0)
231 return make_error<StringError>("zero length section",
232 object_error::parse_failed);
233 if (Ctx.Ptr + Size > Ctx.End)
234 return make_error<StringError>("section too large",
235 object_error::parse_failed);
236 if (Section.Type == wasm::WASM_SEC_CUSTOM) {
237 WasmObjectFile::ReadContext SectionCtx;
238 SectionCtx.Start = Ctx.Ptr;
239 SectionCtx.Ptr = Ctx.Ptr;
240 SectionCtx.End = Ctx.Ptr + Size;
241
242 Section.Name = readString(SectionCtx);
243
244 uint32_t SectionNameSize = SectionCtx.Ptr - SectionCtx.Start;
245 Ctx.Ptr += SectionNameSize;
246 Size -= SectionNameSize;
247 }
248
249 if (!Checker.isValidSectionOrder(Section.Type, Section.Name)) {
250 return make_error<StringError>("out of order section type: " +
251 llvm::to_string(Section.Type),
252 object_error::parse_failed);
253 }
254
255 Section.Content = ArrayRef<uint8_t>(Ctx.Ptr, Size);
256 Ctx.Ptr += Size;
257 return Error::success();
258 }
259
WasmObjectFile(MemoryBufferRef Buffer,Error & Err)260 WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err)
261 : ObjectFile(Binary::ID_Wasm, Buffer) {
262 ErrorAsOutParameter ErrAsOutParam(&Err);
263 Header.Magic = getData().substr(0, 4);
264 if (Header.Magic != StringRef("\0asm", 4)) {
265 Err = make_error<StringError>("invalid magic number",
266 object_error::parse_failed);
267 return;
268 }
269
270 ReadContext Ctx;
271 Ctx.Start = getData().bytes_begin();
272 Ctx.Ptr = Ctx.Start + 4;
273 Ctx.End = Ctx.Start + getData().size();
274
275 if (Ctx.Ptr + 4 > Ctx.End) {
276 Err = make_error<StringError>("missing version number",
277 object_error::parse_failed);
278 return;
279 }
280
281 Header.Version = readUint32(Ctx);
282 if (Header.Version != wasm::WasmVersion) {
283 Err = make_error<StringError>("invalid version number: " +
284 Twine(Header.Version),
285 object_error::parse_failed);
286 return;
287 }
288
289 WasmSection Sec;
290 WasmSectionOrderChecker Checker;
291 while (Ctx.Ptr < Ctx.End) {
292 if ((Err = readSection(Sec, Ctx, Checker)))
293 return;
294 if ((Err = parseSection(Sec)))
295 return;
296
297 Sections.push_back(Sec);
298 }
299 }
300
parseSection(WasmSection & Sec)301 Error WasmObjectFile::parseSection(WasmSection &Sec) {
302 ReadContext Ctx;
303 Ctx.Start = Sec.Content.data();
304 Ctx.End = Ctx.Start + Sec.Content.size();
305 Ctx.Ptr = Ctx.Start;
306 switch (Sec.Type) {
307 case wasm::WASM_SEC_CUSTOM:
308 return parseCustomSection(Sec, Ctx);
309 case wasm::WASM_SEC_TYPE:
310 return parseTypeSection(Ctx);
311 case wasm::WASM_SEC_IMPORT:
312 return parseImportSection(Ctx);
313 case wasm::WASM_SEC_FUNCTION:
314 return parseFunctionSection(Ctx);
315 case wasm::WASM_SEC_TABLE:
316 return parseTableSection(Ctx);
317 case wasm::WASM_SEC_MEMORY:
318 return parseMemorySection(Ctx);
319 case wasm::WASM_SEC_EVENT:
320 return parseEventSection(Ctx);
321 case wasm::WASM_SEC_GLOBAL:
322 return parseGlobalSection(Ctx);
323 case wasm::WASM_SEC_EXPORT:
324 return parseExportSection(Ctx);
325 case wasm::WASM_SEC_START:
326 return parseStartSection(Ctx);
327 case wasm::WASM_SEC_ELEM:
328 return parseElemSection(Ctx);
329 case wasm::WASM_SEC_CODE:
330 return parseCodeSection(Ctx);
331 case wasm::WASM_SEC_DATA:
332 return parseDataSection(Ctx);
333 case wasm::WASM_SEC_DATACOUNT:
334 return parseDataCountSection(Ctx);
335 default:
336 return make_error<GenericBinaryError>(
337 "invalid section type: " + Twine(Sec.Type), object_error::parse_failed);
338 }
339 }
340
parseDylinkSection(ReadContext & Ctx)341 Error WasmObjectFile::parseDylinkSection(ReadContext &Ctx) {
342 // See https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md
343 HasDylinkSection = true;
344 DylinkInfo.MemorySize = readVaruint32(Ctx);
345 DylinkInfo.MemoryAlignment = readVaruint32(Ctx);
346 DylinkInfo.TableSize = readVaruint32(Ctx);
347 DylinkInfo.TableAlignment = readVaruint32(Ctx);
348 uint32_t Count = readVaruint32(Ctx);
349 while (Count--) {
350 DylinkInfo.Needed.push_back(readString(Ctx));
351 }
352 if (Ctx.Ptr != Ctx.End)
353 return make_error<GenericBinaryError>("dylink section ended prematurely",
354 object_error::parse_failed);
355 return Error::success();
356 }
357
parseNameSection(ReadContext & Ctx)358 Error WasmObjectFile::parseNameSection(ReadContext &Ctx) {
359 llvm::DenseSet<uint64_t> SeenFunctions;
360 llvm::DenseSet<uint64_t> SeenGlobals;
361 llvm::DenseSet<uint64_t> SeenSegments;
362 if (FunctionTypes.size() && !SeenCodeSection) {
363 return make_error<GenericBinaryError>("names must come after code section",
364 object_error::parse_failed);
365 }
366
367 while (Ctx.Ptr < Ctx.End) {
368 uint8_t Type = readUint8(Ctx);
369 uint32_t Size = readVaruint32(Ctx);
370 const uint8_t *SubSectionEnd = Ctx.Ptr + Size;
371 switch (Type) {
372 case wasm::WASM_NAMES_FUNCTION:
373 case wasm::WASM_NAMES_GLOBAL:
374 case wasm::WASM_NAMES_DATA_SEGMENT: {
375 uint32_t Count = readVaruint32(Ctx);
376 while (Count--) {
377 uint32_t Index = readVaruint32(Ctx);
378 StringRef Name = readString(Ctx);
379 wasm::NameType nameType = wasm::NameType::FUNCTION;
380 if (Type == wasm::WASM_NAMES_FUNCTION) {
381 if (!SeenFunctions.insert(Index).second)
382 return make_error<GenericBinaryError>(
383 "function named more than once", object_error::parse_failed);
384 if (!isValidFunctionIndex(Index) || Name.empty())
385 return make_error<GenericBinaryError>("invalid name entry",
386 object_error::parse_failed);
387
388 if (isDefinedFunctionIndex(Index))
389 getDefinedFunction(Index).DebugName = Name;
390 } else if (Type == wasm::WASM_NAMES_GLOBAL) {
391 nameType = wasm::NameType::GLOBAL;
392 if (!SeenGlobals.insert(Index).second)
393 return make_error<GenericBinaryError>("global named more than once",
394 object_error::parse_failed);
395 if (!isValidGlobalIndex(Index) || Name.empty())
396 return make_error<GenericBinaryError>("invalid name entry",
397 object_error::parse_failed);
398 } else {
399 nameType = wasm::NameType::DATA_SEGMENT;
400 if (!SeenSegments.insert(Index).second)
401 return make_error<GenericBinaryError>(
402 "segment named more than once", object_error::parse_failed);
403 if (Index > DataSegments.size())
404 return make_error<GenericBinaryError>("invalid named data segment",
405 object_error::parse_failed);
406 }
407 DebugNames.push_back(wasm::WasmDebugName{nameType, Index, Name});
408 }
409 break;
410 }
411 // Ignore local names for now
412 case wasm::WASM_NAMES_LOCAL:
413 default:
414 Ctx.Ptr += Size;
415 break;
416 }
417 if (Ctx.Ptr != SubSectionEnd)
418 return make_error<GenericBinaryError>(
419 "name sub-section ended prematurely", object_error::parse_failed);
420 }
421
422 if (Ctx.Ptr != Ctx.End)
423 return make_error<GenericBinaryError>("name section ended prematurely",
424 object_error::parse_failed);
425 return Error::success();
426 }
427
parseLinkingSection(ReadContext & Ctx)428 Error WasmObjectFile::parseLinkingSection(ReadContext &Ctx) {
429 HasLinkingSection = true;
430 if (FunctionTypes.size() && !SeenCodeSection) {
431 return make_error<GenericBinaryError>(
432 "linking data must come after code section",
433 object_error::parse_failed);
434 }
435
436 LinkingData.Version = readVaruint32(Ctx);
437 if (LinkingData.Version != wasm::WasmMetadataVersion) {
438 return make_error<GenericBinaryError>(
439 "unexpected metadata version: " + Twine(LinkingData.Version) +
440 " (Expected: " + Twine(wasm::WasmMetadataVersion) + ")",
441 object_error::parse_failed);
442 }
443
444 const uint8_t *OrigEnd = Ctx.End;
445 while (Ctx.Ptr < OrigEnd) {
446 Ctx.End = OrigEnd;
447 uint8_t Type = readUint8(Ctx);
448 uint32_t Size = readVaruint32(Ctx);
449 LLVM_DEBUG(dbgs() << "readSubsection type=" << int(Type) << " size=" << Size
450 << "\n");
451 Ctx.End = Ctx.Ptr + Size;
452 switch (Type) {
453 case wasm::WASM_SYMBOL_TABLE:
454 if (Error Err = parseLinkingSectionSymtab(Ctx))
455 return Err;
456 break;
457 case wasm::WASM_SEGMENT_INFO: {
458 uint32_t Count = readVaruint32(Ctx);
459 if (Count > DataSegments.size())
460 return make_error<GenericBinaryError>("too many segment names",
461 object_error::parse_failed);
462 for (uint32_t I = 0; I < Count; I++) {
463 DataSegments[I].Data.Name = readString(Ctx);
464 DataSegments[I].Data.Alignment = readVaruint32(Ctx);
465 DataSegments[I].Data.LinkingFlags = readVaruint32(Ctx);
466 }
467 break;
468 }
469 case wasm::WASM_INIT_FUNCS: {
470 uint32_t Count = readVaruint32(Ctx);
471 LinkingData.InitFunctions.reserve(Count);
472 for (uint32_t I = 0; I < Count; I++) {
473 wasm::WasmInitFunc Init;
474 Init.Priority = readVaruint32(Ctx);
475 Init.Symbol = readVaruint32(Ctx);
476 if (!isValidFunctionSymbol(Init.Symbol))
477 return make_error<GenericBinaryError>("invalid function symbol: " +
478 Twine(Init.Symbol),
479 object_error::parse_failed);
480 LinkingData.InitFunctions.emplace_back(Init);
481 }
482 break;
483 }
484 case wasm::WASM_COMDAT_INFO:
485 if (Error Err = parseLinkingSectionComdat(Ctx))
486 return Err;
487 break;
488 default:
489 Ctx.Ptr += Size;
490 break;
491 }
492 if (Ctx.Ptr != Ctx.End)
493 return make_error<GenericBinaryError>(
494 "linking sub-section ended prematurely", object_error::parse_failed);
495 }
496 if (Ctx.Ptr != OrigEnd)
497 return make_error<GenericBinaryError>("linking section ended prematurely",
498 object_error::parse_failed);
499 return Error::success();
500 }
501
parseLinkingSectionSymtab(ReadContext & Ctx)502 Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
503 uint32_t Count = readVaruint32(Ctx);
504 LinkingData.SymbolTable.reserve(Count);
505 Symbols.reserve(Count);
506 StringSet<> SymbolNames;
507
508 std::vector<wasm::WasmImport *> ImportedGlobals;
509 std::vector<wasm::WasmImport *> ImportedFunctions;
510 std::vector<wasm::WasmImport *> ImportedEvents;
511 std::vector<wasm::WasmImport *> ImportedTables;
512 ImportedGlobals.reserve(Imports.size());
513 ImportedFunctions.reserve(Imports.size());
514 ImportedEvents.reserve(Imports.size());
515 ImportedTables.reserve(Imports.size());
516 for (auto &I : Imports) {
517 if (I.Kind == wasm::WASM_EXTERNAL_FUNCTION)
518 ImportedFunctions.emplace_back(&I);
519 else if (I.Kind == wasm::WASM_EXTERNAL_GLOBAL)
520 ImportedGlobals.emplace_back(&I);
521 else if (I.Kind == wasm::WASM_EXTERNAL_EVENT)
522 ImportedEvents.emplace_back(&I);
523 else if (I.Kind == wasm::WASM_EXTERNAL_TABLE)
524 ImportedTables.emplace_back(&I);
525 }
526
527 while (Count--) {
528 wasm::WasmSymbolInfo Info;
529 const wasm::WasmSignature *Signature = nullptr;
530 const wasm::WasmGlobalType *GlobalType = nullptr;
531 const wasm::WasmTableType *TableType = nullptr;
532 const wasm::WasmEventType *EventType = nullptr;
533
534 Info.Kind = readUint8(Ctx);
535 Info.Flags = readVaruint32(Ctx);
536 bool IsDefined = (Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0;
537
538 switch (Info.Kind) {
539 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
540 Info.ElementIndex = readVaruint32(Ctx);
541 if (!isValidFunctionIndex(Info.ElementIndex) ||
542 IsDefined != isDefinedFunctionIndex(Info.ElementIndex))
543 return make_error<GenericBinaryError>("invalid function symbol index",
544 object_error::parse_failed);
545 if (IsDefined) {
546 Info.Name = readString(Ctx);
547 unsigned FuncIndex = Info.ElementIndex - NumImportedFunctions;
548 Signature = &Signatures[FunctionTypes[FuncIndex]];
549 wasm::WasmFunction &Function = Functions[FuncIndex];
550 if (Function.SymbolName.empty())
551 Function.SymbolName = Info.Name;
552 } else {
553 wasm::WasmImport &Import = *ImportedFunctions[Info.ElementIndex];
554 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
555 Info.Name = readString(Ctx);
556 Info.ImportName = Import.Field;
557 } else {
558 Info.Name = Import.Field;
559 }
560 Signature = &Signatures[Import.SigIndex];
561 if (!Import.Module.empty()) {
562 Info.ImportModule = Import.Module;
563 }
564 }
565 break;
566
567 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
568 Info.ElementIndex = readVaruint32(Ctx);
569 if (!isValidGlobalIndex(Info.ElementIndex) ||
570 IsDefined != isDefinedGlobalIndex(Info.ElementIndex))
571 return make_error<GenericBinaryError>("invalid global symbol index",
572 object_error::parse_failed);
573 if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
574 wasm::WASM_SYMBOL_BINDING_WEAK)
575 return make_error<GenericBinaryError>("undefined weak global symbol",
576 object_error::parse_failed);
577 if (IsDefined) {
578 Info.Name = readString(Ctx);
579 unsigned GlobalIndex = Info.ElementIndex - NumImportedGlobals;
580 wasm::WasmGlobal &Global = Globals[GlobalIndex];
581 GlobalType = &Global.Type;
582 if (Global.SymbolName.empty())
583 Global.SymbolName = Info.Name;
584 } else {
585 wasm::WasmImport &Import = *ImportedGlobals[Info.ElementIndex];
586 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
587 Info.Name = readString(Ctx);
588 Info.ImportName = Import.Field;
589 } else {
590 Info.Name = Import.Field;
591 }
592 GlobalType = &Import.Global;
593 if (!Import.Module.empty()) {
594 Info.ImportModule = Import.Module;
595 }
596 }
597 break;
598
599 case wasm::WASM_SYMBOL_TYPE_TABLE:
600 Info.ElementIndex = readVaruint32(Ctx);
601 if (!isValidTableNumber(Info.ElementIndex) ||
602 IsDefined != isDefinedTableNumber(Info.ElementIndex))
603 return make_error<GenericBinaryError>("invalid table symbol index",
604 object_error::parse_failed);
605 if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
606 wasm::WASM_SYMBOL_BINDING_WEAK)
607 return make_error<GenericBinaryError>("undefined weak table symbol",
608 object_error::parse_failed);
609 if (IsDefined) {
610 Info.Name = readString(Ctx);
611 unsigned TableNumber = Info.ElementIndex - NumImportedTables;
612 wasm::WasmTable &Table = Tables[TableNumber];
613 TableType = &Table.Type;
614 if (Table.SymbolName.empty())
615 Table.SymbolName = Info.Name;
616 } else {
617 wasm::WasmImport &Import = *ImportedTables[Info.ElementIndex];
618 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
619 Info.Name = readString(Ctx);
620 Info.ImportName = Import.Field;
621 } else {
622 Info.Name = Import.Field;
623 }
624 TableType = &Import.Table;
625 if (!Import.Module.empty()) {
626 Info.ImportModule = Import.Module;
627 }
628 }
629 break;
630
631 case wasm::WASM_SYMBOL_TYPE_DATA:
632 Info.Name = readString(Ctx);
633 if (IsDefined) {
634 auto Index = readVaruint32(Ctx);
635 if (Index >= DataSegments.size())
636 return make_error<GenericBinaryError>("invalid data symbol index",
637 object_error::parse_failed);
638 auto Offset = readVaruint64(Ctx);
639 auto Size = readVaruint64(Ctx);
640 size_t SegmentSize = DataSegments[Index].Data.Content.size();
641 if (Offset > SegmentSize)
642 return make_error<GenericBinaryError>(
643 "invalid data symbol offset: `" + Info.Name + "` (offset: " +
644 Twine(Offset) + " segment size: " + Twine(SegmentSize) + ")",
645 object_error::parse_failed);
646 Info.DataRef = wasm::WasmDataReference{Index, Offset, Size};
647 }
648 break;
649
650 case wasm::WASM_SYMBOL_TYPE_SECTION: {
651 if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) !=
652 wasm::WASM_SYMBOL_BINDING_LOCAL)
653 return make_error<GenericBinaryError>(
654 "section symbols must have local binding",
655 object_error::parse_failed);
656 Info.ElementIndex = readVaruint32(Ctx);
657 // Use somewhat unique section name as symbol name.
658 StringRef SectionName = Sections[Info.ElementIndex].Name;
659 Info.Name = SectionName;
660 break;
661 }
662
663 case wasm::WASM_SYMBOL_TYPE_EVENT: {
664 Info.ElementIndex = readVaruint32(Ctx);
665 if (!isValidEventIndex(Info.ElementIndex) ||
666 IsDefined != isDefinedEventIndex(Info.ElementIndex))
667 return make_error<GenericBinaryError>("invalid event symbol index",
668 object_error::parse_failed);
669 if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
670 wasm::WASM_SYMBOL_BINDING_WEAK)
671 return make_error<GenericBinaryError>("undefined weak global symbol",
672 object_error::parse_failed);
673 if (IsDefined) {
674 Info.Name = readString(Ctx);
675 unsigned EventIndex = Info.ElementIndex - NumImportedEvents;
676 wasm::WasmEvent &Event = Events[EventIndex];
677 Signature = &Signatures[Event.Type.SigIndex];
678 EventType = &Event.Type;
679 if (Event.SymbolName.empty())
680 Event.SymbolName = Info.Name;
681
682 } else {
683 wasm::WasmImport &Import = *ImportedEvents[Info.ElementIndex];
684 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
685 Info.Name = readString(Ctx);
686 Info.ImportName = Import.Field;
687 } else {
688 Info.Name = Import.Field;
689 }
690 EventType = &Import.Event;
691 Signature = &Signatures[EventType->SigIndex];
692 if (!Import.Module.empty()) {
693 Info.ImportModule = Import.Module;
694 }
695 }
696 break;
697 }
698
699 default:
700 return make_error<GenericBinaryError>("invalid symbol type: " +
701 Twine(unsigned(Info.Kind)),
702 object_error::parse_failed);
703 }
704
705 if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) !=
706 wasm::WASM_SYMBOL_BINDING_LOCAL &&
707 !SymbolNames.insert(Info.Name).second)
708 return make_error<GenericBinaryError>("duplicate symbol name " +
709 Twine(Info.Name),
710 object_error::parse_failed);
711 LinkingData.SymbolTable.emplace_back(Info);
712 Symbols.emplace_back(LinkingData.SymbolTable.back(), GlobalType, TableType,
713 EventType, Signature);
714 LLVM_DEBUG(dbgs() << "Adding symbol: " << Symbols.back() << "\n");
715 }
716
717 return Error::success();
718 }
719
parseLinkingSectionComdat(ReadContext & Ctx)720 Error WasmObjectFile::parseLinkingSectionComdat(ReadContext &Ctx) {
721 uint32_t ComdatCount = readVaruint32(Ctx);
722 StringSet<> ComdatSet;
723 for (unsigned ComdatIndex = 0; ComdatIndex < ComdatCount; ++ComdatIndex) {
724 StringRef Name = readString(Ctx);
725 if (Name.empty() || !ComdatSet.insert(Name).second)
726 return make_error<GenericBinaryError>("bad/duplicate COMDAT name " +
727 Twine(Name),
728 object_error::parse_failed);
729 LinkingData.Comdats.emplace_back(Name);
730 uint32_t Flags = readVaruint32(Ctx);
731 if (Flags != 0)
732 return make_error<GenericBinaryError>("unsupported COMDAT flags",
733 object_error::parse_failed);
734
735 uint32_t EntryCount = readVaruint32(Ctx);
736 while (EntryCount--) {
737 unsigned Kind = readVaruint32(Ctx);
738 unsigned Index = readVaruint32(Ctx);
739 switch (Kind) {
740 default:
741 return make_error<GenericBinaryError>("invalid COMDAT entry type",
742 object_error::parse_failed);
743 case wasm::WASM_COMDAT_DATA:
744 if (Index >= DataSegments.size())
745 return make_error<GenericBinaryError>(
746 "COMDAT data index out of range", object_error::parse_failed);
747 if (DataSegments[Index].Data.Comdat != UINT32_MAX)
748 return make_error<GenericBinaryError>("data segment in two COMDATs",
749 object_error::parse_failed);
750 DataSegments[Index].Data.Comdat = ComdatIndex;
751 break;
752 case wasm::WASM_COMDAT_FUNCTION:
753 if (!isDefinedFunctionIndex(Index))
754 return make_error<GenericBinaryError>(
755 "COMDAT function index out of range", object_error::parse_failed);
756 if (getDefinedFunction(Index).Comdat != UINT32_MAX)
757 return make_error<GenericBinaryError>("function in two COMDATs",
758 object_error::parse_failed);
759 getDefinedFunction(Index).Comdat = ComdatIndex;
760 break;
761 case wasm::WASM_COMDAT_SECTION:
762 if (Index >= Sections.size())
763 return make_error<GenericBinaryError>(
764 "COMDAT section index out of range", object_error::parse_failed);
765 if (Sections[Index].Type != wasm::WASM_SEC_CUSTOM)
766 return make_error<GenericBinaryError>(
767 "non-custom section in a COMDAT", object_error::parse_failed);
768 Sections[Index].Comdat = ComdatIndex;
769 break;
770 }
771 }
772 }
773 return Error::success();
774 }
775
parseProducersSection(ReadContext & Ctx)776 Error WasmObjectFile::parseProducersSection(ReadContext &Ctx) {
777 llvm::SmallSet<StringRef, 3> FieldsSeen;
778 uint32_t Fields = readVaruint32(Ctx);
779 for (size_t I = 0; I < Fields; ++I) {
780 StringRef FieldName = readString(Ctx);
781 if (!FieldsSeen.insert(FieldName).second)
782 return make_error<GenericBinaryError>(
783 "producers section does not have unique fields",
784 object_error::parse_failed);
785 std::vector<std::pair<std::string, std::string>> *ProducerVec = nullptr;
786 if (FieldName == "language") {
787 ProducerVec = &ProducerInfo.Languages;
788 } else if (FieldName == "processed-by") {
789 ProducerVec = &ProducerInfo.Tools;
790 } else if (FieldName == "sdk") {
791 ProducerVec = &ProducerInfo.SDKs;
792 } else {
793 return make_error<GenericBinaryError>(
794 "producers section field is not named one of language, processed-by, "
795 "or sdk",
796 object_error::parse_failed);
797 }
798 uint32_t ValueCount = readVaruint32(Ctx);
799 llvm::SmallSet<StringRef, 8> ProducersSeen;
800 for (size_t J = 0; J < ValueCount; ++J) {
801 StringRef Name = readString(Ctx);
802 StringRef Version = readString(Ctx);
803 if (!ProducersSeen.insert(Name).second) {
804 return make_error<GenericBinaryError>(
805 "producers section contains repeated producer",
806 object_error::parse_failed);
807 }
808 ProducerVec->emplace_back(std::string(Name), std::string(Version));
809 }
810 }
811 if (Ctx.Ptr != Ctx.End)
812 return make_error<GenericBinaryError>("producers section ended prematurely",
813 object_error::parse_failed);
814 return Error::success();
815 }
816
parseTargetFeaturesSection(ReadContext & Ctx)817 Error WasmObjectFile::parseTargetFeaturesSection(ReadContext &Ctx) {
818 llvm::SmallSet<std::string, 8> FeaturesSeen;
819 uint32_t FeatureCount = readVaruint32(Ctx);
820 for (size_t I = 0; I < FeatureCount; ++I) {
821 wasm::WasmFeatureEntry Feature;
822 Feature.Prefix = readUint8(Ctx);
823 switch (Feature.Prefix) {
824 case wasm::WASM_FEATURE_PREFIX_USED:
825 case wasm::WASM_FEATURE_PREFIX_REQUIRED:
826 case wasm::WASM_FEATURE_PREFIX_DISALLOWED:
827 break;
828 default:
829 return make_error<GenericBinaryError>("unknown feature policy prefix",
830 object_error::parse_failed);
831 }
832 Feature.Name = std::string(readString(Ctx));
833 if (!FeaturesSeen.insert(Feature.Name).second)
834 return make_error<GenericBinaryError>(
835 "target features section contains repeated feature \"" +
836 Feature.Name + "\"",
837 object_error::parse_failed);
838 TargetFeatures.push_back(Feature);
839 }
840 if (Ctx.Ptr != Ctx.End)
841 return make_error<GenericBinaryError>(
842 "target features section ended prematurely",
843 object_error::parse_failed);
844 return Error::success();
845 }
846
parseRelocSection(StringRef Name,ReadContext & Ctx)847 Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
848 uint32_t SectionIndex = readVaruint32(Ctx);
849 if (SectionIndex >= Sections.size())
850 return make_error<GenericBinaryError>("invalid section index",
851 object_error::parse_failed);
852 WasmSection &Section = Sections[SectionIndex];
853 uint32_t RelocCount = readVaruint32(Ctx);
854 uint32_t EndOffset = Section.Content.size();
855 uint32_t PreviousOffset = 0;
856 while (RelocCount--) {
857 wasm::WasmRelocation Reloc = {};
858 uint32_t type = readVaruint32(Ctx);
859 Reloc.Type = type;
860 Reloc.Offset = readVaruint32(Ctx);
861 if (Reloc.Offset < PreviousOffset)
862 return make_error<GenericBinaryError>("relocations not in offset order",
863 object_error::parse_failed);
864 PreviousOffset = Reloc.Offset;
865 Reloc.Index = readVaruint32(Ctx);
866 switch (type) {
867 case wasm::R_WASM_FUNCTION_INDEX_LEB:
868 case wasm::R_WASM_TABLE_INDEX_SLEB:
869 case wasm::R_WASM_TABLE_INDEX_SLEB64:
870 case wasm::R_WASM_TABLE_INDEX_I32:
871 case wasm::R_WASM_TABLE_INDEX_I64:
872 case wasm::R_WASM_TABLE_INDEX_REL_SLEB:
873 case wasm::R_WASM_TABLE_INDEX_REL_SLEB64:
874 if (!isValidFunctionSymbol(Reloc.Index))
875 return make_error<GenericBinaryError>(
876 "invalid relocation function index", object_error::parse_failed);
877 break;
878 case wasm::R_WASM_TABLE_NUMBER_LEB:
879 if (!isValidTableSymbol(Reloc.Index))
880 return make_error<GenericBinaryError>("invalid relocation table index",
881 object_error::parse_failed);
882 break;
883 case wasm::R_WASM_TYPE_INDEX_LEB:
884 if (Reloc.Index >= Signatures.size())
885 return make_error<GenericBinaryError>("invalid relocation type index",
886 object_error::parse_failed);
887 break;
888 case wasm::R_WASM_GLOBAL_INDEX_LEB:
889 // R_WASM_GLOBAL_INDEX_LEB are can be used against function and data
890 // symbols to refer to their GOT entries.
891 if (!isValidGlobalSymbol(Reloc.Index) &&
892 !isValidDataSymbol(Reloc.Index) &&
893 !isValidFunctionSymbol(Reloc.Index))
894 return make_error<GenericBinaryError>("invalid relocation global index",
895 object_error::parse_failed);
896 break;
897 case wasm::R_WASM_GLOBAL_INDEX_I32:
898 if (!isValidGlobalSymbol(Reloc.Index))
899 return make_error<GenericBinaryError>("invalid relocation global index",
900 object_error::parse_failed);
901 break;
902 case wasm::R_WASM_EVENT_INDEX_LEB:
903 if (!isValidEventSymbol(Reloc.Index))
904 return make_error<GenericBinaryError>("invalid relocation event index",
905 object_error::parse_failed);
906 break;
907 case wasm::R_WASM_MEMORY_ADDR_LEB:
908 case wasm::R_WASM_MEMORY_ADDR_SLEB:
909 case wasm::R_WASM_MEMORY_ADDR_I32:
910 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:
911 case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB:
912 case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32:
913 if (!isValidDataSymbol(Reloc.Index))
914 return make_error<GenericBinaryError>("invalid relocation data index",
915 object_error::parse_failed);
916 Reloc.Addend = readVarint32(Ctx);
917 break;
918 case wasm::R_WASM_MEMORY_ADDR_LEB64:
919 case wasm::R_WASM_MEMORY_ADDR_SLEB64:
920 case wasm::R_WASM_MEMORY_ADDR_I64:
921 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64:
922 if (!isValidDataSymbol(Reloc.Index))
923 return make_error<GenericBinaryError>("invalid relocation data index",
924 object_error::parse_failed);
925 Reloc.Addend = readVarint64(Ctx);
926 break;
927 case wasm::R_WASM_FUNCTION_OFFSET_I32:
928 if (!isValidFunctionSymbol(Reloc.Index))
929 return make_error<GenericBinaryError>(
930 "invalid relocation function index", object_error::parse_failed);
931 Reloc.Addend = readVarint32(Ctx);
932 break;
933 case wasm::R_WASM_FUNCTION_OFFSET_I64:
934 if (!isValidFunctionSymbol(Reloc.Index))
935 return make_error<GenericBinaryError>(
936 "invalid relocation function index", object_error::parse_failed);
937 Reloc.Addend = readVarint64(Ctx);
938 break;
939 case wasm::R_WASM_SECTION_OFFSET_I32:
940 if (!isValidSectionSymbol(Reloc.Index))
941 return make_error<GenericBinaryError>(
942 "invalid relocation section index", object_error::parse_failed);
943 Reloc.Addend = readVarint32(Ctx);
944 break;
945 default:
946 return make_error<GenericBinaryError>("invalid relocation type: " +
947 Twine(type),
948 object_error::parse_failed);
949 }
950
951 // Relocations must fit inside the section, and must appear in order. They
952 // also shouldn't overlap a function/element boundary, but we don't bother
953 // to check that.
954 uint64_t Size = 5;
955 if (Reloc.Type == wasm::R_WASM_MEMORY_ADDR_LEB64 ||
956 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_SLEB64 ||
957 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_REL_SLEB64)
958 Size = 10;
959 if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I32 ||
960 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I32 ||
961 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_LOCREL_I32 ||
962 Reloc.Type == wasm::R_WASM_SECTION_OFFSET_I32 ||
963 Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I32 ||
964 Reloc.Type == wasm::R_WASM_GLOBAL_INDEX_I32)
965 Size = 4;
966 if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I64 ||
967 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I64 ||
968 Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I64)
969 Size = 8;
970 if (Reloc.Offset + Size > EndOffset)
971 return make_error<GenericBinaryError>("invalid relocation offset",
972 object_error::parse_failed);
973
974 Section.Relocations.push_back(Reloc);
975 }
976 if (Ctx.Ptr != Ctx.End)
977 return make_error<GenericBinaryError>("reloc section ended prematurely",
978 object_error::parse_failed);
979 return Error::success();
980 }
981
parseCustomSection(WasmSection & Sec,ReadContext & Ctx)982 Error WasmObjectFile::parseCustomSection(WasmSection &Sec, ReadContext &Ctx) {
983 if (Sec.Name == "dylink") {
984 if (Error Err = parseDylinkSection(Ctx))
985 return Err;
986 } else if (Sec.Name == "name") {
987 if (Error Err = parseNameSection(Ctx))
988 return Err;
989 } else if (Sec.Name == "linking") {
990 if (Error Err = parseLinkingSection(Ctx))
991 return Err;
992 } else if (Sec.Name == "producers") {
993 if (Error Err = parseProducersSection(Ctx))
994 return Err;
995 } else if (Sec.Name == "target_features") {
996 if (Error Err = parseTargetFeaturesSection(Ctx))
997 return Err;
998 } else if (Sec.Name.startswith("reloc.")) {
999 if (Error Err = parseRelocSection(Sec.Name, Ctx))
1000 return Err;
1001 }
1002 return Error::success();
1003 }
1004
parseTypeSection(ReadContext & Ctx)1005 Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
1006 uint32_t Count = readVaruint32(Ctx);
1007 Signatures.reserve(Count);
1008 while (Count--) {
1009 wasm::WasmSignature Sig;
1010 uint8_t Form = readUint8(Ctx);
1011 if (Form != wasm::WASM_TYPE_FUNC) {
1012 return make_error<GenericBinaryError>("invalid signature type",
1013 object_error::parse_failed);
1014 }
1015 uint32_t ParamCount = readVaruint32(Ctx);
1016 Sig.Params.reserve(ParamCount);
1017 while (ParamCount--) {
1018 uint32_t ParamType = readUint8(Ctx);
1019 Sig.Params.push_back(wasm::ValType(ParamType));
1020 }
1021 uint32_t ReturnCount = readVaruint32(Ctx);
1022 while (ReturnCount--) {
1023 uint32_t ReturnType = readUint8(Ctx);
1024 Sig.Returns.push_back(wasm::ValType(ReturnType));
1025 }
1026 Signatures.push_back(std::move(Sig));
1027 }
1028 if (Ctx.Ptr != Ctx.End)
1029 return make_error<GenericBinaryError>("type section ended prematurely",
1030 object_error::parse_failed);
1031 return Error::success();
1032 }
1033
parseImportSection(ReadContext & Ctx)1034 Error WasmObjectFile::parseImportSection(ReadContext &Ctx) {
1035 uint32_t Count = readVaruint32(Ctx);
1036 Imports.reserve(Count);
1037 for (uint32_t I = 0; I < Count; I++) {
1038 wasm::WasmImport Im;
1039 Im.Module = readString(Ctx);
1040 Im.Field = readString(Ctx);
1041 Im.Kind = readUint8(Ctx);
1042 switch (Im.Kind) {
1043 case wasm::WASM_EXTERNAL_FUNCTION:
1044 NumImportedFunctions++;
1045 Im.SigIndex = readVaruint32(Ctx);
1046 break;
1047 case wasm::WASM_EXTERNAL_GLOBAL:
1048 NumImportedGlobals++;
1049 Im.Global.Type = readUint8(Ctx);
1050 Im.Global.Mutable = readVaruint1(Ctx);
1051 break;
1052 case wasm::WASM_EXTERNAL_MEMORY:
1053 Im.Memory = readLimits(Ctx);
1054 if (Im.Memory.Flags & wasm::WASM_LIMITS_FLAG_IS_64)
1055 HasMemory64 = true;
1056 break;
1057 case wasm::WASM_EXTERNAL_TABLE: {
1058 Im.Table = readTableType(Ctx);
1059 NumImportedTables++;
1060 auto ElemType = Im.Table.ElemType;
1061 if (ElemType != wasm::WASM_TYPE_FUNCREF &&
1062 ElemType != wasm::WASM_TYPE_EXTERNREF)
1063 return make_error<GenericBinaryError>("invalid table element type",
1064 object_error::parse_failed);
1065 break;
1066 }
1067 case wasm::WASM_EXTERNAL_EVENT:
1068 NumImportedEvents++;
1069 Im.Event.Attribute = readVarint32(Ctx);
1070 Im.Event.SigIndex = readVarint32(Ctx);
1071 break;
1072 default:
1073 return make_error<GenericBinaryError>("unexpected import kind",
1074 object_error::parse_failed);
1075 }
1076 Imports.push_back(Im);
1077 }
1078 if (Ctx.Ptr != Ctx.End)
1079 return make_error<GenericBinaryError>("import section ended prematurely",
1080 object_error::parse_failed);
1081 return Error::success();
1082 }
1083
parseFunctionSection(ReadContext & Ctx)1084 Error WasmObjectFile::parseFunctionSection(ReadContext &Ctx) {
1085 uint32_t Count = readVaruint32(Ctx);
1086 FunctionTypes.reserve(Count);
1087 Functions.resize(Count);
1088 uint32_t NumTypes = Signatures.size();
1089 while (Count--) {
1090 uint32_t Type = readVaruint32(Ctx);
1091 if (Type >= NumTypes)
1092 return make_error<GenericBinaryError>("invalid function type",
1093 object_error::parse_failed);
1094 FunctionTypes.push_back(Type);
1095 }
1096 if (Ctx.Ptr != Ctx.End)
1097 return make_error<GenericBinaryError>("function section ended prematurely",
1098 object_error::parse_failed);
1099 return Error::success();
1100 }
1101
parseTableSection(ReadContext & Ctx)1102 Error WasmObjectFile::parseTableSection(ReadContext &Ctx) {
1103 TableSection = Sections.size();
1104 uint32_t Count = readVaruint32(Ctx);
1105 Tables.reserve(Count);
1106 while (Count--) {
1107 wasm::WasmTable T;
1108 T.Type = readTableType(Ctx);
1109 T.Index = NumImportedTables + Tables.size();
1110 Tables.push_back(T);
1111 auto ElemType = Tables.back().Type.ElemType;
1112 if (ElemType != wasm::WASM_TYPE_FUNCREF &&
1113 ElemType != wasm::WASM_TYPE_EXTERNREF) {
1114 return make_error<GenericBinaryError>("invalid table element type",
1115 object_error::parse_failed);
1116 }
1117 }
1118 if (Ctx.Ptr != Ctx.End)
1119 return make_error<GenericBinaryError>("table section ended prematurely",
1120 object_error::parse_failed);
1121 return Error::success();
1122 }
1123
parseMemorySection(ReadContext & Ctx)1124 Error WasmObjectFile::parseMemorySection(ReadContext &Ctx) {
1125 uint32_t Count = readVaruint32(Ctx);
1126 Memories.reserve(Count);
1127 while (Count--) {
1128 auto Limits = readLimits(Ctx);
1129 if (Limits.Flags & wasm::WASM_LIMITS_FLAG_IS_64)
1130 HasMemory64 = true;
1131 Memories.push_back(Limits);
1132 }
1133 if (Ctx.Ptr != Ctx.End)
1134 return make_error<GenericBinaryError>("memory section ended prematurely",
1135 object_error::parse_failed);
1136 return Error::success();
1137 }
1138
parseEventSection(ReadContext & Ctx)1139 Error WasmObjectFile::parseEventSection(ReadContext &Ctx) {
1140 EventSection = Sections.size();
1141 uint32_t Count = readVaruint32(Ctx);
1142 Events.reserve(Count);
1143 while (Count--) {
1144 wasm::WasmEvent Event;
1145 Event.Index = NumImportedEvents + Events.size();
1146 Event.Type.Attribute = readVaruint32(Ctx);
1147 Event.Type.SigIndex = readVaruint32(Ctx);
1148 Events.push_back(Event);
1149 }
1150
1151 if (Ctx.Ptr != Ctx.End)
1152 return make_error<GenericBinaryError>("event section ended prematurely",
1153 object_error::parse_failed);
1154 return Error::success();
1155 }
1156
parseGlobalSection(ReadContext & Ctx)1157 Error WasmObjectFile::parseGlobalSection(ReadContext &Ctx) {
1158 GlobalSection = Sections.size();
1159 uint32_t Count = readVaruint32(Ctx);
1160 Globals.reserve(Count);
1161 while (Count--) {
1162 wasm::WasmGlobal Global;
1163 Global.Index = NumImportedGlobals + Globals.size();
1164 Global.Type.Type = readUint8(Ctx);
1165 Global.Type.Mutable = readVaruint1(Ctx);
1166 if (Error Err = readInitExpr(Global.InitExpr, Ctx))
1167 return Err;
1168 Globals.push_back(Global);
1169 }
1170 if (Ctx.Ptr != Ctx.End)
1171 return make_error<GenericBinaryError>("global section ended prematurely",
1172 object_error::parse_failed);
1173 return Error::success();
1174 }
1175
parseExportSection(ReadContext & Ctx)1176 Error WasmObjectFile::parseExportSection(ReadContext &Ctx) {
1177 uint32_t Count = readVaruint32(Ctx);
1178 Exports.reserve(Count);
1179 for (uint32_t I = 0; I < Count; I++) {
1180 wasm::WasmExport Ex;
1181 Ex.Name = readString(Ctx);
1182 Ex.Kind = readUint8(Ctx);
1183 Ex.Index = readVaruint32(Ctx);
1184 switch (Ex.Kind) {
1185 case wasm::WASM_EXTERNAL_FUNCTION:
1186
1187 if (!isDefinedFunctionIndex(Ex.Index))
1188 return make_error<GenericBinaryError>("invalid function export",
1189 object_error::parse_failed);
1190 getDefinedFunction(Ex.Index).ExportName = Ex.Name;
1191 break;
1192 case wasm::WASM_EXTERNAL_GLOBAL:
1193 if (!isValidGlobalIndex(Ex.Index))
1194 return make_error<GenericBinaryError>("invalid global export",
1195 object_error::parse_failed);
1196 break;
1197 case wasm::WASM_EXTERNAL_EVENT:
1198 if (!isValidEventIndex(Ex.Index))
1199 return make_error<GenericBinaryError>("invalid event export",
1200 object_error::parse_failed);
1201 break;
1202 case wasm::WASM_EXTERNAL_MEMORY:
1203 case wasm::WASM_EXTERNAL_TABLE:
1204 break;
1205 default:
1206 return make_error<GenericBinaryError>("unexpected export kind",
1207 object_error::parse_failed);
1208 }
1209 Exports.push_back(Ex);
1210 }
1211 if (Ctx.Ptr != Ctx.End)
1212 return make_error<GenericBinaryError>("export section ended prematurely",
1213 object_error::parse_failed);
1214 return Error::success();
1215 }
1216
isValidFunctionIndex(uint32_t Index) const1217 bool WasmObjectFile::isValidFunctionIndex(uint32_t Index) const {
1218 return Index < NumImportedFunctions + FunctionTypes.size();
1219 }
1220
isDefinedFunctionIndex(uint32_t Index) const1221 bool WasmObjectFile::isDefinedFunctionIndex(uint32_t Index) const {
1222 return Index >= NumImportedFunctions && isValidFunctionIndex(Index);
1223 }
1224
isValidGlobalIndex(uint32_t Index) const1225 bool WasmObjectFile::isValidGlobalIndex(uint32_t Index) const {
1226 return Index < NumImportedGlobals + Globals.size();
1227 }
1228
isValidTableNumber(uint32_t Index) const1229 bool WasmObjectFile::isValidTableNumber(uint32_t Index) const {
1230 return Index < NumImportedTables + Tables.size();
1231 }
1232
isDefinedGlobalIndex(uint32_t Index) const1233 bool WasmObjectFile::isDefinedGlobalIndex(uint32_t Index) const {
1234 return Index >= NumImportedGlobals && isValidGlobalIndex(Index);
1235 }
1236
isDefinedTableNumber(uint32_t Index) const1237 bool WasmObjectFile::isDefinedTableNumber(uint32_t Index) const {
1238 return Index >= NumImportedTables && isValidTableNumber(Index);
1239 }
1240
isValidEventIndex(uint32_t Index) const1241 bool WasmObjectFile::isValidEventIndex(uint32_t Index) const {
1242 return Index < NumImportedEvents + Events.size();
1243 }
1244
isDefinedEventIndex(uint32_t Index) const1245 bool WasmObjectFile::isDefinedEventIndex(uint32_t Index) const {
1246 return Index >= NumImportedEvents && isValidEventIndex(Index);
1247 }
1248
isValidFunctionSymbol(uint32_t Index) const1249 bool WasmObjectFile::isValidFunctionSymbol(uint32_t Index) const {
1250 return Index < Symbols.size() && Symbols[Index].isTypeFunction();
1251 }
1252
isValidTableSymbol(uint32_t Index) const1253 bool WasmObjectFile::isValidTableSymbol(uint32_t Index) const {
1254 return Index < Symbols.size() && Symbols[Index].isTypeTable();
1255 }
1256
isValidGlobalSymbol(uint32_t Index) const1257 bool WasmObjectFile::isValidGlobalSymbol(uint32_t Index) const {
1258 return Index < Symbols.size() && Symbols[Index].isTypeGlobal();
1259 }
1260
isValidEventSymbol(uint32_t Index) const1261 bool WasmObjectFile::isValidEventSymbol(uint32_t Index) const {
1262 return Index < Symbols.size() && Symbols[Index].isTypeEvent();
1263 }
1264
isValidDataSymbol(uint32_t Index) const1265 bool WasmObjectFile::isValidDataSymbol(uint32_t Index) const {
1266 return Index < Symbols.size() && Symbols[Index].isTypeData();
1267 }
1268
isValidSectionSymbol(uint32_t Index) const1269 bool WasmObjectFile::isValidSectionSymbol(uint32_t Index) const {
1270 return Index < Symbols.size() && Symbols[Index].isTypeSection();
1271 }
1272
getDefinedFunction(uint32_t Index)1273 wasm::WasmFunction &WasmObjectFile::getDefinedFunction(uint32_t Index) {
1274 assert(isDefinedFunctionIndex(Index));
1275 return Functions[Index - NumImportedFunctions];
1276 }
1277
1278 const wasm::WasmFunction &
getDefinedFunction(uint32_t Index) const1279 WasmObjectFile::getDefinedFunction(uint32_t Index) const {
1280 assert(isDefinedFunctionIndex(Index));
1281 return Functions[Index - NumImportedFunctions];
1282 }
1283
getDefinedGlobal(uint32_t Index)1284 wasm::WasmGlobal &WasmObjectFile::getDefinedGlobal(uint32_t Index) {
1285 assert(isDefinedGlobalIndex(Index));
1286 return Globals[Index - NumImportedGlobals];
1287 }
1288
getDefinedEvent(uint32_t Index)1289 wasm::WasmEvent &WasmObjectFile::getDefinedEvent(uint32_t Index) {
1290 assert(isDefinedEventIndex(Index));
1291 return Events[Index - NumImportedEvents];
1292 }
1293
parseStartSection(ReadContext & Ctx)1294 Error WasmObjectFile::parseStartSection(ReadContext &Ctx) {
1295 StartFunction = readVaruint32(Ctx);
1296 if (!isValidFunctionIndex(StartFunction))
1297 return make_error<GenericBinaryError>("invalid start function",
1298 object_error::parse_failed);
1299 return Error::success();
1300 }
1301
parseCodeSection(ReadContext & Ctx)1302 Error WasmObjectFile::parseCodeSection(ReadContext &Ctx) {
1303 SeenCodeSection = true;
1304 CodeSection = Sections.size();
1305 uint32_t FunctionCount = readVaruint32(Ctx);
1306 if (FunctionCount != FunctionTypes.size()) {
1307 return make_error<GenericBinaryError>("invalid function count",
1308 object_error::parse_failed);
1309 }
1310
1311 for (uint32_t i = 0; i < FunctionCount; i++) {
1312 wasm::WasmFunction& Function = Functions[i];
1313 const uint8_t *FunctionStart = Ctx.Ptr;
1314 uint32_t Size = readVaruint32(Ctx);
1315 const uint8_t *FunctionEnd = Ctx.Ptr + Size;
1316
1317 Function.CodeOffset = Ctx.Ptr - FunctionStart;
1318 Function.Index = NumImportedFunctions + i;
1319 Function.CodeSectionOffset = FunctionStart - Ctx.Start;
1320 Function.Size = FunctionEnd - FunctionStart;
1321
1322 uint32_t NumLocalDecls = readVaruint32(Ctx);
1323 Function.Locals.reserve(NumLocalDecls);
1324 while (NumLocalDecls--) {
1325 wasm::WasmLocalDecl Decl;
1326 Decl.Count = readVaruint32(Ctx);
1327 Decl.Type = readUint8(Ctx);
1328 Function.Locals.push_back(Decl);
1329 }
1330
1331 uint32_t BodySize = FunctionEnd - Ctx.Ptr;
1332 Function.Body = ArrayRef<uint8_t>(Ctx.Ptr, BodySize);
1333 // This will be set later when reading in the linking metadata section.
1334 Function.Comdat = UINT32_MAX;
1335 Ctx.Ptr += BodySize;
1336 assert(Ctx.Ptr == FunctionEnd);
1337 }
1338 if (Ctx.Ptr != Ctx.End)
1339 return make_error<GenericBinaryError>("code section ended prematurely",
1340 object_error::parse_failed);
1341 return Error::success();
1342 }
1343
parseElemSection(ReadContext & Ctx)1344 Error WasmObjectFile::parseElemSection(ReadContext &Ctx) {
1345 uint32_t Count = readVaruint32(Ctx);
1346 ElemSegments.reserve(Count);
1347 while (Count--) {
1348 wasm::WasmElemSegment Segment;
1349 Segment.Flags = readVaruint32(Ctx);
1350
1351 uint32_t SupportedFlags = wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER |
1352 wasm::WASM_ELEM_SEGMENT_IS_PASSIVE |
1353 wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS;
1354 if (Segment.Flags & ~SupportedFlags)
1355 return make_error<GenericBinaryError>(
1356 "Unsupported flags for element segment", object_error::parse_failed);
1357
1358 if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER)
1359 Segment.TableNumber = readVaruint32(Ctx);
1360 else
1361 Segment.TableNumber = 0;
1362 if (!isValidTableNumber(Segment.TableNumber))
1363 return make_error<GenericBinaryError>("invalid TableNumber",
1364 object_error::parse_failed);
1365
1366 if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_PASSIVE) {
1367 Segment.Offset.Opcode = wasm::WASM_OPCODE_I32_CONST;
1368 Segment.Offset.Value.Int32 = 0;
1369 } else {
1370 if (Error Err = readInitExpr(Segment.Offset, Ctx))
1371 return Err;
1372 }
1373
1374 if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND) {
1375 Segment.ElemKind = readUint8(Ctx);
1376 if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS) {
1377 if (Segment.ElemKind != uint8_t(wasm::ValType::FUNCREF) &&
1378 Segment.ElemKind != uint8_t(wasm::ValType::EXTERNREF)) {
1379 return make_error<GenericBinaryError>("invalid reference type",
1380 object_error::parse_failed);
1381 }
1382 } else {
1383 if (Segment.ElemKind != 0)
1384 return make_error<GenericBinaryError>("invalid elemtype",
1385 object_error::parse_failed);
1386 Segment.ElemKind = uint8_t(wasm::ValType::FUNCREF);
1387 }
1388 } else {
1389 Segment.ElemKind = uint8_t(wasm::ValType::FUNCREF);
1390 }
1391
1392 if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS)
1393 return make_error<GenericBinaryError>(
1394 "elem segment init expressions not yet implemented",
1395 object_error::parse_failed);
1396
1397 uint32_t NumElems = readVaruint32(Ctx);
1398 while (NumElems--) {
1399 Segment.Functions.push_back(readVaruint32(Ctx));
1400 }
1401 ElemSegments.push_back(Segment);
1402 }
1403 if (Ctx.Ptr != Ctx.End)
1404 return make_error<GenericBinaryError>("elem section ended prematurely",
1405 object_error::parse_failed);
1406 return Error::success();
1407 }
1408
parseDataSection(ReadContext & Ctx)1409 Error WasmObjectFile::parseDataSection(ReadContext &Ctx) {
1410 DataSection = Sections.size();
1411 uint32_t Count = readVaruint32(Ctx);
1412 if (DataCount && Count != DataCount.getValue())
1413 return make_error<GenericBinaryError>(
1414 "number of data segments does not match DataCount section");
1415 DataSegments.reserve(Count);
1416 while (Count--) {
1417 WasmSegment Segment;
1418 Segment.Data.InitFlags = readVaruint32(Ctx);
1419 Segment.Data.MemoryIndex =
1420 (Segment.Data.InitFlags & wasm::WASM_DATA_SEGMENT_HAS_MEMINDEX)
1421 ? readVaruint32(Ctx)
1422 : 0;
1423 if ((Segment.Data.InitFlags & wasm::WASM_DATA_SEGMENT_IS_PASSIVE) == 0) {
1424 if (Error Err = readInitExpr(Segment.Data.Offset, Ctx))
1425 return Err;
1426 } else {
1427 Segment.Data.Offset.Opcode = wasm::WASM_OPCODE_I32_CONST;
1428 Segment.Data.Offset.Value.Int32 = 0;
1429 }
1430 uint32_t Size = readVaruint32(Ctx);
1431 if (Size > (size_t)(Ctx.End - Ctx.Ptr))
1432 return make_error<GenericBinaryError>("invalid segment size",
1433 object_error::parse_failed);
1434 Segment.Data.Content = ArrayRef<uint8_t>(Ctx.Ptr, Size);
1435 // The rest of these Data fields are set later, when reading in the linking
1436 // metadata section.
1437 Segment.Data.Alignment = 0;
1438 Segment.Data.LinkingFlags = 0;
1439 Segment.Data.Comdat = UINT32_MAX;
1440 Segment.SectionOffset = Ctx.Ptr - Ctx.Start;
1441 Ctx.Ptr += Size;
1442 DataSegments.push_back(Segment);
1443 }
1444 if (Ctx.Ptr != Ctx.End)
1445 return make_error<GenericBinaryError>("data section ended prematurely",
1446 object_error::parse_failed);
1447 return Error::success();
1448 }
1449
parseDataCountSection(ReadContext & Ctx)1450 Error WasmObjectFile::parseDataCountSection(ReadContext &Ctx) {
1451 DataCount = readVaruint32(Ctx);
1452 return Error::success();
1453 }
1454
getHeader() const1455 const wasm::WasmObjectHeader &WasmObjectFile::getHeader() const {
1456 return Header;
1457 }
1458
moveSymbolNext(DataRefImpl & Symb) const1459 void WasmObjectFile::moveSymbolNext(DataRefImpl &Symb) const { Symb.d.b++; }
1460
getSymbolFlags(DataRefImpl Symb) const1461 Expected<uint32_t> WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const {
1462 uint32_t Result = SymbolRef::SF_None;
1463 const WasmSymbol &Sym = getWasmSymbol(Symb);
1464
1465 LLVM_DEBUG(dbgs() << "getSymbolFlags: ptr=" << &Sym << " " << Sym << "\n");
1466 if (Sym.isBindingWeak())
1467 Result |= SymbolRef::SF_Weak;
1468 if (!Sym.isBindingLocal())
1469 Result |= SymbolRef::SF_Global;
1470 if (Sym.isHidden())
1471 Result |= SymbolRef::SF_Hidden;
1472 if (!Sym.isDefined())
1473 Result |= SymbolRef::SF_Undefined;
1474 if (Sym.isTypeFunction())
1475 Result |= SymbolRef::SF_Executable;
1476 return Result;
1477 }
1478
symbol_begin() const1479 basic_symbol_iterator WasmObjectFile::symbol_begin() const {
1480 DataRefImpl Ref;
1481 Ref.d.a = 1; // Arbitrary non-zero value so that Ref.p is non-null
1482 Ref.d.b = 0; // Symbol index
1483 return BasicSymbolRef(Ref, this);
1484 }
1485
symbol_end() const1486 basic_symbol_iterator WasmObjectFile::symbol_end() const {
1487 DataRefImpl Ref;
1488 Ref.d.a = 1; // Arbitrary non-zero value so that Ref.p is non-null
1489 Ref.d.b = Symbols.size(); // Symbol index
1490 return BasicSymbolRef(Ref, this);
1491 }
1492
getWasmSymbol(const DataRefImpl & Symb) const1493 const WasmSymbol &WasmObjectFile::getWasmSymbol(const DataRefImpl &Symb) const {
1494 return Symbols[Symb.d.b];
1495 }
1496
getWasmSymbol(const SymbolRef & Symb) const1497 const WasmSymbol &WasmObjectFile::getWasmSymbol(const SymbolRef &Symb) const {
1498 return getWasmSymbol(Symb.getRawDataRefImpl());
1499 }
1500
getSymbolName(DataRefImpl Symb) const1501 Expected<StringRef> WasmObjectFile::getSymbolName(DataRefImpl Symb) const {
1502 return getWasmSymbol(Symb).Info.Name;
1503 }
1504
getSymbolAddress(DataRefImpl Symb) const1505 Expected<uint64_t> WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const {
1506 auto &Sym = getWasmSymbol(Symb);
1507 if (Sym.Info.Kind == wasm::WASM_SYMBOL_TYPE_FUNCTION &&
1508 isDefinedFunctionIndex(Sym.Info.ElementIndex))
1509 return getDefinedFunction(Sym.Info.ElementIndex).CodeSectionOffset;
1510 else
1511 return getSymbolValue(Symb);
1512 }
1513
getWasmSymbolValue(const WasmSymbol & Sym) const1514 uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol &Sym) const {
1515 switch (Sym.Info.Kind) {
1516 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1517 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1518 case wasm::WASM_SYMBOL_TYPE_EVENT:
1519 case wasm::WASM_SYMBOL_TYPE_TABLE:
1520 return Sym.Info.ElementIndex;
1521 case wasm::WASM_SYMBOL_TYPE_DATA: {
1522 // The value of a data symbol is the segment offset, plus the symbol
1523 // offset within the segment.
1524 uint32_t SegmentIndex = Sym.Info.DataRef.Segment;
1525 const wasm::WasmDataSegment &Segment = DataSegments[SegmentIndex].Data;
1526 if (Segment.Offset.Opcode == wasm::WASM_OPCODE_I32_CONST) {
1527 return Segment.Offset.Value.Int32 + Sym.Info.DataRef.Offset;
1528 } else if (Segment.Offset.Opcode == wasm::WASM_OPCODE_I64_CONST) {
1529 return Segment.Offset.Value.Int64 + Sym.Info.DataRef.Offset;
1530 } else {
1531 llvm_unreachable("unknown init expr opcode");
1532 }
1533 }
1534 case wasm::WASM_SYMBOL_TYPE_SECTION:
1535 return 0;
1536 }
1537 llvm_unreachable("invalid symbol type");
1538 }
1539
getSymbolValueImpl(DataRefImpl Symb) const1540 uint64_t WasmObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
1541 return getWasmSymbolValue(getWasmSymbol(Symb));
1542 }
1543
getSymbolAlignment(DataRefImpl Symb) const1544 uint32_t WasmObjectFile::getSymbolAlignment(DataRefImpl Symb) const {
1545 llvm_unreachable("not yet implemented");
1546 return 0;
1547 }
1548
getCommonSymbolSizeImpl(DataRefImpl Symb) const1549 uint64_t WasmObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
1550 llvm_unreachable("not yet implemented");
1551 return 0;
1552 }
1553
1554 Expected<SymbolRef::Type>
getSymbolType(DataRefImpl Symb) const1555 WasmObjectFile::getSymbolType(DataRefImpl Symb) const {
1556 const WasmSymbol &Sym = getWasmSymbol(Symb);
1557
1558 switch (Sym.Info.Kind) {
1559 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1560 return SymbolRef::ST_Function;
1561 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1562 return SymbolRef::ST_Other;
1563 case wasm::WASM_SYMBOL_TYPE_DATA:
1564 return SymbolRef::ST_Data;
1565 case wasm::WASM_SYMBOL_TYPE_SECTION:
1566 return SymbolRef::ST_Debug;
1567 case wasm::WASM_SYMBOL_TYPE_EVENT:
1568 return SymbolRef::ST_Other;
1569 case wasm::WASM_SYMBOL_TYPE_TABLE:
1570 return SymbolRef::ST_Other;
1571 }
1572
1573 llvm_unreachable("unknown WasmSymbol::SymbolType");
1574 return SymbolRef::ST_Other;
1575 }
1576
1577 Expected<section_iterator>
getSymbolSection(DataRefImpl Symb) const1578 WasmObjectFile::getSymbolSection(DataRefImpl Symb) const {
1579 const WasmSymbol &Sym = getWasmSymbol(Symb);
1580 if (Sym.isUndefined())
1581 return section_end();
1582
1583 DataRefImpl Ref;
1584 Ref.d.a = getSymbolSectionIdImpl(Sym);
1585 return section_iterator(SectionRef(Ref, this));
1586 }
1587
getSymbolSectionId(SymbolRef Symb) const1588 uint32_t WasmObjectFile::getSymbolSectionId(SymbolRef Symb) const {
1589 const WasmSymbol &Sym = getWasmSymbol(Symb);
1590 return getSymbolSectionIdImpl(Sym);
1591 }
1592
getSymbolSectionIdImpl(const WasmSymbol & Sym) const1593 uint32_t WasmObjectFile::getSymbolSectionIdImpl(const WasmSymbol &Sym) const {
1594 switch (Sym.Info.Kind) {
1595 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1596 return CodeSection;
1597 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1598 return GlobalSection;
1599 case wasm::WASM_SYMBOL_TYPE_DATA:
1600 return DataSection;
1601 case wasm::WASM_SYMBOL_TYPE_SECTION:
1602 return Sym.Info.ElementIndex;
1603 case wasm::WASM_SYMBOL_TYPE_EVENT:
1604 return EventSection;
1605 case wasm::WASM_SYMBOL_TYPE_TABLE:
1606 return TableSection;
1607 default:
1608 llvm_unreachable("unknown WasmSymbol::SymbolType");
1609 }
1610 }
1611
moveSectionNext(DataRefImpl & Sec) const1612 void WasmObjectFile::moveSectionNext(DataRefImpl &Sec) const { Sec.d.a++; }
1613
getSectionName(DataRefImpl Sec) const1614 Expected<StringRef> WasmObjectFile::getSectionName(DataRefImpl Sec) const {
1615 const WasmSection &S = Sections[Sec.d.a];
1616 #define ECase(X) \
1617 case wasm::WASM_SEC_##X: \
1618 return #X;
1619 switch (S.Type) {
1620 ECase(TYPE);
1621 ECase(IMPORT);
1622 ECase(FUNCTION);
1623 ECase(TABLE);
1624 ECase(MEMORY);
1625 ECase(GLOBAL);
1626 ECase(EVENT);
1627 ECase(EXPORT);
1628 ECase(START);
1629 ECase(ELEM);
1630 ECase(CODE);
1631 ECase(DATA);
1632 ECase(DATACOUNT);
1633 case wasm::WASM_SEC_CUSTOM:
1634 return S.Name;
1635 default:
1636 return createStringError(object_error::invalid_section_index, "");
1637 }
1638 #undef ECase
1639 }
1640
getSectionAddress(DataRefImpl Sec) const1641 uint64_t WasmObjectFile::getSectionAddress(DataRefImpl Sec) const { return 0; }
1642
getSectionIndex(DataRefImpl Sec) const1643 uint64_t WasmObjectFile::getSectionIndex(DataRefImpl Sec) const {
1644 return Sec.d.a;
1645 }
1646
getSectionSize(DataRefImpl Sec) const1647 uint64_t WasmObjectFile::getSectionSize(DataRefImpl Sec) const {
1648 const WasmSection &S = Sections[Sec.d.a];
1649 return S.Content.size();
1650 }
1651
1652 Expected<ArrayRef<uint8_t>>
getSectionContents(DataRefImpl Sec) const1653 WasmObjectFile::getSectionContents(DataRefImpl Sec) const {
1654 const WasmSection &S = Sections[Sec.d.a];
1655 // This will never fail since wasm sections can never be empty (user-sections
1656 // must have a name and non-user sections each have a defined structure).
1657 return S.Content;
1658 }
1659
getSectionAlignment(DataRefImpl Sec) const1660 uint64_t WasmObjectFile::getSectionAlignment(DataRefImpl Sec) const {
1661 return 1;
1662 }
1663
isSectionCompressed(DataRefImpl Sec) const1664 bool WasmObjectFile::isSectionCompressed(DataRefImpl Sec) const {
1665 return false;
1666 }
1667
isSectionText(DataRefImpl Sec) const1668 bool WasmObjectFile::isSectionText(DataRefImpl Sec) const {
1669 return getWasmSection(Sec).Type == wasm::WASM_SEC_CODE;
1670 }
1671
isSectionData(DataRefImpl Sec) const1672 bool WasmObjectFile::isSectionData(DataRefImpl Sec) const {
1673 return getWasmSection(Sec).Type == wasm::WASM_SEC_DATA;
1674 }
1675
isSectionBSS(DataRefImpl Sec) const1676 bool WasmObjectFile::isSectionBSS(DataRefImpl Sec) const { return false; }
1677
isSectionVirtual(DataRefImpl Sec) const1678 bool WasmObjectFile::isSectionVirtual(DataRefImpl Sec) const { return false; }
1679
section_rel_begin(DataRefImpl Ref) const1680 relocation_iterator WasmObjectFile::section_rel_begin(DataRefImpl Ref) const {
1681 DataRefImpl RelocRef;
1682 RelocRef.d.a = Ref.d.a;
1683 RelocRef.d.b = 0;
1684 return relocation_iterator(RelocationRef(RelocRef, this));
1685 }
1686
section_rel_end(DataRefImpl Ref) const1687 relocation_iterator WasmObjectFile::section_rel_end(DataRefImpl Ref) const {
1688 const WasmSection &Sec = getWasmSection(Ref);
1689 DataRefImpl RelocRef;
1690 RelocRef.d.a = Ref.d.a;
1691 RelocRef.d.b = Sec.Relocations.size();
1692 return relocation_iterator(RelocationRef(RelocRef, this));
1693 }
1694
moveRelocationNext(DataRefImpl & Rel) const1695 void WasmObjectFile::moveRelocationNext(DataRefImpl &Rel) const { Rel.d.b++; }
1696
getRelocationOffset(DataRefImpl Ref) const1697 uint64_t WasmObjectFile::getRelocationOffset(DataRefImpl Ref) const {
1698 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1699 return Rel.Offset;
1700 }
1701
getRelocationSymbol(DataRefImpl Ref) const1702 symbol_iterator WasmObjectFile::getRelocationSymbol(DataRefImpl Ref) const {
1703 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1704 if (Rel.Type == wasm::R_WASM_TYPE_INDEX_LEB)
1705 return symbol_end();
1706 DataRefImpl Sym;
1707 Sym.d.a = 1;
1708 Sym.d.b = Rel.Index;
1709 return symbol_iterator(SymbolRef(Sym, this));
1710 }
1711
getRelocationType(DataRefImpl Ref) const1712 uint64_t WasmObjectFile::getRelocationType(DataRefImpl Ref) const {
1713 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1714 return Rel.Type;
1715 }
1716
getRelocationTypeName(DataRefImpl Ref,SmallVectorImpl<char> & Result) const1717 void WasmObjectFile::getRelocationTypeName(
1718 DataRefImpl Ref, SmallVectorImpl<char> &Result) const {
1719 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1720 StringRef Res = "Unknown";
1721
1722 #define WASM_RELOC(name, value) \
1723 case wasm::name: \
1724 Res = #name; \
1725 break;
1726
1727 switch (Rel.Type) {
1728 #include "llvm/BinaryFormat/WasmRelocs.def"
1729 }
1730
1731 #undef WASM_RELOC
1732
1733 Result.append(Res.begin(), Res.end());
1734 }
1735
section_begin() const1736 section_iterator WasmObjectFile::section_begin() const {
1737 DataRefImpl Ref;
1738 Ref.d.a = 0;
1739 return section_iterator(SectionRef(Ref, this));
1740 }
1741
section_end() const1742 section_iterator WasmObjectFile::section_end() const {
1743 DataRefImpl Ref;
1744 Ref.d.a = Sections.size();
1745 return section_iterator(SectionRef(Ref, this));
1746 }
1747
getBytesInAddress() const1748 uint8_t WasmObjectFile::getBytesInAddress() const {
1749 return HasMemory64 ? 8 : 4;
1750 }
1751
getFileFormatName() const1752 StringRef WasmObjectFile::getFileFormatName() const { return "WASM"; }
1753
getArch() const1754 Triple::ArchType WasmObjectFile::getArch() const {
1755 return HasMemory64 ? Triple::wasm64 : Triple::wasm32;
1756 }
1757
getFeatures() const1758 SubtargetFeatures WasmObjectFile::getFeatures() const {
1759 return SubtargetFeatures();
1760 }
1761
isRelocatableObject() const1762 bool WasmObjectFile::isRelocatableObject() const { return HasLinkingSection; }
1763
isSharedObject() const1764 bool WasmObjectFile::isSharedObject() const { return HasDylinkSection; }
1765
getWasmSection(DataRefImpl Ref) const1766 const WasmSection &WasmObjectFile::getWasmSection(DataRefImpl Ref) const {
1767 assert(Ref.d.a < Sections.size());
1768 return Sections[Ref.d.a];
1769 }
1770
1771 const WasmSection &
getWasmSection(const SectionRef & Section) const1772 WasmObjectFile::getWasmSection(const SectionRef &Section) const {
1773 return getWasmSection(Section.getRawDataRefImpl());
1774 }
1775
1776 const wasm::WasmRelocation &
getWasmRelocation(const RelocationRef & Ref) const1777 WasmObjectFile::getWasmRelocation(const RelocationRef &Ref) const {
1778 return getWasmRelocation(Ref.getRawDataRefImpl());
1779 }
1780
1781 const wasm::WasmRelocation &
getWasmRelocation(DataRefImpl Ref) const1782 WasmObjectFile::getWasmRelocation(DataRefImpl Ref) const {
1783 assert(Ref.d.a < Sections.size());
1784 const WasmSection &Sec = Sections[Ref.d.a];
1785 assert(Ref.d.b < Sec.Relocations.size());
1786 return Sec.Relocations[Ref.d.b];
1787 }
1788
getSectionOrder(unsigned ID,StringRef CustomSectionName)1789 int WasmSectionOrderChecker::getSectionOrder(unsigned ID,
1790 StringRef CustomSectionName) {
1791 switch (ID) {
1792 case wasm::WASM_SEC_CUSTOM:
1793 return StringSwitch<unsigned>(CustomSectionName)
1794 .Case("dylink", WASM_SEC_ORDER_DYLINK)
1795 .Case("linking", WASM_SEC_ORDER_LINKING)
1796 .StartsWith("reloc.", WASM_SEC_ORDER_RELOC)
1797 .Case("name", WASM_SEC_ORDER_NAME)
1798 .Case("producers", WASM_SEC_ORDER_PRODUCERS)
1799 .Case("target_features", WASM_SEC_ORDER_TARGET_FEATURES)
1800 .Default(WASM_SEC_ORDER_NONE);
1801 case wasm::WASM_SEC_TYPE:
1802 return WASM_SEC_ORDER_TYPE;
1803 case wasm::WASM_SEC_IMPORT:
1804 return WASM_SEC_ORDER_IMPORT;
1805 case wasm::WASM_SEC_FUNCTION:
1806 return WASM_SEC_ORDER_FUNCTION;
1807 case wasm::WASM_SEC_TABLE:
1808 return WASM_SEC_ORDER_TABLE;
1809 case wasm::WASM_SEC_MEMORY:
1810 return WASM_SEC_ORDER_MEMORY;
1811 case wasm::WASM_SEC_GLOBAL:
1812 return WASM_SEC_ORDER_GLOBAL;
1813 case wasm::WASM_SEC_EXPORT:
1814 return WASM_SEC_ORDER_EXPORT;
1815 case wasm::WASM_SEC_START:
1816 return WASM_SEC_ORDER_START;
1817 case wasm::WASM_SEC_ELEM:
1818 return WASM_SEC_ORDER_ELEM;
1819 case wasm::WASM_SEC_CODE:
1820 return WASM_SEC_ORDER_CODE;
1821 case wasm::WASM_SEC_DATA:
1822 return WASM_SEC_ORDER_DATA;
1823 case wasm::WASM_SEC_DATACOUNT:
1824 return WASM_SEC_ORDER_DATACOUNT;
1825 case wasm::WASM_SEC_EVENT:
1826 return WASM_SEC_ORDER_EVENT;
1827 default:
1828 return WASM_SEC_ORDER_NONE;
1829 }
1830 }
1831
1832 // Represents the edges in a directed graph where any node B reachable from node
1833 // A is not allowed to appear before A in the section ordering, but may appear
1834 // afterward.
1835 int WasmSectionOrderChecker::DisallowedPredecessors
1836 [WASM_NUM_SEC_ORDERS][WASM_NUM_SEC_ORDERS] = {
1837 // WASM_SEC_ORDER_NONE
1838 {},
1839 // WASM_SEC_ORDER_TYPE
1840 {WASM_SEC_ORDER_TYPE, WASM_SEC_ORDER_IMPORT},
1841 // WASM_SEC_ORDER_IMPORT
1842 {WASM_SEC_ORDER_IMPORT, WASM_SEC_ORDER_FUNCTION},
1843 // WASM_SEC_ORDER_FUNCTION
1844 {WASM_SEC_ORDER_FUNCTION, WASM_SEC_ORDER_TABLE},
1845 // WASM_SEC_ORDER_TABLE
1846 {WASM_SEC_ORDER_TABLE, WASM_SEC_ORDER_MEMORY},
1847 // WASM_SEC_ORDER_MEMORY
1848 {WASM_SEC_ORDER_MEMORY, WASM_SEC_ORDER_EVENT},
1849 // WASM_SEC_ORDER_EVENT
1850 {WASM_SEC_ORDER_EVENT, WASM_SEC_ORDER_GLOBAL},
1851 // WASM_SEC_ORDER_GLOBAL
1852 {WASM_SEC_ORDER_GLOBAL, WASM_SEC_ORDER_EXPORT},
1853 // WASM_SEC_ORDER_EXPORT
1854 {WASM_SEC_ORDER_EXPORT, WASM_SEC_ORDER_START},
1855 // WASM_SEC_ORDER_START
1856 {WASM_SEC_ORDER_START, WASM_SEC_ORDER_ELEM},
1857 // WASM_SEC_ORDER_ELEM
1858 {WASM_SEC_ORDER_ELEM, WASM_SEC_ORDER_DATACOUNT},
1859 // WASM_SEC_ORDER_DATACOUNT
1860 {WASM_SEC_ORDER_DATACOUNT, WASM_SEC_ORDER_CODE},
1861 // WASM_SEC_ORDER_CODE
1862 {WASM_SEC_ORDER_CODE, WASM_SEC_ORDER_DATA},
1863 // WASM_SEC_ORDER_DATA
1864 {WASM_SEC_ORDER_DATA, WASM_SEC_ORDER_LINKING},
1865
1866 // Custom Sections
1867 // WASM_SEC_ORDER_DYLINK
1868 {WASM_SEC_ORDER_DYLINK, WASM_SEC_ORDER_TYPE},
1869 // WASM_SEC_ORDER_LINKING
1870 {WASM_SEC_ORDER_LINKING, WASM_SEC_ORDER_RELOC, WASM_SEC_ORDER_NAME},
1871 // WASM_SEC_ORDER_RELOC (can be repeated)
1872 {},
1873 // WASM_SEC_ORDER_NAME
1874 {WASM_SEC_ORDER_NAME, WASM_SEC_ORDER_PRODUCERS},
1875 // WASM_SEC_ORDER_PRODUCERS
1876 {WASM_SEC_ORDER_PRODUCERS, WASM_SEC_ORDER_TARGET_FEATURES},
1877 // WASM_SEC_ORDER_TARGET_FEATURES
1878 {WASM_SEC_ORDER_TARGET_FEATURES}};
1879
isValidSectionOrder(unsigned ID,StringRef CustomSectionName)1880 bool WasmSectionOrderChecker::isValidSectionOrder(unsigned ID,
1881 StringRef CustomSectionName) {
1882 int Order = getSectionOrder(ID, CustomSectionName);
1883 if (Order == WASM_SEC_ORDER_NONE)
1884 return true;
1885
1886 // Disallowed predecessors we need to check for
1887 SmallVector<int, WASM_NUM_SEC_ORDERS> WorkList;
1888
1889 // Keep track of completed checks to avoid repeating work
1890 bool Checked[WASM_NUM_SEC_ORDERS] = {};
1891
1892 int Curr = Order;
1893 while (true) {
1894 // Add new disallowed predecessors to work list
1895 for (size_t I = 0;; ++I) {
1896 int Next = DisallowedPredecessors[Curr][I];
1897 if (Next == WASM_SEC_ORDER_NONE)
1898 break;
1899 if (Checked[Next])
1900 continue;
1901 WorkList.push_back(Next);
1902 Checked[Next] = true;
1903 }
1904
1905 if (WorkList.empty())
1906 break;
1907
1908 // Consider next disallowed predecessor
1909 Curr = WorkList.pop_back_val();
1910 if (Seen[Curr])
1911 return false;
1912 }
1913
1914 // Have not seen any disallowed predecessors
1915 Seen[Order] = true;
1916 return true;
1917 }
1918