* 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.
This commit is contained in:
Stu Grossman 1992-06-19 22:43:49 +00:00
parent 9aa448333d
commit 7da1e27dd4
16 changed files with 5959 additions and 8 deletions

View File

@ -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.

View File

@ -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

View File

@ -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 <obstack.h>
#include <sys/param.h>
#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);
}

121
gdb/hppa-coredep.c Normal file
View File

@ -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 <stdio.h>
/* These are needed on various systems to expand REGISTER_U_ADDR. */
#include <sys/types.h>
#include <sys/param.h>
#include <sys/dir.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/user.h>
#ifndef USG
#include <sys/ptrace.h>
#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 */

382
gdb/hppa-pinsn.c Normal file
View File

@ -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 <stdio.h>
#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<?!@-+&U>~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);
}

254
gdb/hppabsd-core.c Normal file
View File

@ -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 <stdio.h>
#include "defs.h"
#include "param.h"
#include "frame.h"
#include "inferior.h"
#ifdef USG
#include <sys/types.h>
#endif
#include <sys/param.h>
#include <sys/dir.h>
#include <signal.h>
#include <sys/ioctl.h>
/* #include <fcntl.h> Can we live without this? */
#ifndef hpux
#include <a.out.h>
#include <machine/pcb.h>
#include <sys/time.h>
#include "/usr/src/sys/hpux/hpux.h"
#define USRSTACK 0x68FF3000
#else
#include <sys/user.h> /* After a.out.h */
#endif
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/ptrace.h>
#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");
}

1428
gdb/hppabsd-tdep.c Normal file

File diff suppressed because it is too large Load Diff

417
gdb/hppabsd-xdep.c Normal file
View File

@ -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 <stdio.h>
#include "defs.h"
#include "frame.h"
#include "inferior.h"
#include "target.h"
#ifdef USG
#include <sys/types.h>
#endif
#include <sys/param.h>
#include <sys/dir.h>
#include <signal.h>
#include <sys/ioctl.h>
#ifndef USG
#include <sys/ptrace.h>
#endif
#ifndef PT_ATTACH
#define PT_ATTACH PTRACE_ATTACH
#endif
#ifndef PT_DETACH
#define PT_DETACH PTRACE_DETACH
#endif
#include "gdbcore.h"
#include <sys/user.h> /* After a.out.h */
#include <sys/file.h>
#include <sys/stat.h>
/* This function simply calls ptrace with the given arguments.
It exists so that all calls to ptrace are isolated in this
machine-dependent file. */
int
call_ptrace (request, pid, addr, data)
int request, pid, *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 <a.out.gnu.h> /* 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 *) &registers[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 *) &registers[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;
}

1432
gdb/hppahpux-tdep.c Normal file

File diff suppressed because it is too large Load Diff

421
gdb/hppahpux-xdep.c Normal file
View File

@ -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 <stdio.h>
#include "defs.h"
#include "frame.h"
#include "inferior.h"
#include "target.h"
#ifdef USG
#include <sys/types.h>
#endif
#include <sys/param.h>
#include <sys/dir.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/ptrace.h>
#ifndef PT_ATTACH
#define PT_ATTACH PTRACE_ATTACH
#endif
#ifndef PT_DETACH
#define PT_DETACH PTRACE_DETACH
#endif
#include "gdbcore.h"
#include <sys/user.h> /* After a.out.h */
#include <sys/file.h>
#include <sys/stat.h>
/* This function simply calls ptrace with the given arguments.
It exists so that all calls to ptrace are isolated in this
machine-dependent file. */
int
call_ptrace (request, pid, addr, data)
int request, pid, *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 <a.out.gnu.h> /* 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 *) &registers[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 *) &registers[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);
}

View File

@ -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.

View File

@ -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. */

570
gdb/tm-hppabsd.h Normal file
View File

@ -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 */

576
gdb/tm-hppahpux.h Normal file
View File

@ -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);}

49
gdb/xm-hppabsd.h Normal file
View File

@ -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 <machine/machtypes.h> 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

50
gdb/xm-hppahpux.h Normal file
View File

@ -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 <machine/machtypes.h> 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