mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-11-16 12:34:43 +00:00
Compare commits
12 Commits
efbd9add96
...
users/mmet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
13403511a1 | ||
|
|
57531a5fa4 | ||
|
|
e20f632287 | ||
|
|
db9809ed6b | ||
|
|
d36829aa37 | ||
|
|
9c29dc7d14 | ||
|
|
252498d882 | ||
|
|
60113a4b3b | ||
|
|
c925bff825 | ||
|
|
5f5d5a5165 | ||
|
|
18c82d81fe | ||
|
|
b384d69217 |
66
gdb/infrun.c
66
gdb/infrun.c
@@ -2392,7 +2392,7 @@ user_visible_resume_ptid (int step)
|
||||
resume_ptid = inferior_ptid;
|
||||
}
|
||||
else if ((scheduler_mode == schedlock_replay)
|
||||
&& target_record_will_replay (minus_one_ptid, execution_direction))
|
||||
&& target_record_will_replay (inferior_ptid, execution_direction))
|
||||
{
|
||||
/* User-settable 'scheduler' mode requires solo thread resume in replay
|
||||
mode. */
|
||||
@@ -3104,16 +3104,14 @@ notify_about_to_proceed ()
|
||||
void
|
||||
clear_proceed_status (int step)
|
||||
{
|
||||
/* With scheduler-locking replay, stop replaying other threads if we're
|
||||
not replaying the user-visible resume ptid.
|
||||
/* With scheduler-locking replay, stop replaying other threads in the
|
||||
same process if we're not replaying the selected thread.
|
||||
|
||||
This is a convenience feature to not require the user to explicitly
|
||||
stop replaying the other threads. We're assuming that the user's
|
||||
intent is to resume tracing the recorded process. */
|
||||
if (!non_stop && scheduler_mode == schedlock_replay
|
||||
&& target_record_is_replaying (minus_one_ptid)
|
||||
&& !target_record_will_replay (user_visible_resume_ptid (step),
|
||||
execution_direction))
|
||||
&& !target_record_will_replay (inferior_ptid, execution_direction))
|
||||
target_record_stop_replaying ();
|
||||
|
||||
if (!non_stop && inferior_ptid != null_ptid)
|
||||
@@ -3197,8 +3195,7 @@ schedlock_applies (struct thread_info *tp)
|
||||
|| (scheduler_mode == schedlock_step
|
||||
&& tp->control.stepping_command)
|
||||
|| (scheduler_mode == schedlock_replay
|
||||
&& target_record_will_replay (minus_one_ptid,
|
||||
execution_direction)));
|
||||
&& target_record_will_replay (tp->ptid, execution_direction)));
|
||||
}
|
||||
|
||||
/* When FORCE_P is false, set process_stratum_target::COMMIT_RESUMED_STATE
|
||||
@@ -4206,7 +4203,24 @@ do_target_wait (ptid_t wait_ptid, execution_control_state *ecs,
|
||||
|
||||
auto do_wait = [&] (inferior *inf)
|
||||
{
|
||||
ecs->ptid = do_target_wait_1 (inf, wait_ptid, &ecs->ws, options);
|
||||
ptid_t ptid { inf->pid };
|
||||
|
||||
/* Make sure we're not widening WAIT_PTID. */
|
||||
if (!ptid.matches (wait_ptid)
|
||||
/* Targets that cannot async will be asked for a blocking wait.
|
||||
|
||||
Blocking wait does not work inferior-by-inferior if the target
|
||||
provides more than one inferior. Fall back to waiting for
|
||||
WAIT_PTID in that case. */
|
||||
|| !target_can_async_p () || ((options & TARGET_WNOHANG) == 0)
|
||||
/* We cannot wait for inferiors without a pid.
|
||||
|
||||
One such inferior is created by initialize_inferiors () to
|
||||
ensure that there always is an inferior. */
|
||||
|| !ptid.is_pid ())
|
||||
ptid = wait_ptid;
|
||||
|
||||
ecs->ptid = do_target_wait_1 (inf, ptid, &ecs->ws, options);
|
||||
ecs->target = inf->process_target ();
|
||||
return (ecs->ws.kind () != TARGET_WAITKIND_IGNORE);
|
||||
};
|
||||
@@ -4216,6 +4230,18 @@ do_target_wait (ptid_t wait_ptid, execution_control_state *ecs,
|
||||
reported the stop to the user, polling for events. */
|
||||
scoped_restore_current_thread restore_thread;
|
||||
|
||||
/* The first TARGET_WAITKIND_NO_RESUMED execution state.
|
||||
|
||||
We do not want to return TARGET_WAITKIND_NO_RESUMED right away since
|
||||
another inferior may have a more interesting event to report. If
|
||||
there is no other event to report, after all, we want to report the
|
||||
first such event.
|
||||
|
||||
This variable holds that first event, which will be copied on the
|
||||
first TARGET_WAITKIND_NO_RESUMED below. */
|
||||
execution_control_state no_resumed {};
|
||||
no_resumed.ptid = null_ptid;
|
||||
|
||||
intrusive_list_iterator<inferior> start
|
||||
= inferior_list.iterator_to (*selected);
|
||||
|
||||
@@ -4226,7 +4252,13 @@ do_target_wait (ptid_t wait_ptid, execution_control_state *ecs,
|
||||
inferior *inf = &*it;
|
||||
|
||||
if (inferior_matches (inf) && do_wait (inf))
|
||||
return true;
|
||||
{
|
||||
if (ecs->ws.kind () != TARGET_WAITKIND_NO_RESUMED)
|
||||
return true;
|
||||
|
||||
if (no_resumed.ptid == null_ptid)
|
||||
no_resumed = *ecs;
|
||||
}
|
||||
}
|
||||
|
||||
for (intrusive_list_iterator<inferior> it = inferior_list.begin ();
|
||||
@@ -4236,7 +4268,19 @@ do_target_wait (ptid_t wait_ptid, execution_control_state *ecs,
|
||||
inferior *inf = &*it;
|
||||
|
||||
if (inferior_matches (inf) && do_wait (inf))
|
||||
return true;
|
||||
{
|
||||
if (ecs->ws.kind () != TARGET_WAITKIND_NO_RESUMED)
|
||||
return true;
|
||||
|
||||
if (no_resumed.ptid == null_ptid)
|
||||
no_resumed = *ecs;
|
||||
}
|
||||
}
|
||||
|
||||
if (no_resumed.ptid != null_ptid)
|
||||
{
|
||||
*ecs = no_resumed;
|
||||
return true;
|
||||
}
|
||||
|
||||
ecs->ws.set_ignore ();
|
||||
|
||||
@@ -1162,6 +1162,7 @@ linux_nat_target::attach (const char *args, int from_tty)
|
||||
|
||||
/* Add the initial process as the first LWP to the list. */
|
||||
lp = add_initial_lwp (ptid);
|
||||
lp->last_resume_kind = resume_stop;
|
||||
|
||||
status = linux_nat_post_attach_wait (lp->ptid, &lp->signalled);
|
||||
if (!WIFSTOPPED (status))
|
||||
@@ -1769,9 +1770,45 @@ linux_nat_target::resume (ptid_t scope_ptid, int step, enum gdb_signal signo)
|
||||
last_resume_kind to resume_continue. */
|
||||
iterate_over_lwps (scope_ptid, resume_set_callback);
|
||||
|
||||
/* Let's see if we're supposed to resume INFERIOR_PTID at all. */
|
||||
if (!inferior_ptid.matches (scope_ptid))
|
||||
{
|
||||
linux_nat_debug_printf ("inferior_ptid %s not in scope %s",
|
||||
inferior_ptid.to_string ().c_str (),
|
||||
scope_ptid.to_string ().c_str ());
|
||||
iterate_over_lwps (scope_ptid, [=] (struct lwp_info *info)
|
||||
{
|
||||
return linux_nat_resume_callback (info, nullptr);
|
||||
});
|
||||
|
||||
if (target_can_async_p ())
|
||||
{
|
||||
target_async (true);
|
||||
/* Tell the event loop we have something to process. */
|
||||
async_file_mark ();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
lp = find_lwp_pid (inferior_ptid);
|
||||
gdb_assert (lp != NULL);
|
||||
|
||||
if (!lp->stopped)
|
||||
{
|
||||
linux_nat_debug_printf ("inferior_ptid %s not stopped",
|
||||
inferior_ptid.to_string ().c_str ());
|
||||
|
||||
if (target_can_async_p ())
|
||||
{
|
||||
target_async (true);
|
||||
/* Tell the event loop we have something to process. */
|
||||
async_file_mark ();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Remember if we're stepping. */
|
||||
lp->last_resume_kind = step ? resume_step : resume_continue;
|
||||
|
||||
@@ -3324,12 +3361,18 @@ linux_nat_wait_1 (ptid_t ptid, struct target_waitstatus *ourstatus,
|
||||
moment at which we know its PID. */
|
||||
if (ptid.is_pid () && find_lwp_pid (ptid) == nullptr)
|
||||
{
|
||||
ptid_t lwp_ptid (ptid.pid (), ptid.pid ());
|
||||
/* Unless we already did and this is simply a request to wait for a
|
||||
particular inferior. */
|
||||
inferior *inf = find_inferior_ptid (linux_target, ptid);
|
||||
if ((inf != nullptr) && (inf->find_thread (ptid) != nullptr))
|
||||
{
|
||||
ptid_t lwp_ptid (ptid.pid (), ptid.pid ());
|
||||
|
||||
/* Upgrade the main thread's ptid. */
|
||||
thread_change_ptid (linux_target, ptid, lwp_ptid);
|
||||
lp = add_initial_lwp (lwp_ptid);
|
||||
lp->resumed = 1;
|
||||
/* Upgrade the main thread's ptid. */
|
||||
thread_change_ptid (linux_target, ptid, lwp_ptid);
|
||||
lp = add_initial_lwp (lwp_ptid);
|
||||
lp->resumed = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Make sure SIGCHLD is blocked until the sigsuspend below. */
|
||||
|
||||
@@ -80,7 +80,7 @@ public:
|
||||
|
||||
enum record_method record_method (ptid_t ptid) override;
|
||||
|
||||
void stop_recording () override;
|
||||
bool stop_recording () override;
|
||||
void info_record () override;
|
||||
|
||||
void insn_history (int size, gdb_disassembly_flags flags) override;
|
||||
@@ -123,8 +123,6 @@ public:
|
||||
ptid_t wait (ptid_t, struct target_waitstatus *, target_wait_flags) override;
|
||||
|
||||
void stop (ptid_t) override;
|
||||
void update_thread_list () override;
|
||||
bool thread_alive (ptid_t ptid) override;
|
||||
void goto_record_begin () override;
|
||||
void goto_record_end () override;
|
||||
void goto_record (ULONGEST insn) override;
|
||||
@@ -408,16 +406,20 @@ record_btrace_target_open (const char *args, int from_tty)
|
||||
|
||||
/* The stop_recording method of target record-btrace. */
|
||||
|
||||
void
|
||||
bool
|
||||
record_btrace_target::stop_recording ()
|
||||
{
|
||||
DEBUG ("stop recording");
|
||||
|
||||
bool is_replaying = record_is_replaying (inferior_ptid);
|
||||
record_stop_replaying ();
|
||||
record_btrace_auto_disable ();
|
||||
|
||||
for (thread_info *tp : current_inferior ()->non_exited_threads ())
|
||||
if (tp->btrace.target != NULL)
|
||||
btrace_disable (tp);
|
||||
|
||||
return is_replaying;
|
||||
}
|
||||
|
||||
/* The disconnect method of target record-btrace. */
|
||||
@@ -2189,11 +2191,14 @@ record_btrace_target::resume (ptid_t ptid, int step, enum gdb_signal signal)
|
||||
For non-stop targets this means that no thread is replaying. In order to
|
||||
make progress, we may need to explicitly move replaying threads to the end
|
||||
of their execution history. */
|
||||
if ((::execution_direction != EXEC_REVERSE)
|
||||
&& !record_is_replaying (minus_one_ptid))
|
||||
if (::execution_direction != EXEC_REVERSE)
|
||||
{
|
||||
this->beneath ()->resume (ptid, step, signal);
|
||||
return;
|
||||
ptid_t check { ptid == minus_one_ptid ? ptid : ptid_t (ptid.pid ()) };
|
||||
if (!record_is_replaying (check))
|
||||
{
|
||||
this->beneath ()->resume (ptid, step, signal);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Compute the btrace thread flag for the requested move. */
|
||||
@@ -2213,25 +2218,45 @@ record_btrace_target::resume (ptid_t ptid, int step, enum gdb_signal signal)
|
||||
|
||||
For all-stop targets, we only step INFERIOR_PTID and continue others. */
|
||||
|
||||
process_stratum_target *proc_target = current_inferior ()->process_target ();
|
||||
process_stratum_target *proc_target
|
||||
= current_inferior ()->process_target ();
|
||||
|
||||
if (!target_is_non_stop_p ())
|
||||
/* Split a minus_one_ptid request into per-inferior requests, so we can
|
||||
forward them for inferiors that are not replaying. */
|
||||
if ((::execution_direction != EXEC_REVERSE) && (ptid == minus_one_ptid))
|
||||
{
|
||||
for (inferior *inf : all_non_exited_inferiors (proc_target))
|
||||
{
|
||||
ptid_t inf_ptid { inf->pid };
|
||||
if (!record_is_replaying (inf_ptid))
|
||||
{
|
||||
this->beneath ()->resume (inf_ptid, step, signal);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (thread_info *tp : inf->non_exited_threads ())
|
||||
{
|
||||
if (target_is_non_stop_p ()
|
||||
|| tp->ptid.matches (inferior_ptid))
|
||||
record_btrace_resume_thread (tp, flag);
|
||||
else
|
||||
record_btrace_resume_thread (tp, cflag);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
gdb_assert (inferior_ptid.matches (ptid));
|
||||
|
||||
for (thread_info *tp : all_non_exited_threads (proc_target, ptid))
|
||||
{
|
||||
if (tp->ptid.matches (inferior_ptid))
|
||||
if (target_is_non_stop_p ()
|
||||
|| tp->ptid.matches (inferior_ptid))
|
||||
record_btrace_resume_thread (tp, flag);
|
||||
else
|
||||
record_btrace_resume_thread (tp, cflag);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (thread_info *tp : all_non_exited_threads (proc_target, ptid))
|
||||
record_btrace_resume_thread (tp, flag);
|
||||
}
|
||||
|
||||
/* Async support. */
|
||||
if (target_can_async_p ())
|
||||
@@ -2310,14 +2335,14 @@ btrace_step_spurious (void)
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Return a target_waitstatus indicating that the thread was not resumed. */
|
||||
/* Return a target_waitstatus indicating that nothing is moving. */
|
||||
|
||||
static struct target_waitstatus
|
||||
btrace_step_no_resumed (void)
|
||||
btrace_step_no_moving_threads (void)
|
||||
{
|
||||
struct target_waitstatus status;
|
||||
|
||||
status.set_no_resumed ();
|
||||
status.set_ignore ();
|
||||
|
||||
return status;
|
||||
}
|
||||
@@ -2608,10 +2633,11 @@ record_btrace_target::wait (ptid_t ptid, struct target_waitstatus *status,
|
||||
(unsigned) options);
|
||||
|
||||
/* As long as we're not replaying, just forward the request. */
|
||||
if ((::execution_direction != EXEC_REVERSE)
|
||||
&& !record_is_replaying (minus_one_ptid))
|
||||
if (::execution_direction != EXEC_REVERSE)
|
||||
{
|
||||
return this->beneath ()->wait (ptid, status, options);
|
||||
ptid_t check { ptid == minus_one_ptid ? ptid : ptid_t (ptid.pid ()) };
|
||||
if (!record_is_replaying (check))
|
||||
return this->beneath ()->wait (ptid, status, options);
|
||||
}
|
||||
|
||||
/* Keep a work list of moving threads. */
|
||||
@@ -2622,7 +2648,20 @@ record_btrace_target::wait (ptid_t ptid, struct target_waitstatus *status,
|
||||
|
||||
if (moving.empty ())
|
||||
{
|
||||
*status = btrace_step_no_resumed ();
|
||||
/* Splitting a minus_one_ptid wait request per inferior is not safe
|
||||
for blocking targets. If one of the inferiors has an event to
|
||||
report, but we happen to forward the wait request on another
|
||||
inferior first that has nothing to report, we'd hang, whereas a
|
||||
minus_one_ptid request would succeed.
|
||||
|
||||
A replaying inferior would be completely stopped for the target
|
||||
beneath, so waiting for it should not result in any events. It
|
||||
should be safe to forward the minus_one_ptid request. */
|
||||
if ((::execution_direction != EXEC_REVERSE)
|
||||
&& (ptid == minus_one_ptid))
|
||||
return this->beneath ()->wait (ptid, status, options);
|
||||
|
||||
*status = btrace_step_no_moving_threads ();
|
||||
|
||||
DEBUG ("wait ended by %s: %s", null_ptid.to_string ().c_str (),
|
||||
status->to_string ().c_str ());
|
||||
@@ -2692,17 +2731,28 @@ record_btrace_target::wait (ptid_t ptid, struct target_waitstatus *status,
|
||||
|
||||
gdb_assert (eventing != NULL);
|
||||
|
||||
/* We kept threads replaying at the end of their execution history. Stop
|
||||
replaying EVENTING now that we are going to report its stop. */
|
||||
record_btrace_stop_replaying_at_end (eventing);
|
||||
|
||||
/* Stop all other threads. */
|
||||
if (!target_is_non_stop_p ())
|
||||
{
|
||||
for (thread_info *tp : current_inferior ()->non_exited_threads ())
|
||||
record_btrace_cancel_resume (tp);
|
||||
if (tp != eventing)
|
||||
record_btrace_cancel_resume (tp);
|
||||
|
||||
if ((::execution_direction != EXEC_REVERSE) && (ptid == minus_one_ptid))
|
||||
{
|
||||
for (inferior *inf : all_non_exited_inferiors (proc_target))
|
||||
{
|
||||
ptid_t inf_ptid { inf->pid };
|
||||
if (!record_is_replaying (inf_ptid))
|
||||
this->beneath ()->stop (inf_ptid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* We kept threads replaying at the end of their execution history. Stop
|
||||
replaying EVENTING now that we are going to report its stop. */
|
||||
record_btrace_stop_replaying_at_end (eventing);
|
||||
|
||||
/* In async mode, we need to announce further events. */
|
||||
if (target_is_async_p ())
|
||||
record_btrace_maybe_mark_async_event (moving, no_history);
|
||||
@@ -2729,21 +2779,46 @@ record_btrace_target::stop (ptid_t ptid)
|
||||
DEBUG ("stop %s", ptid.to_string ().c_str ());
|
||||
|
||||
/* As long as we're not replaying, just forward the request. */
|
||||
if ((::execution_direction != EXEC_REVERSE)
|
||||
&& !record_is_replaying (minus_one_ptid))
|
||||
if (::execution_direction != EXEC_REVERSE)
|
||||
{
|
||||
this->beneath ()->stop (ptid);
|
||||
ptid_t check { ptid == minus_one_ptid ? ptid : ptid_t (ptid.pid ()) };
|
||||
if (!record_is_replaying (check))
|
||||
{
|
||||
this->beneath ()->stop (ptid);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
process_stratum_target *proc_target
|
||||
= current_inferior ()->process_target ();
|
||||
|
||||
/* Split a minus_one_ptid request into per-inferior requests, so we can
|
||||
forward them for inferiors that are not replaying. */
|
||||
if ((::execution_direction != EXEC_REVERSE) && (ptid == minus_one_ptid))
|
||||
{
|
||||
for (inferior *inf : all_non_exited_inferiors (proc_target))
|
||||
{
|
||||
ptid_t inf_ptid { inf->pid };
|
||||
if (!record_is_replaying (inf_ptid))
|
||||
{
|
||||
this->beneath ()->stop (inf_ptid);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (thread_info *tp : inf->non_exited_threads ())
|
||||
{
|
||||
tp->btrace.flags &= ~BTHR_MOVE;
|
||||
tp->btrace.flags |= BTHR_STOP;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
process_stratum_target *proc_target
|
||||
= current_inferior ()->process_target ();
|
||||
|
||||
for (thread_info *tp : all_non_exited_threads (proc_target, ptid))
|
||||
{
|
||||
tp->btrace.flags &= ~BTHR_MOVE;
|
||||
tp->btrace.flags |= BTHR_STOP;
|
||||
}
|
||||
{
|
||||
tp->btrace.flags &= ~BTHR_MOVE;
|
||||
tp->btrace.flags |= BTHR_STOP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2760,7 +2835,7 @@ record_btrace_target::can_execute_reverse ()
|
||||
bool
|
||||
record_btrace_target::stopped_by_sw_breakpoint ()
|
||||
{
|
||||
if (record_is_replaying (minus_one_ptid))
|
||||
if (record_is_replaying (inferior_ptid))
|
||||
{
|
||||
struct thread_info *tp = inferior_thread ();
|
||||
|
||||
@@ -2775,7 +2850,7 @@ record_btrace_target::stopped_by_sw_breakpoint ()
|
||||
bool
|
||||
record_btrace_target::stopped_by_hw_breakpoint ()
|
||||
{
|
||||
if (record_is_replaying (minus_one_ptid))
|
||||
if (record_is_replaying (inferior_ptid))
|
||||
{
|
||||
struct thread_info *tp = inferior_thread ();
|
||||
|
||||
@@ -2785,32 +2860,6 @@ record_btrace_target::stopped_by_hw_breakpoint ()
|
||||
return this->beneath ()->stopped_by_hw_breakpoint ();
|
||||
}
|
||||
|
||||
/* The update_thread_list method of target record-btrace. */
|
||||
|
||||
void
|
||||
record_btrace_target::update_thread_list ()
|
||||
{
|
||||
/* We don't add or remove threads during replay. */
|
||||
if (record_is_replaying (minus_one_ptid))
|
||||
return;
|
||||
|
||||
/* Forward the request. */
|
||||
this->beneath ()->update_thread_list ();
|
||||
}
|
||||
|
||||
/* The thread_alive method of target record-btrace. */
|
||||
|
||||
bool
|
||||
record_btrace_target::thread_alive (ptid_t ptid)
|
||||
{
|
||||
/* We don't add or remove threads during replay. */
|
||||
if (record_is_replaying (minus_one_ptid))
|
||||
return true;
|
||||
|
||||
/* Forward the request. */
|
||||
return this->beneath ()->thread_alive (ptid);
|
||||
}
|
||||
|
||||
/* Set the replay branch trace instruction iterator. If IT is NULL, replay
|
||||
is stopped. */
|
||||
|
||||
|
||||
@@ -2072,7 +2072,8 @@ record_full_base_target::goto_record (ULONGEST target_insn)
|
||||
void
|
||||
record_full_base_target::record_stop_replaying ()
|
||||
{
|
||||
goto_record_end ();
|
||||
if (RECORD_FULL_IS_REPLAY)
|
||||
goto_record_end ();
|
||||
}
|
||||
|
||||
/* "resume" method for prec over corefile. */
|
||||
|
||||
19
gdb/record.c
19
gdb/record.c
@@ -152,12 +152,12 @@ record_read_memory (struct gdbarch *gdbarch,
|
||||
|
||||
/* Stop recording. */
|
||||
|
||||
static void
|
||||
static bool
|
||||
record_stop (struct target_ops *t)
|
||||
{
|
||||
DEBUG ("stop %s", t->shortname ());
|
||||
|
||||
t->stop_recording ();
|
||||
return t->stop_recording ();
|
||||
}
|
||||
|
||||
/* Unpush the record target. */
|
||||
@@ -179,7 +179,7 @@ record_disconnect (struct target_ops *t, const char *args, int from_tty)
|
||||
|
||||
DEBUG ("disconnect %s", t->shortname ());
|
||||
|
||||
record_stop (t);
|
||||
(void) record_stop (t);
|
||||
record_unpush (t);
|
||||
|
||||
target_disconnect (args, from_tty);
|
||||
@@ -194,7 +194,7 @@ record_detach (struct target_ops *t, inferior *inf, int from_tty)
|
||||
|
||||
DEBUG ("detach %s", t->shortname ());
|
||||
|
||||
record_stop (t);
|
||||
(void) record_stop (t);
|
||||
record_unpush (t);
|
||||
|
||||
target_detach (inf, from_tty);
|
||||
@@ -306,16 +306,17 @@ cmd_record_delete (const char *args, int from_tty)
|
||||
static void
|
||||
cmd_record_stop (const char *args, int from_tty)
|
||||
{
|
||||
struct target_ops *t;
|
||||
|
||||
t = require_record_target ();
|
||||
|
||||
record_stop (t);
|
||||
struct target_ops *t = require_record_target ();
|
||||
bool notify_stop = record_stop (t);
|
||||
record_unpush (t);
|
||||
|
||||
gdb_printf (_("Process record is stopped and all execution "
|
||||
"logs are deleted.\n"));
|
||||
|
||||
/* INFERIOR_PTID may have moved when we stopped recording. */
|
||||
if (notify_stop)
|
||||
notify_normal_stop (nullptr, true);
|
||||
|
||||
interps_notify_record_changed (current_inferior (), 0, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
34
gdb/remote.c
34
gdb/remote.c
@@ -7919,23 +7919,35 @@ remote_target::remote_notif_remove_queued_reply (ptid_t ptid)
|
||||
{
|
||||
remote_state *rs = get_remote_state ();
|
||||
|
||||
auto pred = [=] (const stop_reply_up &event)
|
||||
{
|
||||
/* A null ptid should only happen if we have a single process. It
|
||||
wouldn't match the process ptid, though, so let's check this case
|
||||
separately. */
|
||||
if ((event->ptid == null_ptid) && ptid.is_pid ())
|
||||
return true;
|
||||
|
||||
/* A minus one ptid should only happen for events that match
|
||||
everything. It wouldn't match a process or thread ptid, though, so
|
||||
let's check this case separately. */
|
||||
if (event->ptid == minus_one_ptid)
|
||||
return true;
|
||||
|
||||
return event->ptid.matches (ptid);
|
||||
};
|
||||
auto iter = std::find_if (rs->stop_reply_queue.begin (),
|
||||
rs->stop_reply_queue.end (),
|
||||
[=] (const stop_reply_up &event)
|
||||
{
|
||||
return event->ptid.matches (ptid);
|
||||
});
|
||||
rs->stop_reply_queue.end (), pred);
|
||||
stop_reply_up result;
|
||||
if (iter != rs->stop_reply_queue.end ())
|
||||
{
|
||||
result = std::move (*iter);
|
||||
rs->stop_reply_queue.erase (iter);
|
||||
}
|
||||
|
||||
if (notif_debug)
|
||||
gdb_printf (gdb_stdlog,
|
||||
"notif: discard queued event: 'Stop' in %s\n",
|
||||
ptid.to_string ().c_str ());
|
||||
if (notif_debug)
|
||||
gdb_printf (gdb_stdlog,
|
||||
"notif: discard queued event: 'Stop' in %s\n",
|
||||
ptid.to_string ().c_str ());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -8841,8 +8853,6 @@ ptid_t
|
||||
remote_target::wait (ptid_t ptid, struct target_waitstatus *status,
|
||||
target_wait_flags options)
|
||||
{
|
||||
REMOTE_SCOPED_DEBUG_ENTER_EXIT;
|
||||
|
||||
remote_state *rs = get_remote_state ();
|
||||
|
||||
/* Start by clearing the flag that asks for our wait method to be called,
|
||||
|
||||
@@ -172,7 +172,7 @@ struct dummy_target : public target_ops
|
||||
enum btrace_error read_btrace (struct btrace_data *arg0, struct btrace_target_info *arg1, enum btrace_read_type arg2) override;
|
||||
const struct btrace_config *btrace_conf (const struct btrace_target_info *arg0) override;
|
||||
enum record_method record_method (ptid_t arg0) override;
|
||||
void stop_recording () override;
|
||||
bool stop_recording () override;
|
||||
void info_record () override;
|
||||
void save_record (const char *arg0) override;
|
||||
bool supports_delete_record () override;
|
||||
@@ -353,7 +353,7 @@ struct debug_target : public target_ops
|
||||
enum btrace_error read_btrace (struct btrace_data *arg0, struct btrace_target_info *arg1, enum btrace_read_type arg2) override;
|
||||
const struct btrace_config *btrace_conf (const struct btrace_target_info *arg0) override;
|
||||
enum record_method record_method (ptid_t arg0) override;
|
||||
void stop_recording () override;
|
||||
bool stop_recording () override;
|
||||
void info_record () override;
|
||||
void save_record (const char *arg0) override;
|
||||
bool supports_delete_record () override;
|
||||
@@ -3794,24 +3794,28 @@ debug_target::record_method (ptid_t arg0)
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
target_ops::stop_recording ()
|
||||
{
|
||||
this->beneath ()->stop_recording ();
|
||||
return this->beneath ()->stop_recording ();
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
dummy_target::stop_recording ()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
bool
|
||||
debug_target::stop_recording ()
|
||||
{
|
||||
target_debug_printf_nofunc ("-> %s->stop_recording (...)", this->beneath ()->shortname ());
|
||||
this->beneath ()->stop_recording ();
|
||||
target_debug_printf_nofunc ("<- %s->stop_recording ()",
|
||||
this->beneath ()->shortname ());
|
||||
bool result
|
||||
= this->beneath ()->stop_recording ();
|
||||
target_debug_printf_nofunc ("<- %s->stop_recording () = %s",
|
||||
this->beneath ()->shortname (),
|
||||
target_debug_print_bool (result).c_str ());
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -1236,9 +1236,9 @@ struct target_ops
|
||||
virtual enum record_method record_method (ptid_t ptid)
|
||||
TARGET_DEFAULT_RETURN (RECORD_METHOD_NONE);
|
||||
|
||||
/* Stop trace recording. */
|
||||
virtual void stop_recording ()
|
||||
TARGET_DEFAULT_IGNORE ();
|
||||
/* Stop trace recording. Return whether the selected thread moved. */
|
||||
virtual bool stop_recording ()
|
||||
TARGET_DEFAULT_RETURN (false);
|
||||
|
||||
/* Print information about the recording. */
|
||||
virtual void info_record ()
|
||||
|
||||
@@ -15,8 +15,16 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
|
||||
static int
|
||||
fun (void)
|
||||
{
|
||||
int x = fun (); /* fun.1 */
|
||||
return x; /* fun.2 */
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
return 0;
|
||||
int x = fun (); /* main.1 */
|
||||
return x; /* main.2 */
|
||||
}
|
||||
|
||||
@@ -37,6 +37,10 @@ with_test_prefix "inferior 1" {
|
||||
if ![runto_main] {
|
||||
return -1
|
||||
}
|
||||
|
||||
gdb_test_no_output "record btrace"
|
||||
gdb_test "step 4" "fun\.1.*"
|
||||
gdb_test "reverse-step" "fun\.1.*"
|
||||
}
|
||||
|
||||
with_test_prefix "inferior 2" {
|
||||
@@ -48,25 +52,22 @@ with_test_prefix "inferior 2" {
|
||||
return -1
|
||||
}
|
||||
|
||||
gdb_test_no_output "record btrace" "record btrace"
|
||||
gdb_test_no_output "record btrace"
|
||||
gdb_test "step 4" "fun\.1.*"
|
||||
gdb_test "reverse-step" "fun\.1.*"
|
||||
|
||||
gdb_test "info record" "Replay in progress.*"
|
||||
gdb_test "record stop" "Process record is stopped.*"
|
||||
|
||||
gdb_test "step" "fun\.1.*"
|
||||
}
|
||||
|
||||
with_test_prefix "inferior 1" {
|
||||
gdb_test "inferior 1" "Switching to inferior 1.*"
|
||||
|
||||
gdb_test "info record" "No recording is currently active\\."
|
||||
gdb_test_no_output "record btrace" "record btrace"
|
||||
}
|
||||
|
||||
with_test_prefix "inferior 3" {
|
||||
gdb_test "add-inferior -exec ${host_binfile}" "Added inferior 3.*" \
|
||||
"add third inferior"
|
||||
gdb_test "inferior 3" "Switching to inferior 3.*"
|
||||
|
||||
if ![runto_main] {
|
||||
return -1
|
||||
}
|
||||
|
||||
gdb_test "info record" "No recording is currently active\\."
|
||||
gdb_test_no_output "record btrace" "record btrace"
|
||||
gdb_test "info record" "Replay in progress.*"
|
||||
gdb_test "reverse-finish" "fun\.1.*"
|
||||
gdb_test "record goto end" "fun\.1.*"
|
||||
gdb_test "step 2" "fun\.1.*"
|
||||
gdb_test "reverse-step 3"
|
||||
}
|
||||
|
||||
@@ -28,21 +28,29 @@ if ![runto_main] {
|
||||
return -1
|
||||
}
|
||||
|
||||
# trace the call to the test function
|
||||
# Trace the call to the test function.
|
||||
with_test_prefix "record" {
|
||||
gdb_test_no_output "record btrace"
|
||||
gdb_test "next"
|
||||
gdb_test "step"
|
||||
gdb_test "next 2"
|
||||
}
|
||||
|
||||
# let's step around a bit
|
||||
# Let's step around a bit.
|
||||
with_test_prefix "replay" {
|
||||
gdb_test "reverse-next" ".*main\.2.*" "reverse-next.1"
|
||||
gdb_test "reverse-finish" ".*main\.2.*" "reverse-finish.1"
|
||||
gdb_test "step" ".*fun4\.2.*" "step.1"
|
||||
gdb_test "next" ".*fun4\.3.*" "next.1"
|
||||
gdb_test "step" ".*fun2\.2.*" "step.2"
|
||||
gdb_test "finish" ".*fun4\.4.*" "finish.1"
|
||||
gdb_test "reverse-step" ".*fun2\.3.*" "reverse-step.1"
|
||||
gdb_test "reverse-finish" ".*fun4\.3.*" "reverse-finish.1"
|
||||
gdb_test "reverse-next" ".*fun4\.2.*" "reverse-next.2"
|
||||
gdb_test "reverse-finish" ".*main\.2.*" "reverse-finish.2"
|
||||
gdb_test "reverse-finish" ".*fun4\.3.*" "reverse-finish.2"
|
||||
gdb_test "reverse-step" ".*fun1\.2.*" "reverse-step.1"
|
||||
gdb_test "finish" ".*fun4\.3.*" "finish.1"
|
||||
gdb_test "reverse-next" ".*fun4\.2.*" "reverse-next.1"
|
||||
gdb_test "reverse-finish" ".*main\.2.*" "reverse-finish.3"
|
||||
}
|
||||
|
||||
# Stop recording and try to step live (pr19340).
|
||||
with_test_prefix "live" {
|
||||
gdb_test "record stop" "Process record is stopped.*fun4\.4.*"
|
||||
gdb_test "reverse-next" "Target .* does not support this command.*"
|
||||
gdb_test "step" ".*fun3\.2.*"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user