各语言打印调用栈

来源:互联网 发布:网络配置教程 编辑:程序博客网 时间:2024/05/20 12:49

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

[java] view plaincopy
  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. }  

 

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

[c-sharp] view plaincopy
  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. }  
 

 

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

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

[cpp] view plaincopy
  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. }  
 

 

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

[cpp] view plaincopy
  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. }  
 

完整的代码到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

原创粉丝点击