backtrace.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868
  1. /*
  2. * Copyright (C) 2006-2013 Martin Willi
  3. * HSR Hochschule fuer Technik Rapperswil
  4. * Copyright (C) 2013 revosec AG
  5. *
  6. * This program is free software; you can redistribute it and/or modify it
  7. * under the terms of the GNU General Public License as published by the
  8. * Free Software Foundation; either version 2 of the License, or (at your
  9. * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
  10. *
  11. * This program is distributed in the hope that it will be useful, but
  12. * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  13. * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  14. * for more details.
  15. */
  16. #define _GNU_SOURCE
  17. #ifdef HAVE_BACKTRACE
  18. # include <execinfo.h>
  19. #endif /* HAVE_BACKTRACE */
  20. #ifdef HAVE_DBGHELP
  21. # include <winsock2.h>
  22. # include <windows.h>
  23. # include <dbghelp.h>
  24. #endif /* HAVE_DBGHELP */
  25. #include <string.h>
  26. #include "backtrace.h"
  27. #include <utils/debug.h>
  28. #ifdef WIN32
  29. # include <psapi.h>
  30. /* missing in MinGW */
  31. #ifdef WIN64
  32. #ifndef GetModuleInformation
  33. WINBOOL K32GetModuleInformation(HANDLE hProcess, HMODULE hModule,
  34. LPMODULEINFO lpmodinfo, DWORD cb);
  35. #define GetModuleInformation K32GetModuleInformation
  36. #endif /* !GetModuleInformation */
  37. #ifndef GetModuleFileNameEx
  38. DWORD K32GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule,
  39. LPTSTR lpFilename, DWORD nSize);
  40. #define GetModuleFileNameEx K32GetModuleFileNameExA
  41. #endif /* !GetModuleFileNameEx */
  42. #endif /* WIN64 */
  43. #endif
  44. typedef struct private_backtrace_t private_backtrace_t;
  45. /**
  46. * Private data of an backtrace_t object.
  47. */
  48. struct private_backtrace_t {
  49. /**
  50. * Public backtrace_t interface.
  51. */
  52. backtrace_t public;
  53. /**
  54. * Number of stacks frames obtained in stack_frames
  55. */
  56. int frame_count;
  57. /**
  58. * Recorded stack frames.
  59. */
  60. void *frames[];
  61. };
  62. /**
  63. * Forward declaration of method getter
  64. */
  65. static backtrace_t get_methods();
  66. /**
  67. * Write a format string with arguments to a FILE line, if it is NULL to DBG
  68. */
  69. static void println(FILE *file, char *format, ...)
  70. {
  71. char buf[512];
  72. va_list args;
  73. va_start(args, format);
  74. if (file)
  75. {
  76. vfprintf(file, format, args);
  77. fputs("\n", file);
  78. }
  79. else
  80. {
  81. vsnprintf(buf, sizeof(buf), format, args);
  82. DBG1(DBG_LIB, "%s", buf);
  83. }
  84. va_end(args);
  85. }
  86. /**
  87. * Same as tty_escape_get(), but for a potentially NULL FILE*
  88. */
  89. static inline char* esc(FILE *file, tty_escape_t escape)
  90. {
  91. if (file)
  92. {
  93. return tty_escape_get(fileno(file), escape);
  94. }
  95. return "";
  96. }
  97. #ifdef HAVE_DBGHELP
  98. #include <dbghelp.h>
  99. #include <threading/mutex.h>
  100. /**
  101. * Mutex to access non-thread-safe dbghelp functions
  102. */
  103. static mutex_t *dbghelp_mutex;
  104. void backtrace_init()
  105. {
  106. SymSetOptions(SYMOPT_LOAD_LINES);
  107. SymInitialize(GetCurrentProcess(), NULL, TRUE);
  108. dbghelp_mutex = mutex_create(MUTEX_TYPE_DEFAULT);
  109. }
  110. void backtrace_deinit()
  111. {
  112. dbghelp_mutex->destroy(dbghelp_mutex);
  113. SymCleanup(GetCurrentProcess());
  114. }
  115. #elif defined(HAVE_DLADDR) || defined(HAVE_BFD_H)
  116. #ifdef HAVE_DLADDR
  117. #include <dlfcn.h>
  118. #endif
  119. #ifdef HAVE_BFD_H
  120. #include <bfd.h>
  121. #include <collections/hashtable.h>
  122. #include <threading/mutex.h>
  123. /**
  124. * Hashtable-cached bfd handle
  125. */
  126. typedef struct {
  127. /** binary file name on disk */
  128. char *filename;
  129. /** bfd handle */
  130. bfd *abfd;
  131. /** loaded symbols */
  132. asymbol **syms;
  133. } bfd_entry_t;
  134. /**
  135. * Destroy a bfd_entry
  136. */
  137. static void bfd_entry_destroy(bfd_entry_t *this)
  138. {
  139. free(this->filename);
  140. free(this->syms);
  141. bfd_close(this->abfd);
  142. free(this);
  143. }
  144. /**
  145. * Data to pass to find_addr()
  146. */
  147. typedef struct {
  148. /** used bfd entry */
  149. bfd_entry_t *entry;
  150. /** backtrace address */
  151. bfd_vma vma;
  152. /** stream to log to */
  153. FILE *file;
  154. /** TRUE if complete */
  155. bool found;
  156. } bfd_find_data_t;
  157. /**
  158. * bfd entry cache
  159. */
  160. static hashtable_t *bfds;
  161. static mutex_t *bfd_mutex;
  162. /**
  163. * Hashtable hash function
  164. */
  165. static u_int bfd_hash(char *key)
  166. {
  167. return chunk_hash(chunk_create(key, strlen(key)));
  168. }
  169. /**
  170. * Hashtable equals function
  171. */
  172. static bool bfd_equals(char *a, char *b)
  173. {
  174. return streq(a, b);
  175. }
  176. /**
  177. * See header.
  178. */
  179. void backtrace_init()
  180. {
  181. bfd_init();
  182. bfds = hashtable_create((hashtable_hash_t)bfd_hash,
  183. (hashtable_equals_t)bfd_equals, 8);
  184. bfd_mutex = mutex_create(MUTEX_TYPE_DEFAULT);
  185. }
  186. /**
  187. * See header.
  188. */
  189. void backtrace_deinit()
  190. {
  191. enumerator_t *enumerator;
  192. bfd_entry_t *entry;
  193. char *key;
  194. enumerator = bfds->create_enumerator(bfds);
  195. while (enumerator->enumerate(enumerator, &key, &entry))
  196. {
  197. bfds->remove_at(bfds, enumerator);
  198. bfd_entry_destroy(entry);
  199. }
  200. enumerator->destroy(enumerator);
  201. bfds->destroy(bfds);
  202. bfd_mutex->destroy(bfd_mutex);
  203. }
  204. /**
  205. * Find and print information to an address
  206. */
  207. static void find_addr(bfd *abfd, asection *section, bfd_find_data_t *data)
  208. {
  209. bfd_size_type size;
  210. bfd_vma vma;
  211. const char *source;
  212. const char *function;
  213. char fbuf[512] = "", sbuf[512] = "";
  214. u_int line;
  215. if (!data->found || (bfd_get_section_flags(abfd, section) & SEC_ALLOC) != 0)
  216. {
  217. vma = bfd_get_section_vma(abfd, section);
  218. if (data->vma >= vma)
  219. {
  220. size = bfd_get_section_size(section);
  221. if (data->vma < vma + size)
  222. {
  223. data->found = bfd_find_nearest_line(abfd, section,
  224. data->entry->syms, data->vma - vma,
  225. &source, &function, &line);
  226. if (data->found)
  227. {
  228. if (source || function)
  229. {
  230. if (function)
  231. {
  232. snprintf(fbuf, sizeof(fbuf), "%s%s() ",
  233. esc(data->file, TTY_FG_BLUE), function);
  234. }
  235. if (source)
  236. {
  237. snprintf(sbuf, sizeof(sbuf), "%s@ %s:%d",
  238. esc(data->file, TTY_FG_GREEN), source, line);
  239. }
  240. println(data->file, " -> %s%s%s", fbuf, sbuf,
  241. esc(data->file, TTY_FG_DEF));
  242. }
  243. }
  244. }
  245. }
  246. }
  247. }
  248. /**
  249. * Find a cached bfd entry, create'n'cache if not found
  250. */
  251. static bfd_entry_t *get_bfd_entry(char *filename)
  252. {
  253. bool dynamic = FALSE, ok = FALSE;
  254. bfd_entry_t *entry;
  255. long size;
  256. /* check cache */
  257. entry = bfds->get(bfds, filename);
  258. if (entry)
  259. {
  260. return entry;
  261. }
  262. INIT(entry,
  263. .abfd = bfd_openr(filename, NULL),
  264. );
  265. if (!entry->abfd)
  266. {
  267. free(entry);
  268. return NULL;
  269. }
  270. #ifdef BFD_DECOMPRESS
  271. entry->abfd->flags |= BFD_DECOMPRESS;
  272. #endif
  273. if (bfd_check_format(entry->abfd, bfd_archive) == 0 &&
  274. bfd_check_format_matches(entry->abfd, bfd_object, NULL))
  275. {
  276. if (bfd_get_file_flags(entry->abfd) & HAS_SYMS)
  277. {
  278. size = bfd_get_symtab_upper_bound(entry->abfd);
  279. if (size == 0)
  280. {
  281. size = bfd_get_dynamic_symtab_upper_bound(entry->abfd);
  282. dynamic = TRUE;
  283. }
  284. if (size >= 0)
  285. {
  286. entry->syms = malloc(size);
  287. if (dynamic)
  288. {
  289. ok = bfd_canonicalize_dynamic_symtab(entry->abfd,
  290. entry->syms) >= 0;
  291. }
  292. else
  293. {
  294. ok = bfd_canonicalize_symtab(entry->abfd,
  295. entry->syms) >= 0;
  296. }
  297. }
  298. }
  299. }
  300. if (ok)
  301. {
  302. entry->filename = strdup(filename);
  303. bfds->put(bfds, entry->filename, entry);
  304. return entry;
  305. }
  306. bfd_entry_destroy(entry);
  307. return NULL;
  308. }
  309. /**
  310. * Print the source file with line number to file, libbfd variant
  311. */
  312. static void print_sourceline(FILE *file, char *filename, void *ptr, void *base)
  313. {
  314. bfd_entry_t *entry;
  315. bfd_find_data_t data = {
  316. .file = file,
  317. .vma = (uintptr_t)ptr,
  318. };
  319. bool old = FALSE;
  320. bfd_mutex->lock(bfd_mutex);
  321. if (lib && lib->leak_detective)
  322. {
  323. old = lib->leak_detective->set_state(lib->leak_detective, FALSE);
  324. }
  325. entry = get_bfd_entry(filename);
  326. if (entry)
  327. {
  328. data.entry = entry;
  329. bfd_map_over_sections(entry->abfd, (void*)find_addr, &data);
  330. }
  331. if (lib && lib->leak_detective)
  332. {
  333. lib->leak_detective->set_state(lib->leak_detective, old);
  334. }
  335. bfd_mutex->unlock(bfd_mutex);
  336. }
  337. #else /* !HAVE_BFD_H */
  338. void backtrace_init() {}
  339. void backtrace_deinit() {}
  340. /**
  341. * Print the source file with line number to file, slow addr2line variant
  342. */
  343. static void print_sourceline(FILE *file, char *filename, void *ptr, void* base)
  344. {
  345. char buf[1024];
  346. FILE *output;
  347. int c, i = 0;
  348. #ifdef __APPLE__
  349. snprintf(buf, sizeof(buf), "atos -o %s -l %p %p 2>&1 | tail -n1",
  350. filename, base, ptr);
  351. #else /* !__APPLE__ */
  352. snprintf(buf, sizeof(buf), "addr2line -e %s %p", filename, ptr);
  353. #endif /* __APPLE__ */
  354. output = popen(buf, "r");
  355. if (output)
  356. {
  357. while (i < sizeof(buf))
  358. {
  359. c = getc(output);
  360. if (c == '\n' || c == EOF)
  361. {
  362. buf[i++] = 0;
  363. break;
  364. }
  365. buf[i++] = c;
  366. }
  367. pclose(output);
  368. println(file, " -> %s%s%s", esc(file, TTY_FG_GREEN), buf,
  369. esc(file, TTY_FG_DEF));
  370. }
  371. }
  372. #endif /* HAVE_BFD_H */
  373. #else /* !HAVE_DLADDR && !HAVE_DBGHELP */
  374. void backtrace_init() {}
  375. void backtrace_deinit() {}
  376. #endif /* HAVE_DLADDR */
  377. METHOD(backtrace_t, log_, void,
  378. private_backtrace_t *this, FILE *file, bool detailed)
  379. {
  380. #if defined(HAVE_BACKTRACE) || defined(HAVE_LIBUNWIND_H) || defined(WIN32)
  381. size_t i;
  382. char **strings = NULL;
  383. println(file, " dumping %d stack frame addresses:", this->frame_count);
  384. for (i = 0; i < this->frame_count; i++)
  385. {
  386. #ifdef HAVE_DLADDR
  387. Dl_info info;
  388. if (dladdr(this->frames[i], &info))
  389. {
  390. void *ptr = this->frames[i];
  391. if (strstr(info.dli_fname, ".so"))
  392. {
  393. ptr = (void*)(this->frames[i] - info.dli_fbase);
  394. }
  395. if (info.dli_sname)
  396. {
  397. println(file, " %s%s%s @ %p (%s%s%s+0x%tx) [%p]",
  398. esc(file, TTY_FG_YELLOW), info.dli_fname,
  399. esc(file, TTY_FG_DEF), info.dli_fbase,
  400. esc(file, TTY_FG_RED), info.dli_sname,
  401. esc(file, TTY_FG_DEF), this->frames[i] - info.dli_saddr,
  402. this->frames[i]);
  403. }
  404. else
  405. {
  406. println(file, " %s%s%s @ %p [%p]",
  407. esc(file, TTY_FG_YELLOW), info.dli_fname,
  408. esc(file, TTY_FG_DEF), info.dli_fbase, this->frames[i]);
  409. }
  410. if (detailed && info.dli_fname[0])
  411. {
  412. print_sourceline(file, (char*)info.dli_fname,
  413. ptr, info.dli_fbase);
  414. }
  415. }
  416. else
  417. #elif defined(HAVE_DBGHELP)
  418. struct {
  419. SYMBOL_INFO hdr;
  420. char buf[128];
  421. } symbol;
  422. char filename[MAX_PATH];
  423. HINSTANCE module;
  424. HANDLE process;
  425. DWORD64 displace, frame;
  426. process = GetCurrentProcess();
  427. frame = (uintptr_t)this->frames[i];
  428. memset(&symbol, 0, sizeof(symbol));
  429. symbol.hdr.SizeOfStruct = sizeof(symbol.hdr);
  430. symbol.hdr.MaxNameLen = sizeof(symbol.buf) - 1;
  431. dbghelp_mutex->lock(dbghelp_mutex);
  432. module = (HINSTANCE)SymGetModuleBase64(process, frame);
  433. if (module && GetModuleFileName(module, filename, sizeof(filename)))
  434. {
  435. if (SymFromAddr(process, frame, &displace, &symbol.hdr))
  436. {
  437. println(file, " %s%s%s @ %p (%s%s%s+0x%tx) [%p]",
  438. esc(file, TTY_FG_YELLOW), filename,
  439. esc(file, TTY_FG_DEF), (void*)module,
  440. esc(file, TTY_FG_RED), symbol.hdr.Name,
  441. esc(file, TTY_FG_DEF), displace,
  442. this->frames[i]);
  443. }
  444. else
  445. {
  446. println(file, " %s%s%s @ %p [%p]",
  447. esc(file, TTY_FG_YELLOW), filename,
  448. esc(file, TTY_FG_DEF), (void*)module, this->frames[i]);
  449. }
  450. if (detailed)
  451. {
  452. IMAGEHLP_LINE64 line;
  453. DWORD off;
  454. memset(&line, 0, sizeof(line));
  455. line.SizeOfStruct = sizeof(line);
  456. if (SymGetLineFromAddr64(process, frame, &off, &line))
  457. {
  458. println(file, " -> %s%s:%u%s", esc(file, TTY_FG_GREEN),
  459. line.FileName, line.LineNumber,
  460. esc(file, TTY_FG_DEF));
  461. }
  462. }
  463. }
  464. else
  465. #elif defined(WIN32)
  466. HMODULE module;
  467. MODULEINFO info;
  468. char filename[MAX_PATH];
  469. if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
  470. this->frames[i], &module) &&
  471. GetModuleInformation(GetCurrentProcess(), module,
  472. &info, sizeof(info)) &&
  473. GetModuleFileNameEx(GetCurrentProcess(), module,
  474. filename, sizeof(filename)))
  475. {
  476. println(file, " %s%s%s @ %p [%p]",
  477. esc(file, TTY_FG_YELLOW), filename,
  478. esc(file, TTY_FG_DEF), info.lpBaseOfDll, this->frames[i]);
  479. #ifdef HAVE_BFD_H
  480. print_sourceline(file, filename, this->frames[i], info.lpBaseOfDll);
  481. #endif /* HAVE_BFD_H */
  482. }
  483. else
  484. #endif /* HAVE_DLADDR/HAVE_DBGHELP */
  485. {
  486. #ifdef HAVE_BACKTRACE
  487. if (!strings)
  488. {
  489. strings = backtrace_symbols(this->frames, this->frame_count);
  490. }
  491. if (strings)
  492. {
  493. println(file, " %s", strings[i]);
  494. }
  495. else
  496. #endif /* HAVE_BACKTRACE */
  497. {
  498. println(file, " %p", this->frames[i]);
  499. }
  500. }
  501. #ifdef HAVE_DBGHELP
  502. dbghelp_mutex->unlock(dbghelp_mutex);
  503. #endif
  504. }
  505. free(strings);
  506. #else /* !HAVE_BACKTRACE && !HAVE_LIBUNWIND_H */
  507. println(file, "no support for capturing backtraces");
  508. #endif /* HAVE_BACKTRACE/HAVE_LIBUNWIND_H */
  509. }
  510. METHOD(backtrace_t, contains_function, bool,
  511. private_backtrace_t *this, char *function[], int count)
  512. {
  513. #ifdef HAVE_DLADDR
  514. int i, j;
  515. for (i = 0; i< this->frame_count; i++)
  516. {
  517. Dl_info info;
  518. if (dladdr(this->frames[i], &info) && info.dli_sname)
  519. {
  520. for (j = 0; j < count; j++)
  521. {
  522. if (streq(info.dli_sname, function[j]))
  523. {
  524. return TRUE;
  525. }
  526. }
  527. }
  528. }
  529. #elif defined(HAVE_DBGHELP)
  530. int i, j;
  531. HANDLE process;
  532. process = GetCurrentProcess();
  533. dbghelp_mutex->lock(dbghelp_mutex);
  534. for (i = 0; i < this->frame_count; i++)
  535. {
  536. struct {
  537. SYMBOL_INFO hdr;
  538. char buf[128];
  539. } symbol;
  540. memset(&symbol, 0, sizeof(symbol));
  541. symbol.hdr.SizeOfStruct = sizeof(symbol.hdr);
  542. symbol.hdr.MaxNameLen = sizeof(symbol.buf) - 1;
  543. if (SymFromAddr(process, (DWORD64)this->frames[i], NULL, &symbol.hdr))
  544. {
  545. for (j = 0; j < count; j++)
  546. {
  547. if (streq(symbol.hdr.Name, function[j]))
  548. {
  549. dbghelp_mutex->unlock(dbghelp_mutex);
  550. return TRUE;
  551. }
  552. }
  553. }
  554. }
  555. dbghelp_mutex->unlock(dbghelp_mutex);
  556. #endif /* HAVE_DLADDR/HAVE_DBGHELP */
  557. return FALSE;
  558. }
  559. METHOD(backtrace_t, equals, bool,
  560. private_backtrace_t *this, backtrace_t *other_public)
  561. {
  562. private_backtrace_t *other = (private_backtrace_t*)other_public;
  563. int i;
  564. if (this == other)
  565. {
  566. return TRUE;
  567. }
  568. if (this->frame_count != other->frame_count)
  569. {
  570. return FALSE;
  571. }
  572. for (i = 0; i < this->frame_count; i++)
  573. {
  574. if (this->frames[i] != other->frames[i])
  575. {
  576. return FALSE;
  577. }
  578. }
  579. return TRUE;
  580. }
  581. /**
  582. * Frame enumerator
  583. */
  584. typedef struct {
  585. /** implements enumerator_t */
  586. enumerator_t public;
  587. /** reference to backtrace */
  588. private_backtrace_t *bt;
  589. /** current position */
  590. int i;
  591. } frame_enumerator_t;
  592. METHOD(enumerator_t, frame_enumerate, bool,
  593. frame_enumerator_t *this, va_list args)
  594. {
  595. void **addr;
  596. VA_ARGS_VGET(args, addr);
  597. if (this->i < this->bt->frame_count)
  598. {
  599. *addr = this->bt->frames[this->i++];
  600. return TRUE;
  601. }
  602. return FALSE;
  603. }
  604. METHOD(backtrace_t, create_frame_enumerator, enumerator_t*,
  605. private_backtrace_t *this)
  606. {
  607. frame_enumerator_t *enumerator;
  608. INIT(enumerator,
  609. .public = {
  610. .enumerate = enumerator_enumerate_default,
  611. .venumerate = _frame_enumerate,
  612. .destroy = (void*)free,
  613. },
  614. .bt = this,
  615. );
  616. return &enumerator->public;
  617. }
  618. METHOD(backtrace_t, clone_, backtrace_t*,
  619. private_backtrace_t *this)
  620. {
  621. private_backtrace_t *clone;
  622. clone = malloc(sizeof(private_backtrace_t) +
  623. this->frame_count * sizeof(void*));
  624. memcpy(clone->frames, this->frames, this->frame_count * sizeof(void*));
  625. clone->frame_count = this->frame_count;
  626. clone->public = get_methods();
  627. return &clone->public;
  628. }
  629. METHOD(backtrace_t, destroy, void,
  630. private_backtrace_t *this)
  631. {
  632. free(this);
  633. }
  634. #ifdef HAVE_LIBUNWIND_H
  635. #define UNW_LOCAL_ONLY
  636. #include <libunwind.h>
  637. /**
  638. * libunwind variant for glibc backtrace()
  639. */
  640. static inline int backtrace_unwind(void **frames, int count)
  641. {
  642. unw_context_t context;
  643. unw_cursor_t cursor;
  644. unw_word_t ip;
  645. int depth = 0;
  646. unw_getcontext(&context);
  647. unw_init_local(&cursor, &context);
  648. do
  649. {
  650. unw_get_reg(&cursor, UNW_REG_IP, &ip);
  651. frames[depth++] = (void*)ip;
  652. }
  653. while (depth < count && unw_step(&cursor) > 0);
  654. return depth;
  655. }
  656. #endif /* HAVE_UNWIND */
  657. #ifdef HAVE_DBGHELP
  658. /**
  659. * Windows dbghelp variant for glibc backtrace()
  660. */
  661. static inline int backtrace_win(void **frames, int count)
  662. {
  663. STACKFRAME frame;
  664. HANDLE process, thread;
  665. DWORD machine;
  666. CONTEXT context;
  667. int got = 0;
  668. memset(&frame, 0, sizeof(frame));
  669. memset(&context, 0, sizeof(context));
  670. process = GetCurrentProcess();
  671. thread = GetCurrentThread();
  672. #ifdef __x86_64
  673. machine = IMAGE_FILE_MACHINE_AMD64;
  674. frame.AddrPC.Offset = context.Rip;
  675. frame.AddrPC.Mode = AddrModeFlat;
  676. frame.AddrStack.Offset = context.Rsp;
  677. frame.AddrStack.Mode = AddrModeFlat;
  678. frame.AddrFrame.Offset = context.Rbp;
  679. frame.AddrFrame.Mode = AddrModeFlat;
  680. #else /* x86 */
  681. machine = IMAGE_FILE_MACHINE_I386;
  682. frame.AddrPC.Offset = context.Eip;
  683. frame.AddrPC.Mode = AddrModeFlat;
  684. frame.AddrStack.Offset = context.Esp;
  685. frame.AddrStack.Mode = AddrModeFlat;
  686. frame.AddrFrame.Offset = context.Ebp;
  687. frame.AddrFrame.Mode = AddrModeFlat;
  688. #endif /* x86_64/x86 */
  689. dbghelp_mutex->lock(dbghelp_mutex);
  690. RtlCaptureContext(&context);
  691. while (got < count)
  692. {
  693. if (!StackWalk64(machine, process, thread, &frame, &context,
  694. NULL, SymFunctionTableAccess, SymGetModuleBase, NULL))
  695. {
  696. break;
  697. }
  698. frames[got++] = (void*)frame.AddrPC.Offset;
  699. }
  700. dbghelp_mutex->unlock(dbghelp_mutex);
  701. return got;
  702. }
  703. #endif /* HAVE_DBGHELP */
  704. /**
  705. * Get implementation methods of backtrace_t
  706. */
  707. static backtrace_t get_methods()
  708. {
  709. return (backtrace_t) {
  710. .log = _log_,
  711. .contains_function = _contains_function,
  712. .equals = _equals,
  713. .clone = _clone_,
  714. .create_frame_enumerator = _create_frame_enumerator,
  715. .destroy = _destroy,
  716. };
  717. }
  718. /**
  719. * See header
  720. */
  721. backtrace_t *backtrace_create(int skip)
  722. {
  723. private_backtrace_t *this;
  724. void *frames[50];
  725. int frame_count = 0;
  726. #ifdef HAVE_LIBUNWIND_H
  727. frame_count = backtrace_unwind(frames, countof(frames));
  728. #elif defined(HAVE_BACKTRACE)
  729. frame_count = backtrace(frames, countof(frames));
  730. #elif defined(HAVE_DBGHELP)
  731. frame_count = backtrace_win(frames, countof(frames));
  732. #elif defined(WIN32)
  733. frame_count = CaptureStackBackTrace(skip, countof(frames), frames, NULL);
  734. skip = 0;
  735. #endif
  736. frame_count = max(frame_count - skip, 0);
  737. this = malloc(sizeof(private_backtrace_t) + frame_count * sizeof(void*));
  738. memcpy(this->frames, frames + skip, frame_count * sizeof(void*));
  739. this->frame_count = frame_count;
  740. this->public = get_methods();
  741. return &this->public;
  742. }
  743. /**
  744. * See header
  745. */
  746. void backtrace_dump(char *label, FILE *file, bool detailed)
  747. {
  748. backtrace_t *backtrace;
  749. backtrace = backtrace_create(2);
  750. if (label)
  751. {
  752. println(file, "Debug backtrace: %s", label);
  753. }
  754. backtrace->log(backtrace, file, detailed);
  755. backtrace->destroy(backtrace);
  756. }