aix.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:12k
源码类别:

数据库系统

开发平台:

Unix_Linux

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