diff options
author | Kamil Rytarowski <n54@gmx.com> | 2020-03-25 20:29:44 +0100 |
---|---|---|
committer | Kamil Rytarowski <n54@gmx.com> | 2020-04-06 23:04:36 +0200 |
commit | 05f00e223d56927bfb03e3272a4827276ed67372 (patch) | |
tree | c01229abb010a78b721e0b69578eaf5985b17caa /gdb/nbsd-nat.c | |
parent | 6ee448cc2d0b9337713ecb6bb2e6305b4f504cbc (diff) | |
download | gdb-05f00e223d56927bfb03e3272a4827276ed67372.zip gdb-05f00e223d56927bfb03e3272a4827276ed67372.tar.gz gdb-05f00e223d56927bfb03e3272a4827276ed67372.tar.bz2 |
Implement basic threading support in the NetBSD target
Use sysctl(3) as the portable interface to prompt NetBSD threads on
all supported NetBSD versions. In future newer versions could switch
to PT_LWPSTATUS ptrace(2) API that will be supported on NetBSD 10.0
and newer.
Implement as part of nbsd_nat_target:
- thread_name() - read descriptive thread name
- thread_alive() - check whether a thread is alive
- post_attach() - updates the list of threads after attach
- update_thread_list() - updates the list of threads
- pid_to_str() - translates ptid to a descriptive string
There are two local static functions:
- nbsd_thread_lister() - generic LWP lister for a specified pid
- nbsd_add_threads() - utility to update the list of threads
Now, GDB on NetBSD can attach to a multithreaded process, spawn
a multithreaded process, list threads, print their LWP+PID numbers
and descriptive thread names.
gdb/ChangeLog:
* nbsd-nat.h (struct thread_info): Add forward declaration.
(nbsd_nat_target::thread_alive): Add.
(nbsd_nat_target::thread_name): Likewise.
(nbsd_nat_target::update_thread_list): Likewise.
(update_thread_list::post_attach): Likewise.
(post_attach::pid_to_str): Likewise.
* nbsd-nat.c: Include "gdbthread.h" and "inferior.h".
(nbsd_thread_lister): Add.
(nbsd_nat_target::thread_alive): Likewise.
(nbsd_nat_target::thread_name): Likewise.
(nbsd_add_threads): Likewise.
(update_thread_list::post_attach): Likewise.
(nbsd_nat_target::update_thread_list): Likewise.
(post_attach::pid_to_str): Likewise.
Diffstat (limited to 'gdb/nbsd-nat.c')
-rw-r--r-- | gdb/nbsd-nat.c | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/gdb/nbsd-nat.c b/gdb/nbsd-nat.c index 326bbe3..4423e19 100644 --- a/gdb/nbsd-nat.c +++ b/gdb/nbsd-nat.c @@ -20,6 +20,8 @@ #include "defs.h" #include "nbsd-nat.h" +#include "gdbthread.h" +#include "inferior.h" #include <sys/types.h> #include <sys/ptrace.h> @@ -39,3 +41,161 @@ nbsd_nat_target::pid_to_exec_file (int pid) return NULL; return buf; } + +/* Generic thread (LWP) lister within a specified process. The callback + parameters is a C++ function that is called for each detected thread. */ + +static bool +nbsd_thread_lister (const pid_t pid, + gdb::function_view<bool (const struct kinfo_lwp *)> + callback) +{ + int mib[5] = {CTL_KERN, KERN_LWP, pid, sizeof (struct kinfo_lwp), 0}; + size_t size; + + if (sysctl (mib, ARRAY_SIZE (mib), NULL, &size, NULL, 0) == -1 || size == 0) + perror_with_name (("sysctl")); + + mib[4] = size / sizeof (size_t); + + gdb::unique_xmalloc_ptr<struct kinfo_lwp[]> kl + ((struct kinfo_lwp *) xcalloc (size, 1)); + + if (sysctl (mib, ARRAY_SIZE (mib), kl.get (), &size, NULL, 0) == -1 + || size == 0) + perror_with_name (("sysctl")); + + for (size_t i = 0; i < size / sizeof (struct kinfo_lwp); i++) + { + struct kinfo_lwp *l = &kl[i]; + + /* Return true if the specified thread is alive. */ + auto lwp_alive + = [] (struct kinfo_lwp *lwp) + { + switch (lwp->l_stat) + { + case LSSLEEP: + case LSRUN: + case LSONPROC: + case LSSTOP: + case LSSUSPENDED: + return true; + default: + return false; + } + }; + + /* Ignore embryonic or demised threads. */ + if (!lwp_alive (l)) + continue; + + if (callback (l)) + return true; + } + + return false; +} + +/* Return true if PTID is still active in the inferior. */ + +bool +nbsd_nat_target::thread_alive (ptid_t ptid) +{ + pid_t pid = ptid.pid (); + int lwp = ptid.lwp (); + + auto fn + = [&lwp] (const struct kinfo_lwp *kl) + { + return kl->l_lid == lwp; + }; + + return nbsd_thread_lister (pid, fn); +} + +/* Return the name assigned to a thread by an application. Returns + the string in a static buffer. */ + +const char * +nbsd_nat_target::thread_name (struct thread_info *thr) +{ + ptid_t ptid = thr->ptid; + pid_t pid = ptid.pid (); + int lwp = ptid.lwp (); + + static char buf[KI_LNAMELEN] = {}; + + auto fn + = [&lwp] (const struct kinfo_lwp *kl) + { + if (kl->l_lid == lwp) + { + xsnprintf (buf, sizeof buf, "%s", kl->l_name); + return true; + } + return false; + }; + + if (nbsd_thread_lister (pid, fn)) + return buf; + else + return NULL; +} + +/* Implement the "post_attach" target_ops method. */ + +static void +nbsd_add_threads (nbsd_nat_target *target, pid_t pid) +{ + auto fn + = [&target, &pid] (const struct kinfo_lwp *kl) + { + ptid_t ptid = ptid_t (pid, kl->l_lid, 0); + if (!in_thread_list (target, ptid)) + { + if (inferior_ptid.lwp () == 0) + thread_change_ptid (target, inferior_ptid, ptid); + else + add_thread (target, ptid); + } + return false; + }; + + nbsd_thread_lister (pid, fn); +} + +/* Implement the "post_attach" target_ops method. */ + +void +nbsd_nat_target::post_attach (int pid) +{ + nbsd_add_threads (this, pid); +} + +/* Implement the "update_thread_list" target_ops method. */ + +void +nbsd_nat_target::update_thread_list () +{ + prune_threads (); + + nbsd_add_threads (this, inferior_ptid.pid ()); +} + +/* Convert PTID to a string. */ + +std::string +nbsd_nat_target::pid_to_str (ptid_t ptid) +{ + int lwp = ptid.lwp (); + + if (lwp != 0) + { + pid_t pid = ptid.pid (); + + return string_printf ("LWP %d of process %d", lwp, pid); + } + + return normal_pid_to_str (ptid); +} |