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