打印函数调用的堆栈信息
2016-07-02 23:59
1206 查看
有些时候为了便于调试,我们需要记录函数调用的堆栈信息。为此,封装了一个类StackDumper,在相应的函数中调用该类的成员函数即可。
stack_dumper.h
stack_dumper.cpp
测试程序:
测试结果:
stack_dumper.h
#ifndef STACK_DUMPER_H #define STACK_DUMPER_H #ifdef _WIN32 #include <windows.h> #include <dbghelp.h> #include <string> #include <sstream> #pragma comment (lib, "dbghelp.lib") #endif // _WIN32 class StackDumper { public: StackDumper(); ~StackDumper(); void Destory(); std::string DumpStack(); private: #ifdef _WIN32 UINT max_name_length_; // Max length of symbols' name. CONTEXT context_; // Store register addresses. STACKFRAME64 stackframe_; // Call stack. HANDLE process_, thread_; // Handle to current process & thread. PSYMBOL_INFO symbol_; // Debugging symbol's information. IMAGEHLP_LINE64 source_info_; // Source information (file name & line number) DWORD displacement_; // Source line displacement. #endif // _WIN32 std::ostringstream stack_info_str_stream_; }; #endif // STACK_DUMPER_H
stack_dumper.cpp
#include "stack_dumper.h" StackDumper::StackDumper() { #ifdef _WIN32 enum { MAX_NAME_LENGTH = 256 }; // max length of symbols' name. // Initialize PSYMBOL_INFO structure. // Allocate a properly-sized block. symbol_ = (PSYMBOL_INFO)malloc(sizeof(SYMBOL_INFO)+(MAX_NAME_LENGTH - 1) * sizeof(TCHAR)); memset(symbol_, 0, sizeof(SYMBOL_INFO)+(MAX_NAME_LENGTH - 1) * sizeof(TCHAR)); symbol_->SizeOfStruct = sizeof(SYMBOL_INFO); // SizeOfStruct *MUST BE* set to sizeof(SYMBOL_INFO). symbol_->MaxNameLen = MAX_NAME_LENGTH; // Initialize IMAGEHLP_LINE64 structure. memset(&source_info_, 0, sizeof(IMAGEHLP_LINE64)); source_info_.SizeOfStruct = sizeof(IMAGEHLP_LINE64); // Initialize STACKFRAME64 structure. RtlCaptureContext(&context_); // Get context. memset(&stackframe_, 0, sizeof(STACKFRAME64)); stackframe_.AddrPC.Offset = context_.Eip; // Fill in register addresses (EIP, ESP, EBP). stackframe_.AddrPC.Mode = AddrModeFlat; stackframe_.AddrStack.Offset = context_.Esp; stackframe_.AddrStack.Mode = AddrModeFlat; stackframe_.AddrFrame.Offset = context_.Ebp; stackframe_.AddrFrame.Mode = AddrModeFlat; stack_info_str_stream_.str(""); process_ = GetCurrentProcess(); // Get current process & thread. thread_ = GetCurrentThread(); // Initialize dbghelp library. if (!SymInitialize(process_, NULL, TRUE)) { stack_info_str_stream_ << "Initialize dbghelp library ERROR!\n"; } #endif // _WIN32 } StackDumper::~StackDumper() { Destory(); } void StackDumper::Destory() { SymCleanup(process_); // Clean up and exit. free(symbol_); stack_info_str_stream_ << "StackDumper is cleaned up!\n"; } std::string StackDumper::DumpStack() { #ifdef _WIN32 stack_info_str_stream_ << "Call stack: \n"; // Enumerate call stack frame. while (StackWalk64(IMAGE_FILE_MACHINE_I386, process_, thread_, &stackframe_, &context_, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) { if (stackframe_.AddrFrame.Offset == 0) { // End reaches. break; } if (SymFromAddr(process_, stackframe_.AddrPC.Offset, NULL, symbol_)) { // Get symbol. stack_info_str_stream_ << " ==> " << symbol_->Name << "\n"; } if (SymGetLineFromAddr64(process_, stackframe_.AddrPC.Offset, &displacement_, &source_info_)) { // Get source information. stack_info_str_stream_ << "\t[" << source_info_.FileName << ":" << source_info_.LineNumber << "]\n"; } else { if (GetLastError() == 0x1E7) { // If err_code == 0x1e7, no symbol was found. stack_info_str_stream_ << "\tNo debug symbol loaded for this function.\n"; } } } #endif // _WIN32 return stack_info_str_stream_.str(); }
测试程序:
#include <iostream> #include <string> #include <sstream> #include "stack_dumper.h" #define LOG_DEBUG \ { \ auto &str = StackDumper().DumpStack(); \ std::cout << str.c_str() << std::endl; \ } int Func(int arc) { LOG_DEBUG; return arc; } void Show(const std::string& str) { Func(11); std::cout << str << std::endl; } void main() { Show("AnonymousRookie..."); system("pause"); }
测试结果:
相关文章推荐
- Linux 自检和 SystemTap
- Python 七步捉虫法
- 路由器的配置与调试
- 对于技术人员的出现了运行时间错误,是否要进行调试的解决方法
- 在ASP.NET 2.0中操作数据之七十二:调试存储过程
- 讲解WordPress开发中一些常用的debug技巧
- JavaScript程序设计之JS调试
- 可以用来调试JavaScript错误的解决方案
- 如何调试异步加载页面里包含的js文件
- jQuery下的Ajax调试步骤
- 调试一段PHP程序时遇到的三个问题
- JavaScript高级程序设计 错误处理与调试学习笔记
- Javascript调试脚本的经验之谈第1/2页
- 在IE,Firefox,Safari,Chrome,Opera浏览器上调试javascript
- Android App调试内存泄露之Cursor篇
- Lua的编译、执行和调试技术介绍
- 解决Visual Studio 2012 Update 4 RC启动调试失败的方案
- PHPStorm+XDebug进行调试图文教程
- 10个调试和排错的小建议
- 调试PHP程序的多种方法介绍