]> granicus.if.org Git - php/commitdiff
Provide method to access opcodes via command line argument
authorBob Weinand <bobwei9@hotmail.com>
Sun, 19 Apr 2015 19:53:49 +0000 (21:53 +0200)
committerBob Weinand <bobwei9@hotmail.com>
Sun, 19 Apr 2015 19:54:09 +0000 (21:54 +0200)
sapi/phpdbg/phpdbg.c
sapi/phpdbg/phpdbg_help.c
sapi/phpdbg/phpdbg_print.c
sapi/phpdbg/phpdbg_print.h

index d9d61a8a7369602cd45c39cda9069fc5d5a6edcc..a1af1e0ea967c06cde2314d7c62fb7fb127fffa1 100644 (file)
@@ -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;
index 654a8fef72c85a6513c3578520c1c49997f59f7e..6b105511924326ce0c48b38acbb798eabb0a2af2 100644 (file)
@@ -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
index ae450e8ebbded70744beea18d88395df61e67358..052ac12884bad99ebbff88b5e0337f5ac2b3db6d 100644 (file)
@@ -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);
+       }
+}
index a4ed2d0cbc8c41b5f7b1ec469cb0d87f784abec4..029c15946f4e6079222e49849b024c2abd93de55 100644 (file)
@@ -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 */