Chinaunix首页 | 论坛 | 博客
  • 博客访问: 198521
  • 博文数量: 264
  • 博客积分: 6010
  • 博客等级: 准将
  • 技术积分: 2740
  • 用 户 组: 普通用户
  • 注册时间: 2009-06-03 13:25
文章分类

全部博文(264)

文章存档

2011年(1)

2009年(263)

我的朋友

分类:

2009-06-03 16:34:00

· 作者:laruence(
· 本文地址: 
· 转载请注明出处

PHP提供了一个Embed SAPI,也就是说,PHP容许你在C/C++语言中调用PHP/ZE提供的函数。本文就通过基于Embed SAPI实现一个PHP的opcodes查看器。
首先,下载PHP源码以供编译, 我现在使用的是PHP5.3 alpha2
进入源码目录

./configure --enable-embed 
 ./make
 ./make install


最后,记得要将生成的libphp5.so复制到运行时库的目录,我直接拷贝到了/lib/, 否则会在运行你自己的embed程序的时候报错:

./embed: error while loading shared libraries: libphp5.so: cannot open shared object file: No such file or directory


如果你对PHP的SAPI还不熟悉的话,我建议你看看我的这篇文章:
这个时候,你就可以在你的C代码中,嵌入PHP脚本解析器了, 我的例子:

#include "sapi/embed/php_embed.h"

 
int main(int argcchar * argv[]){
    
PHP_EMBED_START_BLOCK(argc,argv);
    
char * script = " print 'Hello World!';";
    
zend_eval_string(scriptNULL,
                                      
"Simple Hello World App" TSRMLS_CC);
    
PHP_EMBED_END_BLOCK();
    
return 0;
}


然后就是要指明include path了,一个简单的Makefile

CC = gcc
CFLAGS = -I/usr/local/include/php/ \
            -I/usr/local/include/php/main \
            -I/usr/local/include/php/Zend \
            -I/usr/local/include/php/TSRM \
            -Wall -g
LDFLAGS = -lstdc++ -L/usr/local/lib -lphp5
ALL:
    $(CC) -o embed embed.cpp $(CFLAGS) $(LDFLAGS)


编译成功以后, 运行,我们可以看到, stdout输出 Hello World!
基于这个,我们就可以很容易的实现一个类似于vld的Opcodes dumper:
首先我们定义opcode的转换函数(全部的opcodes可以查看Zend/zend_vm_opcodes.h);

char *opname(zend_uchar opcode){
    
switch(opcode) {
        
case ZEND_NOPreturn "ZEND_NOP"break;
        
case ZEND_ADDreturn "ZEND_ADD"break;
        
case ZEND_SUBreturn "ZEND_SUB"break;
        
case ZEND_MULreturn "ZEND_MUL"break;
        
case ZEND_DIVreturn "ZEND_DIV"break;
        
case ZEND_MODreturn "ZEND_MOD"break;
        
case ZEND_SLreturn "ZEND_SL"break;
        
case ZEND_SRreturn "ZEND_SR"break;
        
case ZEND_CONCATreturn "ZEND_CONCAT"break;
        
case ZEND_BW_ORreturn "ZEND_BW_OR"break;
        
case ZEND_BW_ANDreturn "ZEND_BW_AND"break;
        
case ZEND_BW_XORreturn "ZEND_BW_XOR"break;
        
case ZEND_BW_NOTreturn "ZEND_BW_NOT"break;
        
/*...省略 ....*/
        
default : return "UNKNOW"break;


然后定义zval和znode的输出函数:

char *format_zval(zval *z)
{
    
static char buffer[BUFFER_LEN];
    
int len;
 
    
switch(z->type) {
        
case IS_NULL:
            
return "NULL";
        
case IS_LONG:
        
case IS_BOOL:
            
snprintf(bufferBUFFER_LEN"%d"z->value.lval);
            
return buffer;
        
case IS_DOUBLE:
            
snprintf(bufferBUFFER_LEN"%f"z->value.dval);
            
return buffer;
        
case IS_STRING:
            
snprintf(bufferBUFFER_LEN"\"%s\""z->value.str.val);
            
return buffer;
        
case IS_ARRAY:
        
case IS_OBJECT:
        
case IS_RESOURCE:
        
case IS_CONSTANT:
        
case IS_CONSTANT_ARRAY:
            
return "";
        
default:
            
return "unknown";
    
}
}
 
char * format_znode(znode *n){
    
static char buffer[BUFFER_LEN];
 
    
switch (n->op_type) {
        
case IS_CONST:
            
return format_zval(&n->u.constant);
            
break;
        
case IS_VAR:
            
snprintf(bufferBUFFER_LEN"$%d",  n->u.var/sizeof(temp_variable));
            
return buffer;
            
break;
        
case IS_TMP_VAR:
            
snprintf(bufferBUFFER_LEN"~%d",  n->u.var/sizeof(temp_variable));
            
return buffer;
            
break;
        
default:
            
return "";
            
break;
    
}
}


然后定义op_array的输出函数:

void dump_op(zend_op *opint num){
    
printf("%5d  %5d %30s %040s %040s %040s\n"numop->lineno,
            
opname(op->opcode),
            
format_znode(&op->op1),
            
format_znode(&op->op2),
            
format_znode(&op->result)) ;
}
 
void dump_op_array(zend_op_array *op_array){
    
if(op_array) {
        
int i;
        
printf("%5s  %5s %30s %040s %040s %040s\n""opnum""line""opcode""op1""op2""result");
        
for(i = 0i < op_array->lasti++) {
            
dump_op(&op_array->opcodes[i]i);
        
}
    
}
}


最后,就是程序的主函数了:

int main(int argcchar **argv){
    
zend_op_array *op_array;
    
zend_file_handle file_handle;
 
    
if(argc != 2) {
        
printf("usage:  op_dumper

阅读(178) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~