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>