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 <stdio.h> 19 #include <string.h> 20 21 void backtrace(int lower_bound) { 22 unw_context_t context; 23 unw_getcontext(&context); 24 25 unw_cursor_t cursor; 26 unw_init_local(&cursor, &context); 27 28 char buffer[1024]; 29 unw_word_t offset = 0; 30 31 int n = 0; 32 do { 33 n++; 34 if (unw_get_proc_name(&cursor, buffer, sizeof(buffer), &offset) == 0) { 35 fprintf(stderr, "Frame %d: %s+%p\n", n, buffer, (void*)offset); 36 } else { 37 fprintf(stderr, "Frame %d: Could not get name for cursor\n", n); 38 } 39 if (n > 100) { 40 abort(); 41 } 42 } while (unw_step(&cursor) > 0); 43 44 if (n < lower_bound) { 45 abort(); 46 } 47 } 48 49 __attribute__((noinline)) void test1(int i) { 50 fprintf(stderr, "starting %s\n", __func__); 51 backtrace(i); 52 fprintf(stderr, "finished %s\n", __func__); // ensure return address is saved 53 } 54 55 __attribute__((noinline)) void test2(int i, int j) { 56 fprintf(stderr, "starting %s\n", __func__); 57 backtrace(i); 58 test1(j); 59 fprintf(stderr, "finished %s\n", __func__); // ensure return address is saved 60 } 61 62 __attribute__((noinline)) void test3(int i, int j, int k) { 63 fprintf(stderr, "starting %s\n", __func__); 64 backtrace(i); 65 test2(j, k); 66 fprintf(stderr, "finished %s\n", __func__); // ensure return address is saved 67 } 68 69 void test_no_info() { 70 unw_context_t context; 71 unw_getcontext(&context); 72 73 unw_cursor_t cursor; 74 unw_init_local(&cursor, &context); 75 76 unw_proc_info_t info; 77 int ret = unw_get_proc_info(&cursor, &info); 78 if (ret != UNW_ESUCCESS) 79 abort(); 80 81 // Set the IP to an address clearly outside any function. 82 unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)0); 83 84 ret = unw_get_proc_info(&cursor, &info); 85 if (ret != UNW_ENOINFO) 86 abort(); 87 } 88 89 void test_reg_names() { 90 unw_context_t context; 91 unw_getcontext(&context); 92 93 unw_cursor_t cursor; 94 unw_init_local(&cursor, &context); 95 96 int max_reg_num = -100; 97 #if defined(__i386__) 98 max_reg_num = 7; 99 #elif defined(__x86_64__) 100 max_reg_num = 32; 101 #endif 102 103 const char prefix[] = "unknown"; 104 for (int i = -2; i < max_reg_num; ++i) { 105 if (strncmp(prefix, unw_regname(&cursor, i), sizeof(prefix) - 1) == 0) 106 abort(); 107 } 108 109 if (strncmp(prefix, unw_regname(&cursor, max_reg_num + 1), 110 sizeof(prefix) - 1) != 0) 111 abort(); 112 } 113 114 #if defined(__x86_64__) 115 void test_reg_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 for (int i = 0; i < 17; ++i) { 123 const unw_word_t set_value = 7; 124 if (unw_set_reg(&cursor, i, set_value) != UNW_ESUCCESS) 125 abort(); 126 127 unw_word_t get_value = 0; 128 if (unw_get_reg(&cursor, i, &get_value) != UNW_ESUCCESS) 129 abort(); 130 131 if (set_value != get_value) 132 abort(); 133 } 134 } 135 136 void test_fpreg_get_set() { 137 unw_context_t context; 138 unw_getcontext(&context); 139 140 unw_cursor_t cursor; 141 unw_init_local(&cursor, &context); 142 143 // get/set is not implemented for x86_64 fpregs. 144 for (int i = 17; i < 33; ++i) { 145 const unw_fpreg_t set_value = 7; 146 if (unw_set_fpreg(&cursor, i, set_value) != UNW_EBADREG) 147 abort(); 148 149 unw_fpreg_t get_value = 0; 150 if (unw_get_fpreg(&cursor, i, &get_value) != UNW_EBADREG) 151 abort(); 152 } 153 } 154 #else 155 void test_reg_get_set() {} 156 void test_fpreg_get_set() {} 157 #endif 158 159 int main(int, char**) { 160 test1(3); 161 test2(3, 4); 162 test3(3, 4, 5); 163 test_no_info(); 164 test_reg_names(); 165 test_reg_get_set(); 166 test_fpreg_get_set(); 167 return 0; 168 } 169