1 /* The library used by gdb.
2 Copyright (C) 2014-2021 Free Software Foundation, Inc.
4 This file is part of GCC.
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
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
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/>. */
20 #include <cc1plugin-config.h>
23 #include <sys/socket.h>
24 #include <sys/types.h>
32 #include "marshall-cp.hh"
34 #include "connection.hh"
36 #include "callbacks.hh"
37 #include "libiberty.h"
39 #include "findcomp.hh"
40 #include "compiler-name.hh"
45 class libcp1_connection
;
47 // The C compiler context that we hand back to our caller.
48 struct libcp1
: public gcc_cp_context
50 libcp1 (const gcc_base_vtable
*, const gcc_cp_fe_vtable
*);
52 // A convenience function to print something.
53 void print (const char *str
)
55 this->print_function (this->print_datum
, str
);
58 std::unique_ptr
<libcp1_connection
> connection
;
60 gcc_cp_oracle_function
*binding_oracle
;
61 gcc_cp_symbol_address_function
*address_oracle
;
62 gcc_cp_enter_leave_user_expr_scope_function
*enter_scope
;
63 gcc_cp_enter_leave_user_expr_scope_function
*leave_scope
;
66 void (*print_function
) (void *datum
, const char *message
);
69 std::vector
<std::string
> args
;
70 std::string source_file
;
72 /* Non-zero as an equivalent to gcc driver option "-v". */
75 /* Compiler to set by set_triplet_regexp or set_driver_filename. */
81 compiler (libcp1
*self
) : self_ (self
)
84 virtual char *find (std::string
&compiler
) const;
90 std::unique_ptr
<compiler
> compilerp
;
92 /* Compiler to set by set_triplet_regexp. */
93 class compiler_triplet_regexp
: public compiler
96 std::string triplet_regexp_
;
98 char *find (std::string
&compiler
) const override
;
99 compiler_triplet_regexp (libcp1
*self
, std::string triplet_regexp
)
100 : compiler (self
), triplet_regexp_ (triplet_regexp
)
103 virtual ~compiler_triplet_regexp ()
108 /* Compiler to set by set_driver_filename. */
109 class compiler_driver_filename
: public compiler
112 std::string driver_filename_
;
114 char *find (std::string
&compiler
) const override
;
115 compiler_driver_filename (libcp1
*self
, std::string driver_filename
)
116 : compiler (self
), driver_filename_ (driver_filename
)
119 virtual ~compiler_driver_filename ()
125 // A local subclass of connection that holds a back-pointer to the
126 // gcc_c_context object that we provide to our caller.
127 class libcp1_connection
: public cc1_plugin::connection
131 libcp1_connection (int fd
, int aux_fd
, libcp1
*b
)
132 : connection (fd
, aux_fd
),
137 void print (const char *buf
) override
139 back_ptr
->print (buf
);
145 libcp1::libcp1 (const gcc_base_vtable
*v
,
146 const gcc_cp_fe_vtable
*cv
)
147 : binding_oracle (NULL
),
148 address_oracle (NULL
),
150 print_function (NULL
),
155 compilerp (new libcp1::compiler (this))
163 // Enclose these functions in an anonymous namespace because they
164 // shouldn't be exported, but they can't be static because they're
165 // used as template arguments.
167 // This is a wrapper function that is called by the RPC system and
168 // that then forwards the call to the library user. Note that the
169 // return value is not used; the type cannot be 'void' due to
170 // limitations in our simple RPC.
172 cp_call_binding_oracle (cc1_plugin::connection
*conn
,
173 enum gcc_cp_oracle_request request
,
174 const char *identifier
)
176 libcp1
*self
= ((libcp1_connection
*) conn
)->back_ptr
;
178 self
->binding_oracle (self
->oracle_datum
, self
, request
, identifier
);
182 // This is a wrapper function that is called by the RPC system and
183 // that then forwards the call to the library user.
185 cp_call_symbol_address (cc1_plugin::connection
*conn
, const char *identifier
)
187 libcp1
*self
= ((libcp1_connection
*) conn
)->back_ptr
;
189 return self
->address_oracle (self
->oracle_datum
, self
, identifier
);
193 cp_call_enter_scope (cc1_plugin::connection
*conn
)
195 libcp1
*self
= ((libcp1_connection
*) conn
)->back_ptr
;
197 self
->enter_scope (self
->oracle_datum
, self
);
202 cp_call_leave_scope (cc1_plugin::connection
*conn
)
204 libcp1
*self
= ((libcp1_connection
*) conn
)->back_ptr
;
206 self
->leave_scope (self
->oracle_datum
, self
);
209 } /* anonymous namespace */
214 set_callbacks (struct gcc_cp_context
*s
,
215 gcc_cp_oracle_function
*binding_oracle
,
216 gcc_cp_symbol_address_function
*address_oracle
,
217 gcc_cp_enter_leave_user_expr_scope_function
*enter_scope
,
218 gcc_cp_enter_leave_user_expr_scope_function
*leave_scope
,
221 libcp1
*self
= (libcp1
*) s
;
223 self
->binding_oracle
= binding_oracle
;
224 self
->address_oracle
= address_oracle
;
225 self
->enter_scope
= enter_scope
;
226 self
->leave_scope
= leave_scope
;
227 self
->oracle_datum
= datum
;
230 // Instances of this rpc<> template function are installed into the
231 // "cp_vtable". These functions are parameterized by type and method
232 // name and forward the call via the connection.
234 template<typename R
, const char *&NAME
, typename
... Arg
>
235 R
rpc (struct gcc_cp_context
*s
, Arg
... rest
)
237 libcp1
*self
= (libcp1
*) s
;
240 if (!cc1_plugin::call (self
->connection
.get (), NAME
, &result
, rest
...))
245 static const struct gcc_cp_fe_vtable cp_vtable
=
250 #define GCC_METHOD0(R, N) \
251 rpc<R, cc1_plugin::cp::N>,
252 #define GCC_METHOD1(R, N, A) \
253 rpc<R, cc1_plugin::cp::N, A>,
254 #define GCC_METHOD2(R, N, A, B) \
255 rpc<R, cc1_plugin::cp::N, A, B>,
256 #define GCC_METHOD3(R, N, A, B, C) \
257 rpc<R, cc1_plugin::cp::N, A, B, C>,
258 #define GCC_METHOD4(R, N, A, B, C, D) \
259 rpc<R, cc1_plugin::cp::N, A, B, C, D>,
260 #define GCC_METHOD5(R, N, A, B, C, D, E) \
261 rpc<R, cc1_plugin::cp::N, A, B, C, D, E>,
262 #define GCC_METHOD7(R, N, A, B, C, D, E, F, G) \
263 rpc<R, cc1_plugin::cp::N, A, B, C, D, E, F, G>,
265 #include "gcc-cp-fe.def"
278 // Construct an appropriate regexp to match the compiler name.
280 make_regexp (const char *triplet_regexp
, const char *compiler
)
282 std::stringstream buf
;
284 buf
<< "^" << triplet_regexp
<< "-";
286 // Quote the compiler name in case it has something funny in it.
287 for (const char *p
= compiler
; *p
; ++p
)
314 libcp1_set_verbose (struct gcc_base_context
*s
, int /* bool */ verbose
)
316 libcp1
*self
= (libcp1
*) s
;
318 self
->verbose
= verbose
!= 0;
322 libcp1::compiler::find (std::string
&compiler ATTRIBUTE_UNUSED
) const
324 return xstrdup (_("Compiler has not been specified"));
328 libcp1::compiler_triplet_regexp::find (std::string
&compiler
) const
330 std::string rx
= make_regexp (triplet_regexp_
.c_str (), CP_COMPILER_NAME
);
332 fprintf (stderr
, _("searching for compiler matching regex %s\n"),
335 int code
= regcomp (&triplet
, rx
.c_str (), REG_EXTENDED
| REG_NOSUB
);
338 size_t len
= regerror (code
, &triplet
, NULL
, 0);
341 regerror (code
, &triplet
, err
, len
);
343 return concat ("Could not compile regexp \"",
350 if (!find_compiler (triplet
, &compiler
))
353 return concat ("Could not find a compiler matching \"",
360 fprintf (stderr
, _("found compiler %s\n"), compiler
.c_str());
365 libcp1::compiler_driver_filename::find (std::string
&compiler
) const
367 // Simulate fnotice by fprintf.
369 fprintf (stderr
, _("using explicit compiler filename %s\n"),
370 driver_filename_
.c_str());
371 compiler
= driver_filename_
;
376 libcp1_set_arguments (struct gcc_base_context
*s
,
377 int argc
, char **argv
)
379 libcp1
*self
= (libcp1
*) s
;
381 std::string compiler
;
382 char *errmsg
= self
->compilerp
->find (compiler
);
386 self
->args
.push_back (compiler
);
388 for (int i
= 0; i
< argc
; ++i
)
389 self
->args
.push_back (argv
[i
]);
395 libcp1_set_triplet_regexp (struct gcc_base_context
*s
,
396 const char *triplet_regexp
)
398 libcp1
*self
= (libcp1
*) s
;
400 self
->compilerp
.reset (new libcp1::compiler_triplet_regexp (self
,
406 libcp1_set_driver_filename (struct gcc_base_context
*s
,
407 const char *driver_filename
)
409 libcp1
*self
= (libcp1
*) s
;
411 self
->compilerp
.reset (new libcp1::compiler_driver_filename (self
,
417 libcp1_set_arguments_v0 (struct gcc_base_context
*s
,
418 const char *triplet_regexp
,
419 int argc
, char **argv
)
421 char *errmsg
= libcp1_set_triplet_regexp (s
, triplet_regexp
);
425 return libcp1_set_arguments (s
, argc
, argv
);
429 libcp1_set_source_file (struct gcc_base_context
*s
,
432 libcp1
*self
= (libcp1
*) s
;
434 self
->source_file
= file
;
438 libcp1_set_print_callback (struct gcc_base_context
*s
,
439 void (*print_function
) (void *datum
,
440 const char *message
),
443 libcp1
*self
= (libcp1
*) s
;
445 self
->print_function
= print_function
;
446 self
->print_datum
= datum
;
450 fork_exec (libcp1
*self
, char **argv
, int spair_fds
[2], int stderr_fds
[2])
452 pid_t child_pid
= fork ();
456 close (spair_fds
[0]);
457 close (spair_fds
[1]);
458 close (stderr_fds
[0]);
459 close (stderr_fds
[1]);
466 dup2 (stderr_fds
[1], 1);
467 dup2 (stderr_fds
[1], 2);
468 close (stderr_fds
[0]);
469 close (stderr_fds
[1]);
470 close (spair_fds
[0]);
472 execvp (argv
[0], argv
);
478 close (spair_fds
[1]);
479 close (stderr_fds
[1]);
481 cc1_plugin::status result
= cc1_plugin::FAIL
;
482 if (self
->connection
->send ('H')
483 && ::cc1_plugin::marshall (self
->connection
.get (),
484 GCC_CP_FE_VERSION_0
))
485 result
= self
->connection
->wait_for_query ();
487 close (spair_fds
[0]);
488 close (stderr_fds
[0]);
494 if (waitpid (child_pid
, &status
, 0) == -1)
500 if (!WIFEXITED (status
) || WEXITSTATUS (status
) != 0)
512 libcp1_compile (struct gcc_base_context
*s
,
513 const char *filename
)
515 libcp1
*self
= (libcp1
*) s
;
518 if (socketpair (AF_UNIX
, SOCK_STREAM
, 0, fds
) != 0)
520 self
->print ("could not create socketpair\n");
525 if (pipe (stderr_fds
) != 0)
527 self
->print ("could not create pipe\n");
533 self
->args
.push_back ("-fplugin=libcp1plugin");
535 if (snprintf (buf
, sizeof (buf
), "-fplugin-arg-libcp1plugin-fd=%d", fds
[1])
536 >= (long) sizeof (buf
))
538 self
->args
.push_back (buf
);
540 self
->args
.push_back (self
->source_file
);
541 self
->args
.push_back ("-c");
542 self
->args
.push_back ("-o");
543 self
->args
.push_back (filename
);
545 self
->args
.push_back ("-v");
547 self
->connection
.reset (new libcp1_connection (fds
[0], stderr_fds
[0], self
));
549 cc1_plugin::callback_ftype
*fun
550 = cc1_plugin::callback
<int,
551 enum gcc_cp_oracle_request
,
553 cp_call_binding_oracle
>;
554 self
->connection
->add_callback ("binding_oracle", fun
);
556 fun
= cc1_plugin::callback
<gcc_address
,
558 cp_call_symbol_address
>;
559 self
->connection
->add_callback ("address_oracle", fun
);
561 fun
= cc1_plugin::callback
<int,
562 cp_call_enter_scope
>;
563 self
->connection
->add_callback ("enter_scope", fun
);
565 fun
= cc1_plugin::callback
<int,
566 cp_call_leave_scope
>;
567 self
->connection
->add_callback ("leave_scope", fun
);
569 char **argv
= new (std::nothrow
) char *[self
->args
.size () + 1];
573 for (unsigned int i
= 0; i
< self
->args
.size (); ++i
)
574 argv
[i
] = const_cast<char *> (self
->args
[i
].c_str ());
575 argv
[self
->args
.size ()] = NULL
;
577 return fork_exec (self
, argv
, fds
, stderr_fds
);
581 libcp1_compile_v0 (struct gcc_base_context
*s
, const char *filename
,
584 libcp1_set_verbose (s
, verbose
);
585 return libcp1_compile (s
, filename
);
589 libcp1_destroy (struct gcc_base_context
*s
)
591 libcp1
*self
= (libcp1
*) s
;
596 static const struct gcc_base_vtable vtable
=
599 libcp1_set_arguments_v0
,
600 libcp1_set_source_file
,
601 libcp1_set_print_callback
,
606 libcp1_set_arguments
,
607 libcp1_set_triplet_regexp
,
608 libcp1_set_driver_filename
,
611 extern "C" gcc_cp_fe_context_function gcc_cp_fe_context
;
614 #pragma GCC visibility push(default)
618 struct gcc_cp_context
*
619 gcc_cp_fe_context (enum gcc_base_api_version base_version
,
620 enum gcc_cp_api_version cp_version
)
622 if ((base_version
!= GCC_FE_VERSION_0
&& base_version
!= GCC_FE_VERSION_1
)
623 || cp_version
!= GCC_CP_FE_VERSION_0
)
626 return new libcp1 (&vtable
, &cp_vtable
);