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:
parent
cef717dccf
commit
0d62e5e807
28 changed files with 2700 additions and 344 deletions
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
41
gdb/gdbserver/acinclude.m4
Normal file
41
gdb/gdbserver/acinclude.m4
Normal 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"
|
||||
]])
|
||||
)])
|
124
gdb/gdbserver/aclocal.m4
vendored
124
gdb/gdbserver/aclocal.m4
vendored
|
@ -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"
|
||||
]])
|
||||
)])
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
422
gdb/gdbserver/configure
vendored
422
gdb/gdbserver/configure
vendored
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
|
|
@ -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 = {
|
||||
|
|
256
gdb/gdbserver/proc-service.c
Normal file
256
gdb/gdbserver/proc-service.c
Normal 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;
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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':
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
342
gdb/gdbserver/thread-db.c
Normal 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, ¬ify);
|
||||
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, ¬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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
Loading…
Reference in a new issue