xref: /PHP-7.1/sapi/phpdbg/phpdbg.c (revision 7f6387b5)
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, 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 
phpdbg_interned_strings_nothing(void)818 static void phpdbg_interned_strings_nothing(void) { }
819 
php_sapi_phpdbg_module_startup(sapi_module_struct * module)820 static inline int php_sapi_phpdbg_module_startup(sapi_module_struct *module) /* {{{ */
821 {
822 	if (php_module_startup(module, &sapi_phpdbg_module_entry, 1) == FAILURE) {
823 		return FAILURE;
824 	}
825 	/* prevent zend_interned_strings_restore from invalidating our string pointers too early (in phpdbg allocated memory only gets freed after module shutdown) */
826 	zend_interned_strings_restore = phpdbg_interned_strings_nothing;
827 
828 	phpdbg_booted = 1;
829 
830 	return SUCCESS;
831 } /* }}} */
832 
php_sapi_phpdbg_read_cookies(void)833 static char* php_sapi_phpdbg_read_cookies(void) /* {{{ */
834 {
835 	return NULL;
836 } /* }}} */
837 
php_sapi_phpdbg_header_handler(sapi_header_struct * h,sapi_header_op_enum op,sapi_headers_struct * s)838 static int php_sapi_phpdbg_header_handler(sapi_header_struct *h, sapi_header_op_enum op, sapi_headers_struct *s) /* {{{ */
839 {
840 	return 0;
841 }
842 /* }}} */
843 
php_sapi_phpdbg_send_headers(sapi_headers_struct * sapi_headers)844 static int php_sapi_phpdbg_send_headers(sapi_headers_struct *sapi_headers) /* {{{ */
845 {
846 	/* We do nothing here, this function is needed to prevent that the fallback
847 	 * header handling is called. */
848 	return SAPI_HEADER_SENT_SUCCESSFULLY;
849 }
850 /* }}} */
851 
php_sapi_phpdbg_send_header(sapi_header_struct * sapi_header,void * server_context)852 static void php_sapi_phpdbg_send_header(sapi_header_struct *sapi_header, void *server_context) /* {{{ */
853 {
854 }
855 /* }}} */
856 
php_sapi_phpdbg_log_message(char * message,int syslog_type_int)857 static void php_sapi_phpdbg_log_message(char *message, int syslog_type_int) /* {{{ */
858 {
859 	/*
860 	* We must not request TSRM before being booted
861 	*/
862 	if (phpdbg_booted) {
863 		if (PHPDBG_G(flags) & PHPDBG_IN_EVAL) {
864 			phpdbg_error("eval", "msg=\"%s\"", "%s", message);
865 			return;
866 		}
867 
868 		phpdbg_error("php", "msg=\"%s\"", "%s", message);
869 
870 		if (PHPDBG_G(flags) & PHPDBG_PREVENT_INTERACTIVE) {
871 			return;
872 		}
873 
874 		switch (PG(last_error_type)) {
875 			case E_ERROR:
876 			case E_CORE_ERROR:
877 			case E_COMPILE_ERROR:
878 			case E_USER_ERROR:
879 			case E_PARSE:
880 			case E_RECOVERABLE_ERROR: {
881 				const char *file_char = zend_get_executed_filename();
882 				zend_string *file = zend_string_init(file_char, strlen(file_char), 0);
883 				phpdbg_list_file(file, 3, zend_get_executed_lineno() - 1, zend_get_executed_lineno());
884 				zend_string_release(file);
885 
886 				if (!phpdbg_fully_started) {
887 					return;
888 				}
889 
890 				do {
891 					switch (phpdbg_interactive(1, NULL)) {
892 						case PHPDBG_LEAVE:
893 						case PHPDBG_FINISH:
894 						case PHPDBG_UNTIL:
895 						case PHPDBG_NEXT:
896 							return;
897 					}
898 				} while (!(PHPDBG_G(flags) & PHPDBG_IS_STOPPING));
899 			}
900 		}
901 	} else {
902 		fprintf(stdout, "%s\n", message);
903 	}
904 }
905 /* }}} */
906 
php_sapi_phpdbg_activate(void)907 static int php_sapi_phpdbg_activate(void) /* {{{ */
908 {
909 	return SUCCESS;
910 }
911 
php_sapi_phpdbg_deactivate(void)912 static int php_sapi_phpdbg_deactivate(void) /* {{{ */
913 {
914 	return SUCCESS;
915 }
916 
php_sapi_phpdbg_register_vars(zval * track_vars_array)917 static void php_sapi_phpdbg_register_vars(zval *track_vars_array) /* {{{ */
918 {
919 	size_t len;
920 	char  *docroot = "";
921 
922 	/* In phpdbg mode, we consider the environment to be a part of the server variables
923 	*/
924 	php_import_environment_variables(track_vars_array);
925 
926 	if (PHPDBG_G(exec)) {
927 		len = PHPDBG_G(exec_len);
928 		if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF", &PHPDBG_G(exec), PHPDBG_G(exec_len), &len)) {
929 			php_register_variable("PHP_SELF", PHPDBG_G(exec), track_vars_array);
930 		}
931 		if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_NAME", &PHPDBG_G(exec), PHPDBG_G(exec_len), &len)) {
932 			php_register_variable("SCRIPT_NAME", PHPDBG_G(exec), track_vars_array);
933 		}
934 
935 		if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_FILENAME", &PHPDBG_G(exec), PHPDBG_G(exec_len), &len)) {
936 			php_register_variable("SCRIPT_FILENAME", PHPDBG_G(exec), track_vars_array);
937 		}
938 		if (sapi_module.input_filter(PARSE_SERVER, "PATH_TRANSLATED", &PHPDBG_G(exec), PHPDBG_G(exec_len), &len)) {
939 			php_register_variable("PATH_TRANSLATED", PHPDBG_G(exec), track_vars_array);
940 		}
941 	}
942 
943 	/* any old docroot will do */
944 	len = 0;
945 	if (sapi_module.input_filter(PARSE_SERVER, "DOCUMENT_ROOT", &docroot, len, &len)) {
946 		php_register_variable("DOCUMENT_ROOT", docroot, track_vars_array);
947 	}
948 }
949 /* }}} */
950 
php_sapi_phpdbg_ub_write(const char * message,size_t length)951 static inline size_t php_sapi_phpdbg_ub_write(const char *message, size_t length) /* {{{ */
952 {
953 	if (PHPDBG_G(socket_fd) != -1 && !(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) {
954 		send(PHPDBG_G(socket_fd), message, length, 0);
955 	}
956 	return phpdbg_script(P_STDOUT, "%.*s", (int) length, message);
957 } /* }}} */
958 
959 /* beginning of struct, see main/streams/plain_wrapper.c line 111 */
960 typedef struct {
961 	FILE *file;
962 	int fd;
963 } php_stdio_stream_data;
964 
phpdbg_stdiop_write(php_stream * stream,const char * buf,size_t count)965 static size_t phpdbg_stdiop_write(php_stream *stream, const char *buf, size_t count) {
966 	php_stdio_stream_data *data = (php_stdio_stream_data*)stream->abstract;
967 
968 	while (data->fd >= 0) {
969 		struct stat stat[3];
970 		memset(stat, 0, sizeof(stat));
971 		if (((fstat(fileno(stderr), &stat[2]) < 0) & (fstat(fileno(stdout), &stat[0]) < 0)) | (fstat(data->fd, &stat[1]) < 0)) {
972 			break;
973 		}
974 
975 		if (stat[0].st_dev == stat[1].st_dev && stat[0].st_ino == stat[1].st_ino) {
976 			phpdbg_script(P_STDOUT, "%.*s", (int) count, buf);
977 			return count;
978 		}
979 		if (stat[2].st_dev == stat[1].st_dev && stat[2].st_ino == stat[1].st_ino) {
980 			phpdbg_script_ex(PHPDBG_G(io)[PHPDBG_STDERR].fd, P_STDERR, "%.*s", (int) count, buf);
981 			return count;
982 		}
983 		break;
984 	}
985 
986 	return PHPDBG_G(php_stdiop_write)(stream, buf, count);
987 }
988 
php_sapi_phpdbg_flush(void * context)989 static inline void php_sapi_phpdbg_flush(void *context)  /* {{{ */
990 {
991 	if (!phpdbg_active_sigsafe_mem()) {
992 		fflush(PHPDBG_G(io)[PHPDBG_STDOUT].ptr);
993 	}
994 } /* }}} */
995 
996 /* copied from sapi/cli/php_cli.c cli_register_file_handles */
phpdbg_register_file_handles(void)997 void phpdbg_register_file_handles(void) /* {{{ */
998 {
999 	zval zin, zout, zerr;
1000 	php_stream *s_in, *s_out, *s_err;
1001 	php_stream_context *sc_in=NULL, *sc_out=NULL, *sc_err=NULL;
1002 	zend_constant ic, oc, ec;
1003 
1004 	s_in  = php_stream_open_wrapper_ex("php://stdin",  "rb", 0, NULL, sc_in);
1005 	s_out = php_stream_open_wrapper_ex("php://stdout", "wb", 0, NULL, sc_out);
1006 	s_err = php_stream_open_wrapper_ex("php://stderr", "wb", 0, NULL, sc_err);
1007 
1008 	if (s_in==NULL || s_out==NULL || s_err==NULL) {
1009 		if (s_in) php_stream_close(s_in);
1010 		if (s_out) php_stream_close(s_out);
1011 		if (s_err) php_stream_close(s_err);
1012 		return;
1013 	}
1014 
1015 #if PHP_DEBUG
1016 	/* do not close stdout and stderr */
1017 	s_out->flags |= PHP_STREAM_FLAG_NO_CLOSE;
1018 	s_err->flags |= PHP_STREAM_FLAG_NO_CLOSE;
1019 #endif
1020 
1021 	php_stream_to_zval(s_in,  &zin);
1022 	php_stream_to_zval(s_out, &zout);
1023 	php_stream_to_zval(s_err, &zerr);
1024 
1025 	ic.value = zin;
1026 	ic.flags = CONST_CS;
1027 	ic.name = zend_string_init(ZEND_STRL("STDIN"), 0);
1028 	ic.module_number = 0;
1029 	zend_hash_del(EG(zend_constants), ic.name);
1030 	zend_register_constant(&ic);
1031 
1032 	oc.value = zout;
1033 	oc.flags = CONST_CS;
1034 	oc.name = zend_string_init(ZEND_STRL("STDOUT"), 0);
1035 	oc.module_number = 0;
1036 	zend_hash_del(EG(zend_constants), oc.name);
1037 	zend_register_constant(&oc);
1038 
1039 	ec.value = zerr;
1040 	ec.flags = CONST_CS;
1041 	ec.name = zend_string_init(ZEND_STRL("STDERR"), 0);
1042 	ec.module_number = 0;
1043 	zend_hash_del(EG(zend_constants), ec.name);
1044 	zend_register_constant(&ec);
1045 }
1046 /* }}} */
1047 
1048 /* {{{ sapi_module_struct phpdbg_sapi_module
1049 */
1050 static sapi_module_struct phpdbg_sapi_module = {
1051 	"phpdbg",                       /* name */
1052 	"phpdbg",                       /* pretty name */
1053 
1054 	php_sapi_phpdbg_module_startup, /* startup */
1055 	php_module_shutdown_wrapper,    /* shutdown */
1056 
1057 	php_sapi_phpdbg_activate,       /* activate */
1058 	php_sapi_phpdbg_deactivate,     /* deactivate */
1059 
1060 	php_sapi_phpdbg_ub_write,       /* unbuffered write */
1061 	php_sapi_phpdbg_flush,          /* flush */
1062 	NULL,                           /* get uid */
1063 	NULL,                           /* getenv */
1064 
1065 	php_error,                      /* error handler */
1066 
1067 	php_sapi_phpdbg_header_handler, /* header handler */
1068 	php_sapi_phpdbg_send_headers,   /* send headers handler */
1069 	php_sapi_phpdbg_send_header,    /* send header handler */
1070 
1071 	NULL,                           /* read POST data */
1072 	php_sapi_phpdbg_read_cookies,   /* read Cookies */
1073 
1074 	php_sapi_phpdbg_register_vars,  /* register server variables */
1075 	php_sapi_phpdbg_log_message,    /* Log message */
1076 	NULL,                           /* Get request time */
1077 	NULL,                           /* Child terminate */
1078 	STANDARD_SAPI_MODULE_PROPERTIES
1079 };
1080 /* }}} */
1081 
1082 const opt_struct OPTIONS[] = { /* {{{ */
1083 	{'c', 1, "ini path override"},
1084 	{'d', 1, "define ini entry on command line"},
1085 	{'n', 0, "no php.ini"},
1086 	{'z', 1, "load zend_extension"},
1087 	/* phpdbg options */
1088 	{'q', 0, "no banner"},
1089 	{'v', 0, "disable quietness"},
1090 	{'b', 0, "boring colours"},
1091 	{'i', 1, "specify init"},
1092 	{'I', 0, "ignore init"},
1093 	{'O', 1, "opline log"},
1094 	{'r', 0, "run"},
1095 	{'e', 0, "generate ext_stmt opcodes"},
1096 	{'E', 0, "step-through-eval"},
1097 	{'s', 1, "script from stdin"},
1098 	{'S', 1, "sapi-name"},
1099 #ifndef _WIN32
1100 	{'l', 1, "listen"},
1101 	{'a', 1, "address-or-any"},
1102 #endif
1103 	{'x', 0, "xml output"},
1104 	{'p', 2, "show opcodes"},
1105 	{'h', 0, "help"},
1106 	{'V', 0, "version"},
1107 	{'-', 0, NULL}
1108 }; /* }}} */
1109 
1110 const char phpdbg_ini_hardcoded[] =
1111 "html_errors=Off\n"
1112 "register_argc_argv=On\n"
1113 "implicit_flush=On\n"
1114 "display_errors=Off\n"
1115 "log_errors=On\n"
1116 "max_execution_time=0\n"
1117 "max_input_time=-1\n"
1118 "error_log=\n"
1119 "output_buffering=off\n\0";
1120 
1121 /* overwriteable ini defaults must be set in phpdbg_ini_defaults() */
1122 #define INI_DEFAULT(name, value) \
1123 	ZVAL_NEW_STR(&tmp, zend_string_init(value, sizeof(value) - 1, 1)); \
1124 	zend_hash_str_update(configuration_hash, name, sizeof(name) - 1, &tmp);
1125 
phpdbg_ini_defaults(HashTable * configuration_hash)1126 void phpdbg_ini_defaults(HashTable *configuration_hash) /* {{{ */
1127 {
1128 	zval tmp;
1129 	INI_DEFAULT("report_zend_debug", "0");
1130 } /* }}} */
1131 
phpdbg_welcome(zend_bool cleaning)1132 static void phpdbg_welcome(zend_bool cleaning) /* {{{ */
1133 {
1134 	/* print blurb */
1135 	if (!cleaning) {
1136 		phpdbg_xml("<intros>");
1137 		phpdbg_notice("intro", "version=\"%s\"", "Welcome to phpdbg, the interactive PHP debugger, v%s", PHPDBG_VERSION);
1138 		phpdbg_writeln("intro", "help=\"help\"", "To get help using phpdbg type \"help\" and press enter");
1139 		phpdbg_notice("intro", "report=\"%s\"", "Please report bugs to <%s>", PHPDBG_ISSUES);
1140 		phpdbg_xml("</intros>");
1141 	} else if (phpdbg_startup_run == 0) {
1142 		if (!(PHPDBG_G(flags) & PHPDBG_WRITE_XML)) {
1143 			phpdbg_notice(NULL, NULL, "Clean Execution Environment");
1144 		}
1145 
1146 		phpdbg_write("cleaninfo", "classes=\"%d\" functions=\"%d\" constants=\"%d\" includes=\"%d\"",
1147 			"Classes              %d\n"
1148 			"Functions            %d\n"
1149 			"Constants            %d\n"
1150 			"Includes             %d\n",
1151 			zend_hash_num_elements(EG(class_table)),
1152 			zend_hash_num_elements(EG(function_table)),
1153 			zend_hash_num_elements(EG(zend_constants)),
1154 			zend_hash_num_elements(&EG(included_files)));
1155 	}
1156 } /* }}} */
1157 
phpdbg_sigint_handler(int signo)1158 static inline void phpdbg_sigint_handler(int signo) /* {{{ */
1159 {
1160 
1161 	if (PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE) {
1162 		/* we quit remote consoles on recv SIGINT */
1163 		if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) {
1164 			PHPDBG_G(flags) |= PHPDBG_IS_STOPPING;
1165 			zend_bailout();
1166 		}
1167 	} else {
1168 		/* set signalled only when not interactive */
1169 		if (PHPDBG_G(flags) & PHPDBG_IS_SIGNALED) {
1170 			char mem[PHPDBG_SIGSAFE_MEM_SIZE + 1];
1171 
1172 			phpdbg_set_sigsafe_mem(mem);
1173 			zend_try {
1174 				phpdbg_force_interruption();
1175 			} zend_end_try()
1176 			phpdbg_clear_sigsafe_mem();
1177 
1178 			PHPDBG_G(flags) &= ~PHPDBG_IS_SIGNALED;
1179 
1180 			if (PHPDBG_G(flags) & PHPDBG_IS_STOPPING) {
1181 				zend_bailout();
1182 			}
1183 		} else {
1184 			PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED;
1185 			if (PHPDBG_G(flags) & PHPDBG_PREVENT_INTERACTIVE) {
1186 				PHPDBG_G(flags) |= PHPDBG_HAS_PAGINATION;
1187 				PHPDBG_G(flags) &= ~PHPDBG_PREVENT_INTERACTIVE;
1188 			}
1189 		}
1190 	}
1191 } /* }}} */
1192 
phpdbg_remote_close(int socket,FILE * stream)1193 static void phpdbg_remote_close(int socket, FILE *stream) {
1194 	if (socket >= 0) {
1195 		phpdbg_close_socket(socket);
1196 	}
1197 
1198 	if (stream) {
1199 		fclose(stream);
1200 	}
1201 }
1202 
1203 /* 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)1204 static int phpdbg_remote_init(const char* address, unsigned short port, int server, int *socket, FILE **stream) {
1205 	phpdbg_remote_close(*socket, *stream);
1206 
1207 	if (server < 0) {
1208 		phpdbg_rlog(fileno(stderr), "Initializing connection on %s:%u failed", address, port);
1209 
1210 		return FAILURE;
1211 	}
1212 
1213 	phpdbg_rlog(fileno(stderr), "accepting connections on %s:%u", address, port);
1214 	{
1215 		struct sockaddr_storage address;
1216 		socklen_t size = sizeof(address);
1217 		char buffer[20] = {0};
1218 		/* XXX error checks */
1219 		memset(&address, 0, size);
1220 		*socket = accept(server, (struct sockaddr *) &address, &size);
1221 		inet_ntop(AF_INET, &(((struct sockaddr_in *)&address)->sin_addr), buffer, sizeof(buffer));
1222 
1223 		phpdbg_rlog(fileno(stderr), "connection established from %s", buffer);
1224 	}
1225 
1226 #ifndef _WIN32
1227 	dup2(*socket, fileno(stdout));
1228 	dup2(*socket, fileno(stdin));
1229 
1230 	setbuf(stdout, NULL);
1231 
1232 	*stream = fdopen(*socket, "r+");
1233 
1234 	phpdbg_set_async_io(*socket);
1235 #endif
1236 	return SUCCESS;
1237 }
1238 
1239 #ifndef _WIN32
1240 /* This function *strictly* assumes that SIGIO is *only* used on the remote connection stream */
phpdbg_sigio_handler(int sig,siginfo_t * info,void * context)1241 void phpdbg_sigio_handler(int sig, siginfo_t *info, void *context) /* {{{ */
1242 {
1243 	int flags;
1244 	size_t newlen;
1245 	size_t i/*, last_nl*/;
1246 
1247 //	if (!(info->si_band & POLLIN)) {
1248 //		return; /* Not interested in writeablility etc., just interested in incoming data */
1249 //	}
1250 
1251 	/* only non-blocking reading, avoid non-blocking writing */
1252 	flags = fcntl(PHPDBG_G(io)[PHPDBG_STDIN].fd, F_GETFL, 0);
1253 	fcntl(PHPDBG_G(io)[PHPDBG_STDIN].fd, F_SETFL, flags | O_NONBLOCK);
1254 
1255 	do {
1256 		char mem[PHPDBG_SIGSAFE_MEM_SIZE + 1];
1257 		size_t off = 0;
1258 
1259 		if ((newlen = recv(PHPDBG_G(io)[PHPDBG_STDIN].fd, mem, PHPDBG_SIGSAFE_MEM_SIZE, MSG_PEEK)) == (size_t) -1) {
1260 			break;
1261 		}
1262 		for (i = 0; i < newlen; i++) {
1263 			switch (mem[off + i]) {
1264 				case '\x03': /* ^C char */
1265 					if (PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE) {
1266 						break; /* or quit ??? */
1267 					}
1268 					if (PHPDBG_G(flags) & PHPDBG_IS_SIGNALED) {
1269 						phpdbg_set_sigsafe_mem(mem);
1270 						zend_try {
1271 							phpdbg_force_interruption();
1272 						} zend_end_try();
1273 						phpdbg_clear_sigsafe_mem();
1274 
1275 						PHPDBG_G(flags) &= ~PHPDBG_IS_SIGNALED;
1276 
1277 						if (PHPDBG_G(flags) & PHPDBG_IS_STOPPING) {
1278 							zend_bailout();
1279 						}
1280 					} else if (!(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) {
1281 						PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED;
1282 					}
1283 					break;
1284 /*				case '\n':
1285 					zend_llist_add_element(PHPDBG_G(stdin), strndup()
1286 					last_nl = PHPDBG_G(stdin_buf).len + i;
1287 					break;
1288 */			}
1289 		}
1290 		off += i;
1291 	} while (0);
1292 
1293 
1294 	fcntl(PHPDBG_G(io)[PHPDBG_STDIN].fd, F_SETFL, flags);
1295 } /* }}} */
1296 
phpdbg_signal_handler(int sig,siginfo_t * info,void * context)1297 void phpdbg_signal_handler(int sig, siginfo_t *info, void *context) /* {{{ */
1298 {
1299 	int is_handled = FAILURE;
1300 
1301 	switch (sig) {
1302 		case SIGBUS:
1303 		case SIGSEGV:
1304 			is_handled = phpdbg_watchpoint_segfault_handler(info, context);
1305 			if (is_handled == FAILURE) {
1306 				if (PHPDBG_G(sigsegv_bailout)) {
1307 					LONGJMP(*PHPDBG_G(sigsegv_bailout), FAILURE);
1308 				}
1309 				zend_sigaction(sig, &PHPDBG_G(old_sigsegv_signal), NULL);
1310 			}
1311 			break;
1312 	}
1313 
1314 } /* }}} */
1315 #endif
1316 
phpdbg_sighup_handler(int sig)1317 void phpdbg_sighup_handler(int sig) /* {{{ */
1318 {
1319 	exit(0);
1320 } /* }}} */
1321 
phpdbg_malloc_wrapper(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)1322 void *phpdbg_malloc_wrapper(size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) /* {{{ */
1323 {
1324 	return _zend_mm_alloc(zend_mm_get_heap(), size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
1325 } /* }}} */
1326 
phpdbg_free_wrapper(void * p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)1327 void phpdbg_free_wrapper(void *p ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) /* {{{ */
1328 {
1329 	zend_mm_heap *heap = zend_mm_get_heap();
1330 	if (UNEXPECTED(heap == p)) {
1331 		/* TODO: heap maybe allocated by mmap(zend_mm_init) or malloc(USE_ZEND_ALLOC=0)
1332 		 * let's prevent it from segfault for now
1333 		 */
1334 	} else {
1335 		phpdbg_watch_efree(p);
1336 		_zend_mm_free(heap, p ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
1337 	}
1338 } /* }}} */
1339 
phpdbg_realloc_wrapper(void * ptr,size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)1340 void *phpdbg_realloc_wrapper(void *ptr, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) /* {{{ */
1341 {
1342 	return _zend_mm_realloc(zend_mm_get_heap(), ptr, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
1343 } /* }}} */
1344 
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)1345 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) /* {{{ */
1346 {
1347 	if (!strncasecmp(path, "php://", 6)) {
1348 		path += 6;
1349 	}
1350 
1351 	if (!strncasecmp(path, "stdin", 6) && PHPDBG_G(stdin_file)) {
1352 		php_stream *stream = php_stream_fopen_from_fd(dup(fileno(PHPDBG_G(stdin_file))), "r", NULL);
1353 #ifdef PHP_WIN32
1354 		zval *blocking_pipes = php_stream_context_get_option(context, "pipe", "blocking");
1355 		if (blocking_pipes) {
1356 			convert_to_long(blocking_pipes);
1357 			php_stream_set_option(stream, PHP_STREAM_OPTION_PIPE_BLOCKING, Z_LVAL_P(blocking_pipes), NULL);
1358 		}
1359 #endif
1360 		return stream;
1361 	}
1362 
1363 	return PHPDBG_G(orig_url_wrap_php)(wrapper, path, mode, options, opened_path, context STREAMS_CC);
1364 } /* }}} */
1365 
main(int argc,char ** argv)1366 int main(int argc, char **argv) /* {{{ */
1367 {
1368 	sapi_module_struct *phpdbg = &phpdbg_sapi_module;
1369 	char *sapi_name;
1370 	char *ini_entries;
1371 	int   ini_entries_len;
1372 	char **zend_extensions = NULL;
1373 	zend_ulong zend_extensions_len = 0L;
1374 	zend_bool ini_ignore;
1375 	char *ini_override;
1376 	char *exec = NULL;
1377 	char *first_command = NULL;
1378 	char *init_file;
1379 	size_t init_file_len;
1380 	zend_bool init_file_default;
1381 	char *oplog_file;
1382 	size_t oplog_file_len;
1383 	uint64_t flags;
1384 	char *php_optarg;
1385 	int php_optind, opt, show_banner = 1;
1386 	long cleaning = -1;
1387 	volatile zend_bool quit_immediately = 0; /* somehow some gcc release builds will play a bit around with order in combination with setjmp..., hence volatile */
1388 	zend_bool remote = 0;
1389 	zend_phpdbg_globals *settings = NULL;
1390 	char *bp_tmp = NULL;
1391 	char *address;
1392 	int listen = -1;
1393 	int server = -1;
1394 	int socket = -1;
1395 	FILE* stream = NULL;
1396 	char *print_opline_func;
1397 	zend_bool ext_stmt = 0;
1398 	zend_bool is_exit;
1399 	int exit_status;
1400 	char *read_from_stdin = NULL;
1401 	zend_string *backup_phpdbg_compile = NULL;
1402 	zend_bool show_help = 0, show_version = 0;
1403 	void* (*_malloc)(size_t);
1404 	void (*_free)(void*);
1405 	void* (*_realloc)(void*, size_t);
1406 
1407 
1408 #ifndef _WIN32
1409 	struct sigaction sigio_struct;
1410 	struct sigaction signal_struct;
1411 	signal_struct.sa_sigaction = phpdbg_signal_handler;
1412 	signal_struct.sa_flags = SA_SIGINFO | SA_NODEFER;
1413 	sigemptyset(&signal_struct.sa_mask);
1414 	sigio_struct.sa_sigaction = phpdbg_sigio_handler;
1415 	sigio_struct.sa_flags = SA_SIGINFO;
1416 	sigemptyset(&sigio_struct.sa_mask);
1417 
1418 	address = strdup("127.0.0.1");
1419 #endif
1420 
1421 #ifdef PHP_WIN32
1422 	_fmode = _O_BINARY;                 /* sets default for file streams to binary */
1423 	setmode(_fileno(stdin), O_BINARY);  /* make the stdio mode be binary */
1424 	setmode(_fileno(stdout), O_BINARY); /* make the stdio mode be binary */
1425 	setmode(_fileno(stderr), O_BINARY); /* make the stdio mode be binary */
1426 #endif
1427 
1428 phpdbg_main:
1429 #ifdef ZTS
1430 	tsrm_startup(1, 1, 0, NULL);
1431 	(void)ts_resource(0);
1432 	ZEND_TSRMLS_CACHE_UPDATE();
1433 #endif
1434 
1435 	zend_signal_startup();
1436 
1437 	ini_entries = NULL;
1438 	ini_entries_len = 0;
1439 	ini_ignore = 0;
1440 	ini_override = NULL;
1441 	zend_extensions = NULL;
1442 	zend_extensions_len = 0L;
1443 	init_file = NULL;
1444 	init_file_len = 0;
1445 	init_file_default = 1;
1446 	oplog_file = NULL;
1447 	oplog_file_len = 0;
1448 	flags = PHPDBG_DEFAULT_FLAGS;
1449 	is_exit = 0;
1450 	php_optarg = NULL;
1451 	php_optind = 1;
1452 	opt = 0;
1453 	sapi_name = NULL;
1454 	exit_status = 0;
1455 	if (settings) {
1456 		exec = settings->exec;
1457 	}
1458 
1459 	while ((opt = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) {
1460 		switch (opt) {
1461 			case 'r':
1462 				if (settings == NULL) {
1463 					phpdbg_startup_run++;
1464 				}
1465 				break;
1466 			case 'n':
1467 				ini_ignore = 1;
1468 				break;
1469 			case 'c':
1470 				if (ini_override) {
1471 					free(ini_override);
1472 				}
1473 				ini_override = strdup(php_optarg);
1474 				break;
1475 			case 'd': {
1476 				int len = strlen(php_optarg);
1477 				char *val;
1478 
1479 				if ((val = strchr(php_optarg, '='))) {
1480 				  val++;
1481 				  if (!isalnum(*val) && *val != '"' && *val != '\'' && *val != '\0') {
1482 					  ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("\"\"\n\0"));
1483 					  memcpy(ini_entries + ini_entries_len, php_optarg, (val - php_optarg));
1484 					  ini_entries_len += (val - php_optarg);
1485 					  memcpy(ini_entries + ini_entries_len, "\"", 1);
1486 					  ini_entries_len++;
1487 					  memcpy(ini_entries + ini_entries_len, val, len - (val - php_optarg));
1488 					  ini_entries_len += len - (val - php_optarg);
1489 					  memcpy(ini_entries + ini_entries_len, "\"\n\0", sizeof("\"\n\0"));
1490 					  ini_entries_len += sizeof("\n\0\"") - 2;
1491 				  } else {
1492 					  ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("\n\0"));
1493 					  memcpy(ini_entries + ini_entries_len, php_optarg, len);
1494 					  memcpy(ini_entries + ini_entries_len + len, "\n\0", sizeof("\n\0"));
1495 					  ini_entries_len += len + sizeof("\n\0") - 2;
1496 				  }
1497 				} else {
1498 				  ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("=1\n\0"));
1499 				  memcpy(ini_entries + ini_entries_len, php_optarg, len);
1500 				  memcpy(ini_entries + ini_entries_len + len, "=1\n\0", sizeof("=1\n\0"));
1501 				  ini_entries_len += len + sizeof("=1\n\0") - 2;
1502 				}
1503 			} break;
1504 
1505 			case 'z':
1506 				zend_extensions_len++;
1507 				if (zend_extensions) {
1508 					zend_extensions = realloc(zend_extensions, sizeof(char*) * zend_extensions_len);
1509 				} else zend_extensions = malloc(sizeof(char*) * zend_extensions_len);
1510 				zend_extensions[zend_extensions_len-1] = strdup(php_optarg);
1511 			break;
1512 
1513 			/* begin phpdbg options */
1514 
1515 			case 's': { /* read script from stdin */
1516 				if (settings == NULL) {
1517 					read_from_stdin = strdup(php_optarg);
1518 				}
1519 			} break;
1520 
1521 			case 'S': { /* set SAPI name */
1522 				sapi_name = strdup(php_optarg);
1523 			} break;
1524 
1525 			case 'I': { /* ignore .phpdbginit */
1526 				init_file_default = 0;
1527 			} break;
1528 
1529 			case 'i': { /* set init file */
1530 				if (init_file) {
1531 					free(init_file);
1532 					init_file = NULL;
1533 				}
1534 
1535 				init_file_len = strlen(php_optarg);
1536 				if (init_file_len) {
1537 					init_file = strdup(php_optarg);
1538 				}
1539 			} break;
1540 
1541 			case 'O': { /* set oplog output */
1542 				oplog_file_len = strlen(php_optarg);
1543 				if (oplog_file_len) {
1544 					oplog_file = strdup(php_optarg);
1545 				}
1546 			} break;
1547 
1548 			case 'v': /* set quietness off */
1549 				flags &= ~PHPDBG_IS_QUIET;
1550 			break;
1551 
1552 			case 'e':
1553 				ext_stmt = 1;
1554 			break;
1555 
1556 			case 'E': /* stepping through eval on */
1557 				flags |= PHPDBG_IS_STEPONEVAL;
1558 			break;
1559 
1560 			case 'b': /* set colours off */
1561 				flags &= ~PHPDBG_IS_COLOURED;
1562 			break;
1563 
1564 			case 'q': /* hide banner */
1565 				show_banner = 0;
1566 			break;
1567 
1568 #ifndef _WIN32
1569 			/* if you pass a listen port, we will read and write on listen port */
1570 			case 'l': /* set listen ports */
1571 				if (sscanf(php_optarg, "%d", &listen) != 1) {
1572 					listen = 8000;
1573 				}
1574 			break;
1575 
1576 			case 'a': { /* set bind address */
1577 				free(address);
1578 				if (!php_optarg) {
1579 					address = strdup("*");
1580 				} else address = strdup(php_optarg);
1581 			} break;
1582 #endif
1583 
1584 			case 'x':
1585 				flags |= PHPDBG_WRITE_XML;
1586 			break;
1587 
1588 
1589 			case 'p': {
1590 				print_opline_func = php_optarg;
1591 				show_banner = 0;
1592 				settings = (void *) 0x1;
1593 			} break;
1594 
1595 			case 'h': {
1596 				show_help = 1;
1597 			} break;
1598 
1599 			case 'V': {
1600 				show_version = 1;
1601 			} break;
1602 		}
1603 
1604 		php_optarg = NULL;
1605 	}
1606 
1607 	quit_immediately = phpdbg_startup_run > 1;
1608 
1609 	/* set exec if present on command line */
1610 	if (!read_from_stdin && argc > php_optind) {
1611 		if (!exec && strlen(argv[php_optind])) {
1612 			exec = strdup(argv[php_optind]);
1613 		}
1614 		php_optind++;
1615 	}
1616 
1617 	if (sapi_name) {
1618 		phpdbg->name = sapi_name;
1619 	}
1620 
1621 	phpdbg->ini_defaults = phpdbg_ini_defaults;
1622 	phpdbg->phpinfo_as_text = 1;
1623 	phpdbg->php_ini_ignore_cwd = 1;
1624 
1625 	sapi_startup(phpdbg);
1626 
1627 	phpdbg->executable_location = argv[0];
1628 	phpdbg->phpinfo_as_text = 1;
1629 	phpdbg->php_ini_ignore = ini_ignore;
1630 	phpdbg->php_ini_path_override = ini_override;
1631 
1632 	if (ini_entries) {
1633 		ini_entries = realloc(ini_entries, ini_entries_len + sizeof(phpdbg_ini_hardcoded));
1634 		memmove(ini_entries + sizeof(phpdbg_ini_hardcoded) - 2, ini_entries, ini_entries_len + 1);
1635 		memcpy(ini_entries, phpdbg_ini_hardcoded, sizeof(phpdbg_ini_hardcoded) - 2);
1636 	} else {
1637 		ini_entries = malloc(sizeof(phpdbg_ini_hardcoded));
1638 		memcpy(ini_entries, phpdbg_ini_hardcoded, sizeof(phpdbg_ini_hardcoded));
1639 	}
1640 	ini_entries_len += sizeof(phpdbg_ini_hardcoded) - 2;
1641 
1642 	if (zend_extensions_len) {
1643 		zend_ulong zend_extension = 0L;
1644 
1645 		while (zend_extension < zend_extensions_len) {
1646 			const char *ze = zend_extensions[zend_extension];
1647 			size_t ze_len = strlen(ze);
1648 
1649 			ini_entries = realloc(
1650 				ini_entries, ini_entries_len + (ze_len + (sizeof("zend_extension=\n"))));
1651 			memcpy(&ini_entries[ini_entries_len], "zend_extension=", (sizeof("zend_extension=\n")-1));
1652 			ini_entries_len += (sizeof("zend_extension=")-1);
1653 			memcpy(&ini_entries[ini_entries_len], ze, ze_len);
1654 			ini_entries_len += ze_len;
1655 			memcpy(&ini_entries[ini_entries_len], "\n", (sizeof("\n") - 1));
1656 
1657 			free(zend_extensions[zend_extension]);
1658 			zend_extension++;
1659 		}
1660 
1661 		free(zend_extensions);
1662 	}
1663 
1664 	phpdbg->ini_entries = ini_entries;
1665 
1666 	ZEND_INIT_MODULE_GLOBALS(phpdbg, php_phpdbg_globals_ctor, NULL);
1667 
1668 	/* set default colors */
1669 	phpdbg_set_color_ex(PHPDBG_COLOR_PROMPT,  PHPDBG_STRL("white-bold"));
1670 	phpdbg_set_color_ex(PHPDBG_COLOR_ERROR,   PHPDBG_STRL("red-bold"));
1671 	phpdbg_set_color_ex(PHPDBG_COLOR_NOTICE,  PHPDBG_STRL("green"));
1672 
1673 	/* set default prompt */
1674 	phpdbg_set_prompt(PHPDBG_DEFAULT_PROMPT);
1675 
1676 	if (settings > (zend_phpdbg_globals *) 0x2) {
1677 #ifdef ZTS
1678 		*((zend_phpdbg_globals *) (*((void ***) TSRMLS_CACHE))[TSRM_UNSHUFFLE_RSRC_ID(phpdbg_globals_id)]) = *settings;
1679 #else
1680 		phpdbg_globals = *settings;
1681 #endif
1682 		free(settings);
1683 	}
1684 
1685 	/* set flags from command line */
1686 	PHPDBG_G(flags) = flags;
1687 
1688 	if (phpdbg->startup(phpdbg) == SUCCESS) {
1689 		zend_mm_heap *mm_heap;
1690 #ifdef _WIN32
1691     EXCEPTION_POINTERS *xp;
1692     __try {
1693 #endif
1694 
1695 		if (show_version || show_help) {
1696 			/* It ain't gonna proceed to real execution anyway,
1697 				but the correct descriptor is needed already. */
1698 			PHPDBG_G(io)[PHPDBG_STDOUT].ptr = stdout;
1699 			PHPDBG_G(io)[PHPDBG_STDOUT].fd = fileno(stdout);
1700 			if (show_help) {
1701 				phpdbg_do_help_cmd(exec);
1702 			} else if (show_version) {
1703 				phpdbg_out(
1704 					"phpdbg %s (built: %s %s)\nPHP %s, Copyright (c) 1997-2018 The PHP Group\n%s",
1705 					PHPDBG_VERSION,
1706 					__DATE__,
1707 					__TIME__,
1708 					PHP_VERSION,
1709 					get_zend_version()
1710 				);
1711 			}
1712 			sapi_deactivate();
1713 			sapi_shutdown();
1714 			if (ini_entries) {
1715 				free(ini_entries);
1716 			}
1717 			if (ini_override) {
1718 				free(ini_override);
1719 			}
1720 			if (exec) {
1721 				free(exec);
1722 			}
1723 			if (oplog_file) {
1724 				free(oplog_file);
1725 			}
1726 			if (init_file) {
1727 				free(init_file);
1728 			}
1729 			goto free_and_return;
1730 		}
1731 
1732 		zend_try {
1733 			zend_signal_activate();
1734 		} zend_end_try();
1735 
1736 		/* setup remote server if necessary */
1737 		if (cleaning <= 0 && listen > 0) {
1738 			server = phpdbg_open_socket(address, listen);
1739 			if (-1 > server || phpdbg_remote_init(address, listen, server, &socket, &stream) == FAILURE) {
1740 				exit(0);
1741 			}
1742 
1743 #ifndef _WIN32
1744 			zend_sigaction(SIGIO, &sigio_struct, NULL);
1745 #endif
1746 
1747 			/* set remote flag to stop service shutting down upon quit */
1748 			remote = 1;
1749 #ifndef _WIN32
1750 		} else {
1751 
1752 			zend_signal(SIGHUP, phpdbg_sighup_handler);
1753 #endif
1754 		}
1755 
1756 		mm_heap = zend_mm_get_heap();
1757 		zend_mm_get_custom_handlers(mm_heap, &_malloc, &_free, &_realloc);
1758 
1759 		use_mm_wrappers = !_malloc && !_realloc && !_free;
1760 
1761 		PHPDBG_G(original_free_function) = _free;
1762 		_free = phpdbg_watch_efree;
1763 
1764 		if (use_mm_wrappers) {
1765 #if ZEND_DEBUG
1766 			zend_mm_set_custom_debug_handlers(mm_heap, phpdbg_malloc_wrapper, phpdbg_free_wrapper, phpdbg_realloc_wrapper);
1767 #else
1768 			zend_mm_set_custom_handlers(mm_heap, phpdbg_malloc_wrapper, phpdbg_free_wrapper, phpdbg_realloc_wrapper);
1769 #endif
1770 		} else {
1771 			zend_mm_set_custom_handlers(mm_heap, _malloc, _free, _realloc);
1772 		}
1773 
1774 		_free = PHPDBG_G(original_free_function);
1775 
1776 
1777 		phpdbg_init_list();
1778 
1779 		PHPDBG_G(sapi_name_ptr) = sapi_name;
1780 
1781 		if (exec) { /* set execution context */
1782 			PHPDBG_G(exec) = phpdbg_resolve_path(exec);
1783 			PHPDBG_G(exec_len) = PHPDBG_G(exec) ? strlen(PHPDBG_G(exec)) : 0;
1784 
1785 			free(exec);
1786 			exec = NULL;
1787 		}
1788 
1789 		php_output_activate();
1790 		php_output_deactivate();
1791 
1792 		if (SG(sapi_headers).mimetype) {
1793 			efree(SG(sapi_headers).mimetype);
1794 			SG(sapi_headers).mimetype = NULL;
1795 		}
1796 
1797 		php_output_activate();
1798 
1799 		{
1800 			int i;
1801 
1802 			SG(request_info).argc = argc - php_optind + 1;
1803 			SG(request_info).argv = emalloc(SG(request_info).argc * sizeof(char *));
1804 			for (i = SG(request_info).argc; --i;) {
1805 				SG(request_info).argv[i] = estrdup(argv[php_optind - 1 + i]);
1806 			}
1807 			SG(request_info).argv[0] = PHPDBG_G(exec) ? estrdup(PHPDBG_G(exec)) : estrdup("");
1808 		}
1809 
1810 		if (php_request_startup() == FAILURE) {
1811 			PUTS("Could not startup");
1812 #ifndef _WIN32
1813 			if (address) {
1814 				free(address);
1815 			}
1816 #endif
1817 			return 1;
1818 		}
1819 
1820 #ifndef _WIN32
1821 		zend_try { zend_sigaction(SIGSEGV, &signal_struct, &PHPDBG_G(old_sigsegv_signal)); } zend_end_try();
1822 		zend_try { zend_sigaction(SIGBUS, &signal_struct, &PHPDBG_G(old_sigsegv_signal)); } zend_end_try();
1823 #endif
1824 
1825 		/* do not install sigint handlers for remote consoles */
1826 		/* sending SIGINT then provides a decent way of shutting down the server */
1827 #ifndef _WIN32
1828 		if (listen < 0) {
1829 #endif
1830 			zend_try { zend_signal(SIGINT, phpdbg_sigint_handler); } zend_end_try();
1831 #ifndef _WIN32
1832 		}
1833 
1834 		/* setup io here */
1835 		if (remote) {
1836 			PHPDBG_G(flags) |= PHPDBG_IS_REMOTE;
1837 			zend_signal(SIGPIPE, SIG_IGN);
1838 		}
1839 		PHPDBG_G(io)[PHPDBG_STDIN].ptr = stdin;
1840 		PHPDBG_G(io)[PHPDBG_STDIN].fd = fileno(stdin);
1841 		PHPDBG_G(io)[PHPDBG_STDOUT].ptr = stdout;
1842 		PHPDBG_G(io)[PHPDBG_STDOUT].fd = fileno(stdout);
1843 #else
1844 		/* XXX this is a complete mess here with FILE/fd/SOCKET,
1845 			we should let only one to survive probably. Need
1846 			a clean separation whether it's a remote or local
1847 			prompt. And what is supposed to go as user interaction,
1848 			error log, etc. */
1849 		if (remote) {
1850 			PHPDBG_G(io)[PHPDBG_STDIN].ptr = stdin;
1851 			PHPDBG_G(io)[PHPDBG_STDIN].fd = socket;
1852 			PHPDBG_G(io)[PHPDBG_STDOUT].ptr = stdout;
1853 			PHPDBG_G(io)[PHPDBG_STDOUT].fd = socket;
1854 		} else {
1855 			PHPDBG_G(io)[PHPDBG_STDIN].ptr = stdin;
1856 			PHPDBG_G(io)[PHPDBG_STDIN].fd = fileno(stdin);
1857 			PHPDBG_G(io)[PHPDBG_STDOUT].ptr = stdout;
1858 			PHPDBG_G(io)[PHPDBG_STDOUT].fd = fileno(stdout);
1859 		}
1860 #endif
1861 		PHPDBG_G(io)[PHPDBG_STDERR].ptr = stderr;
1862 		PHPDBG_G(io)[PHPDBG_STDERR].fd = fileno(stderr);
1863 
1864 #ifndef _WIN32
1865 		PHPDBG_G(php_stdiop_write) = php_stream_stdio_ops.write;
1866 		php_stream_stdio_ops.write = phpdbg_stdiop_write;
1867 #endif
1868 
1869 		if (oplog_file) { /* open oplog */
1870 			PHPDBG_G(oplog) = fopen(oplog_file, "w+");
1871 			if (!PHPDBG_G(oplog)) {
1872 				phpdbg_error("oplog", "path=\"%s\"", "Failed to open oplog %s", oplog_file);
1873 			}
1874 			free(oplog_file);
1875 			oplog_file = NULL;
1876 		}
1877 
1878 		{
1879 			php_stream_wrapper *wrapper = zend_hash_str_find_ptr(php_stream_get_url_stream_wrappers_hash(), ZEND_STRL("php"));
1880 			PHPDBG_G(orig_url_wrap_php) = wrapper->wops->stream_opener;
1881 			wrapper->wops->stream_opener = phpdbg_stream_url_wrap_php;
1882 		}
1883 
1884 		/* Make stdin, stdout and stderr accessible from PHP scripts */
1885 		phpdbg_register_file_handles();
1886 
1887 		phpdbg_list_update();
1888 
1889 		if (show_banner && cleaning < 2) {
1890 			/* print blurb */
1891 			phpdbg_welcome(cleaning == 1);
1892 		}
1893 
1894 		cleaning = -1;
1895 
1896 		if (ext_stmt) {
1897 			CG(compiler_options) |= ZEND_COMPILE_EXTENDED_INFO;
1898 		}
1899 
1900 		/* initialize from file */
1901 		PHPDBG_G(flags) |= PHPDBG_IS_INITIALIZING;
1902 		zend_try {
1903 			phpdbg_init(init_file, init_file_len, init_file_default);
1904 		} zend_end_try();
1905 		PHPDBG_G(flags) &= ~PHPDBG_IS_INITIALIZING;
1906 
1907 		/* quit if init says so */
1908 		if (PHPDBG_G(flags) & PHPDBG_IS_QUITTING) {
1909 			goto phpdbg_out;
1910 		}
1911 
1912 		/* auto compile */
1913 		if (read_from_stdin) {
1914 			if (!read_from_stdin[0]) {
1915 				if (!quit_immediately) {
1916 					phpdbg_error("error", "", "Impossible to not specify a stdin delimiter without -rr");
1917 					PHPDBG_G(flags) |= PHPDBG_IS_QUITTING;
1918 					goto phpdbg_out;
1919 				}
1920 			}
1921 			if (show_banner || read_from_stdin[0]) {
1922 				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);
1923 			}
1924 
1925 			if (phpdbg_startup_run > 0) {
1926 				PHPDBG_G(flags) |= PHPDBG_DISCARD_OUTPUT;
1927 			}
1928 
1929 			zend_try {
1930 				phpdbg_param_t cmd;
1931 				cmd.str = read_from_stdin;
1932 				cmd.len = strlen(read_from_stdin);
1933 				PHPDBG_COMMAND_HANDLER(stdin)(&cmd);
1934 			} zend_end_try();
1935 
1936 			PHPDBG_G(flags) &= ~PHPDBG_DISCARD_OUTPUT;
1937 		} else if (PHPDBG_G(exec)) {
1938 			if (settings || phpdbg_startup_run > 0) {
1939 				PHPDBG_G(flags) |= PHPDBG_DISCARD_OUTPUT;
1940 			}
1941 
1942 			zend_try {
1943 				if (backup_phpdbg_compile) {
1944 					phpdbg_compile_stdin(backup_phpdbg_compile);
1945 				} else {
1946 					phpdbg_compile();
1947 				}
1948 			} zend_end_try();
1949 			backup_phpdbg_compile = NULL;
1950 
1951 			PHPDBG_G(flags) &= ~PHPDBG_DISCARD_OUTPUT;
1952 		}
1953 
1954 		if (bp_tmp) {
1955 			PHPDBG_G(flags) |= PHPDBG_DISCARD_OUTPUT | PHPDBG_IS_INITIALIZING;
1956 			phpdbg_string_init(bp_tmp);
1957 			free(bp_tmp);
1958 			bp_tmp = NULL;
1959 			PHPDBG_G(flags) &= ~PHPDBG_DISCARD_OUTPUT & ~PHPDBG_IS_INITIALIZING;
1960 		}
1961 
1962 		if (settings == (void *) 0x1) {
1963 			if (PHPDBG_G(ops)) {
1964 				phpdbg_print_opcodes(print_opline_func);
1965 			} else {
1966 				zend_quiet_write(PHPDBG_G(io)[PHPDBG_STDERR].fd, ZEND_STRL("No opcodes could be compiled | No file specified or compilation failed?\n"));
1967 			}
1968 			goto phpdbg_out;
1969 		}
1970 
1971 		PG(during_request_startup) = 0;
1972 
1973 		phpdbg_fully_started = 1;
1974 
1975 /* #ifndef for making compiler shutting up */
1976 #ifndef _WIN32
1977 phpdbg_interact:
1978 #endif
1979 		/* phpdbg main() */
1980 		do {
1981 			zend_try {
1982 				if (phpdbg_startup_run) {
1983 					phpdbg_startup_run = 0;
1984 					if (quit_immediately) {
1985 						PHPDBG_G(flags) = (PHPDBG_G(flags) & ~PHPDBG_HAS_PAGINATION) | PHPDBG_IS_INTERACTIVE | PHPDBG_PREVENT_INTERACTIVE;
1986 					} else {
1987 						PHPDBG_G(flags) |= PHPDBG_IS_INTERACTIVE;
1988 					}
1989 					zend_try {
1990 						if (first_command) {
1991 							phpdbg_interactive(1, estrdup(first_command));
1992 						} else {
1993 							PHPDBG_COMMAND_HANDLER(run)(NULL);
1994 						}
1995 					} zend_end_try();
1996 					if (quit_immediately) {
1997 						/* if -r is on the command line more than once just quit */
1998 						EG(bailout) = __orig_bailout; /* reset zend_try */
1999 						exit_status = EG(exit_status);
2000 						break;
2001 					}
2002 				}
2003 
2004 				CG(unclean_shutdown) = 0;
2005 				phpdbg_interactive(1, NULL);
2006 			} zend_catch {
2007 				if ((PHPDBG_G(flags) & PHPDBG_IS_CLEANING)) {
2008 					char *bp_tmp_str;
2009 					PHPDBG_G(flags) |= PHPDBG_DISCARD_OUTPUT;
2010 					phpdbg_export_breakpoints_to_string(&bp_tmp_str);
2011 					PHPDBG_G(flags) &= ~PHPDBG_DISCARD_OUTPUT;
2012 					if (bp_tmp_str) {
2013 						bp_tmp = strdup(bp_tmp_str);
2014 						efree(bp_tmp_str);
2015 					}
2016 					cleaning = 1;
2017 				} else {
2018 					cleaning = 0;
2019 				}
2020 
2021 #ifndef _WIN32
2022 				if (!cleaning) {
2023 					/* remote client disconnected */
2024 					if ((PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED)) {
2025 
2026 						if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) {
2027 							/* renegociate connections */
2028 							phpdbg_remote_init(address, listen, server, &socket, &stream);
2029 
2030 							/* set streams */
2031 							if (stream) {
2032 								PHPDBG_G(flags) &= ~PHPDBG_IS_QUITTING;
2033 							}
2034 
2035 							/* this must be forced */
2036 							CG(unclean_shutdown) = 0;
2037 						} else {
2038 							/* local consoles cannot disconnect, ignore EOF */
2039 							PHPDBG_G(flags) &= ~PHPDBG_IS_DISCONNECTED;
2040 						}
2041 					}
2042 				}
2043 #endif
2044 			} zend_end_try();
2045 		} while (!(PHPDBG_G(flags) & PHPDBG_IS_STOPPING));
2046 
2047 
2048 #ifndef _WIN32
2049 phpdbg_out:
2050 		if ((PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED)) {
2051 			PHPDBG_G(flags) &= ~PHPDBG_IS_DISCONNECTED;
2052 			goto phpdbg_interact;
2053 		}
2054 #endif
2055 
2056 #ifdef _WIN32
2057 	} __except(phpdbg_exception_handler_win32(xp = GetExceptionInformation())) {
2058 		phpdbg_error("segfault", "", "Access violation (Segmentation fault) encountered\ntrying to abort cleanly...");
2059 	}
2060 phpdbg_out:
2061 #endif
2062 
2063 		if (first_command) {
2064 			free(first_command);
2065 			first_command = NULL;
2066 		}
2067 
2068 		if (cleaning <= 0) {
2069 			PHPDBG_G(flags) &= ~PHPDBG_IS_CLEANING;
2070 			cleaning = -1;
2071 		}
2072 
2073 		{
2074 			int i;
2075 			/* free argv */
2076 			for (i = SG(request_info).argc; i--;) {
2077 				efree(SG(request_info).argv[i]);
2078 			}
2079 			efree(SG(request_info).argv);
2080 		}
2081 
2082 		if (ini_entries) {
2083 			free(ini_entries);
2084 		}
2085 
2086 		if (ini_override) {
2087 			free(ini_override);
2088 		}
2089 
2090 		/* In case we aborted during script execution, we may not reset CG(unclean_shutdown) */
2091 		if (!(PHPDBG_G(flags) & PHPDBG_IS_RUNNING)) {
2092 			is_exit = !PHPDBG_G(in_execution);
2093 			CG(unclean_shutdown) = is_exit || PHPDBG_G(unclean_eval);
2094 		}
2095 
2096 		if ((PHPDBG_G(flags) & (PHPDBG_IS_CLEANING | PHPDBG_IS_RUNNING)) == PHPDBG_IS_CLEANING) {
2097 			php_free_shutdown_functions();
2098 			zend_objects_store_mark_destructed(&EG(objects_store));
2099 		}
2100 
2101 		zend_try {
2102 			php_request_shutdown(NULL);
2103 		} zend_end_try();
2104 
2105 		if (PHPDBG_G(exec) && !memcmp("-", PHPDBG_G(exec), 2)) { /* i.e. execution context has been read from stdin - back it up */
2106 			phpdbg_file_source *data = zend_hash_str_find_ptr(&PHPDBG_G(file_sources), PHPDBG_G(exec), PHPDBG_G(exec_len));
2107 			backup_phpdbg_compile = zend_string_alloc(data->len + 2, 1);
2108 			sprintf(ZSTR_VAL(backup_phpdbg_compile), "?>%.*s", (int) data->len, data->buf);
2109 		}
2110 
2111 		/* backup globals when cleaning */
2112 		if ((cleaning > 0 || remote) && !quit_immediately) {
2113 			settings = calloc(1, sizeof(zend_phpdbg_globals));
2114 
2115 			php_phpdbg_globals_ctor(settings);
2116 
2117 			if (PHPDBG_G(exec)) {
2118 				settings->exec = zend_strndup(PHPDBG_G(exec), PHPDBG_G(exec_len));
2119 				settings->exec_len = PHPDBG_G(exec_len);
2120 			}
2121 			settings->oplog = PHPDBG_G(oplog);
2122 			settings->prompt[0] = PHPDBG_G(prompt)[0];
2123 			settings->prompt[1] = PHPDBG_G(prompt)[1];
2124 			memcpy(settings->colors, PHPDBG_G(colors), sizeof(settings->colors));
2125 			settings->eol = PHPDBG_G(eol);
2126 			settings->input_buflen = PHPDBG_G(input_buflen);
2127 			memcpy(settings->input_buffer, PHPDBG_G(input_buffer), settings->input_buflen);
2128 			settings->flags = PHPDBG_G(flags) & PHPDBG_PRESERVE_FLAGS_MASK;
2129 			first_command = PHPDBG_G(cur_command);
2130 		} else {
2131 			if (PHPDBG_G(prompt)[0]) {
2132 				free(PHPDBG_G(prompt)[0]);
2133 			}
2134 			if (PHPDBG_G(prompt)[1]) {
2135 				free(PHPDBG_G(prompt)[1]);
2136 			}
2137 			if (PHPDBG_G(cur_command)) {
2138 				free(PHPDBG_G(cur_command));
2139 			}
2140 		}
2141 
2142 		if (exit_status == 0) {
2143 			exit_status = EG(exit_status);
2144 		}
2145 
2146 		php_output_deactivate();
2147 
2148 		if (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING)) {
2149 			PHPDBG_G(flags) |= PHPDBG_IS_QUITTING;
2150 			if (PHPDBG_G(in_execution) || is_exit) {
2151 				if (!quit_immediately && !phpdbg_startup_run) {
2152 					PHPDBG_G(flags) -= PHPDBG_IS_QUITTING;
2153 					cleaning++;
2154 				}
2155 			}
2156 		}
2157 
2158 		{
2159 			php_stream_wrapper *wrapper = zend_hash_str_find_ptr(php_stream_get_url_stream_wrappers_hash(), ZEND_STRL("php"));
2160 			wrapper->wops->stream_opener = PHPDBG_G(orig_url_wrap_php);
2161 		}
2162 
2163 		zend_hash_destroy(&PHPDBG_G(file_sources));
2164 
2165 		zend_try {
2166 			php_module_shutdown();
2167 		} zend_end_try();
2168 
2169 #ifndef _WIN32
2170 		/* force override (no zend_signals) to prevent crashes due to signal recursion in SIGSEGV/SIGBUS handlers */
2171 		signal(SIGSEGV, SIG_DFL);
2172 		signal(SIGBUS, SIG_DFL);
2173 
2174 		/* reset it... else we risk a stack overflow upon next run (when clean'ing) */
2175 		php_stream_stdio_ops.write = PHPDBG_G(php_stdiop_write);
2176 #endif
2177 	}
2178 
2179 	sapi_shutdown();
2180 
2181 	if (sapi_name) {
2182 		free(sapi_name);
2183 	}
2184 
2185 free_and_return:
2186 	if (read_from_stdin) {
2187 		free(read_from_stdin);
2188 		read_from_stdin = NULL;
2189 	}
2190 
2191 #ifdef ZTS
2192 	/* reset to original handlers - otherwise PHPDBG_G() in phpdbg_watch_efree will be segfaulty (with e.g. USE_ZEND_ALLOC=0) */
2193 	if (!use_mm_wrappers) {
2194 		zend_mm_set_custom_handlers(zend_mm_get_heap(), _malloc, _free, _realloc);
2195 	}
2196 
2197 	ts_free_id(phpdbg_globals_id);
2198 
2199 	tsrm_shutdown();
2200 #endif
2201 
2202 	if ((cleaning > 0 || remote) && !quit_immediately) {
2203 		/* reset internal php_getopt state */
2204 		php_getopt(-1, argv, OPTIONS, NULL, &php_optind, 0, 0);
2205 
2206 		goto phpdbg_main;
2207 	}
2208 
2209 	if (backup_phpdbg_compile) {
2210 		zend_string_free(backup_phpdbg_compile);
2211 	}
2212 
2213 #ifndef _WIN32
2214 	if (address) {
2215 		free(address);
2216 	}
2217 #endif
2218 
2219 	/* usually 0; just for -rr */
2220 	return exit_status;
2221 } /* }}} */
2222