Linux gdbserver confused when event randomization picks process exit event

The tail end of linux_wait_1 isn't expecting that the select_event_lwp
machinery can pick a whole-process exit event to report to GDB.  When
that happens, both gdb and gdbserver end up quite confused:

 ...
 (gdb)
 [Thread 24971.24971] #1 stopped.
 0x0000003615a011f0 in ?? ()
 c&
 Continuing.
 (gdb) [New Thread 24971.24981]
 [New Thread 24983.24983]
 [New Thread 24971.24982]

 [Thread 24983.24983] #3 stopped.
 0x0000003615ebc7cc in __libc_fork () at ../nptl/sysdeps/unix/sysv/linux/fork.c:130
 130       pid = ARCH_FORK ();
 [New Thread 24984.24984]
 Error in re-setting breakpoint -16: PC register is not available
 Error in re-setting breakpoint -17: PC register is not available
 Error in re-setting breakpoint -18: PC register is not available
 Error in re-setting breakpoint -19: PC register is not available
 Error in re-setting breakpoint -24: PC register is not available
 Error in re-setting breakpoint -25: PC register is not available
 Error in re-setting breakpoint -26: PC register is not available
 Error in re-setting breakpoint -27: PC register is not available
 Error in re-setting breakpoint -28: PC register is not available
 Error in re-setting breakpoint -29: PC register is not available
 Error in re-setting breakpoint -30: PC register is not available
 PC register is not available
 (gdb)

gdb/gdbserver/ChangeLog:
2015-08-06  Pedro Alves  <palves@redhat.com>

	* linux-low.c (add_lwp): Set waitstatus to TARGET_WAITKIND_IGNORE.
	(linux_thread_alive): Use lwp_is_marked_dead.
	(extended_event_reported): Delete.
	(linux_wait_1): Check if waitstatus is TARGET_WAITKIND_IGNORE
	instead of extended_event_reported.
	(mark_lwp_dead): Don't set the 'dead' flag.  Store the waitstatus
	as well.
	(lwp_is_marked_dead): New function.
	(lwp_running): Use lwp_is_marked_dead.
	* linux-low.h: Delete 'dead' field, and update 'waitstatus's
	comment.
This commit is contained in:
Pedro Alves 2015-08-06 10:30:17 +01:00
parent ad071a3055
commit 00db26facc
3 changed files with 54 additions and 35 deletions

View file

@ -1,3 +1,17 @@
2015-08-06 Pedro Alves <palves@redhat.com>
* linux-low.c (add_lwp): Set waitstatus to TARGET_WAITKIND_IGNORE.
(linux_thread_alive): Use lwp_is_marked_dead.
(extended_event_reported): Delete.
(linux_wait_1): Check if waitstatus is TARGET_WAITKIND_IGNORE
instead of extended_event_reported.
(mark_lwp_dead): Don't set the 'dead' flag. Store the waitstatus
as well.
(lwp_is_marked_dead): New function.
(lwp_running): Use lwp_is_marked_dead.
* linux-low.h: Delete 'dead' field, and update 'waitstatus's
comment.
2015-08-06 Pedro Alves <palves@redhat.com>
* linux-low.c (linux_wait_1): Move fork event output out of the

View file

@ -267,6 +267,7 @@ static int linux_wait_for_event (ptid_t ptid, int *wstat, int options);
static struct lwp_info *add_lwp (ptid_t ptid);
static int linux_stopped_by_watchpoint (void);
static void mark_lwp_dead (struct lwp_info *lwp, int wstat);
static int lwp_is_marked_dead (struct lwp_info *lwp);
static void proceed_all_lwps (void);
static int finish_step_over (struct lwp_info *lwp);
static int kill_lwp (unsigned long lwpid, int signo);
@ -746,8 +747,9 @@ add_lwp (ptid_t ptid)
{
struct lwp_info *lwp;
lwp = (struct lwp_info *) xmalloc (sizeof (*lwp));
memset (lwp, 0, sizeof (*lwp));
lwp = (struct lwp_info *) xcalloc (1, sizeof (*lwp));
lwp->waitstatus.kind = TARGET_WAITKIND_IGNORE;
if (the_low_target.new_thread != NULL)
the_low_target.new_thread (lwp);
@ -1396,7 +1398,7 @@ linux_thread_alive (ptid_t ptid)
exited but we still haven't been able to report it to GDB, we'll
hold on to the last lwp of the dead process. */
if (lwp != NULL)
return !lwp->dead;
return !lwp_is_marked_dead (lwp);
else
return 0;
}
@ -2750,20 +2752,6 @@ ignore_event (struct target_waitstatus *ourstatus)
return null_ptid;
}
/* Return non-zero if WAITSTATUS reflects an extended linux
event. Otherwise, return zero. */
static int
extended_event_reported (const struct target_waitstatus *waitstatus)
{
if (waitstatus == NULL)
return 0;
return (waitstatus->kind == TARGET_WAITKIND_FORKED
|| waitstatus->kind == TARGET_WAITKIND_VFORKED
|| waitstatus->kind == TARGET_WAITKIND_VFORK_DONE);
}
/* Wait for process, returns status. */
static ptid_t
@ -3131,7 +3119,7 @@ linux_wait_1 (ptid_t ptid,
|| (gdb_breakpoint_here (event_child->stop_pc)
&& gdb_condition_true_at_breakpoint (event_child->stop_pc)
&& gdb_no_commands_at_breakpoint (event_child->stop_pc))
|| extended_event_reported (&event_child->waitstatus));
|| event_child->waitstatus.kind != TARGET_WAITKIND_IGNORE);
run_breakpoint_commands (event_child->stop_pc);
@ -3183,7 +3171,7 @@ linux_wait_1 (ptid_t ptid,
if (debug_threads)
{
if (extended_event_reported (&event_child->waitstatus))
if (event_child->waitstatus.kind != TARGET_WAITKIND_IGNORE)
{
char *str;
@ -3271,12 +3259,11 @@ linux_wait_1 (ptid_t ptid,
unstop_all_lwps (1, event_child);
}
if (extended_event_reported (&event_child->waitstatus))
if (event_child->waitstatus.kind != TARGET_WAITKIND_IGNORE)
{
/* If the reported event is a fork, vfork or exec, let GDB know. */
ourstatus->kind = event_child->waitstatus.kind;
ourstatus->value = event_child->waitstatus.value;
/* If the reported event is an exit, fork, vfork or exec, let
GDB know. */
*ourstatus = event_child->waitstatus;
/* Clear the event lwp's waitstatus since we handled it already. */
event_child->waitstatus.kind = TARGET_WAITKIND_IGNORE;
}
@ -3484,13 +3471,23 @@ suspend_and_send_sigstop_callback (struct inferior_list_entry *entry,
static void
mark_lwp_dead (struct lwp_info *lwp, int wstat)
{
/* It's dead, really. */
lwp->dead = 1;
/* Store the exit status for later. */
lwp->status_pending_p = 1;
lwp->status_pending = wstat;
/* Store in waitstatus as well, as there's nothing else to process
for this event. */
if (WIFEXITED (wstat))
{
lwp->waitstatus.kind = TARGET_WAITKIND_EXITED;
lwp->waitstatus.value.integer = WEXITSTATUS (wstat);
}
else if (WIFSIGNALED (wstat))
{
lwp->waitstatus.kind = TARGET_WAITKIND_SIGNALLED;
lwp->waitstatus.value.sig = gdb_signal_from_host (WTERMSIG (wstat));
}
/* Prevent trying to stop it. */
lwp->stopped = 1;
@ -3498,6 +3495,17 @@ mark_lwp_dead (struct lwp_info *lwp, int wstat)
lwp->stop_expected = 0;
}
/* Return true if LWP has exited already, and has a pending exit event
to report to GDB. */
static int
lwp_is_marked_dead (struct lwp_info *lwp)
{
return (lwp->status_pending_p
&& (WIFEXITED (lwp->status_pending)
|| WIFSIGNALED (lwp->status_pending)));
}
/* Wait for all children to stop for the SIGSTOPs we just queued. */
static void
@ -3614,7 +3622,7 @@ lwp_running (struct inferior_list_entry *entry, void *data)
struct thread_info *thread = (struct thread_info *) entry;
struct lwp_info *lwp = get_thread_lwp (thread);
if (lwp->dead)
if (lwp_is_marked_dead (lwp))
return 0;
if (lwp->stopped)
return 0;

View file

@ -261,16 +261,13 @@ struct lwp_info
event already received in a wait()). */
int stopped;
/* If this flag is set, the lwp is known to be dead already (exit
event already received in a wait(), and is cached in
status_pending). */
int dead;
/* When stopped is set, the last wait status recorded for this lwp. */
int last_status;
/* This is used to store extended ptrace event information until
it is reported to GDB. */
/* If WAITSTATUS->KIND != TARGET_WAITKIND_IGNORE, the waitstatus for
this LWP's last event, to pass to GDB without any further
processing. This is used to store extended ptrace event
information or exit status until it can be reported to GDB. */
struct target_waitstatus waitstatus;
/* When stopped is set, this is where the lwp last stopped, with