summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKieran Bingham <kieran.bingham@linaro.org>2016-03-15 14:38:07 +0000
committerKieran Bingham <kieran.bingham@linaro.org>2016-03-17 10:21:02 +0000
commited79a0e291b90c865c269bd2e713f1e84a382056 (patch)
tree73dac4c66b760fff97e2d375bd76799eb093914d
parent4f80d1d12657552f57b64693fef6ba55cd7d9f92 (diff)
gdb/linux-kthread: Introduce kernel thread support
This successfully registers a simple layer on to the target stack Template extracted from bsd-uthreads.c (gdb) maintenance print target-stack The current target stack is: - linux-kthreads (linux kernel-level threads) - remote (Remote serial target in gdb-specific protocol) - exec (Local exec file) - None (None) Signed-off-by: Kieran Bingham <kieran.bingham@linaro.org>
-rw-r--r--gdb/Makefile.in4
-rw-r--r--gdb/configure.tgt6
-rw-r--r--gdb/linux-kthread.c286
-rw-r--r--gdb/linux-kthread.h40
4 files changed, 332 insertions, 4 deletions
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index ec2af52dc4..1a4aaba999 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -676,6 +676,7 @@ ALL_TARGET_OBS = \
i386-sol2-tdep.o i386-tdep.o i387-tdep.o \
i386-dicos-tdep.o i386-darwin-tdep.o \
iq2000-tdep.o \
+ linux-kthread.o \
linux-tdep.o \
lm32-tdep.o \
m32c-tdep.o \
@@ -988,7 +989,7 @@ common/common-exceptions.h target/target.h common/symbol.h \
common/common-regcache.h fbsd-tdep.h nat/linux-personality.h \
common/fileio.h nat/x86-linux.h nat/x86-linux-dregs.h nat/amd64-linux-siginfo.h\
nat/linux-namespaces.h arch/arm.h common/gdb_sys_time.h arch/aarch64-insn.h \
-tid-parse.h
+tid-parse.h linux-kthread.h
# Header files that already have srcdir in them, or which are in objdir.
@@ -1698,6 +1699,7 @@ ALLDEPFILES = \
inf-ptrace.c \
ia64-libunwind-tdep.c \
linux-fork.c \
+ linux-kthread.c \
linux-tdep.c \
linux-record.c \
lm32-tdep.c \
diff --git a/gdb/configure.tgt b/gdb/configure.tgt
index 54245c3d55..d5cbc2213f 100644
--- a/gdb/configure.tgt
+++ b/gdb/configure.tgt
@@ -45,7 +45,7 @@ aarch64*-*-linux*)
# Target: AArch64 linux
gdb_target_obs="aarch64-tdep.o aarch64-linux-tdep.o aarch64-insn.o \
arm.o arm-linux.o arm-get-next-pcs.o arm-tdep.o \
- arm-linux-tdep.o \
+ arm-linux-tdep.o linux-kthread.o \
glibc-tdep.o linux-tdep.o solib-svr4.o \
symfile-mem.o linux-record.o"
build_gdbserver=yes
@@ -80,7 +80,7 @@ alpha*-*-*)
am33_2.0*-*-linux*)
# Target: Matsushita mn10300 (AM33) running Linux
gdb_target_obs="mn10300-tdep.o mn10300-linux-tdep.o linux-tdep.o \
- solib-svr4.o"
+ linux-kthread.o solib-svr4.o"
;;
arm*-wince-pe | arm*-*-mingw32ce*)
@@ -92,7 +92,7 @@ arm*-wince-pe | arm*-*-mingw32ce*)
arm*-*-linux*)
# Target: ARM based machine running GNU/Linux
gdb_target_obs="arm.o arm-linux.o arm-get-next-pcs.o arm-tdep.o \
- arm-linux-tdep.o glibc-tdep.o \
+ arm-linux-tdep.o glibc-tdep.o linux-kthread.o \
solib-svr4.o symfile-mem.o linux-tdep.o linux-record.o"
build_gdbserver=yes
;;
diff --git a/gdb/linux-kthread.c b/gdb/linux-kthread.c
new file mode 100644
index 0000000000..837366ec86
--- /dev/null
+++ b/gdb/linux-kthread.c
@@ -0,0 +1,286 @@
+/* Linux kernel-level threads support.
+
+ Copyright (C) 2016 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "gdbcore.h"
+#include "gdbthread.h"
+#include "inferior.h"
+#include "objfiles.h"
+#include "observer.h"
+#include "regcache.h"
+#include "target.h"
+
+#include "gdb_obstack.h"
+
+
+#include "linux-kthread.h"
+
+/* Save the linux_kthreads ops returned by linux_kthread_target. */
+static struct target_ops *linux_kthread_ops;
+
+/* Architecture-specific operations. */
+
+/* Per-architecture data key. */
+static struct gdbarch_data *linux_kthread_data;
+
+struct linux_kthread_ops
+{
+ /* Supply registers for a thread to a register cache. */
+ void (*supply_kthread) (struct regcache *, int, CORE_ADDR);
+
+ /* Collect registers for a thread from a register cache. */
+ void (*collect_kthread) (const struct regcache *, int, CORE_ADDR);
+};
+
+static void *
+linux_kthread_init (struct obstack *obstack)
+{
+ struct linux_kthread_ops *ops;
+
+ ops = OBSTACK_ZALLOC (obstack, struct linux_kthread_ops);
+ return ops;
+}
+
+/* Set the function that supplies registers from an inactive thread
+ for architecture GDBARCH to SUPPLY_UTHREAD. */
+
+void
+linux_kthread_set_supply_thread (struct gdbarch *gdbarch,
+ void (*supply_kthread) (struct regcache *,
+ int, CORE_ADDR))
+{
+ struct linux_kthread_ops *ops
+ = (struct linux_kthread_ops *) gdbarch_data (gdbarch, linux_kthread_data);
+
+ ops->supply_kthread = supply_kthread;
+}
+
+/* Set the function that collects registers for an inactive thread for
+ architecture GDBARCH to SUPPLY_UTHREAD. */
+
+void
+linux_kthread_set_collect_thread (struct gdbarch *gdbarch,
+ void (*collect_kthread) (const struct
+ regcache *, int,
+ CORE_ADDR))
+{
+ struct linux_kthread_ops *ops
+ = (struct linux_kthread_ops *) gdbarch_data (gdbarch, linux_kthread_data);
+
+ ops->collect_kthread = collect_kthread;
+}
+
+
+static char *
+ptid_to_str (ptid_t ptid)
+{
+ static char str[32];
+ snprintf (str, sizeof (str) - 1, "%d:%ld:%ld",
+ ptid_get_pid (ptid), ptid_get_lwp (ptid), ptid_get_tid (ptid));
+
+ return str;
+}
+
+/* Non-zero if the thread stratum implemented by this module is active. */
+static int linux_kthread_active;
+
+/* If OBJFILE contains the symbols corresponding to one of the
+ supported user-level threads libraries, activate the thread stratum
+ implemented by this module. */
+
+static int
+linux_kthread_activate (struct objfile *objfile)
+{
+ struct gdbarch *gdbarch = target_gdbarch ();
+ struct linux_kthread_ops *ops
+ = (struct linux_kthread_ops *) gdbarch_data (gdbarch, linux_kthread_data);
+
+ /* Skip if the thread stratum has already been activated. */
+ if (linux_kthread_active)
+ return 0;
+
+ /* There's no point in enabling this module if no
+ architecture-specific operations are provided. */
+ if (!ops->supply_kthread)
+ return 0;
+
+ /* Verify that this represents an appropriate linux target */
+
+ push_target (linux_kthread_ops);
+ linux_kthread_active = 1;
+ return 1;
+}
+
+/* Cleanup due to deactivation. */
+
+static void
+linux_kthread_close (struct target_ops *self)
+{
+ linux_kthread_active = 0;
+ /* Reset global variables */
+}
+
+/* Deactivate the thread stratum implemented by this module. */
+
+static void
+linux_kthread_deactivate (void)
+{
+ /* Skip if the thread stratum has already been deactivated. */
+ if (!linux_kthread_active)
+ return;
+
+ unpush_target (linux_kthread_ops);
+}
+
+static void
+linux_kthread_inferior_created (struct target_ops *ops, int from_tty)
+{
+ linux_kthread_activate (NULL);
+}
+
+static void
+linux_kthread_mourn_inferior (struct target_ops *ops)
+{
+ struct target_ops *beneath = find_target_beneath (ops);
+ beneath->to_mourn_inferior (beneath);
+ linux_kthread_deactivate ();
+}
+
+static void
+linux_kthread_fetch_registers (struct target_ops *ops,
+ struct regcache *regcache, int regnum)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct linux_kthread_ops *kthread_ops
+ = (struct linux_kthread_ops *) gdbarch_data (gdbarch, linux_kthread_data);
+ CORE_ADDR addr = ptid_get_tid (inferior_ptid);
+ struct target_ops *beneath = find_target_beneath (ops);
+
+ /* Always fetch the appropriate registers from the layer beneath. */
+ beneath->to_fetch_registers (beneath, regcache, regnum);
+}
+
+static void
+linux_kthread_store_registers (struct target_ops *ops,
+ struct regcache *regcache, int regnum)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct linux_kthread_ops *kthread_ops
+ = (struct linux_kthread_ops *) gdbarch_data (gdbarch, linux_kthread_data);
+ struct target_ops *beneath = find_target_beneath (ops);
+
+ beneath->to_store_registers (beneath, regcache, regnum);
+}
+
+static ptid_t
+linux_kthread_wait (struct target_ops *ops,
+ ptid_t ptid, struct target_waitstatus *status,
+ int options)
+{
+ struct target_ops *beneath = find_target_beneath (ops);
+
+ /* Pass the request to the layer beneath. */
+ ptid = beneath->to_wait (beneath, ptid, status, options);
+
+ return ptid;
+}
+
+static void
+linux_kthread_resume (struct target_ops *ops,
+ ptid_t ptid, int step, enum gdb_signal sig)
+{
+ /* Pass the request to the layer beneath. */
+ struct target_ops *beneath = find_target_beneath (ops);
+ beneath->to_resume (beneath, ptid, step, sig);
+}
+
+static int
+linux_kthread_thread_alive (struct target_ops *ops, ptid_t ptid)
+{
+ enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
+ struct target_ops *beneath = find_target_beneath (ops);
+
+ return beneath->to_thread_alive (beneath, ptid);
+}
+
+static void
+linux_kthread_update_thread_list (struct target_ops *ops)
+{
+ struct target_ops *beneath = find_target_beneath (ops);
+
+ prune_threads ();
+
+ beneath->to_update_thread_list (beneath);
+}
+
+/* Return a string describing the state of the thread specified by
+ INFO. */
+
+static char *
+linux_kthread_extra_thread_info (struct target_ops *self,
+ struct thread_info *info)
+{
+ enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
+
+ return "LinuxThread";
+}
+
+static char *
+linux_kthread_pid_to_str (struct target_ops *ops, ptid_t ptid)
+{
+ return ptid_to_str (ptid);
+}
+
+static struct target_ops *
+linux_kthread_target (void)
+{
+ struct target_ops *t = XCNEW (struct target_ops);
+
+ t->to_shortname = "linux-kthreads";
+ t->to_longname = "linux kernel-level threads";
+ t->to_doc = "Linux kernel-level threads";
+ t->to_close = linux_kthread_close;
+ t->to_mourn_inferior = linux_kthread_mourn_inferior;
+ t->to_fetch_registers = linux_kthread_fetch_registers;
+ t->to_store_registers = linux_kthread_store_registers;
+ t->to_wait = linux_kthread_wait;
+ t->to_resume = linux_kthread_resume;
+ t->to_thread_alive = linux_kthread_thread_alive;
+ t->to_update_thread_list = linux_kthread_update_thread_list;
+ t->to_extra_thread_info = linux_kthread_extra_thread_info;
+ t->to_pid_to_str = linux_kthread_pid_to_str;
+ t->to_stratum = thread_stratum;
+ t->to_magic = OPS_MAGIC;
+ linux_kthread_ops = t;
+
+ return t;
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+extern initialize_file_ftype _initialize_linux_kthread;
+
+void
+_initialize_linux_kthread (void)
+{
+ complete_target_initialization (linux_kthread_target ());
+
+ linux_kthread_data = gdbarch_data_register_pre_init (linux_kthread_init);
+
+ observer_attach_inferior_created (linux_kthread_inferior_created);
+}
diff --git a/gdb/linux-kthread.h b/gdb/linux-kthread.h
new file mode 100644
index 0000000000..0d8b6e65aa
--- /dev/null
+++ b/gdb/linux-kthread.h
@@ -0,0 +1,40 @@
+/* Linux kernel-level threads support.
+
+ Copyright (C) 2016 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef LINUX_KTHREAD_H
+#define LINUX_KTHREAD_H 1
+
+
+/* Set the function that supplies registers for an inactive thread for
+ architecture GDBARCH to SUPPLY_KTHREAD. */
+
+extern void linux_kthread_set_supply_thread (struct gdbarch *gdbarch,
+ void (*supply_kthread) (struct regcache *,
+ int, CORE_ADDR));
+
+
+/* Set the function that collects registers for an inactive thread for
+ architecture GDBARCH to SUPPLY_KTHREAD. */
+
+extern void linux_kthread_set_collect_thread (struct gdbarch *gdbarch,
+ void (*collect_kthread) (const struct regcache *,
+ int, CORE_ADDR));
+
+
+#endif /* linux_kthread.h */