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.
func_index() const26   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.
func_offset() const29   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.
module_offset() const32   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.
func_name() const38   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.
module_name() const50   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 
Trace(wasm_frame_vec_t vec)72   Trace(wasm_frame_vec_t vec) : vec(vec) {}
73 
74 public:
~Trace()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
begin() const86   iterator begin() const {
87     return reinterpret_cast<FrameRef *>(&vec.data[0]); // NOLINT
88   }
89   /// Returns the end of iteration
end() const90   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.
size() const94   size_t size() const { return vec.size; }
95 };
96 
trace() const97 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.
Trap(std::string_view msg)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.
Trap(wasmtime_trap_code_enum code)121   Trap(wasmtime_trap_code_enum code) : Trap(wasmtime_trap_new_code(code)) {}
122 
123   /// Returns the descriptive message associated with this trap.
message() const124   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.
trace() const135   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.
code() const143   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`
TrapErrorwasmtime::TrapError158   TrapError(Trap t) : data(std::move(t)) {}
159   /// Creates a new `TrapError` from an `Error`
TrapErrorwasmtime::TrapError160   TrapError(Error e) : data(std::move(e)) {}
161 
162   /// Dispatches internally to return the message associated with this error.
messagewasmtime::TrapError163   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