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