您的位置:首页 > 其它

打印函数调用堆栈

2012-11-23 17:01 405 查看
转自:http://hi.baidu.com/bcber/item/ed68a2172996a209d1d66d04

 

注:如果要在C++ Builder中使用的话,切记需要进行map2dbg的转换

http://blog.csdn.net/chief1985/archive/2009/09/29/4618492.aspx

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

view plaincopy to clipboardprint?

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类似的方法,示例代码如下:

view plaincopy to clipboardprint?

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)

view plaincopy to clipboardprint?

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

view plaincopy to clipboardprint?

#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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: