diff --git a/lib/debugger/debugger.c b/lib/debugger/debugger.c index 47b86fec0..6e574884d 100644 --- a/lib/debugger/debugger.c +++ b/lib/debugger/debugger.c @@ -30,10 +30,12 @@ #include "timeutils/misc.h" #include "compat/time.h" #include "scratch-buffers.h" +#include "cfg-source.h" #include #include #include +#include struct _Debugger { @@ -43,11 +45,20 @@ struct _Debugger struct iv_signal sigint; MainLoop *main_loop; GlobalConfig *cfg; - gchar *command_buffer; - LogTemplate *display_template; + GThread *debugger_thread; BreakpointSite *breakpoint_site; struct timespec last_trace_event; - GThread *debugger_thread; + + /* user interface related state */ + gchar *command_buffer; + struct + { + gchar *filename; + gint line; + gint column; + gint list_start; + } current_location; + LogTemplate *display_template; }; static void @@ -118,42 +129,39 @@ _display_msg_with_template_string(Debugger *self, LogMessage *msg, const gchar * } static void -_display_source_line(LogExprNode *expr_node) +_set_current_location(Debugger *self, LogExprNode *expr_node) { - FILE *f; - gint lineno = 1; - gchar buf[1024]; - - if (!expr_node || !expr_node->filename) - return; - - f = fopen(expr_node->filename, "r"); - if (f) + g_free(self->current_location.filename); + if (expr_node) { - while (fgets(buf, sizeof(buf), f) && lineno < expr_node->line) - lineno++; - if (lineno != expr_node->line) - buf[0] = 0; - fclose(f); + self->current_location.filename = g_strdup(expr_node->filename); + self->current_location.line = expr_node->line; + self->current_location.column = expr_node->column; + self->current_location.list_start = expr_node->line - 5; } else { - buf[0] = 0; + memset(&self->current_location, 0, sizeof(self->current_location)); } - printf("%-8d %s", expr_node->line, buf); - if (buf[0] == 0 || buf[strlen(buf) - 1] != '\n') - putc('\n', stdout); - fflush(stdout); } +static void +_display_source_line(Debugger *self) +{ + if (self->current_location.filename) + cfg_source_print_source_text(self->current_location.filename, self->current_location.line, self->current_location.column, self->current_location.list_start); + else + puts("Unable to list source, no current location set"); +} static gboolean _cmd_help(Debugger *self, gint argc, gchar *argv[]) { printf("syslog-ng interactive console, the following commands are available\n\n" " help, h, or ? Display this help\n" - " info Display information about the current execution state\n" " continue or c Continue until the next breakpoint\n" + " info Display information about the current execution state\n" + " list or l Display source code at the current location\n" " follow or f Follow this message along the configuration\n" " unfollow or u Unfollow the current message and wait for the next breakpoint\n" " trace Trace this message along the configuration\n" @@ -229,7 +237,7 @@ _cmd_info_pipe(Debugger *self, LogPipe *pipe) gchar buf[1024]; printf("LogPipe %p at %s\n", pipe, log_expr_node_format_location(pipe->expr_node, buf, sizeof(buf))); - _display_source_line(pipe->expr_node); + _display_source_line(self); return TRUE; } @@ -248,6 +256,38 @@ _cmd_info(Debugger *self, gint argc, gchar *argv[]) return TRUE; } +static gboolean +_cmd_list(Debugger *self, gint argc, gchar *argv[]) +{ + gint shift = 11; + if (argc >= 2) + { + if (strcmp(argv[1], "+") == 0) + shift = 11; + else if (strcmp(argv[1], "-") == 0) + shift = -11; + else if (strcmp(argv[1], ".") == 0) + { + shift = 0; + if (self->breakpoint_site) + _set_current_location(self, self->breakpoint_site->pipe->expr_node); + } + else if (isdigit(argv[1][0])) + { + gint target_lineno = atoi(argv[1]); + if (target_lineno <= 0) + target_lineno = 1; + self->current_location.list_start = target_lineno; + } + /* drop any arguments for repeated execution */ + _set_command(self, "l"); + } + _display_source_line(self); + if (shift) + self->current_location.list_start += shift; + return TRUE; +} + static gboolean _cmd_trace(Debugger *self, gint argc, gchar *argv[]) { @@ -293,6 +333,8 @@ struct { "u", _cmd_unfollow }, { "print", _cmd_print, .requires_breakpoint_site = TRUE }, { "p", _cmd_print, .requires_breakpoint_site = TRUE }, + { "list", _cmd_list, }, + { "l", _cmd_list, }, { "display", _cmd_display }, { "drop", _cmd_drop, .requires_breakpoint_site = TRUE }, { "quit", _cmd_quit }, @@ -334,6 +376,7 @@ debugger_register_command_fetcher(FetchCommandFunc fetcher) fetch_command_func = fetcher; } + static void _fetch_command(Debugger *self) { @@ -389,18 +432,19 @@ static void _handle_interactive_prompt(Debugger *self) { gchar buf[1024]; - LogPipe *current_pipe; if (self->breakpoint_site) { - current_pipe = self->breakpoint_site->pipe; + LogPipe *current_pipe = self->breakpoint_site->pipe; + _set_current_location(self, current_pipe->expr_node); printf("Breakpoint hit %s\n", log_expr_node_format_location(current_pipe->expr_node, buf, sizeof(buf))); - _display_source_line(current_pipe->expr_node); + _display_source_line(self); _display_msg_with_template(self, self->breakpoint_site->msg, self->display_template); } else { + _set_current_location(self, NULL); printf("Stopping on interrupt, message related commands are unavailable...\n"); } while (1) @@ -514,6 +558,7 @@ debugger_new(MainLoop *main_loop, GlobalConfig *cfg) void debugger_free(Debugger *self) { + g_free(self->current_location.filename); log_template_unref(self->display_template); tracer_free(self->tracer); g_free(self->command_buffer);