source: trunk/xcache.c @ 1477

Last change on this file since 1477 was 1477, checked in by moo, 8 months ago

adds reflection info for APIs

  • Property svn:eol-style set to native
File size: 28.9 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#ifdef __GNUC__
118#pragma GCC push_options
119#pragma GCC diagnostic ignored "-Wshadow"
120#endif
121
122#ifdef PHP_GINIT_FUNCTION
123static PHP_GINIT_FUNCTION(xcache)
124#else
125static void xc_init_globals(zend_xcache_globals* xcache_globals TSRMLS_DC)
126#endif
127{
128#ifdef __GNUC__
129#pragma GCC pop_options
130#endif
131
132    memset(xcache_globals, 0, sizeof(zend_xcache_globals));
133
134#ifdef HAVE_XCACHE_CONSTANT
135    zend_hash_init_ex(&xcache_globals->internal_constant_table, 1, NULL, (dtor_func_t) xc_zend_constant_dtor, 1, 0);
136#endif
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);
139}
140/* }}} */
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
148{
149    size_t i;
150
151    if (xcache_globals->php_holds != NULL) {
152        for (i = 0; i < xcache_globals->php_holds_size; i ++) {
153            xc_stack_destroy(&xcache_globals->php_holds[i]);
154        }
155        free(xcache_globals->php_holds);
156        xcache_globals->php_holds = NULL;
157        xcache_globals->php_holds_size = 0;
158    }
159
160    if (xcache_globals->var_holds != NULL) {
161        for (i = 0; i < xcache_globals->var_holds_size; i ++) {
162            xc_stack_destroy(&xcache_globals->var_holds[i]);
163        }
164        free(xcache_globals->var_holds);
165        xcache_globals->var_holds = NULL;
166        xcache_globals->var_holds_size = 0;
167    }
168
169    if (xcache_globals->internal_table_copied) {
170#ifdef HAVE_XCACHE_CONSTANT
171        zend_hash_destroy(&xcache_globals->internal_constant_table);
172#endif
173        zend_hash_destroy(&xcache_globals->internal_function_table);
174        zend_hash_destroy(&xcache_globals->internal_class_table);
175    }
176}
177/* }}} */
178
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"
183
184#ifdef ZEND_BEGIN_ARG_INFO_EX
185ZEND_BEGIN_ARG_INFO_EX(arginfo_xcache_dprint, 0, 0, 1)
186    ZEND_ARG_INFO(0, value)
187ZEND_END_ARG_INFO()
188#else
189static unsigned char arginfo_xcache_dprint[] = { 1, BYREF_NONE };
190#endif
191
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
203#ifdef HAVE_XCACHE_ASSEMBLER
204/* {{{ proto string xcache_asm(string filename)
205 */
206PHP_FUNCTION(xcache_asm)
207{
208}
209/* }}} */
210#endif
211#ifdef HAVE_XCACHE_ENCODER
212/* {{{ proto string xcache_encode(string filename)
213   Encode php file into XCache opcode encoded format */
214PHP_FUNCTION(xcache_encode)
215{
216}
217/* }}} */
218#endif
219#ifdef HAVE_XCACHE_DECODER
220/* {{{ proto bool xcache_decode_file(string filename)
221   Decode(load) opcode from XCache encoded format file */
222PHP_FUNCTION(xcache_decode_file)
223{
224}
225/* }}} */
226/* {{{ proto bool xcache_decode_string(string data)
227   Decode(load) opcode from XCache encoded format data */
228PHP_FUNCTION(xcache_decode_string)
229{
230}
231/* }}} */
232#endif
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) {
244        name = getter((zend_uchar) spec);
245        if (name) {
246            /* RETURN_STRING */
247            int len = (int) strlen(name);
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) */
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
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) */
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
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) */
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
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) */
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
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) */
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
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    }
330    if ((zend_uchar) spec <= xc_get_opcode_spec_count()) {
331        opspec = xc_get_opcode_spec((zend_uchar) spec);
332        if (opspec) {
333            array_init(return_value);
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);
338            return;
339        }
340    }
341    RETURN_NULL();
342}
343/* }}} */
344/* {{{ proto mixed xcache_get_special_value(zval value)
345   XCache internal use only: For decompiler to get static value with type fixed */
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
354PHP_FUNCTION(xcache_get_special_value)
355{
356    zval *value;
357
358    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
359        return;
360    }
361
362    switch ((Z_TYPE_P(value) & IS_CONSTANT_TYPE_MASK)) {
363    case IS_CONSTANT:
364        *return_value = *value;
365        zval_copy_ctor(return_value);
366        return_value->type = UNISW(IS_STRING, UG(unicode) ? IS_UNICODE : IS_STRING);
367        break;
368
369    case IS_CONSTANT_ARRAY:
370        *return_value = *value;
371        zval_copy_ctor(return_value);
372        return_value->type = IS_ARRAY;
373        break;
374
375    default:
376        if ((Z_TYPE_P(value) & ~IS_CONSTANT_TYPE_MASK)) {
377            *return_value = *value;
378            zval_copy_ctor(return_value);
379            return_value->type &= IS_CONSTANT_TYPE_MASK;
380        }
381        else {
382            RETURN_NULL();
383        }
384    }
385}
386/* }}} */
387/* {{{ proto int xcache_get_type(zval value)
388   XCache internal use only for disassembler to get variable type in engine level */
389#ifdef ZEND_BEGIN_ARG_INFO_EX
390ZEND_BEGIN_ARG_INFO_EX(arginfo_xcache_get_type, 0, 0, 1)
391    ZEND_ARG_INFO(0, value)
392ZEND_END_ARG_INFO()
393#else
394static unsigned char arginfo_xcache_get_type[] = { 1, BYREF_NONE };
395#endif
396
397PHP_FUNCTION(xcache_get_type)
398{
399    zval *value;
400
401    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &value) == FAILURE) {
402        return;
403    }
404
405    RETURN_LONG(Z_TYPE_P(value));
406}
407/* }}} */
408/* {{{ proto string xcache_coredump() */
409#ifdef ZEND_BEGIN_ARG_INFO_EX
410ZEND_BEGIN_ARG_INFO_EX(arginfo_xcache_coredump, 0, 0, 0)
411ZEND_END_ARG_INFO()
412#else
413static unsigned char arginfo_xcache_coredump[] = { 1, BYREF_NONE };
414#endif
415
416PHP_FUNCTION(xcache_coredump)
417{
418    if (xc_test) {
419        char *null_ptr = NULL;
420        *null_ptr = 0;
421        raise(SIGSEGV);
422    }
423    else {
424        php_error_docref(NULL TSRMLS_CC, E_WARNING, "xcache.test must be enabled to test xcache_coredump()");
425    }
426}
427/* }}} */
428/* {{{ proto string xcache_is_autoglobal(string name) */
429#ifdef ZEND_BEGIN_ARG_INFO_EX
430ZEND_BEGIN_ARG_INFO_EX(arginfo_xcache_is_autoglobal, 0, 0, 1)
431    ZEND_ARG_INFO(0, name)
432ZEND_END_ARG_INFO()
433#else
434static unsigned char arginfo_xcache_is_autoglobal[] = { 1, BYREF_NONE };
435#endif
436
437PHP_FUNCTION(xcache_is_autoglobal)
438{
439    zval *name;
440
441    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &name) == FAILURE) {
442        return;
443    }
444
445#ifdef IS_UNICODE
446    convert_to_unicode(name);
447#else
448    convert_to_string(name);
449#endif
450
451    RETURN_BOOL(zend_u_hash_exists(CG(auto_globals), UG(unicode), Z_STRVAL_P(name), Z_STRLEN_P(name) + 1));
452}
453/* }}} */
454/* {{{ proto int xcache_get_refcount(mixed &variable)
455   XCache internal uses only: Get reference count of referenced variable */
456#ifdef ZEND_BEGIN_ARG_INFO_EX
457ZEND_BEGIN_ARG_INFO_EX(arginfo_xcache_get_refcount, 0, 0, 1)
458    ZEND_ARG_INFO(1, variable)
459ZEND_END_ARG_INFO()
460#else
461static unsigned char arginfo_xcache_get_refcount[] = { 1, BYREF_FORCE };
462#endif
463
464PHP_FUNCTION(xcache_get_refcount)
465{
466    zval *variable;
467    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &variable) == FAILURE) {
468        RETURN_NULL();
469    }
470
471    RETURN_LONG(Z_REFCOUNT(*variable) - 1);
472}
473/* }}} */
474/* {{{ proto int xcache_get_cowcount(mixed value)
475   XCache internal uses only: Get reference count of copy-on-write variable or data */
476#ifdef ZEND_BEGIN_ARG_INFO_EX
477ZEND_BEGIN_ARG_INFO_EX(arginfo_xcache_get_cowcount, 0, 0, 1)
478    ZEND_ARG_INFO(0, variable)
479ZEND_END_ARG_INFO()
480#else
481static unsigned char arginfo_xcache_get_cowcount[] = { 1, BYREF_NONE };
482#endif
483
484PHP_FUNCTION(xcache_get_cowcount)
485{
486    zval *variable;
487    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &variable) == FAILURE) {
488        RETURN_NULL();
489    }
490
491    RETURN_LONG(Z_REFCOUNT(*variable) - 1);
492}
493/* }}} */
494/* {{{ proto bool xcache_get_isref(mixed variable)
495   XCache internal uses only: Check if variable data is marked referenced */
496#ifdef ZEND_BEGIN_ARG_INFO_EX
497ZEND_BEGIN_ARG_INFO_EX(arginfo_xcache_get_isref, 0, 0, 1)
498    ZEND_ARG_INFO(1, variable)
499ZEND_END_ARG_INFO()
500#else
501static unsigned char arginfo_xcache_get_isref[] = { 1, BYREF_FORCE };
502#endif
503
504PHP_FUNCTION(xcache_get_isref)
505{
506    zval *variable;
507    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &variable) == FAILURE) {
508        RETURN_NULL();
509    }
510
511    RETURN_BOOL(Z_ISREF(*variable) && Z_REFCOUNT(*variable) >= 3);
512}
513/* }}} */
514static zend_function_entry xcache_functions[] = /* {{{ */
515{
516#ifdef HAVE_XCACHE_DPRINT
517    PHP_FE(xcache_dprint,            arginfo_xcache_dprint)
518#endif
519#ifdef HAVE_XCACHE_ASSEMBLER
520    PHP_FE(xcache_asm,               NULL)
521#endif
522#ifdef HAVE_XCACHE_ENCODER
523    PHP_FE(xcache_encode,            NULL)
524#endif
525#ifdef HAVE_XCACHE_DECODER
526    PHP_FE(xcache_decode_file,       NULL)
527    PHP_FE(xcache_decode_string,     NULL)
528#endif
529    PHP_FE(xcache_get_special_value, arginfo_xcache_get_special_value)
530    PHP_FE(xcache_get_type,          arginfo_xcache_get_type)
531    PHP_FE(xcache_get_op_type,       arginfo_xcache_get_op_type)
532    PHP_FE(xcache_get_data_type,     arginfo_xcache_get_data_type)
533    PHP_FE(xcache_get_opcode,        arginfo_xcache_get_opcode)
534    PHP_FE(xcache_get_opcode_spec,   arginfo_xcache_get_opcode_spec)
535    PHP_FE(xcache_coredump,          arginfo_xcache_coredump)
536    PHP_FE(xcache_is_autoglobal,     arginfo_xcache_is_autoglobal)
537    PHP_FE(xcache_get_refcount,      arginfo_xcache_get_refcount)
538    PHP_FE(xcache_get_cowcount,      arginfo_xcache_get_cowcount)
539    PHP_FE(xcache_get_isref,         arginfo_xcache_get_isref)
540    PHP_FE_END
541};
542/* }}} */
543
544#ifdef ZEND_WIN32
545#include "dbghelp.h"
546typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType,
547        CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
548        CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
549        CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam
550        );
551
552static PTOP_LEVEL_EXCEPTION_FILTER oldFilter = NULL;
553static HMODULE dbghelpModule = NULL;
554static char crash_dumpPath[_MAX_PATH] = { 0 };
555static MINIDUMPWRITEDUMP dbghelp_MiniDumpWriteDump = NULL;
556
557static LONG WINAPI miniDumperFilter(struct _EXCEPTION_POINTERS *pExceptionInfo) /* {{{ */
558{
559    HANDLE fileHandle;
560    LONG ret = EXCEPTION_CONTINUE_SEARCH;
561
562    SetUnhandledExceptionFilter(oldFilter);
563
564    /* create the file */
565    fileHandle = CreateFile(crash_dumpPath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
566
567    if (fileHandle != INVALID_HANDLE_VALUE) {
568        MINIDUMP_EXCEPTION_INFORMATION exceptionInformation;
569        MINIDUMP_TYPE type = xc_coredump_type ? xc_coredump_type : (MiniDumpNormal|MiniDumpWithDataSegs|MiniDumpWithIndirectlyReferencedMemory);
570        BOOL ok;
571
572        exceptionInformation.ThreadId = GetCurrentThreadId();
573        exceptionInformation.ExceptionPointers = pExceptionInfo;
574        exceptionInformation.ClientPointers = FALSE;
575
576        /* write the dump */
577        ok = dbghelp_MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), fileHandle, type, &exceptionInformation, NULL, NULL);
578        CloseHandle(fileHandle);
579        if (ok) {
580            zend_error(E_ERROR, "Saved dump file to '%s'", crash_dumpPath);
581            ret = EXCEPTION_EXECUTE_HANDLER;
582        }
583        else {
584            zend_error(E_ERROR, "Failed to save dump file to '%s' (error %d)", crash_dumpPath, GetLastError());
585        }
586    }
587    else {
588        zend_error(E_ERROR, "Failed to create dump file '%s' (error %d)", crash_dumpPath, GetLastError());
589    }
590
591    if (xc_disable_on_crash) {
592        xc_disable_on_crash = 0;
593        xc_cacher_disable();
594    }
595
596    return ret;
597}
598/* }}} */
599
600static void xcache_restore_crash_handler() /* {{{ */
601{
602    if (oldFilter) {
603        SetUnhandledExceptionFilter(oldFilter);
604        oldFilter = NULL;
605    }
606}
607/* }}} */
608static void xcache_init_crash_handler() /* {{{ */
609{
610    /* firstly see if dbghelp.dll is around and has the function we need
611       look next to the EXE first, as the one in System32 might be old
612       (e.g. Windows 2000) */
613    char dbghelpPath[_MAX_PATH];
614
615    if (GetModuleFileName(NULL, dbghelpPath, _MAX_PATH)) {
616        char *slash = strchr(dbghelpPath, '\\');
617        if (slash) {
618            strcpy(slash + 1, "DBGHELP.DLL");
619            dbghelpModule = LoadLibrary(dbghelpPath);
620        }
621    }
622
623    if (!dbghelpModule) {
624        /* load any version we can */
625        dbghelpModule = LoadLibrary("DBGHELP.DLL");
626        if (!dbghelpModule) {
627            zend_error(E_ERROR, "Unable to enable crash dump saver: %s", "DBGHELP.DLL not found");
628            return;
629        }
630    }
631
632    dbghelp_MiniDumpWriteDump = (MINIDUMPWRITEDUMP)GetProcAddress(dbghelpModule, "MiniDumpWriteDump");
633    if (!dbghelp_MiniDumpWriteDump) {
634        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");
635        return;
636    }
637
638#ifdef XCACHE_VERSION_REVISION
639#define REVISION "r" XCACHE_VERSION_REVISION
640#else
641#define REVISION ""
642#endif
643    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());
644#undef REVISION
645
646    oldFilter = SetUnhandledExceptionFilter(&miniDumperFilter);
647}
648/* }}} */
649#else
650/* old signal handlers {{{ */
651typedef void (*xc_sighandler_t)(int);
652#define FOREACH_SIG(sig) static xc_sighandler_t old_##sig##_handler = NULL
653#include "util/xc_foreachcoresig.h"
654#undef FOREACH_SIG
655/* }}} */
656static void xcache_signal_handler(int sig);
657static void xcache_restore_crash_handler() /* {{{ */
658{
659#define FOREACH_SIG(sig) do { \
660    if (old_##sig##_handler != xcache_signal_handler) { \
661        signal(sig, old_##sig##_handler); \
662    } \
663    else { \
664        signal(sig, SIG_DFL); \
665    } \
666} while (0)
667#include "util/xc_foreachcoresig.h"
668#undef FOREACH_SIG
669}
670/* }}} */
671static void xcache_init_crash_handler() /* {{{ */
672{
673#define FOREACH_SIG(sig) \
674    old_##sig##_handler = signal(sig, xcache_signal_handler)
675#include "util/xc_foreachcoresig.h"
676#undef FOREACH_SIG
677}
678/* }}} */
679static void xcache_signal_handler(int sig) /* {{{ */
680{
681    xcache_restore_crash_handler();
682    if (xc_coredump_dir && xc_coredump_dir[0]) {
683        if (chdir(xc_coredump_dir) != 0) {
684            /* error, but nothing can do about it
685             * and should'nt print anything which might SEGV again */
686        }
687    }
688    if (xc_disable_on_crash) {
689        xc_disable_on_crash = 0;
690        xc_cacher_disable();
691    }
692
693    if (0) {
694    }
695#define FOREACH_SIG(forsig) \
696    else if (sig == forsig) \
697        write(2, XCACHE_STRL("Program received signal " #forsig ", Segmentation fault\n"))
698
699#include "util/xc_foreachcoresig.h"
700#undef FOREACH_SIG
701
702    write(2, XCACHE_STRL("If core dump is enabled it can be found at "));
703    write(2, xc_coredump_dir, strlen(xc_coredump_dir));
704    write(2, XCACHE_STRL("\n"));
705
706    raise(sig);
707}
708/* }}} */
709#endif
710
711/* {{{ incompatible zend extensions handling */
712typedef struct {
713    const char *name;
714    startup_func_t old_startup;
715} xc_incompatible_zend_extension_info_t;
716static xc_incompatible_zend_extension_info_t xc_incompatible_zend_extensions[] = {
717    { "Zend Extension Manager", NULL },
718    { "Zend Optimizer", NULL },
719    { "the ionCube PHP Loader", NULL }
720};
721
722static xc_incompatible_zend_extension_info_t *xc_get_incompatible_zend_extension_info(const char *name)
723{
724    size_t i;
725
726    for (i = 0; i < sizeof(xc_incompatible_zend_extensions) / sizeof(xc_incompatible_zend_extensions[0]); ++i) {
727        xc_incompatible_zend_extension_info_t *incompatible_zend_extension_info = &xc_incompatible_zend_extensions[i];
728        if (strcmp(incompatible_zend_extension_info->name, name) == 0) {
729            return incompatible_zend_extension_info;
730        }
731    }
732
733    return NULL;
734}
735/* }}} */
736static void xc_zend_llist_add_element(zend_llist *list, zend_llist_element *element) /* {{{ */
737{
738    if (!zend_extensions.head) {
739        zend_extensions.head = zend_extensions.tail = element;
740    }
741    else {
742        zend_extensions.tail->next = element;
743        element->prev = zend_extensions.tail;
744        zend_extensions.tail = element;
745    }
746}
747/* }}} */
748static int xc_incompatible_zend_extension_startup_hook(zend_extension *extension) /* {{{ */
749{
750    xc_incompatible_zend_extension_info_t *incompatible_zend_extension_info = xc_get_incompatible_zend_extension_info(extension->name);
751    int status;
752    zend_bool catched = 0;
753    zend_llist saved_zend_extensions_container; /* without elements */
754    zend_llist_element **saved_zend_extensions_elments;
755    size_t new_zend_extensions_elments_count;
756    zend_llist_element **new_zend_extensions_elments;
757    zend_extension *ext;
758    size_t i;
759    zend_llist_element *element;
760    TSRMLS_FETCH();
761
762    /* restore startup hack */
763    extension->startup = incompatible_zend_extension_info->old_startup;
764    incompatible_zend_extension_info->old_startup = NULL;
765    assert(extension->startup);
766
767    /* save extensions list */
768    saved_zend_extensions_container = zend_extensions;
769    saved_zend_extensions_elments = malloc(sizeof(zend_llist_element *) * saved_zend_extensions_container.count);
770    for (i = 0, element = saved_zend_extensions_container.head; element; ++i, element = element->next) {
771        saved_zend_extensions_elments[i] = element;
772    }
773
774    /* hide all XCache extensions from it */
775    zend_extensions.head = NULL;
776    zend_extensions.tail = NULL;
777    zend_extensions.count = 0;
778
779    for (i = 0; i < saved_zend_extensions_container.count; ++i) {
780        element = saved_zend_extensions_elments[i];
781        element->next = element->prev = NULL;
782
783        ext = (zend_extension *) element->data;
784
785        if (!(strcmp(ext->name, XCACHE_NAME) == 0 || strncmp(ext->name, XCACHE_NAME " ", sizeof(XCACHE_NAME " ") - 1) == 0)) {
786            xc_zend_llist_add_element(&zend_extensions, element);
787            ++zend_extensions.count;
788        }
789    }
790
791    assert(extension->startup != xc_incompatible_zend_extension_startup_hook);
792    zend_try {
793        status = extension->startup(extension);
794    } zend_catch {
795        catched = 1;
796    } zend_end_try();
797
798    /* save newly added extensions added by this extension*/
799    new_zend_extensions_elments_count = zend_extensions.count - 1;
800    new_zend_extensions_elments = NULL;
801    if (new_zend_extensions_elments_count) {
802        new_zend_extensions_elments = malloc(sizeof(zend_llist_element *) * new_zend_extensions_elments_count);
803        element = zend_extensions.head;
804        for (i = 0, element = element->next; element; ++i, element = element->next) {
805            new_zend_extensions_elments[i] = element;
806        }
807    }
808
809    /* restore original extension list*/
810    zend_extensions = saved_zend_extensions_container;
811    zend_extensions.head = NULL;
812    zend_extensions.tail = NULL;
813    zend_extensions.count = 0;
814    for (i = 0; i < saved_zend_extensions_container.count; ++i) {
815        element = saved_zend_extensions_elments[i];
816        element->next = element->prev = NULL;
817
818        xc_zend_llist_add_element(&zend_extensions, element);
819        ++zend_extensions.count;
820
821        ext = (zend_extension *) element->data;
822        if (ext == extension && new_zend_extensions_elments_count) {
823            /* add new created extension */
824            size_t j;
825            for (j = 0; j < new_zend_extensions_elments_count; ++j) {
826                element = new_zend_extensions_elments[j];
827                element->next = element->prev = NULL;
828
829                xc_zend_llist_add_element(&zend_extensions, element);
830                ++zend_extensions.count;
831            }
832        }
833    }
834    free(saved_zend_extensions_elments);
835    if (new_zend_extensions_elments) {
836        free(new_zend_extensions_elments);
837    }
838
839    if (catched) {
840        zend_bailout();
841    }
842    return status;
843}
844/* }}} */
845static int xc_zend_startup(zend_extension *extension) /* {{{ */
846{
847    zend_llist_position lpos;
848    zend_extension *ext;
849
850    ext = (zend_extension *) zend_extensions.head->data;
851    if (strcmp(ext->name, XCACHE_NAME) != 0) {
852        zend_error(E_WARNING, "XCache failed to load itself to before zend_extension=\"%s\". compatibility downgraded", ext->name);
853    }
854
855    for (ext = (zend_extension *) zend_llist_get_first_ex(&zend_extensions, &lpos);
856            ext;
857            ext = (zend_extension *) zend_llist_get_next_ex(&zend_extensions, &lpos)) {
858        xc_incompatible_zend_extension_info_t *incompatible_zend_extension_info = xc_get_incompatible_zend_extension_info(ext->name);
859        if (incompatible_zend_extension_info) {
860            assert(!incompatible_zend_extension_info->old_startup);
861            incompatible_zend_extension_info->old_startup = ext->startup;
862            ext->startup = xc_incompatible_zend_extension_startup_hook;
863        }
864    }
865    return SUCCESS;
866}
867/* }}} */
868static void xc_zend_shutdown(zend_extension *extension) /* {{{ */
869{
870}
871/* }}} */
872/* {{{ zend extension definition structure */
873static zend_extension xc_zend_extension_entry = {
874    XCACHE_NAME,
875    XCACHE_VERSION,
876    XCACHE_AUTHOR,
877    XCACHE_URL,
878    XCACHE_COPYRIGHT,
879    xc_zend_startup,
880    xc_zend_shutdown,
881    NULL,           /* activate_func_t */
882    NULL,           /* deactivate_func_t */
883    NULL,           /* message_handler_func_t */
884    NULL,           /* op_array_handler_func_t */
885    NULL,           /* statement_handler_func_t */
886    NULL,           /* fcall_begin_handler_func_t */
887    NULL,           /* fcall_end_handler_func_t */
888    NULL,           /* op_array_ctor_func_t */
889    NULL,           /* op_array_dtor_func_t */
890    STANDARD_ZEND_EXTENSION_PROPERTIES
891};
892/* }}} */
893
894/* {{{ PHP_INI */
895PHP_INI_BEGIN()
896    PHP_INI_ENTRY1     ("xcache.coredump_directory",      "", PHP_INI_SYSTEM, xcache_OnUpdateString,   &xc_coredump_dir)
897#ifdef ZEND_WIN32
898    PHP_INI_ENTRY1     ("xcache.coredump_type",          "0", PHP_INI_SYSTEM, xcache_OnUpdateULong,    &xc_coredump_type)
899#endif
900    PHP_INI_ENTRY1_EX  ("xcache.disable_on_crash",       "0", PHP_INI_SYSTEM, xcache_OnUpdateBool,     &xc_disable_on_crash, zend_ini_boolean_displayer_cb)
901    PHP_INI_ENTRY1_EX  ("xcache.test",                   "0", PHP_INI_SYSTEM, xcache_OnUpdateBool,     &xc_test,             zend_ini_boolean_displayer_cb)
902    STD_PHP_INI_BOOLEAN("xcache.experimental",           "0", PHP_INI_ALL,    OnUpdateBool,        experimental,      zend_xcache_globals, xcache_globals)
903PHP_INI_END()
904/* }}} */
905static PHP_MINFO_FUNCTION(xcache) /* {{{ */
906{
907    php_info_print_table_start();
908    php_info_print_table_row(2, "XCache Version", XCACHE_VERSION);
909#ifdef XCACHE_VERSION_REVISION
910    php_info_print_table_row(2, "Revision", "r" XCACHE_VERSION_REVISION);
911#endif
912    php_info_print_table_row(2, "Modules Built", XCACHE_MODULES);
913    php_info_print_table_end();
914
915    DISPLAY_INI_ENTRIES();
916}
917/* }}} */
918static PHP_MINIT_FUNCTION(xcache) /* {{{ */
919{
920#ifndef PHP_GINIT
921    ZEND_INIT_MODULE_GLOBALS(xcache, xc_init_globals, xc_shutdown_globals);
922#endif
923    REGISTER_INI_ENTRIES();
924
925    if (xc_coredump_dir && xc_coredump_dir[0]) {
926        xcache_init_crash_handler();
927    }
928
929    if (strcmp(sapi_module.name, "cli") == 0) {
930        char *env;
931        if ((env = getenv("XCACHE_TEST")) != NULL) {
932            xc_test = (zend_bool) atoi(env);
933        }
934    }
935
936    xc_init_constant(module_number TSRMLS_CC);
937    xc_shm_init_modules();
938
939    /* must be the first */
940    xcache_zend_extension_add(&xc_zend_extension_entry, 1);
941    old_compile_file = zend_compile_file;
942    zend_compile_file = xc_check_initial_compile_file;
943
944#ifdef HAVE_XCACHE_OPTIMIZER
945    xc_optimizer_startup_module();
946#endif
947#ifdef HAVE_XCACHE_CACHER
948    xc_cacher_startup_module();
949#endif
950#ifdef HAVE_XCACHE_COVERAGER
951    xc_coverager_startup_module();
952#endif
953#ifdef HAVE_XCACHE_DISASSEMBLER
954    xc_disassembler_startup_module();
955#endif
956
957    return SUCCESS;
958}
959/* }}} */
960static PHP_MSHUTDOWN_FUNCTION(xcache) /* {{{ */
961{
962    if (old_compile_file && zend_compile_file == xc_check_initial_compile_file) {
963        zend_compile_file = old_compile_file;
964        old_compile_file = NULL;
965    }
966
967    if (xc_coredump_dir && xc_coredump_dir[0]) {
968        xcache_restore_crash_handler();
969    }
970    if (xc_coredump_dir) {
971        pefree(xc_coredump_dir, 1);
972        xc_coredump_dir = NULL;
973    }
974#ifndef PHP_GINIT
975#   ifdef ZTS
976    ts_free_id(xcache_globals_id);
977#   else
978    xc_shutdown_globals(&xcache_globals TSRMLS_CC);
979#   endif
980#endif
981
982    UNREGISTER_INI_ENTRIES();
983    xcache_zend_extension_remove(&xc_zend_extension_entry);
984    return SUCCESS;
985}
986/* }}} */
987/* {{{ module dependencies */
988#ifdef STANDARD_MODULE_HEADER_EX
989static zend_module_dep xcache_module_deps[] = {
990    ZEND_MOD_REQUIRED("standard")
991    ZEND_MOD_CONFLICTS("apc")
992    ZEND_MOD_CONFLICTS("eAccelerator")
993    ZEND_MOD_CONFLICTS("Turck MMCache")
994    ZEND_MOD_END
995};
996#endif
997/* }}} */ 
998/* {{{ module definition structure */
999zend_module_entry xcache_module_entry = {
1000#ifdef STANDARD_MODULE_HEADER_EX
1001    STANDARD_MODULE_HEADER_EX,
1002    NULL,
1003    xcache_module_deps,
1004#else
1005    STANDARD_MODULE_HEADER,
1006#endif
1007    XCACHE_NAME,
1008    xcache_functions,
1009    PHP_MINIT(xcache),
1010    PHP_MSHUTDOWN(xcache),
1011    NULL, /* RINIT */
1012    NULL, /* RSHUTDOWN */
1013    PHP_MINFO(xcache),
1014    XCACHE_VERSION,
1015#ifdef PHP_GINIT
1016    PHP_MODULE_GLOBALS(xcache),
1017    PHP_GINIT(xcache),
1018    PHP_GSHUTDOWN(xcache),
1019#endif
1020#ifdef ZEND_ENGINE_2
1021    NULL /* ZEND_MODULE_POST_ZEND_DEACTIVATE_N */,
1022#else
1023    NULL,
1024    NULL,
1025#endif
1026    STANDARD_MODULE_PROPERTIES_EX
1027};
1028
1029#ifdef COMPILE_DL_XCACHE
1030ZEND_GET_MODULE(xcache)
1031#endif
1032/* }}} */
Note: See TracBrowser for help on using the repository browser.