1 //===- WasmObjectFile.cpp - Wasm object file implementation ---------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "llvm/ADT/ArrayRef.h"
11 #include "llvm/ADT/DenseSet.h"
12 #include "llvm/ADT/STLExtras.h"
13 #include "llvm/ADT/StringRef.h"
14 #include "llvm/ADT/StringSet.h"
15 #include "llvm/ADT/Triple.h"
16 #include "llvm/BinaryFormat/Wasm.h"
17 #include "llvm/MC/SubtargetFeature.h"
18 #include "llvm/Object/Binary.h"
19 #include "llvm/Object/Error.h"
20 #include "llvm/Object/ObjectFile.h"
21 #include "llvm/Object/SymbolicFile.h"
22 #include "llvm/Object/Wasm.h"
23 #include "llvm/Support/Endian.h"
24 #include "llvm/Support/Error.h"
25 #include "llvm/Support/ErrorHandling.h"
26 #include "llvm/Support/LEB128.h"
27 #include "llvm/Support/ScopedPrinter.h"
28 #include <algorithm>
29 #include <cassert>
30 #include <cstdint>
31 #include <cstring>
32 #include <system_error>
33
34 #define DEBUG_TYPE "wasm-object"
35
36 using namespace llvm;
37 using namespace object;
38
print(raw_ostream & Out) const39 void WasmSymbol::print(raw_ostream &Out) const {
40 Out << "Name=" << Info.Name
41 << ", Kind=" << toString(wasm::WasmSymbolType(Info.Kind))
42 << ", Flags=" << Info.Flags;
43 if (!isTypeData()) {
44 Out << ", ElemIndex=" << Info.ElementIndex;
45 } else if (isDefined()) {
46 Out << ", Segment=" << Info.DataRef.Segment;
47 Out << ", Offset=" << Info.DataRef.Offset;
48 Out << ", Size=" << Info.DataRef.Size;
49 }
50 }
51
52 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump() const53 LLVM_DUMP_METHOD void WasmSymbol::dump() const { print(dbgs()); }
54 #endif
55
56 Expected<std::unique_ptr<WasmObjectFile>>
createWasmObjectFile(MemoryBufferRef Buffer)57 ObjectFile::createWasmObjectFile(MemoryBufferRef Buffer) {
58 Error Err = Error::success();
59 auto ObjectFile = llvm::make_unique<WasmObjectFile>(Buffer, Err);
60 if (Err)
61 return std::move(Err);
62
63 return std::move(ObjectFile);
64 }
65
66 #define VARINT7_MAX ((1 << 7) - 1)
67 #define VARINT7_MIN (-(1 << 7))
68 #define VARUINT7_MAX (1 << 7)
69 #define VARUINT1_MAX (1)
70
readUint8(WasmObjectFile::ReadContext & Ctx)71 static uint8_t readUint8(WasmObjectFile::ReadContext &Ctx) {
72 if (Ctx.Ptr == Ctx.End)
73 report_fatal_error("EOF while reading uint8");
74 return *Ctx.Ptr++;
75 }
76
readUint32(WasmObjectFile::ReadContext & Ctx)77 static uint32_t readUint32(WasmObjectFile::ReadContext &Ctx) {
78 if (Ctx.Ptr + 4 > Ctx.End)
79 report_fatal_error("EOF while reading uint32");
80 uint32_t Result = support::endian::read32le(Ctx.Ptr);
81 Ctx.Ptr += 4;
82 return Result;
83 }
84
readFloat32(WasmObjectFile::ReadContext & Ctx)85 static int32_t readFloat32(WasmObjectFile::ReadContext &Ctx) {
86 if (Ctx.Ptr + 4 > Ctx.End)
87 report_fatal_error("EOF while reading float64");
88 int32_t Result = 0;
89 memcpy(&Result, Ctx.Ptr, sizeof(Result));
90 Ctx.Ptr += sizeof(Result);
91 return Result;
92 }
93
readFloat64(WasmObjectFile::ReadContext & Ctx)94 static int64_t readFloat64(WasmObjectFile::ReadContext &Ctx) {
95 if (Ctx.Ptr + 8 > Ctx.End)
96 report_fatal_error("EOF while reading float64");
97 int64_t Result = 0;
98 memcpy(&Result, Ctx.Ptr, sizeof(Result));
99 Ctx.Ptr += sizeof(Result);
100 return Result;
101 }
102
readULEB128(WasmObjectFile::ReadContext & Ctx)103 static uint64_t readULEB128(WasmObjectFile::ReadContext &Ctx) {
104 unsigned Count;
105 const char *Error = nullptr;
106 uint64_t Result = decodeULEB128(Ctx.Ptr, &Count, Ctx.End, &Error);
107 if (Error)
108 report_fatal_error(Error);
109 Ctx.Ptr += Count;
110 return Result;
111 }
112
readString(WasmObjectFile::ReadContext & Ctx)113 static StringRef readString(WasmObjectFile::ReadContext &Ctx) {
114 uint32_t StringLen = readULEB128(Ctx);
115 if (Ctx.Ptr + StringLen > Ctx.End)
116 report_fatal_error("EOF while reading string");
117 StringRef Return =
118 StringRef(reinterpret_cast<const char *>(Ctx.Ptr), StringLen);
119 Ctx.Ptr += StringLen;
120 return Return;
121 }
122
readLEB128(WasmObjectFile::ReadContext & Ctx)123 static int64_t readLEB128(WasmObjectFile::ReadContext &Ctx) {
124 unsigned Count;
125 const char *Error = nullptr;
126 uint64_t Result = decodeSLEB128(Ctx.Ptr, &Count, Ctx.End, &Error);
127 if (Error)
128 report_fatal_error(Error);
129 Ctx.Ptr += Count;
130 return Result;
131 }
132
readVaruint1(WasmObjectFile::ReadContext & Ctx)133 static uint8_t readVaruint1(WasmObjectFile::ReadContext &Ctx) {
134 int64_t result = readLEB128(Ctx);
135 if (result > VARUINT1_MAX || result < 0)
136 report_fatal_error("LEB is outside Varuint1 range");
137 return result;
138 }
139
readVarint32(WasmObjectFile::ReadContext & Ctx)140 static int32_t readVarint32(WasmObjectFile::ReadContext &Ctx) {
141 int64_t result = readLEB128(Ctx);
142 if (result > INT32_MAX || result < INT32_MIN)
143 report_fatal_error("LEB is outside Varint32 range");
144 return result;
145 }
146
readVaruint32(WasmObjectFile::ReadContext & Ctx)147 static uint32_t readVaruint32(WasmObjectFile::ReadContext &Ctx) {
148 uint64_t result = readULEB128(Ctx);
149 if (result > UINT32_MAX)
150 report_fatal_error("LEB is outside Varuint32 range");
151 return result;
152 }
153
readVarint64(WasmObjectFile::ReadContext & Ctx)154 static int64_t readVarint64(WasmObjectFile::ReadContext &Ctx) {
155 return readLEB128(Ctx);
156 }
157
readOpcode(WasmObjectFile::ReadContext & Ctx)158 static uint8_t readOpcode(WasmObjectFile::ReadContext &Ctx) {
159 return readUint8(Ctx);
160 }
161
readInitExpr(wasm::WasmInitExpr & Expr,WasmObjectFile::ReadContext & Ctx)162 static Error readInitExpr(wasm::WasmInitExpr &Expr,
163 WasmObjectFile::ReadContext &Ctx) {
164 Expr.Opcode = readOpcode(Ctx);
165
166 switch (Expr.Opcode) {
167 case wasm::WASM_OPCODE_I32_CONST:
168 Expr.Value.Int32 = readVarint32(Ctx);
169 break;
170 case wasm::WASM_OPCODE_I64_CONST:
171 Expr.Value.Int64 = readVarint64(Ctx);
172 break;
173 case wasm::WASM_OPCODE_F32_CONST:
174 Expr.Value.Float32 = readFloat32(Ctx);
175 break;
176 case wasm::WASM_OPCODE_F64_CONST:
177 Expr.Value.Float64 = readFloat64(Ctx);
178 break;
179 case wasm::WASM_OPCODE_GLOBAL_GET:
180 Expr.Value.Global = readULEB128(Ctx);
181 break;
182 default:
183 return make_error<GenericBinaryError>("Invalid opcode in init_expr",
184 object_error::parse_failed);
185 }
186
187 uint8_t EndOpcode = readOpcode(Ctx);
188 if (EndOpcode != wasm::WASM_OPCODE_END) {
189 return make_error<GenericBinaryError>("Invalid init_expr",
190 object_error::parse_failed);
191 }
192 return Error::success();
193 }
194
readLimits(WasmObjectFile::ReadContext & Ctx)195 static wasm::WasmLimits readLimits(WasmObjectFile::ReadContext &Ctx) {
196 wasm::WasmLimits Result;
197 Result.Flags = readVaruint32(Ctx);
198 Result.Initial = readVaruint32(Ctx);
199 if (Result.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX)
200 Result.Maximum = readVaruint32(Ctx);
201 return Result;
202 }
203
readTable(WasmObjectFile::ReadContext & Ctx)204 static wasm::WasmTable readTable(WasmObjectFile::ReadContext &Ctx) {
205 wasm::WasmTable Table;
206 Table.ElemType = readUint8(Ctx);
207 Table.Limits = readLimits(Ctx);
208 return Table;
209 }
210
readSection(WasmSection & Section,WasmObjectFile::ReadContext & Ctx,WasmSectionOrderChecker & Checker)211 static Error readSection(WasmSection &Section, WasmObjectFile::ReadContext &Ctx,
212 WasmSectionOrderChecker &Checker) {
213 Section.Offset = Ctx.Ptr - Ctx.Start;
214 Section.Type = readUint8(Ctx);
215 LLVM_DEBUG(dbgs() << "readSection type=" << Section.Type << "\n");
216 uint32_t Size = readVaruint32(Ctx);
217 if (Size == 0)
218 return make_error<StringError>("Zero length section",
219 object_error::parse_failed);
220 if (Ctx.Ptr + Size > Ctx.End)
221 return make_error<StringError>("Section too large",
222 object_error::parse_failed);
223 if (Section.Type == wasm::WASM_SEC_CUSTOM) {
224 WasmObjectFile::ReadContext SectionCtx;
225 SectionCtx.Start = Ctx.Ptr;
226 SectionCtx.Ptr = Ctx.Ptr;
227 SectionCtx.End = Ctx.Ptr + Size;
228
229 Section.Name = readString(SectionCtx);
230
231 uint32_t SectionNameSize = SectionCtx.Ptr - SectionCtx.Start;
232 Ctx.Ptr += SectionNameSize;
233 Size -= SectionNameSize;
234 }
235
236 if (!Checker.isValidSectionOrder(Section.Type, Section.Name)) {
237 return make_error<StringError>("Out of order section type: " +
238 llvm::to_string(Section.Type),
239 object_error::parse_failed);
240 }
241
242 Section.Content = ArrayRef<uint8_t>(Ctx.Ptr, Size);
243 Ctx.Ptr += Size;
244 return Error::success();
245 }
246
WasmObjectFile(MemoryBufferRef Buffer,Error & Err)247 WasmObjectFile::WasmObjectFile(MemoryBufferRef Buffer, Error &Err)
248 : ObjectFile(Binary::ID_Wasm, Buffer) {
249 ErrorAsOutParameter ErrAsOutParam(&Err);
250 Header.Magic = getData().substr(0, 4);
251 if (Header.Magic != StringRef("\0asm", 4)) {
252 Err =
253 make_error<StringError>("Bad magic number", object_error::parse_failed);
254 return;
255 }
256
257 ReadContext Ctx;
258 Ctx.Start = getPtr(0);
259 Ctx.Ptr = Ctx.Start + 4;
260 Ctx.End = Ctx.Start + getData().size();
261
262 if (Ctx.Ptr + 4 > Ctx.End) {
263 Err = make_error<StringError>("Missing version number",
264 object_error::parse_failed);
265 return;
266 }
267
268 Header.Version = readUint32(Ctx);
269 if (Header.Version != wasm::WasmVersion) {
270 Err = make_error<StringError>("Bad version number",
271 object_error::parse_failed);
272 return;
273 }
274
275 WasmSection Sec;
276 WasmSectionOrderChecker Checker;
277 while (Ctx.Ptr < Ctx.End) {
278 if ((Err = readSection(Sec, Ctx, Checker)))
279 return;
280 if ((Err = parseSection(Sec)))
281 return;
282
283 Sections.push_back(Sec);
284 }
285 }
286
parseSection(WasmSection & Sec)287 Error WasmObjectFile::parseSection(WasmSection &Sec) {
288 ReadContext Ctx;
289 Ctx.Start = Sec.Content.data();
290 Ctx.End = Ctx.Start + Sec.Content.size();
291 Ctx.Ptr = Ctx.Start;
292 switch (Sec.Type) {
293 case wasm::WASM_SEC_CUSTOM:
294 return parseCustomSection(Sec, Ctx);
295 case wasm::WASM_SEC_TYPE:
296 return parseTypeSection(Ctx);
297 case wasm::WASM_SEC_IMPORT:
298 return parseImportSection(Ctx);
299 case wasm::WASM_SEC_FUNCTION:
300 return parseFunctionSection(Ctx);
301 case wasm::WASM_SEC_TABLE:
302 return parseTableSection(Ctx);
303 case wasm::WASM_SEC_MEMORY:
304 return parseMemorySection(Ctx);
305 case wasm::WASM_SEC_GLOBAL:
306 return parseGlobalSection(Ctx);
307 case wasm::WASM_SEC_EVENT:
308 return parseEventSection(Ctx);
309 case wasm::WASM_SEC_EXPORT:
310 return parseExportSection(Ctx);
311 case wasm::WASM_SEC_START:
312 return parseStartSection(Ctx);
313 case wasm::WASM_SEC_ELEM:
314 return parseElemSection(Ctx);
315 case wasm::WASM_SEC_CODE:
316 return parseCodeSection(Ctx);
317 case wasm::WASM_SEC_DATA:
318 return parseDataSection(Ctx);
319 default:
320 return make_error<GenericBinaryError>("Bad section type",
321 object_error::parse_failed);
322 }
323 }
324
parseDylinkSection(ReadContext & Ctx)325 Error WasmObjectFile::parseDylinkSection(ReadContext &Ctx) {
326 // See https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md
327 DylinkInfo.MemorySize = readVaruint32(Ctx);
328 DylinkInfo.MemoryAlignment = readVaruint32(Ctx);
329 DylinkInfo.TableSize = readVaruint32(Ctx);
330 DylinkInfo.TableAlignment = readVaruint32(Ctx);
331 uint32_t Count = readVaruint32(Ctx);
332 while (Count--) {
333 DylinkInfo.Needed.push_back(readString(Ctx));
334 }
335 if (Ctx.Ptr != Ctx.End)
336 return make_error<GenericBinaryError>("dylink section ended prematurely",
337 object_error::parse_failed);
338 return Error::success();
339 }
340
parseNameSection(ReadContext & Ctx)341 Error WasmObjectFile::parseNameSection(ReadContext &Ctx) {
342 llvm::DenseSet<uint64_t> Seen;
343 if (Functions.size() != FunctionTypes.size()) {
344 return make_error<GenericBinaryError>("Names must come after code section",
345 object_error::parse_failed);
346 }
347
348 while (Ctx.Ptr < Ctx.End) {
349 uint8_t Type = readUint8(Ctx);
350 uint32_t Size = readVaruint32(Ctx);
351 const uint8_t *SubSectionEnd = Ctx.Ptr + Size;
352 switch (Type) {
353 case wasm::WASM_NAMES_FUNCTION: {
354 uint32_t Count = readVaruint32(Ctx);
355 while (Count--) {
356 uint32_t Index = readVaruint32(Ctx);
357 if (!Seen.insert(Index).second)
358 return make_error<GenericBinaryError>("Function named more than once",
359 object_error::parse_failed);
360 StringRef Name = readString(Ctx);
361 if (!isValidFunctionIndex(Index) || Name.empty())
362 return make_error<GenericBinaryError>("Invalid name entry",
363 object_error::parse_failed);
364 DebugNames.push_back(wasm::WasmFunctionName{Index, Name});
365 if (isDefinedFunctionIndex(Index))
366 getDefinedFunction(Index).DebugName = Name;
367 }
368 break;
369 }
370 // Ignore local names for now
371 case wasm::WASM_NAMES_LOCAL:
372 default:
373 Ctx.Ptr += Size;
374 break;
375 }
376 if (Ctx.Ptr != SubSectionEnd)
377 return make_error<GenericBinaryError>(
378 "Name sub-section ended prematurely", object_error::parse_failed);
379 }
380
381 if (Ctx.Ptr != Ctx.End)
382 return make_error<GenericBinaryError>("Name section ended prematurely",
383 object_error::parse_failed);
384 return Error::success();
385 }
386
parseLinkingSection(ReadContext & Ctx)387 Error WasmObjectFile::parseLinkingSection(ReadContext &Ctx) {
388 HasLinkingSection = true;
389 if (Functions.size() != FunctionTypes.size()) {
390 return make_error<GenericBinaryError>(
391 "Linking data must come after code section",
392 object_error::parse_failed);
393 }
394
395 LinkingData.Version = readVaruint32(Ctx);
396 if (LinkingData.Version != wasm::WasmMetadataVersion) {
397 return make_error<GenericBinaryError>(
398 "Unexpected metadata version: " + Twine(LinkingData.Version) +
399 " (Expected: " + Twine(wasm::WasmMetadataVersion) + ")",
400 object_error::parse_failed);
401 }
402
403 const uint8_t *OrigEnd = Ctx.End;
404 while (Ctx.Ptr < OrigEnd) {
405 Ctx.End = OrigEnd;
406 uint8_t Type = readUint8(Ctx);
407 uint32_t Size = readVaruint32(Ctx);
408 LLVM_DEBUG(dbgs() << "readSubsection type=" << int(Type) << " size=" << Size
409 << "\n");
410 Ctx.End = Ctx.Ptr + Size;
411 switch (Type) {
412 case wasm::WASM_SYMBOL_TABLE:
413 if (Error Err = parseLinkingSectionSymtab(Ctx))
414 return Err;
415 break;
416 case wasm::WASM_SEGMENT_INFO: {
417 uint32_t Count = readVaruint32(Ctx);
418 if (Count > DataSegments.size())
419 return make_error<GenericBinaryError>("Too many segment names",
420 object_error::parse_failed);
421 for (uint32_t i = 0; i < Count; i++) {
422 DataSegments[i].Data.Name = readString(Ctx);
423 DataSegments[i].Data.Alignment = readVaruint32(Ctx);
424 DataSegments[i].Data.Flags = readVaruint32(Ctx);
425 }
426 break;
427 }
428 case wasm::WASM_INIT_FUNCS: {
429 uint32_t Count = readVaruint32(Ctx);
430 LinkingData.InitFunctions.reserve(Count);
431 for (uint32_t i = 0; i < Count; i++) {
432 wasm::WasmInitFunc Init;
433 Init.Priority = readVaruint32(Ctx);
434 Init.Symbol = readVaruint32(Ctx);
435 if (!isValidFunctionSymbol(Init.Symbol))
436 return make_error<GenericBinaryError>("Invalid function symbol: " +
437 Twine(Init.Symbol),
438 object_error::parse_failed);
439 LinkingData.InitFunctions.emplace_back(Init);
440 }
441 break;
442 }
443 case wasm::WASM_COMDAT_INFO:
444 if (Error Err = parseLinkingSectionComdat(Ctx))
445 return Err;
446 break;
447 default:
448 Ctx.Ptr += Size;
449 break;
450 }
451 if (Ctx.Ptr != Ctx.End)
452 return make_error<GenericBinaryError>(
453 "Linking sub-section ended prematurely", object_error::parse_failed);
454 }
455 if (Ctx.Ptr != OrigEnd)
456 return make_error<GenericBinaryError>("Linking section ended prematurely",
457 object_error::parse_failed);
458 return Error::success();
459 }
460
parseLinkingSectionSymtab(ReadContext & Ctx)461 Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
462 uint32_t Count = readVaruint32(Ctx);
463 LinkingData.SymbolTable.reserve(Count);
464 Symbols.reserve(Count);
465 StringSet<> SymbolNames;
466
467 std::vector<wasm::WasmImport *> ImportedGlobals;
468 std::vector<wasm::WasmImport *> ImportedFunctions;
469 std::vector<wasm::WasmImport *> ImportedEvents;
470 ImportedGlobals.reserve(Imports.size());
471 ImportedFunctions.reserve(Imports.size());
472 ImportedEvents.reserve(Imports.size());
473 for (auto &I : Imports) {
474 if (I.Kind == wasm::WASM_EXTERNAL_FUNCTION)
475 ImportedFunctions.emplace_back(&I);
476 else if (I.Kind == wasm::WASM_EXTERNAL_GLOBAL)
477 ImportedGlobals.emplace_back(&I);
478 else if (I.Kind == wasm::WASM_EXTERNAL_EVENT)
479 ImportedEvents.emplace_back(&I);
480 }
481
482 while (Count--) {
483 wasm::WasmSymbolInfo Info;
484 const wasm::WasmSignature *Signature = nullptr;
485 const wasm::WasmGlobalType *GlobalType = nullptr;
486 const wasm::WasmEventType *EventType = nullptr;
487
488 Info.Kind = readUint8(Ctx);
489 Info.Flags = readVaruint32(Ctx);
490 bool IsDefined = (Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0;
491
492 switch (Info.Kind) {
493 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
494 Info.ElementIndex = readVaruint32(Ctx);
495 if (!isValidFunctionIndex(Info.ElementIndex) ||
496 IsDefined != isDefinedFunctionIndex(Info.ElementIndex))
497 return make_error<GenericBinaryError>("invalid function symbol index",
498 object_error::parse_failed);
499 if (IsDefined) {
500 Info.Name = readString(Ctx);
501 unsigned FuncIndex = Info.ElementIndex - NumImportedFunctions;
502 Signature = &Signatures[FunctionTypes[FuncIndex]];
503 wasm::WasmFunction &Function = Functions[FuncIndex];
504 if (Function.SymbolName.empty())
505 Function.SymbolName = Info.Name;
506 } else {
507 wasm::WasmImport &Import = *ImportedFunctions[Info.ElementIndex];
508 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0)
509 Info.Name = readString(Ctx);
510 else
511 Info.Name = Import.Field;
512 Signature = &Signatures[Import.SigIndex];
513 Info.ImportName = Import.Field;
514 Info.ImportModule = Import.Module;
515 }
516 break;
517
518 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
519 Info.ElementIndex = readVaruint32(Ctx);
520 if (!isValidGlobalIndex(Info.ElementIndex) ||
521 IsDefined != isDefinedGlobalIndex(Info.ElementIndex))
522 return make_error<GenericBinaryError>("invalid global symbol index",
523 object_error::parse_failed);
524 if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
525 wasm::WASM_SYMBOL_BINDING_WEAK)
526 return make_error<GenericBinaryError>("undefined weak global symbol",
527 object_error::parse_failed);
528 if (IsDefined) {
529 Info.Name = readString(Ctx);
530 unsigned GlobalIndex = Info.ElementIndex - NumImportedGlobals;
531 wasm::WasmGlobal &Global = Globals[GlobalIndex];
532 GlobalType = &Global.Type;
533 if (Global.SymbolName.empty())
534 Global.SymbolName = Info.Name;
535 } else {
536 wasm::WasmImport &Import = *ImportedGlobals[Info.ElementIndex];
537 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0)
538 Info.Name = readString(Ctx);
539 else
540 Info.Name = Import.Field;
541 GlobalType = &Import.Global;
542 Info.ImportName = Import.Field;
543 Info.ImportModule = Import.Module;
544 }
545 break;
546
547 case wasm::WASM_SYMBOL_TYPE_DATA:
548 Info.Name = readString(Ctx);
549 if (IsDefined) {
550 uint32_t Index = readVaruint32(Ctx);
551 if (Index >= DataSegments.size())
552 return make_error<GenericBinaryError>("invalid data symbol index",
553 object_error::parse_failed);
554 uint32_t Offset = readVaruint32(Ctx);
555 uint32_t Size = readVaruint32(Ctx);
556 if (Offset + Size > DataSegments[Index].Data.Content.size())
557 return make_error<GenericBinaryError>("invalid data symbol offset",
558 object_error::parse_failed);
559 Info.DataRef = wasm::WasmDataReference{Index, Offset, Size};
560 }
561 break;
562
563 case wasm::WASM_SYMBOL_TYPE_SECTION: {
564 if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) !=
565 wasm::WASM_SYMBOL_BINDING_LOCAL)
566 return make_error<GenericBinaryError>(
567 "Section symbols must have local binding",
568 object_error::parse_failed);
569 Info.ElementIndex = readVaruint32(Ctx);
570 // Use somewhat unique section name as symbol name.
571 StringRef SectionName = Sections[Info.ElementIndex].Name;
572 Info.Name = SectionName;
573 break;
574 }
575
576 case wasm::WASM_SYMBOL_TYPE_EVENT: {
577 Info.ElementIndex = readVaruint32(Ctx);
578 if (!isValidEventIndex(Info.ElementIndex) ||
579 IsDefined != isDefinedEventIndex(Info.ElementIndex))
580 return make_error<GenericBinaryError>("invalid event symbol index",
581 object_error::parse_failed);
582 if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
583 wasm::WASM_SYMBOL_BINDING_WEAK)
584 return make_error<GenericBinaryError>("undefined weak global symbol",
585 object_error::parse_failed);
586 if (IsDefined) {
587 Info.Name = readString(Ctx);
588 unsigned EventIndex = Info.ElementIndex - NumImportedEvents;
589 wasm::WasmEvent &Event = Events[EventIndex];
590 Signature = &Signatures[Event.Type.SigIndex];
591 EventType = &Event.Type;
592 if (Event.SymbolName.empty())
593 Event.SymbolName = Info.Name;
594
595 } else {
596 wasm::WasmImport &Import = *ImportedEvents[Info.ElementIndex];
597 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0)
598 Info.Name = readString(Ctx);
599 else
600 Info.Name = Import.Field;
601 EventType = &Import.Event;
602 Signature = &Signatures[EventType->SigIndex];
603 Info.ImportName = Import.Field;
604 Info.ImportModule = Import.Module;
605 }
606 break;
607 }
608
609 default:
610 return make_error<GenericBinaryError>("Invalid symbol type",
611 object_error::parse_failed);
612 }
613
614 if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) !=
615 wasm::WASM_SYMBOL_BINDING_LOCAL &&
616 !SymbolNames.insert(Info.Name).second)
617 return make_error<GenericBinaryError>("Duplicate symbol name " +
618 Twine(Info.Name),
619 object_error::parse_failed);
620 LinkingData.SymbolTable.emplace_back(Info);
621 Symbols.emplace_back(LinkingData.SymbolTable.back(), GlobalType, EventType,
622 Signature);
623 LLVM_DEBUG(dbgs() << "Adding symbol: " << Symbols.back() << "\n");
624 }
625
626 return Error::success();
627 }
628
parseLinkingSectionComdat(ReadContext & Ctx)629 Error WasmObjectFile::parseLinkingSectionComdat(ReadContext &Ctx) {
630 uint32_t ComdatCount = readVaruint32(Ctx);
631 StringSet<> ComdatSet;
632 for (unsigned ComdatIndex = 0; ComdatIndex < ComdatCount; ++ComdatIndex) {
633 StringRef Name = readString(Ctx);
634 if (Name.empty() || !ComdatSet.insert(Name).second)
635 return make_error<GenericBinaryError>("Bad/duplicate COMDAT name " +
636 Twine(Name),
637 object_error::parse_failed);
638 LinkingData.Comdats.emplace_back(Name);
639 uint32_t Flags = readVaruint32(Ctx);
640 if (Flags != 0)
641 return make_error<GenericBinaryError>("Unsupported COMDAT flags",
642 object_error::parse_failed);
643
644 uint32_t EntryCount = readVaruint32(Ctx);
645 while (EntryCount--) {
646 unsigned Kind = readVaruint32(Ctx);
647 unsigned Index = readVaruint32(Ctx);
648 switch (Kind) {
649 default:
650 return make_error<GenericBinaryError>("Invalid COMDAT entry type",
651 object_error::parse_failed);
652 case wasm::WASM_COMDAT_DATA:
653 if (Index >= DataSegments.size())
654 return make_error<GenericBinaryError>(
655 "COMDAT data index out of range", object_error::parse_failed);
656 if (DataSegments[Index].Data.Comdat != UINT32_MAX)
657 return make_error<GenericBinaryError>("Data segment in two COMDATs",
658 object_error::parse_failed);
659 DataSegments[Index].Data.Comdat = ComdatIndex;
660 break;
661 case wasm::WASM_COMDAT_FUNCTION:
662 if (!isDefinedFunctionIndex(Index))
663 return make_error<GenericBinaryError>(
664 "COMDAT function index out of range", object_error::parse_failed);
665 if (getDefinedFunction(Index).Comdat != UINT32_MAX)
666 return make_error<GenericBinaryError>("Function in two COMDATs",
667 object_error::parse_failed);
668 getDefinedFunction(Index).Comdat = ComdatIndex;
669 break;
670 }
671 }
672 }
673 return Error::success();
674 }
675
parseRelocSection(StringRef Name,ReadContext & Ctx)676 Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
677 uint32_t SectionIndex = readVaruint32(Ctx);
678 if (SectionIndex >= Sections.size())
679 return make_error<GenericBinaryError>("Invalid section index",
680 object_error::parse_failed);
681 WasmSection &Section = Sections[SectionIndex];
682 uint32_t RelocCount = readVaruint32(Ctx);
683 uint32_t EndOffset = Section.Content.size();
684 uint32_t PreviousOffset = 0;
685 while (RelocCount--) {
686 wasm::WasmRelocation Reloc = {};
687 Reloc.Type = readVaruint32(Ctx);
688 Reloc.Offset = readVaruint32(Ctx);
689 if (Reloc.Offset < PreviousOffset)
690 return make_error<GenericBinaryError>("Relocations not in offset order",
691 object_error::parse_failed);
692 PreviousOffset = Reloc.Offset;
693 Reloc.Index = readVaruint32(Ctx);
694 switch (Reloc.Type) {
695 case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
696 case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB:
697 case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32:
698 if (!isValidFunctionSymbol(Reloc.Index))
699 return make_error<GenericBinaryError>("Bad relocation function index",
700 object_error::parse_failed);
701 break;
702 case wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB:
703 if (Reloc.Index >= Signatures.size())
704 return make_error<GenericBinaryError>("Bad relocation type index",
705 object_error::parse_failed);
706 break;
707 case wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB:
708 if (!isValidGlobalSymbol(Reloc.Index))
709 return make_error<GenericBinaryError>("Bad relocation global index",
710 object_error::parse_failed);
711 break;
712 case wasm::R_WEBASSEMBLY_EVENT_INDEX_LEB:
713 if (!isValidEventSymbol(Reloc.Index))
714 return make_error<GenericBinaryError>("Bad relocation event index",
715 object_error::parse_failed);
716 break;
717 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB:
718 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB:
719 case wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32:
720 if (!isValidDataSymbol(Reloc.Index))
721 return make_error<GenericBinaryError>("Bad relocation data index",
722 object_error::parse_failed);
723 Reloc.Addend = readVarint32(Ctx);
724 break;
725 case wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32:
726 if (!isValidFunctionSymbol(Reloc.Index))
727 return make_error<GenericBinaryError>("Bad relocation function index",
728 object_error::parse_failed);
729 Reloc.Addend = readVarint32(Ctx);
730 break;
731 case wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32:
732 if (!isValidSectionSymbol(Reloc.Index))
733 return make_error<GenericBinaryError>("Bad relocation section index",
734 object_error::parse_failed);
735 Reloc.Addend = readVarint32(Ctx);
736 break;
737 default:
738 return make_error<GenericBinaryError>("Bad relocation type: " +
739 Twine(Reloc.Type),
740 object_error::parse_failed);
741 }
742
743 // Relocations must fit inside the section, and must appear in order. They
744 // also shouldn't overlap a function/element boundary, but we don't bother
745 // to check that.
746 uint64_t Size = 5;
747 if (Reloc.Type == wasm::R_WEBASSEMBLY_TABLE_INDEX_I32 ||
748 Reloc.Type == wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32 ||
749 Reloc.Type == wasm::R_WEBASSEMBLY_SECTION_OFFSET_I32 ||
750 Reloc.Type == wasm::R_WEBASSEMBLY_FUNCTION_OFFSET_I32)
751 Size = 4;
752 if (Reloc.Offset + Size > EndOffset)
753 return make_error<GenericBinaryError>("Bad relocation offset",
754 object_error::parse_failed);
755
756 Section.Relocations.push_back(Reloc);
757 }
758 if (Ctx.Ptr != Ctx.End)
759 return make_error<GenericBinaryError>("Reloc section ended prematurely",
760 object_error::parse_failed);
761 return Error::success();
762 }
763
parseCustomSection(WasmSection & Sec,ReadContext & Ctx)764 Error WasmObjectFile::parseCustomSection(WasmSection &Sec, ReadContext &Ctx) {
765 if (Sec.Name == "dylink") {
766 if (Error Err = parseDylinkSection(Ctx))
767 return Err;
768 } else if (Sec.Name == "name") {
769 if (Error Err = parseNameSection(Ctx))
770 return Err;
771 } else if (Sec.Name == "linking") {
772 if (Error Err = parseLinkingSection(Ctx))
773 return Err;
774 } else if (Sec.Name.startswith("reloc.")) {
775 if (Error Err = parseRelocSection(Sec.Name, Ctx))
776 return Err;
777 }
778 return Error::success();
779 }
780
parseTypeSection(ReadContext & Ctx)781 Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
782 uint32_t Count = readVaruint32(Ctx);
783 Signatures.reserve(Count);
784 while (Count--) {
785 wasm::WasmSignature Sig;
786 uint8_t Form = readUint8(Ctx);
787 if (Form != wasm::WASM_TYPE_FUNC) {
788 return make_error<GenericBinaryError>("Invalid signature type",
789 object_error::parse_failed);
790 }
791 uint32_t ParamCount = readVaruint32(Ctx);
792 Sig.Params.reserve(ParamCount);
793 while (ParamCount--) {
794 uint32_t ParamType = readUint8(Ctx);
795 Sig.Params.push_back(wasm::ValType(ParamType));
796 }
797 uint32_t ReturnCount = readVaruint32(Ctx);
798 if (ReturnCount) {
799 if (ReturnCount != 1) {
800 return make_error<GenericBinaryError>(
801 "Multiple return types not supported", object_error::parse_failed);
802 }
803 Sig.Returns.push_back(wasm::ValType(readUint8(Ctx)));
804 }
805 Signatures.push_back(std::move(Sig));
806 }
807 if (Ctx.Ptr != Ctx.End)
808 return make_error<GenericBinaryError>("Type section ended prematurely",
809 object_error::parse_failed);
810 return Error::success();
811 }
812
parseImportSection(ReadContext & Ctx)813 Error WasmObjectFile::parseImportSection(ReadContext &Ctx) {
814 uint32_t Count = readVaruint32(Ctx);
815 Imports.reserve(Count);
816 for (uint32_t i = 0; i < Count; i++) {
817 wasm::WasmImport Im;
818 Im.Module = readString(Ctx);
819 Im.Field = readString(Ctx);
820 Im.Kind = readUint8(Ctx);
821 switch (Im.Kind) {
822 case wasm::WASM_EXTERNAL_FUNCTION:
823 NumImportedFunctions++;
824 Im.SigIndex = readVaruint32(Ctx);
825 break;
826 case wasm::WASM_EXTERNAL_GLOBAL:
827 NumImportedGlobals++;
828 Im.Global.Type = readUint8(Ctx);
829 Im.Global.Mutable = readVaruint1(Ctx);
830 break;
831 case wasm::WASM_EXTERNAL_MEMORY:
832 Im.Memory = readLimits(Ctx);
833 break;
834 case wasm::WASM_EXTERNAL_TABLE:
835 Im.Table = readTable(Ctx);
836 if (Im.Table.ElemType != wasm::WASM_TYPE_FUNCREF)
837 return make_error<GenericBinaryError>("Invalid table element type",
838 object_error::parse_failed);
839 break;
840 case wasm::WASM_EXTERNAL_EVENT:
841 NumImportedEvents++;
842 Im.Event.Attribute = readVarint32(Ctx);
843 Im.Event.SigIndex = readVarint32(Ctx);
844 break;
845 default:
846 return make_error<GenericBinaryError>("Unexpected import kind",
847 object_error::parse_failed);
848 }
849 Imports.push_back(Im);
850 }
851 if (Ctx.Ptr != Ctx.End)
852 return make_error<GenericBinaryError>("Import section ended prematurely",
853 object_error::parse_failed);
854 return Error::success();
855 }
856
parseFunctionSection(ReadContext & Ctx)857 Error WasmObjectFile::parseFunctionSection(ReadContext &Ctx) {
858 uint32_t Count = readVaruint32(Ctx);
859 FunctionTypes.reserve(Count);
860 uint32_t NumTypes = Signatures.size();
861 while (Count--) {
862 uint32_t Type = readVaruint32(Ctx);
863 if (Type >= NumTypes)
864 return make_error<GenericBinaryError>("Invalid function type",
865 object_error::parse_failed);
866 FunctionTypes.push_back(Type);
867 }
868 if (Ctx.Ptr != Ctx.End)
869 return make_error<GenericBinaryError>("Function section ended prematurely",
870 object_error::parse_failed);
871 return Error::success();
872 }
873
parseTableSection(ReadContext & Ctx)874 Error WasmObjectFile::parseTableSection(ReadContext &Ctx) {
875 uint32_t Count = readVaruint32(Ctx);
876 Tables.reserve(Count);
877 while (Count--) {
878 Tables.push_back(readTable(Ctx));
879 if (Tables.back().ElemType != wasm::WASM_TYPE_FUNCREF) {
880 return make_error<GenericBinaryError>("Invalid table element type",
881 object_error::parse_failed);
882 }
883 }
884 if (Ctx.Ptr != Ctx.End)
885 return make_error<GenericBinaryError>("Table section ended prematurely",
886 object_error::parse_failed);
887 return Error::success();
888 }
889
parseMemorySection(ReadContext & Ctx)890 Error WasmObjectFile::parseMemorySection(ReadContext &Ctx) {
891 uint32_t Count = readVaruint32(Ctx);
892 Memories.reserve(Count);
893 while (Count--) {
894 Memories.push_back(readLimits(Ctx));
895 }
896 if (Ctx.Ptr != Ctx.End)
897 return make_error<GenericBinaryError>("Memory section ended prematurely",
898 object_error::parse_failed);
899 return Error::success();
900 }
901
parseGlobalSection(ReadContext & Ctx)902 Error WasmObjectFile::parseGlobalSection(ReadContext &Ctx) {
903 GlobalSection = Sections.size();
904 uint32_t Count = readVaruint32(Ctx);
905 Globals.reserve(Count);
906 while (Count--) {
907 wasm::WasmGlobal Global;
908 Global.Index = NumImportedGlobals + Globals.size();
909 Global.Type.Type = readUint8(Ctx);
910 Global.Type.Mutable = readVaruint1(Ctx);
911 if (Error Err = readInitExpr(Global.InitExpr, Ctx))
912 return Err;
913 Globals.push_back(Global);
914 }
915 if (Ctx.Ptr != Ctx.End)
916 return make_error<GenericBinaryError>("Global section ended prematurely",
917 object_error::parse_failed);
918 return Error::success();
919 }
920
parseEventSection(ReadContext & Ctx)921 Error WasmObjectFile::parseEventSection(ReadContext &Ctx) {
922 EventSection = Sections.size();
923 uint32_t Count = readVarint32(Ctx);
924 Events.reserve(Count);
925 while (Count--) {
926 wasm::WasmEvent Event;
927 Event.Index = NumImportedEvents + Events.size();
928 Event.Type.Attribute = readVaruint32(Ctx);
929 Event.Type.SigIndex = readVarint32(Ctx);
930 Events.push_back(Event);
931 }
932
933 if (Ctx.Ptr != Ctx.End)
934 return make_error<GenericBinaryError>("Event section ended prematurely",
935 object_error::parse_failed);
936 return Error::success();
937 }
938
parseExportSection(ReadContext & Ctx)939 Error WasmObjectFile::parseExportSection(ReadContext &Ctx) {
940 uint32_t Count = readVaruint32(Ctx);
941 Exports.reserve(Count);
942 for (uint32_t i = 0; i < Count; i++) {
943 wasm::WasmExport Ex;
944 Ex.Name = readString(Ctx);
945 Ex.Kind = readUint8(Ctx);
946 Ex.Index = readVaruint32(Ctx);
947 switch (Ex.Kind) {
948 case wasm::WASM_EXTERNAL_FUNCTION:
949 if (!isValidFunctionIndex(Ex.Index))
950 return make_error<GenericBinaryError>("Invalid function export",
951 object_error::parse_failed);
952 break;
953 case wasm::WASM_EXTERNAL_GLOBAL:
954 if (!isValidGlobalIndex(Ex.Index))
955 return make_error<GenericBinaryError>("Invalid global export",
956 object_error::parse_failed);
957 break;
958 case wasm::WASM_EXTERNAL_EVENT:
959 if (!isValidEventIndex(Ex.Index))
960 return make_error<GenericBinaryError>("Invalid event export",
961 object_error::parse_failed);
962 break;
963 case wasm::WASM_EXTERNAL_MEMORY:
964 case wasm::WASM_EXTERNAL_TABLE:
965 break;
966 default:
967 return make_error<GenericBinaryError>("Unexpected export kind",
968 object_error::parse_failed);
969 }
970 Exports.push_back(Ex);
971 }
972 if (Ctx.Ptr != Ctx.End)
973 return make_error<GenericBinaryError>("Export section ended prematurely",
974 object_error::parse_failed);
975 return Error::success();
976 }
977
isValidFunctionIndex(uint32_t Index) const978 bool WasmObjectFile::isValidFunctionIndex(uint32_t Index) const {
979 return Index < NumImportedFunctions + FunctionTypes.size();
980 }
981
isDefinedFunctionIndex(uint32_t Index) const982 bool WasmObjectFile::isDefinedFunctionIndex(uint32_t Index) const {
983 return Index >= NumImportedFunctions && isValidFunctionIndex(Index);
984 }
985
isValidGlobalIndex(uint32_t Index) const986 bool WasmObjectFile::isValidGlobalIndex(uint32_t Index) const {
987 return Index < NumImportedGlobals + Globals.size();
988 }
989
isDefinedGlobalIndex(uint32_t Index) const990 bool WasmObjectFile::isDefinedGlobalIndex(uint32_t Index) const {
991 return Index >= NumImportedGlobals && isValidGlobalIndex(Index);
992 }
993
isValidEventIndex(uint32_t Index) const994 bool WasmObjectFile::isValidEventIndex(uint32_t Index) const {
995 return Index < NumImportedEvents + Events.size();
996 }
997
isDefinedEventIndex(uint32_t Index) const998 bool WasmObjectFile::isDefinedEventIndex(uint32_t Index) const {
999 return Index >= NumImportedEvents && isValidEventIndex(Index);
1000 }
1001
isValidFunctionSymbol(uint32_t Index) const1002 bool WasmObjectFile::isValidFunctionSymbol(uint32_t Index) const {
1003 return Index < Symbols.size() && Symbols[Index].isTypeFunction();
1004 }
1005
isValidGlobalSymbol(uint32_t Index) const1006 bool WasmObjectFile::isValidGlobalSymbol(uint32_t Index) const {
1007 return Index < Symbols.size() && Symbols[Index].isTypeGlobal();
1008 }
1009
isValidEventSymbol(uint32_t Index) const1010 bool WasmObjectFile::isValidEventSymbol(uint32_t Index) const {
1011 return Index < Symbols.size() && Symbols[Index].isTypeEvent();
1012 }
1013
isValidDataSymbol(uint32_t Index) const1014 bool WasmObjectFile::isValidDataSymbol(uint32_t Index) const {
1015 return Index < Symbols.size() && Symbols[Index].isTypeData();
1016 }
1017
isValidSectionSymbol(uint32_t Index) const1018 bool WasmObjectFile::isValidSectionSymbol(uint32_t Index) const {
1019 return Index < Symbols.size() && Symbols[Index].isTypeSection();
1020 }
1021
getDefinedFunction(uint32_t Index)1022 wasm::WasmFunction &WasmObjectFile::getDefinedFunction(uint32_t Index) {
1023 assert(isDefinedFunctionIndex(Index));
1024 return Functions[Index - NumImportedFunctions];
1025 }
1026
getDefinedGlobal(uint32_t Index)1027 wasm::WasmGlobal &WasmObjectFile::getDefinedGlobal(uint32_t Index) {
1028 assert(isDefinedGlobalIndex(Index));
1029 return Globals[Index - NumImportedGlobals];
1030 }
1031
getDefinedEvent(uint32_t Index)1032 wasm::WasmEvent &WasmObjectFile::getDefinedEvent(uint32_t Index) {
1033 assert(isDefinedEventIndex(Index));
1034 return Events[Index - NumImportedEvents];
1035 }
1036
parseStartSection(ReadContext & Ctx)1037 Error WasmObjectFile::parseStartSection(ReadContext &Ctx) {
1038 StartFunction = readVaruint32(Ctx);
1039 if (!isValidFunctionIndex(StartFunction))
1040 return make_error<GenericBinaryError>("Invalid start function",
1041 object_error::parse_failed);
1042 return Error::success();
1043 }
1044
parseCodeSection(ReadContext & Ctx)1045 Error WasmObjectFile::parseCodeSection(ReadContext &Ctx) {
1046 CodeSection = Sections.size();
1047 uint32_t FunctionCount = readVaruint32(Ctx);
1048 if (FunctionCount != FunctionTypes.size()) {
1049 return make_error<GenericBinaryError>("Invalid function count",
1050 object_error::parse_failed);
1051 }
1052
1053 while (FunctionCount--) {
1054 wasm::WasmFunction Function;
1055 const uint8_t *FunctionStart = Ctx.Ptr;
1056 uint32_t Size = readVaruint32(Ctx);
1057 const uint8_t *FunctionEnd = Ctx.Ptr + Size;
1058
1059 Function.CodeOffset = Ctx.Ptr - FunctionStart;
1060 Function.Index = NumImportedFunctions + Functions.size();
1061 Function.CodeSectionOffset = FunctionStart - Ctx.Start;
1062 Function.Size = FunctionEnd - FunctionStart;
1063
1064 uint32_t NumLocalDecls = readVaruint32(Ctx);
1065 Function.Locals.reserve(NumLocalDecls);
1066 while (NumLocalDecls--) {
1067 wasm::WasmLocalDecl Decl;
1068 Decl.Count = readVaruint32(Ctx);
1069 Decl.Type = readUint8(Ctx);
1070 Function.Locals.push_back(Decl);
1071 }
1072
1073 uint32_t BodySize = FunctionEnd - Ctx.Ptr;
1074 Function.Body = ArrayRef<uint8_t>(Ctx.Ptr, BodySize);
1075 // This will be set later when reading in the linking metadata section.
1076 Function.Comdat = UINT32_MAX;
1077 Ctx.Ptr += BodySize;
1078 assert(Ctx.Ptr == FunctionEnd);
1079 Functions.push_back(Function);
1080 }
1081 if (Ctx.Ptr != Ctx.End)
1082 return make_error<GenericBinaryError>("Code section ended prematurely",
1083 object_error::parse_failed);
1084 return Error::success();
1085 }
1086
parseElemSection(ReadContext & Ctx)1087 Error WasmObjectFile::parseElemSection(ReadContext &Ctx) {
1088 uint32_t Count = readVaruint32(Ctx);
1089 ElemSegments.reserve(Count);
1090 while (Count--) {
1091 wasm::WasmElemSegment Segment;
1092 Segment.TableIndex = readVaruint32(Ctx);
1093 if (Segment.TableIndex != 0) {
1094 return make_error<GenericBinaryError>("Invalid TableIndex",
1095 object_error::parse_failed);
1096 }
1097 if (Error Err = readInitExpr(Segment.Offset, Ctx))
1098 return Err;
1099 uint32_t NumElems = readVaruint32(Ctx);
1100 while (NumElems--) {
1101 Segment.Functions.push_back(readVaruint32(Ctx));
1102 }
1103 ElemSegments.push_back(Segment);
1104 }
1105 if (Ctx.Ptr != Ctx.End)
1106 return make_error<GenericBinaryError>("Elem section ended prematurely",
1107 object_error::parse_failed);
1108 return Error::success();
1109 }
1110
parseDataSection(ReadContext & Ctx)1111 Error WasmObjectFile::parseDataSection(ReadContext &Ctx) {
1112 DataSection = Sections.size();
1113 uint32_t Count = readVaruint32(Ctx);
1114 DataSegments.reserve(Count);
1115 while (Count--) {
1116 WasmSegment Segment;
1117 Segment.Data.MemoryIndex = readVaruint32(Ctx);
1118 if (Error Err = readInitExpr(Segment.Data.Offset, Ctx))
1119 return Err;
1120 uint32_t Size = readVaruint32(Ctx);
1121 if (Size > (size_t)(Ctx.End - Ctx.Ptr))
1122 return make_error<GenericBinaryError>("Invalid segment size",
1123 object_error::parse_failed);
1124 Segment.Data.Content = ArrayRef<uint8_t>(Ctx.Ptr, Size);
1125 // The rest of these Data fields are set later, when reading in the linking
1126 // metadata section.
1127 Segment.Data.Alignment = 0;
1128 Segment.Data.Flags = 0;
1129 Segment.Data.Comdat = UINT32_MAX;
1130 Segment.SectionOffset = Ctx.Ptr - Ctx.Start;
1131 Ctx.Ptr += Size;
1132 DataSegments.push_back(Segment);
1133 }
1134 if (Ctx.Ptr != Ctx.End)
1135 return make_error<GenericBinaryError>("Data section ended prematurely",
1136 object_error::parse_failed);
1137 return Error::success();
1138 }
1139
getPtr(size_t Offset) const1140 const uint8_t *WasmObjectFile::getPtr(size_t Offset) const {
1141 return reinterpret_cast<const uint8_t *>(getData().data() + Offset);
1142 }
1143
getHeader() const1144 const wasm::WasmObjectHeader &WasmObjectFile::getHeader() const {
1145 return Header;
1146 }
1147
moveSymbolNext(DataRefImpl & Symb) const1148 void WasmObjectFile::moveSymbolNext(DataRefImpl &Symb) const { Symb.d.a++; }
1149
getSymbolFlags(DataRefImpl Symb) const1150 uint32_t WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const {
1151 uint32_t Result = SymbolRef::SF_None;
1152 const WasmSymbol &Sym = getWasmSymbol(Symb);
1153
1154 LLVM_DEBUG(dbgs() << "getSymbolFlags: ptr=" << &Sym << " " << Sym << "\n");
1155 if (Sym.isBindingWeak())
1156 Result |= SymbolRef::SF_Weak;
1157 if (!Sym.isBindingLocal())
1158 Result |= SymbolRef::SF_Global;
1159 if (Sym.isHidden())
1160 Result |= SymbolRef::SF_Hidden;
1161 if (!Sym.isDefined())
1162 Result |= SymbolRef::SF_Undefined;
1163 if (Sym.isTypeFunction())
1164 Result |= SymbolRef::SF_Executable;
1165 return Result;
1166 }
1167
symbol_begin() const1168 basic_symbol_iterator WasmObjectFile::symbol_begin() const {
1169 DataRefImpl Ref;
1170 Ref.d.a = 0;
1171 return BasicSymbolRef(Ref, this);
1172 }
1173
symbol_end() const1174 basic_symbol_iterator WasmObjectFile::symbol_end() const {
1175 DataRefImpl Ref;
1176 Ref.d.a = Symbols.size();
1177 return BasicSymbolRef(Ref, this);
1178 }
1179
getWasmSymbol(const DataRefImpl & Symb) const1180 const WasmSymbol &WasmObjectFile::getWasmSymbol(const DataRefImpl &Symb) const {
1181 return Symbols[Symb.d.a];
1182 }
1183
getWasmSymbol(const SymbolRef & Symb) const1184 const WasmSymbol &WasmObjectFile::getWasmSymbol(const SymbolRef &Symb) const {
1185 return getWasmSymbol(Symb.getRawDataRefImpl());
1186 }
1187
getSymbolName(DataRefImpl Symb) const1188 Expected<StringRef> WasmObjectFile::getSymbolName(DataRefImpl Symb) const {
1189 return getWasmSymbol(Symb).Info.Name;
1190 }
1191
getSymbolAddress(DataRefImpl Symb) const1192 Expected<uint64_t> WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const {
1193 return getSymbolValue(Symb);
1194 }
1195
getWasmSymbolValue(const WasmSymbol & Sym) const1196 uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol &Sym) const {
1197 switch (Sym.Info.Kind) {
1198 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1199 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1200 case wasm::WASM_SYMBOL_TYPE_EVENT:
1201 return Sym.Info.ElementIndex;
1202 case wasm::WASM_SYMBOL_TYPE_DATA: {
1203 // The value of a data symbol is the segment offset, plus the symbol
1204 // offset within the segment.
1205 uint32_t SegmentIndex = Sym.Info.DataRef.Segment;
1206 const wasm::WasmDataSegment &Segment = DataSegments[SegmentIndex].Data;
1207 assert(Segment.Offset.Opcode == wasm::WASM_OPCODE_I32_CONST);
1208 return Segment.Offset.Value.Int32 + Sym.Info.DataRef.Offset;
1209 }
1210 case wasm::WASM_SYMBOL_TYPE_SECTION:
1211 return 0;
1212 }
1213 llvm_unreachable("invalid symbol type");
1214 }
1215
getSymbolValueImpl(DataRefImpl Symb) const1216 uint64_t WasmObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
1217 return getWasmSymbolValue(getWasmSymbol(Symb));
1218 }
1219
getSymbolAlignment(DataRefImpl Symb) const1220 uint32_t WasmObjectFile::getSymbolAlignment(DataRefImpl Symb) const {
1221 llvm_unreachable("not yet implemented");
1222 return 0;
1223 }
1224
getCommonSymbolSizeImpl(DataRefImpl Symb) const1225 uint64_t WasmObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
1226 llvm_unreachable("not yet implemented");
1227 return 0;
1228 }
1229
1230 Expected<SymbolRef::Type>
getSymbolType(DataRefImpl Symb) const1231 WasmObjectFile::getSymbolType(DataRefImpl Symb) const {
1232 const WasmSymbol &Sym = getWasmSymbol(Symb);
1233
1234 switch (Sym.Info.Kind) {
1235 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1236 return SymbolRef::ST_Function;
1237 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1238 return SymbolRef::ST_Other;
1239 case wasm::WASM_SYMBOL_TYPE_DATA:
1240 return SymbolRef::ST_Data;
1241 case wasm::WASM_SYMBOL_TYPE_SECTION:
1242 return SymbolRef::ST_Debug;
1243 case wasm::WASM_SYMBOL_TYPE_EVENT:
1244 return SymbolRef::ST_Other;
1245 }
1246
1247 llvm_unreachable("Unknown WasmSymbol::SymbolType");
1248 return SymbolRef::ST_Other;
1249 }
1250
1251 Expected<section_iterator>
getSymbolSection(DataRefImpl Symb) const1252 WasmObjectFile::getSymbolSection(DataRefImpl Symb) const {
1253 const WasmSymbol &Sym = getWasmSymbol(Symb);
1254 if (Sym.isUndefined())
1255 return section_end();
1256
1257 DataRefImpl Ref;
1258 switch (Sym.Info.Kind) {
1259 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1260 Ref.d.a = CodeSection;
1261 break;
1262 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1263 Ref.d.a = GlobalSection;
1264 break;
1265 case wasm::WASM_SYMBOL_TYPE_DATA:
1266 Ref.d.a = DataSection;
1267 break;
1268 case wasm::WASM_SYMBOL_TYPE_SECTION:
1269 Ref.d.a = Sym.Info.ElementIndex;
1270 break;
1271 case wasm::WASM_SYMBOL_TYPE_EVENT:
1272 Ref.d.a = EventSection;
1273 break;
1274 default:
1275 llvm_unreachable("Unknown WasmSymbol::SymbolType");
1276 }
1277 return section_iterator(SectionRef(Ref, this));
1278 }
1279
moveSectionNext(DataRefImpl & Sec) const1280 void WasmObjectFile::moveSectionNext(DataRefImpl &Sec) const { Sec.d.a++; }
1281
getSectionName(DataRefImpl Sec,StringRef & Res) const1282 std::error_code WasmObjectFile::getSectionName(DataRefImpl Sec,
1283 StringRef &Res) const {
1284 const WasmSection &S = Sections[Sec.d.a];
1285 #define ECase(X) \
1286 case wasm::WASM_SEC_##X: \
1287 Res = #X; \
1288 break
1289 switch (S.Type) {
1290 ECase(TYPE);
1291 ECase(IMPORT);
1292 ECase(FUNCTION);
1293 ECase(TABLE);
1294 ECase(MEMORY);
1295 ECase(GLOBAL);
1296 ECase(EVENT);
1297 ECase(EXPORT);
1298 ECase(START);
1299 ECase(ELEM);
1300 ECase(CODE);
1301 ECase(DATA);
1302 case wasm::WASM_SEC_CUSTOM:
1303 Res = S.Name;
1304 break;
1305 default:
1306 return object_error::invalid_section_index;
1307 }
1308 #undef ECase
1309 return std::error_code();
1310 }
1311
getSectionAddress(DataRefImpl Sec) const1312 uint64_t WasmObjectFile::getSectionAddress(DataRefImpl Sec) const { return 0; }
1313
getSectionIndex(DataRefImpl Sec) const1314 uint64_t WasmObjectFile::getSectionIndex(DataRefImpl Sec) const {
1315 return Sec.d.a;
1316 }
1317
getSectionSize(DataRefImpl Sec) const1318 uint64_t WasmObjectFile::getSectionSize(DataRefImpl Sec) const {
1319 const WasmSection &S = Sections[Sec.d.a];
1320 return S.Content.size();
1321 }
1322
getSectionContents(DataRefImpl Sec,StringRef & Res) const1323 std::error_code WasmObjectFile::getSectionContents(DataRefImpl Sec,
1324 StringRef &Res) const {
1325 const WasmSection &S = Sections[Sec.d.a];
1326 // This will never fail since wasm sections can never be empty (user-sections
1327 // must have a name and non-user sections each have a defined structure).
1328 Res = StringRef(reinterpret_cast<const char *>(S.Content.data()),
1329 S.Content.size());
1330 return std::error_code();
1331 }
1332
getSectionAlignment(DataRefImpl Sec) const1333 uint64_t WasmObjectFile::getSectionAlignment(DataRefImpl Sec) const {
1334 return 1;
1335 }
1336
isSectionCompressed(DataRefImpl Sec) const1337 bool WasmObjectFile::isSectionCompressed(DataRefImpl Sec) const {
1338 return false;
1339 }
1340
isSectionText(DataRefImpl Sec) const1341 bool WasmObjectFile::isSectionText(DataRefImpl Sec) const {
1342 return getWasmSection(Sec).Type == wasm::WASM_SEC_CODE;
1343 }
1344
isSectionData(DataRefImpl Sec) const1345 bool WasmObjectFile::isSectionData(DataRefImpl Sec) const {
1346 return getWasmSection(Sec).Type == wasm::WASM_SEC_DATA;
1347 }
1348
isSectionBSS(DataRefImpl Sec) const1349 bool WasmObjectFile::isSectionBSS(DataRefImpl Sec) const { return false; }
1350
isSectionVirtual(DataRefImpl Sec) const1351 bool WasmObjectFile::isSectionVirtual(DataRefImpl Sec) const { return false; }
1352
isSectionBitcode(DataRefImpl Sec) const1353 bool WasmObjectFile::isSectionBitcode(DataRefImpl Sec) const { return false; }
1354
section_rel_begin(DataRefImpl Ref) const1355 relocation_iterator WasmObjectFile::section_rel_begin(DataRefImpl Ref) const {
1356 DataRefImpl RelocRef;
1357 RelocRef.d.a = Ref.d.a;
1358 RelocRef.d.b = 0;
1359 return relocation_iterator(RelocationRef(RelocRef, this));
1360 }
1361
section_rel_end(DataRefImpl Ref) const1362 relocation_iterator WasmObjectFile::section_rel_end(DataRefImpl Ref) const {
1363 const WasmSection &Sec = getWasmSection(Ref);
1364 DataRefImpl RelocRef;
1365 RelocRef.d.a = Ref.d.a;
1366 RelocRef.d.b = Sec.Relocations.size();
1367 return relocation_iterator(RelocationRef(RelocRef, this));
1368 }
1369
moveRelocationNext(DataRefImpl & Rel) const1370 void WasmObjectFile::moveRelocationNext(DataRefImpl &Rel) const { Rel.d.b++; }
1371
getRelocationOffset(DataRefImpl Ref) const1372 uint64_t WasmObjectFile::getRelocationOffset(DataRefImpl Ref) const {
1373 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1374 return Rel.Offset;
1375 }
1376
getRelocationSymbol(DataRefImpl Ref) const1377 symbol_iterator WasmObjectFile::getRelocationSymbol(DataRefImpl Ref) const {
1378 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1379 if (Rel.Type == wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB)
1380 return symbol_end();
1381 DataRefImpl Sym;
1382 Sym.d.a = Rel.Index;
1383 Sym.d.b = 0;
1384 return symbol_iterator(SymbolRef(Sym, this));
1385 }
1386
getRelocationType(DataRefImpl Ref) const1387 uint64_t WasmObjectFile::getRelocationType(DataRefImpl Ref) const {
1388 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1389 return Rel.Type;
1390 }
1391
getRelocationTypeName(DataRefImpl Ref,SmallVectorImpl<char> & Result) const1392 void WasmObjectFile::getRelocationTypeName(
1393 DataRefImpl Ref, SmallVectorImpl<char> &Result) const {
1394 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1395 StringRef Res = "Unknown";
1396
1397 #define WASM_RELOC(name, value) \
1398 case wasm::name: \
1399 Res = #name; \
1400 break;
1401
1402 switch (Rel.Type) {
1403 #include "llvm/BinaryFormat/WasmRelocs.def"
1404 }
1405
1406 #undef WASM_RELOC
1407
1408 Result.append(Res.begin(), Res.end());
1409 }
1410
section_begin() const1411 section_iterator WasmObjectFile::section_begin() const {
1412 DataRefImpl Ref;
1413 Ref.d.a = 0;
1414 return section_iterator(SectionRef(Ref, this));
1415 }
1416
section_end() const1417 section_iterator WasmObjectFile::section_end() const {
1418 DataRefImpl Ref;
1419 Ref.d.a = Sections.size();
1420 return section_iterator(SectionRef(Ref, this));
1421 }
1422
getBytesInAddress() const1423 uint8_t WasmObjectFile::getBytesInAddress() const { return 4; }
1424
getFileFormatName() const1425 StringRef WasmObjectFile::getFileFormatName() const { return "WASM"; }
1426
getArch() const1427 Triple::ArchType WasmObjectFile::getArch() const { return Triple::wasm32; }
1428
getFeatures() const1429 SubtargetFeatures WasmObjectFile::getFeatures() const {
1430 return SubtargetFeatures();
1431 }
1432
isRelocatableObject() const1433 bool WasmObjectFile::isRelocatableObject() const { return HasLinkingSection; }
1434
isSharedObject() const1435 bool WasmObjectFile::isSharedObject() const { return HasDylinkSection; }
1436
getWasmSection(DataRefImpl Ref) const1437 const WasmSection &WasmObjectFile::getWasmSection(DataRefImpl Ref) const {
1438 assert(Ref.d.a < Sections.size());
1439 return Sections[Ref.d.a];
1440 }
1441
1442 const WasmSection &
getWasmSection(const SectionRef & Section) const1443 WasmObjectFile::getWasmSection(const SectionRef &Section) const {
1444 return getWasmSection(Section.getRawDataRefImpl());
1445 }
1446
1447 const wasm::WasmRelocation &
getWasmRelocation(const RelocationRef & Ref) const1448 WasmObjectFile::getWasmRelocation(const RelocationRef &Ref) const {
1449 return getWasmRelocation(Ref.getRawDataRefImpl());
1450 }
1451
1452 const wasm::WasmRelocation &
getWasmRelocation(DataRefImpl Ref) const1453 WasmObjectFile::getWasmRelocation(DataRefImpl Ref) const {
1454 assert(Ref.d.a < Sections.size());
1455 const WasmSection &Sec = Sections[Ref.d.a];
1456 assert(Ref.d.b < Sec.Relocations.size());
1457 return Sec.Relocations[Ref.d.b];
1458 }
1459
getSectionOrder(unsigned ID,StringRef CustomSectionName)1460 int WasmSectionOrderChecker::getSectionOrder(unsigned ID,
1461 StringRef CustomSectionName) {
1462 switch (ID) {
1463 case wasm::WASM_SEC_CUSTOM:
1464 return StringSwitch<unsigned>(CustomSectionName)
1465 .Case("dylink", WASM_SEC_ORDER_DYLINK)
1466 .Case("linking", WASM_SEC_ORDER_LINKING)
1467 .StartsWith("reloc.", WASM_SEC_ORDER_RELOC)
1468 .Case("name", WASM_SEC_ORDER_NAME)
1469 .Case("producers", WASM_SEC_ORDER_PRODUCERS)
1470 .Default(-1);
1471 case wasm::WASM_SEC_TYPE:
1472 return WASM_SEC_ORDER_TYPE;
1473 case wasm::WASM_SEC_IMPORT:
1474 return WASM_SEC_ORDER_IMPORT;
1475 case wasm::WASM_SEC_FUNCTION:
1476 return WASM_SEC_ORDER_FUNCTION;
1477 case wasm::WASM_SEC_TABLE:
1478 return WASM_SEC_ORDER_TABLE;
1479 case wasm::WASM_SEC_MEMORY:
1480 return WASM_SEC_ORDER_MEMORY;
1481 case wasm::WASM_SEC_GLOBAL:
1482 return WASM_SEC_ORDER_GLOBAL;
1483 case wasm::WASM_SEC_EXPORT:
1484 return WASM_SEC_ORDER_EXPORT;
1485 case wasm::WASM_SEC_START:
1486 return WASM_SEC_ORDER_START;
1487 case wasm::WASM_SEC_ELEM:
1488 return WASM_SEC_ORDER_ELEM;
1489 case wasm::WASM_SEC_CODE:
1490 return WASM_SEC_ORDER_CODE;
1491 case wasm::WASM_SEC_DATA:
1492 return WASM_SEC_ORDER_DATA;
1493 case wasm::WASM_SEC_DATACOUNT:
1494 return WASM_SEC_ORDER_DATACOUNT;
1495 case wasm::WASM_SEC_EVENT:
1496 return WASM_SEC_ORDER_EVENT;
1497 default:
1498 llvm_unreachable("invalid section");
1499 }
1500 }
1501
isValidSectionOrder(unsigned ID,StringRef CustomSectionName)1502 bool WasmSectionOrderChecker::isValidSectionOrder(unsigned ID,
1503 StringRef CustomSectionName) {
1504 int Order = getSectionOrder(ID, CustomSectionName);
1505 if (Order == -1) // Skip unknown sections
1506 return true;
1507 // There can be multiple "reloc." sections. Otherwise there shouldn't be any
1508 // duplicate section orders.
1509 bool IsValid = (LastOrder == Order && Order == WASM_SEC_ORDER_RELOC) ||
1510 LastOrder < Order;
1511 LastOrder = Order;
1512 return IsValid;
1513 }
1514