1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/**
* \file wasmtime/trap.hh
*/
#ifndef WASMTIME_TRAP_HH
#define WASMTIME_TRAP_HH
#include <wasmtime/error.hh>
#include <wasmtime/trap.h>
namespace wasmtime {
/**
* \brief Non-owning reference to a WebAssembly function frame as part of a
* `Trace`
*
* A `FrameRef` represents a WebAssembly function frame on the stack which was
* collected as part of a trap.
*/
class FrameRef {
wasm_frame_t *frame;
public:
/// Returns the WebAssembly function index of this function, in the original
/// module.
uint32_t func_index() const { return wasm_frame_func_index(frame); }
/// Returns the offset, in bytes from the start of the function in the
/// original module, to this frame's program counter.
size_t func_offset() const { return wasm_frame_func_offset(frame); }
/// Returns the offset, in bytes from the start of the original module,
/// to this frame's program counter.
size_t module_offset() const { return wasm_frame_module_offset(frame); }
/// Returns the name, if present, associated with this function.
///
/// Note that this requires that the `name` section is present in the original
/// WebAssembly binary.
std::optional<std::string_view> func_name() const {
const auto *name = wasmtime_frame_func_name(frame);
if (name != nullptr) {
return std::string_view(name->data, name->size);
}
return std::nullopt;
}
/// Returns the name, if present, associated with this function's module.
///
/// Note that this requires that the `name` section is present in the original
/// WebAssembly binary.
std::optional<std::string_view> module_name() const {
const auto *name = wasmtime_frame_module_name(frame);
if (name != nullptr) {
return std::string_view(name->data, name->size);
}
return std::nullopt;
}
};
/**
* \brief An owned vector of `FrameRef` instances representing the WebAssembly
* call-stack on a trap.
*
* This can be used to iterate over the frames of a trap and determine what was
* running when a trap happened.
*/
class Trace {
friend class Trap;
friend class Error;
wasm_frame_vec_t vec;
Trace(wasm_frame_vec_t vec) : vec(vec) {}
public:
~Trace() { wasm_frame_vec_delete(&vec); }
Trace(const Trace &other) = delete;
Trace(Trace &&other) = delete;
Trace &operator=(const Trace &other) = delete;
Trace &operator=(Trace &&other) = delete;
/// Iterator used to iterate over this trace.
typedef const FrameRef *iterator;
/// Returns the start of iteration
iterator begin() const {
return reinterpret_cast<FrameRef *>(&vec.data[0]); // NOLINT
}
/// Returns the end of iteration
iterator end() const {
return reinterpret_cast<FrameRef *>(&vec.data[vec.size]); // NOLINT
}
/// Returns the size of this trace, or how many frames it contains.
size_t size() const { return vec.size; }
};
inline Trace Error::trace() const {
wasm_frame_vec_t frames;
wasmtime_error_wasm_trace(ptr.get(), &frames);
return Trace(frames);
}
/**
* \brief Information about a WebAssembly trap.
*
* Traps can happen during normal wasm execution (such as the `unreachable`
* instruction) but they can also happen in host-provided functions to a host
* function can simulate raising a trap.
*
* Traps have a message associated with them as well as a trace of WebAssembly
* frames on the stack.
*/
class Trap {
WASMTIME_OWN_WRAPPER(Trap, wasm_trap);
/// Creates a new host-defined trap with the specified message.
explicit Trap(std::string_view msg)
: Trap(wasmtime_trap_new(msg.data(), msg.size())) {}
/// Creates a new trap with the given wasmtime trap code.
Trap(wasmtime_trap_code_enum code) : Trap(wasmtime_trap_new_code(code)) {}
/// Returns the descriptive message associated with this trap.
std::string message() const {
wasm_byte_vec_t msg;
wasm_trap_message(ptr.get(), &msg);
std::string ret(msg.data, msg.size - 1);
wasm_byte_vec_delete(&msg);
return ret;
}
/// Returns the trace of WebAssembly frames associated with this trap.
///
/// Note that the `trace` cannot outlive this error object.
Trace trace() const {
wasm_frame_vec_t frames;
wasm_trap_trace(ptr.get(), &frames);
return Trace(frames);
}
/// \brief Returns the trap code associated with this trap, or nothing if
/// it was a manually created trap.
std::optional<wasmtime_trap_code_t> code() const {
wasmtime_trap_code_t code;
bool present = wasmtime_trap_code(ptr.get(), &code);
if (present)
return code;
return std::nullopt;
}
};
/// Structure used to represent either a `Trap` or an `Error`.
struct TrapError {
/// Storage for what this trap represents.
std::variant<Trap, Error> data;
/// Creates a new `TrapError` from a `Trap`
TrapError(Trap t) : data(std::move(t)) {}
/// Creates a new `TrapError` from an `Error`
TrapError(Error e) : data(std::move(e)) {}
/// Dispatches internally to return the message associated with this error.
std::string message() const {
if (const auto *trap = std::get_if<Trap>(&data)) {
return trap->message();
}
if (const auto *error = std::get_if<Error>(&data)) {
return std::string(error->message());
}
std::abort();
}
};
/// Result used by functions which can fail because of invariants being violated
/// (such as a type error) as well as because of a WebAssembly trap.
template <typename T> using TrapResult = Result<T, TrapError>;
} // namespace wasmtime
#endif // WASMTIME_TRAP_HH