mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-07 07:58:54 +08:00
doc/
2009-10-08 Paul Pluzhnikov <ppluzhnikov@google.com> * gdb.texinfo (Server): Document libthread-db-search-path. gdbserver/ 2009-10-08 Paul Pluzhnikov <ppluzhnikov@google.com> * acinclude.m4: (SRV_CHECK_THREAD_DB, SRV_CHECK_TLS_GET_ADDR): Remove. * configure.ac: Adjust. * linux-low.h (struct process_info_private): Move members to struct thread_db. (thread_db_free, thread_db_handle_monitor_command): New prototype. * linux-low.c (linux_remove_process): Adjust. (linux_wait_for_event_1, linux_look_up_symbols): Likewise. * server.c (handle_query): Move code ... (handle_monitor_command): ... here. New function. * target.h (struct target_ops): New member. * thread-db.c (struct thread_db): New. (libthread_db_search_path): New variable. (thread_db_create_event, thread_db_enable_reporting) (find_one_thread, maybe_attach_thread, find_new_threads_callback) (thread_db_find_new_threads, (thread_db_get_tls_address): Adjust. (try_thread_db_load_1, dladdr_to_soname): New functions. (try_thread_db_load, thread_db_load_search): New functions. (thread_db_init): Search for libthread_db. (thread_db_free): New function. (thread_db_handle_monitor_command): Likewise. * config.in: Regenerate. * configure: Regenerate.
This commit is contained in:
@ -14903,6 +14903,13 @@ Disable or enable general debugging messages.
|
|||||||
Disable or enable specific debugging messages associated with the remote
|
Disable or enable specific debugging messages associated with the remote
|
||||||
protocol (@pxref{Remote Protocol}).
|
protocol (@pxref{Remote Protocol}).
|
||||||
|
|
||||||
|
@item monitor set libthread-db-search-path [PATH]
|
||||||
|
@cindex gdbserver, search path for @code{libthread_db}
|
||||||
|
When this command is issued, @var{path} is a colon-separated list of
|
||||||
|
directories to search for @code{libthread_db} (@pxref{Threads,,set
|
||||||
|
libthread-db-search-path}). If you omit @var{path},
|
||||||
|
@samp{libthread-db-search-path} will be reset to an empty list.
|
||||||
|
|
||||||
@item monitor exit
|
@item monitor exit
|
||||||
Tell gdbserver to exit immediately. This command should be followed by
|
Tell gdbserver to exit immediately. This command should be followed by
|
||||||
@code{disconnect} to close the debugging session. @code{gdbserver} will
|
@code{disconnect} to close the debugging session. @code{gdbserver} will
|
||||||
|
@ -1,3 +1,28 @@
|
|||||||
|
2009-10-08 Paul Pluzhnikov <ppluzhnikov@google.com>
|
||||||
|
|
||||||
|
* acinclude.m4: (SRV_CHECK_THREAD_DB, SRV_CHECK_TLS_GET_ADDR): Remove.
|
||||||
|
* configure.ac: Adjust.
|
||||||
|
* linux-low.h (struct process_info_private): Move members to struct
|
||||||
|
thread_db.
|
||||||
|
(thread_db_free, thread_db_handle_monitor_command): New prototype.
|
||||||
|
* linux-low.c (linux_remove_process): Adjust.
|
||||||
|
(linux_wait_for_event_1, linux_look_up_symbols): Likewise.
|
||||||
|
* server.c (handle_query): Move code ...
|
||||||
|
(handle_monitor_command): ... here. New function.
|
||||||
|
* target.h (struct target_ops): New member.
|
||||||
|
* thread-db.c (struct thread_db): New.
|
||||||
|
(libthread_db_search_path): New variable.
|
||||||
|
(thread_db_create_event, thread_db_enable_reporting)
|
||||||
|
(find_one_thread, maybe_attach_thread, find_new_threads_callback)
|
||||||
|
(thread_db_find_new_threads, (thread_db_get_tls_address): Adjust.
|
||||||
|
(try_thread_db_load_1, dladdr_to_soname): New functions.
|
||||||
|
(try_thread_db_load, thread_db_load_search): New functions.
|
||||||
|
(thread_db_init): Search for libthread_db.
|
||||||
|
(thread_db_free): New function.
|
||||||
|
(thread_db_handle_monitor_command): Likewise.
|
||||||
|
* config.in: Regenerate.
|
||||||
|
* configure: Regenerate.
|
||||||
|
|
||||||
2009-09-27 Ulrich Weigand <uweigand@de.ibm.com>
|
2009-09-27 Ulrich Weigand <uweigand@de.ibm.com>
|
||||||
|
|
||||||
* spu-low.c (spu_kill): Wait for inferior to terminate.
|
* spu-low.c (spu_kill): Wait for inferior to terminate.
|
||||||
|
@ -7,63 +7,3 @@ sinclude(../../config/override.m4)
|
|||||||
dnl For ACX_PKGVERSION and ACX_BUGURL.
|
dnl For ACX_PKGVERSION and ACX_BUGURL.
|
||||||
sinclude(../../config/acx.m4)
|
sinclude(../../config/acx.m4)
|
||||||
|
|
||||||
AC_DEFUN([SRV_CHECK_THREAD_DB],
|
|
||||||
[AC_CACHE_CHECK([for libthread_db],[srv_cv_thread_db],
|
|
||||||
[old_LIBS="$LIBS"
|
|
||||||
LIBS="$LIBS -lthread_db"
|
|
||||||
AC_TRY_LINK(
|
|
||||||
[void ps_pglobal_lookup() {}
|
|
||||||
void ps_pdread() {}
|
|
||||||
void ps_pdwrite() {}
|
|
||||||
void ps_lgetregs() {}
|
|
||||||
void ps_lsetregs() {}
|
|
||||||
void ps_lgetfpregs() {}
|
|
||||||
void ps_lsetfpregs() {}
|
|
||||||
void ps_get_thread_area() {}
|
|
||||||
void ps_getpid() {}],
|
|
||||||
[td_ta_new();],
|
|
||||||
[srv_cv_thread_db="-lthread_db"],
|
|
||||||
[srv_cv_thread_db=no
|
|
||||||
|
|
||||||
if test "$prefix" = "/usr" || test "$prefix" = "NONE"; then
|
|
||||||
thread_db="/lib/libthread_db.so.1"
|
|
||||||
else
|
|
||||||
thread_db='$prefix/lib/libthread_db.so.1'
|
|
||||||
fi
|
|
||||||
LIBS="$old_LIBS `eval echo "$thread_db"`"
|
|
||||||
AC_TRY_LINK(
|
|
||||||
[void ps_pglobal_lookup() {}
|
|
||||||
void ps_pdread() {}
|
|
||||||
void ps_pdwrite() {}
|
|
||||||
void ps_lgetregs() {}
|
|
||||||
void ps_lsetregs() {}
|
|
||||||
void ps_lgetfpregs() {}
|
|
||||||
void ps_lsetfpregs() {}
|
|
||||||
void ps_get_thread_area() {}
|
|
||||||
void ps_getpid() {}],
|
|
||||||
[td_ta_new();],
|
|
||||||
[srv_cv_thread_db="$thread_db"],
|
|
||||||
[srv_cv_thread_db=no])
|
|
||||||
])
|
|
||||||
LIBS="$old_LIBS"
|
|
||||||
])])
|
|
||||||
|
|
||||||
AC_DEFUN([SRV_CHECK_TLS_GET_ADDR],
|
|
||||||
[AC_CACHE_CHECK([for thread_db_tls_get_addr],[srv_cv_tls_get_addr],
|
|
||||||
[old_LIBS="$LIBS"
|
|
||||||
LIBS="$LIBS $srv_cv_thread_db"
|
|
||||||
AC_TRY_LINK(
|
|
||||||
[void ps_pglobal_lookup() {}
|
|
||||||
void ps_pdread() {}
|
|
||||||
void ps_pdwrite() {}
|
|
||||||
void ps_lgetregs() {}
|
|
||||||
void ps_lsetregs() {}
|
|
||||||
void ps_lgetfpregs() {}
|
|
||||||
void ps_lsetfpregs() {}
|
|
||||||
void ps_get_thread_area() {}
|
|
||||||
void ps_getpid() {}],
|
|
||||||
[td_thr_tls_get_addr();],
|
|
||||||
[srv_cv_tls_get_addr=yes],
|
|
||||||
[srv_cv_tls_get_addr=no])
|
|
||||||
LIBS="$old_LIBS"
|
|
||||||
])])
|
|
||||||
|
@ -130,9 +130,6 @@
|
|||||||
/* Define to 1 if you have the <sys/wait.h> header file. */
|
/* Define to 1 if you have the <sys/wait.h> header file. */
|
||||||
#undef HAVE_SYS_WAIT_H
|
#undef HAVE_SYS_WAIT_H
|
||||||
|
|
||||||
/* Define if td_thr_tls_get_addr is available. */
|
|
||||||
#undef HAVE_TD_THR_TLS_GET_ADDR
|
|
||||||
|
|
||||||
/* Define if TD_VERSION is available. */
|
/* Define if TD_VERSION is available. */
|
||||||
#undef HAVE_TD_VERSION
|
#undef HAVE_TD_VERSION
|
||||||
|
|
||||||
|
128
gdb/gdbserver/configure
vendored
128
gdb/gdbserver/configure
vendored
@ -4210,125 +4210,7 @@ srv_libs=
|
|||||||
USE_THREAD_DB=
|
USE_THREAD_DB=
|
||||||
|
|
||||||
if test "$srv_linux_thread_db" = "yes"; then
|
if test "$srv_linux_thread_db" = "yes"; then
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libthread_db" >&5
|
srv_libs="-ldl"
|
||||||
$as_echo_n "checking for libthread_db... " >&6; }
|
|
||||||
if test "${srv_cv_thread_db+set}" = set; then :
|
|
||||||
$as_echo_n "(cached) " >&6
|
|
||||||
else
|
|
||||||
old_LIBS="$LIBS"
|
|
||||||
LIBS="$LIBS -lthread_db"
|
|
||||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
|
||||||
/* end confdefs.h. */
|
|
||||||
void ps_pglobal_lookup() {}
|
|
||||||
void ps_pdread() {}
|
|
||||||
void ps_pdwrite() {}
|
|
||||||
void ps_lgetregs() {}
|
|
||||||
void ps_lsetregs() {}
|
|
||||||
void ps_lgetfpregs() {}
|
|
||||||
void ps_lsetfpregs() {}
|
|
||||||
void ps_get_thread_area() {}
|
|
||||||
void ps_getpid() {}
|
|
||||||
int
|
|
||||||
main ()
|
|
||||||
{
|
|
||||||
td_ta_new();
|
|
||||||
;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
_ACEOF
|
|
||||||
if ac_fn_c_try_link "$LINENO"; then :
|
|
||||||
srv_cv_thread_db="-lthread_db"
|
|
||||||
else
|
|
||||||
srv_cv_thread_db=no
|
|
||||||
|
|
||||||
if test "$prefix" = "/usr" || test "$prefix" = "NONE"; then
|
|
||||||
thread_db="/lib/libthread_db.so.1"
|
|
||||||
else
|
|
||||||
thread_db='$prefix/lib/libthread_db.so.1'
|
|
||||||
fi
|
|
||||||
LIBS="$old_LIBS `eval echo "$thread_db"`"
|
|
||||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
|
||||||
/* end confdefs.h. */
|
|
||||||
void ps_pglobal_lookup() {}
|
|
||||||
void ps_pdread() {}
|
|
||||||
void ps_pdwrite() {}
|
|
||||||
void ps_lgetregs() {}
|
|
||||||
void ps_lsetregs() {}
|
|
||||||
void ps_lgetfpregs() {}
|
|
||||||
void ps_lsetfpregs() {}
|
|
||||||
void ps_get_thread_area() {}
|
|
||||||
void ps_getpid() {}
|
|
||||||
int
|
|
||||||
main ()
|
|
||||||
{
|
|
||||||
td_ta_new();
|
|
||||||
;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
_ACEOF
|
|
||||||
if ac_fn_c_try_link "$LINENO"; then :
|
|
||||||
srv_cv_thread_db="$thread_db"
|
|
||||||
else
|
|
||||||
srv_cv_thread_db=no
|
|
||||||
fi
|
|
||||||
rm -f core conftest.err conftest.$ac_objext \
|
|
||||||
conftest$ac_exeext conftest.$ac_ext
|
|
||||||
|
|
||||||
fi
|
|
||||||
rm -f core conftest.err conftest.$ac_objext \
|
|
||||||
conftest$ac_exeext conftest.$ac_ext
|
|
||||||
LIBS="$old_LIBS"
|
|
||||||
|
|
||||||
fi
|
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $srv_cv_thread_db" >&5
|
|
||||||
$as_echo "$srv_cv_thread_db" >&6; }
|
|
||||||
if test "$srv_cv_thread_db" = no; then
|
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Could not find libthread_db." >&5
|
|
||||||
$as_echo "$as_me: WARNING: Could not find libthread_db." >&2;}
|
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Disabling thread support in gdbserver." >&5
|
|
||||||
$as_echo "$as_me: WARNING: Disabling thread support in gdbserver." >&2;}
|
|
||||||
srv_linux_thread_db=no
|
|
||||||
else
|
|
||||||
srv_libs="$srv_cv_thread_db"
|
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for thread_db_tls_get_addr" >&5
|
|
||||||
$as_echo_n "checking for thread_db_tls_get_addr... " >&6; }
|
|
||||||
if test "${srv_cv_tls_get_addr+set}" = set; then :
|
|
||||||
$as_echo_n "(cached) " >&6
|
|
||||||
else
|
|
||||||
old_LIBS="$LIBS"
|
|
||||||
LIBS="$LIBS $srv_cv_thread_db"
|
|
||||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
|
||||||
/* end confdefs.h. */
|
|
||||||
void ps_pglobal_lookup() {}
|
|
||||||
void ps_pdread() {}
|
|
||||||
void ps_pdwrite() {}
|
|
||||||
void ps_lgetregs() {}
|
|
||||||
void ps_lsetregs() {}
|
|
||||||
void ps_lgetfpregs() {}
|
|
||||||
void ps_lsetfpregs() {}
|
|
||||||
void ps_get_thread_area() {}
|
|
||||||
void ps_getpid() {}
|
|
||||||
int
|
|
||||||
main ()
|
|
||||||
{
|
|
||||||
td_thr_tls_get_addr();
|
|
||||||
;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
_ACEOF
|
|
||||||
if ac_fn_c_try_link "$LINENO"; then :
|
|
||||||
srv_cv_tls_get_addr=yes
|
|
||||||
else
|
|
||||||
srv_cv_tls_get_addr=no
|
|
||||||
fi
|
|
||||||
rm -f core conftest.err conftest.$ac_objext \
|
|
||||||
conftest$ac_exeext conftest.$ac_ext
|
|
||||||
LIBS="$old_LIBS"
|
|
||||||
|
|
||||||
fi
|
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $srv_cv_tls_get_addr" >&5
|
|
||||||
$as_echo "$srv_cv_tls_get_addr" >&6; }
|
|
||||||
fi
|
|
||||||
old_LDFLAGS="$LDFLAGS"
|
old_LDFLAGS="$LDFLAGS"
|
||||||
LDFLAGS="$LDFLAGS -rdynamic"
|
LDFLAGS="$LDFLAGS -rdynamic"
|
||||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||||
@ -4351,9 +4233,7 @@ rm -f core conftest.err conftest.$ac_objext \
|
|||||||
conftest$ac_exeext conftest.$ac_ext
|
conftest$ac_exeext conftest.$ac_ext
|
||||||
|
|
||||||
LDFLAGS="$old_LDFLAGS"
|
LDFLAGS="$old_LDFLAGS"
|
||||||
fi
|
|
||||||
|
|
||||||
if test "$srv_linux_thread_db" = "yes"; then
|
|
||||||
srv_thread_depfiles="thread-db.o proc-service.o"
|
srv_thread_depfiles="thread-db.o proc-service.o"
|
||||||
USE_THREAD_DB="-DUSE_THREAD_DB"
|
USE_THREAD_DB="-DUSE_THREAD_DB"
|
||||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for TD_VERSION" >&5
|
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for TD_VERSION" >&5
|
||||||
@ -4386,12 +4266,6 @@ $as_echo "$gdbsrv_cv_have_td_version" >&6; }
|
|||||||
$as_echo "#define HAVE_TD_VERSION 1" >>confdefs.h
|
$as_echo "#define HAVE_TD_VERSION 1" >>confdefs.h
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test "$srv_cv_tls_get_addr" = yes; then
|
|
||||||
|
|
||||||
$as_echo "#define HAVE_TD_THR_TLS_GET_ADDR 1" >>confdefs.h
|
|
||||||
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test "$srv_xmlfiles" != ""; then
|
if test "$srv_xmlfiles" != ""; then
|
||||||
|
@ -140,23 +140,13 @@ srv_libs=
|
|||||||
USE_THREAD_DB=
|
USE_THREAD_DB=
|
||||||
|
|
||||||
if test "$srv_linux_thread_db" = "yes"; then
|
if test "$srv_linux_thread_db" = "yes"; then
|
||||||
SRV_CHECK_THREAD_DB
|
srv_libs="-ldl"
|
||||||
if test "$srv_cv_thread_db" = no; then
|
|
||||||
AC_WARN([Could not find libthread_db.])
|
|
||||||
AC_WARN([Disabling thread support in gdbserver.])
|
|
||||||
srv_linux_thread_db=no
|
|
||||||
else
|
|
||||||
srv_libs="$srv_cv_thread_db"
|
|
||||||
SRV_CHECK_TLS_GET_ADDR
|
|
||||||
fi
|
|
||||||
old_LDFLAGS="$LDFLAGS"
|
old_LDFLAGS="$LDFLAGS"
|
||||||
LDFLAGS="$LDFLAGS -rdynamic"
|
LDFLAGS="$LDFLAGS -rdynamic"
|
||||||
AC_TRY_LINK([], [], [RDYNAMIC=-rdynamic], [RDYNAMIC=])
|
AC_TRY_LINK([], [], [RDYNAMIC=-rdynamic], [RDYNAMIC=])
|
||||||
AC_SUBST(RDYNAMIC)
|
AC_SUBST(RDYNAMIC)
|
||||||
LDFLAGS="$old_LDFLAGS"
|
LDFLAGS="$old_LDFLAGS"
|
||||||
fi
|
|
||||||
|
|
||||||
if test "$srv_linux_thread_db" = "yes"; then
|
|
||||||
srv_thread_depfiles="thread-db.o proc-service.o"
|
srv_thread_depfiles="thread-db.o proc-service.o"
|
||||||
USE_THREAD_DB="-DUSE_THREAD_DB"
|
USE_THREAD_DB="-DUSE_THREAD_DB"
|
||||||
AC_CACHE_CHECK([for TD_VERSION], gdbsrv_cv_have_td_version,
|
AC_CACHE_CHECK([for TD_VERSION], gdbsrv_cv_have_td_version,
|
||||||
@ -166,10 +156,6 @@ if test "$srv_linux_thread_db" = "yes"; then
|
|||||||
if test $gdbsrv_cv_have_td_version = yes; then
|
if test $gdbsrv_cv_have_td_version = yes; then
|
||||||
AC_DEFINE(HAVE_TD_VERSION, 1, [Define if TD_VERSION is available.])
|
AC_DEFINE(HAVE_TD_VERSION, 1, [Define if TD_VERSION is available.])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test "$srv_cv_tls_get_addr" = yes; then
|
|
||||||
AC_DEFINE(HAVE_TD_THR_TLS_GET_ADDR, 1, [Define if td_thr_tls_get_addr is available.])
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if test "$srv_xmlfiles" != ""; then
|
if test "$srv_xmlfiles" != ""; then
|
||||||
|
@ -261,8 +261,14 @@ linux_add_process (int pid, int attached)
|
|||||||
static void
|
static void
|
||||||
linux_remove_process (struct process_info *process)
|
linux_remove_process (struct process_info *process)
|
||||||
{
|
{
|
||||||
free (process->private->arch_private);
|
struct process_info_private *priv = process->private;
|
||||||
free (process->private);
|
|
||||||
|
#ifdef USE_THREAD_DB
|
||||||
|
thread_db_free (process);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
free (priv->arch_private);
|
||||||
|
free (priv);
|
||||||
remove_process (process);
|
remove_process (process);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1122,7 +1128,7 @@ linux_wait_for_event_1 (ptid_t ptid, int *wstat, int options)
|
|||||||
&& !event_child->stepping
|
&& !event_child->stepping
|
||||||
&& (
|
&& (
|
||||||
#ifdef USE_THREAD_DB
|
#ifdef USE_THREAD_DB
|
||||||
(current_process ()->private->thread_db_active
|
(current_process ()->private->thread_db != NULL
|
||||||
&& (WSTOPSIG (*wstat) == __SIGRTMIN
|
&& (WSTOPSIG (*wstat) == __SIGRTMIN
|
||||||
|| WSTOPSIG (*wstat) == __SIGRTMIN + 1))
|
|| WSTOPSIG (*wstat) == __SIGRTMIN + 1))
|
||||||
||
|
||
|
||||||
@ -2642,11 +2648,10 @@ linux_look_up_symbols (void)
|
|||||||
#ifdef USE_THREAD_DB
|
#ifdef USE_THREAD_DB
|
||||||
struct process_info *proc = current_process ();
|
struct process_info *proc = current_process ();
|
||||||
|
|
||||||
if (proc->private->thread_db_active)
|
if (proc->private->thread_db != NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
proc->private->thread_db_active
|
thread_db_init (!linux_supports_tracefork_flag);
|
||||||
= thread_db_init (!linux_supports_tracefork_flag);
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3171,7 +3176,12 @@ static struct target_ops linux_target_ops = {
|
|||||||
linux_supports_non_stop,
|
linux_supports_non_stop,
|
||||||
linux_async,
|
linux_async,
|
||||||
linux_start_non_stop,
|
linux_start_non_stop,
|
||||||
linux_supports_multi_process
|
linux_supports_multi_process,
|
||||||
|
#ifdef USE_THREAD_DB
|
||||||
|
thread_db_handle_monitor_command
|
||||||
|
#else
|
||||||
|
NULL
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -47,18 +47,12 @@ struct siginfo;
|
|||||||
|
|
||||||
struct process_info_private
|
struct process_info_private
|
||||||
{
|
{
|
||||||
/* True if this process has loaded thread_db, and it is active. */
|
|
||||||
int thread_db_active;
|
|
||||||
|
|
||||||
/* 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;
|
|
||||||
|
|
||||||
/* Arch-specific additions. */
|
/* Arch-specific additions. */
|
||||||
struct arch_process_info *arch_private;
|
struct arch_process_info *arch_private;
|
||||||
|
|
||||||
|
/* libthread_db-specific additions. Not NULL if this process has loaded
|
||||||
|
thread_db, and it is active. */
|
||||||
|
struct thread_db *thread_db;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct lwp_info;
|
struct lwp_info;
|
||||||
@ -203,9 +197,11 @@ char *linux_child_pid_to_exec_file (int pid);
|
|||||||
int elf_64_file_p (const char *file);
|
int elf_64_file_p (const char *file);
|
||||||
|
|
||||||
void linux_attach_lwp (unsigned long pid);
|
void linux_attach_lwp (unsigned long pid);
|
||||||
|
struct lwp_info *find_lwp_pid (ptid_t ptid);
|
||||||
|
|
||||||
|
/* From thread-db.c */
|
||||||
int thread_db_init (int use_events);
|
int thread_db_init (int use_events);
|
||||||
|
void thread_db_free (struct process_info *);
|
||||||
|
int thread_db_handle_monitor_command (char *);
|
||||||
int thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset,
|
int thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset,
|
||||||
CORE_ADDR load_module, CORE_ADDR *address);
|
CORE_ADDR load_module, CORE_ADDR *address);
|
||||||
|
|
||||||
struct lwp_info *find_lwp_pid (ptid_t ptid);
|
|
||||||
|
@ -660,6 +660,53 @@ handle_search_memory (char *own_buf, int packet_len)
|
|||||||
return; \
|
return; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Handle monitor commands not handled by target-specific handlers. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_monitor_command (char *mon)
|
||||||
|
{
|
||||||
|
if (strcmp (mon, "set debug 1") == 0)
|
||||||
|
{
|
||||||
|
debug_threads = 1;
|
||||||
|
monitor_output ("Debug output enabled.\n");
|
||||||
|
}
|
||||||
|
else if (strcmp (mon, "set debug 0") == 0)
|
||||||
|
{
|
||||||
|
debug_threads = 0;
|
||||||
|
monitor_output ("Debug output disabled.\n");
|
||||||
|
}
|
||||||
|
else if (strcmp (mon, "set debug-hw-points 1") == 0)
|
||||||
|
{
|
||||||
|
debug_hw_points = 1;
|
||||||
|
monitor_output ("H/W point debugging output enabled.\n");
|
||||||
|
}
|
||||||
|
else if (strcmp (mon, "set debug-hw-points 0") == 0)
|
||||||
|
{
|
||||||
|
debug_hw_points = 0;
|
||||||
|
monitor_output ("H/W point debugging output disabled.\n");
|
||||||
|
}
|
||||||
|
else if (strcmp (mon, "set remote-debug 1") == 0)
|
||||||
|
{
|
||||||
|
remote_debug = 1;
|
||||||
|
monitor_output ("Protocol debug output enabled.\n");
|
||||||
|
}
|
||||||
|
else if (strcmp (mon, "set remote-debug 0") == 0)
|
||||||
|
{
|
||||||
|
remote_debug = 0;
|
||||||
|
monitor_output ("Protocol debug output disabled.\n");
|
||||||
|
}
|
||||||
|
else if (strcmp (mon, "help") == 0)
|
||||||
|
monitor_show_help ();
|
||||||
|
else if (strcmp (mon, "exit") == 0)
|
||||||
|
exit_requested = 1;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
monitor_output ("Unknown monitor command.\n\n");
|
||||||
|
monitor_show_help ();
|
||||||
|
write_enn (own_buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Handle all of the extended 'q' packets. */
|
/* Handle all of the extended 'q' packets. */
|
||||||
void
|
void
|
||||||
handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
|
handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
|
||||||
@ -1211,46 +1258,10 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
|
|||||||
|
|
||||||
write_ok (own_buf);
|
write_ok (own_buf);
|
||||||
|
|
||||||
if (strcmp (mon, "set debug 1") == 0)
|
if (the_target->handle_monitor_command == NULL
|
||||||
{
|
|| (*the_target->handle_monitor_command) (mon) == 0)
|
||||||
debug_threads = 1;
|
/* Default processing. */
|
||||||
monitor_output ("Debug output enabled.\n");
|
handle_monitor_command (mon);
|
||||||
}
|
|
||||||
else if (strcmp (mon, "set debug 0") == 0)
|
|
||||||
{
|
|
||||||
debug_threads = 0;
|
|
||||||
monitor_output ("Debug output disabled.\n");
|
|
||||||
}
|
|
||||||
else if (strcmp (mon, "set debug-hw-points 1") == 0)
|
|
||||||
{
|
|
||||||
debug_hw_points = 1;
|
|
||||||
monitor_output ("H/W point debugging output enabled.\n");
|
|
||||||
}
|
|
||||||
else if (strcmp (mon, "set debug-hw-points 0") == 0)
|
|
||||||
{
|
|
||||||
debug_hw_points = 0;
|
|
||||||
monitor_output ("H/W point debugging output disabled.\n");
|
|
||||||
}
|
|
||||||
else if (strcmp (mon, "set remote-debug 1") == 0)
|
|
||||||
{
|
|
||||||
remote_debug = 1;
|
|
||||||
monitor_output ("Protocol debug output enabled.\n");
|
|
||||||
}
|
|
||||||
else if (strcmp (mon, "set remote-debug 0") == 0)
|
|
||||||
{
|
|
||||||
remote_debug = 0;
|
|
||||||
monitor_output ("Protocol debug output disabled.\n");
|
|
||||||
}
|
|
||||||
else if (strcmp (mon, "help") == 0)
|
|
||||||
monitor_show_help ();
|
|
||||||
else if (strcmp (mon, "exit") == 0)
|
|
||||||
exit_requested = 1;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
monitor_output ("Unknown monitor command.\n\n");
|
|
||||||
monitor_show_help ();
|
|
||||||
write_enn (own_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
free (mon);
|
free (mon);
|
||||||
return;
|
return;
|
||||||
|
@ -279,6 +279,10 @@ struct target_ops
|
|||||||
|
|
||||||
/* Returns true if the target supports multi-process debugging. */
|
/* Returns true if the target supports multi-process debugging. */
|
||||||
int (*supports_multi_process) (void);
|
int (*supports_multi_process) (void);
|
||||||
|
|
||||||
|
/* If not NULL, target-specific routine to process monitor command.
|
||||||
|
Returns 1 if handled, or 0 to perform default processing. */
|
||||||
|
int (*handle_monitor_command) (char *);
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct target_ops *the_target;
|
extern struct target_ops *the_target;
|
||||||
|
@ -27,13 +27,51 @@ extern int debug_threads;
|
|||||||
|
|
||||||
static int thread_db_use_events;
|
static int thread_db_use_events;
|
||||||
|
|
||||||
#ifdef HAVE_THREAD_DB_H
|
|
||||||
#include <thread_db.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "gdb_proc_service.h"
|
#include "gdb_proc_service.h"
|
||||||
|
#include "../gdb_thread_db.h"
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
struct thread_db
|
||||||
|
{
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
/* Handle of the libthread_db from dlopen. */
|
||||||
|
void *handle;
|
||||||
|
|
||||||
|
/* 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,
|
||||||
|
void *map_address,
|
||||||
|
size_t offset, void **address);
|
||||||
|
const char ** (*td_symbol_list_p) (void);
|
||||||
|
};
|
||||||
|
|
||||||
|
static char *libthread_db_search_path;
|
||||||
|
|
||||||
static int find_one_thread (ptid_t);
|
static int find_one_thread (ptid_t);
|
||||||
static int find_new_threads_callback (const td_thrhandle_t *th_p, void *data);
|
static int find_new_threads_callback (const td_thrhandle_t *th_p, void *data);
|
||||||
@ -130,7 +168,10 @@ thread_db_create_event (CORE_ADDR where)
|
|||||||
td_event_msg_t msg;
|
td_event_msg_t msg;
|
||||||
td_err_e err;
|
td_err_e err;
|
||||||
struct lwp_info *lwp;
|
struct lwp_info *lwp;
|
||||||
struct process_info_private *proc = current_process()->private;
|
struct thread_db *thread_db = current_process ()->private->thread_db;
|
||||||
|
|
||||||
|
if (thread_db->td_ta_event_getmsg_p == NULL)
|
||||||
|
fatal ("unexpected thread_db->td_ta_event_getmsg_p == NULL");
|
||||||
|
|
||||||
if (debug_threads)
|
if (debug_threads)
|
||||||
fprintf (stderr, "Thread creation event.\n");
|
fprintf (stderr, "Thread creation event.\n");
|
||||||
@ -139,7 +180,7 @@ thread_db_create_event (CORE_ADDR where)
|
|||||||
In the LinuxThreads implementation, this is safe,
|
In the LinuxThreads implementation, this is safe,
|
||||||
because all events come from the manager thread
|
because all events come from the manager thread
|
||||||
(except for its own creation, of course). */
|
(except for its own creation, of course). */
|
||||||
err = td_ta_event_getmsg (proc->thread_agent, &msg);
|
err = thread_db->td_ta_event_getmsg_p (thread_db->thread_agent, &msg);
|
||||||
if (err != TD_OK)
|
if (err != TD_OK)
|
||||||
fprintf (stderr, "thread getmsg err: %s\n",
|
fprintf (stderr, "thread getmsg err: %s\n",
|
||||||
thread_db_err_str (err));
|
thread_db_err_str (err));
|
||||||
@ -158,36 +199,25 @@ thread_db_create_event (CORE_ADDR where)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
static int
|
|
||||||
thread_db_death_event (CORE_ADDR where)
|
|
||||||
{
|
|
||||||
if (debug_threads)
|
|
||||||
fprintf (stderr, "Thread death event.\n");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
thread_db_enable_reporting ()
|
thread_db_enable_reporting ()
|
||||||
{
|
{
|
||||||
td_thr_events_t events;
|
td_thr_events_t events;
|
||||||
td_notify_t notify;
|
td_notify_t notify;
|
||||||
td_err_e err;
|
td_err_e err;
|
||||||
struct process_info_private *proc = current_process()->private;
|
struct thread_db *thread_db = current_process ()->private->thread_db;
|
||||||
|
|
||||||
|
if (thread_db->td_ta_set_event_p == NULL
|
||||||
|
|| thread_db->td_ta_event_addr_p == NULL
|
||||||
|
|| thread_db->td_ta_event_getmsg_p == NULL)
|
||||||
|
/* This libthread_db is missing required support. */
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* Set the process wide mask saying which events we're interested in. */
|
/* Set the process wide mask saying which events we're interested in. */
|
||||||
td_event_emptyset (&events);
|
td_event_emptyset (&events);
|
||||||
td_event_addset (&events, TD_CREATE);
|
td_event_addset (&events, TD_CREATE);
|
||||||
|
|
||||||
#if 0
|
err = thread_db->td_ta_set_event_p (thread_db->thread_agent, &events);
|
||||||
/* This is reported to be broken in glibc 2.1.3. A different approach
|
|
||||||
will be necessary to support that. */
|
|
||||||
td_event_addset (&events, TD_DEATH);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
err = td_ta_set_event (proc->thread_agent, &events);
|
|
||||||
if (err != TD_OK)
|
if (err != TD_OK)
|
||||||
{
|
{
|
||||||
warning ("Unable to set global thread event mask: %s",
|
warning ("Unable to set global thread event mask: %s",
|
||||||
@ -196,7 +226,8 @@ thread_db_enable_reporting ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Get address for thread creation breakpoint. */
|
/* Get address for thread creation breakpoint. */
|
||||||
err = td_ta_event_addr (proc->thread_agent, TD_CREATE, ¬ify);
|
err = thread_db->td_ta_event_addr_p (thread_db->thread_agent, TD_CREATE,
|
||||||
|
¬ify);
|
||||||
if (err != TD_OK)
|
if (err != TD_OK)
|
||||||
{
|
{
|
||||||
warning ("Unable to get location for thread creation breakpoint: %s",
|
warning ("Unable to get location for thread creation breakpoint: %s",
|
||||||
@ -206,22 +237,6 @@ thread_db_enable_reporting ()
|
|||||||
set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
|
set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
|
||||||
thread_db_create_event);
|
thread_db_create_event);
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* Don't concern ourselves with reported thread deaths, only
|
|
||||||
with actual thread deaths (via wait). */
|
|
||||||
|
|
||||||
/* Get address for thread death breakpoint. */
|
|
||||||
err = td_ta_event_addr (proc->thread_agent, TD_DEATH, ¬ify);
|
|
||||||
if (err != TD_OK)
|
|
||||||
{
|
|
||||||
warning ("Unable to get location for thread death breakpoint: %s",
|
|
||||||
thread_db_err_str (err));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
|
|
||||||
thread_db_death_event);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -233,7 +248,7 @@ find_one_thread (ptid_t ptid)
|
|||||||
td_err_e err;
|
td_err_e err;
|
||||||
struct thread_info *inferior;
|
struct thread_info *inferior;
|
||||||
struct lwp_info *lwp;
|
struct lwp_info *lwp;
|
||||||
struct process_info_private *proc;
|
struct thread_db *thread_db = current_process ()->private->thread_db;
|
||||||
int lwpid = ptid_get_lwp (ptid);
|
int lwpid = ptid_get_lwp (ptid);
|
||||||
|
|
||||||
inferior = (struct thread_info *) find_inferior_id (&all_threads, ptid);
|
inferior = (struct thread_info *) find_inferior_id (&all_threads, ptid);
|
||||||
@ -242,13 +257,12 @@ find_one_thread (ptid_t ptid)
|
|||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
/* Get information about this thread. */
|
/* Get information about this thread. */
|
||||||
proc = get_thread_process (inferior)->private;
|
err = thread_db->td_ta_map_lwp2thr_p (thread_db->thread_agent, lwpid, &th);
|
||||||
err = td_ta_map_lwp2thr (proc->thread_agent, lwpid, &th);
|
|
||||||
if (err != TD_OK)
|
if (err != TD_OK)
|
||||||
error ("Cannot get thread handle for LWP %d: %s",
|
error ("Cannot get thread handle for LWP %d: %s",
|
||||||
lwpid, thread_db_err_str (err));
|
lwpid, thread_db_err_str (err));
|
||||||
|
|
||||||
err = td_thr_get_info (&th, &ti);
|
err = thread_db->td_thr_get_info_p (&th, &ti);
|
||||||
if (err != TD_OK)
|
if (err != TD_OK)
|
||||||
error ("Cannot get thread info for LWP %d: %s",
|
error ("Cannot get thread info for LWP %d: %s",
|
||||||
lwpid, thread_db_err_str (err));
|
lwpid, thread_db_err_str (err));
|
||||||
@ -266,7 +280,7 @@ find_one_thread (ptid_t ptid)
|
|||||||
|
|
||||||
if (thread_db_use_events)
|
if (thread_db_use_events)
|
||||||
{
|
{
|
||||||
err = td_thr_event_enable (&th, 1);
|
err = thread_db->td_thr_event_enable_p (&th, 1);
|
||||||
if (err != TD_OK)
|
if (err != TD_OK)
|
||||||
error ("Cannot enable thread event reporting for %d: %s",
|
error ("Cannot enable thread event reporting for %d: %s",
|
||||||
ti.ti_lid, thread_db_err_str (err));
|
ti.ti_lid, thread_db_err_str (err));
|
||||||
@ -310,7 +324,8 @@ maybe_attach_thread (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p)
|
|||||||
|
|
||||||
if (thread_db_use_events)
|
if (thread_db_use_events)
|
||||||
{
|
{
|
||||||
err = td_thr_event_enable (th_p, 1);
|
struct thread_db *thread_db = current_process ()->private->thread_db;
|
||||||
|
err = thread_db->td_thr_event_enable_p (th_p, 1);
|
||||||
if (err != TD_OK)
|
if (err != TD_OK)
|
||||||
error ("Cannot enable thread event reporting for %d: %s",
|
error ("Cannot enable thread event reporting for %d: %s",
|
||||||
ti_p->ti_lid, thread_db_err_str (err));
|
ti_p->ti_lid, thread_db_err_str (err));
|
||||||
@ -322,8 +337,9 @@ find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
|
|||||||
{
|
{
|
||||||
td_thrinfo_t ti;
|
td_thrinfo_t ti;
|
||||||
td_err_e err;
|
td_err_e err;
|
||||||
|
struct thread_db *thread_db = current_process ()->private->thread_db;
|
||||||
|
|
||||||
err = td_thr_get_info (th_p, &ti);
|
err = thread_db->td_thr_get_info_p (th_p, &ti);
|
||||||
if (err != TD_OK)
|
if (err != TD_OK)
|
||||||
error ("Cannot get thread info: %s", thread_db_err_str (err));
|
error ("Cannot get thread info: %s", thread_db_err_str (err));
|
||||||
|
|
||||||
@ -341,7 +357,7 @@ thread_db_find_new_threads (void)
|
|||||||
{
|
{
|
||||||
td_err_e err;
|
td_err_e err;
|
||||||
ptid_t ptid = ((struct inferior_list_entry *) current_inferior)->id;
|
ptid_t ptid = ((struct inferior_list_entry *) current_inferior)->id;
|
||||||
struct process_info_private *proc = current_process()->private;
|
struct thread_db *thread_db = current_process ()->private->thread_db;
|
||||||
|
|
||||||
/* This function is only called when we first initialize thread_db.
|
/* This function is only called when we first initialize thread_db.
|
||||||
First locate the initial thread. If it is not ready for
|
First locate the initial thread. If it is not ready for
|
||||||
@ -350,10 +366,10 @@ thread_db_find_new_threads (void)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
/* Iterate over all user-space threads to discover new threads. */
|
/* Iterate over all user-space threads to discover new threads. */
|
||||||
err = td_ta_thr_iter (proc->thread_agent,
|
err = thread_db->td_ta_thr_iter_p (thread_db->thread_agent,
|
||||||
find_new_threads_callback, NULL,
|
find_new_threads_callback, NULL,
|
||||||
TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
|
TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
|
||||||
TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
|
TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
|
||||||
if (err != TD_OK)
|
if (err != TD_OK)
|
||||||
error ("Cannot find new threads: %s", thread_db_err_str (err));
|
error ("Cannot find new threads: %s", thread_db_err_str (err));
|
||||||
}
|
}
|
||||||
@ -366,10 +382,11 @@ thread_db_find_new_threads (void)
|
|||||||
static void
|
static void
|
||||||
thread_db_look_up_symbols (void)
|
thread_db_look_up_symbols (void)
|
||||||
{
|
{
|
||||||
const char **sym_list = td_symbol_list ();
|
struct thread_db *thread_db = current_process ()->private->thread_db;
|
||||||
|
const char **sym_list;
|
||||||
CORE_ADDR unused;
|
CORE_ADDR unused;
|
||||||
|
|
||||||
for (sym_list = td_symbol_list (); *sym_list; sym_list++)
|
for (sym_list = thread_db->td_symbol_list_p (); *sym_list; sym_list++)
|
||||||
look_up_one_symbol (*sym_list, &unused);
|
look_up_one_symbol (*sym_list, &unused);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -377,16 +394,23 @@ int
|
|||||||
thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset,
|
thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset,
|
||||||
CORE_ADDR load_module, CORE_ADDR *address)
|
CORE_ADDR load_module, CORE_ADDR *address)
|
||||||
{
|
{
|
||||||
#if HAVE_TD_THR_TLS_GET_ADDR
|
|
||||||
psaddr_t addr;
|
psaddr_t addr;
|
||||||
td_err_e err;
|
td_err_e err;
|
||||||
struct lwp_info *lwp;
|
struct lwp_info *lwp;
|
||||||
struct thread_info *saved_inferior;
|
struct thread_info *saved_inferior;
|
||||||
|
struct process_info *proc;
|
||||||
|
struct thread_db *thread_db;
|
||||||
|
|
||||||
|
proc = get_thread_process (thread);
|
||||||
|
thread_db = proc->private->thread_db;
|
||||||
|
|
||||||
/* If the thread layer is not (yet) initialized, fail. */
|
/* If the thread layer is not (yet) initialized, fail. */
|
||||||
if (!get_thread_process (thread)->all_symbols_looked_up)
|
if (!proc->all_symbols_looked_up)
|
||||||
return TD_ERR;
|
return TD_ERR;
|
||||||
|
|
||||||
|
if (thread_db->td_thr_tls_get_addr_p == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
lwp = get_thread_lwp (thread);
|
lwp = get_thread_lwp (thread);
|
||||||
if (!lwp->thread_known)
|
if (!lwp->thread_known)
|
||||||
find_one_thread (lwp->head.id);
|
find_one_thread (lwp->head.id);
|
||||||
@ -398,8 +422,9 @@ thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset,
|
|||||||
/* Note the cast through uintptr_t: this interface only works if
|
/* Note the cast through uintptr_t: this interface only works if
|
||||||
a target address fits in a psaddr_t, which is a host pointer.
|
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. */
|
So a 32-bit debugger can not access 64-bit TLS through this. */
|
||||||
err = td_thr_tls_get_addr (&lwp->th, (psaddr_t) (uintptr_t) load_module,
|
err = thread_db->td_thr_tls_get_addr_p (&lwp->th,
|
||||||
offset, &addr);
|
(psaddr_t) (uintptr_t) load_module,
|
||||||
|
offset, &addr);
|
||||||
current_inferior = saved_inferior;
|
current_inferior = saved_inferior;
|
||||||
if (err == TD_OK)
|
if (err == TD_OK)
|
||||||
{
|
{
|
||||||
@ -408,17 +433,190 @@ thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
return err;
|
return err;
|
||||||
#else
|
}
|
||||||
return -1;
|
|
||||||
#endif
|
static int
|
||||||
|
try_thread_db_load_1 (void *handle)
|
||||||
|
{
|
||||||
|
td_err_e err;
|
||||||
|
struct thread_db tdb;
|
||||||
|
struct process_info *proc = current_process ();
|
||||||
|
|
||||||
|
if (proc->private->thread_db != NULL)
|
||||||
|
fatal ("unexpected: proc->private->thread_db != NULL");
|
||||||
|
|
||||||
|
tdb.handle = handle;
|
||||||
|
|
||||||
|
/* Initialize pointers to the dynamic library functions we will use.
|
||||||
|
Essential functions first. */
|
||||||
|
|
||||||
|
#define CHK(required, a) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if ((a) == NULL) \
|
||||||
|
{ \
|
||||||
|
if (debug_threads) \
|
||||||
|
fprintf (stderr, "dlsym: %s\n", dlerror ()); \
|
||||||
|
if (required) \
|
||||||
|
return 0; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
while (0)
|
||||||
|
|
||||||
|
CHK (1, tdb.td_ta_new_p = dlsym (handle, "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));
|
||||||
|
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"));
|
||||||
|
|
||||||
|
/* 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"));
|
||||||
|
|
||||||
|
/* 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"));
|
||||||
|
|
||||||
|
#undef CHK
|
||||||
|
|
||||||
|
proc->private->thread_db = xmalloc (sizeof (tdb));
|
||||||
|
memcpy (proc->private->thread_db, &tdb, sizeof (tdb));
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lookup a library in which given symbol resides.
|
||||||
|
Note: this is looking in the GDBSERVER process, not in the inferior.
|
||||||
|
Returns library name, or NULL. */
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
dladdr_to_soname (const void *addr)
|
||||||
|
{
|
||||||
|
Dl_info info;
|
||||||
|
|
||||||
|
if (dladdr (addr, &info) != 0)
|
||||||
|
return info.dli_fname;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
try_thread_db_load (const char *library)
|
||||||
|
{
|
||||||
|
void *handle;
|
||||||
|
|
||||||
|
if (debug_threads)
|
||||||
|
fprintf (stderr, "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 ());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debug_threads && strchr (library, '/') == NULL)
|
||||||
|
{
|
||||||
|
void *td_init;
|
||||||
|
|
||||||
|
td_init = dlsym (handle, "td_init");
|
||||||
|
if (td_init != NULL)
|
||||||
|
{
|
||||||
|
const char *const libpath = dladdr_to_soname (td_init);
|
||||||
|
|
||||||
|
if (libpath != NULL)
|
||||||
|
fprintf (stderr, "Host %s resolved to: %s.\n",
|
||||||
|
library, libpath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (try_thread_db_load_1 (handle))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
/* This library "refused" to work on current inferior. */
|
||||||
|
dlclose (handle);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
thread_db_load_search (void)
|
||||||
|
{
|
||||||
|
char path[PATH_MAX];
|
||||||
|
const char *search_path;
|
||||||
|
int 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)
|
||||||
|
{
|
||||||
|
const char *end = strchr (search_path, ':');
|
||||||
|
if (end)
|
||||||
|
{
|
||||||
|
size_t len = end - search_path;
|
||||||
|
if (len + 1 + strlen (LIBTHREAD_DB_SO) + 1 > sizeof (path))
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
warning ("libthread_db_search_path component too long,"
|
||||||
|
" ignored: %s.", search_path);
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (debug_threads)
|
||||||
|
fprintf (stderr, "thread_db_load_search returning %d\n", rc);
|
||||||
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
thread_db_init (int use_events)
|
thread_db_init (int use_events)
|
||||||
{
|
{
|
||||||
int err;
|
|
||||||
struct process_info *proc = current_process ();
|
struct process_info *proc = current_process ();
|
||||||
struct process_info_private *priv = proc->private;
|
|
||||||
|
|
||||||
/* FIXME drow/2004-10-16: This is the "overall process ID", which
|
/* FIXME drow/2004-10-16: This is the "overall process ID", which
|
||||||
GNU/Linux calls tgid, "thread group ID". When we support
|
GNU/Linux calls tgid, "thread group ID". When we support
|
||||||
@ -433,27 +631,68 @@ thread_db_init (int use_events)
|
|||||||
|
|
||||||
thread_db_use_events = use_events;
|
thread_db_use_events = use_events;
|
||||||
|
|
||||||
err = td_ta_new (&priv->proc_handle, &priv->thread_agent);
|
if (thread_db_load_search ())
|
||||||
switch (err)
|
|
||||||
{
|
{
|
||||||
case TD_NOLIBTHREAD:
|
|
||||||
/* No thread library was detected. */
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
case TD_OK:
|
|
||||||
/* The thread library was detected. */
|
|
||||||
|
|
||||||
if (use_events && thread_db_enable_reporting () == 0)
|
if (use_events && thread_db_enable_reporting () == 0)
|
||||||
return 0;
|
{
|
||||||
|
/* Keep trying; maybe event reporting will work later. */
|
||||||
|
thread_db_free (proc);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
thread_db_find_new_threads ();
|
thread_db_find_new_threads ();
|
||||||
thread_db_look_up_symbols ();
|
thread_db_look_up_symbols ();
|
||||||
proc->all_symbols_looked_up = 1;
|
proc->all_symbols_looked_up = 1;
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
default:
|
|
||||||
warning ("error initializing thread_db library: %s",
|
|
||||||
thread_db_err_str (err));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Disconnect from libthread_db and free resources. */
|
||||||
|
|
||||||
|
void
|
||||||
|
thread_db_free (struct process_info *proc)
|
||||||
|
{
|
||||||
|
struct thread_db *thread_db = proc->private->thread_db;
|
||||||
|
if (thread_db)
|
||||||
|
{
|
||||||
|
td_err_e (*td_ta_delete_p) (td_thragent_t *);
|
||||||
|
|
||||||
|
td_ta_delete_p = dlsym (thread_db->handle, "td_ta_delete");
|
||||||
|
if (td_ta_delete_p != NULL)
|
||||||
|
(*td_ta_delete_p) (thread_db->thread_agent);
|
||||||
|
|
||||||
|
dlclose (thread_db->handle);
|
||||||
|
free (thread_db);
|
||||||
|
proc->private->thread_db = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handle "set libthread-db-search-path" monitor command and return 1.
|
||||||
|
For any other command, return 0. */
|
||||||
|
|
||||||
|
int
|
||||||
|
thread_db_handle_monitor_command (char *mon)
|
||||||
|
{
|
||||||
|
if (strncmp (mon, "set libthread-db-search-path ", 29) == 0)
|
||||||
|
{
|
||||||
|
const char *cp = mon + 29;
|
||||||
|
|
||||||
|
if (libthread_db_search_path != NULL)
|
||||||
|
free (libthread_db_search_path);
|
||||||
|
|
||||||
|
/* Skip leading space (if any). */
|
||||||
|
while (isspace (*cp))
|
||||||
|
++cp;
|
||||||
|
|
||||||
|
libthread_db_search_path = xstrdup (cp);
|
||||||
|
|
||||||
|
monitor_output ("libthread-db-search-path set to `");
|
||||||
|
monitor_output (libthread_db_search_path);
|
||||||
|
monitor_output ("'\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tell server.c to perform default processing. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user