debug.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575
  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. #ifdef HAVE_CONFIG_H
  21. #include "config.h"
  22. #endif
  23. #include <stdio.h>
  24. #include <fcntl.h>
  25. #include <winpr/string.h>
  26. #if defined(HAVE_EXECINFO_H)
  27. #include <execinfo.h>
  28. #endif
  29. #if defined(ANDROID)
  30. #include <corkscrew/backtrace.h>
  31. #endif
  32. #if defined(_WIN32) || defined(_WIN64)
  33. #include <io.h>
  34. #include <windows.h>
  35. #include <dbghelp.h>
  36. #define write _write
  37. #endif
  38. #include <winpr/crt.h>
  39. #include <winpr/wlog.h>
  40. #include <winpr/debug.h>
  41. #define TAG "com.winpr.utils.debug"
  42. #define LOGT(...) \
  43. do \
  44. { \
  45. WLog_Print(WLog_Get(TAG), WLOG_TRACE, __VA_ARGS__); \
  46. } while (0)
  47. #define LOGD(...) \
  48. do \
  49. { \
  50. WLog_Print(WLog_Get(TAG), WLOG_DEBUG, __VA_ARGS__); \
  51. } while (0)
  52. #define LOGI(...) \
  53. do \
  54. { \
  55. WLog_Print(WLog_Get(TAG), WLOG_INFO, __VA_ARGS__); \
  56. } while (0)
  57. #define LOGW(...) \
  58. do \
  59. { \
  60. WLog_Print(WLog_Get(TAG), WLOG_WARN, __VA_ARGS__); \
  61. } while (0)
  62. #define LOGE(...) \
  63. do \
  64. { \
  65. WLog_Print(WLog_Get(TAG), WLOG_ERROR, __VA_ARGS__); \
  66. } while (0)
  67. #define LOGF(...) \
  68. do \
  69. { \
  70. WLog_Print(WLog_Get(TAG), WLOG_FATAL, __VA_ARGS__); \
  71. } while (0)
  72. static const char* support_msg = "Invalid stacktrace buffer! check if platform is supported!";
  73. #if defined(HAVE_EXECINFO_H)
  74. typedef struct
  75. {
  76. void** buffer;
  77. size_t max;
  78. size_t used;
  79. } t_execinfo;
  80. #endif
  81. #if defined(_WIN32) || defined(_WIN64)
  82. typedef struct
  83. {
  84. PVOID* stack;
  85. ULONG used;
  86. ULONG max;
  87. } t_win_stack;
  88. #endif
  89. #if defined(ANDROID)
  90. #include <pthread.h>
  91. #include <dlfcn.h>
  92. #include <unistd.h>
  93. typedef struct
  94. {
  95. backtrace_frame_t* buffer;
  96. size_t max;
  97. size_t used;
  98. } t_corkscrew_data;
  99. typedef struct
  100. {
  101. void* hdl;
  102. ssize_t (*unwind_backtrace)(backtrace_frame_t* backtrace, size_t ignore_depth,
  103. size_t max_depth);
  104. ssize_t (*unwind_backtrace_thread)(pid_t tid, backtrace_frame_t* backtrace, size_t ignore_depth,
  105. size_t max_depth);
  106. ssize_t (*unwind_backtrace_ptrace)(pid_t tid, const ptrace_context_t* context,
  107. backtrace_frame_t* backtrace, size_t ignore_depth,
  108. size_t max_depth);
  109. void (*get_backtrace_symbols)(const backtrace_frame_t* backtrace, size_t frames,
  110. backtrace_symbol_t* backtrace_symbols);
  111. void (*get_backtrace_symbols_ptrace)(const ptrace_context_t* context,
  112. const backtrace_frame_t* backtrace, size_t frames,
  113. backtrace_symbol_t* backtrace_symbols);
  114. void (*free_backtrace_symbols)(backtrace_symbol_t* backtrace_symbols, size_t frames);
  115. void (*format_backtrace_line)(unsigned frameNumber, const backtrace_frame_t* frame,
  116. const backtrace_symbol_t* symbol, char* buffer,
  117. size_t bufferSize);
  118. } t_corkscrew;
  119. static pthread_once_t initialized = PTHREAD_ONCE_INIT;
  120. static t_corkscrew* fkt = NULL;
  121. void load_library(void)
  122. {
  123. static t_corkscrew lib;
  124. {
  125. lib.hdl = dlopen("libcorkscrew.so", RTLD_LAZY);
  126. if (!lib.hdl)
  127. {
  128. LOGF("dlopen error %s", dlerror());
  129. goto fail;
  130. }
  131. lib.unwind_backtrace = dlsym(lib.hdl, "unwind_backtrace");
  132. if (!lib.unwind_backtrace)
  133. {
  134. LOGF("dlsym error %s", dlerror());
  135. goto fail;
  136. }
  137. lib.unwind_backtrace_thread = dlsym(lib.hdl, "unwind_backtrace_thread");
  138. if (!lib.unwind_backtrace_thread)
  139. {
  140. LOGF("dlsym error %s", dlerror());
  141. goto fail;
  142. }
  143. lib.unwind_backtrace_ptrace = dlsym(lib.hdl, "unwind_backtrace_ptrace");
  144. if (!lib.unwind_backtrace_ptrace)
  145. {
  146. LOGF("dlsym error %s", dlerror());
  147. goto fail;
  148. }
  149. lib.get_backtrace_symbols = dlsym(lib.hdl, "get_backtrace_symbols");
  150. if (!lib.get_backtrace_symbols)
  151. {
  152. LOGF("dlsym error %s", dlerror());
  153. goto fail;
  154. }
  155. lib.get_backtrace_symbols_ptrace = dlsym(lib.hdl, "get_backtrace_symbols_ptrace");
  156. if (!lib.get_backtrace_symbols_ptrace)
  157. {
  158. LOGF("dlsym error %s", dlerror());
  159. goto fail;
  160. }
  161. lib.free_backtrace_symbols = dlsym(lib.hdl, "free_backtrace_symbols");
  162. if (!lib.free_backtrace_symbols)
  163. {
  164. LOGF("dlsym error %s", dlerror());
  165. goto fail;
  166. }
  167. lib.format_backtrace_line = dlsym(lib.hdl, "format_backtrace_line");
  168. if (!lib.format_backtrace_line)
  169. {
  170. LOGF("dlsym error %s", dlerror());
  171. goto fail;
  172. }
  173. fkt = &lib;
  174. return;
  175. }
  176. fail:
  177. {
  178. if (lib.hdl)
  179. dlclose(lib.hdl);
  180. fkt = NULL;
  181. }
  182. }
  183. #endif
  184. #if defined(_WIN32) && (NTDDI_VERSION <= NTDDI_WINXP)
  185. typedef USHORT(WINAPI* PRTL_CAPTURE_STACK_BACK_TRACE_FN)(ULONG FramesToSkip, ULONG FramesToCapture,
  186. PVOID* BackTrace, PULONG BackTraceHash);
  187. static HMODULE g_NTDLL_Library = NULL;
  188. static BOOL g_RtlCaptureStackBackTrace_Detected = FALSE;
  189. static BOOL g_RtlCaptureStackBackTrace_Available = FALSE;
  190. static PRTL_CAPTURE_STACK_BACK_TRACE_FN g_pRtlCaptureStackBackTrace = NULL;
  191. USHORT RtlCaptureStackBackTrace(ULONG FramesToSkip, ULONG FramesToCapture, PVOID* BackTrace,
  192. PULONG BackTraceHash)
  193. {
  194. if (!g_RtlCaptureStackBackTrace_Detected)
  195. {
  196. g_NTDLL_Library = LoadLibraryA("kernel32.dll");
  197. if (g_NTDLL_Library)
  198. {
  199. g_pRtlCaptureStackBackTrace = (PRTL_CAPTURE_STACK_BACK_TRACE_FN)GetProcAddress(
  200. g_NTDLL_Library, "RtlCaptureStackBackTrace");
  201. g_RtlCaptureStackBackTrace_Available = (g_pRtlCaptureStackBackTrace) ? TRUE : FALSE;
  202. }
  203. else
  204. {
  205. g_RtlCaptureStackBackTrace_Available = FALSE;
  206. }
  207. g_RtlCaptureStackBackTrace_Detected = TRUE;
  208. }
  209. if (g_RtlCaptureStackBackTrace_Available)
  210. {
  211. return (*g_pRtlCaptureStackBackTrace)(FramesToSkip, FramesToCapture, BackTrace,
  212. BackTraceHash);
  213. }
  214. return 0;
  215. }
  216. #endif
  217. void winpr_backtrace_free(void* buffer)
  218. {
  219. if (!buffer)
  220. {
  221. LOGF(support_msg);
  222. return;
  223. }
  224. #if defined(HAVE_EXECINFO_H)
  225. t_execinfo* data = (t_execinfo*)buffer;
  226. free(data->buffer);
  227. free(data);
  228. #elif defined(ANDROID)
  229. t_corkscrew_data* data = (t_corkscrew_data*)buffer;
  230. free(data->buffer);
  231. free(data);
  232. #elif defined(_WIN32) || defined(_WIN64)
  233. {
  234. t_win_stack* data = (t_win_stack*)buffer;
  235. free(data->stack);
  236. free(data);
  237. }
  238. #else
  239. LOGF(support_msg);
  240. #endif
  241. }
  242. void* winpr_backtrace(DWORD size)
  243. {
  244. #if defined(HAVE_EXECINFO_H)
  245. t_execinfo* data = calloc(1, sizeof(t_execinfo));
  246. if (!data)
  247. return NULL;
  248. data->buffer = calloc(size, sizeof(void*));
  249. if (!data->buffer)
  250. {
  251. free(data);
  252. return NULL;
  253. }
  254. data->max = size;
  255. data->used = backtrace(data->buffer, size);
  256. return data;
  257. #elif defined(ANDROID)
  258. t_corkscrew_data* data = calloc(1, sizeof(t_corkscrew_data));
  259. if (!data)
  260. return NULL;
  261. data->buffer = calloc(size, sizeof(backtrace_frame_t));
  262. if (!data->buffer)
  263. {
  264. free(data);
  265. return NULL;
  266. }
  267. pthread_once(&initialized, load_library);
  268. data->max = size;
  269. data->used = fkt->unwind_backtrace(data->buffer, 0, size);
  270. return data;
  271. #elif (defined(_WIN32) || defined(_WIN64)) && !defined(_UWP)
  272. HANDLE process = GetCurrentProcess();
  273. t_win_stack* data = calloc(1, sizeof(t_win_stack));
  274. if (!data)
  275. return NULL;
  276. data->max = size;
  277. data->stack = calloc(data->max, sizeof(PVOID));
  278. if (!data->stack)
  279. {
  280. free(data);
  281. return NULL;
  282. }
  283. SymInitialize(process, NULL, TRUE);
  284. data->used = RtlCaptureStackBackTrace(2, size, data->stack, NULL);
  285. return data;
  286. #else
  287. LOGF(support_msg);
  288. return NULL;
  289. #endif
  290. }
  291. char** winpr_backtrace_symbols(void* buffer, size_t* used)
  292. {
  293. if (used)
  294. *used = 0;
  295. if (!buffer)
  296. {
  297. LOGF(support_msg);
  298. return NULL;
  299. }
  300. #if defined(HAVE_EXECINFO_H)
  301. t_execinfo* data = (t_execinfo*)buffer;
  302. if (!data)
  303. return NULL;
  304. if (used)
  305. *used = data->used;
  306. return backtrace_symbols(data->buffer, data->used);
  307. #elif defined(ANDROID)
  308. t_corkscrew_data* data = (t_corkscrew_data*)buffer;
  309. if (!data)
  310. return NULL;
  311. pthread_once(&initialized, load_library);
  312. if (!fkt)
  313. {
  314. LOGF(support_msg);
  315. return NULL;
  316. }
  317. else
  318. {
  319. size_t line_len = (data->max > 1024) ? data->max : 1024;
  320. size_t i;
  321. size_t array_size = data->used * sizeof(char*);
  322. size_t lines_size = data->used * line_len;
  323. char** vlines = calloc(1, array_size + lines_size);
  324. backtrace_symbol_t* symbols = calloc(data->used, sizeof(backtrace_symbol_t));
  325. if (!vlines || !symbols)
  326. {
  327. free(vlines);
  328. free(symbols);
  329. return NULL;
  330. }
  331. /* Set the pointers in the allocated buffer's initial array section */
  332. for (i = 0; i < data->used; i++)
  333. vlines[i] = (char*)vlines + array_size + i * line_len;
  334. fkt->get_backtrace_symbols(data->buffer, data->used, symbols);
  335. for (i = 0; i < data->used; i++)
  336. fkt->format_backtrace_line(i, &data->buffer[i], &symbols[i], vlines[i], line_len);
  337. fkt->free_backtrace_symbols(symbols, data->used);
  338. free(symbols);
  339. if (used)
  340. *used = data->used;
  341. return vlines;
  342. }
  343. #elif (defined(_WIN32) || defined(_WIN64)) && !defined(_UWP)
  344. {
  345. size_t i;
  346. size_t line_len = 1024;
  347. HANDLE process = GetCurrentProcess();
  348. t_win_stack* data = (t_win_stack*)buffer;
  349. size_t array_size = data->used * sizeof(char*);
  350. size_t lines_size = data->used * line_len;
  351. char** vlines = calloc(1, array_size + lines_size);
  352. SYMBOL_INFO* symbol = calloc(1, sizeof(SYMBOL_INFO) + line_len * sizeof(char));
  353. IMAGEHLP_LINE64* line = (IMAGEHLP_LINE64*)calloc(1, sizeof(IMAGEHLP_LINE64));
  354. if (!vlines || !symbol || !line)
  355. {
  356. free(vlines);
  357. free(symbol);
  358. free(line);
  359. return NULL;
  360. }
  361. line->SizeOfStruct = sizeof(IMAGEHLP_LINE64);
  362. symbol->MaxNameLen = line_len;
  363. symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
  364. /* Set the pointers in the allocated buffer's initial array section */
  365. for (i = 0; i < data->used; i++)
  366. vlines[i] = (char*)vlines + array_size + i * line_len;
  367. for (i = 0; i < data->used; i++)
  368. {
  369. DWORD64 address = (DWORD64)(data->stack[i]);
  370. DWORD displacement;
  371. SymFromAddr(process, address, 0, symbol);
  372. if (SymGetLineFromAddr64(process, address, &displacement, line))
  373. {
  374. sprintf_s(vlines[i], line_len, "%016" PRIx64 ": %s in %s:%" PRIu32, symbol->Address,
  375. symbol->Name, line->FileName, line->LineNumber);
  376. }
  377. else
  378. sprintf_s(vlines[i], line_len, "%016" PRIx64 ": %s", symbol->Address, symbol->Name);
  379. }
  380. if (used)
  381. *used = data->used;
  382. free(symbol);
  383. free(line);
  384. return vlines;
  385. }
  386. #else
  387. LOGF(support_msg);
  388. return NULL;
  389. #endif
  390. }
  391. void winpr_backtrace_symbols_fd(void* buffer, int fd)
  392. {
  393. if (!buffer)
  394. {
  395. LOGF(support_msg);
  396. return;
  397. }
  398. #if defined(HAVE_EXECINFO_H)
  399. t_execinfo* data = (t_execinfo*)buffer;
  400. if (!data)
  401. return;
  402. backtrace_symbols_fd(data->buffer, data->used, fd);
  403. #elif defined(_WIN32) || defined(_WIN64) || defined(ANDROID)
  404. {
  405. DWORD i;
  406. size_t used;
  407. char** lines;
  408. lines = winpr_backtrace_symbols(buffer, &used);
  409. if (lines)
  410. {
  411. for (i = 0; i < used; i++)
  412. write(fd, lines[i], strlen(lines[i]));
  413. }
  414. }
  415. #else
  416. LOGF(support_msg);
  417. #endif
  418. }
  419. void winpr_log_backtrace(const char* tag, DWORD level, DWORD size)
  420. {
  421. winpr_log_backtrace_ex(WLog_Get(tag), level, size);
  422. }
  423. void winpr_log_backtrace_ex(wLog* log, DWORD level, DWORD size)
  424. {
  425. size_t used, x;
  426. char** msg;
  427. void* stack = winpr_backtrace(20);
  428. if (!stack)
  429. {
  430. WLog_Print(log, WLOG_ERROR, "winpr_backtrace failed!\n");
  431. winpr_backtrace_free(stack);
  432. return;
  433. }
  434. msg = winpr_backtrace_symbols(stack, &used);
  435. if (msg)
  436. {
  437. for (x = 0; x < used; x++)
  438. WLog_Print(log, level, "%" PRIuz ": %s\n", x, msg[x]);
  439. }
  440. winpr_backtrace_free(stack);
  441. }
  442. char* winpr_strerror(DWORD dw, char* dmsg, size_t size)
  443. {
  444. #if defined(_WIN32)
  445. DWORD rc;
  446. DWORD nSize = 0;
  447. DWORD dwFlags = 0;
  448. LPTSTR msg = NULL;
  449. BOOL alloc = FALSE;
  450. dwFlags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
  451. #ifdef FORMAT_MESSAGE_ALLOCATE_BUFFER
  452. alloc = TRUE;
  453. dwFlags |= FORMAT_MESSAGE_ALLOCATE_BUFFER;
  454. #else
  455. nSize = (DWORD)(size * 2);
  456. msg = (LPTSTR)calloc(nSize, sizeof(TCHAR));
  457. #endif
  458. rc = FormatMessage(dwFlags, NULL, dw, 0, alloc ? (LPTSTR)&msg : msg, nSize, NULL);
  459. if (rc)
  460. {
  461. #if defined(UNICODE)
  462. WideCharToMultiByte(CP_ACP, 0, msg, rc, dmsg, size - 1, NULL, NULL);
  463. #else /* defined(UNICODE) */
  464. memcpy(dmsg, msg, min(rc, size - 1));
  465. #endif /* defined(UNICODE) */
  466. dmsg[min(rc, size - 1)] = 0;
  467. #ifdef FORMAT_MESSAGE_ALLOCATE_BUFFER
  468. LocalFree(msg);
  469. #else
  470. free(msg);
  471. #endif
  472. }
  473. else
  474. {
  475. _snprintf(dmsg, size, "FAILURE: 0x%08" PRIX32 "", GetLastError());
  476. }
  477. #else /* defined(_WIN32) */
  478. _snprintf(dmsg, size, "%s", strerror(dw));
  479. #endif /* defined(_WIN32) */
  480. return dmsg;
  481. }