From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-oa1-x2b.google.com (mail-oa1-x2b.google.com [IPv6:2001:4860:4864:20::2b]) by sourceware.org (Postfix) with ESMTPS id E51373858CDA for ; Wed, 11 Jan 2023 00:36:15 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org E51373858CDA Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com Received: by mail-oa1-x2b.google.com with SMTP id 586e51a60fabf-150debe2b7cso14066870fac.0 for ; Tue, 10 Jan 2023 16:36:15 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=AmVaPrN9sGPnqaGz2N6rsyXd/IXrOGvwBzOxhQTgjHY=; b=bzU7V3YkajOgWR+btekWEw2jsELFxdr0M3sN6oJ7zRUnZPtICWSmI1qCJMtMOWi4gb Jc5/UX2c5gRbQAIRiMXTyrtYfriK7sqbvkpEKs1q7gTXw5q5Mu8xedC8//4v1S6wPDA5 ewuTWbs0Yvi5ZktS6no2bNUDkazBeeGMlws9D+vZEIudizywNb0Lh20yIKhms7NeAHN6 U/aeT7LUtTuAyU2ZO3G20z4x9EH63+uVCVTbP8L/qKKRoVSHcyY8XiJenHyDfSGBCuSg zR+HJnS2E7t6KD2WiRGY/F29JoK9RJct86+Ts0vq3wj3gaVvMv4aomLFPserd5UfueqW dXNg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; 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=AmVaPrN9sGPnqaGz2N6rsyXd/IXrOGvwBzOxhQTgjHY=; b=hCiabA175TRNOxrd9sdRsmltQr+KgWnyurizqsRVOXAZUSnhrs9E1QwE8QQwj5yZsQ pzTfENdPLFSTG9lKsvX4eGlJDzqNQHYQWeTwgKpCHlEMWMJL43+0ZybBhECY83Equ0gW TEQwPInydzL10zVqXbD1VKqsTgmggKCy8+bIfv1RKCPGVxXdkDXgedSrzTCki++JhOzS MSQQkZaVXVqRRNMQ5aieZOQkuSOISOIGTqrv6aDuTGjKrcOaq4+83qW4bKFj9xzQYuAz 344PbltVGtdmuZaUPwlUQXhSFs3d2/VbebYxxaKZ9UMHLtwFbKwMDct4G8c/lmFAPO0E bf8Q== X-Gm-Message-State: AFqh2kpGVY3w8qz0glsMGQaNtKEinTbIWhxQr6fufgS7UJaQOf3DKMU+ 2pqmnZtGk7NrrJuSy0gZMeXK5S7y9VDlXw== X-Google-Smtp-Source: AMrXdXtFXeHgzxFKncxKBV069sBK6hibGMnMVJzcQLv4sOR9cq/pFkd4u/nZlzSDh0A17xB89RPsjg== X-Received: by 2002:a05:6870:e392:b0:150:5fe2:c016 with SMTP id x18-20020a056870e39200b001505fe2c016mr20749210oad.42.1673397374118; Tue, 10 Jan 2023 16:36:14 -0800 (PST) Received: from localhost.localdomain ([2804:431:e7c6:b437:c196:9410:1b9d:ea2]) by smtp.gmail.com with ESMTPSA id t13-20020a056871020d00b0014435b51ef7sm6561280oad.30.2023.01.10.16.36.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Jan 2023 16:36:13 -0800 (PST) From: Matheus Branco Borella To: gdb-patches@sourceware.org Cc: Matheus Branco Borella Subject: [PATCH] Add __repr__() implementation to a few Python types Date: Tue, 10 Jan 2023 21:35:11 -0300 Message-Id: <20230111003510.620-1-dark.ryu.550@gmail.com> X-Mailer: git-send-email 2.37.3.windows.1 In-Reply-To: <3Cc9d2dc49-45c7-d6b9-c567-4ec78dd870a0> References: <3Cc9d2dc49-45c7-d6b9-c567-4ec78dd870a0> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-11.5 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM,GIT_PATCH_0,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS,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: 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") ``` 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. --- 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(""); + + const auto name = block->function () ? block->function ()->print_name () : ""; + + 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; + + 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); +} + /* 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 (""); + + 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; + + 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; } + /* 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); +} + 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" 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" + 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 "" + # 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