提问人:Joey Shepard 提问时间:6/21/2022 更新时间:2/5/2023 访问量:1118
GDB 不会从 NASM 加载源行
GDB does not load source lines from NASM
问:
我正在使用 NASM 在 Ubuntu 上组装一个 x86-64 程序:
nasm -f elf64 -g -F dwarf -o foo.o foo.asm
ld -o foo foo.o
源:
section .text
global _start
_start:
mov rax, 60 ;SYS_exit
mov rdi, 0 ;EXIT_SUCCESS
syscall
使用 GDB 调试程序不会显示指令来自哪个文件或行号。例如,显示“0x401000处的断点 1”,而不是“0x400080处的断点 1:文件 foo.asm,第 4 行”,如本博客文章所示。切换到显示“无可用源”,而不是在源中找到当前指令的位置。 确实显示源,但在单步执行下一条指令时,它会切换回“无可用源”。break _start
layout regs
list
objdump -g foo
似乎表明所需的调试信息在那里:
foo: file format elf64-x86-64
...
The File Name Table (offset 0x1c):
Entry Dir Time Size Name
1 0 0 0 foo.asm
Line Number Statements:
[0x00000028] Extended opcode 2: set Address to 0x401000
[0x00000033] Special opcode 8: advance Address by 0 to 0x401000 and Line by 3 to 4
[0x00000034] Special opcode 76: advance Address by 5 to 0x401005 and Line by 1 to 5
[0x00000035] Special opcode 76: advance Address by 5 to 0x40100a and Line by 1 to 6
[0x00000036] Advance PC by 2 to 0x40100c
[0x00000038] Extended opcode 1: End of Sequence
Ubuntu 22.04、NASM 2.15.05、GDB 12.09
答:
debug-info 生成中存在一个长期存在的 NASM 错误,已在 2.16 中修复。从 NASM 文档中的发行说明中:
- 修复了 ELF 输出格式的 DWARF 调试格式(字段中的信息不正确)中的代码范围生成错误。这个错误碰巧被旧版本的 GNU binutils 链接器中的一个错误所抵消,但与其他链接器和更新的或其他期望遵循规范的链接器一起中断。
DW_AT_high_pc
老答案:调试机器码,忘源码。或使用 STABS
IIRC,GDB 可以很好地与 NASM 的默认 STABS 输出配合使用,所以让它使用它而不是 DWARF。Jester说,GNU工具使用一种更新的DWARF格式,NASM不知道如何制作。但它们仍然支持 DWARF 取代的 STABS 格式。STABS 对于将源行映射到地址的简单任务来说绰绰有余,这就是像 NASM 这样的简单源语言所需要的全部内容。
无需任何选项即可使用。nasm -g
-F
或者也省略 -g
:您仍然可以获得符号名称,除了基本的标签名称之外,我在手写的 asm 中从未对调试信息有太多用处。(当然还有节头,在可执行文件中也不需要,只需要程序头。如果您尝试在 FASM 直接创建的可执行文件上使用 GDB,就会发现这一点。
我总是在布局注册
后使用布局 n
,以切换到寄存器 + 反汇编。过去就是这样;我不确定当前的行为是 GDB 错误还是什么。(在以前的某个版本中,两者都是必需的,就像它认为配置设置与 UI 实际显示的内容不同步一样)。layout reg
layout next
prev
无论如何,我基本上从不希望 GDB 显示源代码,我希望它显示我正在运行的任何内容的规范反汇编,以防我编写一些与外观不同的组装内容。.asm
在 asm 源中使用有意义的标签名称将导致 GDB 显示执行或其他内容。尽管有很多条件分支不太好,因为每个分支目标看起来都像是 GDB 的完整标签。sieve.crossout
评论
layout n.
nasm -felf64 -g foo.asm
ld -o foo foo.o
gdb foo
layout reg
b sym
我设置了一个 Ubuntu 22.04 VM,发现我可以重现您在那里看到的问题,但是,在我的本地计算机上,我无法重现该问题。
我注意到在我的本地机器上我使用的是 nasm 2.14.02,而在 Ubuntu 机器上我使用的是 2.15.05。
如果我们检查两个可执行文件的输出,以下是我从工作可执行文件中看到的部分内容:objdump -g
Contents of the .debug_info section (loaded from foo):
Compilation Unit @ offset 0x0:
Length: 0x45 (32-bit)
Version: 3
Abbrev Offset: 0x0
Pointer Size: 8
<0><b>: Abbrev Number: 1 (DW_TAG_compile_unit)
<c> DW_AT_low_pc : 0x401000
<14> DW_AT_high_pc : 0x40100c
<1c> DW_AT_stmt_list : 0x0
<20> DW_AT_name : foo.asm
<28> DW_AT_producer : NASM 2.14.02
<35> DW_AT_language : 32769 (MIPS assembler)
<1><37>: Abbrev Number: 2 (DW_TAG_subprogram)
<38> DW_AT_low_pc : 0x401000
<40> DW_AT_frame_base : 0x0 (location list)
<1><44>: Abbrev Number: 0
这是损坏的可执行文件中的相同部分:
Contents of the .debug_info section (loaded from foo):
Compilation Unit @ offset 0x0:
Length: 0x45 (32-bit)
Version: 3
Abbrev Offset: 0x0
Pointer Size: 8
<0><b>: Abbrev Number: 1 (DW_TAG_compile_unit)
<c> DW_AT_low_pc : 0x401000
<14> DW_AT_high_pc : 0x401000
<1c> DW_AT_stmt_list : 0x0
<20> DW_AT_name : foo.asm
<28> DW_AT_producer : NASM 2.15.05
<35> DW_AT_language : 32769 (MIPS assembler)
<1><37>: Abbrev Number: 2 (DW_TAG_subprogram)
<38> DW_AT_low_pc : 0x401000
<40> DW_AT_frame_base : 0x0 (location list)
<1><44>: Abbrev Number: 0
关键区别在于 ,这似乎与 2.15.05 nasm 有关。我手动进入并编辑了这个值,突然间,我可以很好地调试以前损坏的可执行文件。DW_AT_high_pc
这似乎是 nasm 2.15.05 中的回归,您应该考虑降级 nasm(我认为 2.15.05 是当前的最新版本),或者可能提交 nasm 错误。
评论
ld
ld
正如安德鲁所指出的,这确实是nasm(https://bugzilla.nasm.us/show_bug.cgi?id=3392798)中的一个错误。它不会通过降级来修复,因为据我所知,这个错误已经很老了。
该错误现在是父错误,因为旧版本的 GNU ld 有一个补充这个问题的问题(使其难以察觉)。LLD 和 gold 的 AFAIK 用户很久以前就遇到了这个问题。
好的部分是我发送了一个非常简单的小补丁(在阅读了 ld-nasm 交互以及为什么以前没有发现它之后,我感到很舒服,认为是正确的)。
如果您倾向于阅读补丁(如果您发现问题,甚至可以留下有用的评论),它就在这里:https://github.com/netwide-assembler/nasm/pull/35
另外,如果您使用 Ubuntu 22.04,我已经构建了一个修补.deb它应该相对容易安装 https://github.com/iglosiggio/nasm/releases/tag/nasm-2.15.05-2。
我有同样的情况“单步执行直到退出函数 main,它没有行号信息。我检查了 gcc 和 gdb 版本,但需要记住 nasm。 我在 2.15.05 版中遇到了这个问题。所以我将 nasm 升级到 2.16.01 版本,没关系。
评论
b _start
run