Electroneum
Toggle main menu visibility
Loading...
Searching...
No Matches
stack_trace.cpp
Go to the documentation of this file.
1
// Copyright (c) 2017-Present, Electroneum
2
// Copyright (c) 2016-2019, The Monero Project
3
//
4
// All rights reserved.
5
//
6
// Redistribution and use in source and binary forms, with or without modification, are
7
// permitted provided that the following conditions are met:
8
//
9
// 1. Redistributions of source code must retain the above copyright notice, this list of
10
// conditions and the following disclaimer.
11
//
12
// 2. Redistributions in binary form must reproduce the above copyright notice, this list
13
// of conditions and the following disclaimer in the documentation and/or other
14
// materials provided with the distribution.
15
//
16
// 3. Neither the name of the copyright holder nor the names of its contributors may be
17
// used to endorse or promote products derived from this software without specific
18
// prior written permission.
19
//
20
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
21
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
23
// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27
// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
28
// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30
#if !defined __GNUC__ || defined __MINGW32__ || defined __MINGW64__ || defined __ANDROID__
31
#define USE_UNWIND
32
#else
33
#define ELPP_FEATURE_CRASH_LOG 1
34
#endif
35
#include "
easylogging++/easylogging++.h
"
36
37
#include <stdexcept>
38
#ifdef USE_UNWIND
39
#define UNW_LOCAL_ONLY
40
#include <libunwind.h>
41
#include <cxxabi.h>
42
#endif
43
#ifndef STATICLIB
44
#include <dlfcn.h>
45
#endif
46
#include <boost/algorithm/string.hpp>
47
#include "
common/stack_trace.h
"
48
#include "
misc_log_ex.h
"
49
50
#undef ELECTRONEUM_DEFAULT_LOG_CATEGORY
51
#define ELECTRONEUM_DEFAULT_LOG_CATEGORY "stacktrace"
52
53
#define ST_LOG(x) \
54
do { \
55
auto elpp = ELPP; \
56
if (elpp) { \
57
CINFO(el::base::Writer,el::base::DispatchAction::FileOnlyLog,ELECTRONEUM_DEFAULT_LOG_CATEGORY) << x; \
58
} \
59
else { \
60
std::cout << x << std::endl; \
61
} \
62
} while(0)
63
64
// from https://stackoverflow.com/questions/11665829/how-can-i-print-stack-trace-for-caught-exceptions-in-c-code-injection-in-c
65
66
// The decl of __cxa_throw in /usr/include/.../cxxabi.h uses
67
// 'std::type_info *', but GCC's built-in protype uses 'void *'.
68
#ifdef __clang__
69
#define CXA_THROW_INFO_T std::type_info
70
#else
// !__clang__
71
#define CXA_THROW_INFO_T void
72
#endif
// !__clang__
73
74
#ifdef STATICLIB
75
#define CXA_THROW __wrap___cxa_throw
76
extern
"C"
77
__attribute__
((noreturn))
78
void
__real___cxa_throw(
void
*ex,
CXA_THROW_INFO_T
*
info
,
void
(*
dest
)(
void
*));
79
#else
// !STATICLIB
80
#define CXA_THROW __cxa_throw
81
extern
"C"
82
typedef
83
#ifdef __clang__
// only clang, not GCC, lets apply the attr in typedef
84
__attribute__
((noreturn))
85
#endif
// __clang__
86
void (
cxa_throw_t
)(
void
*ex,
CXA_THROW_INFO_T
*
info
, void (*
dest
)(
void
*));
87
#endif
// !STATICLIB
88
89
extern
"C"
90
__attribute__
((noreturn))
91
void
CXA_THROW
(
void
*ex,
CXA_THROW_INFO_T
*
info
,
void
(*
dest
)(
void
*))
92
{
93
94
int
status;
95
char
*dsym = abi::__cxa_demangle(((
const
std::type_info*)
info
)->name(), NULL, NULL, &status);
96
tools::log_stack_trace
((std::string(
"Exception: "
)+((!status && dsym) ? dsym : (
const
char
*)
info
)).c_str());
97
free(dsym);
98
99
#ifndef STATICLIB
100
#ifndef __clang__
// for GCC the attr can't be applied in typedef like for clang
101
__attribute__
((noreturn))
102
#endif
// !__clang__
103
cxa_throw_t
*__real___cxa_throw = (
cxa_throw_t
*)dlsym(RTLD_NEXT,
"__cxa_throw"
);
104
#endif
// !STATICLIB
105
__real___cxa_throw(ex,
info
,
dest
);
106
}
107
108
namespace
109
{
110
std::string stack_trace_log;
111
}
112
113
namespace
tools
114
{
115
116
void
set_stack_trace_log
(
const
std::string &log)
117
{
118
stack_trace_log = log;
119
}
120
121
void
log_stack_trace
(
const
char
*msg)
122
{
123
#ifdef USE_UNWIND
124
unw_context_t ctx;
125
unw_cursor_t cur;
126
unw_word_t ip, off;
127
unsigned
level;
128
char
sym[512], *dsym;
129
int
status;
130
const
char
*log = stack_trace_log.empty() ? NULL : stack_trace_log.c_str();
131
#endif
132
133
if
(msg)
134
ST_LOG
(msg);
135
ST_LOG
(
"Unwound call stack:"
);
136
137
#ifdef USE_UNWIND
138
if
(unw_getcontext(&ctx) < 0) {
139
ST_LOG
(
"Failed to create unwind context"
);
140
return
;
141
}
142
if
(unw_init_local(&cur, &ctx) < 0) {
143
ST_LOG
(
"Failed to find the first unwind frame"
);
144
return
;
145
}
146
for
(level = 1; level < 999; ++level) {
// 999 for safety
147
int
ret = unw_step(&cur);
148
if
(ret < 0) {
149
ST_LOG
(
"Failed to find the next frame"
);
150
return
;
151
}
152
if
(ret == 0)
153
break
;
154
if
(unw_get_reg(&cur, UNW_REG_IP, &ip) < 0) {
155
ST_LOG
(
" "
<< std::setw(4) << level);
156
continue
;
157
}
158
if
(unw_get_proc_name(&cur, sym,
sizeof
(sym), &off) < 0) {
159
ST_LOG
(
" "
<< std::setw(4) << level << std::setbase(16) << std::setw(20) <<
"0x"
<< ip);
160
continue
;
161
}
162
dsym = abi::__cxa_demangle(sym, NULL, NULL, &status);
163
ST_LOG
(
" "
<< std::setw(4) << level << std::setbase(16) << std::setw(20) <<
"0x"
<< ip <<
" "
<< (!status && dsym ? dsym : sym) <<
" + "
<<
"0x"
<< off);
164
free(dsym);
165
}
166
#else
167
std::stringstream ss;
168
ss << el::base::debug::StackTrace();
169
std::vector<std::string> lines;
170
std::string s = ss.str();
171
boost::split(lines, s, boost::is_any_of(
"\n"
));
172
for
(
const
auto
&line: lines)
173
ST_LOG
(line);
174
#endif
175
}
176
177
}
// namespace tools
easylogging++.h
misc_log_ex.h
tools
Various Tools.
Definition
tools.cpp:31
tools::log_stack_trace
void log_stack_trace(const char *msg)
Definition
stack_trace.cpp:121
tools::set_stack_trace_log
void set_stack_trace_log(const std::string &log)
Definition
stack_trace.cpp:116
__attribute__
__attribute__((noreturn)) void CXA_THROW(void *ex
dest
CXA_THROW_INFO_T void(* dest)(void *))
Definition
stack_trace.cpp:91
info
CXA_THROW_INFO_T * info
Definition
stack_trace.cpp:91
CXA_THROW_INFO_T
#define CXA_THROW_INFO_T
Definition
stack_trace.cpp:71
ST_LOG
#define ST_LOG(x)
Definition
stack_trace.cpp:53
cxa_throw_t
void cxa_throw_t(void *ex, CXA_THROW_INFO_T *info, void(*dest)(void *))
Definition
stack_trace.cpp:86
CXA_THROW
#define CXA_THROW
Definition
stack_trace.cpp:80
stack_trace.h
src
common
stack_trace.cpp
Generated on
for Electroneum by
1.17.0