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