137 lines
3.8 KiB
C
137 lines
3.8 KiB
C
#include "libafl/tcg.h"
|
|
#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];
|
|
size_t libafl_qemu_hooks_num = 0;
|
|
|
|
size_t libafl_qemu_add_instruction_hooks(target_ulong pc,
|
|
void (*callback)(uint64_t data,
|
|
target_ulong pc),
|
|
uint64_t
|
|
|
|
data,
|
|
int invalidate)
|
|
{
|
|
CPUState* cpu;
|
|
|
|
if (invalidate) {
|
|
CPU_FOREACH(cpu) { libafl_breakpoint_invalidate(cpu, pc); }
|
|
}
|
|
|
|
size_t idx = LIBAFL_TABLES_HASH(pc);
|
|
|
|
struct libafl_instruction_hook* hk =
|
|
calloc(sizeof(struct libafl_instruction_hook), 1);
|
|
hk->addr = pc;
|
|
// hk->callback = callback;
|
|
hk->data = data;
|
|
hk->helper_info.func = callback;
|
|
hk->helper_info.name = "libafl_instruction_hook";
|
|
hk->helper_info.flags = dh_callflag(void);
|
|
hk->helper_info.typemask =
|
|
dh_typemask(void, 0) | dh_typemask(i64, 1) | dh_typemask(tl, 2);
|
|
// TODO check for overflow
|
|
hk->num = libafl_qemu_hooks_num++;
|
|
hk->next = libafl_qemu_instruction_hooks[idx];
|
|
libafl_qemu_instruction_hooks[idx] = hk;
|
|
return hk->num;
|
|
}
|
|
|
|
size_t libafl_qemu_remove_instruction_hooks_at(target_ulong addr,
|
|
int invalidate)
|
|
{
|
|
CPUState* cpu;
|
|
size_t r = 0;
|
|
|
|
size_t idx = LIBAFL_TABLES_HASH(addr);
|
|
struct libafl_instruction_hook** hk = &libafl_qemu_instruction_hooks[idx];
|
|
while (*hk) {
|
|
if ((*hk)->addr == addr) {
|
|
if (invalidate) {
|
|
CPU_FOREACH(cpu) { libafl_breakpoint_invalidate(cpu, addr); }
|
|
}
|
|
|
|
void* tmp = *hk;
|
|
*hk = (*hk)->next;
|
|
free(tmp);
|
|
r++;
|
|
} else {
|
|
hk = &(*hk)->next;
|
|
}
|
|
}
|
|
return r;
|
|
}
|
|
|
|
int libafl_qemu_remove_instruction_hook(size_t num, int invalidate)
|
|
{
|
|
CPUState* cpu;
|
|
size_t idx;
|
|
|
|
for (idx = 0; idx < LIBAFL_TABLES_SIZE; ++idx) {
|
|
struct libafl_instruction_hook** hk =
|
|
&libafl_qemu_instruction_hooks[idx];
|
|
while (*hk) {
|
|
if ((*hk)->num == num) {
|
|
if (invalidate) {
|
|
CPU_FOREACH(cpu)
|
|
{
|
|
libafl_breakpoint_invalidate(cpu, (*hk)->addr);
|
|
}
|
|
}
|
|
|
|
void* tmp = *hk;
|
|
*hk = (*hk)->next;
|
|
free(tmp);
|
|
return 1;
|
|
} else {
|
|
hk = &(*hk)->next;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
struct libafl_instruction_hook*
|
|
libafl_search_instruction_hook(target_ulong addr)
|
|
{
|
|
size_t idx = LIBAFL_TABLES_HASH(addr);
|
|
|
|
struct libafl_instruction_hook* hk = libafl_qemu_instruction_hooks[idx];
|
|
while (hk) {
|
|
if (hk->addr == addr) {
|
|
return hk;
|
|
}
|
|
hk = hk->next;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void libafl_qemu_hook_instruction_run(vaddr pc_next)
|
|
{
|
|
struct libafl_instruction_hook* hk =
|
|
libafl_search_instruction_hook(pc_next);
|
|
if (hk) {
|
|
TCGv_i64 tmp0 = tcg_constant_i64(hk->data);
|
|
#if TARGET_LONG_BITS == 32
|
|
TCGv_i32 tmp1 = tcg_constant_i32(pc_next);
|
|
TCGTemp* tmp2[2] = {tcgv_i64_temp(tmp0), tcgv_i32_temp(tmp1)};
|
|
#else
|
|
TCGv_i64 tmp1 = tcg_constant_i64(pc_next);
|
|
TCGTemp* tmp2[2] = {tcgv_i64_temp(tmp0), tcgv_i64_temp(tmp1)};
|
|
#endif
|
|
// tcg_gen_callN(hk->callback, NULL, 2, tmp2);
|
|
tcg_gen_callN(hk->helper_info.func, &hk->helper_info, NULL, tmp2);
|
|
#if TARGET_LONG_BITS == 32
|
|
tcg_temp_free_i32(tmp1);
|
|
#else
|
|
tcg_temp_free_i64(tmp1);
|
|
#endif
|
|
tcg_temp_free_i64(tmp0);
|
|
}
|
|
}
|