forked from OSchip/llvm-project
169 lines
4.0 KiB
C++
169 lines
4.0 KiB
C++
// -*- C++ -*-
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// TODO: Investigate this failure on x86_64 macOS back deployment
|
|
// 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}}
|
|
|
|
// TODO: Figure out why this fails with Memory Sanitizer.
|
|
// XFAIL: msan
|
|
|
|
#include <libunwind.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
void backtrace(int lower_bound) {
|
|
unw_context_t context;
|
|
unw_getcontext(&context);
|
|
|
|
unw_cursor_t cursor;
|
|
unw_init_local(&cursor, &context);
|
|
|
|
char buffer[1024];
|
|
unw_word_t offset = 0;
|
|
|
|
int n = 0;
|
|
do {
|
|
n++;
|
|
if (unw_get_proc_name(&cursor, buffer, sizeof(buffer), &offset) == 0) {
|
|
fprintf(stderr, "Frame %d: %s+%p\n", n, buffer, (void*)offset);
|
|
} else {
|
|
fprintf(stderr, "Frame %d: Could not get name for cursor\n", n);
|
|
}
|
|
if (n > 100) {
|
|
abort();
|
|
}
|
|
} while (unw_step(&cursor) > 0);
|
|
|
|
if (n < lower_bound) {
|
|
abort();
|
|
}
|
|
}
|
|
|
|
__attribute__((noinline)) void test1(int i) {
|
|
fprintf(stderr, "starting %s\n", __func__);
|
|
backtrace(i);
|
|
fprintf(stderr, "finished %s\n", __func__); // ensure return address is saved
|
|
}
|
|
|
|
__attribute__((noinline)) void test2(int i, int j) {
|
|
fprintf(stderr, "starting %s\n", __func__);
|
|
backtrace(i);
|
|
test1(j);
|
|
fprintf(stderr, "finished %s\n", __func__); // ensure return address is saved
|
|
}
|
|
|
|
__attribute__((noinline)) void test3(int i, int j, int k) {
|
|
fprintf(stderr, "starting %s\n", __func__);
|
|
backtrace(i);
|
|
test2(j, k);
|
|
fprintf(stderr, "finished %s\n", __func__); // ensure return address is saved
|
|
}
|
|
|
|
void test_no_info() {
|
|
unw_context_t context;
|
|
unw_getcontext(&context);
|
|
|
|
unw_cursor_t cursor;
|
|
unw_init_local(&cursor, &context);
|
|
|
|
unw_proc_info_t info;
|
|
int ret = unw_get_proc_info(&cursor, &info);
|
|
if (ret != UNW_ESUCCESS)
|
|
abort();
|
|
|
|
// Set the IP to an address clearly outside any function.
|
|
unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)0);
|
|
|
|
ret = unw_get_proc_info(&cursor, &info);
|
|
if (ret != UNW_ENOINFO)
|
|
abort();
|
|
}
|
|
|
|
void test_reg_names() {
|
|
unw_context_t context;
|
|
unw_getcontext(&context);
|
|
|
|
unw_cursor_t cursor;
|
|
unw_init_local(&cursor, &context);
|
|
|
|
int max_reg_num = -100;
|
|
#if defined(__i386__)
|
|
max_reg_num = 7;
|
|
#elif defined(__x86_64__)
|
|
max_reg_num = 32;
|
|
#endif
|
|
|
|
const char prefix[] = "unknown";
|
|
for (int i = -2; i < max_reg_num; ++i) {
|
|
if (strncmp(prefix, unw_regname(&cursor, i), sizeof(prefix) - 1) == 0)
|
|
abort();
|
|
}
|
|
|
|
if (strncmp(prefix, unw_regname(&cursor, max_reg_num + 1),
|
|
sizeof(prefix) - 1) != 0)
|
|
abort();
|
|
}
|
|
|
|
#if defined(__x86_64__)
|
|
void test_reg_get_set() {
|
|
unw_context_t context;
|
|
unw_getcontext(&context);
|
|
|
|
unw_cursor_t cursor;
|
|
unw_init_local(&cursor, &context);
|
|
|
|
for (int i = 0; i < 17; ++i) {
|
|
const unw_word_t set_value = 7;
|
|
if (unw_set_reg(&cursor, i, set_value) != UNW_ESUCCESS)
|
|
abort();
|
|
|
|
unw_word_t get_value = 0;
|
|
if (unw_get_reg(&cursor, i, &get_value) != UNW_ESUCCESS)
|
|
abort();
|
|
|
|
if (set_value != get_value)
|
|
abort();
|
|
}
|
|
}
|
|
|
|
void test_fpreg_get_set() {
|
|
unw_context_t context;
|
|
unw_getcontext(&context);
|
|
|
|
unw_cursor_t cursor;
|
|
unw_init_local(&cursor, &context);
|
|
|
|
// get/set is not implemented for x86_64 fpregs.
|
|
for (int i = 17; i < 33; ++i) {
|
|
const unw_fpreg_t set_value = 7;
|
|
if (unw_set_fpreg(&cursor, i, set_value) != UNW_EBADREG)
|
|
abort();
|
|
|
|
unw_fpreg_t get_value = 0;
|
|
if (unw_get_fpreg(&cursor, i, &get_value) != UNW_EBADREG)
|
|
abort();
|
|
}
|
|
}
|
|
#else
|
|
void test_reg_get_set() {}
|
|
void test_fpreg_get_set() {}
|
|
#endif
|
|
|
|
int main(int, char**) {
|
|
test1(3);
|
|
test2(3, 4);
|
|
test3(3, 4, 5);
|
|
test_no_info();
|
|
test_reg_names();
|
|
test_reg_get_set();
|
|
test_fpreg_get_set();
|
|
return 0;
|
|
}
|