github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/internal/engine/wazevo/backend/isa/arm64/unwind_stack.go (about) 1 package arm64 2 3 import ( 4 "encoding/binary" 5 "reflect" 6 "unsafe" 7 ) 8 9 // UnwindStack is a function to unwind the stack, and appends return addresses to `returnAddresses` slice. 10 // The implementation must be aligned with the ABI/Calling convention as in machine_pro_epi_logue.go/abi.go. 11 func UnwindStack(sp, top uintptr, returnAddresses []uintptr) []uintptr { 12 l := int(top - sp) 13 14 var stackBuf []byte 15 { 16 // TODO: use unsafe.Slice after floor version is set to Go 1.20. 17 hdr := (*reflect.SliceHeader)(unsafe.Pointer(&stackBuf)) 18 hdr.Data = sp 19 hdr.Len = l 20 hdr.Cap = l 21 } 22 23 for i := uint64(0); i < uint64(l); { 24 // (high address) 25 // +-----------------+ 26 // | ....... | 27 // | ret Y | <----+ 28 // | ....... | | 29 // | ret 0 | | 30 // | arg X | | size_of_arg_ret 31 // | ....... | | 32 // | arg 1 | | 33 // | arg 0 | <----+ 34 // | size_of_arg_ret | 35 // | ReturnAddress | 36 // +-----------------+ <----+ 37 // | ........... | | 38 // | spill slot M | | 39 // | ............ | | 40 // | spill slot 2 | | 41 // | spill slot 1 | | frame size 42 // | spill slot 1 | | 43 // | clobbered N | | 44 // | ............ | | 45 // | clobbered 0 | <----+ 46 // | xxxxxx | ;; unused space to make it 16-byte aligned. 47 // | frame_size | 48 // +-----------------+ <---- SP 49 // (low address) 50 51 frameSize := binary.LittleEndian.Uint64(stackBuf[i:]) 52 i += frameSize + 53 16 // frame size + aligned space. 54 retAddr := binary.LittleEndian.Uint64(stackBuf[i:]) 55 i += 8 // ret addr. 56 sizeOfArgRet := binary.LittleEndian.Uint64(stackBuf[i:]) 57 i += 8 + sizeOfArgRet 58 returnAddresses = append(returnAddresses, uintptr(retAddr)) 59 } 60 return returnAddresses 61 } 62 63 // GoCallStackView is a function to get a view of the stack before a Go call, which 64 // is the view of the stack allocated in CompileGoFunctionTrampoline. 65 func GoCallStackView(stackPointerBeforeGoCall *uint64) []uint64 { 66 // (high address) 67 // +-----------------+ <----+ 68 // | xxxxxxxxxxx | | ;; optional unused space to make it 16-byte aligned. 69 // ^ | arg[N]/ret[M] | | 70 // sliceSize | | ............ | | sliceSize 71 // | | arg[1]/ret[1] | | 72 // v | arg[0]/ret[0] | <----+ 73 // | sliceSize | 74 // | frame_size | 75 // +-----------------+ <---- stackPointerBeforeGoCall 76 // (low address) 77 size := *(*uint64)(unsafe.Pointer(uintptr(unsafe.Pointer(stackPointerBeforeGoCall)) + 8)) 78 var view []uint64 79 { 80 sh := (*reflect.SliceHeader)(unsafe.Pointer(&view)) 81 sh.Data = uintptr(unsafe.Pointer(stackPointerBeforeGoCall)) + 16 // skips the (frame_size, sliceSize). 82 sh.Len = int(size) 83 sh.Cap = int(size) 84 } 85 return view 86 }