diff options
-rw-r--r-- | gdb/ChangeLog | 114 | ||||
-rw-r--r-- | gdb/exec.c | 2 | ||||
-rw-r--r-- | gdb/frame.c | 5 | ||||
-rw-r--r-- | gdb/infcmd.c | 162 | ||||
-rw-r--r-- | gdb/inferior.c | 100 | ||||
-rw-r--r-- | gdb/inferior.h | 12 | ||||
-rw-r--r-- | gdb/infrun.c | 6 | ||||
-rw-r--r-- | gdb/linux-fork.c | 10 | ||||
-rw-r--r-- | gdb/remote.c | 458 | ||||
-rw-r--r-- | gdb/stack.c | 3 | ||||
-rw-r--r-- | gdb/top.c | 4 |
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 |