From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id 00CA73858D28 for ; Wed, 18 Jan 2023 18:02:44 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 00CA73858D28 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1674064964; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=PzREQGgGSHLdmIRcZ1IgP5xQ6f8+RHm8K35Mbv8LIV0=; b=FEU2XZzyTCqA6IiPdzCnjp4JULl3hydAph5Akc1yxtSBMDsazaiJql9ijAiFeblozV64bg S4UaTyHImOySz/x079uzc2jl9MubT4YU8+PX6iNxEmM3VUohq+TVwQcQrA73LWhrGrfjjy IkQNX8vp9aZtfrZlAPVR4D2DY+Vlqbw= Received: from mail-qt1-f198.google.com (mail-qt1-f198.google.com [209.85.160.198]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_128_GCM_SHA256) id us-mta-507-D2g6RE2_NT2HkGD33Y4EYA-1; Wed, 18 Jan 2023 13:02:43 -0500 X-MC-Unique: D2g6RE2_NT2HkGD33Y4EYA-1 Received: by mail-qt1-f198.google.com with SMTP id ez10-20020a05622a4c8a00b003ab6c16856fso15720478qtb.17 for ; Wed, 18 Jan 2023 10:02:42 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=mime-version:message-id:date:references:in-reply-to:subject:cc:to :from:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=PzREQGgGSHLdmIRcZ1IgP5xQ6f8+RHm8K35Mbv8LIV0=; b=hOLtgz4hLAbgVgdq2XNQp00TesfUzBwClNULH68TcNni2KGsmkHGlwxBDTjRiY5n1g Yam9J8XcASaJMUaU6ZfJQDsP3nN8J4RJGZSGiKR4r14yuJo+6A5FJj+6m3QWv2G0mQFD 5ubo7NhXU6H4DOptkXFCcrUJaEF0BIVt1g8hvU8n8EEfH3e3TQ7Hk0xA1/gYVsqmNXSs UmHvF1it3yg0786Efw9RdBES8JnzUbMqI2Uk84FmTyQFljeq2q3a6BZrGzTDE2TSe4Dy a9+1cs2jRnCG9SlbfJ1/jmvmY5q+f+1ySE5EVN7J5ar12ZElwx394+F6RwJVblyaZn6T QYfw== X-Gm-Message-State: AFqh2ko6pGitIdaVhgEjyqx0ROW+06/6Beb/DQUwDSJGbS3O+twQigp1 Uz23/T/WFYUG30LZlRWcgbfL6jgz44zWD7+NAiabAYY/RelHcW0uuHLJai/3G3Dsk906xOqsxwH ZdNYTs5H7tAYdRyLkf6IHI8pGO6rshSnCm0AMUv3eun/0VvcAQ+5QMXSOSikyLLPQXM5FcxIEXQ == X-Received: by 2002:ac8:6b88:0:b0:3b0:4084:d6ad with SMTP id z8-20020ac86b88000000b003b04084d6admr10740274qts.58.1674064961717; Wed, 18 Jan 2023 10:02:41 -0800 (PST) X-Google-Smtp-Source: AMrXdXt7Rxa2AZfyKT6wVc0WgnTjTUKjPnX43MwlPPJKxWZ8Q+U2g78J/kotuoq0MPfpcNrt8CBJxw== X-Received: by 2002:ac8:6b88:0:b0:3b0:4084:d6ad with SMTP id z8-20020ac86b88000000b003b04084d6admr10740232qts.58.1674064961006; Wed, 18 Jan 2023 10:02:41 -0800 (PST) Received: from localhost (95.72.115.87.dyn.plus.net. [87.115.72.95]) by smtp.gmail.com with ESMTPSA id o24-20020ac85558000000b003b646a99aa6sm1551582qtr.77.2023.01.18.10.02.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 18 Jan 2023 10:02:40 -0800 (PST) From: Andrew Burgess To: Matheus Branco Borella via Gdb-patches , gdb-patches@sourceware.org Cc: Matheus Branco Borella Subject: Re: [PATCH] Add __repr__() implementation to a few Python types In-Reply-To: <20230111003510.620-1-dark.ryu.550@gmail.com> References: <20230111003510.620-1-dark.ryu.550@gmail.com> Date: Wed, 18 Jan 2023 18:02:38 +0000 Message-ID: <87wn5jen5t.fsf@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Type: text/plain X-Spam-Status: No, score=-11.8 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_NONE,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: Matheus Branco Borella via Gdb-patches writes: > Only a few types in the Python API currently have __repr__() implementations. > This patch adds a few more of them. specifically: it adds __repr__() > implementations to gdb.Symbol, gdb.Architecture, gdb.Block, gdb.Breakpoint, > and gdb.Type. > > This makes it easier to play around the GDB Python API in the Python interpreter > session invoked with the 'pi' command in GDB, giving more easily accessible tipe > information to users. > > An example of how this would look like: > ``` > (gdb) pi >>> gdb.lookup_type("char") > >>> gdb.lookup_global_symbol("main") > > ``` Thanks for working on this, I think this will be really useful. > > One thing to note about this patch is that it makes use of u8 string literals, > so as to make sure we meet python's expectations of strings passed to it using > PyUnicode_FromFormat being encoded in utf8. This should remove the chance of > odd compilation environments spitting out strings Python would consider invalid > for the function we're calling. Sorry for being a little slow. What does this actually mean? When you say "makes use of u8 string literals" - does this mean you have string literals in this patch containing non ASCII characters? I've trying to understand why this is different to any other part of GDB that prints stuff via Python. > --- > gdb/python/py-arch.c | 18 +++++++- > gdb/python/py-block.c | 30 ++++++++++++- > gdb/python/py-breakpoint.c | 49 +++++++++++++++++++++- > gdb/python/py-symbol.c | 16 ++++++- > gdb/python/py-type.c | 31 +++++++++++++- > gdb/testsuite/gdb.python/py-arch.exp | 4 ++ > gdb/testsuite/gdb.python/py-block.exp | 4 +- > gdb/testsuite/gdb.python/py-breakpoint.exp | 26 +++++++----- > gdb/testsuite/gdb.python/py-symbol.exp | 1 + > gdb/testsuite/gdb.python/py-type.exp | 4 ++ > 10 files changed, 165 insertions(+), 18 deletions(-) > > diff --git a/gdb/python/py-arch.c b/gdb/python/py-arch.c > index cf0978560f9..5384a0d0d0c 100644 > --- a/gdb/python/py-arch.c > +++ b/gdb/python/py-arch.c > @@ -319,6 +319,22 @@ archpy_integer_type (PyObject *self, PyObject *args, PyObject *kw) > return type_to_type_object (type); > } > > +/* __repr__ implementation for gdb.Architecture. */ > + > +static PyObject * > +archpy_repr (PyObject *self) > +{ > + const auto gdbarch = arch_object_to_gdbarch (self); > + if (gdbarch == nullptr) > + return PyUnicode_FromFormat > + (""); > + > + return PyUnicode_FromFormat > + ("", > + gdbarch_bfd_arch_info (gdbarch)->arch_name, > + gdbarch_bfd_arch_info (gdbarch)->printable_name); > +} > + > /* Implementation of gdb.architecture_names(). Return a list of all the > BFD architecture names that GDB understands. */ > > @@ -391,7 +407,7 @@ PyTypeObject arch_object_type = { > 0, /* tp_getattr */ > 0, /* tp_setattr */ > 0, /* tp_compare */ > - 0, /* tp_repr */ > + archpy_repr, /* tp_repr */ > 0, /* tp_as_number */ > 0, /* tp_as_sequence */ > 0, /* tp_as_mapping */ > diff --git a/gdb/python/py-block.c b/gdb/python/py-block.c > index b9aea3aca69..1b8433d41e7 100644 > --- a/gdb/python/py-block.c > +++ b/gdb/python/py-block.c > @@ -23,6 +23,7 @@ > #include "symtab.h" > #include "python-internal.h" > #include "objfiles.h" > +#include > > struct block_object { > PyObject_HEAD > @@ -424,6 +425,33 @@ blpy_iter_is_valid (PyObject *self, PyObject *args) > Py_RETURN_TRUE; > } > > +/* __repr__ implementation for gdb.Block. */ > + > +static PyObject * > +blpy_repr (PyObject *self) > +{ > + const auto block = block_object_to_block (self); > + if (block == nullptr) > + return PyUnicode_FromFormat(""); Missing space before '('. I think Bruno pointed out more of these, so I'll not both pointing out the others I see. > + > + const auto name = block->function () ? block->function ()->print_name () : ""; This line is too long and needs to be wrapped to under 80 characters. > + > + block_iterator iter; > + block_iterator_first (block, &iter); > + > + std::stringstream ss; > + const struct symbol *symbol; > + while ((symbol = block_iterator_next (&iter)) != nullptr) > + { > + ss << std::endl; > + ss << symbol->print_name () << ","; > + } > + if(!ss.str ().empty ()) > + ss << std::endl; We don't make much use of std::stringstream in GDB, and unless there's a compelling reason, then for consistency, I'd prefer to see this written using std::string. While playing with this I rewrote this as: std::string str; const struct symbol *symbol; while ((symbol = block_iterator_next (&iter)) != nullptr) str = (str + "\n") + symbol->print_name () + ","; if(!str.empty ()) str += "\n"; return PyUnicode_FromFormat("", name, str.c_str ()); which still seems to pass your tests. > + > + return PyUnicode_FromFormat("", name, ss.str ().c_str ()); > +} > + > int > gdbpy_initialize_blocks (void) > { > @@ -486,7 +514,7 @@ PyTypeObject block_object_type = { > 0, /*tp_getattr*/ > 0, /*tp_setattr*/ > 0, /*tp_compare*/ > - 0, /*tp_repr*/ > + blpy_repr, /*tp_repr*/ > 0, /*tp_as_number*/ > 0, /*tp_as_sequence*/ > &block_object_as_mapping, /*tp_as_mapping*/ > diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c > index de7b9f4266b..ce307f7be21 100644 > --- a/gdb/python/py-breakpoint.c > +++ b/gdb/python/py-breakpoint.c > @@ -33,6 +33,7 @@ > #include "location.h" > #include "py-event.h" > #include "linespec.h" > +#include > > extern PyTypeObject breakpoint_location_object_type > CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("breakpoint_location_object"); > @@ -967,6 +968,23 @@ bppy_init (PyObject *self, PyObject *args, PyObject *kwargs) > return 0; > } > > +/* __repr__ implementation for gdb.Breakpoint. */ > + > +static PyObject * > +bppy_repr(PyObject *self) > +{ > + const auto bp = (struct gdbpy_breakpoint_object*) self; > + if (bp->bp == nullptr) > + return PyUnicode_FromFormat (""); > + > + return PyUnicode_FromFormat > + ("", > + bp->bp->number, > + bp->bp->thread, > + bp->bp->hit_count, > + bp->bp->enable_count); I think I'd rather see the fields that are included here added dynamically based on their values. For example you choose to include 'thread' but not 'task' which seems pretty arbitrary. Of the fields given here 'number' and 'hits' seem like they should always be included, but I'd then only include 'thread' if it's not -1, and 'task' if it's not 0, similarly, the 'enabled_count' is probably only worth including if it's greater than zero I guess. This leaves the door open for adding more optional fields in the future. > +} > + > /* Append to LIST the breakpoint Python object associated to B. > > Return true on success. Return false on failure, with the Python error > @@ -1389,7 +1407,7 @@ PyTypeObject breakpoint_object_type = > 0, /*tp_getattr*/ > 0, /*tp_setattr*/ > 0, /*tp_compare*/ > - 0, /*tp_repr*/ > + bppy_repr, /*tp_repr*/ > 0, /*tp_as_number*/ > 0, /*tp_as_sequence*/ > 0, /*tp_as_mapping*/ > @@ -1604,6 +1622,33 @@ bplocpy_dealloc (PyObject *py_self) > Py_TYPE (py_self)->tp_free (py_self); > } > > +/* __repr__ implementation for gdb.BreakpointLocation. */ > + > +static PyObject * > +bplocpy_repr (PyObject *py_self) > +{ > + const auto self = (gdbpy_breakpoint_location_object *) py_self; > + if (self->owner == nullptr || self->owner->bp == nullptr || self->owner->bp != self->bp_loc->owner) > + return PyUnicode_FromFormat (""); That `if` condition line is too long. > + > + const auto enabled = self->bp_loc->enabled ? "enabled" : "disabled"; > + > + std::stringstream ss; > + ss << std::endl << enabled << std::endl; > + ss << "requested_address=0x" << std::hex << self->bp_loc->requested_address << " "; > + ss << "address=0x" << self->bp_loc->address << " " << std::dec << std::endl; > + if (self->bp_loc->symtab != nullptr) > + { > + ss << self->bp_loc->symtab->filename << ":" << self->bp_loc->line_number << " " << std::endl; > + } > + > + const auto fn_name = self->bp_loc->function_name.get (); > + if (fn_name != nullptr) > + ss << "in " << fn_name << " " << std::endl; I think this can all be rewritten using std::string instead of std::stringstream, maybe using string_printf to do some of the formatting. IMHO this would be more consistent with the rest of GDB. > + > + return PyUnicode_FromFormat ("", ss.str ().c_str ()); > +} > + > /* Attribute get/set Python definitions. */ > > static gdb_PyGetSetDef bp_location_object_getset[] = { > @@ -1635,7 +1680,7 @@ PyTypeObject breakpoint_location_object_type = > 0, /*tp_getattr*/ > 0, /*tp_setattr*/ > 0, /*tp_compare*/ > - 0, /*tp_repr*/ > + bplocpy_repr, /*tp_repr*/ > 0, /*tp_as_number*/ > 0, /*tp_as_sequence*/ > 0, /*tp_as_mapping*/ > diff --git a/gdb/python/py-symbol.c b/gdb/python/py-symbol.c > index 93c86964f3e..5a8149bbe66 100644 > --- a/gdb/python/py-symbol.c > +++ b/gdb/python/py-symbol.c > @@ -375,6 +375,20 @@ sympy_dealloc (PyObject *obj) > Py_TYPE (obj)->tp_free (obj); > } > > +/* __repr__ implementation for gdb.Symbol. */ > + > +static PyObject * > +sympy_repr (PyObject *self) > +{ > + const auto symbol = symbol_object_to_symbol (self); > + if (symbol == nullptr) > + return PyUnicode_FromFormat (""); > + > + return PyUnicode_FromFormat > + ("", > + symbol->print_name ()); > +} > + > /* Implementation of > gdb.lookup_symbol (name [, block] [, domain]) -> (symbol, is_field_of_this) > A tuple with 2 elements is always returned. The first is the symbol > @@ -732,7 +746,7 @@ PyTypeObject symbol_object_type = { > 0, /*tp_getattr*/ > 0, /*tp_setattr*/ > 0, /*tp_compare*/ > - 0, /*tp_repr*/ > + sympy_repr, /*tp_repr*/ > 0, /*tp_as_number*/ > 0, /*tp_as_sequence*/ > 0, /*tp_as_mapping*/ > diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c > index 928efacfe8a..abe127eca76 100644 > --- a/gdb/python/py-type.c > +++ b/gdb/python/py-type.c > @@ -442,6 +442,7 @@ typy_is_signed (PyObject *self, void *closure) > Py_RETURN_TRUE; > } > > + Random extra blank line here. > /* Return the type, stripped of typedefs. */ > static PyObject * > typy_strip_typedefs (PyObject *self, PyObject *args) > @@ -1026,6 +1027,34 @@ typy_template_argument (PyObject *self, PyObject *args) > return value_to_value_object (val); > } > > +/* __repr__ implementation for gdb.Type. */ > + > +static PyObject * > +typy_repr (PyObject *self) > +{ > + const auto type = type_object_to_type (self); > + if (type == nullptr) > + return PyUnicode_FromFormat (""); > + > + const char *code = pyty_codes[type->code ()].name; > + string_file type_name; > + try > + { > + current_language->print_type (type, "", > + &type_name, -1, 0, > + &type_print_raw_options); > + } > + catch (const gdb_exception &except) > + { > + GDB_PY_HANDLE_EXCEPTION (except); > + } > + auto py_typename = PyUnicode_Decode > + (type_name.c_str (), type_name.size (), > + host_charset (), NULL); > + > + return PyUnicode_FromFormat ("", code, py_typename); Here's your whitespace error. The return line is over indented, and the preceding line has trailing whitespace. > +} > + > static PyObject * > typy_str (PyObject *self) > { > @@ -1612,7 +1641,7 @@ PyTypeObject type_object_type = > 0, /*tp_getattr*/ > 0, /*tp_setattr*/ > 0, /*tp_compare*/ > - 0, /*tp_repr*/ > + typy_repr, /*tp_repr*/ > &type_object_as_number, /*tp_as_number*/ > 0, /*tp_as_sequence*/ > &typy_mapping, /*tp_as_mapping*/ > diff --git a/gdb/testsuite/gdb.python/py-arch.exp b/gdb/testsuite/gdb.python/py-arch.exp > index 1fbbc47c872..a60b4a25cbb 100644 > --- a/gdb/testsuite/gdb.python/py-arch.exp > +++ b/gdb/testsuite/gdb.python/py-arch.exp > @@ -29,6 +29,8 @@ if ![runto_main] { > # Test python/15461. Invalid architectures should not trigger an > # internal GDB assert. > gdb_py_test_silent_cmd "python empty = gdb.Architecture()" "get empty arch" 0 > +gdb_test "python print(repr (empty))" "" \ > + "Test empty achitecture __repr__ does not trigger an assert" I guess I was surprised that so many of the new tests included an explicit call to repr, given the premise of the change was that simply 'print(empty)' would now print something useful. I guess maybe it doesn't hurt to _also_ include some explicit repr calls, but I was expecting most tests to just be printing the object directly. Is there some reasoning here that I'm missing? > gdb_test "python print(empty.name())" ".*Architecture is invalid.*" \ > "Test empty architecture.name does not trigger an assert" > gdb_test "python print(empty.disassemble())" ".*Architecture is invalid.*" \ > @@ -46,6 +48,8 @@ gdb_py_test_silent_cmd "python insn_list3 = arch.disassemble(pc, count=1)" \ > gdb_py_test_silent_cmd "python insn_list4 = arch.disassemble(gdb.Value(pc))" \ > "disassemble no end no count" 0 > > +gdb_test "python print (repr (arch))" "" "test __repr__ for architecture" Over long line, please wrap a little. There's other long lines in your patch, I'll not point out each one. > + > gdb_test "python print (len(insn_list1))" "1" "test number of instructions 1" > gdb_test "python print (len(insn_list2))" "1" "test number of instructions 2" > gdb_test "python print (len(insn_list3))" "1" "test number of instructions 3" > diff --git a/gdb/testsuite/gdb.python/py-block.exp b/gdb/testsuite/gdb.python/py-block.exp > index 0a88aec56a0..5e3d1c72d5e 100644 > --- a/gdb/testsuite/gdb.python/py-block.exp > +++ b/gdb/testsuite/gdb.python/py-block.exp > @@ -39,7 +39,7 @@ gdb_continue_to_breakpoint "Block break here." > gdb_py_test_silent_cmd "python frame = gdb.selected_frame()" "Get Frame" 0 > gdb_py_test_silent_cmd "python block = frame.block()" \ > "Get block, initial innermost block" 0 > -gdb_test "python print (block)" "" "check block not None" > +gdb_test "python print (block)" "" "check block not None" > gdb_test "python print (block.function)" "None" "first anonymous block" > gdb_test "python print (block.start)" "${decimal}" "check start not None" > gdb_test "python print (block.end)" "${decimal}" "check end not None" > @@ -73,7 +73,7 @@ gdb_test "python print (block.function)" "block_func" \ > 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 (block)" "" \ > +gdb_test "python print (repr (block))" "" \ > "Check Frame 2's block not None" > gdb_test "python print (block.function)" "main" "main block" > > diff --git a/gdb/testsuite/gdb.python/py-breakpoint.exp b/gdb/testsuite/gdb.python/py-breakpoint.exp > index e36e87dc291..0c904a12c90 100644 > --- a/gdb/testsuite/gdb.python/py-breakpoint.exp > +++ b/gdb/testsuite/gdb.python/py-breakpoint.exp > @@ -50,11 +50,14 @@ proc_with_prefix test_bkpt_basic { } { > return 0 > } > > + set num_exp "-?\[0-9\]+" > + set repr_pattern "" We already have $decimal. I think if you change py-breakpoint.c as I suggest then you should be able to make use of that and remove num_exp. This applies below too. Thanks, Andrew > + > # Now there should be one breakpoint: main. > gdb_py_test_silent_cmd "python blist = gdb.breakpoints()" \ > "Get Breakpoint List" 0 > - gdb_test "python print (blist\[0\])" \ > - "" "Check obj exists @main" > + gdb_test "python print (repr (blist\[0\]))" \ > + "$repr_pattern" "Check obj exists @main" > gdb_test "python print (blist\[0\].location)" \ > "main." "Check breakpoint location @main" > gdb_test "python print (blist\[0\].pending)" "False" \ > @@ -71,12 +74,12 @@ proc_with_prefix test_bkpt_basic { } { > "Get Breakpoint List" 0 > gdb_test "python print (len(blist))" \ > "2" "Check for two breakpoints" > - gdb_test "python print (blist\[0\])" \ > - "" "Check obj exists @main 2" > + gdb_test "python print (repr (blist\[0\]))" \ > + "$repr_pattern" "Check obj exists @main 2" > gdb_test "python print (blist\[0\].location)" \ > "main." "Check breakpoint location @main 2" > - gdb_test "python print (blist\[1\])" \ > - "" "Check obj exists @mult_line" > + gdb_test "python print (repr (blist\[1\]))" \ > + "$repr_pattern" "Check obj exists @mult_line" > > gdb_test "python print (blist\[1\].location)" \ > "py-breakpoint\.c:${mult_line}*" \ > @@ -224,14 +227,17 @@ proc_with_prefix test_bkpt_invisible { } { > return 0 > } > > + set num_exp "-?\[0-9\]+" > + set repr_pattern "" > + > delete_breakpoints > set ibp_location [gdb_get_line_number "Break at multiply."] > gdb_py_test_silent_cmd "python ibp = gdb.Breakpoint(\"$ibp_location\", internal=False)" \ > "Set invisible breakpoint" 0 > gdb_py_test_silent_cmd "python ilist = gdb.breakpoints()" \ > "Get Breakpoint List" 0 > - gdb_test "python print (ilist\[0\])" \ > - "" "Check invisible bp obj exists 1" > + gdb_test "python print (repr (ilist\[0\]))" \ > + "$repr_pattern" "Check invisible bp obj exists 1" > gdb_test "python print (ilist\[0\].location)" \ > "py-breakpoint\.c:$ibp_location*" "Check breakpoint location 1" > gdb_test "python print (ilist\[0\].visible)" \ > @@ -243,8 +249,8 @@ proc_with_prefix test_bkpt_invisible { } { > "Set invisible breakpoint" 0 > gdb_py_test_silent_cmd "python ilist = gdb.breakpoints()" \ > "Get Breakpoint List" 0 > - gdb_test "python print (ilist\[0\])" \ > - "" "Check invisible bp obj exists 2" > + gdb_test "python print (repr (ilist\[0\]))" \ > + "$repr_pattern" "Check invisible bp obj exists 2" > gdb_test "python print (ilist\[0\].location)" \ > "py-breakpoint\.c:$ibp_location*" "Check breakpoint location 2" > gdb_test "python print (ilist\[0\].visible)" \ > diff --git a/gdb/testsuite/gdb.python/py-symbol.exp b/gdb/testsuite/gdb.python/py-symbol.exp > index ad06b07c2c6..e0baed9b6d4 100644 > --- a/gdb/testsuite/gdb.python/py-symbol.exp > +++ b/gdb/testsuite/gdb.python/py-symbol.exp > @@ -44,6 +44,7 @@ clean_restart ${binfile} > # point where we don't have a current frame, and we don't want to > # require one. > gdb_py_test_silent_cmd "python main_func = gdb.lookup_global_symbol(\"main\")" "Lookup main" 1 > +gdb_test "python print (repr (main_func))" "" "test main_func.__repr__" > gdb_test "python print (main_func.is_function)" "True" "test main_func.is_function" > gdb_test "python print (gdb.lookup_global_symbol(\"junk\"))" "None" "test lookup_global_symbol(\"junk\")" > > diff --git a/gdb/testsuite/gdb.python/py-type.exp b/gdb/testsuite/gdb.python/py-type.exp > index 594c9749d8e..95cdfa54a6e 100644 > --- a/gdb/testsuite/gdb.python/py-type.exp > +++ b/gdb/testsuite/gdb.python/py-type.exp > @@ -393,3 +393,7 @@ if { [build_inferior "${binfile}-cxx" "c++"] == 0 } { > test_type_equality > } > } > + > +# Test __repr__() > +gdb_test "python print (repr (gdb.lookup_type ('char')))" \ > + "" "test __repr__()" > -- > 2.37.3.windows.1