summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPedro Alves <pedro@codesourcery.com>2008-11-25 20:45:05 +0000
committerPedro Alves <pedro@codesourcery.com>2008-11-25 20:45:05 +0000
commit8b11acc6150c279279bc286f4298e79586f171e6 (patch)
tree4c35684a0058c79568c95d5875120c6bf7de3512
parentcad85e9de920700d4e2b58e2f351e802ac068ace (diff)
downloadgdb-8b11acc6150c279279bc286f4298e79586f171e6.tar.gz
2008-11-25 Pedro Alves <pedro@codesourcery.com>
2008-11-25 Pedro Alves <pedro@codesourcery.com> * linux-fork.c (detach_fork): Delete declaration. (_initialize_linux_fork): Move "set detach-on-fork" command to ... * infrun.c (_initialize_infrun): ... here. * inferior.h (detach_fork): Declare. 2008-11-10 Pedro Alves <pedro@codesourcery.com> * remote.c (read_ptid): If we don't know about any inferior yet, use the pid of magic_null_ptid. (remote_start_remote): Don't set inferior_ptid to magic_null_ptid here. 2008-10-14 Pedro Alves <pedro@codesourcery.com> * remote.c (remote_start_remote): Mask async mode while collecting the initial event, use notice_new_inferior. 2008-10-12 Pedro Alves <pedro@codesourcery.com> * infcmd.c (attach_command_post_wait): Set the inferior exec here. (attach_command): Don't set the inferior exec here. (notice_new_inferior): New. * inferior.h (notice_new_inferior): Declare. * remote.c (notice_new_inferiors): Add `stopping' argument. Add the inferior before adding the threads. Call notice_new_inferior. (record_currthread): Adjust. (remote_threads_info): Add the inferior before adding the thread. Call notice_new_inferior. 2008-10-09 Pedro Alves <pedro@codesourcery.com> * remote.c (notice_new_inferiors): If there's only one exec, set it in the new inferior. (set_thread): If setting the thread failed, assume the thread has terminated. 2008-09-17 Pedro Alves <pedro@codesourcery.com> * inferior.c (delete_inferior_1): Free the inferior after freeing its threads. 2008-09-16 Pedro Alves <pedro@codesourcery.com> * inferior.h (discard_all_inferiors): Declare. * inferior.c (delete_inferior): Rename to... (delete_inferior_1): ...this. Add 'silent' argument. If this inferior is has pid not zero, delete its threads. (delete_inferior): New, as wrapper around delete_inferior_1. (delete_inferior_by_pid_1): Reimplement. (discard_all_inferiors): New. 2008-09-15 Pedro Alves <pedro@codesourcery.com> * remote.c (extended_remote_attach_1): Don't set target_attach_no_wait. 2008-09-15 Pedro Alves <pedro@codesourcery.com> * frame.c (get_current_frame, has_stack_frames): Check for null_ptid. * top.c (execute_command): Likewise. 2008-08-29 Pedro Alves <pedro@codesourcery.com> * inferior.c (have_real_inferiors): New. * inferior.h (have_real_inferiors): Declare. * remote.c (extended_remote_mourn_1): Use it. * top.c (quit_target): Use it. 2008-08-28 Pedro Alves <pedro@codesourcery.com> * remote.c (parse_stop_reply): Handle Y;exec. 2008-08-28 Pedro Alves <pedro@codesourcery.com> * infcmd.c (struct exec_file_attach_wrapper_args): New. (exec_file_attach_wrapper): New. (attach_command_post_wait): If there's a sysroot, prepend it to the target reported exec file path. Continue attaching to the inferior event if attaching to the exec file fails. * remote.c (remote_pid_to_exec_file): Rebustify. Expect "QExecFile:PID;" in the reply. 2008-08-28 Pedro Alves <pedro@codesourcery.com> * remote.c (record_currthread): If setting the current thread to minus_one_ptid, don't pass that to the stub. (remote_parse_stop_reply): Handle 'Y' stop reply. (remote_wait_as): Likewise. If remote process exited, invalidate the current thread. (remote_detach_pid): New. (remote_follow_fork): New. (init_remote_ops): Register it. 2008-08-28 Pedro Alves <pedro@codesourcery.com> * remote.c (remote_pid_to_exec_file): New. (init_remote_ops): Register it. 2008-08-28 Pedro Alves <pedro@codesourcery.com> * infcmd.c (kill_if_already_running): If target supports multi-process, allow multi-runs. 2008-08-28 Pedro Alves <pedro@codesourcery.com> * remote.c (extended_remote_create_inferior_1): Don't clear the thread list.
-rw-r--r--gdb/ChangeLog114
-rw-r--r--gdb/exec.c2
-rw-r--r--gdb/frame.c5
-rw-r--r--gdb/infcmd.c162
-rw-r--r--gdb/inferior.c100
-rw-r--r--gdb/inferior.h12
-rw-r--r--gdb/infrun.c6
-rw-r--r--gdb/linux-fork.c10
-rw-r--r--gdb/remote.c458
-rw-r--r--gdb/stack.c3
-rw-r--r--gdb/top.c4
11 files changed, 747 insertions, 129 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 88de57eb120..488453081cf 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,5 +1,119 @@
2008-11-25 Pedro Alves <pedro@codesourcery.com>
+ 2008-11-25 Pedro Alves <pedro@codesourcery.com>
+
+ * linux-fork.c (detach_fork): Delete declaration.
+ (_initialize_linux_fork): Move "set detach-on-fork"
+ command to ...
+ * infrun.c (_initialize_infrun): ... here.
+ * inferior.h (detach_fork): Declare.
+
+ 2008-11-10 Pedro Alves <pedro@codesourcery.com>
+
+ * remote.c (read_ptid): If we don't know about any inferior yet,
+ use the pid of magic_null_ptid.
+ (remote_start_remote): Don't set inferior_ptid to magic_null_ptid
+ here.
+
+ 2008-10-14 Pedro Alves <pedro@codesourcery.com>
+
+ * remote.c (remote_start_remote): Mask async mode while collecting
+ the initial event, use notice_new_inferior.
+
+ 2008-10-12 Pedro Alves <pedro@codesourcery.com>
+
+ * infcmd.c (attach_command_post_wait): Set the inferior exec here.
+ (attach_command): Don't set the inferior exec here.
+ (notice_new_inferior): New.
+ * inferior.h (notice_new_inferior): Declare.
+ * remote.c (notice_new_inferiors): Add `stopping' argument. Add
+ the inferior before adding the threads. Call notice_new_inferior.
+ (record_currthread): Adjust.
+ (remote_threads_info): Add the inferior before adding the thread.
+ Call notice_new_inferior.
+
+ 2008-10-09 Pedro Alves <pedro@codesourcery.com>
+
+ * remote.c (notice_new_inferiors): If there's only one exec, set
+ it in the new inferior.
+ (set_thread): If setting the thread failed, assume the thread has
+ terminated.
+
+ 2008-09-17 Pedro Alves <pedro@codesourcery.com>
+
+ * inferior.c (delete_inferior_1): Free the inferior after freeing
+ its threads.
+
+ 2008-09-16 Pedro Alves <pedro@codesourcery.com>
+
+ * inferior.h (discard_all_inferiors): Declare.
+ * inferior.c (delete_inferior): Rename to...
+ (delete_inferior_1): ...this. Add 'silent' argument. If this
+ inferior is has pid not zero, delete its threads.
+ (delete_inferior): New, as wrapper around delete_inferior_1.
+ (delete_inferior_by_pid_1): Reimplement.
+ (discard_all_inferiors): New.
+
+ 2008-09-15 Pedro Alves <pedro@codesourcery.com>
+
+ * remote.c (extended_remote_attach_1): Don't set target_attach_no_wait.
+
+ 2008-09-15 Pedro Alves <pedro@codesourcery.com>
+
+ * frame.c (get_current_frame, has_stack_frames): Check for
+ null_ptid.
+ * top.c (execute_command): Likewise.
+
+ 2008-08-29 Pedro Alves <pedro@codesourcery.com>
+
+ * inferior.c (have_real_inferiors): New.
+ * inferior.h (have_real_inferiors): Declare.
+ * remote.c (extended_remote_mourn_1): Use it.
+ * top.c (quit_target): Use it.
+
+ 2008-08-28 Pedro Alves <pedro@codesourcery.com>
+
+ * remote.c (parse_stop_reply): Handle Y;exec.
+
+ 2008-08-28 Pedro Alves <pedro@codesourcery.com>
+
+ * infcmd.c (struct exec_file_attach_wrapper_args): New.
+ (exec_file_attach_wrapper): New.
+ (attach_command_post_wait): If there's a sysroot, prepend it to
+ the target reported exec file path. Continue attaching to the
+ inferior event if attaching to the exec file fails.
+
+ * remote.c (remote_pid_to_exec_file): Rebustify. Expect
+ "QExecFile:PID;" in the reply.
+
+ 2008-08-28 Pedro Alves <pedro@codesourcery.com>
+
+ * remote.c (record_currthread): If setting the current thread to
+ minus_one_ptid, don't pass that to the stub.
+ (remote_parse_stop_reply): Handle 'Y' stop reply.
+ (remote_wait_as): Likewise. If remote process exited, invalidate
+ the current thread.
+ (remote_detach_pid): New.
+ (remote_follow_fork): New.
+ (init_remote_ops): Register it.
+
+ 2008-08-28 Pedro Alves <pedro@codesourcery.com>
+
+ * remote.c (remote_pid_to_exec_file): New.
+ (init_remote_ops): Register it.
+
+ 2008-08-28 Pedro Alves <pedro@codesourcery.com>
+
+ * infcmd.c (kill_if_already_running): If target supports
+ multi-process, allow multi-runs.
+
+ 2008-08-28 Pedro Alves <pedro@codesourcery.com>
+
+ * remote.c (extended_remote_create_inferior_1): Don't clear the
+ thread list.
+
+2008-11-25 Pedro Alves <pedro@codesourcery.com>
+
* inferior.c (itset_member): Fix typo again.
2008-11-24 Tom Tromey <tromey@redhat.com>
diff --git a/gdb/exec.c b/gdb/exec.c
index cf4e844f16f..ffa283e48bd 100644
--- a/gdb/exec.c
+++ b/gdb/exec.c
@@ -151,7 +151,7 @@ exec_close (int quitting)
{
/* We don't free objfiles because other code does it. */
if (ex->inferior)
- delete_inferior (ex->inferior->pid);
+ delete_inferior_id (ex->inferior->num);
}
#if 0
VEC_block_remove (exec_p, execs, 0, VEC_length (exec_p, execs));
diff --git a/gdb/frame.c b/gdb/frame.c
index dfd6b2b35f9..52f738ad056 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -982,6 +982,8 @@ get_current_frame (void)
error (_("No stack."));
if (!target_has_memory)
error (_("No memory."));
+ if (ptid_equal (inferior_ptid, null_ptid))
+ error (_("No current inferior."));
if (is_executing (inferior_ptid))
error (_("Target is executing."));
@@ -1011,6 +1013,9 @@ has_stack_frames (void)
if (!target_has_registers || !target_has_stack || !target_has_memory)
return 0;
+ if (ptid_equal (inferior_ptid, null_ptid))
+ return 0;
+
/* If the current thread is executing, don't try to read from
it. */
if (is_executing (inferior_ptid))
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index a9bfd3e6cb0..5d490165bd1 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -553,11 +553,14 @@ kill_if_already_running (int from_tty)
restart it. */
target_require_runnable ();
- if (from_tty
- && !query ("The program being debugged has been started already.\n\
+ if (!target_supports_multi_process ())
+ {
+ if (from_tty
+ && !query ("The program being debugged has been started already.\n\
Start it from the beginning? "))
- error (_("Program not restarted."));
- target_kill ();
+ error (_("Program not restarted."));
+ target_kill ();
+ }
}
}
@@ -574,6 +577,7 @@ run_command_1 (char *args, int from_tty, int tbreak_at_main)
kill_if_already_running (from_tty);
+ /* This is bad. */
init_wait_for_inferior ();
clear_breakpoint_hit_counts ();
@@ -2206,6 +2210,23 @@ proceed_after_attach (int pid)
do_cleanups (old_chain);
}
+struct exec_file_attach_wrapper_args
+{
+ char *path;
+ int from_tty;
+};
+
+static int
+exec_file_attach_wrapper (struct ui_out *ui_out, void *args)
+{
+ struct exec_file_attach_wrapper_args *a = args;
+
+ exec_file_attach (a->path, a->from_tty);
+ symbol_file_add_main (a->path, a->from_tty);
+
+ return 0;
+}
+
/*
* TODO:
* Should save/restore the tty state since it might be that the
@@ -2241,19 +2262,47 @@ attach_command_post_wait (char *args, int from_tty, int async_exec)
exec_file = target_pid_to_exec_file (PIDGET (inferior_ptid));
if (exec_file)
{
- /* It's possible we don't have a full path, but rather just a
- filename. Some targets, such as HP-UX, don't provide the
- full path, sigh.
-
- Attempt to qualify the filename against the source path.
- (If that fails, we'll just fall back on the original
- filename. Not much more we can do...)
- */
- if (!source_full_path_of (exec_file, &full_exec_path))
- full_exec_path = savestring (exec_file, strlen (exec_file));
-
- exec_file_attach (full_exec_path, from_tty);
- symbol_file_add_main (full_exec_path, from_tty);
+ struct exec_file_attach_wrapper_args args;
+
+ if (gdb_sysroot && *gdb_sysroot)
+ {
+ char *name = xmalloc (strlen (gdb_sysroot)
+ + strlen (exec_file)
+ + 1);
+ strcpy (name, gdb_sysroot);
+ strcat (name, exec_file);
+ full_exec_path = name;
+ }
+ else
+ {
+ /* It's possible we don't have a full path, but rather just a
+ filename. Some targets, such as HP-UX, don't provide the
+ full path, sigh.
+
+ Attempt to qualify the filename against the source path.
+ (If that fails, we'll just fall back on the original
+ filename. Not much more we can do...)
+ */
+ if (!source_full_path_of (exec_file, &full_exec_path))
+ full_exec_path = savestring (exec_file, strlen (exec_file));
+ }
+
+ args.path = full_exec_path;
+ args.from_tty = from_tty;
+
+ /* Don't let failing to find symbols prevent trying to
+ finish the attach. */
+ catch_exceptions (uiout, exec_file_attach_wrapper, &args,
+ RETURN_MASK_ERROR);
+
+ /* Try to use the exec we (hopefully) just pulled in as the
+ inferior's exec. */
+ if (!inferior->exec)
+ {
+ exec = find_exec_by_name (full_exec_path);
+ if (exec)
+ set_inferior_exec (inferior, exec);
+ }
}
}
else
@@ -2262,6 +2311,14 @@ attach_command_post_wait (char *args, int from_tty, int async_exec)
reread_symbols ();
}
+ /* As a heuristic, if there is no exec assigned to the attached
+ inferior, but only one exec known to GDB, guess that it is the
+ exec for the the process just attached. (If GDB has guessed
+ wrong, it will be up to the user to use set-exec to fix
+ matters.) */
+ if (!inferior->exec && number_of_execs () == 1)
+ set_inferior_exec (inferior, first_exec);
+
/* Take any necessary post-attaching actions for this platform. */
target_post_attach (PIDGET (inferior_ptid));
@@ -2275,7 +2332,7 @@ attach_command_post_wait (char *args, int from_tty, int async_exec)
/* The user requested an `attach&', so be sure to leave threads
that didn't get a signal running. */
- /* Immediatelly resume all suspended threads of this inferior,
+ /* Immediately resume all suspended threads of this inferior,
and this inferior only. This should have no effect on
already running threads. If a thread has been stopped with a
signal, leave it be. */
@@ -2395,6 +2452,8 @@ attach_command (char *args, int from_tty)
/* Set up execution context to know that we should return from
wait_for_inferior as soon as the target reports a stop. */
+
+ /* NOTE, NOTE, this is wrong in multi-process... */
init_wait_for_inferior ();
clear_proceed_status ();
@@ -2446,19 +2505,64 @@ attach_command (char *args, int from_tty)
attach_command_post_wait (args, from_tty, async_exec);
- /* As a heuristic, if there is no exec assigned to the attached
- inferior, but only one exec known to GDB, guess that it is the
- exec for the the process just attached. (If GDB has guessed
- wrong, it will be up to the user to use set-exec to fix
- matters.) */
- {
- struct inferior *inferior = current_inferior ();
+}
+
+/* We had just found out that the target was already attached to an
+ inferior. PTID points at a thread of this new inferior, that is
+ the most likelly to be stopped right now, but not necessarily so.
+ The new inferior has already been added to the inferior list at
+ this point. */
+
+void
+notice_new_inferior (ptid_t ptid, int stopping, int from_tty)
+{
+ struct cleanup* old_chain;
+ struct inferior *inferior;
+ int async_exec;
+
+ old_chain = make_cleanup (null_cleanup, NULL);
+
+ /* If in non-stop, leave threads as running as they were. If
+ they're stopped for some reason other than us telling it to, it
+ should report a signal != TARGET_SIGNAL_0. */
+ async_exec = non_stop;
+
+ if (!ptid_equal (inferior_ptid, null_ptid))
+ make_cleanup_restore_current_thread ();
+
+ switch_to_thread (ptid);
+
+ inferior = current_inferior ();
+
+ if (is_executing (inferior_ptid))
+ {
+ target_stop (inferior_ptid);
+
+ if (!non_stop)
+ inferior->stop_soon = STOP_QUIETLY_REMOTE;
- if (!inferior->exec && number_of_execs () == 1)
- set_inferior_exec (inferior, first_exec);
- }
+ if (target_can_async_p ())
+ {
+ /* sync_execution mode. Wait for stop. */
+ struct attach_command_continuation_args *a;
- discard_cleanups (back_to);
+ a = xmalloc (sizeof (*a));
+ a->args = xstrdup ("");
+ a->from_tty = from_tty;
+ a->async_exec = async_exec;
+ add_inferior_continuation (attach_command_continuation, a,
+ attach_command_continuation_free_args);
+
+ do_cleanups (old_chain);
+ return;
+ }
+ else
+ wait_for_inferior (0);
+ }
+
+ attach_command_post_wait ("" /* args */, from_tty, !stopping);
+
+ do_cleanups (old_chain);
}
/*
diff --git a/gdb/inferior.c b/gdb/inferior.c
index 28da12df72b..096962d25ab 100644
--- a/gdb/inferior.c
+++ b/gdb/inferior.c
@@ -94,6 +94,8 @@ add_inferior_silent (int pid)
memset (inf, 0, sizeof (*inf));
inf->pid = pid;
+ inf->stop_soon = NO_STOP_QUIETLY;
+
inf->num = ++highest_inferior_num;
inf->next = inferior_list;
inferior_list = inf;
@@ -138,16 +140,17 @@ delete_thread_of_inferior (struct thread_info *tp, void *data)
/* If SILENT then be quiet -- don't announce a inferior death, or the
exit of its threads. */
-static void
-delete_inferior_1 (int pid, int silent)
+
+void
+delete_inferior_struct (struct inferior *inftodel, int silent)
{
struct inferior *inf, *infprev;
- struct delete_thread_of_inferior_arg arg = { pid, silent };
+ struct delete_thread_of_inferior_arg arg;
infprev = NULL;
for (inf = inferior_list; inf; infprev = inf, inf = inf->next)
- if (inf->pid == pid)
+ if (inf == inftodel)
break;
if (!inf)
@@ -158,38 +161,42 @@ delete_inferior_1 (int pid, int silent)
else
inferior_list = inf->next;
- free_inferior (inf);
-
- arg.pid = pid;
- arg.silent = silent;
-
- iterate_over_threads (delete_thread_of_inferior, &arg);
+ if (inf->pid != 0)
+ {
+ arg.pid = inf->pid;
+ arg.silent = silent;
+ iterate_over_threads (delete_thread_of_inferior, &arg);
+ }
- observer_notify_inferior_exit (pid);
+ observer_notify_inferior_exit (inf->pid);
+ free_inferior (inf);
}
void
-delete_inferior (int pid)
+delete_inferior_id (int num)
{
- delete_inferior_1 (pid, 0);
-
- if (print_inferior_events)
- printf_unfiltered (_("[Inferior %d exited]\n"), pid);
+ struct inferior *inf = find_inferior_id (num);
+ delete_inferior_struct (inf, 0);
}
void
-delete_inferior_silent (int pid)
+delete_inferior (int pid)
{
- delete_inferior_1 (pid, 1);
+ struct inferior *inf = find_inferior_pid (pid);
+ if (inf)
+ {
+ delete_inferior_struct (inf, 0);
+ if (print_inferior_events)
+ printf_unfiltered (_("[Inferior %d exited]\n"), pid);
+ }
}
void
-detach_inferior (int pid)
+delete_inferior_silent (int pid)
{
- delete_inferior_1 (pid, 1);
-
- if (print_inferior_events)
- printf_unfiltered (_("[Inferior %d detached]\n"), pid);
+ struct inferior *inf = find_inferior_pid (pid);
+ if (inf)
+ delete_inferior_struct (inf, 1);
}
void
@@ -200,7 +207,20 @@ discard_all_inferiors (void)
for (inf = inferior_list; inf; inf = infnext)
{
infnext = inf->next;
- delete_inferior_silent (inf->pid);
+ if (inf->pid != 0)
+ delete_inferior_struct (inf, 1);
+ }
+}
+
+void
+detach_inferior (int pid)
+{
+ struct inferior *inf = find_inferior_pid (pid);
+ if (inf)
+ {
+ delete_inferior_struct (inf, 1);
+ if (print_inferior_events)
+ printf_unfiltered (_("[Inferior %d detached]\n"), pid);
}
}
@@ -309,6 +329,18 @@ have_inferiors (void)
return inferior_list != NULL;
}
+/* Returns true if there are any non-proto inferiors. */
+int
+have_real_inferiors (void)
+{
+ struct inferior *inf;
+
+ for (inf = inferior_list; inf; inf = inf->next)
+ if (inf->pid != 0)
+ return 1;
+ return 0;
+}
+
int
number_of_inferiors (void)
{
@@ -383,15 +415,21 @@ print_inferior (struct ui_out *uiout, int requested_inferior)
ui_out_field_string (uiout, "io_terminal", "term=Y");
}
}
+
#if 0
- extra_info = target_extra_inferior_info (inf);
- if (extra_info)
+ /* Only query the target about real inferiors. */
+ if (inf->pid != 0)
{
- ui_out_text (uiout, " (");
- ui_out_field_string (uiout, "details", extra_info);
- ui_out_text (uiout, ")");
+ extra_info = target_extra_inferior_info (inf);
+ if (extra_info)
+ {
+ ui_out_text (uiout, " (");
+ ui_out_field_string (uiout, "details", extra_info);
+ ui_out_text (uiout, ")");
+ }
}
#endif
+
ui_out_text (uiout, "\n");
do_cleanups (chain2);
}
@@ -491,11 +529,9 @@ remove_inferior_command (char *args, int from_tty)
for (ix = 0; VEC_iterate (itset_entry, itset->inferiors, ix, entry); ++ix)
{
-#if 0
if (entry->inferior->removable)
- delete_inferior (entry->inferior);
+ delete_inferior_struct (entry->inferior, 0);
/* (should remove threads?) */
-#endif
}
}
diff --git a/gdb/inferior.h b/gdb/inferior.h
index c951026f3e2..ae60e2e9089 100644
--- a/gdb/inferior.h
+++ b/gdb/inferior.h
@@ -274,6 +274,8 @@ extern void interrupt_target_1 (int all_threads);
extern void detach_command (char *, int);
+extern void notice_new_inferior (ptid_t, int, int);
+
/* Address at which inferior stopped. */
extern CORE_ADDR stop_pc;
@@ -366,6 +368,8 @@ extern int suppress_stop_observer;
/* When set, no calls to target_resumed observer will be made. */
extern int suppress_resume_observer;
+extern int detach_fork;
+
/* Possible values for gdbarch_call_dummy_location. */
#define ON_STACK 1
@@ -532,6 +536,9 @@ extern void delete_inferior_silent (int pid);
/* Delete an existing inferior list entry, due to inferior detaching. */
extern void detach_inferior (int pid);
+/* Delete inferior with GDB inferior id NUM. */
+extern void delete_inferior_id (int num);
+
/* Get rid of all inferiors. */
extern void discard_all_inferiors (void);
@@ -550,9 +557,12 @@ extern int in_inferior_list (int pid);
not the system's). */
extern int valid_inferior_id (int num);
-/* Search function to lookup a inferior by target 'pid'. */
+/* Search function to lookup an inferior by target 'pid'. */
extern struct inferior *find_inferior_pid (int pid);
+/* Search function to lookup an inferior by GDB 'num'. */
+extern struct inferior *find_inferior_id (int num);
+
/* Inferior iterator function.
Calls a callback function once for each inferior, so long as the
diff --git a/gdb/infrun.c b/gdb/infrun.c
index a459c97f6b6..cd809edb661 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -5307,6 +5307,12 @@ By default, the debugger will follow the parent process."),
show_follow_fork_mode_string,
&setlist, &showlist);
+ add_setshow_boolean_cmd ("detach-on-fork", class_run, &detach_fork, _("\
+Set whether gdb will detach the child of a fork."), _("\
+Show whether gdb will detach the child of a fork."), _("\
+Tells gdb whether to detach the child of a fork."),
+ NULL, NULL, &setlist, &showlist);
+
add_setshow_enum_cmd ("scheduler-locking", class_run,
scheduler_enums, &scheduler_mode, _("\
Set mode for locking scheduler during execution."), _("\
diff --git a/gdb/linux-fork.c b/gdb/linux-fork.c
index 498db30189b..c8aee9119d0 100644
--- a/gdb/linux-fork.c
+++ b/gdb/linux-fork.c
@@ -34,8 +34,6 @@
#include "gdb_dirent.h"
#include <ctype.h>
-extern int detach_fork;
-
struct fork_info *fork_list;
static int highest_fork_num;
@@ -670,14 +668,6 @@ _initialize_linux_fork (void)
{
init_fork_list ();
- /* Set/show detach-on-fork: user-settable mode. */
-
- add_setshow_boolean_cmd ("detach-on-fork", class_obscure, &detach_fork, _("\
-Set whether gdb will detach the child of a fork."), _("\
-Show whether gdb will detach the child of a fork."), _("\
-Tells gdb whether to detach the child of a fork."),
- NULL, NULL, &setlist, &showlist);
-
/* Set/show restart-auto-finish: user-settable count. Causes the
first "restart" of a fork to do some number of "finish" commands
before returning to user.
diff --git a/gdb/remote.c b/gdb/remote.c
index 47eb98213ab..0d1d79f06d3 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -1126,53 +1126,87 @@ static ptid_t general_thread;
static ptid_t continue_thread;
static void
-notice_new_inferiors (ptid_t currthread)
+notice_new_inferiors (ptid_t currthread, int running)
{
+ struct remote_state *rs = get_remote_state ();
+ struct inferior *inf = NULL;
+
/* If this is a new thread, add it to GDB's thread list.
If we leave it up to WFI to do this, bad things will happen. */
if (in_thread_list (currthread) && is_exited (currthread))
{
+ int pid = ptid_get_pid (currthread);
+ if (!in_inferior_list (pid))
+ {
+ inf = add_inferior (pid);
+
+ /* This may be the first inferior we hear about. */
+ if (!target_has_execution)
+ {
+ if (rs->extended)
+ target_mark_running (&extended_remote_ops);
+ else
+ target_mark_running (&remote_ops);
+ }
+ }
+
/* We're seeing an event on a thread id we knew had exited.
This has to be a new thread reusing the old id. Add it. */
add_thread (currthread);
- return;
- }
- if (!in_thread_list (currthread))
+ set_executing (currthread, running);
+ set_running (currthread, running);
+ }
+ else if (!in_thread_list (currthread))
{
if (ptid_equal (pid_to_ptid (ptid_get_pid (currthread)), inferior_ptid))
{
/* inferior_ptid has no thread member yet. This can happen
with the vAttach -> remote_wait,"TAAthread:" path if the
stub doesn't support qC. This is the first stop reported
- after an attach, so this is the main thread. Update the
- ptid in the thread list. */
- thread_change_ptid (inferior_ptid, currthread);
- return;
+ after an attach, so this is the main thread. */
+ thread_change_ptid (inferior_ptid, currthread);
}
-
- if (ptid_equal (magic_null_ptid, inferior_ptid))
+ else if (ptid_equal (magic_null_ptid, inferior_ptid))
{
/* inferior_ptid is not set yet. This can happen with the
vRun -> remote_wait,"TAAthread:" path if the stub
doesn't support qC. This is the first stop reported
after an attach, so this is the main thread. Update the
ptid in the thread list. */
- thread_change_ptid (inferior_ptid, currthread);
- return;
+ thread_change_ptid (inferior_ptid, currthread);
}
+ else
+ {
+ /* When connecting to a target remote, or to a target
+ extended-remote which already was debugging an inferior, we
+ may not know about it yet. Add it before adding its child
+ thread, so notifications are emitted in a sensible order. */
+ if (!in_inferior_list (ptid_get_pid (currthread)))
+ {
+ inf = add_inferior (ptid_get_pid (currthread));
- /* When connecting to a target remote, or to a target
- extended-remote which already was debugging an inferior, we
- may not know about it yet. Add it before adding its child
- thread, so notifications are emitted in a sensible order. */
- if (!in_inferior_list (ptid_get_pid (currthread)))
- add_inferior (ptid_get_pid (currthread));
+ /* This may be the first inferior we hear about. */
+ if (!target_has_execution)
+ {
+ if (rs->extended)
+ target_mark_running (&extended_remote_ops);
+ else
+ target_mark_running (&remote_ops);
+ }
+ }
- /* This is really a new thread. Add it. */
- add_thread (currthread);
+ /* This is really a new thread. Add it. */
+ add_thread (currthread);
+ set_executing (currthread, running);
+ set_running (currthread, running);
+ }
}
+
+ if (inf)
+ /* Do whatever is needed to do with a new inferior. */
+ notice_new_inferior (currthread, !running, 0);
}
/* Call this function as a result of
@@ -1190,7 +1224,7 @@ record_currthread (ptid_t currthread)
/* We're just invalidating the local thread mirror. */
return;
- notice_new_inferiors (currthread);
+ notice_new_inferiors (currthread, 0);
}
static char *last_pass_packet;
@@ -1279,6 +1313,23 @@ set_thread (struct ptid ptid, int gen)
write_ptid (buf, endbuf, ptid);
putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
+
+ if (rs->buf[0]
+ && strcmp (rs->buf, "OK") != 0)
+ {
+ /* If we get an error setting a thread, it's because it is no
+ longer valid. */
+ if (!ptid_equal (minus_one_ptid, ptid)
+ && !ptid_equal (null_ptid, ptid)
+ && !ptid_equal (any_thread_ptid, ptid)
+ && !ptid_is_pid (ptid))
+ {
+ int num = pid_to_thread_id (ptid);
+ delete_thread (ptid);
+ error (_("Thread ID %d has terminated."), num);
+ }
+ }
+
if (gen)
general_thread = ptid;
else
@@ -1525,8 +1576,13 @@ read_ptid (char *buf, char **obuf)
pp = unpack_varlen_hex (p, &tid);
/* Since the stub is not sending a process id, then default to
- what's in inferior_ptid. */
- pid = ptid_get_pid (inferior_ptid);
+ what's in inferior_ptid, unless it's null at this point. If so,
+ then since there's no way to know the pid of the reported
+ threads, use the magic number. */
+ if (ptid_equal (inferior_ptid, null_ptid))
+ pid = ptid_get_pid (magic_null_ptid);
+ else
+ pid = ptid_get_pid (inferior_ptid);
if (obuf)
*obuf = pp;
@@ -2148,27 +2204,15 @@ remote_threads_info (void)
do
{
new_thread = read_ptid (bufp, &bufp);
- if (!ptid_equal (new_thread, null_ptid)
- && (!in_thread_list (new_thread)
- || is_exited (new_thread)))
+ if (!ptid_equal (new_thread, null_ptid))
{
- /* When connected to a multi-process aware stub,
- "info threads" may show up threads of
- inferiors we didn't know about yet. Add them
- now, and before adding any of its child
- threads, so notifications are emitted in a
- sensible order. */
- if (!in_inferior_list (ptid_get_pid (new_thread)))
- add_inferior (ptid_get_pid (new_thread));
-
- add_thread (new_thread);
-
/* In non-stop mode, we assume new found threads
- are running until we proven otherwise with a
+ are running until proven otherwise with a
stop reply. In all-stop, we can only get
here if all threads are stopped. */
- set_executing (new_thread, non_stop ? 1 : 0);
- set_running (new_thread, non_stop ? 1 : 0);
+ int running = non_stop ? 1 : 0;
+
+ notice_new_inferiors (new_thread, running);
}
}
while (*bufp++ == ','); /* comma-separated list */
@@ -2576,12 +2620,6 @@ remote_start_remote (struct ui_out *uiout, void *opaque)
The '?' query below will then tell us about which threads are
stopped. */
- /* If we're not using the multi-process extensions, there's no
- way to know the pid of the reported threads; use the magic
- number. */
- if (!remote_multi_process_p (rs))
- inferior_ptid = magic_null_ptid;
-
remote_threads_info ();
}
else if (rs->non_stop_aware)
@@ -2601,6 +2639,8 @@ remote_start_remote (struct ui_out *uiout, void *opaque)
if (!non_stop)
{
+ int saved_async = 0;
+
if (rs->buf[0] == 'W' || rs->buf[0] == 'X')
{
if (args->extended_p)
@@ -2638,11 +2678,12 @@ remote_start_remote (struct ui_out *uiout, void *opaque)
/* Now, if we have thread information, update inferior_ptid. */
inferior_ptid = remote_current_thread (inferior_ptid);
- add_inferior (ptid_get_pid (inferior_ptid));
+ inf = add_inferior (ptid_get_pid (inferior_ptid));
/* Always add the main thread. */
add_thread_silent (inferior_ptid);
+ /* TODO: This should be done in notice_new_inferiors. */
get_offsets (); /* Get text, data & bss offsets. */
/* Use the previously fetched status. */
@@ -2651,7 +2692,37 @@ remote_start_remote (struct ui_out *uiout, void *opaque)
rs->cached_wait_status = 1;
immediate_quit--;
- start_remote (args->from_tty); /* Initialize gdb process mechanisms. */
+ init_wait_for_inferior ();
+
+ /* We know the inferior is stopped already, as we have a pending
+ wait status. We need to force this event through
+ handle_inferior_event. Pretend the inferior is running, so
+ notice_new_inferior will force a target_stop and a
+ target_wait, to collect the event. remote_stop_as
+ (target_stop) will notice we have a cached wait status and
+ will not pass the request to the remote. */
+ {
+ struct cleanup *old_chain;
+ old_chain = make_cleanup_restore_integer (&suppress_resume_observer);
+
+ /* Don't output '*running'. */
+ suppress_resume_observer = 1;
+
+ set_executing (inferior_ptid, 1);
+ set_running (inferior_ptid, 1);
+
+ suppress_resume_observer = 0;
+ }
+
+ /* Collect the pending event synchronously, instead of going
+ through the event loop. */
+ if (target_can_async_p ())
+ saved_async = target_async_mask (0);
+
+ notice_new_inferior (inferior_ptid, 1, args->from_tty);
+
+ if (saved_async)
+ target_async_mask (saved_async);
}
else
{
@@ -2710,10 +2781,13 @@ remote_start_remote (struct ui_out *uiout, void *opaque)
if (ptid_equal (inferior_ptid, minus_one_ptid))
error (_("remote didn't report the current thread in non-stop mode"));
+ /* TODO: This should be done whenever we notice a new
+ inferior. */
get_offsets (); /* Get text, data & bss offsets. */
/* In non-stop mode, any cached wait status will be stored in
- the stop reply queue. */
+ the stop reply queue. Also, we can only reach here if
+ threads were found. */
gdb_assert (wait_status == NULL);
}
@@ -4384,7 +4458,65 @@ Packet: '%s'\n"),
else
error (_("unknown stop reply packet: %s"), buf);
event->ptid = pid_to_ptid (pid);
+ break;
}
+ case 'Y':
+ {
+ char *p = buf + 1;
+ if (*p != ';')
+ error (_("unknown stop reply packet: %s"), buf);
+
+ p++;
+ if (strncmp (p, "fork;", 5) == 0)
+ {
+ p += 5;
+ event->ws.kind = TARGET_WAITKIND_FORKED;
+ }
+ else if (strncmp (p, "vfork;", 6) == 0)
+ {
+ p += 6;
+ event->ws.kind = TARGET_WAITKIND_VFORKED;
+ }
+ else if (strncmp (p, "exec;", 5) == 0)
+ {
+ p += 5;
+ event->ws.kind = TARGET_WAITKIND_EXECD;
+ }
+ else
+ error (_("unknown stop reply packet: %s"), buf);
+
+ event->ptid = read_ptid (p, &p);
+
+ if (*p != ';')
+ error (_("unknown stop reply packet: %s"), buf);
+ p++;
+
+ if (event->ws.kind == TARGET_WAITKIND_EXECD)
+ {
+ struct cleanup *old_chain;
+ int result;
+ char *buf;
+
+ buf = xmalloc (strlen (p) + 1);
+ result = hex2bin (p, (gdb_byte *) buf, strlen (p));
+ buf [result] = '\0';
+ event->ws.value.execd_pathname = buf;
+
+ /* At this point, all inserted breakpoints are gone.
+ Doing this as soon as we detect an exec prevents the
+ badness of deleting a breakpoint writing the current
+ "shadow contents" to lift the bp. That shadow is NOT
+ valid after an exec. */
+
+ old_chain = save_inferior_ptid ();
+ inferior_ptid = event->ptid;
+ mark_breakpoints_out ();
+ do_cleanups (old_chain);
+ }
+ else
+ event->ws.value.related_pid = read_ptid (p, &p);
+ }
+
break;
}
@@ -4504,7 +4636,7 @@ process_stop_reply (struct stop_reply *stop_reply,
delete_inferior (pid);
}
else
- notice_new_inferiors (ptid);
+ notice_new_inferiors (ptid, 0);
/* Expedited registers. */
if (stop_reply->regcache)
@@ -4655,7 +4787,7 @@ remote_wait_as (ptid_t ptid, struct target_waitstatus *status)
case 'F': /* File-I/O request. */
remote_fileio_request (buf);
break;
- case 'T': case 'S': case 'X': case 'W':
+ case 'T': case 'S': case 'X': case 'W': case 'Y':
{
struct stop_reply *stop_reply;
struct cleanup *old_chain;
@@ -4681,7 +4813,7 @@ remote_wait_as (ptid_t ptid, struct target_waitstatus *status)
remote system doesn't support it. */
target_terminal_ours_for_output ();
printf_filtered
- ("Can't send signals to this remote system. %s not sent.\n",
+ ("Can't send signals to this remote system. %s not sent.\n",
target_signal_to_name (last_sent_signal));
last_sent_signal = TARGET_SIGNAL_0;
target_terminal_inferior ();
@@ -6550,7 +6682,7 @@ extended_remote_mourn_1 (struct target_ops *target)
/* Unlike "target remote", we do not want to unpush the target; then
the next time the user says "run", we won't be connected. */
- if (have_inferiors ())
+ if (have_real_inferiors ())
{
extern void nullify_last_target_wait_ptid ();
/* Multi-process case. The current process has exited, but
@@ -6691,11 +6823,15 @@ extended_remote_create_inferior_1 (char *exec_file, char *args,
extended_remote_restart ();
}
+#if 0
+ /* FIXME: How does this look with itsets? */
+
/* Clean up from the last time we ran, before we mark the target
running again. This will mark breakpoints uninserted, and
get_offsets may insert breakpoints. */
init_thread_list ();
init_wait_for_inferior ();
+#endif
/* Now mark the inferior as running before we do anything else. */
inferior_ptid = magic_null_ptid;
@@ -6716,7 +6852,7 @@ extended_remote_create_inferior_1 (char *exec_file, char *args,
}
static void
-extended_remote_create_inferior (struct target_ops *ops,
+extended_remote_create_inferior (struct target_ops *ops,
char *exec_file, char *args,
char **env, int from_tty)
{
@@ -7263,7 +7399,6 @@ remote_xfer_partial (struct target_ops *ops, enum target_object object,
char *p2;
char query_type;
-
if (tmp_inf && tmp_inf->pid != ptid_get_pid (inferior_ptid))
{
ptid_t tmp_ptid;
@@ -8635,6 +8770,217 @@ remote_supports_multi_process (void)
return remote_multi_process_p (rs);
}
+char *
+remote_pid_to_exec_file (int pid)
+{
+ struct remote_state *rs;
+
+ rs = get_remote_state ();
+
+ sprintf (rs->buf, "qExecFile:%x", pid);
+ putpkt (rs->buf);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+ if (*rs->buf == '\0')
+ /* Not supported */ ;
+ else if (strncmp (rs->buf, "QExecFile:", 10) == 0)
+ {
+ static char *buf = NULL;
+ int n, result;
+ char *p;
+
+ p = strchr (rs->buf + 10, ';');
+
+ if (p == NULL)
+ {
+ warning (_("Invalid qExecFile reply: %s"), rs->buf);
+ return NULL;
+ }
+
+ p++;
+
+ if (buf == NULL)
+ make_final_cleanup (xfree, buf);
+ else
+ xfree (buf);
+
+ buf = xmalloc (strlen (p) + 1);
+ result = hex2bin (p, (gdb_byte *) buf, strlen (p));
+ buf [result] = '\0';
+
+ return buf;
+ }
+ else if (*rs->buf == 'E')
+ ;
+ else
+ warning (_("Invalid qExecFile reply: %s"), rs->buf);
+
+ return NULL;
+}
+
+static void
+remote_detach_pid (int pid)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ /* Tell the remote target to detach. */
+ sprintf (rs->buf, "D;%x", pid);
+
+ putpkt (rs->buf);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+
+ if (strcmp (rs->buf, "OK") == 0)
+ ;
+ else if (rs->buf[0] == '\0')
+ error (_("Remote doesn't know how to detach"));
+ else
+ error (_("Can't detach process."));
+}
+
+static int
+remote_follow_fork (struct target_ops *ops, int follow_child)
+{
+ ptid_t last_ptid;
+ struct target_waitstatus last_status;
+ int has_vforked;
+ int parent_pid, child_pid;
+
+ get_last_target_status (&last_ptid, &last_status);
+ has_vforked = (last_status.kind == TARGET_WAITKIND_VFORKED);
+ parent_pid = ptid_get_tid (last_ptid);
+ if (parent_pid == 0)
+ parent_pid = ptid_get_pid (last_ptid);
+ child_pid = PIDGET (last_status.value.related_pid);
+
+ if (! follow_child)
+ {
+ /* We're already attached to the parent, by default. */
+
+ /* Before detaching from the child, remove all breakpoints from
+ it. (This won't actually modify the breakpoint list, but
+ will physically remove the breakpoints from the child.) */
+ /* If we vforked this will remove the breakpoints from the
+ parent also, but they'll be reinserted below. */
+ set_general_thread (last_status.value.related_pid);
+ detach_breakpoints (child_pid);
+
+ /* Detach new forked process? */
+ if (detach_fork)
+ {
+ if (info_verbose || remote_debug)
+ {
+ target_terminal_ours ();
+ fprintf_filtered (gdb_stdlog,
+ "Detaching after fork from child process %d.\n",
+ child_pid);
+ }
+
+ /* Tell the remote target to detach. */
+ remote_detach_pid (child_pid);
+ }
+ else
+ {
+ /* Add process to GDB's tables. */
+ add_inferior (child_pid);
+ }
+
+ set_general_thread (last_ptid);
+
+ if (has_vforked)
+ {
+ /* TODO here: Wait for linux's VFORK_DONE, or HPUX's
+ TTEVT_VFORK, or equivalent. */
+
+ /* Since we vforked, breakpoints were removed in the parent
+ too. Put them back. */
+ reattach_breakpoints (parent_pid);
+ }
+ }
+ else
+ {
+ struct thread_info *last_tp = find_thread_pid (last_ptid);
+ struct thread_info *tp;
+
+ /* Copy user stepping state to the new inferior thread. */
+ struct breakpoint *step_resume_breakpoint = last_tp->step_resume_breakpoint;
+ CORE_ADDR step_range_start = last_tp->step_range_start;
+ CORE_ADDR step_range_end = last_tp->step_range_end;
+ struct frame_id step_frame_id = last_tp->step_frame_id;
+
+ last_tp->step_range_start = 0;
+ last_tp->step_range_end = last_tp->step_range_end = 0;
+ last_tp->step_frame_id = null_frame_id;
+
+ /* Otherwise, deleting the parent would get rid of this
+ breakpoint. */
+ last_tp->step_resume_breakpoint = NULL;
+
+ /* Needed to keep the breakpoint lists in sync. */
+ if (! has_vforked)
+ {
+ set_general_thread (last_status.value.related_pid);
+ detach_breakpoints (child_pid);
+ }
+
+ /* Before detaching from the parent, remove all breakpoints from it. */
+ set_general_thread (last_ptid);
+ remove_breakpoints ();
+
+ if (info_verbose || remote_debug)
+ {
+ target_terminal_ours ();
+ fprintf_filtered (gdb_stdlog,
+ "Attaching after fork to child process %d.\n",
+ child_pid);
+ }
+
+ /* If we're vforking, we may want to hold on to the parent until
+ the child exits or execs. At exec time we can remove the old
+ breakpoints from the parent and detach it; at exit time we
+ could do the same (or even, sneakily, resume debugging it - the
+ child's exec has failed, or something similar).
+
+ The holding part is very easy if we have VFORKDONE events;
+ but keeping track of both processes is beyond GDB at the
+ moment. So we don't expose the parent to the rest of GDB.
+ Instead we quietly hold onto it until such time as we can
+ safely resume it. */
+
+ if (has_vforked)
+ {
+ /* TODO: handle this correctly.
+
+ remote_fork_parent_pid = parent_pid;
+
+ */
+ detach_inferior (parent_pid);
+ }
+ else if (detach_fork)
+ {
+ remote_detach_pid (parent_pid);
+ detach_inferior (parent_pid);
+ }
+
+ add_inferior (child_pid);
+
+ inferior_ptid = ptid_build (child_pid, 0, 0);
+ set_general_thread (inferior_ptid);
+ inferior_ptid = remote_current_thread (inferior_ptid);
+ set_general_thread (inferior_ptid);
+
+ tp = add_thread (inferior_ptid);
+
+ tp->step_resume_breakpoint = step_resume_breakpoint;
+ tp->step_range_start = step_range_start;
+ tp->step_range_end = step_range_end;
+ tp->step_frame_id = step_frame_id;
+
+ /* Reset breakpoints in the child as appropriate. */
+ follow_inferior_reset_breakpoints ();
+ }
+
+ return 0;
+}
+
static void
init_remote_ops (void)
{
@@ -8698,6 +9044,8 @@ Specify the serial device it is connected to\n\
remote_ops.to_terminal_ours = remote_terminal_ours;
remote_ops.to_supports_non_stop = remote_supports_non_stop;
remote_ops.to_supports_multi_process = remote_supports_multi_process;
+ remote_ops.to_pid_to_exec_file = remote_pid_to_exec_file;
+ remote_ops.to_follow_fork = remote_follow_fork;
}
/* Set up the extended remote vector by making a copy of the standard
diff --git a/gdb/stack.c b/gdb/stack.c
index 3c1019b22c1..392de10fce9 100644
--- a/gdb/stack.c
+++ b/gdb/stack.c
@@ -1639,6 +1639,9 @@ get_selected_block (CORE_ADDR *addr_in_block)
if (!target_has_stack)
return 0;
+ if (ptid_equal (inferior_ptid, null_ptid))
+ return 0;
+
if (is_exited (inferior_ptid))
return 0;
diff --git a/gdb/top.c b/gdb/top.c
index c77ba9761f8..e77ceb8c1b6 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -481,7 +481,9 @@ Cannot execute this command without a live selected thread. See `help thread'."
/* FIXME: This should be cacheing the frame and only running when
the frame changes. */
- if (target_has_stack && is_stopped (inferior_ptid))
+ if (target_has_stack
+ && !ptid_equal (inferior_ptid, null_ptid)
+ && is_stopped (inferior_ptid))
{
flang = get_frame_language ();
if (!warned