1/*
2 * tclLoadDl.c --
3 *
4 *	This procedure provides a version of the TclLoadFile that
5 *	works with the "dlopen" and "dlsym" library procedures for
6 *	dynamic loading.
7 *
8 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
9 *
10 * See the file "license.terms" for information on usage and redistribution
11 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12 *
13 * RCS: @(#) $Id: tclLoadDl.c,v 1.13.2.1 2006/06/13 22:54:01 dkf Exp $
14 */
15
16#include "tclInt.h"
17#ifdef NO_DLFCN_H
18#   include "../compat/dlfcn.h"
19#else
20#   include <dlfcn.h>
21#endif
22
23/*
24 * In some systems, like SunOS 4.1.3, the RTLD_NOW flag isn't defined
25 * and this argument to dlopen must always be 1.  The RTLD_GLOBAL
26 * flag is needed on some systems (e.g. SCO and UnixWare) but doesn't
27 * exist on others;  if it doesn't exist, set it to 0 so it has no effect.
28 */
29
30#ifndef RTLD_NOW
31#   define RTLD_NOW 1
32#endif
33
34#ifndef RTLD_GLOBAL
35#   define RTLD_GLOBAL 0
36#endif
37
38/*
39 *---------------------------------------------------------------------------
40 *
41 * TclpDlopen --
42 *
43 *	Dynamically loads a binary code file into memory and returns
44 *	a handle to the new code.
45 *
46 * Results:
47 *	A standard Tcl completion code.  If an error occurs, an error
48 *	message is left in the interp's result.
49 *
50 * Side effects:
51 *	New code suddenly appears in memory.
52 *
53 *---------------------------------------------------------------------------
54 */
55
56int
57TclpDlopen(interp, pathPtr, loadHandle, unloadProcPtr)
58    Tcl_Interp *interp;		/* Used for error reporting. */
59    Tcl_Obj *pathPtr;		/* Name of the file containing the desired
60				 * code (UTF-8). */
61    Tcl_LoadHandle *loadHandle;	/* Filled with token for dynamically loaded
62				 * file which will be passed back to
63				 * (*unloadProcPtr)() to unload the file. */
64    Tcl_FSUnloadFileProc **unloadProcPtr;
65				/* Filled with address of Tcl_FSUnloadFileProc
66				 * function which should be used for
67				 * this file. */
68{
69    VOID *handle;
70    CONST char *native;
71
72    /*
73     * First try the full path the user gave us.  This is particularly
74     * important if the cwd is inside a vfs, and we are trying to load
75     * using a relative path.
76     */
77    native = Tcl_FSGetNativePath(pathPtr);
78    handle = dlopen(native, RTLD_NOW | RTLD_GLOBAL);
79    if (handle == NULL) {
80	/*
81	 * Let the OS loader examine the binary search path for
82	 * whatever string the user gave us which hopefully refers
83	 * to a file on the binary path
84	 */
85	Tcl_DString ds;
86	char *fileName = Tcl_GetString(pathPtr);
87	native = Tcl_UtfToExternalDString(NULL, fileName, -1, &ds);
88	handle = dlopen(native, RTLD_NOW | RTLD_GLOBAL);
89	Tcl_DStringFree(&ds);
90    }
91
92    if (handle == NULL) {
93	/*
94	 * Write the string to a variable first to work around a compiler bug
95	 * in the Sun Forte 6 compiler. [Bug 1503729]
96	 */
97
98	CONST char *errorStr = dlerror();
99
100	Tcl_AppendResult(interp, "couldn't load file \"",
101		Tcl_GetString(pathPtr), "\": ", errorStr, (char *) NULL);
102	return TCL_ERROR;
103    }
104
105    *unloadProcPtr = &TclpUnloadFile;
106    *loadHandle = (Tcl_LoadHandle)handle;
107    return TCL_OK;
108}
109
110/*
111 *----------------------------------------------------------------------
112 *
113 * TclpFindSymbol --
114 *
115 *	Looks up a symbol, by name, through a handle associated with
116 *	a previously loaded piece of code (shared library).
117 *
118 * Results:
119 *	Returns a pointer to the function associated with 'symbol' if
120 *	it is found.  Otherwise returns NULL and may leave an error
121 *	message in the interp's result.
122 *
123 *----------------------------------------------------------------------
124 */
125Tcl_PackageInitProc*
126TclpFindSymbol(interp, loadHandle, symbol)
127    Tcl_Interp *interp;
128    Tcl_LoadHandle loadHandle;
129    CONST char *symbol;
130{
131    CONST char *native;
132    Tcl_DString newName, ds;
133    VOID *handle = (VOID*)loadHandle;
134    Tcl_PackageInitProc *proc;
135    /*
136     * Some platforms still add an underscore to the beginning of symbol
137     * names.  If we can't find a name without an underscore, try again
138     * with the underscore.
139     */
140
141    native = Tcl_UtfToExternalDString(NULL, symbol, -1, &ds);
142    proc = (Tcl_PackageInitProc *) dlsym(handle,	/* INTL: Native. */
143	    native);
144    if (proc == NULL) {
145	Tcl_DStringInit(&newName);
146	Tcl_DStringAppend(&newName, "_", 1);
147	native = Tcl_DStringAppend(&newName, native, -1);
148	proc = (Tcl_PackageInitProc *) dlsym(handle, /* INTL: Native. */
149		native);
150	Tcl_DStringFree(&newName);
151    }
152    Tcl_DStringFree(&ds);
153
154    return proc;
155}
156
157/*
158 *----------------------------------------------------------------------
159 *
160 * TclpUnloadFile --
161 *
162 *	Unloads a dynamically loaded binary code file from memory.
163 *	Code pointers in the formerly loaded file are no longer valid
164 *	after calling this function.
165 *
166 * Results:
167 *	None.
168 *
169 * Side effects:
170 *	Code removed from memory.
171 *
172 *----------------------------------------------------------------------
173 */
174
175void
176TclpUnloadFile(loadHandle)
177    Tcl_LoadHandle loadHandle;	/* loadHandle returned by a previous call
178				 * to TclpDlopen().  The loadHandle is
179				 * a token that represents the loaded
180				 * file. */
181{
182    VOID *handle;
183
184    handle = (VOID *) loadHandle;
185    dlclose(handle);
186}
187
188/*
189 *----------------------------------------------------------------------
190 *
191 * TclGuessPackageName --
192 *
193 *	If the "load" command is invoked without providing a package
194 *	name, this procedure is invoked to try to figure it out.
195 *
196 * Results:
197 *	Always returns 0 to indicate that we couldn't figure out a
198 *	package name;  generic code will then try to guess the package
199 *	from the file name.  A return value of 1 would have meant that
200 *	we figured out the package name and put it in bufPtr.
201 *
202 * Side effects:
203 *	None.
204 *
205 *----------------------------------------------------------------------
206 */
207
208int
209TclGuessPackageName(fileName, bufPtr)
210    CONST char *fileName;	/* Name of file containing package (already
211				 * translated to local form if needed). */
212    Tcl_DString *bufPtr;	/* Initialized empty dstring.  Append
213				 * package name to this if possible. */
214{
215    return 0;
216}
217