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, so the following command: "bt" "gdb bt" will output
the same task context.
In addition, set_context() will check if context is already current
to avoid dropping gdb caches unnecessarily.
command "info threads" and "thread x", which were used to view all
active threads and switch gdb context to one, can be achieved by
command "ps" and "set <pid>|<task>", which are used to
view all
active/inactive tasks and switch gdb/crash context to it.
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>
Cc: Aditya Gupta <adityag(a)linux.ibm.com>
Signed-off-by: Tao Liu <ltao(a)redhat.com>
---
crash_target.c | 46 ++++++++++++++++++++++++++++++----------------
defs.h | 5 ++++-
kernel.c | 11 ++++++++---
task.c | 25 +++++++++++++++++--------
tools.c | 8 ++++----
5 files changed, 63 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 9e0130f..695c32d 100644
--- a/defs.h
+++ b/defs.h
@@ -6047,7 +6047,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);
@@ -8083,4 +8083,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 57b8dce..edfd17c 100644
--- a/kernel.c
+++ b/kernel.c
@@ -6508,15 +6508,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..37ac250 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,12 +5288,16 @@ 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;
int found;
+ if (CURRENT_CONTEXT() &&
+ (CURRENT_TASK() == task || CURRENT_PID() == pid))
+ return TRUE;
+
tc = FIRST_CONTEXT();
for (i = 0, found = FALSE; i < RUNNING_TASKS(); i++, tc++) {
@@ -5308,7 +5312,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 8c73d10..a0d5b71 100644
--- a/tools.c
+++ b/tools.c
@@ -1872,7 +1872,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;
}
@@ -1881,7 +1881,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;
@@ -2560,14 +2560,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