2016-12-24 01:03:10 +00:00
|
|
|
#if !defined(__APPLE__) && !defined(__FreeBSD__)
|
2015-10-05 01:11:12 +00:00
|
|
|
#include <malloc.h>
|
2016-10-26 22:27:38 +00:00
|
|
|
#endif
|
2015-10-05 01:11:12 +00:00
|
|
|
#include <execinfo.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <sstream>
|
|
|
|
|
2017-04-01 09:19:00 +00:00
|
|
|
#include <Common/StackTrace.h>
|
2018-08-24 08:32:33 +00:00
|
|
|
#include <Common/SimpleCache.h>
|
|
|
|
|
2018-04-09 13:52:39 +00:00
|
|
|
#include <common/demangle.h>
|
2015-10-05 01:11:12 +00:00
|
|
|
|
2018-08-24 08:32:33 +00:00
|
|
|
|
2018-06-19 18:09:09 +00:00
|
|
|
/// Arcadia compatibility DEVTOOLS-3976
|
|
|
|
#if defined(BACKTRACE_INCLUDE)
|
|
|
|
#include BACKTRACE_INCLUDE
|
|
|
|
#endif
|
|
|
|
#if !defined(BACKTRACE_FUNC)
|
|
|
|
#define BACKTRACE_FUNC backtrace
|
|
|
|
#endif
|
2015-10-05 01:11:12 +00:00
|
|
|
|
|
|
|
StackTrace::StackTrace()
|
|
|
|
{
|
2018-08-24 08:32:33 +00:00
|
|
|
frames_size = BACKTRACE_FUNC(frames.data(), STACK_TRACE_MAX_DEPTH);
|
|
|
|
|
|
|
|
for (size_t i = frames_size; i < STACK_TRACE_MAX_DEPTH; ++i)
|
|
|
|
frames[i] = nullptr;
|
2015-10-05 01:11:12 +00:00
|
|
|
}
|
|
|
|
|
2018-08-24 08:32:33 +00:00
|
|
|
|
|
|
|
std::string StackTrace::toStringImpl(const Frames & frames, size_t frames_size)
|
2015-10-05 01:11:12 +00:00
|
|
|
{
|
2018-08-24 08:32:33 +00:00
|
|
|
char ** symbols = backtrace_symbols(frames.data(), frames_size);
|
2017-04-01 07:20:54 +00:00
|
|
|
if (!symbols)
|
|
|
|
return "Cannot get symbols for stack trace.\n";
|
2015-10-05 01:11:12 +00:00
|
|
|
|
2019-01-02 06:44:36 +00:00
|
|
|
std::stringstream res;
|
2017-04-01 07:20:54 +00:00
|
|
|
try
|
|
|
|
{
|
|
|
|
for (size_t i = 0, size = frames_size; i < size; ++i)
|
|
|
|
{
|
|
|
|
/// We do "demangling" of names. The name is in parenthesis, before the '+' character.
|
2015-12-23 07:16:44 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
char * name_start = nullptr;
|
|
|
|
char * name_end = nullptr;
|
2017-12-08 01:34:52 +00:00
|
|
|
std::string demangled_name;
|
2017-04-01 07:20:54 +00:00
|
|
|
int status = 0;
|
2015-12-23 07:16:44 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
if (nullptr != (name_start = strchr(symbols[i], '('))
|
|
|
|
&& nullptr != (name_end = strchr(name_start, '+')))
|
|
|
|
{
|
|
|
|
++name_start;
|
|
|
|
*name_end = '\0';
|
2017-12-08 01:34:52 +00:00
|
|
|
demangled_name = demangle(name_start, status);
|
2017-04-01 07:20:54 +00:00
|
|
|
*name_end = '+';
|
|
|
|
}
|
2015-10-05 01:11:12 +00:00
|
|
|
|
2017-12-08 01:34:52 +00:00
|
|
|
res << i << ". ";
|
2015-10-05 01:11:12 +00:00
|
|
|
|
2017-12-08 01:34:52 +00:00
|
|
|
if (0 == status && name_start && name_end)
|
2017-04-01 07:20:54 +00:00
|
|
|
{
|
2017-12-08 01:34:52 +00:00
|
|
|
res.write(symbols[i], name_start - symbols[i]);
|
|
|
|
res << demangled_name << name_end;
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
2017-12-08 01:34:52 +00:00
|
|
|
else
|
|
|
|
res << symbols[i];
|
|
|
|
|
|
|
|
res << std::endl;
|
2017-04-01 07:20:54 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
|
|
|
free(symbols);
|
|
|
|
throw;
|
|
|
|
}
|
2015-12-23 07:16:44 +00:00
|
|
|
|
2017-04-01 07:20:54 +00:00
|
|
|
free(symbols);
|
|
|
|
return res.str();
|
2015-10-05 01:11:12 +00:00
|
|
|
}
|
2018-08-24 08:32:33 +00:00
|
|
|
|
|
|
|
|
|
|
|
std::string StackTrace::toString() const
|
|
|
|
{
|
|
|
|
/// Calculation of stack trace text is extremely slow.
|
|
|
|
/// We use simple cache because otherwise the server could be overloaded by trash queries.
|
|
|
|
|
|
|
|
static SimpleCache<decltype(StackTrace::toStringImpl), &StackTrace::toStringImpl> func_cached;
|
|
|
|
return func_cached(frames, frames_size);
|
|
|
|
}
|