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