tclLoadAix.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:13k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tclLoadAix.c --
  3.  *
  4.  * This file implements the dlopen and dlsym APIs under the
  5.  * AIX operating system, to enable the Tcl "load" command to
  6.  * work.  This code was provided by Jens-Uwe Mager.
  7.  *
  8.  * This file is subject to the following copyright notice, which is
  9.  * different from the notice used elsewhere in Tcl.  The file has
  10.  * been modified to incorporate the file dlfcn.h in-line.
  11.  *
  12.  * Copyright (c) 1992,1993,1995,1996, Jens-Uwe Mager, Helios Software GmbH
  13.  * Not derived from licensed software.
  14.  * Permission is granted to freely use, copy, modify, and redistribute
  15.  * this software, provided that the author is not construed to be liable
  16.  * for any results of using the software, alterations are clearly marked
  17.  * as such, and this notice is not modified.
  18.  *
  19.  * RCS: @(#) $Id: tclLoadAix.c,v 1.3 1999/04/16 00:48:04 stanton Exp $
  20.  *
  21.  * Note:  this file has been altered from the original in a few
  22.  * ways in order to work properly with Tcl.
  23.  */
  24. /*
  25.  * @(#)dlfcn.c 1.7 revision of 95/08/14  19:08:38
  26.  * This is an unpublished work copyright (c) 1992 HELIOS Software GmbH
  27.  * 30159 Hannover, Germany
  28.  */
  29. #include <stdio.h>
  30. #include <errno.h>
  31. #include <string.h>
  32. #include <stdlib.h>
  33. #include <sys/types.h>
  34. #include <sys/ldr.h>
  35. #include <a.out.h>
  36. #include <ldfcn.h>
  37. #include "../compat/dlfcn.h"
  38. /*
  39.  * We simulate dlopen() et al. through a call to load. Because AIX has
  40.  * no call to find an exported symbol we read the loader section of the
  41.  * loaded module and build a list of exported symbols and their virtual
  42.  * address.
  43.  */
  44. typedef struct {
  45. char *name; /* the symbols's name */
  46. void *addr; /* its relocated virtual address */
  47. } Export, *ExportPtr;
  48. /*
  49.  * xlC uses the following structure to list its constructors and
  50.  * destructors. This is gleaned from the output of munch.
  51.  */
  52. typedef struct {
  53. void (*init)(void); /* call static constructors */
  54. void (*term)(void); /* call static destructors */
  55. } Cdtor, *CdtorPtr;
  56. /*
  57.  * The void * handle returned from dlopen is actually a ModulePtr.
  58.  */
  59. typedef struct Module {
  60. struct Module *next;
  61. char *name; /* module name for refcounting */
  62. int refCnt; /* the number of references */
  63. void *entry; /* entry point from load */
  64. struct dl_info *info; /* optional init/terminate functions */
  65. CdtorPtr cdtors; /* optional C++ constructors */
  66. int nExports; /* the number of exports found */
  67. ExportPtr exports; /* the array of exports */
  68. } Module, *ModulePtr;
  69. /*
  70.  * We keep a list of all loaded modules to be able to call the fini
  71.  * handlers and destructors at atexit() time.
  72.  */
  73. static ModulePtr modList;
  74. /*
  75.  * The last error from one of the dl* routines is kept in static
  76.  * variables here. Each error is returned only once to the caller.
  77.  */
  78. static char errbuf[BUFSIZ];
  79. static int errvalid;
  80. static void caterr(char *);
  81. static int readExports(ModulePtr);
  82. static void terminate(void);
  83. static void *findMain(void);
  84. VOID *dlopen(const char *path, int mode)
  85. {
  86. register ModulePtr mp;
  87. static void *mainModule;
  88. /*
  89.  * Upon the first call register a terminate handler that will
  90.  * close all libraries. Also get a reference to the main module
  91.  * for use with loadbind.
  92.  */
  93. if (!mainModule) {
  94. if ((mainModule = findMain()) == NULL)
  95. return NULL;
  96. atexit(terminate);
  97. }
  98. /*
  99.  * Scan the list of modules if we have the module already loaded.
  100.  */
  101. for (mp = modList; mp; mp = mp->next)
  102. if (strcmp(mp->name, path) == 0) {
  103. mp->refCnt++;
  104. return (VOID *) mp;
  105. }
  106. if ((mp = (ModulePtr)calloc(1, sizeof(*mp))) == NULL) {
  107. errvalid++;
  108. strcpy(errbuf, "calloc: ");
  109. strcat(errbuf, strerror(errno));
  110. return (VOID *) NULL;
  111. }
  112. mp->name = malloc((unsigned) (strlen(path) + 1));
  113. strcpy(mp->name, path);
  114. /*
  115.  * load should be declared load(const char *...). Thus we
  116.  * cast the path to a normal char *. Ugly.
  117.  */
  118. if ((mp->entry = (void *)load((char *)path, L_NOAUTODEFER, NULL)) == NULL) {
  119. free(mp->name);
  120. free(mp);
  121. errvalid++;
  122. strcpy(errbuf, "dlopen: ");
  123. strcat(errbuf, path);
  124. strcat(errbuf, ": ");
  125. /*
  126.  * If AIX says the file is not executable, the error
  127.  * can be further described by querying the loader about
  128.  * the last error.
  129.  */
  130. if (errno == ENOEXEC) {
  131. char *tmp[BUFSIZ/sizeof(char *)];
  132. if (loadquery(L_GETMESSAGES, tmp, sizeof(tmp)) == -1)
  133. strcpy(errbuf, strerror(errno));
  134. else {
  135. char **p;
  136. for (p = tmp; *p; p++)
  137. caterr(*p);
  138. }
  139. } else
  140. strcat(errbuf, strerror(errno));
  141. return (VOID *) NULL;
  142. }
  143. mp->refCnt = 1;
  144. mp->next = modList;
  145. modList = mp;
  146. if (loadbind(0, mainModule, mp->entry) == -1) {
  147. dlclose(mp);
  148. errvalid++;
  149. strcpy(errbuf, "loadbind: ");
  150. strcat(errbuf, strerror(errno));
  151. return (VOID *) NULL;
  152. }
  153. /*
  154.  * If the user wants global binding, loadbind against all other
  155.  * loaded modules.
  156.  */
  157. if (mode & RTLD_GLOBAL) {
  158. register ModulePtr mp1;
  159. for (mp1 = mp->next; mp1; mp1 = mp1->next)
  160. if (loadbind(0, mp1->entry, mp->entry) == -1) {
  161. dlclose(mp);
  162. errvalid++;
  163. strcpy(errbuf, "loadbind: ");
  164. strcat(errbuf, strerror(errno));
  165. return (VOID *) NULL;
  166. }
  167. }
  168. if (readExports(mp) == -1) {
  169. dlclose(mp);
  170. return (VOID *) NULL;
  171. }
  172. /*
  173.  * If there is a dl_info structure, call the init function.
  174.  */
  175. if (mp->info = (struct dl_info *)dlsym(mp, "dl_info")) {
  176. if (mp->info->init)
  177. (*mp->info->init)();
  178. } else
  179. errvalid = 0;
  180. /*
  181.  * If the shared object was compiled using xlC we will need
  182.  * to call static constructors (and later on dlclose destructors).
  183.  */
  184. if (mp->cdtors = (CdtorPtr)dlsym(mp, "__cdtors")) {
  185. while (mp->cdtors->init) {
  186. (*mp->cdtors->init)();
  187. mp->cdtors++;
  188. }
  189. } else
  190. errvalid = 0;
  191. return (VOID *) mp;
  192. }
  193. /*
  194.  * Attempt to decipher an AIX loader error message and append it
  195.  * to our static error message buffer.
  196.  */
  197. static void caterr(char *s)
  198. {
  199. register char *p = s;
  200. while (*p >= '0' && *p <= '9')
  201. p++;
  202. switch(atoi(s)) { /* INTL: "C", UTF safe. */
  203. case L_ERROR_TOOMANY:
  204. strcat(errbuf, "to many errors");
  205. break;
  206. case L_ERROR_NOLIB:
  207. strcat(errbuf, "can't load library");
  208. strcat(errbuf, p);
  209. break;
  210. case L_ERROR_UNDEF:
  211. strcat(errbuf, "can't find symbol");
  212. strcat(errbuf, p);
  213. break;
  214. case L_ERROR_RLDBAD:
  215. strcat(errbuf, "bad RLD");
  216. strcat(errbuf, p);
  217. break;
  218. case L_ERROR_FORMAT:
  219. strcat(errbuf, "bad exec format in");
  220. strcat(errbuf, p);
  221. break;
  222. case L_ERROR_ERRNO:
  223. strcat(errbuf, strerror(atoi(++p))); /* INTL: "C", UTF safe. */
  224. break;
  225. default:
  226. strcat(errbuf, s);
  227. break;
  228. }
  229. }
  230. VOID *dlsym(void *handle, const char *symbol)
  231. {
  232. register ModulePtr mp = (ModulePtr)handle;
  233. register ExportPtr ep;
  234. register int i;
  235. /*
  236.  * Could speed up the search, but I assume that one assigns
  237.  * the result to function pointers anyways.
  238.  */
  239. for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
  240. if (strcmp(ep->name, symbol) == 0)
  241. return ep->addr;
  242. errvalid++;
  243. strcpy(errbuf, "dlsym: undefined symbol ");
  244. strcat(errbuf, symbol);
  245. return NULL;
  246. }
  247. char *dlerror(void)
  248. {
  249. if (errvalid) {
  250. errvalid = 0;
  251. return errbuf;
  252. }
  253. return NULL;
  254. }
  255. int dlclose(void *handle)
  256. {
  257. register ModulePtr mp = (ModulePtr)handle;
  258. int result;
  259. register ModulePtr mp1;
  260. if (--mp->refCnt > 0)
  261. return 0;
  262. if (mp->info && mp->info->fini)
  263. (*mp->info->fini)();
  264. if (mp->cdtors)
  265. while (mp->cdtors->term) {
  266. (*mp->cdtors->term)();
  267. mp->cdtors++;
  268. }
  269. result = unload(mp->entry);
  270. if (result == -1) {
  271. errvalid++;
  272. strcpy(errbuf, strerror(errno));
  273. }
  274. if (mp->exports) {
  275. register ExportPtr ep;
  276. register int i;
  277. for (ep = mp->exports, i = mp->nExports; i; i--, ep++)
  278. if (ep->name)
  279. free(ep->name);
  280. free(mp->exports);
  281. }
  282. if (mp == modList)
  283. modList = mp->next;
  284. else {
  285. for (mp1 = modList; mp1; mp1 = mp1->next)
  286. if (mp1->next == mp) {
  287. mp1->next = mp->next;
  288. break;
  289. }
  290. }
  291. free(mp->name);
  292. free(mp);
  293. return result;
  294. }
  295. static void terminate(void)
  296. {
  297. while (modList)
  298. dlclose(modList);
  299. }
  300. /*
  301.  * Build the export table from the XCOFF .loader section.
  302.  */
  303. static int readExports(ModulePtr mp)
  304. {
  305. LDFILE *ldp = NULL;
  306. SCNHDR sh, shdata;
  307. LDHDR *lhp;
  308. char *ldbuf;
  309. LDSYM *ls;
  310. int i;
  311. ExportPtr ep;
  312. if ((ldp = ldopen(mp->name, ldp)) == NULL) {
  313. struct ld_info *lp;
  314. char *buf;
  315. int size = 4*1024;
  316. if (errno != ENOENT) {
  317. errvalid++;
  318. strcpy(errbuf, "readExports: ");
  319. strcat(errbuf, strerror(errno));
  320. return -1;
  321. }
  322. /*
  323.  * The module might be loaded due to the LIBPATH
  324.  * environment variable. Search for the loaded
  325.  * module using L_GETINFO.
  326.  */
  327. if ((buf = malloc(size)) == NULL) {
  328. errvalid++;
  329. strcpy(errbuf, "readExports: ");
  330. strcat(errbuf, strerror(errno));
  331. return -1;
  332. }
  333. while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
  334. free(buf);
  335. size += 4*1024;
  336. if ((buf = malloc(size)) == NULL) {
  337. errvalid++;
  338. strcpy(errbuf, "readExports: ");
  339. strcat(errbuf, strerror(errno));
  340. return -1;
  341. }
  342. }
  343. if (i == -1) {
  344. errvalid++;
  345. strcpy(errbuf, "readExports: ");
  346. strcat(errbuf, strerror(errno));
  347. free(buf);
  348. return -1;
  349. }
  350. /*
  351.  * Traverse the list of loaded modules. The entry point
  352.  * returned by load() does actually point to the data
  353.  * segment origin.
  354.  */
  355. lp = (struct ld_info *)buf;
  356. while (lp) {
  357. if (lp->ldinfo_dataorg == mp->entry) {
  358. ldp = ldopen(lp->ldinfo_filename, ldp);
  359. break;
  360. }
  361. if (lp->ldinfo_next == 0)
  362. lp = NULL;
  363. else
  364. lp = (struct ld_info *)((char *)lp + lp->ldinfo_next);
  365. }
  366. free(buf);
  367. if (!ldp) {
  368. errvalid++;
  369. strcpy(errbuf, "readExports: ");
  370. strcat(errbuf, strerror(errno));
  371. return -1;
  372. }
  373. }
  374. if (TYPE(ldp) != U802TOCMAGIC) {
  375. errvalid++;
  376. strcpy(errbuf, "readExports: bad magic");
  377. while(ldclose(ldp) == FAILURE)
  378. ;
  379. return -1;
  380. }
  381. /*
  382.  * Get the padding for the data section. This is needed for
  383.  * AIX 4.1 compilers. This is used when building the final
  384.  * function pointer to the exported symbol.
  385.  */
  386. if (ldnshread(ldp, _DATA, &shdata) != SUCCESS) {
  387. errvalid++;
  388. strcpy(errbuf, "readExports: cannot read data section header");
  389. while(ldclose(ldp) == FAILURE)
  390. ;
  391. return -1;
  392. }
  393. if (ldnshread(ldp, _LOADER, &sh) != SUCCESS) {
  394. errvalid++;
  395. strcpy(errbuf, "readExports: cannot read loader section header");
  396. while(ldclose(ldp) == FAILURE)
  397. ;
  398. return -1;
  399. }
  400. /*
  401.  * We read the complete loader section in one chunk, this makes
  402.  * finding long symbol names residing in the string table easier.
  403.  */
  404. if ((ldbuf = (char *)malloc(sh.s_size)) == NULL) {
  405. errvalid++;
  406. strcpy(errbuf, "readExports: ");
  407. strcat(errbuf, strerror(errno));
  408. while(ldclose(ldp) == FAILURE)
  409. ;
  410. return -1;
  411. }
  412. if (FSEEK(ldp, sh.s_scnptr, BEGINNING) != OKFSEEK) {
  413. errvalid++;
  414. strcpy(errbuf, "readExports: cannot seek to loader section");
  415. free(ldbuf);
  416. while(ldclose(ldp) == FAILURE)
  417. ;
  418. return -1;
  419. }
  420. if (FREAD(ldbuf, sh.s_size, 1, ldp) != 1) {
  421. errvalid++;
  422. strcpy(errbuf, "readExports: cannot read loader section");
  423. free(ldbuf);
  424. while(ldclose(ldp) == FAILURE)
  425. ;
  426. return -1;
  427. }
  428. lhp = (LDHDR *)ldbuf;
  429. ls = (LDSYM *)(ldbuf+LDHDRSZ);
  430. /*
  431.  * Count the number of exports to include in our export table.
  432.  */
  433. for (i = lhp->l_nsyms; i; i--, ls++) {
  434. if (!LDR_EXPORT(*ls))
  435. continue;
  436. mp->nExports++;
  437. }
  438. if ((mp->exports = (ExportPtr)calloc(mp->nExports, sizeof(*mp->exports))) == NULL) {
  439. errvalid++;
  440. strcpy(errbuf, "readExports: ");
  441. strcat(errbuf, strerror(errno));
  442. free(ldbuf);
  443. while(ldclose(ldp) == FAILURE)
  444. ;
  445. return -1;
  446. }
  447. /*
  448.  * Fill in the export table. All entries are relative to
  449.  * the entry point we got from load.
  450.  */
  451. ep = mp->exports;
  452. ls = (LDSYM *)(ldbuf+LDHDRSZ);
  453. for (i = lhp->l_nsyms; i; i--, ls++) {
  454. char *symname;
  455. char tmpsym[SYMNMLEN+1];
  456. if (!LDR_EXPORT(*ls))
  457. continue;
  458. if (ls->l_zeroes == 0)
  459. symname = ls->l_offset+lhp->l_stoff+ldbuf;
  460. else {
  461. /*
  462.  * The l_name member is not zero terminated, we
  463.  * must copy the first SYMNMLEN chars and make
  464.  * sure we have a zero byte at the end.
  465.  */
  466. strncpy(tmpsym, ls->l_name, SYMNMLEN);
  467. tmpsym[SYMNMLEN] = '';
  468. symname = tmpsym;
  469. }
  470. ep->name = malloc((unsigned) (strlen(symname) + 1));
  471. strcpy(ep->name, symname);
  472. ep->addr = (void *)((unsigned long)mp->entry +
  473. ls->l_value - shdata.s_vaddr);
  474. ep++;
  475. }
  476. free(ldbuf);
  477. while(ldclose(ldp) == FAILURE)
  478. ;
  479. return 0;
  480. }
  481. /*
  482.  * Find the main modules entry point. This is used as export pointer
  483.  * for loadbind() to be able to resolve references to the main part.
  484.  */
  485. static void * findMain(void)
  486. {
  487. struct ld_info *lp;
  488. char *buf;
  489. int size = 4*1024;
  490. int i;
  491. void *ret;
  492. if ((buf = malloc(size)) == NULL) {
  493. errvalid++;
  494. strcpy(errbuf, "findMain: ");
  495. strcat(errbuf, strerror(errno));
  496. return NULL;
  497. }
  498. while ((i = loadquery(L_GETINFO, buf, size)) == -1 && errno == ENOMEM) {
  499. free(buf);
  500. size += 4*1024;
  501. if ((buf = malloc(size)) == NULL) {
  502. errvalid++;
  503. strcpy(errbuf, "findMain: ");
  504. strcat(errbuf, strerror(errno));
  505. return NULL;
  506. }
  507. }
  508. if (i == -1) {
  509. errvalid++;
  510. strcpy(errbuf, "findMain: ");
  511. strcat(errbuf, strerror(errno));
  512. free(buf);
  513. return NULL;
  514. }
  515. /*
  516.  * The first entry is the main module. The entry point
  517.  * returned by load() does actually point to the data
  518.  * segment origin.
  519.  */
  520. lp = (struct ld_info *)buf;
  521. ret = lp->ldinfo_dataorg;
  522. free(buf);
  523. return ret;
  524. }