2002-06-11 Daniel Jacobowitz <drow@mvista.com>

* gdbserver/thread-db.c: New file.
	* gdbserver/proc-service.c: New file.
	* gdbserver/acinclude.m4: New file.
	* gdbserver/Makefile.in: Add GDBSERVER_LIBS, gdb_proc_service_h,
	proc-service.o, and thread-db.o.
	(linux-low.o): Add USE_THREAD_DB.
	* gdbserver/acconfig.h: Add HAVE_PRGREGSET_T, HAVE_PRFPREGSET_T,
	HAVE_LWPID_T, HAVE_PSADDR_T, and PRFPREGSET_T_BROKEN.
	* gdbserver/aclocal.m4: Regenerated.
	* gdbserver/config.in: Regenerated.
	* gdbserver/configure: Regenerated.
	* gdbserver/configure.in: Check for proc_service.h, sys/procfs.h,
	thread_db.h, and linux/elf.h headrs.
	Check for lwpid_t, psaddr_t, prgregset_t, prfpregset_t, and
	PRFPREGSET_T_BROKEN.  Introduce srv_thread_depfiles and USE_THREAD_DB.
	Check for -lthread_db and thread support.
	* gdbserver/configure.srv: Enable thread_db support for ARM, i386, MIPS,
	PowerPC, and SuperH.
	* gdbserver/i387-fp.c: Constify arguments.
	* gdbserver/i387-fp.h: Likewise.
	* gdbserver/inferiors.c: (struct thread_info): Renamed from
	`struct inferior_info'.  Remove PID member.  Use generic inferior
	list header.  All uses updated.
	(inferiors, signal_pid): Removed.
	(all_threads): New variable.
	(get_thread): Define.
	(add_inferior_to_list): New function.
	(for_each_inferior): New function.
	(change_inferior_id): New function.
	(add_inferior): Removed.
	(remove_inferior): New function.
	(add_thread): New function.
	(free_one_thread): New function.
	(remove_thread): New function.
	(clear_inferiors): Use for_each_inferior and free_one_thread.
	(find_inferior): New function.
	(find_inferior_id): New function.
	(inferior_target_data): Update argument type.
	(set_inferior_target_data): Likewise.
	(inferior_regcache_data): Likewise.
	(set_inferior_regcache_data): Likewise.
	* gdbserver/linux-low.c (linux_bp_reinsert): Remove.
	(all_processes, stopping_threads, using_thrads)
	(struct pending_signals, debug_threads, pid_of): New.
	(inferior_pid): Replace with macro.
	(struct inferior_linux_data): Remove.
	(get_stop_pc, add_process): New functions.
	(linux_create_inferior): Restore SIGRTMIN+1 before calling exec.
	Use add_process and add_thread.
	(linux_attach_lwp): New function, based on old linux_attach.  Use
	add_process and add_thread.  Set stop_expected for new threads.
	(linux_attach): New function.
	(linux_kill_one_process): New function.
	(linux_kill): Kill all LWPs.
	(linux_thread_alive): Use find_inferior_id.
	(check_removed_breakpoints, status_pending_p): New functions.
	(linux_wait_for_process): Renamed from linux_wait_for_one_inferior.
	Update.  Use WNOHANG.  Wait for cloned processes also.  Update process
	struct for the found process.
	(linux_wait_for_event): New function.
	(linux_wait): Use it.  Support LWPs.
	(send_sigstop, wait_for_sigstop, stop_all_processes)
	(linux_resume_one_process, linux_continue_one_process): New functions.
	(linux_resume): Support LWPs.
	(REGISTER_RAW_SIZE): Remove.
	(fetch_register): Use register_size instead.  Call supply_register.
	(usr_store_inferior_registers): Likewise.  Call collect_register.
	Fix recursive case.
	(regsets_fetch_inferior_registers): Improve error message.
	(regsets_store_inferior_registers): Add debugging.
	(linux_look_up_symbols): Call thread_db_init if USE_THREAD_DB.
	(unstopped_p, linux_signal_pid): New functions.
	(linux_target_ops): Add linux_signal_pid.
	(linux_init_signals): New function.
	(initialize_low): Call it.  Initialize using_threads.
	* gdbserver/regcache.c (inferior_regcache_data): Add valid
	flag.
	(get_regcache): Fetch registers lazily.  Add fetch argument
	and update all callers.
	(regcache_invalidate_one, regcache_invalidate): New
	functions.
	(new_register_cache): Renamed from create_register_cache.
	Return the new regcache.
	(free_register_cache): Change argument to a void *.
	(registers_to_string, registers_from_string): Call get_regcache
	with fetch flag set.
	(register_data): Make static.  Pass fetch flag to get_regcache.
	(supply_register): Call get_regcache with fetch flag clear.
	(collect_register): Call get_regcache with fetch flag set.
	(collect_register_as_string): New function.
	* gdbserver/regcache.h: Update.
	* gdbserver/remote-utils.c (putpkt): Flush after debug output and use
	stderr.
	Handle input interrupts while waiting for an ACK.
	(input_interrupt): Use signal_pid method.
	(getpkt): Flush after debug output and use stderr.
	(outreg): Use collect_register_as_string.
	(new_thread_notify, dead_thread_notify): New functions.
	(prepare_resume_reply): Check using_threads.  Set thread_from_wait
	and general_thread.
	(look_up_one_symbol): Flush after debug output.
	* gdbserver/server.c (step_thread, server_waiting): New variables.
	(start_inferior): Don't use signal_pid.  Update call to mywait.
	(attach_inferior): Update call to mywait.
	(handle_query): Handle qfThreadInfo and qsThreadInfo.
	(main): Don't fetch/store registers explicitly.  Use
	set_desired_inferior.  Support proposed ``Hs'' packet.  Update
	calls to mywait.
	* gdbserver/server.h: Update.
	(struct inferior_list, struct_inferior_list_entry): New.
	* gdbserver/target.c (set_desired_inferior): New.
	(write_inferior_memory): Constify.
	(mywait): New function.
	* gdbserver/target.h: Update.
	(struct target_ops): New signal_pid method.
	(mywait): Removed macro, added prototype.

	* gdbserver/linux-low.h (regset_func): Removed.
	(regset_fill_func, regset_store_func): New.
	(enum regset_type): New.
	(struct regset_info): Add type field.  Use new operation types.
	(struct linux_target_ops): stop_pc renamed to get_pc.
	Add decr_pc_after_break and breakpoint_at.
	(get_process, get_thread_proess, get_process_thread)
	(strut process_info, all_processes, linux_attach_lwp)
	(thread_db_init): New.

	* gdbserver/linux-arm-low.c (arm_get_pc, arm_set_pc,
	arm_breakpoint, arm_breakpoint_len, arm_breakpoint_at): New.
	(the_low_target): Add new members.
	* gdbserver/linux-i386-low.c (i386_store_gregset, i386_store_fpregset)
	(i386_store_fpxregset): Constify.
	(target_regsets): Add new kind identifier.
	(i386_get_pc): Renamed from i386_stop_pc.  Simplify.
	(i386_set_pc): Add debugging.
	(i386_breakpoint_at): New function.
	(the_low_target): Add new members.
	* gdbserver/linux-mips-low.c (mips_get_pc, mips_set_pc)
	(mips_breakpoint, mips_breakpoint_len, mips_reinsert_addr)
	(mips_breakpoint_at): New.
	(the_low_target): Add new members.
	* gdbserver/linux-ppc-low.c (ppc_get_pc, ppc_set_pc)
	(ppc_breakpoint, ppc_breakpoint_len, ppc_breakpoint_at): New.
	(the_low_target): Add new members.
	* gdbserver/linux-sh-low.c (sh_get_pc, sh_set_pc)
	(sh_breakpoint, sh_breakpoint_len, sh_breakpoint_at): New.
	(the_low_target): Add new members.
	* gdbserver/linux-x86-64-low.c (target_regsets): Add new kind
	identifier.
This commit is contained in:
Daniel Jacobowitz 2002-06-11 17:32:40 +00:00
parent cef717dccf
commit 0d62e5e807
28 changed files with 2700 additions and 344 deletions

View file

@ -126,6 +126,7 @@ OBS = inferiors.o regcache.o remote-utils.o server.o signals.o target.o \
utils.o \
mem-break.o \
$(DEPFILES)
GDBSERVER_LIBS = @GDBSERVER_LIBS@
# Prevent Sun make from putting in the machine type. Setting
# TARGET_ARCH to nothing works for SunOS 3, 4.0, but not for 4.1.
@ -231,6 +232,7 @@ MAKEOVERRIDES=
## with no dependencies and no actions.
unexport CHILLFLAGS CHILL_LIB CHILL_FOR_TARGET :
gdb_proc_service_h = $(srcdir)/../gdb_proc_service.h $(srcdir)/../gregset.h
regdat_sh = $(srcdir)/../regformats/regdat.sh
regdef_h = $(srcdir)/../regformats/regdef.h
regcache_h = $(srcdir)/regcache.h
@ -239,10 +241,12 @@ server_h = $(srcdir)/server.h $(regcache_h) config.h $(srcdir)/target.h \
inferiors.o: inferiors.c $(server_h)
mem-break.o: mem-break.c $(server_h)
proc-service.o: proc-service.c $(server_h) $(gdb_proc_service_h)
regcache.o: regcache.c $(server_h) $(regdef_h)
remote-utils.o: remote-utils.c terminal.h $(server_h)
server.o: server.c $(server_h)
target.o: target.c $(server_h)
thread-db.o: thread-db.c $(server_h) $(gdb_proc_service_h)
utils.o: utils.c $(server_h)
signals.o: ../signals/signals.c $(server_h)
@ -253,6 +257,8 @@ i387-fp.o: i387-fp.c $(server_h)
linux_low_h = $(srcdir)/linux-low.h
linux-low.o: linux-low.c $(linux_low_h) $(server_h)
$(CC) -c $(CPPFLAGS) $(INTERNAL_CFLAGS) $< @USE_THREAD_DB@
linux-arm-low.o: linux-arm-low.c $(linux_low_h) $(server_h)
linux-i386-low.o: linux-i386-low.c $(linux_low_h) $(server_h)
linux-ia64-low.o: linux-ia64-low.c $(linux_low_h) $(server_h)

View file

@ -7,3 +7,18 @@
/* Define if the target supports PTRACE_GETFPXREGS for extended
register access. */
#undef HAVE_PTRACE_GETFPXREGS
/* Define if <sys/procfs.h> has prgregset_t. */
#undef HAVE_PRGREGSET_T
/* Define if <sys/procfs.h> has prfpregset_t. */
#undef HAVE_PRFPREGSET_T
/* Define if <sys/procfs.h> has lwpid_t. */
#undef HAVE_LWPID_T
/* Define if <sys/procfs.h> has psaddr_t. */
#undef HAVE_PSADDR_T
/* Define if the prfpregset_t type is broken. */
#undef PRFPREGSET_T_BROKEN

View file

@ -0,0 +1,41 @@
dnl gdb/gdbserver/configure.in uses BFD_HAVE_SYS_PROCFS_TYPE.
sinclude(../../bfd/acinclude.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_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_getpid() {}],
[td_ta_new();],
[srv_cv_thread_db="$thread_db"],
[srv_cv_thread_db=no])
LIBS="$old_LIBS"
]])
)])

View file

@ -10,91 +10,45 @@ dnl but WITHOUT ANY WARRANTY, to the extent permitted by law; without
dnl even the implied warranty of MERCHANTABILITY or FITNESS FOR A
dnl PARTICULAR PURPOSE.
dnl gdb/gdbserver/configure.in uses BFD_HAVE_SYS_PROCFS_TYPE.
sinclude(../../bfd/acinclude.m4)
# serial 1
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_getpid() {}],
[td_ta_new();],
[srv_cv_thread_db="-lthread_db"],
[srv_cv_thread_db=no
# @defmac AC_PROG_CC_STDC
# @maindex PROG_CC_STDC
# @ovindex CC
# If the C compiler in not in ANSI C mode by default, try to add an option
# to output variable @code{CC} to make it so. This macro tries various
# options that select ANSI C on some system or another. It considers the
# compiler to be in ANSI C mode if it handles function prototypes correctly.
#
# If you use this macro, you should check after calling it whether the C
# compiler has been set to accept ANSI C; if not, the shell variable
# @code{am_cv_prog_cc_stdc} is set to @samp{no}. If you wrote your source
# code in ANSI C, you can make an un-ANSIfied copy of it by using the
# program @code{ansi2knr}, which comes with Ghostscript.
# @end defmac
AC_DEFUN(AM_PROG_CC_STDC,
[AC_REQUIRE([AC_PROG_CC])
AC_BEFORE([$0], [AC_C_INLINE])
AC_BEFORE([$0], [AC_C_CONST])
dnl Force this before AC_PROG_CPP. Some cpp's, eg on HPUX, require
dnl a magic option to avoid problems with ANSI preprocessor commands
dnl like #elif.
dnl FIXME: can't do this because then AC_AIX won't work due to a
dnl circular dependency.
dnl AC_BEFORE([$0], [AC_PROG_CPP])
AC_MSG_CHECKING(for ${CC-cc} option to accept ANSI C)
AC_CACHE_VAL(am_cv_prog_cc_stdc,
[am_cv_prog_cc_stdc=no
ac_save_CC="$CC"
# Don't try gcc -ansi; that turns off useful extensions and
# breaks some systems' header files.
# AIX -qlanglvl=ansi
# Ultrix and OSF/1 -std1
# HP-UX -Aa -D_HPUX_SOURCE
# SVR4 -Xc -D__EXTENSIONS__
for ac_arg in "" -qlanglvl=ansi -std1 "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
do
CC="$ac_save_CC $ac_arg"
AC_TRY_COMPILE(
[#include <stdarg.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
struct buf { int x; };
FILE * (*rcsopen) (struct buf *, struct stat *, int);
static char *e (p, i)
char **p;
int i;
{
return p[i];
}
static char *f (char * (*g) (char **, int), char **p, ...)
{
char *s;
va_list v;
va_start (v,p);
s = g (p, va_arg (v,int));
va_end (v);
return s;
}
int test (int i, double x);
struct s1 {int (*f) (int a);};
struct s2 {int (*f) (double a);};
int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
int argc;
char **argv;
], [
return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
],
[am_cv_prog_cc_stdc="$ac_arg"; break])
done
CC="$ac_save_CC"
])
if test -z "$am_cv_prog_cc_stdc"; then
AC_MSG_RESULT([none needed])
else
AC_MSG_RESULT($am_cv_prog_cc_stdc)
fi
case "x$am_cv_prog_cc_stdc" in
x|xno) ;;
*) CC="$CC $am_cv_prog_cc_stdc" ;;
esac
])
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_getpid() {}],
[td_ta_new();],
[srv_cv_thread_db="$thread_db"],
[srv_cv_thread_db=no])
LIBS="$old_LIBS"
]])
)])

View file

@ -1,4 +1,4 @@
/* config.in. Generated automatically from configure.in by autoheader 2.13. */
/* config.in. Generated automatically from configure.in by autoheader. */
/* Define if you have the ANSI C header files. */
#undef STDC_HEADERS
@ -13,12 +13,24 @@
register access. */
#undef HAVE_PTRACE_GETFPXREGS
/* Define if the prfpregset_t type is broken. */
#undef PRFPREGSET_T_BROKEN
/* Define if you have the <linux/elf.h> header file. */
#undef HAVE_LINUX_ELF_H
/* Define if you have the <proc_service.h> header file. */
#undef HAVE_PROC_SERVICE_H
/* Define if you have the <sgtty.h> header file. */
#undef HAVE_SGTTY_H
/* Define if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define if you have the <sys/procfs.h> header file. */
#undef HAVE_SYS_PROCFS_H
/* Define if you have the <sys/reg.h> header file. */
#undef HAVE_SYS_REG_H
@ -27,3 +39,22 @@
/* Define if you have the <termios.h> header file. */
#undef HAVE_TERMIOS_H
/* Define if you have the <thread_db.h> header file. */
#undef HAVE_THREAD_DB_H
/* Define if <sys/procfs.h> has lwpid_t. */
#undef HAVE_LWPID_T
/* Define if <sys/procfs.h> has psaddr_t. */
#undef HAVE_PSADDR_T
/* Define if <sys/procfs.h> has prgregset_t. */
#undef HAVE_PRGREGSET_T
/* Define if <sys/procfs.h> has prfpregset_t. */
#undef HAVE_PRFPREGSET_T
/* Define if <sys/procfs.h> has elf_fpregset_t. */
#undef HAVE_ELF_FPREGSET_T

View file

@ -28,6 +28,7 @@ program_suffix=NONE
program_transform_name=s,x,x,
silent=
site=
sitefile=
srcdir=
target=NONE
verbose=
@ -142,6 +143,7 @@ Configuration:
--help print this message
--no-create do not create output files
--quiet, --silent do not print \`checking...' messages
--site-file=FILE use FILE as the site file
--version print the version of autoconf that created configure
Directory and file names:
--prefix=PREFIX install architecture-independent files in PREFIX
@ -312,6 +314,11 @@ EOF
-site=* | --site=* | --sit=*)
site="$ac_optarg" ;;
-site-file | --site-file | --site-fil | --site-fi | --site-f)
ac_prev=sitefile ;;
-site-file=* | --site-file=* | --site-fil=* | --site-fi=* | --site-f=*)
sitefile="$ac_optarg" ;;
-srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
ac_prev=srcdir ;;
-srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
@ -477,12 +484,16 @@ fi
srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
# Prefer explicitly selected file to automatically selected ones.
if test -z "$CONFIG_SITE"; then
if test "x$prefix" != xNONE; then
CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
else
CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
if test -z "$sitefile"; then
if test -z "$CONFIG_SITE"; then
if test "x$prefix" != xNONE; then
CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
else
CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
fi
fi
else
CONFIG_SITE="$sitefile"
fi
for ac_site_file in $CONFIG_SITE; do
if test -r "$ac_site_file"; then
@ -526,7 +537,7 @@ fi
# Extract the first word of "gcc", so it can be a program name with args.
set dummy gcc; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:530: checking for $ac_word" >&5
echo "configure:541: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@ -556,7 +567,7 @@ if test -z "$CC"; then
# Extract the first word of "cc", so it can be a program name with args.
set dummy cc; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:560: checking for $ac_word" >&5
echo "configure:571: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@ -607,7 +618,7 @@ fi
# Extract the first word of "cl", so it can be a program name with args.
set dummy cl; ac_word=$2
echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
echo "configure:611: checking for $ac_word" >&5
echo "configure:622: checking for $ac_word" >&5
if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@ -639,7 +650,7 @@ fi
fi
echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
echo "configure:643: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
echo "configure:654: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
ac_ext=c
# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
@ -650,12 +661,12 @@ cross_compiling=$ac_cv_prog_cc_cross
cat > conftest.$ac_ext << EOF
#line 654 "configure"
#line 665 "configure"
#include "confdefs.h"
main(){return(0);}
EOF
if { (eval echo configure:659: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
if { (eval echo configure:670: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
ac_cv_prog_cc_works=yes
# If we can't run a trivial program, we are probably using a cross compiler.
if (./conftest; exit) 2>/dev/null; then
@ -681,12 +692,12 @@ if test $ac_cv_prog_cc_works = no; then
{ echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
fi
echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
echo "configure:685: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
echo "configure:696: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
cross_compiling=$ac_cv_prog_cc_cross
echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
echo "configure:690: checking whether we are using GNU C" >&5
echo "configure:701: checking whether we are using GNU C" >&5
if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@ -695,7 +706,7 @@ else
yes;
#endif
EOF
if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:699: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:710: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
ac_cv_prog_gcc=yes
else
ac_cv_prog_gcc=no
@ -714,7 +725,7 @@ ac_test_CFLAGS="${CFLAGS+set}"
ac_save_CFLAGS="$CFLAGS"
CFLAGS=
echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
echo "configure:718: checking whether ${CC-cc} accepts -g" >&5
echo "configure:729: checking whether ${CC-cc} accepts -g" >&5
if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
@ -793,7 +804,7 @@ else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
fi
echo $ac_n "checking host system type""... $ac_c" 1>&6
echo "configure:797: checking host system type" >&5
echo "configure:808: checking host system type" >&5
host_alias=$host
case "$host_alias" in
@ -814,7 +825,7 @@ host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
echo "$ac_t""$host" 1>&6
echo $ac_n "checking target system type""... $ac_c" 1>&6
echo "configure:818: checking target system type" >&5
echo "configure:829: checking target system type" >&5
target_alias=$target
case "$target_alias" in
@ -832,7 +843,7 @@ target_os=`echo $target | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
echo "$ac_t""$target" 1>&6
echo $ac_n "checking build system type""... $ac_c" 1>&6
echo "configure:836: checking build system type" >&5
echo "configure:847: checking build system type" >&5
build_alias=$build
case "$build_alias" in
@ -867,7 +878,7 @@ test "$host_alias" != "$target_alias" &&
# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
# ./install, which can be erroneously created by make from ./install.sh.
echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
echo "configure:871: checking for a BSD compatible install" >&5
echo "configure:882: checking for a BSD compatible install" >&5
if test -z "$INSTALL"; then
if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
@ -921,7 +932,7 @@ test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
echo "configure:925: checking how to run the C preprocessor" >&5
echo "configure:936: checking how to run the C preprocessor" >&5
# On Suns, sometimes $CPP names a directory.
if test -n "$CPP" && test -d "$CPP"; then
CPP=
@ -936,13 +947,13 @@ else
# On the NeXT, cc -E runs the code through the compiler's parser,
# not just through cpp.
cat > conftest.$ac_ext <<EOF
#line 940 "configure"
#line 951 "configure"
#include "confdefs.h"
#include <assert.h>
Syntax Error
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:946: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
{ (eval echo configure:957: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
:
@ -953,13 +964,13 @@ else
rm -rf conftest*
CPP="${CC-cc} -E -traditional-cpp"
cat > conftest.$ac_ext <<EOF
#line 957 "configure"
#line 968 "configure"
#include "confdefs.h"
#include <assert.h>
Syntax Error
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:963: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
{ (eval echo configure:974: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
:
@ -970,13 +981,13 @@ else
rm -rf conftest*
CPP="${CC-cc} -nologo -E"
cat > conftest.$ac_ext <<EOF
#line 974 "configure"
#line 985 "configure"
#include "confdefs.h"
#include <assert.h>
Syntax Error
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:980: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
{ (eval echo configure:991: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
:
@ -1001,12 +1012,12 @@ fi
echo "$ac_t""$CPP" 1>&6
echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
echo "configure:1005: checking for ANSI C header files" >&5
echo "configure:1016: checking for ANSI C header files" >&5
if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 1010 "configure"
#line 1021 "configure"
#include "confdefs.h"
#include <stdlib.h>
#include <stdarg.h>
@ -1014,7 +1025,7 @@ else
#include <float.h>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:1018: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
{ (eval echo configure:1029: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
@ -1031,7 +1042,7 @@ rm -f conftest*
if test $ac_cv_header_stdc = yes; then
# SunOS 4.x string.h does not declare mem*, contrary to ANSI.
cat > conftest.$ac_ext <<EOF
#line 1035 "configure"
#line 1046 "configure"
#include "confdefs.h"
#include <string.h>
EOF
@ -1049,7 +1060,7 @@ fi
if test $ac_cv_header_stdc = yes; then
# ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
cat > conftest.$ac_ext <<EOF
#line 1053 "configure"
#line 1064 "configure"
#include "confdefs.h"
#include <stdlib.h>
EOF
@ -1070,7 +1081,7 @@ if test "$cross_compiling" = yes; then
:
else
cat > conftest.$ac_ext <<EOF
#line 1074 "configure"
#line 1085 "configure"
#include "confdefs.h"
#include <ctype.h>
#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
@ -1081,7 +1092,7 @@ if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
exit (0); }
EOF
if { (eval echo configure:1085: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
if { (eval echo configure:1096: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
then
:
else
@ -1105,21 +1116,21 @@ EOF
fi
for ac_hdr in sgtty.h termio.h termios.h sys/reg.h string.h
for ac_hdr in sgtty.h termio.h termios.h sys/reg.h string.h proc_service.h sys/procfs.h thread_db.h linux/elf.h
do
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
echo "configure:1113: checking for $ac_hdr" >&5
echo "configure:1124: checking for $ac_hdr" >&5
if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 1118 "configure"
#line 1129 "configure"
#include "confdefs.h"
#include <$ac_hdr>
EOF
ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
{ (eval echo configure:1123: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
{ (eval echo configure:1134: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
ac_err=`grep -v '^ *+' conftest.out | grep -v "^conftest.${ac_ext}\$"`
if test -z "$ac_err"; then
rm -rf conftest*
@ -1157,19 +1168,19 @@ fi
if test "${srv_linux_regsets}" = "yes"; then
echo $ac_n "checking for PTRACE_GETREGS""... $ac_c" 1>&6
echo "configure:1161: checking for PTRACE_GETREGS" >&5
echo "configure:1172: checking for PTRACE_GETREGS" >&5
if eval "test \"`echo '$''{'gdbsrv_cv_have_ptrace_getregs'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 1166 "configure"
#line 1177 "configure"
#include "confdefs.h"
#include <sys/ptrace.h>
int main() {
PTRACE_GETREGS;
; return 0; }
EOF
if { (eval echo configure:1173: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
if { (eval echo configure:1184: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
gdbsrv_cv_have_ptrace_getregs=yes
else
@ -1190,19 +1201,19 @@ EOF
fi
echo $ac_n "checking for PTRACE_GETFPXREGS""... $ac_c" 1>&6
echo "configure:1194: checking for PTRACE_GETFPXREGS" >&5
echo "configure:1205: checking for PTRACE_GETFPXREGS" >&5
if eval "test \"`echo '$''{'gdbsrv_cv_have_ptrace_getfpxregs'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 1199 "configure"
#line 1210 "configure"
#include "confdefs.h"
#include <sys/ptrace.h>
int main() {
PTRACE_GETFPXREGS;
; return 0; }
EOF
if { (eval echo configure:1206: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
if { (eval echo configure:1217: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
gdbsrv_cv_have_ptrace_getfpxregs=yes
else
@ -1223,7 +1234,328 @@ EOF
fi
fi
GDBSERVER_DEPFILES="$srv_regobj $srv_tgtobj"
if test "$ac_cv_header_sys_procfs_h" = yes; then
echo $ac_n "checking for lwpid_t in sys/procfs.h""... $ac_c" 1>&6
echo "configure:1240: checking for lwpid_t in sys/procfs.h" >&5
if eval "test \"`echo '$''{'bfd_cv_have_sys_procfs_type_lwpid_t'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 1245 "configure"
#include "confdefs.h"
#define _SYSCALL32
#include <sys/procfs.h>
int main() {
lwpid_t avar
; return 0; }
EOF
if { (eval echo configure:1254: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
bfd_cv_have_sys_procfs_type_lwpid_t=yes
else
echo "configure: failed program was:" >&5
cat conftest.$ac_ext >&5
rm -rf conftest*
bfd_cv_have_sys_procfs_type_lwpid_t=no
fi
rm -f conftest*
fi
if test $bfd_cv_have_sys_procfs_type_lwpid_t = yes; then
cat >> confdefs.h <<\EOF
#define HAVE_LWPID_T 1
EOF
fi
echo "$ac_t""$bfd_cv_have_sys_procfs_type_lwpid_t" 1>&6
echo $ac_n "checking for psaddr_t in sys/procfs.h""... $ac_c" 1>&6
echo "configure:1276: checking for psaddr_t in sys/procfs.h" >&5
if eval "test \"`echo '$''{'bfd_cv_have_sys_procfs_type_psaddr_t'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 1281 "configure"
#include "confdefs.h"
#define _SYSCALL32
#include <sys/procfs.h>
int main() {
psaddr_t avar
; return 0; }
EOF
if { (eval echo configure:1290: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
bfd_cv_have_sys_procfs_type_psaddr_t=yes
else
echo "configure: failed program was:" >&5
cat conftest.$ac_ext >&5
rm -rf conftest*
bfd_cv_have_sys_procfs_type_psaddr_t=no
fi
rm -f conftest*
fi
if test $bfd_cv_have_sys_procfs_type_psaddr_t = yes; then
cat >> confdefs.h <<\EOF
#define HAVE_PSADDR_T 1
EOF
fi
echo "$ac_t""$bfd_cv_have_sys_procfs_type_psaddr_t" 1>&6
echo $ac_n "checking for prgregset_t in sys/procfs.h""... $ac_c" 1>&6
echo "configure:1312: checking for prgregset_t in sys/procfs.h" >&5
if eval "test \"`echo '$''{'bfd_cv_have_sys_procfs_type_prgregset_t'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 1317 "configure"
#include "confdefs.h"
#define _SYSCALL32
#include <sys/procfs.h>
int main() {
prgregset_t avar
; return 0; }
EOF
if { (eval echo configure:1326: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
bfd_cv_have_sys_procfs_type_prgregset_t=yes
else
echo "configure: failed program was:" >&5
cat conftest.$ac_ext >&5
rm -rf conftest*
bfd_cv_have_sys_procfs_type_prgregset_t=no
fi
rm -f conftest*
fi
if test $bfd_cv_have_sys_procfs_type_prgregset_t = yes; then
cat >> confdefs.h <<\EOF
#define HAVE_PRGREGSET_T 1
EOF
fi
echo "$ac_t""$bfd_cv_have_sys_procfs_type_prgregset_t" 1>&6
echo $ac_n "checking for prfpregset_t in sys/procfs.h""... $ac_c" 1>&6
echo "configure:1348: checking for prfpregset_t in sys/procfs.h" >&5
if eval "test \"`echo '$''{'bfd_cv_have_sys_procfs_type_prfpregset_t'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 1353 "configure"
#include "confdefs.h"
#define _SYSCALL32
#include <sys/procfs.h>
int main() {
prfpregset_t avar
; return 0; }
EOF
if { (eval echo configure:1362: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
bfd_cv_have_sys_procfs_type_prfpregset_t=yes
else
echo "configure: failed program was:" >&5
cat conftest.$ac_ext >&5
rm -rf conftest*
bfd_cv_have_sys_procfs_type_prfpregset_t=no
fi
rm -f conftest*
fi
if test $bfd_cv_have_sys_procfs_type_prfpregset_t = yes; then
cat >> confdefs.h <<\EOF
#define HAVE_PRFPREGSET_T 1
EOF
fi
echo "$ac_t""$bfd_cv_have_sys_procfs_type_prfpregset_t" 1>&6
if test $bfd_cv_have_sys_procfs_type_prfpregset_t = yes; then
echo $ac_n "checking whether prfpregset_t type is broken""... $ac_c" 1>&6
echo "configure:1388: checking whether prfpregset_t type is broken" >&5
if eval "test \"`echo '$''{'gdb_cv_prfpregset_t_broken'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
if test "$cross_compiling" = yes; then
gdb_cv_prfpregset_t_broken=yes
else
cat > conftest.$ac_ext <<EOF
#line 1396 "configure"
#include "confdefs.h"
#include <sys/procfs.h>
int main ()
{
if (sizeof (prfpregset_t) == sizeof (void *))
return 1;
return 0;
}
EOF
if { (eval echo configure:1406: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext} && (./conftest; exit) 2>/dev/null
then
gdb_cv_prfpregset_t_broken=no
else
echo "configure: failed program was:" >&5
cat conftest.$ac_ext >&5
rm -fr conftest*
gdb_cv_prfpregset_t_broken=yes
fi
rm -fr conftest*
fi
fi
echo "$ac_t""$gdb_cv_prfpregset_t_broken" 1>&6
if test $gdb_cv_prfpregset_t_broken = yes; then
cat >> confdefs.h <<\EOF
#define PRFPREGSET_T_BROKEN 1
EOF
fi
fi
echo $ac_n "checking for elf_fpregset_t in sys/procfs.h""... $ac_c" 1>&6
echo "configure:1430: checking for elf_fpregset_t in sys/procfs.h" >&5
if eval "test \"`echo '$''{'bfd_cv_have_sys_procfs_type_elf_fpregset_t'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
cat > conftest.$ac_ext <<EOF
#line 1435 "configure"
#include "confdefs.h"
#define _SYSCALL32
#include <sys/procfs.h>
int main() {
elf_fpregset_t avar
; return 0; }
EOF
if { (eval echo configure:1444: \"$ac_compile\") 1>&5; (eval $ac_compile) 2>&5; }; then
rm -rf conftest*
bfd_cv_have_sys_procfs_type_elf_fpregset_t=yes
else
echo "configure: failed program was:" >&5
cat conftest.$ac_ext >&5
rm -rf conftest*
bfd_cv_have_sys_procfs_type_elf_fpregset_t=no
fi
rm -f conftest*
fi
if test $bfd_cv_have_sys_procfs_type_elf_fpregset_t = yes; then
cat >> confdefs.h <<\EOF
#define HAVE_ELF_FPREGSET_T 1
EOF
fi
echo "$ac_t""$bfd_cv_have_sys_procfs_type_elf_fpregset_t" 1>&6
fi
srv_thread_depfiles=
srv_libs=
USE_THREAD_DB=
if test "$srv_linux_thread_db" = "yes"; then
echo $ac_n "checking for libthread_db""... $ac_c" 1>&6
echo "configure:1473: checking for libthread_db" >&5
if eval "test \"`echo '$''{'srv_cv_thread_db'+set}'`\" = set"; then
echo $ac_n "(cached) $ac_c" 1>&6
else
old_LIBS="$LIBS"
LIBS="$LIBS -lthread_db"
cat > conftest.$ac_ext <<EOF
#line 1480 "configure"
#include "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_getpid() {}
int main() {
td_ta_new();
; return 0; }
EOF
if { (eval echo configure:1494: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
srv_cv_thread_db="-lthread_db"
else
echo "configure: failed program was:" >&5
cat conftest.$ac_ext >&5
rm -rf conftest*
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 > conftest.$ac_ext <<EOF
#line 1510 "configure"
#include "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_getpid() {}
int main() {
td_ta_new();
; return 0; }
EOF
if { (eval echo configure:1524: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest${ac_exeext}; then
rm -rf conftest*
srv_cv_thread_db="$thread_db"
else
echo "configure: failed program was:" >&5
cat conftest.$ac_ext >&5
rm -rf conftest*
srv_cv_thread_db=no
fi
rm -f conftest*
LIBS="$old_LIBS"
fi
echo "$ac_t""$srv_cv_thread_db" 1>&6
fi
rm -f conftest*
if test "$srv_cv_thread_db" = no; then
echo "configure: warning: Could not find libthread_db." 1>&2
echo "configure: warning: Disabling thread support in gdbserver." 1>&2
srv_linux_thread_db=no
else
srv_libs="$srv_cv_thread_db"
fi
fi
if test "$srv_linux_thread_db" = "yes"; then
srv_thread_depfiles="thread-db.o proc-service.o"
USE_THREAD_DB="-DUSE_THREAD_DB"
fi
GDBSERVER_DEPFILES="$srv_regobj $srv_tgtobj $srv_thread_depfiles"
GDBSERVER_LIBS="$srv_libs"
@ -1381,6 +1713,8 @@ s%@INSTALL_SCRIPT@%$INSTALL_SCRIPT%g
s%@INSTALL_DATA@%$INSTALL_DATA%g
s%@CPP@%$CPP%g
s%@GDBSERVER_DEPFILES@%$GDBSERVER_DEPFILES%g
s%@GDBSERVER_LIBS@%$GDBSERVER_LIBS%g
s%@USE_THREAD_DB@%$USE_THREAD_DB%g
CEOF
EOF

View file

@ -30,7 +30,8 @@ AC_PROG_INSTALL
AC_HEADER_STDC
AC_CHECK_HEADERS(sgtty.h termio.h termios.h sys/reg.h string.h)
AC_CHECK_HEADERS(sgtty.h termio.h termios.h sys/reg.h string.h dnl
proc_service.h sys/procfs.h thread_db.h linux/elf.h)
. ${srcdir}/configure.srv
@ -62,9 +63,67 @@ if test "${srv_linux_regsets}" = "yes"; then
fi
fi
GDBSERVER_DEPFILES="$srv_regobj $srv_tgtobj"
if test "$ac_cv_header_sys_procfs_h" = yes; then
BFD_HAVE_SYS_PROCFS_TYPE(lwpid_t)
BFD_HAVE_SYS_PROCFS_TYPE(psaddr_t)
BFD_HAVE_SYS_PROCFS_TYPE(prgregset_t)
BFD_HAVE_SYS_PROCFS_TYPE(prfpregset_t)
dnl Check for broken prfpregset_t type
dnl For Linux/i386, glibc 2.1.3 was released with a bogus
dnl prfpregset_t type (it's a typedef for the pointer to a struct
dnl instead of the struct itself). We detect this here, and work
dnl around it in gdb_proc_service.h.
if test $bfd_cv_have_sys_procfs_type_prfpregset_t = yes; then
AC_MSG_CHECKING(whether prfpregset_t type is broken)
AC_CACHE_VAL(gdb_cv_prfpregset_t_broken,
[AC_TRY_RUN([#include <sys/procfs.h>
int main ()
{
if (sizeof (prfpregset_t) == sizeof (void *))
return 1;
return 0;
}],
gdb_cv_prfpregset_t_broken=no,
gdb_cv_prfpregset_t_broken=yes,
gdb_cv_prfpregset_t_broken=yes)])
AC_MSG_RESULT($gdb_cv_prfpregset_t_broken)
if test $gdb_cv_prfpregset_t_broken = yes; then
AC_DEFINE(PRFPREGSET_T_BROKEN)
fi
fi
BFD_HAVE_SYS_PROCFS_TYPE(elf_fpregset_t)
fi
srv_thread_depfiles=
srv_libs=
USE_THREAD_DB=
if test "$srv_linux_thread_db" = "yes"; then
SRV_CHECK_THREAD_DB
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"
fi
fi
if test "$srv_linux_thread_db" = "yes"; then
srv_thread_depfiles="thread-db.o proc-service.o"
USE_THREAD_DB="-DUSE_THREAD_DB"
fi
GDBSERVER_DEPFILES="$srv_regobj $srv_tgtobj $srv_thread_depfiles"
GDBSERVER_LIBS="$srv_libs"
AC_SUBST(GDBSERVER_DEPFILES)
AC_SUBST(GDBSERVER_LIBS)
AC_SUBST(USE_THREAD_DB)
AC_OUTPUT(Makefile,
[case x$CONFIG_HEADERS in

View file

@ -21,11 +21,13 @@ case "${target}" in
arm*-*-linux*) srv_regobj=reg-arm.o
srv_tgtobj="linux-low.o linux-arm-low.o"
srv_linux_usrregs=yes
srv_linux_thread_db=yes
;;
i[3456]86-*-linux*) srv_regobj=reg-i386-linux.o
srv_tgtobj="linux-low.o linux-i386-low.o i387-fp.o"
srv_linux_usrregs=yes
srv_linux_regsets=yes
srv_linux_thread_db=yes
;;
ia64-*-linux*) srv_regobj=reg-ia64.o
srv_tgtobj="linux-low.o linux-ia64-low.o"
@ -38,10 +40,12 @@ case "${target}" in
mips*-*-linux*) srv_regobj=reg-mips.o
srv_tgtobj="linux-low.o linux-mips-low.o"
srv_linux_usrregs=yes
srv_linux_thread_db=yes
;;
powerpc*-*-linux*) srv_regobj=reg-ppc.o
srv_tgtobj="linux-low.o linux-ppc-low.o"
srv_linux_usrregs=yes
srv_linux_thread_db=yes
;;
s390-*-linux*) srv_regobj=reg-s390.o
srv_tgtobj="linux-low.o linux-s390-low.o"
@ -54,6 +58,7 @@ case "${target}" in
sh*-*-linux*) srv_regobj=reg-sh.o
srv_tgtobj="linux-low.o linux-sh-low.o"
srv_linux_usrregs=yes
srv_linux_thread_db=yes
;;
x86_64-*-linux*) srv_regobj=reg-x86-64.o
srv_tgtobj="linux-low.o linux-x86-64-low.o i387-fp.o"

View file

@ -20,6 +20,7 @@
Boston, MA 02111-1307, USA. */
#include "server.h"
#include "i387-fp.h"
int num_xmm_registers = 8;
@ -108,7 +109,7 @@ i387_cache_to_fsave (void *buf)
}
void
i387_fsave_to_cache (void *buf)
i387_fsave_to_cache (const void *buf)
{
struct i387_fsave *fp = (struct i387_fsave *) buf;
int i;
@ -240,7 +241,7 @@ i387_ftag (struct i387_fxsave *fp, int regno)
}
void
i387_fxsave_to_cache (void *buf)
i387_fxsave_to_cache (const void *buf)
{
struct i387_fxsave *fp = (struct i387_fxsave *) buf;
int i, top;
@ -287,4 +288,3 @@ i387_fxsave_to_cache (void *buf)
val = (fp->fop) & 0x7FF;
supply_register_by_name ("fop", &val);
}

View file

@ -23,10 +23,10 @@
#define I387_FP_H
void i387_cache_to_fsave (void *buf);
void i387_fsave_to_cache (void *buf);
void i387_fsave_to_cache (const void *buf);
void i387_cache_to_fxsave (void *buf);
void i387_fxsave_to_cache (void *buf);
void i387_fxsave_to_cache (const void *buf);
extern int num_xmm_registers;

View file

@ -25,81 +25,175 @@
#include "server.h"
struct inferior_info
struct thread_info
{
int pid;
struct inferior_list_entry entry;
void *target_data;
void *regcache_data;
struct inferior_info *next;
};
static struct inferior_info *inferiors;
struct inferior_info *current_inferior;
int signal_pid;
struct inferior_list all_threads;
struct thread_info *current_inferior;
#define get_thread(inf) ((struct thread_info *)(inf))
void
add_inferior (int pid)
add_inferior_to_list (struct inferior_list *list,
struct inferior_list_entry *new_inferior)
{
struct inferior_info *new_inferior
= (struct inferior_info *) malloc (sizeof (*new_inferior));
new_inferior->next = NULL;
if (list->tail != NULL)
list->tail->next = new_inferior;
else
list->head = new_inferior;
list->tail = new_inferior;
}
memset (new_inferior, 0, sizeof (*new_inferior));
void
for_each_inferior (struct inferior_list *list,
void (*action) (struct inferior_list_entry *))
{
struct inferior_list_entry *cur = list->head, *next;
new_inferior->pid = pid;
while (cur != NULL)
{
next = cur->next;
(*action) (cur);
cur = next;
}
}
new_inferior->next = inferiors;
inferiors = new_inferior;
void
change_inferior_id (struct inferior_list *list,
int new_id)
{
if (list->head != list->tail)
error ("tried to change thread ID after multiple threads are created");
list->head->id = new_id;
}
void
remove_inferior (struct inferior_list *list,
struct inferior_list_entry *entry)
{
struct inferior_list_entry **cur;
if (list->head == entry)
{
list->head = entry->next;
if (list->tail == entry)
list->tail = list->head;
return;
}
cur = &list->head;
while (*cur && (*cur)->next != entry)
cur = &(*cur)->next;
if (*cur == NULL)
return;
(*cur)->next = entry->next;
if (list->tail == entry)
list->tail = *cur;
}
void
add_thread (int thread_id, void *target_data)
{
struct thread_info *new_thread
= (struct thread_info *) malloc (sizeof (*new_thread));
memset (new_thread, 0, sizeof (*new_thread));
new_thread->entry.id = thread_id;
add_inferior_to_list (&all_threads, & new_thread->entry);
if (current_inferior == NULL)
current_inferior = inferiors;
current_inferior = new_thread;
create_register_cache (new_inferior);
new_thread->target_data = target_data;
set_inferior_regcache_data (new_thread, new_register_cache ());
}
if (signal_pid == 0)
signal_pid = pid;
static void
free_one_thread (struct inferior_list_entry *inf)
{
struct thread_info *thread = get_thread (inf);
free_register_cache (inferior_regcache_data (thread));
free (thread);
}
void
remove_thread (struct thread_info *thread)
{
remove_inferior (&all_threads, (struct inferior_list_entry *) thread);
free_one_thread (&thread->entry);
}
void
clear_inferiors (void)
{
struct inferior_info *inf = inferiors, *next_inf;
for_each_inferior (&all_threads, free_one_thread);
while (inf)
all_threads.head = all_threads.tail = NULL;
}
struct inferior_list_entry *
find_inferior (struct inferior_list *list,
int (*func) (struct inferior_list_entry *, void *), void *arg)
{
struct inferior_list_entry *inf = list->head;
while (inf != NULL)
{
next_inf = inf->next;
if (inf->target_data)
free (inf->target_data);
if (inf->regcache_data)
free_register_cache (inf);
free (inf);
inf = next_inf;
if ((*func) (inf, arg))
return inf;
inf = inf->next;
}
inferiors = NULL;
return NULL;
}
struct inferior_list_entry *
find_inferior_id (struct inferior_list *list, int id)
{
struct inferior_list_entry *inf = list->head;
while (inf != NULL)
{
if (inf->id == id)
return inf;
inf = inf->next;
}
return NULL;
}
void *
inferior_target_data (struct inferior_info *inferior)
inferior_target_data (struct thread_info *inferior)
{
return inferior->target_data;
}
void
set_inferior_target_data (struct inferior_info *inferior, void *data)
set_inferior_target_data (struct thread_info *inferior, void *data)
{
inferior->target_data = data;
}
void *
inferior_regcache_data (struct inferior_info *inferior)
inferior_regcache_data (struct thread_info *inferior)
{
return inferior->regcache_data;
}
void
set_inferior_regcache_data (struct inferior_info *inferior, void *data)
set_inferior_regcache_data (struct thread_info *inferior, void *data)
{
inferior->regcache_data = data;
}

View file

@ -45,9 +45,49 @@ arm_cannot_fetch_register (int regno)
return (regno >= arm_num_regs);
}
static CORE_ADDR
arm_get_pc ()
{
unsigned long pc;
collect_register_by_name ("pc", &pc);
return pc;
}
static void
arm_set_pc (CORE_ADDR pc)
{
unsigned long newpc = pc;
supply_register_by_name ("pc", &newpc);
}
/* Correct in either endianness. We do not support Thumb yet. */
static const unsigned long arm_breakpoint = 0xef9f0001;
#define arm_breakpoint_len 4
static int
arm_breakpoint_at (CORE_ADDR where)
{
unsigned long insn;
(*the_target->read_memory) (where, (char *) &insn, 4);
if (insn == arm_breakpoint)
return 1;
/* If necessary, recognize more trap instructions here. GDB only uses the
one. */
return 0;
}
struct linux_target_ops the_low_target = {
arm_num_regs,
arm_regmap,
arm_cannot_fetch_register,
arm_cannot_store_register,
arm_get_pc,
arm_set_pc,
(const char *) &arm_breakpoint,
arm_breakpoint_len,
NULL,
0,
arm_breakpoint_at,
};

View file

@ -72,7 +72,7 @@ i386_fill_gregset (void *buf)
}
static void
i386_store_gregset (void *buf)
i386_store_gregset (const void *buf)
{
int i;
@ -89,7 +89,7 @@ i386_fill_fpregset (void *buf)
}
static void
i386_store_fpregset (void *buf)
i386_store_fpregset (const void *buf)
{
i387_fsave_to_cache (buf);
}
@ -101,7 +101,7 @@ i386_fill_fpxregset (void *buf)
}
static void
i386_store_fpxregset (void *buf)
i386_store_fpxregset (const void *buf)
{
i387_fxsave_to_cache (buf);
}
@ -109,14 +109,17 @@ i386_store_fpxregset (void *buf)
struct regset_info target_regsets[] = {
{ PTRACE_GETREGS, PTRACE_SETREGS, sizeof (elf_gregset_t),
GENERAL_REGS,
i386_fill_gregset, i386_store_gregset },
#ifdef HAVE_PTRACE_GETFPXREGS
{ PTRACE_GETFPXREGS, PTRACE_SETFPXREGS, sizeof (elf_fpxregset_t),
EXTENDED_REGS,
i386_fill_fpxregset, i386_store_fpxregset },
#endif
{ PTRACE_GETFPREGS, PTRACE_SETFPREGS, sizeof (elf_fpregset_t),
FP_REGS,
i386_fill_fpregset, i386_store_fpregset },
{ 0, 0, -1, NULL, NULL }
{ 0, 0, -1, -1, NULL, NULL }
};
#endif /* HAVE_LINUX_REGSETS */
@ -124,25 +127,38 @@ struct regset_info target_regsets[] = {
static const char i386_breakpoint[] = { 0xCC };
#define i386_breakpoint_len 1
extern int debug_threads;
static CORE_ADDR
i386_stop_pc ()
i386_get_pc ()
{
unsigned long pc;
/* Overkill */
fetch_inferior_registers (0);
collect_register_by_name ("eip", &pc);
return pc - 1;
if (debug_threads)
fprintf (stderr, "stop pc (before any decrement) is %08lx\n", pc);
return pc;
}
static void
i386_set_pc (CORE_ADDR newpc)
{
if (debug_threads)
fprintf (stderr, "set pc to %08lx\n", (long) newpc);
supply_register_by_name ("eip", &newpc);
}
/* Overkill */
store_inferior_registers (0);
static int
i386_breakpoint_at (CORE_ADDR pc)
{
unsigned char c;
read_inferior_memory (pc, &c, 1);
if (c == 0xCC)
return 1;
return 0;
}
struct linux_target_ops the_low_target = {
@ -150,8 +166,11 @@ struct linux_target_ops the_low_target = {
i386_regmap,
i386_cannot_fetch_register,
i386_cannot_store_register,
i386_stop_pc,
i386_get_pc,
i386_set_pc,
i386_breakpoint,
i386_breakpoint_len,
NULL,
1,
i386_breakpoint_at,
};

File diff suppressed because it is too large Load diff

View file

@ -19,12 +19,21 @@
Boston, MA 02111-1307, USA. */
#ifdef HAVE_LINUX_REGSETS
typedef void (*regset_func) (void *);
typedef void (*regset_fill_func) (void *);
typedef void (*regset_store_func) (const void *);
enum regset_type {
GENERAL_REGS,
FP_REGS,
EXTENDED_REGS,
};
struct regset_info
{
int get_request, set_request;
int size;
regset_func fill_function, store_function;
enum regset_type type;
regset_fill_func fill_function;
regset_store_func store_function;
};
extern struct regset_info target_regsets[];
#endif
@ -39,11 +48,67 @@ struct linux_target_ops
store the register, and 2 if failure to store the register
is acceptable. */
int (*cannot_store_register) (int);
CORE_ADDR (*stop_pc) (void);
CORE_ADDR (*get_pc) (void);
void (*set_pc) (CORE_ADDR newpc);
const char *breakpoint;
int breakpoint_len;
CORE_ADDR (*breakpoint_reinsert_addr) (void);
int decr_pc_after_break;
int (*breakpoint_at) (CORE_ADDR pc);
};
extern struct linux_target_ops the_low_target;
#define get_process(inf) ((struct process_info *)(inf))
#define get_thread_process(thr) (get_process (inferior_target_data (thr)))
#define get_process_thread(proc) ((struct thread_info *) \
find_inferior_id (&all_threads, \
get_process (proc)->tid))
struct process_info
{
struct inferior_list_entry head;
int thread_known;
int lwpid;
int tid;
/* If this flag is set, the next SIGSTOP will be ignored (the process will
be immediately resumed). */
int stop_expected;
/* If this flag is set, the process is known to be stopped right now (stop
event already received in a wait()). */
int stopped;
/* If this flag is set, we have sent a SIGSTOP to this process and are
waiting for it to stop. */
int sigstop_sent;
/* If this flag is set, STATUS_PENDING is a waitstatus that has not yet
been reported. */
int status_pending_p;
int status_pending;
/* If this flag is set, the pending status is a (GDB-placed) breakpoint. */
int pending_is_breakpoint;
CORE_ADDR pending_stop_pc;
/* If this is non-zero, it is a breakpoint to be reinserted at our next
stop (SIGTRAP stops only). */
CORE_ADDR bp_reinsert;
/* If this flag is set, the last continue operation on this process
was a single-step. */
int stepping;
/* If this is non-zero, it points to a chain of signals which need to
be delivered to this process. */
struct pending_signals *pending_signals;
};
extern struct inferior_list all_processes;
void linux_attach_lwp (int pid, int tid);
int thread_db_init (void);

View file

@ -96,9 +96,60 @@ mips_cannot_store_register (int regno)
return 0;
}
static CORE_ADDR
mips_get_pc ()
{
unsigned long pc;
collect_register_by_name ("pc", &pc);
return pc;
}
static void
mips_set_pc (CORE_ADDR pc)
{
unsigned long newpc = pc;
supply_register_by_name ("pc", &newpc);
}
/* Correct in either endianness. */
static const unsigned long mips_breakpoint = 0x0005000d;
#define mips_breakpoint_len 4
/* We only place breakpoints in empty marker functions, and thread locking
is outside of the function. So rather than importing software single-step,
we can just run until exit. */
static CORE_ADDR
mips_reinsert_addr ()
{
unsigned long pc;
collect_register_by_name ("ra", &pc);
return pc;
}
static int
mips_breakpoint_at (CORE_ADDR where)
{
unsigned long insn;
(*the_target->read_memory) (where, (char *) &insn, 4);
if (insn == mips_breakpoint)
return 1;
/* If necessary, recognize more trap instructions here. GDB only uses the
one. */
return 0;
}
struct linux_target_ops the_low_target = {
mips_num_regs,
mips_regmap,
mips_cannot_fetch_register,
mips_cannot_store_register,
mips_get_pc,
mips_set_pc,
(const char *) &mips_breakpoint,
mips_breakpoint_len,
mips_reinsert_addr,
0,
mips_breakpoint_at,
};

View file

@ -64,9 +64,53 @@ ppc_cannot_fetch_register (int regno)
return 0;
}
static CORE_ADDR
ppc_get_pc (void)
{
unsigned long pc;
collect_register_by_name ("pc", &pc);
return (CORE_ADDR) pc;
}
static void
ppc_set_pc (CORE_ADDR pc)
{
unsigned long newpc = pc;
supply_register_by_name ("pc", &newpc);
}
/* Correct in either endianness. Note that this file is
for PowerPC only, not PowerPC64.
This instruction is "twge r2, r2", which GDB uses as a software
breakpoint. */
static const unsigned long ppc_breakpoint = 0x7d821008;
#define ppc_breakpoint_len 4
static int
ppc_breakpoint_at (CORE_ADDR where)
{
unsigned long insn;
(*the_target->read_memory) (where, (char *) &insn, 4);
if (insn == ppc_breakpoint)
return 1;
/* If necessary, recognize more trap instructions here. GDB only uses the
one. */
return 0;
}
struct linux_target_ops the_low_target = {
ppc_num_regs,
ppc_regmap,
ppc_cannot_fetch_register,
ppc_cannot_store_register,
ppc_get_pc,
ppc_set_pc,
(const char *) &ppc_breakpoint,
ppc_breakpoint_len,
NULL,
0,
ppc_breakpoint_at,
};

View file

@ -57,9 +57,49 @@ sh_cannot_fetch_register (int regno)
return 0;
}
static CORE_ADDR
sh_get_pc ()
{
unsigned long pc;
collect_register_by_name ("pc", &pc);
return pc;
}
static void
sh_set_pc (CORE_ADDR pc)
{
unsigned long newpc = pc;
supply_register_by_name ("pc", &newpc);
}
/* Correct in either endianness, obviously. */
static const unsigned short sh_breakpoint = 0xc3c3;
#define sh_breakpoint_len 2
static int
sh_breakpoint_at (CORE_ADDR where)
{
unsigned short insn;
(*the_target->read_memory) (where, (char *) &insn, 2);
if (insn == sh_breakpoint)
return 1;
/* If necessary, recognize more trap instructions here. GDB only uses the
one. */
return 0;
}
struct linux_target_ops the_low_target = {
sh_num_regs,
sh_regmap,
sh_cannot_fetch_register,
sh_cannot_store_register,
sh_get_pc,
sh_set_pc,
(const char *) &sh_breakpoint,
sh_breakpoint_len,
NULL,
0,
sh_breakpoint_at,
};

View file

@ -71,10 +71,12 @@ x86_64_store_fpregset (void *buf)
struct regset_info target_regsets[] = {
{ PTRACE_GETREGS, PTRACE_SETREGS, sizeof (elf_gregset_t),
GENERAL_REGS,
x86_64_fill_gregset, x86_64_store_gregset },
{ PTRACE_GETFPREGS, PTRACE_SETFPREGS, sizeof (elf_fpregset_t),
FP_REGS,
x86_64_fill_fpregset, x86_64_store_fpregset },
{ 0, 0, -1, NULL, NULL }
{ 0, 0, -1, -1, NULL, NULL }
};
struct linux_target_ops the_low_target = {

View file

@ -0,0 +1,256 @@
/* libthread_db helper functions for the remote server for GDB.
Copyright 2002
Free Software Foundation, Inc.
Contributed by MontaVista Software.
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 2 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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "server.h"
/* This file is currently tied to GNU/Linux. It should scale well to
another libthread_db implementation, with the approriate gdbserver
hooks, but for now this means we can use GNU/Linux's target data. */
#include "linux-low.h"
/* Correct for all GNU/Linux targets (for quite some time). */
#define GDB_GREGSET_T elf_gregset_t
#define GDB_FPREGSET_T elf_fpregset_t
#ifndef HAVE_ELF_FPREGSET_T
/* Make sure we have said types. Not all platforms bring in <linux/elf.h>
via <sys/procfs.h>. */
#ifdef HAVE_LINUX_ELF_H
#include <linux/elf.h>
#endif
#endif
#include "../gdb_proc_service.h"
typedef struct ps_prochandle *gdb_ps_prochandle_t;
typedef void *gdb_ps_read_buf_t;
typedef const void *gdb_ps_write_buf_t;
typedef size_t gdb_ps_size_t;
/* FIXME redo this right */
#if 0
#ifndef HAVE_LINUX_REGSETS
#error HAVE_LINUX_REGSETS required!
#else
static struct regset_info *
gregset_info(void)
{
int i = 0;
while (target_regsets[i].size != -1)
{
if (target_regsets[i].type == GENERAL_REGS)
break;
i++;
}
return &target_regsets[i];
}
static struct regset_info *
fpregset_info(void)
{
int i = 0;
while (target_regsets[i].size != -1)
{
if (target_regsets[i].type == FP_REGS)
break;
i++;
}
return &target_regsets[i];
}
#endif
#endif
/* Search for the symbol named NAME within the object named OBJ within
the target process PH. If the symbol is found the address of the
symbol is stored in SYM_ADDR. */
ps_err_e
ps_pglobal_lookup (gdb_ps_prochandle_t ph, const char *obj,
const char *name, paddr_t *sym_addr)
{
CORE_ADDR addr;
if (look_up_one_symbol (name, &addr) == 0)
return PS_NOSYM;
*sym_addr = (paddr_t) (unsigned long) addr;
return PS_OK;
}
/* Read SIZE bytes from the target process PH at address ADDR and copy
them into BUF. */
ps_err_e
ps_pdread (gdb_ps_prochandle_t ph, paddr_t addr,
gdb_ps_read_buf_t buf, gdb_ps_size_t size)
{
read_inferior_memory (addr, buf, size);
return PS_OK;
}
/* Write SIZE bytes from BUF into the target process PH at address ADDR. */
ps_err_e
ps_pdwrite (gdb_ps_prochandle_t ph, paddr_t addr,
gdb_ps_write_buf_t buf, gdb_ps_size_t size)
{
return write_inferior_memory (addr, buf, size);
}
/* Get the general registers of LWP LWPID within the target process PH
and store them in GREGSET. */
ps_err_e
ps_lgetregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, prgregset_t gregset)
{
#if 0
struct thread_info *reg_inferior, *save_inferior;
void *regcache;
reg_inferior = (struct thread_info *) find_inferior_id (&all_threads,
lwpid);
if (reg_inferior == NULL)
return PS_ERR;
save_inferior = current_inferior;
current_inferior = reg_inferior;
regcache = new_register_cache ();
the_target->fetch_registers (0, regcache);
gregset_info()->fill_function (gregset, regcache);
free_register_cache (regcache);
current_inferior = save_inferior;
return PS_OK;
#endif
/* FIXME */
return PS_ERR;
}
/* Set the general registers of LWP LWPID within the target process PH
from GREGSET. */
ps_err_e
ps_lsetregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, const prgregset_t gregset)
{
#if 0
struct thread_info *reg_inferior, *save_inferior;
void *regcache;
reg_inferior = (struct thread_info *) find_inferior_id (&all_threads, lwpid);
if (reg_inferior == NULL)
return PS_ERR;
save_inferior = current_inferior;
current_inferior = reg_inferior;
regcache = new_register_cache ();
gregset_info()->store_function (gregset, regcache);
the_target->store_registers (0, regcache);
free_register_cache (regcache);
current_inferior = save_inferior;
return PS_OK;
#endif
/* FIXME */
return PS_ERR;
}
/* Get the floating-point registers of LWP LWPID within the target
process PH and store them in FPREGSET. */
ps_err_e
ps_lgetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid,
gdb_prfpregset_t *fpregset)
{
#if 0
struct thread_info *reg_inferior, *save_inferior;
void *regcache;
reg_inferior = (struct thread_info *) find_inferior_id (&all_threads, lwpid);
if (reg_inferior == NULL)
return PS_ERR;
save_inferior = current_inferior;
current_inferior = reg_inferior;
regcache = new_register_cache ();
the_target->fetch_registers (0, regcache);
fpregset_info()->fill_function (fpregset, regcache);
free_register_cache (regcache);
current_inferior = save_inferior;
return PS_OK;
#endif
/* FIXME */
return PS_ERR;
}
/* Set the floating-point registers of LWP LWPID within the target
process PH from FPREGSET. */
ps_err_e
ps_lsetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid,
const gdb_prfpregset_t *fpregset)
{
#if 0
struct thread_info *reg_inferior, *save_inferior;
void *regcache;
reg_inferior = (struct thread_info *) find_inferior_id (&all_threads, lwpid);
if (reg_inferior == NULL)
return PS_ERR;
save_inferior = current_inferior;
current_inferior = reg_inferior;
regcache = new_register_cache ();
fpregset_info()->store_function (fpregset, regcache);
the_target->store_registers (0, regcache);
free_register_cache (regcache);
current_inferior = save_inferior;
return PS_OK;
#endif
/* FIXME */
return PS_ERR;
}
/* Return overall process id of the target PH. Special for GNU/Linux
-- not used on Solaris. */
pid_t
ps_getpid (gdb_ps_prochandle_t ph)
{
return ph->pid;
}

View file

@ -27,6 +27,7 @@
struct inferior_regcache_data
{
int registers_valid;
char *registers;
};
@ -38,7 +39,7 @@ static int num_registers;
const char **gdbserver_expedite_regs;
static struct inferior_regcache_data *
get_regcache (struct inferior_info *inf)
get_regcache (struct thread_info *inf, int fetch)
{
struct inferior_regcache_data *regcache;
@ -47,17 +48,50 @@ get_regcache (struct inferior_info *inf)
if (regcache == NULL)
fatal ("no register cache");
/* FIXME - fetch registers for INF */
if (fetch && regcache->registers_valid == 0)
{
fetch_inferior_registers (0);
regcache->registers_valid = 1;
}
return regcache;
}
void
regcache_invalidate_one (struct inferior_list_entry *entry)
{
struct thread_info *thread = (struct thread_info *) entry;
struct inferior_regcache_data *regcache;
regcache = (struct inferior_regcache_data *) inferior_regcache_data (thread);
if (regcache->registers_valid)
{
struct thread_info *saved_inferior = current_inferior;
current_inferior = thread;
store_inferior_registers (-1);
current_inferior = saved_inferior;
}
regcache->registers_valid = 0;
}
void
regcache_invalidate ()
{
for_each_inferior (&all_threads, regcache_invalidate_one);
}
int
registers_length (void)
{
return 2 * register_bytes;
}
void
create_register_cache (struct inferior_info *inferior)
void *
new_register_cache (void)
{
struct inferior_regcache_data *regcache;
@ -67,15 +101,19 @@ create_register_cache (struct inferior_info *inferior)
if (regcache->registers == NULL)
fatal ("Could not allocate register cache.");
set_inferior_regcache_data (inferior, regcache);
regcache->registers_valid = 0;
return regcache;
}
void
free_register_cache (struct inferior_info *inferior)
free_register_cache (void *regcache_p)
{
free (get_regcache (current_inferior)->registers);
free (get_regcache (current_inferior));
set_inferior_regcache_data (inferior, NULL);
struct inferior_regcache_data *regcache
= (struct inferior_regcache_data *) regcache_p;
free (regcache->registers);
free (regcache);
}
void
@ -99,7 +137,7 @@ set_register_cache (struct reg *regs, int n)
void
registers_to_string (char *buf)
{
char *registers = get_regcache (current_inferior)->registers;
char *registers = get_regcache (current_inferior, 1)->registers;
convert_int_to_ascii (registers, buf, register_bytes);
}
@ -108,7 +146,7 @@ void
registers_from_string (char *buf)
{
int len = strlen (buf);
char *registers = get_regcache (current_inferior)->registers;
char *registers = get_regcache (current_inferior, 1)->registers;
if (len != register_bytes * 2)
{
@ -155,10 +193,10 @@ register_size (int n)
return reg_defs[n].size / 8;
}
char *
register_data (int n)
static char *
register_data (int n, int fetch)
{
char *registers = get_regcache (current_inferior)->registers;
char *registers = get_regcache (current_inferior, fetch)->registers;
return registers + (reg_defs[n].offset / 8);
}
@ -166,7 +204,7 @@ register_data (int n)
void
supply_register (int n, const void *buf)
{
memcpy (register_data (n), buf, register_size (n));
memcpy (register_data (n, 0), buf, register_size (n));
}
void
@ -178,7 +216,13 @@ supply_register_by_name (const char *name, const void *buf)
void
collect_register (int n, void *buf)
{
memcpy (buf, register_data (n), register_size (n));
memcpy (buf, register_data (n, 1), register_size (n));
}
void
collect_register_as_string (int n, char *buf)
{
convert_int_to_ascii (register_data (n, 1), buf, register_size (n));
}
void

View file

@ -21,15 +21,20 @@
#ifndef REGCACHE_H
#define REGCACHE_H
struct inferior_info;
struct inferior_list_entry;
/* Create a new register cache for INFERIOR. */
void create_register_cache (struct inferior_info *inferior);
void *new_register_cache (void);
/* Release all memory associated with the register cache for INFERIOR. */
void free_register_cache (struct inferior_info *inferior);
void free_register_cache (void *regcache);
/* Invalidate cached registers for one or all threads. */
void regcache_invalidate_one (struct inferior_list_entry *);
void regcache_invalidate (void);
/* Convert all registers to a string in the currently specified remote
format. */
@ -48,8 +53,6 @@ int registers_length (void);
struct reg *find_register_by_number (int n);
char *register_data (int n);
int register_size (int n);
int find_regno (const char *name);
@ -62,6 +65,8 @@ void supply_register_by_name (const char *name, const void *buf);
void collect_register (int n, void *buf);
void collect_register_as_string (int n, char *buf);
void collect_register_by_name (const char *name, void *buf);
#endif /* REGCACHE_H */

View file

@ -42,6 +42,10 @@ struct ui_file *gdb_stdlog;
static int remote_desc;
/* FIXME headerize? */
extern int using_threads;
extern int debug_threads;
/* Open a connection to a remote debugger.
NAME is the filename used for communication. */
@ -296,10 +300,17 @@ putpkt (char *buf)
}
if (remote_debug)
printf ("putpkt (\"%s\"); [looking for ack]\n", buf2);
{
fprintf (stderr, "putpkt (\"%s\"); [looking for ack]\n", buf2);
fflush (stderr);
}
cc = read (remote_desc, buf3, 1);
if (remote_debug)
printf ("[received '%c' (0x%x)]\n", buf3[0], buf3[0]);
{
fprintf (stderr, "[received '%c' (0x%x)]\n", buf3[0], buf3[0]);
fflush (stderr);
}
if (cc <= 0)
{
if (cc == 0)
@ -310,6 +321,10 @@ putpkt (char *buf)
free (buf2);
return -1;
}
/* Check for an input interrupt while we're here. */
if (buf3[0] == '\003')
kill ((*the_target->signal_pid) (), SIGINT);
}
while (buf3[0] != '+');
@ -346,7 +361,7 @@ input_interrupt (int unused)
return;
}
kill (signal_pid, SIGINT);
kill ((*the_target->signal_pid) (), SIGINT);
}
}
@ -411,7 +426,11 @@ getpkt (char *buf)
if (c == '$')
break;
if (remote_debug)
printf ("[getpkt: discarding char '%c']\n", c);
{
fprintf (stderr, "[getpkt: discarding char '%c']\n", c);
fflush (stderr);
}
if (c < 0)
return -1;
}
@ -441,12 +460,19 @@ getpkt (char *buf)
}
if (remote_debug)
printf ("getpkt (\"%s\"); [sending ack] \n", buf);
{
fprintf (stderr, "getpkt (\"%s\"); [sending ack] \n", buf);
fflush (stderr);
}
write (remote_desc, "+", 1);
if (remote_debug)
printf ("[sent ack]\n");
{
fprintf (stderr, "[sent ack]\n");
fflush (stderr);
}
return bp - buf;
}
@ -499,8 +525,6 @@ convert_ascii_to_int (char *from, char *to, int n)
static char *
outreg (int regno, char *buf)
{
int regsize = register_size (regno);
if ((regno >> 12) != 0)
*buf++ = tohex ((regno >> 12) & 0xf);
if ((regno >> 8) != 0)
@ -508,13 +532,46 @@ outreg (int regno, char *buf)
*buf++ = tohex ((regno >> 4) & 0xf);
*buf++ = tohex (regno & 0xf);
*buf++ = ':';
convert_int_to_ascii (register_data (regno), buf, regsize);
buf += 2 * regsize;
collect_register_as_string (regno, buf);
buf += 2 * register_size (regno);
*buf++ = ';';
return buf;
}
void
new_thread_notify (int id)
{
char own_buf[256];
/* The `n' response is not yet part of the remote protocol. Do nothing. */
if (1)
return;
if (server_waiting == 0)
return;
sprintf (own_buf, "n%x", id);
disable_async_io ();
putpkt (own_buf);
enable_async_io ();
}
void
dead_thread_notify (int id)
{
char own_buf[256];
/* The `x' response is not yet part of the remote protocol. Do nothing. */
if (1)
return;
sprintf (own_buf, "x%x", id);
disable_async_io ();
putpkt (own_buf);
enable_async_io ();
}
void
prepare_resume_reply (char *buf, char status, unsigned char signo)
{
@ -538,12 +595,23 @@ prepare_resume_reply (char *buf, char status, unsigned char signo)
regp ++;
}
/* If the debugger hasn't used any thread features, don't burden it with
threads. If we didn't check this, GDB 4.13 and older would choke. */
if (cont_thread != 0)
/* Formerly, if the debugger had not used any thread features we would not
burden it with a thread status response. This was for the benefit of
GDB 4.13 and older. However, in recent GDB versions the check
(``if (cont_thread != 0)'') does not have the desired effect because of
sillyness in the way that the remote protocol handles specifying a thread.
Since thread support relies on qSymbol support anyway, assume GDB can handle
threads. */
if (using_threads)
{
/* FIXME right place to set this? */
thread_from_wait = ((struct inferior_list_entry *)current_inferior)->id;
if (debug_threads)
fprintf (stderr, "Writing resume reply for %d\n\n", thread_from_wait);
if (old_thread_from_wait != thread_from_wait)
{
general_thread = thread_from_wait;
sprintf (buf, "thread:%x;", thread_from_wait);
buf += strlen (buf);
old_thread_from_wait = thread_from_wait;
@ -620,7 +688,11 @@ look_up_one_symbol (const char *name, CORE_ADDR *addrp)
{
/* Malformed response. */
if (remote_debug)
fprintf (stderr, "Malformed response to qSymbol, ignoring.\n");
{
fprintf (stderr, "Malformed response to qSymbol, ignoring.\n");
fflush (stderr);
}
return -1;
}

View file

@ -23,9 +23,12 @@
int cont_thread;
int general_thread;
int step_thread;
int thread_from_wait;
int old_thread_from_wait;
int extended_protocol;
int server_waiting;
jmp_buf toplevel;
static unsigned char
@ -33,11 +36,12 @@ start_inferior (char *argv[], char *statusptr)
{
/* FIXME Check error? Or turn to void. */
create_inferior (argv[0], argv);
/* FIXME Print pid properly. */
fprintf (stderr, "Process %s created; pid = %d\n", argv[0], signal_pid);
fprintf (stderr, "Process %s created; pid = %d\n", argv[0],
all_threads.head->id);
/* Wait till we are at 1st instruction in program, return signal number. */
return mywait (statusptr);
return mywait (statusptr, 0);
}
static int
@ -48,7 +52,7 @@ attach_inferior (int pid, char *statusptr, unsigned char *sigptr)
if (myattach (pid) != 0)
return -1;
*sigptr = mywait (statusptr);
*sigptr = mywait (statusptr, 0);
return 0;
}
@ -59,6 +63,8 @@ extern int remote_debug;
void
handle_query (char *own_buf)
{
static struct inferior_list_entry *thread_ptr;
if (strcmp ("qSymbol::", own_buf) == 0)
{
if (the_target->look_up_symbols != NULL)
@ -68,6 +74,29 @@ handle_query (char *own_buf)
return;
}
if (strcmp ("qfThreadInfo", own_buf) == 0)
{
thread_ptr = all_threads.head;
sprintf (own_buf, "m%x", thread_ptr->id);
thread_ptr = thread_ptr->next;
return;
}
if (strcmp ("qsThreadInfo", own_buf) == 0)
{
if (thread_ptr != NULL)
{
sprintf (own_buf, "m%x", thread_ptr->id);
thread_ptr = thread_ptr->next;
return;
}
else
{
sprintf (own_buf, "l");
return;
}
}
/* Otherwise we didn't know what packet it was. Say we didn't
understand it. */
own_buf[0] = 0;
@ -188,12 +217,16 @@ main (int argc, char *argv[])
case 'g':
general_thread = strtol (&own_buf[2], NULL, 16);
write_ok (own_buf);
fetch_inferior_registers (0);
set_desired_inferior (1);
break;
case 'c':
cont_thread = strtol (&own_buf[2], NULL, 16);
write_ok (own_buf);
break;
case 's':
step_thread = strtol (&own_buf[2], NULL, 16);
write_ok (own_buf);
break;
default:
/* Silently ignore it so that gdb can extend the protocol
without compatibility headaches. */
@ -202,11 +235,12 @@ main (int argc, char *argv[])
}
break;
case 'g':
set_desired_inferior (1);
registers_to_string (own_buf);
break;
case 'G':
set_desired_inferior (1);
registers_from_string (&own_buf[1]);
store_inferior_registers (-1);
write_ok (own_buf);
break;
case 'm':
@ -227,8 +261,9 @@ main (int argc, char *argv[])
signal = target_signal_to_host (sig);
else
signal = 0;
set_desired_inferior (0);
myresume (0, signal);
signal = mywait (&status);
signal = mywait (&status, 1);
prepare_resume_reply (own_buf, status, signal);
break;
case 'S':
@ -237,18 +272,21 @@ main (int argc, char *argv[])
signal = target_signal_to_host (sig);
else
signal = 0;
set_desired_inferior (0);
myresume (1, signal);
signal = mywait (&status);
signal = mywait (&status, 1);
prepare_resume_reply (own_buf, status, signal);
break;
case 'c':
set_desired_inferior (0);
myresume (0, 0);
signal = mywait (&status);
signal = mywait (&status, 1);
prepare_resume_reply (own_buf, status, signal);
break;
case 's':
set_desired_inferior (0);
myresume (1, 0);
signal = mywait (&status);
signal = mywait (&status, 1);
prepare_resume_reply (own_buf, status, signal);
break;
case 'k':

View file

@ -54,8 +54,21 @@
least the size of a (void *). */
typedef long long CORE_ADDR;
/* Opaque inferior process information. */
struct inferior_info;
/* Generic information for tracking a list of ``inferiors'' - threads,
processes, etc. */
struct inferior_list
{
struct inferior_list_entry *head;
struct inferior_list_entry *tail;
};
struct inferior_list_entry
{
int id;
struct inferior_list_entry *next;
};
/* Opaque type for user-visible threads. */
struct thread_info;
#include "regcache.h"
#include "gdb/signals.h"
@ -67,27 +80,41 @@ struct inferior_info;
void initialize_low ();
/* Target-specific variables */
extern char *registers;
/* From inferiors.c. */
extern struct inferior_info *current_inferior;
extern int signal_pid;
void add_inferior (int pid);
extern struct inferior_list all_threads;
void add_inferior_to_list (struct inferior_list *list,
struct inferior_list_entry *new_inferior);
void for_each_inferior (struct inferior_list *list,
void (*action) (struct inferior_list_entry *));
extern struct thread_info *current_inferior;
void remove_inferior (struct inferior_list *list,
struct inferior_list_entry *entry);
void remove_thread (struct thread_info *thread);
void add_thread (int thread_id, void *target_data);
void clear_inferiors (void);
void *inferior_target_data (struct inferior_info *);
void set_inferior_target_data (struct inferior_info *, void *);
void *inferior_regcache_data (struct inferior_info *);
void set_inferior_regcache_data (struct inferior_info *, void *);
struct inferior_list_entry *find_inferior
(struct inferior_list *,
int (*func) (struct inferior_list_entry *,
void *),
void *arg);
struct inferior_list_entry *find_inferior_id (struct inferior_list *list,
int id);
void *inferior_target_data (struct thread_info *);
void set_inferior_target_data (struct thread_info *, void *);
void *inferior_regcache_data (struct thread_info *);
void set_inferior_regcache_data (struct thread_info *, void *);
void change_inferior_id (struct inferior_list *list,
int new_id);
/* Public variables in server.c */
extern int cont_thread;
extern int general_thread;
extern int step_thread;
extern int thread_from_wait;
extern int old_thread_from_wait;
extern int server_waiting;
extern jmp_buf toplevel;
@ -103,6 +130,8 @@ void enable_async_io (void);
void disable_async_io (void);
void convert_ascii_to_int (char *from, char *to, int n);
void convert_int_to_ascii (char *from, char *to, int n);
void new_thread_notify (int id);
void dead_thread_notify (int id);
void prepare_resume_reply (char *buf, char status, unsigned char sig);
void decode_m_packet (char *from, CORE_ADDR * mem_addr_ptr,

View file

@ -25,6 +25,38 @@
struct target_ops *the_target;
void
set_desired_inferior (int use_general)
{
struct thread_info *found;
if (use_general == 1)
{
found = (struct thread_info *) find_inferior_id (&all_threads,
general_thread);
}
else
{
found = NULL;
/* If we are continuing any (all) thread(s), use step_thread
to decide which thread to step and/or send the specified
signal to. */
if (step_thread > 0 && (cont_thread == 0 || cont_thread == -1))
found = (struct thread_info *) find_inferior_id (&all_threads,
step_thread);
if (found == NULL)
found = (struct thread_info *) find_inferior_id (&all_threads,
cont_thread);
}
if (found == NULL)
current_inferior = (struct thread_info *) all_threads.head;
else
current_inferior = found;
}
void
read_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len)
{
@ -33,10 +65,41 @@ read_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len)
}
int
write_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len)
write_inferior_memory (CORE_ADDR memaddr, const char *myaddr, int len)
{
check_mem_write (memaddr, myaddr, len);
return (*the_target->write_memory) (memaddr, myaddr, len);
/* Lacking cleanups, there is some potential for a memory leak if the
write fails and we go through error(). Make sure that no more than
one buffer is ever pending by making BUFFER static. */
static char *buffer = 0;
int res;
if (buffer != NULL)
free (buffer);
buffer = malloc (len);
memcpy (buffer, myaddr, len);
check_mem_write (memaddr, buffer, len);
res = (*the_target->write_memory) (memaddr, buffer, len);
free (buffer);
buffer = NULL;
return res;
}
unsigned char
mywait (char *statusp, int connected_wait)
{
unsigned char ret;
if (connected_wait)
server_waiting = 1;
ret = (*the_target->wait) (statusp);
if (connected_wait)
server_waiting = 0;
return ret;
}
void

View file

@ -104,6 +104,11 @@ struct target_ops
symbols. */
void (*look_up_symbols) (void);
/* Return the PID we should send a signal to. Used for asynchronous
interrupts (user hitting Control-C). */
int (*signal_pid) (void);
};
extern struct target_ops *the_target;
@ -125,17 +130,18 @@ void set_target_ops (struct target_ops *);
#define myresume(step,signo) \
(*the_target->resume) (step, signo)
#define mywait(statusp) \
(*the_target->wait) (statusp)
#define fetch_inferior_registers(regno) \
(*the_target->fetch_registers) (regno)
#define store_inferior_registers(regno) \
(*the_target->store_registers) (regno)
unsigned char mywait (char *statusp, int connected_wait);
void read_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len);
int write_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len);
int write_inferior_memory (CORE_ADDR memaddr, const char *myaddr, int len);
void set_desired_inferior (int id);
#endif /* TARGET_H */

342
gdb/gdbserver/thread-db.c Normal file
View file

@ -0,0 +1,342 @@
/* Thread management interface, for the remote server for GDB.
Copyright 2002
Free Software Foundation, Inc.
Contributed by MontaVista Software.
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 2 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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
#include "server.h"
#include "linux-low.h"
extern int debug_threads;
#ifdef HAVE_THREAD_DB_H
#include <thread_db.h>
#endif
/* Correct for all GNU/Linux targets (for quite some time). */
#define GDB_GREGSET_T elf_gregset_t
#define GDB_FPREGSET_T elf_fpregset_t
#ifndef HAVE_ELF_FPREGSET_T
/* Make sure we have said types. Not all platforms bring in <linux/elf.h>
via <sys/procfs.h>. */
#ifdef HAVE_LINUX_ELF_H
#include <linux/elf.h>
#endif
#endif
#include "../gdb_proc_service.h"
/* Structure that identifies the child process for the
<proc_service.h> interface. */
static struct ps_prochandle proc_handle;
/* Connection to the libthread_db library. */
static td_thragent_t *thread_agent;
static int find_new_threads_callback (const td_thrhandle_t *th_p, void *data);
static 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";
default:
snprintf (buf, sizeof (buf), "unknown thread_db error '%d'", err);
return buf;
}
}
#if 0
static char *
thread_db_state_str (td_thr_state_e state)
{
static char buf[64];
switch (state)
{
case TD_THR_STOPPED:
return "stopped by debugger";
case TD_THR_RUN:
return "runnable";
case TD_THR_ACTIVE:
return "active";
case TD_THR_ZOMBIE:
return "zombie";
case TD_THR_SLEEP:
return "sleeping";
case TD_THR_STOPPED_ASLEEP:
return "stopped by debugger AND blocked";
default:
snprintf (buf, sizeof (buf), "unknown thread_db state %d", state);
return buf;
}
}
#endif
static void
thread_db_create_event (CORE_ADDR where)
{
td_event_msg_t msg;
td_err_e err;
struct inferior_linux_data *tdata;
if (debug_threads)
fprintf (stderr, "Thread creation event.\n");
tdata = inferior_target_data (current_inferior);
/* FIXME: This assumes we don't get another event.
In the LinuxThreads implementation, this is safe,
because all events come from the manager thread
(except for its own creation, of course). */
err = td_ta_event_getmsg (thread_agent, &msg);
if (err != TD_OK)
fprintf (stderr, "thread getmsg err: %s\n",
thread_db_err_str (err));
/* msg.event == TD_EVENT_CREATE */
find_new_threads_callback (msg.th_p, NULL);
}
#if 0
static void
thread_db_death_event (CORE_ADDR where)
{
if (debug_threads)
fprintf (stderr, "Thread death event.\n");
}
#endif
static int
thread_db_enable_reporting ()
{
td_thr_events_t events;
td_notify_t notify;
td_err_e err;
/* Set the process wide mask saying which events we're interested in. */
td_event_emptyset (&events);
td_event_addset (&events, TD_CREATE);
#if 0
/* 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 (thread_agent, &events);
if (err != TD_OK)
{
warning ("Unable to set global thread event mask: %s",
thread_db_err_str (err));
return 0;
}
/* Get address for thread creation breakpoint. */
err = td_ta_event_addr (thread_agent, TD_CREATE, &notify);
if (err != TD_OK)
{
warning ("Unable to get location for thread creation breakpoint: %s",
thread_db_err_str (err));
return 0;
}
set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
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 (thread_agent, TD_DEATH, &notify);
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;
}
static void
maybe_attach_thread (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p)
{
td_err_e err;
struct thread_info *inferior;
struct process_info *process;
/* If we are attaching to our first thread, things are a little
different. */
if (all_threads.head == all_threads.tail)
{
inferior = (struct thread_info *) all_threads.head;
process = get_thread_process (inferior);
if (process->thread_known == 0)
{
/* Switch to indexing the threads list by TID. */
change_inferior_id (&all_threads, ti_p->ti_tid);
goto found;
}
}
inferior = (struct thread_info *) find_inferior_id (&all_threads,
ti_p->ti_tid);
if (inferior != NULL)
return;
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, ti_p->ti_tid);
inferior = (struct thread_info *) find_inferior_id (&all_threads,
ti_p->ti_tid);
if (inferior == NULL)
{
warning ("Could not attach to thread %ld (LWP %d)\n",
ti_p->ti_tid, ti_p->ti_lid);
return;
}
process = inferior_target_data (inferior);
found:
new_thread_notify (ti_p->ti_tid);
process->tid = ti_p->ti_tid;
process->lwpid = ti_p->ti_lid;
process->thread_known = 1;
err = td_thr_event_enable (th_p, 1);
if (err != TD_OK)
error ("Cannot enable thread event reporting for %d: %s",
ti_p->ti_lid, thread_db_err_str (err));
}
static int
find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
{
td_thrinfo_t ti;
td_err_e err;
err = td_thr_get_info (th_p, &ti);
if (err != TD_OK)
error ("Cannot get thread info: %s", thread_db_err_str (err));
/* Check for zombies. */
if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE)
return 0;
maybe_attach_thread (th_p, &ti);
return 0;
}
static void
thread_db_find_new_threads (void)
{
td_err_e err;
/* Iterate over all user-space threads to discover new threads. */
err = td_ta_thr_iter (thread_agent, find_new_threads_callback, NULL,
TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
if (err != TD_OK)
error ("Cannot find new threads: %s", thread_db_err_str (err));
}
int
thread_db_init ()
{
int err;
proc_handle.pid = ((struct inferior_list_entry *)current_inferior)->id;
err = td_ta_new (&proc_handle, &thread_agent);
switch (err)
{
case TD_NOLIBTHREAD:
/* No thread library was detected. */
return 0;
case TD_OK:
/* The thread library was detected. */
if (thread_db_enable_reporting () == 0)
return 0;
thread_db_find_new_threads ();
return 1;
default:
warning ("error initializing thread_db library.");
}
return 0;
}