summaryrefslogtreecommitdiffstats
path: root/src/parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/parser.c')
-rw-r--r--src/parser.c249
1 files changed, 249 insertions, 0 deletions
diff --git a/src/parser.c b/src/parser.c
new file mode 100644
index 0000000..c42c2cc
--- /dev/null
+++ b/src/parser.c
@@ -0,0 +1,249 @@
+enum TOKEN_TYPE {
+ // Commands
+ TOKEN_CONTINUE,
+ TOKEN_PRINT_REG,
+ TOKEN_STEP_INTO,
+ TOKEN_DUMP_MEMORY,
+ TOKEN_QUIT,
+
+ // Primaries
+ TOKEN_DECIMAL_NUMBER,
+ TOKEN_HEXADECIMAL_NUMBER,
+
+ TOKEN_UNKNOWN,
+};
+
+struct token {
+ enum TOKEN_TYPE type;
+ const char* lexeme;
+ u8 size;
+};
+
+struct command {
+ const char* start;
+ u8 size;
+};
+
+struct ast_node {
+ struct token* token;
+ struct ast_node* left;
+ struct ast_node* right;
+};
+
+static struct command commands[] = {
+ { .start = "g", .size = 1 },
+ { .start = "r", .size = 1 },
+ { .start = "t", .size = 1 },
+ { .start = "db", .size = 2 },
+ { .start = "q", .size = 1 },
+};
+
+_Static_assert((sizeof(commands) / sizeof(commands[0])) == TOKEN_QUIT + 1, "Missing commands");
+
+void lexer(const char* str_cmd, size_t str_cmd_len, struct token* tokens) {
+ const char* cur = str_cmd;
+ const char* end = str_cmd + str_cmd_len;
+ struct token* cur_token = tokens;
+ str_cmd_len = 0;
+
+ while(cur < end) {
+ cur_token->type = TOKEN_UNKNOWN;
+ if(*cur == '0' && cur[1] == 'x') {
+ const char* start = cur;
+ cur += 2;
+
+ while(is_hexadecimal_digit(*cur) && cur < end) {
+ cur++;
+ }
+
+ cur_token->lexeme = start;
+ cur_token->type = TOKEN_HEXADECIMAL_NUMBER;
+ cur_token->size = (u8)(cur - start);
+ cur_token++;
+ } else if(is_decimal_digit(*cur)) {
+ const char* start = cur;
+ cur++;
+
+ while(is_decimal_digit(*cur) && cur < end) {
+ cur++;
+ }
+
+ cur_token->lexeme = start;
+ cur_token->type = TOKEN_DECIMAL_NUMBER;
+ cur_token->size = (u8)(cur - start);
+ cur_token++;
+ } else if(is_alpha(*cur)) {
+ const char* start = cur;
+ cur++;
+ while(is_alpha(*cur) && cur < end) {
+ cur++;
+ }
+
+ cur_token->lexeme = start;
+ cur_token->size = (u8)(cur - start);
+
+ for(int i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) {
+ struct command cur_cmd = commands[i];
+ if (CompareStringA(LOCALE_SYSTEM_DEFAULT, 0, cur_cmd.start, cur_cmd.size, cur_token->lexeme, cur_token->size) == CSTR_EQUAL) {
+ cur_token->type = i;
+ cur_token++;
+ break;
+ }
+ }
+ } else {
+ cur++;
+ }
+ }
+}
+
+struct ast_node* parse_primary(struct token* tokens, struct ast_node* nodes) {
+ struct ast_node* cur_node = &nodes[0];
+ struct token* cur_token = &tokens[0];
+ if (cur_token->type == TOKEN_HEXADECIMAL_NUMBER ||
+ cur_token->type == TOKEN_DECIMAL_NUMBER) {
+ cur_node->token = cur_token;
+ cur_node->left = NULL;
+ cur_node->right = NULL;
+ return cur_node;
+ } else {
+ print("Expecting a primary token\n");
+ return NULL;
+ }
+}
+
+struct ast_node* parse_command(struct token* tokens, struct ast_node* nodes) {
+ struct ast_node* cur_node = &nodes[0];
+ struct token* cur_token = &tokens[0];
+ switch(cur_token->type) {
+ case TOKEN_CONTINUE:
+ tokens++;
+ print("TOKEN_CONTINUE\n");
+ cur_node->token = cur_token;
+ cur_node->left = NULL;
+ cur_node->right = NULL;
+ return cur_node;
+ case TOKEN_PRINT_REG:
+ tokens++;
+ print("TOKEN_PRINT_REG\n");
+ cur_node->token = cur_token;
+ cur_node->left = NULL;
+ cur_node->right = NULL;
+ return cur_node;
+ case TOKEN_STEP_INTO:
+ tokens++;
+ print("TOKEN_STEP_INTO\n");
+ cur_node->token = cur_token;
+ cur_node->left = NULL;
+ cur_node->right = NULL;
+ return cur_node;
+ case TOKEN_DUMP_MEMORY:
+ tokens++;
+ print("TOKEN_DUMP_MEMORY\n");
+ cur_node->token = cur_token;
+ cur_node->left = NULL;
+ cur_node->right = parse_primary(tokens, ++nodes);
+ return cur_node;
+ case TOKEN_QUIT:
+ tokens++;
+ print("TOKEN_QUIT\n");
+ cur_node->token = cur_token;
+ cur_node->left = NULL;
+ cur_node->right = NULL;
+ return cur_node;
+ default:
+ print("%s must be a command\n", cur_token->lexeme);
+ return NULL;
+ }
+}
+
+u64 eval_number(const struct ast_node* node) {
+ if (node->token->type == TOKEN_DECIMAL_NUMBER ||
+ node->token->type == TOKEN_HEXADECIMAL_NUMBER) {
+ return atou64(node->token->lexeme, node->token->size);
+ }
+ return ~0U;
+}
+
+void run(struct ast_node* root) {
+ struct ast_node cur_node = root[0];
+ CONTEXT ctx = {
+ .ContextFlags = CONTEXT_ALL,
+ };
+ HANDLE h_thread = OpenThread(
+ THREAD_GET_CONTEXT | THREAD_SET_CONTEXT,
+ FALSE,
+ dbg_event.dwThreadId
+ );
+ GetThreadContext(h_thread, &ctx);
+
+ if (cur_node.token->type == TOKEN_CONTINUE) {
+ ContinueDebugEvent(
+ dbg_event.dwProcessId,
+ dbg_event.dwThreadId,
+ continue_status
+ );
+ process_commands = FALSE;
+ } else if (cur_node.token->type == TOKEN_PRINT_REG) {
+ print("RIP : %x\n", ctx.Rip);
+ print("RAX : %x\n", ctx.Rax);
+ print("RCX : %x\n", ctx.Rcx);
+ print("RDX : %x\n", ctx.Rdx);
+ print("RBX : %x\n", ctx.Rbx);
+ print("RSP : %x\n", ctx.Rsp);
+ print("RBP : %x\n", ctx.Rbp);
+ print("RSI : %x\n", ctx.Rsi);
+ print("RDI : %x\n", ctx.Rdi);
+ process_commands = TRUE;
+ } else if (cur_node.token->type == TOKEN_STEP_INTO) {
+ ctx.EFlags |= 0x100; // TRAP_FLAG
+ if(SetThreadContext(h_thread, &ctx) == 0) {
+ __debugbreak();
+ }
+ ContinueDebugEvent(
+ dbg_event.dwProcessId,
+ dbg_event.dwThreadId,
+ continue_status
+ );
+ expect_single_step = TRUE;
+ process_commands = FALSE;
+ } else if (cur_node.token->type == TOKEN_QUIT) {
+ is_open = FALSE;
+ process_commands = FALSE;
+ } else if (cur_node.token->type == TOKEN_DUMP_MEMORY) {
+ u64 addr = eval_number(cur_node.right);
+ u8 buf[16U] = { 0 };
+
+ if(read_memory((const void*)addr, (void*)buf, sizeof(buf))) {
+ for (u32 index = 0U; index < sizeof(buf); index++) {
+ print("%b ", buf[index]);
+ }
+ print("\n");
+ } else {
+
+ print("Unable to read memory at this address, error %u\n", GetLastError());
+ }
+
+ } else {
+ print("Command unknown\n");
+ process_commands = TRUE;
+ }
+
+ CloseHandle(h_thread);
+}
+
+u8 interpreter(const char* str_cmd, size_t str_cmd_len) {
+ struct token tokens[64U];
+ struct ast_node nodes[64U];
+
+ lexer(str_cmd, str_cmd_len, tokens);
+
+ struct ast_node* root = parse_command(tokens, nodes);
+
+ if(root == NULL) {
+ print("Ill formed command\n");
+ return FALSE;
+ }
+
+ run(root);
+ return TRUE;
+}