Add IL lifting testing to rz-test

This commit is contained in:
Florian Märkl 2022-01-10 17:15:02 +01:00
parent cd938d2083
commit 7e36f4bd38
8 changed files with 115 additions and 8 deletions

View file

@ -266,6 +266,7 @@ RZ_API void rz_test_asm_test_free(RzAsmTest *test) {
}
free(test->disasm);
free(test->bytes);
free(test->il);
free(test);
}
@ -343,6 +344,7 @@ RZ_API RzPVector *rz_test_load_asm_test_file(RzStrConstPool *strpool, const char
continue;
}
// mode flags
int mode = 0;
while (*line && *line != ' ') {
switch (*line) {
@ -369,6 +371,7 @@ RZ_API RzPVector *rz_test_load_asm_test_file(RzStrConstPool *strpool, const char
continue;
}
// disasm
char *disasm = strchr(line, '"');
if (!disasm) {
eprintf(LINEFMT "Error: Expected \" to begin disassembly.\n", file, linenum);
@ -384,14 +387,30 @@ RZ_API RzPVector *rz_test_load_asm_test_file(RzStrConstPool *strpool, const char
hex++;
rz_str_trim(disasm);
// hex
while (*hex && *hex == ' ') {
hex++;
}
// remove comment at the end of the line
char *latecmt = strchr(hex, '#');
if (latecmt) {
*latecmt = '\0';
}
// offset (optional)
char *offset = strchr(hex, ' ');
char *il = NULL;
if (offset) {
*offset = '\0';
offset++;
// IL (optional, the entire rest)
il = strchr(offset, ' ');
if (il) {
*il = '\0';
il++;
}
}
size_t hexlen = strlen(hex);
@ -425,10 +444,17 @@ RZ_API RzPVector *rz_test_load_asm_test_file(RzStrConstPool *strpool, const char
test->arch = arch;
test->cpu = cpu;
test->mode = mode;
test->offset = offset ? (ut64)strtoull(offset, NULL, 0) : 0;
char *endptr = NULL;
test->offset = offset ? (ut64)strtoull(offset, &endptr, 0) : 0;
if (endptr && *endptr) {
eprintf(LINEFMT "Error: Invalid offset string: \"%s\"\n", file, linenum, offset);
free(bytes);
goto fail;
}
test->disasm = strdup(disasm);
test->bytes = bytes;
test->bytes_size = (size_t)bytesz;
test->il = il ? strdup(il) : NULL;
rz_pvector_push(ret, test);
} while ((line = nextline));

View file

@ -353,6 +353,31 @@ RZ_API RzAsmTestOutput *rz_test_run_asm_test(RzTestRunConfig *config, RzAsmTest
rz_pvector_pop(&args);
rz_subprocess_free(proc);
}
if (test->il) {
char *hex = rz_hex_bin2strdup(test->bytes, test->bytes_size);
if (!hex) {
goto beach;
}
rz_pvector_push(&args, "-I");
rz_pvector_push(&args, hex);
RzSubprocess *proc = rz_subprocess_start(config->rz_asm_cmd, args.v.a, rz_pvector_len(&args), NULL, NULL, 0);
if (rz_subprocess_wait(proc, config->timeout_ms) == RZ_SUBPROCESS_TIMEDOUT) {
rz_subprocess_kill(proc);
out->il_timeout = true;
} else {
char *il = (char *)remove_cr(rz_subprocess_out(proc, NULL));
rz_str_trim(il);
char *il_err = (char *)remove_cr(rz_subprocess_err(proc, NULL));
rz_str_trim(il_err);
out->il = il;
out->il_report = il_err;
out->il_failed = rz_subprocess_ret(proc) != 0;
}
free(hex);
rz_pvector_pop(&args);
rz_pvector_pop(&args);
rz_subprocess_free(proc);
}
beach:
rz_pvector_clear(&args);
@ -379,6 +404,16 @@ RZ_API bool rz_test_check_asm_test(RzAsmTestOutput *out, RzAsmTest *test) {
return false;
}
}
if (test->il) {
// expect some IL, no failure, no report and no timeout
if (!out->il || out->il_failed || (out->il_report && *out->il_report) || out->il_timeout) {
return false;
}
// IL must also be correct
if (strcmp(out->il, test->il) != 0) {
return false;
}
}
return true;
}
@ -388,6 +423,8 @@ RZ_API void rz_test_asm_test_output_free(RzAsmTestOutput *out) {
}
free(out->disasm);
free(out->bytes);
free(out->il);
free(out->il_report);
free(out);
}
@ -464,7 +501,7 @@ RZ_API RzTestResultInfo *rz_test_run_test(RzTestRunConfig *config, RzTest *test)
success = rz_test_check_asm_test(out, asm_test);
ret->asm_out = out;
if (out) {
ret->timeout = out->as_timeout || out->disas_timeout;
ret->timeout = out->as_timeout || out->disas_timeout || out->il_timeout;
}
ret->run_failed = !out;
break;

View file

@ -735,6 +735,27 @@ static void print_result_diff(RzTestRunConfig *config, RzTestResultInfo *result)
}
}
// TODO: assembly
if (result->test->asm_test->il) {
const char *expect = result->test->asm_test->il;
const char *actual = result->asm_out->il;
const char *report = result->asm_out->il_report;
bool il_printed = false;
const char *hdr = "-- IL\n";
if (expect && actual && strcmp(actual, expect)) {
printf("%s", hdr);
il_printed = true;
print_diff(actual, expect, NULL);
}
if (report) {
if (!il_printed) {
printf("%s", hdr);
if (actual) {
printf("%s\n", actual);
}
}
printf(Color_RED "%s" Color_RESET "\n", report);
}
}
break;
case RZ_TEST_TYPE_JSON:
break;

View file

@ -99,9 +99,10 @@ typedef struct rz_test_asm_test_t {
int bits;
int mode;
ut64 offset;
char *disasm;
ut8 *bytes;
RZ_NONNULL char *disasm;
RZ_NONNULL ut8 *bytes;
size_t bytes_size;
RZ_NULLABLE char *il;
} RzAsmTest;
typedef struct rz_test_json_test_t {
@ -149,8 +150,12 @@ typedef struct rz_test_asm_test_output_t {
char *disasm;
ut8 *bytes;
size_t bytes_size;
char *il;
char *il_report;
bool il_failed;
bool as_timeout;
bool disas_timeout;
bool il_timeout;
} RzAsmTestOutput;
typedef enum rz_test_test_result_t {

View file

@ -58,7 +58,7 @@ A test can have one of the following results:
Tests for the assembly and disassembly (in `db/asm/*`) have a different format:
General format:
```
type "assembly" opcode [offset]
type "assembly" opcode [offset] [IL]
```
where type can be any of:
* **a** meaning "assemble"
@ -79,6 +79,21 @@ a "nop" 90 # Assembly is correct
dB "nopppp" 90 # Disassembly test is broken
```
#### IL
To also test lifting an instruction to RzIL, you can append the readable IL
representation like so:
```
d "inc ptr" 3e 0 set(v:ptr, x:add(x:var(v:ptr), y:bitv(bits:0x0000000000000001, len:64)))
```
This means that rz-test will also perform the lifting from bytes to RzIL,
run the validation pass on the result and compare it against the given string.
In this case, passing an offset is mandatory, otherwise the argument would be ambiguous.
#### General hints
You can merge lines:
```
adB "nop" 90

3
test/db/asm/bf Normal file
View file

@ -0,0 +1,3 @@
d "inc ptr" 3e 0 set(v:ptr, x:add(x:var(v:ptr), y:bitv(bits:0x0000000000000001, len:64)))
d "dec ptr" 3c 0 set(v:ptr, x:sub(x:var(v:ptr), y:bitv(bits:0x0000000000000001, len:64)))
d "out [ptr]" 2e 0 goto(lbl:write)

View file

@ -6,7 +6,7 @@ d "? R0 = ##0x101" 20e00078 0x0
d "? R5 = add(clb(R31),#0xffffffff)" 05ff3f8c 0x0
d "? R4 = add(R19,##0x33)" 64c613b0 0x0
d "? nop" 00c0007f 0x10000000 0x0
d "? nop" 00c0007f 0x10000000
d "? R31 = add(R0,##0x2)" 5f4000b0 0x0
d "? P0 = tstbit(R6,#0); if (!P0.new) jump:t 0x14" 04e3c611 0xc
@ -52,4 +52,4 @@ d "? R1:0 = S79:78" 00404e6f 0x0
d "? R1:0 = combine(##0x1b,#0x3)" 6063017c 0x0
d "? if (!P0) R5:4 = memd(R0+R2<<#0x0)" 04c2c031 0x0
d "? if (!P0.new) R2 = add(R2,##0x8)" 02618274 0x0
d "? if (!P0.new) R2 = add(R2,##0x8)" 02618274 0x0

View file

@ -6,7 +6,7 @@ a "jne 0x14" 7512
a "jnz 0x94" 660f858d000000
a "jnz -0x94" 660f8565ffffff
a "jno -0x34" 71ca
dB "jmp 0xfec50" e95bec f000:fff2
dB "jmp 0xfec50" e95bec
d "jmp 0x1fec50" e95bec 0x001ffff2
a "mov al, [0xbeef]" a0efbe
a "mov ax, [0xbeef]" a1efbe