(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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章