Blame winpr/libwinpr/utils/debug.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * WinPR: Windows Portable Runtime
Packit 1fb8d4
 * Debugging Utils
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2014 Armin Novak <armin.novak@thincast.com>
Packit 1fb8d4
 * Copyright 2014 Thincast Technologies GmbH
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <stdio.h>
Packit 1fb8d4
#include <fcntl.h>
Packit 1fb8d4
#include <winpr/string.h>
Packit 1fb8d4
Packit 1fb8d4
#if defined(HAVE_EXECINFO_H)
Packit 1fb8d4
#include <execinfo.h>
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#if defined(ANDROID)
Packit 1fb8d4
#include <corkscrew/backtrace.h>
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#if defined(_WIN32) || defined(_WIN64)
Packit 1fb8d4
#include <io.h>
Packit Service 5a9772
#include <windows.h>
Packit Service 5a9772
#include <dbghelp.h>
Packit 1fb8d4
#define write _write
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
#include <winpr/wlog.h>
Packit 1fb8d4
#include <winpr/debug.h>
Packit 1fb8d4
Packit 1fb8d4
#define TAG "com.winpr.utils.debug"
Packit Service 5a9772
#define LOGT(...)                                           \
Packit Service 5a9772
	do                                                      \
Packit Service 5a9772
	{                                                       \
Packit Service 5a9772
		WLog_Print(WLog_Get(TAG), WLOG_TRACE, __VA_ARGS__); \
Packit Service 5a9772
	} while (0)
Packit Service 5a9772
#define LOGD(...)                                           \
Packit Service 5a9772
	do                                                      \
Packit Service 5a9772
	{                                                       \
Packit Service 5a9772
		WLog_Print(WLog_Get(TAG), WLOG_DEBUG, __VA_ARGS__); \
Packit Service 5a9772
	} while (0)
Packit Service 5a9772
#define LOGI(...)                                          \
Packit Service 5a9772
	do                                                     \
Packit Service 5a9772
	{                                                      \
Packit Service 5a9772
		WLog_Print(WLog_Get(TAG), WLOG_INFO, __VA_ARGS__); \
Packit Service 5a9772
	} while (0)
Packit Service 5a9772
#define LOGW(...)                                          \
Packit Service 5a9772
	do                                                     \
Packit Service 5a9772
	{                                                      \
Packit Service 5a9772
		WLog_Print(WLog_Get(TAG), WLOG_WARN, __VA_ARGS__); \
Packit Service 5a9772
	} while (0)
Packit Service 5a9772
#define LOGE(...)                                           \
Packit Service 5a9772
	do                                                      \
Packit Service 5a9772
	{                                                       \
Packit Service 5a9772
		WLog_Print(WLog_Get(TAG), WLOG_ERROR, __VA_ARGS__); \
Packit Service 5a9772
	} while (0)
Packit Service 5a9772
#define LOGF(...)                                           \
Packit Service 5a9772
	do                                                      \
Packit Service 5a9772
	{                                                       \
Packit Service 5a9772
		WLog_Print(WLog_Get(TAG), WLOG_FATAL, __VA_ARGS__); \
Packit Service 5a9772
	} while (0)
Packit Service 5a9772
Packit Service 5a9772
static const char* support_msg = "Invalid stacktrace buffer! check if platform is supported!";
Packit 1fb8d4
Packit 1fb8d4
#if defined(HAVE_EXECINFO_H)
Packit 1fb8d4
typedef struct
Packit 1fb8d4
{
Packit Service 5a9772
	void** buffer;
Packit 1fb8d4
	size_t max;
Packit 1fb8d4
	size_t used;
Packit 1fb8d4
} t_execinfo;
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#if defined(_WIN32) || defined(_WIN64)
Packit 1fb8d4
typedef struct
Packit 1fb8d4
{
Packit Service 5a9772
	PVOID* stack;
Packit Service 5a9772
	ULONG used;
Packit Service 5a9772
	ULONG max;
Packit 1fb8d4
} t_win_stack;
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#if defined(ANDROID)
Packit 1fb8d4
#include <pthread.h>
Packit 1fb8d4
#include <dlfcn.h>
Packit 1fb8d4
#include <unistd.h>
Packit 1fb8d4
Packit 1fb8d4
typedef struct
Packit 1fb8d4
{
Packit Service 5a9772
	backtrace_frame_t* buffer;
Packit 1fb8d4
	size_t max;
Packit 1fb8d4
	size_t used;
Packit 1fb8d4
} t_corkscrew_data;
Packit 1fb8d4
Packit 1fb8d4
typedef struct
Packit 1fb8d4
{
Packit Service 5a9772
	void* hdl;
Packit Service 5a9772
	ssize_t (*unwind_backtrace)(backtrace_frame_t* backtrace, size_t ignore_depth,
Packit Service 5a9772
	                            size_t max_depth);
Packit Service 5a9772
	ssize_t (*unwind_backtrace_thread)(pid_t tid, backtrace_frame_t* backtrace, size_t ignore_depth,
Packit Service 5a9772
	                                   size_t max_depth);
Packit Service 5a9772
	ssize_t (*unwind_backtrace_ptrace)(pid_t tid, const ptrace_context_t* context,
Packit Service 5a9772
	                                   backtrace_frame_t* backtrace, size_t ignore_depth,
Packit Service 5a9772
	                                   size_t max_depth);
Packit Service 5a9772
	void (*get_backtrace_symbols)(const backtrace_frame_t* backtrace, size_t frames,
Packit Service 5a9772
	                              backtrace_symbol_t* backtrace_symbols);
Packit Service 5a9772
	void (*get_backtrace_symbols_ptrace)(const ptrace_context_t* context,
Packit Service 5a9772
	                                     const backtrace_frame_t* backtrace, size_t frames,
Packit Service 5a9772
	                                     backtrace_symbol_t* backtrace_symbols);
Packit Service 5a9772
	void (*free_backtrace_symbols)(backtrace_symbol_t* backtrace_symbols, size_t frames);
Packit Service 5a9772
	void (*format_backtrace_line)(unsigned frameNumber, const backtrace_frame_t* frame,
Packit Service 5a9772
	                              const backtrace_symbol_t* symbol, char* buffer,
Packit Service 5a9772
	                              size_t bufferSize);
Packit 1fb8d4
} t_corkscrew;
Packit 1fb8d4
Packit 1fb8d4
static pthread_once_t initialized = PTHREAD_ONCE_INIT;
Packit Service 5a9772
static t_corkscrew* fkt = NULL;
Packit 1fb8d4
Packit 1fb8d4
void load_library(void)
Packit 1fb8d4
{
Packit 1fb8d4
	static t_corkscrew lib;
Packit 1fb8d4
	{
Packit 1fb8d4
		lib.hdl = dlopen("libcorkscrew.so", RTLD_LAZY);
Packit 1fb8d4
Packit 1fb8d4
		if (!lib.hdl)
Packit 1fb8d4
		{
Packit 1fb8d4
			LOGF("dlopen error %s", dlerror());
Packit 1fb8d4
			goto fail;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		lib.unwind_backtrace = dlsym(lib.hdl, "unwind_backtrace");
Packit 1fb8d4
Packit 1fb8d4
		if (!lib.unwind_backtrace)
Packit 1fb8d4
		{
Packit 1fb8d4
			LOGF("dlsym error %s", dlerror());
Packit 1fb8d4
			goto fail;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		lib.unwind_backtrace_thread = dlsym(lib.hdl, "unwind_backtrace_thread");
Packit 1fb8d4
Packit 1fb8d4
		if (!lib.unwind_backtrace_thread)
Packit 1fb8d4
		{
Packit 1fb8d4
			LOGF("dlsym error %s", dlerror());
Packit 1fb8d4
			goto fail;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		lib.unwind_backtrace_ptrace = dlsym(lib.hdl, "unwind_backtrace_ptrace");
Packit 1fb8d4
Packit 1fb8d4
		if (!lib.unwind_backtrace_ptrace)
Packit 1fb8d4
		{
Packit 1fb8d4
			LOGF("dlsym error %s", dlerror());
Packit 1fb8d4
			goto fail;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		lib.get_backtrace_symbols = dlsym(lib.hdl, "get_backtrace_symbols");
Packit 1fb8d4
Packit 1fb8d4
		if (!lib.get_backtrace_symbols)
Packit 1fb8d4
		{
Packit 1fb8d4
			LOGF("dlsym error %s", dlerror());
Packit 1fb8d4
			goto fail;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		lib.get_backtrace_symbols_ptrace = dlsym(lib.hdl, "get_backtrace_symbols_ptrace");
Packit 1fb8d4
Packit 1fb8d4
		if (!lib.get_backtrace_symbols_ptrace)
Packit 1fb8d4
		{
Packit 1fb8d4
			LOGF("dlsym error %s", dlerror());
Packit 1fb8d4
			goto fail;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		lib.free_backtrace_symbols = dlsym(lib.hdl, "free_backtrace_symbols");
Packit 1fb8d4
Packit 1fb8d4
		if (!lib.free_backtrace_symbols)
Packit 1fb8d4
		{
Packit 1fb8d4
			LOGF("dlsym error %s", dlerror());
Packit 1fb8d4
			goto fail;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		lib.format_backtrace_line = dlsym(lib.hdl, "format_backtrace_line");
Packit 1fb8d4
Packit 1fb8d4
		if (!lib.format_backtrace_line)
Packit 1fb8d4
		{
Packit 1fb8d4
			LOGF("dlsym error %s", dlerror());
Packit 1fb8d4
			goto fail;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		fkt = &li;;
Packit 1fb8d4
		return;
Packit 1fb8d4
	}
Packit 1fb8d4
fail:
Packit Service 5a9772
{
Packit Service 5a9772
	if (lib.hdl)
Packit Service 5a9772
		dlclose(lib.hdl);
Packit 1fb8d4
Packit Service 5a9772
	fkt = NULL;
Packit Service 5a9772
}
Packit 1fb8d4
}
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#if defined(_WIN32) && (NTDDI_VERSION <= NTDDI_WINXP)
Packit 1fb8d4
Packit Service 5a9772
typedef USHORT(WINAPI* PRTL_CAPTURE_STACK_BACK_TRACE_FN)(ULONG FramesToSkip, ULONG FramesToCapture,
Packit Service 5a9772
                                                         PVOID* BackTrace, PULONG BackTraceHash);
Packit 1fb8d4
Packit 1fb8d4
static HMODULE g_NTDLL_Library = NULL;
Packit 1fb8d4
static BOOL g_RtlCaptureStackBackTrace_Detected = FALSE;
Packit 1fb8d4
static BOOL g_RtlCaptureStackBackTrace_Available = FALSE;
Packit 1fb8d4
static PRTL_CAPTURE_STACK_BACK_TRACE_FN g_pRtlCaptureStackBackTrace = NULL;
Packit 1fb8d4
Packit Service 5a9772
USHORT RtlCaptureStackBackTrace(ULONG FramesToSkip, ULONG FramesToCapture, PVOID* BackTrace,
Packit Service 5a9772
                                PULONG BackTraceHash)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!g_RtlCaptureStackBackTrace_Detected)
Packit 1fb8d4
	{
Packit 1fb8d4
		g_NTDLL_Library = LoadLibraryA("kernel32.dll");
Packit 1fb8d4
Packit 1fb8d4
		if (g_NTDLL_Library)
Packit 1fb8d4
		{
Packit Service 5a9772
			g_pRtlCaptureStackBackTrace = (PRTL_CAPTURE_STACK_BACK_TRACE_FN)GetProcAddress(
Packit Service 5a9772
			    g_NTDLL_Library, "RtlCaptureStackBackTrace");
Packit 1fb8d4
			g_RtlCaptureStackBackTrace_Available = (g_pRtlCaptureStackBackTrace) ? TRUE : FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			g_RtlCaptureStackBackTrace_Available = FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		g_RtlCaptureStackBackTrace_Detected = TRUE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (g_RtlCaptureStackBackTrace_Available)
Packit 1fb8d4
	{
Packit Service 5a9772
		return (*g_pRtlCaptureStackBackTrace)(FramesToSkip, FramesToCapture, BackTrace,
Packit Service 5a9772
		                                      BackTraceHash);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
void winpr_backtrace_free(void* buffer)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!buffer)
Packit 1fb8d4
	{
Packit 1fb8d4
		LOGF(support_msg);
Packit 1fb8d4
		return;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
#if defined(HAVE_EXECINFO_H)
Packit Service 5a9772
	t_execinfo* data = (t_execinfo*)buffer;
Packit 1fb8d4
	free(data->buffer);
Packit 1fb8d4
	free(data);
Packit 1fb8d4
#elif defined(ANDROID)
Packit Service 5a9772
	t_corkscrew_data* data = (t_corkscrew_data*)buffer;
Packit 1fb8d4
	free(data->buffer);
Packit 1fb8d4
	free(data);
Packit 1fb8d4
#elif defined(_WIN32) || defined(_WIN64)
Packit 1fb8d4
	{
Packit Service 5a9772
		t_win_stack* data = (t_win_stack*)buffer;
Packit 1fb8d4
		free(data->stack);
Packit 1fb8d4
		free(data);
Packit 1fb8d4
	}
Packit 1fb8d4
#else
Packit 1fb8d4
	LOGF(support_msg);
Packit 1fb8d4
#endif
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void* winpr_backtrace(DWORD size)
Packit 1fb8d4
{
Packit 1fb8d4
#if defined(HAVE_EXECINFO_H)
Packit 1fb8d4
	t_execinfo* data = calloc(1, sizeof(t_execinfo));
Packit 1fb8d4
Packit 1fb8d4
	if (!data)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	data->buffer = calloc(size, sizeof(void*));
Packit 1fb8d4
Packit 1fb8d4
	if (!data->buffer)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(data);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	data->max = size;
Packit 1fb8d4
	data->used = backtrace(data->buffer, size);
Packit 1fb8d4
	return data;
Packit 1fb8d4
#elif defined(ANDROID)
Packit 1fb8d4
	t_corkscrew_data* data = calloc(1, sizeof(t_corkscrew_data));
Packit 1fb8d4
Packit 1fb8d4
	if (!data)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	data->buffer = calloc(size, sizeof(backtrace_frame_t));
Packit 1fb8d4
Packit 1fb8d4
	if (!data->buffer)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(data);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	pthread_once(&initialized, load_library);
Packit 1fb8d4
	data->max = size;
Packit 1fb8d4
	data->used = fkt->unwind_backtrace(data->buffer, 0, size);
Packit 1fb8d4
	return data;
Packit 1fb8d4
#elif (defined(_WIN32) || defined(_WIN64)) && !defined(_UWP)
Packit 1fb8d4
	HANDLE process = GetCurrentProcess();
Packit 1fb8d4
	t_win_stack* data = calloc(1, sizeof(t_win_stack));
Packit 1fb8d4
Packit 1fb8d4
	if (!data)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	data->max = size;
Packit 1fb8d4
	data->stack = calloc(data->max, sizeof(PVOID));
Packit 1fb8d4
Packit 1fb8d4
	if (!data->stack)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(data);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	SymInitialize(process, NULL, TRUE);
Packit 1fb8d4
	data->used = RtlCaptureStackBackTrace(2, size, data->stack, NULL);
Packit 1fb8d4
	return data;
Packit 1fb8d4
#else
Packit 1fb8d4
	LOGF(support_msg);
Packit 1fb8d4
	return NULL;
Packit 1fb8d4
#endif
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
char** winpr_backtrace_symbols(void* buffer, size_t* used)
Packit 1fb8d4
{
Packit 1fb8d4
	if (used)
Packit 1fb8d4
		*used = 0;
Packit 1fb8d4
Packit 1fb8d4
	if (!buffer)
Packit 1fb8d4
	{
Packit 1fb8d4
		LOGF(support_msg);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
#if defined(HAVE_EXECINFO_H)
Packit Service 5a9772
	t_execinfo* data = (t_execinfo*)buffer;
Packit 1fb8d4
Packit 1fb8d4
	if (!data)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (used)
Packit 1fb8d4
		*used = data->used;
Packit 1fb8d4
Packit 1fb8d4
	return backtrace_symbols(data->buffer, data->used);
Packit 1fb8d4
#elif defined(ANDROID)
Packit Service 5a9772
	t_corkscrew_data* data = (t_corkscrew_data*)buffer;
Packit 1fb8d4
Packit 1fb8d4
	if (!data)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	pthread_once(&initialized, load_library);
Packit 1fb8d4
Packit 1fb8d4
	if (!fkt)
Packit 1fb8d4
	{
Packit 1fb8d4
		LOGF(support_msg);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		size_t line_len = (data->max > 1024) ? data->max : 1024;
Packit 1fb8d4
		size_t i;
Packit 1fb8d4
		size_t array_size = data->used * sizeof(char*);
Packit 1fb8d4
		size_t lines_size = data->used * line_len;
Packit Service 5a9772
		char** vlines = calloc(1, array_size + lines_size);
Packit 1fb8d4
		backtrace_symbol_t* symbols = calloc(data->used, sizeof(backtrace_symbol_t));
Packit 1fb8d4
Packit 1fb8d4
		if (!vlines || !symbols)
Packit 1fb8d4
		{
Packit 1fb8d4
			free(vlines);
Packit 1fb8d4
			free(symbols);
Packit 1fb8d4
			return NULL;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		/* Set the pointers in the allocated buffer's initial array section */
Packit 1fb8d4
		for (i = 0; i < data->used; i++)
Packit 1fb8d4
			vlines[i] = (char*)vlines + array_size + i * line_len;
Packit 1fb8d4
Packit 1fb8d4
		fkt->get_backtrace_symbols(data->buffer, data->used, symbols);
Packit 1fb8d4
Packit Service 5a9772
		for (i = 0; i < data->used; i++)
Packit 1fb8d4
			fkt->format_backtrace_line(i, &data->buffer[i], &symbols[i], vlines[i], line_len);
Packit 1fb8d4
Packit 1fb8d4
		fkt->free_backtrace_symbols(symbols, data->used);
Packit 1fb8d4
		free(symbols);
Packit 1fb8d4
Packit 1fb8d4
		if (used)
Packit 1fb8d4
			*used = data->used;
Packit 1fb8d4
Packit 1fb8d4
		return vlines;
Packit 1fb8d4
	}
Packit Service 5a9772
Packit 1fb8d4
#elif (defined(_WIN32) || defined(_WIN64)) && !defined(_UWP)
Packit 1fb8d4
	{
Packit 1fb8d4
		size_t i;
Packit 1fb8d4
		size_t line_len = 1024;
Packit 1fb8d4
		HANDLE process = GetCurrentProcess();
Packit Service 5a9772
		t_win_stack* data = (t_win_stack*)buffer;
Packit 1fb8d4
		size_t array_size = data->used * sizeof(char*);
Packit 1fb8d4
		size_t lines_size = data->used * line_len;
Packit Service 5a9772
		char** vlines = calloc(1, array_size + lines_size);
Packit 1fb8d4
		SYMBOL_INFO* symbol = calloc(1, sizeof(SYMBOL_INFO) + line_len * sizeof(char));
Packit Service 5a9772
		IMAGEHLP_LINE64* line = (IMAGEHLP_LINE64*)calloc(1, sizeof(IMAGEHLP_LINE64));
Packit 1fb8d4
Packit 1fb8d4
		if (!vlines || !symbol || !line)
Packit 1fb8d4
		{
Packit Service 5a9772
			free(vlines);
Packit Service 5a9772
			free(symbol);
Packit Service 5a9772
			free(line);
Packit Service 5a9772
			return NULL;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		line->SizeOfStruct = sizeof(IMAGEHLP_LINE64);
Packit 1fb8d4
		symbol->MaxNameLen = line_len;
Packit 1fb8d4
		symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
Packit 1fb8d4
Packit 1fb8d4
		/* Set the pointers in the allocated buffer's initial array section */
Packit 1fb8d4
		for (i = 0; i < data->used; i++)
Packit 1fb8d4
			vlines[i] = (char*)vlines + array_size + i * line_len;
Packit 1fb8d4
Packit 1fb8d4
		for (i = 0; i < data->used; i++)
Packit 1fb8d4
		{
Packit 1fb8d4
			DWORD64 address = (DWORD64)(data->stack[i]);
Packit 1fb8d4
			DWORD displacement;
Packit 1fb8d4
			SymFromAddr(process, address, 0, symbol);
Packit 1fb8d4
Packit 1fb8d4
			if (SymGetLineFromAddr64(process, address, &displacement, line))
Packit 1fb8d4
			{
Packit Service 5a9772
				sprintf_s(vlines[i], line_len, "%016" PRIx64 ": %s in %s:%" PRIu32, symbol->Address,
Packit Service 5a9772
				          symbol->Name, line->FileName, line->LineNumber);
Packit 1fb8d4
			}
Packit 1fb8d4
			else
Packit Service 5a9772
				sprintf_s(vlines[i], line_len, "%016" PRIx64 ": %s", symbol->Address, symbol->Name);
Packit Service 5a9772
		}
Packit 1fb8d4
Packit Service 5a9772
		if (used)
Packit Service 5a9772
			*used = data->used;
Packit 1fb8d4
Packit Service 5a9772
		free(symbol);
Packit Service 5a9772
		free(line);
Packit Service 5a9772
		return vlines;
Packit 1fb8d4
	}
Packit 1fb8d4
#else
Packit 1fb8d4
	LOGF(support_msg);
Packit 1fb8d4
	return NULL;
Packit 1fb8d4
#endif
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void winpr_backtrace_symbols_fd(void* buffer, int fd)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!buffer)
Packit 1fb8d4
	{
Packit 1fb8d4
		LOGF(support_msg);
Packit 1fb8d4
		return;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
#if defined(HAVE_EXECINFO_H)
Packit Service 5a9772
	t_execinfo* data = (t_execinfo*)buffer;
Packit 1fb8d4
Packit 1fb8d4
	if (!data)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	backtrace_symbols_fd(data->buffer, data->used, fd);
Packit 1fb8d4
#elif defined(_WIN32) || defined(_WIN64) || defined(ANDROID)
Packit 1fb8d4
	{
Packit 1fb8d4
		DWORD i;
Packit 1fb8d4
		size_t used;
Packit 1fb8d4
		char** lines;
Packit 1fb8d4
		lines = winpr_backtrace_symbols(buffer, &used);
Packit 1fb8d4
Packit 1fb8d4
		if (lines)
Packit 1fb8d4
		{
Packit 1fb8d4
			for (i = 0; i < used; i++)
Packit 1fb8d4
				write(fd, lines[i], strlen(lines[i]));
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
#else
Packit 1fb8d4
	LOGF(support_msg);
Packit 1fb8d4
#endif
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void winpr_log_backtrace(const char* tag, DWORD level, DWORD size)
Packit 1fb8d4
{
Packit Service 5a9772
	winpr_log_backtrace_ex(WLog_Get(tag), level, size);
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
void winpr_log_backtrace_ex(wLog* log, DWORD level, DWORD size)
Packit Service 5a9772
{
Packit 1fb8d4
	size_t used, x;
Packit Service 5a9772
	char** msg;
Packit Service 5a9772
	void* stack = winpr_backtrace(20);
Packit 1fb8d4
Packit 1fb8d4
	if (!stack)
Packit 1fb8d4
	{
Packit Service 5a9772
		WLog_Print(log, WLOG_ERROR, "winpr_backtrace failed!\n");
Packit 1fb8d4
		winpr_backtrace_free(stack);
Packit 1fb8d4
		return;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	msg = winpr_backtrace_symbols(stack, &used);
Packit Service 5a9772
Packit 1fb8d4
	if (msg)
Packit 1fb8d4
	{
Packit Service 5a9772
		for (x = 0; x < used; x++)
Packit Service 5a9772
			WLog_Print(log, level, "%" PRIuz ": %s\n", x, msg[x]);
Packit 1fb8d4
	}
Packit Service 5a9772
Packit 1fb8d4
	winpr_backtrace_free(stack);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
char* winpr_strerror(DWORD dw, char* dmsg, size_t size)
Packit 1fb8d4
{
Packit 1fb8d4
#if defined(_WIN32)
Packit 1fb8d4
	DWORD rc;
Packit 1fb8d4
	DWORD nSize = 0;
Packit 1fb8d4
	DWORD dwFlags = 0;
Packit 1fb8d4
	LPTSTR msg = NULL;
Packit 1fb8d4
	BOOL alloc = FALSE;
Packit 1fb8d4
	dwFlags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
Packit 1fb8d4
#ifdef FORMAT_MESSAGE_ALLOCATE_BUFFER
Packit 1fb8d4
	alloc = TRUE;
Packit 1fb8d4
	dwFlags |= FORMAT_MESSAGE_ALLOCATE_BUFFER;
Packit 1fb8d4
#else
Packit Service 5a9772
	nSize = (DWORD)(size * 2);
Packit Service 5a9772
	msg = (LPTSTR)calloc(nSize, sizeof(TCHAR));
Packit 1fb8d4
#endif
Packit Service 5a9772
	rc = FormatMessage(dwFlags, NULL, dw, 0, alloc ? (LPTSTR)&msg : msg, nSize, NULL);
Packit 1fb8d4
Packit Service 5a9772
	if (rc)
Packit Service 5a9772
	{
Packit 1fb8d4
#if defined(UNICODE)
Packit 1fb8d4
		WideCharToMultiByte(CP_ACP, 0, msg, rc, dmsg, size - 1, NULL, NULL);
Packit Service 5a9772
#else  /* defined(UNICODE) */
Packit 1fb8d4
		memcpy(dmsg, msg, min(rc, size - 1));
Packit 1fb8d4
#endif /* defined(UNICODE) */
Packit 1fb8d4
		dmsg[min(rc, size - 1)] = 0;
Packit 1fb8d4
#ifdef FORMAT_MESSAGE_ALLOCATE_BUFFER
Packit 1fb8d4
		LocalFree(msg);
Packit 1fb8d4
#else
Packit 1fb8d4
		free(msg);
Packit 1fb8d4
#endif
Packit 1fb8d4
	}
Packit Service 5a9772
	else
Packit Service 5a9772
	{
Packit Service 5a9772
		_snprintf(dmsg, size, "FAILURE: 0x%08" PRIX32 "", GetLastError());
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
#else  /* defined(_WIN32) */
Packit 1fb8d4
	_snprintf(dmsg, size, "%s", strerror(dw));
Packit 1fb8d4
#endif /* defined(_WIN32) */
Packit 1fb8d4
	return dmsg;
Packit 1fb8d4
}