1 /*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Authors: Felipe Pena <felipe@php.net> |
14 | Authors: Joe Watkins <joe.watkins@live.co.uk> |
15 | Authors: Bob Weinand <bwoebi@php.net> |
16 +----------------------------------------------------------------------+
17 */
18
19 #include <stdio.h>
20 #include <string.h>
21 #include "zend.h"
22 #include "zend_compile.h"
23 #include "zend_exceptions.h"
24 #include "zend_vm.h"
25 #include "zend_generators.h"
26 #include "zend_interfaces.h"
27 #include "zend_smart_str.h"
28 #include "phpdbg.h"
29 #include "phpdbg_io.h"
30
31 #include "phpdbg_help.h"
32 #include "phpdbg_print.h"
33 #include "phpdbg_info.h"
34 #include "phpdbg_break.h"
35 #include "phpdbg_list.h"
36 #include "phpdbg_utils.h"
37 #include "phpdbg_prompt.h"
38 #include "phpdbg_cmd.h"
39 #include "phpdbg_set.h"
40 #include "phpdbg_frame.h"
41 #include "phpdbg_lexer.h"
42 #include "phpdbg_parser.h"
43
44 #if ZEND_VM_KIND != ZEND_VM_KIND_CALL && ZEND_VM_KIND != ZEND_VM_KIND_HYBRID
45 #error "phpdbg can only be built with CALL zend vm kind"
46 #endif
47
48 ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
49 extern int phpdbg_startup_run;
50
51 #ifdef HAVE_LIBDL
52 #ifdef PHP_WIN32
53 #include "win32/param.h"
54 #include "win32/winutil.h"
55 #define GET_DL_ERROR() php_win_err()
56 #else
57 #include <sys/param.h>
58 #define GET_DL_ERROR() DL_ERROR()
59 #endif
60 #endif
61
62 /* {{{ command declarations */
63 const phpdbg_command_t phpdbg_prompt_commands[] = {
64 PHPDBG_COMMAND_D(exec, "set execution context", 'e', NULL, "s", 0),
65 PHPDBG_COMMAND_D(stdin, "read script from stdin", 0 , NULL, "s", 0),
66 PHPDBG_COMMAND_D(step, "step through execution", 's', NULL, 0, PHPDBG_ASYNC_SAFE),
67 PHPDBG_COMMAND_D(continue, "continue execution", 'c', NULL, 0, PHPDBG_ASYNC_SAFE),
68 PHPDBG_COMMAND_D(run, "attempt execution", 'r', NULL, "|s", 0),
69 PHPDBG_COMMAND_D(ev, "evaluate some code", 0 , NULL, "i", PHPDBG_ASYNC_SAFE), /* restricted ASYNC_SAFE */
70 PHPDBG_COMMAND_D(until, "continue past the current line", 'u', NULL, 0, 0),
71 PHPDBG_COMMAND_D(finish, "continue past the end of the stack", 'F', NULL, 0, 0),
72 PHPDBG_COMMAND_D(leave, "continue until the end of the stack", 'L', NULL, 0, 0),
73 PHPDBG_COMMAND_D(generator, "inspect or switch to a generator", 'g', NULL, "|n", 0),
74 PHPDBG_COMMAND_D(print, "print something", 'p', phpdbg_print_commands, "|*c", 0),
75 PHPDBG_COMMAND_D(break, "set breakpoint", 'b', phpdbg_break_commands, "|*c", 0),
76 PHPDBG_COMMAND_D(back, "show trace", 't', NULL, "|n", PHPDBG_ASYNC_SAFE),
77 PHPDBG_COMMAND_D(frame, "switch to a frame", 'f', NULL, "|n", PHPDBG_ASYNC_SAFE),
78 PHPDBG_COMMAND_D(list, "lists some code", 'l', phpdbg_list_commands, "*", PHPDBG_ASYNC_SAFE),
79 PHPDBG_COMMAND_D(info, "displays some information", 'i', phpdbg_info_commands, "|s", PHPDBG_ASYNC_SAFE),
80 PHPDBG_COMMAND_D(clean, "clean the execution environment", 'X', NULL, 0, 0),
81 PHPDBG_COMMAND_D(clear, "clear breakpoints", 'C', NULL, 0, 0),
82 PHPDBG_COMMAND_D(help, "show help menu", 'h', phpdbg_help_commands, "|s", PHPDBG_ASYNC_SAFE),
83 PHPDBG_COMMAND_D(set, "set phpdbg configuration", 'S', phpdbg_set_commands, "s", PHPDBG_ASYNC_SAFE),
84 PHPDBG_COMMAND_D(register, "register a function", 'R', NULL, "s", 0),
85 PHPDBG_COMMAND_D(source, "execute a phpdbginit", '<', NULL, "s", 0),
86 PHPDBG_COMMAND_D(export, "export breaks to a .phpdbginit script", '>', NULL, "s", PHPDBG_ASYNC_SAFE),
87 PHPDBG_COMMAND_D(sh, "shell a command", 0 , NULL, "i", 0),
88 PHPDBG_COMMAND_D(quit, "exit phpdbg", 'q', NULL, 0, PHPDBG_ASYNC_SAFE),
89 PHPDBG_COMMAND_D(watch, "set watchpoint", 'w', phpdbg_watch_commands, "|ss", 0),
90 PHPDBG_COMMAND_D(next, "step over next line", 'n', NULL, 0, PHPDBG_ASYNC_SAFE),
91 PHPDBG_END_COMMAND
92 }; /* }}} */
93
phpdbg_call_register(phpdbg_param_t * stack)94 static inline int phpdbg_call_register(phpdbg_param_t *stack) /* {{{ */
95 {
96 phpdbg_param_t *name = NULL;
97
98 if (stack->type == STACK_PARAM) {
99 char *lc_name;
100
101 name = stack->next;
102
103 if (!name || name->type != STR_PARAM) {
104 return FAILURE;
105 }
106
107 lc_name = zend_str_tolower_dup(name->str, name->len);
108
109 if (zend_hash_str_exists(&PHPDBG_G(registered), lc_name, name->len)) {
110 zval fretval;
111 zend_fcall_info fci;
112
113 memset(&fci, 0, sizeof(zend_fcall_info));
114
115 ZVAL_STRINGL(&fci.function_name, lc_name, name->len);
116 fci.size = sizeof(zend_fcall_info);
117 //???fci.symbol_table = zend_rebuild_symbol_table();
118 fci.object = NULL;
119 fci.retval = &fretval;
120
121 if (name->next) {
122 zval params;
123 phpdbg_param_t *next = name->next;
124
125 array_init(¶ms);
126
127 while (next) {
128 char *buffered = NULL;
129
130 switch (next->type) {
131 case OP_PARAM:
132 case COND_PARAM:
133 case STR_PARAM:
134 add_next_index_stringl(¶ms, next->str, next->len);
135 break;
136
137 case NUMERIC_PARAM:
138 add_next_index_long(¶ms, next->num);
139 break;
140
141 case METHOD_PARAM:
142 spprintf(&buffered, 0, "%s::%s", next->method.class, next->method.name);
143 add_next_index_string(¶ms, buffered);
144 break;
145
146 case NUMERIC_METHOD_PARAM:
147 spprintf(&buffered, 0, "%s::%s#"ZEND_LONG_FMT, next->method.class, next->method.name, next->num);
148 add_next_index_string(¶ms, buffered);
149 break;
150
151 case NUMERIC_FUNCTION_PARAM:
152 spprintf(&buffered, 0, "%s#"ZEND_LONG_FMT, next->str, next->num);
153 add_next_index_string(¶ms, buffered);
154 break;
155
156 case FILE_PARAM:
157 spprintf(&buffered, 0, "%s:"ZEND_ULONG_FMT, next->file.name, next->file.line);
158 add_next_index_string(¶ms, buffered);
159 break;
160
161 case NUMERIC_FILE_PARAM:
162 spprintf(&buffered, 0, "%s:#"ZEND_ULONG_FMT, next->file.name, next->file.line);
163 add_next_index_string(¶ms, buffered);
164 break;
165
166 default: {
167 /* not yet */
168 }
169 }
170
171 next = next->next;
172 }
173
174 zend_fcall_info_args(&fci, ¶ms);
175 } else {
176 fci.params = NULL;
177 fci.param_count = 0;
178 }
179
180 phpdbg_activate_err_buf(0);
181 phpdbg_free_err_buf();
182
183 phpdbg_debug("created %d params from arguments", fci.param_count);
184
185 if (zend_call_function(&fci, NULL) == SUCCESS) {
186 zend_print_zval_r(&fretval, 0);
187 phpdbg_out("\n");
188 zval_ptr_dtor(&fretval);
189 }
190
191 zval_ptr_dtor_str(&fci.function_name);
192 efree(lc_name);
193
194 return SUCCESS;
195 }
196
197 efree(lc_name);
198 }
199
200 return FAILURE;
201 } /* }}} */
202
203 struct phpdbg_init_state {
204 int line;
205 bool in_code;
206 char *code;
207 size_t code_len;
208 const char *init_file;
209 };
210
phpdbg_line_init(char * cmd,struct phpdbg_init_state * state)211 static void phpdbg_line_init(char *cmd, struct phpdbg_init_state *state) {
212 size_t cmd_len = strlen(cmd);
213
214 state->line++;
215
216 while (cmd_len > 0L && isspace(cmd[cmd_len-1])) {
217 cmd_len--;
218 }
219
220 cmd[cmd_len] = '\0';
221
222 if (*cmd && cmd_len > 0L && cmd[0] != '#') {
223 if (cmd_len == 2) {
224 if (memcmp(cmd, "<:", sizeof("<:")-1) == SUCCESS) {
225 state->in_code = 1;
226 return;
227 } else {
228 if (memcmp(cmd, ":>", sizeof(":>")-1) == SUCCESS) {
229 state->in_code = 0;
230 state->code[state->code_len] = '\0';
231 zend_eval_stringl(state->code, state->code_len, NULL, "phpdbginit code");
232 free(state->code);
233 state->code = NULL;
234 return;
235 }
236 }
237 }
238
239 if (state->in_code) {
240 if (state->code == NULL) {
241 state->code = malloc(cmd_len + 1);
242 } else {
243 state->code = realloc(state->code, state->code_len + cmd_len + 1);
244 }
245
246 if (state->code) {
247 memcpy(&state->code[state->code_len], cmd, cmd_len);
248 state->code_len += cmd_len;
249 }
250
251 return;
252 }
253
254 zend_try {
255 char *input = phpdbg_read_input(cmd);
256 phpdbg_param_t stack;
257
258 phpdbg_init_param(&stack, STACK_PARAM);
259
260 phpdbg_activate_err_buf(1);
261
262 if (phpdbg_do_parse(&stack, input) <= 0) {
263 switch (phpdbg_stack_execute(&stack, 1 /* allow_async_unsafe == 1 */)) {
264 case FAILURE:
265 phpdbg_activate_err_buf(0);
266 if (phpdbg_call_register(&stack) == FAILURE) {
267 if (state->init_file) {
268 phpdbg_output_err_buf("Unrecognized command in %s:%d: %s, %s!", state->init_file, state->line, input, PHPDBG_G(err_buf).msg);
269 } else {
270 phpdbg_output_err_buf("Unrecognized command on line %d: %s, %s!", state->line, input, PHPDBG_G(err_buf).msg);
271 }
272 }
273 break;
274 }
275 }
276
277 phpdbg_activate_err_buf(0);
278 phpdbg_free_err_buf();
279
280 phpdbg_stack_free(&stack);
281 phpdbg_destroy_input(&input);
282 } zend_catch {
283 PHPDBG_G(flags) &= ~(PHPDBG_IS_RUNNING | PHPDBG_IS_CLEANING);
284 if (PHPDBG_G(flags) & PHPDBG_IS_QUITTING) {
285 zend_bailout();
286 }
287 } zend_end_try();
288 }
289
290 }
291
phpdbg_string_init(char * buffer)292 void phpdbg_string_init(char *buffer) {
293 struct phpdbg_init_state state = {0};
294 char *str = strtok(buffer, "\n");
295
296 while (str) {
297 phpdbg_line_init(str, &state);
298
299 str = strtok(NULL, "\n");
300 }
301
302 if (state.code) {
303 free(state.code);
304 }
305 }
306
phpdbg_try_file_init(char * init_file,size_t init_file_len,bool free_init)307 void phpdbg_try_file_init(char *init_file, size_t init_file_len, bool free_init) /* {{{ */
308 {
309 zend_stat_t sb;
310
311 if (init_file && VCWD_STAT(init_file, &sb) != -1) {
312 FILE *fp = fopen(init_file, "r");
313 if (fp) {
314 char cmd[PHPDBG_MAX_CMD];
315 struct phpdbg_init_state state = {0};
316
317 state.init_file = init_file;
318
319 while (fgets(cmd, PHPDBG_MAX_CMD, fp) != NULL) {
320 phpdbg_line_init(cmd, &state);
321 }
322
323 if (state.code) {
324 free(state.code);
325 }
326
327 fclose(fp);
328 } else {
329 phpdbg_error("Failed to open %s for initialization", init_file);
330 }
331
332 if (free_init) {
333 free(init_file);
334 }
335 }
336 } /* }}} */
337
phpdbg_init(char * init_file,size_t init_file_len,bool use_default)338 void phpdbg_init(char *init_file, size_t init_file_len, bool use_default) /* {{{ */
339 {
340 if (init_file) {
341 phpdbg_try_file_init(init_file, init_file_len, 1);
342 } else if (use_default) {
343 char *scan_dir = getenv("PHP_INI_SCAN_DIR");
344 char *sys_ini;
345 int i;
346
347 ZEND_IGNORE_VALUE(asprintf(&sys_ini, "%s/" PHPDBG_INIT_FILENAME, PHP_CONFIG_FILE_PATH));
348 phpdbg_try_file_init(sys_ini, strlen(sys_ini), 0);
349 free(sys_ini);
350
351 if (!scan_dir) {
352 scan_dir = PHP_CONFIG_FILE_SCAN_DIR;
353 }
354 while (*scan_dir != 0) {
355 i = 0;
356 while (scan_dir[i] != ':') {
357 if (scan_dir[i++] == 0) {
358 i = -1;
359 break;
360 }
361 }
362 if (i != -1) {
363 scan_dir[i] = 0;
364 }
365
366 ZEND_IGNORE_VALUE(asprintf(&init_file, "%s/%s", scan_dir, PHPDBG_INIT_FILENAME));
367 phpdbg_try_file_init(init_file, strlen(init_file), 1);
368 free(init_file);
369 if (i == -1) {
370 break;
371 }
372 scan_dir += i + 1;
373 }
374
375 phpdbg_try_file_init(PHPDBG_STRL(PHPDBG_INIT_FILENAME), 0);
376 }
377 }
378 /* }}} */
379
phpdbg_clean(bool full,bool resubmit)380 void phpdbg_clean(bool full, bool resubmit) /* {{{ */
381 {
382 /* this is implicitly required */
383 if (PHPDBG_G(ops)) {
384 destroy_op_array(PHPDBG_G(ops));
385 efree(PHPDBG_G(ops));
386 PHPDBG_G(ops) = NULL;
387 }
388
389 if (!resubmit && PHPDBG_G(cur_command)) {
390 free(PHPDBG_G(cur_command));
391 PHPDBG_G(cur_command) = NULL;
392 }
393
394 if (full) {
395 PHPDBG_G(flags) |= PHPDBG_IS_CLEANING;
396 }
397 } /* }}} */
398
PHPDBG_COMMAND(exec)399 PHPDBG_COMMAND(exec) /* {{{ */
400 {
401 zend_stat_t sb;
402
403 if (VCWD_STAT(param->str, &sb) != FAILURE) {
404 if (sb.st_mode & (S_IFREG|S_IFLNK)) {
405 char *res = phpdbg_resolve_path(param->str);
406 size_t res_len = strlen(res);
407
408 if ((res_len != PHPDBG_G(exec_len)) || (memcmp(res, PHPDBG_G(exec), res_len) != SUCCESS)) {
409 if (PHPDBG_G(in_execution)) {
410 if (phpdbg_ask_user_permission("Do you really want to stop execution to set a new execution context?") == FAILURE) {
411 free(res);
412 return FAILURE;
413 }
414 }
415
416 if (PHPDBG_G(exec)) {
417 phpdbg_notice("Unsetting old execution context: %s", PHPDBG_G(exec));
418 free(PHPDBG_G(exec));
419 PHPDBG_G(exec) = NULL;
420 PHPDBG_G(exec_len) = 0L;
421 }
422
423 if (PHPDBG_G(ops)) {
424 phpdbg_notice("Destroying compiled opcodes");
425 phpdbg_clean(0, 0);
426 }
427
428 PHPDBG_G(exec) = res;
429 PHPDBG_G(exec_len) = res_len;
430
431 VCWD_CHDIR_FILE(res);
432
433 *SG(request_info).argv = estrndup(PHPDBG_G(exec), PHPDBG_G(exec_len));
434 php_build_argv(NULL, &PG(http_globals)[TRACK_VARS_SERVER]);
435
436 phpdbg_notice("Set execution context: %s", PHPDBG_G(exec));
437
438 if (PHPDBG_G(in_execution)) {
439 phpdbg_clean(1, 0);
440 return SUCCESS;
441 }
442
443 phpdbg_compile();
444 } else {
445 free(res);
446 phpdbg_notice("Execution context not changed");
447 }
448 } else {
449 phpdbg_error("Cannot use %s as execution context, not a valid file or symlink", param->str);
450 }
451 } else {
452 phpdbg_error("Cannot stat %s, ensure the file exists", param->str);
453 }
454 return SUCCESS;
455 } /* }}} */
456
PHPDBG_COMMAND(stdin)457 PHPDBG_COMMAND(stdin)
458 {
459 smart_str code = {0};
460 char *buf;
461 char *sep = param->str;
462 int seplen = param->len;
463 int bytes = 0;
464
465 smart_str_appends(&code, "?>");
466
467 do {
468 PHPDBG_G(input_buflen) += bytes;
469 if (PHPDBG_G(input_buflen) <= 0) {
470 continue;
471 }
472
473 if (sep && seplen) {
474 char *nl = buf = PHPDBG_G(input_buffer);
475 do {
476 if (buf == nl + seplen) {
477 if (!memcmp(sep, nl, seplen) && (*buf == '\n' || (*buf == '\r' && buf[1] == '\n'))) {
478 smart_str_appendl(&code, PHPDBG_G(input_buffer), nl - PHPDBG_G(input_buffer));
479 memmove(PHPDBG_G(input_buffer), ++buf, --PHPDBG_G(input_buflen));
480 goto exec_code;
481 }
482 }
483 if (*buf == '\n') {
484 nl = buf + 1;
485 }
486 buf++;
487 } while (--PHPDBG_G(input_buflen));
488 if (buf != nl && buf <= nl + seplen) {
489 smart_str_appendl(&code, PHPDBG_G(input_buffer), nl - PHPDBG_G(input_buffer));
490 PHPDBG_G(input_buflen) = buf - nl;
491 memmove(PHPDBG_G(input_buffer), nl, PHPDBG_G(input_buflen));
492 } else {
493 PHPDBG_G(input_buflen) = 0;
494 smart_str_appendl(&code, PHPDBG_G(input_buffer), buf - PHPDBG_G(input_buffer));
495 }
496 } else {
497 smart_str_appendl(&code, PHPDBG_G(input_buffer), PHPDBG_G(input_buflen));
498 PHPDBG_G(input_buflen) = 0;
499 }
500 } while ((bytes = phpdbg_mixed_read(PHPDBG_G(io)[PHPDBG_STDIN].fd, PHPDBG_G(input_buffer) + PHPDBG_G(input_buflen), PHPDBG_MAX_CMD - PHPDBG_G(input_buflen), -1)) > 0);
501
502 if (bytes < 0) {
503 PHPDBG_G(flags) |= PHPDBG_IS_QUITTING;
504 zend_bailout();
505 }
506
507 exec_code:
508 smart_str_0(&code);
509
510 if (phpdbg_compile_stdin(code.s) == FAILURE) {
511 zend_exception_error(EG(exception), E_ERROR);
512 zend_bailout();
513 }
514
515 return SUCCESS;
516 } /* }}} */
517
phpdbg_compile_stdin(zend_string * code)518 int phpdbg_compile_stdin(zend_string *code) {
519 PHPDBG_G(ops) = zend_compile_string(code, "Standard input code");
520 zend_string_release(code);
521
522 if (EG(exception)) {
523 return FAILURE;
524 }
525
526 if (PHPDBG_G(exec)) {
527 free(PHPDBG_G(exec));
528 }
529 PHPDBG_G(exec) = strdup("Standard input code");
530 PHPDBG_G(exec_len) = sizeof("Standard input code") - 1;
531 { /* remove leading ?> from source */
532 int i;
533 /* remove trailing data after zero byte, used for avoiding conflicts in eval()'ed code snippets */
534 zend_string *source_path = strpprintf(0, "Standard input code%c%p", 0, PHPDBG_G(ops)->opcodes);
535 phpdbg_file_source *data = zend_hash_find_ptr(&PHPDBG_G(file_sources), source_path);
536 dtor_func_t dtor = PHPDBG_G(file_sources).pDestructor;
537 PHPDBG_G(file_sources).pDestructor = NULL;
538 zend_hash_del(&PHPDBG_G(file_sources), source_path);
539 PHPDBG_G(file_sources).pDestructor = dtor;
540 zend_hash_str_update_ptr(&PHPDBG_G(file_sources), "Standard input code", sizeof("Standard input code")-1, data);
541 zend_string_release(source_path);
542
543 for (i = 1; i <= data->lines; i++) {
544 data->line[i] -= 2;
545 }
546 data->len -= 2;
547 memmove(data->buf, data->buf + 2, data->len);
548 }
549
550 phpdbg_notice("Successful compilation of stdin input");
551
552 return SUCCESS;
553 }
554
phpdbg_compile(void)555 int phpdbg_compile(void) /* {{{ */
556 {
557 zend_file_handle fh;
558 char *buf;
559 size_t len;
560
561 if (!PHPDBG_G(exec)) {
562 phpdbg_error("No execution context");
563 return FAILURE;
564 }
565
566 zend_stream_init_filename(&fh, PHPDBG_G(exec));
567 if (php_stream_open_for_zend_ex(&fh, USE_PATH|STREAM_OPEN_FOR_INCLUDE) == SUCCESS && zend_stream_fixup(&fh, &buf, &len) == SUCCESS) {
568 CG(skip_shebang) = 1;
569 PHPDBG_G(ops) = zend_compile_file(&fh, ZEND_INCLUDE);
570 zend_destroy_file_handle(&fh);
571 if (EG(exception)) {
572 zend_exception_error(EG(exception), E_ERROR);
573 zend_bailout();
574 }
575
576 phpdbg_notice("Successful compilation of %s", PHPDBG_G(exec));
577
578 return SUCCESS;
579 } else {
580 phpdbg_error("Could not open file %s", PHPDBG_G(exec));
581 }
582 zend_destroy_file_handle(&fh);
583 return FAILURE;
584 } /* }}} */
585
PHPDBG_COMMAND(step)586 PHPDBG_COMMAND(step) /* {{{ */
587 {
588 if (PHPDBG_G(in_execution)) {
589 PHPDBG_G(flags) |= PHPDBG_IS_STEPPING;
590 }
591
592 return PHPDBG_NEXT;
593 } /* }}} */
594
PHPDBG_COMMAND(continue)595 PHPDBG_COMMAND(continue) /* {{{ */
596 {
597 return PHPDBG_NEXT;
598 } /* }}} */
599
phpdbg_skip_line_helper(void)600 int phpdbg_skip_line_helper(void) /* {{{ */ {
601 zend_execute_data *ex = phpdbg_user_execute_data(EG(current_execute_data));
602 const zend_op_array *op_array = &ex->func->op_array;
603 const zend_op *opline = op_array->opcodes;
604
605 PHPDBG_G(flags) |= PHPDBG_IN_UNTIL;
606 PHPDBG_G(seek_ex) = ex;
607 do {
608 if (opline->lineno != ex->opline->lineno
609 || opline->opcode == ZEND_RETURN
610 || opline->opcode == ZEND_FAST_RET
611 || opline->opcode == ZEND_GENERATOR_RETURN
612 || opline->opcode == ZEND_EXIT
613 || opline->opcode == ZEND_YIELD
614 || opline->opcode == ZEND_YIELD_FROM
615 ) {
616 zend_hash_index_update_ptr(&PHPDBG_G(seek), (zend_ulong) opline, (void *) opline);
617 }
618 } while (++opline < op_array->opcodes + op_array->last);
619
620 return PHPDBG_UNTIL;
621 }
622 /* }}} */
623
PHPDBG_COMMAND(until)624 PHPDBG_COMMAND(until) /* {{{ */
625 {
626 if (!PHPDBG_G(in_execution)) {
627 phpdbg_error("Not executing");
628 return SUCCESS;
629 }
630
631 return phpdbg_skip_line_helper();
632 } /* }}} */
633
PHPDBG_COMMAND(next)634 PHPDBG_COMMAND(next) /* {{{ */
635 {
636 if (!PHPDBG_G(in_execution)) {
637 phpdbg_error("Not executing");
638 return SUCCESS;
639 }
640
641 PHPDBG_G(flags) |= PHPDBG_IS_STEPPING;
642 return phpdbg_skip_line_helper();
643 } /* }}} */
644
phpdbg_seek_to_end(void)645 static void phpdbg_seek_to_end(void) /* {{{ */ {
646 zend_execute_data *ex = phpdbg_user_execute_data(EG(current_execute_data));
647 const zend_op_array *op_array = &ex->func->op_array;
648 const zend_op *opline = op_array->opcodes;
649
650 PHPDBG_G(seek_ex) = ex;
651 do {
652 switch (opline->opcode) {
653 case ZEND_RETURN:
654 case ZEND_FAST_RET:
655 case ZEND_GENERATOR_RETURN:
656 case ZEND_EXIT:
657 case ZEND_YIELD:
658 case ZEND_YIELD_FROM:
659 zend_hash_index_update_ptr(&PHPDBG_G(seek), (zend_ulong) opline, (void *) opline);
660 }
661 } while (++opline < op_array->opcodes + op_array->last);
662 }
663 /* }}} */
664
PHPDBG_COMMAND(finish)665 PHPDBG_COMMAND(finish) /* {{{ */
666 {
667 if (!PHPDBG_G(in_execution)) {
668 phpdbg_error("Not executing");
669 return SUCCESS;
670 }
671
672 phpdbg_seek_to_end();
673 if (zend_hash_index_exists(&PHPDBG_G(seek), (zend_ulong) phpdbg_user_execute_data(EG(current_execute_data))->opline)) {
674 zend_hash_clean(&PHPDBG_G(seek));
675 } else {
676 PHPDBG_G(flags) |= PHPDBG_IN_FINISH;
677 }
678
679 return PHPDBG_FINISH;
680 } /* }}} */
681
PHPDBG_COMMAND(leave)682 PHPDBG_COMMAND(leave) /* {{{ */
683 {
684 if (!PHPDBG_G(in_execution)) {
685 phpdbg_error("Not executing");
686 return SUCCESS;
687 }
688
689 phpdbg_seek_to_end();
690 if (zend_hash_index_exists(&PHPDBG_G(seek), (zend_ulong) phpdbg_user_execute_data(EG(current_execute_data))->opline)) {
691 zend_hash_clean(&PHPDBG_G(seek));
692 phpdbg_notice("Already at the end of the function");
693 return SUCCESS;
694 } else {
695 PHPDBG_G(flags) |= PHPDBG_IN_LEAVE;
696 return PHPDBG_LEAVE;
697 }
698 } /* }}} */
699
PHPDBG_COMMAND(frame)700 PHPDBG_COMMAND(frame) /* {{{ */
701 {
702 if (!param) {
703 phpdbg_notice("Currently in frame #%d", PHPDBG_G(frame).num);
704 } else {
705 phpdbg_switch_frame(param->num);
706 }
707
708 return SUCCESS;
709 } /* }}} */
710
phpdbg_handle_exception(void)711 static inline void phpdbg_handle_exception(void) /* {{{ */
712 {
713 zend_object *ex = EG(exception);
714 zend_string *msg, *file;
715 zend_long line;
716 zval rv, tmp;
717
718 EG(exception) = NULL;
719
720 zend_call_known_instance_method_with_0_params(ex->ce->__tostring, ex, &tmp);
721 file = zval_get_string(zend_read_property(zend_get_exception_base(ex), ex, ZEND_STRL("file"), 1, &rv));
722 line = zval_get_long(zend_read_property(zend_get_exception_base(ex), ex, ZEND_STRL("line"), 1, &rv));
723
724 if (EG(exception)) {
725 EG(exception) = NULL;
726 msg = ZSTR_EMPTY_ALLOC();
727 } else {
728 zend_update_property_string(zend_get_exception_base(ex), ex, ZEND_STRL("string"), Z_STRVAL(tmp));
729 zval_ptr_dtor(&tmp);
730 msg = zval_get_string(zend_read_property(zend_get_exception_base(ex), ex, ZEND_STRL("string"), 1, &rv));
731 }
732
733 phpdbg_error("Uncaught %s in %s on line " ZEND_LONG_FMT, ZSTR_VAL(ex->ce->name), ZSTR_VAL(file), line);
734 zend_string_release(file);
735 phpdbg_writeln("%s", ZSTR_VAL(msg));
736 zend_string_release(msg);
737
738 if (EG(prev_exception)) {
739 OBJ_RELEASE(EG(prev_exception));
740 EG(prev_exception) = 0;
741 }
742 OBJ_RELEASE(ex);
743 EG(opline_before_exception) = NULL;
744
745 EG(exit_status) = 255;
746 } /* }}} */
747
PHPDBG_COMMAND(run)748 PHPDBG_COMMAND(run) /* {{{ */
749 {
750 if (PHPDBG_G(ops) || PHPDBG_G(exec)) {
751 zend_execute_data *ex = EG(current_execute_data);
752 bool restore = 1;
753
754 if (PHPDBG_G(in_execution)) {
755 if (phpdbg_ask_user_permission("Do you really want to restart execution?") == SUCCESS) {
756 phpdbg_startup_run++;
757 phpdbg_clean(1, 1);
758 }
759 return SUCCESS;
760 }
761
762 if (!PHPDBG_G(ops)) {
763 if (phpdbg_compile() == FAILURE) {
764 phpdbg_error("Failed to compile %s, cannot run", PHPDBG_G(exec));
765 EG(exit_status) = FAILURE;
766 goto out;
767 }
768 }
769
770 if (param && param->type != EMPTY_PARAM && param->len != 0) {
771 char **argv = emalloc(5 * sizeof(char *));
772 char *end = param->str + param->len, *p = param->str;
773 char last_byte;
774 int argc = 0;
775 int i;
776
777 while (*end == '\r' || *end == '\n') *(end--) = 0;
778 last_byte = end[1];
779 end[1] = 0;
780
781 while (*p == ' ') p++;
782 while (*p) {
783 char sep = ' ';
784 char *buf = emalloc(end - p + 2), *q = buf;
785
786 if (*p == '<') {
787 /* use as STDIN */
788 do p++; while (*p == ' ');
789
790 if (*p == '\'' || *p == '"') {
791 sep = *(p++);
792 }
793 while (*p && *p != sep) {
794 if (*p == '\\' && (p[1] == sep || p[1] == '\\')) {
795 p++;
796 }
797 *(q++) = *(p++);
798 }
799 *(q++) = 0;
800 if (*p) {
801 do p++; while (*p == ' ');
802 }
803
804 if (*p) {
805 phpdbg_error("Invalid run command, cannot put further arguments after stdin");
806 goto free_cmd;
807 }
808
809 PHPDBG_G(stdin_file) = fopen(buf, "r");
810 if (PHPDBG_G(stdin_file) == NULL) {
811 phpdbg_error("Could not open '%s' for reading from stdin", buf);
812 goto free_cmd;
813 }
814 efree(buf);
815 phpdbg_register_file_handles();
816 break;
817 }
818
819 if (argc >= 4 && argc == (argc & -argc)) {
820 argv = erealloc(argv, (argc * 2 + 1) * sizeof(char *));
821 }
822
823 if (*p == '\'' || *p == '"') {
824 sep = *(p++);
825 }
826 if (*p == '\\' && (p[1] == '<' || p[1] == '\'' || p[1] == '"')) {
827 p++;
828 }
829 while (*p && *p != sep) {
830 if (*p == '\\' && (p[1] == sep || p[1] == '\\' || (p[1] == '#' && sep == ' '))) {
831 p++;
832 }
833 *(q++) = *(p++);
834 }
835 if (!*p && sep != ' ') {
836 phpdbg_error("Invalid run command, unterminated escape sequence");
837 free_cmd:
838 efree(buf);
839 for (i = 0; i < argc; i++) {
840 efree(argv[i]);
841 }
842 efree(argv);
843 end[1] = last_byte;
844 return SUCCESS;
845 }
846
847 *(q++) = 0;
848 argv[++argc] = erealloc(buf, q - buf);
849
850 if (*p) {
851 do p++; while (*p == ' ');
852 }
853 }
854 end[1] = last_byte;
855
856 argv[0] = SG(request_info).argv[0];
857 for (i = SG(request_info).argc; --i;) {
858 efree(SG(request_info).argv[i]);
859 }
860 efree(SG(request_info).argv);
861 SG(request_info).argv = erealloc(argv, ++argc * sizeof(char *));
862 SG(request_info).argc = argc;
863
864 php_build_argv(NULL, &PG(http_globals)[TRACK_VARS_SERVER]);
865 }
866
867 /* clean up from last execution */
868 if (ex && (ZEND_CALL_INFO(ex) & ZEND_CALL_HAS_SYMBOL_TABLE)) {
869 zend_hash_clean(ex->symbol_table);
870 } else {
871 zend_rebuild_symbol_table();
872 }
873 PHPDBG_G(handled_exception) = NULL;
874
875 /* clean seek state */
876 PHPDBG_G(flags) &= ~PHPDBG_SEEK_MASK;
877 zend_hash_clean(&PHPDBG_G(seek));
878
879 /* reset hit counters */
880 phpdbg_reset_breakpoints();
881
882 zend_try {
883 PHPDBG_G(flags) ^= PHPDBG_IS_INTERACTIVE;
884 PHPDBG_G(flags) |= PHPDBG_IS_RUNNING;
885 zend_execute(PHPDBG_G(ops), &PHPDBG_G(retval));
886 PHPDBG_G(flags) ^= PHPDBG_IS_INTERACTIVE;
887 } zend_catch {
888 PHPDBG_G(in_execution) = 0;
889
890 if (!(PHPDBG_G(flags) & PHPDBG_IS_STOPPING)) {
891 restore = 0;
892 } else {
893 zend_bailout();
894 }
895 } zend_end_try();
896
897 if (restore) {
898 zend_exception_restore();
899 zend_try {
900 zend_try_exception_handler();
901 PHPDBG_G(in_execution) = 1;
902 } zend_catch {
903 PHPDBG_G(in_execution) = 0;
904
905 if (PHPDBG_G(flags) & PHPDBG_IS_STOPPING) {
906 zend_bailout();
907 }
908 } zend_end_try();
909
910 if (EG(exception)) {
911 phpdbg_handle_exception();
912 }
913 }
914
915 PHPDBG_G(flags) &= ~PHPDBG_IS_RUNNING;
916
917 phpdbg_clean(1, 0);
918 } else {
919 phpdbg_error("Nothing to execute!");
920 }
921
922 out:
923 PHPDBG_FRAME(num) = 0;
924 return SUCCESS;
925 } /* }}} */
926
phpdbg_output_ev_variable(char * name,size_t len,char * keyname,size_t keylen,HashTable * parent,zval * zv)927 int phpdbg_output_ev_variable(char *name, size_t len, char *keyname, size_t keylen, HashTable *parent, zval *zv) /* {{{ */ {
928 phpdbg_notice("Printing variable %.*s", (int) len, name);
929
930 zend_print_zval_r(zv, 0);
931
932 phpdbg_out("\n");
933
934 efree(name);
935 efree(keyname);
936
937 return SUCCESS;
938 }
939 /* }}} */
940
PHPDBG_COMMAND(ev)941 PHPDBG_COMMAND(ev) /* {{{ */
942 {
943 bool stepping = ((PHPDBG_G(flags) & PHPDBG_IS_STEPPING) == PHPDBG_IS_STEPPING);
944 zval retval;
945
946 zend_execute_data *original_execute_data = EG(current_execute_data);
947 zend_vm_stack original_stack = EG(vm_stack);
948 zend_object *ex = NULL;
949
950 PHPDBG_OUTPUT_BACKUP();
951
952 original_stack->top = EG(vm_stack_top);
953
954 if (PHPDBG_G(flags) & PHPDBG_IN_SIGNAL_HANDLER) {
955 phpdbg_try_access {
956 phpdbg_parse_variable(param->str, param->len, &EG(symbol_table), 0, phpdbg_output_ev_variable, 0);
957 } phpdbg_catch_access {
958 phpdbg_error("Could not fetch data, invalid data source");
959 } phpdbg_end_try_access();
960
961 PHPDBG_OUTPUT_BACKUP_RESTORE();
962 return SUCCESS;
963 }
964
965 if (!(PHPDBG_G(flags) & PHPDBG_IS_STEPONEVAL)) {
966 PHPDBG_G(flags) &= ~PHPDBG_IS_STEPPING;
967 }
968
969 /* disable stepping while eval() in progress */
970 PHPDBG_G(flags) |= PHPDBG_IN_EVAL;
971 zend_try {
972 if (zend_eval_stringl(param->str, param->len, &retval, "eval()'d code") == SUCCESS) {
973 if (EG(exception)) {
974 ex = EG(exception);
975 zend_exception_error(EG(exception), E_ERROR);
976 } else {
977 zend_print_zval_r(&retval, 0);
978 phpdbg_out("\n");
979 zval_ptr_dtor(&retval);
980 }
981 }
982 } zend_catch {
983 PHPDBG_G(unclean_eval) = 1;
984 if (ex) {
985 OBJ_RELEASE(ex);
986 }
987 EG(current_execute_data) = original_execute_data;
988 EG(vm_stack_top) = original_stack->top;
989 EG(vm_stack_end) = original_stack->end;
990 EG(vm_stack) = original_stack;
991 EG(exit_status) = 0;
992 } zend_end_try();
993
994 PHPDBG_G(flags) &= ~PHPDBG_IN_EVAL;
995
996 /* switch stepping back on */
997 if (stepping && !(PHPDBG_G(flags) & PHPDBG_IS_STEPONEVAL)) {
998 PHPDBG_G(flags) |= PHPDBG_IS_STEPPING;
999 }
1000
1001 CG(unclean_shutdown) = 0;
1002
1003 PHPDBG_OUTPUT_BACKUP_RESTORE();
1004
1005 return SUCCESS;
1006 } /* }}} */
1007
PHPDBG_COMMAND(back)1008 PHPDBG_COMMAND(back) /* {{{ */
1009 {
1010 if (!PHPDBG_G(in_execution)) {
1011 phpdbg_error("Not executing!");
1012 return SUCCESS;
1013 }
1014
1015 if (!param) {
1016 phpdbg_dump_backtrace(0);
1017 } else {
1018 phpdbg_dump_backtrace(param->num);
1019 }
1020
1021 return SUCCESS;
1022 } /* }}} */
1023
PHPDBG_COMMAND(generator)1024 PHPDBG_COMMAND(generator) /* {{{ */
1025 {
1026 int i;
1027
1028 if (!PHPDBG_G(in_execution)) {
1029 phpdbg_error("Not executing!");
1030 return SUCCESS;
1031 }
1032
1033 if (param) {
1034 i = param->num;
1035 zend_object **obj = EG(objects_store).object_buckets + i;
1036 if (i < EG(objects_store).top && *obj && IS_OBJ_VALID(*obj) && (*obj)->ce == zend_ce_generator) {
1037 zend_generator *gen = (zend_generator *) *obj;
1038 if (gen->execute_data) {
1039 if (zend_generator_get_current(gen)->flags & ZEND_GENERATOR_CURRENTLY_RUNNING) {
1040 phpdbg_error("Generator currently running");
1041 } else {
1042 phpdbg_open_generator_frame(gen);
1043 }
1044 } else {
1045 phpdbg_error("Generator already closed");
1046 }
1047 } else {
1048 phpdbg_error("Invalid object handle");
1049 }
1050 } else {
1051 for (i = 0; i < EG(objects_store).top; i++) {
1052 zend_object *obj = EG(objects_store).object_buckets[i];
1053 if (obj && IS_OBJ_VALID(obj) && obj->ce == zend_ce_generator) {
1054 zend_generator *gen = (zend_generator *) obj, *current = zend_generator_get_current(gen);
1055 if (gen->execute_data) {
1056 zend_string *s = phpdbg_compile_stackframe(gen->execute_data);
1057 phpdbg_out("#%d: %.*s", i, (int) ZSTR_LEN(s), ZSTR_VAL(s));
1058 zend_string_release(s);
1059 if (gen != current) {
1060 if (gen->node.parent != current) {
1061 phpdbg_out(" with direct parent #%d and", gen->node.parent->std.handle);
1062 }
1063 phpdbg_out(" executing #%d currently", current->std.handle);
1064 }
1065 phpdbg_out("\n");
1066 }
1067 }
1068 }
1069 }
1070
1071 return SUCCESS;
1072 } /* }}} */
1073
PHPDBG_COMMAND(print)1074 PHPDBG_COMMAND(print) /* {{{ */
1075 {
1076 if (!param || param->type == EMPTY_PARAM) {
1077 return phpdbg_do_print_stack(param);
1078 } else switch (param->type) {
1079 case STR_PARAM:
1080 return phpdbg_do_print_func(param);
1081 case METHOD_PARAM:
1082 return phpdbg_do_print_method(param);
1083 default:
1084 phpdbg_error("Invalid arguments to print, expected nothing, function name or method name");
1085 return SUCCESS;
1086 }
1087 } /* }}} */
1088
PHPDBG_COMMAND(info)1089 PHPDBG_COMMAND(info) /* {{{ */
1090 {
1091 phpdbg_out("Execution Context Information\n\n");
1092 #ifdef HAVE_PHPDBG_READLINE
1093 # ifdef HAVE_LIBREADLINE
1094 phpdbg_writeln( "Readline yes");
1095 # else
1096 phpdbg_writeln("Readline no");
1097 # endif
1098 # ifdef HAVE_LIBEDIT
1099 phpdbg_writeln("Libedit yes");
1100 # else
1101 phpdbg_writeln("Libedit no");
1102 # endif
1103 #else
1104 phpdbg_writeln("Readline unavailable");
1105 #endif
1106
1107 phpdbg_writeln("Exec %s", PHPDBG_G(exec) ? PHPDBG_G(exec) : "none");
1108 phpdbg_writeln("Compiled %s", PHPDBG_G(ops) ? "yes" : "no");
1109 phpdbg_writeln("Stepping %s", (PHPDBG_G(flags) & PHPDBG_IS_STEPPING) ? "on" : "off");
1110 phpdbg_writeln("Quietness %s", (PHPDBG_G(flags) & PHPDBG_IS_QUIET) ? "on" : "off");
1111
1112 if (PHPDBG_G(ops)) {
1113 phpdbg_writeln("Opcodes %d", PHPDBG_G(ops)->last);
1114 phpdbg_writeln("Variables %d", PHPDBG_G(ops)->last_var ? PHPDBG_G(ops)->last_var - 1 : 0);
1115 }
1116
1117 phpdbg_writeln("Executing %s", PHPDBG_G(in_execution) ? "yes" : "no");
1118 if (PHPDBG_G(in_execution)) {
1119 phpdbg_writeln("VM Return %d", PHPDBG_G(vmret));
1120 }
1121
1122 phpdbg_writeln("Classes %d", zend_hash_num_elements(EG(class_table)));
1123 phpdbg_writeln("Functions %d", zend_hash_num_elements(EG(function_table)));
1124 phpdbg_writeln("Constants %d", zend_hash_num_elements(EG(zend_constants)));
1125 phpdbg_writeln("Included %d", zend_hash_num_elements(&EG(included_files)));
1126
1127 return SUCCESS;
1128 } /* }}} */
1129
PHPDBG_COMMAND(set)1130 PHPDBG_COMMAND(set) /* {{{ */
1131 {
1132 phpdbg_error("No set command selected!");
1133
1134 return SUCCESS;
1135 } /* }}} */
1136
PHPDBG_COMMAND(break)1137 PHPDBG_COMMAND(break) /* {{{ */
1138 {
1139 if (!param) {
1140 if (PHPDBG_G(exec)) {
1141 phpdbg_set_breakpoint_file(
1142 zend_get_executed_filename(),
1143 strlen(zend_get_executed_filename()),
1144 zend_get_executed_lineno());
1145 } else {
1146 phpdbg_error("Execution context not set!");
1147 }
1148 } else switch (param->type) {
1149 case ADDR_PARAM:
1150 phpdbg_set_breakpoint_opline(param->addr);
1151 break;
1152 case NUMERIC_PARAM:
1153 if (PHPDBG_G(exec)) {
1154 phpdbg_set_breakpoint_file(phpdbg_current_file(), strlen(phpdbg_current_file()), param->num);
1155 } else {
1156 phpdbg_error("Execution context not set!");
1157 }
1158 break;
1159 case METHOD_PARAM:
1160 phpdbg_set_breakpoint_method(param->method.class, param->method.name);
1161 break;
1162 case NUMERIC_METHOD_PARAM:
1163 phpdbg_set_breakpoint_method_opline(param->method.class, param->method.name, param->num);
1164 break;
1165 case NUMERIC_FUNCTION_PARAM:
1166 phpdbg_set_breakpoint_function_opline(param->str, param->num);
1167 break;
1168 case FILE_PARAM:
1169 phpdbg_set_breakpoint_file(param->file.name, 0, param->file.line);
1170 break;
1171 case NUMERIC_FILE_PARAM:
1172 phpdbg_set_breakpoint_file_opline(param->file.name, param->file.line);
1173 break;
1174 case COND_PARAM:
1175 phpdbg_set_breakpoint_expression(param->str, param->len);
1176 break;
1177 case STR_PARAM:
1178 phpdbg_set_breakpoint_symbol(param->str, param->len);
1179 break;
1180 case OP_PARAM:
1181 phpdbg_set_breakpoint_opcode(param->str, param->len);
1182 break;
1183
1184 phpdbg_default_switch_case();
1185 }
1186
1187 return SUCCESS;
1188 } /* }}} */
1189
PHPDBG_COMMAND(sh)1190 PHPDBG_COMMAND(sh) /* {{{ */
1191 {
1192 FILE *fd = NULL;
1193 if ((fd=VCWD_POPEN((char*)param->str, "w"))) {
1194 /* TODO: do something perhaps ?? do we want input ?? */
1195 pclose(fd);
1196 } else {
1197 phpdbg_error("Failed to execute %s", param->str);
1198 }
1199
1200 return SUCCESS;
1201 } /* }}} */
1202
add_module_info(zend_module_entry * module)1203 static int add_module_info(zend_module_entry *module) /* {{{ */ {
1204 phpdbg_write("%s\n", module->name);
1205 return 0;
1206 }
1207 /* }}} */
1208
add_zendext_info(zend_extension * ext)1209 static void add_zendext_info(zend_extension *ext) /* {{{ */ {
1210 phpdbg_write("%s\n", ext->name);
1211 }
1212 /* }}} */
1213
1214 #ifdef HAVE_LIBDL
phpdbg_load_module_or_extension(char ** path,const char ** name)1215 PHPDBG_API const char *phpdbg_load_module_or_extension(char **path, const char **name) /* {{{ */ {
1216 DL_HANDLE handle;
1217 char *extension_dir;
1218
1219 extension_dir = INI_STR("extension_dir");
1220
1221 if (strchr(*path, '/') != NULL || strchr(*path, DEFAULT_SLASH) != NULL) {
1222 /* path is fine */
1223 } else if (extension_dir && extension_dir[0]) {
1224 char *libpath;
1225 int extension_dir_len = strlen(extension_dir);
1226 if (IS_SLASH(extension_dir[extension_dir_len-1])) {
1227 spprintf(&libpath, 0, "%s%s", extension_dir, *path); /* SAFE */
1228 } else {
1229 spprintf(&libpath, 0, "%s%c%s", extension_dir, DEFAULT_SLASH, *path); /* SAFE */
1230 }
1231 efree(*path);
1232 *path = libpath;
1233 } else {
1234 phpdbg_error("Not a full path given or extension_dir ini setting is not set");
1235
1236 return NULL;
1237 }
1238
1239 handle = DL_LOAD(*path);
1240
1241 if (!handle) {
1242 #ifdef PHP_WIN32
1243 char *err = GET_DL_ERROR();
1244 if (err && err[0]) {
1245 phpdbg_error("%s", err);
1246 php_win32_error_msg_free(err);
1247 } else {
1248 phpdbg_error("Unknown reason");
1249 }
1250 #else
1251 phpdbg_error("%s", GET_DL_ERROR());
1252 #endif
1253 return NULL;
1254 }
1255
1256 #if ZEND_EXTENSIONS_SUPPORT
1257 do {
1258 zend_extension *new_extension;
1259 zend_extension_version_info *extension_version_info;
1260
1261 extension_version_info = (zend_extension_version_info *) DL_FETCH_SYMBOL(handle, "extension_version_info");
1262 if (!extension_version_info) {
1263 extension_version_info = (zend_extension_version_info *) DL_FETCH_SYMBOL(handle, "_extension_version_info");
1264 }
1265 new_extension = (zend_extension *) DL_FETCH_SYMBOL(handle, "zend_extension_entry");
1266 if (!new_extension) {
1267 new_extension = (zend_extension *) DL_FETCH_SYMBOL(handle, "_zend_extension_entry");
1268 }
1269 if (!extension_version_info || !new_extension) {
1270 break;
1271 }
1272 if (extension_version_info->zend_extension_api_no != ZEND_EXTENSION_API_NO &&(!new_extension->api_no_check || new_extension->api_no_check(ZEND_EXTENSION_API_NO) != SUCCESS)) {
1273 phpdbg_error("%s requires Zend Engine API version %d, which does not match the installed Zend Engine API version %d", new_extension->name, extension_version_info->zend_extension_api_no, ZEND_EXTENSION_API_NO);
1274
1275 goto quit;
1276 } else if (strcmp(ZEND_EXTENSION_BUILD_ID, extension_version_info->build_id) && (!new_extension->build_id_check || new_extension->build_id_check(ZEND_EXTENSION_BUILD_ID) != SUCCESS)) {
1277 phpdbg_error("%s was built with configuration %s, whereas running engine is %s", new_extension->name, extension_version_info->build_id, ZEND_EXTENSION_BUILD_ID);
1278
1279 goto quit;
1280 }
1281
1282 *name = new_extension->name;
1283
1284 zend_register_extension(new_extension, handle);
1285
1286 if (new_extension->startup) {
1287 if (new_extension->startup(new_extension) != SUCCESS) {
1288 phpdbg_error("Unable to startup Zend extension %s", new_extension->name);
1289
1290 goto quit;
1291 }
1292 zend_append_version_info(new_extension);
1293 }
1294
1295 return "Zend extension";
1296 } while (0);
1297 #endif
1298
1299 do {
1300 zend_module_entry *module_entry;
1301 zend_module_entry *(*get_module)(void);
1302
1303 get_module = (zend_module_entry *(*)(void)) DL_FETCH_SYMBOL(handle, "get_module");
1304 if (!get_module) {
1305 get_module = (zend_module_entry *(*)(void)) DL_FETCH_SYMBOL(handle, "_get_module");
1306 }
1307
1308 if (!get_module) {
1309 break;
1310 }
1311
1312 module_entry = get_module();
1313 *name = module_entry->name;
1314
1315 if (strcmp(ZEND_EXTENSION_BUILD_ID, module_entry->build_id)) {
1316 phpdbg_error("%s was built with configuration %s, whereas running engine is %s", module_entry->name, module_entry->build_id, ZEND_EXTENSION_BUILD_ID);
1317
1318 goto quit;
1319 }
1320
1321 module_entry->type = MODULE_PERSISTENT;
1322 module_entry->module_number = zend_next_free_module();
1323 module_entry->handle = handle;
1324
1325 if ((module_entry = zend_register_module_ex(module_entry)) == NULL) {
1326 phpdbg_error("Unable to register module %s", *name);
1327
1328 goto quit;
1329 }
1330
1331 if (zend_startup_module_ex(module_entry) == FAILURE) {
1332 phpdbg_error("Unable to startup module %s", module_entry->name);
1333
1334 goto quit;
1335 }
1336
1337 if (module_entry->request_startup_func) {
1338 if (module_entry->request_startup_func(MODULE_PERSISTENT, module_entry->module_number) == FAILURE) {
1339 phpdbg_error("Unable to initialize module %s", module_entry->name);
1340
1341 goto quit;
1342 }
1343 }
1344
1345 return "module";
1346 } while (0);
1347
1348 phpdbg_error("This shared object is nor a Zend extension nor a module");
1349
1350 quit:
1351 DL_UNLOAD(handle);
1352 return NULL;
1353 }
1354 /* }}} */
1355 #endif
1356
PHPDBG_COMMAND(dl)1357 PHPDBG_COMMAND(dl) /* {{{ */
1358 {
1359 const char *type, *name;
1360 char *path;
1361
1362 if (!param || param->type == EMPTY_PARAM) {
1363 phpdbg_notice("Zend extensions");
1364 zend_llist_apply(&zend_extensions, (llist_apply_func_t) add_zendext_info);
1365 phpdbg_out("\n");
1366 phpdbg_notice("Modules");
1367 zend_hash_apply(&module_registry, (apply_func_t) add_module_info);
1368 } else switch (param->type) {
1369 case STR_PARAM:
1370 #ifdef HAVE_LIBDL
1371 path = estrndup(param->str, param->len);
1372
1373 phpdbg_activate_err_buf(1);
1374 if ((type = phpdbg_load_module_or_extension(&path, &name)) == NULL) {
1375 phpdbg_error("Could not load %s, not found or invalid zend extension / module: %s", path, PHPDBG_G(err_buf).msg);
1376 } else {
1377 phpdbg_notice("Successfully loaded the %s %s at path %s", type, name, path);
1378 }
1379 phpdbg_activate_err_buf(0);
1380 phpdbg_free_err_buf();
1381 efree(path);
1382 #else
1383 phpdbg_error("Cannot dynamically load %.*s - dynamic modules are not supported", (int) param->len, param->str);
1384 #endif
1385 break;
1386
1387 phpdbg_default_switch_case();
1388 }
1389
1390 return SUCCESS;
1391 } /* }}} */
1392
PHPDBG_COMMAND(source)1393 PHPDBG_COMMAND(source) /* {{{ */
1394 {
1395 zend_stat_t sb;
1396
1397 if (VCWD_STAT(param->str, &sb) != -1) {
1398 phpdbg_try_file_init(param->str, param->len, 0);
1399 } else {
1400 phpdbg_error("Failed to stat %s, file does not exist", param->str);
1401 }
1402
1403 return SUCCESS;
1404 } /* }}} */
1405
PHPDBG_COMMAND(export)1406 PHPDBG_COMMAND(export) /* {{{ */
1407 {
1408 FILE *handle = VCWD_FOPEN(param->str, "w+");
1409
1410 if (handle) {
1411 phpdbg_export_breakpoints(handle);
1412 fclose(handle);
1413 } else {
1414 phpdbg_error("Failed to open or create %s, check path and permissions", param->str);
1415 }
1416
1417 return SUCCESS;
1418 } /* }}} */
1419
PHPDBG_COMMAND(register)1420 PHPDBG_COMMAND(register) /* {{{ */
1421 {
1422 zend_function *function;
1423 char *lcname = zend_str_tolower_dup(param->str, param->len);
1424 size_t lcname_len = strlen(lcname);
1425
1426 if (!zend_hash_str_exists(&PHPDBG_G(registered), lcname, lcname_len)) {
1427 if ((function = zend_hash_str_find_ptr(EG(function_table), lcname, lcname_len))) {
1428 zend_hash_str_update_ptr(&PHPDBG_G(registered), lcname, lcname_len, function);
1429 function_add_ref(function);
1430
1431 phpdbg_notice("Registered %s", lcname);
1432 } else {
1433 phpdbg_error("The requested function (%s) could not be found", param->str);
1434 }
1435 } else {
1436 phpdbg_error("The requested name (%s) is already in use", lcname);
1437 }
1438
1439 efree(lcname);
1440 return SUCCESS;
1441 } /* }}} */
1442
PHPDBG_COMMAND(quit)1443 PHPDBG_COMMAND(quit) /* {{{ */
1444 {
1445 PHPDBG_G(flags) |= PHPDBG_IS_QUITTING;
1446 PHPDBG_G(flags) &= ~PHPDBG_IS_CLEANING;
1447
1448 return SUCCESS;
1449 } /* }}} */
1450
PHPDBG_COMMAND(clean)1451 PHPDBG_COMMAND(clean) /* {{{ */
1452 {
1453 if (PHPDBG_G(in_execution)) {
1454 if (phpdbg_ask_user_permission("Do you really want to clean your current environment?") == FAILURE) {
1455 return SUCCESS;
1456 }
1457 }
1458
1459 phpdbg_out("Cleaning Execution Environment\n");
1460
1461 phpdbg_writeln("Classes %d", zend_hash_num_elements(EG(class_table)));
1462 phpdbg_writeln("Functions %d", zend_hash_num_elements(EG(function_table)));
1463 phpdbg_writeln("Constants %d", zend_hash_num_elements(EG(zend_constants)));
1464 phpdbg_writeln("Includes %d", zend_hash_num_elements(&EG(included_files)));
1465
1466 phpdbg_clean(1, 0);
1467
1468 return SUCCESS;
1469 } /* }}} */
1470
PHPDBG_COMMAND(clear)1471 PHPDBG_COMMAND(clear) /* {{{ */
1472 {
1473 phpdbg_out("Clearing Breakpoints\n");
1474
1475 phpdbg_writeln("File %d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE]));
1476 phpdbg_writeln("Functions %d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM]));
1477 phpdbg_writeln("Methods %d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD]));
1478 phpdbg_writeln("Oplines %d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]));
1479 phpdbg_writeln("File oplines %d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE]));
1480 phpdbg_writeln("Function oplines %d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE]));
1481 phpdbg_writeln("Method oplines %d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE]));
1482 phpdbg_writeln("Conditionals %d", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_COND]));
1483
1484 phpdbg_clear_breakpoints();
1485
1486 return SUCCESS;
1487 } /* }}} */
1488
PHPDBG_COMMAND(list)1489 PHPDBG_COMMAND(list) /* {{{ */
1490 {
1491 if (!param) {
1492 return PHPDBG_LIST_HANDLER(lines)(PHPDBG_COMMAND_ARGS);
1493 } else switch (param->type) {
1494 case NUMERIC_PARAM:
1495 return PHPDBG_LIST_HANDLER(lines)(PHPDBG_COMMAND_ARGS);
1496
1497 case FILE_PARAM:
1498 return PHPDBG_LIST_HANDLER(lines)(PHPDBG_COMMAND_ARGS);
1499
1500 case STR_PARAM:
1501 phpdbg_list_function_byname(param->str, param->len);
1502 break;
1503
1504 case METHOD_PARAM:
1505 return PHPDBG_LIST_HANDLER(method)(PHPDBG_COMMAND_ARGS);
1506
1507 phpdbg_default_switch_case();
1508 }
1509
1510 return SUCCESS;
1511 } /* }}} */
1512
PHPDBG_COMMAND(watch)1513 PHPDBG_COMMAND(watch) /* {{{ */
1514 {
1515 if (!param || param->type == EMPTY_PARAM) {
1516 phpdbg_list_watchpoints();
1517 } else switch (param->type) {
1518 case STR_PARAM:
1519 phpdbg_create_var_watchpoint(param->str, param->len);
1520 break;
1521
1522 phpdbg_default_switch_case();
1523 }
1524
1525 return SUCCESS;
1526 } /* }}} */
1527
phpdbg_interactive(bool allow_async_unsafe,char * input)1528 int phpdbg_interactive(bool allow_async_unsafe, char *input) /* {{{ */
1529 {
1530 int ret = SUCCESS;
1531 phpdbg_param_t stack;
1532
1533 PHPDBG_G(flags) |= PHPDBG_IS_INTERACTIVE;
1534
1535 while (ret == SUCCESS || ret == FAILURE) {
1536 if (PHPDBG_G(flags) & PHPDBG_IS_STOPPING) {
1537 zend_bailout();
1538 }
1539
1540 if (!input && !(input = phpdbg_read_input(NULL))) {
1541 break;
1542 }
1543
1544
1545 phpdbg_init_param(&stack, STACK_PARAM);
1546
1547 if (phpdbg_do_parse(&stack, input) <= 0) {
1548 phpdbg_activate_err_buf(1);
1549
1550 zend_try {
1551 ret = phpdbg_stack_execute(&stack, allow_async_unsafe);
1552 } zend_catch {
1553 phpdbg_stack_free(&stack);
1554 zend_bailout();
1555 } zend_end_try();
1556
1557 switch (ret) {
1558 case FAILURE:
1559 if (!(PHPDBG_G(flags) & PHPDBG_IS_STOPPING)) {
1560 if (!allow_async_unsafe || phpdbg_call_register(&stack) == FAILURE) {
1561 if (PHPDBG_G(err_buf).active) {
1562 phpdbg_output_err_buf("%s", PHPDBG_G(err_buf).msg);
1563 }
1564 }
1565 }
1566 break;
1567
1568 case PHPDBG_LEAVE:
1569 case PHPDBG_FINISH:
1570 case PHPDBG_UNTIL:
1571 case PHPDBG_NEXT: {
1572 phpdbg_activate_err_buf(0);
1573 phpdbg_free_err_buf();
1574 if (!PHPDBG_G(in_execution) && !(PHPDBG_G(flags) & PHPDBG_IS_STOPPING)) {
1575 phpdbg_error("Not running");
1576 }
1577 break;
1578 }
1579 }
1580
1581 phpdbg_activate_err_buf(0);
1582 phpdbg_free_err_buf();
1583 }
1584
1585 phpdbg_stack_free(&stack);
1586 phpdbg_destroy_input(&input);
1587 PHPDBG_G(req_id) = 0;
1588 input = NULL;
1589 }
1590
1591 if (input) {
1592 phpdbg_stack_free(&stack);
1593 phpdbg_destroy_input(&input);
1594 PHPDBG_G(req_id) = 0;
1595 }
1596
1597 if (PHPDBG_G(in_execution)) {
1598 phpdbg_restore_frame();
1599 }
1600
1601 PHPDBG_G(flags) &= ~PHPDBG_IS_INTERACTIVE;
1602
1603 phpdbg_print_changed_zvals();
1604
1605 return ret;
1606 } /* }}} */
1607
list_code(void)1608 static inline void list_code(void) {
1609 if (!(PHPDBG_G(flags) & PHPDBG_IN_EVAL)) {
1610 const char *file_char = zend_get_executed_filename();
1611 zend_string *file = zend_string_init(file_char, strlen(file_char), 0);
1612 phpdbg_list_file(file, 3, zend_get_executed_lineno()-1, zend_get_executed_lineno());
1613 efree(file);
1614 }
1615 }
1616
1617 /* code may behave weirdly if EG(exception) is set; thus backup it */
1618 #define DO_INTERACTIVE(allow_async_unsafe) do { \
1619 if (exception) { \
1620 const zend_op *before_ex = EG(opline_before_exception); \
1621 const zend_op *backup_opline = NULL; \
1622 if (EG(current_execute_data) && EG(current_execute_data)->func && ZEND_USER_CODE(EG(current_execute_data)->func->common.type)) { \
1623 backup_opline = EG(current_execute_data)->opline; \
1624 } \
1625 GC_ADDREF(exception); \
1626 zend_clear_exception(); \
1627 list_code(); \
1628 switch (phpdbg_interactive(allow_async_unsafe, NULL)) { \
1629 case PHPDBG_LEAVE: \
1630 case PHPDBG_FINISH: \
1631 case PHPDBG_UNTIL: \
1632 case PHPDBG_NEXT: \
1633 if (backup_opline \
1634 && (backup_opline->opcode == ZEND_HANDLE_EXCEPTION || backup_opline->opcode == ZEND_CATCH)) { \
1635 EG(current_execute_data)->opline = backup_opline; \
1636 EG(exception) = exception; \
1637 } else { \
1638 zend_throw_exception_internal(exception); \
1639 } \
1640 EG(opline_before_exception) = before_ex; \
1641 } \
1642 } else { \
1643 list_code(); \
1644 phpdbg_interactive(allow_async_unsafe, NULL); \
1645 } \
1646 goto next; \
1647 } while (0)
1648
phpdbg_execute_ex(zend_execute_data * execute_data)1649 void phpdbg_execute_ex(zend_execute_data *execute_data) /* {{{ */
1650 {
1651 bool original_in_execution = PHPDBG_G(in_execution);
1652
1653 if ((PHPDBG_G(flags) & PHPDBG_IS_STOPPING) && !(PHPDBG_G(flags) & PHPDBG_IS_RUNNING)) {
1654 zend_bailout();
1655 }
1656
1657 PHPDBG_G(in_execution) = 1;
1658
1659 while (1) {
1660 zend_object *exception = EG(exception);
1661
1662 if ((PHPDBG_G(flags) & PHPDBG_BP_RESOLVE_MASK)) {
1663 /* resolve nth opline breakpoints */
1664 phpdbg_resolve_op_array_breaks(&execute_data->func->op_array);
1665 }
1666
1667 #ifdef ZEND_WIN32
1668 if (EG(timed_out)) {
1669 zend_timeout();
1670 }
1671 #endif
1672
1673 if (exception && zend_is_unwind_exit(exception)) {
1674 /* Restore bailout based exit. */
1675 zend_bailout();
1676 }
1677
1678 if (PHPDBG_G(flags) & PHPDBG_PREVENT_INTERACTIVE) {
1679 phpdbg_print_opline(execute_data, 0);
1680 goto next;
1681 }
1682
1683 /* check for uncaught exceptions */
1684 if (exception && PHPDBG_G(handled_exception) != exception && !(PHPDBG_G(flags) & PHPDBG_IN_EVAL)) {
1685 zend_execute_data *prev_ex = execute_data;
1686
1687 do {
1688 prev_ex = zend_generator_check_placeholder_frame(prev_ex);
1689 /* assuming that no internal functions will silently swallow exceptions ... */
1690 if (!prev_ex->func || !ZEND_USER_CODE(prev_ex->func->common.type)) {
1691 continue;
1692 }
1693
1694 if (phpdbg_check_caught_ex(prev_ex, exception)) {
1695 goto ex_is_caught;
1696 }
1697 } while ((prev_ex = prev_ex->prev_execute_data));
1698
1699 PHPDBG_G(handled_exception) = exception;
1700
1701 zval rv;
1702 zend_string *file = zval_get_string(zend_read_property(zend_get_exception_base(exception), exception, ZEND_STRL("file"), 1, &rv));
1703 zend_long line = zval_get_long(zend_read_property(zend_get_exception_base(exception), exception, ZEND_STRL("line"), 1, &rv));
1704 zend_string *msg = zval_get_string(zend_read_property(zend_get_exception_base(exception), exception, ZEND_STRL("message"), 1, &rv));
1705
1706 phpdbg_error("Uncaught %s in %s on line " ZEND_LONG_FMT ": %.*s",
1707 ZSTR_VAL(exception->ce->name), ZSTR_VAL(file), line,
1708 ZSTR_LEN(msg) < 80 ? (int) ZSTR_LEN(msg) : 80, ZSTR_VAL(msg));
1709 zend_string_release(msg);
1710 zend_string_release(file);
1711
1712 DO_INTERACTIVE(1);
1713 }
1714 ex_is_caught:
1715
1716 /* allow conditional breakpoints and initialization to access the vm uninterrupted */
1717 if (PHPDBG_G(flags) & (PHPDBG_IN_COND_BP | PHPDBG_IS_INITIALIZING)) {
1718 /* skip possible breakpoints */
1719 goto next;
1720 }
1721
1722 /* not while in conditionals */
1723 phpdbg_print_opline(execute_data, 0);
1724
1725 /* perform seek operation */
1726 if ((PHPDBG_G(flags) & PHPDBG_SEEK_MASK) && !(PHPDBG_G(flags) & PHPDBG_IN_EVAL)) {
1727 /* current address */
1728 zend_ulong address = (zend_ulong) execute_data->opline;
1729
1730 if (PHPDBG_G(seek_ex) != execute_data) {
1731 if (PHPDBG_G(flags) & PHPDBG_IS_STEPPING) {
1732 goto stepping;
1733 }
1734 goto next;
1735 }
1736
1737 #define INDEX_EXISTS_CHECK (zend_hash_index_exists(&PHPDBG_G(seek), address) || (exception && phpdbg_check_caught_ex(execute_data, exception) == 0))
1738
1739 /* run to next line */
1740 if (PHPDBG_G(flags) & PHPDBG_IN_UNTIL) {
1741 if (INDEX_EXISTS_CHECK) {
1742 PHPDBG_G(flags) &= ~PHPDBG_IN_UNTIL;
1743 zend_hash_clean(&PHPDBG_G(seek));
1744 } else {
1745 /* skip possible breakpoints */
1746 goto next;
1747 }
1748 }
1749
1750 /* run to finish */
1751 if (PHPDBG_G(flags) & PHPDBG_IN_FINISH) {
1752 if (INDEX_EXISTS_CHECK) {
1753 PHPDBG_G(flags) &= ~PHPDBG_IN_FINISH;
1754 zend_hash_clean(&PHPDBG_G(seek));
1755 }
1756 /* skip possible breakpoints */
1757 goto next;
1758 }
1759
1760 /* break for leave */
1761 if (PHPDBG_G(flags) & PHPDBG_IN_LEAVE) {
1762 if (INDEX_EXISTS_CHECK) {
1763 PHPDBG_G(flags) &= ~PHPDBG_IN_LEAVE;
1764 zend_hash_clean(&PHPDBG_G(seek));
1765 phpdbg_notice("Breaking for leave at %s:%u",
1766 zend_get_executed_filename(),
1767 zend_get_executed_lineno()
1768 );
1769 DO_INTERACTIVE(1);
1770 } else {
1771 /* skip possible breakpoints */
1772 goto next;
1773 }
1774 }
1775 }
1776
1777 if (PHPDBG_G(flags) & PHPDBG_IS_STEPPING && (PHPDBG_G(flags) & PHPDBG_STEP_OPCODE || execute_data->opline->lineno != PHPDBG_G(last_line))) {
1778 stepping:
1779 PHPDBG_G(flags) &= ~PHPDBG_IS_STEPPING;
1780 DO_INTERACTIVE(1);
1781 }
1782
1783 /* check if some watchpoint was hit */
1784 {
1785 if (phpdbg_print_changed_zvals() == SUCCESS) {
1786 DO_INTERACTIVE(1);
1787 }
1788 }
1789
1790 /* search for breakpoints */
1791 {
1792 phpdbg_breakbase_t *brake;
1793
1794 if ((PHPDBG_G(flags) & PHPDBG_BP_MASK)
1795 && (brake = phpdbg_find_breakpoint(execute_data))
1796 && (brake->type != PHPDBG_BREAK_FILE || execute_data->opline->lineno != PHPDBG_G(last_line))) {
1797 phpdbg_hit_breakpoint(brake, 1);
1798 DO_INTERACTIVE(1);
1799 }
1800 }
1801
1802 if (PHPDBG_G(flags) & PHPDBG_IS_SIGNALED) {
1803 PHPDBG_G(flags) &= ~PHPDBG_IS_SIGNALED;
1804
1805 phpdbg_out("\n");
1806 phpdbg_notice("Program received signal SIGINT");
1807 DO_INTERACTIVE(1);
1808 }
1809
1810 next:
1811
1812 PHPDBG_G(last_line) = execute_data->opline->lineno;
1813
1814 /* stupid hack to make zend_do_fcall_common_helper return ZEND_VM_ENTER() instead of recursively calling zend_execute() and eventually segfaulting */
1815 if ((execute_data->opline->opcode == ZEND_DO_FCALL ||
1816 execute_data->opline->opcode == ZEND_DO_UCALL ||
1817 execute_data->opline->opcode == ZEND_DO_FCALL_BY_NAME) &&
1818 execute_data->call->func->type == ZEND_USER_FUNCTION) {
1819 zend_execute_ex = execute_ex;
1820 }
1821 PHPDBG_G(vmret) = zend_vm_call_opcode_handler(execute_data);
1822 zend_execute_ex = phpdbg_execute_ex;
1823
1824 if (PHPDBG_G(vmret) != 0) {
1825 if (PHPDBG_G(vmret) < 0) {
1826 PHPDBG_G(in_execution) = original_in_execution;
1827 return;
1828 } else {
1829 execute_data = EG(current_execute_data);
1830 }
1831 }
1832 }
1833 zend_error_noreturn(E_ERROR, "Arrived at end of main loop which shouldn't happen");
1834 } /* }}} */
1835
1836 /* only if *not* interactive and while executing */
phpdbg_force_interruption(void)1837 void phpdbg_force_interruption(void) /* {{{ */ {
1838 zend_object *exception = EG(exception);
1839 zend_execute_data *data = EG(current_execute_data); /* should be always readable if not NULL */
1840
1841 PHPDBG_G(flags) |= PHPDBG_IN_SIGNAL_HANDLER;
1842
1843 if (data) {
1844 if (data->func) {
1845 if (ZEND_USER_CODE(data->func->type)) {
1846 phpdbg_notice("Current opline: %p (op #%u) in %s:%u",
1847 data->opline,
1848 (uint32_t) (data->opline - data->func->op_array.opcodes),
1849 data->func->op_array.filename->val,
1850 data->opline->lineno);
1851 } else if (data->func->internal_function.function_name) {
1852 phpdbg_notice("Current opline: in internal function %s",
1853 data->func->internal_function.function_name->val);
1854 } else {
1855 phpdbg_notice("Current opline: executing internal code");
1856 }
1857 } else {
1858 phpdbg_notice("Current opline: %p (op_array information unavailable)",
1859 data->opline);
1860 }
1861 } else {
1862 phpdbg_notice("No information available about executing context");
1863 }
1864
1865 DO_INTERACTIVE(0);
1866
1867 next:
1868 PHPDBG_G(flags) &= ~PHPDBG_IN_SIGNAL_HANDLER;
1869
1870 if (PHPDBG_G(flags) & PHPDBG_IS_STOPPING) {
1871 zend_bailout();
1872 }
1873 }
1874 /* }}} */
1875