1 /* Generic GDB-side plugin
2 Copyright (C) 2020-2023 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 #ifndef CC1_PLUGIN_GDBCTX_HH
21 #define CC1_PLUGIN_GDBCTX_HH
25 // The compiler context that we hand back to our caller.
26 // Due to this, the entire implementation is in this header.
28 struct base_gdb_plugin
: public T
30 base_gdb_plugin (const char *plugin_name_
, const char *base_name
,
33 plugin_name (plugin_name_
),
35 compiler_name (base_name
),
36 compilerp (new compiler (verbose
))
43 do_set_print_callback
,
49 do_set_triplet_regexp
,
50 do_set_driver_filename
,
53 this->base
.ops
= &vtable
;
56 virtual ~base_gdb_plugin () = default;
58 // A convenience function to print something.
59 void print (const char *str
)
61 this->print_function (this->print_datum
, str
);
64 // Set the verbose flag.
65 void set_verbose (bool v
)
68 if (compilerp
!= nullptr)
69 compilerp
->set_verbose (v
);
72 // Make a new connection.
73 void set_connection (int fd
, int aux_fd
)
75 connection
.reset (new local_connection (fd
, aux_fd
, this));
78 // This is called just before compilation begins. It should set
79 // any needed callbacks on the connection.
80 virtual void add_callbacks () = 0;
82 // A local subclass of connection that holds a back-pointer to the
83 // context object that we provide to our caller.
84 class local_connection
: public cc1_plugin::connection
88 local_connection (int fd
, int aux_fd
, base_gdb_plugin
<T
> *b
)
89 : connection (fd
, aux_fd
),
94 void print (const char *buf
) override
96 back_ptr
->print (buf
);
99 base_gdb_plugin
<T
> *back_ptr
;
102 std::unique_ptr
<local_connection
> connection
;
104 void (*print_function
) (void *datum
, const char *message
) = nullptr;
105 void *print_datum
= nullptr;
107 std::vector
<std::string
> args
;
108 std::string source_file
;
110 /* Non-zero as an equivalent to gcc driver option "-v". */
113 const char *plugin_name
;
116 const char *compiler_name
;
117 std::unique_ptr
<cc1_plugin::compiler
> compilerp
;
121 struct gcc_base_vtable vtable
;
123 static inline base_gdb_plugin
<T
> *
124 get_self (gcc_base_context
*s
)
127 return static_cast<base_gdb_plugin
<T
> *> (sub
);
131 do_set_verbose (struct gcc_base_context
*s
, int /* bool */ verbose
)
133 base_gdb_plugin
<T
> *self
= get_self (s
);
135 self
->set_verbose (verbose
!= 0);
139 do_set_arguments (struct gcc_base_context
*s
,
140 int argc
, char **argv
)
142 base_gdb_plugin
<T
> *self
= get_self (s
);
144 std::string compiler
;
145 char *errmsg
= self
->compilerp
->find (self
->compiler_name
, compiler
);
149 self
->args
.push_back (compiler
);
151 for (int i
= 0; i
< argc
; ++i
)
152 self
->args
.push_back (argv
[i
]);
158 do_set_triplet_regexp (struct gcc_base_context
*s
,
159 const char *triplet_regexp
)
161 base_gdb_plugin
<T
> *self
= get_self (s
);
163 self
->compilerp
.reset
164 (new cc1_plugin::compiler_triplet_regexp (self
->verbose
,
170 do_set_driver_filename (struct gcc_base_context
*s
,
171 const char *driver_filename
)
173 base_gdb_plugin
<T
> *self
= get_self (s
);
175 self
->compilerp
.reset
176 (new cc1_plugin::compiler_driver_filename (self
->verbose
,
182 do_set_arguments_v0 (struct gcc_base_context
*s
,
183 const char *triplet_regexp
,
184 int argc
, char **argv
)
186 char *errmsg
= do_set_triplet_regexp (s
, triplet_regexp
);
190 return do_set_arguments (s
, argc
, argv
);
194 do_set_source_file (struct gcc_base_context
*s
,
197 base_gdb_plugin
<T
> *self
= get_self (s
);
199 self
->source_file
= file
;
203 do_set_print_callback (struct gcc_base_context
*s
,
204 void (*print_function
) (void *datum
,
205 const char *message
),
208 base_gdb_plugin
<T
> *self
= get_self (s
);
210 self
->print_function
= print_function
;
211 self
->print_datum
= datum
;
214 int fork_exec (char **argv
, int spair_fds
[2], int stderr_fds
[2])
216 pid_t child_pid
= fork ();
220 close (spair_fds
[0]);
221 close (spair_fds
[1]);
222 close (stderr_fds
[0]);
223 close (stderr_fds
[1]);
230 dup2 (stderr_fds
[1], 1);
231 dup2 (stderr_fds
[1], 2);
232 close (stderr_fds
[0]);
233 close (stderr_fds
[1]);
234 close (spair_fds
[0]);
236 execvp (argv
[0], argv
);
242 close (spair_fds
[1]);
243 close (stderr_fds
[1]);
245 cc1_plugin::status result
= cc1_plugin::FAIL
;
246 if (connection
->send ('H')
247 && ::cc1_plugin::marshall (connection
.get (), fe_version
))
248 result
= connection
->wait_for_query ();
250 close (spair_fds
[0]);
251 close (stderr_fds
[0]);
257 if (waitpid (child_pid
, &status
, 0) == -1)
263 if (!WIFEXITED (status
) || WEXITSTATUS (status
) != 0)
275 do_compile (struct gcc_base_context
*s
,
276 const char *filename
)
278 base_gdb_plugin
<T
> *self
= get_self (s
);
281 if (socketpair (AF_UNIX
, SOCK_STREAM
, 0, fds
) != 0)
283 self
->print ("could not create socketpair\n");
288 if (pipe (stderr_fds
) != 0)
290 self
->print ("could not create pipe\n");
296 self
->args
.push_back (std::string ("-fplugin=") + self
->plugin_name
);
297 self
->args
.push_back (std::string ("-fplugin-arg-") + self
->plugin_name
298 + "-fd=" + std::to_string (fds
[1]));
300 self
->args
.push_back (self
->source_file
);
301 self
->args
.push_back ("-c");
302 self
->args
.push_back ("-o");
303 self
->args
.push_back (filename
);
305 self
->args
.push_back ("-v");
307 self
->set_connection (fds
[0], stderr_fds
[0]);
309 self
->add_callbacks ();
311 std::vector
<char *> argv (self
->args
.size () + 1);
312 for (unsigned int i
= 0; i
< self
->args
.size (); ++i
)
313 argv
[i
] = const_cast<char *> (self
->args
[i
].c_str ());
315 return self
->fork_exec (argv
.data (), fds
, stderr_fds
);
319 do_compile_v0 (struct gcc_base_context
*s
, const char *filename
,
322 do_set_verbose (s
, verbose
);
323 return do_compile (s
, filename
);
327 do_destroy (struct gcc_base_context
*s
)
329 base_gdb_plugin
<T
> *self
= get_self (s
);
335 // Instances of this rpc<> template function are installed into the
336 // "vtable"s. These functions are parameterized by type and method
337 // name and forward the call via the connection.
338 template<typename CTX
, typename R
, const char *&NAME
, typename
... Arg
>
339 R
rpc (CTX
*s
, Arg
... rest
)
341 base_gdb_plugin
<CTX
> *self
= (base_gdb_plugin
<CTX
> *) s
;
344 if (!cc1_plugin::call (self
->connection
.get (), NAME
, &result
, rest
...))
350 #endif // CC1_PLUGIN_GDBCTX_HH