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