#include "gdbcore.h"
#include "frame.h"
#include "value.h"
+/*#include <sys/param.h> */
#include "symtab.h"
#include "inferior.h"
+#include "gdbcmd.h"
extern CORE_ADDR text_start; /* FIXME, kludge... */
+/* The user-settable top of the register stack in virtual memory. We
+ won't attempt to access any stored registers above this address, if set
+ nonzero. */
+
+static CORE_ADDR rstack_high_address = UINT_MAX;
+
/* Structure to hold cached info about function prologues. */
struct prologue_info
{
}
p += 4;
- /* Next instruction must be asgeu V_SPILL,gr1,rab. */
+ /* Next instruction must be asgeu V_SPILL,gr1,rab.
+ * We don't check the vector number to allow for kernel debugging. The
+ * kernel will use a different trap number.
+ */
insn = read_memory_integer (p, 4);
- if (insn != 0x5e40017e)
+ if ((insn & 0xff00ffff) != (0x5e000100|RAB_HW_REGNUM))
{
p = pc;
goto done;
/* Next instruction usually sets the frame pointer (lr1) by adding
<size * 4> from gr1. However, this can (and high C does) be
deferred until anytime before the first function call. So it is
- OK if we don't see anything which sets lr1. */
+ OK if we don't see anything which sets lr1.
+ To allow for alternate register sets (gcc -mkernel-registers) the msp
+ register number is a compile time constant. */
+
/* Normally this is just add lr1,gr1,<size * 4>. */
insn = read_memory_integer (p, 4);
if ((insn & 0xffffff00) == 0x15810100)
we don't check this rsize against the first instruction, and
we don't check that the trace-back tag indicates a memory frame pointer
is in use.
+ To allow for alternate register sets (gcc -mkernel-registers) the msp
+ register number is a compile time constant.
The recommended instruction is actually "sll lr<whatever>,msp,0".
We check for that, too. Originally Jim Kingdon's code seemed
to be looking for a "sub" instruction here, but the mask was set
up to lose all the time. */
insn = read_memory_integer (p, 4);
- if (((insn & 0xff80ffff) == 0x15807d00) /* add */
- || ((insn & 0xff80ffff) == 0x81807d00) ) /* sll */
+ if (((insn & 0xff80ffff) == (0x15800000|(MSP_HW_REGNUM<<8))) /* add */
+ || ((insn & 0xff80ffff) == (0x81800000|(MSP_HW_REGNUM<<8)))) /* sll */
{
p += 4;
if (mfp_used != NULL)
but only if a memory frame is
being used. We don't check msize against the trace-back tag.
+ To allow for alternate register sets (gcc -mkernel-registers) the msp
+ register number is a compile time constant.
+
Normally this is just
sub msp,msp,<msize>
*/
insn = read_memory_integer (p, 4);
- if ((insn & 0xffffff00) == 0x257d7d00)
+ if ((insn & 0xffffff00) ==
+ (0x25000000|(MSP_HW_REGNUM<<16)|(MSP_HW_REGNUM<<8)))
{
p += 4;
- if (msize != NULL)
+ if (msize != NULL)
*msize = insn & 0xff;
}
else
insn = read_memory_integer (q, 4);
}
/* Check for sub msp,msp,<reg>. */
- if ((insn & 0xffffff00) == 0x247d7d00
+ if ((insn & 0xffffff00) ==
+ (0x24000000|(MSP_HW_REGNUM<<16)|(MSP_HW_REGNUM<<8))
&& (insn & 0xff) == reg)
{
p = q + 4;
return examine_prologue (pc, (unsigned *)NULL, (unsigned *)NULL,
(int *)NULL);
}
+/*
+ * Examine the one or two word tag at the beginning of a function.
+ * The tag word is expect to be at 'p', if it is not there, we fail
+ * by returning 0. The documentation for the tag word was taken from
+ * page 7-15 of the 29050 User's Manual. We are assuming that the
+ * m bit is in bit 22 of the tag word, which seems to be the agreed upon
+ * convention today (1/15/92).
+ * msize is return in bytes.
+ */
+static int /* 0/1 - failure/success of finding the tag word */
+examine_tag(p, is_trans, argcount, msize, mfp_used)
+ CORE_ADDR p;
+ int *is_trans;
+ int *argcount;
+ unsigned *msize;
+ int *mfp_used;
+{
+ unsigned int tag1, tag2;
+
+ tag1 = read_memory_integer (p, 4);
+ if ((tag1 & 0xff000000) != 0) /* Not a tag word */
+ return 0;
+ if (tag1 & (1<<23)) /* A two word tag */
+ {
+ tag2 = read_memory_integer (p+4, 4);
+ if (msize)
+ *msize = tag2;
+ }
+ else /* A one word tag */
+ {
+ if (msize)
+ *msize = tag1 & 0x7ff;
+ }
+ if (is_trans)
+ *is_trans = ((tag1 & (1<<21)) ? 1 : 0);
+ if (argcount)
+ *argcount = (tag1 >> 16) & 0x1f;
+ if (mfp_used)
+ *mfp_used = ((tag1 & (1<<22)) ? 1 : 0);
+ return(1);
+}
/* Initialize the frame. In addition to setting "extra" frame info,
we also set ->frame because we use it in a nonstandard way, and ->pc
long insn;
unsigned rsize;
unsigned msize;
- int mfp_used;
+ int mfp_used, trans;
struct symbol *func;
p = fci->pc;
/* Dummy frames always use a memory frame pointer. */
fci->saved_msp =
read_register_stack_integer (fci->frame + DUMMY_FRAME_RSIZE - 4, 4);
+ fci->flags |= (TRANSPARENT|MFP_USED);
return;
}
fci->saved_msp = 0;
fci->rsize = 0;
fci->msize = 0;
+ fci->flags = TRANSPARENT;
return;
}
else
after the trace-back tag. */
p += 4;
}
- /* We've found the start of the function. Since High C interchanges
- the meanings of bits 23 and 22 (as of Jul 90), and we
- need to look at the prologue anyway to figure out
- what rsize is, ignore the contents of the trace-back tag. */
- examine_prologue (p, &rsize, &msize, &mfp_used);
+ /* We've found the start of the function.
+ * Try looking for a tag word that indicates whether there is a
+ * memory frame pointer and what the memory stack allocation is.
+ * If one doesn't exist, try using a more exhaustive search of
+ * the prologue. For now we don't care about the argcount or
+ * whether or not the routine is transparent.
+ */
+ if (examine_tag(p-4,&trans,NULL,&msize,&mfp_used)) /* Found a good tag */
+ examine_prologue (p, &rsize, 0, 0);
+ else /* No tag try prologue */
+ examine_prologue (p, &rsize, &msize, &mfp_used);
+
fci->rsize = rsize;
fci->msize = msize;
+ fci->flags = 0;
+ if (mfp_used)
+ fci->flags |= MFP_USED;
+ if (trans)
+ fci->flags |= TRANSPARENT;
if (innermost_frame)
{
fci->saved_msp = read_register (MSP_REGNUM) + msize;
else
{
if (mfp_used)
- fci->saved_msp =
- read_register_stack_integer (fci->frame + rsize - 1, 4);
+ fci->saved_msp =
+ read_register_stack_integer (fci->frame + rsize - 4, 4);
else
- fci->saved_msp = fci->next->saved_msp + msize;
+ fci->saved_msp = fci->next->saved_msp + msize;
}
}
{
fci->pc = (fromleaf ? SAVED_PC_AFTER_CALL (fci->next) :
fci->next ? FRAME_SAVED_PC (fci->next) : read_pc ());
- init_frame_info (0, fci);
+ init_frame_info (fromleaf, fci);
}
\f
/* Local variables (i.e. LOC_LOCAL) are on the memory stack, with their
frame_locals_address (fi)
struct frame_info *fi;
{
- struct block *b = block_for_pc (fi->pc);
- /* If compiled without -g, assume GCC. */
- if (b == NULL || BLOCK_GCC_COMPILED (b))
+ if (fi->flags & MFP_USED)
return fi->saved_msp;
else
return fi->saved_msp - fi->msize;
{
long rfb = read_register (RFB_REGNUM);
long rsp = read_register (RSP_REGNUM);
- if (memaddr < rfb)
+
+ /* If we don't do this 'info register' stops in the middle. */
+ if (memaddr >= rstack_high_address)
+ {
+ int val = -1; /* a bogus value */
+ /* It's in a local register, but off the end of the stack. */
+ int regnum = (memaddr - rsp) / 4 + LR0_REGNUM;
+ if (myaddr != NULL)
+ *(int*)myaddr = val; /* Provide bogusness */
+ supply_register(regnum,&val); /* More bogusness */
+ if (lval != NULL)
+ *lval = lval_register;
+ if (actual_mem_addr != NULL)
+ *actual_mem_addr = REGISTER_BYTE (regnum);
+ }
+ else if (memaddr < rfb)
{
/* It's in a register. */
int regnum = (memaddr - rsp) / 4 + LR0_REGNUM;
else
{
/* It's in the memory portion of the register stack. */
- if (myaddr != NULL)
- read_memory (memaddr, myaddr, 4);
+ if (myaddr != NULL)
+ read_memory (memaddr, myaddr, 4);
if (lval != NULL)
*lval = lval_memory;
if (actual_mem_addr != NULL)
{
long rfb = read_register (RFB_REGNUM);
long rsp = read_register (RSP_REGNUM);
- if (memaddr < rfb)
+ /* If we don't do this 'info register' stops in the middle. */
+ if (memaddr >= rstack_high_address)
+ {
+ /* It's in a register, but off the end of the stack. */
+ if (actual_mem_addr != NULL)
+ *actual_mem_addr = NULL;
+ }
+ else if (memaddr < rfb)
{
/* It's in a register. */
int regnum = (memaddr - rsp) / 4 + LR0_REGNUM;
if (myaddr != NULL)
write_register (regnum, *(long *)myaddr);
if (actual_mem_addr != NULL)
- *actual_mem_addr = 0;
+ *actual_mem_addr = NULL;
}
else
{
int regnum;
enum lval_type *lvalp;
{
- struct frame_info *fi = get_frame_info (frame);
+ struct frame_info *fi;
CORE_ADDR addr;
enum lval_type lval;
+ if (frame == 0)
+ return;
+
+ fi = get_frame_info (frame);
+
/* Once something has a register number, it doesn't get optimized out. */
if (optimized != NULL)
*optimized = 0;
*addrp = addr;
}
\f
+
/* Discard from the stack the innermost frame,
restoring all saved registers. */
CORE_ADDR rfb = read_register (RFB_REGNUM);
CORE_ADDR gr1 = fi->frame + fi->rsize;
CORE_ADDR lr1;
- CORE_ADDR ret_addr;
int i;
/* If popping a dummy frame, need to restore registers. */
read_register (SP_REGNUM),
FRAME_FP (fi)))
{
+ int lrnum = LR0_REGNUM + DUMMY_ARG/4;
for (i = 0; i < DUMMY_SAVE_SR128; ++i)
- write_register
- (SR_REGNUM (i + 128),
- read_register (LR0_REGNUM + DUMMY_ARG / 4 + i));
+ write_register (SR_REGNUM (i + 128),read_register (lrnum++));
+ for (i = 0; i < DUMMY_SAVE_SR160; ++i)
+ write_register (SR_REGNUM(i+160), read_register (lrnum++));
for (i = 0; i < DUMMY_SAVE_GREGS; ++i)
- write_register
- (RETURN_REGNUM + i,
- read_register (LR0_REGNUM + DUMMY_ARG / 4 + DUMMY_SAVE_SR128 + i));
+ write_register (RETURN_REGNUM + i, read_register (lrnum++));
+ /* Restore the PCs. */
+ write_register(PC_REGNUM, read_register (lrnum++));
+ write_register(NPC_REGNUM, read_register (lrnum));
}
/* Restore the memory stack pointer. */
write_register (LR0_REGNUM + ((rfb - gr1) % 0x80) + i / 4, word);
}
}
- ret_addr = read_register (LR0_REGNUM);
- write_register (PC_REGNUM, ret_addr);
- write_register (NPC_REGNUM, ret_addr + 4);
flush_cached_frames ();
set_current_frame (create_new_frame (0, read_pc()));
}
long w;
CORE_ADDR rab, gr1;
CORE_ADDR msp = read_register (MSP_REGNUM);
- int i;
+ int lrnum, i, saved_lr0;
- /* Save the PC. */
- write_register (LR0_REGNUM, read_register (PC_REGNUM));
- /* Allocate the new frame. */
+ /* Allocate the new frame. */
gr1 = read_register (GR1_REGNUM) - DUMMY_FRAME_RSIZE;
write_register (GR1_REGNUM, gr1);
for (i = 0; i < num_bytes; i += 4)
{
/* Note: word is in target byte order. */
- read_register_gen (LR0_REGNUM + i / 4, (char *)&word);
- write_memory (rfb - num_bytes + i, (char *)&word, 4);
+ read_register_gen (LR0_REGNUM + i / 4, &word);
+ write_memory (rfb - num_bytes + i, &word, 4);
}
}
write_register (MSP_REGNUM, msp - 16 * 4);
/* Save registers. */
+ lrnum = LR0_REGNUM + DUMMY_ARG/4;
for (i = 0; i < DUMMY_SAVE_SR128; ++i)
- write_register (LR0_REGNUM + DUMMY_ARG / 4 + i,
- read_register (SR_REGNUM (i + 128)));
+ write_register (lrnum++, read_register (SR_REGNUM (i + 128)));
+ for (i = 0; i < DUMMY_SAVE_SR160; ++i)
+ write_register (lrnum++, read_register (SR_REGNUM (i + 160)));
for (i = 0; i < DUMMY_SAVE_GREGS; ++i)
- write_register (LR0_REGNUM + DUMMY_ARG / 4 + DUMMY_SAVE_SR128 + i,
- read_register (RETURN_REGNUM + i));
+ write_register (lrnum++, read_register (RETURN_REGNUM + i));
+ /* Save the PCs. */
+ write_register (lrnum++, read_register (PC_REGNUM));
+ write_register (lrnum, read_register (NPC_REGNUM));
+}
+
+reginv_com (args, fromtty)
+ char *args;
+ int fromtty;
+{
+ registers_changed();
+ if (fromtty)
+ printf_filtered("Gdb's register cache invalidated.\n");
+}
+
+/* We use this mostly for debugging gdb */
+void
+_initialize_29k()
+{
+ add_com ("reginv ", class_obscure, reginv_com,
+ "Invalidate gdb's internal register cache.");
+
+ /* FIXME, there should be a way to make a CORE_ADDR variable settable. */
+ add_show_from_set
+ (add_set_cmd ("rstack_high_address", class_support, var_uinteger,
+ (char *)&rstack_high_address,
+ "Set top address in memory of the register stack.\n\
+Attempts to access registers saved above this address will be ignored\n\
+or will produce the value -1.", &setlist),
+ &showlist);
}