嵌入式软件调试之软件断点

李肖遥 2021-12-22 22:08
    关注、星标公众号,直达精彩内容

来源:CSDN | maomao171314

整理:技术让梦想更伟大 | 李肖遥

软件断点

INT 3 指令,即通常所说的“软件断点”,一条X86系列处理器专门用于支持调试的指令。该指令目的是使CPU中断(break)到调试器,供调试器对执行现场进行各种分析。

INT 3

Visual C++ 嵌入内联汇编指令,示例如下:

VS没有下断点,程序会自动断在INT 3 指令所在的位置。这正是通过注入代码手工设置断点的方法。

反汇编窗口如下:

内存地址002719CE 处有INT 3 指令。

打开寄存器窗口,EIP=002719CE

INT 3属于陷阱异常,当CPU产生异常时,EIP指向的是导致异常的下一条指令。但是EIP指向的是导致异常的指令——为什么会发生回跳?

断点命中

当CPU执行INT 3指令时,在执行异常处理例程之前,CPU会保存当前的执行上下文。

实模式下INT 3 指令的执行过程:

1 REAL-ADDRESS-MODE:

2 IF ((vector_number ∗ 4) + 3) is not within IDT limit  //检查根据向量号计算出向量地址是否超出了边界

3 THEN #GP;//发生保护性错误异常

4 FI;//IF语句的结束语句

5 IF stack not large enough for a 6-byte return information //检查栈是否有空间保存寄存器

6 THEN #SS;//堆栈不足以保存要压入的6字节内容(CS、IP和EFLAGS的低16位),产生堆栈异常

7 FI;//IF语句的结束语句

8 Push (EFLAGS[15:0]);

9 IF ← 0; (* Clear interrupt flag *) //清除IF

10 TF ← 0; (* Clear trap flag *) //清除TF

11 AC ← 0; (* Clear AC flag *) //清除AC

12 Push(CS); //保存当前段寄存器

13 Push(IP); //保存程序指针寄存器

14 (* No error codes are pushed *)

15 CS ← IDT(Descriptor (vector_number ∗ 4), selector));  //将异常处理例程入口地址加载到CS和IP寄存器

16 EIP ← IDT(Descriptor (vector_number ∗ 4), offset)); (* 16 bit offset AND 17 0000FFFFH *)

在实模式的单任务操作系统,CPU直接执行调试器注册的断点异常处理例程。然后执行中断返回指令(IRET),恢复被调试程序,从断点位置继续执行。

保护模式下的INT 3指令的执行流程原理上与实模式一致。

Windows保护模式下的多任务操作系统,INT 3 异常的处理函数是内核函数KiTrap03。断点指令在用户模式下的应用程序代码中,CPU会从用户模式转入内核模式。经过几个内核函数分发和处理。由于这个异常是来自用户模式,且该异常的拥有进程正在被调试(进程的Debug Port不为0),所以内核例程会把这个异常通过调试子系统以调试事件的形式分发给用户模式的调试器,内核的调试子系统会等待调试器的回复,收到调试器的回复后,调试子系统会返回到异常处理例程,异常处理例程执行IRET指令使被调试程序回复执行。

在调试器收到调式事件后,会在内部寻找与其匹配的断点记录。如果能找到,则允许用户进行交互式调试。如果找不到,则说明该断点是程序内置的断点,会弹出异常。

在Windows中,操作系统的断点异常处理函数对于x86 CPU的断点异常会有一个特殊的处理:将EIP的值减1。出于这个原因,我们在调试器看到的程序指针指向的仍然是INT 3指令的位置,而不是它的下一条指令。这样处理的目的是:

  1. 调试器在落实断点时只替换一个字节,如果程序指针发生改变指向了下一条指令的位置,指向的可能是原来多字节指令的第二个字节,不是一条完整的指令,造成程序的错误。

  2. 由于断点的存在,被调试程序于断点位置的指令在断点触发时还未被执行,按照“程序指针总是指向将要执行的那条指令”的原则,应该让其指向原指令,即倒退一个字节,指向原指令起始位置。

至此,回跳的问题得到了解答。

恢复执行

当用户结束分析希望恢复被调试程序执行时,调试器通过调试API通知调试子系统,这会使系统内核的异常分发函数返回到异常处理例程,然后异常处理例程通过IRET/IRETD指令触发一个异常返回动作,使CPU恢复执行上下文,从发生异常的位置继续执行。

当断点命中中断到调试器时,调试器会把所有断点处的INT 3替换成原本的内容,因此当用户发出恢复执行的命令后,调试器在通知系统真正恢复程序的执行前需要将断点列表所有断点全部落实一遍,但是对于命中的断点需要特殊处理——如果落实了命中断点,那么程序一恢复执行便会再次触发断点;如果没有落实,程序下次执行到该部分便不会中断。对于这种情况,大多数调试器的做法都是先单步执行一次,设置单步执行标志,然后恢复执行,将断点所在位置的指令执行完。由于设置了单步标志,CPU执行完断点位置的这条指令后会再次中断到调试器中,这次调试器不会通知用户,而是做一些内部操作后恢复程序的执行,而且将所有断点落实,这一过程一般称为“单步走出断点”,如果用户在恢复程序执行前取消了该断点,就不需要单步执行一次。

INT 3指令的特殊用途

由于INT 3 指令的特殊性,对应的机器码是0xCC,对应的汉字是“烫”。编译器在编译调试版本时会用0xCC填充刚刚分配的缓冲区,就是下图经常见到的情形:

编译器还用INT 3 指令来填充函数或代码段末尾的空闲区域,即用它来做内存对齐。

断点API

用户模式,使用DebugBreak() API ,内核模式下使用DbgBreakPoint() 或DbgBreakPointWithStatus() API 主动插入断点。

DebugBreak() 反汇编如下,只是对INT 3指令的简单包装:

1 lkd> u nt!DbgBreakPoint

2 nt!DbgBreakPoint:

3 804df8c4 cc int 3

4 804df8c5 c3 ret

DbgBreakPointWithStatus()允许向调试器传递一个整型参数:

lkd> u nt!DbgBreakPointWithStatus

804df8d1 8b442404 mov eax,[esp+0x4]

804df8d5 cc int 3

其中[esp+0x4]代表DbgBreakPointWithStatus函数的第一个参数。

0xCD03

INT 3指令与当n=3时的INT n指令不同,INT n指令对应的机器码是0xCD后跟1字节的n值,比如INT 23H会被编译为0xCD23。与此不同的是,INT 3指令具有独特的单字节机器码0xCC。用户可以通过_EMIT伪指令来直接嵌入机器码。

#include

int main()

{
    // 手工断点

    _asm INT 3;

    printf("Hello INT 3!\n");

    _asm

    {

        mov eax, eax

        __asm _emit 0xcd __asm _emit 0x03

        nop

        nop

    }

    //或者使用Windows API

    DebugBreak();

   return 0;

}

C++程序在执行的过程中会中断到调试器,但是继续执行会报访问冲突错误。使用windbg打开可执行文件,在反编译窗口中发现了0xCD03指令

00421a9e cc                      int     3

00421a9f 68c47b4200      push   offset test!`string' (00427bc4)

00421aa4 e89ef9ffff          call    test!ILT+1090(_printf) (00421447)

00421aa9 83c404             add    esp,4

00421aac 8bc0                 mov    eax,eax

00421aae cd03                int      3

00421ab0 90                   nop

00421ab1 90                   nop

00421ab2 8bf4                mov     esi,esp

00421ab4 ff155cb04200    call      dword ptr [test!_imp__DebugBreak (0042b05c)]

反汇编程序将0xCD03翻译成了INT 3指令,继续执行,windbg会报以下错误

(c84.1e34): Break instruction exception - code 80000003 (first chance)

eax=0000000d ebx=01058000 ecx=23648826 edx=79dc4a6c esi=004213e3 edi=00fef828

eip=00421aaf esp=00fef75c ebp=00fef828 iopl=0         nv up ei pl nz na pe nc

cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206

test!main+0x2f:

00421aaf 0390908bf4ff    add     edx,dword ptr [eax-0B7470h] ds:002b:fff48b9d=????????

其中80000003是系统定义的断点异常代码,此时程序的EIP=0X00421aaf,这指向的是位于0x00421aae的0xCD03指令的第二个字节。由于EIP指向的是一条指令的中间而不是起始处,后面的指令都错位了。以下为对比

#中断前的反汇编

00421a9e cc                     int     3

00421a9f 68c47b4200      push   offset test!`string' (00427bc4)

00421aa4 e89ef9ffff          call    test!ILT+1090(_printf) (00421447)

00421aa9 83c404             add    esp,4

00421aac 8bc0                 mov    eax,eax

00421aae cd03                int      3

00421ab0 90                    nop

00421ab1 90                   nop

00421ab2 8bf4                mov     esi,esp

00421ab4 ff155cb04200    call      dword ptr [test!_imp__DebugBreak (0042b05c)]
#中断后的反汇编

(c84.1e34): Access violation - code c0000005 (!!! second chance !!!)

eax=0000000d ebx=01058000 ecx=23648826 edx=79dc4a6c esi=004213e3 edi=00fef828

eip=00421aaf esp=00fef75c ebp=00fef828 iopl=0         nv up ei pl nz na pe nc

cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010206

test!main+0x2f:

00421aaf 0390908bf4ff    add     edx,dword ptr [eax-0B7470h] ds:002b:fff48b9d=????????

可以看到,中断后余下的指令都已变得面目全非。由于EIP总是指向将要执行的指令,因此程序会尝试访问eax-0B7470h的内存地址,该地址为非法,因此会导致访问失效错误。

导致该EIP错位的原因是KiTrap03在分发这个异常前总是会将EIP减1,对于单字节的INT 3指令,这样的减法过后刚好指向INT 3指令或原来指令的起始地址。但是对于双字节的0xCD03指令,执行后EIP指向的是该指令的第二个字节处。解决方法为在断点命中后手动修改EIP,重定向至原本的下一指令处,调整后程序可以继续执行。

0:000> r eip = eip+1

# 修改eip后的反汇编

KERNELBASE!DebugBreak+0x2:

76aff092 cc                  int     3

76aff093 c3                  ret

76aff094 8bff                mov     edi,edi

76aff096 55                  push    ebp

76aff097 8bec              mov     ebp,esp

76aff099 68ffff0080      push    8000FFFFh

76aff09e 6a03              push    3

76aff0a0 ff7504            push    dword ptr [ebp+4]

归纳与提示

软件断点具有以下局限性:

  • 属于代码类断点,适用于代码段,不使用于数据段和I/O空间

  • 对在ROM中执行的程序(如BIOS)无法动态加载软件断点

  • 在VDT或IDT还未准备就绪或被破坏的情况下,软件断点无法正常工作

原文链接:https://blog.csdn.net/maomao171314/article/details/109749352


版权归原作者所有,如有侵权,请联系删除。

‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧  END  ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧

关注我的微信公众号,回复“加群”按规则加入技术交流群。

欢迎关注我的视频号:

点击“阅读原文”查看更多分享,欢迎点分享、收藏、点赞、在看。

李肖遥 公众号“技术让梦想更伟大”,作者:李肖遥,专注嵌入式,只推荐适合你的博文,干货,技术心得,与君共勉。
评论
  • 近日,紫光展锐正式推出高性能4G 智能穿戴平台W377E。该产品面向不同的应用场景,拥有丰富特性和超低功耗,进一步壮大紫光展锐的智能穿戴产品组合。紫光展锐面向中高端和海量的智能穿戴市场,持续提供技术先进、高效安全、高质可靠的解决方案。 紫光展锐W377E采用四核A53架构,支持13M摄像头,video 1080P 30fps,集成了Wi-Fi、蓝牙和GPS功能。W377E搭载Android 8.1系统,提供更加丰富多样的APP体验,支持在线好友聊天、支付宝等功能,且支持64位系统的AP
    紫光展锐 2024-12-31 16:26 104浏览
  • 根据Global Info Research项目团队最新调研,预计2030年全球CAN-Bus总线电缆产值达到2287百万美元,2024-2030年期间年复合增长率CAGR为3.6%。一、行业概述CAN-Bus总线电缆是一种专门用于CAN总线(Controller Area Network,控制器局域网络)通信系统中的电缆。CAN总线是一种广泛应用于汽车、工业自动化、机器人等领域的串行通信协议,主要用于微控制器和设备之间的数据交换。CAN-Bus电缆负责在多个设备间传输数据,保证信息的稳定传输和
    GIRtina 2024-12-31 11:00 93浏览
  • 感光百科:4000万片出货量背后的“技术经”目前,仅单点dToF,艾迈斯欧司朗的累积出货量就已超过了4000万片。大量采用的背后必然代表无数用户对这一技术的认可和信赖。究竟是什么魔力,让dToF传感器拥有如此强大的吸引力?又是怎样的know-how积累让艾迈斯欧司朗的dToF产品如此受到青睐?让我们再次回到底层原理来探究dToF 4000万片出货量背后的“技术经”。01、底层原理决定应用上限dToF传感器,顾名思义,直接飞行时间测量,基于光速不变,测量光子从发射端到接收端的光程差,从而直接计算二
    艾迈斯欧司朗 2024-12-30 18:21 82浏览
  • 高精度,抗干扰,设计灵活……一句话总结:打铁还需自身硬!2040年,人形机器人的数量或将超过人类,达到100亿个。 10月29日,沙特投资倡议论坛,在谈及AI和人形机器人赛道时,马斯克再一次大胆预测,描绘出上述令人震撼的未来景象,且预估每台机器人的价格将稳定在2万-2.5万美元之间。当下,技术飞速发展,众多机器人公司如雨后春笋般涌现。余建华,艾迈斯欧司朗资深应用工程师,深感对这个市场的期待,他表示每一个机器人关节的背后,都离不开位置传感器的精准掌控。这片市场的潜力,让人憧憬不已。在工业及消费中
    艾迈斯欧司朗 2024-12-30 17:25 52浏览
  • 全球领先的光学解决方案供应商艾迈斯欧司朗(瑞士证券交易所股票代码:AMS)近日宣布,于2024年6月26-28日携汽车智能照明和智能座舱解决方案及相关产品和技术,亮相位于昆山市花桥国际博览中心的第十九届汽车灯具产业发展技术论坛暨上海国际汽车灯具展览会(以下简称:ALE),展示艾迈斯欧司朗优质的光发射器、光学元件、微型模组、传感器等产品在汽车领域的创新应用,展位号B馆T202。乘着车灯产业盛会的东风,全国汽车标准化技术委员会灯具及灯光分技术委员会秘书长卜伟理, 蔚来汽车内外车灯团队专家及电气工程副
    艾迈斯欧司朗 2024-12-30 16:55 63浏览
  • 时源芯微EMC(电磁兼容)领域,充斥着众多专业术语,令人眼花缭乱。1 电磁兼容(EMC)定义:指电气装置或系统在共同的电磁环境条件下,既能保持正常功能,又不会对周围环境产生不良影响。2  电磁环境Electromagnetic Environment定义:指存在于某一特定场所的所有电磁现象的总和。3半电波暗室Semi-anechoic Chamber定义:一种屏蔽室,除地面安装反射接地平板外,其余内表面均覆盖有吸波材料。4 远场Far Field定义:在天线辐射的场域中,功率密度与距离
    时源芯微 2024-12-31 10:52 98浏览
  •         在之前的文章中,我们介绍了IEEE 802.3cz[1]协议,MultiGABSE-AU物理层中XMII、PCS子层以及两个可选功能的相关内容,本篇将介绍MultiGABSE-AU物理层PMA子层及PMD子层的相关机制。PMA子层        PMA子层位于PCS子层和PMD子层之间,规范中定义了PMA子层的三个功能:PMA Transmit、PMA Receive及PHY Control。&nbs
    经纬恒润 2024-12-30 18:16 96浏览
  • 在当今数字化时代,嵌入式系统无处不在,从我们手中的智能手机、智能手表,到汽车中的电子控制系统、工业自动化设备,嵌入式开发技术的发展历程宛如一部波澜壮阔的科技史诗,深刻地改变了我们的生活和社会的运作方式。萌芽阶段(20 世纪 60 - 70 年代)嵌入式开发的起源可以追溯到 20 世纪 60 年代。当时,计算机技术刚刚兴起,体积庞大且价格昂贵。为了满足特定设备的控制需求,工程师们开始尝试将计算机技术应用于一些专用系统中。这一时期,嵌入式系统的概念逐渐萌芽。1965 年,美国数字设备公司(DEC)推
    Jeffreyzhang123 2024-12-31 10:08 107浏览
  • 产品概述MG600Q2YMS3 是一款基于硅基碳化物(SiC)技术的高功率N沟道MOSFET模块,适用于高功率开关和电机控制应用,如轨道牵引系统。其设计旨在满足高效能和快速切换需求,为工业和能源领域提供可靠解决方案。主要特性1. 高电压和电流能力   耐压 (VDSS):1200 V   漏极电流 (ID):600 A2. 高效率与低损耗   碳化硅材料降低导通损耗和开关损耗,实现更高的转换效率。3. 快速切换性能 支持高频操作,适用于
    东芝铠侠代理 2024-12-31 10:33 65浏览
  • 先临三维普及化手持3D扫描仪Einstar搭载艾迈斯欧司朗SFH 4726AS红外LED,打造真彩扫描、人眼安全、超高性价比的照明解决方案;得益于双堆叠发射器技术和透明硅树脂封装,OSLON® Black系列的SFH 4726AS实现小尺寸、高功率、高效率和优化的热管理,有效减小散热设计的压力;采用3.75×3.75mm的透明硅树脂封装,内置1mm2堆叠红外芯片,单颗光功率可达2W以上,为手持扫描仪这样小巧空间的应用提供更多光源设计空间。全球领先的光学解决方案供应商艾迈斯欧司朗(瑞士证券交易所股
    艾迈斯欧司朗 2024-12-30 16:50 55浏览
  • 本文介绍Linux系统查看硬件配置及常用调试命令,方便开发者快速了解开发板硬件信息及进行相关调试。触觉智能RK3562开发板演示,搭载4核A53处理器,主频高达2.0GHz;内置独立1Tops算力NPU,可应用于物联网网关、平板电脑、智能家居、教育电子、工业显示与控制等行业。查看DDR获取内存信息下面数字以MB为单位。root@ido:/# free -mtotalused free shared buff/cache availableMem:
    Industio_触觉智能 2024-12-31 10:01 63浏览
  • “新时代,共享未来”2024年11月5日-10日,第七届中国国际进口博览会在上海圆满落幕。其中,3万平方米的汽车展区展览面积,也让观众笑谈进博会再次进入“车展”时间。全球15大整车品牌,40多家企业参展,其中不乏耳熟能详,七届进博会“全勤生”的国际知名OEM,也会有首次参加的“新面孔”,它们共同构成了今年汽车展区的“全家福”。近年来,中国汽车进口均超百万辆。因此,对跨国车企来说,中国市场的重要性不言而喻。同时,在电动化和智能化赛道中弯道超车的中国汽车市场,也是全球汽车行业竞争最为激烈的市场,在这
    艾迈斯欧司朗 2024-12-30 17:05 50浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦