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(void *) * 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 + 2) * sizeof(phpdbg_btree));
- do {
- (*branch)->branches[!(((zend_ulong)op_array->opcodes >> i) % 2)] = NULL;
- branch = &(*branch)->branches[((zend_ulong)op_array->opcodes >> i) % 2];
- *branch = ++memory;
- } while (i--);
- }
-
- if (((*branch)->info.func_name = op_array->function_name)) {
- (*branch)->info.func_len = strlen(op_array->function_name);
- if (op_array->scope) {
- (*branch)->info.class_name = op_array->scope->name;
- (*branch)->info.class_len = op_array->scope->name_length;
- } else {
- (*branch)->info.class_name = NULL;
- (*branch)->info.class_len = 0;
- }
- } else {
- (*branch)->info.func_len = 0;
- (*branch)->info.class_name = op_array->filename;
- (*branch)->info.class_len = strlen(op_array->filename);
- }
- (*branch)->info.last = op_array->last;
-}
-
PHPDBG_API void phpdbg_set_breakpoint_opline(zend_ulong opline TSRMLS_DC) /* {{{ */
{
- if (PHPDBG_G(opline_btree) == NULL) {
- phpdbg_error("No oplines initialized yet");
- return;
- }
-
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(void *) * 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 = EG(function_table);
- zend_ulong opcodes = 0;
-
- /* get highest opcodes root lower than or eqal to opline */
-#define CHOOSE_BRANCH(n) \
- opcodes = (opcodes << 1) + !!(n); \
- branch = branch->branches[!!(n)];
-
- do {
- /* an impossible branch was found if: */
- if ((opline >> i) % 2 == 0 && !branch->branches[0]) {
- /* there's no lower branch than opline */
- if (last_superior_i == -1) {
- phpdbg_error("No opline could be found at 0x%lx", opline);
- return;
- }
- /* reset state */
- branch = PHPDBG_G(opline_btree);
- opcodes = 0;
- i = sizeof(void *) * 8 - 1;
- /* follow branch according to bits in opline until the last lower branch before the impossible branch */
- do {
- CHOOSE_BRANCH((opline >> i) % 2 == 1 && branch->branches[1]);
- } while (--i > last_superior_i);
- /* use now the lower branch of which we can be sure that it contains only branches lower than opline */
- CHOOSE_BRANCH(0);
- /* and choose the highest possible branch in the branch containing only branches lower than opline */
- while (i--) {
- CHOOSE_BRANCH(branch->branches[1]);
- }
- break;
- }
- /* follow branch according to bits in opline until having found an impossible branch */
- if ((opline >> i) % 2 == 1 && branch->branches[1]) {
- if (branch->branches[0]) {
- last_superior_i = i;
- }
- CHOOSE_BRANCH(1);
- } else {
- CHOOSE_BRANCH(0);
- }
- } while (i--);
-
- /* make sure that opline is an opcode address in the closest zend_op array */
- if (opcodes + branch->info.last * sizeof(zend_op) <= opline ||
- (opline - opcodes) % sizeof(zend_op) > 0) {
- phpdbg_error("No opline could be found at 0x%lx; the closest opline is at 0x%lx (%s %s%s%s) with size %ld",
- opline,
- opcodes,
- branch->info.func_name?(branch->info.class_name?"method":"function"):"file",
- branch->info.func_name?branch->info.func_name:"",
- branch->info.func_name&&branch->info.class_name?"::":"",
- branch->info.class_name?branch->info.class_name:"",
- branch->info.last);
- return;
- }
-
- opline_break.opline = (opline - opcodes) / sizeof(zend_op);
PHPDBG_G(flags) |= PHPDBG_HAS_OPLINE_BP;
- opline_break.func_len = branch->info.func_len;
- opline_break.func_name = branch->info.func_name;
- opline_break.id = PHPDBG_G(bp_count)++;
- if (branch->info.func_name == NULL) {
- opline_break.func_len = branch->info.class_len;
- opline_break.func_name = branch->info.class_name;
-
- insert = &PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE];
- PHPDBG_G(flags) |= PHPDBG_HAS_FILE_OPLINE_BP;
- new_break.type = PHPDBG_BREAK_FILE_OPLINE;
- } else if (branch->info.class_name) {
- HashTable class_breaks, *class_table;
-
- if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE],
- branch->info.class_name,
- branch->info.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],
- branch->info.class_name,
- branch->info.class_len,
- (void **)&class_breaks, sizeof(HashTable), (void **)&class_table);
- }
-
- opline_break.class_len = branch->info.class_len;
- opline_break.class_name = branch->info.class_name;
-
- insert = class_table;
- PHPDBG_G(flags) |= PHPDBG_HAS_METHOD_OPLINE_BP;
- new_break.type = PHPDBG_BREAK_METHOD_OPLINE;
- } else {
- PHPDBG_G(flags) |= PHPDBG_HAS_FUNCTION_OPLINE_BP;
- new_break.type = PHPDBG_BREAK_FUNCTION_OPLINE;
- }
-
- 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);
- }
-
- /* insert opline num breakpoint information */
- zend_hash_index_update(func_table, opline_break.opline, &opline_break, sizeof(phpdbg_breakopline_t), NULL);
-
- /* insert opline breakpoint */
new_break.name = NULL;
new_break.opline = opline;
- new_break.id = opline_break.id; /* use same id to identify */
+ new_break.id = PHPDBG_G(bp_count)++;
+
zend_hash_index_update(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], opline,
&new_break, sizeof(phpdbg_breakline_t), NULL);
- phpdbg_notice("Breakpoint #%d added at %#lx (opcode #%ld in %s %s%s%s)",
- new_break.id,
- new_break.opline,
- (opline - opcodes) / sizeof(zend_op),
- branch->info.func_name?(branch->info.class_name?"method":"function"):"file",
- branch->info.func_name?branch->info.func_name:"",
- branch->info.func_name&&branch->info.class_name?"::":"",
- branch->info.class_name?branch->info.class_name:"");
+ phpdbg_notice("Breakpoint #%d added at %#lx",
+ new_break.id, new_break.opline);
} else {
phpdbg_notice("Breakpoint exists at %#lx", opline);
}