root/sapi/phpdbg/phpdbg.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. PHP_INI_MH
  2. php_phpdbg_globals_ctor
  3. PHP_MINIT_FUNCTION
  4. php_phpdbg_destroy_bp_file
  5. php_phpdbg_destroy_bp_symbol
  6. php_phpdbg_destroy_bp_opcode
  7. php_phpdbg_destroy_bp_opline
  8. php_phpdbg_destroy_bp_methods
  9. php_phpdbg_destroy_bp_condition
  10. php_phpdbg_destroy_registered
  11. PHP_RINIT_FUNCTION
  12. PHP_RSHUTDOWN_FUNCTION
  13. PHP_FUNCTION
  14. PHP_FUNCTION
  15. PHP_FUNCTION
  16. PHP_FUNCTION
  17. PHP_FUNCTION
  18. PHP_FUNCTION
  19. PHP_FUNCTION
  20. PHP_FUNCTION
  21. PHP_FUNCTION
  22. phpdbg_oplog_fill_executable
  23. phpdbg_add_empty_array
  24. PHP_FUNCTION
  25. PHP_FUNCTION
  26. php_sapi_phpdbg_module_startup
  27. php_sapi_phpdbg_read_cookies
  28. php_sapi_phpdbg_header_handler
  29. php_sapi_phpdbg_send_headers
  30. php_sapi_phpdbg_send_header
  31. php_sapi_phpdbg_log_message
  32. php_sapi_phpdbg_deactivate
  33. php_sapi_phpdbg_register_vars
  34. php_sapi_phpdbg_ub_write
  35. phpdbg_stdiop_write
  36. php_sapi_phpdbg_flush
  37. phpdbg_register_file_handles
  38. phpdbg_ini_defaults
  39. phpdbg_welcome
  40. phpdbg_sigint_handler
  41. phpdbg_remote_close
  42. phpdbg_remote_init
  43. phpdbg_sigio_handler
  44. phpdbg_signal_handler
  45. phpdbg_sighup_handler
  46. phpdbg_malloc_wrapper
  47. phpdbg_free_wrapper
  48. phpdbg_realloc_wrapper
  49. main

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 7                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 The PHP Group                                |
   6    +----------------------------------------------------------------------+
   7    | This source file is subject to version 3.01 of the PHP license,      |
   8    | that is bundled with this package in the file LICENSE, and is        |
   9    | available through the world-wide-web at the following url:           |
  10    | http://www.php.net/license/3_01.txt                                  |
  11    | If you did not receive a copy of the PHP license and are unable to   |
  12    | obtain it through the world-wide-web, please send a note to          |
  13    | license@php.net so we can mail you a copy immediately.               |
  14    +----------------------------------------------------------------------+
  15    | Authors: Felipe Pena <felipe@php.net>                                |
  16    | Authors: Joe Watkins <joe.watkins@live.co.uk>                        |
  17    | Authors: Bob Weinand <bwoebi@php.net>                                |
  18    +----------------------------------------------------------------------+
  19 */
  20 
  21 #if !defined(ZEND_SIGNALS) || defined(_WIN32)
  22 # include <signal.h>
  23 #endif
  24 
  25 #include "phpdbg.h"
  26 #include "phpdbg_prompt.h"
  27 #include "phpdbg_bp.h"
  28 #include "phpdbg_break.h"
  29 #include "phpdbg_list.h"
  30 #include "phpdbg_utils.h"
  31 #include "phpdbg_set.h"
  32 #include "phpdbg_io.h"
  33 #include "zend_alloc.h"
  34 #include "phpdbg_eol.h"
  35 #include "phpdbg_print.h"
  36 
  37 #include "ext/standard/basic_functions.h"
  38 
  39 /* {{{ remote console headers */
  40 #ifndef _WIN32
  41 #       include <sys/socket.h>
  42 #       include <sys/select.h>
  43 #       include <sys/time.h>
  44 #       include <sys/types.h>
  45 #       include <sys/poll.h>
  46 #       include <netinet/in.h>
  47 #       include <unistd.h>
  48 #       include <arpa/inet.h>
  49 #endif /* }}} */
  50 
  51 #if defined(PHP_WIN32) && defined(HAVE_OPENSSL)
  52 # include "openssl/applink.c"
  53 #endif
  54 
  55 #if defined(PHP_WIN32) && defined(ZTS)
  56 ZEND_TSRMLS_CACHE_DEFINE()
  57 #endif
  58 
  59 ZEND_DECLARE_MODULE_GLOBALS(phpdbg);
  60 int phpdbg_startup_run = 0;
  61 
  62 static PHP_INI_MH(OnUpdateEol)
  63 {
  64         if (!new_value) {
  65                 return FAILURE;
  66         }
  67 
  68         return phpdbg_eol_global_update(ZSTR_VAL(new_value));
  69 }
  70 
  71 PHP_INI_BEGIN()
  72         STD_PHP_INI_ENTRY("phpdbg.path", "", PHP_INI_SYSTEM | PHP_INI_PERDIR, OnUpdateString, socket_path, zend_phpdbg_globals, phpdbg_globals)
  73         STD_PHP_INI_ENTRY("phpdbg.eol", "2", PHP_INI_ALL, OnUpdateEol, socket_path, zend_phpdbg_globals, phpdbg_globals)
  74 PHP_INI_END()
  75 
  76 static zend_bool phpdbg_booted = 0;
  77 static zend_bool phpdbg_fully_started = 0;
  78 
  79 static inline void php_phpdbg_globals_ctor(zend_phpdbg_globals *pg) /* {{{ */
  80 {
  81         pg->prompt[0] = NULL;
  82         pg->prompt[1] = NULL;
  83 
  84         pg->colors[0] = NULL;
  85         pg->colors[1] = NULL;
  86         pg->colors[2] = NULL;
  87 
  88         pg->lines = phpdbg_get_terminal_height();
  89         pg->exec = NULL;
  90         pg->exec_len = 0;
  91         pg->buffer = NULL;
  92         pg->last_was_newline = 1;
  93         pg->ops = NULL;
  94         pg->vmret = 0;
  95         pg->in_execution = 0;
  96         pg->bp_count = 0;
  97         pg->flags = PHPDBG_DEFAULT_FLAGS;
  98         pg->oplog = NULL;
  99         memset(pg->io, 0, sizeof(pg->io));
 100         pg->frame.num = 0;
 101         pg->sapi_name_ptr = NULL;
 102         pg->socket_fd = -1;
 103         pg->socket_server_fd = -1;
 104         pg->unclean_eval = 0;
 105 
 106         pg->req_id = 0;
 107         pg->err_buf.active = 0;
 108         pg->err_buf.type = 0;
 109 
 110         pg->input_buflen = 0;
 111         pg->sigsafe_mem.mem = NULL;
 112         pg->sigsegv_bailout = NULL;
 113 
 114         pg->oplog_list = NULL;
 115 
 116 #ifdef PHP_WIN32
 117         pg->sigio_watcher_thread = INVALID_HANDLE_VALUE;
 118         memset(&pg->swd, 0, sizeof(struct win32_sigio_watcher_data));
 119 #endif
 120 
 121         pg->eol = PHPDBG_EOL_LF;
 122 } /* }}} */
 123 
 124 static PHP_MINIT_FUNCTION(phpdbg) /* {{{ */
 125 {
 126         ZEND_INIT_MODULE_GLOBALS(phpdbg, php_phpdbg_globals_ctor, NULL);
 127         REGISTER_INI_ENTRIES();
 128 
 129         zend_execute_ex = phpdbg_execute_ex;
 130 
 131         REGISTER_STRINGL_CONSTANT("PHPDBG_VERSION", PHPDBG_VERSION, sizeof(PHPDBG_VERSION)-1, CONST_CS|CONST_PERSISTENT);
 132 
 133         REGISTER_LONG_CONSTANT("PHPDBG_FILE",   FILE_PARAM, CONST_CS|CONST_PERSISTENT);
 134         REGISTER_LONG_CONSTANT("PHPDBG_METHOD", METHOD_PARAM, CONST_CS|CONST_PERSISTENT);
 135         REGISTER_LONG_CONSTANT("PHPDBG_LINENO", NUMERIC_PARAM, CONST_CS|CONST_PERSISTENT);
 136         REGISTER_LONG_CONSTANT("PHPDBG_FUNC",   STR_PARAM, CONST_CS|CONST_PERSISTENT);
 137 
 138         REGISTER_LONG_CONSTANT("PHPDBG_COLOR_PROMPT", PHPDBG_COLOR_PROMPT, CONST_CS|CONST_PERSISTENT);
 139         REGISTER_LONG_CONSTANT("PHPDBG_COLOR_NOTICE", PHPDBG_COLOR_NOTICE, CONST_CS|CONST_PERSISTENT);
 140         REGISTER_LONG_CONSTANT("PHPDBG_COLOR_ERROR",  PHPDBG_COLOR_ERROR, CONST_CS|CONST_PERSISTENT);
 141 
 142         return SUCCESS;
 143 } /* }}} */
 144 
 145 static void php_phpdbg_destroy_bp_file(zval *brake) /* {{{ */
 146 {
 147         zend_hash_destroy(Z_ARRVAL_P(brake));
 148         efree(Z_ARRVAL_P(brake));
 149 } /* }}} */
 150 
 151 static void php_phpdbg_destroy_bp_symbol(zval *brake) /* {{{ */
 152 {
 153         efree((char *) ((phpdbg_breaksymbol_t *) Z_PTR_P(brake))->symbol);
 154         efree(Z_PTR_P(brake));
 155 } /* }}} */
 156 
 157 static void php_phpdbg_destroy_bp_opcode(zval *brake) /* {{{ */
 158 {
 159         efree((char *) ((phpdbg_breakop_t *) Z_PTR_P(brake))->name);
 160         efree(Z_PTR_P(brake));
 161 } /* }}} */
 162 
 163 static void php_phpdbg_destroy_bp_opline(zval *brake) /* {{{ */
 164 {
 165         efree(Z_PTR_P(brake));
 166 } /* }}} */
 167 
 168 static void php_phpdbg_destroy_bp_methods(zval *brake) /* {{{ */
 169 {
 170         zend_hash_destroy(Z_ARRVAL_P(brake));
 171         efree(Z_ARRVAL_P(brake));
 172 } /* }}} */
 173 
 174 static void php_phpdbg_destroy_bp_condition(zval *data) /* {{{ */
 175 {
 176         phpdbg_breakcond_t *brake = (phpdbg_breakcond_t *) Z_PTR_P(data);
 177 
 178         if (brake->ops) {
 179                 destroy_op_array(brake->ops);
 180                 efree(brake->ops);
 181         }
 182         efree((char*) brake->code);
 183         efree(brake);
 184 } /* }}} */
 185 
 186 static void php_phpdbg_destroy_registered(zval *data) /* {{{ */
 187 {
 188         zend_function *function = (zend_function *) Z_PTR_P(data);
 189         destroy_zend_function(function);
 190 } /* }}} */
 191 
 192 
 193 static PHP_RINIT_FUNCTION(phpdbg) /* {{{ */
 194 {
 195         zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], 8, NULL, php_phpdbg_destroy_bp_file, 0);
 196         zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], 8, NULL, php_phpdbg_destroy_bp_file, 0);
 197         zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], 8, NULL, php_phpdbg_destroy_bp_symbol, 0);
 198         zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
 199         zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
 200         zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
 201         zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], 8, NULL, php_phpdbg_destroy_bp_opline, 0);
 202         zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], 8, NULL, php_phpdbg_destroy_bp_opcode, 0);
 203         zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
 204         zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], 8, NULL, php_phpdbg_destroy_bp_condition, 0);
 205         zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], 8, NULL, NULL, 0);
 206 
 207         zend_hash_init(&PHPDBG_G(seek), 8, NULL, NULL, 0);
 208         zend_hash_init(&PHPDBG_G(registered), 8, NULL, php_phpdbg_destroy_registered, 0);
 209 
 210         return SUCCESS;
 211 } /* }}} */
 212 
 213 static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */
 214 {
 215         zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE]);
 216         zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING]);
 217         zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM]);
 218         zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE]);
 219         zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE]);
 220         zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE]);
 221         zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]);
 222         zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE]);
 223         zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD]);
 224         zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_COND]);
 225         zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP]);
 226         zend_hash_destroy(&PHPDBG_G(file_sources));
 227         zend_hash_destroy(&PHPDBG_G(seek));
 228         zend_hash_destroy(&PHPDBG_G(registered));
 229         zend_hash_destroy(&PHPDBG_G(watchpoints));
 230         zend_llist_destroy(&PHPDBG_G(watchlist_mem));
 231 
 232         if (PHPDBG_G(buffer)) {
 233                 free(PHPDBG_G(buffer));
 234                 PHPDBG_G(buffer) = NULL;
 235         }
 236 
 237         if (PHPDBG_G(exec)) {
 238                 efree(PHPDBG_G(exec));
 239                 PHPDBG_G(exec) = NULL;
 240         }
 241 
 242         if (PHPDBG_G(oplog)) {
 243                 fclose(PHPDBG_G(oplog));
 244                 PHPDBG_G(oplog) = NULL;
 245         }
 246 
 247         if (PHPDBG_G(ops)) {
 248                 destroy_op_array(PHPDBG_G(ops));
 249                 efree(PHPDBG_G(ops));
 250                 PHPDBG_G(ops) = NULL;
 251         }
 252 
 253         if (PHPDBG_G(oplog_list)) {
 254                 phpdbg_oplog_list *cur = PHPDBG_G(oplog_list);
 255                 do {
 256                         phpdbg_oplog_list *prev = cur->prev;
 257                         efree(cur);
 258                         cur = prev;
 259                 } while (cur != NULL);
 260 
 261                 zend_arena_destroy(PHPDBG_G(oplog_arena));
 262                 PHPDBG_G(oplog_list) = NULL;
 263         }
 264 
 265         return SUCCESS;
 266 } /* }}} */
 267 
 268 /* {{{ proto mixed phpdbg_exec(string context)
 269         Attempt to set the execution context for phpdbg
 270         If the execution context was set previously it is returned
 271         If the execution context was not set previously boolean true is returned
 272         If the request to set the context fails, boolean false is returned, and an E_WARNING raised */
 273 static PHP_FUNCTION(phpdbg_exec)
 274 {
 275         zend_string *exec;
 276 
 277         if (zend_parse_parameters(ZEND_NUM_ARGS(), "S", &exec) == FAILURE) {
 278                 return;
 279         }
 280 
 281         {
 282                 zend_stat_t sb;
 283                 zend_bool result = 1;
 284 
 285                 if (VCWD_STAT(ZSTR_VAL(exec), &sb) != FAILURE) {
 286                         if (sb.st_mode & (S_IFREG|S_IFLNK)) {
 287                                 if (PHPDBG_G(exec)) {
 288                                         ZVAL_STRINGL(return_value, PHPDBG_G(exec), PHPDBG_G(exec_len));
 289                                         efree(PHPDBG_G(exec));
 290                                         result = 0;
 291                                 }
 292 
 293                                 PHPDBG_G(exec) = estrndup(ZSTR_VAL(exec), ZSTR_LEN(exec));
 294                                 PHPDBG_G(exec_len) = ZSTR_LEN(exec);
 295 
 296                                 if (result) {
 297                                         ZVAL_TRUE(return_value);
 298                                 }
 299                         } else {
 300                                 zend_error(E_WARNING, "Failed to set execution context (%s), not a regular file or symlink", ZSTR_VAL(exec));
 301                                 ZVAL_FALSE(return_value);
 302                         }
 303                 } else {
 304                         zend_error(E_WARNING, "Failed to set execution context (%s) the file does not exist", ZSTR_VAL(exec));
 305 
 306                         ZVAL_FALSE(return_value);
 307                 }
 308         }
 309 } /* }}} */
 310 
 311 /* {{{ proto void phpdbg_break()
 312     instructs phpdbg to insert a breakpoint at the next opcode */
 313 static PHP_FUNCTION(phpdbg_break_next)
 314 {
 315         zend_execute_data *ex = EG(current_execute_data);
 316 
 317         while (ex && ex->func && !ZEND_USER_CODE(ex->func->type)) {
 318                 ex = ex->prev_execute_data;
 319         }
 320 
 321         if (zend_parse_parameters_none() == FAILURE || !ex) {
 322                 return;
 323         }
 324 
 325         phpdbg_set_breakpoint_opline_ex((phpdbg_opline_ptr_t) ex->opline + 1);
 326 } /* }}} */
 327 
 328 /* {{{ proto void phpdbg_break_file(string file, integer line) */
 329 static PHP_FUNCTION(phpdbg_break_file)
 330 {
 331         char *file;
 332         size_t flen;
 333         zend_long line;
 334 
 335         if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl", &file, &flen, &line) == FAILURE) {
 336                 return;
 337         }
 338 
 339         phpdbg_set_breakpoint_file(file, line);
 340 } /* }}} */
 341 
 342 /* {{{ proto void phpdbg_break_method(string class, string method) */
 343 static PHP_FUNCTION(phpdbg_break_method)
 344 {
 345         char *class = NULL, *method = NULL;
 346         size_t clen = 0, mlen = 0;
 347 
 348         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss", &class, &clen, &method, &mlen) == FAILURE) {
 349                 return;
 350         }
 351 
 352         phpdbg_set_breakpoint_method(class, method);
 353 } /* }}} */
 354 
 355 /* {{{ proto void phpdbg_break_function(string function) */
 356 static PHP_FUNCTION(phpdbg_break_function)
 357 {
 358         char    *function = NULL;
 359         size_t   function_len;
 360 
 361         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &function, &function_len) == FAILURE) {
 362                 return;
 363         }
 364 
 365         phpdbg_set_breakpoint_symbol(function, function_len);
 366 } /* }}} */
 367 
 368 /* {{{ proto void phpdbg_clear(void)
 369    instructs phpdbg to clear breakpoints */
 370 static PHP_FUNCTION(phpdbg_clear)
 371 {
 372         zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE]);
 373         zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING]);
 374         zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM]);
 375         zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE]);
 376         zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE]);
 377         zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE]);
 378         zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]);
 379         zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD]);
 380         zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_COND]);
 381 } /* }}} */
 382 
 383 /* {{{ proto void phpdbg_color(integer element, string color) */
 384 static PHP_FUNCTION(phpdbg_color)
 385 {
 386         zend_long element;
 387         char *color;
 388         size_t color_len;
 389 
 390         if (zend_parse_parameters(ZEND_NUM_ARGS(), "ls", &element, &color, &color_len) == FAILURE) {
 391                 return;
 392         }
 393 
 394         switch (element) {
 395                 case PHPDBG_COLOR_NOTICE:
 396                 case PHPDBG_COLOR_ERROR:
 397                 case PHPDBG_COLOR_PROMPT:
 398                         phpdbg_set_color_ex(element, color, color_len);
 399                 break;
 400 
 401                 default: zend_error(E_ERROR, "phpdbg detected an incorrect color constant");
 402         }
 403 } /* }}} */
 404 
 405 /* {{{ proto void phpdbg_prompt(string prompt) */
 406 static PHP_FUNCTION(phpdbg_prompt)
 407 {
 408         char *prompt = NULL;
 409         size_t prompt_len = 0;
 410 
 411         if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &prompt, &prompt_len) == FAILURE) {
 412                 return;
 413         }
 414 
 415         phpdbg_set_prompt(prompt);
 416 } /* }}} */
 417 
 418 /* {{{ proto void phpdbg_start_oplog() */
 419 static PHP_FUNCTION(phpdbg_start_oplog)
 420 {
 421         phpdbg_oplog_list *prev;
 422 
 423         if (zend_parse_parameters_none() == FAILURE) {
 424                 return;
 425         }
 426 
 427         prev = PHPDBG_G(oplog_list);
 428 
 429         if (!prev) {
 430                 PHPDBG_G(oplog_arena) = zend_arena_create(64 * 1024);
 431 
 432                 PHPDBG_G(oplog_cur) = ((phpdbg_oplog_entry *) zend_arena_alloc(&PHPDBG_G(oplog_arena), sizeof(phpdbg_oplog_entry))) + 1;
 433                 PHPDBG_G(oplog_cur)->next = NULL;
 434         }
 435 
 436         PHPDBG_G(oplog_list) = emalloc(sizeof(phpdbg_oplog_list));
 437         PHPDBG_G(oplog_list)->prev = prev;
 438         PHPDBG_G(oplog_list)->start = PHPDBG_G(oplog_cur);
 439 }
 440 
 441 static void phpdbg_oplog_fill_executable(zend_op_array *op_array, HashTable *insert_ht, zend_bool by_opcode) {
 442         /* ignore RECV_* opcodes */
 443         zend_op *cur = op_array->opcodes + op_array->num_args + !!(op_array->fn_flags & ZEND_ACC_VARIADIC);
 444         zend_op *end = op_array->opcodes + op_array->last;
 445 
 446         zend_long insert_idx;
 447         zval zero;
 448         ZVAL_LONG(&zero, 0);
 449 
 450         /* ignore autogenerated return (well, not too precise with finally branches, but that's okay) */
 451         if (op_array->last >= 1 && (((end - 1)->opcode == ZEND_RETURN || (end - 1)->opcode == ZEND_RETURN_BY_REF || (end - 1)->opcode == ZEND_GENERATOR_RETURN)
 452          && ((op_array->last > 1 && ((end - 2)->opcode == ZEND_RETURN || (end - 2)->opcode == ZEND_RETURN_BY_REF || (end - 2)->opcode == ZEND_GENERATOR_RETURN || (end - 2)->opcode == ZEND_THROW))
 453           || op_array->function_name == NULL || (end - 1)->extended_value == -1))) {
 454                 end--;
 455         }
 456 
 457         for (; cur < end; cur++) {
 458                 if (cur->opcode == ZEND_NOP || cur->opcode == ZEND_OP_DATA || cur->opcode == ZEND_FE_FREE || cur->opcode == ZEND_FREE || cur->opcode == ZEND_ASSERT_CHECK || cur->opcode == ZEND_VERIFY_RETURN_TYPE
 459                  || cur->opcode == ZEND_DECLARE_CONST || cur->opcode == ZEND_DECLARE_CLASS || cur->opcode == ZEND_DECLARE_INHERITED_CLASS || cur->opcode == ZEND_DECLARE_FUNCTION
 460                  || cur->opcode == ZEND_DECLARE_INHERITED_CLASS_DELAYED || cur->opcode == ZEND_VERIFY_ABSTRACT_CLASS || cur->opcode == ZEND_ADD_TRAIT || cur->opcode == ZEND_BIND_TRAITS
 461                  || cur->opcode == ZEND_DECLARE_ANON_CLASS || cur->opcode == ZEND_DECLARE_ANON_INHERITED_CLASS || cur->opcode == ZEND_FAST_RET || cur->opcode == ZEND_TICKS
 462                  || cur->opcode == ZEND_EXT_STMT || cur->opcode == ZEND_EXT_FCALL_BEGIN || cur->opcode == ZEND_EXT_FCALL_END || cur->opcode == ZEND_EXT_NOP || cur->opcode == ZEND_BIND_GLOBAL) {
 463                         continue;
 464                 }
 465 
 466                 if (by_opcode) {
 467                         insert_idx = cur - op_array->opcodes;
 468                 } else {
 469                         insert_idx = cur->lineno;
 470                 }
 471 
 472                 if (cur->opcode == ZEND_NEW && (cur + 1)->opcode == ZEND_DO_FCALL) {
 473                         cur++;
 474                 }
 475 
 476                 zend_hash_index_update(insert_ht, insert_idx, &zero);
 477         }
 478 }
 479 
 480 static inline HashTable* phpdbg_add_empty_array(HashTable *ht, zend_string *name) {
 481         zval *ht_zv = zend_hash_find(ht, name);
 482         if (!ht_zv) {
 483                 zval zv;
 484                 array_init(&zv);
 485                 ht_zv = zend_hash_add_new(ht, name, &zv);
 486         }
 487         return Z_ARR_P(ht_zv);
 488 }
 489 
 490 /* {{{ proto void phpdbg_end_oplog() */
 491 static PHP_FUNCTION(phpdbg_get_executable)
 492 {
 493         HashTable *options = NULL;
 494         zval *option_buffer;
 495         zend_bool by_function = 0;
 496         zend_bool by_opcode = 0;
 497         HashTable *insert_ht;
 498 
 499         zend_function *func;
 500         zend_class_entry *ce;
 501         zend_string *name;
 502         HashTable *files = &PHPDBG_G(file_sources);
 503         HashTable files_tmp;
 504 
 505         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|H", &options) == FAILURE) {
 506                 return;
 507         }
 508 
 509         if (options && (option_buffer = zend_hash_str_find(options, ZEND_STRL("functions")))) {
 510                 by_function = zend_is_true(option_buffer);
 511         }
 512 
 513         if (options && (option_buffer = zend_hash_str_find(options, ZEND_STRL("opcodes")))) {
 514                 if (by_function) {
 515                         by_opcode = zend_is_true(option_buffer);
 516                 }
 517         }
 518 
 519         if (options && (option_buffer = zend_hash_str_find(options, ZEND_STRL("files")))) {
 520                 ZVAL_DEREF(option_buffer);
 521                 if (Z_TYPE_P(option_buffer) == IS_ARRAY && zend_hash_num_elements(Z_ARR_P(option_buffer)) > 0) {
 522                         zval *filename;
 523 
 524                         files = &files_tmp;
 525                         zend_hash_init(files, 0, NULL, NULL, 0);
 526 
 527                         ZEND_HASH_FOREACH_VAL(Z_ARR_P(option_buffer), filename) {
 528                                 zend_hash_add_empty_element(files, zval_get_string(filename));
 529                         } ZEND_HASH_FOREACH_END();
 530                 } else {
 531                         GC_REFCOUNT(files)++;
 532                 }
 533         } else {
 534                 GC_REFCOUNT(files)++;
 535         }
 536 
 537         array_init(return_value);
 538 
 539         ZEND_HASH_FOREACH_STR_KEY_PTR(EG(function_table), name, func) {
 540                 if (func->type == ZEND_USER_FUNCTION) {
 541                         if (zend_hash_exists(files, func->op_array.filename)) {
 542                                 insert_ht = phpdbg_add_empty_array(Z_ARR_P(return_value), func->op_array.filename);
 543 
 544                                 if (by_function) {
 545                                         insert_ht = phpdbg_add_empty_array(insert_ht, name);
 546                                 }
 547 
 548                                 phpdbg_oplog_fill_executable(&func->op_array, insert_ht, by_opcode);
 549                         }
 550                 }
 551         } ZEND_HASH_FOREACH_END();
 552 
 553         ZEND_HASH_FOREACH_STR_KEY_PTR(EG(class_table), name, ce) {
 554                 if (ce->type == ZEND_USER_CLASS) {
 555                         if (zend_hash_exists(files, ce->info.user.filename)) {
 556                                 ZEND_HASH_FOREACH_PTR(&ce->function_table, func) {
 557                                         if (func->type == ZEND_USER_FUNCTION && zend_hash_exists(files, func->op_array.filename)) {
 558                                                 insert_ht = phpdbg_add_empty_array(Z_ARR_P(return_value), func->op_array.filename);
 559 
 560                                                 if (by_function) {
 561                                                         zend_string *fn_name = strpprintf(ZSTR_LEN(name) + ZSTR_LEN(func->op_array.function_name) + 2, "%.*s::%.*s", (int) ZSTR_LEN(name), ZSTR_VAL(name), (int) ZSTR_LEN(func->op_array.function_name), ZSTR_VAL(func->op_array.function_name));
 562                                                         insert_ht = phpdbg_add_empty_array(insert_ht, fn_name);
 563                                                         zend_string_release(fn_name);
 564                                                 }
 565 
 566                                                 phpdbg_oplog_fill_executable(&func->op_array, insert_ht, by_opcode);
 567                                         }
 568                                 } ZEND_HASH_FOREACH_END();
 569                         }
 570                 }
 571         } ZEND_HASH_FOREACH_END();
 572 
 573         ZEND_HASH_FOREACH_STR_KEY(files, name) {
 574                 phpdbg_file_source *source = zend_hash_find_ptr(&PHPDBG_G(file_sources), name);
 575                 if (source) {
 576                         phpdbg_oplog_fill_executable(
 577                                 &source->op_array,
 578                                 phpdbg_add_empty_array(Z_ARR_P(return_value), source->op_array.filename),
 579                                 by_opcode);
 580                 }
 581         } ZEND_HASH_FOREACH_END();
 582 
 583         if (!--GC_REFCOUNT(files)) {
 584                 zend_hash_destroy(files);
 585         }
 586 }
 587 
 588 /* {{{ proto void phpdbg_end_oplog() */
 589 static PHP_FUNCTION(phpdbg_end_oplog)
 590 {
 591         phpdbg_oplog_entry *cur;
 592         phpdbg_oplog_list *prev;
 593 
 594         HashTable *options = NULL;
 595         zval *option_buffer;
 596         zend_bool by_function = 0;
 597         zend_bool by_opcode = 0;
 598 
 599         if (zend_parse_parameters(ZEND_NUM_ARGS(), "|H", &options) == FAILURE) {
 600                 return;
 601         }
 602 
 603         if (!PHPDBG_G(oplog_list)) {
 604                 zend_error(E_WARNING, "Can not end an oplog without starting it");
 605                 return;
 606         }
 607 
 608         cur = PHPDBG_G(oplog_list)->start;
 609         prev = PHPDBG_G(oplog_list)->prev;
 610 
 611         efree(PHPDBG_G(oplog_list));
 612         PHPDBG_G(oplog_list) = prev;
 613 
 614         if (options && (option_buffer = zend_hash_str_find(options, ZEND_STRL("functions")))) {
 615                 by_function = zend_is_true(option_buffer);
 616         }
 617 
 618         if (options && (option_buffer = zend_hash_str_find(options, ZEND_STRL("opcodes")))) {
 619                 if (by_function) {
 620                         by_opcode = zend_is_true(option_buffer);
 621                 }
 622         }
 623 
 624         array_init(return_value);
 625 
 626         {
 627                 zend_string *last_file = NULL;
 628                 HashTable *file_ht;
 629                 zend_string *last_function = (void *)~(uintptr_t)0;
 630                 zend_class_entry *last_scope = NULL;
 631 
 632                 HashTable *insert_ht;
 633                 zend_long insert_idx;
 634 
 635                 do {
 636                         zval zero;
 637                         ZVAL_LONG(&zero, 0);
 638 
 639                         if (cur->filename != last_file) {
 640                                 last_file = cur->filename;
 641                                 file_ht = insert_ht = phpdbg_add_empty_array(Z_ARR_P(return_value), last_file);
 642                         }
 643 
 644                         if (by_function) {
 645                                 if (cur->function_name == NULL) {
 646                                         if (last_function != NULL) {
 647                                                 insert_ht = file_ht;
 648                                         }
 649                                         last_function = NULL;
 650                                 } else if (cur->function_name != last_function || cur->scope != last_scope) {
 651                                         zend_string *fn_name;
 652                                         last_function = cur->function_name;
 653                                         last_scope = cur->scope;
 654                                         if (last_scope == NULL) {
 655                                                 fn_name = zend_string_copy(last_function);
 656                                         } else {
 657                                                 fn_name = strpprintf(ZSTR_LEN(last_function) + ZSTR_LEN(last_scope->name) + 2, "%.*s::%.*s", (int) ZSTR_LEN(last_scope->name), ZSTR_VAL(last_scope->name), (int) ZSTR_LEN(last_function), ZSTR_VAL(last_function));
 658                                         }
 659                                         insert_ht = phpdbg_add_empty_array(Z_ARR_P(return_value), fn_name);
 660                                         zend_string_release(fn_name);
 661                                 }
 662                         }
 663 
 664                         if (by_opcode) {
 665                                 insert_idx = cur->op - cur->opcodes;
 666                         } else {
 667                                 insert_idx = cur->op->lineno;
 668                         }
 669 
 670                         {
 671                                 zval *num = zend_hash_index_find(insert_ht, insert_idx);
 672                                 if (!num) {
 673                                         num = zend_hash_index_add_new(insert_ht, insert_idx, &zero);
 674                                 }
 675                                 Z_LVAL_P(num)++;
 676                         }
 677 
 678                         cur = cur->next;
 679                 } while (cur != NULL);
 680         }
 681 
 682         if (!prev) {
 683                 zend_arena_destroy(PHPDBG_G(oplog_arena));
 684         }
 685 }
 686 
 687 ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_next_arginfo, 0, 0, 0)
 688 ZEND_END_ARG_INFO()
 689 
 690 ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_file_arginfo, 0, 0, 2)
 691         ZEND_ARG_INFO(0, file)
 692         ZEND_ARG_INFO(0, line)
 693 ZEND_END_ARG_INFO()
 694 
 695 ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_method_arginfo, 0, 0, 2)
 696         ZEND_ARG_INFO(0, class)
 697         ZEND_ARG_INFO(0, method)
 698 ZEND_END_ARG_INFO()
 699 
 700 ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_function_arginfo, 0, 0, 1)
 701         ZEND_ARG_INFO(0, function)
 702 ZEND_END_ARG_INFO()
 703 
 704 ZEND_BEGIN_ARG_INFO_EX(phpdbg_color_arginfo, 0, 0, 0)
 705         ZEND_ARG_INFO(0, element)
 706         ZEND_ARG_INFO(0, color)
 707 ZEND_END_ARG_INFO()
 708 
 709 ZEND_BEGIN_ARG_INFO_EX(phpdbg_prompt_arginfo, 0, 0, 0)
 710         ZEND_ARG_INFO(0, string)
 711 ZEND_END_ARG_INFO()
 712 
 713 ZEND_BEGIN_ARG_INFO_EX(phpdbg_exec_arginfo, 0, 0, 0)
 714         ZEND_ARG_INFO(0, context)
 715 ZEND_END_ARG_INFO()
 716 
 717 ZEND_BEGIN_ARG_INFO_EX(phpdbg_clear_arginfo, 0, 0, 0)
 718 ZEND_END_ARG_INFO()
 719 
 720 ZEND_BEGIN_ARG_INFO_EX(phpdbg_start_oplog_arginfo, 0, 0, 0)
 721 ZEND_END_ARG_INFO()
 722 
 723 ZEND_BEGIN_ARG_INFO_EX(phpdbg_end_oplog_arginfo, 0, 0, 0)
 724         ZEND_ARG_INFO(0, options)
 725 ZEND_END_ARG_INFO()
 726 
 727 ZEND_BEGIN_ARG_INFO_EX(phpdbg_get_executable_arginfo, 0, 0, 0)
 728         ZEND_ARG_INFO(0, options)
 729 ZEND_END_ARG_INFO()
 730 
 731 zend_function_entry phpdbg_user_functions[] = {
 732         PHP_FE(phpdbg_clear, phpdbg_clear_arginfo)
 733         PHP_FE(phpdbg_break_next, phpdbg_break_next_arginfo)
 734         PHP_FE(phpdbg_break_file, phpdbg_break_file_arginfo)
 735         PHP_FE(phpdbg_break_method, phpdbg_break_method_arginfo)
 736         PHP_FE(phpdbg_break_function, phpdbg_break_function_arginfo)
 737         PHP_FE(phpdbg_exec,  phpdbg_exec_arginfo)
 738         PHP_FE(phpdbg_color, phpdbg_color_arginfo)
 739         PHP_FE(phpdbg_prompt, phpdbg_prompt_arginfo)
 740         PHP_FE(phpdbg_start_oplog, phpdbg_start_oplog_arginfo)
 741         PHP_FE(phpdbg_end_oplog, phpdbg_end_oplog_arginfo)
 742         PHP_FE(phpdbg_get_executable, phpdbg_get_executable_arginfo)
 743 #ifdef  PHP_FE_END
 744         PHP_FE_END
 745 #else
 746         {NULL,NULL,NULL}
 747 #endif
 748 };
 749 
 750 static zend_module_entry sapi_phpdbg_module_entry = {
 751         STANDARD_MODULE_HEADER,
 752         PHPDBG_NAME,
 753         phpdbg_user_functions,
 754         PHP_MINIT(phpdbg),
 755         NULL,
 756         PHP_RINIT(phpdbg),
 757         PHP_RSHUTDOWN(phpdbg),
 758         NULL,
 759         PHPDBG_VERSION,
 760         STANDARD_MODULE_PROPERTIES
 761 };
 762 
 763 static inline int php_sapi_phpdbg_module_startup(sapi_module_struct *module) /* {{{ */
 764 {
 765         if (php_module_startup(module, &sapi_phpdbg_module_entry, 1) == FAILURE) {
 766                 return FAILURE;
 767         }
 768 
 769         phpdbg_booted=1;
 770 
 771         return SUCCESS;
 772 } /* }}} */
 773 
 774 static char* php_sapi_phpdbg_read_cookies(void) /* {{{ */
 775 {
 776         return NULL;
 777 } /* }}} */
 778 
 779 static int php_sapi_phpdbg_header_handler(sapi_header_struct *h, sapi_header_op_enum op, sapi_headers_struct *s) /* {{{ */
 780 {
 781         return 0;
 782 }
 783 /* }}} */
 784 
 785 static int php_sapi_phpdbg_send_headers(sapi_headers_struct *sapi_headers) /* {{{ */
 786 {
 787         /* We do nothing here, this function is needed to prevent that the fallback
 788          * header handling is called. */
 789         return SAPI_HEADER_SENT_SUCCESSFULLY;
 790 }
 791 /* }}} */
 792 
 793 static void php_sapi_phpdbg_send_header(sapi_header_struct *sapi_header, void *server_context) /* {{{ */
 794 {
 795 }
 796 /* }}} */
 797 
 798 static void php_sapi_phpdbg_log_message(char *message) /* {{{ */
 799 {
 800         /*
 801         * We must not request TSRM before being booted
 802         */
 803         if (phpdbg_booted) {
 804                 if (PHPDBG_G(flags) & PHPDBG_IN_EVAL) {
 805                         phpdbg_error("eval", "msg=\"%s\"", "%s", message);
 806                         return;
 807                 }
 808 
 809                 phpdbg_error("php", "msg=\"%s\"", "%s", message);
 810 
 811                 if (PHPDBG_G(flags) & PHPDBG_PREVENT_INTERACTIVE) {
 812                         return;
 813                 }
 814 
 815                 switch (PG(last_error_type)) {
 816                         case E_ERROR:
 817                         case E_CORE_ERROR:
 818                         case E_COMPILE_ERROR:
 819                         case E_USER_ERROR:
 820                         case E_PARSE:
 821                         case E_RECOVERABLE_ERROR: {
 822                                 const char *file_char = zend_get_executed_filename();
 823                                 zend_string *file = zend_string_init(file_char, strlen(file_char), 0);
 824                                 phpdbg_list_file(file, 3, zend_get_executed_lineno() - 1, zend_get_executed_lineno());
 825                                 zend_string_release(file);
 826 
 827                                 if (!phpdbg_fully_started) {
 828                                         return;
 829                                 }
 830 
 831                                 do {
 832                                         switch (phpdbg_interactive(1)) {
 833                                                 case PHPDBG_LEAVE:
 834                                                 case PHPDBG_FINISH:
 835                                                 case PHPDBG_UNTIL:
 836                                                 case PHPDBG_NEXT:
 837                                                         return;
 838                                         }
 839                                 } while (!(PHPDBG_G(flags) & PHPDBG_IS_STOPPING));
 840                         }
 841                 }
 842         } else {
 843                 fprintf(stdout, "%s\n", message);
 844         }
 845 }
 846 /* }}} */
 847 
 848 static int php_sapi_phpdbg_deactivate(void) /* {{{ */
 849 {
 850         fflush(stdout);
 851         if (SG(request_info).argv0) {
 852                 free(SG(request_info).argv0);
 853                 SG(request_info).argv0 = NULL;
 854         }
 855 
 856         return SUCCESS;
 857 }
 858 /* }}} */
 859 
 860 static void php_sapi_phpdbg_register_vars(zval *track_vars_array) /* {{{ */
 861 {
 862         size_t len;
 863         char  *docroot = "";
 864 
 865         /* In phpdbg mode, we consider the environment to be a part of the server variables
 866         */
 867         php_import_environment_variables(track_vars_array);
 868 
 869         if (PHPDBG_G(exec)) {
 870                 len = PHPDBG_G(exec_len);
 871                 if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", &PHPDBG_G(exec), PHPDBG_G(exec_len), &len)) {
 872                         php_register_variable("PHP_SELF", PHPDBG_G(exec), track_vars_array);
 873                 }
 874                 if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_NAME", &PHPDBG_G(exec), PHPDBG_G(exec_len), &len)) {
 875                         php_register_variable("SCRIPT_NAME", PHPDBG_G(exec), track_vars_array);
 876                 }
 877 
 878                 if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_FILENAME", &PHPDBG_G(exec), PHPDBG_G(exec_len), &len)) {
 879                         php_register_variable("SCRIPT_FILENAME", PHPDBG_G(exec), track_vars_array);
 880                 }
 881                 if (sapi_module.input_filter(PARSE_SERVER, "PATH_TRANSLATED", &PHPDBG_G(exec), PHPDBG_G(exec_len), &len)) {
 882                         php_register_variable("PATH_TRANSLATED", PHPDBG_G(exec), track_vars_array);
 883                 }
 884         }
 885 
 886         /* any old docroot will do */
 887         len = 0;
 888         if (sapi_module.input_filter(PARSE_SERVER, "DOCUMENT_ROOT", &docroot, len, &len)) {
 889                 php_register_variable("DOCUMENT_ROOT", docroot, track_vars_array);
 890         }
 891 }
 892 /* }}} */
 893 
 894 static inline size_t php_sapi_phpdbg_ub_write(const char *message, size_t length) /* {{{ */
 895 {
 896         if (PHPDBG_G(socket_fd) != -1 && !(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) {
 897                 send(PHPDBG_G(socket_fd), message, length, 0);
 898         }
 899         return phpdbg_script(P_STDOUT, "%.*s", (int) length, message);
 900 } /* }}} */
 901 
 902 /* beginning of struct, see main/streams/plain_wrapper.c line 111 */
 903 typedef struct {
 904         FILE *file;
 905         int fd;
 906 } php_stdio_stream_data;
 907 
 908 static size_t phpdbg_stdiop_write(php_stream *stream, const char *buf, size_t count) {
 909         php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract;
 910 
 911         while (data->fd >= 0) {
 912                 struct stat stat[3];
 913                 memset(stat, 0, sizeof(stat));
 914                 if (((fstat(fileno(stderr), &stat[2]) < 0) & (fstat(fileno(stdout), &stat[0]) < 0)) | (fstat(data->fd, &stat[1]) < 0)) {
 915                         break;
 916                 }
 917 
 918                 if (stat[0].st_dev == stat[1].st_dev && stat[0].st_ino == stat[1].st_ino) {
 919                         phpdbg_script(P_STDOUT, "%.*s", (int) count, buf);
 920                         return count;
 921                 }
 922                 if (stat[2].st_dev == stat[1].st_dev && stat[2].st_ino == stat[1].st_ino) {
 923                         phpdbg_script_ex(PHPDBG_G(io)[PHPDBG_STDERR].fd, P_STDERR, "%.*s", (int) count, buf);
 924                         return count;
 925                 }
 926                 break;
 927         }
 928 
 929         return PHPDBG_G(php_stdiop_write)(stream, buf, count);
 930 }
 931 
 932 static inline void php_sapi_phpdbg_flush(void *context)  /* {{{ */
 933 {
 934         if (!phpdbg_active_sigsafe_mem()) {
 935                 fflush(PHPDBG_G(io)[PHPDBG_STDOUT].ptr);
 936         }
 937 } /* }}} */
 938 
 939 /* copied from sapi/cli/php_cli.c cli_register_file_handles */
 940 static void phpdbg_register_file_handles(void) /* {{{ */
 941 {
 942         zval zin, zout, zerr;
 943         php_stream *s_in, *s_out, *s_err;
 944         php_stream_context *sc_in=NULL, *sc_out=NULL, *sc_err=NULL;
 945         zend_constant ic, oc, ec;
 946 
 947         s_in  = php_stream_open_wrapper_ex("php://stdin",  "rb", 0, NULL, sc_in);
 948         s_out = php_stream_open_wrapper_ex("php://stdout", "wb", 0, NULL, sc_out);
 949         s_err = php_stream_open_wrapper_ex("php://stderr", "wb", 0, NULL, sc_err);
 950 
 951         if (s_in==NULL || s_out==NULL || s_err==NULL) {
 952                 if (s_in) php_stream_close(s_in);
 953                 if (s_out) php_stream_close(s_out);
 954                 if (s_err) php_stream_close(s_err);
 955                 return;
 956         }
 957 
 958 #if PHP_DEBUG
 959         /* do not close stdout and stderr */
 960         s_out->flags |= PHP_STREAM_FLAG_NO_CLOSE;
 961         s_err->flags |= PHP_STREAM_FLAG_NO_CLOSE;
 962 #endif
 963 
 964         php_stream_to_zval(s_in,  &zin);
 965         php_stream_to_zval(s_out, &zout);
 966         php_stream_to_zval(s_err, &zerr);
 967 
 968         ic.value = zin;
 969         ic.flags = CONST_CS;
 970         ic.name = zend_string_init(ZEND_STRL("STDIN"), 0);
 971         ic.module_number = 0;
 972         zend_register_constant(&ic);
 973 
 974         oc.value = zout;
 975         oc.flags = CONST_CS;
 976         oc.name = zend_string_init(ZEND_STRL("STDOUT"), 0);
 977         oc.module_number = 0;
 978         zend_register_constant(&oc);
 979 
 980         ec.value = zerr;
 981         ec.flags = CONST_CS;
 982         ec.name = zend_string_init(ZEND_STRL("STDERR"), 0);
 983         ec.module_number = 0;
 984         zend_register_constant(&ec);
 985 }
 986 /* }}} */
 987 
 988 /* {{{ sapi_module_struct phpdbg_sapi_module
 989 */
 990 static sapi_module_struct phpdbg_sapi_module = {
 991         "phpdbg",                       /* name */
 992         "phpdbg",                       /* pretty name */
 993 
 994         php_sapi_phpdbg_module_startup, /* startup */
 995         php_module_shutdown_wrapper,    /* shutdown */
 996 
 997         NULL,                           /* activate */
 998         php_sapi_phpdbg_deactivate,     /* deactivate */
 999 
1000         php_sapi_phpdbg_ub_write,       /* unbuffered write */
1001         php_sapi_phpdbg_flush,          /* flush */
1002         NULL,                           /* get uid */
1003         NULL,                           /* getenv */
1004 
1005         php_error,                      /* error handler */
1006 
1007         php_sapi_phpdbg_header_handler, /* header handler */
1008         php_sapi_phpdbg_send_headers,   /* send headers handler */
1009         php_sapi_phpdbg_send_header,    /* send header handler */
1010 
1011         NULL,                           /* read POST data */
1012         php_sapi_phpdbg_read_cookies,   /* read Cookies */
1013 
1014         php_sapi_phpdbg_register_vars,  /* register server variables */
1015         php_sapi_phpdbg_log_message,    /* Log message */
1016         NULL,                           /* Get request time */
1017         NULL,                           /* Child terminate */
1018         STANDARD_SAPI_MODULE_PROPERTIES
1019 };
1020 /* }}} */
1021 
1022 const opt_struct OPTIONS[] = { /* {{{ */
1023         {'c', 1, "ini path override"},
1024         {'d', 1, "define ini entry on command line"},
1025         {'n', 0, "no php.ini"},
1026         {'z', 1, "load zend_extension"},
1027         /* phpdbg options */
1028         {'q', 0, "no banner"},
1029         {'v', 0, "disable quietness"},
1030         {'b', 0, "boring colours"},
1031         {'i', 1, "specify init"},
1032         {'I', 0, "ignore init"},
1033         {'O', 1, "opline log"},
1034         {'r', 0, "run"},
1035         {'e', 0, "generate ext_stmt opcodes"},
1036         {'E', 0, "step-through-eval"},
1037         {'S', 1, "sapi-name"},
1038 #ifndef _WIN32
1039         {'l', 1, "listen"},
1040         {'a', 1, "address-or-any"},
1041 #endif
1042         {'x', 0, "xml output"},
1043         {'p', 2, "show opcodes"},
1044         {'h', 0, "help"},
1045         {'V', 0, "version"},
1046         {'-', 0, NULL}
1047 }; /* }}} */
1048 
1049 const char phpdbg_ini_hardcoded[] =
1050 "html_errors=Off\n"
1051 "register_argc_argv=On\n"
1052 "implicit_flush=On\n"
1053 "display_errors=Off\n"
1054 "log_errors=On\n"
1055 "max_execution_time=0\n"
1056 "max_input_time=-1\n"
1057 "error_log=\n"
1058 "output_buffering=off\n\0";
1059 
1060 /* overwriteable ini defaults must be set in phpdbg_ini_defaults() */
1061 #define INI_DEFAULT(name, value) \
1062         ZVAL_STRINGL(&tmp, value, sizeof(value) - 1); \
1063         zend_hash_str_update(configuration_hash, name, sizeof(name) - 1, &tmp);
1064 
1065 void phpdbg_ini_defaults(HashTable *configuration_hash) /* {{{ */
1066 {
1067         zval tmp;
1068         INI_DEFAULT("report_zend_debug", "0");
1069 } /* }}} */
1070 
1071 static void phpdbg_welcome(zend_bool cleaning) /* {{{ */
1072 {
1073         /* print blurb */
1074         if (!cleaning) {
1075                 phpdbg_xml("<intros>");
1076                 phpdbg_notice("intro", "version=\"%s\"", "Welcome to phpdbg, the interactive PHP debugger, v%s", PHPDBG_VERSION);
1077                 phpdbg_writeln("intro", "help=\"help\"", "To get help using phpdbg type \"help\" and press enter");
1078                 phpdbg_notice("intro", "report=\"%s\"", "Please report bugs to <%s>", PHPDBG_ISSUES);
1079                 phpdbg_xml("</intros>");
1080         } else if (phpdbg_startup_run == 0) {
1081                 if (!(PHPDBG_G(flags) & PHPDBG_WRITE_XML)) {
1082                         phpdbg_notice(NULL, NULL, "Clean Execution Environment");
1083                 }
1084 
1085                 phpdbg_write("cleaninfo", "classes=\"%d\" functions=\"%d\" constants=\"%d\" includes=\"%d\"",
1086                         "Classes              %d\n"
1087                         "Functions            %d\n"
1088                         "Constants            %d\n"
1089                         "Includes             %d\n",
1090                         zend_hash_num_elements(EG(class_table)),
1091                         zend_hash_num_elements(EG(function_table)),
1092                         zend_hash_num_elements(EG(zend_constants)),
1093                         zend_hash_num_elements(&EG(included_files)));
1094         }
1095 } /* }}} */
1096 
1097 static inline void phpdbg_sigint_handler(int signo) /* {{{ */
1098 {
1099 
1100         if (PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE) {
1101                 /* we quit remote consoles on recv SIGINT */
1102                 if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) {
1103                         PHPDBG_G(flags) |= PHPDBG_IS_STOPPING;
1104                         zend_bailout();
1105                 }
1106         } else {
1107                 /* set signalled only when not interactive */
1108                 if (PHPDBG_G(flags) & PHPDBG_IS_SIGNALED) {
1109                         char mem[PHPDBG_SIGSAFE_MEM_SIZE + 1];
1110 
1111                         phpdbg_set_sigsafe_mem(mem);
1112                         zend_try {
1113                                 phpdbg_force_interruption();
1114                         } zend_end_try()
1115                         phpdbg_clear_sigsafe_mem();
1116 
1117                         PHPDBG_G(flags) &= ~PHPDBG_IS_SIGNALED;
1118 
1119                         if (PHPDBG_G(flags) & PHPDBG_IS_STOPPING) {
1120                                 zend_bailout();
1121                         }
1122                 } else {
1123                         PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED;
1124                 }
1125         }
1126 } /* }}} */
1127 
1128 static void phpdbg_remote_close(int socket, FILE *stream) {
1129         if (socket >= 0) {
1130                 phpdbg_close_socket(socket);
1131         }
1132 
1133         if (stream) {
1134                 fclose(stream);
1135         }
1136 }
1137 
1138 /* don't inline this, want to debug it easily, will inline when done */
1139 static int phpdbg_remote_init(const char* address, unsigned short port, int server, int *socket, FILE **stream) {
1140         phpdbg_remote_close(*socket, *stream);
1141 
1142         if (server < 0) {
1143                 phpdbg_rlog(fileno(stderr), "Initializing connection on %s:%u failed", address, port);
1144 
1145                 return FAILURE;
1146         }
1147 
1148         phpdbg_rlog(fileno(stderr), "accepting connections on %s:%u", address, port);
1149         {
1150                 struct sockaddr_storage address;
1151                 socklen_t size = sizeof(address);
1152                 char buffer[20] = {0};
1153                 /* XXX error checks */
1154                 memset(&address, 0, size);
1155                 *socket = accept(server, (struct sockaddr *) &address, &size);
1156                 inet_ntop(AF_INET, &(((struct sockaddr_in *)&address)->sin_addr), buffer, sizeof(buffer));
1157 
1158                 phpdbg_rlog(fileno(stderr), "connection established from %s", buffer);
1159         }
1160 
1161 #ifndef _WIN32
1162         dup2(*socket, fileno(stdout));
1163         dup2(*socket, fileno(stdin));
1164 
1165         setbuf(stdout, NULL);
1166 
1167         *stream = fdopen(*socket, "r+");
1168 
1169         phpdbg_set_async_io(*socket);
1170 #endif
1171         return SUCCESS;
1172 }
1173 
1174 #ifndef _WIN32
1175 /* This function *strictly* assumes that SIGIO is *only* used on the remote connection stream */
1176 void phpdbg_sigio_handler(int sig, siginfo_t *info, void *context) /* {{{ */
1177 {
1178         int flags;
1179         size_t newlen;
1180         size_t i/*, last_nl*/;
1181 
1182 //      if (!(info->si_band & POLLIN)) {
1183 //              return; /* Not interested in writeablility etc., just interested in incoming data */
1184 //      }
1185 
1186         /* only non-blocking reading, avoid non-blocking writing */
1187         flags = fcntl(PHPDBG_G(io)[PHPDBG_STDIN].fd, F_GETFL, 0);
1188         fcntl(PHPDBG_G(io)[PHPDBG_STDIN].fd, F_SETFL, flags | O_NONBLOCK);
1189 
1190         do {
1191                 char mem[PHPDBG_SIGSAFE_MEM_SIZE + 1];
1192                 size_t off = 0;
1193 
1194                 if ((newlen = recv(PHPDBG_G(io)[PHPDBG_STDIN].fd, mem, PHPDBG_SIGSAFE_MEM_SIZE, MSG_PEEK)) == (size_t) -1) {
1195                         break;
1196                 }
1197                 for (i = 0; i < newlen; i++) {
1198                         switch (mem[off + i]) {
1199                                 case '\x03': /* ^C char */
1200                                         if (PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE) {
1201                                                 break; /* or quit ??? */
1202                                         }
1203                                         if (PHPDBG_G(flags) & PHPDBG_IS_SIGNALED) {
1204                                                 phpdbg_set_sigsafe_mem(mem);
1205                                                 zend_try {
1206                                                         phpdbg_force_interruption();
1207                                                 } zend_end_try();
1208                                                 phpdbg_clear_sigsafe_mem();
1209 
1210                                                 PHPDBG_G(flags) &= ~PHPDBG_IS_SIGNALED;
1211 
1212                                                 if (PHPDBG_G(flags) & PHPDBG_IS_STOPPING) {
1213                                                         zend_bailout();
1214                                                 }
1215                                         } else if (!(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) {
1216                                                 PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED;
1217                                         }
1218                                         break;
1219 /*                              case '\n':
1220                                         zend_llist_add_element(PHPDBG_G(stdin), strndup()
1221                                         last_nl = PHPDBG_G(stdin_buf).len + i;
1222                                         break;
1223 */                      }
1224                 }
1225                 off += i;
1226         } while (0);
1227 
1228 
1229         fcntl(PHPDBG_G(io)[PHPDBG_STDIN].fd, F_SETFL, flags);
1230 } /* }}} */
1231 
1232 void phpdbg_signal_handler(int sig, siginfo_t *info, void *context) /* {{{ */
1233 {
1234         int is_handled = FAILURE;
1235 
1236         switch (sig) {
1237                 case SIGBUS:
1238                 case SIGSEGV:
1239                         if (PHPDBG_G(sigsegv_bailout)) {
1240                                 LONGJMP(*PHPDBG_G(sigsegv_bailout), FAILURE);
1241                         }
1242                         is_handled = phpdbg_watchpoint_segfault_handler(info, context);
1243                         if (is_handled == FAILURE) {
1244 #ifdef ZEND_SIGNALS
1245                                 zend_sigaction(sig, &PHPDBG_G(old_sigsegv_signal), NULL);
1246 #else
1247                                 sigaction(sig, &PHPDBG_G(old_sigsegv_signal), NULL);
1248 #endif
1249                         }
1250                         break;
1251         }
1252 
1253 } /* }}} */
1254 #endif
1255 
1256 void phpdbg_sighup_handler(int sig) /* {{{ */
1257 {
1258         exit(0);
1259 } /* }}} */
1260 
1261 void *phpdbg_malloc_wrapper(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) /* {{{ */
1262 {
1263         return _zend_mm_alloc(zend_mm_get_heap(), size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
1264 } /* }}} */
1265 
1266 void phpdbg_free_wrapper(void *p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) /* {{{ */
1267 {
1268         zend_mm_heap *heap = zend_mm_get_heap();
1269         if (UNEXPECTED(heap == p)) {
1270                 /* TODO: heap maybe allocated by mmap(zend_mm_init) or malloc(USE_ZEND_ALLOC=0) 
1271                  * let's prevent it from segfault for now
1272                  */
1273         } else {
1274                 phpdbg_watch_efree(p);
1275                 return _zend_mm_free(heap, p ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
1276         }
1277 } /* }}} */
1278 
1279 void *phpdbg_realloc_wrapper(void *ptr, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) /* {{{ */
1280 {
1281         return _zend_mm_realloc(zend_mm_get_heap(), ptr, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
1282 } /* }}} */
1283 
1284 int main(int argc, char **argv) /* {{{ */
1285 {
1286         sapi_module_struct *phpdbg = &phpdbg_sapi_module;
1287         char *sapi_name;
1288         char *ini_entries;
1289         int   ini_entries_len;
1290         char **zend_extensions = NULL;
1291         zend_ulong zend_extensions_len = 0L;
1292         zend_bool ini_ignore;
1293         char *ini_override;
1294         char *exec = NULL;
1295         char *init_file;
1296         size_t init_file_len;
1297         zend_bool init_file_default;
1298         char *oplog_file;
1299         size_t oplog_file_len;
1300         uint64_t flags;
1301         char *php_optarg;
1302         int php_optind, opt, show_banner = 1;
1303         long cleaning = -1;
1304         volatile zend_bool quit_immediately = 0; /* somehow some gcc release builds will play a bit around with order in combination with setjmp..., hence volatile */
1305         zend_bool remote = 0;
1306         zend_phpdbg_globals *settings = NULL;
1307         char *bp_tmp = NULL;
1308         char *address;
1309         int listen = -1;
1310         int server = -1;
1311         int socket = -1;
1312         FILE* stream = NULL;
1313         char *print_opline_func;
1314         zend_bool ext_stmt = 0;
1315         zend_bool use_mm_wrappers = 0;
1316         zend_bool is_exit;
1317         int exit_status;
1318 
1319 #ifndef _WIN32
1320         struct sigaction sigio_struct;
1321         struct sigaction signal_struct;
1322         signal_struct.sa_sigaction = phpdbg_signal_handler;
1323         signal_struct.sa_flags = SA_SIGINFO | SA_NODEFER;
1324         sigemptyset(&signal_struct.sa_mask);
1325         sigio_struct.sa_sigaction = phpdbg_sigio_handler;
1326         sigio_struct.sa_flags = SA_SIGINFO;
1327         sigemptyset(&sigio_struct.sa_mask);
1328 
1329         address = strdup("127.0.0.1");
1330 #endif
1331 
1332 #ifdef PHP_WIN32
1333         _fmode = _O_BINARY;                 /* sets default for file streams to binary */
1334         setmode(_fileno(stdin), O_BINARY);  /* make the stdio mode be binary */
1335         setmode(_fileno(stdout), O_BINARY); /* make the stdio mode be binary */
1336         setmode(_fileno(stderr), O_BINARY); /* make the stdio mode be binary */
1337 #endif
1338 
1339 #ifdef ZTS
1340         tsrm_startup(1, 1, 0, NULL);
1341         (void)ts_resource(0);
1342         ZEND_TSRMLS_CACHE_UPDATE();
1343 #endif
1344 
1345 #ifdef ZEND_SIGNALS
1346         zend_signal_startup();
1347 #endif
1348 
1349 phpdbg_main:
1350         ini_entries = NULL;
1351         ini_entries_len = 0;
1352         ini_ignore = 0;
1353         ini_override = NULL;
1354         zend_extensions = NULL;
1355         zend_extensions_len = 0L;
1356         init_file = NULL;
1357         init_file_len = 0;
1358         init_file_default = 1;
1359         oplog_file = NULL;
1360         oplog_file_len = 0;
1361         flags = PHPDBG_DEFAULT_FLAGS;
1362         is_exit = 0;
1363         php_optarg = NULL;
1364         php_optind = 1;
1365         opt = 0;
1366         sapi_name = NULL;
1367         exit_status = 0;
1368         if (settings) {
1369                 exec = settings->exec;
1370         }
1371 
1372         while ((opt = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) {
1373                 switch (opt) {
1374                         case 'r':
1375                                 if (settings == NULL) {
1376                                         phpdbg_startup_run++;
1377                                 }
1378                                 break;
1379                         case 'n':
1380                                 ini_ignore = 1;
1381                                 break;
1382                         case 'c':
1383                                 if (ini_override) {
1384                                         free(ini_override);
1385                                 }
1386                                 ini_override = strdup(php_optarg);
1387                                 break;
1388                         case 'd': {
1389                                 int len = strlen(php_optarg);
1390                                 char *val;
1391 
1392                                 if ((val = strchr(php_optarg, '='))) {
1393                                   val++;
1394                                   if (!isalnum(*val) && *val != '"' && *val != '\'' && *val != '\0') {
1395                                           ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("\"\"\n\0"));
1396                                           memcpy(ini_entries + ini_entries_len, php_optarg, (val - php_optarg));
1397                                           ini_entries_len += (val - php_optarg);
1398                                           memcpy(ini_entries + ini_entries_len, "\"", 1);
1399                                           ini_entries_len++;
1400                                           memcpy(ini_entries + ini_entries_len, val, len - (val - php_optarg));
1401                                           ini_entries_len += len - (val - php_optarg);
1402                                           memcpy(ini_entries + ini_entries_len, "\"\n\0", sizeof("\"\n\0"));
1403                                           ini_entries_len += sizeof("\n\0\"") - 2;
1404                                   } else {
1405                                           ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("\n\0"));
1406                                           memcpy(ini_entries + ini_entries_len, php_optarg, len);
1407                                           memcpy(ini_entries + ini_entries_len + len, "\n\0", sizeof("\n\0"));
1408                                           ini_entries_len += len + sizeof("\n\0") - 2;
1409                                   }
1410                                 } else {
1411                                   ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("=1\n\0"));
1412                                   memcpy(ini_entries + ini_entries_len, php_optarg, len);
1413                                   memcpy(ini_entries + ini_entries_len + len, "=1\n\0", sizeof("=1\n\0"));
1414                                   ini_entries_len += len + sizeof("=1\n\0") - 2;
1415                                 }
1416                         } break;
1417 
1418                         case 'z':
1419                                 zend_extensions_len++;
1420                                 if (zend_extensions) {
1421                                         zend_extensions = realloc(zend_extensions, sizeof(char*) * zend_extensions_len);
1422                                 } else zend_extensions = malloc(sizeof(char*) * zend_extensions_len);
1423                                 zend_extensions[zend_extensions_len-1] = strdup(php_optarg);
1424                         break;
1425 
1426                         /* begin phpdbg options */
1427 
1428                         case 'S': { /* set SAPI name */
1429                                 if (sapi_name) {
1430                                         free(sapi_name);
1431                                 }
1432                                 sapi_name = strdup(php_optarg);
1433                         } break;
1434 
1435                         case 'I': { /* ignore .phpdbginit */
1436                                 init_file_default = 0;
1437                         } break;
1438 
1439                         case 'i': { /* set init file */
1440                                 if (init_file) {
1441                                         free(init_file);
1442                                 }
1443 
1444                                 init_file_len = strlen(php_optarg);
1445                                 if (init_file_len) {
1446                                         init_file = strdup(php_optarg);
1447                                 }
1448                         } break;
1449 
1450                         case 'O': { /* set oplog output */
1451                                 oplog_file_len = strlen(php_optarg);
1452                                 if (oplog_file_len) {
1453                                         oplog_file = strdup(php_optarg);
1454                                 }
1455                         } break;
1456 
1457                         case 'v': /* set quietness off */
1458                                 flags &= ~PHPDBG_IS_QUIET;
1459                         break;
1460 
1461                         case 'e':
1462                                 ext_stmt = 1;
1463                         break;
1464 
1465                         case 'E': /* stepping through eval on */
1466                                 flags |= PHPDBG_IS_STEPONEVAL;
1467                         break;
1468 
1469                         case 'b': /* set colours off */
1470                                 flags &= ~PHPDBG_IS_COLOURED;
1471                         break;
1472 
1473                         case 'q': /* hide banner */
1474                                 show_banner = 0;
1475                         break;
1476 
1477 #ifndef _WIN32
1478                         /* if you pass a listen port, we will read and write on listen port */
1479                         case 'l': /* set listen ports */
1480                                 if (sscanf(php_optarg, "%d", &listen) != 1) {
1481                                         listen = 8000;
1482                                 }
1483                         break;
1484 
1485                         case 'a': { /* set bind address */
1486                                 free(address);
1487                                 if (!php_optarg) {
1488                                         address = strdup("*");
1489                                 } else address = strdup(php_optarg);
1490                         } break;
1491 #endif
1492 
1493                         case 'x':
1494                                 flags |= PHPDBG_WRITE_XML;
1495                         break;
1496 
1497 
1498                         case 'p': {
1499                                 print_opline_func = php_optarg;
1500                                 show_banner = 0;
1501                                 settings = (void *) 0x1;
1502                         } break;
1503 
1504                         case 'h': {
1505                                 sapi_startup(phpdbg);
1506                                 phpdbg->startup(phpdbg);
1507                                 PHPDBG_G(flags) = 0;
1508                                 /* It ain't gonna proceed to real execution anyway,
1509                                         but the correct descriptor is needed already. */
1510                                 PHPDBG_G(io)[PHPDBG_STDOUT].ptr = stdout;
1511                                 PHPDBG_G(io)[PHPDBG_STDOUT].fd = fileno(stdout);
1512                                 phpdbg_set_prompt(PHPDBG_DEFAULT_PROMPT);
1513                                 phpdbg_do_help(NULL);
1514                                 sapi_deactivate();
1515                                 sapi_shutdown();
1516                                 return 0;
1517                         } break;
1518 
1519                         case 'V': {
1520                                 sapi_startup(phpdbg);
1521                                 phpdbg->startup(phpdbg);
1522                                 printf(
1523                                         "phpdbg %s (built: %s %s)\nPHP %s, Copyright (c) 1997-2016 The PHP Group\n%s",
1524                                         PHPDBG_VERSION,
1525                                         __DATE__,
1526                                         __TIME__,
1527                                         PHP_VERSION,
1528                                         get_zend_version()
1529                                 );
1530                                 sapi_deactivate();
1531                                 sapi_shutdown();
1532                                 return 0;
1533                         } break;
1534                 }
1535 
1536                 php_optarg = NULL;
1537         }
1538 
1539         /* set exec if present on command line */
1540         if (argc > php_optind && (strcmp(argv[php_optind-1], "--") != SUCCESS)) {
1541                 if (!exec && strlen(argv[php_optind])) {
1542                         exec = strdup(argv[php_optind]);
1543                 }
1544                 php_optind++;
1545         }
1546 
1547         if (sapi_name) {
1548                 phpdbg->name = sapi_name;
1549         }
1550 
1551         phpdbg->ini_defaults = phpdbg_ini_defaults;
1552         phpdbg->phpinfo_as_text = 1;
1553         phpdbg->php_ini_ignore_cwd = 1;
1554 
1555         sapi_startup(phpdbg);
1556 
1557         phpdbg->executable_location = argv[0];
1558         phpdbg->phpinfo_as_text = 1;
1559         phpdbg->php_ini_ignore = ini_ignore;
1560         phpdbg->php_ini_path_override = ini_override;
1561 
1562         if (ini_entries) {
1563                 ini_entries = realloc(ini_entries, ini_entries_len + sizeof(phpdbg_ini_hardcoded));
1564                 memmove(ini_entries + sizeof(phpdbg_ini_hardcoded) - 2, ini_entries, ini_entries_len + 1);
1565                 memcpy(ini_entries, phpdbg_ini_hardcoded, sizeof(phpdbg_ini_hardcoded) - 2);
1566         } else {
1567                 ini_entries = malloc(sizeof(phpdbg_ini_hardcoded));
1568                 memcpy(ini_entries, phpdbg_ini_hardcoded, sizeof(phpdbg_ini_hardcoded));
1569         }
1570         ini_entries_len += sizeof(phpdbg_ini_hardcoded) - 2;
1571 
1572         if (zend_extensions_len) {
1573                 zend_ulong zend_extension = 0L;
1574 
1575                 while (zend_extension < zend_extensions_len) {
1576                         const char *ze = zend_extensions[zend_extension];
1577                         size_t ze_len = strlen(ze);
1578 
1579                         ini_entries = realloc(
1580                                 ini_entries, ini_entries_len + (ze_len + (sizeof("zend_extension=\n"))));
1581                         memcpy(&ini_entries[ini_entries_len], "zend_extension=", (sizeof("zend_extension=\n")-1));
1582                         ini_entries_len += (sizeof("zend_extension=")-1);
1583                         memcpy(&ini_entries[ini_entries_len], ze, ze_len);
1584                         ini_entries_len += ze_len;
1585                         memcpy(&ini_entries[ini_entries_len], "\n", (sizeof("\n") - 1));
1586 
1587                         free(zend_extensions[zend_extension]);
1588                         zend_extension++;
1589                 }
1590 
1591                 free(zend_extensions);
1592         }
1593 
1594         phpdbg->ini_entries = ini_entries;
1595 
1596         if (phpdbg->startup(phpdbg) == SUCCESS) {
1597                 zend_mm_heap *mm_heap;
1598 #ifdef _WIN32
1599     EXCEPTION_POINTERS *xp;
1600     __try {
1601 #endif
1602                 void* (*_malloc)(size_t);
1603                 void (*_free)(void*);
1604                 void* (*_realloc)(void*, size_t);
1605 
1606                 /* set flags from command line */
1607                 PHPDBG_G(flags) = flags;
1608 
1609                 if (settings > (zend_phpdbg_globals *) 0x2) {
1610 #ifdef ZTS
1611                         *((zend_phpdbg_globals *) (*((void ***) TSRMLS_CACHE))[TSRM_UNSHUFFLE_RSRC_ID(phpdbg_globals_id)]) = *settings;
1612 #else
1613                         phpdbg_globals = *settings;
1614 #endif
1615                         free(settings);
1616                 }
1617 
1618                 /* setup remote server if necessary */
1619                 if (cleaning <= 0 && listen > 0) {
1620                         server = phpdbg_open_socket(address, listen);
1621                         if (-1 > server || phpdbg_remote_init(address, listen, server, &socket, &stream) == FAILURE) {
1622                                 exit(0);
1623                         }
1624 
1625 #ifndef _WIN32
1626                         sigaction(SIGIO, &sigio_struct, NULL);
1627 #endif
1628 
1629                         /* set remote flag to stop service shutting down upon quit */
1630                         remote = 1;
1631 #ifndef _WIN32
1632                 } else {
1633 
1634                         signal(SIGHUP, phpdbg_sighup_handler);
1635 #endif
1636                 }
1637 
1638                 mm_heap = zend_mm_get_heap();
1639                 zend_mm_get_custom_handlers(mm_heap, &_malloc, &_free, &_realloc);
1640 
1641                 use_mm_wrappers = !_malloc && !_realloc && !_free;
1642 
1643                 phpdbg_init_list();
1644 
1645                 PHPDBG_G(original_free_function) = _free;
1646                 _free = phpdbg_watch_efree;
1647 
1648                 if (use_mm_wrappers) {
1649 #if ZEND_DEBUG
1650                         zend_mm_set_custom_debug_handlers(mm_heap, phpdbg_malloc_wrapper, phpdbg_free_wrapper, phpdbg_realloc_wrapper);
1651 #else
1652                         zend_mm_set_custom_handlers(mm_heap, phpdbg_malloc_wrapper, phpdbg_free_wrapper, phpdbg_realloc_wrapper);
1653 #endif
1654                 } else {
1655                         zend_mm_set_custom_handlers(mm_heap, _malloc, _free, _realloc);
1656                 }
1657 
1658                 phpdbg_setup_watchpoints();
1659 
1660 #if defined(ZEND_SIGNALS) && !defined(_WIN32)
1661                 zend_try {
1662                         zend_signal_activate();
1663                 } zend_end_try();
1664 #endif
1665 
1666 #if defined(ZEND_SIGNALS) && !defined(_WIN32)
1667                 zend_try { zend_sigaction(SIGSEGV, &signal_struct, &PHPDBG_G(old_sigsegv_signal)); } zend_end_try();
1668                 zend_try { zend_sigaction(SIGBUS, &signal_struct, &PHPDBG_G(old_sigsegv_signal)); } zend_end_try();
1669 #elif !defined(_WIN32)
1670                 sigaction(SIGSEGV, &signal_struct, &PHPDBG_G(old_sigsegv_signal));
1671                 sigaction(SIGBUS, &signal_struct, &PHPDBG_G(old_sigsegv_signal));
1672 #endif
1673 
1674                 PHPDBG_G(sapi_name_ptr) = sapi_name;
1675 
1676                 if (exec) { /* set execution context */
1677                         PHPDBG_G(exec) = phpdbg_resolve_path(exec);
1678                         PHPDBG_G(exec_len) = PHPDBG_G(exec) ? strlen(PHPDBG_G(exec)) : 0;
1679 
1680                         free(exec);
1681                         exec = NULL;
1682                 }
1683 
1684                 php_output_activate();
1685                 php_output_deactivate();
1686 
1687                 if (SG(sapi_headers).mimetype) {
1688                         efree(SG(sapi_headers).mimetype);
1689                         SG(sapi_headers).mimetype = NULL;
1690                 }
1691 
1692                 php_output_activate();
1693 
1694                 {
1695                         int i;
1696 
1697                         SG(request_info).argc = argc - php_optind + 1;
1698                         SG(request_info).argv = emalloc(SG(request_info).argc * sizeof(char *));
1699                         for (i = SG(request_info).argc; --i;) {
1700                                 SG(request_info).argv[i] = estrdup(argv[php_optind - 1 + i]);
1701                         }
1702                         SG(request_info).argv[0] = PHPDBG_G(exec) ? estrdup(PHPDBG_G(exec)) : estrdup("");
1703                 }
1704 
1705                 if (php_request_startup() == FAILURE) {
1706                         PUTS("Could not startup");
1707                         return 1;
1708                 }
1709 
1710                 /* do not install sigint handlers for remote consoles */
1711                 /* sending SIGINT then provides a decent way of shutting down the server */
1712 #ifndef _WIN32
1713                 if (listen < 0) {
1714 #endif
1715 #if defined(ZEND_SIGNALS) && !defined(_WIN32)
1716                         zend_try { zend_signal(SIGINT, phpdbg_sigint_handler); } zend_end_try();
1717 #else
1718                         signal(SIGINT, phpdbg_sigint_handler);
1719 #endif
1720 #ifndef _WIN32
1721                 }
1722 
1723                 /* setup io here */
1724                 if (remote) {
1725                         PHPDBG_G(flags) |= PHPDBG_IS_REMOTE;
1726 
1727                         signal(SIGPIPE, SIG_IGN);
1728                 }
1729                 PHPDBG_G(io)[PHPDBG_STDIN].ptr = stdin;
1730                 PHPDBG_G(io)[PHPDBG_STDIN].fd = fileno(stdin);
1731                 PHPDBG_G(io)[PHPDBG_STDOUT].ptr = stdout;
1732                 PHPDBG_G(io)[PHPDBG_STDOUT].fd = fileno(stdout);
1733 #else
1734                 /* XXX this is a complete mess here with FILE/fd/SOCKET,
1735                         we should let only one to survive probably. Need
1736                         a clean separation whether it's a remote or local
1737                         prompt. And what is supposed to go as user interaction,
1738                         error log, etc. */
1739                 if (remote) {
1740                         PHPDBG_G(io)[PHPDBG_STDIN].ptr = stdin;
1741                         PHPDBG_G(io)[PHPDBG_STDIN].fd = socket;
1742                         PHPDBG_G(io)[PHPDBG_STDOUT].ptr = stdout;
1743                         PHPDBG_G(io)[PHPDBG_STDOUT].fd = socket;
1744                 } else {
1745                         PHPDBG_G(io)[PHPDBG_STDIN].ptr = stdin;
1746                         PHPDBG_G(io)[PHPDBG_STDIN].fd = fileno(stdin);
1747                         PHPDBG_G(io)[PHPDBG_STDOUT].ptr = stdout;
1748                         PHPDBG_G(io)[PHPDBG_STDOUT].fd = fileno(stdout);
1749                 }
1750 #endif
1751                 PHPDBG_G(io)[PHPDBG_STDERR].ptr = stderr;
1752                 PHPDBG_G(io)[PHPDBG_STDERR].fd = fileno(stderr);
1753 
1754 #ifndef _WIN32
1755                 PHPDBG_G(php_stdiop_write) = php_stream_stdio_ops.write;
1756                 php_stream_stdio_ops.write = phpdbg_stdiop_write;
1757 #endif
1758 
1759                 if (oplog_file) { /* open oplog */
1760                         PHPDBG_G(oplog) = fopen(oplog_file, "w+");
1761                         if (!PHPDBG_G(oplog)) {
1762                                 phpdbg_error("oplog", "path=\"%s\"", "Failed to open oplog %s", oplog_file);
1763                         }
1764                         free(oplog_file);
1765                         oplog_file = NULL;
1766                 }
1767 
1768                 /* set default colors */
1769                 phpdbg_set_color_ex(PHPDBG_COLOR_PROMPT,  PHPDBG_STRL("white-bold"));
1770                 phpdbg_set_color_ex(PHPDBG_COLOR_ERROR,   PHPDBG_STRL("red-bold"));
1771                 phpdbg_set_color_ex(PHPDBG_COLOR_NOTICE,  PHPDBG_STRL("green"));
1772 
1773                 /* set default prompt */
1774                 phpdbg_set_prompt(PHPDBG_DEFAULT_PROMPT);
1775 
1776                 /* Make stdin, stdout and stderr accessible from PHP scripts */
1777                 phpdbg_register_file_handles();
1778 
1779                 phpdbg_list_update();
1780 
1781                 if (show_banner && cleaning < 2) {
1782                         /* print blurb */
1783                         phpdbg_welcome(cleaning == 1);
1784                 }
1785 
1786                 cleaning = -1;
1787 
1788                 if (ext_stmt) {
1789                         CG(compiler_options) |= ZEND_COMPILE_EXTENDED_INFO;
1790                 }
1791 
1792                 /* initialize from file */
1793                 PHPDBG_G(flags) |= PHPDBG_IS_INITIALIZING;
1794                 zend_try {
1795                         phpdbg_init(init_file, init_file_len, init_file_default);
1796                         if (bp_tmp) {
1797                                 PHPDBG_G(flags) |= PHPDBG_DISCARD_OUTPUT;
1798                                 phpdbg_string_init(bp_tmp);
1799                                 free(bp_tmp);
1800                                 bp_tmp = NULL;
1801                                 PHPDBG_G(flags) &= ~PHPDBG_DISCARD_OUTPUT;
1802                         }
1803                 } zend_end_try();
1804                 PHPDBG_G(flags) &= ~PHPDBG_IS_INITIALIZING;
1805 
1806                 /* quit if init says so */
1807                 if (PHPDBG_G(flags) & PHPDBG_IS_QUITTING) {
1808                         goto phpdbg_out;
1809                 }
1810 
1811                 /* auto compile */
1812                 if (PHPDBG_G(exec)) {
1813                         if (settings || phpdbg_startup_run > 0) {
1814                                 PHPDBG_G(flags) |= PHPDBG_DISCARD_OUTPUT;
1815                         }
1816 
1817                         zend_try {
1818                                 phpdbg_compile();
1819                         } zend_end_try();
1820 
1821                         PHPDBG_G(flags) &= ~PHPDBG_DISCARD_OUTPUT;
1822                 }
1823 
1824                 if (settings == (void *) 0x1) {
1825                         if (PHPDBG_G(ops)) {
1826                                 phpdbg_print_opcodes(print_opline_func);
1827                         } else {
1828                                 quiet_write(PHPDBG_G(io)[PHPDBG_STDERR].fd, ZEND_STRL("No opcodes could be compiled | No file specified or compilation failed?\n"));
1829                         }
1830                         goto phpdbg_out;
1831                 }
1832 
1833                 PG(during_request_startup) = 0;
1834 
1835                 phpdbg_fully_started = 1;
1836 
1837 /* #ifndef for making compiler shutting up */
1838 #ifndef _WIN32
1839 phpdbg_interact:
1840 #endif
1841                 /* phpdbg main() */
1842                 do {
1843                         zend_try {
1844                                 if (phpdbg_startup_run) {
1845                                         quit_immediately = phpdbg_startup_run > 1;
1846                                         phpdbg_startup_run = 0;
1847                                         if (quit_immediately) {
1848                                                 PHPDBG_G(flags) = (PHPDBG_G(flags) & ~PHPDBG_HAS_PAGINATION) | PHPDBG_IS_INTERACTIVE | PHPDBG_PREVENT_INTERACTIVE;
1849                                         } else {
1850                                                 PHPDBG_G(flags) |= PHPDBG_IS_INTERACTIVE;
1851                                         }
1852                                         zend_try {
1853                                                 PHPDBG_COMMAND_HANDLER(run)(NULL);
1854                                         } zend_end_try();
1855                                         if (quit_immediately) {
1856                                                 /* if -r is on the command line more than once just quit */
1857                                                 EG(bailout) = __orig_bailout; /* reset zend_try */
1858                                                 exit_status = EG(exit_status);
1859                                                 break;
1860                                         }
1861                                 }
1862 
1863                                 CG(unclean_shutdown) = 0;
1864                                 phpdbg_interactive(1);
1865                         } zend_catch {
1866                                 if ((PHPDBG_G(flags) & PHPDBG_IS_CLEANING)) {
1867                                         char *bp_tmp_str;
1868                                         PHPDBG_G(flags) |= PHPDBG_DISCARD_OUTPUT;
1869                                         phpdbg_export_breakpoints_to_string(&bp_tmp_str);
1870                                         PHPDBG_G(flags) &= ~PHPDBG_DISCARD_OUTPUT;
1871                                         if (bp_tmp_str) {
1872                                                 bp_tmp = strdup(bp_tmp_str);
1873                                                 efree(bp_tmp_str);
1874                                         }
1875                                         cleaning = 1;
1876                                 } else {
1877                                         cleaning = 0;
1878                                 }
1879 
1880 #ifndef _WIN32
1881                                 if (!cleaning) {
1882                                         /* remote client disconnected */
1883                                         if ((PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED)) {
1884 
1885                                                 if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) {
1886                                                         /* renegociate connections */
1887                                                         phpdbg_remote_init(address, listen, server, &socket, &stream);
1888 
1889                                                         /* set streams */
1890                                                         if (stream) {
1891                                                                 PHPDBG_G(flags) &= ~PHPDBG_IS_QUITTING;
1892                                                         }
1893 
1894                                                         /* this must be forced */
1895                                                         CG(unclean_shutdown) = 0;
1896                                                 } else {
1897                                                         /* local consoles cannot disconnect, ignore EOF */
1898                                                         PHPDBG_G(flags) &= ~PHPDBG_IS_DISCONNECTED;
1899                                                 }
1900                                         }
1901                                 }
1902 #endif
1903                         } zend_end_try();
1904                 } while (!(PHPDBG_G(flags) & PHPDBG_IS_STOPPING));
1905 
1906 
1907 #ifndef _WIN32
1908 phpdbg_out:
1909                 if ((PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED)) {
1910                         PHPDBG_G(flags) &= ~PHPDBG_IS_DISCONNECTED;
1911                         goto phpdbg_interact;
1912                 }
1913 #endif
1914 
1915 #ifdef _WIN32
1916         } __except(phpdbg_exception_handler_win32(xp = GetExceptionInformation())) {
1917                 phpdbg_error("segfault", "", "Access violation (Segmentation fault) encountered\ntrying to abort cleanly...");
1918         }
1919 phpdbg_out:
1920 #endif
1921 
1922                 if (cleaning <= 0) {
1923                         PHPDBG_G(flags) &= ~PHPDBG_IS_CLEANING;
1924                         cleaning = -1;
1925                 }
1926 
1927                 {
1928                         int i;
1929                         /* free argv */
1930                         for (i = SG(request_info).argc; i--;) {
1931                                 efree(SG(request_info).argv[i]);
1932                         }
1933                         efree(SG(request_info).argv);
1934                 }
1935 
1936                 if (ini_entries) {
1937                         free(ini_entries);
1938                 }
1939 
1940                 if (ini_override) {
1941                         free(ini_override);
1942                 }
1943 
1944                 /* In case we aborted during script execution, we may not reset CG(unclean_shutdown) */
1945                 if (!(PHPDBG_G(flags) & PHPDBG_IS_RUNNING)) {
1946                         is_exit = !PHPDBG_G(in_execution);
1947                         CG(unclean_shutdown) = is_exit || PHPDBG_G(unclean_eval);
1948                 }
1949 
1950                 if ((PHPDBG_G(flags) & (PHPDBG_IS_CLEANING | PHPDBG_IS_RUNNING)) == PHPDBG_IS_CLEANING) {
1951                         php_free_shutdown_functions();
1952                         zend_objects_store_mark_destructed(&EG(objects_store));
1953                 }
1954 
1955                 /* backup globals when cleaning */
1956                 if ((cleaning > 0 || remote) && !quit_immediately) {
1957                         settings = calloc(1, sizeof(zend_phpdbg_globals));
1958 
1959                         php_phpdbg_globals_ctor(settings);
1960 
1961                         if (PHPDBG_G(exec)) {
1962                                 settings->exec = zend_strndup(PHPDBG_G(exec), PHPDBG_G(exec_len));
1963                                 settings->exec_len = PHPDBG_G(exec_len);
1964                         }
1965                         settings->oplog = PHPDBG_G(oplog);
1966                         settings->prompt[0] = PHPDBG_G(prompt)[0];
1967                         settings->prompt[1] = PHPDBG_G(prompt)[1];
1968                         memcpy(settings->colors, PHPDBG_G(colors), sizeof(settings->colors));
1969                         settings->eol = PHPDBG_G(eol);
1970                         settings->input_buflen = PHPDBG_G(input_buflen);
1971                         memcpy(settings->input_buffer, PHPDBG_G(input_buffer), settings->input_buflen);
1972                         settings->flags = PHPDBG_G(flags) & PHPDBG_PRESERVE_FLAGS_MASK;
1973                 } else {
1974                         if (PHPDBG_G(prompt)[0]) {
1975                                 free(PHPDBG_G(prompt)[0]);
1976                         }
1977                         if (PHPDBG_G(prompt)[1]) {
1978                                 free(PHPDBG_G(prompt)[1]);
1979                         }
1980                 }
1981 
1982                 /* hack to restore mm_heap->use_custom_heap in order to receive memory leak info */
1983                 if (use_mm_wrappers) {
1984                         /* ASSUMING that mm_heap->use_custom_heap is the first element of the struct ... */
1985                         *(int *) mm_heap = 0;
1986                 }
1987                 zend_try {
1988                         php_request_shutdown(NULL);
1989                 } zend_end_try();
1990 
1991                 if (exit_status == 0) {
1992                         exit_status = EG(exit_status);
1993                 }
1994 
1995                 if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) {
1996                         if (PHPDBG_G(in_execution) || is_exit) {
1997                                 if (!quit_immediately && !phpdbg_startup_run) {
1998                                         phpdbg_notice("stop", "type=\"normal\"", "Script ended normally");
1999                                         cleaning++;
2000                                 }
2001                         }
2002                 }
2003                 php_output_deactivate();
2004 
2005                 zend_try {
2006                         php_module_shutdown();
2007                 } zend_end_try();
2008 
2009 #ifndef _WIN32
2010                 /* reset it... else we risk a stack overflow upon next run (when clean'ing) */
2011                 php_stream_stdio_ops.write = PHPDBG_G(php_stdiop_write);
2012 #endif
2013 
2014                 sapi_shutdown();
2015         }
2016 
2017         if ((cleaning > 0 || remote) && !quit_immediately) {
2018                 /* reset internal php_getopt state */
2019                 php_getopt(-1, argv, OPTIONS, NULL, &php_optind, 0, 0);
2020 
2021                 goto phpdbg_main;
2022         }
2023 
2024 #ifdef ZTS
2025         /* bugggy */
2026         /* tsrm_shutdown(); */
2027 #endif
2028 
2029 #ifndef _WIN32
2030         if (address) {
2031                 free(address);
2032         }
2033 #endif
2034 
2035         if (PHPDBG_G(sapi_name_ptr)) {
2036                 free(PHPDBG_G(sapi_name_ptr));
2037         }
2038 
2039         /* usually 0; just for -rr */
2040         return exit_status;
2041 } /* }}} */

/* [<][>][^][v][top][bottom][index][help] */