1/* 2 * dlf.c 3 * 4 * $Id: dlf.c,v 1.4 2006/02/13 16:01:41 source Exp $ 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 * Copyright (C) 1996-2006 by OpenLink Software <iodbc@openlinksw.com> 12 * All Rights Reserved. 13 * 14 * This software is released under the terms of either of the following 15 * licenses: 16 * 17 * - GNU Library General Public License (see LICENSE.LGPL) 18 * - The BSD License (see LICENSE.BSD). 19 * 20 * Note that the only valid version of the LGPL license as far as this 21 * project is concerned is the original GNU Library General Public License 22 * Version 2, dated June 1991. 23 * 24 * While not mandated by the BSD license, any patches you make to the 25 * iODBC source code may be contributed back into the iODBC project 26 * at your discretion. Contributions will benefit the Open Source and 27 * Data Access community as a whole. Submissions may be made at: 28 * 29 * http://www.iodbc.org 30 * 31 * 32 * GNU Library Generic Public License Version 2 33 * ============================================ 34 * This library is free software; you can redistribute it and/or 35 * modify it under the terms of the GNU Library General Public 36 * License as published by the Free Software Foundation; only 37 * Version 2 of the License dated June 1991. 38 * 39 * This library is distributed in the hope that it will be useful, 40 * but WITHOUT ANY WARRANTY; without even the implied warranty of 41 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 42 * Library General Public License for more details. 43 * 44 * You should have received a copy of the GNU Library General Public 45 * License along with this library; if not, write to the Free 46 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 47 * 48 * 49 * The BSD License 50 * =============== 51 * Redistribution and use in source and binary forms, with or without 52 * modification, are permitted provided that the following conditions 53 * are met: 54 * 55 * 1. Redistributions of source code must retain the above copyright 56 * notice, this list of conditions and the following disclaimer. 57 * 2. Redistributions in binary form must reproduce the above copyright 58 * notice, this list of conditions and the following disclaimer in 59 * the documentation and/or other materials provided with the 60 * distribution. 61 * 3. Neither the name of OpenLink Software Inc. nor the names of its 62 * contributors may be used to endorse or promote products derived 63 * from this software without specific prior written permission. 64 * 65 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 66 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 67 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 68 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OPENLINK OR 69 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 70 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 71 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 72 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 73 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 74 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 75 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 76 */ 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92#include <dlf.h> 93#include <errno.h> 94 95#ifdef DLDAPI_DEFINED 96#undef DLDAPI_DEFINED 97#endif 98 99#ifdef DLDAPI_SVR4_DLFCN 100#define DLDAPI_DEFINED 101static char sccsid[] = "@(#)dynamic load interface -- SVR4 (dlfcn)"; 102#endif 103 104/********************************* 105 * 106 * HP/UX 107 * 108 *********************************/ 109 110#ifdef DLDAPI_HP_SHL 111#define DLDAPI_DEFINED 112static char sccsid[] = "@(#)dynamic load interface -- HP/UX (shl)"; 113 114#include <dl.h> 115 116 117void * 118dlopen (char *path, int mode) 119{ 120 return (void *) shl_load ((char *) (path), BIND_IMMEDIATE | BIND_NONFATAL, 0L); 121} 122 123 124void * 125dlsym (void *hdll, char *sym) 126{ 127 void *symaddr = 0; 128 int ret; 129 130#if 0 131 /* 132 * iODBC does not need a handle to itself 133 */ 134 if (!hdll) 135 hdll = (void *) PROG_HANDLE; 136#endif 137 138 /* Remember, a driver may export calls as function pointers 139 * (i.e. with type TYPE_DATA) rather than as functions 140 * (i.e. with type TYPE_PROCEDURE). Thus, to be safe, we 141 * uses TYPE_UNDEFINED to cover all of them. 142 */ 143 ret = shl_findsym ((shl_t *) & hdll, sym, TYPE_UNDEFINED, &symaddr); 144 145 if (ret == -1) 146 return 0; 147 148 return symaddr; 149} 150 151 152char * 153dlerror () 154{ 155 extern char *strerror (); 156 157 return strerror (errno); 158} 159 160 161int 162dlclose (void *hdll) 163{ 164 struct shl_descriptor d; 165 166 /* 167 * As HP/UX does not use a reference counter for unloading, 168 * we can only unload the driver when it is loaded once. 169 */ 170 if (shl_gethandle_r ((shl_t) hdll, &d) < 0 || d.ref_count > 1) 171 { 172 return 0; 173 } 174 175 return shl_unload ((shl_t) hdll); 176} 177#endif /* end of HP/UX Section */ 178 179 180/********************************* 181 * 182 * IBM AIX 183 * 184 *********************************/ 185 186#ifdef DLDAPI_AIX_LOAD 187#define DLDAPI_DEFINED 188static char sccsid[] = "@(#)dynamic load interface -- AIX (ldr)"; 189 190#include <sys/types.h> 191#include <sys/ldr.h> 192#include <sys/stat.h> 193#include <nlist.h> 194 195#ifndef HTAB_SIZE 196#define HTAB_SIZE 256 197#endif 198 199#define FACTOR 0.618039887 /* i.e. (sqrt(5) - 1)/2 */ 200 201#ifndef ENTRY_SYM 202#define ENTRY_SYM ".__start" /* default entry point for aix */ 203#endif 204 205typedef struct slot_s 206{ 207 char *sym; 208 long fdesc[3]; /* 12 bytes function descriptor */ 209 struct slot_s *next; 210} 211slot_t; 212 213/* Note: on AIX, a function pointer actually points to a 214 * function descriptor, a 12 bytes data. The first 4 bytes 215 * is the virtual address of the function. The next 4 bytes 216 * is the virtual address of TOC (Table of Contents) of the 217 * object module the function belong to. The last 4 bytes 218 * are always 0 for C and Fortran functions. Every object 219 * module has an entry point (which can be specified at link 220 * time by -e ld option). iODBC driver manager requires ODBC 221 * driver shared library always use the default entry point 222 * (so you shouldn't use -e ld option when creating a driver 223 * share library). load() returns the function descriptor of 224 * a module's entry point. From which we can calculate function 225 * descriptors of other functions in the same module by using 226 * the fact that the load() doesn't change the relative 227 * offset of functions to their module entry point(i.e the 228 * offset in memory loaded by load() will be as same as in 229 * the module library file). 230 */ 231 232typedef slot_t *hent_t; 233typedef struct nlist nlist_t; 234typedef struct stat stat_t; 235 236typedef struct obj 237 { 238 int dev; /* device id */ 239 int ino; /* inode number */ 240 char *path; /* file name */ 241 int (*pentry) (); /* entry point of this share library */ 242 int refn; /* number of reference */ 243 hent_t htab[HTAB_SIZE]; 244 struct obj *next; 245 } 246obj_t; 247 248static char *errmsg = 0; 249 250static void 251init_htab (hent_t * ht) 252/* initialize a hashing table */ 253{ 254 int i; 255 256 for (i = 0; i < HTAB_SIZE; i++) 257 ht[i] = (slot_t *) 0; 258 259 return; 260} 261 262 263static void 264clean_htab (hent_t * ht) 265/* free all slots */ 266{ 267 int i; 268 slot_t *ent; 269 slot_t *tent; 270 271 for (i = 0; i < HTAB_SIZE; i++) 272 { 273 for (ent = ht[i]; ent;) 274 { 275 tent = ent->next; 276 277 free (ent->sym); 278 free (ent); 279 280 ent = tent; 281 } 282 283 ht[i] = 0; 284 } 285 286 return; 287} 288 289 290static int 291hash (char *sym) 292{ 293 int a, key; 294 double f; 295 296 if (!sym || !*sym) 297 return 0; 298 299 for (key = *sym; *sym; sym++) 300 { 301 key += *sym; 302 a = key; 303 304 key = (int) ((a << 8) + (key >> 8)); 305 key = (key > 0) ? key : -key; 306 } 307 308 f = key * FACTOR; 309 a = (int) f; 310 311 return (int) ((HTAB_SIZE - 1) * (f - a)); 312} 313 314 315static hent_t 316search (hent_t * htab, char *sym) 317/* search hashing table to find a matched slot */ 318{ 319 int key; 320 slot_t *ent; 321 322 key = hash (sym); 323 324 for (ent = htab[key]; ent; ent = ent->next) 325 { 326 if (!strcmp (ent->sym, sym)) 327 return ent; 328 } 329 330 return 0; /* no match */ 331} 332 333 334static void 335insert (hent_t * htab, slot_t * ent) 336/* insert a new slot to hashing table */ 337{ 338 int key; 339 340 key = hash (ent->sym); 341 342 ent->next = htab[key]; 343 htab[key] = ent; 344 345 return; 346} 347 348 349static slot_t * 350slot_alloc (char *sym) 351/* allocate a new slot with symbol */ 352{ 353 slot_t *ent; 354 355 ent = (slot_t *) malloc (sizeof (slot_t)); 356 357 ent->sym = (char *) malloc (STRLEN (sym) + 1); 358 359 if (!ent->sym) 360 { 361 free (ent); 362 return 0; 363 } 364 365 STRCPY (ent->sym, sym); 366 367 return ent; 368} 369 370 371static obj_t *obj_list = 0; 372 373void * 374dlopen (char *file, int mode) 375{ 376 stat_t st; 377 obj_t *pobj; 378 char buf[1024]; 379 380 if (!file || !*file) 381 { 382 errno = EINVAL; 383 return 0; 384 } 385 386 errno = 0; 387 errmsg = 0; 388 389 if (stat (file, &st)) 390 return 0; 391 392 for (pobj = obj_list; pobj; pobj = pobj->next) 393 /* find a match object */ 394 { 395 if (pobj->ino == st.st_ino 396 && pobj->dev == st.st_dev) 397 { 398 /* found a match. increase its 399 * reference count and return 400 * its address */ 401 pobj->refn++; 402 return pobj; 403 } 404 } 405 406 pobj = (obj_t *) malloc (sizeof (obj_t)); 407 408 if (!pobj) 409 return 0; 410 411 pobj->path = (char *) malloc (STRLEN (file) + 1); 412 413 if (!pobj->path) 414 { 415 free (pobj); 416 return 0; 417 } 418 419 STRCPY (pobj->path, file); 420 421 pobj->dev = st.st_dev; 422 pobj->ino = st.st_ino; 423 pobj->refn = 1; 424 425 pobj->pentry = (int (*)()) load (file, 0, 0); 426 427 if (!pobj->pentry) 428 { 429 free (pobj->path); 430 free (pobj); 431 return 0; 432 } 433 434 init_htab (pobj->htab); 435 436 pobj->next = obj_list; 437 obj_list = pobj; 438 439 return pobj; 440} 441 442 443int 444dlclose (void *hobj) 445{ 446 obj_t *pobj = (obj_t *) hobj; 447 obj_t *tpobj; 448 int match = 0; 449 450 if (!hobj) 451 { 452 errno = EINVAL; 453 return -1; 454 } 455 456 errno = 0; 457 errmsg = 0; 458 459 if (pobj == obj_list) 460 { 461 pobj->refn--; 462 463 if (pobj->refn) 464 return 0; 465 466 match = 1; 467 obj_list = pobj->next; 468 } 469 470 for (tpobj = obj_list; !match && tpobj; tpobj = tpobj->next) 471 { 472 if (tpobj->next == pobj) 473 { 474 pobj->refn--; 475 476 if (pobj->refn) 477 return 0; 478 479 match = 1; 480 tpobj->next = pobj->next; 481 } 482 } 483 484 if (match) 485 { 486 unload ((void *) (pobj->pentry)); 487 clean_htab (pobj->htab); 488 free (pobj->path); 489 free (pobj); 490 } 491 492 return 0; 493} 494 495 496char * 497dlerror () 498{ 499 extern char *sys_errlist[]; 500 501 if (!errmsg || !errmsg[0]) 502 { 503 if (errno >= 0) 504 return sys_errlist[errno]; 505 506 return ""; 507 } 508 509 return errmsg; 510} 511 512 513void * 514dlsym (void *hdl, char *sym) 515{ 516 nlist_t nl[3]; 517 obj_t *pobj = (obj_t *) hdl; 518 slot_t *ent; 519 int (*fp) (); 520 long lbuf[3]; 521 522 if (!hdl || !(pobj->htab) || !sym || !*sym) 523 { 524 errno = EINVAL; 525 return 0; 526 } 527 528 errno = 0; 529 errmsg = 0; 530 531 ent = search (pobj->htab, sym); 532 533 if (ent) 534 return ent->fdesc; 535 536#define n_name _n._n_name 537 538 nl[0].n_name = ENTRY_SYM; 539 nl[1].n_name = sym; 540 nl[2].n_name = 0; 541 542 /* There is a potential problem here. If application 543 * did not pass a full path name, and changed the 544 * working directory after the load(), then nlist() 545 * will be unable to open the original shared library 546 * file to resolve the symbols. there are 3 ways to working 547 * round this: 1. convert to full pathname in driver 548 * manager. 2. applications always pass driver's full 549 * path name. 3. if driver itself don't support 550 * SQLGetFunctions(), call it with SQL_ALL_FUNCTIONS 551 * as flag immediately after SQLConnect(), SQLDriverConnect() 552 * and SQLBrowseConnect() to force the driver manager 553 * resolving all will be used symbols. 554 */ 555 if (nlist (pobj->path, nl) == -1) 556 return 0; 557 558 if (!nl[0].n_type && !nl[0].n_value) 559 { 560 errmsg = "can't locate module entry symbol"; 561 return 0; 562 } 563 564 /* Note: On AIX 3.x if the object library is not 565 * built with -g compiling option, .n_type field 566 * is always 0. While on 4.x it will be 32. 567 * On AIX 4.x, if the symbol is a entry point, 568 * n_value will be 0. However, one thing is for sure 569 * that if a symbol does not exists in the file, 570 * both .n_type and .n_value would be 0. 571 */ 572 573 if (!nl[1].n_type && !nl[1].n_value) 574 { 575 errmsg = "symbol does not exist in this module"; 576 return 0; 577 } 578 579 ent = slot_alloc (sym); 580 581 if (!ent) 582 return 0; 583 584 /* catch it with a slot in the hashing table */ 585 insert (pobj->htab, ent); 586 587 memcpy (ent->fdesc, pobj->pentry, sizeof (ent->fdesc)); 588 589 /* now ent->fdesc[0] is the virtual address of entry point 590 * and ent->fdesc[1] is the TOC of the module 591 */ 592 593 /* let's calculate the virtual address of the symbol 594 * by adding a relative offset getting from the module 595 * file symbol table, i.e 596 * 597 * function virtual address = entry point virtual address + 598 * + ( function offset in file - entry point offset in file ) 599 */ 600 601 (ent->fdesc)[0] = (ent->fdesc)[0] + 602 (nl[1].n_value - nl[0].n_value); 603 604 /* return the function descriptor */ 605 return ent->fdesc; 606} 607#endif /* end of IBM AIX Section */ 608 609 610/********************************* 611 * 612 * Windows 3.x, 95, NT 613 * 614 *********************************/ 615 616#ifdef DLDAPI_WINDOWS 617#define DLDAPI_DEFINED 618static char sccsid[] = "@(#)dynamic load interface -- Windows (LoadLibrary)"; 619 620#include <windows.h> 621 622void * 623dlopen (char * dll, int mode) 624{ 625 HINSTANCE hint; 626 627 if (dll == NULL) 628 { 629 return GetWindowWord (NULL, GWW_HINSTANCE); 630 } 631 632 hint = LoadLibrary (dll); 633 634 if (hint < HINSTANCE_ERROR) 635 { 636 return NULL; 637 } 638 639 return (void *) hint; 640} 641 642 643void * 644dlsym (void * hdll, char * sym) 645{ 646 return (void *) GetProcAddress (hdll, sym); 647} 648 649 650char * 651dlerror () 652{ 653 return 0L; /* unimplemented yet */ 654} 655 656 657int 658dlclose (void * hdll) 659{ 660 FreeLibrary ((HINSTANCE) hdll); 661} 662#endif /* end of Windows family */ 663 664 665/*********************************** 666 * 667 * VMS 668 * 669 ***********************************/ 670 671#ifdef VMS 672#define DLDAPI_DEFINED 673#ifdef DLDAPI_VMS_IODBC 674static char sccsid[] = "@(#)dynamic load interface -- VMS"; 675 676#include <stdio.h> 677#include <descrip.h> 678#include <starlet.h> 679#include <ssdef.h> 680#include <libdef.h> 681#include <lib$routines> 682#include <rmsdef.h> 683#include <fabdef.h> 684#include <namdef.h> 685 686#ifndef LIB$M_FIS_MIXCASE 687#define LIB$M_FIS_MIXCASE 1<<4 688#endif 689 690typedef struct 691{ 692 struct dsc$descriptor_s filename_d; 693 struct dsc$descriptor_s image_d; 694 char filename[NAM$C_MAXRSS]; /* $PARSEd image name */ 695} 696dll_t; 697 698/* 699 * The following static int contains the last VMS error returned. It is kept 700 * static so that dlerror() can get it. This method is dangerous if you have 701 * threaded applications, but this is the way the UNIX dlopen() etc 702 * is defined. 703 */ 704static int saved_status = SS$_NORMAL; 705static char dlerror_buf[256]; 706 707 708static int 709iodbc_find_image_symbol ( 710 struct dsc$descriptor_s *filename_d, 711 struct dsc$descriptor_s *symbol_d, 712 void **rp, 713 struct dsc$descriptor_s *image_d, int flag) 714{ 715 lib$establish (lib$sig_to_ret); 716 return lib$find_image_symbol (filename_d, symbol_d, rp, image_d, flag); 717} 718 719 720void * 721iodbc_dlopen (char *path, int unused_flag) 722{ 723 int status; 724 dll_t *dll; 725 struct FAB imgfab; 726 struct NAM imgnam; 727 static char defimg[] = "SYS$SHARE:.EXE"; 728 729 if (path == NULL) 730 { 731 saved_status = SS$_UNSUPPORTED; 732 return NULL; 733 } 734 735 dll = malloc (sizeof (dll_t)); 736 if (dll == NULL) 737 { 738 saved_status = SS$_INSFMEM; 739 return NULL; 740 } 741 742 imgfab = cc$rms_fab; 743 imgfab.fab$l_fna = path; 744 imgfab.fab$b_fns = STRLEN (path); 745 imgfab.fab$w_ifi = 0; 746 imgfab.fab$l_dna = defimg; 747 imgfab.fab$b_dns = sizeof (defimg); 748 imgfab.fab$l_fop = FAB$M_NAM; 749 imgfab.fab$l_nam = &imgnam; 750 imgnam = cc$rms_nam; 751 imgnam.nam$l_esa = dll->filename; 752 imgnam.nam$b_ess = NAM$C_MAXRSS; 753 status = sys$parse (&imgfab); 754 if (!(status & 1)) 755 { 756 free (dll); 757 saved_status = status; 758 return NULL; 759 } 760 761 dll->filename_d.dsc$b_dtype = DSC$K_DTYPE_T; 762 dll->filename_d.dsc$b_class = DSC$K_CLASS_S; 763 dll->filename_d.dsc$a_pointer = imgnam.nam$l_name; 764 dll->filename_d.dsc$w_length = imgnam.nam$b_name; 765 dll->image_d.dsc$b_dtype = DSC$K_DTYPE_T; 766 dll->image_d.dsc$b_class = DSC$K_CLASS_S; 767 dll->image_d.dsc$a_pointer = dll->filename; 768 dll->image_d.dsc$w_length = imgnam.nam$b_esl; 769 770 /* 771 * VMS does not have the concept of first opening a shared library and then 772 * asking for symbols; the LIB$FIND_IMAGE_SYMBOL routine does both. 773 * Since I want my implementation of dlopen() to return an error if the 774 * shared library can not be loaded, I try to find a dummy symbol in the 775 * library. 776 */ 777 iodbc_dlsym (dll, "THIS_ROUTINE_MIGHT_NOT_EXIST"); 778 if (!((saved_status ^ LIB$_KEYNOTFOU) & ~7)) 779 { 780 saved_status = SS$_NORMAL; 781 } 782 if (saved_status & 1) 783 { 784 return dll; 785 } 786 else 787 { 788 free (dll); 789 return NULL; 790 } 791} 792 793 794void * 795iodbc_dlsym (void *hdll, char *sym) 796{ 797 int status; 798 dll_t *dll; 799 struct dsc$descriptor_s symbol_d; 800 void *rp; 801 802 dll = hdll; 803 if (dll == NULL) 804 return NULL; 805 806 symbol_d.dsc$b_dtype = DSC$K_DTYPE_T; 807 symbol_d.dsc$b_class = DSC$K_CLASS_S; 808 symbol_d.dsc$a_pointer = sym; 809 symbol_d.dsc$w_length = STRLEN (sym); 810 status = iodbc_find_image_symbol (&dll->filename_d, &symbol_d, &rp, 811 &dll->image_d, 0); 812 if (!((saved_status ^ LIB$_KEYNOTFOU) & ~7)) 813 { 814 status = iodbc_find_image_symbol (&dll->filename_d, &symbol_d, &rp, 815 &dll->image_d, LIB$M_FIS_MIXCASE); 816 } 817 if (status & 1) 818 { 819 return rp; 820 } 821 else 822 { 823 saved_status = status; 824 return NULL; 825 } 826} 827 828 829char * 830iodbc_dlerror () 831{ 832 struct dsc$descriptor desc; 833 short outlen; 834 int status; 835 836 if (saved_status & 1) 837 { 838 return NULL; 839 } 840 841 desc.dsc$b_dtype = DSC$K_DTYPE_T; 842 desc.dsc$b_class = DSC$K_CLASS_S; 843 desc.dsc$a_pointer = dlerror_buf; 844 desc.dsc$w_length = sizeof (dlerror_buf); 845 status = sys$getmsg (saved_status, &outlen, &desc, 15, 0); 846 if (status & 1) 847 { 848 dlerror_buf[outlen] = '\0'; 849 } 850 else 851 { 852 sprintf (dlerror_buf, "Message number %8X", saved_status); 853 } 854 saved_status = SS$_NORMAL; 855 return (dlerror_buf); 856} 857 858 859int 860iodbc_dlclose (void *hdll) 861{ 862 /* 863 * Not really implemented since VMS doesn't support unloading images. 864 * The hdll pointer is released though. 865 */ 866 free (hdll); 867 return 0; 868} 869#endif /* DLDAPI_VMS_IODBC */ 870#endif /* VMS */ 871 872 873/********************************* 874 * 875 * Apple MacOS X Rhapsody 876 * 877 *********************************/ 878#ifdef DLDAPI_DYLD 879#define DLDAPI_DEFINED 880static char sccsid[] = "@(#)dynamic load interface -- Mac OS X (dyld)"; 881 882#include <stdio.h> 883#include <mach-o/dyld.h> 884 885 886static void 887undefined_symbol_handler (const char *symbolName) 888{ 889 fprintf (stderr, "dyld found undefined symbol: %s\n", symbolName); 890 891 abort (); 892} 893 894 895static NSModule 896multiple_symbol_handler (NSSymbol s, NSModule old, NSModule new) 897{ 898 /* 899 * Since we can't unload symbols, we're going to run into this 900 * every time we reload a module. Workaround here is to just 901 * rebind to the new symbol, and forget about the old one. 902 * This is crummy, because it's basically a memory leak. 903 */ 904 905 return (new); 906} 907 908 909static void 910linkEdit_symbol_handler (NSLinkEditErrors c, int errorNumber, 911 const char *fileName, const char *errorString) 912{ 913 fprintf (stderr, "dyld errors during link edit for file %s\n%s\n", 914 fileName, errorString); 915 916 abort (); 917} 918 919 920void * 921dlopen (char *path, int mode) 922{ 923 NSObjectFileImage image; 924 NSLinkEditErrorHandlers handlers; 925 NSModule handle = NULL; 926 int i; 927 928 /* 929 * Install error handler 930 */ 931 handlers.undefined = undefined_symbol_handler; 932#if !defined (NSLINKMODULE_OPTION_PRIVATE) 933 handlers.multiple = multiple_symbol_handler; 934#endif 935 handlers.linkEdit = linkEdit_symbol_handler; 936 937 NSInstallLinkEditErrorHandlers (&handlers); 938 939 /* 940 * Load object 941 */ 942 i = NSCreateObjectFileImageFromFile (path, &image); 943 if (i != NSObjectFileImageSuccess) 944 { 945 static char *ErrorStrings[] = 946 { 947 "%s(%d): Object Image Load Failure\n", 948 "%s(%d): Object Image Load Success\n", 949 "%s(%d): Not an recognizable object file\n", 950 "%s(%d): No valid architecture\n", 951 "%s(%d): Object image has an invalid format\n", 952 "%s(%d): Invalid access (permissions?)\n", 953 "%s(%d): Unknown error code from NSCreateObjectFileImageFromFile\n", 954 }; 955 956 if (i < 0 || i > 6) 957 i = 6; 958 959 fprintf (stderr, ErrorStrings[i], path, i); 960 } 961 else 962 { 963#if !defined (NSLINKMODULE_OPTION_PRIVATE) 964 handle = NSLinkModule (image, path, TRUE); 965#else 966 handle = NSLinkModule (image, path, NSLINKMODULE_OPTION_PRIVATE); 967#endif 968 } 969 970 return (void *) handle; 971} 972 973 974void * 975dlsym (void *hdll, char *sym) 976{ 977 NSSymbol symbol; 978 979#if !defined (NSLINKMODULE_OPTION_PRIVATE) 980 if (NSIsSymbolNameDefined (sym)) 981 { 982 symbol = NSLookupAndBindSymbol (sym); 983 984 return NSAddressOfSymbol (symbol); 985 } 986 987 return NULL; 988#else 989 symbol = NSLookupSymbolInModule ((NSModule) hdll, sym); 990 991 return NSAddressOfSymbol (symbol); 992#endif 993} 994 995 996char * 997dlerror () 998{ 999 return NULL; 1000} 1001 1002 1003int 1004dlclose (void *hdll) 1005{ 1006 NSUnLinkModule (hdll, FALSE); 1007 return 0; 1008} 1009#endif /* end of Rhapsody Section */ 1010 1011 1012/********************************* 1013 * 1014 * Apple MacOS X Rhapsody 1015 * 1016 *********************************/ 1017#ifdef DLDAPI_MACX 1018#define DLDAPI_DEFINED 1019static char sccsid[] = "@(#)dynamic load interface -- Mac OS X 10.x (dyld)"; 1020 1021static struct dlopen_handle *dlopen_handles = NULL; 1022static const struct dlopen_handle main_program_handle = { 0 }; 1023static char *dlerror_pointer = NULL; 1024 1025/* 1026 * NSMakePrivateModulePublic() is not part of the public dyld API so we define 1027 * it here. The internal dyld function pointer for 1028 * __dyld_NSMakePrivateModulePublic is returned so thats all that matters to get 1029 * the functionality need to implement the dlopen() interfaces. 1030 */ 1031static int 1032NSMakePrivateModulePublic (NSModule module) 1033{ 1034 static int (*p) (NSModule module) = NULL; 1035 1036 if (p == NULL) 1037 _dyld_func_lookup ("__dyld_NSMakePrivateModulePublic", 1038 (void *) &p); 1039 if (p == NULL) 1040 { 1041#ifdef DEBUG 1042 printf ("_dyld_func_lookup of __dyld_NSMakePrivateModulePublic " 1043 "failed\n"); 1044#endif 1045 return (FALSE); 1046 } 1047 return (p (module)); 1048} 1049 1050 1051/* 1052 * dlopen() the MacOS X version of the FreeBSD dlopen() interface. 1053 */ 1054void * 1055iodbc_dlopen (char * path, int mode) 1056{ 1057 void *retval; 1058 struct stat stat_buf; 1059 NSObjectFileImage objectFileImage; 1060 NSObjectFileImageReturnCode ofile_result_code; 1061 NSModule module; 1062 struct dlopen_handle *p; 1063 unsigned long options; 1064 NSSymbol NSSymbol; 1065 void (*init) (void); 1066 static char errbuf[640]; 1067 1068 dlerror_pointer = NULL; 1069 1070 /* 1071 * A NULL path is to indicate the caller wants a handle for the 1072 * main program. 1073 */ 1074 if (path == NULL) 1075 { 1076 retval = (void *) &main_program_handle; 1077 return (retval); 1078 } 1079 1080 /* see if the path exists and if so get the device and inode number */ 1081 if (stat (path, &stat_buf) == -1) 1082 { 1083 dlerror_pointer = strerror (errno); 1084 return (NULL); 1085 } 1086 1087 /* 1088 * If we don't want an unshared handle see if we already have a handle 1089 * for this path. 1090 */ 1091 if ((mode & RTLD_UNSHARED) != RTLD_UNSHARED) 1092 { 1093 p = dlopen_handles; 1094 while (p != NULL) 1095 { 1096 if (p->dev == stat_buf.st_dev && p->ino == stat_buf.st_ino) 1097 { 1098 /* skip unshared handles */ 1099 if ((p->dlopen_mode & RTLD_UNSHARED) == RTLD_UNSHARED) 1100 continue; 1101 /* 1102 * We have already created a handle for this path. The 1103 * caller might be trying to promote an RTLD_LOCAL handle 1104 * to a RTLD_GLOBAL. Or just looking it up with 1105 * RTLD_NOLOAD. 1106 */ 1107 if ((p->dlopen_mode & RTLD_LOCAL) == RTLD_LOCAL && 1108 (mode & RTLD_GLOBAL) == RTLD_GLOBAL) 1109 { 1110 /* promote the handle */ 1111 if (NSMakePrivateModulePublic (p->module) == TRUE) 1112 { 1113 p->dlopen_mode &= ~RTLD_LOCAL; 1114 p->dlopen_mode |= RTLD_GLOBAL; 1115 p->dlopen_count++; 1116 return (p); 1117 } 1118 else 1119 { 1120 dlerror_pointer = "can't promote handle from " 1121 "RTLD_LOCAL to RTLD_GLOBAL"; 1122 return (NULL); 1123 } 1124 } 1125 p->dlopen_count++; 1126 return (p); 1127 } 1128 p = p->next; 1129 } 1130 } 1131 1132 /* 1133 * We do not have a handle for this path if we were just trying to 1134 * look it up return NULL to indicate we don't have it. 1135 */ 1136 if ((mode & RTLD_NOLOAD) == RTLD_NOLOAD) 1137 { 1138 dlerror_pointer = "no existing handle for path RTLD_NOLOAD test"; 1139 return (NULL); 1140 } 1141 1142 /* try to create an object file image from this path */ 1143 ofile_result_code = NSCreateObjectFileImageFromFile (path, 1144 &objectFileImage); 1145 if (ofile_result_code != NSObjectFileImageSuccess) 1146 { 1147 switch (ofile_result_code) 1148 { 1149 case NSObjectFileImageFailure: 1150 dlerror_pointer = "object file setup failure"; 1151 return (NULL); 1152 case NSObjectFileImageInappropriateFile: 1153 dlerror_pointer = "not a Mach-O MH_BUNDLE file type"; 1154 return (NULL); 1155 case NSObjectFileImageArch: 1156 dlerror_pointer = "no object for this architecture"; 1157 return (NULL); 1158 case NSObjectFileImageFormat: 1159 dlerror_pointer = "bad object file format"; 1160 return (NULL); 1161 case NSObjectFileImageAccess: 1162 dlerror_pointer = "can't read object file"; 1163 return (NULL); 1164 default: 1165 dlerror_pointer = "unknown error from " 1166 "NSCreateObjectFileImageFromFile()"; 1167 return (NULL); 1168 } 1169 } 1170 1171 /* try to link in this object file image */ 1172 options = NSLINKMODULE_OPTION_NONE | 1173 NSLINKMODULE_OPTION_PRIVATE | 1174 NSLINKMODULE_OPTION_RETURN_ON_ERROR; 1175 if ((mode & RTLD_NOW) == RTLD_NOW) 1176 options |= NSLINKMODULE_OPTION_BINDNOW; 1177 module = NSLinkModule (objectFileImage, path, options); 1178 NSDestroyObjectFileImage (objectFileImage); 1179 if (module == NULL) 1180 { 1181 NSLinkEditErrors lerr; 1182 int errNum; 1183 const char *fname; 1184 const char *errStr; 1185 NSLinkEditError(&lerr, &errNum, &fname, &errStr); 1186 sprintf(errbuf, "NSLinkModule() failed for dlopen() ([%.256s][%.256s])", 1187 fname, errStr); 1188 dlerror_pointer = errbuf; 1189 return (NULL); 1190 } 1191 1192 /* 1193 * If the handle is to be global promote the handle. It is done this 1194 * way to avoid multiply defined symbols. 1195 */ 1196 if ((mode & RTLD_GLOBAL) == RTLD_GLOBAL) 1197 { 1198 if (NSMakePrivateModulePublic (module) == FALSE) 1199 { 1200 dlerror_pointer = "can't promote handle from RTLD_LOCAL to " 1201 "RTLD_GLOBAL"; 1202 return (NULL); 1203 } 1204 } 1205 1206 p = malloc (sizeof (struct dlopen_handle)); 1207 if (p == NULL) 1208 { 1209 dlerror_pointer = "can't allocate memory for the dlopen handle"; 1210 return (NULL); 1211 } 1212 1213 /* fill in the handle */ 1214 p->dev = stat_buf.st_dev; 1215 p->ino = stat_buf.st_ino; 1216 if (mode & RTLD_GLOBAL) 1217 p->dlopen_mode = RTLD_GLOBAL; 1218 else 1219 p->dlopen_mode = RTLD_LOCAL; 1220 p->dlopen_mode |= (mode & RTLD_UNSHARED) | 1221 (mode & RTLD_NODELETE) | (mode & RTLD_LAZY_UNDEF); 1222 p->dlopen_count = 1; 1223 p->module = module; 1224 p->prev = NULL; 1225 p->next = dlopen_handles; 1226 if (dlopen_handles != NULL) 1227 dlopen_handles->prev = p; 1228 dlopen_handles = p; 1229 1230 /* call the init function if one exists */ 1231 NSSymbol = NSLookupSymbolInModule (p->module, "__init"); 1232 if (NSSymbol != NULL) 1233 { 1234 init = NSAddressOfSymbol (NSSymbol); 1235 init (); 1236 } 1237 1238 return (p); 1239} 1240 1241 1242/* 1243 * dlsym() the MacOS X version of the FreeBSD dlopen() interface. 1244 */ 1245void * 1246iodbc_dlsym (void * handle, char * symbol) 1247{ 1248 struct dlopen_handle *dlopen_handle, *p; 1249 char symbol2[1024]; 1250 NSSymbol NSSymbol; 1251 void *address; 1252 1253 symbol2[0] = '_'; 1254 strcpy (symbol2 + 1, symbol); 1255 1256 dlopen_handle = (struct dlopen_handle *) handle; 1257 1258 /* 1259 * If this is the handle for the main program do a global lookup. 1260 */ 1261 if (dlopen_handle == (struct dlopen_handle *) &main_program_handle) 1262 { 1263 if (NSIsSymbolNameDefined (symbol2) == TRUE) 1264 { 1265 NSSymbol = NSLookupAndBindSymbol (symbol2); 1266 address = NSAddressOfSymbol (NSSymbol); 1267 dlerror_pointer = NULL; 1268 return (address); 1269 } 1270 else 1271 { 1272 dlerror_pointer = "symbol not found"; 1273 return (NULL); 1274 } 1275 } 1276 1277 /* 1278 * Find this handle and do a lookup in just this module. 1279 */ 1280 p = dlopen_handles; 1281 while (p != NULL) 1282 { 1283 if (dlopen_handle == p) 1284 { 1285 NSSymbol = NSLookupSymbolInModule (p->module, symbol2); 1286 if (NSSymbol != NULL) 1287 { 1288 address = NSAddressOfSymbol (NSSymbol); 1289 dlerror_pointer = NULL; 1290 return (address); 1291 } 1292 else 1293 { 1294 dlerror_pointer = "symbol not found"; 1295 return (NULL); 1296 } 1297 } 1298 p = p->next; 1299 } 1300 1301 dlerror_pointer = "bad handle passed to dlsym()"; 1302 return (NULL); 1303} 1304 1305 1306/* 1307 * dlerror() the MacOS X version of the FreeBSD dlopen() interface. 1308 */ 1309char * 1310iodbc_dlerror (void) 1311{ 1312 const char *p; 1313 1314 p = (const char *) dlerror_pointer; 1315 dlerror_pointer = NULL; 1316 return (char *)(p); 1317} 1318 1319 1320/* 1321 * dlclose() the MacOS X version of the FreeBSD dlopen() interface. 1322 */ 1323int 1324iodbc_dlclose (void * handle) 1325{ 1326 struct dlopen_handle *p, *q; 1327 unsigned long options; 1328 NSSymbol NSSymbol; 1329 void (*fini) (void); 1330 1331 dlerror_pointer = NULL; 1332 q = (struct dlopen_handle *) handle; 1333 p = dlopen_handles; 1334 while (p != NULL) 1335 { 1336 if (p == q) 1337 { 1338 /* if the dlopen() count is not zero we are done */ 1339 p->dlopen_count--; 1340 if (p->dlopen_count != 0) 1341 return (0); 1342 1343 /* call the fini function if one exists */ 1344 NSSymbol = NSLookupSymbolInModule (p->module, "__fini"); 1345 if (NSSymbol != NULL) 1346 { 1347 fini = NSAddressOfSymbol (NSSymbol); 1348 fini (); 1349 } 1350 1351 /* unlink the module for this handle */ 1352 options = 0; 1353 if (p->dlopen_mode & RTLD_NODELETE) 1354 options |= NSUNLINKMODULE_OPTION_KEEP_MEMORY_MAPPED; 1355 if (p->dlopen_mode & RTLD_LAZY_UNDEF) 1356 options |= NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES; 1357 if (NSUnLinkModule (p->module, options) == FALSE) 1358 { 1359 dlerror_pointer = "NSUnLinkModule() failed for dlclose()"; 1360 return (-1); 1361 } 1362 if (p->prev != NULL) 1363 p->prev->next = p->next; 1364 if (p->next != NULL) 1365 p->next->prev = p->prev; 1366 if (dlopen_handles == p) 1367 dlopen_handles = p->next; 1368 free (p); 1369 return (0); 1370 } 1371 p = p->next; 1372 } 1373 dlerror_pointer = "invalid handle passed to dlclose()"; 1374 return (-1); 1375} 1376 1377#endif /* end of Rhapsody Section */ 1378 1379/********************************* 1380 * 1381 * Macintosh 1382 * 1383 *********************************/ 1384#ifdef DLDAPI_MAC 1385static char sccsid[] = "@(#)dynamic load interface -- Mac Classic"; 1386 1387#include <CodeFragments.h> 1388#include <strconv.h> 1389 1390static char *msg_error = NULL; 1391 1392void * 1393dlopen (char *dll, int mode) 1394{ 1395#ifdef __POWERPC__ 1396 CFragConnectionID conn_id; 1397 Ptr main_addr; 1398 Str255 name; 1399 OSErr err; 1400 1401 if (dll == NULL) 1402 { 1403 msg_error = "Library name not valid."; 1404 return NULL; 1405 } 1406 1407 if ((err = GetSharedLibrary ((unsigned char *) str_to_Str255 (dll), 1408 kPowerPCCFragArch, kLoadCFrag, &conn_id, &main_addr, 1409 name)) != noErr) 1410 { 1411 msg_error = "Library cannot be loaded."; 1412 return NULL; 1413 } 1414 1415 msg_error = NULL; 1416 return (void *) conn_id; 1417#else 1418 CFragConnectionID conn_id; 1419 Ptr main_addr; 1420 Str255 name; 1421 OSErr err; 1422 1423 if (dll == NULL) 1424 { 1425 msg_error = "Library name not valid."; 1426 return NULL; 1427 } 1428 1429 if ((err = GetSharedLibrary ((unsigned char *) str_to_Str255 (dll), 1430 kMotorola68KCFragArch, kLoadCFrag, &conn_id, &main_addr, 1431 name)) != noErr) 1432 { 1433 msg_error = "Library cannot be loaded."; 1434 return NULL; 1435 } 1436 1437 msg_error = NULL; 1438 return (void *) conn_id; 1439#endif 1440} 1441 1442 1443void * 1444dlsym (void *hdll, char *sym) 1445{ 1446#ifdef __POWERPC__ 1447 Ptr symbol; 1448 CFragSymbolClass symbol_type; 1449 OSErr err; 1450 1451 if (sym == NULL) 1452 { 1453 msg_error = "Symbol name not valid."; 1454 return NULL; 1455 } 1456 1457 if ((err = 1458 FindSymbol ((CFragConnectionID) hdll, 1459 (unsigned char *) str_to_Str255 (sym), &symbol, 1460 &symbol_type)) != noErr) 1461 { 1462 msg_error = "Symbol cannot be loaded."; 1463 return NULL; 1464 } 1465 1466 msg_error = NULL; 1467 return symbol; 1468#else 1469 Ptr symbol; 1470 CFragSymbolClass symbol_type; 1471 1472 if (sym == NULL) 1473 { 1474 msg_error = "Symbol name not valid."; 1475 return NULL; 1476 } 1477 1478 if (FindSymbol ((CFragConnectionID) hdll, 1479 (unsigned char *) str_to_Str255 (sym), &symbol, 1480 &symbol_type) != noErr) 1481 { 1482 msg_error = "Symbol cannot be loaded."; 1483 return NULL; 1484 } 1485 1486 msg_error = NULL; 1487 return symbol; 1488#endif 1489} 1490 1491 1492char * 1493dlerror () 1494{ 1495 return (msg_error) ? msg_error : "No error detected."; 1496} 1497 1498 1499int 1500dlclose (void *hdll) 1501{ 1502 /* It should be something like that .... */ 1503 /* but some applications like Office 2001 */ 1504 /* have a problem with that ... just let */ 1505 /* the Mac unload the library when the */ 1506 /* application stop ... */ 1507#ifdef __POWERPC__ 1508/* if( CloseConnection((CFragConnectionID*)hdll) ) 1509 { 1510 msg_error = "Library cannot be unloaded."; 1511 return 1; 1512 } 1513 msg_error = NULL; 1514 return 0;*/ 1515#else 1516 if (CloseConnection ((CFragConnectionID *) hdll)) 1517 { 1518 msg_error = "Library cannot be unloaded."; 1519 return 1; 1520 } 1521 1522 msg_error = NULL; 1523 return 0; 1524#endif 1525} 1526 1527#define DLDAPI_DEFINED 1528#endif /* end of Macintosh family */ 1529 1530 1531/********************************* 1532 * 1533 * BeOS 1534 * 1535 *********************************/ 1536#ifdef DLDAPI_BE 1537#define DLDAPI_DEFINED 1538static char sccsid[] = "@(#)dynamic load interface -- BeOS"; 1539 1540#include <kernel/image.h> 1541#include <be/support/Errors.h> 1542 1543static char *msg_error = NULL; 1544 1545void * 1546dlopen (char *dll, int mode) 1547{ 1548 image_id dll_id; 1549 1550 if (dll == NULL) 1551 { 1552 msg_error = "Library name not valid."; 1553 return NULL; 1554 } 1555 1556 dll_id = load_add_on (dll); 1557 1558 if (dll_id == B_ERROR) 1559 { 1560 msg_error = "Library cannot be loaded."; 1561 return NULL; 1562 } 1563 1564 msg_error = NULL; 1565 return (void *) dll_id; 1566} 1567 1568 1569void * 1570dlsym (void *hdll, char *sym) 1571{ 1572 void *address = NULL; 1573 1574 if (sym == NULL) 1575 { 1576 msg_error = "Symbol name not valid."; 1577 return NULL; 1578 } 1579 1580 if (get_image_symbol ((image_id) hdll, sym, B_SYMBOL_TYPE_ANY, 1581 &address) != B_OK) 1582 { 1583 msg_error = "Symbol cannot be loaded."; 1584 return NULL; 1585 } 1586 1587 msg_error = NULL; 1588 return address; 1589} 1590 1591 1592char * 1593dlerror () 1594{ 1595 return (msg_error) ? msg_error : "No error detected."; 1596} 1597 1598 1599int 1600dlclose (void *hdll) 1601{ 1602 if (unload_add_on ((image_id) hdll) != B_OK) 1603 { 1604 msg_error = "Library cannot be unloaded."; 1605 return 1; 1606 } 1607 1608 msg_error = NULL; 1609 return 0; 1610} 1611 1612#endif /* end of BeOS */ 1613 1614 1615 1616/*********************************** 1617 * 1618 * other platforms 1619 * 1620 ***********************************/ 1621 1622#ifdef DLDAPI_OS2 1623#define DLDAPI_DEFINED 1624/* 1625 * DosLoadModule(), DosQueryProcAddress(), DosFreeModule(), ... 1626 */ 1627#endif 1628 1629#ifdef DLDAPI_NEXT 1630#define DLDAPI_DEFINED 1631#endif 1632 1633#ifndef DLDAPI_DEFINED 1634#error "dynamic load editor undefined" 1635#endif 1636