zoukankan      html  css  js  c++  java
  • (转)调试程序时设置断点的原理

    简单总结:有软件断点和硬件断点

    软件断点:软件断点在X86系统中为中断指令INT 3,其二进制代码opcode是0xCC。当程序执行到INT 3指令时,会引发软件中断。操作系统的INT 3中断处理器会寻找注册在该进程上的调试处理程序。从而像Windbg和VS等等调试器就有了上下其手的机会。程序出错时常看到的”烫烫烫“、”锟斤拷“、”屯屯屯“等与这个终端指令有关

    硬件断点:X86系统提供8个调试寄存器(DR0~DR7)和2个MSR用于硬件调试。

    转自:https://zhuanlan.zhihu.com/p/34003929

    以下为原文:

    对于程序员来说,debug的时间往往比写程序的时间还要长。尤其对我这种专写bug为主的程序员来说,一个好的调试器意味着早点下班和休息。现在方便的调试器很多,有著名的Visual Studio(VS)等IDE,也有免费的Windbg和GDB等等。加个断点也很简单,就是按一下键而已。但你有没有想过,调试器Debugger并不能控制程序的执行顺序,为什么它可以让CPU在需要的地方停住呢?

    今天我们就来揭开调试断点的神秘面纱,并通过一个实例来看看调试器实际都做了些什么。调试器能够随心所欲的停止程序的执行,主要通过软件断点和硬件断点两种方式。

    软件断点

    软件断点在X86系统中就是指令INT 3,它的二进制代码opcode是0xCC。当程序执行到INT 3指令时,会引发软件中断。操作系统的INT 3中断处理器会寻找注册在该进程上的调试处理程序。从而像Windbg和VS等等调试器就有了上下其手的机会。

    我们先通过一个例子来看看调试器都倒了什么鬼:

    #include 
    int main ()
    {
    // This loop takes some time so that we
    // get a chance to examine the address of
    // the breakpoint at the second printf
    for (int i = 1; i < 100000000; i++)
       printf("Hello World!");
    for (int i = 1; i < 10000000; i++)
       printf("Hello World!");
    return 0;
    } 

    这是一个比较傻的Hello World程序。我们用Windbg打开它,并设置一个断点:

    这时Windbg会将自己Attach到该程序的进程,通过程序PE文件的debug节找到调试信息。在调试信息里面找到加断点行所在的机器代码,并把头一个字节用WriteProcessMemory()函数换成0xCC(INT 3)。

    让我们来验证一下:

    推荐点开全屏看,可能更清楚

    注意左边是Windbg窗口,右边是用Process view打开的进程空间,左右的红框是对应的。在我们设置断点之前,左右的内容是完全一样的,这里要特别注意printf编译出来的第一个二进制代码0x68。接下来我们设置断点,并开始运行,那100万个printf让我们有充分的时间,看看发生了什么:

    我们会发现push操作代码0x68600e2900的第一个字节被windbg换成了0xCC也就是INT 3。这样windbg就可以在执行到这里时被调度。

    不一会,windbg的断点到了:

    到达断点后,操作符又被还原为0x68,似乎什么都没有发生,用户被蒙在鼓里,是不是很有意思?

    实际上,一般情况下,调试器维护了一大组调试断点,在并把他们都换成了INT 3。在被调度回来后,会都填回去,并通过现在的地址判断是到了那个断点。软件断点没有数目限制。

    硬件断点

    X86系统提供8个调试寄存器(DR0~DR7)和2个MSR用于硬件调试。其中前四个DR0~DR3是硬件断点寄存器,可以放入内存地址或者IO地址,还可以设置为执行、修改等条件。CPU在执行的到这里并满足条件会自动停下来。

    硬件断点十分强大,但缺点是只有四个,这也是为什么所有调试器的硬件断点只能设置4个原因。我们在调试不能修改的ROM时,只能选择这个,所以要省着点用,在一般情况下还是尽量选择软件断点。

    还有个INT 1是单步调试命令,这里略过。

    其他

    Visual Studio有个有趣的特性是debug编译后,会把0xcc(INT 3)填入代码的空隙,这样一旦程序越界就会被VS捕捉而容易发现错误。而0xCCCC在中国的GBK编码是“烫”。有中国程序员翻看内存到代码段会发现很多"烫烫烫",不明所以,以为发生了什么神奇的事情。

    有些程序越界也会打出"烫烫烫":

    有的用户被吓得够呛,以为计算机过热了,喊烫了,赶紧关机,十分搞笑。

  • 相关阅读:
    实现响应式——Bootstrap的删格系统详解
    javascript-OOP基础详解
    简单又炫酷的two.js 二维动画教程
    AngularJS [ 快速入门教程 ]
    Js函数初学者练习(一)switch-case结构实现计算器。
    通过JS检测客户端是否禁用Cookie
    JavaScript数组去重多种方法
    前端页面灰白
    VUE 移动端只获取当前拍摄照片,不允许相册获取 及 input标签capture属性详解
    VUE 超好看气泡进度条组件
  • 原文地址:https://www.cnblogs.com/z-sm/p/11956004.html
Copyright © 2011-2022 走看看