• (zt)打印函数调用堆栈【转】


    转自:https://blog.csdn.net/csucrab/article/details/5675686

    强帖,简直是代码大全了,包括各种语言,后来还有来源,特别是C++的做法

    注:如果要在C++ Builder中使用的话,切记需要进行map2dbg的转换

    http://blog.csdn.net/chief1985/archive/2009/09/29/4618492.aspx

    java里面可以使用Throwable类来获取堆栈,示例代码如下:


    view plaincopy to clipboardprint?
    package name.xu;
    public class CallStack {
        public static void printCallStatck() {
            Throwable ex = new Throwable();
            StackTraceElement[] stackElements = ex.getStackTrace();
            if (stackElements != null) {
                for (int i = 0; i < stackElements.length; i++) {
                    System.out.print(stackElements[i].getClassName()+"/t");
                    System.out.print(stackElements[i].getFileName()+"/t");
                    System.out.print(stackElements[i].getLineNumber()+"/t");
                    System.out.println(stackElements[i].getMethodName());
                    System.out.println("-----------------------------------");
                }
            }
        }
         
    }


    C#里面使用与java类似的方法,示例代码如下:


    view plaincopy to clipboardprint?
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Diagnostics;
    namespace TestProjectCSharp
    {
        class CallStack
        {
            public static void printCallStack()
            {
                StackTrace ss = new StackTrace(true);
                String flName = ss.GetFrame(1).GetFileName();// GetMethod().DeclaringType;  
                int lineNo = ss.GetFrame(1).GetFileLineNumber();
                String methodName = ss.GetFrame(1).GetMethod().Name;
                Console.WriteLine(flName+"---"+lineNo+"---"+methodName);
            }
        }
    }

    c里面获取堆栈跟系统有关(主要是获取函数名称不一致,获取地址是一致的),

    linux下使用backtrace和backtrace_symbols函数,示例代码如下:(编译方法:gcc -o funstack -rdynamic -ldl funstack.c)


    view plaincopy to clipboardprint?
    //funstack.c
    #define _GNU_SOURCE
    #include <memory.h>
    #include <stdlib.h>
    #include <stdio.h>
    #include <signal.h>
    #include <ucontext.h>
    #include <dlfcn.h>
    #include <execinfo.h>
    #if defined(REG_RIP)
    # define SIGSEGV_STACK_IA64
    # define REGFORMAT "%016lx"
    #elif defined(REG_EIP)
    # define SIGSEGV_STACK_X86
    # define REGFORMAT "%08x"
    #else
    # define SIGSEGV_STACK_GENERIC
    # define REGFORMAT "%x"
    #endif
    static void signal_segv(int signum, siginfo_t* info, void*ptr) {
            static const char *si_codes[3] = {"", "SEGV_MAPERR", "SEGV_ACCERR"};
            size_t i;
            ucontext_t *ucontext = (ucontext_t*)ptr;
    #if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64)
            int f = 0;
            Dl_info dlinfo;
            void **bp = 0;
            void *ip = 0;
    #else
            void *bt[20];
            char **strings;
            size_t sz;
    #endif
    #if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64)
    # if defined(SIGSEGV_STACK_IA64)
            ip = (void*)ucontext->uc_mcontext.gregs[REG_RIP];
            bp = (void**)ucontext->uc_mcontext.gregs[REG_RBP];
    # elif defined(SIGSEGV_STACK_X86)
            ip = (void*)ucontext->uc_mcontext.gregs[REG_EIP];
            bp = (void**)ucontext->uc_mcontext.gregs[REG_EBP];
    # endif
            fprintf(stderr, "Stack trace:/n");
            while(bp && ip) {
                    if(!dladdr(ip, &dlinfo))
                            break;
                    const char *symname = dlinfo.dli_sname;
                    fprintf(stderr, "% 2d: %p %s+%u (%s)/n",
                                    ++f,
                                    ip,
                                    symname,
                                    (unsigned)(ip - dlinfo.dli_saddr),
                                    dlinfo.dli_fname);
                    if(dlinfo.dli_sname && !strcmp(dlinfo.dli_sname, "main"))
                            break;
                    ip = bp[1];
                    bp = (void**)bp[0];
            }
    #else
            fprintf(stderr, "Stack trace (non-dedicated):/n");
            sz = backtrace(bt, 20);
            strings = backtrace_symbols(bt, sz);
            for(i = 0; i < sz; ++i)
                    fprintf(stderr, "%s/n", strings[i]);
    #endif
            fprintf(stderr, "End of stack trace/n");
            return;
    }
    int setup_sigsegv() {
            struct sigaction action;
            memset(&action, 0, sizeof(action));
            action.sa_sigaction = signal_segv;
            action.sa_flags = SA_SIGINFO;
            if(sigaction(SIGUSR1, &action, NULL) < 0) {
                    perror("sigaction");
                    return 0;
            }
            return 1;
    }

    void func1()
    {
            raise(SIGUSR1);
            return ;
    }
    void func2()
    {
            raise(SIGUSR1);
            return ;
    }
    void entry()
    {
            func1();
            func2();
            return;
    }
    int main()
    {
            setup_sigsegv();
            entry();
    }

    windows下使用GetThreadContext ,StackWalk,SymGetOptions ,SymFunctionTableAccess,示例代码如下:


    view plaincopy to clipboardprint?
    #include "SimpleSymbolEngine.h"
    #include <windows.h>
    #include <psapi.h>
    #include <iostream>
    #include <sstream>
    #include <cstddef>
    #include <dbghelp.h>
    #pragma comment( lib, "dbghelp" )
    static char const szRCSID[] = "$Id: SimpleSymbolEngine.cpp,v 1.4 2005/05/04 21:52:05 Eleanor Exp $";
    //
    // Singleton for the engine (SymInitialize doesn't support multiple calls)
    SimpleSymbolEngine& SimpleSymbolEngine::instance()
    {
    static SimpleSymbolEngine theEngine;
        return theEngine;
    }
    /
    SimpleSymbolEngine::SimpleSymbolEngine()
    {
        hProcess = GetCurrentProcess();
        DWORD dwOpts = SymGetOptions();
        dwOpts |= SYMOPT_LOAD_LINES | SYMOPT_DEFERRED_LOADS;
        SymSetOptions ( dwOpts );
        ::SymInitialize( hProcess, 0, true );
    }
    /
    SimpleSymbolEngine::~SimpleSymbolEngine()
    {
        ::SymCleanup( hProcess );
    }
    /
    std::string SimpleSymbolEngine::addressToString( PVOID address )
    {
        std::ostringstream oss;
        // First the raw address
        oss << "0x" << address;
        // Then any name for the symbol
        struct tagSymInfo
        {
            IMAGEHLP_SYMBOL symInfo;
            char nameBuffer[ 4 * 256 ];
        } SymInfo = { { sizeof( IMAGEHLP_SYMBOL ) } };
        IMAGEHLP_SYMBOL * pSym = &SymInfo.symInfo;
        pSym->MaxNameLength = sizeof( SymInfo ) - offsetof( tagSymInfo, symInfo.Name );
        DWORD dwDisplacement;
        if ( SymGetSymFromAddr( hProcess, (DWORD)address, &dwDisplacement, pSym) )
        {
            oss << " " << pSym->Name;
            if ( dwDisplacement != 0 )
                oss << "+0x" << std::hex << dwDisplacement << std::dec;
        }
             
        // Finally any file/line number
        IMAGEHLP_LINE lineInfo = { sizeof( IMAGEHLP_LINE ) };
        if ( SymGetLineFromAddr( hProcess, (DWORD)address, &dwDisplacement, &lineInfo ) )
        {
            char const *pDelim = strrchr( lineInfo.FileName, '//' );
            oss << " at " << ( pDelim ? pDelim + 1 : lineInfo.FileName ) << "(" << lineInfo.LineNumber << ")";
        }
        return oss.str();
    }
    /
    // StackTrace: try to trace the stack to the given output
    void SimpleSymbolEngine::StackTrace( PCONTEXT pContext, std::ostream & os )
    {
        os << " Frame       Code address/n";
        STACKFRAME stackFrame = {0};
        stackFrame.AddrPC.Offset = pContext->Eip;
        stackFrame.AddrPC.Mode = AddrModeFlat;
        stackFrame.AddrFrame.Offset = pContext->Ebp;
        stackFrame.AddrFrame.Mode = AddrModeFlat;
        stackFrame.AddrStack.Offset = pContext->Esp;
        stackFrame.AddrStack.Mode = AddrModeFlat;
        while ( ::StackWalk(
           IMAGE_FILE_MACHINE_I386,
           hProcess,
           GetCurrentThread(), // this value doesn't matter much if previous one is a real handle
           &stackFrame,  
           pContext,
           NULL,
           ::SymFunctionTableAccess,
           ::SymGetModuleBase,
           NULL ) )
        {
            os << " 0x" << (PVOID) stackFrame.AddrFrame.Offset << " " << addressToString( (PVOID)stackFrame.AddrPC.Offset ) << "/n";
        }
        os.flush();
    }

    完整的代码到http://www.howzatt.demon.co.uk/articles/SimpleSymbolEngine.zip下载。http://www.codeproject.com/KB/threads/StackWalker.aspx里面也有例子。

    参考:

    http://www.diybl.com/course/3_program/java/javashl/2008119/96739.html

    http://topic.csdn.net/u/20090618/11/7c19832a-975e-4be6-987b-e61d789b31b5.html

    http://bbs3.chinaunix.net/viewthread.php?tid=950357&extra=&page=2

    http://www.codeproject.com/KB/threads/StackWalker.aspx

    http://topic.csdn.net/u/20070515/21/fc3ebc11-b871-4761-90ae-3c6ddc7b4248.html

    http://www.diybl.com/course/3_program/c++/cppjs/20090403/163752_2.html

    http://accu.org/index.php/journals/276

    http://blog.thepimp.net/archives/how-to-generate-backtraces-on-windows-without-compiler.html

    【作者】张昺华
    【大饼教你学系列】https://edu.csdn.net/course/detail/10393
    【新浪微博】 张昺华--sky
    【twitter】 @sky2030_
    【微信公众号】 张昺华
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
  • 相关阅读:
    JS代码判断IE不同版本
    极简技术类录--正则表达式
    Java读取系统Properties
    极简技术类录--maven
    极简技术类录--git
    JVM字节码增强
    如何避免死锁?
    有三个线程T1,T2,T3,怎么确保它们按顺序执行?
    编写两个线程,顺序输出自然顺序:1,2,3,4,...,99,100
    对文本单词进行技数,并倒序列出计数统计
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/13652435.html
Copyright © 2020-2023  润新知