github.com/tetratelabs/wazero@v1.7.3-0.20240513003603-48f702e154b5/internal/engine/wazevo/backend/isa/amd64/stack.go (about) 1 package amd64 2 3 import ( 4 "encoding/binary" 5 "reflect" 6 "unsafe" 7 8 "github.com/tetratelabs/wazero/internal/wasmdebug" 9 ) 10 11 func stackView(rbp, top uintptr) []byte { 12 var stackBuf []byte 13 { 14 // TODO: use unsafe.Slice after floor version is set to Go 1.20. 15 hdr := (*reflect.SliceHeader)(unsafe.Pointer(&stackBuf)) 16 hdr.Data = rbp 17 setSliceLimits(hdr, top-rbp) 18 } 19 return stackBuf 20 } 21 22 // UnwindStack implements wazevo.unwindStack. 23 func UnwindStack(_, rbp, top uintptr, returnAddresses []uintptr) []uintptr { 24 stackBuf := stackView(rbp, top) 25 26 for i := uint64(0); i < uint64(len(stackBuf)); { 27 // (high address) 28 // +-----------------+ 29 // | ....... | 30 // | ret Y | 31 // | ....... | 32 // | ret 0 | 33 // | arg X | 34 // | ....... | 35 // | arg 1 | 36 // | arg 0 | 37 // | ReturnAddress | 38 // | Caller_RBP | 39 // +-----------------+ <---- Caller_RBP 40 // | ........... | 41 // | clobbered M | 42 // | ............ | 43 // | clobbered 0 | 44 // | spill slot N | 45 // | ............ | 46 // | spill slot 0 | 47 // | ReturnAddress | 48 // | Caller_RBP | 49 // +-----------------+ <---- RBP 50 // (low address) 51 52 callerRBP := binary.LittleEndian.Uint64(stackBuf[i:]) 53 retAddr := binary.LittleEndian.Uint64(stackBuf[i+8:]) 54 returnAddresses = append(returnAddresses, uintptr(retAddr)) 55 i = callerRBP - uint64(rbp) 56 if len(returnAddresses) == wasmdebug.MaxFrames { 57 break 58 } 59 } 60 return returnAddresses 61 } 62 63 // GoCallStackView implements wazevo.goCallStackView. 64 func GoCallStackView(stackPointerBeforeGoCall *uint64) []uint64 { 65 // (high address) 66 // +-----------------+ <----+ 67 // | xxxxxxxxxxx | | ;; optional unused space to make it 16-byte aligned. 68 // ^ | arg[N]/ret[M] | | 69 // sliceSize | | ............ | | SizeInBytes/8 70 // | | arg[1]/ret[1] | | 71 // v | arg[0]/ret[0] | <----+ 72 // | SizeInBytes | 73 // +-----------------+ <---- stackPointerBeforeGoCall 74 // (low address) 75 data := unsafe.Pointer(uintptr(unsafe.Pointer(stackPointerBeforeGoCall)) + 8) 76 size := *stackPointerBeforeGoCall / 8 77 return unsafe.Slice((*uint64)(data), int(size)) 78 } 79 80 func AdjustClonedStack(oldRsp, oldTop, rsp, rbp, top uintptr) { 81 diff := uint64(rsp - oldRsp) 82 83 newBuf := stackView(rbp, top) 84 for i := uint64(0); i < uint64(len(newBuf)); { 85 // (high address) 86 // +-----------------+ 87 // | ....... | 88 // | ret Y | 89 // | ....... | 90 // | ret 0 | 91 // | arg X | 92 // | ....... | 93 // | arg 1 | 94 // | arg 0 | 95 // | ReturnAddress | 96 // | Caller_RBP | 97 // +-----------------+ <---- Caller_RBP 98 // | ........... | 99 // | clobbered M | 100 // | ............ | 101 // | clobbered 0 | 102 // | spill slot N | 103 // | ............ | 104 // | spill slot 0 | 105 // | ReturnAddress | 106 // | Caller_RBP | 107 // +-----------------+ <---- RBP 108 // (low address) 109 110 callerRBP := binary.LittleEndian.Uint64(newBuf[i:]) 111 if callerRBP == 0 { 112 // End of stack. 113 break 114 } 115 if i64 := int64(callerRBP); i64 < int64(oldRsp) || i64 >= int64(oldTop) { 116 panic("BUG: callerRBP is out of range") 117 } 118 if int(callerRBP) < 0 { 119 panic("BUG: callerRBP is negative") 120 } 121 adjustedCallerRBP := callerRBP + diff 122 if int(adjustedCallerRBP) < 0 { 123 panic("BUG: adjustedCallerRBP is negative") 124 } 125 binary.LittleEndian.PutUint64(newBuf[i:], adjustedCallerRBP) 126 i = adjustedCallerRBP - uint64(rbp) 127 } 128 }