6

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

  • What exact command are you using to run the program in the debugger? – Michael Petch Jun 21 '22 at 05:04
  • Why do you need to see the source lines to debug an assembly program? The debugger can already show you the assembly instructions with its disassembler. – xiver77 Jun 21 '22 at 07:08
  • Apparently recent gnu tools switched to a newer dwarf format that nasm can not yet produce. – Jester Jun 21 '22 at 10:20
  • @MichaelPetch, running with `b _start` then `run`. @xiver77, yes, gdb can show the disassembly as you execute each line but it's a little hard to follow the raw numbers in the disassembly since you lose the symbol names. Also, when you need to step through a few instructions to get to the one you care about, it's a lot faster to be able to see the whole source as you execute. – Joey Shepard Jun 21 '22 at 12:11
  • @Jester, thanks. So, maybe downgrade gdb and wait for NASM to catch up? – Joey Shepard Jun 21 '22 at 12:17
  • @JoeyShepard Are you sure GDB looses symbol names? AFAIK symbol names are different from debug symbols. At least GDB doesn't loose symbol names if an executable compiled from C without debugging symbols isn't stripped. – xiver77 Jun 21 '22 at 12:21
  • @xiver77, GDB still matches addresses to label names, but it loses all the constants and variable names resolved at assembly time. You need to see the source for those. – Joey Shepard Jun 21 '22 at 12:42

4 Answers4

5

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.

Andrew
  • 3,770
  • 15
  • 22
  • I thought it was simple, but how do you downgrade nasm on Ubuntu ? – Christian Singer Jan 09 '23 at 15:55
  • Turns out it was actually a longstanding NASM bug (fixed in 2.16.01: https://nasm.us/doc/nasmdocc.html), but cancelled out by a bug in GNU Binutils `ld` that was recently fixed. So downgrading NASM won't help, and you likely don't want to downgrade the system's `ld`. – Peter Cordes Feb 05 '23 at 06:06
3

I have the same situation 'Single stepping until exit from function main, which has no line number information.' I checked the gcc and gdb versions but needed to remember the nasm. I have this problem in version 2.15.05. So I upgrade the nasm to version 2.16.01, and it's okay.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
Ian
  • 31
  • 3
  • 1
    Yes, the release notes mention the relevant bugfix to DWARF debug info. https://nasm.us/doc/nasmdocc.html – Peter Cordes Jan 28 '23 at 03:03
  • Please don't edit fluff like "thanks a lot" back into your posts after other people clean it up. See [Should I remove 'fluff' (like greetings, signatures, "thanks", etc.) when editing questions?](https://meta.stackoverflow.com/q/260776) and [Why are fellow users removing thank-you's from my questions?](https://meta.stackoverflow.com/q/328379) / [Should 'Hi', 'thanks', taglines, and salutations be removed from posts?](https://meta.stackexchange.com/q/2950) re: it being standard practice on SO to edit out stuff like that. In future, please keep it technical and save everyone the trouble. – Peter Cordes Feb 05 '23 at 06:09
2

There was a longstanding NASM bug in debug-info generation, fixed in 2.16. From the release notes in the NASM docs:

  • Fix a code range generation bug in the DWARF debug format (incorrect information in the DW_AT_high_pc field) for the ELF output formats. This bug happened to cancel out with a bug in older versions of the GNU binutils linker, but breaks with other linkers and updated or other linkers that expect the spec to be followed.

Old answer: Debug the machine code, forget the source. Or use STABS

IIRC, GDB works fine with 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.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • 1
    GDB does not work with stabs either for me. Have you tried it with the most recent version of NASM and GDB? Maybe whatever led them to stop supporting the older version of dwarf led them to remove stabs support too. Thanks for the tip about `layout n.` That is a good temporary solution. In my case, I absolutely do need to see which variables and constants the lines are using and for that, I need the original source instead of the disassembly. – Joey Shepard Jun 21 '22 at 12:46
  • @JoeyShepard: No, I didn't try, sorry. Re: needing line numbers for variable definitions: I guess they're not unique enough names to just search on in your editor? Or that would be less convenient a workflow. Fair enough. – Peter Cordes Jun 21 '22 at 12:50
  • 1
    @JoeyShepard: Just tried `nasm -felf64 -g foo.asm` / `ld -o foo foo.o` / `gdb foo`, and yes I get source displayed in the `layout reg` source pane, and yes, `b sym` prints a filename and line number. I haven't updated my Arch Linux in a few months, so I'm using GDB 11.2 and NASM 2.15.05. (GNU Binutils version 2.36.1) – Peter Cordes Jun 21 '22 at 12:59
  • Semi-related re: bad debug info: [Setting breakpoints in GDB on a program build with YASM -g dwarf2 changes program behaviour and segfaults or SIGILL](https://stackoverflow.com/a/73453211) has details about a YASM bug, but NASM 2.15.05 doesn't work either. Same as Andrew reports in their answer. – Peter Cordes Aug 28 '22 at 00:37
2

As pointed by Andrew this is indeed a bug in nasm (https://bugzilla.nasm.us/show_bug.cgi?id=3392798). It will not be fixed by downgrading as the bug is pretty old from what I understand.

The bug is aparent right now because older version of GNU ld had an issue that complemented this one (making it imperceptible). AFAIK users of lld and gold were experiencing this issue long ago.

The nice part is that I've sent a really simple and small patch (and that I feel comfortable thinking is correct after reading through the ld-nasm interaction and why it wasn't discovered before).

If you are inclined to read the patch (maybe even leave helpful comments if you find an issue) it's here: https://github.com/netwide-assembler/nasm/pull/35

Also, if you use Ubuntu 22.04 I've built a patched .deb that should be relatively easy to install https://github.com/iglosiggio/nasm/releases/tag/nasm-2.15.05-2.

mega
  • 21
  • 3