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