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've included with this mail a complete patch build agains the current
HEAD, and checked that there was no regression in the testsuite


Kevin

On Mon, May 16, 2011 at 7:23 AM, Kevin Pouget <kevin.pouget@gmail.com> wrote:
> 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
>

Attachment: 0001-Python-Finish-Breakpoints.txt
Description: Text document


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