1. 程式人生 > >列印呼叫堆疊

列印呼叫堆疊

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

               

java裡面可以使用Throwable類來獲取堆疊,示例程式碼如下:

[java] view plain copy print
?
  1. package name.xu;  
  2. public class CallStack {  
  3.     public static void printCallStatck() {  
  4.         Throwable ex = new Throwable();  
  5.         StackTraceElement[] stackElements = ex.getStackTrace();  
  6.         if (stackElements != null) {  
  7.             for
     (int i = 0; i < stackElements.length; i++) {  
  8.                 System.out.print(stackElements[i].getClassName()+"/t");  
  9.                 System.out.print(stackElements[i].getFileName()+"/t");  
  10.                 System.out.print(stackElements[i].getLineNumber()+"/t");  
  11.                 System.out.println(stackElements[i].getMethodName());  
  12.                 System.out.println("-----------------------------------");  
  13.             }  
  14.         }  
  15.     }  
  16.       
  17. }  
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類似的方法,示例程式碼如下:

[c-sharp] view plain copy print ?
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Diagnostics;  
  6. namespace TestProjectCSharp  
  7. {  
  8.     class CallStack  
  9.     {  
  10.         public static void printCallStack()  
  11.         {  
  12.             StackTrace ss = new StackTrace(true);  
  13.             String flName = ss.GetFrame(1).GetFileName();// GetMethod().DeclaringType;   
  14.             int lineNo = ss.GetFrame(1).GetFileLineNumber();  
  15.             String methodName = ss.GetFrame(1).GetMethod().Name;  
  16.             Console.WriteLine(flName+"---"+lineNo+"---"+methodName);  
  17.         }  
  18.     }  
  19. }  
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)

[cpp] view plain copy print ?
  1. //funstack.c  
  2. #define _GNU_SOURCE  
  3. #include <memory.h>  
  4. #include <stdlib.h>  
  5. #include <stdio.h>  
  6. #include <signal.h>  
  7. #include <ucontext.h>  
  8. #include <dlfcn.h>  
  9. #include <execinfo.h>  
  10. #if defined(REG_RIP)  
  11. # define SIGSEGV_STACK_IA64  
  12. # define REGFORMAT "%016lx"  
  13. #elif defined(REG_EIP)  
  14. # define SIGSEGV_STACK_X86  
  15. # define REGFORMAT "%08x"  
  16. #else  
  17. # define SIGSEGV_STACK_GENERIC  
  18. # define REGFORMAT "%x"  
  19. #endif  
  20. static void signal_segv(int signum, siginfo_t* info, void*ptr) {  
  21.         static const char *si_codes[3] = {"""SEGV_MAPERR""SEGV_ACCERR"};  
  22.         size_t i;  
  23.         ucontext_t *ucontext = (ucontext_t*)ptr;  
  24. #if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64)  
  25.         int f = 0;  
  26.         Dl_info dlinfo;  
  27.         void **bp = 0;  
  28.         void *ip = 0;  
  29. #else  
  30.         void *bt[20];  
  31.         char **strings;  
  32.         size_t sz;  
  33. #endif  
  34. #if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64)  
  35. # if defined(SIGSEGV_STACK_IA64)  
  36.         ip = (void*)ucontext->uc_mcontext.gregs[REG_RIP];  
  37.         bp = (void**)ucontext->uc_mcontext.gregs[REG_RBP];  
  38. # elif defined(SIGSEGV_STACK_X86)  
  39.         ip = (void*)ucontext->uc_mcontext.gregs[REG_EIP];  
  40.         bp = (void**)ucontext->uc_mcontext.gregs[REG_EBP];  
  41. # endif  
  42.         fprintf(stderr, "Stack trace:/n");  
  43.         while(bp && ip) {  
  44.                 if(!dladdr(ip, &dlinfo))  
  45.                         break;  
  46.                 const char *symname = dlinfo.dli_sname;  
  47.                 fprintf(stderr, "% 2d: %p %s+%u (%s)/n",  
  48.                                 ++f,  
  49.                                 ip,  
  50.                                 symname,  
  51.                                 (unsigned)(ip - dlinfo.dli_saddr),  
  52.                                 dlinfo.dli_fname);  
  53.                 if(dlinfo.dli_sname && !strcmp(dlinfo.dli_sname, "main"))  
  54.                         break;  
  55.                 ip = bp[1];  
  56.                 bp = (void**)bp[0];  
  57.         }  
  58. #else  
  59.         fprintf(stderr, "Stack trace (non-dedicated):/n");  
  60.         sz = backtrace(bt, 20);  
  61.         strings = backtrace_symbols(bt, sz);  
  62.         for(i = 0; i < sz; ++i)  
  63.                 fprintf(stderr, "%s/n", strings[i]);  
  64. #endif  
  65.         fprintf(stderr, "End of stack trace/n");  
  66.         return;  
  67. }  
  68. int setup_sigsegv() {  
  69.         struct sigaction action;  
  70.         memset(&action, 0, sizeof(action));  
  71.         action.sa_sigaction = signal_segv;  
  72.         action.sa_flags = SA_SIGINFO;  
  73.         if(sigaction(SIGUSR1, &action, NULL) < 0) {  
  74.                 perror("sigaction");  
  75.                 return 0;  
  76.         }  
  77.         return 1;  
  78. }  
  79.   
  80. void func1()  
  81. {  
  82.         raise(SIGUSR1);  
  83.         return ;  
  84. }  
  85. void func2()  
  86. {  
  87.         raise(SIGUSR1);  
  88.         return ;  
  89. }  
  90. void entry()  
  91. {  
  92.         func1();  
  93.         func2();  
  94.         return;  
  95. }  
  96. int main()  
  97. {  
  98.         setup_sigsegv();  
  99.         entry();  
  100. }  
//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"#endifstatic 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,示例程式碼如下:

[cpp] view plain copy print ?
  1. #include "SimpleSymbolEngine.h"  
  2. #include <windows.h>  
  3. #include <psapi.h>  
  4. #include <iostream>  
  5. #include <sstream>  
  6. #include <cstddef>  
  7. #include <dbghelp.h>  
  8. #pragma comment( lib, "dbghelp" )  
  9. static char const szRCSID[] = "$Id: SimpleSymbolEngine.cpp,v 1.4 2005/05/04 21:52:05 Eleanor Exp $";  
  10. //////////////////////////////////////////////////////////////////////////////////////  
  11. // Singleton for the engine (SymInitialize doesn't support multiple calls)  
  12. SimpleSymbolEngine& SimpleSymbolEngine::instance()  
  13. {  
  14. static SimpleSymbolEngine theEngine;  
  15.     return theEngine;  
  16. }  
  17. /////////////////////////////////////////////////////////////////////////////////////  
  18. SimpleSymbolEngine::SimpleSymbolEngine()  
  19. {  
  20.     hProcess = GetCurrentProcess();  
  21.     DWORD dwOpts = SymGetOptions();  
  22.     dwOpts |= SYMOPT_LOAD_LINES | SYMOPT_DEFERRED_LOADS;  
  23.     SymSetOptions ( dwOpts );  
  24.     ::SymInitialize( hProcess, 0, true );  
  25. }  
  26. /////////////////////////////////////////////////////////////////////////////////////  
  27. SimpleSymbolEngine::~SimpleSymbolEngine()  
  28. {  
  29.     ::SymCleanup( hProcess );  
  30. }  
  31. /////////////////////////////////////////////////////////////////////////////////////  
  32. std::string SimpleSymbolEngine::addressToString( PVOID address )  
  33. {  
  34.     std::ostringstream oss;  
  35.     // First the raw address  
  36.     oss << "0x" << address;  
  37.     // Then any name for the symbol  
  38.     struct tagSymInfo  
  39.     {  
  40.         IMAGEHLP_SYMBOL symInfo;  
  41.         char nameBuffer[ 4 * 256 ];  
  42.     } SymInfo = { { sizeof( IMAGEHLP_SYMBOL ) } };  
  43.     IMAGEHLP_SYMBOL * pSym = &SymInfo.symInfo;  
  44.     pSym->MaxNameLength = sizeof( SymInfo ) - offsetof( tagSymInfo, symInfo.Name );  
  45.     DWORD dwDisplacement;  
  46.     if ( SymGetSymFromAddr( hProcess, (DWORD)address, &dwDisplacement, pSym) )  
  47.     {  
  48.         oss << " " << pSym->Name;  
  49.         if ( dwDisplacement != 0 )  
  50.             oss << "+0x" << std::hex << dwDisplacement << std::dec;  
  51.     }  
  52.           
  53.     // Finally any file/line number  
  54.     IMAGEHLP_LINE lineInfo = { sizeof( IMAGEHLP_LINE ) };  
  55.     if ( SymGetLineFromAddr( hProcess, (DWORD)address, &dwDisplacement, &lineInfo ) )  
  56.     {  
  57.         char const *pDelim = strrchr( lineInfo.FileName, '//' );  
  58.         oss << " at " << ( pDelim ? pDelim + 1 : lineInfo.FileName ) << "(" << lineInfo.LineNumber << ")";  
  59.     }  
  60.     return oss.str();  
  61. }  
  62. /////////////////////////////////////////////////////////////////////////////////////  
  63. // StackTrace: try to trace the stack to the given output  
  64. void SimpleSymbolEngine::StackTrace( PCONTEXT pContext, std::ostream & os )  
  65. {  
  66.     os << "  Frame       Code address/n";  
  67.     STACKFRAME stackFrame = {0};  
  68.     stackFrame.AddrPC.Offset = pContext->Eip;  
  69.     stackFrame.AddrPC.Mode = AddrModeFlat;  
  70.     stackFrame.AddrFrame.Offset = pContext->Ebp;  
  71.     stackFrame.AddrFrame.Mode = AddrModeFlat;  
  72.     stackFrame.AddrStack.Offset = pContext->Esp;  
  73.     stackFrame.AddrStack.Mode = AddrModeFlat;  
  74.     while ( ::StackWalk(  
  75.        IMAGE_FILE_MACHINE_I386,  
  76.        hProcess,  
  77.        GetCurrentThread(), // this value doesn't matter much if previous one is a real handle  
  78.        &stackFrame,   
  79.        pContext,  
  80.        NULL,  
  81.        ::SymFunctionTableAccess,  
  82.        ::SymGetModuleBase,  
  83.        NULL ) )  
  84.     {  
  85.         os << "  0x" << (PVOID) stackFrame.AddrFrame.Offset << "  " << addressToString( (PVOID)stackFrame.AddrPC.Offset ) << "/n";  
  86.     }  
  87.     os.flush();  
  88. }  
#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 outputvoid 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

           

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述