xref: /netbsd-src/external/gpl3/gdb/dist/libbacktrace/btest.c (revision d16b7486a53dcb8072b60ec6fcb4373a2d0c27b7)
1 /* btest.c -- Test for libbacktrace library
2    Copyright (C) 2012-2021 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 #include <sys/stat.h>
42 
43 #include "filenames.h"
44 
45 #include "backtrace.h"
46 #include "backtrace-supported.h"
47 
48 #include "testlib.h"
49 
50 /* Test the backtrace function with non-inlined functions.  */
51 
52 static int test1 (void) __attribute__ ((noinline, noclone, unused));
53 static int f2 (int) __attribute__ ((noinline, noclone));
54 static int f3 (int, int) __attribute__ ((noinline, noclone));
55 
56 static int
57 test1 (void)
58 {
59   /* Returning a value here and elsewhere avoids a tailcall which
60      would mess up the backtrace.  */
61   return f2 (__LINE__) + 1;
62 }
63 
64 static int
65 f2 (int f1line)
66 {
67   return f3 (f1line, __LINE__) + 2;
68 }
69 
70 static int
71 f3 (int f1line, int f2line)
72 {
73   struct info all[20];
74   struct bdata data;
75   int f3line;
76   int i;
77 
78   data.all = &all[0];
79   data.index = 0;
80   data.max = 20;
81   data.failed = 0;
82 
83   f3line = __LINE__ + 1;
84   i = backtrace_full (state, 0, callback_one, error_callback_one, &data);
85 
86   if (i != 0)
87     {
88       fprintf (stderr, "test1: unexpected return value %d\n", i);
89       data.failed = 1;
90     }
91 
92   if (data.index < 3)
93     {
94       fprintf (stderr,
95 	       "test1: not enough frames; got %zu, expected at least 3\n",
96 	       data.index);
97       data.failed = 1;
98     }
99 
100   check ("test1", 0, all, f3line, "f3", "btest.c", &data.failed);
101   check ("test1", 1, all, f2line, "f2", "btest.c", &data.failed);
102   check ("test1", 2, all, f1line, "test1", "btest.c", &data.failed);
103 
104   printf ("%s: backtrace_full noinline\n", data.failed ? "FAIL" : "PASS");
105 
106   if (data.failed)
107     ++failures;
108 
109   return failures;
110 }
111 
112 /* Test the backtrace function with inlined functions.  */
113 
114 static inline int test2 (void) __attribute__ ((always_inline, unused));
115 static inline int f12 (int) __attribute__ ((always_inline));
116 static inline int f13 (int, int) __attribute__ ((always_inline));
117 
118 static inline int
119 test2 (void)
120 {
121   return f12 (__LINE__) + 1;
122 }
123 
124 static inline int
125 f12 (int f1line)
126 {
127   return f13 (f1line, __LINE__) + 2;
128 }
129 
130 static inline int
131 f13 (int f1line, int f2line)
132 {
133   struct info all[20];
134   struct bdata data;
135   int f3line;
136   int i;
137 
138   data.all = &all[0];
139   data.index = 0;
140   data.max = 20;
141   data.failed = 0;
142 
143   f3line = __LINE__ + 1;
144   i = backtrace_full (state, 0, callback_one, error_callback_one, &data);
145 
146   if (i != 0)
147     {
148       fprintf (stderr, "test2: unexpected return value %d\n", i);
149       data.failed = 1;
150     }
151 
152   check ("test2", 0, all, f3line, "f13", "btest.c", &data.failed);
153   check ("test2", 1, all, f2line, "f12", "btest.c", &data.failed);
154   check ("test2", 2, all, f1line, "test2", "btest.c", &data.failed);
155 
156   printf ("%s: backtrace_full inline\n", data.failed ? "FAIL" : "PASS");
157 
158   if (data.failed)
159     ++failures;
160 
161   return failures;
162 }
163 
164 /* Test the backtrace_simple function with non-inlined functions.  */
165 
166 static int test3 (void) __attribute__ ((noinline, noclone, unused));
167 static int f22 (int) __attribute__ ((noinline, noclone));
168 static int f23 (int, int) __attribute__ ((noinline, noclone));
169 
170 static int
171 test3 (void)
172 {
173   return f22 (__LINE__) + 1;
174 }
175 
176 static int
177 f22 (int f1line)
178 {
179   return f23 (f1line, __LINE__) + 2;
180 }
181 
182 static int
183 f23 (int f1line, int f2line)
184 {
185   uintptr_t addrs[20];
186   struct sdata data;
187   int f3line;
188   int i;
189 
190   data.addrs = &addrs[0];
191   data.index = 0;
192   data.max = 20;
193   data.failed = 0;
194 
195   f3line = __LINE__ + 1;
196   i = backtrace_simple (state, 0, callback_two, error_callback_two, &data);
197 
198   if (i != 0)
199     {
200       fprintf (stderr, "test3: unexpected return value %d\n", i);
201       data.failed = 1;
202     }
203 
204   if (!data.failed)
205     {
206       struct info all[20];
207       struct bdata bdata;
208       int j;
209 
210       bdata.all = &all[0];
211       bdata.index = 0;
212       bdata.max = 20;
213       bdata.failed = 0;
214 
215       for (j = 0; j < 3; ++j)
216 	{
217 	  i = backtrace_pcinfo (state, addrs[j], callback_one,
218 				error_callback_one, &bdata);
219 	  if (i != 0)
220 	    {
221 	      fprintf (stderr,
222 		       ("test3: unexpected return value "
223 			"from backtrace_pcinfo %d\n"),
224 		       i);
225 	      bdata.failed = 1;
226 	    }
227 	  if (!bdata.failed && bdata.index != (size_t) (j + 1))
228 	    {
229 	      fprintf (stderr,
230 		       ("wrong number of calls from backtrace_pcinfo "
231 			"got %u expected %d\n"),
232 		       (unsigned int) bdata.index, j + 1);
233 	      bdata.failed = 1;
234 	    }
235 	}
236 
237       check ("test3", 0, all, f3line, "f23", "btest.c", &bdata.failed);
238       check ("test3", 1, all, f2line, "f22", "btest.c", &bdata.failed);
239       check ("test3", 2, all, f1line, "test3", "btest.c", &bdata.failed);
240 
241       if (bdata.failed)
242 	data.failed = 1;
243 
244       for (j = 0; j < 3; ++j)
245 	{
246 	  struct symdata symdata;
247 
248 	  symdata.name = NULL;
249 	  symdata.val = 0;
250 	  symdata.size = 0;
251 	  symdata.failed = 0;
252 
253 	  i = backtrace_syminfo (state, addrs[j], callback_three,
254 				 error_callback_three, &symdata);
255 	  if (i == 0)
256 	    {
257 	      fprintf (stderr,
258 		       ("test3: [%d]: unexpected return value "
259 			"from backtrace_syminfo %d\n"),
260 		       j, i);
261 	      symdata.failed = 1;
262 	    }
263 
264 	  if (!symdata.failed)
265 	    {
266 	      const char *expected;
267 
268 	      switch (j)
269 		{
270 		case 0:
271 		  expected = "f23";
272 		  break;
273 		case 1:
274 		  expected = "f22";
275 		  break;
276 		case 2:
277 		  expected = "test3";
278 		  break;
279 		default:
280 		  assert (0);
281 		}
282 
283 	      if (symdata.name == NULL)
284 		{
285 		  fprintf (stderr, "test3: [%d]: NULL syminfo name\n", j);
286 		  symdata.failed = 1;
287 		}
288 	      /* Use strncmp, not strcmp, because GCC might create a
289 		 clone.  */
290 	      else if (strncmp (symdata.name, expected, strlen (expected))
291 		       != 0)
292 		{
293 		  fprintf (stderr,
294 			   ("test3: [%d]: unexpected syminfo name "
295 			    "got %s expected %s\n"),
296 			   j, symdata.name, expected);
297 		  symdata.failed = 1;
298 		}
299 	    }
300 
301 	  if (symdata.failed)
302 	    data.failed = 1;
303 	}
304     }
305 
306   printf ("%s: backtrace_simple noinline\n", data.failed ? "FAIL" : "PASS");
307 
308   if (data.failed)
309     ++failures;
310 
311   return failures;
312 }
313 
314 /* Test the backtrace_simple function with inlined functions.  */
315 
316 static inline int test4 (void) __attribute__ ((always_inline, unused));
317 static inline int f32 (int) __attribute__ ((always_inline));
318 static inline int f33 (int, int) __attribute__ ((always_inline));
319 
320 static inline int
321 test4 (void)
322 {
323   return f32 (__LINE__) + 1;
324 }
325 
326 static inline int
327 f32 (int f1line)
328 {
329   return f33 (f1line, __LINE__) + 2;
330 }
331 
332 static inline int
333 f33 (int f1line, int f2line)
334 {
335   uintptr_t addrs[20];
336   struct sdata data;
337   int f3line;
338   int i;
339 
340   data.addrs = &addrs[0];
341   data.index = 0;
342   data.max = 20;
343   data.failed = 0;
344 
345   f3line = __LINE__ + 1;
346   i = backtrace_simple (state, 0, callback_two, error_callback_two, &data);
347 
348   if (i != 0)
349     {
350       fprintf (stderr, "test3: unexpected return value %d\n", i);
351       data.failed = 1;
352     }
353 
354   if (!data.failed)
355     {
356       struct info all[20];
357       struct bdata bdata;
358 
359       bdata.all = &all[0];
360       bdata.index = 0;
361       bdata.max = 20;
362       bdata.failed = 0;
363 
364       i = backtrace_pcinfo (state, addrs[0], callback_one, error_callback_one,
365 			    &bdata);
366       if (i != 0)
367 	{
368 	  fprintf (stderr,
369 		   ("test4: unexpected return value "
370 		    "from backtrace_pcinfo %d\n"),
371 		   i);
372 	  bdata.failed = 1;
373 	}
374 
375       check ("test4", 0, all, f3line, "f33", "btest.c", &bdata.failed);
376       check ("test4", 1, all, f2line, "f32", "btest.c", &bdata.failed);
377       check ("test4", 2, all, f1line, "test4", "btest.c", &bdata.failed);
378 
379       if (bdata.failed)
380 	data.failed = 1;
381     }
382 
383   printf ("%s: backtrace_simple inline\n", data.failed ? "FAIL" : "PASS");
384 
385   if (data.failed)
386     ++failures;
387 
388   return failures;
389 }
390 
391 static int test5 (void) __attribute__ ((unused));
392 
393 int global = 1;
394 
395 static int
396 test5 (void)
397 {
398   struct symdata symdata;
399   int i;
400   uintptr_t addr = (uintptr_t) &global;
401 
402   if (sizeof (global) > 1)
403     addr += 1;
404 
405   symdata.name = NULL;
406   symdata.val = 0;
407   symdata.size = 0;
408   symdata.failed = 0;
409 
410   i = backtrace_syminfo (state, addr, callback_three,
411 			 error_callback_three, &symdata);
412   if (i == 0)
413     {
414       fprintf (stderr,
415 	       "test5: unexpected return value from backtrace_syminfo %d\n",
416 	       i);
417       symdata.failed = 1;
418     }
419 
420   if (!symdata.failed)
421     {
422       if (symdata.name == NULL)
423 	{
424 	  fprintf (stderr, "test5: NULL syminfo name\n");
425 	  symdata.failed = 1;
426 	}
427       else if (!(strncmp (symdata.name, "global", 6) == 0
428 		 && (symdata.name[6] == '\0'|| symdata.name[6] == '.')))
429 	{
430 	  fprintf (stderr,
431 		   "test5: unexpected syminfo name got %s expected %s\n",
432 		   symdata.name, "global");
433 	  symdata.failed = 1;
434 	}
435       else if (symdata.val != (uintptr_t) &global)
436 	{
437 	  fprintf (stderr,
438 		   "test5: unexpected syminfo value got %lx expected %lx\n",
439 		   (unsigned long) symdata.val,
440 		   (unsigned long) (uintptr_t) &global);
441 	  symdata.failed = 1;
442 	}
443       else if (symdata.size != sizeof (global))
444 	{
445 	  fprintf (stderr,
446 		   "test5: unexpected syminfo size got %lx expected %lx\n",
447 		   (unsigned long) symdata.size,
448 		   (unsigned long) sizeof (global));
449 	  symdata.failed = 1;
450 	}
451     }
452 
453   printf ("%s: backtrace_syminfo variable\n",
454 	  symdata.failed ? "FAIL" : "PASS");
455 
456   if (symdata.failed)
457     ++failures;
458 
459   return failures;
460 }
461 
462 #define MIN_DESCRIPTOR 3
463 #define MAX_DESCRIPTOR 10
464 
465 static int fstat_status[MAX_DESCRIPTOR];
466 
467 /* Check files that are available.  */
468 
469 static void
470 check_available_files (void)
471 {
472   struct stat s;
473   for (unsigned i = MIN_DESCRIPTOR; i < MAX_DESCRIPTOR; i++)
474     fstat_status[i] = fstat (i, &s);
475 }
476 
477 /* Check that are no files left open.  */
478 
479 static void
480 check_open_files (void)
481 {
482   for (unsigned i = MIN_DESCRIPTOR; i < MAX_DESCRIPTOR; i++)
483     {
484       if (fstat_status[i] != 0 && close (i) == 0)
485 	{
486 	  fprintf (stderr,
487 		   "ERROR: descriptor %d still open after tests complete\n",
488 		   i);
489 	  ++failures;
490 	}
491     }
492 }
493 
494 /* Run all the tests.  */
495 
496 int
497 main (int argc ATTRIBUTE_UNUSED, char **argv)
498 {
499   check_available_files ();
500 
501   state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS,
502 				  error_callback_create, NULL);
503 
504 #if BACKTRACE_SUPPORTED
505   test1 ();
506   test2 ();
507   test3 ();
508   test4 ();
509 #if BACKTRACE_SUPPORTS_DATA
510   test5 ();
511 #endif
512 #endif
513 
514   check_open_files ();
515 
516   exit (failures ? EXIT_FAILURE : EXIT_SUCCESS);
517 }
518