1 /* 2 * tools/testing/selftests/kvm/lib/assert.c 3 * 4 * Copyright (C) 2018, Google LLC. 5 * 6 * This work is licensed under the terms of the GNU GPL, version 2. 7 */ 8 9 #define _GNU_SOURCE /* for getline(3) and strchrnul(3)*/ 10 11 #include "test_util.h" 12 13 #include <execinfo.h> 14 #include <sys/syscall.h> 15 16 /* Dumps the current stack trace to stderr. */ 17 static void __attribute__((noinline)) test_dump_stack(void); 18 static void test_dump_stack(void) 19 { 20 /* 21 * Build and run this command: 22 * 23 * addr2line -s -e /proc/$PPID/exe -fpai {backtrace addresses} | \ 24 * grep -v test_dump_stack | cat -n 1>&2 25 * 26 * Note that the spacing is different and there's no newline. 27 */ 28 size_t i; 29 size_t n = 20; 30 void *stack[n]; 31 const char *addr2line = "addr2line -s -e /proc/$PPID/exe -fpai"; 32 const char *pipeline = "|cat -n 1>&2"; 33 char cmd[strlen(addr2line) + strlen(pipeline) + 34 /* N bytes per addr * 2 digits per byte + 1 space per addr: */ 35 n * (((sizeof(void *)) * 2) + 1) + 36 /* Null terminator: */ 37 1]; 38 char *c; 39 40 n = backtrace(stack, n); 41 c = &cmd[0]; 42 c += sprintf(c, "%s", addr2line); 43 /* 44 * Skip the first 3 frames: backtrace, test_dump_stack, and 45 * test_assert. We hope that backtrace isn't inlined and the other two 46 * we've declared noinline. 47 */ 48 for (i = 2; i < n; i++) 49 c += sprintf(c, " %lx", ((unsigned long) stack[i]) - 1); 50 c += sprintf(c, "%s", pipeline); 51 #pragma GCC diagnostic push 52 #pragma GCC diagnostic ignored "-Wunused-result" 53 system(cmd); 54 #pragma GCC diagnostic pop 55 } 56 57 static pid_t gettid(void) 58 { 59 return syscall(SYS_gettid); 60 } 61 62 void __attribute__((noinline)) 63 test_assert(bool exp, const char *exp_str, 64 const char *file, unsigned int line, const char *fmt, ...) 65 { 66 va_list ap; 67 68 if (!(exp)) { 69 va_start(ap, fmt); 70 71 fprintf(stderr, "==== Test Assertion Failure ====\n" 72 " %s:%u: %s\n" 73 " pid=%d tid=%d\n", 74 file, line, exp_str, getpid(), gettid()); 75 test_dump_stack(); 76 if (fmt) { 77 fputs(" ", stderr); 78 vfprintf(stderr, fmt, ap); 79 fputs("\n", stderr); 80 } 81 va_end(ap); 82 83 exit(254); 84 } 85 86 return; 87 } 88