]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
eu-stacktrace: use libebl register handling api
authorSerhei Makarov <serhei@serhei.io>
Thu, 5 Dec 2024 21:16:00 +0000 (16:16 -0500)
committerSerhei Makarov <serhei@serhei.io>
Thu, 5 Dec 2024 21:16:00 +0000 (16:16 -0500)
Change the sample_set_initial_registers callback in eu-stacktrace to
use the proper libebl ebl_set_initial_registers_sample function.

* src/Makefile.am (stacktrace_LDADD): Add libebl.
* src/stacktrace.c (sample_registers_cb): New function,
  though identical to pid_thread_state_registers_cb.
  (sample_set_initial_registers): Invoke
  ebl_set_initial_registers_sample instead of containing
  platform-specific code directly.

src/Makefile.am
src/stacktrace.c

index 6bdf2dfbcc338a51938315adec9c0d40d65e82bf..20ee3e8f49621e4c6e0019bbb54e25fd1d5a8b60 100644 (file)
@@ -99,7 +99,7 @@ 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)
 if ENABLE_STACKTRACE
-stacktrace_LDADD = $(libelf) $(libdw) $(libeu) $(argp_LDADD)
+stacktrace_LDADD = $(libebl) $(libelf) $(libdw) $(libeu) $(argp_LDADD)
 endif
 elfcompress_LDADD = $(libebl) $(libelf) $(libdw) $(libeu) $(argp_LDADD)
 elfclassify_LDADD = $(libelf) $(libdw) $(libeu) $(argp_LDADD)
index 438cb1dd0d389f2dadc140bf4d3968448ca14ec9..3813e3409970189bb59d61889b002dbca7c7fa0a 100644 (file)
  * Includes: libdwfl data structures *
  *************************************/
 
+#include ELFUTILS_HEADER(ebl)
 /* #include ELFUTILS_HEADER(dwfl) */
 #include "../libdwfl/libdwflP.h"
-/* XXX: Private header needed for find_procfile, sysprof_init_dwfl */
+/* XXX: Private header needed for find_procfile, sysprof_init_dwfl,
+   sample_set_initial_registers. */
 
 /*************************************
  * Includes: sysprof data structures *
@@ -573,42 +575,41 @@ sample_memory_read (Dwfl *dwfl, Dwarf_Addr addr, Dwarf_Word *result, void *arg)
   return true;
 }
 
-/* TODO: Need to generalize this code beyond x86 architectures. */
+/* Implement the ebl_set_initial_registers_sample setfunc callback.  */
 static bool
-sample_set_initial_registers (Dwfl_Thread *thread, void *thread_arg)
+sample_registers_cb (int firstreg, unsigned nregs,
+                     const Dwarf_Word *regs, void *arg)
 {
-  /* The following facts are needed to translate x86 registers correctly:
-     - perf register order seen in linux arch/x86/include/uapi/asm/perf_regs.h
-       The registers array is built in the same order as the enum!
-       (See the code in tools/perf/util/intel-pt.c intel_pt_add_gp_regs().)
-     - sysprof libsysprof/perf-event-stream-private.h records all registers
-       except segment and flags.
-       - TODO: Should include the perf regs mask in sysprof data and
-         translate registers in fully-general fashion, removing this assumption.
-     - dwarf register order seen in elfutils backends/{x86_64,i386}_initreg.c;
-       and it's a fairly different register order!
-
-     For comparison, you can study codereview.qt-project.org/gitweb?p=qt-creator/perfparser.git;a=blob;f=app/perfregisterinfo.cpp;hb=HEAD
-     and follow the code which uses those tables of magic numbers.
-     But it's better to follow original sources of truth for this. */
-  struct __sample_arg *sample_arg = (struct __sample_arg *)thread_arg;
-  bool is_abi32 = (sample_arg->abi == PERF_SAMPLE_REGS_ABI_32);
-  static const int regs_i386[] = {0, 2, 3, 1, 7/*sp*/, 6, 4, 5, 8/*ip*/};
-  static const int regs_x86_64[] = {0, 3, 2, 1, 4, 5, 6, 7/*sp*/, 9, 10, 11, 12, 13, 14, 15, 16, 8/*ip*/};
-  const int *reg_xlat = is_abi32 ? regs_i386 : regs_x86_64;
-  int n_regs = is_abi32 ? 9 : 17;
-  dwfl_thread_state_register_pc (thread, sample_arg->pc);
-  if (sample_arg->n_regs < (uint64_t)n_regs && show_failures)
-    fprintf(stderr, N_("sample_set_initial_regs: n_regs=%ld, expected %d\n"),
-           sample_arg->n_regs, n_regs);
-  for (int i = 0; i < n_regs; i++)
+  /* TODO Identical to pid_thread_state_registers_cb in linux-pid-attach.c. */
+  Dwfl_Thread *thread = (Dwfl_Thread *)arg;
+  if (firstreg == -1)
     {
-      int j = reg_xlat[i];
-      if (j < 0) continue;
-      if (sample_arg->n_regs <= (uint64_t)j) continue;
-      dwfl_thread_state_registers (thread, i, 1, &sample_arg->regs[j]);
+      assert (nregs == 1);
+      dwfl_thread_state_register_pc (thread, *regs);
+      return true;
     }
-  return true;
+  else if (firstreg == -2)
+    {
+      assert (nregs == 1);
+      dwfl_thread_state_registers (thread, firstreg, nregs, regs);
+      return true;
+    }
+  assert (nregs > 0);
+  return dwfl_thread_state_registers (thread, firstreg, nregs, regs);
+}
+
+static bool
+sample_set_initial_registers (Dwfl_Thread *thread, void *arg)
+{
+  struct __sample_arg *sample_arg = (struct __sample_arg *)arg;
+  dwfl_thread_state_register_pc (thread, sample_arg->pc);
+  Dwfl_Process *process = thread->process;
+  Ebl *ebl = process->ebl;
+  /* XXX Sysprof provides exactly the required registers for unwinding: */
+  uint64_t regs_mask = ebl_perf_frame_regs_mask (ebl);
+  return ebl_set_initial_registers_sample
+    (ebl, sample_arg->regs, sample_arg->n_regs, regs_mask, sample_arg->abi,
+     sample_registers_cb, thread);
 }
 
 static void