source: trunk/xcache.c

Last change on this file was 1565, checked in by moo, 7 weeks ago

kill some warnings

  • Property svn:eol-style set to native
File size: 29.8 KB
RevLine 
[1]1/* {{{ macros */
2#include <stdlib.h>
3#include <stdio.h>
4#include <string.h>
5
6#include <signal.h>
7
8#include "xcache.h"
[993]9
10#ifdef HAVE_XCACHE_OPTIMIZER
[1003]11#   include "mod_optimizer/xc_optimizer.h"
[993]12#endif
[1040]13#ifdef HAVE_XCACHE_CACHER
14#   include "mod_cacher/xc_cacher.h"
15#endif
[993]16#ifdef HAVE_XCACHE_COVERAGER
[1003]17#   include "mod_coverager/xc_coverager.h"
[993]18#endif
19#ifdef HAVE_XCACHE_DISASSEMBLER
[1003]20#   include "mod_disassembler/xc_disassembler.h"
[993]21#endif
22
[1]23#include "xcache_globals.h"
[1026]24#include "xcache/xc_extension.h"
25#include "xcache/xc_ini.h"
[987]26#include "xcache/xc_const_string.h"
27#include "xcache/xc_opcode_spec.h"
28#include "xcache/xc_utils.h"
[1551]29#include "util/xc_vector.h"
[1]30
[1026]31#include "php.h"
32#include "ext/standard/info.h"
33#include "ext/standard/php_string.h"
[1131]34#include "SAPI.h"
[1]35/* }}} */
36
37/* {{{ globals */
38static char *xc_coredump_dir = NULL;
[1230]39#ifdef ZEND_WIN32
40static zend_ulong xc_coredump_type = 0;
41#endif
[979]42static zend_bool xc_disable_on_crash = 0;
[1]43
[403]44static zend_compile_file_t *old_compile_file = NULL;
[1]45
[1040]46zend_bool xc_test = 0;
[1]47
[982]48ZEND_DECLARE_MODULE_GLOBALS(xcache)
[854]49
[1]50/* }}} */
51
[405]52static zend_op_array *xc_check_initial_compile_file(zend_file_handle *h, int type TSRMLS_DC) /* {{{ */
53{
54    XG(initial_compile_file_called) = 1;
[1040]55    return old_compile_file(h, type TSRMLS_CC);
[405]56}
57/* }}} */
[937]58
[1251]59/* devel helper function */
60#if 0
61static void xc_list_extensions() /* {{{ */
62{
63    zend_llist_element *element;
64    zend_extension *ext;
65    fprintf(stderr, "extensions:\n");
66    for (element = zend_extensions.head; element; element = element->next) {
67        ext = (zend_extension *) element->data;
68        fprintf(stderr, " - %s\n", ext->name);
69    }
70}
71/* }}} */
72#endif
73
[1]74/* module helper function */
75static int xc_init_constant(int module_number TSRMLS_DC) /* {{{ */
76{
[11]77    typedef struct {
[1]78        const char *prefix;
[20]79        zend_uchar (*getsize)();
[1]80        const char *(*get)(zend_uchar i);
[1133]81    } xc_nameinfo_t;
82    xc_nameinfo_t nameinfos[] = {
[1]83        { "",        xc_get_op_type_count,   xc_get_op_type   },
84        { "",        xc_get_data_type_count, xc_get_data_type },
85        { "",        xc_get_opcode_count,    xc_get_opcode    },
86        { "OPSPEC_", xc_get_op_spec_count,   xc_get_op_spec   },
87        { NULL, NULL, NULL }
88    };
89    int undefdone = 0;
[1134]90    xc_nameinfo_t *p;
[1]91
92    for (p = nameinfos; p->getsize; p ++) {
[1133]93        zend_uchar i, count;
94        char const_name[96];
95        int const_name_len;
96
[20]97        count = p->getsize();
98        for (i = 0; i < count; i ++) {
[1]99            const char *name = p->get(i);
100            if (!name) continue;
101            if (strcmp(name, "UNDEF") == 0) {
102                if (undefdone) continue;
103                undefdone = 1;
104            }
105            const_name_len = snprintf(const_name, sizeof(const_name), "XC_%s%s", p->prefix, name);
106            zend_register_long_constant(const_name, const_name_len+1, i, CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
107        }
108    }
109
[1313]110    zend_register_long_constant(XCACHE_STRS("XC_SIZEOF_TEMP_VARIABLE"), sizeof(temp_variable), CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
111    zend_register_stringl_constant(XCACHE_STRS("XCACHE_VERSION"), XCACHE_STRL(XCACHE_VERSION), CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
112    zend_register_stringl_constant(XCACHE_STRS("XCACHE_MODULES"), XCACHE_STRL(XCACHE_MODULES), CONST_CS | CONST_PERSISTENT, module_number TSRMLS_CC);
[1]113    return 0;
114}
115/* }}} */
[92]116/* {{{ PHP_GINIT_FUNCTION(xcache) */
[1346]117#ifdef __GNUC__
[1321]118#pragma GCC push_options
119#pragma GCC diagnostic ignored "-Wshadow"
[1346]120#endif
[1321]121
[92]122#ifdef PHP_GINIT_FUNCTION
[1050]123static PHP_GINIT_FUNCTION(xcache)
[92]124#else
[1321]125static void xc_init_globals(zend_xcache_globals* xcache_globals TSRMLS_DC)
[92]126#endif
[1]127{
[1346]128#ifdef __GNUC__
[1321]129#pragma GCC pop_options
[1346]130#endif
[1321]131
[92]132    memset(xcache_globals, 0, sizeof(zend_xcache_globals));
[429]133
[588]134#ifdef HAVE_XCACHE_CONSTANT
[640]135    zend_hash_init_ex(&xcache_globals->internal_constant_table, 1, NULL, (dtor_func_t) xc_zend_constant_dtor, 1, 0);
[588]136#endif
[429]137    zend_hash_init_ex(&xcache_globals->internal_function_table, 1, NULL, NULL, 1, 0);
138    zend_hash_init_ex(&xcache_globals->internal_class_table,    1, NULL, NULL, 1, 0);
[1]139}
140/* }}} */
[92]141/* {{{ PHP_GSHUTDOWN_FUNCTION(xcache) */
142static
143#ifdef PHP_GSHUTDOWN_FUNCTION
144PHP_GSHUTDOWN_FUNCTION(xcache)
145#else
146void xc_shutdown_globals(zend_xcache_globals* xcache_globals TSRMLS_DC)
147#endif
[1]148{
[917]149    size_t i;
[1]150
[92]151    if (xcache_globals->php_holds != NULL) {
[1040]152        for (i = 0; i < xcache_globals->php_holds_size; i ++) {
[1551]153            xc_vector_destroy(&xcache_globals->php_holds[i]);
[1]154        }
[92]155        free(xcache_globals->php_holds);
156        xcache_globals->php_holds = NULL;
[1040]157        xcache_globals->php_holds_size = 0;
[1]158    }
159
[92]160    if (xcache_globals->var_holds != NULL) {
[1040]161        for (i = 0; i < xcache_globals->var_holds_size; i ++) {
[1551]162            xc_vector_destroy(&xcache_globals->var_holds[i]);
[1]163        }
[92]164        free(xcache_globals->var_holds);
165        xcache_globals->var_holds = NULL;
[1040]166        xcache_globals->var_holds_size = 0;
[1]167    }
[344]168
[438]169    if (xcache_globals->internal_table_copied) {
[588]170#ifdef HAVE_XCACHE_CONSTANT
171        zend_hash_destroy(&xcache_globals->internal_constant_table);
172#endif
[435]173        zend_hash_destroy(&xcache_globals->internal_function_table);
174        zend_hash_destroy(&xcache_globals->internal_class_table);
175    }
[1]176}
177/* }}} */
178
[1477]179#ifdef HAVE_XCACHE_DPRINT
180/* {{{ proto bool  xcache_dprint(mixed value)
181   Prints internal struct of an zval (debug only) */
182#include "xc_processor.h"
[1476]183
184#ifdef ZEND_BEGIN_ARG_INFO_EX
[1477]185ZEND_BEGIN_ARG_INFO_EX(arginfo_xcache_dprint, 0, 0, 1)
186    ZEND_ARG_INFO(0, value)
[1476]187ZEND_END_ARG_INFO()
188#else
[1477]189static unsigned char arginfo_xcache_dprint[] = { 1, BYREF_NONE };
[1476]190#endif
191
[532]192PHP_FUNCTION(xcache_dprint)
193{
194    zval *value;
195
196    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
197        return;
198    }
199    xc_dprint_zval(value, 0 TSRMLS_CC);
200}
201/* }}} */
202#endif
[1477]203#ifdef HAVE_XCACHE_ASSEMBLER
[9]204/* {{{ proto string xcache_asm(string filename)
205 */
[1]206PHP_FUNCTION(xcache_asm)
207{
208}
[1477]209/* }}} */
[1]210#endif
[1477]211#ifdef HAVE_XCACHE_ENCODER
[9]212/* {{{ proto string xcache_encode(string filename)
213   Encode php file into XCache opcode encoded format */
[1]214PHP_FUNCTION(xcache_encode)
215{
216}
[1477]217/* }}} */
[1]218#endif
[1477]219#ifdef HAVE_XCACHE_DECODER
[9]220/* {{{ proto bool xcache_decode_file(string filename)
221   Decode(load) opcode from XCache encoded format file */
222PHP_FUNCTION(xcache_decode_file)
[1]223{
224}
225/* }}} */
[9]226/* {{{ proto bool xcache_decode_string(string data)
227   Decode(load) opcode from XCache encoded format data */
228PHP_FUNCTION(xcache_decode_string)
229{
230}
[1477]231/* }}} */
[9]232#endif
[1]233/* {{{ xc_call_getter */
234typedef const char *(xc_name_getter_t)(zend_uchar type);
235static void xc_call_getter(xc_name_getter_t getter, int count, INTERNAL_FUNCTION_PARAMETERS)
236{
237    long spec;
238    const char *name;
239
240    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &spec) == FAILURE) {
241        return;
242    }
243    if (spec >= 0 && spec < count) {
[11]244        name = getter((zend_uchar) spec);
[1]245        if (name) {
246            /* RETURN_STRING */
[1201]247            int len = (int) strlen(name);
[1]248            return_value->value.str.len = len;
249            return_value->value.str.val = estrndup(name, len);
250            return_value->type = IS_STRING; 
251            return;
252        }
253    }
254    RETURN_NULL();
255}
256/* }}} */
257/* {{{ proto string xcache_get_op_type(int op_type) */
[1477]258#ifdef ZEND_BEGIN_ARG_INFO_EX
259ZEND_BEGIN_ARG_INFO_EX(arginfo_xcache_get_op_type, 0, 0, 1)
260    ZEND_ARG_INFO(0, op_type)
261ZEND_END_ARG_INFO()
262#else
263static unsigned char arginfo_xcache_get_op_type[] = { 1, BYREF_NONE };
264#endif
265
[1]266PHP_FUNCTION(xcache_get_op_type)
267{
268    xc_call_getter(xc_get_op_type, xc_get_op_type_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
269}
270/* }}} */
271/* {{{ proto string xcache_get_data_type(int type) */
[1477]272#ifdef ZEND_BEGIN_ARG_INFO_EX
273ZEND_BEGIN_ARG_INFO_EX(arginfo_xcache_get_data_type, 0, 0, 1)
274    ZEND_ARG_INFO(0, type)
275ZEND_END_ARG_INFO()
276#else
277static unsigned char arginfo_xcache_get_data_type[] = { 1, BYREF_NONE };
278#endif
279
[1]280PHP_FUNCTION(xcache_get_data_type)
281{
282    xc_call_getter(xc_get_data_type, xc_get_data_type_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
283}
284/* }}} */
285/* {{{ proto string xcache_get_opcode(int opcode) */
[1477]286#ifdef ZEND_BEGIN_ARG_INFO_EX
287ZEND_BEGIN_ARG_INFO_EX(arginfo_xcache_get_opcode, 0, 0, 1)
288    ZEND_ARG_INFO(0, opcode)
289ZEND_END_ARG_INFO()
290#else
291static unsigned char arginfo_xcache_get_opcode[] = { 1, BYREF_NONE };
292#endif
293
[1]294PHP_FUNCTION(xcache_get_opcode)
295{
296    xc_call_getter(xc_get_opcode, xc_get_opcode_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
297}
298/* }}} */
299/* {{{ proto string xcache_get_op_spec(int op_type) */
[1477]300#ifdef ZEND_BEGIN_ARG_INFO_EX
301ZEND_BEGIN_ARG_INFO_EX(arginfo_xcache_get_op_spec, 0, 0, 1)
302    ZEND_ARG_INFO(0, op_type)
303ZEND_END_ARG_INFO()
304#else
305static unsigned char arginfo_xcache_get_op_spec[] = { 1, BYREF_NONE };
306#endif
307
[1]308PHP_FUNCTION(xcache_get_op_spec)
309{
310    xc_call_getter(xc_get_op_spec, xc_get_op_spec_count(), INTERNAL_FUNCTION_PARAM_PASSTHRU);
311}
312/* }}} */
313/* {{{ proto string xcache_get_opcode_spec(int opcode) */
[1477]314#ifdef ZEND_BEGIN_ARG_INFO_EX
315ZEND_BEGIN_ARG_INFO_EX(arginfo_xcache_get_opcode_spec, 0, 0, 1)
316    ZEND_ARG_INFO(0, opcode)
317ZEND_END_ARG_INFO()
318#else
319static unsigned char arginfo_xcache_get_opcode_spec[] = { 1, BYREF_NONE };
320#endif
321
[1]322PHP_FUNCTION(xcache_get_opcode_spec)
323{
324    long spec;
325    const xc_opcode_spec_t *opspec;
326
327    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &spec) == FAILURE) {
328        return;
329    }
[17]330    if ((zend_uchar) spec <= xc_get_opcode_spec_count()) {
[11]331        opspec = xc_get_opcode_spec((zend_uchar) spec);
[1]332        if (opspec) {
333            array_init(return_value);
[1313]334            add_assoc_long_ex(return_value, XCACHE_STRS("ext"), opspec->ext);
335            add_assoc_long_ex(return_value, XCACHE_STRS("op1"), opspec->op1);
336            add_assoc_long_ex(return_value, XCACHE_STRS("op2"), opspec->op2);
337            add_assoc_long_ex(return_value, XCACHE_STRS("res"), opspec->res);
[1]338            return;
339        }
340    }
341    RETURN_NULL();
342}
343/* }}} */
[781]344/* {{{ proto mixed xcache_get_special_value(zval value)
345   XCache internal use only: For decompiler to get static value with type fixed */
[1477]346#ifdef ZEND_BEGIN_ARG_INFO_EX
347ZEND_BEGIN_ARG_INFO_EX(arginfo_xcache_get_special_value, 0, 0, 1)
348    ZEND_ARG_INFO(0, value)
349ZEND_END_ARG_INFO()
350#else
351static unsigned char arginfo_xcache_get_special_value[] = { 1, BYREF_NONE };
352#endif
353
[1]354PHP_FUNCTION(xcache_get_special_value)
355{
356    zval *value;
[1523]357    zval value_copied;
[1]358
359    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
360        return;
361    }
[1523]362    value_copied = *value;
363    value = &value_copied;
[1]364
[713]365    switch ((Z_TYPE_P(value) & IS_CONSTANT_TYPE_MASK)) {
366    case IS_CONSTANT:
[1523]367        value->type = UNISW(IS_STRING, UG(unicode) ? IS_UNICODE : IS_STRING);
368        RETURN_ZVAL(value, 1, 0);
[713]369        break;
[1]370
[1486]371#ifdef IS_CONSTANT_ARRAY
[713]372    case IS_CONSTANT_ARRAY:
[1523]373        value->type = IS_ARRAY;
374        RETURN_ZVAL(value, 1, 0);
[713]375        break;
[1486]376#endif
[713]377
[1486]378#ifdef IS_CONSTANT_AST
379    case IS_CONSTANT_AST:
380        RETURN_NULL();
381        break;
382#endif
383
[713]384    default:
[1374]385        if ((Z_TYPE_P(value) & ~IS_CONSTANT_TYPE_MASK)) {
[1523]386            value->type &= IS_CONSTANT_TYPE_MASK;
387            RETURN_ZVAL(value, 1, 0);
[1374]388        }
389        else {
390            RETURN_NULL();
391        }
[1]392    }
393}
394/* }}} */
[781]395/* {{{ proto int xcache_get_type(zval value)
396   XCache internal use only for disassembler to get variable type in engine level */
[1477]397#ifdef ZEND_BEGIN_ARG_INFO_EX
398ZEND_BEGIN_ARG_INFO_EX(arginfo_xcache_get_type, 0, 0, 1)
399    ZEND_ARG_INFO(0, value)
400ZEND_END_ARG_INFO()
401#else
402static unsigned char arginfo_xcache_get_type[] = { 1, BYREF_NONE };
403#endif
404
[781]405PHP_FUNCTION(xcache_get_type)
406{
407    zval *value;
408
409    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
410        return;
411    }
412
413    RETURN_LONG(Z_TYPE_P(value));
414}
415/* }}} */
[1477]416/* {{{ proto string xcache_coredump() */
417#ifdef ZEND_BEGIN_ARG_INFO_EX
418ZEND_BEGIN_ARG_INFO_EX(arginfo_xcache_coredump, 0, 0, 0)
419ZEND_END_ARG_INFO()
420#else
421static unsigned char arginfo_xcache_coredump[] = { 1, BYREF_NONE };
422#endif
423
[1]424PHP_FUNCTION(xcache_coredump)
425{
[9]426    if (xc_test) {
[1181]427        char *null_ptr = NULL;
428        *null_ptr = 0;
[9]429        raise(SIGSEGV);
430    }
431    else {
432        php_error_docref(NULL TSRMLS_CC, E_WARNING, "xcache.test must be enabled to test xcache_coredump()");
433    }
[1]434}
435/* }}} */
436/* {{{ proto string xcache_is_autoglobal(string name) */
[1477]437#ifdef ZEND_BEGIN_ARG_INFO_EX
438ZEND_BEGIN_ARG_INFO_EX(arginfo_xcache_is_autoglobal, 0, 0, 1)
439    ZEND_ARG_INFO(0, name)
440ZEND_END_ARG_INFO()
441#else
442static unsigned char arginfo_xcache_is_autoglobal[] = { 1, BYREF_NONE };
443#endif
444
[1]445PHP_FUNCTION(xcache_is_autoglobal)
446{
[860]447    zval *name;
[1]448
[862]449    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
[1]450        return;
451    }
452
[862]453#ifdef IS_UNICODE
454    convert_to_unicode(name);
455#else
456    convert_to_string(name);
457#endif
458
[860]459    RETURN_BOOL(zend_u_hash_exists(CG(auto_globals), UG(unicode), Z_STRVAL_P(name), Z_STRLEN_P(name) + 1));
[1]460}
461/* }}} */
[1477]462/* {{{ proto int xcache_get_refcount(mixed &variable)
463   XCache internal uses only: Get reference count of referenced variable */
464#ifdef ZEND_BEGIN_ARG_INFO_EX
465ZEND_BEGIN_ARG_INFO_EX(arginfo_xcache_get_refcount, 0, 0, 1)
466    ZEND_ARG_INFO(1, variable)
467ZEND_END_ARG_INFO()
468#else
469static unsigned char arginfo_xcache_get_refcount[] = { 1, BYREF_FORCE };
470#endif
471
472PHP_FUNCTION(xcache_get_refcount)
473{
474    zval *variable;
475    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &variable) == FAILURE) {
476        RETURN_NULL();
477    }
478
479    RETURN_LONG(Z_REFCOUNT(*variable) - 1);
480}
481/* }}} */
482/* {{{ proto int xcache_get_cowcount(mixed value)
483   XCache internal uses only: Get reference count of copy-on-write variable or data */
484#ifdef ZEND_BEGIN_ARG_INFO_EX
485ZEND_BEGIN_ARG_INFO_EX(arginfo_xcache_get_cowcount, 0, 0, 1)
486    ZEND_ARG_INFO(0, variable)
487ZEND_END_ARG_INFO()
488#else
489static unsigned char arginfo_xcache_get_cowcount[] = { 1, BYREF_NONE };
490#endif
491
492PHP_FUNCTION(xcache_get_cowcount)
493{
494    zval *variable;
495    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &variable) == FAILURE) {
496        RETURN_NULL();
497    }
498
499    RETURN_LONG(Z_REFCOUNT(*variable) - 1);
500}
501/* }}} */
502/* {{{ proto bool xcache_get_isref(mixed variable)
503   XCache internal uses only: Check if variable data is marked referenced */
504#ifdef ZEND_BEGIN_ARG_INFO_EX
505ZEND_BEGIN_ARG_INFO_EX(arginfo_xcache_get_isref, 0, 0, 1)
506    ZEND_ARG_INFO(1, variable)
507ZEND_END_ARG_INFO()
508#else
509static unsigned char arginfo_xcache_get_isref[] = { 1, BYREF_FORCE };
510#endif
511
512PHP_FUNCTION(xcache_get_isref)
513{
514    zval *variable;
515    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &variable) == FAILURE) {
516        RETURN_NULL();
517    }
518
519    RETURN_BOOL(Z_ISREF(*variable) && Z_REFCOUNT(*variable) >= 3);
520}
521/* }}} */
[716]522static zend_function_entry xcache_functions[] = /* {{{ */
[1]523{
[1477]524#ifdef HAVE_XCACHE_DPRINT
525    PHP_FE(xcache_dprint,            arginfo_xcache_dprint)
526#endif
[1]527#ifdef HAVE_XCACHE_ASSEMBLER
528    PHP_FE(xcache_asm,               NULL)
529#endif
530#ifdef HAVE_XCACHE_ENCODER
531    PHP_FE(xcache_encode,            NULL)
532#endif
533#ifdef HAVE_XCACHE_DECODER
[9]534    PHP_FE(xcache_decode_file,       NULL)
535    PHP_FE(xcache_decode_string,     NULL)
[1]536#endif
[1477]537    PHP_FE(xcache_get_special_value, arginfo_xcache_get_special_value)
538    PHP_FE(xcache_get_type,          arginfo_xcache_get_type)
539    PHP_FE(xcache_get_op_type,       arginfo_xcache_get_op_type)
540    PHP_FE(xcache_get_data_type,     arginfo_xcache_get_data_type)
541    PHP_FE(xcache_get_opcode,        arginfo_xcache_get_opcode)
[1565]542    PHP_FE(xcache_get_op_spec,       arginfo_xcache_get_op_spec)
[1477]543    PHP_FE(xcache_get_opcode_spec,   arginfo_xcache_get_opcode_spec)
544    PHP_FE(xcache_coredump,          arginfo_xcache_coredump)
545    PHP_FE(xcache_is_autoglobal,     arginfo_xcache_is_autoglobal)
[1476]546    PHP_FE(xcache_get_refcount,      arginfo_xcache_get_refcount)
547    PHP_FE(xcache_get_cowcount,      arginfo_xcache_get_cowcount)
[781]548    PHP_FE(xcache_get_isref,         arginfo_xcache_get_isref)
[983]549    PHP_FE_END
[1]550};
551/* }}} */
552
[914]553#ifdef ZEND_WIN32
554#include "dbghelp.h"
555typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
556        CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
557        CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
558        CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
559        );
560
[915]561static PTOP_LEVEL_EXCEPTION_FILTER oldFilter = NULL;
[914]562static HMODULE dbghelpModule = NULL;
[915]563static char crash_dumpPath[_MAX_PATH] = { 0 };
564static MINIDUMPWRITEDUMP dbghelp_MiniDumpWriteDump = NULL;
[914]565
566static LONG WINAPI miniDumperFilter(struct _EXCEPTION_POINTERS *pExceptionInfo) /* {{{ */
567{
568    HANDLE fileHandle;
[1106]569    LONG ret = EXCEPTION_CONTINUE_SEARCH;
[914]570
571    SetUnhandledExceptionFilter(oldFilter);
572
573    /* create the file */
574    fileHandle = CreateFile(crash_dumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
575
576    if (fileHandle != INVALID_HANDLE_VALUE) {
577        MINIDUMP_EXCEPTION_INFORMATION exceptionInformation;
[1182]578        MINIDUMP_TYPE type = xc_coredump_type ? xc_coredump_type : (MiniDumpNormal|MiniDumpWithDataSegs|MiniDumpWithIndirectlyReferencedMemory);
[914]579        BOOL ok;
580
581        exceptionInformation.ThreadId = GetCurrentThreadId();
582        exceptionInformation.ExceptionPointers = pExceptionInfo;
583        exceptionInformation.ClientPointers = FALSE;
584
585        /* write the dump */
[1182]586        ok = dbghelp_MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), fileHandle, type, &exceptionInformation, NULL, NULL);
[914]587        CloseHandle(fileHandle);
588        if (ok) {
589            zend_error(E_ERROR, "Saved dump file to '%s'", crash_dumpPath);
[1106]590            ret = EXCEPTION_EXECUTE_HANDLER;
[914]591        }
592        else {
593            zend_error(E_ERROR, "Failed to save dump file to '%s' (error %d)", crash_dumpPath, GetLastError());
594        }
595    }
596    else {
597        zend_error(E_ERROR, "Failed to create dump file '%s' (error %d)", crash_dumpPath, GetLastError());
598    }
599
[1106]600    if (xc_disable_on_crash) {
601        xc_disable_on_crash = 0;
602        xc_cacher_disable();
603    }
604
605    return ret;
[914]606}
607/* }}} */
608
609static void xcache_restore_crash_handler() /* {{{ */
610{
611    if (oldFilter) {
612        SetUnhandledExceptionFilter(oldFilter);
613        oldFilter = NULL;
614    }
615}
616/* }}} */
617static void xcache_init_crash_handler() /* {{{ */
618{
619    /* firstly see if dbghelp.dll is around and has the function we need
620       look next to the EXE first, as the one in System32 might be old
621       (e.g. Windows 2000) */
622    char dbghelpPath[_MAX_PATH];
623
624    if (GetModuleFileName(NULL, dbghelpPath, _MAX_PATH)) {
625        char *slash = strchr(dbghelpPath, '\\');
626        if (slash) {
627            strcpy(slash + 1, "DBGHELP.DLL");
628            dbghelpModule = LoadLibrary(dbghelpPath);
629        }
630    }
631
632    if (!dbghelpModule) {
633        /* load any version we can */
634        dbghelpModule = LoadLibrary("DBGHELP.DLL");
635        if (!dbghelpModule) {
636            zend_error(E_ERROR, "Unable to enable crash dump saver: %s", "DBGHELP.DLL not found");
637            return;
638        }
639    }
640
641    dbghelp_MiniDumpWriteDump = (MINIDUMPWRITEDUMP)GetProcAddress(dbghelpModule, "MiniDumpWriteDump");
[918]642    if (!dbghelp_MiniDumpWriteDump) {
643        zend_error(E_ERROR, "Unable to enable crash dump saver: %s", "DBGHELP.DLL too old. Get updated dll and put it aside of php_xcache.dll");
[914]644        return;
645    }
646
[923]647#ifdef XCACHE_VERSION_REVISION
648#define REVISION "r" XCACHE_VERSION_REVISION
649#else
650#define REVISION ""
651#endif
[925]652    sprintf(crash_dumpPath, "%s\\php-%s-xcache-%s%s-%lu-%lu.dmp", xc_coredump_dir, zend_get_module_version("standard"), XCACHE_VERSION, REVISION, (unsigned long) time(NULL), (unsigned long) GetCurrentProcessId());
[923]653#undef REVISION
[914]654
655    oldFilter = SetUnhandledExceptionFilter(&miniDumperFilter);
656}
657/* }}} */
658#else
[75]659/* old signal handlers {{{ */
660typedef void (*xc_sighandler_t)(int);
661#define FOREACH_SIG(sig) static xc_sighandler_t old_##sig##_handler = NULL
[982]662#include "util/xc_foreachcoresig.h"
[75]663#undef FOREACH_SIG
664/* }}} */
665static void xcache_signal_handler(int sig);
[914]666static void xcache_restore_crash_handler() /* {{{ */
[1]667{
[75]668#define FOREACH_SIG(sig) do { \
669    if (old_##sig##_handler != xcache_signal_handler) { \
670        signal(sig, old_##sig##_handler); \
671    } \
672    else { \
673        signal(sig, SIG_DFL); \
674    } \
675} while (0)
[982]676#include "util/xc_foreachcoresig.h"
[75]677#undef FOREACH_SIG
678}
679/* }}} */
[914]680static void xcache_init_crash_handler() /* {{{ */
[75]681{
682#define FOREACH_SIG(sig) \
683    old_##sig##_handler = signal(sig, xcache_signal_handler)
[982]684#include "util/xc_foreachcoresig.h"
[75]685#undef FOREACH_SIG
686}
687/* }}} */
688static void xcache_signal_handler(int sig) /* {{{ */
689{
[914]690    xcache_restore_crash_handler();
[1]691    if (xc_coredump_dir && xc_coredump_dir[0]) {
[767]692        if (chdir(xc_coredump_dir) != 0) {
693            /* error, but nothing can do about it
694             * and should'nt print anything which might SEGV again */
695        }
[1]696    }
[979]697    if (xc_disable_on_crash) {
698        xc_disable_on_crash = 0;
[1040]699        xc_cacher_disable();
[979]700    }
[1445]701
702    if (0) {
703    }
704#define FOREACH_SIG(forsig) \
705    else if (sig == forsig) \
706        write(2, XCACHE_STRL("Program received signal " #forsig ", Segmentation fault\n"))
707
708#include "util/xc_foreachcoresig.h"
709#undef FOREACH_SIG
710
711    write(2, XCACHE_STRL("If core dump is enabled it can be found at "));
712    write(2, xc_coredump_dir, strlen(xc_coredump_dir));
713    write(2, XCACHE_STRL("\n"));
714
[65]715    raise(sig);
[1]716}
717/* }}} */
[914]718#endif
[1]719
[1563]720static zend_bool xc_is_xcache(const char *name) /* {{{ */
721{
722    return strcmp(name, XCACHE_NAME) == 0 || strncmp(name, XCACHE_NAME " ", sizeof(XCACHE_NAME " ") - 1) == 0;
723}
724/* }}} */
[1047]725/* {{{ incompatible zend extensions handling */
726typedef struct {
727    const char *name;
728    startup_func_t old_startup;
729} xc_incompatible_zend_extension_info_t;
730static xc_incompatible_zend_extension_info_t xc_incompatible_zend_extensions[] = {
[1251]731    { "Zend Extension Manager", NULL },
[1163]732    { "Zend Optimizer", NULL },
733    { "the ionCube PHP Loader", NULL }
[1047]734};
735
736static xc_incompatible_zend_extension_info_t *xc_get_incompatible_zend_extension_info(const char *name)
[164]737{
[1047]738    size_t i;
739
740    for (i = 0; i < sizeof(xc_incompatible_zend_extensions) / sizeof(xc_incompatible_zend_extensions[0]); ++i) {
741        xc_incompatible_zend_extension_info_t *incompatible_zend_extension_info = &xc_incompatible_zend_extensions[i];
742        if (strcmp(incompatible_zend_extension_info->name, name) == 0) {
743            return incompatible_zend_extension_info;
[1026]744        }
745    }
[1045]746
[1047]747    return NULL;
748}
749/* }}} */
[1177]750static void xc_zend_llist_add_element(zend_llist *list, zend_llist_element *element) /* {{{ */
751{
752    if (!zend_extensions.head) {
753        zend_extensions.head = zend_extensions.tail = element;
754    }
755    else {
756        zend_extensions.tail->next = element;
757        element->prev = zend_extensions.tail;
758        zend_extensions.tail = element;
759    }
760}
761/* }}} */
[1047]762static int xc_incompatible_zend_extension_startup_hook(zend_extension *extension) /* {{{ */
763{
764    xc_incompatible_zend_extension_info_t *incompatible_zend_extension_info = xc_get_incompatible_zend_extension_info(extension->name);
765    int status;
766    zend_bool catched = 0;
[1251]767    zend_llist saved_zend_extensions_container; /* without elements */
768    zend_llist_element **saved_zend_extensions_elments;
769    size_t new_zend_extensions_elments_count;
770    zend_llist_element **new_zend_extensions_elments;
[1172]771    zend_extension *ext;
[1177]772    size_t i;
773    zend_llist_element *element;
[1164]774    TSRMLS_FETCH();
[1047]775
[1251]776    /* restore startup hack */
[1047]777    extension->startup = incompatible_zend_extension_info->old_startup;
778    incompatible_zend_extension_info->old_startup = NULL;
779    assert(extension->startup);
780
[1251]781    /* save extensions list */
782    saved_zend_extensions_container = zend_extensions;
783    saved_zend_extensions_elments = malloc(sizeof(zend_llist_element *) * saved_zend_extensions_container.count);
784    for (i = 0, element = saved_zend_extensions_container.head; element; ++i, element = element->next) {
785        saved_zend_extensions_elments[i] = element;
[1177]786    }
787
788    /* hide all XCache extensions from it */
[1163]789    zend_extensions.head = NULL;
790    zend_extensions.tail = NULL;
791    zend_extensions.count = 0;
[1177]792
[1251]793    for (i = 0; i < saved_zend_extensions_container.count; ++i) {
794        element = saved_zend_extensions_elments[i];
[1177]795        element->next = element->prev = NULL;
796
797        ext = (zend_extension *) element->data;
798
[1563]799        if (!xc_is_xcache(ext->name)) {
[1177]800            xc_zend_llist_add_element(&zend_extensions, element);
801            ++zend_extensions.count;
[1172]802        }
803    }
[1163]804
805    assert(extension->startup != xc_incompatible_zend_extension_startup_hook);
[1047]806    zend_try {
807        status = extension->startup(extension);
808    } zend_catch {
809        catched = 1;
810    } zend_end_try();
811
[1251]812    /* save newly added extensions added by this extension*/
813    new_zend_extensions_elments_count = zend_extensions.count - 1;
814    new_zend_extensions_elments = NULL;
815    if (new_zend_extensions_elments_count) {
816        new_zend_extensions_elments = malloc(sizeof(zend_llist_element *) * new_zend_extensions_elments_count);
817        element = zend_extensions.head;
818        for (i = 0, element = element->next; element; ++i, element = element->next) {
819            new_zend_extensions_elments[i] = element;
820        }
821    }
822
823    /* restore original extension list*/
824    zend_extensions = saved_zend_extensions_container;
[1177]825    zend_extensions.head = NULL;
826    zend_extensions.tail = NULL;
827    zend_extensions.count = 0;
[1251]828    for (i = 0; i < saved_zend_extensions_container.count; ++i) {
829        element = saved_zend_extensions_elments[i];
[1177]830        element->next = element->prev = NULL;
831
832        xc_zend_llist_add_element(&zend_extensions, element);
833        ++zend_extensions.count;
[1251]834
835        ext = (zend_extension *) element->data;
836        if (ext == extension && new_zend_extensions_elments_count) {
837            /* add new created extension */
838            size_t j;
839            for (j = 0; j < new_zend_extensions_elments_count; ++j) {
840                element = new_zend_extensions_elments[j];
841                element->next = element->prev = NULL;
842
843                xc_zend_llist_add_element(&zend_extensions, element);
844                ++zend_extensions.count;
845            }
846        }
[1177]847    }
[1251]848    free(saved_zend_extensions_elments);
849    if (new_zend_extensions_elments) {
850        free(new_zend_extensions_elments);
851    }
[1177]852
[1047]853    if (catched) {
854        zend_bailout();
[1045]855    }
[1047]856    return status;
[164]857}
[1026]858/* }}} */
859static int xc_zend_startup(zend_extension *extension) /* {{{ */
[164]860{
[1047]861    zend_llist_position lpos;
862    zend_extension *ext;
863
864    ext = (zend_extension *) zend_extensions.head->data;
865    if (strcmp(ext->name, XCACHE_NAME) != 0) {
[1435]866        zend_error(E_WARNING, "XCache failed to load itself to before zend_extension=\"%s\". compatibility downgraded", ext->name);
[1047]867    }
868
869    for (ext = (zend_extension *) zend_llist_get_first_ex(&zend_extensions, &lpos);
870            ext;
871            ext = (zend_extension *) zend_llist_get_next_ex(&zend_extensions, &lpos)) {
[1061]872        xc_incompatible_zend_extension_info_t *incompatible_zend_extension_info = xc_get_incompatible_zend_extension_info(ext->name);
[1047]873        if (incompatible_zend_extension_info) {
874            assert(!incompatible_zend_extension_info->old_startup);
875            incompatible_zend_extension_info->old_startup = ext->startup;
876            ext->startup = xc_incompatible_zend_extension_startup_hook;
[1026]877        }
[1]878    }
879    return SUCCESS;
880}
[1026]881/* }}} */
882static void xc_zend_shutdown(zend_extension *extension) /* {{{ */
[1]883{
884}
[1026]885/* }}} */
886/* {{{ zend extension definition structure */
[1040]887static zend_extension xc_zend_extension_entry = {
[1026]888    XCACHE_NAME,
889    XCACHE_VERSION,
890    XCACHE_AUTHOR,
891    XCACHE_URL,
892    XCACHE_COPYRIGHT,
893    xc_zend_startup,
894    xc_zend_shutdown,
895    NULL,           /* activate_func_t */
896    NULL,           /* deactivate_func_t */
897    NULL,           /* message_handler_func_t */
898    NULL,           /* op_array_handler_func_t */
899    NULL,           /* statement_handler_func_t */
900    NULL,           /* fcall_begin_handler_func_t */
901    NULL,           /* fcall_end_handler_func_t */
902    NULL,           /* op_array_ctor_func_t */
903    NULL,           /* op_array_dtor_func_t */
904    STANDARD_ZEND_EXTENSION_PROPERTIES
905};
906/* }}} */
[82]907
[1026]908/* {{{ PHP_INI */
[1]909PHP_INI_BEGIN()
[1026]910    PHP_INI_ENTRY1     ("xcache.coredump_directory",      "", PHP_INI_SYSTEM, xcache_OnUpdateString,   &xc_coredump_dir)
[1230]911#ifdef ZEND_WIN32
[1182]912    PHP_INI_ENTRY1     ("xcache.coredump_type",          "0", PHP_INI_SYSTEM, xcache_OnUpdateULong,    &xc_coredump_type)
[1230]913#endif
[1067]914    PHP_INI_ENTRY1_EX  ("xcache.disable_on_crash",       "0", PHP_INI_SYSTEM, xcache_OnUpdateBool,     &xc_disable_on_crash, zend_ini_boolean_displayer_cb)
915    PHP_INI_ENTRY1_EX  ("xcache.test",                   "0", PHP_INI_SYSTEM, xcache_OnUpdateBool,     &xc_test,             zend_ini_boolean_displayer_cb)
[399]916    STD_PHP_INI_BOOLEAN("xcache.experimental",           "0", PHP_INI_ALL,    OnUpdateBool,        experimental,      zend_xcache_globals, xcache_globals)
[1]917PHP_INI_END()
918/* }}} */
[1026]919static PHP_MINFO_FUNCTION(xcache) /* {{{ */
[1]920{
921    php_info_print_table_start();
[1026]922    php_info_print_table_row(2, "XCache Version", XCACHE_VERSION);
[923]923#ifdef XCACHE_VERSION_REVISION
924    php_info_print_table_row(2, "Revision", "r" XCACHE_VERSION_REVISION);
925#endif
[26]926    php_info_print_table_row(2, "Modules Built", XCACHE_MODULES);
[1]927    php_info_print_table_end();
[82]928
[1]929    DISPLAY_INI_ENTRIES();
930}
931/* }}} */
[1026]932static PHP_MINIT_FUNCTION(xcache) /* {{{ */
[1]933{
[92]934#ifndef PHP_GINIT
[17]935    ZEND_INIT_MODULE_GLOBALS(xcache, xc_init_globals, xc_shutdown_globals);
[92]936#endif
[17]937    REGISTER_INI_ENTRIES();
938
[65]939    if (xc_coredump_dir && xc_coredump_dir[0]) {
[914]940        xcache_init_crash_handler();
[65]941    }
[1]942
[1129]943    if (strcmp(sapi_module.name, "cli") == 0) {
[1131]944        char *env;
[1129]945        if ((env = getenv("XCACHE_TEST")) != NULL) {
[1201]946            xc_test = (zend_bool) atoi(env);
[1129]947        }
948    }
949
[1]950    xc_init_constant(module_number TSRMLS_CC);
[148]951    xc_shm_init_modules();
[1]952
[1047]953    /* must be the first */
954    xcache_zend_extension_add(&xc_zend_extension_entry, 1);
[1435]955    old_compile_file = zend_compile_file;
956    zend_compile_file = xc_check_initial_compile_file;
957
[1047]958#ifdef HAVE_XCACHE_OPTIMIZER
959    xc_optimizer_startup_module();
960#endif
961#ifdef HAVE_XCACHE_CACHER
962    xc_cacher_startup_module();
963#endif
[27]964#ifdef HAVE_XCACHE_COVERAGER
[1026]965    xc_coverager_startup_module();
[1]966#endif
[1026]967#ifdef HAVE_XCACHE_DISASSEMBLER
968    xc_disassembler_startup_module();
969#endif
[1045]970
[1]971    return SUCCESS;
972}
973/* }}} */
[1040]974static PHP_MSHUTDOWN_FUNCTION(xcache) /* {{{ */
[1]975{
[1040]976    if (old_compile_file && zend_compile_file == xc_check_initial_compile_file) {
977        zend_compile_file = old_compile_file;
978        old_compile_file = NULL;
[1]979    }
980
[65]981    if (xc_coredump_dir && xc_coredump_dir[0]) {
[914]982        xcache_restore_crash_handler();
[65]983    }
[1]984    if (xc_coredump_dir) {
985        pefree(xc_coredump_dir, 1);
986        xc_coredump_dir = NULL;
987    }
[92]988#ifndef PHP_GINIT
989#   ifdef ZTS
[25]990    ts_free_id(xcache_globals_id);
[92]991#   else
[1]992    xc_shutdown_globals(&xcache_globals TSRMLS_CC);
[92]993#   endif
[1]994#endif
995
996    UNREGISTER_INI_ENTRIES();
[1045]997    xcache_zend_extension_remove(&xc_zend_extension_entry);
[1563]998
999#ifndef ZEND_ENGINE_2
1000    /* XCache main module is registered last of all XCache modules in PHP_4
1001     * move handle to first XCache module to avoid early unload of this dll(so)
1002     */
1003    {
1004        zend_module_entry *handle_holder = NULL, *first = NULL;
1005        Bucket *p;
1006       
1007        for (p = module_registry.pListHead; p; p = p->pListNext) {
1008            zend_module_entry *module = p->pData;
1009            if (xc_is_xcache(module->name)) {
1010                if (!first) {
1011                    first = module;
1012                }
1013                if (module->handle) {
1014                    handle_holder = module;
1015                    break;
1016                }
1017            }
1018        }
1019
1020        if (first && handle_holder && handle_holder != first) {
1021            first->handle = handle_holder->handle;
1022            handle_holder->handle = NULL;
1023        }
1024    }
1025#endif
[1]1026    return SUCCESS;
1027}
1028/* }}} */
[492]1029/* {{{ module dependencies */
[1026]1030#ifdef STANDARD_MODULE_HEADER_EX
[847]1031static zend_module_dep xcache_module_deps[] = {
[492]1032    ZEND_MOD_REQUIRED("standard")
1033    ZEND_MOD_CONFLICTS("apc")
1034    ZEND_MOD_CONFLICTS("eAccelerator")
1035    ZEND_MOD_CONFLICTS("Turck MMCache")
[983]1036    ZEND_MOD_END
[492]1037};
1038#endif
1039/* }}} */ 
[1]1040/* {{{ module definition structure */
1041zend_module_entry xcache_module_entry = {
[1026]1042#ifdef STANDARD_MODULE_HEADER_EX
[492]1043    STANDARD_MODULE_HEADER_EX,
1044    NULL,
1045    xcache_module_deps,
1046#else
[1]1047    STANDARD_MODULE_HEADER,
[492]1048#endif
1049    XCACHE_NAME,
[1]1050    xcache_functions,
1051    PHP_MINIT(xcache),
1052    PHP_MSHUTDOWN(xcache),
[1040]1053    NULL, /* RINIT */
1054    NULL, /* RSHUTDOWN */
[1]1055    PHP_MINFO(xcache),
1056    XCACHE_VERSION,
[92]1057#ifdef PHP_GINIT
1058    PHP_MODULE_GLOBALS(xcache),
1059    PHP_GINIT(xcache),
1060    PHP_GSHUTDOWN(xcache),
1061#endif
[1321]1062#ifdef ZEND_ENGINE_2
[1040]1063    NULL /* ZEND_MODULE_POST_ZEND_DEACTIVATE_N */,
[1321]1064#else
1065    NULL,
1066    NULL,
1067#endif
[1]1068    STANDARD_MODULE_PROPERTIES_EX
1069};
1070
1071#ifdef COMPILE_DL_XCACHE
1072ZEND_GET_MODULE(xcache)
1073#endif
1074/* }}} */
Note: See TracBrowser for help on using the repository browser.