]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * dlf.c | |
3 | * | |
4 | * $Id$ | |
5 | * | |
6 | * Dynamic Library Loader (mapping to SVR4) | |
7 | * | |
8 | * The iODBC driver manager. | |
9 | * | |
10 | * Copyright (C) 1995 by Ke Jin <kejin@empress.com> | |
11 | * | |
12 | * This library is free software; you can redistribute it and/or | |
13 | * modify it under the terms of the GNU Library General Public | |
14 | * License as published by the Free Software Foundation; either | |
15 | * version 2 of the License, or (at your option) any later version. | |
16 | * | |
17 | * This library is distributed in the hope that it will be useful, | |
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
20 | * Library General Public License for more details. | |
21 | * | |
22 | * You should have received a copy of the GNU Library General Public | |
23 | * License along with this library; if not, write to the Free | |
24 | * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
25 | */ | |
26 | ||
27 | #include "dlf.h" | |
28 | #include <errno.h> | |
29 | ||
30 | #ifdef DLDAPI_DEFINED | |
31 | #undef DLDAPI_DEFINED | |
32 | #endif | |
33 | ||
34 | #ifdef DLDAPI_SVR4_DLFCN | |
35 | #define DLDAPI_DEFINED | |
36 | static char sccsid[] = "@(#)dynamic load interface -- SVR4 dlfcn"; | |
37 | #endif | |
38 | ||
39 | /********************************* | |
40 | * | |
41 | * HP/UX | |
42 | * | |
43 | *********************************/ | |
44 | ||
45 | #ifdef DLDAPI_HP_SHL | |
46 | #define DLDAPI_DEFINED | |
47 | #include <dl.h> | |
48 | ||
49 | static char sccsid[] = "@(#)dynamic load interface -- HP/UX dl(shl)"; | |
50 | ||
51 | void * | |
52 | dlopen (char *path, int mode) | |
53 | { | |
54 | return (void *) shl_load ((char *) (path), BIND_DEFERRED, 0L); | |
55 | } | |
56 | ||
57 | ||
58 | void * | |
59 | dlsym (void *hdll, char *sym) | |
60 | { | |
61 | void *symaddr = 0; | |
62 | int ret; | |
63 | ||
64 | if (!hdll) | |
65 | hdll = (void *) PROG_HANDLE; | |
66 | ||
67 | /* Remember, a driver may export calls as function pointers | |
68 | * (i.e. with type TYPE_DATA) rather than as functions | |
69 | * (i.e. with type TYPE_PROCEDURE). Thus, to be safe, we | |
70 | * uses TYPE_UNDEFINED to cover all of them. | |
71 | */ | |
72 | ret = shl_findsym ((shl_t *) & hdll, sym, TYPE_UNDEFINED, &symaddr); | |
73 | ||
74 | if (ret == -1) | |
75 | return 0; | |
76 | ||
77 | return symaddr; | |
78 | } | |
79 | ||
80 | ||
81 | char * | |
82 | dlerror () | |
83 | { | |
84 | extern char *strerror (); | |
85 | ||
86 | return strerror (errno); | |
87 | } | |
88 | ||
89 | ||
90 | int | |
91 | dlclose (void *hdll) | |
92 | { | |
93 | return shl_unload ((shl_t) hdll); | |
94 | } | |
95 | #endif /* end of HP/UX Seection */ | |
96 | ||
97 | ||
98 | /********************************* | |
99 | * | |
100 | * IBM AIX | |
101 | * | |
102 | *********************************/ | |
103 | ||
104 | #ifdef DLDAPI_AIX_LOAD | |
105 | #define DLDAPI_DEFINED | |
106 | #include <sys/types.h> | |
107 | #include <sys/ldr.h> | |
108 | #include <sys/stat.h> | |
109 | #include <nlist.h> | |
110 | ||
111 | /* | |
112 | * Following id sting is a copyright mark. Removing(i.e. use the | |
113 | * source code in this .c file without include it or make it not | |
114 | * appear in the final object file of AIX platform) or modifing | |
115 | * it without permission from original author(kejin@empress.com) | |
116 | * are copyright violation. | |
117 | */ | |
118 | static char sccsid[] | |
119 | = "@(#)dynamic load interface, Copyright(c) 1995 by Ke Jin"; | |
120 | ||
121 | #ifndef HTAB_SIZE | |
122 | #define HTAB_SIZE 256 | |
123 | #endif | |
124 | ||
125 | #define FACTOR 0.618039887 /* i.e. (sqrt(5) - 1)/2 */ | |
126 | ||
127 | #ifndef ENTRY_SYM | |
128 | #define ENTRY_SYM ".__start" /* default entry point for aix */ | |
129 | #endif | |
130 | ||
131 | typedef struct slot_s | |
132 | { | |
133 | char *sym; | |
134 | long fdesc[3]; /* 12 bytes function descriptor */ | |
135 | struct slot_s *next; | |
136 | } | |
137 | slot_t; | |
138 | ||
139 | /* Note: on AIX, a function pointer actually points to a | |
140 | * function descriptor, a 12 bytes data. The first 4 bytes | |
141 | * is the virtual address of the function. The next 4 bytes | |
142 | * is the virtual address of TOC (Table of Contents) of the | |
143 | * object module the function belong to. The last 4 bytes | |
144 | * are always 0 for C and Fortran functions. Every object | |
145 | * module has an entry point (which can be specified at link | |
146 | * time by -e ld option). iODBC driver manager requires ODBC | |
147 | * driver shared library always use the default entry point | |
148 | * (so you shouldn't use -e ld option when creating a driver | |
149 | * share library). load() returns the function descriptor of | |
150 | * a module's entry point. From which we can calculate function | |
151 | * descriptors of other functions in the same module by using | |
152 | * the fact that the load() doesn't change the relative | |
153 | * offset of functions to their module entry point(i.e the | |
154 | * offset in memory loaded by load() will be as same as in | |
155 | * the module library file). | |
156 | */ | |
157 | ||
158 | typedef slot_t *hent_t; | |
159 | typedef struct nlist nlist_t; | |
160 | typedef struct stat stat_t; | |
161 | ||
162 | typedef struct obj | |
163 | { | |
164 | int dev; /* device id */ | |
165 | int ino; /* inode number */ | |
166 | char *path; /* file name */ | |
167 | int (*pentry) (); /* entry point of this share library */ | |
168 | int refn; /* number of reference */ | |
169 | hent_t htab[HTAB_SIZE]; | |
170 | struct obj * next; | |
171 | } | |
172 | obj_t; | |
173 | ||
174 | static char *errmsg = 0; | |
175 | ||
176 | static void | |
177 | init_htab (hent_t * ht) | |
178 | /* initate a hashing table */ | |
179 | { | |
180 | int i; | |
181 | ||
182 | for (i = 0; i < HTAB_SIZE; i++) | |
183 | ht[i] = (slot_t *) 0; | |
184 | ||
185 | return; | |
186 | } | |
187 | ||
188 | ||
189 | static void | |
190 | clean_htab (hent_t * ht) | |
191 | /* free all slots */ | |
192 | { | |
193 | int i; | |
194 | slot_t *ent; | |
195 | slot_t *tent; | |
196 | ||
197 | for (i = 0; i < HTAB_SIZE; i++) | |
198 | { | |
199 | for (ent = ht[i]; ent;) | |
200 | { | |
201 | tent = ent->next; | |
202 | ||
203 | free (ent->sym); | |
204 | free (ent); | |
205 | ||
206 | ent = tent; | |
207 | } | |
208 | ||
209 | ht[i] = 0; | |
210 | } | |
211 | ||
212 | return; | |
213 | } | |
214 | ||
215 | ||
216 | static int | |
217 | hash (char *sym) | |
218 | { | |
219 | int a, key; | |
220 | double f; | |
221 | ||
222 | if (!sym || !*sym) | |
223 | return 0; | |
224 | ||
225 | for (key = *sym; *sym; sym++) | |
226 | { | |
227 | key += *sym; | |
228 | a = key; | |
229 | ||
230 | key = (int) ((a << 8) + (key >> 8)); | |
231 | key = (key > 0) ? key : -key; | |
232 | } | |
233 | ||
234 | f = key * FACTOR; | |
235 | a = (int) f; | |
236 | ||
237 | return (int) ((HTAB_SIZE - 1) * (f - a)); | |
238 | } | |
239 | ||
240 | ||
241 | static hent_t | |
242 | search (hent_t * htab, char *sym) | |
243 | /* search hashing table to find a matched slot */ | |
244 | { | |
245 | int key; | |
246 | slot_t *ent; | |
247 | ||
248 | key = hash (sym); | |
249 | ||
250 | for (ent = htab[key]; ent; ent = ent->next) | |
251 | { | |
252 | if (!strcmp (ent->sym, sym)) | |
253 | return ent; | |
254 | } | |
255 | ||
256 | return 0; /* no match */ | |
257 | } | |
258 | ||
259 | ||
260 | static void | |
261 | insert (hent_t * htab, slot_t * ent) | |
262 | /* insert a new slot to hashing table */ | |
263 | { | |
264 | int key; | |
265 | ||
266 | key = hash (ent->sym); | |
267 | ||
268 | ent->next = htab[key]; | |
269 | htab[key] = ent; | |
270 | ||
271 | return; | |
272 | } | |
273 | ||
274 | ||
275 | static slot_t * | |
276 | slot_alloc (char *sym) | |
277 | /* allocate a new slot with symbol */ | |
278 | { | |
279 | slot_t *ent; | |
280 | ||
281 | ent = (slot_t *) malloc (sizeof (slot_t)); | |
282 | ||
283 | ent->sym = (char *) malloc (strlen (sym) + 1); | |
284 | ||
285 | if (!ent->sym) | |
286 | { | |
287 | free (ent); | |
288 | return 0; | |
289 | } | |
290 | ||
291 | strcpy (ent->sym, sym); | |
292 | ||
293 | return ent; | |
294 | } | |
295 | ||
296 | ||
297 | static obj_t *obj_list = 0; | |
298 | ||
299 | void * | |
300 | dlopen (char *file, int mode) | |
301 | { | |
302 | stat_t st; | |
303 | obj_t *pobj; | |
304 | char buf[1024]; | |
305 | ||
306 | if (!file || !*file) | |
307 | { | |
308 | errno = EINVAL; | |
309 | return 0; | |
310 | } | |
311 | ||
312 | errno = 0; | |
313 | errmsg = 0; | |
314 | ||
315 | if (stat (file, &st)) | |
316 | return 0; | |
317 | ||
318 | for (pobj = obj_list; pobj; pobj = pobj->next) | |
319 | /* find a match object */ | |
320 | { | |
321 | if (pobj->ino == st.st_ino | |
322 | && pobj->dev == st.st_dev) | |
323 | { | |
324 | /* found a match. increase its | |
325 | * reference count and return | |
326 | * its address */ | |
327 | pobj->refn++; | |
328 | return pobj; | |
329 | } | |
330 | } | |
331 | ||
332 | pobj = (obj_t *) malloc (sizeof (obj_t)); | |
333 | ||
334 | if (!pobj) | |
335 | return 0; | |
336 | ||
337 | pobj->path = (char *) malloc (strlen (file) + 1); | |
338 | ||
339 | if (!pobj->path) | |
340 | { | |
341 | free (pobj); | |
342 | return 0; | |
343 | } | |
344 | ||
345 | strcpy (pobj->path, file); | |
346 | ||
347 | pobj->dev = st.st_dev; | |
348 | pobj->ino = st.st_ino; | |
349 | pobj->refn = 1; | |
350 | ||
351 | pobj->pentry = (int (*)()) load (file, 0, 0); | |
352 | ||
353 | if (!pobj->pentry) | |
354 | { | |
355 | free (pobj->path); | |
356 | free (pobj); | |
357 | return 0; | |
358 | } | |
359 | ||
360 | init_htab (pobj->htab); | |
361 | ||
362 | pobj->next = obj_list; | |
363 | obj_list = pobj; | |
364 | ||
365 | return pobj; | |
366 | } | |
367 | ||
368 | ||
369 | int | |
370 | dlclose (void *hobj) | |
371 | { | |
372 | obj_t *pobj = (obj_t *) hobj; | |
373 | obj_t *tpobj; | |
374 | int match = 0; | |
375 | ||
376 | if (!hobj) | |
377 | { | |
378 | errno = EINVAL; | |
379 | return -1; | |
380 | } | |
381 | ||
382 | errno = 0; | |
383 | errmsg = 0; | |
384 | ||
385 | if (pobj == obj_list) | |
386 | { | |
387 | pobj->refn--; | |
388 | ||
389 | if (pobj->refn) | |
390 | return 0; | |
391 | ||
392 | match = 1; | |
393 | obj_list = pobj->next; | |
394 | } | |
395 | ||
396 | for (tpobj = obj_list; !match && tpobj; tpobj = tpobj->next) | |
397 | { | |
398 | if (tpobj->next == pobj) | |
399 | { | |
400 | pobj->refn--; | |
401 | ||
402 | if (pobj->refn) | |
403 | return 0; | |
404 | ||
405 | match = 1; | |
406 | tpobj->next = pobj->next; | |
407 | } | |
408 | } | |
409 | ||
410 | if (match) | |
411 | { | |
412 | unload ((void *) (pobj->pentry)); | |
413 | clean_htab (pobj->htab); | |
414 | free (pobj->path); | |
415 | free (pobj); | |
416 | } | |
417 | ||
418 | return 0; | |
419 | } | |
420 | ||
421 | ||
422 | char * | |
423 | dlerror () | |
424 | { | |
425 | extern char *sys_errlist[]; | |
426 | ||
427 | if (!errmsg || !errmsg[0]) | |
428 | { | |
429 | if (errno >= 0) | |
430 | return sys_errlist[errno]; | |
431 | ||
432 | return ""; | |
433 | } | |
434 | ||
435 | return errmsg; | |
436 | } | |
437 | ||
438 | ||
439 | void * | |
440 | dlsym (void *hdl, char *sym) | |
441 | { | |
442 | nlist_t nl[3]; | |
443 | obj_t *pobj = (obj_t *) hdl; | |
444 | slot_t *ent; | |
445 | int (*fp) (); | |
446 | long lbuf[3]; | |
447 | ||
448 | if (!hdl || !(pobj->htab) || !sym || !*sym) | |
449 | { | |
450 | errno = EINVAL; | |
451 | return 0; | |
452 | } | |
453 | ||
454 | errno = 0; | |
455 | errmsg = 0; | |
456 | ||
457 | ent = search (pobj->htab, sym); | |
458 | ||
459 | if (ent) | |
460 | return ent->fdesc; | |
461 | ||
462 | #define n_name _n._n_name | |
463 | ||
464 | nl[0].n_name = ENTRY_SYM; | |
465 | nl[1].n_name = sym; | |
466 | nl[2].n_name = 0; | |
467 | ||
468 | /* There is a potential problem here. If application | |
469 | * did not pass a full path name, and changed the | |
470 | * working directory after the load(), then nlist() | |
471 | * will be unable to open the original shared library | |
472 | * file to resolve the symbols. there are 3 ways to working | |
473 | * round this: 1. convert to full pathname in driver | |
474 | * manager. 2. applications always pass driver's full | |
475 | * path name. 3. if driver itself don't support | |
476 | * SQLGetFunctions(), call it with SQL_ALL_FUNCTIONS | |
477 | * as flag immidately after SQLConnect(), SQLDriverConnect() | |
478 | * and SQLBrowseConnect() to force the driver manager | |
479 | * resolving all will be used symbols. | |
480 | */ | |
481 | if (nlist (pobj->path, nl) == -1) | |
482 | return 0; | |
483 | ||
484 | if (!nl[0].n_type && !nl[0].n_value) | |
485 | { | |
486 | errmsg = "can't locate module entry symbol"; | |
487 | return 0; | |
488 | } | |
489 | ||
490 | /* Note: On AIX 3.x if the object library is not | |
491 | * built with -g compiling option, .n_type field | |
492 | * is always 0. While on 4.x it will be 32. | |
493 | * On AIX 4.x, if the symbol is a entry point, | |
494 | * n_value will be 0. However, one thing is for sure | |
495 | * that if a symbol is not existance in the file, | |
496 | * both .n_type and .n_value would be 0. | |
497 | */ | |
498 | ||
499 | if (!nl[1].n_type && !nl[1].n_value) | |
500 | { | |
501 | errmsg = "symbol not existance in this module"; | |
502 | return 0; | |
503 | } | |
504 | ||
505 | ent = slot_alloc (sym); | |
506 | ||
507 | if (!ent) | |
508 | return 0; | |
509 | ||
510 | /* catch it with a slot in the hashing table */ | |
511 | insert (pobj->htab, ent); | |
512 | ||
513 | memcpy (ent->fdesc, pobj->pentry, sizeof (ent->fdesc)); | |
514 | ||
515 | /* now ent->fdesc[0] is the virtual address of entry point | |
516 | * and ent->fdesc[1] is the TOC of the module | |
517 | */ | |
518 | ||
519 | /* let's calculate the virtual address of the symbol | |
520 | * by adding a relative offset getting from the module | |
521 | * file symbol table, i.e | |
522 | * | |
523 | * functin virtual address = entry point virtual address + | |
524 | * + ( function offset in file - entry point offset in file ) | |
525 | */ | |
526 | ||
527 | (ent->fdesc)[0] = (ent->fdesc)[0] + | |
528 | (nl[1].n_value - nl[0].n_value); | |
529 | ||
530 | /* return the function descriptor */ | |
531 | return ent->fdesc; | |
532 | } | |
533 | #endif /* end of IBM AIX Section */ | |
534 | ||
535 | ||
536 | /********************************* | |
537 | * | |
538 | * Windows 3.x, 95, NT | |
539 | * | |
540 | *********************************/ | |
541 | ||
542 | #ifdef DLDAPI_WINDOWS | |
543 | #define DLDAPI_DEFINED | |
544 | #include <windows.h> | |
545 | ||
546 | void FAR * | |
547 | dlopen (char FAR * dll, int mode) | |
548 | { | |
549 | HINSTANCE hint; | |
550 | ||
551 | if (dll == NULL) | |
552 | { | |
553 | return GetWindowWord (NULL, GWW_HINSTANCE); | |
554 | } | |
555 | ||
556 | hint = LoadLibrary (dll); | |
557 | ||
558 | if (hint < HINSTANCE_ERROR) | |
559 | { | |
560 | return NULL; | |
561 | } | |
562 | ||
563 | return (void FAR *) hint; | |
564 | } | |
565 | ||
566 | ||
567 | void FAR * | |
568 | dlsym (void FAR * hdll, char FAR * sym) | |
569 | { | |
570 | return (void FAR *) GetProcAddress (hdll, sym); | |
571 | } | |
572 | ||
573 | ||
574 | char FAR * | |
575 | dlerror () | |
576 | { | |
577 | return 0L; /* unimplemented yet */ | |
578 | } | |
579 | ||
580 | ||
581 | int | |
582 | dlclose (void FAR * hdll) | |
583 | { | |
584 | FreeLibrary ((HINSTANCE) hdll); | |
585 | } | |
586 | #endif /* end of Windows family */ | |
587 | ||
588 | ||
589 | /*********************************** | |
590 | * | |
591 | * other platforms | |
592 | * | |
593 | ***********************************/ | |
594 | ||
595 | #ifdef DLDAPI_OS2 | |
596 | #define DLDAPI_DEFINED | |
597 | /* | |
598 | * DosLoadModule(), DosQueryProcAddress(), DosFreeModule(), ... | |
599 | */ | |
600 | #endif | |
601 | ||
602 | #ifdef DLDAPI_MAC | |
603 | #define DLDAPI_DEFINED | |
604 | #endif | |
605 | ||
606 | #ifdef DLDAPI_NEXT | |
607 | #define DLDAPI_DEFINED | |
608 | #endif | |
609 | ||
610 | #ifndef DLDAPI_DEFINED | |
611 | #error "dynamic load editor undefined" | |
612 | #endif |