Skip to content

Commit f3fbeb4

Browse files
authored
libbpf-tools: convert BCC syscount to BPF CO-RE version
Add a new libbpf-based tool, syscount, and add some helpers which may be used by other tools. Namely, * syscall_helpers.{c,h}: convert system call numbers to names * errno_helpers.{c,h}: convert errno names to numbers The helpers contain pre-generated tables for x86_64 (which will be outdated at some point, so require to be updated on demand), but for other architectures require additional tools: syscall helpers require the ausyscall(1) tool, and errno helpers require errno(1) utility from the moreutils package. So, if you run on non-x86_64, then either install these tools, or use numeric values. If possible, use bpf_map_lookup_and_delete_batch function to read and reset values in the data map. This is a raceless way to obtain all values. If the function is not available, e.g., for old kernels, then fall back to the old version which can loose some syscalls (happened between reading values and resetting them). Signed-off-by: Anton Protopopov <[email protected]>
1 parent b20f5e7 commit f3fbeb4

File tree

12 files changed

+1416
-5
lines changed

12 files changed

+1416
-5
lines changed

libbpf-tools/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@
44
/filelife
55
/opensnoop
66
/runqslower
7+
/syscount
78
/vfsstat
89
/xfsslower

libbpf-tools/Makefile

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,22 @@ INCLUDES := -I$(OUTPUT)
99
CFLAGS := -g -O2 -Wall
1010
ARCH := $(shell uname -m | sed 's/x86_64/x86/')
1111

12-
APPS = drsnoop execsnoop filelife opensnoop runqslower vfsstat xfsslower
12+
APPS = \
13+
drsnoop \
14+
execsnoop \
15+
filelife \
16+
opensnoop \
17+
runqslower \
18+
syscount \
19+
vfsstat \
20+
xfsslower \
21+
#
22+
23+
COMMON_OBJ = \
24+
$(OUTPUT)/trace_helpers.o \
25+
$(OUTPUT)/syscall_helpers.o \
26+
$(OUTPUT)/errno_helpers.o \
27+
#
1328

1429
.PHONY: all
1530
all: $(APPS)
@@ -32,7 +47,7 @@ $(OUTPUT) $(OUTPUT)/libbpf:
3247
$(call msg,MKDIR,$@)
3348
$(Q)mkdir -p $@
3449

35-
$(APPS): %: $(OUTPUT)/%.o $(LIBBPF_OBJ) $(OUTPUT)/trace_helpers.o | $(OUTPUT)
50+
$(APPS): %: $(OUTPUT)/%.o $(LIBBPF_OBJ) $(COMMON_OBJ) | $(OUTPUT)
3651
$(call msg,BINARY,$@)
3752
$(Q)$(CC) $(CFLAGS) $^ -lelf -lz -o $@
3853

libbpf-tools/drsnoop.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ int main(int argc, char **argv)
167167

168168
obj = drsnoop_bpf__open();
169169
if (!obj) {
170-
fprintf(stderr, "failed to open and/or load BPF ojbect\n");
170+
fprintf(stderr, "failed to open and/or load BPF object\n");
171171
return 1;
172172
}
173173

libbpf-tools/errno_helpers.c

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2+
// Copyright (c) 2020 Anton Protopopov
3+
#include <stdlib.h>
4+
#include <limits.h>
5+
#include <string.h>
6+
#include <errno.h>
7+
#include <stdio.h>
8+
9+
#define warn(...) fprintf(stderr, __VA_ARGS__)
10+
11+
#ifdef __x86_64__
12+
static int errno_by_name_x86_64(const char *errno_name)
13+
{
14+
15+
#define strcase(X, N) if (!strcmp(errno_name, (X))) return N
16+
17+
strcase("EPERM", 1);
18+
strcase("ENOENT", 2);
19+
strcase("ESRCH", 3);
20+
strcase("EINTR", 4);
21+
strcase("EIO", 5);
22+
strcase("ENXIO", 6);
23+
strcase("E2BIG", 7);
24+
strcase("ENOEXEC", 8);
25+
strcase("EBADF", 9);
26+
strcase("ECHILD", 10);
27+
strcase("EAGAIN", 11);
28+
strcase("EWOULDBLOCK", 11);
29+
strcase("ENOMEM", 12);
30+
strcase("EACCES", 13);
31+
strcase("EFAULT", 14);
32+
strcase("ENOTBLK", 15);
33+
strcase("EBUSY", 16);
34+
strcase("EEXIST", 17);
35+
strcase("EXDEV", 18);
36+
strcase("ENODEV", 19);
37+
strcase("ENOTDIR", 20);
38+
strcase("EISDIR", 21);
39+
strcase("EINVAL", 22);
40+
strcase("ENFILE", 23);
41+
strcase("EMFILE", 24);
42+
strcase("ENOTTY", 25);
43+
strcase("ETXTBSY", 26);
44+
strcase("EFBIG", 27);
45+
strcase("ENOSPC", 28);
46+
strcase("ESPIPE", 29);
47+
strcase("EROFS", 30);
48+
strcase("EMLINK", 31);
49+
strcase("EPIPE", 32);
50+
strcase("EDOM", 33);
51+
strcase("ERANGE", 34);
52+
strcase("EDEADLK", 35);
53+
strcase("EDEADLOCK", 35);
54+
strcase("ENAMETOOLONG", 36);
55+
strcase("ENOLCK", 37);
56+
strcase("ENOSYS", 38);
57+
strcase("ENOTEMPTY", 39);
58+
strcase("ELOOP", 40);
59+
strcase("ENOMSG", 42);
60+
strcase("EIDRM", 43);
61+
strcase("ECHRNG", 44);
62+
strcase("EL2NSYNC", 45);
63+
strcase("EL3HLT", 46);
64+
strcase("EL3RST", 47);
65+
strcase("ELNRNG", 48);
66+
strcase("EUNATCH", 49);
67+
strcase("ENOCSI", 50);
68+
strcase("EL2HLT", 51);
69+
strcase("EBADE", 52);
70+
strcase("EBADR", 53);
71+
strcase("EXFULL", 54);
72+
strcase("ENOANO", 55);
73+
strcase("EBADRQC", 56);
74+
strcase("EBADSLT", 57);
75+
strcase("EBFONT", 59);
76+
strcase("ENOSTR", 60);
77+
strcase("ENODATA", 61);
78+
strcase("ETIME", 62);
79+
strcase("ENOSR", 63);
80+
strcase("ENONET", 64);
81+
strcase("ENOPKG", 65);
82+
strcase("EREMOTE", 66);
83+
strcase("ENOLINK", 67);
84+
strcase("EADV", 68);
85+
strcase("ESRMNT", 69);
86+
strcase("ECOMM", 70);
87+
strcase("EPROTO", 71);
88+
strcase("EMULTIHOP", 72);
89+
strcase("EDOTDOT", 73);
90+
strcase("EBADMSG", 74);
91+
strcase("EOVERFLOW", 75);
92+
strcase("ENOTUNIQ", 76);
93+
strcase("EBADFD", 77);
94+
strcase("EREMCHG", 78);
95+
strcase("ELIBACC", 79);
96+
strcase("ELIBBAD", 80);
97+
strcase("ELIBSCN", 81);
98+
strcase("ELIBMAX", 82);
99+
strcase("ELIBEXEC", 83);
100+
strcase("EILSEQ", 84);
101+
strcase("ERESTART", 85);
102+
strcase("ESTRPIPE", 86);
103+
strcase("EUSERS", 87);
104+
strcase("ENOTSOCK", 88);
105+
strcase("EDESTADDRREQ", 89);
106+
strcase("EMSGSIZE", 90);
107+
strcase("EPROTOTYPE", 91);
108+
strcase("ENOPROTOOPT", 92);
109+
strcase("EPROTONOSUPPORT", 93);
110+
strcase("ESOCKTNOSUPPORT", 94);
111+
strcase("ENOTSUP", 95);
112+
strcase("EOPNOTSUPP", 95);
113+
strcase("EPFNOSUPPORT", 96);
114+
strcase("EAFNOSUPPORT", 97);
115+
strcase("EADDRINUSE", 98);
116+
strcase("EADDRNOTAVAIL", 99);
117+
strcase("ENETDOWN", 100);
118+
strcase("ENETUNREACH", 101);
119+
strcase("ENETRESET", 102);
120+
strcase("ECONNABORTED", 103);
121+
strcase("ECONNRESET", 104);
122+
strcase("ENOBUFS", 105);
123+
strcase("EISCONN", 106);
124+
strcase("ENOTCONN", 107);
125+
strcase("ESHUTDOWN", 108);
126+
strcase("ETOOMANYREFS", 109);
127+
strcase("ETIMEDOUT", 110);
128+
strcase("ECONNREFUSED", 111);
129+
strcase("EHOSTDOWN", 112);
130+
strcase("EHOSTUNREACH", 113);
131+
strcase("EALREADY", 114);
132+
strcase("EINPROGRESS", 115);
133+
strcase("ESTALE", 116);
134+
strcase("EUCLEAN", 117);
135+
strcase("ENOTNAM", 118);
136+
strcase("ENAVAIL", 119);
137+
strcase("EISNAM", 120);
138+
strcase("EREMOTEIO", 121);
139+
strcase("EDQUOT", 122);
140+
strcase("ENOMEDIUM", 123);
141+
strcase("EMEDIUMTYPE", 124);
142+
strcase("ECANCELED", 125);
143+
strcase("ENOKEY", 126);
144+
strcase("EKEYEXPIRED", 127);
145+
strcase("EKEYREVOKED", 128);
146+
strcase("EKEYREJECTED", 129);
147+
strcase("EOWNERDEAD", 130);
148+
strcase("ENOTRECOVERABLE", 131);
149+
strcase("ERFKILL", 132);
150+
strcase("EHWPOISON", 133);
151+
152+
#undef strcase
153+
154+
return -1;
155+
156+
}
157+
#endif
158+
159+
/* Try to find the errno number using the errno(1) program */
160+
static int errno_by_name_dynamic(const char *errno_name)
161+
{
162+
int len = strlen(errno_name);
163+
int err, number = -1;
164+
char buf[128];
165+
char cmd[64];
166+
char *end;
167+
long val;
168+
FILE *f;
169+
170+
/* sanity check to not call popen with random input */
171+
for (int i = 0; i < len; i++) {
172+
if (errno_name[i] < 'A' || errno_name[i] > 'Z') {
173+
warn("errno_name contains invalid char 0x%02x: %s\n",
174+
errno_name[i], errno_name);
175+
return -1;
176+
}
177+
}
178+
179+
snprintf(cmd, sizeof(cmd), "errno %s", errno_name);
180+
f = popen(cmd, "r");
181+
if (!f) {
182+
warn("popen: %s: %s\n", cmd, strerror(errno));
183+
return -1;
184+
}
185+
186+
if (!fgets(buf, sizeof(buf), f)) {
187+
goto close;
188+
} else if (ferror(f)) {
189+
warn("fgets: %s\n", strerror(errno));
190+
goto close;
191+
}
192+
193+
// expecting "<name> <number> <description>"
194+
if (strncmp(errno_name, buf, len) || strlen(buf) < len+2) {
195+
warn("expected '%s': %s\n", errno_name, buf);
196+
goto close;
197+
}
198+
errno = 0;
199+
val = strtol(buf+len+2, &end, 10);
200+
if (errno || end == (buf+len+2) || number < 0 || number > INT_MAX) {
201+
warn("can't parse the second column, expected int: %s\n", buf);
202+
goto close;
203+
}
204+
number = val;
205+
206+
close:
207+
err = pclose(f);
208+
if (err < 0)
209+
warn("pclose: %s\n", strerror(errno));
210+
#ifndef __x86_64__
211+
/* Ignore the error for x86_64 where we have a table compiled in */
212+
else if (err && WEXITSTATUS(err) == 127) {
213+
warn("errno(1) required for errno name/number mapping\n");
214+
} else if (err) {
215+
warn("errno(1) exit status (see wait(2)): 0x%x\n", err);
216+
}
217+
#endif
218+
return number;
219+
}
220+
221+
int errno_by_name(const char *errno_name)
222+
{
223+
#ifdef __x86_64__
224+
int err;
225+
226+
err = errno_by_name_x86_64(errno_name);
227+
if (err >= 0)
228+
return err;
229+
#endif
230+
231+
return errno_by_name_dynamic(errno_name);
232+
}

libbpf-tools/errno_helpers.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
2+
#ifndef __ERRNO_HELPERS_H
3+
#define __ERRNO_HELPERS_H
4+
5+
int errno_by_name(const char *errno_name);
6+
7+
#endif /* __ERRNO_HELPERS_H */

libbpf-tools/filelife.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ int main(int argc, char **argv)
127127

128128
obj = filelife_bpf__open();
129129
if (!obj) {
130-
fprintf(stderr, "failed to open and/or load BPF ojbect\n");
130+
fprintf(stderr, "failed to open and/or load BPF object\n");
131131
return 1;
132132
}
133133

0 commit comments

Comments
 (0)