FreeRDP
Loading...
Searching...
No Matches
debug.c
1
21#include <winpr/config.h>
22#include <winpr/platform.h>
23
24WINPR_PRAGMA_DIAG_PUSH
25WINPR_PRAGMA_DIAG_IGNORED_RESERVED_ID_MACRO
26WINPR_PRAGMA_DIAG_IGNORED_UNUSED_MACRO
27
28#define __STDC_WANT_LIB_EXT1__ 1 // NOLINT(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
29
30WINPR_PRAGMA_DIAG_POP
31
32#include <stdio.h>
33#include <string.h>
34#include <fcntl.h>
35
36#include <winpr/crt.h>
37#include <winpr/string.h>
38
39#if defined(USE_EXECINFO)
40#include <execinfo/debug.h>
41#endif
42
43#if defined(USE_UNWIND)
44#include <unwind/debug.h>
45#endif
46
47#if defined(WINPR_HAVE_CORKSCREW)
48#include <corkscrew/debug.h>
49#endif
50
51#if defined(_WIN32) || defined(_WIN64)
52#include <io.h>
53#include <windows/debug.h>
54#endif
55
56#include <winpr/wlog.h>
57#include <winpr/debug.h>
58
59#define TAG "com.winpr.utils.debug"
60
61#define LINE_LENGTH_MAX 2048
62
63static const char support_msg[] = "Invalid stacktrace buffer! check if platform is supported!";
64
65void winpr_backtrace_free(void* buffer)
66{
67 if (!buffer)
68 return;
69
70#if defined(USE_UNWIND)
71 winpr_unwind_backtrace_free(buffer);
72#elif defined(USE_EXECINFO)
73 winpr_execinfo_backtrace_free(buffer);
74#elif defined(WINPR_HAVE_CORKSCREW)
75 winpr_corkscrew_backtrace_free(buffer);
76#elif defined(_WIN32) || defined(_WIN64)
77 winpr_win_backtrace_free(buffer);
78#else
79 free(buffer);
80 WLog_FATAL(TAG, "%s", support_msg);
81#endif
82}
83
84void* winpr_backtrace(DWORD size)
85{
86#if defined(USE_UNWIND)
87 return winpr_unwind_backtrace(size);
88#elif defined(USE_EXECINFO)
89 return winpr_execinfo_backtrace(size);
90#elif defined(WINPR_HAVE_CORKSCREW)
91 return winpr_corkscrew_backtrace(size);
92#elif (defined(_WIN32) || defined(_WIN64)) && !defined(_UWP)
93 return winpr_win_backtrace(size);
94#else
95 WLog_FATAL(TAG, "%s", support_msg);
96 /* return a non NULL buffer to allow the backtrace function family to succeed without failing
97 */
98 return strndup(support_msg, sizeof(support_msg));
99#endif
100}
101
102char** winpr_backtrace_symbols(void* buffer, size_t* used)
103{
104 if (used)
105 *used = 0;
106
107 if (!buffer)
108 {
109 WLog_FATAL(TAG, "%s", support_msg);
110 return NULL;
111 }
112
113#if defined(USE_UNWIND)
114 return winpr_unwind_backtrace_symbols(buffer, used);
115#elif defined(USE_EXECINFO)
116 return winpr_execinfo_backtrace_symbols(buffer, used);
117#elif defined(WINPR_HAVE_CORKSCREW)
118 return winpr_corkscrew_backtrace_symbols(buffer, used);
119#elif (defined(_WIN32) || defined(_WIN64)) && !defined(_UWP)
120 return winpr_win_backtrace_symbols(buffer, used);
121#else
122 WLog_FATAL(TAG, "%s", support_msg);
123
124 /* We return a char** on heap that is compatible with free:
125 *
126 * 1. We allocate sizeof(char*) + strlen + 1 bytes.
127 * 2. The first sizeof(char*) bytes contain the pointer to the string following the pointer.
128 * 3. The at data + sizeof(char*) contains the actual string
129 */
130 size_t len = strnlen(support_msg, sizeof(support_msg));
131 char* ppmsg = calloc(sizeof(char*) + len + 1, sizeof(char));
132 if (!ppmsg)
133 return NULL;
134 char** msgptr = (char**)ppmsg;
135 char* msg = &ppmsg[sizeof(char*)];
136
137 *msgptr = msg;
138 strncpy(msg, support_msg, len);
139 *used = 1;
140 return msgptr;
141#endif
142}
143
144void winpr_backtrace_symbols_fd(void* buffer, int fd)
145{
146 if (!buffer)
147 {
148 WLog_FATAL(TAG, "%s", support_msg);
149 return;
150 }
151
152#if defined(USE_EXECINFO) && !defined(USE_UNWIND)
153 winpr_execinfo_backtrace_symbols_fd(buffer, fd);
154#elif !defined(ANDROID)
155 {
156 size_t used = 0;
157 char** lines = winpr_backtrace_symbols(buffer, &used);
158
159 if (!lines)
160 return;
161
162 for (size_t i = 0; i < used; i++)
163 (void)_write(fd, lines[i], (unsigned)strnlen(lines[i], LINE_LENGTH_MAX));
164 free((void*)lines);
165 }
166#else
167 WLog_FATAL(TAG, "%s", support_msg);
168#endif
169}
170
171void winpr_log_backtrace(const char* tag, DWORD level, DWORD size)
172{
173 winpr_log_backtrace_ex(WLog_Get(tag), level, size);
174}
175
176void winpr_log_backtrace_ex(wLog* log, DWORD level, WINPR_ATTR_UNUSED DWORD size)
177{
178 size_t used = 0;
179 char** msg = NULL;
180 void* stack = winpr_backtrace(20);
181
182 if (!stack)
183 {
184 WLog_Print(log, WLOG_ERROR, "winpr_backtrace failed!\n");
185 goto fail;
186 }
187
188 msg = winpr_backtrace_symbols(stack, &used);
189
190 if (msg)
191 {
192 for (size_t x = 0; x < used; x++)
193 WLog_Print(log, level, "%" PRIuz ": %s", x, msg[x]);
194 }
195 free((void*)msg);
196
197fail:
198 winpr_backtrace_free(stack);
199}
200
201char* winpr_strerror(INT32 dw, char* dmsg, size_t size)
202{
203#ifdef __STDC_LIB_EXT1__
204 (void)strerror_s(dw, dmsg, size);
205#elif defined(WINPR_HAVE_STRERROR_R)
206 (void)strerror_r(dw, dmsg, size);
207#else
208 (void)_snprintf(dmsg, size, "%s", strerror(dw));
209#endif
210 return dmsg;
211}