diff --git a/crash_target.c b/crash_target.c index 4554806..1080976 100644 --- a/crash_target.c +++ b/crash_target.c @@ -26,10 +26,10 @@ void crash_target_init (void); extern "C" int gdb_readmem_callback(unsigned long, void *, int, int); -extern "C" int crash_get_nr_cpus(void); -extern "C" int crash_get_cpu_reg (int cpu, int regno, const char *regname, +extern "C" int crash_get_current_task_reg (int regno, const char *regname, int regsize, void *val); - +extern "C" int gdb_change_thread_context (void); +extern "C" void crash_get_current_task_info(unsigned long *pid, char **comm); /* The crash target. */ @@ -60,30 +60,40 @@ public: bool has_registers () override { return true; } bool thread_alive (ptid_t ptid) override { return true; } std::string pid_to_str (ptid_t ptid) override - { return string_printf ("CPU %ld", ptid.tid ()); } + { + unsigned long pid; + char *comm; + crash_get_current_task_info(&pid, &comm); + return string_printf ("%ld %s", pid, comm); + } }; -/* We just get all the registers, so we don't use regno. */ +static void supply_registers(struct regcache *regcache, int regno) +{ + gdb_byte regval[16]; + struct gdbarch *arch = regcache->arch (); + const char *regname = gdbarch_register_name(arch, regno); + int regsize = register_size(arch, regno); + + if (regsize > sizeof (regval)) + error (_("fatal error: buffer size is not enough to fit register value")); + + if (crash_get_current_task_reg (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) { - gdb_byte regval[16]; - int cpu = inferior_ptid.tid(); - struct gdbarch *arch = regcache->arch (); - - 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 (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); + } } @@ -110,7 +120,6 @@ crash_target::xfer_partial (enum target_object object, const char *annex, void crash_target_init (void) { - int nr_cpus = crash_get_nr_cpus(); crash_target *target = new crash_target (); /* Own the target until it is successfully pushed. */ @@ -119,13 +128,11 @@ crash_target_init (void) push_target (std::move (target_holder)); inferior_appeared (current_inferior (), CRASH_INFERIOR_PID); - for (int i = 0; i < nr_cpus; i++) - { - thread_info *thread = add_thread_silent (target, - ptid_t(CRASH_INFERIOR_PID, 0, i)); - if (!i) - switch_to_thread (thread); - } + + /*Only create 1 gdb threads to view tasks' stack unwinding*/ + thread_info *thread = add_thread_silent (target, + ptid_t(CRASH_INFERIOR_PID, 0, 0)); + switch_to_thread (thread); /* Fetch all registers from core file. */ target_fetch_registers (get_current_regcache (), -1); @@ -133,3 +140,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 116aaf7..511942a 100644 --- a/defs.h +++ b/defs.h @@ -1080,7 +1080,7 @@ struct machdep_table { void (*get_irq_affinity)(int); void (*show_interrupts)(int, ulong *); int (*is_page_ptr)(ulong, physaddr_t *); - int (*get_cpu_reg)(int, int, const char *, int, void *); + int (*get_current_task_reg)(int, const char *, int, void *); int (*is_cpu_prstatus_valid)(int cpu); }; @@ -6079,7 +6079,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); @@ -8115,4 +8115,7 @@ enum x86_64_regnum { LAST_REGNUM }; +/* crash_target.c */ +extern int gdb_change_thread_context (void); + #endif /* !GDB_COMMON */ diff --git a/gdb_interface.c b/gdb_interface.c index b14319c..03681ec 100644 --- a/gdb_interface.c +++ b/gdb_interface.c @@ -1067,30 +1067,13 @@ unsigned long crash_get_kaslr_offset(void) } /* Callbacks for crash_target */ -int crash_get_nr_cpus(void); -int crash_get_cpu_reg (int cpu, int regno, const char *regname, - int regsize, void *val); - -int crash_get_nr_cpus(void) +int crash_get_current_task_reg (int regno, const char *regname, + int regsize, void *value); +int crash_get_current_task_reg (int regno, const char *regname, + int regsize, void *value) { - if (SADUMP_DUMPFILE()) - return sadump_get_nr_cpus(); - else if (DISKDUMP_DUMPFILE()) - return diskdump_get_nr_cpus(); - else if (KDUMP_DUMPFILE()) - return kdump_get_nr_cpus(); - else if (VMSS_DUMPFILE()) - return vmware_vmss_get_nr_cpus(); - - /* Just CPU #0 */ - return 1; -} - -int crash_get_cpu_reg (int cpu, int regno, const char *regname, - int regsize, void *value) -{ - if (!machdep->get_cpu_reg) - return FALSE; - return machdep->get_cpu_reg(cpu, regno, regname, regsize, value); + if (!machdep->get_current_task_reg) + return FALSE; + return machdep->get_current_task_reg(regno, regname, regsize, value); } 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..c131cc3 100644 --- a/task.c +++ b/task.c @@ -120,6 +120,7 @@ static int has_sched_policy(ulong, ulong); static ulong task_policy(ulong); static ulong sched_policy_bit_from_str(const char *); static ulong make_sched_policy(const char *); +void crash_get_current_task_info(unsigned long *, char **); static struct sched_policy_info { ulong value; @@ -679,7 +680,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 +692,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 +2993,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 +3061,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 +3108,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 +5289,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 +5313,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); @@ -11287,3 +11297,11 @@ check_stack_end_magic: if (!total) fprintf(fp, "No stack overflows detected\n"); } + +void crash_get_current_task_info(unsigned long *pid, char **comm) +{ + struct task_context *tc = CURRENT_CONTEXT(); + + *pid = tc->pid; + *comm = tc->comm; +} diff --git a/tools.c b/tools.c index 277510f..85d8b6f 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; diff --git a/x86_64.c b/x86_64.c index 11a6aab..afd35a4 100644 --- a/x86_64.c +++ b/x86_64.c @@ -126,7 +126,7 @@ static int x86_64_get_framesize(struct bt_info *, ulong, ulong, char *); static void x86_64_framesize_debug(struct bt_info *); static void x86_64_get_active_set(void); static int x86_64_get_kvaddr_ranges(struct vaddr_range *); -static int x86_64_get_cpu_reg(int, int, const char *, int, void *); +static int x86_64_get_cpu_reg(int, const char *, int, void *); static int x86_64_verify_paddr(uint64_t); static void GART_init(void); static void x86_64_exception_stacks_init(void); @@ -195,7 +195,7 @@ x86_64_init(int when) machdep->machspec->irq_eframe_link = UNINITIALIZED; machdep->machspec->irq_stack_gap = UNINITIALIZED; machdep->get_kvaddr_ranges = x86_64_get_kvaddr_ranges; - machdep->get_cpu_reg = x86_64_get_cpu_reg; + machdep->get_current_task_reg = x86_64_get_cpu_reg; if (machdep->cmdline_args[0]) parse_cmdline_args(); if ((string = pc->read_vmcoreinfo("relocate"))) { @@ -9077,14 +9077,22 @@ x86_64_get_kvaddr_ranges(struct vaddr_range *vrp) } static int -x86_64_get_cpu_reg(int cpu, int regno, const char *name, +x86_64_get_cpu_reg(int regno, const char *name, int size, void *value) { - if (regno >= LAST_REGNUM) - return FALSE; + struct task_context *tc; - if (VMSS_DUMPFILE()) - return vmware_vmss_get_cpu_reg(cpu, regno, name, size, value); + tc = CURRENT_CONTEXT(); + if (!tc) + return FALSE; + + if (regno >= LAST_REGNUM) + return FALSE; + /* + * Task is active, grab CPU's registers + */ + if (is_task_active(tc->task) && VMSS_DUMPFILE()) + return vmware_vmss_get_cpu_reg(tc->processor, regno, name, size, value); return FALSE; }