PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - sapi/phpdbg - phpdbg_bp.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 306 780 39.2 %
Date: 2018-09-10 Functions: 25 45 55.6 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Mon, 10 Sep 2018 14:11:53 +0000 (10 days ago)

Copyright © 2005-2018 The PHP Group
All rights reserved.