php-src/phpdbg.c

1407 lines
36 KiB
C
Raw Normal View History

2013-11-09 22:35:03 +00:00
/*
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
2014-01-17 22:09:07 +00:00
| Copyright (c) 1997-2014 The PHP Group |
2013-11-09 22:35:03 +00:00
+----------------------------------------------------------------------+
| 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. |
+----------------------------------------------------------------------+
2013-11-17 12:40:51 +00:00
| Authors: Felipe Pena <felipe@php.net> |
2013-11-09 22:35:03 +00:00
| Authors: Joe Watkins <joe.watkins@live.co.uk> |
2013-12-23 22:55:07 +00:00
| Authors: Bob Weinand <bwoebi@php.net> |
2013-11-09 22:35:03 +00:00
+----------------------------------------------------------------------+
*/
2013-11-09 23:07:04 +00:00
#if !defined(ZEND_SIGNALS) || defined(_WIN32)
# include <signal.h>
#endif
#include "phpdbg.h"
2013-11-10 19:15:32 +00:00
#include "phpdbg_prompt.h"
2013-11-10 21:38:58 +00:00
#include "phpdbg_bp.h"
2013-11-15 16:24:22 +00:00
#include "phpdbg_break.h"
#include "phpdbg_list.h"
#include "phpdbg_utils.h"
2013-11-24 14:54:14 +00:00
#include "phpdbg_set.h"
#include "zend_alloc.h"
/* {{{ remote console headers */
2013-11-28 17:21:34 +00:00
#ifndef _WIN32
# include <sys/socket.h>
# include <sys/select.h>
# include <sys/time.h>
# include <sys/types.h>
# include <unistd.h>
# include <arpa/inet.h>
#endif /* }}} */
2013-11-27 16:49:51 +00:00
ZEND_DECLARE_MODULE_GLOBALS(phpdbg);
2013-12-05 11:20:16 +00:00
static zend_bool phpdbg_booted = 0;
2013-11-15 11:19:26 +00:00
#if PHP_VERSION_ID >= 50500
2013-11-10 13:01:46 +00:00
void (*zend_execute_old)(zend_execute_data *execute_data TSRMLS_DC);
2013-11-15 11:19:26 +00:00
#else
void (*zend_execute_old)(zend_op_array *op_array TSRMLS_DC);
#endif
2013-11-10 13:01:46 +00:00
2013-11-10 15:47:28 +00:00
static inline void php_phpdbg_globals_ctor(zend_phpdbg_globals *pg) /* {{{ */
{
pg->prompt[0] = NULL;
pg->prompt[1] = NULL;
2013-11-24 19:41:00 +00:00
pg->colors[0] = NULL;
pg->colors[1] = NULL;
pg->colors[2] = NULL;
2013-11-24 19:41:00 +00:00
2013-11-23 17:30:10 +00:00
pg->exec = NULL;
pg->exec_len = 0;
pg->ops = NULL;
pg->vmret = 0;
pg->bp_count = 0;
pg->lcmd = NULL;
pg->flags = PHPDBG_DEFAULT_FLAGS;
pg->oplog = NULL;
pg->io[PHPDBG_STDIN] = NULL;
pg->io[PHPDBG_STDOUT] = NULL;
pg->io[PHPDBG_STDERR] = NULL;
memset(&pg->lparam, 0, sizeof(phpdbg_param_t));
pg->frame.num = 0;
2013-11-10 15:47:28 +00:00
} /* }}} */
2013-11-10 15:47:28 +00:00
static PHP_MINIT_FUNCTION(phpdbg) /* {{{ */
{
2013-11-23 17:30:10 +00:00
ZEND_INIT_MODULE_GLOBALS(phpdbg, php_phpdbg_globals_ctor, NULL);
2013-11-15 11:19:26 +00:00
#if PHP_VERSION_ID >= 50500
2013-11-23 17:30:10 +00:00
zend_execute_old = zend_execute_ex;
zend_execute_ex = phpdbg_execute_ex;
2013-11-15 11:19:26 +00:00
#else
2013-11-23 17:30:10 +00:00
zend_execute_old = zend_execute;
zend_execute = phpdbg_execute_ex;
2013-11-15 11:19:26 +00:00
#endif
2013-11-10 14:36:30 +00:00
2013-12-18 16:33:21 +00:00
REGISTER_STRINGL_CONSTANT("PHPDBG_VERSION", PHPDBG_VERSION, sizeof(PHPDBG_VERSION)-1, CONST_CS|CONST_PERSISTENT);
2013-11-26 10:02:58 +00:00
REGISTER_LONG_CONSTANT("PHPDBG_FILE", FILE_PARAM, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PHPDBG_METHOD", METHOD_PARAM, CONST_CS|CONST_PERSISTENT);
2013-11-23 17:30:10 +00:00
REGISTER_LONG_CONSTANT("PHPDBG_LINENO", NUMERIC_PARAM, CONST_CS|CONST_PERSISTENT);
2013-11-26 10:02:58 +00:00
REGISTER_LONG_CONSTANT("PHPDBG_FUNC", STR_PARAM, CONST_CS|CONST_PERSISTENT);
2013-11-15 16:24:22 +00:00
2013-11-24 20:00:56 +00:00
REGISTER_LONG_CONSTANT("PHPDBG_COLOR_PROMPT", PHPDBG_COLOR_PROMPT, CONST_CS|CONST_PERSISTENT);
REGISTER_LONG_CONSTANT("PHPDBG_COLOR_NOTICE", PHPDBG_COLOR_NOTICE, CONST_CS|CONST_PERSISTENT);
2013-11-26 10:02:58 +00:00
REGISTER_LONG_CONSTANT("PHPDBG_COLOR_ERROR", PHPDBG_COLOR_ERROR, CONST_CS|CONST_PERSISTENT);
2013-11-23 17:30:10 +00:00
return SUCCESS;
2013-11-10 15:47:28 +00:00
} /* }}} */
2013-11-10 14:36:30 +00:00
2013-11-10 21:38:58 +00:00
static void php_phpdbg_destroy_bp_file(void *brake) /* {{{ */
2013-11-10 15:47:28 +00:00
{
zend_hash_destroy((HashTable*)brake);
2013-11-10 15:47:28 +00:00
} /* }}} */
2013-11-10 21:38:58 +00:00
static void php_phpdbg_destroy_bp_symbol(void *brake) /* {{{ */
{
efree((char*)((phpdbg_breaksymbol_t*)brake)->symbol);
2013-11-10 21:38:58 +00:00
} /* }}} */
static void php_phpdbg_destroy_bp_opcode(void *brake) /* {{{ */
{
efree((char*)((phpdbg_breakop_t*)brake)->name);
} /* }}} */
static void php_phpdbg_destroy_bp_methods(void *brake) /* {{{ */
{
2013-11-23 17:30:10 +00:00
zend_hash_destroy((HashTable*)brake);
} /* }}} */
2013-11-13 14:22:01 +00:00
static void php_phpdbg_destroy_bp_condition(void *data) /* {{{ */
{
2013-11-23 17:30:10 +00:00
phpdbg_breakcond_t *brake = (phpdbg_breakcond_t*) data;
if (brake) {
if (brake->ops) {
TSRMLS_FETCH();
destroy_op_array(
brake->ops TSRMLS_CC);
efree(brake->ops);
}
efree((char*)brake->code);
2013-11-23 17:30:10 +00:00
}
2013-11-13 14:22:01 +00:00
} /* }}} */
static void php_phpdbg_destroy_registered(void *data) /* {{{ */
2013-11-19 01:18:43 +00:00
{
zend_function *function = (zend_function*) data;
2014-01-17 22:09:07 +00:00
TSRMLS_FETCH();
2013-11-20 13:28:41 +00:00
2013-11-19 01:18:43 +00:00
destroy_zend_function(
function TSRMLS_CC);
} /* }}} */
2013-11-19 01:18:43 +00:00
2013-11-18 17:51:14 +00:00
static PHP_RINIT_FUNCTION(phpdbg) /* {{{ */
2013-11-20 13:28:41 +00:00
{
2013-11-12 01:51:50 +00:00
zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], 8, NULL, php_phpdbg_destroy_bp_file, 0);
zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], 8, NULL, php_phpdbg_destroy_bp_symbol, 0);
2013-11-28 20:36:45 +00:00
zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
2013-11-23 17:30:10 +00:00
zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], 8, NULL, NULL, 0);
zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], 8, NULL, php_phpdbg_destroy_bp_opcode, 0);
2013-11-23 17:30:10 +00:00
zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], 8, NULL, php_phpdbg_destroy_bp_condition, 0);
zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], 8, NULL, NULL, 0);
phpdbg_setup_watchpoints(TSRMLS_C);
2013-11-18 03:18:37 +00:00
zend_hash_init(&PHPDBG_G(seek), 8, NULL, NULL, 0);
2013-11-19 01:18:43 +00:00
zend_hash_init(&PHPDBG_G(registered), 8, NULL, php_phpdbg_destroy_registered, 0);
2013-11-20 13:28:41 +00:00
2013-11-10 14:36:30 +00:00
return SUCCESS;
2013-11-10 15:47:28 +00:00
} /* }}} */
2013-11-10 15:47:28 +00:00
static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */
{
2013-11-23 17:30:10 +00:00
zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE]);
zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM]);
zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE]);
zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE]);
zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE]);
2013-11-23 17:30:10 +00:00
zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]);
2013-11-23 23:14:16 +00:00
zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE]);
2013-11-23 17:30:10 +00:00
zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD]);
zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_COND]);
zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP]);
2013-11-18 03:18:37 +00:00
zend_hash_destroy(&PHPDBG_G(seek));
2013-11-19 01:18:43 +00:00
zend_hash_destroy(&PHPDBG_G(registered));
zend_hash_destroy(&PHPDBG_G(watchpoints));
zend_llist_destroy(&PHPDBG_G(watchlist_mem));
2013-11-20 13:28:41 +00:00
2013-11-23 17:30:10 +00:00
if (PHPDBG_G(exec)) {
efree(PHPDBG_G(exec));
PHPDBG_G(exec) = NULL;
}
2013-11-14 21:39:59 +00:00
if (PHPDBG_G(prompt)[0]) {
free(PHPDBG_G(prompt)[0]);
2013-11-24 14:54:14 +00:00
}
if (PHPDBG_G(prompt)[1]) {
free(PHPDBG_G(prompt)[1]);
}
2013-11-24 19:41:00 +00:00
PHPDBG_G(prompt)[0] = NULL;
PHPDBG_G(prompt)[1] = NULL;
2013-11-23 17:30:10 +00:00
if (PHPDBG_G(oplog)) {
fclose(
PHPDBG_G(oplog));
PHPDBG_G(oplog) = NULL;
}
2013-11-10 14:36:30 +00:00
2013-11-23 17:30:10 +00:00
if (PHPDBG_G(ops)) {
destroy_op_array(PHPDBG_G(ops) TSRMLS_CC);
efree(PHPDBG_G(ops));
PHPDBG_G(ops) = NULL;
}
2013-11-14 21:39:59 +00:00
2013-11-23 17:30:10 +00:00
return SUCCESS;
2013-11-10 15:47:28 +00:00
} /* }}} */
2013-11-09 22:35:03 +00:00
2013-12-15 13:55:03 +00:00
/* {{{ proto mixed phpdbg_exec(string context)
Attempt to set the execution context for phpdbg
If the execution context was set previously it is returned
2013-12-15 13:55:03 +00:00
If the execution context was not set previously boolean true is returned
If the request to set the context fails, boolean false is returned, and an E_WARNING raised */
2013-12-15 13:55:03 +00:00
static PHP_FUNCTION(phpdbg_exec)
{
char *exec = NULL;
zend_ulong exec_len = 0L;
2013-12-15 13:55:03 +00:00
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &exec, &exec_len) == FAILURE) {
return;
}
2013-12-15 13:55:03 +00:00
{
struct stat sb;
zend_bool result = 1;
2013-12-15 13:55:03 +00:00
if (VCWD_STAT(exec, &sb) != FAILURE) {
if (sb.st_mode & (S_IFREG|S_IFLNK)) {
if (PHPDBG_G(exec)) {
ZVAL_STRINGL(return_value, PHPDBG_G(exec), PHPDBG_G(exec_len), 1);
efree(PHPDBG_G(exec));
result = 0;
}
2013-12-15 13:55:03 +00:00
PHPDBG_G(exec) = estrndup(exec, exec_len);
PHPDBG_G(exec_len) = exec_len;
2013-12-15 13:55:03 +00:00
if (result)
ZVAL_BOOL(return_value, 1);
} else {
zend_error(
E_WARNING, "Failed to set execution context (%s), not a regular file or symlink", exec);
ZVAL_BOOL(return_value, 0);
}
} else {
zend_error(
E_WARNING, "Failed to set execution context (%s) the file does not exist", exec);
ZVAL_BOOL(return_value, 0);
}
}
} /* }}} */
2013-11-15 16:22:20 +00:00
/* {{{ proto void phpdbg_break([integer type, string expression])
instructs phpdbg to insert a breakpoint at the next opcode */
2013-11-11 15:14:37 +00:00
static PHP_FUNCTION(phpdbg_break)
2013-11-11 14:33:53 +00:00
{
2013-11-23 17:30:10 +00:00
if (ZEND_NUM_ARGS() > 0) {
long type;
char *expr = NULL;
zend_uint expr_len = 0;
phpdbg_param_t param;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &type, &expr, &expr_len) == FAILURE) {
return;
}
2013-11-17 12:40:51 +00:00
2013-11-23 17:30:10 +00:00
phpdbg_parse_param(expr, expr_len, &param TSRMLS_CC);
2013-11-17 12:40:51 +00:00
2013-11-23 17:30:10 +00:00
switch (type) {
case METHOD_PARAM:
phpdbg_do_break_method(&param, NULL TSRMLS_CC);
break;
2013-11-15 16:24:22 +00:00
2013-11-23 17:30:10 +00:00
case FILE_PARAM:
phpdbg_do_break_file(&param, NULL TSRMLS_CC);
break;
2013-11-15 16:24:22 +00:00
2013-11-23 17:30:10 +00:00
case NUMERIC_PARAM:
phpdbg_do_break_lineno(&param, NULL TSRMLS_CC);
break;
2013-11-15 16:24:22 +00:00
2013-11-23 17:30:10 +00:00
case STR_PARAM:
phpdbg_do_break_func(&param, NULL TSRMLS_CC);
break;
2013-11-15 16:24:22 +00:00
2013-11-23 17:30:10 +00:00
default: zend_error(
E_WARNING, "unrecognized parameter type %ld", type);
}
2013-11-17 12:40:51 +00:00
2013-11-23 17:30:10 +00:00
phpdbg_clear_param(&param TSRMLS_CC);
2013-11-17 12:40:51 +00:00
2013-11-23 17:30:10 +00:00
} else if (EG(current_execute_data) && EG(active_op_array)) {
zend_ulong opline_num = (EG(current_execute_data)->opline -
EG(active_op_array)->opcodes);
2013-11-23 17:30:10 +00:00
phpdbg_set_breakpoint_opline_ex(
&EG(active_op_array)->opcodes[opline_num+1] TSRMLS_CC);
}
2013-11-11 14:33:53 +00:00
} /* }}} */
2013-11-11 15:14:37 +00:00
/* {{{ proto void phpdbg_clear(void)
2013-11-23 17:30:10 +00:00
instructs phpdbg to clear breakpoints */
2013-11-11 15:14:37 +00:00
static PHP_FUNCTION(phpdbg_clear)
{
2013-11-23 17:30:10 +00:00
zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE]);
zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM]);
zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE]);
zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE]);
zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE]);
2013-11-23 17:30:10 +00:00
zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]);
zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD]);
zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_COND]);
2013-11-11 15:14:37 +00:00
} /* }}} */
2013-11-24 20:00:56 +00:00
/* {{{ proto void phpdbg_color(integer element, string color) */
static PHP_FUNCTION(phpdbg_color)
{
long element;
char *color;
zend_uint color_len;
2013-11-24 20:00:56 +00:00
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &element, &color, &color_len) == FAILURE) {
return;
}
2013-11-24 20:00:56 +00:00
switch (element) {
case PHPDBG_COLOR_NOTICE:
case PHPDBG_COLOR_ERROR:
case PHPDBG_COLOR_PROMPT:
phpdbg_set_color_ex(element, color, color_len TSRMLS_CC);
break;
2013-11-24 20:00:56 +00:00
default: zend_error(E_ERROR, "phpdbg detected an incorrect color constant");
}
} /* }}} */
/* {{{ proto void phpdbg_prompt(string prompt) */
static PHP_FUNCTION(phpdbg_prompt)
2013-11-24 20:00:56 +00:00
{
char *prompt;
zend_uint prompt_len;
2013-11-24 20:00:56 +00:00
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &prompt, &prompt_len) == FAILURE) {
return;
}
2013-11-24 20:00:56 +00:00
phpdbg_set_prompt(prompt TSRMLS_CC);
} /* }}} */
ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_arginfo, 0, 0, 0)
2013-11-23 17:30:10 +00:00
ZEND_ARG_INFO(0, type)
ZEND_ARG_INFO(0, expression)
2013-11-15 16:22:20 +00:00
ZEND_END_ARG_INFO()
2013-11-24 20:00:56 +00:00
ZEND_BEGIN_ARG_INFO_EX(phpdbg_color_arginfo, 0, 0, 0)
ZEND_ARG_INFO(0, element)
ZEND_ARG_INFO(0, color)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(phpdbg_prompt_arginfo, 0, 0, 0)
ZEND_ARG_INFO(0, string)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(phpdbg_exec_arginfo, 0, 0, 0)
ZEND_ARG_INFO(0, context)
ZEND_END_ARG_INFO()
2013-11-24 20:00:56 +00:00
ZEND_BEGIN_ARG_INFO_EX(phpdbg_clear_arginfo, 0, 0, 0)
2013-11-15 16:22:20 +00:00
ZEND_END_ARG_INFO()
2013-11-24 20:00:56 +00:00
zend_function_entry phpdbg_user_functions[] = {
PHP_FE(phpdbg_clear, phpdbg_clear_arginfo)
PHP_FE(phpdbg_break, phpdbg_break_arginfo)
PHP_FE(phpdbg_exec, phpdbg_exec_arginfo)
2013-11-24 20:00:56 +00:00
PHP_FE(phpdbg_color, phpdbg_color_arginfo)
PHP_FE(phpdbg_prompt, phpdbg_prompt_arginfo)
2013-11-11 14:33:53 +00:00
#ifdef PHP_FE_END
PHP_FE_END
#else
{NULL,NULL,NULL}
#endif
};
2013-11-09 22:47:39 +00:00
static zend_module_entry sapi_phpdbg_module_entry = {
2013-11-09 22:35:03 +00:00
STANDARD_MODULE_HEADER,
2013-11-28 20:36:45 +00:00
PHPDBG_NAME,
2013-11-11 14:33:53 +00:00
phpdbg_user_functions,
PHP_MINIT(phpdbg),
2013-11-09 22:35:03 +00:00
NULL,
PHP_RINIT(phpdbg),
PHP_RSHUTDOWN(phpdbg),
2013-11-09 22:35:03 +00:00
NULL,
2013-11-28 20:36:45 +00:00
PHPDBG_VERSION,
2013-11-09 22:35:03 +00:00
STANDARD_MODULE_PROPERTIES
};
2013-11-09 23:07:04 +00:00
static inline int php_sapi_phpdbg_module_startup(sapi_module_struct *module) /* {{{ */
{
2013-11-23 17:30:10 +00:00
if (php_module_startup(module, &sapi_phpdbg_module_entry, 1) == FAILURE) {
2013-11-09 22:35:03 +00:00
return FAILURE;
}
2013-12-15 13:55:03 +00:00
2013-12-05 11:20:16 +00:00
phpdbg_booted=1;
2013-12-15 13:55:03 +00:00
2013-11-09 22:35:03 +00:00
return SUCCESS;
} /* }}} */
2013-11-12 21:40:15 +00:00
static char* php_sapi_phpdbg_read_cookies(TSRMLS_D) /* {{{ */
{
2013-11-23 17:30:10 +00:00
return NULL;
2013-11-10 22:44:28 +00:00
} /* }}} */
static int php_sapi_phpdbg_header_handler(sapi_header_struct *h, sapi_header_op_enum op, sapi_headers_struct *s TSRMLS_DC) /* {{{ */
{
return 0;
}
/* }}} */
static int php_sapi_phpdbg_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC) /* {{{ */
{
/* We do nothing here, this function is needed to prevent that the fallback
* header handling is called. */
return SAPI_HEADER_SENT_SUCCESSFULLY;
}
/* }}} */
static void php_sapi_phpdbg_send_header(sapi_header_struct *sapi_header, void *server_context TSRMLS_DC) /* {{{ */
{
}
/* }}} */
static void php_sapi_phpdbg_log_message(char *message TSRMLS_DC) /* {{{ */
{
2013-12-05 11:20:16 +00:00
/*
* We must not request TSRM before being boot
*/
if (phpdbg_booted) {
phpdbg_error("%s", message);
2013-12-21 21:42:11 +00:00
switch (PG(last_error_type)) {
case E_ERROR:
case E_CORE_ERROR:
case E_COMPILE_ERROR:
case E_USER_ERROR:
case E_PARSE:
case E_RECOVERABLE_ERROR:
if (!(PHPDBG_G(flags) & PHPDBG_IN_EVAL)) {
phpdbg_list_file(
zend_get_executed_filename(TSRMLS_C),
3,
zend_get_executed_lineno(TSRMLS_C)-1,
zend_get_executed_lineno(TSRMLS_C)
TSRMLS_CC
);
}
do {
switch (phpdbg_interactive(TSRMLS_C)) {
case PHPDBG_LEAVE:
case PHPDBG_FINISH:
case PHPDBG_UNTIL:
case PHPDBG_NEXT:
return;
}
} while (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING));
}
2013-12-05 11:20:16 +00:00
} else fprintf(stdout, "%s\n", message);
2013-11-10 22:44:28 +00:00
}
/* }}} */
static int php_sapi_phpdbg_deactivate(TSRMLS_D) /* {{{ */
{
fflush(stdout);
if(SG(request_info).argv0) {
free(SG(request_info).argv0);
SG(request_info).argv0 = NULL;
}
return SUCCESS;
}
/* }}} */
2013-11-10 23:30:52 +00:00
static void php_sapi_phpdbg_register_vars(zval *track_vars_array TSRMLS_DC) /* {{{ */
{
unsigned int len;
char *docroot = "";
/* In phpdbg mode, we consider the environment to be a part of the server variables
2013-11-23 17:30:10 +00:00
*/
php_import_environment_variables(track_vars_array TSRMLS_CC);
if (PHPDBG_G(exec)) {
len = PHPDBG_G(exec_len);
if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF",
&PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) {
php_register_variable("PHP_SELF", PHPDBG_G(exec),
track_vars_array TSRMLS_CC);
}
if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_NAME",
&PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) {
php_register_variable("SCRIPT_NAME", PHPDBG_G(exec),
track_vars_array TSRMLS_CC);
}
if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_FILENAME",
&PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) {
php_register_variable("SCRIPT_FILENAME", PHPDBG_G(exec),
track_vars_array TSRMLS_CC);
}
if (sapi_module.input_filter(PARSE_SERVER, "PATH_TRANSLATED",
&PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) {
php_register_variable("PATH_TRANSLATED", PHPDBG_G(exec),
track_vars_array TSRMLS_CC);
}
}
/* any old docroot will doo */
len = 0U;
if (sapi_module.input_filter(PARSE_SERVER, "DOCUMENT_ROOT",
&docroot, len, &len TSRMLS_CC)) {
php_register_variable("DOCUMENT_ROOT", docroot, track_vars_array TSRMLS_CC);
}
2013-11-10 23:30:52 +00:00
}
/* }}} */
static inline int php_sapi_phpdbg_ub_write(const char *message, unsigned int length TSRMLS_DC) /* {{{ */
{
2013-11-23 17:36:33 +00:00
return phpdbg_write("%s", message);
} /* }}} */
2013-12-18 10:31:14 +00:00
#if PHP_VERSION_ID >= 50700
static inline void php_sapi_phpdbg_flush(void *context TSRMLS_DC) /* {{{ */
{
#else
static inline void php_sapi_phpdbg_flush(void *context) /* {{{ */
{
2013-11-22 16:15:24 +00:00
TSRMLS_FETCH();
2013-12-18 10:31:14 +00:00
#endif
2013-11-23 16:45:03 +00:00
2013-11-22 16:15:24 +00:00
fflush(PHPDBG_G(io)[PHPDBG_STDOUT]);
} /* }}} */
2013-11-09 22:47:39 +00:00
/* {{{ sapi_module_struct phpdbg_sapi_module
2013-11-23 17:30:10 +00:00
*/
2013-11-09 22:47:39 +00:00
static sapi_module_struct phpdbg_sapi_module = {
2013-11-26 10:02:58 +00:00
"phpdbg", /* name */
"phpdbg", /* pretty name */
2013-11-09 22:35:03 +00:00
2013-11-26 10:02:58 +00:00
php_sapi_phpdbg_module_startup, /* startup */
2013-11-09 22:35:03 +00:00
php_module_shutdown_wrapper, /* shutdown */
2013-11-26 10:02:58 +00:00
NULL, /* activate */
php_sapi_phpdbg_deactivate, /* deactivate */
2013-11-09 22:35:03 +00:00
2013-11-26 10:02:58 +00:00
php_sapi_phpdbg_ub_write, /* unbuffered write */
php_sapi_phpdbg_flush, /* flush */
NULL, /* get uid */
NULL, /* getenv */
2013-11-09 22:35:03 +00:00
2013-11-26 10:02:58 +00:00
php_error, /* error handler */
2013-11-09 22:35:03 +00:00
2013-11-26 10:02:58 +00:00
php_sapi_phpdbg_header_handler, /* header handler */
php_sapi_phpdbg_send_headers, /* send headers handler */
php_sapi_phpdbg_send_header, /* send header handler */
2013-11-09 22:35:03 +00:00
2013-11-26 10:02:58 +00:00
NULL, /* read POST data */
2013-11-10 22:44:28 +00:00
php_sapi_phpdbg_read_cookies, /* read Cookies */
2013-11-09 22:35:03 +00:00
2013-11-26 10:02:58 +00:00
php_sapi_phpdbg_register_vars, /* register server variables */
php_sapi_phpdbg_log_message, /* Log message */
NULL, /* Get request time */
NULL, /* Child terminate */
2013-11-09 22:35:03 +00:00
STANDARD_SAPI_MODULE_PROPERTIES
};
/* }}} */
2013-11-10 22:01:40 +00:00
const opt_struct OPTIONS[] = { /* {{{ */
2013-11-12 21:40:15 +00:00
{'c', 1, "ini path override"},
{'d', 1, "define ini entry on command line"},
{'n', 0, "no php.ini"},
{'z', 1, "load zend_extension"},
/* phpdbg options */
2013-11-20 14:35:25 +00:00
{'q', 0, "no banner"},
2013-11-12 21:40:15 +00:00
{'e', 1, "exec"},
{'v', 0, "disable quietness"},
{'s', 0, "enable stepping"},
2013-11-12 21:40:15 +00:00
{'b', 0, "boring colours"},
{'i', 1, "specify init"},
{'I', 0, "ignore init"},
{'O', 1, "opline log"},
2013-11-20 16:19:37 +00:00
{'r', 0, "run"},
2013-11-20 17:01:37 +00:00
{'E', 0, "step-through-eval"},
2013-12-02 14:45:41 +00:00
{'S', 1, "sapi-name"},
#ifndef _WIN32
2013-11-27 16:49:51 +00:00
{'l', 1, "listen"},
2013-11-29 19:42:41 +00:00
{'a', 1, "address-or-any"},
#endif
{'V', 0, "version"},
2013-11-12 21:40:15 +00:00
{'-', 0, NULL}
2013-11-10 17:45:06 +00:00
}; /* }}} */
2013-11-10 22:44:28 +00:00
const char phpdbg_ini_hardcoded[] =
2013-11-23 17:30:10 +00:00
"html_errors=Off\n"
"register_argc_argv=On\n"
"implicit_flush=On\n"
"display_errors=Off\n"
"log_errors=On\n"
"max_execution_time=0\n"
"max_input_time=-1\n"
"error_log=\n\0";
2013-11-10 22:44:28 +00:00
2013-11-10 17:45:06 +00:00
/* overwriteable ini defaults must be set in phpdbg_ini_defaults() */
2013-11-26 10:02:58 +00:00
#define INI_DEFAULT(name, value) \
Z_SET_REFCOUNT(tmp, 0); \
Z_UNSET_ISREF(tmp); \
ZVAL_STRINGL(&tmp, zend_strndup(value, sizeof(value)-1), sizeof(value)-1, 0); \
zend_hash_update(configuration_hash, name, sizeof(name), &tmp, sizeof(zval), NULL);
2013-11-10 17:45:06 +00:00
2013-11-12 21:40:15 +00:00
void phpdbg_ini_defaults(HashTable *configuration_hash) /* {{{ */
{
2013-11-23 17:30:10 +00:00
zval tmp;
2013-11-10 17:45:06 +00:00
INI_DEFAULT("report_zend_debug", "0");
} /* }}} */
static void phpdbg_welcome(zend_bool cleaning TSRMLS_DC) /* {{{ */
{
2013-11-23 17:30:10 +00:00
/* print blurb */
if (!cleaning) {
phpdbg_notice("Welcome to phpdbg, the interactive PHP debugger, v%s",
2013-11-23 17:30:10 +00:00
PHPDBG_VERSION);
phpdbg_writeln("To get help using phpdbg type \"help\" and press enter");
phpdbg_notice("Please report bugs to <%s>", PHPDBG_ISSUES);
} else {
phpdbg_notice("Clean Execution Environment");
phpdbg_writeln("Classes\t\t\t%d", zend_hash_num_elements(EG(class_table)));
phpdbg_writeln("Functions\t\t%d", zend_hash_num_elements(EG(function_table)));
phpdbg_writeln("Constants\t\t%d", zend_hash_num_elements(EG(zend_constants)));
phpdbg_writeln("Includes\t\t%d", zend_hash_num_elements(&EG(included_files)));
}
} /* }}} */
static inline void phpdbg_sigint_handler(int signo) /* {{{ */
{
TSRMLS_FETCH();
2013-11-23 16:45:03 +00:00
if (EG(in_execution)) {
2013-11-23 17:01:18 +00:00
/* set signalled only when not interactive */
if (!(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) {
PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED;
}
} else {
/* we quit remote consoles on recv SIGINT */
if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) {
PHPDBG_G(flags) |= PHPDBG_IS_QUITTING;
zend_bailout();
}
}
} /* }}} */
#ifndef _WIN32
2013-11-29 19:42:41 +00:00
int phpdbg_open_socket(const char *interface, short port) /* {{{ */
2013-11-27 16:49:51 +00:00
{
int fd = socket(AF_INET, SOCK_STREAM, 0);
2013-12-15 13:55:03 +00:00
2013-11-27 16:49:51 +00:00
switch (fd) {
case -1:
return -1;
2013-12-15 13:55:03 +00:00
2013-11-27 16:49:51 +00:00
default: {
int reuse = 1;
2013-11-28 17:30:27 +00:00
switch (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*) &reuse, sizeof(reuse))) {
2013-11-27 16:49:51 +00:00
case -1:
close(fd);
return -2;
2013-12-15 13:55:03 +00:00
2013-11-27 16:49:51 +00:00
default: {
struct sockaddr_in address;
2013-12-15 13:55:03 +00:00
2013-11-27 16:49:51 +00:00
memset(&address, 0, sizeof(address));
2013-12-15 13:55:03 +00:00
2013-11-27 16:49:51 +00:00
address.sin_port = htons(port);
address.sin_family = AF_INET;
2013-12-15 13:55:03 +00:00
2013-11-29 19:42:41 +00:00
if ((*interface == '*')) {
2013-12-15 13:55:03 +00:00
address.sin_addr.s_addr = htonl(INADDR_ANY);
2013-11-29 19:42:41 +00:00
} else if (!inet_pton(AF_INET, interface, &address.sin_addr)) {
2013-11-27 16:49:51 +00:00
close(fd);
return -3;
}
2013-12-15 13:55:03 +00:00
2013-11-27 16:49:51 +00:00
switch (bind(fd, (struct sockaddr *)&address, sizeof(address))) {
case -1:
close(fd);
return -4;
2013-12-15 13:55:03 +00:00
2013-11-27 16:49:51 +00:00
default: {
listen(fd, 5);
}
}
}
}
}
}
2013-12-15 13:55:03 +00:00
2013-11-27 16:49:51 +00:00
return fd;
} /* }}} */
2013-11-28 14:54:06 +00:00
static inline void phpdbg_close_sockets(int (*socket)[2], FILE *streams[2]) /* {{{ */
2013-12-15 13:55:03 +00:00
{
if ((*socket)[0] >= 0) {
shutdown(
(*socket)[0], SHUT_RDWR);
2013-11-28 14:54:06 +00:00
close((*socket)[0]);
}
2013-12-15 13:55:03 +00:00
2013-11-28 15:51:11 +00:00
if (streams[0]) {
fclose(streams[0]);
2013-11-28 14:54:06 +00:00
}
2013-12-15 13:55:03 +00:00
if ((*socket)[1] >= 0) {
shutdown(
(*socket)[1], SHUT_RDWR);
2013-11-28 14:54:06 +00:00
close((*socket)[1]);
}
2013-12-15 13:55:03 +00:00
2013-11-28 15:51:11 +00:00
if (streams[1]) {
fclose(streams[1]);
}
2013-11-28 14:54:06 +00:00
} /* }}} */
/* don't inline this, want to debug it easily, will inline when done */
2013-11-29 19:42:41 +00:00
int phpdbg_open_sockets(char *address, int port[2], int (*listen)[2], int (*socket)[2], FILE* streams[2]) /* {{{ */
2013-11-27 16:49:51 +00:00
{
if (((*listen)[0]) < 0 && ((*listen)[1]) < 0) {
2013-11-29 19:42:41 +00:00
((*listen)[0]) = phpdbg_open_socket(address, (short)port[0]);
((*listen)[1]) = phpdbg_open_socket(address, (short)port[1]);
}
2013-11-27 16:49:51 +00:00
streams[0] = NULL;
streams[1] = NULL;
if ((*listen)[0] < 0 || (*listen)[1] < 0) {
if ((*listen)[0] < 0) {
phpdbg_rlog(stderr,
"console failed to initialize (stdin) on %s:%d", address, port[0]);
}
if ((*listen)[1] < 0) {
phpdbg_rlog(stderr,
"console failed to initialize (stdout) on %s:%d", address, port[1]);
}
if ((*listen)[0] >= 0) {
close((*listen)[0]);
}
if ((*listen)[1] >= 0) {
close((*listen)[1]);
}
2013-11-27 16:49:51 +00:00
return FAILURE;
}
2013-11-28 14:54:06 +00:00
phpdbg_close_sockets(socket, streams);
phpdbg_rlog(stderr,
"accepting connections on %s:%d/%d", address, port[0], port[1]);
2013-11-27 16:49:51 +00:00
{
struct sockaddr_in address;
socklen_t size = sizeof(address);
char buffer[20] = {0};
{
memset(&address, 0, size);
(*socket)[0] = accept(
(*listen)[0], (struct sockaddr *) &address, &size);
inet_ntop(AF_INET, &address.sin_addr, buffer, sizeof(buffer));
phpdbg_rlog(stderr, "connection (stdin) from %s", buffer);
}
{
memset(&address, 0, size);
(*socket)[1] = accept(
(*listen)[1], (struct sockaddr *) &address, &size);
inet_ntop(AF_INET, &address.sin_addr, buffer, sizeof(buffer));
phpdbg_rlog(stderr, "connection (stdout) from %s", buffer);
}
2013-11-27 16:49:51 +00:00
}
2013-11-28 14:54:06 +00:00
dup2((*socket)[0], fileno(stdin));
dup2((*socket)[1], fileno(stdout));
2013-12-15 13:55:03 +00:00
2013-11-28 15:51:11 +00:00
setbuf(stdout, NULL);
streams[0] = fdopen((*socket)[0], "r");
streams[1] = fdopen((*socket)[1], "w");
2013-12-15 13:55:03 +00:00
2013-11-27 16:49:51 +00:00
return SUCCESS;
} /* }}} */
void phpdbg_signal_handler(int sig, siginfo_t *info, void *context) {
int is_handled = FAILURE;
TSRMLS_FETCH();
switch (sig) {
case SIGBUS:
case SIGSEGV:
is_handled = phpdbg_watchpoint_segfault_handler(info, context TSRMLS_CC);
if (is_handled == FAILURE) {
#ifdef ZEND_SIGNALS
zend_sigaction(sig, &PHPDBG_G(old_sigsegv_signal), NULL TSRMLS_CC);
#else
sigaction(sig, &PHPDBG_G(old_sigsegv_signal), NULL);
#endif
}
break;
}
}
#endif
2013-11-12 21:40:15 +00:00
int main(int argc, char **argv) /* {{{ */
2013-11-09 23:07:04 +00:00
{
2013-11-10 00:34:38 +00:00
sapi_module_struct *phpdbg = &phpdbg_sapi_module;
char *sapi_name;
char *ini_entries;
int ini_entries_len;
char **zend_extensions = NULL;
zend_ulong zend_extensions_len = 0L;
2013-11-23 15:11:09 +00:00
zend_bool ini_ignore;
char *ini_override;
char *exec;
size_t exec_len;
char *init_file;
size_t init_file_len;
zend_bool init_file_default;
char *oplog_file;
size_t oplog_file_len;
zend_ulong flags;
char *php_optarg;
2013-11-20 14:35:25 +00:00
int php_optind, opt, show_banner = 1;
2013-11-18 01:08:53 +00:00
long cleaning = 0;
zend_bool remote = 0;
2013-11-20 16:19:37 +00:00
int run = 0;
int step = 0;
char *bp_tmp_file;
#ifndef _WIN32
2013-11-29 19:42:41 +00:00
char *address;
int listen[2];
int server[2];
int socket[2];
2013-11-27 16:49:51 +00:00
FILE* streams[2] = {NULL, NULL};
#endif
2013-11-20 18:52:34 +00:00
2013-11-09 22:35:03 +00:00
#ifdef ZTS
2013-11-09 23:07:04 +00:00
void ***tsrm_ls;
2013-11-09 22:35:03 +00:00
#endif
2013-11-09 23:07:04 +00:00
#ifndef _WIN32
struct sigaction signal_struct;
signal_struct.sa_sigaction = phpdbg_signal_handler;
signal_struct.sa_flags = SA_SIGINFO | SA_NODEFER;
2013-11-29 19:42:41 +00:00
address = strdup("127.0.0.1");
socket[0] = -1;
socket[1] = -1;
listen[0] = -1;
listen[1] = -1;
server[0] = -1;
server[1] = -1;
streams[0] = NULL;
streams[1] = NULL;
#endif
2013-11-09 23:07:04 +00:00
2013-11-09 22:47:39 +00:00
#ifdef PHP_WIN32
2013-11-09 23:07:04 +00:00
_fmode = _O_BINARY; /* sets default for file streams to binary */
setmode(_fileno(stdin), O_BINARY); /* make the stdio mode be binary */
setmode(_fileno(stdout), O_BINARY); /* make the stdio mode be binary */
setmode(_fileno(stderr), O_BINARY); /* make the stdio mode be binary */
2013-11-09 22:47:39 +00:00
#endif
2013-11-10 22:44:28 +00:00
#ifdef ZTS
2013-11-18 01:18:12 +00:00
tsrm_startup(1, 1, 0, NULL);
2013-11-10 22:44:28 +00:00
tsrm_ls = ts_resource(0);
2013-12-15 13:55:03 +00:00
#endif
2013-11-25 23:02:54 +00:00
phpdbg_main:
if (!cleaning) {
bp_tmp_file = malloc(L_tmpnam);
tmpnam(bp_tmp_file);
if (bp_tmp_file == NULL) {
phpdbg_error("Unable to create temporary file");
}
}
2013-11-18 01:18:12 +00:00
ini_entries = NULL;
ini_entries_len = 0;
2013-11-23 15:11:09 +00:00
ini_ignore = 0;
ini_override = NULL;
zend_extensions = NULL;
zend_extensions_len = 0L;
2013-11-18 01:18:12 +00:00
exec = NULL;
exec_len = 0;
init_file = NULL;
init_file_len = 0;
init_file_default = 1;
oplog_file = NULL;
oplog_file_len = 0;
flags = PHPDBG_DEFAULT_FLAGS;
php_optarg = NULL;
php_optind = 1;
opt = 0;
2013-11-20 16:19:37 +00:00
run = 0;
step = 0;
2013-12-02 14:45:41 +00:00
sapi_name = NULL;
2013-12-15 13:55:03 +00:00
2013-11-18 01:18:12 +00:00
while ((opt = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) {
switch (opt) {
2013-11-20 16:19:37 +00:00
case 'r':
run++;
2013-11-23 17:30:10 +00:00
break;
2013-11-18 01:18:12 +00:00
case 'n':
2013-11-23 15:11:09 +00:00
ini_ignore = 1;
2013-11-23 17:30:10 +00:00
break;
2013-11-18 01:18:12 +00:00
case 'c':
2013-11-23 15:11:09 +00:00
if (ini_override) {
free(ini_override);
2013-11-18 01:18:12 +00:00
}
2013-11-23 15:11:09 +00:00
ini_override = strdup(php_optarg);
2013-11-23 17:30:10 +00:00
break;
2013-11-18 01:18:12 +00:00
case 'd': {
2013-11-26 07:11:34 +00:00
int len = strlen(php_optarg);
char *val;
if ((val = strchr(php_optarg, '='))) {
val++;
if (!isalnum(*val) && *val != '"' && *val != '\'' && *val != '\0') {
ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("\"\"\n\0"));
memcpy(ini_entries + ini_entries_len, php_optarg, (val - php_optarg));
ini_entries_len += (val - php_optarg);
memcpy(ini_entries + ini_entries_len, "\"", 1);
ini_entries_len++;
memcpy(ini_entries + ini_entries_len, val, len - (val - php_optarg));
ini_entries_len += len - (val - php_optarg);
memcpy(ini_entries + ini_entries_len, "\"\n\0", sizeof("\"\n\0"));
ini_entries_len += sizeof("\n\0\"") - 2;
} else {
ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("\n\0"));
memcpy(ini_entries + ini_entries_len, php_optarg, len);
memcpy(ini_entries + ini_entries_len + len, "\n\0", sizeof("\n\0"));
ini_entries_len += len + sizeof("\n\0") - 2;
}
} else {
ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("=1\n\0"));
memcpy(ini_entries + ini_entries_len, php_optarg, len);
memcpy(ini_entries + ini_entries_len + len, "=1\n\0", sizeof("=1\n\0"));
ini_entries_len += len + sizeof("=1\n\0") - 2;
}
} break;
2013-12-15 13:55:03 +00:00
2013-11-18 01:18:12 +00:00
case 'z':
zend_extensions_len++;
if (zend_extensions) {
zend_extensions = realloc(zend_extensions, sizeof(char*) * zend_extensions_len);
} else zend_extensions = malloc(sizeof(char*) * zend_extensions_len);
zend_extensions[zend_extensions_len-1] = strdup(php_optarg);
2013-11-26 07:11:34 +00:00
break;
2013-11-18 01:18:12 +00:00
2013-11-26 07:11:34 +00:00
/* begin phpdbg options */
2013-11-18 01:18:12 +00:00
case 'e': { /* set execution context */
2013-11-26 07:11:34 +00:00
exec_len = strlen(php_optarg);
if (exec_len) {
2013-12-02 14:45:41 +00:00
if (exec) {
free(exec);
}
2013-11-26 07:11:34 +00:00
exec = strdup(php_optarg);
}
} break;
2013-12-15 13:55:03 +00:00
2013-12-02 14:45:41 +00:00
case 'S': { /* set SAPI name */
if (sapi_name) {
free(sapi_name);
}
sapi_name = strdup(php_optarg);
} break;
2013-11-18 01:18:12 +00:00
case 'I': { /* ignore .phpdbginit */
2013-11-26 07:11:34 +00:00
init_file_default = 0;
} break;
2013-11-18 01:18:12 +00:00
case 'i': { /* set init file */
2013-12-04 23:26:14 +00:00
if (init_file) {
free(init_file);
}
2013-12-15 13:55:03 +00:00
2013-11-26 07:11:34 +00:00
init_file_len = strlen(php_optarg);
if (init_file_len) {
2013-12-04 23:26:14 +00:00
init_file = strdup(php_optarg);
2013-11-26 07:11:34 +00:00
}
} break;
2013-11-18 01:18:12 +00:00
case 'O': { /* set oplog output */
2013-11-26 07:11:34 +00:00
oplog_file_len = strlen(php_optarg);
if (oplog_file_len) {
oplog_file = strdup(php_optarg);
}
} break;
2013-11-18 01:18:12 +00:00
case 'v': /* set quietness off */
2013-11-26 07:11:34 +00:00
flags &= ~PHPDBG_IS_QUIET;
break;
2013-11-18 01:18:12 +00:00
case 's': /* set stepping on */
2013-11-26 07:11:34 +00:00
step = 1;
break;
2013-11-20 18:52:34 +00:00
2013-11-20 17:01:37 +00:00
case 'E': /* stepping through eval on */
2013-11-26 07:11:34 +00:00
flags |= PHPDBG_IS_STEPONEVAL;
break;
2013-11-18 01:18:12 +00:00
case 'b': /* set colours off */
2013-11-26 07:11:34 +00:00
flags &= ~PHPDBG_IS_COLOURED;
break;
2013-11-20 14:35:25 +00:00
case 'q': /* hide banner */
2013-11-26 07:11:34 +00:00
show_banner = 0;
break;
#ifndef _WIN32
2013-11-27 16:49:51 +00:00
/* if you pass a listen port, we will accept input on listen port */
/* and write output to listen port * 2 */
2013-12-15 13:55:03 +00:00
2013-11-29 19:42:41 +00:00
case 'l': { /* set listen ports */
if (sscanf(php_optarg, "%d/%d", &listen[0], &listen[1]) != 2) {
if (sscanf(php_optarg, "%d", &listen[0]) != 1) {
/* default to hardcoded ports */
listen[0] = 4000;
listen[1] = 8000;
} else {
listen[1] = (listen[0] * 2);
}
}
} break;
2013-12-15 13:55:03 +00:00
2013-11-29 19:42:41 +00:00
case 'a': { /* set bind address */
free(address);
if (!php_optarg) {
address = strdup("*");
} else address = strdup(php_optarg);
} break;
#endif
case 'V': {
2013-12-18 15:13:14 +00:00
sapi_startup(phpdbg);
phpdbg->startup(phpdbg);
printf(
2014-01-17 22:09:07 +00:00
"phpdbg %s (built: %s %s)\nPHP %s, Copyright (c) 1997-2014 The PHP Group\n%s",
PHPDBG_VERSION,
__DATE__,
__TIME__,
2013-12-18 15:13:14 +00:00
PHP_VERSION,
get_zend_version()
);
2013-12-18 15:13:14 +00:00
sapi_deactivate(TSRMLS_C);
sapi_shutdown();
return 0;
} break;
2013-11-18 01:18:12 +00:00
}
}
2013-11-10 17:51:20 +00:00
#ifndef _WIN32
/* setup remote server if necessary */
if (!cleaning &&
(listen[0] > 0 && listen[1] > 0)) {
2013-11-29 19:42:41 +00:00
if (phpdbg_open_sockets(address, listen, &server, &socket, streams) == FAILURE) {
remote = 0;
2013-11-28 18:22:30 +00:00
exit(0);
2013-11-28 15:51:11 +00:00
}
/* set remote flag to stop service shutting down upon quit */
remote = 1;
2013-11-27 16:49:51 +00:00
}
#endif
2013-12-02 14:45:41 +00:00
if (sapi_name) {
phpdbg->name = sapi_name;
}
2013-12-15 13:55:03 +00:00
2013-11-18 01:18:12 +00:00
phpdbg->ini_defaults = phpdbg_ini_defaults;
2013-11-10 17:45:06 +00:00
phpdbg->phpinfo_as_text = 1;
phpdbg->php_ini_ignore_cwd = 1;
2013-11-09 23:07:04 +00:00
sapi_startup(phpdbg);
2013-11-18 01:18:12 +00:00
phpdbg->executable_location = argv[0];
phpdbg->phpinfo_as_text = 1;
2013-11-23 15:11:09 +00:00
phpdbg->php_ini_ignore = ini_ignore;
phpdbg->php_ini_path_override = ini_override;
2013-11-18 01:18:12 +00:00
if (ini_entries) {
2013-11-10 22:44:28 +00:00
ini_entries = realloc(ini_entries, ini_entries_len + sizeof(phpdbg_ini_hardcoded));
memmove(ini_entries + sizeof(phpdbg_ini_hardcoded) - 2, ini_entries, ini_entries_len + 1);
memcpy(ini_entries, phpdbg_ini_hardcoded, sizeof(phpdbg_ini_hardcoded) - 2);
} else {
ini_entries = malloc(sizeof(phpdbg_ini_hardcoded));
memcpy(ini_entries, phpdbg_ini_hardcoded, sizeof(phpdbg_ini_hardcoded));
}
ini_entries_len += sizeof(phpdbg_ini_hardcoded) - 2;
2013-12-15 13:55:03 +00:00
if (zend_extensions_len) {
zend_ulong zend_extension = 0L;
2013-12-15 13:55:03 +00:00
while (zend_extension < zend_extensions_len) {
const char *ze = zend_extensions[zend_extension];
size_t ze_len = strlen(ze);
2013-12-15 13:55:03 +00:00
ini_entries = realloc(
ini_entries, ini_entries_len + (ze_len + (sizeof("zend_extension=\n"))));
memcpy(&ini_entries[ini_entries_len], "zend_extension=", (sizeof("zend_extension=\n")-1));
ini_entries_len += (sizeof("zend_extension=")-1);
memcpy(&ini_entries[ini_entries_len], ze, ze_len);
ini_entries_len += ze_len;
memcpy(&ini_entries[ini_entries_len], "\n", (sizeof("\n") - 1));
2013-12-04 23:26:14 +00:00
free(zend_extensions[zend_extension]);
zend_extension++;
}
2013-12-15 13:55:03 +00:00
free(zend_extensions);
}
2013-11-18 01:18:12 +00:00
phpdbg->ini_entries = ini_entries;
2013-12-15 13:55:03 +00:00
2013-11-09 23:07:04 +00:00
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);
2013-11-09 23:07:04 +00:00
zend_activate(TSRMLS_C);
#if defined(ZEND_SIGNALS) && !defined(_WIN32)
zend_try {
zend_signal_activate(TSRMLS_C);
} zend_end_try();
#endif
#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();
#elif !defined(_WIN32)
sigaction(SIGSEGV, &signal_struct, &PHPDBG_G(old_sigsegv_signal));
sigaction(SIGBUS, &signal_struct, &PHPDBG_G(old_sigsegv_signal));
#endif
2013-11-28 15:51:11 +00:00
/* do not install sigint handlers for remote consoles */
/* sending SIGINT then provides a decent way of shutting down the server */
#if defined(ZEND_SIGNALS) && !defined(_WIN32)
2013-11-28 15:51:11 +00:00
if (listen[0] < 0) {
zend_try { zend_signal(SIGINT, phpdbg_sigint_handler TSRMLS_CC); } zend_end_try();
2013-11-28 15:51:11 +00:00
}
#elif !defined(_WIN32)
2013-11-28 15:51:11 +00:00
if (listen[0] < 0) {
#endif
2013-11-28 15:51:11 +00:00
signal(SIGINT, phpdbg_sigint_handler);
2013-12-01 08:55:37 +00:00
#ifndef _WIN32
2013-11-28 15:51:11 +00:00
}
2013-11-09 22:35:03 +00:00
#endif
2013-11-09 23:07:04 +00:00
PG(modules_activated) = 0;
2013-12-15 13:55:03 +00:00
/* set flags from command line */
PHPDBG_G(flags) = flags;
2013-11-09 23:07:04 +00:00
#ifndef _WIN32
2013-11-27 16:49:51 +00:00
/* setup io here */
if (streams[0] && streams[1]) {
PHPDBG_G(flags) |= PHPDBG_IS_REMOTE;
2013-11-27 16:49:51 +00:00
signal(SIGPIPE, SIG_IGN);
}
#endif
2013-11-09 23:07:04 +00:00
2013-11-22 16:15:24 +00:00
PHPDBG_G(io)[PHPDBG_STDIN] = stdin;
PHPDBG_G(io)[PHPDBG_STDOUT] = stdout;
PHPDBG_G(io)[PHPDBG_STDERR] = stderr;
2013-12-15 13:55:03 +00:00
2013-11-23 17:30:10 +00:00
if (exec) { /* set execution context */
PHPDBG_G(exec) = phpdbg_resolve_path(
exec TSRMLS_CC);
PHPDBG_G(exec_len) = strlen(PHPDBG_G(exec));
2013-11-23 17:30:10 +00:00
free(exec);
}
2013-11-14 21:39:59 +00:00
2013-11-18 01:18:12 +00:00
if (oplog_file) { /* open oplog */
PHPDBG_G(oplog) = fopen(oplog_file, "w+");
if (!PHPDBG_G(oplog)) {
phpdbg_error(
2013-11-23 17:30:10 +00:00
"Failed to open oplog %s", oplog_file);
2013-11-18 01:18:12 +00:00
}
free(oplog_file);
}
/* set default colors */
2013-11-24 19:41:00 +00:00
phpdbg_set_color_ex(PHPDBG_COLOR_PROMPT, PHPDBG_STRL("white-bold") TSRMLS_CC);
phpdbg_set_color_ex(PHPDBG_COLOR_ERROR, PHPDBG_STRL("red-bold") TSRMLS_CC);
phpdbg_set_color_ex(PHPDBG_COLOR_NOTICE, PHPDBG_STRL("green") TSRMLS_CC);
2013-11-24 14:54:14 +00:00
/* set default prompt */
phpdbg_set_prompt(PROMPT TSRMLS_CC);
2013-11-24 19:41:00 +00:00
2013-11-09 23:07:04 +00:00
zend_try {
zend_activate_modules(TSRMLS_C);
} zend_end_try();
2013-11-13 23:36:02 +00:00
2013-11-20 14:35:25 +00:00
if (show_banner) {
/* print blurb */
phpdbg_welcome((cleaning > 0) TSRMLS_CC);
}
2013-11-20 13:28:41 +00:00
2013-11-18 21:59:42 +00:00
zend_try {
2013-11-23 17:30:10 +00:00
/* activate globals, they can be overwritten */
zend_activate_auto_globals(TSRMLS_C);
} zend_end_try();
/* initialize from file */
PHPDBG_G(flags) |= PHPDBG_IS_INITIALIZING;
2013-11-23 17:30:10 +00:00
zend_try {
phpdbg_init(init_file, init_file_len, init_file_default TSRMLS_CC);
phpdbg_try_file_init(bp_tmp_file, strlen(bp_tmp_file), 0 TSRMLS_CC);
2013-11-23 17:30:10 +00:00
} zend_end_try();
PHPDBG_G(flags) &= ~PHPDBG_IS_INITIALIZING;
/* quit if init says so */
if (PHPDBG_G(flags) & PHPDBG_IS_QUITTING) {
goto phpdbg_out;
}
2013-11-23 17:30:10 +00:00
/* step from here, not through init */
if (step) {
PHPDBG_G(flags) |= PHPDBG_IS_STEPPING;
}
if (run) {
/* no need to try{}, run does it ... */
PHPDBG_COMMAND_HANDLER(run)(NULL, NULL TSRMLS_CC);
if (run > 1) {
/* if -r is on the command line more than once just quit */
goto phpdbg_out;
}
}
/* #ifndef for making compiler shutting up */
#ifndef _WIN32
phpdbg_interact:
#endif
2013-11-23 17:30:10 +00:00
/* phpdbg main() */
do {
zend_try {
phpdbg_interactive(TSRMLS_C);
} zend_catch {
if ((PHPDBG_G(flags) & PHPDBG_IS_CLEANING)) {
FILE *bp_tmp_fp = fopen(bp_tmp_file, "w");
phpdbg_export_breakpoints(bp_tmp_fp TSRMLS_CC);
fclose(bp_tmp_fp);
2013-11-23 17:30:10 +00:00
cleaning = 1;
} else {
cleaning = 0;
}
2013-12-15 13:55:03 +00:00
#ifndef _WIN32
2014-01-17 21:15:03 +00:00
if (!cleaning) {
/* remote client disconnected */
if ((PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED)) {
2014-01-17 21:15:03 +00:00
if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) {
/* renegociate connections */
phpdbg_open_sockets(
address, listen, &server, &socket, streams);
2014-01-17 21:15:03 +00:00
/* set streams */
if (streams[0] && streams[1]) {
PHPDBG_G(flags) &= ~PHPDBG_IS_QUITTING;
}
2014-01-17 21:15:03 +00:00
/* this must be forced */
CG(unclean_shutdown) = 0;
} else {
/* local consoles cannot disconnect, ignore EOF */
PHPDBG_G(flags) &= ~PHPDBG_IS_DISCONNECTED;
}
}
}
#endif
2013-11-23 17:30:10 +00:00
} zend_end_try();
} while(!cleaning && !(PHPDBG_G(flags) & PHPDBG_IS_QUITTING));
2013-11-29 02:42:34 +00:00
/* this must be forced */
CG(unclean_shutdown) = 0;
/* this is just helpful */
PG(report_memleaks) = 0;
2013-11-14 12:21:28 +00:00
phpdbg_out:
#ifndef _WIN32
2014-01-13 08:14:04 +00:00
if ((PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED)) {
PHPDBG_G(flags) &= ~PHPDBG_IS_DISCONNECTED;
goto phpdbg_interact;
}
#endif
2013-12-15 13:55:03 +00:00
2014-03-16 19:04:08 +00:00
#ifdef _WIN32
} __except(phpdbg_exception_handler_win32(xp = GetExceptionInformation())) {
phpdbg_error("Access violation (Segementation fault) encountered\ntrying to abort cleanly...");
}
#endif
2013-12-18 07:57:27 +00:00
#ifndef ZTS
/* force cleanup of auto and core globals */
zend_hash_clean(CG(auto_globals));
memset(
&core_globals, 0, sizeof(php_core_globals));
#endif
2013-11-10 17:45:06 +00:00
if (ini_entries) {
2013-11-23 17:30:10 +00:00
free(ini_entries);
2013-11-10 17:45:06 +00:00
}
2013-11-23 16:45:03 +00:00
2013-11-23 15:11:09 +00:00
if (ini_override) {
free(ini_override);
}
2013-11-09 23:07:04 +00:00
if (PG(modules_activated)) {
zend_try {
zend_deactivate_modules(TSRMLS_C);
} zend_end_try();
}
zend_deactivate(TSRMLS_C);
zend_try {
zend_post_deactivate_modules(TSRMLS_C);
} zend_end_try();
2013-11-09 22:35:03 +00:00
#ifdef ZEND_SIGNALS
2013-11-09 23:07:04 +00:00
zend_try {
zend_signal_deactivate(TSRMLS_C);
} zend_end_try();
2013-11-09 22:35:03 +00:00
#endif
2013-11-14 11:30:31 +00:00
zend_try {
2013-11-23 17:30:10 +00:00
php_module_shutdown(TSRMLS_C);
2013-11-14 11:30:31 +00:00
} zend_end_try();
2013-11-09 23:07:04 +00:00
sapi_shutdown();
2014-03-16 19:04:08 +00:00
2013-11-09 23:07:04 +00:00
}
2013-11-14 21:39:59 +00:00
if (cleaning || remote) {
2013-11-25 22:19:21 +00:00
goto phpdbg_main;
}
2014-01-13 08:14:04 +00:00
2013-11-25 23:02:54 +00:00
#ifdef ZTS
/* bugggy */
/* tsrm_shutdown(); */
#endif
2013-11-29 19:42:41 +00:00
#ifndef _WIN32
if (address) {
2013-12-15 13:55:03 +00:00
free(address);
2013-11-29 19:42:41 +00:00
}
#endif
2013-12-02 14:45:41 +00:00
if (sapi_name) {
free(sapi_name);
}
2013-12-15 13:55:03 +00:00
free(bp_tmp_file);
2013-11-25 23:02:54 +00:00
2013-11-09 23:07:04 +00:00
return 0;
2013-11-09 22:35:03 +00:00
} /* }}} */