rust-lang / rust-lang/rust

#[naked] function emits no DWARF info

Open
#152,456 3 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

A-debuginfo A-naked C-bug needs-triage T-compiler
Dominant language
Rust
Stars
119k
Forks
16.2k
PR merge metrics
PR metrics pending

Description

I looks as if #[naked] functions are not being associated with the usual function debug information (e.g, a DW_TAG_subprogram entry in .debug_info). This results in debuggers and symbolizers being unable to resolve source locations for addresses within naked functions. This seems broadly relevant to embedded Rust (the context in which this came up for me).

My understanding is that the "naked" contract concerns codegen (i.e., no prologue/epilogue), but not debug metadata. For contrast, Clang and GCC both emit full debug info for naked functions in C. I've included a minimal reproducer of the debug info not being present with rustc, as well as reproducers of it being present with Clang and GCC.

Rust reproducer:

// naked_debug.rs
#[no_mangle]
#[unsafe(naked)]
pub extern "C" fn naked_func() {
    std::arch::naked_asm!("ret")
}

#[no_mangle]
pub fn normal_func() {}

fn main() {
    println!("{:#x?}", normal_func as *const ());
    println!("{:#x?}", naked_func as *const ());
}

We see normal_func in the same translation unit gets a DW_TAG_subprogram with name, file, and line, but not with naked_func:

$ rustc -g --target x86_64-unknown-linux-gnu --emit obj naked_debug.rs -o naked_debug.o
$ llvm-dwarfdump --name=normal_func naked_debug.o
naked_debug.o:  file format elf64-x86-64

0x0000039f: DW_TAG_subprogram
              DW_AT_low_pc      (0x0000000000000000)
              DW_AT_high_pc     (0x0000000000000001)
              DW_AT_frame_base  (DW_OP_reg7 RSP)
              DW_AT_name        ("normal_func")
              DW_AT_decl_file   ("/home/joshuaseaton/temp/naked_debug.rs")
              DW_AT_decl_line   (10)
              DW_AT_external    (true)


$ llvm-dwarfdump --name=naked_func naked_debug.o
naked_debug.o:  file format elf64-x86-64

Clang and GCC reproducer:

// naked_debug.c

__attribute__((naked)) void naked_func(void) { __asm__ volatile("ret"); }

void normal_func(void) {}
$ clang -g --target=x86_64-unknown-linux-gnu -c naked_debug.c -o naked_debug.clang.o
$ llvm-dwarfdump --name=normal_func naked_debug.clang.o
naked_debug.c.o:        file format elf64-x86-64

0x0000002e: DW_TAG_subprogram
              DW_AT_low_pc      (0x0000000000000010)
              DW_AT_high_pc     (0x0000000000000016)
              DW_AT_frame_base  (DW_OP_reg6 RBP)
              DW_AT_name        ("normal_func")
              DW_AT_decl_file   ("/home/joshuaseaton/temp/naked_debug.c")
              DW_AT_decl_line   (3)
              DW_AT_prototyped  (true)
              DW_AT_external    (true)
$ llvm-dwarfdump --name=naked_func naked_debug.clang.o
naked_debug.c.o:        file format elf64-x86-64

0x00000023: DW_TAG_subprogram
              DW_AT_low_pc      (0x0000000000000000)
              DW_AT_high_pc     (0x0000000000000001)
              DW_AT_frame_base  (DW_OP_reg7 RSP)
              DW_AT_name        ("naked_func")
              DW_AT_decl_file   ("/home/joshuaseaton/temp/naked_debug.c")
              DW_AT_decl_line   (1)
              DW_AT_prototyped  (true)
              DW_AT_external    (true)

$ x86_64-linux-gnu-gcc -g -c naked_debug.c -o naked_debug.gcc.o
$ llvm-dwarfdump --name=normal_func naked_debug.gcc.o
naked_debug.gcc.o:      file format elf64-x86-64

0x00000033: DW_TAG_subprogram
              DW_AT_external    (true)
              DW_AT_name        ("normal_func")
              DW_AT_decl_file   ("/home/joshuaseaton/temp/naked_debug.c")
              DW_AT_decl_line   (3)
              DW_AT_decl_column (6)
              DW_AT_prototyped  (true)
              DW_AT_low_pc      (0x0000000000000004)
              DW_AT_high_pc     (0x000000000000000b)
              DW_AT_frame_base  (DW_OP_call_frame_cfa)
              DW_AT_call_all_calls      (true)
$ llvm-dwarfdump --name=naked_func naked_debug.gcc.o
naked_debug.gcc.o:      file format elf64-x86-64

0x0000004c: DW_TAG_subprogram
              DW_AT_external    (true)
              DW_AT_name        ("naked_func")
              DW_AT_decl_file   ("/home/joshuaseaton/temp/naked_debug.c")
              DW_AT_decl_line   (1)
              DW_AT_decl_column (29)
              DW_AT_prototyped  (true)
              DW_AT_low_pc      (0x0000000000000000)
              DW_AT_high_pc     (0x0000000000000004)
              DW_AT_frame_base  (DW_OP_call_frame_cfa)
              DW_AT_call_all_calls      (true)
Meta
$ rustc --version --verbose
rustc 1.93.0 (254b59607 2026-01-19)
binary: rustc
commit-hash: 254b59607d4417e9dffbc307138ae5c86280fe4c
commit-date: 2026-01-19
host: x86_64-unknown-linux-gnu
release: 1.93.0
LLVM version: 21.1.8

I have also reproduced this with the 01.01.2026 nightly aarch64-apple-darwin toolchain targeting riscv32 and riscv64.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the Rust reproducer in the issue and inspect the compiler's debug-info emission for #[naked] functions, comparing rustc output with the shown Clang and GCC DWARF dumps. Use rustc -g --emit obj and llvm-dwarfdump to verify that naked_func receives a DW_TAG_subprogram with its name, file, line, and address range.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.