/* libthread_db assisted debugging support, generic parts.
- Copyright (C) 1999-2019 Free Software Foundation, Inc.
+ Copyright (C) 1999-2020 Free Software Foundation, Inc.
This file is part of GDB.
#include <dlfcn.h>
#include "gdb_proc_service.h"
#include "nat/gdb_thread_db.h"
-#include "common/gdb_vecs.h"
+#include "gdbsupport/gdb_vecs.h"
#include "bfd.h"
#include "command.h"
#include "gdbcmd.h"
#include <ctype.h>
#include "nat/linux-namespaces.h"
#include <algorithm>
-#include "common/pathstuff.h"
+#include "gdbsupport/pathstuff.h"
#include "valprint.h"
+#include "cli/cli-style.h"
/* GNU/Linux libthread_db support.
static char *libthread_db_search_path;
-/* Set to non-zero if thread_db auto-loading is enabled
+/* Set to true if thread_db auto-loading is enabled
by the "set auto-load libthread-db" command. */
-static int auto_load_thread_db = 1;
+static bool auto_load_thread_db = true;
-/* Set to non-zero if load-time libthread_db tests have been enabled
- by the "maintenence set check-libthread-db" command. */
-static int check_thread_db_on_load = 0;
+/* Set to true if load-time libthread_db tests have been enabled
+ by the "maintenance set check-libthread-db" command. */
+static bool check_thread_db_on_load = false;
/* "show" command for the auto_load_thread_db configuration variable. */
}
/* Attempt to initialize dlopen()ed libthread_db, described by INFO.
- Return 1 on success.
+ Return true 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
+static bool
try_thread_db_load_1 (struct thread_db_info *info)
{
td_err_e err;
do \
{ \
if ((a) == NULL) \
- return 0; \
+ return false; \
} while (0)
CHK (TDB_VERBOSE_DLSYM (info, td_init));
{
warning (_("Cannot initialize libthread_db: %s"),
thread_db_err_str (err));
- return 0;
+ return false;
}
CHK (TDB_VERBOSE_DLSYM (info, td_ta_new));
default:
warning (_("td_ta_new failed: %s"), thread_db_err_str (err));
}
- return 0;
+ return false;
}
/* These are essential. */
if (check_thread_db_on_load)
{
if (!check_thread_db (info, libthread_db_debug))
- return 0;
+ return false;
}
if (info->td_ta_thr_iter_p == NULL)
/* Even if libthread_db initializes, if the thread list is
corrupted, we'd not manage to list any threads. Better reject this
thread_db, and fall back to at least listing LWPs. */
- return 0;
+ return false;
}
printf_unfiltered (_("[Thread debugging using libthread_db enabled]\n"));
enabled. User visible output should not depend on debug
settings. */
file = *libthread_db_search_path != '\0' ? gdb_stdout : gdb_stdlog;
- fprintf_unfiltered (file, _("Using host libthread_db library \"%s\".\n"),
- library);
+ fprintf_unfiltered (file,
+ _("Using host libthread_db library \"%ps\".\n"),
+ styled_string (file_name_style.style (), library));
}
/* The thread library was detected. Activate the thread_db target
if (thread_db_list->next == NULL)
push_target (&the_thread_db_target);
- return 1;
+ return true;
}
/* Attempt to use LIBRARY as libthread_db. LIBRARY could be absolute,
relative, or just LIBTHREAD_DB. */
-static int
-try_thread_db_load (const char *library, int check_auto_load_safe)
+static bool
+try_thread_db_load (const char *library, bool check_auto_load_safe)
{
void *handle;
struct thread_db_info *info;
if (libthread_db_debug)
fprintf_unfiltered (gdb_stdlog, _("open failed: %s.\n"),
safe_strerror (errno));
- return 0;
+ return false;
}
if (!file_is_auto_load_safe (library, _("auto-load: Loading libthread-db "
"library \"%s\" from explicit "
"directory.\n"),
library))
- return 0;
+ return false;
}
handle = dlopen (library, RTLD_NOW);
{
if (libthread_db_debug)
fprintf_unfiltered (gdb_stdlog, _("dlopen failed: %s.\n"), dlerror ());
- return 0;
+ return false;
}
if (libthread_db_debug && strchr (library, '/') == NULL)
info->filename = gdb_realpath (library).release ();
if (try_thread_db_load_1 (info))
- return 1;
+ return true;
/* This library "refused" to work on current inferior. */
delete_thread_db_info (inferior_ptid.pid ());
- return 0;
+ return false;
}
/* Subroutine of try_thread_db_load_from_pdir to simplify it.
SUBDIR may be NULL. It may also be something like "../lib64".
The result is true for success. */
-static int
+static bool
try_thread_db_load_from_pdir_1 (struct objfile *obj, const char *subdir)
{
const char *obj_name = objfile_name (obj);
if (obj_name[0] != '/')
{
warning (_("Expected absolute pathname for libpthread in the"
- " inferior, but got %s."), obj_name);
- return 0;
+ " inferior, but got %ps."),
+ styled_string (file_name_style.style (), obj_name));
+ return false;
}
std::string path = obj_name;
path = path + subdir + "/";
path += LIBTHREAD_DB_SO;
- return try_thread_db_load (path.c_str (), 1);
+ return try_thread_db_load (path.c_str (), true);
}
/* Handle $pdir in libthread-db-search-path.
SUBDIR may be NULL. It may also be something like "../lib64".
The result is true for success. */
-static int
+static bool
try_thread_db_load_from_pdir (const char *subdir)
{
if (!auto_load_thread_db)
- return 0;
+ return false;
for (objfile *obj : current_program_space->objfiles ())
if (libpthread_name_p (objfile_name (obj)))
{
if (try_thread_db_load_from_pdir_1 (obj, subdir))
- return 1;
+ return true;
/* We may have found the separate-debug-info version of
libpthread, and it may live in a directory without a matching
return try_thread_db_load_from_pdir_1 (obj->separate_debug_objfile_backlink,
subdir);
- return 0;
+ return false;
}
- return 0;
+ return false;
}
/* Handle $sdir in libthread-db-search-path.
dlopen(file_without_path) will look.
The result is true for success. */
-static int
+static bool
try_thread_db_load_from_sdir (void)
{
- return try_thread_db_load (LIBTHREAD_DB_SO, 0);
+ return try_thread_db_load (LIBTHREAD_DB_SO, false);
}
/* Try to load libthread_db from directory DIR of length DIR_LEN.
The result is true for success. */
-static int
+static bool
try_thread_db_load_from_dir (const char *dir, size_t dir_len)
{
if (!auto_load_thread_db)
- return 0;
+ return false;
std::string path = std::string (dir, dir_len) + "/" + LIBTHREAD_DB_SO;
- return try_thread_db_load (path.c_str (), 1);
+ return try_thread_db_load (path.c_str (), true);
}
/* Search libthread_db_search_path for libthread_db which "agrees"
to work on current inferior.
The result is true for success. */
-static int
+static bool
thread_db_load_search (void)
{
- int rc = 0;
+ bool rc = false;
std::vector<gdb::unique_xmalloc_ptr<char>> dir_vec
= dirnames_to_char_ptr_vec (libthread_db_search_path);
return rc;
}
-/* Return non-zero if the inferior has a libpthread. */
+/* Return true if the inferior has a libpthread. */
-static int
+static bool
has_libpthread (void)
{
for (objfile *obj : current_program_space->objfiles ())
if (libpthread_name_p (objfile_name (obj)))
- return 1;
+ return true;
- return 0;
+ return false;
}
/* Attempt to load and initialize libthread_db.
Return 1 on success. */
-static int
+static bool
thread_db_load (void)
{
struct thread_db_info *info;
info = get_thread_db_info (inferior_ptid.pid ());
if (info != NULL)
- return 1;
+ return true;
/* Don't attempt to use thread_db on executables not running
yet. */
if (!target_has_registers)
- return 0;
+ return false;
/* Don't attempt to use thread_db for remote targets. */
if (!(target_can_run () || core_bfd))
- return 0;
+ return false;
if (thread_db_load_search ())
- return 1;
+ return true;
/* We couldn't find a libthread_db.
If the inferior has a libpthread warn the user. */
{
warning (_("Unable to find libthread_db matching inferior's thread"
" library, thread debugging will not be available."));
- return 0;
+ return false;
}
/* 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;
+ return false;
}
static void
{
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))
+ /* When debugging a 32-bit target from a 64-bit host, handle_len
+ will be 4 and sizeof (handle_tid) will be 8. This requires
+ a different cast than the more straightforward case where
+ the sizes are the same.
+
+ Use "--target_board unix/-m32" from a native x86_64 linux build
+ to test the 32/64-bit case. */
+ if (handle_len == 4 && sizeof (handle_tid) == 8)
+ handle_tid = (thread_t) * (const uint32_t *) thread_handle;
+ else if (handle_len == sizeof (handle_tid))
+ handle_tid = * (const thread_t *) thread_handle;
+ else
error (_("Thread handle size mismatch: %d vs %zu (from libthread_db)"),
handle_len, sizeof (handle_tid));
- handle_tid = * (const thread_t *) thread_handle;
-
for (thread_info *tp : inf->non_exited_threads ())
{
thread_db_thread_info *priv = get_thread_db_thread_info (tp);