169 lines · cpp
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-exception7//8//===----------------------------------------------------------------------===//9 10// TODO: Investigate this failure on x86_64 macOS back deployment11// XFAIL: stdlib=system && 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: msan15 16#include <libunwind.h>17#include <stdlib.h>18#include <stdio.h>19#include <string.h>20 21void 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 saved53}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 saved60}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 saved67}68 69void 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 89void 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#endif102 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__)115void 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 136void 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#else155void test_reg_get_set() {}156void test_fpreg_get_set() {}157#endif158 159int 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