This is the mail archive of the gdb@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFC] Python Finish Breakpoints


Hello,

I prepared some tests which show the behavior of this new Breakpoint
type in various environment:
- normal termination, forced termination (gdb return)
- longjmp
- c++ exception
- breakpoint condition

there is two bits which differs from what I expected, in the
breakpoint conditions

* setting a BP in a DUMMY_FRAME: the `stop' function will be triggerd,
but it's return value (stop or continue/booleans) won't be taken into
account. I'm not sure whether the kind of FinishBreakpoint should be
forbidden or not, because I may want to track ALL the calls to that
function, including GDB inferior calls

* the "normal_stop" notification if not triggered during condition
evaluation, so the `out_of_scope_notif' flag is not turn off (more
generally, the notification should be disabled when the breakpoint is
hit, and not when GDB stops)


otherwise, for c++ exception, the return PC of a frame surrounded by a
try/catch is at the end of the catch, so with
try { fct_1() } catch { ... }, a FinishBreakpoint in fct_1 will be
correcty catch, but it won't work for function nested within fct_1.



Does this testsuite match your expectations, or would you like it to
be more advanced? (I'll need more hints in this case)


cordially,

Kevin


diff --git a/gdb/testsuite/gdb.python/py-finish-breakpoint-cc.cc
b/gdb/testsuite/gdb.python/py-finish-breakpoint-cc.cc
new file mode 100644
index 0000000..a0eea06
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-finish-breakpoint-cc.cc
@@ -0,0 +1,59 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2011 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/>.
+*/
+
+
+#include <iostream>
+
+void
+throw_exception_1 (int e)
+{
+  throw new int (e);
+}
+
+void
+throw_exception (int e)
+{
+  throw_exception_1 (e);
+}
+
+int
+main (void)
+{
+  int i;
+  try
+    {
+      throw_exception_1 (10);
+    }
+  catch (const int *e)
+    {
+        std::cerr << "Exception #" << *e << std::endl;
+    }
+  i += 1; /* Break after exception 1.  */
+
+  try
+    {
+      throw_exception (10);
+    }
+  catch (const int *e)
+    {
+        std::cerr << "Exception #" << *e << std::endl;
+    }
+  i += 1; /* Break after exception 2.  */
+
+  return i;
+}
diff --git a/gdb/testsuite/gdb.python/py-finish-breakpoint-cc.exp
b/gdb/testsuite/gdb.python/py-finish-breakpoint-cc.exp
new file mode 100644
index 0000000..e74023d
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-finish-breakpoint-cc.exp
@@ -0,0 +1,59 @@
+# Copyright (C) 2011 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 file is part of the GDB testsuite.  It tests the mechanism
+# exposing values to Python.
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+load_lib gdb-python.exp
+
+set testfile "py-finish-breakpoint-cc"
+set srcfile ${testfile}.cc
+set binfile ${objdir}/${subdir}/${testfile}
+set pyfile  ${srcdir}/${subdir}/${testfile}.py
+
+# Start with a fresh gdb.
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}"
executable {debug c++}] != "" } {
+    untested "Couldn't compile ${srcfile}"
+    return -1
+}
+
+if ![runto_main] then {
+    fail "Cannot run to main."
+    return 0
+}
+
+gdb_test "source $pyfile" ".*Python script imported.*" \
+         "import python scripts"
+
+gdb_test "break [gdb_get_line_number "Break after exception 1."]"
"Breakpoint.* at .*" \
+         "set watchdog after the exception 1"
+gdb_test "break [gdb_get_line_number "Break after exception 2."]"
"Breakpoint.* at .*" \
+         "set watchdog after the exception 2"
+
+gdb_test "python ExceptionBreakpoint()" "ExceptionBreakpoint init"
"set BP before throwing the exception"
+gdb_test "python print len(gdb.breakpoints())" "4" "check number of BPs"
+gdb_test "continue" ".*stopped at ExceptionFinishBreakpoint.*" "check
FinishBreakpoint in catch()"
+gdb_test "python print len(gdb.breakpoints())" "4" "check finish BP removal"
+
+gdb_test "continue" ".*exception did not finish.*" "FinishBreakpoint
with exception thrown not caught"
diff --git a/gdb/testsuite/gdb.python/py-finish-breakpoint-cc.py
b/gdb/testsuite/gdb.python/py-finish-breakpoint-cc.py
new file mode 100644
index 0000000..d0dfe2f
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-finish-breakpoint-cc.py
@@ -0,0 +1,43 @@
+# Copyright (C) 2011 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 file is part of the GDB testsuite.  It tests python Finish
+# Breakpoints.
+
+class ExceptionBreakpoint(gdb.Breakpoint):
+    def __init__(self):
+        gdb.Breakpoint.__init__(self, spec="throw_exception_1", internal=1)
+        self.silent = True
+        print "ExceptionBreakpoint init"
+
+    def stop(self):
+        ExceptionFinishBreakpoint(gdb.newest_frame())
+        return False
+
+class ExceptionFinishBreakpoint(gdb.FinishBreakpoint):
+    def __init__(self, frame):
+        gdb.FinishBreakpoint.__init__(self, frame, internal=1)
+        self.silent = True;
+
+    def stop(self):
+	print "stopped at ExceptionFinishBreakpoint"
+	gdb.post_event(self.delete)
+        return True
+
+    def out_of_scope(self):
+        print "exception did not finish ..."
+
+
+print "Python script imported"
diff --git a/gdb/testsuite/gdb.python/py-finish-breakpoint.c
b/gdb/testsuite/gdb.python/py-finish-breakpoint.c
new file mode 100644
index 0000000..32b8b38
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-finish-breakpoint.c
@@ -0,0 +1,82 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+   Copyright 2011 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/>.
+*/
+#include <setjmp.h>
+
+int increase_1(int *a)
+{
+  *a += 1;
+  return -5;
+}
+
+void increase(int *a)
+{
+  increase_1(a);
+}
+
+int
+test_1(int i, int j)
+{
+  return i == j;
+}
+
+int
+test(int i, int j)
+{
+  return test_1(i, j);
+}
+
+int
+call_longjmp_1 (jmp_buf *buf)
+{
+  longjmp (*buf, 1);
+}
+
+int
+call_longjmp (jmp_buf *buf)
+{
+  call_longjmp_1 (buf);
+}
+
+
+int main (int argc, char *argv[])
+{
+  jmp_buf env;
+  int foo = 5;
+  int bar = 42;
+  int i, j;
+
+  i = 0 ;
+  /* Break at increase. */
+  increase (&i) ;
+  increase (&i) ;
+  increase (&i) ;
+
+  for (i = 0; i < 10; i++)
+    {
+      j += 1; /* Condition Break. */
+    }
+
+  if (setjmp (env) == 0) /* longjmp caught */
+    {
+      call_longjmp (&env);
+    }
+  else
+	  j += 1; /* after longjmp. */
+
+  return j; /* Break at end. */
+}
diff --git a/gdb/testsuite/gdb.python/py-finish-breakpoint.exp
b/gdb/testsuite/gdb.python/py-finish-breakpoint.exp
new file mode 100644
index 0000000..65eebc9
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-finish-breakpoint.exp
@@ -0,0 +1,183 @@
+# Copyright (C) 2011 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 file is part of the GDB testsuite.  It tests the mechanism
+# exposing values to Python.
+
+if $tracelevel then {
+    strace $tracelevel
+}
+
+load_lib gdb-python.exp
+
+set testfile "py-finish-breakpoint"
+set srcfile ${testfile}.c
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile}] } {
+    return -1
+}
+
+set remote_python_file [remote_download host
${srcdir}/${subdir}/${testfile}.py]
+
+
+# Skip all tests if Python scripting is not enabled.
+if { [skip_python_tests] } { continue }
+
+#
+# Test FinishBreakpoint in function returned by longjmp
+#
+
+clean_restart ${testfile}
+
+if ![runto call_longjmp_1] then {
+    perror "couldn't run to breakpoint call_longjmp"
+    continue
+}
+
+gdb_test "source $remote_python_file" ".*Python script imported.*" \
+         "import python scripts"
+
+gdb_test "python ljmpBP = LongjmpFinishBreakpoint(gdb.newest_frame())" \
+         "LongjmpFinishBreakpoint init" \
+         "set finish breakpoint"
+gdb_test "break [gdb_get_line_number "after longjmp."]" "Breakpoint.* at .*" \
+         "set BP after the jump"
+gdb_test "continue" ".*Longjmp didn't finish.*" "check FinishBP out
of scope notification"
+
+#
+# Test FinishBreakpoint in BP condition evaluation
+# (finish in dummy frame)
+#
+
+clean_restart ${testfile}
+
+set cond_line [gdb_get_line_number "Condition Break."]
+if ![runto_main] then {
+    fail "Cannot run to main."
+    return 0
+}
+
+gdb_test "source $remote_python_file" ".*Python script imported.*" \
+         "import python scripts"
+
+gdb_test "break ${cond_line} if test_1(i,8)" ".*Breakpoint .* at .*"
"set conditional BP"
+gdb_test "python TestBreakpoint()" "TestBreakpoint init" "set BP in condition"
+
+
+set msg "check FinishBreakpoint don't stop in GDB Dummy Frame"
+gdb_test_multiple "continue" $msg {
+	-re ".*test don't stop 2.*test stop.*test don't stop 4.*" {
+		pass $msg
+	}
+	-re ".*test don't stop 2.*test stop.*$gdb_prompt" {
+		fail $msg
+	}
+}
+
+gdb_test "print i" "8" "check stopped location"
+
+#
+# Test FinishBreakpoint in BP condition evaluation
+# (finish in normal frame)
+#
+
+clean_restart ${testfile}
+
+gdb_test "source $remote_python_file" ".*Python script imported.*" \
+         "import python scripts"
+
+if ![runto_main] then {
+    fail "Cannot run to main."
+    return 0
+}
+
+gdb_test "break ${cond_line} if test(i,8)" ".*Breakpoint .* at .*"
"set conditional BP"
+gdb_test "python TestBreakpoint()" "TestBreakpoint init" "set BP in condition"
+
+gdb_test "continue" ".*test don't stop 1.*test don't stop 2.*test
stop.*Error in testing breakpoint condition.*The program being
debugged stopped while in a function called from GDB.*" \
+         "stop in condition function"
+
+setup_kfail "normal_stop_notification not triggered during condition
evaluation" *-*-*
+gdb_test "python print gdb.breakpoints()\[2\].out_of_scope_notif"
".*False.*" "check out_of_scope notification disabled"
+gdb_test_no_output "python gdb.breakpoints()\[2\].out_of_scope_notif
= False" "reestablish correct value"
+
+gdb_test "continue" "Continuing.*" "finish condition evaluation"
+gdb_test "continue" "Breakpoint.*" "stop at conditional breakpoint"
+gdb_test "print i" "8" "check stopped location"
+
+#
+# Test FinishBreakpoint in normal conditions
+#
+
+clean_restart ${testfile}
+
+if ![runto_main] then {
+    fail "Cannot run to main."
+    return 0
+}
+gdb_test_no_output "set confirm off" "disable confirmation"
+gdb_test "source $remote_python_file" ".*Python script imported.*" \
+         "import python scripts"
+gdb_test "python MyBreakpoint(\"increase_1\")" ".*Breakpoint 2.*" \
+         "create Python function breakpoint"
+gdb_test "continue" ".*Arrived at MyBreakpoint with 0.*" "check
MyBreakpoint hit"
+
+# set FinishBreakpoint
+
+gdb_test "python finishbp = MyFinishBreakpoint (gdb.parse_and_eval
(\"a\"), gdb.selected_frame ())" \
+         ".*Breakpoint 3.*" "set FinishBreakpoint"
+gdb_test "python print finishbp.out_of_scope_notif" ".*True.*" \
+         "check out_of_scope_notif at init"
+gdb_test "python print finishbp.return_value" ".*None.*" \
+         "check return_value at init"
+
+# check normal bp hit
+
+gdb_test "continue" ".*MyFinishBreakpoint stop with.*#0.*increase.*" \
+         "check MyFinishBreakpoint hit"
+gdb_test "python print finishbp.return_value" ".*-5.*" "check return_value"
+gdb_test "python print finishbp.out_of_scope_notif" ".*False.*" \
+         "check out_of_scope_notif disabled after hit"
+gdb_test "finish" ".*main.*" "return to main()"
+gdb_test "python print finishbp.return_value" ".*None.*" "check return_value"
+
+# check forced return / check out of scpop
+gdb_test_no_output "python finishbp.out_of_scope_notif = True" \
+         "re-enable out_of_scope_notif"
+
+gdb_test "continue" ".*Arrived at MyBreakpoint with.*" "check
MyBreakpoint second hit"
+gdb_test "up" ".*increase_1.*" "go one frame up"
+gdb_test_no_output "return" "return from the frame"
+gdb_test "python print finishbp.check_scope()" ".*MyFinishBreakpoint
out of scope.*True.*" \
+         "go one frame up"
+
+# check forced return / automatic notification
+
+gdb_test_no_output "python finishbp.out_of_scope_notif = True" \
+         "re-enable out_of_scope_notif"
+
+gdb_test "continue" ".*Arrived at MyBreakpoint with.*" "check
MyBreakpoint third hit"
+gdb_test "up" ".*increase_1.*" "go one frame up"
+gdb_test_no_output "return" "return from the frame"
+gdb_test "next" ".*MyFinishBreakpoint out of scope.*" "check Finish
breakpoint discard"
+gdb_test "python print finishbp.out_of_scope_notif" ".*False.*"
"check out_of_scope_notif"
+
+# check FinishBreakpoint in main
+
+gdb_test "python MyFinishBreakpoint (None, gdb.selected_frame ())" \
+         ".*ValueError: \"FinishBreakpoint\" not meaningful in the
outermost frame..*" \
+         "check FinishBP not allowed in main"
+
+
diff --git a/gdb/testsuite/gdb.python/py-finish-breakpoint.py
b/gdb/testsuite/gdb.python/py-finish-breakpoint.py
new file mode 100644
index 0000000..f014cc6
--- /dev/null
+++ b/gdb/testsuite/gdb.python/py-finish-breakpoint.py
@@ -0,0 +1,85 @@
+# Copyright (C) 2011 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 file is part of the GDB testsuite.  It tests python Finish
+# Breakpoints.
+
+class MyBreakpoint(gdb.Breakpoint):		
+	def stop(self):
+		val = gdb.parse_and_eval ("a")
+		print "Arrived at MyBreakpoint with %d" % int(val.dereference())
+		return True
+		
+class MyFinishBreakpoint(gdb.FinishBreakpoint):
+	def __init__(self, val, frame):
+		super (MyFinishBreakpoint, self).__init__ (frame)
+		print "MyFinishBreakpoint init"
+		self.val = val
+		
+	def stop(self):
+		print "MyFinishBreakpoint stop with %d" % int(self.val.dereference())
+		gdb.execute("where 1")
+		return True
+	
+	def out_of_scope(self):
+		print "MyFinishBreakpoint out of scope..."
+
+test_finish_bp = None
+class TestBreakpoint(gdb.Breakpoint):
+    def __init__(self):
+        gdb.Breakpoint.__init__(self, spec="test_1", internal=1)
+        self.silent = True
+        self.finish = None
+        print "TestBreakpoint init"
+
+    def stop(self):
+    	global test_finish_bp
+        if (self.finish == None):
+            self.finish = TestFinishBreakpoint(gdb.newest_frame())
+            test_finish_bp = self.finish
+        return False
+
+
+class TestFinishBreakpoint(gdb.FinishBreakpoint):
+    def __init__(self, frame):
+        gdb.FinishBreakpoint.__init__(self, frame, internal=1)
+        self.count = 0
+
+    def stop(self):
+        self.count += 1
+        if (self.count == 3):
+            print "test stop ..."
+            return True
+        else:
+            print "test don't stop %d" % self.count
+            return False
+
+
+    def out_of_scope(self):
+        print "test didn't finish ..."
+		
+class LongjmpFinishBreakpoint(gdb.FinishBreakpoint):
+	def __init__(self, frame):
+		gdb.FinishBreakpoint.__init__(self, frame, internal=1)
+		print "LongjmpFinishBreakpoint init"
+		
+	def stop(self):
+		print "Stopped at LongjmpFinishBreakpoint"
+
+
+	def out_of_scope(self):
+		print "Longjmp didn't finish ..."
+
+print "Python script imported"
-- 
1.7.4.4


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]