aboutsummaryrefslogtreecommitdiff
path: root/libcc1/gdbctx.hh
diff options
context:
space:
mode:
Diffstat (limited to 'libcc1/gdbctx.hh')
-rw-r--r--libcc1/gdbctx.hh253
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