Annotation of embedaddon/strongswan/src/libstrongswan/utils/backtrace.c, revision 1.1.1.1
1.1 misho 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:
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: dynamic = TRUE;
323: }
324: if (size >= 0)
325: {
326: entry->syms = malloc(size);
327: if (dynamic)
328: {
329: ok = bfd_canonicalize_dynamic_symtab(entry->abfd,
330: entry->syms) >= 0;
331: }
332: else
333: {
334: ok = bfd_canonicalize_symtab(entry->abfd,
335: entry->syms) >= 0;
336: }
337: }
338: }
339: }
340: if (ok)
341: {
342: entry->filename = strdup(filename);
343: bfds->put(bfds, entry->filename, entry);
344: return entry;
345: }
346: bfd_entry_destroy(entry);
347: return NULL;
348: }
349:
350: /**
351: * Print the source file with line number to file, libbfd variant
352: */
353: static void print_sourceline(FILE *file, char *filename, void *ptr, void *base)
354: {
355: bfd_entry_t *entry;
356: bfd_find_data_t data = {
357: .file = file,
358: .vma = (uintptr_t)ptr,
359: };
360: bool old = FALSE;
361:
362: bfd_mutex->lock(bfd_mutex);
363: if (lib && lib->leak_detective)
364: {
365: old = lib->leak_detective->set_state(lib->leak_detective, FALSE);
366: }
367: entry = get_bfd_entry(filename);
368: if (entry)
369: {
370: data.entry = entry;
371: bfd_map_over_sections(entry->abfd, (void*)find_addr, &data);
372: }
373: if (lib && lib->leak_detective)
374: {
375: lib->leak_detective->set_state(lib->leak_detective, old);
376: }
377: bfd_mutex->unlock(bfd_mutex);
378: }
379:
380: #else /* !HAVE_BFD_H */
381:
382: void backtrace_init() {}
383: void backtrace_deinit() {}
384:
385: /**
386: * Print the source file with line number to file, slow addr2line variant
387: */
388: static void print_sourceline(FILE *file, char *filename, void *ptr, void* base)
389: {
390: char buf[1024];
391: FILE *output;
392: int c, i = 0;
393:
394: #ifdef __APPLE__
395: snprintf(buf, sizeof(buf), "atos -o %s -l %p %p 2>&1 | tail -n1",
396: filename, base, ptr);
397: #else /* !__APPLE__ */
398: snprintf(buf, sizeof(buf), "addr2line -e %s %p", filename, ptr);
399: #endif /* __APPLE__ */
400:
401: output = popen(buf, "r");
402: if (output)
403: {
404: while (i < sizeof(buf))
405: {
406: c = getc(output);
407: if (c == '\n' || c == EOF)
408: {
409: buf[i++] = 0;
410: break;
411: }
412: buf[i++] = c;
413: }
414: pclose(output);
415:
416: println(file, " -> %s%s%s", esc(file, TTY_FG_GREEN), buf,
417: esc(file, TTY_FG_DEF));
418: }
419: }
420:
421: #endif /* HAVE_BFD_H */
422:
423: #else /* !HAVE_DLADDR && !HAVE_DBGHELP */
424:
425: void backtrace_init() {}
426: void backtrace_deinit() {}
427:
428: #endif /* HAVE_DLADDR */
429:
430: METHOD(backtrace_t, log_, void,
431: private_backtrace_t *this, FILE *file, bool detailed)
432: {
433: #if defined(HAVE_BACKTRACE) || defined(HAVE_LIBUNWIND_H) || defined(WIN32)
434: size_t i;
435: char **strings = NULL;
436:
437: println(file, " dumping %d stack frame addresses:", this->frame_count);
438: for (i = 0; i < this->frame_count; i++)
439: {
440: #ifdef HAVE_DLADDR
441: Dl_info info;
442:
443: if (dladdr(this->frames[i], &info))
444: {
445: void *ptr = this->frames[i];
446:
447: if (strstr(info.dli_fname, ".so"))
448: {
449: ptr = (void*)(this->frames[i] - info.dli_fbase);
450: }
451: if (info.dli_sname)
452: {
453: println(file, " %s%s%s @ %p (%s%s%s+0x%tx) [%p]",
454: esc(file, TTY_FG_YELLOW), info.dli_fname,
455: esc(file, TTY_FG_DEF), info.dli_fbase,
456: esc(file, TTY_FG_RED), info.dli_sname,
457: esc(file, TTY_FG_DEF), this->frames[i] - info.dli_saddr,
458: this->frames[i]);
459: }
460: else
461: {
462: println(file, " %s%s%s @ %p [%p]",
463: esc(file, TTY_FG_YELLOW), info.dli_fname,
464: esc(file, TTY_FG_DEF), info.dli_fbase, this->frames[i]);
465: }
466: if (detailed && info.dli_fname[0])
467: {
468: print_sourceline(file, (char*)info.dli_fname,
469: ptr, info.dli_fbase);
470: }
471: }
472: else
473: #elif defined(HAVE_DBGHELP)
474: struct {
475: SYMBOL_INFO hdr;
476: char buf[128];
477: } symbol;
478: char filename[MAX_PATH];
479: HINSTANCE module;
480: HANDLE process;
481: DWORD64 displace, frame;
482:
483: process = GetCurrentProcess();
484: frame = (uintptr_t)this->frames[i];
485:
486: memset(&symbol, 0, sizeof(symbol));
487: symbol.hdr.SizeOfStruct = sizeof(symbol.hdr);
488: symbol.hdr.MaxNameLen = sizeof(symbol.buf) - 1;
489:
490: dbghelp_mutex->lock(dbghelp_mutex);
491:
492: module = (HINSTANCE)SymGetModuleBase64(process, frame);
493:
494: if (module && GetModuleFileName(module, filename, sizeof(filename)))
495: {
496: if (SymFromAddr(process, frame, &displace, &symbol.hdr))
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: for (j = 0; j < count; j++)
619: {
620: if (streq(symbol.hdr.Name, function[j]))
621: {
622: dbghelp_mutex->unlock(dbghelp_mutex);
623: return TRUE;
624: }
625: }
626: }
627: }
628:
629: dbghelp_mutex->unlock(dbghelp_mutex);
630: #endif /* HAVE_DLADDR/HAVE_DBGHELP */
631: return FALSE;
632: }
633:
634: METHOD(backtrace_t, equals, bool,
635: private_backtrace_t *this, backtrace_t *other_public)
636: {
637: private_backtrace_t *other = (private_backtrace_t*)other_public;
638: int i;
639:
640: if (this == other)
641: {
642: return TRUE;
643: }
644: if (this->frame_count != other->frame_count)
645: {
646: return FALSE;
647: }
648: for (i = 0; i < this->frame_count; i++)
649: {
650: if (this->frames[i] != other->frames[i])
651: {
652: return FALSE;
653: }
654: }
655: return TRUE;
656: }
657:
658: /**
659: * Frame enumerator
660: */
661: typedef struct {
662: /** implements enumerator_t */
663: enumerator_t public;
664: /** reference to backtrace */
665: private_backtrace_t *bt;
666: /** current position */
667: int i;
668: } frame_enumerator_t;
669:
670: METHOD(enumerator_t, frame_enumerate, bool,
671: frame_enumerator_t *this, va_list args)
672: {
673: void **addr;
674:
675: VA_ARGS_VGET(args, addr);
676:
677: if (this->i < this->bt->frame_count)
678: {
679: *addr = this->bt->frames[this->i++];
680: return TRUE;
681: }
682: return FALSE;
683: }
684:
685: METHOD(backtrace_t, create_frame_enumerator, enumerator_t*,
686: private_backtrace_t *this)
687: {
688: frame_enumerator_t *enumerator;
689:
690: INIT(enumerator,
691: .public = {
692: .enumerate = enumerator_enumerate_default,
693: .venumerate = _frame_enumerate,
694: .destroy = (void*)free,
695: },
696: .bt = this,
697: );
698: return &enumerator->public;
699: }
700:
701: METHOD(backtrace_t, clone_, backtrace_t*,
702: private_backtrace_t *this)
703: {
704: private_backtrace_t *clone;
705:
706: clone = malloc(sizeof(private_backtrace_t) +
707: this->frame_count * sizeof(void*));
708: memcpy(clone->frames, this->frames, this->frame_count * sizeof(void*));
709: clone->frame_count = this->frame_count;
710:
711: clone->public = get_methods();
712:
713: return &clone->public;
714: }
715:
716: METHOD(backtrace_t, destroy, void,
717: private_backtrace_t *this)
718: {
719: free(this);
720: }
721:
722: #ifdef HAVE_LIBUNWIND_H
723: #define UNW_LOCAL_ONLY
724: #include <libunwind.h>
725:
726: /**
727: * libunwind variant for glibc backtrace()
728: */
729: static inline int backtrace_unwind(void **frames, int count)
730: {
731: unw_context_t context;
732: unw_cursor_t cursor;
733: unw_word_t ip;
734: int depth = 0;
735:
736: unw_getcontext(&context);
737: unw_init_local(&cursor, &context);
738: do
739: {
740: unw_get_reg(&cursor, UNW_REG_IP, &ip);
741: frames[depth++] = (void*)ip;
742: }
743: while (depth < count && unw_step(&cursor) > 0);
744:
745: return depth;
746: }
747: #endif /* HAVE_UNWIND */
748:
749: #ifdef HAVE_DBGHELP
750:
751: /**
752: * Windows dbghelp variant for glibc backtrace()
753: */
754: static inline int backtrace_win(void **frames, int count)
755: {
756: STACKFRAME frame;
757: HANDLE process, thread;
758: DWORD machine;
759: CONTEXT context;
760: int got = 0;
761:
762: memset(&frame, 0, sizeof(frame));
763: memset(&context, 0, sizeof(context));
764:
765: process = GetCurrentProcess();
766: thread = GetCurrentThread();
767:
768: #ifdef __x86_64
769: machine = IMAGE_FILE_MACHINE_AMD64;
770:
771: frame.AddrPC.Offset = context.Rip;
772: frame.AddrPC.Mode = AddrModeFlat;
773: frame.AddrStack.Offset = context.Rsp;
774: frame.AddrStack.Mode = AddrModeFlat;
775: frame.AddrFrame.Offset = context.Rbp;
776: frame.AddrFrame.Mode = AddrModeFlat;
777: #else /* x86 */
778: machine = IMAGE_FILE_MACHINE_I386;
779:
780: frame.AddrPC.Offset = context.Eip;
781: frame.AddrPC.Mode = AddrModeFlat;
782: frame.AddrStack.Offset = context.Esp;
783: frame.AddrStack.Mode = AddrModeFlat;
784: frame.AddrFrame.Offset = context.Ebp;
785: frame.AddrFrame.Mode = AddrModeFlat;
786: #endif /* x86_64/x86 */
787:
788: dbghelp_mutex->lock(dbghelp_mutex);
789:
790: RtlCaptureContext(&context);
791:
792: while (got < count)
793: {
794: if (!StackWalk64(machine, process, thread, &frame, &context,
795: NULL, SymFunctionTableAccess, SymGetModuleBase, NULL))
796: {
797: break;
798: }
799: frames[got++] = (void*)frame.AddrPC.Offset;
800: }
801:
802: dbghelp_mutex->unlock(dbghelp_mutex);
803:
804: return got;
805: }
806:
807: #endif /* HAVE_DBGHELP */
808:
809: /**
810: * Get implementation methods of backtrace_t
811: */
812: static backtrace_t get_methods()
813: {
814: return (backtrace_t) {
815: .log = _log_,
816: .contains_function = _contains_function,
817: .equals = _equals,
818: .clone = _clone_,
819: .create_frame_enumerator = _create_frame_enumerator,
820: .destroy = _destroy,
821: };
822: }
823:
824: /**
825: * See header
826: */
827: backtrace_t *backtrace_create(int skip)
828: {
829: private_backtrace_t *this;
830: void *frames[50];
831: int frame_count = 0;
832:
833: #ifdef HAVE_LIBUNWIND_H
834: frame_count = backtrace_unwind(frames, countof(frames));
835: #elif defined(HAVE_BACKTRACE)
836: frame_count = backtrace(frames, countof(frames));
837: #elif defined(HAVE_DBGHELP)
838: frame_count = backtrace_win(frames, countof(frames));
839: #elif defined(WIN32)
840: frame_count = CaptureStackBackTrace(skip, countof(frames), frames, NULL);
841: skip = 0;
842: #endif
843: frame_count = max(frame_count - skip, 0);
844: this = malloc(sizeof(private_backtrace_t) + frame_count * sizeof(void*));
845: memcpy(this->frames, frames + skip, frame_count * sizeof(void*));
846: this->frame_count = frame_count;
847:
848: this->public = get_methods();
849:
850: return &this->public;
851: }
852:
853: /**
854: * See header
855: */
856: void backtrace_dump(char *label, FILE *file, bool detailed)
857: {
858: backtrace_t *backtrace;
859:
860: backtrace = backtrace_create(2);
861:
862: if (label)
863: {
864: println(file, "Debug backtrace: %s", label);
865: }
866: backtrace->log(backtrace, file, detailed);
867: backtrace->destroy(backtrace);
868: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>