The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
btest.c
Go to the documentation of this file.
1/* btest.c -- Test for libbacktrace library
2 Copyright (C) 2012-2024 Free Software Foundation, Inc.
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>
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
52static int test1 (void) __attribute__ ((noinline, noclone, optnone, unused));
53static int f2 (int) __attribute__ ((noinline, noclone));
54static int f3 (int, int) __attribute__ ((noinline, noclone));
55
56static int
57test1 (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
64static int
65f2 (int f1line)
66{
67 return f3 (f1line, __LINE__) + 2;
68}
69
70static int
71f3 (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;
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
114static inline int test2 (void) __attribute__ ((always_inline, unused));
115static inline int f12 (int) __attribute__ ((always_inline));
116static inline int f13 (int, int) __attribute__ ((always_inline));
117
118static inline int
119test2 (void)
120{
121 return f12 (__LINE__) + 1;
122}
123
124static inline int
125f12 (int f1line)
126{
127 return f13 (f1line, __LINE__) + 2;
128}
129
130static inline int
131f13 (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;
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
166static int test3 (void) __attribute__ ((noinline, noclone, optnone, unused));
167static int f22 (int) __attribute__ ((noinline, noclone));
168static int f23 (int, int) __attribute__ ((noinline, noclone));
169
170static int
171test3 (void)
172{
173 return f22 (__LINE__) + 1;
174}
175
176static int
177f22 (int f1line)
178{
179 return f23 (f1line, __LINE__) + 2;
180}
181
182static int
183f23 (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;
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,
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,
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
316static inline int test4 (void) __attribute__ ((always_inline, unused));
317static inline int f32 (int) __attribute__ ((always_inline));
318static inline int f33 (int, int) __attribute__ ((always_inline));
319
320static inline int
321test4 (void)
322{
323 return f32 (__LINE__) + 1;
324}
325
326static inline int
327f32 (int f1line)
328{
329 return f33 (f1line, __LINE__) + 2;
330}
331
332static inline int
333f33 (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;
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
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
391static int test5 (void) __attribute__ ((unused));
392
393int global = 1;
394
395static int
396test5 (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
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) && symdata.size != 0)
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
466
467/* Check files that are available. */
468
469static 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
479static 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
496int
497main (int argc ATTRIBUTE_UNUSED, char **argv)
498{
500
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
515
516 exit (failures ? EXIT_FAILURE : EXIT_SUCCESS);
517}
#define BACKTRACE_SUPPORTS_THREADS
int backtrace_syminfo(struct backtrace_state *state, uintptr_t addr, backtrace_syminfo_callback callback, backtrace_error_callback error_callback, void *data)
Definition fileline.c:402
int backtrace_simple(struct backtrace_state *state, int skip, backtrace_simple_callback callback, backtrace_error_callback error_callback, void *data)
int backtrace_full(struct backtrace_state *state, int skip, backtrace_full_callback callback, backtrace_error_callback error_callback, void *data)
struct backtrace_state * backtrace_create_state(const char *filename, int threaded, backtrace_error_callback error_callback, void *data)
Definition state.c:46
int backtrace_pcinfo(struct backtrace_state *state, uintptr_t pc, backtrace_full_callback callback, backtrace_error_callback error_callback, void *data)
Definition fileline.c:386
static void check_open_files(void)
Definition btest.c:480
static int f12(int f1line)
Definition btest.c:125
static int f2(int f1line)
Definition btest.c:65
static int f32(int f1line)
Definition btest.c:327
static int fstat_status[MAX_DESCRIPTOR]
Definition btest.c:465
static int f13(int f1line, int f2line)
Definition btest.c:131
static int f23(int f1line, int f2line)
Definition btest.c:183
static int test1(void)
Definition btest.c:52
static void check_available_files(void)
Definition btest.c:470
static int test2(void)
Definition btest.c:114
static int test3(void)
Definition btest.c:166
int main(int argc ATTRIBUTE_UNUSED, char **argv)
Definition btest.c:497
#define MAX_DESCRIPTOR
Definition btest.c:463
static int test5(void)
Definition btest.c:391
static int test4(void)
Definition btest.c:316
static int f22(int f1line)
Definition btest.c:177
static int f3(int f1line, int f2line)
Definition btest.c:71
#define MIN_DESCRIPTOR
Definition btest.c:462
static int f33(int f1line, int f2line)
Definition btest.c:333
#define ATTRIBUTE_UNUSED
Definition filenames.h:42
#define __attribute__(x)
Definition filenames.h:38
void callback_three(void *vdata, uintptr_t pc ATTRIBUTE_UNUSED, const char *symname, uintptr_t symval, uintptr_t symsize)
Definition testlib.c:192
void check(const char *name, int index, const struct info *all, int want_lineno, const char *want_function, const char *want_file, int *failed)
Definition testlib.c:72
void * state
Definition testlib.c:46
void error_callback_three(void *vdata, const char *msg, int errnum)
Definition testlib.c:212
int failures
Definition testlib.c:50
int callback_two(void *vdata, uintptr_t pc)
Definition testlib.c:158
void error_callback_create(void *data ATTRIBUTE_UNUSED, const char *msg, int errnum)
Definition testlib.c:226
int callback_one(void *vdata, uintptr_t pc ATTRIBUTE_UNUSED, const char *filename, int lineno, const char *function)
Definition testlib.c:107
void error_callback_one(void *vdata, const char *msg, int errnum)
Definition testlib.c:144
void error_callback_two(void *vdata, const char *msg, int errnum)
Definition testlib.c:178
size_t index
Definition testlib.h:65
struct info * all
Definition testlib.h:64
const char * name
Definition testlib.h:84
uintptr_t val
Definition testlib.h:85
size_t max
Definition testlib.h:66
uintptr_t * addrs
Definition testlib.h:74
int failed
Definition testlib.h:67
uintptr_t size
Definition testlib.h:85
int failed
Definition testlib.h:86
Definition testlib.h:54
Functions to help with cleanup.
static fr_slen_t data
Definition value.h:1340