/* Thread management interface, for the remote server for GDB.
- Copyright (C) 2002, 2004, 2005, 2006, 2007, 2008, 2009, 2010
- Free Software Foundation, Inc.
+ Copyright (C) 2002-2015 Free Software Foundation, Inc.
Contributed by MontaVista Software.
static int thread_db_use_events;
#include "gdb_proc_service.h"
-#include "../gdb_thread_db.h"
+#include "nat/gdb_thread_db.h"
+#include "gdb_vecs.h"
+#include "nat/linux-procfs.h"
#ifndef USE_LIBTHREAD_DB_DIRECTLY
#include <dlfcn.h>
#endif
-
-#include <stdint.h>
#include <limits.h>
#include <ctype.h>
struct breakpoint *td_create_bp;
/* Addresses of libthread_db functions. */
- td_err_e (*td_ta_new_p) (struct ps_prochandle * ps, td_thragent_t **ta);
- td_err_e (*td_ta_event_getmsg_p) (const td_thragent_t *ta,
- td_event_msg_t *msg);
- td_err_e (*td_ta_set_event_p) (const td_thragent_t *ta,
- td_thr_events_t *event);
- td_err_e (*td_ta_event_addr_p) (const td_thragent_t *ta,
- td_event_e event, td_notify_t *ptr);
- td_err_e (*td_ta_map_lwp2thr_p) (const td_thragent_t *ta, lwpid_t lwpid,
- td_thrhandle_t *th);
- td_err_e (*td_thr_get_info_p) (const td_thrhandle_t *th,
- td_thrinfo_t *infop);
- td_err_e (*td_thr_event_enable_p) (const td_thrhandle_t *th, int event);
- td_err_e (*td_ta_thr_iter_p) (const td_thragent_t *ta,
- td_thr_iter_f *callback, void *cbdata_p,
- td_thr_state_e state, int ti_pri,
- sigset_t *ti_sigmask_p,
- unsigned int ti_user_flags);
- td_err_e (*td_thr_tls_get_addr_p) (const td_thrhandle_t *th,
- psaddr_t map_address,
- size_t offset, psaddr_t *address);
- const char ** (*td_symbol_list_p) (void);
+ td_ta_new_ftype *td_ta_new_p;
+ td_ta_event_getmsg_ftype * td_ta_event_getmsg_p;
+ td_ta_set_event_ftype *td_ta_set_event_p;
+ td_ta_event_addr_ftype *td_ta_event_addr_p;
+ td_ta_map_lwp2thr_ftype *td_ta_map_lwp2thr_p;
+ td_thr_get_info_ftype *td_thr_get_info_p;
+ td_thr_event_enable_ftype *td_thr_event_enable_p;
+ td_ta_thr_iter_ftype *td_ta_thr_iter_p;
+ td_thr_tls_get_addr_ftype *td_thr_tls_get_addr_p;
+ td_thr_tlsbase_ftype *td_thr_tlsbase_p;
+ td_symbol_list_ftype *td_symbol_list_p;
};
static char *libthread_db_search_path;
td_event_msg_t msg;
td_err_e err;
struct lwp_info *lwp;
- struct thread_db *thread_db = current_process ()->private->thread_db;
+ struct thread_db *thread_db = current_process ()->priv->thread_db;
- if (thread_db->td_ta_event_getmsg_p == NULL)
- fatal ("unexpected thread_db->td_ta_event_getmsg_p == NULL");
+ gdb_assert (thread_db->td_ta_event_getmsg_p != NULL);
if (debug_threads)
- fprintf (stderr, "Thread creation event.\n");
+ debug_printf ("Thread creation event.\n");
/* FIXME: This assumes we don't get another event.
In the LinuxThreads implementation, this is safe,
/* If we do not know about the main thread yet, this would be a good time to
find it. We need to do this to pick up the main thread before any newly
created threads. */
- lwp = get_thread_lwp (current_inferior);
+ lwp = get_thread_lwp (current_thread);
if (lwp->thread_known == 0)
- find_one_thread (lwp->head.id);
+ find_one_thread (current_thread->entry.id);
/* msg.event == TD_EVENT_CREATE */
td_thr_events_t events;
td_notify_t notify;
td_err_e err;
- struct thread_db *thread_db = current_process ()->private->thread_db;
+ struct thread_db *thread_db = current_process ()->priv->thread_db;
if (thread_db->td_ta_set_event_p == NULL
|| thread_db->td_ta_event_addr_p == NULL
td_err_e err;
struct thread_info *inferior;
struct lwp_info *lwp;
- struct thread_db *thread_db = current_process ()->private->thread_db;
+ struct thread_db *thread_db = current_process ()->priv->thread_db;
int lwpid = ptid_get_lwp (ptid);
inferior = (struct thread_info *) find_inferior_id (&all_threads, ptid);
lwpid, thread_db_err_str (err));
if (debug_threads)
- fprintf (stderr, "Found thread %ld (LWP %d)\n",
- ti.ti_tid, ti.ti_lid);
+ debug_printf ("Found thread %ld (LWP %d)\n",
+ (unsigned long) ti.ti_tid, ti.ti_lid);
if (lwpid != ti.ti_lid)
{
static int
attach_thread (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p)
{
+ struct process_info *proc = current_process ();
+ int pid = pid_of (proc);
+ ptid_t ptid = ptid_build (pid, ti_p->ti_lid, 0);
struct lwp_info *lwp;
+ int err;
if (debug_threads)
- fprintf (stderr, "Attaching to thread %ld (LWP %d)\n",
- ti_p->ti_tid, ti_p->ti_lid);
- linux_attach_lwp (ti_p->ti_lid);
- lwp = find_lwp_pid (pid_to_ptid (ti_p->ti_lid));
- if (lwp == NULL)
+ debug_printf ("Attaching to thread %ld (LWP %d)\n",
+ (unsigned long) ti_p->ti_tid, ti_p->ti_lid);
+ err = linux_attach_lwp (ptid);
+ if (err != 0)
{
- warning ("Could not attach to thread %ld (LWP %d)\n",
- ti_p->ti_tid, ti_p->ti_lid);
+ warning ("Could not attach to thread %ld (LWP %d): %s\n",
+ (unsigned long) ti_p->ti_tid, ti_p->ti_lid,
+ linux_ptrace_attach_fail_reason_string (ptid, err));
return 0;
}
+ lwp = find_lwp_pid (ptid);
+ gdb_assert (lwp != NULL);
lwp->thread_known = 1;
lwp->th = *th_p;
if (thread_db_use_events)
{
td_err_e err;
- struct thread_db *thread_db = current_process ()->private->thread_db;
+ struct thread_db *thread_db = proc->priv->thread_db;
err = thread_db->td_thr_event_enable_p (th_p, 1);
if (err != TD_OK)
{
td_thrinfo_t ti;
td_err_e err;
- struct thread_db *thread_db = current_process ()->private->thread_db;
+ struct thread_db *thread_db = current_process ()->priv->thread_db;
err = thread_db->td_thr_get_info_p (th_p, &ti);
if (err != TD_OK)
error ("Cannot get thread info: %s", thread_db_err_str (err));
+ if (ti.ti_lid == -1)
+ {
+ /* A thread with kernel thread ID -1 is either a thread that
+ exited and was joined, or a thread that is being created but
+ hasn't started yet, and that is reusing the tcb/stack of a
+ thread that previously exited and was joined. (glibc marks
+ terminated and joined threads with kernel thread ID -1. See
+ glibc PR17707. */
+ if (debug_threads)
+ debug_printf ("thread_db: skipping exited and "
+ "joined thread (0x%lx)\n",
+ (unsigned long) ti.ti_tid);
+ return 0;
+ }
+
/* Check for zombies. */
if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE)
return 0;
thread_db_find_new_threads (void)
{
td_err_e err;
- ptid_t ptid = ((struct inferior_list_entry *) current_inferior)->id;
- struct thread_db *thread_db = current_process ()->private->thread_db;
+ ptid_t ptid = current_ptid;
+ struct thread_db *thread_db = current_process ()->priv->thread_db;
int loop, iteration;
/* This function is only called when we first initialize thread_db.
err = thread_db->td_ta_thr_iter_p (thread_db->thread_agent,
find_new_threads_callback,
&new_thread_count,
- TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
+ TD_THR_ANY_STATE,
+ TD_THR_LOWEST_PRIORITY,
TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
if (debug_threads)
- fprintf (stderr, "Found %d threads in iteration %d.\n",
- new_thread_count, iteration);
+ debug_printf ("Found %d threads in iteration %d.\n",
+ new_thread_count, iteration);
if (new_thread_count != 0)
{
static void
thread_db_look_up_symbols (void)
{
- struct thread_db *thread_db = current_process ()->private->thread_db;
+ struct thread_db *thread_db = current_process ()->priv->thread_db;
const char **sym_list;
CORE_ADDR unused;
int
thread_db_look_up_one_symbol (const char *name, CORE_ADDR *addrp)
{
- struct thread_db *thread_db = current_process ()->private->thread_db;
+ struct thread_db *thread_db = current_process ()->priv->thread_db;
int may_ask_gdb = !thread_db->all_symbols_looked_up;
/* If we've passed the call to thread_db_look_up_symbols, then
psaddr_t addr;
td_err_e err;
struct lwp_info *lwp;
- struct thread_info *saved_inferior;
+ struct thread_info *saved_thread;
struct process_info *proc;
struct thread_db *thread_db;
proc = get_thread_process (thread);
- thread_db = proc->private->thread_db;
+ thread_db = proc->priv->thread_db;
/* If the thread layer is not (yet) initialized, fail. */
- if (!thread_db->all_symbols_looked_up)
+ if (thread_db == NULL || !thread_db->all_symbols_looked_up)
return TD_ERR;
- if (thread_db->td_thr_tls_get_addr_p == NULL)
+ /* If td_thr_tls_get_addr is missing rather do not expect td_thr_tlsbase
+ could work. */
+ if (thread_db->td_thr_tls_get_addr_p == NULL
+ || (load_module == 0 && thread_db->td_thr_tlsbase_p == NULL))
return -1;
lwp = get_thread_lwp (thread);
if (!lwp->thread_known)
- find_one_thread (lwp->head.id);
+ find_one_thread (thread->entry.id);
if (!lwp->thread_known)
return TD_NOTHR;
- saved_inferior = current_inferior;
- current_inferior = thread;
- /* 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 = thread_db->td_thr_tls_get_addr_p (&lwp->th,
- (psaddr_t) (uintptr_t) load_module,
- offset, &addr);
- current_inferior = saved_inferior;
+ saved_thread = current_thread;
+ current_thread = thread;
+
+ if (load_module != 0)
+ {
+ /* 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 = thread_db->td_thr_tls_get_addr_p (&lwp->th,
+ (psaddr_t) (uintptr_t) load_module,
+ offset, &addr);
+ }
+ else
+ {
+ /* This code path handles the case of -static -pthread executables:
+ https://sourceware.org/ml/libc-help/2014-03/msg00024.html
+ For older GNU libc r_debug.r_map is NULL. For GNU libc after
+ PR libc/16831 due to GDB PR threads/16954 LOAD_MODULE is also NULL.
+ The constant number 1 depends on GNU __libc_setup_tls
+ initialization of l_tls_modid to 1. */
+ err = thread_db->td_thr_tlsbase_p (&lwp->th, 1, &addr);
+ addr = (char *) addr + offset;
+ }
+
+ current_thread = saved_thread;
if (err == TD_OK)
{
*address = (CORE_ADDR) (uintptr_t) addr;
struct thread_db *tdb;
struct process_info *proc = current_process ();
- if (proc->private->thread_db != NULL)
- fatal ("unexpected: proc->private->thread_db != NULL");
+ gdb_assert (proc->priv->thread_db == NULL);
- tdb = xcalloc (1, sizeof (*tdb));
- proc->private->thread_db = tdb;
+ tdb = XCNEW (struct thread_db);
+ proc->priv->thread_db = tdb;
tdb->td_ta_new_p = &td_ta_new;
if (err != TD_OK)
{
if (debug_threads)
- fprintf (stderr, "td_ta_new(): %s\n", thread_db_err_str (err));
+ debug_printf ("td_ta_new(): %s\n", thread_db_err_str (err));
free (tdb);
- proc->private->thread_db = NULL;
+ proc->priv->thread_db = NULL;
return 0;
}
tdb->td_ta_set_event_p = &td_ta_set_event;
tdb->td_ta_event_getmsg_p = &td_ta_event_getmsg;
tdb->td_thr_tls_get_addr_p = &td_thr_tls_get_addr;
+ tdb->td_thr_tlsbase_p = &td_thr_tlsbase;
return 1;
}
struct thread_db *tdb;
struct process_info *proc = current_process ();
- if (proc->private->thread_db != NULL)
- fatal ("unexpected: proc->private->thread_db != NULL");
+ gdb_assert (proc->priv->thread_db == NULL);
- tdb = xcalloc (1, sizeof (*tdb));
- proc->private->thread_db = tdb;
+ tdb = XCNEW (struct thread_db);
+ proc->priv->thread_db = tdb;
tdb->handle = handle;
if ((a) == NULL) \
{ \
if (debug_threads) \
- fprintf (stderr, "dlsym: %s\n", dlerror ()); \
+ debug_printf ("dlsym: %s\n", dlerror ()); \
if (required) \
{ \
free (tdb); \
- proc->private->thread_db = NULL; \
+ proc->priv->thread_db = NULL; \
return 0; \
} \
} \
} \
while (0)
- CHK (1, tdb->td_ta_new_p = dlsym (handle, "td_ta_new"));
+#define TDB_DLSYM(tdb, func) \
+ tdb->func ## _p = (func ## _ftype *) dlsym (tdb->handle, #func)
+
+ CHK (1, TDB_DLSYM (tdb, td_ta_new));
/* Attempt to open a connection to the thread library. */
err = tdb->td_ta_new_p (&tdb->proc_handle, &tdb->thread_agent);
if (err != TD_OK)
{
if (debug_threads)
- fprintf (stderr, "td_ta_new(): %s\n", thread_db_err_str (err));
+ debug_printf ("td_ta_new(): %s\n", thread_db_err_str (err));
free (tdb);
- proc->private->thread_db = NULL;
+ proc->priv->thread_db = NULL;
return 0;
}
- CHK (1, tdb->td_ta_map_lwp2thr_p = dlsym (handle, "td_ta_map_lwp2thr"));
- CHK (1, tdb->td_thr_get_info_p = dlsym (handle, "td_thr_get_info"));
- CHK (1, tdb->td_ta_thr_iter_p = dlsym (handle, "td_ta_thr_iter"));
- CHK (1, tdb->td_symbol_list_p = dlsym (handle, "td_symbol_list"));
+ CHK (1, TDB_DLSYM (tdb, td_ta_map_lwp2thr));
+ CHK (1, TDB_DLSYM (tdb, td_thr_get_info));
+ CHK (1, TDB_DLSYM (tdb, td_ta_thr_iter));
+ CHK (1, TDB_DLSYM (tdb, td_symbol_list));
/* This is required only when thread_db_use_events is on. */
- CHK (thread_db_use_events,
- tdb->td_thr_event_enable_p = dlsym (handle, "td_thr_event_enable"));
+ CHK (thread_db_use_events, TDB_DLSYM (tdb, td_thr_event_enable));
/* These are not essential. */
- CHK (0, tdb->td_ta_event_addr_p = dlsym (handle, "td_ta_event_addr"));
- CHK (0, tdb->td_ta_set_event_p = dlsym (handle, "td_ta_set_event"));
- CHK (0, tdb->td_ta_event_getmsg_p = dlsym (handle, "td_ta_event_getmsg"));
- CHK (0, tdb->td_thr_tls_get_addr_p = dlsym (handle, "td_thr_tls_get_addr"));
+ CHK (0, TDB_DLSYM (tdb, td_ta_event_addr));
+ CHK (0, TDB_DLSYM (tdb, td_ta_set_event));
+ CHK (0, TDB_DLSYM (tdb, td_ta_event_getmsg));
+ CHK (0, TDB_DLSYM (tdb, td_thr_tls_get_addr));
+ CHK (0, TDB_DLSYM (tdb, td_thr_tlsbase));
#undef CHK
+#undef TDB_DLSYM
return 1;
}
void *handle;
if (debug_threads)
- fprintf (stderr, "Trying host libthread_db library: %s.\n",
- library);
+ debug_printf ("Trying host libthread_db library: %s.\n",
+ library);
handle = dlopen (library, RTLD_NOW);
if (handle == NULL)
{
if (debug_threads)
- fprintf (stderr, "dlopen failed: %s.\n", dlerror ());
+ debug_printf ("dlopen failed: %s.\n", dlerror ());
return 0;
}
return 0;
}
+/* Handle $sdir in libthread-db-search-path.
+ Look for libthread_db in the system dirs, or wherever a plain
+ dlopen(file_without_path) will look.
+ The result is true for success. */
+
+static int
+try_thread_db_load_from_sdir (void)
+{
+ return try_thread_db_load (LIBTHREAD_DB_SO);
+}
+
+/* Try to load libthread_db from directory DIR of length DIR_LEN.
+ The result is true for success. */
+
static int
-thread_db_load_search (void)
+try_thread_db_load_from_dir (const char *dir, size_t dir_len)
{
char path[PATH_MAX];
- const char *search_path;
- int rc = 0;
+
+ if (dir_len + 1 + strlen (LIBTHREAD_DB_SO) + 1 > sizeof (path))
+ {
+ char *cp = (char *) xmalloc (dir_len + 1);
+
+ memcpy (cp, dir, dir_len);
+ cp[dir_len] = '\0';
+ warning (_("libthread-db-search-path component too long,"
+ " ignored: %s."), cp);
+ free (cp);
+ return 0;
+ }
+
+ memcpy (path, dir, dir_len);
+ path[dir_len] = '/';
+ strcpy (path + dir_len + 1, LIBTHREAD_DB_SO);
+ return try_thread_db_load (path);
+}
+
+/* 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)
+{
+ VEC (char_ptr) *dir_vec;
+ char *this_dir;
+ int i, rc = 0;
if (libthread_db_search_path == NULL)
libthread_db_search_path = xstrdup (LIBTHREAD_DB_SEARCH_PATH);
- search_path = libthread_db_search_path;
- while (*search_path)
+ dir_vec = dirnames_to_char_ptr_vec (libthread_db_search_path);
+
+ for (i = 0; VEC_iterate (char_ptr, dir_vec, i, this_dir); ++i)
{
- const char *end = strchr (search_path, ':');
- if (end)
+ const int pdir_len = sizeof ("$pdir") - 1;
+ size_t this_dir_len;
+
+ this_dir_len = strlen (this_dir);
+
+ if (strncmp (this_dir, "$pdir", pdir_len) == 0
+ && (this_dir[pdir_len] == '\0'
+ || this_dir[pdir_len] == '/'))
{
- size_t len = end - search_path;
- if (len + 1 + strlen (LIBTHREAD_DB_SO) + 1 > sizeof (path))
+ /* We don't maintain a list of loaded libraries so we don't know
+ where libpthread lives. We *could* fetch the info, but we don't
+ do that yet. Ignore it. */
+ }
+ else if (strcmp (this_dir, "$sdir") == 0)
+ {
+ if (try_thread_db_load_from_sdir ())
{
- char *cp = xmalloc (len + 1);
- memcpy (cp, search_path, len);
- cp[len] = '\0';
- warning ("libthread_db_search_path component too long, "
- "ignored: %s.", cp);
- free (cp);
- search_path += len + 1;
- continue;
+ rc = 1;
+ break;
}
- memcpy (path, search_path, len);
- path[len] = '\0';
- search_path += len + 1;
}
else
{
- size_t len = strlen (search_path);
-
- if (len + 1 + strlen (LIBTHREAD_DB_SO) + 1 > sizeof (path))
+ if (try_thread_db_load_from_dir (this_dir, this_dir_len))
{
- warning ("libthread_db_search_path component too long,"
- " ignored: %s.", search_path);
+ rc = 1;
break;
}
- memcpy (path, search_path, len + 1);
- search_path += len;
- }
- strcat (path, "/");
- strcat (path, LIBTHREAD_DB_SO);
- if (debug_threads)
- fprintf (stderr, "thread_db_load_search trying %s\n", path);
- if (try_thread_db_load (path))
- {
- rc = 1;
- break;
}
}
- if (rc == 0)
- rc = try_thread_db_load (LIBTHREAD_DB_SO);
+ free_char_ptr_vec (dir_vec);
if (debug_threads)
- fprintf (stderr, "thread_db_load_search returning %d\n", rc);
+ debug_printf ("thread_db_load_search returning %d\n", rc);
return rc;
}
thread_db_mourn (proc);
return 0;
}
- thread_db_find_new_threads ();
+
+ /* It's best to avoid td_ta_thr_iter if possible. That walks
+ data structures in the inferior's address space that may be
+ corrupted, or, if the target is running, the list may change
+ while we walk it. In the latter case, it's possible that a
+ thread exits just at the exact time that causes GDBserver to
+ get stuck in an infinite loop. If the kernel supports clone
+ events, and /proc/PID/task/ exits, then we already know about
+ all threads in the process. When we need info out of
+ thread_db on a given thread (e.g., for TLS), we'll use
+ find_one_thread then. That uses thread_db entry points that
+ do not walk libpthread's thread list, so should be safe, as
+ well as more efficient. */
+ if (use_events
+ || !linux_proc_task_list_dir_exists (pid_of (proc)))
+ thread_db_find_new_threads ();
thread_db_look_up_symbols ();
return 1;
}
static int
any_thread_of (struct inferior_list_entry *entry, void *args)
{
- int *pid_p = args;
+ int *pid_p = (int *) args;
if (ptid_get_pid (entry->id) == *pid_p)
return 1;
{
int pid = pid_of (proc);
- current_inferior =
+ current_thread =
(struct thread_info *) find_inferior (&all_threads,
any_thread_of, &pid);
}
static void
disable_thread_event_reporting (struct process_info *proc)
{
- struct thread_db *thread_db = proc->private->thread_db;
+ struct thread_db *thread_db = proc->priv->thread_db;
if (thread_db)
{
td_err_e (*td_ta_clear_event_p) (const td_thragent_t *ta,
td_thr_events_t *event);
#ifndef USE_LIBTHREAD_DB_DIRECTLY
- td_ta_clear_event_p = dlsym (thread_db->handle, "td_ta_clear_event");
+ td_ta_clear_event_p
+ = (td_ta_clear_event_ftype *) dlsym (thread_db->handle,
+ "td_ta_clear_event");
#else
td_ta_clear_event_p = &td_ta_clear_event;
#endif
if (td_ta_clear_event_p != NULL)
{
- struct thread_info *saved_inferior = current_inferior;
+ struct thread_info *saved_thread = current_thread;
td_thr_events_t events;
switch_to_process (proc);
td_event_fillset (&events);
(*td_ta_clear_event_p) (thread_db->thread_agent, &events);
- current_inferior = saved_inferior;
+ current_thread = saved_thread;
}
}
}
static void
remove_thread_event_breakpoints (struct process_info *proc)
{
- struct thread_db *thread_db = proc->private->thread_db;
+ struct thread_db *thread_db = proc->priv->thread_db;
if (thread_db->td_create_bp != NULL)
{
- struct thread_info *saved_inferior = current_inferior;
+ struct thread_info *saved_thread = current_thread;
switch_to_process (proc);
delete_breakpoint (thread_db->td_create_bp);
thread_db->td_create_bp = NULL;
- current_inferior = saved_inferior;
+ current_thread = saved_thread;
}
}
void
thread_db_detach (struct process_info *proc)
{
- struct thread_db *thread_db = proc->private->thread_db;
+ struct thread_db *thread_db = proc->priv->thread_db;
if (thread_db)
{
void
thread_db_mourn (struct process_info *proc)
{
- struct thread_db *thread_db = proc->private->thread_db;
+ struct thread_db *thread_db = proc->priv->thread_db;
if (thread_db)
{
- td_err_e (*td_ta_delete_p) (td_thragent_t *);
+ td_ta_delete_ftype *td_ta_delete_p;
#ifndef USE_LIBTHREAD_DB_DIRECTLY
- td_ta_delete_p = dlsym (thread_db->handle, "td_ta_delete");
+ td_ta_delete_p = (td_ta_delete_ftype *) dlsym (thread_db->handle, "td_ta_delete");
#else
td_ta_delete_p = &td_ta_delete;
#endif
#endif /* USE_LIBTHREAD_DB_DIRECTLY */
free (thread_db);
- proc->private->thread_db = NULL;
+ proc->priv->thread_db = NULL;
}
}
int
thread_db_handle_monitor_command (char *mon)
{
- if (strncmp (mon, "set libthread-db-search-path ", 29) == 0)
+ const char *cmd = "set libthread-db-search-path";
+ size_t cmd_len = strlen (cmd);
+
+ if (strncmp (mon, cmd, cmd_len) == 0
+ && (mon[cmd_len] == '\0'
+ || mon[cmd_len] == ' '))
{
- const char *cp = mon + 29;
+ const char *cp = mon + cmd_len;
if (libthread_db_search_path != NULL)
free (libthread_db_search_path);
while (isspace (*cp))
++cp;
+ if (*cp == '\0')
+ cp = LIBTHREAD_DB_SEARCH_PATH;
libthread_db_search_path = xstrdup (cp);
monitor_output ("libthread-db-search-path set to `");