diff options
Diffstat (limited to 'gdb/testsuite/gdb.python')
137 files changed, 3714 insertions, 905 deletions
diff --git a/gdb/testsuite/gdb.python/amd64-py-framefilter-invalidarg.S b/gdb/testsuite/gdb.python/amd64-py-framefilter-invalidarg.S index 0280591..1e5d8ac7 100644 --- a/gdb/testsuite/gdb.python/amd64-py-framefilter-invalidarg.S +++ b/gdb/testsuite/gdb.python/amd64-py-framefilter-invalidarg.S @@ -46,7 +46,7 @@ main: .loc 1 3 0 popq %rbp .cfi_def_cfa 7, 8 -# SUCC: EXIT [100.0%] +# SUCC: EXIT [100.0%] ret .cfi_endproc .LFE0: diff --git a/gdb/testsuite/gdb.python/gdb_leak_detector.py b/gdb/testsuite/gdb.python/gdb_leak_detector.py new file mode 100644 index 0000000..8f74b67 --- /dev/null +++ b/gdb/testsuite/gdb.python/gdb_leak_detector.py @@ -0,0 +1,121 @@ +# Copyright (C) 2021-2025 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/>. + +# Defines a base class, which can be sub-classed, in order to run +# memory leak tests on some aspects of GDB's Python API. See the +# comments on the gdb_leak_detector class for more details. + +import os +import tracemalloc + +import gdb + + +# This class must be sub-classed to create a memory leak test. The +# sub-classes __init__ method should call the parent classes __init__ +# method, and the sub-class should override allocate() and +# deallocate(). See the comments on the various methods below for +# more details of required arguments and expected usage. +class gdb_leak_detector: + + # Class initialisation. FILENAME is the file in which the + # sub-class is defined, usually passed as just '__file__'. This + # is used when looking for memory allocations; only allocations in + # FILENAME are considered. + def __init__(self, filename): + self.filters = [tracemalloc.Filter(True, "*" + os.path.basename(filename))] + + # Internal helper function to actually run the test. Calls the + # allocate() method to allocate an object from GDB's Python API. + # When CLEAR is True the object will then be deallocated by + # calling deallocate(), otherwise, deallocate() is not called. + # + # Finally, this function checks for any memory allocatios + # originating from 'self.filename' that have not been freed, and + # returns the total (in bytes) of the memory that has been + # allocated, but not freed. + def _do_test(self, clear): + # Start tracing, and take a snapshot of the current allocations. + tracemalloc.start() + snapshot1 = tracemalloc.take_snapshot() + + # Generate the GDB Python API object by calling the allocate + # method. + self.allocate() + + # Possibly clear the reference to the allocated object. + if clear: + self.deallocate() + + # Now grab a second snapshot of memory allocations, and stop + # tracing memory allocations. + snapshot2 = tracemalloc.take_snapshot() + tracemalloc.stop() + + # Filter the snapshots; we only care about allocations originating + # from this file. + snapshot1 = snapshot1.filter_traces(self.filters) + snapshot2 = snapshot2.filter_traces(self.filters) + + # Compare the snapshots, this leaves only things that were + # allocated, but not deallocated since the first snapshot. + stats = snapshot2.compare_to(snapshot1, "traceback") + + # Total up all the allocated things. + total = 0 + for stat in stats: + total += stat.size_diff + return total + + # Run the memory leak test. Prints 'PASS' if successful, + # otherwise, raises an exception (of type GdbError). + def run(self): + # The first time we run this some global state will be allocated which + # shows up as memory that is allocated, but not released. So, run the + # test once and discard the result. + self._do_test(True) + + # Now run the test twice, the first time we clear our global reference + # to the allocated object, which should allow Python to deallocate the + # object. The second time we hold onto the global reference, preventing + # Python from performing the deallocation. + bytes_with_clear = self._do_test(True) + bytes_without_clear = self._do_test(False) + + # If there are any allocations left over when we cleared the reference + # (and expected deallocation) then this indicates a leak. + if bytes_with_clear > 0: + raise gdb.GdbError("memory leak when object reference was released") + + # If there are no allocations showing when we hold onto a reference, + # then this likely indicates that the testing infrastructure is broken, + # and we're no longer spotting the allocations at all. + if bytes_without_clear == 0: + raise gdb.GdbError("object is unexpectedly not showing as allocated") + + # Print a PASS message that the TCL script can see. + print("PASS") + + # Sub-classes must override this method. Allocate an object (or + # multiple objects) from GDB's Python API. Store references to + # these objects within SELF. + def allocate(self): + raise NotImplementedError("allocate() not implemented") + + # Sub-classes must override this method. Deallocate the object(s) + # allocated by the allocate() method. All that is required is for + # the references created in allocate() to be set to None. + def deallocate(self): + raise NotImplementedError("allocate() not implemented") diff --git a/gdb/testsuite/gdb.python/lookup-type-block.exp b/gdb/testsuite/gdb.python/lookup-type-block.exp new file mode 100644 index 0000000..7d04eb6 --- /dev/null +++ b/gdb/testsuite/gdb.python/lookup-type-block.exp @@ -0,0 +1,68 @@ +# Copyright (C) 2025 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/>. + +# Test the 'block' argument to gdb.lookup_type. + +load_lib gdb-python.exp + +require allow_python_tests + +standard_testfile lookup1.c lookup2.c + +if {[prepare_for_testing "failed to prepare" ${testfile} \ + [list $srcfile $srcfile2]]} { + return +} + +proc check_type {which type_name} { + if {$which == "one"} { + set fn_name function + } else { + set fn_name main + } + + gdb_test_no_output \ + "python block = gdb.decode_line(\"$fn_name\")\[1\]\[0\].symtab.static_block()" \ + "compute block" + gdb_test_no_output \ + "python ty = gdb.lookup_type(\"$type_name\", block).strip_typedefs()" \ + "find the type" + gdb_test "python print(ty.fields()\[0\].name)" \ + "$which" \ + "examine first field" +} + +proc check_all_types {} { + foreach_with_prefix which {one two} { + foreach_with_prefix type_name { + "struct the_struct" + "enum the_enum" + "union the_union" + "the_typedef" + } { + check_type $which $type_name + } + } +} + +check_all_types + +if {![runto_main]} { + return +} + +with_test_prefix "while running" { + check_all_types +} diff --git a/gdb/testsuite/gdb.python/lookup1.c b/gdb/testsuite/gdb.python/lookup1.c new file mode 100644 index 0000000..488ffcb --- /dev/null +++ b/gdb/testsuite/gdb.python/lookup1.c @@ -0,0 +1,44 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2025 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/>. */ + +struct the_struct { + int one; +}; + +struct the_struct struct1; + +enum the_enum { + one +}; + +enum the_enum enum1; + +union the_union { + int one; + void *ptr; +}; + +union the_union union1; + +typedef struct the_struct the_typedef; + +the_typedef typedef1; + +int function (void) +{ + return 0; +} diff --git a/gdb/testsuite/gdb.python/lookup2.c b/gdb/testsuite/gdb.python/lookup2.c new file mode 100644 index 0000000..63d1030 --- /dev/null +++ b/gdb/testsuite/gdb.python/lookup2.c @@ -0,0 +1,46 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2025 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/>. */ + +struct the_struct { + int two; +}; + +struct the_struct struct2; + +enum the_enum { + two +}; + +enum the_enum enum2; + +union the_union { + int two; + void *ptr; +}; + +union the_union union2; + +typedef struct the_struct the_typedef; + +the_typedef typedef2; + +extern int function (void); + +int main (void) +{ + return function (); +} diff --git a/gdb/testsuite/gdb.python/make-visualizer.exp b/gdb/testsuite/gdb.python/make-visualizer.exp new file mode 100644 index 0000000..2c6b40d --- /dev/null +++ b/gdb/testsuite/gdb.python/make-visualizer.exp @@ -0,0 +1,176 @@ +# Copyright (C) 2025 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/>. + +# Tests for gdb.printing.make_visualizer; specifically that the +# optimized-out and synthetic pointer cases work properly. + +load_lib dwarf.exp +load_lib gdb-python.exp + +require dwarf2_support +require allow_python_tests + +# Use a simple plain-"main" source file. +standard_testfile py-progspace.c -dw.S + +if {[prepare_for_testing "failed to prepare" $testfile $srcfile {debug}]} { + return +} + +if {![runto_main]} { + return +} + +# Get size to create fake DWARF for the test. +set ptr_size [get_sizeof "void *" 96] + +set asm_file [standard_output_file ${srcfile2}] +Dwarf::assemble $asm_file { + cu {} { + compile_unit {} { + declare_labels i32_type i32_array \ + struct_label variable_label pointer_label + + i32_type: DW_TAG_base_type { + DW_AT_name "int32_t" + DW_AT_encoding @DW_ATE_signed + DW_AT_byte_size 4 DW_FORM_sdata + } + + i32_array: DW_TAG_array_type { + DW_AT_name array_type + DW_AT_type :$i32_type + } { + DW_TAG_subrange_type { + DW_AT_type :$i32_type + DW_AT_lower_bound 0 DW_FORM_data1 + DW_AT_upper_bound 3 DW_FORM_data1 + } + } + + # Used for testing optimized-out elements of an array. + DW_TAG_variable { + DW_AT_name i32_noptr + DW_AT_type :$i32_array + DW_AT_location { + DW_OP_constu 1779823878 + DW_OP_stack_value + DW_OP_piece 4 + } SPECIAL_expr + } + + struct_label: DW_TAG_structure_type { + DW_AT_name i32_noptr + DW_AT_byte_size 4 DW_FORM_sdata + } { + DW_TAG_member { + DW_AT_name f + DW_AT_type :$i32_type + DW_AT_data_member_location 0 DW_FORM_data1 + } + } + + pointer_label: DW_TAG_pointer_type { + DW_AT_byte_size $::ptr_size DW_FORM_sdata + DW_AT_type :$struct_label + } + + variable_label: DW_TAG_variable { + DW_AT_name v + DW_AT_location { + DW_OP_implicit_value 0x1 0x1 0x1 0x1 + } SPECIAL_expr + DW_AT_type :$struct_label + } + + # Used for testing synthetic pointers. + DW_TAG_variable { + DW_AT_name synthptr + DW_AT_location { + DW_OP_GNU_implicit_pointer $variable_label 0 + } SPECIAL_expr + DW_AT_type :$pointer_label + } + + # Optimized-out pointer. + DW_TAG_variable { + DW_AT_name optoutptr + DW_AT_location { } SPECIAL_expr + DW_AT_type :$pointer_label + } + } + } +} + +if {[prepare_for_testing "failed to prepare" ${testfile} \ + [list $srcfile $asm_file] {nodebug}]} { + return +} + +# Need a frame to evaluate a synthetic pointer. +if {![runto_main]} { + return +} + +gdb_test_no_output "python import gdb" +gdb_test_no_output "python import gdb.printing" + +gdb_test_no_output "python val = gdb.parse_and_eval('i32_noptr')" \ + "fetch i32_noptr" +gdb_test_no_output "python vz = gdb.printing.make_visualizer(val)" \ + "create i32_noptr visualizer" +gdb_test "python print(isinstance(vz, gdb.printing.NoOpArrayPrinter))" \ + True \ + "i32_noptr uses array printer" + +gdb_test_no_output "python vz1 = gdb.printing.make_visualizer(val\[0\])" \ + "create visualizer for valid element" +gdb_test "python print(isinstance(vz1, gdb.printing.NoOpScalarPrinter))" \ + True \ + "valid element uses scalar printer" +gdb_test "python print(vz1.to_string())" \ + 1779823878 \ + "string form of valid element" + +gdb_test_no_output "python vz2 = gdb.printing.make_visualizer(val\[1\])" \ + "create visualizer for optimized-out element" +gdb_test "python print(isinstance(vz2, gdb.printing.NoOpScalarPrinter))" \ + True \ + "optimized-out element uses scalar printer" +gdb_test "python print(vz2.to_string())" \ + "<optimized out>" \ + "string form of optimized-out element" + +gdb_test_no_output "python val2 = gdb.parse_and_eval('synthptr')" \ + "fetch synthetic pointer" +gdb_test_no_output "python vzv2 = gdb.printing.make_visualizer(val2)" \ + "create synthetic pointer visualizer" +gdb_test "python print(isinstance(vzv2, gdb.printing.NoOpPointerReferencePrinter))" \ + True \ + "synthetic pointer uses pointer printer" +gdb_test "python print(vzv2.child(0)\[1\])" \ + "{f = 16843009}" \ + "child of synthetic pointer" + +gdb_test_no_output "python val3 = gdb.parse_and_eval('optoutptr')" \ + "fetch optimized-out pointer" +gdb_test_no_output "python vzv3 = gdb.printing.make_visualizer(val3)" \ + "create optimized-out pointer visualizer" +gdb_test "python print(isinstance(vzv3, gdb.printing.NoOpScalarPrinter))" \ + True \ + "optimized-out pointer uses scalar printer" +gdb_test "python print(vzv3.to_string())" \ + "<optimized out>" \ + "string representation of optimized-out pointer" diff --git a/gdb/testsuite/gdb.python/pretty-print-call-by-hand.exp b/gdb/testsuite/gdb.python/pretty-print-call-by-hand.exp index dd6cb59..17b8afe 100644 --- a/gdb/testsuite/gdb.python/pretty-print-call-by-hand.exp +++ b/gdb/testsuite/gdb.python/pretty-print-call-by-hand.exp @@ -39,7 +39,7 @@ proc start_test { breakpoint_comment } { # Start with a fresh gdb. # This is important because the test can crash GDB. - clean_restart ${binfile} + clean_restart ${::testfile} if {![runto_main]} { untested "couldn't run to breakpoint" diff --git a/gdb/testsuite/gdb.python/pretty-print-call-by-hand.py b/gdb/testsuite/gdb.python/pretty-print-call-by-hand.py index 3620354..57af869 100644 --- a/gdb/testsuite/gdb.python/pretty-print-call-by-hand.py +++ b/gdb/testsuite/gdb.python/pretty-print-call-by-hand.py @@ -14,6 +14,9 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. +import gdb + + class MytypePrinter: """pretty print my type""" @@ -21,7 +24,7 @@ class MytypePrinter: self.val = val def to_string(self): - calls = gdb.parse_and_eval("f()") + gdb.parse_and_eval("f()") return "mytype is %s" % self.val["x"] diff --git a/gdb/testsuite/gdb.python/py-arch-reg-groups.exp b/gdb/testsuite/gdb.python/py-arch-reg-groups.exp index 855af27..2b0ac3e 100644 --- a/gdb/testsuite/gdb.python/py-arch-reg-groups.exp +++ b/gdb/testsuite/gdb.python/py-arch-reg-groups.exp @@ -23,7 +23,7 @@ if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } { return -1 } -if ![runto_main] { +if {![runto_main]} { return -1 } diff --git a/gdb/testsuite/gdb.python/py-arch-reg-names.exp b/gdb/testsuite/gdb.python/py-arch-reg-names.exp index 7093674..99fb8ce 100644 --- a/gdb/testsuite/gdb.python/py-arch-reg-names.exp +++ b/gdb/testsuite/gdb.python/py-arch-reg-names.exp @@ -23,7 +23,7 @@ if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } { return -1 } -if ![runto_main] { +if {![runto_main]} { return -1 } diff --git a/gdb/testsuite/gdb.python/py-arch.exp b/gdb/testsuite/gdb.python/py-arch.exp index 79e5939..531ae50 100644 --- a/gdb/testsuite/gdb.python/py-arch.exp +++ b/gdb/testsuite/gdb.python/py-arch.exp @@ -20,7 +20,7 @@ if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } { return -1 } -if ![runto_main] { +if {![runto_main]} { return -1 } @@ -78,7 +78,7 @@ foreach size {0 1 2 3 4 8 16} { } else { set sign_result [lindex $sign_data 1] } - set fullsize [expr 8 * $size] + set fullsize [expr {8 * $size}] gdb_test_no_output "python t = arch.integer_type($fullsize$sign)" \ "get integer type for $size$sign" gdb_test "python print(t.sizeof)" "$size" \ diff --git a/gdb/testsuite/gdb.python/py-as-string.exp b/gdb/testsuite/gdb.python/py-as-string.exp index 05d55df..2ad179d 100644 --- a/gdb/testsuite/gdb.python/py-as-string.exp +++ b/gdb/testsuite/gdb.python/py-as-string.exp @@ -26,7 +26,7 @@ if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } { return -1 } -if ![runto_main] { +if {![runto_main]} { return 0 } diff --git a/gdb/testsuite/gdb.python/py-auto-load-chaining-f1.o-gdb.py b/gdb/testsuite/gdb.python/py-auto-load-chaining-f1.o-gdb.py index 9641a86..7c107ec 100644 --- a/gdb/testsuite/gdb.python/py-auto-load-chaining-f1.o-gdb.py +++ b/gdb/testsuite/gdb.python/py-auto-load-chaining-f1.o-gdb.py @@ -18,6 +18,8 @@ import re +import gdb + print("Entering f1.o auto-load script") print("Current objfile is: %s" % gdb.current_objfile().filename) diff --git a/gdb/testsuite/gdb.python/py-auto-load-chaining-f2.o-gdb.py b/gdb/testsuite/gdb.python/py-auto-load-chaining-f2.o-gdb.py index f1abc2c..6c33118 100644 --- a/gdb/testsuite/gdb.python/py-auto-load-chaining-f2.o-gdb.py +++ b/gdb/testsuite/gdb.python/py-auto-load-chaining-f2.o-gdb.py @@ -16,6 +16,8 @@ # This script is auto-loaded when the py-auto-load-chaining-f2.o # object is loaded. +import gdb + print("Entering f2.o auto-load script") print("Current objfile is: %s" % gdb.current_objfile().filename) diff --git a/gdb/testsuite/gdb.python/py-auto-load-chaining.c b/gdb/testsuite/gdb.python/py-auto-load-chaining.c index 74ec04f..1b6508c 100644 --- a/gdb/testsuite/gdb.python/py-auto-load-chaining.c +++ b/gdb/testsuite/gdb.python/py-auto-load-chaining.c @@ -33,7 +33,7 @@ allocate_page (void) void *addr; int pgsize = sysconf(_SC_PAGE_SIZE); addr = mmap (NULL, pgsize, PROT_EXEC | PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (addr == MAP_FAILED) perror ("mmap"); } diff --git a/gdb/testsuite/gdb.python/py-auto-load-chaining.exp b/gdb/testsuite/gdb.python/py-auto-load-chaining.exp index 451dca6..fbb95d9 100644 --- a/gdb/testsuite/gdb.python/py-auto-load-chaining.exp +++ b/gdb/testsuite/gdb.python/py-auto-load-chaining.exp @@ -49,7 +49,7 @@ if {[prepare_for_testing "failed to prepare" ${testfile} ${srcfile}]} { return -1 } -if ![runto_main] { +if {![runto_main]} { return -1 } diff --git a/gdb/testsuite/gdb.python/py-bad-printers.py b/gdb/testsuite/gdb.python/py-bad-printers.py index c93923c..b4f84bc 100644 --- a/gdb/testsuite/gdb.python/py-bad-printers.py +++ b/gdb/testsuite/gdb.python/py-bad-printers.py @@ -18,7 +18,6 @@ # Test a printer with a bad children iterator. -import re import gdb.printing @@ -34,7 +33,6 @@ class BadChildrenContainerPrinter1(object): @staticmethod def _bad_iterator(pointer, len): - start = pointer end = pointer + len while pointer != end: yield "intentional violation of children iterator protocol" @@ -55,7 +53,6 @@ class BadChildrenContainerPrinter2(object): @staticmethod def _bad_iterator(pointer, len): - start = pointer end = pointer + len while pointer != end: # The first argument is supposed to be a string. diff --git a/gdb/testsuite/gdb.python/py-block.exp b/gdb/testsuite/gdb.python/py-block.exp index ce3f7ce..5d0d408 100644 --- a/gdb/testsuite/gdb.python/py-block.exp +++ b/gdb/testsuite/gdb.python/py-block.exp @@ -45,9 +45,9 @@ gdb_test "python print (block.start)" "${decimal}" "check start not None" gdb_test "python print (block.end)" "${decimal}" "check end not None" gdb_test "python print (block\['f'\].name == 'f')" "True" "check variable access" gdb_test "python print (block\['nonexistent'\])" ".*KeyError.*: 'nonexistent'.*" \ - "check nonexistent variable" + "check nonexistent variable" gdb_test "python print (block\[42\])" ".*TypeError.*: Expected a string.*" \ - "check non-string key" + "check non-string key" # Test global/static blocks gdb_py_test_silent_cmd "python frame = gdb.selected_frame()" "Get Frame" 0 @@ -71,7 +71,7 @@ gdb_test_no_output "python block = block.superblock" "get superblock" gdb_test "python print (block.function)" "None" "second anonymous block" gdb_test_no_output "python block = block.superblock" "get superblock 2" gdb_test "python print (block.function)" "block_func" \ - "Print superblock 2 function" + "Print superblock 2 function" # Switch frames, then test block for no_locals_func. gdb_test "continue" ".*" "continue to no_locals_func breakpoint" @@ -110,7 +110,7 @@ gdb_test "up" ".*" gdb_py_test_silent_cmd "python frame = gdb.selected_frame()" "Get Frame 2" 0 gdb_py_test_silent_cmd "python block = frame.block()" "Get Frame 2's block" 0 gdb_test "python print (repr (block))" "<gdb.Block main \{.*\}>" \ - "Check Frame 2's block not None" + "Check Frame 2's block not None" gdb_test "python print (block.function)" "main" "main block" # Test Block is_valid. This must always be the last test in this @@ -120,15 +120,15 @@ gdb_py_test_silent_cmd "python frame = gdb.selected_frame()" "Get Frame" 0 gdb_py_test_silent_cmd "python block = frame.block()" "Get Frame block" 0 gdb_py_test_silent_cmd "python block_iter = iter (block)" "Get Frame block" 0 gdb_test "python print (block.is_valid())" "True" \ - "Check block validity" + "Check block validity" gdb_test "python print (block_iter.is_valid())" "True" \ - "Check block_iter validity" + "Check block_iter validity" gdb_test_no_output "python x = hash(block)" "block is hashable" gdb_test "python print (type (x))" "<class 'int'>" "block hash is integer" gdb_unload gdb_test "python print (block.is_valid())" "False" \ - "Check block validity after unload" + "Check block validity after unload" gdb_test "python print (block_iter.is_valid())" "False" \ - "Check block_iter validity after unload" + "Check block_iter validity after unload" gdb_test "python print (hash (block) == x)" "True" \ "block hash did not change" diff --git a/gdb/testsuite/gdb.python/py-bp-locations.exp b/gdb/testsuite/gdb.python/py-bp-locations.exp index 61e4e38..b09a401 100644 --- a/gdb/testsuite/gdb.python/py-bp-locations.exp +++ b/gdb/testsuite/gdb.python/py-bp-locations.exp @@ -27,7 +27,7 @@ save_vars { GDBFLAGS } { clean_restart $testfile } -if ![runto_main] { +if {![runto_main]} { return -1 } @@ -79,7 +79,7 @@ gdb_test "python print(gdb.breakpoints()\[1\].locations\[0\])" \ "check repr of disabled breakpoint location" gdb_continue_to_breakpoint "" ".*25.*" -if ![runto_main] { +if {![runto_main]} { return -1 } diff --git a/gdb/testsuite/gdb.python/py-breakpoint-create-fail.exp b/gdb/testsuite/gdb.python/py-breakpoint-create-fail.exp index 391744e..0305604 100644 --- a/gdb/testsuite/gdb.python/py-breakpoint-create-fail.exp +++ b/gdb/testsuite/gdb.python/py-breakpoint-create-fail.exp @@ -27,7 +27,7 @@ if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } { } clean_restart "${testfile}" -if ![runto_main] { +if {![runto_main]} { return } @@ -46,9 +46,9 @@ gdb_test "break foo" set test "continuing to foo" gdb_test_multiple "continue" "$test" { -re "MyBP\.stop was invoked\!.*$gdb_prompt $" { - fail "$test" + fail "$test" } -re "Continuing.*Breakpoint 2, foo.*$gdb_prompt $" { - pass "$test" + pass "$test" } } diff --git a/gdb/testsuite/gdb.python/py-breakpoint.exp b/gdb/testsuite/gdb.python/py-breakpoint.exp index 1b9c05f..9a901a3 100644 --- a/gdb/testsuite/gdb.python/py-breakpoint.exp +++ b/gdb/testsuite/gdb.python/py-breakpoint.exp @@ -707,7 +707,7 @@ proc_with_prefix test_bkpt_explicit_loc {} { delete_breakpoints gdb_test "python bp1 = gdb.Breakpoint (line=bp1)" \ - "RuntimeError.*: Line keyword should be an integer or a string.*" \ + "RuntimeError.*: Line keyword should be an integer or a string\\.\r\n.*" \ "set explicit breakpoint by invalid line type" delete_breakpoints diff --git a/gdb/testsuite/gdb.python/py-caller-is.exp b/gdb/testsuite/gdb.python/py-caller-is.exp index 8e54c3b..0fdb80e 100644 --- a/gdb/testsuite/gdb.python/py-caller-is.exp +++ b/gdb/testsuite/gdb.python/py-caller-is.exp @@ -26,7 +26,7 @@ if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } { return -1 } -if ![runto_main] { +if {![runto_main]} { return 0 } diff --git a/gdb/testsuite/gdb.python/py-cmd.exp b/gdb/testsuite/gdb.python/py-cmd.exp index f76c176..1fa3c73 100644 --- a/gdb/testsuite/gdb.python/py-cmd.exp +++ b/gdb/testsuite/gdb.python/py-cmd.exp @@ -278,13 +278,7 @@ gdb_test_multiline "input multi-line-output command" \ set test "verify pagination from test_multiline" gdb_test_multiple "test_multiline" $test { - -re "--Type <RET>" { - exp_continue - } - -re " for more, q to quit" { - exp_continue - } - -re ", c to continue without paging--$" { + -re "$pagination_prompt$" { pass $test } } @@ -328,4 +322,89 @@ proc_with_prefix test_command_redefining_itself {} { "call command redefining itself 2" } +# Try to create commands using unknown prefixes and check GDB gives an +# error. There's also a test in here for an ambiguous prefix, which +# gives the same error. +proc_with_prefix test_unknown_prefix {} { + clean_restart + + gdb_test_no_output "python gdb.Command('foo1', gdb.COMMAND_NONE, prefix=True)" + gdb_test_no_output "python gdb.Command('foo cmd', gdb.COMMAND_NONE)" + + foreach prefix { "xxx" "foo xxx" "foo1 xxx" } { + gdb_test "python gdb.Command('$prefix cmd', gdb.COMMAND_NONE)" \ + [multi_line \ + "Python Exception <class 'RuntimeError'>: Could not find command prefix $prefix\\." \ + "Error occurred in Python: Could not find command prefix $prefix\\."] + } + + gdb_test_no_output "python gdb.Command('foo2', gdb.COMMAND_NONE, prefix=True)" + + foreach prefix { "foo" "foo xxx" "foo1 xxx" "foo2 xxx" } { + gdb_test "python gdb.Command('$prefix cmd2', gdb.COMMAND_NONE)" \ + [multi_line \ + "Python Exception <class 'RuntimeError'>: Could not find command prefix $prefix\\." \ + "Error occurred in Python: Could not find command prefix $prefix\\."] + } +} + +# Check what happens if a command object is called without an 'invoke' +# method. +proc_with_prefix test_deleting_invoke_methods {} { + clean_restart + + gdb_test_multiline "create 'foo' prefix command" \ + "python" "" \ + "class test_prefix(gdb.Command):" "" \ + " def __init__ (self):" "" \ + " super().__init__ (\"foo\", gdb.COMMAND_USER, prefix=True)" "" \ + " def invoke (self, arg, from_tty):" "" \ + " print(\"In 'foo' invoke: %s\" % arg)" "" \ + "foo = test_prefix()" "" \ + "end" "" + + gdb_test_multiline "create 'foo bar' command" \ + "python" "" \ + "class test_cmd(gdb.Command):" "" \ + " def __init__ (self):" "" \ + " super().__init__ (\"foo bar\", gdb.COMMAND_USER)" "" \ + " def invoke (self, arg, from_tty):" "" \ + " print(\"In 'foo bar' invoke: %s\" % arg)" "" \ + "foo_bar = test_cmd()" "" \ + "end" "" + + gdb_test "foo def" "In 'foo' invoke: def" \ + "call 'foo' with an unknown sub-command" + + gdb_test "foo bar def" "In 'foo bar' invoke: def" \ + "call 'foo bar' with arguments" + + gdb_test_no_output "python del(foo_bar.__class__.invoke)" \ + "delete invoke from test_cmd class" + + with_test_prefix "after deleting test_cmd.invoke" { + gdb_test "foo def" "In 'foo' invoke: def" \ + "call 'foo' with an unknown sub-command" + + gdb_test "foo bar def" \ + "^Python command object missing 'invoke' method\\." \ + "call 'foo bar' with arguments" + } + + gdb_test_no_output "python del(foo.__class__.invoke)" \ + "delete invoke from test_prefix class" + + with_test_prefix "after deleting test_prefix.invoke" { + gdb_test "foo def" \ + "^Python command object missing 'invoke' method\\." \ + "call 'foo' with an unknown sub-command" + + gdb_test "foo bar def" \ + "^Python command object missing 'invoke' method\\." \ + "call 'foo bar' with arguments" + } +} + test_command_redefining_itself +test_unknown_prefix +test_deleting_invoke_methods diff --git a/gdb/testsuite/gdb.python/py-color-leak.exp b/gdb/testsuite/gdb.python/py-color-leak.exp new file mode 100644 index 0000000..6d7fa7c --- /dev/null +++ b/gdb/testsuite/gdb.python/py-color-leak.exp @@ -0,0 +1,28 @@ +# Copyright (C) 2025 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 checks for memory leaks +# associated with allocating gdb.Color objects. + +load_lib gdb-python.exp + +require allow_python_tests + +standard_testfile + +clean_restart + +gdb_py_run_memory_leak_test ${srcdir}/${subdir}/${testfile}.py \ + "gdb.Color object deallocates correctly" diff --git a/gdb/testsuite/gdb.python/py-color-leak.py b/gdb/testsuite/gdb.python/py-color-leak.py new file mode 100644 index 0000000..852458f --- /dev/null +++ b/gdb/testsuite/gdb.python/py-color-leak.py @@ -0,0 +1,39 @@ +# Copyright (C) 2025 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/>. + +import sys + +import gdb + +# Avoid generating +# src/gdb/testsuite/gdb.python/__pycache__/gdb_leak_detector.cpython-<n>.pyc. +sys.dont_write_bytecode = True + +import gdb_leak_detector # noqa: E402 + + +class color_leak_detector(gdb_leak_detector.gdb_leak_detector): + def __init__(self): + super().__init__(__file__) + self.color = None + + def allocate(self): + self.color = gdb.Color("red") + + def deallocate(self): + self.color = None + + +color_leak_detector().run() diff --git a/gdb/testsuite/gdb.python/py-color-pagination.exp b/gdb/testsuite/gdb.python/py-color-pagination.exp new file mode 100644 index 0000000..6b10f9c --- /dev/null +++ b/gdb/testsuite/gdb.python/py-color-pagination.exp @@ -0,0 +1,194 @@ +# Copyright (C) 2025 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 gdb.Color and how this +# interacts with GDB's pagination system. The test also tests gdb.Style +# because the tests are very similar. + +load_lib gdb-python.exp + +require allow_python_tests +require {!is_remote host} + +standard_testfile + +set pyfile [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py] + +set str "<[string repeat - 78]>" + +# These define all the default attributes for a style: background +# color, intensity, italics, and underlined. +set other_attr ";49;22;23;24;27" + +# These colors set the foreground color only. Everything else is the +# default. +set black "(?:\033\\\[30${other_attr}m)" +set red "(?:\033\\\[31${other_attr}m)" +set green "(?:\033\\\[32${other_attr}m)" +set yellow "(?:\033\\\[33${other_attr}m)" +set blue "(?:\033\\\[34${other_attr}m)" +set magenta "(?:\033\\\[35${other_attr}m)" +set cyan "(?:\033\\\[36${other_attr}m)" +set white "(?:\033\\\[37${other_attr}m)" + +set any_color "(?:${black}|${red}|${green}|${yellow}|${blue}|${magenta}|${cyan}|${white})" + +# Run the command 'TYPE-fill MODE' which fills the screen with output and +# triggers the pagination prompt. Check that styling is applied correctly +# to the output. +proc test_pagination { type mode } { + + # Start with a fresh GDB, but enable color support. + with_ansi_styling_terminal { + clean_restart + } + + gdb_test_no_output "source $::pyfile" "source the script" + + gdb_test_no_output "set width 80" + gdb_test_no_output "set height 15" + + set saw_bad_color_handling false + set expected_restore_color "" + set last_color "" + gdb_test_multiple "$type-fill $mode" "" { + -re "^$type-fill $mode\r\n" { + exp_continue + } + + -re "^(${::any_color})(${::any_color})$::str" { + # After a continuation prompt GDB will restore the previous + # color, and then we immediately switch to a new color. + set restored_color $expect_out(1,string) + if { $restored_color ne $expected_restore_color } { + set saw_bad_color_handling true + } + set last_color $expect_out(2,string) + exp_continue + } + + -re "^(${::any_color})$::str" { + # This pattern matches printing STR in all cases that are not + # immediately after a pagination prompt. In this case there is + # a single escape sequence to set the color. + set last_color $expect_out(1,string) + exp_continue + } + + -re "^\033\\\[${::decimal}m$::str" { + # This catches the case where the color's escape sequence has + # not been converted back into a full style. This indicates + # something went wrong in the pager_file::puts function. + set saw_bad_color_handling true + exp_continue + } + + -re "^\033\\\[m$::pagination_prompt$" { + # After a pagination prompt we expect GDB to restore the last + # color. + set expected_restore_color $last_color + + # Send '\n' to view more output. + send_gdb "\n" + exp_continue + } + + -re "^$::pagination_prompt$" { + # After a pagination prompt we expect GDB to restore the last + # color. + set expected_restore_color $last_color + + # If we didn't see a color reset sequence before the pagination + # prompt, then the prompt will have been printed in the wrong + # color, this is a GDB bug. + set saw_bad_color_handling true + + # Send '\n' to view more output. + send_gdb "\n" + exp_continue + } + + -re "^\r\n" { + # The matches the newline sent to the continuation prompt. + exp_continue + } + + -re "^\033\\\[m\r\n$::gdb_prompt $" { + gdb_assert { !$saw_bad_color_handling } $gdb_test_name + } + } +} + +# Run the command 'style-fill-v2' which fills the screen with output and +# triggers the pagination prompt. Check that styling is applied correctly +# to the output. This v2 command is exercising passing a style to +# gdb.write() rather than passing the escape sequence for the style. +proc test_pagination_v2 { } { + set saw_bad_color_handling false + set expected_restore_color "" + set last_color "" + gdb_test_multiple "style-fill-v2" "" { + -re "^style-fill-v2\r\n" { + exp_continue + } + + -re "^(${::any_color}\033\\\[m)(${::any_color})$::str\033\\\[m" { + # After a continuation prompt GDB will restore the previous + # color, and then we immediately switch to a new color. + set restored_color $expect_out(1,string) + if { $restored_color ne $expected_restore_color } { + set saw_bad_color_handling true + } + set last_color $expect_out(2,string) + exp_continue + } + + -re "^(${::any_color})$::str\033\\\[m" { + # This pattern matches printing STR in all cases that are not + # immediately after a pagination prompt. In this case there is + # a single escape sequence to set the color. + set last_color $expect_out(1,string) + exp_continue + } + + -re "^$::pagination_prompt$" { + # After a pagination prompt we expect GDB to restore the last + # color, but this will then be disabled due to a styled + # gdb.write emitting a return to default style escape sequence. + set expected_restore_color "$last_color\033\[m" + + # Send '\n' to view more output. + send_gdb "\n" + exp_continue + } + + -re "^\r\n" { + # The matches the newline sent to the continuation prompt. + exp_continue + } + + -re "^$::gdb_prompt $" { + gdb_assert { !$saw_bad_color_handling } $gdb_test_name + } + } +} + +foreach_with_prefix type { color style } { + foreach_with_prefix mode { write print } { + test_pagination $type $mode + } +} + +test_pagination_v2 diff --git a/gdb/testsuite/gdb.python/py-color-pagination.py b/gdb/testsuite/gdb.python/py-color-pagination.py new file mode 100644 index 0000000..9cdc76c --- /dev/null +++ b/gdb/testsuite/gdb.python/py-color-pagination.py @@ -0,0 +1,82 @@ +# Copyright (C) 2025 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/>. + +import gdb + +basic_colors = ["black", "red", "green", "yellow", "blue", "magenta", "cyan", "white"] + + +def write(mode, text): + if mode == "write": + gdb.write(text) + else: + print(text, end="") + + +class ColorTester(gdb.Command): + def __init__(self): + super().__init__("color-fill", gdb.COMMAND_USER) + + def invoke(self, args, from_tty): + mode = args + str = "<" + "-" * 78 + ">" + for i in range(0, 20): + for color_name in basic_colors: + c = gdb.Color(color_name) + write(mode, c.escape_sequence(True)) + write(mode, str) + + default = gdb.Color("none") + write(mode, default.escape_sequence(True)) + write(mode, "\n") + + +class StyleTester(gdb.Command): + def __init__(self): + super().__init__("style-fill", gdb.COMMAND_USER) + + def invoke(self, args, from_tty): + mode = args + str = "<" + "-" * 78 + ">" + for i in range(0, 20): + for color_name in basic_colors: + c = gdb.Color(color_name) + s = gdb.Style(foreground=c) + write(mode, s.escape_sequence()) + write(mode, str) + + default = gdb.Style() + write(mode, default.escape_sequence()) + write(mode, "\n") + + +class StyleTester2(gdb.Command): + def __init__(self): + super().__init__("style-fill-v2", gdb.COMMAND_USER) + + def invoke(self, args, from_tty): + str = "<" + "-" * 78 + ">" + for i in range(0, 20): + for color_name in basic_colors: + c = gdb.Color(color_name) + s = gdb.Style(foreground=c) + gdb.write(str, style=s) + + gdb.write("\n") + + +ColorTester() +StyleTester() +StyleTester2() diff --git a/gdb/testsuite/gdb.python/py-color.exp b/gdb/testsuite/gdb.python/py-color.exp index c6f1041..08089e5 100644 --- a/gdb/testsuite/gdb.python/py-color.exp +++ b/gdb/testsuite/gdb.python/py-color.exp @@ -13,17 +13,22 @@ # 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 gdb.parameter and gdb.Parameter. +# This file is part of the GDB testsuite. It tests gdb.Color. load_lib gdb-python.exp require allow_python_tests +require {!is_remote host} -# Start with a fresh gdb. -clean_restart +# Start with a fresh GDB, but enable color support. +with_ansi_styling_terminal { + clean_restart +} -gdb_test_no_output "python print_color_attrs = lambda c: print (c, c.colorspace, c.is_none, c.is_indexed, c.is_direct)" \ +gdb_test_no_output "python get_color_attrs = lambda c: \"%s %s %s %s %s\" % (str(c), c.colorspace, c.is_none, c.is_indexed, c.is_direct)" \ + "get_color_attrs helper" + +gdb_test_no_output "python print_color_attrs = lambda c: print (get_color_attrs (c))" \ "print_color_attrs helper" gdb_test_no_output "python c = gdb.Color ()" \ @@ -59,6 +64,15 @@ gdb_test "python print_color_attrs (c)" "green 1 False True False" \ gdb_test "python print (c.index)" "2" \ "print index of a basic color with ansi colorspace" +# Create a color using keyword arguments, and check it matches the +# non-keyword color. +gdb_test_no_output "python c2 = gdb.Color (color_space = gdb.COLORSPACE_ANSI_8COLOR, value = 2)" \ + "create color from basic index and ansi colorspace using keywords" +gdb_test "python print(get_color_attrs (c) == get_color_attrs (c2))" "True" \ + "check attributes match" +gdb_test "python print(c.index == c2.index)" "True" \ + "check index matches" + gdb_test_no_output "python c = gdb.Color (2, gdb.COLORSPACE_XTERM_256COLOR)" \ "create color from basic index and xterm256 colorspace" gdb_test "python print_color_attrs (c)" "2 3 False True False" \ @@ -97,4 +111,54 @@ gdb_test [concat "python print (c_red.escape_sequence (True) + " \ "c_none.escape_sequence (True))"] \ "\033\\\[31m\033\\\[42mred on green\033\\\[49m red on default\033\\\[39m" \ "escape sequences" - +gdb_test [concat "python print (c_red.escape_sequence (is_foreground = True) + " \ + "c_green.escape_sequence (is_foreground = False) + 'red on green' + " \ + "c_none.escape_sequence (is_foreground = False) + ' red on default' + " \ + "c_none.escape_sequence (is_foreground = True))"] \ + "\033\\\[31m\033\\\[42mred on green\033\\\[49m red on default\033\\\[39m" \ + "escape sequences using keyword arguments" + +# Ensure that turning styling off means no escape sequences. +gdb_test_no_output "set style enabled off" +gdb_test_no_output "python print (c_red.escape_sequence (True), end='')" +gdb_test_no_output "python print (c_red.escape_sequence (False), end='')" +gdb_test_no_output "set style enabled on" + +gdb_test_multiline "Try to sub-class gdb.Color" \ + "python" "" \ + "class my_color(gdb.Color):" "" \ + " def __init__(self):" "" \ + " super().__init__('red')" "" \ + "end" \ + [multi_line \ + "Python Exception <class 'TypeError'>: type 'gdb\\.Color' is not an acceptable base type" \ + "Error occurred in Python: type 'gdb\\.Color' is not an acceptable base type"] + +gdb_test_multiline "Setup a color parameter and non gdb.Color object" \ + "python" "" \ + "class my_param(gdb.Parameter):" "" \ + " def __init__(self):" "" \ + " super().__init__('color-param', gdb.COMMAND_NONE, gdb.PARAM_COLOR)" "" \ + " self.value = gdb.Color('red')" "" \ + "color_param = my_param()" "" \ + " " "" \ + "class bad_type:" "" \ + " @property" "" \ + " def __class__(self):" "" \ + " raise RuntimeError('__class__ error for bad_type')" "" \ + "bad_obj = bad_type()" "" \ + "end" "" + +gdb_test_no_output "python color_param.value = gdb.Color('blue')" \ + "set color parameter to blue" + +gdb_test "python color_param.value = bad_obj" \ + [multi_line \ + "Python Exception <class 'RuntimeError'>: color argument must be a gdb\\.Color object\\." \ + "Error occurred in Python: color argument must be a gdb\\.Color object\\."] \ + "set color parameter to a non-color type" + +gdb_test "python c_none.escape_sequence(c_red)" \ + [multi_line \ + "Python Exception <class 'TypeError'>: argument 1 must be bool, not gdb.Color" \ + "Error occurred in Python: argument 1 must be bool, not gdb.Color"] diff --git a/gdb/testsuite/gdb.python/py-commands-breakpoint.py b/gdb/testsuite/gdb.python/py-commands-breakpoint.py index dbe7676..df732e7 100644 --- a/gdb/testsuite/gdb.python/py-commands-breakpoint.py +++ b/gdb/testsuite/gdb.python/py-commands-breakpoint.py @@ -34,10 +34,10 @@ class PyCommandsBreakpoint(gdb.Breakpoint): def __setattr__(self, name, value): if name == "commands": - l = ["python PyCommandsBreakpoint.run_py_commands(%d)" % self.number] + cmds = ["python PyCommandsBreakpoint.run_py_commands(%d)" % self.number] if value != "": - l.append(value) - value = "\n".join(l) + cmds.append(value) + value = "\n".join(cmds) super().__setattr__(name, value) diff --git a/gdb/testsuite/gdb.python/py-connection-removed.exp b/gdb/testsuite/gdb.python/py-connection-removed.exp index d60ebb0..5056eb1 100644 --- a/gdb/testsuite/gdb.python/py-connection-removed.exp +++ b/gdb/testsuite/gdb.python/py-connection-removed.exp @@ -58,8 +58,17 @@ if { [target_info exists gdb_protocol] } { set connection_type "native" } -# Add an inferior that shares a connection with inferior 1. -gdb_test "add-inferior" "Added inferior 2 on connection 1 \[^\r\n\]+" +# Add an inferior that shares a connection with inferior 1. If we are +# using a 'remote' connection then this cannot be shared with the new +# inferior, so we get a warning, and a new inferior with no connection. +if { $connection_type == "remote" } { + gdb_test "add-inferior" \ + [multi_line \ + "warning: can't share connection 1 \\(remote \[^\r\n\]+\\) between inferiors" \ + "Added inferior 2"] +} else { + gdb_test "add-inferior" "Added inferior 2 on connection 1 \[^\r\n\]+" +} # Add an inferior with no connection. gdb_test "add-inferior -no-connection" "Added inferior 3" diff --git a/gdb/testsuite/gdb.python/py-corefile.c b/gdb/testsuite/gdb.python/py-corefile.c new file mode 100644 index 0000000..1334ff6 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-corefile.c @@ -0,0 +1,25 @@ +/* Copyright 2025 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 <stdlib.h> + +int +main (void) +{ + /* With correct ulimit, etc. this should cause a core dump. */ + abort (); +} diff --git a/gdb/testsuite/gdb.python/py-corefile.exp b/gdb/testsuite/gdb.python/py-corefile.exp new file mode 100644 index 0000000..866b60a --- /dev/null +++ b/gdb/testsuite/gdb.python/py-corefile.exp @@ -0,0 +1,281 @@ +# Copyright (C) 2025 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 core file +# support in Python. + +require isnative + +load_lib gdb-python.exp + +require allow_python_tests + +standard_testfile + +if {[build_executable "build executable" $testfile $srcfile] == -1} { + return +} + +set corefile [core_find $binfile] +if {$corefile == ""} { + unsupported "couldn't create or find corefile" + return +} + +# Create a copy of the corefile. +set other_corefile [standard_output_file ${testfile}-other.core] +remote_exec build "cp $corefile $other_corefile" + +clean_restart + +gdb_test_no_output "python inf = gdb.selected_inferior()" \ + "capture current inferior" + +gdb_test "python print(inf.corefile)" "^None" \ + "Inferior.corefile is None before loading a core file" + +gdb_test "core-file $corefile" ".*" \ + "load core file" + +set file_re [string_to_regexp $corefile] +gdb_test "python print(inf.corefile)" "^<gdb\\.Corefile inferior=1 filename='$file_re'>" \ + "Inferior.corefile is a valid object after loading a core file" + +gdb_test_no_output "python core1=inf.corefile" "capture gdb.Corefile object" + +gdb_test "python print(core1.__dict__)" "^\\{\\}" \ + "print Corefile.__dict__ when empty" + +gdb_test_no_output "python core1._my_attribute = \"Hello\"" \ + "write new attribute into Corefile object" + +gdb_test "python print(core1._my_attribute)" "^Hello" \ + "immediately read new attribute" + +gdb_test "python print(core1.__dict__)" "^\\{'_my_attribute': 'Hello'\\}" \ + "print Corefile.__dict__ after adding an attribute" + +gdb_test "python print(core1.filename)" "^$file_re" \ + "Corefile.filename attribute works as expected" + +gdb_test "python print(core1.is_valid())" "^True" \ + "Corefile.is_valid() is True while corefile is loaded" + +gdb_test "core-file" "^No core file now\\." "unload current core file" + +gdb_test "python print(core1.is_valid())" "^False" \ + "Corefile.is_valid() is False after corefile is unloaded" + +gdb_test "python print(core1.__dict__)" "^\\{'_my_attribute': 'Hello'\\}" \ + "print Corefile.__dict__ with attribute when invalid" + +gdb_test "python print(core1)" "^<gdb\\.Corefile \\(invalid\\)>" \ + "print an invalid gdb.Corefile object" + +gdb_test "python print(core1.filename)" \ + [multi_line \ + "Python Exception <class 'RuntimeError'>: Corefile no longer exists\\." \ + "Error occurred in Python: Corefile no longer exists\\."] \ + "error when reading filename from invalid Corefile" + +gdb_test "python print(inf.corefile)" "^None" \ + "Inferior.corefile is None again after corefile unload" + +gdb_test "python print(core1._my_attribute)" "^Hello" \ + "read new attribute from invalid core file" + +# Create a second inferior. +gdb_test "add-inferior" +gdb_test "inferior 2" + +with_test_prefix "in second inferior" { + gdb_test "core-file $corefile" ".*" \ + "load core file" + + gdb_test "python print(inf.corefile)" "^None" \ + "first inferior still has no core file" + + gdb_test_no_output "python core2=gdb.selected_inferior().corefile" \ + "capture gdb.Corefile object" + + # The _my_attribute was added to CORE1, not CORE2. Check it + # doesn't somehow appear on CORE2. + gdb_test "python print(core2._my_attribute)" \ + "AttributeError.*: 'gdb\\.Corefile' object has no attribute '_my_attribute'" \ + "try to read attribute that doesn't exist" + + gdb_test "python print(core2.filename)" "^$file_re" \ + "Corefile.filename attribute works as expected" + + gdb_test "inferior 1" +} + +# Read the name of the core file from the second program space while +# the current program space is the first one. +gdb_test "python print(core2.filename)" "^$file_re" \ + "Corefile.filename attribute works from different progspace" + +# Load the other corefile into the first inferior. +gdb_test "core $other_corefile" ".*" \ + "load other corefile into inferior 1" + +# Delete the second inferior. We need to switch to the second +# inferior and unload its corefile before we can do that. Then, +# switch back to the first inferior, delete the second, and try to +# read the filename of the core file from the (now deleted) second +# inferior. We should get an error about the gdb.Corefile being +# invalid. +with_test_prefix "remove second inferior" { + gdb_test "inferior 2" + + gdb_test "python print(inf.corefile.filename)" \ + "^[string_to_regexp $other_corefile]" \ + "read inferior 1 corefile when in inferior 2" + + gdb_test_no_output "python core1=inf.corefile" \ + "capture inferior 1 gdb.Corefile while in inferior 2" + + # This is a new CORE1 object, check that _my_attribute is gone. + gdb_test "python print(core1._my_attribute)" \ + "AttributeError.*: 'gdb\\.Corefile' object has no attribute '_my_attribute'" \ + "try to read attribute that doesn't exist" + + gdb_test "core-file" + + gdb_test "python print(core2.filename)" \ + [multi_line \ + "Python Exception <class 'RuntimeError'>: Corefile no longer exists\\." \ + "Error occurred in Python: Corefile no longer exists\\."] \ + "error when reading filename from invalid Corefile" + + gdb_test "inferior 1" + + gdb_test "remove-inferiors 2" + + gdb_test "python print(core2.is_valid())" "^False" \ + "Corefile.is_valid() is False after corefile is unloaded, and Progspace is deleted" + + gdb_test "python print(core2.filename)" \ + [multi_line \ + "Python Exception <class 'RuntimeError'>: Corefile no longer exists\\." \ + "Error occurred in Python: Corefile no longer exists\\."] \ + "error when reading filename of an invalid Corefile, from deleted program space" + + gdb_test "python print(core1.is_valid())" "^True" \ + "check inferior 1 core file is still valid" +} + +# Test the Corefile.mapped_files() API. The Python script that is +# sourced here implements 'info proc mappings' in Python using the +# mapped_files API. The output from the built-in command, and the +# Python command should be identical. +with_test_prefix "test mapped files data" { + clean_restart + + set remote_python_file \ + [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py] + + # Load the Python script into GDB. + gdb_test "source $remote_python_file" "^Success" \ + "source python script" + + # Load the core file. + gdb_test "core-file $corefile" ".*" \ + "load core file" + + # Two files to write the output to. + set out_1 [standard_output_file ${gdb_test_file_name}-out-1.txt] + set out_2 [standard_output_file ${gdb_test_file_name}-out-2.txt] + + # Run the built-in command, then the new Python command, capture + # the output. + gdb_test "pipe info proc mappings | tee $out_1" ".*" \ + "capture built-in mappings output" + gdb_test "pipe info proc py-mappings | tee $out_2" ".*" \ + "capture Python based mappings data" + + # Check the output is identical. + gdb_test "shell diff -s $out_1 $out_2" \ + "Files \[^\r\n\]+-out-1.txt and \[^\r\n\]+-out-2.txt are identical" \ + "diff input and output one" + + # Check build-ids within the core file mapping data. I'm only + # aware of GNU/Linux placing the first page of each mapped ELF + # into the generated core file so that the build-id can be found. + if {[istarget *-*-linux*]} { + set results [list] + gdb_test_multiple "show-build-ids" "" { + -re "^show-build-ids\r\n" { + exp_continue + } + -re "^Objfile Build-Id\\s+Core File Build-Id\\s+File Name\\s*\r\n" { + exp_continue + } + -re "^(\\S+)\\s+(\\S+)\\s+(\[^\r\n\]+)\r\n" { + set objfile_build_id $expect_out(1,string) + set core_file_build_id $expect_out(2,string) + set file_name $expect_out(3,string) + lappend results [list $objfile_build_id \ + $core_file_build_id \ + $file_name] + exp_continue + } + -re "^$gdb_prompt " { + pass $gdb_test_name + } + } + + set bad_count 0 + foreach entry $results { + set objfile_build_id [lindex $entry 0] + set core_file_build_id [lindex $entry 1] + set file_name [lindex $entry 2] + if { $objfile_build_id ne $core_file_build_id } { + if { $core_file_build_id ne "None" } { + verbose -log "Mismatched build-ids $objfile_build_id vs $core_file_build_id for $file_name" + incr bad_count + } elseif { [expect_build_id_in_core_file $file_name] } { + verbose -log "Failed to find build-id for $file_name" + incr bad_count + } else { + verbose -log "This build-id was likely not in the core file" + } + } + } + + gdb_assert { $bad_count == 0 } \ + "found expected build-ids in core file" + } + + # Check the is_main_executable flag in the mapping data. + gdb_test "check-main-executable" "^PASS" + + # Check that the mapped files "list" is actually an immutable + # tuple. + gdb_test_no_output "python core = gdb.selected_inferior().corefile" + gdb_test_no_output "python mapped_files = core.mapped_files()" + gdb_test "python print(type(mapped_files))" \ + "^<class 'tuple'>" + gdb_test "python mapped_files\[0\] = None" \ + "'tuple' object does not support item assignment" + gdb_test "python print(mapped_files\[0\] is None)" "^False" + + # And same for the list of regions for a mapped file. + gdb_test_no_output "python regions = mapped_files\[0\].regions" + gdb_test "python print(type(regions))" \ + "^<class 'tuple'>" + gdb_test "python regions\[0\] = None" \ + "'tuple' object does not support item assignment" +} diff --git a/gdb/testsuite/gdb.python/py-corefile.py b/gdb/testsuite/gdb.python/py-corefile.py new file mode 100644 index 0000000..ab3d1b7 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-corefile.py @@ -0,0 +1,187 @@ +# Copyright (C) 2025 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/>. + +import pathlib + +import gdb + + +class Mapping: + def __init__(self, mapping, region): + self._mapping = mapping + self._region = region + + @property + def start(self): + return self._region.start + + @property + def end(self): + return self._region.end + + @property + def offset(self): + return self._region.file_offset + + @property + def filename(self): + return self._mapping.filename + + +def info_proc_mappings(): + print("Mapped address spaces:") + print("") + format_str = "%-18s %-18s %-18s %-18s %s " + print(format_str % ("Start Addr", "End Addr", "Size", "Offset", "File")) + + core = gdb.selected_inferior().corefile + mappings = core.mapped_files() + + result = [] + for m in mappings: + for r in m.regions: + result.append(Mapping(m, r)) + + result.sort(key=lambda x: x.start) + for r in result: + sz = r.end - r.start + print( + format_str + % ( + "0x%016x" % r.start, + "0x%016x" % r.end, + "0x%-16x" % sz, + "0x%-16x" % r.offset, + "%s" % r.filename, + ) + ) + + +class InfoProcPyMappings(gdb.Command): + def __init__(self): + gdb.Command.__init__(self, "info proc py-mappings", gdb.COMMAND_DATA) + + def invoke(self, args, from_tty): + info_proc_mappings() + + +InfoProcPyMappings() + + +# Assume that a core file is currently loaded. +# +# Look through all the objfiles for the current inferior, and record +# any that have a build-id. +# +# Then look through the core file mapped files. Look for entries that +# correspond with the loaded objfiles. For these matching entries, +# capture the build-id extracted from the core file. +# +# Finally, print a table with the build-id from the objfile, the +# build-id from the core file, and the file name. +# +# This is then processed from the test script to check the build-ids +# match. +class ShowBuildIds(gdb.Command): + def __init__(self): + gdb.Command.__init__(self, "show-build-ids", gdb.COMMAND_DATA) + + def invoke(self, args, from_tty): + inf = gdb.selected_inferior() + objfiles = inf.progspace.objfiles() + + path_to_build_id = {} + + # Initial length based on column headings. + longest_build_id = 18 + + for o in objfiles: + if not o.is_file or o.build_id is None or o.owner is not None: + continue + p = pathlib.Path(o.filename).resolve() + b = o.build_id + path_to_build_id[p] = {"objfile": b, "corefile": "missing"} + if len(b) > longest_build_id: + longest_build_id = len(b) + + core_mapped_files = inf.corefile.mapped_files() + for m in core_mapped_files: + p = pathlib.Path(m.filename).resolve() + b = m.build_id + + if b is not None and len(b) > longest_build_id: + longest_build_id = len(b) + + if p in path_to_build_id: + path_to_build_id[p]["corefile"] = b + + format_str = ( + "%-" + str(longest_build_id) + "s %-" + str(longest_build_id) + "s %s" + ) + + def make_title(string, length=0): + if length > 0: + padding_len = length - len(string) + else: + padding_len = 0 + + padding = " " * padding_len + style = gdb.Style("title") + return style.apply(string) + padding + + print( + "%s %s %s" + % ( + make_title("Objfile Build-Id", longest_build_id), + make_title("Core File Build-Id", longest_build_id), + make_title("File Name"), + ) + ) + for p, b in path_to_build_id.items(): + print(format_str % (b["objfile"], b["corefile"], p)) + + +ShowBuildIds() + + +class CheckMainExec(gdb.Command): + def __init__(self): + gdb.Command.__init__(self, "check-main-executable", gdb.COMMAND_DATA) + + def invoke(self, args, from_tty): + inf = gdb.selected_inferior() + pspace = inf.progspace + exec_filename = pathlib.Path(pspace.executable_filename).resolve() + + count = 0 + core_mapped_files = inf.corefile.mapped_files() + for m in core_mapped_files: + if not m.is_main_executable: + continue + + p = pathlib.Path(m.filename).resolve() + + count += 1 + assert exec_filename == p, "main exec filename mismatch" + + assert count == 1, "invalid main executable count" + + print("PASS") + + +CheckMainExec() + + +print("Success") diff --git a/gdb/testsuite/gdb.python/py-disasm.exp.tcl b/gdb/testsuite/gdb.python/py-disasm.exp.tcl index 938326d..c936f0d 100644 --- a/gdb/testsuite/gdb.python/py-disasm.exp.tcl +++ b/gdb/testsuite/gdb.python/py-disasm.exp.tcl @@ -24,14 +24,16 @@ standard_testfile py-disasm.c if { $kind == "obj" } { - set obj [standard_output_file ${gdb_test_file_name}.o] + set testfile $testfile.o + set binfile [standard_output_file $testfile] - if { [gdb_compile "$srcdir/$subdir/$srcfile" $obj object "debug"] != "" } { - untested "failed to compile object file [file tail $obj]" + if { [gdb_compile "$srcdir/$subdir/$srcfile" $binfile object \ + "debug"] != "" } { + untested "failed to compile object file $testfile" return -1 } - clean_restart $obj + clean_restart $testfile } else { @@ -49,7 +51,7 @@ if { $kind == "obj" } { set pyfile [gdb_remote_download host ${srcdir}/${subdir}/py-disasm.py] gdb_test "source ${pyfile}" "Python script imported" \ - "import python scripts" + "import python scripts" set line [gdb_get_line_number "Break here."] @@ -152,7 +154,10 @@ set test_plans \ "Buffer returned from read_memory is sized $decimal instead of the expected $decimal"]] \ [list "ResultOfWrongType" \ [make_exception_pattern "TypeError" \ - "Result is not a DisassemblerResult."]] \ + "Result from Disassembler must be gdb.DisassemblerResult, not Blah."]] \ + [list "ResultOfVeryWrongType" \ + [make_exception_pattern "TypeError" \ + "Result from Disassembler must be gdb.DisassemblerResult, not Blah."]] \ [list "ErrorCreatingTextPart_NoArgs" \ [make_exception_pattern "TypeError" \ [missing_arg_pattern "style" 1]]] \ diff --git a/gdb/testsuite/gdb.python/py-disasm.py b/gdb/testsuite/gdb.python/py-disasm.py index 32d6aa7..d88c7a2 100644 --- a/gdb/testsuite/gdb.python/py-disasm.py +++ b/gdb/testsuite/gdb.python/py-disasm.py @@ -39,9 +39,7 @@ def builtin_disassemble_wrapper(info): def check_building_disassemble_result(): """Check that we can create DisassembleResult objects correctly.""" - - result = gdb.disassembler.DisassemblerResult() - + gdb.disassembler.DisassemblerResult() print("PASS") @@ -62,16 +60,12 @@ class TestDisassembler(Disassembler): disassembly wrapping for the global CURRENT_PC.""" def __init__(self): - global current_pc - super().__init__("TestDisassembler") self.__info = None - if current_pc == None: + if current_pc is None: raise gdb.GdbError("no current_pc set") def __call__(self, info): - global current_pc - if info.address != current_pc: return None self.__info = info @@ -234,7 +228,7 @@ class GdbErrorLateDisassembler(TestDisassembler): """Raise a GdbError after calling the builtin disassembler.""" def disassemble(self, info): - result = builtin_disassemble_wrapper(info) + builtin_disassemble_wrapper(info) raise gdb.GdbError("GdbError after builtin disassembler") @@ -242,7 +236,7 @@ class RuntimeErrorLateDisassembler(TestDisassembler): """Raise a RuntimeError after calling the builtin disassembler.""" def disassemble(self, info): - result = builtin_disassemble_wrapper(info) + builtin_disassemble_wrapper(info) raise RuntimeError("RuntimeError after builtin disassembler") @@ -265,7 +259,7 @@ class MemoryErrorLateDisassembler(TestDisassembler): before we return a result.""" def disassemble(self, info): - result = builtin_disassemble_wrapper(info) + builtin_disassemble_wrapper(info) # The following read will throw an error. info.read_memory(1, -info.address - 1) return DisassemblerResult(1, "BAD") @@ -277,7 +271,7 @@ class RethrowMemoryErrorDisassembler(TestDisassembler): def disassemble(self, info): try: info.read_memory(1, -info.address - 1) - except gdb.MemoryError as e: + except gdb.MemoryError: raise gdb.MemoryError("cannot read code at address -1") return DisassemblerResult(1, "BAD") @@ -294,6 +288,24 @@ class ResultOfWrongType(TestDisassembler): return self.Blah(1, "ABC") +class ResultOfVeryWrongType(TestDisassembler): + """Return something that is not a DisassemblerResult from disassemble + method. The thing returned will raise an exception if used in an + isinstance() call, or in PyObject_IsInstance from C++. + """ + + class Blah: + def __init__(self): + pass + + @property + def __class__(self): + raise RuntimeError("error from __class__ in Blah") + + def disassemble(self, info): + return self.Blah() + + class TaggingDisassembler(TestDisassembler): """A simple disassembler that just tags the output.""" @@ -339,31 +351,31 @@ class GlobalCachingDisassembler(TestDisassembler): assert isinstance(info, gdb.disassembler.DisassembleInfo) assert not info.is_valid() try: - val = info.address + info.address raise gdb.GdbError("DisassembleInfo.address is still valid") except RuntimeError as e: assert str(e) == "DisassembleInfo is no longer valid." - except: + except Exception: raise gdb.GdbError( "DisassembleInfo.address raised an unexpected exception" ) try: - val = info.architecture + info.architecture raise gdb.GdbError("DisassembleInfo.architecture is still valid") except RuntimeError as e: assert str(e) == "DisassembleInfo is no longer valid." - except: + except Exception: raise gdb.GdbError( "DisassembleInfo.architecture raised an unexpected exception" ) try: - val = info.read_memory(1, 0) + info.read_memory(1, 0) raise gdb.GdbError("DisassembleInfo.read is still valid") except RuntimeError as e: assert str(e) == "DisassembleInfo is no longer valid." - except: + except Exception: raise gdb.GdbError( "DisassembleInfo.read raised an unexpected exception" ) @@ -528,32 +540,28 @@ class ErrorCreatingTextPart_NoArgs(TestDisassembler): """Try to create a DisassemblerTextPart with no arguments.""" def disassemble(self, info): - part = info.text_part() - return None + info.text_part() class ErrorCreatingAddressPart_NoArgs(TestDisassembler): """Try to create a DisassemblerAddressPart with no arguments.""" def disassemble(self, info): - part = info.address_part() - return None + info.address_part() class ErrorCreatingTextPart_NoString(TestDisassembler): """Try to create a DisassemblerTextPart with no string argument.""" def disassemble(self, info): - part = info.text_part(gdb.disassembler.STYLE_TEXT) - return None + info.text_part(gdb.disassembler.STYLE_TEXT) class ErrorCreatingTextPart_NoStyle(TestDisassembler): """Try to create a DisassemblerTextPart with no string argument.""" def disassemble(self, info): - part = info.text_part(string="abc") - return None + info.text_part(string="abc") class ErrorCreatingTextPart_StringAndParts(TestDisassembler): @@ -600,8 +608,6 @@ class Build_Result_Using_All_Parts(TestDisassembler): text and address parts.""" def disassemble(self, info): - global current_pc - parts = [] parts.append(info.text_part(gdb.disassembler.STYLE_MNEMONIC, "fake")) parts.append(info.text_part(gdb.disassembler.STYLE_TEXT, "\t")) @@ -759,8 +765,8 @@ class AnalyzingDisassembler(Disassembler): idx > 0 and idx != nop_idx and not is_nop(self._pass_1_insn[idx]) - and self._pass_1_length[idx] > self._pass_1_length[nop_idx] - and self._pass_1_length[idx] % self._pass_1_length[nop_idx] == 0 + and self._pass_1_length[idx] > nop_length + and self._pass_1_length[idx] % nop_length == 0 ): replace_idx = idx break @@ -774,7 +780,7 @@ class AnalyzingDisassembler(Disassembler): idx > 0 and idx != nop_idx and not is_nop(self._pass_1_insn[idx]) - and self._pass_1_length[idx] == self._pass_1_length[nop_idx] + and self._pass_1_length[idx] == nop_length ): replace_idx = idx break @@ -795,7 +801,7 @@ class AnalyzingDisassembler(Disassembler): # is a copy of _pass_1_insn, but replace the instruction we # identified above with a series of 'nop' instructions. self._check = list(self._pass_1_insn) - nop_count = int(self._pass_1_length[replace_idx] / self._pass_1_length[nop_idx]) + nop_count = int(self._pass_1_length[replace_idx] / nop_length) nop_insn = self._pass_1_insn[nop_idx] nops = [nop_insn] * nop_count self._check[replace_idx : (replace_idx + 1)] = nops @@ -834,7 +840,6 @@ class InvalidDisassembleInfo(gdb.disassembler.DisassembleInfo): @property def address(self): - global current_pc return current_pc @property diff --git a/gdb/testsuite/gdb.python/py-event-load.exp b/gdb/testsuite/gdb.python/py-event-load.exp index a09a946..dbb225f 100644 --- a/gdb/testsuite/gdb.python/py-event-load.exp +++ b/gdb/testsuite/gdb.python/py-event-load.exp @@ -20,12 +20,6 @@ load_lib gdb-python.exp require allow_shlib_tests allow_python_tests -if {[get_compiler_info]} { - warning "Could not get compiler info" - untested "no compiler info" - return -1 -} - standard_testfile .c if {[gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" \ executable {debug shlib_load}] != ""} { diff --git a/gdb/testsuite/gdb.python/py-events-shlib.c b/gdb/testsuite/gdb.python/py-events-shlib.c index d77517a..d480da2 100644 --- a/gdb/testsuite/gdb.python/py-events-shlib.c +++ b/gdb/testsuite/gdb.python/py-events-shlib.c @@ -17,4 +17,3 @@ void do_nothing (void) {} - diff --git a/gdb/testsuite/gdb.python/py-evsignal.exp b/gdb/testsuite/gdb.python/py-evsignal.exp index 22b13af..86444d7 100644 --- a/gdb/testsuite/gdb.python/py-evsignal.exp +++ b/gdb/testsuite/gdb.python/py-evsignal.exp @@ -39,9 +39,9 @@ gdb_test_no_output "set non-stop on" gdb_run_cmd gdb_test_multiple "" "signal Thread 3" { -re "event type: stop\r\nstop reason: signal\r\nstop signal: SIGUSR1\r\nthread num: 3\r\nevent type: stop\r\n.*$gdb_prompt $" { - pass "thread 3 was signaled" + pass "thread 3 was signaled" } -re "The target does not support running in non-stop mode" { - unsupported "non-stop mode is unsupported" + unsupported "non-stop mode is unsupported" } } diff --git a/gdb/testsuite/gdb.python/py-evthreads.exp b/gdb/testsuite/gdb.python/py-evthreads.exp index 0e9cd97..c0c17b3 100644 --- a/gdb/testsuite/gdb.python/py-evthreads.exp +++ b/gdb/testsuite/gdb.python/py-evthreads.exp @@ -41,11 +41,11 @@ gdb_run_cmd set test "run to breakpoint 1" gdb_test_multiple "" $test { -re "event type: stop\r\nstop reason: breakpoint\r\nfirst breakpoint number: 1\r\nbreakpoint number: 1\r\nthread num: 1\r\n.*$gdb_prompt $" { - pass $test + pass $test } -re "The target does not support running in non-stop mode" { - unsupported "non-stop mode is unsupported" - return + unsupported "non-stop mode is unsupported" + return } } @@ -61,13 +61,13 @@ set test "continue thread 1" gdb_test_multiple "continue&" $test { -re "event type: continue\r\nthread num: 3\r\n$gdb_prompt " { # This expect string must not expect the end-of-buffer '$'. - pass $test + pass $test } } set test "thread 3 was signaled" gdb_test_multiple "" $test { -re "event type: stop\r\nstop reason: signal\r\nstop signal: SIGUSR1\r\nthread num: 3\r\nevent type: stop\r\n" { - pass $test + pass $test } } diff --git a/gdb/testsuite/gdb.python/py-exec-file.exp b/gdb/testsuite/gdb.python/py-exec-file.exp index b3418a5..139ce83 100644 --- a/gdb/testsuite/gdb.python/py-exec-file.exp +++ b/gdb/testsuite/gdb.python/py-exec-file.exp @@ -19,8 +19,10 @@ load_lib gdb-python.exp standard_testfile -set binfile1 ${binfile}-a -set binfile2 ${binfile}-b +set testfile1 $testfile-a +set binfile1 [standard_output_file $testfile1] +set testfile2 $testfile-b +set binfile2 [standard_output_file $testfile2] if {[build_executable "failed to prepare first executable" \ $binfile1 $srcfile]} { @@ -176,7 +178,7 @@ with_test_prefix "using 'symbol-file' command" { # Check the executable_changed event when the executable changes on disk. with_test_prefix "exec changes on disk" { - clean_restart $binfile1 + clean_restart $::testfile1 setup_exec_change_handler diff --git a/gdb/testsuite/gdb.python/py-explore-cc.exp b/gdb/testsuite/gdb.python/py-explore-cc.exp index 0be7019..c3b1309 100644 --- a/gdb/testsuite/gdb.python/py-explore-cc.exp +++ b/gdb/testsuite/gdb.python/py-explore-cc.exp @@ -36,7 +36,7 @@ A = <Enter 0 to explore this base class of type 'A'>.*\ i = <Enter 1 to explore this field of type 'int'>.*\ c = <Enter 2 to explore this field of type 'char'>.*" -if ![runto_main] { +if {![runto_main]} { return -1 } @@ -49,93 +49,93 @@ gdb_test "explore int_ref" "'int_ref' is a scalar value of type 'int'.*int_ref = gdb_test_multiple "explore int_ptr_ref" "" { -re "$int_ptr_ref_desc.*Continue exploring it as a pointer to a single value \\\[y/n\\\]:.*" { - pass "explore int_ptr_ref" - gdb_test_multiple "y" "explore_int_ptr_ref_as_single_value_pointer" { - -re "'\[*\]int_ptr_ref' is a scalar value of type 'int'.*\[*\]int_ptr_ref = 10.*$gdb_prompt" { - pass "explore_int_ptr_ref_as_single_value_pointer" - } - } + pass "explore int_ptr_ref" + gdb_test_multiple "y" "explore_int_ptr_ref_as_single_value_pointer" { + -re "'\[*\]int_ptr_ref' is a scalar value of type 'int'.*\[*\]int_ptr_ref = 10.*$gdb_prompt" { + pass "explore_int_ptr_ref_as_single_value_pointer" + } + } } } gdb_test_multiple "explore b" "" { -re "$b_desc.*Enter the field number of choice:.*" { - pass "explore b" - gdb_test_multiple "0" "explore_base_class_A" { - -re "The value of 'b\.A' is a struct/class of type 'A' with no fields\." { - pass "explore_base_class_A, exploring b" - gdb_test_multiple "\0" "return_to_b_from_A" { - -re ".*$b_desc.*Enter the field number of choice:.*" { - pass "return_to_b_from_A" - gdb_test_multiple "1" "explore_field_i_of_b" { - -re "'b\.i' is a scalar value of type 'int'.*b\.i = 10.*" { - pass "explore_field_i_of_b" - gdb_test_multiple "\0" "return_to_b_from_i" { - -re "$b_desc.*Enter the field number of choice:.*" { - pass "return_to_b_from_i" - } - } - } - } - gdb_test_multiple "2" "explore_field_c_of_b" { - -re "'b\.c' is a scalar value of type 'char'.*b\.c = .*'a'.*" { - pass "explore_field_c_of_b" - gdb_test_multiple "\0" "return_to_b_from_c" { - -re "$b_desc.*Enter the field number of choice:.*" { - pass "return_to_b_from_c" - } - } - } - } - gdb_test_multiple "\0" "return_to_gdb_prompt" { - -re "$gdb_prompt" { - pass "return_to_gdb_prompt_from_b" - } - } - } - } - } - } + pass "explore b" + gdb_test_multiple "0" "explore_base_class_A" { + -re "The value of 'b\.A' is a struct/class of type 'A' with no fields\." { + pass "explore_base_class_A, exploring b" + gdb_test_multiple "\0" "return_to_b_from_A" { + -re ".*$b_desc.*Enter the field number of choice:.*" { + pass "return_to_b_from_A" + gdb_test_multiple "1" "explore_field_i_of_b" { + -re "'b\.i' is a scalar value of type 'int'.*b\.i = 10.*" { + pass "explore_field_i_of_b" + gdb_test_multiple "\0" "return_to_b_from_i" { + -re "$b_desc.*Enter the field number of choice:.*" { + pass "return_to_b_from_i" + } + } + } + } + gdb_test_multiple "2" "explore_field_c_of_b" { + -re "'b\.c' is a scalar value of type 'char'.*b\.c = .*'a'.*" { + pass "explore_field_c_of_b" + gdb_test_multiple "\0" "return_to_b_from_c" { + -re "$b_desc.*Enter the field number of choice:.*" { + pass "return_to_b_from_c" + } + } + } + } + gdb_test_multiple "\0" "return_to_gdb_prompt" { + -re "$gdb_prompt" { + pass "return_to_gdb_prompt_from_b" + } + } + } + } + } + } } } gdb_test_multiple "explore B" "" { -re "$B_desc.*Enter the field number of choice:.*" { - pass "explore B" - gdb_test_multiple "0" "explore_base_class_A" { - -re "base class 'A' of 'B' is a struct/class of type 'A' with no fields\." { - pass "explore_base_class_A, exploring B" - gdb_test_multiple "\0" "return_to_B" { - -re "$B_desc.*Enter the field number of choice:.*" { - pass "return_to_B" - gdb_test_multiple "1" "explore_field_i_of_B" { - -re "field 'i' of 'B' is of a scalar type 'int'.*" { - pass "explore_field_i_of_B" - gdb_test_multiple "\0" "return_to_B_from_i" { - -re "$B_desc.*Enter the field number of choice:.*" { - pass "return_to_B_from_i, exploring B" - } - } - } - } - gdb_test_multiple "2" "explore_field_c_of_B" { - -re "field 'c' of 'B' is of a scalar type 'char'.*" { - pass "explore_field_c_of_B" - gdb_test_multiple "\0" "return_to_B_from_c" { - -re "$B_desc.*Enter the field number of choice:.*" { - pass "return_to_B_from_c" - } - } - } - } - gdb_test_multiple "\0" "return_to_gdb_prompt" { - -re "$gdb_prompt" { - pass "return_to_gdb_prompt_from_B" - } - } - } - } - } - } + pass "explore B" + gdb_test_multiple "0" "explore_base_class_A" { + -re "base class 'A' of 'B' is a struct/class of type 'A' with no fields\." { + pass "explore_base_class_A, exploring B" + gdb_test_multiple "\0" "return_to_B" { + -re "$B_desc.*Enter the field number of choice:.*" { + pass "return_to_B" + gdb_test_multiple "1" "explore_field_i_of_B" { + -re "field 'i' of 'B' is of a scalar type 'int'.*" { + pass "explore_field_i_of_B" + gdb_test_multiple "\0" "return_to_B_from_i" { + -re "$B_desc.*Enter the field number of choice:.*" { + pass "return_to_B_from_i, exploring B" + } + } + } + } + gdb_test_multiple "2" "explore_field_c_of_B" { + -re "field 'c' of 'B' is of a scalar type 'char'.*" { + pass "explore_field_c_of_B" + gdb_test_multiple "\0" "return_to_B_from_c" { + -re "$B_desc.*Enter the field number of choice:.*" { + pass "return_to_B_from_c" + } + } + } + } + gdb_test_multiple "\0" "return_to_gdb_prompt" { + -re "$gdb_prompt" { + pass "return_to_gdb_prompt_from_B" + } + } + } + } + } + } } } diff --git a/gdb/testsuite/gdb.python/py-explore.c b/gdb/testsuite/gdb.python/py-explore.c index 5546eaf..cd64a57 100644 --- a/gdb/testsuite/gdb.python/py-explore.c +++ b/gdb/testsuite/gdb.python/py-explore.c @@ -64,7 +64,7 @@ main (void) ss.a = 10; ss.d = 100.01; ss_t = ss; - + su.d = 100.1; cs.s = ss; diff --git a/gdb/testsuite/gdb.python/py-explore.exp b/gdb/testsuite/gdb.python/py-explore.exp index a68c110..102355e 100644 --- a/gdb/testsuite/gdb.python/py-explore.exp +++ b/gdb/testsuite/gdb.python/py-explore.exp @@ -47,14 +47,14 @@ proc array_description { value_name type } { proc pointer_description { value_name type_name } { set type_description "'$value_name' is a pointer to a value of type '$type_name'\.\[\r\n\]+" - set prompt "Continue exploring it as a pointer to a single value \[\[\]y/n\[\]\]: " + set prompt "Continue exploring it as a pointer to a single value \[\[\]y/n\[\]\]: " return "$type_description$prompt" } proc field_values { args } { set result "" foreach field $args { - set result "$result\[ \]*$field \[\.\]\[\.\] \[\(\]Value of type .*\[\)\]\[\r\n\]+" + set result "$result\[ \]*$field \[\.\]\[\.\] \[\(\]Value of type .*\[\)\]\[\r\n\]+" } return $result } @@ -63,8 +63,8 @@ proc field_choices { args } { set result "" set field_num 0 foreach field $args { - set result "$result$field\[ \]+=\[ \]+<Enter $field_num to explore this field of type .*" - incr field_num + set result "$result$field\[ \]+=\[ \]+<Enter $field_num to explore this field of type .*" + incr field_num } return $result } @@ -75,7 +75,7 @@ proc scalar_value { value_name value } { set SS_fields [field_values {a = 10} {d = 100[.].*}] -if ![runto_main] { +if {![runto_main]} { return -1 } @@ -93,126 +93,126 @@ gdb_test "explore ss_t" "[typedef_description {ss_t} {SS} $SS].*[compound_descri gdb_test_multiple "explore ss_ptr" "" { -re "[pointer_description {ss_ptr} $SS].*" { - pass "explore ss_ptr" - gdb_test_multiple "y" "explore_as_single_value_pointer" { - -re "$SS_fields.*$gdb_prompt" { - pass "explore ss_ptr as single value pointer" - } - } + pass "explore ss_ptr" + gdb_test_multiple "y" "explore_as_single_value_pointer" { + -re "$SS_fields.*$gdb_prompt" { + pass "explore ss_ptr as single value pointer" + } + } } } gdb_test_multiple "explore darray_ref" "" { -re "[pointer_description {darray_ref} {double}].*" { - pass "explore darray_ref" - gdb_test_multiple "n" "no_to_explore_as_pointer" { - -re "Continue exploring it as a pointer to an array \[\[\]y/n\[\]\]: " { - pass "no_to_explore_as_pointer" - gdb_test_multiple "y" "explore_as_array" { - -re ".*Enter the index of the element you want to explore in 'darray_ref':.*" { - pass "explore_as_array" - gdb_test_multiple "2" "explore_as_array_index_2" { - -re ".*'darray_ref\\\[2\\\]' is a scalar value of type 'double'\..*darray_ref\\\[2\\\] = 0.*" { - pass "explore_as_array_index_2" - gdb_test_multiple "\0" "end explore_as_array_index_2" { - -re ".*Returning to parent value.*Enter the index of the element you want to explore in 'darray_ref':.*" { - pass "end explore_as_array_index_2" - gdb_test_multiple "\0" "end explore_as_array" { - -re "\[\n\r\]+$gdb_prompt" { - pass "end explore_as_array" - } - } - } - } - } - } - } - } - } - } + pass "explore darray_ref" + gdb_test_multiple "n" "no_to_explore_as_pointer" { + -re "Continue exploring it as a pointer to an array \[\[\]y/n\[\]\]: " { + pass "no_to_explore_as_pointer" + gdb_test_multiple "y" "explore_as_array" { + -re ".*Enter the index of the element you want to explore in 'darray_ref':.*" { + pass "explore_as_array" + gdb_test_multiple "2" "explore_as_array_index_2" { + -re ".*'darray_ref\\\[2\\\]' is a scalar value of type 'double'\..*darray_ref\\\[2\\\] = 0.*" { + pass "explore_as_array_index_2" + gdb_test_multiple "\0" "end explore_as_array_index_2" { + -re ".*Returning to parent value.*Enter the index of the element you want to explore in 'darray_ref':.*" { + pass "end explore_as_array_index_2" + gdb_test_multiple "\0" "end explore_as_array" { + -re "\[\n\r\]+$gdb_prompt" { + pass "end explore_as_array" + } + } + } + } + } + } + } + } + } + } } } gdb_test_multiple "explore su" "" { -re "[compound_description {su} {union} {union SimpleUnion}].*[field_choices {i} {c} {f} {d}].*$enter_field_number_prompt" { - pass "explore su" - gdb_test_multiple "3" "explore su.d" { - -re "[scalar_description {su.d} {double}].*[scalar_value {su.d} {100[.].*}].*$return_to_parent_prompt" { - pass "explore su.d" - gdb_test_multiple " " "end su.d exploration" { - -re ".*[compound_description {su} {union} {union SimpleUnion}].*[field_choices {i} {c} {f} {d}].*$enter_field_number_prompt" { - pass "end su.d exploration" - gdb_test_multiple "\0" "end su exploration" { - -re "$gdb_prompt" { - pass "end su exploration" - } - } - } - } - } - } + pass "explore su" + gdb_test_multiple "3" "explore su.d" { + -re "[scalar_description {su.d} {double}].*[scalar_value {su.d} {100[.].*}].*$return_to_parent_prompt" { + pass "explore su.d" + gdb_test_multiple " " "end su.d exploration" { + -re ".*[compound_description {su} {union} {union SimpleUnion}].*[field_choices {i} {c} {f} {d}].*$enter_field_number_prompt" { + pass "end su.d exploration" + gdb_test_multiple "\0" "end su exploration" { + -re "$gdb_prompt" { + pass "end su exploration" + } + } + } + } + } + } } } gdb_test_multiple "explore cs" "" { -re "[compound_description {cs} {struct/class} {struct ComplexStruct}].*[field_choices {s} {u} {sa}].*$enter_field_number_prompt" { - pass "explore cs" - gdb_test_multiple "0" "explore cs.s" { - -re "[compound_description {cs.s} {struct/class} {struct SimpleStruct}].*[field_values {a = 10} {d = 100[.].*}].*$return_to_parent_prompt" { - pass "explore cs.s" - gdb_test_multiple " " "end cs.s exploration" { - -re ".*$enter_field_number_prompt" { - pass "end cs.s exploration" - } - } - } - } - gdb_test_multiple "1" "explore cs.u" { - -re "[compound_description {cs.u} {union} {union SimpleUnion}].*.*[field_choices {i} {c} {f} {d}].*$enter_field_number_prompt" { - pass "explore cs.u" - gdb_test_multiple " " "end cs.u exploration" { - -re ".*$enter_field_number_prompt" { - pass "end cs.u exploration" - } - } - } - } - gdb_test_multiple "\0" "explore cs.u" { - -re "$gdb_prompt" { - pass "end cs exploration" - } - } + pass "explore cs" + gdb_test_multiple "0" "explore cs.s" { + -re "[compound_description {cs.s} {struct/class} {struct SimpleStruct}].*[field_values {a = 10} {d = 100[.].*}].*$return_to_parent_prompt" { + pass "explore cs.s" + gdb_test_multiple " " "end cs.s exploration" { + -re ".*$enter_field_number_prompt" { + pass "end cs.s exploration" + } + } + } + } + gdb_test_multiple "1" "explore cs.u" { + -re "[compound_description {cs.u} {union} {union SimpleUnion}].*.*[field_choices {i} {c} {f} {d}].*$enter_field_number_prompt" { + pass "explore cs.u" + gdb_test_multiple " " "end cs.u exploration" { + -re ".*$enter_field_number_prompt" { + pass "end cs.u exploration" + } + } + } + } + gdb_test_multiple "\0" "explore cs.u" { + -re "$gdb_prompt" { + pass "end cs exploration" + } + } } } gdb_test_multiple "explore cu" "" { -re "[compound_description {cu} {union} {union ComplexUnion}].*[field_choices {s} {sa}].*$enter_field_number_prompt" { - pass "explore cu" - gdb_test_multiple "1" "explore cu.sa" { - -re ".*[array_description {cu.sa} $SS].*$array_index_prompt" { - pass "explore cu.sa" - gdb_test_multiple "0" "explore cu.sa\[0\]" { - -re "[compound_description {\(cu.sa\)\[0\]} {struct/class} {struct SimpleStruct}].*[field_values {a = 0} {d = 100[.].*}].*$return_to_parent_prompt" { - pass "explore cu.sa\[0\]" - gdb_test_multiple "\0" "end cu.sa\[0\] exploration" { - -re "[array_description {cu.sa} $SS]$array_index_prompt" { - pass "end cu.sa\[0\] exploration" - } - } - } - } - gdb_test_multiple "\0" "end cu.sa exploration" { - -re ".*$enter_field_number_prompt" { - pass "end cu.sa exploration" - gdb_test_multiple "\0" "end cu exploration" { - -re "$gdb_prompt" { - pass "end cu exploration" - } - } - } - } - } - } + pass "explore cu" + gdb_test_multiple "1" "explore cu.sa" { + -re ".*[array_description {cu.sa} $SS].*$array_index_prompt" { + pass "explore cu.sa" + gdb_test_multiple "0" "explore cu.sa\[0\]" { + -re "[compound_description {\(cu.sa\)\[0\]} {struct/class} {struct SimpleStruct}].*[field_values {a = 0} {d = 100[.].*}].*$return_to_parent_prompt" { + pass "explore cu.sa\[0\]" + gdb_test_multiple "\0" "end cu.sa\[0\] exploration" { + -re "[array_description {cu.sa} $SS]$array_index_prompt" { + pass "end cu.sa\[0\] exploration" + } + } + } + } + gdb_test_multiple "\0" "end cu.sa exploration" { + -re ".*$enter_field_number_prompt" { + pass "end cu.sa exploration" + gdb_test_multiple "\0" "end cu exploration" { + -re "$gdb_prompt" { + pass "end cu exploration" + } + } + } + } + } + } } } @@ -262,186 +262,186 @@ gdb_test "explore int" ".*[scalar_type_decsription {int}].*" gdb_test_multiple "explore struct SimpleStruct" "" { -re ".*[compound_type_description $SS {struct/class}].*$SS_fields_types.*" { - pass "explore struct SimpleStruct" - gdb_test_multiple "0" "explore type struct SimpleStruct feild 0" { - -re ".*[child_scalar_type_description {field 'a' of 'struct SimpleStruct'} {int}].*" { - pass "explore type struct SimpleStruct feild 0" - gdb_test_multiple "\0" "return to struct SimpleStruct from field 0" { - -re ".*[compound_type_description $SS {struct/class}].*$SS_fields_types.*" { - pass "return to struct SimpleStruct from field 0" - } - } - } - } - gdb_test_multiple "1" "explore type struct SimpleStruct feild 1" { - -re ".*[child_scalar_type_description {field 'd' of 'struct SimpleStruct'} {double}].*" { - pass "explore type struct SimpleStruct feild 1" - gdb_test_multiple "\0" "return to struct SimpleStruct from field 1" { - -re ".*[compound_type_description $SS {struct/class}].*$SS_fields_types.*" { - pass "return to struct SimpleStruct from field 1" - } - } - } - } - gdb_test_multiple "\0" "return to GDB prompt from struct SimpleStruct" { - -re "$gdb_prompt" { - pass "return to GDB prompt from struct SimpleStruct" - } - } + pass "explore struct SimpleStruct" + gdb_test_multiple "0" "explore type struct SimpleStruct field 0" { + -re ".*[child_scalar_type_description {field 'a' of 'struct SimpleStruct'} {int}].*" { + pass "explore type struct SimpleStruct field 0" + gdb_test_multiple "\0" "return to struct SimpleStruct from field 0" { + -re ".*[compound_type_description $SS {struct/class}].*$SS_fields_types.*" { + pass "return to struct SimpleStruct from field 0" + } + } + } + } + gdb_test_multiple "1" "explore type struct SimpleStruct field 1" { + -re ".*[child_scalar_type_description {field 'd' of 'struct SimpleStruct'} {double}].*" { + pass "explore type struct SimpleStruct field 1" + gdb_test_multiple "\0" "return to struct SimpleStruct from field 1" { + -re ".*[compound_type_description $SS {struct/class}].*$SS_fields_types.*" { + pass "return to struct SimpleStruct from field 1" + } + } + } + } + gdb_test_multiple "\0" "return to GDB prompt from struct SimpleStruct" { + -re "$gdb_prompt" { + pass "return to GDB prompt from struct SimpleStruct" + } + } } } gdb_test_multiple "explore union SimpleUnion" "" { -re ".*[compound_type_description $SU {union}].*$SU_fields_types.*" { pass "explore union SimpleUnion" - gdb_test_multiple "0" "explore type union SimpleUnion feild 0" { - -re ".*[child_scalar_type_description {field 'i' of 'union SimpleUnion'} {int}].*" { - pass "explore type union SimpleUnion feild 0" - gdb_test_multiple "\0" "return to union SimpleUnion from field 0" { - -re ".*[compound_type_description $SU {union}].*$SU_fields_types.*" { - pass "return to union SimpleUnion from field 0" - } - } - } - } - gdb_test_multiple "1" "explore type union SimpleUnion feild 1" { - -re ".*[child_scalar_type_description {field 'c' of 'union SimpleUnion'} {char}].*" { - pass "explore type union SimpleUnion feild 1" - gdb_test_multiple "\0" "return to union SimpleUnion from field 1" { - -re ".*[compound_type_description $SU {union}].*$SU_fields_types.*" { - pass "return to union SimpleUnion from field 1" - } - } - } - } - gdb_test_multiple "2" "explore type union SimpleUnion feild 2" { - -re ".*[child_scalar_type_description {field 'f' of 'union SimpleUnion'} {float}].*" { - pass "explore type union SimpleUnion feild 2" - gdb_test_multiple "\0" "return to union SimpleUnion from field 2" { - -re ".*[compound_type_description $SU {union}].*$SU_fields_types.*" { - pass "return to union SimpleUnion from field 2" - } - } - } - } - gdb_test_multiple "3" "explore type union SimpleUnion feild 3" { - -re ".*[child_scalar_type_description {field 'd' of 'union SimpleUnion'} {double}].*" { - pass "explore type union SimpleUnion feild 3" - gdb_test_multiple "\0" "return to union SimpleUnion from field 3" { - -re ".*[compound_type_description $SU {union}].*$SU_fields_types.*" { - pass "return to union SimpleUnion from field 3" - } - } - } - } - gdb_test_multiple "\0" "return to GDB prompt from union SimpleUnion" { - -re "$gdb_prompt" { - pass "return to GDB prompt from union SimpleUnion" - } - } + gdb_test_multiple "0" "explore type union SimpleUnion field 0" { + -re ".*[child_scalar_type_description {field 'i' of 'union SimpleUnion'} {int}].*" { + pass "explore type union SimpleUnion field 0" + gdb_test_multiple "\0" "return to union SimpleUnion from field 0" { + -re ".*[compound_type_description $SU {union}].*$SU_fields_types.*" { + pass "return to union SimpleUnion from field 0" + } + } + } + } + gdb_test_multiple "1" "explore type union SimpleUnion field 1" { + -re ".*[child_scalar_type_description {field 'c' of 'union SimpleUnion'} {char}].*" { + pass "explore type union SimpleUnion field 1" + gdb_test_multiple "\0" "return to union SimpleUnion from field 1" { + -re ".*[compound_type_description $SU {union}].*$SU_fields_types.*" { + pass "return to union SimpleUnion from field 1" + } + } + } + } + gdb_test_multiple "2" "explore type union SimpleUnion field 2" { + -re ".*[child_scalar_type_description {field 'f' of 'union SimpleUnion'} {float}].*" { + pass "explore type union SimpleUnion field 2" + gdb_test_multiple "\0" "return to union SimpleUnion from field 2" { + -re ".*[compound_type_description $SU {union}].*$SU_fields_types.*" { + pass "return to union SimpleUnion from field 2" + } + } + } + } + gdb_test_multiple "3" "explore type union SimpleUnion field 3" { + -re ".*[child_scalar_type_description {field 'd' of 'union SimpleUnion'} {double}].*" { + pass "explore type union SimpleUnion field 3" + gdb_test_multiple "\0" "return to union SimpleUnion from field 3" { + -re ".*[compound_type_description $SU {union}].*$SU_fields_types.*" { + pass "return to union SimpleUnion from field 3" + } + } + } + } + gdb_test_multiple "\0" "return to GDB prompt from union SimpleUnion" { + -re "$gdb_prompt" { + pass "return to GDB prompt from union SimpleUnion" + } + } } } gdb_test_multiple "explore SS" "" { -re ".*[typedef_type_description {SS} $SS].*[compound_type_description {SS} {struct/class}].*$SS_fields_types.*" { - pass "explore SS" - gdb_test_multiple "0" "explore type SS feild 0" { - -re ".*[child_scalar_type_description {field 'a' of 'SS'} {int}].*" { - pass "explore type SS feild 0" - gdb_test_multiple "\0" "return to SS from field 0" { - -re ".*[compound_type_description {SS} {struct/class}].*$SS_fields_types.*" { - pass "return to SS from field 0" - } - } - } - } - gdb_test_multiple "1" "explore type SS feild 1" { - -re ".*[child_scalar_type_description {field 'd' of 'SS'} {double}].*" { - pass "explore type SS feild 1" - gdb_test_multiple "\0" "return to struct SimpleStruct from field 1" { - -re ".*[compound_type_description {SS} {struct/class}].*$SS_fields_types.*" { - pass "return to SS field 1" - } - } - } - } - gdb_test_multiple "\0" "return to GDB prompt from SS" { - -re "$gdb_prompt" { - pass "return to GDB prompt from SS" - } - } + pass "explore SS" + gdb_test_multiple "0" "explore type SS field 0" { + -re ".*[child_scalar_type_description {field 'a' of 'SS'} {int}].*" { + pass "explore type SS field 0" + gdb_test_multiple "\0" "return to SS from field 0" { + -re ".*[compound_type_description {SS} {struct/class}].*$SS_fields_types.*" { + pass "return to SS from field 0" + } + } + } + } + gdb_test_multiple "1" "explore type SS field 1" { + -re ".*[child_scalar_type_description {field 'd' of 'SS'} {double}].*" { + pass "explore type SS field 1" + gdb_test_multiple "\0" "return to struct SimpleStruct from field 1" { + -re ".*[compound_type_description {SS} {struct/class}].*$SS_fields_types.*" { + pass "return to SS field 1" + } + } + } + } + gdb_test_multiple "\0" "return to GDB prompt from SS" { + -re "$gdb_prompt" { + pass "return to GDB prompt from SS" + } + } } } gdb_test_multiple "explore type struct ComplexStruct" "" { -re ".*[compound_type_description $CS {struct/class}].*$CS_fields_types.*" { - pass "explore type struct ComplexStruct" - gdb_test_multiple "0" "explore type struct ComplexStruct field 0" { - -re ".*[child_compound_type_description $CS_field_0 $SS {struct/class}].*$SS_fields_types.*" { - pass "explore type struct ComplexStruct field 0" - gdb_test_multiple "\0" "return to ComplexStruct from field 0" { - -re ".*[compound_type_description $CS {struct/class}].*$CS_fields_types.*" { - pass "return to ComplexStruct from field 0" - } - } - } - } - gdb_test_multiple "1" "explore type struct ComplexStruct field 1" { - -re ".*[child_compound_type_description $CS_field_1 $SU {union}].*$SU_fields_types.*" { - pass "explore type struct ComplexStruct field 1" - gdb_test_multiple "\0" "return to ComplexStruct from field 1" { - -re ".*[compound_type_description $CS {struct/class}].*$CS_fields_types.*" { - pass "return to ComplexStruct from field 1" - } - } - } - } - gdb_test_multiple "2" "explore type struct ComplexStruct field 2" { - -re ".*[child_array_type_description $CS_field_2 {SS}].*" { - pass "explore type struct ComplexStruct field 2" - gdb_test_multiple "\0" "return to ComplexStruct from field 2" { - -re ".*[compound_type_description $CS {struct/class}].*$CS_fields_types.*" { - pass "return to ComplexStruct from field 2" - } - } - } - } - gdb_test_multiple "\0" "return to GDB prompt from ComplexStruct type exploration" { - -re "$gdb_prompt" { - pass "return to GDB prompt from ComplexStruct type exploration" - } - } + pass "explore type struct ComplexStruct" + gdb_test_multiple "0" "explore type struct ComplexStruct field 0" { + -re ".*[child_compound_type_description $CS_field_0 $SS {struct/class}].*$SS_fields_types.*" { + pass "explore type struct ComplexStruct field 0" + gdb_test_multiple "\0" "return to ComplexStruct from field 0" { + -re ".*[compound_type_description $CS {struct/class}].*$CS_fields_types.*" { + pass "return to ComplexStruct from field 0" + } + } + } + } + gdb_test_multiple "1" "explore type struct ComplexStruct field 1" { + -re ".*[child_compound_type_description $CS_field_1 $SU {union}].*$SU_fields_types.*" { + pass "explore type struct ComplexStruct field 1" + gdb_test_multiple "\0" "return to ComplexStruct from field 1" { + -re ".*[compound_type_description $CS {struct/class}].*$CS_fields_types.*" { + pass "return to ComplexStruct from field 1" + } + } + } + } + gdb_test_multiple "2" "explore type struct ComplexStruct field 2" { + -re ".*[child_array_type_description $CS_field_2 {SS}].*" { + pass "explore type struct ComplexStruct field 2" + gdb_test_multiple "\0" "return to ComplexStruct from field 2" { + -re ".*[compound_type_description $CS {struct/class}].*$CS_fields_types.*" { + pass "return to ComplexStruct from field 2" + } + } + } + } + gdb_test_multiple "\0" "return to GDB prompt from ComplexStruct type exploration" { + -re "$gdb_prompt" { + pass "return to GDB prompt from ComplexStruct type exploration" + } + } } } gdb_test_multiple "explore type union ComplexUnion" "" { -re ".*[compound_type_description $CU {union}].*$CU_fields_types.*" { - pass "explore type union ComplexUnion" - gdb_test_multiple "0" "explore type union ComplexStruct field 0" { - -re ".*[child_compound_type_description $CU_field_0 $SS {struct/class}].*$SS_fields_types.*" { - pass "explore type union ComplexUnion field 0" - gdb_test_multiple "\0" "return to ComplexUnion from field 0" { - -re ".*[compound_type_description $CU {union}].*$CU_fields_types.*" { - pass "return to ComplexUnion from field 0" - } - } - } - } - gdb_test_multiple "1" "explore type union ComplexUnion field 1" { - -re ".*[child_array_type_description $CU_field_1 $SS].*" { - pass "explore type union ComplexUnion field 1" - gdb_test_multiple "\0" "return to ComplexUnion array" { - -re ".*[compound_type_description $CU {union}].*$CU_fields_types.*" { - pass "return to ComplexUnion from field 1" - } - } - } - } - gdb_test_multiple "\0" "return to GDB prompt from ComplexUnion type exploration" { - -re "$gdb_prompt" { - pass "return to GDB prompt from ComplexUnion type exploration" - } - } + pass "explore type union ComplexUnion" + gdb_test_multiple "0" "explore type union ComplexStruct field 0" { + -re ".*[child_compound_type_description $CU_field_0 $SS {struct/class}].*$SS_fields_types.*" { + pass "explore type union ComplexUnion field 0" + gdb_test_multiple "\0" "return to ComplexUnion from field 0" { + -re ".*[compound_type_description $CU {union}].*$CU_fields_types.*" { + pass "return to ComplexUnion from field 0" + } + } + } + } + gdb_test_multiple "1" "explore type union ComplexUnion field 1" { + -re ".*[child_array_type_description $CU_field_1 $SS].*" { + pass "explore type union ComplexUnion field 1" + gdb_test_multiple "\0" "return to ComplexUnion array" { + -re ".*[compound_type_description $CU {union}].*$CU_fields_types.*" { + pass "return to ComplexUnion from field 1" + } + } + } + } + gdb_test_multiple "\0" "return to GDB prompt from ComplexUnion type exploration" { + -re "$gdb_prompt" { + pass "return to GDB prompt from ComplexUnion type exploration" + } + } } } diff --git a/gdb/testsuite/gdb.python/py-finish-breakpoint-deletion.py b/gdb/testsuite/gdb.python/py-finish-breakpoint-deletion.py index 8d8ca53..d8235e3 100644 --- a/gdb/testsuite/gdb.python/py-finish-breakpoint-deletion.py +++ b/gdb/testsuite/gdb.python/py-finish-breakpoint-deletion.py @@ -14,6 +14,9 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. +import gdb + + class MyFinishBreakpoint(gdb.FinishBreakpoint): def stop(self): print("stopped at MyFinishBreakpoint") diff --git a/gdb/testsuite/gdb.python/py-finish-breakpoint.exp b/gdb/testsuite/gdb.python/py-finish-breakpoint.exp index c7d31f0..bec22ee 100644 --- a/gdb/testsuite/gdb.python/py-finish-breakpoint.exp +++ b/gdb/testsuite/gdb.python/py-finish-breakpoint.exp @@ -112,7 +112,7 @@ with_test_prefix "return to inlined function" { } # -# Test FinishBreakpoint with no debug symbol +# Test FinishBreakpoint with no debug symbol # with_test_prefix "no debug symbol" { @@ -140,7 +140,7 @@ with_test_prefix "no debug symbol" { } # -# Test FinishBreakpoint in function returned by longjmp +# Test FinishBreakpoint in function returned by longjmp # with_test_prefix "function returned by longjump" { @@ -166,7 +166,7 @@ with_test_prefix "function returned by longjump" { } # -# Test FinishBreakpoint in BP condition evaluation +# Test FinishBreakpoint in BP condition evaluation # (finish in dummy frame) # @@ -194,7 +194,7 @@ with_test_prefix "finish in dummy frame" { } # -# Test FinishBreakpoint in BP condition evaluation +# Test FinishBreakpoint in BP condition evaluation # (finish in normal frame) # diff --git a/gdb/testsuite/gdb.python/py-finish-breakpoint.py b/gdb/testsuite/gdb.python/py-finish-breakpoint.py index 413489f..dd2e158 100644 --- a/gdb/testsuite/gdb.python/py-finish-breakpoint.py +++ b/gdb/testsuite/gdb.python/py-finish-breakpoint.py @@ -17,6 +17,9 @@ # Breakpoints. +import gdb + + class MyFinishBreakpoint(gdb.FinishBreakpoint): def __init__(self, val, frame): gdb.FinishBreakpoint.__init__(self, frame) diff --git a/gdb/testsuite/gdb.python/py-finish-breakpoint2.cc b/gdb/testsuite/gdb.python/py-finish-breakpoint2.cc index af8801f..d190143 100644 --- a/gdb/testsuite/gdb.python/py-finish-breakpoint2.cc +++ b/gdb/testsuite/gdb.python/py-finish-breakpoint2.cc @@ -42,7 +42,7 @@ main (void) } catch (const int *e) { - std::cerr << "Exception #" << *e << std::endl; + std::cerr << "Exception #" << *e << std::endl; } i += 1; /* Break after exception 1. */ @@ -52,7 +52,7 @@ main (void) } catch (const int *e) { - std::cerr << "Exception #" << *e << std::endl; + std::cerr << "Exception #" << *e << std::endl; } i += 1; /* Break after exception 2. */ diff --git a/gdb/testsuite/gdb.python/py-finish-breakpoint2.exp b/gdb/testsuite/gdb.python/py-finish-breakpoint2.exp index 922426f..fe3ef4e 100644 --- a/gdb/testsuite/gdb.python/py-finish-breakpoint2.exp +++ b/gdb/testsuite/gdb.python/py-finish-breakpoint2.exp @@ -41,8 +41,8 @@ gdb_breakpoint [gdb_get_line_number "Break before exception"] gdb_breakpoint [gdb_get_line_number "Break after exception 2"] gdb_test "source $pyfile" ".*Python script imported.*" \ - "import python scripts" - + "import python scripts" + gdb_breakpoint "throw_exception_1" # diff --git a/gdb/testsuite/gdb.python/py-finish-breakpoint2.py b/gdb/testsuite/gdb.python/py-finish-breakpoint2.py index ae75e51..01d220c 100644 --- a/gdb/testsuite/gdb.python/py-finish-breakpoint2.py +++ b/gdb/testsuite/gdb.python/py-finish-breakpoint2.py @@ -16,6 +16,8 @@ # This file is part of the GDB testsuite. It tests python Finish # Breakpoints. +import gdb + class ExceptionFinishBreakpoint(gdb.FinishBreakpoint): def __init__(self, frame): diff --git a/gdb/testsuite/gdb.python/py-format-address.exp b/gdb/testsuite/gdb.python/py-format-address.exp index 173297c..2946314 100644 --- a/gdb/testsuite/gdb.python/py-format-address.exp +++ b/gdb/testsuite/gdb.python/py-format-address.exp @@ -27,12 +27,14 @@ foreach func_name { foo bar } { } } -set binary_foo [standard_output_file "${testfile}-foo"] -set binary_bar [standard_output_file "${testfile}-bar"] +set testfile_foo $testfile-foo +set testfile_bar $testfile-bar +set binary_foo [standard_output_file $testfile_foo] +set binary_bar [standard_output_file $testfile_bar] -clean_restart $binary_foo +clean_restart $testfile_foo -if ![runto_main] { +if {![runto_main]} { return -1 } @@ -51,7 +53,7 @@ gdb_test_multiple "info break 1" "" { } } if { $next_addr == "UNKNOWN" || $next_addr == $main_addr } { - set next_addr [format 0x%x [expr $main_addr + 1]] + set next_addr [format 0x%x [expr {$main_addr + 1}]] } verbose -log "main_addr: $main_addr" diff --git a/gdb/testsuite/gdb.python/py-format-string.exp b/gdb/testsuite/gdb.python/py-format-string.exp index 114a606..53fa553 100644 --- a/gdb/testsuite/gdb.python/py-format-string.exp +++ b/gdb/testsuite/gdb.python/py-format-string.exp @@ -47,7 +47,8 @@ proc build_inferior {exefile lang} { proc prepare_gdb {exefile} { global srcdir subdir srcfile testfile hex - clean_restart $exefile + clean_restart + gdb_load $exefile if {![runto_main]} { return @@ -109,7 +110,7 @@ proc get_cut_big_string { max } { return "\"${whole_big_string}\"" } - set cut_string [string range $whole_big_string 0 [expr $max - 1]] + set cut_string [string range $whole_big_string 0 [expr {$max - 1}]] return "\"${cut_string}\"..." } @@ -775,7 +776,7 @@ proc test_max_string_one { setting unlimited } { check_format_string "a_binary_string" $opts check_format_string "a_binary_string_array" $opts check_format_string "a_big_string" $opts \ - [get_cut_big_string 1000] + [get_cut_big_string 1000] if { $setting == "elements"} { check_format_string "an_array" $opts check_format_string "an_array_with_repetition" $opts @@ -783,8 +784,8 @@ proc test_max_string_one { setting unlimited } { check_format_string "a_symbol_pointer" $opts if { $current_lang == "c++" } { - check_format_string "a_point_t_ref" $opts - check_format_string "a_base_ref" $opts + check_format_string "a_point_t_ref" $opts + check_format_string "a_base_ref" $opts } } } @@ -928,12 +929,12 @@ proc_with_prefix test_repeat_threshold {} { check_format_string "a_big_string" $opts check_format_string "an_array" $opts check_format_string "an_array_with_repetition" $opts \ - "\\{1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5\\}" + "\\{1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 5, 5, 5\\}" check_format_string "a_symbol_pointer" $opts if { $current_lang == "c++" } { - check_format_string "a_point_t_ref" $opts - check_format_string "a_base_ref" $opts + check_format_string "a_point_t_ref" $opts + check_format_string "a_base_ref" $opts } } } @@ -1202,7 +1203,9 @@ with_test_prefix "format_string" { set current_lang "c" prepare_gdb "${binfile}" test_all_common - test_styling + if { ![is_remote host] } { + test_styling + } } } } diff --git a/gdb/testsuite/gdb.python/py-frame-args.exp b/gdb/testsuite/gdb.python/py-frame-args.exp index 1dbd30e..12f1651 100644 --- a/gdb/testsuite/gdb.python/py-frame-args.exp +++ b/gdb/testsuite/gdb.python/py-frame-args.exp @@ -21,7 +21,7 @@ if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } { return -1 } -if ![runto_main] { +if {![runto_main]} { return -1 } diff --git a/gdb/testsuite/gdb.python/py-frame-args.py b/gdb/testsuite/gdb.python/py-frame-args.py index 45476b1..b72b453 100644 --- a/gdb/testsuite/gdb.python/py-frame-args.py +++ b/gdb/testsuite/gdb.python/py-frame-args.py @@ -23,7 +23,6 @@ class pp_s(object): self.val = val def to_string(self): - m = self.val["m"] return "m=<" + str(self.val["m"]) + ">" diff --git a/gdb/testsuite/gdb.python/py-frame.exp b/gdb/testsuite/gdb.python/py-frame.exp index 5668807..c1e3e33 100644 --- a/gdb/testsuite/gdb.python/py-frame.exp +++ b/gdb/testsuite/gdb.python/py-frame.exp @@ -188,6 +188,21 @@ gdb_test "python print(gdb.selected_frame().read_register(list()))" \ ".*Invalid type for register.*" \ "test Frame.read_register with list" +gdb_test_multiline "setup a bad object" \ + "python" "" \ + "class bad_type:" "" \ + " def __init__ (self):" "" \ + " pass" "" \ + " @property" "" \ + " def __class__(self):" "" \ + " raise RuntimeError('error from __class in bad_type')" "" \ + "bad_object = bad_type()" "" \ + "end" "" + +gdb_test "python print(gdb.selected_frame().read_register(bad_object))" \ + ".*Invalid type for register.*" \ + "test Frame.read_register with bad_type object" + # Compile again without debug info. gdb_exit if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} {}] } { diff --git a/gdb/testsuite/gdb.python/py-framefilter-addr.exp b/gdb/testsuite/gdb.python/py-framefilter-addr.exp index 14eebc2..27c1de3 100644 --- a/gdb/testsuite/gdb.python/py-framefilter-addr.exp +++ b/gdb/testsuite/gdb.python/py-framefilter-addr.exp @@ -27,7 +27,7 @@ if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } { return -1 } -if ![runto_main] { +if {![runto_main]} { return -1 } diff --git a/gdb/testsuite/gdb.python/py-framefilter-addr.py b/gdb/testsuite/gdb.python/py-framefilter-addr.py index 513bf6f..336571a 100644 --- a/gdb/testsuite/gdb.python/py-framefilter-addr.py +++ b/gdb/testsuite/gdb.python/py-framefilter-addr.py @@ -13,7 +13,6 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -import copy import itertools import gdb diff --git a/gdb/testsuite/gdb.python/py-framefilter-gdb.py b/gdb/testsuite/gdb.python/py-framefilter-gdb.py index a725dce..969371c 100644 --- a/gdb/testsuite/gdb.python/py-framefilter-gdb.py +++ b/gdb/testsuite/gdb.python/py-framefilter-gdb.py @@ -13,12 +13,9 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -import itertools - # This file is part of the GDB testsuite. It tests Python-based # frame-filters. import gdb -from gdb.FrameDecorator import FrameDecorator class FrameObjFile: diff --git a/gdb/testsuite/gdb.python/py-framefilter-invalidarg-gdb.py b/gdb/testsuite/gdb.python/py-framefilter-invalidarg-gdb.py index 51922fc..96c97aa 100644 --- a/gdb/testsuite/gdb.python/py-framefilter-invalidarg-gdb.py +++ b/gdb/testsuite/gdb.python/py-framefilter-invalidarg-gdb.py @@ -13,12 +13,10 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -import itertools # This file is part of the GDB testsuite. It tests Python-based # frame-filters. import gdb -from gdb.FrameDecorator import FrameDecorator class FrameObjFile: diff --git a/gdb/testsuite/gdb.python/py-framefilter-invalidarg.py b/gdb/testsuite/gdb.python/py-framefilter-invalidarg.py index b262968..a8e52e0 100644 --- a/gdb/testsuite/gdb.python/py-framefilter-invalidarg.py +++ b/gdb/testsuite/gdb.python/py-framefilter-invalidarg.py @@ -13,7 +13,6 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -import copy import itertools # This file is part of the GDB testsuite. It tests Python-based diff --git a/gdb/testsuite/gdb.python/py-framefilter-mi.exp b/gdb/testsuite/gdb.python/py-framefilter-mi.exp index de04236..03e5f90 100644 --- a/gdb/testsuite/gdb.python/py-framefilter-mi.exp +++ b/gdb/testsuite/gdb.python/py-framefilter-mi.exp @@ -28,7 +28,7 @@ if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {deb return -1 } -if {[mi_clean_restart $binfile]} { +if {[mi_clean_restart $::testfile]} { return } diff --git a/gdb/testsuite/gdb.python/py-framefilter.exp b/gdb/testsuite/gdb.python/py-framefilter.exp index 7cc8b01..5a7a72b 100644 --- a/gdb/testsuite/gdb.python/py-framefilter.exp +++ b/gdb/testsuite/gdb.python/py-framefilter.exp @@ -112,8 +112,8 @@ gdb_test "show frame-filter priority global Elider" \ gdb_test_no_output "set frame-filter priority global Elider 1000" \ "set frame-filter priotiy global Elider 1000" gdb_test "show frame-filter priority global Elider" \ - "Priority of filter 'Elider' in list 'global' is: 1000" \ - "show frame-filter priority global Elider after setting" + "Priority of filter 'Elider' in list 'global' is: 1000" \ + "show frame-filter priority global Elider after setting" gdb_test "info frame-filter" \ ".*1000.*Yes.*Elider.*100.*Yes.*Reverse.*10.*.*No.*Object.*1.*" \ "info frame filter after setting priority" diff --git a/gdb/testsuite/gdb.python/py-framefilter.py b/gdb/testsuite/gdb.python/py-framefilter.py index 5c3790d..1fc8025 100644 --- a/gdb/testsuite/gdb.python/py-framefilter.py +++ b/gdb/testsuite/gdb.python/py-framefilter.py @@ -13,7 +13,6 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -import copy import itertools # This file is part of the GDB testsuite. It tests Python-based diff --git a/gdb/testsuite/gdb.python/py-inferior-leak.exp b/gdb/testsuite/gdb.python/py-inferior-leak.exp index 6710f59..15216ee 100644 --- a/gdb/testsuite/gdb.python/py-inferior-leak.exp +++ b/gdb/testsuite/gdb.python/py-inferior-leak.exp @@ -24,15 +24,5 @@ standard_testfile clean_restart -# Skip this test if the tracemalloc module is not available. -if { ![gdb_py_module_available "tracemalloc"] } { - unsupported "tracemalloc module not available" - return -} - -set pyfile [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py] - -# Source the Python script, this runs the test (which is written -# completely in Python), and either prints PASS, or throws an -# exception. -gdb_test "source ${pyfile}" "PASS" "source python script" +gdb_py_run_memory_leak_test ${srcdir}/${subdir}/${testfile}.py \ + "gdb.Inferior object deallocates correctly" diff --git a/gdb/testsuite/gdb.python/py-inferior-leak.py b/gdb/testsuite/gdb.python/py-inferior-leak.py index 97837dc..375e909e 100644 --- a/gdb/testsuite/gdb.python/py-inferior-leak.py +++ b/gdb/testsuite/gdb.python/py-inferior-leak.py @@ -14,99 +14,40 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. import re -import tracemalloc +import sys import gdb -# A global variable in which we store a reference to the gdb.Inferior -# object sent to us in the new_inferior event. -inf = None +# Avoid generating +# src/gdb/testsuite/gdb.python/__pycache__/gdb_leak_detector.cpython-<n>.pyc. +sys.dont_write_bytecode = True -# Register the new_inferior event handler. -def new_inferior_handler(event): - global inf - inf = event.inferior +import gdb_leak_detector # noqa: E402 -gdb.events.new_inferior.connect(new_inferior_handler) +class inferior_leak_detector(gdb_leak_detector.gdb_leak_detector): + def __init__(self): + super().__init__(__file__) + self.inferior = None + self.__handler = lambda event: setattr(self, "inferior", event.inferior) + gdb.events.new_inferior.connect(self.__handler) -# A global filters list, we only care about memory allocations -# originating from this script. -filters = [tracemalloc.Filter(True, "*py-inferior-leak.py")] + def __del__(self): + gdb.events.new_inferior.disconnect(self.__handler) + def allocate(self): + output = gdb.execute("add-inferior", False, True) + m = re.search(r"Added inferior (\d+)", output) + if m: + num = int(m.group(1)) + else: + raise RuntimeError("no match") -# Add a new inferior, and return the number of the new inferior. -def add_inferior(): - output = gdb.execute("add-inferior", False, True) - m = re.search(r"Added inferior (\d+)", output) - if m: - num = int(m.group(1)) - else: - raise RuntimeError("no match") - return num + gdb.execute("remove-inferiors %s" % num) + def deallocate(self): + self.inferior = None -# Run the test. When CLEAR is True we clear the global INF variable -# before comparing the before and after memory allocation traces. -# When CLEAR is False we leave INF set to reference the gdb.Inferior -# object, thus preventing the gdb.Inferior from being deallocated. -def test(clear): - global filters, inf - # Start tracing, and take a snapshot of the current allocations. - tracemalloc.start() - snapshot1 = tracemalloc.take_snapshot() - - # Create an inferior, this triggers the new_inferior event, which - # in turn holds a reference to the new gdb.Inferior object in the - # global INF variable. - num = add_inferior() - gdb.execute("remove-inferiors %s" % num) - - # Possibly clear the global INF variable. - if clear: - inf = None - - # Now grab a second snapshot of memory allocations, and stop - # tracing memory allocations. - snapshot2 = tracemalloc.take_snapshot() - tracemalloc.stop() - - # Filter the snapshots; we only care about allocations originating - # from this file. - snapshot1 = snapshot1.filter_traces(filters) - snapshot2 = snapshot2.filter_traces(filters) - - # Compare the snapshots, this leaves only things that were - # allocated, but not deallocated since the first snapshot. - stats = snapshot2.compare_to(snapshot1, "traceback") - - # Total up all the deallocated things. - total = 0 - for stat in stats: - total += stat.size_diff - return total - - -# The first time we run this some global state will be allocated which -# shows up as memory that is allocated, but not released. So, run the -# test once and discard the result. -test(True) - -# Now run the test twice, the first time we clear our global reference -# to the gdb.Inferior object, which should allow Python to deallocate -# the object. The second time we hold onto the global reference, -# preventing Python from performing the deallocation. -bytes_with_clear = test(True) -bytes_without_clear = test(False) - -# The bug that used to exist in GDB was that even when we released the -# global reference the gdb.Inferior object would not be deallocated. -if bytes_with_clear > 0: - raise gdb.GdbError("memory leak when gdb.Inferior should be released") -if bytes_without_clear == 0: - raise gdb.GdbError("gdb.Inferior object is no longer allocated") - -# Print a PASS message that the test script can see. -print("PASS") +inferior_leak_detector().run() diff --git a/gdb/testsuite/gdb.python/py-inferior.exp b/gdb/testsuite/gdb.python/py-inferior.exp index 62af1a4..58632f0 100644 --- a/gdb/testsuite/gdb.python/py-inferior.exp +++ b/gdb/testsuite/gdb.python/py-inferior.exp @@ -318,7 +318,7 @@ with_test_prefix "large range" { # For native targets, test a pattern straddling a chunk boundary. -if [isnative] { +if {[isnative]} { with_test_prefix "straddling" { gdb_test_no_output "set *(int32_t*) &search_buf\[${CHUNK_SIZE}-1\] = 0xfdb97531" gdb_test_no_output "py pattern = pack('${python_pack_char}I', 0xfdb97531)" diff --git a/gdb/testsuite/gdb.python/py-label-symbol-value.exp b/gdb/testsuite/gdb.python/py-label-symbol-value.exp index ca534d4..07bc870 100644 --- a/gdb/testsuite/gdb.python/py-label-symbol-value.exp +++ b/gdb/testsuite/gdb.python/py-label-symbol-value.exp @@ -24,7 +24,7 @@ if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } { return -1 } -if ![runto_main] { +if {![runto_main]} { return -1 } diff --git a/gdb/testsuite/gdb.python/py-lazy-string.exp b/gdb/testsuite/gdb.python/py-lazy-string.exp index 7e7272e..a6fdd77 100644 --- a/gdb/testsuite/gdb.python/py-lazy-string.exp +++ b/gdb/testsuite/gdb.python/py-lazy-string.exp @@ -26,7 +26,7 @@ if {[prepare_for_testing "failed to prepare" $testfile $srcfile {debug c++}]} { return -1 } -if ![runto_main ] { +if {![runto_main ]} { return -1 } diff --git a/gdb/testsuite/gdb.python/py-linetable-empty.exp b/gdb/testsuite/gdb.python/py-linetable-empty.exp index 1e737e1..f742d70 100644 --- a/gdb/testsuite/gdb.python/py-linetable-empty.exp +++ b/gdb/testsuite/gdb.python/py-linetable-empty.exp @@ -27,11 +27,11 @@ Dwarf::assemble $asm_file { cu {} { compile_unit { - {language @DW_LANG_C} - {name py-linetable-empty.c} + DW_AT_language @DW_LANG_C + DW_AT_name py-linetable-empty.c } { subprogram { - {MACRO_AT_func {main}} + MACRO_AT_func {main} } } } @@ -42,7 +42,7 @@ if { [prepare_for_testing "failed to prepare" ${testfile} \ return -1 } -if ![runto_main] { +if {![runto_main]} { return -1 } diff --git a/gdb/testsuite/gdb.python/py-linetable.exp b/gdb/testsuite/gdb.python/py-linetable.exp index d27d16e..453ee7a 100644 --- a/gdb/testsuite/gdb.python/py-linetable.exp +++ b/gdb/testsuite/gdb.python/py-linetable.exp @@ -18,7 +18,7 @@ require allow_python_tests set opts {} standard_testfile .S -if [info exists COMPILE] { +if {[info exists COMPILE]} { # make check RUNTESTFLAGS="gdb.python/py-linetable.exp COMPILE=1" standard_testfile lappend opts debug optimize=-O2 @@ -30,7 +30,7 @@ if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} $opts] } { return -1 } -if ![runto_main] { +if {![runto_main]} { return -1 } diff --git a/gdb/testsuite/gdb.python/py-lookup-type.exp b/gdb/testsuite/gdb.python/py-lookup-type.exp index 8673d56..ef04e21 100644 --- a/gdb/testsuite/gdb.python/py-lookup-type.exp +++ b/gdb/testsuite/gdb.python/py-lookup-type.exp @@ -30,8 +30,8 @@ clean_restart proc test_lookup_type { lang type_name } { gdb_test_no_output "set language ${lang}" gdb_test "python print(gdb.lookup_type('${type_name}').name)" \ - "${type_name}" \ - "lookup type ${type_name} using language ${lang}" + "${type_name}" \ + "lookup type ${type_name} using language ${lang}" } test_lookup_type "ada" "character" diff --git a/gdb/testsuite/gdb.python/py-mi-events.exp b/gdb/testsuite/gdb.python/py-mi-events.exp index ecdb74a..a15ba0b 100644 --- a/gdb/testsuite/gdb.python/py-mi-events.exp +++ b/gdb/testsuite/gdb.python/py-mi-events.exp @@ -39,7 +39,7 @@ mi_gdb_test "set auto-load safe-path ${remote_python_file}" \ {.*\^done} \ "set safe-path" -if [is_remote host] { +if {[is_remote host]} { set filename ${testfile} remote_download host ${binfile} ${filename} } else { diff --git a/gdb/testsuite/gdb.python/py-mi-objfile.exp b/gdb/testsuite/gdb.python/py-mi-objfile.exp index 58ecbc5..c1edffe 100644 --- a/gdb/testsuite/gdb.python/py-mi-objfile.exp +++ b/gdb/testsuite/gdb.python/py-mi-objfile.exp @@ -33,7 +33,7 @@ if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {deb # gdb will find it. set remote_python_file [gdb_remote_download host ${srcdir}/${subdir}/${pyfile}] -if {[mi_clean_restart $binfile]} { +if {[mi_clean_restart $::testfile]} { return } @@ -41,7 +41,7 @@ mi_gdb_test "set auto-load safe-path ${remote_python_file}" \ {.*\^done} \ "set safe-path" -if [is_remote host] { +if {[is_remote host]} { set filename ${testfile} remote_download host ${binfile} ${filename} } else { diff --git a/gdb/testsuite/gdb.python/py-mi-var-info-path-expression.exp b/gdb/testsuite/gdb.python/py-mi-var-info-path-expression.exp index 07cd40f..7a9124b 100644 --- a/gdb/testsuite/gdb.python/py-mi-var-info-path-expression.exp +++ b/gdb/testsuite/gdb.python/py-mi-var-info-path-expression.exp @@ -29,7 +29,7 @@ if {[gdb_compile "$srcdir/$subdir/$srcfile" $binfile executable {debug}] != "" } return -1 } -mi_clean_restart $binfile +mi_clean_restart $::testfile set pyfile [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py] mi_gdb_test "source ${pyfile}" \ diff --git a/gdb/testsuite/gdb.python/py-mi-var-info-path-expression.py b/gdb/testsuite/gdb.python/py-mi-var-info-path-expression.py index e7638db..46bbb74 100644 --- a/gdb/testsuite/gdb.python/py-mi-var-info-path-expression.py +++ b/gdb/testsuite/gdb.python/py-mi-var-info-path-expression.py @@ -13,7 +13,6 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -import sys import gdb import gdb.types diff --git a/gdb/testsuite/gdb.python/py-mi.exp b/gdb/testsuite/gdb.python/py-mi.exp index 7f1dffc..28d63c1 100644 --- a/gdb/testsuite/gdb.python/py-mi.exp +++ b/gdb/testsuite/gdb.python/py-mi.exp @@ -26,7 +26,7 @@ if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {deb return -1 } -if {[mi_clean_restart $binfile]} { +if {[mi_clean_restart $::testfile]} { return } @@ -345,7 +345,7 @@ if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}-cxx" \ return -1 } -if {[mi_clean_restart ${binfile}-cxx]} { +if {[mi_clean_restart ${::testfile}-cxx]} { return } diff --git a/gdb/testsuite/gdb.python/py-missing-debug.py b/gdb/testsuite/gdb.python/py-missing-debug.py index c018d4d..18d37ce 100644 --- a/gdb/testsuite/gdb.python/py-missing-debug.py +++ b/gdb/testsuite/gdb.python/py-missing-debug.py @@ -38,7 +38,6 @@ class handler(MissingDebugHandler): self._mode = Mode.RETURN_NONE def __call__(self, objfile): - global handler_call_log handler_call_log.append(self.name) self._call_count += 1 if self._mode == Mode.RETURN_NONE: @@ -95,7 +94,6 @@ class exception_handler(MissingDebugHandler): self.exception_type = None def __call__(self, objfile): - global handler_call_log handler_call_log.append(self.name) assert self.exception_type is not None raise self.exception_type("message") @@ -103,7 +101,6 @@ class exception_handler(MissingDebugHandler): class log_handler(MissingDebugHandler): def __call__(self, objfile): - global handler_call_log handler_call_log.append(self.name) return None diff --git a/gdb/testsuite/gdb.python/py-missing-objfile.exp b/gdb/testsuite/gdb.python/py-missing-objfile.exp index e4a1b3f..2f54f61 100644 --- a/gdb/testsuite/gdb.python/py-missing-objfile.exp +++ b/gdb/testsuite/gdb.python/py-missing-objfile.exp @@ -34,6 +34,11 @@ if { [build_executable "build exec" $binfile $srcfile $opts] == -1} { return } +set expect_build_id_in_core_file_binfile \ + [expect_build_id_in_core_file $binfile] +set expect_build_id_in_core_file_libfile \ + [expect_build_id_in_core_file $libfile] + # The cc-with-gnu-debuglink board will split the debug out into the # .debug directory. This test script relies on having GDB lookup the # objfile and debug via the build-id, which this test sets up. Trying @@ -79,6 +84,16 @@ proc setup_debugdir { dirname files } { # executable (when EXEC_LOADED is true) and/or the library (when LIB_LOADED # is true). proc check_loaded_debug { exec_loaded lib_loaded } { + set re_warn \ + [string_to_regexp \ + "Warning: the current language does not match this frame."] + set cmd "set lang c" + gdb_test_multiple $cmd "" { + -re -wrap "${cmd}(\r\n$re_warn)?" { + pass $gdb_test_name + } + } + if { $exec_loaded } { gdb_test "whatis global_exec_var" "^type = volatile struct exec_type" @@ -124,7 +139,7 @@ proc clean_restart_load_python {} { # For sanity, lets check that we can load the specify the executable # and then load the core-file the easy way. with_test_prefix "initial sanity check" { - clean_restart $binfile + clean_restart $::testfile load_core_file check_loaded_debug true true } @@ -173,6 +188,11 @@ with_test_prefix "no objfiles available" { check_loaded_debug false false } +# The following tests assume that the build-ids of binfile and libfile can be +# found in the core file. +require {expr $expect_build_id_in_core_file_binfile} +require {expr $expect_build_id_in_core_file_libfile} + with_test_prefix "all objfiles available" { # Another sanity check that GDB can find the files via the # debug-file-directory. @@ -226,7 +246,7 @@ with_test_prefix "handler installs lib objfile" { remote_exec host \ "mkdir -p $debugdir_no_lib/[file dirname $build_id_filename]" gdb_test_no_output "python handler_obj.set_mode(Mode.RETURN_TRUE, \ - \"$hidden_libfile\", \"$debugdir_no_lib/$build_id_filename\")" \ + \"$hidden_libfile\", \"$debugdir_no_lib/$build_id_filename\")" \ "configure handler" load_core_file diff --git a/gdb/testsuite/gdb.python/py-missing-objfile.py b/gdb/testsuite/gdb.python/py-missing-objfile.py index 5efc36a..dab3416 100644 --- a/gdb/testsuite/gdb.python/py-missing-objfile.py +++ b/gdb/testsuite/gdb.python/py-missing-objfile.py @@ -41,10 +41,10 @@ handler_last_filename = None # A helper function that makes some assertions about the arguments # passed to a MissingObjfileHandler.__call__() method. def check_args(pspace, buildid, filename): - assert type(filename) == str + assert type(filename) is str assert filename != "" - assert type(pspace) == gdb.Progspace - assert type(buildid) == str + assert type(pspace) is gdb.Progspace + assert type(buildid) is str assert buildid != "" @@ -65,7 +65,7 @@ class handler(MissingObjfileHandler): self._mode = Mode.RETURN_NONE def __call__(self, pspace, buildid, filename): - global handler_call_log, handler_last_buildid, handler_last_filename + global handler_last_buildid, handler_last_filename check_args(pspace, buildid, filename) handler_call_log.append(self.name) handler_last_buildid = buildid @@ -135,7 +135,6 @@ class exception_handler(MissingObjfileHandler): self.exception_type = None def __call__(self, pspace, buildid, filename): - global handler_call_log check_args(pspace, buildid, filename) handler_call_log.append(self.name) assert self.exception_type is not None @@ -148,7 +147,6 @@ class exception_handler(MissingObjfileHandler): # then be checked from the test script. class log_handler(MissingObjfileHandler): def __call__(self, pspace, buildid, filename): - global handler_call_log check_args(pspace, buildid, filename) handler_call_log.append(self.name) return None diff --git a/gdb/testsuite/gdb.python/py-objfile-script-gdb.py b/gdb/testsuite/gdb.python/py-objfile-script-gdb.py index 8666074..6661700 100644 --- a/gdb/testsuite/gdb.python/py-objfile-script-gdb.py +++ b/gdb/testsuite/gdb.python/py-objfile-script-gdb.py @@ -17,6 +17,8 @@ import re +import gdb + class pp_ss: def __init__(self, val): diff --git a/gdb/testsuite/gdb.python/py-objfile-script.exp b/gdb/testsuite/gdb.python/py-objfile-script.exp index 1a3d394..4e6f5b6 100644 --- a/gdb/testsuite/gdb.python/py-objfile-script.exp +++ b/gdb/testsuite/gdb.python/py-objfile-script.exp @@ -41,7 +41,7 @@ gdb_load ${binfile} # Verify gdb loaded the script. gdb_test "info auto-load python-scripts" "Yes.*${testfile}-gdb.py.*" -if ![runto_main] { +if {![runto_main]} { return } diff --git a/gdb/testsuite/gdb.python/py-objfile.c b/gdb/testsuite/gdb.python/py-objfile.c index fe68671..d721e0c 100644 --- a/gdb/testsuite/gdb.python/py-objfile.c +++ b/gdb/testsuite/gdb.python/py-objfile.c @@ -19,7 +19,7 @@ int global_var = 42; static int __attribute__ ((used)) static_var = 50; int -main () +main (void) { int some_var = 0; return 0; diff --git a/gdb/testsuite/gdb.python/py-objfile.exp b/gdb/testsuite/gdb.python/py-objfile.exp index d14eec6..ce4e37a 100644 --- a/gdb/testsuite/gdb.python/py-objfile.exp +++ b/gdb/testsuite/gdb.python/py-objfile.exp @@ -68,7 +68,7 @@ gdb_test "python print (gdb.lookup_objfile (\"${testfile}\").lookup_static_symbo "None" "lookup_static_symbol can handle nonexistent symbol" set binfile_build_id [get_build_id $binfile] -if [string compare $binfile_build_id ""] { +if {[string compare $binfile_build_id ""]} { verbose -log "binfile_build_id = $binfile_build_id" gdb_test "python print (objfile.build_id)" "$binfile_build_id" \ "Get objfile build id" @@ -119,7 +119,7 @@ if { [prepare_for_testing "failed to prepare" ${testfile}2 ${srcfile} {nodebug l return -1 } -if ![runto_main] { +if {![runto_main]} { return 0 } @@ -144,7 +144,8 @@ gdb_test "python print (sep_objfile.owner.filename)" "${testfile}2" \ gdb_test "python print (sep_objfile.owner.username)" "${testfile}2" \ "Test user-name of owner of separate debug file" -gdb_test "p main" "= {int \\(\\)} $hex <main>" \ +set re_prototype [string_to_regexp "int (void)"] +gdb_test "p main" "= {$re_prototype} $hex <main>" \ "print main with debug info" # Separate debug files are not findable. @@ -157,12 +158,13 @@ if { [get_python_valueof "sep_objfile.build_id" "None"] != "None" } { # An objfile that was a symlink to a differently named file is still # findable with its original name. # On Windows we don't have proper symlinks, so skip this. -if ![ishost *-*-mingw*] { +if {![ishost *-*-mingw*]} { set symlink_binary [standard_output_file "symlink-binary"] remote_exec host "rm -f ${symlink_binary}" remote_exec host "ln -sf ${testfile} ${symlink_binary}" - if [remote_file host exists "${symlink_binary}"] { - clean_restart "${symlink_binary}" + if {[remote_file host exists "${symlink_binary}"]} { + clean_restart + gdb_load "${symlink_binary}" gdb_test "python print (gdb.lookup_objfile (\"${symlink_binary}\").filename)" \ "${testfile}" "gdb.lookup_objfile of symlinked binary" } diff --git a/gdb/testsuite/gdb.python/py-parameter-prefix.exp b/gdb/testsuite/gdb.python/py-parameter-prefix.exp new file mode 100644 index 0000000..eb09fe7 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-parameter-prefix.exp @@ -0,0 +1,382 @@ +# Copyright (C) 2025 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 +# gdb.ParameterPrefix. See each of the test procs for a full +# description of what is being tested. + +load_lib gdb-python.exp + +require allow_python_tests + +clean_restart + +# Helper proc to generate the output of 'show PREFIX' commands for the +# case where the prefix command doesn't handle unknown sub-commands. +# In this case GDB will list the value of every sub-command under +# PREFIX. +proc make_show_prefix_re { prefix } { + return "$prefix param-1:\\s+The current value of '$prefix param-1' is \"off\"\\." +} + +# Helper proc to generate the help text that describes all of the sub +# commands under PREFIX. The MODE is either 'set' or 'show'. This +# output will appear for 'help MODE PREFIX' and also for 'set PREFIX'. +proc make_sub_cmd_help_re { mode prefix } { + if { $mode == "set" } { + set word "Set" + } else { + set word "Show" + } + + return \ + [multi_line \ + "List of \"$mode $prefix\" subcommands:" \ + "" \ + "$mode $prefix param-1 -- $word the current value of '$prefix param-1'\\." \ + "" \ + "Type \"help $mode $prefix\" followed by subcommand name for full documentation\\." \ + "Type \"apropos word\" to search for commands related to \"word\"\\." \ + "Type \"apropos -v word\" for full documentation of commands related to \"word\"\\." \ + "Command name abbreviations are allowed if unambiguous\\."] +} + +# Helper proc to generate the output of 'help MODE PREFIX', where MODE +# will be either 'set' or 'show'. The HELP_TEXT is the expected help +# text for this prefix command, this should not be a regexp, as this +# proc converts the text to a regexp. +# +# Return a single regexp which should match the output. +proc make_help_re { mode prefix help_text } { + set help_re [string_to_regexp $help_text] + + return \ + [multi_line \ + "$help_re" \ + "" \ + [make_sub_cmd_help_re $mode $prefix]] +} + +# Create gdb.ParameterPrefix without using a sub-class, both with, and +# without a doc string. For the doc string case, test single line, +# and multi-line doc strings. +proc_with_prefix test_basic_usage {} { + gdb_test_multiline "some basic ParameterPrefix usage" \ + "python" "" \ + "gdb.ParameterPrefix('prefix-1', gdb.COMMAND_NONE)" "" \ + "gdb.Parameter('prefix-1 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \ + "gdb.Parameter('prefix-1 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \ + "gdb.ParameterPrefix('prefix-2', gdb.COMMAND_NONE," "" \ + " \"\"\"This is prefix-2 help string.\"\"\")" "" \ + "gdb.Parameter('prefix-2 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \ + "gdb.ParameterPrefix('prefix-3', gdb.COMMAND_NONE," "" \ + " \"\"\"This is prefix-3 help string." "" \ + " " "" \ + " This help text spans multiple lines.\"\"\")" "" \ + "gdb.Parameter('prefix-3 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \ + "end" + + foreach mode { "set" "show" } { + gdb_test "help $mode prefix-1" \ + [make_help_re $mode "prefix-1" \ + "This command is not documented."] + + gdb_test "help $mode prefix-2" \ + [make_help_re $mode "prefix-2" \ + "This is prefix-2 help string."] + + gdb_test "help $mode prefix-3" \ + [make_help_re $mode "prefix-3" \ + [multi_line \ + "This is prefix-3 help string." \ + "" \ + "This help text spans multiple lines."]] + + foreach prefix { prefix-1 prefix-2 prefix-3 } { + gdb_test "$mode $prefix xxx" \ + "^Undefined $mode $prefix command: \"xxx\"\\. Try \"help $mode $prefix\"\\." + } + } + + foreach prefix { prefix-1 prefix-2 prefix-3 } { + gdb_test "set $prefix" \ + [make_sub_cmd_help_re "set" $prefix] + + gdb_test "show $prefix" \ + [make_show_prefix_re $prefix] + } +} + +# Create a sub-class of gdb.ParameterPrefix, but don't do anything +# particularly interesting. Again test the with and without +# documentation string cases. +proc_with_prefix test_simple_sub_class {} { + gdb_test_multiline "some basic ParameterPrefix usage" \ + "python" "" \ + "class BasicParamPrefix(gdb.ParameterPrefix):" "" \ + " def __init__(self, name):" "" \ + " super().__init__(name, gdb.COMMAND_NONE)" "" \ + "BasicParamPrefix('prefix-4')" "" \ + "gdb.Parameter('prefix-4 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \ + "class BasicParamPrefixWithSingleLineDoc(gdb.ParameterPrefix):" "" \ + " \"\"\"This is a single line doc string.\"\"\"" "" \ + " def __init__(self, name):" "" \ + " super().__init__(name, gdb.COMMAND_NONE)" "" \ + "BasicParamPrefixWithSingleLineDoc('prefix-5')" "" \ + "gdb.Parameter('prefix-5 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \ + "class BasicParamPrefixWithMultiLineDoc(gdb.ParameterPrefix):" "" \ + " \"\"\"This is a multi line doc string." "" \ + " " "" \ + " The rest of the doc string is here.\"\"\"" "" \ + " def __init__(self, name):" "" \ + " super().__init__(name, gdb.COMMAND_NONE)" "" \ + "BasicParamPrefixWithMultiLineDoc('prefix-6')" "" \ + "gdb.Parameter('prefix-6 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \ + "class BasicParamPrefixWithDocParameter(gdb.ParameterPrefix):" "" \ + " \"\"\"This is an unsused doc string.\"\"\"" "" \ + " def __init__(self, name, doc):" "" \ + " super().__init__(name, gdb.COMMAND_NONE, doc)" "" \ + "BasicParamPrefixWithDocParameter('prefix-7'," "" \ + " \"\"\"The doc string text is here.\"\"\")" "" \ + "gdb.Parameter('prefix-7 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \ + "end" + + foreach mode { "set" "show" } { + gdb_test "help $mode prefix-4" \ + [make_help_re $mode "prefix-4" \ + "This command is not documented."] + + gdb_test "help $mode prefix-5" \ + [make_help_re $mode "prefix-5" \ + "This is a single line doc string."] + + gdb_test "help $mode prefix-6" \ + [make_help_re $mode "prefix-6" \ + [multi_line \ + "This is a multi line doc string." \ + "" \ + "The rest of the doc string is here."]] + + gdb_test "help $mode prefix-7" \ + [make_help_re $mode "prefix-7" \ + "The doc string text is here."] + + foreach prefix { prefix-4 prefix-5 prefix-6 prefix-7 } { + gdb_test "$mode $prefix xxx" \ + "^Undefined $mode $prefix command: \"xxx\"\\. Try \"help $mode $prefix\"\\." + } + } + + foreach prefix { prefix-4 prefix-5 prefix-6 prefix-7 } { + gdb_test "set $prefix" \ + [make_sub_cmd_help_re "set" $prefix] + + gdb_test "show $prefix" \ + [make_show_prefix_re $prefix] + } +} + +# Create a sub-class of gdb.ParameterPrefix, and make use of +# 'invoke_set' and 'invoke_show'. Test that the invoke method is +# executed when expected, and that, by default, these invoke methods +# repeat when the user issues an empty command. +proc_with_prefix test_prefix_with_invoke {} { + gdb_test_multiline "ParameterPrefix with invoke_set" \ + "python" "" \ + "class PrefixWithInvokeSet(gdb.ParameterPrefix):" "" \ + " def __init__(self, name):" "" \ + " super().__init__(name, gdb.COMMAND_NONE)" "" \ + " def invoke_set(self, args, from_tty):" "" \ + " print(f\"invoke_set (a): \\\"{args}\\\" {from_tty}\")" "" \ + "PrefixWithInvokeSet('prefix-8')" "" \ + "gdb.Parameter('prefix-8 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \ + "class PrefixWithInvokeShow(gdb.ParameterPrefix):" "" \ + " def __init__(self, name):" "" \ + " super().__init__(name, gdb.COMMAND_NONE)" "" \ + " def invoke_show(self, args, from_tty):" "" \ + " print(f\"invoke_show (b): \\\"{args}\\\" {from_tty}\")" "" \ + "PrefixWithInvokeShow('prefix-9')" "" \ + "gdb.Parameter('prefix-9 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \ + "class PrefixWithBothInvoke(gdb.ParameterPrefix):" "" \ + " def __init__(self, name):" "" \ + " super().__init__(name, gdb.COMMAND_NONE)" "" \ + " def invoke_set(self, args, from_tty):" "" \ + " print(f\"invoke_set (c): \\\"{args}\\\" {from_tty}\")" "" \ + " def invoke_show(self, args, from_tty):" "" \ + " print(f\"invoke_show (d): \\\"{args}\\\" {from_tty}\")" "" \ + "PrefixWithBothInvoke('prefix-10')" "" \ + "gdb.Parameter('prefix-10 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \ + "end" + + gdb_test "set prefix-8 xxx yyy" \ + "^invoke_set \\(a\\): \"xxx yyy\" True" + + send_gdb "\n" + gdb_test "" "^\r\ninvoke_set \\(a\\): \"xxx yyy\" True" \ + "repeat set prefix-8 xxx yyy" + + gdb_test "show prefix-8 xxx yyy" \ + "^Undefined show prefix-8 command: \"xxx yyy\"\\. Try \"help show prefix-8\"\\." + + gdb_test "set prefix-9 xxx yyy" \ + "^Undefined set prefix-9 command: \"xxx yyy\"\\. Try \"help set prefix-9\"\\." + + gdb_test "show prefix-9 xxx yyy" \ + "^invoke_show \\(b\\): \"xxx yyy\" True" + + send_gdb "\n" + gdb_test "" "^\r\ninvoke_show \\(b\\): \"xxx yyy\" True" \ + "repeat show prefix-9 xxx yyy" + + gdb_test "set prefix-10 xxx yyy" \ + "^invoke_set \\(c\\): \"xxx yyy\" True" + + send_gdb "\n" + gdb_test "" "^\r\ninvoke_set \\(c\\): \"xxx yyy\" True" \ + "repeat set prefix-10 xxx yyy" + + gdb_test "show prefix-10 xxx yyy" \ + "^invoke_show \\(d\\): \"xxx yyy\" True" + + send_gdb "\n" + gdb_test "" "^\r\ninvoke_show \\(d\\): \"xxx yyy\" True" \ + "repeat show prefix-10 xxx yyy" + + gdb_test "set prefix-8" \ + "^invoke_set \\(a\\): \"\" True" + + gdb_test "show prefix-8" \ + [make_show_prefix_re "prefix-8"] + + gdb_test "set prefix-9" \ + [make_sub_cmd_help_re "set" "prefix-9"] + + gdb_test "show prefix-9" \ + "^invoke_show \\(b\\): \"\" True" + + gdb_test "set prefix-10" \ + "^invoke_set \\(c\\): \"\" True" + + gdb_test "show prefix-10" \ + "^invoke_show \\(d\\): \"\" True" +} + +# Create ParameterPrefix sub-classes that make use of the +# dont_repeat() method. Check that the relevant set/show invoke +# callback doesn't repeat when an empty command is used. +proc_with_prefix test_dont_repeat {} { + gdb_test_multiline "ParameterPrefix with invoke_set and dont_repeat" \ + "python" "" \ + "class PrefixWithInvokeAndDoNotRepeatSet(gdb.ParameterPrefix):" "" \ + " def __init__(self, name):" "" \ + " super().__init__(name, gdb.COMMAND_NONE)" "" \ + " def invoke_set(self, args, from_tty):" "" \ + " self.dont_repeat()" "" \ + " print(f\"invoke_set: \\\"{args}\\\" {from_tty}\")" "" \ + " def invoke_show(self, args, from_tty):" "" \ + " print(f\"invoke_show: \\\"{args}\\\" {from_tty}\")" "" \ + "PrefixWithInvokeAndDoNotRepeatSet('prefix-11')" "" \ + "gdb.Parameter('prefix-11 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \ + "class PrefixWithInvokeAndDoNotRepeatShow(gdb.ParameterPrefix):" "" \ + " def __init__(self, name):" "" \ + " super().__init__(name, gdb.COMMAND_NONE)" "" \ + " def invoke_set(self, args, from_tty):" "" \ + " print(f\"invoke_set: \\\"{args}\\\" {from_tty}\")" "" \ + " def invoke_show(self, args, from_tty):" "" \ + " self.dont_repeat()" "" \ + " print(f\"invoke_show: \\\"{args}\\\" {from_tty}\")" "" \ + "PrefixWithInvokeAndDoNotRepeatShow('prefix-12')" "" \ + "gdb.Parameter('prefix-12 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \ + "end" + + gdb_test "set prefix-11 xxx yyy" \ + "^invoke_set: \"xxx yyy\" True" + + send_gdb "\n" + gdb_test "" "^" \ + "repeat set prefix-11 xxx yyy" + + gdb_test "show prefix-11 xxx yyy" \ + "^invoke_show: \"xxx yyy\" True" + + send_gdb "\n" + gdb_test "" "invoke_show: \"xxx yyy\" True" \ + "repeat show prefix-11 xxx yyy" + + gdb_test "set prefix-12 xxx yyy" \ + "^invoke_set: \"xxx yyy\" True" + + send_gdb "\n" + gdb_test "" "^\r\ninvoke_set: \"xxx yyy\" True" \ + "repeat set prefix-12 xxx yyy" + + gdb_test "show prefix-12 xxx yyy" \ + "^invoke_show: \"xxx yyy\" True" + + send_gdb "\n" + gdb_test "" "^" \ + "repeat show prefix-12 xxx yyy" +} + +# Create a parameter prefixm, and immediately add another prefix under +# the first. The important thing here is that the second prefix is +# created into an otherwise empty prefix as this triggered a bug at +# one point. +proc_with_prefix test_nested {} { + gdb_test_multiline "Create nested parameter prefixes" \ + "python" "" \ + "gdb.ParameterPrefix('prefix-13', gdb.COMMAND_NONE)" "" \ + "gdb.ParameterPrefix('prefix-13 prefix-14', gdb.COMMAND_NONE)" "" \ + "gdb.Parameter('prefix-13 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \ + "gdb.Parameter('prefix-13 param-2', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \ + "gdb.Parameter('prefix-13 prefix-14 param-3', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \ + "gdb.Parameter('prefix-13 prefix-14 param-4', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \ + "end" "" + + gdb_test "show prefix-13 prefix-14" \ + [multi_line \ + "^prefix-13 prefix-14 param-3: The current value of 'prefix-13 prefix-14 param-3' is \"off\"\\." \ + "prefix-13 prefix-14 param-4: The current value of 'prefix-13 prefix-14 param-4' is \"off\"\\."] + + gdb_test "show prefix-13" \ + [multi_line \ + "^prefix-13 param-1: The current value of 'prefix-13 param-1' is \"off\"\\." \ + "prefix-13 param-2: The current value of 'prefix-13 param-2' is \"off\"\\." \ + "prefix-13 prefix-14 param-3: The current value of 'prefix-13 prefix-14 param-3' is \"off\"\\." \ + "prefix-13 prefix-14 param-4: The current value of 'prefix-13 prefix-14 param-4' is \"off\"\\."] + + gdb_test "set prefix-13 prefix-14" \ + [multi_line \ + "" \ + "set prefix-13 prefix-14 param-3 -- Set the current value of 'prefix-13 prefix-14 param-3'\\." \ + "set prefix-13 prefix-14 param-4 -- Set the current value of 'prefix-13 prefix-14 param-4'\\." \ + "" \ + ".*"] + + gdb_test "set prefix-13" \ + [multi_line \ + "" \ + "set prefix-13 param-1 -- Set the current value of 'prefix-13 param-1'\\." \ + "set prefix-13 param-2 -- Set the current value of 'prefix-13 param-2'\\." \ + "set prefix-13 prefix-14 -- This command is not documented\\." \ + "" \ + ".*"] +} + +test_basic_usage +test_simple_sub_class +test_prefix_with_invoke +test_dont_repeat +test_nested diff --git a/gdb/testsuite/gdb.python/py-parameter.exp b/gdb/testsuite/gdb.python/py-parameter.exp index c15bef1..7c2f5c6 100644 --- a/gdb/testsuite/gdb.python/py-parameter.exp +++ b/gdb/testsuite/gdb.python/py-parameter.exp @@ -24,7 +24,7 @@ require allow_python_tests clean_restart proc py_param_test_maybe_no_output { command pattern args } { - if [string length $pattern] { + if {[string length $pattern]} { gdb_test $command $pattern $args } else { gdb_test_no_output $command $args @@ -38,13 +38,17 @@ proc_with_prefix test_directories { } { # doesn't set search directories on remote host. set directories ".*\\\$cdir.\\\$cwd" } else { - set escaped_directory [string_to_regexp "$::srcdir/$::subdir"] + set directory [host_file_normalize "$::srcdir/$::subdir"] + set escaped_directory [string_to_regexp $directory] set directories "$escaped_directory.\\\$cdir.\\\$cwd" } gdb_test "python print (gdb.parameter ('directories'))" $directories } proc_with_prefix test_data_directory { } { + # Proc assumes local host. + require {!is_remote host} + clean_restart # Check we can correctly read the data-directory parameter. First, @@ -187,6 +191,8 @@ proc_with_prefix test_enum_parameter { } { # Test an color parameter. proc_with_prefix test_color_parameter { } { + require {!is_remote host} + global env with_ansi_styling_terminal { # This enables 256 colors support and disables colors approximation. @@ -346,6 +352,91 @@ proc_with_prefix test_really_undocumented_parameter { } { "test general help" } +# Test a parameter in which the __doc__ string is empty or None. +proc_with_prefix test_empty_doc_parameter {} { + gdb_test_multiline "empty __doc__ parameter" \ + "python" "" \ + "class EmptyDocParam(gdb.Parameter):" "" \ + " __doc__ = \"\"" "" \ + " def __init__(self, name):" "" \ + " super ().__init__(name, gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \ + " self.value = True" "" \ + "test_empty_doc_param = EmptyDocParam('print test-empty-doc-param')" ""\ + "end" + + # Setting the __doc__ string to empty means GDB will completely + # elide it from the output. + gdb_test "help set print test-empty-doc-param" \ + "^Set the current value of 'print test-empty-doc-param'\\." + + gdb_test_multiline "None __doc__ parameter" \ + "python" "" \ + "class NoneDocParam(gdb.Parameter):" "" \ + " __doc__ = None" "" \ + " def __init__(self, name):" "" \ + " super ().__init__(name, gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \ + " self.value = True" "" \ + "test_none_doc_param = NoneDocParam('print test-none-doc-param')" ""\ + "end" + + # Setting the __doc__ string to None, or anything else that isn't + # a string, causes GDB to use a default string instead. + gdb_test "help set print test-none-doc-param" \ + [multi_line \ + "^Set the current value of 'print test-none-doc-param'\\." \ + "This command is not documented\\."] +} + +# Test a parameter in which the set_doc/show_doc strings are either +# empty, or None. +proc_with_prefix test_empty_set_show_doc_parameter {} { + gdb_test_multiline "empty set/show doc parameter" \ + "python" "" \ + "class EmptySetShowParam(gdb.Parameter):" "" \ + " set_doc = \"\"" "" \ + " show_doc = \"\"" "" \ + " def __init__(self, name):" "" \ + " super ().__init__(name, gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \ + " self.value = True" "" \ + "test_empty_set_show_param = EmptySetShowParam('print test-empty-set-show-param')" ""\ + "end" + + # Setting the set_doc/show_doc string to empty means GDB will use + # a suitable default string. + gdb_test "help set print test-empty-set-show-param" \ + [multi_line \ + "^Set the current value of 'print test-empty-set-show-param'\\." \ + "This command is not documented\\."] + + gdb_test "help show print test-empty-set-show-param" \ + [multi_line \ + "^Show the current value of 'print test-empty-set-show-param'\\." \ + "This command is not documented\\."] + + gdb_test_multiline "None set/show doc parameter" \ + "python" "" \ + "class NoneSetShowParam(gdb.Parameter):" "" \ + " set_doc = None" "" \ + " show_doc = None" "" \ + " def __init__(self, name):" "" \ + " super ().__init__(name, gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \ + " self.value = True" "" \ + "test_none_set_show_param = NoneSetShowParam('print test-none-set-show-param')" ""\ + "end" + + # Setting the set_doc/show_doc string to None (or any non-string + # value) means GDB will use a suitable default string. + gdb_test "help set print test-none-set-show-param" \ + [multi_line \ + "^Set the current value of 'print test-none-set-show-param'\\." \ + "This command is not documented\\."] + + gdb_test "help show print test-none-set-show-param" \ + [multi_line \ + "^Show the current value of 'print test-none-set-show-param'\\." \ + "This command is not documented\\."] +} + # Test deprecated API. Do not use in your own implementations. proc_with_prefix test_deprecated_api_parameter { } { clean_restart @@ -627,6 +718,38 @@ proc_with_prefix test_throwing_parameter { } { "gdb.GdbError does not show Python stack" } +# Some parameters are per inferior. The value returned by gdb.parameter for +# them should be dependent on which is the current inferior. +proc_with_prefix test_per_inferior_parameters { } { + clean_restart + + # Add a second inferior. + gdb_test "add-inferior" "Added inferior 2.*" + + # Set some parameters on each inferior. + foreach_with_prefix inf {1 2} { + gdb_test "inferior ${inf}" "Switching to inferior ${inf}.*" \ + "switch to inferior ${inf} before show" + gdb_test_no_output "set inferior-tty /inf${inf}-tty" + gdb_test_no_output "set cwd /inf${inf}-cwd" + gdb_test_no_output "set args /inf${inf}-args" + gdb_test_no_output "set remote exec-file /inf${inf}-ref" + # Outputs a warning, ignore it. + gdb_test "set tdesc filename /inf${inf}-tf" + } + + # Check the values on each inferior. + foreach_with_prefix inf {1 2} { + gdb_test "inferior ${inf}" "Switching to inferior ${inf}.*" \ + "switch to inferior ${inf} before set" + gdb_test "python print(gdb.parameter('inferior-tty'))" "/inf${inf}-tty" + gdb_test "python print(gdb.parameter('cwd'))" "/inf${inf}-cwd" + gdb_test "python print(gdb.parameter('args'))" "/inf${inf}-args" + gdb_test "python print(gdb.parameter('remote exec-file'))" "/inf${inf}-ref" + gdb_test "python print(gdb.parameter('tdesc filename'))" "/inf${inf}-tf" + } +} + proc_with_prefix test_language {} { gdb_test "python print(gdb.parameter('language'))" "auto" \ "print language parameter" @@ -669,6 +792,104 @@ proc_with_prefix test_ambiguous_parameter {} { "Parameter .* is ambiguous.*Error occurred in Python.*" gdb_test "python print(gdb.parameter('test-ambiguous-value-1a'))" \ "Could not find parameter.*Error occurred in Python.*" + + # Create command prefixs 'set foo1' and 'show foo1'. + gdb_test_no_output "python gdb.Command('set foo1', gdb.COMMAND_NONE, prefix=True)" + gdb_test_no_output "python gdb.Command('show foo1', gdb.COMMAND_NONE, prefix=True)" + + # Create a parameter under 'foo1', but use a truncated prefix. At + # this point though, the prefix is not ambiguous. + gdb_test_no_output "python gdb.Parameter('foo bar', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" + gdb_test "python print(gdb.parameter('foo1 bar'))" "False" + + # Create another prefix command, similar in name to the first. + gdb_test_no_output "python gdb.Command('set foo2', gdb.COMMAND_NONE, prefix=True)" + gdb_test_no_output "python gdb.Command('show foo2', gdb.COMMAND_NONE, prefix=True)" + + # An attempt to create a parameter using an ambiguous prefix will give an error. + gdb_test "python gdb.Parameter('foo baz', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" \ + [multi_line \ + "Python Exception <class 'RuntimeError'>: Could not find command prefix foo\\." \ + "Error occurred in Python: Could not find command prefix foo\\."] +} + +# Check that creating a gdb.Parameter with an unknown command prefix results in an error. +proc_with_prefix test_unknown_prefix {} { + gdb_test_multiline "create parameter" \ + "python" "" \ + "class UnknownPrefixParam(gdb.Parameter):" "" \ + " def __init__ (self, name):" "" \ + " super().__init__ (name, gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \ + " self.value = True" "" \ + "end" + + foreach prefix { "unknown-prefix" "style unknown-prefix" "style disassembler unknown-prefix"} { + gdb_test "python UnknownPrefixParam('$prefix new-param')" \ + [multi_line \ + "Python Exception <class 'RuntimeError'>: Could not find command prefix $prefix\\." \ + "Error occurred in Python: Could not find command prefix $prefix\\."] + } +} + +# Test the default behaviour of a set/show parameter prefix command. +proc_with_prefix test_set_show_parameters {} { + # This first set/show prefix command doesn't have an invoke + # method. As such, GDB installs the default invoke behaviour; set + # prints the full list of sub-commands, and show prints all the + # sub-command values. + gdb_test_multiline "Setup set/show parameter prefix with no invoke" \ + "python" "" \ + "class TestParamPrefix(gdb.Command):" "" \ + " \"\"\"TestParamPrefix documentation string.\"\"\"" "" \ + " def __init__(self, name):" "" \ + " super().__init__(name, gdb.COMMAND_NONE, prefix = True)" "" \ + "TestParamPrefix('set test-prefix')" "" \ + "TestParamPrefix('show test-prefix')" "" \ + "gdb.Parameter('test-prefix param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \ + "gdb.Parameter('test-prefix param-2', gdb.COMMAND_NONE, gdb.PARAM_INTEGER)" "" \ + "gdb.Parameter('test-prefix param-3', gdb.COMMAND_NONE, gdb.PARAM_STRING)" "" \ + "end" + + gdb_test "set test-prefix" \ + [multi_line \ + "List of \"set test-prefix\" subcommands:" \ + "" \ + "set test-prefix param-1 -- Set the current value of 'test-prefix param-1'." \ + "set test-prefix param-2 -- Set the current value of 'test-prefix param-2'." \ + "set test-prefix param-3 -- Set the current value of 'test-prefix param-3'." \ + "" \ + "Type \"help set test-prefix\" followed by subcommand name for full documentation\\." \ + "Type \"apropos word\" to search for commands related to \"word\"\\." \ + "Type \"apropos -v word\" for full documentation of commands related to \"word\"\\." \ + "Command name abbreviations are allowed if unambiguous\\."] + + gdb_test "show test-prefix" \ + [multi_line \ + "test-prefix param-1: The current value of 'test-prefix param-1' is \"off\"\\." \ + "test-prefix param-2: The current value of 'test-prefix param-2' is \"0\"\\." \ + "test-prefix param-3: The current value of 'test-prefix param-3' is \"\"\\."] + + # This next set/show prefix has an invoke method, which will be + # called instead of the default behaviour tested above. + gdb_test_multiline "Setup set/show parameter prefix with invoke" \ + "python" "" \ + "class TestParamPrefix(gdb.Command):" "" \ + " \"\"\"TestParamPrefix documentation string.\"\"\"" "" \ + " def __init__(self, name, mode):" "" \ + " self._mode = mode" "" \ + " super().__init__(self._mode + ' ' + name, gdb.COMMAND_NONE, prefix = True)" "" \ + " def invoke(self, args, from_tty):" "" \ + " print('invoke -- ' + self._mode)" "" \ + "TestParamPrefix('test-prefix-2', 'set')" "" \ + "TestParamPrefix('test-prefix-2', 'show')" "" \ + "gdb.Parameter('test-prefix-2 param-1', gdb.COMMAND_NONE, gdb.PARAM_BOOLEAN)" "" \ + "gdb.Parameter('test-prefix-2 param-2', gdb.COMMAND_NONE, gdb.PARAM_INTEGER)" "" \ + "gdb.Parameter('test-prefix-2 param-3', gdb.COMMAND_NONE, gdb.PARAM_STRING)" "" \ + "end" + + gdb_test "set test-prefix-2" "^invoke -- set" + + gdb_test "show test-prefix-2" "^invoke -- show" } test_directories @@ -679,11 +900,16 @@ test_color_parameter test_file_parameter test_undocumented_parameter test_really_undocumented_parameter +test_empty_doc_parameter +test_empty_set_show_doc_parameter test_deprecated_api_parameter test_gdb_parameter test_integer_parameter test_throwing_parameter +test_per_inferior_parameters test_language test_ambiguous_parameter +test_unknown_prefix +test_set_show_parameters rename py_param_test_maybe_no_output "" diff --git a/gdb/testsuite/gdb.python/py-pp-cast.exp b/gdb/testsuite/gdb.python/py-pp-cast.exp index 7e20756..917547c 100644 --- a/gdb/testsuite/gdb.python/py-pp-cast.exp +++ b/gdb/testsuite/gdb.python/py-pp-cast.exp @@ -25,7 +25,7 @@ if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } { return -1 } -if ![runto break_function] { +if {![runto break_function]} { return -1 } diff --git a/gdb/testsuite/gdb.python/py-pp-integral.exp b/gdb/testsuite/gdb.python/py-pp-integral.exp index 8111d75..45645f9 100644 --- a/gdb/testsuite/gdb.python/py-pp-integral.exp +++ b/gdb/testsuite/gdb.python/py-pp-integral.exp @@ -21,7 +21,7 @@ if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } { return -1 } -if ![runto tick_tock] { +if {![runto tick_tock]} { return -1 } diff --git a/gdb/testsuite/gdb.python/py-pp-maint.c b/gdb/testsuite/gdb.python/py-pp-maint.c index f40bbe5..4221539 100644 --- a/gdb/testsuite/gdb.python/py-pp-maint.c +++ b/gdb/testsuite/gdb.python/py-pp-maint.c @@ -81,6 +81,6 @@ main () init_flt (&flt, 42, 43); init_ss (&ss, 1, 2); - + return 0; /* break to inspect */ } diff --git a/gdb/testsuite/gdb.python/py-pp-maint.exp b/gdb/testsuite/gdb.python/py-pp-maint.exp index 74d8e76..bd26b91 100644 --- a/gdb/testsuite/gdb.python/py-pp-maint.exp +++ b/gdb/testsuite/gdb.python/py-pp-maint.exp @@ -72,10 +72,10 @@ gdb_test "enable pretty-printer" \ "second enable of all pretty printers" gdb_test "disable pretty-printer global lookup_function_lookup_test" \ - "1 printer disabled.*[expr $num_pp - 1] of $num_pp printers enabled" + "1 printer disabled.*[expr {$num_pp - 1}] of $num_pp printers enabled" gdb_test "disable pretty-printer global pp-test;.*" \ - "[expr 5] printers disabled.*0 of $num_pp printers enabled" + "[expr {$num_pp - 1}] printers disabled.*0 of $num_pp printers enabled" gdb_test "info pretty-printer global .*function" \ {.*function_lookup_test \[disabled\].*} \ @@ -101,10 +101,10 @@ gdb_test "enable pretty-printer global pp-test" \ "0 printers enabled.*1 of $num_pp printers enabled" gdb_test "enable pretty-printer global pp-test;.*ss.*" \ - "2 printers enabled.*[expr $num_pp - 3] of $num_pp printers enabled" + "2 printers enabled.*[expr {$num_pp - 3}] of $num_pp printers enabled" gdb_test "enable pretty-printer global pp-test;.*s.*" \ - "2 printers enabled.*[expr $num_pp - 1] of $num_pp printers enabled" + "2 printers enabled.*[expr {$num_pp - 1}] of $num_pp printers enabled" gdb_test "enable pretty-printer global pp-test;.*" \ "1 printer enabled.*$num_pp of $num_pp printers enabled" diff --git a/gdb/testsuite/gdb.python/py-pp-maint.py b/gdb/testsuite/gdb.python/py-pp-maint.py index 8b96cc0..a7e0815 100644 --- a/gdb/testsuite/gdb.python/py-pp-maint.py +++ b/gdb/testsuite/gdb.python/py-pp-maint.py @@ -16,8 +16,6 @@ # This file is part of the GDB testsuite. It tests python pretty # printers. -import re - import gdb.printing import gdb.types diff --git a/gdb/testsuite/gdb.python/py-pp-re-notag.exp b/gdb/testsuite/gdb.python/py-pp-re-notag.exp index 8111d75..45645f9 100644 --- a/gdb/testsuite/gdb.python/py-pp-re-notag.exp +++ b/gdb/testsuite/gdb.python/py-pp-re-notag.exp @@ -21,7 +21,7 @@ if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } { return -1 } -if ![runto tick_tock] { +if {![runto tick_tock]} { return -1 } diff --git a/gdb/testsuite/gdb.python/py-pp-registration.c b/gdb/testsuite/gdb.python/py-pp-registration.c index 5a95917..e7dfd60 100644 --- a/gdb/testsuite/gdb.python/py-pp-registration.c +++ b/gdb/testsuite/gdb.python/py-pp-registration.c @@ -50,6 +50,6 @@ main () init_flt (&flt, 42, 43); init_s (&s, 1); - + return 0; /* break to inspect */ } diff --git a/gdb/testsuite/gdb.python/py-pp-registration.exp b/gdb/testsuite/gdb.python/py-pp-registration.exp index c5e7f9a..d0d1fda 100644 --- a/gdb/testsuite/gdb.python/py-pp-registration.exp +++ b/gdb/testsuite/gdb.python/py-pp-registration.exp @@ -29,7 +29,7 @@ if {[prepare_for_testing "failed to prepare" $testfile $srcfile debug]} { set remote_python_file [gdb_remote_download host \ ${srcdir}/${subdir}/${testfile}.py] -if ![runto_main ] { +if {![runto_main ]} { return -1 } @@ -40,7 +40,7 @@ proc prepare_test { } { clean_restart ${testfile} set run_to_here [gdb_get_line_number {break to inspect} ${testfile}.c ] - if ![runto ${testfile}.c:$run_to_here] { + if {![runto ${testfile}.c:$run_to_here]} { return 0 } @@ -63,7 +63,7 @@ proc test_printers { s_prefix } { # Test registration with verbose off. with_test_prefix "verbose off" { - if ![prepare_test] { + if {![prepare_test]} { return -1 } @@ -78,7 +78,7 @@ with_test_prefix "verbose off" { # Test registration with verbose on. with_test_prefix "verbose on" { - if ![prepare_test] { + if {![prepare_test]} { return -1 } @@ -95,7 +95,7 @@ with_test_prefix "verbose on" { # Exercise the "replace" argument to register_pretty_printer. with_test_prefix "replace" { - if ![prepare_test] { + if {![prepare_test]} { return -1 } diff --git a/gdb/testsuite/gdb.python/py-pp-registration.py b/gdb/testsuite/gdb.python/py-pp-registration.py index e9f3dfb..02ef2d2 100644 --- a/gdb/testsuite/gdb.python/py-pp-registration.py +++ b/gdb/testsuite/gdb.python/py-pp-registration.py @@ -16,8 +16,6 @@ # This file is part of the GDB testsuite. It tests python pretty # printer registration. -import re - import gdb.printing import gdb.types @@ -42,8 +40,6 @@ class pp_s1(object): self.val = val def to_string(self): - a = self.val["a"] - b = self.val["b"] return "s1 a=<" + str(self.val["a"]) + "> b=<" + str(self.val["b"]) + ">" @@ -52,8 +48,6 @@ class pp_s2(object): self.val = val def to_string(self): - a = self.val["a"] - b = self.val["b"] return "s2 a=<" + str(self.val["a"]) + "> b=<" + str(self.val["b"]) + ">" diff --git a/gdb/testsuite/gdb.python/py-prettyprint.c b/gdb/testsuite/gdb.python/py-prettyprint.c index 56c19ad..3951b19 100644 --- a/gdb/testsuite/gdb.python/py-prettyprint.c +++ b/gdb/testsuite/gdb.python/py-prettyprint.c @@ -72,16 +72,16 @@ struct SSS }; SSS::SSS (int x, const S& r) : a(x), b(r) { } -class VirtualTest -{ - private: - int value; - - public: - VirtualTest () - { +class VirtualTest +{ + private: + int value; + + public: + VirtualTest () + { value = 1; - } + } }; class Vbase1 : public virtual VirtualTest { }; @@ -89,21 +89,21 @@ class Vbase2 : public virtual VirtualTest { }; class Vbase3 : public virtual VirtualTest { }; class Derived : public Vbase1, public Vbase2, public Vbase3 -{ - private: - int value; - +{ + private: + int value; + public: - Derived () - { - value = 2; + Derived () + { + value = 2; } }; class Fake { int sname; - + public: Fake (const int name = 0): sname (name) @@ -150,7 +150,7 @@ substruct_test (void) outer.s.a = 3; /* MI outer breakpoint here */ - return outer; + return outer; } typedef struct string_repr @@ -362,7 +362,7 @@ main () SSS& ref (sss); Derived derived; - + Fake fake (42); init_s (&has_static_member::global, 23); @@ -387,7 +387,7 @@ main () nstype.elements[0] = 7; nstype.elements[1] = 42; nstype.len = 2; - + nstype2 = nstype; eval_sub (); diff --git a/gdb/testsuite/gdb.python/py-prettyprint.exp b/gdb/testsuite/gdb.python/py-prettyprint.exp index 0b5ca9a..e450edc 100644 --- a/gdb/testsuite/gdb.python/py-prettyprint.exp +++ b/gdb/testsuite/gdb.python/py-prettyprint.exp @@ -36,7 +36,8 @@ proc run_lang_tests {exefile lang} { set nl "\[\r\n\]+" # Start with a fresh gdb. - clean_restart $exefile + clean_restart + gdb_load $exefile if {![runto_main]} { return @@ -52,11 +53,11 @@ proc run_lang_tests {exefile lang} { ${srcdir}/${subdir}/${testfile}.py] gdb_test_no_output "source ${remote_python_file}" "load python file" - + gdb_test "print ss" " = a=< a=<1> b=<$hex>> b=< a=<2> b=<$hex>>" gdb_test "print ssa\[1\]" " = a=< a=<5> b=<$hex>> b=< a=<6> b=<$hex>>" gdb_test "print ssa" " = {a=< a=<3> b=<$hex>> b=< a=<4> b=<$hex>>, a=< a=<5> b=<$hex>> b=< a=<6> b=<$hex>>}" - + gdb_test "print arraystruct" " = {$nl *y = 7, *$nl *x = { a=<23> b=<$hex>, a=<24> b=<$hex>} *$nl *}" # Test that when a pretty-printer returns a gdb.Value in its to_string, we @@ -192,7 +193,7 @@ with_test_prefix c++ { # Run various other tests. -clean_restart $binfile +clean_restart $::testfile if {![runto_main]} { return @@ -242,5 +243,3 @@ gdb_test "print /r ss" " = {a = {a = 1, b = $hex}, b = {a = 2, b = $hex}}" gdb_test "with print raw-values off -- print /r ss" " = {a = {a = 1, b = $hex}, b = {a = 2, b = $hex}}" gdb_test "print -raw-values off -- /r ss" " = {a = {a = 1, b = $hex}, b = {a = 2, b = $hex}}" - - diff --git a/gdb/testsuite/gdb.python/py-progspace.exp b/gdb/testsuite/gdb.python/py-progspace.exp index 1d271d4..822c079 100644 --- a/gdb/testsuite/gdb.python/py-progspace.exp +++ b/gdb/testsuite/gdb.python/py-progspace.exp @@ -76,7 +76,7 @@ gdb_test "python print (blk.end >= ${pc_val})" "True" \ "block end is after \$pc" # Check what happens when we ask for a block of an invalid address. -if ![is_address_zero_readable] { +if {![is_address_zero_readable]} { gdb_test "python print (gdb.current_progspace ().block_for_pc (0))" "None" } diff --git a/gdb/testsuite/gdb.python/py-read-memory-leak.exp b/gdb/testsuite/gdb.python/py-read-memory-leak.exp index 0015a57..0b663d7 100644 --- a/gdb/testsuite/gdb.python/py-read-memory-leak.exp +++ b/gdb/testsuite/gdb.python/py-read-memory-leak.exp @@ -26,19 +26,9 @@ if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } { return -1 } -if ![runto_main] { +if {![runto_main]} { return -1 } -# Skip this test if the tracemalloc module is not available. -if { ![gdb_py_module_available "tracemalloc"] } { - unsupported "tracemalloc module not available" - return -} - -set pyfile [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py] - -# Source the Python script, this runs the test (which is written -# completely in Python), and either prints PASS, or throws an -# exception. -gdb_test "source ${pyfile}" "PASS" "source python script" +gdb_py_run_memory_leak_test ${srcdir}/${subdir}/${testfile}.py \ + "buffers returned by read_memory() deallocates correctly" diff --git a/gdb/testsuite/gdb.python/py-read-memory-leak.py b/gdb/testsuite/gdb.python/py-read-memory-leak.py index 348403d..6bab0d7 100644 --- a/gdb/testsuite/gdb.python/py-read-memory-leak.py +++ b/gdb/testsuite/gdb.python/py-read-memory-leak.py @@ -13,81 +13,29 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -import os -import tracemalloc +import sys import gdb -# A global variable in which we store a reference to the memory buffer -# returned from gdb.Inferior.read_memory(). -mem_buf = None +# Avoid generating +# src/gdb/testsuite/gdb.python/__pycache__/gdb_leak_detector.cpython-<n>.pyc. +sys.dont_write_bytecode = True +import gdb_leak_detector # noqa: E402 -# A global filters list, we only care about memory allocations -# originating from this script. -filters = [tracemalloc.Filter(True, "*" + os.path.basename(__file__))] +class read_leak_detector(gdb_leak_detector.gdb_leak_detector): + def __init__(self): + super().__init__(__file__) + self.mem_buf = None + self.addr = gdb.parse_and_eval("px") + self.inf = gdb.inferiors()[0] -# Run the test. When CLEAR is True we clear the global INF variable -# before comparing the before and after memory allocation traces. -# When CLEAR is False we leave INF set to reference the gdb.Inferior -# object, thus preventing the gdb.Inferior from being deallocated. -def test(clear): - global filters, mem_buf + def allocate(self): + self.mem_buf = self.inf.read_memory(self.addr, 4096) - addr = gdb.parse_and_eval("px") - inf = gdb.inferiors()[0] + def deallocate(self): + self.mem_buf = None - # Start tracing, and take a snapshot of the current allocations. - tracemalloc.start() - snapshot1 = tracemalloc.take_snapshot() - # Read from the inferior, this allocate a memory buffer object. - mem_buf = inf.read_memory(addr, 4096) - - # Possibly clear the global INF variable. - if clear: - mem_buf = None - - # Now grab a second snapshot of memory allocations, and stop - # tracing memory allocations. - snapshot2 = tracemalloc.take_snapshot() - tracemalloc.stop() - - # Filter the snapshots; we only care about allocations originating - # from this file. - snapshot1 = snapshot1.filter_traces(filters) - snapshot2 = snapshot2.filter_traces(filters) - - # Compare the snapshots, this leaves only things that were - # allocated, but not deallocated since the first snapshot. - stats = snapshot2.compare_to(snapshot1, "traceback") - - # Total up all the allocated things. - total = 0 - for stat in stats: - total += stat.size_diff - return total - - -# The first time we run this some global state will be allocated which -# shows up as memory that is allocated, but not released. So, run the -# test once and discard the result. -test(True) - -# Now run the test twice, the first time we clear our global reference -# to the memory buffer object, which should allow Python to deallocate -# the object. The second time we hold onto the global reference, -# preventing Python from performing the deallocation. -bytes_with_clear = test(True) -bytes_without_clear = test(False) - -# The bug that used to exist in GDB was that even when we released the -# global reference the gdb.Inferior object would not be deallocated. -if bytes_with_clear > 0: - raise gdb.GdbError("memory leak when memory buffer should be released") -if bytes_without_clear == 0: - raise gdb.GdbError("memory buffer object is no longer allocated") - -# Print a PASS message that the test script can see. -print("PASS") +read_leak_detector().run() diff --git a/gdb/testsuite/gdb.python/py-record-btrace.exp b/gdb/testsuite/gdb.python/py-record-btrace.exp index aff7c6c..207161d 100644 --- a/gdb/testsuite/gdb.python/py-record-btrace.exp +++ b/gdb/testsuite/gdb.python/py-record-btrace.exp @@ -23,7 +23,7 @@ load_lib gdb-python.exp standard_testfile -if [prepare_for_testing "failed to prepare" $testfile $srcfile] { return -1 } +if {[prepare_for_testing "failed to prepare" $testfile $srcfile]} { return -1 } if {![runto_main]} { return -1 @@ -66,8 +66,8 @@ with_test_prefix "prepare record" { set v [linux_kernel_version] if { $v != {} } { set have_xfail \ - [expr [version_compare [list 5 5 0] <= $v] \ - && [version_compare $v < [list 6 1 0]]] + [expr {[version_compare [list 5 5 0] <= $v] \ + && [version_compare $v < [list 6 1 0]]}] } set nonl_re \[^\r\n\] set xfail_re \ diff --git a/gdb/testsuite/gdb.python/py-record-full.exp b/gdb/testsuite/gdb.python/py-record-full.exp index 97d21ce..790e5b3 100644 --- a/gdb/testsuite/gdb.python/py-record-full.exp +++ b/gdb/testsuite/gdb.python/py-record-full.exp @@ -23,7 +23,7 @@ load_lib gdb-python.exp standard_testfile -if [prepare_for_testing "failed to prepare" $testfile $srcfile] { return -1 } +if {[prepare_for_testing "failed to prepare" $testfile $srcfile]} { return -1 } if {![runto_main]} { return -1 diff --git a/gdb/testsuite/gdb.python/py-recurse-unwind.exp b/gdb/testsuite/gdb.python/py-recurse-unwind.exp index a1d1462..fbcb959 100644 --- a/gdb/testsuite/gdb.python/py-recurse-unwind.exp +++ b/gdb/testsuite/gdb.python/py-recurse-unwind.exp @@ -35,7 +35,7 @@ if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } { set pyfile [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py] gdb_test "source ${pyfile}" "Python script imported" \ - "import python scripts" + "import python scripts" # The following tests require execution. diff --git a/gdb/testsuite/gdb.python/py-recurse-unwind.py b/gdb/testsuite/gdb.python/py-recurse-unwind.py index 244c693..51bc600 100644 --- a/gdb/testsuite/gdb.python/py-recurse-unwind.py +++ b/gdb/testsuite/gdb.python/py-recurse-unwind.py @@ -59,20 +59,15 @@ class TestUnwinder(Unwinder): TestUnwinder.inc_count() if TestUnwinder.test == "check_user_reg_pc": - pc = pending_frame.read_register("pc") - pc_as_int = int(pc.cast(gdb.lookup_type("int"))) - # gdb.write("In unwinder: pc=%x\n" % pc_as_int) + pending_frame.read_register("pc") elif TestUnwinder.test == "check_pae_pc": - pc = gdb.parse_and_eval("$pc") - pc_as_int = int(pc.cast(gdb.lookup_type("int"))) - # gdb.write("In unwinder: pc=%x\n" % pc_as_int) + gdb.parse_and_eval("$pc") elif TestUnwinder.test == "check_undefined_symbol": try: - val = gdb.parse_and_eval("undefined_symbol") - - except Exception as arg: + gdb.parse_and_eval("undefined_symbol") + except Exception: pass self.recurse_level -= 1 diff --git a/gdb/testsuite/gdb.python/py-section-script.exp b/gdb/testsuite/gdb.python/py-section-script.exp index cc4425c..369c887 100644 --- a/gdb/testsuite/gdb.python/py-section-script.exp +++ b/gdb/testsuite/gdb.python/py-section-script.exp @@ -71,13 +71,13 @@ clean_restart # Get the name of the binfile on the host; on a remote host this means # stripping off any directory prefix. -if [is_remote host] { +if {[is_remote host]} { set remote_binfile [file tail ${binfile}] } else { set remote_binfile ${binfile} } -if [ishost *-*-mingw*] { +if {[ishost *-*-mingw*]} { set remote_pathsep ";" } else { set remote_pathsep ":" @@ -107,7 +107,7 @@ gdb_test "info auto-load python-scripts ${testfile}" "Yes.*${testfile}.py.*" gdb_test "info auto-load python-scripts no-script-matches-this" \ "No auto-load scripts matching no-script-matches-this." -if ![runto_main] { +if {![runto_main]} { return } @@ -126,7 +126,7 @@ gdb_test "test-cmd 1 2 3" "test-cmd output, arg = 1 2 3" with_test_prefix "sepdebug" { gdb_exit - set result [catch "exec eu-strip -g -f ${binfile}.debug ${binfile}" output] + set result [catch {exec eu-strip -g -f ${binfile}.debug ${binfile}} output] verbose "result is $result" verbose "output is $output" if {$result != 0 || $output != ""} { diff --git a/gdb/testsuite/gdb.python/py-section-script.py b/gdb/testsuite/gdb.python/py-section-script.py index d85221e..fb7bef3 100644 --- a/gdb/testsuite/gdb.python/py-section-script.py +++ b/gdb/testsuite/gdb.python/py-section-script.py @@ -17,6 +17,8 @@ import re +import gdb + class pp_ss: def __init__(self, val): diff --git a/gdb/testsuite/gdb.python/py-send-packet.py b/gdb/testsuite/gdb.python/py-send-packet.py index 0a0b359..7b852ed 100644 --- a/gdb/testsuite/gdb.python/py-send-packet.py +++ b/gdb/testsuite/gdb.python/py-send-packet.py @@ -65,7 +65,7 @@ def run_send_packet_test(): # find them, mark the ones we do find. for thr in threads_xml: id = thr.get("id") - if not id in all_threads: + if id not in all_threads: raise "found unexpected thread in remote thread list" else: all_threads[id] = True @@ -144,7 +144,7 @@ def run_set_global_var_test(): res = conn.send_packet("X%x,4:\xff\xff\xff\xff" % addr) except UnicodeError: saw_error = True - except: + except Exception: assert False assert saw_error diff --git a/gdb/testsuite/gdb.python/py-source-styling-2.exp b/gdb/testsuite/gdb.python/py-source-styling-2.exp index b13ee1f..ebf7f32 100644 --- a/gdb/testsuite/gdb.python/py-source-styling-2.exp +++ b/gdb/testsuite/gdb.python/py-source-styling-2.exp @@ -32,7 +32,9 @@ if { [build_executable "failed to build" $testfile $srcfile $opts] == -1 } { return } -clean_restart +with_ansi_styling_terminal { + clean_restart +} gdb_test_no_output "maint set gnu-source-highlight enabled off" @@ -40,16 +42,14 @@ gdb_load $binfile require {gdb_py_module_available pygments} -with_ansi_styling_terminal { - gdb_test_no_output "set style enabled on" - - gdb_test_multiple "list $line_number" "Styling of c++ keyword try" { - -re -wrap " try\r\n.*" { - # Unstyled. - fail $gdb_test_name - } - -re -wrap "" { - pass $gdb_test_name - } +gdb_test_no_output "set style enabled on" + +gdb_test_multiple "list $line_number" "Styling of c++ keyword try" { + -re -wrap " try\r\n.*" { + # Unstyled. + fail $gdb_test_name + } + -re -wrap "" { + pass $gdb_test_name } } diff --git a/gdb/testsuite/gdb.python/py-source-styling.exp b/gdb/testsuite/gdb.python/py-source-styling.exp index 308053c..e030768 100644 --- a/gdb/testsuite/gdb.python/py-source-styling.exp +++ b/gdb/testsuite/gdb.python/py-source-styling.exp @@ -62,7 +62,7 @@ proc check_source_listing_styling { cmd expect_styled { testname "" } } { # highlighting when GNU source highlight is not available (or is # disabled, as is done in this test). proc test_pygments_styling {} { - clean_restart $::binfile + clean_restart $::testfile # Remote host boards disable styling via GDB's command line. Turn # it back on now. @@ -75,7 +75,7 @@ proc test_pygments_styling {} { return } - if ![runto_main] { + if {![runto_main]} { return } @@ -91,7 +91,7 @@ proc test_pygments_styling {} { # string, then set the correct host encoding, and try again. This # time the conversion should succeed. proc test_gdb_execute_non_utf8_source {} { - clean_restart $::binfile + clean_restart $::testfile # The default host charset is utf-8, the source code contains a # non-utf-8 character, so this will fail. @@ -117,7 +117,7 @@ proc test_gdb_execute_non_utf8_source {} { # output to be returned via a string, and in other cases we ask for # the output to be sent straight to stdout. proc_with_prefix test_source_cache_style_tracking {} { - clean_restart $::binfile + clean_restart $::testfile # Remote host boards disable styling via GDB's command line. Turn # it back on now. diff --git a/gdb/testsuite/gdb.python/py-startup-opt.exp b/gdb/testsuite/gdb.python/py-startup-opt.exp index 7410706..929c64d 100644 --- a/gdb/testsuite/gdb.python/py-startup-opt.exp +++ b/gdb/testsuite/gdb.python/py-startup-opt.exp @@ -17,6 +17,7 @@ # initialized. require allow_python_tests +require {!is_remote host} # Return a list containing two directory paths for newly created home # directories. diff --git a/gdb/testsuite/gdb.python/py-strfns.exp b/gdb/testsuite/gdb.python/py-strfns.exp index 2b5dff19..13b8d2e 100644 --- a/gdb/testsuite/gdb.python/py-strfns.exp +++ b/gdb/testsuite/gdb.python/py-strfns.exp @@ -26,7 +26,7 @@ if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } { return -1 } -if ![runto_main] { +if {![runto_main]} { return 0 } diff --git a/gdb/testsuite/gdb.python/py-style-parameter-set.exp b/gdb/testsuite/gdb.python/py-style-parameter-set.exp new file mode 100644 index 0000000..73d94d1 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-style-parameter-set.exp @@ -0,0 +1,366 @@ +# Copyright (C) 2025 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 gdb.StyleParameterSet. + +load_lib gdb-python.exp + +require allow_python_tests + +# Create a regexp that can be used to match the output of a 'show style +# NAME' command. HAS_INTENSITY is a boolean and indicates if style NAME has +# an intensity attribute. +proc gen_show_style_re { name has_intensity } { + set output \ + [list \ + "style ${name} background: The \"${name}\" style background color is: none" \ + "style ${name} foreground: The \"${name}\" style foreground color is: none"] + + if { $has_intensity } { + lappend output \ + "style ${name} intensity: The \"${name}\" style display intensity is: normal" + } + + return [multi_line {*}$output] +} + +# Create a regexp to match against the output of a 'set style NAME' command, +# that is, a 'set' command that doesn't actually set an attribute of a +# style, in this case GDB will print some useful help text. HAS_INTENSITY is +# a boolean and indicates if style NAME has an intensity attribute or not. +proc gen_set_style_re { name has_intensity } { + set output \ + [list \ + "List of \"set style $name\" subcommands:" \ + "" \ + "set style $name background -- Set the background color for this property\\." \ + "set style $name foreground -- Set the foreground color for this property\\."] + + if { $has_intensity } { + lappend output \ + "set style $name intensity -- Set the display intensity for this property\\." + } + + lappend output \ + "" \ + "Type \"help set style $name\" followed by subcommand name for full documentation\\." \ + "Type \"apropos word\" to search for commands related to \"word\"\\." \ + "Type \"apropos -v word\" for full documentation of commands related to \"word\"\\." \ + "Command name abbreviations are allowed if unambiguous\\." + + return [multi_line {*}$output] +} + +# Create a regexp to match against the output of a 'help show style NAME' +# command. HAS_INTENSITY is a boolean and indicates if style NAME has an +# intensity attribute or not. DOC is a regexp that matches the doc string +# for style NAME. +proc gen_help_show_style_re { name has_intensity doc } { + set output \ + [list \ + $doc \ + "" \ + "List of \"show style ${name}\" subcommands:" \ + "" \ + "show style $name background -- Show the background color for this property\\." \ + "show style $name foreground -- Show the foreground color for this property\\."] + if { $has_intensity } { + lappend output \ + "show style $name intensity -- Show the display intensity for this property\\." + } + + lappend output \ + "" \ + "Type \"help show style $name\" followed by subcommand name for full documentation\\." \ + "Type \"apropos word\" to search for commands related to \"word\"\\." \ + "Type \"apropos -v word\" for full documentation of commands related to \"word\"\\." \ + "Command name abbreviations are allowed if unambiguous\\." + + return [multi_line {*}$output] +} + +# Create a regexp to match against the output of a 'help set style NAME' +# command. HAS_INTENSITY is a boolean and indicates if style NAME has an +# intensity attribute or not. DOC is a regexp that matches the doc string +# for style NAME. +proc gen_help_set_style_re { name has_intensity doc } { + return \ + [multi_line \ + $doc \ + "" \ + [gen_set_style_re $name $has_intensity]] +} + +# Create styles with and without intensity. Use named and unnamed +# argument passing, and vary the argument passing order. Create +# styles with and without documentation. +# +# Confirm that the styles contain the expected sub-commands, and that +# the documentation is as expected. +proc_with_prefix test_basic_usage {} { + gdb_test_no_output \ + "python style_1 = gdb.StyleParameterSet(\"style-1\")" \ + "create style-1" + + gdb_test_no_output \ + "python style_2 = gdb.StyleParameterSet(add_intensity=True, name=\"style-2\")" \ + "create style-2" + + gdb_test_no_output \ + "python style_3 = gdb.StyleParameterSet(name=\"style-3\", doc=\"Style-3 display styling.\\nThis is a multi-line documentation\\nstring describing style-3.\")" \ + "create style-3" + + gdb_test_no_output \ + "python style_4 = gdb.StyleParameterSet(\"style-4\", add_intensity=False)" \ + "create style-4" + + foreach style { style-1 style-2 style-3 } { + gdb_test "show style $style" \ + [gen_show_style_re $style true] + gdb_test "set style $style" \ + [gen_set_style_re $style true] + } + + gdb_test "show style style-4" \ + [gen_show_style_re "style-4" false] + + foreach style { style-1 style-2 } { + gdb_test "help show style $style" \ + [gen_help_show_style_re $style true \ + [multi_line \ + "The $style display styling\\." \ + "Configure $style colors and display intensity\\."]] + + + set out [gen_help_set_style_re $style true \ + [multi_line \ + "The $style display styling\\." \ + "Configure $style colors and display intensity\\."]] + + gdb_test "help set style $style" \ + [gen_help_set_style_re $style true \ + [multi_line \ + "The $style display styling\\." \ + "Configure $style colors and display intensity\\."]] + } + + gdb_test "help show style style-3" \ + [gen_help_show_style_re "style-3" true \ + [multi_line \ + "Style-3 display styling\\." \ + "This is a multi-line documentation" \ + "string describing style-3\\."]] + + gdb_test "help show style style-4" \ + [gen_help_show_style_re "style-4" false \ + [multi_line \ + "The style-4 display styling\\." \ + "Configure style-4 colors and display intensity\\."]] + + for { set i 1 } { $i < 5 } { incr i } { + gdb_test "python print(style_$i)" \ + "<gdb.StyleParameterSet name='style-$i'>" \ + "print repr of style_$i" + } + + # There is no 'style-4 intensity' property. + gdb_test "show style style-4 foreground" \ + "The \"style-4\" style foreground color is: none" + gdb_test "show style style-4 background" \ + "The \"style-4\" style background color is: none" + gdb_test "show style style-4 intensity" \ + "Undefined show style style-4 command: \"intensity\"\\. Try \"help show style style-4\"\\." + + # There is a 'style-1 intensity' property. + gdb_test "show style style-1 foreground" \ + "The \"style-1\" style foreground color is: none" \ + "show style-1 foreground before changes" + gdb_test "show style style-1 background" \ + "The \"style-1\" style background color is: none" \ + "show style-1 background before changes" + gdb_test "show style style-1 intensity" \ + "The \"style-1\" style display intensity is: normal" \ + "show style-1 intensity before changes" + + # Grab the gdb.Style objects from 'style-1'. + gdb_test_no_output "python s1 = style_1.style" + gdb_test_no_output "python s2 = style_1.value" + + # Check both represent the same style. + gdb_test "python print(s1)" \ + "<gdb.Style name='style-1', fg=none, bg=none, intensity=normal>" \ + "print s1 style before changes" + gdb_test "python print(s2)" \ + "<gdb.Style name='style-1', fg=none, bg=none, intensity=normal>" \ + "print s2 style before changes" + + gdb_test_no_output \ + "python s1.foreground=gdb.Color('red')" "set foreground" + gdb_test_no_output \ + "python s1.background=gdb.Color('blue')" "set background" + gdb_test_no_output \ + "python s1.intensity=gdb.INTENSITY_DIM" "set intensity" + + gdb_test "python print(s1)" \ + "<gdb.Style name='style-1', fg=red, bg=blue, intensity=dim>" \ + "print s1 style after first set of changes" + gdb_test "python print(s2)" \ + "<gdb.Style name='style-1', fg=red, bg=blue, intensity=dim>" \ + "print s2 style after first set of changes" + + # Check the style properties have updated. + gdb_test "show style style-1 foreground" \ + "The \"style-1\" style foreground color is: red" \ + "show style-1 foreground after first set of changes" + gdb_test "show style style-1 background" \ + "The \"style-1\" style background color is: blue" \ + "show style-1 background after first set of changes" + gdb_test "show style style-1 intensity" \ + "The \"style-1\" style display intensity is: dim" \ + "show style-1 intensity after first set of changes" + + # Change the style properties, check gdb.Style objects update. + gdb_test_no_output "set style style-1 foreground yellow" + gdb_test_no_output "set style style-1 background cyan" + gdb_test_no_output "set style style-1 intensity bold" + + gdb_test "python print(s1)" \ + "<gdb.Style name='style-1', fg=yellow, bg=cyan, intensity=bold>" \ + "print s1 style after second set of changes" + gdb_test "python print(s2)" \ + "<gdb.Style name='style-1', fg=yellow, bg=cyan, intensity=bold>" \ + "print s2 style after second set of changes" + + # Assign a gdb.Style to set 'style-1'. First create some unnamed + # style objects that can be used. + gdb_test_no_output \ + "python uns1 = gdb.Style(foreground=gdb.Color('white'), background=gdb.Color('black'), intensity=gdb.INTENSITY_BOLD)" \ + "create uns1" + gdb_test_no_output \ + "python uns2 = gdb.Style(foreground=gdb.Color('black'), background=gdb.Color('white'), intensity=gdb.INTENSITY_DIM)" \ + "create uns2" + + gdb_test_no_output "python style_1.value = uns1" + gdb_test "show style style-1 foreground" \ + "The \"style-1\" style foreground color is: white" \ + "show style-1 foreground after assigning uns1" + gdb_test "show style style-1 background" \ + "The \"style-1\" style background color is: black" \ + "show style-1 background after assigning uns1" + gdb_test "show style style-1 intensity" \ + "The \"style-1\" style display intensity is: bold" \ + "show style-1 intensity after assigning uns1" + + gdb_test_no_output "python style_1.style = uns2" + gdb_test "show style style-1 foreground" \ + "The \"style-1\" style foreground color is: black" \ + "show style-1 foreground after assigning uns2" + gdb_test "show style style-1 background" \ + "The \"style-1\" style background color is: white" \ + "show style-1 background after assigning uns2" + gdb_test "show style style-1 intensity" \ + "The \"style-1\" style display intensity is: dim" \ + "show style-1 intensity after assigning uns2" + + # Assign a style with an intensity that is not 'NORMAL' to a + # StyleParameterSet that doesn't have an intensity. The new + # intensity setting should be ignored. + gdb_test_no_output "python style_4.style = uns1" + gdb_test "show style style-4 foreground" \ + "The \"style-4\" style foreground color is: white" \ + "show style-4 foreground after assigning uns1" + gdb_test "show style style-4 background" \ + "The \"style-4\" style background color is: black" \ + "show style-4 background after assigning uns1" + gdb_test "show style style-4 intensity" \ + "Undefined show style style-4 command: \"intensity\"\\. Try \"help show style style-4\"\\." \ + "show style-4 intensity after assigning uns1" + + gdb_test "python print(style_4.style)" \ + "<gdb.Style name='style-4', fg=white, bg=black, intensity=normal>" \ + "print string repr of style_4's style" +} + +# Test creating a style prefix with gdb.ParameterPrefix, then adding +# some styles within the new prefix. Change the style through the CLI +# and confirm that the associated Python object updated as expected. +proc_with_prefix test_style_prefix {} { + gdb_test_no_output \ + "python gdb.ParameterPrefix(\"style my-style-group\", gdb.COMMAND_NONE)" + gdb_test_no_output \ + "python style_1 = gdb.StyleParameterSet(\"my-style-group style-1\")" \ + "create style-1" + gdb_test_no_output \ + "python style_2 = gdb.StyleParameterSet(\"my-style-group style-2\")" \ + "create style-2" + + gdb_test "python print(style_1.style)" \ + "<gdb.Style name='my-style-group style-1', fg=none, bg=none, intensity=normal>" \ + "print 'my-style-group style-1' style before changes" + gdb_test "python print(style_2.style)" \ + "<gdb.Style name='my-style-group style-2', fg=none, bg=none, intensity=normal>" \ + "print 'my-style-group style-2' style before changes" + + gdb_test_no_output "set style my-style-group style-1 foreground red" + gdb_test_no_output "set style my-style-group style-1 background yellow" + gdb_test_no_output "set style my-style-group style-1 intensity bold" + gdb_test_no_output "set style my-style-group style-2 foreground black" + gdb_test_no_output "set style my-style-group style-2 background blue" + gdb_test_no_output "set style my-style-group style-2 intensity dim" + + gdb_test "python print(style_1.style)" \ + "<gdb.Style name='my-style-group style-1', fg=red, bg=yellow, intensity=bold>" \ + "print 'my-style-group style-1' style after changes" + gdb_test "python print(style_2.style)" \ + "<gdb.Style name='my-style-group style-2', fg=black, bg=blue, intensity=dim>" \ + "print 'my-style-group style-2' style after changes" +} + +# Test that gdb.StyleParameterSet.apply() works as expected. +proc_with_prefix test_applying {} { + # Create a new StyleParameterSet, and adjust its settings. + gdb_test_no_output \ + "python style_1 = gdb.StyleParameterSet(\"style-1\")" \ + "create style-1" + gdb_test_no_output \ + "python uns1 = gdb.Style(foreground=gdb.Color('red'), background=gdb.Color('blue'), intensity=gdb.INTENSITY_BOLD)" \ + "create uns1" + gdb_test_no_output "python style_1 = uns1" + + # When styling is off (which it currently is), no escape sequences + # should be added. + gdb_test \ + "python print(style_1.apply('xxx'))" "^xxx" \ + "apply StyleParameterSet to a string when styling is off" + + # When styling is on, we should see an escape sequence added. + gdb_test "with style enabled on -- python print(style_1.apply('xxx'))" \ + "\033\\\[31;44;1;23;24;27mxxx\033\\\[m" \ + "apply a style when styling is on" +} + +# Start GDB. +with_ansi_styling_terminal { + clean_restart +} + +# Turn styling off so that the output of 'show style ...' isn't styled, this +# makes it easier to match the output. +gdb_test_no_output "set style enabled off" + +# Run the tests. +test_basic_usage +test_style_prefix +test_applying diff --git a/gdb/testsuite/gdb.python/py-style.exp b/gdb/testsuite/gdb.python/py-style.exp new file mode 100644 index 0000000..491e189 --- /dev/null +++ b/gdb/testsuite/gdb.python/py-style.exp @@ -0,0 +1,371 @@ +# Copyright (C) 2025 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 gdb.Style. + +load_lib gdb-python.exp + +require allow_python_tests + +# Start GDB, allow styling. +with_ansi_styling_terminal { + clean_restart +} + +# Check the error for unknown style names. +foreach unknown_style { "unknown-style" "disassembler unknown-style" } { + gdb_test "python filename_style = gdb.Style('$unknown_style')" \ + [multi_line \ + "Python Exception <class 'RuntimeError'>: style '$unknown_style' cannot be found\\." \ + "Error occurred in Python: style '$unknown_style' cannot be found\\."] \ + "attempt to create named style for '$unknown_style'" +} + +# Check we can create a style using an abbreviated style name. +gdb_test_no_output "python abbrev_style = gdb.Style('high')" \ + "create style using abbreviated name 'high'" +gdb_test "python print(abbrev_style)" \ + "^<gdb.Style name='highlight', fg=red, bg=none, intensity=normal>" \ + "print the 'highlight' style" + +gdb_test_no_output "python abbrev_style = gdb.Style('disas mnem')" \ + "create style using abbreviated name 'disas mnem'" +gdb_test "python print(abbrev_style)" \ + "^<gdb.Style name='disassembler mnemonic', fg=green, bg=none, intensity=normal>" \ + "print the 'disassembler mnemonic' style" + +# Creating a style using an ambiguous abbreviated name will give an error. +gdb_test "python abbrev_style = gdb.Style('f')" \ + [multi_line \ + "Python Exception <class 'RuntimeError'>: style 'f' cannot be found\\." \ + "Error occurred in Python: style 'f' cannot be found\\."] \ + "create style using abbreviated name 'f'" + +# Check a couple of different styles can be read. The 'tui-border' is +# interesting as there is no 'intensity' for this one, the gdb.Style +# object will show this as gdb.INTENSITY_NORMAL. The disassembler +# styles are interesting because they are two word style names, and +# the comment style has a foreground and intensity set. +foreach style_check { { "filename" green none NORMAL } \ + { "title" none none BOLD } \ + { "tui-border" cyan none NORMAL } \ + { "disassembler address" blue none NORMAL } \ + { "disassembler comment" white none DIM } } { + set style_name [lindex $style_check 0] + set fg [lindex $style_check 1] + set bg [lindex $style_check 2] + set intensity [lindex $style_check 3] + + with_test_prefix "check style $style_name" { + gdb_test_no_output "python style_obj = gdb.Style('$style_name')" \ + "create named style for $style_name" + + gdb_test "python print(style_obj.foreground)" "^$fg" \ + "print foreground color" + gdb_test "python print(style_obj.background)" "^$bg" \ + "print background color" + gdb_test "python print(style_obj.intensity == gdb.INTENSITY_$intensity)" \ + "^True" "print intensity" + + gdb_test "python print(style_obj)" \ + "^<gdb.Style name='$style_name', fg=$fg, bg=$bg, intensity=[string tolower $intensity]>" \ + "print string representation" + } +} + +# Check that the intensity of a named style with no intensity +# (tui-border) cannot be changed. +gdb_test_no_output "python tui_border_style = gdb.Style('tui-border')" \ + "create named style for 'tui-border'" +gdb_test "python tui_border_style.intensity = gdb.INTENSITY_BOLD" \ + [multi_line \ + "Python Exception <class 'ValueError'>: the intensity of style 'tui-border' is not writable\\." \ + "Error occurred in Python: the intensity of style 'tui-border' is not writable\\."] + +# Change the attributes of a named style, check the settings update as +# expected. +gdb_test_no_output "python filename_style = gdb.Style('filename')" \ + "create named style for 'filename'" +gdb_test_no_output "python filename_style.foreground = gdb.Color('blue')" \ + "assign blue to filename foreground color" +gdb_test_no_output "python filename_style.background = gdb.Color('red')" \ + "assign red to filename background color" +gdb_test_no_output "python filename_style.intensity = gdb.INTENSITY_BOLD" + +# Use 'with style enabled off' so that there are no escape sequences +# in the output. +gdb_test "with style enabled off -- show style filename" \ + [multi_line \ + "style filename background: The \"filename\" style background color is: red" \ + "style filename foreground: The \"filename\" style foreground color is: blue" \ + "style filename intensity: The \"filename\" style display intensity is: bold"] + +gdb_test "python print(filename_style)" \ + "^<gdb.Style name='filename', fg=blue, bg=red, intensity=bold>" \ + "print string representation of filename_style" + +# Check some attempts to set the gdb.Style attributes to invalid types. +foreach attr { foreground background } { + gdb_test "python filename_style.$attr = None" \ + [multi_line \ + "Python Exception <class 'TypeError'>: value must be gdb.Color, not NoneType" \ + "Error occurred in Python: value must be gdb.Color, not NoneType"] + + gdb_test "python filename_style.$attr = list()" \ + [multi_line \ + "Python Exception <class 'TypeError'>: value must be gdb.Color, not list" \ + "Error occurred in Python: value must be gdb.Color, not list"] + + gdb_test "python filename_style.$attr = 'red'" \ + [multi_line \ + "Python Exception <class 'TypeError'>: value must be gdb.Color, not str" \ + "Error occurred in Python: value must be gdb.Color, not str"] +} + +gdb_test "python filename_style.intensity = None" \ + [multi_line \ + "Python Exception <class 'TypeError'>: value must be a Long \\(a gdb.INTENSITY constant\\), not NoneType" \ + "Error occurred in Python: value must be a Long \\(a gdb.INTENSITY constant\\), not NoneType"] + +gdb_test "python filename_style.intensity = 'dim'" \ + [multi_line \ + "Python Exception <class 'TypeError'>: value must be a Long \\(a gdb.INTENSITY constant\\), not str" \ + "Error occurred in Python: value must be a Long \\(a gdb.INTENSITY constant\\), not str"] + +# Check attempts to set the intensity to an integer value work as +# expected. This is mostly about testing invalid integer values, but +# we do also check that 0, 1, and 2 work as expected, though it is bad +# practice to use the raw integer value rather than the defined +# constants. +set intensity_str { NORMAL BOLD DIM } +for { set i -3 } { $i < 6 } { incr i } { + if { $i < 0 || $i > 2 } { + gdb_test "python filename_style.intensity = $i" \ + [multi_line \ + "Python Exception <class 'ValueError'>: invalid 'intensity' value $i\\." \ + "Error occurred in Python: invalid 'intensity' value $i\\."] + } else { + gdb_test_no_output "python filename_style.intensity = $i" + + set str [lindex $intensity_str $i] + gdb_test "python print(filename_style.intensity == gdb.INTENSITY_$str)" \ + "^True" "check filename_style intensity is $str" + } +} + +# Check the filename style has changed as expected. +gdb_test "python print(filename_style)" \ + "^<gdb.Style name='filename', fg=blue, bg=red, intensity=dim>" \ + "check filename_style is now dim" + +# Check Style.escape_sequence and Style.apply when styling is disabled. +gdb_test_no_output "with style enabled off -- python print(filename_style.escape_sequence(), end='')" \ + "print escape sequence when styling is off" +gdb_test "with style enabled off -- python print(filename_style.apply('xxx'))" "^xxx" \ + "apply style to a string when styling is off" + +# Now check the escape sequences are emitted as expected. +gdb_test "python print(filename_style.escape_sequence())" \ + "\033\\\[34;41;2;23;24;27m" \ + "print escape sequence when styling is on" +gdb_test "python print(filename_style.apply('xxx'))" \ + "\033\\\[34;41;2;23;24;27mxxx\033\\\[m" \ + "apply a style when styling is on" + +# Test creating a style from component parts. +gdb_test_no_output "python my_style_1 = gdb.Style(gdb.Color('red'), gdb.Color('blue'), gdb.INTENSITY_BOLD)" \ + "create my_style_1" +gdb_test "python print(my_style_1)" \ + "^<gdb.Style fg=red, bg=blue, intensity=bold>" \ + "check my_style_1" + +gdb_test_no_output "python my_style_2 = gdb.Style(background = gdb.Color('blue'))" \ + "create my_style_2" +gdb_test "python print(my_style_2)" \ + "^<gdb.Style fg=none, bg=blue, intensity=normal>" \ + "check my_style_2" + +gdb_test_no_output "python my_style_3 = gdb.Style(intensity = gdb.INTENSITY_DIM)" \ + "create my_style_3" +gdb_test "python print(my_style_3)" \ + "^<gdb.Style fg=none, bg=none, intensity=dim>" \ + "check my_style_3" + +# The precise error message, about 'None' not being an integer, varies +# with Python version. We just check that we get a TypeError and +# assume that this is related to the argument type. +gdb_test "python my_style_4 = gdb.Style(intensity = None)" \ + [multi_line \ + "Python Exception <class 'TypeError'>: \[^\r\n\]+" \ + "Error occurred in Python: \[^\r\n\]+"] \ + "attempt to create my_style_4" + +gdb_test "python my_style_5 = gdb.Style(foreground = list())" \ + [multi_line \ + "Python Exception <class 'TypeError'>: 'foreground' argument must be gdb.Color or None, not list\\." \ + "Error occurred in Python: 'foreground' argument must be gdb.Color or None, not list\\."] \ + "attempt to create my_style_5" + +gdb_test "python my_style_6 = gdb.Style(background = list())" \ + [multi_line \ + "Python Exception <class 'TypeError'>: 'background' argument must be gdb.Color or None, not list\\." \ + "Error occurred in Python: 'background' argument must be gdb.Color or None, not list\\."] \ + "attempt to create my_style_6" + +# Adjust the attributes of an unnamed style. +gdb_test_no_output "python my_style_1.foreground = gdb.Color('green')" \ + "change my_style_1.foreground to green" +gdb_test_no_output "python my_style_1.background = gdb.Color('cyan')" \ + "change my_style_1.background to cyan" +gdb_test_no_output "python my_style_1.intensity = gdb.INTENSITY_DIM" \ + "change my_style_1.intensity to dim" +gdb_test "python print(my_style_1)" \ + "^<gdb.Style fg=green, bg=cyan, intensity=dim>" \ + "check my_style_1 after changes." + +# Setup some prefix commands under 'set/show style ...'. Each prefix +# command is called 'new-style-X' where X is an integer; 1, 2, 3, or 4. +for { set i 1 } { $i < 5 } { incr i } { + gdb_test_no_output "python gdb.Command('set style new-style-$i', gdb.COMMAND_NONE, prefix = True)" \ + "create set style new-style-$i" + gdb_test_no_output "python gdb.Command('show style new-style-$i', gdb.COMMAND_NONE, prefix = True)" \ + "create show style new-style-$i" +} + +# A helper class for creating color settings under the 'new-style-X' +# prefix commands. The NUM to the __init__ supplies the value of +# 'X', and NAME is either 'foreground' or 'background'. +gdb_test_multiline "Class to create color parameters" \ + "python" "" \ + "class color_param(gdb.Parameter):" "" \ + " def __init__(self, num, name):" "" \ + " super().__init__(f\"style new-style-{num} {name}\", gdb.COMMAND_NONE, gdb.PARAM_COLOR)" "" \ + " self.value = gdb.Color()" "" \ + "end" "" + +# A helper class for creating intensity settings under the new +# 'new-style-X' prefix commands. The NUM in the __init__ supplies the +# value of 'X'. +gdb_test_multiline "Class to create intensity parameters" \ + "python" "" \ + "class intensity_param(gdb.Parameter):" "" \ + " def __init__(self, num):" "" \ + " super().__init__(f\"style new-style-{num} intensity\", gdb.COMMAND_NONE, gdb.PARAM_ENUM," "" \ + " \[\"normal\", \"bold\", \"dim\"\])" "" \ + " self.value = \"normal\"" "" \ + "end" "" + +# Within 'style new-style-1' we only have a 'foreground' setting. +# This will not be usable as a gdb.Style. +gdb_test_no_output "python color_param(1, 'foreground')" \ + "setup new-style-1 foreground" + +# Within 'style new-style-2' we only have a 'background' setting. +# This will not be usable as a gdb.Style. +gdb_test_no_output "python color_param(2, 'background')" \ + "setup new-style-2 background" + +# Within 'style new-style-3' we have both a 'foreground' and +# 'background' setting. Even though 'intensity' is missing, this is +# still usable as a style. +gdb_test_no_output "python color_param(3, 'foreground')" \ + "setup new-style-3 foreground" +gdb_test_no_output "python color_param(3, 'background')" \ + "setup new-style-3 background" + +# Within 'style new-style-4' we have a 'foreground', 'background', and +# 'intensity' setting. This is a complete style setting group. +gdb_test_no_output "python color_param(4, 'foreground')" \ + "setup new-style-4 foreground" +gdb_test_no_output "python color_param(4, 'background')" \ + "setup new-style-4 background" +gdb_test_no_output "python intensity_param(4)" \ + "setup new-style-4 intensity" + +# Trying to create a style for 'new-style-1' should fail. +gdb_test "python my_style_7 = gdb.Style('new-style-1')" \ + [multi_line \ + "Python Exception <class 'RuntimeError'>: style 'new-style-1' missing 'background' component\\." \ + "Error occurred in Python: style 'new-style-1' missing 'background' component\\."] \ + "try to create style for new-style-1" + +# Trying to create a style for 'new-style-2' should fail. +gdb_test "python my_style_8 = gdb.Style('new-style-2')" \ + [multi_line \ + "Python Exception <class 'RuntimeError'>: style 'new-style-2' missing 'foreground' component\\." \ + "Error occurred in Python: style 'new-style-2' missing 'foreground' component\\."] \ + "try to create style for new-style-2" + +# Trying to create a style for 'new-style-3' should succeed. +gdb_test_no_output "python my_style_9 = gdb.Style('new-style-3')" \ + "create a style for new-style-3" +gdb_test "python print(my_style_9)" \ + "^<gdb.Style name='new-style-3', fg=none, bg=none, intensity=normal>" \ + "print my_style_9" + +# Trying to create a style for 'new-style-4' should succeed too. +gdb_test_no_output "python my_style_10 = gdb.Style('new-style-4')" \ + "create a style for new-style-4" +gdb_test "python print(my_style_10)" \ + "^<gdb.Style name='new-style-4', fg=none, bg=none, intensity=normal>" \ + "print my_style_10" + +# Adjust the settings directly, and check the gdb.Style updates. +gdb_test_no_output "set style new-style-4 intensity bold" +gdb_test_no_output "set style new-style-4 foreground red" +gdb_test_no_output "set style new-style-4 background blue" +gdb_test "python print(my_style_10)" \ + "^<gdb.Style name='new-style-4', fg=red, bg=blue, intensity=bold>" \ + "print my_style_10, intensity updated" + +# Check the reference counting on 'gdb.Style.apply' when global styling is disabled. +gdb_test_no_output "python input_text = \"this is a unique string that is unlikely to appear elsewhere 12345\"" \ + "setup an input string" +gdb_test_no_output "with style enabled off -- python output_text = filename_style.apply(input_text)" \ + "create an ouput string by applying filename_style" +gdb_test_no_output "python input_text = \"a totally different string that is also, hopefully, unique\"" \ + "replace the input string" +gdb_test "python print(output_text)" \ + "^this is a unique string that is unlikely to appear elsewhere 12345" \ + "check the output_text is still valid" + +# Test gdb.write passing in a style. Define a helper function to +# ensure all output is flushed before we return to the prompt. +gdb_test_multiline "create function to call gdb.write then flush" \ + "python" "" \ + "def write_and_flush(*args, **kwargs):" "" \ + " gdb.write(*args, **kwargs)" "" \ + " gdb.write(\"\\n\")" "" \ + " gdb.flush(gdb.STDOUT)" "" \ + "end" "" + +gdb_test "python write_and_flush(\"some text\")" \ + "^some text" "unstyled text, no style passed" + +gdb_test "python write_and_flush(\"some text\", style=None)" \ + "^some text" "unstyled text, pass style as None" + +gdb_test "python write_and_flush(\"some text\", style=filename_style)" \ + "^\033\\\[34;41;2;23;24;27msome text\033\\\[m" \ + "styled output, pass style by keyword" + +gdb_test "python write_and_flush(\"some text\", gdb.STDOUT, filename_style)" \ + "^\033\\\[34;41;2;23;24;27msome text\033\\\[m" \ + "styled output, pass style by position" + +gdb_test "python write_and_flush(\"some text\", style='filename')" \ + [multi_line \ + "Python Exception <class 'TypeError'>: 'style' argument must be gdb\\.Style or None, not str\\." \ + "Error occurred in Python: 'style' argument must be gdb\\.Style or None, not str\\."] diff --git a/gdb/testsuite/gdb.python/py-styled-execute.exp b/gdb/testsuite/gdb.python/py-styled-execute.exp index 0b27c63..198dab5 100644 --- a/gdb/testsuite/gdb.python/py-styled-execute.exp +++ b/gdb/testsuite/gdb.python/py-styled-execute.exp @@ -17,6 +17,7 @@ # on the value of the third argument passed to gdb.execute. require allow_python_tests +require {!is_remote host} load_lib gdb-python.exp diff --git a/gdb/testsuite/gdb.python/py-sym-artificial.exp b/gdb/testsuite/gdb.python/py-sym-artificial.exp index e26e9d2..831ebd2 100644 --- a/gdb/testsuite/gdb.python/py-sym-artificial.exp +++ b/gdb/testsuite/gdb.python/py-sym-artificial.exp @@ -27,21 +27,21 @@ set asm_file [standard_output_file ${srcfile2}] Dwarf::assemble $asm_file { cu {} { compile_unit { - {language @DW_LANG_C} - {name py-sym-artificial.c} + DW_AT_language @DW_LANG_C + DW_AT_name py-sym-artificial.c } { declare_labels signed signed: DW_TAG_base_type { - {DW_AT_byte_size 1 DW_FORM_sdata} - {DW_AT_encoding @DW_ATE_signed} - {DW_AT_name bool} + DW_AT_byte_size 1 DW_FORM_sdata + DW_AT_encoding @DW_ATE_signed + DW_AT_name bool } DW_TAG_variable { - {name the_variable} - {DW_AT_type :$signed} - {artificial 1 DW_FORM_flag_present} + DW_AT_name the_variable + DW_AT_type :$signed + DW_AT_artificial 1 DW_FORM_flag_present } } } diff --git a/gdb/testsuite/gdb.python/py-symbol.exp b/gdb/testsuite/gdb.python/py-symbol.exp index 55cdebe..6f0fcee 100644 --- a/gdb/testsuite/gdb.python/py-symbol.exp +++ b/gdb/testsuite/gdb.python/py-symbol.exp @@ -44,7 +44,7 @@ if {!$readnow_p} { } # Restart so we don't have expanded symtabs after the previous test. -clean_restart ${binfile} +clean_restart ${::testfile} # Test looking up a global symbol before we runto_main as this is the # point where we don't have a current frame, and we don't want to @@ -70,37 +70,14 @@ gdb_test "python print (gdb.lookup_global_symbol('qq').needs_frame)" \ "print whether qq needs a frame" # Similarly, test looking up a static symbol before we runto_main. -set rr_line [gdb_get_line_number "line of rr"] -set rr_line_alt [gdb_get_line_number "line of other rr" py-symbol-2.c] gdb_test "python print (gdb.lookup_global_symbol ('qqrr') is None)" "True" \ "lookup_global_symbol for static var" -set cmd "python print (gdb.lookup_static_symbol ('rr').line)" -gdb_test_multiple $cmd "print line number of rr" { - -re -wrap "$rr_line" { - pass $gdb_test_name - } - -re -wrap "$rr_line_alt" { - if { $readnow_p } { - setup_kfail "symtab/25857" *-*-* - } - fail $gdb_test_name - } -} - -set cmd "python print (gdb.lookup_static_symbol ('rr').value ())" -gdb_test_multiple $cmd "print value of rr" { - -re -wrap "42" { - pass $gdb_test_name - } - -re -wrap "99" { - if { $readnow_p } { - setup_kfail "symtab/25857" *-*-* - } - fail $gdb_test_name - } -} - +# Either "rr" static symbol is a valid result. +set rr_line_1 [gdb_get_line_number "line of rr"] +set rr_line_2 [gdb_get_line_number "line of other rr" py-symbol-2.c] +gdb_test "python print (gdb.lookup_static_symbol ('rr').line)" "($rr_line_1|$rr_line_2)" +gdb_test "python print (gdb.lookup_static_symbol ('rr').value ())" "(42|99)" gdb_test "python print (gdb.lookup_static_symbol ('rr').needs_frame)" \ "False" \ @@ -215,8 +192,10 @@ gdb_test "python print (t\[0\].symtab)" "${py_symbol_c}" "get symtab" # C++ tests # Recompile binary. lappend opts c++ -if {[prepare_for_testing "failed to prepare" "${binfile}-cxx" \ - [list $srcfile $srcfile2] $opts]} { +set testfile $testfile-cxx +set binfile [standard_output_file $testfile] +if { [prepare_for_testing "failed to prepare" $testfile \ + [list $srcfile $srcfile2] $opts] } { return -1 } @@ -252,7 +231,7 @@ gdb_test "python print (cplusfunc.addr_class == gdb.SYMBOL_LOC_BLOCK)" "True" "t # Test is_valid when the objfile is unloaded. This must be the last # test as it unloads the object file in GDB. # Start with a fresh gdb. -clean_restart ${binfile} +clean_restart ${::testfile} if {![runto_main]} { return 0 } diff --git a/gdb/testsuite/gdb.python/py-template.exp b/gdb/testsuite/gdb.python/py-template.exp index a0f9d80..251b478 100644 --- a/gdb/testsuite/gdb.python/py-template.exp +++ b/gdb/testsuite/gdb.python/py-template.exp @@ -31,7 +31,7 @@ proc test_template_arg {exefile type} { global testfile srcdir subdir srcfile if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${exefile}" \ executable \ - [list debug c++ additional_flags="-DTYPE=$type"]] != "" } { + [list debug c++ additional_flags="-DTYPE=$type"]] != "" } { untested $type return -1 } diff --git a/gdb/testsuite/gdb.python/py-thread-exited.exp b/gdb/testsuite/gdb.python/py-thread-exited.exp index dcacb11..0f47ce0 100644 --- a/gdb/testsuite/gdb.python/py-thread-exited.exp +++ b/gdb/testsuite/gdb.python/py-thread-exited.exp @@ -32,7 +32,7 @@ gdb_test_no_output "source ${pyfile}" "load python file" gdb_test "test-events" "Event testers registered." -if ![runto_main] { +if {![runto_main]} { return -1 } diff --git a/gdb/testsuite/gdb.python/py-thread-exited.py b/gdb/testsuite/gdb.python/py-thread-exited.py index ef5a244..f725bd5 100644 --- a/gdb/testsuite/gdb.python/py-thread-exited.py +++ b/gdb/testsuite/gdb.python/py-thread-exited.py @@ -26,6 +26,8 @@ def thread_exited_handler(event): global threadOneExit, threadTwoExit, mainThreadExit print("{}".format(event)) assert isinstance(event, gdb.ThreadExitedEvent) + # Also check the inheritance. + assert isinstance(event, gdb.ThreadEvent) if threadOneExit == "": threadOneExit = "event type: thread-exited. global num: {}".format( event.inferior_thread.global_num diff --git a/gdb/testsuite/gdb.python/py-thrhandle.exp b/gdb/testsuite/gdb.python/py-thrhandle.exp index 343bf4b..599473c 100644 --- a/gdb/testsuite/gdb.python/py-thrhandle.exp +++ b/gdb/testsuite/gdb.python/py-thrhandle.exp @@ -29,17 +29,17 @@ if {[gdb_compile_pthreads "${srcdir}/${subdir}/${srcfile}" "${binfile}" executab return -1 } -clean_restart ${binfile} +clean_restart ${::testfile} runto_main gdb_test "break after_mc_barrier" \ "Breakpoint 2 at .*: file .*${srcfile}, line .*" \ - "breakpoint on after_mc_barrier" + "breakpoint on after_mc_barrier" gdb_test "break do_something" \ "Breakpoint 3 at .*: file .*${srcfile}, line .*" \ - "breakpoint on do_something" + "breakpoint on do_something" gdb_test "continue" \ "Breakpoint 2, after_mc_barrier .*" \ @@ -90,19 +90,19 @@ gdb_test "python print(gdb.selected_inferior().thread_from_handle(gdb.parse_and_ # We should see an exception when passing an object of the wrong type. gdb_test "python print(gdb.selected_inferior().thread_from_handle(gdb.lookup_symbol('main')))" \ - ".*TypeError.*: Argument 'handle' must be a thread handle object.*" \ + ".*TypeError.*: Argument 'handle' must be a thread handle object.*" \ "TypeError when passing a symbol object to thread_from_handle" # We should see an exception when passing too large of an object. gdb_test "python print(gdb.selected_inferior().thread_from_handle(gdb.parse_and_eval('thrs')))" \ - ".*Thread handle size mismatch.*" \ + ".*Thread handle size mismatch.*" \ "Pass overly large object to thread_from_handle" # We should see an exception when passing too small of an object. gdb_test "python print(gdb.selected_inferior().thread_from_handle(gdb.parse_and_eval('\"S\"')))" \ - ".*Thread handle size mismatch.*" \ + ".*Thread handle size mismatch.*" \ "Pass too small of an object to thread_from_handle" # Test the thread_handle method @@ -134,8 +134,8 @@ foreach thrN {0 1 2} { # object into a gdb.value by calling the two argument form of # its constructor. - gdb_test "python print(gdb.Value(hand_bytes, tp) == hand)" \ - "True" \ - "verify that handles are the same" + gdb_test "python print(gdb.Value(hand_bytes, tp) == hand)" \ + "True" \ + "verify that handles are the same" } } diff --git a/gdb/testsuite/gdb.python/py-type.exp b/gdb/testsuite/gdb.python/py-type.exp index 0bc4556..4cef150 100644 --- a/gdb/testsuite/gdb.python/py-type.exp +++ b/gdb/testsuite/gdb.python/py-type.exp @@ -33,8 +33,9 @@ proc build_inferior {exefile lang} { } # Restart GDB. -proc restart_gdb {exefile} { - clean_restart $exefile +proc restart_gdb {exefile} { + clean_restart + gdb_load $exefile if {![runto_main]} { return @@ -53,7 +54,7 @@ proc test_fields {lang} { # .fields() of a typedef should still return the underlying field list gdb_test "python print (len(gdb.parse_and_eval('ts').type.fields()))" "2" \ - "$lang typedef field list" + "$lang typedef field list" if {$lang == "c++"} { # Test usage with a class @@ -134,7 +135,7 @@ proc test_fields {lang} { # Test conversion to bool on scalar types gdb_test "python print (not not st.type\['a'\].type)" "True" - + # Test regression PR python/10805 gdb_py_test_silent_cmd "print (ar)" "print value(ar)" 1 gdb_py_test_silent_cmd "python ar = gdb.history (0)" "get value (ar) from history" 1 @@ -144,9 +145,9 @@ proc test_fields {lang} { # Test gdb.Type.array. gdb_test "python print (ar\[0\].cast(ar\[0\].type.array(1)))" \ - ".1, 2." "cast to array with one argument" + ".1, 2." "cast to array with one argument" gdb_test "python print (ar\[0\].cast(ar\[0\].type.array(0, 1)))" \ - ".1, 2." "cast to array with two arguments" + ".1, 2." "cast to array with two arguments" gdb_test "python print (ar\[0\].type == ar\[0\].type)" "True" @@ -253,9 +254,9 @@ proc test_template {} { || [test_compiler_info {gcc-4-[0-4]-*}]} { set have_older_gcc 1 } - if $have_older_gcc { setup_xfail *-*-* } + if {$have_older_gcc} { setup_xfail *-*-* } gdb_test "python print (ttype.template_argument(1))" "23" - if $have_older_gcc { setup_xfail *-*-* } + if {$have_older_gcc} { setup_xfail *-*-* } gdb_test "python print (isinstance(ttype.template_argument(1), gdb.Value))" \ "True" @@ -391,6 +392,12 @@ if { [build_inferior "${binfile}" "c"] == 0 } { test_type_equality test_type_identity } + + gdb_test "python print(gdb.lookup_type('int').const().volatile())" \ + "const volatile int" + gdb_test "python print(gdb.lookup_type('int').volatile().const())" \ + "const volatile int" \ + "volatile const int" } # Perform C++ Tests. diff --git a/gdb/testsuite/gdb.python/py-typeprint.py b/gdb/testsuite/gdb.python/py-typeprint.py index dc13210..208b368 100644 --- a/gdb/testsuite/gdb.python/py-typeprint.py +++ b/gdb/testsuite/gdb.python/py-typeprint.py @@ -14,6 +14,7 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. import gdb +import gdb.types class StringRecognizer(object): @@ -57,6 +58,4 @@ class OtherTypePrinter(object): return OtherRecognizer() -import gdb.types - gdb.types.register_type_printer(gdb.objfiles()[0], OtherTypePrinter()) diff --git a/gdb/testsuite/gdb.python/py-unwind-inline.exp b/gdb/testsuite/gdb.python/py-unwind-inline.exp index 74d4ead..b0b06b2 100644 --- a/gdb/testsuite/gdb.python/py-unwind-inline.exp +++ b/gdb/testsuite/gdb.python/py-unwind-inline.exp @@ -37,7 +37,7 @@ set pyfile [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py] gdb_breakpoint "foo" gdb_test "source ${pyfile}" "Python script imported" \ - "import python scripts" + "import python scripts" gdb_continue_to_breakpoint "foo" diff --git a/gdb/testsuite/gdb.python/py-unwind-inline.py b/gdb/testsuite/gdb.python/py-unwind-inline.py index ca6b16e..95310b7 100644 --- a/gdb/testsuite/gdb.python/py-unwind-inline.py +++ b/gdb/testsuite/gdb.python/py-unwind-inline.py @@ -58,8 +58,8 @@ class dummy_unwinder(Unwinder): to see if the unwinder should claim it, which is never does.""" try: for r in self.get_regs(pending_frame): - v = pending_frame.read_register(r).cast(self.void_ptr_t) - except: + pending_frame.read_register(r).cast(self.void_ptr_t) + except Exception: print("Dummy unwinder, exception") raise diff --git a/gdb/testsuite/gdb.python/py-unwind-maint.py b/gdb/testsuite/gdb.python/py-unwind-maint.py index 4a109d5..b6b621b 100644 --- a/gdb/testsuite/gdb.python/py-unwind-maint.py +++ b/gdb/testsuite/gdb.python/py-unwind-maint.py @@ -15,10 +15,8 @@ # This file is part of the GDB testsuite. It tests python unwinders. -import re - import gdb.types -from gdb.unwinder import Unwinder, register_unwinder +from gdb.unwinder import Unwinder class TestGlobalUnwinder(Unwinder): diff --git a/gdb/testsuite/gdb.python/py-unwind.c b/gdb/testsuite/gdb.python/py-unwind.c index f785c5e..318458f 100644 --- a/gdb/testsuite/gdb.python/py-unwind.c +++ b/gdb/testsuite/gdb.python/py-unwind.c @@ -33,8 +33,8 @@ static void bad_layout(void **variable_ptr, void *fp) { fprintf (stderr, "First variable should be allocated one word below " - "the frame. Got variable's address %p, frame at %p instead.\n", - variable_ptr, fp); + "the frame. Got variable's address %p, frame at %p instead.\n", + variable_ptr, fp); abort(); } diff --git a/gdb/testsuite/gdb.python/py-unwind.exp b/gdb/testsuite/gdb.python/py-unwind.exp index 80eac28..b416c2f 100644 --- a/gdb/testsuite/gdb.python/py-unwind.exp +++ b/gdb/testsuite/gdb.python/py-unwind.exp @@ -245,6 +245,13 @@ with_test_prefix "frame-id 'pc' is invalid" { "Python Exception <class 'ValueError'>: invalid literal for int\\(\\) with base 10: 'xyz'\r\n.*" } +with_test_prefix "bad object unwinder" { + gdb_test_no_output "python obj = bad_object_unwinder(\"bad-object\")" + gdb_test_no_output "python gdb.unwinder.register_unwinder(None, obj, replace=True)" + gdb_test "backtrace" \ + "Python Exception <class 'gdb.error'>: an Unwinder should return gdb.UnwindInfo, not Blah\\.\r\n.*" +} + # Gather information about every frame. gdb_test_no_output "python capture_all_frame_information()" gdb_test_no_output "python gdb.newest_frame().select()" diff --git a/gdb/testsuite/gdb.python/py-unwind.py b/gdb/testsuite/gdb.python/py-unwind.py index 8e65a1a..50c6d55 100644 --- a/gdb/testsuite/gdb.python/py-unwind.py +++ b/gdb/testsuite/gdb.python/py-unwind.py @@ -106,7 +106,6 @@ class TestUnwinder(Unwinder): unwind_info.add_saved_register(value=previous_ip, register="rip") unwind_info.add_saved_register(register="rsp", value=previous_sp) - global add_saved_register_errors try: unwind_info.add_saved_register("nosuchregister", previous_sp) except ValueError as ve: @@ -230,7 +229,6 @@ def capture_all_frame_information(): # Assert that every entry in the global ALL_FRAME_INFORMATION list was # matched by the validating_unwinder. def check_all_frame_information_matched(): - global all_frame_information for entry in all_frame_information: assert entry["matched"] @@ -245,8 +243,6 @@ class validating_unwinder(Unwinder): def __call__(self, pending_frame): info = capture_frame_information(pending_frame) level = info["level"] - - global all_frame_information old_info = all_frame_information[level] assert old_info is not None @@ -254,7 +250,7 @@ class validating_unwinder(Unwinder): for key, value in info.items(): assert key in old_info, key + " not in old_info" - assert type(value) == type(old_info[key]) + assert type(value) is type(old_info[key]) if isinstance(value, gdb.Block): assert value.start == old_info[key].start assert value.end == old_info[key].end @@ -267,4 +263,24 @@ class validating_unwinder(Unwinder): return None +class bad_object_unwinder(Unwinder): + def __init__(self, name): + super().__init__(name) + + def __call__(self, pending_frame): + + if pending_frame.level() != 1: + return None + + class Blah: + def __init__(self): + pass + + @property + def __class__(self): + raise RuntimeError("error in Blah.__class__") + + return Blah() + + print("Python script imported") diff --git a/gdb/testsuite/gdb.python/py-value-cc.exp b/gdb/testsuite/gdb.python/py-value-cc.exp index 3d371bc..6d261fb 100644 --- a/gdb/testsuite/gdb.python/py-value-cc.exp +++ b/gdb/testsuite/gdb.python/py-value-cc.exp @@ -24,7 +24,7 @@ if {[prepare_for_testing "failed to prepare" $testfile $srcfile {debug c++}]} { return -1 } -if ![runto_main] { +if {![runto_main]} { return -1 } diff --git a/gdb/testsuite/gdb.python/py-value.c b/gdb/testsuite/gdb.python/py-value.c index a822346..f6dbf55 100644 --- a/gdb/testsuite/gdb.python/py-value.c +++ b/gdb/testsuite/gdb.python/py-value.c @@ -19,6 +19,14 @@ #include <stdlib.h> #include <string.h> +int long_array[] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, 48, 49 +}; + struct s { int a; @@ -60,6 +68,7 @@ struct Derived : public Base { Base *base = new Derived (); Derived derived; Base &base_ref = derived; +struct str pod; void ptr_ref(int*& rptr_int) { diff --git a/gdb/testsuite/gdb.python/py-value.exp b/gdb/testsuite/gdb.python/py-value.exp index 93985a9..ffc4b7c 100644 --- a/gdb/testsuite/gdb.python/py-value.exp +++ b/gdb/testsuite/gdb.python/py-value.exp @@ -297,9 +297,9 @@ proc test_value_in_inferior {} { gdb_test "print argc" " = $argc_value" "sanity check argc" gdb_test "python print (argc_lazy.is_lazy)" "\r\nTrue" \ "python print (argc_lazy.is_lazy) the second time" - gdb_test_no_output "set argc=[expr $argc_value + 1]" "change argc" + gdb_test_no_output "set argc=[expr {$argc_value + 1}]" "change argc" gdb_test "python print (argc_notlazy)" "\r\n$argc_value" - gdb_test "python print (argc_lazy)" "\r\n[expr $argc_value + 1]" + gdb_test "python print (argc_lazy)" "\r\n[expr {$argc_value + 1}]" gdb_test "python print (argc_lazy.is_lazy)" "False" # Test string fetches, both partial and whole. @@ -431,7 +431,8 @@ proc test_value_after_death {} { proc test_subscript_regression {exefile lang} { # Start with a fresh gdb. - clean_restart ${exefile} + clean_restart + gdb_load $exefile if {![runto_main]} { return @@ -457,6 +458,8 @@ proc test_subscript_regression {exefile lang} { "Derived \[*\]" gdb_test "python print (gdb.parse_and_eval('base_ref').dynamic_type)" \ "Derived \[&\]" + gdb_test "python print (gdb.parse_and_eval('pod').dynamic_type)" \ + "str" # A static type case. gdb_test "python print (gdb.parse_and_eval('5').dynamic_type)" \ "int" @@ -541,13 +544,13 @@ proc test_float_conversion {} { proc prepare_type_and_buffer {} { gdb_py_test_silent_cmd "python tp=gdb.lookup_type('int')" "look up int type" 0 gdb_py_test_silent_cmd "python size_a=gdb.parse_and_eval('sizeof(a)')" \ - "find size of a" 0 + "find size of a" 0 gdb_py_test_silent_cmd "python size_a0=gdb.parse_and_eval('sizeof(a\[0\])')" \ - "find size of element of a" 0 + "find size of element of a" 0 gdb_py_test_silent_cmd "python addr=gdb.parse_and_eval('&a')" \ - "find address of a" 0 + "find address of a" 0 gdb_py_test_silent_cmd "python b=gdb.selected_inferior().read_memory(addr,size_a)" \ - "read buffer from memory" 0 + "read buffer from memory" 0 } proc test_value_from_buffer {} { @@ -567,23 +570,23 @@ proc test_value_from_buffer {} { prepare_type_and_buffer gdb_test "python v=gdb.Value(b,tp); print(v)" "1" \ - "construct value from buffer" + "construct value from buffer" gdb_test_no_output { python compare_value_bytes_to_mem(v, addr, size_a0) } gdb_test "python v=gdb.Value(b\[size_a0:\],tp); print(v)" "2" \ - "convert 2nd elem of buffer to value" + "convert 2nd elem of buffer to value" gdb_test_no_output \ { python compare_value_bytes_to_mem(v, (int(addr) + size_a0), size_a0) } gdb_test "python v=gdb.Value(b\[2*size_a0:\],tp); print(v)" "3" \ - "convert 3rd elem of buffer to value" + "convert 3rd elem of buffer to value" gdb_test_no_output \ { python compare_value_bytes_to_mem(v, (int(addr) + (2 * size_a0)), size_a0) } gdb_test "python v=gdb.Value(b\[2*size_a0+1:\],tp); print(v)" \ - "ValueError.*: Size of type is larger than that of buffer object\..*" \ + "ValueError.*: Size of type is larger than that of buffer object\..*" \ "attempt to convert smaller buffer than size of type" gdb_py_test_silent_cmd "python atp=tp.array(2) ; print(atp)" \ - "make array type" 0 + "make array type" 0 gdb_py_test_silent_cmd "python va=gdb.Value(b,atp)" \ - "construct array value from buffer" 0 + "construct array value from buffer" 0 gdb_test_no_output \ { python compare_value_bytes_to_mem(va, addr, size_a0 * 3) } gdb_test "python print(va)" "\\{1, 2, 3\\}" "print array value" @@ -591,16 +594,16 @@ proc test_value_from_buffer {} { gdb_test "python print(va\[1\])" "2" "print second array element" gdb_test "python print(va\[2\])" "3" "print third array element" gdb_test "python print(va\[3\])" "gdb\.error.*: no such vector element.*" \ - "print out of bounds array element" + "print out of bounds array element" gdb_py_test_silent_cmd "python atpbig=tp.array(3)" "make bigger array type" 0 gdb_test "python vabig=gdb.Value(b,atpbig)" \ - "ValueError.*: Size of type is larger than that of buffer object\..*" \ - "attempt to construct large value with small buffer" + "ValueError.*: Size of type is larger than that of buffer object\..*" \ + "attempt to construct large value with small buffer" gdb_test "python v=gdb.Value(2048,tp)" \ - "TypeError.*: Object must support the python buffer protocol\..*" \ - "attempt to construct value from buffer with non-buffer object" + "TypeError.*: Object must support the python buffer protocol\..*" \ + "attempt to construct value from buffer with non-buffer object" gdb_test "python v=gdb.Value(b,'int'); print(v)" \ - "TypeError.*: type argument must be a gdb\.Type\..*" \ + "TypeError.*: type argument must be a gdb\.Type\..*" \ "attempt to construct value with string as type" } @@ -680,6 +683,7 @@ proc_with_prefix test_value_bytes { } { "python" "" \ "def check_value_bytes(var_name):" "" \ " val = gdb.parse_and_eval(var_name)" "" \ + " assert not val.is_unavailable" "" \ " addr = val.address" "" \ " len = val.type.sizeof" "" \ " mem = gdb.selected_inferior().read_memory(addr, len)" "" \ @@ -762,13 +766,45 @@ proc test_assign {} { "cannot assign to integer" } +# Test Value.is_unavailable +proc test_unavailable {} { + set elem_size [get_valueof "/d" "sizeof(long_array\[0\])" "UNKNOWN" \ + "get size of long_array element"] + set max [expr {$elem_size * 10}] + + with_set "print elements" 5 { + with_max_value_size $max { + gdb_test "p long_array" + + gdb_test_no_output "set print elements 15" + + gdb_test_no_output "python v = gdb.history(0)" + + gdb_test "python print(v.is_unavailable)" "^True" \ + "overall object shows as unavailable" + for { set i 0 } { $i < 10 } { incr i } { + gdb_test "python print(v\[$i\].is_unavailable)" "^False" \ + "array element $i is available" + gdb_test "python print(v\[$i\])" "^$i" \ + "array element $i has correct value" + } + for { set i 10 } { $i < 15 } { incr i } { + gdb_test "python print(v\[$i\].is_unavailable)" "^True" \ + "array element $i is unavailable" + gdb_test "python print(v\[$i\])" "^<unavailable>" \ + "array element $i shows as unavailable" + } + } + } +} + # Build C version of executable. C++ is built later. if { [build_inferior "${binfile}" "c"] < 0 } { return -1 } # Start with a fresh gdb. -clean_restart ${binfile} +clean_restart ${::testfile} test_history_count test_value_creation @@ -788,6 +824,7 @@ if {![runto_main]} { return 0 } +test_unavailable test_value_in_inferior test_value_from_buffer test_value_sub_classes @@ -797,7 +834,7 @@ test_assign test_value_bytes test_value_after_death -# Test either C or C++ values. +# Test either C or C++ values. test_subscript_regression "${binfile}" "c" @@ -809,3 +846,15 @@ if {[allow_cplus_tests]} { test_subscript_regression "${binfile}-cxx" "c++" } } + +if {[allow_rust_tests]} { + gdb_test "set lang rust" + + set cst 0x80000000000000000000000000000000 + gdb_test "python print(int(gdb.parse_and_eval('${cst}u128')))" \ + "170141183460469231731687303715884105728" \ + "convert 128 bit unsigned constant to python int" + gdb_test "python print(int(gdb.parse_and_eval('${cst}i128')))" \ + "-170141183460469231731687303715884105728" \ + "convert 128 bit signed constant to python int" +} diff --git a/gdb/testsuite/gdb.python/py-varobj.exp b/gdb/testsuite/gdb.python/py-varobj.exp index 7fb45f9..cf6a662 100644 --- a/gdb/testsuite/gdb.python/py-varobj.exp +++ b/gdb/testsuite/gdb.python/py-varobj.exp @@ -25,7 +25,7 @@ if {[gdb_compile "$srcdir/$subdir/$srcfile" $binfile executable {debug}] != ""} return -1 } -mi_clean_restart $binfile +mi_clean_restart $::testfile set pyfile [gdb_remote_download host ${srcdir}/${subdir}/${testfile}.py] mi_gdb_test "source ${pyfile}" \ diff --git a/gdb/testsuite/gdb.python/py-warning.exp b/gdb/testsuite/gdb.python/py-warning.exp new file mode 100644 index 0000000..6b26a4e --- /dev/null +++ b/gdb/testsuite/gdb.python/py-warning.exp @@ -0,0 +1,63 @@ +# Copyright (C) 2025 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/>. + +# Test the gdb.warning() function. + +load_lib gdb-python.exp + +require allow_python_tests + +clean_restart + +# Basic usage. +gdb_test "python gdb.warning(\"some text\")" \ + "warning: some text" + +# Basic usage with named argument. +gdb_test "python gdb.warning(text=\"a warning message\")" \ + "warning: a warning message" + +# Make sure GDB prints format specifiers correctly. +gdb_test "python gdb.warning(\"%s %d %p\")" \ + "warning: %s %d %p" + +# Empty string gives an error. +gdb_test "python gdb.warning(\"\")" \ + [multi_line \ + "Python Exception <class 'ValueError'>: Empty text string passed to gdb\\.warning" \ + "Error occurred in Python: Empty text string passed to gdb\\.warning"] + +# Missing argument gives an error. +set re1 \ + [multi_line \ + [string_to_regexp \ + [concat \ + "Python Exception <class 'TypeError'>:" \ + "function missing required argument 'text' (pos 1)"]] \ + [string_to_regexp \ + [concat \ + "Error occurred in Python:" \ + "function missing required argument 'text' (pos 1)"]]] +set re2 \ + [multi_line \ + [string_to_regexp \ + [concat \ + "Python Exception <class 'TypeError'>:" \ + "Required argument 'text' (pos 1) not found"]] \ + [string_to_regexp \ + [concat \ + "Error occurred in Python:" \ + "Required argument 'text' (pos 1) not found"]]] +gdb_test "python gdb.warning()" $re1|$re2 diff --git a/gdb/testsuite/gdb.python/py-watchpoint.py b/gdb/testsuite/gdb.python/py-watchpoint.py index d25826f..9d1ea5e 100644 --- a/gdb/testsuite/gdb.python/py-watchpoint.py +++ b/gdb/testsuite/gdb.python/py-watchpoint.py @@ -14,6 +14,9 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. +import gdb + + class MyBreakpoint(gdb.Breakpoint): def __init__(self): super().__init__("i", gdb.BP_WATCHPOINT) diff --git a/gdb/testsuite/gdb.python/py-xmethods.exp b/gdb/testsuite/gdb.python/py-xmethods.exp index 3dafe0e..5863ec5 100644 --- a/gdb/testsuite/gdb.python/py-xmethods.exp +++ b/gdb/testsuite/gdb.python/py-xmethods.exp @@ -26,7 +26,7 @@ if {[prepare_for_testing "failed to prepare" $testfile $srcfile {debug c++}]} { return -1 } -if ![runto_main] { +if {![runto_main]} { return -1 } diff --git a/gdb/testsuite/gdb.python/python.exp b/gdb/testsuite/gdb.python/python.exp index 6b2f671..020fc66 100644 --- a/gdb/testsuite/gdb.python/python.exp +++ b/gdb/testsuite/gdb.python/python.exp @@ -152,29 +152,17 @@ gdb_test_no_output "set height $lines" set test "verify pagination beforehand" gdb_test_multiple "python print (\"\\n\" * $lines)" $test { - -re "--Type <RET>" { - exp_continue - } - -re " for more, q to quit" { - exp_continue - } - -re ", c to continue without paging--$" { + -re "$pagination_prompt$" { pass $test } } gdb_test "q" "Quit.*" "verify pagination beforehand: q" -gdb_test "python if gdb.execute('python print (\"\\\\n\" * $lines)', to_string=True) == \"\\n\" * [expr $lines + 1]: print (\"yes\")" "yes" "gdb.execute does not page" +gdb_test "python if gdb.execute('python print (\"\\\\n\" * $lines)', to_string=True) == \"\\n\" * [expr {$lines + 1}]: print (\"yes\")" "yes" "gdb.execute does not page" set test "verify pagination afterwards" gdb_test_multiple "python print (\"\\n\" * $lines)" $test { - -re "--Type <RET>" { - exp_continue - } - -re " for more, q to quit" { - exp_continue - } - -re ", c to continue without paging--$" { + -re "$pagination_prompt$" { pass $test } } @@ -300,7 +288,7 @@ gdb_test "python gdb.write(\"Foo\\n\")" "Foo" "test default write" gdb_test "python gdb.write(\"Error stream\\n\", stream=gdb.STDERR)" "Error stream" "test stderr write" gdb_test "python gdb.write(\"Normal stream\\n\", stream=gdb.STDOUT)" "Normal stream" "test stdout write" -if ![gdb_debug_enabled] { +if {![gdb_debug_enabled]} { gdb_test "python gdb.write(\"Log stream\\n\", stream=gdb.STDLOG)" "Log stream" "test stdlog write" } diff --git a/gdb/testsuite/gdb.python/source2.py b/gdb/testsuite/gdb.python/source2.py index 7ca0bb2..59ac6f6 100644 --- a/gdb/testsuite/gdb.python/source2.py +++ b/gdb/testsuite/gdb.python/source2.py @@ -16,6 +16,6 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # Make sure __file__ is defined. -assert type(__file__) == str +assert type(__file__) is str print("y%ss" % "e") diff --git a/gdb/testsuite/gdb.python/tui-window-disabled.py b/gdb/testsuite/gdb.python/tui-window-disabled.py index 8d140c4..e7195ea 100644 --- a/gdb/testsuite/gdb.python/tui-window-disabled.py +++ b/gdb/testsuite/gdb.python/tui-window-disabled.py @@ -46,9 +46,6 @@ class EventWindow: self._win.write("Hello world...") def close(self): - global cleanup_properly - global titles_at_the_close - # Ensure that window properties can be read within the close method. titles_at_the_close[self._win.title] = dict( width=self._win.width, height=self._win.height @@ -70,9 +67,6 @@ class EventWindow: self._exit_listener = None def _event(self, type, event): - global perform_valid_check - global update_title - self._count += 1 self._events.insert(0, type) if not perform_valid_check or self._win.is_valid(): @@ -83,7 +77,6 @@ class EventWindow: def render(self): self._win.erase() - w = self._win.width h = self._win.height for i in range(min(h, len(self._events))): self._win.write(self._events[i] + "\n") diff --git a/gdb/testsuite/gdb.python/tui-window-factory.py b/gdb/testsuite/gdb.python/tui-window-factory.py index 7593214..9ad75f7 100644 --- a/gdb/testsuite/gdb.python/tui-window-factory.py +++ b/gdb/testsuite/gdb.python/tui-window-factory.py @@ -14,6 +14,9 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. +import gdb + + class TestWindow: def __init__(self, tui_win, msg): self.msg = msg |
