diff options
author | Mark Wielaard <[email protected]> | 2013-12-20 10:09:12 +0100 |
---|---|---|
committer | Mark Wielaard <[email protected]> | 2013-12-23 22:57:22 +0100 |
commit | e962ec3bcbe8eccdcded36aaafee7bec41fa1bc4 (patch) | |
tree | d250cd9aecff3f8e539b301398027b1fc0a25c46 /libdwfl/dwfl_frame.c | |
parent | b6ef1ce4695cea00d097c7fcac8d0014ff01a5bf (diff) |
libdwfl: Add dwfl_getthread_frames.
dwfl_getthread_frames is a convenience function for when the user is only
interested in one specific thread id of a process. It can be implemented by
a simple wrapper function that removes an extra callback layer just to
filter on thread id. But it also provides an optimized path to getting
access to just one particular Dwfl_Thread of the Dwfl process by providing
and (optional) new callback for the state provider. The pid_thread_callbacks
now provide an (optional) pid_getthread that doesn't need to travers all
threads anymore. Which is implemented for the linux-pid-attach provider.
stack now uses this to implement a new '-1' option that shows just one
specific thread of a process.
Signed-off-by: Mark Wielaard <[email protected]>
Diffstat (limited to 'libdwfl/dwfl_frame.c')
-rw-r--r-- | libdwfl/dwfl_frame.c | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/libdwfl/dwfl_frame.c b/libdwfl/dwfl_frame.c index 4a7b3cdb..28008e90 100644 --- a/libdwfl/dwfl_frame.c +++ b/libdwfl/dwfl_frame.c @@ -273,6 +273,103 @@ dwfl_getthreads (Dwfl *dwfl, int (*callback) (Dwfl_Thread *thread, void *arg), } INTDEF(dwfl_getthreads) +struct one_arg +{ + pid_t tid; + bool seen; + int (*callback) (Dwfl_Thread *thread, void *arg); + void *arg; + int ret; +}; + +static int +get_one_thread_cb (Dwfl_Thread *thread, void *arg) +{ + struct one_arg *oa = (struct one_arg *) arg; + if (! oa->seen && INTUSE(dwfl_thread_tid) (thread) == oa->tid) + { + oa->seen = true; + oa->ret = oa->callback (thread, oa->arg); + return DWARF_CB_ABORT; + } + + return DWARF_CB_OK; +} + +/* Note not currently exported, will be when there are more Dwfl_Thread + properties to query. Use dwfl_getthread_frames for now directly. */ +static int +getthread (Dwfl *dwfl, pid_t tid, + int (*callback) (Dwfl_Thread *thread, void *arg), + void *arg) +{ + Dwfl_Process *process = dwfl->process; + if (process == NULL) + { + __libdwfl_seterrno (dwfl->process_attach_error); + return -1; + } + + if (process->callbacks->get_thread != NULL) + { + Dwfl_Thread thread; + thread.process = process; + thread.unwound = NULL; + thread.callbacks_arg = NULL; + + if (process->callbacks->get_thread (dwfl, tid, process->callbacks_arg, + &thread.callbacks_arg)) + { + int err; + thread.tid = tid; + err = callback (&thread, arg); + thread_free_all_states (&thread); + return err; + } + + return -1; + } + + struct one_arg oa = { .tid = tid, .callback = callback, + .arg = arg, .seen = false }; + int err = INTUSE(dwfl_getthreads) (dwfl, get_one_thread_cb, &oa); + + if (err == DWARF_CB_ABORT && oa.seen) + return oa.ret; + + if (err == DWARF_CB_OK && ! oa.seen) + { + errno = ESRCH; + __libdwfl_seterrno (DWFL_E_ERRNO); + return -1; + } + + return err; +} + +struct one_thread +{ + int (*callback) (Dwfl_Frame *frame, void *arg); + void *arg; +}; + +static int +get_one_thread_frames_cb (Dwfl_Thread *thread, void *arg) +{ + struct one_thread *ot = (struct one_thread *) arg; + return INTUSE(dwfl_thread_getframes) (thread, ot->callback, ot->arg); +} + +int +dwfl_getthread_frames (Dwfl *dwfl, pid_t tid, + int (*callback) (Dwfl_Frame *frame, void *arg), + void *arg) +{ + struct one_thread ot = { .callback = callback, .arg = arg }; + return getthread (dwfl, tid, get_one_thread_frames_cb, &ot); +} +INTDEF(dwfl_getthread_frames) + int dwfl_thread_getframes (Dwfl_Thread *thread, int (*callback) (Dwfl_Frame *state, void *arg), |