1/* Generic plugin context
2   Copyright (C) 2020-2022 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free
8Software Foundation; either version 3, or (at your option) any later
9version.
10
11GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or
13FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14for more details.
15
16You should have received a copy of the GNU General Public License
17along with GCC; see the file COPYING3.  If not see
18<http://www.gnu.org/licenses/>.  */
19
20#include <cc1plugin-config.h>
21
22#undef PACKAGE_NAME
23#undef PACKAGE_STRING
24#undef PACKAGE_TARNAME
25#undef PACKAGE_VERSION
26
27#include "../gcc/config.h"
28
29#undef PACKAGE_NAME
30#undef PACKAGE_STRING
31#undef PACKAGE_TARNAME
32#undef PACKAGE_VERSION
33
34#include "gcc-plugin.h"
35#include "system.h"
36#include "coretypes.h"
37#include "stringpool.h"
38#include "hash-set.h"
39#include "diagnostic.h"
40#include "langhooks.h"
41#include "langhooks-def.h"
42
43#include "gcc-interface.h"
44
45#include "context.hh"
46#include "marshall.hh"
47
48
49
50#ifdef __GNUC__
51#pragma GCC visibility push(default)
52#endif
53int plugin_is_GPL_compatible;
54#ifdef __GNUC__
55#pragma GCC visibility pop
56#endif
57
58cc1_plugin::plugin_context *cc1_plugin::current_context;
59
60
61
62// This is put into the lang hooks when the plugin starts.
63
64static void
65plugin_print_error_function (diagnostic_context *context, const char *file,
66			     diagnostic_info *diagnostic)
67{
68  if (current_function_decl != NULL_TREE
69      && DECL_NAME (current_function_decl) != NULL_TREE
70      && strcmp (IDENTIFIER_POINTER (DECL_NAME (current_function_decl)),
71		 GCC_FE_WRAPPER_FUNCTION) == 0)
72    return;
73  lhd_print_error_function (context, file, diagnostic);
74}
75
76
77
78location_t
79cc1_plugin::plugin_context::get_location_t (const char *filename,
80					    unsigned int line_number)
81{
82  if (filename == NULL)
83    return UNKNOWN_LOCATION;
84
85  filename = intern_filename (filename);
86  linemap_add (line_table, LC_ENTER, false, filename, line_number);
87  location_t loc = linemap_line_start (line_table, line_number, 0);
88  linemap_add (line_table, LC_LEAVE, false, NULL, 0);
89  return loc;
90}
91
92// Add a file name to FILE_NAMES and return the canonical copy.
93const char *
94cc1_plugin::plugin_context::intern_filename (const char *filename)
95{
96  const char **slot = file_names.find_slot (filename, INSERT);
97  if (*slot == NULL)
98    {
99      /* The file name must live as long as the line map, which
100	 effectively means as long as this compilation.  So, we copy
101	 the string here but never free it.  */
102      *slot = xstrdup (filename);
103    }
104  return *slot;
105}
106
107void
108cc1_plugin::plugin_context::mark ()
109{
110  for (const auto &item : address_map)
111    {
112      ggc_mark (item->decl);
113      ggc_mark (item->address);
114    }
115
116  for (const auto &item : preserved)
117    ggc_mark (&item);
118}
119
120
121
122// Perform GC marking.
123
124static void
125gc_mark (void *, void *)
126{
127  if (cc1_plugin::current_context != NULL)
128    cc1_plugin::current_context->mark ();
129}
130
131void
132cc1_plugin::generic_plugin_init (struct plugin_name_args *plugin_info,
133				 unsigned int version)
134{
135  long fd = -1;
136  for (int i = 0; i < plugin_info->argc; ++i)
137    {
138      if (strcmp (plugin_info->argv[i].key, "fd") == 0)
139	{
140	  char *tail;
141	  errno = 0;
142	  fd = strtol (plugin_info->argv[i].value, &tail, 0);
143	  if (*tail != '\0' || errno != 0)
144	    fatal_error (input_location,
145			 "%s: invalid file descriptor argument to plugin",
146			 plugin_info->base_name);
147	  break;
148	}
149    }
150  if (fd == -1)
151    fatal_error (input_location,
152		 "%s: required plugin argument %<fd%> is missing",
153		 plugin_info->base_name);
154
155  current_context = new plugin_context (fd);
156
157  // Handshake.
158  cc1_plugin::protocol_int h_version;
159  if (!current_context->require ('H')
160      || ! ::cc1_plugin::unmarshall (current_context, &h_version))
161    fatal_error (input_location,
162		 "%s: handshake failed", plugin_info->base_name);
163  if (h_version != version)
164    fatal_error (input_location,
165		 "%s: unknown version in handshake", plugin_info->base_name);
166
167  register_callback (plugin_info->base_name, PLUGIN_GGC_MARKING,
168		     gc_mark, NULL);
169
170  lang_hooks.print_error_function = plugin_print_error_function;
171}
172