quark-btf.c (224 lines of code) (raw):

// SPDX-License-Identifier: Apache-2.0 /* Copyright (c) 2024 Elastic NV */ #include <err.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <strings.h> #include <unistd.h> #include <sys/wait.h> #include "quark.h" #define MAN_QUARK_BTF #include "manpages.h" static int bflag; static int fflag; static int gflag; static int lflag; static void disply_version(void) { printf("%s-%s\n", program_invocation_short_name, QUARK_VERSION); printf("License: Apache-2.0\n"); printf("Copyright (c) 2024 Elastic NV\n"); exit(0); } static void usage(void) { fprintf(stderr, "usage: %s -h\n", program_invocation_short_name); fprintf(stderr, "usage: %s [-bv] [targets...]\n", program_invocation_short_name); fprintf(stderr, "usage: %s [-bv] [-f btf_file]\n", program_invocation_short_name); fprintf(stderr, "usage: %s [-bv] [-l version]\n", program_invocation_short_name); fprintf(stderr, "usage: %s [-v] [-g btf_file name version]\n", program_invocation_short_name); fprintf(stderr, "usage: %s -V\n", program_invocation_short_name); exit(1); } static size_t calc_longest(struct quark_btf *qbtf) { struct quark_btf_target *ta; size_t longest; for (ta = qbtf->targets, longest = 0; ta->dotname != NULL; ta++) if (strlen(ta->dotname) > longest) longest = strlen(ta->dotname); return (longest); } static void printit(const char *t, ssize_t off, size_t longest) { printf("%-*s ", (int)longest, t); if (off == -1) printf("U"); else printf("%-7zd", off); if (bflag && off != -1) printf("%zd", off * 8); printf("\n"); fflush(stdout); } static struct quark_btf_target * target_lookup(struct quark_btf *qbtf, const char *dotname) { struct quark_btf_target *ta; for (ta = qbtf->targets; ta->dotname != NULL; ta++) { if (!strcmp(ta->dotname, dotname)) return (ta); } return (NULL); } static void quark_btf_printit(struct quark_btf *qbtf, int argc, char *argv[]) { struct quark_btf_target *ta; size_t longest; int i; if (argc == 0) longest = calc_longest(qbtf); else { for (i = 0, longest = 0; i < argc; i++) if (strlen(argv[i]) > longest) longest = strlen(argv[i]); } /* Print them all */ if (argc == 0) { for (ta = qbtf->targets; ta->dotname != NULL; ta++) printit(ta->dotname, ta->offset, longest); return; } /* Print only the requested ones if argc */ for (i = 0; i < argc; i++) { ta = target_lookup(qbtf, argv[i]); if (ta == NULL) errx(1, "dotname `%s` doesn't exist, " "did you type it correctly?", argv[i]); printit(ta->dotname, ta->offset, longest); } } static int gen_c(int argc, char *argv[]) { char *p; const char *path, *distro, *version; struct quark_btf *qbtf; struct quark_btf_target *ta; char namebuf[1024]; size_t longest; if (argc != 3) usage(); path = argv[0]; distro = argv[1]; version = argv[2]; /* * First we figure the name of the structure, this is basically an * escaped concat(distro, version) */ if (snprintf(namebuf, sizeof(namebuf), "%s_%s", distro, version) >= (int)sizeof(namebuf)) errx(1, "distro + version is too long"); /* * Escape invalid characters since this will be the name of the * structure */ for (p = namebuf; *p != 0; p++) { if (*p == '.' || *p == '-' || *p == '/') *p = '_'; } if ((qbtf = quark_btf_open2(path, version)) == NULL) err(1, "quark_btf_open"); /* * Declare the structure as static to make sure it gets referenced * later in all_btfs[]. */ longest = calc_longest(qbtf); printf("static struct quark_btf %s = {\n", namebuf); printf("\t\"%s\", {\n", version); for (ta = qbtf->targets; /* NADA */; ta++) { const char *dotname; size_t off; printf("\t{ "); if (ta->dotname != NULL) { off = 1; dotname = ta->dotname; printf("\"%s\",", ta->dotname); } else { off = 3; dotname = "NULL"; printf("NULL,"); } printf("%-*s%-5zd },\n", (int)longest - (int)strlen(dotname) + (int)off, " ", ta->offset); if (ta->dotname == NULL) break; } printf("\t}\n};\n\n"); quark_btf_close(qbtf); return (0); } static int hub_lookup(int argc, char *argv[]) { struct quark_btf *qbtf; if (argc != 1) usage(); qbtf = quark_btf_open_hub(argv[0]); if (qbtf == NULL) errx(1, "can't match `%s` with any kernel in btfhub", optarg); printf("%s\n", qbtf->kname); if (quark_verbose) quark_btf_printit(qbtf, 0, NULL); quark_btf_close(qbtf); return (0); } static int doit(const char *path, int argc, char *argv[]) { struct quark_btf *qbtf; if (path == NULL) qbtf = quark_btf_open(); else qbtf = quark_btf_open2(path, "temp"); if (qbtf == NULL) err(1, "can't open btf, maybe some offsets failed"); quark_btf_printit(qbtf, argc, argv); quark_btf_close(qbtf); return (0); } int main(int argc, char *argv[]) { int ch; const char *path = NULL; while ((ch = getopt(argc, argv, "bf:ghlvV")) != -1) { switch (ch) { case 'b': bflag = 1; break; case 'g': gflag = 1; break; case 'h': if (isatty(STDOUT_FILENO)) display_man(); else usage(); break; /* NOTREACHED */ case 'l': lflag = 1; break; case 'f': if (optarg == NULL) usage(); path = optarg; fflag = 1; break; case 'v': quark_verbose++; break; case 'V': disply_version(); break; default: usage(); } } argc -= optind; argv += optind; if ((fflag + gflag + lflag) > 1) usage(); /* path distro version */ if (gflag) return (gen_c(argc, argv)); if (lflag) return (hub_lookup(argc, argv)); return (doit(path, argc, argv)); }