1 #include <libunwind.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4 
backtrace(int lower_bound)5 void backtrace(int lower_bound) {
6   unw_context_t context;
7   unw_getcontext(&context);
8 
9   unw_cursor_t cursor;
10   unw_init_local(&cursor, &context);
11 
12   char buffer[1024];
13   size_t offset = 0;
14 
15   int n = 0;
16   while (1) {
17     n++;
18     if (unw_get_proc_name(&cursor, buffer, sizeof(buffer), &offset) == 0) {
19       fprintf(stderr, "Frame %d: %s+%p\n", n, buffer, (void*)(intptr_t)offset);
20     } else {
21       fprintf(stderr, "Frame %d: Could not get name for cursor\n", n);
22     }
23     if (n > 100) {
24       fprintf(stderr, "ERROR: Got %d frames, but expected at most 100\n", n);
25       abort();
26     }
27     int error = unw_step(&cursor);
28     if (error == 0) {
29       fprintf(stderr, "Note: Reached final frame after %d steps\n", n);
30       break;
31     } else if (error < 0) {
32       fprintf(stderr, "ERROR: Got error in unw_step: %d\n", error);
33       abort();
34     }
35   };
36 
37   if (n < lower_bound) {
38     fprintf(stderr, "ERROR: Got %d frames, but expected at least %d\n", n, lower_bound);
39     abort();
40   }
41 }
42 
test1(int i)43 __attribute__((noinline)) void test1(int i) {
44   fprintf(stderr, "starting %s\n", __func__);
45   backtrace(i);
46   fprintf(stderr, "finished %s\n", __func__); // ensure return address is saved
47 }
48 
test2(int i,int j)49 __attribute__((noinline)) void test2(int i, int j) {
50   fprintf(stderr, "starting %s\n", __func__);
51   backtrace(i);
52   test1(j);
53   fprintf(stderr, "finished %s\n", __func__); // ensure return address is saved
54 }
55 
test3(int i,int j,int k)56 __attribute__((noinline)) void test3(int i, int j, int k) {
57   fprintf(stderr, "starting %s\n", __func__);
58   backtrace(i);
59   test2(j, k);
60   fprintf(stderr, "finished %s\n", __func__); // ensure return address is saved
61 }
62 
test_no_info()63 void test_no_info() {
64   unw_context_t context;
65   unw_getcontext(&context);
66 
67   unw_cursor_t cursor;
68   unw_init_local(&cursor, &context);
69 
70   unw_proc_info_t info;
71   int ret = unw_get_proc_info(&cursor, &info);
72   if (ret != UNW_ESUCCESS)
73     abort();
74 
75   // Set the IP to an address clearly outside any function.
76   unw_set_reg(&cursor, UNW_REG_IP, (unw_word_t)0);
77 
78   ret = unw_get_proc_info(&cursor, &info);
79   if (ret != UNW_ENOINFO)
80     abort();
81 }
82 
main()83 int main() {
84   test1(3);
85   test2(3, 4);
86   test3(3, 4, 5);
87   test_no_info();
88   fprintf(stderr, "Success!\n");
89   return 0;
90 }
91