diff options
Diffstat (limited to 'sapi/phpdbg/phpdbg_bp.c')
-rw-r--r-- | sapi/phpdbg/phpdbg_bp.c | 232 |
1 files changed, 184 insertions, 48 deletions
diff --git a/sapi/phpdbg/phpdbg_bp.c b/sapi/phpdbg/phpdbg_bp.c index aaeaee13fd..cd40510c79 100644 --- a/sapi/phpdbg/phpdbg_bp.c +++ b/sapi/phpdbg/phpdbg_bp.c @@ -104,9 +104,18 @@ PHPDBG_API void phpdbg_reset_breakpoints(TSRMLS_D) /* {{{ */ PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC) /* {{{ */ { + char *string; + phpdbg_export_breakpoints_to_string(&string TSRMLS_CC); + fputs(string, handle); +} + +PHPDBG_API void phpdbg_export_breakpoints_to_string(char **str TSRMLS_DC) /* {{{ */ +{ HashTable *table; zend_ulong id = 0L; + *str = ""; + if (zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP])) { phpdbg_notice("exportbreakpoint", "count=\"%d\"", "Exporting %d breakpoints", zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP])); @@ -116,52 +125,54 @@ PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC) /* {{{ */ ZEND_HASH_FOREACH_PTR(table, brake) { if (brake->id == id) { + char *new_str = NULL; + switch (brake->type) { case PHPDBG_BREAK_FILE: { - fprintf(handle, - "break %s:%lu\n", + phpdbg_asprintf(&new_str, + "%sbreak %s:%lu\n", *str, ((phpdbg_breakfile_t*)brake)->filename, ((phpdbg_breakfile_t*)brake)->line); } break; case PHPDBG_BREAK_SYM: { - fprintf(handle, - "break %s\n", + phpdbg_asprintf(&new_str, + "%sbreak %s\n", *str, ((phpdbg_breaksymbol_t*)brake)->symbol); } break; case PHPDBG_BREAK_METHOD: { - fprintf(handle, - "break %s::%s\n", + phpdbg_asprintf(&new_str, + "%sbreak %s::%s\n", *str, ((phpdbg_breakmethod_t*)brake)->class_name, ((phpdbg_breakmethod_t*)brake)->func_name); } break; case PHPDBG_BREAK_METHOD_OPLINE: { - fprintf(handle, - "break %s::%s#%llu\n", + phpdbg_asprintf(&new_str, + "%sbreak %s::%s#%llu\n", *str, ((phpdbg_breakopline_t*)brake)->class_name, ((phpdbg_breakopline_t*)brake)->func_name, ((phpdbg_breakopline_t*)brake)->opline_num); } break; case PHPDBG_BREAK_FUNCTION_OPLINE: { - fprintf(handle, - "break %s#%llu\n", + phpdbg_asprintf(&new_str, + "%sbreak %s#%llu\n", *str, ((phpdbg_breakopline_t*)brake)->func_name, ((phpdbg_breakopline_t*)brake)->opline_num); } break; case PHPDBG_BREAK_FILE_OPLINE: { - fprintf(handle, - "break %s:#%llu\n", + phpdbg_asprintf(&new_str, + "%sbreak %s:#%llu\n", *str, ((phpdbg_breakopline_t*)brake)->class_name, ((phpdbg_breakopline_t*)brake)->opline_num); } break; case PHPDBG_BREAK_OPCODE: { - fprintf(handle, - "break %s\n", + phpdbg_asprintf(&new_str, + "%sbreak %s\n", *str, ((phpdbg_breakop_t*)brake)->name); } break; @@ -171,20 +182,20 @@ PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC) /* {{{ */ if (conditional->paramed) { switch (conditional->param.type) { case STR_PARAM: - fprintf(handle, - "break at %s if %s\n", conditional->param.str, conditional->code); + phpdbg_asprintf(&new_str, + "%sbreak at %s if %s\n", *str, conditional->param.str, conditional->code); break; case METHOD_PARAM: - fprintf(handle, - "break at %s::%s if %s\n", + phpdbg_asprintf(&new_str, + "%sbreak at %s::%s if %s\n", *str, conditional->param.method.class, conditional->param.method.name, conditional->code); break; case FILE_PARAM: - fprintf(handle, - "break at %s:%lu if %s\n", + phpdbg_asprintf(&new_str, + "%sbreak at %s:%lu if %s\n", *str, conditional->param.file.name, conditional->param.file.line, conditional->code); break; @@ -192,65 +203,163 @@ PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC) /* {{{ */ default: { /* do nothing */ } break; } } else { - fprintf( - handle, "break if %s\n", conditional->code); + phpdbg_asprintf(&new_str, "%sbreak if %s\n", str, conditional->code); } } break; } + + if ((*str)[0]) { + efree(*str); + } + *str = new_str; } } ZEND_HASH_FOREACH_END(); } ZEND_HASH_FOREACH_END(); } + + if (!(*str)[0]) { + *str = NULL; + } } /* }}} */ PHPDBG_API void phpdbg_set_breakpoint_file(const char *path, long line_num TSRMLS_DC) /* {{{ */ { php_stream_statbuf ssb; char realpath[MAXPATHLEN]; + const char *original_path = path; + zend_bool pending = 0; - if (php_stream_stat_path(path, &ssb) != FAILURE) { - if (ssb.sb.st_mode & (S_IFREG|S_IFLNK)) { - HashTable *broken; - phpdbg_breakfile_t new_break; - size_t path_len = 0L; + HashTable *broken, *file_breaks = &PHPDBG_G(bp)[PHPDBG_BREAK_FILE]; + phpdbg_breakfile_t new_break; + size_t path_len = 0L; - if (VCWD_REALPATH(path, realpath)) { - path = realpath; + if (VCWD_REALPATH(path, realpath)) { + path = realpath; + } + path_len = strlen(path); + + phpdbg_debug("file path: %s, resolved path: %s, was compiled: %d\n", original_path, path, zend_hash_exists(&PHPDBG_G(file_sources), path, path_len)); + + if (!zend_hash_str_exists(&PHPDBG_G(file_sources), path, path_len)) { + if (php_stream_stat_path(path, &ssb) == FAILURE) { + if (original_path[0] == '/') { + phpdbg_error("breakpoint", "type=\"nofile\" add=\"fail\" file=\"%s\"", "Cannot stat %s, it does not exist", original_path); + return; } + + file_breaks = &PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING]; + path = original_path; path_len = strlen(path); + pending = 1; + } else if (!(ssb.sb.st_mode & (S_IFREG|S_IFLNK))) { + phpdbg_error("breakpoint", "type=\"notregular\" add=\"fail\" file=\"%s\"", "Cannot set breakpoint in %s, it is not a regular file", path); + return; + } else { + phpdbg_debug("File exists, but not compiled\n"); + } + } - if (!(broken = zend_hash_str_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], path, path_len))) { - HashTable breaks; + if (!(broken = zend_hash_str_find_ptr(file_breaks, path, path_len))) { + HashTable breaks; + zend_hash_init(&breaks, 8, NULL, phpdbg_file_breaks_dtor, 0); - zend_hash_init(&breaks, 8, NULL, phpdbg_file_breaks_dtor, 0); + broken = zend_hash_str_add_mem(file_breaks, path, path_len, &breaks, sizeof(HashTable)); + } - broken = zend_hash_str_update_mem(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], path, path_len, &breaks, sizeof(HashTable)); - } + if (!zend_hash_index_exists(broken, line_num)) { + PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_FILE); + new_break.filename = estrndup(path, path_len); + new_break.line = line_num; - if (!zend_hash_index_exists(broken, line_num)) { - PHPDBG_G(flags) |= PHPDBG_HAS_FILE_BP; + zend_hash_index_update_mem(broken, line_num, &new_break, sizeof(phpdbg_breakfile_t)); - PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_FILE); - new_break.filename = estrndup(path, path_len); - new_break.line = line_num; + PHPDBG_BREAK_MAPPING(new_break.id, broken); - zend_hash_index_update_mem(broken, line_num, &new_break, sizeof(phpdbg_breakfile_t)); + if (pending) { + zend_string *file, *path_str = zend_string_init(path, path_len, 0); + ZEND_HASH_FOREACH_STR_KEY(&PHPDBG_G(file_sources), file) { + HashTable *fileht; - phpdbg_notice("breakpoint", "add=\"success\" id=\"%d\" file=\"%s\" line=\"%ld\"", "Breakpoint #%d added at %s:%ld", new_break.id, new_break.filename, new_break.line); + phpdbg_debug("Compare against loaded %s\n", file); - PHPDBG_BREAK_MAPPING(new_break.id, broken); - } else { - phpdbg_error("breakpoint", "type=\"exists\" add=\"fail\" file=\"%s\" line=\"%ld\"", "Breakpoint at %s:%ld exists", path, line_num); - } + if (!(pending = ((fileht = phpdbg_resolve_pending_file_break_ex(file->val, file->len, path_str, broken TSRMLS_CC)) == NULL))) { + new_break = *(phpdbg_breakfile_t *) zend_hash_index_find_ptr(broken, line_num); + break; + } + } ZEND_HASH_FOREACH_END(); + zend_string_release(path_str); + } + if (pending) { + PHPDBG_G(flags) |= PHPDBG_HAS_PENDING_FILE_BP; + + phpdbg_notice("breakpoint", "add=\"success\" id=\"%d\" file=\"%s\" line=\"%ld\" pending=\"pending\"", "Pending breakpoint #%d added at %s:%ld", new_break.id, new_break.filename, new_break.line); } else { - phpdbg_error("breakpoint", "type=\"notregular\" add=\"fail\" file=\"%s\"", "Cannot set breakpoint in %s, it is not a regular file", path); + PHPDBG_G(flags) |= PHPDBG_HAS_FILE_BP; + + phpdbg_notice("breakpoint", "add=\"success\" id=\"%d\" file=\"%s\" line=\"%ld\"", "Breakpoint #%d added at %s:%ld", new_break.id, new_break.filename, new_break.line); } } else { - phpdbg_error("breakpoint", "type=\"nofile\" add=\"fail\" file=\"%s\"", "Cannot stat %s, it does not exist", path); + phpdbg_error("breakpoint", "type=\"exists\" add=\"fail\" file=\"%s\" line=\"%ld\"", "Breakpoint at %s:%ld exists", path, line_num); } } /* }}} */ +PHPDBG_API HashTable *phpdbg_resolve_pending_file_break_ex(const char *file, uint filelen, zend_string *cur, HashTable *fileht TSRMLS_DC) /* {{{ */ +{ + phpdbg_debug("file: %s, filelen: %u, cur: %s, curlen %u, pos: %c, memcmp: %d\n", file, filelen, cur, curlen, filelen > curlen ? file[filelen - curlen - 1] : '?', filelen > curlen ? memcmp(file + filelen - curlen, cur, curlen) : 0); + + if (((cur->len < filelen && file[filelen - cur->len - 1] == '/') || filelen == cur->len) && !memcmp(file + filelen - cur->len, cur->val, cur->len)) { + phpdbg_breakfile_t *brake, new_brake; + HashTable *master; + + PHPDBG_G(flags) |= PHPDBG_HAS_FILE_BP; + + if (!(master = zend_hash_str_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], file, filelen))) { + HashTable new_ht; + zend_hash_init(&new_ht, 8, NULL, phpdbg_file_breaks_dtor, 0); + master = zend_hash_str_add_mem(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], file, filelen, &new_ht, sizeof(HashTable)); + } + + ZEND_HASH_FOREACH_PTR(fileht, brake) { + new_brake = *brake; + new_brake.filename = estrndup(file, filelen); + PHPDBG_BREAK_UNMAPPING(brake->id); + + if (master) { + zend_hash_index_update_mem(master, brake->line, &new_brake, sizeof(phpdbg_breakfile_t)); + PHPDBG_BREAK_MAPPING(brake->id, master); + } + } ZEND_HASH_FOREACH_END(); + + zend_hash_del(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], cur); + + if (!zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING])) { + PHPDBG_G(flags) &= ~PHPDBG_HAS_PENDING_FILE_BP; + } + + phpdbg_debug("compiled file: %s, cur bp file: %s\n", file, cur); + + return master; + } + + return NULL; +} /* }}} */ + +PHPDBG_API void phpdbg_resolve_pending_file_break(const char *file TSRMLS_DC) /* {{{ */ +{ + HashTable *fileht; + uint filelen = strlen(file); + zend_string *cur; + + phpdbg_debug("was compiled: %s\n", file); + + ZEND_HASH_FOREACH_STR_KEY_PTR(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], cur, fileht) { + phpdbg_debug("check bp: %s\n", cur); + + phpdbg_resolve_pending_file_break_ex(file, filelen, cur, fileht TSRMLS_CC); + } ZEND_HASH_FOREACH_END(); +} /* }}} */ + PHPDBG_API void phpdbg_set_breakpoint_symbol(const char *name, size_t name_len TSRMLS_DC) /* {{{ */ { if (!zend_hash_str_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], name, name_len)) { @@ -732,8 +841,21 @@ static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_file(zend_op_array *op_ { HashTable *breaks; phpdbg_breakbase_t *brake; + size_t path_len; + char realpath[MAXPATHLEN]; + const char *path = op_array->filename->val; + + if (VCWD_REALPATH(path, realpath)) { + path = realpath; + } - if (!(breaks = zend_hash_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], op_array->filename))) { + path_len = strlen(path); + +#if 0 + phpdbg_debug("Op at: %.*s %d\n", path_len, path, (*EG(opline_ptr))->lineno); +#endif + + if (!(breaks = zend_hash_str_find_ptr(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], path, path_len))) { return NULL; } @@ -1048,6 +1170,7 @@ PHPDBG_API void phpdbg_delete_breakpoint(zend_ulong num TSRMLS_DC) /* {{{ */ PHPDBG_API void phpdbg_clear_breakpoints(TSRMLS_D) /* {{{ */ { zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE]); + zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING]); zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM]); zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]); zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE]); @@ -1283,7 +1406,20 @@ PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC) /* {{{ */ ((phpdbg_breakbase_t *) brake)->disabled ? " [disabled]" : ""); } ZEND_HASH_FOREACH_END(); } ZEND_HASH_FOREACH_END(); + } if ((PHPDBG_G(flags) & PHPDBG_HAS_PENDING_FILE_BP)) { + HashTable *points; + phpdbg_out(SEPARATE "\n"); + phpdbg_out("Pending File Breakpoints:\n"); + ZEND_HASH_FOREACH_PTR(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_PENDING], points) { + phpdbg_breakfile_t *brake; + + ZEND_HASH_FOREACH_PTR(points, brake) { + phpdbg_writeln("file", "id=\"%d\" name=\"%s\" line=\"%lu\" disabled=\"%s\" pending=\"pending\"", "#%d\t\t%s:%lu%s", + brake->id, brake->filename, brake->line, + ((phpdbg_breakbase_t *) brake)->disabled ? " [disabled]" : ""); + } ZEND_HASH_FOREACH_END(); + } ZEND_HASH_FOREACH_END(); } break; case PHPDBG_BREAK_OPLINE: if ((PHPDBG_G(flags) & PHPDBG_HAS_OPLINE_BP)) { |