/* Remote target communications for serial-line targets in custom GDB protocol
- Copyright (C) 1988-2013 Free Software Foundation, Inc.
+ Copyright (C) 1988-2014 Free Software Foundation, Inc.
This file is part of GDB.
/* See the GDB User Guide for details of the GDB remote protocol. */
#include "defs.h"
-#include "gdb_string.h"
+#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include "inferior.h"
#include "gdb_bfd.h"
#include "filestuff.h"
-#include <ctype.h>
#include <sys/time.h>
#include "event-loop.h"
#include "remote-fileio.h"
#include "gdb/fileio.h"
-#include "gdb_stat.h"
+#include <sys/stat.h>
#include "xml-support.h"
#include "memory-map.h"
static void remote_async (void (*callback) (enum inferior_event_type event_type,
void *context), void *context);
-static void remote_detach (struct target_ops *ops, char *args, int from_tty);
-
static void sync_remote_interrupt_twice (int signo);
static void interrupt_query (void);
static void stop_reply_xfree (struct stop_reply *);
static void remote_parse_stop_reply (char *, struct stop_reply *);
static void push_stop_reply (struct stop_reply *);
-static void discard_pending_stop_replies (struct inferior *);
+static void discard_pending_stop_replies_in_queue (struct remote_state *);
static int peek_stop_reply (ptid_t ptid);
static void remote_async_inferior_event_handler (gdb_client_data);
threadref echo_nextthread;
threadref nextthread;
threadref resultthreadlist[MAXTHREADLISTRESULTS];
+
+ /* The state of remote notification. */
+ struct remote_notif_state *notif_state;
};
/* Private data that we'll store in (struct thread_info)->private. */
static void
remote_add_thread (ptid_t ptid, int running)
{
- add_thread (ptid);
+ struct remote_state *rs = get_remote_state ();
+
+ /* GDB historically didn't pull threads in the initial connection
+ setup. If the remote target doesn't even have a concept of
+ threads (e.g., a bare-metal target), even if internally we
+ consider that a single-threaded target, mentioning a new thread
+ might be confusing to the user. Be silent then, preserving the
+ age old behavior. */
+ if (rs->starting_up)
+ add_thread_silent (ptid);
+ else
+ add_thread (ptid);
set_executing (ptid, running);
set_running (ptid, running);
/* If we found a new inferior, let the common code do whatever
it needs to with it (e.g., read shared libraries, insert
- breakpoints). */
+ breakpoints), unless we're just setting up an all-stop
+ connection. */
if (inf != NULL)
- notice_new_inferior (currthread, running, 0);
+ {
+ struct remote_state *rs = get_remote_state ();
+
+ if (non_stop || !rs->starting_up)
+ notice_new_inferior (currthread, running, 0);
+ }
}
}
inferior_ptid = null_ptid;
discard_all_inferiors ();
- /* Stop replies may from inferiors which are still unknown to GDB.
- We are closing the remote target, so we should discard
- everything, including the stop replies from GDB-unknown
- inferiors. */
- discard_pending_stop_replies (NULL);
+ /* We are closing the remote target, so we should discard
+ everything of this target. */
+ discard_pending_stop_replies_in_queue (rs);
if (remote_async_inferior_event_token)
delete_async_event_handler (&remote_async_inferior_event_token);
- remote_notif_unregister_async_event_handler ();
+ remote_notif_state_xfree (rs->notif_state);
trace_reset_local_state ();
}
return null_ptid;
}
+/* Determine the remote side's current thread. If we have a stop
+ reply handy (in WAIT_STATUS), maybe it's a T stop reply with a
+ "thread" register we can extract the current thread from. If not,
+ ask the remote which is the current thread with qC. The former
+ method avoids a roundtrip. */
+
+static ptid_t
+get_current_thread (char *wait_status)
+{
+ ptid_t ptid;
+
+ /* Note we don't use remote_parse_stop_reply as that makes use of
+ the target architecture, which we haven't yet fully determined at
+ this point. */
+ if (wait_status != NULL)
+ ptid = stop_reply_extract_thread (wait_status);
+ if (ptid_equal (ptid, null_ptid))
+ ptid = remote_current_thread (inferior_ptid);
+
+ return ptid;
+}
+
/* Query the remote target for which is the current thread/process,
add it to our tables, and update INFERIOR_PTID. The caller is
responsible for setting the state such that the remote end is ready
inferior_ptid = null_ptid;
- /* Now, if we have thread information, update inferior_ptid. First
- if we have a stop reply handy, maybe it's a T stop reply with a
- "thread" register we can extract the current thread from. If
- not, ask the remote which is the current thread, with qC. The
- former method avoids a roundtrip. Note we don't use
- remote_parse_stop_reply as that makes use of the target
- architecture, which we haven't yet fully determined at this
- point. */
- if (wait_status != NULL)
- ptid = stop_reply_extract_thread (wait_status);
- if (ptid_equal (ptid, null_ptid))
- ptid = remote_current_thread (inferior_ptid);
+ /* Now, if we have thread information, update inferior_ptid. */
+ ptid = get_current_thread (wait_status);
if (!ptid_equal (ptid, null_ptid))
{
strcpy (wait_status, rs->buf);
}
+ /* Fetch thread list. */
+ target_find_new_threads ();
+
/* Let the stub know that we want it to return the thread. */
set_continue_thread (minus_one_ptid);
- add_current_inferior_and_thread (wait_status);
+ if (thread_count () == 0)
+ {
+ /* Target has no concept of threads at all. GDB treats
+ non-threaded target as single-threaded; add a main
+ thread. */
+ add_current_inferior_and_thread (wait_status);
+ }
+ else
+ {
+ /* We have thread information; select the thread the target
+ says should be current. If we're reconnecting to a
+ multi-threaded program, this will ideally be the thread
+ that last reported an event before GDB disconnected. */
+ inferior_ptid = get_current_thread (wait_status);
+ if (ptid_equal (inferior_ptid, null_ptid))
+ {
+ /* Odd... The target was able to list threads, but not
+ tell us which thread was current (no "thread"
+ register in T stop reply?). Just pick the first
+ thread in the thread list then. */
+ inferior_ptid = thread_list->ptid;
+ }
+ }
/* init_wait_for_inferior should be called before get_offsets in order
to manage `inserted' flag in bp loc in a correct state.
/* remote_notif_get_pending_replies acks this one, and gets
the rest out. */
- notif_client_stop.pending_event
+ rs->notif_state->pending_event[notif_client_stop.id]
= remote_notif_parse (notif, rs->buf);
remote_notif_get_pending_events (notif);
remote_async_inferior_event_token
= create_async_event_handler (remote_async_inferior_event_handler,
NULL);
- remote_notif_register_async_event_handler ();
+ rs->notif_state = remote_notif_state_allocate ();
/* Reset the target state; these things will be queried either by
remote_query_supported or as they are needed. */
die when it hits one. */
static void
-remote_detach_1 (char *args, int from_tty, int extended)
+remote_detach_1 (const char *args, int from_tty, int extended)
{
int pid = ptid_get_pid (inferior_ptid);
struct remote_state *rs = get_remote_state ();
}
static void
-remote_detach (struct target_ops *ops, char *args, int from_tty)
+remote_detach (struct target_ops *ops, const char *args, int from_tty)
{
remote_detach_1 (args, from_tty, 0);
}
static void
-extended_remote_detach (struct target_ops *ops, char *args, int from_tty)
+extended_remote_detach (struct target_ops *ops, const char *args, int from_tty)
{
remote_detach_1 (args, from_tty, 1);
}
before resuming inferior, because inferior was stopped and no RSP
traffic at that moment. */
if (!non_stop)
- remote_notif_process (¬if_client_stop);
+ remote_notif_process (rs->notif_state, ¬if_client_stop);
rs->last_sent_signal = siggnal;
rs->last_sent_step = step;
/* The identifier of the thread about this event */
ptid_t ptid;
+ /* The remote state this event is associated with. When the remote
+ connection, represented by a remote_state object, is closed,
+ all the associated stop_reply events should be released. */
+ struct remote_state *rs;
+
struct target_waitstatus ws;
/* Expedited registers. This makes remote debugging a bit more
int stopped_by_watchpoint_p;
CORE_ADDR watch_data_address;
- int solibs_changed;
- int replay_event;
-
int core;
} *stop_reply_p;
static void
stop_reply_xfree (struct stop_reply *r)
{
- if (r != NULL)
- {
- VEC_free (cached_reg_t, r->regcache);
- xfree (r);
- }
+ notif_event_xfree ((struct notif_event *) r);
}
static void
remote_notif_stop_alloc_reply (void)
{
struct notif_event *r
- = (struct notif_event *) XMALLOC (struct stop_reply);
+ = (struct notif_event *) XNEW (struct stop_reply);
r->dtr = stop_reply_dtr;
remote_notif_stop_ack,
remote_notif_stop_can_get_pending_events,
remote_notif_stop_alloc_reply,
- NULL,
+ REMOTE_NOTIF_STOP,
};
/* A parameter to pass data in and out. */
struct stop_reply *output;
};
-/* Remove all queue elements meet the condition it checks. */
+/* Remove stop replies in the queue if its pid is equal to the given
+ inferior's pid. */
static int
-remote_notif_remove_all (QUEUE (stop_reply_p) *q,
- QUEUE_ITER (stop_reply_p) *iter,
- stop_reply_p event,
- void *data)
+remove_stop_reply_for_inferior (QUEUE (stop_reply_p) *q,
+ QUEUE_ITER (stop_reply_p) *iter,
+ stop_reply_p event,
+ void *data)
{
struct queue_iter_param *param = data;
struct inferior *inf = param->input;
- if (inf == NULL || ptid_get_pid (event->ptid) == inf->pid)
+ if (ptid_get_pid (event->ptid) == inf->pid)
{
stop_reply_xfree (event);
QUEUE_remove_elem (stop_reply_p, q, iter);
return 1;
}
-/* Discard all pending stop replies of inferior INF. If INF is NULL,
- discard everything. */
+/* Discard all pending stop replies of inferior INF. */
static void
discard_pending_stop_replies (struct inferior *inf)
{
int i;
struct queue_iter_param param;
- struct stop_reply *reply
- = (struct stop_reply *) notif_client_stop.pending_event;
+ struct stop_reply *reply;
+ struct remote_state *rs = get_remote_state ();
+ struct remote_notif_state *rns = rs->notif_state;
+
+ /* This function can be notified when an inferior exists. When the
+ target is not remote, the notification state is NULL. */
+ if (rs->remote_desc == NULL)
+ return;
+
+ reply = (struct stop_reply *) rns->pending_event[notif_client_stop.id];
/* Discard the in-flight notification. */
- if (reply != NULL
- && (inf == NULL
- || ptid_get_pid (reply->ptid) == inf->pid))
+ if (reply != NULL && ptid_get_pid (reply->ptid) == inf->pid)
{
stop_reply_xfree (reply);
- notif_client_stop.pending_event = NULL;
+ rns->pending_event[notif_client_stop.id] = NULL;
}
param.input = inf;
/* Discard the stop replies we have already pulled with
vStopped. */
QUEUE_iterate (stop_reply_p, stop_reply_queue,
- remote_notif_remove_all, ¶m);
+ remove_stop_reply_for_inferior, ¶m);
+}
+
+/* If its remote state is equal to the given remote state,
+ remove EVENT from the stop reply queue. */
+
+static int
+remove_stop_reply_of_remote_state (QUEUE (stop_reply_p) *q,
+ QUEUE_ITER (stop_reply_p) *iter,
+ stop_reply_p event,
+ void *data)
+{
+ struct queue_iter_param *param = data;
+ struct remote_state *rs = param->input;
+
+ if (event->rs == rs)
+ {
+ stop_reply_xfree (event);
+ QUEUE_remove_elem (stop_reply_p, q, iter);
+ }
+
+ return 1;
+}
+
+/* Discard the stop replies for RS in stop_reply_queue. */
+
+static void
+discard_pending_stop_replies_in_queue (struct remote_state *rs)
+{
+ struct queue_iter_param param;
+
+ param.input = rs;
+ param.output = NULL;
+ /* Discard the stop replies we have already pulled with
+ vStopped. */
+ QUEUE_iterate (stop_reply_p, stop_reply_queue,
+ remove_stop_reply_of_remote_state, ¶m);
}
/* A parameter to pass data in and out. */
char *p;
event->ptid = null_ptid;
+ event->rs = get_remote_state ();
event->ws.kind = TARGET_WAITKIND_IGNORE;
event->ws.value.integer = 0;
- event->solibs_changed = 0;
- event->replay_event = 0;
event->stopped_by_watchpoint_p = 0;
event->regcache = NULL;
event->core = -1;
while (*p_temp && *p_temp != ';')
p_temp++;
- event->solibs_changed = 1;
+ event->ws.kind = TARGET_WAITKIND_LOADED;
p = p_temp;
}
else if (strncmp (p, "replaylog", p1 - p) == 0)
{
- /* NO_HISTORY event.
- p1 will indicate "begin" or "end", but
- it makes no difference for now, so ignore it. */
- event->replay_event = 1;
+ event->ws.kind = TARGET_WAITKIND_NO_HISTORY;
+ /* p1 will indicate "begin" or "end", but it makes
+ no difference for now, so ignore it. */
p_temp = strchr (p1 + 1, ';');
if (p_temp)
p = p_temp;
buf, p);
++p;
}
+
+ if (event->ws.kind != TARGET_WAITKIND_IGNORE)
+ break;
+
/* fall through */
case 'S': /* Old style status, just signal only. */
- if (event->solibs_changed)
- event->ws.kind = TARGET_WAITKIND_LOADED;
- else if (event->replay_event)
- event->ws.kind = TARGET_WAITKIND_NO_HISTORY;
- else
- {
- event->ws.kind = TARGET_WAITKIND_STOPPED;
- event->ws.value.sig = (enum gdb_signal)
- (((fromhex (buf[1])) << 4) + (fromhex (buf[2])));
- }
+ {
+ int sig;
+
+ event->ws.kind = TARGET_WAITKIND_STOPPED;
+ sig = (fromhex (buf[1]) << 4) + fromhex (buf[2]);
+ if (GDB_SIGNAL_FIRST <= sig && sig < GDB_SIGNAL_LAST)
+ event->ws.value.sig = (enum gdb_signal) sig;
+ else
+ event->ws.value.sig = GDB_SIGNAL_UNKNOWN;
+ }
break;
case 'W': /* Target exited. */
case 'X':
{
/* The remote process exited with a signal. */
event->ws.kind = TARGET_WAITKIND_SIGNALLED;
- event->ws.value.sig = (enum gdb_signal) value;
+ if (GDB_SIGNAL_FIRST <= value && value < GDB_SIGNAL_LAST)
+ event->ws.value.sig = (enum gdb_signal) value;
+ else
+ event->ws.value.sig = GDB_SIGNAL_UNKNOWN;
}
/* If no process is specified, assume inferior_ptid. */
{
struct remote_state *rs = get_remote_state ();
- if (nc->pending_event)
+ if (rs->notif_state->pending_event[nc->id] != NULL)
{
if (notif_debug)
fprintf_unfiltered (gdb_stdlog,
nc->name);
/* acknowledge */
- nc->ack (nc, rs->buf, nc->pending_event);
- nc->pending_event = NULL;
+ nc->ack (nc, rs->buf, rs->notif_state->pending_event[nc->id]);
+ rs->notif_state->pending_event[nc->id] = NULL;
while (1)
{
/* Acknowledge a pending stop reply that may have arrived in the
mean time. */
- if (notif_client_stop.pending_event != NULL)
+ if (rs->notif_state->pending_event[notif_client_stop.id] != NULL)
remote_notif_get_pending_events (¬if_client_stop);
/* If indeed we noticed a stop reply, we're done. */
If USE_LENGTH is 0, then the <LENGTH> field and the preceding comma
are omitted.
- Returns the number of bytes transferred, or 0 (setting errno) for
- error. Only transfer a single packet. */
+ Returns the number of bytes transferred, or a negative value (an
+ 'enum target_xfer_error' value) for error. Only transfer a single
+ packet. */
-static int
+static LONGEST
remote_write_bytes_aux (const char *header, CORE_ADDR memaddr,
const gdb_byte *myaddr, ssize_t len,
char packet_format, int use_length)
getpkt (&rs->buf, &rs->buf_size, 0);
if (rs->buf[0] == 'E')
- {
- /* There is no correspondance between what the remote protocol
- uses for errors and errno codes. We would like a cleaner way
- of representing errors (big enough to include errno codes,
- bfd_error codes, and others). But for now just return EIO. */
- errno = EIO;
- return 0;
- }
+ return TARGET_XFER_E_IO;
/* Return NR_BYTES, not TODO, in case escape chars caused us to send
fewer bytes than we'd planned. */
MYADDR is the address of the buffer in our space.
LEN is the number of bytes.
- Returns number of bytes transferred, or 0 (setting errno) for
- error. Only transfer a single packet. */
+ Returns number of bytes transferred, or a negative value (an 'enum
+ target_xfer_error' value) for error. Only transfer a single
+ packet. */
-static int
+static LONGEST
remote_write_bytes (CORE_ADDR memaddr, const gdb_byte *myaddr, ssize_t len)
{
char *packet_format = 0;
MYADDR is the address of the buffer in our space.
LEN is the number of bytes.
- Returns number of bytes transferred, or 0 for error. */
+ Returns number of bytes transferred, or a negative value (an 'enum
+ target_xfer_error' value) for error. */
-static int
+static LONGEST
remote_read_bytes (CORE_ADDR memaddr, gdb_byte *myaddr, int len)
{
struct remote_state *rs = get_remote_state ();
if (rs->buf[0] == 'E'
&& isxdigit (rs->buf[1]) && isxdigit (rs->buf[2])
&& rs->buf[3] == '\0')
- {
- /* There is no correspondance between what the remote protocol
- uses for errors and errno codes. We would like a cleaner way
- of representing errors (big enough to include errno codes,
- bfd_error codes, and others). But for now just return
- EIO. */
- errno = EIO;
- return 0;
- }
+ return TARGET_XFER_E_IO;
/* Reply describes memory byte by byte, each byte encoded as two hex
characters. */
p = rs->buf;
}
\f
-/* Read or write LEN bytes from inferior memory at MEMADDR,
- transferring to or from debugger address BUFFER. Write to inferior
- if SHOULD_WRITE is nonzero. Returns length of data written or
- read; 0 for error. TARGET is unused. */
-
-static int
-remote_xfer_memory (CORE_ADDR mem_addr, gdb_byte *buffer, int mem_len,
- int should_write, struct mem_attrib *attrib,
- struct target_ops *target)
-{
- int res;
-
- set_remote_traceframe ();
- set_general_thread (inferior_ptid);
-
- if (should_write)
- res = remote_write_bytes (mem_addr, buffer, mem_len);
- else
- res = remote_read_bytes (mem_addr, buffer, mem_len);
-
- return res;
-}
/* Sends a packet with content determined by the printf format string
FORMAT and the remaining arguments, then gets the reply. Returns
const gdb_byte *data)
{
int saved_remote_timeout = remote_timeout;
- int ret;
+ LONGEST ret;
struct cleanup *back_to = make_cleanup (restore_remote_timeout,
&saved_remote_timeout);
str);
do_cleanups (old_chain);
}
- handle_notification (rs->buf);
+ handle_notification (rs->notif_state, rs->buf);
/* We're in sync now, rewait for the ack. */
tcount = 0;
}
we get a packet. */
for (;;)
{
- /* If we get a timeout or bad checksm, retry up to MAX_TRIES
+ /* If we get a timeout or bad checksum, retry up to MAX_TRIES
times. */
for (tries = 1; tries <= MAX_TRIES; tries++)
{
if (is_notif != NULL)
*is_notif = 1;
- handle_notification (*buf);
+ handle_notification (rs->notif_state, *buf);
/* Notifications require no acknowledgement. */
}
\f
-/* A helper function that just calls putpkt; for type correctness. */
-
-static int
-putpkt_for_catch_errors (void *arg)
-{
- return putpkt (arg);
-}
-
static void
remote_kill (struct target_ops *ops)
{
- /* Use catch_errors so the user can quit from gdb even when we
+ struct gdb_exception ex;
+
+ /* Catch errors so the user can quit from gdb even when we
aren't on speaking terms with the remote system. */
- catch_errors (putpkt_for_catch_errors, "k", "", RETURN_MASK_ERROR);
+ TRY_CATCH (ex, RETURN_MASK_ERROR)
+ {
+ putpkt ("k");
+ }
+ if (ex.reason < 0)
+ {
+ if (ex.error == TARGET_CLOSE_ERROR)
+ {
+ /* If we got an (EOF) error that caused the target
+ to go away, then we're done, that's what we wanted.
+ "k" is susceptible to cause a premature EOF, given
+ that the remote server isn't actually required to
+ reply to "k", and it can happen that it doesn't
+ even get to reply ACK to the "k". */
+ return;
+ }
- /* Don't wait for it to die. I'm not really sure it matters whether
- we do or not. For the existing stubs, kill is a noop. */
+ /* Otherwise, something went wrong. We didn't actually kill
+ the target. Just propagate the exception, and let the
+ user or higher layers decide what to do. */
+ throw_exception (ex);
+ }
+
+ /* We've killed the remote end, we get to mourn it. Since this is
+ target remote, single-process, mourning the inferior also
+ unpushes remote_ops. */
target_mourn_inferior ();
}
buf = pack_hex_byte (buf, aexpr->buf[i]);
*buf = '\0';
}
-
- VEC_free (agent_expr_p, bp_tgt->conditions);
return 0;
}
buf = pack_hex_byte (buf, aexpr->buf[i]);
*buf = '\0';
}
-
- VEC_free (agent_expr_p, bp_tgt->tcommands);
}
/* Insert a breakpoint. On targets that have software breakpoint
}
}
+ /* If this breakpoint has target-side commands but this stub doesn't
+ support Z0 packets, throw error. */
+ if (!VEC_empty (agent_expr_p, bp_tgt->tcommands))
+ throw_error (NOT_SUPPORTED_ERROR, _("\
+Target doesn't support breakpoints that have target side commands."));
+
return memory_insert_breakpoint (gdbarch, bp_tgt);
}
static LONGEST
remote_xfer_partial (struct target_ops *ops, enum target_object object,
const char *annex, gdb_byte *readbuf,
- const gdb_byte *writebuf, ULONGEST offset, LONGEST len)
+ const gdb_byte *writebuf, ULONGEST offset, ULONGEST len)
{
struct remote_state *rs;
int i;
/* Handle memory using the standard memory routines. */
if (object == TARGET_OBJECT_MEMORY)
{
- int xfered;
-
- errno = 0;
+ LONGEST xfered;
/* If the remote target is connected but not running, we should
pass this request down to a lower stratum (e.g. the executable
else
xfered = remote_read_bytes (offset, readbuf, len);
- if (xfered > 0)
- return xfered;
- else if (xfered == 0 && errno == 0)
- return 0;
- else
- return -1;
+ return xfered;
}
/* Handle SPU memory using qxfer packets. */
switch (object)
{
case TARGET_OBJECT_FLASH:
- xfered = remote_flash_write (ops, offset, len, writebuf);
-
- if (xfered > 0)
- return xfered;
- else if (xfered == 0 && errno == 0)
- return 0;
- else
- return -1;
+ return remote_flash_write (ops, offset, len, writebuf);
default:
return -1;
int
remote_filename_p (const char *filename)
{
- return strncmp (filename, "remote:", 7) == 0;
+ return strncmp (filename,
+ REMOTE_SYSROOT_PREFIX,
+ sizeof (REMOTE_SYSROOT_PREFIX) - 1) == 0;
}
bfd *
{
char *text;
+ /* If current traceframe is not selected, don't bother the remote
+ stub. */
+ if (get_traceframe_number () < 0)
+ return NULL;
+
text = target_read_stralloc (¤t_target,
TARGET_OBJECT_TRACEFRAME_INFO, NULL);
if (text != NULL)
switch (type)
{
- case btrace_read_all:
+ case BTRACE_READ_ALL:
annex = "all";
break;
- case btrace_read_new:
+ case BTRACE_READ_NEW:
annex = "new";
break;
default:
remote_ops.to_fetch_registers = remote_fetch_registers;
remote_ops.to_store_registers = remote_store_registers;
remote_ops.to_prepare_to_store = remote_prepare_to_store;
- remote_ops.deprecated_xfer_memory = remote_xfer_memory;
remote_ops.to_files_info = remote_files_info;
remote_ops.to_insert_breakpoint = remote_insert_breakpoint;
remote_ops.to_remove_breakpoint = remote_remove_breakpoint;