QEMU

From MILEDROPEDIA
Jump to: navigation, search

Contents

Intro

Sometimes, we need debug program, because static analisys can't cover all our hopes. Sometimes we need run program to see value of register or variable. For usual program it is so simple - just start any degugger, load program, run and debug, debug... But, not for bootloaders, even more for embedded platform. But this is also possible. We need to know that we are luckies - qemu (now - the best system emulator) support gdbserver mode, which allow run everything you want in qemu, stop, and then connect from any other place with gdb or it's frontend to the running qemu, as for real hardware. But, if PC emulation support BIOS loading/debugging, mainstream QEMU doesnt support such thing for ARM. Here you can find patched qemu, for support booting and debugging bootrom, and bootloaders. Also here you can find examples of its use.

Install

Download sources from Gitorious: [1]

Build them :

./configure --target-list=arm-softmmu
make
sudo make install

Use case

You can use loading your custom bootrom from file by using parameters: -bios and -L dir. They let choose bios (bootrom) name and path Because we need ARM, we need use name "bootrom.bin" as bios name, and it must be valid 32K file

Also, if something goes wrong, for example:

qemu: fatal: Trying to execute code outside RAM or ROM at 0x00014748
 
R00=0001b860 R01=4020fcb0 R02=0000002c R03=00014748
R04=00014000 R05=00000000 R06=0000030f R07=4001b82f
R08=00000000 R09=00000000 R10=4001b840 R11=4001b860
R12=00000000 R13=4020fcac R14=40014724 R15=00014748
PSR=400001d3 -Z-- A svc32

you can enable tracing in qemu by enabling option "-d cpu,exec,in_asm" - it create trace log in /tmp/qemu.log, for example:

----------------
IN: 
0x40014708:  ea000000      b    0x40014710
 
R00=00c51878 R01=00000001 R02=00000000 R03=00000000
R04=00014000 R05=00000000 R06=0000030f R07=00000000
R08=00000000 R09=00000000 R10=00000000 R11=00000000
R12=00000000 R13=4020fcac R14=40014904 R15=40014710
PSR=600001d3 -ZC- A svc32
----------------
IN: 
0x40014710:  e28f0028      add  r0, pc, #40     ; 0x28
0x40014714:  e8900c00      ldm  r0, {sl, fp}
0x40014718:  e08aa000      add  sl, sl, r0
0x4001471c:  e08bb000      add  fp, fp, r0
0x40014720:  e24a7001      sub  r7, sl, #1      ; 0x1
0x40014724:  e15a000b      cmp  sl, fp
0x40014728:  0a000164      beq  0x40014cc0
 
R00=40014740 R01=00000001 R02=00000000 R03=00000000
R04=00014000 R05=00000000 R06=0000030f R07=4001b82f
R08=00000000 R09=00000000 R10=4001b830 R11=4001b860
R12=00000000 R13=4020fcac R14=40014904 R15=4001472c
PSR=800001d3 N--- A svc32
----------------

Such log can help you find the place of error (or in qemu or in running image)

so, for example you can run qemu:

qemu-system-arm -M milestone -m 256 -L . -bios bootrom.bin -mtdblock mbmloader-1.raw -d in_asm,cpu,exec -nographic


Here you can find examples of trace logs:

File:Bootrom-qemu.log.gz

File:Bootrom-ida.log.gz

Debugging

Also it is possible use qemu for debugging purposes: you need only two options for that: -s and -S

  • -s option run qemu in gdbserver mode at localhost port 1234
  • -S stop execution when debugging start

for example:

qemu-system-arm -M milestone -m 256 -L . -bios bootrom.bin -mtdblock mbmloader-1.raw -d in_asm,cpu,exec -s -S -nographic

And now we can connect with gdb or any its frontend to localhost:1234 and start debuging process:

(gdb) target remote localhost:1234
(gdb) set architecture arm

Useful commands:

  • "x/i $pc" - enable printing each executed instruction
  • "si" - step one machine instruction (enter inside each function)
  • "ni" - step one machine instruction (without entering functions)
  • "c" - continue execution
  • "bt" - backtrace - show stack
  • "i p" - show current state of the program
  • "i r" - show all registers
  • "p $eax" - show content of eax register (can be used with any register/variable)

My ~/.gdbinit file:

python
import sys
sys.path.insert(0, '/home/xvilka/gdb/python')
from libstdcxx.v6.printers import register_libstdcxx_printers
register_libstdcxx_printers (None)
end
set history save on
set disassembly-flavor intel
display/4i $pc

Here you can see example of my session:

(gdb) show architecture
The target architecture is set automatically (currently i386)
(gdb) target remote localhost:1234
Remote debugging using localhost:1234
warning: Architecture rejected target-supplied description
0x00000000 in ?? ()
1: x/4i $pc
=> 0x0:	add    BYTE PTR [eax],al
   0x2:	add    BYTE PTR [eax],al
   0x4:	add    BYTE PTR [eax],al
   0x6:	add    BYTE PTR [eax],al
(gdb) show architecture
The target architecture is set automatically (currently i386)
(gdb) set architecture arm
The target architecture is assumed to be arm
(gdb) i prog
Debugging a target over a serial line.
Program stopped at 0x0.
It stopped with signal SIGTRAP, Trace/breakpoint trap.
(gdb) si
Prologue scan stopped at 0xfffffff8
Prologue scan stopped at 0xfffffff8
0x400148c0 in ?? ()
1: x/4i $pc
=> 0x400148c0:	ldr	r0, [pc, #148]	; 0x4001495c
   0x400148c4:	ldr	r0, [r0]
   0x400148c8:	lsr	r0, r0, #8
   0x400148cc:	and	r0, r0, #7
(gdb) si
Prologue scan stopped at 0xfffffff8
0x400148c4 in ?? ()
1: x/4i $pc
=> 0x400148c4:	ldr	r0, [r0]
   0x400148c8:	lsr	r0, r0, #8
   0x400148cc:	and	r0, r0, #7
   0x400148d0:	cmp	r0, #3
(gdb) i r
r0             0x480022f0	1207968496
r1             0x0	0
r2             0x0	0
r3             0x0	0
r4             0x0	0
r5             0x0	0
r6             0x0	0
r7             0x0	0
r8             0x0	0
r9             0x0	0
r10            0x0	0
r11            0x0	0
r12            0x0	0
sp             0x0	0x0
lr             0x0	0
pc             0x400148c4	0x400148c4
cpsr           0x400001d3	1073742291
(gdb) si
Prologue scan stopped at 0xfffffff8
0x400148c8 in ?? ()
1: x/4i $pc
=> 0x400148c8:	lsr	r0, r0, #8
   0x400148cc:	and	r0, r0, #7
   0x400148d0:	cmp	r0, #3
   0x400148d4:	bne	0x400148f0
(gdb) si
Prologue scan stopped at 0xfffffff8
0x400148cc in ?? ()
1: x/4i $pc
=> 0x400148cc:	and	r0, r0, #7
   0x400148d0:	cmp	r0, #3
   0x400148d4:	bne	0x400148f0
   0x400148d8:	ldr	r0, [pc, #124]	; 0x4001495c
(gdb) si
Prologue scan stopped at 0xfffffff8
0x400148d0 in ?? ()
1: x/4i $pc
=> 0x400148d0:	cmp	r0, #3
   0x400148d4:	bne	0x400148f0
   0x400148d8:	ldr	r0, [pc, #124]	; 0x4001495c
   0x400148dc:	ldr	r0, [r0]
(gdb) si
Prologue scan stopped at 0xfffffff8
0x400148d4 in ?? ()
1: x/4i $pc
=> 0x400148d4:	bne	0x400148f0
   0x400148d8:	ldr	r0, [pc, #124]	; 0x4001495c
   0x400148dc:	ldr	r0, [r0]
   0x400148e0:	mov	r6, r0
(gdb) si
Prologue scan stopped at 0xfffffff8
0x400148d8 in ?? ()
1: x/4i $pc
=> 0x400148d8:	ldr	r0, [pc, #124]	; 0x4001495c
   0x400148dc:	ldr	r0, [r0]
   0x400148e0:	mov	r6, r0
   0x400148e4:	and	r0, r0, #31
(gdb) i r
r0             0x3	3
r1             0x0	0
r2             0x0	0
r3             0x0	0
r4             0x0	0
r5             0x0	0
r6             0x0	0
r7             0x0	0
r8             0x0	0
r9             0x0	0
r10            0x0	0
r11            0x0	0
r12            0x0	0
sp             0x0	0x0
lr             0x0	0
pc             0x400148d8	0x400148d8
cpsr           0x600001d3	1610613203
(gdb) 

IDA Pro

First, start IDA Pro, open idb for your file, go to menu Debugging -> Debugging Options -> edit all that you want For start debugging just open Debugging -> Attach to process -> Remote GDB debugger -> localhost:1234 (if you use "-s" option for qemu) run!

Here you can see example of debugging bootrom in the IDA Pro disassembler: Ida debug 0.png Usually i'm also enabling tracing log / instruction tracing - it is very useful: Ida debug 1.png

Personal tools
Namespaces
Variants
Actions
Navigation
see also
Toolbox