I'm assembling an x86-64 program on Ubuntu with NASM:
nasm -f elf64 -g -F dwarf -o foo.o foo.asm
ld -o foo foo.o
Source:
section .text
global _start
_start:
mov rax, 60 ;SYS_exit
mov rdi, 0 ;EXIT_SUCCESS
syscall
Debugging the program with GDB does not show what file or line number an instruction comes from. For example, break _start
shows "Breakpoint 1 at 0x401000" rather than "Breakpoint 1 at 0x400080: file foo.asm, line 4." as shown in this blog post. Switching to layout regs
shows "No Source Available" rather than where in the source the current instruction is found. list
does show the source, but it switches back to "No Source Available" upon stepping to the next instruction.
objdump -g foo
seems to show that the required debug information is there:
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
I setup an Ubuntu 22.04 VM and found that I could reproduce the issue that you are seeing there, however, on my local machine, I could not reproduce the problem.
I noticed that on my local machine I was using nasm 2.14.02, while on the Ubuntu machine I was using 2.15.05.
If we check the objdump -g
output on the two executables, here's part of what I see from the working executable:
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
And here's the same part from the broken executable:
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
The critical difference is the DW_AT_high_pc
, this appears to be wrong with the 2.15.05 nasm. I manually went in and edited this value, and suddenly, I can debug the previously broken executable just fine.
This appears to be a regression in 2.15.05 of nasm, you should consider downgrading nasm (I think 2.15.05 is the current latest release), or maybe file a nasm bug.