1 /* btest.c -- Test for libbacktrace library
2    Copyright (C) 2012-2018 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, unused));
52 static int f2 (int) __attribute__ ((noinline));
53 static int f3 (int, int) __attribute__ ((noinline));
54 
55 static int
test1(void)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
f2(int f1line)64 f2 (int f1line)
65 {
66   return f3 (f1line, __LINE__) + 2;
67 }
68 
69 static int
f3(int f1line,int f2line)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
test2(void)118 test2 (void)
119 {
120   return f12 (__LINE__) + 1;
121 }
122 
123 static inline int
f12(int f1line)124 f12 (int f1line)
125 {
126   return f13 (f1line, __LINE__) + 2;
127 }
128 
129 static inline int
f13(int f1line,int f2line)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, unused));
166 static int f22 (int) __attribute__ ((noinline));
167 static int f23 (int, int) __attribute__ ((noinline));
168 
169 static int
test3(void)170 test3 (void)
171 {
172   return f22 (__LINE__) + 1;
173 }
174 
175 static int
f22(int f1line)176 f22 (int f1line)
177 {
178   return f23 (f1line, __LINE__) + 2;
179 }
180 
181 static int
f23(int f1line,int f2line)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
test4(void)320 test4 (void)
321 {
322   return f32 (__LINE__) + 1;
323 }
324 
325 static inline int
f32(int f1line)326 f32 (int f1line)
327 {
328   return f33 (f1line, __LINE__) + 2;
329 }
330 
331 static inline int
f33(int f1line,int f2line)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
test5(void)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 (strcmp (symdata.name, "global") != 0)
427 	{
428 	  fprintf (stderr,
429 		   "test5: unexpected syminfo name got %s expected %s\n",
430 		   symdata.name, "global");
431 	  symdata.failed = 1;
432 	}
433       else if (symdata.val != (uintptr_t) &global)
434 	{
435 	  fprintf (stderr,
436 		   "test5: unexpected syminfo value got %lx expected %lx\n",
437 		   (unsigned long) symdata.val,
438 		   (unsigned long) (uintptr_t) &global);
439 	  symdata.failed = 1;
440 	}
441       else if (symdata.size != sizeof (global))
442 	{
443 	  fprintf (stderr,
444 		   "test5: unexpected syminfo size got %lx expected %lx\n",
445 		   (unsigned long) symdata.size,
446 		   (unsigned long) sizeof (global));
447 	  symdata.failed = 1;
448 	}
449     }
450 
451   printf ("%s: backtrace_syminfo variable\n",
452 	  symdata.failed ? "FAIL" : "PASS");
453 
454   if (symdata.failed)
455     ++failures;
456 
457   return failures;
458 }
459 
460 /* Check that are no files left open.  */
461 
462 static void
check_open_files(void)463 check_open_files (void)
464 {
465   int i;
466 
467   for (i = 3; i < 10; i++)
468     {
469       if (close (i) == 0)
470 	{
471 	  fprintf (stderr,
472 		   "ERROR: descriptor %d still open after tests complete\n",
473 		   i);
474 	  ++failures;
475 	}
476     }
477 }
478 
479 /* Run all the tests.  */
480 
481 int
main(int argc ATTRIBUTE_UNUSED,char ** argv)482 main (int argc ATTRIBUTE_UNUSED, char **argv)
483 {
484   state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS,
485 				  error_callback_create, NULL);
486 
487 #if BACKTRACE_SUPPORTED
488   test1 ();
489   test2 ();
490   test3 ();
491   test4 ();
492 #if BACKTRACE_SUPPORTS_DATA
493   test5 ();
494 #endif
495 #endif
496 
497   check_open_files ();
498 
499   exit (failures ? EXIT_FAILURE : EXIT_SUCCESS);
500 }
501