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