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:
parent
86d38fbfa7
commit
7f468ebba6
@ -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);
|
||||
|
152
cpu-target.c
152
cpu-target.c
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
31
include/libafl/cpu.h
Normal 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
|
@ -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
14
include/libafl/gdb.h
Normal 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);
|
6
include/libafl/qemu_snapshot.h
Normal file
6
include/libafl/qemu_snapshot.h
Normal 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);
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
160
libafl/cpu.c
Normal 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
|
@ -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
35
libafl/gdb.c
Normal 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;
|
||||
}
|
@ -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];
|
||||
|
@ -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;
|
||||
|
@ -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
89
libafl/qemu_snapshot.c
Normal 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");
|
||||
}
|
@ -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
37
libafl/user.c
Normal 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;
|
||||
}
|
@ -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
|
||||
|
@ -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 = ®s1;
|
||||
//// --- 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();
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user