diff --git a/defs.h b/defs.h index 98650e87..694d2809 100644 --- a/defs.h +++ b/defs.h @@ -982,6 +982,7 @@ struct bt_info { ulong eframe_ip; ulong radix; ulong *cpumask; + bool need_free; }; #define STACK_OFFSET_TYPE(OFF) \ @@ -6095,6 +6096,7 @@ int load_module_symbols_helper(char *); void unlink_module(struct load_module *); int check_specified_module_tree(char *, char *); int is_system_call(char *, ulong); +void get_dumpfile_regs(struct bt_info*, ulong*, ulong*); void generic_dump_irq(int); void generic_get_irq_affinity(int); void generic_show_interrupts(int, ulong *); @@ -6194,6 +6196,7 @@ ulong cpu_map_addr(const char *type); #define BT_REGS_NOT_FOUND (0x4000000000000ULL) #define BT_OVERFLOW_STACK (0x8000000000000ULL) #define BT_SKIP_IDLE (0x10000000000000ULL) +#define BT_NO_PRINT_REGS (0x20000000000000ULL) #define BT_SYMBOL_OFFSET (BT_SYMBOLIC_ARGS) #define BT_REF_HEXVAL (0x1) @@ -8050,4 +8053,124 @@ enum x86_64_regnum { LAST_REGNUM }; +/* + * Register numbers to make crash_target->fetch_registers() + * ---> machdep->get_cpu_reg() work properly. + * + * These register numbers and names are given according to output of + * `rs6000_register_name`, because that is what was being used by + * crash_target::fetch_registers in case of PPC64 + */ +enum ppc64_regnum { + PPC64_R0_REGNUM = 0, + PPC64_R1_REGNUM, + PPC64_R2_REGNUM, + PPC64_R3_REGNUM, + PPC64_R4_REGNUM, + PPC64_R5_REGNUM, + PPC64_R6_REGNUM, + PPC64_R7_REGNUM, + PPC64_R8_REGNUM, + PPC64_R9_REGNUM, + PPC64_R10_REGNUM, + PPC64_R11_REGNUM, + PPC64_R12_REGNUM, + PPC64_R13_REGNUM, + PPC64_R14_REGNUM, + PPC64_R15_REGNUM, + PPC64_R16_REGNUM, + PPC64_R17_REGNUM, + PPC64_R18_REGNUM, + PPC64_R19_REGNUM, + PPC64_R20_REGNUM, + PPC64_R21_REGNUM, + PPC64_R22_REGNUM, + PPC64_R23_REGNUM, + PPC64_R24_REGNUM, + PPC64_R25_REGNUM, + PPC64_R26_REGNUM, + PPC64_R27_REGNUM, + PPC64_R28_REGNUM, + PPC64_R29_REGNUM, + PPC64_R30_REGNUM, + PPC64_R31_REGNUM, + + PPC64_F0_REGNUM = 32, + PPC64_F1_REGNUM, + PPC64_F2_REGNUM, + PPC64_F3_REGNUM, + PPC64_F4_REGNUM, + PPC64_F5_REGNUM, + PPC64_F6_REGNUM, + PPC64_F7_REGNUM, + PPC64_F8_REGNUM, + PPC64_F9_REGNUM, + PPC64_F10_REGNUM, + PPC64_F11_REGNUM, + PPC64_F12_REGNUM, + PPC64_F13_REGNUM, + PPC64_F14_REGNUM, + PPC64_F15_REGNUM, + PPC64_F16_REGNUM, + PPC64_F17_REGNUM, + PPC64_F18_REGNUM, + PPC64_F19_REGNUM, + PPC64_F20_REGNUM, + PPC64_F21_REGNUM, + PPC64_F22_REGNUM, + PPC64_F23_REGNUM, + PPC64_F24_REGNUM, + PPC64_F25_REGNUM, + PPC64_F26_REGNUM, + PPC64_F27_REGNUM, + PPC64_F28_REGNUM, + PPC64_F29_REGNUM, + PPC64_F30_REGNUM, + PPC64_F31_REGNUM, + + PPC64_PC_REGNUM = 64, + PPC64_MSR_REGNUM = 65, + PPC64_CR_REGNUM = 66, + PPC64_LR_REGNUM = 67, + PPC64_CTR_REGNUM = 68, + PPC64_XER_REGNUM = 69, + PPC64_FPSCR_REGNUM = 70, + + PPC64_VR0_REGNUM = 106, + PPC64_VR1_REGNUM, + PPC64_VR2_REGNUM, + PPC64_VR3_REGNUM, + PPC64_VR4_REGNUM, + PPC64_VR5_REGNUM, + PPC64_VR6_REGNUM, + PPC64_VR7_REGNUM, + PPC64_VR8_REGNUM, + PPC64_VR9_REGNUM, + PPC64_VR10_REGNUM, + PPC64_VR11_REGNUM, + PPC64_VR12_REGNUM, + PPC64_VR13_REGNUM, + PPC64_VR14_REGNUM, + PPC64_VR15_REGNUM, + PPC64_VR16_REGNUM, + PPC64_VR17_REGNUM, + PPC64_VR18_REGNUM, + PPC64_VR19_REGNUM, + PPC64_VR20_REGNUM, + PPC64_VR21_REGNUM, + PPC64_VR22_REGNUM, + PPC64_VR23_REGNUM, + PPC64_VR24_REGNUM, + PPC64_VR25_REGNUM, + PPC64_VR26_REGNUM, + PPC64_VR27_REGNUM, + PPC64_VR28_REGNUM, + PPC64_VR29_REGNUM, + PPC64_VR30_REGNUM, + PPC64_VR31_REGNUM, + + PPC64_VSCR_REGNUM = 138, + PPC64_VRSAVE_REGNU = 139 +}; + #endif /* !GDB_COMMON */ diff --git a/kernel.c b/kernel.c index 1728b70c..661ef0e2 100644 --- a/kernel.c +++ b/kernel.c @@ -3533,6 +3533,39 @@ get_lkcd_regs(struct bt_info *bt, ulong *eip, ulong *esp) machdep->get_stack_frame(bt, eip, esp); } +void +get_dumpfile_regs(struct bt_info *bt, ulong *eip, ulong *esp) +{ + bt->flags |= BT_NO_PRINT_REGS; + + if (NETDUMP_DUMPFILE()) + get_netdump_regs(bt, eip, esp); + else if (KDUMP_DUMPFILE()) + get_kdump_regs(bt, eip, esp); + else if (DISKDUMP_DUMPFILE()) + get_diskdump_regs(bt, eip, esp); + else if (KVMDUMP_DUMPFILE()) + get_kvmdump_regs(bt, eip, esp); + else if (LKCD_DUMPFILE()) + get_lkcd_regs(bt, eip, esp); + else if (XENDUMP_DUMPFILE()) + get_xendump_regs(bt, eip, esp); + else if (SADUMP_DUMPFILE()) + get_sadump_regs(bt, eip, esp); + else if (VMSS_DUMPFILE()) + get_vmware_vmss_regs(bt, eip, esp); + else if (REMOTE_PAUSED()) { + if (!is_task_active(bt->task) || !get_remote_regs(bt, eip, esp)) + machdep->get_stack_frame(bt, eip, esp); + } else + machdep->get_stack_frame(bt, eip, esp); + + bt->flags &= ~BT_NO_PRINT_REGS; + + bt->instptr = *eip; + bt->stkptr = *esp; +} + /* * Store the head of the kernel module list for future use. diff --git a/ppc64.c b/ppc64.c index e8930a13..f86d951d 100644 --- a/ppc64.c +++ b/ppc64.c @@ -55,6 +55,8 @@ static void ppc64_set_bt_emergency_stack(enum emergency_stack_type type, static char * ppc64_check_eframe(struct ppc64_pt_regs *); static void ppc64_print_eframe(char *, struct ppc64_pt_regs *, struct bt_info *); +static int ppc64_get_cpu_reg(int cpu, int regno, const char *name, int size, + void *value); static void parse_cmdline_args(void); static int ppc64_paca_percpu_offset_init(int); static void ppc64_init_cpu_info(void); @@ -704,6 +706,8 @@ ppc64_init(int when) error(FATAL, "cannot malloc hwirqstack buffer space."); } + machdep->get_cpu_reg = ppc64_get_cpu_reg; + ppc64_init_paca_info(); if (!machdep->hz) { @@ -2501,6 +2505,109 @@ ppc64_print_eframe(char *efrm_str, struct ppc64_pt_regs *regs, ppc64_print_nip_lr(regs, 1); } +static int +ppc64_get_cpu_reg(int cpu, int regno, const char *name, int size, + void *value) +{ + struct bt_info bt_info, bt_setup; + struct task_context *tc; + ulong task; + struct ppc64_pt_regs *pt_regs; + ulong ip, sp; + bool ret = FALSE; + + if (LIVE()) { + /* doesn't support reading registers in live dump */ + return FALSE; + } + + /* Currently only handling registers available in ppc64_pt_regs: + * + * 0-31: r0-r31 + * 64: pc/nip + * 65: msr + * + * 67: lr + * 68: ctr + */ + switch (regno) { + case PPC64_R0_REGNUM ... PPC64_R31_REGNUM: + + case PPC64_PC_REGNUM: + case PPC64_MSR_REGNUM: + case PPC64_LR_REGNUM: + case PPC64_CTR_REGNUM: + break; + + default: + // return false if we can't get that register + if (CRASHDEBUG(1)) + error(WARNING, "unsupported register, regno=%d\n", regno); + return FALSE; + } + + tc = CURRENT_CONTEXT(); + if (!tc) + return FALSE; + BZERO(&bt_setup, sizeof(struct bt_info)); + clone_bt_info(&bt_setup, &bt_info, tc); + fill_stackbuf(&bt_info); + + // reusing the get_dumpfile_regs function to get pt regs structure + get_dumpfile_regs(&bt_info, &sp, &ip); + if (bt_info.stackbuf) + FREEBUF(bt_info.stackbuf); + pt_regs = (struct ppc64_pt_regs *)bt_info.machdep; + + if (!pt_regs) { + error(WARNING, "pt_regs not available for cpu %d\n", cpu); + return FALSE; + } + + switch (regno) { + case PPC64_R0_REGNUM ... PPC64_R31_REGNUM: + if (size != sizeof(pt_regs->gpr[regno])) { + ret = FALSE; break; // size mismatch + } + memcpy(value, &pt_regs->gpr[regno], size); + ret = TRUE; break; + + case PPC64_PC_REGNUM: + if (size != sizeof(pt_regs->nip)) { + ret = FALSE; break; // size mismatch + } + memcpy(value, &pt_regs->nip, size); + ret = TRUE; break; + + case PPC64_MSR_REGNUM: + if (size != sizeof(pt_regs->msr)) { + ret = FALSE; break; // size mismatch + } + memcpy(value, &pt_regs->msr, size); + ret = TRUE; break; + + case PPC64_LR_REGNUM: + if (size != sizeof(pt_regs->link)) { + ret = FALSE; break; // size mismatch + } + memcpy(value, &pt_regs->link, size); + ret = TRUE; break; + + case PPC64_CTR_REGNUM: + if (size != sizeof(pt_regs->ctr)) { + ret = FALSE; break; // size mismatch + } + memcpy(value, &pt_regs->ctr, size); + ret = TRUE; break; + } + if (bt_info.need_free) { + FREEBUF(pt_regs); + bt_info.need_free = FALSE; + } + + return ret; +} + /* * For vmcore typically saved with KDump or FADump, get SP and IP values * from the saved ptregs. @@ -2613,9 +2720,11 @@ ppc64_get_dumpfile_stack_frame(struct bt_info *bt_in, ulong *nip, ulong *ksp) pt_regs = (struct ppc64_pt_regs *)bt->machdep; ur_nip = pt_regs->nip; ur_ksp = pt_regs->gpr[1]; - /* Print the collected regs for panic task. */ - ppc64_print_regs(pt_regs); - ppc64_print_nip_lr(pt_regs, 1); + if (!(bt->flags & BT_NO_PRINT_REGS)) { + /* Print the collected regs for panic task. */ + ppc64_print_regs(pt_regs); + ppc64_print_nip_lr(pt_regs, 1); + } } else if ((pc->flags & KDUMP) || ((pc->flags & DISKDUMP) && (*diskdump_flags & KDUMP_CMPRS_LOCAL))) { @@ -2779,19 +2888,27 @@ static void ppc64_get_stack_frame(struct bt_info *bt, ulong *pcp, ulong *spp) { ulong ksp, nip; - + struct ppc64_pt_regs *regs; + nip = ksp = 0; - if (DUMPFILE() && is_task_active(bt->task)) + if (DUMPFILE() && is_task_active(bt->task)) { ppc64_get_dumpfile_stack_frame(bt, &nip, &ksp); - else + bt->need_free = FALSE; + } else { get_ppc64_frame(bt, &nip, &ksp); + regs = (struct ppc64_pt_regs *)GETBUF(sizeof(struct ppc64_pt_regs)); + memset(regs, 0, sizeof(struct ppc64_pt_regs)); + regs->nip = nip; + regs->gpr[1] = ksp; + bt->machdep = regs; + bt->need_free = TRUE; + } if (pcp) *pcp = nip; if (spp) *spp = ksp; - } static ulong