2310D,Dll,栈跟踪
原文
帮助
有没有想过,如果运行时拥有调试器功能,会怎样?
对系统语言来说,常见问题是解引用空针.这几乎总是会导致崩溃,很难找到该问题,特别是你不是该项目的原始开发者时.
但是,不要害怕,在此我要讲如何在不需要实际附加调试器时获得有用的调试信息.
在Java中,已存在一个叫NullPointerException的方法,它非常有用,因为它准确地显示了崩溃的内容,地点和时间,这就是本文要实现的目标.
检测崩溃(微软C++运行时异常)
每当你的程序崩溃时,程序基本上都会退出,并返回一个负的错误码,或终止信号.
问题是,得不到有意义的错误消息,所以,唯一方法是附加一个调试器,但不是每次都可能,特别是随机发生该错误.
因此,先要检测崩溃,为此,使用Win32API来查找它:
LPTOP_LEVEL_EXCEPTION_FILTER SetUnhandledExceptionFilter(LPTOP_LEVEL_EXCEPTION_FILTER
);
SetUnhandledExceptionFilter函数,参考地址
因此,此函数作用是,在类型运行异常时设置回调,即获得一些有关该异常的信息,如,上面显示的代码0xC..05.
第一个区别是,现在可决定是要继续运行还是处理此错误.
现在,进入回调部分:
extern (窗口) LONG TopLevelExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo)
{debug{//在D中,可调用`throw`来结束,因为它会自动为我们取栈跟踪throw new Exception("Caught Exception (0x"~toHex(pExceptionInfo.ExceptionRecord.ExceptionCode)~")");//但请继续阅读以了解如何`手动`取栈跟踪}//在此,可控制是否`继续执行`return EXCEPTION_CONTINUE_SEARCH;
}
访问可取错误码.用.而不是->.
取栈跟踪信息
在直接跳转到代码之前,还要包含2个系统库,这九分根据你的语言或构建系统,在D中,可直接从代码中包含库:
debug version(窗口)
{pragma(lib, "psapi.lib");pragma(lib, "dbghelp.lib");
}//Windows
也可在你的构建系统中用-Lpsapi-Ldbghelp来包含,直接放在代码中更清楚.应该放在默认库路径上.
现在,增加可用性的部分:
extern (C) export void backtraced_Register()
{debug{//初化`.pdb`读取进程SymInitialize(GetCurrentProcess(), null, true);//需要取有关文件的行信息SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_DEBUG);SetUnhandledExceptionFilter(&TopLevelExceptionHandler);}
}
现在,细节,分配一些内存来存储异常栈:
debug void printStackTrace()
{enum MAX_DEPTH = 256;void*[MAX_DEPTH] stack;HANDLE process = GetCurrentProcess();ushort frames = RtlCaptureStackBackTrace(0, MAX_DEPTH, stack.ptr, null);SYMBOL_INFO* symbol = cast(SYMBOL_INFO*) calloc((SYMBOL_INFO.sizeof) + 256 * char.sizeof, 1);symbol.MaxNameLen = 255;symbol.SizeOfStruct = SYMBOL_INFO.sizeof;IMAGEHLP_LINEA64 line = void;line.SizeOfStruct = SYMBOL_INFO.sizeof;DWORD dwDisplacement;for (uint i = 0; i < frames; i++){//从当前循环帧中取符号SymFromAddr(process, cast(DWORD64)(stack[i]), null, symbol);//取高级文件信息SymGetLineFromAddr64(process, cast(DWORD64)(stack[i]), &dwDisplacement, &line);//如果用`C++`或D编程,你可能需要一个`"demangle"`函数.来更易阅读符号.此外,`[0..symbol.NameLen]`基本上是来创建一个区间.char[] funcName = demangle(symbol.Name.ptr[0..symbol.NameLen]);auto fname = line.FileName;auto lnum = line.LineNumber;fprintf(stderr, "%s:%i - %.*s\n", fname, lnum, cast(int)funcName.length, funcName.ptr);}free(symbol);
}
现在,有了它,可打印在UnhandledExceptionFilter中的栈跟踪,如下:
结果:
Caught exception (0xC0000005)
-------------------------------------------------------------------+
G:\HipremeEngine\source\hip\systems\game.d:251 - hip::systems::game::GameSystem::addScene::__lambda2
G:\HipremeEngine\modules\util\source\hip\util\concurrency.d:307 - hip::util::concurrency::HipWorkerPool::addOnAllTasksFinished
G:\HipremeEngine\modules\assets\source\hip\assetmanager.d:955 - hip::assetmanager::HipAssetManager::addOnLoadingFinish
G:\HipremeEngine\source\hip\systems\game.d:257 - hip::systems::game::GameSystem::addScene
G:\HipremeEngine\source\hip\systems\game.d:207 - hip::systems::game::GameSystem::startGame
G:\HipremeEngine\source\app.d:238 - app::gameInitialize
G:\HipremeEngine\source\app.d:214 - app::HipremeMain::__lambda4
G:\HipremeEngine\source\hip\global\gamedef.d:85 - hip::global::gamedef::loadDefaultAssets
G:\HipremeEngine\source\app.d:218 - app::HipremeMain
G:\HipremeEngine\source\app.d:296 - app::D main
G:\HipremeEngine\source\app.d:296 - _d_run_main2
G:\HipremeEngine\source\app.d:296 - _d_wrun_main
G:\HipremeEngine\tools\user\build_selector\D\ldc2-1.33.0-beta1-窗口-x64\import\core\internal\entrypoint.d:32 - app::wmain
D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288 - __scrt_common_main_seh
D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288 - BaseThreadInitThunk
D:\a\_work\1\s\src\vctools\crt\vcstartup\src\startup\exe_common.inl:288 - RtlUserThreadStart
可见,得到了执行如何达到该异常的整个栈跟踪,这使你的程序现在更加可靠,特别是在新项目或DLL上处理其他人代码时.
附录:从DLL取栈跟踪
如果运行的是DLL,特别是在重新加载热代码的系统上,则无法取栈信息(是的,一旦初化异常处理器,它就可在可执行文件和dll代码之间工作).
要解决,你需要沿着dependency.dll文件加载依赖项.pdb,当然,在调试器中运行时都会发生,但是在调用LoadLibrary的独立可执行文件上时,不是这样.
为此,需要一些额外的代码,我叫它DebugLoadLibrary.
void* DebugLoadLibrary(const char* libName)
{import core.sys.windows.winbase;import core.sys.windows.windef;void* ret = LoadLibrary(libName);debug{import core.sys.windows.psapi;MODULEINFO moduleInfo;GetModuleInformation(GetCurrentProcess(), ret, &moduleInfo, MODULEINFO.sizeof);if(!SymLoadModuleEx(GetCurrentProcess(), null, libName, null, cast(ulong)moduleInfo.lpBaseOfDll, moduleInfo.SizeOfImage, null, 0)){throw new Error(format("Failed to load the DLL named ", libName, " pdb"));}}return ret;
}
这样,如果DLL文件内部崩溃了,你会获得一些有用的信息(其栈跟踪),因此,可轻松调试它.
相关文章:
2310D,Dll,栈跟踪
原文 帮助 有没有想过,如果运行时拥有调试器功能,会怎样? 对系统语言来说,常见问题是解引用空针.这几乎总是会导致崩溃,很难找到该问题,特别是你不是该项目的原始开发者时. 但是,不要害怕,在此我要讲如何在不需要实际附加调试器时获得有用的调试信息. 在Java中,已存在一个叫…...
JVS-BI数字大屏设计器:一站式解决方案
数字大屏介绍 数字大屏是当下数据展示、业务监控、指挥调度常见的业务表达形态,常有可视化的图表、效果装饰、事件操作等技术组成酷炫的效果展示。 配置入口 进入JVS-BI(bi.bctools.cn),进入大屏页面,如下图所示 ①…...
uniapp 中添加 vconsole
uniapp 中添加 vconsole 一、安装 vconsole npm i vconsole二、使用 vconsole 在项目的 main.js 文件中添加如下内容 // #ifdef H5 // 提交前需要注释 本地调试使用 import * as vconsole from "vconsole"; new vconsole() // 使用 vconsole // #endif三、成功...
目标检测 YOLOv5 预训练模型下载方法
目标检测 YOLOv5 预训练模型下载方法 flyfish https://github.com/ultralytics/yolov5 https://github.com/ultralytics/yolov5/releases 可以选择自己需要的版本和不同任务类型的模型 后缀名是pt...
第16章_变量、流程控制与游标
第16章_变量、流程控制与游标 讲师:尚硅谷-宋红康(江湖人称:康师傅) 官网:http://www.atguigu.com 1. 变量 在MySQL数据库的存储过程和函数中,可以使用变量来存储查询或计算的中间结果数据,或…...
谁知道腾讯云轻量服务器“月流量”是什么意思?
腾讯云轻量服务器月流量什么意思?月流量是指轻量服务器限制每月流量的意思,不能肆无忌惮地使用公网,流量超额需要另外支付流量费,上海/广州/北京等地域的轻量服务器月流量不够用超额部分按照0.8元/GB的价格支付流量费。阿腾云aten…...
算法笔记【4】-冒泡排序法改进
一、冒泡排序缺点 冒泡排序是一种简单但效率较低的排序算法。冒泡排序通过比较相邻元素并交换位置来实现排序。具体而言,它从数组的第一个元素开始,依次比较相邻的两个元素,如果顺序错误则交换它们的位置,直到整个数组排好序为止…...
cocos creator 资源管理
cocos creator 在使用过程中,经常需要动态加载远端资源,比日说 用户头像,龙骨动画皮肤资源,这些资源不可能都做成 预制体交给 cocos creator 帮助我们管理; 这个时候就需要我们 动态加载远端资源(但是 动态…...
好用的API调试工具推荐:Apipost
随着数字化转型的加速,API(应用程序接口)已经成为企业间沟通和数据交换的关键。而在API开发和管理过程中,API文档、调试、Mock和测试的协作显得尤为重要。Apipost正是这样一款一体化协作平台,旨在解决这些问题…...
贪心算法学习——最长单调递增子序列
目录 编辑 一,题目 二,题目接口 三,解题思路和代码 一,题目 给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列,删除(或不删除)数组…...
银行家算法(Python实现)
银行家算法,以及安全检测算法: import copy# 银行家算法(资源分配合法性) def BankersAlgorithm(Process_num, Resources_num, Request, Max, Available, Allocation, Need):PID Request[PID] # 获取发起请求的进程ID# Step1.如…...
安装终端 ·Terminator
安装终端 在 ROS 中,需要频繁的使用到终端,且可能需要同时开启多个窗口,推荐一款较为好用的终端:**Terminator。**效果如下: 1.安装 sudo apt install terminator2.添加到收藏夹 显示应用程序 —> 搜索 terminator —> 右击 选择 添…...
【Python文件操作的其他例子】
A.Python文件操作的其他例子 当然,以下是一些Python文件操作的其他例子: 1. 读取文件内容: with open(example.txt, r) as f:content f.read()print(content)这个例子会打开名为’example.txt’的文件,读取其内容,…...
使用Terraform管理已经存在的kubernates和默认的节点池
背景: 通过terraform resource "alicloud_cs_managed_kubernetes" "k8s" {...}创建集群时,会产生一个默认的节点池default-nodepool,但是如何去修改这个默认节点池的信息呢? 解决思路: 因为Ter…...
在HTML当中引入Vue控件,以element-ui为例
前情:需要实现一个同时满足按天、按周、按月选择的时间选择器,但是以HTML为基础写的都不太满足我的要求,要么只能按天选择,要么就是想选择久远的时间得点很久,除非自己写捷径,所以就看上了element-ui的这个…...
UE5实现相机水平矫正
UE5实现相机水平矫正 思路,用HIT获得基于相机视角的 离散采样点,然后根据距离相机距离进行权重分析。 距离越近,采样约中心,即越接近人眼注意点,最后算出加权平均高度,赋予给相机,相机将水平旋…...
Word插入Latex语句并编译为数学公式
WPS不可行,正版word可以(垃圾WPS) 选中Latex语句并按下Alt (此处以后补一张图) 该方法不需要额外安装什么插件哦!...
Google Play PolicyBytes 政策更新中文视频 | 2023 年 10 月
Google Play 持续帮助开发者开启成功出海之旅,为用户提供安全优质的应用。也感谢大家与我们携手合作,继续努力将 Google Play 打造为一个安全可信赖的平台。欢迎您观看 Google Play PolicyBytes 中文视频了解 2023 年 10 月政策更新内容,更及…...
pytorch-fastrcnn识别王者荣耀敌方英雄血条
文章目录 前言效果如下实现训练数据获得训练数据和测试数据yaml文件训练py画框文件的修改py测试py升级 前言 最近看王者荣耀视频看到了一个别人提供的一个百里自动设计解决方案,使用一个外设放在百里的二技能上,然后拖动外设在屏幕上滑动,当外设检测到有敌方英雄时外设自动松开…...
阿里云推出通义千问App,提供全方位的协助
🦉 AI新闻 🚀 阿里云推出通义千问App,提供全方位的协助 摘要:阿里云旗下大模型通义千问App登陆各大安卓应用市场,具有超大规模预训练模型,可在创意文案、办公助理、学习助手、趣味生活等方面协助用户。功…...
css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
在rocky linux 9.5上在线安装 docker
前面是指南,后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...
Go 语言接口详解
Go 语言接口详解 核心概念 接口定义 在 Go 语言中,接口是一种抽象类型,它定义了一组方法的集合: // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的: // 矩形结构体…...
【RockeMQ】第2节|RocketMQ快速实战以及核⼼概念详解(二)
升级Dledger高可用集群 一、主从架构的不足与Dledger的定位 主从架构缺陷 数据备份依赖Slave节点,但无自动故障转移能力,Master宕机后需人工切换,期间消息可能无法读取。Slave仅存储数据,无法主动升级为Master响应请求ÿ…...
自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...
wpf在image控件上快速显示内存图像
wpf在image控件上快速显示内存图像https://www.cnblogs.com/haodafeng/p/10431387.html 如果你在寻找能够快速在image控件刷新大图像(比如分辨率3000*3000的图像)的办法,尤其是想把内存中的裸数据(只有图像的数据,不包…...
Kafka主题运维全指南:从基础配置到故障处理
#作者:张桐瑞 文章目录 主题日常管理1. 修改主题分区。2. 修改主题级别参数。3. 变更副本数。4. 修改主题限速。5.主题分区迁移。6. 常见主题错误处理常见错误1:主题删除失败。常见错误2:__consumer_offsets占用太多的磁盘。 主题日常管理 …...
MyBatis中关于缓存的理解
MyBatis缓存 MyBatis系统当中默认定义两级缓存:一级缓存、二级缓存 默认情况下,只有一级缓存开启(sqlSession级别的缓存)二级缓存需要手动开启配置,需要局域namespace级别的缓存 一级缓存(本地缓存&#…...
6个月Python学习计划 Day 16 - 面向对象编程(OOP)基础
第三周 Day 3 🎯 今日目标 理解类(class)和对象(object)的关系学会定义类的属性、方法和构造函数(init)掌握对象的创建与使用初识封装、继承和多态的基本概念(预告) &a…...
