列印呼叫堆疊
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow
也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!
java裡面可以使用Throwable類來獲取堆疊,示例程式碼如下:
[java] view plain copy print
- package name.xu;
- public class CallStack {
- public static void printCallStatck() {
- Throwable ex = new Throwable();
- StackTraceElement[] stackElements = ex.getStackTrace();
- if (stackElements != null) {
- for
- 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 ?- 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 ?- //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,示例程式碼如下:
[cpp] view plain copy print ?- #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