1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1997-2010 AT&T Intellectual Property * 5 * and is licensed under the * 6 * Common Public License, Version 1.0 * 7 * by AT&T Intellectual Property * 8 * * 9 * A copy of the License is available at * 10 * http://www.opensource.org/licenses/cpl1.0.txt * 11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * 12 * * 13 * Information and Software Systems Research * 14 * AT&T Research * 15 * Florham Park NJ * 16 * * 17 * Glenn Fowler <gsf@research.att.com> * 18 * * 19 ***********************************************************************/ 20 #pragma prototyped 21 /* 22 * provide dlopen/dlsym/dlerror interface 23 * 24 * David Korn 25 * Glenn Fowler 26 * AT&T Research 27 */ 28 29 static const char id[] = "\n@(#)$Id: dll library (AT&T Research) 2009-04-15 $\0\n"; 30 31 #include <ast.h> 32 #include <dlldefs.h> 33 #include <error.h> 34 35 #define T(x) ERROR_dictionary(x) 36 37 #if _BLD_dll && defined(__EXPORT__) 38 #define extern __EXPORT__ 39 #endif 40 41 #if _hdr_dlfcn && _lib_dlopen 42 43 /* 44 * standard 45 */ 46 47 # include <dlfcn.h> 48 49 #else 50 #if _hdr_dl 51 52 /* 53 * HP-UX 54 */ 55 56 # include <dl.h> 57 # ifndef BIND_FIRST 58 # define BIND_FIRST 0x4 59 # endif 60 # ifndef BIND_NOSTART 61 # define BIND_NOSTART 0x10 62 # endif 63 64 static shl_t all; 65 static int err; 66 67 extern void* dlopen(const char* path, int mode) 68 { 69 void* dll; 70 71 if (!path) 72 return (void*)&all; 73 if (mode) 74 mode = (BIND_IMMEDIATE|BIND_FIRST|BIND_NOSTART); 75 if (!(dll = (void*)shl_load(path, mode, 0L))) 76 err = errno; 77 return dll; 78 } 79 80 extern int dlclose(void* dll) 81 { 82 return 0; 83 } 84 85 extern void* dlsym(void* dll, const char* name) 86 { 87 shl_t handle; 88 long addr; 89 90 handle = dll == (void*)&all ? (shl_t)0 : (shl_t)dll; 91 if (shl_findsym(&handle, name, TYPE_UNDEFINED, &addr)) 92 { 93 err = errno; 94 return 0; 95 } 96 return (void*)addr; 97 } 98 99 extern char* dlerror(void) 100 { 101 char* msg; 102 103 if (!err) 104 return 0; 105 msg = fmterror(err); 106 err = 0; 107 return msg; 108 } 109 110 #else 111 #if _sys_ldr && _lib_loadbind 112 113 /* 114 * rs6000 115 */ 116 117 # include <sys/ldr.h> 118 # include <xcoff.h> 119 120 /* xcoff module header */ 121 struct hdr 122 { 123 struct filehdr f; 124 struct aouthdr a; 125 struct scnhdr s[1]; 126 }; 127 128 static struct ld_info* ld_info; 129 static unsigned int ld_info_size = 1024; 130 static void* last_module; 131 static int err; 132 133 extern void* dlopen(const char* path, int mode) 134 { 135 void* dll; 136 137 if (!(dll = (void*)load((char*)path, mode, getenv("LIBPATH")))) 138 err = errno; 139 return dll; 140 } 141 142 extern int dlclose(void* dll) 143 { 144 return 0; 145 } 146 147 static int getquery(void) 148 { 149 if (!ld_info) 150 ld_info = malloc(ld_info_size); 151 for (;;) 152 { 153 if (!ld_info) 154 return 1; 155 if (!loadquery(L_GETINFO, ld_info, ld_info_size)) 156 return 0; 157 if (errno != ENOMEM) 158 return 1; 159 ld_info = realloc(ld_info, ld_info_size *= 2); 160 } 161 } 162 163 /* find the loaded module whose data area contains the 164 * address passed in. Remember that procedure pointers 165 * are implemented as pointers to descriptors in the 166 * data area of the module defining the procedure 167 */ 168 static struct ld_info* getinfo(void* module) 169 { 170 struct ld_info* info = ld_info; 171 register int n = 1; 172 173 if (!ld_info || module != last_module) 174 { 175 last_module = module; 176 if (getquery()) 177 return 0; 178 info = ld_info; 179 } 180 while (n) 181 { 182 if ((char*)(info->ldinfo_dataorg) <= (char*)module && 183 (char*)module <= ((char*)(info->ldinfo_dataorg) 184 + (unsigned)(info->ldinfo_datasize))) 185 return info; 186 if (n=info->ldinfo_next) 187 info = (void*)((char*)info + n); 188 } 189 return 0; 190 } 191 192 static char* getloc(struct hdr* hdr, char* data, char* name) 193 { 194 struct ldhdr* ldhdr; 195 struct ldsym* ldsym; 196 ulong datareloc; 197 ulong textreloc; 198 int i; 199 200 /* data is relocated by the difference between 201 * its virtual origin and where it was 202 * actually placed 203 */ 204 /*N.B. o_sndata etc. are one based */ 205 datareloc = (ulong)data - hdr->s[hdr->a.o_sndata-1].s_vaddr; 206 /*hdr is address of header, not text, so add text s_scnptr */ 207 textreloc = (ulong)hdr + hdr->s[hdr->a.o_sntext-1].s_scnptr 208 - hdr->s[hdr->a.o_sntext-1].s_vaddr; 209 ldhdr = (void*)((char*)hdr+ hdr->s[hdr->a.o_snloader-1].s_scnptr); 210 ldsym = (void*) (ldhdr+1); 211 /* search the exports symbols */ 212 for(i=0; i < ldhdr->l_nsyms;ldsym++,i++) 213 { 214 char *symname,symbuf[9]; 215 char *loc; 216 /* the symbol name representation is a nuisance since 217 * 8 character names appear in l_name but may 218 * not be null terminated. This code works around 219 * that by brute force 220 */ 221 if (ldsym->l_zeroes) 222 { 223 symname = symbuf; 224 memcpy(symbuf,ldsym->l_name,8); 225 symbuf[8] = 0; 226 } 227 else 228 symname = (void*)(ldsym->l_offset + (ulong)ldhdr + ldhdr->l_stoff); 229 if (strcmp(symname,name)) 230 continue; 231 loc = (char*)ldsym->l_value; 232 if ((ldsym->l_scnum==hdr->a.o_sndata) || 233 (ldsym->l_scnum==hdr->a.o_snbss)) 234 loc += datareloc; 235 else if (ldsym->l_scnum==hdr->a.o_sntext) 236 loc += textreloc; 237 return loc; 238 } 239 return 0; 240 } 241 242 extern void* dlsym(void* handle, const char* name) 243 { 244 void* addr; 245 struct ld_info* info; 246 247 if (!(info = getinfo(handle)) || !(addr = getloc(info->ldinfo_textorg,info->ldinfo_dataorg,(char*)name))) 248 { 249 err = errno; 250 return 0; 251 } 252 return addr; 253 } 254 255 extern char* dlerror(void) 256 { 257 char* msg; 258 259 if (!err) 260 return 0; 261 msg = fmterror(err); 262 err = 0; 263 return msg; 264 } 265 266 #else 267 #if _hdr_dll && _lib_dllload 268 269 /* 270 * MVS 271 */ 272 273 # include <dll.h> 274 275 static int err; 276 277 extern void* dlopen(const char* path, int mode) 278 { 279 void* dll; 280 281 NoP(mode); 282 if (!(dll = (void*)dllload(path))) 283 err = errno; 284 return dll; 285 } 286 287 extern int dlclose(void* dll) 288 { 289 return 0; 290 } 291 292 extern void* dlsym(void* handle, const char* name) 293 { 294 void* addr; 295 296 if (!(addr = (void*)dllqueryfn(handle, (char*)name))) 297 err = errno; 298 return addr; 299 } 300 301 extern char* dlerror(void) 302 { 303 char* msg; 304 305 if (!err) 306 return 0; 307 msg = fmterror(err); 308 err = 0; 309 return msg; 310 } 311 312 #else 313 #if _hdr_mach_o_dyld 314 315 /* 316 * mac[h] 317 */ 318 319 # include <mach-o/dyld.h> 320 321 typedef const struct mach_header* NSImage; 322 323 typedef struct Dll_s 324 { 325 unsigned long magic; 326 NSImage image; 327 NSModule module; 328 char path[1]; 329 } Dll_t; 330 331 #define DL_MAGIC 0x04190c04 332 #define DL_NEXT ((Dll_t*)RTLD_NEXT) 333 334 static const char* dlmessage = "no error"; 335 336 static const char e_cover[] = T("cannot access covered library"); 337 static const char e_handle[] = T("invalid handle"); 338 static const char e_space[] = T("out of space"); 339 static const char e_static[] = T("image statically linked"); 340 static const char e_undefined[] = T("undefined symbol"); 341 342 static Dll_t global = { DL_MAGIC }; 343 344 static void undefined(const char* name) 345 { 346 } 347 348 static NSModule multiple(NSSymbol sym, NSModule om, NSModule nm) 349 { 350 return om; 351 } 352 353 static void linkedit(NSLinkEditErrors c, int n, const char* f, const char* m) 354 { 355 dlmessage = m; 356 } 357 358 static NSLinkEditErrorHandlers handlers = 359 { 360 undefined, multiple, linkedit 361 }; 362 363 extern void* dlopen(const char* path, int mode) 364 { 365 Dll_t* dll; 366 int i; 367 NSObjectFileImage image; 368 369 static int init = 0; 370 371 if (!_dyld_present()) 372 { 373 dlmessage = e_static; 374 return 0; 375 } 376 if (!init) 377 { 378 init = 1; 379 NSInstallLinkEditErrorHandlers(&handlers); 380 } 381 if (!path) 382 dll = &global; 383 else if (!(dll = newof(0, Dll_t, 1, strlen(path)))) 384 { 385 dlmessage = e_space; 386 return 0; 387 } 388 else 389 { 390 switch (NSCreateObjectFileImageFromFile(path, &image)) 391 { 392 case NSObjectFileImageSuccess: 393 dll->module = NSLinkModule(image, path, (mode & RTLD_LAZY) ? 0 : NSLINKMODULE_OPTION_BINDNOW); 394 NSDestroyObjectFileImage(image); 395 if (!dll->module) 396 { 397 free(dll); 398 return 0; 399 } 400 break; 401 case NSObjectFileImageInappropriateFile: 402 dll->image = NSAddImage(path, 0); 403 if (!dll->image) 404 { 405 free(dll); 406 return 0; 407 } 408 break; 409 default: 410 free(dll); 411 return 0; 412 } 413 strcpy(dll->path, path); 414 dll->magic = DL_MAGIC; 415 } 416 return (void*)dll; 417 } 418 419 extern int dlclose(void* handle) 420 { 421 Dll_t* dll = (Dll_t*)handle; 422 423 if (!dll || dll == DL_NEXT || dll->magic != DL_MAGIC) 424 { 425 dlmessage = e_handle; 426 return -1; 427 } 428 if (dll->module) 429 NSUnLinkModule(dll->module, 0); 430 free(dll); 431 return 0; 432 } 433 434 static NSSymbol 435 lookup(Dll_t* dll, const char* name) 436 { 437 unsigned long pun; 438 void* address; 439 440 if (dll == DL_NEXT) 441 { 442 if (!_dyld_func_lookup(name, &pun)) 443 return 0; 444 address = (NSSymbol)pun; 445 } 446 else if (dll->module) 447 address = NSLookupSymbolInModule(dll->module, name); 448 else if (dll->image) 449 { 450 if (!NSIsSymbolNameDefinedInImage(dll->image, name)) 451 return 0; 452 address = NSLookupSymbolInImage(dll->image, name, 0); 453 } 454 else 455 { 456 if (!NSIsSymbolNameDefined(name)) 457 return 0; 458 address = NSLookupAndBindSymbol(name); 459 } 460 if (address) 461 address = NSAddressOfSymbol(address); 462 return address; 463 } 464 465 extern void* dlsym(void* handle, const char* name) 466 { 467 Dll_t* dll = (Dll_t*)handle; 468 NSSymbol address; 469 char buf[1024]; 470 471 if (!dll || dll != DL_NEXT && (dll->magic != DL_MAGIC || !dll->image && !dll->module)) 472 { 473 dlmessage = e_handle; 474 return 0; 475 } 476 if (!(address = lookup(dll, name)) && name[0] != '_' && strlen(name) < (sizeof(buf) - 1)) 477 { 478 buf[0] = '_'; 479 strcpy(buf + 1, name); 480 address = lookup(dll, buf); 481 } 482 if (!address) 483 { 484 dlmessage = dll == DL_NEXT ? e_cover : e_undefined; 485 return 0; 486 } 487 return (void*)address; 488 } 489 490 extern char* dlerror(void) 491 { 492 char* msg; 493 494 msg = (char*)dlmessage; 495 dlmessage = 0; 496 return msg; 497 } 498 499 #else 500 /* 501 * punt 502 */ 503 504 static int err; 505 506 extern void* dlopen(const char* path, int mode) 507 { 508 err = 1; 509 return 0; 510 } 511 512 extern int dlclose(void* dll) 513 { 514 err = 1; 515 return 0; 516 } 517 518 extern void* dlsym(void* handle, const char* name) 519 { 520 err = 1; 521 return 0; 522 } 523 524 extern char* dlerror(void) 525 { 526 if (!err) 527 return 0; 528 err = 0; 529 return "dynamic linking not supported"; 530 } 531 532 #endif 533 #endif 534 #endif 535 #endif 536 #endif 537