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