static void _log_stack(int32_t logLev,int32_t start,char *str) { void* bt[64]; char** strings; size_t sz; int32_t i,f; int32_t size = 0; char logbuf[MAX_LOG_SIZE]; char addr[32],buf[1024]; char *ptr; sz = backtrace(bt, 64); strings = backtrace_symbols(bt, sz); size += snprintf(logbuf,MAX_LOG_SIZE,"%s",str); for(i = start,f = 0; i < sz; ++i) { if(strstr(strings[i],"main+")) break; ptr = logbuf + size; if(getaddr(strings[i],addr,32) && !addr2line(addr,buf,1024)) size += snprintf(ptr,MAX_LOG_SIZE-size, "\t% 2d: %s %s\n",++f,strings[i],buf); else size += snprintf(ptr,MAX_LOG_SIZE-size, "\t% 2d: %s\n",++f,strings[i]); } SYS_LOG(logLev,"%s",logbuf); free(strings); }
void windows_print_stacktrace(CONTEXT* context) { SymInitialize(GetCurrentProcess(), 0, true); STACKFRAME frame = { 0 }; /* setup initial stack frame */ frame.AddrPC.Offset = context->Eip; frame.AddrPC.Mode = AddrModeFlat; frame.AddrStack.Offset = context->Esp; frame.AddrStack.Mode = AddrModeFlat; frame.AddrFrame.Offset = context->Ebp; frame.AddrFrame.Mode = AddrModeFlat; while (StackWalk(IMAGE_FILE_MACHINE_I386 , GetCurrentProcess(), GetCurrentThread(), &frame, context, 0, SymFunctionTableAccess, SymGetModuleBase, 0 ) ) { addr2line(icky_global_program_name, (void*)frame.AddrPC.Offset); } SymCleanup( GetCurrentProcess() ); }
static struct inline_node *addr2inlines(const char *dso_name, u64 addr, struct dso *dso, struct symbol *sym) { struct inline_node *node; node = zalloc(sizeof(*node)); if (node == NULL) { perror("not enough memory for the inline node"); return NULL; } INIT_LIST_HEAD(&node->val); node->addr = addr; addr2line(dso_name, addr, NULL, NULL, dso, true, node, sym); return node; }
void posix_print_stack_trace() { int i, trace_size = 0; char **messages = (char **)NULL; trace_size = backtrace(stack_traces, MAX_STACK_FRAMES); messages = backtrace_symbols(stack_traces, trace_size); /* skip the first couple stack frames (as they are this function and our handler) and also skip the last frame as it's (always?) junk. */ // for (i = 3; i < (trace_size - 1); ++i) for (i = 0; i < trace_size; ++i) // we'll use this for now so you can see what's going on { if (addr2line(icky_global_program_name, stack_traces[i]) != 0) { printf(" error determining line # for: %s\n", messages[i]); } } if (messages) { free(messages); } }
void print_trace(void) { void *array[10]; size_t size; char **strings; size_t i; #ifndef __mips__ size = backtrace(array, 10); LOGL(0, "Obtained %zd stack frames.\n", size); for (i = 0; i < size; i++) { LOGL(0, "%p : ", array[i]); if (addr2line(pn, array[i])) LOGL(0, "\n"); } #else LOGL(0, " No backtrace defined\n"); #endif }
void Cache :: line_get(Addr addr, uint8_t line_state_req, size_t &latency, uint8_t *&pdata) { ////////////////////////////////////////////////////////////////// // // proudly serving cache requests // since september 2008 // ////////////////////////////////////////////////////////////////// // // line_state_req(uest) values: // LINE_SHR - request a read // LINE_EXC - request an exclusive access (invalidate other readers) // LINE_MOD - perform a write (invalidate other readers and mark line as dirty) bool set_overflow = false; Line *overflow_line = NULL; // this adds a line (if it's not already in the cache) but with LINE_INV state Line *line = addr2line(addr, set_overflow, overflow_line); // if some line has been replaced, get the value and evict/invalidate the same line and its parts // in all child caches if (set_overflow) { NVLOG1("%s\tline_get overflow 0x%lx\n", _name.c_str(), overflow_line->addr); this->line_evict(overflow_line); } uint8_t __attribute__((unused)) line_state_orig = line->state; uint64_t __attribute__((unused)) line_sharers_orig = line->sharers; bool hit = true; size_t old_ticks = latency; if (line->state & LINE_MOD) { switch (line_state_req) { case LINE_MOD: case LINE_EXC: case LINE_SHR: break; default: assert(!"invalid line_state request!"); } } else if (line->state & LINE_EXC) { // line is EXCLUSIVE when it is not modified and there is no other line sharer // TODO update the functionality to reflect this; // first line sharer should automatically get exclusive access; // this exclusive access should be reduced to shared when another core requests line copy (for read) switch (line_state_req) { case LINE_MOD: if (_is_writeback_cache || !_parent_cache) { // mark line as dirty (for writeback) line->state |= line_state_req; } else { // write latency should include writing to the parent _parent->line_get_intercache(addr, line_state_req, latency, _index_in_parent, line->parent_line); // TODO should also write data to the parent cache hit = false; break; } case LINE_EXC: case LINE_SHR: break; default: assert(!"invalid line_state request!"); } } else if (line->state & LINE_SHR) { switch (line_state_req) { case LINE_MOD: case LINE_EXC: if (_parent_cache) { if (_is_writeback_cache) { _parent->line_get_intercache(addr, LINE_EXC, latency, _index_in_parent, line->parent_line); } else { _parent->line_get_intercache(addr, line_state_req, latency, _index_in_parent, line->parent_line); } hit = false; } line->state |= line_state_req; break; case LINE_SHR: break; default: assert(!"invalid line_state request!"); } } else if (line->state == LINE_INV) { hit = false; switch (line_state_req) { case LINE_TXW: case LINE_TXR: _parent->line_get_intercache(addr, LINE_SHR, latency, _index_in_parent, line->parent_line); line->state |= line->parent_line->state & ( LINE_TXR | LINE_TXW); line->state |= (LINE_SHR | line_state_req); break; case LINE_MOD: case LINE_EXC: if (_is_writeback_cache) { _parent->line_get_intercache(addr, LINE_EXC, latency, _index_in_parent, line->parent_line); } else { _parent->line_get_intercache(addr, line_state_req, latency, _index_in_parent, line->parent_line); } line->state |= line_state_req; break; case LINE_SHR: _parent->line_get_intercache(addr, LINE_SHR, latency, _index_in_parent, line->parent_line); line->state |= line_state_req; break; default: assert(!"invalid line_state request!"); } } else { NVLOG_ERROR("invalid current line_state %x\n", line->state); assert(false && "invalid current line_state!"); } if (line->pdata == NULL) { line->pdata = (uint8_t*)malloc(get_line_size()); if (_parent_cache && line->parent_line) { // if data found in parent cache NVLOG1("%s\tline_get data copy from %s 0x%lx data 0x%lx -> 0x%lx\n", this->_name.c_str(), _parent_cache->_name.c_str(), line->addr, (Addr)line->parent_line->pdata, (Addr)line->pdata); memcpy(line->pdata, line->parent_line->pdata+(line->addr - line->parent_line->addr), get_line_size()); } else { // get the data from the memory NVLOG1("%s\tline_get data copy from memory 0x%lx data -> 0x%lx\n", this->_name.c_str(), line->addr, (Addr)line->pdata); //Fault fault = rw_array_silent(line->addr, get_line_size(), line->pdata, false/*READ*/); //assert(fault == NoFault); } } pdata = line->pdata; latency += _hit_latency; // update statistics if (hit) { this->stats.hits_inc(); } else { this->stats.misses_inc(); if (line_state_req & LINE_MOD || line_state_req & LINE_EXC) { this->stats.misses_st_inc(); } else { this->stats.misses_ld_inc(); } } this->stats.ticks_inc(latency - old_ticks); NVLOG1("%s\tline_get 0x%lx\t state %s->%s sharers 0x%lx->0x%lx\n", _name.c_str(), line->addr, state2str(line_state_orig).c_str(), state2str(line->state).c_str(), line_sharers_orig, line->sharers); assert(! ((line->state & (LINE_MOD | LINE_EXC)) && (line->state & LINE_TXW)) ); }
void Cache :: line_get_intercache(Addr addr, uint8_t line_state_req, size_t &latency, unsigned child_index, Line *&parent_line) { ////////////////////////////////////////////////////////////////////// // serving line relocations inside the cache hierarchy ////////////////////////////////////////////////////////////////////// bool set_overflow = false; Line *overflow_line = NULL; // this adds a line (if it's not already in the cache) but with LINE_INV state Line *line = addr2line(addr, set_overflow, overflow_line); if (set_overflow) { // if some line has been replaced, get the value and invalidate the same line and its parts // in all child caches NVLOG1("%s\tline_get overflow 0x%lx\n", _name.c_str(), overflow_line->addr); this->line_evict(overflow_line); } uint8_t __attribute__((unused)) line_state_orig = line->state; uint64_t __attribute__((unused)) line_sharers_orig = line->sharers; bool hit = true; size_t old_ticks = latency; if (line->state & (LINE_MOD | LINE_EXC)) { // this directory already owns a line (exclusively) // just in case we'll invalidate the line in // all other child-caches switch (line_state_req) { case LINE_MOD: if (line->sharers != (1ULL<<child_index)) { this->line_make_owner_in_child_caches(line, child_index); setbit(line->sharers, child_index); } if (_is_writeback_cache || !_parent_cache) { line->state |= line_state_req; } else { _parent->line_get_intercache(addr, line_state_req, latency, _index_in_parent, line->parent_line); hit = false; break; } break; case LINE_EXC: // this processor wants to have an exclusive copy // (and it didn't have it until now, as we got an intercache request) if (line->sharers != (1ULL<<child_index)) { this->line_make_owner_in_child_caches(line, child_index); setbit(line->sharers, child_index); } break; case LINE_SHR: if (line->sharers != (1ULL<<child_index)) { this->line_writer_to_sharer(line, latency); // and do not write the data up in the memory hierarchy setbit(line->sharers, child_index); } break; default: assert(!"invalid line_state request!"); } //assert(line_state_req == LINE_SHR || line_state_req == LINE_EXC || line_state_req == LINE_MOD); line->state |= line_state_req; // we might also reduce from writer to LINE_SHR in this cache } else if (line->state & LINE_SHR) { switch (line_state_req) { case LINE_MOD: case LINE_EXC: this->line_make_owner_in_child_caches(line, child_index); setbit(line->sharers, child_index); if (_parent_cache) { if (_is_writeback_cache) { _parent->line_get_intercache(addr, LINE_EXC, latency, _index_in_parent, line->parent_line); } else { _parent->line_get_intercache(addr, line_state_req, latency, _index_in_parent, line->parent_line); } hit = false; } line->state |= line_state_req; break; case LINE_SHR: setbit(line->sharers, child_index); break; default: assert(!"invalid line_state request!"); } } else if (line->state == LINE_INV) { hit = false; switch (line_state_req) { case LINE_MOD: case LINE_EXC: if (_is_writeback_cache) { _parent->line_get_intercache(addr, LINE_EXC, latency, _index_in_parent, line->parent_line); } else { _parent->line_get_intercache(addr, line_state_req, latency, _index_in_parent, line->parent_line); } if (line->parent_line) { line->state = line->parent_line->state; } line->state |= line_state_req; setbit(line->sharers, child_index); break; case LINE_SHR: _parent->line_get_intercache(addr, LINE_SHR, latency, _index_in_parent, line->parent_line); if (line->parent_line) { line->state = line->parent_line->state; } line->state |= line_state_req; setbit(line->sharers, child_index); break; default: assert(!"invalid line_state request!"); } } else { NVLOG_ERROR("invalid current line_state %x\n", line->state); assert(false && "invalid current line_state!"); } if (line->pdata == NULL) { line->pdata = (uint8_t*)malloc(get_line_size()); if (_parent_cache && line->parent_line) { // if data found in any parent cache NVLOG1("%s\tline_get data copy from %s 0x%lx data 0x%lx -> 0x%lx\n", this->_name.c_str(), _parent_cache->_name.c_str(), line->addr, (Addr)line->parent_line->pdata, (Addr)line->pdata); memcpy(line->pdata, line->parent_line->pdata+(line->addr - line->parent_line->addr), get_line_size()); } else { // get the data from the memory NVLOG1("%s\tline_get data copy from memory 0x%lx data 0x%lx\n", this->_name.c_str(), line->addr, (Addr)line->pdata); // Fault fault = rw_array_silent(line->addr, get_line_size(), line->pdata, false/*READ*/); // assert(fault == NoFault); } } parent_line = line; latency += _hit_latency; // update statistics if (hit) { this->stats.hits_inc(); } else { this->stats.misses_inc(); if (line_state_req & LINE_MOD || line_state_req & LINE_EXC) { this->stats.misses_st_inc(); } else { this->stats.misses_ld_inc(); } } this->stats.ticks_inc(latency - old_ticks); NVLOG1("%s\tline_get 0x%lx\t state %s->%s sharers 0x%lx->0x%lx\n", _name.c_str(), line->addr, state2str(line_state_orig).c_str(), state2str(line->state).c_str(), line_sharers_orig, line->sharers); assert(! ((line->state & (LINE_MOD | LINE_EXC)) && (line->state & LINE_TXW)) ); }
void DeathHandler::HandleSignal(int sig, void * /* info */, void *secret) { // Stop all other running threads by forking pid_t forkedPid = fork(); if (forkedPid != 0) { int status; if (thread_safe_) { // Freeze the original process, until it's child prints the stack trace kill(getpid(), SIGSTOP); // Wait for the child without blocking and exit as soon as possible, // so that no zombies are left. waitpid(forkedPid, &status, WNOHANG); } else { // Wait for the child, blocking only the current thread. // All other threads will continue to run, potentially crashing the parent. waitpid(forkedPid, &status, 0); } #ifdef QUICK_EXIT if (quick_exit_) { ::quick_exit(EXIT_FAILURE); } #endif if (generate_core_dump_) { struct sigaction sa; sigaction(SIGABRT, NULL, &sa); sa.sa_handler = SIG_DFL; sigaction(SIGABRT, &sa, NULL); abort(); } else { if (cleanup_) { exit(EXIT_FAILURE); } else { _Exit(EXIT_FAILURE); } } } ucontext_t *uc = reinterpret_cast<ucontext_t *>(secret); if (dup2(STDERR_FILENO, STDOUT_FILENO) == -1) { // redirect stdout to stderr print("Failed to redirect stdout to stderr\n"); } char* memory = memory_; { char* msg = memory; const int msg_max_length = 128; if (color_output_) { // \033[31;1mSegmentation fault\033[0m \033[33;1m(%i)\033[0m\n strcpy(msg, "\033[31;1m"); // NOLINT(runtime/printf) } else { msg[0] = '\0'; } switch (sig) { case SIGSEGV: strcat(msg, "Segmentation fault"); // NOLINT(runtime/printf) break; case SIGABRT: strcat(msg, "Aborted"); // NOLINT(runtime/printf) break; case SIGFPE: strcat(msg, "Floating point exception"); // NOLINT(runtime/printf) break; default: strcat(msg, "Caught signal "); // NOLINT(runtime/printf) strcat(msg, Safe::itoa(sig, msg + msg_max_length)); // NOLINT(*) break; } if (color_output_) { strcat(msg, "\033[0m"); // NOLINT(runtime/printf) } strcat(msg, " (thread "); // NOLINT(runtime/printf) if (color_output_) { strcat(msg, "\033[33;1m"); // NOLINT(runtime/printf) } #ifndef __APPLE__ strcat(msg, Safe::utoa(pthread_self(), msg + msg_max_length)); // NOLINT(*) #else strcat(msg, Safe::ptoa(pthread_self(), msg + msg_max_length)); // NOLINT(*) #endif if (color_output_) { strcat(msg, "\033[0m"); // NOLINT(runtime/printf) } strcat(msg, ", pid "); // NOLINT(runtime/printf) if (color_output_) { strcat(msg, "\033[33;1m"); // NOLINT(runtime/printf) } strcat(msg, Safe::itoa(getppid(), msg + msg_max_length)); // NOLINT(*) if (color_output_) { strcat(msg, "\033[0m"); // NOLINT(runtime/printf) } strcat(msg, ")"); // NOLINT(runtime/printf) print(msg); } print("\nStack trace:\n"); void **trace = reinterpret_cast<void**>(memory); memory += (frames_count_ + 2) * sizeof(void*); // Workaround malloc() inside backtrace() heap_trap_active_ = true; int trace_size = backtrace(trace, frames_count_ + 2); heap_trap_active_ = false; if (trace_size <= 2) { safe_abort(); } // Overwrite sigaction with caller's address #ifdef __linux__ #if defined(__arm__) trace[1] = reinterpret_cast<void *>(uc->uc_mcontext.arm_pc); #elif defined(__aarch64__) trace[1] = reinterpret_cast<void *>(uc->uc_mcontext.pc); #else #if !defined(__i386__) && !defined(__x86_64__) #error Only ARM, AARCH64, x86 and x86-64 are supported #endif #if defined(__x86_64__) trace[1] = reinterpret_cast<void *>(uc->uc_mcontext.gregs[REG_RIP]); #else trace[1] = reinterpret_cast<void *>(uc->uc_mcontext.gregs[REG_EIP]); #endif #endif const int path_max_length = 2048; char* name_buf = memory; ssize_t name_buf_length = readlink("/proc/self/exe", name_buf, path_max_length - 1); if (name_buf_length < 1) { safe_abort(); } name_buf[name_buf_length] = 0; memory += name_buf_length + 1; char* cwd = memory; if (getcwd(cwd, path_max_length) == NULL) { safe_abort(); } strcat(cwd, "/"); // NOLINT(runtime/printf) memory += strlen(cwd) + 1; char* prev_memory = memory; int stackOffset = trace[2] == trace[1]? 2 : 1; for (int i = stackOffset; i < trace_size; i++) { memory = prev_memory; char *line; Dl_info dlinf; if (dladdr(trace[i], &dlinf) == 0 || dlinf.dli_fname[0] != '/' || !strcmp(name_buf, dlinf.dli_fname)) { line = addr2line(name_buf, trace[i], color_output_, &memory); } else { line = addr2line(dlinf.dli_fname, reinterpret_cast<void *>( reinterpret_cast<char *>(trace[i]) - reinterpret_cast<char *>(dlinf.dli_fbase)), color_output_, &memory); } char *function_name_end = strstr(line, "\n"); if (function_name_end != NULL) { *function_name_end = 0; { // "\033[34;1m[%s]\033[0m \033[33;1m(%i)\033[0m\n char* msg = memory; const int msg_max_length = 512; if (color_output_) { strcpy(msg, "\033[34;1m"); // NOLINT(runtime/printf) } else { msg[0] = 0; } strcat(msg, "["); // NOLINT(runtime/printf) strcat(msg, line); // NOLINT(runtime/printf) strcat(msg, "]"); // NOLINT(runtime/printf) if (append_pid_) { if (color_output_) { strcat(msg, "\033[0m\033[33;1m"); // NOLINT(runtime/printf) } strcat(msg, " ("); // NOLINT(runtime/printf) strcat(msg, Safe::itoa(getppid(), msg + msg_max_length)); // NOLINT(*) strcat(msg, ")"); // NOLINT(runtime/printf) if (color_output_) { strcat(msg, "\033[0m"); // NOLINT(runtime/printf) } strcat(msg, "\n"); // NOLINT(runtime/printf) } else { if (color_output_) { strcat(msg, "\033[0m"); // NOLINT(runtime/printf) } strcat(msg, "\n"); // NOLINT(runtime/printf) } print(msg); } line = function_name_end + 1; // Remove the common path root if (cut_common_path_root_) { int cpi; for (cpi = 0; cwd[cpi] == line[cpi]; cpi++) {}; if (line[cpi - 1] != '/') { for (; line[cpi - 1] != '/'; cpi--) {}; } if (cpi > 1) { line = line + cpi; } } // Remove relative path root if (cut_relative_paths_) { char *path_cut_pos = strstr(line, "../"); if (path_cut_pos != NULL) { path_cut_pos += 3; while (!strncmp(path_cut_pos, "../", 3)) { path_cut_pos += 3; } line = path_cut_pos; } } // Mark line number if (color_output_) { char* number_pos = strstr(line, ":"); if (number_pos != NULL) { char* line_number = memory; // 128 strcpy(line_number, number_pos); // NOLINT(runtime/printf) // Overwrite the new line char line_number[strlen(line_number) - 1] = 0; // \033[32;1m%s\033[0m\n strcpy(number_pos, "\033[32;1m"); // NOLINT(runtime/printf) strcat(line, line_number); // NOLINT(runtime/printf) strcat(line, "\033[0m\n"); // NOLINT(runtime/printf) } } } // Overwrite the new line char line[strlen(line) - 1] = 0; // Append pid if (append_pid_) { // %s\033[33;1m(%i)\033[0m\n strcat(line, " "); // NOLINT(runtime/printf) if (color_output_) { strcat(line, "\033[33;1m"); // NOLINT(runtime/printf) } strcat(line, "("); // NOLINT(runtime/printf) strcat(line, Safe::itoa(getppid(), memory)); // NOLINT(runtime/printf) strcat(line, ")"); // NOLINT(runtime/printf) if (color_output_) { strcat(line, "\033[0m"); // NOLINT(runtime/printf) } } strcat(line, "\n"); // NOLINT(runtime/printf) print(line); } // Write '\0' to indicate the end of the output char end = '\0'; write(STDERR_FILENO, &end, 1); #elif defined(__APPLE__) for (int i = 0; i < trace_size; i++) { Safe::ptoa(trace[i], memory); strcat(memory, "\n"); print(memory); } #endif if (thread_safe_) { // Resume the parent process kill(getppid(), SIGCONT); } // This is called in the child process _Exit(EXIT_SUCCESS); }
LONG WINAPI windows_exception_handler(EXCEPTION_POINTERS * ExceptionInfo) { switch(ExceptionInfo->ExceptionRecord->ExceptionCode) { case EXCEPTION_ACCESS_VIOLATION: fputs("Error: EXCEPTION_ACCESS_VIOLATION\n", stderr); break; case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: fputs("Error: EXCEPTION_ARRAY_BOUNDS_EXCEEDED\n", stderr); break; case EXCEPTION_BREAKPOINT: fputs("Error: EXCEPTION_BREAKPOINT\n", stderr); break; case EXCEPTION_DATATYPE_MISALIGNMENT: fputs("Error: EXCEPTION_DATATYPE_MISALIGNMENT\n", stderr); break; case EXCEPTION_FLT_DENORMAL_OPERAND: fputs("Error: EXCEPTION_FLT_DENORMAL_OPERAND\n", stderr); break; case EXCEPTION_FLT_DIVIDE_BY_ZERO: fputs("Error: EXCEPTION_FLT_DIVIDE_BY_ZERO\n", stderr); break; case EXCEPTION_FLT_INEXACT_RESULT: fputs("Error: EXCEPTION_FLT_INEXACT_RESULT\n", stderr); break; case EXCEPTION_FLT_INVALID_OPERATION: fputs("Error: EXCEPTION_FLT_INVALID_OPERATION\n", stderr); break; case EXCEPTION_FLT_OVERFLOW: fputs("Error: EXCEPTION_FLT_OVERFLOW\n", stderr); break; case EXCEPTION_FLT_STACK_CHECK: fputs("Error: EXCEPTION_FLT_STACK_CHECK\n", stderr); break; case EXCEPTION_FLT_UNDERFLOW: fputs("Error: EXCEPTION_FLT_UNDERFLOW\n", stderr); break; case EXCEPTION_ILLEGAL_INSTRUCTION: fputs("Error: EXCEPTION_ILLEGAL_INSTRUCTION\n", stderr); break; case EXCEPTION_IN_PAGE_ERROR: fputs("Error: EXCEPTION_IN_PAGE_ERROR\n", stderr); break; case EXCEPTION_INT_DIVIDE_BY_ZERO: fputs("Error: EXCEPTION_INT_DIVIDE_BY_ZERO\n", stderr); break; case EXCEPTION_INT_OVERFLOW: fputs("Error: EXCEPTION_INT_OVERFLOW\n", stderr); break; case EXCEPTION_INVALID_DISPOSITION: fputs("Error: EXCEPTION_INVALID_DISPOSITION\n", stderr); break; case EXCEPTION_NONCONTINUABLE_EXCEPTION: fputs("Error: EXCEPTION_NONCONTINUABLE_EXCEPTION\n", stderr); break; case EXCEPTION_PRIV_INSTRUCTION: fputs("Error: EXCEPTION_PRIV_INSTRUCTION\n", stderr); break; case EXCEPTION_SINGLE_STEP: fputs("Error: EXCEPTION_SINGLE_STEP\n", stderr); break; case EXCEPTION_STACK_OVERFLOW: fputs("Error: EXCEPTION_STACK_OVERFLOW\n", stderr); break; default: fputs("Error: Unrecognized Exception\n", stderr); break; } fflush(stderr); /* If this is a stack overflow then we can't walk the stack, so just show where the error happened */ if (EXCEPTION_STACK_OVERFLOW != ExceptionInfo->ExceptionRecord->ExceptionCode) { windows_print_stacktrace(ExceptionInfo->ContextRecord); } else { #ifdef AMD64 addr2line(icky_global_program_name, (void*)ExceptionInfo->ContextRecord->Rip); #else addr2line(icky_global_program_name, (void*)ExceptionInfo->ContextRecord->Eip); #endif } return EXCEPTION_EXECUTE_HANDLER; }