Merge pull request #2110 from akallabeth/winpr_backtrace_windows

Winpr backtrace windows
This commit is contained in:
Martin Fleisz 2014-12-04 15:03:37 +01:00
commit 441632310a
5 changed files with 146 additions and 18 deletions

View File

@ -27,10 +27,10 @@ extern "C" {
#include <winpr/wtypes.h>
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
}

View File

@ -113,6 +113,10 @@ if(UNIX)
winpr_library_add(m)
endif()
if(WIN32)
winpr_library_add(Dbghelp)
endif()
if(BUILD_TESTING)
add_subdirectory(test)
endif()

View File

@ -24,6 +24,9 @@
#include <assert.h>
#include <stdio.h>
#include <fcntl.h>
#if defined(HAVE_EXECINFO_H)
#include <execinfo.h>
#endif
@ -32,6 +35,11 @@
#include <corkscrew/backtrace.h>
#endif
#if defined(_WIN32) || defined(_WIN64)
#include <Windows.h>
#include <Dbghelp.h>
#endif
#include <winpr/crt.h>
#include <winpr/wlog.h>
#include <winpr/debug.h>
@ -55,6 +63,15 @@ typedef struct
} t_execinfo;
#endif
#if defined(_WIN32) || defined(_WIN64)
typedef struct
{
PVOID* stack;
ULONG used;
ULONG max;
} t_win_stack;
#endif
#if defined(ANDROID)
#include <pthread.h>
#include <dlfcn.h>
@ -191,6 +208,13 @@ 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
@ -232,6 +256,25 @@ void *winpr_backtrace(DWORD size)
pthread_once(&initialized, load_library);
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->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);
return data;
#else
LOGF(support_msg);
@ -274,7 +317,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)
{
@ -298,13 +341,67 @@ 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;
size_t line_len = 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);
/* 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; i<data->used; i++)
vlines[i] = &lines[(i + 1) * line_len];
for (i=0; i<data->used; i++)
{
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
LOGF(support_msg);
return NULL;
@ -323,20 +420,18 @@ 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)
#elif defined(_WIN32) || defined(_WIN64) || defined(ANDROID)
{
size_t used;
t_corkscrew_data *data = (t_corkscrew_data *)buffer;
assert(data);
char **lines = winpr_backtrace_symbols(buffer, &used);
if (lines)
{
DWORD i;
for (i=0; i<used; i++)
write(fd, lines[i], strlen(lines[i]));
}
}
#else
LOGF(support_msg);
#endif

View File

@ -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

View File

@ -0,0 +1,28 @@
#include <stdio.h>
#include <winpr/debug.h>
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<used; x++)
printf("%zd: %s\n", x, msg[x]);
rc = 0;
}
winpr_backtrace_symbols_fd(stack, stdout);
winpr_backtrace_free(stack);
return rc;
}