]> git.saurik.com Git - apple/libc.git/blame - tests/backtrace.c
Libc-1272.200.26.tar.gz
[apple/libc.git] / tests / backtrace.c
CommitLineData
70ad1dc8
A
1#include <darwintest.h>
2#include <dlfcn.h>
3#include <execinfo.h>
4#include <mach-o/dyld_priv.h>
5#include <stdbool.h>
6#include <stdlib.h>
7#include <uuid/uuid.h>
8
9
10#define MAX_FRAMES 32
11static const int expected_nframes = 20;
12
13static void *observed_bt[MAX_FRAMES] = {};
14static int observed_nframes = 0;
15static unsigned int save_fp_at_nframes = 0;
16static void *save_fp = NULL;
17
18static int __attribute__((noinline,not_tail_called,disable_tail_calls))
19recurse_a(unsigned int frames);
20static int __attribute__((noinline,not_tail_called,disable_tail_calls))
21recurse_b(unsigned int frames);
22
23static int __attribute__((noinline,not_tail_called,disable_tail_calls))
24recurse_a(unsigned int frames)
25{
26 if (frames == 1) {
27 if (save_fp_at_nframes > 0) {
28 observed_nframes = backtrace_from_fp(save_fp, observed_bt,
29 MAX_FRAMES);
30 } else {
31 observed_nframes = backtrace(observed_bt, MAX_FRAMES);
32 }
33 return 0;
34 } else if (frames == save_fp_at_nframes) {
35 save_fp = __builtin_frame_address(0);
36 }
37
38 return recurse_b(frames - 1);
39}
40
41static int __attribute__((noinline,not_tail_called,disable_tail_calls))
42recurse_b(unsigned int frames)
43{
44 if (frames == 1) {
45 if (save_fp_at_nframes > 0) {
46 observed_nframes = backtrace_from_fp(save_fp, observed_bt,
47 MAX_FRAMES);
48 } else {
49 observed_nframes = backtrace(observed_bt, MAX_FRAMES);
50 }
51 return 0;
52 } else if (frames == save_fp_at_nframes) {
53 save_fp = __builtin_frame_address(0);
54 }
55
56 return recurse_a(frames - 1);
57}
58
59static void __attribute__((noinline,not_tail_called,disable_tail_calls))
60setup_and_backtrace(unsigned int nframes, unsigned int skip_nframes)
61{
62 save_fp_at_nframes = skip_nframes ? skip_nframes - 1 : 0;
63 recurse_a(nframes - 1);
64}
65
66static bool
67check_for_setup(int i, struct dl_info *info)
68{
69 int ret = dladdr(observed_bt[i], info);
70 T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "dladdr(%p)", observed_bt[i]);
71 void *setup_fp = (void *)&setup_and_backtrace;
72 return info->dli_saddr == setup_fp;
73}
74
75static void __attribute__((noinline))
76expect_backtrace(void)
77{
78 void *recurse_a_fp = (void *)&recurse_a;
79 void *recurse_b_fp = (void *)&recurse_b;
80
81 void *tmp_backtrace[MAX_FRAMES];
82 const int observed_existing_nframes = backtrace(tmp_backtrace, MAX_FRAMES);
83
84 T_EXPECT_EQ(expected_nframes,
85 observed_nframes - observed_existing_nframes,
86 "number of frames traced matches");
87 bool expect_a = true;
88 bool found_setup = false;
89
90 for (int i = 0; i < observed_nframes; i++) {
91 struct dl_info info;
92 if (check_for_setup(i, &info)) {
93 found_setup = true;
94 break;
95 }
96
97 void *expected_saddr = expect_a ? recurse_a_fp : recurse_b_fp;
98 void *observed_saddr = info.dli_saddr;
99 T_EXPECT_GE(observed_saddr, expected_saddr,
100 "frame %d (%p) matches", i, observed_bt[i]);
101 expect_a = !expect_a;
102 }
103
104 T_EXPECT_TRUE(found_setup, "should have found the setup frame");
105}
106
107T_DECL(backtrace, "ensure backtrace(3) gives the correct backtrace")
108{
109 setup_and_backtrace(expected_nframes, 0);
110 expect_backtrace();
111}
112
113T_DECL(backtrace_from_fp,
114 "ensure backtrace_from_fp(3) starts from the correct frame")
115{
116 const int skip_nframes = 5;
117 setup_and_backtrace(expected_nframes + skip_nframes, skip_nframes);
118 expect_backtrace();
119}
120
121T_DECL(backtrace_image_offsets,
122 "ensure backtrace_image_offsets(3) provides valid UUIDs and offsets")
123{
124 setup_and_backtrace(expected_nframes, 0);
125 struct image_offset imgoffs[observed_nframes];
126 backtrace_image_offsets(observed_bt, imgoffs, observed_nframes);
127
128 bool found_setup = false;
129
130 for (int i = 0; i < observed_nframes; i++) {
131 struct dl_info info;
132 if (check_for_setup(i, &info)) {
133 found_setup = true;
134 break;
135 }
136
137 const struct mach_header *mh =
138 dyld_image_header_containing_address(observed_bt[i]);
139
140 uuid_t expected_uuid;
141 bool got_uuid = _dyld_get_image_uuid(mh, expected_uuid);
142 T_QUIET; T_ASSERT_TRUE(got_uuid, "got UUID for Mach-O header");
143
144 T_EXPECT_EQ(uuid_compare(expected_uuid, imgoffs[i].uuid), 0,
145 "frame %d's UUID matches", i);
146 T_EXPECT_EQ((uintptr_t)observed_bt[i] - (uintptr_t)info.dli_fbase,
147 (uintptr_t)imgoffs[i].offset, "frame %d's offset matches", i);
148 }
149
150 T_EXPECT_TRUE(found_setup, "should have found the setup frame");
151}