diff options
author | Stu Grossman <grossman@cygnus> | 1992-06-19 22:43:49 +0000 |
---|---|---|
committer | Stu Grossman <grossman@cygnus> | 1992-06-19 22:43:49 +0000 |
commit | 7da1e27dd4814e6e718404f294d3ef63e15054e2 (patch) | |
tree | 88de18c03a71c4f3fca192c8d9d597842c686ff6 /gdb/hppabsd-tdep.c | |
parent | 9aa448333dc03c53f4ed8826251f813123705217 (diff) | |
download | binutils-gdb-7da1e27dd4814e6e718404f294d3ef63e15054e2.tar.gz |
* configure.in, dbxread.c, hppa-coredep.c, hppa-pinsn.c,
hppabsd-core.c, hppabsd-tdep.c, hppabsd-xdep.c, hppahpux-tdep.c,
hppahpux-xdep.c, munch, partial-stab.h, tm-hppabsd.h,
tm-hppahpux.h, xm-hppabsd.h, xm-hppahpux.h: HPPA merge.
Diffstat (limited to 'gdb/hppabsd-tdep.c')
-rw-r--r-- | gdb/hppabsd-tdep.c | 1428 |
1 files changed, 1428 insertions, 0 deletions
diff --git a/gdb/hppabsd-tdep.c b/gdb/hppabsd-tdep.c new file mode 100644 index 00000000000..c9912b05ea6 --- /dev/null +++ b/gdb/hppabsd-tdep.c @@ -0,0 +1,1428 @@ +/* Machine-dependent code which would otherwise be in inflow.c and core.c, + for GDB, the GNU debugger. This code is for the HP PA-RISC cpu. + Copyright (C) 1986, 1987, 1989, 1990, 1991 Free Software Foundation, Inc. + + Contributed by the Center for Software Science at the + University of Utah (pa-gdb-bugs@cs.utah.edu). + +This file is part of GDB. + +GDB 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 1, or (at your option) +any later version. + +GDB 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. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <stdio.h> +#include "defs.h" +#include "frame.h" +#include "inferior.h" +#include "value.h" + +/* For argument passing to the inferior */ +#include "symtab.h" + +#ifdef USG +#include <sys/types.h> +#endif + +#include <sys/param.h> +#include <sys/dir.h> +#include <signal.h> +#include <sys/ioctl.h> +/* #include <fcntl.h> Can we live without this? */ + +#ifdef COFF_ENCAPSULATE +#include "a.out.encap.h" +#else +#include <a.out.h> +#endif +#ifndef N_SET_MAGIC +#define N_SET_MAGIC(exec, val) ((exec).a_magic = (val)) +#endif + +/*#include <sys/user.h> After a.out.h */ +#include <sys/file.h> +#include <sys/stat.h> +#include <sys/ptrace.h> +#include <machine/psl.h> + +#ifdef KERNELDEBUG +#include <sys/vmmac.h> +#include <machine/machparam.h> +#include <machine/vmparam.h> +#include <machine/pde.h> +#include <machine/cpu.h> +#include <machine/iomod.h> +#include <machine/pcb.h> +#include <machine/rpb.h> +#include <ctype.h> + +extern int kernel_debugging; +extern CORE_ADDR startup_file_start; +extern CORE_ADDR startup_file_end; + +#define KERNOFF ((unsigned)KERNBASE) +#define INKERNEL(x) ((x) >= KERNOFF && (x) < KERNOFF + ctob(slr)) + +static int ok_to_cache(); +static void set_kernel_boundaries(); + +int devmem = 0; +int vtophys_ready = 0; +int kerneltype; +#define OS_BSD 1 +#define OS_MACH 2 +#endif + +#include "gdbcore.h" +#include "gdbcmd.h" + +extern int errno; + + + + + + +/* Last modification time of executable file. + Also used in source.c to compare against mtime of a source file. */ + +extern int exec_mtime; + +/* Virtual addresses of bounds of the two areas of memory in the core file. */ + +/* extern CORE_ADDR data_start; */ +extern CORE_ADDR data_end; +extern CORE_ADDR stack_start; +extern CORE_ADDR stack_end; + +/* Virtual addresses of bounds of two areas of memory in the exec file. + Note that the data area in the exec file is used only when there is no core file. */ + +extern CORE_ADDR text_start; +extern CORE_ADDR text_end; + +extern CORE_ADDR exec_data_start; +extern CORE_ADDR exec_data_end; + +/* Address in executable file of start of text area data. */ + +extern int text_offset; + +/* Address in executable file of start of data area data. */ + +extern int exec_data_offset; + +/* Address in core file of start of data area data. */ + +extern int data_offset; + +/* Address in core file of start of stack area data. */ + +extern int stack_offset; + +struct header file_hdr; +struct som_exec_auxhdr exec_hdr; + +#ifdef KERNELDEBUG +/* + * Kernel debugging routines. + */ + +static struct pcb pcb; +static struct pde *pdir; +static struct hte *htbl; +static u_int npdir, nhtbl; + +static CORE_ADDR +ksym_lookup(name) + char *name; +{ + struct symbol *sym; + int i; + + if ((i = lookup_misc_func(name)) < 0) + error("kernel symbol `%s' not found.", name); + + return (misc_function_vector[i].address); +} + +/* + * (re-)set the variables that tell "inside_entry_file" where to end + * a stack backtrace. + */ +void +set_kernel_boundaries() +{ + switch (kerneltype) { + case OS_MACH: + startup_file_start = ksym_lookup("$syscall"); + startup_file_end = ksym_lookup("trap"); + break; + case OS_BSD: + startup_file_start = ksym_lookup("syscallinit"); + startup_file_end = ksym_lookup("$syscallexit"); + break; + } +} + +/* + * return true if 'len' bytes starting at 'addr' can be read out as + * longwords and/or locally cached (this is mostly for memory mapped + * i/o register access when debugging remote kernels). + */ +static int +ok_to_cache(addr, len) +{ + static CORE_ADDR ioptr; + + if (! ioptr) + ioptr = ksym_lookup("ioptr"); + + if (addr >= ioptr && addr < SPA_HIGH) + return (0); + + return (1); +} + +static +physrd(addr, dat, len) + u_int addr; + char *dat; +{ + if (lseek(corechan, addr, L_SET) == -1) + return (-1); + if (read(corechan, dat, len) != len) + return (-1); + + return (0); +} + +/* + * When looking at kernel data space through /dev/mem or with a core file, do + * virtual memory mapping. + */ +static CORE_ADDR +vtophys(space, addr) + unsigned space; + CORE_ADDR addr; +{ + struct pde *pptr; + u_int hindx, vpageno, ppageno; + CORE_ADDR phys = ~0; + + if (!vtophys_ready) { + phys = addr; /* XXX for kvread */ + } else if (kerneltype == OS_BSD) { + /* make offset into a virtual page no */ + vpageno = btop(addr); + /* + * Determine index into hash table, initialize pptr to this + * entry (since first word of pte & hte are same), and set + * physical page number for first entry in chain. + */ + hindx = pdirhash(space, addr) & (nhtbl-1); + pptr = (struct pde *) &htbl[hindx]; + ppageno = pptr->pde_next; + while (1) { + if (pptr->pde_end) + break; + pptr = &pdir[ppageno]; + /* + * If space id & virtual page number match, return + * "next PDIR entry of previous PDIR entry" as the + * physical page or'd with offset into page. + */ + if (pptr->pde_space == space && + pptr->pde_page == vpageno) { + phys = (CORE_ADDR) ((u_int)ptob(ppageno) | + (addr & PGOFSET)); + break; + } + ppageno = pptr->pde_next; + } + } +#ifdef MACHKERNELDEBUG + else if (kerneltype == OS_MACH) { + (void) mach_vtophys(space, addr, &phys); + } +#endif +#if 0 + printf("vtophys(%x.%x) -> %x\n", space, addr, phys); +#endif + return (phys); +} + +static +kvread(addr) + CORE_ADDR addr; +{ + CORE_ADDR paddr; + + paddr = vtophys(0, addr); + if (paddr != ~0) + if (physrd(paddr, (char *)&addr, sizeof(addr)) == 0) + return (addr); + + return (~0); +} + +static void +read_pcb(addr) + u_int addr; +{ + int i, off; + extern char registers[]; + static int reg2pcb[] = { + /* RPB */ + -1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 45, 52, 51, 75, 74, 49, 53, 54, 55, 56, -1, 70, 66, 67, 68, 69, + 71, 72, 73, 34, 42, 43, 44, 46, 47, 58, 59, 60, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, + /* BSD */ + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 43, 64, 67, 68, 67, 47, 51, 52, 53, 54, -1, 35, 31, 32, 33, 34, + 36, 37, 38, 39, 40, 41, 42, 44, 45, 56, 57, 58,102,103,104, -1, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 80, 82, 84, 86, 88, 90, 92, + 94, 96, 98, 100, + /* Mach */ + -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, -1, -1, -1, -1, -1, -1, -1, -1, 17, -1, -1, 18, -1, + 25, -1, -1, -1, -1, 30, -1, -1, -1, -1, -1, 20, -1, -1, -1, 19, + 21, 22, 23, 24, 26, 27, -1, 28, 29, -1, -1, -1, -1, -1, -1, -1, + 34, 35, 36, 37, 38, 39, 40, 41, -1, -1, -1, -1, -1, -1, -1, -1, + 42, 44, 46, 48 + }; + static struct rpb *rpbaddr = (struct rpb *) 0; + static u_int rpbpcbaddr = 0; + + if (!remote_debugging) { + /* + * If we are debugging a post-mortem and this is the first + * call of read_pcb, read the RPB. Also assoicate the + * thread/proc running at the time with the RPB. + */ + if (!devmem && rpbpcbaddr == 0) { + CORE_ADDR raddr = ksym_lookup("rpb"); + int usepcb = 1; + + if (raddr != ~0) { + rpbaddr = (struct rpb *) malloc(sizeof *rpbaddr); + if (!physrd(raddr, (char *)rpbaddr, sizeof *rpbaddr)) { + rpbpcbaddr = addr; + usepcb = 0; + } + } + if (usepcb) { + error("cannot read rpb, using pcb for registers\n"); + if (rpbaddr) + free((char *)rpbaddr); + rpbpcbaddr = ~0; + } + } + if (physrd (addr, (char *)&pcb, sizeof pcb)) + error ("cannot read pcb at %x.\n", addr); + } else { + if (remote_read_inferior_memory(addr, (char *)&pcb, sizeof pcb)) + error ("cannot read pcb at %x.\n", addr); + } + + if (kerneltype == OS_BSD) { + printf("p0br %lx p0lr %lx p1br %lx p1lr %lx\n", + pcb.pcb_p0br, pcb.pcb_p0lr, pcb.pcb_p1br, pcb.pcb_p1lr); + off = NUM_REGS; + } else { + printf("pcb %lx psw %lx ksp %lx\n", + addr, ((int *)&pcb)[31], ((int *)&pcb)[32]); + off = NUM_REGS * 2; + } + /* + * get the register values out of the sys pcb and + * store them where `read_register' will find them. + */ + bzero(registers, REGISTER_BYTES); + for (i = 0; i < NUM_REGS; ++i) + if (reg2pcb[i+off] != -1) + supply_register(i, &((int *)&pcb)[reg2pcb[i+off]]); + /* + * If the RPB is valid for this thread/proc use the register values + * contained there. + */ + if (addr == rpbpcbaddr) { + off = 0; + for (i = 0; i < NUM_REGS; ++i) + if (reg2pcb[i+off] != -1) + supply_register(i, &((int *)rpbaddr)[reg2pcb[i+off]]); + } +} + +void +setup_kernel_debugging() +{ + struct stat stb; + CORE_ADDR addr; + + fstat(corechan, &stb); + devmem = 0; + if ((stb.st_mode & S_IFMT) == S_IFCHR && stb.st_rdev == makedev(2, 0)) + devmem = 1; + + /* XXX */ + if (lookup_misc_func("Sysmap") < 0) + kerneltype = OS_MACH; + else + kerneltype = OS_BSD; + + if (kerneltype == OS_BSD) { + int len, err = 0; + + /* + * Hash table and PDIR are equivalently mapped + */ + nhtbl = kvread(ksym_lookup("nhtbl")); + if (nhtbl != ~0) { + len = nhtbl * sizeof(*htbl); + htbl = (struct hte *) malloc(len); + if (htbl) { + addr = kvread(ksym_lookup("htbl")); + if (physrd(addr, (char *)htbl, len)) + err++; + } else + err++; + } else + err++; + npdir = kvread(ksym_lookup("npdir")); + if (npdir != ~0) { + len = npdir * sizeof(*pdir); + pdir = (struct pde *) malloc(len); + if (pdir) { + addr = kvread(ksym_lookup("pdir")); + if (physrd(addr, (char *)pdir, len)) + err++; + } else + err++; + } else + err++; + if (err) { + error("cannot read PDIR/HTBL"); + return; + } + vtophys_ready = 1; + + /* + * pcb where "panic" saved registers in first thing in + * current u-area. The current u-area is pointed to by + * "uptr". + */ + addr = kvread(ksym_lookup("uptr")); + if (addr == ~0) { + error("cannot read current u-area address"); + return; + } + read_pcb(vtophys(0, addr)); /* XXX space */ + if (!devmem) { + /* find stack frame */ + CORE_ADDR panicstr; + char buf[256]; + register char *cp; + + panicstr = kvread(ksym_lookup("panicstr")); + if (panicstr == ~0) + return; + (void) kernel_core_file_hook(panicstr, buf, sizeof(buf)); + for (cp = buf; cp < &buf[sizeof(buf)] && *cp; cp++) + if (!isascii(*cp) || (!isprint(*cp) && !isspace(*cp))) + *cp = '?'; + if (*cp) + *cp = '\0'; + printf("panic: %s\n", buf); + } + } +#ifdef MACHKERNELDEBUG + else { + int *thread; + + /* + * Set up address translation + */ + if (mach_vtophys_init() == 0) { + error("cannot initialize vtophys for Mach"); + return; + } + vtophys_ready = 1; + + /* + * Locate active thread and read PCB + * XXX MAJOR HACK + * - assumes uni-processor + * - assumes position of pcb to avoid mach includes + */ + thread = (int *)kvread(ksym_lookup("active_threads")); + addr = kvread(&thread[9]); /* XXX: pcb addr */ + read_pcb(vtophys(0, addr)); + } +#endif +} + +vtop_command(arg) + char *arg; +{ + u_int sp, off, pa; + + if (!arg) + error_no_arg("kernel virtual address"); + if (!kernel_debugging) + error("not debugging kernel"); + + sp = 0; /* XXX */ + off = (u_int) parse_and_eval_address(arg); + pa = vtophys(sp, off); + printf("%lx.%lx -> ", sp, off); + if (pa == ~0) + printf("<invalid>\n"); + else + printf("%lx\n", pa); +} + +set_paddr_command(arg) + char *arg; +{ + u_int addr; + + if (!arg) { + if (kerneltype == OS_BSD) + error_no_arg("ps-style address for new process"); + else + error_no_arg("thread structure virtual address"); + } + if (!kernel_debugging) + error("not debugging kernel"); + + addr = (u_int) parse_and_eval_address(arg); + if (kerneltype == OS_BSD) + addr = ctob(addr); + else { + addr = kvread(&(((int *)addr)[9])); /* XXX: pcb addr */ + addr = vtophys(0, addr); /* XXX space */ + } + read_pcb(addr); + + flush_cached_frames(); + set_current_frame(create_new_frame(read_register(FP_REGNUM), read_pc())); + select_frame(get_current_frame(), 0); +} + +/* + * read len bytes from kernel virtual address 'addr' into local + * buffer 'buf'. Return 0 if read ok, 1 otherwise. On read + * errors, portion of buffer not read is zeroed. + */ +kernel_core_file_hook(addr, buf, len) + CORE_ADDR addr; + char *buf; + int len; +{ + int i; + CORE_ADDR paddr; + + while (len > 0) { + paddr = vtophys(0, addr); /* XXX space */ + if (paddr == ~0) { + bzero(buf, len); + return (1); + } + /* we can't read across a page boundary */ + i = min(len, NBPG - (addr & PGOFSET)); + if (physrd(paddr, buf, i)) { + bzero(buf, len); + return (1); + } + buf += i; + addr += i; + len -= i; + } + return (0); +} +#endif + + + + + +/* Routines to extract various sized constants out of hppa + instructions. */ + +/* This assumes that no garbage lies outside of the lower bits of + value. */ + +int +sign_extend (val, bits) + unsigned val, bits; +{ + return (int)(val >> bits - 1 ? (-1 << bits) | val : val); +} + +/* For many immediate values the sign bit is the low bit! */ + +int +low_sign_extend (val, bits) + unsigned val, bits; +{ + return (int)((val & 0x1 ? (-1 << (bits - 1)) : 0) | val >> 1); +} +/* extract the immediate field from a ld{bhw}s instruction */ + + + +unsigned +get_field (val, from, to) + unsigned val, from, to; +{ + val = val >> 31 - to; + return val & ((1 << 32 - from) - 1); +} + +unsigned +set_field (val, from, to, new_val) + unsigned *val, from, to; +{ + unsigned mask = ~((1 << (to - from + 1)) << (31 - from)); + return *val = *val & mask | (new_val << (31 - from)); +} + +/* extract a 3-bit space register number from a be, ble, mtsp or mfsp */ + +extract_3 (word) + unsigned word; +{ + return GET_FIELD (word, 18, 18) << 2 | GET_FIELD (word, 16, 17); +} + +extract_5_load (word) + unsigned word; +{ + return low_sign_extend (word >> 16 & MASK_5, 5); +} + +/* extract the immediate field from a st{bhw}s instruction */ + +int +extract_5_store (word) + unsigned word; +{ + return low_sign_extend (word & MASK_5, 5); +} + +/* extract an 11 bit immediate field */ + +int +extract_11 (word) + unsigned word; +{ + return low_sign_extend (word & MASK_11, 11); +} + +/* extract a 14 bit immediate field */ + +int +extract_14 (word) + unsigned word; +{ + return low_sign_extend (word & MASK_14, 14); +} + +/* deposit a 14 bit constant in a word */ + +unsigned +deposit_14 (opnd, word) + int opnd; + unsigned word; +{ + unsigned sign = (opnd < 0 ? 1 : 0); + + return word | ((unsigned)opnd << 1 & MASK_14) | sign; +} + +/* extract a 21 bit constant */ + +int +extract_21 (word) + unsigned word; +{ + int val; + + word &= MASK_21; + word <<= 11; + val = GET_FIELD (word, 20, 20); + val <<= 11; + val |= GET_FIELD (word, 9, 19); + val <<= 2; + val |= GET_FIELD (word, 5, 6); + val <<= 5; + val |= GET_FIELD (word, 0, 4); + val <<= 2; + val |= GET_FIELD (word, 7, 8); + return sign_extend (val, 21) << 11; +} + +/* deposit a 21 bit constant in a word. Although 21 bit constants are + usually the top 21 bits of a 32 bit constant, we assume that only + the low 21 bits of opnd are relevant */ + +unsigned +deposit_21 (opnd, word) + unsigned opnd, word; +{ + unsigned val = 0; + + val |= GET_FIELD (opnd, 11 + 14, 11 + 18); + val <<= 2; + val |= GET_FIELD (opnd, 11 + 12, 11 + 13); + val <<= 2; + val |= GET_FIELD (opnd, 11 + 19, 11 + 20); + val <<= 11; + val |= GET_FIELD (opnd, 11 + 1, 11 + 11); + val <<= 1; + val |= GET_FIELD (opnd, 11 + 0, 11 + 0); + return word | val; +} + +/* extract a 12 bit constant from branch instructions */ + +int +extract_12 (word) + unsigned word; +{ + return sign_extend (GET_FIELD (word, 19, 28) | + GET_FIELD (word, 29, 29) << 10 | + (word & 0x1) << 11, 12) << 2; +} + +/* extract a 17 bit constant from branch instructions, returning the + 19 bit signed value. */ + +int +extract_17 (word) + unsigned word; +{ + return sign_extend (GET_FIELD (word, 19, 28) | + GET_FIELD (word, 29, 29) << 10 | + GET_FIELD (word, 11, 15) << 11 | + (word & 0x1) << 16, 17) << 2; +} + + +CORE_ADDR +frame_saved_pc (frame) + FRAME frame; +{ + if (get_current_frame () == frame) + { + struct frame_saved_regs saved_regs; + + get_frame_saved_regs (frame, &saved_regs); + if (saved_regs.regs[RP_REGNUM]) + return read_memory_integer (saved_regs.regs[RP_REGNUM], 4); + else + return read_register (RP_REGNUM); + } + return read_memory_integer (frame->frame - 20, 4) & ~0x3; +} + +/* To see if a frame chain is valid, see if the caller looks like it + was compiled with gcc. */ + +int frame_chain_valid (chain, thisframe) + FRAME_ADDR chain; + FRAME thisframe; +{ + if (chain && (chain > 0x60000000 + /* || remote_debugging -this is no longer used */ +#ifdef KERNELDEBUG + || kernel_debugging +#endif + )) + { + CORE_ADDR pc = get_pc_function_start (FRAME_SAVED_PC (thisframe)); + + if (!inside_entry_file (pc)) + return 0; + /* look for stw rp, -20(0,sp); copy 4,1; copy sp, 4 */ + if (read_memory_integer (pc, 4) == 0x6BC23FD9) + pc = pc + 4; + + if (read_memory_integer (pc, 4) == 0x8040241 && + read_memory_integer (pc + 4, 4) == 0x81E0244) + return 1; + else + return 0; + } + else + return 0; +} + +/* Some helper functions. gcc_p returns 1 if the function beginning at + pc appears to have been compiled with gcc. hpux_cc_p returns 1 if + fn was compiled with hpux cc. gcc functions look like : + + stw rp,-0x14(sp) ; optional + or r4,r0,r1 + or sp,r0,r4 + stwm r1,framesize(sp) + + hpux cc functions look like: + + stw rp,-0x14(sp) ; optional. + stwm r3,framesiz(sp) + */ + +gcc_p (pc) + CORE_ADDR pc; +{ + if (read_memory_integer (pc, 4) == 0x6BC23FD9) + pc = pc + 4; + + if (read_memory_integer (pc, 4) == 0x8040241 && + read_memory_integer (pc + 4, 4) == 0x81E0244) + return 1; + return 0; +} + + +find_dummy_frame_regs (frame, frame_saved_regs) + struct frame_info *frame; + struct frame_saved_regs *frame_saved_regs; +{ + CORE_ADDR fp = frame->frame; + int i; + + frame_saved_regs->regs[RP_REGNUM] = fp - 20 & ~0x3; + frame_saved_regs->regs[FP_REGNUM] = fp; + frame_saved_regs->regs[1] = fp + 8; + frame_saved_regs->regs[3] = fp + 12; + for (fp += 16, i = 3; i < 30; fp += 4, i++) + frame_saved_regs->regs[i] = fp; + frame_saved_regs->regs[31] = fp; + fp += 4; + for (i = FP0_REGNUM; i < NUM_REGS; i++, fp += 8) + frame_saved_regs->regs[i] = fp; + /* depend on last increment of fp */ + frame_saved_regs->regs[IPSW_REGNUM] = fp - 4; + frame_saved_regs->regs[SAR_REGNUM] = fp; + fp += 4; + frame_saved_regs->regs[PCOQ_TAIL_REGNUM] = fp; + frame_saved_regs->regs[PCSQ_TAIL_REGNUM] = fp; +} + +CORE_ADDR +hp_push_arguments (nargs, args, sp, struct_return, struct_addr) + int nargs; + value *args; + CORE_ADDR sp; + int struct_return; + CORE_ADDR struct_addr; +{ + /* array of arguments' offsets */ + int *offset = (int *)alloca(nargs); + int cum = 0; + int i, alignment; + + for (i = 0; i < nargs; i++) + { + cum += TYPE_LENGTH (VALUE_TYPE (args[i])); + /* value must go at proper alignment. Assume alignment is a + power of two.*/ + alignment = hp_alignof (VALUE_TYPE (args[i])); + if (cum % alignment) + cum = (cum + alignment) & -alignment; + offset[i] = -cum; + } + for (i == 0; i < nargs; i++) + { + write_memory (sp + offset[i], VALUE_CONTENTS (args[i]), sizeof(int)); + } + sp += min ((cum + 7) & -8, 48); + if (struct_return) + write_register (28, struct_addr); + return sp + 48; +} + +/* return the alignment of a type in bytes. Structures have the maximum + alignment required by their fields. */ + +int +hp_alignof (arg) + struct type *arg; +{ + int max_align, align, i; + switch (TYPE_CODE (arg)) + { + case TYPE_CODE_PTR: + case TYPE_CODE_INT: + case TYPE_CODE_FLT: + return TYPE_LENGTH (arg); + case TYPE_CODE_ARRAY: + return hp_alignof (TYPE_FIELD_TYPE (arg, 0)); + case TYPE_CODE_STRUCT: + case TYPE_CODE_UNION: + max_align = 2; + for (i = 0; i < TYPE_NFIELDS (arg); i++) + { + /* Bit fields have no real alignment. */ + if (!TYPE_FIELD_BITPOS (arg, i)) + { + align = hp_alignof (TYPE_FIELD_TYPE (arg, i)); + max_align = max (max_align, align); + } + } + return max_align; + default: + return 4; + } +} + +/* Print the register regnum, or all registers if regnum is -1 */ + +pa_do_registers_info (regnum, fpregs) + int regnum; + int fpregs; +{ + char raw_regs [REGISTER_BYTES]; + int i; + + for (i = 0; i < NUM_REGS; i++) + read_relative_register_raw_bytes (i, raw_regs + REGISTER_BYTE (i)); + if (regnum = -1) + pa_print_registers (raw_regs, regnum); + else if (regnum < FP0_REGNUM) + { + printf ("%s %x\n", reg_names[regnum], *(long *)(raw_regs + + REGISTER_BYTE (regnum))); + } + else + pa_print_fp_reg (regnum); +} + +pa_print_registers (raw_regs, regnum) + char *raw_regs; + int regnum; +{ + int i; + + for (i = 0; i < 18; i++) + printf ("%8.8s: %8x %8.8s: %8x %8.8s: %8x %8.8s: %8x\n", + reg_names[i], + *(int *)(raw_regs + REGISTER_BYTE (i)), + reg_names[i + 18], + *(int *)(raw_regs + REGISTER_BYTE (i + 18)), + reg_names[i + 36], + *(int *)(raw_regs + REGISTER_BYTE (i + 36)), + reg_names[i + 54], + *(int *)(raw_regs + REGISTER_BYTE (i + 54))); + for (i = 72; i < NUM_REGS; i++) + pa_print_fp_reg (i); +} + +pa_print_fp_reg (i) + int i; +{ + unsigned char raw_buffer[MAX_REGISTER_RAW_SIZE]; + unsigned char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE]; + REGISTER_TYPE val; + + /* Get the data in raw format, then convert also to virtual format. */ + read_relative_register_raw_bytes (i, raw_buffer); + REGISTER_CONVERT_TO_VIRTUAL (i, raw_buffer, virtual_buffer); + + fputs_filtered (reg_names[i], stdout); + print_spaces_filtered (15 - strlen (reg_names[i]), stdout); + + val_print (REGISTER_VIRTUAL_TYPE (i), virtual_buffer, 0, stdout, 0, + 1, 0, Val_pretty_default); + printf_filtered ("\n"); + +} + +/* + * Virtual to physical translation routines for Utah's Mach 3.0 + */ +#ifdef MACHKERNELDEBUG + +#define STATIC + +#if 0 /* too many includes to resolve, too much crap */ +#include <kern/queue.h> +#include <vm/pmap.h> +#include <mach/vm_prot.h> +#else +/* queue.h */ +struct queue_entry { + struct queue_entry *next; /* next element */ + struct queue_entry *prev; /* previous element */ +}; + +typedef struct queue_entry *queue_t; +typedef struct queue_entry queue_head_t; +typedef struct queue_entry queue_chain_t; +typedef struct queue_entry *queue_entry_t; + +/* pmap.h */ +#define HP800_HASHSIZE 1024 +#define HP800_HASHSIZE_LOG2 10 + +#define pmap_hash(space, offset) \ + (((unsigned) (space) << 5 ^ \ + ((unsigned) (offset) >> 19 | (unsigned) (space) << 13) ^ \ + (unsigned) (offset) >> 11) & (HP800_HASHSIZE-1)) + +struct mapping { + queue_head_t hash_link; /* hash table links */ + queue_head_t phys_link; /* for mappings of a given PA */ + space_t space; /* virtual space */ + unsigned offset; /* virtual page number */ + unsigned tlbpage; /* physical page (for TLB load) */ + unsigned tlbprot; /* prot/access rights (for TLB load) */ + struct pmap *pmap; /* pmap mapping belongs to */ +}; + +struct phys_entry { + queue_head_t phys_link; /* head of mappings of a given PA */ + struct mapping *writer; /* mapping with R/W access */ + unsigned tlbprot; /* TLB format protection */ +}; + +#endif + +#define atop(a) ((unsigned)(a) >> 11) +#define ptoa(p) ((unsigned)(p) << 11) +#define trunc_page(a) ((unsigned)(a) & ~2047) + +STATIC long equiv_end; +STATIC queue_head_t *Ovtop_table, *vtop_table, *Ofree_mapping, free_mapping; +STATIC struct phys_entry *Ophys_table, *phys_table; +STATIC long vm_last_phys, vm_first_phys; +STATIC struct mapping *firstmap, *lastmap, *Omap_table, *map_table; +STATIC unsigned Omlow, Omhigh, Omhead, Ovlow, Ovhigh, Oplow, Ophigh; +STATIC unsigned mlow, mhigh, mhead, vlow, vhigh, plow, phigh; +STATIC int vtopsize, physsize, mapsize; +STATIC int kmemfd; + +#define IS_OVTOPPTR(p) ((unsigned)(p) >= Ovlow && (unsigned)(p) < Ovhigh) +#define IS_OMAPPTR(p) ((unsigned)(p) >= Omlow && (unsigned)(p) < Omhigh) +#define IS_OPHYSPTR(p) ((unsigned)(p) >= Oplow && (unsigned)(p) < Ophigh) +#define IS_VTOPPTR(p) ((unsigned)(p) >= vlow && (unsigned)(p) < vhigh) +#define IS_MAPPTR(p) ((unsigned)(p) >= mlow && (unsigned)(p) < mhigh) +#define IS_PHYSPTR(p) ((unsigned)(p) >= plow && (unsigned)(p) < phigh) + +struct mapstate { + char unused; + char flags; + short hashix; + short physix; +} *mapstate; + +/* flags */ +#define M_ISFREE 1 +#define M_ISHASH 2 +#define M_ISPHYS 4 + +mach_vtophys_init() +{ + int errors = 0; + + if (!readdata()) + errors++; + if (!verifydata()) + errors++; + if (!errors) + return(1); + fflush(stdout); + fprintf(stderr, + "translate: may not be able to translate all addresses\n"); + return(0); +} + +mach_vtophys(space, off, pa) + unsigned space, off, *pa; +{ + register int i; + register queue_t qp; + register struct mapping *mp; + int poff; + + /* + * Kernel IO or equivilently mapped, one to one. + */ + if (space == 0 && (long)off < equiv_end) { + *pa = off; + return(1); + } + /* + * Else look it up in specified space + */ + poff = off - trunc_page(off); + off = trunc_page(off); + qp = &vtop_table[pmap_hash(space, off)]; + for (mp = (struct mapping *)qp->next; + qp != (queue_entry_t)mp; + mp = (struct mapping *)mp->hash_link.next) { + if (mp->space == space && mp->offset == off) { + *pa = (mp->tlbpage << 7) | poff; + return(1); + } + } + return(0); +} + +STATIC +readdata() +{ + char *tmp, *mach_malloc(); + long size; + + /* easy scalars */ + mach_read("equiv_end", ~0, (char *)&equiv_end, sizeof equiv_end); + mach_read("vm_first_phys", ~0, + (char *)&vm_first_phys, sizeof vm_first_phys); + mach_read("vm_last_phys", ~0, + (char *)&vm_last_phys, sizeof vm_last_phys); + mach_read("firstmap", ~0, (char *)&firstmap, sizeof firstmap); + mach_read("lastmap", ~0, (char *)&lastmap, sizeof lastmap); + + /* virtual to physical hash table */ + vtopsize = HP800_HASHSIZE; + size = vtopsize * sizeof(queue_head_t); + tmp = mach_malloc("vtop table", size); + mach_read("vtop_table", ~0, (char *)&Ovtop_table, sizeof Ovtop_table); + mach_read("vtop table", (CORE_ADDR)Ovtop_table, tmp, size); + vtop_table = (queue_head_t *) tmp; + + /* inverted page table */ + physsize = atop(vm_last_phys - vm_first_phys); + size = physsize * sizeof(struct phys_entry); + tmp = mach_malloc("phys table", size); + mach_read("phys_table", ~0, (char *)&Ophys_table, sizeof Ophys_table); + mach_read("phys table", (CORE_ADDR)Ophys_table, tmp, size); + phys_table = (struct phys_entry *) tmp; + + /* mapping structures */ + Ofree_mapping = (queue_head_t *) ksym_lookup("free_mapping"); + mach_read("free mapping", (CORE_ADDR)Ofree_mapping, + (char *) &free_mapping, sizeof free_mapping); + Omap_table = firstmap; + mapsize = lastmap - firstmap; + size = mapsize * sizeof(struct mapping); + tmp = mach_malloc("mapping table", size); + mach_read("mapping table", (CORE_ADDR)Omap_table, tmp, size); + map_table = (struct mapping *) tmp; + + /* set limits */ + Ovlow = (unsigned) Ovtop_table; + Ovhigh = (unsigned) &Ovtop_table[vtopsize]; + Oplow = (unsigned) Ophys_table; + Ophigh = (unsigned) &Ophys_table[physsize]; + Omhead = (unsigned) Ofree_mapping; + Omlow = (unsigned) firstmap; + Omhigh = (unsigned) lastmap; + mlow = (unsigned) map_table; + mhigh = (unsigned) &map_table[mapsize]; + mhead = (unsigned) &free_mapping; + vlow = (unsigned) vtop_table; + vhigh = (unsigned) &vtop_table[vtopsize]; + plow = (unsigned) phys_table; + phigh = (unsigned) &phys_table[physsize]; + +#if 0 + fprintf(stderr, "Ovtop [%#x-%#x) Ophys [%#x-%#x) Omap %#x [%#x-%#x)\n", + Ovlow, Ovhigh, Oplow, Ophigh, Omhead, Omlow, Omhigh); + fprintf(stderr, "vtop [%#x-%#x) phys [%#x-%#x) map %#x [%#x-%#x)\n", + vlow, vhigh, plow, phigh, mhead, mlow, mhigh); +#endif + return(adjustdata()); +} + +STATIC unsigned +ptrcvt(ptr) + unsigned ptr; +{ + unsigned ret; + char *str; + + if (ptr == 0) { + ret = ptr; + str = "null"; + } else if (IS_OVTOPPTR(ptr)) { + ret = vlow + (ptr - Ovlow); + str = "vtop"; + } else if (IS_OPHYSPTR(ptr)) { + ret = plow + (ptr - Oplow); + str = "phys"; + } else if (IS_OMAPPTR(ptr)) { + ret = mlow + (ptr - Omlow); + str = "map"; + } else if (ptr == Omhead) { + ret = mhead; + str = "maphead"; + } else { + error("bogus pointer %#x", ptr); + str = "wild"; + ret = ptr; + } +#if 0 + fprintf(stderr, "%x (%s) -> %x\n", ptr, str, ret); +#endif + return(ret); +} + +STATIC int +adjustdata() +{ + register int i, lim; + queue_head_t *nq; + struct phys_entry *np; + struct mapping *nm; + + /* hash table */ + lim = vtopsize; + for (nq = vtop_table; nq < &vtop_table[lim]; nq++) { + nq->next = (queue_entry_t) ptrcvt((unsigned)nq->next); + nq->prev = (queue_entry_t) ptrcvt((unsigned)nq->prev); + } + + /* IPT */ + lim = physsize; + for (np = phys_table; np < &phys_table[lim]; np++) { + np->phys_link.next = (queue_entry_t) + ptrcvt((unsigned)np->phys_link.next); + np->phys_link.prev = (queue_entry_t) + ptrcvt((unsigned)np->phys_link.prev); + np->writer = (struct mapping *) ptrcvt((unsigned)np->writer); + } + + /* mapping table */ + free_mapping.next = (queue_entry_t)ptrcvt((unsigned)free_mapping.next); + free_mapping.prev = (queue_entry_t)ptrcvt((unsigned)free_mapping.prev); + lim = mapsize; + for (nm = map_table; nm < &map_table[lim]; nm++) { + nm->hash_link.next = (queue_entry_t) + ptrcvt((unsigned)nm->hash_link.next); + nm->hash_link.prev = (queue_entry_t) + ptrcvt((unsigned)nm->hash_link.prev); + nm->phys_link.next = (queue_entry_t) + ptrcvt((unsigned)nm->phys_link.next); + nm->phys_link.prev = (queue_entry_t) + ptrcvt((unsigned)nm->phys_link.prev); + } + return(1); +} + +/* + * Consistency checks, make sure: + * + * 1. all mappings are accounted for + * 2. no cycles + * 3. no wild pointers + * 4. consisent TLB state + */ +STATIC int +verifydata() +{ + register struct mapstate *ms; + register int i; + int errors = 0; + + mapstate = (struct mapstate *) + mach_malloc("map state", mapsize * sizeof(struct mapstate)); + for (ms = mapstate; ms < &mapstate[mapsize]; ms++) { + ms->flags = 0; + ms->hashix = ms->physix = -2; + } + + /* + * Check the free list + */ + checkhashchain(&free_mapping, M_ISFREE, -1); + /* + * Check every hash chain + */ + for (i = 0; i < vtopsize; i++) + checkhashchain(&vtop_table[i], M_ISHASH, i); + /* + * Check every phys chain + */ + for (i = 0; i < physsize; i++) + checkphyschain(&phys_table[i].phys_link, M_ISPHYS, i); + /* + * Cycle through mapstate looking for anomolies + */ + ms = mapstate; + for (i = 0; i < mapsize; i++) { + switch (ms->flags) { + case M_ISFREE: + case M_ISHASH|M_ISPHYS: + break; + case 0: + merror(ms, "not found"); + errors++; + break; + case M_ISHASH: + merror(ms, "in vtop but not phys"); + errors++; + break; + case M_ISPHYS: + merror(ms, "in phys but not vtop"); + errors++; + break; + default: + merror(ms, "totally bogus"); + errors++; + break; + } + ms++; + } + return(errors ? 0 : 1); +} + +STATIC void +checkhashchain(qhp, flag, ix) + queue_entry_t qhp; +{ + register queue_entry_t qp, pqp; + register struct mapping *mp; + struct mapstate *ms; + + qp = qhp->next; + /* + * First element is not a mapping structure, + * chain must be empty. + */ + if (!IS_MAPPTR(qp)) { + if (qp != qhp || qp != qhp->prev) + fatal("bad vtop_table header pointer"); + } else { + pqp = qhp; + do { + mp = (struct mapping *) qp; + qp = &mp->hash_link; + if (qp->prev != pqp) + fatal("bad hash_link prev pointer"); + ms = &mapstate[mp-map_table]; + ms->flags |= flag; + ms->hashix = ix; + pqp = (queue_entry_t) mp; + qp = qp->next; + } while (IS_MAPPTR(qp)); + if (qp != qhp) + fatal("bad hash_link next pointer"); + } +} + +STATIC void +checkphyschain(qhp, flag, ix) + queue_entry_t qhp; +{ + register queue_entry_t qp, pqp; + register struct mapping *mp; + struct mapstate *ms; + + qp = qhp->next; + /* + * First element is not a mapping structure, + * chain must be empty. + */ + if (!IS_MAPPTR(qp)) { + if (qp != qhp || qp != qhp->prev) + fatal("bad phys_table header pointer"); + } else { + pqp = qhp; + do { + mp = (struct mapping *) qp; + qp = &mp->phys_link; + if (qp->prev != pqp) + fatal("bad phys_link prev pointer"); + ms = &mapstate[mp-map_table]; + ms->flags |= flag; + ms->physix = ix; + pqp = (queue_entry_t) mp; + qp = qp->next; + } while (IS_MAPPTR(qp)); + if (qp != qhp) + fatal("bad phys_link next pointer"); + } +} + +STATIC void +merror(ms, str) + struct mapstate *ms; + char *str; +{ + terminal_ours(); + fflush(stdout); + fprintf(stderr, + "vtophys: %s: %c%c%c, hashix %d, physix %d, mapping %x\n", + str, + (ms->flags & M_ISFREE) ? 'F' : '-', + (ms->flags & M_ISHASH) ? 'H' : '-', + (ms->flags & M_ISPHYS) ? 'P' : '-', + ms->hashix, ms->physix, &map_table[ms-mapstate]); + return_to_top_level(); +} + +STATIC int +mach_read(str, from, top, size) + char *str; + CORE_ADDR from; + char *top; + int size; +{ + CORE_ADDR paddr; + + if (from == ~0) + from = ksym_lookup(str); + paddr = vtophys(0, from); + if (paddr == ~0 || physrd(paddr, top, size) != 0) + fatal("cannot read %s", str); +} + +STATIC char * +mach_malloc(str, size) + char *str; + int size; +{ + char *ptr = (char *) malloc(size); + + if (ptr == 0) + fatal("no memory for %s", str); + return(ptr); +} +#endif + +#ifdef KERNELDEBUG +void +_initialize_hp9k8_dep() +{ + add_com ("process-address", class_obscure, set_paddr_command, +"The process identified by (ps-style) ADDR becomes the\n\ +\"current\" process context for kernel debugging."); + add_com_alias ("paddr", "process-address", class_obscure, 0); + add_com ("virtual-to-physical", class_obscure, vtop_command, +"Translates the kernel virtual address ADDR into a physical address."); + add_com_alias ("vtop", "virtual-to-physical", class_obscure, 0); +} +#endif + + + + |