PHP內核之opcode的處理函數查找

首先我們需要知道有個存放 所有opcode 的 opcode_handler_t 的函數指針字段 的集合 的文件 php-5.5.12\Zend\zend_vm_execute.h

void zend_init_opcodes_handlers(void)
{
	/* opcode執行函數的指針字段集合 */
  static const opcode_handler_t labels[] = {
  	ZEND_NOP_SPEC_HANDLER,
  	ZEND_NOP_SPEC_HANDLER,
  	ZEND_NOP_SPEC_HANDLER,
  	ZEND_NOP_SPEC_HANDLER,
  	ZEND_NOP_SPEC_HANDLER,
  	ZEND_NOP_SPEC_HANDLER,
  	ZEND_NOP_SPEC_HANDLER,
  	ZEND_NOP_SPEC_HANDLER,
  	ZEND_NOP_SPEC_HANDLER,
  	ZEND_NOP_SPEC_HANDLER,
  	ZEND_NOP_SPEC_HANDLER,
  	ZEND_NOP_SPEC_HANDLER,
  	ZEND_NOP_SPEC_HANDLER,
  	ZEND_NOP_SPEC_HANDLER,
  	ZEND_NOP_SPEC_HANDLER,
  	ZEND_NOP_SPEC_HANDLER,
  	ZEND_NOP_SPEC_HANDLER,
  	ZEND_NOP_SPEC_HANDLER,
        ........
        ZEND_FAST_RET_SPEC_HANDLER,
  	ZEND_FAST_RET_SPEC_HANDLER,
  	ZEND_FAST_RET_SPEC_HANDLER,
  	ZEND_FAST_RET_SPEC_HANDLER,
  	ZEND_FAST_RET_SPEC_HANDLER,
  	ZEND_FAST_RET_SPEC_HANDLER,
  	ZEND_FAST_RET_SPEC_HANDLER,
  	ZEND_NULL_HANDLER
  };
  zend_opcode_handlers = (opcode_handler_t*)labels;
}

接下來進入正題:

這裏我們使用 日誌記錄的方式 查找 opcode 對應的處理函數

在 zend_vm_get_opcode_handler 方法中添加以下代碼:

static opcode_handler_t zend_vm_get_opcode_handler(zend_uchar opcode, zend_op* op)
{
		static const int zend_vm_decode[] = {
			_UNUSED_CODE, /* 0              */
			_CONST_CODE,  /* 1 = IS_CONST   */
			_TMP_CODE,    /* 2 = IS_TMP_VAR */
			_UNUSED_CODE, /* 3              */
			_VAR_CODE,    /* 4 = IS_VAR     */
			_UNUSED_CODE, /* 5              */
			_UNUSED_CODE, /* 6              */
			_UNUSED_CODE, /* 7              */
			_UNUSED_CODE, /* 8 = IS_UNUSED  */
			_UNUSED_CODE, /* 9              */
			_UNUSED_CODE, /* 10             */
			_UNUSED_CODE, /* 11             */
			_UNUSED_CODE, /* 12             */
			_UNUSED_CODE, /* 13             */
			_UNUSED_CODE, /* 14             */
			_UNUSED_CODE, /* 15             */
			_CV_CODE      /* 16 = IS_CV     */
		};

		/* 日誌記錄法記錄opcode的處理函數 */
		int 		  op_index;
		FILE          *stream;

		op_index = opcode * 25 + zend_vm_decode[op->op1_type] * 5 + zend_vm_decode[op->op2_type];

		if((stream = fopen("./tmp/php-opcode.log", "a+")) != NULL){
			fprintf(stream, "opcode: %d, zend_opcode_handlers_index: %d\n", opcode, op_index );
		}
		fclose(stream);

		return zend_opcode_handlers[opcode * 25 + zend_vm_decode[op->op1_type] * 5 + zend_vm_decode[op->op2_type]];
}


然後編譯php源碼包,爲了方便看代碼中的opcode,編譯時候記得開啓動態鏈接庫 vld

configure --disable-all --enable-snapshot-build --enable-cli --enable-cgi --enable-object-out-dir=..\obj --enable-session  --enable-vld=shared


編譯完成後 

1、在生成的 obj\Release_TS\php-5.5.12 下 手動新建 tmp 文件夾

2、在生成的 obj\Release_TS\php-5.5.12 下 做php.ini文件 並制定ext爲擴展目錄

3、添加php_vld.dll擴展

至此準備工作完成,接下來 我們看步入真正的查找工作

php代碼:


opcode信息:



生成的opcode.log日誌

其中的

opcode 數值 可從 http://php.net/manual/zh/internals2.opcodes.list.php 中查找到

 zend_opcode_handlers_index 就是 stati cconst opcode_handler_t labels[] 的索引,裏面對應了處理函數的名稱

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章