1 /*
2 ** FFI C library loader.
3 ** Copyright (C) 2005-2014 Mike Pall. See Copyright Notice in luajit.h
4 */
5 
6 #include "lj_obj.h"
7 
8 #if LJ_HASFFI
9 
10 #include "lj_gc.h"
11 #include "lj_err.h"
12 #include "lj_tab.h"
13 #include "lj_str.h"
14 #include "lj_udata.h"
15 #include "lj_ctype.h"
16 #include "lj_cconv.h"
17 #include "lj_cdata.h"
18 #include "lj_clib.h"
19 
20 /* -- OS-specific functions ----------------------------------------------- */
21 
22 #if LJ_TARGET_DLOPEN
23 
24 #include <dlfcn.h>
25 #include <stdio.h>
26 
27 #if defined(RTLD_DEFAULT)
28 #define CLIB_DEFHANDLE	RTLD_DEFAULT
29 #elif LJ_TARGET_OSX || LJ_TARGET_BSD
30 #define CLIB_DEFHANDLE	((void *)(intptr_t)-2)
31 #else
32 #define CLIB_DEFHANDLE	NULL
33 #endif
34 
clib_error_(lua_State * L)35 LJ_NORET LJ_NOINLINE static void clib_error_(lua_State *L)
36 {
37   lj_err_callermsg(L, dlerror());
38 }
39 
40 #define clib_error(L, fmt, name)	clib_error_(L)
41 
42 #if defined(__CYGWIN__)
43 #define CLIB_SOPREFIX	"cyg"
44 #else
45 #define CLIB_SOPREFIX	"lib"
46 #endif
47 
48 #if LJ_TARGET_OSX
49 #define CLIB_SOEXT	"%s.dylib"
50 #elif defined(__CYGWIN__)
51 #define CLIB_SOEXT	"%s.dll"
52 #else
53 #define CLIB_SOEXT	"%s.so"
54 #endif
55 
clib_extname(lua_State * L,const char * name)56 static const char *clib_extname(lua_State *L, const char *name)
57 {
58   if (!strchr(name, '/')
59 #ifdef __CYGWIN__
60       && !strchr(name, '\\')
61 #endif
62      ) {
63     if (!strchr(name, '.')) {
64       name = lj_str_pushf(L, CLIB_SOEXT, name);
65       L->top--;
66 #ifdef __CYGWIN__
67     } else {
68       return name;
69 #endif
70     }
71     if (!(name[0] == CLIB_SOPREFIX[0] && name[1] == CLIB_SOPREFIX[1] &&
72 	  name[2] == CLIB_SOPREFIX[2])) {
73       name = lj_str_pushf(L, CLIB_SOPREFIX "%s", name);
74       L->top--;
75     }
76   }
77   return name;
78 }
79 
80 /* Check for a recognized ld script line. */
clib_check_lds(lua_State * L,const char * buf)81 static const char *clib_check_lds(lua_State *L, const char *buf)
82 {
83   char *p, *e;
84   if ((!strncmp(buf, "GROUP", 5) || !strncmp(buf, "INPUT", 5)) &&
85       (p = strchr(buf, '('))) {
86     while (*++p == ' ') ;
87     for (e = p; *e && *e != ' ' && *e != ')'; e++) ;
88     return strdata(lj_str_new(L, p, e-p));
89   }
90   return NULL;
91 }
92 
93 /* Quick and dirty solution to resolve shared library name from ld script. */
clib_resolve_lds(lua_State * L,const char * name)94 static const char *clib_resolve_lds(lua_State *L, const char *name)
95 {
96   FILE *fp = fopen(name, "r");
97   const char *p = NULL;
98   if (fp) {
99     char buf[256];
100     if (fgets(buf, sizeof(buf), fp)) {
101       if (!strncmp(buf, "/* GNU ld script", 16)) {  /* ld script magic? */
102 	while (fgets(buf, sizeof(buf), fp)) {  /* Check all lines. */
103 	  p = clib_check_lds(L, buf);
104 	  if (p) break;
105 	}
106       } else {  /* Otherwise check only the first line. */
107 	p = clib_check_lds(L, buf);
108       }
109     }
110     fclose(fp);
111   }
112   return p;
113 }
114 
clib_loadlib(lua_State * L,const char * name,int global)115 static void *clib_loadlib(lua_State *L, const char *name, int global)
116 {
117   void *h = dlopen(clib_extname(L, name),
118 		   RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL));
119   if (!h) {
120     const char *e, *err = dlerror();
121     if (*err == '/' && (e = strchr(err, ':')) &&
122 	(name = clib_resolve_lds(L, strdata(lj_str_new(L, err, e-err))))) {
123       h = dlopen(name, RTLD_LAZY | (global?RTLD_GLOBAL:RTLD_LOCAL));
124       if (h) return h;
125       err = dlerror();
126     }
127     lj_err_callermsg(L, err);
128   }
129   return h;
130 }
131 
clib_unloadlib(CLibrary * cl)132 static void clib_unloadlib(CLibrary *cl)
133 {
134   if (cl->handle && cl->handle != CLIB_DEFHANDLE)
135     dlclose(cl->handle);
136 }
137 
clib_getsym(CLibrary * cl,const char * name)138 static void *clib_getsym(CLibrary *cl, const char *name)
139 {
140   void *p = dlsym(cl->handle, name);
141   return p;
142 }
143 
144 #elif LJ_TARGET_WINDOWS
145 
146 #define WIN32_LEAN_AND_MEAN
147 #include <windows.h>
148 
149 #ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS
150 #define GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS	4
151 #define GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT	2
152 BOOL WINAPI GetModuleHandleExA(DWORD, LPCSTR, HMODULE*);
153 #endif
154 
155 #define CLIB_DEFHANDLE	((void *)-1)
156 
157 /* Default libraries. */
158 enum {
159   CLIB_HANDLE_EXE,
160   CLIB_HANDLE_DLL,
161   CLIB_HANDLE_CRT,
162   CLIB_HANDLE_KERNEL32,
163   CLIB_HANDLE_USER32,
164   CLIB_HANDLE_GDI32,
165   CLIB_HANDLE_MAX
166 };
167 
168 static void *clib_def_handle[CLIB_HANDLE_MAX];
169 
clib_error(lua_State * L,const char * fmt,const char * name)170 LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L, const char *fmt,
171 					    const char *name)
172 {
173   DWORD err = GetLastError();
174   char buf[128];
175   if (!FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS|FORMAT_MESSAGE_FROM_SYSTEM,
176 		      NULL, err, 0, buf, sizeof(buf), NULL))
177     buf[0] = '\0';
178   lj_err_callermsg(L, lj_str_pushf(L, fmt, name, buf));
179 }
180 
clib_needext(const char * s)181 static int clib_needext(const char *s)
182 {
183   while (*s) {
184     if (*s == '/' || *s == '\\' || *s == '.') return 0;
185     s++;
186   }
187   return 1;
188 }
189 
clib_extname(lua_State * L,const char * name)190 static const char *clib_extname(lua_State *L, const char *name)
191 {
192   if (clib_needext(name)) {
193     name = lj_str_pushf(L, "%s.dll", name);
194     L->top--;
195   }
196   return name;
197 }
198 
clib_loadlib(lua_State * L,const char * name,int global)199 static void *clib_loadlib(lua_State *L, const char *name, int global)
200 {
201   DWORD oldwerr = GetLastError();
202   void *h = (void *)LoadLibraryA(clib_extname(L, name));
203   if (!h) clib_error(L, "cannot load module " LUA_QS ": %s", name);
204   SetLastError(oldwerr);
205   UNUSED(global);
206   return h;
207 }
208 
clib_unloadlib(CLibrary * cl)209 static void clib_unloadlib(CLibrary *cl)
210 {
211   if (cl->handle == CLIB_DEFHANDLE) {
212     MSize i;
213     for (i = CLIB_HANDLE_KERNEL32; i < CLIB_HANDLE_MAX; i++) {
214       void *h = clib_def_handle[i];
215       if (h) {
216 	clib_def_handle[i] = NULL;
217 	FreeLibrary((HINSTANCE)h);
218       }
219     }
220   } else if (cl->handle) {
221     FreeLibrary((HINSTANCE)cl->handle);
222   }
223 }
224 
clib_getsym(CLibrary * cl,const char * name)225 static void *clib_getsym(CLibrary *cl, const char *name)
226 {
227   void *p = NULL;
228   if (cl->handle == CLIB_DEFHANDLE) {  /* Search default libraries. */
229     MSize i;
230     for (i = 0; i < CLIB_HANDLE_MAX; i++) {
231       HINSTANCE h = (HINSTANCE)clib_def_handle[i];
232       if (!(void *)h) {  /* Resolve default library handles (once). */
233 	switch (i) {
234 	case CLIB_HANDLE_EXE: GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, NULL, &h); break;
235 	case CLIB_HANDLE_DLL:
236 	  GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
237 			     (const char *)clib_def_handle, &h);
238 	  break;
239 	case CLIB_HANDLE_CRT:
240 	  GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS|GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
241 			     (const char *)&_fmode, &h);
242 	  break;
243 	case CLIB_HANDLE_KERNEL32: h = LoadLibraryA("kernel32.dll"); break;
244 	case CLIB_HANDLE_USER32: h = LoadLibraryA("user32.dll"); break;
245 	case CLIB_HANDLE_GDI32: h = LoadLibraryA("gdi32.dll"); break;
246 	}
247 	if (!h) continue;
248 	clib_def_handle[i] = (void *)h;
249       }
250       p = (void *)GetProcAddress(h, name);
251       if (p) break;
252     }
253   } else {
254     p = (void *)GetProcAddress((HINSTANCE)cl->handle, name);
255   }
256   return p;
257 }
258 
259 #else
260 
261 #define CLIB_DEFHANDLE	NULL
262 
clib_error(lua_State * L,const char * fmt,const char * name)263 LJ_NORET LJ_NOINLINE static void clib_error(lua_State *L, const char *fmt,
264 					    const char *name)
265 {
266   lj_err_callermsg(L, lj_str_pushf(L, fmt, name, "no support for this OS"));
267 }
268 
clib_loadlib(lua_State * L,const char * name,int global)269 static void *clib_loadlib(lua_State *L, const char *name, int global)
270 {
271   lj_err_callermsg(L, "no support for loading dynamic libraries for this OS");
272   UNUSED(name); UNUSED(global);
273   return NULL;
274 }
275 
clib_unloadlib(CLibrary * cl)276 static void clib_unloadlib(CLibrary *cl)
277 {
278   UNUSED(cl);
279 }
280 
clib_getsym(CLibrary * cl,const char * name)281 static void *clib_getsym(CLibrary *cl, const char *name)
282 {
283   UNUSED(cl); UNUSED(name);
284   return NULL;
285 }
286 
287 #endif
288 
289 /* -- C library indexing -------------------------------------------------- */
290 
291 #if LJ_TARGET_X86 && LJ_ABI_WIN
292 /* Compute argument size for fastcall/stdcall functions. */
clib_func_argsize(CTState * cts,CType * ct)293 static CTSize clib_func_argsize(CTState *cts, CType *ct)
294 {
295   CTSize n = 0;
296   while (ct->sib) {
297     CType *d;
298     ct = ctype_get(cts, ct->sib);
299     if (ctype_isfield(ct->info)) {
300       d = ctype_rawchild(cts, ct);
301       n += ((d->size + 3) & ~3);
302     }
303   }
304   return n;
305 }
306 #endif
307 
308 /* Get redirected or mangled external symbol. */
clib_extsym(CTState * cts,CType * ct,GCstr * name)309 static const char *clib_extsym(CTState *cts, CType *ct, GCstr *name)
310 {
311   if (ct->sib) {
312     CType *ctf = ctype_get(cts, ct->sib);
313     if (ctype_isxattrib(ctf->info, CTA_REDIR))
314       return strdata(gco2str(gcref(ctf->name)));
315   }
316   return strdata(name);
317 }
318 
319 /* Index a C library by name. */
lj_clib_index(lua_State * L,CLibrary * cl,GCstr * name)320 TValue *lj_clib_index(lua_State *L, CLibrary *cl, GCstr *name)
321 {
322   TValue *tv = lj_tab_setstr(L, cl->cache, name);
323   if (LJ_UNLIKELY(tvisnil(tv))) {
324     CTState *cts = ctype_cts(L);
325     CType *ct;
326     CTypeID id = lj_ctype_getname(cts, &ct, name, CLNS_INDEX);
327     if (!id)
328       lj_err_callerv(L, LJ_ERR_FFI_NODECL, strdata(name));
329     if (ctype_isconstval(ct->info)) {
330       CType *ctt = ctype_child(cts, ct);
331       lua_assert(ctype_isinteger(ctt->info) && ctt->size <= 4);
332       if ((ctt->info & CTF_UNSIGNED) && (int32_t)ct->size < 0)
333 	setnumV(tv, (lua_Number)(uint32_t)ct->size);
334       else
335 	setintV(tv, (int32_t)ct->size);
336     } else {
337       const char *sym = clib_extsym(cts, ct, name);
338 #if LJ_TARGET_WINDOWS
339       DWORD oldwerr = GetLastError();
340 #endif
341       void *p = clib_getsym(cl, sym);
342       GCcdata *cd;
343       lua_assert(ctype_isfunc(ct->info) || ctype_isextern(ct->info));
344 #if LJ_TARGET_X86 && LJ_ABI_WIN
345       /* Retry with decorated name for fastcall/stdcall functions. */
346       if (!p && ctype_isfunc(ct->info)) {
347 	CTInfo cconv = ctype_cconv(ct->info);
348 	if (cconv == CTCC_FASTCALL || cconv == CTCC_STDCALL) {
349 	  CTSize sz = clib_func_argsize(cts, ct);
350 	  const char *symd = lj_str_pushf(L,
351 			       cconv == CTCC_FASTCALL ? "@%s@%d" : "_%s@%d",
352 			       sym, sz);
353 	  L->top--;
354 	  p = clib_getsym(cl, symd);
355 	}
356       }
357 #endif
358       if (!p)
359 	clib_error(L, "cannot resolve symbol " LUA_QS ": %s", sym);
360 #if LJ_TARGET_WINDOWS
361       SetLastError(oldwerr);
362 #endif
363       cd = lj_cdata_new(cts, id, CTSIZE_PTR);
364       *(void **)cdataptr(cd) = p;
365       setcdataV(L, tv, cd);
366     }
367   }
368   return tv;
369 }
370 
371 /* -- C library management ------------------------------------------------ */
372 
373 /* Create a new CLibrary object and push it on the stack. */
clib_new(lua_State * L,GCtab * mt)374 static CLibrary *clib_new(lua_State *L, GCtab *mt)
375 {
376   GCtab *t = lj_tab_new(L, 0, 0);
377   GCudata *ud = lj_udata_new(L, sizeof(CLibrary), t);
378   CLibrary *cl = (CLibrary *)uddata(ud);
379   cl->cache = t;
380   ud->udtype = UDTYPE_FFI_CLIB;
381   /* NOBARRIER: The GCudata is new (marked white). */
382   setgcref(ud->metatable, obj2gco(mt));
383   setudataV(L, L->top++, ud);
384   return cl;
385 }
386 
387 /* Load a C library. */
lj_clib_load(lua_State * L,GCtab * mt,GCstr * name,int global)388 void lj_clib_load(lua_State *L, GCtab *mt, GCstr *name, int global)
389 {
390   void *handle = clib_loadlib(L, strdata(name), global);
391   CLibrary *cl = clib_new(L, mt);
392   cl->handle = handle;
393 }
394 
395 /* Unload a C library. */
lj_clib_unload(CLibrary * cl)396 void lj_clib_unload(CLibrary *cl)
397 {
398   clib_unloadlib(cl);
399   cl->handle = NULL;
400 }
401 
402 /* Create the default C library object. */
lj_clib_default(lua_State * L,GCtab * mt)403 void lj_clib_default(lua_State *L, GCtab *mt)
404 {
405   CLibrary *cl = clib_new(L, mt);
406   cl->handle = CLIB_DEFHANDLE;
407 }
408 
409 #endif
410