微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

将源与C ++程序的程序集相关联

分析零售版本中的核心转储通常需要关联任何特定模块和源代码的objdump 。 正常情况下,如果function相当复杂,将程序集转储与源代码关联起来会变得很痛苦。 今天我试着创build一个特定模块的assembly listing (带有编译选项-S ),期望我能看到一个具有汇编或相关性的交错源。 不幸的是,上市不够友好,所以我想知道

给定一个核心转储,我可以从中确定崩溃位置

objdump的失败模块通过重新编译程序集列表

带-S选项的模块。

是否可以与来源进行一对一的对应?

作为一个例子,我看到汇编列表

.LBE7923: .loc 2 4863 0 movq %rdi,%r14 movl %esi,%r12d movl 696(%rsp),%r15d movq 704(%rsp),%rbp .LBB7924: .loc 2 4880 0 testq %rdx,%rdx je .L2680 .LVL2123: testl %ecx,%ecx jle .L2680 movslq %ecx,%rax .loc 2 4882 0 testl %r15d,%r15d .loc 2 4880 0 leaq (%rax,%rax,4),%rax leaq -40(%rdx,8),%rdx movq %rdx,64(%rsp)

但无法理解如何解释像.LVL2123这样的标签和像.loc 2 4863 0这样的指令

如何判断你是否在Windows上编译?

Linux载波检测通知

0x0地址0xdeadbeef是什么意思?

为什么gcc不支持函数

当有一个tcp连接状态为`TIME_WAIT`时,tcp连接无法build立

注意所描述的答案,阅读通过汇编源代码,并根据符号(如函数调用,分支,返回语句)直观地确定模式是我通常做的。 我并不是否认它不起作用,但是当一个函数涉及到的时候,通过Assembly Listing的页面阅读是一件很痛苦的事情,而且经常会因为函数进入或者优化器简单的抛出而导致很less匹配该代码为它感到高兴。 我有一种感觉,看看Valgrind如何有效地处理优化的二进制文件,以及Windows中的WinDBG如何处理优化的二进制文件,这是我缺less的东西。 所以我虽然我会开始与编译器输出,并使用它来关联。 如果我的编译器负责修改二进制文件,它将是最好的人说如何与源关联,但不幸的是这是最没有帮助的, .loc真的是误导。 不幸的是,我经常需要通过不同平台上不可重复的转储来读取,而我花费的最less的时间是通过WinDBGdebuggingWindows Mini-Dump,并花费大量时间来debuggingLinux Coredumps。 我虽然这可能是我不正确做事,所以我想出了这个问题。

使用IDebugControl :: disassemble来查看子例程的指令

Win-build与MinGW-build之间的区别

如何select缓冲区大小?

由CreateFile()函数创build的文本文件不显示

如何展开堆栈以获取指定堆栈指针(SP)的回溯?

是否可以与来源进行一对一的对应?

答:不,除非所有优化都被禁用。 编译器可能最初每行发出一些指令(或类似指令的东西),但是优化器然后重新排序,分割,熔合并且通常完全改变它们。

如果我正在分解发布代码,我会看看应该与代码有明确逻辑关系的说明。 例如,

.LBB7924: .loc 2 4880 0 testq %rdx,%rdx je .L2680

看起来像一个分支,如果%rdx为零,它来自行4880.找到行,确定正在测试的变量,请记下它目前分配给%rdx 。

.LVL2123: testl %ecx,%ecx jle .L2680

好的,所以这个测试和分支有相同的目标,所以接下来知道%rdx和%ecx都是非零的。 原始代码的结构可能如下所示:

if (a && b) {

或者也许是:

if (!a || !b) {

优化器将两个分支重新排序

现在你已经有了一些结构可以与原始代码匹配,你也可以计算出寄存器的赋值。 例如,如果您知道被测试的东西是某个结构的数据成员,请往后读取以查看%rdx从内存中加载的位置:是否将其从某个固定偏移量加载到其他某个寄存器? 如果是这样,该寄存器可能是对象地址。

祝你好运!

.loc指令是你正在寻找的。 这些指示行#4863,4880等。在源和优化的汇编器之间没有完美的映射(这就是为什么你不止一次看到4880)。 但.loc是你如何知道它在文件中的位置。 语法是:

.loc <file> <line> <column>

除非静态链接到系统库,否则即使没有调试符号,二进制文件中也会有符号名称 – 连接到系统库函数名称

这些通常可以帮助缩小代码中的位置。 例如,如果在函数foo()中看到它调用open(),然后调用ioctl(),然后在调用read()之前崩溃,则可以很容易地在foo的源代码中找到该点。 (对于这个问题,你可能甚至不需要转储 – 在Linux上,你可以使用ltrace或strace获得相对于库和系统函数的崩溃发生的记录)

请注意,尽管如此,在一些二进制格式中,可能会通过二进制文件中其他位置的小型封装来实现库函数的间接访问。 转储通常在程序流程的调用地址中仍然有相关的符号名称信息。 但即使不是这样,你也可以通过它们在二进制文件中的地址范围来识别这些外部链接包装,当你看到一个链接时,你可以找到它的代码并找出它所链接的外部函数

但正如其他人所提到的,如果你有源代码和系统崩溃频率足够有用,你最快的选择通常是用调试符号重建,或插入日志记录输出,并获得更有用的崩溃记录。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐