* Commands
*/
const phpdbg_command_t phpdbg_break_commands[] = {
- PHPDBG_COMMAND_D_EX(file, "specify breakpoint by file:line", 'F', break_file, NULL, 1),
- PHPDBG_COMMAND_D_EX(func, "specify breakpoint by global function name", 'f', break_func, NULL, 1),
- PHPDBG_COMMAND_D_EX(method, "specify breakpoint by class::method", 'm', break_method, NULL, 1),
- PHPDBG_COMMAND_D_EX(address, "specify breakpoint by address", 'a', break_address, NULL, 1),
- PHPDBG_COMMAND_D_EX(op, "specify breakpoint by opcode", 'O', break_op, NULL, 1),
- PHPDBG_COMMAND_D_EX(on, "specify breakpoint by condition", 'o', break_on, NULL, 1),
- PHPDBG_COMMAND_D_EX(at, "specify breakpoint by location and condition", 'A', break_at, NULL, 1),
- PHPDBG_COMMAND_D_EX(lineno, "specify breakpoint by line of currently executing file", 'l', break_lineno, NULL, 1),
- PHPDBG_COMMAND_D_EX(del, "delete breakpoint by identifier number", 'd', break_del, NULL, 1),
+ PHPDBG_COMMAND_D_EX(file, "specify breakpoint by file:line", 'F', break_file, NULL, "f"),
+ PHPDBG_COMMAND_D_EX(func, "specify breakpoint by global function name", 'f', break_func, NULL, "s"),
+ PHPDBG_COMMAND_D_EX(method, "specify breakpoint by class::method", 'm', break_method, NULL, "m"),
+ PHPDBG_COMMAND_D_EX(address, "specify breakpoint by address", 'a', break_address, NULL, "a"),
+ PHPDBG_COMMAND_D_EX(op, "specify breakpoint by opcode", 'O', break_op, NULL, "s"),
+ PHPDBG_COMMAND_D_EX(on, "specify breakpoint by condition", 'o', break_on, NULL, "c"),
+ PHPDBG_COMMAND_D_EX(at, "specify breakpoint by location and condition", 'A', break_at, NULL, "*c"),
+ PHPDBG_COMMAND_D_EX(lineno, "specify breakpoint by line of currently executing file", 'l', break_lineno, NULL, "l"),
+ PHPDBG_COMMAND_D_EX(del, "delete breakpoint by identifier number", 'd', break_del, NULL, "l"),
PHPDBG_END_COMMAND
};
stack->len++;
} /* }}} */
+PHPDBG_API int phpdbg_stack_verify(phpdbg_command_t *command, const phpdbg_param_t **stack, char **why TSRMLS_DC) {
+ if (command && command->args) {
+ const phpdbg_param_t *top = (stack != NULL) ? *stack : NULL;
+ const char *arg = command->args;
+ size_t expected = strlen(command->args),
+ received = 0L;
+ zend_bool optional = 0;
+
+ if (*arg == '|') {
+ expected--;
+ optional = 1;
+ arg++;
+ }
+
+ if (arg && !top && !optional) {
+ asprintf(why,
+ "%s expected arguments and received none", command->name);
+ return FAILURE;
+ }
+
+ while (top && arg) {
+
+ switch (*arg) {
+ case '|': {
+ expected--;
+ optional = 1;
+ arg++;
+ } continue;
+
+ case 'i': if (top->type != STR_PARAM) {
+ asprintf(why,
+ "%s expected raw input and got %s at parameter %d",
+ command->name, phpdbg_get_param_type(top TSRMLS_CC),
+ (command->args - arg) + 1);
+ return FAILURE;
+ } break;
+
+ case 's': if (top->type != STR_PARAM) {
+ asprintf(why,
+ "%s expected string and got %s at parameter %d",
+ command->name, phpdbg_get_param_type(top TSRMLS_CC),
+ (command->args - arg) + 1);
+ return FAILURE;
+ } break;
+
+ case 'n': if (top->type != NUMERIC_PARAM) {
+ asprintf(why,
+ "%s expected number and got %s at parameter %d",
+ command->name, phpdbg_get_param_type(top TSRMLS_CC),
+ (command->args - arg) + 1);
+ return FAILURE;
+ } break;
+
+ case 'm': if (top->type != METHOD_PARAM) {
+ asprintf(why,
+ "%s expected method and got %s at parameter %d",
+ command->name, phpdbg_get_param_type(top TSRMLS_CC),
+ (command->args - arg) + 1);
+ return FAILURE;
+ } break;
+
+ case 'a': if (top->type != ADDR_PARAM) {
+ asprintf(why,
+ "%s expected address and got %s at parameter %d",
+ command->name, phpdbg_get_param_type(top TSRMLS_CC),
+ (command->args - arg) + 1);
+ return FAILURE;
+ } break;
+
+ case 'f': if (top->type != FILE_PARAM) {
+ asprintf(why,
+ "%s expected file:line and got %s at parameter %d",
+ command->name, phpdbg_get_param_type(top TSRMLS_CC),
+ (command->args - arg) + 1);
+ return FAILURE;
+ } break;
+
+ case 'c': if (top->type != COND_PARAM) {
+ asprintf(why,
+ "%s expected condition and got %s at parameter %d",
+ command->name, phpdbg_get_param_type(top TSRMLS_CC),
+ (command->args - arg) + 1);
+ return FAILURE;
+ } break;
+
+ case 'b': if (top->type != NUMERIC_PARAM) {
+ asprintf(why,
+ "%s expected boolean and got %s at parameter %d",
+ command->name, phpdbg_get_param_type(top TSRMLS_CC),
+ (command->args - arg) + 1);
+ return FAILURE;
+ } else if (top->num > 1 || top->num < 0) {
+ asprintf(why,
+ "%s expected boolean and got number at parameter %d",
+ command->name, phpdbg_get_param_type(top TSRMLS_CC),
+ (command->args - arg) + 1);
+ return FAILURE;
+ } break;
+
+ case '*': { /* do nothing */ } break;
+ }
+ top = top->next;
+ received++;
+ arg++;
+ }
+
+ if ((received < expected) && (arg && *arg) && !optional) {
+ asprintf(why,
+ "%s expected %d arguments (%s) and received %d",
+ command->name,
+ expected,
+ command->args,
+ received);
+ return FAILURE;
+ }
+ }
+
+ return SUCCESS;
+}
+
/* {{{ */
-PHPDBG_API phpdbg_command_t* phpdbg_stack_resolve(const phpdbg_command_t *commands, phpdbg_param_t **top, char **why) {
+PHPDBG_API phpdbg_command_t* phpdbg_stack_resolve(const phpdbg_command_t *commands, const phpdbg_command_t *parent, phpdbg_param_t **top, char **why) {
const phpdbg_command_t *command = commands;
phpdbg_param_t *name = *top;
phpdbg_command_t *matched[3] = {NULL, NULL, NULL};
+
ulong matches = 0L;
while (command && command->name && command->handler) {
}
switch (matches) {
- case 0: {
+ case 0: if (!parent) {
asprintf(
why,
"The command %s could not be found",
name->str);
- } break;
+ return NULL;
+ } else return parent;
case 1: {
(*top) = (*top)->next;
- if (matched[0]->subs && (*top) && ((*top)->type == STR_PARAM)) {
- command = phpdbg_stack_resolve(matched[0]->subs, top, why);
- if (command) {
- return command;
- }
- }
-
- return matched[0];
+
+ command = matched[0];
} break;
default: {
why,
"The command %s is ambigious, matching %d commands",
name->str, matches);
- }
+ } return NULL;
}
-
+
+ if (command->subs && (*top) && ((*top)->type == STR_PARAM)) {
+ return phpdbg_stack_resolve(command->subs, command, top, why);
+ } else {
+ return command;
+ }
+
return NULL;
} /* }}} */
case STR_PARAM: {
handler = phpdbg_stack_resolve(
- phpdbg_prompt_commands, &command, why);
+ phpdbg_prompt_commands, NULL, &command, why);
if (handler) {
- return handler->handler(command, NULL TSRMLS_CC);
- } else {
- return FAILURE;
+ if (phpdbg_stack_verify(handler, &command, why) == SUCCESS) {
+ return handler->handler(command, NULL TSRMLS_CC);
+ }
}
- } break;
+ } return FAILURE;
default:
asprintf(
char alias; /* Alias */
phpdbg_command_handler_t handler; /* Command handler */
const phpdbg_command_t *subs; /* Sub Commands */
- char arg_type; /* Accept args? */
+ char *args; /* Argument Spec */
};
/* }}} */
* Stack Management
*/
PHPDBG_API void phpdbg_stack_push(phpdbg_param_t *stack, phpdbg_param_t *param);
-PHPDBG_API phpdbg_command_t* phpdbg_stack_resolve(const phpdbg_command_t *commands, phpdbg_param_t **top, char **why);
+PHPDBG_API phpdbg_command_t* phpdbg_stack_resolve(const phpdbg_command_t *commands, const phpdbg_command_t *parent, phpdbg_param_t **top, char **why);
PHPDBG_API int phpdbg_stack_execute(phpdbg_param_t *stack, char **why);
PHPDBG_API void phpdbg_stack_free(phpdbg_param_t *stack);
*/
#define PHPDBG_COMMAND_HANDLER(name) phpdbg_do_##name
-#define PHPDBG_COMMAND_D_EX(name, tip, alias, handler, children, has_args) \
- {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##handler, children, has_args}
+#define PHPDBG_COMMAND_D_EX(name, tip, alias, handler, children, args) \
+ {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##handler, children, args}
-#define PHPDBG_COMMAND_D(name, tip, alias, children, has_args) \
- {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##name, children, has_args}
+#define PHPDBG_COMMAND_D(name, tip, alias, children, args) \
+ {PHPDBG_STRL(#name), tip, sizeof(tip)-1, alias, phpdbg_do_##name, children, args}
#define PHPDBG_COMMAND(name) int phpdbg_do_##name(const phpdbg_param_t *param, const phpdbg_input_t *input TSRMLS_DC)
#define PHPDBG_COMMAND_ARGS param, input TSRMLS_CC
-#define PHPDBG_END_COMMAND {NULL, 0, NULL, 0, '\0', NULL, NULL, '\0'}
+#define PHPDBG_END_COMMAND {NULL, 0, NULL, 0, '\0', NULL, NULL, '\0', '\0'}
/*
* Default Switch Case
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
const phpdbg_command_t phpdbg_list_commands[] = {
- PHPDBG_COMMAND_D_EX(lines, "lists the specified lines", 'l', list_lines, NULL, 1),
- PHPDBG_COMMAND_D_EX(class, "lists the specified class", 'c', list_class, NULL, 1),
- PHPDBG_COMMAND_D_EX(method, "lists the specified method", 'm', list_method, NULL, 1),
- PHPDBG_COMMAND_D_EX(func, "lists the specified function", 'f', list_func, NULL, 1),
+ PHPDBG_COMMAND_D_EX(lines, "lists the specified lines", 'l', list_lines, NULL, "l"),
+ PHPDBG_COMMAND_D_EX(class, "lists the specified class", 'c', list_class, NULL, "s"),
+ PHPDBG_COMMAND_D_EX(method, "lists the specified method", 'm', list_method, NULL, "m"),
+ PHPDBG_COMMAND_D_EX(func, "lists the specified function", 'f', list_func, NULL, "s"),
PHPDBG_END_COMMAND
};
const phpdbg_command_t phpdbg_print_commands[] = {
PHPDBG_COMMAND_D_EX(exec, "print out the instructions in the execution context", 'e', print_exec, NULL, 0),
PHPDBG_COMMAND_D_EX(opline, "print out the instruction in the current opline", 'o', print_opline, NULL, 0),
- PHPDBG_COMMAND_D_EX(class, "print out the instructions in the specified class", 'c', print_class, NULL, 1),
- PHPDBG_COMMAND_D_EX(method, "print out the instructions in the specified method", 'm', print_method, NULL, 1),
- PHPDBG_COMMAND_D_EX(func, "print out the instructions in the specified function", 'f', print_func, NULL, 1),
+ PHPDBG_COMMAND_D_EX(class, "print out the instructions in the specified class", 'c', print_class, NULL, "s"),
+ PHPDBG_COMMAND_D_EX(method, "print out the instructions in the specified method", 'm', print_method, NULL, "m"),
+ PHPDBG_COMMAND_D_EX(func, "print out the instructions in the specified function", 'f', print_func, NULL, "s"),
PHPDBG_COMMAND_D_EX(stack, "print out the instructions in the current stack", 's', print_stack, NULL, 0),
PHPDBG_END_COMMAND
};
/* {{{ command declarations */
const phpdbg_command_t phpdbg_prompt_commands[] = {
- PHPDBG_COMMAND_D(exec, "set execution context", 'e', NULL, 1),
+ PHPDBG_COMMAND_D(exec, "set execution context", 'e', NULL, "s"),
PHPDBG_COMMAND_D(compile, "attempt compilation", 'c', NULL, 0),
- PHPDBG_COMMAND_D(step, "step through execution", 's', NULL, 1),
+ PHPDBG_COMMAND_D(step, "step through execution", 's', NULL, "b"),
PHPDBG_COMMAND_D(next, "continue execution", 'n', NULL, 0),
PHPDBG_COMMAND_D(run, "attempt execution", 'r', NULL, 0),
- PHPDBG_COMMAND_D(eval, "evaluate some code", 'E', NULL, 1),
+ PHPDBG_COMMAND_D(eval, "evaluate some code", 'E', NULL, "i"),
PHPDBG_COMMAND_D(until, "continue past the current line", 'u', NULL, 0),
PHPDBG_COMMAND_D(finish, "continue past the end of the stack", 'F', NULL, 0),
PHPDBG_COMMAND_D(leave, "continue until the end of the stack", 'L', NULL, 0),
- PHPDBG_COMMAND_D(print, "print something", 'p', phpdbg_print_commands, 2),
- PHPDBG_COMMAND_D(break, "set breakpoint", 'b', phpdbg_break_commands, 1),
+ PHPDBG_COMMAND_D(print, "print something", 'p', phpdbg_print_commands, "s"),
+ PHPDBG_COMMAND_D(break, "set breakpoint", 'b', phpdbg_break_commands, 0),
PHPDBG_COMMAND_D(back, "show trace", 't', NULL, 0),
- PHPDBG_COMMAND_D(frame, "switch to a frame", 'f', NULL, 1),
- PHPDBG_COMMAND_D(list, "lists some code", 'l', phpdbg_list_commands, 2),
- PHPDBG_COMMAND_D(info, "displays some informations", 'i', phpdbg_info_commands, 1),
+ PHPDBG_COMMAND_D(frame, "switch to a frame", 'f', NULL, "n"),
+ PHPDBG_COMMAND_D(list, "lists some code", 'l', phpdbg_list_commands, "*"),
+ PHPDBG_COMMAND_D(info, "displays some informations", 'i', phpdbg_info_commands, "s"),
PHPDBG_COMMAND_D(clean, "clean the execution environment", 'X', NULL, 0),
PHPDBG_COMMAND_D(clear, "clear breakpoints", 'C', NULL, 0),
- PHPDBG_COMMAND_D(help, "show help menu", 'h', phpdbg_help_commands, 2),
- PHPDBG_COMMAND_D(quiet, "silence some output", 'Q', NULL, 1),
- PHPDBG_COMMAND_D(set, "set phpdbg configuration", 'S', phpdbg_set_commands, 1),
- PHPDBG_COMMAND_D(register,"register a function", 'R', NULL, 1),
- PHPDBG_COMMAND_D(source, "execute a phpdbginit", '.', NULL, 1),
- PHPDBG_COMMAND_D(shell, "shell a command", '-', NULL, 1),
+ PHPDBG_COMMAND_D(help, "show help menu", 'h', phpdbg_help_commands, "|s"),
+ PHPDBG_COMMAND_D(quiet, "silence some output", 'Q', NULL, "b"),
+ PHPDBG_COMMAND_D(set, "set phpdbg configuration", 'S', phpdbg_set_commands, "s"),
+ PHPDBG_COMMAND_D(register,"register a function", 'R', NULL, "s"),
+ PHPDBG_COMMAND_D(source, "execute a phpdbginit", '.', NULL, "s"),
+ PHPDBG_COMMAND_D(shell, "shell a command", '-', NULL, 0),
PHPDBG_COMMAND_D(quit, "exit phpdbg", 'q', NULL, 0),
PHPDBG_END_COMMAND
}; /* }}} */
}*/
phpdbg_error("%s", why);
}
- if (why)
+ if (why) {
free(why);
+ why = NULL;
+ }
break;
case PHPDBG_LEAVE:
}
}
+ if (why) {
+ free(why);
+ why = NULL;
+ }
+
yy_delete_buffer(state, scanner);
yylex_destroy(scanner);
ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
const phpdbg_command_t phpdbg_set_commands[] = {
- PHPDBG_COMMAND_D_EX(prompt, "usage: set prompt <string>", 'p', set_prompt, NULL, 0),
+ PHPDBG_COMMAND_D_EX(prompt, "usage: set prompt <string>", 'p', set_prompt, NULL, "s"),
#ifndef _WIN32
- PHPDBG_COMMAND_D_EX(color, "usage: set color <element> <color>", 'c', set_color, NULL, 1),
- PHPDBG_COMMAND_D_EX(colors, "usage: set colors <on|off>", 'C', set_colors, NULL, 1),
+ PHPDBG_COMMAND_D_EX(color, "usage: set color <element> <color>", 'c', set_color, NULL, "ss"),
+ PHPDBG_COMMAND_D_EX(colors, "usage: set colors <on|off>", 'C', set_colors, NULL, "b"),
#endif
- PHPDBG_COMMAND_D_EX(oplog, "usage: set oplog <output>", 'O', set_oplog, NULL, 0),
- PHPDBG_COMMAND_D_EX(break, "usage: set break [id] <on|off>", 'b', set_break, NULL, 0),
+ PHPDBG_COMMAND_D_EX(oplog, "usage: set oplog <output>", 'O', set_oplog, NULL, "s"),
+ PHPDBG_COMMAND_D_EX(break, "usage: set break [id] <on|off>", 'b', set_break, NULL, "lb"),
PHPDBG_END_COMMAND
};