Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to single step ARM assembly in GDB on QEMU?

I'm trying to learn about ARM assembler programming using the GNU assembler. I've setup my PC with QEmu and have a Debian ARM-HF chroot environment.

If I assemble and link my test program:

.text
.global _start
_start:
        mov     r0, #6
        bx      lr

with:

as test.s -o test.o
ld test.o -o test

Then load the file into gdb and set a breakpoint on _start:

root@Latitude-E6420:/root# gdb test
GNU gdb (GDB) 7.6.1 (Debian 7.6.1-1)
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later 
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "arm-linux-gnueabihf".
For bug reporting instructions, please see:
...
Reading symbols from /root/test...(no debugging symbols found)...done.
(gdb) break _start
Breakpoint 1 at 0x8054
(gdb)

How do I single step the code, display the assembler source code and monitor the registers? I tried some basic commands and they did not work:

(gdb) break _start
Breakpoint 1 at 0x8054
(gdb) info regi
The program has no registers now.
(gdb) stepi
The program is not being run.
(gdb) disas
No frame selected.
(gdb) r
Starting program: /root/test 
qemu: Unsupported syscall: 26
qemu: uncaught target signal 11 (Segmentation fault) - core dumped
qemu: Unsupported syscall: 26
During startup program terminated with signal SIGSEGV, Segmentation fault.
(gdb) 
like image 488
fred basset Avatar asked Dec 15 '13 01:12

fred basset


People also ask

How do I use GDB with QEMU?

Now you will be dropped to a Qemu prompt, much like the GDB prompt: At the prompt, you should type in gdbserver. You should be seeing the output as: What it says is that GDB is listening on that port of your system. Now you can launch a new terminal and connect to this port. Load the main.o with gdb so that it can read the debugging symbols:

Is it possible to run GDB on an ARM processor?

Unfortunately, unless you have an ARM machine at hand, it will be difficult to execute it: the easiest way to overcome this is to use qemu. To understand what is really going on in the program, we’ll connect gdb to qemu, that will serve as a gdb server.

How do I debug guest code in QEMU?

This allows you to debug guest code in the same way that you might with a low-level debug facility like JTAG on real hardware. You can stop and start the virtual machine, examine state like registers and memory, and set breakpoints and watchpoints. In order to use gdb, launch QEMU with the -s and -S options.

How do I debug a program in gdb?

##Crash course on GDB The TUI provided by GDB is good enough to debug simple (and complex) programs: press Ctrl+x and then A to active it: above your usual GDB command prompt, you will see the source being debugged. Enter this command to have a good view of the registers.


2 Answers

Your problem here is that you're trying to run an ARM gdb under QEMU's user-mode emulation. QEMU doesn't support the ptrace syscall (that's what syscall number 26 is), so this is never going to work.

What you need to do is run your test binary under QEMU with the QEMU options to enable QEMU's own builtin gdb stub which will listen on a TCP port. Then you can run a gdb compiled to run on your host system but with support for ARM targets, and tell that to connect to the TCP port.

(Emulating ptrace within QEMU is technically very tricky, and it would not provide much extra functionality that you can't already achieve via the QEMU builtin gdbstub. It's very unlikely it'll ever be implemented.)

like image 138
Peter Maydell Avatar answered Sep 20 '22 10:09

Peter Maydell


Minimal working QEMU user mode example

I was missing the -fno-pie -no-pie options:

sudo apt-get install gdb-multiarch gcc-arm-linux-gnueabihf qemu-user
printf '
#include <stdio.h>
#include <stdlib.h>

int main() {
    puts("hello world");
    return EXIT_SUCCESS;
}
' >  hello_world.c
arm-linux-gnueabihf-gcc -fno-pie -ggdb3 -no-pie -o hello_world hello_world.c
qemu-arm -L /usr/arm-linux-gnueabihf -g 1234 ./hello_world

On another terminal:

gdb-multiarch -q --nh \
  -ex 'set architecture arm' \
  -ex 'set sysroot /usr/arm-linux-gnueabihf' \
  -ex 'file hello_world' \
  -ex 'target remote localhost:1234' \
  -ex 'break main' \
  -ex continue \
  -ex 'layout split'
;

This leaves us at main, in a split code / disassembly view due to layout split. You will also interested in:

layout regs

which shows the registers.

At the end of the day however, GDB Dashboard is more flexible and reliable: gdb split view with code

-fno-pie -no-pie is required because the packaged Ubuntu GCC uses -fpie -pie by default, and those fail due to a QEMU bug: How to GDB step debug a dynamically linked executable in QEMU user mode?

There was no gdbserver --multi-like functionality for the QEMU GDB stub on QEMU 2.11: How to restart QEMU user mode programs from the GDB stub as in gdbserver --multi?

For those learning ARM assembly, I am starting some runnable examples with assertions and using the C standard library for IO at: https://github.com/cirosantilli/arm-assembly-cheat

Tested on Ubuntu 18.04, gdb-multiarch 8.1, gcc-arm-linux-gnueabihf 7.3.0, qemu-user 2.11.

Freestanding QEMU user mode example

This analogous procedure also works on an ARM freestanding (no standard library) example:

printf '
.data
    msg:
        .ascii "hello world\\n"
    len = . - msg
.text
.global _start
_start:
    /* write syscall */
    mov r0, #1     /* stdout */
    ldr r1, =msg   /* buffer */
    ldr r2, =len   /* len */
    mov r7, #4     /* Syscall ID. */
    swi #0

    /* exit syscall */
    mov r0, #0 /* Status. */
    mov r7, #1 /* Syscall ID. */
    swi #0
' >  hello_world.S
arm-linux-gnueabihf-gcc -ggdb3 -nostdlib -o hello_world -static hello_world.S
qemu-arm -g 1234 ./hello_world

On another terminal:

gdb-multiarch -q --nh \
  -ex 'set architecture arm' \
  -ex 'file hello_world' \
  -ex 'target remote localhost:1234' \
  -ex 'layout split' \
;

We are now left at the first instruction of the program.

QEMU full system examples

  • Linux kernel: How to debug the Linux kernel with GDB and QEMU?
  • Bare metal: https://github.com/cirosantilli/newlib-examples/tree/f70f8a33f8b727422bd6f0b2975c4455d0b33efa#gdb