]> Git Repo - binutils.git/blob - ld/testplug3.c
[gdb/testsuite] Fix gdb.fortran/ptype-on-functions.exp with gcc-4.8
[binutils.git] / ld / testplug3.c
1 /* Test plugin for the GNU linker.  Check non-object IR file and calling
2    release_input_file from onclaim_file.
3    Copyright (C) 2015-2020 Free Software Foundation, Inc.
4
5    This file is part of the GNU Binutils.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20    MA 02110-1301, USA.  */
21
22 #include "sysdep.h"
23 #include "bfd.h"
24 #if BFD_SUPPORTS_PLUGINS
25 #include "plugin-api.h"
26 #include "filenames.h"
27 /* For ARRAY_SIZE macro only - we don't link the library itself.  */
28 #include "libiberty.h"
29
30 extern enum ld_plugin_status onload (struct ld_plugin_tv *tv);
31 static enum ld_plugin_status onclaim_file (const struct ld_plugin_input_file *file,
32                                 int *claimed);
33 static enum ld_plugin_status onall_symbols_read (void);
34 static enum ld_plugin_status oncleanup (void);
35
36 /* Helper for calling plugin api message function.  */
37 #define TV_MESSAGE if (tv_message) (*tv_message)
38
39 /* Struct for recording files to claim / files claimed.  */
40 typedef struct claim_file
41 {
42   struct claim_file *next;
43   struct ld_plugin_input_file file;
44   bfd_boolean claimed;
45   struct ld_plugin_symbol *symbols;
46   int n_syms_allocated;
47   int n_syms_used;
48 } claim_file_t;
49
50 /* Types of things that can be added at all symbols read time.  */
51 typedef enum addfile_enum
52 {
53   ADD_FILE,
54   ADD_LIB,
55   ADD_DIR
56 } addfile_enum_t;
57
58 /* Struct for recording files to add to final link.  */
59 typedef struct add_file
60 {
61   struct add_file *next;
62   const char *name;
63   addfile_enum_t type;
64 } add_file_t;
65
66 /* Helper macro for defining array of transfer vector tags and names.  */
67 #define ADDENTRY(tag) { tag, #tag }
68
69 /* Struct for looking up human-readable versions of tag names.  */
70 typedef struct tag_name
71 {
72   enum ld_plugin_tag tag;
73   const char *name;
74 } tag_name_t;
75
76 /* Array of all known tags and their names.  */
77 static const tag_name_t tag_names[] =
78 {
79   ADDENTRY(LDPT_NULL),
80   ADDENTRY(LDPT_API_VERSION),
81   ADDENTRY(LDPT_GOLD_VERSION),
82   ADDENTRY(LDPT_LINKER_OUTPUT),
83   ADDENTRY(LDPT_OPTION),
84   ADDENTRY(LDPT_REGISTER_CLAIM_FILE_HOOK),
85   ADDENTRY(LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK),
86   ADDENTRY(LDPT_REGISTER_CLEANUP_HOOK),
87   ADDENTRY(LDPT_ADD_SYMBOLS),
88   ADDENTRY(LDPT_GET_SYMBOLS),
89   ADDENTRY(LDPT_GET_SYMBOLS_V2),
90   ADDENTRY(LDPT_ADD_INPUT_FILE),
91   ADDENTRY(LDPT_MESSAGE),
92   ADDENTRY(LDPT_GET_INPUT_FILE),
93   ADDENTRY(LDPT_GET_VIEW),
94   ADDENTRY(LDPT_RELEASE_INPUT_FILE),
95   ADDENTRY(LDPT_ADD_INPUT_LIBRARY),
96   ADDENTRY(LDPT_OUTPUT_NAME),
97   ADDENTRY(LDPT_SET_EXTRA_LIBRARY_PATH),
98   ADDENTRY(LDPT_GNU_LD_VERSION)
99 };
100
101 /* Function pointers to cache hooks passed at onload time.  */
102 static ld_plugin_register_claim_file tv_register_claim_file = 0;
103 static ld_plugin_register_all_symbols_read tv_register_all_symbols_read = 0;
104 static ld_plugin_register_cleanup tv_register_cleanup = 0;
105 static ld_plugin_add_symbols tv_add_symbols = 0;
106 static ld_plugin_get_symbols tv_get_symbols = 0;
107 static ld_plugin_get_symbols tv_get_symbols_v2 = 0;
108 static ld_plugin_add_input_file tv_add_input_file = 0;
109 static ld_plugin_message tv_message = 0;
110 static ld_plugin_get_input_file tv_get_input_file = 0;
111 static ld_plugin_get_view tv_get_view = 0;
112 static ld_plugin_release_input_file tv_release_input_file = 0;
113 static ld_plugin_add_input_library tv_add_input_library = 0;
114 static ld_plugin_set_extra_library_path tv_set_extra_library_path = 0;
115
116 /* Other cached info from the transfer vector.  */
117 static enum ld_plugin_output_file_type linker_output;
118 static const char *output_name;
119
120 /* Behaviour control flags set by plugin options.  */
121 static enum ld_plugin_status onload_ret = LDPS_OK;
122 static enum ld_plugin_status claim_file_ret = LDPS_OK;
123 static enum ld_plugin_status all_symbols_read_ret = LDPS_OK;
124 static enum ld_plugin_status cleanup_ret = LDPS_OK;
125 static bfd_boolean register_claimfile_hook = TRUE;
126 static bfd_boolean register_allsymbolsread_hook = FALSE;
127 static bfd_boolean register_cleanup_hook = FALSE;
128 static bfd_boolean dumpresolutions = FALSE;
129
130 /* The master list of all claimable/claimed files.  */
131 static claim_file_t *claimfiles_list = NULL;
132
133 /* We keep a tail pointer for easy linking on the end.  */
134 static claim_file_t **claimfiles_tail_chain_ptr = &claimfiles_list;
135
136 /* The last claimed file added to the list, for receiving syms.  */
137 static claim_file_t *last_claimfile = NULL;
138
139 /* The master list of all files to add to the final link.  */
140 static add_file_t *addfiles_list = NULL;
141
142 /* We keep a tail pointer for easy linking on the end.  */
143 static add_file_t **addfiles_tail_chain_ptr = &addfiles_list;
144
145 /* Add a new claimfile on the end of the chain.  */
146 static enum ld_plugin_status
147 record_claim_file (const char *file, off_t filesize)
148 {
149   claim_file_t *newfile;
150
151   newfile = malloc (sizeof *newfile);
152   if (!newfile)
153     return LDPS_ERR;
154   memset (newfile, 0, sizeof *newfile);
155   /* Only setup for now is remembering the name to look for.  */
156   newfile->file.name = file;
157   newfile->file.filesize = filesize;
158   /* Chain it on the end of the list.  */
159   *claimfiles_tail_chain_ptr = newfile;
160   claimfiles_tail_chain_ptr = &newfile->next;
161   /* Record it as active for receiving symbols to register.  */
162   last_claimfile = newfile;
163   return LDPS_OK;
164 }
165
166 /* Add a new addfile on the end of the chain.  */
167 static enum ld_plugin_status
168 record_add_file (const char *file, addfile_enum_t type)
169 {
170   add_file_t *newfile;
171
172   newfile = malloc (sizeof *newfile);
173   if (!newfile)
174     return LDPS_ERR;
175   newfile->next = NULL;
176   newfile->name = file;
177   newfile->type = type;
178   /* Chain it on the end of the list.  */
179   *addfiles_tail_chain_ptr = newfile;
180   addfiles_tail_chain_ptr = &newfile->next;
181   return LDPS_OK;
182 }
183
184 /* Parse a command-line argument string into a symbol definition.
185    Symbol-strings follow the colon-separated format:
186         NAME:VERSION:def:vis:size:COMDATKEY
187    where the fields in capitals are strings and those in lower
188    case are integers.  We don't allow to specify a resolution as
189    doing so is not meaningful when calling the add symbols hook.  */
190 static enum ld_plugin_status
191 parse_symdefstr (const char *str, struct ld_plugin_symbol *sym)
192 {
193   int n;
194   long long size;
195   const char *colon1, *colon2, *colon5;
196
197   /* Locate the colons separating the first two strings.  */
198   colon1 = strchr (str, ':');
199   if (!colon1)
200     return LDPS_ERR;
201   colon2 = strchr (colon1+1, ':');
202   if (!colon2)
203     return LDPS_ERR;
204   /* Name must not be empty (version may be).  */
205   if (colon1 == str)
206     return LDPS_ERR;
207
208   /* The fifth colon and trailing comdat key string are optional,
209      but the intermediate ones must all be present.  */
210   colon5 = strchr (colon2+1, ':');      /* Actually only third so far.  */
211   if (!colon5)
212     return LDPS_ERR;
213   colon5 = strchr (colon5+1, ':');      /* Hopefully fourth now.  */
214   if (!colon5)
215     return LDPS_ERR;
216   colon5 = strchr (colon5+1, ':');      /* Optional fifth now.  */
217
218   /* Finally we'll use sscanf to parse the numeric fields, then
219      we'll split out the strings which we need to allocate separate
220      storage for anyway so that we can add nul termination.  */
221   n = sscanf (colon2 + 1, "%hhi:%i:%lli", &sym->def, &sym->visibility, &size);
222   if (n != 3)
223     return LDPS_ERR;
224
225   /* Parsed successfully, so allocate strings and fill out fields.  */
226   sym->size = size;
227   sym->unused = 0;
228   sym->section_kind = 0;
229   sym->symbol_type = 0;
230   sym->resolution = LDPR_UNKNOWN;
231   sym->name = malloc (colon1 - str + 1);
232   if (!sym->name)
233     return LDPS_ERR;
234   memcpy (sym->name, str, colon1 - str);
235   sym->name[colon1 - str] = '\0';
236   if (colon2 > (colon1 + 1))
237     {
238       sym->version = malloc (colon2 - colon1);
239       if (!sym->version)
240         return LDPS_ERR;
241       memcpy (sym->version, colon1 + 1, colon2 - (colon1 + 1));
242       sym->version[colon2 - (colon1 + 1)] = '\0';
243     }
244   else
245     sym->version = NULL;
246   if (colon5 && colon5[1])
247     {
248       sym->comdat_key = malloc (strlen (colon5 + 1) + 1);
249       if (!sym->comdat_key)
250         return LDPS_ERR;
251       strcpy (sym->comdat_key, colon5 + 1);
252     }
253   else
254     sym->comdat_key = 0;
255   return LDPS_OK;
256 }
257
258 /* Record a symbol to be added for the last-added claimfile.  */
259 static enum ld_plugin_status
260 record_claimed_file_symbol (const char *symdefstr)
261 {
262   struct ld_plugin_symbol sym;
263
264   /* Can't add symbols except as belonging to claimed files.  */
265   if (!last_claimfile)
266     return LDPS_ERR;
267
268   /* If string doesn't parse correctly, give an error.  */
269   if (parse_symdefstr (symdefstr, &sym) != LDPS_OK)
270     return LDPS_ERR;
271
272   /* Check for enough space, resize array if needed, and add it.  */
273   if (last_claimfile->n_syms_allocated == last_claimfile->n_syms_used)
274     {
275       int new_n_syms = last_claimfile->n_syms_allocated
276                         ? 2 * last_claimfile->n_syms_allocated
277                         : 10;
278       last_claimfile->symbols = realloc (last_claimfile->symbols,
279                         new_n_syms * sizeof *last_claimfile->symbols);
280       if (!last_claimfile->symbols)
281         return LDPS_ERR;
282       last_claimfile->n_syms_allocated = new_n_syms;
283     }
284   last_claimfile->symbols[last_claimfile->n_syms_used++] = sym;
285
286   return LDPS_OK;
287 }
288
289 /* Records the status to return from one of the registered hooks.  */
290 static enum ld_plugin_status
291 set_ret_val (const char *whichval, enum ld_plugin_status retval)
292 {
293   if (!strcmp ("onload", whichval))
294     onload_ret = retval;
295   else if (!strcmp ("claimfile", whichval))
296     claim_file_ret = retval;
297   else if (!strcmp ("allsymbolsread", whichval))
298     all_symbols_read_ret = retval;
299   else if (!strcmp ("cleanup", whichval))
300     cleanup_ret = retval;
301   else
302     return LDPS_ERR;
303   return LDPS_OK;
304 }
305
306 /* Records hooks which should be registered.  */
307 static enum ld_plugin_status
308 set_register_hook (const char *whichhook, bfd_boolean yesno)
309 {
310   if (!strcmp ("claimfile", whichhook))
311     register_claimfile_hook = yesno;
312   else if (!strcmp ("allsymbolsread", whichhook))
313     register_allsymbolsread_hook = yesno;
314   else if (!strcmp ("cleanup", whichhook))
315     register_cleanup_hook = yesno;
316   else
317     return LDPS_ERR;
318   return LDPS_OK;
319 }
320
321 /* Determine type of plugin option and pass to individual parsers.  */
322 static enum ld_plugin_status
323 parse_option (const char *opt)
324 {
325   if (!strncmp ("fail", opt, 4))
326     return set_ret_val (opt + 4, LDPS_ERR);
327   else if (!strncmp ("pass", opt, 4))
328     return set_ret_val (opt + 4, LDPS_OK);
329   else if (!strncmp ("register", opt, 8))
330     return set_register_hook (opt + 8, TRUE);
331   else if (!strncmp ("noregister", opt, 10))
332     return set_register_hook (opt + 10, FALSE);
333   else if (!strncmp ("claim:", opt, 6))
334     return record_claim_file (opt + 6, 0);
335   else if (!strncmp ("sym:", opt, 4))
336     return record_claimed_file_symbol (opt + 4);
337   else if (!strncmp ("add:", opt, 4))
338     return record_add_file (opt + 4, ADD_FILE);
339   else if (!strncmp ("lib:", opt, 4))
340     return record_add_file (opt + 4, ADD_LIB);
341   else if (!strncmp ("dir:", opt, 4))
342     return record_add_file (opt + 4, ADD_DIR);
343   else if (!strcmp ("dumpresolutions", opt))
344     dumpresolutions = TRUE;
345   else
346     return LDPS_ERR;
347   return LDPS_OK;
348 }
349
350 /* Handle/record information received in a transfer vector entry.  */
351 static enum ld_plugin_status
352 parse_tv_tag (struct ld_plugin_tv *tv)
353 {
354 #define SETVAR(x) x = tv->tv_u.x
355   switch (tv->tv_tag)
356     {
357       case LDPT_OPTION:
358         return parse_option (tv->tv_u.tv_string);
359       case LDPT_NULL:
360       case LDPT_GOLD_VERSION:
361       case LDPT_GNU_LD_VERSION:
362       case LDPT_API_VERSION:
363       default:
364         break;
365       case LDPT_OUTPUT_NAME:
366         output_name = tv->tv_u.tv_string;
367         break;
368       case LDPT_LINKER_OUTPUT:
369         linker_output = tv->tv_u.tv_val;
370         break;
371       case LDPT_REGISTER_CLAIM_FILE_HOOK:
372         SETVAR(tv_register_claim_file);
373         break;
374       case LDPT_REGISTER_ALL_SYMBOLS_READ_HOOK:
375         SETVAR(tv_register_all_symbols_read);
376         break;
377       case LDPT_REGISTER_CLEANUP_HOOK:
378         SETVAR(tv_register_cleanup);
379         break;
380       case LDPT_ADD_SYMBOLS:
381         SETVAR(tv_add_symbols);
382         break;
383       case LDPT_GET_SYMBOLS:
384         SETVAR(tv_get_symbols);
385         break;
386       case LDPT_GET_SYMBOLS_V2:
387         tv_get_symbols_v2 = tv->tv_u.tv_get_symbols;
388         break;
389       case LDPT_ADD_INPUT_FILE:
390         SETVAR(tv_add_input_file);
391         break;
392       case LDPT_MESSAGE:
393         SETVAR(tv_message);
394         break;
395       case LDPT_GET_INPUT_FILE:
396         SETVAR(tv_get_input_file);
397         break;
398       case LDPT_GET_VIEW:
399         SETVAR(tv_get_view);
400         break;
401       case LDPT_RELEASE_INPUT_FILE:
402         SETVAR(tv_release_input_file);
403         break;
404       case LDPT_ADD_INPUT_LIBRARY:
405         SETVAR(tv_add_input_library);
406         break;
407       case LDPT_SET_EXTRA_LIBRARY_PATH:
408         SETVAR(tv_set_extra_library_path);
409         break;
410     }
411 #undef SETVAR
412   return LDPS_OK;
413 }
414
415 /* Standard plugin API entry point.  */
416 enum ld_plugin_status
417 onload (struct ld_plugin_tv *tv)
418 {
419   enum ld_plugin_status rv;
420
421   /* This plugin does nothing but dump the tv array.  It would
422      be an error if this function was called without one.  */
423   if (!tv)
424     return LDPS_ERR;
425
426   /* First entry should always be LDPT_MESSAGE, letting us get
427      hold of it easily so we can send output straight away.  */
428   if (tv[0].tv_tag == LDPT_MESSAGE)
429     tv_message = tv[0].tv_u.tv_message;
430
431   do
432     if ((rv = parse_tv_tag (tv)) != LDPS_OK)
433       return rv;
434   while ((tv++)->tv_tag != LDPT_NULL);
435
436   /* Register hooks only if instructed by options.  */
437   if (register_claimfile_hook)
438     {
439       if (!tv_register_claim_file)
440         {
441           TV_MESSAGE (LDPL_FATAL, "No register_claim_file hook");
442           fflush (NULL);
443           return LDPS_ERR;
444         }
445       (*tv_register_claim_file) (onclaim_file);
446     }
447   if (register_allsymbolsread_hook)
448     {
449       if (!tv_register_all_symbols_read)
450         {
451           TV_MESSAGE (LDPL_FATAL, "No register_all_symbols_read hook");
452           fflush (NULL);
453           return LDPS_ERR;
454         }
455       (*tv_register_all_symbols_read) (onall_symbols_read);
456     }
457   if (register_cleanup_hook)
458     {
459       if (!tv_register_cleanup)
460         {
461           TV_MESSAGE (LDPL_FATAL, "No register_cleanup hook");
462           fflush (NULL);
463           return LDPS_ERR;
464         }
465       (*tv_register_cleanup) (oncleanup);
466     }
467
468   /* Claim testsuite/ld-plugin/func.c, standalone or in a library.  Its
469      size must be SIZE_OF_FUNC_C bytes.  */
470 #define SIZE_OF_FUNC_C  248
471   if (onload_ret == LDPS_OK
472       && (record_claim_file ("func.c", SIZE_OF_FUNC_C) != LDPS_OK
473           || record_claimed_file_symbol ("func::0:0:0") != LDPS_OK
474           || record_claimed_file_symbol ("_func::0:0:0") != LDPS_OK
475           || record_claim_file ("libfunc.a", SIZE_OF_FUNC_C) != LDPS_OK
476           || record_claimed_file_symbol ("func::0:0:0") != LDPS_OK
477           || record_claimed_file_symbol ("_func::0:0:0") != LDPS_OK))
478     onload_ret = LDPS_ERR;
479
480   return onload_ret;
481 }
482
483 char *
484 xstrdup (const char *s)
485 {
486   size_t len = strlen (s) + 1;
487   char *ret = malloc (len + 1);
488   return (char *) memcpy (ret, s, len);
489 }
490
491 /* Standard plugin API registerable hook.  */
492 static enum ld_plugin_status
493 onclaim_file (const struct ld_plugin_input_file *file, int *claimed)
494 {
495   /* Let's see if we want to claim this file.  */
496   claim_file_t *claimfile = claimfiles_list;
497   size_t len = strlen (file->name);
498   char *name = xstrdup (file->name);
499   char *p = name + len;
500   bfd_boolean islib;
501
502   /* Only match the file name without the directory part.  */
503   islib = *p == 'a' && *(p - 1) == '.';
504   for (; p != name; p--)
505     if (IS_DIR_SEPARATOR (*p))
506       {
507         p++;
508         break;
509       }
510
511   while (claimfile)
512     {
513       /* Claim the file only if the file name and size match and don't
514          match the whole library.  */
515       if (!strcmp (p, claimfile->file.name)
516           && claimfile->file.filesize == file->filesize
517           && (!islib || file->offset != 0))
518         break;
519       claimfile = claimfile->next;
520     }
521
522   free (name);
523
524   /* If we decided to claim it, record that fact, and add any symbols
525      that were defined for it by plugin options.  */
526   *claimed = (claimfile != 0);
527   if (claimfile)
528     {
529       char buffer[30];
530       int fd;
531
532       TV_MESSAGE (LDPL_INFO, "Claimed: %s [@%ld/%ld]", file->name,
533                   (long)file->offset, (long)file->filesize);
534
535       claimfile->claimed = TRUE;
536       claimfile->file = *file;
537       if (claimfile->n_syms_used && !tv_add_symbols)
538         claim_file_ret = LDPS_ERR;
539       else if (claimfile->n_syms_used)
540         claim_file_ret = (*tv_add_symbols) (claimfile->file.handle,
541                                             claimfile->n_syms_used,
542                                             claimfile->symbols);
543
544       fd = claimfile->file.fd;
545       name = xstrdup (claimfile->file.name);
546       claim_file_ret = tv_release_input_file (claimfile->file.handle);
547       if (claim_file_ret != LDPS_OK)
548         {
549           free (name);
550           return claim_file_ret;
551         }
552       if (read (fd, buffer, sizeof (buffer)) >= 0)
553         {
554           claim_file_ret = LDPS_ERR;
555           TV_MESSAGE (LDPL_FATAL, "Unreleased file descriptor on: %s", name);
556         }
557       free (name);
558     }
559
560   return claim_file_ret;
561 }
562
563 /* Standard plugin API registerable hook.  */
564 static enum ld_plugin_status
565 onall_symbols_read (void)
566 {
567   static const char *resolutions[] =
568     {
569       "LDPR_UNKNOWN",
570       "LDPR_UNDEF",
571       "LDPR_PREVAILING_DEF",
572       "LDPR_PREVAILING_DEF_IRONLY",
573       "LDPR_PREEMPTED_REG",
574       "LDPR_PREEMPTED_IR",
575       "LDPR_RESOLVED_IR",
576       "LDPR_RESOLVED_EXEC",
577       "LDPR_RESOLVED_DYN",
578       "LDPR_PREVAILING_DEF_IRONLY_EXP",
579     };
580   claim_file_t *claimfile = dumpresolutions ? claimfiles_list : NULL;
581   add_file_t *addfile = addfiles_list;
582   TV_MESSAGE (LDPL_INFO, "hook called: all symbols read.");
583   for ( ; claimfile; claimfile = claimfile->next)
584     {
585       enum ld_plugin_status rv;
586       int n;
587       if (claimfile->n_syms_used && !tv_get_symbols_v2)
588         return LDPS_ERR;
589       else if (!claimfile->n_syms_used)
590         continue;
591       else if (!claimfile->file.handle)
592         continue;
593       rv = tv_get_symbols_v2 (claimfile->file.handle, claimfile->n_syms_used,
594                               claimfile->symbols);
595       if (rv != LDPS_OK)
596         return rv;
597       for (n = 0; n < claimfile->n_syms_used; n++)
598         TV_MESSAGE (LDPL_INFO, "Sym: '%s%s%s' Resolution: %s",
599                     claimfile->symbols[n].name,
600                     claimfile->symbols[n].version ? "@" : "",
601                     (claimfile->symbols[n].version
602                      ? claimfile->symbols[n].version : ""),
603                     resolutions[claimfile->symbols[n].resolution]);
604     }
605   for ( ; addfile ; addfile = addfile->next)
606     {
607       enum ld_plugin_status rv;
608       if (addfile->type == ADD_LIB && tv_add_input_library)
609         rv = (*tv_add_input_library) (addfile->name);
610       else if (addfile->type == ADD_FILE && tv_add_input_file)
611         rv = (*tv_add_input_file) (addfile->name);
612       else if (addfile->type == ADD_DIR && tv_set_extra_library_path)
613         rv = (*tv_set_extra_library_path) (addfile->name);
614       else
615         rv = LDPS_ERR;
616       if (rv != LDPS_OK)
617         return rv;
618     }
619   fflush (NULL);
620   return all_symbols_read_ret;
621 }
622
623 /* Standard plugin API registerable hook.  */
624 static enum ld_plugin_status
625 oncleanup (void)
626 {
627   TV_MESSAGE (LDPL_INFO, "hook called: cleanup.");
628   fflush (NULL);
629   return cleanup_ret;
630 }
631 #endif /* BFD_SUPPORTS_PLUGINS */
This page took 0.060128 seconds and 4 git commands to generate.