/src/WasmEdge/include/common/errinfo.h
Line | Count | Source |
1 | | // SPDX-License-Identifier: Apache-2.0 |
2 | | // SPDX-FileCopyrightText: Copyright The WasmEdge Authors |
3 | | |
4 | | //===-- wasmedge/common/errinfo.h - Error information definition ----------===// |
5 | | // |
6 | | // Part of the WasmEdge Project. |
7 | | // |
8 | | //===----------------------------------------------------------------------===// |
9 | | /// |
10 | | /// \file |
11 | | /// This file contains the enumerations of WasmEdge error information. |
12 | | /// |
13 | | //===----------------------------------------------------------------------===// |
14 | | #pragma once |
15 | | |
16 | | #include "common/enum_ast.hpp" |
17 | | #include "common/enum_configure.hpp" |
18 | | #include "common/enum_errcode.hpp" |
19 | | #include "common/enum_errinfo.hpp" |
20 | | #include "common/enum_types.hpp" |
21 | | #include "common/filesystem.h" |
22 | | #include "common/fmt.h" |
23 | | #include "common/spdlog.h" |
24 | | #include "common/types.h" |
25 | | |
26 | | #include <iterator> |
27 | | #if !defined(__has_include) || __has_include(<spdlog/fmt/ranges.h>) |
28 | | #include <spdlog/fmt/ranges.h> |
29 | | #else |
30 | | #include <fmt/ranges.h> |
31 | | #endif |
32 | | |
33 | | #include <cstdint> |
34 | | #include <iosfwd> |
35 | | #include <limits> |
36 | | #include <string> |
37 | | #include <string_view> |
38 | | #include <vector> |
39 | | |
40 | | namespace WasmEdge { |
41 | | namespace ErrInfo { |
42 | | |
43 | | /// Information structures. |
44 | | struct InfoFile { |
45 | | InfoFile() = delete; |
46 | 0 | InfoFile(const std::filesystem::path &FName) noexcept : FileName(FName) {} |
47 | | |
48 | | std::filesystem::path FileName; |
49 | | }; |
50 | | |
51 | | struct InfoLoading { |
52 | | InfoLoading() = delete; |
53 | 5.15k | InfoLoading(const uint64_t Off) noexcept : Offset(Off) {} |
54 | | |
55 | | uint64_t Offset; |
56 | | }; |
57 | | |
58 | | struct InfoAST { |
59 | | InfoAST() = delete; |
60 | 29.1k | InfoAST(const ASTNodeAttr Attr) noexcept : NodeAttr(Attr) {} |
61 | | |
62 | | ASTNodeAttr NodeAttr; |
63 | | }; |
64 | | |
65 | | struct InfoInstanceBound { |
66 | | InfoInstanceBound() = delete; |
67 | | InfoInstanceBound(const ExternalType Inst, const uint32_t Num, |
68 | | const uint32_t Lim) noexcept |
69 | 0 | : Instance(Inst), Number(Num), Limited(Lim) {} |
70 | | |
71 | | ExternalType Instance; |
72 | | uint32_t Number, Limited; |
73 | | }; |
74 | | |
75 | | struct InfoForbidIndex { |
76 | | InfoForbidIndex() = delete; |
77 | | InfoForbidIndex(const IndexCategory Cate, const uint32_t Idx, |
78 | | const uint32_t Bound) noexcept |
79 | 598 | : Category(Cate), Index(Idx), Boundary(Bound) {} |
80 | | |
81 | | IndexCategory Category; |
82 | | uint32_t Index, Boundary; |
83 | | }; |
84 | | |
85 | | struct InfoExporting { |
86 | | InfoExporting() = delete; |
87 | 0 | InfoExporting(std::string_view Ext) noexcept : ExtName(Ext) {} |
88 | | |
89 | | std::string ExtName; |
90 | | }; |
91 | | |
92 | | struct InfoLimit { |
93 | | InfoLimit() = delete; |
94 | | InfoLimit(const bool HasMax, const uint64_t Min, |
95 | | const uint64_t Max = 0) noexcept |
96 | 53 | : LimHasMax(HasMax), LimMin(Min), LimMax(Max) {} |
97 | | |
98 | | bool LimHasMax; |
99 | | uint64_t LimMin, LimMax; |
100 | | }; |
101 | | |
102 | | struct InfoRegistering { |
103 | | InfoRegistering() = delete; |
104 | 0 | InfoRegistering(std::string_view Mod) noexcept : ModName(Mod) {} |
105 | | |
106 | | std::string ModName; |
107 | | }; |
108 | | |
109 | | struct InfoLinking { |
110 | | InfoLinking() = delete; |
111 | | InfoLinking(std::string_view Mod, std::string_view Ext, |
112 | | const ExternalType ExtT = ExternalType::Function) noexcept |
113 | 0 | : ModName(Mod), ExtName(Ext), ExtType(ExtT) {} |
114 | | |
115 | | std::string ModName; |
116 | | std::string ExtName; |
117 | | ExternalType ExtType; |
118 | | }; |
119 | | |
120 | | struct InfoExecuting { |
121 | | InfoExecuting() = delete; |
122 | | InfoExecuting(std::string_view Mod, std::string_view Func) noexcept |
123 | 0 | : ModName(Mod), FuncName(Func) {} |
124 | 0 | InfoExecuting(std::string_view Func) noexcept : ModName(""), FuncName(Func) {} |
125 | | |
126 | | std::string ModName; |
127 | | std::string FuncName; |
128 | | }; |
129 | | |
130 | | struct InfoMismatch { |
131 | | InfoMismatch() = delete; |
132 | | |
133 | | /// Case 1: unexpected alignment |
134 | | InfoMismatch(const uint8_t ExpAlign, const uint32_t GotAlign) noexcept |
135 | 43 | : Category(MismatchCategory::Alignment), ExpAlignment(ExpAlign), |
136 | 43 | GotAlignment(GotAlign) {} |
137 | | |
138 | | /// Case 2: unexpected value type |
139 | | InfoMismatch(const ValType &ExpVT, const ValType &GotVT) noexcept |
140 | 663 | : Category(MismatchCategory::ValueType), ExpValType(ExpVT), |
141 | 663 | GotValType(GotVT) {} |
142 | | |
143 | | /// Case 3: unexpected value type list |
144 | | InfoMismatch(const std::vector<ValType> &ExpV, |
145 | | const std::vector<ValType> &GotV) noexcept |
146 | 17 | : Category(MismatchCategory::ValueTypes), ExpParams(ExpV), |
147 | 17 | GotParams(GotV) {} |
148 | | |
149 | | /// Case 4: unexpected mutation settings |
150 | | InfoMismatch(const ValMut ExpM, const ValMut GotM) noexcept |
151 | 0 | : Category(MismatchCategory::Mutation), ExpValMut(ExpM), GotValMut(GotM) { |
152 | 0 | } |
153 | | |
154 | | /// Case 5: unexpected external types |
155 | | InfoMismatch(const ExternalType ExpExt, const ExternalType GotExt) noexcept |
156 | 0 | : Category(MismatchCategory::ExternalType), ExpExtType(ExpExt), |
157 | 0 | GotExtType(GotExt) {} |
158 | | |
159 | | /// Case 6: unexpected function types |
160 | | InfoMismatch(const std::vector<ValType> &ExpP, |
161 | | const std::vector<ValType> &ExpR, |
162 | | const std::vector<ValType> &GotP, |
163 | | const std::vector<ValType> &GotR) noexcept |
164 | 2 | : Category(MismatchCategory::FunctionType), ExpParams(ExpP), |
165 | 2 | GotParams(GotP), ExpReturns(ExpR), GotReturns(GotR) {} |
166 | | |
167 | | /// Case 7: unexpected table types |
168 | | InfoMismatch(const ValType &ExpRType, |
169 | | // Expected reference type |
170 | | const bool ExpHasMax, const uint64_t ExpMin, |
171 | | const uint64_t ExpMax, |
172 | | // Expected Limit |
173 | | const ValType &GotRType, |
174 | | // Got reference type |
175 | | const bool GotHasMax, const uint64_t GotMin, |
176 | | const uint64_t GotMax |
177 | | // Got limit |
178 | | ) noexcept |
179 | 0 | : Category(MismatchCategory::Table), ExpValType(ExpRType), |
180 | 0 | GotValType(GotRType), ExpLimHasMax(ExpHasMax), GotLimHasMax(GotHasMax), |
181 | 0 | ExpLimMin(ExpMin), GotLimMin(GotMin), ExpLimMax(ExpMax), |
182 | 0 | GotLimMax(GotMax) {} |
183 | | |
184 | | /// Case 8: unexpected memory limits |
185 | | InfoMismatch(const bool ExpHasMax, const uint64_t ExpMin, |
186 | | const uint64_t ExpMax, |
187 | | // Expect Limit |
188 | | const bool GotHasMax, const uint64_t GotMin, |
189 | | const uint64_t GotMax |
190 | | // Got limit |
191 | | ) noexcept |
192 | 0 | : Category(MismatchCategory::Memory), ExpLimHasMax(ExpHasMax), |
193 | 0 | GotLimHasMax(GotHasMax), ExpLimMin(ExpMin), GotLimMin(GotMin), |
194 | 0 | ExpLimMax(ExpMax), GotLimMax(GotMax) {} |
195 | | |
196 | | /// Case 9: unexpected global types |
197 | | InfoMismatch(const ValType &ExpVType, const ValMut ExpVMut, |
198 | | const ValType &GotVType, const ValMut GotVMut) noexcept |
199 | 0 | : Category(MismatchCategory::Global), ExpValType(ExpVType), |
200 | 0 | GotValType(GotVType), ExpValMut(ExpVMut), GotValMut(GotVMut) {} |
201 | | |
202 | | /// Case 10: unexpected version |
203 | | InfoMismatch(const uint32_t ExpV, const uint32_t GotV) noexcept |
204 | 0 | : Category(MismatchCategory::Version), ExpVersion(ExpV), |
205 | 0 | GotVersion(GotV) {} |
206 | | |
207 | | /// Mismatched category |
208 | | MismatchCategory Category; |
209 | | |
210 | | /// Case 1: unexpected alignment |
211 | | uint8_t ExpAlignment; |
212 | | uint32_t GotAlignment; |
213 | | |
214 | | /// Case 5: unexpected external type |
215 | | ExternalType ExpExtType, GotExtType; |
216 | | |
217 | | /// Case 6: unexpected function type |
218 | | /// Case 3: unexpected value type list |
219 | | std::vector<ValType> ExpParams, GotParams; |
220 | | std::vector<ValType> ExpReturns, GotReturns; |
221 | | |
222 | | /// Case 2: unexpected value type |
223 | | /// Case 7: unexpected table type: reference type |
224 | | /// Case 9: unexpected global type: value type |
225 | | ValType ExpValType, GotValType; |
226 | | /// Case 4: unexpected mutation settings |
227 | | /// Case 9: unexpected global type: value mutation |
228 | | ValMut ExpValMut, GotValMut; |
229 | | /// Case 7 & 8: unexpected table or memory type: limit |
230 | | bool ExpLimHasMax, GotLimHasMax; |
231 | | uint64_t ExpLimMin, GotLimMin; |
232 | | uint64_t ExpLimMax, GotLimMax; |
233 | | |
234 | | /// Case 10: unexpected version |
235 | | uint32_t ExpVersion, GotVersion; |
236 | | }; |
237 | | |
238 | | struct InfoInstruction { |
239 | | InfoInstruction() = delete; |
240 | | InfoInstruction(const OpCode Op, const uint64_t Off, |
241 | | const std::vector<ValVariant> &ArgsVec = {}, |
242 | | const std::vector<ValType> &ArgsTypesVec = {}, |
243 | | const bool Signed = false) noexcept |
244 | 1.73k | : Code(Op), Offset(Off), Args(ArgsVec), ArgsTypes(ArgsTypesVec), |
245 | 1.73k | IsSigned(Signed) {} |
246 | | |
247 | | OpCode Code; |
248 | | uint64_t Offset; |
249 | | std::vector<ValVariant> Args; |
250 | | std::vector<ValType> ArgsTypes; |
251 | | bool IsSigned; |
252 | | }; |
253 | | |
254 | | struct InfoBoundary { |
255 | | InfoBoundary() = delete; |
256 | | InfoBoundary(const uint64_t Off, const uint64_t Len = 0, |
257 | | const uint64_t Lim = std::numeric_limits<uint64_t>::max(), |
258 | | const bool IsOverflow = false) noexcept |
259 | 0 | : IsOffsetOverflow(IsOverflow), Offset(Off), Size(Len), Limit(Lim) {} |
260 | | |
261 | | bool IsOffsetOverflow; |
262 | | uint64_t Offset; |
263 | | uint64_t Size; |
264 | | uint64_t Limit; |
265 | | }; |
266 | | |
267 | | struct InfoProposal { |
268 | | InfoProposal() = delete; |
269 | 119 | InfoProposal(Proposal P) noexcept : P(P) {} |
270 | | |
271 | | Proposal P; |
272 | | }; |
273 | | |
274 | | } // namespace ErrInfo |
275 | | } // namespace WasmEdge |
276 | | |
277 | | template <> |
278 | | struct fmt::formatter<WasmEdge::ErrInfo::InfoFile> |
279 | | : fmt::formatter<std::string_view> { |
280 | | template <typename FmtCtx> |
281 | | auto format(const WasmEdge::ErrInfo::InfoFile &Info, |
282 | 0 | FmtCtx &Ctx) WASMEDGE_FMT_CONST noexcept -> decltype(Ctx.out()) { |
283 | 0 | using namespace std::literals; |
284 | 0 | fmt::memory_buffer Buffer; |
285 | 0 | fmt::format_to(std::back_inserter(Buffer), " File name: {}"sv, |
286 | 0 | Info.FileName); |
287 | 0 | return formatter<std::string_view>::format( |
288 | 0 | std::string_view(Buffer.data(), Buffer.size()), Ctx); |
289 | 0 | } |
290 | | }; |
291 | | template <> |
292 | | struct fmt::formatter<WasmEdge::ErrInfo::InfoLoading> |
293 | | : fmt::formatter<std::string_view> { |
294 | | template <typename FmtCtx> |
295 | | auto format(const WasmEdge::ErrInfo::InfoLoading &Info, |
296 | 0 | FmtCtx &Ctx) WASMEDGE_FMT_CONST noexcept -> decltype(Ctx.out()) { |
297 | 0 | using namespace std::literals; |
298 | 0 | fmt::memory_buffer Buffer; |
299 | 0 | fmt::format_to(std::back_inserter(Buffer), |
300 | 0 | " Bytecode offset: 0x{:08x}"sv, Info.Offset); |
301 | 0 | return formatter<std::string_view>::format( |
302 | 0 | std::string_view(Buffer.data(), Buffer.size()), Ctx); |
303 | 0 | } |
304 | | }; |
305 | | template <> |
306 | | struct fmt::formatter<WasmEdge::ErrInfo::InfoAST> |
307 | | : fmt::formatter<std::string_view> { |
308 | | template <typename FmtCtx> |
309 | | auto format(const WasmEdge::ErrInfo::InfoAST &Info, |
310 | 0 | FmtCtx &Ctx) WASMEDGE_FMT_CONST noexcept -> decltype(Ctx.out()) { |
311 | 0 | using namespace std::literals; |
312 | 0 | fmt::memory_buffer Buffer; |
313 | 0 | fmt::format_to(std::back_inserter(Buffer), " At AST node: {}"sv, |
314 | 0 | Info.NodeAttr); |
315 | 0 | return formatter<std::string_view>::format( |
316 | 0 | std::string_view(Buffer.data(), Buffer.size()), Ctx); |
317 | 0 | } |
318 | | }; |
319 | | template <> |
320 | | struct fmt::formatter<WasmEdge::ErrInfo::InfoInstanceBound> |
321 | | : fmt::formatter<std::string_view> { |
322 | | template <typename FmtCtx> |
323 | | auto format(const WasmEdge::ErrInfo::InfoInstanceBound &Info, |
324 | | FmtCtx &Ctx) WASMEDGE_FMT_CONST noexcept -> decltype(Ctx.out()) { |
325 | | using namespace std::literals; |
326 | | fmt::memory_buffer Buffer; |
327 | | fmt::format_to(std::back_inserter(Buffer), |
328 | | " Instance {} has limited number {} , Got: {}"sv, |
329 | | Info.Instance, Info.Limited, Info.Number); |
330 | | return formatter<std::string_view>::format( |
331 | | std::string_view(Buffer.data(), Buffer.size()), Ctx); |
332 | | } |
333 | | }; |
334 | | template <> |
335 | | struct fmt::formatter<WasmEdge::ErrInfo::InfoForbidIndex> |
336 | | : fmt::formatter<std::string_view> { |
337 | | template <typename FmtCtx> |
338 | | auto format(const WasmEdge::ErrInfo::InfoForbidIndex &Info, |
339 | 0 | FmtCtx &Ctx) WASMEDGE_FMT_CONST noexcept -> decltype(Ctx.out()) { |
340 | 0 | using namespace std::literals; |
341 | 0 | fmt::memory_buffer Buffer; |
342 | 0 | auto Iter = |
343 | 0 | fmt::format_to(std::back_inserter(Buffer), |
344 | 0 | " When checking {} index: {} , Out of boundary: "sv, |
345 | 0 | Info.Category, Info.Index); |
346 | 0 | if (Info.Boundary > 0) { |
347 | 0 | fmt::format_to(Iter, "{}"sv, Info.Boundary - 1); |
348 | 0 | } else { |
349 | 0 | fmt::format_to(Iter, "empty"sv); |
350 | 0 | } |
351 | 0 | return formatter<std::string_view>::format( |
352 | 0 | std::string_view(Buffer.data(), Buffer.size()), Ctx); |
353 | 0 | } |
354 | | }; |
355 | | template <> |
356 | | struct fmt::formatter<WasmEdge::ErrInfo::InfoExporting> |
357 | | : fmt::formatter<std::string_view> { |
358 | | template <typename FmtCtx> |
359 | | auto format(const WasmEdge::ErrInfo::InfoExporting &Info, |
360 | | FmtCtx &Ctx) WASMEDGE_FMT_CONST noexcept -> decltype(Ctx.out()) { |
361 | | using namespace std::literals; |
362 | | fmt::memory_buffer Buffer; |
363 | | fmt::format_to(std::back_inserter(Buffer), |
364 | | " Duplicated exporting name: \"{}\""sv, Info.ExtName); |
365 | | return formatter<std::string_view>::format( |
366 | | std::string_view(Buffer.data(), Buffer.size()), Ctx); |
367 | | } |
368 | | }; |
369 | | template <> |
370 | | struct fmt::formatter<WasmEdge::ErrInfo::InfoLimit> |
371 | | : fmt::formatter<std::string_view> { |
372 | | template <typename FmtCtx> |
373 | | auto format(const WasmEdge::ErrInfo::InfoLimit &Info, |
374 | 0 | FmtCtx &Ctx) WASMEDGE_FMT_CONST noexcept -> decltype(Ctx.out()) { |
375 | 0 | using namespace std::literals; |
376 | 0 | fmt::memory_buffer Buffer; |
377 | 0 | auto Iter = fmt::format_to(std::back_inserter(Buffer), |
378 | 0 | " In Limit type: {{ min: {}"sv, Info.LimMin); |
379 | 0 | if (Info.LimHasMax) { |
380 | 0 | Iter = fmt::format_to(Iter, " , max: {}"sv, Info.LimMax); |
381 | 0 | } |
382 | 0 | fmt::format_to(Iter, " }}"sv); |
383 | 0 | return formatter<std::string_view>::format( |
384 | 0 | std::string_view(Buffer.data(), Buffer.size()), Ctx); |
385 | 0 | } |
386 | | }; |
387 | | template <> |
388 | | struct fmt::formatter<WasmEdge::ErrInfo::InfoRegistering> |
389 | | : fmt::formatter<std::string_view> { |
390 | | template <typename FmtCtx> |
391 | | auto format(const WasmEdge::ErrInfo::InfoRegistering &Info, |
392 | | FmtCtx &Ctx) WASMEDGE_FMT_CONST noexcept -> decltype(Ctx.out()) { |
393 | | using namespace std::literals; |
394 | | fmt::memory_buffer Buffer; |
395 | | fmt::format_to(std::back_inserter(Buffer), " Module name: \"{}\""sv, |
396 | | Info.ModName); |
397 | | return formatter<std::string_view>::format( |
398 | | std::string_view(Buffer.data(), Buffer.size()), Ctx); |
399 | | } |
400 | | }; |
401 | | template <> |
402 | | struct fmt::formatter<WasmEdge::ErrInfo::InfoLinking> |
403 | | : fmt::formatter<std::string_view> { |
404 | | template <typename FmtCtx> |
405 | | auto format(const WasmEdge::ErrInfo::InfoLinking &Info, |
406 | 0 | FmtCtx &Ctx) WASMEDGE_FMT_CONST noexcept -> decltype(Ctx.out()) { |
407 | 0 | using namespace std::literals; |
408 | 0 | fmt::memory_buffer Buffer; |
409 | 0 | fmt::format_to(std::back_inserter(Buffer), |
410 | 0 | " When linking module: \"{}\" , {} name: \"{}\""sv, |
411 | 0 | Info.ModName, Info.ExtType, Info.ExtName); |
412 | 0 | return formatter<std::string_view>::format( |
413 | 0 | std::string_view(Buffer.data(), Buffer.size()), Ctx); |
414 | 0 | } |
415 | | }; |
416 | | template <> |
417 | | struct fmt::formatter<WasmEdge::ErrInfo::InfoExecuting> |
418 | | : fmt::formatter<std::string_view> { |
419 | | template <typename FmtCtx> |
420 | | auto format(const WasmEdge::ErrInfo::InfoExecuting &Info, |
421 | 0 | FmtCtx &Ctx) WASMEDGE_FMT_CONST noexcept -> decltype(Ctx.out()) { |
422 | 0 | using namespace std::literals; |
423 | 0 | fmt::memory_buffer Buffer; |
424 | 0 | auto Iter = |
425 | 0 | fmt::format_to(std::back_inserter(Buffer), " When executing "sv); |
426 | 0 | if (!Info.ModName.empty()) { |
427 | 0 | Iter = fmt::format_to(Iter, "module name: \"{}\" , "sv, Info.ModName); |
428 | 0 | } |
429 | 0 | fmt::format_to(Iter, "function name: \"{}\""sv, Info.FuncName); |
430 | 0 | return formatter<std::string_view>::format( |
431 | 0 | std::string_view(Buffer.data(), Buffer.size()), Ctx); |
432 | 0 | } |
433 | | }; |
434 | | template <> |
435 | | struct fmt::formatter<WasmEdge::ErrInfo::InfoMismatch> |
436 | | : fmt::formatter<std::string_view> { |
437 | | template <typename FmtCtx> |
438 | | auto format(const WasmEdge::ErrInfo::InfoMismatch &Info, |
439 | 0 | FmtCtx &Ctx) WASMEDGE_FMT_CONST noexcept -> decltype(Ctx.out()) { |
440 | 0 | using namespace std::literals; |
441 | 0 | fmt::memory_buffer Buffer; |
442 | 0 | auto Iter = fmt::format_to(std::back_inserter(Buffer), |
443 | 0 | " Mismatched {}. "sv, Info.Category); |
444 | 0 | auto FormatLimit = [](auto Out, bool LimHasMax, uint64_t LimMin, |
445 | 0 | uint64_t LimMax) { |
446 | 0 | Out = fmt::format_to(Out, "Limit{{{}"sv, LimMin); |
447 | 0 | if (LimHasMax) { |
448 | 0 | Out = fmt::format_to(Out, " , {}"sv, LimMax); |
449 | 0 | } |
450 | 0 | Out = fmt::format_to(Out, "}}"sv); |
451 | 0 | return Out; |
452 | 0 | }; |
453 | 0 | switch (Info.Category) { |
454 | 0 | case WasmEdge::ErrInfo::MismatchCategory::Alignment: |
455 | 0 | if (Info.GotAlignment < Info.ExpAlignment) { |
456 | 0 | fmt::format_to(Iter, "Expected: need to == {} , Got: {}"sv, |
457 | 0 | static_cast<uint32_t>(Info.ExpAlignment), |
458 | 0 | static_cast<uint32_t>(Info.GotAlignment)); |
459 | 0 | } else { |
460 | 0 | fmt::format_to(Iter, "Expected: need to <= {} , Got: {}"sv, |
461 | 0 | static_cast<uint32_t>(Info.ExpAlignment), |
462 | 0 | static_cast<uint32_t>(Info.GotAlignment)); |
463 | 0 | } |
464 | 0 | break; |
465 | 0 | case WasmEdge::ErrInfo::MismatchCategory::ValueType: |
466 | 0 | fmt::format_to(Iter, "Expected: {} , Got: {}"sv, Info.ExpValType, |
467 | 0 | Info.GotValType); |
468 | 0 | break; |
469 | 0 | case WasmEdge::ErrInfo::MismatchCategory::ValueTypes: |
470 | 0 | fmt::format_to(Iter, "Expected: types{{{}}} , Got: types{{{}}}"sv, |
471 | 0 | fmt::join(Info.ExpParams, " , "sv), |
472 | 0 | fmt::join(Info.GotParams, " , "sv)); |
473 | 0 | break; |
474 | 0 | case WasmEdge::ErrInfo::MismatchCategory::Mutation: |
475 | 0 | fmt::format_to(Iter, "Expected: {} , Got: {}"sv, Info.ExpValMut, |
476 | 0 | Info.GotValMut); |
477 | 0 | break; |
478 | 0 | case WasmEdge::ErrInfo::MismatchCategory::ExternalType: |
479 | 0 | fmt::format_to(Iter, "Expected: {} , Got: {}", Info.ExpExtType, |
480 | 0 | Info.GotExtType); |
481 | 0 | break; |
482 | 0 | case WasmEdge::ErrInfo::MismatchCategory::FunctionType: |
483 | 0 | fmt::format_to(Iter, |
484 | 0 | "Expected: FuncType {{params{{{}}} returns{{{}}}}} , " |
485 | 0 | "Got: FuncType {{params{{{}}} returns{{{}}}}}"sv, |
486 | 0 | fmt::join(Info.ExpParams, " , "sv), |
487 | 0 | fmt::join(Info.ExpReturns, " , "sv), |
488 | 0 | fmt::join(Info.GotParams, " , "sv), |
489 | 0 | fmt::join(Info.GotReturns, " , "sv)); |
490 | 0 | break; |
491 | 0 | case WasmEdge::ErrInfo::MismatchCategory::Table: |
492 | 0 | Iter = fmt::format_to(Iter, "Expected: TableType {{RefType{{{}}} "sv, |
493 | 0 | static_cast<WasmEdge::ValType>(Info.ExpValType)); |
494 | 0 | Iter = |
495 | 0 | FormatLimit(Iter, Info.ExpLimHasMax, Info.ExpLimMin, Info.ExpLimMax); |
496 | 0 | Iter = fmt::format_to(Iter, "}} , Got: TableType {{RefType{{{}}} "sv, |
497 | 0 | static_cast<WasmEdge::ValType>(Info.GotValType)); |
498 | 0 | Iter = |
499 | 0 | FormatLimit(Iter, Info.GotLimHasMax, Info.GotLimMin, Info.GotLimMax); |
500 | 0 | fmt::format_to(Iter, "}}"sv); |
501 | 0 | break; |
502 | 0 | case WasmEdge::ErrInfo::MismatchCategory::Memory: |
503 | 0 | Iter = fmt::format_to(Iter, "Expected: MemoryType {{"sv); |
504 | 0 | Iter = |
505 | 0 | FormatLimit(Iter, Info.ExpLimHasMax, Info.ExpLimMin, Info.ExpLimMax); |
506 | 0 | Iter = fmt::format_to(Iter, "}} , Got: MemoryType {{"sv); |
507 | 0 | Iter = |
508 | 0 | FormatLimit(Iter, Info.GotLimHasMax, Info.GotLimMin, Info.GotLimMax); |
509 | 0 | fmt::format_to(Iter, "}}"sv); |
510 | 0 | break; |
511 | 0 | case WasmEdge::ErrInfo::MismatchCategory::Global: |
512 | 0 | fmt::format_to(Iter, |
513 | 0 | "Expected: GlobalType {{Mutation{{{}}} ValType{{{}}}}} , " |
514 | 0 | "Got: GlobalType {{Mutation{{{}}} ValType{{{}}}}}"sv, |
515 | 0 | Info.ExpValMut, Info.ExpValType, Info.GotValMut, |
516 | 0 | Info.GotValType); |
517 | 0 | break; |
518 | 0 | case WasmEdge::ErrInfo::MismatchCategory::Version: |
519 | 0 | fmt::format_to(Iter, "Expected: {} , Got: {}"sv, Info.ExpVersion, |
520 | 0 | Info.GotVersion); |
521 | 0 | break; |
522 | 0 | default: |
523 | 0 | break; |
524 | 0 | } |
525 | 0 | return formatter<std::string_view>::format( |
526 | 0 | std::string_view(Buffer.data(), Buffer.size()), Ctx); |
527 | 0 | } |
528 | | }; |
529 | | template <> |
530 | | struct fmt::formatter<WasmEdge::ErrInfo::InfoInstruction> |
531 | | : fmt::formatter<std::string_view> { |
532 | | template <typename FmtCtx> |
533 | | auto format(const WasmEdge::ErrInfo::InfoInstruction &Info, |
534 | 0 | FmtCtx &Ctx) WASMEDGE_FMT_CONST noexcept -> decltype(Ctx.out()) { |
535 | 0 | using namespace std::literals; |
536 | 0 | uint16_t Payload = static_cast<uint16_t>(Info.Code); |
537 | 0 | fmt::memory_buffer Buffer; |
538 | 0 | auto Iter = fmt::format_to(std::back_inserter(Buffer), |
539 | 0 | " In instruction: {} ("sv, Info.Code); |
540 | 0 | if ((Payload >> 8) >= static_cast<uint16_t>(0xFCU)) { |
541 | 0 | Iter = fmt::format_to(Iter, "0x{:02x} "sv, Payload >> 8); |
542 | 0 | } |
543 | 0 | Iter = fmt::format_to(Iter, "0x{:02x}) , Bytecode offset: 0x{:08x}"sv, |
544 | 0 | Payload & 0xFFU, Info.Offset); |
545 | 0 | if (!Info.Args.empty()) { |
546 | 0 | Iter = fmt::format_to(Iter, " , Args: ["sv); |
547 | 0 | for (uint32_t I = 0; I < Info.Args.size(); ++I) { |
548 | 0 | switch (Info.ArgsTypes[I].getCode()) { |
549 | 0 | case WasmEdge::TypeCode::I32: |
550 | 0 | if (Info.IsSigned) { |
551 | 0 | Iter = fmt::format_to(Iter, "{}"sv, Info.Args[I].get<int32_t>()); |
552 | 0 | } else { |
553 | 0 | Iter = fmt::format_to(Iter, "{}"sv, Info.Args[I].get<uint32_t>()); |
554 | 0 | } |
555 | 0 | break; |
556 | 0 | case WasmEdge::TypeCode::I64: |
557 | 0 | if (Info.IsSigned) { |
558 | 0 | Iter = fmt::format_to(Iter, "{}"sv, Info.Args[I].get<int64_t>()); |
559 | 0 | } else { |
560 | 0 | Iter = fmt::format_to(Iter, "{}"sv, Info.Args[I].get<uint64_t>()); |
561 | 0 | } |
562 | 0 | break; |
563 | 0 | case WasmEdge::TypeCode::F32: |
564 | 0 | Iter = fmt::format_to(Iter, "{}"sv, Info.Args[I].get<float>()); |
565 | 0 | break; |
566 | 0 | case WasmEdge::TypeCode::F64: |
567 | 0 | Iter = fmt::format_to(Iter, "{}"sv, Info.Args[I].get<double>()); |
568 | 0 | break; |
569 | 0 | case WasmEdge::TypeCode::V128: { |
570 | 0 | const auto Value = Info.Args[I].get<WasmEdge::uint64x2_t>(); |
571 | 0 | Iter = fmt::format_to(Iter, "0x{:08x}{:08x}"sv, Value[1], Value[0]); |
572 | 0 | break; |
573 | 0 | } |
574 | 0 | case WasmEdge::TypeCode::Ref: |
575 | 0 | case WasmEdge::TypeCode::RefNull: |
576 | 0 | Iter = fmt::format_to(Iter, "{}"sv, Info.ArgsTypes[I]); |
577 | 0 | if (Info.Args[I].get<WasmEdge::RefVariant>().isNull()) { |
578 | 0 | Iter = fmt::format_to(Iter, ":null"sv); |
579 | 0 | } else { |
580 | 0 | Iter = fmt::format_to(Iter, ":0x{:08x}"sv, |
581 | 0 | Info.Args[I].get<uint64_t>()); |
582 | 0 | } |
583 | 0 | break; |
584 | 0 | default: |
585 | 0 | break; |
586 | 0 | } |
587 | 0 | if (I < Info.Args.size() - 1) { |
588 | 0 | Iter = fmt::format_to(Iter, " , "sv); |
589 | 0 | } |
590 | 0 | } |
591 | 0 | Iter = fmt::format_to(Iter, "]"sv); |
592 | 0 | } |
593 | 0 | return formatter<std::string_view>::format( |
594 | 0 | std::string_view(Buffer.data(), Buffer.size()), Ctx); |
595 | 0 | } |
596 | | }; |
597 | | template <> |
598 | | struct fmt::formatter<WasmEdge::ErrInfo::InfoBoundary> |
599 | | : fmt::formatter<std::string_view> { |
600 | | template <typename FmtCtx> |
601 | | auto format(const WasmEdge::ErrInfo::InfoBoundary &Info, |
602 | 0 | FmtCtx &Ctx) WASMEDGE_FMT_CONST noexcept -> decltype(Ctx.out()) { |
603 | 0 | using namespace std::literals; |
604 | 0 | fmt::memory_buffer Buffer; |
605 | 0 | WasmEdge::uint128_t OffFrom = Info.Offset; |
606 | 0 | if (Info.IsOffsetOverflow) { |
607 | 0 | OffFrom += (WasmEdge::uint128_t(1ULL) << 64); |
608 | 0 | } |
609 | 0 | WasmEdge::uint128_t OffTo = |
610 | 0 | OffFrom + WasmEdge::uint128_t(Info.Size > 0U ? Info.Size - 1U : 0U); |
611 | 0 | uint64_t Bound = (Info.Limit > 0U ? Info.Limit - 1U : 0U); |
612 | | #if WASMEDGE_OS_WINDOWS |
613 | | uint64_t OffFromHigh = static_cast<uint64_t>(OffFrom >> 64); |
614 | | uint64_t OffFromLow = static_cast<uint64_t>(OffFrom); |
615 | | uint64_t OffToHigh = static_cast<uint64_t>(OffTo >> 64); |
616 | | uint64_t OffToLow = static_cast<uint64_t>(OffTo); |
617 | | if (OffFromHigh > 0) { |
618 | | fmt::format_to(std::back_inserter(Buffer), |
619 | | " Accessing offset from: 0x{:8x}{:016x} to: " |
620 | | "0x{:8x}{:016x} , Out of " |
621 | | "boundary: 0x{:016x}"sv, |
622 | | OffFromHigh, OffFromLow, OffToHigh, OffToLow, Bound); |
623 | | } else { |
624 | | fmt::format_to( |
625 | | std::back_inserter(Buffer), |
626 | | " Accessing offset from: 0x{:08x} to: 0x{:08x} , Out of " |
627 | | "boundary: 0x{:08x}"sv, |
628 | | OffFromLow, OffToLow, Bound); |
629 | | } |
630 | | #elif defined(__x86_64__) || defined(__aarch64__) || \ |
631 | | (defined(__riscv) && __riscv_xlen == 64) || defined(__s390x__) |
632 | | fmt::format_to(std::back_inserter(Buffer), |
633 | 0 | " Accessing offset from: 0x{:08x} to: 0x{:08x} , Out of " |
634 | 0 | "boundary: 0x{:08x}"sv, |
635 | 0 | OffFrom, OffTo, Bound); |
636 | | #else |
637 | | if (OffFrom.high() > 0) { |
638 | | fmt::format_to(std::back_inserter(Buffer), |
639 | | " Accessing offset from: 0x{:8x}{:016x} to: " |
640 | | "0x{:8x}{:016x} , Out of " |
641 | | "boundary: 0x{:016x}"sv, |
642 | | OffFrom.high(), OffFrom.low(), OffTo.high(), OffTo.low(), |
643 | | Bound); |
644 | | } else { |
645 | | fmt::format_to( |
646 | | std::back_inserter(Buffer), |
647 | | " Accessing offset from: 0x{:08x} to: 0x{:08x} , Out of " |
648 | | "boundary: 0x{:08x}"sv, |
649 | | OffFrom.low(), OffTo.low(), Bound); |
650 | | } |
651 | | #endif |
652 | 0 | return formatter<std::string_view>::format( |
653 | 0 | std::string_view(Buffer.data(), Buffer.size()), Ctx); |
654 | 0 | } |
655 | | }; |
656 | | template <> |
657 | | struct fmt::formatter<WasmEdge::ErrInfo::InfoProposal> |
658 | | : fmt::formatter<std::string_view> { |
659 | | template <typename FmtCtx> |
660 | | auto format(const WasmEdge::ErrInfo::InfoProposal &Info, |
661 | 0 | FmtCtx &Ctx) WASMEDGE_FMT_CONST noexcept -> decltype(Ctx.out()) { |
662 | 0 | using namespace std::literals; |
663 | 0 | fmt::memory_buffer Buffer; |
664 | 0 | if (auto Iter = WasmEdge::ProposalStr.find(Info.P); |
665 | 0 | Iter != WasmEdge::ProposalStr.end()) { |
666 | 0 | fmt::format_to( |
667 | 0 | std::back_inserter(Buffer), |
668 | 0 | " This instruction or syntax requires enabling {} proposal"sv, |
669 | 0 | Iter->second); |
670 | 0 | } else { |
671 | 0 | fmt::format_to(std::back_inserter(Buffer), |
672 | 0 | " Unknown proposal, Code 0x{:08x}"sv, |
673 | 0 | static_cast<uint32_t>(Info.P)); |
674 | 0 | } |
675 | 0 | return formatter<std::string_view>::format( |
676 | 0 | std::string_view(Buffer.data(), Buffer.size()), Ctx); |
677 | 0 | } |
678 | | }; |