df286dbeefe44e5866a145a75e0cd187c1ccb790
[gcc.git] / libbacktrace / btest.c
1 /* btest.c -- Test for libbacktrace library
2 Copyright (C) 2012 Free Software Foundation, Inc.
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
10 notice, this list of conditions and the following disclaimer.
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
15 distribution.
16
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>
37 #include <stdint.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41
42 #include "filenames.h"
43
44 #include "backtrace.h"
45 #include "backtrace-supported.h"
46
47 /* Portable attribute syntax. Actually some of these tests probably
48 won't work if the attributes are not recognized. */
49
50 #ifndef GCC_VERSION
51 # define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
52 #endif
53
54 #if (GCC_VERSION < 2007)
55 # define __attribute__(x)
56 #endif
57
58 #ifndef ATTRIBUTE_UNUSED
59 # define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
60 #endif
61
62 /* Used to collect backtrace info. */
63
64 struct info
65 {
66 char *filename;
67 int lineno;
68 char *function;
69 };
70
71 /* Passed to backtrace callback function. */
72
73 struct bdata
74 {
75 struct info *all;
76 size_t index;
77 size_t max;
78 int failed;
79 };
80
81 /* Passed to backtrace_simple callback function. */
82
83 struct sdata
84 {
85 uintptr_t *addrs;
86 size_t index;
87 size_t max;
88 int failed;
89 };
90
91 /* Passed to backtrace_syminfo callback function. */
92
93 struct symdata
94 {
95 const char *name;
96 uintptr_t val;
97 int failed;
98 };
99
100 /* The backtrace state. */
101
102 static void *state;
103
104 /* The number of failures. */
105
106 static int failures;
107
108 /* Return the base name in a path. */
109
110 static const char *
111 base (const char *p)
112 {
113 const char *last;
114 const char *s;
115
116 last = NULL;
117 for (s = p; *s != '\0'; ++s)
118 {
119 if (IS_DIR_SEPARATOR (*s))
120 last = s + 1;
121 }
122 return last != NULL ? last : p;
123 }
124
125 /* Check an entry in a struct info array. */
126
127 static void
128 check (const char *name, int index, const struct info *all, int want_lineno,
129 const char *want_function, int *failed)
130 {
131 if (*failed)
132 return;
133 if (strcmp (base (all[index].filename), "btest.c") != 0)
134 {
135 fprintf (stderr, "%s: [%d]: got %s expected test.c\n", name, index,
136 all[index].filename);
137 *failed = 1;
138 }
139 if (all[index].lineno != want_lineno)
140 {
141 fprintf (stderr, "%s: [%d]: got %d expected %d\n", name, index,
142 all[index].lineno, want_lineno);
143 *failed = 1;
144 }
145 if (strcmp (all[index].function, want_function) != 0)
146 {
147 fprintf (stderr, "%s: [%d]: got %s expected %s\n", name, index,
148 all[index].function, want_function);
149 *failed = 1;
150 }
151 }
152
153 /* The backtrace callback function. */
154
155 static int
156 callback_one (void *vdata, uintptr_t pc ATTRIBUTE_UNUSED,
157 const char *filename, int lineno, const char *function)
158 {
159 struct bdata *data = (struct bdata *) vdata;
160 struct info *p;
161
162 if (data->index >= data->max)
163 {
164 fprintf (stderr, "callback_one: callback called too many times\n");
165 data->failed = 1;
166 return 1;
167 }
168
169 p = &data->all[data->index];
170 if (filename == NULL)
171 p->filename = NULL;
172 else
173 {
174 p->filename = strdup (filename);
175 assert (p->filename != NULL);
176 }
177 p->lineno = lineno;
178 if (function == NULL)
179 p->function = NULL;
180 else
181 {
182 p->function = strdup (function);
183 assert (p->function != NULL);
184 }
185 ++data->index;
186
187 return 0;
188 }
189
190 /* An error callback passed to backtrace. */
191
192 static void
193 error_callback_one (void *vdata, const char *msg, int errnum)
194 {
195 struct bdata *data = (struct bdata *) vdata;
196
197 fprintf (stderr, "%s", msg);
198 if (errnum > 0)
199 fprintf (stderr, ": %s", strerror (errnum));
200 fprintf (stderr, "\n");
201 data->failed = 1;
202 }
203
204 /* The backtrace_simple callback function. */
205
206 static int
207 callback_two (void *vdata, uintptr_t pc)
208 {
209 struct sdata *data = (struct sdata *) vdata;
210
211 if (data->index >= data->max)
212 {
213 fprintf (stderr, "callback_two: callback called too many times\n");
214 data->failed = 1;
215 return 1;
216 }
217
218 data->addrs[data->index] = pc;
219 ++data->index;
220
221 return 0;
222 }
223
224 /* An error callback passed to backtrace_simple. */
225
226 static void
227 error_callback_two (void *vdata, const char *msg, int errnum)
228 {
229 struct sdata *data = (struct sdata *) vdata;
230
231 fprintf (stderr, "%s", msg);
232 if (errnum > 0)
233 fprintf (stderr, ": %s", strerror (errnum));
234 fprintf (stderr, "\n");
235 data->failed = 1;
236 }
237
238 /* The backtrace_syminfo callback function. */
239
240 static void
241 callback_three (void *vdata, uintptr_t pc ATTRIBUTE_UNUSED,
242 const char *symname, uintptr_t symval)
243 {
244 struct symdata *data = (struct symdata *) vdata;
245
246 if (symname == NULL)
247 data->name = NULL;
248 else
249 {
250 data->name = strdup (symname);
251 assert (data->name != NULL);
252 }
253 data->val = symval;
254 }
255
256 /* The backtrace_syminfo error callback function. */
257
258 static void
259 error_callback_three (void *vdata, const char *msg, int errnum)
260 {
261 struct symdata *data = (struct symdata *) vdata;
262
263 fprintf (stderr, "%s", msg);
264 if (errnum > 0)
265 fprintf (stderr, ": %s", strerror (errnum));
266 fprintf (stderr, "\n");
267 data->failed = 1;
268 }
269
270 /* Test the backtrace function with non-inlined functions. */
271
272 static int test1 (void) __attribute__ ((noinline, unused));
273 static int f2 (int) __attribute__ ((noinline));
274 static int f3 (int, int) __attribute__ ((noinline));
275
276 static int
277 test1 (void)
278 {
279 /* Returning a value here and elsewhere avoids a tailcall which
280 would mess up the backtrace. */
281 return f2 (__LINE__) + 1;
282 }
283
284 static int
285 f2 (int f1line)
286 {
287 return f3 (f1line, __LINE__) + 2;
288 }
289
290 static int
291 f3 (int f1line, int f2line)
292 {
293 struct info all[20];
294 struct bdata data;
295 int f3line;
296 int i;
297
298 data.all = &all[0];
299 data.index = 0;
300 data.max = 20;
301 data.failed = 0;
302
303 f3line = __LINE__ + 1;
304 i = backtrace_full (state, 0, callback_one, error_callback_one, &data);
305
306 if (i != 0)
307 {
308 fprintf (stderr, "test1: unexpected return value %d\n", i);
309 data.failed = 1;
310 }
311
312 check ("test1", 0, all, f3line, "f3", &data.failed);
313 check ("test1", 1, all, f2line, "f2", &data.failed);
314 check ("test1", 2, all, f1line, "test1", &data.failed);
315
316 printf ("%s: backtrace_full noinline\n", data.failed ? "FAIL" : "PASS");
317
318 if (data.failed)
319 ++failures;
320
321 return failures;
322 }
323
324 /* Test the backtrace function with inlined functions. */
325
326 static inline int test2 (void) __attribute__ ((always_inline, unused));
327 static inline int f12 (int) __attribute__ ((always_inline));
328 static inline int f13 (int, int) __attribute__ ((always_inline));
329
330 static inline int
331 test2 (void)
332 {
333 return f12 (__LINE__) + 1;
334 }
335
336 static inline int
337 f12 (int f1line)
338 {
339 return f13 (f1line, __LINE__) + 2;
340 }
341
342 static inline int
343 f13 (int f1line, int f2line)
344 {
345 struct info all[20];
346 struct bdata data;
347 int f3line;
348 int i;
349
350 data.all = &all[0];
351 data.index = 0;
352 data.max = 20;
353 data.failed = 0;
354
355 f3line = __LINE__ + 1;
356 i = backtrace_full (state, 0, callback_one, error_callback_one, &data);
357
358 if (i != 0)
359 {
360 fprintf (stderr, "test2: unexpected return value %d\n", i);
361 data.failed = 1;
362 }
363
364 check ("test2", 0, all, f3line, "f13", &data.failed);
365 check ("test2", 1, all, f2line, "f12", &data.failed);
366 check ("test2", 2, all, f1line, "test2", &data.failed);
367
368 printf ("%s: backtrace_full inline\n", data.failed ? "FAIL" : "PASS");
369
370 if (data.failed)
371 ++failures;
372
373 return failures;
374 }
375
376 /* Test the backtrace_simple function with non-inlined functions. */
377
378 static int test3 (void) __attribute__ ((noinline, unused));
379 static int f22 (int) __attribute__ ((noinline));
380 static int f23 (int, int) __attribute__ ((noinline));
381
382 static int
383 test3 (void)
384 {
385 return f22 (__LINE__) + 1;
386 }
387
388 static int
389 f22 (int f1line)
390 {
391 return f23 (f1line, __LINE__) + 2;
392 }
393
394 static int
395 f23 (int f1line, int f2line)
396 {
397 uintptr_t addrs[20];
398 struct sdata data;
399 int f3line;
400 int i;
401
402 data.addrs = &addrs[0];
403 data.index = 0;
404 data.max = 20;
405 data.failed = 0;
406
407 f3line = __LINE__ + 1;
408 i = backtrace_simple (state, 0, callback_two, error_callback_two, &data);
409
410 if (i != 0)
411 {
412 fprintf (stderr, "test3: unexpected return value %d\n", i);
413 data.failed = 1;
414 }
415
416 if (!data.failed)
417 {
418 struct info all[20];
419 struct bdata bdata;
420 int j;
421
422 bdata.all = &all[0];
423 bdata.index = 0;
424 bdata.max = 20;
425 bdata.failed = 0;
426
427 for (j = 0; j < 3; ++j)
428 {
429 i = backtrace_pcinfo (state, addrs[j], callback_one,
430 error_callback_one, &bdata);
431 if (i != 0)
432 {
433 fprintf (stderr,
434 ("test3: unexpected return value "
435 "from backtrace_pcinfo %d\n"),
436 i);
437 bdata.failed = 1;
438 }
439 if (!bdata.failed && bdata.index != (size_t) (j + 1))
440 {
441 fprintf (stderr,
442 ("wrong number of calls from backtrace_pcinfo "
443 "got %u expected %d\n"),
444 (unsigned int) bdata.index, j + 1);
445 bdata.failed = 1;
446 }
447 }
448
449 check ("test3", 0, all, f3line, "f23", &bdata.failed);
450 check ("test3", 1, all, f2line, "f22", &bdata.failed);
451 check ("test3", 2, all, f1line, "test3", &bdata.failed);
452
453 if (bdata.failed)
454 data.failed = 1;
455
456 for (j = 0; j < 3; ++j)
457 {
458 struct symdata symdata;
459
460 symdata.name = NULL;
461 symdata.val = 0;
462 symdata.failed = 0;
463
464 i = backtrace_syminfo (state, addrs[j], callback_three,
465 error_callback_three, &symdata);
466 if (i == 0)
467 {
468 fprintf (stderr,
469 ("test3: [%d]: unexpected return value "
470 "from backtrace_syminfo %d\n"),
471 j, i);
472 symdata.failed = 1;
473 }
474
475 if (!symdata.failed)
476 {
477 const char *expected;
478
479 switch (j)
480 {
481 case 0:
482 expected = "f23";
483 break;
484 case 1:
485 expected = "f22";
486 break;
487 case 2:
488 expected = "test3";
489 break;
490 case 3:
491 assert (0);
492 }
493
494 if (symdata.name == NULL)
495 {
496 fprintf (stderr, "test3: [%d]: NULL syminfo name\n", j);
497 symdata.failed = 1;
498 }
499 /* Use strncmp, not strcmp, because GCC might create a
500 clone. */
501 else if (strncmp (symdata.name, expected, strlen (expected))
502 != 0)
503 {
504 fprintf (stderr,
505 ("test3: [%d]: unexpected syminfo name "
506 "got %s expected %s\n"),
507 j, symdata.name, expected);
508 symdata.failed = 1;
509 }
510 }
511
512 if (symdata.failed)
513 data.failed = 1;
514 }
515 }
516
517 printf ("%s: backtrace_simple noinline\n", data.failed ? "FAIL" : "PASS");
518
519 if (data.failed)
520 ++failures;
521
522 return failures;
523 }
524
525 /* Test the backtrace_simple function with inlined functions. */
526
527 static inline int test4 (void) __attribute__ ((always_inline, unused));
528 static inline int f32 (int) __attribute__ ((always_inline));
529 static inline int f33 (int, int) __attribute__ ((always_inline));
530
531 static inline int
532 test4 (void)
533 {
534 return f32 (__LINE__) + 1;
535 }
536
537 static inline int
538 f32 (int f1line)
539 {
540 return f33 (f1line, __LINE__) + 2;
541 }
542
543 static inline int
544 f33 (int f1line, int f2line)
545 {
546 uintptr_t addrs[20];
547 struct sdata data;
548 int f3line;
549 int i;
550
551 data.addrs = &addrs[0];
552 data.index = 0;
553 data.max = 20;
554 data.failed = 0;
555
556 f3line = __LINE__ + 1;
557 i = backtrace_simple (state, 0, callback_two, error_callback_two, &data);
558
559 if (i != 0)
560 {
561 fprintf (stderr, "test3: unexpected return value %d\n", i);
562 data.failed = 1;
563 }
564
565 if (!data.failed)
566 {
567 struct info all[20];
568 struct bdata bdata;
569
570 bdata.all = &all[0];
571 bdata.index = 0;
572 bdata.max = 20;
573 bdata.failed = 0;
574
575 i = backtrace_pcinfo (state, addrs[0], callback_one, error_callback_one,
576 &bdata);
577 if (i != 0)
578 {
579 fprintf (stderr,
580 ("test4: unexpected return value "
581 "from backtrace_pcinfo %d\n"),
582 i);
583 bdata.failed = 1;
584 }
585
586 check ("test4", 0, all, f3line, "f33", &bdata.failed);
587 check ("test4", 1, all, f2line, "f32", &bdata.failed);
588 check ("test4", 2, all, f1line, "test4", &bdata.failed);
589
590 if (bdata.failed)
591 data.failed = 1;
592 }
593
594 printf ("%s: backtrace_simple inline\n", data.failed ? "FAIL" : "PASS");
595
596 if (data.failed)
597 ++failures;
598
599 return failures;
600 }
601
602 static void
603 error_callback_create (void *data ATTRIBUTE_UNUSED, const char *msg,
604 int errnum)
605 {
606 fprintf (stderr, "%s", msg);
607 if (errnum > 0)
608 fprintf (stderr, ": %s", strerror (errnum));
609 fprintf (stderr, "\n");
610 exit (EXIT_FAILURE);
611 }
612
613 /* Run all the tests. */
614
615 int
616 main (int argc ATTRIBUTE_UNUSED, char **argv)
617 {
618 state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS,
619 error_callback_create, NULL);
620
621 #if BACKTRACE_SUPPORTED
622 test1 ();
623 test2 ();
624 test3 ();
625 test4 ();
626 #endif
627
628 exit (failures ? EXIT_FAILURE : EXIT_SUCCESS);
629 }