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