plugin_test.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  1. /* test_plugin.c -- simple linker plugin test
  2. Copyright (C) 2008-2015 Free Software Foundation, Inc.
  3. Written by Cary Coutant <ccoutant@google.com>.
  4. This file is part of gold.
  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 3 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
  16. MA 02110-1301, USA. */
  17. #ifdef HAVE_CONFIG_H
  18. #include "config.h"
  19. #endif
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include "plugin-api.h"
  24. struct claimed_file
  25. {
  26. const char* name;
  27. void* handle;
  28. int nsyms;
  29. struct ld_plugin_symbol* syms;
  30. struct claimed_file* next;
  31. };
  32. struct sym_info
  33. {
  34. int size;
  35. char* type;
  36. char* bind;
  37. char* vis;
  38. char* sect;
  39. char* name;
  40. };
  41. static struct claimed_file* first_claimed_file = NULL;
  42. static struct claimed_file* last_claimed_file = NULL;
  43. static ld_plugin_register_claim_file register_claim_file_hook = NULL;
  44. static ld_plugin_register_all_symbols_read register_all_symbols_read_hook = NULL;
  45. static ld_plugin_register_cleanup register_cleanup_hook = NULL;
  46. static ld_plugin_add_symbols add_symbols = NULL;
  47. static ld_plugin_get_symbols get_symbols = NULL;
  48. static ld_plugin_get_symbols get_symbols_v2 = NULL;
  49. static ld_plugin_add_input_file add_input_file = NULL;
  50. static ld_plugin_message message = NULL;
  51. static ld_plugin_get_input_file get_input_file = NULL;
  52. static ld_plugin_release_input_file release_input_file = NULL;
  53. static ld_plugin_get_input_section_count get_input_section_count = NULL;
  54. static ld_plugin_get_input_section_type get_input_section_type = NULL;
  55. static ld_plugin_get_input_section_name get_input_section_name = NULL;
  56. static ld_plugin_get_input_section_contents get_input_section_contents = NULL;
  57. static ld_plugin_update_section_order update_section_order = NULL;
  58. static ld_plugin_allow_section_ordering allow_section_ordering = NULL;
  59. #define MAXOPTS 10
  60. static const char *opts[MAXOPTS];
  61. static int nopts = 0;
  62. enum ld_plugin_status onload(struct ld_plugin_tv *tv);
  63. enum ld_plugin_status claim_file_hook(const struct ld_plugin_input_file *file,
  64. int *claimed);
  65. enum ld_plugin_status all_symbols_read_hook(void);
  66. enum ld_plugin_status cleanup_hook(void);
  67. static void parse_readelf_line(char*, struct sym_info*);
  68. enum ld_plugin_status
  69. onload(struct ld_plugin_tv *tv)
  70. {
  71. struct ld_plugin_tv *entry;
  72. int api_version = 0;
  73. int gold_version = 0;
  74. int i;
  75. for (entry = tv; entry->tv_tag != LDPT_NULL; ++entry)
  76. {
  77. switch (entry->tv_tag)
  78. {
  79. case LDPT_API_VERSION:
  80. api_version = entry->tv_u.tv_val;
  81. break;
  82. case LDPT_GOLD_VERSION:
  83. gold_version = entry->tv_u.tv_val;
  84. break;
  85. case LDPT_LINKER_OUTPUT:
  86. break;
  87. case LDPT_OPTION:
  88. if (nopts < MAXOPTS)
  89. opts[nopts++] = entry->tv_u.tv_string;
  90. break;
  91. case LDPT_REGISTER_CLAIM_FILE_HOOK:
  92. register_claim_file_hook = entry->tv_u.tv_register_claim_file;
  93. break;
  94. case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
  95. register_all_symbols_read_hook =
  96. entry->tv_u.tv_register_all_symbols_read;
  97. break;
  98. case LDPT_REGISTER_CLEANUP_HOOK:
  99. register_cleanup_hook = entry->tv_u.tv_register_cleanup;
  100. break;
  101. case LDPT_ADD_SYMBOLS:
  102. add_symbols = entry->tv_u.tv_add_symbols;
  103. break;
  104. case LDPT_GET_SYMBOLS:
  105. get_symbols = entry->tv_u.tv_get_symbols;
  106. break;
  107. case LDPT_GET_SYMBOLS_V2:
  108. get_symbols_v2 = entry->tv_u.tv_get_symbols;
  109. break;
  110. case LDPT_ADD_INPUT_FILE:
  111. add_input_file = entry->tv_u.tv_add_input_file;
  112. break;
  113. case LDPT_MESSAGE:
  114. message = entry->tv_u.tv_message;
  115. break;
  116. case LDPT_GET_INPUT_FILE:
  117. get_input_file = entry->tv_u.tv_get_input_file;
  118. break;
  119. case LDPT_RELEASE_INPUT_FILE:
  120. release_input_file = entry->tv_u.tv_release_input_file;
  121. break;
  122. case LDPT_GET_INPUT_SECTION_COUNT:
  123. get_input_section_count = *entry->tv_u.tv_get_input_section_count;
  124. break;
  125. case LDPT_GET_INPUT_SECTION_TYPE:
  126. get_input_section_type = *entry->tv_u.tv_get_input_section_type;
  127. break;
  128. case LDPT_GET_INPUT_SECTION_NAME:
  129. get_input_section_name = *entry->tv_u.tv_get_input_section_name;
  130. break;
  131. case LDPT_GET_INPUT_SECTION_CONTENTS:
  132. get_input_section_contents = *entry->tv_u.tv_get_input_section_contents;
  133. break;
  134. case LDPT_UPDATE_SECTION_ORDER:
  135. update_section_order = *entry->tv_u.tv_update_section_order;
  136. break;
  137. case LDPT_ALLOW_SECTION_ORDERING:
  138. allow_section_ordering = *entry->tv_u.tv_allow_section_ordering;
  139. break;
  140. default:
  141. break;
  142. }
  143. }
  144. if (message == NULL)
  145. {
  146. fprintf(stderr, "tv_message interface missing\n");
  147. return LDPS_ERR;
  148. }
  149. if (register_claim_file_hook == NULL)
  150. {
  151. fprintf(stderr, "tv_register_claim_file_hook interface missing\n");
  152. return LDPS_ERR;
  153. }
  154. if (register_all_symbols_read_hook == NULL)
  155. {
  156. fprintf(stderr, "tv_register_all_symbols_read_hook interface missing\n");
  157. return LDPS_ERR;
  158. }
  159. if (register_cleanup_hook == NULL)
  160. {
  161. fprintf(stderr, "tv_register_cleanup_hook interface missing\n");
  162. return LDPS_ERR;
  163. }
  164. (*message)(LDPL_INFO, "API version: %d", api_version);
  165. (*message)(LDPL_INFO, "gold version: %d", gold_version);
  166. for (i = 0; i < nopts; ++i)
  167. (*message)(LDPL_INFO, "option: %s", opts[i]);
  168. if ((*register_claim_file_hook)(claim_file_hook) != LDPS_OK)
  169. {
  170. (*message)(LDPL_ERROR, "error registering claim file hook");
  171. return LDPS_ERR;
  172. }
  173. if ((*register_all_symbols_read_hook)(all_symbols_read_hook) != LDPS_OK)
  174. {
  175. (*message)(LDPL_ERROR, "error registering all symbols read hook");
  176. return LDPS_ERR;
  177. }
  178. if ((*register_cleanup_hook)(cleanup_hook) != LDPS_OK)
  179. {
  180. (*message)(LDPL_ERROR, "error registering cleanup hook");
  181. return LDPS_ERR;
  182. }
  183. if (get_input_section_count == NULL)
  184. {
  185. fprintf(stderr, "tv_get_input_section_count interface missing\n");
  186. return LDPS_ERR;
  187. }
  188. if (get_input_section_type == NULL)
  189. {
  190. fprintf(stderr, "tv_get_input_section_type interface missing\n");
  191. return LDPS_ERR;
  192. }
  193. if (get_input_section_name == NULL)
  194. {
  195. fprintf(stderr, "tv_get_input_section_name interface missing\n");
  196. return LDPS_ERR;
  197. }
  198. if (get_input_section_contents == NULL)
  199. {
  200. fprintf(stderr, "tv_get_input_section_contents interface missing\n");
  201. return LDPS_ERR;
  202. }
  203. if (update_section_order == NULL)
  204. {
  205. fprintf(stderr, "tv_update_section_order interface missing\n");
  206. return LDPS_ERR;
  207. }
  208. if (allow_section_ordering == NULL)
  209. {
  210. fprintf(stderr, "tv_allow_section_ordering interface missing\n");
  211. return LDPS_ERR;
  212. }
  213. return LDPS_OK;
  214. }
  215. enum ld_plugin_status
  216. claim_file_hook (const struct ld_plugin_input_file* file, int* claimed)
  217. {
  218. int len;
  219. off_t end_offset;
  220. char buf[160];
  221. struct claimed_file* claimed_file;
  222. struct ld_plugin_symbol* syms;
  223. int nsyms = 0;
  224. int maxsyms = 0;
  225. FILE* irfile;
  226. struct sym_info info;
  227. int weak;
  228. int def;
  229. int vis;
  230. int is_comdat;
  231. int i;
  232. int irfile_was_opened = 0;
  233. char syms_name[80];
  234. (*message)(LDPL_INFO,
  235. "%s: claim file hook called (offset = %ld, size = %ld)",
  236. file->name, (long)file->offset, (long)file->filesize);
  237. /* Look for matching syms file for an archive member. */
  238. if (file->offset == 0)
  239. snprintf(syms_name, sizeof(syms_name), "%s.syms", file->name);
  240. else
  241. snprintf(syms_name, sizeof(syms_name), "%s-%d.syms",
  242. file->name, (int)file->offset);
  243. irfile = fopen(syms_name, "r");
  244. if (irfile != NULL)
  245. {
  246. irfile_was_opened = 1;
  247. end_offset = 1 << 20;
  248. }
  249. /* Otherwise, see if the file itself is a syms file. */
  250. if (!irfile_was_opened)
  251. {
  252. irfile = fdopen(file->fd, "r");
  253. (void)fseek(irfile, file->offset, SEEK_SET);
  254. end_offset = file->offset + file->filesize;
  255. }
  256. /* Look for the beginning of output from readelf -s. */
  257. len = fread(buf, 1, 13, irfile);
  258. if (len < 13 || strncmp(buf, "\nSymbol table", 13) != 0)
  259. return LDPS_OK;
  260. /* Skip the two header lines. */
  261. (void) fgets(buf, sizeof(buf), irfile);
  262. (void) fgets(buf, sizeof(buf), irfile);
  263. if (add_symbols == NULL)
  264. {
  265. fprintf(stderr, "tv_add_symbols interface missing\n");
  266. return LDPS_ERR;
  267. }
  268. /* Parse the output from readelf. The columns are:
  269. Index Value Size Type Binding Visibility Section Name. */
  270. syms = (struct ld_plugin_symbol*)malloc(sizeof(struct ld_plugin_symbol) * 8);
  271. if (syms == NULL)
  272. return LDPS_ERR;
  273. maxsyms = 8;
  274. while (ftell(irfile) < end_offset
  275. && fgets(buf, sizeof(buf), irfile) != NULL)
  276. {
  277. parse_readelf_line(buf, &info);
  278. /* Ignore local symbols. */
  279. if (strncmp(info.bind, "LOCAL", 5) == 0)
  280. continue;
  281. weak = strncmp(info.bind, "WEAK", 4) == 0;
  282. if (strncmp(info.sect, "UND", 3) == 0)
  283. def = weak ? LDPK_WEAKUNDEF : LDPK_UNDEF;
  284. else if (strncmp(info.sect, "COM", 3) == 0)
  285. def = LDPK_COMMON;
  286. else
  287. def = weak ? LDPK_WEAKDEF : LDPK_DEF;
  288. if (strncmp(info.vis, "INTERNAL", 8) == 0)
  289. vis = LDPV_INTERNAL;
  290. else if (strncmp(info.vis, "HIDDEN", 6) == 0)
  291. vis = LDPV_HIDDEN;
  292. else if (strncmp(info.vis, "PROTECTED", 9) == 0)
  293. vis = LDPV_PROTECTED;
  294. else
  295. vis = LDPV_DEFAULT;
  296. /* If the symbol is listed in the options list, special-case
  297. it as a comdat symbol. */
  298. is_comdat = 0;
  299. for (i = 0; i < nopts; ++i)
  300. {
  301. if (info.name != NULL && strcmp(info.name, opts[i]) == 0)
  302. {
  303. is_comdat = 1;
  304. break;
  305. }
  306. }
  307. if (nsyms >= maxsyms)
  308. {
  309. syms = (struct ld_plugin_symbol*)
  310. realloc(syms, sizeof(struct ld_plugin_symbol) * maxsyms * 2);
  311. if (syms == NULL)
  312. return LDPS_ERR;
  313. maxsyms *= 2;
  314. }
  315. if (info.name == NULL)
  316. syms[nsyms].name = NULL;
  317. else
  318. {
  319. len = strlen(info.name);
  320. syms[nsyms].name = malloc(len + 1);
  321. strncpy(syms[nsyms].name, info.name, len + 1);
  322. }
  323. syms[nsyms].version = NULL;
  324. syms[nsyms].def = def;
  325. syms[nsyms].visibility = vis;
  326. syms[nsyms].size = info.size;
  327. syms[nsyms].comdat_key = is_comdat ? syms[nsyms].name : NULL;
  328. syms[nsyms].resolution = LDPR_UNKNOWN;
  329. ++nsyms;
  330. }
  331. claimed_file = (struct claimed_file*) malloc(sizeof(struct claimed_file));
  332. if (claimed_file == NULL)
  333. return LDPS_ERR;
  334. claimed_file->name = file->name;
  335. claimed_file->handle = file->handle;
  336. claimed_file->nsyms = nsyms;
  337. claimed_file->syms = syms;
  338. claimed_file->next = NULL;
  339. if (last_claimed_file == NULL)
  340. first_claimed_file = claimed_file;
  341. else
  342. last_claimed_file->next = claimed_file;
  343. last_claimed_file = claimed_file;
  344. (*message)(LDPL_INFO, "%s: claiming file, adding %d symbols",
  345. file->name, nsyms);
  346. if (nsyms > 0)
  347. (*add_symbols)(file->handle, nsyms, syms);
  348. *claimed = 1;
  349. if (irfile_was_opened)
  350. fclose(irfile);
  351. return LDPS_OK;
  352. }
  353. enum ld_plugin_status
  354. all_symbols_read_hook(void)
  355. {
  356. int i;
  357. const char* res;
  358. struct claimed_file* claimed_file;
  359. struct ld_plugin_input_file file;
  360. FILE* irfile;
  361. off_t end_offset;
  362. struct sym_info info;
  363. int len;
  364. char buf[160];
  365. char* p;
  366. const char* filename;
  367. (*message)(LDPL_INFO, "all symbols read hook called");
  368. if (get_symbols_v2 == NULL)
  369. {
  370. fprintf(stderr, "tv_get_symbols (v2) interface missing\n");
  371. return LDPS_ERR;
  372. }
  373. for (claimed_file = first_claimed_file;
  374. claimed_file != NULL;
  375. claimed_file = claimed_file->next)
  376. {
  377. (*get_symbols_v2)(claimed_file->handle, claimed_file->nsyms,
  378. claimed_file->syms);
  379. for (i = 0; i < claimed_file->nsyms; ++i)
  380. {
  381. switch (claimed_file->syms[i].resolution)
  382. {
  383. case LDPR_UNKNOWN:
  384. res = "UNKNOWN";
  385. break;
  386. case LDPR_UNDEF:
  387. res = "UNDEF";
  388. break;
  389. case LDPR_PREVAILING_DEF:
  390. res = "PREVAILING_DEF_REG";
  391. break;
  392. case LDPR_PREVAILING_DEF_IRONLY:
  393. res = "PREVAILING_DEF_IRONLY";
  394. break;
  395. case LDPR_PREVAILING_DEF_IRONLY_EXP:
  396. res = "PREVAILING_DEF_IRONLY_EXP";
  397. break;
  398. case LDPR_PREEMPTED_REG:
  399. res = "PREEMPTED_REG";
  400. break;
  401. case LDPR_PREEMPTED_IR:
  402. res = "PREEMPTED_IR";
  403. break;
  404. case LDPR_RESOLVED_IR:
  405. res = "RESOLVED_IR";
  406. break;
  407. case LDPR_RESOLVED_EXEC:
  408. res = "RESOLVED_EXEC";
  409. break;
  410. case LDPR_RESOLVED_DYN:
  411. res = "RESOLVED_DYN";
  412. break;
  413. default:
  414. res = "?";
  415. break;
  416. }
  417. (*message)(LDPL_INFO, "%s: %s: %s", claimed_file->name,
  418. claimed_file->syms[i].name, res);
  419. }
  420. }
  421. if (add_input_file == NULL)
  422. {
  423. fprintf(stderr, "tv_add_input_file interface missing\n");
  424. return LDPS_ERR;
  425. }
  426. if (get_input_file == NULL)
  427. {
  428. fprintf(stderr, "tv_get_input_file interface missing\n");
  429. return LDPS_ERR;
  430. }
  431. if (release_input_file == NULL)
  432. {
  433. fprintf(stderr, "tv_release_input_file interface missing\n");
  434. return LDPS_ERR;
  435. }
  436. for (claimed_file = first_claimed_file;
  437. claimed_file != NULL;
  438. claimed_file = claimed_file->next)
  439. {
  440. int irfile_was_opened = 0;
  441. char syms_name[80];
  442. (*get_input_file) (claimed_file->handle, &file);
  443. if (file.offset == 0)
  444. snprintf(syms_name, sizeof(syms_name), "%s.syms", file.name);
  445. else
  446. snprintf(syms_name, sizeof(syms_name), "%s-%d.syms",
  447. file.name, (int)file.offset);
  448. irfile = fopen(syms_name, "r");
  449. if (irfile != NULL)
  450. {
  451. irfile_was_opened = 1;
  452. end_offset = 1 << 20;
  453. }
  454. if (!irfile_was_opened)
  455. {
  456. irfile = fdopen(file.fd, "r");
  457. (void)fseek(irfile, file.offset, SEEK_SET);
  458. end_offset = file.offset + file.filesize;
  459. }
  460. /* Look for the beginning of output from readelf -s. */
  461. len = fread(buf, 1, 13, irfile);
  462. if (len < 13 || strncmp(buf, "\nSymbol table", 13) != 0)
  463. {
  464. fprintf(stderr, "%s: can't re-read original input file\n",
  465. claimed_file->name);
  466. return LDPS_ERR;
  467. }
  468. /* Skip the two header lines. */
  469. (void) fgets(buf, sizeof(buf), irfile);
  470. (void) fgets(buf, sizeof(buf), irfile);
  471. filename = NULL;
  472. while (ftell(irfile) < end_offset
  473. && fgets(buf, sizeof(buf), irfile) != NULL)
  474. {
  475. parse_readelf_line(buf, &info);
  476. /* Look for file name. */
  477. if (strncmp(info.type, "FILE", 4) == 0)
  478. {
  479. len = strlen(info.name);
  480. p = malloc(len + 1);
  481. strncpy(p, info.name, len + 1);
  482. filename = p;
  483. break;
  484. }
  485. }
  486. if (irfile_was_opened)
  487. fclose(irfile);
  488. (*release_input_file) (claimed_file->handle);
  489. if (filename == NULL)
  490. filename = claimed_file->name;
  491. if (claimed_file->nsyms == 0)
  492. continue;
  493. if (strlen(filename) >= sizeof(buf))
  494. {
  495. (*message)(LDPL_FATAL, "%s: filename too long", filename);
  496. return LDPS_ERR;
  497. }
  498. strcpy(buf, filename);
  499. p = strrchr(buf, '.');
  500. if (p == NULL
  501. || (strcmp(p, ".syms") != 0
  502. && strcmp(p, ".c") != 0
  503. && strcmp(p, ".cc") != 0))
  504. {
  505. (*message)(LDPL_FATAL, "%s: filename has unknown suffix",
  506. filename);
  507. return LDPS_ERR;
  508. }
  509. p[1] = 'o';
  510. p[2] = '\0';
  511. (*message)(LDPL_INFO, "%s: adding new input file", buf);
  512. (*add_input_file)(buf);
  513. }
  514. return LDPS_OK;
  515. }
  516. enum ld_plugin_status
  517. cleanup_hook(void)
  518. {
  519. (*message)(LDPL_INFO, "cleanup hook called");
  520. return LDPS_OK;
  521. }
  522. static void
  523. parse_readelf_line(char* p, struct sym_info* info)
  524. {
  525. int len;
  526. p += strspn(p, " ");
  527. /* Index field. */
  528. p += strcspn(p, " ");
  529. p += strspn(p, " ");
  530. /* Value field. */
  531. p += strcspn(p, " ");
  532. p += strspn(p, " ");
  533. /* Size field. */
  534. info->size = atoi(p);
  535. p += strcspn(p, " ");
  536. p += strspn(p, " ");
  537. /* Type field. */
  538. info->type = p;
  539. p += strcspn(p, " ");
  540. p += strspn(p, " ");
  541. /* Binding field. */
  542. info->bind = p;
  543. p += strcspn(p, " ");
  544. p += strspn(p, " ");
  545. /* Visibility field. */
  546. info->vis = p;
  547. p += strcspn(p, " ");
  548. p += strspn(p, " ");
  549. if (*p == '[')
  550. {
  551. /* Skip st_other. */
  552. p += strcspn(p, "]");
  553. p += strspn(p, "] ");
  554. }
  555. /* Section field. */
  556. info->sect = p;
  557. p += strcspn(p, " ");
  558. p += strspn(p, " ");
  559. /* Name field. */
  560. /* FIXME: Look for version. */
  561. len = strlen(p);
  562. if (len == 0)
  563. p = NULL;
  564. else if (p[len-1] == '\n')
  565. p[--len] = '\0';
  566. info->name = p;
  567. }