Skip to content

Commit bb8ea65

Browse files
committed
fix 'info threads' command
Currently the output is like this ppc64le: crash> info threads Id Target Id Frame 1 CPU 0 <unavailable> in ?? () 2 CPU 1 0xc000000000025d00 in ppc_panic_event (this=<optimized out>, event=<optimized out>, ptr=0x0) at arch/powerpc/kernel/setup-common.c:712 3 CPU 2 0xc000000000025d00 in ppc_panic_event (this=<optimized out>, event=<optimized out>, ptr=0x0) at arch/powerpc/kernel/setup-common.c:712 4 CPU 3 0xc000000000025d00 in ppc_panic_event (this=<optimized out>, event=<optimized out>, ptr=0x0) at arch/powerpc/kernel/setup-common.c:712 * 5 CPU 4 0xc000000000025d00 in ppc_panic_event (this=<optimized out>, event=<optimized out>, ptr=0x0) at arch/powerpc/kernel/setup-common.c:712 6 CPU 5 0xc000000000025d00 in ppc_panic_event (this=<optimized out>, event=<optimized out>, ptr=0x0) at arch/powerpc/kernel/setup-common.c:712 7 CPU 6 0xc000000000025d00 in ppc_panic_event (this=<optimized out>, event=<optimized out>, ptr=0x0) at arch/powerpc/kernel/setup-common.c:712 8 CPU 7 0xc000000000025d00 in ppc_panic_event (this=<optimized out>, event=<optimized out>, ptr=0x0) at arch/powerpc/kernel/setup-common.c:712 There are two issues here: 1. CPU 0 always shows '<unavailable>' frame: This is due to 'thread 0' being initialised in 'crash_target_init', but it's very early in crash init, so it could not get any registers from the vmcore. And, since GDB caches registers (whether it is there or now), it keeps thinking that registers for this thread are unavailable, so all future usage of thread 0 also shows unavailable registers & frame Fix this by refreshing the register cache of all threads in 'gdb_refresh_regcache', at task_init 2. All other CPUs show the same frame: For each thread, GDB depends on crash to give it registers, ie. crash_target::fetch_registers, but this in turn depends on crash's current context GDB internally switches it's thread context internally to each thread one by one, while printing the thread's frame, similarly switch crash's context when the thread context is changed, so that it matches the thread context in gdb (such as, CPU 3 in crash for thread 2(CPU 3) in gdb). Also, since we are switching context multiple times, add an argument to 'set_cpu' to not print the context everytime With these fixed, it will show all threads, as well as correct registers and frame. It might still show similar frame for many threads, due to all of them being on same NMI exception crash path, but if checked with 'info registers', they will have different registers. Cc: Sourabh Jain <[email protected]> Cc: Hari Bathini <[email protected]> Cc: Mahesh J Salgaonkar <[email protected]> Cc: Naveen N. Rao <[email protected]> Cc: Lianbo Jiang <[email protected]> Cc: HAGIO KAZUHITO(萩尾 一仁) <[email protected]> Cc: Tao Liu <[email protected]> Signed-off-by: Aditya Gupta <[email protected]>
1 parent 78a8622 commit bb8ea65

File tree

6 files changed

+124
-20
lines changed

6 files changed

+124
-20
lines changed

crash_target.c

+35-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ extern "C" int crash_get_nr_cpus(void);
3030
extern "C" int crash_get_cpu_reg (int cpu, int regno, const char *regname,
3131
int regsize, void *val);
3232
extern "C" int gdb_change_cpu_context (unsigned int cpu);
33-
extern "C" int set_cpu (int cpu);
33+
extern "C" void gdb_refresh_regcache(unsigned int cpu);
34+
extern "C" int set_cpu(int cpu, int print_context);
3435

3536

3637
/* The crash target. */
@@ -150,10 +151,42 @@ gdb_change_cpu_context(unsigned int cpu)
150151
return FALSE;
151152

152153
/* Making sure that crash's context is same */
153-
set_cpu(cpu);
154+
set_cpu(cpu, FALSE);
154155

155156
/* Switch to the thread */
156157
switch_to_thread(tp);
158+
159+
/* Fetch/Refresh thread's registers */
160+
gdb_refresh_regcache(cpu);
161+
157162
return TRUE;
158163
}
159164

165+
/* Refresh regcache of gdb thread on given CPU
166+
*
167+
* When gdb threads were initially added by 'crash_target_init', crash was not
168+
* yet initialised, and hence crash_target::fetch_registers didn't give any
169+
* registers to gdb.
170+
*
171+
* This is meant to be called after tasks in crash have been initialised, and
172+
* possible machdep->get_cpu_reg is also set so architecture can give registers
173+
*/
174+
extern "C" void
175+
gdb_refresh_regcache(unsigned int cpu)
176+
{
177+
int saved_cpu = inferior_thread()->ptid.tid();
178+
ptid_t ptid = ptid_t(CRASH_INFERIOR_PID, 0, cpu);
179+
inferior *inf = current_inferior();
180+
thread_info *tp = find_thread_ptid (inf, ptid);
181+
182+
if (tp == NULL) {
183+
warning("gdb thread for cpu %d not found\n", cpu);
184+
return;
185+
}
186+
187+
/* temporarily switch to the cpu so we get correct registers */
188+
set_cpu(cpu, FALSE);
189+
target_fetch_registers(get_thread_regcache(tp), -1);
190+
191+
set_cpu(saved_cpu, FALSE);
192+
}

defs.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -6013,7 +6013,7 @@ extern char *help_map[];
60136013
* task.c
60146014
*/
60156015
void task_init(void);
6016-
int set_context(ulong, ulong);
6016+
int set_context(ulong, ulong, uint);
60176017
void show_context(struct task_context *);
60186018
ulong pid_to_task(ulong);
60196019
ulong task_to_pid(ulong);
@@ -6118,7 +6118,7 @@ void parse_kernel_version(char *);
61186118
#define SHOW_LOG_CTIME (0x10)
61196119
#define SHOW_LOG_SAFE (0x20)
61206120
#define SHOW_LOG_CALLER (0x40)
6121-
void set_cpu(int);
6121+
void set_cpu(int cpu, int print_context);
61226122
void clear_machdep_cache(void);
61236123
struct stack_hook *gather_text_list(struct bt_info *);
61246124
int get_cpus_online(void);
@@ -8175,5 +8175,6 @@ enum ppc64_regnum {
81758175

81768176
/* crash_target.c */
81778177
extern int gdb_change_cpu_context (unsigned int cpu);
8178+
extern void gdb_refresh_regcache (unsigned int cpu);
81788179

81798180
#endif /* !GDB_COMMON */

gdb-10.2.patch

+54
Original file line numberDiff line numberDiff line change
@@ -16140,3 +16140,57 @@ exit 0
1614016140
}
1614116141

1614216142
/*
16143+
--- gdb-10.2/gdb/thread.c.orig
16144+
+++ gdb-10.2/gdb/thread.c
16145+
@@ -60,7 +60,7 @@ static thread_info *current_thread_;
16146+
16147+
#ifdef CRASH_MERGE
16148+
/* Function to set cpu, defined by crash-utility */
16149+
-extern "C" void set_cpu (int);
16150+
+extern "C" void set_cpu(int cpu, int print_context);
16151+
#endif
16152+
16153+
/* RAII type used to increase / decrease the refcount of each thread
16154+
@@ -1098,6 +1098,9 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads,
16155+
uiout->table_body ();
16156+
}
16157+
16158+
+#ifdef CRASH_MERGE
16159+
+ int current_cpu = current_thread ? current_thread->ptid.tid() : 0;
16160+
+#endif
16161+
for (inferior *inf : all_inferiors ())
16162+
for (thread_info *tp : inf->threads ())
16163+
{
16164+
@@ -1113,6 +1116,11 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads,
16165+
16166+
ui_out_emit_tuple tuple_emitter (uiout, NULL);
16167+
16168+
+ /* Switch to the thread's CPU in crash */
16169+
+#ifdef CRASH_MERGE
16170+
+ set_cpu(tp->ptid.tid(), FALSE);
16171+
+#endif
16172+
+
16173+
if (!uiout->is_mi_like_p ())
16174+
{
16175+
if (tp == current_thread)
16176+
@@ -1185,6 +1193,11 @@ print_thread_info_1 (struct ui_out *uiout, const char *requested_threads,
16177+
/* This end scope restores the current thread and the frame
16178+
selected before the "info threads" command, and it finishes the
16179+
ui-out list or table. */
16180+
+
16181+
+#ifdef CRASH_MERGE
16182+
+ /* Restore crash's context */
16183+
+ set_cpu(current_cpu, FALSE);
16184+
+#endif
16185+
}
16186+
16187+
if (pid == -1 && requested_threads == NULL)
16188+
@@ -1904,7 +1917,7 @@ thread_command (const char *tidstr, int from_tty)
16189+
struct thread_info* thread_id = parse_thread_id (tidstr, NULL);
16190+
16191+
#ifdef CRASH_MERGE
16192+
- set_cpu(thread_id->ptid.tid());
16193+
+ set_cpu(thread_id->ptid.tid(), FALSE);
16194+
#endif
16195+
16196+
thread_select (tidstr, thread_id);

kernel.c

+5-3
Original file line numberDiff line numberDiff line change
@@ -6514,9 +6514,10 @@ dump_kernel_table(int verbose)
65146514

65156515
/*
65166516
* Set the context to the active task on a given cpu -- dumpfiles only.
6517+
* Optionally show the context if print_context is TRUE
65176518
*/
65186519
void
6519-
set_cpu(int cpu)
6520+
set_cpu(int cpu, int print_context)
65206521
{
65216522
ulong task;
65226523

@@ -6534,11 +6535,12 @@ set_cpu(int cpu)
65346535
return;
65356536

65366537
if (task)
6537-
set_context(task, NO_PID);
6538+
set_context(task, NO_PID, TRUE);
65386539
else
65396540
error(FATAL, "cannot determine active task on cpu %ld\n", cpu);
65406541

6541-
show_context(CURRENT_CONTEXT());
6542+
if (print_context)
6543+
show_context(CURRENT_CONTEXT());
65426544
}
65436545

65446546

task.c

+22-8
Original file line numberDiff line numberDiff line change
@@ -672,7 +672,7 @@ task_init(void)
672672
if (ACTIVE()) {
673673
active_pid = REMOTE() ? pc->server_pid :
674674
LOCAL_ACTIVE() ? pc->program_pid : 1;
675-
set_context(NO_TASK, active_pid);
675+
set_context(NO_TASK, active_pid, FALSE);
676676
tt->this_task = pid_to_task(active_pid);
677677
}
678678
else {
@@ -684,7 +684,7 @@ task_init(void)
684684
else if (ELF_NOTES_VALID() && DISKDUMP_DUMPFILE())
685685
map_cpus_to_prstatus_kdump_cmprs();
686686
please_wait("determining panic task");
687-
set_context(get_panic_context(), NO_PID);
687+
set_context(get_panic_context(), NO_PID, TRUE);
688688
please_wait_done();
689689
}
690690

@@ -706,6 +706,17 @@ task_init(void)
706706
kt->boot_date.tv_nsec = 0;
707707
}
708708

709+
/*
710+
* Refresh CPU 0's thread's regcache
711+
*
712+
* This is required since, it's registers were initialised in
713+
* crash_target_init when crash was not initialised yet and hence could
714+
* not pass registers to gdb when gdb requests via
715+
* crash_target::fetch_registers, so CPU 0's registers are shown as
716+
* <unavailable> in gdb mode
717+
* */
718+
gdb_refresh_regcache(0);
719+
709720
tt->flags |= TASK_INIT_DONE;
710721
}
711722

@@ -2985,9 +2996,9 @@ refresh_context(ulong curtask, ulong curpid)
29852996
struct task_context *tc;
29862997

29872998
if (task_exists(curtask) && pid_exists(curpid)) {
2988-
set_context(curtask, NO_PID);
2999+
set_context(curtask, NO_PID, FALSE);
29893000
} else {
2990-
set_context(tt->this_task, NO_PID);
3001+
set_context(tt->this_task, NO_PID, FALSE);
29913002

29923003
complain = TRUE;
29933004
if (STREQ(args[0], "set") && (argcnt == 2) &&
@@ -3053,7 +3064,7 @@ sort_context_array(void)
30533064
curtask = CURRENT_TASK();
30543065
qsort((void *)tt->context_array, (size_t)tt->running_tasks,
30553066
sizeof(struct task_context), sort_by_pid);
3056-
set_context(curtask, NO_PID);
3067+
set_context(curtask, NO_PID, FALSE);
30573068

30583069
sort_context_by_task();
30593070
}
@@ -3100,7 +3111,7 @@ sort_context_array_by_last_run(void)
31003111
curtask = CURRENT_TASK();
31013112
qsort((void *)tt->context_array, (size_t)tt->running_tasks,
31023113
sizeof(struct task_context), sort_by_last_run);
3103-
set_context(curtask, NO_PID);
3114+
set_context(curtask, NO_PID, FALSE);
31043115

31053116
sort_context_by_task();
31063117
}
@@ -5281,7 +5292,7 @@ comm_exists(char *s)
52815292
* that pid is selected.
52825293
*/
52835294
int
5284-
set_context(ulong task, ulong pid)
5295+
set_context(ulong task, ulong pid, uint update_gdb_thread)
52855296
{
52865297
int i;
52875298
struct task_context *tc;
@@ -5303,7 +5314,10 @@ set_context(ulong task, ulong pid)
53035314
CURRENT_CONTEXT() = tc;
53045315

53055316
/* change the selected thread in gdb, according to current context */
5306-
return gdb_change_cpu_context(tc->processor);
5317+
if (update_gdb_thread)
5318+
return gdb_change_cpu_context(tc->processor);
5319+
else
5320+
return TRUE;
53075321
} else {
53085322
if (task)
53095323
error(INFO, "cannot set context for task: %lx\n", task);

tools.c

+5-5
Original file line numberDiff line numberDiff line change
@@ -1860,7 +1860,7 @@ cmd_set(void)
18601860
break;
18611861
}
18621862
cpu = dtoi(optarg, FAULT_ON_ERROR, NULL);
1863-
set_cpu(cpu);
1863+
set_cpu(cpu, TRUE);
18641864
return;
18651865

18661866
case 'p':
@@ -1871,7 +1871,7 @@ cmd_set(void)
18711871
return;
18721872

18731873
if (ACTIVE()) {
1874-
set_context(tt->this_task, NO_PID);
1874+
set_context(tt->this_task, NO_PID, TRUE);
18751875
show_context(CURRENT_CONTEXT());
18761876
return;
18771877
}
@@ -1880,7 +1880,7 @@ cmd_set(void)
18801880
error(INFO, "no panic task found!\n");
18811881
return;
18821882
}
1883-
set_context(tt->panic_task, NO_PID);
1883+
set_context(tt->panic_task, NO_PID, TRUE);
18841884
show_context(CURRENT_CONTEXT());
18851885
return;
18861886

@@ -2559,14 +2559,14 @@ cmd_set(void)
25592559
case STR_PID:
25602560
pid = value;
25612561
task = NO_TASK;
2562-
if (set_context(task, pid))
2562+
if (set_context(task, pid, TRUE))
25632563
show_context(CURRENT_CONTEXT());
25642564
break;
25652565

25662566
case STR_TASK:
25672567
task = value;
25682568
pid = NO_PID;
2569-
if (set_context(task, pid))
2569+
if (set_context(task, pid, TRUE))
25702570
show_context(CURRENT_CONTEXT());
25712571
break;
25722572

0 commit comments

Comments
 (0)