From fb1415aebefaf9091dc268a47045c832a8778622 Mon Sep 17 00:00:00 2001 From: John Gilmore Date: Sat, 26 Sep 1992 10:27:10 +0000 Subject: Rename all HPPA files to fit into unique DOS filenames: *hppabsd* => *hppab* *hppahpux* => *hppah* --- gdb/hppab-core.c | 251 ++++++++++ gdb/hppab-tdep.c | 1422 +++++++++++++++++++++++++++++++++++++++++++++++++++++ gdb/hppab-xdep.c | 406 ++++++++++++++++ gdb/hppah-tdep.c | 1427 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ gdb/hppah-xdep.c | 417 ++++++++++++++++ gdb/tm-hppab.h | 6 + gdb/tm-hppah.h | 39 ++ gdb/xm-hppab.h | 48 ++ gdb/xm-hppah.h | 52 ++ 9 files changed, 4068 insertions(+) create mode 100644 gdb/hppab-core.c create mode 100644 gdb/hppab-tdep.c create mode 100644 gdb/hppab-xdep.c create mode 100644 gdb/hppah-tdep.c create mode 100644 gdb/hppah-xdep.c create mode 100644 gdb/tm-hppab.h create mode 100644 gdb/tm-hppah.h create mode 100644 gdb/xm-hppab.h create mode 100644 gdb/xm-hppah.h diff --git a/gdb/hppab-core.c b/gdb/hppab-core.c new file mode 100644 index 0000000..5ca5f9b --- /dev/null +++ b/gdb/hppab-core.c @@ -0,0 +1,251 @@ +/* Machine-dependent code which would otherwise be in core.c + for GDB, the GNU debugger. This code is for the HP PA-RISC cpu. + Copyright 1986, 1987, 1989, 1990, 1991, 1992 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. + +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. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" + +#ifdef USG +#include +#endif + +#include +#include +#include +#include +/* #include Can we live without this? */ + +#ifndef hpux +#include +#include +#include +#include "/usr/src/sys/hpux/hpux.h" +#define USRSTACK 0x68FF3000 +#else +#include /* After a.out.h */ +#endif + +#include +#include +#include + +#ifndef hpux +#undef USIZE +#undef UPAGES + +#define USIZE 3 +#define UPAGES 7 +#endif + +extern int errno; + +/* File names of core file and executable file. */ + +extern char *corefile; +extern char *execfile; + +/* Descriptors on which core file and executable file are open. + Note that the execchan is closed when an inferior is created + and reopened if the inferior dies or is killed. */ + +extern int corechan; +extern int execchan; + +/* 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; + +extern struct header file_hdr; +extern struct som_exec_auxhdr exec_hdr; + +extern int (*core_file_hook)(); + +#ifdef KERNELDEBUG + +extern int kernel_debugging; +extern int kernel_core_file_hook(); + +#endif + +core_file_command (filename, from_tty) + char *filename; + int from_tty; +{ + int val; + extern char registers[]; +#ifdef KERNELDEBUG + struct stat stb; +#endif + + /* Discard all vestiges of any previous core file + and mark data and stack spaces as empty. */ + + if (corefile) + free (corefile); + corefile = 0; + core_file_hook = 0; + + if (corechan >= 0) + close (corechan); + corechan = -1; + + data_start = 0; + data_end = 0; + stack_start = STACK_END_ADDR; + stack_end = STACK_END_ADDR; + + /* Now, if a new core file was specified, open it and digest it. */ + + if (filename) + { + filename = tilde_expand (filename); + make_cleanup (free, filename); + + if (have_inferior_p ()) + error ("To look at a core file, you must kill the inferior with \"kill\"."); + corechan = open (filename, O_RDONLY, 0); + if (corechan < 0) + perror_with_name (filename); + +#ifdef KERNELDEBUG + fstat(corechan, &stb); + + if (kernel_debugging) { + setup_kernel_debugging(); + core_file_hook = kernel_core_file_hook; + set_kernel_boundaries(); + } else if ((stb.st_mode & S_IFMT) == S_IFCHR && + stb.st_rdev == makedev(2, 1)) { + /* looking at /dev/kmem */ + data_offset = data_start = KERNBASE; + data_end = ~0; /* XXX */ + stack_end = stack_start = data_end; + set_kernel_boundaries(); + } else +#endif + { + /* HP PA-RISC style corefile. */ +#ifndef hpux + struct hpuxuser u; +#else + struct user u; +#endif + + unsigned int reg_offset; + + val = myread (corechan, &u, sizeof u); + if (val < 0) + perror_with_name ("Not a core file: reading upage"); + if (val != sizeof u) + error ("Not a core file: could only read %d bytes", val); + + /* We are depending on exec_file_command having been called + previously to set exec_data_start. Since the executable + and the core file share the same text segment, the address + of the data segment will be the same in both. */ + data_start = exec_data_start; + + data_end = data_start + NBPG * u.u_dsize; + stack_start = USRSTACK; /* from sys/param.h */ + stack_end = stack_start + NBPG * u.u_ssize; + data_offset = NBPG * UPAGES; + stack_offset = NBPG * (UPAGES + u.u_dsize); + + /* Some machines put an absolute address in here and some put + the offset in the upage of the regs. */ + reg_offset = NBPG * USIZE; + /* Read the register values out of the core file and store + them where `read_register' will find them. */ + + { + register int regno; + + for (regno = 0; regno < NUM_REGS; regno++) + { + unsigned char buf[MAX_REGISTER_RAW_SIZE]; + + val = lseek (corechan, register_addr (regno, reg_offset), 0); + if (val < 0 + || (val = myread (corechan, buf, sizeof buf)) < 0) + { + char * buffer = (char *) alloca (strlen (reg_names[regno]) + + 30); + strcpy (buffer, "Reading register "); + strcat (buffer, reg_names[regno]); + + perror_with_name (buffer); + } + if (regno == PCOQ_HEAD_REGNUM || regno == PCOQ_TAIL_REGNUM) + buf[3] &= ~0x3; + supply_register (regno, buf); + } + } + } + if (filename[0] == '/') + corefile = savestring (filename, strlen (filename)); + else + { + corefile = concat (current_directory, "/", filename); + } + + set_current_frame ( create_new_frame (read_register (FP_REGNUM), + read_pc ())); + select_frame (get_current_frame (), 0); + validate_files (); + } + else if (from_tty) + printf ("No core file now.\n"); +} diff --git a/gdb/hppab-tdep.c b/gdb/hppab-tdep.c new file mode 100644 index 0000000..8fe6d28 --- /dev/null +++ b/gdb/hppab-tdep.c @@ -0,0 +1,1422 @@ +/* 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 1986, 1987, 1989, 1990, 1991, 1992 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. + +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. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" +#include "value.h" + +/* For argument passing to the inferior */ +#include "symtab.h" + +#ifdef USG +#include +#endif + +#include +#include +#include +#include + +#ifdef COFF_ENCAPSULATE +#include "a.out.encap.h" +#else +#include +#endif +#ifndef N_SET_MAGIC +#define N_SET_MAGIC(exec, val) ((exec).a_magic = (val)) +#endif + +/*#include After a.out.h */ +#include +#include +#include +#include + +#ifdef KERNELDEBUG +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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) { + 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; + 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("\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 +#include +#include +#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 diff --git a/gdb/hppab-xdep.c b/gdb/hppab-xdep.c new file mode 100644 index 0000000..01d7404 --- /dev/null +++ b/gdb/hppab-xdep.c @@ -0,0 +1,406 @@ +/* Host-dependent code for HP PA-RISC running BSD Unix, for GDB. + Copyright 1986, 1987, 1989, 1990, 1991, 1992 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. + +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. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" +#include "target.h" + +#ifdef USG +#include +#endif + +#include +#include +#include +#include +#ifndef USG +#include +#endif + + +#ifndef PT_ATTACH +#define PT_ATTACH PTRACE_ATTACH +#endif +#ifndef PT_DETACH +#define PT_DETACH PTRACE_DETACH +#endif + +#include "gdbcore.h" +#include /* After a.out.h */ +#include +#include + +/* This function simply calls ptrace with the given arguments. + It exists so that all calls to ptrace are isolated in this + machine-dependent file. */ +int +call_ptrace (request, pid, addr, data) + int request, pid; + PTRACE_ARG3_TYPE addr; + int data; +{ + return ptrace (request, pid, addr, data); +} + +#ifdef DEBUG_PTRACE +/* For the rest of the file, use an extra level of indirection */ +/* This lets us breakpoint usefully on call_ptrace. */ +#define ptrace call_ptrace +#endif + +void +kill_inferior () +{ + if (inferior_pid == 0) + return; + ptrace (PT_KILL, inferior_pid, (PTRACE_ARG3_TYPE) 0, 0); + wait ((int *)0); + target_mourn_inferior (); +} + +/* Resume execution of the inferior process. + If STEP is nonzero, single-step it. + If SIGNAL is nonzero, give it that signal. */ + +void +child_resume (step, signal) + int step; + int signal; +{ + errno = 0; + + /* An address of (PTRACE_ARG3_TYPE) 1 tells ptrace to continue from where + it was. (If GDB wanted it to start some other way, we have already + written a new PC value to the child.) */ + + if (step) + ptrace (PT_STEP, inferior_pid, (PTRACE_ARG3_TYPE) 1, signal); + else + ptrace (PT_CONTINUE, inferior_pid, (PTRACE_ARG3_TYPE) 1, signal); + + if (errno) + perror_with_name ("ptrace"); +} + +#ifdef ATTACH_DETACH +/* Nonzero if we are debugging an attached process rather than + an inferior. */ +extern int attach_flag; + +/* Start debugging the process whose number is PID. */ +int +attach (pid) + int pid; +{ + errno = 0; + ptrace (PT_ATTACH, pid, (PTRACE_ARG3_TYPE) 0, 0); + if (errno) + perror_with_name ("ptrace"); + attach_flag = 1; + return pid; +} + +/* Stop debugging the process whose number is PID + and continue it with signal number SIGNAL. + SIGNAL = 0 means just continue it. */ + +void +detach (signal) + int signal; +{ + errno = 0; + ptrace (PT_DETACH, inferior_pid, (PTRACE_ARG3_TYPE) 1, signal); + if (errno) + perror_with_name ("ptrace"); + attach_flag = 0; +} +#endif /* ATTACH_DETACH */ + +#if !defined (FETCH_INFERIOR_REGISTERS) + +/* KERNEL_U_ADDR is the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. */ +#if defined (KERNEL_U_ADDR_BSD) +/* Get kernel_u_addr using BSD-style nlist(). */ +CORE_ADDR kernel_u_addr; + +#include /* For struct nlist */ + +void +_initialize_kernel_u_addr () +{ + struct nlist names[2]; + + names[0].n_un.n_name = "_u"; + names[1].n_un.n_name = NULL; + if (nlist ("/vmunix", names) == 0) + kernel_u_addr = names[0].n_value; + else + fatal ("Unable to get kernel u area address."); +} +#endif /* KERNEL_U_ADDR_BSD. */ + +#if defined (KERNEL_U_ADDR_HPUX) +/* Get kernel_u_addr using HPUX-style nlist(). */ +CORE_ADDR kernel_u_addr; + +struct hpnlist { + char * n_name; + long n_value; + unsigned char n_type; + unsigned char n_length; + short n_almod; + short n_unused; +}; +static struct hpnlist nl[] = {{ "_u", -1, }, { (char *) 0, }}; + +/* read the value of the u area from the hp-ux kernel */ +void _initialize_kernel_u_addr () +{ + struct user u; + nlist ("/hp-ux", &nl); + kernel_u_addr = nl[0].n_value; +} +#endif /* KERNEL_U_ADDR_HPUX. */ + +#if !defined (offsetof) +#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER) +#endif + +/* U_REGS_OFFSET is the offset of the registers within the u area. */ +#if !defined (U_REGS_OFFSET) +#define U_REGS_OFFSET \ + ptrace (PT_READ_U, inferior_pid, \ + (PTRACE_ARG3_TYPE) (offsetof (struct user, u_ar0)), 0) \ + - KERNEL_U_ADDR +#endif + +/* Registers we shouldn't try to fetch. */ +#if !defined (CANNOT_FETCH_REGISTER) +#define CANNOT_FETCH_REGISTER(regno) 0 +#endif + +/* Fetch one register. */ + +static void +fetch_register (regno) + int regno; +{ + register unsigned int regaddr; + char buf[MAX_REGISTER_RAW_SIZE]; + char mess[128]; /* For messages */ + register int i; + + /* Offset of registers within the u area. */ + unsigned int offset; + + if (CANNOT_FETCH_REGISTER (regno)) + { + bzero (buf, REGISTER_RAW_SIZE (regno)); /* Supply zeroes */ + supply_register (regno, buf); + return; + } + + offset = U_REGS_OFFSET; + + regaddr = register_addr (regno, offset); + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int)) + { + errno = 0; + *(int *) &buf[i] = ptrace (PT_RUREGS, inferior_pid, + (PTRACE_ARG3_TYPE) regaddr, 0); + regaddr += sizeof (int); + if (errno != 0) + { + sprintf (mess, "reading register %s (#%d)", reg_names[regno], regno); + perror_with_name (mess); + } + } + supply_register (regno, buf); +} + + +/* Fetch all registers, or just one, from the child process. */ + +void +fetch_inferior_registers (regno) + int regno; +{ + if (regno == -1) + for (regno = 0; regno < NUM_REGS; regno++) + fetch_register (regno); + else + fetch_register (regno); +} + +/* Registers we shouldn't try to store. */ +#if !defined (CANNOT_STORE_REGISTER) +#define CANNOT_STORE_REGISTER(regno) 0 +#endif + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +void +store_inferior_registers (regno) + int regno; +{ + register unsigned int regaddr; + char buf[80]; + extern char registers[]; + register int i; + + unsigned int offset = U_REGS_OFFSET; + + if (regno >= 0) + { + regaddr = register_addr (regno, offset); + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(int)) + { + errno = 0; + ptrace (PT_WRITE_U, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, + *(int *) ®isters[REGISTER_BYTE (regno) + i]); + if (errno != 0) + { + sprintf (buf, "writing register number %d(%d)", regno, i); + perror_with_name (buf); + } + regaddr += sizeof(int); + } + } + else + { + for (regno = 0; regno < NUM_REGS; regno++) + { + if (CANNOT_STORE_REGISTER (regno)) + continue; + regaddr = register_addr (regno, offset); + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(int)) + { + errno = 0; + ptrace (PT_WRITE_U, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, + *(int *) ®isters[REGISTER_BYTE (regno) + i]); + if (errno != 0) + { + sprintf (buf, "writing register number %d(%d)", regno, i); + perror_with_name (buf); + } + regaddr += sizeof(int); + } + } + } + return; +} +#endif /* !defined (FETCH_INFERIOR_REGISTERS). */ + +/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory + in the NEW_SUN_PTRACE case. + It ought to be straightforward. But it appears that writing did + not write the data that I specified. I cannot understand where + it got the data that it actually did write. */ + +/* Copy LEN bytes to or from inferior's memory starting at MEMADDR + to debugger memory starting at MYADDR. Copy to inferior if + WRITE is nonzero. + + Returns the length copied, which is either the LEN argument or zero. + This xfer function does not do partial moves, since child_ops + doesn't allow memory operations to cross below us in the target stack + anyway. */ + +int +child_xfer_memory (memaddr, myaddr, len, write, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; + struct target_ops *target; /* ignored */ +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & - sizeof (int); + /* Round ending address up; get number of longwords that makes. */ + register int count + = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); + /* Allocate buffer of that many longwords. */ + register int *buffer = (int *) alloca (count * sizeof (int)); + + if (write) + { + /* Fill start and end extra bytes of buffer with existing memory data. */ + + if (addr != memaddr || len < (int)sizeof (int)) { + /* Need part of initial word -- fetch it. */ + buffer[0] = ptrace (PT_READ_I, inferior_pid, (PTRACE_ARG3_TYPE) addr, + 0); + } + + if (count > 1) /* FIXME, avoid if even boundary */ + { + buffer[count - 1] + = ptrace (PT_READ_I, inferior_pid, + (PTRACE_ARG3_TYPE) (addr + (count - 1) * sizeof (int)), + 0); + } + + /* Copy data to be written over corresponding part of buffer */ + + bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len); + + /* Write the entire buffer. */ + + for (i = 0; i < count; i++, addr += sizeof (int)) + { + errno = 0; + ptrace (PT_WRITE_D, inferior_pid, (PTRACE_ARG3_TYPE) addr, + buffer[i]); + if (errno) + { + /* Using the appropriate one (I or D) is necessary for + Gould NP1, at least. */ + errno = 0; + ptrace (PT_WRITE_I, inferior_pid, (PTRACE_ARG3_TYPE) addr, + buffer[i]); + } + if (errno) + return 0; + } + } + else + { + /* Read all the longwords */ + for (i = 0; i < count; i++, addr += sizeof (int)) + { + errno = 0; + buffer[i] = ptrace (PT_READ_I, inferior_pid, + (PTRACE_ARG3_TYPE) addr, 0); + if (errno) + return 0; + QUIT; + } + + /* Copy appropriate bytes out of the buffer. */ + bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len); + } + return len; +} diff --git a/gdb/hppah-tdep.c b/gdb/hppah-tdep.c new file mode 100644 index 0000000..27bf9e9 --- /dev/null +++ b/gdb/hppah-tdep.c @@ -0,0 +1,1427 @@ +/* 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 1986, 1987, 1989, 1990, 1991, 1992 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. + +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. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" +#include "value.h" + +/* For argument passing to the inferior */ +#include "symtab.h" + +#ifdef USG +#include +#endif + +#include +#include +#include +#include + +#ifdef COFF_ENCAPSULATE +#include "a.out.encap.h" +#else +#include +#endif +#ifndef N_SET_MAGIC +#define N_SET_MAGIC(exec, val) ((exec).a_magic = (val)) +#endif + +/*#include After a.out.h */ +#include +#include +#include +#include + +#ifdef KERNELDEBUG +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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) { + 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; + 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("\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; + CORE_ADDR pc = get_frame_pc (frame); + + get_frame_saved_regs (frame, &saved_regs); + if (pc >= millicode_start && pc < millicode_end) + return read_register (31); + else 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 +#include +#include +#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 diff --git a/gdb/hppah-xdep.c b/gdb/hppah-xdep.c new file mode 100644 index 0000000..a556998 --- /dev/null +++ b/gdb/hppah-xdep.c @@ -0,0 +1,417 @@ +/* Host-dependent code for HP PA-RISC runing HP/UX, for GDB. + Copyright 1986, 1987, 1989, 1990, 1991, 1992 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. + +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. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "defs.h" +#include "frame.h" +#include "inferior.h" +#include "target.h" + +#ifdef USG +#include +#endif + +#include +#include +#include +#include + +#include + + +#ifndef PT_ATTACH +#define PT_ATTACH PTRACE_ATTACH +#endif +#ifndef PT_DETACH +#define PT_DETACH PTRACE_DETACH +#endif + +#include "gdbcore.h" + +/* This function simply calls ptrace with the given arguments. + It exists so that all calls to ptrace are isolated in this + machine-dependent file. */ +int +call_ptrace (request, pid, addr, data) + int request, pid; + PTRACE_ARG3_TYPE addr; + int data; +{ + return ptrace (request, pid, addr, data, 0); +} + +#ifdef DEBUG_PTRACE +/* For the rest of the file, use an extra level of indirection */ +/* This lets us breakpoint usefully on call_ptrace. */ +#define ptrace call_ptrace +#endif + +void +kill_inferior () +{ + if (inferior_pid == 0) + return; + ptrace (PT_EXIT, inferior_pid, (PTRACE_ARG3_TYPE) 0, 0, 0); /* PT_EXIT = PT_KILL ? */ + wait ((int *)0); + target_mourn_inferior (); +} + +/* Resume execution of the inferior process. + If STEP is nonzero, single-step it. + If SIGNAL is nonzero, give it that signal. */ + +void +child_resume (step, signal) + int step; + int signal; +{ + errno = 0; + + /* An address of (PTRACE_ARG3_TYPE) 1 tells ptrace to continue from where + it was. (If GDB wanted it to start some other way, we have already + written a new PC value to the child.) */ + + if (step) + ptrace (PT_SINGLE, inferior_pid, (PTRACE_ARG3_TYPE) 1, signal, 0); + else + ptrace (PT_CONTIN, inferior_pid, (PTRACE_ARG3_TYPE) 1, signal, 0); + + if (errno) + perror_with_name ("ptrace"); +} + +#ifdef ATTACH_DETACH +/* Nonzero if we are debugging an attached process rather than + an inferior. */ +extern int attach_flag; + +/* Start debugging the process whose number is PID. */ +int +attach (pid) + int pid; +{ + errno = 0; + ptrace (PT_ATTACH, pid, (PTRACE_ARG3_TYPE) 0, 0, 0); + if (errno) + perror_with_name ("ptrace"); + attach_flag = 1; + return pid; +} + +/* Stop debugging the process whose number is PID + and continue it with signal number SIGNAL. + SIGNAL = 0 means just continue it. */ + +void +detach (signal) + int signal; +{ + errno = 0; + ptrace (PT_DETACH, inferior_pid, (PTRACE_ARG3_TYPE) 1, signal, 0); + if (errno) + perror_with_name ("ptrace"); + attach_flag = 0; +} +#endif /* ATTACH_DETACH */ + +#if !defined (FETCH_INFERIOR_REGISTERS) + +/* KERNEL_U_ADDR is the amount to subtract from u.u_ar0 + to get the offset in the core file of the register values. */ +#if defined (KERNEL_U_ADDR_BSD) +/* Get kernel_u_addr using BSD-style nlist(). */ +CORE_ADDR kernel_u_addr; + +#include /* For struct nlist */ + +void +_initialize_kernel_u_addr () +{ + struct nlist names[2]; + + names[0].n_un.n_name = "_u"; + names[1].n_un.n_name = NULL; + if (nlist ("/vmunix", names) == 0) + kernel_u_addr = names[0].n_value; + else + fatal ("Unable to get kernel u area address."); +} +#endif /* KERNEL_U_ADDR_BSD. */ + +#if defined (KERNEL_U_ADDR_HPUX) +/* Get kernel_u_addr using HPUX-style nlist(). */ +CORE_ADDR kernel_u_addr; + +struct hpnlist { + char * n_name; + long n_value; + unsigned char n_type; + unsigned char n_length; + short n_almod; + short n_unused; +}; +static struct hpnlist nl[] = {{ "_u", -1, }, { (char *) 0, }}; + +/* read the value of the u area from the hp-ux kernel */ +void _initialize_kernel_u_addr () +{ + struct user u; + nlist ("/hp-ux", &nl); + kernel_u_addr = nl[0].n_value; +} +#endif /* KERNEL_U_ADDR_HPUX. */ + +#if !defined (offsetof) +#define offsetof(TYPE, MEMBER) ((unsigned long) &((TYPE *)0)->MEMBER) +#endif + +/* U_REGS_OFFSET is the offset of the registers within the u area. */ +#if !defined (U_REGS_OFFSET) +#define U_REGS_OFFSET \ + ptrace (PT_READ_U, inferior_pid, \ + (PTRACE_ARG3_TYPE) (offsetof (struct user, u_ar0)), 0, 0) \ + - KERNEL_U_ADDR +#endif + +/* Registers we shouldn't try to fetch. */ +#if !defined (CANNOT_FETCH_REGISTER) +#define CANNOT_FETCH_REGISTER(regno) 0 +#endif + +/* Fetch one register. */ + +static void +fetch_register (regno) + int regno; +{ + register unsigned int regaddr; + char buf[MAX_REGISTER_RAW_SIZE]; + char mess[128]; /* For messages */ + register int i; + + /* Offset of registers within the u area. */ + unsigned int offset; + + if (CANNOT_FETCH_REGISTER (regno)) + { + bzero (buf, REGISTER_RAW_SIZE (regno)); /* Supply zeroes */ + supply_register (regno, buf); + return; + } + + offset = U_REGS_OFFSET; + + regaddr = register_addr (regno, offset); + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof (int)) + { + errno = 0; + *(int *) &buf[i] = ptrace (PT_RUREGS, inferior_pid, + (PTRACE_ARG3_TYPE) regaddr, 0, 0); + regaddr += sizeof (int); + if (errno != 0) + { + sprintf (mess, "reading register %s (#%d)", reg_names[regno], regno); + perror_with_name (mess); + } + } + supply_register (regno, buf); +} + + +/* Fetch all registers, or just one, from the child process. */ + +void +fetch_inferior_registers (regno) + int regno; +{ + if (regno == -1) + for (regno = 0; regno < NUM_REGS; regno++) + fetch_register (regno); + else + fetch_register (regno); +} + +/* Registers we shouldn't try to store. */ +#if !defined (CANNOT_STORE_REGISTER) +#define CANNOT_STORE_REGISTER(regno) 0 +#endif + +/* Store our register values back into the inferior. + If REGNO is -1, do this for all registers. + Otherwise, REGNO specifies which register (so we can save time). */ + +void +store_inferior_registers (regno) + int regno; +{ + register unsigned int regaddr; + char buf[80]; + extern char registers[]; + register int i; + + unsigned int offset = U_REGS_OFFSET; + + if (regno >= 0) + { + regaddr = register_addr (regno, offset); + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(int)) + { + errno = 0; + ptrace (PT_WUAREA, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, + *(int *) ®isters[REGISTER_BYTE (regno) + i], 0); + if (errno != 0) + { + sprintf (buf, "writing register number %d(%d)", regno, i); + perror_with_name (buf); + } + regaddr += sizeof(int); + } + } + else + { + for (regno = 0; regno < NUM_REGS; regno++) + { + if (CANNOT_STORE_REGISTER (regno)) + continue; + regaddr = register_addr (regno, offset); + for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(int)) + { + errno = 0; + ptrace (PT_WUAREA, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, + *(int *) ®isters[REGISTER_BYTE (regno) + i], 0); + if (errno != 0) + { + sprintf (buf, "writing register number %d(%d)", regno, i); + perror_with_name (buf); + } + regaddr += sizeof(int); + } + } + } + return; +} +#endif /* !defined (FETCH_INFERIOR_REGISTERS). */ + +/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory + in the NEW_SUN_PTRACE case. + It ought to be straightforward. But it appears that writing did + not write the data that I specified. I cannot understand where + it got the data that it actually did write. */ + +/* Copy LEN bytes to or from inferior's memory starting at MEMADDR + to debugger memory starting at MYADDR. Copy to inferior if + WRITE is nonzero. + + Returns the length copied, which is either the LEN argument or zero. + This xfer function does not do partial moves, since child_ops + doesn't allow memory operations to cross below us in the target stack + anyway. */ + +int +child_xfer_memory (memaddr, myaddr, len, write, target) + CORE_ADDR memaddr; + char *myaddr; + int len; + int write; + struct target_ops *target; /* ignored */ +{ + register int i; + /* Round starting address down to longword boundary. */ + register CORE_ADDR addr = memaddr & - sizeof (int); + /* Round ending address up; get number of longwords that makes. */ + register int count + = (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int); + /* Allocate buffer of that many longwords. */ + register int *buffer = (int *) alloca (count * sizeof (int)); + + if (write) + { + /* Fill start and end extra bytes of buffer with existing memory data. */ + + if (addr != memaddr || len < (int)sizeof (int)) { + /* Need part of initial word -- fetch it. */ + buffer[0] = ptrace (PT_RIUSER, inferior_pid, + (PTRACE_ARG3_TYPE) addr, 0, 0); + } + + if (count > 1) /* FIXME, avoid if even boundary */ + { + buffer[count - 1] + = ptrace (PT_RIUSER, inferior_pid, + (PTRACE_ARG3_TYPE) (addr + (count - 1) * sizeof (int)), + 0, 0); + } + + /* Copy data to be written over corresponding part of buffer */ + + bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len); + + /* Write the entire buffer. */ + + for (i = 0; i < count; i++, addr += sizeof (int)) + { +#if 0 +/* The HP-UX kernel crashes if you use PT_WDUSER to write into the text + segment. FIXME -- does it work to write into the data segment using + WIUSER, or do these idiots really expect us to figure out which segment + the address is in, so we can use a separate system call for it??! */ + errno = 0; + ptrace (PT_WDUSER, inferior_pid, (PTRACE_ARG3_TYPE) addr, + buffer[i], 0); + if (errno) +#endif + { + /* Using the appropriate one (I or D) is necessary for + Gould NP1, at least. */ + errno = 0; + ptrace (PT_WIUSER, inferior_pid, (PTRACE_ARG3_TYPE) addr, + buffer[i], 0); + } + if (errno) + return 0; + } + } + else + { + /* Read all the longwords */ + for (i = 0; i < count; i++, addr += sizeof (int)) + { + errno = 0; + buffer[i] = ptrace (PT_RIUSER, inferior_pid, + (PTRACE_ARG3_TYPE) addr, 0, 0); + if (errno) + return 0; + QUIT; + } + + /* Copy appropriate bytes out of the buffer. */ + bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len); + } + return len; +} + + + + +int +getpagesize() +{ + return(4096); +} diff --git a/gdb/tm-hppab.h b/gdb/tm-hppab.h new file mode 100644 index 0000000..577bb9b --- /dev/null +++ b/gdb/tm-hppab.h @@ -0,0 +1,6 @@ +/* Parameters for execution on an HP PA-RISC machine running BSD, for GDB. + Contributed by the Center for Software Science at the + University of Utah (pa-gdb-bugs@cs.utah.edu). */ + +/* It's all just the common stuff. */ +#include "tm-hppa.h" diff --git a/gdb/tm-hppah.h b/gdb/tm-hppah.h new file mode 100644 index 0000000..130365d --- /dev/null +++ b/gdb/tm-hppah.h @@ -0,0 +1,39 @@ +/* Parameters for execution on an HP PA-RISC machine, running HPUX, for GDB. + Copyright 1991, 1992 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. + +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. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Mostly it's common to all HPPA's. */ +#include "tm-hppa.h" + +/* Saved PC's are different, since there is millicode. */ +extern CORE_ADDR millicode_start, millicode_end; + +/* Immediately after a function call, return the saved pc. + Can't go through the frames for this because on some machines + the new frame is not set up until the new function executes + some instructions. */ + +#undef SAVED_PC_AFTER_CALL +#define SAVED_PC_AFTER_CALL(frame) \ + ((get_frame_pc (frame) >= millicode_start \ + && get_frame_pc (frame) < millicode_end) ? \ + read_register (31) & ~3 \ + : read_register (RP_REGNUM) & ~3) diff --git a/gdb/xm-hppab.h b/gdb/xm-hppab.h new file mode 100644 index 0000000..f326876 --- /dev/null +++ b/gdb/xm-hppab.h @@ -0,0 +1,48 @@ +/* Parameters for hosting on an HPPA PA-RISC machine, running BSD, for GDB. + Copyright 1991, 1992 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. + +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. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* This is a big-endian host. */ + +#define HOST_BYTE_ORDER BIG_ENDIAN + +/* Avoid "INT_MIN redefined" warnings -- by defining it here, exactly + the same as in the system file. */ +#undef INT_MIN +#define INT_MIN 0x80000000 + +#ifndef hp800 +#define USG +#endif + +#define KERNEL_U_ADDR 0 + +/* What a coincidence! */ +#define REGISTER_U_ADDR(addr, blockend, regno) \ +{ addr = (int)(blockend) + REGISTER_BYTE (regno);} + +#define U_REGS_OFFSET 0 + +#ifndef SEEK_SET +# define SEEK_SET 0 /* Set file pointer to "offset" */ +# define SEEK_CUR 1 /* Set file pointer to current plus "offset" */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif /* SEEK_SET */ diff --git a/gdb/xm-hppah.h b/gdb/xm-hppah.h new file mode 100644 index 0000000..bdb0b95 --- /dev/null +++ b/gdb/xm-hppah.h @@ -0,0 +1,52 @@ +/* Parameters for hosting on an HPPA-RISC machine running HPUX, for GDB. + Copyright 1991, 1992 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. + +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. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Host is big-endian. */ +#define HOST_BYTE_ORDER BIG_ENDIAN + +/* Avoid "INT_MIN redefined" warnings -- by defining it here, exactly + the same as in the system file. */ +#undef INT_MIN +#define INT_MIN 0x80000000 + +#ifndef hp800 +#define USG +#endif + +#define HAVE_TERMIO + +#define KERNEL_U_ADDR 0 + +/* What a coincidence! */ +#define REGISTER_U_ADDR(addr, blockend, regno) \ +{ addr = (int)(blockend) + REGISTER_BYTE (regno);} + +#define U_REGS_OFFSET 0 + +/* HP uses non-ANSI definitions, but with void * results. */ +#define MEM_FNS_DECLARED /* Some non-ANSI use void *, not char *. */ +extern void * +memcpy PARAMS ((void *, const void *, size_t)); /* 4.11.2.1 */ + +extern void * +memset PARAMS ((void *, int, size_t)); /* 4.11.6.1 */ + -- cgit v1.1