]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
eu-stacktrace WIP: optional LIBDWFL_TRACKS_UNWOUND_SOURCE patch
authorSerhei Makarov <serhei@serhei.io>
Thu, 15 Aug 2024 21:37:48 +0000 (17:37 -0400)
committerSerhei Makarov <serhei@serhei.io>
Thu, 15 Aug 2024 21:37:48 +0000 (17:37 -0400)
patch -p1 <libdwfl-report-unwound-source.patch

This is an optional diagnostic patch that tracks the unwinding
mechanism used to produce each Dwfl_Frame.

Plus some #ifdef code in src/stacktrace.c that uses the
field to report per-frame or per-process which unwinding
mechanism was used.

Pending to figure out a better way to expand the libdwfl
data structures with additional tracking info.

libdwfl-report-unwound-source.patch [new file with mode: 0644]
src/stacktrace.c

diff --git a/libdwfl-report-unwound-source.patch b/libdwfl-report-unwound-source.patch
new file mode 100644 (file)
index 0000000..f84109a
--- /dev/null
@@ -0,0 +1,71 @@
+diff --git a/libdwfl/frame_unwind.c b/libdwfl/frame_unwind.c
+index 1e2f0255..384d9288 100644
+--- a/libdwfl/frame_unwind.c
++++ b/libdwfl/frame_unwind.c
+@@ -730,14 +730,20 @@ __libdwfl_frame_unwind (Dwfl_Frame *state)
+       {
+         handle_cfi (state, pc - bias, cfi_eh, bias);
+         if (state->unwound)
+-          return;
++          {
++            state->unwound_source = DWFL_UNWOUND_EH_CFI;
++            return;
++          }
+       }
+       Dwarf_CFI *cfi_dwarf = INTUSE(dwfl_module_dwarf_cfi) (mod, &bias);
+       if (cfi_dwarf)
+       {
+         handle_cfi (state, pc - bias, cfi_dwarf, bias);
+         if (state->unwound)
+-          return;
++          {
++            state->unwound_source = DWFL_UNWOUND_DWARF_CFI;
++            return;
++          }
+       }
+     }
+   assert (state->unwound == NULL);
+@@ -759,9 +765,11 @@ __libdwfl_frame_unwind (Dwfl_Frame *state)
+       assert (state->unwound->unwound == NULL);
+       free (state->unwound);
+       state->unwound = NULL;
++      state->unwound_source = DWFL_UNWOUND_UNKNOWN;
+       // __libdwfl_seterrno has been called above.
+       return;
+     }
++  state->unwound_source = DWFL_UNWOUND_EBL;
+   assert (state->unwound->pc_state == DWFL_FRAME_STATE_PC_SET);
+   state->unwound->signal_frame = signal_frame;
+ }
+diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h
+index cdc528d0..62120b43 100644
+--- a/libdwfl/libdwflP.h
++++ b/libdwfl/libdwflP.h
+@@ -243,6 +243,18 @@ struct Dwfl_Thread
+   void *callbacks_arg;
+ };
++/* XXX Temporary, for diagnostic purposes: */
++
++#define LIBDWFL_TRACKS_UNWOUND_SOURCE
++typedef enum {
++    DWFL_UNWOUND_NONE = 0,
++    DWFL_UNWOUND_EH_CFI,
++    DWFL_UNWOUND_DWARF_CFI,
++    DWFL_UNWOUND_EBL,
++    DWFL_UNWOUND_UNKNOWN,
++    DWFL_UNWOUND_NUM,
++} Dwfl_Unwound_Source;
++
+ /* See its typedef in libdwfl.h.  */
+ struct Dwfl_Frame
+@@ -263,6 +275,8 @@ struct Dwfl_Frame
+        outermost frame.  */
+     DWFL_FRAME_STATE_PC_UNDEFINED
+   } pc_state;
++  /* XXX Temporary, for diagnostic purposes: */
++  Dwfl_Unwound_Source unwound_source;
+   /* Either initialized from appropriate REGS element or on some archs
+      initialized separately as the return address has no DWARF register.  */
+   Dwarf_Addr pc;
index ec0c508679d2ebfb573f583de74792b32e57fc31..98c350ca08306c62efe24ba0bb34e8b5f3439718 100644 (file)
 #include <signal.h>
 /* #include ELFUTILS_HEADER(dwfl) */
 #include "../libdwfl/libdwflP.h"
-/* XXX: Private header needed for sysprof_find_procfile, sysprof_init_dwfl. */
+/* XXX: Private header needed for sysprof_find_procfile, sysprof_init_dwfl, XXX LIBDWFL_TRACKS_UNWOUND_SOURCE. */
+
+#ifdef LIBDWFL_TRACKS_UNWOUND_SOURCE
+char *
+unwound_source_str (Dwfl_Unwound_Source unwound_source)
+{
+  switch (unwound_source) {
+  case DWFL_UNWOUND_NONE:
+    return "none";
+  case DWFL_UNWOUND_EH_CFI:
+    return "eh_frame";
+  case DWFL_UNWOUND_DWARF_CFI:
+    return "dwarf";
+  case DWFL_UNWOUND_EBL:
+    return "ebl";
+  default:
+    return "unknown";
+  }
+}
+#endif
 
 #include <system.h>
 
@@ -565,6 +584,9 @@ struct sysprof_unwind_info
   Dwarf_Addr last_sp; /* for diagnostic purposes */
 #ifdef DEBUG_MODULES
   Dwfl *last_dwfl; /* for diagnostic purposes */
+#endif
+#ifdef LIBDWFL_TRACKS_UNWOUND_SOURCE
+  int last_pid; /* for diagnostic purposes, to provide access to dwfltab */
 #endif
   Dwarf_Addr *addrs; /* allocate blocks of UNWIND_ADDR_INCREMENT */
   void *outbuf;
@@ -803,6 +825,11 @@ typedef struct
   int max_frames; /* for diagnostic purposes */
   int total_samples; /* for diagnostic purposes */
   int lost_samples; /* for diagnostic purposes */
+  int shown_error; /* already shown an error for this pid? TODO */
+#ifdef LIBDWFL_TRACKS_UNWOUND_SOURCE
+  Dwfl_Unwound_Source last_unwound; /* track CFI source with enum above, for diagnostic purposes */
+  Dwfl_Unwound_Source worst_unwound; /* track CFI source with enum above, for diagnostic purposes */
+#endif
 } dwfltab_ent;
 
 typedef struct
@@ -1054,9 +1081,29 @@ sysprof_unwind_frame_cb (Dwfl_Frame *state, void *arg)
        fprintf(stderr, "* pc=%lx -> NO EH_CFI\n", pc);
     }
 #endif
+
+#ifdef LIBDWFL_TRACKS_UNWOUND_SOURCE
+  dwfltab_ent *dwfl_ent = dwfltab_find(sui->last_pid);
+  if (dwfl_ent != NULL)
+    {
+      if (state->unwound_source > dwfl_ent->worst_unwound)
+       dwfl_ent->worst_unwound = state->unwound_source;
+      dwfl_ent->last_unwound = state->unwound_source;
+      if (show_frames)
+       fprintf(stderr, "* frame %d: pc_adjusted=%lx sp=%lx+(%lx) unwound_source=%s\n",
+               sui->n_addrs, pc_adjusted, sui->last_base, sp - sui->last_base, unwound_source_str(state->unwound_source));
+    }
+  else
+    {
+      if (show_frames)
+       fprintf(stderr, "* frame %d: pc_adjusted=%lx sp=%lx+(%lx), unwound_source not found\n",
+               sui->n_addrs, pc_adjusted, sui->last_base, sp - sui->last_base);
+    }
+#else
   if (show_frames)
     fprintf(stderr, "* frame %d: pc_adjusted=%lx sp=%lx+(%lx)\n",
            sui->n_addrs, pc_adjusted, sui->last_base, sp - sui->last_base);
+#endif
 
   if (sui->n_addrs > maxframes)
     {
@@ -1134,6 +1181,9 @@ sysprof_unwind_cb (SysprofCaptureFrame *frame, void *arg)
   sui->n_addrs = 0;
 #ifdef DEBUG_MODULES
   sui->last_dwfl = dwfl;
+#endif
+#ifdef LIBDWFL_TRACKS_UNWOUND_SOURCE
+  sui->last_pid = frame->pid;
 #endif
   int rc = dwfl_getthread_frames (dwfl, ev->tid, sysprof_unwind_frame_cb, sui);
   if (rc < 0)
@@ -1301,12 +1351,16 @@ Utility is a work-in-progress, see README.eu-stacktrace in the source branch.")
              dwfltab *htab = &default_table;
              if (!htab->table[idx].used)
                continue;
-             fprintf(stderr, "%d %s -- max %d frames, received %d samples, lost %d samples (%.1f%%)\n",
+             fprintf(stderr, "%d %s -- max %d frames, received %d samples, lost %d samples (%.1f%%)",
                      htab->table[idx].pid, htab->table[idx].comm, htab->table[idx].max_frames,
                      htab->table[idx].total_samples, htab->table[idx].lost_samples,
                      PERCENT(htab->table[idx].lost_samples, htab->table[idx].total_samples));
              total_samples += htab->table[idx].total_samples;
              total_lost_samples += htab->table[idx].lost_samples;
+#ifdef LIBDWFL_TRACKS_UNWOUND_SOURCE
+             fprintf(stderr, " (last %s, worst %s)", unwound_source_str(htab->table[idx].last_unwound), unwound_source_str(htab->table[idx].worst_unwound));
+#endif
+             fprintf(stderr, "\n");
            }
          fprintf(stderr, "===\n");
          fprintf(stderr, "TOTAL -- received %d samples, lost %d samples\n",