loader.c revision 6747b715
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
78extern void *xorg_symbols[];
79
80#define MAX_HANDLE 256
81static int refCount[MAX_HANDLE];
82
83static int moduleseq = 0;
84
85/* Prototypes for static functions. */
86static loaderPtr listHead = NULL;
87
88static loaderPtr
89_LoaderListPush(void)
90{
91    loaderPtr item = calloc(1, sizeof(struct _loader));
92
93    item->next = listHead;
94    listHead = item;
95
96    return item;
97}
98
99static loaderPtr
100_LoaderListPop(int handle)
101{
102    loaderPtr item = listHead;
103    loaderPtr *bptr = &listHead;	/* pointer to previous node */
104
105    while (item) {
106	if (item->handle == handle) {
107	    *bptr = item->next;	/* remove this from the list */
108	    return item;
109	}
110	bptr = &(item->next);
111	item = item->next;
112    }
113
114    return 0;
115}
116
117void
118LoaderInit(void)
119{
120    xf86MsgVerb(X_INFO, 2, "Loader magic: %p\n", (void *)xorg_symbols);
121    xf86MsgVerb(X_INFO, 2, "Module ABI versions:\n");
122    xf86ErrorFVerb(2, "\t%s: %d.%d\n", ABI_CLASS_ANSIC,
123		   GET_ABI_MAJOR(LoaderVersionInfo.ansicVersion),
124		   GET_ABI_MINOR(LoaderVersionInfo.ansicVersion));
125    xf86ErrorFVerb(2, "\t%s: %d.%d\n", ABI_CLASS_VIDEODRV,
126		   GET_ABI_MAJOR(LoaderVersionInfo.videodrvVersion),
127		   GET_ABI_MINOR(LoaderVersionInfo.videodrvVersion));
128    xf86ErrorFVerb(2, "\t%s : %d.%d\n", ABI_CLASS_XINPUT,
129		   GET_ABI_MAJOR(LoaderVersionInfo.xinputVersion),
130		   GET_ABI_MINOR(LoaderVersionInfo.xinputVersion));
131    xf86ErrorFVerb(2, "\t%s : %d.%d\n", ABI_CLASS_EXTENSION,
132		   GET_ABI_MAJOR(LoaderVersionInfo.extensionVersion),
133		   GET_ABI_MINOR(LoaderVersionInfo.extensionVersion));
134
135#if defined(__UNIXWARE__) && !defined(__GNUC__)
136    /* For UnixWare we need to load the C Runtime libraries which are
137     * normally auto-linked by the compiler. Otherwise we are bound to
138     * see unresolved symbols when trying to use the type "long long".
139     * Obviously, this does not apply if the GNU C compiler is used.
140     */
141    {
142	int errmaj, errmin, wasLoaded; /* place holders */
143	char *xcrtpath = DEFAULT_MODULE_PATH "/libcrt.a";
144	char *uwcrtpath = "/usr/ccs/lib/libcrt.a";
145	char *path;
146	struct stat st;
147
148	if(stat(xcrtpath, &st) < 0)
149	    path = uwcrtpath; /* fallback: try to get libcrt.a from the uccs */
150	else
151	    path = xcrtpath; /* get the libcrt.a we compiled with */
152	LoaderOpen (path, "libcrt", 0, &errmaj, &errmin, &wasLoaded);
153    }
154#endif
155}
156
157/* Public Interface to the loader. */
158
159int
160LoaderOpen(const char *module, const char *cname, int handle,
161	   int *errmaj, int *errmin, int *wasLoaded, int flags)
162{
163    loaderPtr tmp;
164    int new_handle;
165
166#if defined(DEBUG)
167    ErrorF("LoaderOpen(%s)\n", module);
168#endif
169
170    /* Is the module already loaded? */
171    if (handle >= 0) {
172	tmp = listHead;
173	while (tmp) {
174#ifdef DEBUGLIST
175	    ErrorF("strcmp(%x(%s),{%x} %x(%s))\n", module, module,
176		   &(tmp->name), tmp->name, tmp->name);
177#endif
178	    if (!strcmp(module, tmp->name)) {
179		refCount[tmp->handle]++;
180		if (wasLoaded)
181		    *wasLoaded = 1;
182		xf86MsgVerb(X_INFO, 2, "Reloading %s\n", module);
183		return tmp->handle;
184	    }
185	    tmp = tmp->next;
186	}
187    }
188
189    /*
190     * OK, it's a new one. Add it.
191     */
192    xf86Msg(X_INFO, "Loading %s\n", module);
193    if (wasLoaded)
194	*wasLoaded = 0;
195
196    /*
197     * Find a free handle.
198     */
199    new_handle = 1;
200    while (new_handle < MAX_HANDLE && refCount[new_handle])
201	new_handle++;
202
203    if (new_handle == MAX_HANDLE) {
204	xf86Msg(X_ERROR, "Out of loader space\n");	/* XXX */
205	if (errmaj)
206	    *errmaj = LDR_NOSPACE;
207	if (errmin)
208	    *errmin = LDR_NOSPACE;
209	return -1;
210    }
211
212    refCount[new_handle] = 1;
213
214    tmp = _LoaderListPush();
215    tmp->name = malloc(strlen(module) + 1);
216    strcpy(tmp->name, module);
217    tmp->cname = malloc(strlen(cname) + 1);
218    strcpy(tmp->cname, cname);
219    tmp->handle = new_handle;
220    tmp->module = moduleseq++;
221
222    if ((tmp->private = DLLoadModule(tmp, flags)) == NULL) {
223	xf86Msg(X_ERROR, "Failed to load %s\n", module);
224	_LoaderListPop(new_handle);
225	refCount[new_handle] = 0;
226	if (errmaj)
227	    *errmaj = LDR_NOLOAD;
228	if (errmin)
229	    *errmin = LDR_NOLOAD;
230	return -1;
231    }
232
233    return new_handle;
234}
235
236int
237LoaderHandleOpen(int handle)
238{
239    if (handle < 0 || handle >= MAX_HANDLE)
240	return -1;
241
242    if (!refCount[handle])
243	return -1;
244
245    refCount[handle]++;
246    return handle;
247}
248
249void *
250LoaderSymbol(const char *sym)
251{
252    return (DLFindSymbol(sym));
253}
254
255int
256LoaderUnload(int handle)
257{
258    loaderRec fakeHead;
259    loaderPtr tmp = &fakeHead;
260
261    if (handle < 0 || handle >= MAX_HANDLE)
262	return -1;
263
264    /*
265     * check the reference count, only free it if it goes to zero
266     */
267    if (--refCount[handle])
268	return 0;
269    /*
270     * find the loaderRecs associated with this handle.
271     */
272
273    while ((tmp = _LoaderListPop(handle)) != NULL) {
274	xf86Msg(X_INFO, "Unloading %s\n", tmp->name);
275	DLUnloadModule(tmp->private);
276	free(tmp->name);
277	free(tmp->cname);
278	free(tmp);
279    }
280
281    return 0;
282}
283
284unsigned long LoaderOptions = 0;
285
286void
287LoaderSetOptions(unsigned long opts)
288{
289    LoaderOptions |= opts;
290}
291
292Bool
293LoaderShouldIgnoreABI(void)
294{
295    return (LoaderOptions & LDR_OPT_ABI_MISMATCH_NONFATAL) != 0;
296}
297
298int
299LoaderGetABIVersion(const char *abiclass)
300{
301    struct {
302        const char *name;
303        int version;
304    } classes[] = {
305        { ABI_CLASS_ANSIC,     LoaderVersionInfo.ansicVersion },
306        { ABI_CLASS_VIDEODRV,  LoaderVersionInfo.videodrvVersion },
307        { ABI_CLASS_XINPUT,    LoaderVersionInfo.xinputVersion },
308        { ABI_CLASS_EXTENSION, LoaderVersionInfo.extensionVersion },
309        { ABI_CLASS_FONT,      LoaderVersionInfo.fontVersion },
310        { NULL,                0 }
311    };
312    int i;
313
314    for(i = 0; classes[i].name; i++) {
315        if(!strcmp(classes[i].name, abiclass)) {
316            return classes[i].version;
317        }
318    }
319
320    return 0;
321}
322