1. WinDbg概述

总目录

1. WinDbg概述
2. WinDbg主要功能
3. WinDbg程序调试示例
4. CPU寄存器及指令系统
5. CPU保护模式概述
6. 汇编语言不等于CPU指令
7. 用WinDbg观察托管程序架构
8. Windows PE/COFF文件格式简述
9. 让WinDbg自动打开DotNet Runtime源程序
10. WinDbg综合实战

前言

本篇主要介绍WinDbg的下载、安装、主界面介绍、加载被调试程序、WinDbg命令类型、WinDbg命令列表、WinDbg帮助系统的使用。

下载与安装

WinDbg安装包并非普通exe或rar文件,而是扩展名为.appinstaller的微软应用商店安装包文件,文件名为windbg.appinstaller,下载请点击这里,如果链接失效,可以到这里查找。

备注:.appinstaller应用商店文件本质是xml文件,可以用任何文本阅读器打开。在Windows 10及以上环境双击该文件,Windows会自动连网,并到https://windbg.download.prss.microsoft.com/dbazure/prod/1-2402-24001-0/windbg.msixbundle下载真实的安装包文件并自动安装。

由于我的电脑已经安装好了,所以双击后会显示如下页面。图中左上角是原始安装文件,右上角是WinDbg应用程序Logo图像。
WinDbg安装界面
软件安装好以后,在开始菜单就可以找到WinDbg图标。在我的电脑上,该图标实际指向了这个文件:

C:\Program Files\WindowsApps\Microsoft.WinDbg_1.2402.24001.0_x64__8wekyb3d8bbwe\DbgX.Shell.exe。

WinDbg界面

打开的WinDbg,初始界面如下图所示。其中虚线框称为命令(Command)窗口,是我们调试程序时最常用到的窗口。该窗口底部红色实线框是命令输入栏,由于图示状态下尚未加载任何被调试程序,此时还无法输入任何调试命令,而是显示:

Debuggee not connected (当前未与被调试应用建立连接)。

启动后界面
上图中点击红色虚线圆所示的关闭符号,会关闭命令窗口,可以使用以下三种方式将该窗口再找回:

  • View -> Layouts -> Default(见下图右侧):此按钮将恢复系统默认窗口布局
  • View -> Command(见下图左侧):此按钮会显示Command窗口,可能需要重新定位
  • Alt + 1 快捷键

WinDbg还有其他窗口可用,如下图红色虚线框所示,读者可尝试使用。
恢复命令窗口

加载被调试程序

WinDbg是用来调试程序或进程的,只有和被调试程序或进程进行了连接,才能输入调试命令。

在上图中点击左上角的文件按钮,就会打开如下图所示界面:

在这里插入图片描述

界面很简洁,可以打开exe文件,也可以让WinDbg附加到已经运行的进程上,或者使用调试器打开转储文件(俗称Dump文件),甚至可以调试内核等。本系列文章主要使用打开exe文件方式,也就是上图中的第二项(Launch executable)。本文中,我将使用一个自编的C#小程序(Core.exe)作为示例,但你可以调试任何其他应用Windows程序,比如Windows自带的记事本程序(notepad.exe)。

一旦选定了被调试对象,WinDbg就会启动程序加载,期间命令窗口会输出很多信息。启动完成后的界面如下图所示。此界面和前面界面之间的最主要差别是:命令行已经不是灰显了,可以输入调试命令了。除此以外,左上角还列出了被调试的程序、WinDbg版本,命令窗口还会输出更多信息,比如截图显示:当前使用的是64位版本的WinDbg(因为有AMD64)。

在这里插入图片描述
图中命令行左侧的**0:000>**是命令行提示符,冒号左侧的0代表的是进程号,冒号后面的000代表的是当前线程。既然调试一个应用程序实际上就是打开了一个操作系统进程,而一个进程可能会包含数个线程,所以输入命令时一定要关注当前处于哪个进程和哪个线程。

在命令行输入波浪号 ~ 并回车,可以显示当前所有线程。

如下图所示,我的调试器当前有两个线程,分别是0号和1号线程。切换线程的命令是 ~[线程ID]s,比如输入 ~1s就会将当前线程切换到1号线程,命令行提示符也会发生相应变化。您可以试试在不同的线程下输入k命令显示当前栈帧,会发现0:000>和0:001>下的栈帧结果是不同的,比如1号线程栈中的KERNEL32模块在0号线程中就不存在:

CPU与线程

备注:如果WinDbg是以内核态调试,则命令行提示符会包含kd字样,意思是kernel debug,如果被调试电脑有多个CPU,则KD前还会显示CPU编号。如:

0: kd> 

如果调试器暂时正忙于处理未执行完毕的上一条命令,则命令行会显示BUSY字样。系统BUSY时,虽然可以输入新命令,但系统必须等到之前命令执行完毕以后才能执行新命令。下图所示的BUSY是因为WinDbg正在从微软符号服务器下载符号。

在这里插入图片描述
如果被调试程序处于运行状态,则不仅有BUSY标记,还会显示Debuggee is running,此时无法输入命令。这种情况下,必须先使用Break按钮将被调试程序中断到调试器,然后才能输入命令,如下图所示:
在这里插入图片描述

WinDbg帮助

WinDbg功能实在太过强大了,真想将其写透,至少需要上千页的文章。

不过,我们并不需要学会所有功能以后才开始实际调试。WinDbg是图形界面,简单上手其实非常容易,只要稍加学习即可。当确实需要深入研究某项具体功能时,可以使用WinDbg自带的帮助系统,也就是点击上图中右上方那个Local Help按钮,即可弹出帮助窗口,如下图所示:
帮助窗口
帮助窗口中有目录、索引、搜索和收藏夹四个选项卡,如上图红色框所示。如果需要系统学习,可以使用目录选项卡,此时整个帮助就如同一本教科书。建议初学者起码跟随图示Getting Started with WinDbg(User-Mode)操作一遍,算是初步入门。

如果需要深入了解某个具体命令,可以点击搜索选项卡,输入要查找的命令名回车,然后双击列表中合适的行,右侧就会出现该命令的详细解释。下图以查询bp命令为例说明:

搜索
上述示例中我们搜索bp,结果列出了bp, bu, bm三个命令在一行的一篇文章。

如果我们又想查找与bp命令相关的其他主题,比如我们想知道bp和bu有什么区别,那么我们可以使用索引选项卡,依旧输入bp,目录窗口会列出和bp相关的很多主题,比如在breakpoints主题下,我们发现有BP versus BU(BP与BU),双击即可直接显示这篇文章。
索引
如果此时又想知道Unresolved Breakpoints(bu Breakpoints)在整个帮助目录中的位置,那么我们可以再切换到目录选项卡,此时左侧的目录结构清晰表明,这篇文章位于Debugging Technique -> Standard Debugging Techniques -> Using Breakpoints目录下,其上一篇文章是Breakpoint Syntax(断点命令语法)。

另外,在命令行窗口直接输入.hh加上欲查询命令可以快速打开WinDbg帮助窗口并直接完成搜索,比如使用下面的命令同样可以达到前文所述效果,但速度更快。

0:000> .hh bp

WinDbg命令

WinDbg之所以非常强大,主要基于两项重大支撑:

  1. 丰富的命令
  2. 脚本支持

WinDbg命令非常多,如能熟练驾驭,调试Windows程序几乎可以说所向披靡。

不过正因为它的命令太多,也让熟练掌握该技术充满挑战。

脚本支持是建立在命令基础上的,WinDbg可以通过编写脚本(比如使用JavaScript、lambda表达式等),将诸多命令链接起来,实现复杂的调试和丰富且个性化的显示。微软官网有一系列有关WinDbg使用的视频,感兴趣的可以点击这里学习。

WinDbg有三种命令,分别称为基本命令,元命令和扩展命令,三者各自有不同的语法。

基本命令

可以直接在命令行输入的命令称为基本命令。基本命令是WinDbg自带的命令。以下例子使用 lmnm 命令列出 Core 模块的基本信息(加载起始地址、加载结束地址、模块名、所属文件):

0:000> lmnm core
Browse full module list
start             end                 module   name
00000000`02330000 00000000`02338000   Core     Core.dll

WinDbg的基本命令是调试过程中使用最多的命令,其命令一般比较短,数量也并不很多。

可以使用?命令可以列出所有基本命令!

0:000> ?

Open debugger.chm for complete debugger documentation

B[C|D|E][<bps>] - clear/disable/enable breakpoint(s)
BL - list breakpoints
BA <access> <size> <addr> - set processor breakpoint
BP <address> - set soft breakpoint
D[type][<range>] - dump memory
DT [-n|y] [[mod!]name] [[-n|y]fields]
   [address] [-l list] [-a[]|c|i|o|r[#]|v] - dump using type information
DV [<name>] - dump local variables
DX [-r[#]] <expr> - display C++ expression using extension model (e.g.: NatVis)
E[type] <address> [<values>] - enter memory values
G[H|N] [=<address> [<address>...]] - go
K <count> - stacktrace
KP <count> - stacktrace with source arguments
LM[k|l|u|v] - list modules
LN <expr> - list nearest symbols
P [=<addr>] [<value>] - step over
Q - quit
R [[<reg> [= <expr>]]] - view or set registers
S[<opts>] <range> <values> - search memory
SX [{
   
   e|d|i|n} [-c "Cmd1"] [-c2
### 大模型对齐微调DPO方法详解 #### DPO简介 直接偏好优化(Direct Preference Optimization, DPO)是一种用于改进大型语言模型行为的技术,该技术通过结合奖励模型训练和强化学习来提升训练效率与稳定性[^1]。 #### 实现机制 DPO的核心在于它能够依据人类反馈调整模型输出的概率分布。具体来说,当给定一对候选响应时,DPO试图使更受偏好的那个选项具有更高的生成概率。这种方法不仅简化了传统强化学习所需的复杂环境设置,而且显著增强了模型对于多样化指令的理解能力和执行精度[^2]。 #### PAI平台上的实践指南 为了便于开发者实施这一先进理念,在PAI-QuickStart框架下提供了详尽的操作手册。这份文档覆盖了从环境配置直至完成整个微调流程所需的一切细节,包括但不限于数据准备、参数设定以及性能评估等方面的内容。尤其值得注意的是,针对阿里云最新发布的开源LLM——Qwen2系列,文中给出了具体的实例说明,使得即使是初次接触此类工作的用户也能顺利上手。 ```python from transformers import AutoModelForCausalLM, Trainer, TrainingArguments model_name_or_path = "qwen-model-name" tokenizer_name = model_name_or_path training_args = TrainingArguments( output_dir="./results", per_device_train_batch_size=8, num_train_epochs=3, ) trainer = Trainer( model_init=lambda: AutoModelForCausalLM.from_pretrained(model_name_or_path), args=training_args, train_dataset=train_dataset, ) # 假设已经定义好了train_dataset trainer.train() ``` 这段代码片段展示了如何使用Hugging Face库加载预训练模型并对其进行微调的过程。虽然这里展示的例子并不完全对应于DPO的具体实现方式,但它提供了一个基础模板供进一步定制化开发之用[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值