Browse Source

initial import to online

git-svn-id: svn://svn.lighttpd.net/xcache/trunk@1 c26eb9a1-5813-0410-bd6c-c2e55f420ca7
tags/1.0.0
Xuefer 14 years ago
commit
4389208e02
53 changed files with 8716 additions and 0 deletions
  1. +2
    -0
      .vimrc
  2. +1886
    -0
      Decompiler.class.php
  3. +26
    -0
      INSTALL
  4. +28
    -0
      Makefile.frag
  5. +18
    -0
      align.h
  6. +0
    -0
      assembler.c
  7. +61
    -0
      config.m4
  8. +114
    -0
      const_string.c
  9. +8
    -0
      const_string.h
  10. +116
    -0
      const_string_opcodes_php4.x.h
  11. +154
    -0
      const_string_opcodes_php5.1.h
  12. +155
    -0
      const_string_opcodes_php6.x.h
  13. +425
    -0
      coverage.c
  14. +11
    -0
      coverage.h
  15. +0
    -0
      decoder.c
  16. +154
    -0
      disassembler.c
  17. +4
    -0
      disassembler.h
  18. +0
    -0
      encoder.c
  19. +2
    -0
      includes.c
  20. +129
    -0
      lock.c
  21. +11
    -0
      lock.h
  22. +43
    -0
      make.devel
  23. +7
    -0
      make.inc.example
  24. +268
    -0
      mem.c
  25. +20
    -0
      mem.h
  26. +72
    -0
      mkopcode.awk
  27. +39
    -0
      mkopcode_spec.awk
  28. +82
    -0
      mkstructinfo.awk
  29. +191
    -0
      mmap.c
  30. +13
    -0
      myshm.h
  31. +41
    -0
      opcode_spec.c
  32. +43
    -0
      opcode_spec.h
  33. +27
    -0
      optimizer.c
  34. +4
    -0
      optimizer.h
  35. +30
    -0
      phpdc.phpr
  36. +118
    -0
      phpdop.phpr
  37. +1
    -0
      processor.c
  38. +27
    -0
      processor/dispatch.m4
  39. +140
    -0
      processor/hashtable.m4
  40. +311
    -0
      processor/head.m4
  41. +210
    -0
      processor/main.m4
  42. +710
    -0
      processor/processor.m4
  43. +88
    -0
      processor/string.m4
  44. +179
    -0
      processor/struct.m4
  45. +62
    -0
      stack.c
  46. +17
    -0
      stack.h
  47. +2
    -0
      test.php
  48. +401
    -0
      utils.c
  49. +48
    -0
      utils.h
  50. +1952
    -0
      xcache.c
  51. +208
    -0
      xcache.h
  52. +36
    -0
      xcache.ini
  53. +22
    -0
      xcache_globals.h

+ 2
- 0
.vimrc View File

@@ -0,0 +1,2 @@

au FileType m4 setlocal ts=2 sw=2 fdm=marker

+ 1886
- 0
Decompiler.class.php
File diff suppressed because it is too large
View File


+ 26
- 0
INSTALL View File

@@ -0,0 +1,26 @@
# vim:ts=4:sw=4
Installtion:

$ phpize --clean && phpize
$ ./configure --help
$ CFLAGS='your cflags' ./configure --enable-xcache --enable...
$ make
$ su
# make install
(update php.ini, restart php)

Reinstall:

$ mv config.nice conf
$ make distclean && phpize --clean && phpize
$ mv conf config.nice
$ ./config.nice
$ make
$ su
# make install
(update php.ini, restart php)

Update php.ini:
$ su
# cat xcache.ini >> /etc/php.ini
# $EDITOR /etc/php.ini

+ 28
- 0
Makefile.frag View File

@@ -0,0 +1,28 @@
XCACHE_PROC_SRC=$(srcdir)/processor/main.m4
XCACHE_PROC_OUT=$(builddir)/processor.out
XCACHE_PROC_C=$(builddir)/processor_real.c
XCACHE_PROC_H=$(builddir)/processor.h
XCACHE_INCLUDES_SRC=$(srcdir)/includes.c
XCACHE_INCLUDES_I=$(builddir)/includes.i
XCACHE_STRUCT_OUT=$(builddir)/structinfo.m4

$(XCACHE_INCLUDES_I): $(XCACHE_INCLUDES_SRC) $(srcdir)/xcache.h
$(CC) -I. -I$(srcdir) $(COMMON_FLAGS) $(CFLAGS_CLEAN) $(EXTRA_CFLAGS) -E $(XCACHE_INCLUDES_SRC) -o $(XCACHE_INCLUDES_I)

$(XCACHE_STRUCT_OUT): $(XCACHE_INCLUDES_I) $(srcdir)/mkstructinfo.awk
$(AWK) -f $(srcdir)/mkstructinfo.awk < $(XCACHE_INCLUDES_I) > $(XCACHE_STRUCT_OUT)

$(XCACHE_PROC_OUT): $(XCACHE_PROC_SRC) $(XCACHE_STRUCT_OUT) $(XCACHE_PROC_SOURCES)
m4 -I$(srcdir)/processor/ -I$(builddir)/ -I$(srcdir)/ $(XCACHE_ENABLE_TEST) -E $(XCACHE_PROC_SRC) > $(XCACHE_PROC_OUT).tmp && mv -f $(XCACHE_PROC_OUT).tmp $(XCACHE_PROC_OUT)

$(XCACHE_PROC_H): $(XCACHE_PROC_OUT)
grep -F 'export: ' $(XCACHE_PROC_OUT) | sed -r 's/.*export:(.*):export.*/\1/g' | $(XCACHE_INDENT) > $(XCACHE_PROC_H).tmp && mv -f $(XCACHE_PROC_H).tmp $(XCACHE_PROC_H)

$(XCACHE_PROC_C): $(XCACHE_PROC_OUT) $(XCACHE_PROC_H)
cat $(XCACHE_PROC_OUT) | $(XCACHE_INDENT) > $(XCACHE_PROC_C).tmp && mv -f $(XCACHE_PROC_C).tmp $(XCACHE_PROC_C)

$(builddir)/processor.lo: $(XCACHE_PROC_C) $(XCACHE_PROC_H) $(srcdir)/processor.c

$(builddir)/disassembler.lo: $(XCACHE_PROC_H) $(srcdir)/processor.c

$(builddir)/xcache.lo: $(XCACHE_PROC_H) $(srcdir)/myshm.h $(srcdir)/stack.h $(srcdir)/xcache_globals.h $(srcdir)/xcache.c

+ 18
- 0
align.h View File

@@ -0,0 +1,18 @@
#ifndef __ALIGN_H
#define __ALIGN_H
typedef union align_union {
double d;
void *v;
int (*func)(int);
long l;
} align_union;

#if (defined (__GNUC__) && __GNUC__ >= 2)
#define XCACHE_PLATFORM_ALIGNMENT (__alignof__ (align_union))
#else
#define XCACHE_PLATFORM_ALIGNMENT (sizeof(align_union))
#endif

#define ALIGN(n) ((((size_t)(n)-1) & ~(XCACHE_PLATFORM_ALIGNMENT-1)) + XCACHE_PLATFORM_ALIGNMENT)

#endif /* __ALIGN_H */

+ 0
- 0
assembler.c View File


+ 61
- 0
config.m4 View File

@@ -0,0 +1,61 @@
dnl
dnl $Id:$
dnl vim:ts=2:sw=2:expandtab

AC_DEFUN([XCACHE_OPTION], [
PHP_ARG_ENABLE(xcache-$1, for XCACHE $1,
[ --enable-xcache-$2 XCACHE: $4], no, no)
if test "$PHP_$3" = "yes"; then
xcache_sources="$xcache_sources $1.c"
AC_DEFINE([HAVE_$3], 1, [Define for XCACHE: $4])
fi
])dnl

PHP_ARG_ENABLE(xcache, for XCACHE support,
[ --enable-xcache Include XCACHE support.])

if test "$PHP_XCACHE" != "no"; then
xcache_sources="processor.c \
xcache.c \
mmap.c \
mem.c \
const_string.c \
opcode_spec.c \
stack.c \
utils.c \
lock.c \
"
XCACHE_OPTION([optimizer], [optimizer ], [XCACHE_OPTIMIZER], [(N/A)])
XCACHE_OPTION([coverage], [coverage ], [XCACHE_COVERAGE], [Enable code coverage dumper, NOT for production server])
XCACHE_OPTION([assembler], [assembler ], [XCACHE_ASSEMBLER], [(N/A)])
XCACHE_OPTION([disassembler], [disassembler], [XCACHE_DISASSEMBLER], [Enable opcode to php variable dumper, NOT for production server])
XCACHE_OPTION([encoder], [encoder ], [XCACHE_ENCODER], [(N/A)])
XCACHE_OPTION([decoder], [decoder ], [XCACHE_DECODER], [(N/A)])

PHP_NEW_EXTENSION(xcache, $xcache_sources, $ext_shared)
PHP_ADD_MAKEFILE_FRAGMENT()

PHP_ARG_ENABLE(xcache-test, for XCACHE self test,
[ --enable-xcache-test XCACHE: Enable self test - FOR DEVELOPERS ONLY!!], no, no)
if test "$PHP_XCACHE_TEST" = "yes"; then
XCACHE_ENABLE_TEST=-DXCACHE_ENABLE_TEST
AC_DEFINE([HAVE_XCACHE_TEST], 1, [Define to enable XCACHE self test])
else
XCACHE_ENABLE_TEST=
fi
PHP_SUBST([XCACHE_ENABLE_TEST])

AC_PATH_PROGS(INDENT, [indent cat])
case $INDENT in
*/indent[)]
XCACHE_INDENT="$INDENT -kr --use-tabs --tab-size 4 -sob -nce"
;;
*[)]
XCACHE_INDENT=cat
;;
esac
PHP_SUBST([XCACHE_INDENT])

XCACHE_PROC_SOURCES=`ls $ac_srcdir/processor/*.m4`
PHP_SUBST([XCACHE_PROC_SOURCES])
fi

+ 114
- 0
const_string.c View File

@@ -0,0 +1,114 @@
#include "xcache.h"
#include "const_string.h"

/* {{{ xc_get_op_type */
static const char *const op_type_names[] = {
/* 0 */ "NULL?",
/* 1 */ "IS_CONST",
/* 2 */ "IS_TMP_VAR",
/* 3 */ NULL,
/* 4 */ "IS_VAR",
/* 5 */ NULL,
/* 6 */ NULL,
/* 7 */ NULL,
/* 8 */ "IS_UNUSED",
#ifdef IS_CV
/* 9 */ NULL,
/* 10 */ NULL,
/* 11 */ NULL,
/* 12 */ NULL,
/* 13 */ NULL,
/* 14 */ NULL,
/* 15 */ NULL,
/* 16 */ "IS_CV"
#endif
};

int xc_get_op_type_count()
{
return sizeof(op_type_names) / sizeof(op_type_names[0]);
}

const char *xc_get_op_type(zend_uchar op_type)
{
assert(op_type < xc_get_op_type_count());
return op_type_names[op_type];
}
/* }}} */
/* {{{ xc_get_data_type */
static const char *const data_type_names[] = {
/* 0 */ "IS_NULL",
/* 1 */ "IS_LONG",
/* 2 */ "IS_DOUBLE",
/* 3 */ "IS_BOOL",
/* 4 */ "IS_ARRAY",
/* 5 */ "IS_OBJECT",
/* 6 */ "IS_STRING",
/* 7 */ "IS_RESOURCE",
/* 8 */ "IS_CONSTANT",
/* 9 */ "IS_CONSTANT_ARRAY",
/* 10 */ "IS_UNICODE",
#if 0
/* 11 */ "",
/* 12 */ "",
/* 13 */ "",
/* 14 */ "",
/* 15 */ "", "", "", "", "",

/* IS_CONSTANT_INDEX */
/* 20 */ "CIDX IS_NULL",
/* 21 */ "CIDX IS_LONG",
/* 22 */ "CIDX IS_DOUBLE",
/* 23 */ "CIDX IS_BOOL",
/* 24 */ "CIDX IS_ARRAY",
/* 25 */ "CIDX IS_OBJECT",
/* 26 */ "CIDX IS_STRING",
/* 27 */ "CIDX IS_RESOURCE",
/* 28 */ "CIDX IS_CONSTANT",
/* 29 */ "CIDX IS_CONSTANT_ARRAY"
/* 20 */ "CIDX IS_UNICODE",
#endif
};

int xc_get_data_type_count()
{
return sizeof(data_type_names) / sizeof(data_type_names[0]);
}

const char *xc_get_data_type(zend_uchar data_type)
{
#if 0
if (data_type & IS_CONSTANT_INDEX) {
data_type = (data_type & ~IS_CONSTANT_INDEX) + 20;
}
#endif
data_type &= ~IS_CONSTANT_INDEX;
return data_type_names[data_type];
}
/* }}} */
/* {{{ xc_get_opcode */
#if PHP_MAJAR_VERSION >= 6
# include "const_string_opcodes_php6.x.h"
#else
# ifdef ZEND_ENGINE_2_1
# include "const_string_opcodes_php5.1.h"
# else
# ifdef ZEND_ENGINE_2
# include "const_string_opcodes_php5.0.h"
# else
# include "const_string_opcodes_php4.x.h"
# endif
# endif
#endif

int xc_get_opcode_count()
{
return sizeof(xc_opcode_names) / sizeof(xc_opcode_names[0]);
}

const char *xc_get_opcode(zend_uchar opcode)
{
assert(opcode < xc_get_opcode_count());
return xc_opcode_names[opcode];
}
/* }}} */

+ 8
- 0
const_string.h View File

@@ -0,0 +1,8 @@
#include "php.h"

int xc_get_op_type_count();
const char *xc_get_op_type(zend_uchar op_type);
int xc_get_data_type_count();
const char *xc_get_data_type(zend_uchar data_type);
int xc_get_opcode_count();
const char *xc_get_opcode(zend_uchar opcode);

+ 116
- 0
const_string_opcodes_php4.x.h View File

@@ -0,0 +1,116 @@
/* size = 112 */
static const char *const xc_opcode_names[] = {
/* 0 */ "NOP",
/* 1 */ "ADD",
/* 2 */ "SUB",
/* 3 */ "MUL",
/* 4 */ "DIV",
/* 5 */ "MOD",
/* 6 */ "SL",
/* 7 */ "SR",
/* 8 */ "CONCAT",
/* 9 */ "BW_OR",
/* 10 */ "BW_AND",
/* 11 */ "BW_XOR",
/* 12 */ "BW_NOT",
/* 13 */ "BOOL_NOT",
/* 14 */ "BOOL_XOR",
/* 15 */ "IS_IDENTICAL",
/* 16 */ "IS_NOT_IDENTICAL",
/* 17 */ "IS_EQUAL",
/* 18 */ "IS_NOT_EQUAL",
/* 19 */ "IS_SMALLER",
/* 20 */ "IS_SMALLER_OR_EQUAL",
/* 21 */ "CAST",
/* 22 */ "QM_ASSIGN",
/* 23 */ "ASSIGN_ADD",
/* 24 */ "ASSIGN_SUB",
/* 25 */ "ASSIGN_MUL",
/* 26 */ "ASSIGN_DIV",
/* 27 */ "ASSIGN_MOD",
/* 28 */ "ASSIGN_SL",
/* 29 */ "ASSIGN_SR",
/* 30 */ "ASSIGN_CONCAT",
/* 31 */ "ASSIGN_BW_OR",
/* 32 */ "ASSIGN_BW_AND",
/* 33 */ "ASSIGN_BW_XOR",
/* 34 */ "PRE_INC",
/* 35 */ "PRE_DEC",
/* 36 */ "POST_INC",
/* 37 */ "POST_DEC",
/* 38 */ "ASSIGN",
/* 39 */ "ASSIGN_REF",
/* 40 */ "ECHO",
/* 41 */ "PRINT",
/* 42 */ "JMP",
/* 43 */ "JMPZ",
/* 44 */ "JMPNZ",
/* 45 */ "JMPZNZ",
/* 46 */ "JMPZ_EX",
/* 47 */ "JMPNZ_EX",
/* 48 */ "CASE",
/* 49 */ "SWITCH_FREE",
/* 50 */ "BRK",
/* 51 */ "CONT",
/* 52 */ "BOOL",
/* 53 */ "INIT_STRING",
/* 54 */ "ADD_CHAR",
/* 55 */ "ADD_STRING",
/* 56 */ "ADD_VAR",
/* 57 */ "BEGIN_SILENCE",
/* 58 */ "END_SILENCE",
/* 59 */ "INIT_FCALL_BY_NAME",
/* 60 */ "DO_FCALL",
/* 61 */ "DO_FCALL_BY_NAME",
/* 62 */ "RETURN",
/* 63 */ "RECV",
/* 64 */ "RECV_INIT",
/* 65 */ "SEND_VAL",
/* 66 */ "SEND_VAR",
/* 67 */ "SEND_REF",
/* 68 */ "NEW",
/* 69 */ "JMP_NO_CTOR",
/* 70 */ "FREE",
/* 71 */ "INIT_ARRAY",
/* 72 */ "ADD_ARRAY_ELEMENT",
/* 73 */ "INCLUDE_OR_EVAL",
/* 74 */ "UNSET_VAR",
/* 75 */ "UNSET_DIM_OBJ",
/* 76 */ "ISSET_ISEMPTY",
/* 77 */ "FE_RESET",
/* 78 */ "FE_FETCH",
/* 79 */ "EXIT",
/* 80 */ "FETCH_R",
/* 81 */ "FETCH_DIM_R",
/* 82 */ "FETCH_OBJ_R",
/* 83 */ "FETCH_W",
/* 84 */ "FETCH_DIM_W",
/* 85 */ "FETCH_OBJ_W",
/* 86 */ "FETCH_RW",
/* 87 */ "FETCH_DIM_RW",
/* 88 */ "FETCH_OBJ_RW",
/* 89 */ "FETCH_IS",
/* 90 */ "FETCH_DIM_IS",
/* 91 */ "FETCH_OBJ_IS",
/* 92 */ "FETCH_FUNC_ARG",
/* 93 */ "FETCH_DIM_FUNC_ARG",
/* 94 */ "FETCH_OBJ_FUNC_ARG",
/* 95 */ "FETCH_UNSET",
/* 96 */ "FETCH_DIM_UNSET",
/* 97 */ "FETCH_OBJ_UNSET",
/* 98 */ "FETCH_DIM_TMP_VAR",
/* 99 */ "FETCH_CONSTANT",
/* 100 */ "DECLARE_FUNCTION_OR_CLASS",
/* 101 */ "EXT_STMT",
/* 102 */ "EXT_FCALL_BEGIN",
/* 103 */ "EXT_FCALL_END",
/* 104 */ "EXT_NOP",
/* 105 */ "TICKS",
/* 106 */ "SEND_VAR_NO_REF",
/* 107 */ "UNDEF",
/* 108 */ "UNDEF",
/* 109 */ "UNDEF",
/* 110 */ "DO_FCALL_BY_FUNC",
/* 111 */ "INIT_FCALL_BY_FUNC",
/* 112 */ "UNDEF"
};

+ 154
- 0
const_string_opcodes_php5.1.h View File

@@ -0,0 +1,154 @@
/* size = 150 */
static const char *const xc_opcode_names[] = {
/* 0 */ "NOP",
/* 1 */ "ADD",
/* 2 */ "SUB",
/* 3 */ "MUL",
/* 4 */ "DIV",
/* 5 */ "MOD",
/* 6 */ "SL",
/* 7 */ "SR",
/* 8 */ "CONCAT",
/* 9 */ "BW_OR",
/* 10 */ "BW_AND",
/* 11 */ "BW_XOR",
/* 12 */ "BW_NOT",
/* 13 */ "BOOL_NOT",
/* 14 */ "BOOL_XOR",
/* 15 */ "IS_IDENTICAL",
/* 16 */ "IS_NOT_IDENTICAL",
/* 17 */ "IS_EQUAL",
/* 18 */ "IS_NOT_EQUAL",
/* 19 */ "IS_SMALLER",
/* 20 */ "IS_SMALLER_OR_EQUAL",
/* 21 */ "CAST",
/* 22 */ "QM_ASSIGN",
/* 23 */ "ASSIGN_ADD",
/* 24 */ "ASSIGN_SUB",
/* 25 */ "ASSIGN_MUL",
/* 26 */ "ASSIGN_DIV",
/* 27 */ "ASSIGN_MOD",
/* 28 */ "ASSIGN_SL",
/* 29 */ "ASSIGN_SR",
/* 30 */ "ASSIGN_CONCAT",
/* 31 */ "ASSIGN_BW_OR",
/* 32 */ "ASSIGN_BW_AND",
/* 33 */ "ASSIGN_BW_XOR",
/* 34 */ "PRE_INC",
/* 35 */ "PRE_DEC",
/* 36 */ "POST_INC",
/* 37 */ "POST_DEC",
/* 38 */ "ASSIGN",
/* 39 */ "ASSIGN_REF",
/* 40 */ "ECHO",
/* 41 */ "PRINT",
/* 42 */ "JMP",
/* 43 */ "JMPZ",
/* 44 */ "JMPNZ",
/* 45 */ "JMPZNZ",
/* 46 */ "JMPZ_EX",
/* 47 */ "JMPNZ_EX",
/* 48 */ "CASE",
/* 49 */ "SWITCH_FREE",
/* 50 */ "BRK",
/* 51 */ "CONT",
/* 52 */ "BOOL",
/* 53 */ "INIT_STRING",
/* 54 */ "ADD_CHAR",
/* 55 */ "ADD_STRING",
/* 56 */ "ADD_VAR",
/* 57 */ "BEGIN_SILENCE",
/* 58 */ "END_SILENCE",
/* 59 */ "INIT_FCALL_BY_NAME",
/* 60 */ "DO_FCALL",
/* 61 */ "DO_FCALL_BY_NAME",
/* 62 */ "RETURN",
/* 63 */ "RECV",
/* 64 */ "RECV_INIT",
/* 65 */ "SEND_VAL",
/* 66 */ "SEND_VAR",
/* 67 */ "SEND_REF",
/* 68 */ "NEW",
/* 69 */ "UNDEF",
/* 70 */ "FREE",
/* 71 */ "INIT_ARRAY",
/* 72 */ "ADD_ARRAY_ELEMENT",
/* 73 */ "INCLUDE_OR_EVAL",
/* 74 */ "UNSET_VAR",
/* 75 */ "UNSET_DIM",
/* 76 */ "UNSET_OBJ",
/* 77 */ "FE_RESET",
/* 78 */ "FE_FETCH",
/* 79 */ "EXIT",
/* 80 */ "FETCH_R",
/* 81 */ "FETCH_DIM_R",
/* 82 */ "FETCH_OBJ_R",
/* 83 */ "FETCH_W",
/* 84 */ "FETCH_DIM_W",
/* 85 */ "FETCH_OBJ_W",
/* 86 */ "FETCH_RW",
/* 87 */ "FETCH_DIM_RW",
/* 88 */ "FETCH_OBJ_RW",
/* 89 */ "FETCH_IS",
/* 90 */ "FETCH_DIM_IS",
/* 91 */ "FETCH_OBJ_IS",
/* 92 */ "FETCH_FUNC_ARG",
/* 93 */ "FETCH_DIM_FUNC_ARG",
/* 94 */ "FETCH_OBJ_FUNC_ARG",
/* 95 */ "FETCH_UNSET",
/* 96 */ "FETCH_DIM_UNSET",
/* 97 */ "FETCH_OBJ_UNSET",
/* 98 */ "FETCH_DIM_TMP_VAR",
/* 99 */ "FETCH_CONSTANT",
/* 100 */ "UNDEF",
/* 101 */ "EXT_STMT",
/* 102 */ "EXT_FCALL_BEGIN",
/* 103 */ "EXT_FCALL_END",
/* 104 */ "EXT_NOP",
/* 105 */ "TICKS",
/* 106 */ "SEND_VAR_NO_REF",
/* 107 */ "CATCH",
/* 108 */ "THROW",
/* 109 */ "FETCH_CLASS",
/* 110 */ "CLONE",
/* 111 */ "UNDEF",
/* 112 */ "INIT_METHOD_CALL",
/* 113 */ "INIT_STATIC_METHOD_CALL",
/* 114 */ "ISSET_ISEMPTY_VAR",
/* 115 */ "ISSET_ISEMPTY_DIM_OBJ",
/* 116 */ "UNDEF",
/* 117 */ "UNDEF",
/* 118 */ "UNDEF",
/* 119 */ "UNDEF",
/* 120 */ "UNDEF",
/* 121 */ "UNDEF",
/* 122 */ "UNDEF",
/* 123 */ "UNDEF",
/* 124 */ "UNDEF",
/* 125 */ "UNDEF",
/* 126 */ "UNDEF",
/* 127 */ "UNDEF",
/* 128 */ "UNDEF",
/* 129 */ "UNDEF",
/* 130 */ "UNDEF",
/* 131 */ "UNDEF",
/* 132 */ "PRE_INC_OBJ",
/* 133 */ "PRE_DEC_OBJ",
/* 134 */ "POST_INC_OBJ",
/* 135 */ "POST_DEC_OBJ",
/* 136 */ "ASSIGN_OBJ",
/* 137 */ "OP_DATA",
/* 138 */ "INSTANCEOF",
/* 139 */ "DECLARE_CLASS",
/* 140 */ "DECLARE_INHERITED_CLASS",
/* 141 */ "DECLARE_FUNCTION",
/* 142 */ "RAISE_ABSTRACT_ERROR",
/* 143 */ "UNDEF",
/* 144 */ "ADD_INTERFACE",
/* 145 */ "UNDEF",
/* 146 */ "VERIFY_ABSTRACT_CLASS",
/* 147 */ "ASSIGN_DIM",
/* 148 */ "ISSET_ISEMPTY_PROP_OBJ",
/* 149 */ "HANDLE_EXCEPTION",
/* 150 */ "USER_OPCODE"
};

+ 155
- 0
const_string_opcodes_php6.x.h View File

@@ -0,0 +1,155 @@
/* size = 151 */
static const char *const xc_opcode_names[] = {
/* 0 */ "NOP",
/* 1 */ "ADD",
/* 2 */ "SUB",
/* 3 */ "MUL",
/* 4 */ "DIV",
/* 5 */ "MOD",
/* 6 */ "SL",
/* 7 */ "SR",
/* 8 */ "CONCAT",
/* 9 */ "BW_OR",
/* 10 */ "BW_AND",
/* 11 */ "BW_XOR",
/* 12 */ "BW_NOT",
/* 13 */ "BOOL_NOT",
/* 14 */ "BOOL_XOR",
/* 15 */ "IS_IDENTICAL",
/* 16 */ "IS_NOT_IDENTICAL",
/* 17 */ "IS_EQUAL",
/* 18 */ "IS_NOT_EQUAL",
/* 19 */ "IS_SMALLER",
/* 20 */ "IS_SMALLER_OR_EQUAL",
/* 21 */ "CAST",
/* 22 */ "QM_ASSIGN",
/* 23 */ "ASSIGN_ADD",
/* 24 */ "ASSIGN_SUB",
/* 25 */ "ASSIGN_MUL",
/* 26 */ "ASSIGN_DIV",
/* 27 */ "ASSIGN_MOD",
/* 28 */ "ASSIGN_SL",
/* 29 */ "ASSIGN_SR",
/* 30 */ "ASSIGN_CONCAT",
/* 31 */ "ASSIGN_BW_OR",
/* 32 */ "ASSIGN_BW_AND",
/* 33 */ "ASSIGN_BW_XOR",
/* 34 */ "PRE_INC",
/* 35 */ "PRE_DEC",
/* 36 */ "POST_INC",
/* 37 */ "POST_DEC",
/* 38 */ "ASSIGN",
/* 39 */ "ASSIGN_REF",
/* 40 */ "ECHO",
/* 41 */ "PRINT",
/* 42 */ "JMP",
/* 43 */ "JMPZ",
/* 44 */ "JMPNZ",
/* 45 */ "JMPZNZ",
/* 46 */ "JMPZ_EX",
/* 47 */ "JMPNZ_EX",
/* 48 */ "CASE",
/* 49 */ "SWITCH_FREE",
/* 50 */ "BRK",
/* 51 */ "CONT",
/* 52 */ "BOOL",
/* 53 */ "INIT_STRING",
/* 54 */ "ADD_CHAR",
/* 55 */ "ADD_STRING",
/* 56 */ "ADD_VAR",
/* 57 */ "BEGIN_SILENCE",
/* 58 */ "END_SILENCE",
/* 59 */ "INIT_FCALL_BY_NAME",
/* 60 */ "DO_FCALL",
/* 61 */ "DO_FCALL_BY_NAME",
/* 62 */ "RETURN",
/* 63 */ "RECV",
/* 64 */ "RECV_INIT",
/* 65 */ "SEND_VAL",
/* 66 */ "SEND_VAR",
/* 67 */ "SEND_REF",
/* 68 */ "NEW",
/* 69 */ "UNDEF",
/* 70 */ "FREE",
/* 71 */ "INIT_ARRAY",
/* 72 */ "ADD_ARRAY_ELEMENT",
/* 73 */ "INCLUDE_OR_EVAL",
/* 74 */ "UNSET_VAR",
/* 75 */ "UNSET_DIM",
/* 76 */ "UNSET_OBJ",
/* 77 */ "FE_RESET",
/* 78 */ "FE_FETCH",
/* 79 */ "EXIT",
/* 80 */ "FETCH_R",
/* 81 */ "FETCH_DIM_R",
/* 82 */ "FETCH_OBJ_R",
/* 83 */ "FETCH_W",
/* 84 */ "FETCH_DIM_W",
/* 85 */ "FETCH_OBJ_W",
/* 86 */ "FETCH_RW",
/* 87 */ "FETCH_DIM_RW",
/* 88 */ "FETCH_OBJ_RW",
/* 89 */ "FETCH_IS",
/* 90 */ "FETCH_DIM_IS",
/* 91 */ "FETCH_OBJ_IS",
/* 92 */ "FETCH_FUNC_ARG",
/* 93 */ "FETCH_DIM_FUNC_ARG",
/* 94 */ "FETCH_OBJ_FUNC_ARG",
/* 95 */ "FETCH_UNSET",
/* 96 */ "FETCH_DIM_UNSET",
/* 97 */ "FETCH_OBJ_UNSET",
/* 98 */ "FETCH_DIM_TMP_VAR",
/* 99 */ "FETCH_CONSTANT",
/* 100 */ "UNDEF",
/* 101 */ "EXT_STMT",
/* 102 */ "EXT_FCALL_BEGIN",
/* 103 */ "EXT_FCALL_END",
/* 104 */ "EXT_NOP",
/* 105 */ "TICKS",
/* 106 */ "SEND_VAR_NO_REF",
/* 107 */ "CATCH",
/* 108 */ "THROW",
/* 109 */ "FETCH_CLASS",
/* 110 */ "CLONE",
/* 111 */ "UNDEF",
/* 112 */ "INIT_METHOD_CALL",
/* 113 */ "INIT_STATIC_METHOD_CALL",
/* 114 */ "ISSET_ISEMPTY_VAR",
/* 115 */ "ISSET_ISEMPTY_DIM_OBJ",
/* 116 */ "UNDEF",
/* 117 */ "UNDEF",
/* 118 */ "UNDEF",
/* 119 */ "UNDEF",
/* 120 */ "UNDEF",
/* 121 */ "UNDEF",
/* 122 */ "UNDEF",
/* 123 */ "UNDEF",
/* 124 */ "UNDEF",
/* 125 */ "UNDEF",
/* 126 */ "UNDEF",
/* 127 */ "UNDEF",
/* 128 */ "UNDEF",
/* 129 */ "UNDEF",
/* 130 */ "UNDEF",
/* 131 */ "UNDEF",
/* 132 */ "PRE_INC_OBJ",
/* 133 */ "PRE_DEC_OBJ",
/* 134 */ "POST_INC_OBJ",
/* 135 */ "POST_DEC_OBJ",
/* 136 */ "ASSIGN_OBJ",
/* 137 */ "OP_DATA",
/* 138 */ "INSTANCEOF",
/* 139 */ "DECLARE_CLASS",
/* 140 */ "DECLARE_INHERITED_CLASS",
/* 141 */ "DECLARE_FUNCTION",
/* 142 */ "RAISE_ABSTRACT_ERROR",
/* 143 */ "UNDEF",
/* 144 */ "ADD_INTERFACE",
/* 145 */ "UNDEF",
/* 146 */ "VERIFY_ABSTRACT_CLASS",
/* 147 */ "ASSIGN_DIM",
/* 148 */ "ISSET_ISEMPTY_PROP_OBJ",
/* 149 */ "HANDLE_EXCEPTION",
/* 150 */ "USER_OPCODE",
/* 151 */ "U_NORMALIZE"
};

+ 425
- 0
coverage.c View File

@@ -0,0 +1,425 @@
#include <stdio.h>
#include "xcache.h"
#include "ext/standard/flock_compat.h"
#ifdef HAVE_SYS_FILE_H
# include <sys/file.h>
#endif
#include "stack.h"
#include "xcache_globals.h"
#include "coverage.h"
#include "utils.h"
typedef HashTable *coverage_t;
#define PCOV_HEADER_MAGIC 0x564f4350

char *xc_coveragedump_dir = NULL;
static zend_compile_file_t *origin_compile_file;

#undef DEBUG
/* dumper */
static void xc_destroy_coverage(void *pDest) /* {{{ */
{
coverage_t cov = *(coverage_t*) pDest;
#ifdef DEBUG
fprintf(stderr, "destroy %p\n", cov);
#endif
zend_hash_destroy(cov);
efree(cov);
}
/* }}} */
PHPAPI void xcache_mkdirs_ex(char *root, int rootlen, char *path, int pathlen TSRMLS_DC) /* {{{ */
{
char *fullpath;
struct stat st;

#ifdef DEBUG
fprintf(stderr, "mkdirs %s %d %s %d\n", root, rootlen, path, pathlen);
#endif
fullpath = do_alloca(rootlen + pathlen + 1);
memcpy(fullpath, root, rootlen);
memcpy(fullpath + rootlen, path, pathlen);
fullpath[rootlen + pathlen] = '\0';

if (stat(fullpath, &st) != 0) {
char *chr;

chr = strrchr(path, PHP_DIR_SEPARATOR);
if (chr && chr != path) {
*chr = '\0';
xcache_mkdirs_ex(root, rootlen, path, chr - path TSRMLS_CC);
*chr = PHP_DIR_SEPARATOR;
}
#ifdef DEBUG
fprintf(stderr, "mkdir %s\n", fullpath);
#endif
php_stream_mkdir(fullpath, 0700, REPORT_ERRORS, NULL);
}
free_alloca(fullpath);
}
/* }}} */
static void xc_coverage_save_cov(char *srcfile, char *outfilename, coverage_t cov TSRMLS_DC) /* {{{ */
{
long *buf = NULL, *p;
long covlines, *phits;
int fd = -1;
int size;
int newfile;
struct stat srcstat, outstat;
HashPosition pos;
char *contents = NULL;
long len;

if (stat(srcfile, &srcstat) != 0) {
return;
}

newfile = 0;
if (stat(outfilename, &outstat) != 0) {
newfile = 1;
}
else {
if (srcstat.st_mtime > outstat.st_mtime) {
newfile = 1;
}
}

fd = open(outfilename, O_RDWR | O_CREAT, 0600);
if (fd < 0) {
char *chr;
chr = strrchr(srcfile, PHP_DIR_SEPARATOR);
if (chr) {
*chr = '\0';
xcache_mkdirs_ex(xc_coveragedump_dir, strlen(xc_coveragedump_dir), srcfile, chr - srcfile TSRMLS_CC);
*chr = PHP_DIR_SEPARATOR;
}
fd = open(outfilename, O_RDWR | O_CREAT, 0600);
if (fd < 0) {
goto bailout;
}
}
if (flock(fd, LOCK_EX) != SUCCESS) {
goto bailout;
}

if (newfile) {
#ifdef DEBUG
fprintf(stderr, "new file\n");
#endif
}
else if (outstat.st_size) {
len = outstat.st_size;
contents = emalloc(len);
if (read(fd, (void *) contents, len) != len) {
goto bailout;
}
#ifdef DEBUG
fprintf(stderr, "oldsize %d\n", (int) len);
#endif
do {
p = (long *) contents;
len -= sizeof(long);
if (len < 0) {
break;
}
if (*p++ != PCOV_HEADER_MAGIC) {
#ifdef DEBUG
fprintf(stderr, "wrong magic in file %s\n", outfilename);
#endif
break;
}

p += 2; /* skip covliens */
len -= sizeof(long) * 2;
if (len < 0) {
break;
}

for (; len >= sizeof(long) * 2; len -= sizeof(long) * 2, p += 2) {
if (zend_hash_index_find(cov, p[0], (void**)&phits) == SUCCESS) {
if (p[1] <= 0) {
/* already marked */
continue;
}
if (*phits > 0) {
p[1] += *phits;
}
}
zend_hash_index_update(cov, p[0], &p[1], sizeof(p[1]), NULL);
}
} while (0);
efree(contents);
contents = NULL;
}


/* serialize */
size = (zend_hash_num_elements(cov) + 1) * sizeof(long) * 2 + sizeof(long);
p = buf = emalloc(size);
*p++ = PCOV_HEADER_MAGIC;
p += 2; /* for covlines */
covlines = 0;

zend_hash_internal_pointer_reset_ex(cov, &pos);
while (zend_hash_get_current_data_ex(cov, (void**)&phits, &pos) == SUCCESS) {
*p++ = pos->h;
if (*phits <= 0) {
*p++ = 0;
}
else {
*p++ = *phits;
covlines ++;
}
zend_hash_move_forward_ex(cov, &pos);
}
p = buf + 1;
p[0] = 0;
p[1] = covlines;

ftruncate(fd, 0);
lseek(fd, 0, SEEK_SET);
write(fd, (char *) buf, size);

bailout:
if (contents) efree(contents);
if (fd >= 0) close(fd);
if (buf) efree(buf);
}
/* }}} */
void xc_coverage_request_init(TSRMLS_D) /* {{{ */
{
if (XG(coveragedumper)) {
XG(coverages) = emalloc(sizeof(HashTable));
zend_hash_init(XG(coverages), 0, NULL, xc_destroy_coverage, 0);
}
}
/* }}} */
void xc_coverage_request_shutdown(TSRMLS_D) /* {{{ */
{
coverage_t *pcov;
zstr s;
char *outfilename;
int dumpdir_len, outfilelen, size, alloc_len = 0;

if (!XG(coverages)) {
return;
}
if (XG(coveragedumper)) {
dumpdir_len = strlen(xc_coveragedump_dir);
alloc_len = dumpdir_len + 1 + 128;
outfilename = emalloc(alloc_len);
strcpy(outfilename, xc_coveragedump_dir);

zend_hash_internal_pointer_reset(XG(coverages));
while (zend_hash_get_current_data(XG(coverages), (void **) &pcov) == SUCCESS) {
zend_hash_get_current_key_ex(XG(coverages), &s, &size, NULL, 0, NULL);
outfilelen = dumpdir_len + size + 5;
if (alloc_len < outfilelen) {
alloc_len = outfilelen + 128;
outfilename = erealloc(outfilename, alloc_len);
}
strcpy(outfilename + dumpdir_len, ZSTR_S(s));
strcpy(outfilename + dumpdir_len + size - 1, ".pcov");

#ifdef DEBUG
fprintf(stderr, "outfilename %s\n", outfilename);
#endif
xc_coverage_save_cov(ZSTR_S(s), outfilename, *pcov TSRMLS_CC);
zend_hash_move_forward(XG(coverages));
}
}

zend_hash_destroy(XG(coverages));
efree(XG(coverages));
XG(coverages) = NULL;
}
/* }}} */

/* helper func to store hits into coverages */
static coverage_t xc_coverage_get(char *filename TSRMLS_DC) /* {{{ */
{
int len = strlen(filename) + 1;
coverage_t cov, *pcov;

if (zend_hash_find(XG(coverages), filename, len, (void **) &pcov) == SUCCESS) {
#ifdef DEBUG
fprintf(stderr, "got coverage %s %p\n", filename, *pcov);
#endif
return *pcov;
}
else {
cov = emalloc(sizeof(HashTable));
zend_hash_init(cov, 0, NULL, NULL, 0);
zend_hash_add(XG(coverages), filename, len, (void **) &cov, sizeof(cov), NULL);
#ifdef DEBUG
fprintf(stderr, "new coverage %s %p\n", filename, cov);
#endif
return cov;
}
}
/* }}} */
static void xc_coverage_add_hits(HashTable *cov, long line, long hits TSRMLS_DC) /* {{{ */
{
long *poldhits;

if (line == 0) {
return;
}
if (zend_hash_index_find(cov, line, (void**)&poldhits) == SUCCESS) {
if (hits == -1) {
/* already marked */
return;
}
if (*poldhits != -1) {
hits += *poldhits;
}
}
zend_hash_index_update(cov, line, &hits, sizeof(hits), NULL);
}
/* }}} */

static int xc_coverage_get_op_array_size_no_tail(zend_op_array *op_array) /* {{{ */
{
zend_uint size;

size = op_array->size;
#ifdef ZEND_ENGINE_2
if (op_array->opcodes[size - 1].opcode == ZEND_HANDLE_EXCEPTION) {
size --;
#endif
if (op_array->opcodes[size - 1].opcode == ZEND_RETURN) {
size --;
/* it's not real php statement */
if (op_array->opcodes[size - 1].opcode == ZEND_EXT_STMT) {
size --;
}
}
#ifdef ZEND_ENGINE_2
}
#endif
return size;
}
/* }}} */

/* prefill */
static int xc_coverage_init_op_array(zend_op_array *op_array TSRMLS_DC) /* {{{ */
{
zend_uint size;
coverage_t cov;
int i;

if (op_array->type != ZEND_USER_FUNCTION) {
return 0;
}

size = xc_coverage_get_op_array_size_no_tail(op_array);
cov = xc_coverage_get(op_array->filename);
for (i = 0; i < size; i++) {
switch (op_array->opcodes[i].opcode) {
case ZEND_EXT_STMT:
#if 0
case ZEND_EXT_FCALL_BEGIN:
case ZEND_EXT_FCALL_END:
#endif
xc_coverage_add_hits(cov, op_array->opcodes[i].lineno, -1 TSRMLS_CC);
break;
}
}
return 0;
}
/* }}} */
static void xc_coverage_init_compile_result(zend_op_array *op_array TSRMLS_DC) /* {{{ */
{
xc_compile_result_t cr;

xc_compile_result_init_cur(&cr, op_array TSRMLS_CC);
xc_apply_op_array(&cr, (apply_func_t) xc_coverage_init_op_array TSRMLS_CC);
xc_compile_result_free(&cr);
}
/* }}} */
static zend_op_array *xc_compile_file_for_coverage(zend_file_handle *h, int type TSRMLS_DC) /* {{{ */
{
zend_op_array *op_array;

op_array = origin_compile_file(h, type TSRMLS_CC);
if (XG(coveragedumper) && XG(coverages)) {
xc_coverage_init_compile_result(op_array TSRMLS_CC);
}
return op_array;
}
/* }}} */

/* hits */
void xc_coverage_handle_ext_stmt(zend_op_array *op_array, zend_uchar op) /* {{{ */
{
if (XG(coveragedumper) && XG(coverages)) {
TSRMLS_FETCH();
int size = xc_coverage_get_op_array_size_no_tail(op_array);
int oplineno = (*EG(opline_ptr)) - op_array->opcodes;
if (oplineno < size) {
xc_coverage_add_hits(xc_coverage_get(op_array->filename), (*EG(opline_ptr))->lineno, 1 TSRMLS_CC);
}
}
}
/* }}} */

/* init/destroy */
int xc_coverage_init(int module_number TSRMLS_DC) /* {{{ */
{
if (xc_coveragedump_dir) {
int len = strlen(xc_coveragedump_dir);
if (len) {
if (xc_coveragedump_dir[len - 1] == '/') {
xc_coveragedump_dir[len - 1] = '\0';
}
}
}
if (xc_coveragedump_dir && xc_coveragedump_dir[0]) {
origin_compile_file = zend_compile_file;
zend_compile_file = xc_compile_file_for_coverage;
CG(extended_info) = 1;
}
return SUCCESS;
}
/* }}} */
void xc_coverage_destroy() /* {{{ */
{
if (origin_compile_file == xc_compile_file_for_coverage) {
zend_compile_file = origin_compile_file;
}
if (xc_coveragedump_dir) {
pefree(xc_coveragedump_dir, 1);
xc_coveragedump_dir = NULL;
}
}
/* }}} */

/* user api */
PHP_FUNCTION(xcache_coverage_decode) /* {{{ */
{
char *str;
int len;
long *p;

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &len) == FAILURE) {
return;
}

array_init(return_value);

p = (long*) str;
len -= sizeof(long);
if (len < 0) {
return;
}
if (*p++ != PCOV_HEADER_MAGIC) {
#ifdef DEBUG
fprintf(stderr, "wrong magic in xcache_coverage_decode");
#endif
return;
}

for (; len >= sizeof(long) * 2; len -= sizeof(long) * 2, p += 2) {
add_index_long(return_value, p[0], p[1]);
}
}
/* }}} */


+ 11
- 0
coverage.h View File

@@ -0,0 +1,11 @@
#include "php.h"
#include "xcache.h"

extern char *xc_coveragedump_dir;

void xc_coverage_handle_ext_stmt(zend_op_array *op_array, zend_uchar op);
int xc_coverage_init(int module_number TSRMLS_DC);
void xc_coverage_destroy();
void xc_coverage_request_init(TSRMLS_D);
void xc_coverage_request_shutdown(TSRMLS_D);
PHP_FUNCTION(xcache_coverage_decode);

+ 0
- 0
decoder.c View File


+ 154
- 0
disassembler.c View File

@@ -0,0 +1,154 @@
#include "disassembler.h"
#include "xcache.h"
#include "utils.h"
#include "processor.h"

#define return_value dst

static void xc_dasm(zval *dst, zend_op_array *op_array TSRMLS_DC) /* {{{ */
{
Bucket *b;
zval *zv, *list;
xc_compile_result_t cr;
int bufsize = 2;
char *buf;
int keysize;

xc_compile_result_init_cur(&cr, op_array TSRMLS_CC);

xc_apply_op_array(&cr, (apply_func_t) xc_undo_pass_two TSRMLS_CC);
xc_apply_op_array(&cr, (apply_func_t) xc_fix_opcode TSRMLS_CC);

/* go */
array_init(dst);

ALLOC_INIT_ZVAL(zv);
array_init(zv);
xc_dasm_zend_op_array(zv, op_array TSRMLS_CC);
add_assoc_zval_ex(dst, ZEND_STRS("op_array"), zv);

ALLOC_INIT_ZVAL(list);
array_init(list);
xc_dasm_HashTable_zend_function(list, CG(function_table) TSRMLS_CC);
add_assoc_zval_ex(dst, ZEND_STRS("function_table"), list);
buf = emalloc(bufsize);
ALLOC_INIT_ZVAL(list);
array_init(list);
for (b = CG(class_table)->pListHead; b; b = b->pListNext) {
ALLOC_INIT_ZVAL(zv);
array_init(zv);
xc_dasm_zend_class_entry(zv, CestToCePtr(*(xc_cest_t *)b->pData) TSRMLS_CC);

keysize = BUCKET_KEY_SIZE(b) + 2;
if (keysize > bufsize) {
do {
bufsize *= 2;
} while (keysize > bufsize);
buf = erealloc(buf, bufsize);
}
memcpy(buf, BUCKET_KEY(b), keysize);
buf[keysize - 2] = buf[keysize - 1] = ""[0];
keysize = b->nKeyLength;
#ifdef IS_UNICODE
if (BUCKET_KEY_TYPE(b) == IS_UNICODE) {
if (buf[0] == ""[0] && buf[1] == ""[0]) {
keysize ++;
}
} else
#endif
{
if (buf[0] == ""[0]) {
keysize ++;
}
}
add_u_assoc_zval_ex(list, BUCKET_KEY_TYPE(b), buf, b->nKeyLength, zv);
}
efree(buf);
add_assoc_zval_ex(dst, ZEND_STRS("class_table"), list);

/*xc_apply_op_array(&cr, (apply_func_t) xc_redo_pass_two TSRMLS_CC);*/
xc_compile_result_free(&cr);

return;
}
/* }}} */
void xc_dasm_string(zval *dst, zval *source TSRMLS_DC) /* {{{ */
{
int catched;
zend_op_array *op_array = NULL;
xc_sandbox_t sandbox;
char *eval_name = zend_make_compiled_string_description("runtime-created function" TSRMLS_CC);

xc_sandbox_init(&sandbox, eval_name TSRMLS_CC);

catched = 0;
zend_try {
op_array = compile_string(source, eval_name TSRMLS_CC);
} zend_catch {
catched = 1;
} zend_end_try();

if (catched || !op_array) {
goto err_compile;
}

xc_dasm(dst, op_array TSRMLS_CC);

/* free */
efree(eval_name);
destroy_op_array(op_array TSRMLS_CC);
efree(op_array);
xc_sandbox_free(&sandbox, 0 TSRMLS_CC);
return;

err_compile:
efree(eval_name);
xc_sandbox_free(&sandbox, 0 TSRMLS_CC);

RETURN_FALSE;
}
/* }}} */
void xc_dasm_file(zval *dst, const char *filename TSRMLS_DC) /* {{{ */
{
int catched;
zend_op_array *op_array = NULL;
xc_sandbox_t sandbox;
zval *zfilename;

MAKE_STD_ZVAL(zfilename);
zfilename->value.str.val = estrdup(filename);
zfilename->value.str.len = strlen(filename);
zfilename->type = IS_STRING;

xc_sandbox_init(&sandbox, zfilename->value.str.val TSRMLS_CC);

catched = 0;
zend_try {
op_array = compile_filename(ZEND_REQUIRE, zfilename TSRMLS_CC);
} zend_catch {
catched = 1;
} zend_end_try();

if (catched || !op_array) {
goto err_compile;
}

xc_dasm(dst, op_array TSRMLS_CC);

/* free */
destroy_op_array(op_array TSRMLS_CC);
efree(op_array);
xc_sandbox_free(&sandbox, 0 TSRMLS_CC);
zval_dtor(zfilename);
FREE_ZVAL(zfilename);
return;

err_compile:
xc_sandbox_free(&sandbox, 0 TSRMLS_CC);

zval_dtor(zfilename);
FREE_ZVAL(zfilename);
RETURN_FALSE;
}
/* }}} */

+ 4
- 0
disassembler.h View File

@@ -0,0 +1,4 @@
#include "php.h"

void xc_dasm_string(zval *return_value, zval *code TSRMLS_DC);
void xc_dasm_file(zval *return_value, const char *filename TSRMLS_DC);

+ 0
- 0
encoder.c View File


+ 2
- 0
includes.c View File

@@ -0,0 +1,2 @@
#include "xcache.h"
#include "zend_compile.h"

+ 129
- 0
lock.c View File

@@ -0,0 +1,129 @@
#include <stdio.h>
#include <string.h>
#include <malloc.h>

#include <php.h>
#ifndef ZEND_WIN32
typedef int HANDLE;
#endif
#include "lock.h"

struct _xc_lock_t {
HANDLE fd;
char *pathname;
};

#ifndef ZEND_WIN32
# include <unistd.h>
# include <fcntl.h>
# include <errno.h>
static inline int dolock(xc_lock_t *lck, int type) /* {{{ */
{
int ret;
struct flock lock;

lock.l_type = type;
lock.l_start = 0;
lock.l_whence = SEEK_SET;
lock.l_len = 1;
lock.l_pid = 0;

do {
ret = fcntl(lck->fd, F_SETLKW, &lock);
} while (ret < 0 && errno == EINTR);
return ret;
}
/* }}} */
#define LCK_WR F_WRLCK
#define LCK_RD F_RDLCK
#define LCK_UN F_UNLCK
#define LCK_NB 0
#else

# include <win32/flock.h>
# include <io.h>
# include <fcntl.h>
# include <sys/types.h>
# include <sys/stat.h>
# define errno GetLastError()
static inline int dolock(xc_lock_t *lck, int type) /* {{{ */
{
static OVERLAPPED offset = {0, 0, 0, 0, NULL};

if (type == LCK_UN) {
return UnlockFileEx((HANDLE)fd, 0, 1, 0, &offset);
}
else {
return LockFileEx((HANDLE)fd, type, 0, 1, 0, &offset);
}
}
/* }}} */
#define LCK_WR LOCKFILE_EXCLUSIVE_LOCK
#define LCK_RD 0
#define LCK_UN 0
#define LCK_NB LOCKFILE_FAIL_IMMEDIATELY
#endif

xc_lock_t *xc_fcntl_init(const char *pathname) /* {{{ */
{
HANDLE fd;
char myname[sizeof("/tmp/.xcache.lock") - 1 + 20];

if (pathname == NULL) {
static int i = 0;
snprintf(myname, sizeof(myname) - 1, "/tmp/.xcache.%d.%d.lock", (int) getuid(), i ++);
pathname = myname;
}

fd = open(pathname, O_RDWR|O_CREAT, 0666);

if (fd > 0) {
xc_lock_t *lck = malloc(sizeof(lck[0]));
int size;

#ifndef __CYGWIN__
unlink(pathname);
#endif
lck->fd = fd;
size = strlen(pathname) + 1;
lck->pathname = malloc(size);
memcpy(lck->pathname, pathname, size);
return lck;
}
else {
fprintf(stderr, "xc_fcntl_create: open(%s, O_RDWR|O_CREAT, 0666) failed:", pathname);
return NULL;
}
}
/* }}} */
void xc_fcntl_destroy(xc_lock_t *lck) /* {{{ */
{
close(lck->fd);
#ifdef __CYGWIN__
unlink(lck->pathname);
#endif
free(lck->pathname);
free(lck);
}
/* }}} */
void xc_fcntl_lock(xc_lock_t *lck) /* {{{ */
{
if (dolock(lck, LCK_WR) < 0) {
fprintf(stderr, "xc_fcntl_lock failed errno:%d", errno);
}
}
/* }}} */
void xc_fcntl_rdlock(xc_lock_t *lck) /* {{{ */
{
if (dolock(lck, LCK_RD) < 0) {
fprintf(stderr, "xc_fcntl_lock failed errno:%d", errno);
}
}
/* }}} */
void xc_fcntl_unlock(xc_lock_t *lck) /* {{{ */
{
if (dolock(lck, LCK_UN) < 0) {
fprintf(stderr, "xc_fcntl_unlock failed errno:%d", errno);
}
}
/* }}} */

+ 11
- 0
lock.h View File

@@ -0,0 +1,11 @@
typedef struct _xc_lock_t xc_lock_t;

xc_lock_t *xc_fcntl_init(const char *pathname);
void xc_fcntl_destroy(xc_lock_t *lck);
void xc_fcntl_lock(xc_lock_t *lck);
void xc_fcntl_unlock(xc_lock_t *lck);

#define xc_lock_init(name) xc_fcntl_init(name)
#define xc_lock_destroy(fd) xc_fcntl_destroy(fd)
#define xc_lock(fd) xc_fcntl_lock(fd)
#define xc_unlock(fd) xc_fcntl_unlock(fd)

+ 43
- 0
make.devel View File

@@ -0,0 +1,43 @@
#!/usr/bin/make -if
# vim:syntax=make
SELF=MAKELEVEL=0 ./make.devel

# You should copy make.inc from make.inc.default
include make.inc

all: opcode_spec_def const_string tags

clean: clean_const_string
rm -f tags opcode_spec_def.h

const_string:
@-$(SELF) const_string_opcodes_php4.x.h
@-$(SELF) const_string_opcodes_php5.0.h
@-$(SELF) const_string_opcodes_php5.1.h
@-$(SELF) const_string_opcodes_php6.x.h

clean_const_string:
rm -f const_string_opcodes_php4.x.h const_string_opcodes_php5.0.h const_string_opcodes_php5.1.h const_string_opcodes_php6.x.h

const_string_opcodes_php4.x.h: $(PHP4_x_DIR)/Zend/zend_compile.h
./mkopcode.awk < $(PHP4_x_DIR)/Zend/zend_compile.h > const_string_opcodes_php4.x.h

const_string_opcodes_php5.0.h: $(PHP5_0_DIR)/Zend/zend_vm_def.h
./mkopcode.awk < $(PHP5_0_DIR)/Zend/zend_vm_def.h > const_string_opcodes_php5.0.h

const_string_opcodes_php5.1.h: $(PHP5_1_DIR)/Zend/zend_vm_def.h
./mkopcode.awk < $(PHP5_1_DIR)/Zend/zend_vm_def.h > const_string_opcodes_php5.1.h

const_string_opcodes_php6.x.h: $(PHP6_x_DIR)/Zend/zend_vm_def.h
./mkopcode.awk < $(PHP6_x_DIR)/Zend/zend_vm_def.h > const_string_opcodes_php6.x.h

tags:
test -d $(PHP_DEVEL_DIR) && ctags -R . $(PHP_DEVEL_DIR)/main $(PHP_DEVEL_DIR)/Zend $(PHP_DEVEL_DIR)/TSRM $(PHP_DEVEL_DIR)/ext/standard || ctags -R .

opcode_spec_def:
@-$(SELF) opcode_spec_def.h

opcode_spec_def.h: $(EA_DIR)/opcodes.c
./mkopcode_spec.awk < $(EA_DIR)/opcodes.c > opcode_spec_def.h \

.PHONY: const_string opcode_spec_def

+ 7
- 0
make.inc.example View File

@@ -0,0 +1,7 @@
# copy this file to make.inc before modifying
PHP4_x_DIR=
PHP5_0_DIR=
PHP5_1_DIR=
PHP6_x_DIR=

PHP_DEVEL_DIR=

+ 268
- 0
mem.c View File

@@ -0,0 +1,268 @@
#include <php.h>
#include <stdlib.h>
#include "mem.h"
#include "align.h"
#define PADD(p, a) (((char*)p) + a)

// {{{ mem
struct _xc_block_t {
#ifdef ALLOC_DEBUG
unsigned int magic;
#endif
xc_memsize_t size; /* reserved even after alloc */
xc_block_t *next; /* not used after alloc */
};

struct _xc_mem_t {
xc_memsize_t size;
xc_memsize_t avail; /* total free */
xc_block_t headblock[1]; /* just as a pointer to first block*/
};

#ifndef offsetof
# define offsetof(type, field) ((int) ((char *) &((type *) 0)->field))
#endif
#define SizeOf(type, field) sizeof( ((type *) 0)->field )
#define BLOCK_HEADER_SIZE() (ALIGN( offsetof(xc_block_t, size) + SizeOf(xc_block_t, size) ))

#define BLOCK_MAGIC ((unsigned int) 0x87655678)

/* }}} */
static inline void xc_block_setup(xc_block_t *b, xc_memsize_t size, xc_block_t *next) /* {{{ */
{
#ifdef ALLOC_DEBUG
b->magic = BLOCK_MAGIC;
#endif
b->size = size;
b->next = next;
}
/* }}} */
#ifdef ALLOC_DEBUG
static void xc_block_check(xc_block_t *b) /* {{{ */
{
if (b->magic != BLOCK_MAGIC) {
fprintf(stderr, "0x%X != 0x%X magic wrong \n", b->magic, BLOCK_MAGIC);
}
}
/* }}} */
#else
# define xc_block_check(b) do { } while(0)
#endif


void *xc_mem_malloc(xc_mem_t *mem, xc_memsize_t size) /* {{{ */
{
xc_block_t *prev, *cur;
xc_block_t *newb, *b;
xc_memsize_t realsize;
xc_memsize_t minsize;
void *p;
/* [xc_block_t:size|size] */
realsize = BLOCK_HEADER_SIZE() + size;
/* realsize is ALIGNed so next block start at ALIGNed address */
realsize = ALIGN(realsize);

do {
p = NULL;
if (mem->avail < realsize) {
break;
}

b = NULL;
minsize = INT_MAX;

/* prev|cur */

for (prev = mem->headblock; prev->next; prev = cur) {
/* while (prev->next != 0) { */
cur = prev->next;
xc_block_check(cur);
if (cur->size == realsize) {
/* found a perfect fit, stop searching */
b = prev;
break;
}
/* make sure we can split on the block */
else if (cur->size > (sizeof(xc_block_t) + realsize) &&
cur->size < minsize) {
/* cur is acceptable and memller */
b = prev;
minsize = cur->size;
}
prev = cur;
}

if (b == NULL) {
break;
}

prev = b;

cur = prev->next;
p = PADD(cur, BLOCK_HEADER_SIZE());

/* update the block header */
mem->avail -= realsize;

/*perfect fit, just unlink */
if (cur->size == realsize) {
prev->next = cur->next;
break;
}

/* make new free block after alloced space */

/* save, as it might be overwrited by newb (cur->size is ok) */
b = cur->next;

/* prev|cur |next=b */

newb = (xc_block_t *)PADD(cur, realsize);
xc_block_setup(newb, cur->size - realsize, b);
cur->size = realsize;
/* prev|cur|newb|next
* `--^
*/

#ifdef ALLOC_DEBUG
fprintf(stderr, "avail: %d (%dKB). size: %d %d (%dKB) new next: %p offset: %d %dKB\n"
, mem->avail, mem->avail/1024
, size
, realsize, realsize/1024
, newb
, ((char*)newb - mem->rw), ((char*)newb - mem->rw) / 1024
);
#endif
prev->next = newb;
/* prev|cur|newb|next
* `-----^
*/

} while (0);

return p;
}
/* }}} */
int xc_mem_free(xc_mem_t *mem, const void *p) /* {{{ return block size freed */
{
xc_block_t *cur, *b;
int size;

cur = (xc_block_t *) (((char *) p) - BLOCK_HEADER_SIZE());
xc_block_check(cur);
assert((char*)mem < (char*)cur && (char*)cur < (char*)mem + mem->size);

/* find free block right before the p */
b = mem->headblock;
while (b->next != 0 && b->next < cur) {
b = b->next;
}

/* restore block */
cur->next = b->next;
b->next = cur;
size = cur->size;

mem->avail += size;

/* combine prev|cur */
if (PADD(b, b->size) == (char *)cur) {
b->size += cur->size;
b->next = cur->next;
cur = b;
}

/* combine cur|next */
b = cur->next;
if (PADD(cur, cur->size) == (char *)b) {
cur->size += b->size;
cur->next = b->next;
}
return size;
}
/* }}} */
void *xc_mem_calloc(xc_mem_t *mem, xc_memsize_t memb, xc_memsize_t size) /* {{{ */
{
xc_memsize_t realsize = memb * size;
void *p = xc_mem_malloc(mem, realsize);

memset(p, 0, realsize);
return p;
}
/* }}} */
void *xc_mem_realloc(xc_mem_t *mem, const void *p, xc_memsize_t size) /* {{{ */
{
void *newp = xc_mem_malloc(mem, size);
memcpy(newp, p, size);
xc_mem_free(mem, p);
return newp;
}
/* }}} */
char *xc_mem_strndup(xc_mem_t *mem, const char *str, xc_memsize_t len) /* {{{ */
{
void *p = xc_mem_malloc(mem, len + 1);
memcpy(p, str, len + 1);
return p;
}
/* }}} */
char *xc_mem_strdup(xc_mem_t *mem, const char *str) /* {{{ */
{
return xc_mem_strndup(mem, str, strlen(str));
}
/* }}} */

xc_memsize_t xc_mem_avail(xc_mem_t *mem) /* {{{ */
{
return mem->avail;
}
/* }}} */
xc_memsize_t xc_mem_size(xc_mem_t *mem) /* {{{ */
{
return mem->size;
}
/* }}} */

const xc_block_t *xc_mem_freeblock_first(xc_mem_t *mem) /* {{{ */
{
return mem->headblock->next;
}
/* }}} */
const xc_block_t *xc_mem_freeblock_next(const xc_block_t *block) /* {{{ */
{
return block->next;
}
/* }}} */
xc_memsize_t xc_mem_block_size(const xc_block_t *block) /* {{{ */
{
return block->size;
}
/* }}} */
xc_memsize_t xc_mem_block_offset(const xc_mem_t *mem, const xc_block_t *block) /* {{{ */
{
return ((char *) block) - ((char *) mem);
}
/* }}} */

xc_mem_t *xc_mem_init(void *ptr, xc_memsize_t size) /* {{{ */
{
xc_mem_t *mem = (xc_mem_t *) ptr;
xc_block_t *b;

mem->size = size;
mem->avail = size - ALIGN(sizeof(xc_mem_t));

/* pointer to first block */
b = mem->headblock;
xc_block_setup(b, 0, (xc_block_t *)(mem + ALIGN(sizeof(xc_mem_t))));

/* first block*/
b = b->next;
xc_block_setup(b, mem->avail, 0);

return mem;
}
/* }}} */
void xc_mem_destroy(xc_mem_t *mem) /* {{{ */
{
}
/* }}} */

+ 20
- 0
mem.h View File

@@ -0,0 +1,20 @@
typedef struct _xc_mem_t xc_mem_t;
typedef struct _xc_block_t xc_block_t;
typedef unsigned int xc_memsize_t;

void *xc_mem_malloc(xc_mem_t *mem, xc_memsize_t size);
int xc_mem_free(xc_mem_t *mem, const void *p);
void *xc_mem_calloc(xc_mem_t *mem, xc_memsize_t memb, xc_memsize_t size);
void *xc_mem_realloc(xc_mem_t *mem, const void *p, xc_memsize_t size);
char *xc_mem_strndup(xc_mem_t *mem, const char *str, xc_memsize_t len);
char *xc_mem_strdup(xc_mem_t *mem, const char *str);
const xc_block_t *xc_mem_freeblock_first(xc_mem_t *mem);
const xc_block_t *xc_mem_freeblock_next(const xc_block_t *block);
xc_memsize_t xc_mem_block_size(const xc_block_t *block);
xc_memsize_t xc_mem_block_offset(const xc_mem_t *mem, const xc_block_t *block);

xc_memsize_t xc_mem_avail(xc_mem_t *mem);
xc_memsize_t xc_mem_size(xc_mem_t *mem);

xc_mem_t *xc_mem_init(void *ptr, xc_memsize_t size);
void xc_mem_destroy(xc_mem_t *mem);

+ 72
- 0
mkopcode.awk View File

@@ -0,0 +1,72 @@
#!/usr/bin/gawk -f
# vim:ts=4:sw=4
# process zend_vm_def.h or zend_compile.h
BEGIN {
FS=" "
max = 0;
delete opcodes;
}

/^ZEND_VM_HANDLER\(/ {
# regex from php5.1+/Zend/zend_vm_gen.php
gsub(/ +/, "");
if (!match($0, /^ZEND_VM_HANDLER\(([0-9]+),([A-Z_]+),([A-Z|]+),([A-Z|]+)\)/, array)) {
print "error unmatch $0";
exit;
}
id = 0 + array[1];
name = array[2];
if (max < id) {
max = id;
}
opcodes[id] = name;
next;
}

/^#define +ZEND_[A-Z_]+[\t ]+[[:digit:]]+$/ {
id = 0 + $3;
name = $2;
if (max < id) {
max = id;
}
opcodes[id] = name;
next;
}

/end of block/ {
exit;
}

END {
mymax = 112;
if (max < mymax) {
for (i = max + 1; i <= mymax; i ++) {
opcodes[i] = "UNDEF";
}
max = mymax;
opcodes[110] = "ZEND_DO_FCALL_BY_FUNC";
opcodes[111] = "ZEND_INIT_FCALL_BY_FUNC";
opcodes[112] = "UNDEF";
}
printf "/* size = %d */\n", max;
print "static const char *const xc_opcode_names[] = {";
for (i = 0; i <= max; i ++) {
if (i != 0) {
print ",";
}
printf "/* %d */\t", i
if (i in opcodes) {
name = opcodes[i];
sub(/^ZEND_/, "", name);
printf "\"%s\"", name;
}
else if (i == 137) {
printf "\"%s\"", "OP_DATA";
}
else {
printf "\"UNDEF\"";
}
}
print "";
print "};";
}

+ 39
- 0
mkopcode_spec.awk View File

@@ -0,0 +1,39 @@
#!/usr/bin/gawk -f
# vim:ts=4:sw=4
# process eaccelerator/opcodes.c
BEGIN {
FS=" "
max = 0;
started = 0
delete opcodes;
}

/OPDEF/ {
if (started) {
sub(/".*"/, "")
if (!match($0, /EXT_([^ |]+).*OP[1S]_([^ |]+).*OP2_([^ |]+).*RES_([^ |)]+).*/, array)) {
print "error" $0
exit
}
printf "\tOPSPEC(%10s, %10s, %10s, %10s)\n", array[1], array[2], array[3], array[4]
next
}
}
/^}/ {
print $0
exit;
}
/^[ ]*,[ ]*$/ {
next
}
{
if (started) {
print $0
next
}
}

/^static/ {
started = 1;
print "static const xc_opcode_spec_t xc_opcode_spec[] = {"
}

+ 82
- 0
mkstructinfo.awk View File

@@ -0,0 +1,82 @@
#!/usr/bin/gawk -f
# vim:ts=4:sw=4
BEGIN {
brace = 0;
delete buffer;
buffer_len = 0;
}
/^}.*;/ {
if (instruct) {
sub(";", "");
if (instruct == 1 && $2) {
instruct = $2;
}
if (instruct in typedefs) {
instruct = typedefs[instruct];
}
elm = "";
elms = "";
for (i = 0; i in buffer; i ++) {
if (i) elm = elm " + ";
# elm = elm "sizeof(((`" instruct "'*)NULL)->`" buffer[i] "')";
# elms = elms " `" buffer[i] "'";
elm = elm "sizeof(((" instruct "*)NULL)->" buffer[i] ")";
elms = elms " " buffer[i] "";
}
printf "define(`ELEMENTSOF_%s', `%s')\n", instruct, elms;
printf "define(`COUNTOF_%s', `%s')\n", instruct, i;
printf "define(`SIZEOF_%s', `( %s )')\n", instruct, elm;
print "\n";
delete buffer;
buffer_len = 0;
instruct = 0;
}
next;
}

/.{/ {
brace = brace + 1;
}
/.}/ {
brace = brace - 1;
}

{
if (brace == 1 && instruct) {
sub(/.*[{}]/, "");
gsub(/\[[^\]]+\]/, "");
gsub(/:[0-9]+/, "");
str = $0;
if (match(str, /\([ ]*\*([^)]+)\)/, a)) {
buffer[buffer_len] = a[1];
buffer_len ++;
}
else {
while (gsub(/(\([^)]*\))/, "", str)) {
}
while (match(str, /([^*() ]+)[ ]*[,;](.*)/, a)) {
buffer[buffer_len] = a[1];
buffer_len ++;
str = a[2];
}
}
next;
}
}

/^typedef struct [^{]*;/ {
sub(";", "");
typedefs[$3] = $4;
next;
}
/^typedef struct .*{/ {
brace = 1;
instruct = 1;
next;
}

/^struct .*{/ {
instruct = $2;
brace = 1;
next;
}

+ 191
- 0
mmap.c View File

@@ -0,0 +1,191 @@

#undef ALLOC_DEBUG

#include <stdio.h>
#include <assert.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>
/* mmap */
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>

#include "php.h"
#include "myshm.h"

#ifndef max
#define max(a, b) ((a) < (b) ? (b) : (a))
#endif

// {{{ xc_shm_t
struct _xc_shm_t {
void *ptr;
void *ptr_ro;
long diff;
xc_shmsize_t size;
};

#ifdef ALLOC_DEBUG
# undef NDEBUG
# define inline
#else
# define NDEBUG
#endif
#include <assert.h>
/* }}} */
#define CHECK(x, e) do { if ((x) == NULL) { zend_error(E_ERROR, "XCache: " e); goto err; } } while (0)

int xc_shm_can_readonly(xc_shm_t *shm) /* {{{ */
{
return shm->ptr_ro != NULL;
}
/* }}} */
int xc_shm_is_readwrite(xc_shm_t *shm, const void *p) /* {{{ */
{
return p >= shm->ptr && (char *)p < (char *)shm->ptr + shm->size;
}
/* }}} */
int xc_shm_is_readonly(xc_shm_t *shm, const void *p) /* {{{ */
{
return xc_shm_can_readonly(shm) && p >= shm->ptr_ro && (char *)p < (char *)shm->ptr_ro + shm->size;
}
/* }}} */
void *xc_shm_to_readwrite(xc_shm_t *shm, void *p) /* {{{ */
{
if (shm->diff) {
assert(xc_shm_is_readonly(p));
p = p - shm->diff;
}
assert(xc_shm_is_readwrite(p));
return p;
}
/* }}} */
void *xc_shm_to_readonly(xc_shm_t *shm, void *p) /* {{{ */
{
assert(xc_shm_is_readwrite(p));
if (shm->diff) {
p = p + shm->diff;
assert(xc_shm_is_readonly(p));
}
return p;
}
/* }}} */

void xc_shm_destroy(xc_shm_t *shm) /* {{{ */
{
if (shm->ptr_ro) {
munmap(shm->ptr_ro, shm->size);
/*
shm->ptr_ro = NULL;
*/
}
if (shm->ptr) {
/* shm->size depends on shm->ptr */
munmap(shm->ptr, shm->size);
/*
shm->ptr = NULL;
*/
}
/*
shm->size = NULL;
shm->diff = 0;
*/

free(shm);
return;
}
/* }}} */
xc_shm_t *xc_shm_init(const char *path, xc_shmsize_t size, zend_bool readonly_protection) /* {{{ */
{
xc_shm_t *shm = NULL;
int fd;
int ro_ok;
volatile void *romem;
int created = 0;

CHECK(shm = calloc(1, sizeof(xc_shm_t)), "shm OOM");
shm->size = size;
if (path == NULL || !path[0]) {
path = "/tmp/xcache";
}
fd = open(path, O_RDWR, S_IRUSR | S_IWUSR);
if (fd == -1) {
created = 1;
fd = open(path, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
if (fd == -1) {
if (created) {
unlink(path);
}
goto err;
}
}
ftruncate(fd, size);

shm->ptr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (shm->ptr == MAP_FAILED) {
shm->ptr = NULL;
close(fd);
if (created) {
unlink(path);
}
goto err;
}

ro_ok = 0;
if (readonly_protection) {
shm->ptr_ro = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
romem = shm->ptr_ro;

/* {{{ check if ptr_ro works */
do {
if (shm->ptr_ro == MAP_FAILED || shm->ptr_ro == shm->ptr) {
break;
}
*(char *)shm->ptr = 1;
if (*(char *)romem != 1) {
break;
}
*(char *)shm->ptr = 2;
if (*(char *)romem != 2) {