Second round of cleanups (#83)

* get rid of as many extern / function definition in QEMU codebase.

* mostly moved cpu / gdb related code.

* move qemu snapshot code in dedicated files.
This commit is contained in:
Romain Malmain 2024-08-14 10:28:47 +02:00 committed by GitHub
parent 86d38fbfa7
commit 7f468ebba6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 449 additions and 401 deletions

View File

@ -39,99 +39,6 @@
#include "libafl/exit.h"
#ifndef CONFIG_USER_ONLY
#include "sysemu/runstate.h"
#include "migration/snapshot.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
#include "hw/core/cpu.h"
#include "sysemu/hw_accel.h"
#include <stdlib.h>
#include <string.h>
void libafl_save_qemu_snapshot(char *name, bool sync);
void libafl_load_qemu_snapshot(char *name, bool sync);
static void save_snapshot_cb(void* opaque)
{
char* name = (char*)opaque;
Error *err = NULL;
if(!save_snapshot(name, true, NULL, false, NULL, &err)) {
error_report_err(err);
error_report("Could not save snapshot");
}
free(opaque);
}
void libafl_save_qemu_snapshot(char *name, bool sync)
{
// use snapshots synchronously, use if main loop is not running
if (sync) {
//TODO: eliminate this code duplication
//by passing a heap-allocated buffer from rust to c,
//which c needs to free
Error *err = NULL;
if(!save_snapshot(name, true, NULL, false, NULL, &err)) {
error_report_err(err);
error_report("Could not save snapshot");
}
return;
}
char* name_buffer = malloc(strlen(name)+1);
strcpy(name_buffer, name);
aio_bh_schedule_oneshot_full(qemu_get_aio_context(), save_snapshot_cb, (void*)name_buffer, "save_snapshot");
}
static void load_snapshot_cb(void* opaque)
{
char* name = (char*)opaque;
Error *err = NULL;
int saved_vm_running = runstate_is_running();
vm_stop(RUN_STATE_RESTORE_VM);
bool loaded = load_snapshot(name, NULL, false, NULL, &err);
if(!loaded) {
error_report_err(err);
error_report("Could not load snapshot");
}
if (loaded && saved_vm_running) {
vm_start();
}
free(opaque);
}
void libafl_load_qemu_snapshot(char *name, bool sync)
{
// use snapshots synchronously, use if main loop is not running
if (sync) {
//TODO: see libafl_save_qemu_snapshot
Error *err = NULL;
int saved_vm_running = runstate_is_running();
vm_stop(RUN_STATE_RESTORE_VM);
bool loaded = load_snapshot(name, NULL, false, NULL, &err);
if(!loaded) {
error_report_err(err);
error_report("Could not load snapshot");
}
if (loaded && saved_vm_running) {
vm_start();
}
return;
}
char* name_buffer = malloc(strlen(name)+1);
strcpy(name_buffer, name);
aio_bh_schedule_oneshot_full(qemu_get_aio_context(), load_snapshot_cb, (void*)name_buffer, "load_snapshot");
}
#endif
void HELPER(libafl_qemu_handle_breakpoint)(CPUArchState *env, uint64_t pc)
{
CPUState* cpu = env_cpu(env);

View File

@ -47,139 +47,10 @@
//// --- Begin LibAFL code ---
#include "exec/gdbstub.h"
#include "libafl/exit.h"
#include "libafl/hook.h"
int gdb_write_register(CPUState *cpu, uint8_t *mem_buf, int reg);
static __thread GByteArray *libafl_qemu_mem_buf = NULL;
target_ulong libafl_page_from_addr(target_ulong addr);
CPUState* libafl_qemu_get_cpu(int cpu_index);
int libafl_qemu_num_cpus(void);
CPUState* libafl_qemu_current_cpu(void);
int libafl_qemu_cpu_index(CPUState*);
int libafl_qemu_write_reg(CPUState* cpu, int reg, uint8_t* val);
int libafl_qemu_read_reg(CPUState* cpu, int reg, uint8_t* val);
int libafl_qemu_num_regs(CPUState* cpu);
#ifndef CONFIG_USER_ONLY
hwaddr libafl_qemu_current_paging_id(CPUState* cpu);
#include "libafl/syx-snapshot/device-save.h"
#endif
void libafl_flush_jit(void);
extern int libafl_restoring_devices;
/*
void* libafl_qemu_g2h(CPUState *cpu, target_ulong x);
target_ulong libafl_qemu_h2g(CPUState *cpu, void* x);
void* libafl_qemu_g2h(CPUState *cpu, target_ulong x)
{
return g2h(cpu, x);
}
target_ulong libafl_qemu_h2g(CPUState *cpu, void* x)
{
return h2g(cpu, x);
}
*/
target_ulong libafl_page_from_addr(target_ulong addr) {
return addr & TARGET_PAGE_MASK;
}
CPUState* libafl_qemu_get_cpu(int cpu_index)
{
CPUState *cpu;
CPU_FOREACH(cpu) {
if (cpu->cpu_index == cpu_index)
return cpu;
}
return NULL;
}
int libafl_qemu_num_cpus(void)
{
CPUState *cpu;
int num = 0;
CPU_FOREACH(cpu) {
num++;
}
return num;
}
CPUState* libafl_qemu_current_cpu(void)
{
#ifndef CONFIG_USER_ONLY
if (current_cpu == NULL) {
return libafl_last_exit_cpu();
}
#endif
return current_cpu;
}
int libafl_qemu_cpu_index(CPUState* cpu)
{
if (cpu) return cpu->cpu_index;
return -1;
}
int libafl_qemu_write_reg(CPUState* cpu, int reg, uint8_t* val)
{
return gdb_write_register(cpu, val, reg);
}
int libafl_qemu_read_reg(CPUState* cpu, int reg, uint8_t* val)
{
int len;
if (libafl_qemu_mem_buf == NULL) {
libafl_qemu_mem_buf = g_byte_array_sized_new(64);
}
g_byte_array_set_size(libafl_qemu_mem_buf, 0);
len = gdb_read_register(cpu, libafl_qemu_mem_buf, reg);
if (len > 0) {
memcpy(val, libafl_qemu_mem_buf->data, len);
}
return len;
}
int libafl_qemu_num_regs(CPUState* cpu)
{
CPUClass *cc = CPU_GET_CLASS(cpu);
return cc->gdb_num_core_regs;
}
#ifndef CONFIG_USER_ONLY
hwaddr libafl_qemu_current_paging_id(CPUState* cpu)
{
CPUClass* cc = CPU_GET_CLASS(cpu);
if (cc->sysemu_ops && cc->sysemu_ops->get_paging_id) {
return cc->sysemu_ops->get_paging_id(cpu);
} else {
return 0;
}
}
#endif
void libafl_flush_jit(void)
{
CPUState *cpu;
CPU_FOREACH(cpu) {
tb_flush(cpu);
}
}
//// --- End LibAFL code ---
#ifndef CONFIG_USER_ONLY
@ -203,7 +74,9 @@ static int cpu_common_post_load(void *opaque, int version_id)
// flushing the TBs every restore makes it really slow
// TODO handle writes to X code with specific calls to tb_invalidate_phys_addr
if (!libafl_restoring_devices) tb_flush(cpu);
if (!libafl_devices_is_restoring()) {
tb_flush(cpu);
}
//// --- End LibAFL code ---
@ -462,23 +335,6 @@ void list_cpus(void)
cpu_list();
}
//// --- Begin LibAFL code ---
#if defined(CONFIG_USER_ONLY)
void libafl_breakpoint_invalidate(CPUState *cpu, target_ulong pc)
{
mmap_lock();
tb_invalidate_phys_range(pc, pc + 1);
mmap_unlock();
}
#else
void libafl_breakpoint_invalidate(CPUState *cpu, target_ulong pc)
{
// TODO invalidate only the virtual pages related to the TB
tb_flush(cpu);
}
#endif
//// --- End LibAFL code ---
/* enable or disable single step mode. EXCP_DEBUG is returned by the
CPU loop after each instruction */
void cpu_single_step(CPUState *cpu, int enabled)

View File

@ -1648,30 +1648,6 @@ static void handle_query_thread_extra(GArray *params, void *user_ctx)
gdb_put_strbuf();
}
//// --- Begin LibAFL code ---
struct libafl_custom_gdb_cmd* libafl_qemu_gdb_cmds;
void libafl_qemu_add_gdb_cmd(int (*callback)(void*, uint8_t*, size_t), void* data);
void libafl_qemu_add_gdb_cmd(int (*callback)(void*, uint8_t*, size_t), void* data)
{
struct libafl_custom_gdb_cmd* c = malloc(sizeof(struct libafl_custom_gdb_cmd));
c->callback = callback;
c->data = data;
c->next = libafl_qemu_gdb_cmds;
libafl_qemu_gdb_cmds = c;
}
void libafl_qemu_gdb_reply(const char* buf, size_t len);
void libafl_qemu_gdb_reply(const char* buf, size_t len)
{
g_autoptr(GString) hex_buf = g_string_new("O");
gdb_memtohex(hex_buf, (const uint8_t *) buf, len);
gdb_put_packet(hex_buf->str);
}
//// --- End LibAFL code ---
static void handle_query_supported(GArray *params, void *user_ctx)
{
CPUClass *cc;

View File

@ -240,16 +240,4 @@ void gdb_breakpoint_remove_all(CPUState *cs);
int gdb_target_memory_rw_debug(CPUState *cs, hwaddr addr,
uint8_t *buf, int len, bool is_write);
//// --- Begin LibAFL code ---
struct libafl_custom_gdb_cmd {
int (*callback)(void*, uint8_t*, size_t);
void* data;
struct libafl_custom_gdb_cmd* next;
};
extern struct libafl_custom_gdb_cmd* libafl_qemu_gdb_cmds;
//// --- End LibAFL code ---
#endif /* GDBSTUB_INTERNALS_H */

View File

@ -30,6 +30,10 @@
#include "trace.h"
#include "internals.h"
//// --- Begin LibAFL code ---
#include "libafl/gdb.h"
//// --- End LibAFL code ---
/* System emulation specific state */
typedef struct {
CharBackend chr;
@ -531,14 +535,7 @@ void gdb_handle_query_rcmd(GArray *params, void *ctx)
//// --- Begin LibAFL code ---
struct libafl_custom_gdb_cmd** c = &libafl_qemu_gdb_cmds;
int recognized = 0;
while (*c) {
recognized |= (*c)->callback((*c)->data, gdbserver_state.mem_buf->data, gdbserver_state.mem_buf->len);
c = &(*c)->next;
}
if (recognized) {
if (libafl_qemu_gdb_exec()) {
gdb_put_packet("OK");
return;
}

View File

@ -14,6 +14,11 @@
#ifdef CONFIG_LINUX
#include "linux-user/loader.h"
#include "linux-user/qemu.h"
//// --- Begin LibAFL code ---
#include "libafl/gdb.h"
//// --- End LibAFL code ---
#endif
/*
@ -305,27 +310,17 @@ void gdb_handle_query_rcmd(GArray *params, void *user_ctx)
g_assert(gdbserver_state.mem_buf->len == 0);
len = len / 2;
gdb_hextomem(gdbserver_state.mem_buf, get_param(params, 0)->data, len);
//// --- Begin LibAFL code ---
struct libafl_custom_gdb_cmd** c = &libafl_qemu_gdb_cmds;
int recognized = 0;
while (*c) {
recognized |= (*c)->callback((*c)->data, gdbserver_state.mem_buf->data, gdbserver_state.mem_buf->len);
c = &(*c)->next;
}
if (recognized) {
if (libafl_qemu_gdb_exec()) {
gdb_put_packet("OK");
} else {
gdb_put_packet("");
}
}
#endif
//// --- End LibAFL code ---
#endif
static const char *get_filename_param(GArray *params, int i)
{
const char *hex_filename = get_param(params, i)->data;

31
include/libafl/cpu.h Normal file
View File

@ -0,0 +1,31 @@
#pragma once
#include "qemu/osdep.h"
#ifndef CONFIG_USER_ONLY
#include "exec/memory.h"
#include "qemu/rcu.h"
#include "cpu.h"
#endif
#ifndef CONFIG_USER_ONLY
uint8_t* libafl_paddr2host(CPUState* cpu, hwaddr addr, bool is_write);
hwaddr libafl_qemu_current_paging_id(CPUState* cpu);
#endif
target_ulong libafl_page_from_addr(target_ulong addr);
CPUState* libafl_qemu_get_cpu(int cpu_index);
int libafl_qemu_num_cpus(void);
CPUState* libafl_qemu_current_cpu(void);
int libafl_qemu_cpu_index(CPUState*);
int libafl_qemu_write_reg(CPUState* cpu, int reg, uint8_t* val);
int libafl_qemu_read_reg(CPUState* cpu, int reg, uint8_t* val);
int libafl_qemu_num_regs(CPUState* cpu);
void libafl_flush_jit(void);
void libafl_breakpoint_invalidate(CPUState* cpu, target_ulong pc);
#ifdef CONFIG_USER_ONLY
int libafl_qemu_main(void);
int libafl_qemu_run(void);
void libafl_set_qemu_env(CPUArchState* env);
#endif

View File

@ -12,9 +12,6 @@ struct libafl_breakpoint {
struct libafl_breakpoint* next;
};
// in cpu-target.c
void libafl_breakpoint_invalidate(CPUState* cpu, target_ulong pc);
int libafl_qemu_set_breakpoint(target_ulong pc);
int libafl_qemu_remove_breakpoint(target_ulong pc);
void libafl_qemu_trigger_breakpoint(CPUState* cpu);

14
include/libafl/gdb.h Normal file
View File

@ -0,0 +1,14 @@
#pragma once
#include "qemu/osdep.h"
struct libafl_custom_gdb_cmd {
bool (*callback)(void*, uint8_t*, size_t);
void* data;
struct libafl_custom_gdb_cmd* next;
};
void libafl_qemu_add_gdb_cmd(bool (*callback)(void*, uint8_t*, size_t),
void* data);
void libafl_qemu_gdb_reply(const uint8_t* buf, size_t len);
bool libafl_qemu_gdb_exec(void);

View File

@ -0,0 +1,6 @@
#pragma once
#include "qemu/osdep.h"
void libafl_save_qemu_snapshot(char* name, bool sync);
void libafl_load_qemu_snapshot(char* name, bool sync);

View File

@ -24,3 +24,5 @@ void device_restore_all(DeviceSaveState* device_save_state);
void device_free_all(DeviceSaveState* dss);
char** device_list_all(void);
bool libafl_devices_is_restoring(void);

View File

@ -2,6 +2,9 @@
#include "qapi/error.h"
#include "qemu/osdep.h"
#include "qemu/interval-tree.h"
#include "exec/cpu-defs.h"
struct libafl_mapinfo {
target_ulong start;
@ -13,9 +16,17 @@ struct libafl_mapinfo {
bool is_valid;
};
void libafl_dump_core_exec(int signal);
void libafl_qemu_handle_crash(int host_sig, siginfo_t* info, void* puc);
IntervalTreeNode* libafl_maps_first(IntervalTreeRoot* map_info);
IntervalTreeNode* libafl_maps_next(IntervalTreeNode* pageflags_maps_node,
IntervalTreeRoot* proc_maps_node,
struct libafl_mapinfo* ret);
uint64_t libafl_load_addr(void);
struct image_info* libafl_get_image_info(void);
uint64_t libafl_get_brk(void);
uint64_t libafl_set_brk(uint64_t new_brk);

View File

@ -1,15 +1,3 @@
#pragma once
#include "qemu/osdep.h"
#ifndef CONFIG_USER_ONLY
#include "exec/memory.h"
#include "qemu/rcu.h"
#include "cpu.h"
#endif
uintptr_t libafl_qemu_host_page_size(void);
#ifndef CONFIG_USER_ONLY
uint8_t* libafl_paddr2host(CPUState* cpu, hwaddr addr, bool is_write);
#endif

160
libafl/cpu.c Normal file
View File

@ -0,0 +1,160 @@
#include "qemu/osdep.h"
#ifdef CONFIG_USER_ONLY
#include "qemu.h"
#include "user-internals.h"
#endif
#include "exec/gdbstub.h"
#include "exec/cpu-defs.h"
#include "exec/tb-flush.h"
#include "exec/exec-all.h"
#include "hw/core/sysemu-cpu-ops.h"
#include "libafl/cpu.h"
#include "libafl/exit.h"
#include "libafl/hook.h"
int gdb_write_register(CPUState* cpu, uint8_t* mem_buf, int reg);
static __thread GByteArray* libafl_qemu_mem_buf = NULL;
#ifdef CONFIG_USER_ONLY
static __thread CPUArchState* libafl_qemu_env;
#endif
#ifndef CONFIG_USER_ONLY
uint8_t* libafl_paddr2host(CPUState* cpu, hwaddr addr, bool is_write)
{
if (addr == -1) {
return NULL;
}
hwaddr xlat;
MemoryRegion* mr;
WITH_RCU_READ_LOCK_GUARD()
{
mr = address_space_translate(cpu->as, addr, &xlat, NULL, is_write,
MEMTXATTRS_UNSPECIFIED);
}
return qemu_map_ram_ptr(mr->ram_block, xlat);
}
hwaddr libafl_qemu_current_paging_id(CPUState* cpu)
{
CPUClass* cc = CPU_GET_CLASS(cpu);
if (cc->sysemu_ops && cc->sysemu_ops->get_paging_id) {
return cc->sysemu_ops->get_paging_id(cpu);
} else {
return 0;
}
}
void libafl_breakpoint_invalidate(CPUState* cpu, target_ulong pc)
{
// TODO invalidate only the virtual pages related to the TB
tb_flush(cpu);
}
#else
void libafl_breakpoint_invalidate(CPUState* cpu, target_ulong pc)
{
mmap_lock();
tb_invalidate_phys_range(pc, pc + 1);
mmap_unlock();
}
#endif
target_ulong libafl_page_from_addr(target_ulong addr)
{
return addr & TARGET_PAGE_MASK;
}
CPUState* libafl_qemu_get_cpu(int cpu_index)
{
CPUState* cpu;
CPU_FOREACH(cpu)
{
if (cpu->cpu_index == cpu_index)
return cpu;
}
return NULL;
}
int libafl_qemu_num_cpus(void)
{
CPUState* cpu;
int num = 0;
CPU_FOREACH(cpu) { num++; }
return num;
}
CPUState* libafl_qemu_current_cpu(void)
{
#ifndef CONFIG_USER_ONLY
if (current_cpu == NULL) {
return libafl_last_exit_cpu();
}
#endif
return current_cpu;
}
int libafl_qemu_cpu_index(CPUState* cpu)
{
if (cpu)
return cpu->cpu_index;
return -1;
}
int libafl_qemu_write_reg(CPUState* cpu, int reg, uint8_t* val)
{
return gdb_write_register(cpu, val, reg);
}
int libafl_qemu_read_reg(CPUState* cpu, int reg, uint8_t* val)
{
int len;
if (libafl_qemu_mem_buf == NULL) {
libafl_qemu_mem_buf = g_byte_array_sized_new(64);
}
g_byte_array_set_size(libafl_qemu_mem_buf, 0);
len = gdb_read_register(cpu, libafl_qemu_mem_buf, reg);
if (len > 0) {
memcpy(val, libafl_qemu_mem_buf->data, len);
}
return len;
}
int libafl_qemu_num_regs(CPUState* cpu)
{
CPUClass* cc = CPU_GET_CLASS(cpu);
return cc->gdb_num_core_regs;
}
void libafl_flush_jit(void)
{
CPUState* cpu;
CPU_FOREACH(cpu) { tb_flush(cpu); }
}
#ifdef CONFIG_USER_ONLY
__attribute__((weak)) int libafl_qemu_main(void)
{
libafl_qemu_run();
return 0;
}
int libafl_qemu_run(void)
{
cpu_loop(libafl_qemu_env);
return 1;
}
void libafl_set_qemu_env(CPUArchState* env) { libafl_qemu_env = env; }
#endif

View File

@ -7,6 +7,7 @@
#include "exec/translator.h"
#include "cpu.h"
#include "libafl/cpu.h"
#ifdef CONFIG_USER_ONLY
#define THREAD_MODIFIER __thread

35
libafl/gdb.c Normal file
View File

@ -0,0 +1,35 @@
#include "qemu/osdep.h"
#include "libafl/gdb.h"
#include "gdbstub/internals.h"
static struct libafl_custom_gdb_cmd* libafl_qemu_gdb_cmds;
void libafl_qemu_add_gdb_cmd(bool (*callback)(void*, uint8_t*, size_t),
void* data)
{
struct libafl_custom_gdb_cmd* c =
malloc(sizeof(struct libafl_custom_gdb_cmd));
c->callback = callback;
c->data = data;
c->next = libafl_qemu_gdb_cmds;
libafl_qemu_gdb_cmds = c;
}
void libafl_qemu_gdb_reply(const uint8_t* buf, size_t len)
{
g_autoptr(GString) hex_buf = g_string_new("O");
gdb_memtohex(hex_buf, buf, len);
gdb_put_packet(hex_buf->str);
}
bool libafl_qemu_gdb_exec(void)
{
struct libafl_custom_gdb_cmd** c = &libafl_qemu_gdb_cmds;
bool recognized = false;
while (*c) {
recognized |= (*c)->callback((*c)->data, gdbserver_state.mem_buf->data,
gdbserver_state.mem_buf->len);
c = &(*c)->next;
}
return recognized;
}

View File

@ -1,5 +1,7 @@
#include "libafl/hooks/tcg/instruction.h"
#include "libafl/cpu.h"
target_ulong libafl_gen_cur_pc;
struct libafl_instruction_hook*
libafl_qemu_instruction_hooks[LIBAFL_TABLES_SIZE];

View File

@ -1,9 +1,8 @@
#include "libafl/hooks/thread.h"
#include "libafl/cpu.h"
#include <linux/unistd.h>
extern __thread CPUArchState* libafl_qemu_env;
struct libafl_new_thread_hook* libafl_new_thread_hooks;
size_t libafl_new_thread_hooks_num = 0;
@ -27,7 +26,7 @@ size_t libafl_add_new_thread_hook(bool (*callback)(uint64_t data,
bool libafl_hook_new_thread_run(CPUArchState* env)
{
libafl_qemu_env = env;
libafl_set_qemu_env(env);
if (libafl_new_thread_hooks) {
bool continue_execution = true;

View File

@ -1,8 +1,10 @@
specific_ss.add(files(
'cpu.c',
'exit.c',
'hook.c',
'jit.c',
'utils.c',
'gdb.c',
# TCG-related hooks
'hooks/tcg/backdoor.c',
@ -17,6 +19,7 @@ specific_ss.add(files(
))
specific_ss.add(when : 'CONFIG_SOFTMMU', if_true : [files(
'qemu_snapshot.c',
'syx-snapshot/device-save.c',
'syx-snapshot/syx-snapshot.c',
'syx-snapshot/syx-cow-cache.c',
@ -24,6 +27,7 @@ specific_ss.add(when : 'CONFIG_SOFTMMU', if_true : [files(
)])
specific_ss.add(when : 'CONFIG_USER_ONLY', if_true : [files(
'user.c',
'hooks/syscall.c',
'hooks/thread.c',
)])

89
libafl/qemu_snapshot.c Normal file
View File

@ -0,0 +1,89 @@
#include "libafl/qemu_snapshot.h"
#include "sysemu/runstate.h"
#include "migration/snapshot.h"
#include "qapi/error.h"
#include "qemu/error-report.h"
#include "qemu/main-loop.h"
#include "hw/core/cpu.h"
#include "sysemu/hw_accel.h"
#include <stdlib.h>
#include <string.h>
static void save_snapshot_cb(void* opaque)
{
char* name = (char*)opaque;
Error* err = NULL;
if (!save_snapshot(name, true, NULL, false, NULL, &err)) {
error_report_err(err);
error_report("Could not save snapshot");
}
free(opaque);
}
static void load_snapshot_cb(void* opaque)
{
char* name = (char*)opaque;
Error* err = NULL;
int saved_vm_running = runstate_is_running();
vm_stop(RUN_STATE_RESTORE_VM);
bool loaded = load_snapshot(name, NULL, false, NULL, &err);
if (!loaded) {
error_report_err(err);
error_report("Could not load snapshot");
}
if (loaded && saved_vm_running) {
vm_start();
}
free(opaque);
}
void libafl_save_qemu_snapshot(char* name, bool sync)
{
// use snapshots synchronously, use if main loop is not running
if (sync) {
// TODO: eliminate this code duplication
// by passing a heap-allocated buffer from rust to c,
// which c needs to free
Error* err = NULL;
if (!save_snapshot(name, true, NULL, false, NULL, &err)) {
error_report_err(err);
error_report("Could not save snapshot");
}
return;
}
char* name_buffer = malloc(strlen(name) + 1);
strcpy(name_buffer, name);
aio_bh_schedule_oneshot_full(qemu_get_aio_context(), save_snapshot_cb,
(void*)name_buffer, "save_snapshot");
}
void libafl_load_qemu_snapshot(char* name, bool sync)
{
// use snapshots synchronously, use if main loop is not running
if (sync) {
// TODO: see libafl_save_qemu_snapshot
Error* err = NULL;
int saved_vm_running = runstate_is_running();
vm_stop(RUN_STATE_RESTORE_VM);
bool loaded = load_snapshot(name, NULL, false, NULL, &err);
if (!loaded) {
error_report_err(err);
error_report("Could not load snapshot");
}
if (loaded && saved_vm_running) {
vm_start();
}
return;
}
char* name_buffer = malloc(strlen(name) + 1);
strcpy(name_buffer, name);
aio_bh_schedule_oneshot_full(qemu_get_aio_context(), load_snapshot_cb,
(void*)name_buffer, "load_snapshot");
}

View File

@ -11,12 +11,13 @@
#include "migration/savevm.h"
int libafl_restoring_devices;
extern SaveState savevm_state;
extern int vmstate_save(QEMUFile* f, SaveStateEntry* se, JSONWriter* vmdesc);
static bool libafl_restoring_devices = false;
bool libafl_devices_is_restoring(void) { return libafl_restoring_devices; }
// iothread must be locked
DeviceSaveState* device_save_all(void)
{
@ -101,8 +102,8 @@ void device_restore_all(DeviceSaveState* dss)
QEMUFile* f = qemu_file_new_input(ioc);
int save_libafl_restoring_devices = libafl_restoring_devices;
libafl_restoring_devices = 1;
bool save_libafl_restoring_devices = libafl_restoring_devices;
libafl_restoring_devices = true;
qemu_load_device_state(f);

37
libafl/user.c Normal file
View File

@ -0,0 +1,37 @@
#include "qemu/osdep.h"
#include "qemu.h"
#include "loader.h"
#include "libafl/user.h"
void (*libafl_dump_core_hook)(int host_sig) = NULL;
static struct image_info libafl_image_info;
extern abi_ulong target_brk, initial_target_brk;
void host_signal_handler(int host_sig, siginfo_t* info, void* puc);
void libafl_qemu_handle_crash(int host_sig, siginfo_t* info, void* puc)
{
host_signal_handler(host_sig, info, puc);
}
void libafl_dump_core_exec(int signal)
{
if (libafl_dump_core_hook) {
libafl_dump_core_hook(signal);
}
}
uint64_t libafl_load_addr(void) { return libafl_image_info.load_addr; }
struct image_info* libafl_get_image_info(void) { return &libafl_image_info; }
uint64_t libafl_get_brk(void) { return (uint64_t)target_brk; }
uint64_t libafl_set_brk(uint64_t new_brk)
{
uint64_t old_brk = (uint64_t)target_brk;
target_brk = (abi_ulong)new_brk;
return old_brk;
}

View File

@ -5,24 +5,3 @@ uintptr_t libafl_qemu_host_page_size(void)
{
return qemu_real_host_page_size();
}
#ifndef CONFIG_USER_ONLY
uint8_t* libafl_paddr2host(CPUState* cpu, hwaddr addr, bool is_write)
{
if (addr == -1) {
return NULL;
}
hwaddr xlat;
MemoryRegion* mr;
WITH_RCU_READ_LOCK_GUARD()
{
mr = address_space_translate(cpu->as, addr, &xlat, NULL, is_write,
MEMTXATTRS_UNSPECIFIED);
}
return qemu_map_ram_ptr(mr->ram_block, xlat);
}
#endif

View File

@ -57,6 +57,11 @@
#include "tcg/perf.h"
#include "exec/page-vary.h"
//// --- End LibAFL code ---
#include "libafl/cpu.h"
#include "libafl/user.h"
//// --- Begin LibAFL code ---
#ifdef CONFIG_SEMIHOSTING
#include "semihosting/semihost.h"
#endif
@ -685,45 +690,22 @@ static int parse_args(int argc, char **argv)
}
//// --- Begin LibAFL code ---
uint64_t libafl_load_addr(void);
int libafl_qemu_main(void);
int libafl_qemu_run(void);
__thread CPUArchState *libafl_qemu_env;
struct image_info libafl_image_info;
struct linux_binprm bprm;
uint64_t libafl_load_addr(void) {
return libafl_image_info.load_addr;
}
__attribute__((weak)) int libafl_qemu_main(void)
{
libafl_qemu_run();
return 0;
}
int libafl_qemu_run(void)
{
cpu_loop(libafl_qemu_env);
return 1;
}
//// --- End LibAFL code ---
#ifdef AS_LIB
int qemu_user_init(int argc, char **argv, char **envp);
int qemu_user_init(int argc, char **argv, char **envp)
#else
//// --- End LibAFL code ---
int main(int argc, char **argv, char **envp)
//// --- Begin LibAFL code ---
#endif
//// --- End LibAFL code ---
{
struct target_pt_regs regs1, *regs = &regs1;
//// --- Begin LibAFL code ---
//struct image_info info1, *info = &info1;
struct image_info *info = &libafl_image_info;
struct image_info *info = libafl_get_image_info();
// struct linux_binprm bprm;
//// --- End LibAFL code ---
TaskState *ts;
@ -1076,7 +1058,7 @@ int main(int argc, char **argv, char **envp)
//// --- Begin LibAFL code ---
libafl_qemu_env = env;
libafl_set_qemu_env(env);
#ifndef AS_LIB
return libafl_qemu_main();

View File

@ -34,12 +34,21 @@
#include "user/safe-syscall.h"
#include "tcg/tcg.h"
//// --- Begin LibAFL code ---
#include "libafl/user.h"
//// --- End LibAFL code ---
/* target_siginfo_t must fit in gdbstub's siginfo save area. */
QEMU_BUILD_BUG_ON(sizeof(target_siginfo_t) > MAX_SIGINFO_LENGTH);
static struct target_sigaction sigact_table[TARGET_NSIG];
static void host_signal_handler(int host_signum, siginfo_t *info,
//// --- Begin LibAFL code ---
/* static */
//// --- End LibAFL code ---
void host_signal_handler(int host_signum, siginfo_t *info,
void *puc);
/* Fallback addresses into sigtramp page. */
@ -729,7 +738,6 @@ void die_with_signal(int host_sig)
//// --- Begin LibAFL code ---
void (*libafl_dump_core_hook)(int host_sig);
//// --- End LibAFL code ---
@ -770,8 +778,8 @@ void dump_core_and_abort(CPUArchState *env, int target_sig)
//// --- Begin LibAFL code ---
if (libafl_dump_core_hook) libafl_dump_core_hook(host_sig);
libafl_dump_core_exec(host_sig);
// die_with_signal_nodfl(host_sig); // to trigger LibAFL sig handler
//// --- End LibAFL code ---
@ -890,9 +898,9 @@ void die_from_signal(siginfo_t *info)
sig, code, info->si_addr);
//// --- Begin LibAFL code ---
if (libafl_dump_core_hook) libafl_dump_core_hook(info->si_signo);
libafl_dump_core_exec(info->si_signo);
//// --- End LibAFL code ---
die_with_signal(info->si_signo);
@ -997,15 +1005,12 @@ static uintptr_t host_sigbus_handler(CPUState *cpu, siginfo_t *info,
pc, guest_addr);
} */
#include "libafl/user.h"
void libafl_qemu_handle_crash(int host_sig, siginfo_t *info, void *puc) {
host_signal_handler(host_sig, info, puc);
}
//// --- End LibAFL code ---
static void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
//// --- Begin LibAFL code ---
/* static */
//// --- End LibAFL code ---
void host_signal_handler(int host_sig, siginfo_t *info, void *puc)
{
CPUState *cpu = thread_cpu;
CPUArchState *env = cpu_env(cpu);

View File

@ -805,7 +805,10 @@ static inline int host_to_target_sock_type(int host_type)
return target_type;
}
static abi_ulong target_brk, initial_target_brk;
//// --- Begin LibAFL code ---
/* static */
//// --- End LibAFL code ---
abi_ulong target_brk, initial_target_brk;
void target_set_brk(abi_ulong new_brk)
{
@ -813,23 +816,6 @@ void target_set_brk(abi_ulong new_brk)
initial_target_brk = target_brk;
}
//// --- Begin LibAFL code ---
uint64_t libafl_get_brk(void);
uint64_t libafl_set_brk(uint64_t new_brk);
uint64_t libafl_get_brk(void) {
return (uint64_t)target_brk;
}
uint64_t libafl_set_brk(uint64_t new_brk) {
uint64_t old_brk = (uint64_t)target_brk;
target_brk = (abi_ulong)new_brk;
return old_brk;
}
//// --- End LibAFL code ---
/* do_brk() must return target values and target errnos. */
abi_long do_brk(abi_ulong brk_val)
{