19年12月发布的Qemu版本4.2.0包含一项称为TCG插件的新功能。他们在tests / plugins目录中有一些示例,并且该API或多或少在qemu-plugin.h中定义。
该文件定义了两个枚举类型qemu_plugin_cb_flags
和qemu_plugin_mem_rw
,它们被传递到注册回调的函数中。这些枚举似乎表明回调函数将读取还是写入CPU寄存器或内存。但是,所有示例插件都使用QEMU_PLUGIN_CB_NO_REGS
,只有两个插件使用内存访问枚举。hotpages.c
和mem.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团队确实试图阻止我们使用插件中的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*
为no-op,所以在那里无所事事。
然后,查看target/arm/cpu.h
,我们可以看到该结构:
struct ARMCPU {
/*< private >*/
CPUState parent_obj;
/*< public >*/
CPUNegativeOffsetState neg;
CPUARMState env;
// ...
我使用此编译器技巧来获取CPUState和CPUNegativeOffsetState的大小,在我的情况下分别为33488和5424。这为我们提供的偏移量,CPUARMState
其起始位置如下:
typedef struct CPUARMState {
/* Regs for current mode. */
uint32_t regs[16];
// ...
所以寄存器只是开始,所以才使用reg * 4
。
现在我们可以阅读我们的寄存器了,下一步是...
这个比较容易,我从gdbstub.c
qemu本身得到了它:
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);
我们只是声明我们需要的方法并调用它。似乎该方法永远不会失败,从未映射的内存中读取内容不会执行任何操作。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句