static void remote_close (struct target_ops *self);
+struct remote_state;
+
+static int remote_vkill (int pid, struct remote_state *rs);
+
static void remote_mourn (struct target_ops *ops);
static void extended_remote_restart (void);
static void extended_remote_mourn (struct target_ops *);
-static void remote_mourn_1 (struct target_ops *);
-
static void remote_send (char **buf, long *sizeof_buf_p);
static int readchar (int timeout);
static int remote_is_async_p (struct target_ops *);
-static void remote_async (struct target_ops *ops,
- void (*callback) (enum inferior_event_type event_type,
- void *context),
- void *context);
+static void remote_async (struct target_ops *ops, int enable);
static void sync_remote_interrupt_twice (int signo);
static void remote_set_permissions (struct target_ops *self);
-struct remote_state;
static int remote_get_trace_status (struct target_ops *self,
struct trace_status *ts);
static void discard_pending_stop_replies_in_queue (struct remote_state *);
static int peek_stop_reply (ptid_t ptid);
+struct threads_listing_context;
+static void remove_new_fork_children (struct threads_listing_context *);
+
static void remote_async_inferior_event_handler (gdb_client_data);
static void remote_terminal_ours (struct target_ops *self);
int use_threadinfo_query;
int use_threadextra_query;
- void (*async_client_callback) (enum inferior_event_type event_type,
- void *context);
- void *async_client_context;
-
/* This is set to the data address of the access causing the target
to stop for a watchpoint. */
CORE_ADDR remote_watch_data_address;
PACKET_vFile_fstat,
PACKET_qXfer_auxv,
PACKET_qXfer_features,
+ PACKET_qXfer_exec_file,
PACKET_qXfer_libraries,
PACKET_qXfer_libraries_svr4,
PACKET_qXfer_memory_map,
/* Support for hwbreak+ feature. */
PACKET_hwbreak_feature,
+ /* Support for fork events. */
+ PACKET_fork_event_feature,
+
+ /* Support for vfork events. */
+ PACKET_vfork_event_feature,
+
PACKET_MAX
};
return packet_support (PACKET_multiprocess_feature) == PACKET_ENABLE;
}
+/* Returns true if fork events are supported. */
+
+static int
+remote_fork_event_p (struct remote_state *rs)
+{
+ return packet_support (PACKET_fork_event_feature) == PACKET_ENABLE;
+}
+
+/* Returns true if vfork events are supported. */
+
+static int
+remote_vfork_event_p (struct remote_state *rs)
+{
+ return packet_support (PACKET_vfork_event_feature) == PACKET_ENABLE;
+}
+
+/* Insert fork catchpoint target routine. If fork events are enabled
+ then return success, nothing more to do. */
+
+static int
+remote_insert_fork_catchpoint (struct target_ops *ops, int pid)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ return !remote_fork_event_p (rs);
+}
+
+/* Remove fork catchpoint target routine. Nothing to do, just
+ return success. */
+
+static int
+remote_remove_fork_catchpoint (struct target_ops *ops, int pid)
+{
+ return 0;
+}
+
+/* Insert vfork catchpoint target routine. If vfork events are enabled
+ then return success, nothing more to do. */
+
+static int
+remote_insert_vfork_catchpoint (struct target_ops *ops, int pid)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ return !remote_vfork_event_p (rs);
+}
+
+/* Remove vfork catchpoint target routine. Nothing to do, just
+ return success. */
+
+static int
+remote_remove_vfork_catchpoint (struct target_ops *ops, int pid)
+{
+ return 0;
+}
+
/* Tokens for use by the asynchronous signal handlers for SIGINT. */
static struct async_signal_handler *async_sigint_remote_twice_token;
static struct async_signal_handler *async_sigint_remote_token;
inferior. If ATTACHED is 1, then we had just attached to this
inferior. If it is 0, then we just created this inferior. If it
is -1, then try querying the remote stub to find out if it had
- attached to the inferior or not. */
+ attached to the inferior or not. If TRY_OPEN_EXEC is true then
+ attempt to open this inferior's executable as the main executable
+ if no main executable is open already. */
static struct inferior *
-remote_add_inferior (int fake_pid_p, int pid, int attached)
+remote_add_inferior (int fake_pid_p, int pid, int attached,
+ int try_open_exec)
{
struct inferior *inf;
inf->attach_flag = attached;
inf->fake_pid_p = fake_pid_p;
+ /* If no main executable is currently open then attempt to
+ open the file that was executed to create this inferior. */
+ if (try_open_exec && get_exec_file (0) == NULL)
+ exec_file_locate_attach (pid, 1);
+
return inf;
}
int fake_pid_p = !remote_multi_process_p (rs);
inf = remote_add_inferior (fake_pid_p,
- ptid_get_pid (currthread), -1);
+ ptid_get_pid (currthread), -1, 1);
}
/* This is really a new thread. Add it. */
VEC_free (thread_item_t, context->items);
}
+/* Remove the thread specified as the related_pid field of WS
+ from the CONTEXT list. */
+
+static void
+threads_listing_context_remove (struct target_waitstatus *ws,
+ struct threads_listing_context *context)
+{
+ struct thread_item *item;
+ int i;
+ ptid_t child_ptid = ws->value.related_pid;
+
+ for (i = 0; VEC_iterate (thread_item_t, context->items, i, item); ++i)
+ {
+ if (ptid_equal (item->ptid, child_ptid))
+ {
+ VEC_ordered_remove (thread_item_t, context->items, i);
+ break;
+ }
+ }
+}
+
static int
remote_newthread_step (threadref *ref, void *data)
{
/* CONTEXT now holds the current thread list on the remote
target end. Delete GDB-side threads no longer found on the
target. */
- ALL_NON_EXITED_THREADS_SAFE (tp, tmp)
- {
+ ALL_THREADS_SAFE (tp, tmp)
+ {
for (i = 0;
VEC_iterate (thread_item_t, context.items, i, item);
++i)
/* Not found. */
delete_thread (tp->ptid);
}
- }
+ }
+
+ /* Remove any unreported fork child threads from CONTEXT so
+ that we don't interfere with follow fork, which is where
+ creation of such threads is handled. */
+ remove_new_fork_children (&context);
/* And now add threads we don't know about yet to our list. */
for (i = 0;
fake_pid_p = 1;
}
- remote_add_inferior (fake_pid_p, ptid_get_pid (inferior_ptid), -1);
+ remote_add_inferior (fake_pid_p, ptid_get_pid (inferior_ptid), -1, 1);
/* Add the main thread. */
add_thread_silent (inferior_ptid);
}
if (target_can_async_p ())
- target_async (inferior_event_handler, 0);
+ target_async (1);
if (thread_count () == 0)
{
{ "PacketSize", PACKET_DISABLE, remote_packet_size, -1 },
{ "qXfer:auxv:read", PACKET_DISABLE, remote_supported_packet,
PACKET_qXfer_auxv },
+ { "qXfer:exec-file:read", PACKET_DISABLE, remote_supported_packet,
+ PACKET_qXfer_exec_file },
{ "qXfer:features:read", PACKET_DISABLE, remote_supported_packet,
PACKET_qXfer_features },
{ "qXfer:libraries:read", PACKET_DISABLE, remote_supported_packet,
PACKET_Qbtrace_conf_bts_size },
{ "swbreak", PACKET_DISABLE, remote_supported_packet, PACKET_swbreak_feature },
{ "hwbreak", PACKET_DISABLE, remote_supported_packet, PACKET_hwbreak_feature },
- { "vFile:fstat", PACKET_DISABLE, remote_supported_packet,
- PACKET_vFile_fstat },
+ { "fork-events", PACKET_DISABLE, remote_supported_packet,
+ PACKET_fork_event_feature },
+ { "vfork-events", PACKET_DISABLE, remote_supported_packet,
+ PACKET_vfork_event_feature },
};
static char *remote_support_xml;
q = remote_query_supported_append (q, "qRelocInsn+");
+ if (rs->extended)
+ {
+ if (packet_set_cmd_state (PACKET_fork_event_feature)
+ != AUTO_BOOLEAN_FALSE)
+ q = remote_query_supported_append (q, "fork-events+");
+ if (packet_set_cmd_state (PACKET_vfork_event_feature)
+ != AUTO_BOOLEAN_FALSE)
+ q = remote_query_supported_append (q, "vfork-events+");
+ }
+
q = reconcat (q, "qSupported:", q, (char *) NULL);
putpkt (q);
}
}
+ serial_setparity (rs->remote_desc, serial_parity);
serial_raw (rs->remote_desc);
/* If there is something sitting in the buffer we might take it as a
wait_forever_enabled_p = 1;
}
-/* This takes a program previously attached to and detaches it. After
- this is done, GDB can be used to debug some other program. We
- better not have left any breakpoints in the target program or it'll
- die when it hits one. */
+/* Detach the specified process. */
+
+static void
+remote_detach_pid (int pid)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ if (remote_multi_process_p (rs))
+ xsnprintf (rs->buf, get_remote_packet_size (), "D;%x", pid);
+ else
+ strcpy (rs->buf, "D");
+
+ putpkt (rs->buf);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+
+ if (rs->buf[0] == 'O' && rs->buf[1] == 'K')
+ ;
+ else if (rs->buf[0] == '\0')
+ error (_("Remote doesn't know how to detach"));
+ else
+ error (_("Can't detach process."));
+}
+
+/* This detaches a program to which we previously attached, using
+ inferior_ptid to identify the process. After this is done, GDB
+ can be used to debug some other program. We better not have left
+ any breakpoints in the target program or it'll die when it hits
+ one. */
static void
-remote_detach_1 (const char *args, int from_tty, int extended)
+remote_detach_1 (const char *args, int from_tty)
{
int pid = ptid_get_pid (inferior_ptid);
struct remote_state *rs = get_remote_state ();
+ struct thread_info *tp = find_thread_ptid (inferior_ptid);
+ int is_fork_parent;
if (args)
error (_("Argument given to \"detach\" when remotely debugging."));
}
/* Tell the remote target to detach. */
- if (remote_multi_process_p (rs))
- xsnprintf (rs->buf, get_remote_packet_size (), "D;%x", pid);
- else
- strcpy (rs->buf, "D");
+ remote_detach_pid (pid);
- putpkt (rs->buf);
- getpkt (&rs->buf, &rs->buf_size, 0);
-
- if (rs->buf[0] == 'O' && rs->buf[1] == 'K')
- ;
- else if (rs->buf[0] == '\0')
- error (_("Remote doesn't know how to detach"));
- else
- error (_("Can't detach process."));
-
- if (from_tty && !extended)
+ if (from_tty && !rs->extended)
puts_filtered (_("Ending remote debugging.\n"));
- target_mourn_inferior ();
+ /* Check to see if we are detaching a fork parent. Note that if we
+ are detaching a fork child, tp == NULL. */
+ is_fork_parent = (tp != NULL
+ && tp->pending_follow.kind == TARGET_WAITKIND_FORKED);
+
+ /* If doing detach-on-fork, we don't mourn, because that will delete
+ breakpoints that should be available for the followed inferior. */
+ if (!is_fork_parent)
+ target_mourn_inferior ();
+ else
+ {
+ inferior_ptid = null_ptid;
+ detach_inferior (pid);
+ }
}
static void
remote_detach (struct target_ops *ops, const char *args, int from_tty)
{
- remote_detach_1 (args, from_tty, 0);
+ remote_detach_1 (args, from_tty);
}
static void
extended_remote_detach (struct target_ops *ops, const char *args, int from_tty)
{
- remote_detach_1 (args, from_tty, 1);
+ remote_detach_1 (args, from_tty);
+}
+
+/* Target follow-fork function for remote targets. On entry, and
+ at return, the current inferior is the fork parent.
+
+ Note that although this is currently only used for extended-remote,
+ it is named remote_follow_fork in anticipation of using it for the
+ remote target as well. */
+
+static int
+remote_follow_fork (struct target_ops *ops, int follow_child,
+ int detach_fork)
+{
+ struct remote_state *rs = get_remote_state ();
+ enum target_waitkind kind = inferior_thread ()->pending_follow.kind;
+
+ if ((kind == TARGET_WAITKIND_FORKED && remote_fork_event_p (rs))
+ || (kind == TARGET_WAITKIND_VFORKED && remote_vfork_event_p (rs)))
+ {
+ /* When following the parent and detaching the child, we detach
+ the child here. For the case of following the child and
+ detaching the parent, the detach is done in the target-
+ independent follow fork code in infrun.c. We can't use
+ target_detach when detaching an unfollowed child because
+ the client side doesn't know anything about the child. */
+ if (detach_fork && !follow_child)
+ {
+ /* Detach the fork child. */
+ ptid_t child_ptid;
+ pid_t child_pid;
+
+ child_ptid = inferior_thread ()->pending_follow.value.related_pid;
+ child_pid = ptid_get_pid (child_ptid);
+
+ remote_detach_pid (child_pid);
+ detach_inferior (child_pid);
+ }
+ }
+ return 0;
}
/* Same as remote_detach, but don't send the "D" packet; just disconnect. */
error (_("Argument given to \"disconnect\" when remotely debugging."));
/* Make sure we unpush even the extended remote targets; mourn
- won't do it. So call remote_mourn_1 directly instead of
+ won't do it. So call remote_mourn directly instead of
target_mourn_inferior. */
- remote_mourn_1 (target);
+ remote_mourn (target);
if (from_tty)
puts_filtered ("Ending remote debugging.\n");
be chatty about it. */
static void
-extended_remote_attach_1 (struct target_ops *target, const char *args,
- int from_tty)
+extended_remote_attach (struct target_ops *target, const char *args,
+ int from_tty)
{
struct remote_state *rs = get_remote_state ();
int pid;
target_pid_to_str (pid_to_ptid (pid)));
}
- set_current_inferior (remote_add_inferior (0, pid, 1));
+ set_current_inferior (remote_add_inferior (0, pid, 1, 0));
inferior_ptid = pid_to_ptid (pid);
push_stop_reply ((struct stop_reply *) reply);
- target_async (inferior_event_handler, 0);
+ target_async (1);
}
else
{
gdb_assert (wait_status == NULL);
}
-static void
-extended_remote_attach (struct target_ops *ops, const char *args, int from_tty)
-{
- extended_remote_attach_1 (ops, args, from_tty);
-}
-
/* Implementation of the to_post_attach method. */
static void
into infcmd.c in order to allow inferior function calls to work
NOT asynchronously. */
if (target_can_async_p ())
- target_async (inferior_event_handler, 0);
+ target_async (1);
/* We've just told the target to resume. The remote server will
wait for the inferior to stop, and then send a stop reply. In
struct stop_reply *output;
};
+/* Determine if THREAD is a pending fork parent thread. ARG contains
+ the pid of the process that owns the threads we want to check, or
+ -1 if we want to check all threads. */
+
+static int
+is_pending_fork_parent (struct target_waitstatus *ws, int event_pid,
+ ptid_t thread_ptid)
+{
+ if (ws->kind == TARGET_WAITKIND_FORKED
+ || ws->kind == TARGET_WAITKIND_VFORKED)
+ {
+ if (event_pid == -1 || event_pid == ptid_get_pid (thread_ptid))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Check whether EVENT is a fork event, and if it is, remove the
+ fork child from the context list passed in DATA. */
+
+static int
+remove_child_of_pending_fork (QUEUE (stop_reply_p) *q,
+ QUEUE_ITER (stop_reply_p) *iter,
+ stop_reply_p event,
+ void *data)
+{
+ struct queue_iter_param *param = data;
+ struct threads_listing_context *context = param->input;
+
+ if (event->ws.kind == TARGET_WAITKIND_FORKED
+ || event->ws.kind == TARGET_WAITKIND_VFORKED)
+ {
+ threads_listing_context_remove (&event->ws, context);
+ }
+
+ return 1;
+}
+
+/* If CONTEXT contains any fork child threads that have not been
+ reported yet, remove them from the CONTEXT list. If such a
+ thread exists it is because we are stopped at a fork catchpoint
+ and have not yet called follow_fork, which will set up the
+ host-side data structures for the new process. */
+
+static void
+remove_new_fork_children (struct threads_listing_context *context)
+{
+ struct thread_info * thread;
+ int pid = -1;
+ struct notif_client *notif = ¬if_client_stop;
+ struct queue_iter_param param;
+
+ /* For any threads stopped at a fork event, remove the corresponding
+ fork child threads from the CONTEXT list. */
+ ALL_NON_EXITED_THREADS (thread)
+ {
+ struct target_waitstatus *ws = &thread->pending_follow;
+
+ if (is_pending_fork_parent (ws, pid, thread->ptid))
+ {
+ threads_listing_context_remove (ws, context);
+ }
+ }
+
+ /* Check for any pending fork events (not reported or processed yet)
+ in process PID and remove those fork child threads from the
+ CONTEXT list as well. */
+ remote_notif_get_pending_events (notif);
+ param.input = context;
+ param.output = NULL;
+ QUEUE_iterate (stop_reply_p, stop_reply_queue,
+ remove_child_of_pending_fork, ¶m);
+}
+
/* Remove stop replies in the queue if its pid is equal to the given
inferior's pid. */
p = unpack_varlen_hex (++p1, &c);
event->core = c;
}
+ else if (strncmp (p, "fork", p1 - p) == 0)
+ {
+ event->ws.value.related_pid = read_ptid (++p1, &p);
+ event->ws.kind = TARGET_WAITKIND_FORKED;
+ }
+ else if (strncmp (p, "vfork", p1 - p) == 0)
+ {
+ event->ws.value.related_pid = read_ptid (++p1, &p);
+ event->ws.kind = TARGET_WAITKIND_VFORKED;
+ }
+ else if (strncmp (p, "vforkdone", p1 - p) == 0)
+ {
+ event->ws.kind = TARGET_WAITKIND_VFORK_DONE;
+ p = skip_to_semicolon (p1 + 1);
+ }
else
{
ULONGEST pnum;
is_notif);
}
+/* Check whether EVENT is a fork event for the process specified
+ by the pid passed in DATA, and if it is, kill the fork child. */
+
+static int
+kill_child_of_pending_fork (QUEUE (stop_reply_p) *q,
+ QUEUE_ITER (stop_reply_p) *iter,
+ stop_reply_p event,
+ void *data)
+{
+ struct queue_iter_param *param = data;
+ int parent_pid = *(int *) param->input;
+
+ if (is_pending_fork_parent (&event->ws, parent_pid, event->ptid))
+ {
+ struct remote_state *rs = get_remote_state ();
+ int child_pid = ptid_get_pid (event->ws.value.related_pid);
+ int res;
+
+ res = remote_vkill (child_pid, rs);
+ if (res != 0)
+ error (_("Can't kill fork child process %d"), child_pid);
+ }
+
+ return 1;
+}
+
+/* Kill any new fork children of process PID that haven't been
+ processed by follow_fork. */
+
+static void
+kill_new_fork_children (int pid, struct remote_state *rs)
+{
+ struct thread_info *thread;
+ struct notif_client *notif = ¬if_client_stop;
+ struct queue_iter_param param;
+
+ /* Kill the fork child threads of any threads in process PID
+ that are stopped at a fork event. */
+ ALL_NON_EXITED_THREADS (thread)
+ {
+ struct target_waitstatus *ws = &thread->pending_follow;
+
+ if (is_pending_fork_parent (ws, pid, thread->ptid))
+ {
+ struct remote_state *rs = get_remote_state ();
+ int child_pid = ptid_get_pid (ws->value.related_pid);
+ int res;
+
+ res = remote_vkill (child_pid, rs);
+ if (res != 0)
+ error (_("Can't kill fork child process %d"), child_pid);
+ }
+ }
+
+ /* Check for any pending fork events (not reported or processed yet)
+ in process PID and kill those fork child threads as well. */
+ remote_notif_get_pending_events (notif);
+ param.input = &pid;
+ param.output = NULL;
+ QUEUE_iterate (stop_reply_p, stop_reply_queue,
+ kill_child_of_pending_fork, ¶m);
+}
+
\f
static void
remote_kill (struct target_ops *ops)
int pid = ptid_get_pid (inferior_ptid);
struct remote_state *rs = get_remote_state ();
+ /* If we're stopped while forking and we haven't followed yet, kill the
+ child task. We need to do this before killing the parent task
+ because if this is a vfork then the parent will be sleeping. */
+ kill_new_fork_children (pid, rs);
+
res = remote_vkill (pid, rs);
if (res == -1 && !(rs->extended && remote_multi_process_p (rs)))
{
}
static void
-remote_mourn (struct target_ops *ops)
-{
- remote_mourn_1 (ops);
-}
-
-/* Worker function for remote_mourn. */
-static void
-remote_mourn_1 (struct target_ops *target)
+remote_mourn (struct target_ops *target)
{
unpush_target (target);
}
static void
-extended_remote_mourn_1 (struct target_ops *target)
+extended_remote_mourn (struct target_ops *target)
{
struct remote_state *rs = get_remote_state ();
}
}
-static void
-extended_remote_mourn (struct target_ops *ops)
-{
- extended_remote_mourn_1 (ops);
-}
-
static int
extended_remote_supports_disable_randomization (struct target_ops *self)
{
/* If running asynchronously, register the target file descriptor
with the event loop. */
if (target_can_async_p ())
- target_async (inferior_event_handler, 0);
+ target_async (1);
/* Disable address space randomization if requested (and supported). */
if (extended_remote_supports_disable_randomization (ops))
len, xfered_len,
&remote_protocol_packets[PACKET_qXfer_btrace_conf]);
+ case TARGET_OBJECT_EXEC_FILE:
+ return remote_read_qxfer (ops, "exec-file", annex, readbuf, offset,
+ len, xfered_len,
+ &remote_protocol_packets[PACKET_qXfer_exec_file]);
+
default:
return TARGET_XFER_E_IO;
}
if (ptid_equal (magic_null_ptid, ptid))
xsnprintf (buf, sizeof buf, "Thread <main>");
else if (rs->extended && remote_multi_process_p (rs))
- xsnprintf (buf, sizeof buf, "Thread %d.%ld",
- ptid_get_pid (ptid), ptid_get_lwp (ptid));
+ if (ptid_get_lwp (ptid) == 0)
+ return normal_pid_to_str (ptid);
+ else
+ xsnprintf (buf, sizeof buf, "Thread %d.%ld",
+ ptid_get_pid (ptid), ptid_get_lwp (ptid));
else
xsnprintf (buf, sizeof buf, "Thread %ld",
ptid_get_lwp (ptid));
struct fio_stat fst;
int read_len;
- if (packet_support (PACKET_vFile_fstat) != PACKET_ENABLE)
+ remote_buffer_add_string (&p, &left, "vFile:fstat:");
+
+ remote_buffer_add_int (&p, &left, fd);
+
+ ret = remote_hostio_send_command (p - rs->buf, PACKET_vFile_fstat,
+ remote_errno, &attachment,
+ &attachment_len);
+ if (ret < 0)
{
+ if (*remote_errno != FILEIO_ENOSYS)
+ return ret;
+
/* Strictly we should return -1, ENOSYS here, but when
"set sysroot remote:" was implemented in August 2008
BFD's need for a stat function was sidestepped with
return 0;
}
- remote_buffer_add_string (&p, &left, "vFile:fstat:");
-
- remote_buffer_add_int (&p, &left, fd);
-
- ret = remote_hostio_send_command (p - rs->buf, PACKET_vFile_fstat,
- remote_errno, &attachment,
- &attachment_len);
- if (ret < 0)
- return ret;
-
read_len = remote_unescape_input ((gdb_byte *) attachment, attachment_len,
(gdb_byte *) &fst, sizeof (fst));
return 0;
}
+/* Return nonzero if the filesystem accessed by the target_fileio_*
+ methods is the local filesystem, zero otherwise. */
+
+static int
+remote_filesystem_is_local (struct target_ops *self)
+{
+ /* Valgrind GDB presents itself as a remote target but works
+ on the local filesystem: it does not implement remote get
+ and users are not expected to set a sysroot. To handle
+ this case we treat the remote filesystem as local if the
+ sysroot is exactly TARGET_SYSROOT_PREFIX and if the stub
+ does not support vFile:open. */
+ if (gdb_sysroot != NULL
+ && strcmp (gdb_sysroot, TARGET_SYSROOT_PREFIX) == 0)
+ {
+ enum packet_support ps = packet_support (PACKET_vFile_open);
+
+ if (ps == PACKET_SUPPORT_UNKNOWN)
+ {
+ int fd, remote_errno;
+
+ /* Try opening a file to probe support. The supplied
+ filename is irrelevant, we only care about whether
+ the stub recognizes the packet or not. */
+ fd = remote_hostio_open (self, "just probing",
+ FILEIO_O_RDONLY, 0700,
+ &remote_errno);
+
+ if (fd >= 0)
+ remote_hostio_close (self, fd, &remote_errno);
+
+ ps = packet_support (PACKET_vFile_open);
+ }
+
+ if (ps == PACKET_DISABLE)
+ {
+ static int warning_issued = 0;
+
+ if (!warning_issued)
+ {
+ warning (_("remote target does not support file"
+ " transfer, attempting to access files"
+ " from local filesystem."));
+ warning_issued = 1;
+ }
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
static int
remote_fileio_errno_to_host (int errnum)
{
remote_hostio_close (find_target_at (process_stratum), fd, &remote_errno);
}
-
-static void *
-remote_bfd_iovec_open (struct bfd *abfd, void *open_closure)
-{
- const char *filename = bfd_get_filename (abfd);
- int fd, remote_errno;
- int *stream;
-
- gdb_assert (remote_filename_p (filename));
-
- fd = remote_hostio_open (find_target_at (process_stratum),
- filename + 7, FILEIO_O_RDONLY, 0, &remote_errno);
- if (fd == -1)
- {
- errno = remote_fileio_errno_to_host (remote_errno);
- bfd_set_error (bfd_error_system_call);
- return NULL;
- }
-
- stream = xmalloc (sizeof (int));
- *stream = fd;
- return stream;
-}
-
-static int
-remote_bfd_iovec_close (struct bfd *abfd, void *stream)
-{
- int fd = *(int *)stream;
- int remote_errno;
-
- xfree (stream);
-
- /* Ignore errors on close; these may happen if the remote
- connection was already torn down. */
- remote_hostio_close (find_target_at (process_stratum), fd, &remote_errno);
-
- /* Zero means success. */
- return 0;
-}
-
-static file_ptr
-remote_bfd_iovec_pread (struct bfd *abfd, void *stream, void *buf,
- file_ptr nbytes, file_ptr offset)
-{
- int fd = *(int *)stream;
- int remote_errno;
- file_ptr pos, bytes;
-
- pos = 0;
- while (nbytes > pos)
- {
- bytes = remote_hostio_pread (find_target_at (process_stratum),
- fd, (gdb_byte *) buf + pos, nbytes - pos,
- offset + pos, &remote_errno);
- if (bytes == 0)
- /* Success, but no bytes, means end-of-file. */
- break;
- if (bytes == -1)
- {
- errno = remote_fileio_errno_to_host (remote_errno);
- bfd_set_error (bfd_error_system_call);
- return -1;
- }
-
- pos += bytes;
- }
-
- return pos;
-}
-
-static int
-remote_bfd_iovec_stat (struct bfd *abfd, void *stream, struct stat *sb)
-{
- int fd = *(int *) stream;
- int remote_errno;
- int result;
-
- result = remote_hostio_fstat (find_target_at (process_stratum),
- fd, sb, &remote_errno);
-
- if (result == -1)
- {
- errno = remote_fileio_errno_to_host (remote_errno);
- bfd_set_error (bfd_error_system_call);
- }
-
- return result;
-}
-
-int
-remote_filename_p (const char *filename)
-{
- return startswith (filename, REMOTE_SYSROOT_PREFIX);
-}
-
-bfd *
-remote_bfd_open (const char *remote_file, const char *target)
-{
- bfd *abfd = gdb_bfd_openr_iovec (remote_file, target,
- remote_bfd_iovec_open, NULL,
- remote_bfd_iovec_pread,
- remote_bfd_iovec_close,
- remote_bfd_iovec_stat);
-
- return abfd;
-}
-
void
remote_file_put (const char *local_file, const char *remote_file, int from_tty)
{
generic_load (name, from_tty);
}
+/* Accepts an integer PID; returns a string representing a file that
+ can be opened on the remote side to get the symbols for the child
+ process. Returns NULL if the operation is not supported. */
+
+static char *
+remote_pid_to_exec_file (struct target_ops *self, int pid)
+{
+ static char *filename = NULL;
+ struct inferior *inf;
+ char *annex = NULL;
+
+ if (packet_support (PACKET_qXfer_exec_file) != PACKET_ENABLE)
+ return NULL;
+
+ if (filename != NULL)
+ xfree (filename);
+
+ inf = find_inferior_pid (pid);
+ if (inf == NULL)
+ internal_error (__FILE__, __LINE__,
+ _("not currently attached to process %d"), pid);
+
+ if (!inf->fake_pid_p)
+ {
+ const int annex_size = 9;
+
+ annex = alloca (annex_size);
+ xsnprintf (annex, annex_size, "%x", pid);
+ }
+
+ filename = target_read_stralloc (¤t_target,
+ TARGET_OBJECT_EXEC_FILE, annex);
+
+ return filename;
+}
+
static void
init_remote_ops (void)
{
remote_ops.to_stop = remote_stop;
remote_ops.to_xfer_partial = remote_xfer_partial;
remote_ops.to_rcmd = remote_rcmd;
+ remote_ops.to_pid_to_exec_file = remote_pid_to_exec_file;
remote_ops.to_log_command = serial_log_command;
remote_ops.to_get_thread_local_address = remote_get_thread_local_address;
remote_ops.to_stratum = process_stratum;
remote_ops.to_supports_multi_process = remote_supports_multi_process;
remote_ops.to_supports_disable_randomization
= remote_supports_disable_randomization;
+ remote_ops.to_filesystem_is_local = remote_filesystem_is_local;
remote_ops.to_fileio_open = remote_hostio_open;
remote_ops.to_fileio_pwrite = remote_hostio_pwrite;
remote_ops.to_fileio_pread = remote_hostio_pread;
+ remote_ops.to_fileio_fstat = remote_hostio_fstat;
remote_ops.to_fileio_close = remote_hostio_close;
remote_ops.to_fileio_unlink = remote_hostio_unlink;
remote_ops.to_fileio_readlink = remote_hostio_readlink;
extended_remote_ops.to_kill = extended_remote_kill;
extended_remote_ops.to_supports_disable_randomization
= extended_remote_supports_disable_randomization;
+ extended_remote_ops.to_follow_fork = remote_follow_fork;
+ extended_remote_ops.to_insert_fork_catchpoint
+ = remote_insert_fork_catchpoint;
+ extended_remote_ops.to_remove_fork_catchpoint
+ = remote_remove_fork_catchpoint;
+ extended_remote_ops.to_insert_vfork_catchpoint
+ = remote_insert_vfork_catchpoint;
+ extended_remote_ops.to_remove_vfork_catchpoint
+ = remote_remove_vfork_catchpoint;
}
static int
/* Don't propogate error information up to the client. Instead let
the client find out about the error by querying the target. */
- rs->async_client_callback (INF_REG_EVENT, rs->async_client_context);
+ inferior_event_handler (INF_REG_EVENT, NULL);
}
static void
}
static void
-remote_async (struct target_ops *ops,
- void (*callback) (enum inferior_event_type event_type,
- void *context),
- void *context)
+remote_async (struct target_ops *ops, int enable)
{
struct remote_state *rs = get_remote_state ();
- if (callback != NULL)
+ if (enable)
{
serial_async (rs->remote_desc, remote_async_serial_handler, rs);
- rs->async_client_callback = callback;
- rs->async_client_context = context;
/* If there are pending events in the stop reply queue tell the
event loop to process them. */
add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_auxv],
"qXfer:auxv:read", "read-aux-vector", 0);
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_exec_file],
+ "qXfer:exec-file:read", "pid-to-exec-file", 0);
+
add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_features],
"qXfer:features:read", "target-features", 0);
add_packet_config_cmd (&remote_protocol_packets[PACKET_hwbreak_feature],
"hwbreak-feature", "hwbreak-feature", 0);
- /* Assert that we've registered commands for all packet configs. */
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_fork_event_feature],
+ "fork-event-feature", "fork-event-feature", 0);
+
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_vfork_event_feature],
+ "vfork-event-feature", "vfork-event-feature", 0);
+
+ /* Assert that we've registered "set remote foo-packet" commands
+ for all packet configs. */
{
int i;