40d8c251f0e484123277dfda6b97f4c517fbb97c
[m6w6/ext-psi] / src / types / decl.c
1 /*******************************************************************************
2 Copyright (c) 2016, Michael Wallner <mike@php.net>.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7
8 * Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13
14 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
18 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 *******************************************************************************/
25
26 #include "php_psi_stdinc.h"
27
28 #include "php_psi.h"
29
30 #include <dlfcn.h>
31 #include <fnmatch.h>
32
33 #include "data.h"
34
35 #define PSI_FUNC_REDIRS
36 #include "php_psi_posix.h"
37
38 struct psi_decl *psi_decl_init(struct psi_decl_arg *func, struct psi_plist *args)
39 {
40 struct psi_decl *d = calloc(1, sizeof(*d));
41
42 d->func = func;
43 d->args = args;
44
45 return d;
46 }
47
48 void psi_decl_free(struct psi_decl **d_ptr)
49 {
50 if (*d_ptr) {
51 struct psi_decl *d = *d_ptr;
52
53 *d_ptr = NULL;
54
55 psi_decl_abi_free(&d->abi);
56 psi_decl_arg_free(&d->func);
57 if (d->args) {
58 psi_plist_free(d->args);
59 }
60 if (d->redir) {
61 free(d->redir);
62 }
63 free(d);
64 }
65 }
66
67 void psi_decl_dump(int fd, struct psi_decl *decl)
68 {
69 if (decl->abi) {
70 psi_decl_abi_dump(fd, decl->abi);
71 }
72 dprintf(fd, " ");
73 /* FIXME: functions returning arrays */
74 psi_decl_arg_dump(fd, decl->func, 0);
75 dprintf(fd, "(");
76 if (decl->args) {
77 size_t i;
78 struct psi_decl_arg *arg;
79
80 for (i = 0; psi_plist_get(decl->args, i, &arg); ++i) {
81 if (i) {
82 dprintf(fd, ", ");
83 }
84 psi_decl_arg_dump(fd, arg, 0);
85 }
86 if (decl->varargs) {
87 dprintf(fd, ", ...");
88 }
89 }
90 if (decl->func->var->array_size) {
91 dprintf(fd, ")[%zu]", decl->func->var->array_size);
92 }
93 if (decl->redir) {
94 dprintf(fd, ") __asm__ (\"%s\");", decl->redir);
95 } else {
96 dprintf(fd, ");");
97 }
98 }
99
100 static inline bool psi_decl_validate_func(struct psi_data *data,
101 struct psi_decl *decl, struct psi_decl_arg *func)
102 {
103 struct psi_func_redir *redir;
104
105 if (!func->var->name) {
106 data->error(data, func->token, PSI_WARNING, "Cannot load anonymous decl");
107 return false;
108 }
109
110 for (redir = &psi_func_redirs[0]; redir->name; ++redir) {
111 if (!strcmp(func->var->name, redir->name)) {
112 decl->sym = redir->func;
113 }
114 }
115 if (!decl->sym) {
116 size_t i = 0;
117 void *dl;
118
119 while (!decl->sym && psi_plist_get(data->file.dlopened, i++, &dl)) {
120 decl->sym = dlsym(dl, decl->redir ?: func->var->name);
121 }
122 }
123 if (!decl->sym) {
124 #ifndef RTLD_NEXT
125 # define RTLD_NEXT ((void *) -1l)
126 #endif
127 #ifndef RTLD_DEFAULT
128 # define RTLD_DEFAULT ((void *) 0)
129 #endif
130 decl->sym = dlsym(RTLD_DEFAULT, decl->redir ?: func->var->name);
131 if (!decl->sym) {
132 data->error(data, func->token, PSI_WARNING,
133 "Failed to locate symbol '%s(%s)': %s",
134 func->var->name, decl->redir ?: "",
135 dlerror() ?: "not found");
136 return false;
137 }
138 }
139 return true;
140 }
141
142 bool psi_decl_validate(struct psi_data *data, struct psi_decl *decl,
143 struct psi_validate_scope *scope)
144 {
145 if (!psi_decl_validate_nodl(data, decl, scope)) {
146 return false;
147 }
148 if (!psi_decl_validate_func(data, decl, decl->func)) {
149 return false;
150 }
151
152 return true;
153 }
154
155 bool psi_decl_validate_nodl(struct psi_data *data, struct psi_decl *decl,
156 struct psi_validate_scope *scope)
157 {
158 if (!decl->abi) {
159 decl->abi = psi_decl_abi_init("default");
160 } else if (!psi_decl_abi_validate(data, decl->abi)) {
161 data->error(data, decl->abi->token, PSI_WARNING,
162 "Invalid calling convention: '%s'", decl->abi->token->text);
163 return false;
164 }
165 if (!psi_decl_arg_validate(data, decl->func, scope)) {
166 return false;
167 }
168 if (decl->args) {
169 size_t i = 0;
170 struct psi_decl_arg *arg;
171
172 while (psi_plist_get(decl->args, i++, &arg)) {
173 if (!arg->var->name) {
174 arg->var->name = malloc(7);
175 snprintf(arg->var->name, 6, "arg%zu", i);
176 arg->var->fqn = strdup(arg->var->name);
177 }
178 if (!psi_decl_arg_validate(data, arg, scope)) {
179 return false;
180 }
181 }
182 }
183
184 return true;
185 }
186
187 bool psi_decl_is_blacklisted(const char *name)
188 {
189 char *blacklisted;
190 size_t i = 0;
191
192 while (psi_plist_get(PSI_G(blacklist).decls, i++, &blacklisted)) {
193 if (!fnmatch(blacklisted, name, 0)) {
194 return true;
195 }
196 }
197 return false;
198 }
199
200 struct psi_decl_arg *psi_decl_get_arg(struct psi_decl *decl, struct psi_decl_var *var) {
201 if (var->arg) {
202 size_t i = 0;
203 struct psi_decl_arg *arg = decl->func;
204
205 do {
206 if (var->arg == arg) {
207 return arg;
208 }
209 } while (psi_plist_get(decl->args, i++, &arg));
210 }
211
212 return psi_decl_arg_get_by_var(var, decl->args, decl->func);
213 }
214