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