Qemu插件功能-如何访问来宾存储器和寄存器

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

背景

Qemu version 4.2.0,于19年12月发布,包括一项称为TCG Plugins的新功能。它们在tests/plugins目录中有一些示例,并且在qemu-plugin.h中或多或少地定义了API。

此文件定义了两个枚举类型qemu_plugin_cb_flagsqemu_plugin_mem_rw,它们被传递到注册回调的函数中。这些枚举似乎表明回调函数将读取还是写入CPU寄存器或内存。但是,所有示例插件都使用QEMU_PLUGIN_CB_NO_REGS,只有两个插件使用内存访问枚举。 hotpages.cmem.c使用QEMU_PLUGIN_MEM_RW作为注册内存回调(qemu_plugin_register_vcpu_mem_cb)的默认设置。 mem.c在加载插件时有一个参数可以选择是读还是写,但是,在回调函数中似乎没有任何区别。

问题

我的问题是,如何从插件回调函数访问来宾存储器并进行注册?该API似乎表明这是可能的,因为回调注册要求您说出是否将访问它们,以及是否为RW或只是读取。

是否有使用此API部分的示例?我意识到这是Qemu功能的一个非常新的部分。

代码

当您在指令上注册回调时,就像在insn.c中一样,您可以获得指令的虚拟地址。

uint64_t insn_vaddr = qemu_plugin_insn_vaddr(insn);

我正在运行裸机ARM程序,并且该虚拟地址似乎与ELF文件中指令的地址相关。

内部内存回调函数中,您可以调用qemu_plugin_get_hwaddr以获取内存访问的硬件地址,但我不确定该结构代表什么。

相关

此答案已有7年历史,建议使用GDB界面。我的问题与使用TCG插件功能特别相关。

此外,QEMU Tiny Code Generator(TCG)是否应该有一个标签?

c arm qemu bare-metal
1个回答
0
投票

我刚遇到同样的问题。似乎qemu团队确实试图阻止我们使用插件中的CPU或内存。我尝试通过修改Makefiles来包含所需的标头,但是不应将这些标头包含在插件之类的外部代码中。我无法使其编译。

正如您所说,有标志表明这是可能的。我的猜测是该功能尚未完全实现,也许很快就能实现。

同时,当我们等待适当的方法来执行此操作时,这就是我如何破解它的方法:

获取注册

就我而言,CPU是ARM。我将首先显示代码,然后进行解释。

void *qemu_get_cpu(int index);

static uint32_t get_cpu_register(unsigned int cpu_index, unsigned int reg) {
    uint8_t* cpu = qemu_get_cpu(cpu_index);
    return *(uint32_t*)(cpu + 33488 + 5424 + reg * 4);
}

我首先声明qemu_get_cpu函数,因为我们不能包括它的标题。该函数返回CPUState*。由于我的CPU是ARM,因此我知道指针实际上是ARMCPU*。由于在qemu中实现了继承,因此从CPUState*ARMCPU*的强制转换是无操作的,因此在此无需执行任何操作。

然后,在target/arm/cpu.h中,我们可以看到该结构:

struct ARMCPU {
    /*< private >*/
    CPUState parent_obj;
    /*< public >*/

    CPUNegativeOffsetState neg;
    CPUARMState env;
    // ...

我使用this compiler trick来获取CPUState和CPUNegativeOffsetState的大小,在我的情况下分别为33488和5424。这为我们提供了CPUARMState的偏移量,其起始位置如下:

typedef struct CPUARMState {
    /* Regs for current mode.  */
    uint32_t regs[16];
    // ...

所以寄存器只是开始,这就是为什么我使用reg * 4

现在我们可以阅读我们的寄存器,下一步是...

从内存中读取

这个比较容易,我从qemu本身的gdbstub.c中获得了它:

void cpu_physical_memory_rw(uint64_t addr, uint8_t *buf,
                            uint64_t len, int is_write);

// and in my function:
    char name[9] = {0};
    cpu_physical_memory_rw(name_addr, name, 8, 0);

我们只是声明我们需要的方法并调用它。似乎该方法永远不会失败,从未映射的内存中读取内容不会执行任何操作。

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