65e9770205c0e982b93a40aa978396900e1e03ea
[platform/upstream/gcc.git] / libcc1 / libcp1.cc
1 /* The library used by gdb.
2    Copyright (C) 2014-2021 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 it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation; either version 3, or (at your option) any later
9 version.
10
11 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 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 #include <cc1plugin-config.h>
21 #include <vector>
22 #include <string>
23 #include <sys/socket.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 #include <sys/wait.h>
27 #include <stdio.h>
28 #include <errno.h>
29 #include <sys/stat.h>
30 #include <stdlib.h>
31 #include "marshall-cp.hh"
32 #include "rpc.hh"
33 #include "connection.hh"
34 #include "names.hh"
35 #include "callbacks.hh"
36 #include "libiberty.h"
37 #include "compiler-name.hh"
38 #include "compiler.hh"
39 #include "gdbctx.hh"
40
41 // The C compiler context that we hand back to our caller.
42 struct libcp1 : public cc1_plugin::base_gdb_plugin<gcc_cp_context>
43 {
44   libcp1 (const gcc_base_vtable *, const gcc_cp_fe_vtable *);
45
46   gcc_cp_oracle_function *binding_oracle = nullptr;
47   gcc_cp_symbol_address_function *address_oracle = nullptr;
48   gcc_cp_enter_leave_user_expr_scope_function *enter_scope = nullptr;
49   gcc_cp_enter_leave_user_expr_scope_function *leave_scope = nullptr;
50   void *oracle_datum = nullptr;
51 };
52
53 libcp1::libcp1 (const gcc_base_vtable *v, const gcc_cp_fe_vtable *cv)
54   : cc1_plugin::base_gdb_plugin<gcc_cp_context> (v)
55 {
56   cp_ops = cv;
57 }
58
59 \f
60
61 // Enclose these functions in an anonymous namespace because they
62 // shouldn't be exported, but they can't be static because they're
63 // used as template arguments.
64 namespace {
65   // This is a wrapper function that is called by the RPC system and
66   // that then forwards the call to the library user.  Note that the
67   // return value is not used; the type cannot be 'void' due to
68   // limitations in our simple RPC.
69   int
70   cp_call_binding_oracle (cc1_plugin::connection *conn,
71                        enum gcc_cp_oracle_request request,
72                        const char *identifier)
73   {
74     libcp1 *self = (libcp1 *) (((libcp1::local_connection *) conn)->back_ptr);
75
76     self->binding_oracle (self->oracle_datum, self, request, identifier);
77     return 1;
78   }
79
80   // This is a wrapper function that is called by the RPC system and
81   // that then forwards the call to the library user.
82   gcc_address
83   cp_call_symbol_address (cc1_plugin::connection *conn, const char *identifier)
84   {
85     libcp1 *self = (libcp1 *) (((libcp1::local_connection *) conn)->back_ptr);
86
87     return self->address_oracle (self->oracle_datum, self, identifier);
88   }
89
90   int
91   cp_call_enter_scope (cc1_plugin::connection *conn)
92   {
93     libcp1 *self = (libcp1 *) (((libcp1::local_connection *) conn)->back_ptr);
94
95     self->enter_scope (self->oracle_datum, self);
96     return 1;
97   }
98
99   int
100   cp_call_leave_scope (cc1_plugin::connection *conn)
101   {
102     libcp1 *self = (libcp1 *) (((libcp1::local_connection *) conn)->back_ptr);
103
104     self->leave_scope (self->oracle_datum, self);
105     return 1;
106   }
107 } /* anonymous namespace */
108
109 \f
110
111 static void
112 set_callbacks (struct gcc_cp_context *s,
113                gcc_cp_oracle_function *binding_oracle,
114                gcc_cp_symbol_address_function *address_oracle,
115                gcc_cp_enter_leave_user_expr_scope_function *enter_scope,
116                gcc_cp_enter_leave_user_expr_scope_function *leave_scope,
117                void *datum)
118 {
119   libcp1 *self = (libcp1 *) s;
120
121   self->binding_oracle = binding_oracle;
122   self->address_oracle = address_oracle;
123   self->enter_scope = enter_scope;
124   self->leave_scope = leave_scope;
125   self->oracle_datum = datum;
126 }
127
128 static const struct gcc_cp_fe_vtable cp_vtable =
129 {
130   GCC_CP_FE_VERSION_0,
131   set_callbacks,
132
133 #define GCC_METHOD0(R, N) \
134   cc1_plugin::rpc<gcc_cp_context, R, cc1_plugin::cp::N>,
135 #define GCC_METHOD1(R, N, A) \
136   cc1_plugin::rpc<gcc_cp_context, R, cc1_plugin::cp::N, A>,
137 #define GCC_METHOD2(R, N, A, B) \
138   cc1_plugin::rpc<gcc_cp_context, R, cc1_plugin::cp::N, A, B>,
139 #define GCC_METHOD3(R, N, A, B, C) \
140   cc1_plugin::rpc<gcc_cp_context, R, cc1_plugin::cp::N, A, B, C>,
141 #define GCC_METHOD4(R, N, A, B, C, D) \
142   cc1_plugin::rpc<gcc_cp_context, R, cc1_plugin::cp::N, A, B, C, D>,
143 #define GCC_METHOD5(R, N, A, B, C, D, E) \
144   cc1_plugin::rpc<gcc_cp_context, R, cc1_plugin::cp::N, A, B, C, D, E>,
145 #define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \
146   cc1_plugin::rpc<gcc_cp_context, R, cc1_plugin::cp::N, A, B, C, D, E, F, G>,
147
148 #include "gcc-cp-fe.def"
149
150 #undef GCC_METHOD0
151 #undef GCC_METHOD1
152 #undef GCC_METHOD2
153 #undef GCC_METHOD3
154 #undef GCC_METHOD4
155 #undef GCC_METHOD5
156 #undef GCC_METHOD7
157 };
158
159 \f
160
161 static void
162 libcp1_set_verbose (struct gcc_base_context *s, int /* bool */ verbose)
163 {
164   libcp1 *self = (libcp1 *) s;
165
166   self->set_verbose (verbose != 0);
167 }
168
169 static char *
170 libcp1_set_arguments (struct gcc_base_context *s,
171                       int argc, char **argv)
172 {
173   libcp1 *self = (libcp1 *) s;
174
175   std::string compiler;
176   char *errmsg = self->compilerp->find (CP_COMPILER_NAME, compiler);
177   if (errmsg != NULL)
178     return errmsg;
179
180   self->args.push_back (compiler);
181
182   for (int i = 0; i < argc; ++i)
183     self->args.push_back (argv[i]);
184
185   return NULL;
186 }
187
188 static char *
189 libcp1_set_triplet_regexp (struct gcc_base_context *s,
190                            const char *triplet_regexp)
191 {
192   libcp1 *self = (libcp1 *) s;
193
194   self->compilerp.reset
195     (new cc1_plugin::compiler_triplet_regexp (self->verbose,
196                                               triplet_regexp));
197   return NULL;
198 }
199
200 static char *
201 libcp1_set_driver_filename (struct gcc_base_context *s,
202                             const char *driver_filename)
203 {
204   libcp1 *self = (libcp1 *) s;
205
206   self->compilerp.reset
207     (new cc1_plugin::compiler_driver_filename (self->verbose,
208                                                driver_filename));
209   return NULL;
210 }
211
212 static char *
213 libcp1_set_arguments_v0 (struct gcc_base_context *s,
214                          const char *triplet_regexp,
215                          int argc, char **argv)
216 {
217   char *errmsg = libcp1_set_triplet_regexp (s, triplet_regexp);
218   if (errmsg != NULL)
219     return errmsg;
220
221   return libcp1_set_arguments (s, argc, argv);
222 }
223
224 static void
225 libcp1_set_source_file (struct gcc_base_context *s,
226                          const char *file)
227 {
228   libcp1 *self = (libcp1 *) s;
229
230   self->source_file = file;
231 }
232
233 static void
234 libcp1_set_print_callback (struct gcc_base_context *s,
235                             void (*print_function) (void *datum,
236                                                     const char *message),
237                             void *datum)
238 {
239   libcp1 *self = (libcp1 *) s;
240
241   self->print_function = print_function;
242   self->print_datum = datum;
243 }
244
245 static int
246 fork_exec (libcp1 *self, char **argv, int spair_fds[2], int stderr_fds[2])
247 {
248   pid_t child_pid = fork ();
249
250   if (child_pid == -1)
251     {
252       close (spair_fds[0]);
253       close (spair_fds[1]);
254       close (stderr_fds[0]);
255       close (stderr_fds[1]);
256       return 0;
257     }
258
259   if (child_pid == 0)
260     {
261       // Child.
262       dup2 (stderr_fds[1], 1);
263       dup2 (stderr_fds[1], 2);
264       close (stderr_fds[0]);
265       close (stderr_fds[1]);
266       close (spair_fds[0]);
267
268       execvp (argv[0], argv);
269       _exit (127);
270     }
271   else
272     {
273       // Parent.
274       close (spair_fds[1]);
275       close (stderr_fds[1]);
276
277       cc1_plugin::status result = cc1_plugin::FAIL;
278       if (self->connection->send ('H')
279           && ::cc1_plugin::marshall (self->connection.get (),
280                                      GCC_CP_FE_VERSION_0))
281         result = self->connection->wait_for_query ();
282
283       close (spair_fds[0]);
284       close (stderr_fds[0]);
285
286       while (true)
287         {
288           int status;
289
290           if (waitpid (child_pid, &status, 0) == -1)
291             {
292               if (errno != EINTR)
293                 return 0;
294             }
295
296           if (!WIFEXITED (status) || WEXITSTATUS (status) != 0)
297             return 0;
298           break;
299         }
300
301       if (!result)
302         return 0;
303       return 1;
304     }
305 }
306
307 static int
308 libcp1_compile (struct gcc_base_context *s,
309                 const char *filename)
310 {
311   libcp1 *self = (libcp1 *) s;
312
313   int fds[2];
314   if (socketpair (AF_UNIX, SOCK_STREAM, 0, fds) != 0)
315     {
316       self->print ("could not create socketpair\n");
317       return 0;
318     }
319
320   int stderr_fds[2];
321   if (pipe (stderr_fds) != 0)
322     {
323       self->print ("could not create pipe\n");
324       close (fds[0]);
325       close (fds[1]);
326       return 0;
327     }
328
329   self->args.push_back ("-fplugin=libcp1plugin");
330   char buf[100];
331   if (snprintf (buf, sizeof (buf), "-fplugin-arg-libcp1plugin-fd=%d", fds[1])
332       >= (long) sizeof (buf))
333     abort ();
334   self->args.push_back (buf);
335
336   self->args.push_back (self->source_file);
337   self->args.push_back ("-c");
338   self->args.push_back ("-o");
339   self->args.push_back (filename);
340   if (self->verbose)
341     self->args.push_back ("-v");
342
343   self->set_connection (fds[0], stderr_fds[0]);
344
345   cc1_plugin::callback_ftype *fun
346     = cc1_plugin::callback<int,
347                            enum gcc_cp_oracle_request,
348                            const char *,
349                            cp_call_binding_oracle>;
350   self->connection->add_callback ("binding_oracle", fun);
351
352   fun = cc1_plugin::callback<gcc_address,
353                              const char *,
354                              cp_call_symbol_address>;
355   self->connection->add_callback ("address_oracle", fun);
356
357   fun = cc1_plugin::callback<int,
358                              cp_call_enter_scope>;
359   self->connection->add_callback ("enter_scope", fun);
360
361   fun = cc1_plugin::callback<int,
362                              cp_call_leave_scope>;
363   self->connection->add_callback ("leave_scope", fun);
364
365   char **argv = new (std::nothrow) char *[self->args.size () + 1];
366   if (argv == NULL)
367     return 0;
368
369   for (unsigned int i = 0; i < self->args.size (); ++i)
370     argv[i] = const_cast<char *> (self->args[i].c_str ());
371   argv[self->args.size ()] = NULL;
372
373   return fork_exec (self, argv, fds, stderr_fds);
374 }
375
376 static int
377 libcp1_compile_v0 (struct gcc_base_context *s, const char *filename,
378                    int verbose)
379 {
380   libcp1_set_verbose (s, verbose);
381   return libcp1_compile (s, filename);
382 }
383
384 static void
385 libcp1_destroy (struct gcc_base_context *s)
386 {
387   libcp1 *self = (libcp1 *) s;
388
389   delete self;
390 }
391
392 static const struct gcc_base_vtable vtable =
393 {
394   GCC_FE_VERSION_1,
395   libcp1_set_arguments_v0,
396   libcp1_set_source_file,
397   libcp1_set_print_callback,
398   libcp1_compile_v0,
399   libcp1_destroy,
400   libcp1_set_verbose,
401   libcp1_compile,
402   libcp1_set_arguments,
403   libcp1_set_triplet_regexp,
404   libcp1_set_driver_filename,
405 };
406
407 extern "C" gcc_cp_fe_context_function gcc_cp_fe_context;
408
409 #ifdef __GNUC__
410 #pragma GCC visibility push(default)
411 #endif
412
413 extern "C"
414 struct gcc_cp_context *
415 gcc_cp_fe_context (enum gcc_base_api_version base_version,
416                     enum gcc_cp_api_version cp_version)
417 {
418   if ((base_version != GCC_FE_VERSION_0 && base_version != GCC_FE_VERSION_1)
419       || cp_version != GCC_CP_FE_VERSION_0)
420     return NULL;
421
422   return new libcp1 (&vtable, &cp_vtable);
423 }