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