at v4.17 87 lines 2.0 kB view raw
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. */ 17static void __attribute__((noinline)) test_dump_stack(void); 18static 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 57static pid_t gettid(void) 58{ 59 return syscall(SYS_gettid); 60} 61 62void __attribute__((noinline)) 63test_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}