#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#define HAS_DLOPEN_CALLBACK 0
#define HAS_DLSYM_CALLBACK 0
#define NO_DLOPEN 0
#define LAZY_LOAD 1
#define THREAD_SAFE 1
#include <dlfcn.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#if THREAD_SAFE
#include <pthread.h>
#endif
#ifdef __arm__
# if defined __thumb__ && ! defined __THUMB_INTERWORK__
# error "ARM trampolines need -mthumb-interwork to work in Thumb mode"
# endif
#endif
#ifdef __cplusplus
extern "C" {
#endif
#define CHECK(cond, fmt, ...) do { \
if(!(cond)) { \
fprintf(stderr, "implib-gen: libdrm.so.2: " fmt "\n", ##__VA_ARGS__); \
assert(0 && "Assertion in generated code"); \
abort(); \
} \
} while(0)
static void *lib_handle;
static int dlopened;
#if ! NO_DLOPEN
#if THREAD_SAFE
static pthread_mutex_t mtx;
static int rec_count;
static void init_lock(void) {
pthread_mutexattr_t attr;
CHECK(0 == pthread_mutexattr_init(&attr), "failed to init mutex");
CHECK(0 == pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE), "failed to init mutex");
CHECK(0 == pthread_mutex_init(&mtx, &attr), "failed to init mutex");
}
static int lock(void) {
static pthread_once_t once = PTHREAD_ONCE_INIT;
CHECK(0 == pthread_once(&once, init_lock), "failed to init lock");
CHECK(0 == pthread_mutex_lock(&mtx), "failed to lock mutex");
return 0 == __sync_fetch_and_add(&rec_count, 1);
}
static void unlock(void) {
__sync_fetch_and_add(&rec_count, -1);
CHECK(0 == pthread_mutex_unlock(&mtx), "failed to unlock mutex");
}
#else
static int lock(void) {
return 1;
}
static void unlock(void) {}
#endif
static int load_library(void) {
int publish = lock();
if (lib_handle) {
unlock();
return publish;
}
#if HAS_DLOPEN_CALLBACK
extern void *(const char *lib_name);
lib_handle = ("libdrm.so.2");
CHECK(lib_handle, "failed to load library 'libdrm.so.2' via callback ''");
#else
lib_handle = dlopen("libdrm.so.2", RTLD_LAZY | RTLD_GLOBAL);
CHECK(lib_handle, "failed to load library 'libdrm.so.2' via dlopen: %s", dlerror());
#endif
if (__sync_val_compare_and_swap(&dlopened, 0, 1)) {
dlclose(lib_handle);
}
unlock();
return publish;
}
static void __attribute__((destructor(101))) unload_lib(void) {
if (dlopened) {
dlclose(lib_handle);
lib_handle = 0;
dlopened = 0;
}
}
#endif
#if ! NO_DLOPEN && ! LAZY_LOAD
static void __attribute__((constructor(101))) load_lib(void) {
load_library();
}
#endif
static const char *const sym_names[] = {
"drmAddBufs",
"drmAddContextPrivateMapping",
"drmAddContextTag",
"drmAddMap",
"drmAgpAcquire",
"drmAgpAlloc",
"drmAgpBase",
"drmAgpBind",
"drmAgpDeviceId",
"drmAgpEnable",
"drmAgpFree",
"drmAgpGetMode",
"drmAgpMemoryAvail",
"drmAgpMemoryUsed",
"drmAgpRelease",
"drmAgpSize",
"drmAgpUnbind",
"drmAgpVendorId",
"drmAgpVersionMajor",
"drmAgpVersionMinor",
"drmAuthMagic",
"drmAvailable",
"drmCheckModesettingSupported",
"drmClose",
"drmCloseBufferHandle",
"drmCloseOnce",
"drmCommandNone",
"drmCommandRead",
"drmCommandWrite",
"drmCommandWriteRead",
"drmCreateContext",
"drmCreateDrawable",
"drmCrtcGetSequence",
"drmCrtcQueueSequence",
"drmCtlInstHandler",
"drmCtlUninstHandler",
"drmDMA",
"drmDelContextTag",
"drmDestroyContext",
"drmDestroyDrawable",
"drmDevicesEqual",
"drmDropMaster",
"drmError",
"drmFinish",
"drmFree",
"drmFreeBufs",
"drmFreeBusid",
"drmFreeDevice",
"drmFreeDevices",
"drmFreeReservedContextList",
"drmFreeVersion",
"drmGetBufInfo",
"drmGetBusid",
"drmGetCap",
"drmGetClient",
"drmGetContextFlags",
"drmGetContextPrivateMapping",
"drmGetContextTag",
"drmGetDevice",
"drmGetDevice2",
"drmGetDeviceFromDevId",
"drmGetDeviceNameFromFd",
"drmGetDeviceNameFromFd2",
"drmGetDevices",
"drmGetDevices2",
"drmGetEntry",
"drmGetFormatModifierName",
"drmGetFormatModifierVendor",
"drmGetFormatName",
"drmGetHashTable",
"drmGetInterruptFromBusID",
"drmGetLibVersion",
"drmGetLock",
"drmGetMagic",
"drmGetMap",
"drmGetNodeTypeFromDevId",
"drmGetNodeTypeFromFd",
"drmGetPrimaryDeviceNameFromFd",
"drmGetRenderDeviceNameFromFd",
"drmGetReservedContextList",
"drmGetStats",
"drmGetVersion",
"drmHandleEvent",
"drmHashCreate",
"drmHashDelete",
"drmHashDestroy",
"drmHashFirst",
"drmHashInsert",
"drmHashLookup",
"drmHashNext",
"drmIoctl",
"drmIsKMS",
"drmIsMaster",
"drmMalloc",
"drmMap",
"drmMapBufs",
"drmMarkBufs",
"drmModeAddFB",
"drmModeAddFB2",
"drmModeAddFB2WithModifiers",
"drmModeAtomicAddProperty",
"drmModeAtomicAlloc",
"drmModeAtomicCommit",
"drmModeAtomicDuplicate",
"drmModeAtomicFree",
"drmModeAtomicGetCursor",
"drmModeAtomicMerge",
"drmModeAtomicSetCursor",
"drmModeAttachMode",
"drmModeCloseFB",
"drmModeConnectorGetPossibleCrtcs",
"drmModeConnectorSetProperty",
"drmModeCreateDumbBuffer",
"drmModeCreateLease",
"drmModeCreatePropertyBlob",
"drmModeCrtcGetGamma",
"drmModeCrtcSetGamma",
"drmModeDestroyDumbBuffer",
"drmModeDestroyPropertyBlob",
"drmModeDetachMode",
"drmModeDirtyFB",
"drmModeFormatModifierBlobIterNext",
"drmModeFreeConnector",
"drmModeFreeCrtc",
"drmModeFreeEncoder",
"drmModeFreeFB",
"drmModeFreeFB2",
"drmModeFreeModeInfo",
"drmModeFreeObjectProperties",
"drmModeFreePlane",
"drmModeFreePlaneResources",
"drmModeFreeProperty",
"drmModeFreePropertyBlob",
"drmModeFreeResources",
"drmModeGetConnector",
"drmModeGetConnectorCurrent",
"drmModeGetConnectorTypeName",
"drmModeGetCrtc",
"drmModeGetEncoder",
"drmModeGetFB",
"drmModeGetFB2",
"drmModeGetLease",
"drmModeGetPlane",
"drmModeGetPlaneResources",
"drmModeGetProperty",
"drmModeGetPropertyBlob",
"drmModeGetResources",
"drmModeListLessees",
"drmModeMapDumbBuffer",
"drmModeMoveCursor",
"drmModeObjectGetProperties",
"drmModeObjectSetProperty",
"drmModePageFlip",
"drmModePageFlipTarget",
"drmModeRevokeLease",
"drmModeRmFB",
"drmModeSetCrtc",
"drmModeSetCursor",
"drmModeSetCursor2",
"drmModeSetPlane",
"drmMsg",
"drmOpen",
"drmOpenControl",
"drmOpenOnce",
"drmOpenOnceWithType",
"drmOpenRender",
"drmOpenWithType",
"drmPrimeFDToHandle",
"drmPrimeHandleToFD",
"drmRandom",
"drmRandomCreate",
"drmRandomDestroy",
"drmRandomDouble",
"drmRmMap",
"drmSLCreate",
"drmSLDelete",
"drmSLDestroy",
"drmSLDump",
"drmSLFirst",
"drmSLInsert",
"drmSLLookup",
"drmSLLookupNeighbors",
"drmSLNext",
"drmScatterGatherAlloc",
"drmScatterGatherFree",
"drmSetBusid",
"drmSetClientCap",
"drmSetContextFlags",
"drmSetInterfaceVersion",
"drmSetMaster",
"drmSetServerInfo",
"drmSwitchToContext",
"drmSyncobjCreate",
"drmSyncobjDestroy",
"drmSyncobjEventfd",
"drmSyncobjExportSyncFile",
"drmSyncobjFDToHandle",
"drmSyncobjHandleToFD",
"drmSyncobjImportSyncFile",
"drmSyncobjQuery",
"drmSyncobjQuery2",
"drmSyncobjReset",
"drmSyncobjSignal",
"drmSyncobjTimelineSignal",
"drmSyncobjTimelineWait",
"drmSyncobjTransfer",
"drmSyncobjWait",
"drmUnlock",
"drmUnmap",
"drmUnmapBufs",
"drmUpdateDrawableInfo",
"drmWaitVBlank",
0
};
#define SYM_COUNT (sizeof(sym_names)/sizeof(sym_names[0]) - 1)
extern void *_libdrm_so_tramp_table[];
void *_libdrm_so_tramp_resolve(size_t i) {
assert(i < SYM_COUNT);
int publish = 1;
void *h = 0;
#if NO_DLOPEN
if (lib_handle) {
h = lib_handle;
} else {
# ifndef IMPLIB_EXPORT_SHIMS
h = RTLD_DEFAULT;
# else
h = RTLD_NEXT;
# endif
}
#else
publish = load_library();
h = lib_handle;
CHECK(h, "failed to resolve symbol '%s', library failed to load", sym_names[i]);
#endif
void *addr;
#if HAS_DLSYM_CALLBACK
extern void *(void *handle, const char *sym_name);
addr = (h, sym_names[i]);
CHECK(addr, "failed to resolve symbol '%s' via callback ", sym_names[i]);
#else
addr = dlsym(h, sym_names[i]);
CHECK(addr, "failed to resolve symbol '%s' via dlsym: %s", sym_names[i], dlerror());
#endif
if (publish) {
(void)__sync_val_compare_and_swap(&_libdrm_so_tramp_table[i], 0, addr);
}
return addr;
}
void _libdrm_so_tramp_resolve_all(void) {
size_t i;
for(i = 0; i < SYM_COUNT; ++i)
_libdrm_so_tramp_resolve(i);
}
void _libdrm_so_tramp_set_handle(void *handle) {
lib_handle = handle;
dlopened = 0;
}
void _libdrm_so_tramp_reset(void) {
memset(_libdrm_so_tramp_table, 0, SYM_COUNT * sizeof(_libdrm_so_tramp_table[0]));
lib_handle = 0;
dlopened = 0;
}
#ifdef __cplusplus
} #endif