diff --git a/common/daemon.c b/common/daemon.c index 276bb4838..67fc16e39 100644 --- a/common/daemon.c +++ b/common/daemon.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -150,3 +151,23 @@ void daemon_shutdown(void) tal_free(tmpctx); 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 */ +} diff --git a/common/daemon.h b/common/daemon.h index b211e3777..d252dff3a 100644 --- a/common/daemon.h +++ b/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) */ 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; #endif /* LIGHTNING_COMMON_DAEMON_H */ diff --git a/common/subdaemon.c b/common/subdaemon.c index ed3b8bd0b..58349f343 100644 --- a/common/subdaemon.c +++ b/common/subdaemon.c @@ -37,19 +37,10 @@ void subdaemon_setup(int argc, char *argv[]) logging_io = true; } + daemon_maybe_debug(argc, argv); + #if DEVELOPER - /* From debugger, set debugger_spin to 0. */ 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=")) { dev_disconnect_init(atoi(argv[i] + strlen("--dev-disconnect="))); diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index ebcac22dc..1b897211a 100644 --- a/lightningd/lightningd.c +++ b/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 * testing, but its existence means we're not actually testing the * same exact code users will be running. */ + ld->dev_debug_subprocess = NULL; #if DEVELOPER - ld->dev_debug_subdaemon = NULL; ld->dev_disconnect_fd = -1; ld->dev_subdaemon_fail = 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 * do their thing and tell us about themselves (including * options registration). */ - plugins_init(ld->plugins); + plugins_init(ld->plugins, ld->dev_debug_subprocess); /*~ Handle options and config; move to .lightningd (--lightning-dir) */ handle_opts(ld, argc, argv); diff --git a/lightningd/lightningd.h b/lightningd/lightningd.h index d508c02eb..4c1ebb286 100644 --- a/lightningd/lightningd.h +++ b/lightningd/lightningd.h @@ -183,10 +183,10 @@ struct lightningd { * if we are the fundee. */ u32 max_funding_unconfirmed; -#if DEVELOPER - /* If we want to debug a subdaemon. */ - const char *dev_debug_subdaemon; + /* If we want to debug a subdaemon/plugin. */ + const char *dev_debug_subprocess; +#if DEVELOPER /* If we have a --dev-disconnect file */ int dev_disconnect_fd; diff --git a/lightningd/options.c b/lightningd/options.c index 6569157ca..7307ab73e 100644 --- a/lightningd/options.c +++ b/lightningd/options.c @@ -435,6 +435,12 @@ static void config_register_opts(struct lightningd *ld) } #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) { 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"); opt_register_noarg("--dev-fail-on-subdaemon-fail", opt_set_bool, &ld->dev_subdaemon_fail, opt_hidden); - opt_register_arg("--dev-debugger=", opt_subd_debug, NULL, - ld, "Invoke gdb at start of "); + opt_register_early_arg("--dev-debugger=", opt_subprocess_debug, NULL, + ld, "Invoke gdb at start of "); opt_register_arg("--dev-broadcast-interval=", opt_set_uintval, opt_show_uintval, &ld->config.broadcast_interval_msec, "Time between gossip broadcasts in milliseconds"); diff --git a/lightningd/plugin.c b/lightningd/plugin.c index b37fb932f..46d72dc6b 100644 --- a/lightningd/plugin.c +++ b/lightningd/plugin.c @@ -766,7 +766,7 @@ void clear_plugins(struct plugins *plugins) tal_free(p); } -void plugins_init(struct plugins *plugins) +void plugins_init(struct plugins *plugins, const char *dev_plugin_debug) { struct plugin *p; char **cmd; @@ -778,9 +778,13 @@ void plugins_init(struct plugins *plugins) /* Spawn the plugin processes before entering the io_loop */ 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[1] = NULL; + if (debug) + cmd[1] = "--debugger"; p->pid = pipecmdarr(&stdout, &stdin, NULL, cmd); if (p->pid == -1) @@ -798,9 +802,15 @@ void plugins_init(struct plugins *plugins) json_array_end(req->stream); plugin_request_queue(req); plugins->pending_manifests++; - p->timeout_timer = new_reltimer( - &plugins->timers, p, time_from_sec(PLUGIN_MANIFEST_TIMEOUT), - plugin_manifest_timeout, p); + /* Don't timeout if they're running a debugger. */ + if (debug) + 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); } diff --git a/lightningd/plugin.h b/lightningd/plugin.h index 2e9582e7b..40d64caf4 100644 --- a/lightningd/plugin.h +++ b/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 * we spin up our own io_loop that exits once all plugins have * 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. diff --git a/lightningd/subd.c b/lightningd/subd.c index 41bb0dd17..62c9361be 100644 --- a/lightningd/subd.c +++ b/lightningd/subd.c @@ -626,7 +626,7 @@ static struct subd *new_subd(struct lightningd *ld, assert(name != NULL); #if DEVELOPER - debug_subd = ld->dev_debug_subdaemon; + debug_subd = ld->dev_debug_subprocess; disconnect_fd = ld->dev_disconnect_fd; #endif /* DEVELOPER */ @@ -784,12 +784,6 @@ void subd_release_channel(struct subd *owner, void *channel) } #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) { ld->dev_disconnect_fd = open(optarg, O_RDONLY); diff --git a/lightningd/subd.h b/lightningd/subd.h index 81730ef81..2cfaf3957 100644 --- a/lightningd/subd.h +++ b/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); #if DEVELOPER -char *opt_subd_debug(const char *optarg, struct lightningd *ld); char *opt_subd_dev_disconnect(const char *optarg, struct lightningd *ld); bool dev_disconnect_permanent(struct lightningd *ld); diff --git a/lightningd/test/run-find_my_abspath.c b/lightningd/test/run-find_my_abspath.c index 143f211cf..9044ea432 100644 --- a/lightningd/test/run-find_my_abspath.c +++ b/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) { fprintf(stderr, "plugins_config called!\n"); abort(); } /* 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(); } /* Generated stub for plugins_new */ struct plugins *plugins_new(const tal_t *ctx UNNEEDED, struct log_book *log_book UNNEEDED,