diff --git a/crash-7.3.0-sw.patch b/crash-7.3.0-sw.patch new file mode 100755 index 0000000000000000000000000000000000000000..4a78574e158ecfa37cf737e3b9c74d29998a27fa --- /dev/null +++ b/crash-7.3.0-sw.patch @@ -0,0 +1,3105 @@ +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 \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 : subq sp,0x50,sp ++ * fffffc00003217e8: 43ca153e ++ * 010000 11110 01010000 1 0101001 11110 ++ * ++ * 0xfffffc0000321668 : subq sp,0x60,sp ++ * fffffc0000321668: 43cc153e ++ * 010000 11110 01100000 1 0101001 11110 ++ * ++ * 0xfffffc000035d028 : 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 : ldah gp,35(t12) ++ * 0xfffffc0000349fa4 : 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 : ldq t12,-29336(gp) ++ * 0xfffffc000042c368 : ++ * jsr ra,(t12),0xfffffc0000429dc0 ++ * ++ * 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 */ diff --git a/crash.spec b/crash.spec index 7316395a89644bd21ff602b432d0942b36826961..334c545d82e271f5dba5943ad12a280dda08079a 100644 --- a/crash.spec +++ b/crash.spec @@ -1,6 +1,6 @@ Name: crash Version: 7.3.0 -Release: 6 +Release: 7 Summary: Linux kernel crash utility. License: GPLv3 URL: https://crash-utility.github.io @@ -16,6 +16,9 @@ Patch6: add-SDEI-stack-resolution.patch Patch7: Handle-task_struct-cpu-member-changes-for-kernels-5..patch Patch8: 0001-CVE-2019-1010180-Add-bfd_get_file_size-to-get-archive-element-size.patch Patch9: 0002-CVE-2019-1010180-DWARF-reader-Reject-sections-with-invalid-sizes.patch +%ifarch sw_64 +Patch10: crash-7.3.0-sw.patch +%endif BuildRequires: ncurses-devel zlib-devel lzo-devel snappy-devel BuildRequires: gcc gcc-c++ bison m4 @@ -81,6 +84,9 @@ install -D -m 0644 defs.h %{buildroot}%{_includedir}/%{name}/defs.h %{_mandir}/man8/crash.8* %changelog +* Wed Oct 19 2022 wuzx - 7.3.0-7 +- add sw64 patch + * Sun Oct 9 2022 chenhaixiang - 7.3.0-6 - fix gdb CVE-2019-1010180