1 /*	$NetBSD: dlfcn_w32.c,v 1.1.1.2 2014/04/24 12:45:52 pettai Exp $	*/
2 
3 /***********************************************************************
4  * Copyright (c) 2009, Secure Endpoints Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * - Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  *
14  * - Redistributions in binary form must reproduce the above copyright
15  *   notice, this list of conditions and the following disclaimer in
16  *   the documentation and/or other materials provided with the
17  *   distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30  * OF THE POSSIBILITY OF SUCH DAMAGE.
31  *
32  **********************************************************************/
33 
34 #include <config.h>
35 #include <windows.h>
36 #include <dlfcn.h>
37 #include <strsafe.h>
38 
39 #define ERR_STR_LEN 256
40 
41 static volatile LONG dlfcn_tls = TLS_OUT_OF_INDEXES;
42 
get_tl_error_slot(void)43 static DWORD get_tl_error_slot(void)
44 {
45     if (dlfcn_tls == TLS_OUT_OF_INDEXES) {
46         DWORD slot = TlsAlloc();
47         DWORD old_slot;
48 
49         if (slot == TLS_OUT_OF_INDEXES)
50             return dlfcn_tls;
51 
52         if ((old_slot = InterlockedCompareExchange(&dlfcn_tls, slot,
53                                                    TLS_OUT_OF_INDEXES)) !=
54             TLS_OUT_OF_INDEXES) {
55 
56             /* Lost a race */
57             TlsFree(slot);
58             return old_slot;
59         } else {
60             return slot;
61         }
62     }
63 
64     return dlfcn_tls;
65 }
66 
set_error(const char * e)67 static void set_error(const char * e)
68 {
69     char * s;
70     char * old_s;
71     size_t len;
72 
73     DWORD slot = get_tl_error_slot();
74 
75     if (slot == TLS_OUT_OF_INDEXES)
76         return;
77 
78     len = strlen(e) * sizeof(char) + sizeof(char);
79     s = LocalAlloc(LMEM_FIXED, len);
80     if (s == NULL)
81         return;
82 
83     old_s = (char *) TlsGetValue(slot);
84     TlsSetValue(slot, (LPVOID) s);
85 
86     if (old_s != NULL)
87         LocalFree(old_s);
88 }
89 
set_error_from_last(void)90 static void set_error_from_last(void) {
91     DWORD slot = get_tl_error_slot();
92     char * s = NULL;
93     char * old_s;
94 
95     if (slot == TLS_OUT_OF_INDEXES)
96         return;
97 
98     FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
99 		  0, GetLastError(), 0,
100 		  (LPTSTR) &s, 0,
101 		  NULL);
102     if (s == NULL)
103         return;
104 
105     old_s = (char *) TlsGetValue(slot);
106     TlsSetValue(slot, (LPVOID) s);
107 
108     if (old_s != NULL)
109         LocalFree(old_s);
110 }
111 
112 ROKEN_LIB_FUNCTION int ROKEN_LIB_CALL
dlclose(void * vhm)113 dlclose(void * vhm)
114 {
115     BOOL brv;
116 
117     brv = FreeLibrary((HMODULE) vhm);
118     if (!brv) {
119 	set_error_from_last();
120     }
121     return !brv;
122 }
123 
124 ROKEN_LIB_FUNCTION char  * ROKEN_LIB_CALL
dlerror(void)125 dlerror(void)
126 {
127     DWORD slot = get_tl_error_slot();
128 
129     if (slot == TLS_OUT_OF_INDEXES)
130         return NULL;
131 
132     return (char *) TlsGetValue(slot);
133 }
134 
135 ROKEN_LIB_FUNCTION void  * ROKEN_LIB_CALL
dlopen(const char * fn,int flags)136 dlopen(const char *fn, int flags)
137 {
138     HMODULE hm;
139     UINT    old_error_mode;
140 
141     /* We don't support dlopen(0, ...) on Windows.*/
142     if ( fn == NULL ) {
143 	set_error("Not implemented");
144 	return NULL;
145     }
146 
147     old_error_mode = SetErrorMode(SEM_FAILCRITICALERRORS);
148 
149     hm = LoadLibrary(fn);
150 
151     if (hm == NULL) {
152 	set_error_from_last();
153     }
154 
155     SetErrorMode(old_error_mode);
156 
157     return (void *) hm;
158 }
159 
160 ROKEN_LIB_FUNCTION DLSYM_RET_TYPE ROKEN_LIB_CALL
dlsym(void * vhm,const char * func_name)161 dlsym(void * vhm, const char * func_name)
162 {
163     HMODULE hm = (HMODULE) vhm;
164 
165     return (DLSYM_RET_TYPE)(ULONG_PTR)GetProcAddress(hm, func_name);
166 }
167 
168