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