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