In commit 3ce0d5ed, I missed the fact that
dwflst_perf_sample_getframes needs to handle the case of an unattached
Dwfl, when dwfl->process->ebl is not yet available to translate the
registers. Thus, it can't be a straightforward wrapper of
dwfl_sample_getframes, but should instead handle the attaching logic
identically to that function.

* libdwfl_stacktrace (dwflst_perf_sample_getframes): Implement
  attaching the Dwfl identically to dwflst_sample_getframes.

Signed-off-by: Serhei Makarov <[email protected]>
---
 libdwfl_stacktrace/dwflst_sample_frame.c | 49 +++++++++++++++++++-----
 1 file changed, 39 insertions(+), 10 deletions(-)

diff --git a/libdwfl_stacktrace/dwflst_sample_frame.c 
b/libdwfl_stacktrace/dwflst_sample_frame.c
index 090d3220..9f527579 100644
--- a/libdwfl_stacktrace/dwflst_sample_frame.c
+++ b/libdwfl_stacktrace/dwflst_sample_frame.c
@@ -259,26 +259,55 @@ dwflst_perf_sample_getframes (Dwfl *dwfl, Elf *elf,
                              int (*callback) (Dwfl_Frame *state, void *arg),
                              void *arg)
 {
+  /* TODO: Lock the dwfl to ensure attach_state does not interfere
+     with other dwfl_perf_sample_getframes calls. */
+
+  struct sample_info *sample_arg;
+  bool attached = false;
+  if (dwfl->process != NULL)
+    {
+      sample_arg = dwfl->process->callbacks_arg;
+      attached = true;
+    }
+  else
+    {
+      sample_arg = malloc (sizeof *sample_arg);
+      if (sample_arg == NULL)
+       {
+         __libdwfl_seterrno(DWFL_E_NOMEM);
+         return -1;
+       }
+    }
+
+  sample_arg->pid = pid;
+  sample_arg->tid = tid;
+  sample_arg->stack = (const uint8_t *)stack;
+  sample_arg->stack_size = stack_size;
+  sample_arg->regs = regs;
+  sample_arg->n_regs = n_regs;
+
+  if (! attached
+      && ! INTUSE(dwfl_attach_state) (dwfl, elf, pid,
+                                     &sample_thread_callbacks, sample_arg))
+    return -1;
+
   /* Select the regs_mapping based on architecture.  This will be
      cached in ebl to avoid having to recompute the regs_mapping array
      when perf_regs_mask is consistent for the entire session: */
-  const int *regs_mapping;
-  size_t n_regs_mapping;
   Dwfl_Process *process = dwfl->process;
   Ebl *ebl = process->ebl;
-  /* XXX May want to check if abi matches ebl_get_elfclass(ebl). */
   if (!ebl_sample_perf_regs_mapping(ebl,
                                    perf_regs_mask, abi,
-                                   &regs_mapping, &n_regs_mapping))
+                                   &sample_arg->regs_mapping, 
&sample_arg->n_regs_mapping))
     {
       __libdwfl_seterrno(DWFL_E_LIBEBL_BAD);
       return -1;
     }
+  sample_arg->elfclass = ebl_get_elfclass(ebl);
+  ebl_sample_sp_pc(ebl, regs, n_regs,
+                   sample_arg->regs_mapping, sample_arg->n_regs_mapping,
+                   &sample_arg->base_addr, &sample_arg->pc);
 
-  /* Then we can call dwflst_sample_getframes: */
-  return dwflst_sample_getframes (dwfl, elf, pid, tid,
-                                 stack, stack_size,
-                                 regs, n_regs,
-                                 regs_mapping, n_regs_mapping,
-                                 callback, arg);
+  /* XXX May want to check if abi matches ebl_get_elfclass(ebl). */
+  return INTUSE(dwfl_getthread_frames) (dwfl, tid, callback, arg);
 }
-- 
2.52.0

Reply via email to