Annotation of embedaddon/strongswan/src/libstrongswan/utils/backtrace.c, revision 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>