From 4e837dae298ed286547e7a59a0156e7fff580b69 Mon Sep 17 00:00:00 2001 From: Balazs Scheidler Date: Sat, 12 Oct 2024 07:38:36 +0200 Subject: [PATCH 01/11] cfg-source: add num_lines argument to _print_underlined_source_block() Instead of using "NULL" as the indicator for the end of the lines to print, just pass the number of entries in the lines array. Signed-off-by: Balazs Scheidler --- lib/cfg-source.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/lib/cfg-source.c b/lib/cfg-source.c index 4695c40225..505cb7d868 100644 --- a/lib/cfg-source.c +++ b/lib/cfg-source.c @@ -55,13 +55,13 @@ _print_underline(const gchar *line, gint whitespace_before, gint number_of_caret } static void -_print_underlined_source_block(const CFG_LTYPE *yylloc, gchar **lines, gint error_index) +_print_underlined_source_block(const CFG_LTYPE *yylloc, gchar **lines, gsize num_lines, gint error_index) { gint line_ndx; gchar line_prefix[12]; gint error_length = yylloc->last_line - yylloc->first_line + 1; - for (line_ndx = 0; lines[line_ndx]; line_ndx++) + for (line_ndx = 0; line_ndx < num_lines; line_ndx++) { gint lineno = yylloc->first_line + line_ndx - error_index; const gchar *line = lines[line_ndx]; @@ -84,8 +84,6 @@ _print_underlined_source_block(const CFG_LTYPE *yylloc, gchar **lines, gint erro multi_line ? strlen(&line[yylloc->first_column]) + 1 : yylloc->last_column - yylloc->first_column); } - else if (line_ndx >= error_index + CONTEXT) - break; } } @@ -116,11 +114,10 @@ _report_file_location(const gchar *filename, const CFG_LTYPE *yylloc) /* NOTE: do we have the appropriate number of lines? */ if (lineno <= yylloc->first_line) goto exit; - g_ptr_array_add(context, NULL); fclose(f); } if (context->len > 0) - _print_underlined_source_block(yylloc, (gchar **) context->pdata, error_index); + _print_underlined_source_block(yylloc, (gchar **) context->pdata, context->len, error_index); exit: g_free(buf); @@ -144,7 +141,7 @@ _report_buffer_location(const gchar *buffer_content, const CFG_LTYPE *file_lloc, error_index += start; start = 0; } - _print_underlined_source_block(file_lloc, &lines[start], error_index); + _print_underlined_source_block(file_lloc, &lines[start], num_lines - start, error_index); exit: g_strfreev(lines); From 2480d7bc3ca752d6a1f30b0c894f267bc95f159b Mon Sep 17 00:00:00 2001 From: Balazs Scheidler Date: Sat, 12 Oct 2024 11:54:20 +0200 Subject: [PATCH 02/11] cfg-source: refactor source file printing to use line numbers Signed-off-by: Balazs Scheidler --- lib/cfg-source.c | 67 +++++++++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 29 deletions(-) diff --git a/lib/cfg-source.c b/lib/cfg-source.c index 505cb7d868..889453839f 100644 --- a/lib/cfg-source.c +++ b/lib/cfg-source.c @@ -55,25 +55,24 @@ _print_underline(const gchar *line, gint whitespace_before, gint number_of_caret } static void -_print_underlined_source_block(const CFG_LTYPE *yylloc, gchar **lines, gsize num_lines, gint error_index) +_print_underlined_source_block(const CFG_LTYPE *yylloc, gchar **lines, gsize num_lines, gint start_line) { gint line_ndx; gchar line_prefix[12]; - gint error_length = yylloc->last_line - yylloc->first_line + 1; for (line_ndx = 0; line_ndx < num_lines; line_ndx++) { - gint lineno = yylloc->first_line + line_ndx - error_index; + gint lineno = start_line + line_ndx; const gchar *line = lines[line_ndx]; gint line_len = strlen(line); gboolean line_ends_with_newline = line_len > 0 && line[line_len - 1] == '\n'; _format_source_prefix(line_prefix, sizeof(line_prefix), lineno, - line_ndx >= error_index && line_ndx < error_index + error_length); + lineno >= yylloc->first_line && lineno <= yylloc->last_line); fprintf(stderr, "%-8s%s%s", line_prefix, line, line_ends_with_newline ? "" : "\n"); - if (line_ndx == error_index) + if (lineno == yylloc->first_line) { /* print the underline right below the source line we just printed */ fprintf(stderr, "%-8s", line_prefix); @@ -88,14 +87,20 @@ _print_underlined_source_block(const CFG_LTYPE *yylloc, gchar **lines, gsize num } static void -_report_file_location(const gchar *filename, const CFG_LTYPE *yylloc) +_report_file_location(const gchar *filename, const CFG_LTYPE *yylloc, gint start_line) { FILE *f; gint lineno = 0; gsize buflen = 65520; gchar *buf = g_malloc(buflen); GPtrArray *context = g_ptr_array_new(); - gint error_index = 0; + gint end_line = start_line + 2*CONTEXT; + + if (start_line <= 0) + { + start_line = yylloc->first_line > CONTEXT ? yylloc->first_line - CONTEXT : 1; + end_line = yylloc->first_line + CONTEXT; + } f = fopen(filename, "r"); if (f) @@ -103,48 +108,52 @@ _report_file_location(const gchar *filename, const CFG_LTYPE *yylloc) while (fgets(buf, buflen, f)) { lineno++; - if (lineno > (gint) yylloc->first_line + CONTEXT) + if (lineno > end_line) break; - else if (lineno < (gint) yylloc->first_line - CONTEXT) + else if (lineno < start_line) continue; - else if (lineno == yylloc->first_line) - error_index = context->len; g_ptr_array_add(context, g_strdup(buf)); } - /* NOTE: do we have the appropriate number of lines? */ - if (lineno <= yylloc->first_line) - goto exit; fclose(f); } if (context->len > 0) - _print_underlined_source_block(yylloc, (gchar **) context->pdata, context->len, error_index); + _print_underlined_source_block(yylloc, (gchar **) context->pdata, context->len, start_line); -exit: g_free(buf); g_ptr_array_foreach(context, (GFunc) g_free, NULL); g_ptr_array_free(context, TRUE); } +/* this will report source content from the buffer, but use the line numbers + * of the file where the block was defined. + * + * buffer_* => tracks buffer related information + * file_* => tracks file related information + */ static void _report_buffer_location(const gchar *buffer_content, const CFG_LTYPE *file_lloc, const CFG_LTYPE *buf_lloc) { - gchar **lines = g_strsplit(buffer_content, "\n", buf_lloc->first_line + CONTEXT + 1); - gint num_lines = g_strv_length(lines); + gchar **buffer_lines = g_strsplit(buffer_content, "\n", buf_lloc->first_line + CONTEXT + 1); + gint buffer_num_lines = g_strv_length(buffer_lines); - if (num_lines <= buf_lloc->first_line) + if (buffer_num_lines <= buf_lloc->first_line) goto exit; - gint start = buf_lloc->first_line - 1 - CONTEXT; - gint error_index = CONTEXT; - if (start < 0) - { - error_index += start; - start = 0; - } - _print_underlined_source_block(file_lloc, &lines[start], num_lines - start, error_index); + /* the line number in the file, which we report in the source dump, 1 based */ + gint range_backwards = CONTEXT; + if (file_lloc->first_line <= range_backwards) + range_backwards = file_lloc->first_line - 1; + + /* the index of the line in the buffer where we start printing 0-based */ + gint buffer_start_index = buf_lloc->first_line - 1 - range_backwards; + if (buffer_start_index < 0) + buffer_start_index = 0; + + _print_underlined_source_block(file_lloc, &buffer_lines[buffer_start_index], buffer_num_lines - buffer_start_index, + file_lloc->first_line - range_backwards); exit: - g_strfreev(lines); + g_strfreev(buffer_lines); } gboolean @@ -152,7 +161,7 @@ cfg_source_print_source_context(CfgLexer *lexer, CfgIncludeLevel *level, const C { if (level->include_type == CFGI_FILE) { - _report_file_location(yylloc->name, yylloc); + _report_file_location(yylloc->name, yylloc, -1); } else if (level->include_type == CFGI_BUFFER) { From 81cd8c9a63d9b20898622956a4d9ed0606f7ddda Mon Sep 17 00:00:00 2001 From: Balazs Scheidler Date: Fri, 11 Oct 2024 22:07:01 +0200 Subject: [PATCH 03/11] cfg-source: add cfg_source_print_source_text() function Signed-off-by: Balazs Scheidler --- lib/cfg-source.c | 12 ++++++++++++ lib/cfg-source.h | 2 ++ 2 files changed, 14 insertions(+) diff --git a/lib/cfg-source.c b/lib/cfg-source.c index 889453839f..50fec12965 100644 --- a/lib/cfg-source.c +++ b/lib/cfg-source.c @@ -156,6 +156,18 @@ _report_buffer_location(const gchar *buffer_content, const CFG_LTYPE *file_lloc, g_strfreev(buffer_lines); } +gboolean +cfg_source_print_source_text(const gchar *filename, gint line, gint column, gint start_line) +{ + CFG_LTYPE yylloc = {0}; + + yylloc.name = filename; + yylloc.first_line = yylloc.last_line = line; + yylloc.first_column = yylloc.last_column = column; + _report_file_location(yylloc.name, &yylloc, start_line); + return TRUE; +} + gboolean cfg_source_print_source_context(CfgLexer *lexer, CfgIncludeLevel *level, const CFG_LTYPE *yylloc) { diff --git a/lib/cfg-source.h b/lib/cfg-source.h index 51e81fbd7e..55313b3939 100644 --- a/lib/cfg-source.h +++ b/lib/cfg-source.h @@ -26,6 +26,8 @@ #include "cfg-lexer.h" +gboolean cfg_source_print_source_text(const gchar *filename, gint line, gint column, gint offset); + /* These functions are only available during parsing */ gboolean cfg_source_print_source_context(CfgLexer *lexer, CfgIncludeLevel *level, const CFG_LTYPE *yylloc); gboolean cfg_source_extract_source_text(CfgLexer *lexer, const CFG_LTYPE *yylloc, GString *result); From 688119392dd3601c25750d52f57eecd61eac8f82 Mon Sep 17 00:00:00 2001 From: Balazs Scheidler Date: Fri, 11 Oct 2024 22:08:02 +0200 Subject: [PATCH 04/11] debugger: add source display using the cfg-source module Signed-off-by: Balazs Scheidler --- lib/debugger/debugger.c | 101 +++++++++++++++++++++++++++++----------- 1 file changed, 74 insertions(+), 27 deletions(-) diff --git a/lib/debugger/debugger.c b/lib/debugger/debugger.c index 9efac89387..b29d9158d3 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 { @@ -41,11 +43,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 gboolean @@ -108,34 +119,31 @@ _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[]) @@ -147,6 +155,7 @@ _cmd_help(Debugger *self, gint argc, gchar *argv[]) "The following commands are available:\n\n" " help, h, ? Display this help\n" " info, i Display information about the current execution state\n" + " list, l Display source code at the current location\n" " continue, c Continue until the next breakpoint\n" " display Set the displayed message template\n" " trace, t Display timing information as the message traverses the config\n" @@ -161,6 +170,7 @@ _cmd_help(Debugger *self, gint argc, gchar *argv[]) "Stopped on an interrupt.\n" "The following commands are available:\n\n" " help, h, ? Display this help\n" + " list, l Display source code at the current location\n" " continue, c Continue until the next breakpoint\n" " quit, q Tell syslog-ng to exit\n" ); @@ -239,7 +249,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; } @@ -258,6 +268,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; +} + typedef gboolean (*DebuggerCommandFunc)(Debugger *self, gint argc, gchar *argv[]); struct @@ -274,6 +316,8 @@ struct { "c", _cmd_continue }, { "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 }, { "d", _cmd_drop, .requires_breakpoint_site = TRUE }, @@ -316,6 +360,7 @@ debugger_register_command_fetcher(FetchCommandFunc fetcher) fetch_command_func = fetcher; } + static void _fetch_command(Debugger *self) { @@ -379,18 +424,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) @@ -504,6 +550,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); From 2c6227909a62aa24c6cbf983c0b699085d928fda Mon Sep 17 00:00:00 2001 From: Balazs Scheidler Date: Sat, 12 Oct 2024 08:28:53 +0200 Subject: [PATCH 05/11] debugger: extract _set_command() Signed-off-by: Balazs Scheidler --- lib/debugger/debugger.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/debugger/debugger.c b/lib/debugger/debugger.c index b29d9158d3..1e671b9883 100644 --- a/lib/debugger/debugger.c +++ b/lib/debugger/debugger.c @@ -59,6 +59,14 @@ struct _Debugger LogTemplate *display_template; }; +static void +_set_command(Debugger *self, gchar *new_command) +{ + if (self->command_buffer) + g_free(self->command_buffer); + self->command_buffer = g_strdup(new_command); +} + static gboolean _format_nvpair(NVHandle handle, const gchar *name, @@ -368,16 +376,8 @@ _fetch_command(Debugger *self) command = fetch_command_func(); if (command && strlen(command) > 0) - { - if (self->command_buffer) - g_free(self->command_buffer); - self->command_buffer = command; - } - else - { - if (command) - g_free(command); - } + _set_command(self, command); + g_free(command); } static gboolean @@ -542,7 +542,7 @@ debugger_new(MainLoop *main_loop, GlobalConfig *cfg) self->tracer = tracer_new(cfg); self->cfg = cfg; self->display_template = log_template_new(cfg, NULL); - self->command_buffer = g_strdup("help"); + _set_command(self, "help"); log_template_compile(self->display_template, "$DATE $HOST $MSGHDR$MSG", NULL); return self; } From 87fe40daee18cd5f11c4b4155e6612b1f254f7ff Mon Sep 17 00:00:00 2001 From: Balazs Scheidler Date: Sun, 13 Oct 2024 08:06:29 +0200 Subject: [PATCH 06/11] logpipe: add PIF_BREAKPOINT flag Signed-off-by: Balazs Scheidler --- lib/logpipe.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/logpipe.h b/lib/logpipe.h index 8d5ae07f72..3b3b40c13b 100644 --- a/lib/logpipe.h +++ b/lib/logpipe.h @@ -75,6 +75,8 @@ /* sync filterx state to message in right before calling queue() */ #define PIF_SYNC_FILTERX_TO_MSG 0x0200 +#define PIF_BREAKPOINT 0x0400 + /* private flags range, to be used by other LogPipe instances for their own purposes */ #define PIF_PRIVATE(x) ((x) << 16) From 01bd755bde0f825fba2628b46a5acd9256616447 Mon Sep 17 00:00:00 2001 From: Balazs Scheidler Date: Fri, 11 Oct 2024 21:30:00 +0200 Subject: [PATCH 07/11] debugger: add debugger mode The mode field in debugger determines how we respond to trace and breakpoints and is used by the hook to trigger various debugging scenarios. Signed-off-by: Balazs Scheidler --- lib/debugger/debugger-main.c | 7 +++-- lib/debugger/debugger.c | 60 ++++++++++++++++++++++++------------ lib/debugger/debugger.h | 54 +++++++++++++++++++++++++++++++- 3 files changed, 97 insertions(+), 24 deletions(-) diff --git a/lib/debugger/debugger-main.c b/lib/debugger/debugger-main.c index 7f2dc932d4..275043f659 100644 --- a/lib/debugger/debugger-main.c +++ b/lib/debugger/debugger-main.c @@ -32,10 +32,11 @@ static Debugger *current_debugger; static gboolean _pipe_hook(LogPipe *s, LogMessage *msg, const LogPathOptions *path_options) { - if (msg->flags & LF_STATE_TRACING) - return debugger_perform_tracing(current_debugger, s, msg); - else + if (debugger_is_to_stop(current_debugger, s, msg)) return debugger_stop_at_breakpoint(current_debugger, s, msg); + else if (debugger_is_to_trace(current_debugger, s, msg)) + return debugger_perform_tracing(current_debugger, s, msg); + return TRUE; } gboolean diff --git a/lib/debugger/debugger.c b/lib/debugger/debugger.c index 1e671b9883..792e2bd898 100644 --- a/lib/debugger/debugger.c +++ b/lib/debugger/debugger.c @@ -39,6 +39,8 @@ struct _Debugger { + /* debugger_get_mode() assumes this comes as the first field */ + DebuggerMode mode; Tracer *tracer; struct iv_signal sigint; MainLoop *main_loop; @@ -186,11 +188,6 @@ _cmd_help(Debugger *self, gint argc, gchar *argv[]) return TRUE; } -static gboolean -_cmd_continue(Debugger *self, gint argc, gchar *argv[]) -{ - return FALSE; -} static gboolean _cmd_print(Debugger *self, gint argc, gchar *argv[]) @@ -235,21 +232,6 @@ _cmd_drop(Debugger *self, gint argc, gchar *argv[]) return FALSE; } -static gboolean -_cmd_trace(Debugger *self, gint argc, gchar *argv[]) -{ - self->breakpoint_site->msg->flags |= LF_STATE_TRACING; - return FALSE; -} - -static gboolean -_cmd_quit(Debugger *self, gint argc, gchar *argv[]) -{ - main_loop_exit(self->main_loop); - if (self->breakpoint_site) - self->breakpoint_site->drop = TRUE; - return FALSE; -} static gboolean _cmd_info_pipe(Debugger *self, LogPipe *pipe) @@ -308,6 +290,44 @@ _cmd_list(Debugger *self, gint argc, gchar *argv[]) return TRUE; } +static inline void +_set_mode(Debugger *self, DebuggerMode new_mode, gboolean trace_message) +{ + self->mode = new_mode; + if (self->breakpoint_site) + { + if (trace_message) + self->breakpoint_site->msg->flags |= LF_STATE_TRACING; + else + self->breakpoint_site->msg->flags &= ~LF_STATE_TRACING; + } +} + +static gboolean +_cmd_continue(Debugger *self, gint argc, gchar *argv[]) +{ + _set_mode(self, DBG_WAITING_FOR_BREAKPOINT, FALSE); + return FALSE; +} + +static gboolean +_cmd_trace(Debugger *self, gint argc, gchar *argv[]) +{ + clock_gettime(CLOCK_MONOTONIC, &self->last_trace_event); + _set_mode(self, DBG_FOLLOW_AND_TRACE, TRUE); + return FALSE; +} + +static gboolean +_cmd_quit(Debugger *self, gint argc, gchar *argv[]) +{ + _set_mode(self, DBG_QUIT, FALSE); + if (self->breakpoint_site) + self->breakpoint_site->drop = TRUE; + main_loop_exit(self->main_loop); + return FALSE; +} + typedef gboolean (*DebuggerCommandFunc)(Debugger *self, gint argc, gchar *argv[]); struct diff --git a/lib/debugger/debugger.h b/lib/debugger/debugger.h index a1c2b38ac3..12506fc8aa 100644 --- a/lib/debugger/debugger.h +++ b/lib/debugger/debugger.h @@ -27,11 +27,27 @@ #include "syslog-ng.h" #include "cfg.h" #include "mainloop.h" +#include "logpipe.h" + +typedef enum +{ + DBG_WAITING_FOR_STEP, + DBG_WAITING_FOR_BREAKPOINT, + DBG_FOLLOW_AND_BREAK, + DBG_FOLLOW_AND_TRACE, + DBG_QUIT, +} DebuggerMode; typedef struct _Debugger Debugger; -typedef gchar *(*FetchCommandFunc)(void); +static inline DebuggerMode +debugger_get_mode(Debugger *self) +{ + return *(DebuggerMode *) self; +} + +typedef gchar *(*FetchCommandFunc)(void); gchar *debugger_builtin_fetch_command(void); void debugger_register_command_fetcher(FetchCommandFunc fetcher); @@ -43,5 +59,41 @@ gboolean debugger_stop_at_breakpoint(Debugger *self, LogPipe *pipe, LogMessage * Debugger *debugger_new(MainLoop *main_loop, GlobalConfig *cfg); void debugger_free(Debugger *self); +static inline gboolean +debugger_is_to_stop(Debugger *self, LogPipe *pipe, LogMessage *msg) +{ + DebuggerMode mode = debugger_get_mode(self); + + switch (mode) + { + case DBG_WAITING_FOR_BREAKPOINT: + return (pipe->flags & PIF_BREAKPOINT); + + case DBG_WAITING_FOR_STEP: + return TRUE; + + case DBG_FOLLOW_AND_BREAK: + return (msg->flags & LF_STATE_TRACING); + + case DBG_FOLLOW_AND_TRACE: + return FALSE; + + case DBG_QUIT: + return FALSE; + + default: + g_assert_not_reached(); + } + return FALSE; +} + +static inline gboolean +debugger_is_to_trace(Debugger *self, LogPipe *pipe, LogMessage *msg) +{ + DebuggerMode mode = debugger_get_mode(self); + + return (mode == DBG_FOLLOW_AND_TRACE) && (msg->flags & LF_STATE_TRACING); + +} #endif From 64de89e24d238b5f35f67459c075fcc68e025a3c Mon Sep 17 00:00:00 2001 From: Balazs Scheidler Date: Sun, 13 Oct 2024 08:16:10 +0200 Subject: [PATCH 08/11] debugger: filter out uninteresting stop events Some breakpoints are not interesting once the mode changes, even though they were submitted by the pipe hook and are waiting to be resumed. Let's quickly acknowledge them and don't bother the user. Signed-off-by: Balazs Scheidler --- lib/debugger/debugger.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/lib/debugger/debugger.c b/lib/debugger/debugger.c index 792e2bd898..cd57c0df65 100644 --- a/lib/debugger/debugger.c +++ b/lib/debugger/debugger.c @@ -470,6 +470,34 @@ _handle_interactive_prompt(Debugger *self) printf("(continuing)\n"); } +static gboolean +_debugger_wait_for_event(Debugger *self) +{ + while (1) + { + if (!tracer_wait_for_event(self->tracer, &self->breakpoint_site)) + return FALSE; + + /* this is an interrupt, let's handle it now */ + if (!self->breakpoint_site) + return TRUE; + + /* is this an event we are still interested in? */ + if (debugger_is_to_stop(self, self->breakpoint_site->pipe, self->breakpoint_site->msg)) + return TRUE; + + /* not interesting now, let's resume and wait for another */ + tracer_resume_after_event(self->tracer, self->breakpoint_site); + } + return TRUE; +} + +static void +_debugger_ack_event(Debugger *self) +{ + tracer_resume_after_event(self->tracer, self->breakpoint_site); +} + static gpointer _debugger_thread_func(Debugger *self) { @@ -477,13 +505,14 @@ _debugger_thread_func(Debugger *self) printf("Waiting for breakpoint...\n"); while (1) { - self->breakpoint_site = NULL; - if (!tracer_wait_for_event(self->tracer, &self->breakpoint_site)) + if (!_debugger_wait_for_event(self)) break; _handle_interactive_prompt(self); - tracer_resume_after_event(self->tracer, self->breakpoint_site); + + _debugger_ack_event(self); } + scratch_buffers_explicit_gc(); app_thread_stop(); return NULL; From 14b4d2893d642309e0b63ccdb1390f9de4eea752 Mon Sep 17 00:00:00 2001 From: Balazs Scheidler Date: Sun, 13 Oct 2024 08:30:23 +0200 Subject: [PATCH 09/11] debugger: add step and follow commands Signed-off-by: Balazs Scheidler --- lib/debugger/debugger.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/lib/debugger/debugger.c b/lib/debugger/debugger.c index cd57c0df65..f39914a42c 100644 --- a/lib/debugger/debugger.c +++ b/lib/debugger/debugger.c @@ -167,6 +167,8 @@ _cmd_help(Debugger *self, gint argc, gchar *argv[]) " info, i Display information about the current execution state\n" " list, l Display source code at the current location\n" " continue, c Continue until the next breakpoint\n" + " step, s Single step\n" + " follow, f Follow this message, ignoring any other breakpoints\n" " display Set the displayed message template\n" " trace, t Display timing information as the message traverses the config\n" " print, p Print the current log message\n" @@ -310,6 +312,13 @@ _cmd_continue(Debugger *self, gint argc, gchar *argv[]) return FALSE; } +static gboolean +_cmd_step(Debugger *self, gint argc, gchar *argv[]) +{ + _set_mode(self, DBG_WAITING_FOR_STEP, FALSE); + return FALSE; +} + static gboolean _cmd_trace(Debugger *self, gint argc, gchar *argv[]) { @@ -318,6 +327,13 @@ _cmd_trace(Debugger *self, gint argc, gchar *argv[]) return FALSE; } +static gboolean +_cmd_follow(Debugger *self, gint argc, gchar *argv[]) +{ + _set_mode(self, DBG_FOLLOW_AND_BREAK, TRUE); + return FALSE; +} + static gboolean _cmd_quit(Debugger *self, gint argc, gchar *argv[]) { @@ -342,6 +358,10 @@ struct { "?", _cmd_help }, { "continue", _cmd_continue }, { "c", _cmd_continue }, + { "step", _cmd_step }, + { "s", _cmd_step }, + { "follow", _cmd_follow, .requires_breakpoint_site = TRUE }, + { "f", _cmd_follow, .requires_breakpoint_site = TRUE }, { "print", _cmd_print, .requires_breakpoint_site = TRUE }, { "p", _cmd_print, .requires_breakpoint_site = TRUE }, { "list", _cmd_list, }, From ebfaa60af155468a2750108080522d9b42c69851 Mon Sep 17 00:00:00 2001 From: Balazs Scheidler Date: Tue, 10 Dec 2024 11:59:48 +0100 Subject: [PATCH 10/11] debugger: clean up trace command Signed-off-by: Balazs Scheidler --- lib/debugger/debugger.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/debugger/debugger.c b/lib/debugger/debugger.c index f39914a42c..fb7dc9d487 100644 --- a/lib/debugger/debugger.c +++ b/lib/debugger/debugger.c @@ -170,7 +170,7 @@ _cmd_help(Debugger *self, gint argc, gchar *argv[]) " step, s Single step\n" " follow, f Follow this message, ignoring any other breakpoints\n" " display Set the displayed message template\n" - " trace, t Display timing information as the message traverses the config\n" + " trace, t Trace this message along the configuration\n" " print, p Print the current log message\n" " drop, d Drop the current message\n" " quit, q Tell syslog-ng to exit\n" From bfd41fcebf62786763cba12587741175ea336f0b Mon Sep 17 00:00:00 2001 From: Balazs Scheidler Date: Sun, 13 Oct 2024 08:29:03 +0200 Subject: [PATCH 11/11] debugger: add welcome blurb on startup Also, stop at the prompt immediately, instead of wait for a message. Signed-off-by: Balazs Scheidler --- lib/debugger/debugger.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/lib/debugger/debugger.c b/lib/debugger/debugger.c index fb7dc9d487..36891dea20 100644 --- a/lib/debugger/debugger.c +++ b/lib/debugger/debugger.c @@ -48,6 +48,7 @@ struct _Debugger GThread *debugger_thread; BreakpointSite *breakpoint_site; struct timespec last_trace_event; + gboolean starting_up; /* user interface related state */ gchar *command_buffer; @@ -474,10 +475,10 @@ _handle_interactive_prompt(Debugger *self) _display_source_line(self); _display_msg_with_template(self, self->breakpoint_site->msg, self->display_template); } - else + else if (!self->starting_up) { _set_current_location(self, NULL); - printf("Stopping on interrupt, message related commands are unavailable...\n"); + printf(" Stopping on Interrupt...\n"); } while (1) { @@ -522,7 +523,22 @@ static gpointer _debugger_thread_func(Debugger *self) { app_thread_start(); - printf("Waiting for breakpoint...\n"); + self->breakpoint_site = NULL; + + printf("axosyslog interactive debugger\n" + "Copyright (c) 2024 Axoflow and contributors\n\n" + + "This program comes with ABSOLUTELY NO WARRANTY;\n" + "This is free software, and you are welcome to redistribute it\n" + "under certain conditions;\n" + "See https://github.com/axoflow/axosyslog/blob/main/COPYING\n" + "License LGPLV2.1+ and GPLv2+\n\n" + + "For help, type \"help\".\n"); + + self->starting_up = TRUE; + _handle_interactive_prompt(self); + self->starting_up = FALSE; while (1) { if (!_debugger_wait_for_event(self))