Browse Source

plugins: allow --dev-debugger=<pluginname>.

This currently just invokes GDB, but we could generalize it (though
pdb doesn't allow attaching to a running process, other python
debuggers seem to).

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
plugin-6
Rusty Russell 6 years ago
parent
commit
6323cc1898
  1. 21
      common/daemon.c
  2. 3
      common/daemon.h
  3. 13
      common/subdaemon.c
  4. 4
      lightningd/lightningd.c
  5. 6
      lightningd/lightningd.h
  6. 10
      lightningd/options.c
  7. 22
      lightningd/plugin.c
  8. 4
      lightningd/plugin.h
  9. 8
      lightningd/subd.c
  10. 1
      lightningd/subd.h
  11. 2
      lightningd/test/run-find_my_abspath.c

21
common/daemon.c

@ -4,6 +4,7 @@
#include <ccan/err/err.h> #include <ccan/err/err.h>
#include <ccan/io/io.h> #include <ccan/io/io.h>
#include <ccan/str/str.h> #include <ccan/str/str.h>
#include <ccan/tal/str/str.h>
#include <common/daemon.h> #include <common/daemon.h>
#include <common/memleak.h> #include <common/memleak.h>
#include <common/status.h> #include <common/status.h>
@ -150,3 +151,23 @@ void daemon_shutdown(void)
tal_free(tmpctx); tal_free(tmpctx);
wally_cleanup(0); wally_cleanup(0);
} }
void daemon_maybe_debug(int argc, char *argv[])
{
#if DEVELOPER
for (int i = 1; i < argc; i++) {
if (!streq(argv[i], "--debugger"))
continue;
/* Don't let this mess up stdout, so redir to /dev/null */
char *cmd = tal_fmt(NULL, "${DEBUG_TERM:-gnome-terminal --} gdb -ex 'attach %u' %s >/dev/null &", getpid(), argv[0]);
fprintf(stderr, "Running %s\n", cmd);
/* warn_unused_result is fascist bullshit.
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425 */
if (system(cmd))
;
/* Continue in the debugger. */
kill(getpid(), SIGSTOP);
}
#endif /* DEVELOPER */
}

3
common/daemon.h

@ -14,6 +14,9 @@ int daemon_poll(struct pollfd *fds, nfds_t nfds, int timeout);
/* Shutdown for a valgrind-clean exit (frees everything) */ /* Shutdown for a valgrind-clean exit (frees everything) */
void daemon_shutdown(void); void daemon_shutdown(void);
/* Kick in a debugger if they set --debugger */
void daemon_maybe_debug(int argc, char *argv[]);
struct backtrace_state *backtrace_state; struct backtrace_state *backtrace_state;
#endif /* LIGHTNING_COMMON_DAEMON_H */ #endif /* LIGHTNING_COMMON_DAEMON_H */

13
common/subdaemon.c

@ -37,19 +37,10 @@ void subdaemon_setup(int argc, char *argv[])
logging_io = true; logging_io = true;
} }
daemon_maybe_debug(argc, argv);
#if DEVELOPER #if DEVELOPER
/* From debugger, set debugger_spin to 0. */
for (int i = 1; i < argc; i++) { for (int i = 1; i < argc; i++) {
if (streq(argv[i], "--debugger")) {
char *cmd = tal_fmt(NULL, "${DEBUG_TERM:-gnome-terminal --} gdb -ex 'attach %u' %s &", getpid(), argv[0]);
fprintf(stderr, "Running %s\n", cmd);
/* warn_unused_result is fascist bullshit.
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425 */
if (system(cmd))
;
/* Continue in the debugger. */
kill(getpid(), SIGSTOP);
}
if (strstarts(argv[i], "--dev-disconnect=")) { if (strstarts(argv[i], "--dev-disconnect=")) {
dev_disconnect_init(atoi(argv[i] dev_disconnect_init(atoi(argv[i]
+ strlen("--dev-disconnect="))); + strlen("--dev-disconnect=")));

4
lightningd/lightningd.c

@ -110,8 +110,8 @@ static struct lightningd *new_lightningd(const tal_t *ctx)
* is a nod to keeping it minimal and explicit: we need this code for * is a nod to keeping it minimal and explicit: we need this code for
* testing, but its existence means we're not actually testing the * testing, but its existence means we're not actually testing the
* same exact code users will be running. */ * same exact code users will be running. */
ld->dev_debug_subprocess = NULL;
#if DEVELOPER #if DEVELOPER
ld->dev_debug_subdaemon = NULL;
ld->dev_disconnect_fd = -1; ld->dev_disconnect_fd = -1;
ld->dev_subdaemon_fail = false; ld->dev_subdaemon_fail = false;
ld->dev_allow_localhost = false; ld->dev_allow_localhost = false;
@ -611,7 +611,7 @@ int main(int argc, char *argv[])
/*~ Initialize all the plugins we just registered, so they can /*~ Initialize all the plugins we just registered, so they can
* do their thing and tell us about themselves (including * do their thing and tell us about themselves (including
* options registration). */ * options registration). */
plugins_init(ld->plugins); plugins_init(ld->plugins, ld->dev_debug_subprocess);
/*~ Handle options and config; move to .lightningd (--lightning-dir) */ /*~ Handle options and config; move to .lightningd (--lightning-dir) */
handle_opts(ld, argc, argv); handle_opts(ld, argc, argv);

6
lightningd/lightningd.h

@ -183,10 +183,10 @@ struct lightningd {
* if we are the fundee. */ * if we are the fundee. */
u32 max_funding_unconfirmed; u32 max_funding_unconfirmed;
#if DEVELOPER /* If we want to debug a subdaemon/plugin. */
/* If we want to debug a subdaemon. */ const char *dev_debug_subprocess;
const char *dev_debug_subdaemon;
#if DEVELOPER
/* If we have a --dev-disconnect file */ /* If we have a --dev-disconnect file */
int dev_disconnect_fd; int dev_disconnect_fd;

10
lightningd/options.c

@ -435,6 +435,12 @@ static void config_register_opts(struct lightningd *ld)
} }
#if DEVELOPER #if DEVELOPER
static char *opt_subprocess_debug(const char *optarg, struct lightningd *ld)
{
ld->dev_debug_subprocess = optarg;
return NULL;
}
static void dev_register_opts(struct lightningd *ld) static void dev_register_opts(struct lightningd *ld)
{ {
opt_register_noarg("--dev-no-reconnect", opt_set_invbool, opt_register_noarg("--dev-no-reconnect", opt_set_invbool,
@ -442,8 +448,8 @@ static void dev_register_opts(struct lightningd *ld)
"Disable automatic reconnect attempts"); "Disable automatic reconnect attempts");
opt_register_noarg("--dev-fail-on-subdaemon-fail", opt_set_bool, opt_register_noarg("--dev-fail-on-subdaemon-fail", opt_set_bool,
&ld->dev_subdaemon_fail, opt_hidden); &ld->dev_subdaemon_fail, opt_hidden);
opt_register_arg("--dev-debugger=<subdaemon>", opt_subd_debug, NULL, opt_register_early_arg("--dev-debugger=<subprocess>", opt_subprocess_debug, NULL,
ld, "Invoke gdb at start of <subdaemon>"); ld, "Invoke gdb at start of <subprocess>");
opt_register_arg("--dev-broadcast-interval=<ms>", opt_set_uintval, opt_register_arg("--dev-broadcast-interval=<ms>", opt_set_uintval,
opt_show_uintval, &ld->config.broadcast_interval_msec, opt_show_uintval, &ld->config.broadcast_interval_msec,
"Time between gossip broadcasts in milliseconds"); "Time between gossip broadcasts in milliseconds");

22
lightningd/plugin.c

@ -766,7 +766,7 @@ void clear_plugins(struct plugins *plugins)
tal_free(p); tal_free(p);
} }
void plugins_init(struct plugins *plugins) void plugins_init(struct plugins *plugins, const char *dev_plugin_debug)
{ {
struct plugin *p; struct plugin *p;
char **cmd; char **cmd;
@ -778,9 +778,13 @@ void plugins_init(struct plugins *plugins)
/* Spawn the plugin processes before entering the io_loop */ /* Spawn the plugin processes before entering the io_loop */
list_for_each(&plugins->plugins, p, list) { list_for_each(&plugins->plugins, p, list) {
cmd = tal_arr(p, char *, 2); bool debug;
debug = dev_plugin_debug && strends(p->cmd, dev_plugin_debug);
cmd = tal_arrz(p, char *, 2 + debug);
cmd[0] = p->cmd; cmd[0] = p->cmd;
cmd[1] = NULL; if (debug)
cmd[1] = "--debugger";
p->pid = pipecmdarr(&stdout, &stdin, NULL, cmd); p->pid = pipecmdarr(&stdout, &stdin, NULL, cmd);
if (p->pid == -1) if (p->pid == -1)
@ -798,9 +802,15 @@ void plugins_init(struct plugins *plugins)
json_array_end(req->stream); json_array_end(req->stream);
plugin_request_queue(req); plugin_request_queue(req);
plugins->pending_manifests++; plugins->pending_manifests++;
p->timeout_timer = new_reltimer( /* Don't timeout if they're running a debugger. */
&plugins->timers, p, time_from_sec(PLUGIN_MANIFEST_TIMEOUT), if (debug)
plugin_manifest_timeout, p); p->timeout_timer = NULL;
else {
p->timeout_timer
= new_reltimer(&plugins->timers, p,
time_from_sec(PLUGIN_MANIFEST_TIMEOUT),
plugin_manifest_timeout, p);
}
tal_free(cmd); tal_free(cmd);
} }

4
lightningd/plugin.h

@ -27,8 +27,10 @@ struct plugins *plugins_new(const tal_t *ctx, struct log_book *log_book,
* arguments. In order to read the getmanifest reply from the plugins * arguments. In order to read the getmanifest reply from the plugins
* we spin up our own io_loop that exits once all plugins have * we spin up our own io_loop that exits once all plugins have
* responded. * responded.
*
* The dev_plugin_debug arg comes from --dev-debugger if DEVELOPER.
*/ */
void plugins_init(struct plugins *plugins); void plugins_init(struct plugins *plugins, const char *dev_plugin_debug);
/** /**
* Register a plugin for initialization and execution. * Register a plugin for initialization and execution.

8
lightningd/subd.c

@ -626,7 +626,7 @@ static struct subd *new_subd(struct lightningd *ld,
assert(name != NULL); assert(name != NULL);
#if DEVELOPER #if DEVELOPER
debug_subd = ld->dev_debug_subdaemon; debug_subd = ld->dev_debug_subprocess;
disconnect_fd = ld->dev_disconnect_fd; disconnect_fd = ld->dev_disconnect_fd;
#endif /* DEVELOPER */ #endif /* DEVELOPER */
@ -784,12 +784,6 @@ void subd_release_channel(struct subd *owner, void *channel)
} }
#if DEVELOPER #if DEVELOPER
char *opt_subd_debug(const char *optarg, struct lightningd *ld)
{
ld->dev_debug_subdaemon = optarg;
return NULL;
}
char *opt_subd_dev_disconnect(const char *optarg, struct lightningd *ld) char *opt_subd_dev_disconnect(const char *optarg, struct lightningd *ld)
{ {
ld->dev_disconnect_fd = open(optarg, O_RDONLY); ld->dev_disconnect_fd = open(optarg, O_RDONLY);

1
lightningd/subd.h

@ -206,7 +206,6 @@ void subd_shutdown(struct subd *subd, unsigned int seconds);
const char *find_my_abspath(const tal_t *ctx, const char *argv0); const char *find_my_abspath(const tal_t *ctx, const char *argv0);
#if DEVELOPER #if DEVELOPER
char *opt_subd_debug(const char *optarg, struct lightningd *ld);
char *opt_subd_dev_disconnect(const char *optarg, struct lightningd *ld); char *opt_subd_dev_disconnect(const char *optarg, struct lightningd *ld);
bool dev_disconnect_permanent(struct lightningd *ld); bool dev_disconnect_permanent(struct lightningd *ld);

2
lightningd/test/run-find_my_abspath.c

@ -136,7 +136,7 @@ void onchaind_replay_channels(struct lightningd *ld UNNEEDED)
void plugins_config(struct plugins *plugins UNNEEDED) void plugins_config(struct plugins *plugins UNNEEDED)
{ fprintf(stderr, "plugins_config called!\n"); abort(); } { fprintf(stderr, "plugins_config called!\n"); abort(); }
/* Generated stub for plugins_init */ /* Generated stub for plugins_init */
void plugins_init(struct plugins *plugins UNNEEDED) void plugins_init(struct plugins *plugins UNNEEDED, const char *dev_plugin_debug UNNEEDED)
{ fprintf(stderr, "plugins_init called!\n"); abort(); } { fprintf(stderr, "plugins_init called!\n"); abort(); }
/* Generated stub for plugins_new */ /* Generated stub for plugins_new */
struct plugins *plugins_new(const tal_t *ctx UNNEEDED, struct log_book *log_book UNNEEDED, struct plugins *plugins_new(const tal_t *ctx UNNEEDED, struct log_book *log_book UNNEEDED,

Loading…
Cancel
Save