]> granicus.if.org Git - php/commitdiff
First semi-working version of oplines
authorBob Weinand <bobwei9@hotmail.com>
Thu, 28 Nov 2013 20:36:45 +0000 (21:36 +0100)
committerBob Weinand <bobwei9@hotmail.com>
Thu, 28 Nov 2013 20:36:45 +0000 (21:36 +0100)
phpdbg.c
phpdbg.h
phpdbg_bp.c
phpdbg_bp.h
phpdbg_break.c
phpdbg_cmd.c
phpdbg_cmd.h

index f15e023503d3be2866e89057ba30b677e57a94f9..322d54431e5eae4c76bf5b7f6141020009141ed6 100644 (file)
--- a/phpdbg.c
+++ b/phpdbg.c
@@ -133,12 +133,15 @@ static PHP_RINIT_FUNCTION(phpdbg) /* {{{ */
 {
        zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE],   8, NULL, php_phpdbg_destroy_bp_file, 0);
        zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], 8, NULL, php_phpdbg_destroy_bp_symbol, 0);
+       zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
+       zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
        zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], 8, NULL, NULL, 0);
        zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], 8, NULL, php_phpdbg_destroy_bp_opcode, 0);
        zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], 8, NULL, php_phpdbg_destroy_bp_methods, 0);
        zend_hash_init(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], 8, NULL, php_phpdbg_destroy_bp_condition, 0);
        zend_hash_init(&PHPDBG_G(seek), 8, NULL, NULL, 0);
        zend_hash_init(&PHPDBG_G(registered), 8, NULL, php_phpdbg_destroy_registered, 0);
+       PHPDBG_G(opline_btree) = NULL;
 
        return SUCCESS;
 } /* }}} */
@@ -309,14 +312,14 @@ zend_function_entry phpdbg_user_functions[] = {
 
 static zend_module_entry sapi_phpdbg_module_entry = {
        STANDARD_MODULE_HEADER,
-       "phpdbg",
+       PHPDBG_NAME,
        phpdbg_user_functions,
        PHP_MINIT(phpdbg),
        NULL,
        PHP_RINIT(phpdbg),
        PHP_RSHUTDOWN(phpdbg),
        NULL,
-       "0.1",
+       PHPDBG_VERSION,
        STANDARD_MODULE_PROPERTIES
 };
 
@@ -458,6 +461,38 @@ static sapi_module_struct phpdbg_sapi_module = {
 };
 /* }}} */
 
+void phpdbg_op_array_handler(zend_op_array *op_array) {
+       TSRMLS_FETCH();
+
+       phpdbg_save_oplines(op_array TSRMLS_CC);
+       phpdbg_resolve_op_array_breaks(op_array TSRMLS_CC);
+}
+
+#ifndef ZEND_EXT_API
+#define ZEND_EXT_API ZEND_DLEXPORT
+#endif
+ZEND_EXTENSION();
+
+ZEND_DLEXPORT zend_extension zend_extension_entry = {
+       PHPDBG_NAME,
+       PHPDBG_VERSION,
+       PHPDBG_AUTHORS,
+       PHPDBG_URL,
+       "(c) 2013",
+       NULL,                    /* startup_func_t */
+       NULL,                    /* shutdown_func_t */
+       NULL,                    /* activate_func_t */
+       NULL,                    /* deactivate_func_t */
+       NULL,                    /* message_handler_func_t */
+       phpdbg_op_array_handler, /* op_array_handler_func_t */
+       NULL,                    /* statement_handler_func_t */
+       NULL,                    /* fcall_begin_handler_func_t */
+       NULL,                    /* fcall_end_handler_func_t */
+       NULL,                    /* op_array_ctor_func_t */
+       NULL,                    /* op_array_dtor_func_t */
+       STANDARD_ZEND_EXTENSION_PROPERTIES
+};
+
 const opt_struct OPTIONS[] = { /* {{{ */
        {'c', 1, "ini path override"},
        {'d', 1, "define ini entry on command line"},
@@ -717,6 +752,8 @@ phpdbg_main:
        phpdbg->ini_entries = ini_entries;
 
        if (phpdbg->startup(phpdbg) == SUCCESS) {
+               zend_register_extension(&zend_extension_entry, NULL);
+
                zend_activate(TSRMLS_C);
 
 #ifdef ZEND_SIGNALS
index b045d85fe02f4074b9e67a37cb08b938699ca9db..628f38a0f3f56c5be39b9acad6da5ab1208afddc 100644 (file)
--- a/phpdbg.h
+++ b/phpdbg.h
 #define PHPDBG_LEAVE  5
 
 /* {{{ tables */
-#define PHPDBG_BREAK_FILE       0
-#define PHPDBG_BREAK_SYM        1
-#define PHPDBG_BREAK_OPLINE     2
-#define PHPDBG_BREAK_METHOD     3
-#define PHPDBG_BREAK_COND       4
-#define PHPDBG_BREAK_OPCODE     5
-#define PHPDBG_BREAK_TABLES     6 /* }}} */
+#define PHPDBG_BREAK_FILE            0
+#define PHPDBG_BREAK_SYM             1
+#define PHPDBG_BREAK_OPLINE          2
+#define PHPDBG_BREAK_METHOD          3
+#define PHPDBG_BREAK_COND            4
+#define PHPDBG_BREAK_OPCODE          5
+#define PHPDBG_BREAK_FUNCTION_OPLINE 6
+#define PHPDBG_BREAK_METHOD_OPLINE   7
+#define PHPDBG_BREAK_TABLES          8/* }}} */
 
 /* {{{ flags */
 #define PHPDBG_HAS_FILE_BP      (1<<1)
 #endif /* }}} */
 
 /* {{{ strings */
+#define PHPDBG_NAME "phpdbg"
+#define PHPDBG_AUTHORS "Felipe Pena, Joe Watkins and Bob Weinand" /* Ordered by last name */
+#define PHPDBG_URL "http://phpdbg.com"
 #define PHPDBG_ISSUES "http://github.com/krakjoe/phpdbg/issues"
 #define PHPDBG_VERSION "0.2.0-dev"
 #define PHPDBG_INIT_FILENAME ".phpdbginit"
 #define PHPDBG_IO_FDS                  3 /* }}} */
 
 /* {{{ structs */
+typedef union _phpdbg_btree phpdbg_btree;
+union _phpdbg_btree {
+       phpdbg_btree  *branches[2];
+       zend_op_array *op_array;
+};
+
 ZEND_BEGIN_MODULE_GLOBALS(phpdbg)
        HashTable bp[PHPDBG_BREAK_TABLES];           /* break points */
+       phpdbg_btree *opline_btree;                  /* opline root -> op_array */
        HashTable registered;                        /* registered */
        HashTable seek;                              /* seek oplines */
        phpdbg_frame_t frame;                        /* frame */
index 75d091840182c0c96ca60c145465f0c75aadb710..22d376eb5fe90aa8c17a2c39e43f533a9f318f15 100644 (file)
@@ -44,6 +44,19 @@ static void phpdbg_class_breaks_dtor(void *data) /* {{{ */
        efree((char*)bp->func_name);
 } /* }}} */
 
+static void phpdbg_opline_class_breaks_dtor(void *data) /* {{{ */
+{
+       zend_hash_destroy((HashTable *)data);
+} /* }}} */
+
+static void phpdbg_opline_breaks_dtor(void *data) /* {{{ */
+{
+       phpdbg_breakopline_t *bp = (phpdbg_breakopline_t *) data;
+
+       efree((char*)bp->class_name);
+       efree((char*)bp->func_name);
+} /* }}} */
+
 PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC) /* {{{ */
 {
        HashPosition position;
@@ -251,10 +264,68 @@ PHPDBG_API void phpdbg_set_breakpoint_method(const char* class_name, const char*
     efree(lcname);
 } /* }}} */
 
+PHPDBG_API void phpdbg_save_oplines(zend_op_array *op_array TSRMLS_DC) {
+       phpdbg_btree **branch = &PHPDBG_G(opline_btree);
+       int i = sizeof(zend_ulong) * 8 - 1;
+
+       do {
+               if (*branch == NULL) {
+                       break;
+               }
+               branch = &(*branch)->branches[((zend_ulong)op_array->opcodes >> i) % 2];
+       } while (i--);
+
+       if (*branch == NULL) {
+               phpdbg_btree *memory = *branch = emalloc(i * sizeof(phpdbg_btree));
+               while (i--) {
+                       branch = &(*branch)->branches[((zend_ulong)op_array->opcodes >> i) % 2];
+                       *branch = ++memory;
+               }
+       }
+
+       (*branch)->op_array = op_array;
+}
+
 PHPDBG_API void phpdbg_set_breakpoint_opline(zend_ulong opline TSRMLS_DC) /* {{{ */
 {
        if (!zend_hash_index_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], opline)) {
                phpdbg_breakline_t new_break;
+               phpdbg_breakopline_t opline_break;
+               int i = sizeof(zend_ulong) * 8 - 1, last_superior_i = -1;
+               phpdbg_btree *branch = PHPDBG_G(opline_btree);
+               HashTable *insert = &PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE];
+               HashTable func_breaks, *func_table;
+
+               do {
+                       if ((opline >> i) % 2 == 0 && !branch->branches[0]) {
+                               if (last_superior_i != -1) {
+                                       i = sizeof(zend_ulong) * 8 - 1;
+                                       do {
+                                               branch = branch->branches[(opline >> i) % 2 == 1 && branch->branches[1]];
+                                       } while (i-- > last_superior_i);
+                                       do {
+                                               branch = branch->branches[!!branch->branches[1]];
+                                       } while (i--);
+                               }
+                               break;
+                       }
+                       if ((opline >> i) % 2 == 1 && branch->branches[1]) {
+                               if (branch->branches[0]) {
+                                       last_superior_i = i;
+                               }
+                               branch = branch->branches[1];
+                       } else {
+                               branch = branch->branches[0];
+                       }
+               } while (--i);
+
+               if (!branch ||
+                   (zend_ulong)(branch->op_array + branch->op_array->last) <= opline ||
+                   (opline - (zend_ulong)branch->op_array) % sizeof(zend_op) > 0) {
+                       phpdbg_error("No opline could be found at 0x%lx", opline);
+               }
+
+               opline_break.opline = (opline - (zend_ulong)branch->op_array) / sizeof(zend_op);
 
                PHPDBG_G(flags) |= PHPDBG_HAS_OPLINE_BP;
 
@@ -265,6 +336,42 @@ PHPDBG_API void phpdbg_set_breakpoint_opline(zend_ulong opline TSRMLS_DC) /* {{{
                zend_hash_index_update(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], opline,
                        &new_break, sizeof(phpdbg_breakline_t), NULL);
 
+               opline_break.func_len = branch->op_array->function_name?strlen(branch->op_array->function_name):0;
+               opline_break.func_name = opline_break.func_len?estrndup(branch->op_array->function_name, opline_break.func_len):"";
+               opline_break.id = new_break.id;
+               if (branch->op_array->scope) {
+                       HashTable class_breaks, *class_table;
+
+                       if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE],
+                               branch->op_array->scope->name,
+                               branch->op_array->scope->name_length,
+                               (void **)&class_table
+                       ) == FAILURE) {
+                               zend_hash_init(&class_breaks, 8, NULL, phpdbg_opline_class_breaks_dtor, 0);
+                               zend_hash_update(
+                                       &PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE],
+                                       branch->op_array->scope->name,
+                                       branch->op_array->scope->name_length,
+                                       (void **)&class_breaks, sizeof(HashTable), (void **)&class_table);
+                       }
+
+                       opline_break.class_len = branch->op_array->scope->name_length;
+                       opline_break.class_name = estrndup(branch->op_array->scope->name, opline_break.class_len);
+
+                       insert = class_table;
+               }
+
+               if (zend_hash_find(insert, opline_break.func_name, opline_break.func_len, (void **)&func_table) == FAILURE) {
+                       zend_hash_init(&func_breaks, 8, NULL, phpdbg_opline_breaks_dtor, 0);
+                       zend_hash_update(
+                               insert,
+                               opline_break.func_name,
+                               opline_break.func_len,
+                               (void **)&func_breaks, sizeof(HashTable), (void **)&func_table);
+               }
+
+               zend_hash_index_update(func_table, opline_break.opline, &opline_break, sizeof(phpdbg_breakopline_t), NULL);
+
                phpdbg_notice("Breakpoint #%d added at %#lx",
                        new_break.id, new_break.opline);
        } else {
@@ -272,6 +379,164 @@ PHPDBG_API void phpdbg_set_breakpoint_opline(zend_ulong opline TSRMLS_DC) /* {{{
        }
 } /* }}} */
 
+PHPDBG_API void phpdbg_resolve_op_array_break(phpdbg_breakopline_t *brake, zend_op_array *op_array TSRMLS_DC) {
+       phpdbg_breakline_t opline_break;
+       if (op_array->last < brake->opline) {
+               if (brake->class_name == NULL) {
+                       phpdbg_error("There are only %d oplines in function %s (breaking at opline %d impossible)", op_array->last, brake->func_name, brake->opline);
+               } else {
+                       phpdbg_error("There are only %d oplines in method %s::%s (breaking at opline %d impossible)", op_array->last, brake->class_name, brake->func_name, brake->opline);
+               }
+       }
+
+       opline_break.id = brake->id;
+       opline_break.opline = (zend_ulong)(op_array->opcodes + brake->opline);
+       opline_break.name = NULL;
+
+       PHPDBG_G(flags) |= PHPDBG_HAS_OPLINE_BP;
+
+       zend_hash_index_update(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], opline_break.opline, &opline_break, sizeof(phpdbg_breakline_t), NULL);
+}
+
+PHPDBG_API void phpdbg_resolve_op_array_breaks(zend_op_array *op_array TSRMLS_DC) {
+       HashTable *func_table = &PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE];
+       HashTable *oplines_table;
+       HashPosition position;
+       phpdbg_breakopline_t *brake;
+
+       if (op_array->scope != NULL &&
+           zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], op_array->scope->name, op_array->scope->name_length, (void **)&func_table) == FAILURE) {
+               return;
+       }
+
+       if (zend_hash_find(func_table, op_array->function_name?op_array->function_name:"", op_array->function_name?strlen(op_array->function_name):0, (void **)&oplines_table) == FAILURE) {
+               return;
+       }
+
+       for (zend_hash_internal_pointer_reset_ex(oplines_table, &position);
+            zend_hash_get_current_data_ex(oplines_table, (void**) &brake, &position) == SUCCESS;
+            zend_hash_move_forward_ex(oplines_table, &position)) {
+               zend_try {
+                       phpdbg_resolve_op_array_break(brake, op_array TSRMLS_CC);
+               } zend_end_try();
+       }
+}
+
+PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break TSRMLS_DC) {
+       HashTable *func_table = EG(function_table);
+       zend_function *func;
+
+       if (new_break->class_name != NULL) {
+               zend_class_entry **ce;
+               if (zend_hash_find(EG(class_table), new_break->class_name, new_break->class_len + 1, (void **)&ce) == FAILURE) {
+                       return FAILURE;
+               }
+               func_table = &(*ce)->function_table;
+       }
+
+       if (zend_hash_find(func_table, new_break->func_name, new_break->func_len + 1, (void **)&func) == FAILURE) {
+               if (new_break->class_name != NULL) {
+                       phpdbg_error("Method %s doesn't exist in class %s", new_break->func_name, new_break->class_name);
+               }
+               return FAILURE;
+       }
+
+       if (func->type != ZEND_USER_FUNCTION) {
+               if (new_break->class_name == NULL) {
+                       phpdbg_error("%s is not an user defined function, no oplines exist", new_break->func_name);
+               } else {
+                       phpdbg_error("%s::%s is not an user defined method, no oplines exist", new_break->class_name, new_break->func_name);
+               }
+       }
+
+       phpdbg_resolve_op_array_break(new_break, &func->op_array TSRMLS_CC);
+
+       return SUCCESS;
+}
+
+PHPDBG_API void phpdbg_set_breakpoint_method_opline(const char *class, const char *method, int opline TSRMLS_DC) /* {{{ */
+{
+       phpdbg_breakopline_t new_break;
+       HashTable class_breaks, *class_table;
+       HashTable method_breaks, *method_table;
+
+       new_break.func_len = strlen(method);
+       new_break.func_name = estrndup(method, new_break.func_len);
+       new_break.class_len = strlen(class);
+       new_break.class_name = estrndup(class, new_break.class_len);
+       new_break.opline = opline;
+       new_break.id = PHPDBG_G(bp_count)++;
+
+       if (phpdbg_resolve_opline_break(&new_break TSRMLS_CC) == FAILURE) {
+               phpdbg_notice("Pending breakpoint #%d at %s::%s:%d", new_break.id, new_break.class_name, new_break.func_name, opline);
+       } else {
+               phpdbg_notice("Breakpoint #%d added at %s::%s:%d", new_break.id, new_break.class_name, new_break.func_name, opline);
+       }
+
+       if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], new_break.class_name, new_break.class_len, (void **)&class_table) == FAILURE) {
+               zend_hash_init(&class_breaks, 8, NULL, phpdbg_opline_class_breaks_dtor, 0);
+               zend_hash_update(
+                       &PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE],
+                       new_break.class_name,
+                       new_break.class_len,
+                       (void **)&class_breaks, sizeof(HashTable), (void **)&class_table);
+       }
+
+       if (zend_hash_find(class_table, new_break.func_name, new_break.func_len, (void **)&method_table) == FAILURE) {
+               zend_hash_init(&method_breaks, 8, NULL, phpdbg_opline_breaks_dtor, 0);
+               zend_hash_update(
+                       class_table,
+                       new_break.func_name,
+                       new_break.func_len,
+                       (void **)&method_breaks, sizeof(HashTable), (void **)&method_table);
+       }
+
+       if (zend_hash_index_exists(method_table, opline)) {
+               phpdbg_notice("Breakpoint already exists for %s::%s:%d", new_break.class_name, new_break.func_name, opline);
+               efree(new_break.func_name);
+               efree(new_break.class_name);
+               PHPDBG_G(bp_count)--;
+               return;
+       }
+
+       zend_hash_index_update(method_table, new_break.opline, &new_break, sizeof(phpdbg_breakopline_t), NULL);
+}
+
+PHPDBG_API void phpdbg_set_breakpoint_function_opline(const char *function, int opline TSRMLS_DC) /* {{{ */
+{
+       phpdbg_breakopline_t new_break;
+       HashTable func_breaks, *func_table;
+
+       new_break.func_len = strlen(function);
+       new_break.func_name = estrndup(function, new_break.func_len);
+       new_break.opline = opline;
+       new_break.id = PHPDBG_G(bp_count)++;
+
+       if (phpdbg_resolve_opline_break(&new_break TSRMLS_CC) == FAILURE) {
+               phpdbg_notice("Pending breakpoint #%d at %s:%d", new_break.id, new_break.func_name, new_break.opline);
+       } else {
+               phpdbg_notice("Breakpoint #%d added at %s:%d", new_break.id, new_break.func_name, new_break.opline);
+       }
+
+       if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], new_break.func_name, new_break.func_len, (void **)&func_table) == FAILURE) {
+               zend_hash_init(&func_breaks, 8, NULL, phpdbg_opline_breaks_dtor, 0);
+               zend_hash_update(
+                       &PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE],
+                       new_break.func_name,
+                       new_break.func_len,
+                       (void **)&func_breaks, sizeof(HashTable), (void **)&func_table);
+       }
+
+       if (zend_hash_index_exists(func_table, opline)) {
+               phpdbg_notice("Breakpoint already exists for %s:%d", new_break.func_len, opline);
+               efree(new_break.func_name);
+               PHPDBG_G(bp_count)--;
+               return;
+       }
+
+       zend_hash_index_update(func_table, new_break.opline, &new_break, sizeof(phpdbg_breakopline_t), NULL);
+}
+
 PHPDBG_API void phpdbg_set_breakpoint_opcode(const char *name, size_t name_len TSRMLS_DC) /* {{{ */
 {
        phpdbg_breakop_t new_break;
index eb30e3ee25449a435fc3e47906a840ec23dc5177..0d72ea902885974a62d33c0e95cc1b455e99b374 100644 (file)
@@ -51,6 +51,18 @@ typedef struct _phpdbg_breakmethod_t {
        int         id;
 } phpdbg_breakmethod_t;
 
+/**
+ * Breakpoint opline num based representation
+ */
+typedef struct _phpdbg_breakopline_t {
+       const char *class_name;
+       size_t      class_len;
+       const char *func_name;
+       size_t      func_len;
+       int         opline;
+       int         id;
+} phpdbg_breakopline_t;
+
 /**
  * Breakpoint opline based representation
  */
@@ -79,12 +91,20 @@ typedef struct _phpdbg_breakcond_t {
        int             id;
 } phpdbg_breakcond_t;
 
+PHPDBG_API void phpdbg_save_oplines(zend_op_array *op_array TSRMLS_DC);
+
+PHPDBG_API void phpdbg_resolve_op_array_breaks(zend_op_array *op_array TSRMLS_DC);
+PHPDBG_API void phpdbg_resolve_op_array_break(phpdbg_breakopline_t *brake, zend_op_array *op_array TSRMLS_DC);
+PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break TSRMLS_DC);
+
 PHPDBG_API void phpdbg_set_breakpoint_file(const char*, long TSRMLS_DC);
 PHPDBG_API void phpdbg_set_breakpoint_symbol(const char*, size_t TSRMLS_DC);
 PHPDBG_API void phpdbg_set_breakpoint_method(const char*, const char* TSRMLS_DC);
 PHPDBG_API void phpdbg_set_breakpoint_opcode(const char*, size_t TSRMLS_DC);
 PHPDBG_API void phpdbg_set_breakpoint_opline(zend_ulong TSRMLS_DC);
 PHPDBG_API void phpdbg_set_breakpoint_opline_ex(phpdbg_opline_ptr_t TSRMLS_DC);
+PHPDBG_API void phpdbg_set_breakpoint_method_opline(const char *class, const char *method, int opline TSRMLS_DC);
+PHPDBG_API void phpdbg_set_breakpoint_function_opline(const char *function, int opline TSRMLS_DC);
 PHPDBG_API void phpdbg_set_breakpoint_expression(const char*, size_t TSRMLS_DC);
 
 int phpdbg_find_breakpoint_file(zend_op_array* TSRMLS_DC);
index 1b9b14b82a221f7bdf9423652057d5972b8b779f..cb2a01b5bd9c2c4cfc9c637de5dc873cd93938c7 100644 (file)
@@ -59,6 +59,15 @@ PHPDBG_BREAK(address) /* {{{ */
                        phpdbg_set_breakpoint_opline(param->addr TSRMLS_CC);
                        break;
 
+               case NUMERIC_METHOD_PARAM:
+                       phpdbg_set_breakpoint_method_opline(param->method.class, param->method.name, param->num TSRMLS_CC);
+                       break;
+
+               case NUMERIC_PARAM:
+               case FILE_PARAM:
+                       phpdbg_set_breakpoint_function_opline(param->str, param->num TSRMLS_CC);
+                       break;
+
                phpdbg_default_switch_case();
        }
 
index e9a81c950596a124cba8ca55360bb574dfddbcac..4f3fe71eed1684276dff51c1714afc7fd4599ef6 100644 (file)
@@ -35,8 +35,10 @@ PHPDBG_API const char *phpdbg_get_param_type(const phpdbg_param_t *param TSRMLS_
                        return "numeric";
                case METHOD_PARAM:
                        return "method";
+               case NUMERIC_METHOD_PARAM:
+                       return "method opline";
                case FILE_PARAM:
-                       return "file";
+                       return "file or function opline";
                case STR_PARAM:
                        return "string";
                default: /* this is bad */
@@ -54,36 +56,44 @@ PHPDBG_API phpdbg_param_type phpdbg_parse_param(const char *str, size_t len, php
        }
 
        if (phpdbg_is_addr(str)) {
-
                param->addr = strtoul(str, 0, 16);
                param->type = ADDR_PARAM;
                goto parsed;
 
        } else if (phpdbg_is_numeric(str)) {
-
                param->num = strtol(str, NULL, 0);
                param->type = NUMERIC_PARAM;
                goto parsed;
 
        } else if (phpdbg_is_class_method(str, len+1, &class_name, &func_name)) {
-
                param->method.class = class_name;
                param->method.name = func_name;
                param->type = METHOD_PARAM;
                goto parsed;
-
        } else {
-               const char *line_pos = strchr(str, ':');
+               char *line_pos = strrchr(str, ':');
 
                if (line_pos && phpdbg_is_numeric(line_pos+1)) {
-                       char path[MAXPATHLEN];
-
-                       memcpy(path, str, line_pos - str);
-                       path[line_pos - str] = 0;
+                       param->len = line_pos - str;
+                       param->str = estrndup(str, param->len);
+
+                       if (strchr(str, ':') == line_pos) {
+                               *line_pos = 0;
+                               param->file.name = phpdbg_resolve_path(param->str TSRMLS_CC);
+                               param->num = param->file.line = strtol(line_pos+1, NULL, 0);
+                               param->type = FILE_PARAM;
+                       } else {
+                               *line_pos = 0;
+                                if (phpdbg_is_class_method(str, line_pos - str, &class_name, &func_name)) {
+                                       param->num = strtol(str, NULL, 0);
+                                       param->method.class = class_name;
+                                       param->method.name = func_name;
+                                       param->type = NUMERIC_METHOD_PARAM;
+                               } else {
+                                       phpdbg_error("Impossible to parse %s", str);
+                               }
+                       }
 
-                       param->file.name = phpdbg_resolve_path(path TSRMLS_CC);
-                       param->file.line = strtol(line_pos+1, NULL, 0);
-                       param->type = FILE_PARAM;
                        goto parsed;
                }
        }
index d72cb5b0bd1741716bc2fea1cd7f795c690f4aaf..69d36828c3548070321a3a578c1bd90db66a07ef 100644 (file)
@@ -37,7 +37,8 @@ typedef enum {
        FILE_PARAM,
        METHOD_PARAM,
        STR_PARAM,
-       NUMERIC_PARAM
+       NUMERIC_PARAM,
+       NUMERIC_METHOD_PARAM
 } phpdbg_param_type;
 
 typedef struct _phpdbg_input_t phpdbg_input_t;