source: src/router/php7/sapi/phpdbg/phpdbg.c @ 31879

Last change on this file since 31879 was 31879, checked in by brainslayer, 3 months ago

update php

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