3106 lines
91 KiB
Diff
3106 lines
91 KiB
Diff
|
|
diff -Nuar crash-7.3.0.org/Makefile crash-7.3.0.sw/Makefile
|
||
|
|
--- crash-7.3.0.org/Makefile 2022-03-14 07:58:52.278814120 +0000
|
||
|
|
+++ crash-7.3.0.sw/Makefile 2022-03-15 06:11:27.978814120 +0000
|
||
|
|
@@ -20,7 +20,7 @@
|
||
|
|
PROGRAM=crash
|
||
|
|
|
||
|
|
#
|
||
|
|
-# Supported targets: X86 ALPHA PPC IA64 PPC64 SPARC64
|
||
|
|
+# Supported targets: X86 SW_64 ALPHA PPC IA64 PPC64 SPARC64
|
||
|
|
# TARGET and GDB_CONF_FLAGS will be configured automatically by configure
|
||
|
|
#
|
||
|
|
TARGET=
|
||
|
|
@@ -62,7 +62,7 @@
|
||
|
|
CFILES=main.c tools.c global_data.c memory.c filesys.c help.c task.c \
|
||
|
|
kernel.c test.c gdb_interface.c configure.c net.c dev.c bpf.c \
|
||
|
|
printk.c \
|
||
|
|
- alpha.c x86.c ppc.c ia64.c s390.c s390x.c s390dbf.c ppc64.c x86_64.c \
|
||
|
|
+ sw_64.c alpha.c x86.c ppc.c ia64.c s390.c s390x.c s390dbf.c ppc64.c x86_64.c \
|
||
|
|
arm.c arm64.c mips.c mips64.c sparc64.c \
|
||
|
|
extensions.c remote.c va_server.c va_server_v1.c symbols.c cmdline.c \
|
||
|
|
lkcd_common.c lkcd_v1.c lkcd_v2_v3.c lkcd_v5.c lkcd_v7.c lkcd_v8.c\
|
||
|
|
@@ -82,7 +82,7 @@
|
||
|
|
OBJECT_FILES=main.o tools.o global_data.o memory.o filesys.o help.o task.o \
|
||
|
|
build_data.o kernel.o test.o gdb_interface.o net.o dev.o bpf.o \
|
||
|
|
printk.o \
|
||
|
|
- alpha.o x86.o ppc.o ia64.o s390.o s390x.o s390dbf.o ppc64.o x86_64.o \
|
||
|
|
+ sw_64.o alpha.o x86.o ppc.o ia64.o s390.o s390x.o s390dbf.o ppc64.o x86_64.o \
|
||
|
|
arm.o arm64.o mips.o mips64.o sparc64.o \
|
||
|
|
extensions.o remote.o va_server.o va_server_v1.o symbols.o cmdline.o \
|
||
|
|
lkcd_common.o lkcd_v1.o lkcd_v2_v3.o lkcd_v5.o lkcd_v7.o lkcd_v8.o \
|
||
|
|
@@ -415,6 +415,9 @@
|
||
|
|
x86.o: ${GENERIC_HFILES} ${REDHAT_HFILES} x86.c
|
||
|
|
${CC} -c ${CRASH_CFLAGS} x86.c -DMCLX ${WARNING_OPTIONS} ${WARNING_ERROR}
|
||
|
|
|
||
|
|
+sw_64.o: ${GENERIC_HFILES} sw_64.c
|
||
|
|
+ ${CC} -c ${CRASH_CFLAGS} sw_64.c ${WARNING_OPTIONS} ${WARNING_ERROR}
|
||
|
|
+
|
||
|
|
alpha.o: ${GENERIC_HFILES} alpha.c
|
||
|
|
${CC} -c ${CRASH_CFLAGS} alpha.c ${WARNING_OPTIONS} ${WARNING_ERROR}
|
||
|
|
|
||
|
|
diff -Nuar crash-7.3.0.org/configure.c crash-7.3.0.sw/configure.c
|
||
|
|
--- crash-7.3.0.org/configure.c 2022-03-14 07:58:52.278814120 +0000
|
||
|
|
+++ crash-7.3.0.sw/configure.c 2022-03-24 06:48:16.423873440 +0000
|
||
|
|
@@ -107,6 +107,7 @@
|
||
|
|
#undef MIPS
|
||
|
|
#undef SPARC64
|
||
|
|
#undef MIPS64
|
||
|
|
+#undef SW_64
|
||
|
|
|
||
|
|
#define UNKNOWN 0
|
||
|
|
#define X86 1
|
||
|
|
@@ -122,6 +123,7 @@
|
||
|
|
#define MIPS 11
|
||
|
|
#define SPARC64 12
|
||
|
|
#define MIPS64 13
|
||
|
|
+#define SW_64 14
|
||
|
|
|
||
|
|
#define TARGET_X86 "TARGET=X86"
|
||
|
|
#define TARGET_ALPHA "TARGET=ALPHA"
|
||
|
|
@@ -136,6 +138,7 @@
|
||
|
|
#define TARGET_MIPS "TARGET=MIPS"
|
||
|
|
#define TARGET_MIPS64 "TARGET=MIPS64"
|
||
|
|
#define TARGET_SPARC64 "TARGET=SPARC64"
|
||
|
|
+#define TARGET_SW_64 "TARGET=SW_64"
|
||
|
|
|
||
|
|
#define TARGET_CFLAGS_X86 "TARGET_CFLAGS=-D_FILE_OFFSET_BITS=64"
|
||
|
|
#define TARGET_CFLAGS_ALPHA "TARGET_CFLAGS="
|
||
|
|
@@ -158,6 +161,7 @@
|
||
|
|
#define TARGET_CFLAGS_MIPS_ON_X86_64 "TARGET_CFLAGS=-m32 -D_FILE_OFFSET_BITS=64"
|
||
|
|
#define TARGET_CFLAGS_MIPS64 "TARGET_CFLAGS="
|
||
|
|
#define TARGET_CFLAGS_SPARC64 "TARGET_CFLAGS="
|
||
|
|
+#define TARGET_CFLAGS_SW_64 "TARGET_CFLAGS="
|
||
|
|
|
||
|
|
#define GDB_TARGET_DEFAULT "GDB_CONF_FLAGS="
|
||
|
|
#define GDB_TARGET_ARM_ON_X86 "GDB_CONF_FLAGS=--target=arm-elf-linux"
|
||
|
|
@@ -354,6 +358,9 @@
|
||
|
|
static char buf[512];
|
||
|
|
char *p;
|
||
|
|
|
||
|
|
+#ifdef __sw_64__
|
||
|
|
+ target_data.target = SW_64;
|
||
|
|
+#endif
|
||
|
|
#ifdef __alpha__
|
||
|
|
target_data.target = ALPHA;
|
||
|
|
#endif
|
||
|
|
@@ -614,6 +621,9 @@
|
||
|
|
case X86:
|
||
|
|
printf("TARGET: X86\n");
|
||
|
|
break;
|
||
|
|
+ case SW_64:
|
||
|
|
+ printf("TARGET: SW_64\n");
|
||
|
|
+ break;
|
||
|
|
case ALPHA:
|
||
|
|
printf("TARGET: ALPHA\n");
|
||
|
|
break;
|
||
|
|
@@ -693,6 +703,10 @@
|
||
|
|
} else
|
||
|
|
target_CFLAGS = TARGET_CFLAGS_X86;
|
||
|
|
break;
|
||
|
|
+ case SW_64:
|
||
|
|
+ target = TARGET_SW_64;
|
||
|
|
+ target_CFLAGS = TARGET_CFLAGS_SW_64;
|
||
|
|
+ break;
|
||
|
|
case ALPHA:
|
||
|
|
target = TARGET_ALPHA;
|
||
|
|
target_CFLAGS = TARGET_CFLAGS_ALPHA;
|
||
|
|
@@ -1364,7 +1378,7 @@
|
||
|
|
printf("Vendor: Red Hat, Inc.\n");
|
||
|
|
printf("Packager: Dave Anderson <anderson@redhat.com>\n");
|
||
|
|
printf("ExclusiveOS: Linux\n");
|
||
|
|
- printf("ExclusiveArch: %%{ix86} alpha ia64 ppc ppc64 ppc64pseries ppc64iseries x86_64 s390 s390x arm aarch64 ppc64le mips mipsel mips64el sparc64\n");
|
||
|
|
+ printf("ExclusiveArch: %%{ix86} sw_64 alpha ia64 ppc ppc64 ppc64pseries ppc64iseries x86_64 s390 s390x arm aarch64 ppc64le mips mipsel mips64el sparc64\n");
|
||
|
|
printf("Buildroot: %%{_tmppath}/%%{name}-root\n");
|
||
|
|
printf("BuildRequires: ncurses-devel zlib-devel bison\n");
|
||
|
|
printf("Requires: binutils\n");
|
||
|
|
@@ -1575,6 +1589,8 @@
|
||
|
|
target_data.initial_gdb_target = X86_64;
|
||
|
|
else if (strncmp(buf, "X86", strlen("X86")) == 0)
|
||
|
|
target_data.initial_gdb_target = X86;
|
||
|
|
+ else if (strncmp(buf, "SW_64", strlen("SW_64")) == 0)
|
||
|
|
+ target_data.initial_gdb_target = SW_64;
|
||
|
|
else if (strncmp(buf, "ALPHA", strlen("ALPHA")) == 0)
|
||
|
|
target_data.initial_gdb_target = ALPHA;
|
||
|
|
else if (strncmp(buf, "PPC64", strlen("PPC64")) == 0)
|
||
|
|
@@ -1606,6 +1622,7 @@
|
||
|
|
{
|
||
|
|
case X86: return("X86");
|
||
|
|
case ALPHA: return("ALPHA");
|
||
|
|
+ case SW_64: return("SW_64");
|
||
|
|
case PPC: return("PPC");
|
||
|
|
case IA64: return("IA64");
|
||
|
|
case S390: return("S390");
|
||
|
|
@@ -1633,6 +1650,10 @@
|
||
|
|
return X86;
|
||
|
|
else if (strncmp(name, "x86", strlen("x86")) == 0)
|
||
|
|
return X86;
|
||
|
|
+ else if (strncmp(name, "SW_64", strlen("SW_64")) == 0)
|
||
|
|
+ return SW_64;
|
||
|
|
+ else if (strncmp(name, "sw_64", strlen("sw_64")) == 0)
|
||
|
|
+ return SW_64;
|
||
|
|
else if (strncmp(name, "ALPHA", strlen("ALPHA")) == 0)
|
||
|
|
return ALPHA;
|
||
|
|
else if (strncmp(name, "alpha", strlen("alpha")) == 0)
|
||
|
|
diff -Nuar crash-7.3.0.org/defs.h crash-7.3.0.sw/defs.h
|
||
|
|
--- crash-7.3.0.org/defs.h 2022-03-14 07:58:52.278814120 +0000
|
||
|
|
+++ crash-7.3.0.sw/defs.h 2022-03-24 06:45:53.683873440 +0000
|
||
|
|
@@ -69,13 +69,16 @@
|
||
|
|
# define offsetof(TYPE, MEMBER) ((ulong)&((TYPE *)0)->MEMBER)
|
||
|
|
#endif
|
||
|
|
|
||
|
|
-#if !defined(X86) && !defined(X86_64) && !defined(ALPHA) && !defined(PPC) && \
|
||
|
|
+#if !defined(X86) && !defined(X86_64) && !defined(ALPHA) && !defined(SW_64) && !defined(PPC) && \
|
||
|
|
!defined(IA64) && !defined(PPC64) && !defined(S390) && !defined(S390X) && \
|
||
|
|
!defined(ARM) && !defined(ARM64) && !defined(MIPS) && !defined(MIPS64) && \
|
||
|
|
!defined(SPARC64)
|
||
|
|
#ifdef __alpha__
|
||
|
|
#define ALPHA
|
||
|
|
#endif
|
||
|
|
+#ifdef __sw_64__
|
||
|
|
+#define SW_64
|
||
|
|
+#endif
|
||
|
|
#ifdef __i386__
|
||
|
|
#define X86
|
||
|
|
#endif
|
||
|
|
@@ -122,6 +125,9 @@
|
||
|
|
#ifdef X86_64
|
||
|
|
#define NR_CPUS (8192)
|
||
|
|
#endif
|
||
|
|
+#ifdef SW_64
|
||
|
|
+#define NR_CPUS (64)
|
||
|
|
+#endif
|
||
|
|
#ifdef ALPHA
|
||
|
|
#define NR_CPUS (64)
|
||
|
|
#endif
|
||
|
|
@@ -3753,6 +3759,53 @@
|
||
|
|
|
||
|
|
#endif /* ALPHA */
|
||
|
|
|
||
|
|
+#ifdef SW_64
|
||
|
|
+#define _64BIT_
|
||
|
|
+#define MACHINE_TYPE "SW_64"
|
||
|
|
+
|
||
|
|
+#define PAGEBASE(X) (((unsigned long)(X)) & (unsigned long)machdep->pagemask)
|
||
|
|
+
|
||
|
|
+#define PTOV(X) ((unsigned long)(X)+(machdep->kvbase))
|
||
|
|
+#define VTOP(X) ((unsigned long)(X)-(machdep->kvbase))
|
||
|
|
+#define IS_VMALLOC_ADDR(X) (vt->vmalloc_start && (ulong)(X) >= vt->vmalloc_start)
|
||
|
|
+#define KSEG_BASE_48_BIT (0xffff800000000000)
|
||
|
|
+#define KSEG_BASE (0xfffffc0000000000)
|
||
|
|
+#define _PFN_MASK (0xFFFFFFFF00000000)
|
||
|
|
+#define VMALLOC_START (0xFFFFFE0000000000)
|
||
|
|
+#define MIN_SYMBOL_VALUE (KSEG_BASE_48_BIT)
|
||
|
|
+
|
||
|
|
+#define PGDIR_SHIFT (PAGESHIFT() + 2*(PAGESHIFT()-3))
|
||
|
|
+#define PMD_SHIFT (PAGESHIFT() + (PAGESHIFT()-3))
|
||
|
|
+#define PTRS_PER_PAGE (1024)
|
||
|
|
+
|
||
|
|
+#define PTRS_PER_PGD (1UL << (PAGESHIFT()-3))
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * OSF/1 PAL-code-imposed page table bits
|
||
|
|
+ */
|
||
|
|
+#define _PAGE_VALID 0x0001
|
||
|
|
+#define _PAGE_FOR 0x0002 /* used for page protection (fault on read) */
|
||
|
|
+#define _PAGE_FOW 0x0004 /* used for page protection (fault on write) */
|
||
|
|
+#define _PAGE_FOE 0x0008 /* used for page protection (fault on exec) */
|
||
|
|
+#define _PAGE_ASM 0x0010
|
||
|
|
+#define _PAGE_KRE 0x0400 /* xxx - see below on the "accessed" bit */
|
||
|
|
+#define _PAGE_URE 0x0800 /* xxx */
|
||
|
|
+#define _PAGE_KWE 0x4000 /* used to do the dirty bit in software */
|
||
|
|
+#define _PAGE_UWE 0x8000 /* used to do the dirty bit in software */
|
||
|
|
+
|
||
|
|
+/* .. and these are ours ... */
|
||
|
|
+#define _PAGE_DIRTY 0x20000
|
||
|
|
+#define _PAGE_ACCESSED 0x40000
|
||
|
|
+
|
||
|
|
+#define SWP_TYPE(entry) (((entry) >> 32) & 0xff)
|
||
|
|
+#define SWP_OFFSET(entry) ((entry) >> 40)
|
||
|
|
+#define __swp_type(entry) SWP_TYPE(entry)
|
||
|
|
+#define __swp_offset(entry) SWP_OFFSET(entry)
|
||
|
|
+
|
||
|
|
+#define TIF_SIGPENDING (2)
|
||
|
|
+
|
||
|
|
+#endif /* SW_64 */
|
||
|
|
+
|
||
|
|
#ifdef PPC
|
||
|
|
#define _32BIT_
|
||
|
|
#define MACHINE_TYPE "PPC"
|
||
|
|
@@ -4428,6 +4481,10 @@
|
||
|
|
#define MAX_HEXADDR_STRLEN (8)
|
||
|
|
#define UVADDR_PRLEN (8)
|
||
|
|
#endif
|
||
|
|
+#ifdef SW_64
|
||
|
|
+#define MAX_HEXADDR_STRLEN (16)
|
||
|
|
+#define UVADDR_PRLEN (11)
|
||
|
|
+#endif
|
||
|
|
#ifdef ALPHA
|
||
|
|
#define MAX_HEXADDR_STRLEN (16)
|
||
|
|
#define UVADDR_PRLEN (11)
|
||
|
|
@@ -4641,6 +4698,12 @@
|
||
|
|
#define SA_RESTORER 0x04000000
|
||
|
|
#endif
|
||
|
|
|
||
|
|
+#ifdef SW_64
|
||
|
|
+#define SA_PROBE SA_ONESHOT
|
||
|
|
+#define SA_SAMPLE_RANDOM SA_RESTART
|
||
|
|
+#define SA_SHIRQ 0x40000000
|
||
|
|
+#endif
|
||
|
|
+
|
||
|
|
#ifdef ALPHA
|
||
|
|
#define SA_PROBE SA_ONESHOT
|
||
|
|
#define SA_SAMPLE_RANDOM SA_RESTART
|
||
|
|
@@ -5020,6 +5083,9 @@
|
||
|
|
#ifdef X86
|
||
|
|
#define machdep_init(X) x86_init(X)
|
||
|
|
#endif
|
||
|
|
+#ifdef SW_64
|
||
|
|
+#define machdep_init(X) sw_64_init(X)
|
||
|
|
+#endif
|
||
|
|
#ifdef ALPHA
|
||
|
|
#define machdep_init(X) alpha_init(X)
|
||
|
|
#endif
|
||
|
|
@@ -5503,6 +5569,9 @@
|
||
|
|
#ifdef X86
|
||
|
|
#define dump_machdep_table(X) x86_dump_machdep_table(X)
|
||
|
|
#endif
|
||
|
|
+#ifdef SW_64
|
||
|
|
+#define dump_machdep_table(X) sw_64_dump_machdep_table(X)
|
||
|
|
+#endif
|
||
|
|
#ifdef ALPHA
|
||
|
|
#define dump_machdep_table(X) alpha_dump_machdep_table(X)
|
||
|
|
#endif
|
||
|
|
@@ -5909,6 +5978,19 @@
|
||
|
|
#endif
|
||
|
|
|
||
|
|
/*
|
||
|
|
+ * sw_64.c
|
||
|
|
+ */
|
||
|
|
+#ifdef SW_64
|
||
|
|
+void sw_64_init(int);
|
||
|
|
+void sw_64_dump_machdep_table(ulong);
|
||
|
|
+#define display_idt_table() \
|
||
|
|
+ error(FATAL, "-d option is not applicable to sw_64 architecture\n")
|
||
|
|
+
|
||
|
|
+#define HWRESET_TASK(X) ((machdep->flags & HWRESET) && is_task_active(X) && \
|
||
|
|
+ (task_to_context(X)->processor == 0))
|
||
|
|
+#endif
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
* alpha.c
|
||
|
|
*/
|
||
|
|
#ifdef ALPHA
|
||
|
|
diff -Nuar crash-7.3.0.org/gdb_interface.c crash-7.3.0.sw/gdb_interface.c
|
||
|
|
--- crash-7.3.0.org/gdb_interface.c 2022-03-14 07:58:52.288814120 +0000
|
||
|
|
+++ crash-7.3.0.sw/gdb_interface.c 2022-03-14 09:10:49.778814120 +0000
|
||
|
|
@@ -1053,7 +1053,7 @@
|
||
|
|
return TRUE;
|
||
|
|
}
|
||
|
|
|
||
|
|
-#ifndef ALPHA
|
||
|
|
+#if !defined ALPHA && !defined SW_64
|
||
|
|
/*
|
||
|
|
* Stub routine needed for resolution by non-alpha, modified gdb code.
|
||
|
|
*/
|
||
|
|
diff -Nuar crash-7.3.0.org/lkcd_v2_v3.c crash-7.3.0.sw/lkcd_v2_v3.c
|
||
|
|
--- crash-7.3.0.org/lkcd_v2_v3.c 2022-03-14 07:58:52.288814120 +0000
|
||
|
|
+++ crash-7.3.0.sw/lkcd_v2_v3.c 2022-03-24 07:10:23.603873440 +0000
|
||
|
|
@@ -336,7 +336,7 @@
|
||
|
|
lkcd_print(" dha_esp: %lx\n", dha->dha_esp);
|
||
|
|
lkcd_print(" dha_eip: %lx\n", dha->dha_eip);
|
||
|
|
#endif
|
||
|
|
-#if defined PPC || ALPHA || IA64
|
||
|
|
+#if defined PPC || ALPHA || SW_64 || IA64
|
||
|
|
/* TBD */
|
||
|
|
#endif
|
||
|
|
lkcd_print(" dha_regs:\n");
|
||
|
|
@@ -362,7 +362,38 @@
|
||
|
|
lkcd_print(" esp: %lx\n", dha->dha_regs.esp);
|
||
|
|
lkcd_print(" xss: %x\n", dha->dha_regs.xss);
|
||
|
|
#endif
|
||
|
|
-#ifdef ALPHA
|
||
|
|
+#if defined ALPHA
|
||
|
|
+ lkcd_print(" r0: %lx\n", dha->dha_regs.r0);
|
||
|
|
+ lkcd_print(" r1: %lx\n", dha->dha_regs.r1);
|
||
|
|
+ lkcd_print(" r2: %lx\n", dha->dha_regs.r2);
|
||
|
|
+ lkcd_print(" r3: %lx\n", dha->dha_regs.r3);
|
||
|
|
+ lkcd_print(" r4: %lx\n", dha->dha_regs.r4);
|
||
|
|
+ lkcd_print(" r5: %lx\n", dha->dha_regs.r5);
|
||
|
|
+ lkcd_print(" r6: %lx\n", dha->dha_regs.r6);
|
||
|
|
+ lkcd_print(" r7: %lx\n", dha->dha_regs.r7);
|
||
|
|
+ lkcd_print(" r8: %lx\n", dha->dha_regs.r8);
|
||
|
|
+ lkcd_print(" r19: %lx\n", dha->dha_regs.r19);
|
||
|
|
+ lkcd_print(" r20: %lx\n", dha->dha_regs.r20);
|
||
|
|
+ lkcd_print(" r21: %lx\n", dha->dha_regs.r21);
|
||
|
|
+ lkcd_print(" r22: %lx\n", dha->dha_regs.r22);
|
||
|
|
+ lkcd_print(" r23: %lx\n", dha->dha_regs.r23);
|
||
|
|
+ lkcd_print(" r24: %lx\n", dha->dha_regs.r24);
|
||
|
|
+ lkcd_print(" r25: %lx\n", dha->dha_regs.r25);
|
||
|
|
+ lkcd_print(" r26: %lx\n", dha->dha_regs.r26);
|
||
|
|
+ lkcd_print(" r27: %lx\n", dha->dha_regs.r27);
|
||
|
|
+ lkcd_print(" r28: %lx\n", dha->dha_regs.r28);
|
||
|
|
+ lkcd_print(" hae: %lx\n", dha->dha_regs.hae);
|
||
|
|
+ lkcd_print(" trap_a0: %lx\n", dha->dha_regs.trap_a0);
|
||
|
|
+ lkcd_print(" trap_a1: %lx\n", dha->dha_regs.trap_a1);
|
||
|
|
+ lkcd_print(" trap_a2: %lx\n", dha->dha_regs.trap_a2);
|
||
|
|
+ lkcd_print(" ps: %lx\n", dha->dha_regs.ps);
|
||
|
|
+ lkcd_print(" pc: %lx\n", dha->dha_regs.pc);
|
||
|
|
+ lkcd_print(" gp: %lx\n", dha->dha_regs.gp);
|
||
|
|
+ lkcd_print(" r16: %lx\n", dha->dha_regs.r16);
|
||
|
|
+ lkcd_print(" r17: %lx\n", dha->dha_regs.r17);
|
||
|
|
+ lkcd_print(" r18: %lx\n", dha->dha_regs.r18);
|
||
|
|
+#endif
|
||
|
|
+#if defined SW_64
|
||
|
|
lkcd_print(" r0: %lx\n", dha->dha_regs.r0);
|
||
|
|
lkcd_print(" r1: %lx\n", dha->dha_regs.r1);
|
||
|
|
lkcd_print(" r2: %lx\n", dha->dha_regs.r2);
|
||
|
|
diff -Nuar crash-7.3.0.org/lkcd_vmdump_v2_v3.h crash-7.3.0.sw/lkcd_vmdump_v2_v3.h
|
||
|
|
--- crash-7.3.0.org/lkcd_vmdump_v2_v3.h 2022-03-14 07:58:52.288814120 +0000
|
||
|
|
+++ crash-7.3.0.sw/lkcd_vmdump_v2_v3.h 2022-03-24 06:53:52.563873440 +0000
|
||
|
|
@@ -98,7 +98,7 @@
|
||
|
|
|
||
|
|
#endif /* ARM || X86 || PPC */
|
||
|
|
|
||
|
|
-#if defined(ALPHA) || defined(IA64) || defined(X86_64) || defined(PPC64)
|
||
|
|
+#if defined(ALPHA) || defined(SW_64) || defined(IA64) || defined(X86_64) || defined(PPC64)
|
||
|
|
|
||
|
|
/*
|
||
|
|
* Plug in the real ../arch/alpha/vmdump.h when available. For now the
|
||
|
|
diff -Nuar crash-7.3.0.org/sw_64.c crash-7.3.0.sw/sw_64.c
|
||
|
|
--- crash-7.3.0.org/sw_64.c 1970-01-01 00:00:00.000000000 +0000
|
||
|
|
+++ crash-7.3.0.sw/sw_64.c 2022-03-24 07:15:25.743873440 +0000
|
||
|
|
@@ -0,0 +1,2733 @@
|
||
|
|
+/* sw_64.c - core analysis suite
|
||
|
|
+ *
|
||
|
|
+ * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc.
|
||
|
|
+ * Copyright (C) 2002-2006, 2010-2013 David Anderson
|
||
|
|
+ * Copyright (C) 2002-2006, 2010-2013 Red Hat, Inc. All rights reserved.
|
||
|
|
+ *
|
||
|
|
+ * This program is free software; you can redistribute it and/or modify
|
||
|
|
+ * it under the terms of the GNU General Public License as published by
|
||
|
|
+ * the Free Software Foundation; either version 2 of the License, or
|
||
|
|
+ * (at your option) any later version.
|
||
|
|
+ *
|
||
|
|
+ * This program is distributed in the hope that it will be useful,
|
||
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
|
+ * GNU General Public License for more details.
|
||
|
|
+ *
|
||
|
|
+ */
|
||
|
|
+#ifdef SW_64
|
||
|
|
+#include "defs.h"
|
||
|
|
+
|
||
|
|
+static void sw_64_back_trace(struct gnu_request *, struct bt_info *);
|
||
|
|
+static int sw_64_trace_status(struct gnu_request *, struct bt_info *);
|
||
|
|
+static void sw_64_exception_frame(ulong, ulong,
|
||
|
|
+ struct gnu_request *, struct bt_info *);
|
||
|
|
+static void sw_64_frame_offset(struct gnu_request *, ulong);
|
||
|
|
+static int sw_64_backtrace_resync(struct gnu_request *, ulong,
|
||
|
|
+ struct bt_info *);
|
||
|
|
+static void sw_64_print_stack_entry(struct gnu_request *, ulong,
|
||
|
|
+ char *, ulong, struct bt_info *);
|
||
|
|
+static int sw_64_resync_speculate(struct gnu_request *, ulong,struct bt_info *);
|
||
|
|
+static int sw_64_dis_filter(ulong, char *, unsigned int);
|
||
|
|
+static void dis_address_translation(ulong, char *, unsigned int);
|
||
|
|
+static void sw_64_cmd_mach(void);
|
||
|
|
+static int sw_64_get_smp_cpus(void);
|
||
|
|
+static void sw_64_display_machine_stats(void);
|
||
|
|
+static void sw_64_dump_line_number(char *, ulong);
|
||
|
|
+static void display_hwrpb(unsigned int);
|
||
|
|
+static void sw_64_post_init(void);
|
||
|
|
+static struct line_number_hook sw_64_line_number_hooks[];
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+#define SW_64_CONTINUE_TRACE (1)
|
||
|
|
+#define SW_64_END_OF_TRACE (2)
|
||
|
|
+#define SW_64_EXCEPTION_FRAME (3)
|
||
|
|
+#define SW_64_SYSCALL_FRAME (4)
|
||
|
|
+#define SW_64_MM_FAULT (5)
|
||
|
|
+#define SW_64_INTERRUPT_PENDING (6)
|
||
|
|
+#define SW_64_RESCHEDULE (7)
|
||
|
|
+#define SW_64_DOWN_FAILED (8)
|
||
|
|
+#define SW_64_RET_FROM_SMP_FORK (9)
|
||
|
|
+#define SW_64_SIGNAL_RETURN (10)
|
||
|
|
+#define SW_64_STRACE (11)
|
||
|
|
+
|
||
|
|
+static int sw_64_eframe_search(struct bt_info *);
|
||
|
|
+static int sw_64_uvtop(struct task_context *, ulong, physaddr_t *, int);
|
||
|
|
+static int sw_64_kvtop(struct task_context *, ulong, physaddr_t *, int);
|
||
|
|
+static void sw_64_back_trace_cmd(struct bt_info *);
|
||
|
|
+static ulong sw_64_get_task_pgd(ulong task);
|
||
|
|
+static ulong sw_64_processor_speed(void);
|
||
|
|
+static void sw_64_dump_irq(int);
|
||
|
|
+static void sw_64_get_stack_frame(struct bt_info *, ulong *, ulong *);
|
||
|
|
+static void get_sw_64_frame(struct bt_info *, ulong *, ulong *);
|
||
|
|
+static int verify_user_eframe(struct bt_info *, ulong, ulong);
|
||
|
|
+static int sw_64_translate_pte(ulong, void *, ulonglong);
|
||
|
|
+static uint64_t sw_64_memory_size(void);
|
||
|
|
+static ulong sw_64_vmalloc_start(void);
|
||
|
|
+static int sw_64_is_task_addr(ulong);
|
||
|
|
+static int sw_64_verify_symbol(const char *, ulong, char);
|
||
|
|
+
|
||
|
|
+struct percpu_data {
|
||
|
|
+ ulong halt_PC;
|
||
|
|
+ ulong halt_ra;
|
||
|
|
+ ulong halt_pv;
|
||
|
|
+};
|
||
|
|
+#define GET_HALT_PC 0x1
|
||
|
|
+#define GET_HALT_RA 0x2
|
||
|
|
+#define GET_HALT_PV 0x3
|
||
|
|
+static ulong get_percpu_data(int, ulong, struct percpu_data *);
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * Do all necessary machine-specific setup here. This is called three times,
|
||
|
|
+ * before symbol table initialization, and before and after GDB has been
|
||
|
|
+ * initialized.
|
||
|
|
+ */
|
||
|
|
+void
|
||
|
|
+sw_64_init(int when)
|
||
|
|
+{
|
||
|
|
+ int tmp;
|
||
|
|
+
|
||
|
|
+ switch (when)
|
||
|
|
+ {
|
||
|
|
+ case PRE_SYMTAB:
|
||
|
|
+ machdep->verify_symbol = sw_64_verify_symbol;
|
||
|
|
+ if (pc->flags & KERNEL_DEBUG_QUERY)
|
||
|
|
+ return;
|
||
|
|
+ machdep->pagesize = memory_page_size();
|
||
|
|
+ machdep->pageshift = ffs(machdep->pagesize) - 1;
|
||
|
|
+ machdep->pageoffset = machdep->pagesize - 1;
|
||
|
|
+ machdep->pagemask = ~(machdep->pageoffset);
|
||
|
|
+ machdep->stacksize = machdep->pagesize * 2;
|
||
|
|
+ if ((machdep->pgd = (char *)malloc(PAGESIZE())) == NULL)
|
||
|
|
+ error(FATAL, "cannot malloc pgd space.");
|
||
|
|
+ if ((machdep->pmd = (char *)malloc(PAGESIZE())) == NULL)
|
||
|
|
+ error(FATAL, "cannot malloc pmd space.");
|
||
|
|
+ if ((machdep->ptbl = (char *)malloc(PAGESIZE())) == NULL)
|
||
|
|
+ error(FATAL, "cannot malloc ptbl space.");
|
||
|
|
+ machdep->last_pgd_read = 0;
|
||
|
|
+ machdep->last_pmd_read = 0;
|
||
|
|
+ machdep->last_ptbl_read = 0;
|
||
|
|
+ machdep->verify_paddr = generic_verify_paddr;
|
||
|
|
+ machdep->ptrs_per_pgd = PTRS_PER_PGD;
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ case PRE_GDB:
|
||
|
|
+ switch (symbol_value("_stext") & KSEG_BASE)
|
||
|
|
+ {
|
||
|
|
+ case KSEG_BASE:
|
||
|
|
+ machdep->kvbase = KSEG_BASE;
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ case KSEG_BASE_48_BIT:
|
||
|
|
+ machdep->kvbase = KSEG_BASE_48_BIT;
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ default:
|
||
|
|
+ error(FATAL,
|
||
|
|
+ "cannot determine KSEG base from _stext: %lx\n",
|
||
|
|
+ symbol_value("_stext"));
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ machdep->identity_map_base = machdep->kvbase;
|
||
|
|
+ machdep->is_kvaddr = generic_is_kvaddr;
|
||
|
|
+ machdep->is_uvaddr = generic_is_uvaddr;
|
||
|
|
+ machdep->eframe_search = sw_64_eframe_search;
|
||
|
|
+ machdep->back_trace = sw_64_back_trace_cmd;
|
||
|
|
+ machdep->processor_speed = sw_64_processor_speed;
|
||
|
|
+ machdep->uvtop = sw_64_uvtop;
|
||
|
|
+ machdep->kvtop = sw_64_kvtop;
|
||
|
|
+ machdep->get_task_pgd = sw_64_get_task_pgd;
|
||
|
|
+ if (symbol_exists("irq_desc"))
|
||
|
|
+ machdep->dump_irq = generic_dump_irq;
|
||
|
|
+ else
|
||
|
|
+ machdep->dump_irq = sw_64_dump_irq;
|
||
|
|
+ machdep->get_stack_frame = sw_64_get_stack_frame;
|
||
|
|
+ machdep->get_stackbase = generic_get_stackbase;
|
||
|
|
+ machdep->get_stacktop = generic_get_stacktop;
|
||
|
|
+ machdep->translate_pte = sw_64_translate_pte;
|
||
|
|
+ machdep->memory_size = sw_64_memory_size;
|
||
|
|
+ machdep->vmalloc_start = sw_64_vmalloc_start;
|
||
|
|
+ machdep->is_task_addr = sw_64_is_task_addr;
|
||
|
|
+ if (symbol_exists("console_crash")) {
|
||
|
|
+ get_symbol_data("console_crash", sizeof(int), &tmp);
|
||
|
|
+ if (tmp)
|
||
|
|
+ machdep->flags |= HWRESET;
|
||
|
|
+ }
|
||
|
|
+ machdep->dis_filter = sw_64_dis_filter;
|
||
|
|
+ machdep->cmd_mach = sw_64_cmd_mach;
|
||
|
|
+ machdep->get_smp_cpus = sw_64_get_smp_cpus;
|
||
|
|
+ machdep->line_number_hooks = sw_64_line_number_hooks;
|
||
|
|
+ machdep->value_to_symbol = generic_machdep_value_to_symbol;
|
||
|
|
+ machdep->init_kernel_pgd = NULL;
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ case POST_GDB:
|
||
|
|
+ MEMBER_OFFSET_INIT(thread_struct_ptbr,
|
||
|
|
+ "thread_struct", "ptbr");
|
||
|
|
+ MEMBER_OFFSET_INIT(hwrpb_struct_cycle_freq,
|
||
|
|
+ "hwrpb_struct", "cycle_freq");
|
||
|
|
+ MEMBER_OFFSET_INIT(hwrpb_struct_processor_offset,
|
||
|
|
+ "hwrpb_struct", "processor_offset");
|
||
|
|
+ MEMBER_OFFSET_INIT(hwrpb_struct_processor_size,
|
||
|
|
+ "hwrpb_struct", "processor_size");
|
||
|
|
+ MEMBER_OFFSET_INIT(percpu_struct_halt_PC,
|
||
|
|
+ "percpu_struct", "halt_PC");
|
||
|
|
+ MEMBER_OFFSET_INIT(percpu_struct_halt_ra,
|
||
|
|
+ "percpu_struct", "halt_ra");
|
||
|
|
+ MEMBER_OFFSET_INIT(percpu_struct_halt_pv,
|
||
|
|
+ "percpu_struct", "halt_pv");
|
||
|
|
+ MEMBER_OFFSET_INIT(switch_stack_r26,
|
||
|
|
+ "switch_stack", "r26");
|
||
|
|
+ if (symbol_exists("irq_action"))
|
||
|
|
+ ARRAY_LENGTH_INIT(machdep->nr_irqs, irq_action,
|
||
|
|
+ "irq_action", NULL, 0);
|
||
|
|
+ else if (symbol_exists("irq_desc"))
|
||
|
|
+ ARRAY_LENGTH_INIT(machdep->nr_irqs, irq_desc,
|
||
|
|
+ "irq_desc", NULL, 0);
|
||
|
|
+ else
|
||
|
|
+ machdep->nr_irqs = 0;
|
||
|
|
+ if (!machdep->hz)
|
||
|
|
+ machdep->hz = HZ;
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ case POST_INIT:
|
||
|
|
+ sw_64_post_init();
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * Unroll a kernel stack.
|
||
|
|
+ */
|
||
|
|
+static void
|
||
|
|
+sw_64_back_trace_cmd(struct bt_info *bt)
|
||
|
|
+{
|
||
|
|
+ char buf[BUFSIZE];
|
||
|
|
+ struct gnu_request *req;
|
||
|
|
+
|
||
|
|
+ bt->flags |= BT_EXCEPTION_FRAME;
|
||
|
|
+
|
||
|
|
+ if (CRASHDEBUG(1) || bt->debug)
|
||
|
|
+ fprintf(fp, " => PC: %lx (%s) FP: %lx \n",
|
||
|
|
+ bt->instptr, value_to_symstr(bt->instptr, buf, 0),
|
||
|
|
+ bt->stkptr );
|
||
|
|
+
|
||
|
|
+ req = (struct gnu_request *)GETBUF(sizeof(struct gnu_request));
|
||
|
|
+ req->command = GNU_STACK_TRACE;
|
||
|
|
+ req->flags = GNU_RETURN_ON_ERROR;
|
||
|
|
+ req->buf = GETBUF(BUFSIZE);
|
||
|
|
+ req->debug = bt->debug;
|
||
|
|
+ req->task = bt->task;
|
||
|
|
+
|
||
|
|
+ req->pc = bt->instptr;
|
||
|
|
+ req->sp = bt->stkptr;
|
||
|
|
+
|
||
|
|
+ if (bt->flags & BT_USE_GDB) {
|
||
|
|
+ strcpy(req->buf, "backtrace");
|
||
|
|
+ gdb_interface(req);
|
||
|
|
+ }
|
||
|
|
+ else
|
||
|
|
+ sw_64_back_trace(req, bt);
|
||
|
|
+
|
||
|
|
+ FREEBUF(req->buf);
|
||
|
|
+ FREEBUF(req);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * Unroll the kernel stack.
|
||
|
|
+ */
|
||
|
|
+
|
||
|
|
+#define SW_64_BACKTRACE_SPECULATE(X) \
|
||
|
|
+{ \
|
||
|
|
+ speculate_location = X; \
|
||
|
|
+ \
|
||
|
|
+ if (bt->flags & BT_SPECULATE) \
|
||
|
|
+ return; \
|
||
|
|
+ \
|
||
|
|
+ BZERO(btloc, sizeof(struct bt_info)); \
|
||
|
|
+ btloc->task = req->task; \
|
||
|
|
+ btloc->tc = bt->tc; \
|
||
|
|
+ btloc->stackbase = bt->stackbase; \
|
||
|
|
+ btloc->stacktop = bt->stacktop; \
|
||
|
|
+ btloc->flags = BT_TEXT_SYMBOLS_NOPRINT; \
|
||
|
|
+ hook.eip = 0; \
|
||
|
|
+ hook.esp = req->lastsp ? req->lastsp + sizeof(long) : 0; \
|
||
|
|
+ btloc->hp = &hook; \
|
||
|
|
+ \
|
||
|
|
+ back_trace(btloc); \
|
||
|
|
+ \
|
||
|
|
+ if (hook.esp && hook.eip) { \
|
||
|
|
+ req->hookp = &hook; \
|
||
|
|
+ if (sw_64_resync_speculate(req, bt->flags, bt)) { \
|
||
|
|
+ req->pc = hook.eip; \
|
||
|
|
+ req->sp = hook.esp; \
|
||
|
|
+ continue; \
|
||
|
|
+ } \
|
||
|
|
+ goto show_remaining_text; \
|
||
|
|
+ } \
|
||
|
|
+ goto show_remaining_text; \
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+static void
|
||
|
|
+sw_64_back_trace(struct gnu_request *req, struct bt_info *bt)
|
||
|
|
+{
|
||
|
|
+ char buf[BUFSIZE];
|
||
|
|
+ int frame;
|
||
|
|
+ int done;
|
||
|
|
+ int status;
|
||
|
|
+ struct stack_hook hook;
|
||
|
|
+ int eframe_same_pc_ra_function;
|
||
|
|
+ int speculate_location;
|
||
|
|
+ struct bt_info bt_info, *btloc;
|
||
|
|
+
|
||
|
|
+ frame = 0;
|
||
|
|
+ req->curframe = 0;
|
||
|
|
+ btloc = &bt_info;
|
||
|
|
+
|
||
|
|
+ if (!IS_KVADDR(req->pc)) {
|
||
|
|
+ if (BT_REFERENCE_CHECK(bt))
|
||
|
|
+ return;
|
||
|
|
+
|
||
|
|
+ if ((machdep->flags & HWRESET) && is_task_active(req->task)) {
|
||
|
|
+ fprintf(fp, "(hardware reset while in user space)\n");
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ fprintf(fp, "invalid pc: %lx\n", req->pc);
|
||
|
|
+
|
||
|
|
+ sw_64_exception_frame(USER_EFRAME_ADDR(req->task),
|
||
|
|
+ BT_USER_EFRAME, req, bt);
|
||
|
|
+
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+ for (done = FALSE; !done && (frame < 100); frame++) {
|
||
|
|
+
|
||
|
|
+ speculate_location = 0;
|
||
|
|
+
|
||
|
|
+ if ((req->name = closest_symbol(req->pc)) == NULL) {
|
||
|
|
+ req->ra = req->pc = 0;
|
||
|
|
+ if (sw_64_backtrace_resync(req,
|
||
|
|
+ bt->flags | BT_FROM_CALLFRAME, bt))
|
||
|
|
+ continue;
|
||
|
|
+
|
||
|
|
+ if (BT_REFERENCE_FOUND(bt))
|
||
|
|
+ return;
|
||
|
|
+
|
||
|
|
+ SW_64_BACKTRACE_SPECULATE(1);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (!INSTACK(req->sp, bt))
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ if (!is_kernel_text(req->pc))
|
||
|
|
+ SW_64_BACKTRACE_SPECULATE(2);
|
||
|
|
+
|
||
|
|
+ sw_64_print_stack_entry(req, req->pc, req->name,
|
||
|
|
+ bt->flags | BT_SAVE_LASTSP, bt);
|
||
|
|
+
|
||
|
|
+ if (BT_REFERENCE_FOUND(bt))
|
||
|
|
+ return;
|
||
|
|
+
|
||
|
|
+ switch (status = sw_64_trace_status(req, bt))
|
||
|
|
+ {
|
||
|
|
+ case SW_64_CONTINUE_TRACE:
|
||
|
|
+ sw_64_frame_offset(req, 0);
|
||
|
|
+ if (!req->value) {
|
||
|
|
+ done = TRUE;
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+ req->prevpc = req->pc;
|
||
|
|
+ req->pc = GET_STACK_ULONG(req->sp);
|
||
|
|
+ req->prevsp = req->sp;
|
||
|
|
+ req->sp += req->value;
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ case SW_64_END_OF_TRACE:
|
||
|
|
+ done = TRUE;
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ case SW_64_STRACE:
|
||
|
|
+ sw_64_exception_frame(req->sp,
|
||
|
|
+ BT_USER_EFRAME|BT_STRACE, req, bt);
|
||
|
|
+ done = TRUE;
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ case SW_64_RET_FROM_SMP_FORK:
|
||
|
|
+ sw_64_exception_frame(USER_EFRAME_ADDR(req->task),
|
||
|
|
+ BT_USER_EFRAME|BT_RET_FROM_SMP_FORK, req, bt);
|
||
|
|
+ done = TRUE;
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ case SW_64_DOWN_FAILED:
|
||
|
|
+ frame++;
|
||
|
|
+ sw_64_print_stack_entry(req,
|
||
|
|
+ req->pc, closest_symbol(req->pc),
|
||
|
|
+ bt->flags | BT_SAVE_LASTSP, bt);
|
||
|
|
+
|
||
|
|
+ if (BT_REFERENCE_FOUND(bt))
|
||
|
|
+ return;
|
||
|
|
+
|
||
|
|
+ sw_64_frame_offset(req, 0);
|
||
|
|
+ if (!req->value) {
|
||
|
|
+ done = TRUE;
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+ req->prevpc = req->pc;
|
||
|
|
+ req->pc = GET_STACK_ULONG(req->sp);
|
||
|
|
+ req->prevsp = req->sp;
|
||
|
|
+ req->sp += req->value;
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ case SW_64_RESCHEDULE:
|
||
|
|
+ sw_64_exception_frame(USER_EFRAME_ADDR(req->task),
|
||
|
|
+ BT_USER_EFRAME|BT_RESCHEDULE, req, bt);
|
||
|
|
+ done = TRUE;
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ case SW_64_MM_FAULT:
|
||
|
|
+ sw_64_exception_frame(req->sp, bt->flags, req, bt);
|
||
|
|
+
|
||
|
|
+ if (!IS_KVADDR(req->pc)) {
|
||
|
|
+ done = TRUE;
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ sw_64_frame_offset(req, 0);
|
||
|
|
+ if (!req->value) {
|
||
|
|
+ done = TRUE;
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ frame++;
|
||
|
|
+ sw_64_print_stack_entry(req,
|
||
|
|
+ req->pc, closest_symbol(req->pc),
|
||
|
|
+ bt->flags | BT_SAVE_LASTSP, bt);
|
||
|
|
+
|
||
|
|
+ if (BT_REFERENCE_FOUND(bt))
|
||
|
|
+ return;
|
||
|
|
+
|
||
|
|
+ if (!IS_KVADDR(req->pc)) {
|
||
|
|
+ done = TRUE;
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ req->prevpc = req->pc;
|
||
|
|
+ req->pc = GET_STACK_ULONG(req->sp);
|
||
|
|
+ req->prevsp = req->sp;
|
||
|
|
+ req->sp += req->value;
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ case SW_64_SYSCALL_FRAME:
|
||
|
|
+ req->sp = verify_user_eframe(bt, req->task, req->sp) ?
|
||
|
|
+ req->sp : USER_EFRAME_ADDR(req->task);
|
||
|
|
+
|
||
|
|
+ sw_64_exception_frame(req->sp, bt->flags, req, bt);
|
||
|
|
+
|
||
|
|
+ if (!IS_KVADDR(req->pc)) {
|
||
|
|
+ done = TRUE;
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ sw_64_frame_offset(req, 0);
|
||
|
|
+ if (!req->value) {
|
||
|
|
+ done = TRUE;
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+ req->prevpc = req->pc;
|
||
|
|
+ req->pc = GET_STACK_ULONG(req->sp);
|
||
|
|
+ req->prevsp = req->sp;
|
||
|
|
+ req->sp += req->value;
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ case SW_64_SIGNAL_RETURN:
|
||
|
|
+ sw_64_exception_frame(USER_EFRAME_ADDR(req->task),
|
||
|
|
+ bt->flags, req, bt);
|
||
|
|
+ done = TRUE;
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ case SW_64_EXCEPTION_FRAME:
|
||
|
|
+ sw_64_frame_offset(req, 0);
|
||
|
|
+ if (!req->value) {
|
||
|
|
+ fprintf(fp,
|
||
|
|
+ "SW_64 EXCEPTION FRAME w/no frame offset for %lx (%s)\n",
|
||
|
|
+ req->pc,
|
||
|
|
+ value_to_symstr(req->pc, buf, 0));
|
||
|
|
+ done = TRUE;
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ sw_64_exception_frame(req->sp + req->value,
|
||
|
|
+ bt->flags, req, bt);
|
||
|
|
+
|
||
|
|
+ if (!IS_KVADDR(req->pc)) {
|
||
|
|
+ done = TRUE;
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ sw_64_frame_offset(req, 0);
|
||
|
|
+
|
||
|
|
+ if (!req->value) {
|
||
|
|
+ fprintf(fp,
|
||
|
|
+ "SW_64 EXCEPTION FRAME w/no frame offset for %lx (%s)\n",
|
||
|
|
+ req->pc,
|
||
|
|
+ value_to_symstr(req->pc, buf, 0));
|
||
|
|
+ done = TRUE;
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ eframe_same_pc_ra_function =
|
||
|
|
+ SAME_FUNCTION(req->pc, req->ra);
|
||
|
|
+
|
||
|
|
+ frame++;
|
||
|
|
+ sw_64_print_stack_entry(req, req->pc,
|
||
|
|
+ closest_symbol(req->pc),
|
||
|
|
+ bt->flags | BT_SAVE_LASTSP, bt);
|
||
|
|
+
|
||
|
|
+ if (BT_REFERENCE_FOUND(bt))
|
||
|
|
+ return;
|
||
|
|
+
|
||
|
|
+ if (!IS_KVADDR(req->pc)) {
|
||
|
|
+ done = TRUE;
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (STREQ(closest_symbol(req->pc),
|
||
|
|
+ "ret_from_reschedule")) {
|
||
|
|
+ sw_64_exception_frame(
|
||
|
|
+ USER_EFRAME_ADDR(req->task),
|
||
|
|
+ BT_USER_EFRAME|BT_RESCHEDULE, req, bt);
|
||
|
|
+ done = TRUE;
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ req->prevpc = req->pc;
|
||
|
|
+ req->pc = GET_STACK_ULONG(req->sp);
|
||
|
|
+
|
||
|
|
+ if (!is_kernel_text(req->pc)) {
|
||
|
|
+ if (sw_64_backtrace_resync(req,
|
||
|
|
+ bt->flags | BT_FROM_EXCEPTION, bt))
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ if (BT_REFERENCE_FOUND(bt))
|
||
|
|
+ return;
|
||
|
|
+
|
||
|
|
+ SW_64_BACKTRACE_SPECULATE(3);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (!eframe_same_pc_ra_function &&
|
||
|
|
+ (req->pc != req->ra)) {
|
||
|
|
+ req->pc = req->ra;
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ req->prevsp = req->sp;
|
||
|
|
+ req->sp += req->value;
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ case SW_64_INTERRUPT_PENDING:
|
||
|
|
+ sw_64_frame_offset(req, 0);
|
||
|
|
+ if (!req->value) {
|
||
|
|
+ req->prevpc = req->pc;
|
||
|
|
+ req->pc = req->addr;
|
||
|
|
+ req->prevsp = req->sp;
|
||
|
|
+ req->sp = req->frame;
|
||
|
|
+ } else {
|
||
|
|
+ req->prevpc = req->pc;
|
||
|
|
+ req->pc = GET_STACK_ULONG(req->sp);
|
||
|
|
+ req->prevsp = req->sp;
|
||
|
|
+ req->sp += req->value;
|
||
|
|
+ }
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return;
|
||
|
|
+
|
||
|
|
+show_remaining_text:
|
||
|
|
+
|
||
|
|
+ if (BT_REFERENCE_CHECK(bt))
|
||
|
|
+ return;
|
||
|
|
+
|
||
|
|
+ BZERO(btloc, sizeof(struct bt_info));
|
||
|
|
+ btloc->task = req->task;
|
||
|
|
+ btloc->tc = bt->tc;
|
||
|
|
+ btloc->stackbase = bt->stackbase;
|
||
|
|
+ btloc->stacktop = bt->stacktop;
|
||
|
|
+ btloc->flags = BT_TEXT_SYMBOLS_NOPRINT;
|
||
|
|
+ hook.esp = req->lastsp + sizeof(long);
|
||
|
|
+ btloc->hp = &hook;
|
||
|
|
+ back_trace(btloc);
|
||
|
|
+
|
||
|
|
+ if (hook.eip) {
|
||
|
|
+ fprintf(fp,
|
||
|
|
+"NOTE: cannot resolve trace from this point -- remaining text symbols on stack:\n");
|
||
|
|
+ btloc->flags = BT_TEXT_SYMBOLS_PRINT|BT_ERROR_MASK;
|
||
|
|
+ hook.esp = req->lastsp + sizeof(long);
|
||
|
|
+ back_trace(btloc);
|
||
|
|
+ } else
|
||
|
|
+ fprintf(fp,
|
||
|
|
+"NOTE: cannot resolve trace from this point -- no remaining text symbols\n");
|
||
|
|
+
|
||
|
|
+ if (CRASHDEBUG(1))
|
||
|
|
+ fprintf(fp, "speculate_location: %d\n", speculate_location);
|
||
|
|
+
|
||
|
|
+ sw_64_exception_frame(USER_EFRAME_ADDR(req->task),
|
||
|
|
+ BT_USER_EFRAME, req, bt);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * print one entry of a stack trace
|
||
|
|
+ */
|
||
|
|
+static void
|
||
|
|
+sw_64_print_stack_entry(struct gnu_request *req,
|
||
|
|
+ ulong callpc,
|
||
|
|
+ char *name,
|
||
|
|
+ ulong flags,
|
||
|
|
+ struct bt_info *bt)
|
||
|
|
+{
|
||
|
|
+ struct load_module *lm;
|
||
|
|
+
|
||
|
|
+ if (BT_REFERENCE_CHECK(bt)) {
|
||
|
|
+ switch (bt->ref->cmdflags & (BT_REF_SYMBOL|BT_REF_HEXVAL))
|
||
|
|
+ {
|
||
|
|
+ case BT_REF_SYMBOL:
|
||
|
|
+ if (STREQ(name, bt->ref->str) ||
|
||
|
|
+ (STREQ(name, "strace") &&
|
||
|
|
+ STREQ(bt->ref->str, "entSys"))) {
|
||
|
|
+ bt->ref->cmdflags |= BT_REF_FOUND;
|
||
|
|
+ }
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ case BT_REF_HEXVAL:
|
||
|
|
+ if (bt->ref->hexval == callpc)
|
||
|
|
+ bt->ref->cmdflags |= BT_REF_FOUND;
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+ } else {
|
||
|
|
+ fprintf(fp, "%s#%d [%lx] %s at %lx",
|
||
|
|
+ req->curframe < 10 ? " " : "", req->curframe, req->sp,
|
||
|
|
+ STREQ(name, "strace") ? "strace (via entSys)" : name,
|
||
|
|
+ callpc);
|
||
|
|
+ if (module_symbol(callpc, NULL, &lm, NULL, 0))
|
||
|
|
+ fprintf(fp, " [%s]", lm->mod_name);
|
||
|
|
+ fprintf(fp, "\n");
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (!(flags & BT_SPECULATE))
|
||
|
|
+ req->curframe++;
|
||
|
|
+
|
||
|
|
+ if (flags & BT_SAVE_LASTSP)
|
||
|
|
+ req->lastsp = req->sp;
|
||
|
|
+
|
||
|
|
+ if (BT_REFERENCE_CHECK(bt))
|
||
|
|
+ return;
|
||
|
|
+
|
||
|
|
+ if (flags & BT_LINE_NUMBERS)
|
||
|
|
+ sw_64_dump_line_number(name, callpc);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+static const char *hook_files[] = {
|
||
|
|
+ "arch/sw_64/kernel/entry.S",
|
||
|
|
+ "arch/sw_64/kernel/head.S",
|
||
|
|
+ "init/main.c",
|
||
|
|
+ "arch/sw_64/kernel/smp.c",
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
+#define ENTRY_S ((char **)&hook_files[0])
|
||
|
|
+#define HEAD_S ((char **)&hook_files[1])
|
||
|
|
+#define MAIN_C ((char **)&hook_files[2])
|
||
|
|
+#define SMP_C ((char **)&hook_files[3])
|
||
|
|
+
|
||
|
|
+static struct line_number_hook sw_64_line_number_hooks[] = {
|
||
|
|
+ {"entInt", ENTRY_S},
|
||
|
|
+ {"entMM", ENTRY_S},
|
||
|
|
+ {"entArith", ENTRY_S},
|
||
|
|
+ {"entIF", ENTRY_S},
|
||
|
|
+ {"entDbg", ENTRY_S},
|
||
|
|
+ {"kernel_clone", ENTRY_S},
|
||
|
|
+ {"kernel_thread", ENTRY_S},
|
||
|
|
+ {"__kernel_execve", ENTRY_S},
|
||
|
|
+ {"do_switch_stack", ENTRY_S},
|
||
|
|
+ {"undo_switch_stack", ENTRY_S},
|
||
|
|
+ {"entUna", ENTRY_S},
|
||
|
|
+ {"entUnaUser", ENTRY_S},
|
||
|
|
+ {"sys_fork", ENTRY_S},
|
||
|
|
+ {"sys_clone", ENTRY_S},
|
||
|
|
+ {"sys_vfork", ENTRY_S},
|
||
|
|
+ {"sw_64_switch_to", ENTRY_S},
|
||
|
|
+ {"entSys", ENTRY_S},
|
||
|
|
+ {"ret_from_sys_call", ENTRY_S},
|
||
|
|
+ {"ret_from_reschedule", ENTRY_S},
|
||
|
|
+ {"restore_all", ENTRY_S},
|
||
|
|
+ {"strace", ENTRY_S},
|
||
|
|
+ {"strace_success", ENTRY_S},
|
||
|
|
+ {"strace_error", ENTRY_S},
|
||
|
|
+ {"syscall_error", ENTRY_S},
|
||
|
|
+ {"ret_success", ENTRY_S},
|
||
|
|
+ {"signal_return", ENTRY_S},
|
||
|
|
+ {"ret_from_fork", ENTRY_S},
|
||
|
|
+ {"reschedule", ENTRY_S},
|
||
|
|
+ {"sys_sigreturn", ENTRY_S},
|
||
|
|
+ {"sys_rt_sigreturn", ENTRY_S},
|
||
|
|
+ {"sys_sigsuspend", ENTRY_S},
|
||
|
|
+ {"sys_rt_sigsuspend", ENTRY_S},
|
||
|
|
+ {"ret_from_smpfork", ENTRY_S},
|
||
|
|
+
|
||
|
|
+ {"_stext", HEAD_S},
|
||
|
|
+ {"__start", HEAD_S},
|
||
|
|
+ {"__smp_callin", HEAD_S},
|
||
|
|
+ {"cserve_ena", HEAD_S},
|
||
|
|
+ {"cserve_dis", HEAD_S},
|
||
|
|
+ {"halt", HEAD_S},
|
||
|
|
+
|
||
|
|
+ {"start_kernel", MAIN_C},
|
||
|
|
+
|
||
|
|
+ {"smp_callin", SMP_C},
|
||
|
|
+
|
||
|
|
+ {NULL, NULL} /* list must be NULL-terminated */
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
+static void
|
||
|
|
+sw_64_dump_line_number(char *name, ulong callpc)
|
||
|
|
+{
|
||
|
|
+ char buf[BUFSIZE], *p;
|
||
|
|
+ int retries;
|
||
|
|
+
|
||
|
|
+ retries = 0;
|
||
|
|
+try_closest:
|
||
|
|
+ get_line_number(callpc, buf, FALSE);
|
||
|
|
+ if (strlen(buf)) {
|
||
|
|
+ if (retries) {
|
||
|
|
+ p = strstr(buf, ": ");
|
||
|
|
+ if (p)
|
||
|
|
+ *p = NULLCHAR;
|
||
|
|
+ }
|
||
|
|
+ fprintf(fp, " %s\n", buf);
|
||
|
|
+ } else {
|
||
|
|
+ if (retries)
|
||
|
|
+ fprintf(fp, GDB_PATCHED() ?
|
||
|
|
+ "" : " (cannot determine file and line number)\n");
|
||
|
|
+ else {
|
||
|
|
+ retries++;
|
||
|
|
+ callpc = closest_symbol_value(callpc);
|
||
|
|
+ goto try_closest;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * Look for the frame size storage at the beginning of a function.
|
||
|
|
+ * If it's not obvious, try gdb.
|
||
|
|
+ *
|
||
|
|
+ * For future reference, here's where the numbers come from:
|
||
|
|
+ *
|
||
|
|
+ * 0xfffffc00003217e8 <schedule+8>: subq sp,0x50,sp
|
||
|
|
+ * fffffc00003217e8: 43ca153e
|
||
|
|
+ * 010000 11110 01010000 1 0101001 11110
|
||
|
|
+ *
|
||
|
|
+ * 0xfffffc0000321668 <schedule_timeout+8>: subq sp,0x60,sp
|
||
|
|
+ * fffffc0000321668: 43cc153e
|
||
|
|
+ * 010000 11110 01100000 1 0101001 11110
|
||
|
|
+ *
|
||
|
|
+ * 0xfffffc000035d028 <do_select+8>: subq sp,0x70,sp
|
||
|
|
+ * fffffc000035d028: 43ce153e
|
||
|
|
+ * 010000 11110 01110000 1 0101001 11110
|
||
|
|
+ *
|
||
|
|
+ * 0100 0011 110x xxxx xxx1 0101 0011 1110
|
||
|
|
+ * 1111 1111 111x xxxx xxx1 1111 1111 1111
|
||
|
|
+ * 0000 0000 0001 1111 1110 0000 0000 0000
|
||
|
|
+ * f f e 0 1 f f f instruction mask
|
||
|
|
+ * 0 0 1 f e 0 0 0 offset
|
||
|
|
+ *
|
||
|
|
+ * stq ra,0(sp)
|
||
|
|
+ * fffffc000035d034: b75e0000
|
||
|
|
+ */
|
||
|
|
+
|
||
|
|
+static void
|
||
|
|
+sw_64_frame_offset(struct gnu_request *req, ulong alt_pc)
|
||
|
|
+{
|
||
|
|
+ uint *ip, ival;
|
||
|
|
+ ulong value;
|
||
|
|
+
|
||
|
|
+ req->value = value = 0;
|
||
|
|
+
|
||
|
|
+ if (alt_pc && !is_kernel_text(alt_pc))
|
||
|
|
+ error(FATAL,
|
||
|
|
+ "trying to get frame offset of non-text address: %lx\n",
|
||
|
|
+ alt_pc);
|
||
|
|
+ else if (!alt_pc && !is_kernel_text(req->pc))
|
||
|
|
+ error(FATAL,
|
||
|
|
+ "trying to get frame offset of non-text address: %lx\n",
|
||
|
|
+ req->pc);
|
||
|
|
+
|
||
|
|
+ ip = alt_pc ? (int *)closest_symbol_value(alt_pc) :
|
||
|
|
+ (int *)closest_symbol_value(req->pc);
|
||
|
|
+ if (!ip)
|
||
|
|
+ goto use_gdb;
|
||
|
|
+
|
||
|
|
+ ival = 0;
|
||
|
|
+
|
||
|
|
+ /*
|
||
|
|
+ * Don't go any farther than "stq ra,0(sp)" (0xb75e0000)
|
||
|
|
+ */
|
||
|
|
+ while (ival != 0xb75e0000) {
|
||
|
|
+ if (!text_value_cache((ulong)ip, 0, &ival)) {
|
||
|
|
+ readmem((ulong)ip, KVADDR, &ival,
|
||
|
|
+ sizeof(uint), "uncached text value",
|
||
|
|
+ FAULT_ON_ERROR);
|
||
|
|
+ text_value_cache((ulong)ip, ival, NULL);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if ((ival & 0xffe01fff) == 0x43c0153e) {
|
||
|
|
+ value = (ival & 0x1fe000) >> 13;
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+ ip++;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (value) {
|
||
|
|
+ req->value = value;
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+use_gdb:
|
||
|
|
+#ifndef GDB_5_3
|
||
|
|
+{
|
||
|
|
+ static int gdb_frame_offset_warnings = 10;
|
||
|
|
+
|
||
|
|
+ if (gdb_frame_offset_warnings-- > 0)
|
||
|
|
+ error(WARNING,
|
||
|
|
+ "GNU_ALPHA_FRAME_OFFSET functionality not ported to gdb\n");
|
||
|
|
+}
|
||
|
|
+#endif
|
||
|
|
+ req->command = GNU_ALPHA_FRAME_OFFSET;
|
||
|
|
+ if (alt_pc) {
|
||
|
|
+ ulong pc_save;
|
||
|
|
+ pc_save = req->pc;
|
||
|
|
+ req->pc = alt_pc;
|
||
|
|
+ gdb_interface(req);
|
||
|
|
+ req->pc = pc_save;
|
||
|
|
+ } else
|
||
|
|
+ gdb_interface(req);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * Look for key routines that either mean the trace has ended or has
|
||
|
|
+ * bumped into an exception frame.
|
||
|
|
+ */
|
||
|
|
+int
|
||
|
|
+sw_64_trace_status(struct gnu_request *req, struct bt_info *bt)
|
||
|
|
+{
|
||
|
|
+ ulong value;
|
||
|
|
+ char *func;
|
||
|
|
+ ulong frame;
|
||
|
|
+
|
||
|
|
+ req->addr = 0;
|
||
|
|
+ func = req->name;
|
||
|
|
+ frame = req->sp;
|
||
|
|
+
|
||
|
|
+ if (STREQ(func, "start_kernel") ||
|
||
|
|
+ STREQ(func, "smp_callin") ||
|
||
|
|
+ STREQ(func, "kernel_thread") ||
|
||
|
|
+ STREQ(func, "__kernel_thread"))
|
||
|
|
+ return SW_64_END_OF_TRACE;
|
||
|
|
+
|
||
|
|
+ if (STREQ(func, "ret_from_smp_fork") ||
|
||
|
|
+ STREQ(func, "ret_from_smpfork"))
|
||
|
|
+ return SW_64_RET_FROM_SMP_FORK;
|
||
|
|
+
|
||
|
|
+ if (STREQ(func, "entSys"))
|
||
|
|
+ return SW_64_SYSCALL_FRAME;
|
||
|
|
+
|
||
|
|
+ if (STREQ(func, "entMM")) {
|
||
|
|
+ req->sp += 56; /* see entMM in entry.S */
|
||
|
|
+ return SW_64_MM_FAULT;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (STREQ(func, "do_entInt"))
|
||
|
|
+ return SW_64_EXCEPTION_FRAME;
|
||
|
|
+
|
||
|
|
+ if (STREQ(func, "do_entArith"))
|
||
|
|
+ return SW_64_EXCEPTION_FRAME;
|
||
|
|
+
|
||
|
|
+ if (STREQ(func, "do_entIF"))
|
||
|
|
+ return SW_64_EXCEPTION_FRAME;
|
||
|
|
+
|
||
|
|
+ if (STREQ(func, "do_entDbg"))
|
||
|
|
+ return SW_64_EXCEPTION_FRAME;
|
||
|
|
+
|
||
|
|
+ if (STREQ(func, "handle_bottom_half"))
|
||
|
|
+ return SW_64_EXCEPTION_FRAME;
|
||
|
|
+
|
||
|
|
+ if (STREQ(func, "handle_softirq"))
|
||
|
|
+ return SW_64_EXCEPTION_FRAME;
|
||
|
|
+
|
||
|
|
+ if (STREQ(func, "reschedule"))
|
||
|
|
+ return SW_64_RESCHEDULE;
|
||
|
|
+
|
||
|
|
+ if (STREQ(func, "ret_from_reschedule"))
|
||
|
|
+ return SW_64_RESCHEDULE;
|
||
|
|
+
|
||
|
|
+ if (STREQ(func, "signal_return"))
|
||
|
|
+ return SW_64_SIGNAL_RETURN;
|
||
|
|
+
|
||
|
|
+ if (STREQ(func, "strace"))
|
||
|
|
+ return SW_64_STRACE;
|
||
|
|
+
|
||
|
|
+ if (STREQ(func, "__down_failed") ||
|
||
|
|
+ STREQ(func, "__down_failed_interruptible")) {
|
||
|
|
+ readmem(req->sp + 144, KVADDR, &req->pc, sizeof(ulong),
|
||
|
|
+ "__down_failed r26", FAULT_ON_ERROR);
|
||
|
|
+ req->sp += 160;
|
||
|
|
+ return SW_64_DOWN_FAILED;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ value = GET_STACK_ULONG(frame);
|
||
|
|
+
|
||
|
|
+ if (STREQ(closest_symbol(value), "do_entInt") ||
|
||
|
|
+ STREQ(closest_symbol(value), "do_entArith") ||
|
||
|
|
+ STREQ(closest_symbol(value), "do_entIF") ||
|
||
|
|
+ STREQ(closest_symbol(value), "do_entDbg")) {
|
||
|
|
+ req->addr = value;
|
||
|
|
+ req->frame = 0;
|
||
|
|
+
|
||
|
|
+ while (INSTACK(frame, bt)) {
|
||
|
|
+ frame += sizeof(ulong);
|
||
|
|
+ value = GET_STACK_ULONG(frame);
|
||
|
|
+ if (STREQ(closest_symbol(value), "ret_from_sys_call")) {
|
||
|
|
+ sw_64_frame_offset(req, req->addr);
|
||
|
|
+ /* req->frame = frame + req->value; XXX */
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ return SW_64_INTERRUPT_PENDING;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return SW_64_CONTINUE_TRACE;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * Redo the gdb pt_regs structure output.
|
||
|
|
+ */
|
||
|
|
+enum regnames { _r0_, _r1_, _r2_, _r3_, _r4_, _r5_, _r6_, _r7_, _r8_,
|
||
|
|
+ _r19_, _r20_, _r21_, _r22_, _r23_, _r24_, _r25_, _r26_,
|
||
|
|
+ _r27_, _r28_, _hae_, _trap_a0_, _trap_a1_, _trap_a2_,
|
||
|
|
+ _ps_, _pc_, _gp_, _r16_, _r17_, _r18_, NUMREGS};
|
||
|
|
+
|
||
|
|
+struct sw_64_eframe {
|
||
|
|
+ char regs[30][30];
|
||
|
|
+ ulong value[29];
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
+static void
|
||
|
|
+sw_64_exception_frame(ulong addr,
|
||
|
|
+ ulong flags,
|
||
|
|
+ struct gnu_request *req,
|
||
|
|
+ struct bt_info *bt)
|
||
|
|
+{
|
||
|
|
+ int i, j;
|
||
|
|
+ char buf[BUFSIZE];
|
||
|
|
+ ulong value;
|
||
|
|
+ physaddr_t paddr;
|
||
|
|
+ struct sw_64_eframe eframe;
|
||
|
|
+
|
||
|
|
+ if (CRASHDEBUG(4))
|
||
|
|
+ fprintf(fp, "sw_64_exception_frame: %lx\n", addr);
|
||
|
|
+
|
||
|
|
+ if (flags & BT_SPECULATE) {
|
||
|
|
+ req->pc = 0;
|
||
|
|
+ fprintf(fp, "SW_64 EXCEPTION FRAME\n");
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ BZERO(&eframe, sizeof(struct sw_64_eframe));
|
||
|
|
+
|
||
|
|
+ open_tmpfile();
|
||
|
|
+ dump_struct("pt_regs", addr, RADIX(16));
|
||
|
|
+ rewind(pc->tmpfile);
|
||
|
|
+ while (fgets(buf, BUFSIZE, pc->tmpfile)) {
|
||
|
|
+ strip_comma(clean_line(buf));
|
||
|
|
+ if (!strstr(buf, "0x"))
|
||
|
|
+ continue;
|
||
|
|
+
|
||
|
|
+ extract_hex(buf, &value, NULLCHAR, TRUE);
|
||
|
|
+ if (CRASHDEBUG(4))
|
||
|
|
+ fprintf(pc->saved_fp, "<%s> %lx\n", buf, value);
|
||
|
|
+
|
||
|
|
+ if (STRNEQ(buf, "r0 = ")) {
|
||
|
|
+ sprintf(eframe.regs[_r0_], " V0/R0: %016lx", value);
|
||
|
|
+ eframe.value[_r0_] = value;
|
||
|
|
+ }
|
||
|
|
+ if (STRNEQ(buf, "r1 = ")) {
|
||
|
|
+ sprintf(eframe.regs[_r1_], " T0/R1: %016lx", value);
|
||
|
|
+ eframe.value[_r1_] = value;
|
||
|
|
+ }
|
||
|
|
+ if (STRNEQ(buf, "r2 = ")) {
|
||
|
|
+ sprintf(eframe.regs[_r2_], " T1/R2: %016lx", value);
|
||
|
|
+ eframe.value[_r2_] = value;
|
||
|
|
+ }
|
||
|
|
+ if (STRNEQ(buf, "r3 = ")) {
|
||
|
|
+ sprintf(eframe.regs[_r3_], " T2/R3: %016lx", value);
|
||
|
|
+ eframe.value[_r3_] = value;
|
||
|
|
+ }
|
||
|
|
+ if (STRNEQ(buf, "r4 = ")) {
|
||
|
|
+ sprintf(eframe.regs[_r4_], " T3/R4: %016lx", value);
|
||
|
|
+ eframe.value[_r4_] = value;
|
||
|
|
+ }
|
||
|
|
+ if (STRNEQ(buf, "r5 = ")) {
|
||
|
|
+ sprintf(eframe.regs[_r5_], " T4/R5: %016lx", value);
|
||
|
|
+ eframe.value[_r5_] = value;
|
||
|
|
+ }
|
||
|
|
+ if (STRNEQ(buf, "r6 = ")) {
|
||
|
|
+ sprintf(eframe.regs[_r6_], " T5/R6: %016lx", value);
|
||
|
|
+ eframe.value[_r6_] = value;
|
||
|
|
+ }
|
||
|
|
+ if (STRNEQ(buf, "r7 = ")) {
|
||
|
|
+ sprintf(eframe.regs[_r7_], " T6/R7: %016lx", value);
|
||
|
|
+ eframe.value[_r7_] = value;
|
||
|
|
+ }
|
||
|
|
+ if (STRNEQ(buf, "r8 = ")) {
|
||
|
|
+ sprintf(eframe.regs[_r8_], " T7/R8: %016lx", value);
|
||
|
|
+ eframe.value[_r8_] = value;
|
||
|
|
+ }
|
||
|
|
+ if (STRNEQ(buf, "r19 = ")) {
|
||
|
|
+ sprintf(eframe.regs[_r19_], " A3/R19: %016lx", value);
|
||
|
|
+ eframe.value[_r19_] = value;
|
||
|
|
+ }
|
||
|
|
+ if (STRNEQ(buf, "r20 = ")) {
|
||
|
|
+ sprintf(eframe.regs[_r20_], " A4/R20: %016lx", value);
|
||
|
|
+ eframe.value[_r20_] = value;
|
||
|
|
+ }
|
||
|
|
+ if (STRNEQ(buf, "r21 = ")) {
|
||
|
|
+ sprintf(eframe.regs[_r21_], " A5/R21: %016lx", value);
|
||
|
|
+ eframe.value[_r21_] = value;
|
||
|
|
+ }
|
||
|
|
+ if (STRNEQ(buf, "r22 = ")) {
|
||
|
|
+ sprintf(eframe.regs[_r22_], " T8/R22: %016lx", value);
|
||
|
|
+ eframe.value[_r22_] = value;
|
||
|
|
+ }
|
||
|
|
+ if (STRNEQ(buf, "r23 = ")) {
|
||
|
|
+ sprintf(eframe.regs[_r23_], " T9/R23: %016lx", value);
|
||
|
|
+ eframe.value[_r23_] = value;
|
||
|
|
+ }
|
||
|
|
+ if (STRNEQ(buf, "r24 = ")) {
|
||
|
|
+ sprintf(eframe.regs[_r24_], "T10/R24: %016lx", value);
|
||
|
|
+ eframe.value[_r24_] = value;
|
||
|
|
+ }
|
||
|
|
+ if (STRNEQ(buf, "r25 = ")) {
|
||
|
|
+ sprintf(eframe.regs[_r25_], "T11/R25: %016lx", value);
|
||
|
|
+ eframe.value[_r25_] = value;
|
||
|
|
+ }
|
||
|
|
+ if (STRNEQ(buf, "r26 = ")) {
|
||
|
|
+ sprintf(eframe.regs[_r26_], " RA/R26: %016lx", value);
|
||
|
|
+ eframe.value[_r26_] = value;
|
||
|
|
+ }
|
||
|
|
+ if (STRNEQ(buf, "r27 = ")) {
|
||
|
|
+ sprintf(eframe.regs[_r27_], "T12/R27: %016lx", value);
|
||
|
|
+ eframe.value[_r27_] = value;
|
||
|
|
+ }
|
||
|
|
+ if (STRNEQ(buf, "r28 = ")) {
|
||
|
|
+ sprintf(eframe.regs[_r28_], " AT/R28: %016lx", value);
|
||
|
|
+ eframe.value[_r28_] = value;
|
||
|
|
+ }
|
||
|
|
+ if (STRNEQ(buf, "hae = ")) {
|
||
|
|
+ sprintf(eframe.regs[_hae_], " HAE: %016lx", value);
|
||
|
|
+ eframe.value[_hae_] = value;
|
||
|
|
+ }
|
||
|
|
+ if (STRNEQ(buf, "trap_a0 = ")) {
|
||
|
|
+ sprintf(eframe.regs[_trap_a0_], "TRAP_A0: %016lx",
|
||
|
|
+ value);
|
||
|
|
+ eframe.value[_trap_a0_] = value;
|
||
|
|
+ }
|
||
|
|
+ if (STRNEQ(buf, "trap_a1 = ")) {
|
||
|
|
+ sprintf(eframe.regs[_trap_a1_], "TRAP_A1: %016lx",
|
||
|
|
+ value);
|
||
|
|
+ eframe.value[_trap_a1_] = value;
|
||
|
|
+ }
|
||
|
|
+ if (STRNEQ(buf, "trap_a2 = ")) {
|
||
|
|
+ sprintf(eframe.regs[_trap_a2_], "TRAP_A2: %016lx",
|
||
|
|
+ value);
|
||
|
|
+ eframe.value[_trap_a2_] = value;
|
||
|
|
+ }
|
||
|
|
+ if (STRNEQ(buf, "ps = ")) {
|
||
|
|
+ sprintf(eframe.regs[_ps_], " PS: %016lx", value);
|
||
|
|
+ eframe.value[_ps_] = value;
|
||
|
|
+ }
|
||
|
|
+ if (STRNEQ(buf, "pc = ")) {
|
||
|
|
+ sprintf(eframe.regs[_pc_], " PC: %016lx", value);
|
||
|
|
+ eframe.value[_pc_] = value;
|
||
|
|
+ }
|
||
|
|
+ if (STRNEQ(buf, "gp = ")) {
|
||
|
|
+ sprintf(eframe.regs[_gp_], " GP/R29: %016lx", value);
|
||
|
|
+ eframe.value[_gp_] = value;
|
||
|
|
+ }
|
||
|
|
+ if (STRNEQ(buf, "r16 = ")) {
|
||
|
|
+ sprintf(eframe.regs[_r16_], " A0/R16: %016lx", value);
|
||
|
|
+ eframe.value[_r16_] = value;
|
||
|
|
+ }
|
||
|
|
+ if (STRNEQ(buf, "r17 = ")) {
|
||
|
|
+ sprintf(eframe.regs[_r17_], " A1/R17: %016lx", value);
|
||
|
|
+ eframe.value[_r17_] = value;
|
||
|
|
+ }
|
||
|
|
+ if (STRNEQ(buf, "r18 =")) {
|
||
|
|
+ sprintf(eframe.regs[_r18_], " A2/R18: %016lx", value);
|
||
|
|
+ eframe.value[_r18_] = value;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ close_tmpfile();
|
||
|
|
+
|
||
|
|
+ if ((flags & BT_EXCEPTION_FRAME) && !BT_REFERENCE_CHECK(bt)) {
|
||
|
|
+dump_eframe:
|
||
|
|
+ fprintf(fp, " EFRAME: %lx ", addr);
|
||
|
|
+ fprintf(fp, "%s\n", eframe.regs[_r24_]);
|
||
|
|
+
|
||
|
|
+ for (i = 0; i < (((NUMREGS+1)/2)-1); i++) {
|
||
|
|
+ fprintf(fp, "%s ", eframe.regs[i]);
|
||
|
|
+ pad_line(fp, 21 - strlen(eframe.regs[i]), ' ');
|
||
|
|
+ j = i+((NUMREGS+1)/2);
|
||
|
|
+ fprintf(fp, "%s", eframe.regs[j]);
|
||
|
|
+ if (((j == _pc_) || (j == _r26_)) &&
|
||
|
|
+ is_kernel_text(eframe.value[j]))
|
||
|
|
+ fprintf(fp, " <%s>",
|
||
|
|
+ value_to_symstr(eframe.value[j], buf, 0));
|
||
|
|
+ fprintf(fp, "\n");
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ req->ra = eframe.value[_r26_];
|
||
|
|
+ req->pc = eframe.value[_pc_];
|
||
|
|
+ req->sp = addr + (29 * sizeof(ulong));
|
||
|
|
+
|
||
|
|
+ if (flags & BT_USER_EFRAME) {
|
||
|
|
+ flags &= ~BT_USER_EFRAME;
|
||
|
|
+ if (!BT_REFERENCE_CHECK(bt) && (eframe.value[_ps_] == 8) &&
|
||
|
|
+ (((uvtop(task_to_context(req->task), req->pc, &paddr, 0) ||
|
||
|
|
+ (volatile ulong)paddr) &&
|
||
|
|
+ (uvtop(task_to_context(req->task), req->ra, &paddr, 0) ||
|
||
|
|
+ (volatile ulong)paddr)) ||
|
||
|
|
+ (IS_ZOMBIE(req->task) || IS_EXITING(req->task)))) {
|
||
|
|
+ if (!(flags &
|
||
|
|
+ (BT_RESCHEDULE|BT_RET_FROM_SMP_FORK|BT_STRACE)))
|
||
|
|
+ fprintf(fp,
|
||
|
|
+ "NOTE: kernel-entry exception frame:\n");
|
||
|
|
+ goto dump_eframe;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * Look for likely exception frames in a stack.
|
||
|
|
+ */
|
||
|
|
+struct sw_64_pt_regs {
|
||
|
|
+ ulong reg_value[NUMREGS];
|
||
|
|
+};
|
||
|
|
+
|
||
|
|
+static int
|
||
|
|
+sw_64_eframe_search(struct bt_info *bt)
|
||
|
|
+{
|
||
|
|
+ ulong *first, *last;
|
||
|
|
+ ulong eframe;
|
||
|
|
+ struct sw_64_pt_regs *pt;
|
||
|
|
+ struct gnu_request *req; /* needed for sw_64_exception_frame */
|
||
|
|
+ ulong *stack;
|
||
|
|
+ int cnt;
|
||
|
|
+
|
||
|
|
+ stack = (ulong *)bt->stackbuf;
|
||
|
|
+ req = (struct gnu_request *)GETBUF(sizeof(struct gnu_request));
|
||
|
|
+ req->task = bt->task;
|
||
|
|
+
|
||
|
|
+ first = stack +
|
||
|
|
+ (roundup(SIZE(task_struct), sizeof(ulong)) / sizeof(ulong));
|
||
|
|
+ last = stack +
|
||
|
|
+ (((bt->stacktop - bt->stackbase) - SIZE(pt_regs)) / sizeof(ulong));
|
||
|
|
+
|
||
|
|
+ for (cnt = 0; first <= last; first++) {
|
||
|
|
+ pt = (struct sw_64_pt_regs *)first;
|
||
|
|
+
|
||
|
|
+ /* check for kernel exception frame */
|
||
|
|
+
|
||
|
|
+ if (!(pt->reg_value[_ps_] & 0xfffffffffffffff8) &&
|
||
|
|
+ (is_kernel_text(pt->reg_value[_pc_]) ||
|
||
|
|
+ IS_MODULE_VADDR(pt->reg_value[_pc_])) &&
|
||
|
|
+ (is_kernel_text(pt->reg_value[_r26_]) ||
|
||
|
|
+ IS_MODULE_VADDR(pt->reg_value[_r26_])) &&
|
||
|
|
+ IS_KVADDR(pt->reg_value[_gp_])) {
|
||
|
|
+ cnt++;
|
||
|
|
+ if (bt->flags & BT_EFRAME_COUNT)
|
||
|
|
+ continue;
|
||
|
|
+ fprintf(fp, "\nKERNEL-MODE EXCEPTION FRAME:\n");
|
||
|
|
+ eframe = bt->task + ((ulong)first - (ulong)stack);
|
||
|
|
+ sw_64_exception_frame(eframe, BT_EXCEPTION_FRAME,
|
||
|
|
+ req, bt);
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /* check for user exception frame */
|
||
|
|
+
|
||
|
|
+ if ((pt->reg_value[_ps_] == 0x8) &&
|
||
|
|
+ ((IN_TASK_VMA(bt->task, pt->reg_value[_pc_]) &&
|
||
|
|
+ IN_TASK_VMA(bt->task, pt->reg_value[_r26_]) &&
|
||
|
|
+ IS_UVADDR(pt->reg_value[_gp_], bt->tc)) ||
|
||
|
|
+ ((first == last) &&
|
||
|
|
+ (IS_ZOMBIE(bt->task) || IS_EXITING(bt->task))))) {
|
||
|
|
+ cnt++;
|
||
|
|
+ if (bt->flags & BT_EFRAME_COUNT)
|
||
|
|
+ continue;
|
||
|
|
+ fprintf(fp, "\nUSER-MODE EXCEPTION FRAME:\n");
|
||
|
|
+ eframe = bt->task + ((ulong)first - (ulong)stack);
|
||
|
|
+ sw_64_exception_frame(eframe, BT_EXCEPTION_FRAME,
|
||
|
|
+ req, bt);
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ FREEBUF(req);
|
||
|
|
+
|
||
|
|
+ return cnt;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * Before dumping a nonsensical exception frame, give it a quick test.
|
||
|
|
+ */
|
||
|
|
+static int
|
||
|
|
+verify_user_eframe(struct bt_info *bt, ulong task, ulong sp)
|
||
|
|
+{
|
||
|
|
+ struct sw_64_pt_regs ptbuf, *pt;
|
||
|
|
+
|
||
|
|
+ readmem(sp, KVADDR, &ptbuf, sizeof(struct sw_64_pt_regs),
|
||
|
|
+ "pt_regs", FAULT_ON_ERROR);
|
||
|
|
+
|
||
|
|
+ pt = &ptbuf;
|
||
|
|
+
|
||
|
|
+ if ((pt->reg_value[_ps_] == 0x8) &&
|
||
|
|
+ ((IN_TASK_VMA(task, pt->reg_value[_pc_]) &&
|
||
|
|
+ IN_TASK_VMA(task, pt->reg_value[_r26_]) &&
|
||
|
|
+ IS_UVADDR(pt->reg_value[_gp_], bt->tc)) ||
|
||
|
|
+ ((pt == (struct sw_64_pt_regs *)USER_EFRAME_ADDR(task)) &&
|
||
|
|
+ (IS_ZOMBIE(task) || IS_EXITING(task))))) {
|
||
|
|
+ return TRUE;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return FALSE;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * Try to resync the stack location when there is no valid stack frame,
|
||
|
|
+ * typically just above an exception frame. Use the req->ra value from the
|
||
|
|
+ * exception frame as the new starting req->pc. Then walk up the stack until
|
||
|
|
+ * a text routine that calls the newly-assigned pc is found -- that stack
|
||
|
|
+ * location then becomes the new req->sp.
|
||
|
|
+ *
|
||
|
|
+ * If we're not coming from an exception frame, req-ra and req->pc will be
|
||
|
|
+ * purposely zeroed out. In that case, use the prevsp value to find the
|
||
|
|
+ * first pc that called the last frame's pc.
|
||
|
|
+ *
|
||
|
|
+ * Add any other repeatable "special-case" frames to the beginning of this
|
||
|
|
+ * routine (ex. debug_spin_lock). Last ditch -- at the end of this routine,
|
||
|
|
+ * speculate what might have happened (possibly in the background) -- and
|
||
|
|
+ * if it looks good, run with it.
|
||
|
|
+ */
|
||
|
|
+static int
|
||
|
|
+sw_64_backtrace_resync(struct gnu_request *req, ulong flags, struct bt_info *bt)
|
||
|
|
+{
|
||
|
|
+ char addr[BUFSIZE];
|
||
|
|
+ char buf[BUFSIZE];
|
||
|
|
+ char lookfor1[BUFSIZE];
|
||
|
|
+ char lookfor2[BUFSIZE];
|
||
|
|
+ ulong newpc;
|
||
|
|
+ ulong *stkp;
|
||
|
|
+ ulong *stkp_newpc, *stkp_next;
|
||
|
|
+ ulong value;
|
||
|
|
+ int found;
|
||
|
|
+ char *name;
|
||
|
|
+ int exception;
|
||
|
|
+
|
||
|
|
+ if (CRASHDEBUG(1))
|
||
|
|
+ fprintf(fp,
|
||
|
|
+ "RESYNC1: [%lx-%d] ra: %lx pc: %lx sp: %lx\n",
|
||
|
|
+ flags, req->curframe, req->ra, req->pc, req->sp);
|
||
|
|
+
|
||
|
|
+ if (!req->ra && !req->pc) {
|
||
|
|
+ req->ra = req->prevpc;
|
||
|
|
+ exception = FALSE;
|
||
|
|
+ } else
|
||
|
|
+ exception = TRUE;
|
||
|
|
+
|
||
|
|
+ if (!IS_KVADDR(req->ra))
|
||
|
|
+ return FALSE;
|
||
|
|
+
|
||
|
|
+ name = closest_symbol(req->ra);
|
||
|
|
+ sprintf(lookfor1, "<%s>", name);
|
||
|
|
+ sprintf(lookfor2, "<%s+", name);
|
||
|
|
+
|
||
|
|
+ if (CRASHDEBUG(1))
|
||
|
|
+ fprintf(fp, "RESYNC2: exception: %s lookfor: %s or %s\n",
|
||
|
|
+ exception ? "TRUE" : "FALSE",
|
||
|
|
+ lookfor1, lookfor2);
|
||
|
|
+
|
||
|
|
+ /*
|
||
|
|
+ * This is common when a non-panicking active CPU is spinning
|
||
|
|
+ * in debug_spin_lock(). The next pc is offset by 0x30 from
|
||
|
|
+ * the top of the exception frame, and the next sp is equal
|
||
|
|
+ * to the frame offset of debug_spin_lock(). I can't explain it...
|
||
|
|
+ */
|
||
|
|
+ if ((flags & BT_FROM_EXCEPTION) && STREQ(name, "debug_spin_lock")) {
|
||
|
|
+ sw_64_print_stack_entry(req, req->ra,
|
||
|
|
+ closest_symbol(req->ra), flags, bt);
|
||
|
|
+
|
||
|
|
+ if (BT_REFERENCE_FOUND(bt))
|
||
|
|
+ return FALSE;
|
||
|
|
+
|
||
|
|
+ sw_64_frame_offset(req, req->ra);
|
||
|
|
+ stkp = (ulong *)(req->sp + 0x30);
|
||
|
|
+ value = GET_STACK_ULONG(stkp);
|
||
|
|
+ if (!is_kernel_text(value)) {
|
||
|
|
+ req->sp = req->prevsp;
|
||
|
|
+ return FALSE;
|
||
|
|
+ }
|
||
|
|
+ req->pc = value;
|
||
|
|
+ req->sp += req->value;
|
||
|
|
+ return TRUE;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /*
|
||
|
|
+ * If the ra is a system call, then all we should have to do is
|
||
|
|
+ * find the next reference to entSys on the stack, and set the
|
||
|
|
+ * sp to that value.
|
||
|
|
+ */
|
||
|
|
+ if (is_system_call(name, 0)) {
|
||
|
|
+ /* stkp = (ulong *)req->sp; */
|
||
|
|
+ stkp = (ulong *)req->prevsp;
|
||
|
|
+
|
||
|
|
+ for (stkp++; INSTACK(stkp, bt); stkp++) {
|
||
|
|
+ value = GET_STACK_ULONG(stkp);
|
||
|
|
+
|
||
|
|
+ if (IS_KVADDR(value) && is_kernel_text(value)) {
|
||
|
|
+ if (STREQ(closest_symbol(value), "entSys")) {
|
||
|
|
+ req->pc = value;
|
||
|
|
+ req->sp = USER_EFRAME_ADDR(req->task);
|
||
|
|
+ return TRUE;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /*
|
||
|
|
+ * Just find the next location containing text. (?)
|
||
|
|
+ */
|
||
|
|
+ if (STREQ(name, "do_coredump")) {
|
||
|
|
+ stkp = (ulong *)(req->sp + sizeof(long));
|
||
|
|
+ for (stkp++; INSTACK(stkp, bt); stkp++) {
|
||
|
|
+ value = GET_STACK_ULONG(stkp);
|
||
|
|
+
|
||
|
|
+ if (IS_KVADDR(value) && is_kernel_text(value)) {
|
||
|
|
+ req->pc = req->ra;
|
||
|
|
+ req->sp = (ulong)stkp;
|
||
|
|
+ return TRUE;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (flags & BT_SPECULATE)
|
||
|
|
+ return FALSE;
|
||
|
|
+
|
||
|
|
+ if (CRASHDEBUG(1)) {
|
||
|
|
+ fprintf(fp, "RESYNC3: prevsp: %lx ra: %lx name: %s\n",
|
||
|
|
+ req->prevsp, req->ra, name);
|
||
|
|
+ fprintf(fp, "RESYNC3: prevpc: %lx\n", req->prevpc);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ stkp_newpc = stkp_next = 0;
|
||
|
|
+ newpc = 0;
|
||
|
|
+ found = FALSE;
|
||
|
|
+ if (exception) {
|
||
|
|
+ newpc = req->ra;
|
||
|
|
+ stkp = (ulong *)req->sp;
|
||
|
|
+ } else
|
||
|
|
+ stkp = (ulong *)req->prevsp;
|
||
|
|
+
|
||
|
|
+ if (CRASHDEBUG(1))
|
||
|
|
+ fprintf(fp, "RESYNC4: stkp: %lx newpc: %lx\n",
|
||
|
|
+ (ulong)stkp, newpc);
|
||
|
|
+
|
||
|
|
+ for (stkp++; INSTACK(stkp, bt); stkp++) {
|
||
|
|
+ value = GET_STACK_ULONG(stkp);
|
||
|
|
+ /*
|
||
|
|
+ * First find the new pc on the stack.
|
||
|
|
+ */
|
||
|
|
+ if (!found) {
|
||
|
|
+ if (!exception && is_kernel_text(value)) {
|
||
|
|
+ found = TRUE;
|
||
|
|
+ } else if (value == newpc) {
|
||
|
|
+ found = TRUE;
|
||
|
|
+ stkp_newpc = stkp;
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (!IS_KVADDR(value))
|
||
|
|
+ continue;
|
||
|
|
+
|
||
|
|
+ if (is_kernel_text(value)) {
|
||
|
|
+ if (!stkp_next)
|
||
|
|
+ stkp_next = stkp;
|
||
|
|
+ if (CRASHDEBUG(2)) {
|
||
|
|
+ fprintf(fp,
|
||
|
|
+ "RESYNC6: disassemble %lx (%s)\n",
|
||
|
|
+ value - sizeof(uint),
|
||
|
|
+ value_to_symstr(value - sizeof(uint),
|
||
|
|
+ buf, 0));
|
||
|
|
+ }
|
||
|
|
+ req->command = GNU_DISASSEMBLE;
|
||
|
|
+ req->addr = value - sizeof(uint);
|
||
|
|
+ sprintf(addr, "0x%lx", req->addr);
|
||
|
|
+ open_tmpfile();
|
||
|
|
+ req->fp = pc->tmpfile;
|
||
|
|
+ gdb_interface(req);
|
||
|
|
+ rewind(pc->tmpfile);
|
||
|
|
+ while (fgets(buf, BUFSIZE, pc->tmpfile)) {
|
||
|
|
+ clean_line(buf);
|
||
|
|
+ if (STRNEQ(buf, "Dump of") ||
|
||
|
|
+ STRNEQ(buf, "End of"))
|
||
|
|
+ continue;
|
||
|
|
+
|
||
|
|
+ if (STRNEQ(buf, addr)) {
|
||
|
|
+ if (LASTCHAR(buf) == ':') {
|
||
|
|
+ fgets(buf, BUFSIZE,
|
||
|
|
+ pc->tmpfile);
|
||
|
|
+ clean_line(buf);
|
||
|
|
+ }
|
||
|
|
+ if (CRASHDEBUG(2) &&
|
||
|
|
+ (strstr(buf, "jsr")
|
||
|
|
+ || strstr(buf, "bsr")))
|
||
|
|
+ fprintf(pc->saved_fp, "%s\n",
|
||
|
|
+ buf);
|
||
|
|
+ if ((strstr(buf, "jsr") ||
|
||
|
|
+ strstr(buf, "bsr")) &&
|
||
|
|
+ (strstr(buf, lookfor1) ||
|
||
|
|
+ strstr(buf, lookfor2))) {
|
||
|
|
+ if (exception) {
|
||
|
|
+ req->pc = newpc;
|
||
|
|
+ req->sp = (ulong)stkp;
|
||
|
|
+ } else
|
||
|
|
+ req->pc = req->addr;
|
||
|
|
+ close_tmpfile();
|
||
|
|
+ return TRUE;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ close_tmpfile();
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (CRASHDEBUG(1)) {
|
||
|
|
+ fprintf(fp, "RESYNC9: [%d] name: %s pc: %lx ra: %lx\n",
|
||
|
|
+ req->curframe, name, req->pc, req->ra);
|
||
|
|
+ fprintf(fp, "RESYNC9: sp: %lx lastsp: %lx\n",
|
||
|
|
+ req->sp, req->lastsp);
|
||
|
|
+ fprintf(fp, "RESYNC9: prevpc: %lx prevsp: %lx\n",
|
||
|
|
+ req->prevpc, req->prevsp);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /*
|
||
|
|
+ * At this point, all we can do is speculate based upon
|
||
|
|
+ * past experiences...
|
||
|
|
+ */
|
||
|
|
+ return (sw_64_resync_speculate(req, flags, bt));
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * Try one level of speculation. If it works, fine -- if not, give up.
|
||
|
|
+ */
|
||
|
|
+static int
|
||
|
|
+sw_64_resync_speculate(struct gnu_request *req, ulong flags, struct bt_info *bt)
|
||
|
|
+{
|
||
|
|
+ ulong *stkp;
|
||
|
|
+ ulong value;
|
||
|
|
+ ulong found_sp, found_ra;
|
||
|
|
+ struct stack_hook hook;
|
||
|
|
+ struct bt_info bt_info, *btloc;
|
||
|
|
+ char buf[BUFSIZE];
|
||
|
|
+ int kernel_thread;
|
||
|
|
+ int looks_good;
|
||
|
|
+
|
||
|
|
+ if (flags & BT_SPECULATE) /* already been here on this trace... */
|
||
|
|
+ return FALSE;
|
||
|
|
+
|
||
|
|
+ if (pc->tmpfile)
|
||
|
|
+ return FALSE;
|
||
|
|
+
|
||
|
|
+ found_ra = found_sp = 0;
|
||
|
|
+ kernel_thread = is_kernel_thread(req->task);
|
||
|
|
+
|
||
|
|
+ /*
|
||
|
|
+ * Add "known" possibilities here.
|
||
|
|
+ */
|
||
|
|
+ switch (flags & (BT_FROM_EXCEPTION|BT_FROM_CALLFRAME))
|
||
|
|
+ {
|
||
|
|
+ case BT_FROM_EXCEPTION:
|
||
|
|
+ if (STREQ(closest_symbol(req->prevpc), "read_lock") ||
|
||
|
|
+ STREQ(closest_symbol(req->ra), "do_select") ||
|
||
|
|
+ STREQ(closest_symbol(req->ra), "schedule")) {
|
||
|
|
+ stkp = (ulong *)req->sp;
|
||
|
|
+ for (stkp++; INSTACK(stkp, bt); stkp++) {
|
||
|
|
+ value = GET_STACK_ULONG(stkp);
|
||
|
|
+
|
||
|
|
+ if (found_ra) {
|
||
|
|
+ if (is_kernel_text_offset(value)) {
|
||
|
|
+ found_sp = (ulong)stkp;
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (value == req->ra)
|
||
|
|
+ found_ra = value;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ case BT_FROM_CALLFRAME:
|
||
|
|
+ if (STREQ(closest_symbol(req->ra), "sys_read")) {
|
||
|
|
+ value = GET_STACK_ULONG(req->prevsp - 32);
|
||
|
|
+ if (STREQ(closest_symbol(value), "entSys")) {
|
||
|
|
+ found_ra = value;
|
||
|
|
+ found_sp = req->prevsp - 32;
|
||
|
|
+ }
|
||
|
|
+ } else if (STREQ(closest_symbol(req->ra), "exit_autofs4_fs")) {
|
||
|
|
+ stkp = (ulong *)req->sp;
|
||
|
|
+ for (stkp++; INSTACK(stkp, bt); stkp++) {
|
||
|
|
+ value = GET_STACK_ULONG(stkp);
|
||
|
|
+
|
||
|
|
+ if (found_ra && (value != found_ra)) {
|
||
|
|
+ if (is_kernel_text_offset(value)) {
|
||
|
|
+ found_sp = (ulong)stkp;
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (is_kernel_text_offset(value))
|
||
|
|
+ found_ra = value;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ default:
|
||
|
|
+ if (req->hookp &&
|
||
|
|
+ STREQ(closest_symbol(req->prevpc), "filemap_nopage") &&
|
||
|
|
+ !STREQ(closest_symbol(req->hookp->eip), "do_no_page")) {
|
||
|
|
+ found_ra = found_sp = 0;
|
||
|
|
+ stkp = (ulong *)req->prevsp;
|
||
|
|
+ for (stkp++; INSTACK(stkp, bt); stkp++) {
|
||
|
|
+ value = GET_STACK_ULONG(stkp);
|
||
|
|
+
|
||
|
|
+ if (found_ra && (value != found_ra)) {
|
||
|
|
+ if (is_kernel_text_offset(value)) {
|
||
|
|
+ found_sp = (ulong)stkp;
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (is_kernel_text_offset(value) &&
|
||
|
|
+ STREQ(closest_symbol(value), "do_no_page"))
|
||
|
|
+ found_ra = value;
|
||
|
|
+ }
|
||
|
|
+ if (found_ra && found_sp) {
|
||
|
|
+ req->hookp->eip = found_ra;
|
||
|
|
+ req->hookp->esp = found_sp;
|
||
|
|
+ return TRUE;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (req->hookp) {
|
||
|
|
+ found_ra = req->hookp->eip;
|
||
|
|
+ found_sp = req->hookp->esp;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (found_ra && found_sp) {
|
||
|
|
+ looks_good = FALSE;
|
||
|
|
+ hook.esp = found_sp;
|
||
|
|
+ hook.eip = found_ra;
|
||
|
|
+
|
||
|
|
+ if (CRASHDEBUG(1))
|
||
|
|
+ fprintf(pc->saved_fp,
|
||
|
|
+ "----- RESYNC SPECULATE START -----\n");
|
||
|
|
+
|
||
|
|
+ open_tmpfile();
|
||
|
|
+ btloc = &bt_info;
|
||
|
|
+ BZERO(btloc, sizeof(struct bt_info));
|
||
|
|
+ btloc->task = req->task;
|
||
|
|
+ btloc->tc = bt->tc;
|
||
|
|
+ btloc->stackbase = bt->stackbase;
|
||
|
|
+ btloc->stacktop = bt->stacktop;
|
||
|
|
+ btloc->flags = BT_SPECULATE;
|
||
|
|
+ btloc->hp = &hook;
|
||
|
|
+ back_trace(btloc);
|
||
|
|
+ rewind(pc->tmpfile);
|
||
|
|
+ while (fgets(buf, BUFSIZE, pc->tmpfile)) {
|
||
|
|
+ if (CRASHDEBUG(1))
|
||
|
|
+ fprintf(pc->saved_fp, "%s", buf);
|
||
|
|
+
|
||
|
|
+ if (strstr(buf, "NOTE: cannot resolve")) {
|
||
|
|
+ looks_good = FALSE;
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (strstr(buf, "SW_64 EXCEPTION FRAME")) {
|
||
|
|
+ looks_good = TRUE;
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (kernel_thread) {
|
||
|
|
+ if (strstr(buf, " kernel_thread ") ||
|
||
|
|
+ strstr(buf, " __kernel_thread ") ||
|
||
|
|
+ strstr(buf, " start_kernel ") ||
|
||
|
|
+ strstr(buf, " smp_callin ")) {
|
||
|
|
+ looks_good = TRUE;
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ close_tmpfile();
|
||
|
|
+
|
||
|
|
+ if (CRASHDEBUG(1))
|
||
|
|
+ fprintf(pc->saved_fp,
|
||
|
|
+ "----- RESYNC SPECULATE DONE ------\n");
|
||
|
|
+
|
||
|
|
+ if (looks_good) {
|
||
|
|
+ req->pc = found_ra;
|
||
|
|
+ req->sp = found_sp;
|
||
|
|
+ return TRUE;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return FALSE;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * Translates a user virtual address to its physical address. cmd_vtop()
|
||
|
|
+ * sets the verbose flag so that the pte translation gets displayed; all
|
||
|
|
+ * other callers quietly accept the translation.
|
||
|
|
+ *
|
||
|
|
+ * This routine can also take mapped kernel virtual addresses if the -u flag
|
||
|
|
+ * was passed to cmd_vtop(). If so, it makes the translation using the
|
||
|
|
+ * kernel-memory PGD entry instead of swapper_pg_dir.
|
||
|
|
+ */
|
||
|
|
+
|
||
|
|
+static int
|
||
|
|
+sw_64_uvtop(struct task_context *tc, ulong vaddr, physaddr_t *paddr, int verbose)
|
||
|
|
+{
|
||
|
|
+ ulong mm;
|
||
|
|
+ ulong *pgd;
|
||
|
|
+ ulong *page_dir;
|
||
|
|
+ ulong *page_middle;
|
||
|
|
+ ulong *page_table;
|
||
|
|
+ ulong pgd_pte;
|
||
|
|
+ ulong pmd_pte;
|
||
|
|
+ ulong pte;
|
||
|
|
+
|
||
|
|
+ if (!tc)
|
||
|
|
+ error(FATAL, "current context invalid\n");
|
||
|
|
+
|
||
|
|
+ *paddr = 0;
|
||
|
|
+
|
||
|
|
+ if (is_kernel_thread(tc->task) && IS_KVADDR(vaddr)) {
|
||
|
|
+ pgd = (ulong *)machdep->get_task_pgd(tc->task);
|
||
|
|
+ } else {
|
||
|
|
+ if (!tc->mm_struct)
|
||
|
|
+ pgd = (ulong *)machdep->get_task_pgd(tc->task);
|
||
|
|
+ else {
|
||
|
|
+ if ((mm = task_mm(tc->task, TRUE)))
|
||
|
|
+ pgd = ULONG_PTR(tt->mm_struct +
|
||
|
|
+ OFFSET(mm_struct_pgd));
|
||
|
|
+ else
|
||
|
|
+ readmem(tc->mm_struct + OFFSET(mm_struct_pgd),
|
||
|
|
+ KVADDR, &pgd, sizeof(long),
|
||
|
|
+ "mm_struct pgd", FAULT_ON_ERROR);
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (verbose)
|
||
|
|
+ fprintf(fp, "PAGE DIRECTORY: %lx\n", (ulong)pgd);
|
||
|
|
+
|
||
|
|
+ page_dir = pgd + ((vaddr >> PGDIR_SHIFT) & (PTRS_PER_PAGE - 1));
|
||
|
|
+
|
||
|
|
+ FILL_PGD(PAGEBASE(pgd), KVADDR, PAGESIZE());
|
||
|
|
+ pgd_pte = ULONG(machdep->pgd + PAGEOFFSET(page_dir));
|
||
|
|
+
|
||
|
|
+ if (verbose)
|
||
|
|
+ fprintf(fp, " PGD: %lx => %lx\n", (ulong)page_dir, pgd_pte);
|
||
|
|
+
|
||
|
|
+ if (!(pgd_pte & _PAGE_VALID))
|
||
|
|
+ goto no_upage;
|
||
|
|
+
|
||
|
|
+ page_middle = (ulong *)
|
||
|
|
+ (PTOV((pgd_pte & _PFN_MASK) >> (32-PAGESHIFT()))) +
|
||
|
|
+ ((vaddr >> PMD_SHIFT) & (PTRS_PER_PAGE - 1));
|
||
|
|
+
|
||
|
|
+ FILL_PMD(PAGEBASE(page_middle), KVADDR, PAGESIZE());
|
||
|
|
+ pmd_pte = ULONG(machdep->pmd + PAGEOFFSET(page_middle));
|
||
|
|
+
|
||
|
|
+ if (verbose)
|
||
|
|
+ fprintf(fp, " PMD: %lx => %lx\n", (ulong)page_middle, pmd_pte);
|
||
|
|
+
|
||
|
|
+ if (!(pmd_pte & _PAGE_VALID))
|
||
|
|
+ goto no_upage;
|
||
|
|
+
|
||
|
|
+ page_table = (ulong *)
|
||
|
|
+ (PTOV((pmd_pte & _PFN_MASK) >> (32-PAGESHIFT()))) +
|
||
|
|
+ (BTOP(vaddr) & (PTRS_PER_PAGE - 1));
|
||
|
|
+
|
||
|
|
+ FILL_PTBL(PAGEBASE(page_table), KVADDR, PAGESIZE());
|
||
|
|
+ pte = ULONG(machdep->ptbl + PAGEOFFSET(page_table));
|
||
|
|
+
|
||
|
|
+ if (verbose)
|
||
|
|
+ fprintf(fp, " PTE: %lx => %lx\n", (ulong)page_table, pte);
|
||
|
|
+
|
||
|
|
+ if (!(pte & (_PAGE_VALID))) {
|
||
|
|
+ *paddr = pte;
|
||
|
|
+ if (pte && verbose) {
|
||
|
|
+ fprintf(fp, "\n");
|
||
|
|
+ sw_64_translate_pte(pte, 0, 0);
|
||
|
|
+ }
|
||
|
|
+ goto no_upage;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ *paddr = ((pte & _PFN_MASK) >> (32-PAGESHIFT())) + PAGEOFFSET(vaddr);
|
||
|
|
+
|
||
|
|
+ if (verbose) {
|
||
|
|
+ fprintf(fp, " PAGE: %lx\n\n", PAGEBASE(*paddr));
|
||
|
|
+ sw_64_translate_pte(pte, 0, 0);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return TRUE;
|
||
|
|
+
|
||
|
|
+no_upage:
|
||
|
|
+ return FALSE;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * Translates a kernel virtual address to its physical address. cmd_vtop()
|
||
|
|
+ * sets the verbose flag so that the pte translation gets displayed; all
|
||
|
|
+ * other callers quietly accept the translation.
|
||
|
|
+ */
|
||
|
|
+
|
||
|
|
+static int
|
||
|
|
+sw_64_kvtop(struct task_context *tc, ulong kvaddr, physaddr_t *paddr, int verbose)
|
||
|
|
+{
|
||
|
|
+ ulong *pgd;
|
||
|
|
+ ulong *page_dir;
|
||
|
|
+ ulong *page_middle;
|
||
|
|
+ ulong *page_table;
|
||
|
|
+ ulong pgd_pte;
|
||
|
|
+ ulong pmd_pte;
|
||
|
|
+ ulong pte;
|
||
|
|
+
|
||
|
|
+ if (!IS_KVADDR(kvaddr))
|
||
|
|
+ return FALSE;
|
||
|
|
+
|
||
|
|
+ if (!vt->vmalloc_start) { /* presume KSEG this early */
|
||
|
|
+ *paddr = VTOP(kvaddr);
|
||
|
|
+ return TRUE;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (!IS_VMALLOC_ADDR(kvaddr)) {
|
||
|
|
+ *paddr = VTOP(kvaddr);
|
||
|
|
+ return TRUE;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ pgd = (ulong *)vt->kernel_pgd[0];
|
||
|
|
+
|
||
|
|
+ if (verbose)
|
||
|
|
+ fprintf(fp, "PAGE DIRECTORY: %lx\n", (ulong)pgd);
|
||
|
|
+
|
||
|
|
+ page_dir = pgd + ((kvaddr >> PGDIR_SHIFT) & (PTRS_PER_PAGE - 1));
|
||
|
|
+
|
||
|
|
+ FILL_PGD(PAGEBASE(pgd), KVADDR, PAGESIZE());
|
||
|
|
+ pgd_pte = ULONG(machdep->pgd + PAGEOFFSET(page_dir));
|
||
|
|
+
|
||
|
|
+ if (verbose)
|
||
|
|
+ fprintf(fp, " PGD: %lx => %lx\n", (ulong)page_dir, pgd_pte);
|
||
|
|
+
|
||
|
|
+ if (!(pgd_pte & _PAGE_VALID))
|
||
|
|
+ goto no_kpage;
|
||
|
|
+
|
||
|
|
+ page_middle = (ulong *)
|
||
|
|
+ (PTOV((pgd_pte & _PFN_MASK) >> (32-PAGESHIFT()))) +
|
||
|
|
+ ((kvaddr >> PMD_SHIFT) & (PTRS_PER_PAGE - 1));
|
||
|
|
+
|
||
|
|
+ FILL_PMD(PAGEBASE(page_middle), KVADDR, PAGESIZE());
|
||
|
|
+ pmd_pte = ULONG(machdep->pmd + PAGEOFFSET(page_middle));
|
||
|
|
+
|
||
|
|
+ if (verbose)
|
||
|
|
+ fprintf(fp, " PMD: %lx => %lx\n", (ulong)page_middle, pmd_pte);
|
||
|
|
+
|
||
|
|
+ if (!(pmd_pte & _PAGE_VALID))
|
||
|
|
+ goto no_kpage;
|
||
|
|
+
|
||
|
|
+ page_table = (ulong *)
|
||
|
|
+ (PTOV((pmd_pte & _PFN_MASK) >> (32-PAGESHIFT()))) +
|
||
|
|
+ (BTOP(kvaddr) & (PTRS_PER_PAGE - 1));
|
||
|
|
+
|
||
|
|
+ FILL_PTBL(PAGEBASE(page_table), KVADDR, PAGESIZE());
|
||
|
|
+ pte = ULONG(machdep->ptbl + PAGEOFFSET(page_table));
|
||
|
|
+
|
||
|
|
+ if (verbose)
|
||
|
|
+ fprintf(fp, " PTE: %lx => %lx\n", (ulong)page_table, pte);
|
||
|
|
+
|
||
|
|
+ if (!(pte & (_PAGE_VALID))) {
|
||
|
|
+ if (pte && verbose) {
|
||
|
|
+ fprintf(fp, "\n");
|
||
|
|
+ sw_64_translate_pte(pte, 0, 0);
|
||
|
|
+ }
|
||
|
|
+ goto no_kpage;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ *paddr = ((pte & _PFN_MASK) >> (32-PAGESHIFT())) + PAGEOFFSET(kvaddr);
|
||
|
|
+
|
||
|
|
+ if (verbose) {
|
||
|
|
+ fprintf(fp, " PAGE: %lx\n\n", PAGEBASE(*paddr));
|
||
|
|
+ sw_64_translate_pte(pte, 0, 0);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return TRUE;
|
||
|
|
+
|
||
|
|
+no_kpage:
|
||
|
|
+ return FALSE;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * Get the relevant page directory pointer from a task structure.
|
||
|
|
+ */
|
||
|
|
+static ulong
|
||
|
|
+sw_64_get_task_pgd(ulong task)
|
||
|
|
+{
|
||
|
|
+ long offset;
|
||
|
|
+ ulong ptbr;
|
||
|
|
+
|
||
|
|
+ offset = OFFSET_OPTION(task_struct_thread, task_struct_tss);
|
||
|
|
+
|
||
|
|
+ offset += OFFSET(thread_struct_ptbr);
|
||
|
|
+
|
||
|
|
+ readmem(task + offset, KVADDR, &ptbr,
|
||
|
|
+ sizeof(ulong), "task thread ptbr", FAULT_ON_ERROR);
|
||
|
|
+
|
||
|
|
+ return(PTOV(PTOB(ptbr)));
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * Calculate and return the speed of the processor.
|
||
|
|
+ */
|
||
|
|
+static ulong
|
||
|
|
+sw_64_processor_speed(void)
|
||
|
|
+{
|
||
|
|
+ ulong hwrpb;
|
||
|
|
+ long offset;
|
||
|
|
+ long cycle_freq;
|
||
|
|
+ ulong mhz;
|
||
|
|
+
|
||
|
|
+ if (machdep->mhz)
|
||
|
|
+ return machdep->mhz;
|
||
|
|
+
|
||
|
|
+ mhz = 0;
|
||
|
|
+
|
||
|
|
+ get_symbol_data("hwrpb", sizeof(void *), &hwrpb);
|
||
|
|
+ offset = OFFSET(hwrpb_struct_cycle_freq);
|
||
|
|
+
|
||
|
|
+ if (!hwrpb || (offset == -1) ||
|
||
|
|
+ !readmem(hwrpb+offset, KVADDR, &cycle_freq,
|
||
|
|
+ sizeof(ulong), "hwrpb cycle_freq", RETURN_ON_ERROR))
|
||
|
|
+ return (machdep->mhz = mhz);
|
||
|
|
+
|
||
|
|
+ mhz = cycle_freq/1000000;
|
||
|
|
+
|
||
|
|
+ return (machdep->mhz = mhz);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+void
|
||
|
|
+sw_64_dump_machdep_table(ulong arg)
|
||
|
|
+{
|
||
|
|
+ int others;
|
||
|
|
+
|
||
|
|
+ others = 0;
|
||
|
|
+ fprintf(fp, " flags: %lx (", machdep->flags);
|
||
|
|
+ if (machdep->flags & HWRESET)
|
||
|
|
+ fprintf(fp, "%sHWRESET", others++ ? "|" : "");
|
||
|
|
+ fprintf(fp, ")\n");
|
||
|
|
+ fprintf(fp, " kvbase: %lx\n", machdep->kvbase);
|
||
|
|
+ fprintf(fp, " identity_map_base: %lx\n", machdep->identity_map_base);
|
||
|
|
+ fprintf(fp, " pagesize: %d\n", machdep->pagesize);
|
||
|
|
+ fprintf(fp, " pageshift: %d\n", machdep->pageshift);
|
||
|
|
+ fprintf(fp, " pagemask: %llx\n", machdep->pagemask);
|
||
|
|
+ fprintf(fp, " pageoffset: %lx\n", machdep->pageoffset);
|
||
|
|
+ fprintf(fp, " stacksize: %ld\n", machdep->stacksize);
|
||
|
|
+ fprintf(fp, " hz: %d\n", machdep->hz);
|
||
|
|
+ fprintf(fp, " mhz: %ld\n", machdep->mhz);
|
||
|
|
+ fprintf(fp, " memsize: %ld (0x%lx)\n",
|
||
|
|
+ machdep->memsize, machdep->memsize);
|
||
|
|
+ fprintf(fp, " bits: %d\n", machdep->bits);
|
||
|
|
+ fprintf(fp, " nr_irqs: %d\n", machdep->nr_irqs);
|
||
|
|
+ fprintf(fp, " eframe_search: sw_64_eframe_search()\n");
|
||
|
|
+ fprintf(fp, " back_trace: sw_64_back_trace_cmd()\n");
|
||
|
|
+ fprintf(fp, " processor_speed: sw_64_processor_speed()\n");
|
||
|
|
+ fprintf(fp, " uvtop: sw_64_uvtop()\n");
|
||
|
|
+ fprintf(fp, " kvtop: sw_64_uvtop()\n");
|
||
|
|
+ fprintf(fp, " get_task_pgd: sw_64_get_task_pgd()\n");
|
||
|
|
+ if (machdep->dump_irq == generic_dump_irq)
|
||
|
|
+ fprintf(fp, " dump_irq: generic_dump_irq()\n");
|
||
|
|
+ else
|
||
|
|
+ fprintf(fp, " dump_irq: sw_64_dump_irq()\n");
|
||
|
|
+ fprintf(fp, " get_stack_frame: sw_64_get_stack_frame()\n");
|
||
|
|
+ fprintf(fp, " get_stackbase: generic_get_stackbase()\n");
|
||
|
|
+ fprintf(fp, " get_stacktop: generic_get_stacktop()\n");
|
||
|
|
+ fprintf(fp, " translate_pte: sw_64_translate_pte()\n");
|
||
|
|
+ fprintf(fp, " memory_size: sw_64_get_memory_size()\n");
|
||
|
|
+ fprintf(fp, " vmalloc_start: sw_64_get_vmalloc_start()\n");
|
||
|
|
+ fprintf(fp, " is_task_addr: sw_64_is_task_addr()\n");
|
||
|
|
+ fprintf(fp, " verify_symbol: sw_64_verify_symbol()\n");
|
||
|
|
+ fprintf(fp, " dis_filter: sw_64_dis_filter()\n");
|
||
|
|
+ fprintf(fp, " cmd_mach: sw_64_cmd_mach()\n");
|
||
|
|
+ fprintf(fp, " get_smp_cpus: sw_64_get_smp_cpus()\n");
|
||
|
|
+ fprintf(fp, " is_kvaddr: generic_is_kvaddr()\n");
|
||
|
|
+ fprintf(fp, " is_uvaddr: generic_is_uvaddr()\n");
|
||
|
|
+ fprintf(fp, " verify_paddr: generic_verify_paddr()\n");
|
||
|
|
+ fprintf(fp, " init_kernel_pgd: NULL\n");
|
||
|
|
+ fprintf(fp, " value_to_symbol: generic_machdep_value_to_symbol()\n");
|
||
|
|
+ fprintf(fp, " line_number_hooks: sw_64_line_number_hooks\n");
|
||
|
|
+ fprintf(fp, " last_pgd_read: %lx\n", machdep->last_pgd_read);
|
||
|
|
+ fprintf(fp, " last_pmd_read: %lx\n", machdep->last_pmd_read);
|
||
|
|
+ fprintf(fp, " last_ptbl_read: %lx\n", machdep->last_ptbl_read);
|
||
|
|
+ fprintf(fp, " pgd: %lx\n", (ulong)machdep->pgd);
|
||
|
|
+ fprintf(fp, " pmd: %lx\n", (ulong)machdep->pmd);
|
||
|
|
+ fprintf(fp, " ptbl: %lx\n", (ulong)machdep->ptbl);
|
||
|
|
+ fprintf(fp, " ptrs_per_pgd: %d\n", machdep->ptrs_per_pgd);
|
||
|
|
+ fprintf(fp, " machspec: %lx\n", (ulong)machdep->machspec);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * Fix up jsr's to show the right target.
|
||
|
|
+ *
|
||
|
|
+ * If a value is passed with no buf, then cmd_dis is fishing for whether
|
||
|
|
+ * the GP can be calculated from the first couple of instructions of the
|
||
|
|
+ * target routine:
|
||
|
|
+ *
|
||
|
|
+ * 0xfffffc0000349fa0 <sys_read>: ldah gp,35(t12)
|
||
|
|
+ * 0xfffffc0000349fa4 <sys_read+4>: lda gp,6216(gp)
|
||
|
|
+ *
|
||
|
|
+ * If a buf pointer is passed, then check whether the t12 register
|
||
|
|
+ * is being set up as an offset from gp, then calculate the target address:
|
||
|
|
+ *
|
||
|
|
+ * 0xfffffc000042c364 <start_tty+228>: ldq t12,-29336(gp)
|
||
|
|
+ * 0xfffffc000042c368 <start_tty+232>:
|
||
|
|
+ * jsr ra,(t12),0xfffffc0000429dc0 <decr_console+96>
|
||
|
|
+ *
|
||
|
|
+ * If the next instruction is a jsr ra,(t12), then correct the bracketed
|
||
|
|
+ * target address translation.
|
||
|
|
+ *
|
||
|
|
+ */
|
||
|
|
+
|
||
|
|
+#define LDAH_GP_T12 (0x27bb0000)
|
||
|
|
+#define LDA_GP_GP (0x23bd0000)
|
||
|
|
+#define LDQ_T12_GP (0xa77d0000)
|
||
|
|
+#define JSR_RA_T12 (0x6b5b0000)
|
||
|
|
+
|
||
|
|
+#define OPCODE_OPERAND_MASK (0xffff0000)
|
||
|
|
+#define OPCODE_MEM_DISP_MASK (0x0000ffff)
|
||
|
|
+
|
||
|
|
+static struct instruction_data {
|
||
|
|
+ uint inst[2];
|
||
|
|
+ short mem_disp[2];
|
||
|
|
+ ulong gp;
|
||
|
|
+ ulong target;
|
||
|
|
+ char *curfunc;
|
||
|
|
+} instruction_data = { {0} };
|
||
|
|
+
|
||
|
|
+static int
|
||
|
|
+sw_64_dis_filter(ulong vaddr, char *buf, unsigned int output_radix)
|
||
|
|
+{
|
||
|
|
+ struct syment *sp;
|
||
|
|
+ struct instruction_data *id;
|
||
|
|
+ char buf2[BUFSIZE], *p1;
|
||
|
|
+
|
||
|
|
+ id = &instruction_data;
|
||
|
|
+
|
||
|
|
+ if (!buf) {
|
||
|
|
+ BZERO(id, sizeof(struct instruction_data));
|
||
|
|
+
|
||
|
|
+ if (!(sp = value_search(vaddr, NULL)))
|
||
|
|
+ return FALSE;
|
||
|
|
+
|
||
|
|
+ readmem(sp->value, KVADDR, &id->inst[0],
|
||
|
|
+ sizeof(uint) * 2, "two instructions", FAULT_ON_ERROR);
|
||
|
|
+
|
||
|
|
+ if (((id->inst[0] & OPCODE_OPERAND_MASK) == LDAH_GP_T12) &&
|
||
|
|
+ ((id->inst[1] & OPCODE_OPERAND_MASK) == LDA_GP_GP)) {
|
||
|
|
+ id->mem_disp[0] = (short)(id->inst[0] &
|
||
|
|
+ OPCODE_MEM_DISP_MASK);
|
||
|
|
+ id->mem_disp[1] = (short)(id->inst[1] &
|
||
|
|
+ OPCODE_MEM_DISP_MASK);
|
||
|
|
+ id->gp = sp->value + (65536*id->mem_disp[0]) +
|
||
|
|
+ id->mem_disp[1];
|
||
|
|
+ id->curfunc = sp->name;
|
||
|
|
+
|
||
|
|
+ if (CRASHDEBUG(1))
|
||
|
|
+ console("%s: ldah(%d) and lda(%d) gp: %lx\n",
|
||
|
|
+ id->curfunc,
|
||
|
|
+ id->mem_disp[0], id->mem_disp[1],
|
||
|
|
+ id->gp);
|
||
|
|
+
|
||
|
|
+ return TRUE;
|
||
|
|
+ }
|
||
|
|
+ /* send all lines through the generic */
|
||
|
|
+ return TRUE; /* dis_address_translation() filter */
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ dis_address_translation(vaddr, buf, output_radix);
|
||
|
|
+
|
||
|
|
+ if (!id->gp || !(sp = value_search(vaddr, NULL)) ||
|
||
|
|
+ !STREQ(id->curfunc, sp->name)) {
|
||
|
|
+ BZERO(id, sizeof(struct instruction_data));
|
||
|
|
+ return FALSE;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ readmem(vaddr, KVADDR, &id->inst[0],
|
||
|
|
+ sizeof(uint), "one instruction", FAULT_ON_ERROR);
|
||
|
|
+
|
||
|
|
+ if ((id->inst[0] & OPCODE_OPERAND_MASK) == JSR_RA_T12) {
|
||
|
|
+
|
||
|
|
+ if (!id->target || !strstr(buf, "jsr\tra,(t12)") ||
|
||
|
|
+ !strstr(buf, "<"))
|
||
|
|
+ return FALSE;
|
||
|
|
+
|
||
|
|
+ p1 = strstr(strstr(buf, "jsr"), "0x");
|
||
|
|
+ sprintf(p1, "0x%lx <%s>%s",
|
||
|
|
+ id->target,
|
||
|
|
+ value_to_symstr(id->target, buf2, output_radix),
|
||
|
|
+ CRASHDEBUG(1) ? " [PATCHED]\n" : "\n");
|
||
|
|
+ return TRUE;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if ((id->inst[0] & OPCODE_OPERAND_MASK) == LDQ_T12_GP) {
|
||
|
|
+ id->mem_disp[0] = (short)(id->inst[0] & OPCODE_MEM_DISP_MASK);
|
||
|
|
+ readmem(id->gp + id->mem_disp[0], KVADDR, &id->target,
|
||
|
|
+ sizeof(ulong), "jsr target", FAULT_ON_ERROR);
|
||
|
|
+ } else
|
||
|
|
+ id->target = 0;
|
||
|
|
+
|
||
|
|
+ return TRUE;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * For some reason gdb can go off into the weeds translating text addresses,
|
||
|
|
+ * so this routine both fixes the references as well as imposing the current
|
||
|
|
+ * output radix on the translations.
|
||
|
|
+ */
|
||
|
|
+static void
|
||
|
|
+dis_address_translation(ulong vaddr, char *inbuf, unsigned int output_radix)
|
||
|
|
+{
|
||
|
|
+ char buf1[BUFSIZE];
|
||
|
|
+ char buf2[BUFSIZE];
|
||
|
|
+ char *colon, *p1;
|
||
|
|
+ int argc;
|
||
|
|
+ char *argv[MAXARGS];
|
||
|
|
+ ulong value;
|
||
|
|
+
|
||
|
|
+ console("IN: %s", inbuf);
|
||
|
|
+
|
||
|
|
+ colon = strstr(inbuf, ":");
|
||
|
|
+
|
||
|
|
+ if (colon) {
|
||
|
|
+ sprintf(buf1, "0x%lx <%s>", vaddr,
|
||
|
|
+ value_to_symstr(vaddr, buf2, output_radix));
|
||
|
|
+ sprintf(buf2, "%s%s", buf1, colon);
|
||
|
|
+ strcpy(inbuf, buf2);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ strcpy(buf1, inbuf);
|
||
|
|
+ argc = parse_line(buf1, argv);
|
||
|
|
+
|
||
|
|
+ if ((FIRSTCHAR(argv[argc-1]) == '<') &&
|
||
|
|
+ (LASTCHAR(argv[argc-1]) == '>')) {
|
||
|
|
+ p1 = rindex(inbuf, '<');
|
||
|
|
+ while ((p1 > inbuf) && (*p1 != ','))
|
||
|
|
+ p1--;
|
||
|
|
+
|
||
|
|
+ if (!STRNEQ(p1, ",0x"))
|
||
|
|
+ return;
|
||
|
|
+ p1++;
|
||
|
|
+
|
||
|
|
+ if (!extract_hex(p1, &value, NULLCHAR, TRUE))
|
||
|
|
+ return;
|
||
|
|
+
|
||
|
|
+ sprintf(buf1, "0x%lx <%s>\n", value,
|
||
|
|
+ value_to_symstr(value, buf2, output_radix));
|
||
|
|
+
|
||
|
|
+ sprintf(p1, "%s", buf1);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ console(" %s", inbuf);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * If we're generically-inclined, call generic_dump_irq(). Otherwise
|
||
|
|
+ * dump the IRQ table the old-fashioned way.
|
||
|
|
+ */
|
||
|
|
+static void
|
||
|
|
+sw_64_dump_irq(int irq)
|
||
|
|
+{
|
||
|
|
+ ulong action;
|
||
|
|
+ ulong value;
|
||
|
|
+ char *arglist[MAXARGS];
|
||
|
|
+ int argc, others;
|
||
|
|
+ char buf[BUFSIZE];
|
||
|
|
+
|
||
|
|
+ if (symbol_exists("irq_desc")) {
|
||
|
|
+ machdep->dump_irq = generic_dump_irq;
|
||
|
|
+ return(generic_dump_irq(irq));
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ action = symbol_value("irq_action") + (sizeof(void *) * irq);
|
||
|
|
+
|
||
|
|
+ readmem(action, KVADDR, &action,
|
||
|
|
+ sizeof(void *), "irq_action pointer", FAULT_ON_ERROR);
|
||
|
|
+
|
||
|
|
+ if (!action) {
|
||
|
|
+ fprintf(fp, " IRQ: %d\n", irq);
|
||
|
|
+ fprintf(fp, "handler:\n");
|
||
|
|
+ fprintf(fp, " flags: \n");
|
||
|
|
+ fprintf(fp, " mask: \n");
|
||
|
|
+ fprintf(fp, " name: \n");
|
||
|
|
+ fprintf(fp, " dev_id: \n");
|
||
|
|
+ fprintf(fp, " next: \n\n");
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ fprintf(fp, " IRQ: %d\n", irq);
|
||
|
|
+
|
||
|
|
+ open_tmpfile();
|
||
|
|
+
|
||
|
|
+do_linked_action:
|
||
|
|
+ dump_struct("irqaction", action, RADIX(16));
|
||
|
|
+ action = 0;
|
||
|
|
+ rewind(pc->tmpfile);
|
||
|
|
+ while (fgets(buf, BUFSIZE, pc->tmpfile)) {
|
||
|
|
+ strip_comma(buf);
|
||
|
|
+ argc = parse_line(buf, arglist);
|
||
|
|
+ if (STREQ(arglist[0], "struct") || STREQ(buf, "};"))
|
||
|
|
+ continue;
|
||
|
|
+
|
||
|
|
+ if (STREQ(arglist[0], "handler")) {
|
||
|
|
+ fprintf(pc->saved_fp, "handler: %s ",
|
||
|
|
+ strip_hex(arglist[2]));
|
||
|
|
+ if (argc == 4)
|
||
|
|
+ fprintf(pc->saved_fp, "%s", arglist[3]);
|
||
|
|
+ fprintf(pc->saved_fp, "\n");
|
||
|
|
+ }
|
||
|
|
+ if (STREQ(arglist[0], "flags")) {
|
||
|
|
+ value = htol(strip_comma(arglist[2]),
|
||
|
|
+ FAULT_ON_ERROR, NULL);
|
||
|
|
+ fprintf(pc->saved_fp,
|
||
|
|
+ " flags: %lx ", value);
|
||
|
|
+
|
||
|
|
+ if (value) {
|
||
|
|
+ others = 0;
|
||
|
|
+ fprintf(pc->saved_fp, "(");
|
||
|
|
+
|
||
|
|
+ if (value & SA_INTERRUPT)
|
||
|
|
+ fprintf(pc->saved_fp,
|
||
|
|
+ "%sSA_INTERRUPT",
|
||
|
|
+ others++ ? "|" : "");
|
||
|
|
+ if (value & SA_PROBE)
|
||
|
|
+ fprintf(pc->saved_fp,
|
||
|
|
+ "%sSA_PROBE",
|
||
|
|
+ others++ ? "|" : "");
|
||
|
|
+ if (value & SA_SAMPLE_RANDOM)
|
||
|
|
+ fprintf(pc->saved_fp,
|
||
|
|
+ "%sSA_SAMPLE_RANDOM",
|
||
|
|
+ others++ ? "|" : "");
|
||
|
|
+ if (value & SA_SHIRQ)
|
||
|
|
+ fprintf(pc->saved_fp,
|
||
|
|
+ "%sSA_SHIRQ",
|
||
|
|
+ others++ ? "|" : "");
|
||
|
|
+ fprintf(pc->saved_fp, ")");
|
||
|
|
+ if (value & ~ACTION_FLAGS) {
|
||
|
|
+ fprintf(pc->saved_fp,
|
||
|
|
+ " (bits %lx not translated)",
|
||
|
|
+ value & ~ACTION_FLAGS);
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ fprintf(pc->saved_fp, "\n");
|
||
|
|
+
|
||
|
|
+ }
|
||
|
|
+ if (STREQ(arglist[0], "mask")) {
|
||
|
|
+ value = htol(strip_comma(arglist[2]),
|
||
|
|
+ FAULT_ON_ERROR, NULL);
|
||
|
|
+ fprintf(pc->saved_fp,
|
||
|
|
+ " mask: %lx\n", value);
|
||
|
|
+ }
|
||
|
|
+ if (STREQ(arglist[0], "name")) {
|
||
|
|
+ fprintf(pc->saved_fp, " name: %s ",
|
||
|
|
+ strip_hex(arglist[2]));
|
||
|
|
+ if (argc == 4)
|
||
|
|
+ fprintf(pc->saved_fp, "\"%s\"", arglist[3]);
|
||
|
|
+ fprintf(pc->saved_fp, "\n");
|
||
|
|
+ }
|
||
|
|
+ if (STREQ(arglist[0], "dev_id")) {
|
||
|
|
+ value = htol(strip_comma(arglist[2]),
|
||
|
|
+ FAULT_ON_ERROR, NULL);
|
||
|
|
+ fprintf(pc->saved_fp,
|
||
|
|
+ " dev_id: %lx\n", value);
|
||
|
|
+ }
|
||
|
|
+ if (STREQ(arglist[0], "next")) {
|
||
|
|
+ value = htol(strip_comma(arglist[2]),
|
||
|
|
+ FAULT_ON_ERROR, NULL);
|
||
|
|
+ fprintf(pc->saved_fp,
|
||
|
|
+ " next: %s\n",
|
||
|
|
+ strip_hex(arglist[2]));
|
||
|
|
+ if (value)
|
||
|
|
+ action = value;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+ close_tmpfile();
|
||
|
|
+
|
||
|
|
+ fprintf(fp, "\n");
|
||
|
|
+
|
||
|
|
+ if (action)
|
||
|
|
+ goto do_linked_action;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * Get a stack frame combination of pc and ra from the most relevent spot.
|
||
|
|
+ */
|
||
|
|
+static void
|
||
|
|
+sw_64_get_stack_frame(struct bt_info *bt, ulong *pcp, ulong *spp)
|
||
|
|
+{
|
||
|
|
+ struct syment *sp;
|
||
|
|
+ ulong ksp;
|
||
|
|
+ ulong ip;
|
||
|
|
+
|
||
|
|
+ if (pcp) {
|
||
|
|
+ if (DUMPFILE() && is_panic_thread(bt->task)) {
|
||
|
|
+ sp = next_symbol("crash_save_current_state", NULL);
|
||
|
|
+
|
||
|
|
+ if (HWRESET_TASK(bt->task))
|
||
|
|
+ ip = get_percpu_data(0, GET_HALT_PC, 0);
|
||
|
|
+ else if (sp)
|
||
|
|
+ ip = sp->value - 4;
|
||
|
|
+ else
|
||
|
|
+ ip = symbol_value("crash_save_current_state")
|
||
|
|
+ + 16;
|
||
|
|
+ } else
|
||
|
|
+ get_sw_64_frame(bt, &ip, NULL);
|
||
|
|
+
|
||
|
|
+ *pcp = ip;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (spp) {
|
||
|
|
+ ip = 0;
|
||
|
|
+ if (!get_panic_ksp(bt, &ksp))
|
||
|
|
+ get_sw_64_frame(bt,
|
||
|
|
+ HWRESET_TASK(bt->task) ? &ip : NULL, &ksp);
|
||
|
|
+
|
||
|
|
+ if (!INSTACK(ksp, bt))
|
||
|
|
+ error(FATAL,
|
||
|
|
+ "cannot determine starting stack address\n",
|
||
|
|
+ bt->task);
|
||
|
|
+
|
||
|
|
+ *spp = ksp;
|
||
|
|
+ if (ip)
|
||
|
|
+ *pcp = ip;
|
||
|
|
+ }
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * Do the work formerly done by sw_64_get_sp() and sw_64_get_pc().
|
||
|
|
+ */
|
||
|
|
+static void
|
||
|
|
+get_sw_64_frame(struct bt_info *bt, ulong *getpc, ulong *getsp)
|
||
|
|
+{
|
||
|
|
+ int i;
|
||
|
|
+ ulong ip;
|
||
|
|
+ ulong r26;
|
||
|
|
+ ulong ksp, sp;
|
||
|
|
+ ulong *spp;
|
||
|
|
+ ulong percpu_ra;
|
||
|
|
+ ulong percpu_pv;
|
||
|
|
+ struct percpu_data percpu_data;
|
||
|
|
+ char buf[BUFSIZE];
|
||
|
|
+ ulong task;
|
||
|
|
+ ulong *stack;
|
||
|
|
+
|
||
|
|
+ task = bt->task;
|
||
|
|
+ stack = (ulong *)bt->stackbuf;
|
||
|
|
+
|
||
|
|
+ if (tt->flags & THREAD_INFO) { /* pcb.ksp is 1st word in thread_info */
|
||
|
|
+ readmem(bt->tc->thread_info, KVADDR, &ksp, sizeof(ulong),
|
||
|
|
+ "thread_info pcb ksp", FAULT_ON_ERROR);
|
||
|
|
+ sp = ksp;
|
||
|
|
+ } else if (VALID_MEMBER(task_struct_tss_ksp))
|
||
|
|
+ ksp = sp = stack[OFFSET(task_struct_tss_ksp)/sizeof(long)];
|
||
|
|
+ else
|
||
|
|
+ ksp = sp = stack[OFFSET(task_struct_thread_ksp)/sizeof(long)];
|
||
|
|
+
|
||
|
|
+ ip = 0;
|
||
|
|
+ percpu_ra = percpu_pv = 0;
|
||
|
|
+ spp = &stack[(sp - task)/sizeof(long)];
|
||
|
|
+
|
||
|
|
+ if (DUMPFILE() && getsp) {
|
||
|
|
+ if (HWRESET_TASK(task)) {
|
||
|
|
+ if (INSTACK(sp, bt)) {
|
||
|
|
+ *getsp = sp;
|
||
|
|
+ return;
|
||
|
|
+ } else {
|
||
|
|
+ get_percpu_data(0, 0, &percpu_data);
|
||
|
|
+ percpu_ra = percpu_data.halt_ra;
|
||
|
|
+ percpu_pv = percpu_data.halt_pv;
|
||
|
|
+ spp = &stack[roundup(SIZE(task_struct),
|
||
|
|
+ sizeof(ulong)) / sizeof(ulong)];
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (!percpu_ra && (STREQ(closest_symbol(*spp), "panic") ||
|
||
|
|
+ STREQ(closest_symbol(*spp), "handle_ipi"))) {
|
||
|
|
+ *getsp = sp;
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+percpu_retry:
|
||
|
|
+
|
||
|
|
+ if (CRASHDEBUG(1) && percpu_ra) {
|
||
|
|
+ fprintf(fp, "get_sw_64_frame: look for %lx (%s)\n",
|
||
|
|
+ percpu_ra, value_to_symstr(percpu_ra, buf, 0));
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ for (i = 0, spp++; spp < &stack[LONGS_PER_STACK]; spp++,i++) {
|
||
|
|
+
|
||
|
|
+ if (CRASHDEBUG(1) && (percpu_ra || percpu_pv) &&
|
||
|
|
+ is_kernel_text(*spp)) {
|
||
|
|
+ fprintf(fp, "%lx: %lx (%s)\n",
|
||
|
|
+ ((ulong)spp - (ulong)stack) + task,
|
||
|
|
+ *spp, value_to_symstr(*spp, buf, 0));
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (percpu_ra) {
|
||
|
|
+ if (*spp == percpu_ra) {
|
||
|
|
+ *getsp = ((ulong)spp - (ulong)stack) + task;
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+ continue;
|
||
|
|
+ } else if (percpu_pv) {
|
||
|
|
+ if (*spp == percpu_pv) {
|
||
|
|
+ *getsp = ((ulong)spp - (ulong)stack) + task;
|
||
|
|
+ if (getpc)
|
||
|
|
+ *getpc = percpu_pv;
|
||
|
|
+ return;
|
||
|
|
+ }
|
||
|
|
+ continue;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (!INSTACK(*spp, bt))
|
||
|
|
+ continue;
|
||
|
|
+
|
||
|
|
+ if (is_kernel_text(*(spp+1))) {
|
||
|
|
+ sp = *spp;
|
||
|
|
+ ip = *(spp+1);
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (percpu_ra) {
|
||
|
|
+ percpu_ra = 0;
|
||
|
|
+
|
||
|
|
+ error(INFO,
|
||
|
|
+ "cannot find return address (percpu_ra) in HARDWARE RESET stack\n");
|
||
|
|
+ error(INFO,
|
||
|
|
+ "looking for procedure address (percpu_pv) in HARDWARE RESET stack\n");
|
||
|
|
+
|
||
|
|
+ if (CRASHDEBUG(1)) {
|
||
|
|
+ fprintf(fp, "get_sw_64_frame: look for %lx (%s)\n",
|
||
|
|
+ percpu_pv, value_to_symstr(percpu_pv, buf, 0));
|
||
|
|
+ }
|
||
|
|
+ spp = &stack[roundup(SIZE(task_struct),
|
||
|
|
+ sizeof(ulong)) / sizeof(ulong)];
|
||
|
|
+
|
||
|
|
+ goto percpu_retry;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (percpu_pv) {
|
||
|
|
+ error(INFO,
|
||
|
|
+ "cannot find procedure address (percpu_pv) in HARDWARE RESET stack\n");
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ /*
|
||
|
|
+ * Check for a forked task that has not yet run in user space.
|
||
|
|
+ */
|
||
|
|
+ if (!ip) {
|
||
|
|
+ if (INSTACK(ksp + OFFSET(switch_stack_r26), bt)) {
|
||
|
|
+ readmem(ksp + OFFSET(switch_stack_r26), KVADDR,
|
||
|
|
+ &r26, sizeof(ulong),
|
||
|
|
+ "ret_from_smp_fork check", FAULT_ON_ERROR);
|
||
|
|
+ if (STREQ(closest_symbol(r26), "ret_from_smp_fork") ||
|
||
|
|
+ STREQ(closest_symbol(r26), "ret_from_smpfork")) {
|
||
|
|
+ ip = r26;
|
||
|
|
+ sp = ksp;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (getsp)
|
||
|
|
+ *getsp = sp;
|
||
|
|
+ if (getpc)
|
||
|
|
+ *getpc = ip;
|
||
|
|
+
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * Fill the percpu_data structure with information from the
|
||
|
|
+ * hwrpb/percpu_data structures for a given CPU. If requested,
|
||
|
|
+ * return one of the specified entries.
|
||
|
|
+ */
|
||
|
|
+static ulong
|
||
|
|
+get_percpu_data(int cpu, ulong flag, struct percpu_data *pd)
|
||
|
|
+{
|
||
|
|
+ ulong hwrpb, halt_ra, halt_PC, halt_pv;
|
||
|
|
+ unsigned long processor_offset, processor_size;
|
||
|
|
+
|
||
|
|
+ get_symbol_data("hwrpb", sizeof(void *), &hwrpb);
|
||
|
|
+
|
||
|
|
+ readmem(hwrpb+OFFSET(hwrpb_struct_processor_offset), KVADDR,
|
||
|
|
+ &processor_offset, sizeof(ulong),
|
||
|
|
+ "hwrpb processor_offset", FAULT_ON_ERROR);
|
||
|
|
+
|
||
|
|
+ readmem(hwrpb+OFFSET(hwrpb_struct_processor_size), KVADDR,
|
||
|
|
+ &processor_size, sizeof(ulong),
|
||
|
|
+ "hwrpb processor_size", FAULT_ON_ERROR);
|
||
|
|
+
|
||
|
|
+ readmem(hwrpb + processor_offset + (cpu * processor_size) +
|
||
|
|
+ OFFSET(percpu_struct_halt_PC),
|
||
|
|
+ KVADDR, &halt_PC, sizeof(ulong),
|
||
|
|
+ "percpu halt_PC", FAULT_ON_ERROR);
|
||
|
|
+
|
||
|
|
+ readmem(hwrpb + processor_offset + (cpu * processor_size) +
|
||
|
|
+ OFFSET(percpu_struct_halt_ra),
|
||
|
|
+ KVADDR, &halt_ra, sizeof(ulong),
|
||
|
|
+ "percpu halt_ra", FAULT_ON_ERROR);
|
||
|
|
+
|
||
|
|
+ readmem(hwrpb + processor_offset + (cpu * processor_size) +
|
||
|
|
+ OFFSET(percpu_struct_halt_pv),
|
||
|
|
+ KVADDR, &halt_pv, sizeof(ulong),
|
||
|
|
+ "percpu halt_pv", FAULT_ON_ERROR);
|
||
|
|
+
|
||
|
|
+ if (pd) {
|
||
|
|
+ pd->halt_PC = halt_PC;
|
||
|
|
+ pd->halt_ra = halt_ra;
|
||
|
|
+ pd->halt_pv = halt_pv;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ switch (flag)
|
||
|
|
+ {
|
||
|
|
+ case GET_HALT_PC:
|
||
|
|
+ return halt_PC;
|
||
|
|
+
|
||
|
|
+ case GET_HALT_RA:
|
||
|
|
+ return halt_ra;
|
||
|
|
+
|
||
|
|
+ case GET_HALT_PV:
|
||
|
|
+ return halt_pv;
|
||
|
|
+
|
||
|
|
+ default:
|
||
|
|
+ return 0;
|
||
|
|
+ }
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * Translate a PTE, returning TRUE if the page is _PAGE_VALID or _PAGE_PRESENT,
|
||
|
|
+ * whichever is appropriate for the machine type. If a physaddr pointer is
|
||
|
|
+ * passed in, don't print anything.
|
||
|
|
+ */
|
||
|
|
+static int
|
||
|
|
+sw_64_translate_pte(ulong pte, void *physaddr, ulonglong unused)
|
||
|
|
+{
|
||
|
|
+ int c, len1, len2, len3, others, page_present;
|
||
|
|
+ char buf[BUFSIZE];
|
||
|
|
+ char buf2[BUFSIZE];
|
||
|
|
+ char buf3[BUFSIZE];
|
||
|
|
+ char ptebuf[BUFSIZE];
|
||
|
|
+ char physbuf[BUFSIZE];
|
||
|
|
+ char *arglist[MAXARGS];
|
||
|
|
+ physaddr_t paddr;
|
||
|
|
+
|
||
|
|
+ paddr = PTOB(pte >> 32);
|
||
|
|
+ page_present = (pte & _PAGE_VALID);
|
||
|
|
+
|
||
|
|
+ if (physaddr) {
|
||
|
|
+ *((ulong *)physaddr) = paddr;
|
||
|
|
+ return page_present;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ sprintf(ptebuf, "%lx", pte);
|
||
|
|
+ len1 = MAX(strlen(ptebuf), strlen("PTE"));
|
||
|
|
+ fprintf(fp, "%s ", mkstring(buf, len1, CENTER|LJUST, "PTE"));
|
||
|
|
+
|
||
|
|
+ if (!page_present && pte) {
|
||
|
|
+ swap_location(pte, buf);
|
||
|
|
+ if ((c = parse_line(buf, arglist)) != 3)
|
||
|
|
+ error(FATAL, "cannot determine swap location\n");
|
||
|
|
+
|
||
|
|
+ len2 = MAX(strlen(arglist[0]), strlen("SWAP"));
|
||
|
|
+ len3 = MAX(strlen(arglist[2]), strlen("OFFSET"));
|
||
|
|
+
|
||
|
|
+ fprintf(fp, "%s %s\n",
|
||
|
|
+ mkstring(buf2, len2, CENTER|LJUST, "SWAP"),
|
||
|
|
+ mkstring(buf3, len3, CENTER|LJUST, "OFFSET"));
|
||
|
|
+
|
||
|
|
+ strcpy(buf2, arglist[0]);
|
||
|
|
+ strcpy(buf3, arglist[2]);
|
||
|
|
+ fprintf(fp, "%s %s %s\n",
|
||
|
|
+ mkstring(ptebuf, len1, CENTER|RJUST, NULL),
|
||
|
|
+ mkstring(buf2, len2, CENTER|RJUST, NULL),
|
||
|
|
+ mkstring(buf3, len3, CENTER|RJUST, NULL));
|
||
|
|
+
|
||
|
|
+ return page_present;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ sprintf(physbuf, "%llx", paddr);
|
||
|
|
+ len2 = MAX(strlen(physbuf), strlen("PHYSICAL"));
|
||
|
|
+ fprintf(fp, "%s ", mkstring(buf, len2, CENTER|LJUST, "PHYSICAL"));
|
||
|
|
+
|
||
|
|
+ fprintf(fp, "FLAGS\n");
|
||
|
|
+
|
||
|
|
+ fprintf(fp, "%s %s ",
|
||
|
|
+ mkstring(ptebuf, len1, CENTER|RJUST, NULL),
|
||
|
|
+ mkstring(physbuf, len2, CENTER|RJUST, NULL));
|
||
|
|
+ fprintf(fp, "(");
|
||
|
|
+ others = 0;
|
||
|
|
+
|
||
|
|
+ if (pte) {
|
||
|
|
+ if (pte & _PAGE_VALID)
|
||
|
|
+ fprintf(fp, "%sVALID", others++ ? "|" : "");
|
||
|
|
+ if (pte & _PAGE_FOR)
|
||
|
|
+ fprintf(fp, "%sFOR", others++ ? "|" : "");
|
||
|
|
+ if (pte & _PAGE_FOW)
|
||
|
|
+ fprintf(fp, "%sFOW", others++ ? "|" : "");
|
||
|
|
+ if (pte & _PAGE_FOE)
|
||
|
|
+ fprintf(fp, "%sFOE", others++ ? "|" : "");
|
||
|
|
+ if (pte & _PAGE_ASM)
|
||
|
|
+ fprintf(fp, "%sASM", others++ ? "|" : "");
|
||
|
|
+ if (pte & _PAGE_KRE)
|
||
|
|
+ fprintf(fp, "%sKRE", others++ ? "|" : "");
|
||
|
|
+ if (pte & _PAGE_URE)
|
||
|
|
+ fprintf(fp, "%sURE", others++ ? "|" : "");
|
||
|
|
+ if (pte & _PAGE_KWE)
|
||
|
|
+ fprintf(fp, "%sKWE", others++ ? "|" : "");
|
||
|
|
+ if (pte & _PAGE_UWE)
|
||
|
|
+ fprintf(fp, "%sUWE", others++ ? "|" : "");
|
||
|
|
+ if (pte & _PAGE_DIRTY)
|
||
|
|
+ fprintf(fp, "%sDIRTY", others++ ? "|" : "");
|
||
|
|
+ if (pte & _PAGE_ACCESSED)
|
||
|
|
+ fprintf(fp, "%sACCESSED", others++ ? "|" : "");
|
||
|
|
+ } else {
|
||
|
|
+ fprintf(fp, "no mapping");
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ fprintf(fp, ")\n");
|
||
|
|
+
|
||
|
|
+ return page_present;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * This is currently not machine-dependent, but eventually I'd prefer to use
|
||
|
|
+ * the HWPCB for the real physical memory size.
|
||
|
|
+ */
|
||
|
|
+static uint64_t
|
||
|
|
+sw_64_memory_size(void)
|
||
|
|
+{
|
||
|
|
+ return (generic_memory_size());
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * Determine where vmalloc'd memory starts.
|
||
|
|
+ */
|
||
|
|
+static ulong
|
||
|
|
+sw_64_vmalloc_start(void)
|
||
|
|
+{
|
||
|
|
+ return VMALLOC_START;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * SW_64 tasks are all stacksize-aligned.
|
||
|
|
+ */
|
||
|
|
+static int
|
||
|
|
+sw_64_is_task_addr(ulong task)
|
||
|
|
+{
|
||
|
|
+ return (IS_KVADDR(task) && (ALIGNED_STACK_OFFSET(task) == 0));
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * Keep or reject a symbol from the kernel namelist.
|
||
|
|
+ */
|
||
|
|
+int
|
||
|
|
+sw_64_verify_symbol(const char *name, ulong value, char type)
|
||
|
|
+{
|
||
|
|
+ if (CRASHDEBUG(8) && name && strlen(name))
|
||
|
|
+ fprintf(fp, "%016lx %s\n", value, name);
|
||
|
|
+
|
||
|
|
+ return (name && strlen(name) && (value > MIN_SYMBOL_VALUE));
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * Override smp_num_cpus if possible and necessary.
|
||
|
|
+ */
|
||
|
|
+int
|
||
|
|
+sw_64_get_smp_cpus(void)
|
||
|
|
+{
|
||
|
|
+ int cpus;
|
||
|
|
+
|
||
|
|
+ if ((cpus = get_cpus_online()))
|
||
|
|
+ return cpus;
|
||
|
|
+ else
|
||
|
|
+ return kt->cpus;
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * Machine dependent command.
|
||
|
|
+ */
|
||
|
|
+void
|
||
|
|
+sw_64_cmd_mach(void)
|
||
|
|
+{
|
||
|
|
+ int c, cflag;
|
||
|
|
+ unsigned int radix;
|
||
|
|
+
|
||
|
|
+ cflag = radix = 0;
|
||
|
|
+
|
||
|
|
+ while ((c = getopt(argcnt, args, "cxd")) != EOF) {
|
||
|
|
+ switch(c)
|
||
|
|
+ {
|
||
|
|
+ case 'c':
|
||
|
|
+ cflag++;
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ case 'x':
|
||
|
|
+ if (radix == 10)
|
||
|
|
+ error(FATAL,
|
||
|
|
+ "-d and -x are mutually exclusive\n");
|
||
|
|
+ radix = 16;
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ case 'd':
|
||
|
|
+ if (radix == 16)
|
||
|
|
+ error(FATAL,
|
||
|
|
+ "-d and -x are mutually exclusive\n");
|
||
|
|
+ radix = 10;
|
||
|
|
+ break;
|
||
|
|
+
|
||
|
|
+ default:
|
||
|
|
+ argerrs++;
|
||
|
|
+ break;
|
||
|
|
+ }
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (argerrs)
|
||
|
|
+ cmd_usage(pc->curcmd, SYNOPSIS);
|
||
|
|
+
|
||
|
|
+ if (cflag)
|
||
|
|
+ display_hwrpb(radix);
|
||
|
|
+ else
|
||
|
|
+ sw_64_display_machine_stats();
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * "mach" command output.
|
||
|
|
+ */
|
||
|
|
+static void
|
||
|
|
+sw_64_display_machine_stats(void)
|
||
|
|
+{
|
||
|
|
+ struct new_utsname *uts;
|
||
|
|
+ char buf[BUFSIZE];
|
||
|
|
+ ulong mhz;
|
||
|
|
+
|
||
|
|
+ uts = &kt->utsname;
|
||
|
|
+
|
||
|
|
+ fprintf(fp, " MACHINE TYPE: %s\n", uts->machine);
|
||
|
|
+ fprintf(fp, " MEMORY SIZE: %s\n", get_memory_size(buf));
|
||
|
|
+ fprintf(fp, " CPUS: %d\n", kt->cpus);
|
||
|
|
+ fprintf(fp, " PROCESSOR SPEED: ");
|
||
|
|
+ if ((mhz = machdep->processor_speed()))
|
||
|
|
+ fprintf(fp, "%ld Mhz\n", mhz);
|
||
|
|
+ else
|
||
|
|
+ fprintf(fp, "(unknown)\n");
|
||
|
|
+ fprintf(fp, " HZ: %d\n", machdep->hz);
|
||
|
|
+ fprintf(fp, " PAGE SIZE: %d\n", PAGESIZE());
|
||
|
|
+ fprintf(fp, " L1 CACHE SIZE: %d\n", l1_cache_size());
|
||
|
|
+ fprintf(fp, "KERNEL VIRTUAL BASE: %lx\n", machdep->kvbase);
|
||
|
|
+ fprintf(fp, "KERNEL VMALLOC BASE: %lx\n", vt->vmalloc_start);
|
||
|
|
+ fprintf(fp, " KERNEL STACK SIZE: %ld\n", STACKSIZE());
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * Display the hwrpb_struct and each percpu_struct.
|
||
|
|
+ */
|
||
|
|
+static void
|
||
|
|
+display_hwrpb(unsigned int radix)
|
||
|
|
+{
|
||
|
|
+ int cpu;
|
||
|
|
+ ulong hwrpb, percpu;
|
||
|
|
+ ulong processor_offset, processor_size;
|
||
|
|
+
|
||
|
|
+ get_symbol_data("hwrpb", sizeof(void *), &hwrpb);
|
||
|
|
+
|
||
|
|
+ readmem(hwrpb+OFFSET(hwrpb_struct_processor_offset), KVADDR,
|
||
|
|
+ &processor_offset, sizeof(ulong),
|
||
|
|
+ "hwrpb processor_offset", FAULT_ON_ERROR);
|
||
|
|
+ readmem(hwrpb+OFFSET(hwrpb_struct_processor_size), KVADDR,
|
||
|
|
+ &processor_size, sizeof(ulong),
|
||
|
|
+ "hwrpb processor_size", FAULT_ON_ERROR);
|
||
|
|
+
|
||
|
|
+ fprintf(fp, "HWRPB:\n");
|
||
|
|
+ dump_struct("hwrpb_struct", hwrpb, radix);
|
||
|
|
+
|
||
|
|
+ for (cpu = 0; cpu < kt->cpus; cpu++) {
|
||
|
|
+ fprintf(fp, "\nCPU %d:\n", cpu);
|
||
|
|
+ percpu = hwrpb + processor_offset + (processor_size * cpu);
|
||
|
|
+ dump_struct("percpu_struct", percpu, radix);
|
||
|
|
+ }
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+/*
|
||
|
|
+ * Perform any leftover pre-prompt machine-specific initialization tasks here.
|
||
|
|
+ */
|
||
|
|
+static void
|
||
|
|
+sw_64_post_init(void)
|
||
|
|
+{
|
||
|
|
+ modify_signame(7, "SIGEMT", NULL);
|
||
|
|
+ modify_signame(10, "SIGBUS", NULL);
|
||
|
|
+ modify_signame(12, "SIGSYS", NULL);
|
||
|
|
+ modify_signame(16, "SIGURG", NULL);
|
||
|
|
+ modify_signame(17, "SIGSTOP", NULL);
|
||
|
|
+ modify_signame(18, "SIGTSTP", NULL);
|
||
|
|
+ modify_signame(19, "SIGCONT", NULL);
|
||
|
|
+ modify_signame(20, "SIGCHLD", NULL);
|
||
|
|
+ modify_signame(23, "SIGIO", "SIGPOLL");
|
||
|
|
+ modify_signame(29, "SIGINFO", "SIGPWR");
|
||
|
|
+ modify_signame(30, "SIGUSR1", NULL);
|
||
|
|
+ modify_signame(31, "SIGUSR2", NULL);
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+
|
||
|
|
+#endif /* SW_64 */
|