我在QEMU源文件编译选项中添加了-fPCI,在最后的链接命令中添加了-shared,这样QEMU就变成了一个可以动态加载的共享库。从那时起,我开始尝试了解 QEMU。我使用 dlopen 动态加载 qemu 并使用 dlsym 搜索 qemu 中的函数。这是我的代码:
#include<iostream>
#include<dlfcn.h>
#include<stdint.h>
using namespace std;
int main(int argc,char* argv[],char* envp[])
{
void* handle = dlopen("/home/jack/qemu/qemu-5.0.0/arm-softmmu/libqemu-system-arm.so",RTLD_NOW);
if(handle == nullptr)
{
printf("%s\n",dlerror());
return 0;
}
void (* qemu_init )(int,char**,char**);
void (* qemu_main_loop )(void);
void (* qemu_cleanup )(void);
bool (* main_loop_should_exit )(void);
void (* main_loop_wait )(int);
int64_t (* cpu_get_icount )(void);
int64_t (* cpu_get_icount_raw )(void);
int64_t (* cpu_icount_to_ns )(int64_t);
int64_t (* cpu_get_clock )(void);
int64_t (* cpu_get_ticks )(void);
#define GET_SYMBOL_AND_CHECK(X) *((void**)(&X)) = dlsym(handle,#X);if(nullptr == X){printf("lost symbol: "#X"\n");return 0;}
GET_SYMBOL_AND_CHECK(qemu_init);
GET_SYMBOL_AND_CHECK(qemu_main_loop);
GET_SYMBOL_AND_CHECK(qemu_cleanup);
GET_SYMBOL_AND_CHECK(main_loop_should_exit);
GET_SYMBOL_AND_CHECK(main_loop_wait);
GET_SYMBOL_AND_CHECK(cpu_get_icount);
GET_SYMBOL_AND_CHECK(cpu_get_icount_raw);
GET_SYMBOL_AND_CHECK(cpu_icount_to_ns);
GET_SYMBOL_AND_CHECK(cpu_get_clock);
GET_SYMBOL_AND_CHECK(cpu_get_ticks);
#undef GET_SYMBOL_AND_CHECK
char* _argv[]=
{
"qemu-system-arm",
"-M",
"vexpress-a9",
"-nographic",
"-kernel",
"/home/jack/temp/u-boot-2015.01/u-boot",
"-icount",
"1",
"-singlestep",
"-S",
"-s",
};
int _argc=sizeof(_argv) / sizeof(_argv[0]);
qemu_init(_argc,_argv,envp);
while(!main_loop_should_exit())
{
main_loop_wait(false);
//my test code:
int64_t icount_raw = cpu_get_icount_raw();
int64_t icount = cpu_get_icount();
int64_t ticks = cpu_get_ticks();
int64_t clock = cpu_get_clock();
printf("----------icount_raw: %jd\n",icount_raw);
printf("----------icount: %jd\n",icount);
printf("----------ticks: %jd\n",ticks);
printf("----------clock: %jd\n",clock);
}
qemu_cleanup();
dlclose(handle);
return 0;
}
程序的输出如下:
----------icount_raw: 0
----------icount: 0
----------ticks: 0
----------clock: 27595
----------icount_raw: 0
----------icount: 0
----------ticks: 0
----------clock: 47394
U-Boot 2015.01 (May 25 2020 - 14:42:11)
DRAM: 128 MiB
WARNING: Caches not enabled
Flash: 128 MiB
MMC: MMC: 0
*** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
Net: smc911x-0
Warning: smc911x-0 using MAC address from net device
Warning: Your board does not use generic board. Please read
doc/README.generic-board and take action. Boards not
upgraded by the late 2014 may break or be removed.
Hit any key to stop autoboot: 2 ----------icount_raw: 60040125
----------icount: 120271139
----------ticks: 120271139
----------clock: 1001128004
----------icount_raw: 119738560
----------icount: 239668009
----------ticks: 239668009
----------clock: 2002239949
----------icount_raw: 180295711
----------icount: 360782311
----------ticks: 360782311
----------clock: 3003347066
----------icount_raw: 240405702
----------icount: 481002293
----------ticks: 481002293
----------clock: 4004446427
----------icount_raw: 300858002
----------icount: 601906893
----------ticks: 601906893
----------clock: 5005552419
----------icount_raw: 361297422
----------icount: 722785733
----------ticks: 722785733
----------clock: 6006625721
----------icount_raw: 420679210
----------icount: 841549309
----------ticks: 841549309
----------clock: 7007717838
----------icount_raw: 424900860
----------icount: 849992609
----------ticks: 849992609
----------clock: 7082080834
----------icount_raw: 424900883
----------icount: 849992655
----------ticks: 849992655
----------clock: 7082105752
----------icount_raw: 424900906
----------icount: 849992701
----------ticks: 849992701
----------clock: 7082120318
QEMU: Terminated
我为 QEMU 的主循环建模并编写了这个 while 循环。我每次循环打印获取的数据,发现icount_raw可以表示CPU当前执行的指令数。关于其他数据,我仍然感到困惑。本程序运行时,uboot程序可以正常运行。我发现屏幕上打印数据的频率大约是每秒一次。每次 icount_raw 增加很多。当我使用gdb远程控制程序运行时,使用“si”命令时,icount_raw每次递增1,这就是我想要实现的:每次QEMU只执行一条指令,就可以返回主循环. 我想知道如何修改QEMU的代码,让QEMU每次执行一条指令时,都能返回到主循环,而不是使用gdb的“si”命令。以后想知道每次执行N条指令后如何控制QEMU返回主循环。这个N我可以自由设置。我了解QEMU的事件循环是基于Glib的,我想我的问题可能需要修改QEMU中调用Glib的代码。