root/sapi/phpdbg/phpdbg_bp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. _phpdbg_break_mapping
  2. phpdbg_file_breaks_dtor
  3. phpdbg_class_breaks_dtor
  4. phpdbg_opline_class_breaks_dtor
  5. phpdbg_opline_breaks_dtor
  6. phpdbg_reset_breakpoints
  7. phpdbg_export_breakpoints
  8. phpdbg_set_breakpoint_file
  9. phpdbg_set_breakpoint_symbol
  10. phpdbg_set_breakpoint_method
  11. phpdbg_set_breakpoint_opline
  12. phpdbg_resolve_op_array_break
  13. phpdbg_resolve_op_array_breaks
  14. phpdbg_resolve_opline_break
  15. phpdbg_set_breakpoint_method_opline
  16. phpdbg_set_breakpoint_function_opline
  17. phpdbg_set_breakpoint_file_opline
  18. phpdbg_set_breakpoint_opcode
  19. phpdbg_set_breakpoint_opline_ex
  20. phpdbg_create_conditional_break
  21. phpdbg_set_breakpoint_expression
  22. phpdbg_set_breakpoint_at
  23. phpdbg_find_breakpoint_file
  24. phpdbg_find_breakpoint_symbol
  25. phpdbg_find_breakpoint_method
  26. phpdbg_find_breakpoint_opline
  27. phpdbg_find_breakpoint_opcode
  28. phpdbg_find_breakpoint_param
  29. phpdbg_find_conditional_breakpoint
  30. phpdbg_find_breakpoint
  31. phpdbg_delete_breakpoint
  32. phpdbg_clear_breakpoints
  33. phpdbg_hit_breakpoint
  34. phpdbg_print_breakpoint
  35. phpdbg_enable_breakpoint
  36. phpdbg_disable_breakpoint
  37. phpdbg_enable_breakpoints
  38. phpdbg_disable_breakpoints
  39. phpdbg_find_breakbase
  40. phpdbg_find_breakbase_ex
  41. phpdbg_print_breakpoints

   1 /*
   2    +----------------------------------------------------------------------+
   3    | PHP Version 5                                                        |
   4    +----------------------------------------------------------------------+
   5    | Copyright (c) 1997-2016 The PHP Group                                |
   6    +----------------------------------------------------------------------+
   7    | This source file is subject to version 3.01 of the PHP license,      |
   8    | that is bundled with this package in the file LICENSE, and is        |
   9    | available through the world-wide-web at the following url:           |
  10    | http://www.php.net/license/3_01.txt                                  |
  11    | If you did not receive a copy of the PHP license and are unable to   |
  12    | obtain it through the world-wide-web, please send a note to          |
  13    | license@php.net so we can mail you a copy immediately.               |
  14    +----------------------------------------------------------------------+
  15    | Authors: Felipe Pena <felipe@php.net>                                |
  16    | Authors: Joe Watkins <joe.watkins@live.co.uk>                        |
  17    | Authors: Bob Weinand <bwoebi@php.net>                                |
  18    +----------------------------------------------------------------------+
  19 */
  20 
  21 #include "zend.h"
  22 #include "zend_hash.h"
  23 #include "phpdbg.h"
  24 #include "phpdbg_bp.h"
  25 #include "phpdbg_utils.h"
  26 #include "phpdbg_opcode.h"
  27 #include "zend_globals.h"
  28 
  29 ZEND_EXTERN_MODULE_GLOBALS(phpdbg);
  30 
  31 /* {{{ private api functions */
  32 static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_file(zend_op_array* TSRMLS_DC);
  33 static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_symbol(zend_function* TSRMLS_DC);
  34 static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_method(zend_op_array* TSRMLS_DC);
  35 static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_opline(phpdbg_opline_ptr_t TSRMLS_DC);
  36 static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_opcode(zend_uchar TSRMLS_DC);
  37 static inline phpdbg_breakbase_t *phpdbg_find_conditional_breakpoint(zend_execute_data *execute_data TSRMLS_DC); /* }}} */
  38 
  39 /*
  40 * Note:
  41 *       A break point must always set the correct id and type
  42 *       A set breakpoint function must always map new points
  43 */
  44 static inline void _phpdbg_break_mapping(int id, HashTable *table TSRMLS_DC)
  45 {
  46         zend_hash_index_update(
  47                 &PHPDBG_G(bp)[PHPDBG_BREAK_MAP], (id), (void**) &table, sizeof(void*), NULL);
  48 }
  49 
  50 #define PHPDBG_BREAK_MAPPING(id, table) _phpdbg_break_mapping(id, table TSRMLS_CC)
  51 #define PHPDBG_BREAK_UNMAPPING(id) \
  52         zend_hash_index_del(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], (id))
  53 
  54 #define PHPDBG_BREAK_INIT(b, t) do {\
  55         b.id = PHPDBG_G(bp_count)++; \
  56         b.type = t; \
  57         b.disabled = 0;\
  58         b.hits = 0; \
  59 } while(0)
  60 
  61 static void phpdbg_file_breaks_dtor(void *data) /* {{{ */
  62 {
  63         phpdbg_breakfile_t *bp = (phpdbg_breakfile_t*) data;
  64 
  65         efree((char*)bp->filename);
  66 } /* }}} */
  67 
  68 static void phpdbg_class_breaks_dtor(void *data) /* {{{ */
  69 {
  70         phpdbg_breakmethod_t *bp = (phpdbg_breakmethod_t*) data;
  71 
  72         efree((char*)bp->class_name);
  73         efree((char*)bp->func_name);
  74 } /* }}} */
  75 
  76 static void phpdbg_opline_class_breaks_dtor(void *data) /* {{{ */
  77 {
  78         zend_hash_destroy((HashTable *)data);
  79 } /* }}} */
  80 
  81 static void phpdbg_opline_breaks_dtor(void *data) /* {{{ */
  82 {
  83         phpdbg_breakopline_t *bp = (phpdbg_breakopline_t *) data;
  84 
  85         if (bp->class_name) {
  86                 efree((char*)bp->class_name);
  87         }
  88         if (bp->func_name) {
  89                 efree((char*)bp->func_name);
  90         }
  91 } /* }}} */
  92 
  93 PHPDBG_API void phpdbg_reset_breakpoints(TSRMLS_D) /* {{{ */
  94 {
  95         if (zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP])) {
  96                 HashPosition position[2];
  97                 HashTable **table = NULL;
  98 
  99                 for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], &position[0]);
 100                         zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], (void**)&table, &position[0]) == SUCCESS;
 101                         zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], &position[0])) {
 102                         phpdbg_breakbase_t *brake;
 103 
 104                         for (zend_hash_internal_pointer_reset_ex((*table), &position[1]);
 105                                 zend_hash_get_current_data_ex((*table), (void**)&brake, &position[1]) == SUCCESS;
 106                                 zend_hash_move_forward_ex((*table), &position[1])) {
 107                                 brake->hits = 0;
 108                         }
 109                 }
 110         }
 111 } /* }}} */
 112 
 113 PHPDBG_API void phpdbg_export_breakpoints(FILE *handle TSRMLS_DC) /* {{{ */
 114 {
 115         HashPosition position[2];
 116         HashTable **table = NULL;
 117         zend_ulong id = 0L;
 118 
 119         if (zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP])) {
 120                 phpdbg_notice(
 121                         "Exporting %d breakpoints",
 122                         zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP]));
 123                 /* this only looks like magic, it isn't */
 124                 for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], &position[0]);
 125                         zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], (void**)&table, &position[0]) == SUCCESS;
 126                         zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], &position[0])) {
 127                         phpdbg_breakbase_t *brake;
 128 
 129                         zend_hash_get_current_key_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], NULL, NULL, &id, 0, &position[0]);
 130 
 131                         for (zend_hash_internal_pointer_reset_ex((*table), &position[1]);
 132                                 zend_hash_get_current_data_ex((*table), (void**)&brake, &position[1]) == SUCCESS;
 133                                 zend_hash_move_forward_ex((*table), &position[1])) {
 134                                 if (brake->id == id) {
 135                                         switch (brake->type) {
 136                                                 case PHPDBG_BREAK_FILE: {
 137                                                         fprintf(handle,
 138                                                                 "break %s:%lu\n",
 139                                                                 ((phpdbg_breakfile_t*)brake)->filename,
 140                                                                 ((phpdbg_breakfile_t*)brake)->line);
 141                                                 } break;
 142 
 143                                                 case PHPDBG_BREAK_SYM: {
 144                                                         fprintf(handle,
 145                                                                 "break %s\n",
 146                                                                 ((phpdbg_breaksymbol_t*)brake)->symbol);
 147                                                 } break;
 148 
 149                                                 case PHPDBG_BREAK_METHOD: {
 150                                                         fprintf(handle,
 151                                                                 "break %s::%s\n",
 152                                                                 ((phpdbg_breakmethod_t*)brake)->class_name,
 153                                                                 ((phpdbg_breakmethod_t*)brake)->func_name);
 154                                                 } break;
 155 
 156                                                 case PHPDBG_BREAK_METHOD_OPLINE: {
 157                                                         fprintf(handle,
 158                                                                 "break %s::%s#%ld\n",
 159                                                                 ((phpdbg_breakopline_t*)brake)->class_name,
 160                                                                 ((phpdbg_breakopline_t*)brake)->func_name,
 161                                                                 ((phpdbg_breakopline_t*)brake)->opline_num);
 162                                                 } break;
 163 
 164                                                 case PHPDBG_BREAK_FUNCTION_OPLINE: {
 165                                                         fprintf(handle,
 166                                                                 "break %s#%ld\n",
 167                                                                 ((phpdbg_breakopline_t*)brake)->func_name,
 168                                                                 ((phpdbg_breakopline_t*)brake)->opline_num);
 169                                                 } break;
 170 
 171                                                 case PHPDBG_BREAK_FILE_OPLINE: {
 172                                                         fprintf(handle,
 173                                                                 "break %s:#%ld\n",
 174                                                                 ((phpdbg_breakopline_t*)brake)->class_name,
 175                                                                 ((phpdbg_breakopline_t*)brake)->opline_num);
 176                                                 } break;
 177 
 178                                                 case PHPDBG_BREAK_OPCODE: {
 179                                                         fprintf(handle,
 180                                                                 "break %s\n",
 181                                                                 ((phpdbg_breakop_t*)brake)->name);
 182                                                 } break;
 183 
 184                                                 case PHPDBG_BREAK_COND: {
 185                                                         phpdbg_breakcond_t *conditional = (phpdbg_breakcond_t*) brake;
 186 
 187                                                         if (conditional->paramed) {
 188                                                                 switch (conditional->param.type) {
 189                                                                         case STR_PARAM:
 190                                                                                 fprintf(handle,
 191                                                                                         "break at %s if %s\n", conditional->param.str, conditional->code);
 192                                                                         break;
 193 
 194                                                                         case METHOD_PARAM:
 195                                                                                 fprintf(handle,
 196                                                                                         "break at %s::%s if %s\n",
 197                                                                                         conditional->param.method.class, conditional->param.method.name,
 198                                                                                         conditional->code);
 199                                                                         break;
 200 
 201                                                                         case FILE_PARAM:
 202                                                                                 fprintf(handle,
 203                                                                                         "break at %s:%lu if %s\n",
 204                                                                                         conditional->param.file.name, conditional->param.file.line,
 205                                                                                         conditional->code);
 206                                                                         break;
 207 
 208                                                                         default: { /* do nothing */ } break;
 209                                                                 }
 210                                                         } else {
 211                                                                 fprintf(
 212                                                                         handle, "break if %s\n", conditional->code);
 213                                                         }
 214                                                 } break;
 215                                         }
 216                                 }
 217                         }
 218                 }
 219         }
 220 } /* }}} */
 221 
 222 PHPDBG_API void phpdbg_set_breakpoint_file(const char *path, long line_num TSRMLS_DC) /* {{{ */
 223 {
 224         php_stream_statbuf ssb;
 225         char realpath[MAXPATHLEN];
 226         
 227         if (php_stream_stat_path(path, &ssb) != FAILURE) {
 228                 if (ssb.sb.st_mode & (S_IFREG|S_IFLNK)) {
 229                         HashTable *broken;
 230                         phpdbg_breakfile_t new_break;
 231                         size_t path_len = 0L;
 232                         
 233                         if (VCWD_REALPATH(path, realpath)) {
 234                                 path = realpath;
 235                         }
 236                         path_len = strlen(path);
 237                         
 238                         if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE],
 239                                 path, path_len, (void**)&broken) == FAILURE) {
 240                                 HashTable breaks;
 241 
 242                                 zend_hash_init(&breaks, 8, NULL, phpdbg_file_breaks_dtor, 0);
 243 
 244                                 zend_hash_update(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE],
 245                                         path, path_len, &breaks, sizeof(HashTable),
 246                                         (void**)&broken);
 247                         }
 248 
 249                         if (!zend_hash_index_exists(broken, line_num)) {
 250                                 PHPDBG_G(flags) |= PHPDBG_HAS_FILE_BP;
 251 
 252                                 PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_FILE);
 253                                 new_break.filename = estrndup(path, path_len);
 254                                 new_break.line = line_num;
 255 
 256                                 zend_hash_index_update(
 257                                         broken, line_num, (void**)&new_break, sizeof(phpdbg_breakfile_t), NULL);
 258 
 259                                 phpdbg_notice("Breakpoint #%d added at %s:%ld",
 260                                         new_break.id, new_break.filename, new_break.line);
 261 
 262                                 PHPDBG_BREAK_MAPPING(new_break.id, broken);
 263                         } else {
 264                                 phpdbg_error("Breakpoint at %s:%ld exists", path, line_num);
 265                         }
 266 
 267                 } else {
 268                         phpdbg_error("Cannot set breakpoint in %s, it is not a regular file", path);
 269                 }
 270         } else {
 271                 phpdbg_error("Cannot stat %s, it does not exist", path);
 272         }
 273 } /* }}} */
 274 
 275 PHPDBG_API void phpdbg_set_breakpoint_symbol(const char *name, size_t name_len TSRMLS_DC) /* {{{ */
 276 {
 277         if (!zend_hash_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], name, name_len)) {
 278                 phpdbg_breaksymbol_t new_break;
 279 
 280                 PHPDBG_G(flags) |= PHPDBG_HAS_SYM_BP;
 281 
 282                 PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_SYM);
 283                 new_break.symbol = estrndup(name, name_len);
 284 
 285                 zend_hash_update(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], new_break.symbol,
 286                         name_len, &new_break, sizeof(phpdbg_breaksymbol_t), NULL);
 287 
 288                 phpdbg_notice("Breakpoint #%d added at %s",
 289                         new_break.id, new_break.symbol);
 290 
 291                 PHPDBG_BREAK_MAPPING(new_break.id, &PHPDBG_G(bp)[PHPDBG_BREAK_SYM]);
 292         } else {
 293                 phpdbg_notice("Breakpoint exists at %s", name);
 294         }
 295 } /* }}} */
 296 
 297 PHPDBG_API void phpdbg_set_breakpoint_method(const char *class_name, const char *func_name TSRMLS_DC) /* {{{ */
 298 {
 299         HashTable class_breaks, *class_table;
 300         size_t class_len = strlen(class_name);
 301         size_t func_len = strlen(func_name);
 302         char *lcname = zend_str_tolower_dup(func_name, func_len);
 303 
 304         if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], class_name,
 305                 class_len, (void**)&class_table) != SUCCESS) {
 306                 zend_hash_init(&class_breaks, 8, NULL, phpdbg_class_breaks_dtor, 0);
 307                 zend_hash_update(
 308                         &PHPDBG_G(bp)[PHPDBG_BREAK_METHOD],
 309                         class_name, class_len,
 310                         (void**)&class_breaks, sizeof(HashTable), (void**)&class_table);
 311         }
 312 
 313         if (!zend_hash_exists(class_table, lcname, func_len)) {
 314                 phpdbg_breakmethod_t new_break;
 315 
 316                 PHPDBG_G(flags) |= PHPDBG_HAS_METHOD_BP;
 317 
 318                 PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_METHOD);
 319                 new_break.class_name = estrndup(class_name, class_len);
 320                 new_break.class_len = class_len;
 321                 new_break.func_name = estrndup(func_name, func_len);
 322                 new_break.func_len = func_len;
 323 
 324                 zend_hash_update(class_table, lcname, func_len,
 325                         &new_break, sizeof(phpdbg_breakmethod_t), NULL);
 326 
 327                 phpdbg_notice("Breakpoint #%d added at %s::%s",
 328                         new_break.id, class_name, func_name);
 329 
 330                 PHPDBG_BREAK_MAPPING(new_break.id, class_table);
 331         } else {
 332                 phpdbg_notice("Breakpoint exists at %s::%s", class_name, func_name);
 333         }
 334 
 335         efree(lcname);
 336 } /* }}} */
 337 
 338 PHPDBG_API void phpdbg_set_breakpoint_opline(zend_ulong opline TSRMLS_DC) /* {{{ */
 339 {
 340         if (!zend_hash_index_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], opline)) {
 341                 phpdbg_breakline_t new_break;
 342 
 343                 PHPDBG_G(flags) |= PHPDBG_HAS_OPLINE_BP;
 344 
 345                 PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_OPLINE);
 346                 new_break.name = NULL;
 347                 new_break.opline = opline;
 348                 new_break.base = NULL;
 349 
 350                 zend_hash_index_update(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], opline,
 351                         &new_break, sizeof(phpdbg_breakline_t), NULL);
 352 
 353                 phpdbg_notice("Breakpoint #%d added at %#lx",
 354                         new_break.id, new_break.opline);
 355                 PHPDBG_BREAK_MAPPING(new_break.id, &PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]);
 356         } else {
 357                 phpdbg_notice("Breakpoint exists at %#lx", opline);
 358         }
 359 } /* }}} */
 360 
 361 PHPDBG_API int phpdbg_resolve_op_array_break(phpdbg_breakopline_t *brake, zend_op_array *op_array TSRMLS_DC) /* {{{ */
 362 {
 363         phpdbg_breakline_t opline_break;
 364         if (op_array->last <= brake->opline_num) {
 365                 if (brake->class_name == NULL) {
 366                         phpdbg_error("There are only %d oplines in function %s (breaking at opline %ld impossible)", op_array->last, brake->func_name, brake->opline_num);
 367                 } else if (brake->func_name == NULL) {
 368                         phpdbg_error("There are only %d oplines in file %s (breaking at opline %ld impossible)", op_array->last, brake->class_name, brake->opline_num);
 369                 } else {
 370                         phpdbg_error("There are only %d oplines in method %s::%s (breaking at opline %ld impossible)", op_array->last, brake->class_name, brake->func_name, brake->opline_num);
 371                 }
 372 
 373                 return FAILURE;
 374         }
 375 
 376         opline_break.disabled = 0;
 377         opline_break.hits = 0;
 378         opline_break.id = brake->id;
 379         opline_break.opline = brake->opline = (zend_ulong)(op_array->opcodes + brake->opline_num);
 380         opline_break.name = NULL;
 381         opline_break.base = brake;
 382         if (op_array->scope) {
 383                 opline_break.type = PHPDBG_BREAK_METHOD_OPLINE;
 384         } else if (op_array->function_name) {
 385                 opline_break.type = PHPDBG_BREAK_FUNCTION_OPLINE;
 386         } else {
 387                 opline_break.type = PHPDBG_BREAK_FILE_OPLINE;
 388         }
 389 
 390         PHPDBG_G(flags) |= PHPDBG_HAS_OPLINE_BP;
 391 
 392         zend_hash_index_update(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], opline_break.opline, &opline_break, sizeof(phpdbg_breakline_t), NULL);
 393 
 394         return SUCCESS;
 395 } /* }}} */
 396 
 397 PHPDBG_API void phpdbg_resolve_op_array_breaks(zend_op_array *op_array TSRMLS_DC) /* {{{ */
 398 {
 399         HashTable *func_table = &PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE];
 400         HashTable *oplines_table;
 401         HashPosition position;
 402         phpdbg_breakopline_t *brake;
 403 
 404         if (op_array->scope != NULL &&
 405             zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], op_array->scope->name, op_array->scope->name_length, (void **)&func_table) == FAILURE) {
 406                 return;
 407         }
 408 
 409         if (op_array->function_name == NULL) {
 410                 if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], op_array->filename, strlen(op_array->filename), (void **)&oplines_table) == FAILURE) {
 411                         return;
 412                 }
 413         } else 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) {
 414                 return;
 415         }
 416 
 417         for (zend_hash_internal_pointer_reset_ex(oplines_table, &position);
 418              zend_hash_get_current_data_ex(oplines_table, (void**) &brake, &position) == SUCCESS;
 419              zend_hash_move_forward_ex(oplines_table, &position)) {
 420                 if (phpdbg_resolve_op_array_break(brake, op_array TSRMLS_CC) == SUCCESS) {
 421                         phpdbg_breakline_t *opline_break;
 422 
 423                         zend_hash_internal_pointer_end(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]);
 424                         zend_hash_get_current_data(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], (void **)&opline_break);
 425 
 426                         phpdbg_notice("Breakpoint #%d resolved at %s%s%s#%ld (opline %#lx)",
 427                                 brake->id,
 428                                 brake->class_name?brake->class_name:"",
 429                                 brake->class_name&&brake->func_name?"::":"",
 430                                 brake->func_name?brake->func_name:"",
 431                                 brake->opline_num,
 432                                 brake->opline);
 433                 }
 434         }
 435 } /* }}} */
 436 
 437 PHPDBG_API int phpdbg_resolve_opline_break(phpdbg_breakopline_t *new_break TSRMLS_DC) /* {{{ */
 438 {
 439         HashTable *func_table = EG(function_table);
 440         zend_function *func;
 441 
 442         if (new_break->func_name == NULL) {
 443                 if (EG(current_execute_data) == NULL) {
 444                         if (PHPDBG_G(ops) != NULL && !memcmp(PHPDBG_G(ops)->filename, new_break->class_name, new_break->class_len)) {
 445                                 if (phpdbg_resolve_op_array_break(new_break, PHPDBG_G(ops) TSRMLS_CC) == SUCCESS) {
 446                                         return SUCCESS;
 447                                 } else {
 448                                         return 2;
 449                                 }
 450                         }
 451                         return FAILURE;
 452                 } else {
 453                         zend_execute_data *execute_data = EG(current_execute_data);
 454                         do {
 455                                 if (execute_data->op_array->function_name == NULL && execute_data->op_array->scope == NULL && !memcmp(execute_data->op_array->filename, new_break->class_name, new_break->class_len)) {
 456                                         if (phpdbg_resolve_op_array_break(new_break, execute_data->op_array TSRMLS_CC) == SUCCESS) {
 457                                                 return SUCCESS;
 458                                         } else {
 459                                                 return 2;
 460                                         }
 461                                 }
 462                         } while ((execute_data = execute_data->prev_execute_data) != NULL);
 463                         return FAILURE;
 464                 }
 465         }
 466 
 467         if (new_break->class_name != NULL) {
 468                 zend_class_entry **ce;
 469                 if (zend_hash_find(EG(class_table), zend_str_tolower_dup(new_break->class_name, new_break->class_len), new_break->class_len + 1, (void **)&ce) == FAILURE) {
 470                         return FAILURE;
 471                 }
 472                 func_table = &(*ce)->function_table;
 473         }
 474 
 475         if (zend_hash_find(func_table, zend_str_tolower_dup(new_break->func_name, new_break->func_len), new_break->func_len + 1, (void **)&func) == FAILURE) {
 476                 if (new_break->class_name != NULL && new_break->func_name != NULL) {
 477                         phpdbg_error("Method %s doesn't exist in class %s", new_break->func_name, new_break->class_name);
 478                         return 2;
 479                 }
 480                 return FAILURE;
 481         }
 482 
 483         if (func->type != ZEND_USER_FUNCTION) {
 484                 if (new_break->class_name == NULL) {
 485                         phpdbg_error("%s is not an user defined function, no oplines exist", new_break->func_name);
 486                 } else {
 487                         phpdbg_error("%s::%s is not an user defined method, no oplines exist", new_break->class_name, new_break->func_name);
 488                 }
 489                 return 2;
 490         }
 491 
 492         if (phpdbg_resolve_op_array_break(new_break, &func->op_array TSRMLS_CC) == FAILURE) {
 493                 return 2;
 494         }
 495 
 496         return SUCCESS;
 497 } /* }}} */
 498 
 499 PHPDBG_API void phpdbg_set_breakpoint_method_opline(const char *class, const char *method, zend_ulong opline TSRMLS_DC) /* {{{ */
 500 {
 501         phpdbg_breakopline_t new_break;
 502         HashTable class_breaks, *class_table;
 503         HashTable method_breaks, *method_table;
 504 
 505         PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_METHOD_OPLINE);
 506         new_break.func_len = strlen(method);
 507         new_break.func_name = estrndup(method, new_break.func_len);
 508         new_break.class_len = strlen(class);
 509         new_break.class_name = estrndup(class, new_break.class_len);
 510         new_break.opline_num = opline;
 511         new_break.opline = 0;
 512 
 513         switch (phpdbg_resolve_opline_break(&new_break TSRMLS_CC)) {
 514                 case FAILURE:
 515                         phpdbg_notice("Pending breakpoint #%d at %s::%s#%ld", new_break.id, new_break.class_name, new_break.func_name, opline);
 516                         break;
 517 
 518                 case SUCCESS:
 519                         phpdbg_notice("Breakpoint #%d added at %s::%s#%ld", new_break.id, new_break.class_name, new_break.func_name, opline);
 520                         break;
 521 
 522                 case 2:
 523                         return;
 524         }
 525 
 526         if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], new_break.class_name, new_break.class_len, (void **)&class_table) == FAILURE) {
 527                 zend_hash_init(&class_breaks, 8, NULL, phpdbg_opline_class_breaks_dtor, 0);
 528                 zend_hash_update(
 529                         &PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE],
 530                         new_break.class_name,
 531                         new_break.class_len,
 532                         (void **)&class_breaks, sizeof(HashTable), (void **)&class_table);
 533         }
 534 
 535         if (zend_hash_find(class_table, new_break.func_name, new_break.func_len, (void **)&method_table) == FAILURE) {
 536                 zend_hash_init(&method_breaks, 8, NULL, phpdbg_opline_breaks_dtor, 0);
 537                 zend_hash_update(
 538                         class_table,
 539                         new_break.func_name,
 540                         new_break.func_len,
 541                         (void **)&method_breaks, sizeof(HashTable), (void **)&method_table);
 542         }
 543 
 544         if (zend_hash_index_exists(method_table, opline)) {
 545                 phpdbg_notice("Breakpoint already exists for %s::%s#%ld", new_break.class_name, new_break.func_name, opline);
 546                 efree((char*)new_break.func_name);
 547                 efree((char*)new_break.class_name);
 548                 PHPDBG_G(bp_count)--;
 549                 return;
 550         }
 551 
 552         PHPDBG_G(flags) |= PHPDBG_HAS_METHOD_OPLINE_BP;
 553 
 554         PHPDBG_BREAK_MAPPING(new_break.id, method_table);
 555 
 556         zend_hash_index_update(method_table, opline, &new_break, sizeof(phpdbg_breakopline_t), NULL);
 557 }
 558 
 559 PHPDBG_API void phpdbg_set_breakpoint_function_opline(const char *function, zend_ulong opline TSRMLS_DC) /* {{{ */
 560 {
 561         phpdbg_breakopline_t new_break;
 562         HashTable func_breaks, *func_table;
 563 
 564         PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_FUNCTION_OPLINE);
 565         new_break.func_len = strlen(function);
 566         new_break.func_name = estrndup(function, new_break.func_len);
 567         new_break.class_len = 0;
 568         new_break.class_name = NULL;
 569         new_break.opline_num = opline;
 570         new_break.opline = 0;
 571 
 572         switch (phpdbg_resolve_opline_break(&new_break TSRMLS_CC)) {
 573                 case FAILURE:
 574                         phpdbg_notice("Pending breakpoint #%d at %s#%ld", new_break.id, new_break.func_name, opline);
 575                         break;
 576 
 577                 case SUCCESS:
 578                         phpdbg_notice("Breakpoint #%d added at %s#%ld", new_break.id, new_break.func_name, opline);
 579                         break;
 580 
 581                 case 2:
 582                         return;
 583         }
 584 
 585         if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], new_break.func_name, new_break.func_len, (void **)&func_table) == FAILURE) {
 586                 zend_hash_init(&func_breaks, 8, NULL, phpdbg_opline_breaks_dtor, 0);
 587                 zend_hash_update(
 588                         &PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE],
 589                         new_break.func_name,
 590                         new_break.func_len,
 591                         (void **)&func_breaks, sizeof(HashTable), (void **)&func_table);
 592         }
 593 
 594         if (zend_hash_index_exists(func_table, opline)) {
 595                 phpdbg_notice("Breakpoint already exists for %s#%ld", new_break.func_name, opline);
 596                 efree((char*)new_break.func_name);
 597                 PHPDBG_G(bp_count)--;
 598                 return;
 599         }
 600 
 601         PHPDBG_BREAK_MAPPING(new_break.id, func_table);
 602 
 603         PHPDBG_G(flags) |= PHPDBG_HAS_FUNCTION_OPLINE_BP;
 604 
 605         zend_hash_index_update(func_table, opline, &new_break, sizeof(phpdbg_breakopline_t), NULL);
 606 }
 607 
 608 PHPDBG_API void phpdbg_set_breakpoint_file_opline(const char *file, zend_ulong opline TSRMLS_DC) /* {{{ */
 609 {
 610         phpdbg_breakopline_t new_break;
 611         HashTable file_breaks, *file_table;
 612 
 613         PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_FILE_OPLINE);
 614         new_break.func_len = 0;
 615         new_break.func_name = NULL;
 616         new_break.class_len = strlen(file);
 617         new_break.class_name = estrndup(file, new_break.class_len);
 618         new_break.opline_num = opline;
 619         new_break.opline = 0;
 620 
 621         switch (phpdbg_resolve_opline_break(&new_break TSRMLS_CC)) {
 622                 case FAILURE:
 623                         phpdbg_notice("Pending breakpoint #%d at %s:%ld", new_break.id, new_break.class_name, opline);
 624                         break;
 625 
 626                 case SUCCESS:
 627                         phpdbg_notice("Breakpoint #%d added at %s:%ld", new_break.id, new_break.class_name, opline);
 628                         break;
 629 
 630                 case 2:
 631                         return;
 632         }
 633 
 634         if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], new_break.class_name, new_break.class_len, (void **)&file_table) == FAILURE) {
 635                 zend_hash_init(&file_breaks, 8, NULL, phpdbg_opline_breaks_dtor, 0);
 636                 zend_hash_update(
 637                         &PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE],
 638                         new_break.class_name,
 639                         new_break.class_len,
 640                         (void **)&file_breaks, sizeof(HashTable), (void **)&file_table);
 641         }
 642 
 643         if (zend_hash_index_exists(file_table, opline)) {
 644                 phpdbg_notice("Breakpoint already exists for %s:%ld", new_break.class_name, opline);
 645                 efree((char*)new_break.class_name);
 646                 PHPDBG_G(bp_count)--;
 647                 return;
 648         }
 649 
 650         PHPDBG_BREAK_MAPPING(new_break.id, file_table);
 651 
 652         PHPDBG_G(flags) |= PHPDBG_HAS_FILE_OPLINE_BP;
 653 
 654         zend_hash_index_update(file_table, opline, &new_break, sizeof(phpdbg_breakopline_t), NULL);
 655 }
 656 
 657 PHPDBG_API void phpdbg_set_breakpoint_opcode(const char *name, size_t name_len TSRMLS_DC) /* {{{ */
 658 {
 659         phpdbg_breakop_t new_break;
 660         zend_ulong hash = zend_hash_func(name, name_len);
 661 
 662         if (zend_hash_index_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], hash)) {
 663                 phpdbg_notice(
 664                         "Breakpoint exists for %s", name);
 665                 return;
 666         }
 667 
 668         PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_OPCODE);
 669         new_break.hash = hash;
 670         new_break.name = estrndup(name, name_len);
 671 
 672         zend_hash_index_update(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], hash,
 673                 &new_break, sizeof(phpdbg_breakop_t), NULL);
 674 
 675         PHPDBG_G(flags) |= PHPDBG_HAS_OPCODE_BP;
 676 
 677         phpdbg_notice("Breakpoint #%d added at %s", new_break.id, name);
 678         PHPDBG_BREAK_MAPPING(new_break.id, &PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE]);
 679 } /* }}} */
 680 
 681 PHPDBG_API void phpdbg_set_breakpoint_opline_ex(phpdbg_opline_ptr_t opline TSRMLS_DC) /* {{{ */
 682 {
 683         if (!zend_hash_index_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], (zend_ulong) opline)) {
 684                 phpdbg_breakline_t new_break;
 685 
 686                 PHPDBG_G(flags) |= PHPDBG_HAS_OPLINE_BP;
 687 
 688                 PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_OPLINE);
 689                 new_break.opline = (zend_ulong) opline;
 690                 new_break.base = NULL;
 691 
 692                 zend_hash_index_update(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE],
 693                         (zend_ulong) opline, &new_break, sizeof(phpdbg_breakline_t), NULL);
 694 
 695                 phpdbg_notice("Breakpoint #%d added at %#lx",
 696                         new_break.id, new_break.opline);
 697                 PHPDBG_BREAK_MAPPING(new_break.id, &PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]);
 698         }
 699 } /* }}} */
 700 
 701 static inline void phpdbg_create_conditional_break(phpdbg_breakcond_t *brake, const phpdbg_param_t *param, const char *expr, size_t expr_len, zend_ulong hash TSRMLS_DC) /* {{{ */
 702 {
 703         phpdbg_breakcond_t new_break;
 704         zend_uint cops = CG(compiler_options);
 705         zval pv;
 706 
 707         PHPDBG_BREAK_INIT(new_break, PHPDBG_BREAK_COND);
 708         new_break.hash = hash;
 709 
 710         if (param) {
 711                 new_break.paramed = 1;
 712                 phpdbg_copy_param(
 713                         param, &new_break.param TSRMLS_CC);
 714         } else {
 715                 new_break.paramed = 0;
 716         }
 717 
 718         cops = CG(compiler_options);
 719 
 720         CG(compiler_options) = ZEND_COMPILE_DEFAULT_FOR_EVAL;
 721 
 722         new_break.code = estrndup(expr, expr_len);
 723         new_break.code_len = expr_len;
 724 
 725         Z_STRLEN(pv) = expr_len + sizeof("return ;") - 1;
 726         Z_STRVAL(pv) = emalloc(Z_STRLEN(pv) + 1);
 727         memcpy(Z_STRVAL(pv), "return ", sizeof("return ") - 1);
 728         memcpy(Z_STRVAL(pv) + sizeof("return ") - 1, expr, expr_len);
 729         Z_STRVAL(pv)[Z_STRLEN(pv) - 1] = ';';
 730         Z_STRVAL(pv)[Z_STRLEN(pv)] = '\0';
 731         Z_TYPE(pv) = IS_STRING;
 732 
 733         new_break.ops = zend_compile_string(
 734                 &pv, "Conditional Breakpoint Code" TSRMLS_CC);
 735 
 736         zval_dtor(&pv);
 737 
 738         if (new_break.ops) {
 739                 zend_hash_index_update(
 740                         &PHPDBG_G(bp)[PHPDBG_BREAK_COND], hash, &new_break,
 741                         sizeof(phpdbg_breakcond_t), (void**)&brake);
 742 
 743                 phpdbg_notice("Conditional breakpoint #%d added %s/%p",
 744                         brake->id, brake->code, brake->ops);
 745 
 746                 PHPDBG_G(flags) |= PHPDBG_HAS_COND_BP;
 747                 PHPDBG_BREAK_MAPPING(new_break.id, &PHPDBG_G(bp)[PHPDBG_BREAK_COND]);
 748         } else {
 749                  phpdbg_error(
 750                         "Failed to compile code for expression %s", expr);
 751                  efree((char*)new_break.code);
 752                  PHPDBG_G(bp_count)--;
 753         }
 754         CG(compiler_options) = cops;
 755 } /* }}} */
 756 
 757 PHPDBG_API void phpdbg_set_breakpoint_expression(const char *expr, size_t expr_len TSRMLS_DC) /* {{{ */
 758 {
 759         zend_ulong expr_hash = zend_inline_hash_func(expr, expr_len);
 760         phpdbg_breakcond_t new_break;
 761 
 762         if (!zend_hash_index_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], expr_hash)) {
 763                 phpdbg_create_conditional_break(
 764                         &new_break, NULL, expr, expr_len, expr_hash TSRMLS_CC);
 765         } else {
 766                 phpdbg_notice("Conditional break %s exists", expr);
 767         }
 768 } /* }}} */
 769 
 770 PHPDBG_API void phpdbg_set_breakpoint_at(const phpdbg_param_t *param TSRMLS_DC) /* {{{ */
 771 {
 772         phpdbg_breakcond_t new_break;
 773         phpdbg_param_t *condition;
 774         zend_ulong hash = 0L;
 775         
 776         if (param->next) {
 777                 condition = param->next;
 778                 hash = zend_inline_hash_func(condition->str, condition->len);
 779                 
 780                 if (!zend_hash_index_exists(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], hash)) {
 781                         phpdbg_create_conditional_break(
 782                                 &new_break, param, 
 783                                         condition->str, condition->len, hash TSRMLS_CC);
 784                 } else {
 785                         phpdbg_notice(
 786                                 "Conditional break %s exists at the specified location", condition->str);
 787                 }       
 788         }
 789         
 790 } /* }}} */
 791 
 792 static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_file(zend_op_array *op_array TSRMLS_DC) /* {{{ */
 793 {
 794         HashTable *breaks;
 795         phpdbg_breakbase_t *brake;
 796         size_t name_len = strlen(op_array->filename);
 797 
 798         if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], op_array->filename,
 799                 name_len, (void**)&breaks) == FAILURE) {
 800                 return NULL;
 801         }
 802 
 803         if (zend_hash_index_find(breaks, (*EG(opline_ptr))->lineno, (void**)&brake) == SUCCESS) {
 804                 return brake;
 805         }
 806 
 807         return NULL;
 808 } /* }}} */
 809 
 810 static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_symbol(zend_function *fbc TSRMLS_DC) /* {{{ */
 811 {
 812         const char *fname;
 813         zend_op_array *ops;
 814         phpdbg_breakbase_t *brake;
 815 
 816         if (fbc->type != ZEND_USER_FUNCTION) {
 817                 return NULL;
 818         }
 819 
 820         ops = (zend_op_array*)fbc;
 821 
 822         if (ops->scope) {
 823                 /* find method breaks here */
 824                 return phpdbg_find_breakpoint_method(ops TSRMLS_CC);
 825         }
 826 
 827         fname = ops->function_name;
 828 
 829         if (!fname) {
 830                 fname = "main";
 831         }
 832 
 833         if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], fname, strlen(fname), (void**)&brake) == SUCCESS) {
 834                 return brake;
 835         }
 836 
 837         return NULL;
 838 } /* }}} */
 839 
 840 static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_method(zend_op_array *ops TSRMLS_DC) /* {{{ */
 841 {
 842         HashTable *class_table;
 843         phpdbg_breakbase_t *brake;
 844 
 845         if (zend_hash_find(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], ops->scope->name,
 846                 ops->scope->name_length, (void**)&class_table) == SUCCESS) {
 847                 char *lcname = zend_str_tolower_dup(ops->function_name, strlen(ops->function_name));
 848                 size_t lcname_len = strlen(lcname);
 849 
 850                 if (zend_hash_find(
 851                         class_table,
 852                         lcname,
 853                         lcname_len, (void**)&brake) == SUCCESS) {
 854                         efree(lcname);
 855                         return brake;
 856                 }
 857 
 858                 efree(lcname);
 859         }
 860 
 861         return NULL;
 862 } /* }}} */
 863 
 864 static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_opline(phpdbg_opline_ptr_t opline TSRMLS_DC) /* {{{ */
 865 {
 866         phpdbg_breakline_t *brake;
 867 
 868         if (zend_hash_index_find(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE],
 869                 (zend_ulong) opline, (void**)&brake) == SUCCESS) {
 870                 return (brake->base?(phpdbg_breakbase_t *)brake->base:(phpdbg_breakbase_t *)brake);
 871         }
 872 
 873         return NULL;
 874 } /* }}} */
 875 
 876 static inline phpdbg_breakbase_t *phpdbg_find_breakpoint_opcode(zend_uchar opcode TSRMLS_DC) /* {{{ */
 877 {
 878         phpdbg_breakbase_t *brake;
 879         const char *opname = phpdbg_decode_opcode(opcode);
 880 
 881         if (memcmp(opname, PHPDBG_STRL("UNKNOWN")) == 0) {
 882                 return NULL;
 883         }
 884 
 885         if (zend_hash_index_find(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE],
 886                 zend_hash_func(opname, strlen(opname)), (void**)&brake) == SUCCESS) {
 887                 return brake;
 888         }
 889         return NULL;
 890 } /* }}} */
 891 
 892 static inline zend_bool phpdbg_find_breakpoint_param(phpdbg_param_t *param, zend_execute_data *execute_data TSRMLS_DC) /* {{{ */
 893 {
 894         zend_function *function = (zend_function*) execute_data->function_state.function;
 895 
 896         switch (param->type) {
 897                 case NUMERIC_FUNCTION_PARAM:
 898                 case STR_PARAM: {
 899                         /* function breakpoint */
 900 
 901                         if (function->type != ZEND_USER_FUNCTION) {
 902                                 return 0;
 903                         }
 904 
 905                         {
 906                                 const char *str = NULL;
 907                                 size_t len = 0L;
 908                                 zend_op_array *ops = (zend_op_array*)function;
 909                                 str = ops->function_name ? ops->function_name : "main";
 910                                 len = strlen(str);
 911 
 912                                 if (len == param->len && memcmp(param->str, str, len) == SUCCESS) {
 913                                         return param->type == STR_PARAM || execute_data->opline - ops->opcodes == param->num;
 914                                 }
 915                         }
 916                 } break;
 917 
 918                 case FILE_PARAM: {
 919                         if (param->file.line == zend_get_executed_lineno(TSRMLS_C)) {
 920                                 const char *str = zend_get_executed_filename(TSRMLS_C);
 921                                 size_t lengths[2] = {strlen(param->file.name), strlen(str)};
 922 
 923                                 if (lengths[0] == lengths[1]) {
 924                                         return (memcmp(
 925                                                 param->file.name, str, lengths[0]) == SUCCESS);
 926                                 }
 927                         }
 928                 } break;
 929 
 930                 case NUMERIC_METHOD_PARAM:
 931                 case METHOD_PARAM: {
 932                         if (function->type != ZEND_USER_FUNCTION) {
 933                                 return 0;
 934                         }
 935 
 936                         {
 937                                 zend_op_array *ops = (zend_op_array*) function;
 938 
 939                                 if (ops->scope) {
 940                                         size_t lengths[2] = {strlen(param->method.class), ops->scope->name_length};
 941                                         if (lengths[0] == lengths[1] && memcmp(param->method.class, ops->scope->name, lengths[0]) == SUCCESS) {
 942                                                 lengths[0] = strlen(param->method.name);
 943                                                 lengths[1] = strlen(ops->function_name);
 944 
 945                                                 if (lengths[0] == lengths[1] && memcmp(param->method.name, ops->function_name, lengths[0]) == SUCCESS) {
 946                                                         return param->type == METHOD_PARAM || (execute_data->opline - ops->opcodes) == param->num;
 947                                                 }
 948                                         }
 949                                 }
 950                         }
 951                 } break;
 952 
 953                 case ADDR_PARAM: {
 954                         return ((zend_ulong)(phpdbg_opline_ptr_t)execute_data->opline == param->addr);
 955                 } break;
 956 
 957                 default: {
 958                         /* do nothing */
 959                 } break;
 960         }
 961         return 0;
 962 } /* }}} */
 963 
 964 static inline phpdbg_breakbase_t *phpdbg_find_conditional_breakpoint(zend_execute_data *execute_data TSRMLS_DC) /* {{{ */
 965 {
 966         phpdbg_breakcond_t *bp;
 967         HashPosition position;
 968         int breakpoint = FAILURE;
 969 
 970         for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], &position);
 971              zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], (void*)&bp, &position) == SUCCESS;
 972              zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], &position)) {
 973                 zval *retval = NULL;
 974                 int orig_interactive = CG(interactive);
 975                 zval **orig_retval = EG(return_value_ptr_ptr);
 976                 zend_op_array *orig_ops = EG(active_op_array);
 977                 zend_op **orig_opline = EG(opline_ptr);
 978 
 979                 if (((phpdbg_breakbase_t*)bp)->disabled) {
 980                         continue;
 981                 }
 982 
 983                 if (bp->paramed) {
 984                         if (!phpdbg_find_breakpoint_param(&bp->param, execute_data TSRMLS_CC)) {
 985                                 continue;
 986                         }
 987                 }
 988 
 989                 ALLOC_INIT_ZVAL(retval);
 990 
 991                 EG(return_value_ptr_ptr) = &retval;
 992                 EG(active_op_array) = bp->ops;
 993                 EG(no_extensions) = 1;
 994 
 995                 if (!EG(active_symbol_table)) {
 996                         zend_rebuild_symbol_table(TSRMLS_C);
 997                 }
 998 
 999                 CG(interactive) = 0;
1000 
1001                 zend_try {
1002                         PHPDBG_G(flags) |= PHPDBG_IN_COND_BP;
1003                         zend_execute(EG(active_op_array) TSRMLS_CC);
1004 #if PHP_VERSION_ID >= 50700
1005                         if (zend_is_true(retval TSRMLS_CC)) {
1006 #else
1007                         if (zend_is_true(retval)) {
1008 #endif
1009                                 breakpoint = SUCCESS;
1010                         }
1011                 } zend_catch {
1012                         CG(interactive) = orig_interactive;
1013 
1014                         EG(no_extensions)=1;
1015                         EG(return_value_ptr_ptr) = orig_retval;
1016                         EG(active_op_array) = orig_ops;
1017                         EG(opline_ptr) = orig_opline;
1018                         PHPDBG_G(flags) &= ~PHPDBG_IN_COND_BP;
1019                 } zend_end_try();
1020 
1021                 CG(interactive) = orig_interactive;
1022 
1023                 EG(no_extensions)=1;
1024                 EG(return_value_ptr_ptr) = orig_retval;
1025                 EG(active_op_array) = orig_ops;
1026                 EG(opline_ptr) = orig_opline;
1027                 PHPDBG_G(flags) &= ~PHPDBG_IN_COND_BP;
1028 
1029                 if (breakpoint == SUCCESS) {
1030                         break;
1031                 }
1032         }
1033 
1034         return (breakpoint == SUCCESS) ? ((phpdbg_breakbase_t*)bp) : NULL;
1035 } /* }}} */
1036 
1037 PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakpoint(zend_execute_data* execute_data TSRMLS_DC) /* {{{ */
1038 {
1039         phpdbg_breakbase_t *base = NULL;
1040 
1041         if (!(PHPDBG_G(flags) & PHPDBG_IS_BP_ENABLED)) {
1042                 return NULL;
1043         }
1044 
1045         /* conditions cannot be executed by eval()'d code */
1046         if (!(PHPDBG_G(flags) & PHPDBG_IN_EVAL) &&
1047                 (PHPDBG_G(flags) & PHPDBG_HAS_COND_BP) &&
1048                 (base = phpdbg_find_conditional_breakpoint(execute_data TSRMLS_CC))) {
1049                 goto result;
1050         }
1051 
1052         if ((PHPDBG_G(flags) & PHPDBG_HAS_FILE_BP) &&
1053                 (base = phpdbg_find_breakpoint_file(execute_data->op_array TSRMLS_CC))) {
1054                 goto result;
1055         }
1056 
1057         if (PHPDBG_G(flags) & (PHPDBG_HAS_METHOD_BP|PHPDBG_HAS_SYM_BP)) {
1058                 /* check we are at the beginning of the stack */
1059                 if (execute_data->opline == EG(active_op_array)->opcodes) {
1060                         if ((base = phpdbg_find_breakpoint_symbol(
1061                                         execute_data->function_state.function TSRMLS_CC))) {
1062                                 goto result;
1063                         }
1064                 }
1065         }
1066 
1067         if ((PHPDBG_G(flags) & PHPDBG_HAS_OPLINE_BP) &&
1068                 (base = phpdbg_find_breakpoint_opline(execute_data->opline TSRMLS_CC))) {
1069                 goto result;
1070         }
1071 
1072         if ((PHPDBG_G(flags) & PHPDBG_HAS_OPCODE_BP) &&
1073                 (base = phpdbg_find_breakpoint_opcode(execute_data->opline->opcode TSRMLS_CC))) {
1074                 goto result;
1075         }
1076 
1077         return NULL;
1078 
1079 result:
1080         /* we return nothing for disable breakpoints */
1081         if (base->disabled) {
1082                 return NULL;
1083         }
1084 
1085         return base;
1086 } /* }}} */
1087 
1088 PHPDBG_API void phpdbg_delete_breakpoint(zend_ulong num TSRMLS_DC) /* {{{ */
1089 {
1090         HashTable **table;
1091         HashPosition position;
1092         phpdbg_breakbase_t *brake;
1093 
1094         if ((brake = phpdbg_find_breakbase_ex(num, &table, &position TSRMLS_CC))) {
1095                 char *key;
1096                 zend_uint klen;
1097                 zend_ulong idx;
1098                 int type = brake->type;
1099                 char *name = NULL;
1100                 size_t name_len = 0L;
1101 
1102                 switch (type) {
1103                         case PHPDBG_BREAK_FILE:
1104                         case PHPDBG_BREAK_METHOD:
1105                                 if (zend_hash_num_elements((*table)) == 1) {
1106                                         name = estrdup(brake->name);
1107                                         name_len = strlen(name);
1108                                         if (zend_hash_num_elements(&PHPDBG_G(bp)[type]) == 1) {
1109                                                 PHPDBG_G(flags) &= ~(1<<(brake->type+1));
1110                                         }
1111                                 }
1112                         break;
1113 
1114                         default: {
1115                                 if (zend_hash_num_elements((*table)) == 1) {
1116                                         PHPDBG_G(flags) &= ~(1<<(brake->type+1));
1117                                 }
1118                         }
1119                 }
1120 
1121                 switch (type) {
1122                         case PHPDBG_BREAK_FILE_OPLINE:
1123                         case PHPDBG_BREAK_FUNCTION_OPLINE:
1124                         case PHPDBG_BREAK_METHOD_OPLINE:
1125                                 if (zend_hash_num_elements(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]) == 1) {
1126                                         PHPDBG_G(flags) &= PHPDBG_HAS_OPLINE_BP;
1127                                 }
1128                                 zend_hash_index_del(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], ((phpdbg_breakopline_t*)brake)->opline);
1129                 }
1130 
1131                 switch (zend_hash_get_current_key_ex(
1132                         (*table), &key, &klen, &idx, 0, &position)) {
1133 
1134                         case HASH_KEY_IS_STRING:
1135                                 zend_hash_del((*table), key, klen);
1136                         break;
1137 
1138                         default:
1139                                 zend_hash_index_del((*table), idx);
1140                 }
1141 
1142                 switch (type) {
1143                         case PHPDBG_BREAK_FILE:
1144                         case PHPDBG_BREAK_METHOD:
1145                                 if (name) {
1146                                         zend_hash_del(&PHPDBG_G(bp)[type], name, name_len);
1147                                         efree(name);
1148                                 }
1149                         break;
1150                 }
1151 
1152                 phpdbg_notice("Deleted breakpoint #%ld", num);
1153                 PHPDBG_BREAK_UNMAPPING(num);
1154         } else {
1155                 phpdbg_error("Failed to find breakpoint #%ld", num);
1156         }
1157 } /* }}} */
1158 
1159 PHPDBG_API void phpdbg_clear_breakpoints(TSRMLS_D) /* {{{ */
1160 {
1161         zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE]);
1162         zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM]);
1163         zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE]);
1164         zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE]);
1165         zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE]);
1166         zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE]);
1167         zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE]);
1168         zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD]);
1169         zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_COND]);
1170         zend_hash_clean(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP]);
1171 
1172         PHPDBG_G(flags) &= ~PHPDBG_BP_MASK;
1173 
1174         PHPDBG_G(bp_count) = 0;
1175 } /* }}} */
1176 
1177 PHPDBG_API void phpdbg_hit_breakpoint(phpdbg_breakbase_t *brake, zend_bool output TSRMLS_DC) /* {{{ */
1178 {
1179         brake->hits++;
1180 
1181         if (output) {
1182                 phpdbg_print_breakpoint(brake TSRMLS_CC);
1183         }
1184 } /* }}} */
1185 
1186 PHPDBG_API void phpdbg_print_breakpoint(phpdbg_breakbase_t *brake TSRMLS_DC) /* {{{ */
1187 {
1188         if (!brake)
1189                 goto unknown;
1190 
1191         switch (brake->type) {
1192                 case PHPDBG_BREAK_FILE: {
1193                         phpdbg_notice("Breakpoint #%d at %s:%ld, hits: %lu",
1194                                 ((phpdbg_breakfile_t*)brake)->id,
1195                                 ((phpdbg_breakfile_t*)brake)->filename,
1196                                 ((phpdbg_breakfile_t*)brake)->line,
1197                                 ((phpdbg_breakfile_t*)brake)->hits);
1198                 } break;
1199 
1200                 case PHPDBG_BREAK_SYM: {
1201                         phpdbg_notice("Breakpoint #%d in %s() at %s:%u, hits: %lu",
1202                                 ((phpdbg_breaksymbol_t*)brake)->id,
1203                                 ((phpdbg_breaksymbol_t*)brake)->symbol,
1204                                 zend_get_executed_filename(TSRMLS_C),
1205                                 zend_get_executed_lineno(TSRMLS_C),
1206                                 ((phpdbg_breakfile_t*)brake)->hits);
1207                 } break;
1208 
1209                 case PHPDBG_BREAK_OPLINE: {
1210                         phpdbg_notice("Breakpoint #%d in %#lx at %s:%u, hits: %lu",
1211                                 ((phpdbg_breakline_t*)brake)->id,
1212                                 ((phpdbg_breakline_t*)brake)->opline,
1213                                 zend_get_executed_filename(TSRMLS_C),
1214                                 zend_get_executed_lineno(TSRMLS_C),
1215                                 ((phpdbg_breakline_t*)brake)->hits);
1216                 } break;
1217 
1218                 case PHPDBG_BREAK_METHOD_OPLINE: {
1219                          phpdbg_notice("Breakpoint #%d in %s::%s()#%lu at %s:%u, hits: %lu",
1220                                 ((phpdbg_breakopline_t*)brake)->id,
1221                                 ((phpdbg_breakopline_t*)brake)->class_name,
1222                                 ((phpdbg_breakopline_t*)brake)->func_name,
1223                                 ((phpdbg_breakopline_t*)brake)->opline_num,
1224                                 zend_get_executed_filename(TSRMLS_C),
1225                                 zend_get_executed_lineno(TSRMLS_C),
1226                                 ((phpdbg_breakopline_t*)brake)->hits);
1227                 } break;
1228 
1229                 case PHPDBG_BREAK_FUNCTION_OPLINE: {
1230                          phpdbg_notice("Breakpoint #%d in %s()#%lu at %s:%u, hits: %lu",
1231                                 ((phpdbg_breakopline_t*)brake)->id,
1232                                 ((phpdbg_breakopline_t*)brake)->func_name,
1233                                 ((phpdbg_breakopline_t*)brake)->opline_num,
1234                                 zend_get_executed_filename(TSRMLS_C),
1235                                 zend_get_executed_lineno(TSRMLS_C),
1236                                 ((phpdbg_breakopline_t*)brake)->hits);
1237                 } break;
1238 
1239                 case PHPDBG_BREAK_FILE_OPLINE: {
1240                          phpdbg_notice("Breakpoint #%d in %s:%lu at %s:%u, hits: %lu",
1241                                 ((phpdbg_breakopline_t*)brake)->id,
1242                                 ((phpdbg_breakopline_t*)brake)->class_name,
1243                                 ((phpdbg_breakopline_t*)brake)->opline_num,
1244                                 zend_get_executed_filename(TSRMLS_C),
1245                                 zend_get_executed_lineno(TSRMLS_C),
1246                                 ((phpdbg_breakopline_t*)brake)->hits);
1247                 } break;
1248 
1249                 case PHPDBG_BREAK_OPCODE: {
1250                          phpdbg_notice("Breakpoint #%d in %s at %s:%u, hits: %lu",
1251                                 ((phpdbg_breakop_t*)brake)->id,
1252                                 ((phpdbg_breakop_t*)brake)->name,
1253                                 zend_get_executed_filename(TSRMLS_C),
1254                                 zend_get_executed_lineno(TSRMLS_C),
1255                                 ((phpdbg_breakop_t*)brake)->hits);
1256                 } break;
1257 
1258                 case PHPDBG_BREAK_METHOD: {
1259                          phpdbg_notice("Breakpoint #%d in %s::%s() at %s:%u, hits: %lu",
1260                                 ((phpdbg_breakmethod_t*)brake)->id,
1261                                 ((phpdbg_breakmethod_t*)brake)->class_name,
1262                                 ((phpdbg_breakmethod_t*)brake)->func_name,
1263                                 zend_get_executed_filename(TSRMLS_C),
1264                                 zend_get_executed_lineno(TSRMLS_C),
1265                                 ((phpdbg_breakmethod_t*)brake)->hits);
1266                 } break;
1267 
1268                 case PHPDBG_BREAK_COND: {
1269                         if (((phpdbg_breakcond_t*)brake)->paramed) {
1270                                 char *param;
1271                                 phpdbg_notice("Conditional breakpoint #%d: at %s if %s %s:%u, hits: %lu",
1272                                         ((phpdbg_breakcond_t*)brake)->id,
1273                                         phpdbg_param_tostring(&((phpdbg_breakcond_t*)brake)->param, &param TSRMLS_CC),
1274                                         ((phpdbg_breakcond_t*)brake)->code,
1275                                         zend_get_executed_filename(TSRMLS_C),
1276                                         zend_get_executed_lineno(TSRMLS_C),
1277                                         ((phpdbg_breakcond_t*)brake)->hits);
1278                                 if (param)
1279                                         free(param);
1280                         } else {
1281                                 phpdbg_notice("Conditional breakpoint #%d: on %s == true %s:%u, hits: %lu",
1282                                         ((phpdbg_breakcond_t*)brake)->id,
1283                                         ((phpdbg_breakcond_t*)brake)->code,
1284                                         zend_get_executed_filename(TSRMLS_C),
1285                                         zend_get_executed_lineno(TSRMLS_C),
1286                                         ((phpdbg_breakcond_t*)brake)->hits);
1287                         }
1288 
1289                 } break;
1290 
1291                 default: {
1292 unknown:
1293                         phpdbg_notice("Unknown breakpoint at %s:%u",
1294                                 zend_get_executed_filename(TSRMLS_C),
1295                                 zend_get_executed_lineno(TSRMLS_C));
1296                 }
1297         }
1298 } /* }}} */
1299 
1300 PHPDBG_API void phpdbg_enable_breakpoint(zend_ulong id TSRMLS_DC) /* {{{ */
1301 {
1302         phpdbg_breakbase_t *brake = phpdbg_find_breakbase(id TSRMLS_CC);
1303 
1304         if (brake) {
1305                 brake->disabled = 0;
1306         }
1307 } /* }}} */
1308 
1309 PHPDBG_API void phpdbg_disable_breakpoint(zend_ulong id TSRMLS_DC) /* {{{ */
1310 {
1311         phpdbg_breakbase_t *brake = phpdbg_find_breakbase(id TSRMLS_CC);
1312 
1313         if (brake) {
1314                 brake->disabled = 1;
1315         }
1316 } /* }}} */
1317 
1318 PHPDBG_API void phpdbg_enable_breakpoints(TSRMLS_D) /* {{{ */
1319 {
1320         PHPDBG_G(flags) |= PHPDBG_IS_BP_ENABLED;
1321 } /* }}} */
1322 
1323 PHPDBG_API void phpdbg_disable_breakpoints(TSRMLS_D) { /* {{{ */
1324         PHPDBG_G(flags) &= ~PHPDBG_IS_BP_ENABLED;
1325 } /* }}} */
1326 
1327 PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakbase(zend_ulong id TSRMLS_DC) /* {{{ */
1328 {
1329         HashTable **table;
1330         HashPosition position;
1331 
1332         return phpdbg_find_breakbase_ex(id, &table, &position TSRMLS_CC);
1333 } /* }}} */
1334 
1335 PHPDBG_API phpdbg_breakbase_t *phpdbg_find_breakbase_ex(zend_ulong id, HashTable ***table, HashPosition *position TSRMLS_DC) /* {{{ */
1336 {
1337         if (zend_hash_index_find(&PHPDBG_G(bp)[PHPDBG_BREAK_MAP], id, (void**)table) == SUCCESS) {
1338                 phpdbg_breakbase_t *brake;
1339 
1340                 for (zend_hash_internal_pointer_reset_ex((**table), position);
1341                         zend_hash_get_current_data_ex((**table), (void**)&brake, position) == SUCCESS;
1342                         zend_hash_move_forward_ex((**table), position)) {
1343 
1344                         if (brake->id == id) {
1345                                 return brake;
1346                         }
1347                 }
1348         }
1349         return NULL;
1350 } /* }}} */
1351 
1352 PHPDBG_API void phpdbg_print_breakpoints(zend_ulong type TSRMLS_DC) /* {{{ */
1353 {
1354         switch (type) {
1355                 case PHPDBG_BREAK_SYM: if ((PHPDBG_G(flags) & PHPDBG_HAS_SYM_BP)) {
1356                         HashPosition position;
1357                         phpdbg_breaksymbol_t *brake;
1358 
1359                         phpdbg_writeln(SEPARATE);
1360                         phpdbg_writeln("Function Breakpoints:");
1361                         for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], &position);
1362                              zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], (void**) &brake, &position) == SUCCESS;
1363                              zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_SYM], &position)) {
1364                                 phpdbg_writeln("#%d\t\t%s%s",
1365                                         brake->id, brake->symbol,
1366                                         ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
1367                         }
1368                 } break;
1369 
1370                 case PHPDBG_BREAK_METHOD: if ((PHPDBG_G(flags) & PHPDBG_HAS_METHOD_BP)) {
1371                         HashPosition position[2];
1372                         HashTable *class_table;
1373                         char *class_name = NULL;
1374                         zend_uint class_len = 0;
1375                         zend_ulong class_idx = 0L;
1376 
1377                         phpdbg_writeln(SEPARATE);
1378                         phpdbg_writeln("Method Breakpoints:");
1379                         for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], &position[0]);
1380                              zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], (void**) &class_table, &position[0]) == SUCCESS;
1381                              zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD], &position[0])) {
1382 
1383                                 if (zend_hash_get_current_key_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD],
1384                                         &class_name, &class_len, &class_idx, 0, &position[0]) == HASH_KEY_IS_STRING) {
1385                                         phpdbg_breakmethod_t *brake;
1386 
1387                                         for (zend_hash_internal_pointer_reset_ex(class_table, &position[1]);
1388                                              zend_hash_get_current_data_ex(class_table, (void**)&brake, &position[1]) == SUCCESS;
1389                                              zend_hash_move_forward_ex(class_table, &position[1])) {
1390                                                 phpdbg_writeln("#%d\t\t%s::%s%s",
1391                                                         brake->id, brake->class_name, brake->func_name,
1392                                                         ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
1393                                         }
1394                                 }
1395 
1396                         }
1397                 } break;
1398 
1399                 case PHPDBG_BREAK_FILE: if ((PHPDBG_G(flags) & PHPDBG_HAS_FILE_BP)) {
1400                         HashPosition position[2];
1401                         HashTable *points;
1402 
1403                         phpdbg_writeln(SEPARATE);
1404                         phpdbg_writeln("File Breakpoints:");
1405                         for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], &position[0]);
1406                              zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], (void**) &points, &position[0]) == SUCCESS;
1407                              zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE], &position[0])) {
1408                                 phpdbg_breakfile_t *brake;
1409 
1410                                 for (zend_hash_internal_pointer_reset_ex(points, &position[1]);
1411                                      zend_hash_get_current_data_ex(points, (void**)&brake, &position[1]) == SUCCESS;
1412                                      zend_hash_move_forward_ex(points, &position[1])) {
1413                                         phpdbg_writeln("#%d\t\t%s:%lu%s",
1414                                                 brake->id, brake->filename, brake->line,
1415                                                 ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
1416                                 }
1417                         }
1418 
1419                 } break;
1420 
1421                 case PHPDBG_BREAK_OPLINE: if ((PHPDBG_G(flags) & PHPDBG_HAS_OPLINE_BP)) {
1422                         HashPosition position;
1423                         phpdbg_breakline_t *brake;
1424 
1425                         phpdbg_writeln(SEPARATE);
1426                         phpdbg_writeln("Opline Breakpoints:");
1427                         for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], &position);
1428                              zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], (void**) &brake, &position) == SUCCESS;
1429                              zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPLINE], &position)) {
1430                                 switch (brake->type) {
1431                                         case PHPDBG_BREAK_METHOD_OPLINE:
1432                                         case PHPDBG_BREAK_FUNCTION_OPLINE:
1433                                         case PHPDBG_BREAK_FILE_OPLINE:
1434                                                 phpdbg_writeln("#%d\t\t%#lx\t\t(%s breakpoint)%s", brake->id, brake->opline,
1435                                                         brake->type == PHPDBG_BREAK_METHOD_OPLINE?"method":
1436                                                                 brake->type == PHPDBG_BREAK_FUNCTION_OPLINE?"function":
1437                                                                         brake->type == PHPDBG_BREAK_FILE_OPLINE?"file":
1438                                                                                 "--- error ---",
1439                                                         ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
1440                                                 break;
1441 
1442                                         default:
1443                                                 phpdbg_writeln("#%d\t\t%#lx", brake->id, brake->opline);
1444                                                 break;
1445                                 }
1446                         }
1447                 } break;
1448 
1449                 case PHPDBG_BREAK_METHOD_OPLINE: if ((PHPDBG_G(flags) & PHPDBG_HAS_METHOD_OPLINE_BP)) {
1450                         HashPosition position[3];
1451                         HashTable *class_table, *method_table;
1452                         char *class_name = NULL, *method_name = NULL;
1453                         zend_uint class_len = 0, method_len = 0;
1454                         zend_ulong class_idx = 0L, method_idx = 0L;
1455 
1456                         phpdbg_writeln(SEPARATE);
1457                         phpdbg_writeln("Method opline Breakpoints:");
1458                         for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], &position[0]);
1459                              zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], (void**) &class_table, &position[0]) == SUCCESS;
1460                              zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE], &position[0])) {
1461 
1462                                 if (zend_hash_get_current_key_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_METHOD_OPLINE],
1463                                         &class_name, &class_len, &class_idx, 0, &position[0]) == HASH_KEY_IS_STRING) {
1464 
1465                                         for (zend_hash_internal_pointer_reset_ex(class_table, &position[1]);
1466                                              zend_hash_get_current_data_ex(class_table, (void**) &method_table, &position[1]) == SUCCESS;
1467                                              zend_hash_move_forward_ex(class_table, &position[1])) {
1468 
1469                                                 if (zend_hash_get_current_key_ex(class_table,
1470                                                         &method_name, &method_len, &method_idx, 0, &position[0]) == HASH_KEY_IS_STRING) {
1471 
1472                                                         phpdbg_breakopline_t *brake;
1473 
1474                                                         for (zend_hash_internal_pointer_reset_ex(method_table, &position[2]);
1475                                                              zend_hash_get_current_data_ex(method_table, (void**)&brake, &position[2]) == SUCCESS;
1476                                                              zend_hash_move_forward_ex(method_table, &position[2])) {
1477                                                                 phpdbg_writeln("#%d\t\t%s::%s opline %ld%s",
1478                                                                         brake->id, brake->class_name, brake->func_name, brake->opline_num,
1479                                                                         ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
1480                                                         }
1481                                                 }
1482                                         }
1483                                 }
1484 
1485                         }
1486                 } break;
1487 
1488                 case PHPDBG_BREAK_FUNCTION_OPLINE: if ((PHPDBG_G(flags) & PHPDBG_HAS_FUNCTION_OPLINE_BP)) {
1489                         HashPosition position[2];
1490                         HashTable *function_table;
1491                         char *function_name = NULL;
1492                         zend_uint function_len = 0;
1493                         zend_ulong function_idx = 0L;
1494 
1495                         phpdbg_writeln(SEPARATE);
1496                         phpdbg_writeln("Function opline Breakpoints:");
1497                         for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], &position[0]);
1498                              zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], (void**) &function_table, &position[0]) == SUCCESS;
1499                              zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE], &position[0])) {
1500 
1501                                 if (zend_hash_get_current_key_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FUNCTION_OPLINE],
1502                                         &function_name, &function_len, &function_idx, 0, &position[0]) == HASH_KEY_IS_STRING) {
1503 
1504                                         phpdbg_breakopline_t *brake;
1505 
1506                                         for (zend_hash_internal_pointer_reset_ex(function_table, &position[1]);
1507                                              zend_hash_get_current_data_ex(function_table, (void**)&brake, &position[1]) == SUCCESS;
1508                                              zend_hash_move_forward_ex(function_table, &position[1])) {
1509                                                 phpdbg_writeln("#%d\t\t%s opline %ld%s",
1510                                                         brake->id, brake->func_name, brake->opline_num,
1511                                                         ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
1512                                         }
1513                                 }
1514 
1515                         }
1516                 } break;
1517 
1518                 case PHPDBG_BREAK_FILE_OPLINE: if ((PHPDBG_G(flags) & PHPDBG_HAS_FILE_OPLINE_BP)) {
1519                         HashPosition position[2];
1520                         HashTable *file_table;
1521                         char *file_name = NULL;
1522                         zend_uint file_len = 0;
1523                         zend_ulong file_idx = 0L;
1524 
1525                         phpdbg_writeln(SEPARATE);
1526                         phpdbg_writeln("File opline Breakpoints:");
1527                         for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], &position[0]);
1528                              zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], (void**) &file_table, &position[0]) == SUCCESS;
1529                              zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE], &position[0])) {
1530 
1531                                 if (zend_hash_get_current_key_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_FILE_OPLINE],
1532                                         &file_name, &file_len, &file_idx, 0, &position[0]) == HASH_KEY_IS_STRING) {
1533 
1534                                         phpdbg_breakopline_t *brake;
1535 
1536                                         for (zend_hash_internal_pointer_reset_ex(file_table, &position[1]);
1537                                              zend_hash_get_current_data_ex(file_table, (void**)&brake, &position[1]) == SUCCESS;
1538                                              zend_hash_move_forward_ex(file_table, &position[1])) {
1539                                                 phpdbg_writeln("#%d\t\t%s opline %ld%s",
1540                                                         brake->id, brake->class_name, brake->opline_num,
1541                                                         ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
1542                                         }
1543                                 }
1544                         }
1545                 } break;
1546 
1547                 case PHPDBG_BREAK_COND: if ((PHPDBG_G(flags) & PHPDBG_HAS_COND_BP)) {
1548                         HashPosition position;
1549                         phpdbg_breakcond_t *brake;
1550 
1551                         phpdbg_writeln(SEPARATE);
1552                         phpdbg_writeln("Conditional Breakpoints:");
1553                         for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], &position);
1554                              zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], (void**) &brake, &position) == SUCCESS;
1555                              zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_COND], &position)) {
1556                                 if (brake->paramed) {
1557                                         switch (brake->param.type) {
1558                                                 case STR_PARAM:
1559                                                         phpdbg_writeln("#%d\t\tat %s if %s%s",
1560                                                                 brake->id,
1561                                                                 brake->param.str,
1562                                                                 brake->code,
1563                                                                 ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
1564                                                 break;
1565 
1566                                                 case NUMERIC_FUNCTION_PARAM:
1567                                                         phpdbg_writeln("#%d\t\tat %s#%ld if %s%s",
1568                                                                 brake->id,
1569                                                                 brake->param.str,
1570                                                                 brake->param.num,
1571                                                                 brake->code,
1572                                                                 ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
1573                                                 break;
1574 
1575                                                 case METHOD_PARAM:
1576                                                         phpdbg_writeln("#%d\t\tat %s::%s if %s%s",
1577                                                                 brake->id,
1578                                                                 brake->param.method.class,
1579                                                                 brake->param.method.name,
1580                                                                 brake->code,
1581                                                                 ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
1582                                                 break;
1583 
1584                                                 case NUMERIC_METHOD_PARAM:
1585                                                         phpdbg_writeln("#%d\t\tat %s::%s#%ld if %s%s",
1586                                                                 brake->id,
1587                                                                 brake->param.method.class,
1588                                                                 brake->param.method.name,
1589                                                                 brake->param.num,
1590                                                                 brake->code,
1591                                                                 ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
1592                                                 break;
1593 
1594                                                 case FILE_PARAM:
1595                                                         phpdbg_writeln("#%d\t\tat %s:%lu if %s%s",
1596                                                                 brake->id,
1597                                                                 brake->param.file.name,
1598                                                                 brake->param.file.line,
1599                                                                 brake->code,
1600                                                                 ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
1601                                                 break;
1602 
1603                                                 case ADDR_PARAM:
1604                                                         phpdbg_writeln("#%d\t\tat #%lx if %s%s",
1605                                                                 brake->id,
1606                                                                 brake->param.addr,
1607                                                                 brake->code,
1608                                                                 ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
1609                                                 break;
1610 
1611                                                 default:
1612                                                         phpdbg_error("Invalid parameter type for conditional breakpoint");
1613                                                 return;
1614                                         }
1615                                 } else {
1616                                         phpdbg_writeln("#%d\t\tif %s%s",
1617                                                 brake->id, brake->code,
1618                                                 ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
1619                                 }
1620                         }
1621                 } break;
1622 
1623                 case PHPDBG_BREAK_OPCODE: if (PHPDBG_G(flags) & PHPDBG_HAS_OPCODE_BP) {
1624                         HashPosition position;
1625                         phpdbg_breakop_t *brake;
1626 
1627                         phpdbg_writeln(SEPARATE);
1628                         phpdbg_writeln("Opcode Breakpoints:");
1629                         for (zend_hash_internal_pointer_reset_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], &position);
1630                              zend_hash_get_current_data_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], (void**) &brake, &position) == SUCCESS;
1631                              zend_hash_move_forward_ex(&PHPDBG_G(bp)[PHPDBG_BREAK_OPCODE], &position)) {
1632                                 phpdbg_writeln("#%d\t\t%s%s",
1633                                         brake->id, brake->name,
1634                                         ((phpdbg_breakbase_t*)brake)->disabled ? " [disabled]" : "");
1635                         }
1636                 } break;
1637         }
1638 } /* }}} */

/* [<][>][^][v][top][bottom][index][help] */