123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868 |
- /*
- * Copyright (C) 2006-2013 Martin Willi
- * HSR Hochschule fuer Technik Rapperswil
- * Copyright (C) 2013 revosec AG
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- */
- #define _GNU_SOURCE
- #ifdef HAVE_BACKTRACE
- # include <execinfo.h>
- #endif /* HAVE_BACKTRACE */
- #ifdef HAVE_DBGHELP
- # include <winsock2.h>
- # include <windows.h>
- # include <dbghelp.h>
- #endif /* HAVE_DBGHELP */
- #include <string.h>
- #include "backtrace.h"
- #include <utils/debug.h>
- #ifdef WIN32
- # include <psapi.h>
- /* missing in MinGW */
- #ifdef WIN64
- #ifndef GetModuleInformation
- WINBOOL K32GetModuleInformation(HANDLE hProcess, HMODULE hModule,
- LPMODULEINFO lpmodinfo, DWORD cb);
- #define GetModuleInformation K32GetModuleInformation
- #endif /* !GetModuleInformation */
- #ifndef GetModuleFileNameEx
- DWORD K32GetModuleFileNameExA(HANDLE hProcess, HMODULE hModule,
- LPTSTR lpFilename, DWORD nSize);
- #define GetModuleFileNameEx K32GetModuleFileNameExA
- #endif /* !GetModuleFileNameEx */
- #endif /* WIN64 */
- #endif
- typedef struct private_backtrace_t private_backtrace_t;
- /**
- * Private data of an backtrace_t object.
- */
- struct private_backtrace_t {
- /**
- * Public backtrace_t interface.
- */
- backtrace_t public;
- /**
- * Number of stacks frames obtained in stack_frames
- */
- int frame_count;
- /**
- * Recorded stack frames.
- */
- void *frames[];
- };
- /**
- * Forward declaration of method getter
- */
- static backtrace_t get_methods();
- /**
- * Write a format string with arguments to a FILE line, if it is NULL to DBG
- */
- static void println(FILE *file, char *format, ...)
- {
- char buf[512];
- va_list args;
- va_start(args, format);
- if (file)
- {
- vfprintf(file, format, args);
- fputs("\n", file);
- }
- else
- {
- vsnprintf(buf, sizeof(buf), format, args);
- DBG1(DBG_LIB, "%s", buf);
- }
- va_end(args);
- }
- /**
- * Same as tty_escape_get(), but for a potentially NULL FILE*
- */
- static inline char* esc(FILE *file, tty_escape_t escape)
- {
- if (file)
- {
- return tty_escape_get(fileno(file), escape);
- }
- return "";
- }
- #ifdef HAVE_DBGHELP
- #include <dbghelp.h>
- #include <threading/mutex.h>
- /**
- * Mutex to access non-thread-safe dbghelp functions
- */
- static mutex_t *dbghelp_mutex;
- void backtrace_init()
- {
- SymSetOptions(SYMOPT_LOAD_LINES);
- SymInitialize(GetCurrentProcess(), NULL, TRUE);
- dbghelp_mutex = mutex_create(MUTEX_TYPE_DEFAULT);
- }
- void backtrace_deinit()
- {
- dbghelp_mutex->destroy(dbghelp_mutex);
- SymCleanup(GetCurrentProcess());
- }
- #elif defined(HAVE_DLADDR) || defined(HAVE_BFD_H)
- #ifdef HAVE_DLADDR
- #include <dlfcn.h>
- #endif
- #ifdef HAVE_BFD_H
- #include <bfd.h>
- #include <collections/hashtable.h>
- #include <threading/mutex.h>
- /**
- * Hashtable-cached bfd handle
- */
- typedef struct {
- /** binary file name on disk */
- char *filename;
- /** bfd handle */
- bfd *abfd;
- /** loaded symbols */
- asymbol **syms;
- } bfd_entry_t;
- /**
- * Destroy a bfd_entry
- */
- static void bfd_entry_destroy(bfd_entry_t *this)
- {
- free(this->filename);
- free(this->syms);
- bfd_close(this->abfd);
- free(this);
- }
- /**
- * Data to pass to find_addr()
- */
- typedef struct {
- /** used bfd entry */
- bfd_entry_t *entry;
- /** backtrace address */
- bfd_vma vma;
- /** stream to log to */
- FILE *file;
- /** TRUE if complete */
- bool found;
- } bfd_find_data_t;
- /**
- * bfd entry cache
- */
- static hashtable_t *bfds;
- static mutex_t *bfd_mutex;
- /**
- * Hashtable hash function
- */
- static u_int bfd_hash(char *key)
- {
- return chunk_hash(chunk_create(key, strlen(key)));
- }
- /**
- * Hashtable equals function
- */
- static bool bfd_equals(char *a, char *b)
- {
- return streq(a, b);
- }
- /**
- * See header.
- */
- void backtrace_init()
- {
- bfd_init();
- bfds = hashtable_create((hashtable_hash_t)bfd_hash,
- (hashtable_equals_t)bfd_equals, 8);
- bfd_mutex = mutex_create(MUTEX_TYPE_DEFAULT);
- }
- /**
- * See header.
- */
- void backtrace_deinit()
- {
- enumerator_t *enumerator;
- bfd_entry_t *entry;
- char *key;
- enumerator = bfds->create_enumerator(bfds);
- while (enumerator->enumerate(enumerator, &key, &entry))
- {
- bfds->remove_at(bfds, enumerator);
- bfd_entry_destroy(entry);
- }
- enumerator->destroy(enumerator);
- bfds->destroy(bfds);
- bfd_mutex->destroy(bfd_mutex);
- }
- /**
- * Find and print information to an address
- */
- static void find_addr(bfd *abfd, asection *section, bfd_find_data_t *data)
- {
- bfd_size_type size;
- bfd_vma vma;
- const char *source;
- const char *function;
- char fbuf[512] = "", sbuf[512] = "";
- u_int line;
- if (!data->found || (bfd_get_section_flags(abfd, section) & SEC_ALLOC) != 0)
- {
- vma = bfd_get_section_vma(abfd, section);
- if (data->vma >= vma)
- {
- size = bfd_get_section_size(section);
- if (data->vma < vma + size)
- {
- data->found = bfd_find_nearest_line(abfd, section,
- data->entry->syms, data->vma - vma,
- &source, &function, &line);
- if (data->found)
- {
- if (source || function)
- {
- if (function)
- {
- snprintf(fbuf, sizeof(fbuf), "%s%s() ",
- esc(data->file, TTY_FG_BLUE), function);
- }
- if (source)
- {
- snprintf(sbuf, sizeof(sbuf), "%s@ %s:%d",
- esc(data->file, TTY_FG_GREEN), source, line);
- }
- println(data->file, " -> %s%s%s", fbuf, sbuf,
- esc(data->file, TTY_FG_DEF));
- }
- }
- }
- }
- }
- }
- /**
- * Find a cached bfd entry, create'n'cache if not found
- */
- static bfd_entry_t *get_bfd_entry(char *filename)
- {
- bool dynamic = FALSE, ok = FALSE;
- bfd_entry_t *entry;
- long size;
- /* check cache */
- entry = bfds->get(bfds, filename);
- if (entry)
- {
- return entry;
- }
- INIT(entry,
- .abfd = bfd_openr(filename, NULL),
- );
- if (!entry->abfd)
- {
- free(entry);
- return NULL;
- }
- #ifdef BFD_DECOMPRESS
- entry->abfd->flags |= BFD_DECOMPRESS;
- #endif
- if (bfd_check_format(entry->abfd, bfd_archive) == 0 &&
- bfd_check_format_matches(entry->abfd, bfd_object, NULL))
- {
- if (bfd_get_file_flags(entry->abfd) & HAS_SYMS)
- {
- size = bfd_get_symtab_upper_bound(entry->abfd);
- if (size == 0)
- {
- size = bfd_get_dynamic_symtab_upper_bound(entry->abfd);
- dynamic = TRUE;
- }
- if (size >= 0)
- {
- entry->syms = malloc(size);
- if (dynamic)
- {
- ok = bfd_canonicalize_dynamic_symtab(entry->abfd,
- entry->syms) >= 0;
- }
- else
- {
- ok = bfd_canonicalize_symtab(entry->abfd,
- entry->syms) >= 0;
- }
- }
- }
- }
- if (ok)
- {
- entry->filename = strdup(filename);
- bfds->put(bfds, entry->filename, entry);
- return entry;
- }
- bfd_entry_destroy(entry);
- return NULL;
- }
- /**
- * Print the source file with line number to file, libbfd variant
- */
- static void print_sourceline(FILE *file, char *filename, void *ptr, void *base)
- {
- bfd_entry_t *entry;
- bfd_find_data_t data = {
- .file = file,
- .vma = (uintptr_t)ptr,
- };
- bool old = FALSE;
- bfd_mutex->lock(bfd_mutex);
- if (lib && lib->leak_detective)
- {
- old = lib->leak_detective->set_state(lib->leak_detective, FALSE);
- }
- entry = get_bfd_entry(filename);
- if (entry)
- {
- data.entry = entry;
- bfd_map_over_sections(entry->abfd, (void*)find_addr, &data);
- }
- if (lib && lib->leak_detective)
- {
- lib->leak_detective->set_state(lib->leak_detective, old);
- }
- bfd_mutex->unlock(bfd_mutex);
- }
- #else /* !HAVE_BFD_H */
- void backtrace_init() {}
- void backtrace_deinit() {}
- /**
- * Print the source file with line number to file, slow addr2line variant
- */
- static void print_sourceline(FILE *file, char *filename, void *ptr, void* base)
- {
- char buf[1024];
- FILE *output;
- int c, i = 0;
- #ifdef __APPLE__
- snprintf(buf, sizeof(buf), "atos -o %s -l %p %p 2>&1 | tail -n1",
- filename, base, ptr);
- #else /* !__APPLE__ */
- snprintf(buf, sizeof(buf), "addr2line -e %s %p", filename, ptr);
- #endif /* __APPLE__ */
- output = popen(buf, "r");
- if (output)
- {
- while (i < sizeof(buf))
- {
- c = getc(output);
- if (c == '\n' || c == EOF)
- {
- buf[i++] = 0;
- break;
- }
- buf[i++] = c;
- }
- pclose(output);
- println(file, " -> %s%s%s", esc(file, TTY_FG_GREEN), buf,
- esc(file, TTY_FG_DEF));
- }
- }
- #endif /* HAVE_BFD_H */
- #else /* !HAVE_DLADDR && !HAVE_DBGHELP */
- void backtrace_init() {}
- void backtrace_deinit() {}
- #endif /* HAVE_DLADDR */
- METHOD(backtrace_t, log_, void,
- private_backtrace_t *this, FILE *file, bool detailed)
- {
- #if defined(HAVE_BACKTRACE) || defined(HAVE_LIBUNWIND_H) || defined(WIN32)
- size_t i;
- char **strings = NULL;
- println(file, " dumping %d stack frame addresses:", this->frame_count);
- for (i = 0; i < this->frame_count; i++)
- {
- #ifdef HAVE_DLADDR
- Dl_info info;
- if (dladdr(this->frames[i], &info))
- {
- void *ptr = this->frames[i];
- if (strstr(info.dli_fname, ".so"))
- {
- ptr = (void*)(this->frames[i] - info.dli_fbase);
- }
- if (info.dli_sname)
- {
- println(file, " %s%s%s @ %p (%s%s%s+0x%tx) [%p]",
- esc(file, TTY_FG_YELLOW), info.dli_fname,
- esc(file, TTY_FG_DEF), info.dli_fbase,
- esc(file, TTY_FG_RED), info.dli_sname,
- esc(file, TTY_FG_DEF), this->frames[i] - info.dli_saddr,
- this->frames[i]);
- }
- else
- {
- println(file, " %s%s%s @ %p [%p]",
- esc(file, TTY_FG_YELLOW), info.dli_fname,
- esc(file, TTY_FG_DEF), info.dli_fbase, this->frames[i]);
- }
- if (detailed && info.dli_fname[0])
- {
- print_sourceline(file, (char*)info.dli_fname,
- ptr, info.dli_fbase);
- }
- }
- else
- #elif defined(HAVE_DBGHELP)
- struct {
- SYMBOL_INFO hdr;
- char buf[128];
- } symbol;
- char filename[MAX_PATH];
- HINSTANCE module;
- HANDLE process;
- DWORD64 displace, frame;
- process = GetCurrentProcess();
- frame = (uintptr_t)this->frames[i];
- memset(&symbol, 0, sizeof(symbol));
- symbol.hdr.SizeOfStruct = sizeof(symbol.hdr);
- symbol.hdr.MaxNameLen = sizeof(symbol.buf) - 1;
- dbghelp_mutex->lock(dbghelp_mutex);
- module = (HINSTANCE)SymGetModuleBase64(process, frame);
- if (module && GetModuleFileName(module, filename, sizeof(filename)))
- {
- if (SymFromAddr(process, frame, &displace, &symbol.hdr))
- {
- println(file, " %s%s%s @ %p (%s%s%s+0x%tx) [%p]",
- esc(file, TTY_FG_YELLOW), filename,
- esc(file, TTY_FG_DEF), (void*)module,
- esc(file, TTY_FG_RED), symbol.hdr.Name,
- esc(file, TTY_FG_DEF), displace,
- this->frames[i]);
- }
- else
- {
- println(file, " %s%s%s @ %p [%p]",
- esc(file, TTY_FG_YELLOW), filename,
- esc(file, TTY_FG_DEF), (void*)module, this->frames[i]);
- }
- if (detailed)
- {
- IMAGEHLP_LINE64 line;
- DWORD off;
- memset(&line, 0, sizeof(line));
- line.SizeOfStruct = sizeof(line);
- if (SymGetLineFromAddr64(process, frame, &off, &line))
- {
- println(file, " -> %s%s:%u%s", esc(file, TTY_FG_GREEN),
- line.FileName, line.LineNumber,
- esc(file, TTY_FG_DEF));
- }
- }
- }
- else
- #elif defined(WIN32)
- HMODULE module;
- MODULEINFO info;
- char filename[MAX_PATH];
- if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
- this->frames[i], &module) &&
- GetModuleInformation(GetCurrentProcess(), module,
- &info, sizeof(info)) &&
- GetModuleFileNameEx(GetCurrentProcess(), module,
- filename, sizeof(filename)))
- {
- println(file, " %s%s%s @ %p [%p]",
- esc(file, TTY_FG_YELLOW), filename,
- esc(file, TTY_FG_DEF), info.lpBaseOfDll, this->frames[i]);
- #ifdef HAVE_BFD_H
- print_sourceline(file, filename, this->frames[i], info.lpBaseOfDll);
- #endif /* HAVE_BFD_H */
- }
- else
- #endif /* HAVE_DLADDR/HAVE_DBGHELP */
- {
- #ifdef HAVE_BACKTRACE
- if (!strings)
- {
- strings = backtrace_symbols(this->frames, this->frame_count);
- }
- if (strings)
- {
- println(file, " %s", strings[i]);
- }
- else
- #endif /* HAVE_BACKTRACE */
- {
- println(file, " %p", this->frames[i]);
- }
- }
- #ifdef HAVE_DBGHELP
- dbghelp_mutex->unlock(dbghelp_mutex);
- #endif
- }
- free(strings);
- #else /* !HAVE_BACKTRACE && !HAVE_LIBUNWIND_H */
- println(file, "no support for capturing backtraces");
- #endif /* HAVE_BACKTRACE/HAVE_LIBUNWIND_H */
- }
- METHOD(backtrace_t, contains_function, bool,
- private_backtrace_t *this, char *function[], int count)
- {
- #ifdef HAVE_DLADDR
- int i, j;
- for (i = 0; i< this->frame_count; i++)
- {
- Dl_info info;
- if (dladdr(this->frames[i], &info) && info.dli_sname)
- {
- for (j = 0; j < count; j++)
- {
- if (streq(info.dli_sname, function[j]))
- {
- return TRUE;
- }
- }
- }
- }
- #elif defined(HAVE_DBGHELP)
- int i, j;
- HANDLE process;
- process = GetCurrentProcess();
- dbghelp_mutex->lock(dbghelp_mutex);
- for (i = 0; i < this->frame_count; i++)
- {
- struct {
- SYMBOL_INFO hdr;
- char buf[128];
- } symbol;
- memset(&symbol, 0, sizeof(symbol));
- symbol.hdr.SizeOfStruct = sizeof(symbol.hdr);
- symbol.hdr.MaxNameLen = sizeof(symbol.buf) - 1;
- if (SymFromAddr(process, (DWORD64)this->frames[i], NULL, &symbol.hdr))
- {
- for (j = 0; j < count; j++)
- {
- if (streq(symbol.hdr.Name, function[j]))
- {
- dbghelp_mutex->unlock(dbghelp_mutex);
- return TRUE;
- }
- }
- }
- }
- dbghelp_mutex->unlock(dbghelp_mutex);
- #endif /* HAVE_DLADDR/HAVE_DBGHELP */
- return FALSE;
- }
- METHOD(backtrace_t, equals, bool,
- private_backtrace_t *this, backtrace_t *other_public)
- {
- private_backtrace_t *other = (private_backtrace_t*)other_public;
- int i;
- if (this == other)
- {
- return TRUE;
- }
- if (this->frame_count != other->frame_count)
- {
- return FALSE;
- }
- for (i = 0; i < this->frame_count; i++)
- {
- if (this->frames[i] != other->frames[i])
- {
- return FALSE;
- }
- }
- return TRUE;
- }
- /**
- * Frame enumerator
- */
- typedef struct {
- /** implements enumerator_t */
- enumerator_t public;
- /** reference to backtrace */
- private_backtrace_t *bt;
- /** current position */
- int i;
- } frame_enumerator_t;
- METHOD(enumerator_t, frame_enumerate, bool,
- frame_enumerator_t *this, va_list args)
- {
- void **addr;
- VA_ARGS_VGET(args, addr);
- if (this->i < this->bt->frame_count)
- {
- *addr = this->bt->frames[this->i++];
- return TRUE;
- }
- return FALSE;
- }
- METHOD(backtrace_t, create_frame_enumerator, enumerator_t*,
- private_backtrace_t *this)
- {
- frame_enumerator_t *enumerator;
- INIT(enumerator,
- .public = {
- .enumerate = enumerator_enumerate_default,
- .venumerate = _frame_enumerate,
- .destroy = (void*)free,
- },
- .bt = this,
- );
- return &enumerator->public;
- }
- METHOD(backtrace_t, clone_, backtrace_t*,
- private_backtrace_t *this)
- {
- private_backtrace_t *clone;
- clone = malloc(sizeof(private_backtrace_t) +
- this->frame_count * sizeof(void*));
- memcpy(clone->frames, this->frames, this->frame_count * sizeof(void*));
- clone->frame_count = this->frame_count;
- clone->public = get_methods();
- return &clone->public;
- }
- METHOD(backtrace_t, destroy, void,
- private_backtrace_t *this)
- {
- free(this);
- }
- #ifdef HAVE_LIBUNWIND_H
- #define UNW_LOCAL_ONLY
- #include <libunwind.h>
- /**
- * libunwind variant for glibc backtrace()
- */
- static inline int backtrace_unwind(void **frames, int count)
- {
- unw_context_t context;
- unw_cursor_t cursor;
- unw_word_t ip;
- int depth = 0;
- unw_getcontext(&context);
- unw_init_local(&cursor, &context);
- do
- {
- unw_get_reg(&cursor, UNW_REG_IP, &ip);
- frames[depth++] = (void*)ip;
- }
- while (depth < count && unw_step(&cursor) > 0);
- return depth;
- }
- #endif /* HAVE_UNWIND */
- #ifdef HAVE_DBGHELP
- /**
- * Windows dbghelp variant for glibc backtrace()
- */
- static inline int backtrace_win(void **frames, int count)
- {
- STACKFRAME frame;
- HANDLE process, thread;
- DWORD machine;
- CONTEXT context;
- int got = 0;
- memset(&frame, 0, sizeof(frame));
- memset(&context, 0, sizeof(context));
- process = GetCurrentProcess();
- thread = GetCurrentThread();
- #ifdef __x86_64
- machine = IMAGE_FILE_MACHINE_AMD64;
- frame.AddrPC.Offset = context.Rip;
- frame.AddrPC.Mode = AddrModeFlat;
- frame.AddrStack.Offset = context.Rsp;
- frame.AddrStack.Mode = AddrModeFlat;
- frame.AddrFrame.Offset = context.Rbp;
- frame.AddrFrame.Mode = AddrModeFlat;
- #else /* x86 */
- machine = IMAGE_FILE_MACHINE_I386;
- frame.AddrPC.Offset = context.Eip;
- frame.AddrPC.Mode = AddrModeFlat;
- frame.AddrStack.Offset = context.Esp;
- frame.AddrStack.Mode = AddrModeFlat;
- frame.AddrFrame.Offset = context.Ebp;
- frame.AddrFrame.Mode = AddrModeFlat;
- #endif /* x86_64/x86 */
- dbghelp_mutex->lock(dbghelp_mutex);
- RtlCaptureContext(&context);
- while (got < count)
- {
- if (!StackWalk64(machine, process, thread, &frame, &context,
- NULL, SymFunctionTableAccess, SymGetModuleBase, NULL))
- {
- break;
- }
- frames[got++] = (void*)frame.AddrPC.Offset;
- }
- dbghelp_mutex->unlock(dbghelp_mutex);
- return got;
- }
- #endif /* HAVE_DBGHELP */
- /**
- * Get implementation methods of backtrace_t
- */
- static backtrace_t get_methods()
- {
- return (backtrace_t) {
- .log = _log_,
- .contains_function = _contains_function,
- .equals = _equals,
- .clone = _clone_,
- .create_frame_enumerator = _create_frame_enumerator,
- .destroy = _destroy,
- };
- }
- /**
- * See header
- */
- backtrace_t *backtrace_create(int skip)
- {
- private_backtrace_t *this;
- void *frames[50];
- int frame_count = 0;
- #ifdef HAVE_LIBUNWIND_H
- frame_count = backtrace_unwind(frames, countof(frames));
- #elif defined(HAVE_BACKTRACE)
- frame_count = backtrace(frames, countof(frames));
- #elif defined(HAVE_DBGHELP)
- frame_count = backtrace_win(frames, countof(frames));
- #elif defined(WIN32)
- frame_count = CaptureStackBackTrace(skip, countof(frames), frames, NULL);
- skip = 0;
- #endif
- frame_count = max(frame_count - skip, 0);
- this = malloc(sizeof(private_backtrace_t) + frame_count * sizeof(void*));
- memcpy(this->frames, frames + skip, frame_count * sizeof(void*));
- this->frame_count = frame_count;
- this->public = get_methods();
- return &this->public;
- }
- /**
- * See header
- */
- void backtrace_dump(char *label, FILE *file, bool detailed)
- {
- backtrace_t *backtrace;
- backtrace = backtrace_create(2);
- if (label)
- {
- println(file, "Debug backtrace: %s", label);
- }
- backtrace->log(backtrace, file, detailed);
- backtrace->destroy(backtrace);
- }
|