mirror of
https://github.com/bminor/binutils-gdb.git
synced 2025-11-16 12:34:43 +00:00
Compare commits
8 Commits
binutils-2
...
users/mmet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31d025c07d | ||
|
|
8c62f01902 | ||
|
|
8e1542c8aa | ||
|
|
8cca3e100f | ||
|
|
41af4a217b | ||
|
|
037ca1addd | ||
|
|
b323ffa153 | ||
|
|
e0139aa5f2 |
@@ -2785,10 +2785,9 @@ new_stop_id (void)
|
||||
current_stop_id++;
|
||||
}
|
||||
|
||||
/* Clear out all variables saying what to do when inferior is continued.
|
||||
First do this, then set the ones you want, then call `proceed'. */
|
||||
/* See infrun.h. */
|
||||
|
||||
static void
|
||||
void
|
||||
clear_proceed_status_thread (struct thread_info *tp)
|
||||
{
|
||||
if (debug_infrun)
|
||||
|
||||
@@ -80,6 +80,9 @@ extern void start_remote (int from_tty);
|
||||
step/stepi command. */
|
||||
extern void clear_proceed_status (int step);
|
||||
|
||||
/* Clear out the proceed status of TP. */
|
||||
extern void clear_proceed_status_thread (struct thread_info *tp);
|
||||
|
||||
extern void proceed (CORE_ADDR, enum gdb_signal);
|
||||
|
||||
/* The `resume' routine should only be called in special circumstances.
|
||||
|
||||
@@ -97,6 +97,11 @@ static struct cmd_list_element *show_record_btrace_pt_cmdlist;
|
||||
} \
|
||||
while (0)
|
||||
|
||||
static void record_btrace_set_replay (struct thread_info *tp,
|
||||
const struct btrace_insn_iterator *it);
|
||||
|
||||
static void record_btrace_stop_replaying (struct thread_info *tp);
|
||||
|
||||
|
||||
/* Update the branch trace for the current thread and return a pointer to its
|
||||
thread_info.
|
||||
@@ -252,9 +257,57 @@ record_btrace_stop_recording (struct target_ops *self)
|
||||
|
||||
record_btrace_auto_disable ();
|
||||
|
||||
ALL_NON_EXITED_THREADS (tp)
|
||||
if (tp->btrace.target != NULL)
|
||||
btrace_disable (tp);
|
||||
/* In non-stop mode, we indicate the implicit move of each replaying thread.
|
||||
In stop-all mode, we indicate the implicit move of the selected thread if
|
||||
it is replaying. Other threads are silently moved. The MI notification
|
||||
will indicate that all threads have been stopped which should be enough to
|
||||
indicate this implicit move to front-ends. */
|
||||
if (non_stop)
|
||||
{
|
||||
ALL_NON_EXITED_THREADS (tp)
|
||||
if (tp->btrace.target != NULL)
|
||||
{
|
||||
if (btrace_is_replaying (tp))
|
||||
{
|
||||
printf_filtered (_("Thread %s (%s) stopped replaying.\n"),
|
||||
print_thread_id (tp),
|
||||
target_pid_to_str (tp->ptid));
|
||||
record_btrace_set_replay (tp, NULL);
|
||||
}
|
||||
|
||||
btrace_disable (tp);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int send_stopped = 0;
|
||||
|
||||
/* If the selected thread is replaying, we do an implicit "record goto
|
||||
end" to make it stop replaying and indicate this to front-ends. This
|
||||
causes the updated location to be printed for the selected thread.
|
||||
|
||||
If it isn't replaying, we will send an unspecific stopped notification
|
||||
to front-ends at the end. This doesn't print the (unchanged) location
|
||||
but indicates to front-ends that other thread's locations may have
|
||||
changed. */
|
||||
tp = inferior_thread ();
|
||||
if (tp != NULL && btrace_is_replaying (tp))
|
||||
record_btrace_set_replay (tp, NULL);
|
||||
else
|
||||
send_stopped = 1;
|
||||
|
||||
ALL_NON_EXITED_THREADS (tp)
|
||||
if (tp->btrace.target != NULL)
|
||||
{
|
||||
/* Stop replaying before we disable tracing to clear TP's register
|
||||
state in addition to the btrace state. */
|
||||
record_btrace_stop_replaying (tp);
|
||||
btrace_disable (tp);
|
||||
}
|
||||
|
||||
if (send_stopped)
|
||||
observer_notify_normal_stop (NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/* The to_close method of target record-btrace. */
|
||||
@@ -2704,7 +2757,12 @@ record_btrace_set_replay (struct thread_info *tp,
|
||||
btinfo = &tp->btrace;
|
||||
|
||||
if (it == NULL || it->function == NULL)
|
||||
record_btrace_stop_replaying (tp);
|
||||
{
|
||||
if (!btrace_is_replaying (tp))
|
||||
return;
|
||||
|
||||
record_btrace_stop_replaying (tp);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (btinfo->replay == NULL)
|
||||
@@ -2719,8 +2777,12 @@ record_btrace_set_replay (struct thread_info *tp,
|
||||
/* Start anew from the new replay position. */
|
||||
record_btrace_clear_histories (btinfo);
|
||||
|
||||
stop_pc = regcache_read_pc (get_current_regcache ());
|
||||
print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
|
||||
/* We changed the PC of TP. Update the global state if TP is the selected
|
||||
thread. */
|
||||
if (ptid_equal (tp->ptid, inferior_ptid))
|
||||
stop_pc = regcache_read_pc (get_current_regcache ());
|
||||
|
||||
record_signal_goto_stop (tp);
|
||||
}
|
||||
|
||||
/* The to_goto_record_begin method of target record-btrace. */
|
||||
|
||||
@@ -1905,7 +1905,7 @@ record_full_goto_entry (struct record_full_entry *p)
|
||||
registers_changed ();
|
||||
reinit_frame_cache ();
|
||||
stop_pc = regcache_read_pc (get_current_regcache ());
|
||||
print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
|
||||
record_signal_goto_stop (inferior_thread ());
|
||||
}
|
||||
|
||||
/* The "to_goto_record_begin" target method. */
|
||||
|
||||
35
gdb/record.c
35
gdb/record.c
@@ -26,6 +26,7 @@
|
||||
#include "common/common-utils.h"
|
||||
#include "cli/cli-utils.h"
|
||||
#include "disasm.h"
|
||||
#include "gdbthread.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
@@ -80,6 +81,16 @@ require_record_target (void)
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Check that the inferior thread is not running. Throw an error if it is. */
|
||||
|
||||
static void
|
||||
require_not_running (void)
|
||||
{
|
||||
if (is_running (inferior_ptid))
|
||||
error (_("Cannot execute this command while "
|
||||
"the selected thread is running."));
|
||||
}
|
||||
|
||||
/* See record.h. */
|
||||
|
||||
void
|
||||
@@ -331,6 +342,27 @@ cmd_record_save (char *args, int from_tty)
|
||||
|
||||
/* See record.h. */
|
||||
|
||||
void
|
||||
record_signal_goto_stop (struct thread_info *tp)
|
||||
{
|
||||
struct target_waitstatus ws;
|
||||
struct cleanup *cleanup;
|
||||
|
||||
clear_proceed_status_thread (tp);
|
||||
|
||||
cleanup = make_cleanup_restore_current_thread ();
|
||||
switch_to_thread (tp->ptid);
|
||||
|
||||
ws.kind = TARGET_WAITKIND_NO_RESUMED;
|
||||
set_last_target_status (tp->ptid, ws);
|
||||
|
||||
observer_notify_normal_stop (NULL, 1);
|
||||
|
||||
do_cleanups (cleanup);
|
||||
}
|
||||
|
||||
/* See record.h. */
|
||||
|
||||
void
|
||||
record_goto (const char *arg)
|
||||
{
|
||||
@@ -342,6 +374,7 @@ record_goto (const char *arg)
|
||||
insn = parse_and_eval_long (arg);
|
||||
|
||||
require_record_target ();
|
||||
require_not_running ();
|
||||
target_goto_record (insn);
|
||||
}
|
||||
|
||||
@@ -365,6 +398,7 @@ cmd_record_goto_begin (char *arg, int from_tty)
|
||||
error (_("Junk after argument: %s."), arg);
|
||||
|
||||
require_record_target ();
|
||||
require_not_running ();
|
||||
target_goto_record_begin ();
|
||||
}
|
||||
|
||||
@@ -377,6 +411,7 @@ cmd_record_goto_end (char *arg, int from_tty)
|
||||
error (_("Junk after argument: %s."), arg);
|
||||
|
||||
require_record_target ();
|
||||
require_not_running ();
|
||||
target_goto_record_end ();
|
||||
}
|
||||
|
||||
|
||||
@@ -91,4 +91,7 @@ extern struct target_ops *find_record_target (void);
|
||||
it does anything. */
|
||||
extern void record_preopen (void);
|
||||
|
||||
/* Signal a record-goto stop of TP to front-ends. */
|
||||
extern void record_signal_goto_stop (struct thread_info *tp);
|
||||
|
||||
#endif /* _RECORD_H_ */
|
||||
|
||||
@@ -27,7 +27,9 @@ test (void *arg)
|
||||
i = 0; /* bp.1 */
|
||||
for (; i < 10; ++i) global += i; /* loop */
|
||||
|
||||
return arg; /* bp.2 */
|
||||
global *= 2; /* bp.2 */
|
||||
|
||||
return arg; /* bp.3 */
|
||||
}
|
||||
|
||||
int
|
||||
@@ -41,5 +43,5 @@ main (void)
|
||||
|
||||
pthread_join (th, NULL);
|
||||
|
||||
return 0; /* bp.3 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -239,7 +239,22 @@ with_test_prefix "no progress" {
|
||||
}
|
||||
|
||||
# now that both threads stopped replaying we may resume recording
|
||||
with_test_prefix "cont to end" {
|
||||
with_test_prefix "resume recording" {
|
||||
gdb_breakpoint $bp_3
|
||||
gdb_cont_to_bp_line "$srcfile:$bp_3" all 1
|
||||
gdb_cont_to_bp_line "$srcfile:$bp_3" all 2
|
||||
}
|
||||
|
||||
# when we stop recording we get notifications for replaying threads
|
||||
with_test_prefix "stop" {
|
||||
gdb_test "thread 1" ".*"
|
||||
gdb_test "thread apply 2 record goto begin" ".*"
|
||||
|
||||
gdb_test "record stop" [multi_line \
|
||||
"Thread 2 \[^\\\r\\\n\]* stopped replaying\." \
|
||||
"\[^\\\r\\\n\]*$srcfile:$bp_3" \
|
||||
"$bp_3\[^\\\r\\\n\]* bp\.3 \[^\\\r\\\n\]*" \
|
||||
"Process record is stopped and all execution logs are deleted\." \
|
||||
]
|
||||
|
||||
gdb_test "info record" "No record target is currently active\."
|
||||
}
|
||||
|
||||
@@ -160,6 +160,9 @@ gdb_test "record instruction-history -" [multi_line \
|
||||
# check that we can go to the end of the trace
|
||||
gdb_test "record goto end" ".*main \\(\\) at record_goto.c:50.*"
|
||||
|
||||
# check that we don't repeat the current location if we go to the end again
|
||||
gdb_test_no_output "record goto end" "goto end again"
|
||||
|
||||
# check that we're filling up the context correctly
|
||||
gdb_test "record function-call-history /ci" [multi_line \
|
||||
"14\t fun2\tinst 35,36" \
|
||||
|
||||
70
gdb/testsuite/gdb.btrace/stop.exp
Normal file
70
gdb/testsuite/gdb.btrace/stop.exp
Normal file
@@ -0,0 +1,70 @@
|
||||
# This testcase is part of GDB, the GNU debugger.
|
||||
#
|
||||
# Copyright 2016 Free Software Foundation, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# check for btrace support
|
||||
if { [skip_btrace_tests] } { return -1 }
|
||||
|
||||
standard_testfile record_goto.c
|
||||
|
||||
# start inferior
|
||||
if [prepare_for_testing $testfile.exp $testfile $srcfile] {
|
||||
return -1
|
||||
}
|
||||
|
||||
# we use the list command to check the current source location
|
||||
gdb_test "set listsize 1"
|
||||
|
||||
if ![runto_main] {
|
||||
return -1
|
||||
}
|
||||
|
||||
# trace the call to the test function
|
||||
gdb_test_no_output "record btrace" "move: enable"
|
||||
gdb_test "next" ".*main\.3.*" "move: trace"
|
||||
|
||||
# move to the beginning of the trace
|
||||
gdb_test "record goto begin" ".*main\.2.*" "move: navigate"
|
||||
|
||||
# when we stop recording, we move back to the end of the trace
|
||||
gdb_test "record stop" "main\.3.*Process record is stopped.*" "move: stop"
|
||||
|
||||
# check that we're really there
|
||||
gdb_test "list" ".*main\.3.*" "move: at end of trace"
|
||||
|
||||
if ![runto_main] {
|
||||
return -1
|
||||
}
|
||||
|
||||
# trace the call to the test function
|
||||
gdb_test_no_output "record btrace" "already: enable"
|
||||
gdb_test "next" ".*main\.3.*" "already: trace"
|
||||
|
||||
# we're already at the end so we didn't have to move
|
||||
gdb_test_multiple "record stop" "already: stop" {
|
||||
-re "main.*$gdb_prompt $" {
|
||||
fail "already: stop"
|
||||
}
|
||||
-re "Process record is stopped\[^\\\r\\\n\]*\r\n$gdb_prompt $" {
|
||||
pass "already: stop"
|
||||
}
|
||||
-re "$gdb_prompt $" {
|
||||
fail "already: stop"
|
||||
}
|
||||
}
|
||||
|
||||
# check that we're really there
|
||||
gdb_test "list" ".*main\.3.*" "already: at end of trace"
|
||||
@@ -93,6 +93,7 @@ proc test_controlled_execution_reverse {} {
|
||||
global line_callee1_head line_callee1_body line_callee1_close
|
||||
global line_main_head line_main_body
|
||||
global line_main_hello line_main_callme_1
|
||||
global line_callme_body
|
||||
|
||||
# Test exec-reverse-finish
|
||||
|
||||
@@ -166,6 +167,14 @@ proc test_controlled_execution_reverse {} {
|
||||
"" "main" "" \
|
||||
"basics.c" $line_main_body "" \
|
||||
"reverse-continue at main"
|
||||
|
||||
send_gdb "record goto end\n"
|
||||
mi_expect_stop "" "callme" "\{name=\"i\",value=\"1\"\}" "basics.c" \
|
||||
$line_callme_body { "" "" "\\^done\r\n" } "record goto end"
|
||||
|
||||
send_gdb "record goto begin\n"
|
||||
mi_expect_stop "" "main" "" "basics.c" $line_main_body \
|
||||
{ "" "" "\\^done\r\n" } "record goto begin"
|
||||
}
|
||||
|
||||
test_controlled_execution_reverse
|
||||
|
||||
@@ -1127,6 +1127,8 @@ proc mi_detect_async {} {
|
||||
# output right after *stopped, and the second element is output
|
||||
# right after reason field. The regex after reason should not include
|
||||
# the comma separating it from the following fields.
|
||||
# If EXTRA is a list of three elements, the first two are for the above
|
||||
# and the third element is for output right before GDB prompt.
|
||||
#
|
||||
# When we fail to match output at all, -1 is returned. If FILE does
|
||||
# match and the target system has no debug info for FILE return 0.
|
||||
@@ -1150,7 +1152,15 @@ proc mi_expect_stop { reason func args file line extra test } {
|
||||
|
||||
set after_stopped ""
|
||||
set after_reason ""
|
||||
if { [llength $extra] == 2 } {
|
||||
set before_prompt ""
|
||||
if { [llength $extra] == 3 } {
|
||||
set after_stopped [lindex $extra 0]
|
||||
set after_reason [lindex $extra 1]
|
||||
if { $after_reason != "" } {
|
||||
set after_reason "${after_reason},"
|
||||
}
|
||||
set before_prompt [lindex $extra 2]
|
||||
} elseif { [llength $extra] == 2 } {
|
||||
set after_stopped [lindex $extra 0]
|
||||
set after_reason [lindex $extra 1]
|
||||
set after_reason "${after_reason},"
|
||||
@@ -1166,7 +1176,7 @@ proc mi_expect_stop { reason func args file line extra test } {
|
||||
|
||||
if { $reason == "really-no-reason" } {
|
||||
gdb_expect {
|
||||
-re "\\*stopped\r\n$prompt_re" {
|
||||
-re "\\*stopped\r\n$before_prompt$prompt_re" {
|
||||
pass "$test"
|
||||
}
|
||||
timeout {
|
||||
@@ -1179,7 +1189,7 @@ proc mi_expect_stop { reason func args file line extra test } {
|
||||
if { $reason == "exited-normally" } {
|
||||
|
||||
gdb_expect {
|
||||
-re "\\*stopped,reason=\"exited-normally\"\r\n$prompt_re" {
|
||||
-re "\\*stopped,reason=\"exited-normally\"\r\n$before_prompt$prompt_re" {
|
||||
pass "$test"
|
||||
}
|
||||
-re ".*$mi_gdb_prompt$" {fail "continue to end (2)"}
|
||||
@@ -1191,7 +1201,7 @@ proc mi_expect_stop { reason func args file line extra test } {
|
||||
}
|
||||
if { $reason == "exited" } {
|
||||
gdb_expect {
|
||||
-re "\\*stopped,reason=\"exited\",exit-code=\"\[0-7\]+\"\r\n$prompt_re" {
|
||||
-re "\\*stopped,reason=\"exited\",exit-code=\"\[0-7\]+\"\r\n$before_prompt$prompt_re" {
|
||||
pass "$test"
|
||||
}
|
||||
-re ".*$mi_gdb_prompt$" {
|
||||
@@ -1205,7 +1215,7 @@ proc mi_expect_stop { reason func args file line extra test } {
|
||||
}
|
||||
|
||||
if { $reason == "solib-event" } {
|
||||
set pattern "\\*stopped,reason=\"solib-event\",thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re"
|
||||
set pattern "\\*stopped,reason=\"solib-event\",thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$before_prompt$prompt_re"
|
||||
verbose -log "mi_expect_stop: expecting: $pattern"
|
||||
gdb_expect {
|
||||
-re "$pattern" {
|
||||
@@ -1235,9 +1245,9 @@ proc mi_expect_stop { reason func args file line extra test } {
|
||||
|
||||
set a $after_reason
|
||||
|
||||
verbose -log "mi_expect_stop: expecting: \\*stopped,${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"$line\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re"
|
||||
verbose -log "mi_expect_stop: expecting: \\*stopped,${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"$line\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$before_prompt$prompt_re"
|
||||
gdb_expect {
|
||||
-re "\\*stopped,${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"($line)\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re" {
|
||||
-re "\\*stopped,${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"($line)\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$before_prompt$prompt_re" {
|
||||
pass "$test"
|
||||
if {[array names expect_out "2,string"] != ""} {
|
||||
return $expect_out(2,string)
|
||||
@@ -1245,7 +1255,7 @@ proc mi_expect_stop { reason func args file line extra test } {
|
||||
# No debug info available but $file does match.
|
||||
return 0
|
||||
}
|
||||
-re "\\*stopped,${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$any\",args=\[\\\[\{\]$any\[\\\]\}\],file=\"$any\",fullname=\"${fullname_syntax}$any\",line=\"\[0-9\]*\"\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re" {
|
||||
-re "\\*stopped,${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$any\",args=\[\\\[\{\]$any\[\\\]\}\],file=\"$any\",fullname=\"${fullname_syntax}$any\",line=\"\[0-9\]*\"\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$before_prompt$prompt_re" {
|
||||
verbose -log "got $expect_out(buffer)"
|
||||
fail "$test (stopped at wrong place)"
|
||||
return -1
|
||||
|
||||
Reference in New Issue
Block a user