xref: /netbsd-src/external/gpl3/gcc.old/dist/libbacktrace/btest.c (revision 82d56013d7b633d116a93943de88e08335357a7c)
1 /* btest.c -- Test for libbacktrace library
2    Copyright (C) 2012-2019 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 <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41 
42 #include "filenames.h"
43 
44 #include "backtrace.h"
45 #include "backtrace-supported.h"
46 
47 #include "testlib.h"
48 
49 /* Test the backtrace function with non-inlined functions.  */
50 
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));
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 
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 
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);
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 
113 static inline int test2 (void) __attribute__ ((always_inline, unused));
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 
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);
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 
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));
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 	    }
234 	}
235 
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);
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;
249 	  symdata.size = 0;
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;
278 		default:
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 
315 static inline int test4 (void) __attribute__ ((always_inline, unused));
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 
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);
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 
390 static int test5 (void) __attribute__ ((unused));
391 
392 int global = 1;
393 
394 static int
395 test5 (void)
396 {
397   struct symdata symdata;
398   int i;
399   uintptr_t addr = (uintptr_t) &global;
400 
401   if (sizeof (global) > 1)
402     addr += 1;
403 
404   symdata.name = NULL;
405   symdata.val = 0;
406   symdata.size = 0;
407   symdata.failed = 0;
408 
409   i = backtrace_syminfo (state, addr, callback_three,
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 	}
426       else if (!(strncmp (symdata.name, "global", 6) == 0
427 		 && (symdata.name[6] == '\0'|| symdata.name[6] == '.')))
428 	{
429 	  fprintf (stderr,
430 		   "test5: unexpected syminfo name got %s expected %s\n",
431 		   symdata.name, "global");
432 	  symdata.failed = 1;
433 	}
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 	}
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 
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 
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 ();
493 #if BACKTRACE_SUPPORTS_DATA
494   test5 ();
495 #endif
496 #endif
497 
498   check_open_files ();
499 
500   exit (failures ? EXIT_FAILURE : EXIT_SUCCESS);
501 }
502