java裡面可以使用Throwable類來擷取堆棧,範例程式碼如下:
package name.xu;<br />public class CallStack {<br />public static void printCallStatck() {<br />Throwable ex = new Throwable();<br />StackTraceElement[] stackElements = ex.getStackTrace();<br />if (stackElements != null) {<br />for (int i = 0; i < stackElements.length; i++) {<br />System.out.print(stackElements[i].getClassName()+"/t");<br />System.out.print(stackElements[i].getFileName()+"/t");<br />System.out.print(stackElements[i].getLineNumber()+"/t");<br />System.out.println(stackElements[i].getMethodName());<br />System.out.println("-----------------------------------");<br />}<br />}<br />}</p><p>}
C#裡面使用與java類似的方法,範例程式碼如下:
using System;<br />using System.Collections.Generic;<br />using System.Linq;<br />using System.Text;<br />using System.Diagnostics;<br />namespace TestProjectCSharp<br />{<br /> class CallStack<br /> {<br /> public static void printCallStack()<br /> {<br /> StackTrace ss = new StackTrace(true);<br /> String flName = ss.GetFrame(1).GetFileName();// GetMethod().DeclaringType;<br /> int lineNo = ss.GetFrame(1).GetFileLineNumber();<br /> String methodName = ss.GetFrame(1).GetMethod().Name;<br /> Console.WriteLine(flName+"---"+lineNo+"---"+methodName);<br /> }<br /> }<br />}
c裡面擷取堆棧跟系統有關(主要是擷取函數名稱不一致,擷取地址是一致的),
linux下使用backtrace和backtrace_symbols函數,範例程式碼如下:(編譯方法:gcc -o funstack -rdynamic -ldl funstack.c)
//funstack.c<br />#define _GNU_SOURCE<br />#include <memory.h><br />#include <stdlib.h><br />#include <stdio.h><br />#include <signal.h><br />#include <ucontext.h><br />#include <dlfcn.h><br />#include <execinfo.h><br />#if defined(REG_RIP)<br /># define SIGSEGV_STACK_IA64<br /># define REGFORMAT "%016lx"<br />#elif defined(REG_EIP)<br /># define SIGSEGV_STACK_X86<br /># define REGFORMAT "%08x"<br />#else<br /># define SIGSEGV_STACK_GENERIC<br /># define REGFORMAT "%x"<br />#endif<br />static void signal_segv(int signum, siginfo_t* info, void*ptr) {<br /> static const char *si_codes[3] = {"", "SEGV_MAPERR", "SEGV_ACCERR"};<br /> size_t i;<br /> ucontext_t *ucontext = (ucontext_t*)ptr;<br />#if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64)<br /> int f = 0;<br /> Dl_info dlinfo;<br /> void **bp = 0;<br /> void *ip = 0;<br />#else<br /> void *bt[20];<br /> char **strings;<br /> size_t sz;<br />#endif<br />#if defined(SIGSEGV_STACK_X86) || defined(SIGSEGV_STACK_IA64)<br /># if defined(SIGSEGV_STACK_IA64)<br /> ip = (void*)ucontext->uc_mcontext.gregs[REG_RIP];<br /> bp = (void**)ucontext->uc_mcontext.gregs[REG_RBP];<br /># elif defined(SIGSEGV_STACK_X86)<br /> ip = (void*)ucontext->uc_mcontext.gregs[REG_EIP];<br /> bp = (void**)ucontext->uc_mcontext.gregs[REG_EBP];<br /># endif<br /> fprintf(stderr, "Stack trace:/n");<br /> while(bp && ip) {<br /> if(!dladdr(ip, &dlinfo))<br /> break;<br /> const char *symname = dlinfo.dli_sname;<br /> fprintf(stderr, "% 2d: %p %s+%u (%s)/n",<br /> ++f,<br /> ip,<br /> symname,<br /> (unsigned)(ip - dlinfo.dli_saddr),<br /> dlinfo.dli_fname);<br /> if(dlinfo.dli_sname && !strcmp(dlinfo.dli_sname, "main"))<br /> break;<br /> ip = bp[1];<br /> bp = (void**)bp[0];<br /> }<br />#else<br /> fprintf(stderr, "Stack trace (non-dedicated):/n");<br /> sz = backtrace(bt, 20);<br /> strings = backtrace_symbols(bt, sz);<br /> for(i = 0; i < sz; ++i)<br /> fprintf(stderr, "%s/n", strings[i]);<br />#endif<br /> fprintf(stderr, "End of stack trace/n");<br /> return;<br />}<br />int setup_sigsegv() {<br /> struct sigaction action;<br /> memset(&action, 0, sizeof(action));<br /> action.sa_sigaction = signal_segv;<br /> action.sa_flags = SA_SIGINFO;<br /> if(sigaction(SIGUSR1, &action, NULL) < 0) {<br /> perror("sigaction");<br /> return 0;<br /> }<br /> return 1;<br />}</p><p>void func1()<br />{<br /> raise(SIGUSR1);<br /> return ;<br />}<br />void func2()<br />{<br /> raise(SIGUSR1);<br /> return ;<br />}<br />void entry()<br />{<br /> func1();<br /> func2();<br /> return;<br />}<br />int main()<br />{<br /> setup_sigsegv();<br /> entry();<br />}
windows下使用GetThreadContext ,StackWalk,SymGetOptions ,SymFunctionTableAccess,範例程式碼如下:
#include "SimpleSymbolEngine.h"<br />#include <windows.h><br />#include <psapi.h><br />#include <iostream><br />#include <sstream><br />#include <cstddef><br />#include <dbghelp.h><br />#pragma comment( lib, "dbghelp" )<br />static char const szRCSID[] = "$Id: SimpleSymbolEngine.cpp,v 1.4 2005/05/04 21:52:05 Eleanor Exp $";<br />//////////////////////////////////////////////////////////////////////////////////////<br />// Singleton for the engine (SymInitialize doesn't support multiple calls)<br />SimpleSymbolEngine& SimpleSymbolEngine::instance()<br />{<br />static SimpleSymbolEngine theEngine;<br /> return theEngine;<br />}<br />/////////////////////////////////////////////////////////////////////////////////////<br />SimpleSymbolEngine::SimpleSymbolEngine()<br />{<br /> hProcess = GetCurrentProcess();<br /> DWORD dwOpts = SymGetOptions();<br /> dwOpts |= SYMOPT_LOAD_LINES | SYMOPT_DEFERRED_LOADS;<br /> SymSetOptions ( dwOpts );<br /> ::SymInitialize( hProcess, 0, true );<br />}<br />/////////////////////////////////////////////////////////////////////////////////////<br />SimpleSymbolEngine::~SimpleSymbolEngine()<br />{<br /> ::SymCleanup( hProcess );<br />}<br />/////////////////////////////////////////////////////////////////////////////////////<br />std::string SimpleSymbolEngine::addressToString( PVOID address )<br />{<br /> std::ostringstream oss;<br /> // First the raw address<br /> oss << "0x" << address;<br /> // Then any name for the symbol<br /> struct tagSymInfo<br /> {<br /> IMAGEHLP_SYMBOL symInfo;<br /> char nameBuffer[ 4 * 256 ];<br /> } SymInfo = { { sizeof( IMAGEHLP_SYMBOL ) } };<br /> IMAGEHLP_SYMBOL * pSym = &SymInfo.symInfo;<br /> pSym->MaxNameLength = sizeof( SymInfo ) - offsetof( tagSymInfo, symInfo.Name );<br /> DWORD dwDisplacement;<br /> if ( SymGetSymFromAddr( hProcess, (DWORD)address, &dwDisplacement, pSym) )<br /> {<br /> oss << " " << pSym->Name;<br /> if ( dwDisplacement != 0 )<br /> oss << "+0x" << std::hex << dwDisplacement << std::dec;<br /> }</p><p> // Finally any file/line number<br /> IMAGEHLP_LINE lineInfo = { sizeof( IMAGEHLP_LINE ) };<br /> if ( SymGetLineFromAddr( hProcess, (DWORD)address, &dwDisplacement, &lineInfo ) )<br /> {<br /> char const *pDelim = strrchr( lineInfo.FileName, '//' );<br /> oss << " at " << ( pDelim ? pDelim + 1 : lineInfo.FileName ) << "(" << lineInfo.LineNumber << ")";<br /> }<br /> return oss.str();<br />}<br />/////////////////////////////////////////////////////////////////////////////////////<br />// StackTrace: try to trace the stack to the given output<br />void SimpleSymbolEngine::StackTrace( PCONTEXT pContext, std::ostream & os )<br />{<br /> os << " Frame Code address/n";<br /> STACKFRAME stackFrame = {0};<br /> stackFrame.AddrPC.Offset = pContext->Eip;<br /> stackFrame.AddrPC.Mode = AddrModeFlat;<br /> stackFrame.AddrFrame.Offset = pContext->Ebp;<br /> stackFrame.AddrFrame.Mode = AddrModeFlat;<br /> stackFrame.AddrStack.Offset = pContext->Esp;<br /> stackFrame.AddrStack.Mode = AddrModeFlat;<br /> while ( ::StackWalk(<br /> IMAGE_FILE_MACHINE_I386,<br /> hProcess,<br /> GetCurrentThread(), // this value doesn't matter much if previous one is a real handle<br /> &stackFrame,<br /> pContext,<br /> NULL,<br /> ::SymFunctionTableAccess,<br /> ::SymGetModuleBase,<br /> NULL ) )<br /> {<br /> os << " 0x" << (PVOID) stackFrame.AddrFrame.Offset << " " << addressToString( (PVOID)stackFrame.AddrPC.Offset ) << "/n";<br /> }<br /> os.flush();<br />}<br />
完整的代碼到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