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