打印调用堆栈

来源:互联网 发布:数据透视表按次序刷新 编辑:程序博客网 时间:2024/04/29 06:26


原文链接:http://blog.csdn.net/chief1985/article/details/4618492


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 <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,示例代码如下:
#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


0 0
原创粉丝点击