I am trying to build a basic project for ARM with symbols and associated line numbers, so that I can easily debug the project from GDB Multiarch while it is running in QEMU.
I have two files, a C source file and some assembly. In this example, they are very simple:
cmain.c:
int add_numbers(int a, int b) {
return a + b;
}
int cmain() {
int a = 3;
int b = 4;
int c = add_numbers(a, b);
}
main.s:
.section .init
.global _start
_start:
.extern cmain
mov sp, #0x8000
bl cmain
Additionally, here's the linker file, kernel.ld:
SECTIONS {
.init 0x8000 : {
*(.init)
}
.text : {
*(.text)
}
.data : {
*(.data)
*(.bss)
*(.rodata*)
*(.COMMON)
}
/DISCARD/ : {
*(*)
}
}
I then build these projects with debugging symbols using the following shell script. In brief, it assembles and compiles the files into object files, then links them into an ELF and objcopies into an IMG.
rm -r build
mkdir -p build
arm-none-eabi-as -I . main.s -o build/main.o
arm-none-eabi-gcc -ffreestanding -fno-builtin -march=armv7-a -MD -MP -g -c cmain.c -o build/cmain.o
arm-none-eabi-ld build/main.o build/cmain.o -L/usr/lib/gcc/arm-none-eabi/6.3.1/ -lgcc --no-undefined -o build/output.elf -T kernel.ld
arm-none-eabi-objcopy build/output.elf -O binary build/kernel.img --keep-file-symbols
For GDB debugger stepping, I need the ELF to have line numbers for the C source. (Note that the actual project has many more C files.) The lines numbers are present in C object file, but not in the ELF.
$ arm-none-eabi-nm build/cmain.o --line-numbers
00000000 T add_numbers /home/aaron/Desktop/arm-mcve/cmain.c:1
00000030 T cmain /home/aaron/Desktop/arm-mcve/cmain.c:5
$ arm-none-eabi-nm build/output.elf --line-numbers
00008008 T add_numbers
00008038 T cmain
00008000 T _start
Why is there no line number information in the ELF, and how can I add it so that GDB can step through it?
Your linker script discards the sections with debugging information. Look at the default linker script arm-none-eabi-ld --verbose
for some ideas. You will at least need some of the DWARF 2 sections:
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
(Adding all of them should work.)