Direct-BT  2.3.1
Direct-BT - Direct Bluetooth Programming.
debug.cpp
Go to the documentation of this file.
1 /*
2  * Author: Sven Gothel <sgothel@jausoft.com>
3  * Copyright (c) 2020 Gothel Software e.K.
4  * Copyright (c) 2020 ZAFENA AB
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining
7  * a copy of this software and associated documentation files (the
8  * "Software"), to deal in the Software without restriction, including
9  * without limitation the rights to use, copy, modify, merge, publish,
10  * distribute, sublicense, and/or sell copies of the Software, and to
11  * permit persons to whom the Software is furnished to do so, subject to
12  * the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be
15  * included in all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25 
26 #include <jau/debug.hpp>
27 
28 #include <cstdarg>
29 
30 #define UNW_LOCAL_ONLY
31 #include <libunwind.h>
32 #include <cxxabi.h>
33 
34 using namespace jau;
35 
36 std::string jau::get_backtrace(const bool skip_anon_frames, const jau::snsize_t max_frames, const jau::nsize_t skip_frames) noexcept {
37  // symbol:
38  // 1: _ZN9direct_bt10DBTAdapter14startDiscoveryEbNS_19HCILEOwnAddressTypeEtt + 0x58d @ ip 0x7faa959d6daf, sp 0x7ffe38f301e0
39  // de-mangled:
40  // 1: direct_bt::DBTAdapter::startDiscovery(bool, direct_bt::HCILEOwnAddressType, unsigned short, unsigned short) + 0x58d @ ip 0x7f687b459071, sp 0x7fff2bf795d0
41  std::string out;
42  jau::nsize_t frame=0;
43  int res;
44  char cstr[256];
45  unw_context_t uc;
46  unw_word_t ip, sp;
47  unw_cursor_t cursor;
48  unw_word_t offset;
49  unw_getcontext(&uc);
50  unw_init_local(&cursor, &uc);
51  bool last_frame_anon = false;
52  while( unw_step(&cursor) > 0 && ( max_frames - skip_frames ) > frame ) {
53  frame++;
54  if( skip_frames > frame ) {
55  continue;
56  }
57  bool append_line;
58  snprintf(cstr, sizeof(cstr), "%3zu: ", (size_t)frame);
59  std::string line(cstr);
60 
61  unw_get_reg(&cursor, UNW_REG_IP, &ip); // instruction pointer (pc)
62  unw_get_reg(&cursor, UNW_REG_SP, &sp); // stack pointer
63  if( 0 == ( res = unw_get_proc_name(&cursor, cstr, sizeof(cstr), &offset) ) ) {
64  int status;
65  char *real_name;
66  cstr[sizeof(cstr) -1] = 0; // fail safe
67  if ( (real_name = abi::__cxa_demangle(cstr, nullptr, nullptr, &status)) == nullptr ) {
68  line.append(cstr); // didn't work, use cstr
69  } else {
70  line.append(real_name);
71  free( real_name );
72  }
73  snprintf(cstr, sizeof(cstr), " + 0x%lx @ ip %p, sp %p", (unsigned long)offset, (void*)ip, (void*)sp);
74  append_line = true;
75  last_frame_anon = false;
76  } else {
77  // anon frame w/o proc-name
78  snprintf(cstr, sizeof(cstr), "__no_proc_name__ @ ip %p, sp %p", (void*)ip, (void*)sp);
79  append_line = !skip_anon_frames || !last_frame_anon;
80  last_frame_anon = true;
81  }
82  line.append(cstr);
83  line.append("\n");
84  if( append_line ) {
85  out.append(line);
86  }
87  }
88  return out;
89 }
90 
91 void jau::print_backtrace(const bool skip_anon_frames, const jau::snsize_t max_frames, const jau::nsize_t skip_frames) noexcept {
92  fprintf(stderr, "%s", get_backtrace(skip_anon_frames, max_frames, skip_frames).c_str());
93  fflush(stderr);
94 }
95 
96 void jau::DBG_PRINT_impl(const char * format, ...) noexcept {
97  fprintf(stderr, "[%s] Debug: ", jau::to_decstring(environment::getElapsedMillisecond(), ',', 9).c_str());
98  va_list args;
99  va_start (args, format);
100  vfprintf(stderr, format, args);
101  va_end (args);
102  fprintf(stderr, "\n");
103  fflush(stderr);
104 }
105 
106 void jau::WORDY_PRINT_impl(const char * format, ...) noexcept {
107  fprintf(stderr, "[%s] Wordy: ", jau::to_decstring(environment::getElapsedMillisecond(), ',', 9).c_str());
108  va_list args;
109  va_start (args, format);
110  vfprintf(stderr, format, args);
111  va_end (args);
112  fprintf(stderr, "\n");
113  fflush(stderr);
114 }
115 
116 void jau::ABORT_impl(const char *func, const char *file, const int line, const char * format, ...) noexcept {
117  fprintf(stderr, "[%s] ABORT @ %s:%d %s: ", jau::to_decstring(environment::getElapsedMillisecond(), ',', 9).c_str(), file, line, func);
118  va_list args;
119  va_start (args, format);
120  vfprintf(stderr, format, args);
121  va_end (args);
122  fprintf(stderr, "; last errno %d %s\n", errno, strerror(errno));
123  fflush(stderr);
124  jau::print_backtrace(true, 2);
125  abort();
126 }
127 
128 void jau::ERR_PRINTv(const char *func, const char *file, const int line, const char * format, va_list args) noexcept {
129  fprintf(stderr, "[%s] Error @ %s:%d %s: ", jau::to_decstring(environment::getElapsedMillisecond(), ',', 9).c_str(), file, line, func);
130  vfprintf(stderr, format, args);
131  fprintf(stderr, "; last errno %d %s\n", errno, strerror(errno));
132  fflush(stderr);
133  jau::print_backtrace(true, 2);
134 }
135 
136 void jau::ERR_PRINT_impl(const char *prefix, const bool backtrace, const char *func, const char *file, const int line, const char * format, ...) noexcept {
137  fprintf(stderr, "[%s] %s @ %s:%d %s: ", jau::to_decstring(environment::getElapsedMillisecond(), ',', 9).c_str(), prefix, file, line, func);
138  va_list args;
139  va_start (args, format);
140  vfprintf(stderr, format, args);
141  va_end (args);
142  fprintf(stderr, "; last errno %d %s\n", errno, strerror(errno));
143  fflush(stderr);
144  if( backtrace ) {
145  jau::print_backtrace(true, 2);
146  }
147 }
148 
149 void jau::WARN_PRINTv(const char *func, const char *file, const int line, const char * format, va_list args) noexcept {
150  fprintf(stderr, "[%s] Warning @ %s:%d %s: ", jau::to_decstring(environment::getElapsedMillisecond(), ',', 9).c_str(), file, line, func);
151  vfprintf(stderr, format, args);
152  fprintf(stderr, "\n");
153  fflush(stderr);
154 }
155 
156 void jau::WARN_PRINT_impl(const char *func, const char *file, const int line, const char * format, ...) noexcept {
157  fprintf(stderr, "[%s] Warning @ %s:%d %s: ", jau::to_decstring(environment::getElapsedMillisecond(), ',', 9).c_str(), file, line, func);
158  va_list args;
159  va_start (args, format);
160  vfprintf(stderr, format, args);
161  va_end (args);
162  fprintf(stderr, "\n");
163  fflush(stderr);
164 }
165 
166 void jau::INFO_PRINT(const char * format, ...) noexcept {
167  fprintf(stderr, "[%s] Info: ", jau::to_decstring(environment::getElapsedMillisecond(), ',', 9).c_str());
168  va_list args;
169  va_start (args, format);
170  vfprintf(stderr, format, args);
171  va_end (args);
172  fprintf(stderr, "\n");
173  fflush(stderr);
174 }
175 
176 void jau::PLAIN_PRINT(const bool printPrefix, const char * format, ...) noexcept {
177  if( printPrefix ) {
178  fprintf(stderr, "[%s] ", jau::to_decstring(environment::getElapsedMillisecond(), ',', 9).c_str());
179  }
180  va_list args;
181  va_start (args, format);
182  vfprintf(stderr, format, args);
183  va_end (args);
184  fprintf(stderr, "\n");
185  fflush(stderr);
186 }
187 
188 int jau::fprintf_td(FILE* stream, const char * format, ...) noexcept {
189  int res = ::fprintf(stderr, "[%s] ", jau::to_decstring(environment::getElapsedMillisecond(), ',', 9).c_str());
190  va_list args;
191  va_start (args, format);
192  res += ::vfprintf(stream, format, args);
193  va_end (args);
194  return res;
195 }
196 
197 void jau::COND_PRINT_impl(const char * format, ...) noexcept {
198  fprintf(stderr, "[%s] ", jau::to_decstring(environment::getElapsedMillisecond(), ',', 9).c_str());
199  va_list args;
200  va_start (args, format);
201  vfprintf(stderr, format, args);
202  va_end (args);
203  fprintf(stderr, "\n");
204  fflush(stderr);
205 }
jau::to_decstring
std::string to_decstring(const value_type &v, const char separator=',', const nsize_t width=0) noexcept
Produce a decimal string representation of an integral integer value.
Definition: string_util.hpp:143
jau::print_backtrace
void print_backtrace(const bool skip_anon_frames, const jau::snsize_t max_frames=-1, const jau::nsize_t skip_frames=2) noexcept
Prints the de-mangled backtrace string separated by newline excluding this function to stderr,...
Definition: debug.cpp:91
jau::environment::getElapsedMillisecond
static uint64_t getElapsedMillisecond() noexcept
Returns current elapsed monotonic time in milliseconds since module startup, see startupTimeMilliseco...
Definition: environment.hpp:80
jau
Definition: basic_algos.hpp:34
jau::WORDY_PRINT_impl
void WORDY_PRINT_impl(const char *format,...) noexcept
Definition: debug.cpp:106
jau::get_backtrace
std::string get_backtrace(const bool skip_anon_frames, const jau::snsize_t max_frames=-1, const jau::nsize_t skip_frames=1) noexcept
Returns a de-mangled backtrace string separated by newline excluding this function.
Definition: debug.cpp:36
jau::ERR_PRINTv
void ERR_PRINTv(const char *func, const char *file, const int line, const char *format, va_list args) noexcept
Use for unconditional error messages, prefix '[elapsed_time] Error @ file:line: '.
Definition: debug.cpp:128
jau::fprintf_td
int fprintf_td(FILE *stream, const char *format,...) noexcept
Convenient fprintf() invocation, prepending the environment::getElapsedMillisecond() timestamp.
Definition: debug.cpp:188
jau::INFO_PRINT
void INFO_PRINT(const char *format,...) noexcept
Use for unconditional informal messages, prefix '[elapsed_time] Info: '.
Definition: debug.cpp:166
jau::WARN_PRINT_impl
void WARN_PRINT_impl(const char *func, const char *file, const int line, const char *format,...) noexcept
Definition: debug.cpp:156
debug.hpp
jau::PLAIN_PRINT
void PLAIN_PRINT(const bool printPrefix, const char *format,...) noexcept
Use for unconditional plain messages, prefix '[elapsed_time] ' if printPrefix == true.
Definition: debug.cpp:176
jau::snsize_t
int_fast32_t snsize_t
Natural 'ssize_t' alternative using int_fast32_t as its natural sized type.
Definition: int_types.hpp:56
jau::nsize_t
uint_fast32_t nsize_t
Natural 'size_t' alternative using uint_fast32_t as its natural sized type.
Definition: int_types.hpp:44
jau::ERR_PRINT_impl
void ERR_PRINT_impl(const char *prefix, const bool backtrace, const char *func, const char *file, const int line, const char *format,...) noexcept
Definition: debug.cpp:136
jau::WARN_PRINTv
void WARN_PRINTv(const char *func, const char *file, const int line, const char *format, va_list args) noexcept
Use for unconditional warning messages, prefix '[elapsed_time] Warning @ file:line: '.
Definition: debug.cpp:149
jau::ABORT_impl
void ABORT_impl(const char *func, const char *file, const int line, const char *format,...) noexcept
Use for unconditional ::abort() call with given messages, prefix '[elapsed_time] ABORT @ file:line: '...
Definition: debug.cpp:116
jau::COND_PRINT_impl
void COND_PRINT_impl(const char *format,...) noexcept
Definition: debug.cpp:197
jau::DBG_PRINT_impl
void DBG_PRINT_impl(const char *format,...) noexcept
Definition: debug.cpp:96