如何使QEMU每次只执行一条指令就返回主循环?

问题描述 投票:0回答:1

我在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 "命令。以后,我想知道如何控制QEMU每次执行N条指令后返回主循环。这个N可以由我自由设置.我知道QEMU的事件循环是基于Glib的,我想我的问题可能需要修改QEMU中调用Glib的代码。

qemu glib mainloop
1个回答
0
投票

试图把QEMU的内部结构放到DLL中是完全不支持的事情,所以你要想办法修复其中的bug,恐怕要靠你自己了。

一般来说,你所描述的行为是可以预期的。QEMU将客体代码编译成 "翻译块",这些翻译块对应多个客体指令,然后它还试图在这些翻译块之间直接创建跳转,如果可以的话。这对于性能来说是很重要的:我们不希望在绝对必要的情况下更频繁地返回到顶层执行循环。

其中一些优化是可控的:在上游QEMU中,-singlestep命令行选项意味着 "在每个TB中只放一条客座指令","-d nochain "选项意味着 "不做将TB连接在一起的优化"。主要是为了调试的目的,做这种事情很有用:行为更容易理解,调试日志更容易阅读。缺点是性能会跌破地板。

© www.soinside.com 2019 - 2024. All rights reserved.