root/lj_clib.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. clib_error_
  2. clib_extname
  3. clib_check_lds
  4. clib_resolve_lds
  5. clib_loadlib
  6. clib_unloadlib
  7. clib_getsym
  8. clib_error
  9. clib_needext
  10. clib_extname
  11. clib_loadlib
  12. clib_unloadlib
  13. clib_getsym
  14. clib_error
  15. clib_loadlib
  16. clib_unloadlib
  17. clib_getsym
  18. clib_func_argsize
  19. clib_extsym
  20. lj_clib_index
  21. clib_new
  22. lj_clib_load
  23. lj_clib_unload
  24. lj_clib_default

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

/* [<][>][^][v][top][bottom][index][help] */