loader.c revision 4642e01f
1/*
2 * Copyright 1995-1998 by Metro Link, Inc.
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Metro Link, Inc. not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission.  Metro Link, Inc. makes no
11 * representations about the suitability of this software for any purpose.
12 *  It is provided "as is" without express or implied warranty.
13 *
14 * METRO LINK, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL METRO LINK, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 */
22/*
23 * Copyright (c) 1997-2003 by The XFree86 Project, Inc.
24 *
25 * Permission is hereby granted, free of charge, to any person obtaining a
26 * copy of this software and associated documentation files (the "Software"),
27 * to deal in the Software without restriction, including without limitation
28 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
29 * and/or sell copies of the Software, and to permit persons to whom the
30 * Software is furnished to do so, subject to the following conditions:
31 *
32 * The above copyright notice and this permission notice shall be included in
33 * all copies or substantial portions of the Software.
34 *
35 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
38 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
39 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
40 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
41 * OTHER DEALINGS IN THE SOFTWARE.
42 *
43 * Except as contained in this notice, the name of the copyright holder(s)
44 * and author(s) shall not be used in advertising or otherwise to promote
45 * the sale, use or other dealings in this Software without prior written
46 * authorization from the copyright holder(s) and author(s).
47 */
48
49#ifdef HAVE_XORG_CONFIG_H
50#include <xorg-config.h>
51#endif
52
53#include <errno.h>
54#include <stdio.h>
55#include <stdlib.h>
56#include <sys/types.h>
57#if defined(UseMMAP) || (defined(linux) && defined(__ia64__))
58#include <sys/mman.h>
59#endif
60#include <unistd.h>
61#include <sys/stat.h>
62#include <fcntl.h>
63#include <string.h>
64#if defined(linux) && \
65    (defined(__alpha__) || defined(__powerpc__) || defined(__ia64__) \
66    || defined(__amd64__))
67#include <malloc.h>
68#endif
69#include <stdarg.h>
70
71#include "os.h"
72#include "loader.h"
73#include "loaderProcs.h"
74#include "xf86.h"
75#include "xf86Priv.h"
76#include "compiler.h"
77#include "sym.h"
78
79/*
80 * handles are used to identify files that are loaded. Even archives
81 * are counted as a single file.
82 */
83#define MAX_HANDLE 256
84#define HANDLE_FREE 0
85#define HANDLE_USED 1
86static char freeHandles[MAX_HANDLE];
87static int refCount[MAX_HANDLE];
88
89/*
90 * modules are used to identify compilation units (ie object modules).
91 * Archives contain multiple modules, each of which is treated seperately.
92 */
93static int moduleseq = 0;
94
95/* Prototypes for static functions. */
96static loaderPtr _LoaderListPush(void);
97static loaderPtr _LoaderListPop(int);
98
99void
100LoaderInit(void)
101{
102    const char *osname = NULL;
103
104    char *ld_bind_now = getenv("LD_BIND_NOW");
105    if (ld_bind_now && *ld_bind_now) {
106        xf86Msg(X_ERROR, "LD_BIND_NOW is set, dlloader will NOT work!\n");
107    }
108
109    xf86MsgVerb(X_INFO, 2, "Loader magic: %p\n", (void *)
110		((long)dixLookupTab ^ (long)extLookupTab
111	        ^ (long)miLookupTab ^ (long)xfree86LookupTab));
112    xf86MsgVerb(X_INFO, 2, "Module ABI versions:\n");
113    xf86ErrorFVerb(2, "\t%s: %d.%d\n", ABI_CLASS_ANSIC,
114		   GET_ABI_MAJOR(LoaderVersionInfo.ansicVersion),
115		   GET_ABI_MINOR(LoaderVersionInfo.ansicVersion));
116    xf86ErrorFVerb(2, "\t%s: %d.%d\n", ABI_CLASS_VIDEODRV,
117		   GET_ABI_MAJOR(LoaderVersionInfo.videodrvVersion),
118		   GET_ABI_MINOR(LoaderVersionInfo.videodrvVersion));
119    xf86ErrorFVerb(2, "\t%s : %d.%d\n", ABI_CLASS_XINPUT,
120		   GET_ABI_MAJOR(LoaderVersionInfo.xinputVersion),
121		   GET_ABI_MINOR(LoaderVersionInfo.xinputVersion));
122    xf86ErrorFVerb(2, "\t%s : %d.%d\n", ABI_CLASS_EXTENSION,
123		   GET_ABI_MAJOR(LoaderVersionInfo.extensionVersion),
124		   GET_ABI_MINOR(LoaderVersionInfo.extensionVersion));
125
126    LoaderGetOS(&osname, NULL, NULL, NULL);
127    if (osname)
128	xf86MsgVerb(X_INFO, 2, "Loader running on %s\n", osname);
129
130#if defined(__UNIXWARE__) && !defined(__GNUC__)
131    /* For UnixWare we need to load the C Runtime libraries which are
132     * normally auto-linked by the compiler. Otherwise we are bound to
133     * see unresolved symbols when trying to use the type "long long".
134     * Obviously, this does not apply if the GNU C compiler is used.
135     */
136    {
137	int errmaj, errmin, wasLoaded; /* place holders */
138	char *xcrtpath = DEFAULT_MODULE_PATH "/libcrt.a";
139	char *uwcrtpath = "/usr/ccs/lib/libcrt.a";
140	char *path;
141	struct stat st;
142
143	if(stat(xcrtpath, &st) < 0)
144	    path = uwcrtpath; /* fallback: try to get libcrt.a from the uccs */
145	else
146	    path = xcrtpath; /* get the libcrt.a we compiled with */
147	LoaderOpen (path, "libcrt", 0, &errmaj, &errmin, &wasLoaded);
148    }
149#endif
150}
151
152static loaderPtr listHead = (loaderPtr) 0;
153
154static loaderPtr
155_LoaderListPush()
156{
157    loaderPtr item = calloc(1, sizeof(struct _loader));
158
159    item->next = listHead;
160    listHead = item;
161
162    return item;
163}
164
165static loaderPtr
166_LoaderListPop(int handle)
167{
168    loaderPtr item = listHead;
169    loaderPtr *bptr = &listHead;	/* pointer to previous node */
170
171    while (item) {
172	if (item->handle == handle) {
173	    *bptr = item->next;	/* remove this from the list */
174	    return item;
175	}
176	bptr = &(item->next);
177	item = item->next;
178    }
179
180    return 0;
181}
182
183/* These four are just ABI stubs */
184_X_EXPORT void
185LoaderRefSymbols(const char *sym0, ...)
186{
187}
188
189_X_EXPORT void
190LoaderRefSymLists(const char **list0, ...)
191{
192}
193
194_X_EXPORT void
195LoaderReqSymLists(const char **list0, ...)
196{
197}
198
199_X_EXPORT void
200LoaderReqSymbols(const char *sym0, ...)
201{
202}
203
204/* Public Interface to the loader. */
205
206int
207LoaderOpen(const char *module, const char *cname, int handle,
208	   int *errmaj, int *errmin, int *wasLoaded, int flags)
209{
210    loaderPtr tmp;
211    int new_handle;
212
213#if defined(DEBUG)
214    ErrorF("LoaderOpen(%s)\n", module);
215#endif
216
217    /*
218     * Check to see if the module is already loaded.
219     * Only if we are loading it into an existing namespace.
220     * If it is to be loaded into a new namespace, don't check.
221     * Note: We only have one namespace.
222     */
223    if (handle >= 0) {
224	tmp = listHead;
225	while (tmp) {
226#ifdef DEBUGLIST
227	    ErrorF("strcmp(%x(%s),{%x} %x(%s))\n", module, module,
228		   &(tmp->name), tmp->name, tmp->name);
229#endif
230	    if (!strcmp(module, tmp->name)) {
231		refCount[tmp->handle]++;
232		if (wasLoaded)
233		    *wasLoaded = 1;
234		xf86MsgVerb(X_INFO, 2, "Reloading %s\n", module);
235		return tmp->handle;
236	    }
237	    tmp = tmp->next;
238	}
239    }
240
241    /*
242     * OK, it's a new one. Add it.
243     */
244    xf86Msg(X_INFO, "Loading %s\n", module);
245    if (wasLoaded)
246	*wasLoaded = 0;
247
248    /*
249     * Find a free handle.
250     */
251    new_handle = 1;
252    while (freeHandles[new_handle] && new_handle < MAX_HANDLE)
253	new_handle++;
254
255    if (new_handle == MAX_HANDLE) {
256	xf86Msg(X_ERROR, "Out of loader space\n");	/* XXX */
257	if (errmaj)
258	    *errmaj = LDR_NOSPACE;
259	if (errmin)
260	    *errmin = LDR_NOSPACE;
261	return -1;
262    }
263
264    freeHandles[new_handle] = HANDLE_USED;
265    refCount[new_handle] = 1;
266
267    tmp = _LoaderListPush();
268    tmp->name = malloc(strlen(module) + 1);
269    strcpy(tmp->name, module);
270    tmp->cname = malloc(strlen(cname) + 1);
271    strcpy(tmp->cname, cname);
272    tmp->handle = new_handle;
273    tmp->module = moduleseq++;
274
275    if ((tmp->private = DLLoadModule(tmp, flags)) == NULL) {
276	xf86Msg(X_ERROR, "Failed to load %s\n", module);
277	_LoaderListPop(new_handle);
278	freeHandles[new_handle] = HANDLE_FREE;
279	if (errmaj)
280	    *errmaj = LDR_NOLOAD;
281	if (errmin)
282	    *errmin = LDR_NOLOAD;
283	return -1;
284    }
285
286    return new_handle;
287}
288
289int
290LoaderHandleOpen(int handle)
291{
292    if (handle < 0 || handle >= MAX_HANDLE)
293	return -1;
294
295    if (freeHandles[handle] != HANDLE_USED)
296	return -1;
297
298    refCount[handle]++;
299    return handle;
300}
301
302_X_EXPORT void *
303LoaderSymbol(const char *sym)
304{
305    return (DLFindSymbol(sym));
306}
307
308/* more stub */
309_X_EXPORT int
310LoaderCheckUnresolved(int delay_flag)
311{
312    return 0;
313}
314
315int
316LoaderUnload(int handle)
317{
318    loaderRec fakeHead;
319    loaderPtr tmp = &fakeHead;
320
321    if (handle < 0 || handle >= MAX_HANDLE)
322	return -1;
323
324    /*
325     * check the reference count, only free it if it goes to zero
326     */
327    if (--refCount[handle])
328	return 0;
329    /*
330     * find the loaderRecs associated with this handle.
331     */
332
333    while ((tmp = _LoaderListPop(handle)) != NULL) {
334	if (strchr(tmp->name, ':') == NULL) {
335	    /* It is not a member of an archive */
336	    xf86Msg(X_INFO, "Unloading %s\n", tmp->name);
337	}
338	DLUnloadModule(tmp->private);
339	free(tmp->name);
340	free(tmp->cname);
341	free(tmp);
342    }
343
344    freeHandles[handle] = HANDLE_FREE;
345
346    return 0;
347}
348
349unsigned long LoaderOptions = 0;
350
351void
352LoaderSetOptions(unsigned long opts)
353{
354    LoaderOptions |= opts;
355}
356
357_X_EXPORT Bool
358LoaderShouldIgnoreABI(void)
359{
360    return (LoaderOptions & LDR_OPT_ABI_MISMATCH_NONFATAL) != 0;
361}
362
363_X_EXPORT int
364LoaderGetABIVersion(const char *abiclass)
365{
366    struct {
367        const char *name;
368        int version;
369    } classes[] = {
370        { ABI_CLASS_ANSIC,     LoaderVersionInfo.ansicVersion },
371        { ABI_CLASS_VIDEODRV,  LoaderVersionInfo.videodrvVersion },
372        { ABI_CLASS_XINPUT,    LoaderVersionInfo.xinputVersion },
373        { ABI_CLASS_EXTENSION, LoaderVersionInfo.extensionVersion },
374        { ABI_CLASS_FONT,      LoaderVersionInfo.fontVersion },
375        { NULL,                0 }
376    };
377    int i;
378
379    for(i = 0; classes[i].name; i++) {
380        if(!strcmp(classes[i].name, abiclass)) {
381            return classes[i].version;
382        }
383    }
384
385    return 0;
386}
387