/* 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_files_info (struct target_ops *ignore);
-static void remote_prepare_to_store (struct regcache *regcache);
+static void remote_prepare_to_store (struct target_ops *self,
+ struct regcache *regcache);
static void remote_open (char *name, int from_tty);
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);
+ }
}
}
*p = 0;
if (!rs->last_pass_packet || strcmp (rs->last_pass_packet, pass_packet))
{
- char *buf = rs->buf;
-
putpkt (pass_packet);
getpkt (&rs->buf, &rs->buf_size, 0);
- packet_ok (buf, &remote_protocol_packets[PACKET_QPassSignals]);
+ packet_ok (rs->buf, &remote_protocol_packets[PACKET_QPassSignals]);
if (rs->last_pass_packet)
xfree (rs->last_pass_packet);
rs->last_pass_packet = pass_packet;
if (!rs->last_program_signals_packet
|| strcmp (rs->last_program_signals_packet, packet) != 0)
{
- char *buf = rs->buf;
-
putpkt (packet);
getpkt (&rs->buf, &rs->buf_size, 0);
- packet_ok (buf, &remote_protocol_packets[PACKET_QProgramSignals]);
+ packet_ok (rs->buf, &remote_protocol_packets[PACKET_QProgramSignals]);
xfree (rs->last_program_signals_packet);
rs->last_program_signals_packet = packet;
}
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);
/* If we connected to a live target, do some additional setup. */
if (target_has_execution)
{
- if (exec_bfd) /* No use without an exec file. */
+ if (symfile_objfile) /* No use without a symbol-file. */
remote_check_symbols ();
}
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
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->stopped_by_watchpoint_p = 0;
/* fall through */
case 'S': /* Old style status, just signal only. */
- 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. */
first. */
static void
-remote_prepare_to_store (struct regcache *regcache)
+remote_prepare_to_store (struct target_ops *self, struct regcache *regcache)
{
struct remote_arch_state *rsa = get_remote_arch_state ();
int i;
static LONGEST
remote_write_bytes_aux (const char *header, CORE_ADDR memaddr,
- const gdb_byte *myaddr, ssize_t len,
+ const gdb_byte *myaddr, ULONGEST len,
char packet_format, int use_length)
{
struct remote_state *rs = get_remote_state ();
internal_error (__FILE__, __LINE__,
_("remote_write_bytes_aux: bad packet format"));
- if (len <= 0)
+ if (len == 0)
return 0;
payload_size = get_memory_write_packet_size ();
packet. */
static LONGEST
-remote_write_bytes (CORE_ADDR memaddr, const gdb_byte *myaddr, ssize_t len)
+remote_write_bytes (CORE_ADDR memaddr, const gdb_byte *myaddr, ULONGEST len)
{
char *packet_format = 0;
target_xfer_error' value) for error. */
static LONGEST
-remote_read_bytes (CORE_ADDR memaddr, gdb_byte *myaddr, int len)
+remote_read_bytes (CORE_ADDR memaddr, gdb_byte *myaddr, ULONGEST len)
{
struct remote_state *rs = get_remote_state ();
int max_buf_size; /* Max size of packet output buffer. */
int todo;
int i;
- if (len <= 0)
+ if (len == 0)
return 0;
max_buf_size = get_memory_read_packet_size ();
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
+ volatile 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;
+ }
+
+ /* 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);
+ }
- /* 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. */
+ /* 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 ();
}
environment. */
static void
-extended_remote_create_inferior_1 (char *exec_file, char *args,
- char **env, int from_tty)
+extended_remote_create_inferior (struct target_ops *ops,
+ char *exec_file, char *args,
+ char **env, int from_tty)
{
int run_worked;
char *stop_reply;
/* Get updated offsets, if the stub uses qOffsets. */
get_offsets ();
}
-
-static void
-extended_remote_create_inferior (struct target_ops *ops,
- char *exec_file, char *args,
- char **env, int from_tty)
-{
- extended_remote_create_inferior_1 (exec_file, args, env, from_tty);
-}
\f
/* Given a location's target info BP_TGT and the packet buffer BUF, output
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
which don't, we insert a traditional memory breakpoint. */
static int
-remote_insert_breakpoint (struct gdbarch *gdbarch,
+remote_insert_breakpoint (struct target_ops *ops,
+ struct gdbarch *gdbarch,
struct bp_target_info *bp_tgt)
{
/* Try the "Z" s/w breakpoint packet if it is not already disabled.
}
}
- return memory_insert_breakpoint (gdbarch, bp_tgt);
+ /* 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 (ops, gdbarch, bp_tgt);
}
static int
-remote_remove_breakpoint (struct gdbarch *gdbarch,
+remote_remove_breakpoint (struct target_ops *ops,
+ struct gdbarch *gdbarch,
struct bp_target_info *bp_tgt)
{
CORE_ADDR addr = bp_tgt->placed_address;
return (rs->buf[0] == 'E');
}
- return memory_remove_breakpoint (gdbarch, bp_tgt);
+ return memory_remove_breakpoint (ops, gdbarch, bp_tgt);
}
static int
int max_size = get_memory_write_packet_size ();
if (packet->support == PACKET_DISABLE)
- return -1;
+ return TARGET_XFER_E_IO;
/* Insert header. */
i = snprintf (rs->buf, max_size,
if (putpkt_binary (rs->buf, i + buf_len) < 0
|| getpkt_sane (&rs->buf, &rs->buf_size, 0) < 0
|| packet_ok (rs->buf, packet) != PACKET_OK)
- return -1;
+ return TARGET_XFER_E_IO;
unpack_varlen_hex (rs->buf, &n);
return n;
LONGEST i, n, packet_len;
if (packet->support == PACKET_DISABLE)
- return -1;
+ return TARGET_XFER_E_IO;
/* Check whether we've cached an end-of-object packet that matches
this request. */
phex_nz (n, sizeof n));
i = putpkt (rs->buf);
if (i < 0)
- return -1;
+ return TARGET_XFER_E_IO;
rs->buf[0] = '\0';
packet_len = getpkt_sane (&rs->buf, &rs->buf_size, 0);
if (packet_len < 0 || packet_ok (rs->buf, packet) != PACKET_OK)
- return -1;
+ return TARGET_XFER_E_IO;
if (rs->buf[0] != 'l' && rs->buf[0] != 'm')
error (_("Unknown remote qXfer reply: %s"), rs->buf);
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;
&remote_protocol_packets
[PACKET_qXfer_statictrace_read]);
else
- return -1;
+ return TARGET_XFER_E_IO;
}
/* Only handle flash writes. */
return remote_flash_write (ops, offset, len, writebuf);
default:
- return -1;
+ return TARGET_XFER_E_IO;
}
}
&remote_protocol_packets[PACKET_qXfer_btrace]);
default:
- return -1;
+ return TARGET_XFER_E_IO;
}
/* Note: a zero OFFSET and LEN can be used to query the minimum
/* Minimum outbuf size is get_remote_packet_size (). If LEN is not
large enough let the caller deal with it. */
if (len < get_remote_packet_size ())
- return -1;
+ return TARGET_XFER_E_IO;
len = get_remote_packet_size ();
/* Except for querying the minimum buffer size, target must be open. */
i = putpkt (rs->buf);
if (i < 0)
- return i;
+ return TARGET_XFER_E_IO;
getpkt (&rs->buf, &rs->buf_size, 0);
strcpy ((char *) readbuf, rs->buf);
{
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)
/* Read the branch trace. */
-static VEC (btrace_block_s) *
-remote_read_btrace (struct btrace_target_info *tinfo,
+static enum btrace_error
+remote_read_btrace (VEC (btrace_block_s) **btrace,
+ struct btrace_target_info *tinfo,
enum btrace_read_type type)
{
struct packet_config *packet = &remote_protocol_packets[PACKET_qXfer_btrace];
struct remote_state *rs = get_remote_state ();
- VEC (btrace_block_s) *btrace = NULL;
+ struct cleanup *cleanup;
const char *annex;
char *xml;
switch (type)
{
- case btrace_read_all:
+ case BTRACE_READ_ALL:
annex = "all";
break;
- case btrace_read_new:
+ case BTRACE_READ_NEW:
annex = "new";
break;
+ case BTRACE_READ_DELTA:
+ annex = "delta";
+ break;
default:
internal_error (__FILE__, __LINE__,
_("Bad branch tracing read type: %u."),
xml = target_read_stralloc (¤t_target,
TARGET_OBJECT_BTRACE, annex);
- if (xml != NULL)
- {
- struct cleanup *cleanup = make_cleanup (xfree, xml);
+ if (xml == NULL)
+ return BTRACE_ERR_UNKNOWN;
- btrace = parse_xml_btrace (xml);
- do_cleanups (cleanup);
- }
+ cleanup = make_cleanup (xfree, xml);
+ *btrace = parse_xml_btrace (xml);
+ do_cleanups (cleanup);
- return btrace;
+ return BTRACE_ERR_NONE;
}
static int