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