2013-11-10 18:06:41 +00:00
/*
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| PHP Version 5 |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Copyright ( c ) 1997 - 2013 The PHP Group |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| This source file is subject to version 3.01 of the PHP license , |
| that is bundled with this package in the file LICENSE , and is |
| available through the world - wide - web at the following url : |
| http : //www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world - wide - web , please send a note to |
| license @ php . net so we can mail you a copy immediately . |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Authors : Felipe Pena < felipe @ php . net > |
| Authors : Joe Watkins < joe . watkins @ live . co . uk > |
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*/
# include "zend.h"
# include "zend_hash.h"
2013-11-10 20:10:54 +00:00
# include "zend_llist.h"
2013-11-10 18:06:41 +00:00
# include "phpdbg.h"
# include "phpdbg_bp.h"
2013-11-12 22:39:39 +00:00
# include "phpdbg_utils.h"
2013-11-23 23:46:24 +00:00
# include "phpdbg_opcode.h"
2013-11-13 14:22:01 +00:00
# include "zend_globals.h"
2013-11-10 18:06:41 +00:00
ZEND_EXTERN_MODULE_GLOBALS ( phpdbg ) ;
static void phpdbg_llist_breakfile_dtor ( void * data ) /* { { { */
{
phpdbg_breakfile_t * bp = ( phpdbg_breakfile_t * ) data ;
efree ( ( char * ) bp - > filename ) ;
} /* }}} */
2013-11-12 00:27:48 +00:00
static void phpdbg_class_breaks_dtor ( void * data ) /* { { { */
{
2013-11-26 10:02:58 +00:00
phpdbg_breakmethod_t * bp = ( phpdbg_breakmethod_t * ) data ;
2013-11-12 01:41:14 +00:00
2013-11-26 10:02:58 +00:00
efree ( ( char * ) bp - > class_name ) ;
efree ( ( char * ) bp - > func_name ) ;
2013-11-12 00:27:48 +00:00
} /* }}} */
2013-11-28 20:36:45 +00:00
static void phpdbg_opline_class_breaks_dtor ( void * data ) /* { { { */
{
zend_hash_destroy ( ( HashTable * ) data ) ;
} /* }}} */
static void phpdbg_opline_breaks_dtor ( void * data ) /* { { { */
{
phpdbg_breakopline_t * bp = ( phpdbg_breakopline_t * ) data ;
efree ( ( char * ) bp - > class_name ) ;
efree ( ( char * ) bp - > func_name ) ;
} /* }}} */
2013-11-25 17:41:09 +00:00
PHPDBG_API void phpdbg_export_breakpoints ( FILE * handle TSRMLS_DC ) /* { { { */
{
HashPosition position ;
HashTable * table = NULL ;
2013-11-25 21:39:17 +00:00
2013-11-25 17:41:09 +00:00
if ( PHPDBG_G ( flags ) & PHPDBG_HAS_FILE_BP ) {
zend_llist * brakes ;
table = & PHPDBG_G ( bp ) [ PHPDBG_BREAK_FILE ] ;
2013-11-25 21:39:17 +00:00
2013-11-25 17:41:09 +00:00
for ( zend_hash_internal_pointer_reset_ex ( table , & position ) ;
zend_hash_get_current_data_ex ( table , ( void * ) & brakes , & position ) = = SUCCESS ;
zend_hash_move_forward_ex ( table , & position ) ) {
2013-11-25 21:39:17 +00:00
2013-11-25 17:41:09 +00:00
zend_llist_position lposition ;
2013-11-26 08:21:04 +00:00
phpdbg_breakfile_t * brake ;
int count = zend_llist_count ( brakes ) ;
2013-11-25 21:39:17 +00:00
2013-11-25 17:41:09 +00:00
if ( ( brake = zend_llist_get_first_ex ( brakes , & lposition ) ) ) {
phpdbg_notice (
" Exporting file breakpoints in %s (%d) " , brake - > filename , count ) ;
do {
fprintf ( handle , " break file %s:%lu \n " , brake - > filename , brake - > line ) ;
} while ( ( brake = zend_llist_get_next_ex ( brakes , & lposition ) ) ) ;
}
}
}
2013-11-25 21:39:17 +00:00
2013-11-25 18:03:38 +00:00
if ( PHPDBG_G ( flags ) & PHPDBG_HAS_SYM_BP ) {
phpdbg_breaksymbol_t * brake ;
2013-11-25 21:39:17 +00:00
2013-11-25 18:03:38 +00:00
table = & PHPDBG_G ( bp ) [ PHPDBG_BREAK_SYM ] ;
2013-11-25 21:39:17 +00:00
2013-11-25 18:03:38 +00:00
phpdbg_notice ( " Exporting symbol breakpoints (%d) " , zend_hash_num_elements ( table ) ) ;
2013-11-25 21:39:17 +00:00
2013-11-25 18:03:38 +00:00
for ( zend_hash_internal_pointer_reset_ex ( table , & position ) ;
zend_hash_get_current_data_ex ( table , ( void * ) & brake , & position ) = = SUCCESS ;
zend_hash_move_forward_ex ( table , & position ) ) {
fprintf (
handle , " break %s \n " , brake - > symbol ) ;
}
}
2013-11-25 18:27:58 +00:00
2013-11-25 18:16:31 +00:00
if ( PHPDBG_G ( flags ) & PHPDBG_HAS_METHOD_BP ) {
HashTable * class ;
phpdbg_breakmethod_t * brake ;
HashPosition mposition ;
zend_bool noted = 0 ;
2013-11-25 18:27:58 +00:00
2013-11-25 18:16:31 +00:00
table = & PHPDBG_G ( bp ) [ PHPDBG_BREAK_METHOD ] ;
2013-11-25 18:27:58 +00:00
2013-11-25 18:16:31 +00:00
for ( zend_hash_internal_pointer_reset_ex ( table , & position ) ;
zend_hash_get_current_data_ex ( table , ( void * * ) & class , & position ) = = SUCCESS ;
zend_hash_move_forward_ex ( table , & position ) ) {
noted = 0 ;
2013-11-25 18:27:58 +00:00
2013-11-25 18:16:31 +00:00
for ( zend_hash_internal_pointer_reset_ex ( class , & mposition ) ;
zend_hash_get_current_data_ex ( class , ( void * * ) & brake , & mposition ) = = SUCCESS ;
zend_hash_move_forward_ex ( class , & mposition ) ) {
if ( ! noted ) {
phpdbg_notice (
2013-11-25 21:39:17 +00:00
" Exporting method breakpoints in %s (%d) " ,
2013-11-25 18:16:31 +00:00
brake - > class_name , zend_hash_num_elements ( class ) ) ;
noted = 1 ;
}
2013-11-25 21:39:17 +00:00
2013-11-25 18:16:31 +00:00
fprintf (
handle , " break %s::%s \n " , brake - > class_name , brake - > func_name ) ;
}
}
}
2013-11-25 21:39:17 +00:00
2013-11-25 18:27:58 +00:00
if ( PHPDBG_G ( flags ) & PHPDBG_HAS_OPCODE_BP ) {
phpdbg_breakop_t * brake ;
2013-11-25 21:39:17 +00:00
2013-11-25 18:27:58 +00:00
table = & PHPDBG_G ( bp ) [ PHPDBG_BREAK_OPCODE ] ;
2013-11-25 21:39:17 +00:00
2013-11-25 18:27:58 +00:00
phpdbg_notice (
" Exporting opcode breakpoints (%d) " , zend_hash_num_elements ( table ) ) ;
2013-11-25 21:39:17 +00:00
2013-11-25 18:27:58 +00:00
for ( zend_hash_internal_pointer_reset_ex ( table , & position ) ;
zend_hash_get_current_data_ex ( table , ( void * * ) & brake , & position ) = = SUCCESS ;
zend_hash_move_forward_ex ( table , & position ) ) {
2013-11-25 21:39:17 +00:00
2013-11-25 18:27:58 +00:00
fprintf (
2013-11-25 21:39:17 +00:00
handle , " break op %s \n " , brake - > name ) ;
2013-11-25 18:27:58 +00:00
}
}
2013-11-25 21:39:17 +00:00
2013-11-26 08:21:04 +00:00
if ( PHPDBG_G ( flags ) & PHPDBG_HAS_COND_BP ) {
phpdbg_breakcond_t * brake ;
2013-11-25 21:39:17 +00:00
2013-11-26 08:21:04 +00:00
table = & PHPDBG_G ( bp ) [ PHPDBG_BREAK_COND ] ;
phpdbg_notice (
" Exporting conditional breakpoints (%d) " , zend_hash_num_elements ( table ) ) ;
for ( zend_hash_internal_pointer_reset_ex ( table , & position ) ;
zend_hash_get_current_data_ex ( table , ( void * * ) & brake , & position ) = = SUCCESS ;
zend_hash_move_forward_ex ( table , & position ) ) {
2013-11-25 21:39:17 +00:00
2013-11-26 08:21:04 +00:00
fprintf (
handle , " break on %s \n " , Z_STRVAL ( brake - > code ) ) ;
}
}
2013-11-25 17:41:09 +00:00
} /* }}} */
2013-11-23 18:12:51 +00:00
PHPDBG_API void phpdbg_set_breakpoint_file ( const char * path , long line_num TSRMLS_DC ) /* { { { */
2013-11-10 18:06:41 +00:00
{
2013-11-26 10:02:58 +00:00
struct stat sb ;
2013-11-10 18:06:41 +00:00
2013-11-26 10:02:58 +00:00
if ( VCWD_STAT ( path , & sb ) ! = FAILURE ) {
if ( sb . st_mode & ( S_IFREG | S_IFLNK ) ) {
phpdbg_breakfile_t new_break ;
zend_llist * break_files_ptr ;
size_t path_len = strlen ( path ) ;
2013-11-11 22:06:36 +00:00
2013-11-26 10:02:58 +00:00
new_break . filename = estrndup ( path , path_len ) ;
new_break . line = line_num ;
2013-11-10 18:06:41 +00:00
2013-11-26 10:02:58 +00:00
PHPDBG_G ( flags ) | = PHPDBG_HAS_FILE_BP ;
2013-11-10 18:06:41 +00:00
2013-11-26 10:02:58 +00:00
if ( zend_hash_find ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_FILE ] ,
new_break . filename , path_len , ( void * * ) & break_files_ptr ) = = FAILURE ) {
zend_llist break_files ;
2013-11-10 18:06:41 +00:00
2013-11-26 10:02:58 +00:00
zend_llist_init ( & break_files , sizeof ( phpdbg_breakfile_t ) ,
phpdbg_llist_breakfile_dtor , 0 ) ;
2013-11-10 19:15:32 +00:00
2013-11-26 10:02:58 +00:00
zend_hash_update ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_FILE ] ,
new_break . filename , path_len , & break_files , sizeof ( zend_llist ) ,
( void * * ) & break_files_ptr ) ;
}
2013-11-11 22:06:36 +00:00
2013-11-26 10:02:58 +00:00
new_break . id = PHPDBG_G ( bp_count ) + + ;
zend_llist_add_element ( break_files_ptr , & new_break ) ;
2013-11-16 22:40:01 +00:00
2013-11-26 10:02:58 +00:00
phpdbg_notice ( " Breakpoint #%d added at %s:%ld " ,
new_break . id , new_break . filename , new_break . line ) ;
} else {
phpdbg_error ( " Cannot set breakpoint in %s, it is not a regular file " , path ) ;
}
} else {
phpdbg_error ( " Cannot stat %s, it does not exist " , path ) ;
}
2013-11-10 18:06:41 +00:00
} /* }}} */
2013-11-24 12:00:12 +00:00
PHPDBG_API void phpdbg_set_breakpoint_symbol ( const char * name , size_t name_len TSRMLS_DC ) /* { { { */
2013-11-10 18:06:41 +00:00
{
2013-11-12 01:51:50 +00:00
if ( ! zend_hash_exists ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_SYM ] , name , name_len ) ) {
2013-11-10 21:38:58 +00:00
phpdbg_breaksymbol_t new_break ;
2013-11-10 18:06:41 +00:00
2013-11-12 01:24:53 +00:00
PHPDBG_G ( flags ) | = PHPDBG_HAS_SYM_BP ;
2013-11-10 18:06:41 +00:00
2013-11-20 14:55:07 +00:00
new_break . symbol = estrndup ( name , name_len ) ;
2013-11-10 21:38:58 +00:00
new_break . id = PHPDBG_G ( bp_count ) + + ;
2013-11-10 18:06:41 +00:00
2013-11-12 01:51:50 +00:00
zend_hash_update ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_SYM ] , new_break . symbol ,
2013-11-10 21:38:58 +00:00
name_len , & new_break , sizeof ( phpdbg_breaksymbol_t ) , NULL ) ;
2013-11-11 22:06:36 +00:00
2013-11-26 10:02:58 +00:00
phpdbg_notice ( " Breakpoint #%d added at %s " ,
2013-11-12 22:39:39 +00:00
new_break . id , new_break . symbol ) ;
2013-11-11 09:14:30 +00:00
} else {
2013-11-26 10:02:58 +00:00
phpdbg_notice ( " Breakpoint exists at %s " , name ) ;
2013-11-10 18:06:41 +00:00
}
} /* }}} */
2013-11-23 18:12:51 +00:00
PHPDBG_API void phpdbg_set_breakpoint_method ( const char * class_name , const char * func_name TSRMLS_DC ) /* { { { */
2013-11-12 00:27:48 +00:00
{
2013-11-26 10:02:58 +00:00
HashTable class_breaks , * class_table ;
2013-11-12 13:33:51 +00:00
size_t class_len = strlen ( class_name ) ;
size_t func_len = strlen ( func_name ) ;
2013-11-26 15:58:27 +00:00
char * lcname = zend_str_tolower_dup ( func_name , func_len ) ;
2013-11-20 14:55:07 +00:00
2013-11-26 10:02:58 +00:00
if ( zend_hash_find ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_METHOD ] , class_name ,
2013-11-12 13:33:51 +00:00
class_len , ( void * * ) & class_table ) ! = SUCCESS ) {
2013-11-26 10:02:58 +00:00
zend_hash_init ( & class_breaks , 8 , NULL , phpdbg_class_breaks_dtor , 0 ) ;
zend_hash_update (
& PHPDBG_G ( bp ) [ PHPDBG_BREAK_METHOD ] ,
class_name , class_len ,
( void * * ) & class_breaks , sizeof ( HashTable ) , ( void * * ) & class_table ) ;
}
2013-11-12 00:27:48 +00:00
2013-11-26 10:02:58 +00:00
if ( ! zend_hash_exists ( class_table , func_name , func_len ) ) {
phpdbg_breakmethod_t new_break ;
2013-11-12 01:41:14 +00:00
2013-11-26 10:02:58 +00:00
PHPDBG_G ( flags ) | = PHPDBG_HAS_METHOD_BP ;
2013-11-12 01:41:14 +00:00
2013-11-26 10:02:58 +00:00
new_break . class_name = estrndup ( class_name , class_len ) ;
new_break . class_len = class_len ;
new_break . func_name = estrndup ( func_name , func_len ) ;
new_break . func_len = func_len ;
new_break . id = PHPDBG_G ( bp_count ) + + ;
2013-11-12 01:41:14 +00:00
2013-11-26 16:00:28 +00:00
zend_hash_update ( class_table , lcname , func_len ,
2013-11-12 13:33:51 +00:00
& new_break , sizeof ( phpdbg_breakmethod_t ) , NULL ) ;
2013-11-26 10:02:58 +00:00
phpdbg_notice ( " Breakpoint #%d added at %s::%s " ,
new_break . id , class_name , func_name ) ;
} else {
2013-11-12 22:39:39 +00:00
phpdbg_notice ( " Breakpoint exists at %s::%s " , class_name , func_name ) ;
2013-11-12 00:27:48 +00:00
}
2013-11-26 15:58:27 +00:00
efree ( lcname ) ;
2013-11-12 00:27:48 +00:00
} /* }}} */
2013-11-28 20:36:45 +00:00
PHPDBG_API void phpdbg_save_oplines ( zend_op_array * op_array TSRMLS_DC ) {
phpdbg_btree * * branch = & PHPDBG_G ( opline_btree ) ;
int i = sizeof ( zend_ulong ) * 8 - 1 ;
do {
if ( * branch = = NULL ) {
break ;
}
branch = & ( * branch ) - > branches [ ( ( zend_ulong ) op_array - > opcodes > > i ) % 2 ] ;
} while ( i - - ) ;
if ( * branch = = NULL ) {
phpdbg_btree * memory = * branch = emalloc ( i * sizeof ( phpdbg_btree ) ) ;
while ( i - - ) {
branch = & ( * branch ) - > branches [ ( ( zend_ulong ) op_array - > opcodes > > i ) % 2 ] ;
* branch = + + memory ;
}
}
( * branch ) - > op_array = op_array ;
}
2013-11-23 18:12:51 +00:00
PHPDBG_API void phpdbg_set_breakpoint_opline ( zend_ulong opline TSRMLS_DC ) /* { { { */
2013-11-11 11:54:41 +00:00
{
2013-11-12 01:51:50 +00:00
if ( ! zend_hash_index_exists ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_OPLINE ] , opline ) ) {
2013-11-11 11:54:41 +00:00
phpdbg_breakline_t new_break ;
2013-11-28 20:36:45 +00:00
phpdbg_breakopline_t opline_break ;
int i = sizeof ( zend_ulong ) * 8 - 1 , last_superior_i = - 1 ;
phpdbg_btree * branch = PHPDBG_G ( opline_btree ) ;
HashTable * insert = & PHPDBG_G ( bp ) [ PHPDBG_BREAK_FUNCTION_OPLINE ] ;
HashTable func_breaks , * func_table ;
do {
if ( ( opline > > i ) % 2 = = 0 & & ! branch - > branches [ 0 ] ) {
if ( last_superior_i ! = - 1 ) {
i = sizeof ( zend_ulong ) * 8 - 1 ;
do {
branch = branch - > branches [ ( opline > > i ) % 2 = = 1 & & branch - > branches [ 1 ] ] ;
} while ( i - - > last_superior_i ) ;
do {
branch = branch - > branches [ ! ! branch - > branches [ 1 ] ] ;
} while ( i - - ) ;
}
break ;
}
if ( ( opline > > i ) % 2 = = 1 & & branch - > branches [ 1 ] ) {
if ( branch - > branches [ 0 ] ) {
last_superior_i = i ;
}
branch = branch - > branches [ 1 ] ;
} else {
branch = branch - > branches [ 0 ] ;
}
} while ( - - i ) ;
2013-11-28 21:03:59 +00:00
if ( i | |
2013-11-28 20:36:45 +00:00
( zend_ulong ) ( branch - > op_array + branch - > op_array - > last ) < = opline | |
( opline - ( zend_ulong ) branch - > op_array ) % sizeof ( zend_op ) > 0 ) {
phpdbg_error ( " No opline could be found at 0x%lx " , opline ) ;
2013-11-28 21:03:59 +00:00
return ;
2013-11-28 20:36:45 +00:00
}
opline_break . opline = ( opline - ( zend_ulong ) branch - > op_array ) / sizeof ( zend_op ) ;
2013-11-11 11:54:41 +00:00
2013-11-12 01:24:53 +00:00
PHPDBG_G ( flags ) | = PHPDBG_HAS_OPLINE_BP ;
2013-11-11 22:06:36 +00:00
2013-11-26 10:02:58 +00:00
new_break . name = NULL ;
2013-11-11 13:04:21 +00:00
new_break . opline = opline ;
2013-11-11 11:54:41 +00:00
new_break . id = PHPDBG_G ( bp_count ) + + ;
2013-11-11 22:06:36 +00:00
2013-11-14 00:29:44 +00:00
zend_hash_index_update ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_OPLINE ] , opline ,
& new_break , sizeof ( phpdbg_breakline_t ) , NULL ) ;
2013-11-11 22:06:36 +00:00
2013-11-28 20:36:45 +00:00
opline_break . func_len = branch - > op_array - > function_name ? strlen ( branch - > op_array - > function_name ) : 0 ;
opline_break . func_name = opline_break . func_len ? estrndup ( branch - > op_array - > function_name , opline_break . func_len ) : " " ;
opline_break . id = new_break . id ;
if ( branch - > op_array - > scope ) {
HashTable class_breaks , * class_table ;
if ( zend_hash_find ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_METHOD_OPLINE ] ,
branch - > op_array - > scope - > name ,
branch - > op_array - > scope - > name_length ,
( void * * ) & class_table
) = = FAILURE ) {
zend_hash_init ( & class_breaks , 8 , NULL , phpdbg_opline_class_breaks_dtor , 0 ) ;
zend_hash_update (
& PHPDBG_G ( bp ) [ PHPDBG_BREAK_METHOD_OPLINE ] ,
branch - > op_array - > scope - > name ,
branch - > op_array - > scope - > name_length ,
( void * * ) & class_breaks , sizeof ( HashTable ) , ( void * * ) & class_table ) ;
}
opline_break . class_len = branch - > op_array - > scope - > name_length ;
opline_break . class_name = estrndup ( branch - > op_array - > scope - > name , opline_break . class_len ) ;
insert = class_table ;
}
if ( zend_hash_find ( insert , opline_break . func_name , opline_break . func_len , ( void * * ) & func_table ) = = FAILURE ) {
zend_hash_init ( & func_breaks , 8 , NULL , phpdbg_opline_breaks_dtor , 0 ) ;
zend_hash_update (
insert ,
opline_break . func_name ,
opline_break . func_len ,
( void * * ) & func_breaks , sizeof ( HashTable ) , ( void * * ) & func_table ) ;
}
zend_hash_index_update ( func_table , opline_break . opline , & opline_break , sizeof ( phpdbg_breakopline_t ) , NULL ) ;
2013-11-26 10:02:58 +00:00
phpdbg_notice ( " Breakpoint #%d added at %#lx " ,
2013-11-12 22:39:39 +00:00
new_break . id , new_break . opline ) ;
2013-11-11 11:54:41 +00:00
} else {
2013-11-26 10:02:58 +00:00
phpdbg_notice ( " Breakpoint exists at %#lx " , opline ) ;
2013-11-11 11:54:41 +00:00
}
} /* }}} */
2013-11-28 21:03:59 +00:00
PHPDBG_API int phpdbg_resolve_op_array_break ( phpdbg_breakopline_t * brake , zend_op_array * op_array TSRMLS_DC ) {
2013-11-28 20:36:45 +00:00
phpdbg_breakline_t opline_break ;
if ( op_array - > last < brake - > opline ) {
if ( brake - > class_name = = NULL ) {
phpdbg_error ( " There are only %d oplines in function %s (breaking at opline %d impossible) " , op_array - > last , brake - > func_name , brake - > opline ) ;
} else {
phpdbg_error ( " There are only %d oplines in method %s::%s (breaking at opline %d impossible) " , op_array - > last , brake - > class_name , brake - > func_name , brake - > opline ) ;
}
2013-11-28 21:03:59 +00:00
return FAILURE ;
2013-11-28 20:36:45 +00:00
}
opline_break . id = brake - > id ;
opline_break . opline = ( zend_ulong ) ( op_array - > opcodes + brake - > opline ) ;
opline_break . name = NULL ;
PHPDBG_G ( flags ) | = PHPDBG_HAS_OPLINE_BP ;
zend_hash_index_update ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_OPLINE ] , opline_break . opline , & opline_break , sizeof ( phpdbg_breakline_t ) , NULL ) ;
2013-11-28 21:03:59 +00:00
return SUCCESS ;
2013-11-28 20:36:45 +00:00
}
PHPDBG_API void phpdbg_resolve_op_array_breaks ( zend_op_array * op_array TSRMLS_DC ) {
HashTable * func_table = & PHPDBG_G ( bp ) [ PHPDBG_BREAK_FUNCTION_OPLINE ] ;
HashTable * oplines_table ;
HashPosition position ;
phpdbg_breakopline_t * brake ;
if ( op_array - > scope ! = NULL & &
zend_hash_find ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_METHOD_OPLINE ] , op_array - > scope - > name , op_array - > scope - > name_length , ( void * * ) & func_table ) = = FAILURE ) {
return ;
}
if ( zend_hash_find ( func_table , op_array - > function_name ? op_array - > function_name : " " , op_array - > function_name ? strlen ( op_array - > function_name ) : 0 , ( void * * ) & oplines_table ) = = FAILURE ) {
return ;
}
for ( zend_hash_internal_pointer_reset_ex ( oplines_table , & position ) ;
zend_hash_get_current_data_ex ( oplines_table , ( void * * ) & brake , & position ) = = SUCCESS ;
zend_hash_move_forward_ex ( oplines_table , & position ) ) {
2013-11-28 21:03:59 +00:00
phpdbg_resolve_op_array_break ( brake , op_array TSRMLS_CC ) ;
2013-11-28 20:36:45 +00:00
}
}
PHPDBG_API int phpdbg_resolve_opline_break ( phpdbg_breakopline_t * new_break TSRMLS_DC ) {
HashTable * func_table = EG ( function_table ) ;
zend_function * func ;
if ( new_break - > class_name ! = NULL ) {
zend_class_entry * * ce ;
if ( zend_hash_find ( EG ( class_table ) , new_break - > class_name , new_break - > class_len + 1 , ( void * * ) & ce ) = = FAILURE ) {
return FAILURE ;
}
func_table = & ( * ce ) - > function_table ;
}
if ( zend_hash_find ( func_table , new_break - > func_name , new_break - > func_len + 1 , ( void * * ) & func ) = = FAILURE ) {
if ( new_break - > class_name ! = NULL ) {
phpdbg_error ( " Method %s doesn't exist in class %s " , new_break - > func_name , new_break - > class_name ) ;
}
return FAILURE ;
}
if ( func - > type ! = ZEND_USER_FUNCTION ) {
if ( new_break - > class_name = = NULL ) {
phpdbg_error ( " %s is not an user defined function, no oplines exist " , new_break - > func_name ) ;
} else {
phpdbg_error ( " %s::%s is not an user defined method, no oplines exist " , new_break - > class_name , new_break - > func_name ) ;
}
2013-11-28 21:03:59 +00:00
return 2 ;
2013-11-28 20:36:45 +00:00
}
2013-11-28 21:03:59 +00:00
if ( phpdbg_resolve_op_array_break ( new_break , & func - > op_array TSRMLS_CC ) = = FAILURE ) {
return 2 ;
}
2013-11-28 20:36:45 +00:00
return SUCCESS ;
}
PHPDBG_API void phpdbg_set_breakpoint_method_opline ( const char * class , const char * method , int opline TSRMLS_DC ) /* { { { */
{
phpdbg_breakopline_t new_break ;
HashTable class_breaks , * class_table ;
HashTable method_breaks , * method_table ;
new_break . func_len = strlen ( method ) ;
new_break . func_name = estrndup ( method , new_break . func_len ) ;
new_break . class_len = strlen ( class ) ;
new_break . class_name = estrndup ( class , new_break . class_len ) ;
new_break . opline = opline ;
new_break . id = PHPDBG_G ( bp_count ) + + ;
2013-11-28 21:03:59 +00:00
switch ( phpdbg_resolve_opline_break ( & new_break TSRMLS_CC ) ) {
case FAILURE :
phpdbg_notice ( " Pending breakpoint #%d at %s::%s:%d " , new_break . id , new_break . class_name , new_break . func_name , opline ) ;
break ;
case SUCCESS :
phpdbg_notice ( " Breakpoint #%d added at %s::%s:%d " , new_break . id , new_break . class_name , new_break . func_name , opline ) ;
break ;
case 2 :
return ;
2013-11-28 20:36:45 +00:00
}
if ( zend_hash_find ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_METHOD_OPLINE ] , new_break . class_name , new_break . class_len , ( void * * ) & class_table ) = = FAILURE ) {
zend_hash_init ( & class_breaks , 8 , NULL , phpdbg_opline_class_breaks_dtor , 0 ) ;
zend_hash_update (
& PHPDBG_G ( bp ) [ PHPDBG_BREAK_METHOD_OPLINE ] ,
new_break . class_name ,
new_break . class_len ,
( void * * ) & class_breaks , sizeof ( HashTable ) , ( void * * ) & class_table ) ;
}
if ( zend_hash_find ( class_table , new_break . func_name , new_break . func_len , ( void * * ) & method_table ) = = FAILURE ) {
zend_hash_init ( & method_breaks , 8 , NULL , phpdbg_opline_breaks_dtor , 0 ) ;
zend_hash_update (
class_table ,
new_break . func_name ,
new_break . func_len ,
( void * * ) & method_breaks , sizeof ( HashTable ) , ( void * * ) & method_table ) ;
}
if ( zend_hash_index_exists ( method_table , opline ) ) {
phpdbg_notice ( " Breakpoint already exists for %s::%s:%d " , new_break . class_name , new_break . func_name , opline ) ;
efree ( new_break . func_name ) ;
efree ( new_break . class_name ) ;
PHPDBG_G ( bp_count ) - - ;
return ;
}
zend_hash_index_update ( method_table , new_break . opline , & new_break , sizeof ( phpdbg_breakopline_t ) , NULL ) ;
}
PHPDBG_API void phpdbg_set_breakpoint_function_opline ( const char * function , int opline TSRMLS_DC ) /* { { { */
{
phpdbg_breakopline_t new_break ;
HashTable func_breaks , * func_table ;
new_break . func_len = strlen ( function ) ;
new_break . func_name = estrndup ( function , new_break . func_len ) ;
new_break . opline = opline ;
new_break . id = PHPDBG_G ( bp_count ) + + ;
2013-11-28 21:03:59 +00:00
switch ( phpdbg_resolve_opline_break ( & new_break TSRMLS_CC ) ) {
case FAILURE :
phpdbg_notice ( " Pending breakpoint #%d at %s:%d " , new_break . id , new_break . func_name , new_break . opline ) ;
break ;
case SUCCESS :
phpdbg_notice ( " Breakpoint #%d added at %s:%d " , new_break . id , new_break . func_name , new_break . opline ) ;
break ;
case 2 :
return ;
2013-11-28 20:36:45 +00:00
}
if ( zend_hash_find ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_FUNCTION_OPLINE ] , new_break . func_name , new_break . func_len , ( void * * ) & func_table ) = = FAILURE ) {
zend_hash_init ( & func_breaks , 8 , NULL , phpdbg_opline_breaks_dtor , 0 ) ;
zend_hash_update (
& PHPDBG_G ( bp ) [ PHPDBG_BREAK_FUNCTION_OPLINE ] ,
new_break . func_name ,
new_break . func_len ,
( void * * ) & func_breaks , sizeof ( HashTable ) , ( void * * ) & func_table ) ;
}
if ( zend_hash_index_exists ( func_table , opline ) ) {
phpdbg_notice ( " Breakpoint already exists for %s:%d " , new_break . func_len , opline ) ;
efree ( new_break . func_name ) ;
PHPDBG_G ( bp_count ) - - ;
return ;
}
zend_hash_index_update ( func_table , new_break . opline , & new_break , sizeof ( phpdbg_breakopline_t ) , NULL ) ;
}
2013-11-24 11:43:05 +00:00
PHPDBG_API void phpdbg_set_breakpoint_opcode ( const char * name , size_t name_len TSRMLS_DC ) /* { { { */
2013-11-23 23:14:16 +00:00
{
phpdbg_breakop_t new_break ;
2013-11-24 11:43:05 +00:00
zend_ulong hash = zend_hash_func ( name , name_len ) ;
2013-11-23 23:14:16 +00:00
if ( zend_hash_index_exists ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_OPCODE ] , hash ) ) {
2013-11-25 18:27:58 +00:00
phpdbg_notice (
" Breakpoint exists for %s " , name ) ;
2013-11-23 23:14:16 +00:00
return ;
}
2013-11-24 12:14:53 +00:00
new_break . hash = hash ;
2013-11-24 11:43:05 +00:00
new_break . name = estrndup ( name , name_len ) ;
2013-11-23 23:14:16 +00:00
new_break . id = PHPDBG_G ( bp_count ) + + ;
zend_hash_index_update ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_OPCODE ] , hash ,
& new_break , sizeof ( phpdbg_breakop_t ) , NULL ) ;
PHPDBG_G ( flags ) | = PHPDBG_HAS_OPCODE_BP ;
2013-11-24 11:43:05 +00:00
phpdbg_notice ( " Breakpoint #%d added at %s " , new_break . id , name ) ;
2013-11-23 23:14:16 +00:00
} /* }}} */
2013-11-23 18:12:51 +00:00
PHPDBG_API void phpdbg_set_breakpoint_opline_ex ( phpdbg_opline_ptr_t opline TSRMLS_DC ) /* { { { */
2013-11-11 14:33:53 +00:00
{
2013-11-12 01:51:50 +00:00
if ( ! zend_hash_index_exists ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_OPLINE ] , ( zend_ulong ) opline ) ) {
2013-11-11 14:33:53 +00:00
phpdbg_breakline_t new_break ;
2013-11-12 01:24:53 +00:00
PHPDBG_G ( flags ) | = PHPDBG_HAS_OPLINE_BP ;
2013-11-11 22:06:36 +00:00
2013-11-11 14:59:51 +00:00
new_break . opline = ( zend_ulong ) opline ;
2013-11-11 14:33:53 +00:00
new_break . id = PHPDBG_G ( bp_count ) + + ;
2013-11-11 22:06:36 +00:00
2013-11-14 00:29:44 +00:00
zend_hash_index_update ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_OPLINE ] ,
( zend_ulong ) opline , & new_break , sizeof ( phpdbg_breakline_t ) , NULL ) ;
2013-11-11 22:06:36 +00:00
2013-11-26 10:02:58 +00:00
phpdbg_notice ( " Breakpoint #%d added at %#lx " ,
2013-11-12 22:39:39 +00:00
new_break . id , new_break . opline ) ;
2013-11-11 14:33:53 +00:00
}
} /* }}} */
2013-11-23 18:12:51 +00:00
PHPDBG_API void phpdbg_set_breakpoint_expression ( const char * expr , size_t expr_len TSRMLS_DC ) /* { { { */
2013-11-13 14:22:01 +00:00
{
2013-11-26 10:02:58 +00:00
zend_ulong hash = zend_inline_hash_func ( expr , expr_len ) ;
2013-11-13 23:36:02 +00:00
2013-11-26 10:02:58 +00:00
if ( ! zend_hash_index_exists ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_COND ] , hash ) ) {
phpdbg_breakcond_t new_break ;
zend_uint cops = CG ( compiler_options ) ;
zval pv ;
2013-11-13 14:22:01 +00:00
2013-11-26 10:02:58 +00:00
ZVAL_STRINGL ( & new_break . code , expr , expr_len , 1 ) ;
2013-11-13 23:36:02 +00:00
2013-11-24 11:58:08 +00:00
new_break . hash = hash ;
2013-11-26 10:02:58 +00:00
new_break . id = PHPDBG_G ( bp_count ) + + ;
2013-11-13 23:36:02 +00:00
2013-11-26 10:02:58 +00:00
cops = CG ( compiler_options ) ;
2013-11-13 23:36:02 +00:00
2013-11-26 10:02:58 +00:00
CG ( compiler_options ) = ZEND_COMPILE_DEFAULT_FOR_EVAL ;
2013-11-15 11:27:05 +00:00
Z_STRLEN ( pv ) = expr_len + sizeof ( " return ; " ) - 1 ;
Z_STRVAL ( pv ) = emalloc ( Z_STRLEN ( pv ) + 1 ) ;
memcpy ( Z_STRVAL ( pv ) , " return " , sizeof ( " return " ) - 1 ) ;
memcpy ( Z_STRVAL ( pv ) + sizeof ( " return " ) - 1 , expr , expr_len ) ;
Z_STRVAL ( pv ) [ Z_STRLEN ( pv ) - 1 ] = ' ; ' ;
Z_STRVAL ( pv ) [ Z_STRLEN ( pv ) ] = ' \0 ' ;
Z_TYPE ( pv ) = IS_STRING ;
new_break . ops = zend_compile_string (
& pv , " Conditional Breakpoint Code " TSRMLS_CC ) ;
if ( new_break . ops ) {
2013-11-26 10:02:58 +00:00
phpdbg_breakcond_t * brake ;
2013-11-15 11:27:05 +00:00
zend_hash_index_update (
& PHPDBG_G ( bp ) [ PHPDBG_BREAK_COND ] , hash , & new_break ,
2013-11-26 10:02:58 +00:00
sizeof ( phpdbg_breakcond_t ) , ( void * * ) & brake ) ;
2013-11-15 11:27:05 +00:00
phpdbg_notice ( " Conditional breakpoint #%d added %s/%p " ,
2013-11-26 10:02:58 +00:00
brake - > id , Z_STRVAL ( brake - > code ) , brake - > ops ) ;
2013-11-15 11:27:05 +00:00
PHPDBG_G ( flags ) | = PHPDBG_HAS_COND_BP ;
} else {
phpdbg_error (
" Failed to compile code for expression %s " , expr ) ;
zval_dtor ( & new_break . code ) ;
PHPDBG_G ( bp_count ) - - ;
}
2013-11-13 14:22:01 +00:00
CG ( compiler_options ) = cops ;
2013-11-26 10:02:58 +00:00
} else {
phpdbg_notice ( " Conditional break %s exists " , expr ) ;
}
2013-11-13 14:22:01 +00:00
} /* }}} */
2013-11-10 20:06:19 +00:00
int phpdbg_find_breakpoint_file ( zend_op_array * op_array TSRMLS_DC ) /* { { { */
2013-11-10 18:06:41 +00:00
{
size_t name_len = strlen ( op_array - > filename ) ;
zend_llist * break_list ;
2013-11-10 19:15:32 +00:00
zend_llist_element * le ;
2013-11-10 18:06:41 +00:00
2013-11-14 00:29:44 +00:00
if ( zend_hash_find ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_FILE ] , op_array - > filename ,
name_len , ( void * * ) & break_list ) = = FAILURE ) {
2013-11-10 19:15:32 +00:00
return FAILURE ;
}
2013-11-10 18:06:41 +00:00
2013-11-10 19:15:32 +00:00
for ( le = break_list - > head ; le ; le = le - > next ) {
const phpdbg_breakfile_t * bp = ( phpdbg_breakfile_t * ) le - > data ;
2013-11-10 18:06:41 +00:00
2013-11-10 19:15:32 +00:00
if ( bp - > line = = ( * EG ( opline_ptr ) ) - > lineno ) {
2013-11-12 22:39:39 +00:00
phpdbg_notice ( " Breakpoint #%d at %s:%ld " ,
bp - > id , bp - > filename , bp - > line ) ;
2013-11-10 19:15:32 +00:00
return SUCCESS ;
2013-11-10 18:06:41 +00:00
}
}
return FAILURE ;
} /* }}} */
2013-11-10 20:06:19 +00:00
int phpdbg_find_breakpoint_symbol ( zend_function * fbc TSRMLS_DC ) /* { { { */
2013-11-10 18:06:41 +00:00
{
const char * fname ;
2013-11-12 00:40:40 +00:00
zend_op_array * ops ;
2013-11-10 21:38:58 +00:00
phpdbg_breaksymbol_t * bp ;
2013-11-10 18:06:41 +00:00
if ( fbc - > type ! = ZEND_USER_FUNCTION ) {
return FAILURE ;
}
2013-11-12 01:41:14 +00:00
2013-11-12 00:40:40 +00:00
ops = ( zend_op_array * ) fbc ;
2013-11-12 01:41:14 +00:00
2013-11-12 00:40:40 +00:00
if ( ops - > scope ) {
2013-11-26 10:02:58 +00:00
/* find method breaks here */
return phpdbg_find_breakpoint_method ( ops TSRMLS_CC ) ;
2013-11-12 00:40:40 +00:00
}
2013-11-10 18:06:41 +00:00
2013-11-12 00:47:27 +00:00
fname = ops - > function_name ;
2013-11-10 18:06:41 +00:00
if ( ! fname ) {
fname = " main " ;
}
2013-11-10 21:38:58 +00:00
2013-11-26 10:02:58 +00:00
if ( zend_hash_find ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_SYM ] , fname , strlen ( fname ) , ( void * * ) & bp ) = = SUCCESS ) {
2013-11-12 22:39:39 +00:00
phpdbg_notice ( " Breakpoint #%d in %s() at %s:%u " ,
2013-11-26 10:02:58 +00:00
bp - > id , bp - > symbol ,
2013-11-11 22:06:36 +00:00
zend_get_executed_filename ( TSRMLS_C ) ,
2013-11-12 22:39:39 +00:00
zend_get_executed_lineno ( TSRMLS_C ) ) ;
2013-11-10 18:06:41 +00:00
return SUCCESS ;
}
return FAILURE ;
2013-11-10 21:57:43 +00:00
} /* }}} */
2013-11-11 11:54:41 +00:00
2013-11-12 00:47:27 +00:00
int phpdbg_find_breakpoint_method ( zend_op_array * ops TSRMLS_DC ) /* { { { */
2013-11-12 00:27:48 +00:00
{
HashTable * class_table ;
phpdbg_breakmethod_t * bp ;
2013-11-14 00:29:44 +00:00
if ( zend_hash_find ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_METHOD ] , ops - > scope - > name ,
ops - > scope - > name_length , ( void * * ) & class_table ) = = SUCCESS ) {
2013-11-26 15:58:27 +00:00
char * lcname = zend_str_tolower_dup ( ops - > function_name , strlen ( ops - > function_name ) ) ;
size_t lcname_len = strlen ( lcname ) ;
2013-11-12 00:27:48 +00:00
if ( zend_hash_find (
class_table ,
2013-11-26 15:58:27 +00:00
lcname ,
lcname_len , ( void * * ) & bp ) = = SUCCESS ) {
efree ( lcname ) ;
2013-11-12 22:39:39 +00:00
phpdbg_notice ( " Breakpoint #%d in %s::%s() at %s:%u " ,
2013-11-12 06:03:37 +00:00
bp - > id , bp - > class_name , bp - > func_name ,
2013-11-12 00:27:48 +00:00
zend_get_executed_filename ( TSRMLS_C ) ,
2013-11-12 22:39:39 +00:00
zend_get_executed_lineno ( TSRMLS_C ) ) ;
2013-11-12 00:27:48 +00:00
return SUCCESS ;
}
2013-11-26 15:58:27 +00:00
efree ( lcname ) ;
2013-11-12 00:27:48 +00:00
}
return FAILURE ;
} /* }}} */
2013-11-11 13:07:02 +00:00
int phpdbg_find_breakpoint_opline ( phpdbg_opline_ptr_t opline TSRMLS_DC ) /* { { { */
2013-11-11 11:54:41 +00:00
{
phpdbg_breakline_t * bp ;
2013-11-14 00:29:44 +00:00
if ( zend_hash_index_find ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_OPLINE ] ,
( zend_ulong ) opline , ( void * * ) & bp ) = = SUCCESS ) {
2013-11-12 22:39:39 +00:00
phpdbg_notice ( " Breakpoint #%d in %#lx at %s:%u " ,
2013-11-26 10:02:58 +00:00
bp - > id , bp - > opline ,
2013-11-11 22:06:36 +00:00
zend_get_executed_filename ( TSRMLS_C ) ,
2013-11-12 22:39:39 +00:00
zend_get_executed_lineno ( TSRMLS_C ) ) ;
2013-11-11 22:06:36 +00:00
2013-11-11 11:54:41 +00:00
return SUCCESS ;
}
2013-11-11 22:06:36 +00:00
2013-11-11 11:54:41 +00:00
return FAILURE ;
} /* }}} */
2013-11-11 14:33:53 +00:00
2013-11-23 23:14:16 +00:00
int phpdbg_find_breakpoint_opcode ( zend_uchar opcode TSRMLS_DC ) /* { { { */
{
phpdbg_breakop_t * bp ;
const char * opname = phpdbg_decode_opcode ( opcode ) ;
if ( memcmp ( opname , PHPDBG_STRL ( " UNKNOWN " ) ) = = 0 ) {
return FAILURE ;
}
if ( zend_hash_index_find ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_OPCODE ] ,
zend_hash_func ( opname , strlen ( opname ) ) , ( void * * ) & bp ) = = SUCCESS ) {
phpdbg_notice ( " Breakpoint #%d in %s at %s:%u " ,
bp - > id ,
opname ,
zend_get_executed_filename ( TSRMLS_C ) ,
zend_get_executed_lineno ( TSRMLS_C ) ) ;
return SUCCESS ;
}
return FAILURE ;
} /* }}} */
2013-11-13 14:22:01 +00:00
int phpdbg_find_conditional_breakpoint ( TSRMLS_D ) /* { { { */
{
phpdbg_breakcond_t * bp ;
2013-11-26 10:02:58 +00:00
HashPosition position ;
int breakpoint = FAILURE ;
for ( zend_hash_internal_pointer_reset_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_COND ] , & position ) ;
zend_hash_get_current_data_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_COND ] , ( void * ) & bp , & position ) = = SUCCESS ;
zend_hash_move_forward_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_COND ] , & position ) ) {
zval * retval = NULL ;
int orig_interactive = CG ( interactive ) ;
zval * * orig_retval = EG ( return_value_ptr_ptr ) ;
zend_op_array * orig_ops = EG ( active_op_array ) ;
zend_op * * orig_opline = EG ( opline_ptr ) ;
ALLOC_INIT_ZVAL ( retval ) ;
EG ( return_value_ptr_ptr ) = & retval ;
EG ( active_op_array ) = bp - > ops ;
EG ( no_extensions ) = 1 ;
if ( ! EG ( active_symbol_table ) ) {
zend_rebuild_symbol_table ( TSRMLS_C ) ;
}
CG ( interactive ) = 0 ;
zend_try {
PHPDBG_G ( flags ) | = PHPDBG_IN_COND_BP ;
zend_execute ( EG ( active_op_array ) TSRMLS_CC ) ;
if ( i_zend_is_true ( retval ) ) {
breakpoint = SUCCESS ;
}
} zend_catch {
phpdbg_error ( " Error detected while evaluating expression %s " , Z_STRVAL ( bp - > code ) ) ;
CG ( interactive ) = orig_interactive ;
EG ( no_extensions ) = 1 ;
EG ( return_value_ptr_ptr ) = orig_retval ;
EG ( active_op_array ) = orig_ops ;
EG ( opline_ptr ) = orig_opline ;
PHPDBG_G ( flags ) & = ~ PHPDBG_IN_COND_BP ;
} zend_end_try ( ) ;
CG ( interactive ) = orig_interactive ;
EG ( no_extensions ) = 1 ;
EG ( return_value_ptr_ptr ) = orig_retval ;
EG ( active_op_array ) = orig_ops ;
EG ( opline_ptr ) = orig_opline ;
PHPDBG_G ( flags ) & = ~ PHPDBG_IN_COND_BP ;
if ( breakpoint = = SUCCESS ) {
break ;
}
}
2013-11-13 23:36:02 +00:00
2013-11-26 10:02:58 +00:00
if ( breakpoint = = SUCCESS ) {
phpdbg_notice ( " Conditional breakpoint #%d: (%s) %s:%u " ,
bp - > id , Z_STRVAL ( bp - > code ) ,
2013-11-13 14:22:01 +00:00
zend_get_executed_filename ( TSRMLS_C ) ,
zend_get_executed_lineno ( TSRMLS_C ) ) ;
2013-11-26 10:02:58 +00:00
}
2013-11-13 23:36:02 +00:00
2013-11-13 14:22:01 +00:00
return breakpoint ;
} /* }}} */
2013-11-23 23:46:24 +00:00
int phpdbg_find_breakpoint ( zend_execute_data * execute_data TSRMLS_DC ) /* { { { */
{
2013-11-25 21:39:17 +00:00
if ( ! ( PHPDBG_G ( flags ) & PHPDBG_IS_BP_ENABLED ) ) {
return FAILURE ;
}
2013-11-24 11:45:05 +00:00
/* conditions cannot be executed by eval()'d code */
if ( ! ( PHPDBG_G ( flags ) & PHPDBG_IN_EVAL )
& & ( PHPDBG_G ( flags ) & PHPDBG_HAS_COND_BP )
& & phpdbg_find_conditional_breakpoint ( TSRMLS_C ) = = SUCCESS ) {
return SUCCESS ;
}
2013-11-23 23:46:24 +00:00
if ( PHPDBG_G ( flags ) & PHPDBG_HAS_FILE_BP
& & phpdbg_find_breakpoint_file ( execute_data - > op_array TSRMLS_CC ) = = SUCCESS ) {
return SUCCESS ;
}
if ( PHPDBG_G ( flags ) & ( PHPDBG_HAS_METHOD_BP | PHPDBG_HAS_SYM_BP ) ) {
/* check we are at the beginning of the stack */
if ( execute_data - > opline = = EG ( active_op_array ) - > opcodes ) {
if ( phpdbg_find_breakpoint_symbol (
execute_data - > function_state . function TSRMLS_CC ) = = SUCCESS ) {
return SUCCESS ;
}
}
}
if ( PHPDBG_G ( flags ) & PHPDBG_HAS_OPLINE_BP
& & phpdbg_find_breakpoint_opline ( execute_data - > opline TSRMLS_CC ) = = SUCCESS ) {
return SUCCESS ;
}
if ( PHPDBG_G ( flags ) & PHPDBG_HAS_OPCODE_BP
& & phpdbg_find_breakpoint_opcode ( execute_data - > opline - > opcode TSRMLS_CC ) = = SUCCESS ) {
return SUCCESS ;
}
return FAILURE ;
} /* }}} */
2013-11-24 12:06:45 +00:00
int phpdbg_delete_breakpoint_from_file_llist ( void * brake ) { /* {{{ */
2013-11-24 11:58:08 +00:00
TSRMLS_FETCH ( ) ;
return ( ( phpdbg_breakfile_t * ) brake ) - > id = = PHPDBG_G ( del_bp_num ) ;
2013-11-24 12:06:45 +00:00
} /* }}} */
2013-11-24 11:58:08 +00:00
PHPDBG_API void phpdbg_delete_breakpoint ( zend_ulong num TSRMLS_DC ) /* { { { */
{
if ( PHPDBG_G ( flags ) & PHPDBG_HAS_SYM_BP ) {
HashPosition position ;
phpdbg_breaksymbol_t * brake ;
for ( zend_hash_internal_pointer_reset_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_SYM ] , & position ) ;
zend_hash_get_current_data_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_SYM ] , ( void * * ) & brake , & position ) = = SUCCESS ;
zend_hash_move_forward_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_SYM ] , & position ) ) {
if ( brake - > id = = num ) {
zend_hash_del ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_SYM ] , brake - > symbol , strlen ( brake - > symbol ) ) ;
return ;
}
}
}
if ( PHPDBG_G ( flags ) & PHPDBG_HAS_METHOD_BP ) {
HashPosition position [ 2 ] ;
phpdbg_breakmethod_t * brake ;
HashTable * class_table ;
for ( zend_hash_internal_pointer_reset_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_METHOD ] , & position [ 0 ] ) ;
zend_hash_get_current_data_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_METHOD ] , ( void * * ) & class_table , & position [ 0 ] ) = = SUCCESS ;
zend_hash_move_forward_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_METHOD ] , & position [ 0 ] ) ) {
for ( zend_hash_internal_pointer_reset_ex ( class_table , & position [ 1 ] ) ;
zend_hash_get_current_data_ex ( class_table , ( void * * ) & brake , & position [ 1 ] ) = = SUCCESS ;
zend_hash_move_forward_ex ( class_table , & position [ 1 ] ) ) {
if ( brake - > id = = num ) {
zend_hash_del ( class_table , brake - > func_name , brake - > func_len ) ;
return ;
}
}
}
}
if ( PHPDBG_G ( flags ) & PHPDBG_HAS_FILE_BP ) {
HashPosition position ;
zend_llist * points ;
for ( zend_hash_internal_pointer_reset_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_FILE ] , & position ) ;
zend_hash_get_current_data_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_FILE ] , ( void * * ) & points , & position ) = = SUCCESS ;
zend_hash_move_forward_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_FILE ] , & position ) ) {
size_t size = points - > size ;
PHPDBG_G ( del_bp_num ) = num ;
zend_llist_apply_with_del ( points , phpdbg_delete_breakpoint_from_file_llist ) ;
if ( size ! = points - > size ) {
return ;
}
}
}
if ( PHPDBG_G ( flags ) & PHPDBG_HAS_OPLINE_BP ) {
HashPosition position ;
phpdbg_breakline_t * brake ;
for ( zend_hash_internal_pointer_reset_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_OPLINE ] , & position ) ;
zend_hash_get_current_data_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_OPLINE ] , ( void * * ) & brake , & position ) = = SUCCESS ;
zend_hash_move_forward_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_OPLINE ] , & position ) ) {
if ( brake - > id = = num ) {
zend_hash_index_del ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_OPLINE ] , brake - > opline ) ;
2013-11-24 12:14:53 +00:00
return ;
2013-11-24 11:58:08 +00:00
}
}
}
if ( PHPDBG_G ( flags ) & PHPDBG_HAS_COND_BP ) {
HashPosition position ;
phpdbg_breakcond_t * brake ;
for ( zend_hash_internal_pointer_reset_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_COND ] , & position ) ;
zend_hash_get_current_data_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_COND ] , ( void * * ) & brake , & position ) = = SUCCESS ;
zend_hash_move_forward_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_COND ] , & position ) ) {
if ( brake - > id = = num ) {
zend_hash_index_del ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_COND ] , brake - > hash ) ;
return ;
}
}
}
2013-11-24 12:14:53 +00:00
if ( PHPDBG_G ( flags ) & PHPDBG_HAS_OPCODE_BP ) {
HashPosition position ;
phpdbg_breakop_t * brake ;
for ( zend_hash_internal_pointer_reset_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_OPCODE ] , & position ) ;
zend_hash_get_current_data_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_OPCODE ] , ( void * * ) & brake , & position ) = = SUCCESS ;
zend_hash_move_forward_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_OPCODE ] , & position ) ) {
if ( brake - > id = = num ) {
zend_hash_index_del ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_OPCODE ] , brake - > hash ) ;
return ;
}
}
}
2013-11-24 11:58:08 +00:00
} /* }}} */
2013-11-23 18:12:51 +00:00
PHPDBG_API void phpdbg_clear_breakpoints ( TSRMLS_D ) /* { { { */
2013-11-11 17:19:05 +00:00
{
2013-11-26 10:02:58 +00:00
zend_hash_clean ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_FILE ] ) ;
zend_hash_clean ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_SYM ] ) ;
zend_hash_clean ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_OPLINE ] ) ;
zend_hash_clean ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_OPCODE ] ) ;
zend_hash_clean ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_METHOD ] ) ;
zend_hash_clean ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_COND ] ) ;
2013-11-13 23:36:02 +00:00
2013-11-26 10:02:58 +00:00
PHPDBG_G ( flags ) & = ~ PHPDBG_BP_MASK ;
2013-11-12 01:58:39 +00:00
2013-11-26 10:02:58 +00:00
PHPDBG_G ( bp_count ) = 0 ;
2013-11-11 17:19:05 +00:00
} /* }}} */
2013-11-23 18:12:51 +00:00
PHPDBG_API void phpdbg_print_breakpoints ( zend_ulong type TSRMLS_DC ) /* { { { */
2013-11-12 16:04:41 +00:00
{
2013-11-26 10:02:58 +00:00
switch ( type ) {
case PHPDBG_BREAK_SYM : if ( ( PHPDBG_G ( flags ) & PHPDBG_HAS_SYM_BP ) ) {
HashPosition position ;
phpdbg_breaksymbol_t * brake ;
phpdbg_writeln ( SEPARATE ) ;
phpdbg_writeln ( " Function Breakpoints: " ) ;
for ( zend_hash_internal_pointer_reset_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_SYM ] , & position ) ;
zend_hash_get_current_data_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_SYM ] , ( void * * ) & brake , & position ) = = SUCCESS ;
zend_hash_move_forward_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_SYM ] , & position ) ) {
phpdbg_writeln ( " #%d \t \t %s " , brake - > id , brake - > symbol ) ;
}
2013-11-24 11:43:05 +00:00
} break ;
2013-11-26 10:02:58 +00:00
case PHPDBG_BREAK_METHOD : if ( ( PHPDBG_G ( flags ) & PHPDBG_HAS_METHOD_BP ) ) {
HashPosition position [ 2 ] ;
HashTable * class_table ;
char * class_name = NULL ;
zend_uint class_len = 0 ;
zend_ulong class_idx = 0L ;
phpdbg_writeln ( SEPARATE ) ;
phpdbg_writeln ( " Method Breakpoints: " ) ;
for ( zend_hash_internal_pointer_reset_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_METHOD ] , & position [ 0 ] ) ;
zend_hash_get_current_data_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_METHOD ] , ( void * * ) & class_table , & position [ 0 ] ) = = SUCCESS ;
zend_hash_move_forward_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_METHOD ] , & position [ 0 ] ) ) {
if ( zend_hash_get_current_key_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_METHOD ] ,
& class_name , & class_len , & class_idx , 0 , & position [ 0 ] ) = = HASH_KEY_IS_STRING ) {
phpdbg_breakmethod_t * brake ;
for ( zend_hash_internal_pointer_reset_ex ( class_table , & position [ 1 ] ) ;
zend_hash_get_current_data_ex ( class_table , ( void * * ) & brake , & position [ 1 ] ) = = SUCCESS ;
zend_hash_move_forward_ex ( class_table , & position [ 1 ] ) ) {
phpdbg_writeln ( " #%d \t \t %s::%s " , brake - > id , brake - > class_name , brake - > func_name ) ;
}
}
}
} break ;
case PHPDBG_BREAK_FILE : if ( ( PHPDBG_G ( flags ) & PHPDBG_HAS_FILE_BP ) ) {
HashPosition position ;
zend_llist * points ;
phpdbg_writeln ( SEPARATE ) ;
phpdbg_writeln ( " File Breakpoints: " ) ;
for ( zend_hash_internal_pointer_reset_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_FILE ] , & position ) ;
zend_hash_get_current_data_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_FILE ] , ( void * * ) & points , & position ) = = SUCCESS ;
zend_hash_move_forward_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_FILE ] , & position ) ) {
zend_llist_position lposition ;
phpdbg_breakfile_t * brake ;
if ( ( brake = zend_llist_get_first_ex ( points , & lposition ) ) ) {
do {
phpdbg_writeln ( " #%d \t \t %s:%lu " , brake - > id , brake - > filename , brake - > line ) ;
} while ( ( brake = zend_llist_get_next_ex ( points , & lposition ) ) ) ;
}
}
} break ;
case PHPDBG_BREAK_OPLINE : if ( ( PHPDBG_G ( flags ) & PHPDBG_HAS_OPLINE_BP ) ) {
HashPosition position ;
phpdbg_breakline_t * brake ;
phpdbg_writeln ( SEPARATE ) ;
phpdbg_writeln ( " Opline Breakpoints: " ) ;
for ( zend_hash_internal_pointer_reset_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_OPLINE ] , & position ) ;
zend_hash_get_current_data_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_OPLINE ] , ( void * * ) & brake , & position ) = = SUCCESS ;
zend_hash_move_forward_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_OPLINE ] , & position ) ) {
phpdbg_writeln ( " #%d \t \t %#lx " , brake - > id , brake - > opline ) ;
}
} break ;
case PHPDBG_BREAK_COND : if ( ( PHPDBG_G ( flags ) & PHPDBG_HAS_COND_BP ) ) {
HashPosition position ;
phpdbg_breakcond_t * brake ;
phpdbg_writeln ( SEPARATE ) ;
phpdbg_writeln ( " Conditional Breakpoints: " ) ;
for ( zend_hash_internal_pointer_reset_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_COND ] , & position ) ;
zend_hash_get_current_data_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_COND ] , ( void * * ) & brake , & position ) = = SUCCESS ;
zend_hash_move_forward_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_COND ] , & position ) ) {
phpdbg_writeln ( " #%d \t \t %s " , brake - > id , Z_STRVAL ( brake - > code ) ) ;
}
2013-11-24 11:43:05 +00:00
} break ;
2013-11-26 10:02:58 +00:00
case PHPDBG_BREAK_OPCODE : if ( PHPDBG_G ( flags ) & PHPDBG_HAS_OPCODE_BP ) {
HashPosition position ;
phpdbg_breakop_t * brake ;
phpdbg_writeln ( SEPARATE ) ;
phpdbg_writeln ( " Opcode Breakpoints: " ) ;
for ( zend_hash_internal_pointer_reset_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_OPCODE ] , & position ) ;
zend_hash_get_current_data_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_OPCODE ] , ( void * * ) & brake , & position ) = = SUCCESS ;
zend_hash_move_forward_ex ( & PHPDBG_G ( bp ) [ PHPDBG_BREAK_OPCODE ] , & position ) ) {
phpdbg_writeln ( " #%d \t \t %s " , brake - > id , brake - > name ) ;
}
} break ;
}
2013-11-12 16:04:41 +00:00
} /* }}} */