This is the mail archive of the elfutils-devel@sourceware.org mailing list for the elfutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [patch 4/4 v2] unwinder: The unwinder (x86* only)


On Thu, 2013-06-13 at 00:03 +0200, Mark Wielaard wrote:
> What do you think? I am struggling a bit with this because I can see the
> user might want both (full freeze on begin or minimal thread freeze at
> use only).

What about this interface? Besides the dwarf_report_begin point, there
are explicit actions for, attaching "state", iterating through threads,
starting and ending a frame unwind. That seems to give the most
flexibility. You can attach/freeze at any point, when starting to report
Dwfl modules, when attaching the "state", when iterating through the
threads or only when starting an unwind.

We can then provide an implementation that does attach on report
dwfl_linux_proc_report_state (Dwfl *dwfl, pid_t pid) or one that only
attaches on the start of a frame unwind (and detaches after the unwind
finishes). That one could just be the existing dwfl_linux_proc_report
(Dwfl *dwfl, pid_t pid) because it would only differ to the user when
the other new interfaces are used. For core files we could just make
dwfl_core_file_report (Dwfl *dwfl, Elf *elf) do the right thing.


So on the "backend" side the interface could be:

typedef struct Dwfl_Thread;

typedef struct
{
  /* Called to iterate through threads.  Starting with previous *ptid
     set to -1.  Returns next thread id on success, a negative number on
     failure and zero if there are no more threads.  Should call
     dwfl_thread_state () on nthread if thread can be unwound with
     initial register and memory accessors.  */
  pid_t (*next_thread) (Dwfl *dwfl, pid_t pid, pid_t *ptid,
                        Dwfl_Thread *nthread, void *arg);

  /* Called by dwfl_end ().  */
  void (*detach) (Dwfl *dwfl, pid_t pid, void *arg);

} Dwfl_State_Callbacks;

/* pid is the process id associated with the Dwfl state, arg is the
   callback backend state.  Both will be provided to the callbacks.  */
dwfl_attach_state (Dwfl *dwfl, pid_t pid,
                   Dwfl_State_Callbacks *state, void *arg);

/* probably needed... */
Dwfl *dwfl_thread_dwfl (Dwfl_Thread *thread);
pid_t dwfl_thread_pid (Dwfl_Thread *thread);

typedef struct
{
  /* Called on initial unwind to get the initial register state of the
     first frame.  Should call dwfl_thread_state_registers (), possibly
     multiple times for different ranges, to fill in initial (DWARF)
     register values.  After this call, till at least thread_detach is
     called, the thread is assumed to be frozen, so that it is safe to
     unwind.  Returns true on success or false and sets dwfl_err() on
     failure.  */
  bool (*set_initial_registers) (Dwfl_Thread *thread, pid_t tid,
                                 void *arg);

  /* Called during unwinding to access memory (stack) state. */
  bool (*memory_read) (Dwfl_Thread *thread, pid_t tid,
                       Dwarf_Addr addr, Dwarf_Word *result,
                       void *arg);

  /* Called when unwinding is done. No callback will be called after
     this has been called.  */
  void (*thread_detach) (Dwfl_Thread *thread, pid_t tid, void *arg);
} Dwfl_Thread_Callbacks;

dwfl_thread_state (Dwfl_Thread *thread, Dwfl_Thread_Callbacks *state);

pid_t dwfl_thread_tid (Dwfl_Thread *thread);

dwfl_thread_state_registers (Dwfl_Thread *thread,
                             const int firstreg,
                             unsigned nregs,
                             const Dwarf_Word *regs);

Then (the existing?) dwfl_linux_proc_report and dwfl_core_file_report
could setup the above callbacks. Or they could be setup by someone by
hand if they can provide registers and memory accessors in some other
way.

For the user/usage side we could then have:

/* Gets the next known thread, if any.  To get the initial thread
   provide NULL as previous thread.  */
Dwfl_Thread *dwfl_next_thread (Dwfl *dwfl, Dwfl_Thread *pthread);

/* Iterate through the frames for a thread.  Returns zero if all frames
   have been processed by the callback, returns -1 on error, or the
   value of the callback when not DWARF_CB_OK.  Keeps calling the
   callback with the next frame while the callback returns
   DWARF_CB_OK, till there are no more frames.  On start will call the
   set_initial_registers callback and on return will call the
   detach_thread callback of the Dwfl_Thread.  */
int dwfl_getdwarf (Dwfl_Thread *thread,
		   int (*callback) (Dwfl_Frame *, void *),
		   void *arg);

bool dwfl_frame_state_pc (Dwfl_Frame_State *state, Dwarf_Addr *pc,
		          bool *isactivation)

Note the above is just a first suggestion, not even tried to compile
yet. But unless I forgot something I think this is flexible enough to
support different backends and policies for "freezing" a process.

Cheers,

Mark


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]