This post, is in continuation with “Using GDB to debug functions defined in another file in C” from where will be using add.c and helloworld.c as source code and “Debugging ARM binary on Ubuntu Host using qemu ARM and GDB” from where we will be using the debugging environment for ARM.
so, lets assume we have followed both the above posts and we have helloworld as ARM ELF binary, then start gdb
$ arm-linux-gnueabihf-gcc -g -c -o helloworld_src/add.o helloworld_src/add.c
$ arm-linux-gnueabihf-gcc -g -o helloworld helloworld_src/helloworld.c helloworld_src/add.o -static
Run the qemu ARM in one terminal as,
$ qemu-arm -L gcc-arm-none-eabi-10-2020-q4-major/lib -g 8090 ./helloworld
On second terminal start GDB
$ arm-none-eabi-gdb
(gdb) target remote:8090
Set Breakpoint using Line Number
You can set breakpoints using line number of the source code in that file, for that you must compile your binary with debugging symbols enabled, which we did using “-g” with gcc.
Check the line numbers of the source file using “li” gdb command as,
gdb) li
warning: Source file is more recent than executable.
1 #include <stdio.h>
2
3 extern int add_two_numbers(int, int);
4
5 int main(int argc, char **argv) {
6 int num = 0;
7 printf("helloworld\n");
8 num = add_two_numbers(3, 2);
9 printf("addition: %d\n", 3+2);
10 return 0;
(gdb)
11 }
(gdb)
Now, lets say you want to set breakpoint at line number 8, the type “break 8” or simply “br 8” to set breakpoint using line number i.e. “break line_number”
(gdb) br 8
Breakpoint 1 at 0x1043c: file helloworld_src/helloworld.c, line 9.
(gdb) c
Continuing.
Breakpoint 1, main (argc=1, argv=0xfffef184) at helloworld_src/helloworld.c:9
9 printf("addition: %d\n", 3+2);
As you can see, it set the breakpoint at the next valid statement on line number 9 and our program stopped at that line number after we pressed c i.e. continue.
Set Breakpoint at main
(gdb) break main
Breakpoint 1 at 0x1042e: file helloworld_src/helloworld.c, line 6.
(gdb) c
Continuing.
Breakpoint 1, main (argc=1, argv=0xfffef184) at helloworld_src/helloworld.c:6
warning: Source file is more recent than executable.
6 int num = 0;
Setting Breakpoint using Memory Address
First, we need to check the memory address using objdump as,
$ arm-linux-gnueabihf-objdump -D helloworld > helloworld_objdump.txt
then, we can check the address of main and code inside by reading from helloworld_object.txt as
00010424 <main>:
10424: b580 push {r7, lr}
10426: b084 sub sp, #16
10428: af00 add r7, sp, #0
1042a: 6078 str r0, [r7, #4]
1042c: 6039 str r1, [r7, #0]
1042e: 2300 movs r3, #0
10430: 60fb str r3, [r7, #12]
10432: 4b08 ldr r3, [pc, #32] ; (10454 <main+0x30>)
10434: 447b add r3, pc
10436: 4618 mov r0, r3
10438: f008 fc90 bl 18d5c <_IO_puts>
1043c: 2105 movs r1, #5
1043e: 4b06 ldr r3, [pc, #24] ; (10458 <main+0x34>)
10440: 447b add r3, pc
10442: 4618 mov r0, r3
10444: f004 faac bl 149a0 <_IO_printf>
10448: 2300 movs r3, #0
1044a: 4618 mov r0, r3
1044c: 3710 adds r7, #16
1044e: 46bd mov sp, r7
10450: bd80 pop {r7, pc}
10452: bf00 nop
10454: 00039950 andeq r9, r3, r0, asr r9
10458: 00039950 andeq r9, r3, r0, asr r9
As we can see above, we have a code where its printing using printf, and address is, 0x00043c , so we can set the breakpoint at this address using “star zero x” and then address as,
(gdb) br *0x0001043c
Breakpoint 1 at 0x1043c: file helloworld_src/helloworld.c, line 9.
Now, if we do continue, we can see our program stopped just before printf,
(gdb) c
Continuing.
Breakpoint 1, main (argc=1, argv=0xfffef184) at helloworld_src/helloworld.c:9
warning: Source file is more recent than executable.
9 printf("addition: %d\n", 3+2);