]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
eu-stacktrace WIP: command line args
authorSerhei Makarov <serhei@serhei.io>
Mon, 3 Apr 2023 15:10:44 +0000 (11:10 -0400)
committerSerhei Makarov <serhei@serhei.io>
Mon, 3 Apr 2023 15:10:44 +0000 (11:10 -0400)
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.

src/Makefile.am
src/stacktrace.c [new file with mode: 0644]

index 10d59a48386d0165185691581e40811238c3f0a1..05d5d2fab919d9bef070fcb0e612216b8653eaa8 100644 (file)
@@ -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 (file)
index 0000000..acb86a6
--- /dev/null
@@ -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 */
+}