13 #include <dash-config.h> 42 #include <mach-o/dyld.h> 43 #include <mach/mach_init.h> 44 #include <sys/sysctl.h> 45 #include <mach/mach_vm.h> 48 #include <backtrace.h> 53 #if __GNUC__ || __clang__ 55 char* str = abi::__cxa_demangle(
name.c_str(),
nullptr,
nullptr, &status);
60 std::string ret = str;
76 std::vector<TCHAR> tmp(bufSize);
77 DWORD len = GetModuleFileName(
nullptr, tmp.data(), bufSize);
81 for (
size_t i = 0; i < len; i++) {
82 buf[i] = (char)tmp[i];
86 uint32_t bufSize2 = (uint32_t)bufSize;
87 if (_NSGetExecutablePath(buf, &bufSize2) != 0) {
94 ssize_t len = readlink(
"/proc/self/exe", buf, bufSize - 1);
104 std::vector<char> buf(1024);
110 if (len < buf.size()) {
111 return std::string(buf.begin(), buf.begin() + len);
113 buf.resize(buf.size() * 2);
131 static const char* exeFileNamePtr = fs::exists(debugFileName) ? debugFileName.c_str() :
g_exeFileName.c_str();
149 static uint64_t ConvertAddress(uint64_t addr)
151 MEMORY_BASIC_INFORMATION mbi;
153 if (!VirtualQuery((PVOID)addr, &mbi,
sizeof(mbi)))
156 uint64_t hMod = (uint64_t)mbi.AllocationBase;
157 uint64_t offset = addr - hMod;
158 return 0x400000 + offset;
161 static __attribute__((noinline)) std::vector<uint64_t> GetStackFrames(
size_t skip,
size_t max_frames,
const CONTEXT* pContext =
nullptr)
164 static BOOL symInitialized = SymInitialize(GetCurrentProcess(),
nullptr, TRUE);
168 std::lock_guard<std::mutex> l(m);
170 HANDLE process = GetCurrentProcess();
171 HANDLE thread = GetCurrentThread();
175 memset(&context, 0,
sizeof(CONTEXT));
176 context.ContextFlags = CONTEXT_FULL;
177 RtlCaptureContext(&context);
179 memcpy(&context, pContext,
sizeof(CONTEXT));
183 STACKFRAME64 stackframe;
184 ZeroMemory(&stackframe,
sizeof(STACKFRAME64));
187 image = IMAGE_FILE_MACHINE_I386;
188 stackframe.AddrPC.Offset = context.Eip;
189 stackframe.AddrPC.Mode = AddrModeFlat;
190 stackframe.AddrFrame.Offset = context.Ebp;
191 stackframe.AddrFrame.Mode = AddrModeFlat;
192 stackframe.AddrStack.Offset = context.Esp;
193 stackframe.AddrStack.Mode = AddrModeFlat;
195 image = IMAGE_FILE_MACHINE_AMD64;
196 stackframe.AddrPC.Offset = context.Rip;
197 stackframe.AddrPC.Mode = AddrModeFlat;
198 stackframe.AddrFrame.Offset = context.Rbp;
199 stackframe.AddrFrame.Mode = AddrModeFlat;
200 stackframe.AddrStack.Offset = context.Rsp;
201 stackframe.AddrStack.Mode = AddrModeFlat;
206 #error unsupported architecture 209 std::vector<uint64_t> ret;
212 while (ret.size() < max_frames) {
213 BOOL result = StackWalk64(
214 image, process, thread,
215 &stackframe, &context,
nullptr,
216 SymFunctionTableAccess64, SymGetModuleBase64,
nullptr);
222 uint64_t pc = ConvertAddress(stackframe.AddrPC.Offset);
224 pc = stackframe.AddrPC.Offset;
226 ret.emplace_back(pc);
238 mach_port_name_t target_task;
239 vm_map_offset_t vmoffset;
240 vm_map_size_t vmsize;
241 uint32_t nesting_depth = 0;
242 struct vm_region_submap_info_64 vbr;
243 mach_msg_type_number_t vbrcount = 16;
246 kr = task_for_pid(mach_task_self(), getpid(), &target_task);
247 if (kr != KERN_SUCCESS) {
251 kr = mach_vm_region_recurse(target_task, &vmoffset, &vmsize, &nesting_depth, (vm_region_recurse_info_t)&vbr, &vbrcount);
252 if (kr != KERN_SUCCESS) {
261 uint64_t* p = (uint64_t*)data;
262 if (info->dlpi_name ==
nullptr || info->dlpi_name[0] ==
'\0') {
263 *p = info->dlpi_addr;
270 uint64_t basePtr = 0;
276 static __attribute__((noinline)) std::vector<uint64_t> GetStackFrames(
size_t skip,
size_t max_frames)
279 std::vector<void*> buf(max_frames);
280 int count = backtrace(buf.data(), (int)buf.size());
284 buf.resize((
size_t)
count);
286 std::vector<uint64_t> ret;
288 for (
size_t i = skip + 1; i < buf.size(); i++) {
289 ret.emplace_back((uint64_t) buf[i]);
299 std::string
function;
303 template <
typename Stream,
typename Operation>
315 auto sis = (std::vector<stackframe_info>*)data;
325 sis->emplace_back(si);
326 if (sis->size() >= 128) {
330 if (si.
function ==
"mainCRTStartup" ||
331 si.
function ==
"pthread_create_wrapper" ||
332 si.
function ==
"__tmainCRTStartup") {
342 std::vector<stackframe_info> infos;
343 infos.reserve(stackframes.size());
345 for (
size_t i = 0; i < stackframes.size(); i++) {
362 template <
typename Stream,
typename Operation>
379 template <
typename Stream,
typename Operation>
405 hdr.
magic =
"DashCrashInfo";
414 std::string s = ci.crashDescription +
"\n";
415 s +=
strprintf(
"No debug information available for stacktrace. You should add debug information and then run:\n" 426 bool dataInvalid =
false;
428 if (buf.empty() || dataInvalid) {
429 return "Error while deserializing crash info";
438 return "Error while deserializing crash info header";
441 if (hdr.
magic !=
"DashCrashInfo") {
442 return "Invalid magic string";
445 return "Unsupported version";
448 return "Crash info is not for this executable";
455 return "Error while deserializing crash info";
475 for (
size_t i = 0; i < spaces; i++) {
479 std::vector<std::string> lstrs;
486 if (!si.filename.empty()) {
487 lstr += fs::path(si.filename).filename().string();
489 lstr +=
"<unknown-file>";
491 if (si.lineno != 0) {
495 lstrs.emplace_back(lstr);
499 size_t lstrlen = std::max_element(lstrs.begin(), lstrs.end(), [](
const std::string& a,
const std::string& b) {
return a.size() < b.size(); })->size();
501 std::string fmtStr =
strprintf(
"%%2d#: (0x%%08X) %%-%ds - %%s\n", lstrlen);
507 auto& lstr = lstrs[i];
510 if (!si.function.empty()) {
516 std::string s2 =
strprintf(fmtStr, i, si.pc, lstr, fstr);
528 fprintf(stderr,
"%s", str.c_str());
532 #ifdef ENABLE_CRASH_HOOKS 533 static std::mutex g_stacktraces_mutex;
534 static std::map<void*, std::shared_ptr<std::vector<uint64_t>>> g_stacktraces;
536 #if CRASH_HOOKS_WRAPPED_CXX_ABI 539 extern "C" void* __real___cxa_allocate_exception(
size_t thrown_size);
540 extern "C" void __real___cxa_free_exception(
void * thrown_exception);
542 #error not supported on WIN32 (no dlsym support) 544 extern "C" void __real__assert(
const char *assertion,
const char *file,
unsigned int line);
545 extern "C" void __real__wassert(
const wchar_t *assertion,
const wchar_t *file,
unsigned int line);
547 extern "C" void __real___assert_fail(
const char *assertion,
const char *file,
unsigned int line,
const char *
function);
552 extern "C" void* __real___cxa_allocate_exception(
size_t thrown_size)
554 static auto f = (
void*(*)(
size_t))dlsym(RTLD_NEXT,
"__cxa_allocate_exception");
555 return f(thrown_size);
557 extern "C" void __real___cxa_free_exception(
void * thrown_exception)
559 static auto f = (void(*)(
void*))dlsym(RTLD_NEXT,
"__cxa_free_exception");
560 return f(thrown_exception);
563 extern "C" void __attribute__((noreturn)) __real___assert_rtn(
const char *
function,
const char *file,
int line,
const char *assertion)
565 static auto f = (void(
__attribute__((noreturn)) *) (
const char*,
const char*, int,
const char*))dlsym(RTLD_NEXT,
"__assert_rtn");
566 f(
function, file, line, assertion);
569 #error not supported on WIN32 (no dlsym support) 571 extern "C" void __real___assert_fail(
const char *assertion,
const char *file,
unsigned int line,
const char *
function)
573 static auto f = (void(*)(
const char*,
const char*,
unsigned int,
const char*))dlsym(RTLD_NEXT,
"__assert_fail");
574 f(assertion, file, line,
function);
579 #if CRASH_HOOKS_WRAPPED_CXX_ABI 580 #define WRAPPED_NAME(x) __wrap_##x 582 #define WRAPPED_NAME(x) x 585 extern "C" void*
__attribute__((noinline)) WRAPPED_NAME(__cxa_allocate_exception)(
size_t thrown_size)
588 auto localSt = GetStackFrames(1, 16);
592 std::shared_ptr<std::vector<uint64_t>> st(
new std::vector<uint64_t>(localSt));
594 void* p = __real___cxa_allocate_exception(thrown_size);
596 std::lock_guard<std::mutex> l(g_stacktraces_mutex);
597 g_stacktraces.emplace(p, st);
601 extern "C" void __attribute__((noinline)) WRAPPED_NAME(__cxa_free_exception)(
void * thrown_exception)
603 __real___cxa_free_exception(thrown_exception);
605 std::lock_guard<std::mutex> l(g_stacktraces_mutex);
606 g_stacktraces.erase(thrown_exception);
609 static __attribute__((noinline))
crash_info GetCrashInfoFromAssertion(
const char* assertion,
const char* file,
int line,
const char*
function)
628 extern "C" void __attribute__((noinline)) WRAPPED_NAME(__assert_rtn)(
const char *
function,
const char *file,
int line,
const char *assertion)
630 auto ci = GetCrashInfoFromAssertion(assertion, file, line,
function);
633 __real___assert_rtn(
function, file, line, assertion);
636 extern "C" void __attribute__((noinline)) WRAPPED_NAME(_assert)(
const char *assertion,
const char *file,
unsigned int line)
638 auto ci = GetCrashInfoFromAssertion(assertion, file, line,
nullptr);
641 __real__assert(assertion, file, line);
643 extern "C" void __attribute__((noinline)) WRAPPED_NAME(_wassert)(
const wchar_t *assertion,
const wchar_t *file,
unsigned int line)
645 auto ci = GetCrashInfoFromAssertion(
646 assertion ? std::string(assertion, assertion + wcslen(assertion)).c_str() :
nullptr,
647 file ? std::string(file, file + wcslen(file)).c_str() :
nullptr,
651 __real__wassert(assertion, file, line);
654 extern "C" void __attribute__((noinline)) WRAPPED_NAME(__assert_fail)(
const char *assertion,
const char *file,
unsigned int line,
const char *
function)
656 auto ci = GetCrashInfoFromAssertion(assertion, file, line,
function);
659 __real___assert_fail(assertion, file, line,
function);
662 #endif //ENABLE_CRASH_HOOKS 666 #ifdef ENABLE_CRASH_HOOKS 667 void* p = *(
void**)&e;
669 std::lock_guard<std::mutex> l(g_stacktraces_mutex);
670 auto it = g_stacktraces.find(p);
671 if (it == g_stacktraces.end()) {
693 auto getExceptionType = [&]() -> std::string {
694 auto type = abi::__cxa_current_exception_type();
695 if (type && (strlen(type->name()) > 0)) {
703 std::rethrow_exception(e);
704 }
catch (
const std::exception& e) {
705 type = getExceptionType();
707 }
catch (
const std::string& e) {
708 type = getExceptionType();
710 }
catch (
const char* e) {
711 type = getExceptionType();
714 type = getExceptionType();
717 type = getExceptionType();
739 auto exc = std::current_exception();
774 const char*
name = strsignal(s);
790 static void DoHandleWindowsException(EXCEPTION_POINTERS * ExceptionInfo)
793 switch(ExceptionInfo->ExceptionRecord->ExceptionCode)
795 case EXCEPTION_ACCESS_VIOLATION: excType =
"EXCEPTION_ACCESS_VIOLATION";
break;
796 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: excType =
"EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
break;
797 case EXCEPTION_BREAKPOINT: excType =
"EXCEPTION_BREAKPOINT";
break;
798 case EXCEPTION_DATATYPE_MISALIGNMENT: excType =
"EXCEPTION_DATATYPE_MISALIGNMENT";
break;
799 case EXCEPTION_FLT_DENORMAL_OPERAND: excType =
"EXCEPTION_FLT_DENORMAL_OPERAND";
break;
800 case EXCEPTION_FLT_DIVIDE_BY_ZERO: excType =
"EXCEPTION_FLT_DIVIDE_BY_ZERO";
break;
801 case EXCEPTION_FLT_INEXACT_RESULT: excType =
"EXCEPTION_FLT_INEXACT_RESULT";
break;
802 case EXCEPTION_FLT_INVALID_OPERATION: excType =
"EXCEPTION_FLT_INVALID_OPERATION";
break;
803 case EXCEPTION_FLT_OVERFLOW: excType =
"EXCEPTION_FLT_OVERFLOW";
break;
804 case EXCEPTION_FLT_STACK_CHECK: excType =
"EXCEPTION_FLT_STACK_CHECK";
break;
805 case EXCEPTION_FLT_UNDERFLOW: excType =
"EXCEPTION_FLT_UNDERFLOW";
break;
806 case EXCEPTION_ILLEGAL_INSTRUCTION: excType =
"EXCEPTION_ILLEGAL_INSTRUCTION";
break;
807 case EXCEPTION_IN_PAGE_ERROR: excType =
"EXCEPTION_IN_PAGE_ERROR";
break;
808 case EXCEPTION_INT_DIVIDE_BY_ZERO: excType =
"EXCEPTION_INT_DIVIDE_BY_ZERO";
break;
809 case EXCEPTION_INT_OVERFLOW: excType =
"EXCEPTION_INT_OVERFLOW";
break;
810 case EXCEPTION_INVALID_DISPOSITION: excType =
"EXCEPTION_INVALID_DISPOSITION";
break;
811 case EXCEPTION_NONCONTINUABLE_EXCEPTION: excType =
"EXCEPTION_NONCONTINUABLE_EXCEPTION";
break;
812 case EXCEPTION_PRIV_INSTRUCTION: excType =
"EXCEPTION_PRIV_INSTRUCTION";
break;
813 case EXCEPTION_SINGLE_STEP: excType =
"EXCEPTION_SINGLE_STEP";
break;
814 case EXCEPTION_STACK_OVERFLOW: excType =
"EXCEPTION_STACK_OVERFLOW";
break;
815 default: excType =
"UNKNOWN";
break;
820 ci.
stackframes = GetStackFrames(0, 16, ExceptionInfo->ContextRecord);
826 LONG WINAPI HandleWindowsException(EXCEPTION_POINTERS * ExceptionInfo)
828 if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW) {
833 DoHandleWindowsException(ExceptionInfo);
836 DoHandleWindowsException(ExceptionInfo);
838 return EXCEPTION_CONTINUE_SEARCH;
845 SetUnhandledExceptionFilter(HandleWindowsException);
847 const std::vector<int> posix_signals = {
865 for (
auto s : posix_signals) {
866 struct sigaction sa_segv;
868 sigemptyset(&sa_segv.sa_mask);
869 sa_segv.sa_flags = 0;
870 sigaction(s, &sa_segv,
nullptr);
static int dl_iterate_callback(struct dl_phdr_info *info, size_t s, void *data)
static __attribute__((noinline)) std
std::string GetCrashInfoStrFromSerializedStr(const std::string &ciStr)
std::vector< uint64_t > stackframes
Double ended buffer combining vector and stream-like interfaces.
static void terminate_handler()
static backtrace_state * GetLibBacktraceState()
void ConvertAddresses(int64_t offset)
static void PrintCrashInfo(const crash_info &ci)
static std::string GetCrashInfoStr(const crash_info &ci, size_t spaces=2)
std::string DemangleSymbol(const std::string &name)
static std::string GetExeFileName()
static uint64_t GetBaseAddress()
static std::string g_exeFileBaseName
std::string crashDescription
std::vector< unsigned char > DecodeBase32(const char *p, bool *pfInvalid)
static int my_backtrace_full_callback(void *data, uintptr_t pc, const char *filename, int lineno, const char *function)
static ssize_t GetExeFileNameImpl(char *buf, size_t bufSize)
void RegisterPrettyTerminateHander()
static std::vector< stackframe_info > GetStackFrameInfos(const std::vector< uint64_t > &stackframes)
std::string GetPrettyExceptionStr(const std::exception_ptr &e)
void SerializationOp(Stream &s, Operation ser_action)
static std::atomic< bool > skipAbortSignal(false)
void SerializationOp(Stream &s, Operation ser_action)
void * memcpy(void *a, const void *b, size_t c)
static void HandlePosixSignal(int s)
std::string EncodeBase32(const unsigned char *pch, size_t len)
void RegisterPrettySignalHandlers()
static void my_backtrace_error_callback(void *data, const char *msg, int errnum)
static std::shared_ptr< std::vector< uint64_t > > GetExceptionStacktrace(const std::exception_ptr &e)
std::vector< stackframe_info > stackframeInfos
std::string GetExceptionWhat(const T &e)
static std::string g_exeFileName
static std::string GetCrashInfoStrNoDebugInfo(crash_info ci)
crash_info GetCrashInfoFromException(const std::exception_ptr &e)