From 7e36f4bd38cfb83a22a458626fbeb3f031b9bbf2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Mon, 10 Jan 2022 17:15:02 +0100 Subject: [PATCH] Add IL lifting testing to rz-test --- binrz/rz-test/load.c | 28 +++++++++++++++++++++++++++- binrz/rz-test/run.c | 39 ++++++++++++++++++++++++++++++++++++++- binrz/rz-test/rz-test.c | 21 +++++++++++++++++++++ binrz/rz-test/rz_test.h | 9 +++++++-- test/README.md | 17 ++++++++++++++++- test/db/asm/bf | 3 +++ test/db/asm/hexagon | 4 ++-- test/db/asm/x86_16 | 2 +- 8 files changed, 115 insertions(+), 8 deletions(-) create mode 100644 test/db/asm/bf diff --git a/binrz/rz-test/load.c b/binrz/rz-test/load.c index 8d531d7f3e..4bc42005cd 100644 --- a/binrz/rz-test/load.c +++ b/binrz/rz-test/load.c @@ -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)); diff --git a/binrz/rz-test/run.c b/binrz/rz-test/run.c index 8b2aeb84ba..fbd29b336a 100644 --- a/binrz/rz-test/run.c +++ b/binrz/rz-test/run.c @@ -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; diff --git a/binrz/rz-test/rz-test.c b/binrz/rz-test/rz-test.c index 8351117bdf..7639dc61ff 100644 --- a/binrz/rz-test/rz-test.c +++ b/binrz/rz-test/rz-test.c @@ -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; diff --git a/binrz/rz-test/rz_test.h b/binrz/rz-test/rz_test.h index 747fb50acd..ec2a4d977d 100644 --- a/binrz/rz-test/rz_test.h +++ b/binrz/rz-test/rz_test.h @@ -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 { diff --git a/test/README.md b/test/README.md index aba9bb899f..2ab97adbdb 100644 --- a/test/README.md +++ b/test/README.md @@ -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 diff --git a/test/db/asm/bf b/test/db/asm/bf new file mode 100644 index 0000000000..b24659ac58 --- /dev/null +++ b/test/db/asm/bf @@ -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) diff --git a/test/db/asm/hexagon b/test/db/asm/hexagon index 1e1c38bfca..176143b83d 100644 --- a/test/db/asm/hexagon +++ b/test/db/asm/hexagon @@ -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 \ No newline at end of file +d "? if (!P0.new) R2 = add(R2,##0x8)" 02618274 0x0 diff --git a/test/db/asm/x86_16 b/test/db/asm/x86_16 index f191932b09..37d92e5cb8 100644 --- a/test/db/asm/x86_16 +++ b/test/db/asm/x86_16 @@ -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