From patchwork Fri May 19 21:27:57 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 69704 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 1185E3857700 for ; Fri, 19 May 2023 21:28:34 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 1185E3857700 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1684531714; bh=R+iy5mNNZZkZucsmQFfkH5akVPK7D//Q0DpSnHOKdbU=; h=To:Cc:Subject:Date:In-Reply-To:References:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From:Reply-To:From; b=a8T3gmKpU4N+tvGv9RECzRTNf8HXPyyI81K2XKZ+EBjT8yjuZPneen28+M8zSh5OU GKtXdIoMMmrYQXoSyvKmZeNDYS4I9Cer9vnu4uz9TDJKknsk2mx1jDz9ZKuzJPRZnH FoaKGQysCaS95X20/lU1TBFYV/yYBxy1vWQBjB7c= X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org 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 218083858C52 for ; Fri, 19 May 2023 21:28:09 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 218083858C52 Received: from mail-wr1-f72.google.com (mail-wr1-f72.google.com [209.85.221.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-653-AZvy9YtZOcKbQiUcu3f4Kw-1; Fri, 19 May 2023 17:28:07 -0400 X-MC-Unique: AZvy9YtZOcKbQiUcu3f4Kw-1 Received: by mail-wr1-f72.google.com with SMTP id ffacd0b85a97d-3093b0cf714so1442084f8f.2 for ; Fri, 19 May 2023 14:28:06 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684531685; x=1687123685; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=R+iy5mNNZZkZucsmQFfkH5akVPK7D//Q0DpSnHOKdbU=; b=IBeeVCAo0Ec8ec5RtPJY/lG0YCg+sk4GWJAIIjtmSNU3WElgL73E+Zx/o1s2MD6GF0 lxw24zmHeRPf3lYCFtn1qvnCrNWxS2FNDRiSfPkNGnGk05mLTUm3bCr49OVYCwRzm6fB zWQT3YzAeAcYJj5/iO3TxWXUseUsdbtkq6BRtGmfUoAGABJ+ipTafaOn9BNuG1TzagSp cKkcbkUZ9YV3hvXeq9XcM/MyY2Xp93ylsdsO7epPfVTapHu0MxHCqYmsCc83QGtVIbF1 hcwx9A3qxj3/060IDN4Z96Eh8yheMzraO+3LxoQMF5x4Odkc9cErNT72GOeZl1HZ0nyI YsbQ== X-Gm-Message-State: AC+VfDzwIvMUDxR3oi/pC/JY5wfzcBZsu7iOaSRb0XxcOBB/WKFu5vx0 Sr5Jddhi+ibBOP2QCmB47JshXf1J8PJBiH/sKbzKWWm7XewC5dEsd4/vSx9PngaWAsDQmx4WYm4 3TAISE4JNUeWtfBNKzMJKnN+uaLIq46QTTaWrsoeEGBkc+piIypmBI5CqGNItNmbmIFYlg1WUoc g+YW3elw== X-Received: by 2002:adf:e401:0:b0:309:4176:702 with SMTP id g1-20020adfe401000000b0030941760702mr2564760wrm.37.1684531685451; Fri, 19 May 2023 14:28:05 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ6Yl0sn0uzzKFfg34/Xfh6rh7ryeOw3xE7Nbq0TcZA0cB5A6MXpmCa8iFchEX8JCGSDqu5ngA== X-Received: by 2002:adf:e401:0:b0:309:4176:702 with SMTP id g1-20020adfe401000000b0030941760702mr2564754wrm.37.1684531685105; Fri, 19 May 2023 14:28:05 -0700 (PDT) Received: from localhost (11.72.115.87.dyn.plus.net. [87.115.72.11]) by smtp.gmail.com with ESMTPSA id b15-20020a5d4b8f000000b00306344eaebfsm73752wrt.28.2023.05.19.14.28.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 19 May 2023 14:28:04 -0700 (PDT) To: gdb-patches@sourceware.org Cc: Andrew Burgess Subject: [PATCHv3 1/2] gdb: have mdict_size always return a symbol count Date: Fri, 19 May 2023 22:27:57 +0100 Message-Id: X-Mailer: git-send-email 2.25.4 In-Reply-To: References: <20230518033357.77174-1-dark.ryu.550@gmail.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.6 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, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Andrew Burgess via Gdb-patches From: Andrew Burgess Reply-To: Andrew Burgess Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" In the next commit we would like to have mdict_size return the number of symbols in the dictionary, currently mdict_size is just a heuristic, sometimes it returns the number of symbols, and sometimes the number of buckets in a hashing dictionary (see size_hashed in dictionary.c). Currently this vague notion of size is good enough, the only place mdict_size is used is in a maintenance command in order to print a message containing the size of the dictionary ... so we don't really care that the value isn't correct. However, in the next commit we do want the size returned to be the number of symbols in the dictionary, so this commit makes mdict_size return the symbol count in all cases. The new use is still not on a hot path -- it's going to be a Python __repr__ method, so all I do in this commit is have size_hashed walk the dictionary and count the entries, obviously this could be slow if we have a large number of symbols, but for now I'm not worrying about that case. We could always store the symbol count if we wanted, but that would increase the size of every dictionary for a use case that isn't going to be hit that often. I've updated the text in 'maint print symbols' so that we don't talk about the size being 'syms/buckets', but just 'symbols' now. --- gdb/dictionary.c | 13 ++++++++++++- gdb/dictionary.h | 3 +-- gdb/symmisc.c | 2 +- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/gdb/dictionary.c b/gdb/dictionary.c index 4f8df240a3e..f3dfe092830 100644 --- a/gdb/dictionary.c +++ b/gdb/dictionary.c @@ -650,7 +650,18 @@ insert_symbol_hashed (struct dictionary *dict, static int size_hashed (const struct dictionary *dict) { - return DICT_HASHED_NBUCKETS (dict); + int nbuckets = DICT_HASHED_NBUCKETS (dict); + int total = 0; + + for (int i = 0; i < nbuckets; ++i) + { + for (struct symbol *sym = DICT_HASHED_BUCKET (dict, i); + sym != nullptr; + sym = sym->hash_next) + total++; + } + + return total; } /* Functions only for DICT_HASHED_EXPANDABLE. */ diff --git a/gdb/dictionary.h b/gdb/dictionary.h index d982396cb31..44bd075fcf2 100644 --- a/gdb/dictionary.h +++ b/gdb/dictionary.h @@ -159,8 +159,7 @@ extern struct symbol * extern struct symbol *mdict_iter_match_next (const lookup_name_info &name, struct mdict_iterator *miterator); -/* Return some notion of the size of the multidictionary: the number of - symbols if we have that, the number of hash buckets otherwise. */ +/* Return the number of symbols in multidictionary MDICT. */ extern int mdict_size (const struct multidictionary *mdict); diff --git a/gdb/symmisc.c b/gdb/symmisc.c index ff7f31f885f..e414dea7bf6 100644 --- a/gdb/symmisc.c +++ b/gdb/symmisc.c @@ -286,7 +286,7 @@ dump_symtab_1 (struct symtab *symtab, struct ui_file *outfile) /* drow/2002-07-10: We could save the total symbols count even if we're using a hashtable, but nothing else but this message wants it. */ - gdb_printf (outfile, ", %d syms/buckets in ", + gdb_printf (outfile, ", %d symbols in ", mdict_size (b->multidict ())); gdb_puts (paddress (gdbarch, b->start ()), outfile); gdb_printf (outfile, ".."); From patchwork Fri May 19 21:27:58 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrew Burgess X-Patchwork-Id: 69705 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 2DDE33858C30 for ; Fri, 19 May 2023 21:28:39 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 2DDE33858C30 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1684531719; bh=pxzp38SNtSCUMDOZJaJcH6hA4AUggp7ovWhyoPU26mA=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=ozelQgIX4jrbhmhA5DADGgDfKoi29Bl+15ZS6TqP3KMCgTijeIOWF/6qSrNfcCptc hQ5odA1pTT+DZVZ7OYeJ4IgwV1rqgKLN/wa4KnKM/cRarobezIE+nJAvtsaNMIjhX1 or7htyiB1BH2j69t6XFOaudE22fXAefCw5KBSn9A= X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by sourceware.org (Postfix) with ESMTPS id 440DD3858421 for ; Fri, 19 May 2023 21:28:11 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 440DD3858421 Received: from mail-wr1-f70.google.com (mail-wr1-f70.google.com [209.85.221.70]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-622-kV3amKs2NdSM1sdktNb5jA-1; Fri, 19 May 2023 17:28:09 -0400 X-MC-Unique: kV3amKs2NdSM1sdktNb5jA-1 Received: by mail-wr1-f70.google.com with SMTP id ffacd0b85a97d-30932d15a30so2301123f8f.1 for ; Fri, 19 May 2023 14:28:09 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684531688; x=1687123688; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=pxzp38SNtSCUMDOZJaJcH6hA4AUggp7ovWhyoPU26mA=; b=lU5igu0OGIi13Y1GtG0c4GbkHZA/MAeb7stc4matXlJR6BsWhFuoedZJvzza0awpl7 tCOVUE0n9tt4SQCHSjnmd4Dwh+m1S08RW5qwFwxSMalUHkA0+p8zJ/L3uTwTX6JWUAao 4vCYoKp/TBXd4aDEkB0+fcWK09EczzY++WKTxn68jTttqU56Z+IpSpASAiDXnv21T2lu YJjcUZkIZ+kVKhxaP0NG+dExIiGDU0MSiT6+7bYzyvYvqF+Hu1WC2MicK/FwKDVndEFH l4CcpgTplbaO9DYlfqgbAMcHhHDB5s7wG6+cfmxUoYNEjcDnXqEJFw2MI4GeiDLwvwK4 Xxpg== X-Gm-Message-State: AC+VfDzkWcaXJ4IuRqnKxUFFzwvsXzlp4drxhV38zs/7/SKNw6aAiktZ gVG/Oe3BNemSveJti2rtw4ZDJGf9Xc39/Hq7umTHQWEZO0uMVdXPRVsOGU1yY/nCUwit3MmHP56 a0jo6uj1DD3T5bCZERWsi96m6FIacF8XZdhcyXVpwX82fvaB/E3cukKB9vKp57FKPHc6qvcPQLg NXUSGEMg== X-Received: by 2002:adf:edc8:0:b0:2f6:ca0d:ec1c with SMTP id v8-20020adfedc8000000b002f6ca0dec1cmr2484834wro.10.1684531687540; Fri, 19 May 2023 14:28:07 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ6GHNNUUlr0XuhJiNJwKVpiOuXazvGiI+2Z7O86H6C1GGjCP9GS9vu/nAYG1qgKUxkpYsi2ww== X-Received: by 2002:adf:edc8:0:b0:2f6:ca0d:ec1c with SMTP id v8-20020adfedc8000000b002f6ca0dec1cmr2484821wro.10.1684531686689; Fri, 19 May 2023 14:28:06 -0700 (PDT) Received: from localhost (11.72.115.87.dyn.plus.net. [87.115.72.11]) by smtp.gmail.com with ESMTPSA id l22-20020a7bc356000000b003f1751016desm275963wmj.28.2023.05.19.14.28.06 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 19 May 2023 14:28:06 -0700 (PDT) To: gdb-patches@sourceware.org Subject: [PATCHv3 2/2] gdb: add __repr__() implementation to a few Python types Date: Fri, 19 May 2023 22:27:58 +0100 Message-Id: <8c6f3d108fc2b434194d73c3a3359473a60d571c.1684529933.git.aburgess@redhat.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: References: <20230518033357.77174-1-dark.ryu.550@gmail.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.6 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, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Andrew Burgess via Gdb-patches From: Andrew Burgess Reply-To: Andrew Burgess Errors-To: gdb-patches-bounces+patchwork=sourceware.org@sourceware.org Sender: "Gdb-patches" From: Matheus Branco Borella via Gdb-patches 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, gdb.BreakpointLocation, 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") The gdb.Block.__repr__() method shows the first 5 symbols from the block, and then a message to show how many more were elided (if any). --- gdb/python/py-arch.c | 17 ++++- gdb/python/py-block.c | 37 ++++++++++- gdb/python/py-breakpoint.c | 67 ++++++++++++++++++- gdb/python/py-symbol.c | 15 ++++- gdb/python/py-type.c | 30 ++++++++- gdb/testsuite/gdb.python/py-arch.exp | 6 ++ gdb/testsuite/gdb.python/py-block.c | 31 +++++++++ gdb/testsuite/gdb.python/py-block.exp | 38 ++++++++++- gdb/testsuite/gdb.python/py-bp-locations.exp | 32 +++++++++ gdb/testsuite/gdb.python/py-breakpoint.exp | 69 +++++++++++++++++--- gdb/testsuite/gdb.python/py-symbol.exp | 2 + gdb/testsuite/gdb.python/py-type.exp | 4 ++ 12 files changed, 329 insertions(+), 19 deletions(-) diff --git a/gdb/python/py-arch.c b/gdb/python/py-arch.c index 4d133d1fe14..ac519331f18 100644 --- a/gdb/python/py-arch.c +++ b/gdb/python/py-arch.c @@ -319,6 +319,21 @@ 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 ("<%s (invalid)>", Py_TYPE (self)->tp_name); + + auto arch_info = gdbarch_bfd_arch_info (gdbarch); + return PyUnicode_FromFormat ("<%s arch_name=%s printable_name=%s>", + Py_TYPE (self)->tp_name, arch_info->arch_name, + arch_info->printable_name); +} + /* Implementation of gdb.architecture_names(). Return a list of all the BFD architecture names that GDB understands. */ @@ -395,7 +410,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 09fa74d862c..dd6d6d278a0 100644 --- a/gdb/python/py-block.c +++ b/gdb/python/py-block.c @@ -418,6 +418,41 @@ 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 ("<%s (invalid)>", Py_TYPE (self)->tp_name); + + const auto name = block->function () ? + block->function ()->print_name () : ""; + + std::string str; + unsigned int written_symbols = 0; + const int len = mdict_size (block->multidict ()); + static constexpr int SYMBOLS_TO_SHOW = 5; + for (struct symbol *symbol : block_iterator_range (block)) + { + if (written_symbols == SYMBOLS_TO_SHOW) + { + const int remaining = len - SYMBOLS_TO_SHOW; + if (remaining == 1) + str += string_printf ("... (%d more symbol)", remaining); + else + str += string_printf ("... (%d more symbols)", remaining); + break; + } + str += symbol->print_name (); + if (++written_symbols < len) + str += ", "; + } + return PyUnicode_FromFormat ("<%s %s {%s}>", Py_TYPE (self)->tp_name, + name, str.c_str ()); +} + static int CPYCHECKER_NEGATIVE_RESULT_SETS_EXCEPTION gdbpy_initialize_blocks (void) { @@ -482,7 +517,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 becb04c91c1..caf58e4b101 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 "gdbsupport/common-utils.h" extern PyTypeObject breakpoint_location_object_type CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("breakpoint_location_object"); @@ -981,6 +982,31 @@ 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 ("<%s (invalid)>", Py_TYPE (self)->tp_name); + + std::string str = " "; + if (bp->bp->thread != -1) + str += string_printf ("thread=%d ", bp->bp->thread); + if (bp->bp->task > 0) + str += string_printf ("task=%d ", bp->bp->task); + if (bp->bp->enable_count > 0) + str += string_printf ("enable_count=%d ", bp->bp->enable_count); + str.pop_back (); + + return PyUnicode_FromFormat ("<%s%s number=%d hits=%d%s>", + Py_TYPE (self)->tp_name, + (bp->bp->enable_state == bp_enabled + ? "" : " disabled"), bp->bp->number, + bp->bp->hit_count, str.c_str ()); +} + /* Append to LIST the breakpoint Python object associated to B. Return true on success. Return false on failure, with the Python error @@ -1406,7 +1432,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*/ @@ -1624,6 +1650,43 @@ 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 ("<%s (invalid)>", Py_TYPE (self)->tp_name); + + const auto enabled = self->bp_loc->enabled ? "enabled" : "disabled"; + + std::string str (enabled); + + str += string_printf (" address=%s", + paddress (self->bp_loc->owner->gdbarch, + self->bp_loc->address)); + + if (self->bp_loc->requested_address != self->bp_loc->address) + str += string_printf (" requested_address=%s", + paddress (self->bp_loc->owner->gdbarch, + self->bp_loc->requested_address)); + if (self->bp_loc->symtab != nullptr) + str += string_printf (" source=%s:%d", self->bp_loc->symtab->filename, + self->bp_loc->line_number); + + const auto fn_name = self->bp_loc->function_name.get (); + if (fn_name != nullptr) + { + str += " in "; + str += fn_name; + } + + return PyUnicode_FromFormat ("<%s %s>", Py_TYPE (self)->tp_name, + str.c_str ()); +} + /* Attribute get/set Python definitions. */ static gdb_PyGetSetDef bp_location_object_getset[] = { @@ -1655,7 +1718,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 ff3d18504e7..ee863aa4df4 100644 --- a/gdb/python/py-symbol.c +++ b/gdb/python/py-symbol.c @@ -378,6 +378,19 @@ 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 ("<%s (invalid)>", Py_TYPE (self)->tp_name); + + return PyUnicode_FromFormat ("<%s print_name=%s>", Py_TYPE (self)->tp_name, + 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 @@ -741,7 +754,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 b9fa741177f..b4d1e230b3b 100644 --- a/gdb/python/py-type.c +++ b/gdb/python/py-type.c @@ -1028,6 +1028,34 @@ typy_template_argument (PyObject *self, PyObject *args) return result; } +/* __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 ("<%s (invalid)>", + Py_TYPE (self)->tp_name); + + 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 ("<%s code=%s name=%U>", Py_TYPE (self)->tp_name, + code, py_typename); +} + static PyObject * typy_str (PyObject *self) { @@ -1617,7 +1645,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 4f4b4aa766f..597943ff682 100644 --- a/gdb/testsuite/gdb.python/py-arch.exp +++ b/gdb/testsuite/gdb.python/py-arch.exp @@ -27,6 +27,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" 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.*" \ @@ -44,6 +46,10 @@ 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" + 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.c b/gdb/testsuite/gdb.python/py-block.c index a0c6e165605..dd2e195af4a 100644 --- a/gdb/testsuite/gdb.python/py-block.c +++ b/gdb/testsuite/gdb.python/py-block.c @@ -30,9 +30,40 @@ int block_func (void) } } +/* A function with no locals. Used for testing gdb.Block.__repr__(). */ +int no_locals_func (void) +{ + return block_func (); +} + +/* A function with 5 locals. Used for testing gdb.Block.__repr__(). */ +int few_locals_func (void) +{ + int i = 0; + int j = 0; + int k = 0; + int x = 0; + int y = 0; + return block_func (); +} + +/* A function with 6 locals. Used for testing gdb.Block.__repr__(). */ +int many_locals_func (void) +{ + int i = 0; + int j = 0; + int k = 0; + int x = 0; + int y = 0; + int z = 0; + return block_func (); +} int main (int argc, char *argv[]) { block_func (); + no_locals_func (); + few_locals_func (); + many_locals_func (); return 0; /* Break at end. */ } diff --git a/gdb/testsuite/gdb.python/py-block.exp b/gdb/testsuite/gdb.python/py-block.exp index 3bdf97294ae..37e3105b4e3 100644 --- a/gdb/testsuite/gdb.python/py-block.exp +++ b/gdb/testsuite/gdb.python/py-block.exp @@ -38,7 +38,8 @@ 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)" " \{i, f, b\}>" \ + "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" @@ -68,15 +69,46 @@ gdb_test_no_output "python block = block.superblock" "get superblock 2" gdb_test "python print (block.function)" "block_func" \ "Print superblock 2 function" +# Switch frames, then test block for no_locals_func. +gdb_test "continue" ".*" "continue to no_locals_func breakpoint" +gdb_test "up" ".*" "up to no_locals_func" +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))" "" \ + "Check block in no_locals_func" +gdb_test "python print (block.function)" "no_locals_func" \ + "no_locals_func block" + +# Switch frames, then test block for few_locals_func. +gdb_test "continue" ".*" "continue to few_locals_func breakpoint" +gdb_test "up" ".*" "up to few_locals_func" +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))" \ + "" \ + "Check block in few_locals_func" +gdb_test "python print (block.function)" "few_locals_func" \ + "few_locals_func block" + +# Switch frames, then test block for many_locals_func. +gdb_test "continue" ".*" "continue to many_locals_func breakpoint" +gdb_test "up" ".*" "up to many_locals_func" +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))" \ + "" \ + "Check block in many_locals_func" +gdb_test "python print (block.function)" "many_locals_func" \ + "many_locals_func block" + # Switch frames, then test for main block. 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" - # Test Block is_valid. This must always be the last test in this # testcase as it unloads the object file. delete_breakpoints diff --git a/gdb/testsuite/gdb.python/py-bp-locations.exp b/gdb/testsuite/gdb.python/py-bp-locations.exp index f8649f6c105..b3a8c83bc0a 100644 --- a/gdb/testsuite/gdb.python/py-bp-locations.exp +++ b/gdb/testsuite/gdb.python/py-bp-locations.exp @@ -31,6 +31,30 @@ if ![runto_main] { return -1 } +# Build a regexp string that represents the __repr__ of a +# gdb.BreakpointLocation object. Accepts arguments -enabled, -address, +# -source, -line, and -func. +proc build_bpl_regexp { args } { + parse_args [list {enabled True} [list address "$::hex"] {source ".*"} \ + [list line "$::decimal"] {func ""}] + + set pattern "" + return $pattern +} + # Set breakpoint with 2 locations. gdb_breakpoint "add" @@ -42,9 +66,17 @@ gdb_test "python print(gdb.breakpoints()\[1\].locations\[0\].source)" \ ".*('.*py-bp-locations.c', $expected_line_a).*" gdb_test "python print(gdb.breakpoints()\[1\].locations\[1\].source)" \ ".*('.*py-bp-locations.c', $expected_line_b).*" +gdb_test "python print(gdb.breakpoints()\[1\].locations\[1\])" \ + [build_bpl_regexp -enabled True -source ".*py-bp-locations.c" \ + -line "$expected_line_b" -func ".*"] \ + "check repr of enabled breakpoint location" # Disable first location and make sure we don't hit it. gdb_test "python gdb.breakpoints()\[1\].locations\[0\].enabled = False" "" +gdb_test "python print(gdb.breakpoints()\[1\].locations\[0\])" \ + [build_bpl_regexp -enabled False -source ".*py-bp-locations.c" \ + -line "$expected_line_a" -func ".*"] \ + "check repr of disabled breakpoint location" gdb_continue_to_breakpoint "" ".*25.*" if ![runto_main] { diff --git a/gdb/testsuite/gdb.python/py-breakpoint.exp b/gdb/testsuite/gdb.python/py-breakpoint.exp index 76094c95d10..df17d646b28 100644 --- a/gdb/testsuite/gdb.python/py-breakpoint.exp +++ b/gdb/testsuite/gdb.python/py-breakpoint.exp @@ -38,6 +38,36 @@ if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} ${options}] set past_throw_catch_line [gdb_get_line_number "Past throw-catch."] +# Build a regexp string that can match against the repr of a gdb.Breakpoint +# object. Accepts arguments -enabled, -number, -hits, -thread, -task, and +# -enable_count. The -enabled argument is a boolean, while all of the others +# take a regexp string. +proc build_bp_repr { args } { + parse_args [list {enabled True} [list number "-?$::decimal"] \ + [list hits $::decimal] {thread ""} {task ""} \ + {enable_count ""}] + + set pattern "" + return $pattern +} + proc_with_prefix test_bkpt_basic { } { global srcfile testfile hex decimal @@ -54,8 +84,8 @@ proc_with_prefix test_bkpt_basic { } { # 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\]))" \ + [build_bp_repr -number 1 -hits 1] "Check obj exists @main" gdb_test "python print (blist\[0\].location)" \ "main" "Check breakpoint location @main" gdb_test "python print (blist\[0\].pending)" "False" \ @@ -72,12 +102,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\]))" \ + [build_bp_repr -number 1 -hits 1] "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\]))" \ + [build_bp_repr -number 2 -hits 1] "Check obj exists @mult_line" gdb_test "python print (blist\[1\].location)" \ "py-breakpoint\.c:${mult_line}*" \ @@ -102,6 +132,9 @@ proc_with_prefix test_bkpt_basic { } { "True" "Check breakpoint enabled." gdb_py_test_silent_cmd "python blist\[1\].enabled = False" \ "Set breakpoint disabled." 0 + gdb_test "python print (repr (blist\[1\]))" \ + [build_bp_repr -enabled False -number 2 -hits 6] \ + "Check repr for a disabled breakpoint" gdb_continue_to_breakpoint "Break at add 2" ".*Break at add.*" gdb_py_test_silent_cmd "python blist\[1\].enabled = True" \ "Set breakpoint enabled." 0 @@ -113,6 +146,13 @@ proc_with_prefix test_bkpt_basic { } { "Get Breakpoint List" 0 gdb_test "python print (blist\[1\].thread)" \ "None" "Check breakpoint thread" + gdb_py_test_silent_cmd "python blist\[1\].thread = 1" \ + "set breakpoint thread" 0 + gdb_test "python print (repr (blist\[1\]))" \ + [build_bp_repr -number 2 -hits 7 -thread 1] \ + "Check repr for a thread breakpoint" + gdb_py_test_silent_cmd "python blist\[1\].thread = None" \ + "clear breakpoint thread" 0 gdb_test "python print (blist\[1\].type == gdb.BP_BREAKPOINT)" \ "True" "Check breakpoint type" gdb_test "python print (blist\[0\].number)" \ @@ -231,8 +271,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 1" + gdb_test "python print (repr (ilist\[0\]))" \ + [build_bp_repr -number 2 -hits 0] "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)" \ @@ -244,8 +284,9 @@ 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\]))" \ + [build_bp_repr -number "-$decimal" -hits 0] \ + "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)" \ @@ -835,6 +876,14 @@ proc_with_prefix test_bkpt_auto_disable { } { set mult_line [gdb_get_line_number "Break at multiply."] gdb_breakpoint ${mult_line} gdb_test_no_output "enable count 1 2" "one shot enable" + + # Find the Python gdb.Breakpoint object for breakpoint #2. + gdb_py_test_silent_cmd \ + "python bp = \[b for b in gdb.breakpoints() if b.number == 2\]\[0\]" \ + "Get breakpoint number 2" 0 + gdb_test "python print (repr (bp))" \ + [build_bp_repr -number 2 -hits 0 -enable_count 1] + # Python 2 doesn't support print in lambda function, so use a named # function instead. gdb_test_multiline "Define print_bp_enabled" \ diff --git a/gdb/testsuite/gdb.python/py-symbol.exp b/gdb/testsuite/gdb.python/py-symbol.exp index 9ec2f44e9c0..9bd5a35ed1c 100644 --- a/gdb/testsuite/gdb.python/py-symbol.exp +++ b/gdb/testsuite/gdb.python/py-symbol.exp @@ -43,6 +43,8 @@ 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 c245d41a1ac..918216ddd69 100644 --- a/gdb/testsuite/gdb.python/py-type.exp +++ b/gdb/testsuite/gdb.python/py-type.exp @@ -388,3 +388,7 @@ if { [build_inferior "${binfile}-cxx" "c++"] == 0 } { test_type_equality } } + +# Test __repr__(). +gdb_test "python print (repr (gdb.lookup_type ('char')))" \ + "" "test __repr__()"