├── EXPERIMENTAL ├── CREDITS ├── config.w32 ├── tests ├── ulopcodes_003.phpt ├── ulopcodes_001.phpt ├── ulopcodes_002.phpt ├── ulopcodes_005.phpt ├── ulopcodes_006.phpt └── ulopcodes_004.phpt ├── config.m4 ├── .gitignore ├── .travis.yml ├── LICENSE ├── php_ulopcodes.h ├── README.md └── ulopcodes.c /EXPERIMENTAL: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /CREDITS: -------------------------------------------------------------------------------- 1 | ulopcodes 2 | Pedro Magalhães 3 | -------------------------------------------------------------------------------- /config.w32: -------------------------------------------------------------------------------- 1 | ARG_ENABLE("ulopcodes", "enable ulopcodes support", "no"); 2 | 3 | if (PHP_ULOPCODES != "no") { 4 | EXTENSION("ulopcodes", "ulopcodes.c", true, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); 5 | } 6 | -------------------------------------------------------------------------------- /tests/ulopcodes_003.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check emitting an ECHO 3 | --INI-- 4 | ulopcodes.enabled = 1 5 | ulopcodes.dump_oparray = 0 6 | --FILE-- 7 | 10 | --EXPECT-- 11 | echo emitted 12 | -------------------------------------------------------------------------------- /tests/ulopcodes_001.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check for ulopcodes presence 3 | --FILE-- 4 | 9 | --EXPECT-- 10 | ulopcodes extension is available 11 | -------------------------------------------------------------------------------- /tests/ulopcodes_002.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check that ulopcodes_emit is available 3 | --FILE-- 4 | 9 | --EXPECT-- 10 | ulopcodes_emit() is available 11 | -------------------------------------------------------------------------------- /config.m4: -------------------------------------------------------------------------------- 1 | PHP_ARG_ENABLE(ulopcodes, whether to enable ulopcodes support, 2 | [ --enable-ulopcodes Enable ulopcodes support]) 3 | 4 | if test "$PHP_ULOPCODES" != "no"; then 5 | PHP_NEW_EXTENSION(ulopcodes, ulopcodes.c, yes,, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1,,yes) 6 | fi 7 | -------------------------------------------------------------------------------- /tests/ulopcodes_005.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check emitting jumps 3 | --INI-- 4 | ulopcodes.enabled = 1 5 | ulopcodes.dump_oparray = 0 6 | --FILE-- 7 | 16 | --EXPECT-- 17 | 0123456789 18 | -------------------------------------------------------------------------------- /tests/ulopcodes_006.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check using a function call as an argument 3 | --INI-- 4 | ulopcodes.enabled = 1 5 | ulopcodes.dump_oparray = 0 6 | --FILE-- 7 | 18 | --EXPECT-- 19 | 20 20 | -------------------------------------------------------------------------------- /tests/ulopcodes_004.phpt: -------------------------------------------------------------------------------- 1 | --TEST-- 2 | Check emitting a function call 3 | --INI-- 4 | ulopcodes.enabled = 1 5 | ulopcodes.dump_oparray = 0 6 | --FILE-- 7 | 19 | --EXPECT-- 20 | Hello world! 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .deps 2 | *.lo 3 | *.la 4 | .libs 5 | acinclude.m4 6 | aclocal.m4 7 | autom4te.cache 8 | build 9 | config.guess 10 | config.h 11 | config.h.in 12 | config.log 13 | config.nice 14 | config.status 15 | config.sub 16 | configure 17 | configure.in 18 | include 19 | install-sh 20 | libtool 21 | ltmain.sh 22 | Makefile 23 | Makefile.fragments 24 | Makefile.global 25 | Makefile.objects 26 | missing 27 | mkinstalldirs 28 | modules 29 | run-tests.php 30 | tests/*/*.diff 31 | tests/*/*.out 32 | tests/*/*.php 33 | tests/*/*.exp 34 | tests/*/*.log 35 | tests/*/*.sh 36 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 7.1 5 | - 7.2 6 | - nightly 7 | 8 | script: 9 | - export CFLAGS="-Wall -Wextra -Wdeclaration-after-statement -Wmissing-field-initializers -Wshadow -Wno-unused-parameter -ggdb3" 10 | - phpize 11 | - ./configure 12 | - make all install 13 | - echo "zend_extension=ulopcodes.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini 14 | - phpenv config-rm xdebug.ini || true 15 | - REPORT_EXIT_STATUS=1 TEST_PHP_EXECUTABLE=~/.phpenv/versions/$(phpenv version-name)/bin/php php run-tests.php -c ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini -q -x --show-diff 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Pedro Magalhães 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /php_ulopcodes.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 Pedro Magalhães 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #ifndef PHP_ULOPCODES_H 24 | #define PHP_ULOPCODES_H 25 | 26 | extern zend_module_entry ulopcodes_module_entry; 27 | #define phpext_ulopcodes_ptr &ulopcodes_module_entry 28 | 29 | #define PHP_ULOPCODES_NAME "ulopcodes" 30 | #define PHP_ULOPCODES_VERSION "0.0.4" 31 | #define PHP_ULOPCODES_AUTHOR "Pedro Magalhães" 32 | #define PHP_ULOPCODES_URL "https://pmmaga.net/ulopcodes" 33 | #define PHP_ULOPCODES_COPYRIGHT "Copyright (c) 2016" 34 | 35 | #ifdef PHP_WIN32 36 | # define PHP_ULOPCODES_API __declspec(dllexport) 37 | #elif defined(__GNUC__) && __GNUC__ >= 4 38 | # define PHP_ULOPCODES_API __attribute__ ((visibility("default"))) 39 | #else 40 | # define PHP_ULOPCODES_API 41 | #endif 42 | 43 | #ifdef ZTS 44 | #include "TSRM.h" 45 | #endif 46 | 47 | ZEND_BEGIN_MODULE_GLOBALS(ulopcodes) 48 | zend_bool enabled; 49 | zend_bool dump_oparray; 50 | ZEND_END_MODULE_GLOBALS(ulopcodes) 51 | 52 | #define ULOP_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(ulopcodes, v) 53 | 54 | #define ULOP_OP1_CONSTANT(op_array, opline_num) \ 55 | (op_array)->literals[(op_array)->opcodes[(opline_num)].op1.constant] 56 | 57 | #define ULOP_OP2_CONSTANT(op_array, opline_num) \ 58 | (op_array)->literals[(op_array)->opcodes[(opline_num)].op2.constant] 59 | 60 | #if defined(ZTS) && defined(COMPILE_DL_ULOPCODES) 61 | ZEND_TSRMLS_CACHE_EXTERN() 62 | #endif 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ulopcodes 2 | 3 | Allows emitting opcodes from PHP userland. 4 | 5 | [![Build Status](https://travis-ci.org/pmmaga/php-ulopcodes.svg?branch=master)](https://travis-ci.org/pmmaga/php-ulopcodes) 6 | 7 | Supports PHP 7.1+ 8 | 9 | ## Usage 10 | 11 | You can use the function `[$result = ]ulopcodes_emit($opcode[, $op1][, $op2])` to emit an opcode into the current oparray. Optionally, you can set the operands and assign the result. 12 | 13 | ### Example 14 | 15 | Here's an Hello World: 16 | ``` 17 | Printed when your run with the ini setting `ulopcodes.dump_oparray = 1` 30 | 31 | ``` 32 | --- Function: getGreeting --- 33 | 0 - Opcode: ZEND_RECV Op1: (8 - 1) Op2: (8 - -1) Ext: 0 Res: (16 - 48) 34 | ... 35 | 5 - Opcode: ZEND_CONCAT Op1: (1 - 2) Op2: (16 - 48) Ext: 0 Res: (4 - 0) 36 | 6 - Opcode: ZEND_ASSIGN Op1: (16 - 64) Op2: (4 - 0) Ext: 0 Res: (8 - 1) 37 | ... 38 | 11 - Opcode: ZEND_CONCAT Op1: (16 - 64) Op2: (1 - 5) Ext: 0 Res: (4 - 2) 39 | 12 - Opcode: ZEND_ASSIGN Op1: (16 - 64) Op2: (4 - 2) Ext: 0 Res: (8 - 3) 40 | ... 41 | 16 - Opcode: ZEND_RETURN Op1: (16 - 64) Op2: (8 - 0) Ext: 0 Res: (8 - 4) 42 | 17 - Opcode: ZEND_RETURN Op1: (1 - 8) Op2: (8 - 0) Ext: -1 Res: (8 - 0) 43 | --- End function --- 44 | --- Function: (no name) --- 45 | ... 46 | 4 - Opcode: ZEND_INIT_FCALL Op1: (8 - 160) Op2: (1 - 2) Ext: 1 Res: (8 - 0) 47 | 5 - Opcode: ZEND_SEND_VAL Op1: (1 - 3) Op2: (8 - 1) Ext: 0 Res: (8 - 48) 48 | 6 - Opcode: ZEND_DO_UCALL Op1: (8 - 0) Op2: (8 - 0) Ext: 0 Res: (4 - 0) 49 | 7 - Opcode: ZEND_NOP Op1: (8 - 0) Op2: (8 - 0) Ext: 0 Res: (8 - 0) 50 | 8 - Opcode: ZEND_ASSIGN Op1: (16 - 48) Op2: (4 - 0) Ext: 0 Res: (8 - 1) 51 | ... 52 | 12 - Opcode: ZEND_ECHO Op1: (16 - 48) Op2: (8 - 0) Ext: 0 Res: (8 - 2) 53 | 13 - Opcode: ZEND_RETURN Op1: (1 - 6) Op2: (8 - 0) Ext: -1 Res: (8 - 0) 54 | --- End function --- 55 | ``` 56 | And produce the expect output of the `ZEND_ECHO` call: 57 | ``` 58 | Hello world! 59 | ``` 60 | ## Installation 61 | 62 | As it is a Zend Extension, it must be built as a `shared` extension. 63 | Remember to add the `zend_extension` entry to your ini file. 64 | 65 | ## Configuration 66 | 67 | The following settings are supported: 68 | ``` 69 | ulopcodes.enabled = false ; Enable to activate ulopcodes_emit 70 | ulopcodes.dump_oparray = false ; Enable to print a dump of the oparrays after modification 71 | ``` 72 | -------------------------------------------------------------------------------- /ulopcodes.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2016 Pedro Magalhães 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. 21 | */ 22 | 23 | #ifdef HAVE_CONFIG_H 24 | #include "config.h" 25 | #endif 26 | 27 | #include "php.h" 28 | #include "php_ini.h" 29 | #include "ext/standard/info.h" 30 | #include "Zend/zend.h" 31 | #include "Zend/zend_types.h" 32 | #include "Zend/zend_extensions.h" 33 | #include "Zend/zend_vm_opcodes.h" 34 | #include "php_ulopcodes.h" 35 | 36 | ZEND_DECLARE_MODULE_GLOBALS(ulopcodes) 37 | 38 | /* {{{ PHP_INI 39 | */ 40 | PHP_INI_BEGIN() 41 | STD_PHP_INI_ENTRY("ulopcodes.enabled", "0", PHP_INI_ALL, OnUpdateBool, enabled, zend_ulopcodes_globals, ulopcodes_globals) 42 | STD_PHP_INI_ENTRY("ulopcodes.dump_oparray", "0", PHP_INI_ALL, OnUpdateBool, dump_oparray, zend_ulopcodes_globals, ulopcodes_globals) 43 | PHP_INI_END() 44 | /* }}} */ 45 | 46 | /* {{{ ulopcodes_init_globals 47 | */ 48 | static void ulopcodes_init_globals(zend_ulopcodes_globals *ulopcodes_globals) 49 | { 50 | ulopcodes_globals->enabled = 0; 51 | ulopcodes_globals->dump_oparray = 0; 52 | } 53 | /* }}} */ 54 | 55 | /* {{{ proto string confirm_ulopcodes_compiled(string arg) 56 | */ 57 | PHP_FUNCTION(ulopcodes_emit) 58 | { 59 | // Dummy function to be found in the oparray 60 | } 61 | /* }}} */ 62 | 63 | /* {{{ PHP_MINIT_FUNCTION 64 | */ 65 | PHP_MINIT_FUNCTION(ulopcodes) 66 | { 67 | unsigned int i; 68 | /* 69 | Register the opcodes as constants for the user 70 | */ 71 | for (i = 0; i <= ZEND_VM_LAST_OPCODE; i++) { 72 | const char *name = zend_get_opcode_name(i); 73 | if (name) { 74 | zend_register_long_constant(name, strlen(name), i, CONST_CS|CONST_PERSISTENT, module_number); 75 | } 76 | } 77 | 78 | ZEND_INIT_MODULE_GLOBALS(ulopcodes, ulopcodes_init_globals, NULL); 79 | REGISTER_INI_ENTRIES(); 80 | 81 | return SUCCESS; 82 | } 83 | /* }}} */ 84 | 85 | /* {{{ PHP_MSHUTDOWN_FUNCTION 86 | */ 87 | PHP_MSHUTDOWN_FUNCTION(ulopcodes) 88 | { 89 | UNREGISTER_INI_ENTRIES(); 90 | 91 | return SUCCESS; 92 | } 93 | /* }}} */ 94 | 95 | /* {{{ PHP_MINFO_FUNCTION 96 | */ 97 | PHP_MINFO_FUNCTION(ulopcodes) 98 | { 99 | php_info_print_table_start(); 100 | php_info_print_table_header(2, "ulopcodes support", "enabled"); 101 | php_info_print_table_end(); 102 | 103 | DISPLAY_INI_ENTRIES(); 104 | } 105 | /* }}} */ 106 | 107 | /* {{{ ulopcodes_functions[] 108 | * 109 | * Every user visible function must have an entry in ulopcodes_functions[]. 110 | */ 111 | const zend_function_entry ulopcodes_functions[] = { 112 | PHP_FE(ulopcodes_emit, NULL) 113 | PHP_FE_END /* Must be the last line in ulopcodes_functions[] */ 114 | }; 115 | /* }}} */ 116 | 117 | /* {{{ ulopcodes_module_entry 118 | */ 119 | zend_module_entry ulopcodes_module_entry = { 120 | STANDARD_MODULE_HEADER, 121 | PHP_ULOPCODES_NAME, 122 | ulopcodes_functions, 123 | PHP_MINIT(ulopcodes), 124 | PHP_MSHUTDOWN(ulopcodes), 125 | NULL, 126 | NULL, 127 | PHP_MINFO(ulopcodes), 128 | PHP_ULOPCODES_VERSION, 129 | STANDARD_MODULE_PROPERTIES 130 | }; 131 | /* }}} */ 132 | 133 | /* {{{ ulop_dump_oparray_header 134 | * 135 | * Prints information about an oparray. 136 | */ 137 | static void ulop_dump_oparray_header(zend_op_array *op_array) { 138 | int k; 139 | 140 | if(op_array->function_name) { 141 | php_printf("--- Function: %s ---\n", op_array->function_name->val); 142 | } else { 143 | php_printf("--- Function: (no name) ---\n"); 144 | } 145 | php_printf("Literals:\n"); 146 | for (k = 0; k < op_array->last_literal; k++) { 147 | if (Z_TYPE(op_array->literals[k]) == IS_STRING) { 148 | php_printf("%d - %s\n", k, Z_STRVAL(op_array->literals[k])); 149 | } else { 150 | php_printf("%d - %d\n", k, Z_LVAL(op_array->literals[k])); 151 | } 152 | } 153 | php_printf("------\n"); 154 | } 155 | /* }}} */ 156 | 157 | /* {{{ ulop_dump_opline 158 | * 159 | * Prints information about an opline. 160 | */ 161 | static void ulop_dump_opline(zend_op opline, unsigned int i) { 162 | if (opline.opcode < ZEND_VM_LAST_OPCODE) { 163 | php_printf("%d - Opcode: %s Op1: (%d - %d) Op2: (%d - %d) Ext: %d Res: (%d - %d)\n", 164 | i, 165 | zend_get_opcode_name(opline.opcode), 166 | opline.op1_type, 167 | opline.op1.num, 168 | opline.op2_type, 169 | opline.op2.num, 170 | opline.extended_value, 171 | opline.result_type, 172 | opline.result.num 173 | ); 174 | } else { 175 | php_printf("Opcode: UNKNOWN\n"); 176 | } 177 | } 178 | /* }}} */ 179 | 180 | /* {{{ ulop_dump_oparray_footer 181 | * 182 | * Prints the footer for an oparray. 183 | */ 184 | static void ulop_dump_oparray_footer(zend_op_array *op_array) { 185 | php_printf("--- End function ---\n"); 186 | } 187 | /* }}} */ 188 | 189 | /* {{{ ulop_get_user_opcode 190 | * 191 | * Gets the user's opcode from a SEND_VAL following the call to the dummy function 192 | */ 193 | static unsigned int ulop_get_user_opcode(zend_op_array *op_array, int i) { 194 | if (op_array->opcodes[i].opcode == ZEND_SEND_VAL && 195 | Z_TYPE(ULOP_OP1_CONSTANT(op_array, i)) == IS_LONG && 196 | Z_LVAL(ULOP_OP1_CONSTANT(op_array, i)) < ZEND_VM_LAST_OPCODE 197 | ) { 198 | return Z_LVAL(ULOP_OP1_CONSTANT(op_array, i)); 199 | } else if (op_array->opcodes[i].opcode == ZEND_SEND_VAR) { 200 | php_error(E_ERROR, "Please use constants for the opcode passed to ulopcodes_emit."); 201 | } else { 202 | php_error(E_ERROR, "Unknown opcode passed to ulopcodes_emit."); 203 | } 204 | 205 | return ZEND_NOP; 206 | } 207 | /* }}} */ 208 | 209 | /* {{{ ulop_get_user_op_type 210 | * 211 | * Gets the user's op type 212 | */ 213 | static unsigned int ulop_get_user_op_type(zend_op_array *op_array, int i, unsigned int dest_op_flags, unsigned int source_type) { 214 | if (dest_op_flags & ZEND_VM_OP_JMP_ADDR) { 215 | return IS_UNUSED; 216 | } 217 | if (source_type != IS_UNUSED) { 218 | if (source_type == IS_CONST && 219 | Z_TYPE(ULOP_OP1_CONSTANT(op_array, i)) == IS_NULL 220 | ) { 221 | return IS_UNUSED; 222 | } 223 | } 224 | 225 | return source_type; 226 | } 227 | /* }}} */ 228 | 229 | /* {{{ ulop_get_user_op_val 230 | * 231 | * Gets the user's op value 232 | */ 233 | static znode_op ulop_get_user_op_val(zend_op_array *op_array, int i, unsigned int dest_op_flags, unsigned int source_type, znode_op source_node) { 234 | if (dest_op_flags & ZEND_VM_OP_JMP_ADDR) { 235 | source_node.num = Z_LVAL(ULOP_OP1_CONSTANT(op_array, i)); 236 | } else if (Z_TYPE(ULOP_OP1_CONSTANT(op_array, i)) == IS_NULL) { 237 | source_node.num = 0; 238 | } 239 | return source_node; 240 | } 241 | /* }}} */ 242 | 243 | /* {{{ ulop_get_user_ext_val 244 | * 245 | * Gets the user's extended value 246 | */ 247 | static unsigned int ulop_get_user_ext_val(zend_op_array *op_array, int i) { 248 | if (op_array->opcodes[i].op1_type == IS_CONST && 249 | Z_TYPE(ULOP_OP1_CONSTANT(op_array, i)) == IS_LONG 250 | ) { 251 | return Z_LVAL(ULOP_OP1_CONSTANT(op_array, i)); 252 | } 253 | php_error(E_ERROR, "Please use a number for the extended_value passed to ulopcodes_emit."); 254 | return 0; 255 | } 256 | /* }}} */ 257 | 258 | ZEND_DLEXPORT int ulop_startup(zend_extension *extension) 259 | { 260 | return zend_startup_module(&ulopcodes_module_entry); 261 | } 262 | 263 | ZEND_DLEXPORT void ulop_oparray_h(zend_op_array *op_array) 264 | { 265 | ZEND_TSRMLS_CACHE_UPDATE(); 266 | 267 | if (ULOP_G(enabled)) { 268 | unsigned int i; 269 | 270 | if (ULOP_G(dump_oparray)) { 271 | ulop_dump_oparray_header(op_array); 272 | } 273 | 274 | for (i = 0; i < op_array->last; i++) { 275 | /* 276 | If we find a call to the dummy function on the opcodes 277 | */ 278 | if (op_array->opcodes[i].opcode == ZEND_INIT_FCALL && 279 | op_array->opcodes[i].op2_type == IS_CONST && 280 | Z_TYPE(ULOP_OP2_CONSTANT(op_array, i)) == IS_STRING && 281 | Z_STRLEN(ULOP_OP2_CONSTANT(op_array, i)) == strlen("ulopcodes_emit") && 282 | strcmp(Z_STRVAL(ULOP_OP2_CONSTANT(op_array, i)), "ulopcodes_emit") == 0 //&& false 283 | ) { 284 | zend_op new_op; 285 | MAKE_NOP(&new_op); 286 | new_op.extended_value = 0; 287 | 288 | unsigned int j = 0; 289 | unsigned int found = 0; 290 | unsigned int level = 0; 291 | 292 | unsigned int op_flags; 293 | 294 | /* 295 | Clear the dummy function and get operands from any SEND_VAL|SEND_VAR calls that follow 296 | */ 297 | MAKE_NOP(&op_array->opcodes[i]); 298 | j = i + 1; 299 | while (((op_array->opcodes[j].opcode != ZEND_DO_ICALL) && (j < op_array->last - 1)) || level != 0) { 300 | if (level == 0 && (op_array->opcodes[j].opcode == ZEND_SEND_VAL || op_array->opcodes[j].opcode == ZEND_SEND_VAR)) { 301 | if (found == 0) { 302 | /* 303 | Get the user's opcode 304 | */ 305 | new_op.opcode = ulop_get_user_opcode(op_array, j); 306 | MAKE_NOP(&op_array->opcodes[j]); 307 | } else if (found == 1) { 308 | /* 309 | Get the first op 310 | */ 311 | op_flags = ZEND_VM_OP1_FLAGS(zend_get_opcode_flags(new_op.opcode)); 312 | new_op.op1_type = ulop_get_user_op_type(op_array, j, op_flags, op_array->opcodes[j].op1_type); 313 | new_op.op1 = ulop_get_user_op_val(op_array, j, op_flags, op_array->opcodes[j].op1_type, op_array->opcodes[j].op1); 314 | MAKE_NOP(&op_array->opcodes[j]); 315 | } else if (found == 2) { 316 | /* 317 | Get the second op 318 | */ 319 | op_flags = ZEND_VM_OP2_FLAGS(zend_get_opcode_flags(new_op.opcode)); 320 | new_op.op2_type = ulop_get_user_op_type(op_array, j, op_flags, op_array->opcodes[j].op1_type); 321 | new_op.op2 = ulop_get_user_op_val(op_array, j, op_flags, op_array->opcodes[j].op1_type, op_array->opcodes[j].op1); 322 | MAKE_NOP(&op_array->opcodes[j]); 323 | } else if (found == 3) { 324 | /* 325 | Get the extended value 326 | */ 327 | new_op.extended_value = ulop_get_user_ext_val(op_array, j); 328 | MAKE_NOP(&op_array->opcodes[j]); 329 | } 330 | found++; 331 | } 332 | /* 333 | Don't capture VAL|VAR sent to other functions 334 | */ 335 | if (op_array->opcodes[j].opcode == ZEND_INIT_FCALL || 336 | op_array->opcodes[j].opcode == ZEND_INIT_FCALL_BY_NAME || 337 | op_array->opcodes[j].opcode == ZEND_INIT_NS_FCALL_BY_NAME || 338 | op_array->opcodes[j].opcode == ZEND_INIT_METHOD_CALL || 339 | op_array->opcodes[j].opcode == ZEND_INIT_STATIC_METHOD_CALL || 340 | op_array->opcodes[j].opcode == ZEND_INIT_USER_CALL || 341 | op_array->opcodes[j].opcode == ZEND_INIT_DYNAMIC_CALL 342 | ){ 343 | level++; 344 | } 345 | if (op_array->opcodes[j].opcode == ZEND_DO_FCALL || 346 | op_array->opcodes[j].opcode == ZEND_DO_ICALL || 347 | op_array->opcodes[j].opcode == ZEND_DO_UCALL || 348 | op_array->opcodes[j].opcode == ZEND_DO_FCALL_BY_NAME 349 | ){ 350 | level--; 351 | } 352 | j++; 353 | } 354 | 355 | /* 356 | Set the user's opcode 357 | */ 358 | if (found > 0) { 359 | op_array->opcodes[j].opcode = new_op.opcode; 360 | if (found > 1) { 361 | op_array->opcodes[j].op1_type = new_op.op1_type; 362 | op_array->opcodes[j].op1 = new_op.op1; 363 | if (found > 2) { 364 | op_array->opcodes[j].op2_type = new_op.op2_type; 365 | op_array->opcodes[j].op2 = new_op.op2; 366 | if (found > 3) { 367 | op_array->opcodes[j].extended_value = new_op.extended_value; 368 | } 369 | } 370 | } 371 | } 372 | } 373 | 374 | if (ULOP_G(dump_oparray)) { 375 | ulop_dump_opline(op_array->opcodes[i], i); 376 | } 377 | } 378 | 379 | if (ULOP_G(dump_oparray)) { 380 | ulop_dump_oparray_footer(op_array); 381 | } 382 | } 383 | } 384 | 385 | #ifndef ZEND_EXT_API 386 | #define ZEND_EXT_API ZEND_DLEXPORT 387 | #endif 388 | ZEND_EXTENSION(); 389 | 390 | ZEND_DLEXPORT zend_extension zend_extension_entry = { 391 | PHP_ULOPCODES_NAME, 392 | PHP_ULOPCODES_VERSION, 393 | PHP_ULOPCODES_AUTHOR, 394 | PHP_ULOPCODES_URL, 395 | PHP_ULOPCODES_COPYRIGHT, 396 | ulop_startup, /* startup_func_t */ 397 | NULL, /* shutdown_func_t */ 398 | NULL, /* activate_func_t */ 399 | NULL, /* deactivate_func_t */ 400 | NULL, /* message_handler_func_t */ 401 | ulop_oparray_h, /* op_array_handler_func_t */ 402 | NULL, /* statement_handler_func_t */ 403 | NULL, /* fcall_begin_handler_func_t */ 404 | NULL, /* fcall_end_handler_func_t */ 405 | NULL, /* op_array_ctor_func_t */ 406 | NULL, /* op_array_dtor_func_t */ 407 | STANDARD_ZEND_EXTENSION_PROPERTIES 408 | }; 409 | 410 | #ifdef COMPILE_DL_ULOPCODES 411 | #ifdef ZTS 412 | ZEND_TSRMLS_CACHE_DEFINE() 413 | #endif 414 | ZEND_GET_MODULE(ulopcodes) 415 | #endif 416 | --------------------------------------------------------------------------------