plugin_test.c 19 KB

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