1 #include <darwintest.h>
4 #include <mach-o/dyld_priv.h>
11 static const int expected_nframes
= 20;
12 static const int skip_nframes
= 5;
14 static void *observed_bt
[MAX_FRAMES
] = {};
15 static int observed_nframes
= 0;
16 static unsigned int save_fp_at_nframes
= 0;
17 static void *save_fp
= NULL
;
19 static int __attribute__((noinline
,not_tail_called
,disable_tail_calls
))
20 recurse_a(unsigned int frames
);
21 static int __attribute__((noinline
,not_tail_called
,disable_tail_calls
))
22 recurse_b(unsigned int frames
);
24 static int __attribute__((noinline
,not_tail_called
,disable_tail_calls
))
25 recurse_a(unsigned int frames
)
28 if (save_fp_at_nframes
> 0) {
29 observed_nframes
= backtrace_from_fp(save_fp
, observed_bt
,
32 observed_nframes
= backtrace(observed_bt
, MAX_FRAMES
);
35 } else if (frames
== save_fp_at_nframes
) {
36 save_fp
= __builtin_frame_address(0);
39 return recurse_b(frames
- 1);
42 static int __attribute__((noinline
,not_tail_called
,disable_tail_calls
))
43 recurse_b(unsigned int frames
)
46 if (save_fp_at_nframes
> 0) {
47 observed_nframes
= backtrace_from_fp(save_fp
, observed_bt
,
50 observed_nframes
= backtrace(observed_bt
, MAX_FRAMES
);
53 } else if (frames
== save_fp_at_nframes
) {
54 save_fp
= __builtin_frame_address(0);
57 return recurse_a(frames
- 1);
60 static void __attribute__((noinline
,not_tail_called
,disable_tail_calls
))
61 setup_and_backtrace(unsigned int nframes
, unsigned int skip
)
63 save_fp_at_nframes
= skip
? skip
- 1 : 0;
64 recurse_a(nframes
- 1);
68 check_for_setup(int i
, struct dl_info
*info
)
70 int ret
= dladdr(observed_bt
[i
], info
);
71 T_QUIET
; T_ASSERT_POSIX_SUCCESS(ret
, "dladdr(%p)", observed_bt
[i
]);
72 void *setup_fp
= (void *)&setup_and_backtrace
;
73 return info
->dli_saddr
== setup_fp
;
76 static void __attribute__((noinline
,not_tail_called
))
77 expect_backtrace(void)
79 void *recurse_a_fp
= (void *)&recurse_a
;
80 void *recurse_b_fp
= (void *)&recurse_b
;
82 void *tmp_backtrace
[MAX_FRAMES
];
83 const int observed_existing_nframes
= backtrace(tmp_backtrace
, MAX_FRAMES
);
85 T_EXPECT_EQ(expected_nframes
,
86 observed_nframes
- observed_existing_nframes
,
87 "number of frames traced matches %d", expected_nframes
);
88 bool expect_a
= !(skip_nframes
% 2);
89 bool found_setup
= false;
91 for (int i
= 0; i
< observed_nframes
; i
++) {
93 if (check_for_setup(i
, &info
)) {
98 void *expected_saddr
= expect_a
? recurse_a_fp
: recurse_b_fp
;
99 void *observed_saddr
= info
.dli_saddr
;
100 T_EXPECT_EQ(observed_saddr
, expected_saddr
,
101 "frame %d (%p: %s) matches", i
, observed_bt
[i
], info
.dli_sname
);
102 expect_a
= !expect_a
;
105 T_EXPECT_TRUE(found_setup
, "should have found the setup frame");
108 T_DECL(backtrace
, "ensure backtrace(3) gives the correct backtrace")
110 setup_and_backtrace(expected_nframes
, 0);
114 T_DECL(backtrace_from_fp
,
115 "ensure backtrace_from_fp(3) starts from the correct frame")
117 setup_and_backtrace(expected_nframes
+ skip_nframes
, skip_nframes
);
121 T_DECL(backtrace_image_offsets
,
122 "ensure backtrace_image_offsets(3) provides valid UUIDs and offsets")
124 setup_and_backtrace(expected_nframes
, 0);
125 struct image_offset imgoffs
[observed_nframes
];
126 backtrace_image_offsets(observed_bt
, imgoffs
, observed_nframes
);
128 bool found_setup
= false;
130 for (int i
= 0; i
< observed_nframes
; i
++) {
132 if (check_for_setup(i
, &info
)) {
137 const struct mach_header
*mh
=
138 dyld_image_header_containing_address(observed_bt
[i
]);
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");
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
);
150 T_EXPECT_TRUE(found_setup
, "should have found the setup frame");
153 T_DECL(backtrace_symbols
, "tests backtrace_symbols")
155 setup_and_backtrace(expected_nframes
, 0);
157 char **symbols
= backtrace_symbols(observed_bt
, observed_nframes
);
159 bool found_setup
= false;
161 for (int i
= 0; i
< observed_nframes
; i
++) {
162 T_LOG("frame[%d]: %s", i
, symbols
[i
]);
163 if (strstr(symbols
[i
], "setup_and_backtrace") != NULL
) {
168 T_EXPECT_TRUE(found_setup
, "should have found the setup frame");