From 7da1e27dd4814e6e718404f294d3ef63e15054e2 Mon Sep 17 00:00:00 2001 From: Stu Grossman Date: Fri, 19 Jun 1992 22:43:49 +0000 Subject: [PATCH] * configure.in, dbxread.c, hppa-coredep.c, hppa-pinsn.c, hppabsd-core.c, hppabsd-tdep.c, hppabsd-xdep.c, hppahpux-tdep.c, hppahpux-xdep.c, munch, partial-stab.h, tm-hppabsd.h, tm-hppahpux.h, xm-hppabsd.h, xm-hppahpux.h: HPPA merge. --- gdb/ChangeLog | 5 + gdb/configure.in | 22 + gdb/dbxread.c | 210 ++++++- gdb/hppa-coredep.c | 121 ++++ gdb/hppa-pinsn.c | 382 ++++++++++++ gdb/hppabsd-core.c | 254 ++++++++ gdb/hppabsd-tdep.c | 1428 ++++++++++++++++++++++++++++++++++++++++++ gdb/hppabsd-xdep.c | 417 +++++++++++++ gdb/hppahpux-tdep.c | 1432 +++++++++++++++++++++++++++++++++++++++++++ gdb/hppahpux-xdep.c | 421 +++++++++++++ gdb/munch | 21 +- gdb/partial-stab.h | 9 +- gdb/tm-hppabsd.h | 570 +++++++++++++++++ gdb/tm-hppahpux.h | 576 +++++++++++++++++ gdb/xm-hppabsd.h | 49 ++ gdb/xm-hppahpux.h | 50 ++ 16 files changed, 5959 insertions(+), 8 deletions(-) create mode 100644 gdb/hppa-coredep.c create mode 100644 gdb/hppa-pinsn.c create mode 100644 gdb/hppabsd-core.c create mode 100644 gdb/hppabsd-tdep.c create mode 100644 gdb/hppabsd-xdep.c create mode 100644 gdb/hppahpux-tdep.c create mode 100644 gdb/hppahpux-xdep.c create mode 100644 gdb/tm-hppabsd.h create mode 100644 gdb/tm-hppahpux.h create mode 100644 gdb/xm-hppabsd.h create mode 100644 gdb/xm-hppahpux.h diff --git a/gdb/ChangeLog b/gdb/ChangeLog index a443329b666..9b75e68d9b4 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,10 @@ Fri Jun 19 15:30:15 1992 Stu Grossman (grossman at cygnus.com) + * configure.in, dbxread.c, hppa-coredep.c, hppa-pinsn.c, + hppabsd-core.c, hppabsd-tdep.c, hppabsd-xdep.c, hppahpux-tdep.c, + hppahpux-xdep.c, munch, partial-stab.h, tm-hppabsd.h, + tm-hppahpux.h, xm-hppabsd.h, xm-hppahpux.h: HPPA merge. + * Makefile.in (c-exp.tab.c, m2-exp.tab.c): Filter out bogus extern declarations of malloc/realloc/free that are inserted by some versions of yacc. diff --git a/gdb/configure.in b/gdb/configure.in index 5312f9274bc..ace1ba07203 100644 --- a/gdb/configure.in +++ b/gdb/configure.in @@ -155,6 +155,17 @@ arm | merlin | none | np1 | pn | pyramid | tahoe) gdb_host=${host_cpu} ;; +hppa) + case "${host_vendor}" in + hp) + case "${host_os}" in + hpux) gdb_host=hppahpux ;; + bsd) gdb_host=hppabsd ;; + esac + ;; + esac + ;; + ### unhandled hosts #altosgas #i386v-g @@ -326,6 +337,17 @@ rs6000) gdb_target=rs6000 ;; +hppa) + case "${target_vendor}" in + hp) + case "${target_os}" in + hpux) gdb_target=hppahpux ;; + bsd) gdb_target=hppabsd ;; + esac + ;; + esac + ;; + ### unhandled targets # altosgas # i386v-g diff --git a/gdb/dbxread.c b/gdb/dbxread.c index add45a9bc92..84e9de87135 100644 --- a/gdb/dbxread.c +++ b/gdb/dbxread.c @@ -41,6 +41,11 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #define L_INCR 1 #endif +#ifdef hp9000s800 +/* We don't want to use HP-UX's nlists. */ +#define _NLIST_INCLUDED +#endif + #include #include #ifndef NO_SYS_FILE @@ -54,7 +59,12 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "target.h" #include "gdbcore.h" /* for bfd stuff */ #include "libbfd.h" /* FIXME Secret internal BFD stuff (bfd_read) */ +#ifdef hp9000s800 +#include "libhppa.h" +#include "syms.h" +#else #include "libaout.h" /* FIXME Secret internal BFD stuff for a.out */ +#endif #include "symfile.h" #include "objfiles.h" #include "buildsym.h" @@ -66,6 +76,19 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ symbol files. A pointer to this structure is kept in the sym_private field of the objfile struct. */ +#ifdef hp9000s800 +struct dbx_symfile_info { + asection *text_sect; /* Text section accessor */ + int symcount; /* How many symbols are there in the file */ + char *stringtab; /* The actual string table */ + int stringtab_size; /* Its size */ + off_t symtab_offset; /* Offset in file to symbol table */ + int hp_symcount; + char *hp_stringtab; + int hp_stringtab_size; + off_t hp_symtab_offset; +}; +#else struct dbx_symfile_info { asection *text_sect; /* Text section accessor */ int symcount; /* How many symbols are there in the file */ @@ -74,6 +97,7 @@ struct dbx_symfile_info { off_t symtab_offset; /* Offset in file to symbol table */ int symbol_size; /* Bytes in a single symbol */ }; +#endif #define DBX_SYMFILE_INFO(o) ((struct dbx_symfile_info *)((o)->sym_private)) #define DBX_TEXT_SECT(o) (DBX_SYMFILE_INFO(o)->text_sect) @@ -82,6 +106,12 @@ struct dbx_symfile_info { #define DBX_STRINGTAB_SIZE(o) (DBX_SYMFILE_INFO(o)->stringtab_size) #define DBX_SYMTAB_OFFSET(o) (DBX_SYMFILE_INFO(o)->symtab_offset) #define DBX_SYMBOL_SIZE(o) (DBX_SYMFILE_INFO(o)->symbol_size) +#ifdef hp9000s800 +#define HP_SYMCOUNT(o) (DBX_SYMFILE_INFO(o)->hp_symcount) +#define HP_STRINGTAB(o) (DBX_SYMFILE_INFO(o)->hp_stringtab) +#define HP_STRINGTAB_SIZE(o) (DBX_SYMFILE_INFO(o)->hp_stringtab_size) +#define HP_SYMTAB_OFFSET(o) (DBX_SYMFILE_INFO(o)->hp_symtab_offset) +#endif /* Each partial symbol table entry contains a pointer to private data for the read_symtab() function to use when expanding a partial symbol table entry @@ -470,7 +500,11 @@ dbx_symfile_read (objfile, addr, mainline) if (mainline || objfile->global_psymbols.size == 0 || objfile->static_psymbols.size == 0) init_psymbol_list (objfile); +#ifdef hp9000s800 + symbol_size = obj_dbx_symbol_entry_size (sym_bfd); +#else symbol_size = DBX_SYMBOL_SIZE (objfile); +#endif symbol_table_offset = DBX_SYMTAB_OFFSET (objfile); pending_blocks = 0; @@ -539,8 +573,15 @@ dbx_symfile_init (objfile) xmmalloc (objfile -> md, sizeof (struct dbx_symfile_info)); /* FIXME POKING INSIDE BFD DATA STRUCTURES */ +#ifdef hp9000s800 +#define STRING_TABLE_OFFSET (sym_bfd->origin + obj_dbx_str_filepos (sym_bfd)) +#define SYMBOL_TABLE_OFFSET (sym_bfd->origin + obj_dbx_sym_filepos (sym_bfd)) +#define HP_STRING_TABLE_OFFSET (sym_bfd->origin + obj_hp_str_filepos (sym_bfd)) +#define HP_SYMBOL_TABLE_OFFSET (sym_bfd->origin + obj_hp_sym_filepos (sym_bfd)) +#else #define STRING_TABLE_OFFSET (sym_bfd->origin + obj_str_filepos (sym_bfd)) #define SYMBOL_TABLE_OFFSET (sym_bfd->origin + obj_sym_filepos (sym_bfd)) +#endif /* FIXME POKING INSIDE BFD DATA STRUCTURES */ DBX_TEXT_SECT (objfile) = bfd_get_section_by_name (sym_bfd, ".text"); @@ -548,7 +589,12 @@ dbx_symfile_init (objfile) error ("Can't find .text section in symbol file"); DBX_SYMBOL_SIZE (objfile) = obj_symbol_entry_size (sym_bfd); - DBX_SYMCOUNT (objfile) = bfd_get_symcount (sym_bfd); +#ifdef hp9000s800 + HP_SYMCOUNT (objfile) = obj_hp_sym_count (sym_bfd); + DBX_SYMCOUNT (objfile) = obj_dbx_sym_count (sym_bfd); +#else + DBX_SYMCOUNT (objfile) = bfd_get_symcount (sym_bfd); +#endif DBX_SYMTAB_OFFSET (objfile) = SYMBOL_TABLE_OFFSET; /* Read the string table and stash it away in the psymbol_obstack. It is @@ -563,6 +609,10 @@ dbx_symfile_init (objfile) however at least check to see if the size is zero or some negative value. */ +#ifdef hp9000s800 + DBX_STRINGTAB_SIZE (objfile) = obj_dbx_stringtab_size (sym_bfd); + HP_STRINGTAB_SIZE (objfile) = obj_hp_stringtab_size (sym_bfd); +#else val = bfd_seek (sym_bfd, STRING_TABLE_OFFSET, L_SET); if (val < 0) perror_with_name (name); @@ -572,6 +622,8 @@ dbx_symfile_init (objfile) perror_with_name (name); DBX_STRINGTAB_SIZE (objfile) = bfd_h_get_32 (sym_bfd, size_temp); +#endif + if (DBX_STRINGTAB_SIZE (objfile) <= 0) error ("ridiculous string table size (%d bytes).", DBX_STRINGTAB_SIZE (objfile)); @@ -579,6 +631,15 @@ dbx_symfile_init (objfile) DBX_STRINGTAB (objfile) = (char *) obstack_alloc (&objfile -> psymbol_obstack, DBX_STRINGTAB_SIZE (objfile)); +#ifdef hp9000s800 + if (HP_STRINGTAB_SIZE (objfile) <= 0) + error ("ridiculous string table size (%d bytes).", + HP_STRINGTAB_SIZE (objfile)); + + HP_STRINGTAB (objfile) = + (char *) obstack_alloc (&objfile -> psymbol_obstack, + HP_STRINGTAB_SIZE (objfile)); +#endif /* Now read in the string table in one big gulp. */ @@ -589,6 +650,18 @@ dbx_symfile_init (objfile) sym_bfd); if (val != DBX_STRINGTAB_SIZE (objfile)) perror_with_name (name); +#ifdef hp9000s800 + val = bfd_seek (sym_bfd, HP_STRING_TABLE_OFFSET, L_SET); + if (val < 0) + perror_with_name (name); + val = bfd_read (HP_STRINGTAB (objfile), HP_STRINGTAB_SIZE (objfile), 1, + sym_bfd); + if (val != HP_STRINGTAB_SIZE (objfile)) + perror_with_name (name); +#endif +#ifdef hp9000s800 + HP_SYMTAB_OFFSET (objfile) = HP_SYMBOL_TABLE_OFFSET; +#endif } /* Perform any local cleanups required when we are done with a particular @@ -642,6 +715,25 @@ fill_symbuf (sym_bfd) symbuf_end = nbytes / symbol_size; symbuf_idx = 0; } +#ifdef hp9000s800 +/* same as above for the HP symbol table */ + +static struct symbol_dictionary_record hp_symbuf[4096]; +static int hp_symbuf_idx; +static int hp_symbuf_end; + +static int +fill_hp_symbuf (sym_bfd) + bfd *sym_bfd; +{ + int nbytes = bfd_read ((PTR)hp_symbuf, sizeof (hp_symbuf), 1, sym_bfd); + if (nbytes <= 0) + error ("error or end of file reading symbol table"); + hp_symbuf_end = nbytes / sizeof (struct symbol_dictionary_record); + hp_symbuf_idx = 0; + return 1; +} +#endif #define SWAP_SYMBOL(symp, abfd) \ { \ @@ -689,8 +781,15 @@ init_psymbol_list (objfile) /* Current best guess is that there are approximately a twentieth of the total symbols (in a debugging file) are global or static oriented symbols */ +#ifdef hp9000s800 + objfile -> global_psymbols.size = (DBX_SYMCOUNT (objfile) + + HP_SYMCOUNT (objfile)) / 10; + objfile -> static_psymbols.size = (DBX_SYMCOUNT (objfile) + + HP_SYMCOUNT (objfile)) / 10; +#else objfile -> global_psymbols.size = DBX_SYMCOUNT (objfile) / 10; objfile -> static_psymbols.size = DBX_SYMCOUNT (objfile) / 10; +#endif objfile -> global_psymbols.next = objfile -> global_psymbols.list = (struct partial_symbol *) xmmalloc (objfile -> md, objfile -> global_psymbols.size * sizeof (struct partial_symbol)); objfile -> static_psymbols.next = objfile -> static_psymbols.list = (struct partial_symbol *) @@ -781,6 +880,14 @@ read_dbx_symtab (addr, objfile, text_addr, text_size) CORE_ADDR last_o_file_start = 0; struct cleanup *old_chain; bfd *abfd; +#ifdef hp9000s800 + /* HP stuff */ + struct symbol_dictionary_record *hp_bufp; + int hp_symnum; + /* A hack: the first text symbol in the debugging library */ + int dbsubc_addr = 0; +#endif + /* End of the text segment of the executable file. */ CORE_ADDR end_of_text_addr; @@ -802,7 +909,11 @@ read_dbx_symtab (addr, objfile, text_addr, text_size) file_string_table_offset = 0; next_file_string_table_offset = 0; +#ifdef hp9000s800 + stringtab_global = HP_STRINGTAB (objfile); +#else stringtab_global = DBX_STRINGTAB (objfile); +#endif pst = (struct partial_symtab *) 0; @@ -836,6 +947,75 @@ read_dbx_symtab (addr, objfile, text_addr, text_size) symbuf_end = symbuf_idx = 0; next_symbol_text_func = dbx_next_symbol_text; +#ifdef hp9000s800 + /* On pa machines, the global symbols are all in the regular HP-UX + symbol table. Read them in first. */ + + hp_symbuf_end = hp_symbuf_idx = 0; + bfd_seek (abfd, HP_SYMTAB_OFFSET (objfile), 0); + + for (hp_symnum = 0; hp_symnum < HP_SYMCOUNT (objfile); hp_symnum++) + { + int dbx_type; + + QUIT; + if (hp_symbuf_idx == hp_symbuf_end) + fill_hp_symbuf (abfd); + hp_bufp = &hp_symbuf[hp_symbuf_idx++]; + switch (hp_bufp->symbol_type) + { + case ST_SYM_EXT: + case ST_ARG_EXT: + continue; + case ST_CODE: + case ST_PRI_PROG: + case ST_SEC_PROG: + case ST_ENTRY: + case ST_MILLICODE: + dbx_type = N_TEXT; + hp_bufp->symbol_value &= ~3; /* clear out permission bits */ + break; + case ST_DATA: + dbx_type = N_DATA; + break; +#ifdef KERNELDEBUG + case ST_ABSOLUTE: + { + extern int kernel_debugging; + if (!kernel_debugging) + continue; + dbx_type = N_ABS; + break; + } +#endif + default: + continue; + } + /* Use the address of dbsubc to finish the last psymtab. */ + if (hp_bufp->symbol_type == ST_CODE && + HP_STRINGTAB (objfile)[hp_bufp->name.n_strx] == '_' && + !strcmp (HP_STRINGTAB (objfile) + hp_bufp->name.n_strx, "_dbsubc")) + dbsubc_addr = hp_bufp->symbol_value; + if (hp_bufp->symbol_scope == SS_UNIVERSAL) + { + if (hp_bufp->name.n_strx > HP_STRINGTAB_SIZE (objfile)) + error ("Invalid symbol data; bad HP string table offset: %d", + hp_bufp->name.n_strx); + /* A hack, but gets the job done. */ + if (!strcmp (hp_bufp->name.n_strx + HP_STRINGTAB (objfile), + "$START$")) + objfile -> ei.entry_file_lowpc = hp_bufp->symbol_value; + if (!strcmp (hp_bufp->name.n_strx + HP_STRINGTAB (objfile), + "_sr4export")) + objfile -> ei.entry_file_highpc = hp_bufp->symbol_value; + record_minimal_symbol (hp_bufp->name.n_strx + HP_STRINGTAB (objfile), + hp_bufp->symbol_value, dbx_type | N_EXT, + objfile); + } + } + bfd_seek (abfd, DBX_SYMTAB_OFFSET (objfile), 0); +#endif + for (symnum = 0; symnum < DBX_SYMCOUNT (objfile); symnum++) { /* Get the symbol for this run and pull out some info */ @@ -889,6 +1069,7 @@ read_dbx_symtab (addr, objfile, text_addr, text_size) } /* If there's stuff to be cleaned up, clean it up. */ +#ifndef hp9000s800 if (DBX_SYMCOUNT (objfile) > 0 /* We have some syms */ /*FIXME, does this have a bug at start address 0? */ && last_o_file_start @@ -898,12 +1079,19 @@ read_dbx_symtab (addr, objfile, text_addr, text_size) objfile -> ei.entry_file_lowpc = last_o_file_start; objfile -> ei.entry_file_highpc = bufp->n_value; } +#endif if (pst) { +#ifdef hp9000s800 + end_psymtab (pst, psymtab_include_list, includes_used, + symnum * symbol_size, dbsubc_addr, + dependency_list, dependencies_used); +#else end_psymtab (pst, psymtab_include_list, includes_used, symnum * symbol_size, end_of_text_addr, dependency_list, dependencies_used); +#endif } free_bincl_list (objfile); @@ -1184,7 +1372,11 @@ dbx_psymtab_to_symtab_1 (pst) buildsym_init (); old_chain = make_cleanup (really_free_pendings, 0); file_string_table_offset = FILE_STRING_OFFSET (pst); +#ifdef hp9000s800 + symbol_size = obj_dbx_symbol_entry_size (sym_bfd); +#else symbol_size = SYMBOL_SIZE (pst); +#endif /* Read in this file's symbols */ bfd_seek (pst->objfile->obfd, SYMBOL_OFFSET (pst), L_SET); @@ -1275,7 +1467,11 @@ read_ofile_symtab (objfile, sym_offset, sym_size, text_offset, text_size, current_objfile = objfile; subfile_stack = 0; +#ifdef hp9000s800 + stringtab_global = HP_STRINGTAB (objfile); +#else stringtab_global = DBX_STRINGTAB (objfile); +#endif last_source_file = 0; abfd = objfile->obfd; @@ -1890,10 +2086,22 @@ static struct sym_fns bout_sym_fns = NULL /* next: pointer to next struct sym_fns */ }; +static struct sym_fns hppa_sym_fns = +{ + "hppa", /* sym_name: name or name prefix of BFD target type */ + 4, /* sym_namelen: number of significant sym_name chars */ + dbx_new_init, /* sym_new_init: init anything gbl to entire symtab */ + dbx_symfile_init, /* sym_init: read initial info, setup for sym_read() */ + dbx_symfile_read, /* sym_read: read a symbol file into symtab */ + dbx_symfile_finish, /* sym_finish: finished with file, cleanup */ + NULL /* next: pointer to next struct sym_fns */ +}; + void _initialize_dbxread () { add_symtab_fns(&sunos_sym_fns); add_symtab_fns(&aout_sym_fns); add_symtab_fns(&bout_sym_fns); + add_symtab_fns(&hppa_sym_fns); } diff --git a/gdb/hppa-coredep.c b/gdb/hppa-coredep.c new file mode 100644 index 00000000000..7e1031e49f3 --- /dev/null +++ b/gdb/hppa-coredep.c @@ -0,0 +1,121 @@ +/* Extract registers from a "standard" core file, for GDB. + Copyright (C) 1988-1991 Free Software Foundation, Inc. + +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. */ + +/* core.c is supposed to be the more machine-independent aspects of this; + this file is more machine-specific. */ + +#include "defs.h" +#include "gdbcore.h" +#include + +/* These are needed on various systems to expand REGISTER_U_ADDR. */ +#include +#include +#include +#include +#include +#include +#ifndef USG +#include +#endif + + +/* Extract the register values out of the core file and store + them where `read_register' will find them. + + CORE_REG_SECT points to the register values themselves, read into memory. + CORE_REG_SIZE is the size of that area. + WHICH says which set of registers we are handling (0 = int, 2 = float + on machines where they are discontiguous). + REG_ADDR is the offset from u.u_ar0 to the register values relative to + core_reg_sect. This is used with old-fashioned core files to + locate the registers in a large upage-plus-stack ".reg" section. + Original upage address X is at location core_reg_sect+x+reg_addr. + */ + +void +fetch_core_registers (core_reg_sect, core_reg_size, which, reg_addr) + char *core_reg_sect; + unsigned core_reg_size; + int which; + unsigned reg_addr; +{ + register int regno; + register unsigned int addr; + int bad_reg = -1; + register reg_ptr = -reg_addr; /* Original u.u_ar0 is -reg_addr. */ + + /* If u.u_ar0 was an absolute address in the core file, relativize it now, + so we can use it as an offset into core_reg_sect. When we're done, + "register 0" will be at core_reg_sect+reg_ptr, and we can use + register_addr to offset to the other registers. If this is a modern + core file without a upage, reg_ptr will be zero and this is all a big + NOP. */ + if (reg_ptr > core_reg_size) + reg_ptr -= KERNEL_U_ADDR; + if (reg_ptr > core_reg_size) + fprintf (stderr, "Can't find registers in core file\n"); + + for (regno = 0; regno < NUM_REGS; regno++) + { + addr = register_addr (regno, reg_ptr); + if (addr >= core_reg_size) { + if (bad_reg < 0) + bad_reg = regno; + } else { + if (regno == PCOQ_HEAD_REGNUM || regno == PCOQ_TAIL_REGNUM) + core_reg_sect[addr +3] &= ~0x3; + supply_register (regno, core_reg_sect + addr); + } + } + if (bad_reg > 0) + { + error ("Register %s not found in core file.", reg_names[bad_reg]); + } +} + + +#ifdef REGISTER_U_ADDR + +/* Return the address in the core dump or inferior of register REGNO. + BLOCKEND is the address of the end of the user structure. */ + +unsigned int +register_addr (regno, blockend) + int regno; + int blockend; +{ + int addr; + + if (regno < 0 || regno >= NUM_REGS) + error ("Invalid register number %d.", regno); + + REGISTER_U_ADDR (addr, blockend, regno); + + return addr; +} + +#endif /* REGISTER_U_ADDR */ + + + + + + + diff --git a/gdb/hppa-pinsn.c b/gdb/hppa-pinsn.c new file mode 100644 index 00000000000..5d8df98d189 --- /dev/null +++ b/gdb/hppa-pinsn.c @@ -0,0 +1,382 @@ +/* Disassembler for the PA-RISC. Somewhat derived from sparc-pinsn.c. + Copyright (C) 1989, 1990 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, the GNU disassembler. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include + +#include "defs.h" +#include "symtab.h" +#include "opcode/hppa.h" + +char *control_reg[] = {"rctr", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", + "pidr1", "pidr2", "ccr", "sar", "pidr3", "pidr4", + "iva", "eiem", "itmr", "pcsq", "pcoq", "iir", "isr", + "ior", "ipsw", "eirr", "tr0", "tr1", "tr2", "tr3", + "tr4", "tr5", "tr6", "tr7" + }; + +char *compare_cond_names[] = {"", ",=", ",<", ",<=", ",<<", ",<<=", ",sv", + ",od", ",tr", ",<>", ",>=", ",>", ",>>=", + ",>>", ",nsv", ",ev" + }; +char *add_cond_names[] = {"", ",=", ",<", ",<=", ",nuv", ",znv", ",sv", + ",od", ",tr", ",<>", ",>=", ",>", ",uv", + ",vnz", ",nsv", ",ev" + }; +char *logical_cond_names[] = {"", ",=", ",<", ",<=", 0, 0, 0, ",od", + ",tr", ",<>", ",>=", ",>", 0, 0, 0, ",ev"}; +char *unit_cond_names[] = {"", 0, ",sbz", ",shz", ",sdc", 0, ",sbc", ",shc", + ",tr", 0, ",nbz", ",nhz", ",ndc", 0, ",nbc", ",nhc" + }; +char *shift_cond_names[] = {"", ",=", ",<", ",od", ",tr", ",<>", ",>=", ",ev"}; + +char *index_compl_names[] = {"", ",m", ",s", ",sm"}; +char *short_ldst_compl_names[] = {"", ",ma", "", ",mb"}; +char *short_bytes_compl_names[] = {"", ",b,m", ",e", ",e,m"}; +char *float_format_names[] = {",sgl", ",dbl", ",quad"}; +char *float_comp_names[] = +{",false?", ",false", ",?", ",!<=>", ",=", ",=t", ",?=", ",!<>", + ",!?>=", ",<", ",?<", ",!>=", ",!?>", ",<=", ",?<=", ",!>", + ",!?<=", ",>", ",?>", ",!<=", ",!?<", ",>=", ",?>=", ",!<", + ",!?=", ",<>", ",!=", ",!=t", ",!?", ",<=>", ",true?", ",true" + }; + +/* For a bunch of different instructions form an index into a + completer name table. */ +#define GET_COMPL(insn) (GET_FIELD (insn, 26, 26) | \ + GET_FIELD (insn, 18, 18) << 1) + +#define GET_COND(insn) (GET_FIELD ((insn), 16, 18) + \ + (GET_FIELD ((insn), 19, 19) ? 8 : 0)) + +void fput_reg (), fput_const (); + +/* Print one instruction from MEMADDR on STREAM. */ +int +print_insn (memaddr, stream) + CORE_ADDR memaddr; + FILE *stream; +{ + unsigned int insn, i, op; + + read_memory (memaddr, &insn, sizeof (insn)); + + for (i = 0; i < NUMOPCODES; ++i) + { + const struct pa_opcode *opcode = &pa_opcodes[i]; + if ((insn & opcode->mask) == opcode->match) + { + register const char *s; + + fputs_filtered (opcode->name, stream); + + if (!index ("cCY~nZFM", opcode->args[0])) + fputs_filtered (" ", stream); + for (s = opcode->args; *s != '\0'; ++s) + { + switch (*s) + { + case 'x': + fput_reg (GET_FIELD (insn, 11, 15), stream); + break; + case 'X': + if (GET_FIELD (insn, 25, 25)) + fput_reg_r (GET_FIELD (insn, 11, 15), stream); + else + fput_reg (GET_FIELD (insn, 11, 15), stream); + break; + case 'b': + fput_reg (GET_FIELD (insn, 6, 10), stream); + break; + case '^': + fput_creg (GET_FIELD (insn, 6, 10), stream); + break; + case 'E': + if (GET_FIELD (insn, 25, 25)) + fput_reg_r (GET_FIELD (insn, 6, 10), stream); + else + fput_reg (GET_FIELD (insn, 6, 10), stream); + break; + case 't': + fput_reg (GET_FIELD (insn, 27, 31), stream); + break; + case 'v': + if (GET_FIELD (insn, 25, 25)) + fput_reg_r (GET_FIELD (insn, 27, 31), stream); + else + fput_reg (GET_FIELD (insn, 27, 31), stream); + break; + case '4': + fput_creg (GET_FIELD (insn, 6, 10), stream); + break; + case '6': + fput_reg (GET_FIELD (insn, 11, 15), stream); + break; + case '7': + fput_reg (GET_FIELD (insn, 27, 31), stream); + break; + case '8': + fput_reg (GET_FIELD (insn, 16, 20), stream); + break; + case '9': + fput_reg (GET_FIELD (insn, 21, 25), stream); + break; + case '5': + fput_const (extract_5_load (insn), stream); + break; + /* case 's': */ + case 'S': + fprintf_filtered (stream, "sr%d", extract_3 (insn)); + break; + case 'c': + fprintf_filtered (stream, "%s ", + index_compl_names[GET_COMPL (insn)]); + break; + case 'C': + fprintf_filtered (stream, "%s ", + short_ldst_compl_names[GET_COMPL (insn)]); + break; + case 'Y': + fprintf_filtered (stream, "%s ", + short_bytes_compl_names[GET_COMPL (insn)]); + break; + /* these four conditions are for the set of instructions + which distinguish true/false conditions by opcode rather + than by the 'f' bit (sigh): comb, comib, addb, addib */ + case '<': + fputs_filtered (compare_cond_names[GET_FIELD (insn, 16, 18)], + stream); + break; + case '?': + fputs_filtered (compare_cond_names[GET_FIELD (insn, 16, 18) + 8], + stream); + break; + case '!': + fputs_filtered (add_cond_names[GET_FIELD (insn, 16, 18)], + stream); + break; + case '@': + fputs_filtered (add_cond_names[GET_FIELD (insn, 16, 18) + 8], + stream); + break; + case '-': + fprintf_filtered (stream, "%s ", + compare_cond_names[GET_COND (insn)]); + break; + case '+': + fprintf_filtered (stream, "%s ", + add_cond_names[GET_FIELD (insn, 16, 18)]); + break; + + case '&': + fprintf_filtered (stream, "%s ", + logical_cond_names[GET_COND (insn)]); + break; + case 'U': + fprintf_filtered (stream, "%s ", + unit_cond_names[GET_COND (insn)]); + break; + case '>': + case '~': + fprintf_filtered (stream, "%s ", + shift_cond_names[GET_FIELD (insn, 16, 18)]); + break; + case 'V': + fput_const (extract_5_store (insn), stream); + break; + case 'i': + fput_const (extract_11 (insn), stream); + break; + case 'j': + fput_const (extract_14 (insn), stream); + break; + case 'k': + fput_const (extract_21 (insn), stream); + break; + case 'n': + if (insn & 0x2) + fprintf_filtered (stream, ",n "); + else + fprintf_filtered (stream, " "); + break; + case 'w': + print_address (memaddr + 8 + extract_12 (insn), stream); + break; + case 'W': + /* don't interpret an address if it's an external branch + instruction. */ + op = GET_FIELD (insn, 0, 5); + if (op != 0x38 /* be */ && op != 0x39 /* ble */) + print_address (memaddr + 8 + extract_17 (insn), stream); + else + fput_const (extract_17 (insn), stream); + break; + case 'B': + { + int space; + if (space = GET_FIELD (insn, 16, 17)) + fprintf_filtered (stream, "sr%d,", space); + fput_reg (GET_FIELD (insn, 6, 10), stream); + break; + } + case 'p': + fprintf_filtered (stream, "%d", + 31 - GET_FIELD (insn, 22, 26)); + break; + case 'P': + fprintf_filtered (stream, "%d", + GET_FIELD (insn, 22, 26)); + break; + case 'T': + fprintf_filtered (stream, "%d", + 32 - GET_FIELD (insn, 27, 31)); + break; + case 'A': + fput_const (GET_FIELD (insn, 6, 18), stream); + break; + case 'Z': + if (GET_FIELD (insn, 26, 26)) + fprintf_filtered (stream, ",m "); + else + fprintf_filtered (stream, " "); + break; + case 'D': + fput_const (GET_FIELD (insn, 6, 31), stream); + break; + case 'f': + fprintf_filtered (stream, ",%d", GET_FIELD (insn, 23, 25)); + break; + case 'O': + fput_const ((GET_FIELD (insn, 6,20) << 5 | + GET_FIELD (insn, 27, 31)), stream); + break; + case 'o': + fput_const (GET_FIELD (insn, 6, 20), stream); + break; + case '2': + fput_const ((GET_FIELD (insn, 6, 22) << 5 | + GET_FIELD (insn, 27, 31)), stream); + break; + case '1': + fput_const ((GET_FIELD (insn, 11, 20) << 5 | + GET_FIELD (insn, 27, 31)), stream); + break; + case '0': + fput_const ((GET_FIELD (insn, 16, 20) << 5 | + GET_FIELD (insn, 27, 31)), stream); + break; + case 'u': + fprintf_filtered (stream, "%d", GET_FIELD (insn, 23, 25)); + break; + case 'F': + /* if no destination completer, need a space here */ + if (GET_FIELD (insn, 21, 22) == 1) + fputs_filtered (float_format_names[GET_FIELD (insn, 19, 20)], + stream); + else + fprintf_filtered (stream, "%s ", + float_format_names[GET_FIELD + (insn, 19, 20)]); + break; + case 'G': + fprintf_filtered (stream, "%s ", + float_format_names[GET_FIELD (insn, + 17, 18)]); + break; + case 'H': + fputs_filtered (float_format_names[GET_FIELD + (insn, 26, 26)], stream); + break; + case 'M': + fputs_filtered (float_comp_names[GET_FIELD (insn, 27, 31)], + stream); + break; + case '}': + fprintf_filtered (stream, "fp%d", GET_FIELD (insn, 6, 10)); + break; + case '|': + fprintf_filtered (stream, "fp%d", GET_FIELD (insn, 11, 15)); + break; + case '{': + if (GET_FIELD (insn, 23, 25) == 0) + fprintf_filtered (stream, "fp%d", + GET_FIELD (insn, 27, 31)); + else + fprintf_filtered (stream, "cp%d", + GET_FIELD (insn, 27, 31)); + break; + default: + fprintf_filtered (stream, "%c", *s); + break; + } + } + return sizeof(insn); + } + } + fprintf_filtered (stream, "%#8x", insn); + return sizeof(insn); +} + +/* Utility function to print registers */ + +void +fput_reg (reg, stream) + unsigned reg; + FILE *stream; +{ + if (reg) + fputs_filtered (reg_names[reg], stream); + else + fputs_filtered ("r0", stream); +} + +void +fput_reg_r (reg, stream) + unsigned reg; + FILE *stream; +{ + if (reg) + fputs_filtered (reg_names[reg], stream); + else + fputs_filtered ("r0", stream); + fputs_filtered ("R", stream); +} + +void +fput_creg (reg, stream) + unsigned reg; + FILE *stream; +{ + fputs_filtered (control_reg[reg], stream); +} + +/* print constants with sign */ + +void +fput_const (num, stream) + unsigned num; + FILE *stream; +{ + if ((int)num < 0) + fprintf_filtered (stream, "-%x", -(int)num); + else + fprintf_filtered (stream, "%x", num); +} diff --git a/gdb/hppabsd-core.c b/gdb/hppabsd-core.c new file mode 100644 index 00000000000..0fcc31c94d1 --- /dev/null +++ b/gdb/hppabsd-core.c @@ -0,0 +1,254 @@ +/* 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 (C) 1986, 1987, 1989, 1990, 1991 Free Software Foundation, Inc. + + Contributed by the Center for Software Science at the + University of Utah (pa-gdb-bugs@cs.utah.edu). + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include "defs.h" +#include "param.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/hppabsd-tdep.c b/gdb/hppabsd-tdep.c new file mode 100644 index 00000000000..c9912b05ea6 --- /dev/null +++ b/gdb/hppabsd-tdep.c @@ -0,0 +1,1428 @@ +/* Machine-dependent code which would otherwise be in inflow.c and core.c, + for GDB, the GNU debugger. This code is for the HP PA-RISC cpu. + Copyright (C) 1986, 1987, 1989, 1990, 1991 Free Software Foundation, Inc. + + Contributed by the Center for Software Science at the + University of Utah (pa-gdb-bugs@cs.utah.edu). + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#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 +/* #include Can we live without this? */ + +#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) { + (void) mach_vtophys(space, addr, &phys); + } +#endif +#if 0 + printf("vtophys(%x.%x) -> %x\n", space, addr, phys); +#endif + return (phys); +} + +static +kvread(addr) + CORE_ADDR addr; +{ + CORE_ADDR paddr; + + paddr = vtophys(0, addr); + if (paddr != ~0) + if (physrd(paddr, (char *)&addr, sizeof(addr)) == 0) + return (addr); + + return (~0); +} + +static void +read_pcb(addr) + u_int addr; +{ + int i, off; + extern char registers[]; + static int reg2pcb[] = { + /* RPB */ + -1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 45, 52, 51, 75, 74, 49, 53, 54, 55, 56, -1, 70, 66, 67, 68, 69, + 71, 72, 73, 34, 42, 43, 44, 46, 47, 58, 59, 60, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, + /* BSD */ + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 43, 64, 67, 68, 67, 47, 51, 52, 53, 54, -1, 35, 31, 32, 33, 34, + 36, 37, 38, 39, 40, 41, 42, 44, 45, 56, 57, 58,102,103,104, -1, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 80, 82, 84, 86, 88, 90, 92, + 94, 96, 98, 100, + /* Mach */ + -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, -1, -1, -1, -1, -1, -1, -1, -1, 17, -1, -1, 18, -1, + 25, -1, -1, -1, -1, 30, -1, -1, -1, -1, -1, 20, -1, -1, -1, 19, + 21, 22, 23, 24, 26, 27, -1, 28, 29, -1, -1, -1, -1, -1, -1, -1, + 34, 35, 36, 37, 38, 39, 40, 41, -1, -1, -1, -1, -1, -1, -1, -1, + 42, 44, 46, 48 + }; + static struct rpb *rpbaddr = (struct rpb *) 0; + static u_int rpbpcbaddr = 0; + + if (!remote_debugging) { + /* + * If we are debugging a post-mortem and this is the first + * call of read_pcb, read the RPB. Also assoicate the + * thread/proc running at the time with the RPB. + */ + if (!devmem && rpbpcbaddr == 0) { + CORE_ADDR raddr = ksym_lookup("rpb"); + int usepcb = 1; + + if (raddr != ~0) { + rpbaddr = (struct rpb *) malloc(sizeof *rpbaddr); + if (!physrd(raddr, (char *)rpbaddr, sizeof *rpbaddr)) { + rpbpcbaddr = addr; + usepcb = 0; + } + } + if (usepcb) { + error("cannot read rpb, using pcb for registers\n"); + if (rpbaddr) + free((char *)rpbaddr); + rpbpcbaddr = ~0; + } + } + if (physrd (addr, (char *)&pcb, sizeof pcb)) + error ("cannot read pcb at %x.\n", addr); + } else { + if (remote_read_inferior_memory(addr, (char *)&pcb, sizeof pcb)) + error ("cannot read pcb at %x.\n", addr); + } + + if (kerneltype == OS_BSD) { + printf("p0br %lx p0lr %lx p1br %lx p1lr %lx\n", + pcb.pcb_p0br, pcb.pcb_p0lr, pcb.pcb_p1br, pcb.pcb_p1lr); + off = NUM_REGS; + } else { + printf("pcb %lx psw %lx ksp %lx\n", + addr, ((int *)&pcb)[31], ((int *)&pcb)[32]); + off = NUM_REGS * 2; + } + /* + * get the register values out of the sys pcb and + * store them where `read_register' will find them. + */ + bzero(registers, REGISTER_BYTES); + for (i = 0; i < NUM_REGS; ++i) + if (reg2pcb[i+off] != -1) + supply_register(i, &((int *)&pcb)[reg2pcb[i+off]]); + /* + * If the RPB is valid for this thread/proc use the register values + * contained there. + */ + if (addr == rpbpcbaddr) { + off = 0; + for (i = 0; i < NUM_REGS; ++i) + if (reg2pcb[i+off] != -1) + supply_register(i, &((int *)rpbaddr)[reg2pcb[i+off]]); + } +} + +void +setup_kernel_debugging() +{ + struct stat stb; + CORE_ADDR addr; + + fstat(corechan, &stb); + devmem = 0; + if ((stb.st_mode & S_IFMT) == S_IFCHR && stb.st_rdev == makedev(2, 0)) + devmem = 1; + + /* XXX */ + if (lookup_misc_func("Sysmap") < 0) + kerneltype = OS_MACH; + else + kerneltype = OS_BSD; + + if (kerneltype == OS_BSD) { + int len, err = 0; + + /* + * Hash table and PDIR are equivalently mapped + */ + nhtbl = kvread(ksym_lookup("nhtbl")); + if (nhtbl != ~0) { + len = nhtbl * sizeof(*htbl); + htbl = (struct hte *) malloc(len); + if (htbl) { + addr = kvread(ksym_lookup("htbl")); + if (physrd(addr, (char *)htbl, len)) + err++; + } else + err++; + } else + err++; + npdir = kvread(ksym_lookup("npdir")); + if (npdir != ~0) { + len = npdir * sizeof(*pdir); + pdir = (struct pde *) malloc(len); + if (pdir) { + addr = kvread(ksym_lookup("pdir")); + if (physrd(addr, (char *)pdir, len)) + err++; + } else + err++; + } else + err++; + if (err) { + error("cannot read PDIR/HTBL"); + return; + } + vtophys_ready = 1; + + /* + * pcb where "panic" saved registers in first thing in + * current u-area. The current u-area is pointed to by + * "uptr". + */ + addr = kvread(ksym_lookup("uptr")); + if (addr == ~0) { + error("cannot read current u-area address"); + return; + } + read_pcb(vtophys(0, addr)); /* XXX space */ + if (!devmem) { + /* find stack frame */ + CORE_ADDR panicstr; + char buf[256]; + register char *cp; + + panicstr = kvread(ksym_lookup("panicstr")); + if (panicstr == ~0) + return; + (void) kernel_core_file_hook(panicstr, buf, sizeof(buf)); + for (cp = buf; cp < &buf[sizeof(buf)] && *cp; cp++) + if (!isascii(*cp) || (!isprint(*cp) && !isspace(*cp))) + *cp = '?'; + if (*cp) + *cp = '\0'; + printf("panic: %s\n", buf); + } + } +#ifdef MACHKERNELDEBUG + else { + int *thread; + + /* + * Set up address translation + */ + if (mach_vtophys_init() == 0) { + error("cannot initialize vtophys for Mach"); + return; + } + vtophys_ready = 1; + + /* + * Locate active thread and read PCB + * XXX MAJOR HACK + * - assumes uni-processor + * - assumes position of pcb to avoid mach includes + */ + thread = (int *)kvread(ksym_lookup("active_threads")); + addr = kvread(&thread[9]); /* XXX: pcb addr */ + read_pcb(vtophys(0, addr)); + } +#endif +} + +vtop_command(arg) + char *arg; +{ + u_int sp, off, pa; + + if (!arg) + error_no_arg("kernel virtual address"); + if (!kernel_debugging) + error("not debugging kernel"); + + sp = 0; /* XXX */ + off = (u_int) parse_and_eval_address(arg); + pa = vtophys(sp, off); + printf("%lx.%lx -> ", sp, off); + if (pa == ~0) + printf("\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/hppabsd-xdep.c b/gdb/hppabsd-xdep.c new file mode 100644 index 00000000000..ca3d10e610f --- /dev/null +++ b/gdb/hppabsd-xdep.c @@ -0,0 +1,417 @@ +/* Machine-dependent code which would otherwise be in infptrace.c, + for GDB, the GNU debugger. This code is for the HP PA-RISC cpu. + Copyright (C) 1986, 1987, 1989, 1990, 1991 Free Software Foundation, Inc. + + Contributed by the Center for Software Science at the + University of Utah (pa-gdb-bugs@cs.utah.edu). + +/* Low level Unix child interface to ptrace, for GDB when running under Unix. + Copyright (C) 1988, 1989, 1990, 1991 Free Software Foundation, Inc. + +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 +#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, *addr, 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 + +/* This is used when GDB is exiting. It gives less chance of error.*/ + +void +kill_inferior_fast () +{ + if (inferior_pid == 0) + return; + ptrace (PT_KILL, inferior_pid, 0, 0); + wait ((int *)0); +} + +void +kill_inferior () +{ + kill_inferior_fast (); + 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 (int *)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, (int *)1, signal); + else + ptrace (PT_CONTINUE, inferior_pid, (int *)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, 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, 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, \ + (int *)(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, (int *)regaddr, 0); + regaddr += sizeof (int); + if (errno != 0) + { + sprintf (mess, "reading register %s (#%d)", reg_names[regno], regno); + perror_with_name (mess); + } + } + if (regno == PCOQ_HEAD_REGNUM || regno == PCOQ_TAIL_REGNUM) + buf[3] &= ~0x3; + 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, (int *)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, (int *)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, (int *)addr, 0); + } + + if (count > 1) /* FIXME, avoid if even boundary */ + { + buffer[count - 1] + = ptrace (PT_READ_I, inferior_pid, + (int *)(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, (int *)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, (int *)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, (int *)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/hppahpux-tdep.c b/gdb/hppahpux-tdep.c new file mode 100644 index 00000000000..05679452f6e --- /dev/null +++ b/gdb/hppahpux-tdep.c @@ -0,0 +1,1432 @@ +/* Machine-dependent code which would otherwise be in inflow.c and core.c, + for GDB, the GNU debugger. This code is for the HP PA-RISC cpu. + Copyright (C) 1986, 1987, 1989, 1990, 1991 Free Software Foundation, Inc. + + Contributed by the Center for Software Science at the + University of Utah (pa-gdb-bugs@cs.utah.edu). + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#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 +/* #include Can we live without this? */ + +#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) { + (void) mach_vtophys(space, addr, &phys); + } +#endif +#if 0 + printf("vtophys(%x.%x) -> %x\n", space, addr, phys); +#endif + return (phys); +} + +static +kvread(addr) + CORE_ADDR addr; +{ + CORE_ADDR paddr; + + paddr = vtophys(0, addr); + if (paddr != ~0) + if (physrd(paddr, (char *)&addr, sizeof(addr)) == 0) + return (addr); + + return (~0); +} + +static void +read_pcb(addr) + u_int addr; +{ + int i, off; + extern char registers[]; + static int reg2pcb[] = { + /* RPB */ + -1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, + 45, 52, 51, 75, 74, 49, 53, 54, 55, 56, -1, 70, 66, 67, 68, 69, + 71, 72, 73, 34, 42, 43, 44, 46, 47, 58, 59, 60, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, + /* BSD */ + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 43, 64, 67, 68, 67, 47, 51, 52, 53, 54, -1, 35, 31, 32, 33, 34, + 36, 37, 38, 39, 40, 41, 42, 44, 45, 56, 57, 58,102,103,104, -1, + 70, 71, 72, 73, 74, 75, 76, 77, 78, 80, 82, 84, 86, 88, 90, 92, + 94, 96, 98, 100, + /* Mach */ + -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 14, 15, 16, -1, -1, -1, -1, -1, -1, -1, -1, 17, -1, -1, 18, -1, + 25, -1, -1, -1, -1, 30, -1, -1, -1, -1, -1, 20, -1, -1, -1, 19, + 21, 22, 23, 24, 26, 27, -1, 28, 29, -1, -1, -1, -1, -1, -1, -1, + 34, 35, 36, 37, 38, 39, 40, 41, -1, -1, -1, -1, -1, -1, -1, -1, + 42, 44, 46, 48 + }; + static struct rpb *rpbaddr = (struct rpb *) 0; + static u_int rpbpcbaddr = 0; + + if (!remote_debugging) { + /* + * If we are debugging a post-mortem and this is the first + * call of read_pcb, read the RPB. Also assoicate the + * thread/proc running at the time with the RPB. + */ + if (!devmem && rpbpcbaddr == 0) { + CORE_ADDR raddr = ksym_lookup("rpb"); + int usepcb = 1; + + if (raddr != ~0) { + rpbaddr = (struct rpb *) malloc(sizeof *rpbaddr); + if (!physrd(raddr, (char *)rpbaddr, sizeof *rpbaddr)) { + rpbpcbaddr = addr; + usepcb = 0; + } + } + if (usepcb) { + error("cannot read rpb, using pcb for registers\n"); + if (rpbaddr) + free((char *)rpbaddr); + rpbpcbaddr = ~0; + } + } + if (physrd (addr, (char *)&pcb, sizeof pcb)) + error ("cannot read pcb at %x.\n", addr); + } else { + if (remote_read_inferior_memory(addr, (char *)&pcb, sizeof pcb)) + error ("cannot read pcb at %x.\n", addr); + } + + if (kerneltype == OS_BSD) { + printf("p0br %lx p0lr %lx p1br %lx p1lr %lx\n", + pcb.pcb_p0br, pcb.pcb_p0lr, pcb.pcb_p1br, pcb.pcb_p1lr); + off = NUM_REGS; + } else { + printf("pcb %lx psw %lx ksp %lx\n", + addr, ((int *)&pcb)[31], ((int *)&pcb)[32]); + off = NUM_REGS * 2; + } + /* + * get the register values out of the sys pcb and + * store them where `read_register' will find them. + */ + bzero(registers, REGISTER_BYTES); + for (i = 0; i < NUM_REGS; ++i) + if (reg2pcb[i+off] != -1) + supply_register(i, &((int *)&pcb)[reg2pcb[i+off]]); + /* + * If the RPB is valid for this thread/proc use the register values + * contained there. + */ + if (addr == rpbpcbaddr) { + off = 0; + for (i = 0; i < NUM_REGS; ++i) + if (reg2pcb[i+off] != -1) + supply_register(i, &((int *)rpbaddr)[reg2pcb[i+off]]); + } +} + +void +setup_kernel_debugging() +{ + struct stat stb; + CORE_ADDR addr; + + fstat(corechan, &stb); + devmem = 0; + if ((stb.st_mode & S_IFMT) == S_IFCHR && stb.st_rdev == makedev(2, 0)) + devmem = 1; + + /* XXX */ + if (lookup_misc_func("Sysmap") < 0) + kerneltype = OS_MACH; + else + kerneltype = OS_BSD; + + if (kerneltype == OS_BSD) { + int len, err = 0; + + /* + * Hash table and PDIR are equivalently mapped + */ + nhtbl = kvread(ksym_lookup("nhtbl")); + if (nhtbl != ~0) { + len = nhtbl * sizeof(*htbl); + htbl = (struct hte *) malloc(len); + if (htbl) { + addr = kvread(ksym_lookup("htbl")); + if (physrd(addr, (char *)htbl, len)) + err++; + } else + err++; + } else + err++; + npdir = kvread(ksym_lookup("npdir")); + if (npdir != ~0) { + len = npdir * sizeof(*pdir); + pdir = (struct pde *) malloc(len); + if (pdir) { + addr = kvread(ksym_lookup("pdir")); + if (physrd(addr, (char *)pdir, len)) + err++; + } else + err++; + } else + err++; + if (err) { + error("cannot read PDIR/HTBL"); + return; + } + vtophys_ready = 1; + + /* + * pcb where "panic" saved registers in first thing in + * current u-area. The current u-area is pointed to by + * "uptr". + */ + addr = kvread(ksym_lookup("uptr")); + if (addr == ~0) { + error("cannot read current u-area address"); + return; + } + read_pcb(vtophys(0, addr)); /* XXX space */ + if (!devmem) { + /* find stack frame */ + CORE_ADDR panicstr; + char buf[256]; + register char *cp; + + panicstr = kvread(ksym_lookup("panicstr")); + if (panicstr == ~0) + return; + (void) kernel_core_file_hook(panicstr, buf, sizeof(buf)); + for (cp = buf; cp < &buf[sizeof(buf)] && *cp; cp++) + if (!isascii(*cp) || (!isprint(*cp) && !isspace(*cp))) + *cp = '?'; + if (*cp) + *cp = '\0'; + printf("panic: %s\n", buf); + } + } +#ifdef MACHKERNELDEBUG + else { + int *thread; + + /* + * Set up address translation + */ + if (mach_vtophys_init() == 0) { + error("cannot initialize vtophys for Mach"); + return; + } + vtophys_ready = 1; + + /* + * Locate active thread and read PCB + * XXX MAJOR HACK + * - assumes uni-processor + * - assumes position of pcb to avoid mach includes + */ + thread = (int *)kvread(ksym_lookup("active_threads")); + addr = kvread(&thread[9]); /* XXX: pcb addr */ + read_pcb(vtophys(0, addr)); + } +#endif +} + +vtop_command(arg) + char *arg; +{ + u_int sp, off, pa; + + if (!arg) + error_no_arg("kernel virtual address"); + if (!kernel_debugging) + error("not debugging kernel"); + + sp = 0; /* XXX */ + off = (u_int) parse_and_eval_address(arg); + pa = vtophys(sp, off); + printf("%lx.%lx -> ", sp, off); + if (pa == ~0) + printf("\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/hppahpux-xdep.c b/gdb/hppahpux-xdep.c new file mode 100644 index 00000000000..d5fa3c4a96a --- /dev/null +++ b/gdb/hppahpux-xdep.c @@ -0,0 +1,421 @@ +/* Machine-dependent code which would otherwise be in infptrace.c, + for GDB, the GNU debugger. This code is for the HP PA-RISC cpu. + Copyright (C) 1986, 1987, 1989, 1990, 1991 Free Software Foundation, Inc. + + Contributed by the Center for Software Science at the + University of Utah (pa-gdb-bugs@cs.utah.edu). + +/* Low level Unix child interface to ptrace, for GDB when running under Unix. + Copyright (C) 1988, 1989, 1990, 1991 Free Software Foundation, Inc. + +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 +#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" +#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, *addr, 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 + +/* This is used when GDB is exiting. It gives less chance of error.*/ + +void +kill_inferior_fast () +{ + if (inferior_pid == 0) + return; + ptrace (PT_EXIT, inferior_pid, 0, 0, 0); /* PT_EXIT = PT_KILL ? */ + wait ((int *)0); +} + +void +kill_inferior () +{ + kill_inferior_fast (); + 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 (int *)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, (int *)1, signal, 0); + else + ptrace (PT_CONTIN, inferior_pid, (int *)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, 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, 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, \ + (int *)(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, (int *)regaddr, 0, 0); + regaddr += sizeof (int); + if (errno != 0) + { + sprintf (mess, "reading register %s (#%d)", reg_names[regno], regno); + perror_with_name (mess); + } + } + if (regno == PCOQ_HEAD_REGNUM || regno == PCOQ_TAIL_REGNUM) + buf[3] &= ~0x3; + 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, (int *)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, (int *)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, (int *)addr, 0, 0); + } + + if (count > 1) /* FIXME, avoid if even boundary */ + { + buffer[count - 1] + = ptrace (PT_RIUSER, inferior_pid, + (int *)(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)) + { + errno = 0; + ptrace (PT_WDUSER, inferior_pid, (int *)addr, buffer[i], 0); + if (errno) + { + /* Using the appropriate one (I or D) is necessary for + Gould NP1, at least. */ + errno = 0; + ptrace (PT_WIUSER, inferior_pid, (int *)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, (int *)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/munch b/gdb/munch index 6d8a656f688..62c4cd3fbb6 100755 --- a/gdb/munch +++ b/gdb/munch @@ -23,12 +23,21 @@ if test "`$MUNCH_NM main.o | egrep main | egrep FUNC | egrep GLOB`" != "" ; then 's/^.*\(_initialize_[a-zA-Z0-9_]*\).*$/ {extern void \1 (); \1 ();}/'\ | sort -u elif test "`$MUNCH_NM main.o | egrep '[TD] _?main$'`" = "" ; then - # System V style nm - shift; - $MUNCH_NM $* | egrep '_initialize_.*' | egrep '\.text'|\ - sed -e \ - 's/^.*\(_initialize_[a-zA-Z0-9_]*\).*/ {extern void \1 (); \1 ();}/' \ - | sort -u + if test "`$MUNCH_NM main.o | head -6 | egrep 'Subspace$'`" != "" ; then + # HP PA RISC compilers don't prepend underscores + shift; + $MUNCH_NM $* | egrep '_initialize_.*' | \ + sed -e \ + 's/^.*\(_initialize_[a-zA-Z0-9_]*\).*/ {extern void \1 (); \1 ();}/' \ + | sort -u + else + # System V style nm + shift; + $MUNCH_NM $* | egrep '_initialize_.*' | egrep '\.text'|\ + sed -e \ + 's/^.*\(_initialize_[a-zA-Z0-9_]*\).*/ {extern void \1 (); \1 ();}/' \ + | sort -u + fi else # BSD style nm # We now accept either text or data symbols, since the RT/PC uses data. diff --git a/gdb/partial-stab.h b/gdb/partial-stab.h index 6b6e3de9a31..e064aeb3595 100644 --- a/gdb/partial-stab.h +++ b/gdb/partial-stab.h @@ -70,8 +70,14 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ SET_NAMESTRING(); if ((namestring[0] == '-' && namestring[1] == 'l') || (namestring [(nsl = strlen (namestring)) - 1] == 'o' - && namestring [nsl - 2] == '.')) + && namestring [nsl - 2] == '.') +#ifdef hp9000s800 + /* some cooperation from gcc to get around ld stupidity */ + || (namestring[0] == 'e' && !strcmp (namestring, "end_file.")) +#endif + ) { +#ifndef hp9000s800 if (objfile -> ei.entry_point < CUR_SYMBOL_VALUE && objfile -> ei.entry_point >= last_o_file_start && addr == 0) /* FIXME nogood nomore */ @@ -79,6 +85,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ objfile -> ei.entry_file_lowpc = last_o_file_start; objfile -> ei.entry_file_highpc = CUR_SYMBOL_VALUE; } +#endif if (past_first_source_file && pst /* The gould NP1 uses low values for .o and -l symbols which are not the address. */ diff --git a/gdb/tm-hppabsd.h b/gdb/tm-hppabsd.h new file mode 100644 index 00000000000..c1bb5132de9 --- /dev/null +++ b/gdb/tm-hppabsd.h @@ -0,0 +1,570 @@ +/* Parameters for execution on a Hewlett-Packard PA-RISC machine, running + HPUX or BSD. + Copyright (C) 1986, 1987, 1989, 1990, 1991 Free Software Foundation, Inc. + + Contributed by the Center for Software Science at the + University of Utah (pa-gdb-bugs@cs.utah.edu). + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* Get at various relevent fields of an instruction word. */ + +#define MASK_5 0x1f +#define MASK_11 0x7ff +#define MASK_14 0x3fff +#define MASK_21 0x1fffff + +/* This macro gets bit fields using HP's numbering (MSB = 0) */ + +#define GET_FIELD(X, FROM, TO) \ + ((X) >> 31 - (TO) & (1 << ((TO) - (FROM) + 1)) - 1) + +/* Watch out for NaNs */ + +#define IEEE_FLOAT + +/* Groan */ + +#define ARGS_GROW_DOWN + +/* Get rid of any system-imposed stack limit if possible. */ + + + +/* Define this if the C compiler puts an underscore at the front + of external names before giving them to the linker. */ + +/* #define NAMES_HAVE_UNDERSCORE */ + +/* Debugger information will be in DBX format. */ + +#define READ_DBX_FORMAT + +/* Offset from address of function to start of its code. + Zero on most machines. */ + +#define FUNCTION_START_OFFSET 0 + +/* Advance PC across any function entry prologue instructions + to reach some "real" code. */ + +/* skip (stw rp, -20(0,sp)); copy 4,1; copy sp, 4; stwm 1,framesize(sp) + for gcc, or (stw rp, -20(0,sp); stwm 1, framesize(sp) for hcc */ + +#define SKIP_PROLOGUE(pc) \ +{ if (read_memory_integer ((pc), 4) == 0x6BC23FD9) \ + { if (read_memory_integer ((pc) + 4, 4) == 0x8040241) \ + (pc) += 16; \ + else if ((read_memory_integer (pc + 4, 4) & ~MASK_14) == 0x68810000) \ + (pc) += 8;} \ + else if (read_memory_integer ((pc), 4) == 0x8040241) \ + (pc) += 12; \ + else if ((read_memory_integer (pc, 4) & ~MASK_14) == 0x68810000) \ + (pc) += 4;} + +/* 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. */ + +#define SAVED_PC_AFTER_CALL(frame) (read_register (RP_REGNUM) & ~3) + +/* Address of end of stack space. Who knows. */ + +#define STACK_END_ADDR 0x80000000 + +/* Stack grows upward */ + +#define INNER_THAN > + + +/* Sequence of bytes for breakpoint instruction. */ + +/*#define BREAKPOINT {0x00, 0x00, 0x00, 0x00}*/ +#ifdef KERNELDEBUG /* XXX */ +#define BREAKPOINT {0x00, 0x00, 0xa0, 0x00} +#else +#define BREAKPOINT {0x00, 0x01, 0x00, 0x04} +#endif + +/* Amount PC must be decremented by after a breakpoint. + This is often the number of bytes in BREAKPOINT + but not always. + + Not on the PA-RISC */ + +#define DECR_PC_AFTER_BREAK 0 + +/* return instruction is bv r0(rp) */ + +#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 4) == 0xE840C000) + +/* Return 1 if P points to an invalid floating point value. */ + +#define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */ + +/* Largest integer type */ +#define LONGEST long + +/* Name of the builtin type for the LONGEST type above. */ +#define BUILTIN_TYPE_LONGEST builtin_type_long + +/* Say how long (ordinary) registers are. */ + +#define REGISTER_TYPE long + +/* Number of machine registers */ + +#define NUM_REGS 100 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +#define REGISTER_NAMES \ + {"flags", "r1", "rp", "r3", "r4", "r5", "r6", "r7", "r8", "r9", \ + "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", \ + "r20", "r21", "r22", "arg3", "arg2", "arg1", "arg0", "dp", "ret0", "ret1", \ + "sp", "r31", "sar", "pcoqh", "pcsqh", "pcoqt", "pcsqt", \ + "eiem", "iir", "isr", "ior", "ipsw", "goto", "sr4", "sr0", "sr1", "sr2", \ + "sr3", "sr5", "sr6", "sr7", "cr0", "cr8", "cr9", "ccr", "cr12", "cr13", \ + "cr24", "cr25", "cr26", "mpsfu_high", "mpsfu_low", "mpsfu_ovflo", "pad", \ + "fpsr", "fpe1", "fpe2", "fpe3", "fpe4", "fpe5", "fpe6", "fpe7", \ + "fp4", "fp5", "fp6", "fp7", "fp8", \ + "fp9", "fp10", "fp11", "fp12", "fp13", "fp14", "fp15", \ + "fp16", "fp17", "fp18", "fp19", "fp20", "fp21", "fp22", "fp23", \ + "fp24", "fp25", "fp26", "fp27", "fp28", "fp29", "fp30", "fp31"} + +/* Register numbers of various important registers. + Note that some of these values are "real" register numbers, + and correspond to the general registers of the machine, + and some are "phony" register numbers which are too large + to be actual register numbers as far as the user is concerned + but do serve to get the desired values when passed to read_register. */ + +#define RP_REGNUM 2 /* return pointer */ +#define FP_REGNUM 4 /* Contains address of executing stack */ + /* frame */ +#define SP_REGNUM 30 /* Contains address of top of stack */ +#define SAR_REGNUM 32 /* shift amount register */ +#define IPSW_REGNUM 41 /* processor status word. ? */ +#define PCOQ_HEAD_REGNUM 33 /* instruction offset queue head */ +#define PCSQ_HEAD_REGNUM 34 /* instruction space queue head */ +#define PCOQ_TAIL_REGNUM 35 /* instruction offset queue tail */ +#define PCSQ_TAIL_REGNUM 36 /* instruction space queue tail */ +#define FP0_REGNUM 64 /* floating point reg. 0 */ +#define FP4_REGNUM 72 + +/* compatibility with the rest of gdb. */ +#define PC_REGNUM PCOQ_HEAD_REGNUM +#define NPC_REGNUM PCOQ_TAIL_REGNUM + +/* Define DO_REGISTERS_INFO() to do machine-specific formatting + of register dumps. */ + +#define DO_REGISTERS_INFO(_regnum, fp) pa_do_registers_info (_regnum, fp) + +/* PA specific macro to see if the current instruction is nullified. */ +#define INSTRUCTION_NULLIFIED ((int)read_register (IPSW_REGNUM) & 0x00200000) + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES (32 * 4 + 11 * 4 + 8 * 4 + 12 * 4 + 4 + 32 * 8) + +/* Index within `registers' of the first byte of the space for + register N. */ + +#define REGISTER_BYTE(N) \ + ((N) >= FP4_REGNUM ? ((N) - FP4_REGNUM) * 8 + 288 : (N) * 4) + +/* Number of bytes of storage in the actual machine representation + for register N. On the PA-RISC, all regs are 4 bytes + except the floating point regs which are 8 bytes. */ + +#define REGISTER_RAW_SIZE(N) ((N) < FP4_REGNUM ? 4 : 8) + +/* Number of bytes of storage in the program's representation + for register N. */ + +#define REGISTER_VIRTUAL_SIZE(N) REGISTER_RAW_SIZE(N) + +/* Largest value REGISTER_RAW_SIZE can have. */ + +#define MAX_REGISTER_RAW_SIZE 8 + +/* Largest value REGISTER_VIRTUAL_SIZE can have. */ + +#define MAX_REGISTER_VIRTUAL_SIZE 8 + +/* Nonzero if register N requires conversion + from raw format to virtual format. */ + +#define REGISTER_CONVERTIBLE(N) 0 + +/* Convert data from raw format for register REGNUM + to virtual format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) \ +{ bcopy ((FROM), (TO), (REGNUM) < FP4_REGNUM ? 4 : 8); } + +/* Convert data from virtual format for register REGNUM + to raw format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO) \ +{ bcopy ((FROM), (TO), (REGNUM) < FP4_REGNUM ? 4 : 8); } + +/* Return the GDB type object for the "standard" data type + of data in register N. */ + +#define REGISTER_VIRTUAL_TYPE(N) \ + ((N) < FP4_REGNUM ? builtin_type_int : builtin_type_double) + +/* Store the address of the place in which to copy the structure the + subroutine will return. This is called from call_function. */ + +#define STORE_STRUCT_RETURN(ADDR, SP) {write_register (28, (ADDR)); } + +/* Extract from an array REGBUF containing the (raw) register state + a function return value of type TYPE, and copy that, in virtual format, + into VALBUF. */ + +#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \ + bcopy ((REGBUF) + REGISTER_BYTE(TYPE_LENGTH(TYPE) > 4 ? \ + FP4_REGNUM :28), VALBUF, TYPE_LENGTH (TYPE)) + +/* Write into appropriate registers a function return value + of type TYPE, given in virtual format. */ + +#define STORE_RETURN_VALUE(TYPE,VALBUF) \ + write_register_bytes (TYPE_LENGTH(TYPE) > 4 ? FP4_REGNUM :28, \ + VALBUF, TYPE_LENGTH (TYPE)) + +/* Extract from an array REGBUF containing the (raw) register state + the address in which a function should return its structure value, + as a CORE_ADDR (or an expression that can be used as one). */ + +#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) (*(int *)((REGBUF) + 28)) + +/* This is a piece of magic that is given a register number REGNO + and as BLOCKEND the address in the system of the end of the user structure + and stores in ADDR the address in the kernel or core dump + of that register. */ + + +/* Describe the pointer in each stack frame to the previous stack frame + (its caller). */ + +/* FRAME_CHAIN takes a frame's nominal address + and produces the frame's chain-pointer. + + FRAME_CHAIN_COMBINE takes the chain pointer and the frame's nominal address + and produces the nominal address of the caller frame. + + However, if FRAME_CHAIN_VALID returns zero, + it means the given frame is the outermost one and has no caller. + In that case, FRAME_CHAIN_COMBINE is not used. */ + +/* In the case of the PA-RISC, the frame's nominal address + is the address of a 4-byte word containing the calling frame's + address (previous FP). */ + +#define FRAME_CHAIN(thisframe) \ + (inside_entry_file ((thisframe)->pc) ? \ + read_memory_integer ((thisframe)->frame, 4) :\ + 0) + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + frame_chain_valid (chain, thisframe) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + +/* Define other aspects of the stack frame. */ + +/* A macro that tells us whether the function invocation represented + by FI does not have a frame on the stack associated with it. If it + does not, FRAMELESS is set to 1, else 0. */ +#define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) \ + (FRAMELESS) = frameless_look_for_prologue(FI) + +#define FRAME_SAVED_PC(FRAME) frame_saved_pc (FRAME) + +#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame) + +#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame) +/* Set VAL to the number of args passed to frame described by FI. + Can set VAL to -1, meaning no way to tell. */ + +/* We can't tell how many args there are + now that the C compiler delays popping them. */ +#define FRAME_NUM_ARGS(val,fi) (val = -1) + +/* Return number of bytes at start of arglist that are not really args. */ + +#define FRAME_ARGS_SKIP 0 + +/* Put here the code to store, into a struct frame_saved_regs, + the addresses of the saved registers of frame described by FRAME_INFO. + This includes special registers such as pc and fp saved in special + ways in the stack frame. sp is even more special: + the address we return for it IS the sp for the next frame. */ + +/* Deal with dummy functions later. */ + +#define STW_P(INSN) (((INSN) & 0xfc000000) == 0x68000000) +#define ADDIL_P(INSN) (((INSN) & 0xfc000000) == 0x28000000) +#define LDO_P(INSN) (((INSN) & 0xfc00c000) == 0x34000000) + + +#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \ +{ register int regnum; \ + register CORE_ADDR next_addr; \ + register CORE_ADDR pc; \ + unsigned this_insn; \ + unsigned address; \ + \ + bzero (&frame_saved_regs, sizeof frame_saved_regs); \ + if ((frame_info)->pc <= ((frame_info)->frame - CALL_DUMMY_LENGTH - \ + FP_REGNUM * 4 - 16 * 8) \ + && (frame_info)->pc > (frame_info)->frame) \ + find_dummy_frame_regs ((frame_info), &(frame_saved_regs)); \ + else \ + { pc = get_pc_function_start ((frame_info)->pc); \ + if (read_memory_integer (pc, 4) == 0x6BC23FD9) \ + { (frame_saved_regs).regs[RP_REGNUM] = (frame_info)->frame - 20;\ + pc = pc + 4; \ + } \ + if (read_memory_integer (pc, 4) != 0x8040241) goto lose; \ + pc += 8; /* skip "copy 4,1; copy 30, 4" */ \ + /* skip either "stw 1,0(4);addil L'fsize,30;ldo R'fsize(1),30" \ + or "stwm 1,fsize(30)" */ \ + if ((read_memory_integer (pc, 4) & ~MASK_14) == 0x68810000) \ + pc += 12; \ + else \ + pc += 4; \ + while (1) \ + { this_insn = read_memory_integer(pc, 4); \ + if (STW_P (this_insn)) /* stw */ \ + { regnum = GET_FIELD (this_insn, 11, 15); \ + if (!regnum) goto lose; \ + (frame_saved_regs).regs[regnum] = (frame_info)->frame + \ + extract_14 (this_insn); \ + pc += 4; \ + } \ + else if (ADDIL_P (this_insn)) /* addil */ \ + { int next_insn; \ + next_insn = read_memory_integer(pc + 4, 4); \ + if (STW_P (next_insn)) /* stw */ \ + { regnum = GET_FIELD (this_insn, 6, 10); \ + if (!regnum) goto lose; \ + (frame_saved_regs).regs[regnum] = (frame_info)->frame +\ + (extract_21 (this_insn) << 11) + extract_14 (next_insn);\ + pc += 8; \ + } \ + else \ + break; \ + } \ + else \ + { pc += 4; \ + break; \ + } \ + } \ + this_insn = read_memory_integer (pc, 4); \ + if (LDO_P (this_insn)) \ + { next_addr = (frame_info)->frame + extract_14 (this_insn); \ + pc += 4; \ + } \ + else if (ADDIL_P (this_insn)) \ + { next_addr = (frame_info)->frame + (extract_21 (this_insn) << 11)\ + + extract_14 (read_memory_integer (pc + 4, 4)); \ + pc += 8; \ + } \ + while (1) \ + { this_insn = read_memory_integer (pc, 4); \ + if ((this_insn & 0xfc001fe0) == 0x2c001220) /* fstds,ma */ \ + { regnum = GET_FIELD (this_insn, 27, 31); \ + (frame_saved_regs).regs[regnum + FP0_REGNUM] = next_addr; \ + next_addr += 8; \ + } \ + else \ + break; \ + } \ + lose: \ + (frame_saved_regs).regs[FP_REGNUM] = (frame_info)->frame; \ + (frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame -4; \ + }} + +/* Things needed for making the inferior call functions. */ + +/* Push an empty stack frame, to record the current PC, etc. */ + +#define PUSH_DUMMY_FRAME \ +{ register CORE_ADDR sp = read_register (SP_REGNUM); \ + register int regnum; \ + int int_buffer; \ + double freg_buffer; \ + /* Space for "arguments"; the RP goes in here. */ \ + sp += 48; \ + int_buffer = read_register (RP_REGNUM) | 0x3; \ + write_memory (sp - 20, &int_buffer, 4); \ + int_buffer = read_register (FP_REGNUM); \ + write_memory (sp, &int_buffer, 4); \ + write_register (FP_REGNUM, sp); \ + sp += 4; \ + for (regnum = 1; regnum < 31; regnum++) \ + if (regnum != RP_REGNUM && regnum != FP_REGNUM) \ + sp = push_word (sp, read_register (regnum)); \ + for (regnum = FP0_REGNUM; regnum < NUM_REGS; regnum++) \ + { read_register_bytes (REGISTER_BYTE (regnum), &freg_buffer, 8); \ + sp = push_bytes (sp, &freg_buffer, 8);} \ + sp = push_word (sp, read_register (IPSW_REGNUM)); \ + sp = push_word (sp, read_register (SAR_REGNUM)); \ + sp = push_word (sp, read_register (PCOQ_TAIL_REGNUM)); \ + sp = push_word (sp, read_register (PCSQ_TAIL_REGNUM)); \ + write_register (SP_REGNUM, sp);} + +/* Discard from the stack the innermost frame, + restoring all saved registers. */ +#define POP_FRAME \ +{ register FRAME frame = get_current_frame (); \ + register CORE_ADDR fp; \ + register int regnum; \ + struct frame_saved_regs fsr; \ + struct frame_info *fi; \ + double freg_buffer; \ + fi = get_frame_info (frame); \ + fp = fi->frame; \ + get_frame_saved_regs (fi, &fsr); \ + for (regnum = 31; regnum > 0; regnum--) \ + if (fsr.regs[regnum]) \ + write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \ + for (regnum = NUM_REGS - 1; regnum >= FP0_REGNUM ; regnum--) \ + if (fsr.regs[regnum]) \ + { read_memory (fsr.regs[regnum], &freg_buffer, 8); \ + write_register_bytes (REGISTER_BYTE (regnum), &freg_buffer, 8); }\ + if (fsr.regs[IPSW_REGNUM]) \ + write_register (IPSW_REGNUM, \ + read_memory_integer (fsr.regs[IPSW_REGNUM], 4)); \ + if (fsr.regs[SAR_REGNUM]) \ + write_register (SAR_REGNUM, \ + read_memory_integer (fsr.regs[SAR_REGNUM], 4)); \ + if (fsr.regs[PCOQ_TAIL_REGNUM]) \ + write_register (PCOQ_TAIL_REGNUM, \ + read_memory_integer (fsr.regs[PCOQ_TAIL_REGNUM], 4));\ + if (fsr.regs[PCSQ_TAIL_REGNUM]) \ + write_register (PCSQ_TAIL_REGNUM, \ + read_memory_integer (fsr.regs[PCSQ_TAIL_REGNUM], 4));\ + write_register (FP_REGNUM, read_memory_integer (fp, 4)); \ + write_register (SP_REGNUM, fp + 8); \ + flush_cached_frames (); \ + set_current_frame (create_new_frame (read_register (FP_REGNUM),\ + read_pc ())); } + +/* This sequence of words is the instructions + +; Call stack frame has already been built by gdb. Since we could be calling +; a varargs function, and we do not have the benefit of a stub to put things in +; the right place, we load the first 4 word of arguments into both the general +; and fp registers. +call_dummy + ldw -36(sp), arg0 + ldw -40(sp), arg1 + ldw -44(sp), arg2 + ldw -48(sp), arg3 + ldo -36(sp), r1 + fldws 0(0, r1), fr4 + fldds -4(0, r1), fr5 + fldws -8(0, r1), fr6 + fldds -12(0, r1), fr7 + ldil 0, r22 ; target will be placed here. + ldo 0(r22), r22 + ldsid (0,r22), r3 + ldil 0, r1 ; _sr4export will be placed here. + ldo 0(r1), r1 + ldsid (0,r1), r4 + combt,=,n r3, r4, text_space ; If target is in data space, do a + ble 0(sr5, r22) ; "normal" procedure call + copy r31, r2 + break 4, 8 +text_space ; Otherwise, go through _sr4export, + ble (sr4, r1) ; which will return back here. + stw 31,-24(r30) + break 4, 8 + + The dummy decides if the target is in text space or data space. If + it's in data space, there's no problem because the target can + return back to the dummy. However, if the target is in text space, + the dummy calls the secret, undocumented routine _sr4export, which + calls a function in text space and can return to any space. Instead + of including fake instructions to represent saved registers, we + know that the frame is associated with the call dummy and treat it + specially. */ + +#define CALL_DUMMY { 0x4bda3fb9, 0x4bd93fb1, 0x4bd83fa9, 0x4bd73fa1, \ + 0x37c13fb9, 0x24201004, 0x2c391005, 0x24311006, \ + 0x2c291007, 0x22c00000, 0x36d60000, 0x02c010a3, \ + 0x20200000, 0x34210000, 0x002010a4, 0x80832012, \ + 0xe6c06000, 0x081f0242, 0x00010004, 0xe4202000, \ + 0x6bdf3fd1, 0x00010004} + +#define CALL_DUMMY_LENGTH 88 +#define CALL_DUMMY_START_OFFSET 0 +/* Insert the specified number of args and function address + into a call sequence of the above form stored at DUMMYNAME. */ +#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, args, type, gcc_p) \ +{ static CORE_ADDR sr4export_address = 0; \ + \ + if (!sr4export_address) \ + { \ + struct minimal_symbol *msymbol; \ + msymbol = lookup_minimal_symbol ("_sr4export", (struct objfile *) NULL);\ + if (msymbol = NULL) \ + error ("Can't find an address for _sr4export trampoline"); \ + else \ + sr4export_address = msymbol -> address; \ + } \ + dummyname[9] = deposit_21 (fun >> 11, dummyname[9]); \ + dummyname[10] = deposit_14 (fun & MASK_11, dummyname[10]); \ + dummyname[12] = deposit_21 (sr4export_address >> 11, dummyname[12]); \ + dummyname[13] = deposit_14 (sr4export_address & MASK_11, dummyname[13]);\ +} + +/* Write the PC to a random value. + On PA-RISC, we need to be sure that the PC space queue is correct. */ + +#define WRITE_PC(addr) \ +{ int space_reg, space = ((addr) >> 30); \ + int space_val; \ + if (space == 0) \ + space_reg = 43; /* Space reg sr4 */ \ + else if (space == 1) \ + space_reg = 48; /* Space reg sr5*/ \ + else \ + error ("pc = %x is in illegal space.", addr); \ + space_val = read_register (space_reg); \ + write_register (PCOQ_HEAD_REGNUM, addr); \ + write_register (PCSQ_HEAD_REGNUM, space_val); \ + write_register (PCOQ_TAIL_REGNUM, addr); \ + write_register (PCSQ_TAIL_REGNUM, space_val);} + + +# 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/tm-hppahpux.h b/gdb/tm-hppahpux.h new file mode 100644 index 00000000000..bf1662fd02a --- /dev/null +++ b/gdb/tm-hppahpux.h @@ -0,0 +1,576 @@ +/* Parameters for execution on a Hewlett-Packard PA-RISC machine, running + HPUX or BSD. + Copyright (C) 1986, 1987, 1989, 1990, 1991 Free Software Foundation, Inc. + + Contributed by the Center for Software Science at the + University of Utah (pa-gdb-bugs@cs.utah.edu). + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + + +/* Get at various relevent fields of an instruction word. */ + +#define MASK_5 0x1f +#define MASK_11 0x7ff +#define MASK_14 0x3fff +#define MASK_21 0x1fffff + +/* This macro gets bit fields using HP's numbering (MSB = 0) */ + +#define GET_FIELD(X, FROM, TO) \ + ((X) >> 31 - (TO) & (1 << ((TO) - (FROM) + 1)) - 1) + +/* Watch out for NaNs */ + +#define IEEE_FLOAT + +/* Groan */ + +#define ARGS_GROW_DOWN + +/* Get rid of any system-imposed stack limit if possible. */ + + + +/* Define this if the C compiler puts an underscore at the front + of external names before giving them to the linker. */ + +/* #define NAMES_HAVE_UNDERSCORE */ + +/* Debugger information will be in DBX format. */ + +#define READ_DBX_FORMAT + +/* Offset from address of function to start of its code. + Zero on most machines. */ + +#define FUNCTION_START_OFFSET 0 + +/* Advance PC across any function entry prologue instructions + to reach some "real" code. */ + +/* skip (stw rp, -20(0,sp)); copy 4,1; copy sp, 4; stwm 1,framesize(sp) + for gcc, or (stw rp, -20(0,sp); stwm 1, framesize(sp) for hcc */ + +#define SKIP_PROLOGUE(pc) \ +{ if (read_memory_integer ((pc), 4) == 0x6BC23FD9) \ + { if (read_memory_integer ((pc) + 4, 4) == 0x8040241) \ + (pc) += 16; \ + else if ((read_memory_integer (pc + 4, 4) & ~MASK_14) == 0x68810000) \ + (pc) += 8;} \ + else if (read_memory_integer ((pc), 4) == 0x8040241) \ + (pc) += 12; \ + else if ((read_memory_integer (pc, 4) & ~MASK_14) == 0x68810000) \ + (pc) += 4;} + +/* 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. */ + + +#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) + +/* Address of end of stack space. Who knows. */ + +#define STACK_END_ADDR 0x80000000 + +/* Stack grows upward */ + +#define INNER_THAN > + + +/* Sequence of bytes for breakpoint instruction. */ + +/*#define BREAKPOINT {0x00, 0x00, 0x00, 0x00}*/ +#ifdef KERNELDEBUG /* XXX */ +#define BREAKPOINT {0x00, 0x00, 0xa0, 0x00} +#else +#define BREAKPOINT {0x00, 0x01, 0x00, 0x04} +#endif + +/* Amount PC must be decremented by after a breakpoint. + This is often the number of bytes in BREAKPOINT + but not always. + + Not on the PA-RISC */ + +#define DECR_PC_AFTER_BREAK 0 + +/* return instruction is bv r0(rp) */ + +#define ABOUT_TO_RETURN(pc) (read_memory_integer (pc, 4) == 0xE840C000) + +/* Return 1 if P points to an invalid floating point value. */ + +#define INVALID_FLOAT(p, len) 0 /* Just a first guess; not checked */ + +/* Largest integer type */ +#define LONGEST long + +/* Name of the builtin type for the LONGEST type above. */ +#define BUILTIN_TYPE_LONGEST builtin_type_long + +/* Say how long (ordinary) registers are. */ + +#define REGISTER_TYPE long + +/* Number of machine registers */ + +#define NUM_REGS 100 + +/* Initializer for an array of names of registers. + There should be NUM_REGS strings in this initializer. */ + +#define REGISTER_NAMES \ + {"flags", "r1", "rp", "r3", "r4", "r5", "r6", "r7", "r8", "r9", \ + "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", \ + "r20", "r21", "r22", "arg3", "arg2", "arg1", "arg0", "dp", "ret0", "ret1", \ + "sp", "r31", "sar", "pcoqh", "pcsqh", "pcoqt", "pcsqt", \ + "eiem", "iir", "isr", "ior", "ipsw", "goto", "sr4", "sr0", "sr1", "sr2", \ + "sr3", "sr5", "sr6", "sr7", "cr0", "cr8", "cr9", "ccr", "cr12", "cr13", \ + "cr24", "cr25", "cr26", "mpsfu_high", "mpsfu_low", "mpsfu_ovflo", "pad", \ + "fpsr", "fpe1", "fpe2", "fpe3", "fpe4", "fpe5", "fpe6", "fpe7", \ + "fp4", "fp5", "fp6", "fp7", "fp8", \ + "fp9", "fp10", "fp11", "fp12", "fp13", "fp14", "fp15", \ + "fp16", "fp17", "fp18", "fp19", "fp20", "fp21", "fp22", "fp23", \ + "fp24", "fp25", "fp26", "fp27", "fp28", "fp29", "fp30", "fp31"} + + + +/* Register numbers of various important registers. + Note that some of these values are "real" register numbers, + and correspond to the general registers of the machine, + and some are "phony" register numbers which are too large + to be actual register numbers as far as the user is concerned + but do serve to get the desired values when passed to read_register. */ + +#define RP_REGNUM 2 /* return pointer */ +#define FP_REGNUM 4 /* Contains address of executing stack */ + /* frame */ +#define SP_REGNUM 30 /* Contains address of top of stack */ +#define SAR_REGNUM 32 /* shift amount register */ +#define IPSW_REGNUM 41 /* processor status word. ? */ +#define PCOQ_HEAD_REGNUM 33 /* instruction offset queue head */ +#define PCSQ_HEAD_REGNUM 34 /* instruction space queue head */ +#define PCOQ_TAIL_REGNUM 35 /* instruction offset queue tail */ +#define PCSQ_TAIL_REGNUM 36 /* instruction space queue tail */ +#define FP0_REGNUM 64 /* floating point reg. 0 */ +#define FP4_REGNUM 72 + +/* compatibility with the rest of gdb. */ +#define PC_REGNUM PCOQ_HEAD_REGNUM +#define NPC_REGNUM PCOQ_TAIL_REGNUM + +/* Define DO_REGISTERS_INFO() to do machine-specific formatting + of register dumps. */ + +#define DO_REGISTERS_INFO(_regnum, fp) pa_do_registers_info (_regnum, fp) + +/* PA specific macro to see if the current instruction is nullified. */ +#define INSTRUCTION_NULLIFIED ((int)read_register (IPSW_REGNUM) & 0x00200000) + +/* Total amount of space needed to store our copies of the machine's + register state, the array `registers'. */ +#define REGISTER_BYTES (32 * 4 + 11 * 4 + 8 * 4 + 12 * 4 + 4 + 32 * 8) + +/* Index within `registers' of the first byte of the space for + register N. */ + +#define REGISTER_BYTE(N) \ + ((N) >= FP4_REGNUM ? ((N) - FP4_REGNUM) * 8 + 288 : (N) * 4) + +/* Number of bytes of storage in the actual machine representation + for register N. On the PA-RISC, all regs are 4 bytes + except the floating point regs which are 8 bytes. */ + +#define REGISTER_RAW_SIZE(N) ((N) < FP4_REGNUM ? 4 : 8) + +/* Number of bytes of storage in the program's representation + for register N. */ + +#define REGISTER_VIRTUAL_SIZE(N) REGISTER_RAW_SIZE(N) + +/* Largest value REGISTER_RAW_SIZE can have. */ + +#define MAX_REGISTER_RAW_SIZE 8 + +/* Largest value REGISTER_VIRTUAL_SIZE can have. */ + +#define MAX_REGISTER_VIRTUAL_SIZE 8 + +/* Nonzero if register N requires conversion + from raw format to virtual format. */ + +#define REGISTER_CONVERTIBLE(N) 0 + +/* Convert data from raw format for register REGNUM + to virtual format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_VIRTUAL(REGNUM,FROM,TO) \ +{ bcopy ((FROM), (TO), (REGNUM) < FP4_REGNUM ? 4 : 8); } + +/* Convert data from virtual format for register REGNUM + to raw format for register REGNUM. */ + +#define REGISTER_CONVERT_TO_RAW(REGNUM,FROM,TO) \ +{ bcopy ((FROM), (TO), (REGNUM) < FP4_REGNUM ? 4 : 8); } + +/* Return the GDB type object for the "standard" data type + of data in register N. */ + +#define REGISTER_VIRTUAL_TYPE(N) \ + ((N) < FP4_REGNUM ? builtin_type_int : builtin_type_double) + +/* Store the address of the place in which to copy the structure the + subroutine will return. This is called from call_function. */ + +#define STORE_STRUCT_RETURN(ADDR, SP) {write_register (28, (ADDR)); } + +/* Extract from an array REGBUF containing the (raw) register state + a function return value of type TYPE, and copy that, in virtual format, + into VALBUF. */ + +#define EXTRACT_RETURN_VALUE(TYPE,REGBUF,VALBUF) \ + bcopy ((REGBUF) + REGISTER_BYTE(TYPE_LENGTH(TYPE) > 4 ? \ + FP4_REGNUM :28), VALBUF, TYPE_LENGTH (TYPE)) + +/* Write into appropriate registers a function return value + of type TYPE, given in virtual format. */ + +#define STORE_RETURN_VALUE(TYPE,VALBUF) \ + write_register_bytes (TYPE_LENGTH(TYPE) > 4 ? FP4_REGNUM :28, \ + VALBUF, TYPE_LENGTH (TYPE)) + +/* Extract from an array REGBUF containing the (raw) register state + the address in which a function should return its structure value, + as a CORE_ADDR (or an expression that can be used as one). */ + +#define EXTRACT_STRUCT_VALUE_ADDRESS(REGBUF) (*(int *)((REGBUF) + 28)) + +/* This is a piece of magic that is given a register number REGNO + and as BLOCKEND the address in the system of the end of the user structure + and stores in ADDR the address in the kernel or core dump + of that register. */ + + +/* Describe the pointer in each stack frame to the previous stack frame + (its caller). */ + +/* FRAME_CHAIN takes a frame's nominal address + and produces the frame's chain-pointer. + + FRAME_CHAIN_COMBINE takes the chain pointer and the frame's nominal address + and produces the nominal address of the caller frame. + + However, if FRAME_CHAIN_VALID returns zero, + it means the given frame is the outermost one and has no caller. + In that case, FRAME_CHAIN_COMBINE is not used. */ + +/* In the case of the PA-RISC, the frame's nominal address + is the address of a 4-byte word containing the calling frame's + address (previous FP). */ + +#define FRAME_CHAIN(thisframe) \ + (inside_entry_file ((thisframe)->pc) ? \ + read_memory_integer ((thisframe)->frame, 4) :\ + 0) + +#define FRAME_CHAIN_VALID(chain, thisframe) \ + frame_chain_valid (chain, thisframe) + +#define FRAME_CHAIN_COMBINE(chain, thisframe) (chain) + +/* Define other aspects of the stack frame. */ + +/* A macro that tells us whether the function invocation represented + by FI does not have a frame on the stack associated with it. If it + does not, FRAMELESS is set to 1, else 0. */ +#define FRAMELESS_FUNCTION_INVOCATION(FI, FRAMELESS) \ + (FRAMELESS) = frameless_look_for_prologue(FI) + +#define FRAME_SAVED_PC(FRAME) frame_saved_pc (FRAME) + +#define FRAME_ARGS_ADDRESS(fi) ((fi)->frame) + +#define FRAME_LOCALS_ADDRESS(fi) ((fi)->frame) +/* Set VAL to the number of args passed to frame described by FI. + Can set VAL to -1, meaning no way to tell. */ + +/* We can't tell how many args there are + now that the C compiler delays popping them. */ +#define FRAME_NUM_ARGS(val,fi) (val = -1) + +/* Return number of bytes at start of arglist that are not really args. */ + +#define FRAME_ARGS_SKIP 0 + +/* Put here the code to store, into a struct frame_saved_regs, + the addresses of the saved registers of frame described by FRAME_INFO. + This includes special registers such as pc and fp saved in special + ways in the stack frame. sp is even more special: + the address we return for it IS the sp for the next frame. */ + +/* Deal with dummy functions later. */ + +#define STW_P(INSN) (((INSN) & 0xfc000000) == 0x68000000) +#define ADDIL_P(INSN) (((INSN) & 0xfc000000) == 0x28000000) +#define LDO_P(INSN) (((INSN) & 0xfc00c000) == 0x34000000) + +int millicode_start, millicode_end; + +#define FRAME_FIND_SAVED_REGS(frame_info, frame_saved_regs) \ +{ register int regnum; \ + register CORE_ADDR next_addr; \ + register CORE_ADDR pc; \ + unsigned this_insn; \ + unsigned address; \ + \ + bzero (&frame_saved_regs, sizeof frame_saved_regs); \ + if ((frame_info)->pc <= ((frame_info)->frame - CALL_DUMMY_LENGTH - \ + FP_REGNUM * 4 - 16 * 8) \ + && (frame_info)->pc > (frame_info)->frame) \ + find_dummy_frame_regs ((frame_info), &(frame_saved_regs)); \ + else \ + { pc = get_pc_function_start ((frame_info)->pc); \ + if (read_memory_integer (pc, 4) == 0x6BC23FD9) \ + { (frame_saved_regs).regs[RP_REGNUM] = (frame_info)->frame - 20;\ + pc = pc + 4; \ + } \ + if (read_memory_integer (pc, 4) != 0x8040241) goto lose; \ + pc += 8; /* skip "copy 4,1; copy 30, 4" */ \ + /* skip either "stw 1,0(4);addil L'fsize,30;ldo R'fsize(1),30" \ + or "stwm 1,fsize(30)" */ \ + if ((read_memory_integer (pc, 4) & ~MASK_14) == 0x68810000) \ + pc += 12; \ + else \ + pc += 4; \ + while (1) \ + { this_insn = read_memory_integer(pc, 4); \ + if (STW_P (this_insn)) /* stw */ \ + { regnum = GET_FIELD (this_insn, 11, 15); \ + if (!regnum) goto lose; \ + (frame_saved_regs).regs[regnum] = (frame_info)->frame + \ + extract_14 (this_insn); \ + pc += 4; \ + } \ + else if (ADDIL_P (this_insn)) /* addil */ \ + { int next_insn; \ + next_insn = read_memory_integer(pc + 4, 4); \ + if (STW_P (next_insn)) /* stw */ \ + { regnum = GET_FIELD (this_insn, 6, 10); \ + if (!regnum) goto lose; \ + (frame_saved_regs).regs[regnum] = (frame_info)->frame +\ + (extract_21 (this_insn) << 11) + extract_14 (next_insn);\ + pc += 8; \ + } \ + else \ + break; \ + } \ + else \ + { pc += 4; \ + break; \ + } \ + } \ + this_insn = read_memory_integer (pc, 4); \ + if (LDO_P (this_insn)) \ + { next_addr = (frame_info)->frame + extract_14 (this_insn); \ + pc += 4; \ + } \ + else if (ADDIL_P (this_insn)) \ + { next_addr = (frame_info)->frame + (extract_21 (this_insn) << 11)\ + + extract_14 (read_memory_integer (pc + 4, 4)); \ + pc += 8; \ + } \ + while (1) \ + { this_insn = read_memory_integer (pc, 4); \ + if ((this_insn & 0xfc001fe0) == 0x2c001220) /* fstds,ma */ \ + { regnum = GET_FIELD (this_insn, 27, 31); \ + (frame_saved_regs).regs[regnum + FP0_REGNUM] = next_addr; \ + next_addr += 8; \ + } \ + else \ + break; \ + } \ + lose: \ + (frame_saved_regs).regs[FP_REGNUM] = (frame_info)->frame; \ + (frame_saved_regs).regs[SP_REGNUM] = (frame_info)->frame -4; \ + }} + +/* Things needed for making the inferior call functions. */ + +/* Push an empty stack frame, to record the current PC, etc. */ + +#define PUSH_DUMMY_FRAME \ +{ register CORE_ADDR sp = read_register (SP_REGNUM); \ + register int regnum; \ + int int_buffer; \ + double freg_buffer; \ + /* Space for "arguments"; the RP goes in here. */ \ + sp += 48; \ + int_buffer = read_register (RP_REGNUM) | 0x3; \ + write_memory (sp - 20, &int_buffer, 4); \ + int_buffer = read_register (FP_REGNUM); \ + write_memory (sp, &int_buffer, 4); \ + write_register (FP_REGNUM, sp); \ + sp += 4; \ + for (regnum = 1; regnum < 31; regnum++) \ + if (regnum != RP_REGNUM && regnum != FP_REGNUM) \ + sp = push_word (sp, read_register (regnum)); \ + for (regnum = FP0_REGNUM; regnum < NUM_REGS; regnum++) \ + { read_register_bytes (REGISTER_BYTE (regnum), &freg_buffer, 8); \ + sp = push_bytes (sp, &freg_buffer, 8);} \ + sp = push_word (sp, read_register (IPSW_REGNUM)); \ + sp = push_word (sp, read_register (SAR_REGNUM)); \ + sp = push_word (sp, read_register (PCOQ_TAIL_REGNUM)); \ + sp = push_word (sp, read_register (PCSQ_TAIL_REGNUM)); \ + write_register (SP_REGNUM, sp);} + +/* Discard from the stack the innermost frame, + restoring all saved registers. */ +#define POP_FRAME \ +{ register FRAME frame = get_current_frame (); \ + register CORE_ADDR fp; \ + register int regnum; \ + struct frame_saved_regs fsr; \ + struct frame_info *fi; \ + double freg_buffer; \ + fi = get_frame_info (frame); \ + fp = fi->frame; \ + get_frame_saved_regs (fi, &fsr); \ + for (regnum = 31; regnum > 0; regnum--) \ + if (fsr.regs[regnum]) \ + write_register (regnum, read_memory_integer (fsr.regs[regnum], 4)); \ + for (regnum = NUM_REGS - 1; regnum >= FP0_REGNUM ; regnum--) \ + if (fsr.regs[regnum]) \ + { read_memory (fsr.regs[regnum], &freg_buffer, 8); \ + write_register_bytes (REGISTER_BYTE (regnum), &freg_buffer, 8); }\ + if (fsr.regs[IPSW_REGNUM]) \ + write_register (IPSW_REGNUM, \ + read_memory_integer (fsr.regs[IPSW_REGNUM], 4)); \ + if (fsr.regs[SAR_REGNUM]) \ + write_register (SAR_REGNUM, \ + read_memory_integer (fsr.regs[SAR_REGNUM], 4)); \ + if (fsr.regs[PCOQ_TAIL_REGNUM]) \ + write_register (PCOQ_TAIL_REGNUM, \ + read_memory_integer (fsr.regs[PCOQ_TAIL_REGNUM], 4));\ + if (fsr.regs[PCSQ_TAIL_REGNUM]) \ + write_register (PCSQ_TAIL_REGNUM, \ + read_memory_integer (fsr.regs[PCSQ_TAIL_REGNUM], 4));\ + write_register (FP_REGNUM, read_memory_integer (fp, 4)); \ + write_register (SP_REGNUM, fp + 8); \ + flush_cached_frames (); \ + set_current_frame (create_new_frame (read_register (FP_REGNUM),\ + read_pc ())); } + +/* This sequence of words is the instructions + +; Call stack frame has already been built by gdb. Since we could be calling +; a varargs function, and we do not have the benefit of a stub to put things in +; the right place, we load the first 4 word of arguments into both the general +; and fp registers. +call_dummy + ldw -36(sp), arg0 + ldw -40(sp), arg1 + ldw -44(sp), arg2 + ldw -48(sp), arg3 + ldo -36(sp), r1 + fldws 0(0, r1), fr4 + fldds -4(0, r1), fr5 + fldws -8(0, r1), fr6 + fldds -12(0, r1), fr7 + ldil 0, r22 ; target will be placed here. + ldo 0(r22), r22 + ldsid (0,r22), r3 + ldil 0, r1 ; _sr4export will be placed here. + ldo 0(r1), r1 + ldsid (0,r1), r4 + combt,=,n r3, r4, text_space ; If target is in data space, do a + ble 0(sr5, r22) ; "normal" procedure call + copy r31, r2 + break 4, 8 +text_space ; Otherwise, go through _sr4export, + ble (sr4, r1) ; which will return back here. + stw 31,-24(r30) + break 4, 8 + + The dummy decides if the target is in text space or data space. If + it's in data space, there's no problem because the target can + return back to the dummy. However, if the target is in text space, + the dummy calls the secret, undocumented routine _sr4export, which + calls a function in text space and can return to any space. Instead + of including fake instructions to represent saved registers, we + know that the frame is associated with the call dummy and treat it + specially. */ + +#define CALL_DUMMY { 0x4bda3fb9, 0x4bd93fb1, 0x4bd83fa9, 0x4bd73fa1, \ + 0x37c13fb9, 0x24201004, 0x2c391005, 0x24311006, \ + 0x2c291007, 0x22c00000, 0x36d60000, 0x02c010a3, \ + 0x20200000, 0x34210000, 0x002010a4, 0x80832012, \ + 0xe6c06000, 0x081f0242, 0x00010004, 0xe4202000, \ + 0x6bdf3fd1, 0x00010004} + +#define CALL_DUMMY_LENGTH 88 +#define CALL_DUMMY_START_OFFSET 0 +/* Insert the specified number of args and function address + into a call sequence of the above form stored at DUMMYNAME. */ + +#define FIX_CALL_DUMMY(dummyname, pc, fun, nargs, args, type, gcc_p) \ +{ static CORE_ADDR sr4export_address = 0; \ + \ + if (!sr4export_address) \ + { \ + struct minimal_symbol *msymbol; \ + msymbol = lookup_minimal_symbol ("_sr4export", (struct objfile *) NULL);\ + if (msymbol = NULL) \ + error ("Can't find an address for _sr4export trampoline"); \ + else \ + sr4export_address = msymbol -> address; \ + } \ + dummyname[9] = deposit_21 (fun >> 11, dummyname[9]); \ + dummyname[10] = deposit_14 (fun & MASK_11, dummyname[10]); \ + dummyname[12] = deposit_21 (sr4export_address >> 11, dummyname[12]); \ + dummyname[13] = deposit_14 (sr4export_address & MASK_11, dummyname[13]);\ +} + +/* Write the PC to a random value. + On PA-RISC, we need to be sure that the PC space queue is correct. */ + +#define WRITE_PC(addr) \ +{ int space_reg, space = ((addr) >> 30); \ + int space_val; \ + if (space == 0) \ + space_reg = 43; /* Space reg sr4 */ \ + else if (space == 1) \ + space_reg = 48; /* Space reg sr5*/ \ + else \ + error ("pc = %x is in illegal space.", addr); \ + space_val = read_register (space_reg); \ + write_register (PCOQ_HEAD_REGNUM, addr); \ + write_register (PCSQ_HEAD_REGNUM, space_val); \ + write_register (PCOQ_TAIL_REGNUM, addr); \ + write_register (PCSQ_TAIL_REGNUM, space_val);} + + + + + + diff --git a/gdb/xm-hppabsd.h b/gdb/xm-hppabsd.h new file mode 100644 index 00000000000..08ff5077f80 --- /dev/null +++ b/gdb/xm-hppabsd.h @@ -0,0 +1,49 @@ +/* Parameters for execution on a Hewlett-Packard PA-RISC machine, running + HPUX or BSD. + Copyright (C) 1986, 1987, 1989, 1990, 1991 Free Software Foundation, Inc. + + Contributed by the Center for Software Science at the + University of Utah (pa-gdb-bugs@cs.utah.edu). + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Describe the endian nature of this machine. */ +#define BITS_BIG_ENDIAN 1 +#define BYTES_BIG_ENDIAN 1 +#define WORDS_BIG_ENDIAN 1 + +/* 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 PUSH_ARGUMENTS(nargs, args, sp, struct_return, struct_addr) \ + sp = hp_push_arguments(nargs, args, sp, struct_return, struct_addr) + +#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 diff --git a/gdb/xm-hppahpux.h b/gdb/xm-hppahpux.h new file mode 100644 index 00000000000..5dce5605732 --- /dev/null +++ b/gdb/xm-hppahpux.h @@ -0,0 +1,50 @@ +/* Parameters for execution on a Hewlett-Packard PA-RISC machine, running + HPUX or BSD. + Copyright (C) 1986, 1987, 1989, 1990, 1991 Free Software Foundation, Inc. + + Contributed by the Center for Software Science at the + University of Utah (pa-gdb-bugs@cs.utah.edu). + +This file is part of GDB. + +GDB is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GDB is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GDB; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Describe the endian nature of this machine. */ +#define BITS_BIG_ENDIAN 1 +#define BYTES_BIG_ENDIAN 1 +#define WORDS_BIG_ENDIAN 1 + +/* 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 PUSH_ARGUMENTS(nargs, args, sp, struct_return, struct_addr) \ + sp = hp_push_arguments(nargs, args, sp, struct_return, struct_addr) + +#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 -- 2.30.2