[Crash-utility] [PATCHv2 4/4] Add support for MIPS

Rabin Vincent rabin at rab.in
Mon Jan 12 20:47:42 UTC 2015


---
 Makefile            |   7 +-
 configure.c         |  48 +++
 defs.h              | 111 ++++++-
 help.c              |   6 +-
 lkcd_vmdump_v2_v3.h |   3 +-
 mips.c              | 879 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 netdump.c           |  10 +
 symbols.c           |   9 +
 8 files changed, 1067 insertions(+), 6 deletions(-)
 create mode 100644 mips.c

diff --git a/Makefile b/Makefile
index c1a3efd..184ef66 100644
--- a/Makefile
+++ b/Makefile
@@ -61,7 +61,7 @@ UNWIND_HFILES=unwind.h unwind_i.h rse.h unwind_x86.h unwind_x86_64.h
 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 \
 	alpha.c x86.c ppc.c ia64.c s390.c s390x.c s390dbf.c ppc64.c x86_64.c \
-	arm.c arm64.c \
+	arm.c arm64.c mips.o \
 	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\
 	lkcd_fix_mem.c s390_dump.c lkcd_x86_trace.c \
@@ -79,7 +79,7 @@ SOURCE_FILES=${CFILES} ${GENERIC_HFILES} ${MCORE_HFILES} \
 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 \
 	alpha.o x86.o ppc.o ia64.o s390.o s390x.o s390dbf.o ppc64.o x86_64.o \
-	arm.o arm64.o \
+	arm.o arm64.o mips.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 \
 	lkcd_fix_mem.o s390_dump.o netdump.o diskdump.o makedumpfile.o xendump.o \
@@ -416,6 +416,9 @@ arm.o: ${GENERIC_HFILES} ${REDHAT_HFILES} arm.c
 arm64.o: ${GENERIC_HFILES} ${REDHAT_HFILES} arm64.c
 	${CC} -c ${CRASH_CFLAGS} arm64.c ${WARNING_OPTIONS} ${WARNING_ERROR}
 
+mips.o: ${GENERIC_HFILES} ${REDHAT_HFILES} mips.c
+	${CC} -c ${CRASH_CFLAGS} mips.c ${WARNING_OPTIONS} ${WARNING_ERROR}
+
 s390.o: ${GENERIC_HFILES} ${IBM_HFILES} s390.c
 	${CC} -c ${CRASH_CFLAGS} s390.c ${WARNING_OPTIONS} ${WARNING_ERROR}
 
diff --git a/configure.c b/configure.c
index 7b91e04..800173a 100644
--- a/configure.c
+++ b/configure.c
@@ -116,6 +116,7 @@ void add_extra_lib(char *);
 #define X86_64  8
 #define ARM	9
 #define ARM64   10
+#define MIPS    11
 
 #define TARGET_X86    "TARGET=X86"
 #define TARGET_ALPHA  "TARGET=ALPHA"
@@ -127,6 +128,7 @@ void add_extra_lib(char *);
 #define TARGET_X86_64 "TARGET=X86_64"
 #define TARGET_ARM    "TARGET=ARM"
 #define TARGET_ARM64  "TARGET=ARM64"
+#define TARGET_MIPS   "TARGET=MIPS"
 
 #define TARGET_CFLAGS_X86    "TARGET_CFLAGS=-D_FILE_OFFSET_BITS=64"
 #define TARGET_CFLAGS_ALPHA  "TARGET_CFLAGS="
@@ -144,6 +146,9 @@ void add_extra_lib(char *);
 #define TARGET_CFLAGS_ARM64            "TARGET_CFLAGS="
 #define TARGET_CFLAGS_ARM64_ON_X86_64  "TARGET_CFLAGS="
 #define TARGET_CFLAGS_PPC64_ON_X86_64  "TARGET_CFLAGS="
+#define TARGET_CFLAGS_MIPS            "TARGET_CFLAGS=-D_FILE_OFFSET_BITS=64"
+#define TARGET_CFLAGS_MIPS_ON_X86     "TARGET_CFLAGS=-D_FILE_OFFSET_BITS=64"
+#define TARGET_CFLAGS_MIPS_ON_X86_64  "TARGET_CFLAGS=-m32 -D_FILE_OFFSET_BITS=64"
 
 #define GDB_TARGET_DEFAULT        "GDB_CONF_FLAGS="
 #define GDB_TARGET_ARM_ON_X86     "GDB_CONF_FLAGS=--target=arm-elf-linux"
@@ -152,6 +157,8 @@ void add_extra_lib(char *);
 #define GDB_TARGET_PPC_ON_PPC64   "GDB_CONF_FLAGS=--target=ppc-elf-linux CFLAGS=-m32"
 #define GDB_TARGET_ARM64_ON_X86_64  "GDB_CONF_FLAGS=--target=aarch64-elf-linux"   /* TBD */
 #define GDB_TARGET_PPC64_ON_X86_64  "GDB_CONF_FLAGS=--target=powerpc64le-unknown-linux-gnu"
+#define GDB_TARGET_MIPS_ON_X86     "GDB_CONF_FLAGS=--target=mipsel-elf-linux"
+#define GDB_TARGET_MIPS_ON_X86_64  "GDB_CONF_FLAGS=--target=mipsel-elf-linux CFLAGS=-m32"
      
 /*
  *  The original plan was to allow the use of a particular version
@@ -368,6 +375,9 @@ get_current_configuration(struct supported_gdb_version *sp)
 #ifdef __aarch64__
         target_data.target = ARM64;
 #endif
+#ifdef __mipsel___
+        target_data.target = MIPS;
+#endif
 
 	set_initial_target(sp);
 
@@ -384,6 +394,14 @@ get_current_configuration(struct supported_gdb_version *sp)
 			 *  X86_64 when built as a 32-bit executable.
 			 */
 			target_data.target = ARM;
+		} else if ((target_data.target == X86 || target_data.target == X86_64) &&
+			   (name_to_target((char *)target_data.target_as_param) == MIPS)) {
+			/*
+			 *  Debugging of MIPS little-endian core files
+			 *  supported on X86, and on X86_64 when built as a
+			 *  32-bit executable.
+			 */
+			target_data.target = MIPS;
 		} else if ((target_data.target == X86_64) &&
 			(name_to_target((char *)target_data.target_as_param) == X86)) {
 			/*
@@ -440,6 +458,15 @@ get_current_configuration(struct supported_gdb_version *sp)
 		    (target_data.initial_gdb_target != ARM))
 			arch_mismatch(sp);
 
+		if ((target_data.initial_gdb_target == MIPS) &&
+		    (target_data.target != MIPS)) {
+			if ((target_data.target == X86) ||
+			    (target_data.target == X86_64))
+				target_data.target = MIPS;
+			else
+				arch_mismatch(sp);
+		}
+
 		if ((target_data.initial_gdb_target == X86) &&
 		    (target_data.target != X86)) {
 			if (target_data.target == X86_64) 
@@ -590,6 +617,9 @@ show_configuration(void)
 	case ARM64:
 		printf("TARGET: ARM64\n");
 		break;
+	case MIPS:
+		printf("TARGET: MIPS\n");
+		break;
 	}
 
 	if (strlen(target_data.program)) {
@@ -688,6 +718,17 @@ build_configure(struct supported_gdb_version *sp)
 		} else
 			target_CFLAGS = TARGET_CFLAGS_ARM64;
 		break;
+	case MIPS:
+                target = TARGET_MIPS;
+                if (target_data.host == X86) {
+                        target_CFLAGS = TARGET_CFLAGS_MIPS_ON_X86;
+			gdb_conf_flags = GDB_TARGET_MIPS_ON_X86;
+                } else if (target_data.host == X86_64) {
+                        target_CFLAGS = TARGET_CFLAGS_MIPS_ON_X86_64;
+			gdb_conf_flags = GDB_TARGET_MIPS_ON_X86_64;
+		} else
+                        target_CFLAGS = TARGET_CFLAGS_MIPS;
+                break;
 	}
 
 	ldflags = get_extra_flags("LDFLAGS.extra", NULL);
@@ -1511,6 +1552,8 @@ set_initial_target(struct supported_gdb_version *sp)
 		target_data.initial_gdb_target = ARM64;
 	else if (strncmp(buf, "ARM", strlen("ARM")) == 0)
 		target_data.initial_gdb_target = ARM;
+	else if (strncmp(buf, "MIPS", strlen("MIPS")) == 0)
+		target_data.initial_gdb_target = MIPS;
 }
 
 char *
@@ -1528,6 +1571,7 @@ target_to_name(int target)
 	case X86_64: return("X86_64");
 	case ARM:    return("ARM"); 
 	case ARM64:  return("ARM64");
+	case MIPS:   return("MIPS");
 	}
 
 	return "UNKNOWN";
@@ -1582,6 +1626,10 @@ name_to_target(char *name)
                 return ARM;
         else if (strncmp(name, "arm", strlen("arm")) == 0)
                 return ARM;
+        else if (strncmp(name, "mips", strlen("mips")) == 0)
+                return MIPS;
+        else if (strncmp(name, "MIPS", strlen("MIPS")) == 0)
+                return MIPS;
 
 	return UNKNOWN;
 }
diff --git a/defs.h b/defs.h
index 9d44fbc..c1dfbbc 100644
--- a/defs.h
+++ b/defs.h
@@ -71,7 +71,7 @@
 
 #if !defined(X86) && !defined(X86_64) && !defined(ALPHA) && !defined(PPC) && \
     !defined(IA64) && !defined(PPC64) && !defined(S390) && !defined(S390X) && \
-    !defined(ARM) && !defined(ARM64)
+    !defined(ARM) && !defined(ARM64) && !defined(MIPS)
 #ifdef __alpha__
 #define ALPHA
 #endif
@@ -103,6 +103,9 @@
 #ifdef __aarch64__
 #define ARM64
 #endif
+#ifdef __mipsel__
+#define MIPS
+#endif
 #endif
 
 #ifdef X86
@@ -135,6 +138,9 @@
 #ifdef ARM64
 #define NR_CPUS  (4096)   /* TBD */
 #endif
+#ifdef MIPS
+#define NR_CPUS  (32)
+#endif
 
 #define BUFSIZE  (1500)
 #define NULLCHAR ('\0')
@@ -1928,6 +1934,8 @@ struct offset_table {                    /* stash of commonly-used offsets */
 	long atomic_t_counter;
 	long percpu_counter_count;
 	long mm_struct_mm_count;
+	long task_struct_thread_reg29;
+	long task_struct_thread_reg31;
 };
 
 struct size_table {         /* stash of commonly-used sizes */
@@ -2945,6 +2953,37 @@ struct arm64_stackframe {
 
 #endif  /* ARM64 */
 
+#ifdef MIPS
+#define _32BIT_
+#define MACHINE_TYPE		"MIPS"
+
+#define PAGEBASE(X)		(((ulong)(X)) & (ulong)machdep->pagemask)
+
+#define PTOV(X)            ((unsigned long)(X) + 0x80000000lu)
+#define VTOP(X)            ((unsigned long)(X) & 0x1ffffffflu)
+
+#define IS_VMALLOC_ADDR(X) (vt->vmalloc_start && (ulong)(X) >= vt->vmalloc_start)
+
+#define DEFAULT_MODULES_VADDR	(machdep->kvbase - 16 * 1024 * 1024)
+#define MODULES_VADDR   	(machdep->machspec->modules_vaddr)
+#define MODULES_END     	(machdep->machspec->modules_end)
+#define VMALLOC_START   	(machdep->machspec->vmalloc_start_addr)
+#define VMALLOC_END     	(machdep->machspec->vmalloc_end)
+
+#define __SWP_TYPE_SHIFT	3
+#define __SWP_TYPE_BITS		6
+#define __SWP_TYPE_MASK		((1 << __SWP_TYPE_BITS) - 1)
+#define __SWP_OFFSET_SHIFT	(__SWP_TYPE_BITS + __SWP_TYPE_SHIFT)
+
+#define SWP_TYPE(entry)		(((entry) >> __SWP_TYPE_SHIFT) & __SWP_TYPE_MASK)
+#define SWP_OFFSET(entry)	((entry) >> __SWP_OFFSET_SHIFT)
+
+#define __swp_type(entry)	SWP_TYPE(entry)
+#define __swp_offset(entry)	SWP_OFFSET(entry)
+
+#define TIF_SIGPENDING		(2)
+#endif  /* MIPS */
+
 #ifdef X86
 #define _32BIT_
 #define MACHINE_TYPE       "X86"
@@ -3802,6 +3841,10 @@ struct efi_memory_desc_t {
 #define MAX_HEXADDR_STRLEN (16)
 #define UVADDR_PRLEN       (10)
 #endif
+#ifdef MIPS
+#define MAX_HEXADDR_STRLEN (8)
+#define UVADDR_PRLEN       (8)
+#endif
 
 #define BADADDR  ((ulong)(-1))
 #define BADVAL   ((ulong)(-1))
@@ -4338,6 +4381,9 @@ void dump_build_data(void);
 #ifdef PPC64
 #define machdep_init(X) ppc64_init(X)
 #endif
+#ifdef MIPS
+#define machdep_init(X) mips_init(X)
+#endif
 int clean_exit(int);
 int untrusted_file(FILE *, char *);
 char *readmem_function_name(void);
@@ -4745,6 +4791,9 @@ void display_help_screen(char *);
 #ifdef PPC64
 #define dump_machdep_table(X) ppc64_dump_machdep_table(X)
 #endif
+#ifdef MIPS
+#define dump_machdep_table(X) mips_dump_machdep_table(X)
+#endif
 extern char *help_pointer[];
 extern char *help_alias[];
 extern char *help_ascii[];
@@ -5505,6 +5554,66 @@ void s390x_dump_machdep_table(ulong);
 #define KSYMS_START (0x1)
 #endif
 
+#ifdef MIPS
+void mips_init(int);
+void mips_dump_machdep_table(ulong);
+
+#define display_idt_table() \
+        error(FATAL, "-d option is not applicable to MIPS architecture\n")
+
+struct mips_regset {
+	ulong regs[45];
+};
+
+struct mips_pt_regs {
+        ulong pad0[8];
+        ulong regs[32];
+        ulong cp0_status;
+        ulong hi;
+        ulong lo;
+        ulong cp0_badvaddr;
+        ulong cp0_cause;
+        ulong cp0_epc;
+};
+
+#define KSYMS_START	(0x1)
+#define PHYS_BASE	(0x2)
+
+#define KVBASE_MASK	(0x1ffffff)
+
+struct machine_specific {
+	ulong phys_base;
+	ulong vmalloc_start_addr;
+	ulong modules_vaddr;
+	ulong modules_end;
+
+	ulong _page_present;
+	ulong _page_read;
+	ulong _page_write;
+	ulong _page_accessed;
+	ulong _page_modified;
+	ulong _page_global;
+	ulong _page_valid;
+	ulong _page_no_read;
+	ulong _page_no_exec;
+	ulong _page_dirty;
+
+	ulong _pfn_shift;
+
+#define _PAGE_PRESENT   (machdep->machspec->_page_present)
+#define _PAGE_READ      (machdep->machspec->_page_read)
+#define _PAGE_WRITE     (machdep->machspec->_page_write)
+#define _PAGE_ACCESSED  (machdep->machspec->_page_accessed)
+#define _PAGE_MODIFIED  (machdep->machspec->_page_modified)
+#define _PAGE_GLOBAL    (machdep->machspec->_page_global)
+#define _PAGE_VALID     (machdep->machspec->_page_valid)
+#define _PAGE_NO_READ   (machdep->machspec->_page_no_read)
+#define _PAGE_NO_EXEC   (machdep->machspec->_page_no_exec)
+#define _PAGE_DIRTY     (machdep->machspec->_page_dirty)
+#define _PFN_SHIFT      (machdep->machspec->_pfn_shift)
+};
+#endif /* MIPS */
+
 /*
  *  netdump.c 
  */
diff --git a/help.c b/help.c
index bc0dcde..217b73d 100644
--- a/help.c
+++ b/help.c
@@ -8000,8 +8000,8 @@ char *README[] = {
 " ",
 "  These are the current prerequisites: ",
 "",
-"  o  At this point, x86, ia64, x86_64, ppc64, ppc, arm, arm64, alpha, s390",
-"     and s390x-based kernels are supported.  Other architectures may be",
+"  o  At this point, x86, ia64, x86_64, ppc64, ppc, arm, arm64, alpha, mips,"
+"     s390 and s390x-based kernels are supported.  Other architectures may be",
 "     addressed in the future.",
 "",
 "  o  One size fits all -- the utility can be run on any Linux kernel version",
@@ -8053,6 +8053,8 @@ README_ENTER_DIRECTORY,
 "     32-bit x86 dumpfiles may be built by typing \"make target=X86\".",
 "  o  On an x86 or x86_64 host, a 32-bit x86 binary that can be used to analyze",
 "     32-bit arm dumpfiles may be built by typing \"make target=ARM\".",
+"  o  On an x86 or x86_64 host, a 32-bit x86 binary that can be used to analyze",
+"     32-bit mips dumpfiles may be built by typing \"make target=MIPS\".",
 "  o  On an ppc64 host, a 32-bit ppc binary that can be used to analyze",
 "     32-bit ppc dumpfiles may be built by typing \"make target=PPC\".",
 "  o  On an x86_64 host, an x86_64 binary that can be used to analyze",
diff --git a/lkcd_vmdump_v2_v3.h b/lkcd_vmdump_v2_v3.h
index efcdaf2..7b014ec 100644
--- a/lkcd_vmdump_v2_v3.h
+++ b/lkcd_vmdump_v2_v3.h
@@ -35,7 +35,8 @@
 #include <asm/vmdump.h>                 /* for architecture-specific header */
 #endif
 
-#if defined(ARM) || defined(X86) || defined(PPC) || defined(S390) || defined(S390X) || defined(ARM64)
+#if defined(ARM) || defined(X86) || defined(PPC) || defined(S390) || \
+	defined(S390X) || defined(ARM64) || defined(MIPS)
 
 /*
  * Kernel header file for Linux crash dumps.
diff --git a/mips.c b/mips.c
new file mode 100644
index 0000000..863c182
--- /dev/null
+++ b/mips.c
@@ -0,0 +1,879 @@
+/*
+ * mips.c - core analysis suite
+ *
+ * Copyright (C) 2015 Rabin Vincent <rabin at rab.in>
+ *
+ * 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 MIPS
+
+#include <elf.h>
+#include "defs.h"
+
+/* From arch/mips/asm/include/pgtable{,-32}.h */
+typedef ulong pgd_t;
+typedef ulong pte_t;
+
+#define PTE_ORDER	0
+
+#define PGD_T_LOG2	(__builtin_ffs(sizeof(pgd_t)) - 1)
+#define PTE_T_LOG2	(__builtin_ffs(sizeof(pte_t)) - 1)
+
+#define __PGD_ORDER	(32 - 3 * PAGESHIFT() + PGD_T_LOG2 + PTE_T_LOG2)
+#define PGD_ORDER	(__PGD_ORDER >= 0 ? __PGD_ORDER : 0)
+#define PGD_SIZE	(PAGESIZE() << PGD_ORDER)
+
+#define PGDIR_SHIFT	(2 * PAGESHIFT() + PTE_ORDER - PTE_T_LOG2)
+#define PGDIR_SIZE	(1UL << PGDIR_SHIFT)
+#define PGDIR_MASK	(~(PGDIR_SIZE-1))
+
+#define USER_PTRS_PER_PGD	(0x80000000UL/PGDIR_SIZE)
+
+#define PTRS_PER_PGD	(USER_PTRS_PER_PGD * 2)
+#define PTRS_PER_PTE	((PAGESIZE() << PTE_ORDER) / sizeof(pte_t))
+
+#define pgd_index(address)	(((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
+#define pte_offset(address)						\
+	(((address) >> PAGESHIFT()) & (PTRS_PER_PTE - 1))
+
+#define MIPS_CPU_RIXI	0x00800000llu
+
+static struct machine_specific mips_machine_specific = { 0 };
+
+static void
+mips_display_machine_stats(void)
+{
+        fprintf(fp, "          PAGE SIZE: %d\n", PAGESIZE());
+	fprintf(fp, "\n");
+
+#define PRINT_PAGE_FLAG(flag) 				\
+	if (flag)					\
+		fprintf(fp, "     %14s: %08lx\n", #flag, flag)
+
+	PRINT_PAGE_FLAG(_PAGE_PRESENT);
+	PRINT_PAGE_FLAG(_PAGE_READ);
+	PRINT_PAGE_FLAG(_PAGE_WRITE);
+	PRINT_PAGE_FLAG(_PAGE_ACCESSED);
+	PRINT_PAGE_FLAG(_PAGE_MODIFIED);
+	PRINT_PAGE_FLAG(_PAGE_GLOBAL);
+	PRINT_PAGE_FLAG(_PAGE_VALID);
+	PRINT_PAGE_FLAG(_PAGE_NO_READ);
+	PRINT_PAGE_FLAG(_PAGE_NO_EXEC);
+	PRINT_PAGE_FLAG(_PAGE_DIRTY);
+}
+
+static void
+mips_cmd_mach(void)
+{
+        int c;
+
+        while ((c = getopt(argcnt, args, "")) != EOF) {
+                switch(c) {
+                default:
+                        argerrs++;
+                        break;
+                }
+        }
+
+        if (argerrs)
+                cmd_usage(pc->curcmd, SYNOPSIS);
+
+	mips_display_machine_stats();
+}
+
+#define PGDIR_OFFSET(X) (((ulong)(X)) & (PGD_SIZE - 1))
+
+static void
+mips_init_page_flags(void)
+{
+	ulonglong cpu_options;
+	int rixi;
+	ulong shift = 0;
+	ulong addr;
+
+	addr = symbol_value("cpu_data") +
+	       MEMBER_OFFSET("cpuinfo_mips", "options");
+	readmem(addr, KVADDR, &cpu_options, sizeof(cpu_options),
+		"cpu_data[0].options", FAULT_ON_ERROR);
+
+	rixi = cpu_options & MIPS_CPU_RIXI;
+
+	_PAGE_PRESENT = 1UL << shift++;
+
+	if (!rixi)
+		_PAGE_READ = 1UL << shift++;
+
+	_PAGE_WRITE = 1UL << shift++;
+	_PAGE_ACCESSED = 1UL << shift++;
+	_PAGE_MODIFIED = 1UL << shift++;
+
+	if (rixi) {
+		_PAGE_NO_EXEC = 1UL << shift++;
+		_PAGE_NO_READ = 1UL << shift++;
+	}
+
+	_PAGE_GLOBAL = 1UL << shift++;
+	_PAGE_VALID = 1UL << shift++;
+	_PAGE_DIRTY = 1UL << shift++;
+
+	_PFN_SHIFT = PAGESHIFT() - 12 + shift + 3;
+}
+
+static int
+mips_translate_pte(ulong pte, void *physaddr, ulonglong pte64)
+{
+	char ptebuf[BUFSIZE];
+	char physbuf[BUFSIZE];
+	char buf[BUFSIZE];
+	int present;
+	ulong paddr;
+	int len1, len2, others;
+
+	present = pte & _PAGE_PRESENT;
+	paddr = (pte >> _PFN_SHIFT) << PAGESHIFT();
+
+	if (physaddr) {
+		*(ulong *)physaddr = PAGEBASE(pte);
+		return !!present;
+	}
+
+	sprintf(ptebuf, "%lx", pte);
+	len1 = MAX(strlen(ptebuf), strlen("PTE"));
+	fprintf(fp, "%s  ", mkstring(buf, len1, CENTER | LJUST, "PTE"));
+
+	if (!present)
+		return !!present;
+
+	sprintf(physbuf, "%lx", 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;
+
+#define CHECK_PAGE_FLAG(flag) 				\
+	if ((_PAGE_##flag) && (pte & _PAGE_##flag))	\
+		fprintf(fp, "%s" #flag, others++ ? "|" : "")
+
+	if (pte) {
+		CHECK_PAGE_FLAG(PRESENT);
+		CHECK_PAGE_FLAG(READ);
+		CHECK_PAGE_FLAG(WRITE);
+		CHECK_PAGE_FLAG(ACCESSED);
+		CHECK_PAGE_FLAG(MODIFIED);
+		CHECK_PAGE_FLAG(GLOBAL);
+		CHECK_PAGE_FLAG(VALID);
+		CHECK_PAGE_FLAG(NO_READ);
+		CHECK_PAGE_FLAG(NO_EXEC);
+		CHECK_PAGE_FLAG(DIRTY);
+	} else {
+		fprintf(fp, "no mapping");
+	}
+
+	fprintf(fp, ")\n");
+
+	return !!present;
+}
+
+static int
+mips_pgd_vtop(ulong *pgd, ulong vaddr, physaddr_t *paddr, int verbose)
+{
+	ulong invalid_pte_table = symbol_value("invalid_pte_table");
+	ulong *page_dir;
+	ulong pgd_pte, page_table;
+	ulong pte;
+	ulong pbase;
+
+	if (verbose) {
+		const char *segment;
+
+		if (vaddr < 0x80000000lu)
+			segment = "useg";
+		else if (vaddr < 0xa0000000lu)
+			segment = "kseg0";
+		else if (vaddr < 0xc0000000lu)
+			segment = "kseg1";
+		else if (vaddr < 0xe0000000lu)
+			segment = "ksseg";
+		else
+			segment = "kseg3";
+
+		fprintf(fp, "SEGMENT: %s\n", segment);
+	}
+
+	if (vaddr >= 0x80000000lu && vaddr < 0xc0000000lu) {
+		*paddr = VTOP(vaddr);
+		return TRUE;
+	}
+
+	if (verbose)
+		fprintf(fp, "PAGE DIRECTORY: %lx\n", (ulong)pgd);
+
+	page_dir = pgd + pgd_index(vaddr);
+
+	FILL_PGD(PAGEBASE(pgd), KVADDR, PGD_SIZE);
+	pgd_pte = ULONG(machdep->pgd + PGDIR_OFFSET(page_dir));
+
+	if (verbose)
+		fprintf(fp, "  PGD: %08lx => %lx\n", (ulong)page_dir, pgd_pte);
+
+	if (pgd_pte == invalid_pte_table) {
+		fprintf(fp, "invalid\n");
+		return FALSE;
+	}
+
+	page_table = VTOP(pgd_pte) + sizeof(pte_t) * pte_offset(vaddr);
+
+	FILL_PTBL(PAGEBASE(page_table), PHYSADDR, PAGESIZE());
+	pte = ULONG(machdep->ptbl + PAGEOFFSET(page_table));
+	if (verbose)
+		fprintf(fp, "  PTE: %08lx => %08lx\n", page_table, pte);
+
+	if (!(pte & _PAGE_PRESENT)) {
+		if (verbose) {
+			fprintf(fp, "\n");
+			mips_translate_pte((ulong)pte, 0, pte);
+		}
+		return FALSE;
+	}
+
+	pbase = (pte >> _PFN_SHIFT) << PAGESHIFT();
+	*paddr = pbase + PAGEOFFSET(vaddr);
+
+	if (verbose) {
+		fprintf(fp, " PAGE: %08lx\n\n", pbase);
+		mips_translate_pte(pte, 0, 0);
+	}
+
+	return TRUE;
+}
+
+static int
+mips_uvtop(struct task_context *tc, ulong vaddr, physaddr_t *paddr, int verbose)
+{
+	ulong *pgd;
+
+	if (!tc)
+		error(FATAL, "current context invalid\n");
+
+        if (is_kernel_thread(tc->task) && IS_KVADDR(vaddr)) {
+		ulong active_mm;
+
+		readmem(tc->task + OFFSET(task_struct_active_mm),
+			KVADDR, &active_mm, sizeof(void *),
+			"task active_mm contents", FAULT_ON_ERROR);
+
+		if (!active_mm)
+			error(FATAL,
+			     "no active_mm for this kernel thread\n");
+
+		readmem(active_mm + OFFSET(mm_struct_pgd),
+			KVADDR, &pgd, sizeof(long),
+			"mm_struct pgd", FAULT_ON_ERROR);
+	} else {
+		ulong mm;
+
+		mm = task_mm(tc->task, TRUE);
+		if (mm)
+			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);
+	}
+
+	return mips_pgd_vtop(pgd, vaddr, paddr, verbose);
+}
+
+static int
+mips_kvtop(struct task_context *tc, ulong kvaddr, physaddr_t *paddr, int verbose)
+{
+	if (!IS_KVADDR(kvaddr))
+		return FALSE;
+
+	if (!verbose && !IS_VMALLOC_ADDR(kvaddr)) {
+		*paddr = VTOP(kvaddr);
+		return TRUE;
+	}
+
+	return mips_pgd_vtop((ulong *)vt->kernel_pgd[0], kvaddr, paddr,
+			     verbose);
+}
+
+static void
+mips_dump_exception_stack(struct bt_info *bt, struct mips_pt_regs *regs)
+{
+	int i;
+	char buf[BUFSIZE];
+
+	for (i = 0; i < 32; i += 4) {
+		fprintf(fp, "    $%2d   : %08lx %08lx %08lx %08lx\n",
+			i, regs->regs[i], regs->regs[i+1],
+			regs->regs[i+2], regs->regs[i+3]);
+	}
+	fprintf(fp, "    Hi    : %08lx\n", regs->hi);
+	fprintf(fp, "    Lo    : %08lx\n", regs->lo);
+
+	value_to_symstr(regs->cp0_epc, buf, 16);
+	fprintf(fp, "    epc   : %08lx %s\n", regs->cp0_epc, buf);
+
+	value_to_symstr(regs->regs[31], buf, 16);
+	fprintf(fp, "    ra    : %08lx %s\n", regs->regs[31], buf);
+
+	fprintf(fp, "    Status: %08lx\n", regs->cp0_status);
+	fprintf(fp, "    Cause : %08lx\n", regs->cp0_cause);
+	fprintf(fp, "    BadVA : %08lx\n", regs->cp0_badvaddr);
+}
+
+struct mips_unwind_frame {
+	ulong sp;
+	ulong pc;
+	ulong ra;
+};
+
+static void
+mips_display_full_frame(struct bt_info *bt, struct mips_unwind_frame *current,
+			struct mips_unwind_frame *previous)
+{
+	ulong words, addr;
+	ulong *up;
+	char buf[BUFSIZE];
+	int i, u_idx;
+
+	if (!INSTACK(previous->sp, bt) || !INSTACK(current->sp, bt))
+		return;
+
+	words = (previous->sp - current->sp) / sizeof(ulong);
+
+	if (words == 0) {
+		fprintf(fp, "    (no frame)\n");
+		return;
+	}
+
+	addr = current->sp;
+	u_idx = (current->sp - bt->stackbase) / sizeof(ulong);
+	for (i = 0; i < words; i++, u_idx++) {
+		if ((i % 4) == 0)
+			fprintf(fp, "%s    %lx: ", i ? "\n" : "", addr);
+
+		up = (ulong *)(&bt->stackbuf[u_idx * sizeof(ulong)]);
+		fprintf(fp, "%s ", format_stack_entry(bt, buf, *up, 0));
+		addr += sizeof(ulong);
+	}
+	fprintf(fp, "\n");
+}
+
+static int
+mips_is_exception_entry(struct syment *sym)
+{
+	return STREQ(sym->name, "ret_from_exception") ||
+	       STREQ(sym->name, "ret_from_irq") ||
+	       STREQ(sym->name, "work_resched") ||
+	       STREQ(sym->name, "handle_sys");
+}
+
+static void
+mips_dump_backtrace_entry(struct bt_info *bt, struct syment *sym,
+			  struct mips_unwind_frame *current,
+			  struct mips_unwind_frame *previous, int level)
+{
+	const char *name = sym->name;
+	struct load_module *lm;
+	char *name_plus_offset;
+	char buf[BUFSIZE];
+
+	name_plus_offset = NULL;
+	if (bt->flags & BT_SYMBOL_OFFSET) {
+		struct syment *symp;
+		ulong symbol_offset;
+
+		symp = value_search(current->pc, &symbol_offset);
+
+		if (symp && symbol_offset)
+			name_plus_offset =
+				value_to_symstr(current->pc, buf, bt->radix);
+	}
+
+	fprintf(fp, "%s#%d [%8lx] %s at %lx", level < 10 ? " " : "", level,
+		current->sp, name_plus_offset ? name_plus_offset : name,
+		current->pc);
+
+	if (module_symbol(current->pc, NULL, &lm, NULL, 0))
+		fprintf(fp, " [%s]", lm->mod_name);
+
+	fprintf(fp, "\n");
+
+	if (bt->flags & BT_LINE_NUMBERS) {
+		char buf[BUFSIZE];
+
+		get_line_number(current->pc, buf, FALSE);
+		if (strlen(buf))
+			fprintf(fp, "    %s\n", buf);
+	}
+
+	if (mips_is_exception_entry(sym)) {
+		struct mips_pt_regs ptregs;
+
+		GET_STACK_DATA(current->sp, &ptregs, sizeof(ptregs));
+		mips_dump_exception_stack(bt, &ptregs);
+	}
+
+	if (bt->flags & BT_FULL) {
+		fprintf(fp, "    "
+			"[PC: %08lx RA: %08lx SP: %08lx SIZE: %ld]\n",
+			current->pc, current->ra, current->sp,
+			previous->sp - current->sp);
+		mips_display_full_frame(bt, current, previous);
+	}
+}
+
+
+static void
+mips_analyze_function(ulong start, ulong offset,
+		      struct mips_unwind_frame *current,
+		      struct mips_unwind_frame *previous)
+{
+	ulong rapos = 0;
+	ulong spadjust = 0;
+	ulong *funcbuf, *ip;
+	ulong i;
+
+	if (CRASHDEBUG(8))
+		fprintf(fp, "%s: start %#lx offset %#lx\n",
+			__func__, start, offset);
+
+	if (!offset) {
+		previous->sp = current->sp;
+		return;
+	}
+
+	ip = funcbuf = (ulong *)GETBUF(offset);
+	if (!readmem(start, KVADDR, funcbuf, offset,
+		     "mips_analyze_function", RETURN_ON_ERROR)) {
+		FREEBUF(funcbuf);
+		error(FATAL, "Cannot read function at %8x", start);
+		return;
+	}
+
+	for (i = 0; i < offset; i += 4) {
+		ulong insn = *ip;
+		ulong high = (insn >> 16) & 0xffff;
+		ulong low = insn & 0xffff;
+
+		if (CRASHDEBUG(8))
+			fprintf(fp, "insn @ %#lx = %#lx\n", start + i, insn);
+
+		if (high == 0x27bd) { /* ADDIU sp, sp, imm */
+			if (!(low & 0x8000))
+				break;
+
+			spadjust += 0x10000 - low;
+			if (CRASHDEBUG(8))
+				fprintf(fp, "spadjust = %lu\n", spadjust);
+		} else if (high == 0xafbf) { /* SW RA, imm(SP) */
+			rapos = current->sp + low;
+			if (CRASHDEBUG(8))
+				fprintf(fp, "rapos %lx\n", rapos);
+			break;
+		}
+
+		ip++;
+	}
+
+	FREEBUF(funcbuf);
+
+	previous->sp = current->sp + spadjust;
+
+	if (rapos && !readmem(rapos, KVADDR, &current->ra,
+			      sizeof(current->ra), "RA from stack",
+			      RETURN_ON_ERROR)) {
+		error(FATAL, "Cannot read RA from stack %lx", rapos);
+		return;
+	}
+}
+
+static void
+mips_back_trace_cmd(struct bt_info *bt)
+{
+	struct mips_unwind_frame current, previous;
+	int level = 0;
+
+	previous.sp = previous.pc = previous.ra = 0;
+
+	current.pc = bt->instptr;
+	current.sp = bt->stkptr;
+	current.ra = 0;
+
+	if (bt->machdep) {
+		struct mips_regset *regs = bt->machdep;
+		previous.pc = current.ra = regs->regs[31];
+	}
+
+	while (INSTACK(current.sp, bt)) {
+		struct syment *symbol;
+		ulong offset;
+
+		if (CRASHDEBUG(8))
+			fprintf(fp, "level %d pc %#lx ra %#lx sp %lx\n",
+				level, current.pc, current.ra, current.sp);
+
+		if (!IS_KVADDR(current.pc))
+			return;
+
+		symbol = value_search(current.pc, &offset);
+		if (!symbol) {
+			error(FATAL, "PC is unknown symbol (%lx)", current.pc);
+			return;
+		}
+
+		/*
+		 * If we get an address which points to the start of a
+		 * function, then it could one of the following:
+		 *
+		 *  - we are dealing with a noreturn function.  The last call
+		 *    from a noreturn function has an an ra which points to the
+		 *    start of the function after it.  This is common in the
+		 *    oops callchain because of die() which is annotated as
+		 *    noreturn.
+		 *
+		 *  - we have taken an exception at the start of this function.
+		 *    In this case we already have the RA in current.ra.
+		 *
+		 *  - we are in one of these routines which appear with zero
+		 *    offset in manually-constructed stack frames:
+		 *
+		 *    * ret_from_exception
+		 *    * ret_from_irq
+		 *    * ret_from_fork
+		 *    * ret_from_kernel_thread
+		 */
+		if (!current.ra && !offset && !STRNEQ(symbol->name, "ret_from")) {
+			if (CRASHDEBUG(8))
+				fprintf(fp, "zero offset at %s, try previous symbol\n",
+					symbol->name);
+
+			symbol = value_search(current.pc - 4, &offset);
+			if (!symbol) {
+				error(FATAL, "PC is unknown symbol (%lx)", current.pc);
+				return;
+			}
+		}
+
+		if (mips_is_exception_entry(symbol)) {
+			struct mips_pt_regs ptregs;
+
+			GET_STACK_DATA(current.sp, &ptregs, sizeof(ptregs));
+
+			previous.ra = ptregs.regs[31];
+			previous.sp = ptregs.regs[29];
+			current.ra = ptregs.cp0_epc;
+
+			if (CRASHDEBUG(8))
+				fprintf(fp, "exception pc %#lx ra %#lx sp %lx\n",
+					previous.pc, previous.ra, previous.sp);
+		} else {
+			mips_analyze_function(symbol->value, offset, &current, &previous);
+		}
+
+		mips_dump_backtrace_entry(bt, symbol, &current, &previous, level++);
+		if (!current.ra)
+			break;
+
+		current.pc = current.ra;
+		current.sp = previous.sp;
+		current.ra = previous.ra;
+
+		previous.sp = previous.pc = previous.ra = 0;
+	}
+}
+
+static void
+mips_dumpfile_stack_frame(struct bt_info *bt, ulong *nip, ulong *ksp)
+{
+	struct mips_regset *regs;
+
+	regs = bt->machdep;
+	if (!regs) {
+		fprintf(fp, "0%lx: Register values not available\n",
+			bt->task);
+		return;
+	}
+
+	if (nip)
+		*nip = regs->regs[40];
+	if (ksp)
+		*ksp = regs->regs[29];
+}
+
+static int
+mips_get_frame(struct bt_info *bt, ulong *pcp, ulong *spp)
+{
+	if (!bt->tc || !(tt->flags & THREAD_INFO))
+		return FALSE;
+
+        if (!readmem(bt->task + OFFSET(task_struct_thread_reg31),
+		     KVADDR, pcp, sizeof(*pcp),
+		     "thread_struct.regs31",
+		     RETURN_ON_ERROR)) {
+		return FALSE;
+	}
+
+        if (!readmem(bt->task + OFFSET(task_struct_thread_reg29),
+		     KVADDR, spp, sizeof(*spp),
+		     "thread_struct.regs29",
+		     RETURN_ON_ERROR)) {
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static void
+mips_stackframe_init(void)
+{
+	long task_struct_thread = MEMBER_OFFSET("task_struct", "thread");
+	long thread_reg29 = MEMBER_OFFSET("thread_struct", "reg29");
+	long thread_reg31 = MEMBER_OFFSET("thread_struct", "reg31");
+
+	if ((task_struct_thread == INVALID_OFFSET) ||
+	    (thread_reg29 == INVALID_OFFSET) ||
+	    (thread_reg31 == INVALID_OFFSET)) {
+		error(FATAL,
+		      "cannot determine thread_struct offsets\n");
+		return;
+	}
+
+	ASSIGN_OFFSET(task_struct_thread_reg29) =
+		task_struct_thread + thread_reg29;
+	ASSIGN_OFFSET(task_struct_thread_reg31) =
+		task_struct_thread + thread_reg31;
+}
+
+static void
+mips_get_stack_frame(struct bt_info *bt, ulong *pcp, ulong *spp)
+{
+	*pcp = 0;
+	*spp = 0;
+
+	if (DUMPFILE() && is_task_active(bt->task))
+		mips_dumpfile_stack_frame(bt, pcp, spp);
+	else
+		mips_get_frame(bt, pcp, spp);
+
+}
+
+static int
+mips_eframe_search(struct bt_info *bt)
+{
+	return error(FATAL, "%s: not implemented\n", __func__);
+}
+
+static ulong
+mips_get_task_pgd(ulong task)
+{
+	return error(FATAL, "%s: not implemented\n", __func__);
+}
+
+static int
+mips_is_task_addr(ulong task)
+{
+	if (tt->flags & THREAD_INFO)
+		return IS_KVADDR(task);
+
+	return (IS_KVADDR(task) && ALIGNED_STACK_OFFSET(task) == 0);
+}
+
+static ulong
+mips_processor_speed(void)
+{
+	return 0;
+}
+
+static int
+mips_get_smp_cpus(void)
+{
+	return (get_cpus_online() > 0) ? get_cpus_online() : kt->cpus;
+}
+
+static ulong
+mips_vmalloc_start(void)
+{
+	return first_vmalloc_address();
+}
+
+static int
+mips_verify_symbol(const char *name, ulong value, char type)
+{
+	if (CRASHDEBUG(8) && name && strlen(name))
+		fprintf(fp, "%08lx %s\n", value, name);
+
+	if (STREQ(name, "_text"))
+		machdep->flags |= KSYMS_START;
+
+	return (name && strlen(name) && (machdep->flags & KSYMS_START) &&
+	        !STRNEQ(name, "__func__.") && !STRNEQ(name, "__crc_"));
+}
+
+void
+mips_dump_machdep_table(ulong arg)
+{
+	int others = 0;
+
+	fprintf(fp, "              flags: %lx (", machdep->flags);
+	if (machdep->flags & KSYMS_START)
+		fprintf(fp, "%sKSYMS_START", 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, "        pgdir_shift: %d\n", PGDIR_SHIFT);
+	fprintf(fp, "       ptrs_per_pgd: %lu\n", PTRS_PER_PGD);
+	fprintf(fp, "       ptrs_per_pte: %d\n", PTRS_PER_PTE);
+	fprintf(fp, "          stacksize: %ld\n", machdep->stacksize);
+	fprintf(fp, "            memsize: %lld (0x%llx)\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: mips_eframe_search()\n");
+	fprintf(fp, "         back_trace: mips_back_trace_cmd()\n");
+	fprintf(fp, "    processor_speed: mips_processor_speed()\n");
+	fprintf(fp, "              uvtop: mips_uvtop()\n");
+	fprintf(fp, "              kvtop: mips_kvtop()\n");
+	fprintf(fp, "       get_task_pgd: mips_get_task_pgd()\n");
+	fprintf(fp, "           dump_irq: generic_dump_irq()\n");
+	fprintf(fp, "    show_interrupts: generic_show_interrupts()\n");
+	fprintf(fp, "   get_irq_affinity: generic_get_irq_affinity()\n");
+	fprintf(fp, "    get_stack_frame: mips_get_stack_frame()\n");
+	fprintf(fp, "      get_stackbase: generic_get_stackbase()\n");
+	fprintf(fp, "       get_stacktop: generic_get_stacktop()\n");
+	fprintf(fp, "      translate_pte: mips_translate_pte()\n");
+	fprintf(fp, "        memory_size: generic_memory_size()\n");
+	fprintf(fp, "      vmalloc_start: mips_vmalloc_start()\n");
+	fprintf(fp, "       is_task_addr: mips_is_task_addr()\n");
+	fprintf(fp, "      verify_symbol: mips_verify_symbol()\n");
+	fprintf(fp, "         dis_filter: generic_dis_filter()\n");
+	fprintf(fp, "           cmd_mach: mips_cmd_mach()\n");
+	fprintf(fp, "       get_smp_cpus: mips_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: NULL\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, "  section_size_bits: %ld\n", machdep->section_size_bits);
+	fprintf(fp, "   max_physmem_bits: %ld\n", machdep->max_physmem_bits);
+	fprintf(fp, "  sections_per_root: %ld\n", machdep->sections_per_root);
+	fprintf(fp, "           machspec: %lx\n", (ulong)machdep->machspec);
+}
+
+static ulong
+mips_get_page_size(void)
+{
+	struct syment *spd, *next = NULL;
+
+	spd = symbol_search("swapper_pg_dir");
+	if (spd)
+		next = next_symbol(NULL, spd);
+
+	if (!spd || !next)
+		return memory_page_size();
+
+	return next->value - spd->value;
+}
+
+void
+mips_init(int when)
+{
+#if defined(__i386__) || defined(__x86_64__)
+	if (ACTIVE())
+		error(FATAL, "compiled for the MIPS architecture\n");
+#endif
+
+	switch (when) {
+	case PRE_SYMTAB:
+		machdep->verify_symbol = mips_verify_symbol;
+		machdep->machspec = &mips_machine_specific;
+		if (pc->flags & KERNEL_DEBUG_QUERY)
+			return;
+		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:
+		machdep->pagesize = mips_get_page_size();
+		machdep->pageshift = ffs(machdep->pagesize) - 1;
+		machdep->pageoffset = machdep->pagesize - 1;
+		machdep->pagemask = ~((ulonglong)machdep->pageoffset);
+		if (machdep->pagesize >= 16384)
+			machdep->stacksize = machdep->pagesize;
+		else
+			machdep->stacksize = machdep->pagesize * 2;
+
+		if ((machdep->pgd = malloc(PGD_SIZE)) == NULL)
+			error(FATAL, "cannot malloc pgd space.");
+		if ((machdep->ptbl = malloc(PAGESIZE())) == NULL)
+			error(FATAL, "cannot malloc ptbl space.");
+
+	        machdep->kvbase = 0x80000000;
+		machdep->identity_map_base = machdep->kvbase;
+                machdep->is_kvaddr = generic_is_kvaddr;
+                machdep->is_uvaddr = generic_is_uvaddr;
+	        machdep->uvtop = mips_uvtop;
+	        machdep->kvtop = mips_kvtop;
+		machdep->vmalloc_start = mips_vmalloc_start;
+	        machdep->eframe_search = mips_eframe_search;
+	        machdep->back_trace = mips_back_trace_cmd;
+	        machdep->processor_speed = mips_processor_speed;
+	        machdep->get_task_pgd = mips_get_task_pgd;
+		machdep->get_stack_frame = mips_get_stack_frame;
+		machdep->get_stackbase = generic_get_stackbase;
+		machdep->get_stacktop = generic_get_stacktop;
+		machdep->translate_pte = mips_translate_pte;
+		machdep->memory_size = generic_memory_size;
+		machdep->is_task_addr = mips_is_task_addr;
+		machdep->dis_filter = generic_dis_filter;
+		machdep->cmd_mach = mips_cmd_mach;
+		machdep->get_smp_cpus = mips_get_smp_cpus;
+		machdep->value_to_symbol = generic_machdep_value_to_symbol;
+                machdep->init_kernel_pgd = NULL;
+		break;
+	case POST_GDB:
+		mips_init_page_flags();
+		machdep->dump_irq = generic_dump_irq;
+		machdep->show_interrupts = generic_show_interrupts;
+		machdep->get_irq_affinity = generic_get_irq_affinity;
+		ARRAY_LENGTH_INIT(machdep->nr_irqs, irq_desc,
+			"irq_desc", NULL, 0);
+		mips_stackframe_init();
+		break;
+	}
+}
+
+#endif /* MIPS */
diff --git a/netdump.c b/netdump.c
index ce69310..410455b 100644
--- a/netdump.c
+++ b/netdump.c
@@ -198,6 +198,12 @@ is_netdump(char *file, ulong source_query)
 				goto bailout;
 			break;
 
+		case EM_MIPS:
+			if (machine_type_mismatch(file, "MIPS", NULL,
+			    source_query))
+				goto bailout;
+			break;
+
 		default:
 			if (machine_type_mismatch(file, "(unknown)", NULL,
 			    source_query))
@@ -2390,6 +2396,10 @@ get_netdump_regs(struct bt_info *bt, ulong *eip, ulong *esp)
 		return get_netdump_regs_arm64(bt, eip, esp);
 		break;
 
+	case EM_MIPS:
+		return get_netdump_regs_32(bt, eip, esp);
+		break;
+
 	default:
 		error(FATAL, 
 		   "support for ELF machine type %d not available\n",
diff --git a/symbols.c b/symbols.c
index 6dfd769..59312e6 100644
--- a/symbols.c
+++ b/symbols.c
@@ -3236,6 +3236,11 @@ is_kernel(char *file)
 				goto bailout;
 			break;
 
+		case EM_MIPS:
+			if (machine_type_mismatch(file, "MIPS", NULL, 0))
+				goto bailout;
+			break;
+
 		default:
 			if (machine_type_mismatch(file, "(unknown)", NULL, 0))
 				goto bailout;
@@ -7813,6 +7818,10 @@ dump_offset_table(char *spec, ulong makestruct)
                 OFFSET(task_struct_thread_esp));
         fprintf(fp, "        task_struct_thread_ksp: %ld\n",
                 OFFSET(task_struct_thread_ksp));
+        fprintf(fp, "      task_struct_thread_reg29: %ld\n",
+                OFFSET(task_struct_thread_reg29));
+        fprintf(fp, "      task_struct_thread_reg31: %ld\n",
+                OFFSET(task_struct_thread_reg31));
 	fprintf(fp, " task_struct_thread_context_fp: %ld\n",
 		OFFSET(task_struct_thread_context_fp));
 	fprintf(fp, " task_struct_thread_context_sp: %ld\n",
-- 
2.1.4




More information about the Crash-utility mailing list