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))
43 << ", Flags=" << 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.Initial = readVaruint64(Ctx);
212 if (Result.Flags & wasm::WASM_LIMITS_FLAG_HAS_MAX)
213 Result.Maximum = readVaruint64(Ctx);
214 return Result;
215 }
216
readTable(WasmObjectFile::ReadContext & Ctx)217 static wasm::WasmTable readTable(WasmObjectFile::ReadContext &Ctx) {
218 wasm::WasmTable Table;
219 Table.ElemType = readUint8(Ctx);
220 Table.Limits = readLimits(Ctx);
221 return Table;
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 =
266 make_error<StringError>("Bad magic number", 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>("Bad version number",
284 object_error::parse_failed);
285 return;
286 }
287
288 WasmSection Sec;
289 WasmSectionOrderChecker Checker;
290 while (Ctx.Ptr < Ctx.End) {
291 if ((Err = readSection(Sec, Ctx, Checker)))
292 return;
293 if ((Err = parseSection(Sec)))
294 return;
295
296 Sections.push_back(Sec);
297 }
298 }
299
parseSection(WasmSection & Sec)300 Error WasmObjectFile::parseSection(WasmSection &Sec) {
301 ReadContext Ctx;
302 Ctx.Start = Sec.Content.data();
303 Ctx.End = Ctx.Start + Sec.Content.size();
304 Ctx.Ptr = Ctx.Start;
305 switch (Sec.Type) {
306 case wasm::WASM_SEC_CUSTOM:
307 return parseCustomSection(Sec, Ctx);
308 case wasm::WASM_SEC_TYPE:
309 return parseTypeSection(Ctx);
310 case wasm::WASM_SEC_IMPORT:
311 return parseImportSection(Ctx);
312 case wasm::WASM_SEC_FUNCTION:
313 return parseFunctionSection(Ctx);
314 case wasm::WASM_SEC_TABLE:
315 return parseTableSection(Ctx);
316 case wasm::WASM_SEC_MEMORY:
317 return parseMemorySection(Ctx);
318 case wasm::WASM_SEC_EVENT:
319 return parseEventSection(Ctx);
320 case wasm::WASM_SEC_GLOBAL:
321 return parseGlobalSection(Ctx);
322 case wasm::WASM_SEC_EXPORT:
323 return parseExportSection(Ctx);
324 case wasm::WASM_SEC_START:
325 return parseStartSection(Ctx);
326 case wasm::WASM_SEC_ELEM:
327 return parseElemSection(Ctx);
328 case wasm::WASM_SEC_CODE:
329 return parseCodeSection(Ctx);
330 case wasm::WASM_SEC_DATA:
331 return parseDataSection(Ctx);
332 case wasm::WASM_SEC_DATACOUNT:
333 return parseDataCountSection(Ctx);
334 default:
335 return make_error<GenericBinaryError>(
336 "Invalid section type: " + Twine(Sec.Type), object_error::parse_failed);
337 }
338 }
339
parseDylinkSection(ReadContext & Ctx)340 Error WasmObjectFile::parseDylinkSection(ReadContext &Ctx) {
341 // See https://github.com/WebAssembly/tool-conventions/blob/master/DynamicLinking.md
342 HasDylinkSection = true;
343 DylinkInfo.MemorySize = readVaruint32(Ctx);
344 DylinkInfo.MemoryAlignment = readVaruint32(Ctx);
345 DylinkInfo.TableSize = readVaruint32(Ctx);
346 DylinkInfo.TableAlignment = readVaruint32(Ctx);
347 uint32_t Count = readVaruint32(Ctx);
348 while (Count--) {
349 DylinkInfo.Needed.push_back(readString(Ctx));
350 }
351 if (Ctx.Ptr != Ctx.End)
352 return make_error<GenericBinaryError>("dylink section ended prematurely",
353 object_error::parse_failed);
354 return Error::success();
355 }
356
parseNameSection(ReadContext & Ctx)357 Error WasmObjectFile::parseNameSection(ReadContext &Ctx) {
358 llvm::DenseSet<uint64_t> Seen;
359 if (FunctionTypes.size() && !SeenCodeSection) {
360 return make_error<GenericBinaryError>("Names must come after code section",
361 object_error::parse_failed);
362 }
363
364 while (Ctx.Ptr < Ctx.End) {
365 uint8_t Type = readUint8(Ctx);
366 uint32_t Size = readVaruint32(Ctx);
367 const uint8_t *SubSectionEnd = Ctx.Ptr + Size;
368 switch (Type) {
369 case wasm::WASM_NAMES_FUNCTION: {
370 uint32_t Count = readVaruint32(Ctx);
371 while (Count--) {
372 uint32_t Index = readVaruint32(Ctx);
373 if (!Seen.insert(Index).second)
374 return make_error<GenericBinaryError>("Function named more than once",
375 object_error::parse_failed);
376 StringRef Name = readString(Ctx);
377 if (!isValidFunctionIndex(Index) || Name.empty())
378 return make_error<GenericBinaryError>("Invalid name entry",
379 object_error::parse_failed);
380 DebugNames.push_back(wasm::WasmFunctionName{Index, Name});
381 if (isDefinedFunctionIndex(Index))
382 getDefinedFunction(Index).DebugName = Name;
383 }
384 break;
385 }
386 // Ignore local names for now
387 case wasm::WASM_NAMES_LOCAL:
388 default:
389 Ctx.Ptr += Size;
390 break;
391 }
392 if (Ctx.Ptr != SubSectionEnd)
393 return make_error<GenericBinaryError>(
394 "Name sub-section ended prematurely", object_error::parse_failed);
395 }
396
397 if (Ctx.Ptr != Ctx.End)
398 return make_error<GenericBinaryError>("Name section ended prematurely",
399 object_error::parse_failed);
400 return Error::success();
401 }
402
parseLinkingSection(ReadContext & Ctx)403 Error WasmObjectFile::parseLinkingSection(ReadContext &Ctx) {
404 HasLinkingSection = true;
405 if (FunctionTypes.size() && !SeenCodeSection) {
406 return make_error<GenericBinaryError>(
407 "Linking data must come after code section",
408 object_error::parse_failed);
409 }
410
411 LinkingData.Version = readVaruint32(Ctx);
412 if (LinkingData.Version != wasm::WasmMetadataVersion) {
413 return make_error<GenericBinaryError>(
414 "Unexpected metadata version: " + Twine(LinkingData.Version) +
415 " (Expected: " + Twine(wasm::WasmMetadataVersion) + ")",
416 object_error::parse_failed);
417 }
418
419 const uint8_t *OrigEnd = Ctx.End;
420 while (Ctx.Ptr < OrigEnd) {
421 Ctx.End = OrigEnd;
422 uint8_t Type = readUint8(Ctx);
423 uint32_t Size = readVaruint32(Ctx);
424 LLVM_DEBUG(dbgs() << "readSubsection type=" << int(Type) << " size=" << Size
425 << "\n");
426 Ctx.End = Ctx.Ptr + Size;
427 switch (Type) {
428 case wasm::WASM_SYMBOL_TABLE:
429 if (Error Err = parseLinkingSectionSymtab(Ctx))
430 return Err;
431 break;
432 case wasm::WASM_SEGMENT_INFO: {
433 uint32_t Count = readVaruint32(Ctx);
434 if (Count > DataSegments.size())
435 return make_error<GenericBinaryError>("Too many segment names",
436 object_error::parse_failed);
437 for (uint32_t I = 0; I < Count; I++) {
438 DataSegments[I].Data.Name = readString(Ctx);
439 DataSegments[I].Data.Alignment = readVaruint32(Ctx);
440 DataSegments[I].Data.LinkerFlags = readVaruint32(Ctx);
441 }
442 break;
443 }
444 case wasm::WASM_INIT_FUNCS: {
445 uint32_t Count = readVaruint32(Ctx);
446 LinkingData.InitFunctions.reserve(Count);
447 for (uint32_t I = 0; I < Count; I++) {
448 wasm::WasmInitFunc Init;
449 Init.Priority = readVaruint32(Ctx);
450 Init.Symbol = readVaruint32(Ctx);
451 if (!isValidFunctionSymbol(Init.Symbol))
452 return make_error<GenericBinaryError>("Invalid function symbol: " +
453 Twine(Init.Symbol),
454 object_error::parse_failed);
455 LinkingData.InitFunctions.emplace_back(Init);
456 }
457 break;
458 }
459 case wasm::WASM_COMDAT_INFO:
460 if (Error Err = parseLinkingSectionComdat(Ctx))
461 return Err;
462 break;
463 default:
464 Ctx.Ptr += Size;
465 break;
466 }
467 if (Ctx.Ptr != Ctx.End)
468 return make_error<GenericBinaryError>(
469 "Linking sub-section ended prematurely", object_error::parse_failed);
470 }
471 if (Ctx.Ptr != OrigEnd)
472 return make_error<GenericBinaryError>("Linking section ended prematurely",
473 object_error::parse_failed);
474 return Error::success();
475 }
476
parseLinkingSectionSymtab(ReadContext & Ctx)477 Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) {
478 uint32_t Count = readVaruint32(Ctx);
479 LinkingData.SymbolTable.reserve(Count);
480 Symbols.reserve(Count);
481 StringSet<> SymbolNames;
482
483 std::vector<wasm::WasmImport *> ImportedGlobals;
484 std::vector<wasm::WasmImport *> ImportedFunctions;
485 std::vector<wasm::WasmImport *> ImportedEvents;
486 ImportedGlobals.reserve(Imports.size());
487 ImportedFunctions.reserve(Imports.size());
488 ImportedEvents.reserve(Imports.size());
489 for (auto &I : Imports) {
490 if (I.Kind == wasm::WASM_EXTERNAL_FUNCTION)
491 ImportedFunctions.emplace_back(&I);
492 else if (I.Kind == wasm::WASM_EXTERNAL_GLOBAL)
493 ImportedGlobals.emplace_back(&I);
494 else if (I.Kind == wasm::WASM_EXTERNAL_EVENT)
495 ImportedEvents.emplace_back(&I);
496 }
497
498 while (Count--) {
499 wasm::WasmSymbolInfo Info;
500 const wasm::WasmSignature *Signature = nullptr;
501 const wasm::WasmGlobalType *GlobalType = nullptr;
502 const wasm::WasmEventType *EventType = nullptr;
503
504 Info.Kind = readUint8(Ctx);
505 Info.Flags = readVaruint32(Ctx);
506 bool IsDefined = (Info.Flags & wasm::WASM_SYMBOL_UNDEFINED) == 0;
507
508 switch (Info.Kind) {
509 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
510 Info.ElementIndex = readVaruint32(Ctx);
511 if (!isValidFunctionIndex(Info.ElementIndex) ||
512 IsDefined != isDefinedFunctionIndex(Info.ElementIndex))
513 return make_error<GenericBinaryError>("invalid function symbol index",
514 object_error::parse_failed);
515 if (IsDefined) {
516 Info.Name = readString(Ctx);
517 unsigned FuncIndex = Info.ElementIndex - NumImportedFunctions;
518 Signature = &Signatures[FunctionTypes[FuncIndex]];
519 wasm::WasmFunction &Function = Functions[FuncIndex];
520 if (Function.SymbolName.empty())
521 Function.SymbolName = Info.Name;
522 } else {
523 wasm::WasmImport &Import = *ImportedFunctions[Info.ElementIndex];
524 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
525 Info.Name = readString(Ctx);
526 Info.ImportName = Import.Field;
527 } else {
528 Info.Name = Import.Field;
529 }
530 Signature = &Signatures[Import.SigIndex];
531 if (!Import.Module.empty()) {
532 Info.ImportModule = Import.Module;
533 }
534 }
535 break;
536
537 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
538 Info.ElementIndex = readVaruint32(Ctx);
539 if (!isValidGlobalIndex(Info.ElementIndex) ||
540 IsDefined != isDefinedGlobalIndex(Info.ElementIndex))
541 return make_error<GenericBinaryError>("invalid global symbol index",
542 object_error::parse_failed);
543 if (!IsDefined && (Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) ==
544 wasm::WASM_SYMBOL_BINDING_WEAK)
545 return make_error<GenericBinaryError>("undefined weak global symbol",
546 object_error::parse_failed);
547 if (IsDefined) {
548 Info.Name = readString(Ctx);
549 unsigned GlobalIndex = Info.ElementIndex - NumImportedGlobals;
550 wasm::WasmGlobal &Global = Globals[GlobalIndex];
551 GlobalType = &Global.Type;
552 if (Global.SymbolName.empty())
553 Global.SymbolName = Info.Name;
554 } else {
555 wasm::WasmImport &Import = *ImportedGlobals[Info.ElementIndex];
556 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
557 Info.Name = readString(Ctx);
558 Info.ImportName = Import.Field;
559 } else {
560 Info.Name = Import.Field;
561 }
562 GlobalType = &Import.Global;
563 Info.ImportName = Import.Field;
564 if (!Import.Module.empty()) {
565 Info.ImportModule = Import.Module;
566 }
567 }
568 break;
569
570 case wasm::WASM_SYMBOL_TYPE_DATA:
571 Info.Name = readString(Ctx);
572 if (IsDefined) {
573 auto Index = readVaruint32(Ctx);
574 if (Index >= DataSegments.size())
575 return make_error<GenericBinaryError>("invalid data symbol index",
576 object_error::parse_failed);
577 auto Offset = readVaruint64(Ctx);
578 auto Size = readVaruint64(Ctx);
579 if (Offset + Size > DataSegments[Index].Data.Content.size())
580 return make_error<GenericBinaryError>("invalid data symbol offset",
581 object_error::parse_failed);
582 Info.DataRef = wasm::WasmDataReference{Index, Offset, Size};
583 }
584 break;
585
586 case wasm::WASM_SYMBOL_TYPE_SECTION: {
587 if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) !=
588 wasm::WASM_SYMBOL_BINDING_LOCAL)
589 return make_error<GenericBinaryError>(
590 "Section symbols must have local binding",
591 object_error::parse_failed);
592 Info.ElementIndex = readVaruint32(Ctx);
593 // Use somewhat unique section name as symbol name.
594 StringRef SectionName = Sections[Info.ElementIndex].Name;
595 Info.Name = SectionName;
596 break;
597 }
598
599 case wasm::WASM_SYMBOL_TYPE_EVENT: {
600 Info.ElementIndex = readVaruint32(Ctx);
601 if (!isValidEventIndex(Info.ElementIndex) ||
602 IsDefined != isDefinedEventIndex(Info.ElementIndex))
603 return make_error<GenericBinaryError>("invalid event 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 global symbol",
608 object_error::parse_failed);
609 if (IsDefined) {
610 Info.Name = readString(Ctx);
611 unsigned EventIndex = Info.ElementIndex - NumImportedEvents;
612 wasm::WasmEvent &Event = Events[EventIndex];
613 Signature = &Signatures[Event.Type.SigIndex];
614 EventType = &Event.Type;
615 if (Event.SymbolName.empty())
616 Event.SymbolName = Info.Name;
617
618 } else {
619 wasm::WasmImport &Import = *ImportedEvents[Info.ElementIndex];
620 if ((Info.Flags & wasm::WASM_SYMBOL_EXPLICIT_NAME) != 0) {
621 Info.Name = readString(Ctx);
622 Info.ImportName = Import.Field;
623 } else {
624 Info.Name = Import.Field;
625 }
626 EventType = &Import.Event;
627 Signature = &Signatures[EventType->SigIndex];
628 if (!Import.Module.empty()) {
629 Info.ImportModule = Import.Module;
630 }
631 }
632 break;
633 }
634
635 default:
636 return make_error<GenericBinaryError>("Invalid symbol type",
637 object_error::parse_failed);
638 }
639
640 if ((Info.Flags & wasm::WASM_SYMBOL_BINDING_MASK) !=
641 wasm::WASM_SYMBOL_BINDING_LOCAL &&
642 !SymbolNames.insert(Info.Name).second)
643 return make_error<GenericBinaryError>("Duplicate symbol name " +
644 Twine(Info.Name),
645 object_error::parse_failed);
646 LinkingData.SymbolTable.emplace_back(Info);
647 Symbols.emplace_back(LinkingData.SymbolTable.back(), GlobalType, EventType,
648 Signature);
649 LLVM_DEBUG(dbgs() << "Adding symbol: " << Symbols.back() << "\n");
650 }
651
652 return Error::success();
653 }
654
parseLinkingSectionComdat(ReadContext & Ctx)655 Error WasmObjectFile::parseLinkingSectionComdat(ReadContext &Ctx) {
656 uint32_t ComdatCount = readVaruint32(Ctx);
657 StringSet<> ComdatSet;
658 for (unsigned ComdatIndex = 0; ComdatIndex < ComdatCount; ++ComdatIndex) {
659 StringRef Name = readString(Ctx);
660 if (Name.empty() || !ComdatSet.insert(Name).second)
661 return make_error<GenericBinaryError>("Bad/duplicate COMDAT name " +
662 Twine(Name),
663 object_error::parse_failed);
664 LinkingData.Comdats.emplace_back(Name);
665 uint32_t Flags = readVaruint32(Ctx);
666 if (Flags != 0)
667 return make_error<GenericBinaryError>("Unsupported COMDAT flags",
668 object_error::parse_failed);
669
670 uint32_t EntryCount = readVaruint32(Ctx);
671 while (EntryCount--) {
672 unsigned Kind = readVaruint32(Ctx);
673 unsigned Index = readVaruint32(Ctx);
674 switch (Kind) {
675 default:
676 return make_error<GenericBinaryError>("Invalid COMDAT entry type",
677 object_error::parse_failed);
678 case wasm::WASM_COMDAT_DATA:
679 if (Index >= DataSegments.size())
680 return make_error<GenericBinaryError>(
681 "COMDAT data index out of range", object_error::parse_failed);
682 if (DataSegments[Index].Data.Comdat != UINT32_MAX)
683 return make_error<GenericBinaryError>("Data segment in two COMDATs",
684 object_error::parse_failed);
685 DataSegments[Index].Data.Comdat = ComdatIndex;
686 break;
687 case wasm::WASM_COMDAT_FUNCTION:
688 if (!isDefinedFunctionIndex(Index))
689 return make_error<GenericBinaryError>(
690 "COMDAT function index out of range", object_error::parse_failed);
691 if (getDefinedFunction(Index).Comdat != UINT32_MAX)
692 return make_error<GenericBinaryError>("Function in two COMDATs",
693 object_error::parse_failed);
694 getDefinedFunction(Index).Comdat = ComdatIndex;
695 break;
696 }
697 }
698 }
699 return Error::success();
700 }
701
parseProducersSection(ReadContext & Ctx)702 Error WasmObjectFile::parseProducersSection(ReadContext &Ctx) {
703 llvm::SmallSet<StringRef, 3> FieldsSeen;
704 uint32_t Fields = readVaruint32(Ctx);
705 for (size_t I = 0; I < Fields; ++I) {
706 StringRef FieldName = readString(Ctx);
707 if (!FieldsSeen.insert(FieldName).second)
708 return make_error<GenericBinaryError>(
709 "Producers section does not have unique fields",
710 object_error::parse_failed);
711 std::vector<std::pair<std::string, std::string>> *ProducerVec = nullptr;
712 if (FieldName == "language") {
713 ProducerVec = &ProducerInfo.Languages;
714 } else if (FieldName == "processed-by") {
715 ProducerVec = &ProducerInfo.Tools;
716 } else if (FieldName == "sdk") {
717 ProducerVec = &ProducerInfo.SDKs;
718 } else {
719 return make_error<GenericBinaryError>(
720 "Producers section field is not named one of language, processed-by, "
721 "or sdk",
722 object_error::parse_failed);
723 }
724 uint32_t ValueCount = readVaruint32(Ctx);
725 llvm::SmallSet<StringRef, 8> ProducersSeen;
726 for (size_t J = 0; J < ValueCount; ++J) {
727 StringRef Name = readString(Ctx);
728 StringRef Version = readString(Ctx);
729 if (!ProducersSeen.insert(Name).second) {
730 return make_error<GenericBinaryError>(
731 "Producers section contains repeated producer",
732 object_error::parse_failed);
733 }
734 ProducerVec->emplace_back(std::string(Name), std::string(Version));
735 }
736 }
737 if (Ctx.Ptr != Ctx.End)
738 return make_error<GenericBinaryError>("Producers section ended prematurely",
739 object_error::parse_failed);
740 return Error::success();
741 }
742
parseTargetFeaturesSection(ReadContext & Ctx)743 Error WasmObjectFile::parseTargetFeaturesSection(ReadContext &Ctx) {
744 llvm::SmallSet<std::string, 8> FeaturesSeen;
745 uint32_t FeatureCount = readVaruint32(Ctx);
746 for (size_t I = 0; I < FeatureCount; ++I) {
747 wasm::WasmFeatureEntry Feature;
748 Feature.Prefix = readUint8(Ctx);
749 switch (Feature.Prefix) {
750 case wasm::WASM_FEATURE_PREFIX_USED:
751 case wasm::WASM_FEATURE_PREFIX_REQUIRED:
752 case wasm::WASM_FEATURE_PREFIX_DISALLOWED:
753 break;
754 default:
755 return make_error<GenericBinaryError>("Unknown feature policy prefix",
756 object_error::parse_failed);
757 }
758 Feature.Name = std::string(readString(Ctx));
759 if (!FeaturesSeen.insert(Feature.Name).second)
760 return make_error<GenericBinaryError>(
761 "Target features section contains repeated feature \"" +
762 Feature.Name + "\"",
763 object_error::parse_failed);
764 TargetFeatures.push_back(Feature);
765 }
766 if (Ctx.Ptr != Ctx.End)
767 return make_error<GenericBinaryError>(
768 "Target features section ended prematurely",
769 object_error::parse_failed);
770 return Error::success();
771 }
772
parseRelocSection(StringRef Name,ReadContext & Ctx)773 Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
774 uint32_t SectionIndex = readVaruint32(Ctx);
775 if (SectionIndex >= Sections.size())
776 return make_error<GenericBinaryError>("Invalid section index",
777 object_error::parse_failed);
778 WasmSection &Section = Sections[SectionIndex];
779 uint32_t RelocCount = readVaruint32(Ctx);
780 uint32_t EndOffset = Section.Content.size();
781 uint32_t PreviousOffset = 0;
782 while (RelocCount--) {
783 wasm::WasmRelocation Reloc = {};
784 Reloc.Type = readVaruint32(Ctx);
785 Reloc.Offset = readVaruint32(Ctx);
786 if (Reloc.Offset < PreviousOffset)
787 return make_error<GenericBinaryError>("Relocations not in offset order",
788 object_error::parse_failed);
789 PreviousOffset = Reloc.Offset;
790 Reloc.Index = readVaruint32(Ctx);
791 switch (Reloc.Type) {
792 case wasm::R_WASM_FUNCTION_INDEX_LEB:
793 case wasm::R_WASM_TABLE_INDEX_SLEB:
794 case wasm::R_WASM_TABLE_INDEX_I32:
795 case wasm::R_WASM_TABLE_INDEX_REL_SLEB:
796 if (!isValidFunctionSymbol(Reloc.Index))
797 return make_error<GenericBinaryError>("Bad relocation function index",
798 object_error::parse_failed);
799 break;
800 case wasm::R_WASM_TYPE_INDEX_LEB:
801 if (Reloc.Index >= Signatures.size())
802 return make_error<GenericBinaryError>("Bad relocation type index",
803 object_error::parse_failed);
804 break;
805 case wasm::R_WASM_GLOBAL_INDEX_LEB:
806 // R_WASM_GLOBAL_INDEX_LEB are can be used against function and data
807 // symbols to refer to their GOT entries.
808 if (!isValidGlobalSymbol(Reloc.Index) &&
809 !isValidDataSymbol(Reloc.Index) &&
810 !isValidFunctionSymbol(Reloc.Index))
811 return make_error<GenericBinaryError>("Bad relocation global index",
812 object_error::parse_failed);
813 break;
814 case wasm::R_WASM_GLOBAL_INDEX_I32:
815 if (!isValidGlobalSymbol(Reloc.Index))
816 return make_error<GenericBinaryError>("Bad relocation global index",
817 object_error::parse_failed);
818 break;
819 case wasm::R_WASM_EVENT_INDEX_LEB:
820 if (!isValidEventSymbol(Reloc.Index))
821 return make_error<GenericBinaryError>("Bad relocation event index",
822 object_error::parse_failed);
823 break;
824 case wasm::R_WASM_MEMORY_ADDR_LEB:
825 case wasm::R_WASM_MEMORY_ADDR_SLEB:
826 case wasm::R_WASM_MEMORY_ADDR_I32:
827 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB:
828 if (!isValidDataSymbol(Reloc.Index))
829 return make_error<GenericBinaryError>("Bad relocation data index",
830 object_error::parse_failed);
831 Reloc.Addend = readVarint32(Ctx);
832 break;
833 case wasm::R_WASM_MEMORY_ADDR_LEB64:
834 case wasm::R_WASM_MEMORY_ADDR_SLEB64:
835 case wasm::R_WASM_MEMORY_ADDR_I64:
836 case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64:
837 if (!isValidDataSymbol(Reloc.Index))
838 return make_error<GenericBinaryError>("Bad relocation data index",
839 object_error::parse_failed);
840 Reloc.Addend = readVarint64(Ctx);
841 break;
842 case wasm::R_WASM_FUNCTION_OFFSET_I32:
843 if (!isValidFunctionSymbol(Reloc.Index))
844 return make_error<GenericBinaryError>("Bad relocation function index",
845 object_error::parse_failed);
846 Reloc.Addend = readVarint32(Ctx);
847 break;
848 case wasm::R_WASM_SECTION_OFFSET_I32:
849 if (!isValidSectionSymbol(Reloc.Index))
850 return make_error<GenericBinaryError>("Bad relocation section index",
851 object_error::parse_failed);
852 Reloc.Addend = readVarint32(Ctx);
853 break;
854 default:
855 return make_error<GenericBinaryError>("Bad relocation type: " +
856 Twine(Reloc.Type),
857 object_error::parse_failed);
858 }
859
860 // Relocations must fit inside the section, and must appear in order. They
861 // also shouldn't overlap a function/element boundary, but we don't bother
862 // to check that.
863 uint64_t Size = 5;
864 if (Reloc.Type == wasm::R_WASM_MEMORY_ADDR_LEB64 ||
865 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_SLEB64 ||
866 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_REL_SLEB64)
867 Size = 10;
868 if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I32 ||
869 Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I32 ||
870 Reloc.Type == wasm::R_WASM_SECTION_OFFSET_I32 ||
871 Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I32 ||
872 Reloc.Type == wasm::R_WASM_GLOBAL_INDEX_I32)
873 Size = 4;
874 if (Reloc.Type == wasm::R_WASM_MEMORY_ADDR_I64)
875 Size = 8;
876 if (Reloc.Offset + Size > EndOffset)
877 return make_error<GenericBinaryError>("Bad relocation offset",
878 object_error::parse_failed);
879
880 Section.Relocations.push_back(Reloc);
881 }
882 if (Ctx.Ptr != Ctx.End)
883 return make_error<GenericBinaryError>("Reloc section ended prematurely",
884 object_error::parse_failed);
885 return Error::success();
886 }
887
parseCustomSection(WasmSection & Sec,ReadContext & Ctx)888 Error WasmObjectFile::parseCustomSection(WasmSection &Sec, ReadContext &Ctx) {
889 if (Sec.Name == "dylink") {
890 if (Error Err = parseDylinkSection(Ctx))
891 return Err;
892 } else if (Sec.Name == "name") {
893 if (Error Err = parseNameSection(Ctx))
894 return Err;
895 } else if (Sec.Name == "linking") {
896 if (Error Err = parseLinkingSection(Ctx))
897 return Err;
898 } else if (Sec.Name == "producers") {
899 if (Error Err = parseProducersSection(Ctx))
900 return Err;
901 } else if (Sec.Name == "target_features") {
902 if (Error Err = parseTargetFeaturesSection(Ctx))
903 return Err;
904 } else if (Sec.Name.startswith("reloc.")) {
905 if (Error Err = parseRelocSection(Sec.Name, Ctx))
906 return Err;
907 }
908 return Error::success();
909 }
910
parseTypeSection(ReadContext & Ctx)911 Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) {
912 uint32_t Count = readVaruint32(Ctx);
913 Signatures.reserve(Count);
914 while (Count--) {
915 wasm::WasmSignature Sig;
916 uint8_t Form = readUint8(Ctx);
917 if (Form != wasm::WASM_TYPE_FUNC) {
918 return make_error<GenericBinaryError>("Invalid signature type",
919 object_error::parse_failed);
920 }
921 uint32_t ParamCount = readVaruint32(Ctx);
922 Sig.Params.reserve(ParamCount);
923 while (ParamCount--) {
924 uint32_t ParamType = readUint8(Ctx);
925 Sig.Params.push_back(wasm::ValType(ParamType));
926 }
927 uint32_t ReturnCount = readVaruint32(Ctx);
928 while (ReturnCount--) {
929 uint32_t ReturnType = readUint8(Ctx);
930 Sig.Returns.push_back(wasm::ValType(ReturnType));
931 }
932 Signatures.push_back(std::move(Sig));
933 }
934 if (Ctx.Ptr != Ctx.End)
935 return make_error<GenericBinaryError>("Type section ended prematurely",
936 object_error::parse_failed);
937 return Error::success();
938 }
939
parseImportSection(ReadContext & Ctx)940 Error WasmObjectFile::parseImportSection(ReadContext &Ctx) {
941 uint32_t Count = readVaruint32(Ctx);
942 Imports.reserve(Count);
943 for (uint32_t I = 0; I < Count; I++) {
944 wasm::WasmImport Im;
945 Im.Module = readString(Ctx);
946 Im.Field = readString(Ctx);
947 Im.Kind = readUint8(Ctx);
948 switch (Im.Kind) {
949 case wasm::WASM_EXTERNAL_FUNCTION:
950 NumImportedFunctions++;
951 Im.SigIndex = readVaruint32(Ctx);
952 break;
953 case wasm::WASM_EXTERNAL_GLOBAL:
954 NumImportedGlobals++;
955 Im.Global.Type = readUint8(Ctx);
956 Im.Global.Mutable = readVaruint1(Ctx);
957 break;
958 case wasm::WASM_EXTERNAL_MEMORY:
959 Im.Memory = readLimits(Ctx);
960 break;
961 case wasm::WASM_EXTERNAL_TABLE:
962 Im.Table = readTable(Ctx);
963 if (Im.Table.ElemType != wasm::WASM_TYPE_FUNCREF)
964 return make_error<GenericBinaryError>("Invalid table element type",
965 object_error::parse_failed);
966 break;
967 case wasm::WASM_EXTERNAL_EVENT:
968 NumImportedEvents++;
969 Im.Event.Attribute = readVarint32(Ctx);
970 Im.Event.SigIndex = readVarint32(Ctx);
971 break;
972 default:
973 return make_error<GenericBinaryError>("Unexpected import kind",
974 object_error::parse_failed);
975 }
976 Imports.push_back(Im);
977 }
978 if (Ctx.Ptr != Ctx.End)
979 return make_error<GenericBinaryError>("Import section ended prematurely",
980 object_error::parse_failed);
981 return Error::success();
982 }
983
parseFunctionSection(ReadContext & Ctx)984 Error WasmObjectFile::parseFunctionSection(ReadContext &Ctx) {
985 uint32_t Count = readVaruint32(Ctx);
986 FunctionTypes.reserve(Count);
987 Functions.resize(Count);
988 uint32_t NumTypes = Signatures.size();
989 while (Count--) {
990 uint32_t Type = readVaruint32(Ctx);
991 if (Type >= NumTypes)
992 return make_error<GenericBinaryError>("Invalid function type",
993 object_error::parse_failed);
994 FunctionTypes.push_back(Type);
995 }
996 if (Ctx.Ptr != Ctx.End)
997 return make_error<GenericBinaryError>("Function section ended prematurely",
998 object_error::parse_failed);
999 return Error::success();
1000 }
1001
parseTableSection(ReadContext & Ctx)1002 Error WasmObjectFile::parseTableSection(ReadContext &Ctx) {
1003 uint32_t Count = readVaruint32(Ctx);
1004 Tables.reserve(Count);
1005 while (Count--) {
1006 Tables.push_back(readTable(Ctx));
1007 if (Tables.back().ElemType != wasm::WASM_TYPE_FUNCREF) {
1008 return make_error<GenericBinaryError>("Invalid table element type",
1009 object_error::parse_failed);
1010 }
1011 }
1012 if (Ctx.Ptr != Ctx.End)
1013 return make_error<GenericBinaryError>("Table section ended prematurely",
1014 object_error::parse_failed);
1015 return Error::success();
1016 }
1017
parseMemorySection(ReadContext & Ctx)1018 Error WasmObjectFile::parseMemorySection(ReadContext &Ctx) {
1019 uint32_t Count = readVaruint32(Ctx);
1020 Memories.reserve(Count);
1021 while (Count--) {
1022 Memories.push_back(readLimits(Ctx));
1023 }
1024 if (Ctx.Ptr != Ctx.End)
1025 return make_error<GenericBinaryError>("Memory section ended prematurely",
1026 object_error::parse_failed);
1027 return Error::success();
1028 }
1029
parseEventSection(ReadContext & Ctx)1030 Error WasmObjectFile::parseEventSection(ReadContext &Ctx) {
1031 EventSection = Sections.size();
1032 uint32_t Count = readVarint32(Ctx);
1033 Events.reserve(Count);
1034 while (Count--) {
1035 wasm::WasmEvent Event;
1036 Event.Index = NumImportedEvents + Events.size();
1037 Event.Type.Attribute = readVaruint32(Ctx);
1038 Event.Type.SigIndex = readVarint32(Ctx);
1039 Events.push_back(Event);
1040 }
1041
1042 if (Ctx.Ptr != Ctx.End)
1043 return make_error<GenericBinaryError>("Event section ended prematurely",
1044 object_error::parse_failed);
1045 return Error::success();
1046 }
1047
parseGlobalSection(ReadContext & Ctx)1048 Error WasmObjectFile::parseGlobalSection(ReadContext &Ctx) {
1049 GlobalSection = Sections.size();
1050 uint32_t Count = readVaruint32(Ctx);
1051 Globals.reserve(Count);
1052 while (Count--) {
1053 wasm::WasmGlobal Global;
1054 Global.Index = NumImportedGlobals + Globals.size();
1055 Global.Type.Type = readUint8(Ctx);
1056 Global.Type.Mutable = readVaruint1(Ctx);
1057 if (Error Err = readInitExpr(Global.InitExpr, Ctx))
1058 return Err;
1059 Globals.push_back(Global);
1060 }
1061 if (Ctx.Ptr != Ctx.End)
1062 return make_error<GenericBinaryError>("Global section ended prematurely",
1063 object_error::parse_failed);
1064 return Error::success();
1065 }
1066
parseExportSection(ReadContext & Ctx)1067 Error WasmObjectFile::parseExportSection(ReadContext &Ctx) {
1068 uint32_t Count = readVaruint32(Ctx);
1069 Exports.reserve(Count);
1070 for (uint32_t I = 0; I < Count; I++) {
1071 wasm::WasmExport Ex;
1072 Ex.Name = readString(Ctx);
1073 Ex.Kind = readUint8(Ctx);
1074 Ex.Index = readVaruint32(Ctx);
1075 switch (Ex.Kind) {
1076 case wasm::WASM_EXTERNAL_FUNCTION:
1077
1078 if (!isDefinedFunctionIndex(Ex.Index))
1079 return make_error<GenericBinaryError>("Invalid function export",
1080 object_error::parse_failed);
1081 getDefinedFunction(Ex.Index).ExportName = Ex.Name;
1082 break;
1083 case wasm::WASM_EXTERNAL_GLOBAL:
1084 if (!isValidGlobalIndex(Ex.Index))
1085 return make_error<GenericBinaryError>("Invalid global export",
1086 object_error::parse_failed);
1087 break;
1088 case wasm::WASM_EXTERNAL_EVENT:
1089 if (!isValidEventIndex(Ex.Index))
1090 return make_error<GenericBinaryError>("Invalid event export",
1091 object_error::parse_failed);
1092 break;
1093 case wasm::WASM_EXTERNAL_MEMORY:
1094 case wasm::WASM_EXTERNAL_TABLE:
1095 break;
1096 default:
1097 return make_error<GenericBinaryError>("Unexpected export kind",
1098 object_error::parse_failed);
1099 }
1100 Exports.push_back(Ex);
1101 }
1102 if (Ctx.Ptr != Ctx.End)
1103 return make_error<GenericBinaryError>("Export section ended prematurely",
1104 object_error::parse_failed);
1105 return Error::success();
1106 }
1107
isValidFunctionIndex(uint32_t Index) const1108 bool WasmObjectFile::isValidFunctionIndex(uint32_t Index) const {
1109 return Index < NumImportedFunctions + FunctionTypes.size();
1110 }
1111
isDefinedFunctionIndex(uint32_t Index) const1112 bool WasmObjectFile::isDefinedFunctionIndex(uint32_t Index) const {
1113 return Index >= NumImportedFunctions && isValidFunctionIndex(Index);
1114 }
1115
isValidGlobalIndex(uint32_t Index) const1116 bool WasmObjectFile::isValidGlobalIndex(uint32_t Index) const {
1117 return Index < NumImportedGlobals + Globals.size();
1118 }
1119
isDefinedGlobalIndex(uint32_t Index) const1120 bool WasmObjectFile::isDefinedGlobalIndex(uint32_t Index) const {
1121 return Index >= NumImportedGlobals && isValidGlobalIndex(Index);
1122 }
1123
isValidEventIndex(uint32_t Index) const1124 bool WasmObjectFile::isValidEventIndex(uint32_t Index) const {
1125 return Index < NumImportedEvents + Events.size();
1126 }
1127
isDefinedEventIndex(uint32_t Index) const1128 bool WasmObjectFile::isDefinedEventIndex(uint32_t Index) const {
1129 return Index >= NumImportedEvents && isValidEventIndex(Index);
1130 }
1131
isValidFunctionSymbol(uint32_t Index) const1132 bool WasmObjectFile::isValidFunctionSymbol(uint32_t Index) const {
1133 return Index < Symbols.size() && Symbols[Index].isTypeFunction();
1134 }
1135
isValidGlobalSymbol(uint32_t Index) const1136 bool WasmObjectFile::isValidGlobalSymbol(uint32_t Index) const {
1137 return Index < Symbols.size() && Symbols[Index].isTypeGlobal();
1138 }
1139
isValidEventSymbol(uint32_t Index) const1140 bool WasmObjectFile::isValidEventSymbol(uint32_t Index) const {
1141 return Index < Symbols.size() && Symbols[Index].isTypeEvent();
1142 }
1143
isValidDataSymbol(uint32_t Index) const1144 bool WasmObjectFile::isValidDataSymbol(uint32_t Index) const {
1145 return Index < Symbols.size() && Symbols[Index].isTypeData();
1146 }
1147
isValidSectionSymbol(uint32_t Index) const1148 bool WasmObjectFile::isValidSectionSymbol(uint32_t Index) const {
1149 return Index < Symbols.size() && Symbols[Index].isTypeSection();
1150 }
1151
getDefinedFunction(uint32_t Index)1152 wasm::WasmFunction &WasmObjectFile::getDefinedFunction(uint32_t Index) {
1153 assert(isDefinedFunctionIndex(Index));
1154 return Functions[Index - NumImportedFunctions];
1155 }
1156
1157 const wasm::WasmFunction &
getDefinedFunction(uint32_t Index) const1158 WasmObjectFile::getDefinedFunction(uint32_t Index) const {
1159 assert(isDefinedFunctionIndex(Index));
1160 return Functions[Index - NumImportedFunctions];
1161 }
1162
getDefinedGlobal(uint32_t Index)1163 wasm::WasmGlobal &WasmObjectFile::getDefinedGlobal(uint32_t Index) {
1164 assert(isDefinedGlobalIndex(Index));
1165 return Globals[Index - NumImportedGlobals];
1166 }
1167
getDefinedEvent(uint32_t Index)1168 wasm::WasmEvent &WasmObjectFile::getDefinedEvent(uint32_t Index) {
1169 assert(isDefinedEventIndex(Index));
1170 return Events[Index - NumImportedEvents];
1171 }
1172
parseStartSection(ReadContext & Ctx)1173 Error WasmObjectFile::parseStartSection(ReadContext &Ctx) {
1174 StartFunction = readVaruint32(Ctx);
1175 if (!isValidFunctionIndex(StartFunction))
1176 return make_error<GenericBinaryError>("Invalid start function",
1177 object_error::parse_failed);
1178 return Error::success();
1179 }
1180
parseCodeSection(ReadContext & Ctx)1181 Error WasmObjectFile::parseCodeSection(ReadContext &Ctx) {
1182 SeenCodeSection = true;
1183 CodeSection = Sections.size();
1184 uint32_t FunctionCount = readVaruint32(Ctx);
1185 if (FunctionCount != FunctionTypes.size()) {
1186 return make_error<GenericBinaryError>("Invalid function count",
1187 object_error::parse_failed);
1188 }
1189
1190 for (uint32_t i = 0; i < FunctionCount; i++) {
1191 wasm::WasmFunction& Function = Functions[i];
1192 const uint8_t *FunctionStart = Ctx.Ptr;
1193 uint32_t Size = readVaruint32(Ctx);
1194 const uint8_t *FunctionEnd = Ctx.Ptr + Size;
1195
1196 Function.CodeOffset = Ctx.Ptr - FunctionStart;
1197 Function.Index = NumImportedFunctions + i;
1198 Function.CodeSectionOffset = FunctionStart - Ctx.Start;
1199 Function.Size = FunctionEnd - FunctionStart;
1200
1201 uint32_t NumLocalDecls = readVaruint32(Ctx);
1202 Function.Locals.reserve(NumLocalDecls);
1203 while (NumLocalDecls--) {
1204 wasm::WasmLocalDecl Decl;
1205 Decl.Count = readVaruint32(Ctx);
1206 Decl.Type = readUint8(Ctx);
1207 Function.Locals.push_back(Decl);
1208 }
1209
1210 uint32_t BodySize = FunctionEnd - Ctx.Ptr;
1211 Function.Body = ArrayRef<uint8_t>(Ctx.Ptr, BodySize);
1212 // This will be set later when reading in the linking metadata section.
1213 Function.Comdat = UINT32_MAX;
1214 Ctx.Ptr += BodySize;
1215 assert(Ctx.Ptr == FunctionEnd);
1216 }
1217 if (Ctx.Ptr != Ctx.End)
1218 return make_error<GenericBinaryError>("Code section ended prematurely",
1219 object_error::parse_failed);
1220 return Error::success();
1221 }
1222
parseElemSection(ReadContext & Ctx)1223 Error WasmObjectFile::parseElemSection(ReadContext &Ctx) {
1224 uint32_t Count = readVaruint32(Ctx);
1225 ElemSegments.reserve(Count);
1226 while (Count--) {
1227 wasm::WasmElemSegment Segment;
1228 Segment.TableIndex = readVaruint32(Ctx);
1229 if (Segment.TableIndex != 0) {
1230 return make_error<GenericBinaryError>("Invalid TableIndex",
1231 object_error::parse_failed);
1232 }
1233 if (Error Err = readInitExpr(Segment.Offset, Ctx))
1234 return Err;
1235 uint32_t NumElems = readVaruint32(Ctx);
1236 while (NumElems--) {
1237 Segment.Functions.push_back(readVaruint32(Ctx));
1238 }
1239 ElemSegments.push_back(Segment);
1240 }
1241 if (Ctx.Ptr != Ctx.End)
1242 return make_error<GenericBinaryError>("Elem section ended prematurely",
1243 object_error::parse_failed);
1244 return Error::success();
1245 }
1246
parseDataSection(ReadContext & Ctx)1247 Error WasmObjectFile::parseDataSection(ReadContext &Ctx) {
1248 DataSection = Sections.size();
1249 uint32_t Count = readVaruint32(Ctx);
1250 if (DataCount && Count != DataCount.getValue())
1251 return make_error<GenericBinaryError>(
1252 "Number of data segments does not match DataCount section");
1253 DataSegments.reserve(Count);
1254 while (Count--) {
1255 WasmSegment Segment;
1256 Segment.Data.InitFlags = readVaruint32(Ctx);
1257 Segment.Data.MemoryIndex = (Segment.Data.InitFlags & wasm::WASM_SEGMENT_HAS_MEMINDEX)
1258 ? readVaruint32(Ctx) : 0;
1259 if ((Segment.Data.InitFlags & wasm::WASM_SEGMENT_IS_PASSIVE) == 0) {
1260 if (Error Err = readInitExpr(Segment.Data.Offset, Ctx))
1261 return Err;
1262 } else {
1263 Segment.Data.Offset.Opcode = wasm::WASM_OPCODE_I32_CONST;
1264 Segment.Data.Offset.Value.Int32 = 0;
1265 }
1266 uint32_t Size = readVaruint32(Ctx);
1267 if (Size > (size_t)(Ctx.End - Ctx.Ptr))
1268 return make_error<GenericBinaryError>("Invalid segment size",
1269 object_error::parse_failed);
1270 Segment.Data.Content = ArrayRef<uint8_t>(Ctx.Ptr, Size);
1271 // The rest of these Data fields are set later, when reading in the linking
1272 // metadata section.
1273 Segment.Data.Alignment = 0;
1274 Segment.Data.LinkerFlags = 0;
1275 Segment.Data.Comdat = UINT32_MAX;
1276 Segment.SectionOffset = Ctx.Ptr - Ctx.Start;
1277 Ctx.Ptr += Size;
1278 DataSegments.push_back(Segment);
1279 }
1280 if (Ctx.Ptr != Ctx.End)
1281 return make_error<GenericBinaryError>("Data section ended prematurely",
1282 object_error::parse_failed);
1283 return Error::success();
1284 }
1285
parseDataCountSection(ReadContext & Ctx)1286 Error WasmObjectFile::parseDataCountSection(ReadContext &Ctx) {
1287 DataCount = readVaruint32(Ctx);
1288 return Error::success();
1289 }
1290
getHeader() const1291 const wasm::WasmObjectHeader &WasmObjectFile::getHeader() const {
1292 return Header;
1293 }
1294
moveSymbolNext(DataRefImpl & Symb) const1295 void WasmObjectFile::moveSymbolNext(DataRefImpl &Symb) const { Symb.d.b++; }
1296
getSymbolFlags(DataRefImpl Symb) const1297 Expected<uint32_t> WasmObjectFile::getSymbolFlags(DataRefImpl Symb) const {
1298 uint32_t Result = SymbolRef::SF_None;
1299 const WasmSymbol &Sym = getWasmSymbol(Symb);
1300
1301 LLVM_DEBUG(dbgs() << "getSymbolFlags: ptr=" << &Sym << " " << Sym << "\n");
1302 if (Sym.isBindingWeak())
1303 Result |= SymbolRef::SF_Weak;
1304 if (!Sym.isBindingLocal())
1305 Result |= SymbolRef::SF_Global;
1306 if (Sym.isHidden())
1307 Result |= SymbolRef::SF_Hidden;
1308 if (!Sym.isDefined())
1309 Result |= SymbolRef::SF_Undefined;
1310 if (Sym.isTypeFunction())
1311 Result |= SymbolRef::SF_Executable;
1312 return Result;
1313 }
1314
symbol_begin() const1315 basic_symbol_iterator WasmObjectFile::symbol_begin() const {
1316 DataRefImpl Ref;
1317 Ref.d.a = 1; // Arbitrary non-zero value so that Ref.p is non-null
1318 Ref.d.b = 0; // Symbol index
1319 return BasicSymbolRef(Ref, this);
1320 }
1321
symbol_end() const1322 basic_symbol_iterator WasmObjectFile::symbol_end() const {
1323 DataRefImpl Ref;
1324 Ref.d.a = 1; // Arbitrary non-zero value so that Ref.p is non-null
1325 Ref.d.b = Symbols.size(); // Symbol index
1326 return BasicSymbolRef(Ref, this);
1327 }
1328
getWasmSymbol(const DataRefImpl & Symb) const1329 const WasmSymbol &WasmObjectFile::getWasmSymbol(const DataRefImpl &Symb) const {
1330 return Symbols[Symb.d.b];
1331 }
1332
getWasmSymbol(const SymbolRef & Symb) const1333 const WasmSymbol &WasmObjectFile::getWasmSymbol(const SymbolRef &Symb) const {
1334 return getWasmSymbol(Symb.getRawDataRefImpl());
1335 }
1336
getSymbolName(DataRefImpl Symb) const1337 Expected<StringRef> WasmObjectFile::getSymbolName(DataRefImpl Symb) const {
1338 return getWasmSymbol(Symb).Info.Name;
1339 }
1340
getSymbolAddress(DataRefImpl Symb) const1341 Expected<uint64_t> WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const {
1342 auto &Sym = getWasmSymbol(Symb);
1343 if (Sym.Info.Kind == wasm::WASM_SYMBOL_TYPE_FUNCTION &&
1344 isDefinedFunctionIndex(Sym.Info.ElementIndex))
1345 return getDefinedFunction(Sym.Info.ElementIndex).CodeSectionOffset;
1346 else
1347 return getSymbolValue(Symb);
1348 }
1349
getWasmSymbolValue(const WasmSymbol & Sym) const1350 uint64_t WasmObjectFile::getWasmSymbolValue(const WasmSymbol &Sym) const {
1351 switch (Sym.Info.Kind) {
1352 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1353 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1354 case wasm::WASM_SYMBOL_TYPE_EVENT:
1355 return Sym.Info.ElementIndex;
1356 case wasm::WASM_SYMBOL_TYPE_DATA: {
1357 // The value of a data symbol is the segment offset, plus the symbol
1358 // offset within the segment.
1359 uint32_t SegmentIndex = Sym.Info.DataRef.Segment;
1360 const wasm::WasmDataSegment &Segment = DataSegments[SegmentIndex].Data;
1361 if (Segment.Offset.Opcode == wasm::WASM_OPCODE_I32_CONST) {
1362 return Segment.Offset.Value.Int32 + Sym.Info.DataRef.Offset;
1363 } else if (Segment.Offset.Opcode == wasm::WASM_OPCODE_I64_CONST) {
1364 return Segment.Offset.Value.Int64 + Sym.Info.DataRef.Offset;
1365 } else {
1366 llvm_unreachable("unknown init expr opcode");
1367 }
1368 }
1369 case wasm::WASM_SYMBOL_TYPE_SECTION:
1370 return 0;
1371 }
1372 llvm_unreachable("invalid symbol type");
1373 }
1374
getSymbolValueImpl(DataRefImpl Symb) const1375 uint64_t WasmObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
1376 return getWasmSymbolValue(getWasmSymbol(Symb));
1377 }
1378
getSymbolAlignment(DataRefImpl Symb) const1379 uint32_t WasmObjectFile::getSymbolAlignment(DataRefImpl Symb) const {
1380 llvm_unreachable("not yet implemented");
1381 return 0;
1382 }
1383
getCommonSymbolSizeImpl(DataRefImpl Symb) const1384 uint64_t WasmObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
1385 llvm_unreachable("not yet implemented");
1386 return 0;
1387 }
1388
1389 Expected<SymbolRef::Type>
getSymbolType(DataRefImpl Symb) const1390 WasmObjectFile::getSymbolType(DataRefImpl Symb) const {
1391 const WasmSymbol &Sym = getWasmSymbol(Symb);
1392
1393 switch (Sym.Info.Kind) {
1394 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1395 return SymbolRef::ST_Function;
1396 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1397 return SymbolRef::ST_Other;
1398 case wasm::WASM_SYMBOL_TYPE_DATA:
1399 return SymbolRef::ST_Data;
1400 case wasm::WASM_SYMBOL_TYPE_SECTION:
1401 return SymbolRef::ST_Debug;
1402 case wasm::WASM_SYMBOL_TYPE_EVENT:
1403 return SymbolRef::ST_Other;
1404 }
1405
1406 llvm_unreachable("Unknown WasmSymbol::SymbolType");
1407 return SymbolRef::ST_Other;
1408 }
1409
1410 Expected<section_iterator>
getSymbolSection(DataRefImpl Symb) const1411 WasmObjectFile::getSymbolSection(DataRefImpl Symb) const {
1412 const WasmSymbol &Sym = getWasmSymbol(Symb);
1413 if (Sym.isUndefined())
1414 return section_end();
1415
1416 DataRefImpl Ref;
1417 Ref.d.a = getSymbolSectionIdImpl(Sym);
1418 return section_iterator(SectionRef(Ref, this));
1419 }
1420
getSymbolSectionId(SymbolRef Symb) const1421 uint32_t WasmObjectFile::getSymbolSectionId(SymbolRef Symb) const {
1422 const WasmSymbol &Sym = getWasmSymbol(Symb);
1423 return getSymbolSectionIdImpl(Sym);
1424 }
1425
getSymbolSectionIdImpl(const WasmSymbol & Sym) const1426 uint32_t WasmObjectFile::getSymbolSectionIdImpl(const WasmSymbol &Sym) const {
1427 switch (Sym.Info.Kind) {
1428 case wasm::WASM_SYMBOL_TYPE_FUNCTION:
1429 return CodeSection;
1430 case wasm::WASM_SYMBOL_TYPE_GLOBAL:
1431 return GlobalSection;
1432 case wasm::WASM_SYMBOL_TYPE_DATA:
1433 return DataSection;
1434 case wasm::WASM_SYMBOL_TYPE_SECTION:
1435 return Sym.Info.ElementIndex;
1436 case wasm::WASM_SYMBOL_TYPE_EVENT:
1437 return EventSection;
1438 default:
1439 llvm_unreachable("Unknown WasmSymbol::SymbolType");
1440 }
1441 }
1442
moveSectionNext(DataRefImpl & Sec) const1443 void WasmObjectFile::moveSectionNext(DataRefImpl &Sec) const { Sec.d.a++; }
1444
getSectionName(DataRefImpl Sec) const1445 Expected<StringRef> WasmObjectFile::getSectionName(DataRefImpl Sec) const {
1446 const WasmSection &S = Sections[Sec.d.a];
1447 #define ECase(X) \
1448 case wasm::WASM_SEC_##X: \
1449 return #X;
1450 switch (S.Type) {
1451 ECase(TYPE);
1452 ECase(IMPORT);
1453 ECase(FUNCTION);
1454 ECase(TABLE);
1455 ECase(MEMORY);
1456 ECase(GLOBAL);
1457 ECase(EVENT);
1458 ECase(EXPORT);
1459 ECase(START);
1460 ECase(ELEM);
1461 ECase(CODE);
1462 ECase(DATA);
1463 ECase(DATACOUNT);
1464 case wasm::WASM_SEC_CUSTOM:
1465 return S.Name;
1466 default:
1467 return createStringError(object_error::invalid_section_index, "");
1468 }
1469 #undef ECase
1470 }
1471
getSectionAddress(DataRefImpl Sec) const1472 uint64_t WasmObjectFile::getSectionAddress(DataRefImpl Sec) const { return 0; }
1473
getSectionIndex(DataRefImpl Sec) const1474 uint64_t WasmObjectFile::getSectionIndex(DataRefImpl Sec) const {
1475 return Sec.d.a;
1476 }
1477
getSectionSize(DataRefImpl Sec) const1478 uint64_t WasmObjectFile::getSectionSize(DataRefImpl Sec) const {
1479 const WasmSection &S = Sections[Sec.d.a];
1480 return S.Content.size();
1481 }
1482
1483 Expected<ArrayRef<uint8_t>>
getSectionContents(DataRefImpl Sec) const1484 WasmObjectFile::getSectionContents(DataRefImpl Sec) const {
1485 const WasmSection &S = Sections[Sec.d.a];
1486 // This will never fail since wasm sections can never be empty (user-sections
1487 // must have a name and non-user sections each have a defined structure).
1488 return S.Content;
1489 }
1490
getSectionAlignment(DataRefImpl Sec) const1491 uint64_t WasmObjectFile::getSectionAlignment(DataRefImpl Sec) const {
1492 return 1;
1493 }
1494
isSectionCompressed(DataRefImpl Sec) const1495 bool WasmObjectFile::isSectionCompressed(DataRefImpl Sec) const {
1496 return false;
1497 }
1498
isSectionText(DataRefImpl Sec) const1499 bool WasmObjectFile::isSectionText(DataRefImpl Sec) const {
1500 return getWasmSection(Sec).Type == wasm::WASM_SEC_CODE;
1501 }
1502
isSectionData(DataRefImpl Sec) const1503 bool WasmObjectFile::isSectionData(DataRefImpl Sec) const {
1504 return getWasmSection(Sec).Type == wasm::WASM_SEC_DATA;
1505 }
1506
isSectionBSS(DataRefImpl Sec) const1507 bool WasmObjectFile::isSectionBSS(DataRefImpl Sec) const { return false; }
1508
isSectionVirtual(DataRefImpl Sec) const1509 bool WasmObjectFile::isSectionVirtual(DataRefImpl Sec) const { return false; }
1510
section_rel_begin(DataRefImpl Ref) const1511 relocation_iterator WasmObjectFile::section_rel_begin(DataRefImpl Ref) const {
1512 DataRefImpl RelocRef;
1513 RelocRef.d.a = Ref.d.a;
1514 RelocRef.d.b = 0;
1515 return relocation_iterator(RelocationRef(RelocRef, this));
1516 }
1517
section_rel_end(DataRefImpl Ref) const1518 relocation_iterator WasmObjectFile::section_rel_end(DataRefImpl Ref) const {
1519 const WasmSection &Sec = getWasmSection(Ref);
1520 DataRefImpl RelocRef;
1521 RelocRef.d.a = Ref.d.a;
1522 RelocRef.d.b = Sec.Relocations.size();
1523 return relocation_iterator(RelocationRef(RelocRef, this));
1524 }
1525
moveRelocationNext(DataRefImpl & Rel) const1526 void WasmObjectFile::moveRelocationNext(DataRefImpl &Rel) const { Rel.d.b++; }
1527
getRelocationOffset(DataRefImpl Ref) const1528 uint64_t WasmObjectFile::getRelocationOffset(DataRefImpl Ref) const {
1529 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1530 return Rel.Offset;
1531 }
1532
getRelocationSymbol(DataRefImpl Ref) const1533 symbol_iterator WasmObjectFile::getRelocationSymbol(DataRefImpl Ref) const {
1534 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1535 if (Rel.Type == wasm::R_WASM_TYPE_INDEX_LEB)
1536 return symbol_end();
1537 DataRefImpl Sym;
1538 Sym.d.a = 1;
1539 Sym.d.b = Rel.Index;
1540 return symbol_iterator(SymbolRef(Sym, this));
1541 }
1542
getRelocationType(DataRefImpl Ref) const1543 uint64_t WasmObjectFile::getRelocationType(DataRefImpl Ref) const {
1544 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1545 return Rel.Type;
1546 }
1547
getRelocationTypeName(DataRefImpl Ref,SmallVectorImpl<char> & Result) const1548 void WasmObjectFile::getRelocationTypeName(
1549 DataRefImpl Ref, SmallVectorImpl<char> &Result) const {
1550 const wasm::WasmRelocation &Rel = getWasmRelocation(Ref);
1551 StringRef Res = "Unknown";
1552
1553 #define WASM_RELOC(name, value) \
1554 case wasm::name: \
1555 Res = #name; \
1556 break;
1557
1558 switch (Rel.Type) {
1559 #include "llvm/BinaryFormat/WasmRelocs.def"
1560 }
1561
1562 #undef WASM_RELOC
1563
1564 Result.append(Res.begin(), Res.end());
1565 }
1566
section_begin() const1567 section_iterator WasmObjectFile::section_begin() const {
1568 DataRefImpl Ref;
1569 Ref.d.a = 0;
1570 return section_iterator(SectionRef(Ref, this));
1571 }
1572
section_end() const1573 section_iterator WasmObjectFile::section_end() const {
1574 DataRefImpl Ref;
1575 Ref.d.a = Sections.size();
1576 return section_iterator(SectionRef(Ref, this));
1577 }
1578
getBytesInAddress() const1579 uint8_t WasmObjectFile::getBytesInAddress() const { return 4; }
1580
getFileFormatName() const1581 StringRef WasmObjectFile::getFileFormatName() const { return "WASM"; }
1582
getArch() const1583 Triple::ArchType WasmObjectFile::getArch() const { return Triple::wasm32; }
1584
getFeatures() const1585 SubtargetFeatures WasmObjectFile::getFeatures() const {
1586 return SubtargetFeatures();
1587 }
1588
isRelocatableObject() const1589 bool WasmObjectFile::isRelocatableObject() const { return HasLinkingSection; }
1590
isSharedObject() const1591 bool WasmObjectFile::isSharedObject() const { return HasDylinkSection; }
1592
getWasmSection(DataRefImpl Ref) const1593 const WasmSection &WasmObjectFile::getWasmSection(DataRefImpl Ref) const {
1594 assert(Ref.d.a < Sections.size());
1595 return Sections[Ref.d.a];
1596 }
1597
1598 const WasmSection &
getWasmSection(const SectionRef & Section) const1599 WasmObjectFile::getWasmSection(const SectionRef &Section) const {
1600 return getWasmSection(Section.getRawDataRefImpl());
1601 }
1602
1603 const wasm::WasmRelocation &
getWasmRelocation(const RelocationRef & Ref) const1604 WasmObjectFile::getWasmRelocation(const RelocationRef &Ref) const {
1605 return getWasmRelocation(Ref.getRawDataRefImpl());
1606 }
1607
1608 const wasm::WasmRelocation &
getWasmRelocation(DataRefImpl Ref) const1609 WasmObjectFile::getWasmRelocation(DataRefImpl Ref) const {
1610 assert(Ref.d.a < Sections.size());
1611 const WasmSection &Sec = Sections[Ref.d.a];
1612 assert(Ref.d.b < Sec.Relocations.size());
1613 return Sec.Relocations[Ref.d.b];
1614 }
1615
getSectionOrder(unsigned ID,StringRef CustomSectionName)1616 int WasmSectionOrderChecker::getSectionOrder(unsigned ID,
1617 StringRef CustomSectionName) {
1618 switch (ID) {
1619 case wasm::WASM_SEC_CUSTOM:
1620 return StringSwitch<unsigned>(CustomSectionName)
1621 .Case("dylink", WASM_SEC_ORDER_DYLINK)
1622 .Case("linking", WASM_SEC_ORDER_LINKING)
1623 .StartsWith("reloc.", WASM_SEC_ORDER_RELOC)
1624 .Case("name", WASM_SEC_ORDER_NAME)
1625 .Case("producers", WASM_SEC_ORDER_PRODUCERS)
1626 .Case("target_features", WASM_SEC_ORDER_TARGET_FEATURES)
1627 .Default(WASM_SEC_ORDER_NONE);
1628 case wasm::WASM_SEC_TYPE:
1629 return WASM_SEC_ORDER_TYPE;
1630 case wasm::WASM_SEC_IMPORT:
1631 return WASM_SEC_ORDER_IMPORT;
1632 case wasm::WASM_SEC_FUNCTION:
1633 return WASM_SEC_ORDER_FUNCTION;
1634 case wasm::WASM_SEC_TABLE:
1635 return WASM_SEC_ORDER_TABLE;
1636 case wasm::WASM_SEC_MEMORY:
1637 return WASM_SEC_ORDER_MEMORY;
1638 case wasm::WASM_SEC_GLOBAL:
1639 return WASM_SEC_ORDER_GLOBAL;
1640 case wasm::WASM_SEC_EXPORT:
1641 return WASM_SEC_ORDER_EXPORT;
1642 case wasm::WASM_SEC_START:
1643 return WASM_SEC_ORDER_START;
1644 case wasm::WASM_SEC_ELEM:
1645 return WASM_SEC_ORDER_ELEM;
1646 case wasm::WASM_SEC_CODE:
1647 return WASM_SEC_ORDER_CODE;
1648 case wasm::WASM_SEC_DATA:
1649 return WASM_SEC_ORDER_DATA;
1650 case wasm::WASM_SEC_DATACOUNT:
1651 return WASM_SEC_ORDER_DATACOUNT;
1652 case wasm::WASM_SEC_EVENT:
1653 return WASM_SEC_ORDER_EVENT;
1654 default:
1655 return WASM_SEC_ORDER_NONE;
1656 }
1657 }
1658
1659 // Represents the edges in a directed graph where any node B reachable from node
1660 // A is not allowed to appear before A in the section ordering, but may appear
1661 // afterward.
1662 int WasmSectionOrderChecker::DisallowedPredecessors
1663 [WASM_NUM_SEC_ORDERS][WASM_NUM_SEC_ORDERS] = {
1664 // WASM_SEC_ORDER_NONE
1665 {},
1666 // WASM_SEC_ORDER_TYPE
1667 {WASM_SEC_ORDER_TYPE, WASM_SEC_ORDER_IMPORT},
1668 // WASM_SEC_ORDER_IMPORT
1669 {WASM_SEC_ORDER_IMPORT, WASM_SEC_ORDER_FUNCTION},
1670 // WASM_SEC_ORDER_FUNCTION
1671 {WASM_SEC_ORDER_FUNCTION, WASM_SEC_ORDER_TABLE},
1672 // WASM_SEC_ORDER_TABLE
1673 {WASM_SEC_ORDER_TABLE, WASM_SEC_ORDER_MEMORY},
1674 // WASM_SEC_ORDER_MEMORY
1675 {WASM_SEC_ORDER_MEMORY, WASM_SEC_ORDER_EVENT},
1676 // WASM_SEC_ORDER_EVENT
1677 {WASM_SEC_ORDER_EVENT, WASM_SEC_ORDER_GLOBAL},
1678 // WASM_SEC_ORDER_GLOBAL
1679 {WASM_SEC_ORDER_GLOBAL, WASM_SEC_ORDER_EXPORT},
1680 // WASM_SEC_ORDER_EXPORT
1681 {WASM_SEC_ORDER_EXPORT, WASM_SEC_ORDER_START},
1682 // WASM_SEC_ORDER_START
1683 {WASM_SEC_ORDER_START, WASM_SEC_ORDER_ELEM},
1684 // WASM_SEC_ORDER_ELEM
1685 {WASM_SEC_ORDER_ELEM, WASM_SEC_ORDER_DATACOUNT},
1686 // WASM_SEC_ORDER_DATACOUNT
1687 {WASM_SEC_ORDER_DATACOUNT, WASM_SEC_ORDER_CODE},
1688 // WASM_SEC_ORDER_CODE
1689 {WASM_SEC_ORDER_CODE, WASM_SEC_ORDER_DATA},
1690 // WASM_SEC_ORDER_DATA
1691 {WASM_SEC_ORDER_DATA, WASM_SEC_ORDER_LINKING},
1692
1693 // Custom Sections
1694 // WASM_SEC_ORDER_DYLINK
1695 {WASM_SEC_ORDER_DYLINK, WASM_SEC_ORDER_TYPE},
1696 // WASM_SEC_ORDER_LINKING
1697 {WASM_SEC_ORDER_LINKING, WASM_SEC_ORDER_RELOC, WASM_SEC_ORDER_NAME},
1698 // WASM_SEC_ORDER_RELOC (can be repeated)
1699 {},
1700 // WASM_SEC_ORDER_NAME
1701 {WASM_SEC_ORDER_NAME, WASM_SEC_ORDER_PRODUCERS},
1702 // WASM_SEC_ORDER_PRODUCERS
1703 {WASM_SEC_ORDER_PRODUCERS, WASM_SEC_ORDER_TARGET_FEATURES},
1704 // WASM_SEC_ORDER_TARGET_FEATURES
1705 {WASM_SEC_ORDER_TARGET_FEATURES}};
1706
isValidSectionOrder(unsigned ID,StringRef CustomSectionName)1707 bool WasmSectionOrderChecker::isValidSectionOrder(unsigned ID,
1708 StringRef CustomSectionName) {
1709 int Order = getSectionOrder(ID, CustomSectionName);
1710 if (Order == WASM_SEC_ORDER_NONE)
1711 return true;
1712
1713 // Disallowed predecessors we need to check for
1714 SmallVector<int, WASM_NUM_SEC_ORDERS> WorkList;
1715
1716 // Keep track of completed checks to avoid repeating work
1717 bool Checked[WASM_NUM_SEC_ORDERS] = {};
1718
1719 int Curr = Order;
1720 while (true) {
1721 // Add new disallowed predecessors to work list
1722 for (size_t I = 0;; ++I) {
1723 int Next = DisallowedPredecessors[Curr][I];
1724 if (Next == WASM_SEC_ORDER_NONE)
1725 break;
1726 if (Checked[Next])
1727 continue;
1728 WorkList.push_back(Next);
1729 Checked[Next] = true;
1730 }
1731
1732 if (WorkList.empty())
1733 break;
1734
1735 // Consider next disallowed predecessor
1736 Curr = WorkList.pop_back_val();
1737 if (Seen[Curr])
1738 return false;
1739 }
1740
1741 // Have not seen any disallowed predecessors
1742 Seen[Order] = true;
1743 return true;
1744 }
1745