FreeRDP
debug.c
1 
21 #include <winpr/config.h>
22 #include <winpr/platform.h>
23 
24 WINPR_PRAGMA_DIAG_PUSH
25 WINPR_PRAGMA_DIAG_IGNORED_RESERVED_ID_MACRO
26 WINPR_PRAGMA_DIAG_IGNORED_UNUSED_MACRO
27 
28 #define __STDC_WANT_LIB_EXT1__ 1 // NOLINT(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp)
29 
30 WINPR_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 #ifndef MIN
60 #define MIN(a, b) (a) < (b) ? (a) : (b)
61 #endif
62 
63 #define TAG "com.winpr.utils.debug"
64 #define LOGT(...) \
65  do \
66  { \
67  WLog_Print(WLog_Get(TAG), WLOG_TRACE, __VA_ARGS__); \
68  } while (0)
69 #define LOGD(...) \
70  do \
71  { \
72  WLog_Print(WLog_Get(TAG), WLOG_DEBUG, __VA_ARGS__); \
73  } while (0)
74 #define LOGI(...) \
75  do \
76  { \
77  WLog_Print(WLog_Get(TAG), WLOG_INFO, __VA_ARGS__); \
78  } while (0)
79 #define LOGW(...) \
80  do \
81  { \
82  WLog_Print(WLog_Get(TAG), WLOG_WARN, __VA_ARGS__); \
83  } while (0)
84 #define LOGE(...) \
85  do \
86  { \
87  WLog_Print(WLog_Get(TAG), WLOG_ERROR, __VA_ARGS__); \
88  } while (0)
89 #define LOGF(...) \
90  do \
91  { \
92  WLog_Print(WLog_Get(TAG), WLOG_FATAL, __VA_ARGS__); \
93  } while (0)
94 
95 static const char* support_msg = "Invalid stacktrace buffer! check if platform is supported!";
96 
97 void winpr_backtrace_free(void* buffer)
98 {
99  if (!buffer)
100  return;
101 
102 #if defined(USE_UNWIND)
103  winpr_unwind_backtrace_free(buffer);
104 #elif defined(USE_EXECINFO)
105  winpr_execinfo_backtrace_free(buffer);
106 #elif defined(WINPR_HAVE_CORKSCREW)
107  winpr_corkscrew_backtrace_free(buffer);
108 #elif defined(_WIN32) || defined(_WIN64)
109  winpr_win_backtrace_free(buffer);
110 #else
111  free(buffer);
112  LOGF(support_msg);
113 #endif
114 }
115 
116 void* winpr_backtrace(DWORD size)
117 {
118 #if defined(USE_UNWIND)
119  return winpr_unwind_backtrace(size);
120 #elif defined(USE_EXECINFO)
121  return winpr_execinfo_backtrace(size);
122 #elif defined(WINPR_HAVE_CORKSCREW)
123  return winpr_corkscrew_backtrace(size);
124 #elif (defined(_WIN32) || defined(_WIN64)) && !defined(_UWP)
125  return winpr_win_backtrace(size);
126 #else
127  LOGF(support_msg);
128  /* return a non NULL buffer to allow the backtrace function familiy to succeed without failing
129  */
130  return _strdup(support_msg);
131 #endif
132 }
133 
134 char** winpr_backtrace_symbols(void* buffer, size_t* used)
135 {
136  if (used)
137  *used = 0;
138 
139  if (!buffer)
140  {
141  LOGF(support_msg);
142  return NULL;
143  }
144 
145 #if defined(USE_UNWIND)
146  return winpr_unwind_backtrace_symbols(buffer, used);
147 #elif defined(USE_EXECINFO)
148  return winpr_execinfo_backtrace_symbols(buffer, used);
149 #elif defined(WINPR_HAVE_CORKSCREW)
150  return winpr_corkscrew_backtrace_symbols(buffer, used);
151 #elif (defined(_WIN32) || defined(_WIN64)) && !defined(_UWP)
152  return winpr_win_backtrace_symbols(buffer, used);
153 #else
154  LOGF(support_msg);
155 
156  /* We return a char** on heap that is compatible with free:
157  *
158  * 1. We allocate sizeof(char*) + strlen + 1 bytes.
159  * 2. The first sizeof(char*) bytes contain the pointer to the string following the pointer.
160  * 3. The at data + sizeof(char*) contains the actual string
161  */
162  size_t len = strlen(support_msg);
163  char* ppmsg = calloc(sizeof(char*) + len + 1, sizeof(char));
164  if (!ppmsg)
165  return NULL;
166  char** msgptr = (char**)ppmsg;
167  char* msg = &ppmsg[sizeof(char*)];
168 
169  *msgptr = msg;
170  strncpy(msg, support_msg, len);
171  *used = 1;
172  return msgptr;
173 #endif
174 }
175 
176 void winpr_backtrace_symbols_fd(void* buffer, int fd)
177 {
178  if (!buffer)
179  {
180  LOGF(support_msg);
181  return;
182  }
183 
184 #if defined(USE_EXECINFO) && !defined(USE_UNWIND)
185  winpr_execinfo_backtrace_symbols_fd(buffer, fd);
186 #elif !defined(ANDROID)
187  {
188  size_t used = 0;
189  char** lines = winpr_backtrace_symbols(buffer, &used);
190 
191  if (!lines)
192  return;
193 
194  for (size_t i = 0; i < used; i++)
195  (void)_write(fd, lines[i], (unsigned)strnlen(lines[i], UINT32_MAX));
196  free(lines);
197  }
198 #else
199  LOGF(support_msg);
200 #endif
201 }
202 
203 void winpr_log_backtrace(const char* tag, DWORD level, DWORD size)
204 {
205  winpr_log_backtrace_ex(WLog_Get(tag), level, size);
206 }
207 
208 void winpr_log_backtrace_ex(wLog* log, DWORD level, DWORD size)
209 {
210  size_t used = 0;
211  char** msg = NULL;
212  void* stack = winpr_backtrace(20);
213 
214  if (!stack)
215  {
216  WLog_Print(log, WLOG_ERROR, "winpr_backtrace failed!\n");
217  goto fail;
218  }
219 
220  msg = winpr_backtrace_symbols(stack, &used);
221 
222  if (msg)
223  {
224  for (size_t x = 0; x < used; x++)
225  WLog_Print(log, level, "%" PRIuz ": %s", x, msg[x]);
226  }
227  free(msg);
228 
229 fail:
230  winpr_backtrace_free(stack);
231 }
232 
233 char* winpr_strerror(INT32 dw, char* dmsg, size_t size)
234 {
235 #ifdef __STDC_LIB_EXT1__
236  (void)strerror_s(dw, dmsg, size);
237 #elif defined(WINPR_HAVE_STRERROR_R)
238  (void)strerror_r(dw, dmsg, size);
239 #else
240  (void)_snprintf(dmsg, size, "%s", strerror(dw));
241 #endif
242  return dmsg;
243 }