The way to extend qemu TCG plugin functionality

Hi, if want to to provide other function-calls to TCG plugin, such as reading guest memory, follow these steps:

  1. in include/qemu/qemu-plugin.h, add function header, such as
/**
 * qemu_plugin_read_guest_virt_mem() - Read a buffer of guest memory
 * @gva: Guest virtual address
 * @buf: Buffer to copy guest memory into
 * @length: Size of buf
 *
 * Returns: True if the memory was successfully copied into buf
 */
bool qemu_plugin_read_guest_virt_mem(uint64_t gva, char* buf, size_t length);
  1. in plugins/api.c, add function body, such as
bool qemu_plugin_read_guest_virt_mem(uint64_t gva, char* buf, size_t length) {
#ifdef CONFIG_USER_ONLY
  return false;
#else
    // Convert virtual address to physical, then read it
    CPUState *cpu = current_cpu;
    uint64_t page = gva & TARGET_PAGE_MASK;
    hwaddr gpa = cpu_get_phys_page_debug(cpu, page);
    if (gpa == (hwaddr)-1) {
        return false;
    }
 
    gpa += (gva & ~TARGET_PAGE_MASK);
	// cpu_physical_memory_read(gpa, buf, length);
    cpu_memory_rw_debug(cpu, gva, buf, length, false);
    return true;
#endif
}
  1. in plugins/qemu-plugins.symbols, add
qemu_plugin_read_guest_virt_mem;
  1. in your tcg plugin tests/plugin/mem.c, just call to it, such as
        struct qemu_plugin_hwaddr *hwaddr2 = qemu_plugin_get_hwaddr(meminfo, vaddr);
        const char *name = qemu_plugin_hwaddr_device_name(hwaddr2);
        uint64_t addr = qemu_plugin_hwaddr_phys_addr(hwaddr2);
        g_autoptr(GString) out = g_string_new("");

        uint64_t temp=0;
		unsigned int size=8;
        // unsigned int size=qemu_plugin_mem_size_shift(meminfo);  // get the accessed memory size
        // if (size==2){
        //      size=1;
        // }else if (size==4){
        //      size=2;
        // }else{
        //      size=8;
        // }
        qemu_plugin_read_guest_virt_mem(vaddr, (char *)&temp, size);

        if (qemu_plugin_mem_is_store(meminfo)) {
                        g_string_printf(out, "> mem store (%s), 0x%lx, 0x%lx, 0x%lx, %d\n", name, (long unsigned int)vaddr, (long unsigned int)addr, (long unsigned int)temp, size);
        } else {
                        g_string_printf(out, "> mem load(%s), 0x%lx, 0x%lx, 0x%lx, %d\n", name, (long unsigned int)vaddr, (long unsigned int)addr, (long unsigned int)temp, size);
        }
        qemu_plugin_outs(out->str);

5. Run in qemu

./configure --target-list=riscv64-softmmu --enable-plugins

6. Edit xv6-riscv Makefile:

qemu2: $K/kernel fs.img
        $(QEMU) $(QEMUOPTS) -singlestep -d exec,cpu,nochain,in_asm,int,plugin -plugin ~/workspace/qemu/build/tests/plugin/libmem.so,callback=true -D qemu.log

References:

  1. https://gitlab.com/qemu-project/qemu/-/issues/2152#note_1767322945
  2. https://github.com/qemu/qemu/commit/72c661a7f141ab41fbce5e95eb3593b69f40e246?diff=split&w=0#diff-d508cf0c073440a0ef62534395ec2ccff4378932f755f0d093cdc1795d9f871f
  3. https://airbus-seclab.github.io/qemu_blog/tcg_p3.html
  4. https://airbus-seclab.github.io/qemu_blog/regions.html

Leave a Reply

Your email address will not be published. Required fields are marked *