ClickHouse/dbms/src/Common/StackTrace.cpp

297 lines
7.8 KiB
C++
Raw Normal View History

2019-06-28 18:06:38 +00:00
#include <common/SimpleCache.h>
#include <common/demangle.h>
2019-07-29 22:26:44 +00:00
#include <Common/StackTrace.h>
#include <Common/SymbolIndex.h>
#include <Common/Dwarf.h>
#include <Common/Elf.h>
2019-06-28 18:06:38 +00:00
#include <sstream>
2019-07-29 22:26:44 +00:00
#include <filesystem>
#include <unordered_map>
2019-06-28 18:06:38 +00:00
#include <cstring>
std::string signalToErrorMessage(int sig, const siginfo_t & info, const ucontext_t & context)
{
std::stringstream error;
switch (sig)
{
case SIGSEGV:
{
/// Print info about address and reason.
if (nullptr == info.si_addr)
error << "Address: NULL pointer.";
else
error << "Address: " << info.si_addr;
#if defined(__x86_64__) && !defined(__FreeBSD__) && !defined(__APPLE__)
auto err_mask = context.uc_mcontext.gregs[REG_ERR];
if ((err_mask & 0x02))
error << " Access: write.";
else
error << " Access: read.";
#endif
switch (info.si_code)
{
case SEGV_ACCERR:
error << " Attempted access has violated the permissions assigned to the memory area.";
break;
case SEGV_MAPERR:
error << " Address not mapped to object.";
break;
default:
error << " Unknown si_code.";
break;
}
break;
}
case SIGBUS:
{
switch (info.si_code)
{
case BUS_ADRALN:
error << "Invalid address alignment.";
break;
case BUS_ADRERR:
error << "Non-existant physical address.";
break;
case BUS_OBJERR:
error << "Object specific hardware error.";
break;
// Linux specific
#if defined(BUS_MCEERR_AR)
case BUS_MCEERR_AR:
error << "Hardware memory error: action required.";
break;
#endif
#if defined(BUS_MCEERR_AO)
case BUS_MCEERR_AO:
error << "Hardware memory error: action optional.";
break;
#endif
default:
error << "Unknown si_code.";
break;
}
break;
}
case SIGILL:
{
switch (info.si_code)
{
case ILL_ILLOPC:
error << "Illegal opcode.";
break;
case ILL_ILLOPN:
error << "Illegal operand.";
break;
case ILL_ILLADR:
error << "Illegal addressing mode.";
break;
case ILL_ILLTRP:
error << "Illegal trap.";
break;
case ILL_PRVOPC:
error << "Privileged opcode.";
break;
case ILL_PRVREG:
error << "Privileged register.";
break;
case ILL_COPROC:
error << "Coprocessor error.";
break;
case ILL_BADSTK:
error << "Internal stack error.";
break;
default:
error << "Unknown si_code.";
break;
}
break;
}
case SIGFPE:
{
switch (info.si_code)
{
case FPE_INTDIV:
error << "Integer divide by zero.";
break;
case FPE_INTOVF:
error << "Integer overflow.";
break;
case FPE_FLTDIV:
error << "Floating point divide by zero.";
break;
case FPE_FLTOVF:
error << "Floating point overflow.";
break;
case FPE_FLTUND:
error << "Floating point underflow.";
break;
case FPE_FLTRES:
error << "Floating point inexact result.";
break;
case FPE_FLTINV:
error << "Floating point invalid operation.";
break;
case FPE_FLTSUB:
error << "Subscript out of range.";
break;
default:
error << "Unknown si_code.";
break;
}
break;
}
}
return error.str();
}
static void * getCallerAddress(const ucontext_t & context)
2019-06-28 18:06:38 +00:00
{
#if defined(__x86_64__)
/// Get the address at the time the signal was raised from the RIP (x86-64)
#if defined(__FreeBSD__)
return reinterpret_cast<void *>(context.uc_mcontext.mc_rip);
#elif defined(__APPLE__)
return reinterpret_cast<void *>(context.uc_mcontext->__ss.__rip);
#else
return reinterpret_cast<void *>(context.uc_mcontext.gregs[REG_RIP]);
#endif
#elif defined(__aarch64__)
return reinterpret_cast<void *>(context.uc_mcontext.pc);
2019-07-29 22:26:44 +00:00
#else
2019-06-28 18:06:38 +00:00
return nullptr;
2019-07-29 22:26:44 +00:00
#endif
2019-06-28 18:06:38 +00:00
}
2019-07-01 22:11:11 +00:00
StackTrace::StackTrace()
{
tryCapture();
}
2019-06-28 18:06:38 +00:00
2019-07-01 22:11:11 +00:00
StackTrace::StackTrace(const ucontext_t & signal_context)
2019-06-28 18:06:38 +00:00
{
2019-07-01 22:11:11 +00:00
tryCapture();
2019-06-28 18:06:38 +00:00
void * caller_address = getCallerAddress(signal_context);
if (size == 0 && caller_address)
2019-07-01 22:11:11 +00:00
{
frames[0] = caller_address;
size = 1;
}
else
{
/// Skip excessive stack frames that we have created while finding stack trace.
for (size_t i = 0; i < size; ++i)
{
if (frames[i] == caller_address)
{
offset = i;
break;
}
}
2019-06-28 18:06:38 +00:00
}
}
2019-07-01 22:11:11 +00:00
StackTrace::StackTrace(NoCapture)
{
2019-06-28 18:06:38 +00:00
}
2019-07-29 22:26:44 +00:00
#if USE_UNWIND
extern "C" int unw_backtrace(void **, int);
#endif
2019-07-01 22:11:11 +00:00
void StackTrace::tryCapture()
{
size = 0;
#if USE_UNWIND
size = unw_backtrace(frames.data(), capacity);
#endif
}
size_t StackTrace::getSize() const
{
2019-06-28 18:06:38 +00:00
return size;
}
size_t StackTrace::getOffset() const
2019-07-01 22:11:11 +00:00
{
return offset;
2019-06-28 18:06:38 +00:00
}
const StackTrace::Frames & StackTrace::getFrames() const
2019-06-28 18:06:38 +00:00
{
return frames;
2019-06-28 18:06:38 +00:00
}
static std::string toStringImpl(const StackTrace::Frames & frames, size_t offset, size_t size)
2019-06-28 18:06:38 +00:00
{
if (size == 0)
return "<Empty trace>";
2019-07-29 22:26:44 +00:00
const DB::SymbolIndex & symbol_index = DB::SymbolIndex::instance();
std::unordered_map<std::string, DB::Dwarf> dwarfs;
std::stringstream out;
2019-06-28 18:06:38 +00:00
for (size_t i = offset; i < size; ++i)
2019-06-28 18:06:38 +00:00
{
const void * addr = frames[i];
out << "#" << i << " " << addr << " ";
auto symbol = symbol_index.findSymbol(addr);
2019-07-29 22:26:44 +00:00
if (symbol)
2019-06-28 18:06:38 +00:00
{
int status = 0;
2019-07-29 22:26:44 +00:00
out << demangle(symbol->name, status);
}
else
out << "?";
2019-06-28 18:06:38 +00:00
2019-07-29 22:26:44 +00:00
out << " ";
2019-06-28 18:06:38 +00:00
if (auto object = symbol_index.findObject(addr))
2019-07-29 22:26:44 +00:00
{
if (std::filesystem::exists(object->name))
2019-06-28 18:06:38 +00:00
{
2019-07-29 22:26:44 +00:00
auto dwarf_it = dwarfs.try_emplace(object->name, *object->elf).first;
2019-06-28 18:06:38 +00:00
2019-07-29 22:26:44 +00:00
DB::Dwarf::LocationInfo location;
if (dwarf_it->second.findAddress(uintptr_t(addr) - uintptr_t(object->address_begin), location, DB::Dwarf::LocationInfoMode::FAST))
2019-07-29 22:26:44 +00:00
out << location.file.toString() << ":" << location.line;
else
out << object->name;
}
2019-06-28 18:06:38 +00:00
}
2019-07-29 22:26:44 +00:00
else
out << "?";
out << "\n";
2019-06-28 18:06:38 +00:00
}
2019-07-29 22:26:44 +00:00
return out.str();
2019-06-28 18:06:38 +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(toStringImpl), &toStringImpl> func_cached;
return func_cached(frames, offset, size);
}