debugger: add C backtrace for windows

Because that needs the DbgHelp library, an additional make
    option has been defined for users, who don't want to link to this
    library. Some msvc Makefile cleanup has also been done.
This commit is contained in:
Marius Gerbershagen 2018-05-06 14:28:08 +02:00 committed by Daniel Kochmanski
parent 2279361383
commit a3a44a0eeb
4 changed files with 107 additions and 19 deletions

View file

@ -60,6 +60,8 @@ ECL_RT =
ECL_DEFSYS =
# Profiling
ECL_PROFILE =
# Use the DbgHelp.lib shared library to provide C Backtrace support
ECL_USE_DBGHELP = $(ECL_DEBUG)
!if "$(YASM)" == ""
!if "$(ECL_WIN64)" != ""
@ -78,7 +80,9 @@ TAR_DIR = %CD%\ecl-$(ECL_VERSION)
#
CC = cl
LIBS = eclgc.lib eclgmp.lib user32.lib ws2_32.lib shell32.lib
CLIBS = user32.lib ws2_32.lib shell32.lib
STATICLIBS = eclgc.lib eclgmp.lib
LIBS = $(STATICLIBS) $(CLIBS)
RM = del
RMDIR = rmdir /Q /S
MKDIR = mkdir
@ -123,6 +127,10 @@ SHARED_LDFLAGS = /LD
GCFLAGS = nodebug=1
!endif
!if "$(ECL_USE_DBGHELP)" != ""
CLIBS = $(CLIBS) DbgHelp.lib
!endif
CFLAGS = /EHsc /DGC_DLL /DGC_BUILD /nologo /D_CRT_SECURE_NO_DEPRECATE $(CFLAGS_CONFIG)
LDFLAGS = /link /incremental:no /nologo /nodefaultlib:libcmt /nodefaultlib:libcmtd /nodefaultlib:libc /nodefaultlib:libcd $(LDFLAGS_CONFIG)
@ -263,9 +271,9 @@ compile.lsp: bare.lsp $(srcdir)/compile.lsp.in Makefile
"@LDFLAGS@" "$(LDFLAGS)" \
"@SHARED_LDFLAGS@" "$(SHARED_LDFLAGS)" \
"@BUNDLE_LDFLAGS@" "$(SHARED_LDFLAGS)" \
"@CLIBS@" "user32.lib ws2_32.lib shell32.lib" \
"@STATICLIBS@" "eclgmp.lib eclgc.lib" \
"@LIBS@" "user32.lib ws2_32.lib shell32.lib" \
"@CLIBS@" "$(CLIBS)" \
"@STATICLIBS@" "$(STATICLIBS)" \
"@LIBS@" "$(LIBS)" \
"@CORE_LIBS@" "" \
"@FASL_LIBS@" "" \
"@OBJEXT@" "obj" \
@ -305,8 +313,8 @@ cmp/cmpdefs.lsp: $(srcdir)/cmp/cmpdefs.lsp Makefile
"@LDFLAGS@" "$(LDFLAGS)" \
"@SHARED_LDFLAGS@" "$(SHARED_LDFLAGS)" \
"@BUNDLE_LDFLAGS@" "$(SHARED_LDFLAGS)" \
"@CLIBS@" "user32.lib ws2_32.lib shell32.lib" \
"@STATICLIBS@" "eclgmp.lib eclgc.lib" \
"@CLIBS@" "$(CLIBS)" \
"@STATICLIBS@" "$(STATICLIBS)" \
"@OBJEXT@" "obj" \
"@SHAREDPREFIX@" "" \
"@SHAREDEXT@" "dll" \
@ -340,6 +348,7 @@ eclmin.lib: eclgmp.lib eclgc.lib lsp/config.lsp
$(MAKE) ECL_VERSION_NUMBER=$(ECL_VERSION_NUMBER) \
ECL_THREADS=$(ECL_THREADS) ECL_UNICODE=$(ECL_UNICODE) \
ECL_SSE=$(ECL_SSE) ECL_WIN64=$(ECL_WIN64) \
ECL_USE_DBGHELP=$(ECL_USE_DBGHELP) \
"ECL_CFLAGS=$(CFLAGS) -DGC_BUILD"
cd ..
eclgc.lib:
@ -448,6 +457,7 @@ clean_ecl:
-$(MAKE) ECL_VERSION_NUMBER=$(ECL_VERSION_NUMBER) \
ECL_THREADS=$(ECL_THREADS) ECL_UNICODE=$(ECL_UNICODE) \
ECL_SSE=$(ECL_SSE) ECL_WIN64=$(ECL_WIN64) \
ECL_USE_DBGHELP=$(ECL_USE_DBGHELP) \
"ECL_CFLAGS=$(CFLAGS) -DGC_BUILD" clean
cd ..
clean_lisp:

View file

@ -35,6 +35,12 @@ ECL_SSE_FLAG=0
ECL_SSE_OBJ=
!endif
!if "$(ECL_USE_DBGHELP)" != ""
ECL_USE_DBGHELP_FLAG=1
!else
ECL_USE_DBGHELP_FLAG=0
!endif
# Programs used by "make":
#
TRUE_CC = cl
@ -60,12 +66,14 @@ libdir=$(prefix)\lib\ecl
# Files
HDIR = $(top_srcdir)\h
HFILES = ..\ecl\config.h ..\ecl\atomic_ops.h $(HDIR)\ecl.h $(HDIR)\ecl-cmp.h\
$(HDIR)\object.h $(HDIR)\cs.h $(HDIR)\stacks.h\
$(HDIR)\external.h $(HDIR)\cons.h $(HDIR)\legacy.h\
HFILES = ..\ecl\config.h ..\ecl\config-internal.h ..\ecl\atomic_ops.h \
$(HDIR)\ecl.h $(HDIR)\ecl-cmp.h \
$(HDIR)\object.h $(HDIR)\cs.h $(HDIR)\stacks.h \
$(HDIR)\external.h $(HDIR)\cons.h $(HDIR)\legacy.h \
$(HDIR)\number.h $(HDIR)\page.h \
$(HDIR)\internal.h $(HDIR)\ecl-inl.h $(HDIR)\bytecodes.h \
$(HDIR)\impl\math_dispatch.h
$(HDIR)\impl\math_dispatch.h $(HDIR)\cache.h $(HDIR)\stack-resize.h \
$(HDIR)\ecl-atomic-ops.h
OBJS = main.obj symbol.obj package.obj cons.obj list.obj\
apply.obj eval.obj \
@ -153,21 +161,23 @@ clean:
# Build rules
$(DPP): $(srcdir)/dpp.c $(srcdir)/symbols_list2.h ../ecl/config.h
$(DPP): $(srcdir)/dpp.c $(srcdir)/symbols_list2.h ../ecl/config.h ../ecl/config-internal.h
$(TRUE_CC) -I.. -I./ $(srcdir)/dpp.c -o $@
$(HFILES): ../ecl/config.h.msvc6 Makefile
$(HFILES): ../ecl/config.h.msvc6 ../ecl/config-internal.h.msvc6 Makefile
-mkdir ..\ecl\impl
cut.exe "@ECL_FPE_CODE@" "$(srcdir:\=/)/arch/$(ECL_FPE_CODE)" \
"@ECL_VERSION_NUMBER@" "$(ECL_VERSION_NUMBER)" \
"@ECL_THREADS@" "$(ECL_THREADS_FLAG)" \
"@ECL_UNICODE@" "$(ECL_UNICODE_FLAG)" \
"@ECL_SSE2@" "$(ECL_SSE_FLAG)" \
"@ECL_USE_DBGHELP@" "$(ECL_USE_DBGHELP_FLAG)" \
< ..\ecl\config.h.msvc6 > ..\ecl\config.h
cut.exe "@ECL_FPE_CODE@" "$(srcdir:\=/)/arch/$(ECL_FPE_CODE)" \
"@ECL_VERSION_NUMBER@" "$(ECL_VERSION_NUMBER)" \
"@ECL_THREADS@" "$(ECL_THREADS_FLAG)" \
"@ECL_UNICODE@" "$(ECL_UNICODE_FLAG)" \
"@ECL_SSE2@" "$(ECL_SSE_FLAG)" \
"@ECL_USE_DBGHELP@" "$(ECL_USE_DBGHELP_FLAG)" \
< ..\ecl\config-internal.h.msvc6 > ..\ecl\config-internal.h
xcopy /SYI $(top_srcdir)\h\*.h ..\ecl
-mkdir ..\ecl\atomic_ops

View file

@ -210,3 +210,8 @@
# define ECL_MATHERR_CLEAR
# define ECL_MATHERR_TEST
#endif
#define ECL_WINDOWS_BACKTRACE @ECL_USE_DBGHELP@
#if !ECL_WINDOWS_BACKTRACE
#undef ECL_WINDOWS_BACKTRACE
#endif

View file

@ -14,53 +14,116 @@
#include <stdlib.h>
#include <ecl/ecl.h>
#if defined(HAVE_BACKTRACE) || defined(HAVE_BACKTRACE_SYMBOLS)
#if defined(HAVE_BACKTRACE) && defined(HAVE_BACKTRACE_SYMBOLS)
# include <execinfo.h>
# define ECL_UNIX_BACKTRACE
#endif
#if defined(ECL_WINDOWS_BACKTRACE)
# include <windows.h>
# include <DbgHelp.h>
#endif
/* Max number of frames dumped by _ecl_dump_c_backtrace */
#define MAX_BACKTRACE_SIZE 128
/* Max length of symbols printed */
#define MAX_SYMBOL_LENGTH 256
void
_ecl_dump_c_backtrace()
{
#ifdef HAVE_BACKTRACE_SYMBOLS
#if defined(ECL_UNIX_BACKTRACE) || defined(ECL_WINDOWS_BACKTRACE)
{
void **pointers = malloc(sizeof(void*) * MAX_BACKTRACE_SIZE);
# if defined(ECL_UNIX_BACKTRACE)
int nframes = backtrace(pointers, MAX_BACKTRACE_SIZE);
char **names = backtrace_symbols(pointers, nframes);
# elif defined(ECL_WINDOWS_BACKTRACE)
HANDLE process = GetCurrentProcess();
if (!SymInitialize(process, NULL, TRUE)) {
return;
}
int nframes = CaptureStackBackTrace(0, MAX_BACKTRACE_SIZE, pointers, NULL);
char buffer[sizeof(SYMBOL_INFO) + MAX_SYMBOL_LENGTH * sizeof(TCHAR)];
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
pSymbol->MaxNameLen = MAX_SYMBOL_LENGTH;
# endif
int i;
fprintf(stderr, "\n;;; ECL C Backtrace\n");
for (i = 0; i < nframes; i++) {
# if defined(ECL_UNIX_BACKTRACE)
fprintf(stderr, ";;; %s\n", names[i]);
# elif defined(ECL_WINDOWS_BACKTRACE)
DWORD64 displacement;
if (SymFromAddr(process, (DWORD64) pointers[i], &displacement, pSymbol)) {
fprintf(stderr, ";;; (%s+0x%llx) [0x%p]\n", pSymbol->Name, displacement, pointers[i]);
} else {
fprintf(stderr, ";;; (unknown) [0x%p]\n", pointers[i]);
}
# endif
}
fflush(stderr);
free(names);
free(pointers);
# if defined(ECL_UNIX_BACKTRACE)
free(names);
# elif defined(ECL_WINDOWS_BACKTRACE)
SymCleanup(process);
# endif
}
#endif
#endif /* defined(ECL_UNIX_BACKTRACE) || defined(ECL_WINDOWS_BACKTRACE) */
}
cl_object
si_dump_c_backtrace(cl_object size)
{
cl_env_ptr the_env = ecl_process_env();
#ifdef HAVE_BACKTRACE_SYMBOLS
#if defined(ECL_UNIX_BACKTRACE) || defined(ECL_WINDOWS_BACKTRACE)
{
cl_index nsize = ecl_to_unsigned_integer(size);
void **pointers = malloc(sizeof(void*) * nsize);
# if defined(ECL_UNIX_BACKTRACE)
int nframes = backtrace(pointers, nsize);
char **names = backtrace_symbols(pointers, nframes);
# elif defined(ECL_WINDOWS_BACKTRACE)
HANDLE process = GetCurrentProcess();
if (!SymInitialize(process, NULL, TRUE)) {
return;
}
int nframes = CaptureStackBackTrace(0, nsize, pointers, NULL);
char buffer[sizeof(SYMBOL_INFO) + MAX_SYMBOL_LENGTH * sizeof(TCHAR)];
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
pSymbol->MaxNameLen = MAX_SYMBOL_LENGTH;
# endif
int i;
cl_format(2, ECL_T, make_constant_base_string("~&C Backtrace:~%"));
for (i = 0; i < nframes; i++) {
# if defined(ECL_UNIX_BACKTRACE)
cl_format(3, ECL_T, make_constant_base_string(" > ~a~%"),
make_constant_base_string(names[i]));
# elif defined(ECL_WINDOWS_BACKTRACE)
DWORD64 displacement;
if (SymFromAddr(process, (DWORD64) pointers[i], &displacement, pSymbol)) {
cl_format(5, ECL_T, make_constant_base_string(" > (~a+0x~x) [0x~x]~%"),
make_constant_base_string(pSymbol->Name),
ecl_make_unsigned_integer(displacement),
ecl_make_unsigned_integer((cl_index)pointers[i]));
} else {
cl_format(3, ECL_T, make_constant_base_string(" > (unknown) [0x~x]~%"),
ecl_make_unsigned_integer((cl_index)pointers[i]));
}
# endif
}
free(names);
free(pointers);
# if defined(ECL_UNIX_BACKTRACE)
free(names);
# elif defined(ECL_WINDOWS_BACKTRACE)
SymCleanup(process);
# endif
}
ecl_return1(the_env, ECL_T);
#else
ecl_return1(the_env, ECL_NIL);
#endif
#endif /* defined(ECL_UNIX_BACKTRACE) || defined(ECL_WINDOWS_BACKTRACE) */
}