1 #include "debug.h"
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <stdint.h>
5 #include "time_utils.h"
6 #if !defined(WIN32) && !defined(_WIN32)
7 #include <sys/wait.h>
8 #include <unistd.h>
9 #include <execinfo.h>
10 #endif // !defined(WIN32) && !defined(_WIN32)
11 
12 #define N_DBG_SWITCH (256)
13 
14 static uint8_t _global_dbg_switch[N_DBG_SWITCH];
15 static void* _global_dbg_addr[N_DBG_SWITCH];
16 static uint64_t _global_dbg_uint64_t[N_DBG_SWITCH];
17 
18 // LCOV_EXCL_START
_dbg_sw_set(int n)19 void _dbg_sw_set(int n)
20 {
21     _global_dbg_switch[n] = 1;
22 }
23 
_dbg_sw_clear(int n)24 void _dbg_sw_clear(int n)
25 {
26     _global_dbg_switch[n] = 0;
27 }
28 
_dbg_set_addr(int n, void *addr)29 void _dbg_set_addr(int n, void *addr)
30 {
31     _global_dbg_addr[n] = addr;
32 }
33 
_dbg_get_addr(int n)34 void * _dbg_get_addr(int n)
35 {
36     return _global_dbg_addr[n];
37 }
38 
_dbg_set_uint64_t(int n, uint64_t val)39 void _dbg_set_uint64_t(int n, uint64_t val)
40 {
41     _global_dbg_uint64_t[n] = val;
42 }
43 
_dbg_get_uint64_t(int n)44 uint64_t _dbg_get_uint64_t(int n)
45 {
46     return _global_dbg_uint64_t[n];
47 }
48 
_dbg_is_sw_set(int n)49 int _dbg_is_sw_set(int n)
50 {
51     return _global_dbg_switch[n];
52 }
53 
dump_backtraces()54 void dump_backtraces() {
55 #ifdef __linux__
56     char my_pid[16];
57     char proc_name[512];
58     sprintf(my_pid, "--pid=%d", getpid());
59     proc_name[readlink("/proc/self/exe", proc_name, 511)] = '\0';
60     printf("Dumping backtrace for %s pid=%s..\n", proc_name, my_pid);
61     int gdb_pid = fork();
62     if (!gdb_pid) { // child process...
63         printf("Running gdb backtrace for %s pid=%s\n", proc_name, my_pid);
64         execlp("gdb", "gdb", "--batch", "-n",
65                "-ex", "thread apply all bt 8",
66                proc_name, my_pid, NULL);
67         abort(); /* If gdb failed to start */
68     } else {
69         int ret_stat;
70         waitpid(gdb_pid, &ret_stat, 0);
71         if (!ret_stat) {
72             fprintf(stderr, "\ngdb dumping successful\n");
73         } else {
74             fprintf(stderr, "\ngdb backtracing incomplete\n");
75         }
76     }
77 #elif !defined(WIN32) && !defined(_WIN32)
78     void *callstack[10];
79     char **backtrace_buf;
80     int frames = backtrace(callstack, 10);
81     backtrace_buf = backtrace_symbols(callstack, frames);
82     if (backtrace_buf) {
83         for (int i = 0; i < frames; ++i) {
84             fprintf(stderr, "%d : %s\n", i, backtrace_buf[i]);
85         } // (no need to free memory as process is crashing)
86     }
87 #endif // __linux__ or WIN32 || _WIN32
88 }
89 
_dbg_assert(int line, const char *file, uint64_t val, uint64_t expected)90 void _dbg_assert(int line, const char *file, uint64_t val, uint64_t expected) {
91     char *hang_process;
92      fprintf(stderr, "Assertion in %p != %p in %s:%d\n",
93             (void *)val, (void *)expected, file, line);
94 
95      dump_backtraces(); // try to dump backtraces, for linux use gdb
96 
97      hang_process = getenv("HANG_ON_ASSERTION");
98      if (hang_process) {
99          fprintf(stderr, "Hanging process...");
100          fprintf(stderr, "\n");
101          while (1) {
102              usleep(1000);
103          }
104      }
105 }
106 // LCOV_EXCL_STOP
107 
108