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