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