想到一个有趣的问题,为什么 debug 模式可以进断点而 run 模式不行?

2020-11-20 09:50:14 +08:00
 wqgogogo
5564 次点击
所在节点    程序员
39 条回复
raaaaaar
2020-11-20 13:26:07 +08:00
好强。。
fl2d
2020-11-20 13:28:25 +08:00
matlab 随时可停🤔
no1xsyzy
2020-11-20 14:15:20 +08:00
以前 NOIP 用 Free Pascal 的时候看到文章说简单花指令 asm push pop 一下
然后看到 FP 有 asm,顺便玩了下,然后发现编译输出 debug 的话仅仅 asm push xxx; pop xxx; end; fc 一看,差了非常非常多的部分。而如果编译输出为 release,就只多了几个字节。
YenvY
2020-11-20 14:23:54 +08:00
atempcode
2020-11-20 17:22:20 +08:00
Java 的 debug 不是加 int 3 的,是 JVM 处理的。
Guaidaodl
2020-11-20 17:31:59 +08:00
@wqgogogo JPDA 了解一下.
GrayXu
2020-11-20 19:58:49 +08:00
@warush @Team 这么敏感吗,这个问题的最简单的解答,就是 1L 说的 INT 3,学了编译原理或者汇编什么的就能理解了。这种东西都能装逼那门槛也太低了…建议大家以及在读的本科学生好好学习 CS 基础核心课程。
akira
2020-11-20 20:08:07 +08:00
release 模式的话,可以用 ollydb 之类的来设置断点,唔。。。。
xuboying
2020-11-20 20:13:54 +08:00
@GrayXu #27 忽然想起一个梗,程序员分为 10 类,一类是折腾过硬件的,一类是没折腾过硬件的。
xiangyuecn
2020-11-20 20:23:18 +08:00
@magiclx #1 我胡乱猜测的:目测你说的这个应该是执行的时候发生的替换(几乎不可能是修改的编译后的文件),那么非 debug 模式,按道理也能进行替换,甚至插入指令。意思就是不管是不是 debug 模式都能 debug 。

唯一想到的可能就是:非 debug 模式下不好去定位到源文件,也不好去处理变量名(也许都丢失了),然后调试器的开发者懒得去支持非 debug 模式调试😂 任何语言通用,瞎猜的,无非就是为了避免使用者来找麻烦。
vantis
2020-11-20 21:24:42 +08:00
@xuboying 应该说 0 类是没折腾过硬件的 高电平是折腾过硬件的 233
pikaconan
2020-11-20 21:53:26 +08:00
软件工程专业...没学过编译原理...我确定学校没有安排这门课程...
afx
2020-11-20 21:58:26 +08:00
@GrayXu 编译原理真的讲这个吗
irytu
2020-11-20 22:21:54 +08:00
@magiclx 是的 再补充一个小细节,就是替换回原来的指令之后还需要把用户态 eip 往前挪一个字节,因为 trap 到内核后,内核栈存的 eip 是被替换指令字节的下一条指令,不然再次执行被替换指令就被 skipped 了
lujie2012
2020-11-20 22:35:03 +08:00
前面有楼主说到位了,建议看一下 LLVM 编译原理这本书。简单说,run 的编译过程,做了指令集的优化处理,而 debug 模式可以不做指令集的优化,另外会在编译的代码中加入调试代码,只有这样才能实时的 IDE 中看到内存和执行位置。
release 模式直接是汇编或者说是到了机器码,无调试,所以为了找到那一段代码 crash,会生成其他的文件来定位。

debug 过程生产的代码未必到了汇编或者机器码,而只是编译器自己解析的逻辑代码,当然可以 debug 。
MineDog
2020-11-21 09:48:36 +08:00
java 的话 debug 是 jvm 层面实现的,ide 只是在调用接口,具体没深入了解过
amimo
2020-11-21 10:15:16 +08:00
如果是 native 程序的话,这个问题的主要跟“调试器”相关,debug 模式下运行的程序受调试器控制。native 调试器实现主要依赖硬件和操作系统提供的调试机制,跟编译器,编译原理无关。
lewis89
2020-11-21 13:29:31 +08:00
@MineDog #36 道理是差不多的,都是在二进制指令 生成了中断指令,或者使用 mprotect 这种系统调用 触发一个软中断调用
mingl0280
2020-11-21 16:57:50 +08:00
归根结底不是什么 INT3 的问题(说这个的你用过 od/IDA 么),是 release 模式有优化,编译器会打乱代码行序并且清除大量的编译相关信息以提升运行性能。这样你最多能看到调用了啥函数(某些 stripped 了的程序你连调用栈信息都看不到,里面只剩各种指针了),内部有什么指令偏移多少的信息没了,调试器看到你的源文件的时候不知道去哪里找对应的指令下断点。
为啥 vs 的 release 模式就支持下断点呢,人家有 pdb 文件啊!
debug 模式下编译器会在程序中插入调试用的符号表,以及使用未优化的代码(确保每行源代码都能对应上特定的二进制指令),所以下断点容易得多。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://ex.noerr.eu.org/t/727396

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX