2013-11-12 07:40:03 +08:00
/*
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2015-03-13 17:09:42 +08:00
| PHP Version 7 |
2013-11-12 07:40:03 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
2015-01-15 23:27:30 +08:00
| Copyright ( c ) 1997 - 2015 The PHP Group |
2013-11-12 07:40:03 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| 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 > |
2013-12-18 18:02:50 +08:00
| Authors : Bob Weinand < bwoebi @ php . net > |
2013-11-12 07:40:03 +08:00
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
*/
# include <stdio.h>
# include <string.h>
# include <sys/stat.h>
2013-11-12 20:38:04 +08:00
# ifndef _WIN32
# include <sys / mman.h>
# include <unistd.h>
# endif
2013-11-12 07:40:03 +08:00
# include <fcntl.h>
2013-11-12 10:29:56 +08:00
# include "phpdbg.h"
2013-11-12 07:40:03 +08:00
# include "phpdbg_list.h"
2013-11-13 07:43:49 +08:00
# include "phpdbg_utils.h"
2014-02-20 04:18:49 +08:00
# include "phpdbg_prompt.h"
2014-02-28 03:10:59 +08:00
# include "php_streams.h"
2013-11-12 07:40:03 +08:00
2013-11-14 23:46:06 +08:00
ZEND_EXTERN_MODULE_GLOBALS ( phpdbg ) ;
2014-10-03 07:29:41 +08:00
# define PHPDBG_LIST_COMMAND_D(f, h, a, m, l, s, flags) \
2015-03-22 06:19:12 +08:00
PHPDBG_COMMAND_D_EXP ( f , h , a , m , l , s , & phpdbg_prompt_commands [ 12 ] , flags )
2014-02-20 04:18:49 +08:00
2014-02-03 00:35:28 +08:00
const phpdbg_command_t phpdbg_list_commands [ ] = {
2014-10-03 07:29:41 +08:00
PHPDBG_LIST_COMMAND_D ( lines , " lists the specified lines " , ' l ' , list_lines , NULL , " l " , PHPDBG_ASYNC_SAFE ) ,
PHPDBG_LIST_COMMAND_D ( class , " lists the specified class " , ' c ' , list_class , NULL , " s " , PHPDBG_ASYNC_SAFE ) ,
PHPDBG_LIST_COMMAND_D ( method , " lists the specified method " , ' m ' , list_method , NULL , " m " , PHPDBG_ASYNC_SAFE ) ,
PHPDBG_LIST_COMMAND_D ( func , " lists the specified function " , ' f ' , list_func , NULL , " s " , PHPDBG_ASYNC_SAFE ) ,
2014-02-03 00:35:28 +08:00
PHPDBG_END_COMMAND
} ;
2013-11-14 23:46:06 +08:00
PHPDBG_LIST ( lines ) /* {{{ */
{
2014-12-14 06:06:14 +08:00
if ( ! PHPDBG_G ( exec ) & & ! zend_is_executing ( ) ) {
2014-09-21 10:17:19 +08:00
phpdbg_error ( " inactive " , " type= \" execution \" " , " Not executing, and execution context not set " ) ;
2013-11-17 19:15:53 +08:00
return SUCCESS ;
}
switch ( param - > type ) {
2014-10-25 01:29:50 +08:00
case NUMERIC_PARAM : {
2014-12-14 06:06:14 +08:00
const char * char_file = phpdbg_current_file ( ) ;
2014-10-25 01:29:50 +08:00
zend_string * file = zend_string_init ( char_file , strlen ( char_file ) , 0 ) ;
2014-12-14 06:06:14 +08:00
phpdbg_list_file ( file , param - > num < 0 ? 1 - param - > num : param - > num , ( param - > num < 0 ? param - > num : 0 ) + zend_get_executed_lineno ( ) , 0 ) ;
2014-10-25 01:29:50 +08:00
efree ( file ) ;
} break ;
case FILE_PARAM : {
zend_string * file = zend_string_init ( param - > file . name , strlen ( param - > file . name ) , 0 ) ;
2014-12-14 06:06:14 +08:00
phpdbg_list_file ( file , param - > file . line , 0 , 0 ) ;
2014-10-25 01:29:50 +08:00
efree ( file ) ;
} break ;
2013-11-17 19:37:14 +08:00
2013-11-17 19:31:09 +08:00
phpdbg_default_switch_case ( ) ;
2013-11-17 19:15:53 +08:00
}
2013-11-26 18:02:58 +08:00
return SUCCESS ;
2013-11-14 23:46:06 +08:00
} /* }}} */
PHPDBG_LIST ( func ) /* {{{ */
{
2014-12-14 06:06:14 +08:00
phpdbg_list_function_byname ( param - > str , param - > len ) ;
2013-11-17 19:15:53 +08:00
2013-11-26 18:02:58 +08:00
return SUCCESS ;
2013-11-17 02:53:12 +08:00
} /* }}} */
PHPDBG_LIST ( method ) /* {{{ */
{
2014-10-25 01:29:50 +08:00
zend_class_entry * ce ;
2013-11-26 18:02:58 +08:00
2014-12-14 06:06:14 +08:00
if ( phpdbg_safe_class_lookup ( param - > method . class , strlen ( param - > method . class ) , & ce ) = = SUCCESS ) {
2014-02-22 04:46:56 +08:00
zend_function * function ;
char * lcname = zend_str_tolower_dup ( param - > method . name , strlen ( param - > method . name ) ) ;
2013-11-26 18:02:58 +08:00
2014-10-25 01:29:50 +08:00
if ( ( function = zend_hash_str_find_ptr ( & ce - > function_table , lcname , strlen ( lcname ) ) ) ) {
2014-12-14 06:06:14 +08:00
phpdbg_list_function ( function ) ;
2014-02-22 04:46:56 +08:00
} else {
2014-09-21 10:17:19 +08:00
phpdbg_error ( " list " , " type= \" notfound \" method= \" %s::%s \" " , " Could not find %s::%s " , param - > method . class , param - > method . name ) ;
2014-02-22 04:46:56 +08:00
}
2013-11-26 18:02:58 +08:00
2014-02-22 04:46:56 +08:00
efree ( lcname ) ;
} else {
2014-09-21 10:17:19 +08:00
phpdbg_error ( " list " , " type= \" notfound \" class= \" %s \" " , " Could not find the class %s " , param - > method . class ) ;
2013-11-26 18:02:58 +08:00
}
return SUCCESS ;
2013-11-17 02:53:12 +08:00
} /* }}} */
PHPDBG_LIST ( class ) /* {{{ */
{
2014-10-25 01:29:50 +08:00
zend_class_entry * ce ;
2014-02-22 04:46:56 +08:00
2014-12-14 06:06:14 +08:00
if ( phpdbg_safe_class_lookup ( param - > str , param - > len , & ce ) = = SUCCESS ) {
2014-10-25 01:29:50 +08:00
if ( ce - > type = = ZEND_USER_CLASS ) {
if ( ce - > info . user . filename ) {
2014-12-14 06:06:14 +08:00
phpdbg_list_file ( ce - > info . user . filename , ce - > info . user . line_end - ce - > info . user . line_start + 1 , ce - > info . user . line_start , 0 ) ;
2013-11-26 18:02:58 +08:00
} else {
2014-10-25 01:29:50 +08:00
phpdbg_error ( " list " , " type= \" nosource \" class= \" %s \" " , " The source of the requested class (%s) cannot be found " , ce - > name ) ;
2013-11-26 18:02:58 +08:00
}
2014-02-22 04:46:56 +08:00
} else {
2014-10-25 01:29:50 +08:00
phpdbg_error ( " list " , " type= \" internalclass \" class= \" %s \" " , " The class requested (%s) is not user defined " , ce - > name ) ;
2014-02-22 04:46:56 +08:00
}
} else {
2014-09-21 10:17:19 +08:00
phpdbg_error ( " list " , " type= \" notfound \" class= \" %s \" " , " The requested class (%s) could not be found " , param - > str ) ;
2013-11-26 18:02:58 +08:00
}
return SUCCESS ;
2013-11-14 23:46:06 +08:00
} /* }}} */
2014-12-14 06:06:14 +08:00
void phpdbg_list_file ( zend_string * filename , uint count , int offset , uint highlight ) /* { { { */
2013-11-12 07:40:03 +08:00
{
2014-10-03 07:29:41 +08:00
uint line , lastline ;
2014-10-25 01:29:50 +08:00
phpdbg_file_source * data ;
2014-10-25 21:06:34 +08:00
char resolved_path_buf [ MAXPATHLEN ] ;
2014-10-26 01:09:19 +08:00
const char * abspath ;
2014-06-29 18:43:51 +08:00
2015-06-30 18:59:27 +08:00
if ( VCWD_REALPATH ( ZSTR_VAL ( filename ) , resolved_path_buf ) ) {
2014-10-26 01:09:19 +08:00
abspath = resolved_path_buf ;
} else {
2015-06-30 18:59:27 +08:00
abspath = ZSTR_VAL ( filename ) ;
2014-10-25 21:06:34 +08:00
}
2014-06-29 18:18:39 +08:00
2014-10-26 01:09:19 +08:00
if ( ! ( data = zend_hash_str_find_ptr ( & PHPDBG_G ( file_sources ) , abspath , strlen ( abspath ) ) ) ) {
2014-10-07 19:08:30 +08:00
phpdbg_error ( " list " , " type= \" unknownfile \" " , " Could not find information about included file... " ) ;
2013-11-12 10:29:56 +08:00
return ;
}
2014-09-21 10:17:19 +08:00
2014-06-29 18:43:51 +08:00
if ( offset < 0 ) {
count + = offset ;
offset = 0 ;
}
2014-06-29 18:18:39 +08:00
2014-10-03 07:29:41 +08:00
lastline = offset + count ;
2014-09-21 10:17:19 +08:00
2014-10-25 01:29:50 +08:00
if ( lastline > data - > lines ) {
lastline = data - > lines ;
2014-10-03 07:29:41 +08:00
}
2014-06-29 18:18:39 +08:00
2014-10-07 19:08:30 +08:00
phpdbg_xml ( " <list %r file= \" %s \" > " , filename ) ;
2014-09-21 10:17:19 +08:00
2014-10-03 07:29:41 +08:00
for ( line = offset ; line < lastline ; ) {
2014-10-25 01:29:50 +08:00
uint linestart = data - > line [ line + + ] ;
uint linelen = data - > line [ line ] - linestart ;
char * buffer = data - > buf + linestart ;
2014-06-29 18:18:39 +08:00
2014-10-03 07:29:41 +08:00
if ( ! highlight ) {
2014-10-09 17:52:57 +08:00
phpdbg_write ( " line " , " line= \" %u \" code= \" %.*s \" " , " %05u: %.*s " , line , linelen , buffer ) ;
2014-10-03 07:29:41 +08:00
} else {
if ( highlight ! = line ) {
2014-10-09 17:52:57 +08:00
phpdbg_write ( " line " , " line= \" %u \" code= \" %.*s \" " , " %05u: %.*s " , line , linelen , buffer ) ;
2014-10-03 07:29:41 +08:00
} else {
2014-10-09 17:52:57 +08:00
phpdbg_write ( " line " , " line= \" %u \" code= \" %.*s \" current= \" current \" " , " >%05u: %.*s " , line , linelen , buffer ) ;
2014-06-29 18:18:39 +08:00
}
2013-11-12 07:40:03 +08:00
}
2014-06-29 18:18:39 +08:00
2014-10-09 18:43:53 +08:00
if ( * ( buffer + linelen - 1 ) ! = ' \n ' | | ! linelen ) {
2014-10-07 19:08:30 +08:00
phpdbg_out ( " \n " ) ;
2014-06-29 18:43:51 +08:00
}
2013-11-12 07:40:03 +08:00
}
2014-09-21 10:17:19 +08:00
phpdbg_xml ( " </list> " ) ;
2013-11-12 07:40:03 +08:00
} /* }}} */
2013-11-12 10:19:43 +08:00
2014-12-14 06:06:14 +08:00
void phpdbg_list_function ( const zend_function * fbc ) /* { { { */
2013-11-12 10:19:43 +08:00
{
const zend_op_array * ops ;
if ( fbc - > type ! = ZEND_USER_FUNCTION ) {
2015-06-30 18:59:27 +08:00
phpdbg_error ( " list " , " type= \" internalfunction \" function= \" %s \" " , " The function requested (%s) is not user defined " , ZSTR_VAL ( fbc - > common . function_name ) ) ;
2013-11-12 10:19:43 +08:00
return ;
}
2014-10-25 01:29:50 +08:00
ops = ( zend_op_array * ) fbc ;
2013-11-12 10:19:43 +08:00
2014-12-14 06:06:14 +08:00
phpdbg_list_file ( ops - > filename , ops - > line_end - ops - > line_start + 1 , ops - > line_start , 0 ) ;
2013-11-12 10:19:43 +08:00
} /* }}} */
2013-11-12 20:38:04 +08:00
2014-12-14 06:06:14 +08:00
void phpdbg_list_function_byname ( const char * str , size_t len ) /* { { { */
2013-11-17 07:11:39 +08:00
{
2013-11-26 18:02:58 +08:00
HashTable * func_table = EG ( function_table ) ;
zend_function * fbc ;
char * func_name = ( char * ) str ;
size_t func_name_len = len ;
/* search active scope if begins with period */
if ( func_name [ 0 ] = = ' . ' ) {
if ( EG ( scope ) ) {
func_name + + ;
func_name_len - - ;
func_table = & EG ( scope ) - > function_table ;
} else {
2014-09-21 10:17:19 +08:00
phpdbg_error ( " inactive " , " type= \" noclasses \" " , " No active class " ) ;
2013-11-26 18:02:58 +08:00
return ;
}
} else if ( ! EG ( function_table ) ) {
2014-09-21 10:17:19 +08:00
phpdbg_error ( " inactive " , " type= \" function_table \" " , " No function table loaded " ) ;
2013-11-26 18:02:58 +08:00
return ;
} else {
func_table = EG ( function_table ) ;
}
/* use lowercase names, case insensitive */
func_name = zend_str_tolower_dup ( func_name , func_name_len ) ;
2014-10-03 07:29:41 +08:00
phpdbg_try_access {
2014-10-25 01:29:50 +08:00
if ( ( fbc = zend_hash_str_find_ptr ( func_table , func_name , func_name_len ) ) ) {
2014-12-14 06:06:14 +08:00
phpdbg_list_function ( fbc ) ;
2014-10-03 07:29:41 +08:00
} else {
2014-10-07 19:08:30 +08:00
phpdbg_error ( " list " , " type= \" nofunction \" function= \" %s \" " , " Function %s not found " , func_name ) ;
2014-10-03 07:29:41 +08:00
}
} phpdbg_catch_access {
2014-10-07 19:08:30 +08:00
phpdbg_error ( " signalsegv " , " function= \" %s \" " , " Could not list function %s, invalid data source " , func_name ) ;
2014-10-03 07:29:41 +08:00
} phpdbg_end_try_access ( ) ;
2013-11-26 18:02:58 +08:00
efree ( func_name ) ;
2013-11-21 02:52:34 +08:00
} /* }}} */
2013-11-17 07:11:39 +08:00
2014-12-14 06:06:14 +08:00
zend_op_array * phpdbg_compile_file ( zend_file_handle * file , int type ) {
2014-10-03 07:29:41 +08:00
phpdbg_file_source data , * dataptr ;
2014-10-25 01:29:50 +08:00
zend_file_handle fake = { { 0 } } ;
2014-10-03 07:29:41 +08:00
zend_op_array * ret ;
2015-06-30 18:59:27 +08:00
char * filename = ( char * ) ( file - > opened_path ? ZSTR_VAL ( file - > opened_path ) : file - > filename ) ;
2014-10-03 07:29:41 +08:00
uint line ;
char * bufptr , * endptr ;
2014-10-25 21:06:34 +08:00
char resolved_path_buf [ MAXPATHLEN ] ;
2014-10-03 07:29:41 +08:00
2015-07-22 06:02:40 +08:00
if ( zend_stream_fixup ( file , & data . buf , & data . len ) = = FAILURE ) {
return NULL ;
}
2014-10-03 07:29:41 +08:00
data . filename = filename ;
data . line [ 0 ] = 0 ;
if ( file - > handle . stream . mmap . old_closer ) {
/* do not unmap */
file - > handle . stream . closer = file - > handle . stream . mmap . old_closer ;
}
# if HAVE_MMAP
if ( file - > handle . stream . mmap . map ) {
data . map = file - > handle . stream . mmap . map ;
}
# endif
fake . type = ZEND_HANDLE_MAPPED ;
fake . handle . stream . mmap . buf = data . buf ;
fake . handle . stream . mmap . len = data . len ;
fake . free_filename = 0 ;
2014-10-05 05:21:34 +08:00
fake . opened_path = file - > opened_path ;
2014-10-03 07:29:41 +08:00
fake . filename = filename ;
2014-10-05 05:30:57 +08:00
fake . opened_path = file - > opened_path ;
2014-10-03 07:29:41 +08:00
* ( dataptr = emalloc ( sizeof ( phpdbg_file_source ) + sizeof ( uint ) * data . len ) ) = data ;
2014-10-25 21:06:34 +08:00
if ( VCWD_REALPATH ( filename , resolved_path_buf ) ) {
filename = resolved_path_buf ;
}
2014-10-03 07:29:41 +08:00
for ( line = 0 , bufptr = data . buf - 1 , endptr = data . buf + data . len ; + + bufptr < endptr ; ) {
if ( * bufptr = = ' \n ' ) {
dataptr - > line [ + + line ] = ( uint ) ( bufptr - data . buf ) + 1 ;
}
}
dataptr - > lines = + + line ;
2014-10-09 18:43:53 +08:00
dataptr - > line [ line ] = endptr - data . buf ;
dataptr = erealloc ( dataptr , sizeof ( phpdbg_file_source ) + sizeof ( uint ) * line ) ;
2014-10-03 07:29:41 +08:00
2014-10-25 01:29:50 +08:00
zend_hash_str_add_ptr ( & PHPDBG_G ( file_sources ) , filename , strlen ( filename ) , dataptr ) ;
2014-12-14 06:06:14 +08:00
phpdbg_resolve_pending_file_break ( filename ) ;
2014-10-25 01:29:50 +08:00
2014-12-14 06:06:14 +08:00
ret = PHPDBG_G ( compile_file ) ( & fake , type ) ;
2014-10-03 07:29:41 +08:00
2014-10-05 05:30:57 +08:00
fake . opened_path = NULL ;
2014-12-14 06:06:14 +08:00
zend_file_handle_dtor ( & fake ) ;
2014-10-03 07:29:41 +08:00
2015-07-23 00:11:35 +08:00
dataptr - > op_array = ret ;
2015-07-23 07:03:03 +08:00
if ( dataptr - > op_array - > refcount ) {
+ + * dataptr - > op_array - > refcount ;
} else {
dataptr - > op_array - > refcount = emalloc ( sizeof ( uint32_t ) ) ;
* dataptr - > op_array - > refcount = 2 ;
}
2015-07-23 00:11:35 +08:00
2014-10-03 07:29:41 +08:00
return ret ;
}
void phpdbg_free_file_source ( phpdbg_file_source * data ) {
# if HAVE_MMAP
if ( data - > map ) {
munmap ( data - > map , data - > len + ZEND_MMAP_AHEAD ) ;
} else
# endif
if ( data - > buf ) {
efree ( data - > buf ) ;
}
2015-07-23 00:11:35 +08:00
if ( destroy_op_array ( data - > op_array ) ) {
efree ( data - > op_array ) ;
}
2014-10-03 07:29:41 +08:00
efree ( data ) ;
}
2014-12-14 06:06:14 +08:00
void phpdbg_init_list ( void ) {
2014-10-03 07:29:41 +08:00
PHPDBG_G ( compile_file ) = zend_compile_file ;
zend_hash_init ( & PHPDBG_G ( file_sources ) , 1 , NULL , ( dtor_func_t ) phpdbg_free_file_source , 0 ) ;
zend_compile_file = phpdbg_compile_file ;
}