diff options
author | Bob Weinand <bobwei9@hotmail.com> | 2015-04-19 21:53:49 +0200 |
---|---|---|
committer | Bob Weinand <bobwei9@hotmail.com> | 2015-04-19 21:54:09 +0200 |
commit | 31e98386dbdd0c0853a041fe450c1d48eb39c6ac (patch) | |
tree | 20df06fd06bbcc27c452fb392bf0bf445077b229 | |
parent | 4a38f51857e6d52849fae657d99d1f31492325a0 (diff) | |
download | php-git-31e98386dbdd0c0853a041fe450c1d48eb39c6ac.tar.gz |
Provide method to access opcodes via command line argument
-rw-r--r-- | sapi/phpdbg/phpdbg.c | 22 | ||||
-rw-r--r-- | sapi/phpdbg/phpdbg_help.c | 14 | ||||
-rw-r--r-- | sapi/phpdbg/phpdbg_print.c | 118 | ||||
-rw-r--r-- | sapi/phpdbg/phpdbg_print.h | 2 |
4 files changed, 153 insertions, 3 deletions
diff --git a/sapi/phpdbg/phpdbg.c b/sapi/phpdbg/phpdbg.c index d9d61a8a73..a1af1e0ea9 100644 --- a/sapi/phpdbg/phpdbg.c +++ b/sapi/phpdbg/phpdbg.c @@ -32,6 +32,7 @@ #include "phpdbg_io.h" #include "zend_alloc.h" #include "phpdbg_eol.h" +#include "phpdbg_print.h" #include "ext/standard/basic_functions.h" @@ -761,6 +762,7 @@ const opt_struct OPTIONS[] = { /* {{{ */ {'a', 1, "address-or-any"}, #endif {'x', 0, "xml output"}, + {'p', 2, "show opcodes"}, {'h', 0, "help"}, {'V', 0, "version"}, {'-', 0, NULL} @@ -1028,6 +1030,7 @@ int main(int argc, char **argv) /* {{{ */ int server = -1; int socket = -1; FILE* stream = NULL; + char *print_opline_func; #ifdef ZTS void ***tsrm_ls; @@ -1204,6 +1207,12 @@ phpdbg_main: break; + case 'p': { + print_opline_func = php_optarg; + show_banner = 0; + settings = (void *) 0x1; + } break; + case 'h': { sapi_startup(phpdbg); phpdbg->startup(phpdbg); @@ -1231,6 +1240,8 @@ phpdbg_main: return 0; } break; } + + php_optarg = NULL; } /* set exec if present on command line */ @@ -1306,7 +1317,7 @@ phpdbg_main: /* set flags from command line */ PHPDBG_G(flags) = flags; - if (settings) { + if (settings > (zend_phpdbg_globals *) 0x2) { #ifdef ZTS *((zend_phpdbg_globals *) (*((void ***) tsrm_ls))[TSRM_UNSHUFFLE_RSRC_ID(phpdbg_globals_id)]) = *settings; #else @@ -1509,6 +1520,15 @@ phpdbg_main: PHPDBG_G(flags) &= ~PHPDBG_DISCARD_OUTPUT; } + if (settings == (void *) 0x1) { + if (PHPDBG_G(ops)) { + phpdbg_print_opcodes(print_opline_func); + } else { + write(PHPDBG_G(io)[PHPDBG_STDERR].fd, ZEND_STRL("No opcodes could be compiled | No file specified or compilation failed?\n")); + } + goto phpdbg_out; + } + /* step from here, not through init */ if (step) { PHPDBG_G(flags) |= PHPDBG_IS_STEPPING; diff --git a/sapi/phpdbg/phpdbg_help.c b/sapi/phpdbg/phpdbg_help.c index 654a8fef72..6b10551192 100644 --- a/sapi/phpdbg/phpdbg_help.c +++ b/sapi/phpdbg/phpdbg_help.c @@ -389,6 +389,7 @@ phpdbg_help_text_t phpdbg_help_text[] = { " **-l** **-l**4000 Setup remote console ports" CR " **-a** **-a**192.168.0.3 Setup remote console bind address" CR " **-x** Enable xml output (instead of normal text output)" CR +" **-p** **-p**, **-p=func**, **-p* ** Output opcodes and quit" CR " **-h** Print the help overview" CR " **-V** Print version number" CR " **--** **--** arg1 arg2 Use to delimit phpdbg arguments and php $argv; append any $argv " @@ -396,12 +397,21 @@ phpdbg_help_text_t phpdbg_help_text[] = { "**Remote Console Mode**" CR CR -"This mode is enabled by specifying the **-a** option. Phpdbg will bind only to the loopback " +"This mode is enabled by specifying the **-a** option. Phpdbg will bind only to the loopback " "interface by default, and this can only be overridden by explicitly setting the remote console " "bind address using the **-a** option. If **-a** is specied without an argument, then phpdbg " "will bind to all available interfaces. You should be aware of the security implications of " "doing this, so measures should be taken to secure this service if bound to a publicly accessible " -"interface/port." +"interface/port." CR CR + +"**Opcode output**" CR CR + +"Outputting opcodes requires that a file path is passed as last argument. Modes of execution:" CR +"**-p** Outputs the main execution context" CR +"**-p* **Outputs all opcodes in the whole file (including classes and functions)" CR +"**-p=function_name** Outputs opcodes of a given function in the file" CR +"**-p=class_name::** Outputs opcodes of all the methods of a given class" CR +"**-p=class_name::method** Outputs opcodes of a given method" }, {"phpdbginit", CR diff --git a/sapi/phpdbg/phpdbg_print.c b/sapi/phpdbg/phpdbg_print.c index ae450e8ebb..052ac12884 100644 --- a/sapi/phpdbg/phpdbg_print.c +++ b/sapi/phpdbg/phpdbg_print.c @@ -260,3 +260,121 @@ PHPDBG_PRINT(func) /* {{{ */ return SUCCESS; } /* }}} */ + +void phpdbg_print_opcodes_main() { + phpdbg_out("function name: (null)\n"); + phpdbg_print_function_helper((zend_function *) PHPDBG_G(ops)); +} + +void phpdbg_print_opcodes_function(const char *function, size_t len) { + zend_function *func = zend_hash_str_find_ptr(EG(function_table), function, len); + + if (!func) { + return; + } + + phpdbg_out("function name: %.*s\n", (int) len, function); + phpdbg_print_function_helper(func); +} + +void phpdbg_print_opcodes_method(const char *class, const char *function) { + zend_class_entry *ce = zend_hash_str_find_ptr(EG(class_table), class, strlen(class)); + zend_function *func; + + if (!ce) { + return; + } + if (ce->type != ZEND_USER_CLASS) { + phpdbg_out("function name: %s::%s (internal)\n", class, function); + return; + } + + if (!(func = zend_hash_str_find_ptr(&ce->function_table, function, strlen(function)))) { + return; + } + + phpdbg_out("function name: %s::%s\n", class, function); + phpdbg_print_function_helper(func); +} + +void phpdbg_print_opcodes_class(const char *class) { + zend_class_entry *ce; + zend_function *method; + zend_string *method_name; + zend_bool first = 1; + + if (phpdbg_safe_class_lookup(class, strlen(class), &ce) != SUCCESS) { + return; + } + + phpdbg_out("%s %s: %s\n", + (ce->type == ZEND_USER_CLASS) ? + "user" : "internal", + (ce->ce_flags & ZEND_ACC_INTERFACE) ? + "interface" : + (ce->ce_flags & ZEND_ACC_ABSTRACT) ? + "abstract Class" : + "class", + ce->name->val); + + if (ce->type != ZEND_USER_CLASS) { + return; + } + + phpdbg_out("%d methods: ", zend_hash_num_elements(&ce->function_table)); + ZEND_HASH_FOREACH_PTR(&ce->function_table, method) { + if (first) { + first = 0; + } else { + phpdbg_out(", "); + } + phpdbg_out("%s", method->common.function_name->val); + } ZEND_HASH_FOREACH_END(); + if (first) { + phpdbg_out("-"); + } + phpdbg_out("\n"); + + ZEND_HASH_FOREACH_STR_KEY_PTR(&ce->function_table, method_name, method) { + phpdbg_out("\nfunction name: %s\n", method_name); + phpdbg_print_function_helper(method); + } ZEND_HASH_FOREACH_END(); +} + +PHPDBG_API void phpdbg_print_opcodes(char *function) +{ + char *method_name; + + strtok(function, ":"); + + if (function == NULL) { + phpdbg_print_opcodes_main(); + } else if (function[0] == '*' && function[1] == 0) { + /* all */ + zend_string *name; + zend_function *func; + zend_class_entry *ce; + + phpdbg_print_opcodes_main(); + + ZEND_HASH_FOREACH_STR_KEY_PTR(EG(function_table), name, func) { + if (func->type == ZEND_USER_FUNCTION) { + phpdbg_out("\n"); + phpdbg_print_opcodes_function(name->val, name->len); + } + } ZEND_HASH_FOREACH_END(); + + ZEND_HASH_FOREACH_STR_KEY_PTR(EG(class_table), name, ce) { + if (ce->type == ZEND_USER_CLASS) { + phpdbg_out("\n\n"); + phpdbg_print_opcodes_class(name->val); + } + } ZEND_HASH_FOREACH_END(); + } else if ((method_name = strtok(NULL, ":")) == NULL) { + phpdbg_print_opcodes_function(function, strlen(function)); + } else if (++method_name == NULL || ++method_name == NULL) { + phpdbg_print_opcodes_class(function); + } else { + phpdbg_print_opcodes_method(function, method_name); + } +} diff --git a/sapi/phpdbg/phpdbg_print.h b/sapi/phpdbg/phpdbg_print.h index a4ed2d0cbc..029c15946f 100644 --- a/sapi/phpdbg/phpdbg_print.h +++ b/sapi/phpdbg/phpdbg_print.h @@ -35,6 +35,8 @@ PHPDBG_PRINT(method); PHPDBG_PRINT(func); PHPDBG_PRINT(stack); +PHPDBG_API void phpdbg_print_opcodes(char *function); + extern const phpdbg_command_t phpdbg_print_commands[]; #endif /* PHPDBG_PRINT_H */ |