diff options
author | Tom Tromey <tom@tromey.com> | 2021-05-04 15:26:58 -0600 |
---|---|---|
committer | Tom Tromey <tom@tromey.com> | 2021-05-05 00:06:18 -0600 |
commit | a8deb8323b98fbf4c4779de4b326de72ba22469b (patch) | |
tree | 6e1b3439add29c8ba76b3e5750d39e2bbcc7a8c4 /libcc1/gdbctx.hh | |
parent | b65c0bcbe13b2b56a1e84856856548f2a29ada7e (diff) | |
download | gcc-a8deb8323b98fbf4c4779de4b326de72ba22469b.zip gcc-a8deb8323b98fbf4c4779de4b326de72ba22469b.tar.gz gcc-a8deb8323b98fbf4c4779de4b326de72ba22469b.tar.bz2 |
libcc1: share the GCC interface code
Both the C and C++ side of the GDB plugin in libcc1 share a lot of
code relating to the base GCC interface. It was all copy-and-pasted,
but is essentially identical between the two. This is by design, as
the base GCC API is intended to be shared.
This patch merges the implementations into base_gdb_plugin, which was
introduced earlier for this purpose.
libcc1
* libcp1.cc (libcp1): Change parameters. Update.
(libcp1_set_verbose, libcp1_set_arguments)
(libcp1_set_triplet_regexp, libcp1_set_driver_filename)
(libcp1_set_source_file, libcp1_set_print_callback, fork_exec)
(libcp1_compile, libcp1_destroy, vtable): Remove.
(libcp1::add_callbacks): New method, extracted from
libcp1_compile.
(gcc_c_fe_context): Update.
* libcc1.cc (libcc1): Change parameters. Update.
(libcc1_set_verbose, libcc1_set_arguments)
(libcc1_set_triplet_regexp, libcc1_set_driver_filename)
(libcc1_set_source_file, libcc1_set_print_callback, fork_exec)
(libcc1_compile, libcc1_destroy, vtable): Remove.
(libcc1::add_callbacks): New method, extracted from
libcc1_compile.
(gcc_c_fe_context): Update.
* gdbctx.hh (base_gdb_plugin): Change parameters.
(~base_gdb_plugin): New.
<add_callbacks>: New virtual method.
<plugin_name, fe_version, compiler_name, vtable>: New members.
(get_self, do_set_verbose, do_set_arguments)
(do_set_triplet_regexp, do_set_driver_filename)
(do_set_arguments_v0, do_set_source_file, do_set_print_callback)
(fork_exec, do_compile, do_compile_v0, do_destroy): New methods.
Diffstat (limited to 'libcc1/gdbctx.hh')
-rw-r--r-- | libcc1/gdbctx.hh | 253 |
1 files changed, 251 insertions, 2 deletions
diff --git a/libcc1/gdbctx.hh b/libcc1/gdbctx.hh index 1c8d87d..4a48381 100644 --- a/libcc1/gdbctx.hh +++ b/libcc1/gdbctx.hh @@ -23,16 +23,38 @@ along with GCC; see the file COPYING3. If not see namespace cc1_plugin { // The compiler context that we hand back to our caller. + // Due to this, the entire implementation is in this header. template<typename T> struct base_gdb_plugin : public T { - explicit base_gdb_plugin (const gcc_base_vtable *v) + base_gdb_plugin (const char *plugin_name_, const char *base_name, + int version) : verbose (false), + plugin_name (plugin_name_), + fe_version (version), + compiler_name (base_name), compilerp (new compiler (verbose)) { - this->base.ops = v; + vtable = + { + GCC_FE_VERSION_1, + do_set_arguments_v0, + do_set_source_file, + do_set_print_callback, + do_compile_v0, + do_destroy, + do_set_verbose, + do_compile, + do_set_arguments, + do_set_triplet_regexp, + do_set_driver_filename, + }; + + this->base.ops = &vtable; } + virtual ~base_gdb_plugin () = default; + // A convenience function to print something. void print (const char *str) { @@ -53,6 +75,10 @@ namespace cc1_plugin connection.reset (new local_connection (fd, aux_fd, this)); } + // This is called just before compilation begins. It should set + // any needed callbacks on the connection. + virtual void add_callbacks () = 0; + // A local subclass of connection that holds a back-pointer to the // context object that we provide to our caller. class local_connection : public cc1_plugin::connection @@ -84,7 +110,230 @@ namespace cc1_plugin /* Non-zero as an equivalent to gcc driver option "-v". */ bool verbose; + const char *plugin_name; + int fe_version; + + const char *compiler_name; std::unique_ptr<cc1_plugin::compiler> compilerp; + + private: + + struct gcc_base_vtable vtable; + + static inline base_gdb_plugin<T> * + get_self (gcc_base_context *s) + { + T *sub = (T *) s; + return static_cast<base_gdb_plugin<T> *> (sub); + } + + static void + do_set_verbose (struct gcc_base_context *s, int /* bool */ verbose) + { + base_gdb_plugin<T> *self = get_self (s); + + self->set_verbose (verbose != 0); + } + + static char * + do_set_arguments (struct gcc_base_context *s, + int argc, char **argv) + { + base_gdb_plugin<T> *self = get_self (s); + + std::string compiler; + char *errmsg = self->compilerp->find (self->compiler_name, compiler); + if (errmsg != NULL) + return errmsg; + + self->args.push_back (compiler); + + for (int i = 0; i < argc; ++i) + self->args.push_back (argv[i]); + + return NULL; + } + + static char * + do_set_triplet_regexp (struct gcc_base_context *s, + const char *triplet_regexp) + { + base_gdb_plugin<T> *self = get_self (s); + + self->compilerp.reset + (new cc1_plugin::compiler_triplet_regexp (self->verbose, + triplet_regexp)); + return NULL; + } + + static char * + do_set_driver_filename (struct gcc_base_context *s, + const char *driver_filename) + { + base_gdb_plugin<T> *self = get_self (s); + + self->compilerp.reset + (new cc1_plugin::compiler_driver_filename (self->verbose, + driver_filename)); + return NULL; + } + + static char * + do_set_arguments_v0 (struct gcc_base_context *s, + const char *triplet_regexp, + int argc, char **argv) + { + char *errmsg = do_set_triplet_regexp (s, triplet_regexp); + if (errmsg != NULL) + return errmsg; + + return do_set_arguments (s, argc, argv); + } + + static void + do_set_source_file (struct gcc_base_context *s, + const char *file) + { + base_gdb_plugin<T> *self = get_self (s); + + self->source_file = file; + } + + static void + do_set_print_callback (struct gcc_base_context *s, + void (*print_function) (void *datum, + const char *message), + void *datum) + { + base_gdb_plugin<T> *self = get_self (s); + + self->print_function = print_function; + self->print_datum = datum; + } + + int fork_exec (char **argv, int spair_fds[2], int stderr_fds[2]) + { + pid_t child_pid = fork (); + + if (child_pid == -1) + { + close (spair_fds[0]); + close (spair_fds[1]); + close (stderr_fds[0]); + close (stderr_fds[1]); + return 0; + } + + if (child_pid == 0) + { + // Child. + dup2 (stderr_fds[1], 1); + dup2 (stderr_fds[1], 2); + close (stderr_fds[0]); + close (stderr_fds[1]); + close (spair_fds[0]); + + execvp (argv[0], argv); + _exit (127); + } + else + { + // Parent. + close (spair_fds[1]); + close (stderr_fds[1]); + + cc1_plugin::status result = cc1_plugin::FAIL; + if (connection->send ('H') + && ::cc1_plugin::marshall (connection.get (), fe_version)) + result = connection->wait_for_query (); + + close (spair_fds[0]); + close (stderr_fds[0]); + + while (true) + { + int status; + + if (waitpid (child_pid, &status, 0) == -1) + { + if (errno != EINTR) + return 0; + } + + if (!WIFEXITED (status) || WEXITSTATUS (status) != 0) + return 0; + break; + } + + if (!result) + return 0; + return 1; + } + } + + static int + do_compile (struct gcc_base_context *s, + const char *filename) + { + base_gdb_plugin<T> *self = get_self (s); + + int fds[2]; + if (socketpair (AF_UNIX, SOCK_STREAM, 0, fds) != 0) + { + self->print ("could not create socketpair\n"); + return 0; + } + + int stderr_fds[2]; + if (pipe (stderr_fds) != 0) + { + self->print ("could not create pipe\n"); + close (fds[0]); + close (fds[1]); + return 0; + } + + self->args.push_back (std::string ("-fplugin=") + self->plugin_name); + self->args.push_back (std::string ("-fplugin-arg-") + self->plugin_name + + "-fd=" + std::to_string (fds[1])); + + self->args.push_back (self->source_file); + self->args.push_back ("-c"); + self->args.push_back ("-o"); + self->args.push_back (filename); + if (self->verbose) + self->args.push_back ("-v"); + + self->set_connection (fds[0], stderr_fds[0]); + + self->add_callbacks (); + + char **argv = new (std::nothrow) char *[self->args.size () + 1]; + if (argv == NULL) + return 0; + + for (unsigned int i = 0; i < self->args.size (); ++i) + argv[i] = const_cast<char *> (self->args[i].c_str ()); + argv[self->args.size ()] = NULL; + + return self->fork_exec (argv, fds, stderr_fds); + } + + static int + do_compile_v0 (struct gcc_base_context *s, const char *filename, + int verbose) + { + do_set_verbose (s, verbose); + return do_compile (s, filename); + } + + static void + do_destroy (struct gcc_base_context *s) + { + base_gdb_plugin<T> *self = get_self (s); + + delete self; + } }; // Instances of this rpc<> template function are installed into the |