summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElena Zannoni <ezannoni@kwikemart.cygnus.com>2004-03-23 20:28:36 +0000
committerElena Zannoni <ezannoni@kwikemart.cygnus.com>2004-03-23 20:28:36 +0000
commit6301c13d9ebeab1b0470573b530fb181ad11526c (patch)
treee46e9991750068189857dc1e432efbf18c0a59ac
parent090f1b49a6217b8f868084445df428fcf7ca0e35 (diff)
downloadbinutils-gdb-6301c13d9ebeab1b0470573b530fb181ad11526c.tar.gz
merge mainline chenges into branch
-rw-r--r--gdb/gdbserver/ChangeLog116
-rw-r--r--gdb/gdbserver/Makefile.in10
-rw-r--r--gdb/gdbserver/gdbreplay.c2
-rw-r--r--gdb/gdbserver/linux-arm-low.c6
-rw-r--r--gdb/gdbserver/linux-low.c211
-rw-r--r--gdb/gdbserver/linux-low.h8
-rw-r--r--gdb/gdbserver/linux-s390-low.c10
-rw-r--r--gdb/gdbserver/regcache.c7
-rw-r--r--gdb/gdbserver/remote-utils.c33
-rw-r--r--gdb/gdbserver/server.c195
-rw-r--r--gdb/gdbserver/server.h4
-rw-r--r--gdb/gdbserver/target.c8
-rw-r--r--gdb/gdbserver/target.h49
-rw-r--r--gdb/gdbserver/utils.c2
14 files changed, 580 insertions, 81 deletions
diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index 42dab168db6..e718fa65e61 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -1,3 +1,114 @@
+2004-03-12 Daniel Jacobowitz <drow@mvista.com>
+
+ * linux-low.c: Include <errno.h>. Remove extern declaration of
+ errno.
+
+2004-03-12 Daniel Jacobowitz <drow@mvista.com>
+
+ * gdbreplay.c, server.h, utils.c: Update copyright years.
+
+2004-03-04 Nathan J. Williams <nathanw@wasabisystems.com>
+
+ * server.c (main): Print child status or termination signal from
+ variable 'signal', not 'sig'.
+
+2004-03-04 Nathan J. Williams <nathanw@wasabisystems.com>
+
+ * linux-low.c (linux_read_memory): Change return type to
+ int. Check for and return error from ptrace().
+ * target.c (read_inferior_memory): Change return type to int. Pass
+ back return status from the_target->read_memory().
+ * target.h (struct target_ops): Adapt *read_memory() prototype.
+ Update comment.
+ (read_inferior_memory): Adapt prototype.
+ * server.c (main): Return an error packet if
+ read_inferior_memory() returns an error.
+
+2004-03-04 Daniel Jacobowitz <drow@mvista.com>
+
+ * Makefile.in (distclean): Remove config.h, stamp-h, and config.log.
+ Unify with other clean targets.
+
+2004-02-29 Daniel Jacobowitz <drow@mvista.com>
+
+ * server.c (handle_v_cont): Call set_desired_inferior.
+
+2004-02-29 Daniel Jacobowitz <drow@mvista.com>
+
+ * remote-utils.c (prepare_resume_reply): Always supply "thread:".
+
+2004-02-29 Daniel Jacobowitz <drow@mvista.com>
+
+ * linux-low.c (linux_wait): Unblock async I/O.
+ (linux_resume): Block and enable async I/O.
+ * remote-utils.c (block_async_io, unblock_async_io): New functions.
+ * server.h (block_async_io, unblock_async_io): Add prototypes.
+
+2004-02-29 Daniel Jacobowitz <drow@mvista.com>
+
+ * remote-utils.c (remote_open): Print a status notice after
+ opening a TCP port.
+ * server.c (attach_inferior): Print a status notice after
+ attaching.
+
+2004-02-29 Daniel Jacobowitz <drow@mvista.com>
+
+ * linux-arm-low.c (arm_get_pc): Print out stop PC in debug mode.
+
+2004-02-26 Daniel Jacobowitz <drow@mvista.com>
+
+ * remote-utils.c (write_enn): Use "E01" instead of "ENN" for the
+ error packet.
+ * server.c, target.h: Update copyright years.
+
+2004-02-25 Roland McGrath <roland@redhat.com>
+
+ * target.h (struct target_ops): New member `read_auxv'.
+ * server.c (handle_query): Handle qPart:auxv:read: query using that.
+ * linux-low.c (linux_read_auxv): New function.
+ (linux_target_ops): Initialize `read_auxv' member to that.
+
+2004-02-17 Ulrich Weigand <Ulrich.Weigand@de.ibm.com>
+
+ Committed by Jim Blandy <jimb@redhat.com>.
+
+ * linux-s390-low.c (s390_num_regs): Update.
+ (s390_regmap): Remove control registers. Use __s390x__ predefine
+ instead of GPR_SIZE to distiguish s390 and s390x targets.
+
+2004-01-31 Daniel Jacobowitz <drow@mvista.com>
+
+ * linux-low.c: Update copyright year.
+ (check_removed_breakpoint): Clear pending_is_breakpoint.
+ (linux_set_resume_request, linux_queue_one_thread)
+ (resume_status_pending_p): New functions.
+ (linux_continue_one_thread): Use process->resume.
+ (linux_resume): Only resume threads if there are no pending events.
+ * linux-low.h (struct process_info): Add resume request
+ pointer.
+
+2004-01-30 Daniel Jacobowitz <drow@mvista.com>
+
+ * regcache.c (new_register_cache): Clear the allocated register
+ buffer. Suggested by Atsushi Nemoto <anemo@mba.ocn.ne.jp>.
+
+2003-10-13 Daniel Jacobowitz <drow@mvista.com>
+
+ * linux-low.c (linux_resume): Take a struct thread_resume *
+ argument.
+ (linux_wait): Update call.
+ (resume_ptr): New static variable.
+ (linux_continue_one_thread): Renamed from
+ linux_continue_one_process. Use resume_ptr.
+ (linux_resume): Use linux_continue_one_thread.
+ * server.c (handle_v_cont, handle_v_requests): New functions.
+ (myresume): New function.
+ (main): Handle 'v' case.
+ * target.h (struct thread_resume): New type.
+ (struct target_ops): Change argument of "resume" to struct
+ thread_resume *.
+ (myresume): Delete macro.
+
2003-08-08 H.J. Lu <hongjiu.lu@intel.com>
* Makefile.in (install-only): Create dest dir. Support DESTDIR.
@@ -112,7 +223,7 @@ Mon Jul 21 20:09:34 UTC 2003 Brendan Conoboy <blc@redhat.com>
for create_inferior.
* server.c (signal_pid): New variable.
(create_inferior): Set signal_pid. Block SIGTTOU and SIGTTIN in
- gdbserver. Set the child to be the foreground process group.
+ gdbserver. Set the child to be the foreground process group.
(attach_inferior): Set signal_pid.
2002-08-23 Daniel Jacobowitz <drow@mvista.com>
@@ -141,7 +252,7 @@ Mon Jul 21 20:09:34 UTC 2003 Brendan Conoboy <blc@redhat.com>
2002-07-04 Michal Ludvig <mludvig@suse.cz>
- * linux-x86-64-low.c (x86_64_regmap): Make it an array of
+ * linux-x86-64-low.c (x86_64_regmap): Make it an array of
byte offsets instead of an array of indexes.
(x86_64_store_gregset, x86_64_store_fpregset): Parameter made const.
@@ -526,4 +637,3 @@ Mon Jul 21 20:09:34 UTC 2003 Brendan Conoboy <blc@redhat.com>
* server.h: Add ATTR_NORETURN and ATTR_FORMAT. Update prototypes.
* utils.c (error): Remove NORETURN.
(fatal): Likewise.
-
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 8554dae9afb..3af7eb46180 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -1,5 +1,5 @@
# Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-# 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+# 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
# This file is part of GDB.
@@ -200,12 +200,8 @@ clean:
rm -f reg-arm.c reg-i386.c reg-ia64.c reg-m68k.c reg-mips.c
rm -f reg-ppc.c reg-sh.c reg-x86-64.c reg-i386-linux.c
-distclean: clean
- rm -f nm.h tm.h xm.h config.status
- rm -f Makefile
-
-maintainer-clean realclean: clean
- rm -f nm.h tm.h xm.h config.status
+maintainer-clean realclean distclean: clean
+ rm -f nm.h tm.h xm.h config.status config.h stamp-h config.log
rm -f Makefile
STAGESTUFF=${OBS} ${TSOBS} ${NTSOBS} ${ADD_FILES} init.c init.o version.c gdb
diff --git a/gdb/gdbserver/gdbreplay.c b/gdb/gdbserver/gdbreplay.c
index ec7a2b851fa..7c9064bf2d7 100644
--- a/gdb/gdbserver/gdbreplay.c
+++ b/gdb/gdbserver/gdbreplay.c
@@ -1,5 +1,5 @@
/* Replay a remote debug session logfile for GDB.
- Copyright 1996, 1998, 1999, 2000 Free Software Foundation, Inc.
+ Copyright 1996, 1998, 1999, 2000, 2002, 2003 Free Software Foundation, Inc.
Written by Fred Fish (fnf@cygnus.com) from pieces of gdbserver.
This file is part of GDB.
diff --git a/gdb/gdbserver/linux-arm-low.c b/gdb/gdbserver/linux-arm-low.c
index 2e8bb981b52..f091a3dccc3 100644
--- a/gdb/gdbserver/linux-arm-low.c
+++ b/gdb/gdbserver/linux-arm-low.c
@@ -1,5 +1,5 @@
/* GNU/Linux/ARM specific low level interface, for the remote server for GDB.
- Copyright 1995, 1996, 1998, 1999, 2000, 2001, 2002
+ Copyright 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004
Free Software Foundation, Inc.
This file is part of GDB.
@@ -47,11 +47,15 @@ arm_cannot_fetch_register (int regno)
return (regno >= arm_num_regs);
}
+extern int debug_threads;
+
static CORE_ADDR
arm_get_pc ()
{
unsigned long pc;
collect_register_by_name ("pc", &pc);
+ if (debug_threads)
+ fprintf (stderr, "stop pc is %08lx\n", pc);
return pc;
}
diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c
index 55c187c1bd5..a3d6a54d9cf 100644
--- a/gdb/gdbserver/linux-low.c
+++ b/gdb/gdbserver/linux-low.c
@@ -1,5 +1,5 @@
/* Low level interface to ptrace, for the remote server for GDB.
- Copyright 1995, 1996, 1998, 1999, 2000, 2001, 2002
+ Copyright 1995, 1996, 1998, 1999, 2000, 2001, 2002, 2003, 2004
Free Software Foundation, Inc.
This file is part of GDB.
@@ -34,6 +34,7 @@
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
+#include <errno.h>
/* ``all_threads'' is keyed by the LWP ID - it should be the thread ID instead,
however. This requires changing the ID in place when we go from !using_threads
@@ -52,7 +53,7 @@ int using_threads;
static void linux_resume_one_process (struct inferior_list_entry *entry,
int step, int signal);
-static void linux_resume (int step, int signal);
+static void linux_resume (struct thread_resume *resume_info);
static void stop_all_processes (void);
static int linux_wait_for_event (struct thread_info *child);
@@ -69,8 +70,6 @@ struct pending_signals
static int use_regsets_p = 1;
#endif
-extern int errno;
-
int debug_threads = 0;
#define pid_of(proc) ((proc)->head.id)
@@ -316,6 +315,7 @@ check_removed_breakpoint (struct process_info *event_child)
(*the_low_target.set_pc) (stop_pc);
/* We consumed the pending SIGTRAP. */
+ event_child->pending_is_breakpoint = 0;
event_child->status_pending_p = 0;
event_child->status_pending = 0;
@@ -596,7 +596,7 @@ linux_wait_for_event (struct thread_info *child)
/* If we were single-stepping, we definitely want to report the
SIGTRAP. The single-step operation has completed, so also
- clear the stepping flag; in general this does not matter,
+ clear the stepping flag; in general this does not matter,
because the SIGTRAP will be reported to the client, which
will give us a new action for this thread, but clear it for
consistency anyway. It's safe to clear the stepping flag
@@ -652,10 +652,16 @@ retry:
/* No stepping, no signal - unless one is pending already, of course. */
if (child == NULL)
- linux_resume (0, 0);
+ {
+ struct thread_resume resume_info;
+ resume_info.thread = -1;
+ resume_info.step = resume_info.sig = resume_info.leave_stopped = 0;
+ linux_resume (&resume_info);
+ }
}
enable_async_io ();
+ unblock_async_io ();
w = linux_wait_for_event (child);
stop_all_processes ();
disable_async_io ();
@@ -835,7 +841,7 @@ linux_resume_one_process (struct inferior_list_entry *entry,
check_removed_breakpoint (process);
- if (debug_threads && the_low_target.get_pc != NULL)
+ if (debug_threads && the_low_target.get_pc != NULL)
{
fprintf (stderr, " ");
(long) (*the_low_target.get_pc) ();
@@ -868,33 +874,154 @@ linux_resume_one_process (struct inferior_list_entry *entry,
perror_with_name ("ptrace");
}
-/* This function is called once per process other than the first
- one. The first process we are told the signal to continue
- with, and whether to step or continue; for all others, any
- existing signals will be marked in status_pending_p to be
- reported momentarily, and we preserve the stepping flag. */
+static struct thread_resume *resume_ptr;
+
+/* This function is called once per thread. We look up the thread
+ in RESUME_PTR, and mark the thread with a pointer to the appropriate
+ resume request.
+
+ This algorithm is O(threads * resume elements), but resume elements
+ is small (and will remain small at least until GDB supports thread
+ suspension). */
static void
-linux_continue_one_process (struct inferior_list_entry *entry)
+linux_set_resume_request (struct inferior_list_entry *entry)
{
struct process_info *process;
+ struct thread_info *thread;
+ int ndx;
- process = (struct process_info *) entry;
- linux_resume_one_process (entry, process->stepping, 0);
+ thread = (struct thread_info *) entry;
+ process = get_thread_process (thread);
+
+ ndx = 0;
+ while (resume_ptr[ndx].thread != -1 && resume_ptr[ndx].thread != entry->id)
+ ndx++;
+
+ process->resume = &resume_ptr[ndx];
}
+/* This function is called once per thread. We check the thread's resume
+ request, which will tell us whether to resume, step, or leave the thread
+ stopped; and what signal, if any, it should be sent. For threads which
+ we aren't explicitly told otherwise, we preserve the stepping flag; this
+ is used for stepping over gdbserver-placed breakpoints. */
+
static void
-linux_resume (int step, int signal)
+linux_continue_one_thread (struct inferior_list_entry *entry)
{
struct process_info *process;
+ struct thread_info *thread;
+ int step;
+
+ thread = (struct thread_info *) entry;
+ process = get_thread_process (thread);
+
+ if (process->resume->leave_stopped)
+ return;
+
+ if (process->resume->thread == -1)
+ step = process->stepping || process->resume->step;
+ else
+ step = process->resume->step;
+
+ linux_resume_one_process (&process->head, step, process->resume->sig);
+
+ process->resume = NULL;
+}
+
+/* This function is called once per thread. We check the thread's resume
+ request, which will tell us whether to resume, step, or leave the thread
+ stopped; and what signal, if any, it should be sent. We queue any needed
+ signals, since we won't actually resume. We already have a pending event
+ to report, so we don't need to preserve any step requests; they should
+ be re-issued if necessary. */
+
+static void
+linux_queue_one_thread (struct inferior_list_entry *entry)
+{
+ struct process_info *process;
+ struct thread_info *thread;
+
+ thread = (struct thread_info *) entry;
+ process = get_thread_process (thread);
+
+ if (process->resume->leave_stopped)
+ return;
+
+ /* If we have a new signal, enqueue the signal. */
+ if (process->resume->sig != 0)
+ {
+ struct pending_signals *p_sig;
+ p_sig = malloc (sizeof (*p_sig));
+ p_sig->prev = process->pending_signals;
+ p_sig->signal = process->resume->sig;
+ process->pending_signals = p_sig;
+ }
+
+ process->resume = NULL;
+}
+
+/* Set DUMMY if this process has an interesting status pending. */
+static int
+resume_status_pending_p (struct inferior_list_entry *entry, void *flag_p)
+{
+ struct process_info *process = (struct process_info *) entry;
+
+ /* Processes which will not be resumed are not interesting, because
+ we might not wait for them next time through linux_wait. */
+ if (process->resume->leave_stopped)
+ return 0;
- process = get_thread_process (current_inferior);
+ /* If this thread has a removed breakpoint, we won't have any
+ events to report later, so check now. check_removed_breakpoint
+ may clear status_pending_p. We avoid calling check_removed_breakpoint
+ for any thread that we are not otherwise going to resume - this
+ lets us preserve stopped status when two threads hit a breakpoint.
+ GDB removes the breakpoint to single-step a particular thread
+ past it, then re-inserts it and resumes all threads. We want
+ to report the second thread without resuming it in the interim. */
+ if (process->status_pending_p)
+ check_removed_breakpoint (process);
+
+ if (process->status_pending_p)
+ * (int *) flag_p = 1;
+
+ return 0;
+}
+
+static void
+linux_resume (struct thread_resume *resume_info)
+{
+ int pending_flag;
+
+ /* Yes, the use of a global here is rather ugly. */
+ resume_ptr = resume_info;
- /* If the current process has a status pending, this signal will
- be enqueued and sent later. */
- linux_resume_one_process (&process->head, step, signal);
+ for_each_inferior (&all_threads, linux_set_resume_request);
- if (cont_thread == 0 || cont_thread == -1)
- for_each_inferior (&all_processes, linux_continue_one_process);
+ /* If there is a thread which would otherwise be resumed, which
+ has a pending status, then don't resume any threads - we can just
+ report the pending status. Make sure to queue any signals
+ that would otherwise be sent. */
+ pending_flag = 0;
+ find_inferior (&all_processes, resume_status_pending_p, &pending_flag);
+
+ if (debug_threads)
+ {
+ if (pending_flag)
+ fprintf (stderr, "Not resuming, pending status\n");
+ else
+ fprintf (stderr, "Resuming, no pending status\n");
+ }
+
+ if (pending_flag)
+ for_each_inferior (&all_threads, linux_queue_one_thread);
+ else
+ {
+ block_async_io ();
+ enable_async_io ();
+ for_each_inferior (&all_threads, linux_continue_one_thread);
+ }
}
#ifdef HAVE_LINUX_USRREGS
@@ -1153,28 +1280,33 @@ linux_store_registers (int regno)
/* Copy LEN bytes from inferior's memory starting at MEMADDR
to debugger memory starting at MYADDR. */
-static void
+static int
linux_read_memory (CORE_ADDR memaddr, char *myaddr, int len)
{
register int i;
/* Round starting address down to longword boundary. */
register CORE_ADDR addr = memaddr & -(CORE_ADDR) sizeof (PTRACE_XFER_TYPE);
/* Round ending address up; get number of longwords that makes. */
- register int count
- = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1)
+ register int count
+ = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1)
/ sizeof (PTRACE_XFER_TYPE);
/* Allocate buffer of that many longwords. */
- register PTRACE_XFER_TYPE *buffer
+ register PTRACE_XFER_TYPE *buffer
= (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE));
/* Read all the longwords */
for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE))
{
+ errno = 0;
buffer[i] = ptrace (PTRACE_PEEKTEXT, inferior_pid, (PTRACE_ARG3_TYPE) addr, 0);
+ if (errno)
+ return errno;
}
/* Copy appropriate bytes out of the buffer. */
memcpy (myaddr, (char *) buffer + (memaddr & (sizeof (PTRACE_XFER_TYPE) - 1)), len);
+
+ return 0;
}
/* Copy LEN bytes of data from debugger memory at MYADDR
@@ -1258,6 +1390,32 @@ linux_send_signal (int signum)
kill (signal_pid, signum);
}
+/* Copy LEN bytes from inferior's auxiliary vector starting at OFFSET
+ to debugger memory starting at MYADDR. */
+
+static int
+linux_read_auxv (CORE_ADDR offset, char *myaddr, unsigned int len)
+{
+ char filename[PATH_MAX];
+ int fd, n;
+
+ snprintf (filename, sizeof filename, "/proc/%d/auxv", inferior_pid);
+
+ fd = open (filename, O_RDONLY);
+ if (fd < 0)
+ return -1;
+
+ if (offset != (CORE_ADDR) 0
+ && lseek (fd, (off_t) offset, SEEK_SET) != (off_t) offset)
+ n = -1;
+ else
+ n = read (fd, myaddr, len);
+
+ close (fd);
+
+ return n;
+}
+
static struct target_ops linux_target_ops = {
linux_create_inferior,
@@ -1273,6 +1431,7 @@ static struct target_ops linux_target_ops = {
linux_write_memory,
linux_look_up_symbols,
linux_send_signal,
+ linux_read_auxv,
};
static void
diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h
index bae76b77bdc..d42c9b5b6ee 100644
--- a/gdb/gdbserver/linux-low.h
+++ b/gdb/gdbserver/linux-low.h
@@ -1,5 +1,5 @@
/* Internal interfaces for the GNU/Linux specific target code for gdbserver.
- Copyright 2002, Free Software Foundation, Inc.
+ Copyright 2002, 2004 Free Software Foundation, Inc.
This file is part of GDB.
@@ -106,7 +106,13 @@ struct process_info
/* 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;
+
+ /* A link used when resuming. It is initialized from the resume request,
+ and then processed and cleared in linux_resume_one_process. */
+
+ struct thread_resume *resume;
};
+
extern struct inferior_list all_processes;
void linux_attach_lwp (int pid, int tid);
diff --git a/gdb/gdbserver/linux-s390-low.c b/gdb/gdbserver/linux-s390-low.c
index 9213f68ef00..d1a94fb791b 100644
--- a/gdb/gdbserver/linux-s390-low.c
+++ b/gdb/gdbserver/linux-s390-low.c
@@ -27,7 +27,7 @@
#include <asm/ptrace.h>
-#define s390_num_regs 67
+#define s390_num_regs 51
static int s390_regmap[] = {
PT_PSWMASK, PT_PSWADDR,
@@ -42,15 +42,9 @@ static int s390_regmap[] = {
PT_ACR8, PT_ACR9, PT_ACR10, PT_ACR11,
PT_ACR12, PT_ACR13, PT_ACR14, PT_ACR15,
- -1, -1, -1, -1,
- -1, -1, -1, -1,
- -1, PT_CR_9, PT_CR_10, PT_CR_11,
- -1, -1, -1, -1,
-
PT_FPC,
-/* <asm/ptrace.h> defines GPR_SIZE. */
-#if GPR_SIZE == 4
+#ifndef __s390x__
PT_FPR0_HI, PT_FPR1_HI, PT_FPR2_HI, PT_FPR3_HI,
PT_FPR4_HI, PT_FPR5_HI, PT_FPR6_HI, PT_FPR7_HI,
PT_FPR8_HI, PT_FPR9_HI, PT_FPR10_HI, PT_FPR11_HI,
diff --git a/gdb/gdbserver/regcache.c b/gdb/gdbserver/regcache.c
index be3b3a7f33e..bc64ebcbb97 100644
--- a/gdb/gdbserver/regcache.c
+++ b/gdb/gdbserver/regcache.c
@@ -1,5 +1,5 @@
/* Register support routines for the remote server for GDB.
- Copyright 2001, 2002
+ Copyright 2001, 2002, 2004
Free Software Foundation, Inc.
This file is part of GDB.
@@ -101,7 +101,10 @@ new_register_cache (void)
regcache = malloc (sizeof (*regcache));
- regcache->registers = malloc (register_bytes);
+ /* Make sure to zero-initialize the register cache when it is created,
+ in case there are registers the target never fetches. This way they'll
+ read as zero instead of garbage. */
+ regcache->registers = calloc (1, register_bytes);
if (regcache->registers == NULL)
fatal ("Could not allocate register cache.");
diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c
index eb56c1039a8..26b267a3aaf 100644
--- a/gdb/gdbserver/remote-utils.c
+++ b/gdb/gdbserver/remote-utils.c
@@ -1,6 +1,6 @@
/* Remote utility routines for the remote server for GDB.
Copyright 1986, 1989, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001,
- 2002
+ 2002, 2003, 2004
Free Software Foundation, Inc.
This file is part of GDB.
@@ -135,6 +135,8 @@ remote_open (char *name)
|| listen (tmp_desc, 1))
perror_with_name ("Can't bind address");
+ fprintf (stderr, "Listening on port %d\n", port);
+
tmp = sizeof (sockaddr);
remote_desc = accept (tmp_desc, (struct sockaddr *) &sockaddr, &tmp);
if (remote_desc == -1)
@@ -366,6 +368,24 @@ input_interrupt (int unused)
}
void
+block_async_io (void)
+{
+ sigset_t sigio_set;
+ sigemptyset (&sigio_set);
+ sigaddset (&sigio_set, SIGIO);
+ sigprocmask (SIG_BLOCK, &sigio_set, NULL);
+}
+
+void
+unblock_async_io (void)
+{
+ sigset_t sigio_set;
+ sigemptyset (&sigio_set);
+ sigaddset (&sigio_set, SIGIO);
+ sigprocmask (SIG_UNBLOCK, &sigio_set, NULL);
+}
+
+void
enable_async_io (void)
{
signal (SIGIO, input_interrupt);
@@ -487,9 +507,10 @@ write_ok (char *buf)
void
write_enn (char *buf)
{
+ /* Some day, we should define the meanings of the error codes... */
buf[0] = 'E';
- buf[1] = 'N';
- buf[2] = 'N';
+ buf[1] = '0';
+ buf[2] = '1';
buf[3] = '\0';
}
@@ -609,7 +630,11 @@ prepare_resume_reply (char *buf, char status, unsigned char signo)
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)
+ /* This if (1) ought to be unnecessary. But remote_wait in GDB
+ will claim this event belongs to inferior_ptid if we do not
+ specify a thread, and there's no way for gdbserver to know
+ what inferior_ptid is. */
+ if (1 || old_thread_from_wait != thread_from_wait)
{
general_thread = thread_from_wait;
sprintf (buf, "thread:%x;", thread_from_wait);
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 81fde5b7f73..93e3ea431bb 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -1,5 +1,5 @@
/* Main code for remote server for GDB.
- Copyright 1989, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2002
+ Copyright 1989, 1993, 1994, 1995, 1997, 1998, 1999, 2000, 2002, 2003, 2004
Free Software Foundation, Inc.
This file is part of GDB.
@@ -70,6 +70,8 @@ attach_inferior (int pid, char *statusptr, unsigned char *sigptr)
if (myattach (pid) != 0)
return -1;
+ fprintf (stderr, "Attached; pid = %d\n", pid);
+
/* FIXME - It may be that we should get the SIGNAL_PID from the
attach function, so that it can be the main thread instead of
whichever we were told to attach to. */
@@ -104,7 +106,7 @@ handle_query (char *own_buf)
thread_ptr = thread_ptr->next;
return;
}
-
+
if (strcmp ("qsThreadInfo", own_buf) == 0)
{
if (thread_ptr != NULL)
@@ -119,10 +121,180 @@ handle_query (char *own_buf)
return;
}
}
-
+
+ if (the_target->read_auxv != NULL
+ && strncmp ("qPart:auxv:read::", own_buf, 17) == 0)
+ {
+ char data[(PBUFSIZ - 1) / 2];
+ CORE_ADDR ofs;
+ unsigned int len;
+ int n;
+ decode_m_packet (&own_buf[17], &ofs, &len); /* "OFS,LEN" */
+ if (len > sizeof data)
+ len = sizeof data;
+ n = (*the_target->read_auxv) (ofs, data, len);
+ if (n == 0)
+ write_ok (own_buf);
+ else if (n < 0)
+ write_enn (own_buf);
+ else
+ convert_int_to_ascii (data, own_buf, n);
+ return;
+ }
+
+ /* Otherwise we didn't know what packet it was. Say we didn't
+ understand it. */
+ own_buf[0] = 0;
+}
+
+/* Parse vCont packets. */
+void
+handle_v_cont (char *own_buf, char *status, unsigned char *signal)
+{
+ char *p, *q;
+ int n = 0, i = 0;
+ struct thread_resume *resume_info, default_action;
+
+ /* Count the number of semicolons in the packet. There should be one
+ for every action. */
+ p = &own_buf[5];
+ while (p)
+ {
+ n++;
+ p++;
+ p = strchr (p, ';');
+ }
+ /* Allocate room for one extra action, for the default remain-stopped
+ behavior; if no default action is in the list, we'll need the extra
+ slot. */
+ resume_info = malloc ((n + 1) * sizeof (resume_info[0]));
+
+ default_action.thread = -1;
+ default_action.leave_stopped = 1;
+ default_action.step = 0;
+ default_action.sig = 0;
+
+ p = &own_buf[5];
+ i = 0;
+ while (*p)
+ {
+ p++;
+
+ resume_info[i].leave_stopped = 0;
+
+ if (p[0] == 's' || p[0] == 'S')
+ resume_info[i].step = 1;
+ else if (p[0] == 'c' || p[0] == 'C')
+ resume_info[i].step = 0;
+ else
+ goto err;
+
+ if (p[0] == 'S' || p[0] == 'C')
+ {
+ int sig;
+ sig = strtol (p + 1, &q, 16);
+ if (p == q)
+ goto err;
+ p = q;
+
+ if (!target_signal_to_host_p (sig))
+ goto err;
+ resume_info[i].sig = target_signal_to_host (sig);
+ }
+ else
+ {
+ resume_info[i].sig = 0;
+ p = p + 1;
+ }
+
+ if (p[0] == 0)
+ {
+ resume_info[i].thread = -1;
+ default_action = resume_info[i];
+
+ /* Note: we don't increment i here, we'll overwrite this entry
+ the next time through. */
+ }
+ else if (p[0] == ':')
+ {
+ resume_info[i].thread = strtol (p + 1, &q, 16);
+ if (p == q)
+ goto err;
+ p = q;
+ if (p[0] != ';' && p[0] != 0)
+ goto err;
+
+ i++;
+ }
+ }
+
+ resume_info[i] = default_action;
+
+ /* Still used in occasional places in the backend. */
+ if (n == 1 && resume_info[0].thread != -1)
+ cont_thread = resume_info[0].thread;
+ else
+ cont_thread = -1;
+ set_desired_inferior (0);
+
+ (*the_target->resume) (resume_info);
+
+ free (resume_info);
+
+ *signal = mywait (status, 1);
+ prepare_resume_reply (own_buf, *status, *signal);
+ return;
+
+err:
+ /* No other way to report an error... */
+ strcpy (own_buf, "");
+ free (resume_info);
+ return;
+}
+
+/* Handle all of the extended 'v' packets. */
+void
+handle_v_requests (char *own_buf, char *status, unsigned char *signal)
+{
+ if (strncmp (own_buf, "vCont;", 6) == 0)
+ {
+ handle_v_cont (own_buf, status, signal);
+ return;
+ }
+
+ if (strncmp (own_buf, "vCont?", 6) == 0)
+ {
+ strcpy (own_buf, "vCont;c;C;s;S");
+ return;
+ }
+
/* Otherwise we didn't know what packet it was. Say we didn't
understand it. */
own_buf[0] = 0;
+ return;
+}
+
+void
+myresume (int step, int sig)
+{
+ struct thread_resume resume_info[2];
+ int n = 0;
+
+ if (step || sig || cont_thread > 0)
+ {
+ resume_info[0].thread
+ = ((struct inferior_list_entry *) current_inferior)->id;
+ resume_info[0].step = step;
+ resume_info[0].sig = sig;
+ resume_info[0].leave_stopped = 0;
+ n++;
+ }
+ resume_info[n].thread = -1;
+ resume_info[n].step = 0;
+ resume_info[n].sig = 0;
+ resume_info[n].leave_stopped = (cont_thread > 0);
+
+ (*the_target->resume) (resume_info);
}
static int attached;
@@ -222,7 +394,7 @@ main (int argc, char *argv[])
detach_inferior ();
write_ok (own_buf);
putpkt (own_buf);
- remote_close ();
+ remote_close ();
/* If we are attached, then we can exit. Otherwise, we need to
hang around doing nothing, until the child is gone. */
@@ -290,8 +462,10 @@ main (int argc, char *argv[])
break;
case 'm':
decode_m_packet (&own_buf[1], &mem_addr, &len);
- read_inferior_memory (mem_addr, mem_buf, len);
- convert_int_to_ascii (mem_buf, own_buf, len);
+ if (read_inferior_memory (mem_addr, mem_buf, len) == 0)
+ convert_int_to_ascii (mem_buf, own_buf, len);
+ else
+ write_enn (own_buf);
break;
case 'M':
decode_M_packet (&own_buf[1], &mem_addr, &len, mem_buf);
@@ -383,6 +557,10 @@ main (int argc, char *argv[])
own_buf[0] = '\0';
break;
}
+ case 'v':
+ /* Extended (long) request. */
+ handle_v_requests (own_buf, &status, &signal);
+ break;
default:
/* It is a request we don't understand. Respond with an
empty packet so that gdb knows that we don't support this
@@ -395,9 +573,10 @@ main (int argc, char *argv[])
if (status == 'W')
fprintf (stderr,
- "\nChild exited with status %d\n", sig);
+ "\nChild exited with status %d\n", signal);
if (status == 'X')
- fprintf (stderr, "\nChild terminated with signal = 0x%x\n", sig);
+ fprintf (stderr, "\nChild terminated with signal = 0x%x\n",
+ signal);
if (status == 'W' || status == 'X')
{
if (extended_protocol)
diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h
index 5212deb2c4a..59dbcf97e1c 100644
--- a/gdb/gdbserver/server.h
+++ b/gdb/gdbserver/server.h
@@ -1,5 +1,5 @@
/* Common definitions for remote server for GDB.
- Copyright 1993, 1995, 1997, 1998, 1999, 2000, 2002
+ Copyright 1993, 1995, 1997, 1998, 1999, 2000, 2002, 2003, 2004
Free Software Foundation, Inc.
This file is part of GDB.
@@ -134,6 +134,8 @@ void write_ok (char *buf);
void write_enn (char *buf);
void enable_async_io (void);
void disable_async_io (void);
+void unblock_async_io (void);
+void block_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);
diff --git a/gdb/gdbserver/target.c b/gdb/gdbserver/target.c
index 1c2860a11e9..2c60e1777da 100644
--- a/gdb/gdbserver/target.c
+++ b/gdb/gdbserver/target.c
@@ -1,5 +1,5 @@
/* Target operations for the remote server for GDB.
- Copyright 2002
+ Copyright 2002, 2004
Free Software Foundation, Inc.
Contributed by MontaVista Software.
@@ -57,11 +57,13 @@ set_desired_inferior (int use_general)
current_inferior = found;
}
-void
+int
read_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len)
{
- (*the_target->read_memory) (memaddr, myaddr, len);
+ int res;
+ res = (*the_target->read_memory) (memaddr, myaddr, len);
check_mem_read (memaddr, myaddr, len);
+ return res;
}
int
diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h
index 1c47a3aedb3..770ffcbbb05 100644
--- a/gdb/gdbserver/target.h
+++ b/gdb/gdbserver/target.h
@@ -1,5 +1,5 @@
/* Target operations for the remote server for GDB.
- Copyright 2002
+ Copyright 2002, 2003, 2004
Free Software Foundation, Inc.
Contributed by MontaVista Software.
@@ -24,6 +24,25 @@
#ifndef TARGET_H
#define TARGET_H
+/* This structure describes how to resume a particular thread (or
+ all threads) based on the client's request. If thread is -1, then
+ this entry applies to all threads. These are generally passed around
+ as an array, and terminated by a thread == -1 entry. */
+
+struct thread_resume
+{
+ int thread;
+
+ /* If non-zero, leave this thread stopped. */
+ int leave_stopped;
+
+ /* If non-zero, we want to single-step. */
+ int step;
+
+ /* If non-zero, send this signal when we resume. */
+ int sig;
+};
+
struct target_ops
{
/* Start a new process.
@@ -56,14 +75,9 @@ struct target_ops
int (*thread_alive) (int pid);
- /* Resume the inferior process.
-
- If STEP is non-zero, we want to single-step.
-
- If SIGNAL is nonzero, send the process that signal as we resume it.
- */
+ /* Resume the inferior process. */
- void (*resume) (int step, int signo);
+ void (*resume) (struct thread_resume *resume_info);
/* Wait for the inferior process to change state.
@@ -78,7 +92,7 @@ struct target_ops
If REGNO is -1, fetch all registers; otherwise, fetch at least REGNO. */
void (*fetch_registers) (int regno);
-
+
/* Store registers to the inferior process.
If REGNO is -1, store all registers; otherwise, store at least REGNO. */
@@ -88,9 +102,11 @@ struct target_ops
/* Read memory from the inferior process. This should generally be
called through read_inferior_memory, which handles breakpoint shadowing.
- Read LEN bytes at MEMADDR into a buffer at MYADDR. */
+ Read LEN bytes at MEMADDR into a buffer at MYADDR.
+
+ Returns 0 on success and errno on failure. */
- void (*read_memory) (CORE_ADDR memaddr, char *myaddr, int len);
+ int (*read_memory) (CORE_ADDR memaddr, char *myaddr, int len);
/* Write memory to the inferior process. This should generally be
called through write_inferior_memory, which handles breakpoint shadowing.
@@ -111,6 +127,12 @@ struct target_ops
/* Send a signal to the inferior process, however is appropriate. */
void (*send_signal) (int);
+
+ /* Read auxiliary vector data from the inferior process.
+
+ Read LEN bytes at OFFSET into a buffer at MYADDR. */
+
+ int (*read_auxv) (CORE_ADDR offset, char *myaddr, unsigned int len);
};
extern struct target_ops *the_target;
@@ -132,9 +154,6 @@ void set_target_ops (struct target_ops *);
#define mythread_alive(pid) \
(*the_target->thread_alive) (pid)
-#define myresume(step,signo) \
- (*the_target->resume) (step, signo)
-
#define fetch_inferior_registers(regno) \
(*the_target->fetch_registers) (regno)
@@ -143,7 +162,7 @@ void set_target_ops (struct target_ops *);
unsigned char mywait (char *statusp, int connected_wait);
-void read_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len);
+int read_inferior_memory (CORE_ADDR memaddr, char *myaddr, int len);
int write_inferior_memory (CORE_ADDR memaddr, const char *myaddr, int len);
diff --git a/gdb/gdbserver/utils.c b/gdb/gdbserver/utils.c
index 20244d6cf83..44bdccfb160 100644
--- a/gdb/gdbserver/utils.c
+++ b/gdb/gdbserver/utils.c
@@ -1,5 +1,5 @@
/* General utility routines for the remote server for GDB.
- Copyright 1986, 1989, 1993, 1995, 1996, 1997, 1999, 2000, 2002
+ Copyright 1986, 1989, 1993, 1995, 1996, 1997, 1999, 2000, 2002, 2003
Free Software Foundation, Inc.
This file is part of GDB.