diff options
author | Serhei Makarov <serhei@serhei.io> | 2023-04-03 11:10:44 -0400 |
---|---|---|
committer | Serhei Makarov <serhei@serhei.io> | 2023-04-03 11:10:44 -0400 |
commit | 90b72aea202a676747391f385e0a132aee31e426 (patch) | |
tree | 5b00951ec7f4806dffc1ab160b039962760d1055 | |
parent | b2871fa8d430e2c5fb39e3ebc6745ea32f1bddb4 (diff) | |
download | elfutils-90b72aea202a676747391f385e0a132aee31e426.tar.gz |
eu-stacktrace WIP: command line args
eu-stacktrace is (will be) a utility to process a stream of stack
samples (such as those obtained from PERF_EVENT_SAMPLE) into a stream
of stack traces (such as those obtained from PERF_EVENT_CALLCHAIN),
freeing various profiling utilities from having to implement their own
backtracing logic.
-rw-r--r-- | src/Makefile.am | 5 | ||||
-rw-r--r-- | src/stacktrace.c | 137 |
2 files changed, 140 insertions, 2 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 10d59a48..05d5d2fa 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -26,8 +26,8 @@ AM_CPPFLAGS += -I$(srcdir)/../libelf -I$(srcdir)/../libebl \ AM_LDFLAGS = -Wl,-rpath-link,../libelf:../libdw $(STACK_USAGE_NO_ERROR) bin_PROGRAMS = readelf nm size strip elflint findtextrel addr2line \ - elfcmp objdump ranlib strings ar unstrip stack elfcompress \ - elfclassify + elfcmp objdump ranlib strings ar unstrip stack stacktrace \ + elfcompress elfclassify noinst_LIBRARIES = libar.a @@ -82,6 +82,7 @@ strings_LDADD = $(libelf) $(libeu) $(argp_LDADD) ar_LDADD = libar.a $(libelf) $(libeu) $(argp_LDADD) $(obstack_LIBS) unstrip_LDADD = $(libebl) $(libelf) $(libdw) $(libeu) $(argp_LDADD) stack_LDADD = $(libebl) $(libelf) $(libdw) $(libeu) $(argp_LDADD) $(demanglelib) +stacktrace_LDADD = elfcompress_LDADD = $(libebl) $(libelf) $(libdw) $(libeu) $(argp_LDADD) elfclassify_LDADD = $(libelf) $(libdw) $(libeu) $(argp_LDADD) diff --git a/src/stacktrace.c b/src/stacktrace.c new file mode 100644 index 00000000..acb86a60 --- /dev/null +++ b/src/stacktrace.c @@ -0,0 +1,137 @@ +/* Process a stream of stack samples into stack traces. + Copyright (C) 2023 Red Hat, Inc. + This file is part of elfutils. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + elfutils 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> +#include <argp.h> +#include <stdio.h> +#include <string.h> + +static char *input_path = NULL; +static char *output_path = NULL; + +#define MODE_OPTS "none/passthru" +#define MODE_NONE 0x0 +#define MODE_PASSTHRU 0x1 +#define MODE_NAIVE 0x2 +#define MODE_CACHING 0x3 +static int processing_mode; + +#define FORMAT_OPTS "sysprof" +#define FORMAT_PERF 0x1 +#define FORMAT_SYSPROF 0x2 +static int input_format; + +static error_t +parse_opt (int key, char *arg __attribute__ ((unused)), + struct argp_state *state) +{ + switch (key) + { + case 'i': + input_path = arg; + break; + + case 'o': + output_path = arg; + break; + + case 'm': + if (strcmp (arg, "none") == 0) + { + processing_mode = MODE_NONE; + } + else if (strcmp (arg, "passthru") == 0) + { + processing_mode = MODE_PASSTHRU; + } + else + { + argp_error (state, N_("Unsupported -m '%s', should be " MODE_OPTS "."), arg); + } + break; + + case 'f': + if (strcmp (arg, "sysprof") == 0) + { + input_format = FORMAT_SYSPROF; + } + else + { + argp_error (state, N_("Unsupported -f '%s', should be " FORMAT_OPTS "."), arg); + } + break; + + case ARGP_KEY_END: + if (input_path == NULL) + argp_error (state, N_("-i PATH needs an input file or FIFO.")); + + if (output_path == NULL) + argp_error (state, N_("-o PATH needs an output path or FIFO.")); + + if (processing_mode == 0) + processing_mode = MODE_PASSTHRU; + + if (input_format == 0) + input_format = FORMAT_SYSPROF; + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +int +main (int argc, char **argv) +{ + /* Set locale. */ + (void) setlocale (LC_ALL, ""); + + const struct argp_option options[] = + { + { NULL, 0, NULL, 0, N_("Input and output selection options:"), 0 }, + { "input", 'i', "PATH", 0, + N_("File or FIFO to read stack samples from"), 0 }, + /* TODO: Should also support taking an FD for fork/exec pipes. */ + { "output", 'o', "PATH", 0, + N_("File or FIFO to send stack traces to"), 0 }, + + { NULL, 0, NULL, 0, N_("Processing options:"), 0 }, + { "mode", 'm', MODE_OPTS, 0, + N_("Processing mode, default 'passthru'"), 0 }, + /* TODO: Should also support 'naive', 'caching'. */ + /* TODO: Add an option to control stack-stitching. */ + { "format", 'f', FORMAT_OPTS, 0, + N_("Input data format, default 'sysprof'"), 0 }, + /* TODO: Add an option to control output data format separately, + shift to I/O selection section. */ + { NULL, 0, NULL, 0, NULL, 0 } + }; + + const struct argp argp = + { + .options = options, + .parser = parse_opt, + .doc = N_("Process a stream of stack samples into stack traces.\n\ +\n\ +Utility is a work-in-progress, see README.eu-stacktrace in the source branch.") + }; + + argp_parse(&argp, argc, argv, 0, NULL, NULL); + + /* hello world */ +} |