ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/src/dynlink.c
Revision: 186
Committed: Sun Oct 23 16:05:01 2005 UTC (20 years, 9 months ago) by db
Content type: text/x-csrc
File size: 10779 byte(s)
Log Message:
- Q. When is an address not an address?
  A. When it is a handle!

  Keep track of handle address and base address of loaded module separately.
  The address is also used for modlist and could be derived in modlist
  from handle, but later.


File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 * dynlink.c: A module loader.
4 *
5 * Copyright (C) 2002 by the past and present ircd coders, and others.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 * USA
21 *
22 * $Id$
23 *
24 */
25 #include "stdinc.h"
26 #include "modules.h"
27 #include "client.h"
28 #include "send.h"
29
30 #ifndef RTLD_NOW
31 #define RTLD_NOW RTLD_LAZY /* openbsd deficiency */
32 #endif
33
34 extern dlink_list mod_list;
35
36 static char unknown_ver[] = "<unknown>";
37
38 /* This file contains the core functions to use dynamic libraries.
39 * -TimeMr14C
40 */
41
42 #if !defined(HAVE_SHL_LOAD) && !defined(HAVE_DLFUNC)
43 /*
44 * Fake dlfunc(3) if we don't have it, cause it's happy.
45 */
46 typedef void (*__function_p)(void);
47
48 static __function_p
49 dlfunc(void *myHandle, const char *functionName)
50 {
51 /* XXX This is not guaranteed to work, but with
52 * traditional dl*(3), it is the best we can do.
53 * -jmallett
54 */
55 void *symbolp;
56
57 symbolp = dlsym(myHandle, functionName);
58 return((__function_p)(uintptr_t)symbolp);
59 }
60 #endif
61
62 #ifdef _WIN32
63 /*
64 * jmallett's dl*(3) stubs for DLL management.
65 */
66
67 char *
68 dlerror(void)
69 {
70 static char errbuf[IRCD_BUFSIZE];
71
72 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
73 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), errbuf, sizeof(errbuf), NULL);
74
75 return errbuf;
76 }
77
78 void *
79 dlopen(char *filename, int unused)
80 {
81 return LoadLibrary(filename);
82 }
83
84 int
85 dlclose(void *module)
86 {
87 return FreeLibrary((HMODULE) module) ? 0 : -1;
88 }
89
90 void *
91 dlsym(void *module, char *sym)
92 {
93 return GetProcAddress((HMODULE) module, sym);
94 }
95 #endif
96
97 #ifdef HAVE_MACH_O_DYLD_H
98 /*
99 ** jmallett's dl*(3) shims for NSModule(3) systems.
100 */
101 #include <mach-o/dyld.h>
102
103 #ifndef HAVE_DLOPEN
104 #ifndef RTLD_LAZY
105 #define RTLD_LAZY 2185 /* built-in dl*(3) don't care */
106 #endif
107
108 void undefinedErrorHandler(const char *);
109 NSModule multipleErrorHandler(NSSymbol, NSModule, NSModule);
110 void linkEditErrorHandler(NSLinkEditErrors, int, const char *, const char *);
111 char *dlerror(void);
112 void *dlopen(char *, int);
113 int dlclose(void *);
114 void *dlsym(void *, char *);
115
116 static int firstLoad = TRUE;
117 static int myDlError;
118 static const char *myErrorTable[] =
119 {
120 "Loading file as object failed\n",
121 "Loading file as object succeeded\n",
122 "Not a valid shared object\n",
123 "Architecture of object invalid on this architecture\n",
124 "Invalid or corrupt image\n",
125 "Could not access object\n",
126 "NSCreateObjectFileImageFromFile failed\n",
127 NULL
128 };
129
130 void
131 undefinedErrorHandler(const char *symbolName)
132 {
133 sendto_realops_flags(UMODE_ALL, L_ALL, "Undefined symbol: %s", symbolName);
134 ilog(L_WARN, "Undefined symbol: %s", symbolName);
135 }
136
137 NSModule
138 multipleErrorHandler(NSSymbol s, NSModule old, NSModule new)
139 {
140 /* XXX
141 ** This results in substantial leaking of memory... Should free one
142 ** module, maybe?
143 */
144 sendto_realops_flags(UMODE_ALL, L_ALL, "Symbol `%s' found in `%s' and `%s'",
145 NSNameOfSymbol(s), NSNameOfModule(old), NSNameOfModule(new));
146 ilog(L_WARN, "Symbol `%s' found in `%s' and `%s'", NSNameOfSymbol(s),
147 NSNameOfModule(old), NSNameOfModule(new));
148 /* We return which module should be considered valid, I believe */
149 return new;
150 }
151
152 void
153 linkEditErrorHandler(NSLinkEditErrors errorClass, int errnum,
154 const char *fileName, const char *errorString)
155 {
156 sendto_realops_flags(UMODE_ALL, L_ALL, "Link editor error: %s for %s",
157 errorString, fileName);
158 ilog(L_WARN, "Link editor error: %s for %s", errorString, fileName);
159 return;
160 }
161
162 char *
163 dlerror(void)
164 {
165 return(myDlError == NSObjectFileImageSuccess ? NULL : myErrorTable[myDlError % 7]);
166 }
167
168 void *
169 dlopen(char *filename, int unused)
170 {
171 NSObjectFileImage myImage;
172 NSModule myModule;
173
174 if (firstLoad)
175 {
176 /* If we are loading our first symbol (huzzah!) we should go ahead
177 * and install link editor error handling!
178 */
179 NSLinkEditErrorHandlers linkEditorErrorHandlers;
180
181 linkEditorErrorHandlers.undefined = undefinedErrorHandler;
182 linkEditorErrorHandlers.multiple = multipleErrorHandler;
183 linkEditorErrorHandlers.linkEdit = linkEditErrorHandler;
184 NSInstallLinkEditErrorHandlers(&linkEditorErrorHandlers);
185 firstLoad = FALSE;
186 }
187
188 myDlError = NSCreateObjectFileImageFromFile(filename, &myImage);
189
190 if (myDlError != NSObjectFileImageSuccess)
191 return(NULL);
192
193 myModule = NSLinkModule(myImage, filename, NSLINKMODULE_OPTION_PRIVATE);
194 return((void *)myModule);
195 }
196
197 int
198 dlclose(void *myModule)
199 {
200 NSUnLinkModule(myModule, FALSE);
201 return(0);
202 }
203
204 void *
205 dlsym(void *myModule, char *mySymbolName)
206 {
207 NSSymbol mySymbol;
208
209 mySymbol = NSLookupSymbolInModule((NSModule)myModule, mySymbolName);
210 return NSAddressOfSymbol(mySymbol);
211 }
212 #endif
213 #endif
214
215 /* unload_one_module()
216 *
217 * inputs - name of module to unload
218 * - 1 to say modules unloaded, 0 to not
219 * output - 0 if successful, -1 if error
220 * side effects - module is unloaded
221 */
222 int
223 unload_one_module(char *name, int warn)
224 {
225 dlink_node *ptr = NULL;
226 struct module *modp = NULL;
227
228 if ((ptr = findmodule_byname(name)) == NULL)
229 return -1;
230
231 modp = ptr->data;
232
233 if (modp->modremove)
234 (*modp->modremove)();
235
236 #ifdef HAVE_SHL_LOAD
237 /* shl_* and friends have a slightly different format than dl*. But it does not
238 * require creation of a totally new modules.c, instead proper usage of
239 * defines solve this case. -TimeMr14C
240 */
241 shl_unload((shl_t) & (modp->handle));
242 #else
243 /* We use FreeBSD's dlfunc(3) interface, or fake it as we
244 * used to here if it isn't there. The interface should
245 * be standardised some day, and so it eventually will be
246 * providing something guaranteed to do the right thing here.
247 * -jmallett
248 */
249 dlclose(modp->handle);
250 #endif
251 assert(dlink_list_length(&mod_list) > 0);
252 dlinkDelete(ptr, &mod_list);
253 MyFree(modp->name);
254 MyFree(modp);
255
256 if (warn == 1)
257 {
258 ilog(L_INFO, "Module %s unloaded", name);
259 sendto_realops_flags(UMODE_ALL, L_ALL, "Module %s unloaded", name);
260 }
261
262 return 0;
263 }
264
265 /* load_a_module()
266 *
267 * inputs - path name of module, int to notice, int of core
268 * output - -1 if error 0 if success
269 * side effects - loads a module if successful
270 */
271 int
272 load_a_module(char *path, int warn, int core)
273 {
274 #ifdef HAVE_DLINFO
275 Link_map *map;
276 #endif
277 #ifdef HAVE_SHL_LOAD
278 shl_t tmpptr;
279 #else
280 void *tmpptr = NULL;
281 #endif
282 void *addr = NULL;
283 char *mod_basename;
284 void (*initfunc)(void) = NULL;
285 void (*mod_deinit)(void) = NULL;
286 char **verp;
287 char *ver;
288 struct module *modp;
289
290 mod_basename = basename(path);
291
292 if (findmodule_byname(mod_basename) != NULL)
293 return(1);
294
295 #ifdef HAVE_SHL_LOAD
296 tmpptr = shl_load(path, BIND_IMMEDIATE, NULL);
297 #else
298 tmpptr = dlopen(path, RTLD_NOW);
299 #endif
300
301 if (tmpptr == NULL)
302 {
303 #ifdef HAVE_SHL_LOAD
304 const char *err = strerror(errno);
305 #else
306 const char *err = dlerror();
307 #endif
308 sendto_realops_flags(UMODE_ALL, L_ALL, "Error loading module %s: %s",
309 mod_basename, err);
310 ilog(L_WARN, "Error loading module %s: %s", mod_basename, err);
311
312 return(-1);
313 }
314
315 #ifdef HAVE_SHL_LOAD
316 if (shl_findsym(&tmpptr, "_modinit", TYPE_UNDEFINED, (void *)&initfunc) == -1)
317 {
318 if (shl_findsym(&tmpptr, "__modinit", TYPE_UNDEFINED, (void *)&initfunc) == -1)
319 {
320 ilog(L_WARN, "Module %s has no _modinit() function", mod_basename);
321 sendto_realops_flags(UMODE_ALL, L_ALL, "Module %s has no _modinit() function",
322 mod_basename);
323 shl_unload(tmpptr);
324 return(-1);
325 }
326 }
327
328 if (shl_findsym(&tmpptr, "_moddeinit", TYPE_UNDEFINED, (void *)&mod_deinit) == -1)
329 {
330 if (shl_findsym(&tmpptr, "__moddeinit", TYPE_UNDEFINED, (void *)&mod_deinit) == -1)
331 {
332 ilog(L_WARN, "Module %s has no _moddeinit() function", mod_basename);
333 sendto_realops_flags(UMODE_ALL, L_ALL, "Module %s has no _moddeinit() function",
334 mod_basename);
335 /* this is a soft error. we're allowed not to have one, i guess.
336 * (judging by the code in unload_one_module() */
337 mod_deinit = NULL;
338 }
339 }
340
341 if (shl_findsym(&tmpptr, "_version", TYPE_UNDEFINED, &verp) == -1)
342 {
343 if (shl_findsym(&tmpptr, "__version", TYPE_UNDEFINED, &verp) == -1)
344 ver = unknown_ver;
345 else
346 ver = *verp;
347 }
348 else
349 ver = *verp;
350 #else
351 if ((initfunc = (void(*)(void))dlfunc(tmpptr, "_modinit")) == NULL &&
352 /* Only for compatibility, because some systems have underscore
353 * prepended symbol names */
354 (initfunc = (void(*)(void))dlfunc(tmpptr, "__modinit")) == NULL)
355 {
356 sendto_realops_flags(UMODE_ALL, L_ALL, "Module %s has no _modinit() function",
357 mod_basename);
358 ilog(L_WARN, "Module %s has no _modinit() function", mod_basename);
359 dlclose(tmpptr);
360 return(-1);
361 }
362
363 mod_deinit = (void(*)(void))dlfunc(tmpptr, "_moddeinit");
364
365 if (mod_deinit == NULL && (mod_deinit = (void(*)(void))dlfunc(tmpptr, "__moddeinit")) == NULL)
366 {
367 sendto_realops_flags(UMODE_ALL, L_ALL, "Module %s has no _moddeinit() function",
368 mod_basename);
369 ilog(L_WARN, "Module %s has no _moddeinit() function", mod_basename);
370 /* blah blah soft error, see above. */
371 mod_deinit = NULL;
372 }
373
374 verp = (char **)dlsym(tmpptr, "_version");
375
376 if (verp == NULL && (verp = (char **)dlsym(tmpptr, "__version")) == NULL)
377 ver = unknown_ver;
378 else
379 ver = *verp;
380 #endif
381
382
383 modp = MyMalloc(sizeof(struct module));
384 #ifdef HAVE_DLINFO
385 dlinfo(tmpptr, RTLD_DI_LINKMAP, &map);
386 if (map != NULL)
387 addr = map->l_addr;
388 else
389 addr = tmpptr;
390 #endif
391
392 modp->handle = tmpptr;
393 modp->address = addr;
394 modp->version = ver;
395 modp->core = core;
396 modp->modremove = mod_deinit;
397
398 DupString(modp->name, mod_basename);
399 dlinkAdd(modp, &modp->node, &mod_list);
400
401 initfunc();
402
403 if (warn == 1)
404 {
405 sendto_realops_flags(UMODE_ALL, L_ALL,
406 "Module %s [version: %s] loaded at %p",
407 mod_basename, ver, addr);
408 ilog(L_WARN, "Module %s [version: %s] loaded at %p",
409 mod_basename, ver, addr);
410 }
411
412 return(0);
413 }

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision