首页 > 其他分享 >windbg 基本调试

windbg 基本调试

时间:2023-04-05 09:22:39浏览次数:24  
标签:基本 windbg 托管 转储 命令 线程 断点 调试 调试器

控制调试目标
中断执行
按ctrl + c 来中断程序执行

恢复执行
g 不带任何参数,只是恢复调试目标的执行,直到下一次发生某个调试事件

如果不希望调试器在初始启动时停止程序的执行,在启动调试器时加 -g 如 ntsd -g a.exe

单步调试代码
p step
p 的变种 pt 会一直执行指令,直到遇见一个Ret指令。
pc可以很快地执行到下一个Call指令

t trace 执行单条指令,并显示所有寄存器的结果。命令t在执行call指令或者中断指令时的行为
t的变种
ta <address> 执行到address指定的地址,并将包含被调用函数的单步执行显出来
tc 执行到下一个call指令,并将包含被调用函数的单步执行显示出来。
tt 执行到下一个ret 指令,并将包含被调用函数的单步执行显示出来。

退出调试会话
q 退出调试会话并终止调试目标
qd quit and detach 结束调试会话,但让调试目标继续运行。

加载托管代码调试的扩展命令
非托管调试器中可以使用两种不同类型的命令

元命令 指在调试引擎中内置的命令。如help sympath cls 等,必须在命令前面加上前缀"."
扩展命令 是在调试器引擎之外的独立DLL中实现的,这些DLL也被称为调试器扩展。在执行扩展命令时,要在命令前面加上前缀 “!” ,如!htrace -enable ,在调试托管代码时,有两个DLL需要注意,它们是SOS 和SOSEX
在使用这些扩展DLL之前,必须通过元命令load 来通知调试器。 如.load c:\abc.dll
加载SOS调试器扩展
SOS调试器扩展的DLL (sos.dll)与程序使用的CLR版本是相关的。因此需要加载与目标程序CLR版本一致的sos.dll
如.load c:\windows\Microsoft.NET\Framework\v2.0.50727\sos.dll
这个方法太难用,我们可以用另一个元命令 loadby 语法如下
.loadby DLLName ModuleName
元命令将会找出由ModuleName指定的路径,并且使用这个路径来加载指定的DLLName
例如正在查找的模块是 mscorwk,则只需执行以下命令
.loadby sos.dll mscorwks
如果目标程序的mscorwks模块还没有被加载,那么loadby 将提示错误信息。
如果需要在加载mscorwks模块时立即加载SOS调试器扩展,那么可以使用sxe 命令
sxe ld 可以使得在加载某个特定的模块后,立即中断进入到调试器,然后加载SOS调试器扩展
如 sxe ld mscorwks.dll

加载SOSEX调试器扩展
SOSEX可以用于调试托管代码。增强了SOS的功能,使某些特定的调试任务更高效。
加载SOSEX的命令
.load sosex.dll
或指定sosex.dll的完整路径。
虽然在没有加载mscorwkd.dll的情况下也能加载sosex扩展,但这些命令本身并不能工作。

控制CLR的调试
在调试.Net程序时,调试器可以加载一个辅助DLL 称为mscordacwks.dll ,这个dll用于输出托管代码调试过程中的各种信息,这个dll的路径取决于mscorwks.dll的路径。在实时调试中不会有问题,但在事后调试时可能出现版本不匹配的情况。可以使用cordll来告诉调试器加载mscordacwks.dll的确切位置
.cordll -lp c:\x\y\z 从文件夹c:\x\y\z下加载mscordacwks.dll
如果要卸载mscordacwks.dll可以使用-u 开关。

设置断点
非托管调试中使用bp命令来断点。
使用X 来显示包含 指定函数字符串的所有符号 ,bp的参数可以是 函数名,或地址。

在JIT编译生成的函数上设置断点
先让目标程序运行一次函数,确保已经被JIT编译器编译,然后通过SOS命令 name2ee 来判断
!name2ee <module name> <type or method name>
如果在最后一行输出中 这个方法的状态为JITTED 表示已被 JIT编译器编译过了,并且会给出地址。
可以通过命令U 对这一段代码做一个简单的完整性检查。
!U <address>

!ClrStack 来查看代码位置

在还没有被JIT编译的函数上设置断点
bpmd 用来在还没有被JIT编译的代码上设置断点。它采取的做法是设置一个延时断点,在设置该断点时,断点的位置是未知的,只有将来某个事件发生时,才会真正地设置断点。

在预编译的程序集中设置断点
使用ngen.exe 预编译 !name2ee 可以直接断点指定的函数。

在泛型方法上设置断点
!bpmd aaa.exe XXX`1.method
1
对象检查
内存转储
dd <address> 查看内存
du <address> 把被转储的内存视作Unicode字符
da <address> 把被转储的内存视作ASCII字符
dw <address> 把被转储的内存视作字word
db <address> 把被转储的内存视作字节值和ASCII字符
dq <address> 把被转储的内存视作四字quad word 值

!dumpobj <addr> 可以转储更多信息

值类型的转储
如何判断一个指针指向的是否是值类型?用DumpObj命令试一下就知道了,如果给定的指针指向一个值类型,会报错。
!DumpObj <addr>
如果要显示插管调用栈及相关的局部变量,可以通过ClrStack命令来获取。
!ClrStack -a

如果ClrStack提示错误,指出当前线程上下文不是一个有效的托管线程,需要先切换线程上下文。使用 ~ 将上下文切换到线程0 再执行ClrStack
~0s

通过命令r将寄存器转储出来。

!DumpVC <方法表地址> <地址> 给出方法更为详细的信息,如值类型的名字和大小。

转储基本的引用类型
!DumpObj [-nofields] <obj addr> DumpObj会转储出类型信息及相关的域
这个命令可以缩写为 do

数组的转储
!DumpArray -details <addr> 输出数组的详细信息 DumpArray会自动识别出正在处理的是值类型还是引用类型。

栈上对象的转储
大多时候可以用ClrStack 命令来找出每个栈帧的参数和局部变量
DumpStackObjects 可以对栈进行遍历,并输出栈上的所有托管对象。语法:
!DumpStackObjects [-verify] [top stack [bottom stack]]

如果没有指定任何参数,那么DumpStackObjects 会输出当前线程的所有托管对象。
DumpStackObjects 太长,可以缩写成dso ??

找出对象的大小
对象的大小表示这个类型所占据的内存字节数量。
!DumpObj 可以获得对象大小
通常,对象会引用其它对象,如果要获得对象的总体大小(包括遍历每个类型域的大小)可以使用ObjSize命令
!ObjSize <addr> 如果没有指定地址,那么这个命令将列出进程中所有托管线程中所有对象大小。

异常的转储
Windows在实现异常模型时采用的方法之一就是结构化异常处理(SEH),CLR在每个异常内携带的额外信息被保存在托管堆上。异常是一种引用类型,所有CLR异常都以SHE异常形式出现,错误码为0xe0434f4d

用 kb来输出调用栈。

SOS调试器扩展中包含一个命令 PrintException 参数是托管异常的地址,能以更容易理解的形式输出异常信息。
!PrintException <addr>
另一个有用的命令是 Threads 能显示出系统中各个托管线程的信息,包括该线程抛出的最后一个异常。
!Threads
StopOnException 这个命令的作用是在抛出特定异常时设置一个断点。语法
!StopOnException [-derived] [-create | -create2] <Exception> [<pseudo-register number>]

!StopOnException -create System.ArgumentException

线程的操作
SOS调试器扩展提供了一组线程命令

ClrStack
!ClrStack 可以输出线程ID和托管调用栈的所有栈帧
!ClrStack -l 用于显示局部变量信息(没有名字)
得到变量的地址后,可以用!DumpObj <addr> 来输出变量信息
!ClrStack -p 将显示调用栈上每个托管代码栈帧的所有参数。

Threads
!Threads 可以枚举进程中的所有托管代码线程。
Threads命令包含了一组开关,-live开关将Threads命令限制为只输出那些活跃状态的线程信息。 -special 开关表示输出进程的所有特殊的线程,如垃圾收集线程,调试器线程,线程池定时器线程等。

DumpStack
ClrStack只给出托管代码调用栈,k系列命令只给出非托管调用栈。要同时转储出托管代码调用栈和非托管代码调用栈,可以使用DumpStack命令。

DumpStack 使用-EE 开关表示只显示托管函数。

EEStack
EEStack 会对进程中每个活跃的线程调用DumpStack
两个开关: -short 只输出感兴趣的线程调用栈。即 (这个线程持有一个锁。线程被劫持以执行一个垃圾收集操作。线程当前正在托管代码中执行) -EE 这个开关会直接传给DumpStack命令,表示只显示托管代码调用栈。

COMState
当与COM子系统一起使用时,重点是要知道COM提供的不同套间模型。COM提供了两种主要的套间模型。1,单线程套间 STA 2,多线程套间 MTA 。每当一个线程希望使用COM对象时,它必须告诉COM子系统它需要使用哪一种套间模型。在具体套间模型中对线程进行初始化的概念非常重要,在调用COM互用性问题时,找出线程的套间模型是一个更为重要的方面。
COMState 可以找出系统中每个线程的套间模型。
!COMState

代码审查
反汇编代码
命令u 把代码字节流反汇编为汇编指令,因而能很容易推断出代码所要执行或者曾经执行的功能。
u适用于非托管代码,对于托管代码可以使用 !U <addr> U命令除了指定代码地址外,还可以指定一个方法描述符。

从代码地址上获得方法描述符
!IP2MD <code addr> 将任意的托管代码地址转为一个方法描述符,然后就可以使用DumpMD命令获得进一步的信息。

显示中间语言指令
!DumpIL <addr> 来查看函数的IL
该命令以方法描述符的地址作为参数,从IP2MD 可以得到方法描述符地址。

CLR内部命令
获得CLR的版本
!EEVersion

根据名字找到方法描述符
如果有了某个方法的名字后,找出方法描述符最有用的方法之一就是Name2EE命令 ,其参数是模块的名字和方法的全名,这个命令将输出方法的一些信息,包括方法描述符。

对象同步块的转储
每个CLR托管类型都有一个相应的同步块,用于实现同步行为。 SyncBlk 命令可以用来获得这个同步块的详细信息,这个命令在分析死锁问题时非常有用。

对象方法表的转储
每个托管对象都有一个相应的方法表,其中包含了该对象的一些信息。DumpMT命令可以用来显示方法表的信息,命令参数是方法表的地址。

托管堆和垃圾收集器信息的转储
命令 描述
DumpHeap 遍历托管堆,收集并输出这个堆以及位于堆上所有对象的详细信息
GCRoot 显示对某个对象的引用(根对象)信息。当要找出某个对象为什么还没有被收集时,这将是非常有用的信息
TraverseHeap 遍历托管堆,并把遍历结果输出到一个文件中,由CLR分析器来进行分析
VerifyHeap 与任何堆一样,托管堆可能被破坏,这个命令将验证托管堆的完整性
诊断命令
找出对象的应用程序域
要找出指定的对象实例位于哪一个应用程序域中,可以使用 FindAppDomain 命令,知道了对象的应用程序域之后,可以使用 DumpDomain 来获取应用程序域的进一步信息。

进程信息
用ProcInfo命令
!ProcInfo [-env] [-time] [-mem] 如果不加参数会显示所有这三类信息。

SOSEX扩展命令
扩展的断点支持
断点列表
!mbl 显示所有的断点
mbc 将从列表中清除指定的断点,或清除所有断点
mbd 将禁用列表中指定的断点,或禁用所有的断点
mbe 将启用列表中指定的断点,或启用所有的断点

设置断点
mbp 这个命令可以在任意给定的源代码位置上设置断点。
mbm 可以在特定类型的指定IL偏移处设置一个断点。
!mbm *!Advanced.NET.Debugging.Chapter3.Simple.Main 0
mbm 的选项
!mbm <strTypeAndMethodFilter> <intILOffset> [Options]
其中Options 可以是 /1 只触发这个断点一次。 /p: 表示在第几次执行到断点时才停止执行程序。 /t: 只有由threadID指定线程才可以触发这个断点。
mbm 支持在strTypeAndMethodFilter中使用通配符。

托管元数据
如果想找出类型名和方法名,可以使用mx命令,语法为 !mx <filterString> 其中参数 filter string 表示查找元数据的通配符。
另一个有用的命令是 mln 参数是一个地址,可以识别出与该地址上内容相关的代码,可以准确地识别出JIT已编译的代码,堆及栈对象
————————————————
版权声明:本文为CSDN博主「Pelva」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_33074817/article/details/121899511

标签:基本,windbg,托管,转储,命令,线程,断点,调试,调试器
From: https://www.cnblogs.com/luluping/p/17288829.html

相关文章

  • stm32f407探索者开发板(十三)——JLINK在线调试_软件调试_方法与技巧
    文章目录一、JTAG/SWD调试原理1.1调试原理简析二、在实验中讲解调试方法2.1调试之前的配置2.2调试一、JTAG/SWD调试原理1.1调试原理简析STM32F4xx的内核是CortexTM-M4F,该内核包含用于高级调试功能的硬件。利用这些调试功能,可以在取指(指令断点)或取访问数据(数据断点)时停止内......
  • 内核错误调试技巧记录
    printk打印调试include/linux/printk.h头文件externintconsole_printk[];#defineconsole_loglevel(console_printk[0])#definedefault_message_loglevel(console_printk[1])#defineminimum_console_loglevel(console_printk[2])#definedefault_console_loglevel......
  • 系统架构设计——DDD设计框架基本学习
    摘要最近DDD设计很火,但是刚刚入门还是很懵,通过的学习DDD项目设计的结构目录来实现对DDD设计理解同时也是为大家在公司能够看懂公司的DDD项目结构目录做一个参考和学习。同时后期本人将推出更多的对DDD设计的理解。同时提供一个DDD设计的模板框架:https://github.com/2462612540/Seni......
  • DayOne-Vue的基本使用指令以及过滤器
    一、Vue1、什么是VueVue是一个流行的JavaScript框架,用于构建用户界面。它被设计成渐进式的,可以逐步应用到现有的项目中,也可以构建全新的应用。Vue的核心库只关注视图层,因此易于集成到其他库或现有项目中。Vue具有响应式和组件化的特性,使得开发者可以更轻松地管理和维护复杂的用......
  • 使用内网穿透调试微信小程序
    随意购买一个,登陆后台,选择隧道管理下载客户端点击bat批处理文件输入隧道id回车即可进入微信小程序编程工具将这个勾给勾上,然后修改HTTP_REQUEST_URL即可创作不易,如果能够解决您的问题,请给我点个赞,谢谢......
  • VUE watch监听器的基本使用方法详解
    1、下面代码是watch的一种简单的用法<divid="app"><inputtype="text"v-model="firstName"/></div><scriptsrc="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script><script>......
  • windbg调试命令8(bp、bu、bm、bl、bc、ba、be、bd)
    以下以skinhgy为例,windbg附加运行1.bp命令是在某个地址下断点,可以bp0x7783FEB也可以bpMyApp!SomeFunction对于后者,WinDBG会自动找到MyApp!SomeFunction1)当代码修改之后,函数地址改变,该断点仍然保持在相同位置,不一定继续有效; 2)WinDBG不会把bp断点保存工作空间中bp Addre......
  • 生成对抗网络 GAN 基本原理与发展历程
    1、什么是GAN背景知识:快速掌握机器学习(MachineLearning)常用概念术语,常用算法快速掌握深度学习(DeepLearning)常用概念术语,常用模型从人工到自动的机器学习:从人工提取特征到自动提取特征相对于传统的机器学习,深度学习厉害的地方就是能够自己学习特征提取。机器学习:数据预处......
  • 测试和调试 容器化Node应用
    TestingandDebuggingaContainerizedNodeapplicationIntroductionContainersingeneralandDockerinspecifichavechangedthewayhowwethinkaboutrunninganddeployingsoftwarequiteabit.Runninganapplicationinacontainerinsteadofdirectl......
  • Typora软件基本实用语法
    一、代码块```(即键盘上ESC按键的下面那个符号)后面跟上你的程序语言后缀,就能实现代码块的插入(例如:```c```java```php等)实例publicvoidtest(){System.out.println("HelloWorld!");}```java显示灰色代码块之后再输入代码内容二、各级标题#后面空一格,再加上标题......