Understanding zend_execute APIs

1.1k views Asked by At

I have looked around a lot and never got a good book or any online documentation on zend_extensions [found quite some on PHP extensions but not much on zend_extensions]. I am writing an extension and would like to do the following:

1. Capture the state (mainly arguments of the function call) of the currently executing functions. [I found a struct that contains some function data and look into it to find the function parameter names but am unable to find their values. if zend_execute_data *execd is the struct pointer.

execd->function_state.function->common.(arg_info+i)->name) gives the name of the ith agrument's variable name for current function]. How do I get the value of ith parameter. I know I require to read from stack. How do I get a reference into the parameters in stack? Is there a hash table or something?

2. Secondly, How do I skip the currently executing function and jump to the next function/statement in the php script or replace the current function's code with code from a cleaner or safe version of that function? From the zend_execute function.

Bigger picture: I am trying to get the function state and take some decision of the interpreter's execution flow based on the function state. I am trying to do all this from the zend_execute( ) located in my zend_extension so I only have the zend_execute( ) APIs to accomplish the above 2 tasks. Below is the list of structs I've gone through as of now and inspected to be able to find the value of arguments of the current function.

struct _zend_execute_data {
    struct _zend_op *opline;
    zend_function_state function_state;
    zend_function *fbc; /* Function Being Called */
    zend_class_entry *called_scope;
    zend_op_array *op_array;
    zval *object;
    union _temp_variable *Ts;
    zval ***CVs;
    HashTable *symbol_table;
    struct _zend_execute_data *prev_execute_data;
    zval *old_error_reporting;
    zend_bool nested;
    zval **original_return_value;
    zend_class_entry *current_scope;
    zend_class_entry *current_called_scope;
    zval *current_this;
    zval *current_object;
};

references

typedef struct _zend_function_state {
    zend_function *function;
    void **arguments;
} zend_function_state;

references

typedef union _zend_function {
    zend_uchar type;  /* MUST be the first element of this struct! */

    struct {
        zend_uchar type;  /* never used */
        const char *function_name;
        zend_class_entry *scope;
        zend_uint fn_flags;
        union _zend_function *prototype;
        zend_uint num_args;
        zend_uint required_num_args;
        zend_arg_info *arg_info;
    } common;

    zend_op_array op_array;
    zend_internal_function internal_function;
} zend_function;

There isn't much documentation on the internals and I haven't been able to join the internals mailing list. It says I am waiting for approval. I have referred articles on PHP extension writing and books such as "Advanced PHP programming" and such but am still hazy on these aspects and the APIs around them.

Direct answers or any suggestions in general as to how I can progress from here will be much appreciated. This is my first post on Stack Overflow so I'm sorry if there are any guidelines that I've not adhered to. I tried to be compliant on as many fronts as I could.

2

There are 2 answers

0
Prasanth K On BEST ANSWER

I figured this out inspecting some source code from the Zend folder. The below struct has the element which is a void ** if this is cast into (zval **) and assigned to a (zval *) and then assigned to a zval, each of the elements of the zval can be accessed. Turns out it was pretty trivial question.

typedef struct _zend_function_state {
    zend_function *function;
    void **arguments;
} zend_function_state;

Example usage:

ptr = (zval**)execd_init->function_state.arguments;
ptr1 = *(ptr-2);
ptr3 = *(ptr-1);
ptr2.value.str.val // gives the string value if type is string
ptr4.value.str.val // gives the second argument of type string
0
softwarevamp On
(*(curr_func->common.arg_info + i)).name

gives the name.

void **args = ex->function_state.arguments;
int argc = (int) (zend_uintptr_t) *args;

*(args - (argc - i))

gives the value.