/* libthread_db assisted debugging support, generic parts.
- Copyright (C) 1999-2016 Free Software Foundation, Inc.
+ Copyright (C) 1999-2017 Free Software Foundation, Inc.
This file is part of GDB.
#include <signal.h>
#include <ctype.h>
#include "nat/linux-namespaces.h"
+#include <algorithm>
/* GNU/Linux libthread_db support.
}
static void
-set_libthread_db_search_path (char *ignored, int from_tty,
+set_libthread_db_search_path (const char *ignored, int from_tty,
struct cmd_list_element *c)
{
if (*libthread_db_search_path == '\0')
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_validate_ftype *td_thr_validate_p;
td_thr_get_info_ftype *td_thr_get_info_p;
td_thr_tls_get_addr_ftype *td_thr_tls_get_addr_p;
td_thr_tlsbase_ftype *td_thr_tlsbase_p;
/* Use "struct private_thread_info" to cache thread state. This is
a substantial optimization. */
-struct private_thread_info
+struct thread_db_thread_info : public private_thread_info
{
/* Flag set when we see a TD_DEATH event for this thread. */
- unsigned int dying:1;
+ bool dying = false;
/* Cached thread state. */
- td_thrhandle_t th;
- thread_t tid;
+ td_thrhandle_t th {};
+ thread_t tid {};
};
-\f
-static char *
+static thread_db_thread_info *
+get_thread_db_thread_info (thread_info *thread)
+{
+ return static_cast<thread_db_thread_info *> (thread->priv.get ());
+}
+
+static const char *
thread_db_err_str (td_err_e err)
{
static char buf[64];
int
thread_db_notice_clone (ptid_t parent, ptid_t child)
{
- td_thrhandle_t th;
- td_thrinfo_t ti;
- td_err_e err;
struct thread_db_info *info;
info = get_thread_db_info (ptid_get_pid (child));
/* These are essential. */
CHK (TDB_VERBOSE_DLSYM (info, td_ta_map_lwp2thr));
- CHK (TDB_VERBOSE_DLSYM (info, td_thr_validate));
CHK (TDB_VERBOSE_DLSYM (info, td_thr_get_info));
/* These are not essential. */
/* Do not save system library name, that one is always trusted. */
if (strchr (library, '/') != NULL)
- info->filename = gdb_realpath (library);
+ info->filename = gdb_realpath (library).release ();
if (try_thread_db_load_1 (info))
return 1;
{
warning (_ ("Target and debugger are in different PID "
"namespaces; thread lists and other data are "
- "likely unreliable"));
+ "likely unreliable. "
+ "Connect to gdbserver inside the container."));
}
}
}
from libthread_db thread state information. */
static void
-update_thread_state (struct private_thread_info *priv,
+update_thread_state (thread_db_thread_info *priv,
const td_thrinfo_t *ti_p)
{
priv->dying = (ti_p->ti_state == TD_THR_UNKNOWN
ptid_t ptid, const td_thrhandle_t *th_p,
const td_thrinfo_t *ti_p)
{
- td_err_e err;
- struct private_thread_info *priv;
- int new_thread = (tp == NULL);
-
/* A thread ID of zero may mean the thread library has not
initialized yet. Leave private == NULL until the thread library
has initialized. */
return tp;
/* Construct the thread's private data. */
- priv = XCNEW (struct private_thread_info);
+ thread_db_thread_info *priv = new thread_db_thread_info;
priv->th = *th_p;
priv->tid = ti_p->ti_tid;
if (tp == NULL || tp->state == THREAD_EXITED)
tp = add_thread_with_info (ptid, priv);
else
- tp->priv = priv;
+ tp->priv.reset (priv);
if (target_has_execution)
check_thread_signals ();
ptid = beneath->to_wait (beneath, ptid, ourstatus, options);
- if (ourstatus->kind == TARGET_WAITKIND_IGNORE)
- return ptid;
-
- if (ourstatus->kind == TARGET_WAITKIND_EXITED
- || ourstatus->kind == TARGET_WAITKIND_SIGNALLED)
- return ptid;
+ switch (ourstatus->kind)
+ {
+ case TARGET_WAITKIND_IGNORE:
+ case TARGET_WAITKIND_EXITED:
+ case TARGET_WAITKIND_THREAD_EXITED:
+ case TARGET_WAITKIND_SIGNALLED:
+ return ptid;
+ }
info = get_thread_db_info (ptid_get_pid (ptid));
ops->beneath->to_update_thread_list (ops->beneath);
}
-static char *
+static const char *
thread_db_pid_to_str (struct target_ops *ops, ptid_t ptid)
{
struct thread_info *thread_info = find_thread_ptid (ptid);
if (thread_info != NULL && thread_info->priv != NULL)
{
static char buf[64];
- thread_t tid;
+ thread_db_thread_info *priv = get_thread_db_thread_info (thread_info);
- tid = thread_info->priv->tid;
snprintf (buf, sizeof (buf), "Thread 0x%lx (LWP %ld)",
- (unsigned long) tid, ptid_get_lwp (ptid));
+ (unsigned long) priv->tid, ptid_get_lwp (ptid));
return buf;
}
/* Return a string describing the state of the thread specified by
INFO. */
-static char *
+static const char *
thread_db_extra_thread_info (struct target_ops *self,
struct thread_info *info)
{
if (info->priv == NULL)
return NULL;
- if (info->priv->dying)
+ thread_db_thread_info *priv = get_thread_db_thread_info (info);
+
+ if (priv->dying)
return "Exiting";
return NULL;
}
+/* Return pointer to the thread_info struct which corresponds to
+ THREAD_HANDLE (having length HANDLE_LEN). */
+
+static struct thread_info *
+thread_db_thread_handle_to_thread_info (struct target_ops *ops,
+ const gdb_byte *thread_handle,
+ int handle_len,
+ struct inferior *inf)
+{
+ struct thread_info *tp;
+ thread_t handle_tid;
+
+ /* Thread handle sizes must match in order to proceed. We don't use an
+ assert here because the resulting internal error will cause GDB to
+ exit. This isn't necessarily an internal error due to the possibility
+ of garbage being passed as the thread handle via the python interface. */
+ if (handle_len != sizeof (handle_tid))
+ error (_("Thread handle size mismatch: %d vs %zu (from libthread_db)"),
+ handle_len, sizeof (handle_tid));
+
+ handle_tid = * (const thread_t *) thread_handle;
+
+ ALL_NON_EXITED_THREADS (tp)
+ {
+ thread_db_thread_info *priv = get_thread_db_thread_info (tp);
+
+ if (tp->inf == inf && priv != NULL && handle_tid == priv->tid)
+ return tp;
+ }
+
+ return NULL;
+}
+
/* Get the address of the thread local variable in load module LM which
is stored at OFFSET within the thread local storage for thread PTID. */
{
td_err_e err;
psaddr_t address;
- struct thread_db_info *info;
-
- info = get_thread_db_info (ptid_get_pid (ptid));
+ thread_db_info *info = get_thread_db_info (ptid_get_pid (ptid));
+ thread_db_thread_info *priv = get_thread_db_thread_info (thread_info);
/* Finally, get the address of the variable. */
if (lm != 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 = info->td_thr_tls_get_addr_p (&thread_info->priv->th,
+ err = info->td_thr_tls_get_addr_p (&priv->th,
(psaddr_t)(uintptr_t) lm,
offset, &address);
}
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 = info->td_thr_tlsbase_p (&thread_info->priv->th,
- 1, &address);
+ err = info->td_thr_tlsbase_p (&priv->th, 1, &address);
address = (char *) address + offset;
}
/* Implement 'info auto-load libthread-db'. */
static void
-info_auto_load_libthread_db (char *args, int from_tty)
+info_auto_load_libthread_db (const char *args, int from_tty)
{
struct ui_out *uiout = current_uiout;
const char *cs = args ? args : "";
char *pids;
int i;
- cs = skip_spaces_const (cs);
+ cs = skip_spaces (cs);
if (*cs)
error (_("'info auto-load libthread-db' does not accept any parameters"));
if (i == 0 || strcmp (array[i - 1]->filename, array[i]->filename) != 0)
{
unique_filenames++;
- max_filename_len = max (max_filename_len,
- strlen (array[i]->filename));
+ max_filename_len = std::max (max_filename_len,
+ strlen (array[i]->filename));
if (i > 0)
{
pids_len -= strlen (", ");
- max_pids_len = max (max_pids_len, pids_len);
+ max_pids_len = std::max (max_pids_len, pids_len);
}
pids_len = 0;
}
if (i)
{
pids_len -= strlen (", ");
- max_pids_len = max (max_pids_len, pids_len);
+ max_pids_len = std::max (max_pids_len, pids_len);
}
/* Table header shifted right by preceding "libthread-db: " would not match
its columns. */
if (info_count > 0 && args == auto_load_info_scripts_pattern_nl)
- ui_out_text (uiout, "\n");
+ uiout->text ("\n");
- make_cleanup_ui_out_table_begin_end (uiout, 2, unique_filenames,
- "LinuxThreadDbTable");
+ {
+ ui_out_emit_table table_emitter (uiout, 2, unique_filenames,
+ "LinuxThreadDbTable");
- ui_out_table_header (uiout, max_filename_len, ui_left, "filename",
- "Filename");
- ui_out_table_header (uiout, pids_len, ui_left, "PIDs", "Pids");
- ui_out_table_body (uiout);
+ uiout->table_header (max_filename_len, ui_left, "filename", "Filename");
+ uiout->table_header (pids_len, ui_left, "PIDs", "Pids");
+ uiout->table_body ();
- pids = (char *) xmalloc (max_pids_len + 1);
- make_cleanup (xfree, pids);
+ pids = (char *) xmalloc (max_pids_len + 1);
+ make_cleanup (xfree, pids);
- /* Note I is incremented inside the cycle, not at its end. */
- for (i = 0; i < info_count;)
- {
- struct cleanup *chain = make_cleanup_ui_out_tuple_begin_end (uiout, NULL);
- char *pids_end;
-
- info = array[i];
- ui_out_field_string (uiout, "filename", info->filename);
- pids_end = pids;
+ /* Note I is incremented inside the cycle, not at its end. */
+ for (i = 0; i < info_count;)
+ {
+ ui_out_emit_tuple tuple_emitter (uiout, NULL);
+ char *pids_end;
- while (i < info_count && strcmp (info->filename, array[i]->filename) == 0)
- {
- if (pids_end != pids)
- {
- *pids_end++ = ',';
- *pids_end++ = ' ';
- }
- pids_end += xsnprintf (pids_end, &pids[max_pids_len + 1] - pids_end,
- "%u", array[i]->pid);
- gdb_assert (pids_end < &pids[max_pids_len + 1]);
+ info = array[i];
+ uiout->field_string ("filename", info->filename);
+ pids_end = pids;
- i++;
- }
- *pids_end = '\0';
+ while (i < info_count && strcmp (info->filename,
+ array[i]->filename) == 0)
+ {
+ if (pids_end != pids)
+ {
+ *pids_end++ = ',';
+ *pids_end++ = ' ';
+ }
+ pids_end += xsnprintf (pids_end,
+ &pids[max_pids_len + 1] - pids_end,
+ "%u", array[i]->pid);
+ gdb_assert (pids_end < &pids[max_pids_len + 1]);
+
+ i++;
+ }
+ *pids_end = '\0';
- ui_out_field_string (uiout, "pids", pids);
+ uiout->field_string ("pids", pids);
- ui_out_text (uiout, "\n");
- do_cleanups (chain);
- }
+ uiout->text ("\n");
+ }
+ }
do_cleanups (back_to);
if (info_count == 0)
- ui_out_message (uiout, 0, _("No auto-loaded libthread-db.\n"));
+ uiout->message (_("No auto-loaded libthread-db.\n"));
}
static void
= thread_db_get_thread_local_address;
thread_db_ops.to_extra_thread_info = thread_db_extra_thread_info;
thread_db_ops.to_get_ada_task_ptid = thread_db_get_ada_task_ptid;
+ thread_db_ops.to_thread_handle_to_thread_info = thread_db_thread_handle_to_thread_info;
thread_db_ops.to_magic = OPS_MAGIC;
complete_target_initialization (&thread_db_ops);
}
-/* Provide a prototype to silence -Wmissing-prototypes. */
-extern initialize_file_ftype _initialize_thread_db;
-
void
_initialize_thread_db (void)
{