LCOV - code coverage report
Current view: top level - gcc - plugin.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 64.0 % 369 236
Test Date: 2026-09-19 16:22:48 Functions: 67.9 % 28 19
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* Support for GCC plugin mechanism.
       2              :    Copyright (C) 2009-2026 Free Software Foundation, Inc.
       3              : 
       4              : This file is part of GCC.
       5              : 
       6              : GCC is free software; you can redistribute it and/or modify
       7              : it under the terms of the GNU General Public License as published by
       8              : the Free Software Foundation; either version 3, or (at your option)
       9              : any later version.
      10              : 
      11              : GCC is distributed in the hope that it will be useful,
      12              : but WITHOUT ANY WARRANTY; without even the implied warranty of
      13              : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14              : GNU General Public License for more details.
      15              : 
      16              : You should have received a copy of the GNU General Public License
      17              : along with GCC; see the file COPYING3.  If not see
      18              : <http://www.gnu.org/licenses/>.  */
      19              : 
      20              : /* This file contains the support for GCC plugin mechanism based on the
      21              :    APIs described in doc/plugin.texi.  */
      22              : 
      23              : #include "config.h"
      24              : #define INCLUDE_DLFCN_H
      25              : #include "system.h"
      26              : #include "coretypes.h"
      27              : #include "options.h"
      28              : #include "tree-pass.h"
      29              : #include "diagnostic-core.h"
      30              : #include "flags.h"
      31              : #include "intl.h"
      32              : #include "plugin.h"
      33              : 
      34              : #ifdef ENABLE_PLUGIN
      35              : #include "plugin-version.h"
      36              : #endif
      37              : 
      38              : #ifdef __MINGW32__
      39              : #ifndef WIN32_LEAN_AND_MEAN
      40              : #define WIN32_LEAN_AND_MEAN
      41              : #endif
      42              : #ifndef NOMINMAX
      43              : #define NOMINMAX
      44              : #endif
      45              : #define WIN32_LEAN_AND_MEAN
      46              : #include <windows.h>
      47              : #endif
      48              : 
      49              : #define GCC_PLUGIN_STRINGIFY0(X) #X
      50              : #define GCC_PLUGIN_STRINGIFY1(X) GCC_PLUGIN_STRINGIFY0 (X)
      51              : 
      52              : /* Event names as strings.  Keep in sync with enum plugin_event.  */
      53              : static const char *plugin_event_name_init[] =
      54              : {
      55              : # define DEFEVENT(NAME) GCC_PLUGIN_STRINGIFY1 (NAME),
      56              : # include "plugin.def"
      57              : # undef DEFEVENT
      58              : };
      59              : 
      60              : /* A printf format large enough for the largest event above.  */
      61              : #define FMT_FOR_PLUGIN_EVENT "%-32s"
      62              : 
      63              : const char **plugin_event_name = plugin_event_name_init;
      64              : 
      65              : /* Event hashtable helpers.  */
      66              : 
      67              : struct event_hasher : nofree_ptr_hash <const char *>
      68              : {
      69              :   static inline hashval_t hash (const char **);
      70              :   static inline bool equal (const char **, const char **);
      71              : };
      72              : 
      73              : /* Helper function for the event hash table that hashes the entry V.  */
      74              : 
      75              : inline hashval_t
      76            0 : event_hasher::hash (const char **v)
      77              : {
      78            0 :   return htab_hash_string (*v);
      79              : }
      80              : 
      81              : /* Helper function for the event hash table that compares the name of an
      82              :    existing entry (S1) with the given string (S2).  */
      83              : 
      84              : inline bool
      85            0 : event_hasher::equal (const char **s1, const char **s2)
      86              : {
      87            0 :   return !strcmp (*s1, *s2);
      88              : }
      89              : 
      90              : /* A hash table to map event names to the position of the names in the
      91              :    plugin_event_name table.  */
      92              : static hash_table<event_hasher> *event_tab;
      93              : 
      94              : /* Keep track of the limit of allocated events and space ready for
      95              :    allocating events.  */
      96              : static int event_last = PLUGIN_EVENT_FIRST_DYNAMIC;
      97              : static int event_horizon = PLUGIN_EVENT_FIRST_DYNAMIC;
      98              : 
      99              : /* Hash table for the plugin_name_args objects created during command-line
     100              :    parsing.  */
     101              : static htab_t plugin_name_args_tab = NULL;
     102              : 
     103              : namespace {
     104              : /* List node for keeping track of plugin-registered callback.  */
     105              : struct callback_info
     106              : {
     107              :   const char *plugin_name;   /* Name of plugin that registers the callback.  */
     108              :   plugin_callback_func func; /* Callback to be called.  */
     109              :   void *user_data;           /* plugin-specified data.  */
     110              :   struct callback_info *next;
     111              : };
     112              : }
     113              : 
     114              : /* An array of lists of 'callback_info' objects indexed by the event id.  */
     115              : static struct callback_info *plugin_callbacks_init[PLUGIN_EVENT_FIRST_DYNAMIC];
     116              : static struct callback_info **plugin_callbacks = plugin_callbacks_init;
     117              : 
     118              : /* For invoke_plugin_callbacks(), see plugin.h.  */
     119              : bool flag_plugin_added = false;
     120              : 
     121              : #ifdef ENABLE_PLUGIN
     122              : /* Each plugin should define an initialization function with exactly
     123              :    this name.  */
     124              : static const char *str_plugin_init_func_name = "plugin_init";
     125              : 
     126              : /* Each plugin should define this symbol to assert that it is
     127              :    distributed under a GPL-compatible license.  */
     128              : static const char *str_license = "plugin_is_GPL_compatible";
     129              : #endif
     130              : 
     131              : /* Helper function for hashing the base_name of the plugin_name_args
     132              :    structure to be inserted into the hash table.  */
     133              : 
     134              : static hashval_t
     135            0 : htab_hash_plugin (const void *p)
     136              : {
     137            0 :   const struct plugin_name_args *plugin = (const struct plugin_name_args *) p;
     138            0 :   return htab_hash_string (plugin->base_name);
     139              :  }
     140              : 
     141              : /* Helper function for the hash table that compares the base_name of the
     142              :    existing entry (S1) with the given string (S2).  */
     143              : 
     144              : static int
     145           17 : htab_str_eq (const void *s1, const void *s2)
     146              : {
     147           17 :   const struct plugin_name_args *plugin = (const struct plugin_name_args *) s1;
     148           17 :   return !strcmp (plugin->base_name, (const char *) s2);
     149              : }
     150              : 
     151              : 
     152              : /* Given a plugin's full-path name FULL_NAME, e.g. /pass/to/NAME.so,
     153              :    return NAME.  */
     154              : 
     155              : static char *
     156          163 : get_plugin_base_name (const char *full_name)
     157              : {
     158              :   /* First get the base name part of the full-path name, i.e. NAME.so.  */
     159          163 :   char *base_name = xstrdup (lbasename (full_name));
     160              : 
     161              :   /* Then get rid of the extension in the name, e.g., .so.  */
     162          163 :   strip_off_ending (base_name, strlen (base_name));
     163              : 
     164          163 :   return base_name;
     165              : }
     166              : 
     167              : 
     168              : /* Create a plugin_name_args object for the given plugin and insert it
     169              :    to the hash table. This function is called when
     170              :    -fplugin=/path/to/NAME.so or -fplugin=NAME option is processed.  */
     171              : 
     172              : void
     173          274 : add_new_plugin (const char* plugin_name)
     174              : {
     175          274 :   struct plugin_name_args *plugin;
     176          274 :   void **slot;
     177          274 :   char *base_name;
     178          274 :   bool name_is_short;
     179          274 :   const char *pc;
     180              : 
     181          274 :   flag_plugin_added = true;
     182              : 
     183              :   /* Replace short names by their full path when relevant.  */
     184          274 :   name_is_short  = !IS_ABSOLUTE_PATH (plugin_name);
     185          984 :   for (pc = plugin_name; name_is_short && *pc; pc++)
     186          710 :     if (*pc == '.' || IS_DIR_SEPARATOR (*pc))
     187          163 :       name_is_short = false;
     188              : 
     189          274 :   if (name_is_short)
     190              :     {
     191          111 :       base_name = const_cast<char*> (plugin_name);
     192              : 
     193              : #if defined(__MINGW32__)
     194              :       static const char plugin_ext[] = ".dll";
     195              : #elif defined(__APPLE__)
     196              :       /* macOS has two types of libraries: dynamic libraries (.dylib) and
     197              :          plugins (.bundle). Both can be used with dlopen()/dlsym() but the
     198              :          former cannot be linked at build time (i.e., with the -lfoo linker
     199              :          option). A GCC plugin is therefore probably a macOS plugin but their
     200              :          use seems to be quite rare and the .bundle extension is more of a
     201              :          recommendation rather than the rule. This raises the questions of how
     202              :          well they are supported by tools (e.g., libtool). So to avoid
     203              :          complications let's use the .dylib extension for now. In the future,
     204              :          if this proves to be an issue, we can always check for both
     205              :          extensions.  */
     206              :       static const char plugin_ext[] = ".dylib";
     207              : #else
     208          111 :       static const char plugin_ext[] = ".so";
     209              : #endif
     210              : 
     211          111 :       plugin_name = concat (default_plugin_dir_name (), "/",
     212              :                             plugin_name, plugin_ext, NULL);
     213          111 :       if (access (plugin_name, R_OK))
     214            4 :         fatal_error
     215            4 :           (input_location,
     216              :            "inaccessible plugin file %s expanded from short plugin name %s: %m",
     217              :            plugin_name, base_name);
     218              :     }
     219              :   else
     220          163 :     base_name = get_plugin_base_name (plugin_name);
     221              : 
     222              :   /* If this is the first -fplugin= option we encounter, create
     223              :      'plugin_name_args_tab' hash table.  */
     224          270 :   if (!plugin_name_args_tab)
     225          270 :     plugin_name_args_tab = htab_create (10, htab_hash_plugin, htab_str_eq,
     226              :                                         NULL);
     227              : 
     228          270 :   slot = htab_find_slot_with_hash (plugin_name_args_tab, base_name,
     229              :                                    htab_hash_string (base_name), INSERT);
     230              : 
     231              :   /* If the same plugin (name) has been specified earlier, either emit an
     232              :      error or a warning message depending on if they have identical full
     233              :      (path) names.  */
     234          270 :   if (*slot)
     235              :     {
     236            0 :       plugin = (struct plugin_name_args *) *slot;
     237            0 :       if (strcmp (plugin->full_name, plugin_name))
     238            0 :         error ("plugin %qs was specified with different paths: %qs and %qs",
     239              :                plugin->base_name, plugin->full_name, plugin_name);
     240              :       return;
     241              :     }
     242              : 
     243          270 :   plugin = XCNEW (struct plugin_name_args);
     244          270 :   plugin->base_name = base_name;
     245          270 :   plugin->full_name = plugin_name;
     246              : 
     247          270 :   *slot = plugin;
     248              : }
     249              : 
     250              : 
     251              : /* Parse the -fplugin-arg-<name>-<key>[=<value>] option and create a
     252              :    'plugin_argument' object for the parsed key-value pair. ARG is
     253              :    the <name>-<key>[=<value>] part of the option.  */
     254              : 
     255              : void
     256           17 : parse_plugin_arg_opt (const char *arg)
     257              : {
     258           17 :   size_t len = 0, name_len = 0, key_len = 0, value_len = 0;
     259           17 :   const char *ptr, *name_start = arg, *key_start = NULL, *value_start = NULL;
     260           17 :   char *name, *key, *value;
     261           17 :   void **slot;
     262           17 :   bool name_parsed = false, key_parsed = false;
     263              : 
     264              :   /* Iterate over the ARG string and identify the starting character position
     265              :      of 'name', 'key', and 'value' and their lengths.  */
     266          596 :   for (ptr = arg; *ptr; ++ptr)
     267              :     {
     268              :       /* Only the first '-' encountered is considered a separator between
     269              :          'name' and 'key'. All the subsequent '-'s are considered part of
     270              :          'key'. For example, given -fplugin-arg-foo-bar-primary-key=value,
     271              :          the plugin name is 'foo' and the key is 'bar-primary-key'.  */
     272          579 :       if (*ptr == '-' && !name_parsed)
     273              :         {
     274           17 :           name_len = len;
     275           17 :           len = 0;
     276           17 :           key_start = ptr + 1;
     277           17 :           name_parsed = true;
     278           17 :           continue;
     279              :         }
     280          562 :       else if (*ptr == '=')
     281              :         {
     282           10 :           if (!key_parsed)
     283              :             {
     284           10 :               key_len = len;
     285           10 :               len = 0;
     286           10 :               value_start = ptr + 1;
     287           10 :               key_parsed = true;
     288              :             }
     289           10 :           continue;
     290              :         }
     291              :       else
     292          552 :         ++len;
     293              :     }
     294              : 
     295           17 :   if (!key_start)
     296              :     {
     297            0 :       error ("malformed option %<-fplugin-arg-%s%>: "
     298              :              "missing %<-<key>[=<value>]%>",
     299              :              arg);
     300            0 :       return;
     301              :     }
     302              : 
     303              :   /* If the option doesn't contain the 'value' part, LEN is the KEY_LEN.
     304              :      Otherwise, it is the VALUE_LEN.  */
     305           17 :   if (!value_start)
     306              :     key_len = len;
     307              :   else
     308           10 :     value_len = len;
     309              : 
     310           17 :   name = XNEWVEC (char, name_len + 1);
     311           17 :   strncpy (name, name_start, name_len);
     312           17 :   name[name_len] = '\0';
     313              : 
     314              :   /* Check if the named plugin has already been specified earlier in the
     315              :      command-line.  */
     316           17 :   if (plugin_name_args_tab
     317           17 :       && ((slot = htab_find_slot_with_hash (plugin_name_args_tab, name,
     318              :                                             htab_hash_string (name), NO_INSERT))
     319              :           != NULL))
     320              :     {
     321           17 :       struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
     322              : 
     323           17 :       key = XNEWVEC (char, key_len + 1);
     324           17 :       strncpy (key, key_start, key_len);
     325           17 :       key[key_len] = '\0';
     326           17 :       if (value_start)
     327              :         {
     328           10 :           value = XNEWVEC (char, value_len + 1);
     329           10 :           strncpy (value, value_start, value_len);
     330           10 :           value[value_len] = '\0';
     331              :         }
     332              :       else
     333              :         value = NULL;
     334              : 
     335              :       /* Create a plugin_argument object for the parsed key-value pair.
     336              :          If there are already arguments for this plugin, we will need to
     337              :          adjust the argument array size by creating a new array and deleting
     338              :          the old one. If the performance ever becomes an issue, we can
     339              :          change the code by pre-allocating a larger array first.  */
     340           17 :       if (plugin->argc > 0)
     341              :         {
     342            1 :           struct plugin_argument *args = XNEWVEC (struct plugin_argument,
     343              :                                                   plugin->argc + 1);
     344            1 :           memcpy (args, plugin->argv,
     345            1 :                   sizeof (struct plugin_argument) * plugin->argc);
     346            1 :           XDELETEVEC (plugin->argv);
     347            1 :           plugin->argv = args;
     348            1 :           ++plugin->argc;
     349              :         }
     350              :       else
     351              :         {
     352           16 :           gcc_assert (plugin->argv == NULL);
     353           16 :           plugin->argv = XNEWVEC (struct plugin_argument, 1);
     354           16 :           plugin->argc = 1;
     355              :         }
     356              : 
     357           17 :       plugin->argv[plugin->argc - 1].key = key;
     358           17 :       plugin->argv[plugin->argc - 1].value = value;
     359              :     }
     360              :   else
     361            0 :     error ("plugin %s should be specified before %<-fplugin-arg-%s%> "
     362              :            "in the command line", name, arg);
     363              : 
     364              :   /* We don't need the plugin's name anymore. Just release it.  */
     365           17 :   XDELETEVEC (name);
     366              : }
     367              : 
     368              : /* Register additional plugin information. NAME is the name passed to
     369              :    plugin_init. INFO is the information that should be registered. */
     370              : 
     371              : static void
     372            0 : register_plugin_info (const char* name, struct plugin_info *info)
     373              : {
     374            0 :   void **slot = htab_find_slot_with_hash (plugin_name_args_tab, name,
     375              :                                           htab_hash_string (name), NO_INSERT);
     376            0 :   struct plugin_name_args *plugin;
     377              : 
     378            0 :   if (slot == NULL)
     379              :     {
     380            0 :       error ("unable to register info for plugin %qs - plugin name not found",
     381              :              name);
     382            0 :       return;
     383              :     }
     384            0 :   plugin = (struct plugin_name_args *) *slot;
     385            0 :   plugin->version = info->version;
     386            0 :   plugin->help = info->help;
     387              : }
     388              : 
     389              : /* Look up the event id for NAME.  If the name is not found, return -1
     390              :    if INSERT is NO_INSERT.  */
     391              : 
     392              : int
     393            0 : get_named_event_id (const char *name, enum insert_option insert)
     394              : {
     395            0 :   const char ***slot;
     396              : 
     397            0 :   if (!event_tab)
     398              :     {
     399            0 :       int i;
     400              : 
     401            0 :       event_tab = new hash_table<event_hasher> (150);
     402            0 :       for (i = 0; i < event_last; i++)
     403              :         {
     404            0 :           slot = event_tab->find_slot (&plugin_event_name[i], INSERT);
     405            0 :           gcc_assert (*slot == HTAB_EMPTY_ENTRY);
     406            0 :           *slot = &plugin_event_name[i];
     407              :         }
     408              :     }
     409            0 :   slot = event_tab->find_slot (&name, insert);
     410            0 :   if (slot == NULL)
     411              :     return -1;
     412            0 :   if (*slot != HTAB_EMPTY_ENTRY)
     413            0 :     return *slot - &plugin_event_name[0];
     414              : 
     415            0 :   if (event_last >= event_horizon)
     416              :     {
     417            0 :       event_horizon = event_last * 2;
     418            0 :       if (plugin_event_name == plugin_event_name_init)
     419              :         {
     420            0 :           plugin_event_name = XNEWVEC (const char *, event_horizon);
     421            0 :           memcpy (plugin_event_name, plugin_event_name_init,
     422              :                   sizeof plugin_event_name_init);
     423            0 :           plugin_callbacks = XNEWVEC (struct callback_info *, event_horizon);
     424            0 :           memcpy (plugin_callbacks, plugin_callbacks_init,
     425              :                   sizeof plugin_callbacks_init);
     426              :         }
     427              :       else
     428              :         {
     429            0 :           plugin_event_name
     430            0 :             = XRESIZEVEC (const char *, plugin_event_name, event_horizon);
     431            0 :           plugin_callbacks = XRESIZEVEC (struct callback_info *,
     432              :                                          plugin_callbacks, event_horizon);
     433              :         }
     434              :       /* All the pointers in the hash table will need to be updated.  */
     435            0 :       delete event_tab;
     436            0 :       event_tab = NULL;
     437              :     }
     438              :   else
     439            0 :     *slot = &plugin_event_name[event_last];
     440            0 :   plugin_event_name[event_last] = name;
     441            0 :   return event_last++;
     442              : }
     443              : 
     444              : /* Called from the plugin's initialization code. Register a single callback.
     445              :    This function can be called multiple times.
     446              : 
     447              :    PLUGIN_NAME - display name for this plugin
     448              :    EVENT       - which event the callback is for
     449              :    CALLBACK    - the callback to be called at the event
     450              :    USER_DATA   - plugin-provided data   */
     451              : 
     452              : void
     453          342 : register_callback (const char *plugin_name,
     454              :                    int event,
     455              :                    plugin_callback_func callback,
     456              :                    void *user_data)
     457              : {
     458          342 :   switch (event)
     459              :     {
     460          173 :       case PLUGIN_PASS_MANAGER_SETUP:
     461          173 :         gcc_assert (!callback);
     462          173 :         register_pass ((struct register_pass_info *) user_data);
     463          173 :         break;
     464            0 :       case PLUGIN_INFO:
     465            0 :         gcc_assert (!callback);
     466            0 :         register_plugin_info (plugin_name, (struct plugin_info *) user_data);
     467            0 :         break;
     468           10 :       case PLUGIN_REGISTER_GGC_ROOTS:
     469           10 :         gcc_assert (!callback);
     470           10 :         ggc_register_root_tab ((const struct ggc_root_tab*) user_data);
     471           10 :         break;
     472            0 :       case PLUGIN_EVENT_FIRST_DYNAMIC:
     473            0 :       default:
     474            0 :         if (event < PLUGIN_EVENT_FIRST_DYNAMIC || event >= event_last)
     475              :           {
     476            0 :             error ("unknown callback event registered by plugin %s",
     477              :                    plugin_name);
     478            0 :             return;
     479              :           }
     480              :       /* Fall through.  */
     481          159 :       case PLUGIN_START_PARSE_FUNCTION:
     482          159 :       case PLUGIN_FINISH_PARSE_FUNCTION:
     483          159 :       case PLUGIN_FINISH_TYPE:
     484          159 :       case PLUGIN_FINISH_DECL:
     485          159 :       case PLUGIN_START_UNIT:
     486          159 :       case PLUGIN_FINISH_UNIT:
     487          159 :       case PLUGIN_PRE_GENERICIZE:
     488          159 :       case PLUGIN_GGC_START:
     489          159 :       case PLUGIN_GGC_MARKING:
     490          159 :       case PLUGIN_GGC_END:
     491          159 :       case PLUGIN_ATTRIBUTES:
     492          159 :       case PLUGIN_PRAGMAS:
     493          159 :       case PLUGIN_FINISH:
     494          159 :       case PLUGIN_ALL_PASSES_START:
     495          159 :       case PLUGIN_ALL_PASSES_END:
     496          159 :       case PLUGIN_ALL_IPA_PASSES_START:
     497          159 :       case PLUGIN_ALL_IPA_PASSES_END:
     498          159 :       case PLUGIN_OVERRIDE_GATE:
     499          159 :       case PLUGIN_PASS_EXECUTION:
     500          159 :       case PLUGIN_EARLY_GIMPLE_PASSES_START:
     501          159 :       case PLUGIN_EARLY_GIMPLE_PASSES_END:
     502          159 :       case PLUGIN_NEW_PASS:
     503          159 :       case PLUGIN_INCLUDE_FILE:
     504          159 :         {
     505          159 :           struct callback_info *new_callback;
     506          159 :           if (!callback)
     507              :             {
     508            0 :               error ("plugin %s registered a null callback function "
     509            0 :                      "for event %s", plugin_name, plugin_event_name[event]);
     510            0 :               return;
     511              :             }
     512          159 :           new_callback = XNEW (struct callback_info);
     513          159 :           new_callback->plugin_name = plugin_name;
     514          159 :           new_callback->func = callback;
     515          159 :           new_callback->user_data = user_data;
     516          159 :           new_callback->next = plugin_callbacks[event];
     517          159 :           plugin_callbacks[event] = new_callback;
     518              :         }
     519          159 :         break;
     520              :     }
     521              : }
     522              : 
     523              : /* Remove a callback for EVENT which has been registered with for a plugin
     524              :    PLUGIN_NAME.  Return PLUGEVT_SUCCESS if a matching callback was
     525              :    found & removed, PLUGEVT_NO_CALLBACK if the event does not have a matching
     526              :    callback, and PLUGEVT_NO_SUCH_EVENT if EVENT is invalid.  */
     527              : int
     528            0 : unregister_callback (const char *plugin_name, int event)
     529              : {
     530            0 :   struct callback_info *callback, **cbp;
     531              : 
     532            0 :   if (event >= event_last)
     533              :     return PLUGEVT_NO_SUCH_EVENT;
     534              : 
     535            0 :   for (cbp = &plugin_callbacks[event]; (callback = *cbp); cbp = &callback->next)
     536            0 :     if (strcmp (callback->plugin_name, plugin_name) == 0)
     537              :       {
     538            0 :         *cbp = callback->next;
     539            0 :         return PLUGEVT_SUCCESS;
     540              :       }
     541              :   return PLUGEVT_NO_CALLBACK;
     542              : }
     543              : 
     544              : /* Invoke all plugin callbacks registered with the specified event,
     545              :    called from invoke_plugin_callbacks().  */
     546              : 
     547              : int
     548       838219 : invoke_plugin_callbacks_full (int event, void *gcc_data)
     549              : {
     550       838219 :   int retval = PLUGEVT_SUCCESS;
     551              : 
     552       838219 :   timevar_push (TV_PLUGIN_RUN);
     553              : 
     554       838219 :   switch (event)
     555              :     {
     556            0 :       case PLUGIN_EVENT_FIRST_DYNAMIC:
     557            0 :       default:
     558            0 :         gcc_assert (event >= PLUGIN_EVENT_FIRST_DYNAMIC);
     559            0 :         gcc_assert (event < event_last);
     560              :       /* Fall through.  */
     561       838219 :       case PLUGIN_START_PARSE_FUNCTION:
     562       838219 :       case PLUGIN_FINISH_PARSE_FUNCTION:
     563       838219 :       case PLUGIN_FINISH_TYPE:
     564       838219 :       case PLUGIN_FINISH_DECL:
     565       838219 :       case PLUGIN_START_UNIT:
     566       838219 :       case PLUGIN_FINISH_UNIT:
     567       838219 :       case PLUGIN_PRE_GENERICIZE:
     568       838219 :       case PLUGIN_ATTRIBUTES:
     569       838219 :       case PLUGIN_PRAGMAS:
     570       838219 :       case PLUGIN_FINISH:
     571       838219 :       case PLUGIN_GGC_START:
     572       838219 :       case PLUGIN_GGC_MARKING:
     573       838219 :       case PLUGIN_GGC_END:
     574       838219 :       case PLUGIN_ALL_PASSES_START:
     575       838219 :       case PLUGIN_ALL_PASSES_END:
     576       838219 :       case PLUGIN_ALL_IPA_PASSES_START:
     577       838219 :       case PLUGIN_ALL_IPA_PASSES_END:
     578       838219 :       case PLUGIN_OVERRIDE_GATE:
     579       838219 :       case PLUGIN_PASS_EXECUTION:
     580       838219 :       case PLUGIN_EARLY_GIMPLE_PASSES_START:
     581       838219 :       case PLUGIN_EARLY_GIMPLE_PASSES_END:
     582       838219 :       case PLUGIN_NEW_PASS:
     583       838219 :       case PLUGIN_INCLUDE_FILE:
     584       838219 :         {
     585              :           /* Iterate over every callback registered with this event and
     586              :              call it.  */
     587       838219 :           struct callback_info *callback = plugin_callbacks[event];
     588              : 
     589       838219 :           if (!callback)
     590       728398 :             retval = PLUGEVT_NO_CALLBACK;
     591       948040 :           for ( ; callback; callback = callback->next)
     592       109821 :             (*callback->func) (gcc_data, callback->user_data);
     593              :         }
     594       838219 :         break;
     595              : 
     596            0 :       case PLUGIN_PASS_MANAGER_SETUP:
     597            0 :       case PLUGIN_REGISTER_GGC_ROOTS:
     598            0 :         gcc_assert (false);
     599              :     }
     600              : 
     601       838219 :   timevar_pop (TV_PLUGIN_RUN);
     602       838219 :   return retval;
     603              : }
     604              : 
     605              : #ifdef ENABLE_PLUGIN
     606              : 
     607              : /* Try to initialize PLUGIN. Return true if successful. */
     608              : 
     609              : #ifdef __MINGW32__
     610              : 
     611              : // Return a message string for last error or NULL if unknown. Must be freed
     612              : // with LocalFree().
     613              : static inline char *
     614              : win32_error_msg ()
     615              : {
     616              :   char *msg;
     617              :   return FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER |
     618              :                          FORMAT_MESSAGE_FROM_SYSTEM |
     619              :                          FORMAT_MESSAGE_IGNORE_INSERTS |
     620              :                          FORMAT_MESSAGE_MAX_WIDTH_MASK,
     621              :                          0,
     622              :                          GetLastError (),
     623              :                          MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
     624              :                          (char*)&msg,
     625              :                          0,
     626              :                          0)
     627              :     ? msg
     628              :     : NULL;
     629              : }
     630              : 
     631              : static bool
     632              : try_init_one_plugin (struct plugin_name_args *plugin)
     633              : {
     634              :   HMODULE dl_handle;
     635              :   plugin_init_func plugin_init;
     636              : 
     637              :   dl_handle = LoadLibrary (plugin->full_name);
     638              :   if (!dl_handle)
     639              :     {
     640              :       char *err = win32_error_msg ();
     641              :       error ("cannot load plugin %s\n%s", plugin->full_name, err);
     642              :       LocalFree (err);
     643              :       return false;
     644              :     }
     645              : 
     646              :   /* Check the plugin license. Unlike the name suggests, GetProcAddress()
     647              :      can be used for both functions and variables.  */
     648              :   if (GetProcAddress (dl_handle, str_license) == NULL)
     649              :     {
     650              :       char *err = win32_error_msg ();
     651              :       fatal_error (input_location,
     652              :                    "plugin %s is not licensed under a GPL-compatible license\n"
     653              :                    "%s", plugin->full_name, err);
     654              :     }
     655              : 
     656              :   /* Unlike dlsym(), GetProcAddress() returns a pointer to a function so we
     657              :      can cast directly without union tricks.  */
     658              :   plugin_init = (plugin_init_func)
     659              :     GetProcAddress (dl_handle, str_plugin_init_func_name);
     660              : 
     661              :   if (plugin_init == NULL)
     662              :     {
     663              :       char *err = win32_error_msg ();
     664              :       FreeLibrary (dl_handle);
     665              :       error ("cannot find %s in plugin %s\n%s", str_plugin_init_func_name,
     666              :              plugin->full_name, err);
     667              :       LocalFree (err);
     668              :       return false;
     669              :     }
     670              : 
     671              :   /* Call the plugin-provided initialization routine with the arguments.  */
     672              :   if ((*plugin_init) (plugin, &gcc_version))
     673              :     {
     674              :       FreeLibrary (dl_handle);
     675              :       error ("fail to initialize plugin %s", plugin->full_name);
     676              :       return false;
     677              :     }
     678              :   /* Leak dl_handle on purpose to ensure the plugin is loaded for the
     679              :      entire run of the compiler. */
     680              :   return true;
     681              : }
     682              : 
     683              : #else // POSIX-like with dlopen()/dlsym().
     684              : 
     685              : /* We need a union to cast dlsym return value to a function pointer
     686              :    as ISO C forbids assignment between function pointer and 'void *'.
     687              :    Use explicit union instead of __extension__(<union_cast>) for
     688              :    portability.  */
     689              : #define PTR_UNION_TYPE(TOTYPE) union { void *_q; TOTYPE _nq; }
     690              : #define PTR_UNION_AS_VOID_PTR(NAME) (NAME._q)
     691              : #define PTR_UNION_AS_CAST_PTR(NAME) (NAME._nq)
     692              : 
     693              : static bool
     694          270 : try_init_one_plugin (struct plugin_name_args *plugin)
     695              : {
     696          270 :   void *dl_handle;
     697          270 :   plugin_init_func plugin_init;
     698          270 :   const char *err;
     699          270 :   PTR_UNION_TYPE (plugin_init_func) plugin_init_union;
     700              : 
     701              :   /* We use RTLD_NOW to accelerate binding and detect any mismatch
     702              :      between the API expected by the plugin and the GCC API; we use
     703              :      RTLD_GLOBAL which is useful to plugins which themselves call
     704              :      dlopen.  */
     705          270 :   dl_handle = dlopen (plugin->full_name, RTLD_NOW | RTLD_GLOBAL);
     706          270 :   if (!dl_handle)
     707              :     {
     708            0 :       error ("cannot load plugin %s: %s", plugin->full_name, dlerror ());
     709            0 :       return false;
     710              :     }
     711              : 
     712              :   /* Clear any existing error.  */
     713          270 :   dlerror ();
     714              : 
     715              :   /* Check the plugin license.  */
     716          270 :   if (dlsym (dl_handle, str_license) == NULL)
     717            0 :     fatal_error (input_location,
     718              :                  "plugin %s is not licensed under a GPL-compatible license:"
     719              :                  " %s", plugin->full_name, dlerror ());
     720              : 
     721          270 :   PTR_UNION_AS_VOID_PTR (plugin_init_union)
     722          270 :     = dlsym (dl_handle, str_plugin_init_func_name);
     723          270 :   plugin_init = PTR_UNION_AS_CAST_PTR (plugin_init_union);
     724              : 
     725          270 :   if ((err = dlerror ()) != NULL)
     726              :     {
     727            0 :       dlclose(dl_handle);
     728            0 :       error ("cannot find %s in plugin %s: %s", str_plugin_init_func_name,
     729              :              plugin->full_name, err);
     730            0 :       return false;
     731              :     }
     732              : 
     733              :   /* Call the plugin-provided initialization routine with the arguments.  */
     734          270 :   if ((*plugin_init) (plugin, &gcc_version))
     735              :     {
     736            0 :       dlclose(dl_handle);
     737            0 :       error ("failed to initialize plugin %s", plugin->full_name);
     738            0 :       return false;
     739              :     }
     740              :   /* leak dl_handle on purpose to ensure the plugin is loaded for the
     741              :      entire run of the compiler. */
     742              :   return true;
     743              : }
     744              : #endif
     745              : 
     746              : /* Routine to dlopen and initialize one plugin. This function is passed to
     747              :    (and called by) the hash table traverse routine. Return 1 for the
     748              :    htab_traverse to continue scan, 0 to stop.
     749              : 
     750              :    SLOT - slot of the hash table element
     751              :    INFO - auxiliary pointer handed to hash table traverse routine
     752              :           (unused in this function)  */
     753              : 
     754              : static int
     755          270 : init_one_plugin (void **slot, void * ARG_UNUSED (info))
     756              : {
     757          270 :   struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
     758          270 :   bool ok = try_init_one_plugin (plugin);
     759          270 :   if (!ok)
     760              :     {
     761            0 :       htab_remove_elt_with_hash (plugin_name_args_tab, plugin->base_name,
     762            0 :                                  htab_hash_string (plugin->base_name));
     763            0 :       XDELETE (plugin);
     764              :     }
     765          270 :   return 1;
     766              : }
     767              : 
     768              : #endif  /* ENABLE_PLUGIN  */
     769              : 
     770              : /* Main plugin initialization function.  Called from compile_file() in
     771              :    toplev.cc.  */
     772              : 
     773              : void
     774       294583 : initialize_plugins (void)
     775              : {
     776              :   /* If no plugin was specified in the command-line, simply return.  */
     777       294583 :   if (!plugin_name_args_tab)
     778              :     return;
     779              : 
     780          270 :   timevar_push (TV_PLUGIN_INIT);
     781              : 
     782              : #ifdef ENABLE_PLUGIN
     783              :   /* Traverse and initialize each plugin specified in the command-line.  */
     784          270 :   htab_traverse_noresize (plugin_name_args_tab, init_one_plugin, NULL);
     785              : #endif
     786              : 
     787          270 :   timevar_pop (TV_PLUGIN_INIT);
     788              : }
     789              : 
     790              : /* Release memory used by one plugin. */
     791              : 
     792              : static int
     793          258 : finalize_one_plugin (void **slot, void * ARG_UNUSED (info))
     794              : {
     795          258 :   struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
     796          258 :   XDELETE (plugin);
     797          258 :   return 1;
     798              : }
     799              : 
     800              : /* Free memory allocated by the plugin system. */
     801              : 
     802              : void
     803       292499 : finalize_plugins (void)
     804              : {
     805       292499 :   if (!plugin_name_args_tab)
     806              :     return;
     807              : 
     808              :   /* We can now delete the plugin_name_args object as it will no longer
     809              :      be used. Note that base_name and argv fields (both of which were also
     810              :      dynamically allocated) are not freed as they could still be used by
     811              :      the plugin code.  */
     812              : 
     813          258 :   htab_traverse_noresize (plugin_name_args_tab, finalize_one_plugin, NULL);
     814              : 
     815              :   /* PLUGIN_NAME_ARGS_TAB is no longer needed, just delete it.  */
     816          258 :   htab_delete (plugin_name_args_tab);
     817          258 :   plugin_name_args_tab = NULL;
     818              : }
     819              : 
     820              : /* Implementation detail of for_each_plugin.  */
     821              : 
     822              : struct for_each_plugin_closure
     823              : {
     824              :   void (*cb) (const plugin_name_args *,
     825              :               void *user_data);
     826              :   void *user_data;
     827              : };
     828              : 
     829              : /* Implementation detail of for_each_plugin: callback for htab_traverse_noresize
     830              :    that calls the user-provided callback.  */
     831              : 
     832              : static int
     833           11 : for_each_plugin_cb (void **slot, void *info)
     834              : {
     835           11 :   struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
     836           11 :   for_each_plugin_closure *c = (for_each_plugin_closure *)info;
     837           11 :   c->cb (plugin, c->user_data);
     838           11 :   return 1;
     839              : }
     840              : 
     841              : /* Call CB with USER_DATA on each plugin.  */
     842              : 
     843              : void
     844          114 : for_each_plugin (void (*cb) (const plugin_name_args *,
     845              :                              void *user_data),
     846              :                  void *user_data)
     847              : {
     848          114 :   if (!plugin_name_args_tab)
     849              :     return;
     850              : 
     851           11 :   for_each_plugin_closure c;
     852           11 :   c.cb = cb;
     853           11 :   c.user_data = user_data;
     854              : 
     855           11 :   htab_traverse_noresize (plugin_name_args_tab, for_each_plugin_cb, &c);
     856              : }
     857              : 
     858              : /* Used to pass options to htab_traverse callbacks. */
     859              : 
     860              : struct print_options
     861              : {
     862              :   FILE *file;
     863              :   const char *indent;
     864              : };
     865              : 
     866              : /* Print the version of one plugin. */
     867              : 
     868              : static int
     869            0 : print_version_one_plugin (void **slot, void *data)
     870              : {
     871            0 :   struct print_options *opt = (struct print_options *) data;
     872            0 :   struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
     873            0 :   const char *version = plugin->version ? plugin->version : "Unknown version.";
     874              : 
     875            0 :   fprintf (opt->file, " %s%s: %s\n", opt->indent, plugin->base_name, version);
     876            0 :   return 1;
     877              : }
     878              : 
     879              : /* Print the version of each plugin. */
     880              : 
     881              : void
     882          125 : print_plugins_versions (FILE *file, const char *indent)
     883              : {
     884          125 :   struct print_options opt;
     885          125 :   opt.file = file;
     886          125 :   opt.indent = indent;
     887          125 :   if (!plugin_name_args_tab || htab_elements (plugin_name_args_tab) == 0)
     888          125 :     return;
     889              : 
     890            0 :   fprintf (file, "%sVersions of loaded plugins:\n", indent);
     891            0 :   htab_traverse_noresize (plugin_name_args_tab, print_version_one_plugin, &opt);
     892              : }
     893              : 
     894              : /* Print help for one plugin. SLOT is the hash table slot. DATA is the
     895              :    argument to htab_traverse_noresize. */
     896              : 
     897              : static int
     898            0 : print_help_one_plugin (void **slot, void *data)
     899              : {
     900            0 :   struct print_options *opt = (struct print_options *) data;
     901            0 :   struct plugin_name_args *plugin = (struct plugin_name_args *) *slot;
     902            0 :   const char *help = plugin->help ? plugin->help : "No help available .";
     903              : 
     904            0 :   char *dup = xstrdup (help);
     905            0 :   char *p, *nl;
     906            0 :   fprintf (opt->file, " %s%s:\n", opt->indent, plugin->base_name);
     907              : 
     908            0 :   for (p = nl = dup; nl; p = nl)
     909              :     {
     910            0 :       nl = strchr (nl, '\n');
     911            0 :       if (nl)
     912              :         {
     913            0 :           *nl = '\0';
     914            0 :           nl++;
     915              :         }
     916            0 :       fprintf (opt->file, "   %s %s\n", opt->indent, p);
     917              :     }
     918              : 
     919            0 :   free (dup);
     920            0 :   return 1;
     921              : }
     922              : 
     923              : /* Print help for each plugin. The output goes to FILE and every line starts
     924              :    with INDENT. */
     925              : 
     926              : void
     927            3 : print_plugins_help (FILE *file, const char *indent)
     928              : {
     929            3 :   struct print_options opt;
     930            3 :   opt.file = file;
     931            3 :   opt.indent = indent;
     932            3 :   if (!plugin_name_args_tab || htab_elements (plugin_name_args_tab) == 0)
     933            3 :     return;
     934              : 
     935            0 :   fprintf (file, "%sHelp for the loaded plugins:\n", indent);
     936            0 :   htab_traverse_noresize (plugin_name_args_tab, print_help_one_plugin, &opt);
     937              : }
     938              : 
     939              : 
     940              : /* Return true if plugins have been loaded.  */
     941              : 
     942              : bool
     943           39 : plugins_active_p (void)
     944              : {
     945           39 :   int event;
     946              : 
     947          975 :   for (event = PLUGIN_PASS_MANAGER_SETUP; event < event_last; event++)
     948          936 :     if (plugin_callbacks[event])
     949              :       return true;
     950              : 
     951              :   return false;
     952              : }
     953              : 
     954              : 
     955              : /* Dump to FILE the names and associated events for all the active
     956              :    plugins.  */
     957              : 
     958              : DEBUG_FUNCTION void
     959            0 : dump_active_plugins (FILE *file)
     960              : {
     961            0 :   int event;
     962              : 
     963            0 :   if (!plugins_active_p ())
     964              :     return;
     965              : 
     966            0 :   fprintf (file, FMT_FOR_PLUGIN_EVENT " | %s\n", _("Event"), _("Plugins"));
     967            0 :   for (event = PLUGIN_PASS_MANAGER_SETUP; event < event_last; event++)
     968            0 :     if (plugin_callbacks[event])
     969              :       {
     970            0 :         struct callback_info *ci;
     971              : 
     972            0 :         fprintf (file, FMT_FOR_PLUGIN_EVENT " |", plugin_event_name[event]);
     973              : 
     974            0 :         for (ci = plugin_callbacks[event]; ci; ci = ci->next)
     975            0 :           fprintf (file, " %s", ci->plugin_name);
     976              : 
     977            0 :         putc ('\n', file);
     978              :       }
     979              : }
     980              : 
     981              : 
     982              : /* Dump active plugins to stderr.  */
     983              : 
     984              : DEBUG_FUNCTION void
     985            0 : debug_active_plugins (void)
     986              : {
     987            0 :   dump_active_plugins (stderr);
     988            0 : }
     989              : 
     990              : /* Give a warning if plugins are present, before an ICE message asking
     991              :    to submit a bug report.  */
     992              : 
     993              : void
     994           39 : warn_if_plugins (void)
     995              : {
     996           39 :   if (plugins_active_p ())
     997              :     {
     998            0 :       fnotice (stderr, "*** WARNING *** there are active plugins, do not report"
     999              :                " this as a bug unless you can reproduce it without enabling"
    1000              :                " any plugins.\n");
    1001            0 :       dump_active_plugins (stderr);
    1002              :     }
    1003              : 
    1004           39 : }
    1005              : 
    1006              : /* The default version check. Compares every field in VERSION. */
    1007              : 
    1008              : bool
    1009          188 : plugin_default_version_check (struct plugin_gcc_version *gcc_version,
    1010              :                               struct plugin_gcc_version *plugin_version)
    1011              : {
    1012          188 :   if (!gcc_version || !plugin_version)
    1013              :     return false;
    1014              : 
    1015          188 :   if (strcmp (gcc_version->basever, plugin_version->basever))
    1016              :     return false;
    1017          188 :   if (strcmp (gcc_version->datestamp, plugin_version->datestamp))
    1018              :     return false;
    1019          188 :   if (strcmp (gcc_version->devphase, plugin_version->devphase))
    1020              :     return false;
    1021          188 :   if (strcmp (gcc_version->revision, plugin_version->revision))
    1022              :     return false;
    1023          188 :   if (strcmp (gcc_version->configuration_arguments,
    1024              :               plugin_version->configuration_arguments))
    1025            0 :     return false;
    1026              :   return true;
    1027              : }
    1028              : 
    1029              : 
    1030              : /* Return the current value of event_last, so that plugins which provide
    1031              :    additional functionality for events for the benefit of high-level plugins
    1032              :    know how many valid entries plugin_event_name holds.  */
    1033              : 
    1034              : int
    1035            0 : get_event_last (void)
    1036              : {
    1037            0 :   return event_last;
    1038              : }
    1039              : 
    1040              : 
    1041              : /* Retrieve the default plugin directory.  The gcc driver should have passed
    1042              :    it as -iplugindir <dir> to the cc1 program, and it is queryable through the
    1043              :    -print-file-name=plugin option to gcc.  */
    1044              : const char*
    1045          111 : default_plugin_dir_name (void)
    1046              : {
    1047          111 :   if (!plugindir_string)
    1048            0 :     fatal_error (input_location,
    1049              :                  "%<-iplugindir%> option not passed from the gcc driver");
    1050          111 :   return plugindir_string;
    1051              : }
        

Generated by: LCOV version 2.4-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.