| LIBFEBUG(3) | Library Functions Manual | LIBFEBUG(3) |
febug_start(), febug_end(),
febug_register_type(),
febug_wrap(), febug_unwrap()
—
#include
<libfebug.h>
cc
-lfebug
…
#define FEBUG_DONT 0
#define FEBUG_SOCKET "/var/run/febug.sock"
#define FEBUG_SIGNUM SIGUSR2
getenv("FEBUG_DONT");
getenv("FEBUG_SOCKET");
int febug_global_controlled_socket
= -1;
void febug_start();
void
febug_start_path(const
char * path);
void
febug_debug_handler(int);
void
febug_register_type(uint64_t
type, void
(*formatter)(int, size_t));
void
febug_wrap(uint64_t
type, const void *
data, const char *
name, ...);
void
febug_wrap_signal(uint64_t
type, const void *
data, uint8_t
signal, const char *
name, ...);
void
febug_wrap_signalv(uint64_t
type, const void *
data, uint8_t
signal, const char *
name, va_list
ap);
void
febug_unwrap(const
void * data);
void
febug_end();
There are three compile-time macros that allow customising
libfebug behaviour:
FEBUG_DONTFEBUG_SIGNUMfebug_wrap(). Defaults to
SIGUSR2.FEBUG_SOCKETThere are two environment variables that allow a user to customise its behaviour:
FEBUG_DONTFEBUG_SOCKETFEBUG_SOCKET to connect to
febug(8).To be debugged, a program needs to, first, call
febug_start_path() (likely via
febug_start(), which simply passes
FEBUG_SOCKET thereto) to
connect to febug(8), which, if
successful, will set febug_global_controlled_socket
appropriately.
The program needs to install
febug_debug_handler() (or a wrapper around it) as
the signal handler for FEBUG_SIGNUM (and any other
signals, if different ones are explicitly requested); if notifications are
disabled (by requesting SIGKILL), some event loop
that answers on febug_global_controlled_socket must be
in place. It's a no-op if
febug_global_controlled_socket is
-1.
The program should register handlers for types of variables it
wishes to handle by calling febug_register_type()
— those type numbers should be consistent across the program, lest
the wrong handler is called. If no handler was registered for a type,
febug_debug_handler() will instead return a generic
"not found" message. The handler takes the write end of the pipe
as the first argument, and the variable ID as the second; it shouldn't close
the pipe, as that is done by febug_debug_handler()
regardless, and the program would then run the risk of closing another file
with the same descriptor simultaneously opened by another thread. It's a
no-op if febug_global_controlled_socket is
-1.
At any time, when the program wishes to expose a variable, it can
call febug_wrap_signalv() (likely via
febug_wrap_signal() (likely via
febug_wrap(), which passes
FEBUG_SIGNUM thereto)),
which will send a febug_message with the specified type
and signal numbers, ID equal to the data pointer, and name formatted
according to
printf(3).
It's a no-op if febug_global_controlled_socket is
-1.
When the variable goes out of scope, the program should call
febug_unwrap() to send a
stop_febug_message with the same data pointer as it
did febug_wrap(), to prevent reading random data
that might no longer be mapped, or make sense. It's a no-op if
febug_global_controlled_socket is
-1.
When it wishes to stop being debugged, the program may call
febug_end() which will shut and reset
febug_global_controlled_socket, if any, and deallocate
the type→handler map. The program may omit this if it'd be the last
thing it did before exiting, since the kernel will close all file
descriptors and free all mappings anyway.
// SPDX-License-Identifier: MIT
#define _POSIX_C_SOURCE 200809L
#include <libfebug.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#define CSTRING_FEBUG_TP 420
static void cstring_febug_formatter(int fd, size_t data) {
const char * str = (const char *)data;
dprintf(fd, "%s\n", str);
}
static int char_comp(const void * lhs, const void * rhs) {
const struct timespec half_second = {0, 500 * 1000 * 1000};
nanosleep(&half_second, 0);
return *(const char *)lhs - *(const char *)rhs;
}
int main(void) {
febug_start();
febug_register_type(CSTRING_FEBUG_TP, cstring_febug_formatter);
struct sigaction handler;
memset(&handler, 0, sizeof(handler));
handler.sa_handler = febug_debug_handler;
if(sigaction(FEBUG_SIGNUM, &handler, 0) == -1) {
fprintf(stderr, "sigaction: %s\n", strerror(errno));
return 1;
}
{
__attribute__((__cleanup__(febug_unwrap))) char data[] =
"JVLOkgsYmhCyEFxouKzDNajivGlpWqbdBwnfTAXQcreRHPIUSMtZQWERTYUIOPqwertyuiop"
"1234567890";
febug_wrap(CSTRING_FEBUG_TP, data, "cool_data");
qsort(data, strlen(data), 1, char_comp);
}
sleep(2);
febug_end();
}
febug mailing list: <~nabijaczleweli/febug@lists.sr.ht>, archived at https://lists.sr.ht/~nabijaczleweli/febug
| June 12, 2023 | febug 0.2.1 |