Qemu中翻譯的主要框架位於cpu-exec.c中的cpu_exec()函數。
For (;;) {
If (setjmp(env->jmp_env) == 0) {
// exception handling
For (;;) {
// longjmp if there is an exception has been requested
Tb_find_fast() // Look up translation block.
...
Tb_add_jump() // Chaining
...
Tcg_qemu_tb_exec() // Execute the translation block
}
}
}
外循環一開始設jump context為了將來中斷處理作准備,內循環中檢查是否有中斷,有的話跳到前面設置的jump context處,另外內循環中主要做翻譯和執行翻譯的code。tb_find_fast()用於找要執行的code是否已經被翻譯:
Tb_find_fast() // search the fast lookup table(env->tb_jmp_cache)
If not found
Tb_find_slow() // search the slow lookup table(physical page table – tb_phys_hash)
If not found
Tb_gen_code() // do translation
else
// add to fast lookup table
else
return
其中tb_gen_code開始翻譯:
Tb_gen_code()
// alloc translation block
Cpu_gen_code()
// add to slow lookup table
Cpu_gen_code()
Gen_intermediate_code() // phase 1
Gen_intermediate_code_internal()
Disas_insn()
Tcg_gen_code // phase 2
Tcg_gen_code_common()
翻譯分為兩個階段:
階段1:guest代碼到中間表示(稱為micro operation)。這個階段的實現代碼主要在target-ARCH這個目錄下,產生結果放在gen_opc_buf(TCG opcode)和gen_opparam_buf(TCG operand)中。
階段2:中間表示到host代碼。這個階段的實現代碼主要在tcg目錄下。產生結果放在gen_code_buf中。
翻譯完了該執行翻譯的代碼了:
Tcg_qemu_tb_exec()
Code_gen_prologue // generated by tcg_target_qemu_prologue() when initialization.
Code_gen_prologue
// prologue: callee saved registers, reserve stack space, etc.
// jump to translated code
// epilogue: restore register and stack, etc.
在Android的emulator中,Qemu為我們提供了一些有力的調試工具,如
1. Monitor,這個工具可以讓用戶在Qemu運行過程中與之交互並且加以控制。首先加啟動參數:
$ Emulator.exe –avd test –qemu -monitor telnet::1235,server,nowait
接著用telnet連上:
(telnet) o localhost 1235
然後就應該能看到Qemu shell提示符了。之後就可以運行monitor提供的命令了。
2. Log。啟動時加參數-qemu -d可以根據需要打出log:
Log items (comma separated):
out_asm show generated host assembly code for each compiled TB
in_asm show target assembly code for each compiled TB
op show micro ops for each compiled TB
op_opt show micro ops before eflags optimization and after liveness analysis
int show interrupts/exceptions in short format
exec show trace before each executed TB (lots of logs)
cpu show CPU state before block translation
pcall show protected mode far calls/returns/exceptions
cpu_reset show CPU state before CPU resets
比如加in_asm,out_asm就能把guest code和翻譯好的host code打印出來:
IN:
0xfffffff0: ljmp $0xf000,$0xe05b
OUT: [size=32]
0x06614020: mov $0xf000,%eax
0x06614025: movzwl %ax,%eax
0x06614028: mov %eax,0x50(%ebp)
0x0661402b: shl $0x4,%eax
0x0661402e: mov %eax,0x54(%ebp)
0x06614031: mov $0xe05b,%eax
0x06614036: mov %eax,0x20(%ebp)
0x06614039: xor %eax,%eax
0x0661403b: jmp 0x844548