* 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:
parent
9aa448333d
commit
7da1e27dd4
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
210
gdb/dbxread.c
210
gdb/dbxread.c
|
@ -41,6 +41,11 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|||
#define L_INCR 1
|
||||
#endif
|
||||
|
||||
#ifdef hp9000s800
|
||||
/* We don't want to use HP-UX's nlists. */
|
||||
#define _NLIST_INCLUDED
|
||||
#endif
|
||||
|
||||
#include <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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -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 *) ®isters[REGISTER_BYTE (regno) + i]);
|
||||
if (errno != 0)
|
||||
{
|
||||
sprintf (buf, "writing register number %d(%d)", regno, i);
|
||||
perror_with_name (buf);
|
||||
}
|
||||
regaddr += sizeof(int);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (regno = 0; regno < NUM_REGS; regno++)
|
||||
{
|
||||
if (CANNOT_STORE_REGISTER (regno))
|
||||
continue;
|
||||
regaddr = register_addr (regno, offset);
|
||||
for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(int))
|
||||
{
|
||||
errno = 0;
|
||||
ptrace (PT_WRITE_U, inferior_pid, (int *)regaddr,
|
||||
*(int *) ®isters[REGISTER_BYTE (regno) + i]);
|
||||
if (errno != 0)
|
||||
{
|
||||
sprintf (buf, "writing register number %d(%d)", regno, i);
|
||||
perror_with_name (buf);
|
||||
}
|
||||
regaddr += sizeof(int);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif /* !defined (FETCH_INFERIOR_REGISTERS). */
|
||||
|
||||
/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory
|
||||
in the NEW_SUN_PTRACE case.
|
||||
It ought to be straightforward. But it appears that writing did
|
||||
not write the data that I specified. I cannot understand where
|
||||
it got the data that it actually did write. */
|
||||
|
||||
/* Copy LEN bytes to or from inferior's memory starting at MEMADDR
|
||||
to debugger memory starting at MYADDR. Copy to inferior if
|
||||
WRITE is nonzero.
|
||||
|
||||
Returns the length copied, which is either the LEN argument or zero.
|
||||
This xfer function does not do partial moves, since child_ops
|
||||
doesn't allow memory operations to cross below us in the target stack
|
||||
anyway. */
|
||||
|
||||
int
|
||||
child_xfer_memory (memaddr, myaddr, len, write, target)
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
int len;
|
||||
int write;
|
||||
struct target_ops *target; /* ignored */
|
||||
{
|
||||
register int i;
|
||||
/* Round starting address down to longword boundary. */
|
||||
register CORE_ADDR addr = memaddr & - sizeof (int);
|
||||
/* Round ending address up; get number of longwords that makes. */
|
||||
register int count
|
||||
= (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
|
||||
/* Allocate buffer of that many longwords. */
|
||||
register int *buffer = (int *) alloca (count * sizeof (int));
|
||||
|
||||
if (write)
|
||||
{
|
||||
/* Fill start and end extra bytes of buffer with existing memory data. */
|
||||
|
||||
if (addr != memaddr || len < (int)sizeof (int)) {
|
||||
/* Need part of initial word -- fetch it. */
|
||||
buffer[0] = ptrace (PT_READ_I, inferior_pid, (int *)addr, 0);
|
||||
}
|
||||
|
||||
if (count > 1) /* FIXME, avoid if even boundary */
|
||||
{
|
||||
buffer[count - 1]
|
||||
= ptrace (PT_READ_I, inferior_pid,
|
||||
(int *)(addr + (count - 1) * sizeof (int)), 0);
|
||||
}
|
||||
|
||||
/* Copy data to be written over corresponding part of buffer */
|
||||
|
||||
bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len);
|
||||
|
||||
/* Write the entire buffer. */
|
||||
|
||||
for (i = 0; i < count; i++, addr += sizeof (int))
|
||||
{
|
||||
errno = 0;
|
||||
ptrace (PT_WRITE_D, inferior_pid, (int *)addr, buffer[i]);
|
||||
if (errno)
|
||||
{
|
||||
/* Using the appropriate one (I or D) is necessary for
|
||||
Gould NP1, at least. */
|
||||
errno = 0;
|
||||
ptrace (PT_WRITE_I, inferior_pid, (int *)addr, buffer[i]);
|
||||
}
|
||||
if (errno)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Read all the longwords */
|
||||
for (i = 0; i < count; i++, addr += sizeof (int))
|
||||
{
|
||||
errno = 0;
|
||||
buffer[i] = ptrace (PT_READ_I, inferior_pid, (int *)addr, 0);
|
||||
if (errno)
|
||||
return 0;
|
||||
QUIT;
|
||||
}
|
||||
|
||||
/* Copy appropriate bytes out of the buffer. */
|
||||
bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
|
@ -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 *) ®isters[REGISTER_BYTE (regno) + i], 0);
|
||||
if (errno != 0)
|
||||
{
|
||||
sprintf (buf, "writing register number %d(%d)", regno, i);
|
||||
perror_with_name (buf);
|
||||
}
|
||||
regaddr += sizeof(int);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (regno = 0; regno < NUM_REGS; regno++)
|
||||
{
|
||||
if (CANNOT_STORE_REGISTER (regno))
|
||||
continue;
|
||||
regaddr = register_addr (regno, offset);
|
||||
for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(int))
|
||||
{
|
||||
errno = 0;
|
||||
ptrace (PT_WUAREA, inferior_pid, (int *)regaddr,
|
||||
*(int *) ®isters[REGISTER_BYTE (regno) + i], 0);
|
||||
if (errno != 0)
|
||||
{
|
||||
sprintf (buf, "writing register number %d(%d)", regno, i);
|
||||
perror_with_name (buf);
|
||||
}
|
||||
regaddr += sizeof(int);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif /* !defined (FETCH_INFERIOR_REGISTERS). */
|
||||
|
||||
/* NOTE! I tried using PTRACE_READDATA, etc., to read and write memory
|
||||
in the NEW_SUN_PTRACE case.
|
||||
It ought to be straightforward. But it appears that writing did
|
||||
not write the data that I specified. I cannot understand where
|
||||
it got the data that it actually did write. */
|
||||
|
||||
/* Copy LEN bytes to or from inferior's memory starting at MEMADDR
|
||||
to debugger memory starting at MYADDR. Copy to inferior if
|
||||
WRITE is nonzero.
|
||||
|
||||
Returns the length copied, which is either the LEN argument or zero.
|
||||
This xfer function does not do partial moves, since child_ops
|
||||
doesn't allow memory operations to cross below us in the target stack
|
||||
anyway. */
|
||||
|
||||
int
|
||||
child_xfer_memory (memaddr, myaddr, len, write, target)
|
||||
CORE_ADDR memaddr;
|
||||
char *myaddr;
|
||||
int len;
|
||||
int write;
|
||||
struct target_ops *target; /* ignored */
|
||||
{
|
||||
register int i;
|
||||
/* Round starting address down to longword boundary. */
|
||||
register CORE_ADDR addr = memaddr & - sizeof (int);
|
||||
/* Round ending address up; get number of longwords that makes. */
|
||||
register int count
|
||||
= (((memaddr + len) - addr) + sizeof (int) - 1) / sizeof (int);
|
||||
/* Allocate buffer of that many longwords. */
|
||||
register int *buffer = (int *) alloca (count * sizeof (int));
|
||||
|
||||
if (write)
|
||||
{
|
||||
/* Fill start and end extra bytes of buffer with existing memory data. */
|
||||
|
||||
if (addr != memaddr || len < (int)sizeof (int)) {
|
||||
/* Need part of initial word -- fetch it. */
|
||||
buffer[0] = ptrace (PT_RIUSER, inferior_pid, (int *)addr, 0, 0);
|
||||
}
|
||||
|
||||
if (count > 1) /* FIXME, avoid if even boundary */
|
||||
{
|
||||
buffer[count - 1]
|
||||
= ptrace (PT_RIUSER, inferior_pid,
|
||||
(int *)(addr + (count - 1) * sizeof (int)), 0, 0);
|
||||
}
|
||||
|
||||
/* Copy data to be written over corresponding part of buffer */
|
||||
|
||||
bcopy (myaddr, (char *) buffer + (memaddr & (sizeof (int) - 1)), len);
|
||||
|
||||
/* Write the entire buffer. */
|
||||
|
||||
for (i = 0; i < count; i++, addr += sizeof (int))
|
||||
{
|
||||
errno = 0;
|
||||
ptrace (PT_WDUSER, inferior_pid, (int *)addr, buffer[i], 0);
|
||||
if (errno)
|
||||
{
|
||||
/* Using the appropriate one (I or D) is necessary for
|
||||
Gould NP1, at least. */
|
||||
errno = 0;
|
||||
ptrace (PT_WIUSER, inferior_pid, (int *)addr, buffer[i], 0);
|
||||
}
|
||||
if (errno)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Read all the longwords */
|
||||
for (i = 0; i < count; i++, addr += sizeof (int))
|
||||
{
|
||||
errno = 0;
|
||||
buffer[i] = ptrace (PT_RIUSER, inferior_pid, (int *)addr, 0, 0);
|
||||
if (errno)
|
||||
return 0;
|
||||
QUIT;
|
||||
}
|
||||
|
||||
/* Copy appropriate bytes out of the buffer. */
|
||||
bcopy ((char *) buffer + (memaddr & (sizeof (int) - 1)), myaddr, len);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int
|
||||
getpagesize()
|
||||
{
|
||||
return(4096);
|
||||
}
|
21
gdb/munch
21
gdb/munch
|
@ -23,12 +23,21 @@ if test "`$MUNCH_NM main.o | egrep main | egrep FUNC | egrep GLOB`" != "" ; then
|
|||
's/^.*\(_initialize_[a-zA-Z0-9_]*\).*$/ {extern void \1 (); \1 ();}/'\
|
||||
| sort -u
|
||||
elif test "`$MUNCH_NM main.o | egrep '[TD] _?main$'`" = "" ; then
|
||||
# System V style nm
|
||||
shift;
|
||||
$MUNCH_NM $* | egrep '_initialize_.*' | egrep '\.text'|\
|
||||
sed -e \
|
||||
's/^.*\(_initialize_[a-zA-Z0-9_]*\).*/ {extern void \1 (); \1 ();}/' \
|
||||
| sort -u
|
||||
if test "`$MUNCH_NM main.o | head -6 | egrep 'Subspace$'`" != "" ; then
|
||||
# HP PA RISC compilers don't prepend underscores
|
||||
shift;
|
||||
$MUNCH_NM $* | egrep '_initialize_.*' | \
|
||||
sed -e \
|
||||
's/^.*\(_initialize_[a-zA-Z0-9_]*\).*/ {extern void \1 (); \1 ();}/' \
|
||||
| sort -u
|
||||
else
|
||||
# System V style nm
|
||||
shift;
|
||||
$MUNCH_NM $* | egrep '_initialize_.*' | egrep '\.text'|\
|
||||
sed -e \
|
||||
's/^.*\(_initialize_[a-zA-Z0-9_]*\).*/ {extern void \1 (); \1 ();}/' \
|
||||
| sort -u
|
||||
fi
|
||||
else
|
||||
# BSD style nm
|
||||
# We now accept either text or data symbols, since the RT/PC uses data.
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
@ -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);}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue