* Merge in HPPA/BSD patches from Utah:

* defs.h:  Add const to 2nd arg of psignal prototype.
	* hppah-tdep.c:  Renamed to hppa-tdep.c 'cuz it's common code with
	BSD now.
	* hppab-core.c:  Deleted.  No longer useful.
	* hppab-nat.c:  #include more files.  Use PT_WUREGS, not
	PT_WRITE_U.
	* hppab-tdep.c:  Deleted.  Supplanted by hppa-tdep.c.
	* config/pa/hppabsd.mh (NATDEPFILES):  Remove hppab-core.o.
	* config/pa/hppabsd.mt (TDEPFILES):  hppab-tdep.o => hppa-tdep.o
	* config/pa/hppahpux.mt (TDEPFILES):  hppab-tdep.o => hppa-tdep.o
	* config/pa/xm-hppab.h:  #define SET_STACK_LIMIT_HUGE.
This commit is contained in:
Stu Grossman 1993-04-23 23:43:18 +00:00
parent b5728692b4
commit 66a1aa071e
10 changed files with 963 additions and 2618 deletions

View file

@ -107,11 +107,9 @@ h8300-tdep.c
h8500-tdep.c
hp300ux-nat.c
hppa-pinsn.c
hppab-core.c
hppa-tdep.c
hppab-nat.c
hppab-tdep.c
hppah-nat.c
hppah-tdep.c
i386-pinsn.c
i386-stub.c
i386-tdep.c

View file

@ -1,3 +1,18 @@
Fri Apr 23 16:17:00 1993 Stu Grossman (grossman@cygnus.com)
* Merge in HPPA/BSD patches from Utah:
* defs.h: Add const to 2nd arg of psignal prototype.
* hppah-tdep.c: Renamed to hppa-tdep.c 'cuz it's common code with
BSD now.
* hppab-core.c: Deleted. No longer useful.
* hppab-nat.c: #include more files. Use PT_WUREGS, not
PT_WRITE_U.
* hppab-tdep.c: Deleted. Supplanted by hppa-tdep.c.
* config/pa/hppabsd.mh (NATDEPFILES): Remove hppab-core.o.
* config/pa/hppabsd.mt (TDEPFILES): hppab-tdep.o => hppa-tdep.o
* config/pa/hppahpux.mt (TDEPFILES): hppab-tdep.o => hppa-tdep.o
* config/pa/xm-hppab.h: #define SET_STACK_LIMIT_HUGE.
Fri Apr 23 10:34:02 1993 Stu Grossman (grossman@cygnus.com)
* Fix two bugs found by deja-gnu. One is the incorrect reporting

View file

@ -2,4 +2,4 @@
XDEPFILES=
XM_FILE= xm-hppab.h
NAT_FILE= nm-hppab.h
NATDEPFILES= hppab-nat.o coredep.o corelow.o exec.o hppab-core.o
NATDEPFILES= hppab-nat.o coredep.o corelow.o exec.o

View file

@ -1,4 +1,4 @@
# TARGET: HP PA-RISC running bsd
TDEPFILES= hppa-pinsn.o hppab-tdep.o
TDEPFILES= hppa-pinsn.o hppa-tdep.o
TM_FILE= tm-hppab.h

View file

@ -40,3 +40,5 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
# 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 */
#define SET_STACK_LIMIT_HUGE

938
gdb/hppa-tdep.c Normal file
View file

@ -0,0 +1,938 @@
/* Machine-dependent code which would otherwise be in inflow.c and core.c,
for GDB, the GNU debugger. This code is for the HP PA-RISC cpu.
Copyright 1986, 1987, 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
Contributed by the Center for Software Science at the
University of Utah (pa-gdb-bugs@cs.utah.edu).
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "defs.h"
#include "frame.h"
#include "inferior.h"
#include "value.h"
/* For argument passing to the inferior */
#include "symtab.h"
#ifdef USG
#include <sys/types.h>
#endif
#include <sys/param.h>
#include <sys/dir.h>
#include <signal.h>
#include <sys/ioctl.h>
#ifdef COFF_ENCAPSULATE
#include "a.out.encap.h"
#else
#include <a.out.h>
#endif
#ifndef N_SET_MAGIC
#define N_SET_MAGIC(exec, val) ((exec).a_magic = (val))
#endif
/*#include <sys/user.h> After a.out.h */
#include <sys/file.h>
#include <sys/stat.h>
#include <machine/psl.h>
#include "wait.h"
#include "gdbcore.h"
#include "gdbcmd.h"
#include "target.h"
#include "symfile.h"
#include "objfiles.h"
static int restore_pc_queue PARAMS ((struct frame_saved_regs *fsr));
static int hppa_alignof PARAMS ((struct type *arg));
/* Routines to extract various sized constants out of hppa
instructions. */
/* This assumes that no garbage lies outside of the lower bits of
value. */
int
sign_extend (val, bits)
unsigned val, bits;
{
return (int)(val >> bits - 1 ? (-1 << bits) | val : val);
}
/* For many immediate values the sign bit is the low bit! */
int
low_sign_extend (val, bits)
unsigned val, bits;
{
return (int)((val & 0x1 ? (-1 << (bits - 1)) : 0) | val >> 1);
}
/* extract the immediate field from a ld{bhw}s instruction */
unsigned
get_field (val, from, to)
unsigned val, from, to;
{
val = val >> 31 - to;
return val & ((1 << 32 - from) - 1);
}
unsigned
set_field (val, from, to, new_val)
unsigned *val, from, to;
{
unsigned mask = ~((1 << (to - from + 1)) << (31 - from));
return *val = *val & mask | (new_val << (31 - from));
}
/* extract a 3-bit space register number from a be, ble, mtsp or mfsp */
extract_3 (word)
unsigned word;
{
return GET_FIELD (word, 18, 18) << 2 | GET_FIELD (word, 16, 17);
}
extract_5_load (word)
unsigned word;
{
return low_sign_extend (word >> 16 & MASK_5, 5);
}
/* extract the immediate field from a st{bhw}s instruction */
int
extract_5_store (word)
unsigned word;
{
return low_sign_extend (word & MASK_5, 5);
}
/* extract an 11 bit immediate field */
int
extract_11 (word)
unsigned word;
{
return low_sign_extend (word & MASK_11, 11);
}
/* extract a 14 bit immediate field */
int
extract_14 (word)
unsigned word;
{
return low_sign_extend (word & MASK_14, 14);
}
/* deposit a 14 bit constant in a word */
unsigned
deposit_14 (opnd, word)
int opnd;
unsigned word;
{
unsigned sign = (opnd < 0 ? 1 : 0);
return word | ((unsigned)opnd << 1 & MASK_14) | sign;
}
/* extract a 21 bit constant */
int
extract_21 (word)
unsigned word;
{
int val;
word &= MASK_21;
word <<= 11;
val = GET_FIELD (word, 20, 20);
val <<= 11;
val |= GET_FIELD (word, 9, 19);
val <<= 2;
val |= GET_FIELD (word, 5, 6);
val <<= 5;
val |= GET_FIELD (word, 0, 4);
val <<= 2;
val |= GET_FIELD (word, 7, 8);
return sign_extend (val, 21) << 11;
}
/* deposit a 21 bit constant in a word. Although 21 bit constants are
usually the top 21 bits of a 32 bit constant, we assume that only
the low 21 bits of opnd are relevant */
unsigned
deposit_21 (opnd, word)
unsigned opnd, word;
{
unsigned val = 0;
val |= GET_FIELD (opnd, 11 + 14, 11 + 18);
val <<= 2;
val |= GET_FIELD (opnd, 11 + 12, 11 + 13);
val <<= 2;
val |= GET_FIELD (opnd, 11 + 19, 11 + 20);
val <<= 11;
val |= GET_FIELD (opnd, 11 + 1, 11 + 11);
val <<= 1;
val |= GET_FIELD (opnd, 11 + 0, 11 + 0);
return word | val;
}
/* extract a 12 bit constant from branch instructions */
int
extract_12 (word)
unsigned word;
{
return sign_extend (GET_FIELD (word, 19, 28) |
GET_FIELD (word, 29, 29) << 10 |
(word & 0x1) << 11, 12) << 2;
}
/* extract a 17 bit constant from branch instructions, returning the
19 bit signed value. */
int
extract_17 (word)
unsigned word;
{
return sign_extend (GET_FIELD (word, 19, 28) |
GET_FIELD (word, 29, 29) << 10 |
GET_FIELD (word, 11, 15) << 11 |
(word & 0x1) << 16, 17) << 2;
}
static int use_unwind = 0;
/* Lookup the unwind (stack backtrace) info for the given PC. We search all
of the objfiles seeking the unwind table entry for this PC. Each objfile
contains a sorted list of struct unwind_table_entry. Since we do a binary
search of the unwind tables, we depend upon them to be sorted. */
static struct unwind_table_entry *
find_unwind_entry(pc)
CORE_ADDR pc;
{
int first, middle, last;
struct objfile *objfile;
ALL_OBJFILES (objfile)
{
struct obj_unwind_info *ui;
ui = OBJ_UNWIND_INFO (objfile);
if (!ui)
continue;
/* First, check the cache */
if (ui->cache
&& pc >= ui->cache->region_start
&& pc <= ui->cache->region_end)
return ui->cache;
/* Not in the cache, do a binary search */
first = 0;
last = ui->last;
while (first <= last)
{
middle = (first + last) / 2;
if (pc >= ui->table[middle].region_start
&& pc <= ui->table[middle].region_end)
{
ui->cache = &ui->table[middle];
return &ui->table[middle];
}
if (pc < ui->table[middle].region_start)
last = middle - 1;
else
first = middle + 1;
}
} /* ALL_OBJFILES() */
return NULL;
}
static int
find_return_regnum(pc)
CORE_ADDR pc;
{
struct unwind_table_entry *u;
u = find_unwind_entry (pc);
if (!u)
return RP_REGNUM;
if (u->Millicode)
return 31;
return RP_REGNUM;
}
int
find_proc_framesize(pc)
CORE_ADDR pc;
{
struct unwind_table_entry *u;
if (!use_unwind)
return -1;
u = find_unwind_entry (pc);
if (!u)
return -1;
return u->Total_frame_size << 3;
}
int
rp_saved(pc)
{
struct unwind_table_entry *u;
u = find_unwind_entry (pc);
if (!u)
return 0;
if (u->Save_RP)
return 1;
else
return 0;
}
CORE_ADDR
saved_pc_after_call (frame)
FRAME frame;
{
int ret_regnum;
ret_regnum = find_return_regnum (get_frame_pc (frame));
return read_register (ret_regnum) & ~0x3;
}
CORE_ADDR
frame_saved_pc (frame)
FRAME frame;
{
CORE_ADDR pc = get_frame_pc (frame);
if (frameless_look_for_prologue (frame))
{
int ret_regnum;
ret_regnum = find_return_regnum (pc);
return read_register (ret_regnum) & ~0x3;
}
else if (rp_saved (pc))
return read_memory_integer (frame->frame - 20, 4) & ~0x3;
else
return read_register (RP_REGNUM) & ~0x3;
}
/* We need to correct the PC and the FP for the outermost frame when we are
in a system call. */
void
init_extra_frame_info (fromleaf, frame)
int fromleaf;
struct frame_info *frame;
{
int flags;
int framesize;
if (frame->next) /* Only do this for outermost frame */
return;
flags = read_register (FLAGS_REGNUM);
if (flags & 2) /* In system call? */
frame->pc = read_register (31) & ~0x3;
/* The outermost frame is always derived from PC-framesize */
framesize = find_proc_framesize(frame->pc);
if (framesize == -1)
frame->frame = read_register (FP_REGNUM);
else
frame->frame = read_register (SP_REGNUM) - framesize;
if (!frameless_look_for_prologue (frame)) /* Frameless? */
return; /* No, quit now */
/* For frameless functions, we need to look at the caller's frame */
framesize = find_proc_framesize(FRAME_SAVED_PC(frame));
if (framesize != -1)
frame->frame -= framesize;
}
FRAME_ADDR
frame_chain (frame)
struct frame_info *frame;
{
int framesize;
framesize = find_proc_framesize(FRAME_SAVED_PC(frame));
if (framesize != -1)
return frame->frame - framesize;
return read_memory_integer (frame->frame, 4);
}
/* To see if a frame chain is valid, see if the caller looks like it
was compiled with gcc. */
int
frame_chain_valid (chain, thisframe)
FRAME_ADDR chain;
FRAME thisframe;
{
struct minimal_symbol *msym;
if (!chain)
return 0;
msym = lookup_minimal_symbol_by_pc (FRAME_SAVED_PC (thisframe));
if (msym
&& (strcmp (SYMBOL_NAME (msym), "_start") == 0))
return 0;
else
return 1;
}
#if 0
/* Some helper functions. gcc_p returns 1 if the function beginning at
pc appears to have been compiled with gcc. hpux_cc_p returns 1 if
fn was compiled with hpux cc. gcc functions look like :
stw rp,-0x14(sp) ; optional
or r4,r0,r1
or sp,r0,r4
stwm r1,framesize(sp)
hpux cc functions look like:
stw rp,-0x14(sp) ; optional.
stwm r3,framesiz(sp)
*/
gcc_p (pc)
CORE_ADDR pc;
{
if (read_memory_integer (pc, 4) == 0x6BC23FD9)
pc = pc + 4;
if (read_memory_integer (pc, 4) == 0x8040241
&& read_memory_integer (pc + 4, 4) == 0x81E0244)
return 1;
return 0;
}
#endif
/*
* These functions deal with saving and restoring register state
* around a function call in the inferior. They keep the stack
* double-word aligned; eventually, on an hp700, the stack will have
* to be aligned to a 64-byte boundary.
*/
int
push_dummy_frame ()
{
register CORE_ADDR sp;
register int regnum;
int int_buffer;
double freg_buffer;
/* Space for "arguments"; the RP goes in here. */
sp = read_register (SP_REGNUM) + 48;
int_buffer = read_register (RP_REGNUM) | 0x3;
write_memory (sp - 20, (char *)&int_buffer, 4);
int_buffer = read_register (FP_REGNUM);
write_memory (sp, (char *)&int_buffer, 4);
write_register (FP_REGNUM, sp);
sp += 8;
for (regnum = 1; regnum < 32; regnum++)
if (regnum != RP_REGNUM && regnum != FP_REGNUM)
sp = push_word (sp, read_register (regnum));
sp += 4;
for (regnum = FP0_REGNUM; regnum < NUM_REGS; regnum++)
{
read_register_bytes (REGISTER_BYTE (regnum), (char *)&freg_buffer, 8);
sp = push_bytes (sp, (char *)&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_HEAD_REGNUM));
sp = push_word (sp, read_register (PCSQ_HEAD_REGNUM));
sp = push_word (sp, read_register (PCOQ_TAIL_REGNUM));
sp = push_word (sp, read_register (PCSQ_TAIL_REGNUM));
write_register (SP_REGNUM, sp);
}
find_dummy_frame_regs (frame, frame_saved_regs)
struct frame_info *frame;
struct frame_saved_regs *frame_saved_regs;
{
CORE_ADDR fp = frame->frame;
int i;
frame_saved_regs->regs[RP_REGNUM] = fp - 20 & ~0x3;
frame_saved_regs->regs[FP_REGNUM] = fp;
frame_saved_regs->regs[1] = fp + 8;
frame_saved_regs->regs[3] = fp + 12;
for (fp += 16, i = 5; i < 32; fp += 4, i++)
frame_saved_regs->regs[i] = fp;
fp += 4;
for (i = FP0_REGNUM; i < NUM_REGS; i++, fp += 8)
frame_saved_regs->regs[i] = fp;
frame_saved_regs->regs[IPSW_REGNUM] = fp;
fp += 4;
frame_saved_regs->regs[SAR_REGNUM] = fp;
fp += 4;
frame_saved_regs->regs[PCOQ_HEAD_REGNUM] = fp;
fp +=4;
frame_saved_regs->regs[PCSQ_HEAD_REGNUM] = fp;
fp +=4;
frame_saved_regs->regs[PCOQ_TAIL_REGNUM] = fp;
fp +=4;
frame_saved_regs->regs[PCSQ_TAIL_REGNUM] = fp;
}
int
hppa_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);
if (fsr.regs[IPSW_REGNUM]) /* Restoring a call dummy frame */
restore_pc_queue (&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], (char *)&freg_buffer, 8);
write_register_bytes (REGISTER_BYTE (regnum), (char *)&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));
write_register (FP_REGNUM, read_memory_integer (fp, 4));
if (fsr.regs[IPSW_REGNUM]) /* call dummy */
write_register (SP_REGNUM, fp - 48);
else
write_register (SP_REGNUM, fp);
flush_cached_frames ();
set_current_frame (create_new_frame (read_register (FP_REGNUM),
read_pc ()));
}
/*
* After returning to a dummy on the stack, restore the instruction
* queue space registers. */
static int
restore_pc_queue (fsr)
struct frame_saved_regs *fsr;
{
CORE_ADDR pc = read_pc ();
CORE_ADDR new_pc = read_memory_integer (fsr->regs[PCOQ_HEAD_REGNUM], 4);
int pid;
WAITTYPE w;
int insn_count;
/* Advance past break instruction in the call dummy. */
write_register (PCOQ_HEAD_REGNUM, pc + 4);
write_register (PCOQ_TAIL_REGNUM, pc + 8);
/*
* HPUX doesn't let us set the space registers or the space
* registers of the PC queue through ptrace. Boo, hiss.
* Conveniently, the call dummy has this sequence of instructions
* after the break:
* mtsp r21, sr0
* ble,n 0(sr0, r22)
*
* So, load up the registers and single step until we are in the
* right place.
*/
write_register (21, read_memory_integer (fsr->regs[PCSQ_HEAD_REGNUM], 4));
write_register (22, new_pc);
for (insn_count = 0; insn_count < 3; insn_count++)
{
resume (1, 0);
target_wait(&w);
if (!WIFSTOPPED (w))
{
stop_signal = WTERMSIG (w);
terminal_ours_for_output ();
printf ("\nProgram terminated with signal %d, %s\n",
stop_signal, safe_strsignal (stop_signal));
fflush (stdout);
return 0;
}
}
fetch_inferior_registers (-1);
return 1;
}
CORE_ADDR
hppa_push_arguments (nargs, args, sp, struct_return, struct_addr)
int nargs;
value *args;
CORE_ADDR sp;
int struct_return;
CORE_ADDR struct_addr;
{
/* array of arguments' offsets */
int *offset = (int *)alloca(nargs);
int cum = 0;
int i, alignment;
for (i = 0; i < nargs; i++)
{
/* Coerce chars to int & float to double if necessary */
args[i] = value_arg_coerce (args[i]);
cum += TYPE_LENGTH (VALUE_TYPE (args[i]));
/* value must go at proper alignment. Assume alignment is a
power of two.*/
alignment = hppa_alignof (VALUE_TYPE (args[i]));
if (cum % alignment)
cum = (cum + alignment) & -alignment;
offset[i] = -cum;
}
sp += min ((cum + 7) & -8, 16);
for (i = 0; i < nargs; i++)
write_memory (sp + offset[i], VALUE_CONTENTS (args[i]),
TYPE_LENGTH (VALUE_TYPE (args[i])));
if (struct_return)
write_register (28, struct_addr);
return sp + 32;
}
/*
* Insert the specified number of args and function address
* into a call sequence of the above form stored at DUMMYNAME.
*
* On the hppa we need to call the stack dummy through $$dyncall.
* Therefore our version of FIX_CALL_DUMMY takes an extra argument,
* real_pc, which is the location where gdb should start up the
* inferior to do the function call.
*/
CORE_ADDR
hppa_fix_call_dummy (dummy, pc, fun, nargs, args, type, gcc_p)
REGISTER_TYPE *dummy;
CORE_ADDR pc;
CORE_ADDR fun;
int nargs;
value *args;
struct type *type;
int gcc_p;
{
CORE_ADDR dyncall_addr, sr4export_addr;
struct minimal_symbol *msymbol;
msymbol = lookup_minimal_symbol ("$$dyncall", (struct objfile *) NULL);
if (msymbol == NULL)
error ("Can't find an address for $$dyncall trampoline");
dyncall_addr = SYMBOL_VALUE_ADDRESS (msymbol);
msymbol = lookup_minimal_symbol ("_sr4export", (struct objfile *) NULL);
if (msymbol == NULL)
error ("Can't find an address for _sr4export trampoline");
sr4export_addr = SYMBOL_VALUE_ADDRESS (msymbol);
dummy[9] = deposit_21 (fun >> 11, dummy[9]);
dummy[10] = deposit_14 (fun & MASK_11, dummy[10]);
dummy[12] = deposit_21 (sr4export_addr >> 11, dummy[12]);
dummy[13] = deposit_14 (sr4export_addr & MASK_11, dummy[13]);
write_register (22, pc);
return dyncall_addr;
}
/* return the alignment of a type in bytes. Structures have the maximum
alignment required by their fields. */
static int
hppa_alignof (arg)
struct type *arg;
{
int max_align, align, i;
switch (TYPE_CODE (arg))
{
case TYPE_CODE_PTR:
case TYPE_CODE_INT:
case TYPE_CODE_FLT:
return TYPE_LENGTH (arg);
case TYPE_CODE_ARRAY:
return hppa_alignof (TYPE_FIELD_TYPE (arg, 0));
case TYPE_CODE_STRUCT:
case TYPE_CODE_UNION:
max_align = 2;
for (i = 0; i < TYPE_NFIELDS (arg); i++)
{
/* Bit fields have no real alignment. */
if (!TYPE_FIELD_BITPOS (arg, i))
{
align = hppa_alignof (TYPE_FIELD_TYPE (arg, i));
max_align = max (max_align, align);
}
}
return max_align;
default:
return 4;
}
}
/* Print the register regnum, or all registers if regnum is -1 */
pa_do_registers_info (regnum, fpregs)
int regnum;
int fpregs;
{
char raw_regs [REGISTER_BYTES];
int i;
for (i = 0; i < NUM_REGS; i++)
read_relative_register_raw_bytes (i, raw_regs + REGISTER_BYTE (i));
if (regnum == -1)
pa_print_registers (raw_regs, regnum, fpregs);
else if (regnum < FP0_REGNUM)
printf ("%s %x\n", reg_names[regnum], *(long *)(raw_regs +
REGISTER_BYTE (regnum)));
else
pa_print_fp_reg (regnum);
}
pa_print_registers (raw_regs, regnum, fpregs)
char *raw_regs;
int regnum;
int fpregs;
{
int i;
for (i = 0; i < 18; i++)
printf ("%8.8s: %8x %8.8s: %8x %8.8s: %8x %8.8s: %8x\n",
reg_names[i],
*(int *)(raw_regs + REGISTER_BYTE (i)),
reg_names[i + 18],
*(int *)(raw_regs + REGISTER_BYTE (i + 18)),
reg_names[i + 36],
*(int *)(raw_regs + REGISTER_BYTE (i + 36)),
reg_names[i + 54],
*(int *)(raw_regs + REGISTER_BYTE (i + 54)));
if (fpregs)
for (i = 72; i < NUM_REGS; i++)
pa_print_fp_reg (i);
}
pa_print_fp_reg (i)
int i;
{
unsigned char raw_buffer[MAX_REGISTER_RAW_SIZE];
unsigned char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
REGISTER_TYPE val;
/* Get the data in raw format, then convert also to virtual format. */
read_relative_register_raw_bytes (i, raw_buffer);
REGISTER_CONVERT_TO_VIRTUAL (i, raw_buffer, virtual_buffer);
fputs_filtered (reg_names[i], stdout);
print_spaces_filtered (15 - strlen (reg_names[i]), stdout);
val_print (REGISTER_VIRTUAL_TYPE (i), virtual_buffer, 0, stdout, 0,
1, 0, Val_pretty_default);
printf_filtered ("\n");
}
/* Function calls that pass into a new compilation unit must pass through a
small piece of code that does long format (`external' in HPPA parlance)
jumps. We figure out where the trampoline is going to end up, and return
the PC of the final destination. If we aren't in a trampoline, we just
return NULL.
For computed calls, we just extract the new PC from r22. */
CORE_ADDR
skip_trampoline_code (pc, name)
CORE_ADDR pc;
char *name;
{
long inst0, inst1;
static CORE_ADDR dyncall = 0;
struct minimal_symbol *msym;
/* FIXME XXX - dyncall must be initialized whenever we get a new exec file */
if (!dyncall)
{
msym = lookup_minimal_symbol ("$$dyncall", NULL);
if (msym)
dyncall = SYMBOL_VALUE_ADDRESS (msym);
else
dyncall = -1;
}
if (pc == dyncall)
return (CORE_ADDR)(read_register (22) & ~0x3);
inst0 = read_memory_integer (pc, 4);
inst1 = read_memory_integer (pc+4, 4);
if ( (inst0 & 0xffe00000) == 0x20200000 /* ldil xxx, r1 */
&& (inst1 & 0xffe0e002) == 0xe0202002) /* be,n yyy(sr4, r1) */
pc = extract_21 (inst0) + extract_17 (inst1);
else
pc = (CORE_ADDR)NULL;
return pc;
}
/* 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 */
CORE_ADDR
skip_prologue(pc)
CORE_ADDR pc;
{
int inst;
int status;
status = target_read_memory (pc, (char *)&inst, 4);
SWAP_TARGET_AND_HOST (&inst, sizeof (inst));
if (status != 0)
return pc;
if (inst == 0x6BC23FD9) /* stw rp,-20(sp) */
{
if (read_memory_integer (pc + 4, 4) == 0x8040241) /* copy r4,r1 */
pc += 16;
else if ((read_memory_integer (pc + 4, 4) & ~MASK_14) == 0x68810000) /* stw r1,(r4) */
pc += 8;
}
else if (read_memory_integer (pc, 4) == 0x8040241) /* copy r4,r1 */
pc += 12;
else if ((read_memory_integer (pc, 4) & ~MASK_14) == 0x68810000) /* stw r1,(r4) */
pc += 4;
return pc;
}
static void
unwind_command (exp, from_tty)
char *exp;
int from_tty;
{
CORE_ADDR address;
union
{
int *foo;
struct unwind_table_entry *u;
} xxx;
/* If we have an expression, evaluate it and use it as the address. */
if (exp != 0 && *exp != 0)
address = parse_and_eval_address (exp);
else
return;
xxx.u = find_unwind_entry (address);
if (!xxx.u)
{
printf ("Can't find unwind table entry for PC 0x%x\n", address);
return;
}
printf ("%08x\n%08X\n%08X\n%08X\n", xxx.foo[0], xxx.foo[1], xxx.foo[2],
xxx.foo[3]);
}
void
_initialize_hppah_tdep ()
{
add_com ("unwind", class_obscure, unwind_command, "Print unwind info\n");
add_show_from_set
(add_set_cmd ("use_unwind", class_obscure, var_boolean,
(char *)&use_unwind,
"Set the usage of unwind info", &setlist),
&showlist);
}

View file

@ -1,251 +0,0 @@
/* Machine-dependent code which would otherwise be in core.c
for GDB, the GNU debugger. This code is for the HP PA-RISC cpu.
Copyright 1986, 1987, 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
Contributed by the Center for Software Science at the
University of Utah (pa-gdb-bugs@cs.utah.edu).
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "defs.h"
#include "frame.h"
#include "inferior.h"
#ifdef USG
#include <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");
}

View file

@ -1,7 +1,7 @@
/* Machine-dependent hooks for the unix child process stratum. This
code is for the HP PA-RISC cpu.
Copyright 1986, 1987, 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
Copyright 1986, 1987, 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
Contributed by the Center for Software Science at the
University of Utah (pa-gdb-bugs@cs.utah.edu).
@ -24,6 +24,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "defs.h"
#include "inferior.h"
#include "target.h"
#include <sys/ptrace.h>
#ifndef PT_ATTACH
#define PT_ATTACH PTRACE_ATTACH
@ -239,7 +241,7 @@ store_inferior_registers (regno)
for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(int))
{
errno = 0;
ptrace (PT_WRITE_U, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
ptrace (PT_WUREGS, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
*(int *) &registers[REGISTER_BYTE (regno) + i]);
if (errno != 0)
{
@ -259,7 +261,7 @@ store_inferior_registers (regno)
for (i = 0; i < REGISTER_RAW_SIZE (regno); i += sizeof(int))
{
errno = 0;
ptrace (PT_WRITE_U, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
ptrace (PT_WUREGS, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
*(int *) &registers[REGISTER_BYTE (regno) + i]);
if (errno != 0)
{

File diff suppressed because it is too large Load diff

View file

@ -1,938 +0,0 @@
/* Machine-dependent code which would otherwise be in inflow.c and core.c,
for GDB, the GNU debugger. This code is for the HP PA-RISC cpu.
Copyright 1986, 1987, 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
Contributed by the Center for Software Science at the
University of Utah (pa-gdb-bugs@cs.utah.edu).
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "defs.h"
#include "frame.h"
#include "inferior.h"
#include "value.h"
/* For argument passing to the inferior */
#include "symtab.h"
#ifdef USG
#include <sys/types.h>
#endif
#include <sys/param.h>
#include <sys/dir.h>
#include <signal.h>
#include <sys/ioctl.h>
#ifdef COFF_ENCAPSULATE
#include "a.out.encap.h"
#else
#include <a.out.h>
#endif
#ifndef N_SET_MAGIC
#define N_SET_MAGIC(exec, val) ((exec).a_magic = (val))
#endif
/*#include <sys/user.h> After a.out.h */
#include <sys/file.h>
#include <sys/stat.h>
#include <machine/psl.h>
#include "wait.h"
#include "gdbcore.h"
#include "gdbcmd.h"
#include "target.h"
#include "symfile.h"
#include "objfiles.h"
static int restore_pc_queue PARAMS ((struct frame_saved_regs *fsr));
static int hppa_alignof PARAMS ((struct type *arg));
/* Routines to extract various sized constants out of hppa
instructions. */
/* This assumes that no garbage lies outside of the lower bits of
value. */
int
sign_extend (val, bits)
unsigned val, bits;
{
return (int)(val >> bits - 1 ? (-1 << bits) | val : val);
}
/* For many immediate values the sign bit is the low bit! */
int
low_sign_extend (val, bits)
unsigned val, bits;
{
return (int)((val & 0x1 ? (-1 << (bits - 1)) : 0) | val >> 1);
}
/* extract the immediate field from a ld{bhw}s instruction */
unsigned
get_field (val, from, to)
unsigned val, from, to;
{
val = val >> 31 - to;
return val & ((1 << 32 - from) - 1);
}
unsigned
set_field (val, from, to, new_val)
unsigned *val, from, to;
{
unsigned mask = ~((1 << (to - from + 1)) << (31 - from));
return *val = *val & mask | (new_val << (31 - from));
}
/* extract a 3-bit space register number from a be, ble, mtsp or mfsp */
extract_3 (word)
unsigned word;
{
return GET_FIELD (word, 18, 18) << 2 | GET_FIELD (word, 16, 17);
}
extract_5_load (word)
unsigned word;
{
return low_sign_extend (word >> 16 & MASK_5, 5);
}
/* extract the immediate field from a st{bhw}s instruction */
int
extract_5_store (word)
unsigned word;
{
return low_sign_extend (word & MASK_5, 5);
}
/* extract an 11 bit immediate field */
int
extract_11 (word)
unsigned word;
{
return low_sign_extend (word & MASK_11, 11);
}
/* extract a 14 bit immediate field */
int
extract_14 (word)
unsigned word;
{
return low_sign_extend (word & MASK_14, 14);
}
/* deposit a 14 bit constant in a word */
unsigned
deposit_14 (opnd, word)
int opnd;
unsigned word;
{
unsigned sign = (opnd < 0 ? 1 : 0);
return word | ((unsigned)opnd << 1 & MASK_14) | sign;
}
/* extract a 21 bit constant */
int
extract_21 (word)
unsigned word;
{
int val;
word &= MASK_21;
word <<= 11;
val = GET_FIELD (word, 20, 20);
val <<= 11;
val |= GET_FIELD (word, 9, 19);
val <<= 2;
val |= GET_FIELD (word, 5, 6);
val <<= 5;
val |= GET_FIELD (word, 0, 4);
val <<= 2;
val |= GET_FIELD (word, 7, 8);
return sign_extend (val, 21) << 11;
}
/* deposit a 21 bit constant in a word. Although 21 bit constants are
usually the top 21 bits of a 32 bit constant, we assume that only
the low 21 bits of opnd are relevant */
unsigned
deposit_21 (opnd, word)
unsigned opnd, word;
{
unsigned val = 0;
val |= GET_FIELD (opnd, 11 + 14, 11 + 18);
val <<= 2;
val |= GET_FIELD (opnd, 11 + 12, 11 + 13);
val <<= 2;
val |= GET_FIELD (opnd, 11 + 19, 11 + 20);
val <<= 11;
val |= GET_FIELD (opnd, 11 + 1, 11 + 11);
val <<= 1;
val |= GET_FIELD (opnd, 11 + 0, 11 + 0);
return word | val;
}
/* extract a 12 bit constant from branch instructions */
int
extract_12 (word)
unsigned word;
{
return sign_extend (GET_FIELD (word, 19, 28) |
GET_FIELD (word, 29, 29) << 10 |
(word & 0x1) << 11, 12) << 2;
}
/* extract a 17 bit constant from branch instructions, returning the
19 bit signed value. */
int
extract_17 (word)
unsigned word;
{
return sign_extend (GET_FIELD (word, 19, 28) |
GET_FIELD (word, 29, 29) << 10 |
GET_FIELD (word, 11, 15) << 11 |
(word & 0x1) << 16, 17) << 2;
}
static int use_unwind = 0;
/* Lookup the unwind (stack backtrace) info for the given PC. We search all
of the objfiles seeking the unwind table entry for this PC. Each objfile
contains a sorted list of struct unwind_table_entry. Since we do a binary
search of the unwind tables, we depend upon them to be sorted. */
static struct unwind_table_entry *
find_unwind_entry(pc)
CORE_ADDR pc;
{
int first, middle, last;
struct objfile *objfile;
ALL_OBJFILES (objfile)
{
struct obj_unwind_info *ui;
ui = OBJ_UNWIND_INFO (objfile);
if (!ui)
continue;
/* First, check the cache */
if (ui->cache
&& pc >= ui->cache->region_start
&& pc <= ui->cache->region_end)
return ui->cache;
/* Not in the cache, do a binary search */
first = 0;
last = ui->last;
while (first <= last)
{
middle = (first + last) / 2;
if (pc >= ui->table[middle].region_start
&& pc <= ui->table[middle].region_end)
{
ui->cache = &ui->table[middle];
return &ui->table[middle];
}
if (pc < ui->table[middle].region_start)
last = middle - 1;
else
first = middle + 1;
}
} /* ALL_OBJFILES() */
return NULL;
}
static int
find_return_regnum(pc)
CORE_ADDR pc;
{
struct unwind_table_entry *u;
u = find_unwind_entry (pc);
if (!u)
return RP_REGNUM;
if (u->Millicode)
return 31;
return RP_REGNUM;
}
int
find_proc_framesize(pc)
CORE_ADDR pc;
{
struct unwind_table_entry *u;
if (!use_unwind)
return -1;
u = find_unwind_entry (pc);
if (!u)
return -1;
return u->Total_frame_size << 3;
}
int
rp_saved(pc)
{
struct unwind_table_entry *u;
u = find_unwind_entry (pc);
if (!u)
return 0;
if (u->Save_RP)
return 1;
else
return 0;
}
CORE_ADDR
saved_pc_after_call (frame)
FRAME frame;
{
int ret_regnum;
ret_regnum = find_return_regnum (get_frame_pc (frame));
return read_register (ret_regnum) & ~0x3;
}
CORE_ADDR
frame_saved_pc (frame)
FRAME frame;
{
CORE_ADDR pc = get_frame_pc (frame);
if (frameless_look_for_prologue (frame))
{
int ret_regnum;
ret_regnum = find_return_regnum (pc);
return read_register (ret_regnum) & ~0x3;
}
else if (rp_saved (pc))
return read_memory_integer (frame->frame - 20, 4) & ~0x3;
else
return read_register (RP_REGNUM) & ~0x3;
}
/* We need to correct the PC and the FP for the outermost frame when we are
in a system call. */
void
init_extra_frame_info (fromleaf, frame)
int fromleaf;
struct frame_info *frame;
{
int flags;
int framesize;
if (frame->next) /* Only do this for outermost frame */
return;
flags = read_register (FLAGS_REGNUM);
if (flags & 2) /* In system call? */
frame->pc = read_register (31) & ~0x3;
/* The outermost frame is always derived from PC-framesize */
framesize = find_proc_framesize(frame->pc);
if (framesize == -1)
frame->frame = read_register (FP_REGNUM);
else
frame->frame = read_register (SP_REGNUM) - framesize;
if (!frameless_look_for_prologue (frame)) /* Frameless? */
return; /* No, quit now */
/* For frameless functions, we need to look at the caller's frame */
framesize = find_proc_framesize(FRAME_SAVED_PC(frame));
if (framesize != -1)
frame->frame -= framesize;
}
FRAME_ADDR
frame_chain (frame)
struct frame_info *frame;
{
int framesize;
framesize = find_proc_framesize(FRAME_SAVED_PC(frame));
if (framesize != -1)
return frame->frame - framesize;
return read_memory_integer (frame->frame, 4);
}
/* To see if a frame chain is valid, see if the caller looks like it
was compiled with gcc. */
int
frame_chain_valid (chain, thisframe)
FRAME_ADDR chain;
FRAME thisframe;
{
struct minimal_symbol *msym;
if (!chain)
return 0;
msym = lookup_minimal_symbol_by_pc (FRAME_SAVED_PC (thisframe));
if (msym
&& (strcmp (SYMBOL_NAME (msym), "_start") == 0))
return 0;
else
return 1;
}
#if 0
/* Some helper functions. gcc_p returns 1 if the function beginning at
pc appears to have been compiled with gcc. hpux_cc_p returns 1 if
fn was compiled with hpux cc. gcc functions look like :
stw rp,-0x14(sp) ; optional
or r4,r0,r1
or sp,r0,r4
stwm r1,framesize(sp)
hpux cc functions look like:
stw rp,-0x14(sp) ; optional.
stwm r3,framesiz(sp)
*/
gcc_p (pc)
CORE_ADDR pc;
{
if (read_memory_integer (pc, 4) == 0x6BC23FD9)
pc = pc + 4;
if (read_memory_integer (pc, 4) == 0x8040241
&& read_memory_integer (pc + 4, 4) == 0x81E0244)
return 1;
return 0;
}
#endif
/*
* These functions deal with saving and restoring register state
* around a function call in the inferior. They keep the stack
* double-word aligned; eventually, on an hp700, the stack will have
* to be aligned to a 64-byte boundary.
*/
int
push_dummy_frame ()
{
register CORE_ADDR sp;
register int regnum;
int int_buffer;
double freg_buffer;
/* Space for "arguments"; the RP goes in here. */
sp = read_register (SP_REGNUM) + 48;
int_buffer = read_register (RP_REGNUM) | 0x3;
write_memory (sp - 20, (char *)&int_buffer, 4);
int_buffer = read_register (FP_REGNUM);
write_memory (sp, (char *)&int_buffer, 4);
write_register (FP_REGNUM, sp);
sp += 8;
for (regnum = 1; regnum < 32; regnum++)
if (regnum != RP_REGNUM && regnum != FP_REGNUM)
sp = push_word (sp, read_register (regnum));
sp += 4;
for (regnum = FP0_REGNUM; regnum < NUM_REGS; regnum++)
{
read_register_bytes (REGISTER_BYTE (regnum), (char *)&freg_buffer, 8);
sp = push_bytes (sp, (char *)&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_HEAD_REGNUM));
sp = push_word (sp, read_register (PCSQ_HEAD_REGNUM));
sp = push_word (sp, read_register (PCOQ_TAIL_REGNUM));
sp = push_word (sp, read_register (PCSQ_TAIL_REGNUM));
write_register (SP_REGNUM, sp);
}
find_dummy_frame_regs (frame, frame_saved_regs)
struct frame_info *frame;
struct frame_saved_regs *frame_saved_regs;
{
CORE_ADDR fp = frame->frame;
int i;
frame_saved_regs->regs[RP_REGNUM] = fp - 20 & ~0x3;
frame_saved_regs->regs[FP_REGNUM] = fp;
frame_saved_regs->regs[1] = fp + 8;
frame_saved_regs->regs[3] = fp + 12;
for (fp += 16, i = 5; i < 32; fp += 4, i++)
frame_saved_regs->regs[i] = fp;
fp += 4;
for (i = FP0_REGNUM; i < NUM_REGS; i++, fp += 8)
frame_saved_regs->regs[i] = fp;
frame_saved_regs->regs[IPSW_REGNUM] = fp;
fp += 4;
frame_saved_regs->regs[SAR_REGNUM] = fp;
fp += 4;
frame_saved_regs->regs[PCOQ_HEAD_REGNUM] = fp;
fp +=4;
frame_saved_regs->regs[PCSQ_HEAD_REGNUM] = fp;
fp +=4;
frame_saved_regs->regs[PCOQ_TAIL_REGNUM] = fp;
fp +=4;
frame_saved_regs->regs[PCSQ_TAIL_REGNUM] = fp;
}
int
hppa_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);
if (fsr.regs[IPSW_REGNUM]) /* Restoring a call dummy frame */
restore_pc_queue (&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], (char *)&freg_buffer, 8);
write_register_bytes (REGISTER_BYTE (regnum), (char *)&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));
write_register (FP_REGNUM, read_memory_integer (fp, 4));
if (fsr.regs[IPSW_REGNUM]) /* call dummy */
write_register (SP_REGNUM, fp - 48);
else
write_register (SP_REGNUM, fp);
flush_cached_frames ();
set_current_frame (create_new_frame (read_register (FP_REGNUM),
read_pc ()));
}
/*
* After returning to a dummy on the stack, restore the instruction
* queue space registers. */
static int
restore_pc_queue (fsr)
struct frame_saved_regs *fsr;
{
CORE_ADDR pc = read_pc ();
CORE_ADDR new_pc = read_memory_integer (fsr->regs[PCOQ_HEAD_REGNUM], 4);
int pid;
WAITTYPE w;
int insn_count;
/* Advance past break instruction in the call dummy. */
write_register (PCOQ_HEAD_REGNUM, pc + 4);
write_register (PCOQ_TAIL_REGNUM, pc + 8);
/*
* HPUX doesn't let us set the space registers or the space
* registers of the PC queue through ptrace. Boo, hiss.
* Conveniently, the call dummy has this sequence of instructions
* after the break:
* mtsp r21, sr0
* ble,n 0(sr0, r22)
*
* So, load up the registers and single step until we are in the
* right place.
*/
write_register (21, read_memory_integer (fsr->regs[PCSQ_HEAD_REGNUM], 4));
write_register (22, new_pc);
for (insn_count = 0; insn_count < 3; insn_count++)
{
resume (1, 0);
target_wait(&w);
if (!WIFSTOPPED (w))
{
stop_signal = WTERMSIG (w);
terminal_ours_for_output ();
printf ("\nProgram terminated with signal %d, %s\n",
stop_signal, safe_strsignal (stop_signal));
fflush (stdout);
return 0;
}
}
fetch_inferior_registers (-1);
return 1;
}
CORE_ADDR
hppa_push_arguments (nargs, args, sp, struct_return, struct_addr)
int nargs;
value *args;
CORE_ADDR sp;
int struct_return;
CORE_ADDR struct_addr;
{
/* array of arguments' offsets */
int *offset = (int *)alloca(nargs);
int cum = 0;
int i, alignment;
for (i = 0; i < nargs; i++)
{
/* Coerce chars to int & float to double if necessary */
args[i] = value_arg_coerce (args[i]);
cum += TYPE_LENGTH (VALUE_TYPE (args[i]));
/* value must go at proper alignment. Assume alignment is a
power of two.*/
alignment = hppa_alignof (VALUE_TYPE (args[i]));
if (cum % alignment)
cum = (cum + alignment) & -alignment;
offset[i] = -cum;
}
sp += min ((cum + 7) & -8, 16);
for (i = 0; i < nargs; i++)
write_memory (sp + offset[i], VALUE_CONTENTS (args[i]),
TYPE_LENGTH (VALUE_TYPE (args[i])));
if (struct_return)
write_register (28, struct_addr);
return sp + 32;
}
/*
* Insert the specified number of args and function address
* into a call sequence of the above form stored at DUMMYNAME.
*
* On the hppa we need to call the stack dummy through $$dyncall.
* Therefore our version of FIX_CALL_DUMMY takes an extra argument,
* real_pc, which is the location where gdb should start up the
* inferior to do the function call.
*/
CORE_ADDR
hppa_fix_call_dummy (dummy, pc, fun, nargs, args, type, gcc_p)
REGISTER_TYPE *dummy;
CORE_ADDR pc;
CORE_ADDR fun;
int nargs;
value *args;
struct type *type;
int gcc_p;
{
CORE_ADDR dyncall_addr, sr4export_addr;
struct minimal_symbol *msymbol;
msymbol = lookup_minimal_symbol ("$$dyncall", (struct objfile *) NULL);
if (msymbol == NULL)
error ("Can't find an address for $$dyncall trampoline");
dyncall_addr = SYMBOL_VALUE_ADDRESS (msymbol);
msymbol = lookup_minimal_symbol ("_sr4export", (struct objfile *) NULL);
if (msymbol == NULL)
error ("Can't find an address for _sr4export trampoline");
sr4export_addr = SYMBOL_VALUE_ADDRESS (msymbol);
dummy[9] = deposit_21 (fun >> 11, dummy[9]);
dummy[10] = deposit_14 (fun & MASK_11, dummy[10]);
dummy[12] = deposit_21 (sr4export_addr >> 11, dummy[12]);
dummy[13] = deposit_14 (sr4export_addr & MASK_11, dummy[13]);
write_register (22, pc);
return dyncall_addr;
}
/* return the alignment of a type in bytes. Structures have the maximum
alignment required by their fields. */
static int
hppa_alignof (arg)
struct type *arg;
{
int max_align, align, i;
switch (TYPE_CODE (arg))
{
case TYPE_CODE_PTR:
case TYPE_CODE_INT:
case TYPE_CODE_FLT:
return TYPE_LENGTH (arg);
case TYPE_CODE_ARRAY:
return hppa_alignof (TYPE_FIELD_TYPE (arg, 0));
case TYPE_CODE_STRUCT:
case TYPE_CODE_UNION:
max_align = 2;
for (i = 0; i < TYPE_NFIELDS (arg); i++)
{
/* Bit fields have no real alignment. */
if (!TYPE_FIELD_BITPOS (arg, i))
{
align = hppa_alignof (TYPE_FIELD_TYPE (arg, i));
max_align = max (max_align, align);
}
}
return max_align;
default:
return 4;
}
}
/* Print the register regnum, or all registers if regnum is -1 */
pa_do_registers_info (regnum, fpregs)
int regnum;
int fpregs;
{
char raw_regs [REGISTER_BYTES];
int i;
for (i = 0; i < NUM_REGS; i++)
read_relative_register_raw_bytes (i, raw_regs + REGISTER_BYTE (i));
if (regnum == -1)
pa_print_registers (raw_regs, regnum, fpregs);
else if (regnum < FP0_REGNUM)
printf ("%s %x\n", reg_names[regnum], *(long *)(raw_regs +
REGISTER_BYTE (regnum)));
else
pa_print_fp_reg (regnum);
}
pa_print_registers (raw_regs, regnum, fpregs)
char *raw_regs;
int regnum;
int fpregs;
{
int i;
for (i = 0; i < 18; i++)
printf ("%8.8s: %8x %8.8s: %8x %8.8s: %8x %8.8s: %8x\n",
reg_names[i],
*(int *)(raw_regs + REGISTER_BYTE (i)),
reg_names[i + 18],
*(int *)(raw_regs + REGISTER_BYTE (i + 18)),
reg_names[i + 36],
*(int *)(raw_regs + REGISTER_BYTE (i + 36)),
reg_names[i + 54],
*(int *)(raw_regs + REGISTER_BYTE (i + 54)));
if (fpregs)
for (i = 72; i < NUM_REGS; i++)
pa_print_fp_reg (i);
}
pa_print_fp_reg (i)
int i;
{
unsigned char raw_buffer[MAX_REGISTER_RAW_SIZE];
unsigned char virtual_buffer[MAX_REGISTER_VIRTUAL_SIZE];
REGISTER_TYPE val;
/* Get the data in raw format, then convert also to virtual format. */
read_relative_register_raw_bytes (i, raw_buffer);
REGISTER_CONVERT_TO_VIRTUAL (i, raw_buffer, virtual_buffer);
fputs_filtered (reg_names[i], stdout);
print_spaces_filtered (15 - strlen (reg_names[i]), stdout);
val_print (REGISTER_VIRTUAL_TYPE (i), virtual_buffer, 0, stdout, 0,
1, 0, Val_pretty_default);
printf_filtered ("\n");
}
/* Function calls that pass into a new compilation unit must pass through a
small piece of code that does long format (`external' in HPPA parlance)
jumps. We figure out where the trampoline is going to end up, and return
the PC of the final destination. If we aren't in a trampoline, we just
return NULL.
For computed calls, we just extract the new PC from r22. */
CORE_ADDR
skip_trampoline_code (pc, name)
CORE_ADDR pc;
char *name;
{
long inst0, inst1;
static CORE_ADDR dyncall = 0;
struct minimal_symbol *msym;
/* FIXME XXX - dyncall must be initialized whenever we get a new exec file */
if (!dyncall)
{
msym = lookup_minimal_symbol ("$$dyncall", NULL);
if (msym)
dyncall = SYMBOL_VALUE_ADDRESS (msym);
else
dyncall = -1;
}
if (pc == dyncall)
return (CORE_ADDR)(read_register (22) & ~0x3);
inst0 = read_memory_integer (pc, 4);
inst1 = read_memory_integer (pc+4, 4);
if ( (inst0 & 0xffe00000) == 0x20200000 /* ldil xxx, r1 */
&& (inst1 & 0xffe0e002) == 0xe0202002) /* be,n yyy(sr4, r1) */
pc = extract_21 (inst0) + extract_17 (inst1);
else
pc = (CORE_ADDR)NULL;
return pc;
}
/* 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 */
CORE_ADDR
skip_prologue(pc)
CORE_ADDR pc;
{
int inst;
int status;
status = target_read_memory (pc, (char *)&inst, 4);
SWAP_TARGET_AND_HOST (&inst, sizeof (inst));
if (status != 0)
return pc;
if (inst == 0x6BC23FD9) /* stw rp,-20(sp) */
{
if (read_memory_integer (pc + 4, 4) == 0x8040241) /* copy r4,r1 */
pc += 16;
else if ((read_memory_integer (pc + 4, 4) & ~MASK_14) == 0x68810000) /* stw r1,(r4) */
pc += 8;
}
else if (read_memory_integer (pc, 4) == 0x8040241) /* copy r4,r1 */
pc += 12;
else if ((read_memory_integer (pc, 4) & ~MASK_14) == 0x68810000) /* stw r1,(r4) */
pc += 4;
return pc;
}
static void
unwind_command (exp, from_tty)
char *exp;
int from_tty;
{
CORE_ADDR address;
union
{
int *foo;
struct unwind_table_entry *u;
} xxx;
/* If we have an expression, evaluate it and use it as the address. */
if (exp != 0 && *exp != 0)
address = parse_and_eval_address (exp);
else
return;
xxx.u = find_unwind_entry (address);
if (!xxx.u)
{
printf ("Can't find unwind table entry for PC 0x%x\n", address);
return;
}
printf ("%08x\n%08X\n%08X\n%08X\n", xxx.foo[0], xxx.foo[1], xxx.foo[2],
xxx.foo[3]);
}
void
_initialize_hppah_tdep ()
{
add_com ("unwind", class_obscure, unwind_command, "Print unwind info\n");
add_show_from_set
(add_set_cmd ("use_unwind", class_obscure, var_boolean,
(char *)&use_unwind,
"Set the usage of unwind info", &setlist),
&showlist);
}