| /* Generic plugin context |
| Copyright (C) 2020-2022 Free Software Foundation, Inc. |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify it under |
| the terms of the GNU General Public License as published by the Free |
| Software Foundation; either version 3, or (at your option) any later |
| version. |
| |
| GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
| WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| #include <cc1plugin-config.h> |
| |
| #undef PACKAGE_NAME |
| #undef PACKAGE_STRING |
| #undef PACKAGE_TARNAME |
| #undef PACKAGE_VERSION |
| |
| #include "../gcc/config.h" |
| |
| #undef PACKAGE_NAME |
| #undef PACKAGE_STRING |
| #undef PACKAGE_TARNAME |
| #undef PACKAGE_VERSION |
| |
| #include "gcc-plugin.h" |
| #include "system.h" |
| #include "coretypes.h" |
| #include "stringpool.h" |
| #include "hash-set.h" |
| #include "diagnostic.h" |
| #include "langhooks.h" |
| #include "langhooks-def.h" |
| |
| #include "gcc-interface.h" |
| |
| #include "context.hh" |
| #include "marshall.hh" |
| |
| |
| |
| #ifdef __GNUC__ |
| #pragma GCC visibility push(default) |
| #endif |
| int plugin_is_GPL_compatible; |
| #ifdef __GNUC__ |
| #pragma GCC visibility pop |
| #endif |
| |
| cc1_plugin::plugin_context *cc1_plugin::current_context; |
| |
| |
| |
| // This is put into the lang hooks when the plugin starts. |
| |
| static void |
| plugin_print_error_function (diagnostic_context *context, const char *file, |
| diagnostic_info *diagnostic) |
| { |
| if (current_function_decl != NULL_TREE |
| && DECL_NAME (current_function_decl) != NULL_TREE |
| && strcmp (IDENTIFIER_POINTER (DECL_NAME (current_function_decl)), |
| GCC_FE_WRAPPER_FUNCTION) == 0) |
| return; |
| lhd_print_error_function (context, file, diagnostic); |
| } |
| |
| |
| |
| location_t |
| cc1_plugin::plugin_context::get_location_t (const char *filename, |
| unsigned int line_number) |
| { |
| if (filename == NULL) |
| return UNKNOWN_LOCATION; |
| |
| filename = intern_filename (filename); |
| linemap_add (line_table, LC_ENTER, false, filename, line_number); |
| location_t loc = linemap_line_start (line_table, line_number, 0); |
| linemap_add (line_table, LC_LEAVE, false, NULL, 0); |
| return loc; |
| } |
| |
| // Add a file name to FILE_NAMES and return the canonical copy. |
| const char * |
| cc1_plugin::plugin_context::intern_filename (const char *filename) |
| { |
| const char **slot = file_names.find_slot (filename, INSERT); |
| if (*slot == NULL) |
| { |
| /* The file name must live as long as the line map, which |
| effectively means as long as this compilation. So, we copy |
| the string here but never free it. */ |
| *slot = xstrdup (filename); |
| } |
| return *slot; |
| } |
| |
| void |
| cc1_plugin::plugin_context::mark () |
| { |
| for (const auto &item : address_map) |
| { |
| ggc_mark (item->decl); |
| ggc_mark (item->address); |
| } |
| |
| for (const auto &item : preserved) |
| ggc_mark (&item); |
| } |
| |
| |
| |
| // Perform GC marking. |
| |
| static void |
| gc_mark (void *, void *) |
| { |
| if (cc1_plugin::current_context != NULL) |
| cc1_plugin::current_context->mark (); |
| } |
| |
| void |
| cc1_plugin::generic_plugin_init (struct plugin_name_args *plugin_info, |
| unsigned int version) |
| { |
| long fd = -1; |
| for (int i = 0; i < plugin_info->argc; ++i) |
| { |
| if (strcmp (plugin_info->argv[i].key, "fd") == 0) |
| { |
| char *tail; |
| errno = 0; |
| fd = strtol (plugin_info->argv[i].value, &tail, 0); |
| if (*tail != '\0' || errno != 0) |
| fatal_error (input_location, |
| "%s: invalid file descriptor argument to plugin", |
| plugin_info->base_name); |
| break; |
| } |
| } |
| if (fd == -1) |
| fatal_error (input_location, |
| "%s: required plugin argument %<fd%> is missing", |
| plugin_info->base_name); |
| |
| current_context = new plugin_context (fd); |
| |
| // Handshake. |
| cc1_plugin::protocol_int h_version; |
| if (!current_context->require ('H') |
| || ! ::cc1_plugin::unmarshall (current_context, &h_version)) |
| fatal_error (input_location, |
| "%s: handshake failed", plugin_info->base_name); |
| if (h_version != version) |
| fatal_error (input_location, |
| "%s: unknown version in handshake", plugin_info->base_name); |
| |
| register_callback (plugin_info->base_name, PLUGIN_GGC_MARKING, |
| gc_mark, NULL); |
| |
| lang_hooks.print_error_function = plugin_print_error_function; |
| } |