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