Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Debugger step and follow commands #340

Open
wants to merge 42 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
1eb3781
scratch-buffers: do not use ivykis in non-ivykis threads
bazsi Oct 6, 2024
d14cb21
control: make it possible to query if a worker relates to a connection
bazsi Oct 5, 2024
273eb9b
control: cancel connection related workers
bazsi Oct 5, 2024
b4020dd
control: call app_thread_start/stop from command threads
bazsi Oct 6, 2024
fe854f7
control: add support for passing 3 fds through the control socket
bazsi Oct 5, 2024
43f28e7
console: new module to track the interactive connection to a terminal
bazsi Oct 5, 2024
aad0567
gprocess: integrate startup with the new console management module
bazsi Oct 5, 2024
11fcfc8
mainloop-control: add support for ATTACH STDIO
bazsi Oct 5, 2024
6242056
syslog-ng-ctl: add support for "attach" command
bazsi Oct 5, 2024
66e575e
control: remove and bump verbosity for some control socket related me…
bazsi Oct 5, 2024
6dcf9ab
gprocess: get rid off the stderr_present variable
bazsi Oct 5, 2024
1f68f2b
logpipe: uninline log_pipe_queue()
bazsi Oct 6, 2024
44a8275
logpipe: eliminate s->queue == NULL trick
bazsi Oct 6, 2024
78cf282
logpipe: whitespace fix
bazsi Oct 6, 2024
695b3c0
logpipe: move PIF_CONFIG_RELATED check to the call site
bazsi Oct 6, 2024
0031f3e
debugger: add cancellation support to Tracer
bazsi Oct 6, 2024
79d2f3c
debugger: add debugger_exit()
bazsi Oct 6, 2024
f43d0fb
debugger: rename interactive_thread to debugger_thread
bazsi Oct 6, 2024
abe1d39
debugger: attach and deattach the single step hook in a synchronized …
bazsi Oct 6, 2024
4f15ff1
debugger: add debugger_stop() call alongside debugger_start()
bazsi Oct 6, 2024
d24ee74
debugger: make sure that debugger_start_console and debugger_exit() r…
bazsi Oct 6, 2024
b3ecc34
tracer: move the Tracer struct to the implementation file
bazsi Oct 6, 2024
3a402c3
debugger: support multi-threaded mode
bazsi Oct 6, 2024
ca8b036
syslog-ng-ctl: add support for "attach debugger"
bazsi Oct 6, 2024
de5c76e
mainloop: do not register signal handlers as exclusive
bazsi Oct 6, 2024
45672ea
tracer: implement interrupt support
bazsi Oct 6, 2024
677d350
debugger: get into the debugger on SIGINT
bazsi Oct 6, 2024
5ba6d4d
logreader: retry on main_loop_io_worker_job_submit() failure
bazsi Oct 15, 2024
3228a54
console: extract console_printf from gprocess
bazsi Oct 20, 2024
a136792
gprocess: add fatal signal logging with a backtrace
bazsi Oct 15, 2024
8949ea5
logreader: add exit-on-eof flag()
bazsi Oct 14, 2024
5ce77a2
cfg-source: add num_lines argument to _print_underlined_source_block()
bazsi Oct 12, 2024
00996cb
cfg-source: refactor source file printing to use line numbers
bazsi Oct 12, 2024
e02b15a
cfg-source: add cfg_source_print_source_text() function
bazsi Oct 11, 2024
f263108
debugger: add source display using the cfg-source module
bazsi Oct 11, 2024
34e2e1f
debugger: extract _set_command()
bazsi Oct 12, 2024
f67c4bf
logpipe: add PIF_BREAKPOINT flag
bazsi Oct 13, 2024
709de3b
debugger: add debugger mode
bazsi Oct 11, 2024
11144b7
debugger: filter out uninteresting stop events
bazsi Oct 13, 2024
bd2cdb6
debugger: clean up trace command
bazsi Oct 13, 2024
3415137
debugger: add welcome blurb on startup
bazsi Oct 13, 2024
d1d8188
debugger: add step and follow commands
bazsi Oct 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ set (LIB_HEADERS
atomic-gssize.h
block-ref-parser.h
cache.h
console.h
cfg.h
cfg-lexer.h
cfg-lexer-subst.h
Expand Down Expand Up @@ -152,6 +153,7 @@ set (LIB_HEADERS
serialize.h
service-management.h
seqnum.h
stackdump.h
str-format.h
str-utils.h
syslog-names.h
Expand Down Expand Up @@ -179,6 +181,7 @@ set(LIB_SOURCES
apphook.c
block-ref-parser.c
cache.c
console.c
cfg.c
cfg-args.c
cfg-block.c
Expand Down Expand Up @@ -247,6 +250,7 @@ set(LIB_SOURCES
scratch-buffers.c
serialize.c
service-management.c
stackdump.c
str-format.c
str-utils.c
syslog-names.c
Expand Down
4 changes: 4 additions & 0 deletions lib/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ pkginclude_HEADERS += \
lib/atomic-gssize.h \
lib/block-ref-parser.h \
lib/cache.h \
lib/console.h \
lib/cfg.h \
lib/cfg-grammar.h \
lib/cfg-grammar-internal.h \
Expand Down Expand Up @@ -171,6 +172,7 @@ pkginclude_HEADERS += \
lib/service-management.h \
lib/seqnum.h \
lib/signal-handler.h \
lib/stackdump.h \
lib/str-format.h \
lib/str-utils.h \
lib/syslog-names.h \
Expand All @@ -195,6 +197,7 @@ lib_libsyslog_ng_la_SOURCES = \
lib/apphook.c \
lib/block-ref-parser.c \
lib/cache.c \
lib/console.c \
lib/cfg.c \
lib/cfg-args.c \
lib/cfg-block.c \
Expand Down Expand Up @@ -262,6 +265,7 @@ lib_libsyslog_ng_la_SOURCES = \
lib/scratch-buffers.c \
lib/serialize.c \
lib/service-management.c \
lib/stackdump.c \
lib/str-format.c \
lib/str-utils.c \
lib/syslog-names.c \
Expand Down
84 changes: 51 additions & 33 deletions lib/cfg-source.c
Original file line number Diff line number Diff line change
Expand Up @@ -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, 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; lines[line_ndx]; line_ndx++)
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);
Expand All @@ -84,78 +83,97 @@ _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;
}
}

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)
{
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;
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, 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], 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
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)
{
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)
{
Expand Down
2 changes: 2 additions & 0 deletions lib/cfg-source.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
167 changes: 167 additions & 0 deletions lib/console.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
/*
* Copyright (c) 2002-2012 Balabit
* Copyright (c) 1998-2012 Balázs Scheidler
* Copyright (c) 2024 Balázs Scheidler <[email protected]>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As an additional exemption you are allowed to compile & link against the
* OpenSSL libraries as published by the OpenSSL project. See the file
* COPYING for details.
*
*/
#include "console.h"
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <syslog.h>

GMutex console_lock;
gboolean console_present = FALSE;
gboolean using_initial_console = TRUE;
const gchar *console_prefix;

/**
* console_printf:
* @fmt: format string
* @...: arguments to @fmt
*
* This function sends a message to the client preferring to use the stderr
* channel as long as it is available and switching to using syslog() if it
* isn't. Generally the stderr channell will be available in the startup
* process and in the beginning of the first startup in the
* supervisor/daemon processes. Later on the stderr fd will be closed and we
* have to fall back to using the system log.
**/
void
console_printf(const gchar *fmt, ...)
{
gchar buf[2048];
va_list ap;

va_start(ap, fmt);
g_vsnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
if (console_is_present(FALSE))
fprintf(stderr, "%s: %s\n", console_prefix, buf);
else
{
openlog(console_prefix, LOG_PID, LOG_DAEMON);
syslog(LOG_CRIT, "%s\n", buf);
closelog();
}
}


/* NOTE: this is not synced with any changes and is just an indication whether we have a console */
gboolean
console_is_present(gboolean exclude_initial)
{
gboolean result;
/* the lock only serves a memory barrier but is not a real synchronization */
g_mutex_lock(&console_lock);
if (exclude_initial && using_initial_console)
result = FALSE;
else
result = console_present;
g_mutex_unlock(&console_lock);
return result;
}

/* set the current console to be our current stdin/out/err after we start up */
void
console_acquire_from_stdio(void)
{
g_assert(!console_is_present(FALSE));

g_mutex_lock(&console_lock);
console_present = TRUE;
g_mutex_unlock(&console_lock);
}

/* re-acquire a console after startup using an array of fds */
void
console_acquire_from_fds(gint fds[3])
{
const gchar *takeover_message_on_old_console = "[Console taken over, no further output here]\n";
g_assert(!console_is_present(TRUE));

if (using_initial_console)
{
(void) write(1, takeover_message_on_old_console, strlen(takeover_message_on_old_console));
}

g_mutex_lock(&console_lock);

dup2(fds[0], STDIN_FILENO);
dup2(fds[1], STDOUT_FILENO);
dup2(fds[2], STDERR_FILENO);

console_present = TRUE;
using_initial_console = FALSE;
g_mutex_unlock(&console_lock);
}

/**
* console_release:
*
* Use /dev/null as input/output/error. This function is idempotent, can be
* called any number of times without harm.
**/
void
console_release(void)
{
gint devnull_fd;

g_mutex_lock(&console_lock);

if (!console_present)
goto exit;

devnull_fd = open("/dev/null", O_RDONLY);
if (devnull_fd >= 0)
{
dup2(devnull_fd, STDIN_FILENO);
close(devnull_fd);
}
devnull_fd = open("/dev/null", O_WRONLY);
if (devnull_fd >= 0)
{
dup2(devnull_fd, STDOUT_FILENO);
dup2(devnull_fd, STDERR_FILENO);
close(devnull_fd);
}
clearerr(stdin);
clearerr(stdout);
clearerr(stderr);
console_present = FALSE;
using_initial_console = FALSE;

exit:
g_mutex_unlock(&console_lock);
}

void
console_global_init(const gchar *console_prefix_)
{
g_mutex_init(&console_lock);
console_prefix = console_prefix_;
}

void
console_global_deinit(void)
{
g_mutex_clear(&console_lock);
}
Loading
Loading