summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSerhei Makarov <serhei@serhei.io>2023-04-03 11:10:44 -0400
committerSerhei Makarov <serhei@serhei.io>2023-04-03 11:10:44 -0400
commit90b72aea202a676747391f385e0a132aee31e426 (patch)
tree5b00951ec7f4806dffc1ab160b039962760d1055
parentb2871fa8d430e2c5fb39e3ebc6745ea32f1bddb4 (diff)
downloadelfutils-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.am5
-rw-r--r--src/stacktrace.c137
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 */
+}