On Mon, 23 Dec 2013 13:54:19 +0100, Mark Wielaard wrote:
On Sun, 2013-12-22 at 16:51 +0100, Jan Kratochvil wrote:
> If I have PID=12000 and I do 'eu-stack -p 12001' (its thread TID) then for
> elfutils in fact PID is 12001. So if Dwfl_Thread_Callbacks.next_thread
> returns 12001 first we can backtrace it and stop.
This just shows a bug in linux-pid-attach. It doesn't properly report
the PID (Tgid). It should only report 12001 as PID if it really is the
thread group leader of the given TID. I'll fix that.
OK, I agree, then the situation is different. It looks a bit unusual as it is
not the behavior of GDB.
Updated patch attached.
Fine with that with the comments below.
[...]
--- a/libdwfl/dwfl_frame.c
+++ b/libdwfl/dwfl_frame.c
@@ -273,6 +273,93 @@ 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;
+};
+
+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;
+ return oa->callback (thread, oa->arg);
Maybe it was intentionall to keep the code simple - but if oa->callback
returns DWARF_CB_OK then it will needlessly continue iterating the threads
despite it can never find that TID again.
+ }
+
+ 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
+dwfl_getthread (Dwfl *dwfl, pid_t tid,
It is no longer public so I think it should not have dwfl_* prefix.
+ int (*callback) (Dwfl_Thread *thread, void *arg),
+ void *arg)
+{
+ Dwfl_Process *process = dwfl->process;
+ if (process == NULL)
As the function is no longer public this can be rather an assert.
+ {
+ __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_OK && ! oa.seen)
__libdwfl_seterrno is not called.
+ 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 dwfl_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),
diff --git a/libdwfl/libdwfl.h b/libdwfl/libdwfl.h
index 007089b..f1c0052 100644
--- a/libdwfl/libdwfl.h
+++ b/libdwfl/libdwfl.h
@@ -662,6 +662,17 @@ typedef struct
pid_t (*next_thread) (Dwfl *dwfl, void *dwfl_arg, void **thread_argp)
__nonnull_attribute__ (1);
+ /* Called to get a specific thread. Returns true if there is a
+ thread with the given thread id number, returns false if no such
+ thread exists and may set dwfl_errno in that case. THREAD_ARGP
s/may/it will/. Setting errno has to be mandatory, not voluntary.
+ is never NULL. *THREAD_ARGP will be passed to
+ set_initial_registers or thread_detach callbacks together with
+ Dwfl_Thread *thread. This method may be NULL and will then be
+ emulated using the next_thread callback. */
+ bool (*get_thread) (Dwfl *dwfl, pid_t tid, void *dwfl_arg,
+ void **thread_argp)
+ __nonnull_attribute__ (1);
+
/* Called during unwinding to access memory (stack) state. Returns true for
successfully read *RESULT or false and sets dwfl_errno () on failure.
This method may be NULL - in such case dwfl_thread_getframes will return
@@ -762,6 +773,16 @@ int dwfl_thread_getframes (Dwfl_Thread *thread,
void *arg)
__nonnull_attribute__ (1, 2);
+/* Like dwfl_thread_getframes, but specifying the thread by its unique
+ identifier number. Returns zero if all frames have been processed
+ by the callback, returns -1 on error (and when no thread with
+ the given thread id number exists), or the value of the callback
+ when not DWARF_CB_OK. -1 returned on error will set dwfl_errno (). */
+int dwfl_getthread_frames (Dwfl *dwfl, pid_t tid,
+ int (*callback) (Dwfl_Frame *thread, void *arg),
+ void *arg)
+ __nonnull_attribute__ (1, 3);
+
/* Return *PC (program counter) for thread-specific frame STATE.
Set *ISACTIVATION according to DWARF frame "activation" definition.
Typically you need to substract 1 from *PC if *ACTIVATION is false to safely
[...]
Thanks,
Jan