=== modified file 'win32/SConscript' --- win32/SConscript 2011-04-15 20:53:17 +0000 +++ win32/SConscript 2011-06-05 13:27:19 +0000 @@ -16,6 +16,8 @@ env.Append(LIBS='htmlhelp') env.Append(LIBS = ['comctl32', 'ws2_32', 'ole32', 'gdi32', 'comdlg32', 'iphlpapi', 'winmm', 'shlwapi', 'oleaut32', 'uuid']) +if env['LINK'] == 'g++': + env.Append(LIBS = ['bfd', 'iberty', 'imagehlp']) env.Append(CPPPATH = ['#/openssl/include', '#/bzip2', '#/zlib', '#/miniupnpc', '#/dwt/include']) === added file 'win32/backtrace.cpp' --- win32/backtrace.cpp 1970-01-01 00:00:00 +0000 +++ win32/backtrace.cpp 2011-06-05 15:23:09 +0000 @@ -0,0 +1,367 @@ +/* +* Copyright (C) 2001-2011 Jacek Sieka, arnetheduck on gmail point com +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#include "stdafx.h" +#include "backtrace.h" + +#ifdef __MINGW32__ + +/* + Copyright (c) 2010 , + Cloud Wu . All rights reserved. + + http://www.codingnow.com + + Use, modification and distribution are subject to the "New BSD License" + as listed at . +*/ + +/* This backtrace writer for MinGW comes from the backtrace-mingw project by Cloud Wu: + + +It has been slightly modified for DC++. */ + +#include +#include + +#define BUFFER_MAX (16*1024) + +struct bfd_ctx { + bfd * handle; + asymbol ** symbol; +}; + +struct bfd_set { + char * name; + bfd_ctx * bc; + bfd_set *next; +}; + +struct find_info { + asymbol **symbol; + bfd_vma counter; + const char *file; + const char *func; + unsigned line; +}; + +struct output_buffer { + char * buf; + size_t sz; + size_t ptr; +}; + +void output_init(output_buffer *ob, char * buf, size_t sz) +{ + ob->buf = buf; + ob->sz = sz; + ob->ptr = 0; + ob->buf[0] = '\0'; +} + +void output_print(output_buffer *ob, const char * format, ...) +{ + if (ob->sz == ob->ptr) + return; + ob->buf[ob->ptr] = '\0'; + va_list ap; + va_start(ap,format); + vsnprintf(ob->buf + ob->ptr , ob->sz - ob->ptr , format, ap); + va_end(ap); + + ob->ptr = strlen(ob->buf + ob->ptr) + ob->ptr; +} + +void lookup_section(bfd *abfd, asection *sec, void *opaque_data) +{ + find_info *data = reinterpret_cast(opaque_data); + + if (data->func) + return; + + if (!(bfd_get_section_flags(abfd, sec) & SEC_ALLOC)) + return; + + bfd_vma vma = bfd_get_section_vma(abfd, sec); + if (data->counter < vma || vma + bfd_get_section_size(sec) <= data->counter) + return; + + bfd_find_nearest_line(abfd, sec, data->symbol, data->counter - vma, &(data->file), &(data->func), &(data->line)); +} + +void find(bfd_ctx * b, DWORD offset, const char **file, const char **func, unsigned *line) +{ + find_info data; + data.func = NULL; + data.symbol = b->symbol; + data.counter = offset; + data.file = NULL; + data.func = NULL; + data.line = 0; + + bfd_map_over_sections(b->handle, &lookup_section, &data); + if (file) { + *file = data.file; + } + if (func) { + *func = data.func; + } + if (line) { + *line = data.line; + } +} + +int init_bfd_ctx(bfd_ctx *bc, const char * procname, output_buffer *ob) +{ + bc->handle = NULL; + bc->symbol = NULL; + + bfd *b = bfd_openr(procname, 0); + if (!b) { + output_print(ob,"Failed to open bfd from (%s)\n" , procname); + return 1; + } + + int r1 = bfd_check_format(b, bfd_object); + int r2 = bfd_check_format_matches(b, bfd_object, NULL); + int r3 = bfd_get_file_flags(b) & HAS_SYMS; + + if (!(r1 && r2 && r3)) { + bfd_close(b); + output_print(ob,"Failed to init bfd from (%s)\n", procname); + return 1; + } + + void *symbol_table; + + unsigned dummy = 0; + if (bfd_read_minisymbols(b, FALSE, &symbol_table, &dummy) == 0) { + if (bfd_read_minisymbols(b, TRUE, &symbol_table, &dummy) < 0) { + free(symbol_table); + bfd_close(b); + output_print(ob,"Failed to read symbols from (%s)\n", procname); + return 1; + } + } + + bc->handle = b; + bc->symbol = reinterpret_cast(symbol_table); + + return 0; +} + +void close_bfd_ctx(bfd_ctx *bc) +{ + if (bc) { + if (bc->symbol) { + free(bc->symbol); + } + if (bc->handle) { + bfd_close(bc->handle); + } + } +} + +bfd_ctx * get_bc(output_buffer *ob , bfd_set *set , const char *procname) +{ + while(set->name) { + if (strcmp(set->name , procname) == 0) { + return set->bc; + } + set = set->next; + } + bfd_ctx bc; + if (init_bfd_ctx(&bc, procname , ob)) { + return NULL; + } + set->next = reinterpret_cast(calloc(1, sizeof(*set))); + set->bc = reinterpret_cast(malloc(sizeof(bfd_ctx))); + memcpy(set->bc, &bc, sizeof(bc)); + set->name = strdup(procname); + + return set->bc; +} + +void release_set(bfd_set *set) +{ + while(set) { + bfd_set * temp = set->next; + free(set->name); + close_bfd_ctx(set->bc); + free(set); + set = temp; + } +} + +void _backtrace(output_buffer *ob, bfd_set *set, int depth , LPCONTEXT context) +{ + bfd_ctx *bc = NULL; + + STACKFRAME frame; + memset(&frame,0,sizeof(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; + + HANDLE process = GetCurrentProcess(); + HANDLE thread = GetCurrentThread(); + + char symbol_buffer[sizeof(IMAGEHLP_SYMBOL) + 255]; + char module_name_raw[MAX_PATH]; + + // get the current module address. + HMODULE module = GetModuleHandle(0); + + while(StackWalk(IMAGE_FILE_MACHINE_I386, + process, + thread, + &frame, + context, + 0, + SymFunctionTableAccess, + SymGetModuleBase, 0)) { + + --depth; + if (depth < 0) + break; + + IMAGEHLP_SYMBOL *symbol = (IMAGEHLP_SYMBOL *)symbol_buffer; + symbol->SizeOfStruct = (sizeof *symbol) + 255; + symbol->MaxNameLength = 254; + + HMODULE module_base = reinterpret_cast(SymGetModuleBase(process, frame.AddrPC.Offset)); + + const char * module_name = 0; + if(module_base) { + if(module_base == module) { + module_name = "DCPlusPlus.pdb"; + } else if(GetModuleFileNameA(module_base, module_name_raw, MAX_PATH)) { + module_name = module_name_raw; + } + } + if(module_name) { + bc = get_bc(ob, set, module_name); + } else { + module_name = "[unknown module]"; + } + + const char * file = NULL; + const char * func = NULL; + unsigned line = 0; + + if (bc) { + find(bc,frame.AddrPC.Offset,&file,&func,&line); + } + + if (file == NULL) { + DWORD dummy = 0; + if (SymGetSymFromAddr(process, frame.AddrPC.Offset, &dummy, symbol)) { + file = symbol->Name; + } + else { + file = "[unknown file]"; + } + } + if (func == NULL) { + output_print(ob,"0x%x : %s : %s \n", + frame.AddrPC.Offset, + module_name, + file); + } + else { + output_print(ob,"0x%x : %s : %s (%d) : in function (%s) \n", + frame.AddrPC.Offset, + module_name, + file, + line, + func); + } + } +} + +char* g_output = 0; +std::string g_path; +LPTOP_LEVEL_EXCEPTION_FILTER g_prev = 0; + +LONG WINAPI exception_filter(LPEXCEPTION_POINTERS info) +{ + output_buffer ob; + output_init(&ob, g_output, BUFFER_MAX); + + if (!SymInitialize(GetCurrentProcess(), 0, TRUE)) { + output_print(&ob,"Failed to init symbol context\n"); + } + else { + bfd_init(); + bfd_set *set = reinterpret_cast(calloc(1,sizeof(*set))); + _backtrace(&ob , set , 128 , info->ContextRecord); + release_set(set); + + SymCleanup(GetCurrentProcess()); + } + + if(!g_path.empty()) { + FILE* f = fopen(g_path.c_str(), "w"); + if(f) { + fputs(g_output, f); + fclose(f); + } + } + + fputs(g_output , stderr); + + exit(1); + + return 0; +} + +void backtrace_register(const std::string& path) +{ + if (g_output == NULL) { + g_output = reinterpret_cast(malloc(BUFFER_MAX)); + g_path = path; + g_prev = SetUnhandledExceptionFilter(exception_filter); + } +} + +void backtrace_unregister() +{ + if (g_output) { + free(g_output); + SetUnhandledExceptionFilter(g_prev); + g_prev = NULL; + g_output = NULL; + } +} + +/// @todo add methods for MSVC +#else + +void backtrace_register(const std::string& path) +{ +} + +void backtrace_unregister() +{ +} + +#endif === added file 'win32/backtrace.h' --- win32/backtrace.h 1970-01-01 00:00:00 +0000 +++ win32/backtrace.h 2011-06-05 15:21:17 +0000 @@ -0,0 +1,25 @@ +/* +* Copyright (C) 2001-2011 Jacek Sieka, arnetheduck on gmail point com +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +*/ + +#ifndef DCPLUSPLUS_WIN32_BACKTRACE_H +#define DCPLUSPLUS_WIN32_BACKTRACE_H + +void backtrace_register(const std::string& path); +void backtrace_unregister(); + +#endif // DCPLUSPLUS_WIN32_BACKTRACE_H === modified file 'win32/main.cpp' --- win32/main.cpp 2011-04-07 13:40:55 +0000 +++ win32/main.cpp 2011-06-05 15:02:40 +0000 @@ -20,6 +20,7 @@ #include +#include "backtrace.h" #include "SingleInstance.h" #include "WinUtil.h" #include "MainWindow.h" @@ -93,6 +94,8 @@ Util::initialize(); + backtrace_register(Util::getPath(Util::PATH_USER_LOCAL) + "ErrorLog.txt"); + string configPathHash; { std::string configPath = Util::getPath(Util::PATH_USER_CONFIG); @@ -171,6 +174,8 @@ ::CoUninitialize(); + backtrace_unregister(); + return 0; }