java里面可以使用Throwable类来获取堆栈,示例代码如下:
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类似的方法,示例代码如下:
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)
//funstack.c #define _GNU_SOURCE #include #include #include #include #include #include #include #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,示例代码如下:
#include "SimpleSymbolEngine.h" #include #include #include #include #include #include #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