1 1.1 mrg /* btest.c -- Test for libbacktrace library 2 1.10 mrg Copyright (C) 2012-2022 Free Software Foundation, Inc. 3 1.1 mrg Written by Ian Lance Taylor, Google. 4 1.1 mrg 5 1.1 mrg Redistribution and use in source and binary forms, with or without 6 1.1 mrg modification, are permitted provided that the following conditions are 7 1.1 mrg met: 8 1.1 mrg 9 1.1 mrg (1) Redistributions of source code must retain the above copyright 10 1.6 mrg notice, this list of conditions and the following disclaimer. 11 1.1 mrg 12 1.1 mrg (2) Redistributions in binary form must reproduce the above copyright 13 1.1 mrg notice, this list of conditions and the following disclaimer in 14 1.1 mrg the documentation and/or other materials provided with the 15 1.6 mrg distribution. 16 1.6 mrg 17 1.1 mrg (3) The name of the author may not be used to 18 1.1 mrg endorse or promote products derived from this software without 19 1.1 mrg specific prior written permission. 20 1.1 mrg 21 1.1 mrg THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 1.1 mrg IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 23 1.1 mrg WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 24 1.1 mrg DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 25 1.1 mrg INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 1.1 mrg (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 1.1 mrg SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 1.1 mrg HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 1.1 mrg STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 30 1.1 mrg IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 1.1 mrg POSSIBILITY OF SUCH DAMAGE. */ 32 1.1 mrg 33 1.1 mrg /* This program tests the externally visible interfaces of the 34 1.1 mrg libbacktrace library. */ 35 1.1 mrg 36 1.1 mrg #include <assert.h> 37 1.1 mrg #include <stdio.h> 38 1.1 mrg #include <stdlib.h> 39 1.1 mrg #include <string.h> 40 1.7 mrg #include <unistd.h> 41 1.10 mrg #include <sys/stat.h> 42 1.1 mrg 43 1.1 mrg #include "filenames.h" 44 1.1 mrg 45 1.1 mrg #include "backtrace.h" 46 1.1 mrg #include "backtrace-supported.h" 47 1.1 mrg 48 1.7 mrg #include "testlib.h" 49 1.1 mrg 50 1.1 mrg /* Test the backtrace function with non-inlined functions. */ 51 1.1 mrg 52 1.8 mrg static int test1 (void) __attribute__ ((noinline, noclone, unused)); 53 1.8 mrg static int f2 (int) __attribute__ ((noinline, noclone)); 54 1.8 mrg static int f3 (int, int) __attribute__ ((noinline, noclone)); 55 1.1 mrg 56 1.1 mrg static int 57 1.1 mrg test1 (void) 58 1.1 mrg { 59 1.1 mrg /* Returning a value here and elsewhere avoids a tailcall which 60 1.1 mrg would mess up the backtrace. */ 61 1.1 mrg return f2 (__LINE__) + 1; 62 1.1 mrg } 63 1.1 mrg 64 1.1 mrg static int 65 1.1 mrg f2 (int f1line) 66 1.1 mrg { 67 1.1 mrg return f3 (f1line, __LINE__) + 2; 68 1.1 mrg } 69 1.1 mrg 70 1.1 mrg static int 71 1.1 mrg f3 (int f1line, int f2line) 72 1.1 mrg { 73 1.1 mrg struct info all[20]; 74 1.1 mrg struct bdata data; 75 1.1 mrg int f3line; 76 1.1 mrg int i; 77 1.1 mrg 78 1.1 mrg data.all = &all[0]; 79 1.1 mrg data.index = 0; 80 1.1 mrg data.max = 20; 81 1.1 mrg data.failed = 0; 82 1.1 mrg 83 1.1 mrg f3line = __LINE__ + 1; 84 1.1 mrg i = backtrace_full (state, 0, callback_one, error_callback_one, &data); 85 1.1 mrg 86 1.1 mrg if (i != 0) 87 1.1 mrg { 88 1.1 mrg fprintf (stderr, "test1: unexpected return value %d\n", i); 89 1.1 mrg data.failed = 1; 90 1.1 mrg } 91 1.1 mrg 92 1.3 mrg if (data.index < 3) 93 1.3 mrg { 94 1.3 mrg fprintf (stderr, 95 1.3 mrg "test1: not enough frames; got %zu, expected at least 3\n", 96 1.3 mrg data.index); 97 1.3 mrg data.failed = 1; 98 1.3 mrg } 99 1.3 mrg 100 1.7 mrg check ("test1", 0, all, f3line, "f3", "btest.c", &data.failed); 101 1.7 mrg check ("test1", 1, all, f2line, "f2", "btest.c", &data.failed); 102 1.7 mrg check ("test1", 2, all, f1line, "test1", "btest.c", &data.failed); 103 1.1 mrg 104 1.1 mrg printf ("%s: backtrace_full noinline\n", data.failed ? "FAIL" : "PASS"); 105 1.1 mrg 106 1.1 mrg if (data.failed) 107 1.1 mrg ++failures; 108 1.1 mrg 109 1.1 mrg return failures; 110 1.1 mrg } 111 1.1 mrg 112 1.1 mrg /* Test the backtrace function with inlined functions. */ 113 1.1 mrg 114 1.1 mrg static inline int test2 (void) __attribute__ ((always_inline, unused)); 115 1.1 mrg static inline int f12 (int) __attribute__ ((always_inline)); 116 1.1 mrg static inline int f13 (int, int) __attribute__ ((always_inline)); 117 1.1 mrg 118 1.1 mrg static inline int 119 1.1 mrg test2 (void) 120 1.1 mrg { 121 1.1 mrg return f12 (__LINE__) + 1; 122 1.1 mrg } 123 1.1 mrg 124 1.1 mrg static inline int 125 1.1 mrg f12 (int f1line) 126 1.1 mrg { 127 1.1 mrg return f13 (f1line, __LINE__) + 2; 128 1.1 mrg } 129 1.1 mrg 130 1.1 mrg static inline int 131 1.1 mrg f13 (int f1line, int f2line) 132 1.1 mrg { 133 1.1 mrg struct info all[20]; 134 1.1 mrg struct bdata data; 135 1.1 mrg int f3line; 136 1.1 mrg int i; 137 1.1 mrg 138 1.1 mrg data.all = &all[0]; 139 1.1 mrg data.index = 0; 140 1.1 mrg data.max = 20; 141 1.1 mrg data.failed = 0; 142 1.1 mrg 143 1.1 mrg f3line = __LINE__ + 1; 144 1.1 mrg i = backtrace_full (state, 0, callback_one, error_callback_one, &data); 145 1.1 mrg 146 1.1 mrg if (i != 0) 147 1.1 mrg { 148 1.1 mrg fprintf (stderr, "test2: unexpected return value %d\n", i); 149 1.1 mrg data.failed = 1; 150 1.1 mrg } 151 1.1 mrg 152 1.7 mrg check ("test2", 0, all, f3line, "f13", "btest.c", &data.failed); 153 1.7 mrg check ("test2", 1, all, f2line, "f12", "btest.c", &data.failed); 154 1.7 mrg check ("test2", 2, all, f1line, "test2", "btest.c", &data.failed); 155 1.1 mrg 156 1.1 mrg printf ("%s: backtrace_full inline\n", data.failed ? "FAIL" : "PASS"); 157 1.1 mrg 158 1.1 mrg if (data.failed) 159 1.1 mrg ++failures; 160 1.1 mrg 161 1.1 mrg return failures; 162 1.1 mrg } 163 1.1 mrg 164 1.1 mrg /* Test the backtrace_simple function with non-inlined functions. */ 165 1.1 mrg 166 1.8 mrg static int test3 (void) __attribute__ ((noinline, noclone, unused)); 167 1.8 mrg static int f22 (int) __attribute__ ((noinline, noclone)); 168 1.8 mrg static int f23 (int, int) __attribute__ ((noinline, noclone)); 169 1.1 mrg 170 1.1 mrg static int 171 1.1 mrg test3 (void) 172 1.1 mrg { 173 1.1 mrg return f22 (__LINE__) + 1; 174 1.1 mrg } 175 1.1 mrg 176 1.1 mrg static int 177 1.1 mrg f22 (int f1line) 178 1.1 mrg { 179 1.1 mrg return f23 (f1line, __LINE__) + 2; 180 1.1 mrg } 181 1.1 mrg 182 1.1 mrg static int 183 1.1 mrg f23 (int f1line, int f2line) 184 1.1 mrg { 185 1.1 mrg uintptr_t addrs[20]; 186 1.1 mrg struct sdata data; 187 1.1 mrg int f3line; 188 1.1 mrg int i; 189 1.1 mrg 190 1.1 mrg data.addrs = &addrs[0]; 191 1.1 mrg data.index = 0; 192 1.1 mrg data.max = 20; 193 1.1 mrg data.failed = 0; 194 1.1 mrg 195 1.1 mrg f3line = __LINE__ + 1; 196 1.1 mrg i = backtrace_simple (state, 0, callback_two, error_callback_two, &data); 197 1.1 mrg 198 1.1 mrg if (i != 0) 199 1.1 mrg { 200 1.1 mrg fprintf (stderr, "test3: unexpected return value %d\n", i); 201 1.1 mrg data.failed = 1; 202 1.1 mrg } 203 1.1 mrg 204 1.1 mrg if (!data.failed) 205 1.1 mrg { 206 1.1 mrg struct info all[20]; 207 1.1 mrg struct bdata bdata; 208 1.1 mrg int j; 209 1.1 mrg 210 1.1 mrg bdata.all = &all[0]; 211 1.1 mrg bdata.index = 0; 212 1.1 mrg bdata.max = 20; 213 1.1 mrg bdata.failed = 0; 214 1.1 mrg 215 1.1 mrg for (j = 0; j < 3; ++j) 216 1.1 mrg { 217 1.1 mrg i = backtrace_pcinfo (state, addrs[j], callback_one, 218 1.1 mrg error_callback_one, &bdata); 219 1.1 mrg if (i != 0) 220 1.1 mrg { 221 1.1 mrg fprintf (stderr, 222 1.1 mrg ("test3: unexpected return value " 223 1.1 mrg "from backtrace_pcinfo %d\n"), 224 1.1 mrg i); 225 1.1 mrg bdata.failed = 1; 226 1.1 mrg } 227 1.1 mrg if (!bdata.failed && bdata.index != (size_t) (j + 1)) 228 1.1 mrg { 229 1.1 mrg fprintf (stderr, 230 1.1 mrg ("wrong number of calls from backtrace_pcinfo " 231 1.1 mrg "got %u expected %d\n"), 232 1.1 mrg (unsigned int) bdata.index, j + 1); 233 1.1 mrg bdata.failed = 1; 234 1.1 mrg } 235 1.6 mrg } 236 1.1 mrg 237 1.7 mrg check ("test3", 0, all, f3line, "f23", "btest.c", &bdata.failed); 238 1.7 mrg check ("test3", 1, all, f2line, "f22", "btest.c", &bdata.failed); 239 1.7 mrg check ("test3", 2, all, f1line, "test3", "btest.c", &bdata.failed); 240 1.1 mrg 241 1.1 mrg if (bdata.failed) 242 1.1 mrg data.failed = 1; 243 1.1 mrg 244 1.1 mrg for (j = 0; j < 3; ++j) 245 1.1 mrg { 246 1.1 mrg struct symdata symdata; 247 1.1 mrg 248 1.1 mrg symdata.name = NULL; 249 1.1 mrg symdata.val = 0; 250 1.3 mrg symdata.size = 0; 251 1.1 mrg symdata.failed = 0; 252 1.1 mrg 253 1.1 mrg i = backtrace_syminfo (state, addrs[j], callback_three, 254 1.1 mrg error_callback_three, &symdata); 255 1.1 mrg if (i == 0) 256 1.1 mrg { 257 1.1 mrg fprintf (stderr, 258 1.1 mrg ("test3: [%d]: unexpected return value " 259 1.1 mrg "from backtrace_syminfo %d\n"), 260 1.1 mrg j, i); 261 1.1 mrg symdata.failed = 1; 262 1.1 mrg } 263 1.1 mrg 264 1.1 mrg if (!symdata.failed) 265 1.1 mrg { 266 1.1 mrg const char *expected; 267 1.1 mrg 268 1.1 mrg switch (j) 269 1.1 mrg { 270 1.1 mrg case 0: 271 1.1 mrg expected = "f23"; 272 1.1 mrg break; 273 1.1 mrg case 1: 274 1.1 mrg expected = "f22"; 275 1.1 mrg break; 276 1.1 mrg case 2: 277 1.1 mrg expected = "test3"; 278 1.1 mrg break; 279 1.1 mrg default: 280 1.1 mrg assert (0); 281 1.1 mrg } 282 1.1 mrg 283 1.1 mrg if (symdata.name == NULL) 284 1.1 mrg { 285 1.1 mrg fprintf (stderr, "test3: [%d]: NULL syminfo name\n", j); 286 1.1 mrg symdata.failed = 1; 287 1.1 mrg } 288 1.1 mrg /* Use strncmp, not strcmp, because GCC might create a 289 1.1 mrg clone. */ 290 1.1 mrg else if (strncmp (symdata.name, expected, strlen (expected)) 291 1.1 mrg != 0) 292 1.1 mrg { 293 1.1 mrg fprintf (stderr, 294 1.1 mrg ("test3: [%d]: unexpected syminfo name " 295 1.1 mrg "got %s expected %s\n"), 296 1.1 mrg j, symdata.name, expected); 297 1.1 mrg symdata.failed = 1; 298 1.1 mrg } 299 1.1 mrg } 300 1.1 mrg 301 1.1 mrg if (symdata.failed) 302 1.1 mrg data.failed = 1; 303 1.1 mrg } 304 1.1 mrg } 305 1.1 mrg 306 1.1 mrg printf ("%s: backtrace_simple noinline\n", data.failed ? "FAIL" : "PASS"); 307 1.1 mrg 308 1.1 mrg if (data.failed) 309 1.1 mrg ++failures; 310 1.1 mrg 311 1.1 mrg return failures; 312 1.1 mrg } 313 1.1 mrg 314 1.1 mrg /* Test the backtrace_simple function with inlined functions. */ 315 1.1 mrg 316 1.1 mrg static inline int test4 (void) __attribute__ ((always_inline, unused)); 317 1.1 mrg static inline int f32 (int) __attribute__ ((always_inline)); 318 1.1 mrg static inline int f33 (int, int) __attribute__ ((always_inline)); 319 1.1 mrg 320 1.1 mrg static inline int 321 1.1 mrg test4 (void) 322 1.1 mrg { 323 1.1 mrg return f32 (__LINE__) + 1; 324 1.1 mrg } 325 1.1 mrg 326 1.1 mrg static inline int 327 1.1 mrg f32 (int f1line) 328 1.1 mrg { 329 1.1 mrg return f33 (f1line, __LINE__) + 2; 330 1.1 mrg } 331 1.1 mrg 332 1.1 mrg static inline int 333 1.1 mrg f33 (int f1line, int f2line) 334 1.1 mrg { 335 1.1 mrg uintptr_t addrs[20]; 336 1.1 mrg struct sdata data; 337 1.1 mrg int f3line; 338 1.1 mrg int i; 339 1.1 mrg 340 1.1 mrg data.addrs = &addrs[0]; 341 1.1 mrg data.index = 0; 342 1.1 mrg data.max = 20; 343 1.1 mrg data.failed = 0; 344 1.1 mrg 345 1.1 mrg f3line = __LINE__ + 1; 346 1.1 mrg i = backtrace_simple (state, 0, callback_two, error_callback_two, &data); 347 1.1 mrg 348 1.1 mrg if (i != 0) 349 1.1 mrg { 350 1.1 mrg fprintf (stderr, "test3: unexpected return value %d\n", i); 351 1.1 mrg data.failed = 1; 352 1.1 mrg } 353 1.1 mrg 354 1.1 mrg if (!data.failed) 355 1.1 mrg { 356 1.1 mrg struct info all[20]; 357 1.1 mrg struct bdata bdata; 358 1.1 mrg 359 1.1 mrg bdata.all = &all[0]; 360 1.1 mrg bdata.index = 0; 361 1.1 mrg bdata.max = 20; 362 1.1 mrg bdata.failed = 0; 363 1.1 mrg 364 1.1 mrg i = backtrace_pcinfo (state, addrs[0], callback_one, error_callback_one, 365 1.1 mrg &bdata); 366 1.1 mrg if (i != 0) 367 1.1 mrg { 368 1.1 mrg fprintf (stderr, 369 1.1 mrg ("test4: unexpected return value " 370 1.1 mrg "from backtrace_pcinfo %d\n"), 371 1.1 mrg i); 372 1.1 mrg bdata.failed = 1; 373 1.1 mrg } 374 1.1 mrg 375 1.7 mrg check ("test4", 0, all, f3line, "f33", "btest.c", &bdata.failed); 376 1.7 mrg check ("test4", 1, all, f2line, "f32", "btest.c", &bdata.failed); 377 1.7 mrg check ("test4", 2, all, f1line, "test4", "btest.c", &bdata.failed); 378 1.1 mrg 379 1.1 mrg if (bdata.failed) 380 1.1 mrg data.failed = 1; 381 1.1 mrg } 382 1.1 mrg 383 1.1 mrg printf ("%s: backtrace_simple inline\n", data.failed ? "FAIL" : "PASS"); 384 1.1 mrg 385 1.1 mrg if (data.failed) 386 1.1 mrg ++failures; 387 1.1 mrg 388 1.1 mrg return failures; 389 1.1 mrg } 390 1.1 mrg 391 1.6 mrg static int test5 (void) __attribute__ ((unused)); 392 1.4 mrg 393 1.3 mrg int global = 1; 394 1.3 mrg 395 1.3 mrg static int 396 1.3 mrg test5 (void) 397 1.3 mrg { 398 1.3 mrg struct symdata symdata; 399 1.3 mrg int i; 400 1.3 mrg uintptr_t addr = (uintptr_t) &global; 401 1.3 mrg 402 1.3 mrg if (sizeof (global) > 1) 403 1.3 mrg addr += 1; 404 1.3 mrg 405 1.3 mrg symdata.name = NULL; 406 1.3 mrg symdata.val = 0; 407 1.3 mrg symdata.size = 0; 408 1.3 mrg symdata.failed = 0; 409 1.3 mrg 410 1.3 mrg i = backtrace_syminfo (state, addr, callback_three, 411 1.3 mrg error_callback_three, &symdata); 412 1.3 mrg if (i == 0) 413 1.3 mrg { 414 1.3 mrg fprintf (stderr, 415 1.3 mrg "test5: unexpected return value from backtrace_syminfo %d\n", 416 1.3 mrg i); 417 1.3 mrg symdata.failed = 1; 418 1.3 mrg } 419 1.3 mrg 420 1.3 mrg if (!symdata.failed) 421 1.3 mrg { 422 1.3 mrg if (symdata.name == NULL) 423 1.3 mrg { 424 1.3 mrg fprintf (stderr, "test5: NULL syminfo name\n"); 425 1.3 mrg symdata.failed = 1; 426 1.3 mrg } 427 1.8 mrg else if (!(strncmp (symdata.name, "global", 6) == 0 428 1.8 mrg && (symdata.name[6] == '\0'|| symdata.name[6] == '.'))) 429 1.3 mrg { 430 1.3 mrg fprintf (stderr, 431 1.3 mrg "test5: unexpected syminfo name got %s expected %s\n", 432 1.3 mrg symdata.name, "global"); 433 1.3 mrg symdata.failed = 1; 434 1.3 mrg } 435 1.3 mrg else if (symdata.val != (uintptr_t) &global) 436 1.3 mrg { 437 1.3 mrg fprintf (stderr, 438 1.3 mrg "test5: unexpected syminfo value got %lx expected %lx\n", 439 1.3 mrg (unsigned long) symdata.val, 440 1.3 mrg (unsigned long) (uintptr_t) &global); 441 1.3 mrg symdata.failed = 1; 442 1.3 mrg } 443 1.3 mrg else if (symdata.size != sizeof (global)) 444 1.3 mrg { 445 1.3 mrg fprintf (stderr, 446 1.3 mrg "test5: unexpected syminfo size got %lx expected %lx\n", 447 1.3 mrg (unsigned long) symdata.size, 448 1.3 mrg (unsigned long) sizeof (global)); 449 1.3 mrg symdata.failed = 1; 450 1.3 mrg } 451 1.3 mrg } 452 1.3 mrg 453 1.3 mrg printf ("%s: backtrace_syminfo variable\n", 454 1.3 mrg symdata.failed ? "FAIL" : "PASS"); 455 1.3 mrg 456 1.3 mrg if (symdata.failed) 457 1.3 mrg ++failures; 458 1.3 mrg 459 1.3 mrg return failures; 460 1.3 mrg } 461 1.3 mrg 462 1.10 mrg #define MIN_DESCRIPTOR 3 463 1.10 mrg #define MAX_DESCRIPTOR 10 464 1.10 mrg 465 1.10 mrg static int fstat_status[MAX_DESCRIPTOR]; 466 1.10 mrg 467 1.10 mrg /* Check files that are available. */ 468 1.10 mrg 469 1.10 mrg static void 470 1.10 mrg check_available_files (void) 471 1.10 mrg { 472 1.10 mrg struct stat s; 473 1.10 mrg for (unsigned i = MIN_DESCRIPTOR; i < MAX_DESCRIPTOR; i++) 474 1.10 mrg fstat_status[i] = fstat (i, &s); 475 1.10 mrg } 476 1.10 mrg 477 1.7 mrg /* Check that are no files left open. */ 478 1.7 mrg 479 1.1 mrg static void 480 1.7 mrg check_open_files (void) 481 1.1 mrg { 482 1.10 mrg for (unsigned i = MIN_DESCRIPTOR; i < MAX_DESCRIPTOR; i++) 483 1.7 mrg { 484 1.10 mrg if (fstat_status[i] != 0 && close (i) == 0) 485 1.7 mrg { 486 1.7 mrg fprintf (stderr, 487 1.7 mrg "ERROR: descriptor %d still open after tests complete\n", 488 1.7 mrg i); 489 1.7 mrg ++failures; 490 1.7 mrg } 491 1.7 mrg } 492 1.1 mrg } 493 1.1 mrg 494 1.1 mrg /* Run all the tests. */ 495 1.1 mrg 496 1.1 mrg int 497 1.1 mrg main (int argc ATTRIBUTE_UNUSED, char **argv) 498 1.1 mrg { 499 1.10 mrg check_available_files (); 500 1.10 mrg 501 1.1 mrg state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS, 502 1.1 mrg error_callback_create, NULL); 503 1.1 mrg 504 1.1 mrg #if BACKTRACE_SUPPORTED 505 1.1 mrg test1 (); 506 1.1 mrg test2 (); 507 1.1 mrg test3 (); 508 1.1 mrg test4 (); 509 1.4 mrg #if BACKTRACE_SUPPORTS_DATA 510 1.3 mrg test5 (); 511 1.1 mrg #endif 512 1.4 mrg #endif 513 1.1 mrg 514 1.7 mrg check_open_files (); 515 1.7 mrg 516 1.1 mrg exit (failures ? EXIT_FAILURE : EXIT_SUCCESS); 517 1.1 mrg } 518