Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [RFC] Show the selected frame in "bt"
@ 2026-05-29 18:45 Tom Tromey
  2026-05-29 19:05 ` Simon Marchi
  0 siblings, 1 reply; 3+ messages in thread
From: Tom Tromey @ 2026-05-29 18:45 UTC (permalink / raw)
  To: gdb-patches; +Cc: Tom Tromey

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=<optimized out>, 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


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-06-01  7:07 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-05-29 18:45 [RFC] Show the selected frame in "bt" Tom Tromey
2026-05-29 19:05 ` Simon Marchi
2026-06-01  7:05   ` Schimpe, Christina

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox