162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * tools/testing/selftests/kvm/lib/assert.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2018, Google LLC. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#define _GNU_SOURCE /* for getline(3) and strchrnul(3)*/ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include "test_util.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <execinfo.h> 1362306a36Sopenharmony_ci#include <sys/syscall.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include "kselftest.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/* Dumps the current stack trace to stderr. */ 1862306a36Sopenharmony_cistatic void __attribute__((noinline)) test_dump_stack(void); 1962306a36Sopenharmony_cistatic void test_dump_stack(void) 2062306a36Sopenharmony_ci{ 2162306a36Sopenharmony_ci /* 2262306a36Sopenharmony_ci * Build and run this command: 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * addr2line -s -e /proc/$PPID/exe -fpai {backtrace addresses} | \ 2562306a36Sopenharmony_ci * cat -n 1>&2 2662306a36Sopenharmony_ci * 2762306a36Sopenharmony_ci * Note that the spacing is different and there's no newline. 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_ci size_t i; 3062306a36Sopenharmony_ci size_t n = 20; 3162306a36Sopenharmony_ci void *stack[n]; 3262306a36Sopenharmony_ci const char *addr2line = "addr2line -s -e /proc/$PPID/exe -fpai"; 3362306a36Sopenharmony_ci const char *pipeline = "|cat -n 1>&2"; 3462306a36Sopenharmony_ci char cmd[strlen(addr2line) + strlen(pipeline) + 3562306a36Sopenharmony_ci /* N bytes per addr * 2 digits per byte + 1 space per addr: */ 3662306a36Sopenharmony_ci n * (((sizeof(void *)) * 2) + 1) + 3762306a36Sopenharmony_ci /* Null terminator: */ 3862306a36Sopenharmony_ci 1]; 3962306a36Sopenharmony_ci char *c = cmd; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci n = backtrace(stack, n); 4262306a36Sopenharmony_ci /* 4362306a36Sopenharmony_ci * Skip the first 2 frames, which should be test_dump_stack() and 4462306a36Sopenharmony_ci * test_assert(); both of which are declared noinline. Bail if the 4562306a36Sopenharmony_ci * resulting stack trace would be empty. Otherwise, addr2line will block 4662306a36Sopenharmony_ci * waiting for addresses to be passed in via stdin. 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_ci if (n <= 2) { 4962306a36Sopenharmony_ci fputs(" (stack trace empty)\n", stderr); 5062306a36Sopenharmony_ci return; 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci c += sprintf(c, "%s", addr2line); 5462306a36Sopenharmony_ci for (i = 2; i < n; i++) 5562306a36Sopenharmony_ci c += sprintf(c, " %lx", ((unsigned long) stack[i]) - 1); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci c += sprintf(c, "%s", pipeline); 5862306a36Sopenharmony_ci#pragma GCC diagnostic push 5962306a36Sopenharmony_ci#pragma GCC diagnostic ignored "-Wunused-result" 6062306a36Sopenharmony_ci system(cmd); 6162306a36Sopenharmony_ci#pragma GCC diagnostic pop 6262306a36Sopenharmony_ci} 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_cistatic pid_t _gettid(void) 6562306a36Sopenharmony_ci{ 6662306a36Sopenharmony_ci return syscall(SYS_gettid); 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_civoid __attribute__((noinline)) 7062306a36Sopenharmony_citest_assert(bool exp, const char *exp_str, 7162306a36Sopenharmony_ci const char *file, unsigned int line, const char *fmt, ...) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci va_list ap; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci if (!(exp)) { 7662306a36Sopenharmony_ci va_start(ap, fmt); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci fprintf(stderr, "==== Test Assertion Failure ====\n" 7962306a36Sopenharmony_ci " %s:%u: %s\n" 8062306a36Sopenharmony_ci " pid=%d tid=%d errno=%d - %s\n", 8162306a36Sopenharmony_ci file, line, exp_str, getpid(), _gettid(), 8262306a36Sopenharmony_ci errno, strerror(errno)); 8362306a36Sopenharmony_ci test_dump_stack(); 8462306a36Sopenharmony_ci if (fmt) { 8562306a36Sopenharmony_ci fputs(" ", stderr); 8662306a36Sopenharmony_ci vfprintf(stderr, fmt, ap); 8762306a36Sopenharmony_ci fputs("\n", stderr); 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci va_end(ap); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (errno == EACCES) { 9262306a36Sopenharmony_ci print_skip("Access denied - Exiting"); 9362306a36Sopenharmony_ci exit(KSFT_SKIP); 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci exit(254); 9662306a36Sopenharmony_ci } 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci return; 9962306a36Sopenharmony_ci} 100