summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS3
-rw-r--r--Zend/zend_generators.c10
-rw-r--r--Zend/zend_generators.h3
-rw-r--r--sapi/phpdbg/phpdbg_cmd.h2
-rw-r--r--sapi/phpdbg/phpdbg_frame.c121
-rw-r--r--sapi/phpdbg/phpdbg_frame.h2
-rw-r--r--sapi/phpdbg/phpdbg_help.c73
-rw-r--r--sapi/phpdbg/phpdbg_prompt.c105
-rw-r--r--sapi/phpdbg/phpdbg_prompt.h1
9 files changed, 253 insertions, 67 deletions
diff --git a/NEWS b/NEWS
index 50c862b64d..ff6f5ec67a 100644
--- a/NEWS
+++ b/NEWS
@@ -46,6 +46,9 @@ PHP NEWS
in current rowset haven't been fetched). (Peter LeBrun)
. Ignore potentially misleading dberr values. (Chris Kings-Lynne)
+- phpdbg:
+ . Added generator command for inspection of currently alive generators. (Bob)
+
- Session:
. Fixed bug #73100 (session_destroy null dereference in ps_files_path_create).
(cmb)
diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c
index a238d5b22d..1e6c770b74 100644
--- a/Zend/zend_generators.c
+++ b/Zend/zend_generators.c
@@ -31,7 +31,7 @@ static zend_object_handlers zend_generator_handlers;
static zend_object *zend_generator_create(zend_class_entry *class_type);
-static void zend_restore_call_stack(zend_generator *generator) /* {{{ */
+void zend_generator_restore_call_stack(zend_generator *generator) /* {{{ */
{
zend_execute_data *call, *new_call, *prev_call = NULL;
@@ -57,7 +57,7 @@ static void zend_restore_call_stack(zend_generator *generator) /* {{{ */
}
/* }}} */
-static zend_execute_data* zend_freeze_call_stack(zend_execute_data *execute_data) /* {{{ */
+zend_execute_data* zend_generator_freeze_call_stack(zend_execute_data *execute_data) /* {{{ */
{
size_t used_stack;
zend_execute_data *call, *new_call, *prev_call = NULL;
@@ -106,7 +106,7 @@ static void zend_generator_cleanup_unfinished_execution(
uint32_t op_num = execute_data->opline - execute_data->func->op_array.opcodes - 1;
if (UNEXPECTED(generator->frozen_call_stack)) {
- zend_restore_call_stack(generator);
+ zend_generator_restore_call_stack(generator);
}
zend_cleanup_unfinished_execution(execute_data, op_num, 0);
}
@@ -808,7 +808,7 @@ try_again:
if (UNEXPECTED(generator->frozen_call_stack)) {
/* Restore frozen call-stack */
- zend_restore_call_stack(generator);
+ zend_generator_restore_call_stack(generator);
}
/* Resume execution */
@@ -820,7 +820,7 @@ try_again:
if (EXPECTED(generator->execute_data) &&
UNEXPECTED(generator->execute_data->call)) {
/* Frize call-stack */
- generator->frozen_call_stack = zend_freeze_call_stack(generator->execute_data);
+ generator->frozen_call_stack = zend_generator_freeze_call_stack(generator->execute_data);
}
/* Restore executor globals */
diff --git a/Zend/zend_generators.h b/Zend/zend_generators.h
index 6aabcc6a4d..b74dcca919 100644
--- a/Zend/zend_generators.h
+++ b/Zend/zend_generators.h
@@ -105,6 +105,9 @@ void zend_register_generator_ce(void);
ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished_execution);
ZEND_API void zend_generator_resume(zend_generator *generator);
+void zend_generator_restore_call_stack(zend_generator *generator);
+zend_execute_data* zend_generator_freeze_call_stack(zend_execute_data *execute_data);
+
void zend_generator_yield_from(zend_generator *generator, zend_generator *from);
ZEND_API zend_execute_data *zend_generator_check_placeholder_frame(zend_execute_data *ptr);
diff --git a/sapi/phpdbg/phpdbg_cmd.h b/sapi/phpdbg/phpdbg_cmd.h
index cbf2a8793d..1ecfd62705 100644
--- a/sapi/phpdbg/phpdbg_cmd.h
+++ b/sapi/phpdbg/phpdbg_cmd.h
@@ -22,6 +22,7 @@
#define PHPDBG_CMD_H
#include "TSRM.h"
+#include "zend_generators.h"
/* {{{ Command and Parameter */
enum {
@@ -113,6 +114,7 @@ struct _phpdbg_command_t {
typedef struct {
int num;
+ zend_generator *generator;
zend_execute_data *execute_data;
} phpdbg_frame_t;
/* }}} */
diff --git a/sapi/phpdbg/phpdbg_frame.c b/sapi/phpdbg/phpdbg_frame.c
index f64d18b4bb..85f3341e17 100644
--- a/sapi/phpdbg/phpdbg_frame.c
+++ b/sapi/phpdbg/phpdbg_frame.c
@@ -23,15 +23,95 @@
#include "phpdbg_utils.h"
#include "phpdbg_frame.h"
#include "phpdbg_list.h"
+#include "zend_smart_str.h"
ZEND_EXTERN_MODULE_GLOBALS(phpdbg)
+static inline void phpdbg_append_individual_arg(smart_str *s, uint32_t i, zend_function *func, zval *arg) {
+ const zend_arg_info *arginfo = func->common.arg_info;
+ char *arg_name = NULL;
+
+ if (i) {
+ smart_str_appends(s, ", ");
+ }
+ if (i < func->common.num_args) {
+ if (arginfo) {
+ if (func->type == ZEND_INTERNAL_FUNCTION) {
+ arg_name = (char *) ((zend_internal_arg_info *) &arginfo[i])->name;
+ } else {
+ arg_name = ZSTR_VAL(arginfo[i].name);
+ }
+ }
+ smart_str_appends(s, arg_name ? arg_name : "?");
+ smart_str_appendc(s, '=');
+ }
+ {
+ char *arg_print = phpdbg_short_zval_print(arg, 40);
+ smart_str_appends(s, arg_print);
+ efree(arg_print);
+ }
+}
+
+zend_string *phpdbg_compile_stackframe(zend_execute_data *ex) {
+ smart_str s = {0};
+ zend_op_array *op_array = &ex->func->op_array;
+ uint32_t i = 0, first_extra_arg = op_array->num_args, num_args = ZEND_CALL_NUM_ARGS(ex);
+ zval *p = ZEND_CALL_ARG(ex, 1);
+
+ if (op_array->scope) {
+ smart_str_append(&s, op_array->scope->name);
+ smart_str_appends(&s, "::");
+ }
+ smart_str_append(&s, op_array->function_name);
+ smart_str_appendc(&s, '(');
+ if (ZEND_CALL_NUM_ARGS(ex) > first_extra_arg) {
+ while (i < first_extra_arg) {
+ phpdbg_append_individual_arg(&s, i, ex->func, p);
+ p++;
+ i++;
+ }
+ p = ZEND_CALL_VAR_NUM(ex, op_array->last_var + op_array->T);
+ }
+ while (i < num_args) {
+ phpdbg_append_individual_arg(&s, i, ex->func, p);
+ p++;
+ i++;
+ }
+ smart_str_appendc(&s, ')');
+
+ if (ex->func->type == ZEND_USER_FUNCTION) {
+ smart_str_appends(&s, " at ");
+ smart_str_append(&s, op_array->filename);
+ smart_str_appendc(&s, ':');
+ smart_str_append_unsigned(&s, ex->opline->lineno);
+ } else {
+ smart_str_appends(&s, " [internal function]");
+ }
+
+ return s.s;
+}
+
+void phpdbg_print_cur_frame_info() {
+ const char *file_chr = zend_get_executed_filename();
+ zend_string *file = zend_string_init(file_chr, strlen(file_chr), 0);
+
+ phpdbg_list_file(file, 3, zend_get_executed_lineno() - 1, zend_get_executed_lineno());
+ efree(file);
+}
+
void phpdbg_restore_frame(void) /* {{{ */
{
if (PHPDBG_FRAME(num) == 0) {
return;
}
+ if (PHPDBG_FRAME(generator)) {
+ if (PHPDBG_FRAME(generator)->execute_data->call) {
+ PHPDBG_FRAME(generator)->frozen_call_stack = zend_generator_freeze_call_stack(PHPDBG_FRAME(generator)->execute_data);
+ }
+ PHPDBG_FRAME(generator) = NULL;
+ }
+
PHPDBG_FRAME(num) = 0;
/* move things back */
@@ -40,7 +120,7 @@ void phpdbg_restore_frame(void) /* {{{ */
void phpdbg_switch_frame(int frame) /* {{{ */
{
- zend_execute_data *execute_data = PHPDBG_FRAME(num)?PHPDBG_FRAME(execute_data):EG(current_execute_data);
+ zend_execute_data *execute_data = PHPDBG_FRAME(num) ? PHPDBG_FRAME(execute_data) : EG(current_execute_data);
int i = 0;
if (PHPDBG_FRAME(num) == frame) {
@@ -78,14 +158,15 @@ void phpdbg_switch_frame(int frame) /* {{{ */
EG(current_execute_data) = execute_data;
}
- phpdbg_notice("frame", "id=\"%d\"", "Switched to frame #%d", frame);
+ phpdbg_try_access {
+ zend_string *s = phpdbg_compile_stackframe(EG(current_execute_data));
+ phpdbg_notice("frame", "id=\"%d\" frameinfo=\"%.*s\"", "Switched to frame #%d: %.*s", frame, (int) ZSTR_LEN(s), ZSTR_VAL(s));
+ zend_string_release(s);
+ } phpdbg_catch_access {
+ phpdbg_notice("frame", "id=\"%d\"", "Switched to frame #%d", frame);
+ } phpdbg_end_try_access();
- {
- const char *file_chr = zend_get_executed_filename();
- zend_string *file = zend_string_init(file_chr, strlen(file_chr), 0);
- phpdbg_list_file(file, 3, zend_get_executed_lineno() - 1, zend_get_executed_lineno());
- efree(file);
- }
+ phpdbg_print_cur_frame_info();
} /* }}} */
static void phpdbg_dump_prototype(zval *tmp) /* {{{ */
@@ -238,3 +319,27 @@ void phpdbg_dump_backtrace(size_t num) /* {{{ */
PHPDBG_OUTPUT_BACKUP_RESTORE();
} /* }}} */
+
+void phpdbg_open_generator_frame(zend_generator *gen) {
+ zend_string *s;
+
+ if (EG(current_execute_data) == gen->execute_data) {
+ return;
+ }
+
+ phpdbg_restore_frame();
+
+ PHPDBG_FRAME(num) = -1;
+ PHPDBG_FRAME(generator) = gen;
+
+ EG(current_execute_data) = gen->execute_data;
+ if (gen->frozen_call_stack) {
+ zend_generator_restore_call_stack(gen);
+ }
+ gen->execute_data->prev_execute_data = NULL;
+
+ s = phpdbg_compile_stackframe(EG(current_execute_data));
+ phpdbg_notice("frame", "handle=\"%d\" frameinfo=\"%.*s\"", "Switched to generator with handle #%d: %.*s", gen->std.handle, (int) ZSTR_LEN(s), ZSTR_VAL(s));
+ zend_string_release(s);
+ phpdbg_print_cur_frame_info();
+}
diff --git a/sapi/phpdbg/phpdbg_frame.h b/sapi/phpdbg/phpdbg_frame.h
index 237848c29b..d0baf4b2e0 100644
--- a/sapi/phpdbg/phpdbg_frame.h
+++ b/sapi/phpdbg/phpdbg_frame.h
@@ -23,8 +23,10 @@
#include "TSRM.h"
+zend_string *phpdbg_compile_stackframe(zend_execute_data *);
void phpdbg_restore_frame(void);
void phpdbg_switch_frame(int);
void phpdbg_dump_backtrace(size_t);
+void phpdbg_open_generator_frame(zend_generator *);
#endif /* PHPDBG_FRAME_H */
diff --git a/sapi/phpdbg/phpdbg_help.c b/sapi/phpdbg/phpdbg_help.c
index d01184b102..40716299d4 100644
--- a/sapi/phpdbg/phpdbg_help.c
+++ b/sapi/phpdbg/phpdbg_help.c
@@ -329,34 +329,35 @@ phpdbg_help_text_t phpdbg_help_text[] = {
"It supports the following commands:" CR CR
"**Information**" CR
-" **list** list PHP source" CR
-" **info** displays information on the debug session" CR
-" **print** show opcodes" CR
-" **frame** select a stack frame and print a stack frame summary" CR
-" **back** shows the current backtrace" CR
-" **help** provide help on a topic" CR CR
+" **list** list PHP source" CR
+" **info** displays information on the debug session" CR
+" **print** show opcodes" CR
+" **frame** select a stack frame and print a stack frame summary" CR
+" **generator** show active generators or select a generator frame" CR
+" **back** shows the current backtrace" CR
+" **help** provide help on a topic" CR CR
"**Starting and Stopping Execution**" CR
-" **exec** set execution context" CR
-" **run** attempt execution" CR
-" **step** continue execution until other line is reached" CR
-" **continue** continue execution" CR
-" **until** continue execution up to the given location" CR
-" **next** continue execution up to the given location and halt on the first line after it" CR
-" **finish** continue up to end of the current execution frame" CR
-" **leave** continue up to end of the current execution frame and halt after the calling instruction" CR
-" **break** set a breakpoint at the specified target" CR
-" **watch** set a watchpoint on $variable" CR
-" **clear** clear one or all breakpoints" CR
-" **clean** clean the execution environment" CR CR
+" **exec** set execution context" CR
+" **run** attempt execution" CR
+" **step** continue execution until other line is reached" CR
+" **continue** continue execution" CR
+" **until** continue execution up to the given location" CR
+" **next** continue execution up to the given location and halt on the first line after it" CR
+" **finish** continue up to end of the current execution frame" CR
+" **leave** continue up to end of the current execution frame and halt after the calling instruction" CR
+" **break** set a breakpoint at the specified target" CR
+" **watch** set a watchpoint on $variable" CR
+" **clear** clear one or all breakpoints" CR
+" **clean** clean the execution environment" CR CR
"**Miscellaneous**" CR
-" **set** set the phpdbg configuration" CR
-" **source** execute a phpdbginit script" CR
-" **register** register a phpdbginit function as a command alias" CR
-" **sh** shell a command" CR
-" **ev** evaluate some code" CR
-" **quit** exit phpdbg" CR CR
+" **set** set the phpdbg configuration" CR
+" **source** execute a phpdbginit script" CR
+" **register** register a phpdbginit function as a command alias" CR
+" **sh** shell a command" CR
+" **ev** evaluate some code" CR
+" **quit** exit phpdbg" CR CR
"Type **help <command>** or (**help alias**) to get detailed help on any of the above commands, "
"for example **help list** or **h l**. Note that help will also match partial commands if unique "
@@ -648,8 +649,8 @@ phpdbg_help_text_t phpdbg_help_text[] = {
},
{"frame",
-"The **frame** takes an optional integer argument. If omitted, then the current frame is displayed "
-"If specified then the current scope is set to the corresponding frame listed in a **back** trace. "
+"The **frame** takes an optional integer argument. If omitted, then the current frame is displayed. "
+"If specified, then the current scope is set to the corresponding frame listed in a **back** trace. "
"This can be used to allowing access to the variables in a higher stack frame than that currently being executed." CR CR
"**Examples**" CR CR
@@ -658,7 +659,25 @@ phpdbg_help_text_t phpdbg_help_text[] = {
" Go to frame 2 and print out variable **$count** in that frame" CR CR
"Note that this frame scope is discarded when execution continues, with the execution frame "
-"then reset to the lowest executiong frame."
+"then reset to the lowest executing frame."
+},
+
+{"generator",
+"The **generator** command takes an optional integer argument. If omitted, then a list of the "
+"currently active generators is displayed. If specified then the current scope is set to the frame "
+"of the generator with the corresponding object handle. This can be used to inspect any generators "
+"not in the current **back** trace." CR CR
+
+"**Examples**" CR CR
+" $P generator" CR
+" List of generators, with the #id being the object handle, e.g.:" CR
+" #3: my_generator(argument=\"value\") at test.php:5" CR
+" $P g 3" CR
+" $P ev $i" CR
+" Go to frame of generator with object handle 3 and print out variable **$i** in that frame" CR CR
+
+"Note that this frame scope is discarded when execution continues, with the execution frame "
+"then reset to the lowest executing frame."
},
{"info",
diff --git a/sapi/phpdbg/phpdbg_prompt.c b/sapi/phpdbg/phpdbg_prompt.c
index 2a75dedc67..c0ce007715 100644
--- a/sapi/phpdbg/phpdbg_prompt.c
+++ b/sapi/phpdbg/phpdbg_prompt.c
@@ -67,33 +67,34 @@ extern int phpdbg_startup_run;
/* {{{ command declarations */
const phpdbg_command_t phpdbg_prompt_commands[] = {
- PHPDBG_COMMAND_D(exec, "set execution context", 'e', NULL, "s", 0),
- PHPDBG_COMMAND_D(step, "step through execution", 's', NULL, 0, PHPDBG_ASYNC_SAFE),
- PHPDBG_COMMAND_D(continue,"continue execution", 'c', NULL, 0, PHPDBG_ASYNC_SAFE),
- PHPDBG_COMMAND_D(run, "attempt execution", 'r', NULL, "|s", 0),
- PHPDBG_COMMAND_D(ev, "evaluate some code", 0 , NULL, "i", PHPDBG_ASYNC_SAFE), /* restricted ASYNC_SAFE */
- PHPDBG_COMMAND_D(until, "continue past the current line", 'u', NULL, 0, 0),
- PHPDBG_COMMAND_D(finish, "continue past the end of the stack", 'F', NULL, 0, 0),
- PHPDBG_COMMAND_D(leave, "continue until the end of the stack", 'L', NULL, 0, 0),
- PHPDBG_COMMAND_D(print, "print something", 'p', phpdbg_print_commands, "|*c", 0),
- PHPDBG_COMMAND_D(break, "set breakpoint", 'b', phpdbg_break_commands, "|*c", 0),
- PHPDBG_COMMAND_D(back, "show trace", 't', NULL, "|n", PHPDBG_ASYNC_SAFE),
- PHPDBG_COMMAND_D(frame, "switch to a frame", 'f', NULL, "|n", PHPDBG_ASYNC_SAFE),
- PHPDBG_COMMAND_D(list, "lists some code", 'l', phpdbg_list_commands, "*", PHPDBG_ASYNC_SAFE),
- PHPDBG_COMMAND_D(info, "displays some informations", 'i', phpdbg_info_commands, "|s", PHPDBG_ASYNC_SAFE),
- PHPDBG_COMMAND_D(clean, "clean the execution environment", 'X', NULL, 0, 0),
- PHPDBG_COMMAND_D(clear, "clear breakpoints", 'C', NULL, 0, 0),
- PHPDBG_COMMAND_D(help, "show help menu", 'h', phpdbg_help_commands, "|s", PHPDBG_ASYNC_SAFE),
- PHPDBG_COMMAND_D(set, "set phpdbg configuration", 'S', phpdbg_set_commands, "s", PHPDBG_ASYNC_SAFE),
- PHPDBG_COMMAND_D(register,"register a function", 'R', NULL, "s", 0),
- PHPDBG_COMMAND_D(source, "execute a phpdbginit", '<', NULL, "s", 0),
- PHPDBG_COMMAND_D(export, "export breaks to a .phpdbginit script", '>', NULL, "s", PHPDBG_ASYNC_SAFE),
- PHPDBG_COMMAND_D(sh, "shell a command", 0 , NULL, "i", 0),
- PHPDBG_COMMAND_D(quit, "exit phpdbg", 'q', NULL, 0, PHPDBG_ASYNC_SAFE),
- PHPDBG_COMMAND_D(wait, "wait for other process", 'W', NULL, 0, 0),
- PHPDBG_COMMAND_D(watch, "set watchpoint", 'w', phpdbg_watch_commands, "|ss", 0),
- PHPDBG_COMMAND_D(next, "step over next line", 'n', NULL, 0, PHPDBG_ASYNC_SAFE),
- PHPDBG_COMMAND_D(eol, "set EOL", 'E', NULL, "|s", 0),
+ PHPDBG_COMMAND_D(exec, "set execution context", 'e', NULL, "s", 0),
+ PHPDBG_COMMAND_D(step, "step through execution", 's', NULL, 0, PHPDBG_ASYNC_SAFE),
+ PHPDBG_COMMAND_D(continue, "continue execution", 'c', NULL, 0, PHPDBG_ASYNC_SAFE),
+ PHPDBG_COMMAND_D(run, "attempt execution", 'r', NULL, "|s", 0),
+ PHPDBG_COMMAND_D(ev, "evaluate some code", 0 , NULL, "i", PHPDBG_ASYNC_SAFE), /* restricted ASYNC_SAFE */
+ PHPDBG_COMMAND_D(until, "continue past the current line", 'u', NULL, 0, 0),
+ PHPDBG_COMMAND_D(finish, "continue past the end of the stack", 'F', NULL, 0, 0),
+ PHPDBG_COMMAND_D(leave, "continue until the end of the stack", 'L', NULL, 0, 0),
+ PHPDBG_COMMAND_D(generator, "inspect or switch to a generator", 'g', NULL, "|n", 0),
+ PHPDBG_COMMAND_D(print, "print something", 'p', phpdbg_print_commands, "|*c", 0),
+ PHPDBG_COMMAND_D(break, "set breakpoint", 'b', phpdbg_break_commands, "|*c", 0),
+ PHPDBG_COMMAND_D(back, "show trace", 't', NULL, "|n", PHPDBG_ASYNC_SAFE),
+ PHPDBG_COMMAND_D(frame, "switch to a frame", 'f', NULL, "|n", PHPDBG_ASYNC_SAFE),
+ PHPDBG_COMMAND_D(list, "lists some code", 'l', phpdbg_list_commands, "*", PHPDBG_ASYNC_SAFE),
+ PHPDBG_COMMAND_D(info, "displays some informations", 'i', phpdbg_info_commands, "|s", PHPDBG_ASYNC_SAFE),
+ PHPDBG_COMMAND_D(clean, "clean the execution environment", 'X', NULL, 0, 0),
+ PHPDBG_COMMAND_D(clear, "clear breakpoints", 'C', NULL, 0, 0),
+ PHPDBG_COMMAND_D(help, "show help menu", 'h', phpdbg_help_commands, "|s", PHPDBG_ASYNC_SAFE),
+ PHPDBG_COMMAND_D(set, "set phpdbg configuration", 'S', phpdbg_set_commands, "s", PHPDBG_ASYNC_SAFE),
+ PHPDBG_COMMAND_D(register, "register a function", 'R', NULL, "s", 0),
+ PHPDBG_COMMAND_D(source, "execute a phpdbginit", '<', NULL, "s", 0),
+ PHPDBG_COMMAND_D(export, "export breaks to a .phpdbginit script", '>', NULL, "s", PHPDBG_ASYNC_SAFE),
+ PHPDBG_COMMAND_D(sh, "shell a command", 0 , NULL, "i", 0),
+ PHPDBG_COMMAND_D(quit, "exit phpdbg", 'q', NULL, 0, PHPDBG_ASYNC_SAFE),
+ PHPDBG_COMMAND_D(wait, "wait for other process", 'W', NULL, 0, 0),
+ PHPDBG_COMMAND_D(watch, "set watchpoint", 'w', phpdbg_watch_commands, "|ss", 0),
+ PHPDBG_COMMAND_D(next, "step over next line", 'n', NULL, 0, PHPDBG_ASYNC_SAFE),
+ PHPDBG_COMMAND_D(eol, "set EOL", 'E', NULL, "|s", 0),
PHPDBG_END_COMMAND
}; /* }}} */
@@ -880,6 +881,56 @@ PHPDBG_COMMAND(back) /* {{{ */
return SUCCESS;
} /* }}} */
+PHPDBG_COMMAND(generator) /* {{{ */
+{
+ int i;
+
+ if (!PHPDBG_G(in_execution)) {
+ phpdbg_error("inactive", "type=\"noexec\"", "Not executing!");
+ return SUCCESS;
+ }
+
+ if (param) {
+ i = param->num;
+ zend_object **obj = EG(objects_store).object_buckets + i;
+ if (i < EG(objects_store).top && *obj && IS_OBJ_VALID(*obj) && (*obj)->ce == zend_ce_generator) {
+ zend_generator *gen = (zend_generator *) *obj;
+ if (gen->execute_data) {
+ if (zend_generator_get_current(gen)->flags & ZEND_GENERATOR_CURRENTLY_RUNNING) {
+ phpdbg_error("generator", "type=\"running\"", "Generator currently running");
+ } else {
+ phpdbg_open_generator_frame(gen);
+ }
+ } else {
+ phpdbg_error("generator", "type=\"closed\"", "Generator already closed");
+ }
+ } else {
+ phpdbg_error("invalidarg", "", "Invalid object handle");
+ }
+ } else {
+ for (i = 0; i < EG(objects_store).top; i++) {
+ zend_object *obj = EG(objects_store).object_buckets[i];
+ if (obj && IS_OBJ_VALID(obj) && obj->ce == zend_ce_generator) {
+ zend_generator *gen = (zend_generator *) obj, *current = zend_generator_get_current(gen);
+ if (gen->execute_data) {
+ zend_string *s = phpdbg_compile_stackframe(gen->execute_data);
+ phpdbg_out("#%d: %.*s", i, (int) ZSTR_LEN(s), ZSTR_VAL(s));
+ zend_string_release(s);
+ if (gen != current) {
+ if (gen->node.parent != current) {
+ phpdbg_out(" with direct parent #%d and", gen->node.parent->std.handle);
+ }
+ phpdbg_out(" executing #%d currently", current->std.handle);
+ }
+ phpdbg_out("\n");
+ }
+ }
+ }
+ }
+
+ return SUCCESS;
+} /* }}} */
+
PHPDBG_COMMAND(print) /* {{{ */
{
if (!param || param->type == EMPTY_PARAM) {
diff --git a/sapi/phpdbg/phpdbg_prompt.h b/sapi/phpdbg/phpdbg_prompt.h
index c17e7185ce..fbfbe0af1c 100644
--- a/sapi/phpdbg/phpdbg_prompt.h
+++ b/sapi/phpdbg/phpdbg_prompt.h
@@ -50,6 +50,7 @@ PHPDBG_COMMAND(clear);
PHPDBG_COMMAND(help);
PHPDBG_COMMAND(sh);
PHPDBG_COMMAND(dl);
+PHPDBG_COMMAND(generator);
PHPDBG_COMMAND(set);
PHPDBG_COMMAND(source);
PHPDBG_COMMAND(export);