From 6301c13d9ebeab1b0470573b530fb181ad11526c Mon Sep 17 00:00:00 2001 From: Elena Zannoni Date: Tue, 23 Mar 2004 20:28:36 +0000 Subject: merge mainline chenges into branch --- gdb/gdbserver/ChangeLog | 116 +++++++++++++++++++++- gdb/gdbserver/Makefile.in | 10 +- gdb/gdbserver/gdbreplay.c | 2 +- gdb/gdbserver/linux-arm-low.c | 6 +- gdb/gdbserver/linux-low.c | 211 ++++++++++++++++++++++++++++++++++++----- gdb/gdbserver/linux-low.h | 8 +- gdb/gdbserver/linux-s390-low.c | 10 +- gdb/gdbserver/regcache.c | 7 +- gdb/gdbserver/remote-utils.c | 33 ++++++- gdb/gdbserver/server.c | 195 +++++++++++++++++++++++++++++++++++-- gdb/gdbserver/server.h | 4 +- gdb/gdbserver/target.c | 8 +- gdb/gdbserver/target.h | 49 +++++++--- gdb/gdbserver/utils.c | 2 +- 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 + + * linux-low.c: Include . Remove extern declaration of + errno. + +2004-03-12 Daniel Jacobowitz + + * gdbreplay.c, server.h, utils.c: Update copyright years. + +2004-03-04 Nathan J. Williams + + * server.c (main): Print child status or termination signal from + variable 'signal', not 'sig'. + +2004-03-04 Nathan J. Williams + + * 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 + + * Makefile.in (distclean): Remove config.h, stamp-h, and config.log. + Unify with other clean targets. + +2004-02-29 Daniel Jacobowitz + + * server.c (handle_v_cont): Call set_desired_inferior. + +2004-02-29 Daniel Jacobowitz + + * remote-utils.c (prepare_resume_reply): Always supply "thread:". + +2004-02-29 Daniel Jacobowitz + + * 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 + + * 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 + + * linux-arm-low.c (arm_get_pc): Print out stop PC in debug mode. + +2004-02-26 Daniel Jacobowitz + + * 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 + + * 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 + + Committed by Jim Blandy . + + * 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 + + * 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 + + * regcache.c (new_register_cache): Clear the allocated register + buffer. Suggested by Atsushi Nemoto . + +2003-10-13 Daniel Jacobowitz + + * 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 * Makefile.in (install-only): Create dest dir. Support DESTDIR. @@ -112,7 +223,7 @@ Mon Jul 21 20:09:34 UTC 2003 Brendan Conoboy 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 @@ -141,7 +252,7 @@ Mon Jul 21 20:09:34 UTC 2003 Brendan Conoboy 2002-07-04 Michal Ludvig - * 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 * 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 #include #include +#include /* ``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 -#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, -/* 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) @@ -365,6 +367,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) { @@ -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. -- cgit v1.2.1