Inline uc_tracecode when there is only exactly one hook

This commit is contained in:
lazymio 2021-11-21 16:44:39 +01:00
parent 18d7f090ce
commit 87a391d549
No known key found for this signature in database
GPG Key ID: DFF27E34A47CB873
31 changed files with 173 additions and 6 deletions

View File

@ -142,6 +142,13 @@ struct hook {
void *user_data;
};
// Add an inline hook to helper_table
typedef void (*uc_add_inline_hook_t)(struct uc_struct *uc, struct hook *hk,
void **args, int args_len);
// Delete a hook from helper_table
typedef void (*uc_del_inline_hook_t)(struct uc_struct *uc, struct hook *hk);
// hook list offsets
//
// The lowest 6 bits are used for hook type index while the others
@ -254,6 +261,8 @@ struct uc_struct {
uc_tcg_flush_tlb tcg_flush_tlb;
uc_invalidate_tb_t uc_invalidate_tb;
uc_gen_tb_t uc_gen_tb;
uc_add_inline_hook_t add_inline_hook;
uc_del_inline_hook_t del_inline_hook;
/* only 1 cpu in unicorn,
do not need current_cpu to handle current running cpu. */
@ -296,6 +305,7 @@ struct uc_struct {
// linked lists containing hooks per type
struct list hook[UC_HOOK_MAX];
struct list hooks_to_del;
int hooks_count[UC_HOOK_MAX];
// hook to count number of instructions for uc_emu_start()
uc_hook count_hook;

View File

@ -4,6 +4,8 @@
#ifndef UNICORN_ARCH_POSTFIX
#define UNICORN_ARCH_POSTFIX _aarch64
#endif
#define uc_add_inline_hook uc_add_inline_hook_aarch64
#define uc_del_inline_hook uc_del_inline_hook_aarch64
#define tb_invalidate_phys_range tb_invalidate_phys_range_aarch64
#define use_idiv_instructions use_idiv_instructions_aarch64
#define arm_arch arm_arch_aarch64

View File

@ -4,6 +4,8 @@
#ifndef UNICORN_ARCH_POSTFIX
#define UNICORN_ARCH_POSTFIX _aarch64eb
#endif
#define uc_add_inline_hook uc_add_inline_hook_aarch64eb
#define uc_del_inline_hook uc_del_inline_hook_aarch64eb
#define tb_invalidate_phys_range tb_invalidate_phys_range_aarch64eb
#define use_idiv_instructions use_idiv_instructions_aarch64eb
#define arm_arch arm_arch_aarch64eb

View File

@ -1078,6 +1078,10 @@ void tcg_exec_init(struct uc_struct *uc, unsigned long tb_size)
/* Invalidate / Cache TBs */
uc->uc_invalidate_tb = uc_invalidate_tb;
uc->uc_gen_tb = uc_gen_tb;
/* Inline hooks optimization */
uc->add_inline_hook = uc_add_inline_hook;
uc->del_inline_hook = uc_del_inline_hook;
}
/* call with @p->lock held */

View File

@ -4,6 +4,8 @@
#ifndef UNICORN_ARCH_POSTFIX
#define UNICORN_ARCH_POSTFIX _arm
#endif
#define uc_add_inline_hook uc_add_inline_hook_arm
#define uc_del_inline_hook uc_del_inline_hook_arm
#define tb_invalidate_phys_range tb_invalidate_phys_range_arm
#define use_idiv_instructions use_idiv_instructions_arm
#define arm_arch arm_arch_arm

View File

@ -4,6 +4,8 @@
#ifndef UNICORN_ARCH_POSTFIX
#define UNICORN_ARCH_POSTFIX _armeb
#endif
#define uc_add_inline_hook uc_add_inline_hook_armeb
#define uc_del_inline_hook uc_del_inline_hook_armeb
#define tb_invalidate_phys_range tb_invalidate_phys_range_armeb
#define use_idiv_instructions use_idiv_instructions_armeb
#define arm_arch arm_arch_armeb

View File

@ -32,13 +32,41 @@
static inline void gen_uc_tracecode(TCGContext *tcg_ctx, int32_t size, int32_t type, void *uc, uint64_t pc)
{
TCGv_i32 tsize = tcg_const_i32(tcg_ctx, size);
TCGv_i32 ttype = tcg_const_i32(tcg_ctx, type);
TCGv_i32 ttype;
TCGv_ptr tuc = tcg_const_ptr(tcg_ctx, uc);
TCGv_i64 tpc = tcg_const_i64(tcg_ctx, pc);
gen_helper_uc_tracecode(tcg_ctx, tsize, ttype, tuc, tpc);
TCGv_ptr tdata;
uc_engine* puc = uc;
struct list_item *cur;
struct hook* hk;
TCGTemp* args[] = {
tcgv_ptr_temp(tcg_ctx, tuc),
tcgv_i64_temp(tcg_ctx, tpc),
tcgv_i32_temp(tcg_ctx, tsize),
0
};
if (puc->hooks_count[type] == 1) {
cur = puc->hook[type].head;
while (cur) {
hk = cur->data;
if (!hk->to_delete) {
tdata = tcg_const_ptr(tcg_ctx, hk->user_data);
args[3] = tcgv_ptr_temp(tcg_ctx, tdata);
puc->add_inline_hook(uc, hk, (void**)args, 4);
tcg_temp_free_ptr(tcg_ctx, tdata);
}
cur = cur->next;
}
} else {
ttype = tcg_const_i32(tcg_ctx, type);
gen_helper_uc_tracecode(tcg_ctx, tsize, ttype, tuc, tpc);
tcg_temp_free_i32(tcg_ctx, ttype);
}
tcg_temp_free_i64(tcg_ctx, tpc);
tcg_temp_free_ptr(tcg_ctx, tuc);
tcg_temp_free_i32(tcg_ctx, ttype);
tcg_temp_free_i32(tcg_ctx, tsize);
}

View File

@ -1561,4 +1561,7 @@ struct jit_code_entry {
uint64_t symfile_size;
};
void uc_del_inline_hook(uc_engine *uc, struct hook *hk);
void uc_add_inline_hook(uc_engine *uc, struct hook *hk, void** args, int args_len);
#endif /* TCG_H */

View File

@ -4,6 +4,8 @@
#ifndef UNICORN_ARCH_POSTFIX
#define UNICORN_ARCH_POSTFIX _m68k
#endif
#define uc_add_inline_hook uc_add_inline_hook_m68k
#define uc_del_inline_hook uc_del_inline_hook_m68k
#define tb_invalidate_phys_range tb_invalidate_phys_range_m68k
#define use_idiv_instructions use_idiv_instructions_m68k
#define arm_arch arm_arch_m68k

View File

@ -4,6 +4,8 @@
#ifndef UNICORN_ARCH_POSTFIX
#define UNICORN_ARCH_POSTFIX _mips
#endif
#define uc_add_inline_hook uc_add_inline_hook_mips
#define uc_del_inline_hook uc_del_inline_hook_mips
#define tb_invalidate_phys_range tb_invalidate_phys_range_mips
#define use_idiv_instructions use_idiv_instructions_mips
#define arm_arch arm_arch_mips

View File

@ -4,6 +4,8 @@
#ifndef UNICORN_ARCH_POSTFIX
#define UNICORN_ARCH_POSTFIX _mips64
#endif
#define uc_add_inline_hook uc_add_inline_hook_mips64
#define uc_del_inline_hook uc_del_inline_hook_mips64
#define tb_invalidate_phys_range tb_invalidate_phys_range_mips64
#define use_idiv_instructions use_idiv_instructions_mips64
#define arm_arch arm_arch_mips64

View File

@ -4,6 +4,8 @@
#ifndef UNICORN_ARCH_POSTFIX
#define UNICORN_ARCH_POSTFIX _mips64el
#endif
#define uc_add_inline_hook uc_add_inline_hook_mips64el
#define uc_del_inline_hook uc_del_inline_hook_mips64el
#define tb_invalidate_phys_range tb_invalidate_phys_range_mips64el
#define use_idiv_instructions use_idiv_instructions_mips64el
#define arm_arch arm_arch_mips64el

View File

@ -4,6 +4,8 @@
#ifndef UNICORN_ARCH_POSTFIX
#define UNICORN_ARCH_POSTFIX _mipsel
#endif
#define uc_add_inline_hook uc_add_inline_hook_mipsel
#define uc_del_inline_hook uc_del_inline_hook_mipsel
#define tb_invalidate_phys_range tb_invalidate_phys_range_mipsel
#define use_idiv_instructions use_idiv_instructions_mipsel
#define arm_arch arm_arch_mipsel

View File

@ -4,6 +4,8 @@
#ifndef UNICORN_ARCH_POSTFIX
#define UNICORN_ARCH_POSTFIX _ppc
#endif
#define uc_add_inline_hook uc_add_inline_hook_ppc
#define uc_del_inline_hook uc_del_inline_hook_ppc
#define tb_invalidate_phys_range tb_invalidate_phys_range_ppc
#define use_idiv_instructions use_idiv_instructions_ppc
#define arm_arch arm_arch_ppc

View File

@ -4,6 +4,8 @@
#ifndef UNICORN_ARCH_POSTFIX
#define UNICORN_ARCH_POSTFIX _ppc64
#endif
#define uc_add_inline_hook uc_add_inline_hook_ppc64
#define uc_del_inline_hook uc_del_inline_hook_ppc64
#define tb_invalidate_phys_range tb_invalidate_phys_range_ppc64
#define use_idiv_instructions use_idiv_instructions_ppc64
#define arm_arch arm_arch_ppc64

View File

@ -4,6 +4,8 @@
#ifndef UNICORN_ARCH_POSTFIX
#define UNICORN_ARCH_POSTFIX _riscv32
#endif
#define uc_add_inline_hook uc_add_inline_hook_riscv32
#define uc_del_inline_hook uc_del_inline_hook_riscv32
#define tb_invalidate_phys_range tb_invalidate_phys_range_riscv32
#define use_idiv_instructions use_idiv_instructions_riscv32
#define arm_arch arm_arch_riscv32

View File

@ -4,6 +4,8 @@
#ifndef UNICORN_ARCH_POSTFIX
#define UNICORN_ARCH_POSTFIX _riscv64
#endif
#define uc_add_inline_hook uc_add_inline_hook_riscv64
#define uc_del_inline_hook uc_del_inline_hook_riscv64
#define tb_invalidate_phys_range tb_invalidate_phys_range_riscv64
#define use_idiv_instructions use_idiv_instructions_riscv64
#define arm_arch arm_arch_riscv64

View File

@ -4,6 +4,8 @@
#ifndef UNICORN_ARCH_POSTFIX
#define UNICORN_ARCH_POSTFIX _sparc
#endif
#define uc_add_inline_hook uc_add_inline_hook_sparc
#define uc_del_inline_hook uc_del_inline_hook_sparc
#define tb_invalidate_phys_range tb_invalidate_phys_range_sparc
#define use_idiv_instructions use_idiv_instructions_sparc
#define arm_arch arm_arch_sparc

View File

@ -4,6 +4,8 @@
#ifndef UNICORN_ARCH_POSTFIX
#define UNICORN_ARCH_POSTFIX _sparc64
#endif
#define uc_add_inline_hook uc_add_inline_hook_sparc64
#define uc_del_inline_hook uc_del_inline_hook_sparc64
#define tb_invalidate_phys_range tb_invalidate_phys_range_sparc64
#define use_idiv_instructions use_idiv_instructions_sparc64
#define arm_arch arm_arch_sparc64

View File

@ -14420,7 +14420,10 @@ static void disas_a64_insn(CPUARMState *env, DisasContext *s)
// Unicorn: trace this instruction on request
if (HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_CODE, s->pc_curr)) {
// Sync PC in advance
TCGContext *tcg_ctx = env->uc->tcg_ctx;
gen_a64_set_pc_im(tcg_ctx, s->pc_curr);
gen_uc_tracecode(tcg_ctx, 4, UC_HOOK_CODE_IDX, env->uc, s->pc_curr);
// the callback might want to stop emulation immediately

View File

@ -10910,6 +10910,10 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
// Unicorn: trace this instruction on request
if (HOOK_EXISTS_BOUNDED(s->uc, UC_HOOK_CODE, s->pc_curr)) {
// Sync PC in advance
gen_set_pc_im(s, s->pc_curr);
gen_uc_tracecode(tcg_ctx, 4, UC_HOOK_CODE_IDX, s->uc, s->pc_curr);
// the callback might want to stop emulation immediately
check_exit_request(tcg_ctx);
@ -11538,6 +11542,10 @@ static void thumb_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
// Unicorn: trace this instruction on request
insn_size = is_16bit ? 2 : 4;
if (HOOK_EXISTS_BOUNDED(uc, UC_HOOK_CODE, dc->base.pc_next - insn_size)) {
// Sync PC in advance
gen_set_pc_im(dc, dc->base.pc_next - insn_size);
if (uc->no_exit_request) {
gen_uc_tracecode(tcg_ctx, insn_size, UC_HOOK_CODE_IDX | UC_HOOK_FLAG_NO_STOP, uc, dc->base.pc_next - insn_size);
} else {

View File

@ -4811,6 +4811,9 @@ static target_ulong disas_insn(DisasContext *s, CPUState *cpu)
s->last_cc_op = s->cc_op;
}
// Sync PC in advance
gen_jmp_im(s, pc_start);
// save the last operand
prev_op = tcg_last_op(tcg_ctx);
insn_hook = true;

View File

@ -6333,6 +6333,10 @@ static void m68k_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
// Unicorn: trace this instruction on request
if (HOOK_EXISTS_BOUNDED(uc, UC_HOOK_CODE, dc->pc)) {
// Sync PC in advance
tcg_gen_movi_i32(tcg_ctx, QREG_PC, dc->pc);
gen_uc_tracecode(tcg_ctx, 2, UC_HOOK_CODE_IDX, uc, dc->pc);
// the callback might want to stop emulation immediately
check_exit_request(tcg_ctx);

View File

@ -30941,6 +30941,10 @@ static void mips_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
// Unicorn: trace this instruction on request
if (HOOK_EXISTS_BOUNDED(uc, UC_HOOK_CODE, ctx->base.pc_next)) {
// Sync PC in advance
gen_save_pc(tcg_ctx, ctx->base.pc_next);
// save the last operand
prev_op = tcg_last_op(tcg_ctx);
hook_insn = true;

View File

@ -7633,6 +7633,10 @@ static void ppc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
// Unicorn: trace this instruction on request
if (HOOK_EXISTS_BOUNDED(uc, UC_HOOK_CODE, ctx->base.pc_next)) {
// Sypc PC in advance
gen_update_nip(ctx, ctx->base.pc_next);
gen_uc_tracecode(tcg_ctx, 4, UC_HOOK_CODE_IDX, uc, ctx->base.pc_next);
// the callback might want to stop emulation immediately
check_exit_request(tcg_ctx);

View File

@ -856,6 +856,10 @@ static void riscv_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
} else {
// Unicorn: trace this instruction on request
if (HOOK_EXISTS_BOUNDED(uc, UC_HOOK_CODE, ctx->base.pc_next)) {
// Sync PC in advance
tcg_gen_movi_tl(tcg_ctx, tcg_ctx->cpu_pc, ctx->base.pc_next);
// save the last operand
prev_op = tcg_last_op(tcg_ctx);
insn_hook = true;

View File

@ -5961,6 +5961,10 @@ static void sparc_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
// Unicorn: trace this instruction on request
if (HOOK_EXISTS_BOUNDED(uc, UC_HOOK_CODE, dc->pc)) {
// Sync PC in advance
tcg_gen_movi_tl(tcg_ctx, tcg_ctx->cpu_pc, dc->pc);
gen_uc_tracecode(tcg_ctx, 4, UC_HOOK_CODE_IDX, uc, dc->pc);
// the callback might want to stop emulation immediately
check_exit_request(tcg_ctx);

View File

@ -662,6 +662,54 @@ static void process_op_defs(TCGContext *s);
static TCGTemp *tcg_global_reg_new_internal(TCGContext *s, TCGType type,
TCGReg reg, const char *name);
void uc_add_inline_hook(uc_engine *uc, struct hook *hk, void** args, int args_len)
{
TCGHelperInfo* info = g_malloc(sizeof(TCGHelperInfo));
char *name = g_malloc(64);
unsigned sizemask = 0xFFFFFFFF;
TCGContext *tcg_ctx = uc->tcg_ctx;
GHashTable *helper_table = uc->tcg_ctx->helper_table;
info->func = hk->callback;
info->name = name;
info->flags = 0; // From helper-head.h
// Only UC_HOOK_BLOCK and UC_HOOK_CODE is generated into tcg code and can be inlined.
switch (hk->type) {
case UC_HOOK_BLOCK:
case UC_HOOK_CODE:
// (*uc_cb_hookcode_t)(uc_engine *uc, uint64_t address, uint32_t size, void *user_data);
sizemask = dh_sizemask(void, 0) | dh_sizemask(i64, 1) | dh_sizemask(i32, 2) | dh_sizemask(void, 3);
snprintf(name, 63, "hookcode_%d_%" PRIx64 , hk->type, (uint64_t)hk->callback);
break;
default:
break;
}
name[63] = 0;
info->name = name;
info->sizemask = sizemask;
g_hash_table_insert(helper_table, (gpointer)info->func, (gpointer)info);
tcg_gen_callN(tcg_ctx, info->func, NULL, args_len, (TCGTemp**)args);
}
void uc_del_inline_hook(uc_engine *uc, struct hook *hk)
{
GHashTable *helper_table = uc->tcg_ctx->helper_table;
TCGHelperInfo* info = g_hash_table_lookup(helper_table, hk->callback);
if (info) {
g_hash_table_remove(helper_table, info);
g_free((gpointer)info->name);
g_free(info);
}
}
void tcg_context_init(TCGContext *s)
{
int op, total_args, n, i;

View File

@ -4,6 +4,8 @@
#ifndef UNICORN_ARCH_POSTFIX
#define UNICORN_ARCH_POSTFIX _x86_64
#endif
#define uc_add_inline_hook uc_add_inline_hook_x86_64
#define uc_del_inline_hook uc_del_inline_hook_x86_64
#define tb_invalidate_phys_range tb_invalidate_phys_range_x86_64
#define use_idiv_instructions use_idiv_instructions_x86_64
#define arm_arch arm_arch_x86_64

View File

@ -4,6 +4,8 @@ CMD_PATH=$(realpath $0)
SOURCE_DIR=$(dirname ${CMD_PATH})
COMMON_SYMBOLS="
uc_add_inline_hook \
uc_del_inline_hook \
tb_invalidate_phys_range \
use_idiv_instructions \
arm_arch \

12
uc.c
View File

@ -664,6 +664,7 @@ static void clear_deleted_hooks(uc_engine *uc)
for (i = 0; i < UC_HOOK_MAX; i++) {
if (list_remove(&uc->hook[i], (void *)hook)) {
if (--hook->refs == 0) {
uc->del_inline_hook(uc, hook);
free(hook);
}
@ -1421,6 +1422,7 @@ uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback,
}
}
uc->hooks_count[UC_HOOK_INSN_IDX]++;
hook->refs++;
return UC_ERR_OK;
}
@ -1452,6 +1454,7 @@ uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback,
}
}
uc->hooks_count[UC_HOOK_TCG_OPCODE_IDX]++;
hook->refs++;
return UC_ERR_OK;
}
@ -1475,6 +1478,7 @@ uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback,
return UC_ERR_NOMEM;
}
}
uc->hooks_count[i]++;
hook->refs++;
}
}
@ -1506,6 +1510,7 @@ uc_err uc_hook_del(uc_engine *uc, uc_hook hh)
for (i = 0; i < UC_HOOK_MAX; i++) {
if (list_exists(&uc->hook[i], (void *)hook)) {
hook->to_delete = true;
uc->hooks_count[i]--;
list_append(&uc->hooks_to_del, hook);
}
}
@ -1562,10 +1567,11 @@ void helper_uc_tracecode(int32_t size, uc_hook_idx index, void *handle,
index = index & UC_HOOK_IDX_MASK;
// This has been done in tcg code.
// sync PC in CPUArchState with address
if (uc->set_pc) {
uc->set_pc(uc, address);
}
// if (uc->set_pc) {
// uc->set_pc(uc, address);
// }
// the last callback may already asked to stop emulation
if (uc->stop_request && !(hook_flags & UC_HOOK_FLAG_NO_STOP)) {