diff --git a/Makefile b/Makefile index a4bb539..a85fdfe 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,8 @@ SRC = src/pasm.c \ src/file_utils.c \ src/interpreter_states.c \ src/instructions.c \ - src/api.c + src/api.c \ + src/debug.c OBJ = $(SRC:.c=.o) NAME = pasm CC = gcc @@ -23,10 +24,6 @@ $(NAME): interpreter: $(NAME) -debug: fclean -debug: CFLAGS += -DDEBUG -g3 -debug: $(NAME) - clean: @-rm -f $(OBJ) @-cd tests && $(MAKE) clean @@ -38,4 +35,4 @@ fclean: clean re: fclean re: $(NAME) -.PHONY : all $(NAME) clean fclean re interpreter lib debug +.PHONY : all $(NAME) clean fclean re interpreter lib diff --git a/include/pasm.h b/include/pasm.h index e234cc1..21ee89c 100644 --- a/include/pasm.h +++ b/include/pasm.h @@ -2,6 +2,10 @@ #include #include +// set to 1 for debug mode +// /!\ YOU NEED ACCESS TO STDIN +extern int pasm_debug_mode; + /* filename: path of the pasm script, will use file argument if NULL */ /* file: char** containing the lines of a pasm script, will be used if filename is NULL */ /* lines: number of lines in the file argument, will be used if filename is NULL */ diff --git a/src/debug.c b/src/debug.c new file mode 100644 index 0000000..4f168a1 --- /dev/null +++ b/src/debug.c @@ -0,0 +1,170 @@ +#include "../include/pasm.h" +#include "interpreter_states.h" +#include +#include +#include "debug.h" + +void show_registers() { + printf("--Registers--\n"); + printf("a1: %-3d | ", state->registers->a1); + printf("a2: %-3d | ", state->registers->a2); + printf("a3: %-3d\n", state->registers->a3); + printf("a4: %-3d | ", state->registers->a4); + printf("a5: %-3d | ", state->registers->a5); + printf("a6: %-3d\n", state->registers->a6); + printf("a7: %-3d | ", state->registers->a7); + printf("a8: %-3d | ", state->registers->a8); + printf("a9: %-3d\n", state->registers->a9); + printf("eax: %-3d\n\n", state->registers->eax); +} + +void show_stack() { + printf("--STACK--\n"); + printf("Elements: %d\n\n", state->STACK_IDX); + for (int i = 0; i < state->STACK_IDX; i++) + printf("[%d]: %d\n", i, state->STACK[state->STACK_IDX]); + printf("\n"); +} + +void show_labels() { + printf("\n\n-----LABELS-----\n"); + printf("format:\tlabel|line"); + for (int i = 0; i < state->num_labels; i++) + printf("%s|%d\n", state->labels[i], state->labels_values[i]); + printf("\n\n-----LABELS-----\n"); +} + +void show_breakpoints(int *bp) { + printf("---Breakpoints---\n"); + for (int i = 0; bp[i] != 0 && i < 255; i++) { + if (bp[i] + 1 == -1) continue; //deleted bp + printf("bp line %d\n", bp[i] + 1); + } + printf("---Breakpoints---\n"); +} + +void show_states() { + printf("\n\n--------PASM STATE--------\n"); + show_registers(); + show_labels(); + show_stack(); + printf("\n\n--------PASM STATE--------\n"); +} + +void bp_add(int *bp, int line) { + int i = 0; + for (i = 0; bp[i] != 0 && bp[i] != -1 && i < 255; i++); + bp[i] = line; +} + +void bp_rem(int *bp, int line) { + int i = 0; + for (i = 0; bp[i] != 0 && i < 255; i++) { + if (bp[i] == line) + bp[i] = -2; + } + return; +} + +int add_breakpoint(char *in, int *bp) { + for (int i = 0; i < state->num_labels; i++) { + if (strncmp(state->labels[i], in, strlen(in) - 1) == 0) { + bp_add(bp, state->labels_values[i] + 1); + printf("breakpoint added at line %d.\n", state->labels_values[i] + 2); + return 0; + } + } + int line = atoi(in); + if (line <= 0 && in[0] != '0') + return 1; + bp_add(bp, line - 1); + printf("breakpoint added at line %d.\n", line); + return 0; +} + +int rem_breakpoint(char *in, int *bp) { + for (int i = 0; i < state->num_labels; i++) { + if (strncmp(state->labels[i], in, strlen(in) - 1) == 0) { + bp_rem(bp, state->labels_values[i] + 1); + printf("breakpoint at line %d deleted.\n", state->labels_values[i] + 2); + return 0; + } + } + int line = atoi(in); + if (line == 0 && in[0] != '0') + return 1; + bp_rem(bp, line - 1); + printf("breakpoint at line %d deleted.\n", line); + return 0; +} + +void debug_input(char *line) { + static int should_continue = 0; + static int breakpoints[256] = {0}; + + if (should_continue) { + for (int i = 0; breakpoints[i] != 0 && i < 255; i++) { + if (state->curr_line == breakpoints[i]) { + should_continue = 0; + printf("breakpoint reached at line %d\n", breakpoints[i] + 1); + } + } + } + if (should_continue) return; + while (1) { + char in[20] = {0}; + + printf("\nline %d --> ", state->curr_line + 1); + fgets(in, 19, stdin); + switch (in[0]) { + case 'l': + printf("%s\n", line); + break; + case 'v': + show_states(); + break; + case 'c': + should_continue = 1; + return; + case 's': + return; + case 'b': + in[strlen(in) - 1] = '\0'; + if (strlen(in) < 3) { + printf("command has bad format.\n"); + break; + } + if (in[2] == 'l' && strlen(in) == 3) { + show_breakpoints(breakpoints); + break; + } + if (add_breakpoint(&in[2], breakpoints)) + printf("%s is not a valid label or line number in this context", &in[2]); + break; + case 'd': + in[strlen(in) - 1] = '\0'; + if (strlen(in) < 3) { + printf("command has bad format.\n"); + break; + } + if (rem_breakpoint(&in[2], breakpoints)) + printf("%s is not a valid label or line number in this context", &in[2]); + break; + case 'e': + state->should_exit = 1; + return; + case 'h': + default: + printf("pasm debug mode help message\n"); + printf("h: shows this message.\n"); + printf("l: shows current line\n"); + printf("v: shows states\n"); + printf("e: end the program\n"); + printf("c: continue execution until end or breakpoint.\n"); + printf("s: single step.\n"); + printf("b [line/label]: sets a breakpoint on line [line/label]\n"); + printf("b l: list all breakpoints\n"); + printf("d [line/label]: deletes a breakpoint on line line/label]\n"); + } + } +} diff --git a/src/debug.h b/src/debug.h new file mode 100644 index 0000000..ea9fd76 --- /dev/null +++ b/src/debug.h @@ -0,0 +1,3 @@ +#pragma once + +void debug_input(char *line); diff --git a/src/pasm.c b/src/pasm.c index 0964a2a..50dac0f 100644 --- a/src/pasm.c +++ b/src/pasm.c @@ -2,10 +2,12 @@ #include #include "file_utils.h" +#include "debug.h" #include "interpreter_states.h" #include "instructions.h" int fstream = 0; +int pasm_debug_mode = 0; void show_error(size_t line, char *line_) { #ifdef _WIN32 int wrote = dprintf(fstream, "%llu| ", line + 1); @@ -19,20 +21,6 @@ void show_error(size_t line, char *line_) { dprintf(fstream, " "); } -void show_states() { - printf("\n\n--------PASM STATE--------\n"); - printf("a1: %-3d | ", state->registers->a1); - printf("a2: %-3d | ", state->registers->a2); - printf("a3: %-3d\n", state->registers->a3); - printf("a4: %-3d | ", state->registers->a4); - printf("a5: %-3d | ", state->registers->a5); - printf("a6: %-3d\n", state->registers->a6); - printf("a7: %-3d | ", state->registers->a7); - printf("a8: %-3d | ", state->registers->a8); - printf("a9: %-3d\n", state->registers->a9); - printf("eax: %-3d\n", state->registers->eax); -} - int check_errors(char *line) { if (state->last_check_args_code != OK) { show_error(state->curr_line, line); @@ -81,9 +69,11 @@ int pasm_run_script(const char *filename, char **file, size_t lines, int _fstrea free_script(file); return 1; } - + int found_main = 0; for (state->curr_line = 0; state->curr_line < (int)lines && get_exit_state() == 0 ; ++state->curr_line) { + if (pasm_debug_mode && found_main) + debug_input(file[state->curr_line]); char *line = strdup(file[state->curr_line]); if (line[0] == ';' || line[0] == '\0') { free(line); @@ -115,9 +105,6 @@ int pasm_run_script(const char *filename, char **file, size_t lines, int _fstrea } int ret_code = get_exit_state(); -#ifdef DEBUG - show_states(); -#endif free_script(file); return ret_code; } diff --git a/tests/interpreter.c b/tests/interpreter.c index 0d1ad0c..6b7c144 100644 --- a/tests/interpreter.c +++ b/tests/interpreter.c @@ -4,9 +4,13 @@ #include int main(int argc, char **argv) { - if (argc != 2 || strcmp(argv[1], "-h") == 0) { - fprintf(stderr, "Usage : %s filename\n", argv[0]); + if (argc > 3 || (argc == 2 && strcmp(argv[1], "-h") == 0) || (argc != 2 && argc != 3)) { + fprintf(stderr, "usage : %s filename [-d/--debug]\n", argv[0]); return 1; } + if (argc == 3 && (strcmp(argv[2], "-d") == 0 || strcmp(argv[2], "--debug") == 0)) { + pasm_debug_mode = 1; + printf("pasm: debug mode activated.\n"); + } return pasm_run_script(argv[1], 0, 0, 1); }