void xdebug_branch_post_process(zend_op_array *opa, xdebug_branch_info *branch_info) { unsigned int i; int in_branch = 0, last_start = -1; /* Figure out which CATCHes are chained, and hence which ones should be * considered entry points */ for (i = 0; i < branch_info->entry_points->size; i++) { if (xdebug_set_in(branch_info->entry_points, i) && opa->opcodes[i].opcode == ZEND_CATCH) { only_leave_first_catch(opa, branch_info, opa->opcodes[i].extended_value); } } for (i = 0; i < branch_info->starts->size; i++) { if (xdebug_set_in(branch_info->starts, i)) { if (in_branch) { branch_info->branches[last_start].out[0] = i; branch_info->branches[last_start].end_op = i-1; branch_info->branches[last_start].end_lineno = branch_info->branches[i].start_lineno; } last_start = i; in_branch = 1; } if (xdebug_set_in(branch_info->ends, i)) { branch_info->branches[last_start].out[0] = branch_info->branches[i].out[0]; branch_info->branches[last_start].out[1] = branch_info->branches[i].out[1]; branch_info->branches[last_start].end_op = i; branch_info->branches[last_start].end_lineno = branch_info->branches[i].start_lineno; in_branch = 0; } } }
void xdebug_branch_find_paths(xdebug_branch_info *branch_info) { unsigned int i; for (i = 0; i < branch_info->entry_points->size; i++) { if (xdebug_set_in(branch_info->entry_points, i)) { xdebug_branch_find_path(i, branch_info, NULL); } } branch_info->path_info.path_hash = xdebug_hash_alloc(128, NULL); for (i = 0; i < branch_info->path_info.paths_count; i++) { xdebug_str str = { 0, 0, NULL }; xdebug_create_key_for_path(branch_info->path_info.paths[i], &str); xdebug_hash_add(branch_info->path_info.path_hash, str.d, str.l, branch_info->path_info.paths[i]); xdfree(str.d); } }
static void only_leave_first_catch(zend_op_array *opa, xdebug_branch_info *branch_info, int position) { unsigned int exit_jmp; #if PHP_VERSION_ID >= 70300 && ZEND_USE_ABS_JMP_ADDR zend_op *base_address = &(opa->opcodes[0]); #endif if (opa->opcodes[position].opcode == ZEND_FETCH_CLASS) { position++; } if (opa->opcodes[position].opcode != ZEND_CATCH) { return; } xdebug_set_remove(branch_info->entry_points, position); #if PHP_VERSION_ID >= 70300 if (!(opa->opcodes[position].extended_value & ZEND_LAST_CATCH)) { exit_jmp = XDEBUG_ZNODE_JMP_LINE(opa->opcodes[position].op2, position, base_address); #else if (!opa->opcodes[position].result.num) { # if PHP_VERSION_ID >= 70100 exit_jmp = position + ((signed int) opa->opcodes[position].extended_value / sizeof(zend_op)); # else exit_jmp = opa->opcodes[position].extended_value; # endif #endif if (opa->opcodes[exit_jmp].opcode == ZEND_FETCH_CLASS) { exit_jmp++; } if (opa->opcodes[exit_jmp].opcode == ZEND_CATCH) { only_leave_first_catch(opa, branch_info, exit_jmp); } } } void xdebug_branch_post_process(zend_op_array *opa, xdebug_branch_info *branch_info) { unsigned int i; int in_branch = 0, last_start = -1; #if PHP_VERSION_ID >= 70300 && ZEND_USE_ABS_JMP_ADDR zend_op *base_address = &(opa->opcodes[0]); #endif /* Figure out which CATCHes are chained, and hence which ones should be * considered entry points */ for (i = 0; i < branch_info->entry_points->size; i++) { if (xdebug_set_in(branch_info->entry_points, i) && opa->opcodes[i].opcode == ZEND_CATCH) { #if PHP_VERSION_ID >= 70300 # if ZEND_USE_ABS_JMP_ADDR if (opa->opcodes[i].op2.jmp_addr != NULL) { # else if (opa->opcodes[i].op2.jmp_offset != 0) { # endif only_leave_first_catch(opa, branch_info, XDEBUG_ZNODE_JMP_LINE(opa->opcodes[i].op2, i, base_address)); } #elif PHP_VERSION_ID >= 70100 only_leave_first_catch(opa, branch_info, i + ((signed int) opa->opcodes[i].extended_value / sizeof(zend_op))); #else only_leave_first_catch(opa, branch_info, opa->opcodes[i].extended_value); #endif } } for (i = 0; i < branch_info->starts->size; i++) { if (xdebug_set_in(branch_info->starts, i)) { if (in_branch) { branch_info->branches[last_start].outs_count = 1; branch_info->branches[last_start].outs[0] = i; branch_info->branches[last_start].end_op = i-1; branch_info->branches[last_start].end_lineno = branch_info->branches[i].start_lineno; } last_start = i; in_branch = 1; } if (xdebug_set_in(branch_info->ends, i)) { size_t j; for (j = 0; j < branch_info->branches[i].outs_count; j++) { branch_info->branches[last_start].outs[j] = branch_info->branches[i].outs[j]; } branch_info->branches[last_start].outs_count = branch_info->branches[i].outs_count; branch_info->branches[last_start].end_op = i; branch_info->branches[last_start].end_lineno = branch_info->branches[i].start_lineno; in_branch = 0; } } } void xdebug_path_add(xdebug_path *path, unsigned int nr) { if (!path) { return; } if (path->elements_count == path->elements_size) { path->elements_size += 32; path->elements = realloc(path->elements, sizeof(unsigned int) * path->elements_size); } path->elements[path->elements_count] = nr; path->elements_count++; } static void xdebug_path_info_add_path(xdebug_path_info *path_info, xdebug_path *path) { if (path_info->paths_count == path_info->paths_size) { path_info->paths_size += 32; path_info->paths = realloc(path_info->paths, sizeof(xdebug_path*) * path_info->paths_size); } path_info->paths[path_info->paths_count] = path; path_info->paths_count++; } static void xdebug_path_info_make_sure_level_exists(xdebug_path_info *path_info, unsigned int level TSRMLS_DC) { unsigned int i = 0, orig_size; orig_size = path_info->paths_size; if (level >= path_info->paths_size) { path_info->paths_size = level + 32; path_info->paths = realloc(path_info->paths, sizeof(xdebug_path*) * path_info->paths_size); for (i = orig_size; i < XG(branches).size; i++) { XG(branches).last_branch_nr[i] = -1; } for (i = orig_size; i < path_info->paths_size; i++) { path_info->paths[i] = NULL; } } }