github.com/wasilibs/wazerox@v0.0.0-20240124024944-4923be63ab5f/internal/engine/wazevo/backend/isa/arm64/unwind_stack_test.go (about)

     1  package arm64
     2  
     3  import (
     4  	"encoding/binary"
     5  	"testing"
     6  	"unsafe"
     7  
     8  	"github.com/wasilibs/wazerox/internal/testing/require"
     9  )
    10  
    11  func TestUnwindStack(t *testing.T) {
    12  	for _, tc := range []struct {
    13  		name     string
    14  		contents []uint64
    15  		exp      []uintptr
    16  	}{
    17  		{
    18  			name: "top / with frame and arg-ret-space",
    19  			contents: []uint64{
    20  				32,                 // Frame size: 16 byte-aligned.
    21  				0,                  // reserved.
    22  				0xffffffffffffffff, // in frame.
    23  				0xffffffffffffffff, // in frame.
    24  				0xffffffffffffffff, // in frame.
    25  				0xffffffffffffffff, // in frame.
    26  				0xaa,               // return address.
    27  				48,                 // size_of_arg_ret: 16-byte aligned.
    28  				0xeeeeeeeeeeeeeeee, // in arg-ret space.
    29  				0xeeeeeeeeeeeeeeee, // in arg-ret space.
    30  				0xeeeeeeeeeeeeeeee, // in arg-ret space.
    31  				0xeeeeeeeeeeeeeeee, // in arg-ret space.
    32  				0xeeeeeeeeeeeeeeee, // in arg-ret space.
    33  				0xeeeeeeeeeeeeeeee, // in arg-ret space.
    34  			},
    35  			exp: []uintptr{0xaa},
    36  		},
    37  		{
    38  			name: "top / without frame / with arg-ret-space",
    39  			contents: []uint64{
    40  				0,                  // Frame size: 16 byte-aligned.
    41  				0,                  // reserved.
    42  				0xaa,               // return address.
    43  				48,                 // size_of_arg_ret: 16-byte aligned.
    44  				0xeeeeeeeeeeeeeeee, // in arg-ret space.
    45  				0xeeeeeeeeeeeeeeee, // in arg-ret space.
    46  				0xeeeeeeeeeeeeeeee, // in arg-ret space.
    47  				0xeeeeeeeeeeeeeeee, // in arg-ret space.
    48  				0xeeeeeeeeeeeeeeee, // in arg-ret space.
    49  				0xeeeeeeeeeeeeeeee, // in arg-ret space.
    50  			},
    51  			exp: []uintptr{0xaa},
    52  		},
    53  		{
    54  			name: "top / without frame and arg-ret-space",
    55  			contents: []uint64{
    56  				0,    // Frame size: 16 byte-aligned.
    57  				0,    // reserved.
    58  				0xaa, // return address.
    59  				0,    // size_of_arg_ret: 16-byte aligned.
    60  			},
    61  			exp: []uintptr{0xaa},
    62  		},
    63  		{
    64  			name: "three frames",
    65  			contents: []uint64{
    66  				// ------------ first frame -------------
    67  				32,                 // Frame size: 16 byte-aligned.
    68  				0,                  // reserved.
    69  				0xffffffffffffffff, // in frame.
    70  				0xffffffffffffffff, // in frame.
    71  				0xffffffffffffffff, // in frame.
    72  				0xffffffffffffffff, // in frame.
    73  				0xaa,               // return address.
    74  				48,                 // size_of_arg_ret: 16-byte aligned.
    75  				0xeeeeeeeeeeeeeeee, // in arg-ret space.
    76  				0xeeeeeeeeeeeeeeee, // in arg-ret space.
    77  				0xeeeeeeeeeeeeeeee, // in arg-ret space.
    78  				0xeeeeeeeeeeeeeeee, // in arg-ret space.
    79  				0xeeeeeeeeeeeeeeee, // in arg-ret space.
    80  				0xeeeeeeeeeeeeeeee, // in arg-ret space.
    81  				// ------------ second frame -----------------
    82  				0,                  // Frame size: 16 byte-aligned.
    83  				0,                  // reserved.
    84  				0xbb,               // return address.
    85  				48,                 // size_of_arg_ret: 16-byte aligned.
    86  				0xeeeeeeeeeeeeeeee, // in arg-ret space.
    87  				0xeeeeeeeeeeeeeeee, // in arg-ret space.
    88  				0xeeeeeeeeeeeeeeee, // in arg-ret space.
    89  				0xeeeeeeeeeeeeeeee, // in arg-ret space.
    90  				0xeeeeeeeeeeeeeeee, // in arg-ret space.
    91  				0xeeeeeeeeeeeeeeee, // in arg-ret space.
    92  				// ------------ third frame -----------------
    93  				0,    // Frame size: 16 byte-aligned.
    94  				0,    // reserved.
    95  				0xcc, // return address.
    96  				0,    // size_of_arg_ret: 16-byte aligned.
    97  			},
    98  			exp: []uintptr{0xaa, 0xbb, 0xcc},
    99  		},
   100  	} {
   101  		tc := tc
   102  		t.Run(tc.name, func(t *testing.T) {
   103  			buf := make([]byte, len(tc.contents)*8+1)
   104  			for i, v := range tc.contents {
   105  				binary.LittleEndian.PutUint64(buf[i*8:], v)
   106  			}
   107  			sp := uintptr(unsafe.Pointer(&buf[0]))
   108  			returnAddresses := UnwindStack(sp, uintptr(unsafe.Pointer(&buf[len(buf)-1])), nil)
   109  			require.Equal(t, tc.exp, returnAddresses)
   110  		})
   111  	}
   112  }