backtrace: Remove name checks after SymFromAddr() calls
[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 {
497 println(file, " %s%s%s @ %p (%s%s%s+0x%tx) [%p]",
498 esc(file, TTY_FG_YELLOW), filename,
499 esc(file, TTY_FG_DEF), (void*)module,
500 esc(file, TTY_FG_RED), symbol.hdr.Name,
501 esc(file, TTY_FG_DEF), displace,
502 this->frames[i]);
503 }
504 else
505 {
506 println(file, " %s%s%s @ %p [%p]",
507 esc(file, TTY_FG_YELLOW), filename,
508 esc(file, TTY_FG_DEF), (void*)module, this->frames[i]);
509 }
510 if (detailed)
511 {
512 IMAGEHLP_LINE64 line;
513 DWORD off;
514
515 memset(&line, 0, sizeof(line));
516 line.SizeOfStruct = sizeof(line);
517
518 if (SymGetLineFromAddr64(process, frame, &off, &line))
519 {
520
521 println(file, " -> %s%s:%u%s", esc(file, TTY_FG_GREEN),
522 line.FileName, line.LineNumber,
523 esc(file, TTY_FG_DEF));
524 }
525 }
526 }
527 else
528 #elif defined(WIN32)
529 HMODULE module;
530 MODULEINFO info;
531 char filename[MAX_PATH];
532
533 if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
534 this->frames[i], &module) &&
535 GetModuleInformation(GetCurrentProcess(), module,
536 &info, sizeof(info)) &&
537 GetModuleFileNameEx(GetCurrentProcess(), module,
538 filename, sizeof(filename)))
539 {
540 println(file, " %s%s%s @ %p [%p]",
541 esc(file, TTY_FG_YELLOW), filename,
542 esc(file, TTY_FG_DEF), info.lpBaseOfDll, this->frames[i]);
543 #ifdef HAVE_BFD_H
544 print_sourceline(file, filename, this->frames[i], info.lpBaseOfDll);
545 #endif /* HAVE_BFD_H */
546 }
547 else
548 #endif /* HAVE_DLADDR/HAVE_DBGHELP */
549 {
550 #ifdef HAVE_BACKTRACE
551 if (!strings)
552 {
553 strings = backtrace_symbols(this->frames, this->frame_count);
554 }
555 if (strings)
556 {
557 println(file, " %s", strings[i]);
558 }
559 else
560 #endif /* HAVE_BACKTRACE */
561 {
562 println(file, " %p", this->frames[i]);
563 }
564 }
565 #ifdef HAVE_DBGHELP
566 dbghelp_mutex->unlock(dbghelp_mutex);
567 #endif
568 }
569 free(strings);
570 #else /* !HAVE_BACKTRACE && !HAVE_LIBUNWIND_H */
571 println(file, "no support for capturing backtraces");
572 #endif /* HAVE_BACKTRACE/HAVE_LIBUNWIND_H */
573 }
574
575 METHOD(backtrace_t, contains_function, bool,
576 private_backtrace_t *this, char *function[], int count)
577 {
578 #ifdef HAVE_DLADDR
579 int i, j;
580
581 for (i = 0; i< this->frame_count; i++)
582 {
583 Dl_info info;
584
585 if (dladdr(this->frames[i], &info) && info.dli_sname)
586 {
587 for (j = 0; j < count; j++)
588 {
589 if (streq(info.dli_sname, function[j]))
590 {
591 return TRUE;
592 }
593 }
594 }
595 }
596 #elif defined(HAVE_DBGHELP)
597 int i, j;
598 HANDLE process;
599
600 process = GetCurrentProcess();
601
602 dbghelp_mutex->lock(dbghelp_mutex);
603
604 for (i = 0; i < this->frame_count; i++)
605 {
606 struct {
607 SYMBOL_INFO hdr;
608 char buf[128];
609 } symbol;
610
611 memset(&symbol, 0, sizeof(symbol));
612 symbol.hdr.SizeOfStruct = sizeof(symbol.hdr);
613 symbol.hdr.MaxNameLen = sizeof(symbol.buf) - 1;
614
615 if (SymFromAddr(process, (DWORD64)this->frames[i], NULL, &symbol.hdr))
616 {
617 for (j = 0; j < count; j++)
618 {
619 if (streq(symbol.hdr.Name, function[j]))
620 {
621 dbghelp_mutex->unlock(dbghelp_mutex);
622 return TRUE;
623 }
624 }
625 }
626 }
627
628 dbghelp_mutex->unlock(dbghelp_mutex);
629 #endif /* HAVE_DLADDR/HAVE_DBGHELP */
630 return FALSE;
631 }
632
633 METHOD(backtrace_t, equals, bool,
634 private_backtrace_t *this, backtrace_t *other_public)
635 {
636 private_backtrace_t *other = (private_backtrace_t*)other_public;
637 int i;
638
639 if (this == other)
640 {
641 return TRUE;
642 }
643 if (this->frame_count != other->frame_count)
644 {
645 return FALSE;
646 }
647 for (i = 0; i < this->frame_count; i++)
648 {
649 if (this->frames[i] != other->frames[i])
650 {
651 return FALSE;
652 }
653 }
654 return TRUE;
655 }
656
657 /**
658 * Frame enumerator
659 */
660 typedef struct {
661 /** implements enumerator_t */
662 enumerator_t public;
663 /** reference to backtrace */
664 private_backtrace_t *bt;
665 /** current position */
666 int i;
667 } frame_enumerator_t;
668
669 METHOD(enumerator_t, frame_enumerate, bool,
670 frame_enumerator_t *this, void **addr)
671 {
672 if (this->i < this->bt->frame_count)
673 {
674 *addr = this->bt->frames[this->i++];
675 return TRUE;
676 }
677 return FALSE;
678 }
679
680 METHOD(backtrace_t, create_frame_enumerator, enumerator_t*,
681 private_backtrace_t *this)
682 {
683 frame_enumerator_t *enumerator;
684
685 INIT(enumerator,
686 .public = {
687 .enumerate = (void*)_frame_enumerate,
688 .destroy = (void*)free,
689 },
690 .bt = this,
691 );
692 return &enumerator->public;
693 }
694
695 METHOD(backtrace_t, clone_, backtrace_t*,
696 private_backtrace_t *this)
697 {
698 private_backtrace_t *clone;
699
700 clone = malloc(sizeof(private_backtrace_t) +
701 this->frame_count * sizeof(void*));
702 memcpy(clone->frames, this->frames, this->frame_count * sizeof(void*));
703 clone->frame_count = this->frame_count;
704
705 clone->public = get_methods();
706
707 return &clone->public;
708 }
709
710 METHOD(backtrace_t, destroy, void,
711 private_backtrace_t *this)
712 {
713 free(this);
714 }
715
716 #ifdef HAVE_LIBUNWIND_H
717 #define UNW_LOCAL_ONLY
718 #include <libunwind.h>
719
720 /**
721 * libunwind variant for glibc backtrace()
722 */
723 static inline int backtrace_unwind(void **frames, int count)
724 {
725 unw_context_t context;
726 unw_cursor_t cursor;
727 unw_word_t ip;
728 int depth = 0;
729
730 unw_getcontext(&context);
731 unw_init_local(&cursor, &context);
732 do
733 {
734 unw_get_reg(&cursor, UNW_REG_IP, &ip);
735 frames[depth++] = (void*)ip;
736 }
737 while (depth < count && unw_step(&cursor) > 0);
738
739 return depth;
740 }
741 #endif /* HAVE_UNWIND */
742
743 #ifdef HAVE_DBGHELP
744
745 /**
746 * Windows dbghelp variant for glibc backtrace()
747 */
748 static inline int backtrace_win(void **frames, int count)
749 {
750 STACKFRAME frame;
751 HANDLE process, thread;
752 DWORD machine;
753 CONTEXT context;
754 int got = 0;
755
756 memset(&frame, 0, sizeof(frame));
757 memset(&context, 0, sizeof(context));
758
759 process = GetCurrentProcess();
760 thread = GetCurrentThread();
761
762 #ifdef __x86_64
763 machine = IMAGE_FILE_MACHINE_AMD64;
764
765 frame.AddrPC.Offset = context.Rip;
766 frame.AddrPC.Mode = AddrModeFlat;
767 frame.AddrStack.Offset = context.Rsp;
768 frame.AddrStack.Mode = AddrModeFlat;
769 frame.AddrFrame.Offset = context.Rbp;
770 frame.AddrFrame.Mode = AddrModeFlat;
771 #else /* x86 */
772 machine = IMAGE_FILE_MACHINE_I386;
773
774 frame.AddrPC.Offset = context.Eip;
775 frame.AddrPC.Mode = AddrModeFlat;
776 frame.AddrStack.Offset = context.Esp;
777 frame.AddrStack.Mode = AddrModeFlat;
778 frame.AddrFrame.Offset = context.Ebp;
779 frame.AddrFrame.Mode = AddrModeFlat;
780 #endif /* x86_64/x86 */
781
782 dbghelp_mutex->lock(dbghelp_mutex);
783
784 RtlCaptureContext(&context);
785
786 while (got < count)
787 {
788 if (!StackWalk64(machine, process, thread, &frame, &context,
789 NULL, SymFunctionTableAccess, SymGetModuleBase, NULL))
790 {
791 break;
792 }
793 frames[got++] = (void*)frame.AddrPC.Offset;
794 }
795
796 dbghelp_mutex->unlock(dbghelp_mutex);
797
798 return got;
799 }
800
801 #endif /* HAVE_DBGHELP */
802
803 /**
804 * Get implementation methods of backtrace_t
805 */
806 static backtrace_t get_methods()
807 {
808 return (backtrace_t) {
809 .log = _log_,
810 .contains_function = _contains_function,
811 .equals = _equals,
812 .clone = _clone_,
813 .create_frame_enumerator = _create_frame_enumerator,
814 .destroy = _destroy,
815 };
816 }
817
818 /**
819 * See header
820 */
821 backtrace_t *backtrace_create(int skip)
822 {
823 private_backtrace_t *this;
824 void *frames[50];
825 int frame_count = 0;
826
827 #ifdef HAVE_LIBUNWIND_H
828 frame_count = backtrace_unwind(frames, countof(frames));
829 #elif defined(HAVE_BACKTRACE)
830 frame_count = backtrace(frames, countof(frames));
831 #elif defined(HAVE_DBGHELP)
832 frame_count = backtrace_win(frames, countof(frames));
833 #elif defined(WIN32)
834 frame_count = CaptureStackBackTrace(skip, countof(frames), frames, NULL);
835 skip = 0;
836 #endif
837 frame_count = max(frame_count - skip, 0);
838 this = malloc(sizeof(private_backtrace_t) + frame_count * sizeof(void*));
839 memcpy(this->frames, frames + skip, frame_count * sizeof(void*));
840 this->frame_count = frame_count;
841
842 this->public = get_methods();
843
844 return &this->public;
845 }
846
847 /**
848 * See header
849 */
850 void backtrace_dump(char *label, FILE *file, bool detailed)
851 {
852 backtrace_t *backtrace;
853
854 backtrace = backtrace_create(2);
855
856 if (label)
857 {
858 println(file, "Debug backtrace: %s", label);
859 }
860 backtrace->log(backtrace, file, detailed);
861 backtrace->destroy(backtrace);
862 }