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
CodePudding user response:
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.
CodePudding user response:
IIRC, GDB works fine NASM's default STABS output, so let it use that instead of DWARF. Jester says GNU tools use a newer DWARF format that NASM doesn't know how to make. But they still support the STABS format that DWARF replaced. STABS is more than fine for the simple task for mapping source lines to addresses, which is all that's needed for a simple source language like NASM.
Just use nasm -g
without a -F
option.
Or leave out -g
as well, you still get symbol names, and I've never had much use for debug info in hand-written asm beyond basic label names. (And of course section headers, which are also not needed in an executable, just the program headers. As you'll find out if you try to use GDB on an executable created directly by FASM.)
I always use layout n
after layout reg
, to switch to registers disassembly. That used to be what layout reg
was; I'm not sure if the current behaviour is a GDB bug or what. (In some previous version, both layout next
/ prev
were required, like it thought the config setting was out of sync with what the UI was actually displaying).
Anyway, I basically never want GDB displaying the .asm
source, I want it to show canonical disassembly of whatever I'm running, in case I wrote something that assembled differently from how it looks.
Using meaningful label names in your asm source will lead to GDB showing execution in sieve.crossout
or whatever. Although it's less nice with lots of conditional branching, since every branch target looks like a full label for GDB.