Coverage Report

Created: 2024-05-20 06:11

/src/FreeRDP/winpr/libwinpr/utils/debug.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * WinPR: Windows Portable Runtime
3
 * Debugging Utils
4
 *
5
 * Copyright 2014 Armin Novak <armin.novak@thincast.com>
6
 * Copyright 2014 Thincast Technologies GmbH
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *     http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20
21
#include <winpr/config.h>
22
23
#define __STDC_WANT_LIB_EXT1__ 1
24
#include <stdio.h>
25
#include <string.h>
26
#include <fcntl.h>
27
28
#include <winpr/crt.h>
29
#include <winpr/string.h>
30
31
#if defined(USE_EXECINFO)
32
#include <execinfo/debug.h>
33
#endif
34
35
#if defined(USE_UNWIND)
36
#include <unwind/debug.h>
37
#endif
38
39
#if defined(WINPR_HAVE_CORKSCREW)
40
#include <corkscrew/debug.h>
41
#endif
42
43
#if defined(_WIN32) || defined(_WIN64)
44
#include <io.h>
45
#include <windows/debug.h>
46
#endif
47
48
#include <winpr/wlog.h>
49
#include <winpr/debug.h>
50
51
#ifndef MIN
52
#define MIN(a, b) (a) < (b) ? (a) : (b)
53
#endif
54
55
#define TAG "com.winpr.utils.debug"
56
#define LOGT(...)                                           \
57
  do                                                      \
58
  {                                                       \
59
    WLog_Print(WLog_Get(TAG), WLOG_TRACE, __VA_ARGS__); \
60
  } while (0)
61
#define LOGD(...)                                           \
62
  do                                                      \
63
  {                                                       \
64
    WLog_Print(WLog_Get(TAG), WLOG_DEBUG, __VA_ARGS__); \
65
  } while (0)
66
#define LOGI(...)                                          \
67
  do                                                     \
68
  {                                                      \
69
    WLog_Print(WLog_Get(TAG), WLOG_INFO, __VA_ARGS__); \
70
  } while (0)
71
#define LOGW(...)                                          \
72
  do                                                     \
73
  {                                                      \
74
    WLog_Print(WLog_Get(TAG), WLOG_WARN, __VA_ARGS__); \
75
  } while (0)
76
#define LOGE(...)                                           \
77
  do                                                      \
78
  {                                                       \
79
    WLog_Print(WLog_Get(TAG), WLOG_ERROR, __VA_ARGS__); \
80
  } while (0)
81
#define LOGF(...)                                           \
82
0
  do                                                      \
83
0
  {                                                       \
84
0
    WLog_Print(WLog_Get(TAG), WLOG_FATAL, __VA_ARGS__); \
85
0
  } while (0)
86
87
static const char* support_msg = "Invalid stacktrace buffer! check if platform is supported!";
88
89
void winpr_backtrace_free(void* buffer)
90
157k
{
91
157k
  if (!buffer)
92
0
    return;
93
94
157k
#if defined(USE_UNWIND)
95
157k
  winpr_unwind_backtrace_free(buffer);
96
#elif defined(USE_EXECINFO)
97
  winpr_execinfo_backtrace_free(buffer);
98
#elif defined(WINPR_HAVE_CORKSCREW)
99
  winpr_corkscrew_backtrace_free(buffer);
100
#elif defined(_WIN32) || defined(_WIN64)
101
  winpr_win_backtrace_free(buffer);
102
#else
103
  free(buffer);
104
  LOGF(support_msg);
105
#endif
106
157k
}
107
108
void* winpr_backtrace(DWORD size)
109
157k
{
110
157k
#if defined(USE_UNWIND)
111
157k
  return winpr_unwind_backtrace(size);
112
#elif defined(USE_EXECINFO)
113
  return winpr_execinfo_backtrace(size);
114
#elif defined(WINPR_HAVE_CORKSCREW)
115
  return winpr_corkscrew_backtrace(size);
116
#elif (defined(_WIN32) || defined(_WIN64)) && !defined(_UWP)
117
  return winpr_win_backtrace(size);
118
#else
119
  LOGF(support_msg);
120
  /* return a non NULL buffer to allow the backtrace function familiy to succeed without failing
121
   */
122
  return _strdup(support_msg);
123
#endif
124
157k
}
125
126
char** winpr_backtrace_symbols(void* buffer, size_t* used)
127
157k
{
128
157k
  if (used)
129
157k
    *used = 0;
130
131
157k
  if (!buffer)
132
0
  {
133
0
    LOGF(support_msg);
134
0
    return NULL;
135
0
  }
136
137
157k
#if defined(USE_UNWIND)
138
157k
  return winpr_unwind_backtrace_symbols(buffer, used);
139
#elif defined(USE_EXECINFO)
140
  return winpr_execinfo_backtrace_symbols(buffer, used);
141
#elif defined(WINPR_HAVE_CORKSCREW)
142
  return winpr_corkscrew_backtrace_symbols(buffer, used);
143
#elif (defined(_WIN32) || defined(_WIN64)) && !defined(_UWP)
144
  return winpr_win_backtrace_symbols(buffer, used);
145
#else
146
  LOGF(support_msg);
147
148
  /* We return a char** on heap that is compatible with free:
149
   *
150
   * 1. We allocate sizeof(char*) + strlen + 1 bytes.
151
   * 2. The first sizeof(char*) bytes contain the pointer to the string following the pointer.
152
   * 3. The at data + sizeof(char*) contains the actual string
153
   */
154
  size_t len = strlen(support_msg);
155
  char* ppmsg = calloc(sizeof(char*) + len + 1, sizeof(char));
156
  if (!ppmsg)
157
    return NULL;
158
  char** msgptr = (char**)ppmsg;
159
  char* msg = &ppmsg[sizeof(char*)];
160
161
  *msgptr = msg;
162
  strncpy(msg, support_msg, len);
163
  *used = 1;
164
  return msgptr;
165
#endif
166
157k
}
167
168
void winpr_backtrace_symbols_fd(void* buffer, int fd)
169
0
{
170
0
  if (!buffer)
171
0
  {
172
0
    LOGF(support_msg);
173
0
    return;
174
0
  }
175
176
#if defined(USE_EXECINFO) && !defined(USE_UNWIND)
177
  winpr_execinfo_backtrace_symbols_fd(buffer, fd);
178
#elif !defined(ANDROID)
179
0
  {
180
0
    size_t used = 0;
181
0
    char** lines = winpr_backtrace_symbols(buffer, &used);
182
183
0
    if (!lines)
184
0
      return;
185
186
0
    for (size_t i = 0; i < used; i++)
187
0
      _write(fd, lines[i], (unsigned)strnlen(lines[i], UINT32_MAX));
188
0
    free(lines);
189
0
  }
190
#else
191
  LOGF(support_msg);
192
#endif
193
0
}
194
195
void winpr_log_backtrace(const char* tag, DWORD level, DWORD size)
196
0
{
197
0
  winpr_log_backtrace_ex(WLog_Get(tag), level, size);
198
0
}
199
200
void winpr_log_backtrace_ex(wLog* log, DWORD level, DWORD size)
201
157k
{
202
157k
  size_t used = 0;
203
157k
  char** msg = NULL;
204
157k
  void* stack = winpr_backtrace(20);
205
206
157k
  if (!stack)
207
0
  {
208
0
    WLog_Print(log, WLOG_ERROR, "winpr_backtrace failed!\n");
209
0
    goto fail;
210
0
  }
211
212
157k
  msg = winpr_backtrace_symbols(stack, &used);
213
214
157k
  if (msg)
215
157k
  {
216
2.30M
    for (size_t x = 0; x < used; x++)
217
2.14M
      WLog_Print(log, level, "%" PRIuz ": %s", x, msg[x]);
218
157k
  }
219
157k
  free(msg);
220
221
157k
fail:
222
157k
  winpr_backtrace_free(stack);
223
157k
}
224
225
char* winpr_strerror(DWORD dw, char* dmsg, size_t size)
226
337
{
227
#ifdef __STDC_LIB_EXT1__
228
  strerror_s(dw, dmsg, size);
229
#elif defined(WINPR_HAVE_STRERROR_R)
230
  strerror_r(dw, dmsg, size);
231
#else
232
337
  _snprintf(dmsg, size, "%s", strerror(dw));
233
337
#endif
234
337
  return dmsg;
235
337
}