source: trunk/xcache.c @ 1321

Last change on this file since 1321 was 1321, checked in by moo, 13 months ago

add back PHP_4 code for disassembler

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