FreeRDP
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 
68 static const char* support_msg = "Invalid stacktrace buffer! check if platform is supported!";
69 
70 typedef struct
71 {
72  backtrace_frame_t* buffer;
73  size_t max;
74  size_t used;
75 } t_corkscrew_data;
76 
77 typedef 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 
98 static pthread_once_t initialized = PTHREAD_ONCE_INIT;
99 static t_corkscrew* fkt = NULL;
100 
101 void 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  }
172 fail:
173 {
174  if (lib.hdl)
175  dlclose(lib.hdl);
176 
177  fkt = NULL;
178 }
179 }
180 
181 void 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 
191 void* 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 
212 char** 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 }