Move to the next frame in this activation, if any. # Safety The `unwind` passed in must correspond to the host implementation from which this stack came.
(&mut self, unwind: &dyn Unwind)
| 175 | /// The `unwind` passed in must correspond to the host |
| 176 | /// implementation from which this stack came. |
| 177 | pub unsafe fn advance(&mut self, unwind: &dyn Unwind) { |
| 178 | // This logic will walk the linked list of frame pointers starting |
| 179 | // at `fp` and going up until `trampoline_fp`. We know that both |
| 180 | // `fp` and `trampoline_fp` are "trusted values" aka generated and |
| 181 | // maintained by Wasmtime. This means that it should be safe to |
| 182 | // walk the linked list of pointers and inspect Wasm frames. |
| 183 | // |
| 184 | // Note, though, that any frames outside of this range are not |
| 185 | // guaranteed to have valid frame pointers. For example native code |
| 186 | // might be using the frame pointer as a general purpose register. Thus |
| 187 | // we need to be careful to only walk frame pointers in this one |
| 188 | // contiguous linked list. |
| 189 | // |
| 190 | // To know when to stop iteration all architectures' stacks currently |
| 191 | // look something like this: |
| 192 | // |
| 193 | // | ... | |
| 194 | // | Native Frames | |
| 195 | // | ... | |
| 196 | // |-------------------| |
| 197 | // | ... | <-- Trampoline FP | |
| 198 | // | Trampoline Frame | | |
| 199 | // | ... | <-- Trampoline SP | |
| 200 | // |-------------------| Stack |
| 201 | // | Return Address | Grows |
| 202 | // | Previous FP | <-- Wasm FP Down |
| 203 | // | ... | | |
| 204 | // | Cranelift Frames | | |
| 205 | // | ... | V |
| 206 | // |
| 207 | // The trampoline records its own frame pointer (`trampoline_fp`), |
| 208 | // which is guaranteed to be above all Wasm code. To check when |
| 209 | |
| 210 | // to check when the next frame pointer is equal to |
| 211 | // `trampoline_fp`. Once that's hit then we know that the entire |
| 212 | // linked list has been traversed. |
| 213 | // |
| 214 | // Note that it might be possible that this loop doesn't execute |
| 215 | // at all. For example if the entry trampoline called Wasm code |
| 216 | // which `return_call`'d an exit trampoline, then `fp == |
| 217 | // trampoline_fp` on the entry of this function, meaning the loop |
| 218 | // won't actually execute anything. |
| 219 | if self.fp == self.trampoline_fp { |
| 220 | log::trace!("=== Done tracing contiguous sequence of Wasm frames ==="); |
| 221 | return; |
| 222 | } |
| 223 | |
| 224 | // At the start of each iteration of the loop, we know that |
| 225 | // `fp` is a frame pointer from Wasm code. Therefore, we know |
| 226 | // it is not being used as an extra general-purpose register, |
| 227 | // and it is safe dereference to get the PC and the next older |
| 228 | // frame pointer. |
| 229 | // |
| 230 | // The stack also grows down, and therefore any frame pointer |
| 231 | // we are dealing with should be less than the frame pointer |
| 232 | // on entry to Wasm code. Finally also assert that it's |
| 233 | // aligned correctly as an additional sanity check. |
| 234 | assert!( |
no test coverage detected