12 #include "php_scandir.h"
17 #define psi_predef_count(of) ((sizeof(psi_predef ##of## s)/sizeof(psi_predef ##of))-1)
18 typedef struct psi_predef_type
{
20 const char *type_name
;
23 static const psi_predef_type psi_predef_types
[] = {
26 #define psi_predef_type_count() psi_predef_count(_type)
28 typedef struct psi_predef_const
{
30 const char *type_name
;
35 static const psi_predef_const psi_predef_consts
[] = {
38 #define psi_predef_const_count() psi_predef_count(_const)
40 typedef struct psi_predef_struct_member
{
42 const char *type_name
;
48 } psi_predef_struct_member
;
49 #define PSI_PREDEF_STRUCT_MEMBERS 32
50 typedef struct psi_predef_struct
{
53 psi_predef_struct_member members
[PSI_PREDEF_STRUCT_MEMBERS
];
55 static const psi_predef_struct psi_predef_structs
[] = {
58 #define psi_predef_struct_count() psi_predef_count(_struct)
60 static int validate_lib(PSI_Data
*data
, void **dlopened
) {
62 const char *ptr
= data
->psi
.file
.ln
;
66 /* FIXME: assume stdlib */
68 } else if (!strchr(ptr
, '/')) {
70 len
= snprintf(lib
, MAXPATHLEN
, "lib%s.dylib", ptr
);
72 len
= snprintf(lib
, MAXPATHLEN
, "lib%s.so", ptr
);
74 if (MAXPATHLEN
== len
) {
75 data
->error(PSI_WARNING
, "Library name too long: '%s'", ptr
);
80 if (!(*dlopened
= dlopen(ptr
, RTLD_LAZY
|RTLD_LOCAL
))) {
81 data
->error(PSI_WARNING
, "Could not open library '%s': %s.",
82 data
->psi
.file
.ln
, dlerror());
88 static inline int locate_decl_type_alias(decl_typedefs
*defs
, decl_type
*type
) {
94 for (i
= 0; i
< defs
->count
; ++i
) {
95 if (!strcmp(defs
->list
[i
]->alias
, type
->name
)) {
96 type
->real
= defs
->list
[i
]->type
;
102 static inline int locate_decl_type_struct(decl_structs
*structs
, decl_type
*type
) {
108 for (i
= 0; i
< structs
->count
; ++i
) {
109 if (!strcmp(structs
->list
[i
]->name
, type
->name
)) {
110 type
->strct
= structs
->list
[i
];
117 static inline int validate_decl_type(PSI_Data
*data
, decl_type
*type
) {
118 switch (type
->type
) {
120 if (!data
->defs
|| !locate_decl_type_alias(data
->defs
, type
)) {
123 return validate_decl_type(data
, type
->real
);
125 if (!data
->structs
|| !locate_decl_type_struct(data
->structs
, type
)) {
132 static inline int validate_decl_typedef(PSI_Data
*data
, decl_typedef
*def
) {
133 if (!validate_decl_type(data
, def
->type
)) {
134 data
->error(PSI_WARNING
, "Type '%s' cannot be aliased to '%s'",
135 def
->type
->name
, def
->alias
);
138 /* FIXME: check def->alias */
142 static inline int validate_constant(PSI_Data
*data
, constant
*c
) {
147 static inline int validate_decl_arg(PSI_Data
*data
, decl_arg
*arg
) {
148 if (!validate_decl_type(data
, arg
->type
)) {
149 data
->error(PSI_WARNING
, "Cannot use '%s' as type for '%s'",
150 arg
->type
->name
, arg
->var
->name
);
156 static inline int validate_decl_struct(PSI_Data
*data
, decl_struct
*s
) {
159 for (i
= 0; i
< s
->args
->count
; ++i
) {
160 if (!validate_decl_arg(data
, s
->args
->args
[i
])) {
165 for (i
= 0; i
< s
->args
->count
; ++i
) {
166 decl_arg
*darg
= s
->args
->args
[i
];
168 if (!validate_decl_arg(data
, darg
)) {
172 ZEND_ASSERT(!darg
->var
->arg
|| darg
->var
->arg
== darg
);
173 darg
->var
->arg
= darg
;
178 if (darg
->var
->pointer_level
&& (!darg
->var
->array_size
|| darg
->var
->pointer_level
== 1)) {
181 t
= real_decl_type(darg
->type
)->type
;
185 decl_arg
*last
= s
->args
->args
[i
-1];
186 darg
->layout
= init_decl_struct_layout(
187 psi_t_align(t
, last
->layout
->pos
+ last
->layout
->len
),
188 psi_t_size(t
) * darg
->var
->array_size
);
190 darg
->layout
= init_decl_struct_layout(0, psi_t_size(t
));
193 if (s
->size
< darg
->layout
->pos
+ darg
->layout
->len
) {
194 s
->size
= darg
->layout
->pos
+ darg
->layout
->len
;
200 static const char * const abi_ccs
[] = {
202 "extern", /* > - all the same */
207 static inline int validate_decl_abi(PSI_Data
*data
, decl_abi
*abi
) {
210 for (i
= 0; i
< sizeof(abi_ccs
)/sizeof(char*); ++i
) {
211 if (strcasecmp(abi
->convention
, abi_ccs
[i
])) {
215 data
->error(PSI_WARNING
, "Invalid calling convention: '%s'", abi
->convention
);
218 static inline int validate_decl_func(PSI_Data
*data
, void *dl
, decl
*decl
, decl_arg
*func
)
220 if (!strcmp(func
->var
->name
, "dlsym")) {
221 data
->error(PSI_WARNING
, "Cannot dlsym dlsym (sic!)");
225 if (!validate_decl_arg(data
, func
)) {
229 # define RTLD_NEXT ((void *) -1l)
231 decl
->dlptr
= dlsym(dl
?: RTLD_NEXT
, func
->var
->name
);
233 data
->error(PSI_WARNING
, "Failed to locate symbol '%s': %s",
234 func
->var
->name
, dlerror());
239 static inline int validate_decl(PSI_Data
*data
, void *dl
, decl
*decl
) {
240 if (!validate_decl_abi(data
, decl
->abi
)) {
243 if (!validate_decl_func(data
, dl
, decl
, decl
->func
)) {
249 for (i
= 0; i
< decl
->args
->count
; ++i
) {
250 if (!validate_decl_arg(data
, decl
->args
->args
[i
])) {
257 static inline int validate_set_value(PSI_Data
*data
, set_value
*set
) {
260 static inline decl
*locate_impl_decl(decls
*decls
, return_stmt
*ret
) {
263 for (i
= 0; i
< decls
->count
; ++i
) {
264 if (!strcmp(decls
->list
[i
]->func
->var
->name
, ret
->decl
->name
)) {
265 ret
->decl
->arg
= decls
->list
[i
]->func
;
266 return decls
->list
[i
];
271 static inline int validate_impl_ret_stmt(PSI_Data
*data
, impl
*impl
) {
272 /* we must have exactly one ret stmt delcaring the native func to call */
273 /* and which type cast to apply */
274 if (impl
->stmts
->ret
.count
!= 1) {
275 if (impl
->stmts
->ret
.count
> 1) {
276 data
->error(PSI_WARNING
, "Too many `return` statements for implmentation %s;"
277 " found %zu, exactly one is needed",
278 impl
->func
->name
, impl
->stmts
->ret
.count
);
280 data
->error(PSI_WARNING
, "Missing `return` statement for implementation %s",
285 if (!validate_impl_set_value(data
, impl
->stmts
->ret
.list
[0]->set
)) {
288 if (!(impl
->decl
= locate_impl_decl(data
->decls
, impl
->stmts
->ret
.list
[0]))) {
289 data
->error(PSI_WARNING
, "Missing declaration for implementation %s",
296 static inline int validate_impl_let_stmts(PSI_Data
*data
, impl
*impl
) {
298 /* we can have multiple let stmts */
299 /* check that we have a let stmt for every decl arg */
300 if (impl
->decl
->args
) for (i
= 0; i
< impl
->decl
->args
->count
; ++i
) {
301 decl_arg
*darg
= impl
->decl
->args
->args
[i
];
304 for (j
= 0; j
< impl
->stmts
->let
.count
; ++j
) {
305 let_stmt
*let
= impl
->stmts
->let
.list
[j
];
307 if (!strcmp(let
->var
->name
, darg
->var
->name
)) {
314 data
->error(PSI_WARNING
, "Missing `let` statement for arg '%s %.*s%s'"
315 " of declaration '%s' for implementation '%s'",
316 darg
->type
->name
, (int) darg
->var
->pointer_level
, "*****",
317 darg
->var
->name
, impl
->decl
->func
->var
->name
, impl
->func
->name
);
321 /* check that the let_value references a known variable or NULL */
322 for (i
= 0; i
< impl
->stmts
->let
.count
; ++i
) {
323 let_stmt
*let
= impl
->stmts
->let
.list
[i
];
326 if (let
->val
&& let
->val
->func
&& let
->val
->func
->alloc
) {
327 if (!validate_decl_type(data
, let
->val
->func
->alloc
->type
)) {
328 data
->error(PSI_WARNING
, "Cannot use '%s' as type for calloc in `let` statement",
329 let
->val
->func
->alloc
->type
->name
);
333 if (let
->val
&& let
->val
->var
) {
334 if (impl
->func
->args
) for (j
= 0; j
< impl
->func
->args
->count
; ++j
) {
335 impl_arg
*iarg
= impl
->func
->args
->args
[j
];
337 if (!strcmp(let
->val
->var
->name
, iarg
->var
->name
)) {
344 data
->error(PSI_WARNING
, "Unknown value '$%s' of `let` statement"
345 " for variable '%s' of implementation '%s'",
346 let
->val
->var
->name
, let
->var
->name
, impl
->func
->name
);
353 static inline int validate_impl_set_stmts(PSI_Data
*data
, impl
*impl
) {
355 /* we can have any count of set stmts; processing out vars */
356 /* check that set stmts reference known variables */
357 for (i
= 0; i
< impl
->stmts
->set
.count
; ++i
) {
358 set_stmt
*set
= impl
->stmts
->set
.list
[i
];
361 if (impl
->func
->args
) for (j
= 0; j
< impl
->func
->args
->count
; ++j
) {
362 impl_arg
*iarg
= impl
->func
->args
->args
[j
];
364 if (!strcmp(set
->var
->name
, iarg
->var
->name
)) {
371 data
->error(PSI_WARNING
, "Unknown variable '$%s' of `set` statement"
372 " of implementation '%s'",
373 set
->var
->name
, impl
->func
->name
);
377 for (j
= 0; j
< set
->val
->vars
->count
; ++j
) {
378 decl_var
*set_var
= set
->val
->vars
->vars
[j
];
381 if (impl
->decl
->args
) for (k
= 0; k
< impl
->decl
->args
->count
; ++k
) {
382 decl_arg
*set_arg
= impl
->decl
->args
->args
[k
];
384 if (!strcmp(set_var
->name
, set_arg
->var
->name
)) {
386 set_var
->arg
= set_arg
;
392 data
->error(PSI_WARNING
, "Unknown value '%s' of `set` statement"
393 " for variable '$%s' of implementation '%s'",
394 set_var
->name
, set
->arg
->var
->name
, impl
->func
->name
);
401 static inline int validate_impl_free_stmts(PSI_Data
*data
, impl
*impl
) {
403 /* we can have any count of free stmts; freeing any out vars */
404 for (i
= 0; i
< impl
->stmts
->fre
.count
; ++i
) {
405 free_stmt
*fre
= impl
->stmts
->fre
.list
[i
];
407 for (j
= 0; j
< fre
->vars
->count
; ++j
) {
408 decl_var
*free_var
= fre
->vars
->vars
[j
];
411 if (!strcmp(free_var
->name
, impl
->decl
->func
->var
->name
)) {
414 if (impl
->decl
->args
) for (k
= 0; k
< impl
->decl
->args
->count
; ++k
) {
415 decl_arg
*free_arg
= impl
->decl
->args
->args
[k
];
417 if (!strcmp(free_var
->name
, free_arg
->var
->name
)) {
419 free_var
->arg
= free_arg
;
425 data
->error(PSI_WARNING
, "Unknown variable '%s' of `free` statement"
426 " of implementation '%s'",
427 free_var
->name
, impl
->func
->name
);
434 static inline int validate_impl_stmts(PSI_Data
*data
, impl
*impl
) {
436 data
->error(PSI_WARNING
, "Missing body for implementation %s!",
441 if (!validate_impl_ret_stmt(data
, impl
)) {
445 if (!validate_impl_let_stmts(data
, impl
)) {
448 if (!validate_impl_set_stmts(data
, impl
)) {
451 if (!validate_impl_free_stmts(data
, impl
)) {
458 PSI_Context
*PSI_ContextInit(PSI_Context
*C
, PSI_ContextOps
*ops
, PSI_ContextErrorFunc error
)
464 C
= malloc(sizeof(*C
));
466 memset(C
, 0, sizeof(*C
));
472 /* build up predefs in a temporary PSI_Data for validation */
473 memset(&T
, 0, sizeof(T
));
476 for (i
= 0; i
< psi_predef_type_count(); ++i
) {
477 const psi_predef_type
*pre
= &psi_predef_types
[i
];
478 decl_type
*type
= init_decl_type(pre
->type_tag
, pre
->type_name
);
479 decl_typedef
*def
= init_decl_typedef(pre
->alias
, type
);
481 T
.defs
= add_decl_typedef(T
.defs
, def
);
483 for (i
= 0; i
< psi_predef_const_count(); ++i
) {
484 const psi_predef_const
*pre
= &psi_predef_consts
[i
];
485 impl_def_val
*val
= init_impl_def_val(pre
->val_type_tag
, pre
->val_text
);
486 const_type
*type
= init_const_type(pre
->type_tag
, pre
->type_name
);
487 constant
*constant
= init_constant(type
, pre
->name
, val
);
489 T
.consts
= add_constant(T
.consts
, constant
);
491 for (i
= 0; i
< psi_predef_struct_count(); ++i
) {
492 const psi_predef_struct
*pre
= &psi_predef_structs
[i
];
493 decl_args
*dargs
= init_decl_args(NULL
);
494 decl_struct
*dstruct
;
496 for (j
= 0; j
< PSI_PREDEF_STRUCT_MEMBERS
; ++j
) {
497 const psi_predef_struct_member
*member
= &pre
->members
[j
];
506 type
= init_decl_type(member
->type_tag
, member
->type_name
);
507 dvar
= init_decl_var(member
->name
, member
->pointer_level
, member
->array_size
);
508 darg
= init_decl_arg(type
, dvar
);
509 darg
->layout
= init_decl_struct_layout(member
->off
, member
->len
);
510 dargs
= add_decl_arg(dargs
, darg
);
513 dstruct
= init_decl_struct(pre
->name
, dargs
);
514 dstruct
->size
= pre
->size
;
515 T
.structs
= add_decl_struct(T
.structs
, dstruct
);
518 for (i
= 0; i
< psi_predef_type_count(); ++i
) {
519 decl_typedef
*def
= T
.defs
->list
[i
];
521 if (validate_decl_typedef(&T
, def
)) {
522 C
->defs
= add_decl_typedef(C
->defs
, def
);
526 for (i
= 0; i
< psi_predef_const_count(); ++i
) {
527 constant
*constant
= T
.consts
->list
[i
];
529 if (validate_constant(&T
, constant
)) {
530 C
->consts
= add_constant(C
->consts
, constant
);
534 for (i
= 0; i
< psi_predef_struct_count(); ++i
) {
535 decl_struct
*dstruct
= T
.structs
->list
[i
];
537 if (validate_decl_struct(&T
, dstruct
)) {
538 C
->structs
= add_decl_struct(C
->structs
, dstruct
);
543 C
->data
= malloc(sizeof(*C
->data
));
544 PSI_DataExchange(C
->data
, &T
);
549 int PSI_ContextValidate(PSI_Context
*C
, PSI_Parser
*P
)
552 void *dlopened
= NULL
;
553 size_t count
= C
->count
++;
555 C
->data
= realloc(C
->data
, C
->count
* sizeof(*C
->data
));
556 D
= PSI_DataExchange(&C
->data
[count
], PSI_DATA(P
));
561 for (i
= 0; i
< D
->defs
->count
; ++i
) {
562 if (validate_decl_typedef(PSI_DATA(C
), D
->defs
->list
[i
])) {
563 C
->defs
= add_decl_typedef(C
->defs
, D
->defs
->list
[i
]);
570 for (i
= 0; i
< D
->structs
->count
; ++i
) {
571 if (validate_decl_struct(PSI_DATA(C
), D
->structs
->list
[i
])) {
572 C
->structs
= add_decl_struct(C
->structs
, D
->structs
->list
[i
]);
579 for (i
= 0; i
< D
->consts
->count
; ++i
) {
580 if (validate_constant(PSI_DATA(C
), D
->consts
->list
[i
])) {
581 C
->consts
= add_constant(C
->consts
, D
->consts
->list
[i
]);
586 if (!validate_lib(D
, &dlopened
)) {
590 add_decl_lib(&C
->psi
.libs
, dlopened
);
595 for (i
= 0; i
< D
->decls
->count
; ++i
) {
596 if (validate_decl(PSI_DATA(C
), dlopened
, D
->decls
->list
[i
])) {
597 C
->decls
= add_decl(C
->decls
, D
->decls
->list
[i
]);
604 for (i
= 0; i
< D
->impls
->count
; ++i
) {
605 if (validate_impl_stmts(PSI_DATA(C
), D
->impls
->list
[i
])) {
606 C
->impls
= add_impl(C
->impls
, D
->impls
->list
[i
]);
614 static int psi_select_dirent(const struct dirent
*entry
)
617 #define FNM_CASEFOLD 0
619 return 0 == fnmatch("*.psi", entry
->d_name
, FNM_CASEFOLD
);
622 void PSI_ContextBuild(PSI_Context
*C
, const char *path
)
625 struct dirent
**entries
= NULL
;
627 n
= php_scandir(path
, &entries
, psi_select_dirent
, alphasort
);
631 } else for (i
= 0; i
< n
; ++i
) {
632 char psi
[MAXPATHLEN
];
635 if (MAXPATHLEN
<= slprintf(psi
, MAXPATHLEN
, "%s/%s", path
, entries
[i
]->d_name
)) {
636 C
->error(PSI_WARNING
, "Path to PSI file too long: %s/%s",
637 path
, entries
[i
]->d_name
);
639 if (!PSI_ParserInit(&P
, psi
, C
->error
, 0)) {
640 C
->error(PSI_WARNING
, "Failed to init PSI parser (%s): %s",
641 psi
, strerror(errno
));
645 while (-1 != PSI_ParserScan(&P
)) {
646 PSI_ParserParse(&P
, PSI_TokenAlloc(&P
));
648 PSI_ParserParse(&P
, NULL
);
649 PSI_ContextValidate(C
, &P
);
653 if (PSI_ContextCompile(C
) && SUCCESS
!= zend_register_functions(NULL
, C
->closures
, NULL
, MODULE_PERSISTENT
)) {
654 C
->error(PSI_WARNING
, "Failed to register functions!");
658 for (i
= 0; i
< n
; ++i
) {
666 zend_function_entry
*PSI_ContextCompile(PSI_Context
*C
)
673 zc
.flags
= CONST_PERSISTENT
|CONST_CS
;
674 zc
.module_number
= EG(current_module
)->module_number
;
676 for (i
= 0; i
< C
->consts
->count
; ++i
) {
677 constant
*c
= C
->consts
->list
[i
];
679 zc
.name
= zend_string_init(c
->name
+ (c
->name
[0] == '\\'), strlen(c
->name
) - (c
->name
[0] == '\\'), 1);
680 ZVAL_NEW_STR(&zc
.value
, zend_string_init(c
->val
->text
, strlen(c
->val
->text
), 1));
682 switch (c
->type
->type
) {
684 convert_to_boolean(&zc
.value
);
687 convert_to_long(&zc
.value
);
690 convert_to_double(&zc
.value
);
693 zend_register_constant(&zc
);
698 return C
->closures
= C
->ops
->compile(C
);
701 void PSI_ContextDtor(PSI_Context
*C
)
707 free_decl_libs(&C
->psi
.libs
);
709 for (i
= 0; i
< C
->count
; ++i
) {
710 PSI_DataDtor(&C
->data
[i
]);
717 if (C
->consts
->list
) {
718 free(C
->consts
->list
);
729 if (C
->structs
->list
) {
730 free(C
->structs
->list
);
735 if (C
->decls
->list
) {
736 free(C
->decls
->list
);
741 if (C
->impls
->list
) {
742 free(C
->impls
->list
);
747 memset(C
, 0, sizeof(*C
));
750 void PSI_ContextFree(PSI_Context
**C
)