summaryrefslogtreecommitdiff
path: root/tests/Gx64-test-dwarf-expressions.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/Gx64-test-dwarf-expressions.c')
-rw-r--r--tests/Gx64-test-dwarf-expressions.c68
1 files changed, 68 insertions, 0 deletions
diff --git a/tests/Gx64-test-dwarf-expressions.c b/tests/Gx64-test-dwarf-expressions.c
new file mode 100644
index 00000000..209f8713
--- /dev/null
+++ b/tests/Gx64-test-dwarf-expressions.c
@@ -0,0 +1,68 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <libunwind.h>
+
+static int verbose;
+static int nerrors;
+
+#define panic(args...) \
+ do { printf (args); ++nerrors; } while (0)
+
+// Assembly routine which sets up the stack for the test then calls another one
+// which clobbers the stack, and which in turn calls recover_register below
+extern int64_t DW_CFA_expression_testcase(int64_t regnum, int64_t height);
+
+// recover_register is called by the assembly routines. It returns the value of
+// a register at a specified height from the inner-most frame. The return value
+// is propagated back through the assembly routines to the testcase.
+extern int64_t recover_register(int64_t regnum, int64_t height)
+{
+ // Initialize cursor to current frame
+ int rc, i;
+ unw_cursor_t cursor;
+ unw_context_t context;
+ unw_getcontext(&context);
+ unw_init_local(&cursor, &context);
+ // Unwind frames until required height from inner-most frame (i.e. this one)
+ for (i = 0; i < height; ++i)
+ {
+ rc = unw_step(&cursor);
+ if (rc < 0)
+ panic("%s: unw_step failed on step %d with return code %d", __FUNCTION__, i, rc);
+ else if (rc == 0)
+ panic("%s: unw_step failed to reach the end of the stack", __FUNCTION__);
+ unw_word_t pc;
+ rc = unw_get_reg(&cursor, UNW_REG_IP, &pc);
+ if (rc < 0 || pc == 0)
+ panic("%s: unw_get_reg failed to locate the program counter", __FUNCTION__);
+ }
+ // We're now at the required height, extract register
+ uint64_t value;
+ if ((rc = unw_get_reg(&cursor, (unw_regnum_t) regnum, &value)) != 0)
+ panic("%s: unw_get_reg failed to retrieve register %lu", __FUNCTION__, regnum);
+ return value;
+}
+
+int
+main (int argc, char **argv)
+{
+ if (argc > 1)
+ verbose = 1;
+
+ if (DW_CFA_expression_testcase(12, 1) != 0)
+ panic("r12 should be clobbered at height 1 (DW_CFA_expression_inner)");
+ if (DW_CFA_expression_testcase(12, 2) != 111222333)
+ panic("r12 should be restored at height 2 (DW_CFA_expression_testcase)");
+
+ if (nerrors > 0)
+ {
+ fprintf (stderr, "FAILURE: detected %d errors\n", nerrors);
+ exit (-1);
+ }
+
+ if (verbose)
+ printf ("SUCCESS.\n");
+ return 0;
+}