From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id 4/AEKdneGWrxgycAWB0awg (envelope-from ) for ; Fri, 29 May 2026 14:45:45 -0400 Authentication-Results: simark.ca; dkim=fail reason="signature verification failed" (768-bit key; unprotected) header.d=tromey.com header.i=@tromey.com header.a=rsa-sha256 header.s=default header.b=nJlrDElX; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id 9A1EE1E0A3; Fri, 29 May 2026 14:45:45 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIM_INVALID,DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED, RCVD_IN_VALIDITY_CERTIFIED_BLOCKED,RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED,WEIRD_PORT autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32]) (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 DF58E1E024 for ; Fri, 29 May 2026 14:45:43 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 62F344BA798A for ; Fri, 29 May 2026 18:45:43 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 62F344BA798A Authentication-Results: sourceware.org; dkim=fail reason="signature verification failed" (768-bit key, unprotected) header.d=tromey.com header.i=@tromey.com header.a=rsa-sha256 header.s=default header.b=nJlrDElX Received: from omta040.useast.a.cloudfilter.net (omta040.useast.a.cloudfilter.net [44.202.169.39]) by sourceware.org (Postfix) with ESMTPS id A8C484BA23E0 for ; Fri, 29 May 2026 18:45:13 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org A8C484BA23E0 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=tromey.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=tromey.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org A8C484BA23E0 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=44.202.169.39 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1780080313; cv=none; b=Apoyxqsvzpx73VxeFNY8dC4/ygGEmHaarShJxZDM64knOoqRrO3Jgj1rPDRLwMFsCRgO2LCXfAqKUw0FyKCZ4KX3ZHtiydCzjZXs5HjdmttO3AA41R6tYDxdf4EZAZB1xYk69L0Na86C1/XazdQxvzQWwafRe5E9HyLvSeDOG+I= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1780080313; c=relaxed/simple; bh=zopKJCugar3dkDAEjkC+aIQVPk3M4NmJ2x4kmHjuERI=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=JgwTVyqsgNGUsVy5N8hZ92qCgVM9uza7vevUMK5ix4tT0kVkPt70Ld39fbQxHZMWhMI5+VXAtB3amFby0TN8sm1xQmCki2KZGAuK5afOfmsq0r/riOr58/u0v2n1Z9DAVTFwikpzyP275+5axgBIRWnaMgJpAtUcMUyTJQ2PV2g= ARC-Authentication-Results: i=1; sourceware.org; dkim=policy (768-bit key, unprotected) header.d=tromey.com header.i=@tromey.com header.a=rsa-sha256 header.s=default header.b=nJlrDElX reason="signing key too small" DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A8C484BA23E0 Received: from eig-obgw-6006b.ext.cloudfilter.net ([10.0.30.211]) by cmsmtp with ESMTPS id St4UwVkhiXAbtT2CnwdBbR; Fri, 29 May 2026 18:45:13 +0000 Received: from box5379.bluehost.com ([162.241.216.53]) by cmsmtp with ESMTPS id T2CkwMP8CWBahT2ClwYLlG; Fri, 29 May 2026 18:45:11 +0000 X-Authority-Analysis: v=2.4 cv=Y9D4sgeN c=1 sm=1 tr=0 ts=6a19deb9 a=ApxJNpeYhEAb1aAlGBBbmA==:117 a=ApxJNpeYhEAb1aAlGBBbmA==:17 a=NGcC8JguVDcA:10 a=ItBw4LHWJt0A:10 a=cdNdZQPPu_6_a5nBStQA:9 a=O8hF6Hzn-FEA:10 a=DCx65vhANUyCzuf5D8fC:22 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=tromey.com; s=default; h=Content-Transfer-Encoding:MIME-Version:Message-ID:Date:Subject: Cc:To:From:Sender:Reply-To:Content-Type:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=4QZZMzICaDu4zswxjqkqCM5RJpv+ICH5JiGhSaltH5s=; b=nJlrDElX1DOrNmt8Wynltc7Z6U P7hsHvyfj2lpNzfcnb49EPn3ClqUtSCPIiB7t8/HGSb7Opu14apYV8lDK0kT6m3jkROqh5xCMqGs4 mf/5uAT3yQcmWnV8oTMIim4AU; Received: from 75-166-225-82.hlrn.qwest.net ([75.166.225.82]:51000 helo=localhost.localdomain) by box5379.bluehost.com with esmtpsa (TLS1.3) tls TLS_AES_256_GCM_SHA384 (Exim 4.99.2) (envelope-from ) id 1wT2Ck-0000000384S-2rer; Fri, 29 May 2026 12:45:10 -0600 From: Tom Tromey To: gdb-patches@sourceware.org Cc: Tom Tromey Subject: [RFC] Show the selected frame in "bt" Date: Fri, 29 May 2026 12:45:03 -0600 Message-ID: <20260529184503.3263361-1-tom@tromey.com> X-Mailer: git-send-email 2.49.0 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - box5379.bluehost.com X-AntiAbuse: Original Domain - sourceware.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - tromey.com X-BWhitelist: no X-Source-IP: 75.166.225.82 X-Source-L: No X-Exim-ID: 1wT2Ck-0000000384S-2rer X-Source: X-Source-Args: X-Source-Dir: X-Source-Sender: 75-166-225-82.hlrn.qwest.net (localhost.localdomain) [75.166.225.82]:51000 X-Source-Auth: tom+tromey.com X-Email-Count: 1 X-Org: HG=bhshared;ORG=bluehost; X-Source-Cap: ZWx5bnJvYmk7ZWx5bnJvYmk7Ym94NTM3OS5ibHVlaG9zdC5jb20= X-Local-Domain: yes X-CMAE-Envelope: MS4xfIyCEHusekQ1U/pGy/MOxY6xmmmD3kJ/Mo5AwS67guAiCvSZyrS5oL662lI46cSi/FOaeOzfjsT0M2s8diw/7fc5kVE6Nhnsx0CeWWW/gcxBlHfbZa4G B1y+XPdenBz2ysKmIcUDmdMCKPElHs2xOMCB1zFpj7lfgdxMom/nC/CzxIYCckHUYSeJAB5mjzmc/KIVbIR2NiLEtiLTBsnrlhM= 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 I've occasionally wished that "bt" would indicate the selected frame. This patch implements this idea. In particular it marks the selected frame with "*", similar to other "selected" output in gdb. (See that other series where emoji were allowed in the "current" column of a table; if that is ever resurrected, I'd expect the same treatment to be applied here.) Now the output looks like: (gdb) bt #0 0x00007ffff6e381fd in poll () from /lib64/libc.so.6 #1 0x000000000100b1ee in gdb_wait_for_event (block=1) at ../../binutils-gdb/gdbsupport/event-loop.cc:587 #2 0x000000000100a77f in gdb_do_one_event (mstimeout=-1) at ../../binutils-gdb/gdbsupport/event-loop.cc:263 * #3 0x00000000007d2c6a in interp::do_one_event (this=, mstimeout=-1) at ../../binutils-gdb/gdb/interps.h:90 #4 start_event_loop () at ../../binutils-gdb/gdb/main.c:400 #5 captured_command_loop () at ../../binutils-gdb/gdb/main.c:465 #6 0x00000000007d5715 in captured_main (context=context@entry=0x7fffffffdd10) at ../../binutils-gdb/gdb/main.c:1373 #7 gdb_main (args=args@entry=0x7fffffffdd50) at ../../binutils-gdb/gdb/main.c:1392 #8 0x0000000000452cd5 in main (argc=1, argv=0x7fffffffdea8) at ../../binutils-gdb/gdb/gdb.c:38 I think the main downside of this patch is that it uses a little more horizontal space for the indicator. This patch will not regression-test cleanly. There are many tests that need an update to match the new output. However, I wanted to send this out for conceptual approval before doing that work. Let me know what you think. --- gdb/extension-priv.h | 3 ++- gdb/extension.c | 8 +++++--- gdb/extension.h | 3 ++- gdb/frame.h | 3 ++- gdb/mi/mi-cmd-stack.c | 8 ++++---- gdb/python/py-framefilter.c | 18 +++++++++++++---- gdb/python/python-internal.h | 3 ++- gdb/stack.c | 39 +++++++++++++++++++++++++++--------- 8 files changed, 61 insertions(+), 24 deletions(-) diff --git a/gdb/extension-priv.h b/gdb/extension-priv.h index 4ef87415413..9b0c4815399 100644 --- a/gdb/extension-priv.h +++ b/gdb/extension-priv.h @@ -186,7 +186,8 @@ struct extension_language_ops (const struct extension_language_defn *, const frame_info_ptr &frame, frame_filter_flags flags, enum ext_lang_frame_args args_type, - struct ui_out *out, int frame_low, int frame_high); + struct ui_out *out, int frame_low, int frame_high, + const frame_info_ptr &selected_frame); /* Used for registering the ptwrite filter to the current thread. */ void (*apply_ptwrite_filter) diff --git a/gdb/extension.c b/gdb/extension.c index d8ef8123ab5..a57ad4a517a 100644 --- a/gdb/extension.c +++ b/gdb/extension.c @@ -521,7 +521,8 @@ apply_ext_lang_frame_filter (const frame_info_ptr &frame, frame_filter_flags flags, enum ext_lang_frame_args args_type, struct ui_out *out, - int frame_low, int frame_high) + int frame_low, int frame_high, + const frame_info_ptr &selected_frame) { for (const struct extension_language_defn *extlang : extension_languages) { @@ -531,8 +532,9 @@ apply_ext_lang_frame_filter (const frame_info_ptr &frame, || extlang->ops->apply_frame_filter == NULL) continue; status = extlang->ops->apply_frame_filter (extlang, frame, flags, - args_type, out, - frame_low, frame_high); + args_type, out, + frame_low, frame_high, + selected_frame); /* We use the filters from the first extension language that has applicable filters. Also, an error is reported immediately rather than continue trying. */ diff --git a/gdb/extension.h b/gdb/extension.h index e351b5b672e..af535199adb 100644 --- a/gdb/extension.h +++ b/gdb/extension.h @@ -302,7 +302,8 @@ extern int apply_ext_lang_val_pretty_printer extern enum ext_lang_bt_status apply_ext_lang_frame_filter (const frame_info_ptr &frame, frame_filter_flags flags, enum ext_lang_frame_args args_type, - struct ui_out *out, int frame_low, int frame_high); + struct ui_out *out, int frame_low, int frame_high, + const frame_info_ptr &selected_frame); extern void apply_ext_lang_ptwrite_filter (struct btrace_thread_info *btinfo); diff --git a/gdb/frame.h b/gdb/frame.h index 00485e6d1e2..ed344991330 100644 --- a/gdb/frame.h +++ b/gdb/frame.h @@ -899,7 +899,8 @@ extern void print_stack_frame (const frame_info_ptr &, int print_level, extern void print_frame_info (const frame_print_options &fp_opts, const frame_info_ptr &, int print_level, enum print_what print_what, int args, - int set_current_sal); + int set_current_sal, + const frame_info_ptr &selected_frame); extern frame_info_ptr block_innermost_frame (const struct block *); diff --git a/gdb/mi/mi-cmd-stack.c b/gdb/mi/mi-cmd-stack.c index 3281be2b4dc..ba75b9d92d6 100644 --- a/gdb/mi/mi-cmd-stack.c +++ b/gdb/mi/mi-cmd-stack.c @@ -67,7 +67,7 @@ mi_apply_ext_lang_frame_filter (const frame_info_ptr &frame, return apply_ext_lang_frame_filter (frame, flags, (enum ext_lang_frame_args) print_values, out, - frame_low, frame_high); + frame_low, frame_high, {}); } /* Print a list of the stack frames. Args can be none, in which case @@ -158,7 +158,7 @@ mi_cmd_stack_list_frames (const char *command, const char *const *argv, result = apply_ext_lang_frame_filter (get_current_frame (), flags, NO_VALUES, current_uiout, - py_frame_low, frame_high); + py_frame_low, frame_high, {}); } /* Run the inbuilt backtrace if there are no filters registered, or @@ -175,7 +175,7 @@ mi_cmd_stack_list_frames (const char *command, const char *const *argv, /* Print the location and the address always, even for level 0. If args is 0, don't print the arguments. */ print_frame_info (user_frame_print_options, - fi, 1, LOC_AND_ADDRESS, 0 /* args */, 0); + fi, 1, LOC_AND_ADDRESS, 0 /* args */, 0, {}); } } } @@ -762,5 +762,5 @@ mi_cmd_stack_info_frame (const char *command, const char *const *argv, error (_("-stack-info-frame: No arguments allowed")); print_frame_info (user_frame_print_options, - get_selected_frame (NULL), 1, LOC_AND_ADDRESS, 0, 1); + get_selected_frame (NULL), 1, LOC_AND_ADDRESS, 0, 1, {}); } diff --git a/gdb/python/py-framefilter.c b/gdb/python/py-framefilter.c index f256a26807c..11463746787 100644 --- a/gdb/python/py-framefilter.c +++ b/gdb/python/py-framefilter.c @@ -761,7 +761,8 @@ static enum ext_lang_bt_status py_print_frame (PyObject *filter, frame_filter_flags flags, enum ext_lang_frame_args args_type, struct ui_out *out, int indent, - levels_printed_hash &levels_printed) + levels_printed_hash &levels_printed, + const frame_info_ptr &selected_frame) { int has_addr = 0; CORE_ADDR address = 0; @@ -865,6 +866,14 @@ py_print_frame (PyObject *filter, frame_filter_flags flags, || print_what == LOC_AND_ADDRESS || print_what == SHORT_LOCATION)); + if (!selected_frame.is_null ()) + { + if (frame == selected_frame) + out->text ("* "); + else + out->text (" "); + } + /* Print frame level. MI does not require the level if locals/variables only are being printed. */ if (print_level @@ -1068,7 +1077,7 @@ py_print_frame (PyObject *filter, frame_filter_flags flags, enum ext_lang_bt_status success = py_print_frame (item, flags, args_type, out, indent, - levels_printed); + levels_printed, selected_frame); if (success == EXT_LANG_BT_ERROR) return EXT_LANG_BT_ERROR; @@ -1142,7 +1151,8 @@ enum ext_lang_bt_status gdbpy_apply_frame_filter (const struct extension_language_defn *extlang, const frame_info_ptr &frame, frame_filter_flags flags, enum ext_lang_frame_args args_type, - struct ui_out *out, int frame_low, int frame_high) + struct ui_out *out, int frame_low, int frame_high, + const frame_info_ptr &selected_frame) { struct gdbarch *gdbarch = NULL; enum ext_lang_bt_status success = EXT_LANG_BT_ERROR; @@ -1234,7 +1244,7 @@ gdbpy_apply_frame_filter (const struct extension_language_defn *extlang, try { success = py_print_frame (item.get (), flags, args_type, out, 0, - levels_printed); + levels_printed, selected_frame); } catch (const gdb_exception_error &except) { diff --git a/gdb/python/python-internal.h b/gdb/python/python-internal.h index 10c984bad4b..9245a4e25d7 100644 --- a/gdb/python/python-internal.h +++ b/gdb/python/python-internal.h @@ -444,7 +444,8 @@ extern enum ext_lang_bt_status gdbpy_apply_frame_filter (const struct extension_language_defn *, const frame_info_ptr &frame, frame_filter_flags flags, enum ext_lang_frame_args args_type, - struct ui_out *out, int frame_low, int frame_high); + struct ui_out *out, int frame_low, int frame_high, + const frame_info_ptr &selected_frame); extern void gdbpy_preserve_values (const struct extension_language_defn *, struct objfile *objfile, copied_types_hash_t &copied_types); diff --git a/gdb/stack.c b/gdb/stack.c index 7329430adab..ab1fe33a72a 100644 --- a/gdb/stack.c +++ b/gdb/stack.c @@ -227,7 +227,8 @@ static void print_frame (struct ui_out *uiout, const frame_print_options &opts, const frame_info_ptr &frame, int print_level, enum print_what print_what, int print_args, - struct symtab_and_line sal); + struct symtab_and_line sal, + const frame_info_ptr &selected_frame); static frame_info_ptr find_frame_for_function (const char *); static frame_info_ptr find_frame_for_address (CORE_ADDR); @@ -362,7 +363,7 @@ print_stack_frame (const frame_info_ptr &frame, int print_level, { print_frame_info (user_frame_print_options, frame, print_level, print_what, 1 /* print_args */, - set_current_sal); + set_current_sal, {}); if (set_current_sal) set_current_sal_from_frame (frame); } @@ -961,7 +962,7 @@ static void do_print_frame_info (struct ui_out *uiout, const frame_print_options &fp_opts, const frame_info_ptr &frame, int print_level, enum print_what print_what, int print_args, - int set_current_sal) + int set_current_sal, const frame_info_ptr &selected_frame) { struct gdbarch *gdbarch = get_frame_arch (frame); int source_print; @@ -983,6 +984,14 @@ do_print_frame_info (struct ui_out *uiout, const frame_print_options &fp_opts, annotate_frame_begin (print_level ? frame_relative_level (frame) : 0, gdbarch, get_frame_pc (frame)); + if (!selected_frame.is_null ()) + { + if (frame == selected_frame) + uiout->text ("* "); + else + uiout->text (" "); + } + /* Do this regardless of SOURCE because we don't have any source to list for this frame. */ if (print_level) @@ -1042,7 +1051,7 @@ do_print_frame_info (struct ui_out *uiout, const frame_print_options &fp_opts, || print_what == SHORT_LOCATION); if (location_print || !sal.symtab) print_frame (uiout, fp_opts, frame, print_level, - print_what, print_args, sal); + print_what, print_args, sal, selected_frame); source_print = (print_what == SRC_LINE || print_what == SRC_AND_LOC); @@ -1129,11 +1138,11 @@ void print_frame_info (const frame_print_options &fp_opts, const frame_info_ptr &frame, int print_level, enum print_what print_what, int print_args, - int set_current_sal) + int set_current_sal, const frame_info_ptr &selected_frame) { do_with_buffered_output (do_print_frame_info, current_uiout, fp_opts, frame, print_level, print_what, - print_args, set_current_sal); + print_args, set_current_sal, selected_frame); } /* See stack.h. */ @@ -1263,7 +1272,8 @@ print_frame (struct ui_out *uiout, const frame_print_options &fp_opts, const frame_info_ptr &frame, int print_level, enum print_what print_what, int print_args, - struct symtab_and_line sal) + struct symtab_and_line sal, + const frame_info_ptr &selected_frame) { struct gdbarch *gdbarch = get_frame_arch (frame); enum language funlang = language_unknown; @@ -1282,6 +1292,14 @@ print_frame (struct ui_out *uiout, { ui_out_emit_tuple tuple_emitter (uiout, "frame"); + if (!selected_frame.is_null ()) + { + if (frame == selected_frame) + uiout->text ("* "); + else + uiout->text (" "); + } + if (print_level) { uiout->text ("#"); @@ -1930,6 +1948,8 @@ backtrace_command_1 (const frame_print_options &fp_opts, if (fp_opts.print_raw_frame_arguments) flags |= PRINT_RAW_FRAME_ARGUMENTS; + frame_info_ptr selected_frame = get_selected_frame (); + if (!bt_opts.no_filters) { enum ext_lang_frame_args arg_type; @@ -1951,7 +1971,8 @@ backtrace_command_1 (const frame_print_options &fp_opts, result = apply_ext_lang_frame_filter (get_current_frame (), flags, arg_type, current_uiout, - py_start, py_end); + py_start, py_end, + selected_frame); } /* Run the inbuilt backtrace if there are no filters registered, or @@ -1982,7 +2003,7 @@ backtrace_command_1 (const frame_print_options &fp_opts, hand, perhaps the code does or could be fixed to make sure the frame->prev field gets set to NULL in that case). */ - print_frame_info (fp_opts, fi, 1, LOCATION, 1, 0); + print_frame_info (fp_opts, fi, 1, LOCATION, 1, 0, selected_frame); if ((flags & PRINT_LOCALS) != 0) print_frame_local_vars (fi, false, NULL, NULL, 1, gdb_stdout); -- 2.49.0