diff options
-rw-r--r-- | Makefile.frag | 4 | ||||
-rw-r--r-- | config.w32 | 9 | ||||
-rw-r--r-- | phpdbg.c | 49 | ||||
-rw-r--r-- | phpdbg.h | 17 | ||||
-rw-r--r-- | phpdbg_btree.c | 5 | ||||
-rw-r--r-- | phpdbg_watch.c | 40 | ||||
-rw-r--r-- | phpdbg_watch.h | 23 | ||||
-rw-r--r-- | phpdbg_win.c | 81 | ||||
-rw-r--r-- | phpdbg_win.h | 39 |
9 files changed, 213 insertions, 54 deletions
diff --git a/Makefile.frag b/Makefile.frag index 5be6d5b00f..4aebfb40f3 100644 --- a/Makefile.frag +++ b/Makefile.frag @@ -23,6 +23,4 @@ test-phpdbg: @echo "Running phpdbg tests ..." @$(top_builddir)/sapi/cli/php sapi/phpdbg/tests/run-tests.php --phpdbg sapi/phpdbg/phpdbg -.PHONY: clean-phpdbg test-phpdbg - - +.PHONY: clean-phpdbg test-phpdbg
\ No newline at end of file diff --git a/config.w32 b/config.w32 index 5813e7f156..7501847726 100644 --- a/config.w32 +++ b/config.w32 @@ -1,19 +1,18 @@ ARG_ENABLE('phpdbg', 'Build phpdbg', 'yes'); ARG_ENABLE('phpdbgs', 'Build phpdbg shared', 'no'); -PHPDBG_SOURCES='phpdbg.c phpdbg_prompt.c phpdbg_cmd.c phpdbg_info.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_btree.c'; +PHPDBG_SOURCES='phpdbg.c phpdbg_prompt.c phpdbg_cmd.c phpdbg_info.c phpdbg_help.c phpdbg_break.c phpdbg_print.c phpdbg_bp.c phpdbg_opcode.c phpdbg_list.c phpdbg_utils.c phpdbg_set.c phpdbg_frame.c phpdbg_watch.c phpdbg_win.c phpdbg_btree.c'; PHPDBG_DLL='php' + PHP_VERSION + 'phpdbg.dll'; PHPDBG_EXE='phpdbg.exe'; if (PHP_PHPDBG == "yes") { - /* build phpdbg binary */ SAPI('phpdbg', PHPDBG_SOURCES, PHPDBG_EXE); ADD_FLAG("LIBS_PHPDBG", "ws2_32.lib user32.lib"); + DEFINE("CFLAGS", configure_subst.item("CFLAGS") + " /EHa"); } if (PHP_PHPDBGS == "yes") { SAPI('phpdbgs', PHPDBG_SOURCES, PHPDBG_DLL, '/D PHP_PHPDBG_EXPORTS /I win32'); ADD_FLAG("LIBS_PHPDBGS", "ws2_32.lib user32.lib"); -} - - + DEFINE("CFLAGS", configure_subst.item("CFLAGS") + " /EHa"); +}
\ No newline at end of file @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -#ifndef ZEND_SIGNALS +#if !defined(ZEND_SIGNALS) || defined(_WIN32) # include <signal.h> #endif #include "phpdbg.h" @@ -30,14 +30,6 @@ #include "phpdbg_set.h" #include "zend_alloc.h" -/* the beginning (= the important part) of the _zend_mm_heap struct defined in Zend/zend_alloc.c */ -struct _zend_mm_heap { - int use_zend_alloc; - void *(*_malloc)(size_t); - void (*_free)(void*); - void *(*_realloc)(void*, size_t); -}; - /* {{{ remote console headers */ #ifndef _WIN32 # include <sys/socket.h> @@ -818,7 +810,6 @@ int phpdbg_open_sockets(char *address, int port[2], int (*listen)[2], int (*sock return SUCCESS; } /* }}} */ -#endif void phpdbg_signal_handler(int sig, siginfo_t *info, void *context) { int is_handled = FAILURE; @@ -839,6 +830,7 @@ void phpdbg_signal_handler(int sig, siginfo_t *info, void *context) { } } +#endif int main(int argc, char **argv) /* {{{ */ { @@ -877,11 +869,11 @@ int main(int argc, char **argv) /* {{{ */ void ***tsrm_ls; #endif +#ifndef _WIN32 struct sigaction signal_struct; signal_struct.sa_sigaction = phpdbg_signal_handler; signal_struct.sa_flags = SA_SIGINFO | SA_NODEFER; -#ifndef _WIN32 address = strdup("127.0.0.1"); socket[0] = -1; socket[1] = -1; @@ -1154,51 +1146,52 @@ phpdbg_main: phpdbg->ini_entries = ini_entries; if (phpdbg->startup(phpdbg) == SUCCESS) { - +#ifdef _WIN32 + EXCEPTION_POINTERS *xp; + __try { +#endif zend_mm_heap *mm_heap = zend_mm_set_heap(NULL TSRMLS_CC); if (!mm_heap->use_zend_alloc) { free(mm_heap); mm_heap = zend_mm_startup(); } PHPDBG_G(original_free_function) = mm_heap->_free; +#ifdef _WIN32 + phpdbg_win_set_mm_heap(mm_heap); +#else mm_heap->_free = phpdbg_watch_efree; +#endif zend_mm_set_heap(mm_heap TSRMLS_CC); zend_activate(TSRMLS_C); -#ifdef ZEND_SIGNALS +#if defined(ZEND_SIGNALS) && !defined(_WIN32) zend_try { zend_signal_activate(TSRMLS_C); } zend_end_try(); #endif -#ifdef ZEND_SIGNALS +#if defined(ZEND_SIGNALS) && !defined(_WIN32) zend_try { zend_sigaction(SIGSEGV, &signal_struct, &PHPDBG_G(old_sigsegv_signal) TSRMLS_CC); } zend_end_try(); zend_try { zend_sigaction(SIGBUS, &signal_struct, &PHPDBG_G(old_sigsegv_signal) TSRMLS_CC); } zend_end_try(); -#else +#elif !defined(_WIN32) sigaction(SIGSEGV, &signal_struct, &PHPDBG_G(old_sigsegv_signal)); sigaction(SIGBUS, &signal_struct, &PHPDBG_G(old_sigsegv_signal)); #endif /* do not install sigint handlers for remote consoles */ /* sending SIGINT then provides a decent way of shutting down the server */ -#ifdef ZEND_SIGNALS -# ifndef _WIN32 +#if defined(ZEND_SIGNALS) && !defined(_WIN32) if (listen[0] < 0) { -# endif zend_try { zend_signal(SIGINT, phpdbg_sigint_handler TSRMLS_CC); } zend_end_try(); -# ifndef _WIN32 } -# endif -#else -# ifndef _WIN32 +#elif !defined(_WIN32) if (listen[0] < 0) { -# endif +#endif signal(SIGINT, phpdbg_sigint_handler); #ifndef _WIN32 } #endif -#endif PG(modules_activated) = 0; @@ -1284,7 +1277,10 @@ phpdbg_main: } } +/* #ifndef for making compiler shutting up */ +#ifndef _WIN32 phpdbg_interact: +#endif /* phpdbg main() */ do { zend_try { @@ -1377,6 +1373,11 @@ phpdbg_out: } zend_end_try(); sapi_shutdown(); +#ifdef _WIN32 + } __except(phpdbg_exception_handler_win32(xp = GetExceptionInformation())) { + // if !EXCEPTION_CONTINUE_EXECUTION + } + #endif } if (cleaning || remote) { @@ -39,7 +39,9 @@ #include "zend_globals.h" #include "zend_ini_scanner.h" #include "zend_stream.h" -#include "zend_signal.h" +#ifndef _WIN32 +# include "zend_signal.h" +#endif #include "SAPI.h" #include <fcntl.h> #include <sys/types.h> @@ -169,8 +171,10 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg) HashTable seek; /* seek oplines */ phpdbg_frame_t frame; /* frame */ +#ifndef _WIN32 struct sigaction old_sigsegv_signal; /* segv signal handler */ - +#endif + phpdbg_btree watchpoint_tree; /* tree with watchpoints */ HashTable watchpoints; /* watchpoints */ zend_llist watchlist_mem; /* triggered watchpoints */ @@ -196,4 +200,13 @@ ZEND_BEGIN_MODULE_GLOBALS(phpdbg) zend_ulong flags; /* phpdbg flags */ ZEND_END_MODULE_GLOBALS(phpdbg) /* }}} */ +/* the beginning (= the important part) of the _zend_mm_heap struct defined in Zend/zend_alloc.c + Needed for realizing watchpoints */ +struct _zend_mm_heap { + int use_zend_alloc; + void *(*_malloc)(size_t); + void (*_free)(void *); + void *(*_realloc)(void *, size_t); +}; + #endif /* PHPDBG_H */ diff --git a/phpdbg_btree.c b/phpdbg_btree.c index f3b6306a2a..f606135488 100644 --- a/phpdbg_btree.c +++ b/phpdbg_btree.c @@ -24,6 +24,11 @@ #define CHOOSE_BRANCH(n) \ branch = branch->branches[!!(n)]; +#ifdef _Win32 +# define emalloc malloc +# define efree free +#endif + /* depth in bits */ void phpdbg_btree_init(phpdbg_btree *tree, zend_ulong depth) { tree->depth = depth; diff --git a/phpdbg_watch.c b/phpdbg_watch.c index f89b3277ad..0580592513 100644 --- a/phpdbg_watch.c +++ b/phpdbg_watch.c @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -23,12 +23,13 @@ #include "phpdbg_btree.h" #include "phpdbg_watch.h" #include "phpdbg_utils.h" -#include <unistd.h> -#include <sys/mman.h> +#ifndef _WIN32 +# include <unistd.h> +# include <sys/mman.h> +#endif ZEND_EXTERN_MODULE_GLOBALS(phpdbg); -long phpdbg_pagesize; typedef struct { void *page; @@ -40,13 +41,6 @@ typedef struct { #define MEMDUMP_SIZE(size) (sizeof(phpdbg_watch_memdump) - sizeof(void *) + (size)) -static zend_always_inline void *phpdbg_get_page_boundary(void *addr) { - return (void *)((size_t)addr & ~(phpdbg_pagesize - 1)); -} - -static zend_always_inline size_t phpdbg_get_total_page_size(void *addr, size_t size) { - return (size_t)phpdbg_get_page_boundary(addr + size - 1) - (size_t)phpdbg_get_page_boundary(addr) + phpdbg_pagesize; -} static phpdbg_watchpoint_t *phpdbg_check_for_watchpoint(void *addr TSRMLS_DC) { phpdbg_watchpoint_t *watch; @@ -285,7 +279,7 @@ static int phpdbg_delete_watchpoint(phpdbg_watchpoint_t *tmp_watch TSRMLS_DC) { return ret; } -static int phpdbg_watchpoint_parse_input(char *input, size_t len, HashTable *parent, int i, int (*callback)(phpdbg_watchpoint_t * TSRMLS_DC) TSRMLS_DC) { +static int phpdbg_watchpoint_parse_input(char *input, size_t len, HashTable *parent, size_t i, int (*callback)(phpdbg_watchpoint_t * TSRMLS_DC) TSRMLS_DC) { int ret = FAILURE; zend_bool new_index = 1; char *last_index; @@ -456,13 +450,23 @@ int phpdbg_delete_var_watchpoint(char *input, size_t len TSRMLS_DC) { return phpdbg_watchpoint_parse_input(input, len, EG(active_symbol_table), 0, phpdbg_delete_watchpoint TSRMLS_CC); } +#ifdef _WIN32 +int phpdbg_watchpoint_segfault_handler(void *addr TSRMLS_DC) { +#else int phpdbg_watchpoint_segfault_handler(siginfo_t *info, void *context TSRMLS_DC) { +#endif void *page; phpdbg_watch_memdump *dump; phpdbg_watchpoint_t *watch; size_t size; - watch = phpdbg_check_for_watchpoint(info->si_addr TSRMLS_CC); + watch = phpdbg_check_for_watchpoint( +#ifdef _WIN32 + addr +#else + info->si_addr +#endif + TSRMLS_CC); if (watch == NULL) { return FAILURE; @@ -506,12 +510,12 @@ static void phpdbg_watch_dtor(void *pDest) { static void phpdbg_watch_mem_dtor(void *llist_data) { phpdbg_watch_memdump *dump = *(phpdbg_watch_memdump **)llist_data; - free(*(void **)llist_data); - /* Disble writing again */ if (dump->reenable_writing) { - mprotect(dump->page, dump->size, PROT_NONE | PROT_READ); + mprotect(dump->page, dump->size, PROT_READ); } + + free(*(void **)llist_data); } void phpdbg_setup_watchpoints(TSRMLS_D) { @@ -668,10 +672,10 @@ void phpdbg_watch_efree(void *ptr) { if (result) { phpdbg_watchpoint_t *watch = result->ptr; - if (watch->addr.ptr + watch->size > ptr) { + if ((size_t)watch->addr.ptr + watch->size > (size_t)ptr) { zend_hash_del(&PHPDBG_G(watchpoints), watch->str, watch->str_len); } } PHPDBG_G(original_free_function)(ptr); -} +}
\ No newline at end of file diff --git a/phpdbg_watch.h b/phpdbg_watch.h index 1aa3ad75b0..71402ae803 100644 --- a/phpdbg_watch.h +++ b/phpdbg_watch.h @@ -2,7 +2,7 @@ +----------------------------------------------------------------------+ | PHP Version 5 | +----------------------------------------------------------------------+ - | Copyright (c) 1997-2013 The PHP Group | + | Copyright (c) 1997-2014 The PHP Group | +----------------------------------------------------------------------+ | This source file is subject to version 3.01 of the PHP license, | | that is bundled with this package in the file LICENSE, and is | @@ -24,6 +24,10 @@ #include "TSRM.h" #include "phpdbg_cmd.h" +#ifdef _WIN32 +# include "phpdbg_win.h" +#endif + #define PHPDBG_WATCH(name) PHPDBG_COMMAND(watch_##name) /** @@ -76,7 +80,11 @@ struct _phpdbg_watchpoint_t { void phpdbg_setup_watchpoints(TSRMLS_D); +#ifndef _WIN32 int phpdbg_watchpoint_segfault_handler(siginfo_t *info, void *context TSRMLS_DC); +#else +int phpdbg_watchpoint_segfault_handler(void *addr TSRMLS_DC); +#endif void phpdbg_create_addr_watchpoint(void *addr, size_t size, phpdbg_watchpoint_t *watch); void phpdbg_create_zval_watchpoint(zval *zv, phpdbg_watchpoint_t *watch); @@ -90,4 +98,15 @@ void phpdbg_list_watchpoints(TSRMLS_D); void phpdbg_watch_efree(void *ptr); -#endif + +long phpdbg_pagesize; + +static zend_always_inline void *phpdbg_get_page_boundary(void *addr) { + return (void *)((size_t)addr & ~(phpdbg_pagesize - 1)); +} + +static zend_always_inline size_t phpdbg_get_total_page_size(void *addr, size_t size) { + return (size_t)phpdbg_get_page_boundary((void *)((size_t)addr + size - 1)) - (size_t)phpdbg_get_page_boundary(addr) + phpdbg_pagesize; +} + +#endif
\ No newline at end of file diff --git a/phpdbg_win.c b/phpdbg_win.c new file mode 100644 index 0000000000..29f80449fa --- /dev/null +++ b/phpdbg_win.c @@ -0,0 +1,81 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena <felipe@php.net> | + | Authors: Joe Watkins <joe.watkins@live.co.uk> | + | Authors: Bob Weinand <bwoebi@php.net> | + +----------------------------------------------------------------------+ +*/ + +#include "zend.h" +#include "phpdbg.h" + +phpdbg_btree phpdbg_memory_tree; + +int mprotect(void *addr, size_t size, int protection) { + int var; + //printf("Set protection of %p to %s\n", addr, protection == (PROT_READ | PROT_WRITE) ? "rw": "r-"); + return (int)VirtualProtect(addr, size, protection == (PROT_READ | PROT_WRITE) ? PAGE_READWRITE : PAGE_READONLY, &var); +} + +size_t virtual_size(void *ptr) { + return (size_t)phpdbg_btree_find(&phpdbg_memory_tree, (zend_ulong)ptr)->ptr; +} + +void *virtual_malloc(size_t size) { + size_t real_size = phpdbg_get_total_page_size(NULL, size); + void *addr = VirtualAlloc(NULL, real_size, MEM_COMMIT, PAGE_READWRITE); + phpdbg_btree_insert(&phpdbg_memory_tree, (zend_ulong)addr, (void *)real_size); + return addr; +} + +void virtual_free(void *ptr) { + phpdbg_watch_efree(ptr); + VirtualFree(ptr, virtual_size(ptr), MEM_RELEASE); + phpdbg_btree_delete(&phpdbg_memory_tree, (zend_ulong)ptr); +} + +void *virtual_realloc(void *ptr, size_t size) { + void *ret; + size_t original_size = virtual_size(ptr); + + if (original_size >= size) { + return ptr; + } + + ret = virtual_malloc(size); + memcpy(ret, ptr, original_size); + virtual_free(ptr); + return ret; +} + +void phpdbg_win_set_mm_heap(zend_mm_heap *heap) { + phpdbg_btree_init(&phpdbg_memory_tree, sizeof(void *) * 8); + heap->_free = virtual_free; + heap->_realloc = virtual_realloc; + heap->_malloc = virtual_malloc; +} + +int phpdbg_exception_handler_win32(EXCEPTION_POINTERS *xp) { + EXCEPTION_RECORD *xr = xp->ExceptionRecord; + CONTEXT *xc = xp->ContextRecord; + if(xr->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { + TSRMLS_FETCH(); + //printf("Watchpoint hit at: %p\n", xr->ExceptionInformation[1]); + if (phpdbg_watchpoint_segfault_handler((void *)xr->ExceptionInformation[1] TSRMLS_CC) == SUCCESS) { + return EXCEPTION_CONTINUE_EXECUTION; + } + } + return EXCEPTION_CONTINUE_SEARCH; +}
\ No newline at end of file diff --git a/phpdbg_win.h b/phpdbg_win.h new file mode 100644 index 0000000000..da97c797b1 --- /dev/null +++ b/phpdbg_win.h @@ -0,0 +1,39 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2014 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Felipe Pena <felipe@php.net> | + | Authors: Joe Watkins <joe.watkins@live.co.uk> | + | Authors: Bob Weinand <bwoebi@php.net> | + +----------------------------------------------------------------------+ +*/ + +#ifndef PHPDBG_WIN_H +#define PHPDBG_WIN_H + +#include "winbase.h" +#include "windows.h" +#include "excpt.h" + +#define PROT_READ 1 +#define PROT_WRITE 2 + +int mprotect(void *addr, size_t size, int protection); + +void phpdbg_win_set_mm_heap(zend_mm_heap *heap); + +int phpdbg_exception_handler_win32(EXCEPTION_POINTERS *xp); + +int __stdcall phpdbg_watch_set_segv_handler_asm(); + +#endif
\ No newline at end of file |