]>
Commit | Line | Data |
---|---|---|
eff02e4f | 1 | /* btest.c -- Test for libbacktrace library |
a5544970 | 2 | Copyright (C) 2012-2019 Free Software Foundation, Inc. |
eff02e4f ILT |
3 | Written by Ian Lance Taylor, Google. |
4 | ||
5 | Redistribution and use in source and binary forms, with or without | |
6 | modification, are permitted provided that the following conditions are | |
7 | met: | |
8 | ||
9 | (1) Redistributions of source code must retain the above copyright | |
84ebf639 | 10 | notice, this list of conditions and the following disclaimer. |
eff02e4f ILT |
11 | |
12 | (2) Redistributions in binary form must reproduce the above copyright | |
13 | notice, this list of conditions and the following disclaimer in | |
14 | the documentation and/or other materials provided with the | |
84ebf639 CL |
15 | distribution. |
16 | ||
eff02e4f ILT |
17 | (3) The name of the author may not be used to |
18 | endorse or promote products derived from this software without | |
19 | specific prior written permission. | |
20 | ||
21 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | |
22 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
23 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
24 | DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, | |
25 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
26 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
27 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
28 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
29 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING | |
30 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
31 | POSSIBILITY OF SUCH DAMAGE. */ | |
32 | ||
33 | /* This program tests the externally visible interfaces of the | |
34 | libbacktrace library. */ | |
35 | ||
36 | #include <assert.h> | |
eff02e4f ILT |
37 | #include <stdio.h> |
38 | #include <stdlib.h> | |
39 | #include <string.h> | |
65d0b859 | 40 | #include <unistd.h> |
eff02e4f ILT |
41 | |
42 | #include "filenames.h" | |
43 | ||
44 | #include "backtrace.h" | |
45 | #include "backtrace-supported.h" | |
46 | ||
d1609a23 | 47 | #include "testlib.h" |
eff02e4f ILT |
48 | |
49 | /* Test the backtrace function with non-inlined functions. */ | |
50 | ||
c51b2c8c TV |
51 | static int test1 (void) __attribute__ ((noinline, noclone, unused)); |
52 | static int f2 (int) __attribute__ ((noinline, noclone)); | |
53 | static int f3 (int, int) __attribute__ ((noinline, noclone)); | |
eff02e4f ILT |
54 | |
55 | static int | |
56 | test1 (void) | |
57 | { | |
58 | /* Returning a value here and elsewhere avoids a tailcall which | |
59 | would mess up the backtrace. */ | |
60 | return f2 (__LINE__) + 1; | |
61 | } | |
62 | ||
63 | static int | |
64 | f2 (int f1line) | |
65 | { | |
66 | return f3 (f1line, __LINE__) + 2; | |
67 | } | |
68 | ||
69 | static int | |
70 | f3 (int f1line, int f2line) | |
71 | { | |
72 | struct info all[20]; | |
73 | struct bdata data; | |
74 | int f3line; | |
75 | int i; | |
76 | ||
77 | data.all = &all[0]; | |
78 | data.index = 0; | |
79 | data.max = 20; | |
80 | data.failed = 0; | |
81 | ||
82 | f3line = __LINE__ + 1; | |
83 | i = backtrace_full (state, 0, callback_one, error_callback_one, &data); | |
84 | ||
85 | if (i != 0) | |
86 | { | |
87 | fprintf (stderr, "test1: unexpected return value %d\n", i); | |
88 | data.failed = 1; | |
89 | } | |
90 | ||
b8ddd61b ILT |
91 | if (data.index < 3) |
92 | { | |
93 | fprintf (stderr, | |
94 | "test1: not enough frames; got %zu, expected at least 3\n", | |
95 | data.index); | |
96 | data.failed = 1; | |
97 | } | |
98 | ||
d1609a23 ILT |
99 | check ("test1", 0, all, f3line, "f3", "btest.c", &data.failed); |
100 | check ("test1", 1, all, f2line, "f2", "btest.c", &data.failed); | |
101 | check ("test1", 2, all, f1line, "test1", "btest.c", &data.failed); | |
eff02e4f ILT |
102 | |
103 | printf ("%s: backtrace_full noinline\n", data.failed ? "FAIL" : "PASS"); | |
104 | ||
105 | if (data.failed) | |
106 | ++failures; | |
107 | ||
108 | return failures; | |
109 | } | |
110 | ||
111 | /* Test the backtrace function with inlined functions. */ | |
112 | ||
bd3e497d | 113 | static inline int test2 (void) __attribute__ ((always_inline, unused)); |
eff02e4f ILT |
114 | static inline int f12 (int) __attribute__ ((always_inline)); |
115 | static inline int f13 (int, int) __attribute__ ((always_inline)); | |
116 | ||
117 | static inline int | |
118 | test2 (void) | |
119 | { | |
120 | return f12 (__LINE__) + 1; | |
121 | } | |
122 | ||
123 | static inline int | |
124 | f12 (int f1line) | |
125 | { | |
126 | return f13 (f1line, __LINE__) + 2; | |
127 | } | |
128 | ||
129 | static inline int | |
130 | f13 (int f1line, int f2line) | |
131 | { | |
132 | struct info all[20]; | |
133 | struct bdata data; | |
134 | int f3line; | |
135 | int i; | |
136 | ||
137 | data.all = &all[0]; | |
138 | data.index = 0; | |
139 | data.max = 20; | |
140 | data.failed = 0; | |
141 | ||
142 | f3line = __LINE__ + 1; | |
143 | i = backtrace_full (state, 0, callback_one, error_callback_one, &data); | |
144 | ||
145 | if (i != 0) | |
146 | { | |
147 | fprintf (stderr, "test2: unexpected return value %d\n", i); | |
148 | data.failed = 1; | |
149 | } | |
150 | ||
d1609a23 ILT |
151 | check ("test2", 0, all, f3line, "f13", "btest.c", &data.failed); |
152 | check ("test2", 1, all, f2line, "f12", "btest.c", &data.failed); | |
153 | check ("test2", 2, all, f1line, "test2", "btest.c", &data.failed); | |
eff02e4f ILT |
154 | |
155 | printf ("%s: backtrace_full inline\n", data.failed ? "FAIL" : "PASS"); | |
156 | ||
157 | if (data.failed) | |
158 | ++failures; | |
159 | ||
160 | return failures; | |
161 | } | |
162 | ||
163 | /* Test the backtrace_simple function with non-inlined functions. */ | |
164 | ||
c51b2c8c TV |
165 | static int test3 (void) __attribute__ ((noinline, noclone, unused)); |
166 | static int f22 (int) __attribute__ ((noinline, noclone)); | |
167 | static int f23 (int, int) __attribute__ ((noinline, noclone)); | |
eff02e4f ILT |
168 | |
169 | static int | |
170 | test3 (void) | |
171 | { | |
172 | return f22 (__LINE__) + 1; | |
173 | } | |
174 | ||
175 | static int | |
176 | f22 (int f1line) | |
177 | { | |
178 | return f23 (f1line, __LINE__) + 2; | |
179 | } | |
180 | ||
181 | static int | |
182 | f23 (int f1line, int f2line) | |
183 | { | |
184 | uintptr_t addrs[20]; | |
185 | struct sdata data; | |
186 | int f3line; | |
187 | int i; | |
188 | ||
189 | data.addrs = &addrs[0]; | |
190 | data.index = 0; | |
191 | data.max = 20; | |
192 | data.failed = 0; | |
193 | ||
194 | f3line = __LINE__ + 1; | |
195 | i = backtrace_simple (state, 0, callback_two, error_callback_two, &data); | |
196 | ||
197 | if (i != 0) | |
198 | { | |
199 | fprintf (stderr, "test3: unexpected return value %d\n", i); | |
200 | data.failed = 1; | |
201 | } | |
202 | ||
203 | if (!data.failed) | |
204 | { | |
205 | struct info all[20]; | |
206 | struct bdata bdata; | |
207 | int j; | |
208 | ||
209 | bdata.all = &all[0]; | |
210 | bdata.index = 0; | |
211 | bdata.max = 20; | |
212 | bdata.failed = 0; | |
213 | ||
214 | for (j = 0; j < 3; ++j) | |
215 | { | |
216 | i = backtrace_pcinfo (state, addrs[j], callback_one, | |
217 | error_callback_one, &bdata); | |
218 | if (i != 0) | |
219 | { | |
220 | fprintf (stderr, | |
221 | ("test3: unexpected return value " | |
222 | "from backtrace_pcinfo %d\n"), | |
223 | i); | |
224 | bdata.failed = 1; | |
225 | } | |
226 | if (!bdata.failed && bdata.index != (size_t) (j + 1)) | |
227 | { | |
228 | fprintf (stderr, | |
229 | ("wrong number of calls from backtrace_pcinfo " | |
230 | "got %u expected %d\n"), | |
231 | (unsigned int) bdata.index, j + 1); | |
232 | bdata.failed = 1; | |
233 | } | |
84ebf639 | 234 | } |
eff02e4f | 235 | |
d1609a23 ILT |
236 | check ("test3", 0, all, f3line, "f23", "btest.c", &bdata.failed); |
237 | check ("test3", 1, all, f2line, "f22", "btest.c", &bdata.failed); | |
238 | check ("test3", 2, all, f1line, "test3", "btest.c", &bdata.failed); | |
eff02e4f ILT |
239 | |
240 | if (bdata.failed) | |
241 | data.failed = 1; | |
242 | ||
243 | for (j = 0; j < 3; ++j) | |
244 | { | |
245 | struct symdata symdata; | |
246 | ||
247 | symdata.name = NULL; | |
248 | symdata.val = 0; | |
1f96a712 | 249 | symdata.size = 0; |
eff02e4f ILT |
250 | symdata.failed = 0; |
251 | ||
252 | i = backtrace_syminfo (state, addrs[j], callback_three, | |
253 | error_callback_three, &symdata); | |
254 | if (i == 0) | |
255 | { | |
256 | fprintf (stderr, | |
257 | ("test3: [%d]: unexpected return value " | |
258 | "from backtrace_syminfo %d\n"), | |
259 | j, i); | |
260 | symdata.failed = 1; | |
261 | } | |
262 | ||
263 | if (!symdata.failed) | |
264 | { | |
265 | const char *expected; | |
266 | ||
267 | switch (j) | |
268 | { | |
269 | case 0: | |
270 | expected = "f23"; | |
271 | break; | |
272 | case 1: | |
273 | expected = "f22"; | |
274 | break; | |
275 | case 2: | |
276 | expected = "test3"; | |
277 | break; | |
068ef6d1 | 278 | default: |
eff02e4f ILT |
279 | assert (0); |
280 | } | |
281 | ||
282 | if (symdata.name == NULL) | |
283 | { | |
284 | fprintf (stderr, "test3: [%d]: NULL syminfo name\n", j); | |
285 | symdata.failed = 1; | |
286 | } | |
287 | /* Use strncmp, not strcmp, because GCC might create a | |
288 | clone. */ | |
289 | else if (strncmp (symdata.name, expected, strlen (expected)) | |
290 | != 0) | |
291 | { | |
292 | fprintf (stderr, | |
293 | ("test3: [%d]: unexpected syminfo name " | |
294 | "got %s expected %s\n"), | |
295 | j, symdata.name, expected); | |
296 | symdata.failed = 1; | |
297 | } | |
298 | } | |
299 | ||
300 | if (symdata.failed) | |
301 | data.failed = 1; | |
302 | } | |
303 | } | |
304 | ||
305 | printf ("%s: backtrace_simple noinline\n", data.failed ? "FAIL" : "PASS"); | |
306 | ||
307 | if (data.failed) | |
308 | ++failures; | |
309 | ||
310 | return failures; | |
311 | } | |
312 | ||
313 | /* Test the backtrace_simple function with inlined functions. */ | |
314 | ||
bd3e497d | 315 | static inline int test4 (void) __attribute__ ((always_inline, unused)); |
eff02e4f ILT |
316 | static inline int f32 (int) __attribute__ ((always_inline)); |
317 | static inline int f33 (int, int) __attribute__ ((always_inline)); | |
318 | ||
319 | static inline int | |
320 | test4 (void) | |
321 | { | |
322 | return f32 (__LINE__) + 1; | |
323 | } | |
324 | ||
325 | static inline int | |
326 | f32 (int f1line) | |
327 | { | |
328 | return f33 (f1line, __LINE__) + 2; | |
329 | } | |
330 | ||
331 | static inline int | |
332 | f33 (int f1line, int f2line) | |
333 | { | |
334 | uintptr_t addrs[20]; | |
335 | struct sdata data; | |
336 | int f3line; | |
337 | int i; | |
338 | ||
339 | data.addrs = &addrs[0]; | |
340 | data.index = 0; | |
341 | data.max = 20; | |
342 | data.failed = 0; | |
343 | ||
344 | f3line = __LINE__ + 1; | |
345 | i = backtrace_simple (state, 0, callback_two, error_callback_two, &data); | |
346 | ||
347 | if (i != 0) | |
348 | { | |
349 | fprintf (stderr, "test3: unexpected return value %d\n", i); | |
350 | data.failed = 1; | |
351 | } | |
352 | ||
353 | if (!data.failed) | |
354 | { | |
355 | struct info all[20]; | |
356 | struct bdata bdata; | |
357 | ||
358 | bdata.all = &all[0]; | |
359 | bdata.index = 0; | |
360 | bdata.max = 20; | |
361 | bdata.failed = 0; | |
362 | ||
363 | i = backtrace_pcinfo (state, addrs[0], callback_one, error_callback_one, | |
364 | &bdata); | |
365 | if (i != 0) | |
366 | { | |
367 | fprintf (stderr, | |
368 | ("test4: unexpected return value " | |
369 | "from backtrace_pcinfo %d\n"), | |
370 | i); | |
371 | bdata.failed = 1; | |
372 | } | |
373 | ||
d1609a23 ILT |
374 | check ("test4", 0, all, f3line, "f33", "btest.c", &bdata.failed); |
375 | check ("test4", 1, all, f2line, "f32", "btest.c", &bdata.failed); | |
376 | check ("test4", 2, all, f1line, "test4", "btest.c", &bdata.failed); | |
eff02e4f ILT |
377 | |
378 | if (bdata.failed) | |
379 | data.failed = 1; | |
380 | } | |
381 | ||
382 | printf ("%s: backtrace_simple inline\n", data.failed ? "FAIL" : "PASS"); | |
383 | ||
384 | if (data.failed) | |
385 | ++failures; | |
386 | ||
387 | return failures; | |
388 | } | |
389 | ||
121eb024 | 390 | static int test5 (void) __attribute__ ((unused)); |
e24afc10 | 391 | |
cfa658e4 ILT |
392 | int global = 1; |
393 | ||
394 | static int | |
395 | test5 (void) | |
396 | { | |
397 | struct symdata symdata; | |
398 | int i; | |
1f96a712 JJ |
399 | uintptr_t addr = (uintptr_t) &global; |
400 | ||
401 | if (sizeof (global) > 1) | |
402 | addr += 1; | |
cfa658e4 ILT |
403 | |
404 | symdata.name = NULL; | |
405 | symdata.val = 0; | |
1f96a712 | 406 | symdata.size = 0; |
cfa658e4 ILT |
407 | symdata.failed = 0; |
408 | ||
1f96a712 | 409 | i = backtrace_syminfo (state, addr, callback_three, |
cfa658e4 ILT |
410 | error_callback_three, &symdata); |
411 | if (i == 0) | |
412 | { | |
413 | fprintf (stderr, | |
414 | "test5: unexpected return value from backtrace_syminfo %d\n", | |
415 | i); | |
416 | symdata.failed = 1; | |
417 | } | |
418 | ||
419 | if (!symdata.failed) | |
420 | { | |
421 | if (symdata.name == NULL) | |
422 | { | |
423 | fprintf (stderr, "test5: NULL syminfo name\n"); | |
424 | symdata.failed = 1; | |
425 | } | |
067aef03 TV |
426 | else if (!(strncmp (symdata.name, "global", 6) == 0 |
427 | && (symdata.name[6] == '\0'|| symdata.name[6] == '.'))) | |
cfa658e4 ILT |
428 | { |
429 | fprintf (stderr, | |
430 | "test5: unexpected syminfo name got %s expected %s\n", | |
431 | symdata.name, "global"); | |
432 | symdata.failed = 1; | |
433 | } | |
1f96a712 JJ |
434 | else if (symdata.val != (uintptr_t) &global) |
435 | { | |
436 | fprintf (stderr, | |
437 | "test5: unexpected syminfo value got %lx expected %lx\n", | |
438 | (unsigned long) symdata.val, | |
439 | (unsigned long) (uintptr_t) &global); | |
440 | symdata.failed = 1; | |
441 | } | |
442 | else if (symdata.size != sizeof (global)) | |
443 | { | |
444 | fprintf (stderr, | |
445 | "test5: unexpected syminfo size got %lx expected %lx\n", | |
446 | (unsigned long) symdata.size, | |
447 | (unsigned long) sizeof (global)); | |
448 | symdata.failed = 1; | |
449 | } | |
cfa658e4 ILT |
450 | } |
451 | ||
452 | printf ("%s: backtrace_syminfo variable\n", | |
453 | symdata.failed ? "FAIL" : "PASS"); | |
454 | ||
455 | if (symdata.failed) | |
456 | ++failures; | |
457 | ||
458 | return failures; | |
459 | } | |
460 | ||
65d0b859 ILT |
461 | /* Check that are no files left open. */ |
462 | ||
463 | static void | |
464 | check_open_files (void) | |
465 | { | |
466 | int i; | |
467 | ||
468 | for (i = 3; i < 10; i++) | |
469 | { | |
470 | if (close (i) == 0) | |
471 | { | |
472 | fprintf (stderr, | |
473 | "ERROR: descriptor %d still open after tests complete\n", | |
474 | i); | |
475 | ++failures; | |
476 | } | |
477 | } | |
478 | } | |
479 | ||
eff02e4f ILT |
480 | /* Run all the tests. */ |
481 | ||
482 | int | |
483 | main (int argc ATTRIBUTE_UNUSED, char **argv) | |
484 | { | |
485 | state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS, | |
486 | error_callback_create, NULL); | |
487 | ||
488 | #if BACKTRACE_SUPPORTED | |
489 | test1 (); | |
490 | test2 (); | |
491 | test3 (); | |
492 | test4 (); | |
e24afc10 | 493 | #if BACKTRACE_SUPPORTS_DATA |
cfa658e4 | 494 | test5 (); |
e24afc10 | 495 | #endif |
eff02e4f ILT |
496 | #endif |
497 | ||
65d0b859 ILT |
498 | check_open_files (); |
499 | ||
eff02e4f ILT |
500 | exit (failures ? EXIT_FAILURE : EXIT_SUCCESS); |
501 | } |