summaryrefslogtreecommitdiffhomepage
path: root/mini_xdebug.c
blob: b9263ba72156ab57d759833efe67f79e1af4bc3c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
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,
};