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