This patch is a preparation of gdb stack unwinding support. "set" command
is extended with gdb context change:
crash> set <pid>
or
crash> set <task>
Then the task context of crash and gdb will both be switched to
pid/task, and the following command: "bt" "gdb bt" will output
the same task context.
Co-developed-by: Aditya Gupta <adityag(a)linux.ibm.com>
Co-developed-by: Alexey Makhalov <alexey.makhalov(a)broadcom.com>
Co-developed-by: Tao Liu <ltao(a)redhat.com>
Cc: Sourabh Jain <sourabhjain(a)linux.ibm.com>
Cc: Hari Bathini <hbathini(a)linux.ibm.com>
Cc: Mahesh J Salgaonkar <mahesh(a)linux.ibm.com>
Cc: Naveen N. Rao <naveen.n.rao(a)linux.vnet.ibm.com>
Cc: Lianbo Jiang <lijiang(a)redhat.com>
Cc: HAGIO KAZUHITO(萩尾 一仁) <k-hagio-ab(a)nec.com>
Cc: Tao Liu <ltao(a)redhat.com>
Cc: Alexey Makhalov <alexey.makhalov(a)broadcom.com>
Signed-off-by: Tao Liu <ltao(a)redhat.com>
---
crash_target.c | 46 ++++++++++++++++++++++++++++++----------------
defs.h | 5 ++++-
kernel.c | 11 ++++++++---
task.c | 21 +++++++++++++--------
tools.c | 8 ++++----
5 files changed, 59 insertions(+), 32 deletions(-)
diff --git a/crash_target.c b/crash_target.c
index 1f62bf6..41f0f3a 100644
--- a/crash_target.c
+++ b/crash_target.c
@@ -28,7 +28,7 @@ void crash_target_init (void);
extern "C" int gdb_readmem_callback(unsigned long, void *, int, int);
extern "C" int crash_get_cpu_reg (int cpu, int regno, const char *regname,
int regsize, void *val);
-
+extern "C" int gdb_change_thread_context (void);
/* The crash target. */
@@ -63,26 +63,32 @@ public:
};
-/* We just get all the registers, so we don't use regno. */
-void
-crash_target::fetch_registers (struct regcache *regcache, int regno)
+static void supply_registers(struct regcache *regcache, int regno)
{
gdb_byte regval[16];
int cpu = inferior_ptid.tid();
struct gdbarch *arch = regcache->arch ();
+ const char *regname = gdbarch_register_name(arch, regno);
+ int regsize = register_size(arch, regno);
- for (int r = 0; r < gdbarch_num_regs (arch); r++)
- {
- const char *regname = gdbarch_register_name(arch, r);
- int regsize = register_size (arch, r);
- if (regsize > sizeof (regval))
- error (_("fatal error: buffer size is not enough to fit register
value"));
-
- if (crash_get_cpu_reg (cpu, r, regname, regsize, (void *)®val))
- regcache->raw_supply (r, regval);
- else
- regcache->raw_supply (r, NULL);
- }
+ if (regsize > sizeof (regval))
+ error (_("fatal error: buffer size is not enough to fit register value"));
+
+ if (crash_get_cpu_reg (cpu, regno, regname, regsize, (void *)®val))
+ regcache->raw_supply (regno, regval);
+ else
+ regcache->raw_supply (regno, NULL);
+}
+
+void
+crash_target::fetch_registers (struct regcache *regcache, int regno)
+{
+ if (regno >= 0) {
+ supply_registers(regcache, regno);
+ } else if (regno == -1) {
+ for (int r = 0; r < gdbarch_num_regs (regcache->arch ()); r++)
+ supply_registers(regcache, r);
+ }
}
@@ -129,3 +135,11 @@ crash_target_init (void)
/* Now, set up the frame cache. */
reinit_frame_cache ();
}
+
+extern "C" int
+gdb_change_thread_context (void)
+{
+ target_fetch_registers(get_current_regcache(), -1);
+ reinit_frame_cache();
+ return TRUE;
+}
diff --git a/defs.h b/defs.h
index 49e6923..9ffe7c9 100644
--- a/defs.h
+++ b/defs.h
@@ -6019,7 +6019,7 @@ extern char *help_map[];
* task.c
*/
void task_init(void);
-int set_context(ulong, ulong);
+int set_context(ulong, ulong, uint);
void show_context(struct task_context *);
ulong pid_to_task(ulong);
ulong task_to_pid(ulong);
@@ -8055,4 +8055,7 @@ enum x86_64_regnum {
LAST_REGNUM
};
+/* crash_target.c */
+extern int gdb_change_thread_context (void);
+
#endif /* !GDB_COMMON */
diff --git a/kernel.c b/kernel.c
index 8a9d498..5d25b88 100644
--- a/kernel.c
+++ b/kernel.c
@@ -6507,15 +6507,20 @@ set_cpu(int cpu)
if (hide_offline_cpu(cpu))
error(FATAL, "invalid cpu number: cpu %d is OFFLINE\n", cpu);
- if ((task = get_active_task(cpu)))
- set_context(task, NO_PID);
+ task = get_active_task(cpu);
+
+ /* Check if context is already set to given cpu */
+ if (task == CURRENT_TASK())
+ return;
+
+ if (task)
+ set_context(task, NO_PID, TRUE);
else
error(FATAL, "cannot determine active task on cpu %ld\n", cpu);
show_context(CURRENT_CONTEXT());
}
-
/*
* Collect the irq_desc[] entry along with its associated handler and
* action structures.
diff --git a/task.c b/task.c
index d52ce0b..697a692 100644
--- a/task.c
+++ b/task.c
@@ -679,7 +679,7 @@ task_init(void)
if (ACTIVE()) {
active_pid = REMOTE() ? pc->server_pid :
LOCAL_ACTIVE() ? pc->program_pid : 1;
- set_context(NO_TASK, active_pid);
+ set_context(NO_TASK, active_pid, FALSE);
tt->this_task = pid_to_task(active_pid);
}
else {
@@ -691,7 +691,7 @@ task_init(void)
else if (ELF_NOTES_VALID() && DISKDUMP_DUMPFILE())
map_cpus_to_prstatus_kdump_cmprs();
please_wait("determining panic task");
- set_context(get_panic_context(), NO_PID);
+ set_context(get_panic_context(), NO_PID, TRUE);
please_wait_done();
}
@@ -2992,9 +2992,9 @@ refresh_context(ulong curtask, ulong curpid)
struct task_context *tc;
if (task_exists(curtask) && pid_exists(curpid)) {
- set_context(curtask, NO_PID);
+ set_context(curtask, NO_PID, FALSE);
} else {
- set_context(tt->this_task, NO_PID);
+ set_context(tt->this_task, NO_PID, FALSE);
complain = TRUE;
if (STREQ(args[0], "set") && (argcnt == 2) &&
@@ -3060,7 +3060,7 @@ sort_context_array(void)
curtask = CURRENT_TASK();
qsort((void *)tt->context_array, (size_t)tt->running_tasks,
sizeof(struct task_context), sort_by_pid);
- set_context(curtask, NO_PID);
+ set_context(curtask, NO_PID, TRUE);
sort_context_by_task();
}
@@ -3107,7 +3107,7 @@ sort_context_array_by_last_run(void)
curtask = CURRENT_TASK();
qsort((void *)tt->context_array, (size_t)tt->running_tasks,
sizeof(struct task_context), sort_by_last_run);
- set_context(curtask, NO_PID);
+ set_context(curtask, NO_PID, TRUE);
sort_context_by_task();
}
@@ -5288,7 +5288,7 @@ comm_exists(char *s)
* that pid is selected.
*/
int
-set_context(ulong task, ulong pid)
+set_context(ulong task, ulong pid, uint update_gdb_thread)
{
int i;
struct task_context *tc;
@@ -5308,7 +5308,12 @@ set_context(ulong task, ulong pid)
if (found) {
CURRENT_CONTEXT() = tc;
- return TRUE;
+
+ /* change the selected thread in gdb, according to current context */
+ if (update_gdb_thread)
+ return gdb_change_thread_context();
+ else
+ return TRUE;
} else {
if (task)
error(INFO, "cannot set context for task: %lx\n", task);
diff --git a/tools.c b/tools.c
index 1022d57..a8f9785 100644
--- a/tools.c
+++ b/tools.c
@@ -1871,7 +1871,7 @@ cmd_set(void)
return;
if (ACTIVE()) {
- set_context(tt->this_task, NO_PID);
+ set_context(tt->this_task, NO_PID, TRUE);
show_context(CURRENT_CONTEXT());
return;
}
@@ -1880,7 +1880,7 @@ cmd_set(void)
error(INFO, "no panic task found!\n");
return;
}
- set_context(tt->panic_task, NO_PID);
+ set_context(tt->panic_task, NO_PID, TRUE);
show_context(CURRENT_CONTEXT());
return;
@@ -2559,14 +2559,14 @@ cmd_set(void)
case STR_PID:
pid = value;
task = NO_TASK;
- if (set_context(task, pid))
+ if (set_context(task, pid, TRUE))
show_context(CURRENT_CONTEXT());
break;
case STR_TASK:
task = value;
pid = NO_PID;
- if (set_context(task, pid))
+ if (set_context(task, pid, TRUE))
show_context(CURRENT_CONTEXT());
break;
--
2.40.1