/src/WasmEdge/lib/common/errinfo.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 "common/errinfo.h" |
5 | | #include "common/errcode.h" |
6 | | #include "common/hexstr.h" |
7 | | |
8 | | #include <spdlog/fmt/fmt.h> |
9 | | #include <spdlog/fmt/ranges.h> |
10 | | |
11 | | using namespace std::literals; |
12 | | |
13 | | fmt::format_context::iterator |
14 | | fmt::formatter<WasmEdge::ErrInfo::InfoFile>::format( |
15 | | const WasmEdge::ErrInfo::InfoFile &Info, |
16 | 0 | fmt::format_context &Ctx) const noexcept { |
17 | 0 | fmt::memory_buffer Buffer; |
18 | 0 | fmt::format_to(std::back_inserter(Buffer), " File name: {}"sv, |
19 | 0 | Info.FileName); |
20 | 0 | return formatter<std::string_view>::format( |
21 | 0 | std::string_view(Buffer.data(), Buffer.size()), Ctx); |
22 | 0 | } |
23 | | |
24 | | fmt::format_context::iterator |
25 | | fmt::formatter<WasmEdge::ErrInfo::InfoLoading>::format( |
26 | | const WasmEdge::ErrInfo::InfoLoading &Info, |
27 | 0 | fmt::format_context &Ctx) const noexcept { |
28 | 0 | fmt::memory_buffer Buffer; |
29 | 0 | fmt::format_to(std::back_inserter(Buffer), " Bytecode offset: 0x{:08x}"sv, |
30 | 0 | Info.Offset); |
31 | 0 | return formatter<std::string_view>::format( |
32 | 0 | std::string_view(Buffer.data(), Buffer.size()), Ctx); |
33 | 0 | } |
34 | | |
35 | | fmt::format_context::iterator |
36 | | fmt::formatter<WasmEdge::ErrInfo::InfoAST>::format( |
37 | | const WasmEdge::ErrInfo::InfoAST &Info, |
38 | 0 | fmt::format_context &Ctx) const noexcept { |
39 | 0 | fmt::memory_buffer Buffer; |
40 | 0 | fmt::format_to(std::back_inserter(Buffer), " At AST node: {}"sv, |
41 | 0 | Info.NodeAttr); |
42 | 0 | return formatter<std::string_view>::format( |
43 | 0 | std::string_view(Buffer.data(), Buffer.size()), Ctx); |
44 | 0 | } |
45 | | |
46 | | fmt::format_context::iterator |
47 | | fmt::formatter<WasmEdge::ErrInfo::InfoInstanceBound>::format( |
48 | | const WasmEdge::ErrInfo::InfoInstanceBound &Info, |
49 | 0 | fmt::format_context &Ctx) const noexcept { |
50 | 0 | fmt::memory_buffer Buffer; |
51 | 0 | fmt::format_to(std::back_inserter(Buffer), |
52 | 0 | " Instance {} has limited number {} , Got: {}"sv, |
53 | 0 | Info.Instance, Info.Limited, Info.Number); |
54 | 0 | return formatter<std::string_view>::format( |
55 | 0 | std::string_view(Buffer.data(), Buffer.size()), Ctx); |
56 | 0 | } |
57 | | |
58 | | fmt::format_context::iterator |
59 | | fmt::formatter<WasmEdge::ErrInfo::InfoForbidIndex>::format( |
60 | | const WasmEdge::ErrInfo::InfoForbidIndex &Info, |
61 | 0 | fmt::format_context &Ctx) const noexcept { |
62 | 0 | fmt::memory_buffer Buffer; |
63 | 0 | auto Iter = |
64 | 0 | fmt::format_to(std::back_inserter(Buffer), |
65 | 0 | " When checking {} index: {} , Out of boundary: "sv, |
66 | 0 | Info.Category, Info.Index); |
67 | 0 | if (Info.Boundary > 0) { |
68 | 0 | fmt::format_to(Iter, "{}"sv, Info.Boundary - 1); |
69 | 0 | } else { |
70 | 0 | fmt::format_to(Iter, "empty"sv); |
71 | 0 | } |
72 | 0 | return formatter<std::string_view>::format( |
73 | 0 | std::string_view(Buffer.data(), Buffer.size()), Ctx); |
74 | 0 | } |
75 | | |
76 | | fmt::format_context::iterator |
77 | | fmt::formatter<WasmEdge::ErrInfo::InfoExporting>::format( |
78 | | const WasmEdge::ErrInfo::InfoExporting &Info, |
79 | 0 | fmt::format_context &Ctx) const noexcept { |
80 | 0 | fmt::memory_buffer Buffer; |
81 | 0 | fmt::format_to(std::back_inserter(Buffer), |
82 | 0 | " Duplicated exporting name: \"{}\""sv, Info.ExtName); |
83 | 0 | return formatter<std::string_view>::format( |
84 | 0 | std::string_view(Buffer.data(), Buffer.size()), Ctx); |
85 | 0 | } |
86 | | |
87 | | fmt::format_context::iterator |
88 | | fmt::formatter<WasmEdge::ErrInfo::InfoLimit>::format( |
89 | | const WasmEdge::ErrInfo::InfoLimit &Info, |
90 | 0 | fmt::format_context &Ctx) const noexcept { |
91 | 0 | fmt::memory_buffer Buffer; |
92 | 0 | auto Iter = fmt::format_to(std::back_inserter(Buffer), |
93 | 0 | " In Limit type: {{ min: {}"sv, Info.LimMin); |
94 | 0 | if (Info.LimHasMax) { |
95 | 0 | Iter = fmt::format_to(Iter, " , max: {}"sv, Info.LimMax); |
96 | 0 | } |
97 | 0 | fmt::format_to(Iter, " }}"sv); |
98 | 0 | return formatter<std::string_view>::format( |
99 | 0 | std::string_view(Buffer.data(), Buffer.size()), Ctx); |
100 | 0 | } |
101 | | |
102 | | fmt::format_context::iterator |
103 | | fmt::formatter<WasmEdge::ErrInfo::InfoRegistering>::format( |
104 | | const WasmEdge::ErrInfo::InfoRegistering &Info, |
105 | 0 | fmt::format_context &Ctx) const noexcept { |
106 | 0 | fmt::memory_buffer Buffer; |
107 | 0 | fmt::format_to(std::back_inserter(Buffer), " Module name: \"{}\""sv, |
108 | 0 | Info.ModName); |
109 | 0 | return formatter<std::string_view>::format( |
110 | 0 | std::string_view(Buffer.data(), Buffer.size()), Ctx); |
111 | 0 | } |
112 | | |
113 | | fmt::format_context::iterator |
114 | | fmt::formatter<WasmEdge::ErrInfo::InfoLinking>::format( |
115 | | const WasmEdge::ErrInfo::InfoLinking &Info, |
116 | 0 | fmt::format_context &Ctx) const noexcept { |
117 | 0 | fmt::memory_buffer Buffer; |
118 | 0 | fmt::format_to(std::back_inserter(Buffer), |
119 | 0 | " When linking module: \"{}\" , {} name: \"{}\""sv, |
120 | 0 | Info.ModName, Info.ExtType, Info.ExtName); |
121 | 0 | return formatter<std::string_view>::format( |
122 | 0 | std::string_view(Buffer.data(), Buffer.size()), Ctx); |
123 | 0 | } |
124 | | |
125 | | fmt::format_context::iterator |
126 | | fmt::formatter<WasmEdge::ErrInfo::InfoExecuting>::format( |
127 | | const WasmEdge::ErrInfo::InfoExecuting &Info, |
128 | 0 | fmt::format_context &Ctx) const noexcept { |
129 | 0 | fmt::memory_buffer Buffer; |
130 | 0 | auto Iter = |
131 | 0 | fmt::format_to(std::back_inserter(Buffer), " When executing "sv); |
132 | 0 | if (!Info.ModName.empty()) { |
133 | 0 | Iter = fmt::format_to(Iter, "module name: \"{}\" , "sv, Info.ModName); |
134 | 0 | } |
135 | 0 | fmt::format_to(Iter, "function name: \"{}\""sv, Info.FuncName); |
136 | 0 | return formatter<std::string_view>::format( |
137 | 0 | std::string_view(Buffer.data(), Buffer.size()), Ctx); |
138 | 0 | } |
139 | | |
140 | | fmt::format_context::iterator |
141 | | fmt::formatter<WasmEdge::ErrInfo::InfoMismatch>::format( |
142 | | const WasmEdge::ErrInfo::InfoMismatch &Info, |
143 | 0 | fmt::format_context &Ctx) const noexcept { |
144 | 0 | fmt::memory_buffer Buffer; |
145 | 0 | auto Iter = fmt::format_to(std::back_inserter(Buffer), |
146 | 0 | " Mismatched {}. "sv, Info.Category); |
147 | 0 | auto FormatLimit = [](auto Out, bool LimHasMax, uint32_t LimMin, |
148 | 0 | uint32_t LimMax) { |
149 | 0 | Out = fmt::format_to(Out, "Limit{{{}"sv, LimMin); |
150 | 0 | if (LimHasMax) { |
151 | 0 | Out = fmt::format_to(Out, " , {}"sv, LimMax); |
152 | 0 | } |
153 | 0 | Out = fmt::format_to(Out, "}}"sv); |
154 | 0 | return Out; |
155 | 0 | }; |
156 | 0 | switch (Info.Category) { |
157 | 0 | case WasmEdge::ErrInfo::MismatchCategory::Alignment: |
158 | 0 | if (Info.GotAlignment < Info.ExpAlignment) { |
159 | 0 | fmt::format_to(Iter, "Expected: need to == {} , Got: {}"sv, |
160 | 0 | static_cast<uint32_t>(Info.ExpAlignment), |
161 | 0 | 1UL << Info.GotAlignment); |
162 | 0 | } else { |
163 | 0 | fmt::format_to(Iter, "Expected: need to <= {} , Got: {}"sv, |
164 | 0 | static_cast<uint32_t>(Info.ExpAlignment), |
165 | 0 | 1UL << Info.GotAlignment); |
166 | 0 | } |
167 | 0 | break; |
168 | 0 | case WasmEdge::ErrInfo::MismatchCategory::ValueType: |
169 | 0 | fmt::format_to(Iter, "Expected: {} , Got: {}"sv, Info.ExpValType, |
170 | 0 | Info.GotValType); |
171 | 0 | break; |
172 | 0 | case WasmEdge::ErrInfo::MismatchCategory::ValueTypes: |
173 | 0 | fmt::format_to(Iter, "Expected: types{{{}}} , Got: types{{{}}}"sv, |
174 | 0 | fmt::join(Info.ExpParams, " , "sv), |
175 | 0 | fmt::join(Info.GotParams, " , "sv)); |
176 | 0 | break; |
177 | 0 | case WasmEdge::ErrInfo::MismatchCategory::Mutation: |
178 | 0 | fmt::format_to(Iter, "Expected: {} , Got: {}"sv, Info.ExpValMut, |
179 | 0 | Info.GotValMut); |
180 | 0 | break; |
181 | 0 | case WasmEdge::ErrInfo::MismatchCategory::ExternalType: |
182 | 0 | fmt::format_to(Iter, "Expected: {} , Got: {}", Info.ExpExtType, |
183 | 0 | Info.GotExtType); |
184 | 0 | break; |
185 | 0 | case WasmEdge::ErrInfo::MismatchCategory::FunctionType: |
186 | 0 | fmt::format_to(Iter, |
187 | 0 | "Expected: FuncType {{params{{{}}} returns{{{}}}}} , " |
188 | 0 | "Got: FuncType {{params{{{}}} returns{{{}}}}}"sv, |
189 | 0 | fmt::join(Info.ExpParams, " , "sv), |
190 | 0 | fmt::join(Info.ExpReturns, " , "sv), |
191 | 0 | fmt::join(Info.GotParams, " , "sv), |
192 | 0 | fmt::join(Info.GotReturns, " , "sv)); |
193 | 0 | break; |
194 | 0 | case WasmEdge::ErrInfo::MismatchCategory::Table: |
195 | 0 | Iter = fmt::format_to(Iter, "Expected: TableType {{RefType{{{}}} "sv, |
196 | 0 | static_cast<WasmEdge::ValType>(Info.ExpValType)); |
197 | 0 | Iter = FormatLimit(Iter, Info.ExpLimHasMax, Info.ExpLimMin, Info.ExpLimMax); |
198 | 0 | Iter = fmt::format_to(Iter, "}} , Got: TableType {{RefType{{{}}} "sv, |
199 | 0 | static_cast<WasmEdge::ValType>(Info.GotValType)); |
200 | 0 | Iter = FormatLimit(Iter, Info.GotLimHasMax, Info.GotLimMin, Info.GotLimMax); |
201 | 0 | fmt::format_to(Iter, "}}"sv); |
202 | 0 | break; |
203 | 0 | case WasmEdge::ErrInfo::MismatchCategory::Memory: |
204 | 0 | Iter = fmt::format_to(Iter, "Expected: MemoryType {{"sv); |
205 | 0 | Iter = FormatLimit(Iter, Info.ExpLimHasMax, Info.ExpLimMin, Info.ExpLimMax); |
206 | 0 | Iter = fmt::format_to(Iter, "}} , Got: MemoryType {{"sv); |
207 | 0 | Iter = FormatLimit(Iter, Info.GotLimHasMax, Info.GotLimMin, Info.GotLimMax); |
208 | 0 | fmt::format_to(Iter, "}}"sv); |
209 | 0 | break; |
210 | 0 | case WasmEdge::ErrInfo::MismatchCategory::Global: |
211 | 0 | fmt::format_to(Iter, |
212 | 0 | "Expected: GlobalType {{Mutation{{{}}} ValType{{{}}}}} , " |
213 | 0 | "Got: GlobalType {{Mutation{{{}}} ValType{{{}}}}}"sv, |
214 | 0 | Info.ExpValMut, Info.ExpValType, Info.GotValMut, |
215 | 0 | Info.GotValType); |
216 | 0 | break; |
217 | 0 | case WasmEdge::ErrInfo::MismatchCategory::Version: |
218 | 0 | fmt::format_to(Iter, "Expected: {} , Got: {}"sv, Info.ExpVersion, |
219 | 0 | Info.GotVersion); |
220 | 0 | break; |
221 | 0 | default: |
222 | 0 | break; |
223 | 0 | } |
224 | 0 | return formatter<std::string_view>::format( |
225 | 0 | std::string_view(Buffer.data(), Buffer.size()), Ctx); |
226 | 0 | } |
227 | | |
228 | | fmt::format_context::iterator |
229 | | fmt::formatter<WasmEdge::ErrInfo::InfoInstruction>::format( |
230 | | const WasmEdge::ErrInfo::InfoInstruction &Info, |
231 | 0 | fmt::format_context &Ctx) const noexcept { |
232 | 0 | uint16_t Payload = static_cast<uint16_t>(Info.Code); |
233 | 0 | fmt::memory_buffer Buffer; |
234 | 0 | auto Iter = fmt::format_to(std::back_inserter(Buffer), |
235 | 0 | " In instruction: {} ("sv, Info.Code); |
236 | 0 | if ((Payload >> 8) >= static_cast<uint16_t>(0xFCU)) { |
237 | 0 | Iter = fmt::format_to(Iter, "0x{:02x} "sv, Payload >> 8); |
238 | 0 | } |
239 | 0 | Iter = fmt::format_to(Iter, "0x{:02x}) , Bytecode offset: 0x{:08x}"sv, |
240 | 0 | Payload & 0xFFU, Info.Offset); |
241 | 0 | if (!Info.Args.empty()) { |
242 | 0 | Iter = fmt::format_to(Iter, " , Args: ["sv); |
243 | 0 | for (uint32_t I = 0; I < Info.Args.size(); ++I) { |
244 | 0 | switch (Info.ArgsTypes[I].getCode()) { |
245 | 0 | case WasmEdge::TypeCode::I32: |
246 | 0 | if (Info.IsSigned) { |
247 | 0 | Iter = fmt::format_to(Iter, "{}"sv, Info.Args[I].get<int32_t>()); |
248 | 0 | } else { |
249 | 0 | Iter = fmt::format_to(Iter, "{}"sv, Info.Args[I].get<uint32_t>()); |
250 | 0 | } |
251 | 0 | break; |
252 | 0 | case WasmEdge::TypeCode::I64: |
253 | 0 | if (Info.IsSigned) { |
254 | 0 | Iter = fmt::format_to(Iter, "{}"sv, Info.Args[I].get<int64_t>()); |
255 | 0 | } else { |
256 | 0 | Iter = fmt::format_to(Iter, "{}"sv, Info.Args[I].get<uint64_t>()); |
257 | 0 | } |
258 | 0 | break; |
259 | 0 | case WasmEdge::TypeCode::F32: |
260 | 0 | Iter = fmt::format_to(Iter, "{}"sv, Info.Args[I].get<float>()); |
261 | 0 | break; |
262 | 0 | case WasmEdge::TypeCode::F64: |
263 | 0 | Iter = fmt::format_to(Iter, "{}"sv, Info.Args[I].get<double>()); |
264 | 0 | break; |
265 | 0 | case WasmEdge::TypeCode::V128: { |
266 | 0 | const auto Value = Info.Args[I].get<WasmEdge::uint64x2_t>(); |
267 | 0 | Iter = fmt::format_to(Iter, "0x{:08x}{:08x}"sv, Value[1], Value[0]); |
268 | 0 | break; |
269 | 0 | } |
270 | 0 | case WasmEdge::TypeCode::Ref: |
271 | 0 | case WasmEdge::TypeCode::RefNull: |
272 | 0 | Iter = fmt::format_to(Iter, "{}"sv, Info.ArgsTypes[I]); |
273 | 0 | if (Info.Args[I].get<WasmEdge::RefVariant>().isNull()) { |
274 | 0 | Iter = fmt::format_to(Iter, ":null"sv); |
275 | 0 | } else { |
276 | 0 | Iter = |
277 | 0 | fmt::format_to(Iter, ":0x{:08x}"sv, Info.Args[I].get<uint64_t>()); |
278 | 0 | } |
279 | 0 | break; |
280 | 0 | default: |
281 | 0 | break; |
282 | 0 | } |
283 | 0 | if (I < Info.Args.size() - 1) { |
284 | 0 | Iter = fmt::format_to(Iter, " , "sv); |
285 | 0 | } |
286 | 0 | } |
287 | 0 | Iter = fmt::format_to(Iter, "]"sv); |
288 | 0 | } |
289 | 0 | return formatter<std::string_view>::format( |
290 | 0 | std::string_view(Buffer.data(), Buffer.size()), Ctx); |
291 | 0 | } |
292 | | |
293 | | fmt::format_context::iterator |
294 | | fmt::formatter<WasmEdge::ErrInfo::InfoBoundary>::format( |
295 | | const WasmEdge::ErrInfo::InfoBoundary &Info, |
296 | 0 | fmt::format_context &Ctx) const noexcept { |
297 | 0 | fmt::memory_buffer Buffer; |
298 | 0 | fmt::format_to(std::back_inserter(Buffer), |
299 | 0 | " Accessing offset from: 0x{:08x} to: 0x{:08x} , Out of " |
300 | 0 | "boundary: 0x{:08x}"sv, |
301 | 0 | Info.Offset, |
302 | 0 | Info.Offset + (Info.Size > 0U ? Info.Size - 1U : 0U), |
303 | 0 | Info.Limit); |
304 | 0 | return formatter<std::string_view>::format( |
305 | 0 | std::string_view(Buffer.data(), Buffer.size()), Ctx); |
306 | 0 | } |
307 | | |
308 | | fmt::format_context::iterator |
309 | | fmt::formatter<WasmEdge::ErrInfo::InfoProposal>::format( |
310 | | const WasmEdge::ErrInfo::InfoProposal &Info, |
311 | 0 | fmt::format_context &Ctx) const noexcept { |
312 | 0 | fmt::memory_buffer Buffer; |
313 | 0 | if (auto Iter = WasmEdge::ProposalStr.find(Info.P); |
314 | 0 | Iter != WasmEdge::ProposalStr.end()) { |
315 | 0 | fmt::format_to( |
316 | 0 | std::back_inserter(Buffer), |
317 | 0 | " This instruction or syntax requires enabling {} proposal"sv, |
318 | 0 | Iter->second); |
319 | 0 | } else { |
320 | 0 | fmt::format_to(std::back_inserter(Buffer), |
321 | 0 | " Unknown proposal, Code 0x{:08x}"sv, |
322 | 0 | static_cast<uint32_t>(Info.P)); |
323 | 0 | } |
324 | 0 | return formatter<std::string_view>::format( |
325 | 0 | std::string_view(Buffer.data(), Buffer.size()), Ctx); |
326 | 0 | } |