~nabijaczleweli/febug

ref: 690c8f5b88a65cb0faf978118164190a7917fe5d febug/FreeBSD/libfebug.3 -rw-r--r-- 6.8 KiB
690c8f5b — наб autouploader Debian manpage update by job 401946 8 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
.\" Automatically generated from an mdoc input file.  Do not edit.
.\"" SPDX-License-Identifier: MIT
.TH "LIBFEBUG" "3" "January 20, 2021" "FreeBSD 12.1-RELEASE-p10" "FreeBSD Library Functions Manual"
.nh
.if n .ad l
.SH "NAME"
\fBfebug_start\fR(),
\fBfebug_end\fR(),
\fBfebug_register_type\fR(),
\fBfebug_wrap\fR(),
\fBfebug_unwrap\fR()
\- User-space debugfs ABI wrapper library
.SH "SYNOPSIS"
\fB#include <libfebug.h>\fR
.PP
library \(lqlibfebug\(rq
.PP
\fB#define FEBUG_DONT 0\fR
.br
\fB#define FEBUG_SOCKET \&"/var/run/febug.sock"\fR
.br
\fB#define FEBUG_SIGNUM SIGUSR2\fR
.PP
\fBgetenv("FEBUG_DONT")\fR
.br
\fBgetenv("FEBUG_SOCKET")\fR
.PP
\fIint febug_global_controlled_socket\fR
= -1;
.HP 4n
\fBvoid febug_start\fR();
.HP 4n
\fBvoid febug_start_path\fR(\fIconst\ char\ *\ path\fR);
.HP 4n
\fBvoid febug_debug_handler\fR(\fIint\fR);
.HP 4n
\fBvoid febug_register_type\fR(\fIuint64_t\ type\fR, \fIvoid\ (*formatter)(int,\ size_t)\fR);
.HP 4n
\fBvoid febug_wrap\fR(\fIuint64_t\ type\fR, \fIconst\ void\ *\ data\fR, \fIconst\ char\ *\ name\fR, \fI...\fR);
.HP 4n
\fBvoid febug_wrap_signal\fR(\fIuint64_t\ type\fR, \fIconst\ void\ *\ data\fR, \fIuint8_t\ signal\fR, \fIconst\ char\ *\ name\fR, \fI...\fR);
.HP 4n
\fBvoid febug_wrap_signalv\fR(\fIuint64_t\ type\fR, \fIconst\ void\ *\ data\fR, \fIuint8_t\ signal\fR, \fIconst\ char\ *\ name\fR, \fIva_list\ ap\fR);
.HP 4n
\fBvoid febug_unwrap\fR(\fIconst\ void\ *\ data\fR);
.HP 4n
\fBvoid febug_end\fR();
.SH "DESCRIPTION"
\fBlibfebug\fR
allows a programmer to simplify writing programs debuggable with
febug(8)
by presenting a high-level interface to
febug-abi(5).
.PP
There are three compile-time macros that allow a program to customise its behaviour:
.TP 8n
\fBFEBUG_DONT\fR
.br
If non-zero, all symbols become
\fBstatic\fR,
functions turn into no-ops, and therefore no symbols from libfebug.a/.so are imported at link-time; this is intended as a way to easily disable
febug(8)
integration completely on release builds.
.TP 8n
\fBFEBUG_SIGNUM\fR
.br
The signal to request from
febug(8)
when using
\fBfebug_wrap\fR().
Defaults to
\fRSIGUSR2\fR.
.TP 8n
\fBFEBUG_SOCKET\fR
.br
The path to connect to
febug(8)
on. Defaults to
\fI/var/run/febug.sock\fR.
.PP
There are two environment variables that allow a user to customise its behaviour:
.TP 8n
\fIFEBUG_DONT\fR
If set, don't try to connect to
febug(8),
so all library functions become no-ops.
.TP 8n
\fIFEBUG_SOCKET\fR
If set, use its value instead of
\fBFEBUG_SOCKET\fR
to connect to
febug(8)
.PP
To be debugged, a program needs to, first, call
\fBfebug_start_path\fR()
(likely via
\fBfebug_start\fR(),
which simply passes
\fBFEBUG_SOCKET\fR
.br
thereto) to connect to
febug(8),
which, if successful, will set
\fIfebug_global_controlled_socket\fR
appropriately.
.PP
The program needs to install
\fBfebug_debug_handler\fR()
(or a wrapper around it) as the signal handler for
\fBFEBUG_SIGNUM\fR
(and any other signals, if different ones are explicitly requested; if
\fRSIGKILL\fR,
some event loop that answers on
\fIfebug_global_controlled_socket\fR
must be in place). It's a no-op if
\fIfebug_global_controlled_socket\fR
is -1. This finishes set-up.
.PP
The program should register handlers for types of variables it wishes to handle by calling
\fBfebug_register_type\fR()
\[u2014] those type numbers should be consistent across the program, lest the wrong handler is called.
If no handler was registered for a type,
\fBfebug_debug_handler\fR()
will write 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
\fBfebug_debug_handler\fR()
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
\fIfebug_global_controlled_socket\fR
is -1.
.PP
At any time, when the program wishes to expose a variable, it can call
\fBfebug_wrap_signalv\fR()
(likely via
\fBfebug_wrap_signal\fR()
(likely via
\fBfebug_wrap\fR(),
which passes
\fBFEBUG_SIGNUM\fR
thereto)), which will send a
\fBfebug_message\fR
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
\fIfebug_global_controlled_socket\fR
is -1.
.PP
When the variable goes out of scope, the program should call
\fBfebug_unwrap\fR()
to send a
\fBstop_febug_message\fR
with the same data pointer as it did
\fBfebug_wrap\fR(),
to prevent reading random data that might no longer be mapped, or make sense.
It's a no-op if
\fIfebug_global_controlled_socket\fR
is -1.
.PP
When it wishes to stop being debugged, the program may call
\fBfebug_end\fR()
which will shutter and reset
\fIfebug_global_controlled_socket\fR,
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 FDs and free all mappings anyway.
.SH "EXAMPLES"
The following program sorts a string with
qsort(3)
but waits half a second between each comparison; the string can be inspected via a
febug(8)
mount:
.nf
.sp
.RS 6n
// SPDX-License-Identifier: MIT


#define _POSIX_C_SOURCE 200809L

#include <libfebug.h>

#include <signal.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.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() {
	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[] = "JVLOkgsYmhCyEFxouKzDNajivGlpWqbdBwnfTAXQcreRHPIUSMtZQWERTYUIOPqwertyuiop1234567890";
		febug_wrap(CSTRING_FEBUG_TP, data, "cool_data");

		qsort(data, strlen(data), 1, char_comp);
	}

	sleep(2);

	febug_end();
}
.RE
.fi
.SH "SEE ALSO"
febug-abi(5)
\[u2014] the ABI wrapped by this library.
.PP
libfebug++(3)
\[u2014] an equivalent C++ library.
.PP
libfebug++(3)
\[u2014] an equivalent Rust library.
.SH "AUTHORS"
Written by
\[u043D]\[u0430]\[u0431] <\fInabijaczleweli@nabijaczleweli.xyz\fR>
.SH "SPECIAL THANKS"
To all who support further development, in particular:
.PD 0
.TP 8n
\fB\(bu\fR
ThePhD
.TP 8n
\fB\(bu\fR
Embark Studios
.PD
.SH "REPORTING BUGS"
\fIfebug tracker\fR: \fBhttps://todo.sr.ht/~nabijaczleweli/febug\fR
.PP
febug mailing list:
<\fI~nabijaczleweli/febug@lists.sr.ht\fR>
archived at
\fBhttps://lists.sr.ht/~nabijaczleweli/febug\fR