summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-04-11 03:20:45 +0900
committernsfisis <nsfisis@gmail.com>2026-04-11 03:20:45 +0900
commitbe2211a6fb78375cec9a5d2615dafaf043e5e848 (patch)
tree1047c4a27e7e69b1692c00d08196a2d889c7132d
parentb3b5a0b29ddd627b7cb5f2cce3332f08c412bcdd (diff)
downloadmini-xdebug-main.tar.gz
mini-xdebug-main.tar.zst
mini-xdebug-main.zip
add filesHEADmain
-rw-r--r--.envrc5
-rw-r--r--.gitignore20
-rw-r--r--build.sh6
-rw-r--r--config.m48
-rw-r--r--flake.lock64
-rw-r--r--flake.nix27
-rwxr-xr-xmini-xdebug3
-rw-r--r--mini_xdebug.c132
-rw-r--r--test.php4
9 files changed, 269 insertions, 0 deletions
diff --git a/.envrc b/.envrc
new file mode 100644
index 0000000..09672f8
--- /dev/null
+++ b/.envrc
@@ -0,0 +1,5 @@
+# shellcheck shell=bash
+if ! has nix_direnv_version || ! nix_direnv_version 3.1.1; then
+ source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.1.1/direnvrc" "sha256-p+fzQdrms/hDa7g+soShAybJNo4bN4SIAeSfqNKgD5I="
+fi
+use flake
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a7f06e1
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,20 @@
+# Files generated by phpize and make
+.libs/
+Makefile
+Makefile.fragments
+Makefile.objects
+autom4te.cache/
+build/
+config.h
+config.h.in
+config.log
+config.nice
+config.status
+configure
+configure.ac
+libtool
+mini_xdebug.dep
+mini_xdebug.la
+mini_xdebug.lo
+modules/
+run-tests.php
diff --git a/build.sh b/build.sh
new file mode 100644
index 0000000..e1f9d50
--- /dev/null
+++ b/build.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+PHP_PREFIX="${PHP_PREFIX:-/usr/local}"
+cd "$(dirname "$0")" && \
+ "$PHP_PREFIX/bin/phpize" && \
+ ./configure --with-php-config="$PHP_PREFIX/bin/php-config" --enable-mini-xdebug && \
+ make
diff --git a/config.m4 b/config.m4
new file mode 100644
index 0000000..8527939
--- /dev/null
+++ b/config.m4
@@ -0,0 +1,8 @@
+PHP_ARG_ENABLE([mini_xdebug],
+ [whether to enable mini-xdebug],
+ [AS_HELP_STRING([--enable-mini-xdebug], [Enable mini-xdebug])],
+ [no])
+
+if test "$PHP_MINI_XDEBUG" != "no"; then
+ PHP_NEW_EXTENSION([mini_xdebug], [mini_xdebug.c], [$ext_shared])
+fi
diff --git a/flake.lock b/flake.lock
new file mode 100644
index 0000000..7758994
--- /dev/null
+++ b/flake.lock
@@ -0,0 +1,64 @@
+{
+ "nodes": {
+ "flake-utils": {
+ "inputs": {
+ "systems": [
+ "systems"
+ ]
+ },
+ "locked": {
+ "lastModified": 1731533236,
+ "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
+ "type": "github"
+ },
+ "original": {
+ "owner": "numtide",
+ "repo": "flake-utils",
+ "type": "github"
+ }
+ },
+ "nixpkgs": {
+ "locked": {
+ "lastModified": 1775793324,
+ "narHash": "sha256-omax7atcZbol+6HJ2RLpP+ZCFcPa5bZ65Hn71RufeWQ=",
+ "owner": "NixOS",
+ "repo": "nixpkgs",
+ "rev": "9d29d5f667d7467f98efc31881e824fa586c927e",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NixOS",
+ "ref": "nixpkgs-unstable",
+ "repo": "nixpkgs",
+ "type": "github"
+ }
+ },
+ "root": {
+ "inputs": {
+ "flake-utils": "flake-utils",
+ "nixpkgs": "nixpkgs",
+ "systems": "systems"
+ }
+ },
+ "systems": {
+ "locked": {
+ "lastModified": 1681028828,
+ "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
+ "owner": "nix-systems",
+ "repo": "default",
+ "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
+ "type": "github"
+ },
+ "original": {
+ "owner": "nix-systems",
+ "repo": "default",
+ "type": "github"
+ }
+ }
+ },
+ "root": "root",
+ "version": 7
+}
diff --git a/flake.nix b/flake.nix
new file mode 100644
index 0000000..a149d7b
--- /dev/null
+++ b/flake.nix
@@ -0,0 +1,27 @@
+{
+ description = "A basic flake with a shell";
+ inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
+ inputs.systems.url = "github:nix-systems/default";
+ inputs.flake-utils = {
+ url = "github:numtide/flake-utils";
+ inputs.systems.follows = "systems";
+ };
+
+ outputs =
+ { nixpkgs, flake-utils, ... }:
+ flake-utils.lib.eachDefaultSystem (
+ system:
+ let
+ pkgs = nixpkgs.legacyPackages.${system};
+ in
+ {
+ devShells.default = pkgs.mkShell { packages = [
+ pkgs.autoconf
+ pkgs.bashInteractive
+ pkgs.bison
+ pkgs.pkg-config
+ pkgs.re2c
+ ]; };
+ }
+ );
+}
diff --git a/mini-xdebug b/mini-xdebug
new file mode 100755
index 0000000..9b59f2a
--- /dev/null
+++ b/mini-xdebug
@@ -0,0 +1,3 @@
+#!/bin/sh
+DIR=$(cd "$(dirname "$0")" && pwd)
+php -d "zend_extension=$DIR/modules/mini_xdebug.so" "$@"
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,
+};
diff --git a/test.php b/test.php
new file mode 100644
index 0000000..8c4a7d9
--- /dev/null
+++ b/test.php
@@ -0,0 +1,4 @@
+<?php
+
+echo "Hello, ";
+echo "Odawara!\n";