[PATCH] ntdll: Fix more corner cases for arm64 packed info unwinding

Martin Storsjo martin at martin.st
Mon Sep 7 05:14:57 CDT 2020


Make sure to restore sp from fp for CR == 3.

Fix unwinding of partial prologues/epilogues - the previous logic
had an off-by-one for the pos/skip handling; fix a few more
corner cases with odd number of saved registers.

Functions with the H flag set (saving x0-x7 on the stack) should
be considred having 4 nops (for the instructions saving the
registers) in the prologue for unwind purposes. When unwinding
through a partial epilogue, the same 4 nops should also be
considered to be there (even though no sane epilogue would restore
the registers there) based on how windows handles partial epilogue
unwinding in those cases.

Uncomment prologue/epilogue cases in an existing test and add
tests for many more cases.

Signed-off-by: Martin Storsjo <martin at martin.st>
---
 dlls/ntdll/signal_arm64.c    |  41 +++--
 dlls/ntdll/tests/exception.c | 322 ++++++++++++++++++++++++++++++++++-
 2 files changed, 340 insertions(+), 23 deletions(-)

diff --git a/dlls/ntdll/signal_arm64.c b/dlls/ntdll/signal_arm64.c
index df656d90f22..7100da33d54 100644
--- a/dlls/ntdll/signal_arm64.c
+++ b/dlls/ntdll/signal_arm64.c
@@ -708,6 +708,7 @@ static void *unwind_packed_data( ULONG_PTR base, ULONG_PTR pc, RUNTIME_FUNCTION
             switch (func->u.s.CR)
             {
             case 3:
+                len++; /* mov x29,sp */
                 len++; /* stp x29,lr,[sp,0] */
                 if (local_size <= 512) break;
                 /* fall through */
@@ -717,9 +718,10 @@ static void *unwind_packed_data( ULONG_PTR base, ULONG_PTR pc, RUNTIME_FUNCTION
                 if (local_size > 4088) len++;  /* sub sp,sp,#4088 */
                 break;
             }
-            if (offset < len + 4 * func->u.s.H)  /* prolog */
+            len += 4 * func->u.s.H;
+            if (offset < len)  /* prolog */
             {
-                skip = len + 4 * func->u.s.H - offset;
+                skip = len - offset;
             }
             else if (offset >= func->u.s.FunctionLength - (len + 1))  /* epilog */
             {
@@ -733,6 +735,7 @@ static void *unwind_packed_data( ULONG_PTR base, ULONG_PTR pc, RUNTIME_FUNCTION
         if (func->u.s.CR == 3)
         {
             DWORD64 *fp = (DWORD64 *) context->u.s.Fp; /* u.X[29] */
+            context->Sp = context->u.s.Fp;
             context->u.X[29] = fp[0];
             context->u.X[30] = fp[1];
         }
@@ -748,34 +751,36 @@ static void *unwind_packed_data( ULONG_PTR base, ULONG_PTR pc, RUNTIME_FUNCTION
         switch (func->u.s.CR)
         {
         case 3:
+            /* mov x29,sp */
+            if (pos++ >= skip) context->Sp = context->u.s.Fp;
             if (local_size <= 512)
             {
                 /* stp x29,lr,[sp,-#local_size]! */
-                if (pos++ > skip) restore_regs( 29, 2, -local_size_regs, context, ptrs );
+                if (pos++ >= skip) restore_regs( 29, 2, -local_size_regs, context, ptrs );
                 break;
             }
             /* stp x29,lr,[sp,0] */
-            if (pos++ > skip) restore_regs( 29, 2, 0, context, ptrs );
+            if (pos++ >= skip) restore_regs( 29, 2, 0, context, ptrs );
             /* fall through */
         case 0:
         case 1:
             if (!local_size) break;
             /* sub sp,sp,#local_size */
-            if (pos++ > skip) context->Sp += (local_size - 1) % 4088 + 1;
-            if (local_size > 4088 && pos++ > skip) context->Sp += 4088;
+            if (pos++ >= skip) context->Sp += (local_size - 1) % 4088 + 1;
+            if (local_size > 4088 && pos++ >= skip) context->Sp += 4088;
             break;
         }
 
-        if (func->u.s.H && offset < len + 4) pos += 4;
+        if (func->u.s.H) pos += 4;
 
         if (fp_size)
         {
-            if (func->u.s.RegF % 2 == 0 && pos++ > skip)
+            if (func->u.s.RegF % 2 == 0 && pos++ >= skip)
                 /* str d%u,[sp,#fp_size] */
                 restore_fpregs( 8 + func->u.s.RegF, 1, int_regs + fp_regs - 1, context, ptrs );
-            for (i = func->u.s.RegF / 2 - 1; i >= 0; i--)
+            for (i = (func->u.s.RegF + 1) / 2 - 1; i >= 0; i--)
             {
-                if (pos++ <= skip) continue;
+                if (pos++ < skip) continue;
                 if (!i && !int_size)
                      /* stp d8,d9,[sp,-#regsave]! */
                     restore_fpregs( 8, 2, -saved_regs, context, ptrs );
@@ -785,9 +790,9 @@ static void *unwind_packed_data( ULONG_PTR base, ULONG_PTR pc, RUNTIME_FUNCTION
             }
         }
 
-        if (pos++ > skip)
+        if (func->u.s.RegI % 2)
         {
-            if (func->u.s.RegI % 2)
+            if (pos++ >= skip)
             {
                 /* stp xn,lr,[sp,#offset] */
                 if (func->u.s.CR == 1) restore_regs( 30, 1, int_regs - 1, context, ptrs );
@@ -796,14 +801,16 @@ static void *unwind_packed_data( ULONG_PTR base, ULONG_PTR pc, RUNTIME_FUNCTION
                               (func->u.s.RegI > 1) ? func->u.s.RegI - 1 : -saved_regs,
                               context, ptrs );
             }
-            else if (func->u.s.CR == 1)
-                /* str lr,[sp,#offset] */
-                restore_regs( 30, 1, func->u.s.RegI ? int_regs - 1 : -saved_regs, context, ptrs );
+        }
+        else if (func->u.s.CR == 1)
+        {
+            /* str lr,[sp,#offset] */
+            if (pos++ >= skip) restore_regs( 30, 1, func->u.s.RegI ? int_regs - 1 : -saved_regs, context, ptrs );
         }
 
-        for (i = func->u.s.RegI / 2 - 1; i >= 0; i--)
+        for (i = func->u.s.RegI/ 2 - 1; i >= 0; i--)
         {
-            if (pos++ <= skip) continue;
+            if (pos++ < skip) continue;
             if (i)
                 /* stp xn,xn+1,[sp,#offset] */
                 restore_regs( 19 + 2 * i, 2, 2 * i, context, ptrs );
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c
index 06c4386a881..465c123e675 100644
--- a/dlls/ntdll/tests/exception.c
+++ b/dlls/ntdll/tests/exception.c
@@ -4572,23 +4572,17 @@ static void test_virtual_unwind(void)
 
     static const BYTE unwind_info_1[] = { DW(unwind_info_1_packed) };
 
-    /* The prologue/epilogue locations are commented out below, as we don't
-     * handle those cases at the moment. */
     static const struct results results_1[] =
     {
       /* offset  fp    handler  pc      frame offset  registers */
-#if 0
         { 0x00,  0x00,  0,     ORIG_LR, 0x000, TRUE, { {-1,-1} }},
         { 0x04,  0x00,  0,     ORIG_LR, 0x020, TRUE, { {x19,0x00}, {x20,0x08}, {-1,-1} }},
         { 0x08,  0x00,  0,     0x10,    0x020, TRUE, { {x19,0x00}, {x20,0x08}, {lr,0x10}, {-1,-1} }},
-#endif
         { 0x0c,  0x00,  0,     0x20,    0x030, TRUE, { {x19,0x10}, {x20,0x18}, {lr,0x20}, {-1,-1} }},
         { 0x10,  0x00,  0,     0x20,    0x030, TRUE, { {x19,0x10}, {x20,0x18}, {lr,0x20}, {-1,-1} }},
-#if 0
         { 0x14,  0x00,  0,     0x10,    0x020, TRUE, { {x19,0x00}, {x20,0x08}, {lr,0x10}, {-1,-1} }},
         { 0x18,  0x00,  0,     ORIG_LR, 0x020, TRUE, { {x19,0x00}, {x20,0x08}, {-1,-1} }},
         { 0x1c,  0x00,  0,     ORIG_LR, 0x000, TRUE, { {-1,-1} }},
-#endif
     };
 
     static const BYTE function_2[] =
@@ -4808,6 +4802,314 @@ static void test_virtual_unwind(void)
 #endif
     };
 
+    static const BYTE function_6[] =
+    {
+        0xf3, 0x53, 0xbd, 0xa9,   /* 00: stp x19, x20, [sp, #-48]! */
+        0xf5, 0x0b, 0x00, 0xf9,   /* 04: str x21,      [sp, #16] */
+        0xe8, 0xa7, 0x01, 0x6d,   /* 08: stp d8,  d9,  [sp, #24] */
+        0xea, 0x17, 0x00, 0xfd,   /* 0c: str d10,      [sp, #40] */
+        0xff, 0x03, 0x00, 0xd1,   /* 10: sub sp,  sp,  #0 */
+        0x1f, 0x20, 0x03, 0xd5,   /* 14: nop */
+        0xff, 0x03, 0x00, 0x91,   /* 18: add sp,  sp,  #0 */
+        0xea, 0x17, 0x40, 0xfd,   /* 1c: ldr d10,      [sp, #40] */
+        0xe8, 0xa7, 0x41, 0x6d,   /* 20: ldp d8,  d9,  [sp, #24] */
+        0xf5, 0x0b, 0x40, 0xf9,   /* 24: ldr x21,      [sp, #16] */
+        0xf3, 0x53, 0xc3, 0xa8,   /* 28: ldp x19, x20, [sp], #48 */
+        0xc0, 0x03, 0x5f, 0xd6,   /* 2c: ret */
+    };
+
+    static const DWORD unwind_info_6_packed =
+        (1 << 0)  | /* Flag */
+        (sizeof(function_6)/4 << 2) | /* FunctionLength */
+        (2 << 13) | /* RegF */
+        (3 << 16) | /* RegI */
+        (0 << 20) | /* H */
+        (0 << 21) | /* CR */
+        (3 << 23);  /* FrameSize */
+
+    static const BYTE unwind_info_6[] = { DW(unwind_info_6_packed) };
+
+    static const struct results results_6[] =
+    {
+      /* offset  fp    handler  pc      frame offset  registers */
+        { 0x00,  0x00,  0,     ORIG_LR, 0x000, TRUE, { {-1,-1} }},
+        { 0x04,  0x00,  0,     ORIG_LR, 0x030, TRUE, { {x19,0x00}, {x20,0x08}, {-1,-1} }},
+        { 0x08,  0x00,  0,     ORIG_LR, 0x030, TRUE, { {x19,0x00}, {x20,0x08}, {x21, 0x10}, {-1,-1} }},
+        { 0x0c,  0x00,  0,     ORIG_LR, 0x030, TRUE, { {x19,0x00}, {x20,0x08}, {x21, 0x10}, {d8, 0x18}, {d9, 0x20}, {-1,-1} }},
+        { 0x10,  0x00,  0,     ORIG_LR, 0x030, TRUE, { {x19,0x00}, {x20,0x08}, {x21, 0x10}, {d8, 0x18}, {d9, 0x20}, {d10, 0x28}, {-1,-1} }},
+        { 0x14,  0x00,  0,     ORIG_LR, 0x030, TRUE, { {x19,0x00}, {x20,0x08}, {x21, 0x10}, {d8, 0x18}, {d9, 0x20}, {d10, 0x28}, {-1,-1} }},
+        { 0x18,  0x00,  0,     ORIG_LR, 0x030, TRUE, { {x19,0x00}, {x20,0x08}, {x21, 0x10}, {d8, 0x18}, {d9, 0x20}, {d10, 0x28}, {-1,-1} }},
+        { 0x1c,  0x00,  0,     ORIG_LR, 0x030, TRUE, { {x19,0x00}, {x20,0x08}, {x21, 0x10}, {d8, 0x18}, {d9, 0x20}, {d10, 0x28}, {-1,-1} }},
+        { 0x20,  0x00,  0,     ORIG_LR, 0x030, TRUE, { {x19,0x00}, {x20,0x08}, {x21, 0x10}, {d8, 0x18}, {d9, 0x20}, {-1,-1} }},
+        { 0x24,  0x00,  0,     ORIG_LR, 0x030, TRUE, { {x19,0x00}, {x20,0x08}, {x21, 0x10}, {-1,-1} }},
+        { 0x28,  0x00,  0,     ORIG_LR, 0x030, TRUE, { {x19,0x00}, {x20,0x08}, {-1,-1} }},
+        { 0x2c,  0x00,  0,     ORIG_LR, 0x000, TRUE, { {-1,-1} }},
+    };
+
+    static const BYTE function_7[] =
+    {
+        0xf3, 0x0f, 0x1d, 0xf8,   /* 00: str x19,      [sp, #-48]! */
+        0xe8, 0xa7, 0x00, 0x6d,   /* 04: stp d8,  d9,  [sp, #8] */
+        0xea, 0xaf, 0x01, 0x6d,   /* 08: stp d10, d11, [sp, #24] */
+        0xff, 0x03, 0x00, 0xd1,   /* 0c: sub sp,  sp,  #0 */
+        0x1f, 0x20, 0x03, 0xd5,   /* 10: nop */
+        0xff, 0x03, 0x00, 0x91,   /* 14: add sp,  sp,  #0 */
+        0xea, 0xaf, 0x41, 0x6d,   /* 18: ldp d10, d11, [sp, #24] */
+        0xe8, 0xa7, 0x40, 0x6d,   /* 1c: ldp d8,  d9,  [sp, #8] */
+        0xf3, 0x07, 0x43, 0xf8,   /* 20: ldr x19,      [sp], #48 */
+        0xc0, 0x03, 0x5f, 0xd6,   /* 24: ret */
+    };
+
+    static const DWORD unwind_info_7_packed =
+        (1 << 0)  | /* Flag */
+        (sizeof(function_7)/4 << 2) | /* FunctionLength */
+        (3 << 13) | /* RegF */
+        (1 << 16) | /* RegI */
+        (0 << 20) | /* H */
+        (0 << 21) | /* CR */
+        (3 << 23);  /* FrameSize */
+
+    static const BYTE unwind_info_7[] = { DW(unwind_info_7_packed) };
+
+    static const struct results results_7[] =
+    {
+      /* offset  fp    handler  pc      frame offset  registers */
+        { 0x00,  0x00,  0,     ORIG_LR, 0x000, TRUE, { {-1,-1} }},
+        { 0x04,  0x00,  0,     ORIG_LR, 0x030, TRUE, { {x19, 0x00}, {-1,-1} }},
+        { 0x08,  0x00,  0,     ORIG_LR, 0x030, TRUE, { {x19, 0x00}, {d8, 0x08}, {d9, 0x10}, {-1,-1} }},
+        { 0x0c,  0x00,  0,     ORIG_LR, 0x030, TRUE, { {x19, 0x00}, {d8, 0x08}, {d9, 0x10}, {d10, 0x18}, {d11, 0x20}, {-1,-1} }},
+        { 0x10,  0x00,  0,     ORIG_LR, 0x030, TRUE, { {x19, 0x00}, {d8, 0x08}, {d9, 0x10}, {d10, 0x18}, {d11, 0x20}, {-1,-1} }},
+        { 0x14,  0x00,  0,     ORIG_LR, 0x030, TRUE, { {x19, 0x00}, {d8, 0x08}, {d9, 0x10}, {d10, 0x18}, {d11, 0x20}, {-1,-1} }},
+        { 0x18,  0x00,  0,     ORIG_LR, 0x030, TRUE, { {x19, 0x00}, {d8, 0x08}, {d9, 0x10}, {d10, 0x18}, {d11, 0x20}, {-1,-1} }},
+        { 0x1c,  0x00,  0,     ORIG_LR, 0x030, TRUE, { {x19, 0x00}, {d8, 0x08}, {d9, 0x10}, {-1,-1} }},
+        { 0x20,  0x00,  0,     ORIG_LR, 0x030, TRUE, { {x19, 0x00}, {-1,-1} }},
+        { 0x24,  0x00,  0,     ORIG_LR, 0x000, TRUE, { {-1,-1} }},
+    };
+
+    static const BYTE function_8[] =
+    {
+        0xe8, 0x27, 0xbf, 0x6d,   /* 00: stp d8,  d9,  [sp, #-16]! */
+        0xff, 0x83, 0x00, 0xd1,   /* 04: sub sp,  sp,  #32 */
+        0x1f, 0x20, 0x03, 0xd5,   /* 08: nop */
+        0xff, 0x83, 0x00, 0x91,   /* 0c: add sp,  sp,  #32 */
+        0xe8, 0x27, 0xc1, 0x6c,   /* 10: ldp d8,  d9,  [sp], #16 */
+        0xc0, 0x03, 0x5f, 0xd6,   /* 14: ret */
+    };
+
+    static const DWORD unwind_info_8_packed =
+        (1 << 0)  | /* Flag */
+        (sizeof(function_8)/4 << 2) | /* FunctionLength */
+        (1 << 13) | /* RegF */
+        (0 << 16) | /* RegI */
+        (0 << 20) | /* H */
+        (0 << 21) | /* CR */
+        (3 << 23);  /* FrameSize */
+
+    static const BYTE unwind_info_8[] = { DW(unwind_info_8_packed) };
+
+    static const struct results results_8[] =
+    {
+      /* offset  fp    handler  pc      frame offset  registers */
+        { 0x00,  0x00,  0,     ORIG_LR, 0x000, TRUE, { {-1,-1} }},
+        { 0x04,  0x00,  0,     ORIG_LR, 0x010, TRUE, { {d8, 0x00}, {d9, 0x08}, {-1,-1} }},
+        { 0x08,  0x00,  0,     ORIG_LR, 0x030, TRUE, { {d8, 0x20}, {d9, 0x28}, {-1,-1} }},
+        { 0x0c,  0x00,  0,     ORIG_LR, 0x030, TRUE, { {d8, 0x20}, {d9, 0x28}, {-1,-1} }},
+        { 0x10,  0x00,  0,     ORIG_LR, 0x010, TRUE, { {d8, 0x00}, {d9, 0x08}, {-1,-1} }},
+        { 0x14,  0x00,  0,     ORIG_LR, 0x000, TRUE, { {-1,-1} }},
+    };
+
+    static const BYTE function_9[] =
+    {
+        0xf3, 0x0f, 0x1b, 0xf8,   /* 00: str x19,      [sp, #-80]! */
+        0xe0, 0x87, 0x00, 0xa9,   /* 04: stp x0,  x1,  [sp, #8] */
+        0xe2, 0x8f, 0x01, 0xa9,   /* 08: stp x2,  x3,  [sp, #24] */
+        0xe4, 0x97, 0x02, 0xa9,   /* 0c: stp x4,  x5,  [sp, #40] */
+        0xe6, 0x9f, 0x03, 0xa9,   /* 10: stp x6,  x7,  [sp, #56] */
+        0xff, 0x83, 0x00, 0xd1,   /* 14: sub sp,  sp,  #32 */
+        0x1f, 0x20, 0x03, 0xd5,   /* 18: nop */
+        0xff, 0x83, 0x00, 0x91,   /* 1c: add sp,  sp,  #32 */
+        0x1f, 0x20, 0x03, 0xd5,   /* 20: nop */
+        0x1f, 0x20, 0x03, 0xd5,   /* 24: nop */
+        0x1f, 0x20, 0x03, 0xd5,   /* 28: nop */
+        0x1f, 0x20, 0x03, 0xd5,   /* 2c: nop */
+        0xf3, 0x0f, 0x1b, 0xf8,   /* 30: ldr x19,      [sp], #80 */
+        0xc0, 0x03, 0x5f, 0xd6,   /* 34: ret */
+    };
+
+    static const DWORD unwind_info_9_packed =
+        (1 << 0)  | /* Flag */
+        (sizeof(function_9)/4 << 2) | /* FunctionLength */
+        (0 << 13) | /* RegF */
+        (1 << 16) | /* RegI */
+        (1 << 20) | /* H */
+        (0 << 21) | /* CR */
+        (7 << 23);  /* FrameSize */
+
+    static const BYTE unwind_info_9[] = { DW(unwind_info_9_packed) };
+
+    static const struct results results_9[] =
+    {
+      /* offset  fp    handler  pc      frame offset  registers */
+        { 0x00,  0x00,  0,     ORIG_LR, 0x000, TRUE, { {-1,-1} }},
+        { 0x04,  0x00,  0,     ORIG_LR, 0x050, TRUE, { {x19, 0x00}, {-1,-1} }},
+        { 0x08,  0x00,  0,     ORIG_LR, 0x050, TRUE, { {x19, 0x00}, {-1,-1} }},
+        { 0x0c,  0x00,  0,     ORIG_LR, 0x050, TRUE, { {x19, 0x00}, {-1,-1} }},
+        { 0x10,  0x00,  0,     ORIG_LR, 0x050, TRUE, { {x19, 0x00}, {-1,-1} }},
+        { 0x14,  0x00,  0,     ORIG_LR, 0x050, TRUE, { {x19, 0x00}, {-1,-1} }},
+        { 0x18,  0x00,  0,     ORIG_LR, 0x070, TRUE, { {x19, 0x20}, {-1,-1} }},
+        { 0x1c,  0x00,  0,     ORIG_LR, 0x070, TRUE, { {x19, 0x20}, {-1,-1} }},
+        { 0x20,  0x00,  0,     ORIG_LR, 0x050, TRUE, { {x19, 0x00}, {-1,-1} }},
+        { 0x24,  0x00,  0,     ORIG_LR, 0x050, TRUE, { {x19, 0x00}, {-1,-1} }},
+        { 0x28,  0x00,  0,     ORIG_LR, 0x050, TRUE, { {x19, 0x00}, {-1,-1} }},
+        { 0x2c,  0x00,  0,     ORIG_LR, 0x050, TRUE, { {x19, 0x00}, {-1,-1} }},
+        { 0x30,  0x00,  0,     ORIG_LR, 0x050, TRUE, { {x19, 0x00}, {-1,-1} }},
+        { 0x34,  0x00,  0,     ORIG_LR, 0x000, TRUE, { {-1,-1} }},
+    };
+
+    static const BYTE function_10[] =
+    {
+        0xfe, 0x0f, 0x1f, 0xf8,   /* 00: str lr,       [sp, #-16]! */
+        0xff, 0x43, 0x00, 0xd1,   /* 04: sub sp,  sp,  #16 */
+        0x1f, 0x20, 0x03, 0xd5,   /* 08: nop */
+        0xff, 0x43, 0x00, 0x91,   /* 0c: add sp,  sp,  #16 */
+        0xfe, 0x07, 0x41, 0xf8,   /* 10: ldr lr,       [sp], #16 */
+        0xc0, 0x03, 0x5f, 0xd6,   /* 14: ret */
+    };
+
+    static const DWORD unwind_info_10_packed =
+        (1 << 0)  | /* Flag */
+        (sizeof(function_10)/4 << 2) | /* FunctionLength */
+        (0 << 13) | /* RegF */
+        (0 << 16) | /* RegI */
+        (0 << 20) | /* H */
+        (1 << 21) | /* CR */
+        (2 << 23);  /* FrameSize */
+
+    static const BYTE unwind_info_10[] = { DW(unwind_info_10_packed) };
+
+    static const struct results results_10[] =
+    {
+      /* offset  fp    handler  pc      frame offset  registers */
+        { 0x00,  0x00,  0,     ORIG_LR, 0x000, TRUE, { {-1,-1} }},
+        { 0x04,  0x00,  0,     0x00,    0x010, TRUE, { {lr, 0x00}, {-1,-1} }},
+        { 0x08,  0x00,  0,     0x10,    0x020, TRUE, { {lr, 0x10}, {-1,-1} }},
+        { 0x0c,  0x00,  0,     0x10,    0x020, TRUE, { {lr, 0x10}, {-1,-1} }},
+        { 0x10,  0x00,  0,     0x00,    0x010, TRUE, { {lr, 0x00}, {-1,-1} }},
+        { 0x14,  0x00,  0,     ORIG_LR, 0x000, TRUE, { {-1,-1} }},
+    };
+
+    static const BYTE function_11[] =
+    {
+        0xf3, 0x53, 0xbe, 0xa9,   /* 00: stp x19, x20, [sp, #-32]! */
+        0xf5, 0x7b, 0x01, 0xa9,   /* 04: stp x21, lr,  [sp, #16] */
+        0xff, 0x43, 0x00, 0xd1,   /* 08: sub sp,  sp,  #16 */
+        0x1f, 0x20, 0x03, 0xd5,   /* 0c: nop */
+        0xff, 0x43, 0x00, 0x91,   /* 10: add sp,  sp,  #16 */
+        0xf5, 0x7b, 0x41, 0xa9,   /* 14: ldp x21, lr,  [sp, #16] */
+        0xf3, 0x53, 0xc2, 0xa8,   /* 18: ldp x19, x20, [sp], #32 */
+        0xc0, 0x03, 0x5f, 0xd6,   /* 1c: ret */
+    };
+
+    static const DWORD unwind_info_11_packed =
+        (1 << 0)  | /* Flag */
+        (sizeof(function_11)/4 << 2) | /* FunctionLength */
+        (0 << 13) | /* RegF */
+        (3 << 16) | /* RegI */
+        (0 << 20) | /* H */
+        (1 << 21) | /* CR */
+        (3 << 23);  /* FrameSize */
+
+    static const BYTE unwind_info_11[] = { DW(unwind_info_11_packed) };
+
+    static const struct results results_11[] =
+    {
+      /* offset  fp    handler  pc      frame offset  registers */
+        { 0x00,  0x00,  0,     ORIG_LR, 0x000, TRUE, { {-1,-1} }},
+        { 0x04,  0x00,  0,     ORIG_LR, 0x020, TRUE, { {x19, 0x00}, {x20, 0x08}, {-1,-1} }},
+        { 0x08,  0x00,  0,     0x18,    0x020, TRUE, { {x19, 0x00}, {x20, 0x08}, {x21, 0x10}, {lr, 0x18}, {-1,-1} }},
+        { 0x0c,  0x00,  0,     0x28,    0x030, TRUE, { {x19, 0x10}, {x20, 0x18}, {x21, 0x20}, {lr, 0x28}, {-1,-1} }},
+        { 0x10,  0x00,  0,     0x28,    0x030, TRUE, { {x19, 0x10}, {x20, 0x18}, {x21, 0x20}, {lr, 0x28}, {-1,-1} }},
+        { 0x14,  0x00,  0,     0x18,    0x020, TRUE, { {x19, 0x00}, {x20, 0x08}, {x21, 0x10}, {lr, 0x18}, {-1,-1} }},
+        { 0x18,  0x00,  0,     ORIG_LR, 0x020, TRUE, { {x19, 0x00}, {x20, 0x08}, {-1,-1} }},
+        { 0x1c,  0x00,  0,     ORIG_LR, 0x000, TRUE, { {-1,-1} }},
+    };
+
+    static const BYTE function_12[] =
+    {
+        0xf3, 0x53, 0xbf, 0xa9,   /* 00: stp x19, x20, [sp, #-16]! */
+        0xfd, 0x7b, 0xbe, 0xa9,   /* 04: stp x29, lr,  [sp, #-32]! */
+        0xfd, 0x03, 0x00, 0x91,   /* 08: mov x29, sp */
+        0x1f, 0x20, 0x03, 0xd5,   /* 0c: nop */
+        0xbf, 0x03, 0x00, 0x91,   /* 10: mov sp,  x29 */
+        0xfd, 0x7b, 0xc2, 0xa8,   /* 14: ldp x29, lr,  [sp], #32 */
+        0xf3, 0x53, 0xc1, 0xa8,   /* 18: ldp x19, x20, [sp], #16 */
+        0xc0, 0x03, 0x5f, 0xd6,   /* 1c: ret */
+    };
+
+    static const DWORD unwind_info_12_packed =
+        (1 << 0)  | /* Flag */
+        (sizeof(function_12)/4 << 2) | /* FunctionLength */
+        (0 << 13) | /* RegF */
+        (2 << 16) | /* RegI */
+        (0 << 20) | /* H */
+        (3 << 21) | /* CR */
+        (3 << 23);  /* FrameSize */
+
+    static const BYTE unwind_info_12[] = { DW(unwind_info_12_packed) };
+
+    static const struct results results_12[] =
+    {
+      /* offset  fp    handler  pc      frame offset  registers */
+        { 0x00,  0x10,  0,     ORIG_LR, 0x000, TRUE, { {-1,-1} }},
+        { 0x04,  0x10,  0,     ORIG_LR, 0x010, TRUE, { {x19, 0x00}, {x20, 0x08}, {-1,-1} }},
+        { 0x08,  0x10,  0,     0x08,    0x030, TRUE, { {x19, 0x20}, {x20, 0x28}, {x29, 0x00}, {lr, 0x08}, {-1,-1} }},
+        { 0x0c,  0x10,  0,     0x18,    0x040, TRUE, { {x19, 0x30}, {x20, 0x38}, {x29, 0x10}, {lr, 0x18}, {-1,-1} }},
+        { 0x10,  0x10,  0,     0x18,    0x040, TRUE, { {x19, 0x30}, {x20, 0x38}, {x29, 0x10}, {lr, 0x18}, {-1,-1} }},
+        { 0x14,  0x10,  0,     0x08,    0x030, TRUE, { {x19, 0x20}, {x20, 0x28}, {x29, 0x00}, {lr, 0x08}, {-1,-1} }},
+        { 0x18,  0x10,  0,     ORIG_LR, 0x010, TRUE, { {x19, 0x00}, {x20, 0x08}, {-1,-1} }},
+        { 0x1c,  0x10,  0,     ORIG_LR, 0x000, TRUE, { {-1,-1} }},
+    };
+
+    static const BYTE function_13[] =
+    {
+        0xf3, 0x53, 0xbf, 0xa9,   /* 00: stp x19, x20, [sp, #-16]! */
+        0xff, 0x43, 0x08, 0xd1,   /* 04: sub sp,  sp,  #528 */
+        0xfd, 0x7b, 0x00, 0xd1,   /* 08: stp x29, lr,  [sp] */
+        0xfd, 0x03, 0x00, 0x91,   /* 0c: mov x29, sp */
+        0x1f, 0x20, 0x03, 0xd5,   /* 10: nop */
+        0xbf, 0x03, 0x00, 0x91,   /* 14: mov sp,  x29 */
+        0xfd, 0x7b, 0x40, 0xa9,   /* 18: ldp x29, lr,  [sp] */
+        0xff, 0x43, 0x08, 0x91,   /* 1c: add sp,  sp,  #528 */
+        0xf3, 0x53, 0xc1, 0xa8,   /* 20: ldp x19, x20, [sp], #16 */
+        0xc0, 0x03, 0x5f, 0xd6,   /* 24: ret */
+    };
+
+    static const DWORD unwind_info_13_packed =
+        (1 << 0)  | /* Flag */
+        (sizeof(function_13)/4 << 2) | /* FunctionLength */
+        (0 << 13) | /* RegF */
+        (2 << 16) | /* RegI */
+        (0 << 20) | /* H */
+        (3 << 21) | /* CR */
+        (34 << 23);  /* FrameSize */
+
+    static const BYTE unwind_info_13[] = { DW(unwind_info_13_packed) };
+
+    static const struct results results_13[] =
+    {
+      /* offset  fp    handler  pc      frame offset  registers */
+        { 0x00,  0x10,  0,     ORIG_LR, 0x000, TRUE, { {-1,-1} }},
+        { 0x04,  0x10,  0,     ORIG_LR, 0x010, TRUE, { {x19, 0x00}, {x20, 0x08}, {-1,-1} }},
+        { 0x08,  0x10,  0,     ORIG_LR, 0x220, TRUE, { {x19, 0x210}, {x20, 0x218}, {-1,-1} }},
+        { 0x0c,  0x10,  0,     0x08,    0x220, TRUE, { {x19, 0x210}, {x20, 0x218}, {x29, 0x00}, {lr, 0x08}, {-1,-1} }},
+        { 0x10,  0x10,  0,     0x18,    0x230, TRUE, { {x19, 0x220}, {x20, 0x228}, {x29, 0x10}, {lr, 0x18}, {-1,-1} }},
+        { 0x14,  0x10,  0,     0x18,    0x230, TRUE, { {x19, 0x220}, {x20, 0x228}, {x29, 0x10}, {lr, 0x18}, {-1,-1} }},
+        { 0x18,  0x10,  0,     0x08,    0x220, TRUE, { {x19, 0x210}, {x20, 0x218}, {x29, 0x00}, {lr, 0x08}, {-1,-1} }},
+        { 0x1c,  0x10,  0,     ORIG_LR, 0x220, TRUE, { {x19, 0x210}, {x20, 0x218}, {-1,-1} }},
+        { 0x20,  0x10,  0,     ORIG_LR, 0x010, TRUE, { {x19, 0x00}, {x20, 0x08}, {-1,-1} }},
+        { 0x24,  0x10,  0,     ORIG_LR, 0x000, TRUE, { {-1,-1} }},
+    };
+
     static const struct unwind_test tests[] =
     {
 #define TEST(func, unwind, unwind_packed, results) \
@@ -4818,6 +5120,14 @@ static void test_virtual_unwind(void)
         TEST(function_3, unwind_info_3, 0, results_3),
         TEST(function_4, unwind_info_4, 0, results_4),
         TEST(function_5, unwind_info_5, 0, results_5),
+        TEST(function_6, unwind_info_6, 1, results_6),
+        TEST(function_7, unwind_info_7, 1, results_7),
+        TEST(function_8, unwind_info_8, 1, results_8),
+        TEST(function_9, unwind_info_9, 1, results_9),
+        TEST(function_10, unwind_info_10, 1, results_10),
+        TEST(function_11, unwind_info_11, 1, results_11),
+        TEST(function_12, unwind_info_12, 1, results_12),
+        TEST(function_13, unwind_info_13, 1, results_13),
 #undef TEST
     };
     unsigned int i;
-- 
2.17.1




More information about the wine-devel mailing list