Re: Enhancement - show old and new thread info when switching during debugging

pfee
2011-08-08T11:35:10Z

[-- Attachment #1: Type: text/plain, Size: 2381 bytes --]

> > What he wants is the last user selected thread,

> > not the thread that happens to be current when switch_to_thread
> > is called.
> >
> > - user resumes with thread 1 selected
> > - thread 2 hits breakpoint, gdb switches to thread 2
> > - breakpoint doesn't cause stop, target is re-resumed
> > - thread 3 hits breakpoint, gdb switches to thread 3
> > - breakpoint causes stop, previous_inferior_ptid is
> > thread 1, but the last switch_to_thread would have
> > recorded $previous_thread as thread 2
> >
> > If you want a convenience variable, please model it on
> > $_thread --- see end of thread.c:_initialize_thread.
> >
> > Note that the previously selected thread may not exist anymore,
> > it may have exited meanwhile, for example, or the inferior
> > exec'ed.
> >
> > --
> > Pedro Alves
> >
>
> Hi Pedro,
>
> I agree with your example, the previous_inferior_ptid in infrun.c,
>normal_stop()
>
> has the information I need. I'll try and use that to populate the new
> convenience variable.
>
> I'll a try to construct a test program that creates a scenario where the
> previous thread as died by the time normal_stop() executes.
>

Hello again,

I've looked into convenience variables and have developed a new patch. The gdb
output when switching threads is no longer altered, instead the $_prev_thread
convenience variable can be used to switch back to the previous thread.

When making this patch I renamed an existing variable from
previous_inferior_ptid to current_inferior_ptid. That way we have values that
move from inferior_ptid (the new ptid) to current_inferior_ptid and finally to
previous_inferior_ptid (which is exposed via the convenience variable). This
seemed better than leaving the variables names as was and introducing something

confusing like previous_previous_inferior_ptid.

By the way, I've made the patches against GDB trunk, I presume that's preferred
over GDB 7.3.

Comments welcome.
Thanks,
Paul

2011-08-08 Paul Fee <pfee@talk21.com>

* inferior.h: Add function for handling $_prev_thread convenience variable
* infrun.c: Rename previous_inferior_ptid to current_inferior_ptid.
Add function for handling $_prev_thread convenience variable
* thread.c: Add $_prev_thread convenience variable

[-- Attachment #2: prev_thread.patch --]
[-- Type: application/octet-stream, Size: 5596 bytes --]

Index: inferior.h
===================================================================
RCS file: /cvs/src/src/gdb/inferior.h,v
retrieving revision 1.161
diff -c -p -r1.161 inferior.h
*** inferior.h 21 Jul 2011 23:46:08 -0000 1.161
--- inferior.h 8 Aug 2011 11:23:59 -0000
*************** extern int stop_on_solib_events;
*** 204,209 ****
--- 204,212 ----

extern void start_remote (int from_tty);

+ extern struct value *prev_thread_id_make_value (struct gdbarch *,
+ struct internalvar *);
+
extern void normal_stop (void);

extern int signal_stop_state (int);
Index: infrun.c
===================================================================
RCS file: /cvs/src/src/gdb/infrun.c,v
retrieving revision 1.498
diff -c -p -r1.498 infrun.c
*** infrun.c 4 Aug 2011 19:10:12 -0000 1.498
--- infrun.c 8 Aug 2011 11:24:02 -0000
*************** int sync_execution = 0;
*** 125,130 ****
--- 125,136 ----
when the inferior stopped in a different thread than it had been
running in. */

+ static ptid_t current_inferior_ptid;
+
+ /* Values move from interior_ptid to current_inferior_ptid to
+ * previous_inferior_ptid. The previous value is exposed to the
+ * user through the $_prev_thread convenience variable.
+ */
static ptid_t previous_inferior_ptid;

/* Default behavior is to detach newly forked processes (legacy). */
*************** proceed (CORE_ADDR addr, enum target_sig
*** 2069,2075 ****
}

/* We'll update this if & when we switch to a new thread. */
! previous_inferior_ptid = inferior_ptid;

regcache = get_current_regcache ();
gdbarch = get_regcache_arch (regcache);
--- 2075,2081 ----
}

/* We'll update this if & when we switch to a new thread. */
! current_inferior_ptid = inferior_ptid;

regcache = get_current_regcache ();
gdbarch = get_regcache_arch (regcache);
*************** init_wait_for_inferior (void)
*** 2289,2295 ****

target_last_wait_ptid = minus_one_ptid;

! previous_inferior_ptid = inferior_ptid;
init_infwait_state ();

/* Discard any skipped inlined frames. */
--- 2295,2301 ----

target_last_wait_ptid = minus_one_ptid;

! current_inferior_ptid = inferior_ptid;
init_infwait_state ();

/* Discard any skipped inlined frames. */
*************** handle_inferior_event (struct execution_
*** 3719,3725 ****
switch_to_thread (deferred_step_ptid);
deferred_step_ptid = null_ptid;
/* Suppress spurious "Switching to ..." message. */
! previous_inferior_ptid = inferior_ptid;

resume (1, TARGET_SIGNAL_0);
prepare_to_wait (ecs);
--- 3725,3731 ----
switch_to_thread (deferred_step_ptid);
deferred_step_ptid = null_ptid;
/* Suppress spurious "Switching to ..." message. */
! current_inferior_ptid = inferior_ptid;

resume (1, TARGET_SIGNAL_0);
prepare_to_wait (ecs);
*************** print_no_history_reason (void)
*** 5730,5735 ****
--- 5736,5753 ----
ui_out_text (current_uiout, "\nNo more reverse-execution history.\n");
}

+ /* Return the previous thread's id. Return a value of 0 if
+ no previous thread was selected, or it doesn't exist. */
+
+ struct value *
+ prev_thread_id_make_value (struct gdbarch *gdbarch, struct internalvar *var)
+ {
+ struct thread_info *tp = find_thread_ptid (previous_inferior_ptid);
+
+ return value_from_longest (builtin_type (gdbarch)->builtin_int,
+ (tp ? tp->num : 0));
+ }
+
/* Here to return control to GDB when the inferior stops for real.
Print appropriate messages, remove breakpoints, give terminal our modes.

*************** normal_stop (void)
*** 5770,5785 ****
Note that SIGNALLED here means "exited with a signal", not
"received a signal". */
if (!non_stop
! && !ptid_equal (previous_inferior_ptid, inferior_ptid)
&& target_has_execution
&& last.kind != TARGET_WAITKIND_SIGNALLED
&& last.kind != TARGET_WAITKIND_EXITED)
{
target_terminal_ours_for_output ();
printf_filtered (_("[Switching to %s]\n"),
! target_pid_to_str (inferior_ptid));
annotate_thread_changed ();
! previous_inferior_ptid = inferior_ptid;
}

if (!breakpoints_always_inserted_mode () && target_has_execution)
--- 5788,5804 ----
Note that SIGNALLED here means "exited with a signal", not
"received a signal". */
if (!non_stop
! && !ptid_equal (current_inferior_ptid, inferior_ptid)
&& target_has_execution
&& last.kind != TARGET_WAITKIND_SIGNALLED
&& last.kind != TARGET_WAITKIND_EXITED)
{
target_terminal_ours_for_output ();
printf_filtered (_("[Switching to %s]\n"),
! target_pid_to_str (inferior_ptid));
annotate_thread_changed ();
! previous_inferior_ptid = current_inferior_ptid;
! current_inferior_ptid = inferior_ptid;
}

if (!breakpoints_always_inserted_mode () && target_has_execution)
Index: thread.c
===================================================================
RCS file: /cvs/src/src/gdb/thread.c,v
retrieving revision 1.142
diff -c -p -r1.142 thread.c
*** thread.c 4 Aug 2011 19:10:13 -0000 1.142
--- thread.c 8 Aug 2011 11:24:02 -0000
*************** Show printing of thread events (such as
*** 1498,1501 ****
--- 1498,1502 ----
&setprintlist, &showprintlist);

create_internalvar_type_lazy ("_thread", thread_id_make_value);
+ create_internalvar_type_lazy ("_prev_thread", prev_thread_id_make_value);
}