One need identified from implementing patches for downstream profiling
tools to adopt libdwfl_stacktrace is that libebl per-architecture
constants are not exposed to external projects.

TODO(REVIEW): First iteration of this patch for RFC: the APIs are part
of libdwfl_stacktrace, and return error values on architectures that
lack a sample_regs backend (to signal that libdwflst is not yet
supported there). This is most useful for the profiler use case, but
need to double-check if it makes sense to provide a more general arch
constant API in libdwfl/libdw.

* libdwfl_stacktrace/libdwfl_stacktrace.h
  (dwflst_arch_from_uname): New API, translates umachine str obtained
  from uname() -> struct utsname -> machine to ELF machine ID.
  (dwflst_arch_sp_dwarf_reg): New API, identifies index of stack ptr.
  (dwflst_arch_expected_frame_nregs): New API, minimal number of regs
  for unwinding (useful for sanity-checking incoming stack samples).
* libdwfl_stacktrace/dwflst_sample_frame.c: Format in two sections.
  (dwflst_arch_from_uname): Implementation.
  (dwflst_arch_expected_frame_nregs): Implementation.
  (dwflst_arch_sp_dwarf_reg): Implementation.
* libdw/libdw.map (ELFUTILS_0.196_EXPERIMENTAL): Add the new functions.

Signed-off-by: Serhei Makarov <[email protected]>
---
 libdw/libdw.map                          |  7 +++
 libdwfl_stacktrace/dwflst_sample_frame.c | 58 +++++++++++++++++++++++-
 libdwfl_stacktrace/libdwfl_stacktrace.h  | 21 +++++++++
 3 files changed, 85 insertions(+), 1 deletion(-)

diff --git a/libdw/libdw.map b/libdw/libdw.map
index b45647e6..f1f8362a 100644
--- a/libdw/libdw.map
+++ b/libdw/libdw.map
@@ -411,3 +411,10 @@ ELFUTILS_0.194_EXPERIMENTAL {
   global:
     dwflst_sample_getframes;
 } ELFUTILS_0.193_EXPERIMENTAL;
+
+ELFUTILS_0.196_EXPERIMENTAL {
+  global:
+    dwflst_arch_from_uname;
+    dwflst_arch_expected_frame_nregs;
+    dwflst_arch_sp_dwarf_reg;
+} ELFUTILS_0.194_EXPERIMENTAL;
diff --git a/libdwfl_stacktrace/dwflst_sample_frame.c 
b/libdwfl_stacktrace/dwflst_sample_frame.c
index cf33a439..0e7d9f62 100644
--- a/libdwfl_stacktrace/dwflst_sample_frame.c
+++ b/libdwfl_stacktrace/dwflst_sample_frame.c
@@ -32,10 +32,13 @@
 
 #include "libdwfl_stacktraceP.h"
 
+/* Various functions providing arch-specific info:  */
+
 Ebl *default_ebl = NULL;
 GElf_Half default_ebl_machine = EM_NONE;
 
-uint64_t dwflst_perf_sample_preferred_regs_mask (GElf_Half machine)
+uint64_t
+dwflst_perf_sample_preferred_regs_mask (GElf_Half machine)
 {
   /* XXX The most likely case is that this will only be called once,
      for the current architecture.  So we keep one Ebl* around for
@@ -56,6 +59,59 @@ uint64_t dwflst_perf_sample_preferred_regs_mask (GElf_Half 
machine)
   return 0;
 }
 
+GElf_Half
+dwflst_arch_from_uname (const char *umachine)
+{
+  if (strncmp(umachine, "x86_64", 6) == 0)
+    return EM_X86_64;
+  else if (strncmp(umachine, "i686", 4) == 0
+          || strncmp(umachine, "i386", 4) == 0)
+    return EM_386;
+  else if (strncmp(umachine, "aarch64", 7) == 0)
+    return EM_AARCH64;
+  else if (strncmp(umachine, "armv7l", 6) == 0)
+    return EM_ARM;
+  /* XXX Other architectures not yet supported. */
+  return EM_NONE;
+}
+
+uint32_t
+dwflst_arch_expected_frame_nregs (GElf_Half machine)
+{
+  /* For aarch64, we actually use fewer than ebl->frame_nregs to unwind:  */
+  if (machine == EM_AARCH64)
+    return 14;
+  if (machine == EM_ARM)
+    return 16;
+  /* On x86, expect everything except FLAGS:  */
+  if (machine == EM_X86_64 || machine == EM_386)
+    /* XXX An external user of the library can't access the Ebl, hence
+       can't conveniently provide it to us it here.  We provide the
+       constant directly rather than initializing a new Ebl.  */
+    return machine == EM_X86_64 ? 17 : 9;
+    /* return ebl_frame_nregs(ebl); */
+  /* XXX Other architectures are not supported yet.
+     In general, it's fine to be on the permissive side here.  */
+  return 1;
+}
+
+int
+dwflst_arch_sp_dwarf_reg (GElf_Half machine, bool is_abi32)
+{
+  /* Use is_abi32 to downgrade from 64-bit to 32-bit,
+     but not in the other direction since 64-bit samples
+     do not occur on a 32-bit ELF machine:  */
+  if (machine == EM_X86_64 || machine == EM_386)
+    return (is_abi32 || machine == EM_386) ? 4 : 7;
+  else if (machine == EM_ARM || machine == EM_AARCH64)
+    return (is_abi32 || machine == EM_ARM) ? 13 : 31;
+  else
+    /* XXX Other architectures are not supported yet.  */
+    return -1;
+}
+
+/* Stack sample handling:  */
+
 struct sample_info {
   pid_t pid;
   pid_t tid;
diff --git a/libdwfl_stacktrace/libdwfl_stacktrace.h 
b/libdwfl_stacktrace/libdwfl_stacktrace.h
index 84cb69a3..82689aca 100644
--- a/libdwfl_stacktrace/libdwfl_stacktrace.h
+++ b/libdwfl_stacktrace/libdwfl_stacktrace.h
@@ -154,6 +154,27 @@ int dwflst_perf_sample_getframes (Dwfl *dwfl, Elf *elf, 
pid_t pid, pid_t tid,
    opened later.  */
 uint64_t dwflst_perf_sample_preferred_regs_mask (GElf_Half machine);
 
+/* Returns the correct ELF machine identifier for the arch identifier
+   string UMACHINE from struct utsname, if libdwflst handles stack
+   samples for MACHINE.  Returns EM_NONE if stack sample handling is
+   not supported.  */
+GElf_Half dwflst_arch_from_uname (const char *umachine);
+
+/* Returns the minimum required number of registers for unwinding
+   for MACHINE, which should be at most the number of bits set in
+   dwflst_perf_sample_preferred_regs_mask(MACHINE).  Returns 0
+   if libdwfl does not handle stack samples for MACHINE.  */
+uint32_t dwflst_arch_expected_frame_nregs (GElf_Half machine);
+
+/* Returns the index of the stack pointer register within the
+   dwarf_regs ordering for MACHINE.  If IS_ABI32 is true, returns the
+   index within the dwarf_regs ordering for the 32-bit variant of
+   MACHINE, to allow handling of mixed-architecture perf_events data.
+   (When providing data from non-perf_events sources, IS_ABI32 should
+   be set to false.)  Returns -1 if libdwfl does not handle stack
+   samples for MACHINE.  */
+int dwflst_arch_sp_dwarf_reg (GElf_Half machine, bool is_abi32);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.54.0

Reply via email to