Skip to content

Commit 6dfda0d

Browse files
adi-g15-ibmlian-bo
authored andcommitted
ppc64: Add gdb stack unwind support
Currently, gdb passthroughs of 'bt', 'frame', 'up', 'down', 'info locals' don't work. This is due to gdb not knowing the register values to unwind the stack frames Every gdb passthrough goes through `gdb_interface`. And then, gdb expects `crash_target::fetch_registers` to give it the register values, which is dependent on `machdep->get_current_task_reg` to read the register values for specific architecture. ---------------------------- gdb passthrough (eg. "bt") | | crash -------------------------> | | | gdb_interface | | | | | | ---------------------- | fetch_registers | | | | crash_target<-------------------------+--| gdb | | --------------------------+->| | | Registers (SP,NIP, etc.)| | | | | | | | | ---------------------- | ---------------------------- Implement `machdep->get_current_task_reg` on PPC64, so that crash provides the register values to gdb to unwind stack frames properly With these changes, on powerpc, 'bt' command output in gdb mode, will look like this: gdb> bt #0 0xc0000000002a53e8 in crash_setup_regs (oldregs=<optimized out>, newregs=0xc00000000486f8d8) at ./arch/powerpc/include/asm/kexec.h:69 #1 __crash_kexec (regs=<optimized out>) at kernel/kexec_core.c:974 #2 0xc000000000168918 in panic (fmt=<optimized out>) at kernel/panic.c:358 #3 0xc000000000b735f8 in sysrq_handle_crash (key=<optimized out>) at drivers/tty/sysrq.c:155 #4 0xc000000000b742cc in __handle_sysrq (key=key@entry=99, check_mask=check_mask@entry=false) at drivers/tty/sysrq.c:602 #5 0xc000000000b7506c in write_sysrq_trigger (file=<optimized out>, buf=<optimized out>, count=2, ppos=<optimized out>) at drivers/tty/sysrq.c:1163 #6 0xc00000000069a7bc in pde_write (ppos=<optimized out>, count=<optimized out>, buf=<optimized out>, file=<optimized out>, pde=0xc000000009ed3a80) at fs/proc/inode.c:340 #7 proc_reg_write (file=<optimized out>, buf=<optimized out>, count=<optimized out>, ppos=<optimized out>) at fs/proc/inode.c:352 #8 0xc0000000005b3bbc in vfs_write (file=file@entry=0xc00000009dda7d00, buf=buf@entry=0xebcfc7c6040 <error: Cannot access memory at address 0xebcfc7c6040>, count=count@entry=2, pos=pos@entry=0xc00000000486fda0) at fs/read_write.c:582 instead of earlier output without this patch: gdb> bt #0 <unavailable> in ?? () Backtrace stopped: previous frame identical to this frame (corrupt stack?) Also, 'get_dumpfile_regs' has been introduced to get registers from multiple supported vmcore formats. Correspondingly a flag 'BT_NO_PRINT_REGS' has been introduced to tell helper functions to get registers, to not print registers with every call to backtrace in gdb. Note: This feature to support GDB unwinding doesn't support live debugging [lijiang: squash these five patches(see the Link) into one patch] Link: https://www.mail-archive.com/[email protected]/msg01084.html Link: https://www.mail-archive.com/[email protected]/msg01083.html Link: https://www.mail-archive.com/[email protected]/msg01089.html Link: https://www.mail-archive.com/[email protected]/msg01090.html Link: https://www.mail-archive.com/[email protected]/msg01091.html Co-developed-by:: Tao Liu <[email protected]> Signed-off-by: Aditya Gupta <[email protected]>
1 parent 1fd80c6 commit 6dfda0d

File tree

6 files changed

+437
-13
lines changed

6 files changed

+437
-13
lines changed

defs.h

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -982,6 +982,7 @@ struct bt_info {
982982
ulong eframe_ip;
983983
ulong radix;
984984
ulong *cpumask;
985+
bool need_free;
985986
};
986987

987988
#define STACK_OFFSET_TYPE(OFF) \
@@ -6162,6 +6163,7 @@ int load_module_symbols_helper(char *);
61626163
void unlink_module(struct load_module *);
61636164
int check_specified_module_tree(char *, char *);
61646165
int is_system_call(char *, ulong);
6166+
void get_dumpfile_regs(struct bt_info*, ulong*, ulong*);
61656167
void generic_dump_irq(int);
61666168
void generic_get_irq_affinity(int);
61676169
void generic_show_interrupts(int, ulong *);
@@ -6261,6 +6263,7 @@ ulong cpu_map_addr(const char *type);
62616263
#define BT_REGS_NOT_FOUND (0x4000000000000ULL)
62626264
#define BT_OVERFLOW_STACK (0x8000000000000ULL)
62636265
#define BT_SKIP_IDLE (0x10000000000000ULL)
6266+
#define BT_NO_PRINT_REGS (0x20000000000000ULL)
62646267
#define BT_SYMBOL_OFFSET (BT_SYMBOLIC_ARGS)
62656268

62666269
#define BT_REF_HEXVAL (0x1)
@@ -7966,6 +7969,7 @@ extern unsigned char *gdb_prettyprint_arrays;
79667969
extern unsigned int *gdb_repeat_count_threshold;
79677970
extern unsigned char *gdb_stop_print_at_null;
79687971
extern unsigned int *gdb_output_radix;
7972+
int is_kvaddr(ulong);
79697973

79707974
/*
79717975
* gdb/top.c
@@ -8066,6 +8070,13 @@ extern int have_full_symbols(void);
80668070
#define XEN_HYPERVISOR_ARCH
80678071
#endif
80688072

8073+
#ifndef offsetof
8074+
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
8075+
#endif
8076+
#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
8077+
#define REG_SEQ(TYPE, MEMBER) \
8078+
(offsetof(struct TYPE, MEMBER) / FIELD_SIZEOF(struct TYPE, MEMBER))
8079+
80698080
/*
80708081
* Register numbers must be in sync with gdb/features/i386/64bit-core.c
80718082
* to make crash_target->fetch_registers() ---> machdep->get_cpu_reg()
@@ -8115,6 +8126,126 @@ enum x86_64_regnum {
81158126
LAST_REGNUM
81168127
};
81178128

8129+
/*
8130+
* Register numbers to make crash_target->fetch_registers()
8131+
* ---> machdep->get_current_task_reg() work properly.
8132+
*
8133+
* These register numbers and names are given according to output of
8134+
* `rs6000_register_name`, because that is what was being used by
8135+
* crash_target::fetch_registers in case of PPC64
8136+
*/
8137+
enum ppc64_regnum {
8138+
PPC64_R0_REGNUM = 0,
8139+
PPC64_R1_REGNUM,
8140+
PPC64_R2_REGNUM,
8141+
PPC64_R3_REGNUM,
8142+
PPC64_R4_REGNUM,
8143+
PPC64_R5_REGNUM,
8144+
PPC64_R6_REGNUM,
8145+
PPC64_R7_REGNUM,
8146+
PPC64_R8_REGNUM,
8147+
PPC64_R9_REGNUM,
8148+
PPC64_R10_REGNUM,
8149+
PPC64_R11_REGNUM,
8150+
PPC64_R12_REGNUM,
8151+
PPC64_R13_REGNUM,
8152+
PPC64_R14_REGNUM,
8153+
PPC64_R15_REGNUM,
8154+
PPC64_R16_REGNUM,
8155+
PPC64_R17_REGNUM,
8156+
PPC64_R18_REGNUM,
8157+
PPC64_R19_REGNUM,
8158+
PPC64_R20_REGNUM,
8159+
PPC64_R21_REGNUM,
8160+
PPC64_R22_REGNUM,
8161+
PPC64_R23_REGNUM,
8162+
PPC64_R24_REGNUM,
8163+
PPC64_R25_REGNUM,
8164+
PPC64_R26_REGNUM,
8165+
PPC64_R27_REGNUM,
8166+
PPC64_R28_REGNUM,
8167+
PPC64_R29_REGNUM,
8168+
PPC64_R30_REGNUM,
8169+
PPC64_R31_REGNUM,
8170+
8171+
PPC64_F0_REGNUM = 32,
8172+
PPC64_F1_REGNUM,
8173+
PPC64_F2_REGNUM,
8174+
PPC64_F3_REGNUM,
8175+
PPC64_F4_REGNUM,
8176+
PPC64_F5_REGNUM,
8177+
PPC64_F6_REGNUM,
8178+
PPC64_F7_REGNUM,
8179+
PPC64_F8_REGNUM,
8180+
PPC64_F9_REGNUM,
8181+
PPC64_F10_REGNUM,
8182+
PPC64_F11_REGNUM,
8183+
PPC64_F12_REGNUM,
8184+
PPC64_F13_REGNUM,
8185+
PPC64_F14_REGNUM,
8186+
PPC64_F15_REGNUM,
8187+
PPC64_F16_REGNUM,
8188+
PPC64_F17_REGNUM,
8189+
PPC64_F18_REGNUM,
8190+
PPC64_F19_REGNUM,
8191+
PPC64_F20_REGNUM,
8192+
PPC64_F21_REGNUM,
8193+
PPC64_F22_REGNUM,
8194+
PPC64_F23_REGNUM,
8195+
PPC64_F24_REGNUM,
8196+
PPC64_F25_REGNUM,
8197+
PPC64_F26_REGNUM,
8198+
PPC64_F27_REGNUM,
8199+
PPC64_F28_REGNUM,
8200+
PPC64_F29_REGNUM,
8201+
PPC64_F30_REGNUM,
8202+
PPC64_F31_REGNUM,
8203+
8204+
PPC64_PC_REGNUM = 64,
8205+
PPC64_MSR_REGNUM = 65,
8206+
PPC64_CR_REGNUM = 66,
8207+
PPC64_LR_REGNUM = 67,
8208+
PPC64_CTR_REGNUM = 68,
8209+
PPC64_XER_REGNUM = 69,
8210+
PPC64_FPSCR_REGNUM = 70,
8211+
8212+
PPC64_VR0_REGNUM = 106,
8213+
PPC64_VR1_REGNUM,
8214+
PPC64_VR2_REGNUM,
8215+
PPC64_VR3_REGNUM,
8216+
PPC64_VR4_REGNUM,
8217+
PPC64_VR5_REGNUM,
8218+
PPC64_VR6_REGNUM,
8219+
PPC64_VR7_REGNUM,
8220+
PPC64_VR8_REGNUM,
8221+
PPC64_VR9_REGNUM,
8222+
PPC64_VR10_REGNUM,
8223+
PPC64_VR11_REGNUM,
8224+
PPC64_VR12_REGNUM,
8225+
PPC64_VR13_REGNUM,
8226+
PPC64_VR14_REGNUM,
8227+
PPC64_VR15_REGNUM,
8228+
PPC64_VR16_REGNUM,
8229+
PPC64_VR17_REGNUM,
8230+
PPC64_VR18_REGNUM,
8231+
PPC64_VR19_REGNUM,
8232+
PPC64_VR20_REGNUM,
8233+
PPC64_VR21_REGNUM,
8234+
PPC64_VR22_REGNUM,
8235+
PPC64_VR23_REGNUM,
8236+
PPC64_VR24_REGNUM,
8237+
PPC64_VR25_REGNUM,
8238+
PPC64_VR26_REGNUM,
8239+
PPC64_VR27_REGNUM,
8240+
PPC64_VR28_REGNUM,
8241+
PPC64_VR29_REGNUM,
8242+
PPC64_VR30_REGNUM,
8243+
PPC64_VR31_REGNUM,
8244+
8245+
PPC64_VSCR_REGNUM = 138,
8246+
PPC64_VRSAVE_REGNU = 139
8247+
};
8248+
81188249
/* crash_target.c */
81198250
extern int gdb_change_thread_context (void);
81208251

gdb-10.2.patch

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ tar xvzmf gdb-10.2.tar.gz \
1616
gdb-10.2/gdb/dwarf2/read.c \
1717
gdb-10.2/gdb/ada-lang.c \
1818
gdb-10.2/gdb/objfiles.h \
19-
gdb-10.2/bfd/elf-bfd.h
19+
gdb-10.2/bfd/elf-bfd.h \
20+
gdb-10.2/gdb/stack.c \
21+
gdb-10.2/gdb/ui-file.h
2022

2123
# For newly added gdb files, remove them to be its original state.
2224

@@ -16118,3 +16120,99 @@ exit 0
1611816120
subclass (SYMBOL_NONE)
1611916121
{
1612016122
/* We can't use an initializer list for members of a base class, and
16123+
--- gdb-10.2/gdb/ui-file.h.orig
16124+
+++ gdb-10.2/gdb/ui-file.h
16125+
@@ -195,6 +195,7 @@ public:
16126+
16127+
bool can_emit_style_escape () override;
16128+
16129+
+ FILE *get_stream(void);
16130+
/* Sets the internal stream to FILE, and saves the FILE's file
16131+
descriptor in M_FD. */
16132+
void set_stream (FILE *file);
16133+
--- gdb-10.2/gdb/ui-file.c.orig
16134+
+++ gdb-10.2/gdb/ui-file.c
16135+
@@ -161,6 +161,12 @@ stdio_file::~stdio_file ()
16136+
fclose (m_file);
16137+
}
16138+
16139+
+FILE*
16140+
+stdio_file::get_stream(void)
16141+
+{
16142+
+ return m_file;
16143+
+}
16144+
+
16145+
void
16146+
stdio_file::set_stream (FILE *file)
16147+
{
16148+
--- gdb-10.2/gdb/symtab.c.orig
16149+
+++ gdb-10.2/gdb/symtab.c
16150+
@@ -6964,8 +6964,12 @@ void
16151+
gdb_command_funnel_1(struct gnu_request *req)
16152+
{
16153+
struct symbol *sym;
16154+
+ FILE *original_stdout_stream = nullptr;
16155+
+ FILE *original_stderr_stream = nullptr;
16156+
16157+
if (req->command != GNU_VERSION && req->command != GNU_USER_PRINT_OPTION) {
16158+
+ original_stdout_stream = (dynamic_cast< stdio_file * >gdb_stdout)->get_stream();
16159+
+ original_stderr_stream = (dynamic_cast< stdio_file * >gdb_stderr)->get_stream();
16160+
(dynamic_cast<stdio_file *>gdb_stdout)->set_stream(req->fp);
16161+
(dynamic_cast<stdio_file *>gdb_stderr)->set_stream(req->fp);
16162+
}
16163+
@@ -7068,6 +7072,12 @@ gdb_command_funnel_1(struct gnu_request *req)
16164+
req->flags |= GNU_COMMAND_FAILED;
16165+
break;
16166+
}
16167+
+
16168+
+ /* Restore the streams gdb output was using */
16169+
+ if (original_stdout_stream)
16170+
+ (dynamic_cast<stdio_file *>gdb_stdout)->set_stream(original_stdout_stream);
16171+
+ if (original_stderr_stream)
16172+
+ (dynamic_cast<stdio_file *>gdb_stderr)->set_stream(original_stderr_stream);
16173+
}
16174+
16175+
/*
16176+
--- gdb-10.2/gdb/stack.c.orig
16177+
+++ gdb-10.2/gdb/stack.c
16178+
@@ -1990,6 +1990,11 @@
16179+
/* Print briefly all stack frames or just the innermost COUNT_EXP
16180+
frames. */
16181+
16182+
+#ifdef CRASH_MERGE
16183+
+extern "C" int is_kvaddr(ulong);
16184+
+extern "C" int gdb_CRASHDEBUG(ulong);
16185+
+#endif
16186+
+
16187+
static void
16188+
backtrace_command_1 (const frame_print_options &fp_opts,
16189+
const backtrace_cmd_options &bt_opts,
16190+
@@ -2082,6 +2086,17 @@
16191+
hand, perhaps the code does or could be fixed to make sure
16192+
the frame->prev field gets set to NULL in that case). */
16193+
16194+
+#ifdef CRASH_MERGE
16195+
+ CORE_ADDR pc = 0;
16196+
+ get_frame_pc_if_available (fi, &pc);
16197+
+ if (!is_kvaddr(pc)) {
16198+
+ if (gdb_CRASHDEBUG(1)) {
16199+
+ printf_filtered (_("Backtrace stopped: due to non-kernel addr: 0x%lx\n"),pc);
16200+
+ }
16201+
+ fi = NULL;
16202+
+ break;
16203+
+ }
16204+
+#endif
16205+
print_frame_info (fp_opts, fi, 1, LOCATION, 1, 0);
16206+
if ((flags & PRINT_LOCALS) != 0)
16207+
{
16208+
--- gdb-10.2/gdb/stack.c.orig
16209+
+++ gdb-10.2/gdb/stack.c
16210+
@@ -2127,7 +2127,7 @@
16211+
enum unwind_stop_reason reason;
16212+
16213+
reason = get_frame_unwind_stop_reason (trailing);
16214+
- if (reason >= UNWIND_FIRST_ERROR)
16215+
+ if (reason >= UNWIND_FIRST_ERROR && gdb_CRASHDEBUG(1))
16216+
printf_filtered (_("Backtrace stopped: %s\n"),
16217+
frame_stop_reason_string (trailing));
16218+
}

gdb_interface.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -711,7 +711,7 @@ static char *prohibited_list[] = {
711711
"watch", "rwatch", "awatch", "attach", "continue", "c", "fg", "detach",
712712
"finish", "handle", "interrupt", "jump", "kill", "next", "nexti",
713713
"signal", "step", "s", "stepi", "target", "until", "delete",
714-
"clear", "disable", "enable", "condition", "ignore", "frame", "catch",
714+
"clear", "disable", "enable", "condition", "ignore", "catch",
715715
"tcatch", "return", "file", "exec-file", "core-file", "symbol-file",
716716
"load", "si", "ni", "shell", "sy",
717717
NULL /* must be last */
@@ -947,6 +947,12 @@ gdb_lookup_module_symbol(ulong addr, ulong *offset)
947947
}
948948
}
949949

950+
int
951+
is_kvaddr(ulong addr)
952+
{
953+
return IS_KVADDR(addr);
954+
}
955+
950956
/*
951957
* Used by gdb_interface() to catch gdb-related errors, if desired.
952958
*/

kernel.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3535,6 +3535,39 @@ get_lkcd_regs(struct bt_info *bt, ulong *eip, ulong *esp)
35353535
machdep->get_stack_frame(bt, eip, esp);
35363536
}
35373537

3538+
void
3539+
get_dumpfile_regs(struct bt_info *bt, ulong *eip, ulong *esp)
3540+
{
3541+
bt->flags |= BT_NO_PRINT_REGS;
3542+
3543+
if (NETDUMP_DUMPFILE())
3544+
get_netdump_regs(bt, eip, esp);
3545+
else if (KDUMP_DUMPFILE())
3546+
get_kdump_regs(bt, eip, esp);
3547+
else if (DISKDUMP_DUMPFILE())
3548+
get_diskdump_regs(bt, eip, esp);
3549+
else if (KVMDUMP_DUMPFILE())
3550+
get_kvmdump_regs(bt, eip, esp);
3551+
else if (LKCD_DUMPFILE())
3552+
get_lkcd_regs(bt, eip, esp);
3553+
else if (XENDUMP_DUMPFILE())
3554+
get_xendump_regs(bt, eip, esp);
3555+
else if (SADUMP_DUMPFILE())
3556+
get_sadump_regs(bt, eip, esp);
3557+
else if (VMSS_DUMPFILE())
3558+
get_vmware_vmss_regs(bt, eip, esp);
3559+
else if (REMOTE_PAUSED()) {
3560+
if (!is_task_active(bt->task) || !get_remote_regs(bt, eip, esp))
3561+
machdep->get_stack_frame(bt, eip, esp);
3562+
} else
3563+
machdep->get_stack_frame(bt, eip, esp);
3564+
3565+
bt->flags &= ~BT_NO_PRINT_REGS;
3566+
3567+
bt->instptr = *eip;
3568+
bt->stkptr = *esp;
3569+
}
3570+
35383571

35393572
/*
35403573
* Store the head of the kernel module list for future use.

0 commit comments

Comments
 (0)