FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
corkscrew/debug.c
1
21#include <pthread.h>
22#include <dlfcn.h>
23#include <unistd.h>
24
25#include <stdio.h>
26#include <fcntl.h>
27#include <winpr/string.h>
28
29#include <corkscrew/backtrace.h>
30
31#include <winpr/crt.h>
32#include <winpr/wlog.h>
33
34#include "debug.h"
35
36#define TAG "com.winpr.utils.debug"
37#define LOGT(...) \
38 do \
39 { \
40 WLog_Print(WLog_Get(TAG), WLOG_TRACE, __VA_ARGS__); \
41 } while (0)
42#define LOGD(...) \
43 do \
44 { \
45 WLog_Print(WLog_Get(TAG), WLOG_DEBUG, __VA_ARGS__); \
46 } while (0)
47#define LOGI(...) \
48 do \
49 { \
50 WLog_Print(WLog_Get(TAG), WLOG_INFO, __VA_ARGS__); \
51 } while (0)
52#define LOGW(...) \
53 do \
54 { \
55 WLog_Print(WLog_Get(TAG), WLOG_WARN, __VA_ARGS__); \
56 } while (0)
57#define LOGE(...) \
58 do \
59 { \
60 WLog_Print(WLog_Get(TAG), WLOG_ERROR, __VA_ARGS__); \
61 } while (0)
62#define LOGF(...) \
63 do \
64 { \
65 WLog_Print(WLog_Get(TAG), WLOG_FATAL, __VA_ARGS__); \
66 } while (0)
67
68static const char* support_msg = "Invalid stacktrace buffer! check if platform is supported!";
69
70typedef struct
71{
72 backtrace_frame_t* buffer;
73 size_t max;
74 size_t used;
75} t_corkscrew_data;
76
77typedef struct
78{
79 void* hdl;
80 ssize_t (*unwind_backtrace)(backtrace_frame_t* backtrace, size_t ignore_depth,
81 size_t max_depth);
82 ssize_t (*unwind_backtrace_thread)(pid_t tid, backtrace_frame_t* backtrace, size_t ignore_depth,
83 size_t max_depth);
84 ssize_t (*unwind_backtrace_ptrace)(pid_t tid, const ptrace_context_t* context,
85 backtrace_frame_t* backtrace, size_t ignore_depth,
86 size_t max_depth);
87 void (*get_backtrace_symbols)(const backtrace_frame_t* backtrace, size_t frames,
88 backtrace_symbol_t* backtrace_symbols);
89 void (*get_backtrace_symbols_ptrace)(const ptrace_context_t* context,
90 const backtrace_frame_t* backtrace, size_t frames,
91 backtrace_symbol_t* backtrace_symbols);
92 void (*free_backtrace_symbols)(backtrace_symbol_t* backtrace_symbols, size_t frames);
93 void (*format_backtrace_line)(unsigned frameNumber, const backtrace_frame_t* frame,
94 const backtrace_symbol_t* symbol, char* buffer,
95 size_t bufferSize);
96} t_corkscrew;
97
98static pthread_once_t initialized = PTHREAD_ONCE_INIT;
99static t_corkscrew* fkt = NULL;
100
101void load_library(void)
102{
103 static t_corkscrew lib;
104 {
105 lib.hdl = dlopen("libcorkscrew.so", RTLD_LAZY);
106
107 if (!lib.hdl)
108 {
109 LOGF("dlopen error %s", dlerror());
110 goto fail;
111 }
112
113 lib.unwind_backtrace = dlsym(lib.hdl, "unwind_backtrace");
114
115 if (!lib.unwind_backtrace)
116 {
117 LOGF("dlsym error %s", dlerror());
118 goto fail;
119 }
120
121 lib.unwind_backtrace_thread = dlsym(lib.hdl, "unwind_backtrace_thread");
122
123 if (!lib.unwind_backtrace_thread)
124 {
125 LOGF("dlsym error %s", dlerror());
126 goto fail;
127 }
128
129 lib.unwind_backtrace_ptrace = dlsym(lib.hdl, "unwind_backtrace_ptrace");
130
131 if (!lib.unwind_backtrace_ptrace)
132 {
133 LOGF("dlsym error %s", dlerror());
134 goto fail;
135 }
136
137 lib.get_backtrace_symbols = dlsym(lib.hdl, "get_backtrace_symbols");
138
139 if (!lib.get_backtrace_symbols)
140 {
141 LOGF("dlsym error %s", dlerror());
142 goto fail;
143 }
144
145 lib.get_backtrace_symbols_ptrace = dlsym(lib.hdl, "get_backtrace_symbols_ptrace");
146
147 if (!lib.get_backtrace_symbols_ptrace)
148 {
149 LOGF("dlsym error %s", dlerror());
150 goto fail;
151 }
152
153 lib.free_backtrace_symbols = dlsym(lib.hdl, "free_backtrace_symbols");
154
155 if (!lib.free_backtrace_symbols)
156 {
157 LOGF("dlsym error %s", dlerror());
158 goto fail;
159 }
160
161 lib.format_backtrace_line = dlsym(lib.hdl, "format_backtrace_line");
162
163 if (!lib.format_backtrace_line)
164 {
165 LOGF("dlsym error %s", dlerror());
166 goto fail;
167 }
168
169 fkt = &lib;
170 return;
171 }
172fail:
173{
174 if (lib.hdl)
175 dlclose(lib.hdl);
176
177 fkt = NULL;
178}
179}
180
181void winpr_corkscrew_backtrace_free(void* buffer)
182{
183 t_corkscrew_data* data = (t_corkscrew_data*)buffer;
184 if (!data)
185 return;
186
187 free(data->buffer);
188 free(data);
189}
190
191void* winpr_corkscrew_backtrace(DWORD size)
192{
193 t_corkscrew_data* data = calloc(1, sizeof(t_corkscrew_data));
194
195 if (!data)
196 return NULL;
197
198 data->buffer = calloc(size, sizeof(backtrace_frame_t));
199
200 if (!data->buffer)
201 {
202 free(data);
203 return NULL;
204 }
205
206 pthread_once(&initialized, load_library);
207 data->max = size;
208 data->used = fkt->unwind_backtrace(data->buffer, 0, size);
209 return data;
210}
211
212char** winpr_corkscrew_backtrace_symbols(void* buffer, size_t* used)
213{
214 t_corkscrew_data* data = (t_corkscrew_data*)buffer;
215 if (used)
216 *used = 0;
217
218 if (!data)
219 return NULL;
220
221 pthread_once(&initialized, load_library);
222
223 if (!fkt)
224 {
225 LOGF(support_msg);
226 return NULL;
227 }
228 else
229 {
230 size_t line_len = (data->max > 1024) ? data->max : 1024;
231 size_t array_size = data->used * sizeof(char*);
232 size_t lines_size = data->used * line_len;
233 char** vlines = calloc(1, array_size + lines_size);
234 backtrace_symbol_t* symbols = calloc(data->used, sizeof(backtrace_symbol_t));
235
236 if (!vlines || !symbols)
237 {
238 free(vlines);
239 free(symbols);
240 return NULL;
241 }
242
243 /* Set the pointers in the allocated buffer's initial array section */
244 for (size_t i = 0; i < data->used; i++)
245 vlines[i] = (char*)vlines + array_size + i * line_len;
246
247 fkt->get_backtrace_symbols(data->buffer, data->used, symbols);
248
249 for (size_t i = 0; i < data->used; i++)
250 fkt->format_backtrace_line(i, &data->buffer[i], &symbols[i], vlines[i], line_len);
251
252 fkt->free_backtrace_symbols(symbols, data->used);
253 free(symbols);
254
255 if (used)
256 *used = data->used;
257
258 return vlines;
259 }
260}