How to implement Opcodes Viewer _php instance using PHP Embed SAPI

Source: Internet
Author: User
Tags php script php source code sapi zend

PHP provides a embed SAPI, that is, PHP allows you to invoke the functions provided by php/ze in C + + language. This article implements a PHP Opcodes viewer based on embed SAPI.

First of all, download the PHP source code for compiling, I now use PHP5.3 alpha2

Access to the source directory:

./configure--enable-embed--WITH-CONFIG-FILE-SCAN-DIR=/ETC/PHP.D--with-mysql--with-config-file-path=/etc/
./make
./make Install

Finally, remember to copy the generated libphp5.so to the runtime library directory, I copied directly to the/lib/, otherwise you will be running your own embed program when the error:

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

If you're not familiar with PHP's SAPI, I suggest you take a look at my article: a deep understanding of Zend Sapis (Zend SAPI Internals)
This time, you can embed PHP script parser in your C code, my example:

#include "sapi/embed/php_embed.h"
int main (int argc, char * argv[]) {
 php_embed_start_block (ARGC,ARGV);
 char * script = "print ' Hello world! ';";
 zend_eval_string (script, NULL,
          "Simple Hello World App" tsrmls_cc);
 Php_embed_end_block ();
 return 0;
}

And then you're going to indicate include path, a simple 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)

After compiling successfully, run, we can see that stdout output Hello world!

Based on this, we can easily implement a VLD-like opcodes dumper:
First we define the opcode transformation functions (all opcodes can view zend/zend_vm_opcodes.h);

Char *opname (Zend_uchar opcode) {
 switch (opcode) {case
  Zend_nop:return "Zend_nop";
  Case Zend_add:return "Zend_add"; break;
  Case Zend_sub:return "Zend_sub"; break;
  Case Zend_mul:return "Zend_mul"; break;
  Case Zend_div:return "Zend_div"; break;
  Case Zend_mod:return "Zend_mod"; break;
  Case Zend_sl:return "ZEND_SL"; break;
  Case Zend_sr:return "ZEND_SR"; break;
  Case Zend_concat:return "Zend_concat"; break;
  Case Zend_bw_or:return "Zend_bw_or"; break;
  Case Zend_bw_and:return "Zend_bw_and"; break;
  Case Zend_bw_xor:return "Zend_bw_xor"; break;
  Case Zend_bw_not:return "Zend_bw_not"; break;
  /*... Omit .... * *
  Default:return "Unknow";

Then define the output functions for Zval and 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 (buffer, Buffer_len, "%d", z->value.lval);
  return buffer;
   Case is_double:snprintf (buffer, Buffer_len, "%f", z->value.dval);
  return buffer;
   Case is_string:snprintf (buffer, Buffer_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 (buffer, Buffer_len, "$%d", N->u.var/sizeof (temp_variable));
   return buffer;
  Break
   Case is_tmp_var:snprintf (buffer, Buffer_len, "~%d", N->u.var/sizeof (temp_variable));
   return buffer;
  Break Default:rEturn "";
 Break }
}

Then define the output function of the Op_array:

void Dump_op (zend_op *op, int num) {
 printf ("%5d%5d%30s%040s%040s%040s\n", num, Op->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 = 0; i < op_array->last; i++) {
   dump_op (&op_array->opcodes[i], i);}}


And finally, the main function of the program:

int main (int argc, char **argv) {
 Zend_op_array *op_array;
 Zend_file_handle File_handle;
 if (argc!= 2) {
  printf ("Usage:op_dumper <script>\n");
  return 1;
 }
 Php_embed_start_block (ARGC,ARGV);
 printf ("Script:%s\n", argv[1]);
 File_handle.filename = argv[1];
 File_handle.free_filename = 0;
 File_handle.type = Zend_handle_filename;
 File_handle.opened_path = NULL;
 Op_array = Zend_compile_file (&file_handle, Zend_include tsrmls_cc);
 if (!op_array) {
  printf ("Error parsing script:%s\n", file_handle.filename);
  return 1;
 }
 Dump_op_array (Op_array);
 Php_embed_end_block ();
 return 0;
}

Compile, run test script (sample.php):

Copy Code code as follows:

sample.php:
echo "Laruence";

Command:

Copy Code code as follows:

./opcodes_dumper sample.php

Get the output (if you're confused about the results below, I suggest you take a look at my article: a deep understanding of the opcodes of PHP Principles):

Script:sample.php

opnum line opcode OP1 OP2 Result
0 2 Zend_echo "laruence"
1 4 Zend_return 1

Oh, how, is not very fun?

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.