打印函数调用的堆栈信息

2023-05-16

有些时候为了便于调试,我们需要记录函数调用的堆栈信息。为此,封装了一个类StackDumper,在相应的函数中调用该类的成员函数即可。

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");
}

测试结果:

这里写图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

打印函数调用的堆栈信息 的相关文章

  • axios.create()

    lt DOCTYPE html gt lt html lang 61 34 en 34 gt lt head gt lt meta charset 61 34 UTF 8 34 gt lt meta name 61 34 viewport
  • 【无标题】

    Win11更新后无法使用网络 xff0c 可能是适配器驱动有问题的解决办法 把Win11系统更新后突然无法上网 xff0c 无论是wlan连接还是手机热点都用不了 尝试了网络上找到的多种办法 xff1a 1 使用网络疑难自动解决 xff0c
  • Linux /etc/profile 添加环境变量

    S1 从命令行 sudo vi etc profile S2 按 i 开始编辑 在文件适当位置添加环境变量 xff0c 比如 xff1a export PATH 61 PATH usr local cuda 10 1 bin LD LIBR
  • Kubernetes部署(八):k8s项目交付----(5)持续部署

    一 云计算模型概念 You manage 你管理 Managed by vendor 供应商管理 Applications 开发研发出的业务 Runtimes 运行时环境 xff0c Applications业务运行起来 xff0c 需要依
  • Redis的bind的误区

    Redis的bind的误区 cw hello1的博客 CSDN博客 今天在搭建Redis服务集群的时候 xff0c 发现自己一直以来对Redis中bind 的理解的一个误区 在今天以前 xff0c 我一直认为Redis中的配置文件中的bin
  • 使用find命令在当前目录不包含子目录中查找文件

    Linux中使用find命令在当面目录以及子目录中查找文件 xff0c 这个只需要加一个参数 depth即可 xff0c 然而想要在当前目录不包含子目录就没有一个简单的参数可以实现 xff0c 尤其所要查找的是某一个文件的时候 xff0c
  • NOI2.3.6262 流感传染题解(C++)

    题目 总Time Limit 1000ms Memory Limit 65536kB Description 有一批易感人群住在网格状的宿舍区内 xff0c 宿舍区为n n的矩阵 xff0c 每个格点为一个房间 xff0c 房间里可能住人
  • Ubuntu安装远程桌面软件xrdp

    Ubuntu安装远程桌面软件xrdp linux桌面版在服务器运行 xff0c 通常使用SSH命令访问的方式是比较单一的 xff0c 虽然配置 XShell 43 XManager可以实现打开图形程序 xff0c 但速度较慢 安装xrdp
  • IDEA 使用 SpotBugs 找出你代码中的bug

    SpotBugs 是 Findbugs 的继任者 xff0c 通过静态分析来查找 Java 代码中的 bug 下面我们主要是介绍 SpotBugs 在 idea 中的安装和使用 安装 Idea Preferences Plugins xff
  • Python 面向对象编程入门:从定义类到使用继承和多态

    目录 类的定义 继承 多态 在 Python 中 xff0c 面向对象编程是一种非常重要的编程范式 它允许我们通过创建对象来表示现实世界中的事物 xff0c 并将其组织为类的层次结构 xff0c 使代码更加模块化和易于维护 类的定义 在 P
  • Rust 语言通用代码生成器:莲花,发布冒烟测试版 3, 开始支持 PostgreSQL 数据库,更多功能,更多示例

    Rust 语言通用代码生成器 xff1a 莲花 xff0c 发布冒烟测试版 3 开始支持 PostgreSQL 数据库 xff0c 更多功能 xff0c 更多示例 Rust 语言通用代码生成器 xff1a 莲花 xff0c 已发布冒烟测试版
  • jenkins安装与配置

    一 安装jenkins https www jenkins io doc book installing linux span class token comment red hat centos span span class token
  • centos虚拟机设置禁止休眠

    最近在使用virtualBox的虚拟机 centOS 上学习K8S xff0c 遇到了一个非常苦恼的问题 xff0c 就是宿主机锁屏一段时间后 xff0c 再唤醒 xff0c 虚拟机就无法连接了 xff0c 虚拟机 桥接模式 的ip也pin
  • mysql运维-lower_case_table_names(大小写敏感)

    1 简介 在MySQL中 xff0c 数据库对应数据目录中的目录 数据库中的每个表至少对应数据库目录中的一个文件 也可能是多个 xff0c 取决于存储引擎 因此 xff0c 所使用操作系统的大小写敏感性决定了数据库名和表名的大小写敏感性 在
  • Mobilenet-SSD的Caffe系列实现

    先引出题目 xff0c 占个坑 xff0c 以后慢慢填 mobilenet 也算是提出有一段时间了 xff0c 网上也不乏各种实现版本 xff0c 其中 xff0c 谷歌已经开源了Tensorflow的全部代码 xff0c 无奈自己几乎不熟
  • 给UICollectionView添加尾部视图

    UICollectionView用法与UITableView的用法基本一样 xff0c 但是为UIcollectinView添加头尾视图就相对麻烦了 span class hljs comment 注册尾部视图 span dailyCV r
  • 明德扬手把手教你设计VGA显示颜色

    VGA显示颜色 一 项目背景 VGA介绍 VGA xff08 Video Graphics Array xff09 即视频图形阵列 xff0c 是IBM在1987年随PS 2 xff08 PS 2 原是 Personal System 2
  • 亚马逊EC2建立虚拟机并使用ssh连接

    登录亚马逊AWS后 xff0c 在页面右上角可以选择服务节点 xff0c 可选择最快的服务器地址 xff0c 服务器列表可参考此页面 xff1a http ec2 reachability amazonaws com xff0c 通过pin
  • Dockerfile文件解释

    一 先来看一个简单的 Dockerfile 这个Dockerfile作用是打一个python3项目环境 FROM python 3 alpine WORKDIR app ADD app RUN pip3 install r requirem

随机推荐