1 // TODO: Investigate these failures on x86_64 macOS back deployment
2 // UNSUPPORTED: target=x86_64-apple-darwin{{.+}}
3 
4 #include <libunwind.h>
5 #include <stdlib.h>
6 #include <string.h>
7 
8 void backtrace(int lower_bound) {
9   unw_context_t context;
10   unw_getcontext(&context);
11 
12   unw_cursor_t cursor;
13   unw_init_local(&cursor, &context);
14 
15   int n = 0;
16   do {
17     ++n;
18     if (n > 100) {
19       abort();
20     }
21   } while (unw_step(&cursor) > 0);
22 
23   if (n < lower_bound) {
24     abort();
25   }
26 }
27 
28 void test1(int i) {
29   backtrace(i);
30 }
31 
32 void test2(int i, int j) {
33   backtrace(i);
34   test1(j);
35 }
36 
37 void test3(int i, int j, int k) {
38   backtrace(i);
39   test2(j, k);
40 }
41 
42 void test_no_info() {
43   unw_context_t context;
44   unw_getcontext(&context);
45 
46   unw_cursor_t cursor;
47   unw_init_local(&cursor, &context);
48 
49   unw_proc_info_t info;
50   int ret = unw_get_proc_info(&cursor, &info);
51   if (ret != UNW_ESUCCESS)
52     abort();
53 
54   // Set the IP to an address clearly outside any function.
55   unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)0);
56 
57   ret = unw_get_proc_info(&cursor, &info);
58   if (ret != UNW_ENOINFO)
59     abort();
60 }
61 
62 void test_reg_names() {
63   unw_context_t context;
64   unw_getcontext(&context);
65 
66   unw_cursor_t cursor;
67   unw_init_local(&cursor, &context);
68 
69   int max_reg_num = -100;
70 #if defined(__i386__)
71   max_reg_num = 7;
72 #elif defined(__x86_64__)
73   max_reg_num = 32;
74 #endif
75 
76   const char prefix[] = "unknown";
77   for (int i = -2; i < max_reg_num; ++i) {
78     if (strncmp(prefix, unw_regname(&cursor, i), sizeof(prefix) - 1) == 0)
79       abort();
80   }
81 
82   if (strncmp(prefix, unw_regname(&cursor, max_reg_num + 1),
83               sizeof(prefix) - 1) != 0)
84     abort();
85 }
86 
87 #if defined(__x86_64__)
88 void test_reg_get_set() {
89   unw_context_t context;
90   unw_getcontext(&context);
91 
92   unw_cursor_t cursor;
93   unw_init_local(&cursor, &context);
94 
95   for (int i = 0; i < 17; ++i) {
96     const unw_word_t set_value = 7;
97     if (unw_set_reg(&cursor, i, set_value) != UNW_ESUCCESS)
98       abort();
99 
100     unw_word_t get_value = 0;
101     if (unw_get_reg(&cursor, i, &get_value) != UNW_ESUCCESS)
102       abort();
103 
104     if (set_value != get_value)
105       abort();
106   }
107 }
108 
109 void test_fpreg_get_set() {
110   unw_context_t context;
111   unw_getcontext(&context);
112 
113   unw_cursor_t cursor;
114   unw_init_local(&cursor, &context);
115 
116   // get/set is not implemented for x86_64 fpregs.
117   for (int i = 17; i < 33; ++i) {
118     const unw_fpreg_t set_value = 7;
119     if (unw_set_fpreg(&cursor, i, set_value) != UNW_EBADREG)
120       abort();
121 
122     unw_fpreg_t get_value = 0;
123     if (unw_get_fpreg(&cursor, i, &get_value) != UNW_EBADREG)
124       abort();
125   }
126 }
127 #else
128 void test_reg_get_set() {}
129 void test_fpreg_get_set() {}
130 #endif
131 
132 int main(int, char**) {
133   test1(1);
134   test2(1, 2);
135   test3(1, 2, 3);
136   test_no_info();
137   test_reg_names();
138   test_reg_get_set();
139   test_fpreg_get_set();
140   return 0;
141 }
142