xref: /llvm-project/libunwind/test/libunwind_01.pass.cpp (revision db8c7e004a8acf74f40e0f7bc60066f26d43ccd9)
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: 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: msan
15 
16 #include <libunwind.h>
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 
backtrace(int lower_bound)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 
test1(int i)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 
test2(int i,int j)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 
test3(int i,int j,int k)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 
test_no_info()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 
test_reg_names()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__)
test_reg_get_set()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 
test_fpreg_get_set()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
test_reg_get_set()155 void test_reg_get_set() {}
test_fpreg_get_set()156 void test_fpreg_get_set() {}
157 #endif
158 
main(int,char **)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