1/* btest.c -- Test for libbacktrace library 2 Copyright (C) 2012-2016 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 41#include "backtrace.h" 42#include "backtrace-supported.h" 43 44/* Portable attribute syntax. Actually some of these tests probably 45 won't work if the attributes are not recognized. */ 46 47#ifndef GCC_VERSION 48# define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__) 49#endif 50 51#if (GCC_VERSION < 2007) 52# define __attribute__(x) 53#endif 54 55#ifndef ATTRIBUTE_UNUSED 56# define ATTRIBUTE_UNUSED __attribute__ ((__unused__)) 57#endif 58 59#if defined(__MSDOS__) || defined(_WIN32) || defined(__OS2__) || defined (__CYGWIN__) 60# define IS_DIR_SEPARATOR(c) ((c) == '/' || (c) == '\\') 61#else 62# define IS_DIR_SEPARATOR(c) ((c) == '/') 63#endif 64 65/* Used to collect backtrace info. */ 66 67struct info 68{ 69 char *filename; 70 int lineno; 71 char *function; 72}; 73 74/* Passed to backtrace callback function. */ 75 76struct bdata 77{ 78 struct info *all; 79 size_t index; 80 size_t max; 81 int failed; 82}; 83 84/* Passed to backtrace_simple callback function. */ 85 86struct sdata 87{ 88 uintptr_t *addrs; 89 size_t index; 90 size_t max; 91 int failed; 92}; 93 94/* Passed to backtrace_syminfo callback function. */ 95 96struct symdata 97{ 98 const char *name; 99 uintptr_t val, size; 100 int failed; 101}; 102 103/* The backtrace state. */ 104 105static void *state; 106 107/* The number of failures. */ 108 109static int failures; 110 111/* Return the base name in a path. */ 112 113static const char * 114base (const char *p) 115{ 116 const char *last; 117 const char *s; 118 119 last = NULL; 120 for (s = p; *s != '\0'; ++s) 121 { 122 if (IS_DIR_SEPARATOR (*s)) 123 last = s + 1; 124 } 125 return last != NULL ? last : p; 126} 127 128/* Check an entry in a struct info array. */ 129 130static void 131check (const char *name, int index, const struct info *all, int want_lineno, 132 const char *want_function, int *failed) 133{ 134 if (*failed) 135 return; 136 if (all[index].filename == NULL || all[index].function == NULL) 137 { 138 fprintf (stderr, "%s: [%d]: missing file name or function name\n", 139 name, index); 140 *failed = 1; 141 return; 142 } 143 if (strcmp (base (all[index].filename), "btest.c") != 0) 144 { 145 fprintf (stderr, "%s: [%d]: got %s expected test.c\n", name, index, 146 all[index].filename); 147 *failed = 1; 148 } 149 if (all[index].lineno != want_lineno) 150 { 151 fprintf (stderr, "%s: [%d]: got %d expected %d\n", name, index, 152 all[index].lineno, want_lineno); 153 *failed = 1; 154 } 155 if (strcmp (all[index].function, want_function) != 0) 156 { 157 fprintf (stderr, "%s: [%d]: got %s expected %s\n", name, index, 158 all[index].function, want_function); 159 *failed = 1; 160 } 161} 162 163/* The backtrace callback function. */ 164 165static int 166callback_one (void *vdata, uintptr_t pc ATTRIBUTE_UNUSED, 167 const char *filename, int lineno, const char *function) 168{ 169 struct bdata *data = (struct bdata *) vdata; 170 struct info *p; 171 172 if (data->index >= data->max) 173 { 174 fprintf (stderr, "callback_one: callback called too many times\n"); 175 data->failed = 1; 176 return 1; 177 } 178 179 p = &data->all[data->index]; 180 if (filename == NULL) 181 p->filename = NULL; 182 else 183 { 184 p->filename = strdup (filename); 185 assert (p->filename != NULL); 186 } 187 p->lineno = lineno; 188 if (function == NULL) 189 p->function = NULL; 190 else 191 { 192 p->function = strdup (function); 193 assert (p->function != NULL); 194 } 195 ++data->index; 196 197 return 0; 198} 199 200/* An error callback passed to backtrace. */ 201 202static void 203error_callback_one (void *vdata, const char *msg, int errnum) 204{ 205 struct bdata *data = (struct bdata *) vdata; 206 207 fprintf (stderr, "%s", msg); 208 if (errnum > 0) 209 fprintf (stderr, ": %s", strerror (errnum)); 210 fprintf (stderr, "\n"); 211 data->failed = 1; 212} 213 214/* The backtrace_simple callback function. */ 215 216static int 217callback_two (void *vdata, uintptr_t pc) 218{ 219 struct sdata *data = (struct sdata *) vdata; 220 221 if (data->index >= data->max) 222 { 223 fprintf (stderr, "callback_two: callback called too many times\n"); 224 data->failed = 1; 225 return 1; 226 } 227 228 data->addrs[data->index] = pc; 229 ++data->index; 230 231 return 0; 232} 233 234/* An error callback passed to backtrace_simple. */ 235 236static void 237error_callback_two (void *vdata, const char *msg, int errnum) 238{ 239 struct sdata *data = (struct sdata *) vdata; 240 241 fprintf (stderr, "%s", msg); 242 if (errnum > 0) 243 fprintf (stderr, ": %s", strerror (errnum)); 244 fprintf (stderr, "\n"); 245 data->failed = 1; 246} 247 248/* The backtrace_syminfo callback function. */ 249 250static void 251callback_three (void *vdata, uintptr_t pc ATTRIBUTE_UNUSED, 252 const char *symname, uintptr_t symval, 253 uintptr_t symsize) 254{ 255 struct symdata *data = (struct symdata *) vdata; 256 257 if (symname == NULL) 258 data->name = NULL; 259 else 260 { 261 data->name = strdup (symname); 262 assert (data->name != NULL); 263 } 264 data->val = symval; 265 data->size = symsize; 266} 267 268/* The backtrace_syminfo error callback function. */ 269 270static void 271error_callback_three (void *vdata, const char *msg, int errnum) 272{ 273 struct symdata *data = (struct symdata *) vdata; 274 275 fprintf (stderr, "%s", msg); 276 if (errnum > 0) 277 fprintf (stderr, ": %s", strerror (errnum)); 278 fprintf (stderr, "\n"); 279 data->failed = 1; 280} 281 282/* Test the backtrace function with non-inlined functions. */ 283 284static int test1 (void) __attribute__ ((noinline, unused)); 285static int f2 (int) __attribute__ ((noinline)); 286static int f3 (int, int) __attribute__ ((noinline)); 287 288static int 289test1 (void) 290{ 291 /* Returning a value here and elsewhere avoids a tailcall which 292 would mess up the backtrace. */ 293 return f2 (__LINE__) + 1; 294} 295 296static int 297f2 (int f1line) 298{ 299 return f3 (f1line, __LINE__) + 2; 300} 301 302static int 303f3 (int f1line, int f2line) 304{ 305 struct info all[20]; 306 struct bdata data; 307 int f3line; 308 int i; 309 310 data.all = &all[0]; 311 data.index = 0; 312 data.max = 20; 313 data.failed = 0; 314 315 f3line = __LINE__ + 1; 316 i = backtrace_full (state, 0, callback_one, error_callback_one, &data); 317 318 if (i != 0) 319 { 320 fprintf (stderr, "test1: unexpected return value %d\n", i); 321 data.failed = 1; 322 } 323 324 if (data.index < 3) 325 { 326 fprintf (stderr, 327 "test1: not enough frames; got %zu, expected at least 3\n", 328 data.index); 329 data.failed = 1; 330 } 331 332 check ("test1", 0, all, f3line, "f3", &data.failed); 333 check ("test1", 1, all, f2line, "f2", &data.failed); 334 check ("test1", 2, all, f1line, "test1", &data.failed); 335 336 printf ("%s: backtrace_full noinline\n", data.failed ? "FAIL" : "PASS"); 337 338 if (data.failed) 339 ++failures; 340 341 return failures; 342} 343 344/* Test the backtrace function with inlined functions. */ 345 346static inline int test2 (void) __attribute__ ((always_inline, unused)); 347static inline int f12 (int) __attribute__ ((always_inline)); 348static inline int f13 (int, int) __attribute__ ((always_inline)); 349 350static inline int 351test2 (void) 352{ 353 return f12 (__LINE__) + 1; 354} 355 356static inline int 357f12 (int f1line) 358{ 359 return f13 (f1line, __LINE__) + 2; 360} 361 362static inline int 363f13 (int f1line, int f2line) 364{ 365 struct info all[20]; 366 struct bdata data; 367 int f3line; 368 int i; 369 370 data.all = &all[0]; 371 data.index = 0; 372 data.max = 20; 373 data.failed = 0; 374 375 f3line = __LINE__ + 1; 376 i = backtrace_full (state, 0, callback_one, error_callback_one, &data); 377 378 if (i != 0) 379 { 380 fprintf (stderr, "test2: unexpected return value %d\n", i); 381 data.failed = 1; 382 } 383 384 check ("test2", 0, all, f3line, "f13", &data.failed); 385 check ("test2", 1, all, f2line, "f12", &data.failed); 386 check ("test2", 2, all, f1line, "test2", &data.failed); 387 388 printf ("%s: backtrace_full inline\n", data.failed ? "FAIL" : "PASS"); 389 390 if (data.failed) 391 ++failures; 392 393 return failures; 394} 395 396/* Test the backtrace_simple function with non-inlined functions. */ 397 398static int test3 (void) __attribute__ ((noinline, unused)); 399static int f22 (int) __attribute__ ((noinline)); 400static int f23 (int, int) __attribute__ ((noinline)); 401 402static int 403test3 (void) 404{ 405 return f22 (__LINE__) + 1; 406} 407 408static int 409f22 (int f1line) 410{ 411 return f23 (f1line, __LINE__) + 2; 412} 413 414static int 415f23 (int f1line, int f2line) 416{ 417 uintptr_t addrs[20]; 418 struct sdata data; 419 int f3line; 420 int i; 421 422 data.addrs = &addrs[0]; 423 data.index = 0; 424 data.max = 20; 425 data.failed = 0; 426 427 f3line = __LINE__ + 1; 428 i = backtrace_simple (state, 0, callback_two, error_callback_two, &data); 429 430 if (i != 0) 431 { 432 fprintf (stderr, "test3: unexpected return value %d\n", i); 433 data.failed = 1; 434 } 435 436 if (!data.failed) 437 { 438 struct info all[20]; 439 struct bdata bdata; 440 int j; 441 442 bdata.all = &all[0]; 443 bdata.index = 0; 444 bdata.max = 20; 445 bdata.failed = 0; 446 447 for (j = 0; j < 3; ++j) 448 { 449 i = backtrace_pcinfo (state, addrs[j], callback_one, 450 error_callback_one, &bdata); 451 if (i != 0) 452 { 453 fprintf (stderr, 454 ("test3: unexpected return value " 455 "from backtrace_pcinfo %d\n"), 456 i); 457 bdata.failed = 1; 458 } 459 if (!bdata.failed && bdata.index != (size_t) (j + 1)) 460 { 461 fprintf (stderr, 462 ("wrong number of calls from backtrace_pcinfo " 463 "got %u expected %d\n"), 464 (unsigned int) bdata.index, j + 1); 465 bdata.failed = 1; 466 } 467 } 468 469 check ("test3", 0, all, f3line, "f23", &bdata.failed); 470 check ("test3", 1, all, f2line, "f22", &bdata.failed); 471 check ("test3", 2, all, f1line, "test3", &bdata.failed); 472 473 if (bdata.failed) 474 data.failed = 1; 475 476 for (j = 0; j < 3; ++j) 477 { 478 struct symdata symdata; 479 480 symdata.name = NULL; 481 symdata.val = 0; 482 symdata.size = 0; 483 symdata.failed = 0; 484 485 i = backtrace_syminfo (state, addrs[j], callback_three, 486 error_callback_three, &symdata); 487 if (i == 0) 488 { 489 fprintf (stderr, 490 ("test3: [%d]: unexpected return value " 491 "from backtrace_syminfo %d\n"), 492 j, i); 493 symdata.failed = 1; 494 } 495 496 if (!symdata.failed) 497 { 498 const char *expected; 499 500 switch (j) 501 { 502 case 0: 503 expected = "f23"; 504 break; 505 case 1: 506 expected = "f22"; 507 break; 508 case 2: 509 expected = "test3"; 510 break; 511 default: 512 assert (0); 513 } 514 515 if (symdata.name == NULL) 516 { 517 fprintf (stderr, "test3: [%d]: NULL syminfo name\n", j); 518 symdata.failed = 1; 519 } 520 /* Use strncmp, not strcmp, because GCC might create a 521 clone. */ 522 else if (strncmp (symdata.name, expected, strlen (expected)) 523 != 0) 524 { 525 fprintf (stderr, 526 ("test3: [%d]: unexpected syminfo name " 527 "got %s expected %s\n"), 528 j, symdata.name, expected); 529 symdata.failed = 1; 530 } 531 } 532 533 if (symdata.failed) 534 data.failed = 1; 535 } 536 } 537 538 printf ("%s: backtrace_simple noinline\n", data.failed ? "FAIL" : "PASS"); 539 540 if (data.failed) 541 ++failures; 542 543 return failures; 544} 545 546/* Test the backtrace_simple function with inlined functions. */ 547 548static inline int test4 (void) __attribute__ ((always_inline, unused)); 549static inline int f32 (int) __attribute__ ((always_inline)); 550static inline int f33 (int, int) __attribute__ ((always_inline)); 551 552static inline int 553test4 (void) 554{ 555 return f32 (__LINE__) + 1; 556} 557 558static inline int 559f32 (int f1line) 560{ 561 return f33 (f1line, __LINE__) + 2; 562} 563 564static inline int 565f33 (int f1line, int f2line) 566{ 567 uintptr_t addrs[20]; 568 struct sdata data; 569 int f3line; 570 int i; 571 572 data.addrs = &addrs[0]; 573 data.index = 0; 574 data.max = 20; 575 data.failed = 0; 576 577 f3line = __LINE__ + 1; 578 i = backtrace_simple (state, 0, callback_two, error_callback_two, &data); 579 580 if (i != 0) 581 { 582 fprintf (stderr, "test3: unexpected return value %d\n", i); 583 data.failed = 1; 584 } 585 586 if (!data.failed) 587 { 588 struct info all[20]; 589 struct bdata bdata; 590 591 bdata.all = &all[0]; 592 bdata.index = 0; 593 bdata.max = 20; 594 bdata.failed = 0; 595 596 i = backtrace_pcinfo (state, addrs[0], callback_one, error_callback_one, 597 &bdata); 598 if (i != 0) 599 { 600 fprintf (stderr, 601 ("test4: unexpected return value " 602 "from backtrace_pcinfo %d\n"), 603 i); 604 bdata.failed = 1; 605 } 606 607 check ("test4", 0, all, f3line, "f33", &bdata.failed); 608 check ("test4", 1, all, f2line, "f32", &bdata.failed); 609 check ("test4", 2, all, f1line, "test4", &bdata.failed); 610 611 if (bdata.failed) 612 data.failed = 1; 613 } 614 615 printf ("%s: backtrace_simple inline\n", data.failed ? "FAIL" : "PASS"); 616 617 if (data.failed) 618 ++failures; 619 620 return failures; 621} 622 623#if BACKTRACE_SUPPORTS_DATA 624 625int global = 1; 626 627static int 628test5 (void) 629{ 630 struct symdata symdata; 631 int i; 632 uintptr_t addr = (uintptr_t) &global; 633 634 if (sizeof (global) > 1) 635 addr += 1; 636 637 symdata.name = NULL; 638 symdata.val = 0; 639 symdata.size = 0; 640 symdata.failed = 0; 641 642 i = backtrace_syminfo (state, addr, callback_three, 643 error_callback_three, &symdata); 644 if (i == 0) 645 { 646 fprintf (stderr, 647 "test5: unexpected return value from backtrace_syminfo %d\n", 648 i); 649 symdata.failed = 1; 650 } 651 652 if (!symdata.failed) 653 { 654 if (symdata.name == NULL) 655 { 656 fprintf (stderr, "test5: NULL syminfo name\n"); 657 symdata.failed = 1; 658 } 659 else if (strcmp (symdata.name, "global") != 0) 660 { 661 fprintf (stderr, 662 "test5: unexpected syminfo name got %s expected %s\n", 663 symdata.name, "global"); 664 symdata.failed = 1; 665 } 666 else if (symdata.val != (uintptr_t) &global) 667 { 668 fprintf (stderr, 669 "test5: unexpected syminfo value got %lx expected %lx\n", 670 (unsigned long) symdata.val, 671 (unsigned long) (uintptr_t) &global); 672 symdata.failed = 1; 673 } 674 else if (symdata.size != sizeof (global)) 675 { 676 fprintf (stderr, 677 "test5: unexpected syminfo size got %lx expected %lx\n", 678 (unsigned long) symdata.size, 679 (unsigned long) sizeof (global)); 680 symdata.failed = 1; 681 } 682 } 683 684 printf ("%s: backtrace_syminfo variable\n", 685 symdata.failed ? "FAIL" : "PASS"); 686 687 if (symdata.failed) 688 ++failures; 689 690 return failures; 691} 692 693#endif /* BACKTRACE_SUPPORTS_DATA */ 694 695static void 696error_callback_create (void *data ATTRIBUTE_UNUSED, const char *msg, 697 int errnum) 698{ 699 fprintf (stderr, "%s", msg); 700 if (errnum > 0) 701 fprintf (stderr, ": %s", strerror (errnum)); 702 fprintf (stderr, "\n"); 703 exit (EXIT_FAILURE); 704} 705 706/* Run all the tests. */ 707 708int 709main (int argc ATTRIBUTE_UNUSED, char **argv) 710{ 711 state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS, 712 error_callback_create, NULL); 713 714#if BACKTRACE_SUPPORTED 715 test1 (); 716 test2 (); 717 test3 (); 718 test4 (); 719#if BACKTRACE_SUPPORTS_DATA 720 test5 (); 721#endif 722#endif 723 724 exit (failures ? EXIT_FAILURE : EXIT_SUCCESS); 725} 726