From 9ce5a3168147b60d97a28bfe723b5df98884bdd8 Mon Sep 17 00:00:00 2001 From: "A.Olokhtonov" Date: Tue, 27 Jul 2021 14:57:58 +0300 Subject: [PATCH] Tests! --- build.sh | 33 ++++++ project.4coder | 21 +++- res/002-compilation-units.c | 2 +- res/Makefile | 7 -- res/traceme | Bin 19416 -> 0 bytes src/Makefile | 2 - src/command.c | 2 + src/main.c | 2 - src/util.c | 8 +- test/test_main.c | 211 ++++++++++++++++++++++++++++++++++++ 10 files changed, 274 insertions(+), 14 deletions(-) create mode 100755 build.sh delete mode 100644 res/Makefile delete mode 100755 res/traceme delete mode 100644 src/Makefile create mode 100644 test/test_main.c diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..41f5cb4 --- /dev/null +++ b/build.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +set -e +set -x + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +pushd $SCRIPT_DIR + +if [[ $# = 0 ]]; then + pushd src + mkdir -p ../build + gcc main.c -g -O0 -o ../build/trace -Wall -Wextra -Wno-unused-variable -Wno-unused-function -Wno-switch # -fsanitize=address + popd +elif [[ $1 = "examples" ]]; then + pushd res + gcc -g -o 001-simple 001-simple.c + gcc -g -o 002-compilation-units 002-compilation-units.c 002-compilation-units-impl.c + gcc -g -o 003-recursion 003-recursion.c + gcc -g -o 004-scoped-variables 004-scoped-variables.c + gcc -g -o 005-base-types 005-base-types.c + gcc -g -o 006-composite-types 006-composite-types.c + popd +elif [[ $1 = "tests" ]]; then + pushd test/ + gcc test_main.c -g -o ../build/test -Wall -Wextra -Wno-unused-function -Wno-unused-variable + popd +elif [[ $1 = "clean" ]]; then + rm build/* +else + echo "No such target '$1'" +fi + +popd \ No newline at end of file diff --git a/project.4coder b/project.4coder index bfdf018..ef5fc97 100644 --- a/project.4coder +++ b/project.4coder @@ -11,6 +11,7 @@ patterns = { blacklist_patterns = { ".*", "res", + "test", "lib", "build/*" }; @@ -30,8 +31,26 @@ command_list = { .footer_panel = false, .save_dirty_files = true, .cursor_at_end = true, - .cmd = {{ "cd src && make debug && cd ..", .os = "linux" }}, + .cmd = {{ "./build.sh", .os = "linux" }}, + }, + { + .name = "build examples", + .out = "*compilation*", + .footer_panel = false, + .save_dirty_files = true, + .cursor_at_end = true, + .cmd = {{ "./build.sh examples", .os = "linux" }}, + }, + { + .name = "build tests", + .out = "*compilation*", + .footer_panel = false, + .save_dirty_files = true, + .cursor_at_end = true, + .cmd = {{ "./build.sh tests", .os = "linux" }}, }, }; fkey_command[1] = "build debug"; +fkey_command[2] = "build examples"; +fkey_command[3] = "build tests"; diff --git a/res/002-compilation-units.c b/res/002-compilation-units.c index 09b0031..c02febb 100644 --- a/res/002-compilation-units.c +++ b/res/002-compilation-units.c @@ -5,5 +5,5 @@ main(void) { int a = 3; int b = foo(a); - return(b); + return(0); } diff --git a/res/Makefile b/res/Makefile deleted file mode 100644 index 2f79fb7..0000000 --- a/res/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -all: - gcc -g -o 001-simple 001-simple.c - gcc -g -o 002-compilation-units 002-compilation-units.c 002-compilation-units-impl.c - gcc -g -o 003-recursion 003-recursion.c - gcc -g -o 004-scoped-variables 004-scoped-variables.c - gcc -g -o 005-base-types 005-base-types.c - gcc -g -o 006-composite-types 006-composite-types.c diff --git a/res/traceme b/res/traceme deleted file mode 100755 index fdc818f46611f7a4f06d3804a4b46c436801dcd3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19416 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 u64 raw_value = ptrace(PTRACE_PEEKDATA, proc.pid, address, NULL); + printf("\"%s\", %ld\n", type.name, variable->location); + u8 raw_value1; u16 raw_value2; u32 raw_value4; diff --git a/src/main.c b/src/main.c index 8f6ffba..1bcc0a0 100644 --- a/src/main.c +++ b/src/main.c @@ -21,8 +21,6 @@ main(int argc, char *argv[]) char *command = malloc(max_command_length + 1); char *last_command = malloc(max_command_length + 1); - process.base_address = 0x555555554000UL; // get_executable_base_address(file, proc.pid); - parse_debug_info(process.elf, &process.debug); parse_debug_line(process.elf, &process.debug); diff --git a/src/util.c b/src/util.c index 41472dc..22a987b 100644 --- a/src/util.c +++ b/src/util.c @@ -202,7 +202,7 @@ print_sourcepoint(struct mi_process proc, int comp_unit, struct mi_sourcepoint * } - printf("%.*s\n", len - start, source + i + start); + printf("%d:%d] %.*s\n", sp->line, sp->column, len - start, source + i + start); return; } @@ -236,11 +236,17 @@ process_create(char *path) } } + // TODO: readup man (2) ptrace: how to wait for execve + //waitpid(pid, 0, 0); + //ptrace(PTRACE_CONT, pid, 0, 0); + //waitpid(pid, 0, 0); + struct mi_buffer file = read_file_mmap(path); result.elf = file.data; result.elf_size = file.size; result.pid = pid; + result.base_address = 0x555555554000UL; // get_executable_base_address(file, proc.pid); return(result); } diff --git a/test/test_main.c b/test/test_main.c new file mode 100644 index 0000000..20743fe --- /dev/null +++ b/test/test_main.c @@ -0,0 +1,211 @@ +#include "../src/common.h" + +#include "../src/dwarf.c" +#include "../src/eh_frame.c" +#include "../src/util.c" +#include "../src/command.c" + +#define DO_TEST(title, call) do { \ +int rt = call; \ +if (rt == 0) { \ +fprintf(stderr, "Test '%s' \033[1m\033[32msuccess\033[0m...\n", title); \ +} else { \ +fprintf(stderr, "Test '%s' \033[1m\033[31mfail\033[0m\n", title); \ +exit(1); \ +} \ +} while(0) + +static int +test_start(char *path) +{ + struct mi_process proc = process_create(path); + waitpid(proc.pid, 0, 0); + parse_debug_info(proc.elf, &proc.debug); + proc.main_address = get_address_of_subroutine(proc, "main"); + command_start(proc); + struct mi_registers regs = get_process_registers(proc); + + int result = 1; + + if (proc.main_address == regs.rip - proc.base_address) { + result = 0; + } + + command_kill(proc); + waitpid(proc.pid, 0, 0); + + return(result); +} + +static int +test_regs(char *path) +{ + struct mi_process proc = process_create(path); + waitpid(proc.pid, 0, 0); + parse_debug_info(proc.elf, &proc.debug); + proc.main_address = get_address_of_subroutine(proc, "main"); + command_start(proc); + struct mi_registers regs = get_process_registers(proc); + + int result = 1; + if (regs.rbp > 0 && regs.rsp > 0 && regs.rip > 0) { + result = 0; + } + + command_kill(proc); + waitpid(proc.pid, 0, 0); + + return(result); +} + +static int +test_step(char *path, int steps, u64 pc) +{ + struct mi_process proc = process_create(path); + waitpid(proc.pid, 0, 0); + parse_debug_info(proc.elf, &proc.debug); + parse_debug_line(proc.elf, &proc.debug); + proc.main_address = get_address_of_subroutine(proc, "main"); + command_start(proc); + for (int i = 0; i < steps; ++i) { + command_step(proc); + } + struct mi_registers regs = get_process_registers(proc); + int result = 1; + if ((regs.rip - proc.base_address) == pc) { + result = 0; + } + command_kill(proc); + waitpid(proc.pid, 0, 0); + return(result); +} + +static int +test_next(char *path, int nexts, u64 pc) +{ + struct mi_process proc = process_create(path); + waitpid(proc.pid, 0, 0); + parse_debug_info(proc.elf, &proc.debug); + parse_debug_line(proc.elf, &proc.debug); + proc.main_address = get_address_of_subroutine(proc, "main"); + command_start(proc); + for (int i = 0; i < nexts; ++i) { + command_next(proc); + } + struct mi_registers regs = get_process_registers(proc); + int result = 1; + if ((regs.rip - proc.base_address) == pc) { + result = 0; + } + command_kill(proc); + waitpid(proc.pid, 0, 0); + return(result); +} + +static int +test_list(char *path, int steps, int line, int column) +{ + struct mi_process proc = process_create(path); + waitpid(proc.pid, 0, 0); + parse_debug_info(proc.elf, &proc.debug); + parse_debug_line(proc.elf, &proc.debug); + proc.main_address = get_address_of_subroutine(proc, "main"); + command_start(proc); + for (int i = 0; i < steps; ++i) { + command_step(proc); + } + + int comp_unit; + struct mi_registers regs = get_process_registers(proc); + struct mi_sourcepoint *sp = pc_to_sourcepoint(proc, regs.rip - proc.base_address, &comp_unit); + + int result = 1; + if (sp->line == line && sp->column == column) { + result = 0; + } + command_kill(proc); + waitpid(proc.pid, 0, 0); + return(result); +} + +static int +test_print(char *path, int steps, char *name, char *type, int location) +{ + struct mi_process proc = process_create(path); + waitpid(proc.pid, 0, 0); + parse_debug_info(proc.elf, &proc.debug); + parse_debug_line(proc.elf, &proc.debug); + proc.main_address = get_address_of_subroutine(proc, "main"); + command_start(proc); + for (int i = 0; i < steps; ++i) { + command_step(proc); + } + + struct mi_registers regs = get_process_registers(proc); + u64 pc = regs.rip - proc.base_address; + u64 cfa = get_cfa_at_pc(proc, pc); + + struct mi_variable *variable = get_variable(proc, name, strlen(name), pc); + struct mi_type real_type = proc.debug.types[variable->type]; + + int result = 1; + int type_length = strlen(type); + if (0 == strncmp(type, real_type.name, type_length) && variable->location == location) { + result = 0; + } + command_kill(proc); + waitpid(proc.pid, 0, 0); + return(result); +} + +int +main(void) +{ + DO_TEST("start 001-simple", test_start("res/001-simple")); + DO_TEST("start 002-compilation-units", test_start("res/002-compilation-units")); + DO_TEST("start 003-recursion", test_start("res/003-recursion")); + DO_TEST("start 004-scoped-variables", test_start("res/004-scoped-variables")); + DO_TEST("start 005-base-types", test_start("res/005-base-types")); + DO_TEST("start 006-composite-types", test_start("res/006-composite-types")); + + DO_TEST("regs 001-simple", test_regs("res/001-simple")); + DO_TEST("regs 002-compilation-units", test_regs("res/002-compilation-units")); + DO_TEST("regs 003-recursion", test_regs("res/003-recursion")); + DO_TEST("regs 004-scoped-variables", test_regs("res/004-scoped-variables")); + DO_TEST("regs 005-base-types", test_regs("res/005-base-types")); + DO_TEST("regs 006-composite-types", test_regs("res/006-composite-types")); + + DO_TEST("step 001-simple", test_step("res/001-simple", 4, 0x1166)); + DO_TEST("step 002-compilation-units", test_step("res/002-compilation-units", 4, 0x114f)); + DO_TEST("step 003-recursion", test_step("res/003-recursion", 9, 0x1130)); + DO_TEST("step 004-scoped-variables", test_step("res/004-scoped-variables", 7, 0x1145)); + DO_TEST("step 005-base-types", test_step("res/005-base-types", 3, 0x113e)); + DO_TEST("step 006-composite-types", test_step("res/006-composite-types", 5, 0x114c)); + + DO_TEST("next 001-simple", test_next("res/001-simple", 4, 0x1166)); + DO_TEST("next 002-compilation-units", test_next("res/002-compilation-units", 4, 0x1146)); + DO_TEST("next 003-recursion", test_next("res/003-recursion", 2, 0x116b)); + DO_TEST("next 004-scoped-variables", test_next("res/004-scoped-variables", 4, 0x11a3)); + DO_TEST("next 005-base-types", test_next("res/005-base-types", 3, 0x113e)); + DO_TEST("next 006-composite-types", test_next("res/006-composite-types", 5, 0x114c)); + + DO_TEST("list 001-simple", test_list("res/001-simple", 4, 12, 20)); + DO_TEST("list 002-compilation-units", test_list("res/002-compilation-units", 4, 5, 6)); + DO_TEST("list 003-recursion", test_list("res/003-recursion", 9, 4, 5)); + DO_TEST("list 004-scoped-variables", test_list("res/004-scoped-variables", 7, 15, 6)); + DO_TEST("list 005-base-types", test_list("res/005-base-types", 3, 6, 7)); + DO_TEST("list 006-composite-types", test_list("res/006-composite-types", 5, 18, 14)); + + DO_TEST("print 001-simple", test_print("res/001-simple", 4, "i", "int", -28)); + DO_TEST("print 002-compilation-units", test_print("res/002-compilation-units", 5, "sq", "int", -20)); + DO_TEST("print 003-recursion", test_print("res/003-recursion", 28, "result", "int", -20)); + DO_TEST("print 004-scoped-variables", test_print("res/004-scoped-variables", 9, "b_f2", "int", -24)); + DO_TEST("print 005-base-types long", test_print("res/005-base-types", 5, "var_unsigned_long", "long unsigned int", -40)); + DO_TEST("print 005-base-types char", test_print("res/005-base-types", 4, "var_char", "char", -41)); + DO_TEST("print 005-base-types float", test_print("res/005-base-types", 8, "var_float", "float", -48)); + DO_TEST("print 005-base-types double", test_print("res/005-base-types", 9, "var_double", "double", -56)); + + fprintf(stderr, "\033[1m\033[32mAll tests succeeded!\033[0m\n"); + + return(0); +} \ No newline at end of file