diff options
Diffstat (limited to 'mini_xdebug.c')
| -rw-r--r-- | mini_xdebug.c | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/mini_xdebug.c b/mini_xdebug.c new file mode 100644 index 0000000..b9263ba --- /dev/null +++ b/mini_xdebug.c @@ -0,0 +1,132 @@ +#include <stdio.h> +#include <string.h> + +#include "php.h" +#include "zend_extensions.h" + +#define MINI_XDEBUG_CMD_END -1 +#define MINI_XDEBUG_CMD_INVALID 0 +#define MINI_XDEBUG_CMD_NEXT 1 + +static int g_is_first_statement; +static int g_do_next_cmd; +static int g_next_call_depth; + +static void mini_xdebug_activate(void) { + CG(compiler_options) |= ZEND_COMPILE_EXTENDED_STMT; + g_is_first_statement = 1; + g_do_next_cmd = 0; + g_next_call_depth = 0; +} + +static int get_call_depth(void) { + int depth = 0; + zend_execute_data* ex = EG(current_execute_data); + while (ex) { + depth++; + ex = ex->prev_execute_data; + } + return depth; +} + +static void show_context(const char* filename, int lineno) { + FILE* fp = fopen(filename, "r"); + if (!fp) { + return; + } + + char buf[1024]; + int n = 0; + while (fgets(buf, sizeof(buf), fp)) { + n++; + if (lineno - 1 <= n && n <= lineno + 1) { + fprintf(stdout, "%s %3d | %s", n == lineno ? ">" : " ", n, buf); + } + if (n > lineno + 1) { + break; + } + } + fclose(fp); +} + +static void show_prompt(void) { + fprintf(stdout, "(mini-xdebug) "); + fflush(stdout); +} + +static int query_command(char* buf) { + if (!fgets(buf, sizeof(buf), stdin)) { + return MINI_XDEBUG_CMD_END; + } + buf[strcspn(buf, "\n")] = '\0'; + + return (!strcmp(buf, "next") || !strcmp(buf, "n")) + ? MINI_XDEBUG_CMD_NEXT + : MINI_XDEBUG_CMD_INVALID; +} + +static void mini_xdebug_statement_handler(zend_execute_data* frame) { + if (!g_is_first_statement && !g_do_next_cmd) { + return; + } + + uint32_t lineno = EG(current_execute_data)->opline->lineno; + const char* filename = ZSTR_VAL(frame->func->op_array.filename); + int depth = get_call_depth(); + + if (g_is_first_statement) { + g_is_first_statement = 0; + } else if (g_do_next_cmd) { + if (depth > g_next_call_depth) { + return; + } + g_do_next_cmd = 0; + } + + fprintf(stdout, "\n%s:%d\n", filename, lineno); + show_context(filename, lineno); + + char command_buf[256]; + for (;;) { + show_prompt(); + int cmd = query_command(command_buf); + if (cmd == MINI_XDEBUG_CMD_NEXT) { + g_do_next_cmd = 1; + g_next_call_depth = depth; + break; + } else if (cmd == MINI_XDEBUG_CMD_END) { + break; + } else { + fprintf(stdout, "Available commands: next (n)\n"); + } + } +} + +#ifndef ZEND_EXT_API +#define ZEND_EXT_API ZEND_DLEXPORT +#endif + +ZEND_EXT_API zend_extension_version_info extension_version_info = { + ZEND_EXTENSION_API_NO, + (char*)ZEND_EXTENSION_BUILD_ID, +}; + +ZEND_DLEXPORT zend_extension zend_extension_entry = { + "mini-xdebug", /* name */ + "0.1.0", /* version */ + "nsfisis", /* author */ + "", /* URL */ + "", /* copyright */ + NULL, /* startup */ + NULL, /* shutdown */ + mini_xdebug_activate, /* activate */ + NULL, /* deactivate */ + NULL, /* message_handler */ + NULL, /* op_array_handler */ + mini_xdebug_statement_handler, /* statement_handler */ + NULL, /* fcall_begin_handler */ + NULL, /* fcall_end_handler */ + NULL, /* op_array_ctor */ + NULL, /* op_array_dtor */ + STANDARD_ZEND_EXTENSION_PROPERTIES, +}; |
