Improve aesue feedback and add tests ##esil

This commit is contained in:
pancake 2023-07-11 19:04:06 +02:00
parent 8c447c7129
commit b09ebceba4
3 changed files with 58 additions and 38 deletions

View File

@ -7,7 +7,7 @@ These strings can be evaluated in order to emulate code.
Each element of an esil expression is separated by a comma. The VM can be described as this:
while ((word=haveCommand())) {
while ((word = haveCommand())) {
if (word.isKeyword()) {
esilCommands[word](esil);
} else {
@ -130,8 +130,7 @@ As discussed on irc, current implementation works like this:
This approach is more readable, but it's less stack-friendly
Special instructions
====================
# Special instructions
NOPs are represented as empty strings. Unknown or invalid instructions
@ -143,8 +142,7 @@ Traps are implemented with the `<trap>,<code>,$$` command. They are used to
throw exceptions like invalid instructions, division by zero, memory read
error, etc.
Quick analysis
==============
# Quick analysis
Here's a list of some quick checks to retrieve information from an esil string.
Relevant information will be probably found in the first expression of the
@ -165,7 +163,7 @@ list.
indexOf("LOOP") -> is a loop (rep?)
equalsTo("") -> empty string, means: nop (wrong, if we append pc+=x)
Common operations:
## Common operations:
* Check dstreg
* Check srcreg
@ -175,13 +173,11 @@ Common operations:
* Evulate
* Is syscall
CPU Flags
=========
# CPU Flags
CPU flags are usually defined as 1 bit registers in the RReg profile. and sometimes under the 'flg' register type.
ESIL Flags
==========
# ESIL Flags
ESIL VM have an internal state flags that can are read only and can be used to
export those values to the underlying CPU flags. This is because the ESIL vm
@ -198,8 +194,7 @@ p - parity
r - regsize ( asm.bits/8 )
```
Variables
=========
# Variables
1. No predefined bitness (should be easy to extend them to 128,256 and 512bits, e.g. for MMX, SSE, AVX, Neon)
2. Infinite number (for SSA-form compatibility)
@ -207,12 +202,12 @@ Variables
4. Numbers can be specified in any base supported by RNum (dec, hex, oct, binary ...)
5. Each ESIL backend should have an associated RReg profile to describe the esil register specs
Bitarrays
=========
# Bitarrays
What to do with them? What about bit arithmetic if use variables instead of registers?
Arithmetic
===========
# Arithmetic
1. ADD ("+")
2. MUL ("*")
3. SUB ("-")
@ -220,8 +215,8 @@ Arithmetic
5. MOD ("%")
Bit arithmetic
===============
# Bit arithmetic
1. AND "&"
2. OR "|"
3. XOR "^"
@ -231,8 +226,7 @@ Bit arithmetic
7. ROR ">>>"
8. NEG "!"
Floating point
==============
# Floating point
_TODO_
@ -252,15 +246,15 @@ take care to not reuse any of the following:
Usage example:
### rep cmpsb
---------
ecx,!,?{,BREAK,},edi,[1],esi,[1],==,$z,zf,:=,8,$b,cf,:=,$p,pf,:=,7,$s,sf,:=,edi,[1],0x80,-,!,7,$o,^,of,:=,3,$b,af,:=,df,?{,1,edi,-=,1,esi,-=,}{,1,edi,+=,1,esi,+=,},ecx,--=,zf,!,?{,BREAK,},0,GOTO
```
ecx,!,?{,BREAK,},edi,[1],esi,[1],==,$z,zf,:=,8,$b,cf,:=,$p,pf,:=,7,$s,sf,:=,edi,[1],0x80,-,!,7,$o,^,of,:=,3,$b,af,:=,df,?{,1,edi,-=,1,esi,-=,}{,1,edi,+=,1,esi,+=,},ecx,--=,zf,!,?{,BREAK,},0,GOTO
```
## Executing r2 commands
## Unimplemented/unhandled instructions
====================================
Those are expressed with the 'TODO' command. which acts as a 'BREAK', but
displaying a warning message describing which instruction is not implemented
@ -270,8 +264,7 @@ For example:
fmulp ST(1), ST(0) => TODO,fmulp ST(1),ST(0)
Disassembly example:
====================
## Disassembly example:
```
[0x1000010f8]> e asm.esil=true
@ -301,8 +294,7 @@ Disassembly example:
│ │││ 0x100001147 48394a38 rdx,56,+,[8],rcx,==,cz,?=
```
Radare anal ESIL code example
==============================
# Radare anal ESIL code example
As an example implementation of ESIL analysis for the AVR family of
microcontrollers there is a `avr_op` function in `/libr/arch/p/avr/plugin.c`
@ -336,8 +328,7 @@ Looking at other architectures which already have mature ESIL support such as
x86 can help in understanding the syntax and conventions of radare's ESIL.
Introspection
=============
# Introspection
To ease esil parsing we should have a way to express introspection expressions
to extract the data we want. For example. We want to get the target address of
@ -360,8 +351,7 @@ expressions to get:
- all regs modified (write)
- all regs accessed (read)
API HOOKS
=========
# API HOOKS
It is important for emulation to be able to setup hooks in the parser, so we
can extend the parser to implement the analysis without having to write the

View File

@ -5963,7 +5963,8 @@ R_API int r_core_esil_step(RCore *core, ut64 until_addr, const char *until_expr,
startTime = r_time_now_mono ();
}
r_cons_break_push (NULL, NULL);
for (; ; r_anal_op_fini (&op)) {
for (; true; r_anal_op_fini (&op)) {
R_LOG_DEBUG ("esil step at 0x%08"PFMT64x, addr);
if (r_cons_is_breaked ()) {
R_LOG_INFO ("[+] ESIL emulation interrupted at 0x%08" PFMT64x, addr);
return_tail (0);
@ -6012,6 +6013,7 @@ R_API int r_core_esil_step(RCore *core, ut64 until_addr, const char *until_expr,
r_core_cmd0 (core, pincmd);
ut64 pc = r_reg_getv (core->anal->reg, pcname);
if (addr != pc) {
eprintf ("pincmd fail\n");
return_tail (1);
}
}
@ -6022,7 +6024,7 @@ R_API int r_core_esil_step(RCore *core, ut64 until_addr, const char *until_expr,
esil->cmd (esil, esil->cmd_trap, addr, R_ANAL_TRAP_UNALIGNED);
}
if (breakoninvalid) {
r_cons_printf ("[ESIL] Stopped execution in an unaligned instruction (see e??esil.breakoninvalid)\n");
R_LOG_INFO ("Execution stopped on unaligned instruction (see e?esil.breakoninvalid)");
return_tail (0);
}
}
@ -6038,7 +6040,7 @@ R_API int r_core_esil_step(RCore *core, ut64 until_addr, const char *until_expr,
esil->cmd (esil, esil->cmd_trap, addr, R_ANAL_TRAP_INVALID);
}
if (breakoninvalid) {
R_LOG_INFO ("[ESIL] Stopped execution in an invalid instruction (see e??esil.breakoninvalid)");
R_LOG_INFO ("Stopped execution in an invalid instruction (see e??esil.breakoninvalid)");
return_tail (0);
}
op.size = 1; // avoid inverted stepping
@ -6061,6 +6063,7 @@ R_API int r_core_esil_step(RCore *core, ut64 until_addr, const char *until_expr,
r_reg_setv (core->anal->reg, pcname, op.addr + op.size);
r_reg_setv (core->dbg->reg, pcname, op.addr + op.size);
}
eprintf ("blaaa\n");
return_tail (1);
}
}
@ -6092,6 +6095,13 @@ R_API int r_core_esil_step(RCore *core, ut64 until_addr, const char *until_expr,
core->dbg->reg = reg;
} else if (R_STR_ISNOTEMPTY (e)) {
r_esil_parse (esil, e);
if (esil->trap) {
R_LOG_WARN ("ESIL TRAP ON %s at 0x%08"PFMT64x, e,addr );
if (r_config_get_b (core->config, "esil.exectrap")) {
R_LOG_INFO ("ESIL TRAP ignored");
esil->trap = false;
}
}
#if 0
// XXX thats not related to arch plugins, and wonder if its useful at all or we want it as part of the anal or esil plugs
if (core->anal->cur && core->anal->cur->esil_post_loop) {
@ -6139,6 +6149,7 @@ R_API int r_core_esil_step(RCore *core, ut64 until_addr, const char *until_expr,
const char *e = R_STRBUF_SAFEGET (&op2.esil);
if (R_STR_ISNOTEMPTY (e)) {
r_esil_parse (esil, e);
esil->trap = false; // ignore traps on delayed instructions for now
}
} else {
R_LOG_ERROR ("Invalid instruction at 0x%08"PFMT64x, naddr);
@ -6167,7 +6178,7 @@ R_API int r_core_esil_step(RCore *core, ut64 until_addr, const char *until_expr,
}
// check breakpoints
if (r_bp_get_at (core->dbg->bp, pc)) {
r_cons_printf ("[ESIL] hit breakpoint at 0x%"PFMT64x "\n", pc);
R_LOG_INFO ("esil breakpoint hit at 0x%"PFMT64x, pc);
return_tail (0);
}
// check addr
@ -6177,15 +6188,19 @@ R_API int r_core_esil_step(RCore *core, ut64 until_addr, const char *until_expr,
}
continue;
}
#if 1
if (esil->trap) {
R_LOG_DEBUG ("TRAP");
R_LOG_INFO ("TRAP");
return_tail (0);
}
#endif
if (until_expr) {
// eprintf ("CHK %s\n", until_expr);
if (r_esil_condition (esil, until_expr)) {
R_LOG_DEBUG ("ESIL BREAK!");
R_LOG_INFO ("ESIL BREAK!");
return_tail (0);
}
esil->trap = false;
continue;
}
break;
@ -7609,7 +7624,7 @@ static void cmd_anal_esil(RCore *core, const char *input, bool verbose) {
r_core_cmd_help_match (core, help_msg_aes, "aesu", true);
} else switch (input[2]) {
case 'e': // "aesue"
until_expr = input + 3;
until_expr = r_str_trim_head_ro (input + 3);
break;
case ' ': // "aesu"
until_addr = r_num_math (core->num, input + 2);

View File

@ -597,3 +597,18 @@ EXPECT=<<EOF
0x00000000000000000000000000000001
EOF
RUN
NAME=step until esil
FILE=bins/mach0/ls-m1
ARGS=-a arm -b 64
CMDS=<<EOF
aeim
ar?pc
aesue pc,0x100003ad0,==,$z
ar?pc
EOF
EXPECT=<<EOF
0x100003a90
0x100003ad0
EOF
RUN