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