Blame mips.c

Packit bf408e
/*
Packit bf408e
 * mips.c - core analysis suite
Packit bf408e
 *
Packit bf408e
 * Copyright (C) 2015 Rabin Vincent <rabin rab in>
Packit bf408e
 *
Packit bf408e
 * This program is free software; you can redistribute it and/or modify
Packit bf408e
 * it under the terms of the GNU General Public License as published by
Packit bf408e
 * the Free Software Foundation; either version 2 of the License, or
Packit bf408e
 * (at your option) any later version.
Packit bf408e
 *
Packit bf408e
 * This program is distributed in the hope that it will be useful,
Packit bf408e
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit bf408e
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit bf408e
 * GNU General Public License for more details.
Packit bf408e
 */
Packit bf408e
Packit bf408e
#ifdef MIPS
Packit bf408e
Packit bf408e
#include <elf.h>
Packit bf408e
#include "defs.h"
Packit bf408e
Packit bf408e
/* From arch/mips/asm/include/pgtable{,-32}.h */
Packit bf408e
typedef ulong pgd_t;
Packit bf408e
typedef ulong pte_t;
Packit bf408e
Packit bf408e
#define PTE_ORDER	0
Packit bf408e
Packit bf408e
#define PGD_T_LOG2	(__builtin_ffs(sizeof(pgd_t)) - 1)
Packit bf408e
#define PTE_T_LOG2	(__builtin_ffs(sizeof(pte_t)) - 1)
Packit bf408e
Packit bf408e
#define __PGD_ORDER	(32 - 3 * (int)PAGESHIFT() + PGD_T_LOG2 + PTE_T_LOG2)
Packit bf408e
#define PGD_ORDER	(__PGD_ORDER >= 0 ? __PGD_ORDER : 0)
Packit bf408e
#define PGD_SIZE	(PAGESIZE() << PGD_ORDER)
Packit bf408e
Packit bf408e
#define PGDIR_SHIFT	(2 * PAGESHIFT() + PTE_ORDER - PTE_T_LOG2)
Packit bf408e
#define PGDIR_SIZE	(1UL << PGDIR_SHIFT)
Packit bf408e
#define PGDIR_MASK	(~(PGDIR_SIZE-1))
Packit bf408e
Packit bf408e
#define USER_PTRS_PER_PGD	(0x80000000UL/PGDIR_SIZE)
Packit bf408e
Packit bf408e
#define PTRS_PER_PGD	(USER_PTRS_PER_PGD * 2)
Packit bf408e
#define PTRS_PER_PTE	((PAGESIZE() << PTE_ORDER) / sizeof(pte_t))
Packit bf408e
Packit bf408e
#define pgd_index(address)	(((address) >> PGDIR_SHIFT) & (PTRS_PER_PGD-1))
Packit bf408e
#define pte_offset(address)						\
Packit bf408e
	(((address) >> PAGESHIFT()) & (PTRS_PER_PTE - 1))
Packit bf408e
Packit bf408e
#define MIPS_CPU_RIXI	0x00800000llu
Packit bf408e
Packit bf408e
#define MIPS32_EF_R0		6
Packit bf408e
#define MIPS32_EF_R29		35
Packit bf408e
#define MIPS32_EF_R31		37
Packit bf408e
#define MIPS32_EF_LO		38
Packit bf408e
#define MIPS32_EF_HI		39
Packit bf408e
#define MIPS32_EF_CP0_EPC	40
Packit bf408e
#define MIPS32_EF_CP0_BADVADDR	41
Packit bf408e
#define MIPS32_EF_CP0_STATUS	42
Packit bf408e
#define MIPS32_EF_CP0_CAUSE	43
Packit bf408e
Packit bf408e
static struct machine_specific mips_machine_specific = { 0 };
Packit bf408e
Packit bf408e
/*
Packit bf408e
 * Holds registers during the crash.
Packit bf408e
 */
Packit bf408e
static struct mips_regset *panic_task_regs;
Packit bf408e
Packit bf408e
static void
Packit bf408e
mips_display_machine_stats(void)
Packit bf408e
{
Packit bf408e
	fprintf(fp, "                 HZ: %d\n", machdep->hz);
Packit bf408e
        fprintf(fp, "          PAGE SIZE: %d\n", PAGESIZE());
Packit bf408e
	fprintf(fp, "\n");
Packit bf408e
Packit bf408e
#define PRINT_PAGE_FLAG(flag) 				\
Packit bf408e
	if (flag)					\
Packit bf408e
		fprintf(fp, "     %14s: %08lx\n", #flag, flag)
Packit bf408e
Packit bf408e
	PRINT_PAGE_FLAG(_PAGE_PRESENT);
Packit bf408e
	PRINT_PAGE_FLAG(_PAGE_READ);
Packit bf408e
	PRINT_PAGE_FLAG(_PAGE_WRITE);
Packit bf408e
	PRINT_PAGE_FLAG(_PAGE_ACCESSED);
Packit bf408e
	PRINT_PAGE_FLAG(_PAGE_MODIFIED);
Packit bf408e
	PRINT_PAGE_FLAG(_PAGE_GLOBAL);
Packit bf408e
	PRINT_PAGE_FLAG(_PAGE_VALID);
Packit bf408e
	PRINT_PAGE_FLAG(_PAGE_NO_READ);
Packit bf408e
	PRINT_PAGE_FLAG(_PAGE_NO_EXEC);
Packit bf408e
	PRINT_PAGE_FLAG(_PAGE_DIRTY);
Packit bf408e
}
Packit bf408e
Packit bf408e
static void
Packit bf408e
mips_cmd_mach(void)
Packit bf408e
{
Packit bf408e
        int c;
Packit bf408e
Packit bf408e
        while ((c = getopt(argcnt, args, "")) != EOF) {
Packit bf408e
                switch(c) {
Packit bf408e
                default:
Packit bf408e
                        argerrs++;
Packit bf408e
                        break;
Packit bf408e
                }
Packit bf408e
        }
Packit bf408e
Packit bf408e
        if (argerrs)
Packit bf408e
                cmd_usage(pc->curcmd, SYNOPSIS);
Packit bf408e
Packit bf408e
	mips_display_machine_stats();
Packit bf408e
}
Packit bf408e
Packit bf408e
#define PGDIR_OFFSET(X) (((ulong)(X)) & (PGD_SIZE - 1))
Packit bf408e
Packit bf408e
static void
Packit bf408e
mips_init_page_flags(void)
Packit bf408e
{
Packit bf408e
	ulong shift = 0;
Packit bf408e
Packit bf408e
	_PAGE_PRESENT = 1UL << shift++;
Packit bf408e
Packit bf408e
	if (THIS_KERNEL_VERSION >= LINUX(4,1,0)) {
Packit bf408e
		_PAGE_WRITE = 1UL << shift++;
Packit bf408e
		_PAGE_ACCESSED = 1UL << shift++;
Packit bf408e
		_PAGE_MODIFIED = 1UL << shift++;
Packit bf408e
		_PAGE_NO_EXEC = 1UL << shift++;
Packit bf408e
		_PAGE_READ = _PAGE_NO_READ = 1UL << shift++;
Packit bf408e
	} else {
Packit bf408e
		ulonglong cpu_options;
Packit bf408e
		int rixi;
Packit bf408e
		ulong addr;
Packit bf408e
Packit bf408e
		addr = symbol_value("cpu_data") +
Packit bf408e
		       MEMBER_OFFSET("cpuinfo_mips", "options");
Packit bf408e
		readmem(addr, KVADDR, &cpu_options, sizeof(cpu_options),
Packit bf408e
			"cpu_data[0].options", FAULT_ON_ERROR);
Packit bf408e
Packit bf408e
		rixi = cpu_options & MIPS_CPU_RIXI;
Packit bf408e
Packit bf408e
		if (!rixi)
Packit bf408e
			_PAGE_READ = 1UL << shift++;
Packit bf408e
Packit bf408e
		_PAGE_WRITE = 1UL << shift++;
Packit bf408e
		_PAGE_ACCESSED = 1UL << shift++;
Packit bf408e
		_PAGE_MODIFIED = 1UL << shift++;
Packit bf408e
Packit bf408e
		if (rixi) {
Packit bf408e
			_PAGE_NO_EXEC = 1UL << shift++;
Packit bf408e
			_PAGE_NO_READ = 1UL << shift++;
Packit bf408e
		}
Packit bf408e
	}
Packit bf408e
Packit bf408e
	_PAGE_GLOBAL = 1UL << shift++;
Packit bf408e
	_PAGE_VALID = 1UL << shift++;
Packit bf408e
	_PAGE_DIRTY = 1UL << shift++;
Packit bf408e
Packit bf408e
	_PFN_SHIFT = PAGESHIFT() - 12 + shift + 3;
Packit bf408e
}
Packit bf408e
Packit bf408e
static int
Packit bf408e
mips_translate_pte(ulong pte, void *physaddr, ulonglong pte64)
Packit bf408e
{
Packit bf408e
	char ptebuf[BUFSIZE];
Packit bf408e
	char physbuf[BUFSIZE];
Packit bf408e
	char buf[BUFSIZE];
Packit bf408e
	int present;
Packit bf408e
	ulong paddr;
Packit bf408e
	int len1, len2, others;
Packit bf408e
Packit bf408e
	present = pte & _PAGE_PRESENT;
Packit bf408e
	paddr = (pte >> _PFN_SHIFT) << PAGESHIFT();
Packit bf408e
Packit bf408e
	if (physaddr) {
Packit bf408e
		*(ulong *)physaddr = PAGEBASE(pte);
Packit bf408e
		return !!present;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	sprintf(ptebuf, "%lx", pte);
Packit bf408e
	len1 = MAX(strlen(ptebuf), strlen("PTE"));
Packit bf408e
	fprintf(fp, "%s  ", mkstring(buf, len1, CENTER | LJUST, "PTE"));
Packit bf408e
Packit bf408e
	if (!present)
Packit bf408e
		return !!present;
Packit bf408e
Packit bf408e
	sprintf(physbuf, "%lx", paddr);
Packit bf408e
	len2 = MAX(strlen(physbuf), strlen("PHYSICAL"));
Packit bf408e
	fprintf(fp, "%s  ", mkstring(buf, len2, CENTER | LJUST, "PHYSICAL"));
Packit bf408e
Packit bf408e
	fprintf(fp, "FLAGS\n");
Packit bf408e
	fprintf(fp, "%s  %s  ",
Packit bf408e
		mkstring(ptebuf, len1, CENTER | RJUST, NULL),
Packit bf408e
		mkstring(physbuf, len2, CENTER | RJUST, NULL));
Packit bf408e
Packit bf408e
	fprintf(fp, "(");
Packit bf408e
	others = 0;
Packit bf408e
Packit bf408e
#define CHECK_PAGE_FLAG(flag) 				\
Packit bf408e
	if ((_PAGE_##flag) && (pte & _PAGE_##flag))	\
Packit bf408e
		fprintf(fp, "%s" #flag, others++ ? "|" : "")
Packit bf408e
Packit bf408e
	if (pte) {
Packit bf408e
		CHECK_PAGE_FLAG(PRESENT);
Packit bf408e
		CHECK_PAGE_FLAG(READ);
Packit bf408e
		CHECK_PAGE_FLAG(WRITE);
Packit bf408e
		CHECK_PAGE_FLAG(ACCESSED);
Packit bf408e
		CHECK_PAGE_FLAG(MODIFIED);
Packit bf408e
		CHECK_PAGE_FLAG(GLOBAL);
Packit bf408e
		CHECK_PAGE_FLAG(VALID);
Packit bf408e
		CHECK_PAGE_FLAG(NO_READ);
Packit bf408e
		CHECK_PAGE_FLAG(NO_EXEC);
Packit bf408e
		CHECK_PAGE_FLAG(DIRTY);
Packit bf408e
	} else {
Packit bf408e
		fprintf(fp, "no mapping");
Packit bf408e
	}
Packit bf408e
Packit bf408e
	fprintf(fp, ")\n");
Packit bf408e
Packit bf408e
	return !!present;
Packit bf408e
}
Packit bf408e
Packit bf408e
static int
Packit bf408e
mips_pgd_vtop(ulong *pgd, ulong vaddr, physaddr_t *paddr, int verbose)
Packit bf408e
{
Packit bf408e
	ulong invalid_pte_table = symbol_value("invalid_pte_table");
Packit bf408e
	ulong *page_dir;
Packit bf408e
	ulong pgd_pte, page_table;
Packit bf408e
	ulong pte;
Packit bf408e
	ulong pbase;
Packit bf408e
Packit bf408e
	if (verbose) {
Packit bf408e
		const char *segment;
Packit bf408e
Packit bf408e
		if (vaddr < 0x80000000lu)
Packit bf408e
			segment = "useg";
Packit bf408e
		else if (vaddr < 0xa0000000lu)
Packit bf408e
			segment = "kseg0";
Packit bf408e
		else if (vaddr < 0xc0000000lu)
Packit bf408e
			segment = "kseg1";
Packit bf408e
		else if (vaddr < 0xe0000000lu)
Packit bf408e
			segment = "ksseg";
Packit bf408e
		else
Packit bf408e
			segment = "kseg3";
Packit bf408e
Packit bf408e
		fprintf(fp, "SEGMENT: %s\n", segment);
Packit bf408e
	}
Packit bf408e
Packit bf408e
	if (vaddr >= 0x80000000lu && vaddr < 0xc0000000lu) {
Packit bf408e
		*paddr = VTOP(vaddr);
Packit bf408e
		return TRUE;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	if (verbose)
Packit bf408e
		fprintf(fp, "PAGE DIRECTORY: %lx\n", (ulong)pgd);
Packit bf408e
Packit bf408e
	page_dir = pgd + pgd_index(vaddr);
Packit bf408e
Packit bf408e
	FILL_PGD(PAGEBASE(pgd), KVADDR, PGD_SIZE);
Packit bf408e
	pgd_pte = ULONG(machdep->pgd + PGDIR_OFFSET(page_dir));
Packit bf408e
Packit bf408e
	if (verbose)
Packit bf408e
		fprintf(fp, "  PGD: %08lx => %lx\n", (ulong)page_dir, pgd_pte);
Packit bf408e
Packit bf408e
	if (pgd_pte == invalid_pte_table) {
Packit bf408e
		fprintf(fp, "invalid\n");
Packit bf408e
		return FALSE;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	page_table = VTOP(pgd_pte) + sizeof(pte_t) * pte_offset(vaddr);
Packit bf408e
Packit bf408e
	FILL_PTBL(PAGEBASE(page_table), PHYSADDR, PAGESIZE());
Packit bf408e
	pte = ULONG(machdep->ptbl + PAGEOFFSET(page_table));
Packit bf408e
	if (verbose)
Packit bf408e
		fprintf(fp, "  PTE: %08lx => %08lx\n", page_table, pte);
Packit bf408e
Packit bf408e
	if (!(pte & _PAGE_PRESENT)) {
Packit bf408e
		if (verbose) {
Packit bf408e
			fprintf(fp, "\n");
Packit bf408e
			mips_translate_pte((ulong)pte, 0, pte);
Packit bf408e
		}
Packit bf408e
		return FALSE;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	pbase = (pte >> _PFN_SHIFT) << PAGESHIFT();
Packit bf408e
	*paddr = pbase + PAGEOFFSET(vaddr);
Packit bf408e
Packit bf408e
	if (verbose) {
Packit bf408e
		fprintf(fp, " PAGE: %08lx\n\n", pbase);
Packit bf408e
		mips_translate_pte(pte, 0, 0);
Packit bf408e
	}
Packit bf408e
Packit bf408e
	return TRUE;
Packit bf408e
}
Packit bf408e
Packit bf408e
static int
Packit bf408e
mips_uvtop(struct task_context *tc, ulong vaddr, physaddr_t *paddr, int verbose)
Packit bf408e
{
Packit bf408e
	ulong *pgd;
Packit bf408e
Packit bf408e
	if (!tc)
Packit bf408e
		error(FATAL, "current context invalid\n");
Packit bf408e
Packit bf408e
        if (is_kernel_thread(tc->task) && IS_KVADDR(vaddr)) {
Packit bf408e
		ulong active_mm;
Packit bf408e
Packit bf408e
		readmem(tc->task + OFFSET(task_struct_active_mm),
Packit bf408e
			KVADDR, &active_mm, sizeof(void *),
Packit bf408e
			"task active_mm contents", FAULT_ON_ERROR);
Packit bf408e
Packit bf408e
		if (!active_mm)
Packit bf408e
			error(FATAL,
Packit bf408e
			     "no active_mm for this kernel thread\n");
Packit bf408e
Packit bf408e
		readmem(active_mm + OFFSET(mm_struct_pgd),
Packit bf408e
			KVADDR, &pgd, sizeof(long),
Packit bf408e
			"mm_struct pgd", FAULT_ON_ERROR);
Packit bf408e
	} else {
Packit bf408e
		ulong mm;
Packit bf408e
Packit bf408e
		mm = task_mm(tc->task, TRUE);
Packit bf408e
		if (mm)
Packit bf408e
			pgd = ULONG_PTR(tt->mm_struct + OFFSET(mm_struct_pgd));
Packit bf408e
		else
Packit bf408e
			readmem(tc->mm_struct + OFFSET(mm_struct_pgd),
Packit bf408e
				KVADDR, &pgd, sizeof(long), "mm_struct pgd",
Packit bf408e
				FAULT_ON_ERROR);
Packit bf408e
	}
Packit bf408e
Packit bf408e
	return mips_pgd_vtop(pgd, vaddr, paddr, verbose);
Packit bf408e
}
Packit bf408e
Packit bf408e
static int
Packit bf408e
mips_kvtop(struct task_context *tc, ulong kvaddr, physaddr_t *paddr, int verbose)
Packit bf408e
{
Packit bf408e
	if (!IS_KVADDR(kvaddr))
Packit bf408e
		return FALSE;
Packit bf408e
Packit bf408e
	if (!verbose && !IS_VMALLOC_ADDR(kvaddr)) {
Packit bf408e
		*paddr = VTOP(kvaddr);
Packit bf408e
		return TRUE;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	return mips_pgd_vtop((ulong *)vt->kernel_pgd[0], kvaddr, paddr,
Packit bf408e
			     verbose);
Packit bf408e
}
Packit bf408e
Packit bf408e
static void
Packit bf408e
mips_dump_exception_stack(struct bt_info *bt, char *pt_regs)
Packit bf408e
{
Packit bf408e
	struct mips_pt_regs_main *mains;
Packit bf408e
	struct mips_pt_regs_cp0 *cp0;
Packit bf408e
	int i;
Packit bf408e
	char buf[BUFSIZE];
Packit bf408e
Packit bf408e
	mains = (struct mips_pt_regs_main *) (pt_regs + OFFSET(pt_regs_regs));
Packit bf408e
	cp0 = (struct mips_pt_regs_cp0 *) \
Packit bf408e
	      (pt_regs + OFFSET(pt_regs_cp0_badvaddr));
Packit bf408e
Packit bf408e
	for (i = 0; i < 32; i += 4) {
Packit bf408e
		fprintf(fp, "    $%2d   : %08lx %08lx %08lx %08lx\n",
Packit bf408e
			i, mains->regs[i], mains->regs[i+1],
Packit bf408e
			mains->regs[i+2], mains->regs[i+3]);
Packit bf408e
	}
Packit bf408e
	fprintf(fp, "    Hi    : %08lx\n", mains->hi);
Packit bf408e
	fprintf(fp, "    Lo    : %08lx\n", mains->lo);
Packit bf408e
Packit bf408e
	value_to_symstr(cp0->cp0_epc, buf, 16);
Packit bf408e
	fprintf(fp, "    epc   : %08lx %s\n", cp0->cp0_epc, buf);
Packit bf408e
Packit bf408e
	value_to_symstr(mains->regs[31], buf, 16);
Packit bf408e
	fprintf(fp, "    ra    : %08lx %s\n", mains->regs[31], buf);
Packit bf408e
Packit bf408e
	fprintf(fp, "    Status: %08lx\n", mains->cp0_status);
Packit bf408e
	fprintf(fp, "    Cause : %08lx\n", cp0->cp0_cause);
Packit bf408e
	fprintf(fp, "    BadVA : %08lx\n", cp0->cp0_badvaddr);
Packit bf408e
}
Packit bf408e
Packit bf408e
struct mips_unwind_frame {
Packit bf408e
	ulong sp;
Packit bf408e
	ulong pc;
Packit bf408e
	ulong ra;
Packit bf408e
};
Packit bf408e
Packit bf408e
static void
Packit bf408e
mips_display_full_frame(struct bt_info *bt, struct mips_unwind_frame *current,
Packit bf408e
			struct mips_unwind_frame *previous)
Packit bf408e
{
Packit bf408e
	ulong words, addr;
Packit bf408e
	ulong *up;
Packit bf408e
	char buf[BUFSIZE];
Packit bf408e
	int i, u_idx;
Packit bf408e
Packit bf408e
	if (!INSTACK(previous->sp, bt) || !INSTACK(current->sp, bt))
Packit bf408e
		return;
Packit bf408e
Packit bf408e
	words = (previous->sp - current->sp) / sizeof(ulong);
Packit bf408e
Packit bf408e
	if (words == 0) {
Packit bf408e
		fprintf(fp, "    (no frame)\n");
Packit bf408e
		return;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	addr = current->sp;
Packit bf408e
	u_idx = (current->sp - bt->stackbase) / sizeof(ulong);
Packit bf408e
	for (i = 0; i < words; i++, u_idx++) {
Packit bf408e
		if ((i % 4) == 0)
Packit bf408e
			fprintf(fp, "%s    %lx: ", i ? "\n" : "", addr);
Packit bf408e
Packit bf408e
		up = (ulong *)(&bt->stackbuf[u_idx * sizeof(ulong)]);
Packit bf408e
		fprintf(fp, "%s ", format_stack_entry(bt, buf, *up, 0));
Packit bf408e
		addr += sizeof(ulong);
Packit bf408e
	}
Packit bf408e
	fprintf(fp, "\n");
Packit bf408e
}
Packit bf408e
Packit bf408e
static int
Packit bf408e
mips_is_exception_entry(struct syment *sym)
Packit bf408e
{
Packit bf408e
	return STREQ(sym->name, "ret_from_exception") ||
Packit bf408e
	       STREQ(sym->name, "ret_from_irq") ||
Packit bf408e
	       STREQ(sym->name, "work_resched") ||
Packit bf408e
	       STREQ(sym->name, "handle_sys");
Packit bf408e
}
Packit bf408e
Packit bf408e
static void
Packit bf408e
mips_dump_backtrace_entry(struct bt_info *bt, struct syment *sym,
Packit bf408e
			  struct mips_unwind_frame *current,
Packit bf408e
			  struct mips_unwind_frame *previous, int level)
Packit bf408e
{
Packit bf408e
	const char *name = sym ? sym->name : "(invalid)";
Packit bf408e
	struct load_module *lm;
Packit bf408e
	char *name_plus_offset;
Packit bf408e
	char buf[BUFSIZE];
Packit bf408e
Packit bf408e
	name_plus_offset = NULL;
Packit bf408e
	if (bt->flags & BT_SYMBOL_OFFSET) {
Packit bf408e
		struct syment *symp;
Packit bf408e
		ulong symbol_offset;
Packit bf408e
Packit bf408e
		symp = value_search(current->pc, &symbol_offset);
Packit bf408e
Packit bf408e
		if (symp && symbol_offset)
Packit bf408e
			name_plus_offset =
Packit bf408e
				value_to_symstr(current->pc, buf, bt->radix);
Packit bf408e
	}
Packit bf408e
Packit bf408e
	fprintf(fp, "%s#%d [%8lx] %s at %lx", level < 10 ? " " : "", level,
Packit bf408e
		current->sp, name_plus_offset ? name_plus_offset : name,
Packit bf408e
		current->pc);
Packit bf408e
Packit bf408e
	if (module_symbol(current->pc, NULL, &lm, NULL, 0))
Packit bf408e
		fprintf(fp, " [%s]", lm->mod_name);
Packit bf408e
Packit bf408e
	fprintf(fp, "\n");
Packit bf408e
Packit bf408e
	if (bt->flags & BT_LINE_NUMBERS) {
Packit bf408e
		char buf[BUFSIZE];
Packit bf408e
Packit bf408e
		get_line_number(current->pc, buf, FALSE);
Packit bf408e
		if (strlen(buf))
Packit bf408e
			fprintf(fp, "    %s\n", buf);
Packit bf408e
	}
Packit bf408e
Packit bf408e
	if (sym && mips_is_exception_entry(sym)) {
Packit bf408e
		char pt_regs[SIZE(pt_regs)];
Packit bf408e
Packit bf408e
		GET_STACK_DATA(current->sp, &pt_regs, SIZE(pt_regs));
Packit bf408e
		mips_dump_exception_stack(bt, pt_regs);
Packit bf408e
	}
Packit bf408e
Packit bf408e
	if (bt->flags & BT_FULL) {
Packit bf408e
		fprintf(fp, "    "
Packit bf408e
			"[PC: %08lx RA: %08lx SP: %08lx SIZE: %ld]\n",
Packit bf408e
			current->pc, current->ra, current->sp,
Packit bf408e
			previous->sp - current->sp);
Packit bf408e
		mips_display_full_frame(bt, current, previous);
Packit bf408e
	}
Packit bf408e
}
Packit bf408e
Packit bf408e
Packit bf408e
static void
Packit bf408e
mips_analyze_function(ulong start, ulong offset,
Packit bf408e
		      struct mips_unwind_frame *current,
Packit bf408e
		      struct mips_unwind_frame *previous)
Packit bf408e
{
Packit bf408e
	ulong rapos = 0;
Packit bf408e
	ulong spadjust = 0;
Packit bf408e
	ulong *funcbuf, *ip;
Packit bf408e
	ulong i;
Packit bf408e
Packit bf408e
	if (CRASHDEBUG(8))
Packit bf408e
		fprintf(fp, "%s: start %#lx offset %#lx\n",
Packit bf408e
			__func__, start, offset);
Packit bf408e
Packit bf408e
	if (!offset) {
Packit bf408e
		previous->sp = current->sp;
Packit bf408e
		return;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	ip = funcbuf = (ulong *)GETBUF(offset);
Packit bf408e
	if (!readmem(start, KVADDR, funcbuf, offset,
Packit bf408e
		     "mips_analyze_function", RETURN_ON_ERROR)) {
Packit bf408e
		FREEBUF(funcbuf);
Packit bf408e
		error(FATAL, "Cannot read function at %8x", start);
Packit bf408e
		return;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	for (i = 0; i < offset; i += 4) {
Packit bf408e
		ulong insn = *ip;
Packit bf408e
		ulong high = (insn >> 16) & 0xffff;
Packit bf408e
		ulong low = insn & 0xffff;
Packit bf408e
Packit bf408e
		if (CRASHDEBUG(8))
Packit bf408e
			fprintf(fp, "insn @ %#lx = %#lx\n", start + i, insn);
Packit bf408e
Packit bf408e
		if (high == 0x27bd) { /* ADDIU sp, sp, imm */
Packit bf408e
			if (!(low & 0x8000))
Packit bf408e
				break;
Packit bf408e
Packit bf408e
			spadjust += 0x10000 - low;
Packit bf408e
			if (CRASHDEBUG(8))
Packit bf408e
				fprintf(fp, "spadjust = %lu\n", spadjust);
Packit bf408e
		} else if (high == 0xafbf) { /* SW RA, imm(SP) */
Packit bf408e
			rapos = current->sp + low;
Packit bf408e
			if (CRASHDEBUG(8))
Packit bf408e
				fprintf(fp, "rapos %lx\n", rapos);
Packit bf408e
			break;
Packit bf408e
		}
Packit bf408e
Packit bf408e
		ip++;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	FREEBUF(funcbuf);
Packit bf408e
Packit bf408e
	previous->sp = current->sp + spadjust;
Packit bf408e
Packit bf408e
	if (rapos && !readmem(rapos, KVADDR, &current->ra,
Packit bf408e
			      sizeof(current->ra), "RA from stack",
Packit bf408e
			      RETURN_ON_ERROR)) {
Packit bf408e
		error(FATAL, "Cannot read RA from stack %lx", rapos);
Packit bf408e
		return;
Packit bf408e
	}
Packit bf408e
}
Packit bf408e
Packit bf408e
static void
Packit bf408e
mips_back_trace_cmd(struct bt_info *bt)
Packit bf408e
{
Packit bf408e
	struct mips_unwind_frame current, previous;
Packit bf408e
	int level = 0;
Packit bf408e
	int invalid_ok = 1;
Packit bf408e
Packit bf408e
	if (bt->flags & BT_REGS_NOT_FOUND)
Packit bf408e
		return;
Packit bf408e
Packit bf408e
	previous.sp = previous.pc = previous.ra = 0;
Packit bf408e
Packit bf408e
	current.pc = bt->instptr;
Packit bf408e
	current.sp = bt->stkptr;
Packit bf408e
	current.ra = 0;
Packit bf408e
Packit bf408e
	if (bt->machdep) {
Packit bf408e
		struct mips_regset *regs = bt->machdep;
Packit bf408e
		previous.pc = current.ra = regs->regs[MIPS32_EF_R31];
Packit bf408e
	}
Packit bf408e
Packit bf408e
	while (INSTACK(current.sp, bt)) {
Packit bf408e
		struct syment *symbol = NULL;
Packit bf408e
		ulong offset;
Packit bf408e
Packit bf408e
		if (CRASHDEBUG(8))
Packit bf408e
			fprintf(fp, "level %d pc %#lx ra %#lx sp %lx\n",
Packit bf408e
				level, current.pc, current.ra, current.sp);
Packit bf408e
Packit bf408e
		if (!IS_KVADDR(current.pc) && !invalid_ok)
Packit bf408e
			return;
Packit bf408e
Packit bf408e
		symbol = value_search(current.pc, &offset);
Packit bf408e
		if (!symbol && !invalid_ok) {
Packit bf408e
			error(FATAL, "PC is unknown symbol (%lx)", current.pc);
Packit bf408e
			return;
Packit bf408e
		}
Packit bf408e
Packit bf408e
		invalid_ok = 0;
Packit bf408e
Packit bf408e
		/*
Packit bf408e
		 * If we get an address which points to the start of a
Packit bf408e
		 * function, then it could one of the following:
Packit bf408e
		 *
Packit bf408e
		 *  - we are dealing with a noreturn function.  The last call
Packit bf408e
		 *    from a noreturn function has an an ra which points to the
Packit bf408e
		 *    start of the function after it.  This is common in the
Packit bf408e
		 *    oops callchain because of die() which is annotated as
Packit bf408e
		 *    noreturn.
Packit bf408e
		 *
Packit bf408e
		 *  - we have taken an exception at the start of this function.
Packit bf408e
		 *    In this case we already have the RA in current.ra.
Packit bf408e
		 *
Packit bf408e
		 *  - we are in one of these routines which appear with zero
Packit bf408e
		 *    offset in manually-constructed stack frames:
Packit bf408e
		 *
Packit bf408e
		 *    * ret_from_exception
Packit bf408e
		 *    * ret_from_irq
Packit bf408e
		 *    * ret_from_fork
Packit bf408e
		 *    * ret_from_kernel_thread
Packit bf408e
		 */
Packit bf408e
		if (!current.ra && !offset && symbol && !STRNEQ(symbol->name, "ret_from")) {
Packit bf408e
			if (CRASHDEBUG(8))
Packit bf408e
				fprintf(fp, "zero offset at %s, try previous symbol\n",
Packit bf408e
					symbol->name);
Packit bf408e
Packit bf408e
			symbol = value_search(current.pc - 4, &offset);
Packit bf408e
			if (!symbol) {
Packit bf408e
				error(FATAL, "PC is unknown symbol (%lx)", current.pc);
Packit bf408e
				return;
Packit bf408e
			}
Packit bf408e
		}
Packit bf408e
Packit bf408e
		if (symbol && mips_is_exception_entry(symbol)) {
Packit bf408e
			struct mips_pt_regs_main *mains;
Packit bf408e
			struct mips_pt_regs_cp0 *cp0;
Packit bf408e
			char pt_regs[SIZE(pt_regs)];
Packit bf408e
Packit bf408e
			mains = (struct mips_pt_regs_main *) \
Packit bf408e
			       (pt_regs + OFFSET(pt_regs_regs));
Packit bf408e
			cp0 = (struct mips_pt_regs_cp0 *) \
Packit bf408e
			      (pt_regs + OFFSET(pt_regs_cp0_badvaddr));
Packit bf408e
Packit bf408e
			GET_STACK_DATA(current.sp, pt_regs, sizeof(pt_regs));
Packit bf408e
Packit bf408e
			previous.ra = mains->regs[31];
Packit bf408e
			previous.sp = mains->regs[29];
Packit bf408e
			current.ra = cp0->cp0_epc;
Packit bf408e
Packit bf408e
			if (CRASHDEBUG(8))
Packit bf408e
				fprintf(fp, "exception pc %#lx ra %#lx sp %lx\n",
Packit bf408e
					previous.pc, previous.ra, previous.sp);
Packit bf408e
Packit bf408e
			/* The PC causing the exception may have been invalid */
Packit bf408e
			invalid_ok = 1;
Packit bf408e
		} else if (symbol) {
Packit bf408e
			mips_analyze_function(symbol->value, offset, &current, &previous);
Packit bf408e
		} else {
Packit bf408e
			/*
Packit bf408e
			 * The current PC is invalid.  Assume that the code
Packit bf408e
			 * jumped through a invalid pointer and that the SP has
Packit bf408e
			 * not been adjusted.
Packit bf408e
			 */
Packit bf408e
			previous.sp = current.sp;
Packit bf408e
		}
Packit bf408e
Packit bf408e
		mips_dump_backtrace_entry(bt, symbol, &current, &previous, level++);
Packit bf408e
Packit bf408e
		current.pc = current.ra;
Packit bf408e
		current.sp = previous.sp;
Packit bf408e
		current.ra = previous.ra;
Packit bf408e
Packit bf408e
		if (CRASHDEBUG(8))
Packit bf408e
			fprintf(fp, "next %d pc %#lx ra %#lx sp %lx\n",
Packit bf408e
				level, current.pc, current.ra, current.sp);
Packit bf408e
Packit bf408e
		previous.sp = previous.pc = previous.ra = 0;
Packit bf408e
	}
Packit bf408e
}
Packit bf408e
Packit bf408e
static int
Packit bf408e
mips_dumpfile_stack_frame(struct bt_info *bt, ulong *nip, ulong *ksp)
Packit bf408e
{
Packit bf408e
	const struct machine_specific *ms = machdep->machspec;
Packit bf408e
	struct mips_regset *regs;
Packit bf408e
	ulong epc, r29;
Packit bf408e
Packit bf408e
	if (!ms->crash_task_regs) {
Packit bf408e
		bt->flags |= BT_REGS_NOT_FOUND;
Packit bf408e
		return FALSE;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	regs = &ms->crash_task_regs[bt->tc->processor];
Packit bf408e
	epc = regs->regs[MIPS32_EF_CP0_EPC];
Packit bf408e
	r29 = regs->regs[MIPS32_EF_R29];
Packit bf408e
Packit bf408e
	if (!epc && !r29) {
Packit bf408e
		bt->flags |= BT_REGS_NOT_FOUND;
Packit bf408e
		return FALSE;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	if (nip)
Packit bf408e
		*nip = epc;
Packit bf408e
	if (ksp)
Packit bf408e
		*ksp = r29;
Packit bf408e
Packit bf408e
	bt->machdep = regs;
Packit bf408e
Packit bf408e
	return TRUE;
Packit bf408e
}
Packit bf408e
Packit bf408e
static int
Packit bf408e
mips_get_frame(struct bt_info *bt, ulong *pcp, ulong *spp)
Packit bf408e
{
Packit bf408e
	if (!bt->tc || !(tt->flags & THREAD_INFO))
Packit bf408e
		return FALSE;
Packit bf408e
Packit bf408e
        if (!readmem(bt->task + OFFSET(task_struct_thread_reg31),
Packit bf408e
		     KVADDR, pcp, sizeof(*pcp),
Packit bf408e
		     "thread_struct.regs31",
Packit bf408e
		     RETURN_ON_ERROR)) {
Packit bf408e
		return FALSE;
Packit bf408e
	}
Packit bf408e
Packit bf408e
        if (!readmem(bt->task + OFFSET(task_struct_thread_reg29),
Packit bf408e
		     KVADDR, spp, sizeof(*spp),
Packit bf408e
		     "thread_struct.regs29",
Packit bf408e
		     RETURN_ON_ERROR)) {
Packit bf408e
		return FALSE;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	return TRUE;
Packit bf408e
}
Packit bf408e
Packit bf408e
static void
Packit bf408e
mips_stackframe_init(void)
Packit bf408e
{
Packit bf408e
	long task_struct_thread = MEMBER_OFFSET("task_struct", "thread");
Packit bf408e
	long thread_reg29 = MEMBER_OFFSET("thread_struct", "reg29");
Packit bf408e
	long thread_reg31 = MEMBER_OFFSET("thread_struct", "reg31");
Packit bf408e
Packit bf408e
	if ((task_struct_thread == INVALID_OFFSET) ||
Packit bf408e
	    (thread_reg29 == INVALID_OFFSET) ||
Packit bf408e
	    (thread_reg31 == INVALID_OFFSET)) {
Packit bf408e
		error(FATAL,
Packit bf408e
		      "cannot determine thread_struct offsets\n");
Packit bf408e
		return;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	ASSIGN_OFFSET(task_struct_thread_reg29) =
Packit bf408e
		task_struct_thread + thread_reg29;
Packit bf408e
	ASSIGN_OFFSET(task_struct_thread_reg31) =
Packit bf408e
		task_struct_thread + thread_reg31;
Packit bf408e
Packit bf408e
	STRUCT_SIZE_INIT(pt_regs, "pt_regs");
Packit bf408e
	MEMBER_OFFSET_INIT(pt_regs_regs, "pt_regs", "regs");
Packit bf408e
	MEMBER_OFFSET_INIT(pt_regs_cp0_badvaddr, "pt_regs", "cp0_badvaddr");
Packit bf408e
}
Packit bf408e
Packit bf408e
static void
Packit bf408e
mips_get_stack_frame(struct bt_info *bt, ulong *pcp, ulong *spp)
Packit bf408e
{
Packit bf408e
	int ret;
Packit bf408e
Packit bf408e
	*pcp = 0;
Packit bf408e
	*spp = 0;
Packit bf408e
	bt->machdep = NULL;
Packit bf408e
Packit bf408e
	if (DUMPFILE() && is_task_active(bt->task))
Packit bf408e
		ret = mips_dumpfile_stack_frame(bt, pcp, spp);
Packit bf408e
	else
Packit bf408e
		ret = mips_get_frame(bt, pcp, spp);
Packit bf408e
Packit bf408e
	if (!ret)
Packit bf408e
		error(WARNING, "cannot determine starting stack frame for task %lx\n",
Packit bf408e
			bt->task);
Packit bf408e
}
Packit bf408e
Packit bf408e
static int
Packit bf408e
mips_eframe_search(struct bt_info *bt)
Packit bf408e
{
Packit bf408e
	return error(FATAL, "%s: not implemented\n", __func__);
Packit bf408e
}
Packit bf408e
Packit bf408e
static ulong
Packit bf408e
mips_get_task_pgd(ulong task)
Packit bf408e
{
Packit bf408e
	return error(FATAL, "%s: not implemented\n", __func__);
Packit bf408e
}
Packit bf408e
Packit bf408e
static int
Packit bf408e
mips_is_task_addr(ulong task)
Packit bf408e
{
Packit bf408e
	if (tt->flags & THREAD_INFO)
Packit bf408e
		return IS_KVADDR(task);
Packit bf408e
Packit bf408e
	return (IS_KVADDR(task) && ALIGNED_STACK_OFFSET(task) == 0);
Packit bf408e
}
Packit bf408e
Packit bf408e
static ulong
Packit bf408e
mips_processor_speed(void)
Packit bf408e
{
Packit bf408e
	return 0;
Packit bf408e
}
Packit bf408e
Packit bf408e
static int
Packit bf408e
mips_get_smp_cpus(void)
Packit bf408e
{
Packit bf408e
	return (get_cpus_online() > 0) ? get_cpus_online() : kt->cpus;
Packit bf408e
}
Packit bf408e
Packit bf408e
static ulong
Packit bf408e
mips_vmalloc_start(void)
Packit bf408e
{
Packit bf408e
	return first_vmalloc_address();
Packit bf408e
}
Packit bf408e
Packit bf408e
/*
Packit bf408e
 * Retrieve task registers for the time of the crash.
Packit bf408e
 */
Packit bf408e
static int
Packit bf408e
mips_get_crash_notes(void)
Packit bf408e
{
Packit bf408e
	struct machine_specific *ms = machdep->machspec;
Packit bf408e
	ulong crash_notes;
Packit bf408e
	Elf32_Nhdr *note;
Packit bf408e
	ulong offset;
Packit bf408e
	char *buf, *p;
Packit bf408e
	ulong *notes_ptrs;
Packit bf408e
	ulong i;
Packit bf408e
Packit bf408e
	if (!symbol_exists("crash_notes"))
Packit bf408e
		return FALSE;
Packit bf408e
Packit bf408e
	crash_notes = symbol_value("crash_notes");
Packit bf408e
Packit bf408e
	notes_ptrs = (ulong *)GETBUF(kt->cpus*sizeof(notes_ptrs[0]));
Packit bf408e
Packit bf408e
	/*
Packit bf408e
	 * Read crash_notes for the first CPU. crash_notes are in standard ELF
Packit bf408e
	 * note format.
Packit bf408e
	 */
Packit bf408e
	if (!readmem(crash_notes, KVADDR, &notes_ptrs[kt->cpus-1],
Packit bf408e
	    sizeof(notes_ptrs[kt->cpus-1]), "crash_notes",
Packit bf408e
		     RETURN_ON_ERROR)) {
Packit bf408e
		error(WARNING, "cannot read crash_notes\n");
Packit bf408e
		FREEBUF(notes_ptrs);
Packit bf408e
		return FALSE;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	if (symbol_exists("__per_cpu_offset")) {
Packit bf408e
Packit bf408e
		/* Add __per_cpu_offset for each cpu to form the pointer to the notes */
Packit bf408e
		for (i = 0; i<kt->cpus; i++)
Packit bf408e
			notes_ptrs[i] = notes_ptrs[kt->cpus-1] + kt->__per_cpu_offset[i];
Packit bf408e
	}
Packit bf408e
Packit bf408e
	buf = GETBUF(SIZE(note_buf));
Packit bf408e
Packit bf408e
	if (!(panic_task_regs = calloc((size_t)kt->cpus, sizeof(*panic_task_regs))))
Packit bf408e
		error(FATAL, "cannot calloc panic_task_regs space\n");
Packit bf408e
Packit bf408e
	for  (i=0;i<kt->cpus;i++) {
Packit bf408e
Packit bf408e
		if (!readmem(notes_ptrs[i], KVADDR, buf, SIZE(note_buf), "note_buf_t",
Packit bf408e
			     RETURN_ON_ERROR)) {
Packit bf408e
			error(WARNING, "failed to read note_buf_t\n");
Packit bf408e
			goto fail;
Packit bf408e
		}
Packit bf408e
Packit bf408e
		/*
Packit bf408e
		 * Do some sanity checks for this note before reading registers from it.
Packit bf408e
		 */
Packit bf408e
		note = (Elf32_Nhdr *)buf;
Packit bf408e
		p = buf + sizeof(Elf32_Nhdr);
Packit bf408e
Packit bf408e
		/*
Packit bf408e
		 * dumpfiles created with qemu won't have crash_notes, but there will
Packit bf408e
		 * be elf notes; dumpfiles created by kdump do not create notes for
Packit bf408e
		 * offline cpus.
Packit bf408e
		 */
Packit bf408e
		if (note->n_namesz == 0 && (DISKDUMP_DUMPFILE() || KDUMP_DUMPFILE())) {
Packit bf408e
			if (DISKDUMP_DUMPFILE())
Packit bf408e
				note = diskdump_get_prstatus_percpu(i);
Packit bf408e
			else if (KDUMP_DUMPFILE())
Packit bf408e
				note = netdump_get_prstatus_percpu(i);
Packit bf408e
			if (note) {
Packit bf408e
				/*
Packit bf408e
				 * SIZE(note_buf) accounts for a "final note", which is a
Packit bf408e
				 * trailing empty elf note header.
Packit bf408e
				 */
Packit bf408e
				long notesz = SIZE(note_buf) - sizeof(Elf32_Nhdr);
Packit bf408e
Packit bf408e
				if (sizeof(Elf32_Nhdr) + roundup(note->n_namesz, 4) +
Packit bf408e
				    note->n_descsz == notesz)
Packit bf408e
					BCOPY((char *)note, buf, notesz);
Packit bf408e
			} else {
Packit bf408e
				error(WARNING,
Packit bf408e
					"cannot find NT_PRSTATUS note for cpu: %d\n", i);
Packit bf408e
				continue;
Packit bf408e
			}
Packit bf408e
		}
Packit bf408e
Packit bf408e
		if (note->n_type != NT_PRSTATUS) {
Packit bf408e
			error(WARNING, "invalid note (n_type != NT_PRSTATUS)\n");
Packit bf408e
			goto fail;
Packit bf408e
		}
Packit bf408e
		if (p[0] != 'C' || p[1] != 'O' || p[2] != 'R' || p[3] != 'E') {
Packit bf408e
			error(WARNING, "invalid note (name != \"CORE\"\n");
Packit bf408e
			goto fail;
Packit bf408e
		}
Packit bf408e
Packit bf408e
		/*
Packit bf408e
		 * Find correct location of note data. This contains elf_prstatus
Packit bf408e
		 * structure which has registers etc. for the crashed task.
Packit bf408e
		 */
Packit bf408e
		offset = sizeof(Elf32_Nhdr);
Packit bf408e
		offset = roundup(offset + note->n_namesz, 4);
Packit bf408e
		p = buf + offset; /* start of elf_prstatus */
Packit bf408e
Packit bf408e
		BCOPY(p + OFFSET(elf_prstatus_pr_reg), &panic_task_regs[i],
Packit bf408e
		      sizeof(panic_task_regs[i]));
Packit bf408e
	}
Packit bf408e
Packit bf408e
	/*
Packit bf408e
	 * And finally we have the registers for the crashed task. This is
Packit bf408e
	 * used later on when dumping backtrace.
Packit bf408e
	 */
Packit bf408e
	ms->crash_task_regs = panic_task_regs;
Packit bf408e
Packit bf408e
	FREEBUF(buf);
Packit bf408e
	FREEBUF(notes_ptrs);
Packit bf408e
	return TRUE;
Packit bf408e
Packit bf408e
fail:
Packit bf408e
	FREEBUF(buf);
Packit bf408e
	FREEBUF(notes_ptrs);
Packit bf408e
	free(panic_task_regs);
Packit bf408e
	return FALSE;
Packit bf408e
}
Packit bf408e
Packit bf408e
static int mips_get_elf_notes(void)
Packit bf408e
{
Packit bf408e
	struct machine_specific *ms = machdep->machspec;
Packit bf408e
	int i;
Packit bf408e
Packit bf408e
	if (!DISKDUMP_DUMPFILE() && !KDUMP_DUMPFILE())
Packit bf408e
		return FALSE;
Packit bf408e
Packit bf408e
	panic_task_regs = calloc(kt->cpus, sizeof(*panic_task_regs));
Packit bf408e
	if (!panic_task_regs)
Packit bf408e
		error(FATAL, "cannot calloc panic_task_regs space\n");
Packit bf408e
Packit bf408e
	for (i = 0; i < kt->cpus; i++) {
Packit bf408e
		Elf32_Nhdr *note = NULL;
Packit bf408e
		size_t len;
Packit bf408e
Packit bf408e
		if (DISKDUMP_DUMPFILE())
Packit bf408e
			note = diskdump_get_prstatus_percpu(i);
Packit bf408e
		else if (KDUMP_DUMPFILE())
Packit bf408e
			note = netdump_get_prstatus_percpu(i);
Packit bf408e
Packit bf408e
		if (!note) {
Packit bf408e
			error(WARNING,
Packit bf408e
			      "cannot find NT_PRSTATUS note for cpu: %d\n", i);
Packit bf408e
			continue;
Packit bf408e
		}
Packit bf408e
Packit bf408e
		len = sizeof(Elf32_Nhdr);
Packit bf408e
		len = roundup(len + note->n_namesz, 4);
Packit bf408e
Packit bf408e
		BCOPY((char *)note + len + OFFSET(elf_prstatus_pr_reg),
Packit bf408e
		      &panic_task_regs[i], sizeof(panic_task_regs[i]));
Packit bf408e
	}
Packit bf408e
Packit bf408e
	ms->crash_task_regs = panic_task_regs;
Packit bf408e
Packit bf408e
	return TRUE;
Packit bf408e
}
Packit bf408e
Packit bf408e
static int mips_init_active_task_regs(void)
Packit bf408e
{
Packit bf408e
	int retval;
Packit bf408e
Packit bf408e
	retval = mips_get_crash_notes();
Packit bf408e
	if (retval == TRUE)
Packit bf408e
		return retval;
Packit bf408e
Packit bf408e
	return mips_get_elf_notes();
Packit bf408e
}
Packit bf408e
Packit bf408e
static int
Packit bf408e
mips_verify_symbol(const char *name, ulong value, char type)
Packit bf408e
{
Packit bf408e
	if (STREQ(name, "_text"))
Packit bf408e
		machdep->flags |= KSYMS_START;
Packit bf408e
Packit bf408e
	return (name && strlen(name) && (machdep->flags & KSYMS_START) &&
Packit bf408e
	        !STRNEQ(name, "__func__.") && !STRNEQ(name, "__crc_"));
Packit bf408e
}
Packit bf408e
Packit bf408e
void
Packit bf408e
mips_dump_machdep_table(ulong arg)
Packit bf408e
{
Packit bf408e
	int others = 0;
Packit bf408e
Packit bf408e
	fprintf(fp, "              flags: %lx (", machdep->flags);
Packit bf408e
	if (machdep->flags & KSYMS_START)
Packit bf408e
		fprintf(fp, "%sKSYMS_START", others++ ? "|" : "");
Packit bf408e
	fprintf(fp, ")\n");
Packit bf408e
Packit bf408e
	fprintf(fp, "             kvbase: %lx\n", machdep->kvbase);
Packit bf408e
	fprintf(fp, "  identity_map_base: %lx\n", machdep->identity_map_base);
Packit bf408e
	fprintf(fp, "           pagesize: %d\n", machdep->pagesize);
Packit bf408e
	fprintf(fp, "          pageshift: %d\n", machdep->pageshift);
Packit bf408e
	fprintf(fp, "           pagemask: %llx\n", machdep->pagemask);
Packit bf408e
	fprintf(fp, "         pageoffset: %lx\n", machdep->pageoffset);
Packit bf408e
	fprintf(fp, "        pgdir_shift: %d\n", PGDIR_SHIFT);
Packit bf408e
	fprintf(fp, "       ptrs_per_pgd: %lu\n", PTRS_PER_PGD);
Packit bf408e
	fprintf(fp, "       ptrs_per_pte: %d\n", PTRS_PER_PTE);
Packit bf408e
	fprintf(fp, "          stacksize: %ld\n", machdep->stacksize);
Packit bf408e
	fprintf(fp, "                 hz: %d\n", machdep->hz);
Packit bf408e
	fprintf(fp, "            memsize: %lld (0x%llx)\n",
Packit bf408e
		machdep->memsize, machdep->memsize);
Packit bf408e
	fprintf(fp, "               bits: %d\n", machdep->bits);
Packit bf408e
	fprintf(fp, "            nr_irqs: %d\n", machdep->nr_irqs);
Packit bf408e
	fprintf(fp, "      eframe_search: mips_eframe_search()\n");
Packit bf408e
	fprintf(fp, "         back_trace: mips_back_trace_cmd()\n");
Packit bf408e
	fprintf(fp, "    processor_speed: mips_processor_speed()\n");
Packit bf408e
	fprintf(fp, "              uvtop: mips_uvtop()\n");
Packit bf408e
	fprintf(fp, "              kvtop: mips_kvtop()\n");
Packit bf408e
	fprintf(fp, "       get_task_pgd: mips_get_task_pgd()\n");
Packit bf408e
	fprintf(fp, "           dump_irq: generic_dump_irq()\n");
Packit bf408e
	fprintf(fp, "    show_interrupts: generic_show_interrupts()\n");
Packit bf408e
	fprintf(fp, "   get_irq_affinity: generic_get_irq_affinity()\n");
Packit bf408e
	fprintf(fp, "    get_stack_frame: mips_get_stack_frame()\n");
Packit bf408e
	fprintf(fp, "      get_stackbase: generic_get_stackbase()\n");
Packit bf408e
	fprintf(fp, "       get_stacktop: generic_get_stacktop()\n");
Packit bf408e
	fprintf(fp, "      translate_pte: mips_translate_pte()\n");
Packit bf408e
	fprintf(fp, "        memory_size: generic_memory_size()\n");
Packit bf408e
	fprintf(fp, "      vmalloc_start: mips_vmalloc_start()\n");
Packit bf408e
	fprintf(fp, "       is_task_addr: mips_is_task_addr()\n");
Packit bf408e
	fprintf(fp, "      verify_symbol: mips_verify_symbol()\n");
Packit bf408e
	fprintf(fp, "         dis_filter: generic_dis_filter()\n");
Packit bf408e
	fprintf(fp, "           cmd_mach: mips_cmd_mach()\n");
Packit bf408e
	fprintf(fp, "       get_smp_cpus: mips_get_smp_cpus()\n");
Packit bf408e
	fprintf(fp, "          is_kvaddr: generic_is_kvaddr()\n");
Packit bf408e
	fprintf(fp, "          is_uvaddr: generic_is_uvaddr()\n");
Packit bf408e
	fprintf(fp, "       verify_paddr: generic_verify_paddr()\n");
Packit bf408e
	fprintf(fp, "    init_kernel_pgd: NULL\n");
Packit bf408e
	fprintf(fp, "    value_to_symbol: generic_machdep_value_to_symbol()\n");
Packit bf408e
	fprintf(fp, "  line_number_hooks: NULL\n");
Packit bf408e
	fprintf(fp, "      last_pgd_read: %lx\n", machdep->last_pgd_read);
Packit bf408e
	fprintf(fp, "      last_pmd_read: %lx\n", machdep->last_pmd_read);
Packit bf408e
	fprintf(fp, "     last_ptbl_read: %lx\n", machdep->last_ptbl_read);
Packit bf408e
	fprintf(fp, "                pgd: %lx\n", (ulong)machdep->pgd);
Packit bf408e
	fprintf(fp, "                pmd: %lx\n", (ulong)machdep->pmd);
Packit bf408e
	fprintf(fp, "               ptbl: %lx\n", (ulong)machdep->ptbl);
Packit bf408e
	fprintf(fp, "  section_size_bits: %ld\n", machdep->section_size_bits);
Packit bf408e
	fprintf(fp, "   max_physmem_bits: %ld\n", machdep->max_physmem_bits);
Packit bf408e
	fprintf(fp, "  sections_per_root: %ld\n", machdep->sections_per_root);
Packit bf408e
	fprintf(fp, "           machspec: %lx\n", (ulong)machdep->machspec);
Packit bf408e
}
Packit bf408e
Packit bf408e
static ulong
Packit bf408e
mips_get_page_size(void)
Packit bf408e
{
Packit bf408e
	struct syment *spd, *next = NULL;
Packit bf408e
Packit bf408e
	spd = symbol_search("swapper_pg_dir");
Packit bf408e
	if (spd)
Packit bf408e
		next = next_symbol(NULL, spd);
Packit bf408e
Packit bf408e
	if (!spd || !next)
Packit bf408e
		return memory_page_size();
Packit bf408e
Packit bf408e
	return next->value - spd->value;
Packit bf408e
}
Packit bf408e
Packit bf408e
void
Packit bf408e
mips_init(int when)
Packit bf408e
{
Packit bf408e
#if defined(__i386__) || defined(__x86_64__)
Packit bf408e
	if (ACTIVE())
Packit bf408e
		error(FATAL, "compiled for the MIPS architecture\n");
Packit bf408e
#endif
Packit bf408e
Packit bf408e
	switch (when) {
Packit bf408e
	case SETUP_ENV:
Packit bf408e
		machdep->process_elf_notes = process_elf32_notes;
Packit bf408e
		break;
Packit bf408e
Packit bf408e
	case PRE_SYMTAB:
Packit bf408e
		machdep->verify_symbol = mips_verify_symbol;
Packit bf408e
		machdep->machspec = &mips_machine_specific;
Packit bf408e
		if (pc->flags & KERNEL_DEBUG_QUERY)
Packit bf408e
			return;
Packit bf408e
		machdep->last_pgd_read = 0;
Packit bf408e
		machdep->last_pmd_read = 0;
Packit bf408e
		machdep->last_ptbl_read = 0;
Packit bf408e
		machdep->verify_paddr = generic_verify_paddr;
Packit bf408e
		machdep->ptrs_per_pgd = PTRS_PER_PGD;
Packit bf408e
		break;
Packit bf408e
Packit bf408e
	case PRE_GDB:
Packit bf408e
		machdep->pagesize = mips_get_page_size();
Packit bf408e
		machdep->pageshift = ffs(machdep->pagesize) - 1;
Packit bf408e
		machdep->pageoffset = machdep->pagesize - 1;
Packit bf408e
		machdep->pagemask = ~((ulonglong)machdep->pageoffset);
Packit bf408e
		if (machdep->pagesize >= 16384)
Packit bf408e
			machdep->stacksize = machdep->pagesize;
Packit bf408e
		else
Packit bf408e
			machdep->stacksize = machdep->pagesize * 2;
Packit bf408e
Packit bf408e
		if ((machdep->pgd = malloc(PGD_SIZE)) == NULL)
Packit bf408e
			error(FATAL, "cannot malloc pgd space.");
Packit bf408e
		if ((machdep->ptbl = malloc(PAGESIZE())) == NULL)
Packit bf408e
			error(FATAL, "cannot malloc ptbl space.");
Packit bf408e
Packit bf408e
	        machdep->kvbase = 0x80000000;
Packit bf408e
		machdep->identity_map_base = machdep->kvbase;
Packit bf408e
                machdep->is_kvaddr = generic_is_kvaddr;
Packit bf408e
                machdep->is_uvaddr = generic_is_uvaddr;
Packit bf408e
	        machdep->uvtop = mips_uvtop;
Packit bf408e
	        machdep->kvtop = mips_kvtop;
Packit bf408e
		machdep->vmalloc_start = mips_vmalloc_start;
Packit bf408e
	        machdep->eframe_search = mips_eframe_search;
Packit bf408e
	        machdep->back_trace = mips_back_trace_cmd;
Packit bf408e
	        machdep->processor_speed = mips_processor_speed;
Packit bf408e
	        machdep->get_task_pgd = mips_get_task_pgd;
Packit bf408e
		machdep->get_stack_frame = mips_get_stack_frame;
Packit bf408e
		machdep->get_stackbase = generic_get_stackbase;
Packit bf408e
		machdep->get_stacktop = generic_get_stacktop;
Packit bf408e
		machdep->translate_pte = mips_translate_pte;
Packit bf408e
		machdep->memory_size = generic_memory_size;
Packit bf408e
		machdep->is_task_addr = mips_is_task_addr;
Packit bf408e
		machdep->dis_filter = generic_dis_filter;
Packit bf408e
		machdep->cmd_mach = mips_cmd_mach;
Packit bf408e
		machdep->get_smp_cpus = mips_get_smp_cpus;
Packit bf408e
		machdep->value_to_symbol = generic_machdep_value_to_symbol;
Packit bf408e
                machdep->init_kernel_pgd = NULL;
Packit bf408e
		break;
Packit bf408e
	case POST_GDB:
Packit bf408e
		mips_init_page_flags();
Packit bf408e
		machdep->dump_irq = generic_dump_irq;
Packit bf408e
		machdep->show_interrupts = generic_show_interrupts;
Packit bf408e
		machdep->get_irq_affinity = generic_get_irq_affinity;
Packit bf408e
		machdep->section_size_bits = _SECTION_SIZE_BITS;
Packit bf408e
		machdep->max_physmem_bits = _MAX_PHYSMEM_BITS;
Packit bf408e
		ARRAY_LENGTH_INIT(machdep->nr_irqs, irq_desc,
Packit bf408e
			"irq_desc", NULL, 0);
Packit bf408e
		mips_stackframe_init();
Packit bf408e
Packit bf408e
		if (!machdep->hz)
Packit bf408e
			machdep->hz = 100;
Packit bf408e
Packit bf408e
		MEMBER_OFFSET_INIT(elf_prstatus_pr_reg, "elf_prstatus",
Packit bf408e
				   "pr_reg");
Packit bf408e
Packit bf408e
		STRUCT_SIZE_INIT(note_buf, "note_buf_t");
Packit bf408e
		break;
Packit bf408e
	case POST_VM:
Packit bf408e
		/*
Packit bf408e
		 * crash_notes contains machine specific information about the
Packit bf408e
		 * crash. In particular, it contains CPU registers at the time
Packit bf408e
		 * of the crash. We need this information to extract correct
Packit bf408e
		 * backtraces from the panic task.
Packit bf408e
		 */
Packit bf408e
		if (!ACTIVE() && !mips_init_active_task_regs())
Packit bf408e
			error(WARNING,
Packit bf408e
			    "cannot retrieve registers for active task%s\n\n",
Packit bf408e
				kt->cpus > 1 ? "s" : "");
Packit bf408e
	}
Packit bf408e
}
Packit bf408e
Packit bf408e
void
Packit bf408e
mips_display_regs_from_elf_notes(int cpu, FILE *ofp)
Packit bf408e
{
Packit bf408e
	const struct machine_specific *ms = machdep->machspec;
Packit bf408e
	struct mips_regset *regs;
Packit bf408e
Packit bf408e
	if (!ms->crash_task_regs) {
Packit bf408e
		error(INFO, "registers not collected for cpu %d\n", cpu);
Packit bf408e
		return;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	regs = &ms->crash_task_regs[cpu];
Packit bf408e
	if (!regs->regs[MIPS32_EF_R29] && !regs->regs[MIPS32_EF_CP0_EPC]) {
Packit bf408e
		error(INFO, "registers not collected for cpu %d\n", cpu);
Packit bf408e
		return;
Packit bf408e
	}
Packit bf408e
Packit bf408e
	fprintf(ofp,
Packit bf408e
		"     R0: %08lx   R1: %08lx   R2: %08lx\n"
Packit bf408e
		"     R3: %08lx   R4: %08lx   R5: %08lx\n"
Packit bf408e
		"     R6: %08lx   R7: %08lx   R8: %08lx\n"
Packit bf408e
		"     R9: %08lx  R10: %08lx  R11: %08lx\n"
Packit bf408e
		"    R12: %08lx  R13: %08lx  R14: %08lx\n"
Packit bf408e
		"    R15: %08lx  R16: %08lx  R17: %08lx\n"
Packit bf408e
		"    R18: %08lx  R19: %08lx  R20: %08lx\n"
Packit bf408e
		"    R21: %08lx  R22: %08lx  R23: %08lx\n"
Packit bf408e
		"    R24: %08lx  R25: %08lx  R26: %08lx\n"
Packit bf408e
		"    R27: %08lx  R28: %08lx  R29: %08lx\n"
Packit bf408e
		"    R30: %08lx  R31: %08lx\n"
Packit bf408e
		"       LO: %08lx        HI: %08lx\n"
Packit bf408e
		"      EPC: %08lx  BADVADDR: %08lx\n"
Packit bf408e
		"   STATUS: %08lx     CAUSE: %08lx\n",
Packit bf408e
		regs->regs[MIPS32_EF_R0],
Packit bf408e
		regs->regs[MIPS32_EF_R0 + 1],
Packit bf408e
		regs->regs[MIPS32_EF_R0 + 2],
Packit bf408e
		regs->regs[MIPS32_EF_R0 + 3],
Packit bf408e
		regs->regs[MIPS32_EF_R0 + 4],
Packit bf408e
		regs->regs[MIPS32_EF_R0 + 5],
Packit bf408e
		regs->regs[MIPS32_EF_R0 + 6],
Packit bf408e
		regs->regs[MIPS32_EF_R0 + 7],
Packit bf408e
		regs->regs[MIPS32_EF_R0 + 8],
Packit bf408e
		regs->regs[MIPS32_EF_R0 + 9],
Packit bf408e
		regs->regs[MIPS32_EF_R0 + 10],
Packit bf408e
		regs->regs[MIPS32_EF_R0 + 11],
Packit bf408e
		regs->regs[MIPS32_EF_R0 + 12],
Packit bf408e
		regs->regs[MIPS32_EF_R0 + 13],
Packit bf408e
		regs->regs[MIPS32_EF_R0 + 14],
Packit bf408e
		regs->regs[MIPS32_EF_R0 + 15],
Packit bf408e
		regs->regs[MIPS32_EF_R0 + 16],
Packit bf408e
		regs->regs[MIPS32_EF_R0 + 17],
Packit bf408e
		regs->regs[MIPS32_EF_R0 + 18],
Packit bf408e
		regs->regs[MIPS32_EF_R0 + 19],
Packit bf408e
		regs->regs[MIPS32_EF_R0 + 20],
Packit bf408e
		regs->regs[MIPS32_EF_R0 + 21],
Packit bf408e
		regs->regs[MIPS32_EF_R0 + 22],
Packit bf408e
		regs->regs[MIPS32_EF_R0 + 23],
Packit bf408e
		regs->regs[MIPS32_EF_R0 + 24],
Packit bf408e
		regs->regs[MIPS32_EF_R0 + 25],
Packit bf408e
		regs->regs[MIPS32_EF_R0 + 26],
Packit bf408e
		regs->regs[MIPS32_EF_R0 + 27],
Packit bf408e
		regs->regs[MIPS32_EF_R0 + 28],
Packit bf408e
		regs->regs[MIPS32_EF_R0 + 29],
Packit bf408e
		regs->regs[MIPS32_EF_R0 + 30],
Packit bf408e
		regs->regs[MIPS32_EF_R0 + 31],
Packit bf408e
		regs->regs[MIPS32_EF_LO],
Packit bf408e
		regs->regs[MIPS32_EF_HI],
Packit bf408e
		regs->regs[MIPS32_EF_CP0_EPC],
Packit bf408e
		regs->regs[MIPS32_EF_CP0_BADVADDR],
Packit bf408e
		regs->regs[MIPS32_EF_CP0_STATUS],
Packit bf408e
		regs->regs[MIPS32_EF_CP0_CAUSE]);
Packit bf408e
}
Packit bf408e
#else
Packit bf408e
Packit bf408e
#include "defs.h"
Packit bf408e
Packit bf408e
void
Packit bf408e
mips_display_regs_from_elf_notes(int cpu, FILE *ofp)
Packit bf408e
{
Packit bf408e
	return;
Packit bf408e
}
Packit bf408e
Packit bf408e
#endif /* !MIPS */
Packit bf408e
Packit bf408e