//----------------------------------------------------------------------------// static void dumpBacktrace(size_t frames) { #if defined(__ANDROID__) // Not implemented yet. CEGUI_UNUSED(frames); #else #if defined(_DEBUG) || defined(DEBUG) #if defined(_MSC_VER) SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_INCLUDE_32BIT_MODULES); if (!SymInitialize(GetCurrentProcess(), 0, TRUE)) return; HANDLE thread = GetCurrentThread(); CONTEXT context; RtlCaptureContext(&context); STACKFRAME64 stackframe; ZeroMemory(&stackframe, sizeof(stackframe)); stackframe.AddrPC.Mode = AddrModeFlat; stackframe.AddrStack.Mode = AddrModeFlat; stackframe.AddrFrame.Mode = AddrModeFlat; #if _M_IX86 stackframe.AddrPC.Offset = context.Eip; stackframe.AddrStack.Offset = context.Esp; stackframe.AddrFrame.Offset = context.Ebp; DWORD machine_arch = IMAGE_FILE_MACHINE_I386; #elif _M_X64 stackframe.AddrPC.Offset = context.Rip; stackframe.AddrStack.Offset = context.Rsp; stackframe.AddrFrame.Offset = context.Rbp; DWORD machine_arch = IMAGE_FILE_MACHINE_AMD64; #endif char symbol_buffer[1024]; ZeroMemory(symbol_buffer, sizeof(symbol_buffer)); PSYMBOL_INFO symbol = reinterpret_cast<PSYMBOL_INFO>(symbol_buffer); symbol->SizeOfStruct = sizeof(SYMBOL_INFO); symbol->MaxNameLen = sizeof(symbol_buffer) - sizeof(SYMBOL_INFO); Logger& logger(Logger::getSingleton()); logger.logEvent("========== Start of Backtrace ==========", Errors); size_t frame_no = 0; while (StackWalk64(machine_arch, GetCurrentProcess(), thread, &stackframe, &context, 0, SymFunctionTableAccess64, SymGetModuleBase64, 0) && stackframe.AddrPC.Offset) { symbol->Address = stackframe.AddrPC.Offset; DWORD64 displacement = 0; char signature[256]; if (SymFromAddr(GetCurrentProcess(), symbol->Address, &displacement, symbol)) UnDecorateSymbolName(symbol->Name, signature, sizeof(signature), UNDNAME_COMPLETE); else sprintf_s(signature, sizeof(signature), "%p", ULongToPtr(symbol->Address)); IMAGEHLP_MODULE64 modinfo; modinfo.SizeOfStruct = sizeof(modinfo); const BOOL have_image_name = SymGetModuleInfo64(GetCurrentProcess(), symbol->Address, &modinfo); char outstr[512]; sprintf_s(outstr, sizeof(outstr), "#%d %s +%#llx (%s)", frame_no, signature, displacement, (have_image_name ? modinfo.LoadedImageName : "????")); logger.logEvent(outstr, Errors); if (++frame_no >= frames) break; if (!stackframe.AddrReturn.Offset) break; } logger.logEvent("========== End of Backtrace ==========", Errors); SymCleanup(GetCurrentProcess()); #elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__HAIKU__) void* buffer[frames]; const int received = backtrace(&buffer[0], frames); Logger& logger(Logger::getSingleton()); logger.logEvent("========== Start of Backtrace ==========", Errors); for (int i = 0; i < received; ++i) { char outstr[512]; Dl_info info; if (dladdr(buffer[i], &info)) { if (!info.dli_sname) snprintf(outstr, 512, "#%d %p (%s)", i, buffer[i], info.dli_fname); else { ptrdiff_t offset = static_cast<char*>(buffer[i]) - static_cast<char*>(info.dli_saddr); int demangle_result = 0; char* demangle_name = abi::__cxa_demangle(info.dli_sname, 0, 0, &demangle_result); snprintf(outstr, 512, "#%d %s +%#tx (%s)", i, demangle_name ? demangle_name : info.dli_sname, offset, info.dli_fname); std::free(demangle_name); } } else snprintf(outstr, 512, "#%d --- error ---", i); logger.logEvent(outstr, Errors); } logger.logEvent("========== End of Backtrace ==========", Errors); #else CEGUI_UNUSED(frames); #endif #else CEGUI_UNUSED(frames); #endif #endif }
// Returns a formatted stack trace (with g++ only). Note that it should _not_ throw an exception! // Credits go out to Timo Bingmann (http://idlebox.net/2008/0901-stacktrace-demangled/) std::string PepperException::stackTrace() { #if defined(__GLIBC__) || defined(POS_DARWIN) try { std::string str = "Stack trace:\n"; // storage array for stack trace address data void* addrlist[60+1]; // retrieve current stack addresses int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void*)); if (addrlen == 0) { str += " <empty, possibly corrupt>\n"; return str; } // resolve addresses into strings containing "filename(function+address)", // this array must be free()-ed char** symbollist = backtrace_symbols(addrlist, addrlen); // allocate string which will be filled with the demangled function name size_t funcnamesize = 256; char *funcname = new char[funcnamesize]; // iterate over the returned symbol lines. skip the first, it is the // address of this function. for (int i = 1; i < addrlen; i++) { char *begin_name = 0, *begin_offset = 0, *end_offset = 0; // find parentheses and +address offset surrounding the mangled name: // ./module(function+0x15c) [0x8048a6d] for (char *p = symbollist[i]; *p; ++p) { if (*p == '(') begin_name = p; else if (*p == '+') begin_offset = p; else if (*p == ')' && begin_offset) { end_offset = p; break; } } if (begin_name && begin_offset && end_offset && begin_name < begin_offset) { *begin_name++ = '\0'; *begin_offset++ = '\0'; *end_offset = '\0'; // mangled name is now in [begin_name, begin_offset) and caller // offset in [begin_offset, end_offset). now apply // __cxa_demangle(): int status; char* ret = abi::__cxa_demangle(begin_name, funcname, &funcnamesize, &status); if (status == 0) { funcname = ret; // use possibly realloc()-ed string str += " "; str += std::string(symbollist[i])+": "+(const char *)funcname+"+"+(const char *)begin_offset; } else { // demangling failed. Output function name as a C function with // no arguments. str += " "; str += std::string(symbollist[i])+": "+(const char *)begin_name+"()+"+(const char *)begin_offset; } } else { // couldn't parse the line? print the whole line. str += std::string(" ")+(const char *)symbollist[i]; } str += '\n'; } delete[] funcname; free(symbollist); return str; } catch (...) { return std::string(); } #else return std::string(); #endif }
// return 1: break (should stop being feed with debugger commands), 0: continue (can be feed with other debugger commands) static int process_debug_cmd(char *cmdline) { char *cmd = strtok(cmdline, " \n\r"); if (!cmd) return 0; if (!strcasecmp(cmd, "?") || !strcasecmp(cmd, "h")) { gui_debug_printf( "Debugger commands:\n" "b - stack backtrace\n" "c - continue\n" "d <address> - dump memory\n" "k <address> <+r|+w|+x|-r|-w|-x> - add/remove breakpoint\n" "k - show breakpoints\n" "ln c - connect\n" "ln s <file> - send a file\n" "ln st <dir> - set target directory\n" "mmu - dump memory mappings\n" "n - continue until next instruction\n" "pr <address> - port or memory read\n" "pw <address> <value> - port or memory write\n" "q - quit\n" "r - show registers\n" "rs <regnum> <value> - change register value\n" "ss <address> <length> <string> - search a string\n" "s - step instruction\n" "t+ - enable instruction translation\n" "t- - disable instruction translation\n" "u[a|t] [address] - disassemble memory\n" "wm <file> <start> <size> - write memory to file\n" "wf <file> <start> [size] - write file to memory\n" "exec <path> - exec file with ndless\n"); } else if (!strcasecmp(cmd, "b")) { char *fp = strtok(NULL, " \n\r"); backtrace(fp ? parse_expr(fp) : arm.reg[11]); } else if (!strcasecmp(cmd, "mmu")) { mmu_dump_tables(); } else if (!strcasecmp(cmd, "r")) { int i, show_spsr; uint32_t cpsr = get_cpsr(); const char *mode; for (i = 0; i < 16; i++) { int newline = ((1 << 5) | (1 << 11) | (1 << 15)) & (1 << i); gui_debug_printf("%3s=%08x%c", reg_name[i], arm.reg[i], newline ? '\n' : ' '); } switch (cpsr & 0x1F) { case MODE_USR: mode = "usr"; show_spsr = 0; break; case MODE_SYS: mode = "sys"; show_spsr = 0; break; case MODE_FIQ: mode = "fiq"; show_spsr = 1; break; case MODE_IRQ: mode = "irq"; show_spsr = 1; break; case MODE_SVC: mode = "svc"; show_spsr = 1; break; case MODE_ABT: mode = "abt"; show_spsr = 1; break; case MODE_UND: mode = "und"; show_spsr = 1; break; default: mode = "???"; show_spsr = 0; break; } gui_debug_printf("cpsr=%08x (N=%d Z=%d C=%d V=%d Q=%d IRQ=%s FIQ=%s T=%d Mode=%s)", cpsr, arm.cpsr_n, arm.cpsr_z, arm.cpsr_c, arm.cpsr_v, cpsr >> 27 & 1, (cpsr & 0x80) ? "off" : "on ", (cpsr & 0x40) ? "off" : "on ", cpsr >> 5 & 1, mode); if (show_spsr) gui_debug_printf(" spsr=%08x", get_spsr()); gui_debug_printf("\n"); } else if (!strcasecmp(cmd, "rs")) {
void *utlMem_alloc(UINT32 size, UINT32 allocFlags) { void *buf; UINT32 allocSize; #ifdef UTL_MEM_LEAK_TRACING initAllocSeq(); #endif allocSize = REAL_ALLOC_SIZE(size); buf = osl_malloc(allocSize); if (buf) { mStats.bytesAllocd += size; mStats.numAllocs++; } if (buf != NULL) { UINTPTR *intBuf = (UINTPTR *) buf; #ifdef UTL_MEM_DEBUG UINT32 intSize = allocSize / sizeof(UINTPTR); #endif if (allocFlags & ALLOC_ZEROIZE) { memset(buf, 0, allocSize); } #ifdef UTL_MEM_POISON_ALLOC_FREE else { /* * Set alloc'ed buffer to garbage to catch use-before-init. * But we also allocate huge buffers for storing image downloads. * Don't bother writing garbage to those huge buffers. */ if (allocSize < 64 * 1024) { memset(buf, UTL_MEM_ALLOC_PATTERN, allocSize); } } #endif /* * Record the allocFlags in the first word, and the * size of user buffer in the next 2 words of the buffer. * Make 2 copies of the size in case one of the copies gets corrupted by * an underflow. Make one copy the XOR of the other so that there are * not so many 0's in size fields. */ intBuf[0] = allocFlags; intBuf[1] = size; intBuf[2] = intBuf[1] ^ UTL_MEM_HEADER_MASK; buf = &(intBuf[3]); /* this gets returned to user */ #ifdef UTL_MEM_DEBUG { UINT8 *charBuf = (UINT8 *) buf; UINT32 i, roundupSize = ROUNDUP(size); for (i=size; i < roundupSize; i++) { charBuf[i] = UTL_MEM_FOOTER_PATTERN & 0xff; } intBuf[intSize - 1] = UTL_MEM_FOOTER_PATTERN; intBuf[intSize - 2] = UTL_MEM_FOOTER_PATTERN; } #endif #ifdef UTL_MEM_LEAK_TRACING { AllocRecord *allocRec; if (!(allocRec = calloc(1, sizeof(AllocRecord)))) { utlLog_error("could not malloc a record to track alloc"); } else { allocRec->bufAddr = buf; allocRec->userSize = size; allocRec->seq = allocSeq++; backtrace(allocRec->stackAddr, NUM_STACK_ENTRIES); /* * new allocs are placed at the beginning of the list, right after * the head. */ dlist_append((struct dlist_node *)allocRec, &glbAllocRec); } /* * do periodic garbage collection on the allocRecs which point * to shmBuf's that has been freed by another app. */ if ((allocSeq % 2000) == 0) { utlLog_debug("Starting allocRec garbage collection"); garbageCollectAllocRec(); utlLog_debug("garbage collection done"); } } #endif } return buf; }
/* This function is called when a segmentation fault is caught. The system is in an unstable state now. This means especially that malloc() might not work anymore. */ static void catch_segfault (int signal, SIGCONTEXT ctx) { int fd, cnt, i; void **arr; struct sigaction sa; uintptr_t pc; /* This is the name of the file we are writing to. If none is given or we cannot write to this file write to stderr. */ fd = 2; if (fname != NULL) { fd = open (fname, O_TRUNC | O_WRONLY | O_CREAT, 0666); if (fd == -1) fd = 2; } WRITE_STRING ("*** "); write_strsignal (fd, signal); WRITE_STRING ("\n"); #ifdef REGISTER_DUMP REGISTER_DUMP; #endif WRITE_STRING ("\nBacktrace:\n"); /* Get the backtrace. */ arr = alloca (256 * sizeof (void *)); cnt = backtrace (arr, 256); /* Now try to locate the PC from signal context in the backtrace. Normally it will be found at arr[2], but it might appear later if there were some signal handler wrappers. Allow a few bytes difference to cope with as many arches as possible. */ pc = (uintptr_t) GET_PC (ctx); for (i = 0; i < cnt; ++i) if ((uintptr_t) arr[i] >= pc - 16 && (uintptr_t) arr[i] <= pc + 16) break; /* If we haven't found it, better dump full backtrace even including the signal handler frames instead of not dumping anything. */ if (i == cnt) i = 0; /* Now generate nicely formatted output. */ __backtrace_symbols_fd (arr + i, cnt - i, fd); #ifdef HAVE_PROC_SELF /* Now the link map. */ int mapfd = open ("/proc/self/maps", O_RDONLY); if (mapfd != -1) { write (fd, "\nMemory map:\n\n", 14); char buf[256]; ssize_t n; while ((n = TEMP_FAILURE_RETRY (read (mapfd, buf, sizeof (buf)))) > 0) TEMP_FAILURE_RETRY (write (fd, buf, n)); close (mapfd); } #endif /* Pass on the signal (so that a core file is produced). */ sa.sa_handler = SIG_DFL; sigemptyset (&sa.sa_mask); sa.sa_flags = 0; sigaction (signal, &sa, NULL); raise (signal); }
void CExceptionHandler::WriteExceptionReport() #endif { // Get the current time and date time_t t = time(NULL); const struct tm * tm = localtime(&t); // Get the 'crashinfo' directory path String strPath(SharedUtility::GetAbsolutePath("crashinfo")); // Create the 'crashinfo' directory if needed if(!SharedUtility::Exists(strPath)) SharedUtility::CreateDirectory(strPath); // Append the client or server string to the path #ifdef _SERVER strPath.Append("/Server"); #else strPath.Append("/Client"); #endif // Append the operating system string to the path strPath.Append("-" OS_STRING); // Append the version, date and time to the path strPath.AppendF("-" MOD_VERSION_STRING "-%04d.%02d.%02d-%02d.%02d.%02d", (tm->tm_year + 1900), (tm->tm_mon + 1), tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); // Get the log file path String strLogPath("%s.log", strPath.Get()); // Open the log file FILE * fFile = fopen(strLogPath, "w"); CLogFile::Printf(strLogPath); String reportData; // Did the log file open successfully? if(fFile) { // Write the unhandled exception report start notice to the log file fprintf(fFile, "-- Unhandled Exception Report Start --\n"); #ifdef WIN32 // Write the exception code and exception code string to the log file fprintf(fFile, "Exception code: 0x%p (%s)\n", ExceptionInfo->ExceptionRecord->ExceptionCode, ExceptionCodeToString(ExceptionInfo->ExceptionRecord->ExceptionCode)); // Write the exception address to the log file #ifndef _SERVER fprintf(fFile, "Exception address: 0x%p (0x%p)\n", ExceptionInfo->ExceptionRecord->ExceptionAddress, CGame::GetBase()); fprintf(fFile, "Exception real-add: 0x%p / 0x%p\n", ((int)ExceptionInfo->ExceptionRecord->ExceptionAddress-CGame::GetBase()), (CGame::GetBase()-(int)ExceptionInfo->ExceptionRecord->ExceptionAddress)); #else fprintf(fFile, "Exception address: 0x%p\n", ExceptionInfo->ExceptionRecord->ExceptionAddress); #endif // Create a tool help 32 process snapshot HANDLE hModuleSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, GetCurrentProcessId()); if(hModuleSnapShot) { MODULEENTRY32 ModuleEntry; ModuleEntry.dwSize = sizeof(ModuleEntry); if(Module32First(hModuleSnapShot, &ModuleEntry)) { // Enumerate through all modules while(Module32Next(hModuleSnapShot, &ModuleEntry)) { // See if exception was within this module if((ExceptionInfo->ContextRecord->Eip >= (DWORD)ModuleEntry.modBaseAddr) && (ExceptionInfo->ContextRecord->Eip <= ((DWORD)ModuleEntry.modBaseAddr + ModuleEntry.modBaseSize))) { fprintf(fFile, "Exception module: %s (+0x%p)\n", ModuleEntry.szModule, (ExceptionInfo->ContextRecord->Eip - (DWORD)ModuleEntry.modBaseAddr)); break; } } } } fprintf(fFile, "--Unhandled Exception Report End --\n"); fclose(fFile); // Print a message in the log file CLogFile::Printf("IV:MP has crashed. Please see %s for more information.", strLogPath.Get()); FILE * pFile; pFile = fopen (strLogPath, "r"); if (pFile != NULL) { fseek(pFile ,0 , SEEK_END); int lSize = ftell (pFile); char* buffer = (char*) malloc (sizeof(char)*lSize); if (buffer == NULL) { fclose(pFile); } else { fseek(pFile, 0, SEEK_SET); size_t result = fread (buffer, 1, lSize, pFile); reportData = buffer; fclose(pFile); } } #ifdef WIN32 WinExec((SharedUtility::GetAbsolutePath("crashreporter.exe ") + reportData).Get(), SW_SHOW); return; #endif // Write the registers segment header fprintf(fFile, "Exception registers: \n"); // If we have segments context information then write it to the log file if(ExceptionInfo->ContextRecord->ContextFlags & CONTEXT_SEGMENTS) { fprintf(fFile, "GS=0x%p FS=0x%p ES=0x%p DS=0x%p\n", ExceptionInfo->ContextRecord->SegGs, ExceptionInfo->ContextRecord->SegFs, ExceptionInfo->ContextRecord->SegEs, ExceptionInfo->ContextRecord->SegDs); } // If we have integer context information then write it to the log file if(ExceptionInfo->ContextRecord->ContextFlags & CONTEXT_INTEGER) { fprintf(fFile, "EDI=0x%p ESI=0x%p EBX=0x%p EDX=0x%p\n", ExceptionInfo->ContextRecord->Edi, ExceptionInfo->ContextRecord->Esi, ExceptionInfo->ContextRecord->Ebx, ExceptionInfo->ContextRecord->Edx); fprintf(fFile, "ECX=0x%p EAX=0x%p\n", ExceptionInfo->ContextRecord->Ecx, ExceptionInfo->ContextRecord->Eax); } // If we have control context information then write it to the log file if(ExceptionInfo->ContextRecord->ContextFlags & CONTEXT_CONTROL) { fprintf(fFile, "EBP=0x%p EIP=0x%p CS=0x%p EFLAGS=0x%p\n", ExceptionInfo->ContextRecord->Ebp, ExceptionInfo->ContextRecord->Eip, ExceptionInfo->ContextRecord->SegCs, ExceptionInfo->ContextRecord->EFlags); fprintf(fFile, "ESP=0x%p SS=0x%p\n", ExceptionInfo->ContextRecord->Esp, ExceptionInfo->ContextRecord->SegSs); } #else void * pArray[50]; int size = backtrace(pArray, 50); char ** szMessages = backtrace_symbols(pArray, size); for(int i = 0; i < size && szMessages != NULL; i++) fprintf(fFile, "[Backtrace %d]: %s\n", szMessages[i]); #endif // If we have a callback call it if(m_pfnCallback) m_pfnCallback(fFile); // Write the unhandled exception report end notice to the log file fprintf(fFile, "--Unhandled Exception Report End --\n"); #ifndef _SERVER #ifdef _CLIENT_LOG_REPORT fprintf(fFile, "\n\n------------------------- Client Log -------------------------\n\n\n"); FILE * pFile; String strClientLogOrgPath("%sClient.log",SharedUtility::GetAppPath()); pFile = fopen (strClientLogOrgPath.Get(), "r"); if (pFile != NULL) { fseek(pFile ,0 , SEEK_END); int lSize = ftell (pFile); char* buffer = (char*) malloc (sizeof(char)*lSize); if (buffer == NULL) { fclose(pFile); } else { fseek(pFile, 0, SEEK_SET); size_t result = fread (buffer, 1, lSize, pFile); fprintf(fFile, "%s\n\n", buffer); fprintf(fFile, "---------------------- Client Log End -----------------------\n"); fclose(pFile); } } #endif #endif } // Close the log file fclose(fFile); #ifdef WIN32 // Get the minidump file path String strMiniDumpPath("%s.dmp", strPath.Get()); // Open the minidump file HANDLE hFile = CreateFileA(strMiniDumpPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL , NULL); // Did the minidump file open successfully? if(hFile) { // Create the minidump exception information MINIDUMP_EXCEPTION_INFORMATION exceptionInfo; exceptionInfo.ThreadId = GetCurrentThreadId(); exceptionInfo.ExceptionPointers = ExceptionInfo; exceptionInfo.ClientPointers = FALSE; // Write the minidump to the minidump file bool bWritten = (MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &exceptionInfo, NULL, NULL) != 0); // Close the minidump file CloseHandle(hFile); } #endif // Print a message in the log file CLogFile::Printf("IV:MP has crashed. Please see %s for more information.", strLogPath.Get()); #ifdef WIN32 CreateProcess(SharedUtility::GetAbsolutePath("crashreporter.exe"), (LPSTR)strPath.Get(), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); #endif }
// CmpErrLog::writeQueryInfo() writes the stack trace of the // compiler to the log file. void CmpErrLog::writeStackTrace() { fprintf(fp, "Process Stack Trace:\n"); // This is a quick and dirty implementation for Linux. It is easy to // get the program counters for the stack trace, but is difficult to // look up the function name, line, and file number based off of the // program counter. For simplicity, this code just calls addr2line to // look up the information. This could be changed in the future if an // easy to use API becomes available. void *bt[20]; size_t size = backtrace(bt, 20); pid_t myPID = getpid(); // Write each level of the stack except for the top frame and the // bottom two frames, which aren't important here. Int32 i = 1; while (i < size - 2) { char buffer[128]; // Used for command-line + addr2line output. sprintf(buffer, "/usr/bin/addr2line -e /proc/%d/exe -f -C ", myPID); Int32 j; // Run addr2line on 5 addresses at a time. for (j = i; j < i+5 && j < size-2; j++) { char addrBuf[12]; sprintf(addrBuf, " %p", bt[j]); strcat(buffer, addrBuf); } FILE *cmdFP = popen(buffer, "r"); if (cmdFP == NULL) { fprintf(fp, "Error %d while popen() of %s\n", errno, buffer); break; } else { for (j = i; j < i+5 && j < size-2; j++) { // Read from the addr2line output fgets(buffer, sizeof(buffer), cmdFP); // Replace newline with null character size_t len = strlen(buffer); if (buffer[len-1] == '\n') buffer[len-1] = '\0'; fprintf(fp, "%p: %s()\n", bt[j], buffer); fgets(buffer, sizeof(buffer), cmdFP); fprintf(fp, " %s", buffer); } fclose(cmdFP); } i = j; } fputc('\n', fp); }
int write_log(log_type_t log_type, char *message) { if (created_logger == NULL) { perror("Logger is not initialized! There is not possible to write a message!\n"); return -1; } if (message == NULL) { errno = EINVAL; perror("It is impossible to set file! Input message is wrong!\n"); return -2; } if (log_type > Fatal) { perror("Log level is wrong!\n"); return -3; } if (log_type < Debug) { return -4; } if (log_type == Fatal) { int i = 0; if(created_logger -> buffer -> num_of_circules == 0) { for (i = 0; i < created_logger -> buffer -> position_of_last_empty; i++) { fputs(created_logger -> buffer -> buffer[i], created_logger -> file_pointer); free(created_logger -> buffer -> buffer[i]); created_logger -> buffer -> buffer[i] = NULL; } } else { for (i = 0; i < BUFFER_SIZE; i++) { fputs(created_logger -> buffer -> buffer[i], created_logger -> file_pointer); free(created_logger -> buffer -> buffer[i]); created_logger -> buffer -> buffer[i] = NULL; } } int nptrs = backtrace(buffer_for_stack, SIZE); char **stack_interior; stack_interior = backtrace_symbols(buffer_for_stack, SIZE); for(i = 0; i < nptrs; i++) { printf("%s\n",stack_interior[i]); } logger_deinit(); return -5; } if(log_type < Fatal) { if(created_logger -> buffer -> position_of_last_empty == BUFFER_SIZE) { created_logger -> buffer -> position_of_last_empty = 0; created_logger -> buffer -> num_of_circules += 1; } if(created_logger -> buffer -> num_of_circules != 0) { free(created_logger -> buffer -> buffer[created_logger -> buffer-> position_of_last_empty]); created_logger -> buffer -> buffer[created_logger -> buffer-> position_of_last_empty] = NULL; } created_logger -> buffer -> buffer[created_logger -> buffer-> position_of_last_empty] = formulate_message(log_type, message); created_logger -> buffer -> position_of_last_empty +=1; return 0; } }
void mybacktrace(void) { ENTRY(); void *pointers[16]; size_t count; char **functions; count = backtrace(pointers, 16); functions = backtrace_symbols(pointers, count); size_t i; for(i = 1; i < count; ++i) { size_t sz = 200; char *function = static_cast<char *>(malloc(sz)); char *begin = 0; char *end = 0; // find the parentheses and address offset surrounding the mangled name for(char *j = functions[i]; *j; ++j) { if (*j == '(') { begin = j; } else { if (*j == '+') { end = j; } } } if(begin && end) { *begin++ = '\0'; *end = '\0'; // found our mangled name, now in [begin, end) int status; char *ret = abi::__cxa_demangle(begin, function, &sz, &status); if(ret != NULL) { // return value may be a realloc() of the input function = ret; } else { // demangling failed, just pretend it's a C function with no args strncpy(function, begin, sz); strncat(function, "()", sz); function[sz - 1] = '\0'; } PRINTF("%s:%s\n", functions[i], function); } else { // didn't find the mangled name, just print the whole line PRINTF("%s\n", functions[i]); } free(function); } free(functions); EXIT(); }
unsigned int flag; if ((flagStr = getenv(name)) == NULL) return 0; if (virStrToLong_ui(flagStr, NULL, 10, &flag) < 0) return 0; return flag; } #ifdef TEST_OOM_TRACE static void virTestAllocHook(int nalloc ATTRIBUTE_UNUSED, void *opaque ATTRIBUTE_UNUSED) { ntestAllocStack = backtrace(testAllocStack, ARRAY_CARDINALITY(testAllocStack)); } #endif #ifdef TEST_OOM_TRACE static void virTestShowTrace(void) { size_t j; for (j = 2; j < ntestAllocStack; j++) { Dl_info info; char *cmd; dladdr(testAllocStack[j], &info); if (info.dli_fname && strstr(info.dli_fname, ".so")) {
static int xbt_log_layout_format_doit(xbt_log_layout_t l, xbt_log_event_t ev, const char *msg_fmt) { char *p = ev->buffer; int rem_size = ev->buffer_size; int precision = -1; int length = -1; char *q; for (q = l->data ; *q != '\0' ; q++) { if (*q == '%') { q++; handle_modifier: switch (*q) { case '\0': fprintf(stderr, "Layout format (%s) ending with %%\n", (char *)l->data); xbt_abort(); case '%': *p = '%'; check_overflow(1); break; case 'n': /* platform-dependant line separator; LOG4J compliant */ *p = '\n'; check_overflow(1); break; case 'e': /* plain space; SimGrid extension */ *p = ' '; check_overflow(1); break; case '.': /* precision specifier */ precision = strtol(q + 1, &q, 10); goto handle_modifier; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': /* length modifier */ length = strtol(q, &q, 10); goto handle_modifier; case 'c': /* category name; LOG4J compliant should accept a precision postfix to show the hierarchy */ show_string(ev->cat->name); break; case 'p': /* priority name; LOG4J compliant */ show_string(xbt_log_priority_names[ev->priority]); break; case 'h': /* host name; SimGrid extension */ show_string(SIMIX_host_self_get_name()); break; case 't': /* thread name; LOG4J compliant */ show_string(xbt_thread_self_name()); break; case 'P': /* process name; SimGrid extension */ show_string(xbt_procname()); break; case 'i': /* process PID name; SimGrid extension */ show_int(xbt_getpid()); break; case 'F': /* file name; LOG4J compliant */ show_string(ev->fileName); break; case 'l': { /* location; LOG4J compliant */ int len, sz; set_sz_from_precision(); len = snprintf(p, sz, "%s:%d", ev->fileName, ev->lineNum); check_overflow(MIN(sz, len)); break; } case 'L': /* line number; LOG4J compliant */ show_int(ev->lineNum); break; case 'M': /* method (ie, function) name; LOG4J compliant */ show_string(ev->functionName); break; case 'b': /* backtrace; called %throwable in LOG4J */ case 'B': /* short backtrace; called %throwable{short} in LOG4J */ #if defined(HAVE_EXECINFO_H) && defined(HAVE_POPEN) && defined(ADDR2LINE) { xbt_ex_t e; e.used = backtrace((void **) e.bt, XBT_BACKTRACE_SIZE); e.bt_strings = NULL; e.msg = NULL; xbt_ex_setup_backtrace(&e); if (*q == 'B') { show_string(e.bt_strings[1] + 8); } else { xbt_strbuff_t buff = xbt_strbuff_new(); int i; xbt_strbuff_append(buff, e.bt_strings[1] + 8); for (i = 2; i < e.used; i++) { xbt_strbuff_append(buff, "\n"); xbt_strbuff_append(buff, e.bt_strings[i] + 8); } show_string(buff->data); xbt_strbuff_free(buff); } xbt_ex_free(e); } #else show_string("(no backtrace on this arch)"); #endif break; case 'd': /* date; LOG4J compliant */ show_double(surf_get_clock()); break; case 'r': /* application age; LOG4J compliant */ show_double(surf_get_clock() - format_begin_of_time); break; case 'm': { /* user-provided message; LOG4J compliant */ int len, sz; set_sz_from_precision(); len = vsnprintf(p, sz, msg_fmt, ev->ap); check_overflow(MIN(sz, len)); break; } default: fprintf(stderr, ERRMSG, *q, (char *)l->data); xbt_abort(); } } else { *p = *q; check_overflow(1); } } *p = '\0'; return 1; }
sci_backtrace_t *sci_backtrace_create(void) { #if defined(HAVE_GLIBC_BACKTRACE) sci_backtrace_t *bt = NULL; /* Create backtrace structure */ bt = malloc(sizeof(sci_backtrace_t)); if (bt != NULL) { void * tr_array[200]; int tr_size = backtrace(tr_array, 200); int i = 0; Dl_info * infos = NULL; /* Create arrays; we use malloc() here instead of BFT_MALLOC, as a * backtrace is useful mainly in case of severe errors, so we avoid * higher level constructs as much as possible at this stage. */ if (tr_size < 2)// || tr_strings == NULL) { free(bt); return NULL; } bt->size = tr_size; bt->s_file = malloc(tr_size * sizeof(char *)); bt->s_func = malloc(tr_size * sizeof(char *)); bt->s_addr = malloc(tr_size * sizeof(char *)); /* If allocation has failed, free other allocated arrays, and return NULL */ if (bt->s_file == NULL || bt->s_func == NULL || bt->s_addr == NULL) { if (bt->s_file != NULL) { free(bt->s_file); } if (bt->s_func != NULL) { free(bt->s_func); } if (bt->s_addr != NULL) { free(bt->s_addr); } free(bt); return NULL; } infos = (Dl_info *)MALLOC(sizeof(Dl_info)); for (i = 0; i < bt->size; i++) { char buffer[32]; void * p = tr_array[i]; bt->s_file[i] = NULL; bt->s_func[i] = NULL; bt->s_addr[i] = NULL; if (dladdr(p, infos)) { bt->s_func[i] = infos->dli_sname ? strdup(infos->dli_sname) : strdup(" "); bt->s_file[i] = infos->dli_fname ? strdup(infos->dli_fname) : strdup(" "); // we calculate the relative address in the library snprintf(buffer, 32, "%p", p - infos->dli_fbase); bt->s_addr[i] = strdup(buffer); } } FREE(infos); infos = NULL; } return bt; #else /* defined(HAVE_GLIBC_BACKTRACE) */ return NULL; #endif }
void catchsegv(int sig __attribute__ ((unused))) #endif { char buf[1024]; FILE *g; logmsg("Catched SIGSEGV"); logmsg("Apologies ... this shouldn't have happened. Please verify that"); logmsg("you are running the most current version, downloadable from"); logmsg(" http://www.pro-bono-publico.de/projects/"); logmsg("If the version on that site doesn't equal"); logmsg(" " VERSION); logmsg("please download, compile, install and check if you're"); logmsg("still seeing the crash. After all, this bug may be already fixed."); logmsg("If the issue persists even with the most recent version:"); logmsg("Reconfigure with --debug, recompile and reinstall. Then send"); logmsg("a bug report to the mailing-list at"); logmsg(" [email protected]"); logmsg("and include the backtraces."); logmsg("Please do NOT mail bug reports it to the private mail address of"); logmsg("the author, unless you have a pretty good reason for doing so."); logmsg("Thank you."); snprintf(buf, sizeof(buf), "CRASHPID=%lu", (long unsigned) getpid()); putenv(buf); #ifdef HAVE_EXECINFO_H { void *array[40]; int len = backtrace(array, 40); char **c = backtrace_symbols(array, len); logmsg("EXECINFO: backtrace start"); while (len-- > 0) logmsg("EXECINFO: %d %s", len, c[len]); logmsg("EXECINFO: backtrace end"); } #endif /* HAVE_EXECINFO_H */ if (!gdbcmd) gdbcmd = "(printf 'bt\nq\n';sleep 3)|gdb -n -q -p $CRASHPID 2>/dev/null"; g = popen(gdbcmd, "r"); if (g) { logmsg("GDB: running: \"%s\"", gdbcmd); logmsg("GDB: backtrace start"); while (fgets(buf, sizeof(buf), g)) logmsg("GDB: %s", buf); fclose(g); logmsg("GDB: backtrace end"); } #ifdef EXC_BAD_INSTRUCTION signal(EXC_BAD_INSTRUCTION, SIG_DFL); #endif #ifdef SIGBUS signal(SIGBUS, SIG_DFL); #endif signal(SIGSEGV, SIG_DFL); if (coredumpdir) { struct rlimit rlim; char cdf[PATH_MAX]; snprintf(cdf, sizeof(cdf), "%s/core.%.8lx", coredumpdir, (u_long) time(NULL)); seteuid(getuid()); setegid(getgid()); if (getrlimit(RLIMIT_CORE, &rlim)) { logerr("getrlimit (%s:%d)", __FILE__, __LINE__); exit(EX_OSERR); } rlim.rlim_cur = rlim.rlim_max; setrlimit(RLIMIT_CORE, &rlim); if (chdir(coredumpdir)) { logerr("SIGSEGV: chdir(%s) (%s:%d)", coredumpdir, __FILE__, __LINE__); exit(EX_NOPERM); } rename("core", cdf); logmsg("SIGSEGV: Trying to dump core in %s", coredumpdir); if (gcorecmd) { g = popen(gcorecmd, "r"); if (g) { while (fgets(buf, sizeof(buf), g)) logmsg("GCORE: %s", buf); fclose(g); } } else abort(); } exit(EX_UNAVAILABLE); }
static void SIG_HANDLER_SIGNATURE (sigprof_signal_handler) { int call_chain_depth = mono_profiler_stat_get_call_chain_depth (); MonoProfilerCallChainStrategy call_chain_strategy = mono_profiler_stat_get_call_chain_strategy (); GET_CONTEXT; if (call_chain_depth == 0) { mono_profiler_stat_hit (mono_arch_ip_from_context (ctx), ctx); } else { MonoJitTlsData *jit_tls = mono_native_tls_get_value (mono_jit_tls_id); int current_frame_index = 1; MonoContext mono_context; guchar *ips [call_chain_depth + 1]; mono_arch_sigctx_to_monoctx (ctx, &mono_context); ips [0] = MONO_CONTEXT_GET_IP (&mono_context); if (jit_tls != NULL) { if (call_chain_strategy == MONO_PROFILER_CALL_CHAIN_NATIVE) { #if FULL_STAT_PROFILER_BACKTRACE guchar *current_frame; guchar *stack_bottom; guchar *stack_top; stack_bottom = jit_tls->end_of_stack; stack_top = MONO_CONTEXT_GET_SP (&mono_context); current_frame = MONO_CONTEXT_GET_BP (&mono_context); while ((current_frame_index <= call_chain_depth) && (stack_bottom IS_BEFORE_ON_STACK (guchar*) current_frame) && ((guchar*) current_frame IS_BEFORE_ON_STACK stack_top)) { ips [current_frame_index] = CURRENT_FRAME_GET_RETURN_ADDRESS (current_frame); current_frame_index ++; stack_top = current_frame; current_frame = CURRENT_FRAME_GET_BASE_POINTER (current_frame); } #else call_chain_strategy = MONO_PROFILER_CALL_CHAIN_GLIBC; #endif } if (call_chain_strategy == MONO_PROFILER_CALL_CHAIN_GLIBC) { #if GLIBC_PROFILER_BACKTRACE current_frame_index = backtrace ((void**) & ips [1], call_chain_depth); #else call_chain_strategy = MONO_PROFILER_CALL_CHAIN_MANAGED; #endif } if (call_chain_strategy == MONO_PROFILER_CALL_CHAIN_MANAGED) { MonoDomain *domain = mono_domain_get (); if (domain != NULL) { MonoLMF *lmf = NULL; MonoJitInfo *ji; MonoJitInfo res; MonoContext new_mono_context; int native_offset; ji = mono_find_jit_info (domain, jit_tls, &res, NULL, &mono_context, &new_mono_context, NULL, &lmf, &native_offset, NULL); while ((ji != NULL) && (current_frame_index <= call_chain_depth)) { ips [current_frame_index] = MONO_CONTEXT_GET_IP (&new_mono_context); current_frame_index ++; mono_context = new_mono_context; ji = mono_find_jit_info (domain, jit_tls, &res, NULL, &mono_context, &new_mono_context, NULL, &lmf, &native_offset, NULL); } } } } mono_profiler_stat_call_chain (current_frame_index, & ips [0], ctx); } mono_chain_signal (SIG_HANDLER_PARAMS); }
static void signal_handler(int signo, siginfo_t* info, void* context) { /* int status; int i; */ /* ------------------------------------------------------------ */ switch(signo) { case SIGHUP: { signal_task_logger_handle_reopen_all(); break; } case SIGUSR1: { /* write all (dirty) zones to disk */ signal_task_database_save_all_zones_to_disk(); break; } case SIGUSR2: { // Used to break a syscall (sync) break; } case SIGINT: case SIGTERM: { /* * We are shutting down : ignore other "command" signals */ signal(SIGHUP, SIG_IGN); signal(SIGUSR1, SIG_IGN); signal(SIGINT, SIG_IGN); signal(SIGTERM, SIG_IGN); signal_task_shutdown(); break; } #if SIGNAL_HOOK_COREDUMP == 0 case SIGBUS: case SIGFPE: case SIGILL: case SIGSEGV: { signal(signo, SIG_DFL); if(sigsegv_trytrace) { char filepath[1024]; FILE *f; /* So if we crashed while trying to dump, we will not do it anymore */ sigsegv_trytrace = FALSE; snprintf(filepath, sizeof(filepath), "%ssig%i.%i", config->log_path, signo, getpid()); f = fopen(filepath, "a+"); if(f == NULL) { snprintf(filepath, sizeof(filepath), "/tmp/yadifa.sig%i.%i", signo, getpid()); f = fopen(filepath, "a+"); } if(f != NULL) { #if defined(__linux__) void* buffer[MAXTRACE]; char** strings; int n = backtrace(buffer, MAXTRACE); int i; time_t now = time(NULL); fprintf(f, "Signal %i at time=%li for address %p\n", signo, now, info->si_addr); fflush(f); strings = backtrace_symbols(buffer, n); if(strings != NULL) { for(i = 0; i < n; i++) { fprintf(f, "\t[%3i]: %s\n", i, strings[i]); } } else { fprintf(f, "No backtrace available (%s)\n", strerror(errno)); } fflush(f); fprintf(f, "pid: %i\n", getpid()); fprintf(f, "thread id: %d", (u32)pthread_self()); #else fprintf(f, "Got signal %i. No backtrace available\n", signo); #endif fclose(f); } /** * Do NOT free(strings) : * If the memory is corrupted, this is one more chance to crash * */ } /* There COULD be some relevant information in the logger */ /* try to flush it */ if(sigsegv_tryloggerflush) { sigsegv_tryloggerflush = FALSE; logger_flush(); log_err("CRITICAL ERROR"); logger_flush(); } /* trigger the original signal (to dump a core if possible ) */ raise(signo); /* should never be reached : Exit without disabling stuff (no atexit registered function called) */ _exit(EXIT_CODE_SELFCHECK_ERROR); break; } #endif /* case SIGUSR2: case SIGCHLD: */ default: { break; } } }
static void traphandler(int sig, siginfo_t *si, void *UC) { ucontext_t *uc = UC; if(extra_traphandler != NULL && !extra_traphandler(sig, si, UC)) return; static void *frames[MAXFRAMES]; char buf[256]; int nframes = backtrace(frames, MAXFRAMES); const char *reason = NULL; TRAPMSG("Signal: %d in %s ", sig, line1); switch(sig) { case SIGSEGV: switch(si->si_code) { case SEGV_MAPERR: reason = "Address not mapped"; break; case SEGV_ACCERR: reason = "Access error"; break; } break; case SIGFPE: switch(si->si_code) { case FPE_INTDIV: reason = "Integer division by zero"; break; } break; } addr2text(buf, sizeof(buf), si->si_addr); TRAPMSG("Fault address %s (%s)", buf, reason ?: "N/A"); TRAPMSG("Loaded libraries: %s ", libs); #if defined(__arm__) TRAPMSG(" trap_no = %08lx", uc->uc_mcontext.trap_no); TRAPMSG("error_code = %08lx", uc->uc_mcontext.error_code); TRAPMSG(" oldmask = %08lx", uc->uc_mcontext.oldmask); TRAPMSG(" R0 = %08lx", uc->uc_mcontext.arm_r0); TRAPMSG(" R1 = %08lx", uc->uc_mcontext.arm_r1); TRAPMSG(" R2 = %08lx", uc->uc_mcontext.arm_r2); TRAPMSG(" R3 = %08lx", uc->uc_mcontext.arm_r3); TRAPMSG(" R4 = %08lx", uc->uc_mcontext.arm_r4); TRAPMSG(" R5 = %08lx", uc->uc_mcontext.arm_r5); TRAPMSG(" R6 = %08lx", uc->uc_mcontext.arm_r6); TRAPMSG(" R7 = %08lx", uc->uc_mcontext.arm_r7); TRAPMSG(" R8 = %08lx", uc->uc_mcontext.arm_r8); TRAPMSG(" R9 = %08lx", uc->uc_mcontext.arm_r9); TRAPMSG(" R10 = %08lx", uc->uc_mcontext.arm_r10); TRAPMSG(" FP = %08lx", uc->uc_mcontext.arm_fp); TRAPMSG(" IP = %08lx", uc->uc_mcontext.arm_ip); TRAPMSG(" SP = %08lx", uc->uc_mcontext.arm_sp); TRAPMSG(" LR = %08lx", uc->uc_mcontext.arm_lr); TRAPMSG(" PC = %08lx", uc->uc_mcontext.arm_pc); TRAPMSG(" CPSR = %08lx", uc->uc_mcontext.arm_cpsr); TRAPMSG("fault_addr = %08lx", uc->uc_mcontext.fault_address); #else char tmpbuf[1024]; snprintf(tmpbuf, sizeof(tmpbuf), "Register dump [%d]: ", NGREG); int i; for(i = 0; i < NGREG; i++) { #if __WORDSIZE == 64 sappend(tmpbuf, sizeof(tmpbuf), "%016llx ", uc->uc_mcontext.gregs[i]); #else sappend(tmpbuf, sizeof(tmpbuf), "%08x ", uc->uc_mcontext.gregs[i]); #endif } TRAPMSG("%s", tmpbuf); #endif dumpstack(frames, nframes); _exit(8); }
/** Print a demangled stack backtrace of the caller function to FILE* out. */ static inline void print_stacktrace(FILE *out = stderr, unsigned int max_frames = 63) { pvStackTrace() << "stack trace:" << std::endl; // storage array for stack trace address data void *addrlist[max_frames+1]; // retrieve current stack addresses int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void*)); if (addrlen == 0) { pvStackTrace() << " <empty, possibly corrupt>" << std::endl; return; } // resolve addresses into strings containing "filename(function+address)", // this array must be free()-ed char** symbollist = backtrace_symbols(addrlist, addrlen); // allocate string which will be filled with the demangled function name size_t funcnamesize = 256; char* funcname = (char*) malloc(funcnamesize); // iterate over the returned symbol lines. skip the first, it is the // address of this function. for (int i = 1; i < addrlen; i++) { char *begin_name = 0, *begin_offset = 0, *end_offset = 0; // find parentheses and +address offset surrounding the mangled name: // ./module(function+0x15c) [0x8048a6d] for (char *p = symbollist[i]; *p; ++p) { if (*p == '(') begin_name = p; else if (*p == '+') begin_offset = p; else if (*p == ')' && begin_offset) { end_offset = p; break; } } if (begin_name && begin_offset && end_offset && begin_name < begin_offset) { *begin_name++ = '\0'; *begin_offset++ = '\0'; *end_offset = '\0'; // mangled name is now in [begin_name, begin_offset) and caller // offset in [begin_offset, end_offset). now apply // __cxa_demangle(): int status; char* ret = abi::__cxa_demangle(begin_name, funcname, &funcnamesize, &status); if (status == 0) { funcname = ret; // use possibly realloc()-ed string pvStackTrace() << " " << symbollist[i] << " : " << funcname << "+" << begin_offset << std::endl; } else { // demangling failed. Output function name as a C function with // no arguments. pvStackTrace() << " " << symbollist[i] << " : " << begin_name << "+" << begin_offset << std::endl; } } else { // couldn't parse the line? print the whole line. pvStackTrace() << " " << symbollist[i] << std::endl; } } free(funcname); free(symbollist); }
void print_fatal_info(int sig, siginfo_t *siginfo, void *context) { #ifdef HAVE_SYS_UCONTEXT_H ucontext_t *uctx = (ucontext_t *)context; /* look for GET_PC() macro in sigcontextinfo.h files */ /* of glibc if you wish to add more CPU architectures */ # if defined(REG_EIP) /* i386 */ # define ZBX_GET_REG(uctx, reg) (uctx)->uc_mcontext.gregs[reg] # define ZBX_GET_PC(uctx) ZBX_GET_REG(uctx, REG_EIP) # elif defined(REG_RIP) /* x86_64 */ # define ZBX_GET_REG(uctx, reg) (uctx)->uc_mcontext.gregs[reg] # define ZBX_GET_PC(uctx) ZBX_GET_REG(uctx, REG_RIP) # endif #endif /* HAVE_SYS_UCONTEXT_H */ #ifdef HAVE_EXECINFO_H # define ZBX_BACKTRACE_SIZE 60 char **bcktrc_syms; void *bcktrc[ZBX_BACKTRACE_SIZE]; int bcktrc_sz; #endif /* HAVE_EXECINFO_H */ int i; FILE *fd; zabbix_log(LOG_LEVEL_CRIT, "====== Fatal information: ======"); #ifdef HAVE_SYS_UCONTEXT_H #ifdef ZBX_GET_PC zabbix_log(LOG_LEVEL_CRIT, "Program counter: %p", ZBX_GET_PC(uctx)); zabbix_log(LOG_LEVEL_CRIT, "=== Registers: ==="); for (i = 0; i < NGREG; i++) zabbix_log(LOG_LEVEL_CRIT, "%-7s = %16lx = %20lu = %20ld", get_register_name(i), ZBX_GET_REG(uctx, i), ZBX_GET_REG(uctx, i), ZBX_GET_REG(uctx, i)); #ifdef REG_EBP /* dump a bit of stack frame for i386 */ zabbix_log(LOG_LEVEL_CRIT, "=== Stack frame: ==="); for (i = 16; i >= 2; i--) zabbix_log(LOG_LEVEL_CRIT, "+0x%02x(%%ebp) = ebp + %2d = %08x = %10u = %11d%s", i * ZBX_PTR_SIZE, i * ZBX_PTR_SIZE, *(unsigned int *)((void *)ZBX_GET_REG(uctx, REG_EBP) + i * ZBX_PTR_SIZE), *(unsigned int *)((void *)ZBX_GET_REG(uctx, REG_EBP) + i * ZBX_PTR_SIZE), *(unsigned int *)((void *)ZBX_GET_REG(uctx, REG_EBP) + i * ZBX_PTR_SIZE), i == 2 ? " <--- call arguments" : ""); zabbix_log(LOG_LEVEL_CRIT, "+0x%02x(%%ebp) = ebp + %2d = %08x%28s<--- return address", ZBX_PTR_SIZE, ZBX_PTR_SIZE, *(unsigned int *)((void *)ZBX_GET_REG(uctx, REG_EBP) + ZBX_PTR_SIZE), ""); zabbix_log(LOG_LEVEL_CRIT, " (%%ebp) = ebp = %08x%28s<--- saved ebp value", *(unsigned int *)((void *)ZBX_GET_REG(uctx, REG_EBP)), ""); for (i = 1; i <= 16; i++) zabbix_log(LOG_LEVEL_CRIT, "-0x%02x(%%ebp) = ebp - %2d = %08x = %10u = %11d%s", i * ZBX_PTR_SIZE, i * ZBX_PTR_SIZE, *(unsigned int *)((void *)ZBX_GET_REG(uctx, REG_EBP) - i * ZBX_PTR_SIZE), *(unsigned int *)((void *)ZBX_GET_REG(uctx, REG_EBP) - i * ZBX_PTR_SIZE), *(unsigned int *)((void *)ZBX_GET_REG(uctx, REG_EBP) - i * ZBX_PTR_SIZE), i == 1 ? " <--- local variables" : ""); #endif /* REG_EBP */ #else zabbix_log(LOG_LEVEL_CRIT, "program counter not available for this architecture"); zabbix_log(LOG_LEVEL_CRIT, "=== Registers: ==="); zabbix_log(LOG_LEVEL_CRIT, "register dump not available for this architecture"); #endif /* ZBX_GET_PC */ #endif /* HAVE_SYS_UCONTEXT_H */ zabbix_log(LOG_LEVEL_CRIT, "=== Backtrace: ==="); #ifdef HAVE_EXECINFO_H bcktrc_sz = backtrace(bcktrc, ZBX_BACKTRACE_SIZE); bcktrc_syms = backtrace_symbols(bcktrc, bcktrc_sz); if (NULL == bcktrc_syms) { zabbix_log(LOG_LEVEL_CRIT, "error in backtrace_symbols(): [%s]", strerror(errno)); for (i = 0; i < bcktrc_sz; i++) zabbix_log(LOG_LEVEL_CRIT, "%d: %p", bcktrc_sz - i - 1, bcktrc[i]); } else { for (i = 0; i < bcktrc_sz; i++) zabbix_log(LOG_LEVEL_CRIT, "%d: %s", bcktrc_sz - i - 1, bcktrc_syms[i]); zbx_free(bcktrc_syms); } #else zabbix_log(LOG_LEVEL_CRIT, "backtrace not available for this platform"); #endif /* HAVE_EXECINFO_H */ zabbix_log(LOG_LEVEL_CRIT, "=== Memory map: ==="); if (NULL != (fd = fopen("/proc/self/maps", "r"))) { char line[1024]; while (NULL != fgets(line, sizeof(line), fd)) { if (line[0] != '\0') line[strlen(line) - 1] = '\0'; /* remove trailing '\n' */ zabbix_log(LOG_LEVEL_CRIT, "%s", line); } zbx_fclose(fd); } else zabbix_log(LOG_LEVEL_CRIT, "memory map not available for this platform"); #ifdef ZBX_GET_PC zabbix_log(LOG_LEVEL_CRIT, "================================"); zabbix_log(LOG_LEVEL_CRIT, "Please consider attaching a disassembly listing to your bug report."); zabbix_log(LOG_LEVEL_CRIT, "This listing can be produced with, e.g., objdump -D -S %s.", progname); #endif zabbix_log(LOG_LEVEL_CRIT, "================================"); }
static void traphandler(int sig, siginfo_t *si, void *UC) { #ifdef NGREG ucontext_t *uc = UC; #endif #if ENABLE_EXECINFO char buf[200]; static void *frames[MAXFRAMES]; int nframes = backtrace(frames, MAXFRAMES); Dl_info dli; #endif #if defined(NGREG) || ENABLE_EXECINFO int i; #endif const char *reason = NULL; tvhlog_spawn(LOG_ALERT, "CRASH", "Signal: %d in %s ", sig, line1); switch(sig) { case SIGSEGV: switch(si->si_code) { case SEGV_MAPERR: reason = "Address not mapped"; break; case SEGV_ACCERR: reason = "Access error"; break; } break; case SIGFPE: switch(si->si_code) { case FPE_INTDIV: reason = "Integer division by zero"; break; } break; } tvhlog_spawn(LOG_ALERT, "CRASH", "Fault address %p (%s)", si->si_addr, reason ?: "N/A"); tvhlog_spawn(LOG_ALERT, "CRASH", "Loaded libraries: %s ", libs); #ifdef NGREG snprintf(tmpbuf, sizeof(tmpbuf), "Register dump [%d]: ", (int)NGREG); for(i = 0; i < NGREG; i++) { sappend(tmpbuf, sizeof(tmpbuf), "%016" PRIx64, uc->uc_mcontext.gregs[i]); } #endif tvhlog_spawn(LOG_ALERT, "CRASH", "%s", tmpbuf); #if ENABLE_EXECINFO tvhlog_spawn(LOG_ALERT, "CRASH", "STACKTRACE"); for(i = 0; i < nframes; i++) { if(dladdr(frames[i], &dli)) { if(dli.dli_sname != NULL && dli.dli_saddr != NULL) { tvhlog_spawn(LOG_ALERT, "CRASH", "%s+0x%tx (%s)", dli.dli_sname, frames[i] - dli.dli_saddr, dli.dli_fname); continue; } if(self[0] && !add2lineresolve(self, frames[i], buf, sizeof(buf))) { tvhlog_spawn(LOG_ALERT, "CRASH", "%s %p", buf, frames[i]); continue; } if(dli.dli_fname != NULL && dli.dli_fbase != NULL) { tvhlog_spawn(LOG_ALERT, "CRASH", "%s %p", dli.dli_fname, frames[i]); continue; } tvhlog_spawn(LOG_ALERT, "CRASH", "%p", frames[i]); } } #endif }
inline void DCU_createStackTrace(DCU_ConstPointer stack[DCU_STACK_TRACE_SIZE]) { memset(stack, 0, sizeof(stack)); backtrace((void**)(stack), DCU_STACK_TRACE_SIZE); }
// This uses glibc's basic built-in stack-trace functions together with // ELFIO's ability to parse the .symtab ELF section for better symbol // extraction without exporting symbols (which'd cause subtle, fatal bugs). static inline BOOL do_elfio_glibc_backtrace() { void *array[MAX_STACK_TRACE_DEPTH]; size_t btsize; char **strings; BOOL success = FALSE; std::string appfilename = gDirUtilp->getExecutablePathAndName(); std::string strace_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log"); llinfos << "Opening stack trace file " << strace_filename << llendl; LLFILE* StraceFile = LLFile::fopen(strace_filename, "w"); // Flawfinder: ignore if (!StraceFile) { llinfos << "Opening stack trace file " << strace_filename << " failed. Using stderr." << llendl; StraceFile = stderr; } // get backtrace address list and basic symbol info btsize = backtrace(array, MAX_STACK_TRACE_DEPTH); strings = backtrace_symbols(array, btsize); // create ELF reader for our app binary IELFI* pReader; const IELFISection* pSec = NULL; IELFISymbolTable* pSymTbl = 0; if (ERR_ELFIO_NO_ERROR != ELFIO::GetInstance()->CreateELFI(&pReader) || ERR_ELFIO_NO_ERROR != pReader->Load(appfilename.c_str()) || // find symbol table, create reader-object NULL == (pSec = pReader->GetSection( ".symtab" )) || ERR_ELFIO_NO_ERROR != pReader->CreateSectionReader(IELFI::ELFI_SYMBOL, pSec, (void**)&pSymTbl) ) { // Failed to open our binary and read its symbol table somehow llinfos << "Could not initialize ELF symbol reading - doing basic backtrace." << llendl; if (StraceFile != stderr) fclose(StraceFile); // note that we may be leaking some of the above ELFIO // objects now, but it's expected that we'll be dead soon // and we want to tread delicately until we get *some* kind // of useful backtrace. return do_basic_glibc_backtrace(); } // iterate over trace and symtab, looking for plausible symbols std::string name; Elf32_Addr value; Elf32_Word ssize; unsigned char bind; unsigned char type; Elf32_Half section; int nSymNo = pSymTbl->GetSymbolNum(); size_t btpos; for (btpos = 0; btpos < btsize; ++btpos) { fprintf(StraceFile, "%d:\t", btpos); int symidx; for (symidx = 0; symidx < nSymNo; ++symidx) { if (ERR_ELFIO_NO_ERROR == pSymTbl->GetSymbol(symidx, name, value, ssize, bind, type, section)) { // check if trace address within symbol range if (uintptr_t(array[btpos]) >= value && uintptr_t(array[btpos]) < value+ssize) { char *demangled_str = NULL; int demangle_result = 1; demangled_str = abi::__cxa_demangle (name.c_str(), NULL, NULL, &demangle_result); if (0 == demangle_result && NULL != demangled_str) { fprintf(StraceFile, "ELF(%s", demangled_str); free(demangled_str); } else // failed demangle; print it raw { fprintf(StraceFile, "ELF(%s", name.c_str()); } // print offset from symbol start fprintf(StraceFile, "+0x%lx) [%p]\n", uintptr_t(array[btpos]) - value, array[btpos]); goto got_sym; // early escape } } } // Fallback: // Didn't find a suitable symbol in the binary - it's probably // a symbol in a DSO; use glibc's idea of what it should be. fprintf(StraceFile, "%s\n", strings[btpos]); got_sym:; } if (StraceFile != stderr) fclose(StraceFile); pSymTbl->Release(); pSec->Release(); pReader->Release(); free(strings); llinfos << "Finished generating stack trace." << llendl; success = TRUE; return success; }
void DCU_initialize() { if (DCU_STATE(DCU_INITIALIZED)) { return; } if (DCU_STATE(DCU_MUTEX_INITED)) { DCU_MutexScopedLock lock(DCU_mutex); if (DCU_STATE(DCU_INITIALIZED)) { return; } else { fprintf(DCU_FALLBACK_STREAM, "DynamicCheckUp Concurrency error.\n"); _exit(1); } } if (pthread_mutex_init(&DCU_mutex, 0) < 0) { fprintf(DCU_FALLBACK_STREAM, "DynamicCheckUp unable to initialize mutex\n"); _exit(1); } else { DCU_SET_FLAG(DCU_MUTEX_INITED); } { DCU_MutexScopedLock lock(DCU_mutex); memory_space = create_mspace(0, 0); DCU_SET_FLAG(DCU_INITIALIZED); // // init backtrace so it wont recursively call malloc // DCU_Pointer stack[DCU_STACK_TRACE_SIZE]; backtrace(stack, DCU_STACK_TRACE_SIZE); // // Init Tracing data // DCU_stream = DCU_FALLBACK_STREAM; memset(DCU_memory_stats, 0, sizeof(DCU_MemoryStats) * DCU_DYNAMIC_OPERATION_TYPES); memset(&DCU_memory_stats_new, 0, sizeof(DCU_MemoryStats)); memset(&DCU_memory_stats_new_array, 0, sizeof(DCU_MemoryStats)); memset(&DCU_memory_stats_c, 0, sizeof(DCU_MemoryStats)); memset(DCU_null_stack, 0, sizeof(DCU_null_stack)); // // Operations HashTable // DCU_memory = (DCU_OperationInfo**) DCU_malloc( DCU_HASH_TABLE_SIZE * sizeof(DCU_OperationInfo*) ); memset(DCU_memory, 0, DCU_HASH_TABLE_SIZE * sizeof(DCU_OperationInfo*)); // // Problems Linked-List // DCU_problems = 0; // // Open Log File // DCU_stream = fopen(DCU_OUTPUT_FILE, "w"); if (DCU_stream < 0) { fprintf(DCU_FALLBACK_STREAM, "DynamicCheckUp: Unable to open %s: %m\n", DCU_OUTPUT_FILE); DCU_stream = DCU_FALLBACK_STREAM; } else { int flags = fcntl(fileno(DCU_stream), F_GETFD, 0); if (flags >= 0) { flags |= FD_CLOEXEC; fcntl(fileno(DCU_stream), F_SETFD, flags); } setvbuf(DCU_stream, stream_trace_buffer, _IOFBF, DCU_STREAM_BUFFER_SIZE); } DCU_SET_FLAG(DCU_TRACING); } DCU_write("DynamicCheckUp Started\n"); }
/** * Prints a stack backtrace for the current thread to the specified ostream. * * Does not malloc, does not throw. * * The format of the backtrace is: * * ----- BEGIN BACKTRACE ----- * JSON backtrace * Human-readable backtrace * ----- END BACKTRACE ----- * * The JSON backtrace will be a JSON object with a "backtrace" field, and optionally others. * The "backtrace" field is an array, whose elements are frame objects. A frame object has a * "b" field, which is the base-address of the library or executable containing the symbol, and * an "o" field, which is the offset into said library or executable of the symbol. * * The JSON backtrace may optionally contain additional information useful to a backtrace * analysis tool. For example, on Linux it contains a subobject named "somap", describing * the objects referenced in the "b" fields of the "backtrace" list. * * @param os ostream& to receive printed stack backtrace */ void printStackTrace(std::ostream& os) { static const char unknownFileName[] = "???"; void* addresses[maxBackTraceFrames]; Dl_info dlinfoForFrames[maxBackTraceFrames]; //////////////////////////////////////////////////////////// // Get the backtrace addresses. //////////////////////////////////////////////////////////// const int addressCount = backtrace(addresses, maxBackTraceFrames); if (addressCount == 0) { const int err = errno; os << "Unable to collect backtrace addresses (errno: " << err << ' ' << strerror(err) << ')' << std::endl; return; } //////////////////////////////////////////////////////////// // Collect symbol information for each backtrace address. //////////////////////////////////////////////////////////// os << std::hex << std::uppercase << '\n'; for (int i = 0; i < addressCount; ++i) { Dl_info& dlinfo(dlinfoForFrames[i]); if (!dladdr(addresses[i], &dlinfo)) { dlinfo.dli_fname = unknownFileName; dlinfo.dli_fbase = NULL; dlinfo.dli_sname = NULL; dlinfo.dli_saddr = NULL; } os << ' ' << addresses[i]; } os << "\n----- BEGIN BACKTRACE -----\n"; //////////////////////////////////////////////////////////// // Display the JSON backtrace //////////////////////////////////////////////////////////// os << "{\"backtrace\":["; for (int i = 0; i < addressCount; ++i) { const Dl_info& dlinfo = dlinfoForFrames[i]; const uintptr_t fileOffset = uintptr_t(addresses[i]) - uintptr_t(dlinfo.dli_fbase); if (i) os << ','; os << "{\"b\":\"" << uintptr_t(dlinfo.dli_fbase) << "\",\"o\":\"" << fileOffset; if (dlinfo.dli_sname) { os << "\",\"s\":\"" << dlinfo.dli_sname; } os << "\"}"; } os << ']'; if (soMapJson) os << ",\"processInfo\":" << *soMapJson; os << "}\n"; //////////////////////////////////////////////////////////// // Display the human-readable trace //////////////////////////////////////////////////////////// for (int i = 0; i < addressCount; ++i) { Dl_info& dlinfo(dlinfoForFrames[i]); os << ' '; if (dlinfo.dli_fbase) { os << getBaseName(dlinfo.dli_fname) << '('; if (dlinfo.dli_sname) { const uintptr_t offset = uintptr_t(addresses[i]) - uintptr_t(dlinfo.dli_saddr); os << dlinfo.dli_sname << "+0x" << offset; } else { const uintptr_t offset = uintptr_t(addresses[i]) - uintptr_t(dlinfo.dli_fbase); os << "+0x" << offset; } os << ')'; } else { os << unknownFileName; } os << " [" << addresses[i] << ']' << std::endl; } os << std::dec << std::nouppercase; os << "----- END BACKTRACE -----" << std::endl; }
void Signals::collect_callstack(size_t skipLevels, bool makeFunctionNamesStandOut, const std::function<void(const std::string&)>& write) { write("\n[CALL STACK]\n"); #ifdef _WIN32 static const int MAX_CALLERS = 62; static const unsigned short MAX_CALL_STACK_DEPTH = 20; // RtlCaptureStackBackTrace() is a kernel API without default binding, we must manually determine its function pointer. if(RtlCaptureStackBackTrace_func == nullptr) RtlCaptureStackBackTrace_func = (CaptureStackBackTraceType)(GetProcAddress(LoadLibrary("kernel32.dll"), "RtlCaptureStackBackTrace")); if (RtlCaptureStackBackTrace_func == nullptr) // failed somehow return write("Failed to generate CALL STACK. GetProcAddress(\"RtlCaptureStackBackTrace\") failed with error " + utf8(FormatWin32Error(GetLastError())) + "\n"); HANDLE process = GetCurrentProcess(); if (!SymInitialize(process, nullptr, TRUE)) return write("Failed to generate CALL STACK. SymInitialize() failed with error " + utf8(FormatWin32Error(GetLastError())) + "\n"); // get the call stack void* callStack[MAX_CALLERS]; unsigned short frames; frames = RtlCaptureStackBackTrace_func(0, MAX_CALLERS, callStack, nullptr); SYMBOL_INFO* symbolInfo = (SYMBOL_INFO*)calloc(sizeof(SYMBOL_INFO) + 256 * sizeof(char), 1); // this is a variable-length structure, can't use vector easily symbolInfo->MaxNameLen = 255; symbolInfo->SizeOfStruct = sizeof(SYMBOL_INFO); frames = std::min(frames, MAX_CALL_STACK_DEPTH); // format and emit size_t firstFrame = skipLevels + 1; // skip CollectCallStack() for (size_t i = firstFrame; i < frames; i++) { if (i == firstFrame) write(" > "); else write(" - "); if (SymFromAddr(process, (DWORD64)(callStack[i]), 0, symbolInfo)) { write(makeFunctionNamesStandOut ? MakeFunctionNameStandOut(symbolInfo->Name) : symbolInfo->Name); write("\n"); } else { DWORD error = GetLastError(); char buf[17]; sprintf_s(buf, "%p", callStack[i]); write(buf); write(" (SymFromAddr() error: " + utf8(FormatWin32Error(error)) + ")\n"); } } write("\n"); free(symbolInfo); SymCleanup(process); #else // Linux unsigned int MAX_NUM_FRAMES = 1024; void* backtraceAddresses[MAX_NUM_FRAMES]; unsigned int numFrames = backtrace(backtraceAddresses, MAX_NUM_FRAMES); char** symbolList = backtrace_symbols(backtraceAddresses, numFrames); for (size_t i = skipLevels; i < numFrames; i++) { char* beginName = NULL; char* beginOffset = NULL; char* beginAddress = NULL; // Find parentheses and +address offset surrounding the mangled name for (char* p = symbolList[i]; *p; ++p) { if (*p == '(') // function name begins here beginName = p; else if (*p == '+') // relative address ofset beginOffset = p; else if ((*p == ')') && (beginOffset || beginName)) // absolute address beginAddress = p; } const int buf_size = 1024; char buffer[buf_size]; if (beginName && beginAddress && (beginName < beginAddress)) { *beginName++ = '\0'; *beginAddress++ = '\0'; if (beginOffset) // has relative address *beginOffset++ = '\0'; // Mangled name is now in [beginName, beginOffset) and caller offset in [beginOffset, beginAddress). int status = 0; unsigned int MAX_FUNCNAME_SIZE = 4096; size_t funcNameSize = MAX_FUNCNAME_SIZE; char funcName[MAX_FUNCNAME_SIZE]; // working buffer const char* ret = abi::__cxa_demangle(beginName, funcName, &funcNameSize, &status); std::string fName; if (status == 0) fName = makeFunctionNamesStandOut ? MakeFunctionNameStandOut(ret) : ret; // make it a bit more readable else fName = beginName; // failed: fall back // name of source file--not printing since it is not super-useful //string sourceFile = symbolList[i]; //static const size_t sourceFileWidth = 20; //if (sourceFile.size() > sourceFileWidth) // sourceFile = "..." + sourceFile.substr(sourceFile.size() - (sourceFileWidth-3)); while (*beginAddress == ' ') // eat unnecessary space beginAddress++; std::string pcOffset = beginOffset ? std::string(" + ") + beginOffset : std::string(); snprintf(buffer, buf_size, "%-20s%-50s%s\n", beginAddress, fName.c_str(), pcOffset.c_str()); } else // Couldn't parse the line. Print the whole line as it came. snprintf(buffer, buf_size, "%s\n", symbolList[i]); write(buffer); } free(symbolList); #endif }
void print_backtrace (void) { void *buffer[255]; const int calls = backtrace (buffer, sizeof (buffer) / sizeof (void *)); backtrace_symbols_fd (buffer, calls, 1); }
CStackTraceImpl::CStackTraceImpl(void) { m_Stack.resize(CStackTrace::s_GetStackTraceMaxDepth()); m_Stack.resize(backtrace(&m_Stack[0], m_Stack.size())); }
/* * Wrapped call to libc backtrace function */ uintptr_t protectedBacktrace(struct OMRPortLibrary *port, void *arg) { struct frameData *addresses = (struct frameData *) arg; return backtrace(addresses->address_array, addresses->capacity); }
static void segv_handler(int sig) { static int crashing = 0; void* array[64]; size_t size; // So we don't recurse! if(crashing) exit(101); crashing = 1; int fd = 2; if(getenv("RBX_PAUSE_ON_CRASH")) { std::cerr << "\n========== CRASH (" << getpid(); std::cerr << "), pausing for 60 seconds to attach debugger\n"; sleep(60); } // If there is a report_path setup.. if(report_path[0]) { fd = open(report_path, O_WRONLY | O_CREAT | O_TRUNC, 0666); // If we can't open this path, use stderr. if(fd == -1) fd = 2; } // print out all the frames to stderr static const char header[] = "Rubinius Crash Report #rbxcrashreport\n\n" "Error: signal "; safe_write(fd, header, sizeof(header)); write_sig(fd, sig); safe_write(fd, "\n\n[[Backtrace]]\n"); // get void*'s for all entries on the stack size = backtrace(array, 64); backtrace_symbols_fd(array, size, fd); // Try to get the output to flush... safe_write(fd, "\n[[System Info]]\n"); safe_write(fd, "sysname: "); safe_write(fd, machine_info.sysname); safe_write(fd, "\n"); safe_write(fd, "nodename: "); safe_write(fd, machine_info.nodename); safe_write(fd, "\n"); safe_write(fd, "release: "); safe_write(fd, machine_info.release); safe_write(fd, "\n"); safe_write(fd, "version: "); safe_write(fd, machine_info.version); safe_write(fd, "\n"); safe_write(fd, "machine: "); safe_write(fd, machine_info.machine); safe_write(fd, "\n"); // If we didn't write to stderr, then close the file down and // write info to stderr about reporting the error. if(fd != 2) { close(fd); safe_write(2, "\n---------------------------------------------\n"); safe_write(2, "CRASH: A fatal error has occured.\n\nBacktrace:\n"); backtrace_symbols_fd(array, size, 2); safe_write(2, "\n\n"); safe_write(2, "Wrote full error report to: "); safe_write(2, report_path); safe_write(2, "\nRun 'rbx report' to submit this crash report!\n"); } exit(100); }
void stack_trace() { int ret, i; bool demangled_symbol; size_t stack_depth; size_t sz = 200; /* Just a guess, template names will go much wider */ const size_t max_depth = 100; void *stack_addrs[100]; char **stack_strings, *begin, *end, *j, *function; stack_depth = backtrace(stack_addrs, max_depth); stack_strings = backtrace_symbols(stack_addrs, stack_depth); for (i = 1; i < stack_depth; i++) { function = (char *)actuallymalloc(sz); begin = end = 0; /* * Find the single quote and address offset surrounding the mangled name */ for (j = stack_strings[i]; *j; ++j) { if (*j == '\'') { begin = j; } else if (*j == '+') { end = j; } } if (begin && end) { *begin++ = '\0'; *end = '\0'; /* * Found our mangled name, now in [begin, end) */ demangled_symbol = false; while (!demangled_symbol) { ret = cplus_demangle(begin, function, sz); switch (ret) { case DEMANGLE_ENAME: /* * Demangling failed, just pretend it's a C function with no args */ strcat(function, "()"); function[sz - 1] = '\0'; demangled_symbol = true; break; case DEMANGLE_ESPACE: /* * Need more space for demangled function name. */ actuallyfree(function); sz = sz * 2; function = (char *)actuallymalloc(sz); continue; default: demangled_symbol = true; break; } } Pmsg2(000, " %s:%s\n", stack_strings[i], function); } else { /* * Didn't find the mangled name, just print the whole line */ Pmsg1(000, " %s\n", stack_strings[i]); } actuallyfree(function); } actuallyfree(stack_strings); /* malloc()ed by backtrace_symbols */ }
//============================================================================== std::vector <std::string> getStackBacktrace() { std::vector <std::string> result; #if BEAST_ANDROID || BEAST_MINGW || BEAST_BSD assert(false); // sorry, not implemented yet! #elif BEAST_WINDOWS HANDLE process = GetCurrentProcess(); SymInitialize (process, nullptr, TRUE); void* stack[128]; int frames = (int) CaptureStackBackTrace (0, std::distance(std::begin(stack), std::end(stack)), stack, nullptr); // Allow symbols that are up to 1024 characters long. std::size_t constexpr nameLength = 1024; alignas(SYMBOL_INFO) unsigned char symbuf[ sizeof(SYMBOL_INFO) + nameLength * sizeof(SYMBOL_INFO::Name)]; auto symbol = reinterpret_cast<SYMBOL_INFO*>(symbuf); for (int i = 0; i < frames; ++i) { DWORD64 displacement = 0; std::memset (symbol, 0, sizeof(symbuf)); symbol->SizeOfStruct = sizeof(SYMBOL_INFO); symbol->MaxNameLen = nameLength; if (SymFromAddr (process, (DWORD64)stack[i], &displacement, symbol)) { std::string frame; frame.append (std::to_string (i) + ": "); IMAGEHLP_MODULE64 moduleInfo { sizeof(moduleInfo) }; if (::SymGetModuleInfo64 (process, symbol->ModBase, &moduleInfo)) { frame.append (moduleInfo.ModuleName); frame.append (": "); } frame.append (symbol->Name); if (displacement) { frame.append ("+"); frame.append (std::to_string (displacement)); } result.push_back (frame); } } #else void* stack[128]; int frames = backtrace (stack, std::distance(std::begin(stack), std::end(stack))); std::unique_ptr<char*[], decltype(std::free)*> frame { backtrace_symbols (stack, frames), std::free }; for (int i = 0; i < frames; ++i) result.push_back (frame[i]); #endif return result; }