* lib/mi-support.exp (mi_expect_stop): Produce

more details on failures.
	* gdb.mi/mi-nonstop.exp: New.
	* gdb.mi/non-stop.c: New.
This commit is contained in:
Vladimir Prus 2008-08-19 14:13:29 +00:00
parent 7f7efbd95f
commit 8cf6e61a08
4 changed files with 296 additions and 1 deletions

View File

@ -1,3 +1,10 @@
2008-08-19 Vladimir Prus <vladimir@codesourcery.com>
* lib/mi-support.exp (mi_expect_stop): Produce
more details on failures.
* gdb.mi/mi-nonstop.exp: New.
* gdb.mi/non-stop.c: New.
2008-08-19 Vladimir Prus <vladimir@codesourcery.com>
* gdb.mi/mi-async.exp: Use 'set target-async'.

View File

@ -0,0 +1,197 @@
# Copyright 2002, 2003, 2004, 2005, 2007, 2008 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/>.
# This only works with native configurations
if {![isnative]} {
return
}
load_lib mi-support.exp
set MIFLAGS "-i=mi"
gdb_exit
if {[mi_gdb_start]} {
continue
}
proc myreverse { list } {
if { [llength $list] <= 1 } {
return $list
}
set tail [lrange $list 1 [llength $list]]
set rtail [myreverse $tail]
lappend rtail [lindex $list 0]
return $rtail
}
proc check_thread_states { xstates test } {
global expect_out
set states [myreverse $xstates]
set pattern "\\^done,threads=\\\["
foreach s $states {
set pattern "${pattern}(.*)state=\"$s\""
}
set pattern "$pattern\\\}\\\].*"
verbose -log "expecting: $pattern"
mi_gdb_test "-thread-info" $pattern $test
}
#
# Start here
#
set testfile "non-stop"
set srcfile "$testfile.c"
set binfile "$objdir/$subdir/mi-$testfile"
set options [list debug incdir=$objdir]
if {[gdb_compile_pthreads "$srcdir/$subdir/$srcfile" $binfile executable $options] != "" } {
return -1
}
mi_gdb_reinitialize_dir $srcdir/$subdir
mi_gdb_load $binfile
set supported 0
send_gdb "-gdb-show non-stop\n"
gdb_expect {
-re ".*\\^done,value=\"off\",supported=\"(\[^\"\]+)\"\r\n$mi_gdb_prompt$" {
if { $expect_out(1,string) == "1" } {
set supported 1
}
}
-re ".$mi_gdb_prompt$" {
}
}
if { $supported == 0 } {
verbose -log "Non-stop mode not supported by the target, skipping tests"
return
}
mi_gdb_test "-gdb-set non-stop 1" ".*"
mi_gdb_test "-gdb-set target-async 1" ".*"
detect_async
mi_runto main
mi_create_breakpoint break_at_me 2 keep break_at_me .* .* .* "breakpoint at marker"
mi_send_resuming_command "exec-continue" "resume 1"
mi_expect_stop "breakpoint-hit" "break_at_me" ".*" "non-stop.c" ".*" {"" "disp=\"keep\""} "w0,i0 stop"
mi_expect_stop "breakpoint-hit" "break_at_me" ".*" "non-stop.c" ".*" {"" "disp=\"keep\""} "w1,i0 stop"
check_thread_states {"running" "stopped" "stopped"} "thread state, stop 1"
mi_gdb_test "-thread-select 2" "\\^done.*" "select thread 2"
mi_create_varobj I_W0 "i" "create varobj in first thread"
mi_gdb_test "-thread-select 3" "\\^done.*" "select thread 3"
mi_create_varobj I_W1 "i" "create varobj in second thread"
mi_send_resuming_command "exec-continue --thread 2" "resume 1"
check_thread_states {"running" "running" "stopped"} "thread state, resume 1"
mi_expect_stop "breakpoint-hit" "break_at_me" ".*" "non-stop.c" ".*" {"" "disp=\"keep\""} "w0,i1 stop"
check_thread_states {"running" "stopped" "stopped"} "thread state, stop 2"
mi_send_resuming_command "exec-continue --thread 3" "resume 2"
check_thread_states {"running" "stopped" "running"} "thread state, resume 2"
mi_expect_stop "breakpoint-hit" "break_at_me" ".*" "non-stop.c" ".*" {"" "disp=\"keep\""} "w1,i1 stop"
check_thread_states {"running" "stopped" "stopped"} "thread state, stop 3"
mi_varobj_update * {I_W1 I_W0} "update varobj, 1"
mi_check_varobj_value I_W0 1 "check varobj, w0, 1"
mi_check_varobj_value I_W1 1 "check varobj, w1, 1"
send_gdb "-exec-interrupt --thread 1\n"
gdb_expect {
-re "\\^done\r\n$mi_gdb_prompt\\*stopped\[^\r\n\]+\r\n$" {
pass "interrupted"
}
timeout {
fail "interrupted (timeout)"
}
}
# The interrupt command sends SIGINT to the target, and therefore the
# thread might not be stopped immediately when we return from the target.
# So, wait a bit
sleep 1
check_thread_states {"stopped" "stopped" "stopped"} "thread state, stop 4"
# Note that the order of *running notifications below is 'unnatural'. This is because
# we do only one out-of-line step at the time, so one thread gets resumed immediately
# and another has to wait.
send_gdb "-exec-continue --all\n"
gdb_expect {
-re ".*\\*running,thread-id=\"3\".*\\*running,thread-id=\"1\".*\\*running,thread-id=\"2\"\r\n" {
pass "resume all"
}
timeout {
fail "resume all (timeout)"
}
}
check_thread_states {"running" "running" "running"} "thread state, resume all"
mi_expect_stop "breakpoint-hit" "break_at_me" ".*" "non-stop.c" ".*" {"" "disp=\"keep\""} "w0,i2 stop"
mi_expect_stop "breakpoint-hit" "break_at_me" ".*" "non-stop.c" ".*" {"" "disp=\"keep\""} "w1,i2 stop"
# At this point, thread 1 (main) is running, and worker threads are stopped.
# Check that we can modify breakpoint condition, even when operating on a
# running thread.
mi_gdb_test "-break-condition --thread 1 2 id==1" "\\^done" "set condition, 1"
mi_send_resuming_command "exec-continue --thread 2" "resume 2"
mi_send_resuming_command "exec-continue --thread 3" "resume 3"
sleep 2
mi_expect_stop "breakpoint-hit" "break_at_me" ".*" "non-stop.c" ".*" {"" "disp=\"keep\""} "w0,i3 stop"
check_thread_states {"running" "running" "stopped"} "thread state, stop on cond breakpoint"
# Check that when we update all varobj, we don't get no error about varobj
# bound to running thread.
mi_varobj_update * {I_W1} "update varobj, 2"
mi_check_varobj_value I_W1 3 "check varobj, w1, 1"
# Check that stack commands are allowed on a stopped thread, even if some other threads
# are running, and produce something sane. Also check we check error on running thread.
mi_gdb_test "-stack-list-frames --thread 2" "\\^error,msg=\".*\"" "stacktrace of running thread"
mi_gdb_test "-stack-list-frames --thread 3" \
"\\^done,stack=\\\[frame={level=\"0\",addr=\".*\",func=\"break_at_me\".*" \
"stacktrace of stopped thread"
# verify that after thread exit, the thread is reported as exited in -thread-info, and
# we can still interact with other threads.
mi_gdb_test "-thread-select 2" "\\^done.*" "select first worker thread"
# Since thread 2 is running, we need to set variable via another thread.
mi_gdb_test "-gdb-set --thread 3 variable exit_first_thread=1" ".*\\^done" "ask the second thread to exit"
gdb_expect {
-re ".*=thread-exited,id=\"2\"\r\n$" {
pass "wait for thread exit"
}
timeout {
fail "wait for thread exit (timeout)"
}
}
# See that we can still poke other threads.
mi_gdb_test "-stack-list-frames --thread 3" \
"\\^done,stack=\\\[frame={level=\"0\",addr=\".*\",func=\"break_at_me\".*" \
"stacktrace of stopped thread"
mi_gdb_exit

View File

@ -0,0 +1,89 @@
/* Test program for non-stop debugging.
Copyright 1996, 2002, 2003, 2004, 2007, 2008 Free Software Foundation, Inc.
This file is part of GDB.
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/>. */
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
/* Under OSF 2.0 & 3.0 and HPUX 10, the second arg of pthread_create
is prototyped to be just a "pthread_attr_t", while under Solaris it
is a "pthread_attr_t *". Arg! */
#if defined (__osf__) || defined (__hpux__)
#define PTHREAD_CREATE_ARG2(arg) arg
#define PTHREAD_CREATE_NULL_ARG2 null_attr
static pthread_attr_t null_attr;
#else
#define PTHREAD_CREATE_ARG2(arg) &arg
#define PTHREAD_CREATE_NULL_ARG2 NULL
#endif
int exit_first_thread = 0;
void break_at_me (int id, int i)
{
}
void *
worker (void *arg)
{
int id = (int)arg;
int i = 0;
/* When gdb is running, it sets hidden breakpoints in the thread
library. The signals caused by these hidden breakpoints can
cause system calls such as 'sleep' to return early. Pay attention
to the return value from 'sleep' to get the full sleep. */
for (;;++i)
{
int unslept = 1;
while (unslept > 0)
unslept = sleep (unslept);
if (exit_first_thread && id == 0)
return;
break_at_me (id, i);
}
}
pthread_t
create_thread (int id)
{
pthread_t tid;
if (pthread_create (&tid, PTHREAD_CREATE_NULL_ARG2, worker, (void *) id))
{
perror ("pthread_create 1");
exit (1);
}
return tid;
}
int
main (int argc, char *argv[])
{
pthread_t tid;
create_thread (0);
sleep (1);
tid = create_thread (1);
pthread_join (tid, NULL);
return 0;
}

View File

@ -1009,17 +1009,19 @@ 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}thread-id=\"$decimal\",stopped-threads=.*,frame=\{addr=\"$hex\",func=\"$func\",args=$args,file=\".*$file\",fullname=\"${fullname_syntax}$file\",line=\"$line\"\}$after_stopped\r\n$prompt_re$"
verbose -log "mi_expect_stop: expecting: \\*stopped,${r}${a}${bn}thread-id=\"$decimal\",stopped-threads=.*,frame=\{addr=\"$hex\",func=\"$func\",args=$args,file=\".*$file\",fullname=\"${fullname_syntax}$file\",line=\"$line\"\}\r\n$after_stopped$prompt_re$"
gdb_expect {
-re "\\*stopped,${r}${a}${bn}thread-id=\"$decimal\",stopped-threads=.*,frame=\{addr=\"$hex\",func=\"$func\",args=$args,file=\".*$file\",fullname=\"${fullname_syntax}$file\",line=\"($line)\"\}$after_stopped\r\n$prompt_re$" {
pass "$test"
return $expect_out(2,string)
}
-re "\\*stopped,${r}${a}${bn}thread-id=\"$decimal\",stopped-threads=.*,frame=\{addr=\"$hex\",func=\".*\",args=\[\\\[\{\].*\[\\\]\}\],file=\".*\",fullname=\"${fullname_syntax}.*\",line=\"\[0-9\]*\"\}.*\r\n$prompt_re$" {
verbose -log "got $expect_out(buffer)"
fail "$test (stopped at wrong place)"
return -1
}
-re ".*\r\n$mi_gdb_prompt$" {
verbose -log "got $expect_out(buffer)"
fail "$test (unknown output after running)"
return -1
}