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