`
mmdev
  • 浏览: 12889251 次
  • 性别: Icon_minigender_1
  • 来自: 大连
文章分类
社区版块
存档分类
最新评论

打印函数调用堆栈

 
阅读更多

转自: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

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics