Author: mlytwyn Date: Tue Dec 1 19:46:09 2015 New Revision: 39206 URL: http://svn.gna.org/viewcvs/gnustep?rev=39206&view=rev Log: Add backtrace output to logfile if logging to file enabled
Added: libs/back/branches/gnustep_testplant_branch/Tools/Backtrace/ libs/back/branches/gnustep_testplant_branch/Tools/Backtrace/backtrace.c libs/back/branches/gnustep_testplant_branch/Tools/Backtrace/makefile libs/back/branches/gnustep_testplant_branch/Tools/Backtrace/test.c Modified: libs/back/branches/gnustep_testplant_branch/Tools/GNUmakefile.postamble libs/back/branches/gnustep_testplant_branch/Tools/GNUmakefile.preamble libs/back/branches/gnustep_testplant_branch/Tools/gpbs.m Added: libs/back/branches/gnustep_testplant_branch/Tools/Backtrace/backtrace.c URL: http://svn.gna.org/viewcvs/gnustep/libs/back/branches/gnustep_testplant_branch/Tools/Backtrace/backtrace.c?rev=39206&view=auto ============================================================================== --- libs/back/branches/gnustep_testplant_branch/Tools/Backtrace/backtrace.c (added) +++ libs/back/branches/gnustep_testplant_branch/Tools/Backtrace/backtrace.c Tue Dec 1 19:46:09 2015 @@ -0,0 +1,382 @@ +/* + 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 <url: http://www.opensource.org/licenses/bsd-license.php >. + + filename: backtrace.c + + compiler: gcc 3.4.5 (mingw-win32) + + build command: gcc -O2 -shared -Wall -o backtrace.dll backtrace.c -lbfd -liberty -limagehlp + + how to use: Call LoadLibraryA("backtrace.dll"); at beginning of your program . + + */ + +#include <windows.h> +#include <excpt.h> +#include <imagehlp.h> + +// TO get bfd.h to load... +#if !defined(PACKAGE) +#define PACKAGE "Eggplant" +#define ____PACKAGE_DEFINED +#endif +#if !defined(PACKAGE_VERSION) +#define PACKAGE_VERSION "0.0.0" +#define ____PACKAGE_VERSION_DEFINED +#endif + +#include <bfd.h> + +#if defined(____PACKAGE_DEFINED) +#undef PACKAGE +#undef ____PACKAGE_DEFINED +#endif +#if defined(____PACKAGE_VERSION_DEFINED) +#undef PACKAGE_VERSION +#undef ____PACKAGE_VERSION_DEFINED +#endif + +#include <psapi.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <stdbool.h> +#include <time.h> + +#define BUFFER_MAX (16*1024) + +struct bfd_ctx { + bfd * handle; + asymbol ** symbol; +}; + +struct bfd_set { + char * name; + struct bfd_ctx * bc; + struct 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; +}; + +static void +output_init(struct output_buffer *ob, char * buf, size_t sz) +{ + ob->buf = buf; + ob->sz = sz; + ob->ptr = 0; + ob->buf[0] = '\0'; +} + +static void +output_print(struct 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; +} + +static void +lookup_section(bfd *abfd, asection *sec, void *opaque_data) +{ + struct find_info *data = 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)); +} + +static void +find(struct bfd_ctx * b, DWORD offset, const char **file, const char **func, unsigned *line) +{ + struct 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; + } +} + +static int +init_bfd_ctx(struct bfd_ctx *bc, const char * procname, struct 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 = symbol_table; + + return 0; +} + +static void +close_bfd_ctx(struct bfd_ctx *bc) +{ + if (bc) { + if (bc->symbol) { + free(bc->symbol); + } + if (bc->handle) { + bfd_close(bc->handle); + } + } +} + +static struct bfd_ctx * +get_bc(struct output_buffer *ob , struct bfd_set *set , const char *procname) +{ + while(set->name) { + if (strcmp(set->name , procname) == 0) { + return set->bc; + } + set = set->next; + } + struct bfd_ctx bc; + if (init_bfd_ctx(&bc, procname , ob)) { + return NULL; + } + set->next = calloc(1, sizeof(*set)); + set->bc = malloc(sizeof(struct bfd_ctx)); + memcpy(set->bc, &bc, sizeof(bc)); + set->name = strdup(procname); + + return set->bc; +} + +static void +release_set(struct bfd_set *set) +{ + while(set) { + struct bfd_set * temp = set->next; + free(set->name); + close_bfd_ctx(set->bc); + free(set); + set = temp; + } +} + +static void +_backtrace(struct output_buffer *ob, struct bfd_set *set, int depth , LPCONTEXT context) +{ + char procname[MAX_PATH]; + GetModuleFileNameA(NULL, procname, sizeof procname); + + struct 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]; + + 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; + + DWORD module_base = SymGetModuleBase(process, frame.AddrPC.Offset); + + const char * module_name = "[unknown module]"; + if (module_base && + GetModuleFileNameA((HINSTANCE)module_base, module_name_raw, MAX_PATH)) { + module_name = module_name_raw; + bc = get_bc(ob, set, module_name); + } + + 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); + } + } +} + +static char * g_output = NULL; +static LPTOP_LEVEL_EXCEPTION_FILTER g_prev = NULL; + +static LONG WINAPI +exception_filter(LPEXCEPTION_POINTERS info) +{ + struct output_buffer ob; + time_t *crashTime = calloc(1,sizeof(*crashTime)); + char timeString[256]; + + output_init(&ob, g_output, BUFFER_MAX); + time(crashTime); + strftime(timeString, 256, "%Y-%m-%d %H:%M:%S", localtime(crashTime)); + + output_print(&ob,"\nCrash Backtrace: %s\n", timeString); + + if (!SymInitialize(GetCurrentProcess(), 0, TRUE)) { + output_print(&ob,"\nFailed to init symbol context\n"); + } + else { + bfd_init(); + struct bfd_set *set = calloc(1,sizeof(*set)); + _backtrace(&ob , set , 128 , info->ContextRecord); + release_set(set); + + SymCleanup(GetCurrentProcess()); + } + + fputs(g_output , stderr); + + exit(1); + + return 0; +} + +static void +backtrace_register(void) +{ + if (g_output == NULL) { + g_output = malloc(BUFFER_MAX); + g_prev = SetUnhandledExceptionFilter(exception_filter); + } +} + +static void +backtrace_unregister(void) +{ + if (g_output) { + free(g_output); + SetUnhandledExceptionFilter(g_prev); + g_prev = NULL; + g_output = NULL; + } +} + +BOOL WINAPI +DllMain(HANDLE hinstDLL, DWORD dwReason, LPVOID lpvReserved) +{ + switch (dwReason) { + case DLL_PROCESS_ATTACH: + backtrace_register(); + break; + case DLL_PROCESS_DETACH: + backtrace_unregister(); + break; + } + return TRUE; +} + Added: libs/back/branches/gnustep_testplant_branch/Tools/Backtrace/makefile URL: http://svn.gna.org/viewcvs/gnustep/libs/back/branches/gnustep_testplant_branch/Tools/Backtrace/makefile?rev=39206&view=auto ============================================================================== --- libs/back/branches/gnustep_testplant_branch/Tools/Backtrace/makefile (added) +++ libs/back/branches/gnustep_testplant_branch/Tools/Backtrace/makefile Tue Dec 1 19:46:09 2015 @@ -0,0 +1,12 @@ +.PHONY: all clean + +all : backtrace.dll test.exe + +backtrace.dll : backtrace.c + gcc -O2 -shared -Wall -o $@ $^ -lbfd -lintl -liberty -limagehlp -lz + +test.exe : test.c + gcc -g -Wall -o $@ $^ + +clean : + -rm -f backtrace.dll test.exe Added: libs/back/branches/gnustep_testplant_branch/Tools/Backtrace/test.c URL: http://svn.gna.org/viewcvs/gnustep/libs/back/branches/gnustep_testplant_branch/Tools/Backtrace/test.c?rev=39206&view=auto ============================================================================== --- libs/back/branches/gnustep_testplant_branch/Tools/Backtrace/test.c (added) +++ libs/back/branches/gnustep_testplant_branch/Tools/Backtrace/test.c Tue Dec 1 19:46:09 2015 @@ -0,0 +1,23 @@ +#include <windows.h> + +static void +foo() +{ + int *f=NULL; + *f = 0; +} + +static void +bar() +{ + foo(); +} + +int +main() +{ + LoadLibraryA("backtrace.dll"); + bar(); + + return 0; +} Modified: libs/back/branches/gnustep_testplant_branch/Tools/GNUmakefile.postamble URL: http://svn.gna.org/viewcvs/gnustep/libs/back/branches/gnustep_testplant_branch/Tools/GNUmakefile.postamble?rev=39206&r1=39205&r2=39206&view=diff ============================================================================== --- libs/back/branches/gnustep_testplant_branch/Tools/GNUmakefile.postamble (original) +++ libs/back/branches/gnustep_testplant_branch/Tools/GNUmakefile.postamble Tue Dec 1 19:46:09 2015 @@ -32,6 +32,9 @@ $(LN_S) ../Source/xlib/XGCommonFont.m . -$(RM) xdnd.c $(LN_S) ../Source/x11/xdnd.c . +ifeq ($(findstring mingw32, $(GNUSTEP_TARGET_OS)), mingw32) + (cd Backtrace; make; cd ..) +endif # Things to do after compiling # after-all:: @@ -41,6 +44,9 @@ # Things to do after installing after-install:: +ifeq ($(findstring mingw32, $(GNUSTEP_TARGET_OS)), mingw32) + $(INSTALL) backtrace/backtrace.dll $(GNUSTEP_TOOLS) +endif if [ ! -f $(GNUSTEP_DOC_MAN) ]; then \ $(MKDIRS) $(GNUSTEP_DOC_MAN); \ fi; \ @@ -60,6 +66,9 @@ # Things to do after uninstalling after-uninstall:: +ifeq ($(findstring mingw32, $(GNUSTEP_TARGET_OS)), mingw32) + rm -f $(GNUSTEP_TOOLS)/backtrace.dll +endif for file in $(MAN1_PAGES) __done; do \ if [ $$file != __done ]; then \ rm -f $(GNUSTEP_DOC_MAN)/man1/$$file.gz; \ Modified: libs/back/branches/gnustep_testplant_branch/Tools/GNUmakefile.preamble URL: http://svn.gna.org/viewcvs/gnustep/libs/back/branches/gnustep_testplant_branch/Tools/GNUmakefile.preamble?rev=39206&r1=39205&r2=39206&view=diff ============================================================================== --- libs/back/branches/gnustep_testplant_branch/Tools/GNUmakefile.preamble (original) +++ libs/back/branches/gnustep_testplant_branch/Tools/GNUmakefile.preamble Tue Dec 1 19:46:09 2015 @@ -67,3 +67,10 @@ else ADDITIONAL_TOOL_LIBS += -lgnustep-gui -lgnustep-back $(SYSTEM_LIBS) endif + +ifeq ($(findstring mingw32, $(GNUSTEP_TARGET_OS)), mingw32) +ADDITIONAL_LIB_DIRS += -L./Backtrace +ADDITIONAL_TOOL_LIBS += -lbacktrace +SUBPROJECTS = Backtrace +endif + Modified: libs/back/branches/gnustep_testplant_branch/Tools/gpbs.m URL: http://svn.gna.org/viewcvs/gnustep/libs/back/branches/gnustep_testplant_branch/Tools/gpbs.m?rev=39206&r1=39205&r2=39206&view=diff ============================================================================== --- libs/back/branches/gnustep_testplant_branch/Tools/gpbs.m (original) +++ libs/back/branches/gnustep_testplant_branch/Tools/gpbs.m Tue Dec 1 19:46:09 2015 @@ -1235,6 +1235,7 @@ } } +#if 0 // TODO... // Purge logfile to 3 max each... NSArray *properties = [NSArray arrayWithObjects:@"NSURLCreationDateKey", nil]; NSArray *logfiles = [filemgr contentsOfDirectoryAtURL:[NSURL fileURLWithPath:filepath] @@ -1265,6 +1266,7 @@ NSLog(@"%s:purging output log files: %@", __PRETTY_FUNCTION__, outfiles); } } +#endif if ([filemgr fileExistsAtPath:filepath isDirectory:&isDir] && isDir) { @@ -1418,12 +1420,27 @@ } } } + +#if defined(__MINGW__) + if ([[NSUserDefaults standardUserDefaults] boolForKey:@"GSGPBSLoggingEnabled"]) + { + // Load backtrace library for mingw... + NSString *gpbstool = [NSString stringWithCString:argv[0] encoding:NSASCIIStringEncoding]; + NSString *gpbspath = [gpbstool stringByDeletingLastPathComponent]; + NSString *backtrace = [gpbspath stringByAppendingPathComponent:@"backtrace.dll"]; + + if (LoadLibraryA([backtrace cStringUsingEncoding:NSUTF8StringEncoding]) == 0) + NSWarnMLog(@"error loading mingw backtrace library - status: %d", GetLastError()); + else + NSWarnMLog(@"Windows/mingw backtrace library loaded successfully"); + } +#endif if (verbose) { NSLog(@"GNU pasteboard server startup."); } - + if ([[NSUserDefaults standardUserDefaults] stringForKey: @"GSStartupNotification"]) { _______________________________________________ Gnustep-cvs mailing list Gnustep-cvs@gna.org https://mail.gna.org/listinfo/gnustep-cvs