From: Rajendra SY <rajendra.sy@gmail.com>
To: John Baldwin <jhb@freebsd.org>
Cc: gdb-patches@sourceware.org
Subject: Re: [PATCH] [PR 23660] On FreeBSD platform missing implementation of thread-db support
Date: Wed, 19 Sep 2018 16:52:00 -0000 [thread overview]
Message-ID: <CAMAnt0mHKNfZRcj+XHW+ft0=gd-49Ym-Lyf1rGK5B-foJYsr8A@mail.gmail.com> (raw)
In-Reply-To: <8b47dccf-0b34-9803-8417-42841dd924a7@FreeBSD.org>
[-- Attachment #1: Type: text/plain, Size: 2031 bytes --]
John,
Thanks for reviewing the patch.
> We could instead use libthread_db for now,
I tried to clean up the thread_db implementation (attached a diff file
for reference) as you suggested.
Please see if this needs further cleanup? All TLS test cases pass except below.
The test case "gdb.threads/tls-core.exp" fails with this new
implementation, I am yet to debug this.
I need some help in fixing "gdb.threads/staticthreads.exp" test case
where executable is "statically" linked.
For statically linked executable linkmap is NULL. How do we get link
map address?
Thanks
Rajendra
On Mon, Sep 17, 2018 at 10:41 PM, John Baldwin <jhb@freebsd.org> wrote:
> On 9/15/18 6:21 AM, Rajendra SY wrote:
>> Problem:
>> Missing libthread_db integration with GDB
>>
>> Cause:
>> GDB missing libthread_db integration on FreeBSD target because of this
>> GDB failed to access TLS variable values.
>>
>> Tests failed:
>> - gdb.threads/tls-shared.exp
>> - gdb.threads/tls-nodebug-pie.exp
>> - gdb.threads/tls-so_extern.exp
>> - gdb.threads/tls-var.exp
>> - gdb.threads/tls.exp
>> - gdb.threads/tls-core.exp
>
> I'll have to take some time to review this. I had hoped to avoid using
> libthread_db at all on FreeBSD (it doesn't support AVX or 32-bit processes
> on 64-bit kernels, etc.). For TLS I was planning on teaching fbsd-tdep.c
> about the various special variables libthread_db knows from rtld and libthr
> and using that along with having each FreeBSD architecture provide the
> thread pointer register to implement TLS.
>
> We could instead use libthread_db for now, but if so I'd prefer to only use
> libthread_db for TLS and not for anything else. This means that in theory
> much of the proc-service API can be stubs that should never be called.
> I would also be tempted to not have a separate thread-stratum target at all,
> but just have the native target in fbsd-nat.c call into fbsd-thread-db as if
> it was just a library for things like extra thread info (the pthread_t
> pointer value) and TLS.
>
> --
> John Baldwin
>
>
[-- Attachment #2: 0001-New-TLS-implementation-for-FreeBSD.patch --]
[-- Type: application/octet-stream, Size: 26716 bytes --]
From 7f6d431e4825d545bda95ac9149fd4e952e98f38 Mon Sep 17 00:00:00 2001
From: Rajendra S Y <syrajendra@syrajendra-mbp.jnpr.net>
Date: Wed, 19 Sep 2018 22:01:39 +0530
Subject: [PATCH] New TLS implementation for FreeBSD
Signed-off-by: Rajendra S Y <syrajendra@syrajendra-mbp.jnpr.net>
---
gdb/amd64-fbsd-nat.c | 43 +++
gdb/configure.nat | 3 +-
gdb/fbsd-nat.c | 8 +
gdb/fbsd-nat.h | 8 +
gdb/fbsd-thread-db.c | 737 +++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/i386-bsd-nat.c | 32 +++
6 files changed, 830 insertions(+), 1 deletion(-)
create mode 100644 gdb/fbsd-thread-db.c
diff --git a/gdb/amd64-fbsd-nat.c b/gdb/amd64-fbsd-nat.c
index 7c7c963485..ae2a02d762 100644
--- a/gdb/amd64-fbsd-nat.c
+++ b/gdb/amd64-fbsd-nat.c
@@ -35,6 +35,7 @@
#include "amd64-bsd-nat.h"
#include "x86-nat.h"
#include "x86-xstate.h"
+#include "gregset.h"
\f
class amd64_fbsd_nat_target final
@@ -306,3 +307,45 @@ Please report this to <bug-gdb@gnu.org>."),
}
#endif
}
+
+/* Transfering the registers between GDB, inferiors and core files. */
+
+/* Fill GDB's register array with the general-purpose register values
+ in *GREGSETP. */
+
+void
+supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregs)
+{
+ amd64_supply_native_gregset (regcache, gregs, -1);
+}
+
+/* Fill register REGNUM (if it is a general-purpose register) in
+ *GREGSETPS with the value in GDB's register array. If REGNUM is -1,
+ do this for all registers. */
+
+void
+fill_gregset (const struct regcache *regcache, gdb_gregset_t *gregs, int regno)
+{
+ amd64_collect_native_gregset (regcache, gregs, regno);
+}
+
+/* Fill GDB's register array with the floating-point register values
+ in *FPREGSETP. */
+
+void
+supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregs)
+{
+ amd64_supply_fxsave (regcache, -1, fpregs);
+}
+
+/* Fill register REGNUM (if it is a floating-point register) in
+ *FPREGSETP with the value in GDB's register array. If REGNUM is -1,
+ do this for all registers. */
+
+void
+fill_fpregset (const struct regcache *regcache, gdb_fpregset_t *fpregs,
+ int regno)
+{
+ amd64_collect_fxsave (regcache, regno, fpregs);
+}
+
diff --git a/gdb/configure.nat b/gdb/configure.nat
index 7611266d86..7b53ae319a 100644
--- a/gdb/configure.nat
+++ b/gdb/configure.nat
@@ -62,7 +62,8 @@ case ${gdb_host} in
LOADLIBES='-ldl $(RDYNAMIC)'
;;
fbsd*)
- NATDEPFILES='fork-child.o fork-inferior.o inf-ptrace.o fbsd-nat.o'
+ NATDEPFILES='inf-ptrace.o fork-child.o fork-inferior.o fbsd-nat.o \
+ fbsd-thread-db.o'
HAVE_NATIVE_GCORE_HOST=1
LOADLIBES='-lkvm'
;;
diff --git a/gdb/fbsd-nat.c b/gdb/fbsd-nat.c
index a255318d14..3e2157f81d 100644
--- a/gdb/fbsd-nat.c
+++ b/gdb/fbsd-nat.c
@@ -1625,6 +1625,14 @@ fbsd_nat_target::post_attach (int pid)
fbsd_add_threads (pid);
}
+CORE_ADDR
+fbsd_nat_target::get_thread_local_address (ptid_t ptid,
+ CORE_ADDR linkmap,
+ CORE_ADDR offset)
+{
+ return fbsd_thr_db_get_tls_address(ptid, linkmap, offset);
+}
+
#ifdef PL_FLAG_EXEC
/* If the FreeBSD kernel supports PL_FLAG_EXEC, then traced processes
will always stop after exec. */
diff --git a/gdb/fbsd-nat.h b/gdb/fbsd-nat.h
index 3e34600e15..120e89b8ce 100644
--- a/gdb/fbsd-nat.h
+++ b/gdb/fbsd-nat.h
@@ -30,6 +30,10 @@
# endif
#endif
+/* Below TLS function is implmented in fbsd-thread-db.c */
+extern CORE_ADDR fbsd_thr_db_get_tls_address (ptid_t ptid, CORE_ADDR linkmap,
+ CORE_ADDR offset);
+
/* A prototype FreeBSD target. */
class fbsd_nat_target : public inf_ptrace_target
@@ -60,6 +64,10 @@ public:
void update_thread_list () override;
+ CORE_ADDR get_thread_local_address (ptid_t ptid,
+ CORE_ADDR load_module_addr,
+ CORE_ADDR offset) override;
+
thread_control_capabilities get_thread_control_capabilities () override
{ return tc_schedlock; }
diff --git a/gdb/fbsd-thread-db.c b/gdb/fbsd-thread-db.c
new file mode 100644
index 0000000000..dcc942d351
--- /dev/null
+++ b/gdb/fbsd-thread-db.c
@@ -0,0 +1,737 @@
+/* libthread_db assisted debugging support.
+
+ Copyright (C) 1999-2018 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 <dlfcn.h>
+#include "gdb_proc_service.h"
+#include "nat/gdb_thread_db.h"
+#include "gdb_vecs.h"
+#include "bfd.h"
+#include "command.h"
+#include "gdbcmd.h"
+#include "gdbthread.h"
+#include "inferior.h"
+#include "infrun.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "target.h"
+#include "regcache.h"
+#include "gregset.h"
+#include "solib.h"
+#include "solib-svr4.h"
+#include "gdbcore.h"
+#include "observable.h"
+#include "fbsd-nat.h"
+
+#include <sys/types.h>
+#include <sys/ptrace.h>
+#include <signal.h>
+#if defined(__i386__)
+#include "i387-tdep.h"
+#endif
+
+#if defined (__i386__) && defined (PT_GETXMMREGS)
+#define I386_GETXMMREGS
+#endif
+
+
+static const char *libthread_db_name = "libthread_db.so";
+static const char *libthread_db_path = "/usr/lib";
+
+/* If non-zero, print details of libthread_db processing. */
+static unsigned int libthread_db_debug;
+
+struct thread_db_info
+{
+ struct thread_db_info *next;
+
+ /* Process id this object refers to. */
+ int pid;
+
+ /* Handle from dlopen for libthread_db.so. */
+ void *handle;
+
+ /* Absolute pathname from gdb_realpath to disk file used for dlopen-ing
+ HANDLE. It may be NULL for system library. */
+ char *filename;
+
+ /* Structure that identifies the child process for the
+ <proc_service.h> interface. */
+ struct ps_prochandle proc_handle;
+
+ /* Connection to the libthread_db library. */
+ td_thragent_t *thread_agent;
+
+ /* True if we need to apply the workaround for glibc/BZ5983. When
+ we catch a PTRACE_O_TRACEFORK, and go query the child's thread
+ list, nptl_db returns the parent's threads in addition to the new
+ (single) child thread. If this flag is set, we do extra work to
+ be able to ignore such stale entries. */
+ int need_stale_parent_threads_check;
+
+ /* Pointers to the libthread_db functions. */
+
+ td_init_ftype *td_init_p;
+ td_ta_new_ftype *td_ta_new_p;
+ td_ta_map_lwp2thr_ftype *td_ta_map_lwp2thr_p;
+ td_ta_thr_iter_ftype *td_ta_thr_iter_p;
+ td_thr_get_info_ftype *td_thr_get_info_p;
+ td_thr_tls_get_addr_ftype *td_thr_tls_get_addr_p;
+};
+
+/* List of known processes using thread_db, and the required
+ bookkeeping. */
+struct thread_db_info *thread_db_list;
+
+/* Add the current inferior to the list of processes using libpthread.
+ Return a pointer to the newly allocated object that was added to
+ THREAD_DB_LIST. HANDLE is the handle returned by dlopen'ing
+ LIBTHREAD_DB_SO. */
+
+static struct thread_db_info *
+add_thread_db_info (void *handle)
+{
+ struct thread_db_info *info = XCNEW (struct thread_db_info);
+
+ info->pid = inferior_ptid.pid ();
+ info->handle = handle;
+
+ /* The workaround works by reading from /proc/pid/status, so it is
+ disabled for core files. */
+ if (target_has_execution)
+ info->need_stale_parent_threads_check = 1;
+
+ info->next = thread_db_list;
+ thread_db_list = info;
+
+ return info;
+}
+
+/* Return the thread_db_info object representing the bookkeeping
+ related to process PID, if any; NULL otherwise. */
+
+static struct thread_db_info *
+get_thread_db_info (int pid)
+{
+ struct thread_db_info *info;
+
+ for (info = thread_db_list; info; info = info->next)
+ if (pid == info->pid)
+ return info;
+
+ return NULL;
+}
+
+/* When PID has exited or has been detached, we no longer want to keep
+ track of it as using libpthread. Call this function to discard
+ thread_db related info related to PID. Note that this closes
+ LIBTHREAD_DB_SO's dlopen'ed handle. */
+
+static void
+delete_thread_db_info (int pid)
+{
+ struct thread_db_info *info, *info_prev;
+
+ info_prev = NULL;
+
+ for (info = thread_db_list; info; info_prev = info, info = info->next)
+ if (pid == info->pid)
+ break;
+
+ if (info == NULL)
+ return;
+
+ if (info->handle != NULL)
+ dlclose (info->handle);
+
+ if (info_prev)
+ info_prev->next = info->next;
+ else
+ thread_db_list = info->next;
+
+ xfree (info);
+}
+
+static const char *
+thread_db_err_str (td_err_e err)
+{
+ static char buf[64];
+
+ switch (err)
+ {
+ case TD_OK:
+ return "generic 'call succeeded'";
+ case TD_ERR:
+ return "generic error";
+ case TD_NOTHR:
+ return "no thread to satisfy query";
+ case TD_NOSV:
+ return "no sync handle to satisfy query";
+ case TD_NOLWP:
+ return "no LWP to satisfy query";
+ case TD_BADPH:
+ return "invalid process handle";
+ case TD_BADTH:
+ return "invalid thread handle";
+ case TD_BADSH:
+ return "invalid synchronization handle";
+ case TD_BADTA:
+ return "invalid thread agent";
+ case TD_BADKEY:
+ return "invalid key";
+ case TD_NOMSG:
+ return "no event message for getmsg";
+ case TD_NOFPREGS:
+ return "FPU register set not available";
+ case TD_NOLIBTHREAD:
+ return "application not linked with libthread";
+ case TD_NOEVENT:
+ return "requested event is not supported";
+ case TD_NOCAPAB:
+ return "capability not available";
+ case TD_DBERR:
+ return "debugger service failed";
+ case TD_NOAPLIC:
+ return "operation not applicable to";
+ case TD_NOTSD:
+ return "no thread-specific data for this thread";
+ case TD_MALLOC:
+ return "malloc failed";
+ case TD_PARTIALREG:
+ return "only part of register set was written/read";
+ case TD_NOXREGS:
+ return "X register set not available for this thread";
+#ifdef THREAD_DB_HAS_TD_NOTALLOC
+ case TD_NOTALLOC:
+ return "thread has not yet allocated TLS for given module";
+#endif
+#ifdef THREAD_DB_HAS_TD_VERSION
+ case TD_VERSION:
+ return "versions of libpthread and libthread_db do not match";
+#endif
+#ifdef THREAD_DB_HAS_TD_NOTLS
+ case TD_NOTLS:
+ return "there is no TLS segment in the given module";
+#endif
+ default:
+ snprintf (buf, sizeof (buf), "unknown thread_db error '%d'", err);
+ return buf;
+ }
+}
+
+static void
+core_get_first_lwp_callback (bfd *abfd, asection *asect, void *obj)
+{
+ if (strncmp (bfd_section_name (abfd, asect), ".reg/", 5) != 0)
+ return;
+
+ if (*(lwpid_t *) obj != 0)
+ return;
+
+ *(lwpid_t *) obj = atoi (bfd_section_name (abfd, asect) + 5);
+}
+
+CORE_ADDR
+fbsd_thr_db_get_tls_address (ptid_t ptid, CORE_ADDR linkmap, CORE_ADDR offset)
+{
+ td_thrhandle_t th;
+ struct thread_info *thread_info;
+ lwpid_t lwpid = 0;
+
+ if (!target_has_execution)
+ {
+ bfd_map_over_sections (core_bfd, core_get_first_lwp_callback, &lwpid);
+ ptid = ptid_t (ptid.pid(), lwpid, 0);
+ }
+
+ /* Find the matching thread. */
+ thread_info = find_thread_ptid (ptid);
+ if (thread_info != NULL)
+ {
+ td_err_e err;
+ psaddr_t address;
+ thread_db_info *info = get_thread_db_info (ptid.pid ());
+
+ if (linkmap == 0x0)
+ {
+ /* This code path handles the case of -static -lpthread executables: */
+ throw_error (TLS_GENERIC_ERROR,
+ (("Failed to handle -static -lpthread executable")));
+ }
+
+ err = info->td_ta_map_lwp2thr_p (info->thread_agent, ptid.lwp (), &th);
+ if (err != TD_OK) {
+ /* Cannot find user-level thread. */
+ error (_("Cannot find user-level thread for LWP %ld: %s"),
+ ptid.lwp (), thread_db_err_str (err));
+ return 0x0;
+ }
+
+ /* glibc doesn't provide the needed interface. */
+ if (!info->td_thr_tls_get_addr_p)
+ throw_error (TLS_NO_LIBRARY_SUPPORT_ERROR,
+ _("No TLS library support"));
+
+ /* Note the cast through uintptr_t: this interface only works if
+ a target address fits in a psaddr_t, which is a host pointer.
+ So a 32-bit debugger can not access 64-bit TLS through this. */
+ err = info->td_thr_tls_get_addr_p (&th,
+ (psaddr_t)(uintptr_t) linkmap,
+ offset, &address);
+
+#ifdef THREAD_DB_HAS_TD_NOTALLOC
+ /* The memory hasn't been allocated, yet. */
+ if (err == TD_NOTALLOC)
+ /* Now, if libthread_db provided the initialization image's
+ address, we *could* try to build a non-lvalue value from
+ the initialization image. */
+ throw_error (TLS_NOT_ALLOCATED_YET_ERROR,
+ _("TLS not allocated yet"));
+#endif
+ /* Something else went wrong. */
+ if (err != TD_OK)
+ throw_error (TLS_GENERIC_ERROR,
+ (("%s")), thread_db_err_str (err));
+
+ /* Do proper sign extension for the target. */
+ gdb_assert (exec_bfd);
+ return (bfd_get_sign_extend_vma (exec_bfd) > 0
+ ? (CORE_ADDR) (intptr_t) address
+ : (CORE_ADDR) (uintptr_t) address);
+ } else {
+ throw_error (TLS_GENERIC_ERROR,
+ (("Failed to get valid thread_info pointer")));
+ }
+ return 0x0;
+}
+
+static void
+show_libthread_db_debug (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c, const char *value)
+{
+ fprintf_filtered (file, _("FreeBSD libthread-db debug is %s\n"), value);
+}
+
+static void *
+verbose_dlsym (void *handle, const char *name)
+{
+ void *sym = dlsym (handle, name);
+ if (sym == NULL)
+ warning (_("THR-DB: Symbol \"%s\" not found in libthread_db: %s"),
+ name, dlerror ());
+ return sym;
+}
+
+/* Attempt to initialize dlopen()ed libthread_db, described by INFO.
+ Return 1 on success.
+ Failure could happen if libthread_db does not have symbols we expect,
+ or when it refuses to work with the current inferior (e.g. due to
+ version mismatch between libthread_db and libpthread). */
+
+static int
+try_thread_db_load_1 (struct thread_db_info *info)
+{
+ td_err_e err;
+
+#define TDB_VERBOSE_DLSYM(info, func) \
+ info->func ## _p = (func ## _ftype *) verbose_dlsym (info->handle, #func)
+
+#define CHK(a) \
+ do \
+ { \
+ if ((a) == NULL) \
+ return 0; \
+ } while (0)
+
+ /* Initialize pointers to the dynamic library functions we will use.
+ Essential functions first. */
+ CHK (TDB_VERBOSE_DLSYM (info, td_init));
+
+ err = info->td_init_p ();
+ if (err != TD_OK)
+ {
+ warning (_("Cannot initialize libthread_db: %s"),
+ thread_db_err_str (err));
+ return 0;
+ }
+
+ CHK (TDB_VERBOSE_DLSYM (info, td_ta_new));
+
+ /* Initialize the structure that identifies the child process. */
+ info->proc_handle.thread = find_thread_ptid (inferior_ptid);
+
+ /* Now attempt to open a connection to the thread library. */
+ err = info->td_ta_new_p (&info->proc_handle, &info->thread_agent);
+ if (err != TD_OK)
+ {
+ if (libthread_db_debug)
+ fprintf_unfiltered (gdb_stdlog, _("td_ta_new failed: %s\n"),
+ thread_db_err_str (err));
+ else
+ switch (err)
+ {
+ case TD_NOLIBTHREAD:
+#ifdef THREAD_DB_HAS_TD_VERSION
+ case TD_VERSION:
+#endif
+ /* The errors above are not unexpected and silently ignored:
+ they just mean we haven't found correct version of
+ libthread_db yet. */
+ break;
+ default:
+ warning (_("td_ta_new failed: %s"), thread_db_err_str (err));
+ }
+ return 0;
+ }
+
+ /* These are essential. */
+ CHK (TDB_VERBOSE_DLSYM (info, td_ta_map_lwp2thr));
+ CHK (TDB_VERBOSE_DLSYM (info, td_ta_thr_iter));
+ CHK (TDB_VERBOSE_DLSYM (info, td_thr_get_info));
+ CHK (TDB_VERBOSE_DLSYM (info, td_thr_tls_get_addr));
+
+ printf_unfiltered (_("[Thread debugging using libthread_db enabled]\n"));
+
+ return 1;
+}
+
+/* Attempt to use LIBRARY as libthread_db. LIBRARY could be absolute,
+ relative, or just LIBTHREAD_DB. */
+
+static int
+try_thread_db_load (char *library)
+{
+ void *handle;
+ struct thread_db_info *info;
+
+ if (libthread_db_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ _("Trying host libthread_db library: %s\n"),
+ library);
+
+ if (access (library, R_OK) != 0)
+ {
+ /* Do not print warnings by file_is_auto_load_safe if the library does
+ not exist at this place. */
+ if (libthread_db_debug)
+ fprintf_unfiltered (gdb_stdlog, _("open failed: %s.\n"),
+ safe_strerror (errno));
+ return 0;
+ }
+ handle = dlopen (library, RTLD_NOW);
+ if (handle == NULL)
+ {
+ if (libthread_db_debug)
+ fprintf_unfiltered (gdb_stdlog, _("dlopen failed: %s.\n"), dlerror ());
+ return 0;
+ }
+ info = add_thread_db_info (handle);
+ info->filename = library;
+
+ if (try_thread_db_load_1 (info))
+ return 1;
+
+ /* This library "refused" to work on current inferior. */
+ delete_thread_db_info (inferior_ptid.pid ());
+ return 0;
+}
+
+/* Search libthread_db_search_path for libthread_db which "agrees"
+ to work on current inferior.
+ The result is true for success. */
+
+static int
+thread_db_load_search (void)
+{
+ int rc = 0;
+ static char libpath[PATH_MAX];
+
+ sprintf(libpath, "%s/%s", libthread_db_path, libthread_db_name);
+ if (try_thread_db_load (libpath))
+ {
+ rc = 1;
+ }
+ if (libthread_db_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ _("THR-DB %s: returning %d\n"), __func__, rc);
+ return rc;
+}
+
+/* Return non-zero if the inferior has a libpthread. */
+
+static int
+has_libpthread (void)
+{
+ struct objfile *obj;
+
+ ALL_OBJFILES (obj)
+ if (libpthread_name_p (objfile_name (obj)))
+ return 1;
+
+ return 0;
+}
+
+/* Attempt to load and initialize libthread_db.
+ Return 1 on success. */
+
+static int
+thread_db_load (void)
+{
+ struct thread_db_info *info;
+
+ info = get_thread_db_info (inferior_ptid.pid ());
+
+ if (info != NULL)
+ return 1;
+
+ /* Don't attempt to use thread_db on executables not running
+ yet. */
+ if (!target_has_registers)
+ return 0;
+
+ /* Don't attempt to use thread_db for remote targets. */
+ if (!(target_can_run () || core_bfd))
+ return 0;
+
+ if (thread_db_load_search ())
+ return 1;
+
+ /* We couldn't find a libthread_db.
+ If the inferior has a libpthread warn the user. */
+ if (has_libpthread ())
+ {
+ warning (_("THR-DB: Unable to find libthread_db matching inferior's thread"
+ " library, thread debugging will not be available."));
+ return 0;
+ }
+
+ /* Either this executable isn't using libpthread at all, or it is
+ statically linked. Since we can't easily distinguish these two cases,
+ no warning is issued. */
+ return 0;
+}
+
+/* Check whether thread_db is usable. This function is called when
+ an inferior is created (or otherwise acquired, e.g. attached to)
+ and when new shared libraries are loaded into a running process. */
+
+void
+check_for_thread_db (void)
+{
+ /* Do nothing if we couldn't load libthread_db.so */
+ if (!thread_db_load ())
+ return;
+}
+
+/* This function is called via the new_objfile observer. */
+
+static void
+thread_db_new_objfile (struct objfile *objfile)
+{
+ /* This observer must always be called with inferior_ptid set
+ correctly. */
+
+ if (objfile != NULL)
+ check_for_thread_db ();
+}
+
+/* This function is called via the inferior_created observer.
+ This handles the case of debugging statically linked executables. */
+
+static void
+thread_db_inferior_created (struct target_ops *target, int from_tty)
+{
+ check_for_thread_db ();
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes. */
+extern initialize_file_ftype _initialize_thread_db;
+
+void
+_initialize_thread_db (void)
+{
+ add_setshow_zuinteger_cmd ("libthread-db", class_maintenance,
+ &libthread_db_debug, _("\
+ Set libthread-db debugging."), _("\
+ Show libthread-db debugging."), _("\
+ When non-zero, libthread-db debugging is enabled."),
+ NULL,
+ show_libthread_db_debug,
+ &setdebuglist, &showdebuglist);
+
+ /* Add ourselves to objfile event chain. */
+ gdb::observers::new_objfile.attach (thread_db_new_objfile);
+
+ /* Add ourselves to inferior_created event chain.
+ This is needed to handle debugging statically linked programs where
+ the new_objfile observer won't get called for libpthread. */
+ gdb::observers::inferior_created.attach (thread_db_inferior_created);
+}
+
+/* proc service functions */
+void
+ps_plog (const char *fmt, ...)
+{
+ va_list args;
+
+ va_start (args, fmt);
+ vfprintf_filtered (gdb_stdlog, fmt, args);
+ va_end (args);
+}
+
+ps_err_e
+ps_pglobal_lookup (struct ps_prochandle *ph, const char *obj,
+ const char *name, psaddr_t *sym_addr)
+{
+ struct bound_minimal_symbol ms;
+ CORE_ADDR addr;
+
+ ms = lookup_bound_minimal_symbol (name);
+ if (ms.minsym == NULL) {
+ if (libthread_db_debug) {
+ fprintf_unfiltered (gdb_stdlog, _("THR-DB %s: Sym : %s not found\n"),
+ __func__, name);
+ }
+ return PS_NOSYM;
+ }
+
+ addr = BMSYMBOL_VALUE_ADDRESS (ms);
+ store_typed_address ((gdb_byte *) sym_addr,
+ builtin_type (target_gdbarch ())->builtin_data_ptr, addr);
+ return PS_OK;
+}
+
+ps_err_e
+ps_pread (struct ps_prochandle *ph, psaddr_t addr, void *buf, size_t len)
+{
+ int err = target_read_memory (
+ extract_typed_address ((const gdb_byte *) &addr,
+ builtin_type (target_gdbarch ())->builtin_data_ptr), (gdb_byte *)buf, len);
+ return (err == 0 ? PS_OK : PS_ERR);
+}
+
+ps_err_e
+ps_pwrite (struct ps_prochandle *ph, psaddr_t addr, const void *buf,
+ size_t len)
+{
+ int err = target_write_memory (
+ extract_typed_address ((const gdb_byte *) &addr,
+ builtin_type (target_gdbarch ())->builtin_data_ptr), (const gdb_byte *) buf, len);
+ return (err == 0 ? PS_OK : PS_ERR);
+}
+
+ps_err_e
+ps_lgetregs (struct ps_prochandle *ph, lwpid_t lwpid, prgregset_t gregset)
+{
+ scoped_restore save_inferior_ptid = make_scoped_restore (&inferior_ptid);
+
+ /* Target operation isn't lwp aware: replace pid with lwp */
+ inferior_ptid = ptid_t (lwpid, 0, 0);
+ target_fetch_registers (get_current_regcache(), -1);
+ fill_gregset (get_current_regcache(), gregset, -1);
+ return PS_OK;
+}
+
+ps_err_e
+ps_lsetregs (struct ps_prochandle *ph, lwpid_t lwpid,
+ const prgregset_t gregset)
+{
+ scoped_restore save_inferior_ptid = make_scoped_restore (&inferior_ptid);
+ inferior_ptid = ptid_t (inferior_ptid.pid (), lwpid, 0);
+ supply_gregset (get_current_regcache(), (const gdb_gregset_t *) gregset);
+ target_store_registers (get_current_regcache(), -1);
+ return PS_OK;
+}
+
+ps_err_e
+ps_lgetfpregs (struct ps_prochandle *ph, lwpid_t lwpid, prfpregset_t *fpregset)
+{
+ scoped_restore save_inferior_ptid = make_scoped_restore (&inferior_ptid);
+ inferior_ptid = ptid_t (inferior_ptid.pid (), lwpid, 0);
+ target_fetch_registers (get_current_regcache(), -1);
+ fill_fpregset (get_current_regcache(), fpregset, -1);
+ return PS_OK;
+}
+
+ps_err_e
+ps_lsetfpregs (struct ps_prochandle *ph, lwpid_t lwpid,
+ const prfpregset_t *fpregset)
+{
+ scoped_restore save_inferior_ptid = make_scoped_restore (&inferior_ptid);
+ inferior_ptid = ptid_t (inferior_ptid.pid (), lwpid, 0);
+ supply_fpregset (get_current_regcache(), (gdb_fpregset_t *) fpregset);
+ target_store_registers (get_current_regcache(), -1);
+ return PS_OK;
+}
+
+#ifdef I386_GETXMMREGS
+ps_err_e
+ps_lgetxmmregs (struct ps_prochandle *ph, lwpid_t lwpid, char *xmmregs)
+{
+ scoped_restore save_inferior_ptid = make_scoped_restore (&inferior_ptid);
+ inferior_ptid = ptid_t (inferior_ptid.pid (), lwpid, 0);
+ target_fetch_registers (get_current_regcache (), -1);
+ i387_collect_fxsave (get_current_regcache (), -1, xmmregs);
+ return PS_OK;
+}
+
+ps_err_e
+ps_lsetxmmregs (struct ps_prochandle *ph, lwpid_t lwpid,
+ const char *xmmregs)
+{
+ scoped_restore save_inferior_ptid = make_scoped_restore (&inferior_ptid);
+ inferior_ptid = ptid_t (inferior_ptid.pid (), lwpid, 0);
+ i387_supply_fxsave (get_current_regcache (), -1, xmmregs);
+ target_store_registers (get_current_regcache (), -1);
+ return PS_OK;
+}
+#endif
+
+ps_err_e
+ps_lstop (struct ps_prochandle *ph, lwpid_t lwpid)
+{
+ if (ptrace (PT_SUSPEND, lwpid, 0, 0) == -1)
+ return PS_ERR;
+ return PS_OK;
+}
+
+ps_err_e
+ps_lcontinue (struct ps_prochandle *ph, lwpid_t lwpid)
+{
+ if (ptrace (PT_RESUME, lwpid, 0, 0) == -1)
+ return PS_ERR;
+ return PS_OK;
+}
+
+ps_err_e
+ps_linfo (struct ps_prochandle *ph, lwpid_t lwpid, void *info)
+{
+ if (target_has_execution)
+ {
+ if (ptrace (PT_LWPINFO, lwpid, (caddr_t)info,
+ sizeof (struct ptrace_lwpinfo)) == -1)
+ return PS_ERR;
+ return PS_OK;
+ }
+ else
+ {
+ memset (info, 0, sizeof (struct ptrace_lwpinfo));
+ return PS_OK;
+ }
+}
diff --git a/gdb/i386-bsd-nat.c b/gdb/i386-bsd-nat.c
index 09ea99fd19..b9e8ee3a53 100644
--- a/gdb/i386-bsd-nat.c
+++ b/gdb/i386-bsd-nat.c
@@ -340,3 +340,35 @@ Please report this to <bug-gdb@gnu.org>."),
#endif /* SC_REG_OFFSET */
}
+
+void
+supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
+{
+ i386bsd_supply_gregset (regcache, (const void *) gregsetp);
+}
+
+/* Fill GDB's register array with the floating-point register values in
+ *FPREGSETP. */
+
+void
+supply_fpregset (struct regcache *regcache, const gdb_fpregset_t *fpregsetp)
+{
+ i387_supply_fsave (regcache, -1, fpregsetp);
+}
+
+void
+fill_gregset (const struct regcache *regcache, gdb_gregset_t *gregsetp, int regno)
+{
+ i386bsd_collect_gregset (regcache, (void *) gregsetp, regno);
+}
+
+/* Fill register REGNO (if it is a floating-point register) in
+ *FPREGSETP with the value in GDB's register array. If REGNO is -1,
+ do this for all registers. */
+
+void
+fill_fpregset (const struct regcache *regcache, gdb_fpregset_t *fpregsetp, int regno)
+{
+ i387_collect_fsave (regcache, regno, fpregsetp);
+}
+
--
2.14.3 (Apple Git-98)
next prev parent reply other threads:[~2018-09-19 16:52 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-09-15 13:21 Rajendra SY
2018-09-17 17:11 ` John Baldwin
2018-09-19 16:52 ` Rajendra SY [this message]
2018-09-19 16:59 ` Pedro Alves
2018-09-20 4:38 ` Rajendra SY
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAMAnt0mHKNfZRcj+XHW+ft0=gd-49Ym-Lyf1rGK5B-foJYsr8A@mail.gmail.com' \
--to=rajendra.sy@gmail.com \
--cc=gdb-patches@sourceware.org \
--cc=jhb@freebsd.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox