From ed79a0e291b90c865c269bd2e713f1e84a382056 Mon Sep 17 00:00:00 2001 From: Kieran Bingham Date: Tue, 15 Mar 2016 14:38:07 +0000 Subject: 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 --- gdb/Makefile.in | 4 +- gdb/configure.tgt | 6 +- gdb/linux-kthread.c | 286 ++++++++++++++++++++++++++++++++++++++++++++++++++++ gdb/linux-kthread.h | 40 ++++++++ 4 files changed, 332 insertions(+), 4 deletions(-) create mode 100644 gdb/linux-kthread.c create mode 100644 gdb/linux-kthread.h 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 . */ + +#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 . */ + +#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 */ -- cgit v1.2.3