This source file includes following definitions.
- 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_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_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
- php_sapi_phpdbg_flush
- php_sapi_phpdbg_flush
- phpdbg_register_file_handles
- phpdbg_ini_defaults
- phpdbg_welcome
- phpdbg_sigint_handler
- phpdbg_open_socket
- phpdbg_close_sockets
- phpdbg_open_sockets
- phpdbg_signal_handler
- phpdbg_mm_get_heap
- 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 #include "phpdbg.h"
25 #include "phpdbg_prompt.h"
26 #include "phpdbg_bp.h"
27 #include "phpdbg_break.h"
28 #include "phpdbg_list.h"
29 #include "phpdbg_utils.h"
30 #include "phpdbg_set.h"
31 #include "zend_alloc.h"
32
33
34 #ifndef _WIN32
35 # include <sys/socket.h>
36 # include <sys/select.h>
37 # include <sys/time.h>
38 # include <sys/types.h>
39 # include <netinet/in.h>
40 # include <unistd.h>
41 # include <arpa/inet.h>
42 #endif
43
44 ZEND_DECLARE_MODULE_GLOBALS(phpdbg);
45
46 static zend_bool phpdbg_booted = 0;
47
48 #if PHP_VERSION_ID >= 50500
49 void (*zend_execute_old)(zend_execute_data *execute_data TSRMLS_DC);
50 #else
51 void (*zend_execute_old)(zend_op_array *op_array TSRMLS_DC);
52 #endif
53
54 static inline void php_phpdbg_globals_ctor(zend_phpdbg_globals *pg)
55 {
56 pg->prompt[0] = NULL;
57 pg->prompt[1] = NULL;
58
59 pg->colors[0] = NULL;
60 pg->colors[1] = NULL;
61 pg->colors[2] = NULL;
62
63 pg->exec = NULL;
64 pg->exec_len = 0;
65 pg->buffer = NULL;
66 pg->ops = NULL;
67 pg->vmret = 0;
68 pg->bp_count = 0;
69 pg->flags = PHPDBG_DEFAULT_FLAGS;
70 pg->oplog = NULL;
71 pg->io[PHPDBG_STDIN] = NULL;
72 pg->io[PHPDBG_STDOUT] = NULL;
73 pg->io[PHPDBG_STDERR] = NULL;
74 pg->frame.num = 0;
75 }
76
77 static PHP_MINIT_FUNCTION(phpdbg)
78 {
79 ZEND_INIT_MODULE_GLOBALS(phpdbg, php_phpdbg_globals_ctor, NULL);
80 #if PHP_VERSION_ID >= 50500
81 zend_execute_old = zend_execute_ex;
82 zend_execute_ex = phpdbg_execute_ex;
83 #else
84 zend_execute_old = zend_execute;
85 zend_execute = phpdbg_execute_ex;
86 #endif
87
88 REGISTER_STRINGL_CONSTANT("PHPDBG_VERSION", PHPDBG_VERSION, sizeof(PHPDBG_VERSION)-1, CONST_CS|CONST_PERSISTENT);
89
90 REGISTER_LONG_CONSTANT("PHPDBG_FILE", FILE_PARAM, CONST_CS|CONST_PERSISTENT);
91 REGISTER_LONG_CONSTANT("PHPDBG_METHOD", METHOD_PARAM, CONST_CS|CONST_PERSISTENT);
92 REGISTER_LONG_CONSTANT("PHPDBG_LINENO", NUMERIC_PARAM, CONST_CS|CONST_PERSISTENT);
93 REGISTER_LONG_CONSTANT("PHPDBG_FUNC", STR_PARAM, CONST_CS|CONST_PERSISTENT);
94
95 REGISTER_LONG_CONSTANT("PHPDBG_COLOR_PROMPT", PHPDBG_COLOR_PROMPT, CONST_CS|CONST_PERSISTENT);
96 REGISTER_LONG_CONSTANT("PHPDBG_COLOR_NOTICE", PHPDBG_COLOR_NOTICE, CONST_CS|CONST_PERSISTENT);
97 REGISTER_LONG_CONSTANT("PHPDBG_COLOR_ERROR", PHPDBG_COLOR_ERROR, CONST_CS|CONST_PERSISTENT);
98
99 return SUCCESS;
100 }
101
102 static void php_phpdbg_destroy_bp_file(void *brake)
103 {
104 zend_hash_destroy((HashTable*)brake);
105 }
106
107 static void php_phpdbg_destroy_bp_symbol(void *brake)
108 {
109 efree((char*)((phpdbg_breaksymbol_t*)brake)->symbol);
110 }
111
112 static void php_phpdbg_destroy_bp_opcode(void *brake)
113 {
114 efree((char*)((phpdbg_breakop_t*)brake)->name);
115 }
116
117
118 static void php_phpdbg_destroy_bp_methods(void *brake)
119 {
120 zend_hash_destroy((HashTable*)brake);
121 }
122
123 static void php_phpdbg_destroy_bp_condition(void *data)
124 {
125 phpdbg_breakcond_t *brake = (phpdbg_breakcond_t*) data;
126
127 if (brake) {
128 if (brake->ops) {
129 TSRMLS_FETCH();
130
131 destroy_op_array(
132 brake->ops TSRMLS_CC);
133 efree(brake->ops);
134 }
135 efree((char*)brake->code);
136 }
137 }
138
139 static void php_phpdbg_destroy_registered(void *data)
140 {
141 zend_function *function = (zend_function*) data;
142 TSRMLS_FETCH();
143
144 destroy_zend_function(
145 function TSRMLS_CC);
146 }
147
148
149 static PHP_RINIT_FUNCTION(phpdbg)
150 {
151 zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], 8, NULL, php_phpdbg_destroy_bp_file, 0);
152 zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], 8, NULL, php_phpdbg_destroy_bp_symbol, 0);
153 zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
154 zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
155 zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
156 zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], 8, NULL, NULL, 0);
157 zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], 8, NULL, php_phpdbg_destroy_bp_opcode, 0);
158 zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
159 zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], 8, NULL, php_phpdbg_destroy_bp_condition, 0);
160 zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], 8, NULL, NULL, 0);
161
162 zend_hash_init(&PHPDBG_G(seek), 8, NULL, NULL, 0);
163 zend_hash_init(&PHPDBG_G(registered), 8, NULL, php_phpdbg_destroy_registered, 0);
164
165 return SUCCESS;
166 }
167
168 static PHP_RSHUTDOWN_FUNCTION(phpdbg)
169 {
170 zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE]);
171 zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM]);
172 zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE]);
173 zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE]);
174 zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE]);
175 zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]);
176 zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE]);
177 zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD]);
178 zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_COND]);
179 zend_hash_destroy(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP]);
180 zend_hash_destroy(&PHPDBG_G(seek));
181 zend_hash_destroy(&PHPDBG_G(registered));
182 zend_hash_destroy(&PHPDBG_G(watchpoints));
183 zend_llist_destroy(&PHPDBG_G(watchlist_mem));
184
185 if (PHPDBG_G(buffer)) {
186 efree(PHPDBG_G(buffer));
187 PHPDBG_G(buffer) = NULL;
188 }
189
190 if (PHPDBG_G(exec)) {
191 efree(PHPDBG_G(exec));
192 PHPDBG_G(exec) = NULL;
193 }
194
195 if (PHPDBG_G(prompt)[0]) {
196 free(PHPDBG_G(prompt)[0]);
197 }
198 if (PHPDBG_G(prompt)[1]) {
199 free(PHPDBG_G(prompt)[1]);
200 }
201
202 PHPDBG_G(prompt)[0] = NULL;
203 PHPDBG_G(prompt)[1] = NULL;
204
205 if (PHPDBG_G(oplog)) {
206 fclose(
207 PHPDBG_G(oplog));
208 PHPDBG_G(oplog) = NULL;
209 }
210
211 if (PHPDBG_G(ops)) {
212 destroy_op_array(PHPDBG_G(ops) TSRMLS_CC);
213 efree(PHPDBG_G(ops));
214 PHPDBG_G(ops) = NULL;
215 }
216
217 return SUCCESS;
218 }
219
220
221
222
223
224
225 static PHP_FUNCTION(phpdbg_exec)
226 {
227 char *exec = NULL;
228 int exec_len = 0;
229
230 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &exec, &exec_len) == FAILURE) {
231 return;
232 }
233
234 {
235 struct stat sb;
236 zend_bool result = 1;
237
238 if (VCWD_STAT(exec, &sb) != FAILURE) {
239 if (sb.st_mode & (S_IFREG|S_IFLNK)) {
240 if (PHPDBG_G(exec)) {
241 ZVAL_STRINGL(return_value, PHPDBG_G(exec), PHPDBG_G(exec_len), 1);
242 efree(PHPDBG_G(exec));
243 result = 0;
244 }
245
246 PHPDBG_G(exec) = estrndup(exec, exec_len);
247 PHPDBG_G(exec_len) = exec_len;
248
249 if (result)
250 ZVAL_BOOL(return_value, 1);
251 } else {
252 zend_error(
253 E_WARNING, "Failed to set execution context (%s), not a regular file or symlink", exec);
254 ZVAL_BOOL(return_value, 0);
255 }
256 } else {
257 zend_error(
258 E_WARNING, "Failed to set execution context (%s) the file does not exist", exec);
259
260 ZVAL_BOOL(return_value, 0);
261 }
262 }
263 }
264
265
266
267 static PHP_FUNCTION(phpdbg_break_next)
268 {
269 if (zend_parse_parameters_none() != SUCCESS) {
270 return;
271 } else if (EG(current_execute_data) && EG(active_op_array)) {
272 zend_ulong opline_num = (EG(current_execute_data)->opline -
273 EG(active_op_array)->opcodes);
274
275 phpdbg_set_breakpoint_opline_ex(
276 &EG(active_op_array)->opcodes[opline_num+1] TSRMLS_CC);
277 }
278 }
279
280
281 static PHP_FUNCTION(phpdbg_break_file)
282 {
283 char *file = NULL;
284 int flen = 0;
285 long line;
286
287 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &file, &flen, &line) == FAILURE) {
288 return;
289 }
290
291 phpdbg_set_breakpoint_file(file, line TSRMLS_CC);
292 }
293
294
295 static PHP_FUNCTION(phpdbg_break_method)
296 {
297 char *class = NULL,
298 *method = NULL;
299 int clen = 0,
300 mlen = 0;
301
302 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &class, &clen, &method, &mlen) == FAILURE) {
303 return;
304 }
305
306 phpdbg_set_breakpoint_method(class, method TSRMLS_CC);
307 }
308
309
310 static PHP_FUNCTION(phpdbg_break_function)
311 {
312 char *function = NULL;
313 int function_len;
314
315 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &function, &function_len) == FAILURE) {
316 return;
317 }
318
319 phpdbg_set_breakpoint_symbol(function, function_len TSRMLS_CC);
320 }
321
322
323
324 static PHP_FUNCTION(phpdbg_clear)
325 {
326 zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE]);
327 zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM]);
328 zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE]);
329 zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE]);
330 zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE]);
331 zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]);
332 zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD]);
333 zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_COND]);
334 }
335
336
337 static PHP_FUNCTION(phpdbg_color)
338 {
339 long element = 0L;
340 char *color = NULL;
341 int color_len = 0;
342
343 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &element, &color, &color_len) == FAILURE) {
344 return;
345 }
346
347 switch (element) {
348 case PHPDBG_COLOR_NOTICE:
349 case PHPDBG_COLOR_ERROR:
350 case PHPDBG_COLOR_PROMPT:
351 phpdbg_set_color_ex(element, color, color_len TSRMLS_CC);
352 break;
353
354 default: zend_error(E_ERROR, "phpdbg detected an incorrect color constant");
355 }
356 }
357
358
359 static PHP_FUNCTION(phpdbg_prompt)
360 {
361 char *prompt = NULL;
362 int prompt_len = 0;
363
364 if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &prompt, &prompt_len) == FAILURE) {
365 return;
366 }
367
368 phpdbg_set_prompt(prompt TSRMLS_CC);
369 }
370
371 ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_next_arginfo, 0, 0, 0)
372 ZEND_END_ARG_INFO()
373
374 ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_file_arginfo, 0, 0, 2)
375 ZEND_ARG_INFO(0, file)
376 ZEND_ARG_INFO(0, line)
377 ZEND_END_ARG_INFO()
378
379 ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_method_arginfo, 0, 0, 2)
380 ZEND_ARG_INFO(0, class)
381 ZEND_ARG_INFO(0, method)
382 ZEND_END_ARG_INFO()
383
384 ZEND_BEGIN_ARG_INFO_EX(phpdbg_break_function_arginfo, 0, 0, 1)
385 ZEND_ARG_INFO(0, function)
386 ZEND_END_ARG_INFO()
387
388 ZEND_BEGIN_ARG_INFO_EX(phpdbg_color_arginfo, 0, 0, 0)
389 ZEND_ARG_INFO(0, element)
390 ZEND_ARG_INFO(0, color)
391 ZEND_END_ARG_INFO()
392
393 ZEND_BEGIN_ARG_INFO_EX(phpdbg_prompt_arginfo, 0, 0, 0)
394 ZEND_ARG_INFO(0, string)
395 ZEND_END_ARG_INFO()
396
397 ZEND_BEGIN_ARG_INFO_EX(phpdbg_exec_arginfo, 0, 0, 0)
398 ZEND_ARG_INFO(0, context)
399 ZEND_END_ARG_INFO()
400
401 ZEND_BEGIN_ARG_INFO_EX(phpdbg_clear_arginfo, 0, 0, 0)
402 ZEND_END_ARG_INFO()
403
404 zend_function_entry phpdbg_user_functions[] = {
405 PHP_FE(phpdbg_clear, phpdbg_clear_arginfo)
406 PHP_FE(phpdbg_break_next, phpdbg_break_next_arginfo)
407 PHP_FE(phpdbg_break_file, phpdbg_break_file_arginfo)
408 PHP_FE(phpdbg_break_method, phpdbg_break_method_arginfo)
409 PHP_FE(phpdbg_break_function, phpdbg_break_function_arginfo)
410 PHP_FE(phpdbg_exec, phpdbg_exec_arginfo)
411 PHP_FE(phpdbg_color, phpdbg_color_arginfo)
412 PHP_FE(phpdbg_prompt, phpdbg_prompt_arginfo)
413 #ifdef PHP_FE_END
414 PHP_FE_END
415 #else
416 {NULL,NULL,NULL}
417 #endif
418 };
419
420 static zend_module_entry sapi_phpdbg_module_entry = {
421 STANDARD_MODULE_HEADER,
422 PHPDBG_NAME,
423 phpdbg_user_functions,
424 PHP_MINIT(phpdbg),
425 NULL,
426 PHP_RINIT(phpdbg),
427 PHP_RSHUTDOWN(phpdbg),
428 NULL,
429 PHPDBG_VERSION,
430 STANDARD_MODULE_PROPERTIES
431 };
432
433 static inline int php_sapi_phpdbg_module_startup(sapi_module_struct *module)
434 {
435 if (php_module_startup(module, &sapi_phpdbg_module_entry, 1) == FAILURE) {
436 return FAILURE;
437 }
438
439 phpdbg_booted=1;
440
441 return SUCCESS;
442 }
443
444 static char* php_sapi_phpdbg_read_cookies(TSRMLS_D)
445 {
446 return NULL;
447 }
448
449 static int php_sapi_phpdbg_header_handler(sapi_header_struct *h, sapi_header_op_enum op, sapi_headers_struct *s TSRMLS_DC)
450 {
451 return 0;
452 }
453
454
455 static int php_sapi_phpdbg_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
456 {
457
458
459 return SAPI_HEADER_SENT_SUCCESSFULLY;
460 }
461
462
463 static void php_sapi_phpdbg_send_header(sapi_header_struct *sapi_header, void *server_context TSRMLS_DC)
464 {
465 }
466
467
468 static void php_sapi_phpdbg_log_message(char *message TSRMLS_DC)
469 {
470
471
472
473 if (phpdbg_booted) {
474 phpdbg_error("%s", message);
475
476 switch (PG(last_error_type)) {
477 case E_ERROR:
478 case E_CORE_ERROR:
479 case E_COMPILE_ERROR:
480 case E_USER_ERROR:
481 case E_PARSE:
482 case E_RECOVERABLE_ERROR:
483 if (!(PHPDBG_G(flags) & PHPDBG_IN_EVAL)) {
484 phpdbg_list_file(
485 zend_get_executed_filename(TSRMLS_C),
486 3,
487 zend_get_executed_lineno(TSRMLS_C)-1,
488 zend_get_executed_lineno(TSRMLS_C)
489 TSRMLS_CC
490 );
491 }
492
493 do {
494 switch (phpdbg_interactive(TSRMLS_C)) {
495 case PHPDBG_LEAVE:
496 case PHPDBG_FINISH:
497 case PHPDBG_UNTIL:
498 case PHPDBG_NEXT:
499 return;
500 }
501 } while (!(PHPDBG_G(flags) & PHPDBG_IS_QUITTING));
502
503 }
504 } else fprintf(stdout, "%s\n", message);
505 }
506
507
508 static int php_sapi_phpdbg_deactivate(TSRMLS_D)
509 {
510 fflush(stdout);
511 if(SG(request_info).argv0) {
512 free(SG(request_info).argv0);
513 SG(request_info).argv0 = NULL;
514 }
515 return SUCCESS;
516 }
517
518
519 static void php_sapi_phpdbg_register_vars(zval *track_vars_array TSRMLS_DC)
520 {
521 unsigned int len;
522 char *docroot = "";
523
524
525
526 php_import_environment_variables(track_vars_array TSRMLS_CC);
527
528 if (PHPDBG_G(exec)) {
529 len = PHPDBG_G(exec_len);
530 if (sapi_module.input_filter(PARSE_SERVER, "PHP_SELF",
531 &PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) {
532 php_register_variable("PHP_SELF", PHPDBG_G(exec),
533 track_vars_array TSRMLS_CC);
534 }
535 if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_NAME",
536 &PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) {
537 php_register_variable("SCRIPT_NAME", PHPDBG_G(exec),
538 track_vars_array TSRMLS_CC);
539 }
540
541 if (sapi_module.input_filter(PARSE_SERVER, "SCRIPT_FILENAME",
542 &PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) {
543 php_register_variable("SCRIPT_FILENAME", PHPDBG_G(exec),
544 track_vars_array TSRMLS_CC);
545 }
546 if (sapi_module.input_filter(PARSE_SERVER, "PATH_TRANSLATED",
547 &PHPDBG_G(exec), PHPDBG_G(exec_len), &len TSRMLS_CC)) {
548 php_register_variable("PATH_TRANSLATED", PHPDBG_G(exec),
549 track_vars_array TSRMLS_CC);
550 }
551 }
552
553
554 len = 0U;
555 if (sapi_module.input_filter(PARSE_SERVER, "DOCUMENT_ROOT",
556 &docroot, len, &len TSRMLS_CC)) {
557 php_register_variable("DOCUMENT_ROOT", docroot, track_vars_array TSRMLS_CC);
558 }
559 }
560
561
562 static inline int php_sapi_phpdbg_ub_write(const char *message, unsigned int length TSRMLS_DC)
563 {
564 return phpdbg_write("%s", message);
565 }
566
567 #if PHP_VERSION_ID >= 50700
568 static inline void php_sapi_phpdbg_flush(void *context TSRMLS_DC)
569 {
570 #else
571 static inline void php_sapi_phpdbg_flush(void *context)
572 {
573 TSRMLS_FETCH();
574 #endif
575
576 fflush(PHPDBG_G(io)[PHPDBG_STDOUT]);
577 }
578
579
580 static void phpdbg_register_file_handles(TSRMLS_D)
581 {
582 zval *zin, *zout, *zerr;
583 php_stream *s_in, *s_out, *s_err;
584 php_stream_context *sc_in=NULL, *sc_out=NULL, *sc_err=NULL;
585 zend_constant ic, oc, ec;
586
587 MAKE_STD_ZVAL(zin);
588 MAKE_STD_ZVAL(zout);
589 MAKE_STD_ZVAL(zerr);
590
591 s_in = php_stream_open_wrapper_ex("php://stdin", "rb", 0, NULL, sc_in);
592 s_out = php_stream_open_wrapper_ex("php://stdout", "wb", 0, NULL, sc_out);
593 s_err = php_stream_open_wrapper_ex("php://stderr", "wb", 0, NULL, sc_err);
594
595 if (s_in==NULL || s_out==NULL || s_err==NULL) {
596 FREE_ZVAL(zin);
597 FREE_ZVAL(zout);
598 FREE_ZVAL(zerr);
599 if (s_in) php_stream_close(s_in);
600 if (s_out) php_stream_close(s_out);
601 if (s_err) php_stream_close(s_err);
602 return;
603 }
604
605 #if PHP_DEBUG
606
607 s_out->flags |= PHP_STREAM_FLAG_NO_CLOSE;
608 s_err->flags |= PHP_STREAM_FLAG_NO_CLOSE;
609 #endif
610
611 php_stream_to_zval(s_in, zin);
612 php_stream_to_zval(s_out, zout);
613 php_stream_to_zval(s_err, zerr);
614
615 ic.value = *zin;
616 ic.flags = CONST_CS;
617 ic.name = zend_strndup(ZEND_STRL("STDIN"));
618 ic.name_len = sizeof("STDIN");
619 ic.module_number = 0;
620 zend_register_constant(&ic TSRMLS_CC);
621
622 oc.value = *zout;
623 oc.flags = CONST_CS;
624 oc.name = zend_strndup(ZEND_STRL("STDOUT"));
625 oc.name_len = sizeof("STDOUT");
626 oc.module_number = 0;
627 zend_register_constant(&oc TSRMLS_CC);
628
629 ec.value = *zerr;
630 ec.flags = CONST_CS;
631 ec.name = zend_strndup(ZEND_STRL("STDERR"));
632 ec.name_len = sizeof("STDERR");
633 ec.module_number = 0;
634 zend_register_constant(&ec TSRMLS_CC);
635
636 FREE_ZVAL(zin);
637 FREE_ZVAL(zout);
638 FREE_ZVAL(zerr);
639 }
640
641
642
643
644 static sapi_module_struct phpdbg_sapi_module = {
645 "phpdbg",
646 "phpdbg",
647
648 php_sapi_phpdbg_module_startup,
649 php_module_shutdown_wrapper,
650
651 NULL,
652 php_sapi_phpdbg_deactivate,
653
654 php_sapi_phpdbg_ub_write,
655 php_sapi_phpdbg_flush,
656 NULL,
657 NULL,
658
659 php_error,
660
661 php_sapi_phpdbg_header_handler,
662 php_sapi_phpdbg_send_headers,
663 php_sapi_phpdbg_send_header,
664
665 NULL,
666 php_sapi_phpdbg_read_cookies,
667
668 php_sapi_phpdbg_register_vars,
669 php_sapi_phpdbg_log_message,
670 NULL,
671 NULL,
672 STANDARD_SAPI_MODULE_PROPERTIES
673 };
674
675
676 const opt_struct OPTIONS[] = {
677 {'c', 1, "ini path override"},
678 {'d', 1, "define ini entry on command line"},
679 {'n', 0, "no php.ini"},
680 {'z', 1, "load zend_extension"},
681
682 {'q', 0, "no banner"},
683 {'v', 0, "disable quietness"},
684 {'s', 0, "enable stepping"},
685 {'b', 0, "boring colours"},
686 {'i', 1, "specify init"},
687 {'I', 0, "ignore init"},
688 {'O', 1, "opline log"},
689 {'r', 0, "run"},
690 {'E', 0, "step-through-eval"},
691 {'S', 1, "sapi-name"},
692 #ifndef _WIN32
693 {'l', 1, "listen"},
694 {'a', 1, "address-or-any"},
695 #endif
696 {'V', 0, "version"},
697 {'-', 0, NULL}
698 };
699
700 const char phpdbg_ini_hardcoded[] =
701 "html_errors=Off\n"
702 "register_argc_argv=On\n"
703 "implicit_flush=On\n"
704 "display_errors=Off\n"
705 "log_errors=On\n"
706 "max_execution_time=0\n"
707 "max_input_time=-1\n"
708 "error_log=\n"
709 "output_buffering=off\0";
710
711
712 #define INI_DEFAULT(name, value) \
713 Z_SET_REFCOUNT(tmp, 0); \
714 Z_UNSET_ISREF(tmp); \
715 ZVAL_STRINGL(&tmp, zend_strndup(value, sizeof(value)-1), sizeof(value)-1, 0); \
716 zend_hash_update(configuration_hash, name, sizeof(name), &tmp, sizeof(zval), NULL);
717
718 void phpdbg_ini_defaults(HashTable *configuration_hash)
719 {
720 zval tmp;
721 INI_DEFAULT("report_zend_debug", "0");
722 }
723
724 static void phpdbg_welcome(zend_bool cleaning TSRMLS_DC)
725 {
726
727 if (!cleaning) {
728 phpdbg_notice("Welcome to phpdbg, the interactive PHP debugger, v%s",
729 PHPDBG_VERSION);
730 phpdbg_writeln("To get help using phpdbg type \"help\" and press enter");
731 phpdbg_notice("Please report bugs to <%s>", PHPDBG_ISSUES);
732 } else {
733 phpdbg_notice("Clean Execution Environment");
734
735 phpdbg_writeln("Classes\t\t\t%d", zend_hash_num_elements(EG(class_table)));
736 phpdbg_writeln("Functions\t\t%d", zend_hash_num_elements(EG(function_table)));
737 phpdbg_writeln("Constants\t\t%d", zend_hash_num_elements(EG(zend_constants)));
738 phpdbg_writeln("Includes\t\t%d", zend_hash_num_elements(&EG(included_files)));
739 }
740 }
741
742 static inline void phpdbg_sigint_handler(int signo)
743 {
744 TSRMLS_FETCH();
745
746 if (EG(in_execution)) {
747
748 if (!(PHPDBG_G(flags) & PHPDBG_IS_INTERACTIVE)) {
749 PHPDBG_G(flags) |= PHPDBG_IS_SIGNALED;
750 }
751 } else {
752
753 if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) {
754 PHPDBG_G(flags) |= PHPDBG_IS_QUITTING;
755 zend_bailout();
756 }
757 }
758 }
759
760 #ifndef _WIN32
761 int phpdbg_open_socket(const char *interface, short port)
762 {
763 int fd = socket(AF_INET, SOCK_STREAM, 0);
764
765 switch (fd) {
766 case -1:
767 return -1;
768
769 default: {
770 int reuse = 1;
771
772 switch (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*) &reuse, sizeof(reuse))) {
773 case -1:
774 close(fd);
775 return -2;
776
777 default: {
778 struct sockaddr_in address;
779
780 memset(&address, 0, sizeof(address));
781
782 address.sin_port = htons(port);
783 address.sin_family = AF_INET;
784
785 if ((*interface == '*')) {
786 address.sin_addr.s_addr = htonl(INADDR_ANY);
787 } else if (!inet_pton(AF_INET, interface, &address.sin_addr)) {
788 close(fd);
789 return -3;
790 }
791
792 switch (bind(fd, (struct sockaddr *)&address, sizeof(address))) {
793 case -1:
794 close(fd);
795 return -4;
796
797 default: {
798 listen(fd, 5);
799 }
800 }
801 }
802 }
803 }
804 }
805
806 return fd;
807 }
808
809 static inline void phpdbg_close_sockets(int (*socket)[2], FILE *streams[2])
810 {
811 if ((*socket)[0] >= 0) {
812 shutdown(
813 (*socket)[0], SHUT_RDWR);
814 close((*socket)[0]);
815 }
816
817 if (streams[0]) {
818 fclose(streams[0]);
819 }
820
821 if ((*socket)[1] >= 0) {
822 shutdown(
823 (*socket)[1], SHUT_RDWR);
824 close((*socket)[1]);
825 }
826
827 if (streams[1]) {
828 fclose(streams[1]);
829 }
830 }
831
832
833
834 int phpdbg_open_sockets(char *address, int port[2], int (*listen)[2], int (*socket)[2], FILE* streams[2])
835 {
836 if (((*listen)[0]) < 0 && ((*listen)[1]) < 0) {
837 ((*listen)[0]) = phpdbg_open_socket(address, (short)port[0]);
838 ((*listen)[1]) = phpdbg_open_socket(address, (short)port[1]);
839 }
840
841 streams[0] = NULL;
842 streams[1] = NULL;
843
844 if ((*listen)[0] < 0 || (*listen)[1] < 0) {
845 if ((*listen)[0] < 0) {
846 phpdbg_rlog(stderr,
847 "console failed to initialize (stdin) on %s:%d", address, port[0]);
848 }
849
850 if ((*listen)[1] < 0) {
851 phpdbg_rlog(stderr,
852 "console failed to initialize (stdout) on %s:%d", address, port[1]);
853 }
854
855 if ((*listen)[0] >= 0) {
856 close((*listen)[0]);
857 }
858
859 if ((*listen)[1] >= 0) {
860 close((*listen)[1]);
861 }
862
863 return FAILURE;
864 }
865
866 phpdbg_close_sockets(socket, streams);
867
868 phpdbg_rlog(stderr,
869 "accepting connections on %s:%d/%d", address, port[0], port[1]);
870 {
871 struct sockaddr_in address;
872 socklen_t size = sizeof(address);
873 char buffer[20] = {0};
874
875 {
876 memset(&address, 0, size);
877 (*socket)[0] = accept(
878 (*listen)[0], (struct sockaddr *) &address, &size);
879 inet_ntop(AF_INET, &address.sin_addr, buffer, sizeof(buffer));
880
881 phpdbg_rlog(stderr, "connection (stdin) from %s", buffer);
882 }
883
884 {
885 memset(&address, 0, size);
886 (*socket)[1] = accept(
887 (*listen)[1], (struct sockaddr *) &address, &size);
888 inet_ntop(AF_INET, &address.sin_addr, buffer, sizeof(buffer));
889
890 phpdbg_rlog(stderr, "connection (stdout) from %s", buffer);
891 }
892 }
893
894 dup2((*socket)[0], fileno(stdin));
895 dup2((*socket)[1], fileno(stdout));
896
897 setbuf(stdout, NULL);
898
899 streams[0] = fdopen((*socket)[0], "r");
900 streams[1] = fdopen((*socket)[1], "w");
901
902 return SUCCESS;
903 }
904
905 void phpdbg_signal_handler(int sig, siginfo_t *info, void *context)
906 {
907 int is_handled = FAILURE;
908 TSRMLS_FETCH();
909
910 switch (sig) {
911 case SIGBUS:
912 case SIGSEGV:
913 is_handled = phpdbg_watchpoint_segfault_handler(info, context TSRMLS_CC);
914 if (is_handled == FAILURE) {
915 #ifdef ZEND_SIGNALS
916 zend_sigaction(sig, &PHPDBG_G(old_sigsegv_signal), NULL TSRMLS_CC);
917 #else
918 sigaction(sig, &PHPDBG_G(old_sigsegv_signal), NULL);
919 #endif
920 }
921 break;
922 }
923
924 }
925 #endif
926
927 static inline zend_mm_heap *phpdbg_mm_get_heap()
928 {
929 zend_mm_heap *mm_heap;
930
931 TSRMLS_FETCH();
932
933 mm_heap = zend_mm_set_heap(NULL TSRMLS_CC);
934 zend_mm_set_heap(mm_heap TSRMLS_CC);
935
936 return mm_heap;
937 }
938
939 void *phpdbg_malloc_wrapper(size_t size)
940 {
941 return zend_mm_alloc(phpdbg_mm_get_heap(), size);
942 }
943
944 void phpdbg_free_wrapper(void *p)
945 {
946 zend_mm_free(phpdbg_mm_get_heap(), p);
947 }
948
949 void *phpdbg_realloc_wrapper(void *ptr, size_t size)
950 {
951 return zend_mm_realloc(phpdbg_mm_get_heap(), ptr, size);
952 }
953
954 int main(int argc, char **argv)
955 {
956 sapi_module_struct *phpdbg = &phpdbg_sapi_module;
957 char *sapi_name;
958 char *ini_entries;
959 int ini_entries_len;
960 char **zend_extensions = NULL;
961 zend_ulong zend_extensions_len = 0L;
962 zend_bool ini_ignore;
963 char *ini_override;
964 char *exec;
965 size_t exec_len;
966 char *init_file;
967 size_t init_file_len;
968 zend_bool init_file_default;
969 char *oplog_file;
970 size_t oplog_file_len;
971 zend_ulong flags;
972 char *php_optarg;
973 int php_optind, opt, show_banner = 1;
974 long cleaning = 0;
975 zend_bool remote = 0;
976 int run = 0;
977 int step = 0;
978
979 #ifdef _WIN32
980 char *bp_tmp_file = NULL;
981 #else
982 char bp_tmp_file[] = "/tmp/phpdbg.XXXXXX";
983 #endif
984
985 #ifndef _WIN32
986 char *address;
987 int listen[2];
988 int server[2];
989 int socket[2];
990 FILE* streams[2] = {NULL, NULL};
991 #endif
992
993 #ifdef ZTS
994 void ***tsrm_ls;
995 #endif
996
997 #ifndef _WIN32
998 struct sigaction signal_struct;
999 signal_struct.sa_sigaction = phpdbg_signal_handler;
1000 signal_struct.sa_flags = SA_SIGINFO | SA_NODEFER;
1001
1002 address = strdup("127.0.0.1");
1003 socket[0] = -1;
1004 socket[1] = -1;
1005 listen[0] = -1;
1006 listen[1] = -1;
1007 server[0] = -1;
1008 server[1] = -1;
1009 streams[0] = NULL;
1010 streams[1] = NULL;
1011 #endif
1012
1013 #ifdef PHP_WIN32
1014 _fmode = _O_BINARY;
1015 setmode(_fileno(stdin), O_BINARY);
1016 setmode(_fileno(stdout), O_BINARY);
1017 setmode(_fileno(stderr), O_BINARY);
1018 #endif
1019
1020 #ifdef ZTS
1021 tsrm_startup(1, 1, 0, NULL);
1022
1023 tsrm_ls = ts_resource(0);
1024 #endif
1025
1026 phpdbg_main:
1027 if (!cleaning) {
1028
1029 #ifdef _WIN32
1030 bp_tmp_file = malloc(L_tmpnam);
1031
1032 if (bp_tmp_file) {
1033 if (!tmpnam(bp_tmp_file)) {
1034 free(bp_tmp_file);
1035 bp_tmp_file = NULL;
1036 }
1037 }
1038
1039 if (!bp_tmp_file) {
1040 phpdbg_error("Unable to create temporary file");
1041 return 1;
1042 }
1043 #else
1044 if (!mkstemp(bp_tmp_file)) {
1045 memset(bp_tmp_file, 0, sizeof(bp_tmp_file));
1046 }
1047 #endif
1048
1049 }
1050 ini_entries = NULL;
1051 ini_entries_len = 0;
1052 ini_ignore = 0;
1053 ini_override = NULL;
1054 zend_extensions = NULL;
1055 zend_extensions_len = 0L;
1056 exec = NULL;
1057 exec_len = 0;
1058 init_file = NULL;
1059 init_file_len = 0;
1060 init_file_default = 1;
1061 oplog_file = NULL;
1062 oplog_file_len = 0;
1063 flags = PHPDBG_DEFAULT_FLAGS;
1064 php_optarg = NULL;
1065 php_optind = 1;
1066 opt = 0;
1067 run = 0;
1068 step = 0;
1069 sapi_name = NULL;
1070
1071 while ((opt = php_getopt(argc, argv, OPTIONS, &php_optarg, &php_optind, 0, 2)) != -1) {
1072 switch (opt) {
1073 case 'r':
1074 run++;
1075 break;
1076 case 'n':
1077 ini_ignore = 1;
1078 break;
1079 case 'c':
1080 if (ini_override) {
1081 free(ini_override);
1082 }
1083 ini_override = strdup(php_optarg);
1084 break;
1085 case 'd': {
1086 int len = strlen(php_optarg);
1087 char *val;
1088
1089 if ((val = strchr(php_optarg, '='))) {
1090 val++;
1091 if (!isalnum(*val) && *val != '"' && *val != '\'' && *val != '\0') {
1092 ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("\"\"\n\0"));
1093 memcpy(ini_entries + ini_entries_len, php_optarg, (val - php_optarg));
1094 ini_entries_len += (val - php_optarg);
1095 memcpy(ini_entries + ini_entries_len, "\"", 1);
1096 ini_entries_len++;
1097 memcpy(ini_entries + ini_entries_len, val, len - (val - php_optarg));
1098 ini_entries_len += len - (val - php_optarg);
1099 memcpy(ini_entries + ini_entries_len, "\"\n\0", sizeof("\"\n\0"));
1100 ini_entries_len += sizeof("\n\0\"") - 2;
1101 } else {
1102 ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("\n\0"));
1103 memcpy(ini_entries + ini_entries_len, php_optarg, len);
1104 memcpy(ini_entries + ini_entries_len + len, "\n\0", sizeof("\n\0"));
1105 ini_entries_len += len + sizeof("\n\0") - 2;
1106 }
1107 } else {
1108 ini_entries = realloc(ini_entries, ini_entries_len + len + sizeof("=1\n\0"));
1109 memcpy(ini_entries + ini_entries_len, php_optarg, len);
1110 memcpy(ini_entries + ini_entries_len + len, "=1\n\0", sizeof("=1\n\0"));
1111 ini_entries_len += len + sizeof("=1\n\0") - 2;
1112 }
1113 } break;
1114
1115 case 'z':
1116 zend_extensions_len++;
1117 if (zend_extensions) {
1118 zend_extensions = realloc(zend_extensions, sizeof(char*) * zend_extensions_len);
1119 } else zend_extensions = malloc(sizeof(char*) * zend_extensions_len);
1120 zend_extensions[zend_extensions_len-1] = strdup(php_optarg);
1121 break;
1122
1123
1124
1125 case 'S': {
1126 if (sapi_name) {
1127 free(sapi_name);
1128 }
1129 sapi_name = strdup(php_optarg);
1130 } break;
1131
1132 case 'I': {
1133 init_file_default = 0;
1134 } break;
1135
1136 case 'i': {
1137 if (init_file) {
1138 free(init_file);
1139 }
1140
1141 init_file_len = strlen(php_optarg);
1142 if (init_file_len) {
1143 init_file = strdup(php_optarg);
1144 }
1145 } break;
1146
1147 case 'O': {
1148 oplog_file_len = strlen(php_optarg);
1149 if (oplog_file_len) {
1150 oplog_file = strdup(php_optarg);
1151 }
1152 } break;
1153
1154 case 'v':
1155 flags &= ~PHPDBG_IS_QUIET;
1156 break;
1157
1158 case 's':
1159 step = 1;
1160 break;
1161
1162 case 'E':
1163 flags |= PHPDBG_IS_STEPONEVAL;
1164 break;
1165
1166 case 'b':
1167 flags &= ~PHPDBG_IS_COLOURED;
1168 break;
1169
1170 case 'q':
1171 show_banner = 0;
1172 break;
1173
1174 #ifndef _WIN32
1175
1176
1177
1178 case 'l': {
1179 if (sscanf(php_optarg, "%d/%d", &listen[0], &listen[1]) != 2) {
1180 if (sscanf(php_optarg, "%d", &listen[0]) != 1) {
1181
1182 listen[0] = 4000;
1183 listen[1] = 8000;
1184 } else {
1185 listen[1] = (listen[0] * 2);
1186 }
1187 }
1188 } break;
1189
1190 case 'a': {
1191 free(address);
1192 if (!php_optarg) {
1193 address = strdup("*");
1194 } else address = strdup(php_optarg);
1195 } break;
1196 #endif
1197
1198 case 'V': {
1199 sapi_startup(phpdbg);
1200 phpdbg->startup(phpdbg);
1201 printf(
1202 "phpdbg %s (built: %s %s)\nPHP %s, Copyright (c) 1997-2016 The PHP Group\n%s",
1203 PHPDBG_VERSION,
1204 __DATE__,
1205 __TIME__,
1206 PHP_VERSION,
1207 get_zend_version()
1208 );
1209 sapi_deactivate(TSRMLS_C);
1210 sapi_shutdown();
1211 return 0;
1212 } break;
1213 }
1214 }
1215
1216
1217 if ((argc > php_optind) && (strcmp(argv[php_optind-1],"--") != SUCCESS))
1218 {
1219 exec_len = strlen(argv[php_optind]);
1220 if (exec_len) {
1221 if (exec) {
1222 free(exec);
1223 }
1224 exec = strdup(argv[php_optind]);
1225 }
1226 php_optind++;
1227 }
1228
1229 #ifndef _WIN32
1230
1231 if (!cleaning &&
1232 (listen[0] > 0 && listen[1] > 0)) {
1233 if (phpdbg_open_sockets(address, listen, &server, &socket, streams) == FAILURE) {
1234 remote = 0;
1235 exit(0);
1236 }
1237
1238 remote = 1;
1239 }
1240 #endif
1241
1242 if (sapi_name) {
1243 phpdbg->name = sapi_name;
1244 }
1245
1246 phpdbg->ini_defaults = phpdbg_ini_defaults;
1247 phpdbg->phpinfo_as_text = 1;
1248 phpdbg->php_ini_ignore_cwd = 1;
1249
1250 sapi_startup(phpdbg);
1251
1252 phpdbg->executable_location = argv[0];
1253 phpdbg->phpinfo_as_text = 1;
1254 phpdbg->php_ini_ignore = ini_ignore;
1255 phpdbg->php_ini_path_override = ini_override;
1256
1257 if (ini_entries) {
1258 ini_entries = realloc(ini_entries, ini_entries_len + sizeof(phpdbg_ini_hardcoded));
1259 memmove(ini_entries + sizeof(phpdbg_ini_hardcoded) - 2, ini_entries, ini_entries_len + 1);
1260 memcpy(ini_entries, phpdbg_ini_hardcoded, sizeof(phpdbg_ini_hardcoded) - 2);
1261 } else {
1262 ini_entries = malloc(sizeof(phpdbg_ini_hardcoded));
1263 memcpy(ini_entries, phpdbg_ini_hardcoded, sizeof(phpdbg_ini_hardcoded));
1264 }
1265 ini_entries_len += sizeof(phpdbg_ini_hardcoded) - 2;
1266
1267 if (zend_extensions_len) {
1268 zend_ulong zend_extension = 0L;
1269
1270 while (zend_extension < zend_extensions_len) {
1271 const char *ze = zend_extensions[zend_extension];
1272 size_t ze_len = strlen(ze);
1273
1274 ini_entries = realloc(
1275 ini_entries, ini_entries_len + (ze_len + (sizeof("zend_extension=\n"))));
1276 memcpy(&ini_entries[ini_entries_len], "zend_extension=", (sizeof("zend_extension=\n")-1));
1277 ini_entries_len += (sizeof("zend_extension=")-1);
1278 memcpy(&ini_entries[ini_entries_len], ze, ze_len);
1279 ini_entries_len += ze_len;
1280 memcpy(&ini_entries[ini_entries_len], "\n", (sizeof("\n") - 1));
1281
1282 free(zend_extensions[zend_extension]);
1283 zend_extension++;
1284 }
1285
1286 free(zend_extensions);
1287 }
1288
1289 phpdbg->ini_entries = ini_entries;
1290
1291 if (phpdbg->startup(phpdbg) == SUCCESS) {
1292 #ifdef _WIN32
1293 EXCEPTION_POINTERS *xp;
1294 __try {
1295 #endif
1296 zend_mm_heap *mm_heap = phpdbg_mm_get_heap();
1297
1298 if (mm_heap->use_zend_alloc) {
1299 mm_heap->_malloc = phpdbg_malloc_wrapper;
1300 mm_heap->_realloc = phpdbg_realloc_wrapper;
1301 mm_heap->_free = phpdbg_free_wrapper;
1302 mm_heap->use_zend_alloc = 0;
1303 }
1304
1305 zend_activate(TSRMLS_C);
1306
1307 PHPDBG_G(original_free_function) = mm_heap->_free;
1308 mm_heap->_free = phpdbg_watch_efree;
1309
1310 phpdbg_setup_watchpoints(TSRMLS_C);
1311
1312 #if defined(ZEND_SIGNALS) && !defined(_WIN32)
1313 zend_try {
1314 zend_signal_activate(TSRMLS_C);
1315 } zend_end_try();
1316 #endif
1317
1318 #if defined(ZEND_SIGNALS) && !defined(_WIN32)
1319 zend_try { zend_sigaction(SIGSEGV, &signal_struct, &PHPDBG_G(old_sigsegv_signal) TSRMLS_CC); } zend_end_try();
1320 zend_try { zend_sigaction(SIGBUS, &signal_struct, &PHPDBG_G(old_sigsegv_signal) TSRMLS_CC); } zend_end_try();
1321 #elif !defined(_WIN32)
1322 sigaction(SIGSEGV, &signal_struct, &PHPDBG_G(old_sigsegv_signal));
1323 sigaction(SIGBUS, &signal_struct, &PHPDBG_G(old_sigsegv_signal));
1324 #endif
1325
1326 if (php_request_startup(TSRMLS_C) == SUCCESS) {
1327 int i;
1328
1329 SG(request_info).argc = argc - php_optind + 1;
1330 SG(request_info).argv = emalloc(SG(request_info).argc * sizeof(char *));
1331 for (i = SG(request_info).argc; --i;) {
1332 SG(request_info).argv[i] = estrdup(argv[php_optind - 1 + i]);
1333 }
1334 SG(request_info).argv[i] = exec ? estrndup(exec, exec_len) : estrdup("");
1335
1336 php_hash_environment(TSRMLS_C);
1337 }
1338
1339
1340 php_output_activate(TSRMLS_C);
1341 php_output_deactivate(TSRMLS_C);
1342
1343
1344
1345 #ifndef _WIN32
1346 if (listen[0] < 0) {
1347 #endif
1348 #if defined(ZEND_SIGNALS) && !defined(_WIN32)
1349 zend_try { zend_signal(SIGINT, phpdbg_sigint_handler TSRMLS_CC); } zend_end_try();
1350 #else
1351 signal(SIGINT, phpdbg_sigint_handler);
1352 #endif
1353 #ifndef _WIN32
1354 }
1355 #endif
1356
1357 PG(modules_activated) = 0;
1358
1359
1360 PHPDBG_G(flags) = flags;
1361
1362 #ifndef _WIN32
1363
1364 if (streams[0] && streams[1]) {
1365 PHPDBG_G(flags) |= PHPDBG_IS_REMOTE;
1366
1367 signal(SIGPIPE, SIG_IGN);
1368 }
1369 #endif
1370
1371 PHPDBG_G(io)[PHPDBG_STDIN] = stdin;
1372 PHPDBG_G(io)[PHPDBG_STDOUT] = stdout;
1373 PHPDBG_G(io)[PHPDBG_STDERR] = stderr;
1374
1375 if (exec) {
1376 PHPDBG_G(exec) = phpdbg_resolve_path(exec TSRMLS_CC);
1377 PHPDBG_G(exec_len) = strlen(PHPDBG_G(exec));
1378
1379 free(exec);
1380 }
1381
1382 if (oplog_file) {
1383 PHPDBG_G(oplog) = fopen(oplog_file, "w+");
1384 if (!PHPDBG_G(oplog)) {
1385 phpdbg_error(
1386 "Failed to open oplog %s", oplog_file);
1387 }
1388 free(oplog_file);
1389 }
1390
1391
1392 phpdbg_set_color_ex(PHPDBG_COLOR_PROMPT, PHPDBG_STRL("white-bold") TSRMLS_CC);
1393 phpdbg_set_color_ex(PHPDBG_COLOR_ERROR, PHPDBG_STRL("red-bold") TSRMLS_CC);
1394 phpdbg_set_color_ex(PHPDBG_COLOR_NOTICE, PHPDBG_STRL("green") TSRMLS_CC);
1395
1396
1397 phpdbg_set_prompt(PROMPT TSRMLS_CC);
1398
1399
1400 phpdbg_register_file_handles(TSRMLS_C);
1401
1402 if (show_banner) {
1403
1404 phpdbg_welcome((cleaning > 0) TSRMLS_CC);
1405 }
1406
1407
1408 if (PHPDBG_G(exec)) {
1409 phpdbg_compile(TSRMLS_C);
1410 }
1411
1412
1413 PHPDBG_G(flags) |= PHPDBG_IS_INITIALIZING;
1414 zend_try {
1415 phpdbg_init(init_file, init_file_len, init_file_default TSRMLS_CC);
1416 phpdbg_try_file_init(bp_tmp_file, strlen(bp_tmp_file), 0 TSRMLS_CC);
1417 } zend_end_try();
1418 PHPDBG_G(flags) &= ~PHPDBG_IS_INITIALIZING;
1419
1420
1421 if (PHPDBG_G(flags) & PHPDBG_IS_QUITTING) {
1422 goto phpdbg_out;
1423 }
1424
1425
1426 if (step) {
1427 PHPDBG_G(flags) |= PHPDBG_IS_STEPPING;
1428 }
1429
1430 if (run) {
1431
1432 PHPDBG_COMMAND_HANDLER(run)(NULL TSRMLS_CC);
1433 if (run > 1) {
1434
1435 goto phpdbg_out;
1436 }
1437 }
1438
1439
1440 #ifndef _WIN32
1441 phpdbg_interact:
1442 #endif
1443
1444 do {
1445 zend_try {
1446 phpdbg_interactive(TSRMLS_C);
1447 } zend_catch {
1448 if ((PHPDBG_G(flags) & PHPDBG_IS_CLEANING)) {
1449 FILE *bp_tmp_fp = fopen(bp_tmp_file, "w");
1450 phpdbg_export_breakpoints(bp_tmp_fp TSRMLS_CC);
1451 fclose(bp_tmp_fp);
1452 cleaning = 1;
1453 } else {
1454 cleaning = 0;
1455 }
1456
1457 #ifndef _WIN32
1458 if (!cleaning) {
1459
1460 if ((PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED)) {
1461
1462 if (PHPDBG_G(flags) & PHPDBG_IS_REMOTE) {
1463
1464 phpdbg_open_sockets(
1465 address, listen, &server, &socket, streams);
1466
1467
1468 if (streams[0] && streams[1]) {
1469 PHPDBG_G(flags) &= ~PHPDBG_IS_QUITTING;
1470 }
1471
1472
1473 CG(unclean_shutdown) = 0;
1474 } else {
1475
1476 PHPDBG_G(flags) &= ~PHPDBG_IS_DISCONNECTED;
1477 }
1478 }
1479 }
1480 #endif
1481 } zend_end_try();
1482 } while(!cleaning && !(PHPDBG_G(flags) & PHPDBG_IS_QUITTING));
1483
1484
1485 CG(unclean_shutdown) = 0;
1486
1487
1488 PG(report_memleaks) = 0;
1489
1490 #ifndef _WIN32
1491 phpdbg_out:
1492 if ((PHPDBG_G(flags) & PHPDBG_IS_DISCONNECTED)) {
1493 PHPDBG_G(flags) &= ~PHPDBG_IS_DISCONNECTED;
1494 goto phpdbg_interact;
1495 }
1496 #endif
1497
1498 #ifdef _WIN32
1499 } __except(phpdbg_exception_handler_win32(xp = GetExceptionInformation())) {
1500 phpdbg_error("Access violation (Segmentation fault) encountered\ntrying to abort cleanly...");
1501 }
1502 phpdbg_out:
1503 #endif
1504
1505 {
1506 int i;
1507
1508 for (i = SG(request_info).argc; --i;) {
1509 efree(SG(request_info).argv[i]);
1510 }
1511 efree(SG(request_info).argv);
1512 }
1513
1514 #ifndef ZTS
1515
1516 zend_hash_clean(CG(auto_globals));
1517 memset(
1518 &core_globals, 0, sizeof(php_core_globals));
1519 #endif
1520 if (ini_entries) {
1521 free(ini_entries);
1522 }
1523
1524 if (ini_override) {
1525 free(ini_override);
1526 }
1527
1528
1529 CG(unclean_shutdown) = 0;
1530
1531
1532 PG(report_memleaks) = 0;
1533
1534 php_request_shutdown((void*)0);
1535
1536 zend_try {
1537 php_module_shutdown(TSRMLS_C);
1538 } zend_end_try();
1539
1540 sapi_shutdown();
1541
1542 }
1543
1544 if (cleaning || remote) {
1545 goto phpdbg_main;
1546 }
1547
1548 #ifdef ZTS
1549
1550
1551 #endif
1552
1553 #ifndef _WIN32
1554 if (address) {
1555 free(address);
1556 }
1557 #endif
1558
1559 if (sapi_name) {
1560 free(sapi_name);
1561 }
1562
1563 #ifdef _WIN32
1564 free(bp_tmp_file);
1565 #else
1566 unlink(bp_tmp_file);
1567 #endif
1568
1569 return 0;
1570 }