root/sapi/phpdbg/phpdbg.c

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

DEFINITIONS

This source file includes following definitions.
  1. php_phpdbg_globals_ctor
  2. PHP_MINIT_FUNCTION
  3. php_phpdbg_destroy_bp_file
  4. php_phpdbg_destroy_bp_symbol
  5. php_phpdbg_destroy_bp_opcode
  6. php_phpdbg_destroy_bp_methods
  7. php_phpdbg_destroy_bp_condition
  8. php_phpdbg_destroy_registered
  9. PHP_RINIT_FUNCTION
  10. PHP_RSHUTDOWN_FUNCTION
  11. PHP_FUNCTION
  12. PHP_FUNCTION
  13. PHP_FUNCTION
  14. PHP_FUNCTION
  15. PHP_FUNCTION
  16. PHP_FUNCTION
  17. PHP_FUNCTION
  18. PHP_FUNCTION
  19. php_sapi_phpdbg_module_startup
  20. php_sapi_phpdbg_read_cookies
  21. php_sapi_phpdbg_header_handler
  22. php_sapi_phpdbg_send_headers
  23. php_sapi_phpdbg_send_header
  24. php_sapi_phpdbg_log_message
  25. php_sapi_phpdbg_deactivate
  26. php_sapi_phpdbg_register_vars
  27. php_sapi_phpdbg_ub_write
  28. php_sapi_phpdbg_flush
  29. php_sapi_phpdbg_flush
  30. phpdbg_register_file_handles
  31. phpdbg_ini_defaults
  32. phpdbg_welcome
  33. phpdbg_sigint_handler
  34. phpdbg_open_socket
  35. phpdbg_close_sockets
  36. phpdbg_open_sockets
  37. phpdbg_signal_handler
  38. phpdbg_mm_get_heap
  39. phpdbg_malloc_wrapper
  40. phpdbg_free_wrapper
  41. phpdbg_realloc_wrapper
  42. main

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 5                                                        |
   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 #include "phpdbg.h"
  25 #include "phpdbg_prompt.h"
  26 #include "phpdbg_bp.h"
  27 #include "phpdbg_break.h"
  28 #include "phpdbg_list.h"
  29 #include "phpdbg_utils.h"
  30 #include "phpdbg_set.h"
  31 #include "zend_alloc.h"
  32 
  33 /* {{{ remote console headers */
  34 #ifndef _WIN32
  35 #       include <sys/socket.h>
  36 #       include <sys/select.h>
  37 #       include <sys/time.h>
  38 #       include <sys/types.h>
  39 #       include <netinet/in.h>
  40 #       include <unistd.h>
  41 #       include <arpa/inet.h>
  42 #endif /* }}} */
  43 
  44 ZEND_DECLARE_MODULE_GLOBALS(phpdbg);
  45 
  46 static zend_bool phpdbg_booted = 0;
  47 
  48 #if PHP_VERSION_ID >= 50500
  49 void (*zend_execute_old)(zend_execute_data *execute_data TSRMLS_DC);
  50 #else
  51 void (*zend_execute_old)(zend_op_array *op_array TSRMLS_DC);
  52 #endif
  53 
  54 static inline void php_phpdbg_globals_ctor(zend_phpdbg_globals *pg) /* {{{ */
  55 {
  56         pg->prompt[0] = NULL;
  57         pg->prompt[1] = NULL;
  58 
  59         pg->colors[0] = NULL;
  60         pg->colors[1] = NULL;
  61         pg->colors[2] = NULL;
  62 
  63         pg->exec = NULL;
  64         pg->exec_len = 0;
  65         pg->buffer = NULL;
  66         pg->ops = NULL;
  67         pg->vmret = 0;
  68         pg->bp_count = 0;
  69         pg->flags = PHPDBG_DEFAULT_FLAGS;
  70         pg->oplog = NULL;
  71         pg->io[PHPDBG_STDIN] = NULL;
  72         pg->io[PHPDBG_STDOUT] = NULL;
  73         pg->io[PHPDBG_STDERR] = NULL;
  74         pg->frame.num = 0;
  75 } /* }}} */
  76 
  77 static PHP_MINIT_FUNCTION(phpdbg) /* {{{ */
  78 {
  79         ZEND_INIT_MODULE_GLOBALS(phpdbg, php_phpdbg_globals_ctor, NULL);
  80 #if PHP_VERSION_ID >= 50500
  81         zend_execute_old = zend_execute_ex;
  82         zend_execute_ex = phpdbg_execute_ex;
  83 #else
  84         zend_execute_old = zend_execute;
  85         zend_execute = phpdbg_execute_ex;
  86 #endif
  87 
  88         REGISTER_STRINGL_CONSTANT("PHPDBG_VERSION", PHPDBG_VERSION, sizeof(PHPDBG_VERSION)-1, CONST_CS|CONST_PERSISTENT);
  89         
  90         REGISTER_LONG_CONSTANT("PHPDBG_FILE",   FILE_PARAM, CONST_CS|CONST_PERSISTENT);
  91         REGISTER_LONG_CONSTANT("PHPDBG_METHOD", METHOD_PARAM, CONST_CS|CONST_PERSISTENT);
  92         REGISTER_LONG_CONSTANT("PHPDBG_LINENO", NUMERIC_PARAM, CONST_CS|CONST_PERSISTENT);
  93         REGISTER_LONG_CONSTANT("PHPDBG_FUNC",   STR_PARAM, CONST_CS|CONST_PERSISTENT);
  94 
  95         REGISTER_LONG_CONSTANT("PHPDBG_COLOR_PROMPT", PHPDBG_COLOR_PROMPT, CONST_CS|CONST_PERSISTENT);
  96         REGISTER_LONG_CONSTANT("PHPDBG_COLOR_NOTICE", PHPDBG_COLOR_NOTICE, CONST_CS|CONST_PERSISTENT);
  97         REGISTER_LONG_CONSTANT("PHPDBG_COLOR_ERROR",  PHPDBG_COLOR_ERROR, CONST_CS|CONST_PERSISTENT);
  98 
  99         return SUCCESS;
 100 } /* }}} */
 101 
 102 static void php_phpdbg_destroy_bp_file(void *brake) /* {{{ */
 103 {
 104         zend_hash_destroy((HashTable*)brake);
 105 } /* }}} */
 106 
 107 static void php_phpdbg_destroy_bp_symbol(void *brake) /* {{{ */
 108 {
 109         efree((char*)((phpdbg_breaksymbol_t*)brake)->symbol);
 110 } /* }}} */
 111 
 112 static void php_phpdbg_destroy_bp_opcode(void *brake) /* {{{ */
 113 {
 114         efree((char*)((phpdbg_breakop_t*)brake)->name);
 115 } /* }}} */
 116 
 117 
 118 static void php_phpdbg_destroy_bp_methods(void *brake) /* {{{ */
 119 {
 120         zend_hash_destroy((HashTable*)brake);
 121 } /* }}} */
 122 
 123 static void php_phpdbg_destroy_bp_condition(void *data) /* {{{ */
 124 {
 125         phpdbg_breakcond_t *brake = (phpdbg_breakcond_t*) data;
 126 
 127         if (brake) {
 128                 if (brake->ops) {
 129                         TSRMLS_FETCH();
 130 
 131                         destroy_op_array(
 132                                         brake->ops TSRMLS_CC);
 133                         efree(brake->ops);
 134                 }
 135                 efree((char*)brake->code);
 136         }
 137 } /* }}} */
 138 
 139 static void php_phpdbg_destroy_registered(void *data) /* {{{ */
 140 {
 141         zend_function *function = (zend_function*) data;
 142         TSRMLS_FETCH();
 143 
 144         destroy_zend_function(
 145                 function TSRMLS_CC);
 146 } /* }}} */
 147 
 148 
 149 static PHP_RINIT_FUNCTION(phpdbg) /* {{{ */
 150 {
 151         zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE],   8, NULL, php_phpdbg_destroy_bp_file, 0);
 152         zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], 8, NULL, php_phpdbg_destroy_bp_symbol, 0);
 153         zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
 154         zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
 155         zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
 156         zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], 8, NULL, NULL, 0);
 157         zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], 8, NULL, php_phpdbg_destroy_bp_opcode, 0);
 158         zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
 159         zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], 8, NULL, php_phpdbg_destroy_bp_condition, 0);
 160         zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], 8, NULL, NULL, 0);
 161 
 162         zend_hash_init(&PHPDBG_G(seek), 8, NULL, NULL, 0);
 163         zend_hash_init(&PHPDBG_G(registered), 8, NULL, php_phpdbg_destroy_registered, 0);
 164 
 165         return SUCCESS;
 166 } /* }}} */
 167 
 168 static PHP_RSHUTDOWN_FUNCTION(phpdbg) /* {{{ */
 169 {
 170         zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE]);
 171         zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM]);
 172         zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE]);
 173         zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE]);
 174         zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE]);
 175         zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]);
 176         zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE]);
 177         zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD]);
 178         zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_COND]);
 179         zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP]);
 180         zend_hash_destroy(&PHPDBG_G(seek));
 181         zend_hash_destroy(&PHPDBG_G(registered));
 182         zend_hash_destroy(&PHPDBG_G(watchpoints));
 183         zend_llist_destroy(&PHPDBG_G(watchlist_mem));
 184 
 185         if (PHPDBG_G(buffer)) {
 186                 efree(PHPDBG_G(buffer));
 187                 PHPDBG_G(buffer) = NULL;
 188         }
 189         
 190         if (PHPDBG_G(exec)) {
 191                 efree(PHPDBG_G(exec));
 192                 PHPDBG_G(exec) = NULL;
 193         }
 194 
 195         if (PHPDBG_G(prompt)[0]) {
 196                 free(PHPDBG_G(prompt)[0]);
 197         }
 198         if (PHPDBG_G(prompt)[1]) {
 199                 free(PHPDBG_G(prompt)[1]);
 200         }
 201 
 202         PHPDBG_G(prompt)[0] = NULL;
 203         PHPDBG_G(prompt)[1] = NULL;
 204 
 205         if (PHPDBG_G(oplog)) {
 206                 fclose(
 207                                 PHPDBG_G(oplog));
 208                 PHPDBG_G(oplog) = NULL;
 209         }
 210 
 211         if (PHPDBG_G(ops)) {
 212                 destroy_op_array(PHPDBG_G(ops) TSRMLS_CC);
 213                 efree(PHPDBG_G(ops));
 214                 PHPDBG_G(ops) = NULL;
 215         }
 216 
 217         return SUCCESS;
 218 } /* }}} */
 219 
 220 /* {{{ proto mixed phpdbg_exec(string context)
 221         Attempt to set the execution context for phpdbg
 222         If the execution context was set previously it is returned
 223         If the execution context was not set previously boolean true is returned
 224         If the request to set the context fails, boolean false is returned, and an E_WARNING raised */
 225 static PHP_FUNCTION(phpdbg_exec)
 226 {
 227         char *exec = NULL;
 228         int exec_len = 0;
 229         
 230         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &exec, &exec_len) == FAILURE) {
 231                 return;
 232         }
 233 
 234         {
 235                 struct stat sb;
 236                 zend_bool result = 1;
 237 
 238                 if (VCWD_STAT(exec, &sb) != FAILURE) {
 239                         if (sb.st_mode & (S_IFREG|S_IFLNK)) {
 240                                 if (PHPDBG_G(exec)) {
 241                                         ZVAL_STRINGL(return_value, PHPDBG_G(exec), PHPDBG_G(exec_len), 1);
 242                                         efree(PHPDBG_G(exec));
 243                                         result = 0;
 244                                 }
 245 
 246                                 PHPDBG_G(exec) = estrndup(exec, exec_len);
 247                                 PHPDBG_G(exec_len) = exec_len;
 248 
 249                                 if (result)
 250                                         ZVAL_BOOL(return_value, 1);
 251                         } else {
 252                                 zend_error(
 253                                         E_WARNING, "Failed to set execution context (%s), not a regular file or symlink", exec);
 254                                 ZVAL_BOOL(return_value, 0);
 255                         }
 256                 } else {
 257                         zend_error(
 258                                 E_WARNING, "Failed to set execution context (%s) the file does not exist", exec);
 259 
 260                         ZVAL_BOOL(return_value, 0);
 261                 }
 262         }
 263 } /* }}} */
 264 
 265 /* {{{ proto void phpdbg_break_next()
 266     instructs phpdbg to insert a breakpoint at the next opcode */
 267 static PHP_FUNCTION(phpdbg_break_next)
 268 {
 269         if (zend_parse_parameters_none() != SUCCESS) {
 270                 return;
 271         } else if (EG(current_execute_data) && EG(active_op_array)) {
 272                 zend_ulong opline_num = (EG(current_execute_data)->opline -
 273                                 EG(active_op_array)->opcodes);
 274 
 275                 phpdbg_set_breakpoint_opline_ex(
 276                                 &EG(active_op_array)->opcodes[opline_num+1] TSRMLS_CC);
 277         }
 278 } /* }}} */
 279 
 280 /* {{{ proto void phpdbg_break_file(string file, integer line) */
 281 static PHP_FUNCTION(phpdbg_break_file)
 282 {
 283     char    *file = NULL;
 284     int      flen = 0;
 285     long     line;
 286     
 287     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &file, &flen, &line) == FAILURE) {
 288         return;
 289     }
 290 
 291     phpdbg_set_breakpoint_file(file, line TSRMLS_CC);
 292 } /* }}} */
 293 
 294 /* {{{ proto void phpdbg_break_method(string class, string method) */
 295 static PHP_FUNCTION(phpdbg_break_method)
 296 {
 297     char *class = NULL,
 298          *method = NULL;
 299     int clen = 0, 
 300         mlen = 0;
 301 
 302     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &class, &clen, &method, &mlen) == FAILURE) {
 303     return;
 304     }
 305 
 306     phpdbg_set_breakpoint_method(class, method TSRMLS_CC);
 307 } /* }}} */
 308 
 309 /* {{{ proto void phpdbg_break_function(string function) */
 310 static PHP_FUNCTION(phpdbg_break_function)
 311 {
 312     char *function = NULL;
 313     int   function_len;
 314 
 315     if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &function, &function_len) == FAILURE) {
 316            return;
 317     }
 318 
 319     phpdbg_set_breakpoint_symbol(function, function_len TSRMLS_CC);
 320 } /* }}} */
 321 
 322 /* {{{ proto void phpdbg_clear(void)
 323    instructs phpdbg to clear breakpoints */
 324 static PHP_FUNCTION(phpdbg_clear)
 325 {
 326         zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE]);
 327         zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM]);
 328         zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE]);
 329         zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE]);
 330         zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE]);
 331         zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]);
 332         zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD]);
 333         zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_COND]);
 334 } /* }}} */
 335 
 336 /* {{{ proto void phpdbg_color(integer element, string color) */
 337 static PHP_FUNCTION(phpdbg_color)
 338 {
 339         long element = 0L;
 340         char *color = NULL;
 341         int color_len = 0;
 342 
 343         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &element, &color, &color_len) == FAILURE) {
 344                 return;
 345         }
 346 
 347         switch (element) {
 348                 case PHPDBG_COLOR_NOTICE:
 349                 case PHPDBG_COLOR_ERROR:
 350                 case PHPDBG_COLOR_PROMPT:
 351                         phpdbg_set_color_ex(element, color, color_len TSRMLS_CC);
 352                 break;
 353 
 354                 default: zend_error(E_ERROR, "phpdbg detected an incorrect color constant");
 355         }
 356 } /* }}} */
 357 
 358 /* {{{ proto void phpdbg_prompt(string prompt) */
 359 static PHP_FUNCTION(phpdbg_prompt)
 360 {
 361         char *prompt = NULL;
 362         int prompt_len = 0;
 363 
 364         if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &prompt, &prompt_len) == FAILURE) {
 365                 return;
 366         }
 367 
 368         phpdbg_set_prompt(prompt TSRMLS_CC);
 369 } /* }}} */
 370 
 371 ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_next_arginfo, 0, 0, 0)
 372 ZEND_END_ARG_INFO()
 373 
 374 ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_file_arginfo, 0, 0, 2)
 375     ZEND_ARG_INFO(0, file)
 376     ZEND_ARG_INFO(0, line)
 377 ZEND_END_ARG_INFO()
 378 
 379 ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_method_arginfo, 0, 0, 2)
 380     ZEND_ARG_INFO(0, class)
 381     ZEND_ARG_INFO(0, method)
 382 ZEND_END_ARG_INFO()
 383 
 384 ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_function_arginfo, 0, 0, 1)
 385     ZEND_ARG_INFO(0, function)
 386 ZEND_END_ARG_INFO()
 387 
 388 ZEND_BEGIN_ARG_INFO_EX(phpdbg_color_arginfo, 0, 0, 0)
 389         ZEND_ARG_INFO(0, element)
 390         ZEND_ARG_INFO(0, color)
 391 ZEND_END_ARG_INFO()
 392 
 393 ZEND_BEGIN_ARG_INFO_EX(phpdbg_prompt_arginfo, 0, 0, 0)
 394         ZEND_ARG_INFO(0, string)
 395 ZEND_END_ARG_INFO()
 396 
 397 ZEND_BEGIN_ARG_INFO_EX(phpdbg_exec_arginfo, 0, 0, 0)
 398         ZEND_ARG_INFO(0, context)
 399 ZEND_END_ARG_INFO()
 400 
 401 ZEND_BEGIN_ARG_INFO_EX(phpdbg_clear_arginfo, 0, 0, 0)
 402 ZEND_END_ARG_INFO()
 403 
 404 zend_function_entry phpdbg_user_functions[] = {
 405         PHP_FE(phpdbg_clear, phpdbg_clear_arginfo)
 406         PHP_FE(phpdbg_break_next, phpdbg_break_next_arginfo)
 407         PHP_FE(phpdbg_break_file, phpdbg_break_file_arginfo)
 408         PHP_FE(phpdbg_break_method, phpdbg_break_method_arginfo)
 409         PHP_FE(phpdbg_break_function, phpdbg_break_function_arginfo)
 410         PHP_FE(phpdbg_exec,  phpdbg_exec_arginfo)
 411         PHP_FE(phpdbg_color, phpdbg_color_arginfo)
 412         PHP_FE(phpdbg_prompt, phpdbg_prompt_arginfo)
 413 #ifdef  PHP_FE_END
 414         PHP_FE_END
 415 #else
 416         {NULL,NULL,NULL}
 417 #endif
 418 };
 419 
 420 static zend_module_entry sapi_phpdbg_module_entry = {
 421         STANDARD_MODULE_HEADER,
 422         PHPDBG_NAME,
 423         phpdbg_user_functions,
 424         PHP_MINIT(phpdbg),
 425         NULL,
 426         PHP_RINIT(phpdbg),
 427         PHP_RSHUTDOWN(phpdbg),
 428         NULL,
 429         PHPDBG_VERSION,
 430         STANDARD_MODULE_PROPERTIES
 431 };
 432 
 433 static inline int php_sapi_phpdbg_module_startup(sapi_module_struct *module) /* {{{ */
 434 {
 435         if (php_module_startup(module, &sapi_phpdbg_module_entry, 1) == FAILURE) {
 436                 return FAILURE;
 437         }
 438 
 439         phpdbg_booted=1;
 440 
 441         return SUCCESS;
 442 } /* }}} */
 443 
 444 static char* php_sapi_phpdbg_read_cookies(TSRMLS_D) /* {{{ */
 445 {
 446         return NULL;
 447 } /* }}} */
 448 
 449 static int php_sapi_phpdbg_header_handler(sapi_header_struct *h, sapi_header_op_enum op, sapi_headers_struct *s TSRMLS_DC) /* {{{ */
 450 {
 451         return 0;
 452 }
 453 /* }}} */
 454 
 455 static int php_sapi_phpdbg_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC) /* {{{ */
 456 {
 457         /* We do nothing here, this function is needed to prevent that the fallback
 458          * header handling is called. */
 459         return SAPI_HEADER_SENT_SUCCESSFULLY;
 460 }
 461 /* }}} */
 462 
 463 static void php_sapi_phpdbg_send_header(sapi_header_struct *sapi_header, void *server_context TSRMLS_DC) /* {{{ */
 464 {
 465 }
 466 /* }}} */
 467 
 468 static void php_sapi_phpdbg_log_message(char *message TSRMLS_DC) /* {{{ */
 469 {
 470         /*
 471         * We must not request TSRM before being boot
 472         */
 473         if (phpdbg_booted) {
 474                 phpdbg_error("%s", message);
 475 
 476                 switch (PG(last_error_type)) {
 477                         case E_ERROR:
 478                         case E_CORE_ERROR:
 479                         case E_COMPILE_ERROR:
 480                         case E_USER_ERROR:
 481                         case E_PARSE:
 482                         case E_RECOVERABLE_ERROR:
 483                                 if (!(PHPDBG_G(flags) & PHPDBG_IN_EVAL)) {
 484                                         phpdbg_list_file(
 485                                                 zend_get_executed_filename(TSRMLS_C),
 486                                                 3,
 487                                                 zend_get_executed_lineno(TSRMLS_C)-1,
 488                                                 zend_get_executed_lineno(TSRMLS_C)
 489                                                 TSRMLS_CC
 490                                         );
 491                                 }
 492 
 493                                 do {
 494                                         switch (phpdbg_interactive(TSRMLS_C)) {
 495                                                 case PHPDBG_LEAVE:
 496                                                 case PHPDBG_FINISH:
 497                                                 case PHPDBG_UNTIL:
 498                                                 case PHPDBG_NEXT:
 499                                                         return;
 500                                         }
 501                                 } while (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING));
 502 
 503                 }
 504         } else fprintf(stdout, "%s\n", message);
 505 }
 506 /* }}} */
 507 
 508 static int php_sapi_phpdbg_deactivate(TSRMLS_D) /* {{{ */
 509 {
 510         fflush(stdout);
 511         if(SG(request_info).argv0) {
 512                 free(SG(request_info).argv0);
 513                 SG(request_info).argv0 = NULL;
 514         }
 515         return SUCCESS;
 516 }
 517 /* }}} */
 518 
 519 static void php_sapi_phpdbg_register_vars(zval *track_vars_array TSRMLS_DC) /* {{{ */
 520 {
 521         unsigned int len;
 522         char   *docroot = "";
 523 
 524         /* In phpdbg mode, we consider the environment to be a part of the server variables
 525         */
 526         php_import_environment_variables(track_vars_array TSRMLS_CC);
 527 
 528         if (PHPDBG_G(exec)) {
 529                 len = PHPDBG_G(exec_len);
 530                 if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF",
 531                                         &PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) {
 532                         php_register_variable("PHP_SELF", PHPDBG_G(exec),
 533                                         track_vars_array TSRMLS_CC);
 534                 }
 535                 if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_NAME",
 536                                         &PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) {
 537                         php_register_variable("SCRIPT_NAME", PHPDBG_G(exec),
 538                                         track_vars_array TSRMLS_CC);
 539                 }
 540 
 541                 if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_FILENAME",
 542                                         &PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) {
 543                         php_register_variable("SCRIPT_FILENAME", PHPDBG_G(exec),
 544                                         track_vars_array TSRMLS_CC);
 545                 }
 546                 if (sapi_module.input_filter(PARSE_SERVER, "PATH_TRANSLATED",
 547                                         &PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) {
 548                         php_register_variable("PATH_TRANSLATED", PHPDBG_G(exec),
 549                                         track_vars_array TSRMLS_CC);
 550                 }
 551         }
 552 
 553         /* any old docroot will doo */
 554         len = 0U;
 555         if (sapi_module.input_filter(PARSE_SERVER, "DOCUMENT_ROOT",
 556                                 &docroot, len, &len TSRMLS_CC)) {
 557                 php_register_variable("DOCUMENT_ROOT", docroot, track_vars_array TSRMLS_CC);
 558         }
 559 }
 560 /* }}} */
 561 
 562 static inline int php_sapi_phpdbg_ub_write(const char *message, unsigned int length TSRMLS_DC) /* {{{ */
 563 {
 564         return phpdbg_write("%s", message);
 565 } /* }}} */
 566 
 567 #if PHP_VERSION_ID >= 50700
 568 static inline void php_sapi_phpdbg_flush(void *context TSRMLS_DC)  /* {{{ */
 569 {
 570 #else
 571 static inline void php_sapi_phpdbg_flush(void *context)  /* {{{ */
 572 {
 573         TSRMLS_FETCH();
 574 #endif
 575 
 576         fflush(PHPDBG_G(io)[PHPDBG_STDOUT]);
 577 } /* }}} */
 578 
 579 /* copied from sapi/cli/php_cli.c cli_register_file_handles */
 580 static void phpdbg_register_file_handles(TSRMLS_D) /* {{{ */
 581 {
 582         zval *zin, *zout, *zerr;
 583         php_stream *s_in, *s_out, *s_err;
 584         php_stream_context *sc_in=NULL, *sc_out=NULL, *sc_err=NULL;
 585         zend_constant ic, oc, ec;
 586 
 587         MAKE_STD_ZVAL(zin);
 588         MAKE_STD_ZVAL(zout);
 589         MAKE_STD_ZVAL(zerr);
 590 
 591         s_in  = php_stream_open_wrapper_ex("php://stdin",  "rb", 0, NULL, sc_in);
 592         s_out = php_stream_open_wrapper_ex("php://stdout", "wb", 0, NULL, sc_out);
 593         s_err = php_stream_open_wrapper_ex("php://stderr", "wb", 0, NULL, sc_err);
 594 
 595         if (s_in==NULL || s_out==NULL || s_err==NULL) {
 596                 FREE_ZVAL(zin);
 597                 FREE_ZVAL(zout);
 598                 FREE_ZVAL(zerr);
 599                 if (s_in) php_stream_close(s_in);
 600                 if (s_out) php_stream_close(s_out);
 601                 if (s_err) php_stream_close(s_err);
 602                 return;
 603         }
 604 
 605 #if PHP_DEBUG
 606         /* do not close stdout and stderr */
 607         s_out->flags |= PHP_STREAM_FLAG_NO_CLOSE;
 608         s_err->flags |= PHP_STREAM_FLAG_NO_CLOSE;
 609 #endif
 610 
 611         php_stream_to_zval(s_in,  zin);
 612         php_stream_to_zval(s_out, zout);
 613         php_stream_to_zval(s_err, zerr);
 614 
 615         ic.value = *zin;
 616         ic.flags = CONST_CS;
 617         ic.name = zend_strndup(ZEND_STRL("STDIN"));
 618         ic.name_len = sizeof("STDIN");
 619         ic.module_number = 0;
 620         zend_register_constant(&ic TSRMLS_CC);
 621 
 622         oc.value = *zout;
 623         oc.flags = CONST_CS;
 624         oc.name = zend_strndup(ZEND_STRL("STDOUT"));
 625         oc.name_len = sizeof("STDOUT");
 626         oc.module_number = 0;
 627         zend_register_constant(&oc TSRMLS_CC);
 628 
 629         ec.value = *zerr;
 630         ec.flags = CONST_CS;
 631         ec.name = zend_strndup(ZEND_STRL("STDERR"));
 632         ec.name_len = sizeof("STDERR");
 633         ec.module_number = 0;
 634         zend_register_constant(&ec TSRMLS_CC);
 635 
 636         FREE_ZVAL(zin);
 637         FREE_ZVAL(zout);
 638         FREE_ZVAL(zerr);
 639 }
 640 /* }}} */
 641 
 642 /* {{{ sapi_module_struct phpdbg_sapi_module
 643 */
 644 static sapi_module_struct phpdbg_sapi_module = {
 645         "phpdbg",                       /* name */
 646         "phpdbg",                       /* pretty name */
 647 
 648         php_sapi_phpdbg_module_startup, /* startup */
 649         php_module_shutdown_wrapper,    /* shutdown */
 650 
 651         NULL,                           /* activate */
 652         php_sapi_phpdbg_deactivate,     /* deactivate */
 653 
 654         php_sapi_phpdbg_ub_write,       /* unbuffered write */
 655         php_sapi_phpdbg_flush,          /* flush */
 656         NULL,                           /* get uid */
 657         NULL,                           /* getenv */
 658 
 659         php_error,                      /* error handler */
 660 
 661         php_sapi_phpdbg_header_handler, /* header handler */
 662         php_sapi_phpdbg_send_headers,   /* send headers handler */
 663         php_sapi_phpdbg_send_header,    /* send header handler */
 664 
 665         NULL,                           /* read POST data */
 666         php_sapi_phpdbg_read_cookies,   /* read Cookies */
 667 
 668         php_sapi_phpdbg_register_vars,  /* register server variables */
 669         php_sapi_phpdbg_log_message,    /* Log message */
 670         NULL,                           /* Get request time */
 671         NULL,                           /* Child terminate */
 672         STANDARD_SAPI_MODULE_PROPERTIES
 673 };
 674 /* }}} */
 675 
 676 const opt_struct OPTIONS[] = { /* {{{ */
 677         {'c', 1, "ini path override"},
 678         {'d', 1, "define ini entry on command line"},
 679         {'n', 0, "no php.ini"},
 680         {'z', 1, "load zend_extension"},
 681         /* phpdbg options */
 682         {'q', 0, "no banner"},
 683         {'v', 0, "disable quietness"},
 684         {'s', 0, "enable stepping"},
 685         {'b', 0, "boring colours"},
 686         {'i', 1, "specify init"},
 687         {'I', 0, "ignore init"},
 688         {'O', 1, "opline log"},
 689         {'r', 0, "run"},
 690         {'E', 0, "step-through-eval"},
 691         {'S', 1, "sapi-name"},
 692 #ifndef _WIN32
 693         {'l', 1, "listen"},
 694         {'a', 1, "address-or-any"},
 695 #endif
 696         {'V', 0, "version"},
 697         {'-', 0, NULL}
 698 }; /* }}} */
 699 
 700 const char phpdbg_ini_hardcoded[] =
 701 "html_errors=Off\n"
 702 "register_argc_argv=On\n"
 703 "implicit_flush=On\n"
 704 "display_errors=Off\n"
 705 "log_errors=On\n"
 706 "max_execution_time=0\n"
 707 "max_input_time=-1\n"
 708 "error_log=\n"
 709 "output_buffering=off\0";
 710 
 711 /* overwriteable ini defaults must be set in phpdbg_ini_defaults() */
 712 #define INI_DEFAULT(name, value) \
 713         Z_SET_REFCOUNT(tmp, 0); \
 714         Z_UNSET_ISREF(tmp); \
 715         ZVAL_STRINGL(&tmp, zend_strndup(value, sizeof(value)-1), sizeof(value)-1, 0); \
 716         zend_hash_update(configuration_hash, name, sizeof(name), &tmp, sizeof(zval), NULL);
 717 
 718 void phpdbg_ini_defaults(HashTable *configuration_hash) /* {{{ */
 719 {
 720         zval tmp;
 721         INI_DEFAULT("report_zend_debug", "0");
 722 } /* }}} */
 723 
 724 static void phpdbg_welcome(zend_bool cleaning TSRMLS_DC) /* {{{ */
 725 {
 726         /* print blurb */
 727         if (!cleaning) {
 728                 phpdbg_notice("Welcome to phpdbg, the interactive PHP debugger, v%s",
 729                                 PHPDBG_VERSION);
 730                 phpdbg_writeln("To get help using phpdbg type \"help\" and press enter");
 731                 phpdbg_notice("Please report bugs to <%s>", PHPDBG_ISSUES);
 732         } else {
 733                 phpdbg_notice("Clean Execution Environment");
 734 
 735                 phpdbg_writeln("Classes\t\t\t%d", zend_hash_num_elements(EG(class_table)));
 736                 phpdbg_writeln("Functions\t\t%d", zend_hash_num_elements(EG(function_table)));
 737                 phpdbg_writeln("Constants\t\t%d", zend_hash_num_elements(EG(zend_constants)));
 738                 phpdbg_writeln("Includes\t\t%d",  zend_hash_num_elements(&EG(included_files)));
 739         }
 740 } /* }}} */
 741 
 742 static inline void phpdbg_sigint_handler(int signo) /* {{{ */
 743 {
 744         TSRMLS_FETCH();
 745 
 746         if (EG(in_execution)) {
 747                 /* set signalled only when not interactive */
 748                 if (!(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) {
 749                         PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED;
 750                 }
 751         } else {
 752                 /* we quit remote consoles on recv SIGINT */
 753                 if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) {
 754                         PHPDBG_G(flags) |= PHPDBG_IS_QUITTING;
 755                         zend_bailout();
 756                 }
 757         }
 758 } /* }}} */
 759 
 760 #ifndef _WIN32
 761 int phpdbg_open_socket(const char *interface, short port) /* {{{ */
 762 {
 763         int fd = socket(AF_INET, SOCK_STREAM, 0);
 764 
 765         switch (fd) {
 766                 case -1:
 767                         return -1;
 768 
 769                 default: {
 770                         int reuse = 1;
 771 
 772                         switch (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*) &reuse, sizeof(reuse))) {
 773                                 case -1:
 774                                         close(fd);
 775                                         return -2;
 776 
 777                                 default: {
 778                                         struct sockaddr_in address;
 779 
 780                                         memset(&address, 0, sizeof(address));
 781 
 782                                         address.sin_port = htons(port);
 783                                         address.sin_family = AF_INET;
 784 
 785                                         if ((*interface == '*')) {
 786                                                 address.sin_addr.s_addr = htonl(INADDR_ANY);
 787                                         } else if (!inet_pton(AF_INET, interface, &address.sin_addr)) {
 788                                                 close(fd);
 789                                                 return -3;
 790                                         }
 791 
 792                                         switch (bind(fd, (struct sockaddr *)&address, sizeof(address))) {
 793                                                 case -1:
 794                                                         close(fd);
 795                                                         return -4;
 796 
 797                                                 default: {
 798                                                         listen(fd, 5);
 799                                                 }
 800                                         }
 801                                 }
 802                         }
 803                 }
 804         }
 805 
 806         return fd;
 807 } /* }}} */
 808 
 809 static inline void phpdbg_close_sockets(int (*socket)[2], FILE *streams[2]) /* {{{ */
 810 {
 811         if ((*socket)[0] >= 0) {
 812                 shutdown(
 813                         (*socket)[0], SHUT_RDWR);
 814                 close((*socket)[0]);
 815         }
 816 
 817         if (streams[0]) {
 818                 fclose(streams[0]);
 819         }
 820 
 821         if ((*socket)[1] >= 0) {
 822                 shutdown(
 823                         (*socket)[1], SHUT_RDWR);
 824                 close((*socket)[1]);
 825         }
 826 
 827         if (streams[1]) {
 828                 fclose(streams[1]);
 829         }
 830 } /* }}} */
 831 
 832 /* don't inline this, want to debug it easily, will inline when done */
 833 
 834 int phpdbg_open_sockets(char *address, int port[2], int (*listen)[2], int (*socket)[2], FILE* streams[2]) /* {{{ */
 835 {
 836         if (((*listen)[0]) < 0 && ((*listen)[1]) < 0) {
 837                 ((*listen)[0]) = phpdbg_open_socket(address, (short)port[0]);
 838                 ((*listen)[1]) = phpdbg_open_socket(address, (short)port[1]);
 839         }
 840 
 841         streams[0] = NULL;
 842         streams[1] = NULL;
 843 
 844         if ((*listen)[0] < 0 || (*listen)[1] < 0) {
 845                 if ((*listen)[0] < 0) {
 846                         phpdbg_rlog(stderr,
 847                                 "console failed to initialize (stdin) on %s:%d", address, port[0]);
 848                 }
 849 
 850                 if ((*listen)[1] < 0) {
 851                         phpdbg_rlog(stderr,
 852                                 "console failed to initialize (stdout) on %s:%d", address, port[1]);
 853                 }
 854 
 855                 if ((*listen)[0] >= 0) {
 856                         close((*listen)[0]);
 857                 }
 858 
 859                 if ((*listen)[1] >= 0) {
 860                         close((*listen)[1]);
 861                 }
 862 
 863                 return FAILURE;
 864         }
 865 
 866         phpdbg_close_sockets(socket, streams);
 867 
 868         phpdbg_rlog(stderr,
 869                 "accepting connections on %s:%d/%d", address, port[0], port[1]);
 870         {
 871                 struct sockaddr_in address;
 872                 socklen_t size = sizeof(address);
 873                 char buffer[20] = {0};
 874 
 875                 {
 876                         memset(&address, 0, size);
 877                         (*socket)[0] = accept(
 878                                 (*listen)[0], (struct sockaddr *) &address, &size);
 879                         inet_ntop(AF_INET, &address.sin_addr, buffer, sizeof(buffer));
 880 
 881                         phpdbg_rlog(stderr, "connection (stdin) from %s", buffer);
 882                 }
 883 
 884                 {
 885                         memset(&address, 0, size);
 886                         (*socket)[1] = accept(
 887                                 (*listen)[1], (struct sockaddr *) &address, &size);
 888                     inet_ntop(AF_INET, &address.sin_addr, buffer, sizeof(buffer));
 889 
 890                         phpdbg_rlog(stderr, "connection (stdout) from %s", buffer);
 891                 }
 892         }
 893 
 894         dup2((*socket)[0], fileno(stdin));
 895         dup2((*socket)[1], fileno(stdout));
 896 
 897         setbuf(stdout, NULL);
 898 
 899         streams[0] = fdopen((*socket)[0], "r");
 900         streams[1] = fdopen((*socket)[1], "w");
 901 
 902         return SUCCESS;
 903 } /* }}} */
 904 
 905 void phpdbg_signal_handler(int sig, siginfo_t *info, void *context) /* {{{ */
 906 {
 907         int is_handled = FAILURE;
 908         TSRMLS_FETCH();
 909 
 910         switch (sig) {
 911                 case SIGBUS:
 912                 case SIGSEGV:
 913                         is_handled = phpdbg_watchpoint_segfault_handler(info, context TSRMLS_CC);
 914                         if (is_handled == FAILURE) {
 915 #ifdef ZEND_SIGNALS
 916                                 zend_sigaction(sig, &PHPDBG_G(old_sigsegv_signal), NULL TSRMLS_CC);
 917 #else
 918                                 sigaction(sig, &PHPDBG_G(old_sigsegv_signal), NULL);
 919 #endif
 920                         }
 921                         break;
 922         }
 923 
 924 } /* }}} */
 925 #endif
 926 
 927 static inline zend_mm_heap *phpdbg_mm_get_heap() /* {{{ */
 928 {
 929         zend_mm_heap *mm_heap;
 930 
 931         TSRMLS_FETCH();
 932 
 933         mm_heap = zend_mm_set_heap(NULL TSRMLS_CC);
 934         zend_mm_set_heap(mm_heap TSRMLS_CC);
 935 
 936         return mm_heap;
 937 } /* }}} */
 938 
 939 void *phpdbg_malloc_wrapper(size_t size) /* {{{ */
 940 {
 941         return zend_mm_alloc(phpdbg_mm_get_heap(), size);
 942 } /* }}} */
 943 
 944 void phpdbg_free_wrapper(void *p) /* {{{ */
 945 {
 946         zend_mm_free(phpdbg_mm_get_heap(), p);
 947 } /* }}} */
 948 
 949 void *phpdbg_realloc_wrapper(void *ptr, size_t size) /* {{{ */
 950 {
 951         return zend_mm_realloc(phpdbg_mm_get_heap(), ptr, size);
 952 } /* }}} */
 953 
 954 int main(int argc, char **argv) /* {{{ */
 955 {
 956         sapi_module_struct *phpdbg = &phpdbg_sapi_module;
 957         char *sapi_name;
 958         char *ini_entries;
 959         int   ini_entries_len;
 960         char **zend_extensions = NULL;
 961         zend_ulong zend_extensions_len = 0L;
 962         zend_bool ini_ignore;
 963         char *ini_override;
 964         char *exec;
 965         size_t exec_len;
 966         char *init_file;
 967         size_t init_file_len;
 968         zend_bool init_file_default;
 969         char *oplog_file;
 970         size_t oplog_file_len;
 971         zend_ulong flags;
 972         char *php_optarg;
 973         int php_optind, opt, show_banner = 1;
 974         long cleaning = 0;
 975         zend_bool remote = 0;
 976         int run = 0;
 977         int step = 0;
 978 
 979 #ifdef _WIN32
 980         char *bp_tmp_file = NULL;
 981 #else
 982         char bp_tmp_file[] = "/tmp/phpdbg.XXXXXX";
 983 #endif
 984 
 985 #ifndef _WIN32
 986         char *address;
 987         int listen[2];
 988         int server[2];
 989         int socket[2];
 990         FILE* streams[2] = {NULL, NULL};
 991 #endif
 992 
 993 #ifdef ZTS
 994         void ***tsrm_ls;
 995 #endif
 996 
 997 #ifndef _WIN32
 998         struct sigaction signal_struct;
 999         signal_struct.sa_sigaction = phpdbg_signal_handler;
1000         signal_struct.sa_flags = SA_SIGINFO | SA_NODEFER;
1001 
1002         address = strdup("127.0.0.1");
1003         socket[0] = -1;
1004         socket[1] = -1;
1005         listen[0] = -1;
1006         listen[1] = -1;
1007         server[0] = -1;
1008         server[1] = -1;
1009         streams[0] = NULL;
1010         streams[1] = NULL;
1011 #endif
1012 
1013 #ifdef PHP_WIN32
1014         _fmode = _O_BINARY;                 /* sets default for file streams to binary */
1015         setmode(_fileno(stdin), O_BINARY);  /* make the stdio mode be binary */
1016         setmode(_fileno(stdout), O_BINARY); /* make the stdio mode be binary */
1017         setmode(_fileno(stderr), O_BINARY); /* make the stdio mode be binary */
1018 #endif
1019 
1020 #ifdef ZTS
1021         tsrm_startup(1, 1, 0, NULL);
1022 
1023         tsrm_ls = ts_resource(0);
1024 #endif
1025 
1026 phpdbg_main:
1027         if (!cleaning) {
1028         
1029 #ifdef _WIN32
1030                 bp_tmp_file = malloc(L_tmpnam);
1031 
1032                 if (bp_tmp_file) {
1033                         if (!tmpnam(bp_tmp_file)) {
1034                                 free(bp_tmp_file);
1035                                 bp_tmp_file = NULL;
1036                         }
1037                 }
1038 
1039                 if (!bp_tmp_file) {
1040                         phpdbg_error("Unable to create temporary file");
1041                         return 1;
1042                 }
1043 #else
1044                 if (!mkstemp(bp_tmp_file)) {
1045                         memset(bp_tmp_file, 0, sizeof(bp_tmp_file));
1046                 }
1047 #endif
1048 
1049         }
1050         ini_entries = NULL;
1051         ini_entries_len = 0;
1052         ini_ignore = 0;
1053         ini_override = NULL;
1054         zend_extensions = NULL;
1055         zend_extensions_len = 0L;
1056         exec = NULL;
1057         exec_len = 0;
1058         init_file = NULL;
1059         init_file_len = 0;
1060         init_file_default = 1;
1061         oplog_file = NULL;
1062         oplog_file_len = 0;
1063         flags = PHPDBG_DEFAULT_FLAGS;
1064         php_optarg = NULL;
1065         php_optind = 1;
1066         opt = 0;
1067         run = 0;
1068         step = 0;
1069         sapi_name = NULL;
1070 
1071         while ((opt = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) {
1072                 switch (opt) {
1073                         case 'r':
1074                                 run++;
1075                                 break;
1076                         case 'n':
1077                                 ini_ignore = 1;
1078                                 break;
1079                         case 'c':
1080                                 if (ini_override) {
1081                                         free(ini_override);
1082                                 }
1083                                 ini_override = strdup(php_optarg);
1084                                 break;
1085                         case 'd': {
1086                                 int len = strlen(php_optarg);
1087                                 char *val;
1088 
1089                                 if ((val = strchr(php_optarg, '='))) {
1090                                   val++;
1091                                   if (!isalnum(*val) && *val != '"' && *val != '\'' && *val != '\0') {
1092                                           ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("\"\"\n\0"));
1093                                           memcpy(ini_entries + ini_entries_len, php_optarg, (val - php_optarg));
1094                                           ini_entries_len += (val - php_optarg);
1095                                           memcpy(ini_entries + ini_entries_len, "\"", 1);
1096                                           ini_entries_len++;
1097                                           memcpy(ini_entries + ini_entries_len, val, len - (val - php_optarg));
1098                                           ini_entries_len += len - (val - php_optarg);
1099                                           memcpy(ini_entries + ini_entries_len, "\"\n\0", sizeof("\"\n\0"));
1100                                           ini_entries_len += sizeof("\n\0\"") - 2;
1101                                   } else {
1102                                           ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("\n\0"));
1103                                           memcpy(ini_entries + ini_entries_len, php_optarg, len);
1104                                           memcpy(ini_entries + ini_entries_len + len, "\n\0", sizeof("\n\0"));
1105                                           ini_entries_len += len + sizeof("\n\0") - 2;
1106                                   }
1107                                 } else {
1108                                   ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("=1\n\0"));
1109                                   memcpy(ini_entries + ini_entries_len, php_optarg, len);
1110                                   memcpy(ini_entries + ini_entries_len + len, "=1\n\0", sizeof("=1\n\0"));
1111                                   ini_entries_len += len + sizeof("=1\n\0") - 2;
1112                                 }
1113                         } break;
1114 
1115                         case 'z':
1116                                 zend_extensions_len++;
1117                                 if (zend_extensions) {
1118                                         zend_extensions = realloc(zend_extensions, sizeof(char*) * zend_extensions_len);
1119                                 } else zend_extensions = malloc(sizeof(char*) * zend_extensions_len);
1120                                 zend_extensions[zend_extensions_len-1] = strdup(php_optarg);
1121                         break;
1122 
1123                         /* begin phpdbg options */
1124 
1125                         case 'S': { /* set SAPI name */
1126                                 if (sapi_name) {
1127                                         free(sapi_name);
1128                                 }
1129                                 sapi_name = strdup(php_optarg);
1130                         } break;
1131 
1132                         case 'I': { /* ignore .phpdbginit */
1133                                 init_file_default = 0;
1134                         } break;
1135 
1136                         case 'i': { /* set init file */
1137                                 if (init_file) {
1138                                         free(init_file);
1139                                 }
1140 
1141                                 init_file_len = strlen(php_optarg);
1142                                 if (init_file_len) {
1143                                         init_file = strdup(php_optarg);
1144                                 }
1145                         } break;
1146 
1147                         case 'O': { /* set oplog output */
1148                                 oplog_file_len = strlen(php_optarg);
1149                                 if (oplog_file_len) {
1150                                         oplog_file = strdup(php_optarg);
1151                                 }
1152                         } break;
1153 
1154                         case 'v': /* set quietness off */
1155                                 flags &= ~PHPDBG_IS_QUIET;
1156                         break;
1157 
1158                         case 's': /* set stepping on */
1159                                 step = 1;
1160                         break;
1161 
1162                         case 'E': /* stepping through eval on */
1163                                 flags |= PHPDBG_IS_STEPONEVAL;
1164                         break;
1165 
1166                         case 'b': /* set colours off */
1167                                 flags &= ~PHPDBG_IS_COLOURED;
1168                         break;
1169 
1170                         case 'q': /* hide banner */
1171                                 show_banner = 0;
1172                         break;
1173 
1174 #ifndef _WIN32
1175                         /* if you pass a listen port, we will accept input on listen port */
1176                         /* and write output to listen port * 2 */
1177 
1178                         case 'l': { /* set listen ports */
1179                                 if (sscanf(php_optarg, "%d/%d", &listen[0], &listen[1]) != 2) {
1180                                         if (sscanf(php_optarg, "%d", &listen[0]) != 1) {
1181                                                 /* default to hardcoded ports */
1182                                                 listen[0] = 4000;
1183                                                 listen[1] = 8000;
1184                                         } else {
1185                                                 listen[1] = (listen[0] * 2);
1186                                         }
1187                                 }
1188                         } break;
1189 
1190                         case 'a': { /* set bind address */
1191                                 free(address);
1192                                 if (!php_optarg) {
1193                                         address = strdup("*");
1194                                 } else address = strdup(php_optarg);
1195                         } break;
1196 #endif
1197 
1198                         case 'V': {
1199                                 sapi_startup(phpdbg);
1200                                 phpdbg->startup(phpdbg);
1201                                 printf(
1202                                         "phpdbg %s (built: %s %s)\nPHP %s, Copyright (c) 1997-2016 The PHP Group\n%s",
1203                                         PHPDBG_VERSION,
1204                                         __DATE__,
1205                                         __TIME__,
1206                                         PHP_VERSION,
1207                                         get_zend_version()
1208                                 );
1209                                 sapi_deactivate(TSRMLS_C);
1210                                 sapi_shutdown();
1211                                 return 0;
1212                         } break;
1213                 }
1214         }
1215         
1216         /* set exec if present on command line */
1217         if ((argc > php_optind) && (strcmp(argv[php_optind-1],"--") != SUCCESS))
1218         {
1219                 exec_len = strlen(argv[php_optind]);
1220                 if (exec_len) {
1221                         if (exec) {
1222                                 free(exec);
1223                         }
1224                         exec = strdup(argv[php_optind]);
1225                 }
1226                 php_optind++;
1227         }
1228 
1229 #ifndef _WIN32
1230         /* setup remote server if necessary */
1231         if (!cleaning &&
1232                 (listen[0] > 0 && listen[1] > 0)) {
1233                 if (phpdbg_open_sockets(address, listen, &server, &socket, streams) == FAILURE) {
1234                         remote = 0;
1235                         exit(0);
1236                 }
1237                 /* set remote flag to stop service shutting down upon quit */
1238                 remote = 1;
1239         }
1240 #endif
1241 
1242         if (sapi_name) {
1243                 phpdbg->name = sapi_name;
1244         }
1245 
1246         phpdbg->ini_defaults = phpdbg_ini_defaults;
1247         phpdbg->phpinfo_as_text = 1;
1248         phpdbg->php_ini_ignore_cwd = 1;
1249 
1250         sapi_startup(phpdbg);
1251 
1252         phpdbg->executable_location = argv[0];
1253         phpdbg->phpinfo_as_text = 1;
1254         phpdbg->php_ini_ignore = ini_ignore;
1255         phpdbg->php_ini_path_override = ini_override;
1256 
1257         if (ini_entries) {
1258                 ini_entries = realloc(ini_entries, ini_entries_len + sizeof(phpdbg_ini_hardcoded));
1259                 memmove(ini_entries + sizeof(phpdbg_ini_hardcoded) - 2, ini_entries, ini_entries_len + 1);
1260                 memcpy(ini_entries, phpdbg_ini_hardcoded, sizeof(phpdbg_ini_hardcoded) - 2);
1261         } else {
1262                 ini_entries = malloc(sizeof(phpdbg_ini_hardcoded));
1263                 memcpy(ini_entries, phpdbg_ini_hardcoded, sizeof(phpdbg_ini_hardcoded));
1264         }
1265         ini_entries_len += sizeof(phpdbg_ini_hardcoded) - 2;
1266 
1267         if (zend_extensions_len) {
1268                 zend_ulong zend_extension = 0L;
1269 
1270                 while (zend_extension < zend_extensions_len) {
1271                         const char *ze = zend_extensions[zend_extension];
1272                         size_t ze_len = strlen(ze);
1273 
1274                         ini_entries = realloc(
1275                                 ini_entries, ini_entries_len + (ze_len + (sizeof("zend_extension=\n"))));
1276                         memcpy(&ini_entries[ini_entries_len], "zend_extension=", (sizeof("zend_extension=\n")-1));
1277                         ini_entries_len += (sizeof("zend_extension=")-1);
1278                         memcpy(&ini_entries[ini_entries_len], ze, ze_len);
1279                         ini_entries_len += ze_len;
1280                         memcpy(&ini_entries[ini_entries_len], "\n", (sizeof("\n") - 1));
1281 
1282                         free(zend_extensions[zend_extension]);
1283                         zend_extension++;
1284                 }
1285 
1286                 free(zend_extensions);
1287         }
1288 
1289         phpdbg->ini_entries = ini_entries;
1290 
1291         if (phpdbg->startup(phpdbg) == SUCCESS) {
1292 #ifdef _WIN32
1293     EXCEPTION_POINTERS *xp;
1294     __try {
1295 #endif
1296                 zend_mm_heap *mm_heap = phpdbg_mm_get_heap();
1297 
1298                 if (mm_heap->use_zend_alloc) {
1299                         mm_heap->_malloc = phpdbg_malloc_wrapper;
1300                         mm_heap->_realloc = phpdbg_realloc_wrapper;
1301                         mm_heap->_free = phpdbg_free_wrapper;
1302                         mm_heap->use_zend_alloc = 0;
1303                 }
1304 
1305                 zend_activate(TSRMLS_C);
1306 
1307                 PHPDBG_G(original_free_function) = mm_heap->_free;
1308                 mm_heap->_free = phpdbg_watch_efree;
1309 
1310                 phpdbg_setup_watchpoints(TSRMLS_C);
1311 
1312 #if defined(ZEND_SIGNALS) && !defined(_WIN32)
1313                 zend_try {
1314                         zend_signal_activate(TSRMLS_C);
1315                 } zend_end_try();
1316 #endif
1317 
1318 #if defined(ZEND_SIGNALS) && !defined(_WIN32)
1319                 zend_try { zend_sigaction(SIGSEGV, &signal_struct, &PHPDBG_G(old_sigsegv_signal) TSRMLS_CC); } zend_end_try();
1320                 zend_try { zend_sigaction(SIGBUS, &signal_struct, &PHPDBG_G(old_sigsegv_signal) TSRMLS_CC); } zend_end_try();
1321 #elif !defined(_WIN32)
1322                 sigaction(SIGSEGV, &signal_struct, &PHPDBG_G(old_sigsegv_signal));
1323                 sigaction(SIGBUS, &signal_struct, &PHPDBG_G(old_sigsegv_signal));
1324 #endif
1325 
1326                 if (php_request_startup(TSRMLS_C) == SUCCESS) {
1327                         int i;
1328                 
1329                         SG(request_info).argc = argc - php_optind + 1;          
1330                         SG(request_info).argv = emalloc(SG(request_info).argc * sizeof(char *));
1331                         for (i = SG(request_info).argc; --i;) {
1332                                 SG(request_info).argv[i] = estrdup(argv[php_optind - 1 + i]);
1333                         }
1334                         SG(request_info).argv[i] = exec ? estrndup(exec, exec_len) : estrdup("");
1335 
1336                         php_hash_environment(TSRMLS_C);
1337                 }
1338 
1339                 /* make sure to turn off buffer for ev command */
1340                 php_output_activate(TSRMLS_C);
1341                 php_output_deactivate(TSRMLS_C);
1342                 
1343                 /* do not install sigint handlers for remote consoles */
1344                 /* sending SIGINT then provides a decent way of shutting down the server */
1345 #ifndef _WIN32
1346                 if (listen[0] < 0) {
1347 #endif
1348 #if defined(ZEND_SIGNALS) && !defined(_WIN32)
1349                         zend_try { zend_signal(SIGINT, phpdbg_sigint_handler TSRMLS_CC); } zend_end_try();
1350 #else
1351                         signal(SIGINT, phpdbg_sigint_handler);
1352 #endif
1353 #ifndef _WIN32
1354                 }
1355 #endif
1356 
1357                 PG(modules_activated) = 0;
1358 
1359                 /* set flags from command line */
1360                 PHPDBG_G(flags) = flags;
1361 
1362 #ifndef _WIN32
1363                 /* setup io here */
1364                 if (streams[0] && streams[1]) {
1365                         PHPDBG_G(flags) |= PHPDBG_IS_REMOTE;
1366 
1367                         signal(SIGPIPE, SIG_IGN);
1368                 }
1369 #endif
1370 
1371                 PHPDBG_G(io)[PHPDBG_STDIN] = stdin;
1372                 PHPDBG_G(io)[PHPDBG_STDOUT] = stdout;
1373                 PHPDBG_G(io)[PHPDBG_STDERR] = stderr;
1374 
1375                 if (exec) { /* set execution context */
1376                         PHPDBG_G(exec) = phpdbg_resolve_path(exec TSRMLS_CC);
1377                         PHPDBG_G(exec_len) = strlen(PHPDBG_G(exec));
1378 
1379                         free(exec);
1380                 }
1381 
1382                 if (oplog_file) { /* open oplog */
1383                         PHPDBG_G(oplog) = fopen(oplog_file, "w+");
1384                         if (!PHPDBG_G(oplog)) {
1385                                 phpdbg_error(
1386                                                 "Failed to open oplog %s", oplog_file);
1387                         }
1388                         free(oplog_file);
1389                 }
1390 
1391                 /* set default colors */
1392                 phpdbg_set_color_ex(PHPDBG_COLOR_PROMPT,  PHPDBG_STRL("white-bold") TSRMLS_CC);
1393                 phpdbg_set_color_ex(PHPDBG_COLOR_ERROR,   PHPDBG_STRL("red-bold") TSRMLS_CC);
1394                 phpdbg_set_color_ex(PHPDBG_COLOR_NOTICE,  PHPDBG_STRL("green") TSRMLS_CC);
1395 
1396                 /* set default prompt */
1397                 phpdbg_set_prompt(PROMPT TSRMLS_CC);
1398 
1399                 /* Make stdin, stdout and stderr accessible from PHP scripts */
1400                 phpdbg_register_file_handles(TSRMLS_C);
1401 
1402                 if (show_banner) {
1403                         /* print blurb */
1404                         phpdbg_welcome((cleaning > 0) TSRMLS_CC);
1405                 }
1406 
1407                 /* auto compile */
1408                 if (PHPDBG_G(exec)) {
1409                         phpdbg_compile(TSRMLS_C);
1410                 }
1411 
1412                 /* initialize from file */
1413                 PHPDBG_G(flags) |= PHPDBG_IS_INITIALIZING;
1414                 zend_try {
1415                         phpdbg_init(init_file, init_file_len, init_file_default TSRMLS_CC);
1416                         phpdbg_try_file_init(bp_tmp_file, strlen(bp_tmp_file), 0 TSRMLS_CC);
1417                 } zend_end_try();
1418                 PHPDBG_G(flags) &= ~PHPDBG_IS_INITIALIZING;
1419                 
1420                 /* quit if init says so */
1421                 if (PHPDBG_G(flags) & PHPDBG_IS_QUITTING) {
1422                         goto phpdbg_out;
1423                 }
1424 
1425                 /* step from here, not through init */
1426                 if (step) {
1427                         PHPDBG_G(flags) |= PHPDBG_IS_STEPPING;
1428                 }
1429 
1430                 if (run) {
1431                         /* no need to try{}, run does it ... */
1432                         PHPDBG_COMMAND_HANDLER(run)(NULL TSRMLS_CC);
1433                         if (run > 1) {
1434                                 /* if -r is on the command line more than once just quit */
1435                                 goto phpdbg_out;
1436                         }
1437                 }
1438 
1439 /* #ifndef for making compiler shutting up */
1440 #ifndef _WIN32
1441 phpdbg_interact:
1442 #endif
1443                 /* phpdbg main() */
1444                 do {
1445                         zend_try {
1446                                 phpdbg_interactive(TSRMLS_C);
1447                         } zend_catch {
1448                                 if ((PHPDBG_G(flags) & PHPDBG_IS_CLEANING)) {
1449                                         FILE *bp_tmp_fp = fopen(bp_tmp_file, "w");
1450                                         phpdbg_export_breakpoints(bp_tmp_fp TSRMLS_CC);
1451                                         fclose(bp_tmp_fp);
1452                                         cleaning = 1;
1453                                 } else {
1454                                         cleaning = 0;
1455                                 }
1456 
1457 #ifndef _WIN32
1458                                 if (!cleaning) {
1459                                         /* remote client disconnected */
1460                                         if ((PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED)) {
1461                                         
1462                                                 if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) {
1463                                                         /* renegociate connections */
1464                                                         phpdbg_open_sockets(
1465                                                                 address, listen, &server, &socket, streams);
1466                                 
1467                                                         /* set streams */
1468                                                         if (streams[0] && streams[1]) {
1469                                                                 PHPDBG_G(flags) &= ~PHPDBG_IS_QUITTING;
1470                                                         }
1471                                 
1472                                                         /* this must be forced */
1473                                                         CG(unclean_shutdown) = 0;
1474                                                 } else {
1475                                                         /* local consoles cannot disconnect, ignore EOF */
1476                                                         PHPDBG_G(flags) &= ~PHPDBG_IS_DISCONNECTED;
1477                                                 }
1478                                         }
1479                                 }
1480 #endif
1481                         } zend_end_try();
1482                 } while(!cleaning && !(PHPDBG_G(flags) & PHPDBG_IS_QUITTING));
1483                 
1484                 /* this must be forced */
1485                 CG(unclean_shutdown) = 0;
1486                 
1487                 /* this is just helpful */
1488                 PG(report_memleaks) = 0;
1489                 
1490 #ifndef _WIN32
1491 phpdbg_out:
1492                 if ((PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED)) {
1493                         PHPDBG_G(flags) &= ~PHPDBG_IS_DISCONNECTED;
1494                         goto phpdbg_interact;
1495                 }
1496 #endif
1497 
1498 #ifdef _WIN32
1499         } __except(phpdbg_exception_handler_win32(xp = GetExceptionInformation())) {
1500                 phpdbg_error("Access violation (Segmentation fault) encountered\ntrying to abort cleanly...");
1501         }
1502 phpdbg_out:
1503 #endif
1504         
1505                 {
1506                         int i;
1507                         /* free argv */
1508                         for (i = SG(request_info).argc; --i;) {
1509                                 efree(SG(request_info).argv[i]);
1510                         }
1511                         efree(SG(request_info).argv);
1512                 }
1513 
1514 #ifndef ZTS
1515                 /* force cleanup of auto and core globals */
1516                 zend_hash_clean(CG(auto_globals));
1517                 memset(
1518                         &core_globals, 0, sizeof(php_core_globals));
1519 #endif
1520                 if (ini_entries) {
1521                         free(ini_entries);
1522                 }
1523 
1524                 if (ini_override) {
1525                         free(ini_override);
1526                 }
1527                 
1528                 /* this must be forced */
1529                 CG(unclean_shutdown) = 0;
1530                 
1531                 /* this is just helpful */
1532                 PG(report_memleaks) = 0;
1533 
1534                 php_request_shutdown((void*)0);
1535 
1536                 zend_try {
1537                         php_module_shutdown(TSRMLS_C);
1538                 } zend_end_try();
1539 
1540                 sapi_shutdown();
1541 
1542         }
1543 
1544         if (cleaning || remote) {
1545                 goto phpdbg_main;
1546         }
1547         
1548 #ifdef ZTS
1549         /* bugggy */
1550         /* tsrm_shutdown(); */
1551 #endif
1552 
1553 #ifndef _WIN32
1554         if (address) {
1555                 free(address);
1556         }
1557 #endif
1558 
1559         if (sapi_name) {
1560                 free(sapi_name);
1561         }
1562         
1563 #ifdef _WIN32
1564         free(bp_tmp_file);
1565 #else
1566         unlink(bp_tmp_file);
1567 #endif
1568 
1569         return 0;
1570 } /* }}} */

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