github.com/tetratelabs/wazero@v1.7.3-0.20240513003603-48f702e154b5/internal/engine/wazevo/backend/isa/amd64/stack_test.go (about) 1 package amd64 2 3 import ( 4 "encoding/binary" 5 "testing" 6 "unsafe" 7 8 "github.com/tetratelabs/wazero/internal/testing/require" 9 ) 10 11 func TestUnwindStack(t *testing.T) { 12 for _, tc := range []struct { 13 name string 14 setup func() (stack []byte, exp []uintptr) 15 }{ 16 {name: "no frame", setup: func() (_ []byte, exp []uintptr) { return []byte{0}, exp }}, 17 {name: "three", setup: func() ([]byte, []uintptr) { 18 exp := []uintptr{0xffffffff_00000000, 0xffffffff_00000001, 0xffffffff_00000002} 19 stack := make([]byte, 240) 20 bp := uintptr(unsafe.Pointer(&stack[0])) 21 oldRBP1 := bp + 32 22 binary.LittleEndian.PutUint64(stack[0:], uint64(oldRBP1)) // old bp 23 binary.LittleEndian.PutUint64(stack[8:], uint64(0xffffffff_00000000)) // return address 24 oldRBP2 := oldRBP1 + 16 25 binary.LittleEndian.PutUint64(stack[oldRBP1-bp:], uint64(oldRBP2)) // old bp 26 binary.LittleEndian.PutUint64(stack[oldRBP1-bp+8:], uint64(0xffffffff_00000001)) // return address 27 binary.LittleEndian.PutUint64(stack[oldRBP2-bp:], uint64(0)) // old bp 28 binary.LittleEndian.PutUint64(stack[oldRBP2-bp+8:], uint64(0xffffffff_00000002)) // return address 29 return stack, exp 30 }}, 31 } { 32 tc := tc 33 t.Run(tc.name, func(t *testing.T) { 34 stack, exp := tc.setup() 35 bp := uintptr(unsafe.Pointer(&stack[0])) 36 returnAddresses := UnwindStack(0, bp, uintptr(unsafe.Pointer(&stack[len(stack)-1])), nil) 37 require.Equal(t, exp, returnAddresses) 38 }) 39 } 40 } 41 42 func addressOf(v *byte) uint64 { 43 return uint64(uintptr(unsafe.Pointer(v))) 44 } 45 46 func TestAdjustClonedStack(t *testing.T) { 47 // In order to allocate slices on Go heap, we need to allocSlice function. 48 allocSlice := func(size int) []byte { 49 return make([]byte, size) 50 } 51 52 oldStack := allocSlice(512) 53 oldRsp := uintptr(unsafe.Pointer(&oldStack[0])) 54 oldTop := uintptr(unsafe.Pointer(&oldStack[len(oldStack)-1])) 55 rbpIndex := uintptr(32) 56 binary.LittleEndian.PutUint64(oldStack[rbpIndex:], addressOf(&oldStack[16+rbpIndex])) 57 binary.LittleEndian.PutUint64(oldStack[rbpIndex+16:], addressOf(&oldStack[32+rbpIndex])) 58 binary.LittleEndian.PutUint64(oldStack[rbpIndex+32:], addressOf(&oldStack[160+rbpIndex])) 59 60 newStack := allocSlice(1024) 61 rsp := uintptr(unsafe.Pointer(&newStack[0])) 62 rbp := rsp + rbpIndex 63 // Coy old stack to new stack which contains the old pointers to the old stack elements. 64 copy(newStack, oldStack) 65 66 AdjustClonedStack(oldRsp, oldTop, rsp, rbp, uintptr(addressOf(&newStack[len(newStack)-1]))) 67 require.Equal(t, addressOf(&newStack[rbpIndex+16]), binary.LittleEndian.Uint64(newStack[rbpIndex:])) 68 require.Equal(t, addressOf(&newStack[rbpIndex+32]), binary.LittleEndian.Uint64(newStack[rbpIndex+16:])) 69 require.Equal(t, addressOf(&newStack[rbpIndex+160]), binary.LittleEndian.Uint64(newStack[rbpIndex+32:])) 70 }