From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id tdYqJT86q2gbawsAWB0awg (envelope-from ) for ; Sun, 24 Aug 2025 12:13:51 -0400 Authentication-Results: simark.ca; dkim=pass (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=KasMGMaZ; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 8517C1E023; Sun, 24 Aug 2025 12:13:51 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-1.8 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, RCVD_IN_DNSWL_LOW,RCVD_IN_VALIDITY_CERTIFIED_BLOCKED, RCVD_IN_VALIDITY_RPBL_BLOCKED,RCVD_IN_VALIDITY_SAFE_BLOCKED autolearn=no autolearn_force=no version=4.0.1 Received: from server2.sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 11A651E023 for ; Sun, 24 Aug 2025 12:13:50 -0400 (EDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 7D7FD3858291 for ; Sun, 24 Aug 2025 16:13:49 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 7D7FD3858291 Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=KasMGMaZ Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id ADB943858C39 for ; Sun, 24 Aug 2025 16:13:11 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org ADB943858C39 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org ADB943858C39 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1756051991; cv=none; b=YahSE3XyAn/c0cIt9b06ydBkyGSzN49FRP3SDH7LR3kj4X2xErvfIbWPACzr/+osqA3JyxtN8SE8LHB46Dh7rX2s6xxSukXVqaEBCATbbAOKwsDZQ7QCIt3aW8bNMy2RNhip35WdmxcULhh+niPmKAowqGowaFWDFrW40t/0VK4= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1756051991; c=relaxed/simple; bh=ozlWIral1G7ecKG7OnmrPI5Iw82S2iBMoSQKuViqDPA=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=Pjsr/V9OO/htFpAK8X0pFwN+OtRgwSRHigKy39vZlyPghzxbSAiHgb9VOjVCpeYjeyEpsXEzAP2Rc73VR3VbFX0P1yAg/9c1rfXPP/qE/pLYmGWt8HowglLsvM/OkIuhKR+Kd1mkEbZ13/dkPMlPGY9l4AoEvEFnxaZb7P+oDM8= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org ADB943858C39 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1756051991; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=HlLA0ilZfj/oDTYASTHZMBteZ/JCApuQjpq50YJ+tbo=; b=KasMGMaZ2na014PF/j/Rpl4r/lOrwC5N8cGcQa0pHhcCe3HAWuATMV3k3mv7cCuP9aB+O6 z0Klap52b641SNpd7QoCxqxPjHMxmU1cJ0TJUmcQOIRx/ZMyqSo1C7frheOSHdhHQYzvys fGNJQVo6Fz4JzIJGjS/3WyUp3pUGRN8= Received: from mail-wm1-f72.google.com (mail-wm1-f72.google.com [209.85.128.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-33-Y46Zwk2LMCKxGNM22LAxmQ-1; Sun, 24 Aug 2025 12:13:09 -0400 X-MC-Unique: Y46Zwk2LMCKxGNM22LAxmQ-1 X-Mimecast-MFC-AGG-ID: Y46Zwk2LMCKxGNM22LAxmQ_1756051989 Received: by mail-wm1-f72.google.com with SMTP id 5b1f17b1804b1-45a1b04f817so14949075e9.1 for ; Sun, 24 Aug 2025 09:13:09 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1756051988; x=1756656788; h=mime-version:message-id:date:references:in-reply-to:subject:to:from :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=HlLA0ilZfj/oDTYASTHZMBteZ/JCApuQjpq50YJ+tbo=; b=anNOhWrF9iOh7/sFJSkf1/Hguf3gjZJ8o/o2xQXNOCsKBhVSZMueXvvPpt6hd1xmGE XLRhFdArUqEw+W7MYFqmX97iKopENXXg79+/7ptO1LDfab5FHQaMgWR3Hgz0iBkaZHda yNC30ZKJ5HDICWdVcTTmaADeIsFBFcnxRhe07DOPRX4O55zup8PA1FsAc8GHoFWQpWwq WnPqtxbb0IUCQHKn2oyvhSfRB/A0VMIbOYyEFHIGHUCJePDV7hvSLuDd+hFG2IqrQOwV 2PKcHqe9O3TbRcmM3eFbGxGCS9V28I19tcuSVX8J2R5UMwl0DWAlsVxHnVzzWGIR3ieR o9+g== X-Gm-Message-State: AOJu0Yy5ccn3BCu2tBOwGnBrNOCxYuZG+wMGligMtsWcfdaMa0UOiBCT iG/u0QCN0PPM2qV256kYu8+RUvbJgHZBYwCVoySEWFqOR+FBk8/Xv1fSYUFgV5PBCptZAXZRkbu oZ3dVoCTwQREs65OWlYE0CHR05beigBE8TFnIgF5c1nY09GvHOesuHfKhbjmqWD4EDSScwKpDSn ZWsh1fx52NfXLKh+0oFgCJWumVAQXOjx7tiuaLPznHGB0sy84= X-Gm-Gg: ASbGncu6w1QPagBW557d4GltVt7CVbMNhrEOq4xceaExi0Xns/LUdJbYv/uLtsSGfbj 0OSgmsU1Y+AySeJq5LbiGL80u7cRzjt8pDtjRa11S1G0M/K/RE8UwMJ21j+HvcojvjcqyLwoPb9 uD4kgzniCAxHEKF4KDrciIAA9UcgbTwiu/1oQYFZ2X0DA+X5Kl+wDsMsAN35fCyBpuceNPBSU4B d7C0SXTLTTZGu6dndTykk4NtVM8peL0xcOqchYbZXYSTvdZeQbieXdtZ3zgz+W/nPVpLiVA5W97 UqZaIqLfWRIR5WBaNM4ARkwl5ZdqtULpYak= X-Received: by 2002:a05:600c:1d25:b0:456:fc1:c286 with SMTP id 5b1f17b1804b1-45b517955bcmr72068205e9.1.1756051988065; Sun, 24 Aug 2025 09:13:08 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGSMuQVdwHIvoS5GjT1r/o194ywpRHpMRK5t+QdV9C9FYB42Dp/AuhMFLvlnkAkJNAq50+RDg== X-Received: by 2002:a05:600c:1d25:b0:456:fc1:c286 with SMTP id 5b1f17b1804b1-45b517955bcmr72067955e9.1.1756051987317; Sun, 24 Aug 2025 09:13:07 -0700 (PDT) Received: from localhost ([31.111.84.207]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-45b57498d9csm74036465e9.22.2025.08.24.09.13.06 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 24 Aug 2025 09:13:06 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Subject: Re: [PATCHv7 1/4] gdb: allow gdb.Color to work correctly with pagination In-Reply-To: <844e588de821a4d87f1605d25464f270718f2a17.1755080429.git.aburgess@redhat.com> References: <844e588de821a4d87f1605d25464f270718f2a17.1755080429.git.aburgess@redhat.com> Date: Sun, 24 Aug 2025 17:13:05 +0100 Message-ID: <87y0r866lq.fsf@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: Yo-RkshTwoZ0Vlm8HZqoBNoX_8rx9kdknHAgvO-WqF8_1756051989 X-Mimecast-Originator: redhat.com Content-Type: text/plain X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~public-inbox=simark.ca@sourceware.org Andrew Burgess writes: > This commit allows gdb.Color objects to be used to style output from > GDB commands written in Python, and the styled output should work > correctly with pagination. I've gone ahead and pushed this fix. I believe that the change I've made here is inline with how the same problem is handled in the TUI, parsing the escape sequence and then using the resulting ui_file_style object. And the second part of the fix, changing gdb_printf to gdb_puts falls out from making the first change. Given that the gdb.Color API was added since GDB 16, it seems sensible to get this bug fixed before GDB 17 branches. The other patches in this series I've not pushed, pending review. Thanks, Andrew > > There are two parts to fixing this: > > First, GDB needs to be able to track the currently applied style > within the page_file class. This means that style changes need to be > achieved with calls to pager_file::emit_style_escape. > > Now usually, GDB does this by calling something like fprintf_styled, > which takes care to apply the style for us. However, that's not > really an option here as a gdb.Color isn't a full style, and as the > gdb.Color object is designed to be converted directly into escape > sequences that can then be printed, we really need a solution that > works with this approach. > > However pager_file::puts already has code in place to handle escape > sequences. Right now all this code does is spot the escape sequence > and append it to the m_wrap_buffer. But in this commit I propose that > we go one step further, parse the escape sequence back into a > ui_file_style object in pager_file::puts, and then we can call > pager_file::emit_style_escape. > > If the parsing doesn't work then we can just add the escape sequence > to m_wrap_buffer as we did before. > > But wait, how can this work if a gdb.Color isn't a full style? Turns > out that's not a problem. We only ever emit the escape sequence for > those parts of a style that need changing, so a full style that sets > the foreground color will emit the same escape sequence as a gdb.Color > for the foreground. When we convert the escape sequence back into a > ui_file_style, then we get a style with everything set to default, > except the foreground color. > > I had hoped that this would be all that was needed. But unfortunately > this doesn't work because of the second problem... > > ... the implementation of the Python function gdb.write() calls > gdb_printf(), which calls gdb_vprintf(), which calls ui_file::vprintf, > which calls ui_out::vmessage, which calls ui_out::call_do_message, and > finally we reach cli_ui_out::do_message. This final do_message > function does this: > > ui_file *stream = m_streams.back (); > stream->emit_style_escape (style); > stream->puts (str.c_str ()); > stream->emit_style_escape (ui_file_style ()); > > If we imagine the case where we are emitting a style, triggered from > Python like this: > > gdb.write(gdb.Color('red').escape_sequence(True)) > > the STYLE in this case will be the default ui_file_style(), and STR > will hold the escape sequence we are writing. > > After the first change, where pager_file::puts now calls > pager_file::emit_style_escape, the current style of STREAM will have > been updated. But this means that the final emit_style_escape will > now restore the default style. > > The fix for this is to avoid using the high level gdb_printf from > gdb.write(), and instead use gdb_puts instead. The gdb_puts function > doesn't restore the default style, which means our style modification > survives. > > There's a new test included. This test includes what appears like a > pointless extra loop (looping over a single value), but later commits > in this series will add more values to this list. > --- > gdb/python/python.c | 18 +-- > .../gdb.python/py-color-pagination.exp | 122 ++++++++++++++++++ > .../gdb.python/py-color-pagination.py | 46 +++++++ > gdb/utils.c | 21 ++- > 4 files changed, 195 insertions(+), 12 deletions(-) > create mode 100644 gdb/testsuite/gdb.python/py-color-pagination.exp > create mode 100644 gdb/testsuite/gdb.python/py-color-pagination.py > > diff --git a/gdb/python/python.c b/gdb/python/python.c > index cb0d642a67d..1af7896eb08 100644 > --- a/gdb/python/python.c > +++ b/gdb/python/python.c > @@ -1570,21 +1570,21 @@ gdbpy_write (PyObject *self, PyObject *args, PyObject *kw) > > try > { > + ui_file *stream; > switch (stream_type) > { > case 1: > - { > - gdb_printf (gdb_stderr, "%s", arg); > - break; > - } > + stream = gdb_stderr; > + break; > case 2: > - { > - gdb_printf (gdb_stdlog, "%s", arg); > - break; > - } > + stream = gdb_stdlog; > + break; > default: > - gdb_printf (gdb_stdout, "%s", arg); > + stream = gdb_stdout; > + break; > } > + > + gdb_puts (arg, stream); > } > catch (const gdb_exception &except) > { > 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 00000000000..3235fffe5cc > --- /dev/null > +++ b/gdb/testsuite/gdb.python/py-color-pagination.exp > @@ -0,0 +1,122 @@ > +# 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 . > + > +# This file is part of the GDB testsuite. It tests gdb.Color and how this > +# interacts with GDB's pagination system. > + > +load_lib gdb-python.exp > + > +require allow_python_tests > + > +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 "" > + && $restored_color ne $expected_restore_color } { > + set saw_bad_color_handling true > + } > + set last_color $expect_out(2,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 > + > + # If we didn't see a color reset sequence then the pagination > + # prompt will have been printed in the wrong color, this is a > + # GDB bug. > + set color_reset $expect_out(1,string) > + if { $color_reset eq "" } { > + 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 > + } > + } > +} > + > +foreach_with_prefix type { color } { > + foreach_with_prefix mode { write print } { > + test_pagination $type $mode > + } > +} > 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 00000000000..efd501eedf5 > --- /dev/null > +++ b/gdb/testsuite/gdb.python/py-color-pagination.py > @@ -0,0 +1,46 @@ > +# 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 . > + > +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") > + > + > +ColorTester() > diff --git a/gdb/utils.c b/gdb/utils.c > index 10d3d51e481..92e626a9c75 100644 > --- a/gdb/utils.c > +++ b/gdb/utils.c > @@ -1702,10 +1702,25 @@ pager_file::puts (const char *linebuffer) > else if (*linebuffer == '\033' > && skip_ansi_escape (linebuffer, &skip_bytes)) > { > - m_wrap_buffer.append (linebuffer, skip_bytes); > - /* Note that we don't consider this a character, so we > + /* We don't consider escape sequences as characters, so we > don't increment chars_printed here. */ > - linebuffer += skip_bytes; > + > + size_t style_len; > + ui_file_style style; > + if (style.parse (linebuffer, &style_len) > + && style_len <= skip_bytes) > + { > + this->emit_style_escape (style); > + > + linebuffer += style_len; > + skip_bytes -= style_len; > + } > + > + if (skip_bytes > 0) > + { > + m_wrap_buffer.append (linebuffer, skip_bytes); > + linebuffer += skip_bytes; > + } > } > else if (*linebuffer == '\r') > { > -- > 2.47.1