From 3830a9f5800441ce1c3494fcebd9e14e5357ae91 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 17 Sep 2014 17:24:12 +0200 Subject: [PATCH 01/10] Added windows implementation of backtrace. --- winpr/libwinpr/utils/CMakeLists.txt | 4 ++ winpr/libwinpr/utils/debug.c | 100 ++++++++++++++++++++++++---- 2 files changed, 91 insertions(+), 13 deletions(-) diff --git a/winpr/libwinpr/utils/CMakeLists.txt b/winpr/libwinpr/utils/CMakeLists.txt index 3e75355a5..cee4016c6 100644 --- a/winpr/libwinpr/utils/CMakeLists.txt +++ b/winpr/libwinpr/utils/CMakeLists.txt @@ -111,6 +111,10 @@ if(UNIX) winpr_library_add(m) endif() +if(WIN32) + winpr_library_add(Dbghelp) +endif() + if(BUILD_TESTING) add_subdirectory(test) endif() diff --git a/winpr/libwinpr/utils/debug.c b/winpr/libwinpr/utils/debug.c index d76f1ac8a..b41a0020d 100644 --- a/winpr/libwinpr/utils/debug.c +++ b/winpr/libwinpr/utils/debug.c @@ -32,6 +32,11 @@ #include #endif +#if defined(_WIN32) || defined(_WIN64) +#include +#include +#endif + #include #include #include @@ -55,6 +60,15 @@ typedef struct } t_execinfo; #endif +#if defined(_WIN32) || defined(_WIN64) +typedef struct +{ + PVOID* stack; + ULONG used; + ULONG size; +} t_win_stack; +#endif + #if defined(ANDROID) #include #include @@ -191,6 +205,11 @@ void winpr_backtrace_free(void *buffer) free(data->buffer); free(data); +#elif defined(_WIN32) || defined(_WIN64) + t_win_stack *data = (t_win_stack*)buffer; + if (data->stack) + free(data->stack); + free(data); #else LOGF(support_msg); #endif @@ -230,6 +249,25 @@ void *winpr_backtrace(DWORD size) data->max = size; data->used = fkt->unwind_backtrace(data->buffer, 0, size); return data; +#elif defined(_WIN32) || defined(_WIN64) + HANDLE process = GetCurrentProcess(); + t_win_stack *data = calloc(1, sizeof(t_win_stack)); + + if (!data) + return NULL; + + data->size = size; + data->stack = calloc(data->size, sizeof(PVOID)); + if (!data->stack) + { + free(data); + return NULL; + } + + SymInitialize( process, NULL, TRUE ); + data->used = CaptureStackBackTrace(2, size, data->stack, NULL); + + return data; #else LOGF(support_msg); return NULL; @@ -271,7 +309,7 @@ char **winpr_backtrace_symbols(void *buffer, size_t *used) size_t i; char *lines = calloc(data->used + 1, sizeof(char *) * line_len); char **vlines = (char **)lines; - backtrace_symbol_t *symbols = calloc(data->used, sizeof(backtrace_symbol_t));; + backtrace_symbol_t *symbols = calloc(data->used, sizeof(backtrace_symbol_t)); if (!lines || !symbols) { @@ -295,13 +333,52 @@ char **winpr_backtrace_symbols(void *buffer, size_t *used) fkt->format_backtrace_line(i, &data->buffer[i], &symbols[i], vlines[i], line_len); fkt->free_backtrace_symbols(symbols, data->used); + free(symbols); if (used) *used = data->used; return (char **)lines; } +#elif defined(_WIN32) || defined(_WIN64) + HANDLE process = GetCurrentProcess(); + t_win_stack *data = (t_win_stack *)buffer; + assert(data); + + size_t line_len = (data->max > 1024) ? data->max : 1024; + size_t i; + char *lines = calloc(data->used + 1, sizeof(char *) * line_len); + char **vlines = (char **)lines; + SYMBOL_INFO* symbol = calloc(sizeof(SYMBOL_INFO) + line_len * sizeof(char), 1); + if (!lines || !symbol) + { + if (lines) + free(lines); + + if (symbol) + free(symbol); + + return NULL; + } + + /* To allow a char** malloced array to be returned, allocate n+1 lines + * and fill in the first lines[i] char with the address of lines[(i+1) * 1024] */ + for (i=0; iused; i++) + vlines[i] = &lines[(i + 1) * line_len]; + + for (i=0; iused; i++) + { + SymFromAddr(process, (DWORD64)(data->stack[i]), 0, &symbol); + _snprintf(vlines[i], line_len, "%08lX: %s", symbol->Address, symbol->Name); + } + + if (used) + *used = data->used; + + free(symbol); + + return (char **)lines; #else LOGF(support_msg); return NULL; @@ -320,20 +397,17 @@ void winpr_backtrace_symbols_fd(void *buffer, int fd) t_execinfo *data = (t_execinfo *)buffer; assert(data); backtrace_symbols_fd(data->buffer, data->used, fd); -#elif defined(ANDROID) - size_t used; - t_corkscrew_data *data = (t_corkscrew_data *)buffer; - assert(data); - char **lines = winpr_backtrace_symbols(buffer, &used); +#elif defined(_WIN32) || defined(_WIN64) || defined(ANDROID) + size_t used; + char **lines = winpr_backtrace_symbols(buffer, &used); - if (lines) - { - DWORD i; - - for (i=0; i Date: Wed, 17 Sep 2014 17:30:04 +0200 Subject: [PATCH 02/10] Added unit test for backtrace. --- winpr/libwinpr/utils/test/CMakeLists.txt | 1 + winpr/libwinpr/utils/test/TestBacktrace.c | 28 +++++++++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 winpr/libwinpr/utils/test/TestBacktrace.c diff --git a/winpr/libwinpr/utils/test/CMakeLists.txt b/winpr/libwinpr/utils/test/CMakeLists.txt index 199780d9b..b7a42fbd6 100644 --- a/winpr/libwinpr/utils/test/CMakeLists.txt +++ b/winpr/libwinpr/utils/test/CMakeLists.txt @@ -7,6 +7,7 @@ set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) set(${MODULE_PREFIX}_TESTS TestIni.c TestImage.c + TestBacktrace.c TestQueue.c TestPrint.c TestPubSub.c diff --git a/winpr/libwinpr/utils/test/TestBacktrace.c b/winpr/libwinpr/utils/test/TestBacktrace.c new file mode 100644 index 000000000..f26c83bb7 --- /dev/null +++ b/winpr/libwinpr/utils/test/TestBacktrace.c @@ -0,0 +1,28 @@ + +#include + +int TestBacktrace(int argc, char* argv[]) +{ + int rc = -1; + size_t used, x; + char **msg; + void *stack = winpr_backtrace(20); + if (!stack) + { + fprintf(stderr, "winpr_backtrace failed!\n"); + return -1; + } + + msg = winpr_backtrace_symbols(stack, &used); + if (msg) + { + for (x=0; x Date: Wed, 17 Sep 2014 17:40:09 +0200 Subject: [PATCH 03/10] Fixed missing include in unit test. --- winpr/libwinpr/utils/test/TestBacktrace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winpr/libwinpr/utils/test/TestBacktrace.c b/winpr/libwinpr/utils/test/TestBacktrace.c index f26c83bb7..9d5a80b4c 100644 --- a/winpr/libwinpr/utils/test/TestBacktrace.c +++ b/winpr/libwinpr/utils/test/TestBacktrace.c @@ -1,4 +1,4 @@ - +// #include #include int TestBacktrace(int argc, char* argv[]) From 6c4f013bd97af5f771b3ad0da4e5441f7a773cbb Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 17 Sep 2014 17:59:06 +0200 Subject: [PATCH 04/10] Enhanced debug output, fixed missing includes. --- winpr/libwinpr/utils/debug.c | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/winpr/libwinpr/utils/debug.c b/winpr/libwinpr/utils/debug.c index b41a0020d..9078ca6ef 100644 --- a/winpr/libwinpr/utils/debug.c +++ b/winpr/libwinpr/utils/debug.c @@ -24,6 +24,9 @@ #include +#include +#include + #if defined(HAVE_EXECINFO_H) #include #endif @@ -33,7 +36,7 @@ #endif #if defined(_WIN32) || defined(_WIN64) -#include +#include #include #endif @@ -65,7 +68,7 @@ typedef struct { PVOID* stack; ULONG used; - ULONG size; + ULONG max; } t_win_stack; #endif @@ -256,8 +259,8 @@ void *winpr_backtrace(DWORD size) if (!data) return NULL; - data->size = size; - data->stack = calloc(data->size, sizeof(PVOID)); + data->max = size; + data->stack = calloc(data->max, sizeof(PVOID)); if (!data->stack) { free(data); @@ -350,8 +353,9 @@ char **winpr_backtrace_symbols(void *buffer, size_t *used) char *lines = calloc(data->used + 1, sizeof(char *) * line_len); char **vlines = (char **)lines; SYMBOL_INFO* symbol = calloc(sizeof(SYMBOL_INFO) + line_len * sizeof(char), 1); - - if (!lines || !symbol) + IMAGEHLP_LINE64 *line = (IMAGEHLP_LINE64 *)calloc(1, sizeof(IMAGEHLP_LINE64)); + + if (!lines || !symbol || !line) { if (lines) free(lines); @@ -359,8 +363,13 @@ char **winpr_backtrace_symbols(void *buffer, size_t *used) if (symbol) free(symbol); + if (line) + free(line); return NULL; } + line->SizeOfStruct = sizeof(IMAGEHLP_LINE64); + symbol->MaxNameLen = line_len; + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); /* To allow a char** malloced array to be returned, allocate n+1 lines * and fill in the first lines[i] char with the address of lines[(i+1) * 1024] */ @@ -369,14 +378,23 @@ char **winpr_backtrace_symbols(void *buffer, size_t *used) for (i=0; iused; i++) { - SymFromAddr(process, (DWORD64)(data->stack[i]), 0, &symbol); - _snprintf(vlines[i], line_len, "%08lX: %s", symbol->Address, symbol->Name); + DWORD64 address = (DWORD64)(data->stack[i]); + DWORD displacement; + + SymFromAddr(process, address, 0, symbol); + if (SymGetLineFromAddr64(process, address, &displacement, line)) + { + _snprintf(vlines[i], line_len, "%08lX: %s in %s:%lu", symbol->Address, symbol->Name, line->FileName, line->LineNumber); + } + else + _snprintf(vlines[i], line_len, "%08lX: %s", symbol->Address, symbol->Name); } if (used) *used = data->used; free(symbol); + free(line); return (char **)lines; #else From 56f087dfbca7ef517418f7f7bd8bb861f735c37c Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 17 Sep 2014 18:04:47 +0200 Subject: [PATCH 05/10] Fixed commented include. --- winpr/libwinpr/utils/test/TestBacktrace.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winpr/libwinpr/utils/test/TestBacktrace.c b/winpr/libwinpr/utils/test/TestBacktrace.c index 9d5a80b4c..2857f315b 100644 --- a/winpr/libwinpr/utils/test/TestBacktrace.c +++ b/winpr/libwinpr/utils/test/TestBacktrace.c @@ -1,4 +1,4 @@ -// #include +#include #include int TestBacktrace(int argc, char* argv[]) From c39fbcfacb40416659e9afa865c3f09391580322 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 17 Sep 2014 18:08:57 +0200 Subject: [PATCH 06/10] Fixed scope of variable declarations, MSVC does not like mixed variable declaration. --- winpr/libwinpr/utils/debug.c | 135 ++++++++++++++++++----------------- 1 file changed, 69 insertions(+), 66 deletions(-) diff --git a/winpr/libwinpr/utils/debug.c b/winpr/libwinpr/utils/debug.c index 9078ca6ef..e0f89d1f3 100644 --- a/winpr/libwinpr/utils/debug.c +++ b/winpr/libwinpr/utils/debug.c @@ -66,9 +66,9 @@ typedef struct #if defined(_WIN32) || defined(_WIN64) typedef struct { - PVOID* stack; - ULONG used; - ULONG max; + PVOID* stack; + ULONG used; + ULONG max; } t_win_stack; #endif @@ -209,10 +209,12 @@ void winpr_backtrace_free(void *buffer) free(data); #elif defined(_WIN32) || defined(_WIN64) - t_win_stack *data = (t_win_stack*)buffer; - if (data->stack) - free(data->stack); - free(data); + { + t_win_stack *data = (t_win_stack*)buffer; + if (data->stack) + free(data->stack); + free(data); + } #else LOGF(support_msg); #endif @@ -253,24 +255,24 @@ void *winpr_backtrace(DWORD size) data->used = fkt->unwind_backtrace(data->buffer, 0, size); return data; #elif defined(_WIN32) || defined(_WIN64) - HANDLE process = GetCurrentProcess(); - t_win_stack *data = calloc(1, sizeof(t_win_stack)); + HANDLE process = GetCurrentProcess(); + t_win_stack *data = calloc(1, sizeof(t_win_stack)); - if (!data) - return NULL; + if (!data) + return NULL; - data->max = size; - data->stack = calloc(data->max, sizeof(PVOID)); - if (!data->stack) - { - free(data); - return NULL; - } + data->max = size; + data->stack = calloc(data->max, sizeof(PVOID)); + if (!data->stack) + { + free(data); + return NULL; + } - SymInitialize( process, NULL, TRUE ); - data->used = CaptureStackBackTrace(2, size, data->stack, NULL); + SymInitialize( process, NULL, TRUE ); + data->used = CaptureStackBackTrace(2, size, data->stack, NULL); - return data; + return data; #else LOGF(support_msg); return NULL; @@ -312,7 +314,7 @@ char **winpr_backtrace_symbols(void *buffer, size_t *used) size_t i; char *lines = calloc(data->used + 1, sizeof(char *) * line_len); char **vlines = (char **)lines; - backtrace_symbol_t *symbols = calloc(data->used, sizeof(backtrace_symbol_t)); + backtrace_symbol_t *symbols = calloc(data->used, sizeof(backtrace_symbol_t)); if (!lines || !symbols) { @@ -344,59 +346,61 @@ char **winpr_backtrace_symbols(void *buffer, size_t *used) return (char **)lines; } #elif defined(_WIN32) || defined(_WIN64) - HANDLE process = GetCurrentProcess(); - t_win_stack *data = (t_win_stack *)buffer; - assert(data); - - size_t line_len = (data->max > 1024) ? data->max : 1024; - size_t i; - char *lines = calloc(data->used + 1, sizeof(char *) * line_len); - char **vlines = (char **)lines; - SYMBOL_INFO* symbol = calloc(sizeof(SYMBOL_INFO) + line_len * sizeof(char), 1); - IMAGEHLP_LINE64 *line = (IMAGEHLP_LINE64 *)calloc(1, sizeof(IMAGEHLP_LINE64)); - - if (!lines || !symbol || !line) - { - if (lines) - free(lines); + { + HANDLE process = GetCurrentProcess(); + t_win_stack *data = (t_win_stack *)buffer; + assert(data); - if (symbol) - free(symbol); + size_t line_len = (data->max > 1024) ? data->max : 1024; + size_t i; + char *lines = calloc(data->used + 1, sizeof(char *) * line_len); + char **vlines = (char **)lines; + SYMBOL_INFO* symbol = calloc(sizeof(SYMBOL_INFO) + line_len * sizeof(char), 1); + IMAGEHLP_LINE64 *line = (IMAGEHLP_LINE64 *)calloc(1, sizeof(IMAGEHLP_LINE64)); + + if (!lines || !symbol || !line) + { + if (lines) + free(lines); + + if (symbol) + free(symbol); if (line) free(line); - return NULL; - } - line->SizeOfStruct = sizeof(IMAGEHLP_LINE64); - symbol->MaxNameLen = line_len; - symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + return NULL; + } + line->SizeOfStruct = sizeof(IMAGEHLP_LINE64); + symbol->MaxNameLen = line_len; + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); - /* To allow a char** malloced array to be returned, allocate n+1 lines - * and fill in the first lines[i] char with the address of lines[(i+1) * 1024] */ - for (i=0; iused; i++) - vlines[i] = &lines[(i + 1) * line_len]; + /* To allow a char** malloced array to be returned, allocate n+1 lines + * and fill in the first lines[i] char with the address of lines[(i+1) * 1024] */ + for (i=0; iused; i++) + vlines[i] = &lines[(i + 1) * line_len]; - for (i=0; iused; i++) - { + for (i=0; iused; i++) + { DWORD64 address = (DWORD64)(data->stack[i]); DWORD displacement; - SymFromAddr(process, address, 0, symbol); + SymFromAddr(process, address, 0, symbol); if (SymGetLineFromAddr64(process, address, &displacement, line)) { _snprintf(vlines[i], line_len, "%08lX: %s in %s:%lu", symbol->Address, symbol->Name, line->FileName, line->LineNumber); } else _snprintf(vlines[i], line_len, "%08lX: %s", symbol->Address, symbol->Name); - } + } - if (used) - *used = data->used; + if (used) + *used = data->used; - free(symbol); - free(line); + free(symbol); + free(line); - return (char **)lines; + return (char **)lines; + } #else LOGF(support_msg); return NULL; @@ -416,16 +420,15 @@ void winpr_backtrace_symbols_fd(void *buffer, int fd) assert(data); backtrace_symbols_fd(data->buffer, data->used, fd); #elif defined(_WIN32) || defined(_WIN64) || defined(ANDROID) - size_t used; - char **lines = winpr_backtrace_symbols(buffer, &used); + size_t used; + char **lines = winpr_backtrace_symbols(buffer, &used); - if (lines) - { - DWORD i; - - for (i=0; i Date: Wed, 17 Sep 2014 18:15:37 +0200 Subject: [PATCH 07/10] Removed assert, breaking build on visual studio. --- winpr/libwinpr/utils/debug.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/winpr/libwinpr/utils/debug.c b/winpr/libwinpr/utils/debug.c index e0f89d1f3..7562bc6fc 100644 --- a/winpr/libwinpr/utils/debug.c +++ b/winpr/libwinpr/utils/debug.c @@ -349,8 +349,6 @@ char **winpr_backtrace_symbols(void *buffer, size_t *used) { HANDLE process = GetCurrentProcess(); t_win_stack *data = (t_win_stack *)buffer; - assert(data); - size_t line_len = (data->max > 1024) ? data->max : 1024; size_t i; char *lines = calloc(data->used + 1, sizeof(char *) * line_len); From 041c26eff6493ee865d5d583260957b97f37a61b Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 17 Sep 2014 18:21:35 +0200 Subject: [PATCH 08/10] Fixed mixed variable declaration. --- winpr/libwinpr/utils/debug.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/winpr/libwinpr/utils/debug.c b/winpr/libwinpr/utils/debug.c index 7562bc6fc..76dbcc55b 100644 --- a/winpr/libwinpr/utils/debug.c +++ b/winpr/libwinpr/utils/debug.c @@ -418,15 +418,17 @@ void winpr_backtrace_symbols_fd(void *buffer, int fd) assert(data); backtrace_symbols_fd(data->buffer, data->used, fd); #elif defined(_WIN32) || defined(_WIN64) || defined(ANDROID) - size_t used; - char **lines = winpr_backtrace_symbols(buffer, &used); + { + size_t used; + char **lines = winpr_backtrace_symbols(buffer, &used); - if (lines) - { - DWORD i; - for (i=0; i Date: Fri, 26 Sep 2014 12:11:33 +0200 Subject: [PATCH 09/10] Fixed broken cliprdr TAG definition. Added WINPR_API for backtrace functions. --- winpr/include/winpr/debug.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/winpr/include/winpr/debug.h b/winpr/include/winpr/debug.h index 1d1123a80..2d7c2d960 100644 --- a/winpr/include/winpr/debug.h +++ b/winpr/include/winpr/debug.h @@ -27,10 +27,10 @@ extern "C" { #include -void *winpr_backtrace(DWORD size); -void winpr_backtrace_free(void *buffer); -char **winpr_backtrace_symbols(void *buffer, size_t *used); -void winpr_backtrace_symbols_fd(void *buffer, int fd); +WINPR_API void *winpr_backtrace(DWORD size); +WINPR_API void winpr_backtrace_free(void *buffer); +WINPR_API char **winpr_backtrace_symbols(void *buffer, size_t *used); +WINPR_API void winpr_backtrace_symbols_fd(void *buffer, int fd); #ifdef __cplusplus } From eafc49b154e8bcf5e37f23f977a348d1b8e711a2 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Thu, 4 Dec 2014 14:54:08 +0100 Subject: [PATCH 10/10] Using fixed size debug string buffers now. --- winpr/libwinpr/utils/debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winpr/libwinpr/utils/debug.c b/winpr/libwinpr/utils/debug.c index 76dbcc55b..0a6ca69ef 100644 --- a/winpr/libwinpr/utils/debug.c +++ b/winpr/libwinpr/utils/debug.c @@ -349,7 +349,7 @@ char **winpr_backtrace_symbols(void *buffer, size_t *used) { HANDLE process = GetCurrentProcess(); t_win_stack *data = (t_win_stack *)buffer; - size_t line_len = (data->max > 1024) ? data->max : 1024; + size_t line_len = 1024; size_t i; char *lines = calloc(data->used + 1, sizeof(char *) * line_len); char **vlines = (char **)lines;