mirror of
https://github.com/radareorg/radare2.git
synced 2024-12-01 00:51:19 +00:00
347 lines
11 KiB
C
347 lines
11 KiB
C
/* radare2 - LGPL - Copyright 2022-2023 - pancake */
|
|
|
|
#ifndef R_ESIL_H
|
|
#define R_ESIL_H
|
|
|
|
#include <r_reg.h>
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#define esilprintf(op, fmt, ...) r_strbuf_setf (&op->esil, fmt, ##__VA_ARGS__)
|
|
// only flags that affect control flow
|
|
enum {
|
|
R_ESIL_FLAG_ZERO = 1,
|
|
R_ESIL_FLAG_CARRY = 2,
|
|
R_ESIL_FLAG_OVERFLOW = 4,
|
|
R_ESIL_FLAG_PARITY = 8,
|
|
R_ESIL_FLAG_SIGN = 16,
|
|
// ...
|
|
};
|
|
|
|
#define ESIL_INTERNAL_PREFIX '$'
|
|
#define ESIL_STACK_NAME "esil.ram"
|
|
enum {
|
|
R_ESIL_OP_TYPE_UNKNOWN = 0x1,
|
|
R_ESIL_OP_TYPE_CONTROL_FLOW,
|
|
R_ESIL_OP_TYPE_MEM_READ = 0x4,
|
|
R_ESIL_OP_TYPE_MEM_WRITE = 0x8,
|
|
R_ESIL_OP_TYPE_REG_WRITE = 0x10,
|
|
R_ESIL_OP_TYPE_MATH = 0x20,
|
|
R_ESIL_OP_TYPE_CUSTOM = 0x40
|
|
};
|
|
|
|
// this is 80-bit offsets so we can address every piece of esil in an instruction
|
|
typedef struct r_esil_expr_offset_t {
|
|
ut64 off;
|
|
ut16 idx;
|
|
} REsilEOffset;
|
|
|
|
typedef enum {
|
|
R_ESIL_BLOCK_ENTER_NORMAL = 0,
|
|
R_ESIL_BLOCK_ENTER_TRUE,
|
|
R_ESIL_BLOCK_ENTER_FALSE,
|
|
R_ESIL_BLOCK_ENTER_GLUE,
|
|
} REsilBlockEnterType;
|
|
|
|
typedef struct r_esil_basic_block_t {
|
|
REsilEOffset first;
|
|
REsilEOffset last;
|
|
char *expr; //synthesized esil-expression for this block
|
|
REsilBlockEnterType enter; //maybe more type is needed here
|
|
} REsilBB;
|
|
|
|
typedef struct r_esil_t ESIL;
|
|
|
|
typedef bool (*REsilHandlerCB)(ESIL *esil, ut32 h, void *user);
|
|
|
|
typedef struct r_esil_handler_t {
|
|
REsilHandlerCB cb;
|
|
void *user;
|
|
} REsilHandler;
|
|
|
|
typedef struct r_esil_change_reg_t {
|
|
int idx;
|
|
ut64 data;
|
|
} REsilRegChange;
|
|
|
|
typedef struct r_esil_change_mem_t {
|
|
int idx;
|
|
ut8 data;
|
|
} REsilMemChange;
|
|
|
|
typedef struct r_esil_trace_t {
|
|
int idx;
|
|
int end_idx;
|
|
HtUP *registers;
|
|
HtUP *memory;
|
|
RRegArena *arena[R_REG_TYPE_LAST];
|
|
ut64 stack_addr;
|
|
ut64 stack_size;
|
|
ut8 *stack_data;
|
|
//TODO remove `db` and reuse info above
|
|
Sdb *db;
|
|
} REsilTrace;
|
|
|
|
typedef bool (*REsilHookRegWriteCB)(ESIL *esil, const char *name, ut64 *val);
|
|
|
|
typedef struct r_esil_callbacks_t {
|
|
void *user;
|
|
/* callbacks */
|
|
bool (*hook_flag_read)(ESIL *esil, const char *flag, ut64 *num);
|
|
bool (*hook_command)(ESIL *esil, const char *op);
|
|
bool (*hook_mem_read)(ESIL *esil, ut64 addr, ut8 *buf, int len);
|
|
bool (*mem_read)(ESIL *esil, ut64 addr, ut8 *buf, int len);
|
|
bool (*hook_mem_write)(ESIL *esil, ut64 addr, const ut8 *buf, int len);
|
|
bool (*mem_write)(ESIL *esil, ut64 addr, const ut8 *buf, int len);
|
|
bool (*hook_reg_read)(ESIL *esil, const char *name, ut64 *res, int *size);
|
|
bool (*reg_read)(ESIL *esil, const char *name, ut64 *res, int *size);
|
|
REsilHookRegWriteCB hook_reg_write;
|
|
bool (*reg_write)(ESIL *esil, const char *name, ut64 val);
|
|
} REsilCallbacks;
|
|
|
|
#if R2_590
|
|
typedef struct r_esil_options_t {
|
|
int nowrite;
|
|
int iotrap;
|
|
int exectrap;
|
|
} REsilOptions;
|
|
#endif
|
|
|
|
typedef struct r_esil_t {
|
|
struct r_anal_t *anal; // XXX maybe just use arch?
|
|
char **stack;
|
|
ut64 addrmask;
|
|
int stacksize;
|
|
int stackptr;
|
|
ut32 skip;
|
|
int nowrite;
|
|
int iotrap;
|
|
int exectrap;
|
|
int parse_stop;
|
|
int parse_goto;
|
|
int parse_goto_count;
|
|
int verbose;
|
|
ut64 flags;
|
|
ut64 address;
|
|
ut64 stack_addr;
|
|
ut32 stack_size;
|
|
int delay; // mapped to $ds in ESIL
|
|
ut64 jump_target; // mapped to $jt in ESIL
|
|
int jump_target_set; // mapped to $js in ESIL
|
|
int trap;
|
|
int data_align;
|
|
ut32 trap_code; // extend into a struct to store more exception info?
|
|
// parity flag? done with cur
|
|
ut64 old; //used for carry-flagging and borrow-flagging
|
|
ut64 cur; //used for carry-flagging and borrow-flagging
|
|
ut8 lastsz; //in bits //used for signature-flag
|
|
/* native ops and custom ops */
|
|
HtPP *ops;
|
|
char *current_opstr;
|
|
SdbMini *interrupts;
|
|
SdbMini *syscalls;
|
|
//this is a disgusting workaround, because we have no ht-like storage without magic keys, that you cannot use, with int-keys
|
|
REsilHandler *intr0;
|
|
REsilHandler *sysc0;
|
|
RList *plugins;
|
|
RList *active_plugins;
|
|
/* deep esil parsing fills this */
|
|
Sdb *stats;
|
|
REsilTrace *trace;
|
|
REsilCallbacks cb;
|
|
#if 0
|
|
struct r_anal_reil_t *Reil;
|
|
#endif
|
|
char *pending; // pending op computed as a macro
|
|
// this is so cursed, can we please remove external commands from esil internals.
|
|
// Function pointers are fine, but not commands
|
|
char *cmd_step; // r2 (external) command to run before a step is performed
|
|
char *cmd_step_out; // r2 (external) command to run after a step is performed
|
|
char *cmd_intr; // r2 (external) command to run when an interrupt occurs
|
|
char *cmd_trap; // r2 (external) command to run when a trap occurs
|
|
char *cmd_mdev; // r2 (external) command to run when an memory mapped device address is used
|
|
char *cmd_todo; // r2 (external) command to run when esil expr contains TODO
|
|
char *cmd_ioer; // r2 (external) command to run when esil fails to IO
|
|
char *mdev_range; // string containing the r_str_range to match for read/write accesses
|
|
bool (*cmd)(ESIL *esil, const char *name, ut64 a0, ut64 a1);
|
|
void *user;
|
|
int stack_fd; // ahem, let's not do this
|
|
bool in_cmd_step;
|
|
} REsil;
|
|
|
|
enum {
|
|
R_ESIL_PARM_INVALID = 0,
|
|
R_ESIL_PARM_REG,
|
|
R_ESIL_PARM_NUM,
|
|
};
|
|
|
|
typedef struct r_anal_ref_char_t {
|
|
char *str;
|
|
char *cols;
|
|
} RAnalRefStr;
|
|
|
|
#if 0
|
|
|
|
/* reil -- must be deprecated */
|
|
/* Constructs to convert from ESIL to REIL */
|
|
#define FOREACHOP(GENERATE) \
|
|
/* No Operation */ GENERATE(NOP) \
|
|
/* Unknown/Undefined */ GENERATE(UNK) \
|
|
/* Conditional Jump */ GENERATE(JCC) \
|
|
/* Store Value to register */ GENERATE(STR) \
|
|
/* Store value to memory */ GENERATE(STM) \
|
|
/* Load value from memory */ GENERATE(LDM) \
|
|
/* Addition */ GENERATE(ADD) \
|
|
/* Subtraction */ GENERATE(SUB) \
|
|
/* Negation */ GENERATE(NEG) \
|
|
/* Multiplication */ GENERATE(MUL) \
|
|
/* Division */ GENERATE(DIV) \
|
|
/* Modulo */ GENERATE(MOD) \
|
|
/* Signed Multiplication */ GENERATE(SMUL) \
|
|
/* Sugned Division */ GENERATE(SDIV) \
|
|
/* Signed Modulus */ GENERATE(SMOD) \
|
|
/* Shift Left */ GENERATE(SHL) \
|
|
/* Shift Right */ GENERATE(SHR) \
|
|
/* Binary and */ GENERATE(AND) \
|
|
/* Binary or */ GENERATE(OR) \
|
|
/* Binary xor */ GENERATE(XOR) \
|
|
/* Binary not */ GENERATE(NOT) \
|
|
/* Equation */ GENERATE(EQ) \
|
|
/* Less Than */ GENERATE(LT)
|
|
|
|
#define MAKE_ENUM(OP) REIL_##OP,
|
|
#define REIL_OP_STRING(STRING) #STRING,
|
|
|
|
typedef enum {
|
|
FOREACHOP(MAKE_ENUM)
|
|
} RAnalReilOpcode;
|
|
|
|
typedef enum {
|
|
ARG_REG, // CPU Register
|
|
ARG_TEMP, // Temporary register used by REIL
|
|
ARG_CONST, // Constant value
|
|
ARG_ESIL_INTERNAL, // Used to resolve ESIL internal flags
|
|
ARG_NONE // Operand not used by the instruction
|
|
} RAnalReilArgType;
|
|
|
|
// Arguments to a REIL instruction.
|
|
typedef struct r_anal_reil_arg {
|
|
RAnalReilArgType type; // Type of the argument
|
|
ut8 size; // Size of the argument in bytes
|
|
char name[32]; // Name of the argument
|
|
} RAnalReilArg;
|
|
|
|
// Instruction arg1, arg2, arg3
|
|
typedef struct r_anal_reil_inst_t {
|
|
RAnalReilOpcode opcode;
|
|
RAnalReilArg *arg[3];
|
|
} RAnalReilInst;
|
|
|
|
typedef struct r_anal_reil_t {
|
|
char old[32]; // Used to compute flags.
|
|
char cur[32];
|
|
ut8 lastsz;
|
|
ut64 reilNextTemp; // Used to store the index of the next REIL temp register to be used.
|
|
ut64 addr; // Used for instruction sequencing. Check esil2reil.c for details.
|
|
ut8 seq_num; // Incremented and used when noInc is set to 1.
|
|
int skip;
|
|
int cmd_count;
|
|
char if_buf[64];
|
|
char pc[8];
|
|
} RAnalReil;
|
|
#endif
|
|
|
|
typedef struct r_esil_plugin_t {
|
|
char *name;
|
|
char *desc;
|
|
char *license;
|
|
char *arch;
|
|
char *author;
|
|
char *version;
|
|
void *(*init)(REsil *esil); // can allocate stuff and return that
|
|
void (*fini)(REsil *esil, void *user); // deallocates allocated things from init
|
|
} REsilPlugin;
|
|
|
|
// Some kind of container, pointer to plugin + pointer to user
|
|
typedef struct r_esil_active_plugin_t {
|
|
REsilPlugin *plugin;
|
|
void *user;
|
|
} REsilActivePlugin;
|
|
|
|
R_API REsil *r_esil_new(int stacksize, int iotrap, unsigned int addrsize);
|
|
R_API bool r_esil_set_pc(REsil *esil, ut64 addr);
|
|
R_API bool r_esil_setup(REsil *esil, struct r_anal_t *anal, int romem, int stats, int nonull);
|
|
R_API void r_esil_setup_macros(REsil *esil);
|
|
R_API void r_esil_setup_ops(REsil *esil);
|
|
R_API void r_esil_free(REsil *esil);
|
|
R_API bool r_esil_runword(REsil *esil, const char *word);
|
|
R_API bool r_esil_parse(REsil *esil, const char *str);
|
|
R_API bool r_esil_dumpstack(REsil *esil);
|
|
R_API bool r_esil_mem_read(REsil *esil, ut64 addr, ut8 *buf, int len);
|
|
R_API bool r_esil_mem_write(REsil *esil, ut64 addr, const ut8 *buf, int len);
|
|
R_API bool r_esil_reg_read(REsil *esil, const char *regname, ut64 *num, int *size);
|
|
R_API bool r_esil_reg_write(REsil *esil, const char *dst, ut64 num);
|
|
R_API bool r_esil_pushnum(REsil *esil, ut64 num);
|
|
R_API bool r_esil_push(REsil *esil, const char *str);
|
|
#if R2_590
|
|
R_API const char *r_esil_pop(REsil *esil);
|
|
#else
|
|
R_API char *r_esil_pop(REsil *esil);
|
|
#endif
|
|
typedef bool (*REsilOpCb)(REsil *esil);
|
|
|
|
typedef struct r_esil_operation_t {
|
|
REsilOpCb code;
|
|
ut32 push; // amount of operands pushed
|
|
ut32 pop; // amount of operands popped
|
|
ut32 type;
|
|
} REsilOp;
|
|
|
|
R_API bool r_esil_set_op(REsil *esil, const char *op, REsilOpCb code, ut32 push, ut32 pop, ut32 type);
|
|
R_API REsilOp *r_esil_get_op(REsil *esil, const char *op);
|
|
R_API void r_esil_del_op(REsil *esil, const char *op);
|
|
R_API void r_esil_stack_free(REsil *esil);
|
|
R_API int r_esil_get_parm_type(REsil *esil, const char *str);
|
|
R_API int r_esil_get_parm(REsil *esil, const char *str, ut64 *num);
|
|
R_API int r_esil_condition(REsil *esil, const char *str);
|
|
|
|
// esil_handler.c
|
|
R_API void r_esil_handlers_init(REsil *esil);
|
|
R_API bool r_esil_set_interrupt(REsil *esil, ut32 intr_num, REsilHandlerCB cb, void *user);
|
|
R_API REsilHandlerCB r_esil_get_interrupt(REsil *esil, ut32 intr_num);
|
|
R_API void r_esil_del_interrupt(REsil *esil, ut32 intr_num);
|
|
R_API bool r_esil_set_syscall(REsil *esil, ut32 sysc_num, REsilHandlerCB cb, void *user);
|
|
R_API REsilHandlerCB r_esil_get_syscall(REsil *esil, ut32 sysc_num);
|
|
R_API void r_esil_del_syscall(REsil *esil, ut32 sysc_num);
|
|
R_API int r_esil_fire_interrupt(REsil *esil, ut32 intr_num);
|
|
R_API int r_esil_do_syscall(REsil *esil, ut32 sysc_num);
|
|
R_API void r_esil_handlers_fini(REsil *esil);
|
|
|
|
// esil_plugin.c
|
|
R_API void r_esil_plugins_init(REsil *esil);
|
|
R_API void r_esil_plugins_fini(REsil *esil);
|
|
R_API bool r_esil_plugin_add(REsil *esil, REsilPlugin *plugin);
|
|
R_API bool r_esil_plugin_activate(REsil *esil, const char *name);
|
|
R_API void r_esil_plugin_deactivate(REsil *esil, const char *name);
|
|
|
|
R_API void r_esil_mem_ro(REsil *esil, int mem_readonly);
|
|
R_API void r_esil_stats(REsil *esil, int enable);
|
|
|
|
/* trace */
|
|
R_API REsilTrace *r_esil_trace_new(REsil *esil);
|
|
R_API void r_esil_trace_free(REsilTrace *trace);
|
|
R_API void r_esil_trace_op(REsil *esil, RAnalOp *op);
|
|
R_API void r_esil_trace_list(REsil *esil);
|
|
R_API void r_esil_trace_show(REsil *esil, int idx);
|
|
R_API void r_esil_trace_restore(REsil *esil, int idx);
|
|
|
|
extern REsilPlugin r_esil_plugin_dummy;
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|