From 07cfe62467612339476b3a83ef61ffcb9f3ee3e9 Mon Sep 17 00:00:00 2001 From: Jinhyung Jo Date: Mon, 19 Sep 2016 20:04:13 +0900 Subject: util: improve backtrace feature improve & clean up the code: - correct coding convention - add backtrace feature to Mac OS X : remove #ifdef CONFIG_DARWIN ... #endif The 'backtarce' family functions first appeared in Mac OS X 10.5 - modify the Windows code using the APIs in DbgHelp - change debug channel: from debug_ch to new_debug_ch - remove some lines like redundant/unclear/unwanted/etc. - modify output form Change-Id: I8b57d996fa9daabf990932fcfb82e45a5e453636 Signed-off-by: Jinhyung Jo --- tizen/src/util/error_handler.c | 286 ++++++++++++++++++++++------------------- 1 file changed, 153 insertions(+), 133 deletions(-) (limited to 'tizen/src/util/error_handler.c') diff --git a/tizen/src/util/error_handler.c b/tizen/src/util/error_handler.c index 1f91e8df85..5a41b054ea 100644 --- a/tizen/src/util/error_handler.c +++ b/tizen/src/util/error_handler.c @@ -4,6 +4,7 @@ * Copyright (C) 2015 Samsung Electronics Co., Ltd. All rights reserved. * * Contact: + * Jinhyung Jo * SeokYeon Hwang * GiWoong Kim * @@ -37,6 +38,7 @@ #ifdef CONFIG_WIN32 #include +#include #else #include #endif @@ -47,60 +49,40 @@ #include "emulator_common.h" #include "emulator.h" -#include "debug_ch.h" - -MULTI_DEBUG_CHANNEL(qemu, backtrace); - #ifdef CONFIG_QT #include "qt5_error_report.h" #endif -#if defined(CONFIG_WIN32) -static LPTOP_LEVEL_EXCEPTION_FILTER prevExceptionFilter; -#elif defined(CONFIG_LINUX) -static pthread_spinlock_t siglock; -#endif +#include "new_debug_ch.h" -bool print_backtrace_at_normal_exit_enabled = false; +DECLARE_DEBUG_CHANNEL(backtrace); -/* Print 'backtrace' */ -#ifdef _WIN32 -struct frame_layout { - void *pNext; - void *pReturnAddr; -}; +bool print_backtrace_at_normal_exit_enabled; -static char *get_filename_from_path(char *path_buf) +void enable_print_backtrace_at_normal_exit(void) { - char *ret_slash; - char *ret_rslash; - - ret_slash = strrchr(path_buf, '/'); - ret_rslash = strrchr(path_buf, '\\'); - - if (ret_slash || ret_rslash) { - if (ret_slash > ret_rslash) { - return ret_slash + 1; - } else{ - return ret_rslash + 1; - } - } - - return path_buf; + print_backtrace_at_normal_exit_enabled = true; } +#ifdef CONFIG_WIN32 +static LPTOP_LEVEL_EXCEPTION_FILTER prevExceptionFilter; + +/* Windows 32 bit */ +#ifndef _WIN64 +struct frame_layout { + void *pNext; + void *pReturnAddr; +}; static HMODULE get_module_handle(void *dwAddress) { MEMORY_BASIC_INFORMATION Buffer; - return VirtualQuery((LPCVOID) dwAddress, &Buffer, sizeof(Buffer)) - ? (HMODULE) Buffer.AllocationBase : (HMODULE) 0; + return VirtualQuery((LPCVOID)dwAddress, &Buffer, sizeof(Buffer)) + ? (HMODULE)Buffer.AllocationBase : (HMODULE)0; } -#endif -static void dump_backtrace(void *ptr, int depth) +static void dump_backtrace(void *ptr) { -#ifdef _WIN32 int nCount; void *pTopFrame; struct frame_layout currentFrame; @@ -113,15 +95,11 @@ static void dump_backtrace(void *ptr, int depth) if (!pContext) { __asm__ __volatile__ ("movl %%ebp, %0" : "=m" (pTopFrame)); } else { -#ifdef _WIN64 - pTopFrame = (void *)((PCONTEXT)pContext)->Rbp; -#else pTopFrame = (void *)((PCONTEXT)pContext)->Ebp; -#endif } if (pTopFrame == NULL) { - INFO("ebp is null, skip this for now\n"); + LOG_INFO("ebp is null, skip this for now\n"); return ; } @@ -130,30 +108,23 @@ static void dump_backtrace(void *ptr, int depth) currentFrame.pReturnAddr = ((struct frame_layout *)pTopFrame)->pReturnAddr; pCurrentFrame = (struct frame_layout *)pTopFrame; - ERR("\nBacktrace Dump Start :\n"); if (pContext) { memset(module_buf, 0, sizeof(module_buf)); -#ifdef _WIN64 - hModule = get_module_handle((void *)((PCONTEXT)pContext)->Rip); -#else hModule = get_module_handle((void *)((PCONTEXT)pContext)->Eip); -#endif if (hModule) { if (!GetModuleFileNameA(hModule, module_buf, sizeof(module_buf))) { memset(module_buf, 0, sizeof(module_buf)); } } -#ifdef _WIN64 - ERR("[%02d]Addr = 0x%p : %s\n", nCount, ((PCONTEXT)pContext)->Rip, get_filename_from_path(module_buf)); -#else - ERR("[%02d]Addr = 0x%p : %s\n", nCount, ((PCONTEXT)pContext)->Eip, get_filename_from_path(module_buf)); -#endif + LOG_SEVERE("#%04d 0x%08x from %s\n", + nCount, ((PCONTEXT)pContext)->Eip, module_buf); nCount++; } while (1) { if (((void *)pCurrentFrame < pTopFrame) - || ((void *)pCurrentFrame >= (void *)0xC0000000)) { + || ((void *)pCurrentFrame >= (void *)0xC0000000) + || !currentFrame.pReturnAddr) { break; } @@ -164,127 +135,174 @@ static void dump_backtrace(void *ptr, int depth) memset(module_buf, 0, sizeof(module_buf)); } } - ERR("[%02d]Addr = 0x%p : %s\n", nCount, currentFrame.pReturnAddr, get_filename_from_path(module_buf)); + LOG_SEVERE("#%04d 0x%08x from %s\n", + nCount, currentFrame.pReturnAddr, module_buf); - if (!ReadProcessMemory(GetCurrentProcess(), currentFrame.pNext, + if (!ReadProcessMemory(GetCurrentProcess(), currentFrame.pNext, (void *)¤tFrame, sizeof(struct frame_layout), NULL)) { break; } pCurrentFrame = (struct frame_layout *)pCurrentFrame->pNext; - if (depth) { - if (!--depth) { - break; - } - } nCount++; } -#else - void *trace[1024]; - int ndepth = backtrace(trace, 1024); - ERR("Backtrace depth is %d.\n", ndepth); - - backtrace_symbols_fd(trace, ndepth, fileno(stderr)); -#endif } -static void handle_error_at_exit(void) +#else + +/* Windows 64 bit */ +static void dump_backtrace(void *ptr) { - if (print_backtrace_at_normal_exit_enabled) { - INFO("Stack backtrace for tracing...\n"); - INFO("This is not an error.\n"); - dump_backtrace(NULL, 0); + int i; + DWORD image; + STACKFRAME64 frame; + CONTEXT context; + HANDLE hProcess = GetCurrentProcess(); + HANDLE hThread = GetCurrentThread(); + + if (!ptr) { + ZeroMemory(&context, sizeof(CONTEXT)); + context.ContextFlags = CONTEXT_FULL; + RtlCaptureContext(&context); + } else { + CopyMemory(&context, ptr, sizeof(CONTEXT)); } -} -void enable_print_backtrace_at_normal_exit(void) { - print_backtrace_at_normal_exit_enabled = true; + SymSetOptions(SYMOPT_LOAD_LINES); + SymInitialize(hProcess, NULL, TRUE); + + ZeroMemory(&frame, sizeof(STACKFRAME64)); + image = IMAGE_FILE_MACHINE_AMD64; + frame.AddrPC.Offset = context.Rip; + frame.AddrPC.Mode = AddrModeFlat; + frame.AddrFrame.Offset = context.Rbp; + frame.AddrFrame.Mode = AddrModeFlat; + frame.AddrStack.Offset = context.Rsp; + frame.AddrStack.Mode = AddrModeFlat; + + i = 0; + while (1) { + BOOL result = StackWalk64(image, hProcess, hThread, + &frame, &context, NULL, + SymFunctionTableAccess64, + SymGetModuleBase64, NULL); + if (!result) { + break; + } + TCHAR buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)]; + PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer; + pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); + pSymbol->MaxNameLen = MAX_SYM_NAME; + DWORD64 displacement = 0; + TCHAR pFileName[MAX_PATH] = {0, }; + DWORD64 dwBase = SymGetModuleBase64(hProcess, frame.AddrPC.Offset); + if (dwBase) { + HMODULE hModule = (HMODULE)((DWORD_PTR)dwBase); + if (!GetModuleFileNameA(hModule, pFileName, MAX_PATH)) { + snprintf(pFileName, MAX_PATH, "Unknown Module"); + } + } + if (SymFromAddr(hProcess, + frame.AddrPC.Offset, + &displacement, pSymbol)) { + LOG_SEVERE("#%04d 0x%016x in %s from %s\n", + i, frame.AddrPC.Offset, pSymbol->Name, pFileName); + } else { + LOG_SEVERE("#%04d 0x%016x in ???????? from %s\n", + i, frame.AddrPC.Offset, pFileName); + } + i++; + } + SymCleanup(hProcess); } +#endif -#ifdef CONFIG_WIN32 -static WINAPI LONG maru_unhandled_exception_filter(LPEXCEPTION_POINTERS pExceptionInfo){ - char module_buf[1024]; +static WINAPI LONG +maru_unhandled_exception_filter(LPEXCEPTION_POINTERS pException) +{ + LOG_SEVERE("Exception occurred: Code[0x%x], Address[0x%016x]\n", + pException->ExceptionRecord->ExceptionCode, + pException->ExceptionRecord->ExceptionAddress); - // print system information again - print_system_info(); + dump_backtrace(pException->ContextRecord); - DWORD dwException = pExceptionInfo->ExceptionRecord->ExceptionCode; - ERR("%d\n ", (int)dwException); + return EXCEPTION_CONTINUE_SEARCH; +} - PEXCEPTION_RECORD pExceptionRecord; - HMODULE hModule; - PCONTEXT pContext; +static void register_exception_handler(void) +{ + prevExceptionFilter = + SetUnhandledExceptionFilter(maru_unhandled_exception_filter); +} - pExceptionRecord = pExceptionInfo->ExceptionRecord; +#else /* END FOR WINDOWS, START FOR LINUX & DARWIN */ - memset(module_buf, 0, sizeof(module_buf)); - hModule = get_module_handle(pExceptionRecord->ExceptionAddress); - if(hModule){ - if(!GetModuleFileNameA(hModule, module_buf, sizeof(module_buf))){ - memset(module_buf, 0, sizeof(module_buf)); - } - } +/* prevent an interrupt by another signal */ +QemuMutex siglock; +/* uses in case SIGSEGV */ +struct sigaction old_sa; - ERR("Exception [%X] occured at %s:0x%08x\n", - pExceptionRecord->ExceptionCode, - get_filename_from_path(module_buf), - pExceptionRecord->ExceptionAddress - ); +/* Print 'backtrace' */ +static void dump_backtrace(void *ptr) +{ + int i; + void *trace[1024]; + int ndepth = backtrace(trace, 1024); + char **syms = backtrace_symbols(trace, ndepth); - pContext = pExceptionInfo->ContextRecord; - dump_backtrace(pContext, 0); - _exit(0); - //return EXCEPTION_CONTINUE_SEARCH; + LOG_SEVERE("Backtrace depth is %d\n", ndepth); + for (i = 0; i < ndepth; i++) { + LOG_SEVERE("#%04d %s\n", i, syms[i]); + } + free(syms); } -#endif -#ifdef CONFIG_LINUX static void maru_sighandler(int sig) { - ERR("Got signal %d\n", sig); - // print system information again - print_system_info(); - - pthread_spin_lock(&siglock); - dump_backtrace(NULL, 0); - pthread_spin_unlock(&siglock); - _exit(0); + LOG_SEVERE("Got signal: %d(%s)\n", sig, strsignal(sig)); + + qemu_mutex_lock(&siglock); + dump_backtrace(NULL); + qemu_mutex_unlock(&siglock); + qemu_mutex_destroy(&siglock); + if (sig == SIGSEGV) { + sigaction(SIGSEGV, &old_sa, NULL); + raise(SIGSEGV); + } } -#endif - -#ifndef CONFIG_DARWIN static void register_exception_handler(void) { - #ifdef CONFIG_WIN32 - prevExceptionFilter = SetUnhandledExceptionFilter(maru_unhandled_exception_filter); - #else // LINUX void *trace[1]; struct sigaction sa; - // make dummy call to explicitly load glibc library + /* make dummy call to explicitly load glibc library */ backtrace(trace, 1); - pthread_spin_init(&siglock,0); - sa.sa_handler = (void*) maru_sighandler; + qemu_mutex_init(&siglock); + sa.sa_handler = maru_sighandler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; - sigaction(SIGSEGV, &sa, NULL); + /* store previous signal action */ + sigaction(SIGSEGV, &sa, &old_sa); sigaction(SIGBUS, &sa, NULL); sigaction(SIGILL, &sa, NULL); sigaction(SIGFPE, &sa, NULL); sigaction(SIGABRT, &sa, NULL); - // main thread only + /* main thread only */ sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); - #endif } -#else // CONFIG_DARWIN -static void register_exception_handler(void) +#endif /* END FOR LINUX & DARWIN */ + +static void handle_error_at_exit(void) { - // TODO: Exception handling on darwin + if (print_backtrace_at_normal_exit_enabled) { + LOG_INFO("Stack backtrace for tracing...\n"); + LOG_INFO("This is not an error\n"); + dump_backtrace(NULL); + } } -#endif #define MAX_MESSAGE_LEN 2048 static size_t message_len; @@ -296,9 +314,9 @@ static void report(const char *fmt, va_list ap) message_len = g_strlcat(message, new_message, MAX_MESSAGE_LEN); g_free(new_message); - // We are wating for '\n' + /* We are waiting for '\n' */ if (message[message_len - 1] == '\n') { -#if defined(CONFIG_QT) +#ifdef CONFIG_QT start_qt5_msgbox(CRITICAL_ICON, message); #endif @@ -307,10 +325,12 @@ static void report(const char *fmt, va_list ap) } } -static ErrorReporter error_reporter = - { .report = report }; +static ErrorReporter error_reporter = { + .report = report +}; -void init_error_handler(void) { +void init_error_handler(void) +{ register_exception_handler(); add_error_reporter(&error_reporter); -- cgit v1.2.3