diff --git a/defs.h b/defs.h index 511942a..8fa1954 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) \ @@ -6162,6 +6163,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 *); @@ -6261,6 +6263,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) @@ -7966,6 +7969,7 @@ extern unsigned char *gdb_prettyprint_arrays; extern unsigned int *gdb_repeat_count_threshold; extern unsigned char *gdb_stop_print_at_null; extern unsigned int *gdb_output_radix; +int is_kvaddr(ulong); /* * gdb/top.c @@ -8066,6 +8070,13 @@ extern int have_full_symbols(void); #define XEN_HYPERVISOR_ARCH #endif +#ifndef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) +#endif +#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) +#define REG_SEQ(TYPE, MEMBER) \ + (offsetof(struct TYPE, MEMBER) / FIELD_SIZEOF(struct TYPE, MEMBER)) + /* * Register numbers must be in sync with gdb/features/i386/64bit-core.c * to make crash_target->fetch_registers() ---> machdep->get_cpu_reg() @@ -8115,6 +8126,126 @@ enum x86_64_regnum { LAST_REGNUM }; +/* + * Register numbers to make crash_target->fetch_registers() + * ---> machdep->get_current_task_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 +}; + /* crash_target.c */ extern int gdb_change_thread_context (void); diff --git a/gdb-10.2.patch b/gdb-10.2.patch index 3694b13..c867660 100644 --- a/gdb-10.2.patch +++ b/gdb-10.2.patch @@ -16,7 +16,9 @@ tar xvzmf gdb-10.2.tar.gz \ gdb-10.2/gdb/dwarf2/read.c \ gdb-10.2/gdb/ada-lang.c \ gdb-10.2/gdb/objfiles.h \ - gdb-10.2/bfd/elf-bfd.h + gdb-10.2/bfd/elf-bfd.h \ + gdb-10.2/gdb/stack.c \ + gdb-10.2/gdb/ui-file.h # For newly added gdb files, remove them to be its original state. @@ -16118,3 +16120,99 @@ exit 0 subclass (SYMBOL_NONE) { /* We can't use an initializer list for members of a base class, and +--- gdb-10.2/gdb/ui-file.h.orig ++++ gdb-10.2/gdb/ui-file.h +@@ -195,6 +195,7 @@ public: + + bool can_emit_style_escape () override; + ++ FILE *get_stream(void); + /* Sets the internal stream to FILE, and saves the FILE's file + descriptor in M_FD. */ + void set_stream (FILE *file); +--- gdb-10.2/gdb/ui-file.c.orig ++++ gdb-10.2/gdb/ui-file.c +@@ -161,6 +161,12 @@ stdio_file::~stdio_file () + fclose (m_file); + } + ++FILE* ++stdio_file::get_stream(void) ++{ ++ return m_file; ++} ++ + void + stdio_file::set_stream (FILE *file) + { +--- gdb-10.2/gdb/symtab.c.orig ++++ gdb-10.2/gdb/symtab.c +@@ -6964,8 +6964,12 @@ void + gdb_command_funnel_1(struct gnu_request *req) + { + struct symbol *sym; ++ FILE *original_stdout_stream = nullptr; ++ FILE *original_stderr_stream = nullptr; + + if (req->command != GNU_VERSION && req->command != GNU_USER_PRINT_OPTION) { ++ original_stdout_stream = (dynamic_cast< stdio_file * >gdb_stdout)->get_stream(); ++ original_stderr_stream = (dynamic_cast< stdio_file * >gdb_stderr)->get_stream(); + (dynamic_castgdb_stdout)->set_stream(req->fp); + (dynamic_castgdb_stderr)->set_stream(req->fp); + } +@@ -7068,6 +7072,12 @@ gdb_command_funnel_1(struct gnu_request *req) + req->flags |= GNU_COMMAND_FAILED; + break; + } ++ ++ /* Restore the streams gdb output was using */ ++ if (original_stdout_stream) ++ (dynamic_castgdb_stdout)->set_stream(original_stdout_stream); ++ if (original_stderr_stream) ++ (dynamic_castgdb_stderr)->set_stream(original_stderr_stream); + } + + /* +--- gdb-10.2/gdb/stack.c.orig ++++ gdb-10.2/gdb/stack.c +@@ -1990,6 +1990,11 @@ + /* Print briefly all stack frames or just the innermost COUNT_EXP + frames. */ + ++#ifdef CRASH_MERGE ++extern "C" int is_kvaddr(ulong); ++extern "C" int gdb_CRASHDEBUG(ulong); ++#endif ++ + static void + backtrace_command_1 (const frame_print_options &fp_opts, + const backtrace_cmd_options &bt_opts, +@@ -2082,6 +2086,17 @@ + hand, perhaps the code does or could be fixed to make sure + the frame->prev field gets set to NULL in that case). */ + ++#ifdef CRASH_MERGE ++ CORE_ADDR pc = 0; ++ get_frame_pc_if_available (fi, &pc); ++ if (!is_kvaddr(pc)) { ++ if (gdb_CRASHDEBUG(1)) { ++ printf_filtered (_("Backtrace stopped: due to non-kernel addr: 0x%lx\n"),pc); ++ } ++ fi = NULL; ++ break; ++ } ++#endif + print_frame_info (fp_opts, fi, 1, LOCATION, 1, 0); + if ((flags & PRINT_LOCALS) != 0) + { +--- gdb-10.2/gdb/stack.c.orig ++++ gdb-10.2/gdb/stack.c +@@ -2127,7 +2127,7 @@ + enum unwind_stop_reason reason; + + reason = get_frame_unwind_stop_reason (trailing); +- if (reason >= UNWIND_FIRST_ERROR) ++ if (reason >= UNWIND_FIRST_ERROR && gdb_CRASHDEBUG(1)) + printf_filtered (_("Backtrace stopped: %s\n"), + frame_stop_reason_string (trailing)); + } diff --git a/gdb_interface.c b/gdb_interface.c index 03681ec..315711e 100644 --- a/gdb_interface.c +++ b/gdb_interface.c @@ -711,7 +711,7 @@ static char *prohibited_list[] = { "watch", "rwatch", "awatch", "attach", "continue", "c", "fg", "detach", "finish", "handle", "interrupt", "jump", "kill", "next", "nexti", "signal", "step", "s", "stepi", "target", "until", "delete", - "clear", "disable", "enable", "condition", "ignore", "frame", "catch", + "clear", "disable", "enable", "condition", "ignore", "catch", "tcatch", "return", "file", "exec-file", "core-file", "symbol-file", "load", "si", "ni", "shell", "sy", NULL /* must be last */ @@ -947,6 +947,12 @@ gdb_lookup_module_symbol(ulong addr, ulong *offset) } } +int +is_kvaddr(ulong addr) +{ + return IS_KVADDR(addr); +} + /* * Used by gdb_interface() to catch gdb-related errors, if desired. */ diff --git a/kernel.c b/kernel.c index edfd17c..8c2e0ca 100644 --- a/kernel.c +++ b/kernel.c @@ -3535,6 +3535,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 e8930a1..782107b 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_current_task_reg(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); @@ -73,6 +75,11 @@ static ulong pmd_page_vaddr_l4(ulong pmd); static int is_opal_context(ulong sp, ulong nip); void opalmsg(void); +struct user_regs_bitmap_struct { + struct ppc64_pt_regs ur; + ulong bitmap[32]; +}; + static int is_opal_context(ulong sp, ulong nip) { uint64_t opal_start, opal_end; @@ -704,6 +711,8 @@ ppc64_init(int when) error(FATAL, "cannot malloc hwirqstack buffer space."); } + machdep->get_current_task_reg = ppc64_get_current_task_reg; + ppc64_init_paca_info(); if (!machdep->hz) { @@ -2501,6 +2510,145 @@ ppc64_print_eframe(char *efrm_str, struct ppc64_pt_regs *regs, ppc64_print_nip_lr(regs, 1); } +static int +ppc64_get_current_task_reg(int regno, const char *name, int size, + void *value) +{ + struct bt_info bt_info, bt_setup; + struct task_context *tc; + struct user_regs_bitmap_struct *ur_bitmap; + ulong ip, sp; + bool ret = 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); + ur_bitmap = (struct user_regs_bitmap_struct *)bt_info.machdep; + + if (!ur_bitmap) { + error(WARNING, "pt_regs not available for cpu %d\n", tc->processor); + return FALSE; + } + if (!bt_info.need_free) { + goto get_all; + } + + switch (regno) { + case PPC64_R0_REGNUM ... PPC64_R31_REGNUM: + if (!NUM_IN_BITMAP(ur_bitmap->bitmap, + REG_SEQ(ppc64_pt_regs, gpr[0]) + regno - PPC64_R0_REGNUM)) { + FREEBUF(ur_bitmap); + return FALSE; + } + break; + case PPC64_PC_REGNUM: + if (!NUM_IN_BITMAP(ur_bitmap->bitmap, + REG_SEQ(ppc64_pt_regs, nip))) { + FREEBUF(ur_bitmap); + return FALSE; + } + break; + case PPC64_MSR_REGNUM: + if (!NUM_IN_BITMAP(ur_bitmap->bitmap, + REG_SEQ(ppc64_pt_regs, msr))) { + FREEBUF(ur_bitmap); + return FALSE; + } + break; + case PPC64_LR_REGNUM: + if (!NUM_IN_BITMAP(ur_bitmap->bitmap, + REG_SEQ(ppc64_pt_regs, link))) { + FREEBUF(ur_bitmap); + return FALSE; + } + break; + case PPC64_CTR_REGNUM: + if (!NUM_IN_BITMAP(ur_bitmap->bitmap, + REG_SEQ(ppc64_pt_regs, ctr))) { + FREEBUF(ur_bitmap); + return FALSE; + } + break; + } + +get_all: + switch (regno) { + case PPC64_R0_REGNUM ... PPC64_R31_REGNUM: + if (size != sizeof(ur_bitmap->ur.gpr[regno])) + break; + memcpy(value, &ur_bitmap->ur.gpr[regno], size); + ret = TRUE; + break; + + case PPC64_PC_REGNUM: + if (size != sizeof(ur_bitmap->ur.nip)) + break; + memcpy(value, &ur_bitmap->ur.nip, size); + ret = TRUE; + break; + + case PPC64_MSR_REGNUM: + if (size != sizeof(ur_bitmap->ur.msr)) + break; + memcpy(value, &ur_bitmap->ur.msr, size); + ret = TRUE; + break; + + case PPC64_LR_REGNUM: + if (size != sizeof(ur_bitmap->ur.link)) + break; + memcpy(value, &ur_bitmap->ur.link, size); + ret = TRUE; + break; + + case PPC64_CTR_REGNUM: + if (size != sizeof(ur_bitmap->ur.ctr)) + break; + memcpy(value, &ur_bitmap->ur.ctr, size); + ret = TRUE; + break; + } + if (bt_info.need_free) { + FREEBUF(ur_bitmap); + 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 +2761,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 +2929,29 @@ static void ppc64_get_stack_frame(struct bt_info *bt, ulong *pcp, ulong *spp) { ulong ksp, nip; - + struct user_regs_bitmap_struct *ur_bitmap; + 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); + ur_bitmap = (struct user_regs_bitmap_struct *)GETBUF(sizeof(*ur_bitmap)); + memset(ur_bitmap, 0, sizeof(*ur_bitmap)); + ur_bitmap->ur.nip = nip; + ur_bitmap->ur.gpr[1] = ksp; + SET_BIT(ur_bitmap->bitmap, REG_SEQ(ppc64_pt_regs, nip)); + SET_BIT(ur_bitmap->bitmap, REG_SEQ(ppc64_pt_regs, gpr[0]) + 1); + bt->machdep = ur_bitmap; + bt->need_free = TRUE; + } if (pcp) *pcp = nip; if (spp) *spp = ksp; - } static ulong diff --git a/unwind_x86_64.h b/unwind_x86_64.h index 850d488..d16da14 100644 --- a/unwind_x86_64.h +++ b/unwind_x86_64.h @@ -58,13 +58,9 @@ extern int unwind(struct unwind_frame_info *, int); extern void init_unwind_table(void); extern void free_unwind_table(void); -#ifndef offsetof -#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) -#endif #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)])) #define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); })) -#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) #define get_unaligned(ptr) (*(ptr)) //#define __get_user(x,ptr) __get_user_nocheck((x),(ptr),sizeof(*(ptr))) #define THREAD_ORDER 1