/src/WasmEdge/lib/loader/ast/section.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | // SPDX-License-Identifier: Apache-2.0 |
2 | | // SPDX-FileCopyrightText: 2019-2024 Second State INC |
3 | | |
4 | | #include "aot/version.h" |
5 | | #include "common/defines.h" |
6 | | #include "loader/loader.h" |
7 | | |
8 | | #include <tuple> |
9 | | #include <utility> |
10 | | |
11 | | using namespace std::literals; |
12 | | |
13 | | namespace WasmEdge { |
14 | | namespace Loader { |
15 | | |
16 | | // Load content of custom section. See "include/loader/loader.h". |
17 | 45.0k | Expect<void> Loader::loadSection(AST::CustomSection &Sec) { |
18 | 45.0k | return loadSectionContent(Sec, [this, &Sec]() -> Expect<void> { |
19 | 45.0k | auto ReportError = [this](auto E) { |
20 | 120 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Sec_Custom); |
21 | 120 | }; |
22 | | |
23 | | // Read name. |
24 | 45.0k | auto StartOffset = FMgr.getOffset(); |
25 | 45.0k | EXPECTED_TRY(std::string Name, FMgr.readName().map_error(ReportError)); |
26 | 44.8k | Sec.setName(Name); |
27 | 44.8k | auto ReadSize = FMgr.getOffset() - StartOffset; |
28 | | |
29 | | // Read remain bytes. Check is overread or not first. |
30 | 44.8k | if (unlikely(Sec.getContentSize() < ReadSize)) { |
31 | 40 | return logLoadError(ErrCode::Value::UnexpectedEnd, FMgr.getLastOffset(), |
32 | 40 | ASTNodeAttr::Sec_Custom); |
33 | 40 | } |
34 | 44.8k | EXPECTED_TRY( |
35 | 44.8k | std::vector<uint8_t> Bytes, |
36 | 44.8k | FMgr.readBytes(Sec.getContentSize() - ReadSize).map_error(ReportError)); |
37 | 44.8k | Sec.getContent().insert(Sec.getContent().end(), Bytes.begin(), Bytes.end()); |
38 | 44.8k | return {}; |
39 | 44.8k | }); |
40 | 45.0k | } |
41 | | |
42 | | // Load vector of type section. See "include/loader/loader.h". |
43 | 4.55k | Expect<void> Loader::loadSection(AST::TypeSection &Sec) { |
44 | 4.55k | return loadSectionContent(Sec, [this, &Sec]() -> Expect<void> { |
45 | 4.53k | auto ReportError = [this](auto E) { |
46 | 23 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Sec_Type); |
47 | 23 | }; |
48 | | |
49 | | // Read the recursive type vector size. |
50 | 4.53k | EXPECTED_TRY(uint32_t VecCnt, loadVecCnt().map_error(ReportError)); |
51 | | // Read the recursive types. |
52 | 4.51k | Sec.getContent().clear(); |
53 | 4.51k | uint32_t SubTypeCnt = 0; |
54 | 12.9k | for (uint32_t I = 0; I < VecCnt; I++) { |
55 | 8.48k | EXPECTED_TRY(uint8_t CodeByte, FMgr.peekByte().map_error(ReportError)); |
56 | | |
57 | 8.48k | TypeCode Code = static_cast<TypeCode>(CodeByte); |
58 | 8.48k | if (!Conf.hasProposal(Proposal::GC) && Code != TypeCode::Func) { |
59 | 24 | return logNeedProposal(ErrCode::Value::IntegerTooLong, Proposal::GC, |
60 | 24 | FMgr.getOffset(), ASTNodeAttr::Sec_Type); |
61 | 24 | } |
62 | 8.46k | if (Code == TypeCode::Rec) { |
63 | | // Case: 0x4E vec(subtype). |
64 | 0 | FMgr.readByte(); |
65 | 0 | EXPECTED_TRY(uint32_t RecVecCnt, loadVecCnt().map_error(ReportError)); |
66 | 0 | for (uint32_t J = 0; J < RecVecCnt; ++J) { |
67 | 0 | Sec.getContent().emplace_back(); |
68 | 0 | EXPECTED_TRY(loadType(Sec.getContent().back()).map_error([](auto E) { |
69 | 0 | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Type)); |
70 | 0 | return E; |
71 | 0 | })); |
72 | 0 | Sec.getContent().back().setRecursiveInfo(J, RecVecCnt); |
73 | 0 | Sec.getContent().back().setTypeIndex(SubTypeCnt); |
74 | 0 | SubTypeCnt++; |
75 | 0 | } |
76 | 8.46k | } else { |
77 | | // Case: subtype. |
78 | 8.46k | Sec.getContent().emplace_back(); |
79 | 8.46k | Sec.getContent().back().setTypeIndex(SubTypeCnt); |
80 | 8.46k | SubTypeCnt++; |
81 | 8.46k | EXPECTED_TRY(loadType(Sec.getContent().back()).map_error([](auto E) { |
82 | 8.46k | spdlog::error(ErrInfo::InfoAST(ASTNodeAttr::Sec_Type)); |
83 | 8.46k | return E; |
84 | 8.46k | })); |
85 | 8.46k | } |
86 | 8.46k | } |
87 | 4.41k | return {}; |
88 | 4.51k | }); |
89 | 4.55k | } |
90 | | |
91 | | // Load vector of import section. See "include/loader/loader.h". |
92 | 279 | Expect<void> Loader::loadSection(AST::ImportSection &Sec) { |
93 | 279 | return loadSectionContent(Sec, [this, &Sec]() { |
94 | 258 | return loadSectionContentVec( |
95 | 11.2k | Sec, [this](AST::ImportDesc &ImpDesc) { return loadDesc(ImpDesc); }); |
96 | 258 | }); |
97 | 279 | } |
98 | | |
99 | | // Load vector of function section. See "include/loader/loader.h". |
100 | 4.36k | Expect<void> Loader::loadSection(AST::FunctionSection &Sec) { |
101 | 4.36k | return loadSectionContent(Sec, [this, &Sec]() { |
102 | 4.34k | return loadSectionContentVec( |
103 | 36.4k | Sec, [this](uint32_t &FuncIdx) -> Expect<void> { |
104 | 36.4k | EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error([this](auto E) { |
105 | 36.3k | return logLoadError(E, FMgr.getLastOffset(), |
106 | 36.3k | ASTNodeAttr::Sec_Function); |
107 | 36.3k | })); |
108 | 36.3k | FuncIdx = Idx; |
109 | 36.3k | return {}; |
110 | 36.4k | }); |
111 | 4.34k | }); |
112 | 4.36k | } |
113 | | |
114 | | // Load vector of table section. See "include/loader/loader.h". |
115 | 443 | Expect<void> Loader::loadSection(AST::TableSection &Sec) { |
116 | 443 | return loadSectionContent(Sec, [this, &Sec]() { |
117 | 427 | return loadSectionContentVec( |
118 | 580 | Sec, [this](AST::TableSegment &TabSeg) { return loadSegment(TabSeg); }); |
119 | 427 | }); |
120 | 443 | } |
121 | | |
122 | | // Load vector of memory section. See "include/loader/loader.h". |
123 | 1.53k | Expect<void> Loader::loadSection(AST::MemorySection &Sec) { |
124 | 1.53k | return loadSectionContent(Sec, [this, &Sec]() { |
125 | 1.51k | return loadSectionContentVec( |
126 | 2.88k | Sec, [this](AST::MemoryType &MemType) { return loadType(MemType); }); |
127 | 1.51k | }); |
128 | 1.53k | } |
129 | | |
130 | | // Load vector of global section. See "include/loader/loader.h". |
131 | 683 | Expect<void> Loader::loadSection(AST::GlobalSection &Sec) { |
132 | 683 | return loadSectionContent(Sec, [this, &Sec]() { |
133 | 926 | return loadSectionContentVec(Sec, [this](AST::GlobalSegment &GlobSeg) { |
134 | 926 | return loadSegment(GlobSeg); |
135 | 926 | }); |
136 | 666 | }); |
137 | 683 | } |
138 | | |
139 | | // Load vector of export section. See "include/loader/loader.h". |
140 | 1.25k | Expect<void> Loader::loadSection(AST::ExportSection &Sec) { |
141 | 1.25k | return loadSectionContent(Sec, [this, &Sec]() { |
142 | 1.23k | return loadSectionContentVec( |
143 | 21.8k | Sec, [this](AST::ExportDesc &ExpDesc) { return loadDesc(ExpDesc); }); |
144 | 1.23k | }); |
145 | 1.25k | } |
146 | | |
147 | | // Load start function index. See "include/loader/loader.h". |
148 | 46 | Expect<void> Loader::loadSection(AST::StartSection &Sec) { |
149 | 46 | return loadSectionContent(Sec, [this, &Sec]() -> Expect<void> { |
150 | | // Read u32 of start function index. |
151 | 28 | EXPECTED_TRY(uint32_t Idx, FMgr.readU32().map_error([this](auto E) { |
152 | 25 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Sec_Start); |
153 | 25 | })); |
154 | 25 | Sec.setContent(Idx); |
155 | 25 | return {}; |
156 | 28 | }); |
157 | 46 | } |
158 | | |
159 | | // Load vector of element section. See "include/loader/loader.h". |
160 | 1.43k | Expect<void> Loader::loadSection(AST::ElementSection &Sec) { |
161 | 1.43k | return loadSectionContent(Sec, [this, &Sec]() { |
162 | 6.27k | return loadSectionContentVec(Sec, [this](AST::ElementSegment &ElemSeg) { |
163 | 6.27k | return loadSegment(ElemSeg); |
164 | 6.27k | }); |
165 | 1.41k | }); |
166 | 1.43k | } |
167 | | |
168 | | // Load vector of code section. See "include/loader/loader.h". |
169 | 4.58k | Expect<void> Loader::loadSection(AST::CodeSection &Sec) { |
170 | 4.58k | return loadSectionContent(Sec, [this, &Sec]() { |
171 | 22.4k | return loadSectionContentVec(Sec, [this](AST::CodeSegment &CodeSeg) { |
172 | 22.4k | return loadSegment(CodeSeg); |
173 | 22.4k | }); |
174 | 4.57k | }); |
175 | 4.58k | } |
176 | | |
177 | | // Load vector of data section. See "include/loader/loader.h". |
178 | 1.59k | Expect<void> Loader::loadSection(AST::DataSection &Sec) { |
179 | 1.59k | return loadSectionContent(Sec, [this, &Sec]() { |
180 | 5.12k | return loadSectionContentVec(Sec, [this](AST::DataSegment &DataSeg) { |
181 | 5.12k | return loadSegment(DataSeg); |
182 | 5.12k | }); |
183 | 1.56k | }); |
184 | 1.59k | } |
185 | | |
186 | | // Load content of data count section. See "include/loader/loader.h". |
187 | 99 | Expect<void> Loader::loadSection(AST::DataCountSection &Sec) { |
188 | 99 | return loadSectionContent(Sec, [this, &Sec]() -> Expect<void> { |
189 | | // Read u32 of data count. |
190 | 85 | EXPECTED_TRY(uint32_t Cnt, FMgr.readU32().map_error([this](auto E) { |
191 | 83 | return logLoadError(E, FMgr.getLastOffset(), ASTNodeAttr::Sec_DataCount); |
192 | 83 | })); |
193 | 83 | Sec.setContent(Cnt); |
194 | 83 | return {}; |
195 | 85 | }); |
196 | 99 | } |
197 | | |
198 | | // Load content of tag section. See "include/loader/loader.h". |
199 | 0 | Expect<void> Loader::loadSection(AST::TagSection &Sec) { |
200 | 0 | return loadSectionContent(Sec, [this, &Sec]() { |
201 | 0 | return loadSectionContentVec( |
202 | 0 | Sec, [this](AST::TagType &TgType) { return loadType(TgType); }); |
203 | 0 | }); |
204 | 0 | } |
205 | | |
206 | | namespace { |
207 | | |
208 | 0 | inline constexpr uint32_t HostVersion() noexcept { |
209 | 0 | return WasmEdge::AOT::kBinaryVersion; |
210 | 0 | } |
211 | | |
212 | 0 | inline constexpr uint8_t HostOSType() noexcept { |
213 | 0 | #if WASMEDGE_OS_LINUX |
214 | 0 | return UINT8_C(1); |
215 | | #elif WASMEDGE_OS_MACOS |
216 | | return UINT8_C(2); |
217 | | #elif WASMEDGE_OS_WINDOWS |
218 | | return UINT8_C(3); |
219 | | #else |
220 | | // Means WasmEdge is not yet supported on this OS. |
221 | | return UINT8_C(-1); |
222 | | #endif |
223 | 0 | } |
224 | | |
225 | 0 | inline constexpr uint8_t HostArchType() noexcept { |
226 | 0 | #if defined(__x86_64__) || defined(_M_X64) |
227 | 0 | return UINT8_C(1); |
228 | | #elif defined(__aarch64__) |
229 | | return UINT8_C(2); |
230 | | #elif defined(__riscv) && __riscv_xlen == 64 |
231 | | return UINT8_C(3); |
232 | | #elif defined(__arm__) && __ARM_ARCH == 7 |
233 | | return UINT8_C(4); |
234 | | #else |
235 | | // Means universal wasm binary is not yet supported on this arch. |
236 | | return UINT8_C(-1); |
237 | | #endif |
238 | 0 | } |
239 | | |
240 | | } // namespace |
241 | | |
242 | | // If there is any loader error occurs in the loadSection, then fallback |
243 | | // to the interpreter mode with info level log. |
244 | 0 | Expect<void> Loader::loadSection(FileMgr &VecMgr, AST::AOTSection &Sec) { |
245 | 0 | EXPECTED_TRY(auto Version, VecMgr.readU32().map_error([](auto E) { |
246 | 0 | spdlog::error(E); |
247 | 0 | spdlog::error(" AOT binary version read error:{}"sv, E); |
248 | 0 | return E; |
249 | 0 | })); |
250 | 0 | Sec.setVersion(Version); |
251 | 0 | if (unlikely(Sec.getVersion() != HostVersion())) { |
252 | 0 | spdlog::error(ErrCode::Value::MalformedSection); |
253 | 0 | spdlog::error(" AOT binary version unmatched."sv); |
254 | 0 | return Unexpect(ErrCode::Value::MalformedSection); |
255 | 0 | } |
256 | | |
257 | 0 | EXPECTED_TRY(auto OSType, VecMgr.readByte().map_error([](auto E) { |
258 | 0 | spdlog::error(E); |
259 | 0 | spdlog::error(" AOT os type read error:{}"sv, E); |
260 | 0 | return E; |
261 | 0 | })); |
262 | 0 | Sec.setOSType(OSType); |
263 | 0 | if (unlikely(Sec.getOSType() != HostOSType())) { |
264 | 0 | spdlog::error(ErrCode::Value::MalformedSection); |
265 | 0 | spdlog::error(" AOT OS type unmatched."sv); |
266 | 0 | return Unexpect(ErrCode::Value::MalformedSection); |
267 | 0 | } |
268 | | |
269 | 0 | EXPECTED_TRY(auto ArchType, VecMgr.readByte().map_error([](auto E) { |
270 | 0 | spdlog::error(E); |
271 | 0 | spdlog::error(" AOT arch type read error:{}"sv, E); |
272 | 0 | return E; |
273 | 0 | })); |
274 | 0 | Sec.setArchType(ArchType); |
275 | 0 | if (unlikely(Sec.getArchType() != HostArchType())) { |
276 | 0 | spdlog::error(ErrCode::Value::MalformedSection); |
277 | 0 | spdlog::error(" AOT arch type unmatched."sv); |
278 | 0 | return Unexpect(ErrCode::Value::MalformedSection); |
279 | 0 | } |
280 | | |
281 | 0 | EXPECTED_TRY(auto VersionAddress, VecMgr.readU64().map_error([](auto E) { |
282 | 0 | spdlog::error(E); |
283 | 0 | spdlog::error(" AOT version address read error:{}"sv, E); |
284 | 0 | return E; |
285 | 0 | })); |
286 | 0 | Sec.setVersionAddress(VersionAddress); |
287 | |
|
288 | 0 | EXPECTED_TRY(auto IntrinsicsAddress, VecMgr.readU64().map_error([](auto E) { |
289 | 0 | spdlog::error(E); |
290 | 0 | spdlog::error(" AOT intrinsics address read error:{}"sv, E); |
291 | 0 | return E; |
292 | 0 | })); |
293 | 0 | Sec.setIntrinsicsAddress(IntrinsicsAddress); |
294 | |
|
295 | 0 | EXPECTED_TRY(auto TypesSize, VecMgr.readU64().map_error([](auto E) { |
296 | 0 | spdlog::error(E); |
297 | 0 | spdlog::error(" AOT types size read error:{}"sv, E); |
298 | 0 | return E; |
299 | 0 | })); |
300 | 0 | if (TypesSize > VecMgr.getRemainSize()) { |
301 | 0 | spdlog::error(ErrCode::Value::IntegerTooLong); |
302 | 0 | spdlog::error(" AOT types size too large"sv); |
303 | 0 | return Unexpect(ErrCode::Value::IntegerTooLong); |
304 | 0 | } |
305 | 0 | Sec.getTypesAddress().resize(TypesSize); |
306 | |
|
307 | 0 | for (size_t I = 0; I < Sec.getTypesAddress().size(); ++I) { |
308 | 0 | EXPECTED_TRY(auto TypesAddress, VecMgr.readU64().map_error([](auto E) { |
309 | 0 | spdlog::error(E); |
310 | 0 | spdlog::error(" AOT type address read error:{}"sv, E); |
311 | 0 | return E; |
312 | 0 | })); |
313 | 0 | Sec.getTypesAddress()[I] = TypesAddress; |
314 | 0 | } |
315 | | |
316 | 0 | EXPECTED_TRY(auto CodesSize, VecMgr.readU64().map_error([](auto E) { |
317 | 0 | spdlog::error(E); |
318 | 0 | spdlog::error(" AOT code size read error:{}"sv, E); |
319 | 0 | return E; |
320 | 0 | })); |
321 | 0 | if (CodesSize > VecMgr.getRemainSize()) { |
322 | 0 | spdlog::error(ErrCode::Value::IntegerTooLong); |
323 | 0 | spdlog::error(" AOT code size too large"sv); |
324 | 0 | return Unexpect(ErrCode::Value::IntegerTooLong); |
325 | 0 | } |
326 | 0 | Sec.getCodesAddress().resize(CodesSize); |
327 | |
|
328 | 0 | for (size_t I = 0; I < Sec.getCodesAddress().size(); ++I) { |
329 | 0 | EXPECTED_TRY(auto CodesAddress, VecMgr.readU64().map_error([](auto E) { |
330 | 0 | spdlog::error(E); |
331 | 0 | spdlog::error(" AOT code address read error:{}"sv, E); |
332 | 0 | return E; |
333 | 0 | })); |
334 | 0 | Sec.getCodesAddress()[I] = CodesAddress; |
335 | 0 | } |
336 | | |
337 | 0 | EXPECTED_TRY(auto SectionsSize, VecMgr.readU32().map_error([](auto E) { |
338 | 0 | spdlog::error(E); |
339 | 0 | spdlog::error(" AOT section count read error:{}"sv, E); |
340 | 0 | return E; |
341 | 0 | })); |
342 | 0 | if (SectionsSize > VecMgr.getRemainSize()) { |
343 | 0 | spdlog::error(ErrCode::Value::IntegerTooLong); |
344 | 0 | spdlog::error(" AOT section count too large"sv); |
345 | 0 | return Unexpect(ErrCode::Value::IntegerTooLong); |
346 | 0 | } |
347 | 0 | Sec.getSections().resize(SectionsSize); |
348 | |
|
349 | 0 | for (auto &Section : Sec.getSections()) { |
350 | 0 | EXPECTED_TRY(std::get<0>(Section), VecMgr.readByte().map_error([](auto E) { |
351 | 0 | spdlog::error(E); |
352 | 0 | spdlog::error(" AOT section type read error:{}"sv, E); |
353 | 0 | return E; |
354 | 0 | })); |
355 | 0 | EXPECTED_TRY(std::get<1>(Section), VecMgr.readU64().map_error([](auto E) { |
356 | 0 | spdlog::error(E); |
357 | 0 | spdlog::error(" AOT section offset read error:{}"sv, E); |
358 | 0 | return E; |
359 | 0 | })); |
360 | 0 | EXPECTED_TRY(std::get<2>(Section), VecMgr.readU64().map_error([](auto E) { |
361 | 0 | spdlog::error(E); |
362 | 0 | spdlog::error(" AOT section size read error:{}"sv, E); |
363 | 0 | return E; |
364 | 0 | })); |
365 | 0 | EXPECTED_TRY(uint32_t Size, VecMgr.readU32().map_error([](auto E) { |
366 | 0 | spdlog::error(E); |
367 | 0 | spdlog::error(" AOT section data size read error:{}"sv, E); |
368 | 0 | return E; |
369 | 0 | })); |
370 | 0 | if (Size > VecMgr.getRemainSize()) { |
371 | 0 | spdlog::error(ErrCode::Value::IntegerTooLong); |
372 | 0 | spdlog::error(" AOT section data size is too large"sv); |
373 | 0 | return Unexpect(ErrCode::Value::IntegerTooLong); |
374 | 0 | } |
375 | 0 | if (std::get<2>(Section) < Size) { |
376 | 0 | spdlog::error(ErrCode::Value::IntegerTooLong); |
377 | 0 | spdlog::error(" AOT section data size is larger then section size"sv); |
378 | 0 | return Unexpect(ErrCode::Value::IntegerTooLong); |
379 | 0 | } |
380 | 0 | EXPECTED_TRY(auto Data, VecMgr.readBytes(Size).map_error([](auto E) { |
381 | 0 | spdlog::error(E); |
382 | 0 | spdlog::error(" AOT section data read error:{}"sv, E); |
383 | 0 | return E; |
384 | 0 | })); |
385 | 0 | std::get<3>(Section) = std::move(Data); |
386 | 0 | } |
387 | 0 | return {}; |
388 | 0 | } |
389 | | |
390 | | } // namespace Loader |
391 | | } // namespace WasmEdge |