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